@@ -111,7 +111,8 @@ def test_update_connected_not_charging(monkeypatch):
111111
112112def test_update_charging_uses_per_phase_voltages (monkeypatch ):
113113 svc , vedbus , _ = _make_svc (monkeypatch )
114- vedbus .__getitem__ .return_value = 5
114+ # /UpdateIndex starts at 5 (wraps to 6); other paths are uninitialised.
115+ vedbus .__getitem__ .side_effect = lambda k : 5 if k == "/UpdateIndex" else 0
115116 lp = Loadpoint (
116117 title = "HeatingElement" , connected = True , charging = True , mode = "pv" ,
117118 charge_power = 4500.0 ,
@@ -132,13 +133,81 @@ def test_update_charging_uses_per_phase_voltages(monkeypatch):
132133 assert sets ["/Current" ] == 19.5
133134 assert sets ["/MaxCurrent" ] == 20
134135 assert sets ["/Mode" ] == MODE_AUTO
135- # UNVERIFIED unit: chargedEnergy treated as Wh; must confirm against
136- # a live EVCC /api/state sample before merging the deploy.
136+ # Fallback for EVCC payloads without chargeTotalImport.
137137 assert sets ["/Ac/Energy/Forward" ] == 1.8
138138 assert sets ["/ChargingTime" ] == 3600
139139 assert sets ["/UpdateIndex" ] == 6
140140
141141
142+ def test_update_prefers_charge_total_import_for_cumulative_energy (monkeypatch ):
143+ svc , vedbus , _ = _make_svc (monkeypatch )
144+ vedbus .__getitem__ .return_value = 0
145+ lp = Loadpoint (
146+ title = "Heatpump" , connected = True , charging = False , mode = "off" ,
147+ charge_power = 90.25 ,
148+ charge_currents = [0.93 , 0.49 , 0.5 ],
149+ charge_voltages = [237.5 , 236.9 , 236.9 ],
150+ charged_energy = 0.0 ,
151+ charge_total_import = 19341.908 ,
152+ )
153+ svc .update (lp )
154+ sets = dict (c .args for c in vedbus .__setitem__ .call_args_list )
155+ assert sets ["/Ac/Energy/Forward" ] == 19341.908
156+
157+
158+ def test_update_energy_forward_is_monotonic_across_source_switch (monkeypatch ):
159+ """EVCC may transiently return chargeTotalImport: null / 0 (e.g. on a
160+ loadpoint without a meter). The fallback to chargedEnergy/1000 must not
161+ roll /Ac/Energy/Forward backwards for VRM.
162+ """
163+ svc , vedbus , _ = _make_svc (monkeypatch )
164+
165+ state = {"/Ac/Energy/Forward" : 0.0 , "/UpdateIndex" : 0 }
166+ vedbus .__getitem__ .side_effect = lambda k : state .get (k , 0 )
167+ vedbus .__setitem__ .side_effect = lambda k , v : state .__setitem__ (k , v )
168+
169+ lp_high = Loadpoint (
170+ title = "Heatpump" , connected = True , charging = True , mode = "pv" ,
171+ charged_energy = 0.0 , charge_total_import = 19341.908 ,
172+ )
173+ svc .update (lp_high )
174+ assert state ["/Ac/Energy/Forward" ] == 19341.908
175+
176+ # EVCC transiently drops the meter value; chargedEnergy is 0 on a heating LP
177+ lp_drop = Loadpoint (
178+ title = "Heatpump" , connected = True , charging = True , mode = "pv" ,
179+ charged_energy = 0.0 , charge_total_import = 0.0 ,
180+ )
181+ svc .update (lp_drop )
182+ assert state ["/Ac/Energy/Forward" ] == 19341.908 # held, no regression
183+
184+ # Meter value comes back and grows
185+ lp_resume = Loadpoint (
186+ title = "Heatpump" , connected = True , charging = True , mode = "pv" ,
187+ charged_energy = 0.0 , charge_total_import = 19500.0 ,
188+ )
189+ svc .update (lp_resume )
190+ assert state ["/Ac/Energy/Forward" ] == 19500.0
191+
192+
193+ def test_update_disconnected_with_total_import_still_publishes_cumulative (monkeypatch ):
194+ """A disconnected loadpoint with a positive chargeTotalImport (e.g. an
195+ EV that just unplugged) should still publish the lifetime counter so
196+ VRM history doesn't stall on disconnect. /ChargingTime stays unpublished.
197+ """
198+ svc , vedbus , _ = _make_svc (monkeypatch )
199+ vedbus .__getitem__ .return_value = 0
200+ lp = Loadpoint (
201+ title = "Carport" , connected = False , charging = False , mode = "pv" ,
202+ charged_energy = 0.0 , charge_total_import = 15303.908 ,
203+ )
204+ svc .update (lp )
205+ sets = dict (c .args for c in vedbus .__setitem__ .call_args_list )
206+ assert sets ["/Status" ] == STATUS_DISCONNECTED
207+ assert sets ["/Ac/Energy/Forward" ] == 15303.908
208+ assert "/ChargingTime" not in sets
209+
210+
142211def test_update_index_wraps_at_255 (monkeypatch ):
143212 svc , vedbus , _ = _make_svc (monkeypatch )
144213 vedbus .__getitem__ .return_value = 255
0 commit comments