11
11
SERVICE_TURN_ON ,
12
12
)
13
13
from homeassistant .const import ATTR_ENTITY_ID
14
+ import pytest
14
15
from pytest_homeassistant_custom_component .common import MockConfigEntry
15
16
import websockets
16
17
44
45
from .const import MOCK_CONFIG_DATA , MOCK_CONFIG_DATA_2
45
46
46
47
48
+ @pytest .mark .timeout (60 ) # Set timeout to 60 seconds for this test
47
49
async def test_cms_responses (hass , socket_enabled ):
48
50
"""Test central system responses to a charger."""
49
51
@@ -227,6 +229,63 @@ async def test_services(hass, socket_enabled):
227
229
228
230
await asyncio .sleep (1 )
229
231
232
+ # test restore feature of meter_start and active_tranasction_id.
233
+ async with websockets .connect (
234
+ "ws://127.0.0.1:9000/CP_1_res_vals" ,
235
+ subprotocols = ["ocpp1.6" ],
236
+ ) as ws :
237
+ # use a different id for debugging
238
+ cp = ChargePoint ("CP_1_restore_values" , ws )
239
+ cp .active_transactionId = None
240
+ # send None values
241
+ try :
242
+ await asyncio .wait_for (
243
+ asyncio .gather (
244
+ cp .start (),
245
+ cp .send_meter_periodic_data (),
246
+ ),
247
+ timeout = 5 ,
248
+ )
249
+ except asyncio .TimeoutError :
250
+ pass
251
+ # check if None
252
+ assert cs .get_metric ("test_cpid" , "Energy.Meter.Start" ) is None
253
+ assert cs .get_metric ("test_cpid" , "Transaction.Id" ) is None
254
+ # send new data
255
+ try :
256
+ await asyncio .wait_for (
257
+ asyncio .gather (
258
+ cp .send_start_transaction (12344 ),
259
+ cp .send_meter_periodic_data (),
260
+ ),
261
+ timeout = 5 ,
262
+ )
263
+ except asyncio .TimeoutError :
264
+ pass
265
+ # save for reference the values for meter_start and transaction_id
266
+ saved_meter_start = int (cs .get_metric ("test_cpid" , "Energy.Meter.Start" ))
267
+ saved_transactionId = int (cs .get_metric ("test_cpid" , "Transaction.Id" ))
268
+ # delete current values from api memory
269
+ cs .del_metric ("test_cpid" , "Energy.Meter.Start" )
270
+ cs .del_metric ("test_cpid" , "Transaction.Id" )
271
+ # send new data
272
+ try :
273
+ await asyncio .wait_for (
274
+ asyncio .gather (
275
+ cp .send_meter_periodic_data (),
276
+ ),
277
+ timeout = 5 ,
278
+ )
279
+ except asyncio .TimeoutError :
280
+ pass
281
+ await ws .close ()
282
+
283
+ # check if restored old values from HA when api have lost the values, i.e. simulated reboot of HA
284
+ assert int (cs .get_metric ("test_cpid" , "Energy.Meter.Start" )) == saved_meter_start
285
+ assert int (cs .get_metric ("test_cpid" , "Transaction.Id" )) == saved_transactionId
286
+
287
+ await asyncio .sleep (1 )
288
+
230
289
# test ocpp messages sent from charger to cms
231
290
async with websockets .connect (
232
291
"ws://127.0.0.1:9000/CP_1_norm" ,
@@ -245,10 +304,11 @@ async def test_services(hass, socket_enabled):
245
304
cp .send_security_event (),
246
305
cp .send_firmware_status (),
247
306
cp .send_data_transfer (),
248
- cp .send_start_transaction (),
307
+ cp .send_start_transaction (12345 ),
249
308
cp .send_meter_err_phases (),
250
309
cp .send_meter_line_voltage (),
251
310
cp .send_meter_periodic_data (),
311
+ cp .send_main_meter_clock_data (),
252
312
# add delay to allow meter data to be processed
253
313
cp .send_stop_transaction (2 ),
254
314
),
@@ -260,6 +320,9 @@ async def test_services(hass, socket_enabled):
260
320
assert int (cs .get_metric ("test_cpid" , "Energy.Active.Import.Register" )) == int (
261
321
1305570 / 1000
262
322
)
323
+ assert int (cs .get_metric ("test_cpid" , "Energy.Session" )) == int (
324
+ (54321 - 12345 ) / 1000
325
+ )
263
326
assert int (cs .get_metric ("test_cpid" , "Current.Import" )) == int (0 )
264
327
assert int (cs .get_metric ("test_cpid" , "Voltage" )) == int (228 )
265
328
assert cs .get_unit ("test_cpid" , "Energy.Active.Import.Register" ) == "kWh"
@@ -310,6 +373,43 @@ async def test_services(hass, socket_enabled):
310
373
311
374
await asyncio .sleep (1 )
312
375
376
+ # test ocpp messages sent from charger that don't support errata 3.9
377
+ # i.e. "Energy.Meter.Start" starts from 0 for each session and "Energy.Active.Import.Register"
378
+ # reports starting from 0 Wh for every new transaction id. Total main meter values are without transaction id.
379
+ async with websockets .connect (
380
+ "ws://127.0.0.1:9000/CP_1_non_er_3.9" ,
381
+ subprotocols = ["ocpp1.6" ],
382
+ ) as ws :
383
+ # use a different id for debugging
384
+ cp = ChargePoint ("CP_1_non_errata_3.9" , ws )
385
+ try :
386
+ await asyncio .wait_for (
387
+ asyncio .gather (
388
+ cp .start (),
389
+ cp .send_start_transaction (0 ),
390
+ cp .send_meter_periodic_data (),
391
+ cp .send_main_meter_clock_data (),
392
+ # add delay to allow meter data to be processed
393
+ cp .send_stop_transaction (2 ),
394
+ ),
395
+ timeout = 5 ,
396
+ )
397
+ except asyncio .TimeoutError :
398
+ pass
399
+ await ws .close ()
400
+
401
+ # Last sent "Energy.Active.Import.Register" value without transaction id should be here.
402
+ assert int (cs .get_metric ("test_cpid" , "Energy.Active.Import.Register" )) == int (
403
+ 67230012 / 1000
404
+ )
405
+ assert cs .get_unit ("test_cpid" , "Energy.Active.Import.Register" ) == "kWh"
406
+
407
+ # Last sent "Energy.Active.Import.Register" value with transaction id should be here.
408
+ assert int (cs .get_metric ("test_cpid" , "Energy.Session" )) == int (1305570 / 1000 )
409
+ assert cs .get_unit ("test_cpid" , "Energy.Session" ) == "kWh"
410
+
411
+ await asyncio .sleep (1 )
412
+
313
413
# test ocpp rejection messages sent from charger to cms
314
414
cs .charge_points ["test_cpid" ].received_boot_notification = False
315
415
cs .charge_points ["test_cpid" ].post_connect_success = False
@@ -604,12 +704,12 @@ async def send_data_transfer(self):
604
704
resp = await self .call (request )
605
705
assert resp .status == DataTransferStatus .accepted
606
706
607
- async def send_start_transaction (self ):
707
+ async def send_start_transaction (self , meter_start : int = 12345 ):
608
708
"""Send a start transaction notification."""
609
709
request = call .StartTransactionPayload (
610
710
connector_id = 1 ,
611
711
id_tag = "test_cp" ,
612
- meter_start = 12345 ,
712
+ meter_start = meter_start ,
613
713
timestamp = datetime .now (tz = timezone .utc ).isoformat (),
614
714
)
615
715
resp = await self .call (request )
@@ -871,6 +971,30 @@ async def send_meter_err_phases(self):
871
971
resp = await self .call (request )
872
972
assert resp is not None
873
973
974
+ async def send_main_meter_clock_data (self ):
975
+ """Send periodic main meter value. Main meter values dont have transaction_id."""
976
+ while self .active_transactionId == 0 :
977
+ await asyncio .sleep (1 )
978
+ request = call .MeterValuesPayload (
979
+ connector_id = 1 ,
980
+ meter_value = [
981
+ {
982
+ "timestamp" : "2021-06-21T16:15:09Z" ,
983
+ "sampledValue" : [
984
+ {
985
+ "value" : "67230012" ,
986
+ "context" : "Sample.Clock" ,
987
+ "format" : "Raw" ,
988
+ "measurand" : "Energy.Active.Import.Register" ,
989
+ "location" : "Inlet" ,
990
+ },
991
+ ],
992
+ }
993
+ ],
994
+ )
995
+ resp = await self .call (request )
996
+ assert resp is not None
997
+
874
998
async def send_meter_clock_data (self ):
875
999
"""Send periodic meter data notification."""
876
1000
self .active_transactionId = 0
0 commit comments