diff --git a/app/src/mqtt.py b/app/src/mqtt.py index 1ebbd10..7bc9ce0 100644 --- a/app/src/mqtt.py +++ b/app/src/mqtt.py @@ -12,12 +12,12 @@ logger_mqtt = logging.getLogger('mqtt') class Mqtt(metaclass=Singleton): __client = None - __cb_MqttIsUp = None + __cb_mqtt_is_up = None - def __init__(self, cb_MqttIsUp): + def __init__(self, cb_mqtt_is_up): logger_mqtt.debug('MQTT: __init__') - if cb_MqttIsUp: - self.__cb_MqttIsUp = cb_MqttIsUp + if cb_mqtt_is_up: + self.__cb_mqtt_is_up = cb_mqtt_is_up loop = asyncio.get_event_loop() self.task = loop.create_task(self.__loop()) self.ha_restarts = 0 @@ -71,8 +71,8 @@ class Mqtt(metaclass=Singleton): async with self.__client: logger_mqtt.info('MQTT broker connection established') - if self.__cb_MqttIsUp: - await self.__cb_MqttIsUp() + if self.__cb_mqtt_is_up: + await self.__cb_mqtt_is_up() # async with self.__client.messages() as messages: await self.__client.subscribe(ha_status_topic) @@ -89,7 +89,7 @@ class Mqtt(metaclass=Singleton): f' {status}') if status == 'online': self.ha_restarts += 1 - await self.__cb_MqttIsUp() + await self.__cb_mqtt_is_up() if message.topic.matches(mb_rated_topic): await self.modbus_cmd(message, diff --git a/app/tests/test_infos_g3.py b/app/tests/test_infos_g3.py index d335db8..e811d90 100644 --- a/app/tests/test_infos_g3.py +++ b/app/tests/test_infos_g3.py @@ -4,7 +4,7 @@ from app.src.infos import Register, ClrAtMidnight from app.src.gen3.infos_g3 import InfosG3 @pytest.fixture -def ContrDataSeq(): # Get Time Request message +def contr_data_seq(): # Get Time Request message msg = b'\x00\x00\x00\x15\x00\x09\x2b\xa8\x54\x10\x52\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30\x2e\x30\x36\x00\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f' msg += b'\x6e\x00\x09\x2f\x90\x54\x0b\x52\x53\x57\x2d\x31\x2d\x31\x30\x30\x30\x31\x00\x09\x5a\x88\x54\x0f\x74\x2e\x72\x61\x79\x6d\x6f\x6e\x69\x6f\x74\x2e\x63\x6f\x6d\x00\x09\x5a\xec\x54' msg += b'\x1c\x6c\x6f\x67\x67\x65\x72\x2e\x74\x61\x6c\x65\x6e\x74\x2d\x6d\x6f\x6e\x69\x74\x6f\x72\x69\x6e\x67\x2e\x63\x6f\x6d\x00\x0d\x00\x20\x49\x00\x00\x00\x01\x00\x0c\x35\x00\x49\x00' @@ -14,7 +14,7 @@ def ContrDataSeq(): # Get Time Request message return msg @pytest.fixture -def Contr2DataSeq(): # Get Time Request message +def contr2_data_seq(): # Get Time Request message msg = b'\x00\x00\x00\x39\x00\x09\x2b\xa8\x54\x10\x52' msg += b'\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30\x2e\x32\x30\x00' msg += b'\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f\x6e\x00\x09\x2f\x90\x54' @@ -94,19 +94,19 @@ def Contr2DataSeq(): # Get Time Request message return msg @pytest.fixture -def InvDataSeq(): # Data indication from the controller +def inv_data_seq(): # Data indication from the controller msg = b'\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72\x6f\x69\x6e\x76\x00\x00\x00\x14\x54\x04\x54\x53\x55\x4e\x00\x00\x00\x1E\x54\x07\x56\x35\x2e\x30\x2e\x31\x31\x00\x00\x00\x28' msg += b'\x54\x10T170000000000001\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43' return msg @pytest.fixture -def InvalidDataSeq(): # Data indication from the controller +def invalid_data_seq(): # Data indication from the controller msg = b'\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72\x6f\x69\x6e\x76\x00\x00\x00\x14\x64\x04\x54\x53\x55\x4e\x00\x00\x00\x1E\x54\x07\x56\x35\x2e\x30\x2e\x31\x31\x00\x00\x00\x28' msg += b'\x54\x10T170000000000001\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43' return msg @pytest.fixture -def InvDataSeq2(): # Data indication from the controller +def inv_data_seq2(): # Data indication from the controller msg = b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x02\x00\x00\x01\x2c\x53\x00\x00\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00' msg += b'\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00' msg += b'\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53' @@ -141,7 +141,7 @@ def InvDataSeq2(): # Data indication from the controller return msg @pytest.fixture -def InvDataNew(): # Data indication from DSP V5.0.17 +def inv_data_new(): # Data indication from DSP V5.0.17 msg = b'\x00\x00\x00\xa3\x00\x00\x00\x00\x53\x00\x00' msg += b'\x00\x00\x00\x80\x53\x00\x00\x00\x00\x01\x04\x53\x00\x00\x00\x00' msg += b'\x01\x90\x41\x00\x00\x01\x91\x53\x00\x00\x00\x00\x01\x90\x53\x00' @@ -217,7 +217,7 @@ def InvDataNew(): # Data indication from DSP V5.0.17 return msg @pytest.fixture -def InvDataSeq2_Zero(): # Data indication from the controller +def inv_data_seq2_zero(): # Data indication from the controller msg = b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x02\x00\x00\x01\x2c\x53\x00\x00\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00' msg += b'\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00' msg += b'\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53' @@ -252,37 +252,37 @@ def InvDataSeq2_Zero(): # Data indication from the controller return msg -def test_parse_control(ContrDataSeq): +def test_parse_control(contr_data_seq): i = InfosG3() - for key, result in i.parse (ContrDataSeq): - pass + for key, result in i.parse (contr_data_seq): + pass # side effect in calling i.parse() assert json.dumps(i.db) == json.dumps( {"collector": {"Collector_Fw_Version": "RSW_400_V1.00.06", "Chip_Type": "Raymon", "Chip_Model": "RSW-1-10001", "Trace_URL": "t.raymoniot.com", "Logger_URL": "logger.talent-monitoring.com"}, "controller": {"Collect_Interval": 1, "Signal_Strength": 100, "Power_On_Time": 29, "Communication_Type": 1, "Connect_Count": 1, "Data_Up_Interval": 300}}) -def test_parse_control2(Contr2DataSeq): +def test_parse_control2(contr2_data_seq): i = InfosG3() - for key, result in i.parse (Contr2DataSeq): - pass + for key, result in i.parse (contr2_data_seq): + pass # side effect in calling i.parse() assert json.dumps(i.db) == json.dumps( {"collector": {"Collector_Fw_Version": "RSW_400_V1.00.20", "Chip_Type": "Raymon", "Chip_Model": "RSW-1-10001", "Trace_URL": "t.raymoniot.com", "Logger_URL": "logger.talent-monitoring.com"}, "controller": {"Collect_Interval": 1, "Signal_Strength": 16, "Power_On_Time": 334, "Communication_Type": 1, "Connect_Count": 1, "Data_Up_Interval": 300}}) -def test_parse_inverter(InvDataSeq): +def test_parse_inverter(inv_data_seq): i = InfosG3() - for key, result in i.parse (InvDataSeq): - pass + for key, result in i.parse (inv_data_seq): + pass # side effect in calling i.parse() assert json.dumps(i.db) == json.dumps( {"inverter": {"Product_Name": "Microinv", "Manufacturer": "TSUN", "Version": "V5.0.11", "Serial_Number": "T170000000000001", "Equipment_Model": "TSOL-MS600"}}) -def test_parse_cont_and_invert(ContrDataSeq, InvDataSeq): +def test_parse_cont_and_invert(contr_data_seq, inv_data_seq): i = InfosG3() - for key, result in i.parse (ContrDataSeq): - pass + for key, result in i.parse (contr_data_seq): + pass # side effect in calling i.parse() - for key, result in i.parse (InvDataSeq): - pass + for key, result in i.parse (inv_data_seq): + pass # side effect in calling i.parse() assert json.dumps(i.db) == json.dumps( { @@ -290,7 +290,7 @@ def test_parse_cont_and_invert(ContrDataSeq, InvDataSeq): "inverter": {"Product_Name": "Microinv", "Manufacturer": "TSUN", "Version": "V5.0.11", "Serial_Number": "T170000000000001", "Equipment_Model": "TSOL-MS600"}}) -def test_build_ha_conf1(ContrDataSeq): +def test_build_ha_conf1(contr_data_seq): i = InfosG3() i.static_init() # initialize counter @@ -346,14 +346,14 @@ def test_build_ha_conf1(ContrDataSeq): assert tests==5 -def test_build_ha_conf2(ContrDataSeq, InvDataSeq, InvDataSeq2): +def test_build_ha_conf2(contr_data_seq, inv_data_seq, inv_data_seq2): i = InfosG3() - for key, result in i.parse (ContrDataSeq): - pass - for key, result in i.parse (InvDataSeq): - pass - for key, result in i.parse (InvDataSeq2): - pass + for key, result in i.parse (contr_data_seq): + pass # side effect in calling i.parse() + for key, result in i.parse (inv_data_seq): + pass # side effect in calling i.parse() + for key, result in i.parse (inv_data_seq2): + pass # side effect in calling i.parse() tests = 0 for d_json, comp, node_id, id in i.ha_confs(ha_prfx="tsun/", node_id="garagendach/", snr='123', sug_area = 'roof'): @@ -384,10 +384,10 @@ def test_build_ha_conf2(ContrDataSeq, InvDataSeq, InvDataSeq2): tests +=1 assert tests==5 -def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero): +def test_must_incr_total(inv_data_seq2, inv_data_seq2_zero): i = InfosG3() tests = 0 - for key, update in i.parse (InvDataSeq2): + for key, update in i.parse (inv_data_seq2): if key == 'total' or key == 'inverter' or key == 'env': assert update == True tests +=1 @@ -396,7 +396,7 @@ def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero): assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 64.5, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 45.7, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}}) assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 23}) tests = 0 - for key, update in i.parse (InvDataSeq2): + for key, update in i.parse (inv_data_seq2): if key == 'total': assert update == False tests +=1 @@ -411,7 +411,7 @@ def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero): assert json.dumps(i.db['inverter']) == json.dumps({"Rated_Power": 600, "No_Inputs": 2}) tests = 0 - for key, update in i.parse (InvDataSeq2_Zero): + for key, update in i.parse (inv_data_seq2_zero): if key == 'total': assert update == False tests +=1 @@ -424,10 +424,10 @@ def test_must_incr_total(InvDataSeq2, InvDataSeq2_Zero): assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 0.0, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 0.0, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}}) assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0}) -def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero): +def test_must_incr_total2(inv_data_seq2, inv_data_seq2_zero): i = InfosG3() tests = 0 - for key, update in i.parse (InvDataSeq2_Zero): + for key, update in i.parse (inv_data_seq2_zero): if key == 'total': assert update == False tests +=1 @@ -441,7 +441,7 @@ def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero): assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0}) tests = 0 - for key, update in i.parse (InvDataSeq2_Zero): + for key, update in i.parse (inv_data_seq2_zero): if key == 'total': assert update == False tests +=1 @@ -455,7 +455,7 @@ def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero): assert json.dumps(i.db['env']) == json.dumps({"Inverter_Temp": 0}) tests = 0 - for key, update in i.parse (InvDataSeq2): + for key, update in i.parse (inv_data_seq2): if key == 'total': assert update == True tests +=1 @@ -467,10 +467,10 @@ def test_must_incr_total2(InvDataSeq2, InvDataSeq2_Zero): assert json.dumps(i.db['total']) == json.dumps({'Daily_Generation': 1.7, 'Total_Generation': 17.36}) assert json.dumps(i.db['input']) == json.dumps({"pv1": {"Voltage": 33.6, "Current": 1.91, "Power": 64.5, "Daily_Generation": 1.08, "Total_Generation": 9.74}, "pv2": {"Voltage": 33.5, "Current": 1.36, "Power": 45.7, "Daily_Generation": 0.62, "Total_Generation": 7.62}, "pv3": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}, "pv4": {"Voltage": 0.0, "Current": 0.0, "Power": 0.0}}) -def test_new_data_types(InvDataNew): +def test_new_data_types(inv_data_new): i = InfosG3() tests = 0 - for key, update in i.parse (InvDataNew): + for key, update in i.parse (inv_data_new): if key == 'events': tests +=1 elif key == 'inverter': @@ -487,7 +487,7 @@ def test_new_data_types(InvDataNew): assert json.dumps(i.db['input']) == json.dumps({"pv1": {}}) assert json.dumps(i.db['events']) == json.dumps({"401_": 0, "404_": 0, "405_": 0, "408_": 0, "409_No_Utility": 0, "406_": 0, "416_": 0}) -def test_invalid_data_type(InvalidDataSeq): +def test_invalid_data_type(invalid_data_seq): i = InfosG3() i.static_init() # initialize counter @@ -495,8 +495,8 @@ def test_invalid_data_type(InvalidDataSeq): assert val == 0 - for key, result in i.parse (InvalidDataSeq): - pass + for key, result in i.parse (invalid_data_seq): + pass # side effect in calling i.parse() assert json.dumps(i.db) == json.dumps({"inverter": {"Product_Name": "Microinv"}}) val = i.dev_value(Register.INVALID_DATA_TYPE) # check invalid data type counter diff --git a/app/tests/test_solarman.py b/app/tests/test_solarman.py index 6a23e93..7ead651 100644 --- a/app/tests/test_solarman.py +++ b/app/tests/test_solarman.py @@ -3,6 +3,7 @@ import struct import time import asyncio import logging +from math import isclose from app.src.gen3plus.solarman_v5 import SolarmanV5 from app.src.config import Config from app.src.infos import Infos, Register @@ -1665,7 +1666,7 @@ async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp m._send_buffer = bytearray(0) # clear send buffer for next test assert m.state == State.up - assert m.mb_timeout == 0.5 + assert isclose(m.mb_timeout, 0.5) assert next(m.mb_timer.exp_count) == 0 await asyncio.sleep(0.5) @@ -1695,14 +1696,14 @@ async def test_start_client_mode(config_tsun_inv1): await m.send_start_cmd(get_sn_int(), '192.168.1.1', m.mb_first_timeout) assert m.writer.sent_pdu==bytearray(b'\xa5\x17\x00\x10E\x01\x00!Ce{\x02\xb0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x030\x00\x000J\xde\xf1\x15') assert m.db.get_db_value(Register.IP_ADDRESS) == '192.168.1.1' - assert m.db.get_db_value(Register.POLLING_INTERVAL) == 0.5 + assert isclose(m.db.get_db_value(Register.POLLING_INTERVAL), 0.5) assert m.db.get_db_value(Register.HEARTBEAT_INTERVAL) == 120 assert m.state == State.up assert m.no_forwarding == True assert m._send_buffer==b'' - assert m.mb_timeout == 0.5 + assert isclose(m.mb_timeout, 0.5) assert next(m.mb_timer.exp_count) == 0 await asyncio.sleep(0.5) diff --git a/app/tests/test_talent.py b/app/tests/test_talent.py index 5c9a9d7..cf70cd1 100644 --- a/app/tests/test_talent.py +++ b/app/tests/test_talent.py @@ -1,5 +1,6 @@ # test_with_pytest.py import pytest, logging, asyncio +from math import isclose from app.src.gen3.talent import Talent, Control from app.src.config import Config from app.src.infos import Infos, Register @@ -1023,7 +1024,7 @@ def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack): assert m._forward_buffer==msg_inverter_ind_0w assert m._send_buffer==msg_inverter_ack assert m.db.get_db_value(Register.INVERTER_STATUS) == None - assert m.db.db['grid']['Output_Power'] == 0.5 + assert isclose(m.db.db['grid']['Output_Power'], 0.5) m.close() assert m.db.get_db_value(Register.INVERTER_STATUS) == 0 @@ -1206,15 +1207,15 @@ def test_timestamp_cnv(): m = MemoryStream(b'') ts = 1722645998453 # Saturday, 3. August 2024 00:46:38.453 (GMT+2:00) utc =1722638798.453 # GMT: Friday, 2. August 2024 22:46:38.453 - assert utc == m._utcfromts(ts) + assert isclose(utc, m._utcfromts(ts)) ts = 1691246944000 # Saturday, 5. August 2023 14:49:04 (GMT+2:00) utc =1691239744.0 # GMT: Saturday, 5. August 2023 12:49:04 - assert utc == m._utcfromts(ts) + assert isclose(utc, m._utcfromts(ts)) ts = 1704152544000 # Monday, 1. January 2024 23:42:24 (GMT+1:00) utc =1704148944.0 # GMT: Monday, 1. January 2024 22:42:24 - assert utc == m._utcfromts(ts) + assert isclose(utc, m._utcfromts(ts)) m.close() @@ -1581,7 +1582,7 @@ async def test_modbus_polling(config_tsun_inv1, msg_inverter_ind): assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m._send_buffer = bytearray(0) # clear send buffer for next test - assert m.mb_timeout == 0.5 + assert isclose(m.mb_timeout, 0.5) assert next(m.mb_timer.exp_count) == 0 await asyncio.sleep(0.5)