diff --git a/app/src/gen3plus/infos_g3p.py b/app/src/gen3plus/infos_g3p.py index b42b2be..55fdb6a 100644 --- a/app/src/gen3plus/infos_g3p.py +++ b/app/src/gen3plus/infos_g3p.py @@ -5,6 +5,21 @@ from itertools import chain from infos import Infos, Register, ProxyMode, Fmt +class RegisterFunc: + @staticmethod + def prod_sum(info: Infos, arr: dict) -> None | int: + result = 0 + for sum in arr: + prod = 1 + for factor in sum: + val = info.get_db_value(factor) + if val is None: + return None + prod = prod * val + result += prod + return result + + class RegisterMap: # make the class read/only by using __slots__ __slots__ = () @@ -121,11 +136,11 @@ class RegisterMap: 0x42010034: {'reg': Register.BATT_PV2_VOLT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 voltage 0x42010036: {'reg': Register.BATT_PV2_CUR, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, PV2 current 0x42010038: {'reg': Register.BATT_38, 'fmt': '!h'}, # noqa: E501 - 0x4201003a: {'reg': Register.BATT_3a, 'fmt': '!h'}, # noqa: E501 - 0x4201003c: {'reg': Register.BATT_3c, 'fmt': '!h'}, # noqa: E501 - 0x4201003e: {'reg': Register.BATT_3e, 'fmt': '!h'}, # noqa: E501 - 0x42010040: {'reg': Register.BATT_40, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 - 0x42010042: {'reg': Register.BATT_42, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 + 0x4201003a: {'reg': Register.BATT_3a, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 + 0x4201003c: {'reg': Register.BATT_STATUS_1, 'fmt': '!h'}, # noqa: E501 + 0x4201003e: {'reg': Register.BATT_STATUS_2, 'fmt': '!h'}, # noqa: E501 + 0x42010040: {'reg': Register.BATT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 + 0x42010042: {'reg': Register.BATT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 0x42010044: {'reg': Register.BATT_SOC, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501, state of charge (SOC) in percent 0x42010046: {'reg': Register.BATT_46, 'fmt': '!h'}, # noqa: E501 0x42010048: {'reg': Register.BATT_48, 'fmt': '!h'}, # noqa: E501 @@ -136,13 +151,22 @@ class RegisterMap: 0x42010066: {'reg': Register.BATT_66, 'fmt': '!h'}, # noqa: E501 0x42010068: {'reg': Register.BATT_68, 'fmt': '!h'}, # noqa: E501 0x4201006a: {'reg': Register.BATT_6a, 'fmt': '!h'}, # noqa: E501 - 0x4201006c: {'reg': Register.BATT_6c, 'fmt': '!h'}, # noqa: E501 - 0x4201006e: {'reg': Register.BATT_6e, 'fmt': '!h'}, # noqa: E501 + 0x4201006c: {'reg': Register.BATT_OUT_VOLT, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 + 0x4201006e: {'reg': Register.BATT_OUT_CUR, 'fmt': '!h', 'ratio': 0.01}, # noqa: E501 0x42010070: {'reg': Register.BATT_70, 'fmt': '!h'}, # noqa: E501 0x42010072: {'reg': Register.BATT_72, 'fmt': '!h'}, # noqa: E501 0x42010074: {'reg': Register.BATT_74, 'fmt': '!h'}, # noqa: E501 0x42010076: {'reg': Register.BATT_76, 'fmt': '!h'}, # noqa: E501 0x42010078: {'reg': Register.BATT_78, 'fmt': '!h'}, # noqa: E501 + 'calc': { + 1: {'reg': Register.BATT_PV_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 + 'params': [[Register.BATT_PV1_VOLT, Register.BATT_PV1_CUR], + [Register.BATT_PV2_VOLT, Register.BATT_PV2_CUR]]}, + 2: {'reg': Register.BATT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 + 'params': [[Register.BATT_VOLT, Register.BATT_CUR]]}, + 3: {'reg': Register.BATT_OUT_PWR, 'func': RegisterFunc.prod_sum, # noqa: E501 + 'params': [[Register.BATT_OUT_VOLT, Register.BATT_OUT_CUR]]}, + } } @@ -191,13 +215,20 @@ class InfosG3P(Infos): # iterate over RegisterMap.map and get the register values sensor = self.get_db_value(Register.SENSOR_LIST) if "3026" == sensor: - items = RegisterMap.map_3026.items() + reg_map = RegisterMap.map_3026 elif "02b0" == sensor: - items = RegisterMap.map_02b0.items() + reg_map = RegisterMap.map_02b0 else: - items = {} + reg_map = {} + items = reg_map.items() + if 'calc' in reg_map: + virt = reg_map['calc'].items() + else: + virt = {} - for _, row in chain(RegisterMap.map.items(), items): + for idx, row in chain(RegisterMap.map.items(), items, virt): + if 'calc' == idx: + continue info_id = row['reg'] if self.__hide_topic(row): res = self.ha_remove(info_id, node_id, snr) # noqa: E501 @@ -213,7 +244,10 @@ class InfosG3P(Infos): stores the values in Infos.db buf: buffer of the sequence to parse''' - for idx, row in RegisterSel.get(sensor).items(): + reg_map = RegisterSel.get(sensor) + for idx, row in reg_map.items(): + if 'calc' == idx: + continue addr = idx & 0xffff ftype = (idx >> 16) & 0xff mtype = (idx >> 24) & 0xff @@ -223,16 +257,19 @@ class InfosG3P(Infos): continue info_id = row['reg'] result = Fmt.get_value(buf, addr, row) + yield from self.__update_val(node_id, info_id, result) - keys, level, unit, must_incr = self._key_obj(info_id) - - if keys: - name, update = self.update_db(keys, must_incr, result) - yield keys[0], update - else: - name = str(f'info-id.0x{addr:x}') - update = False + if 'calc' in reg_map: + for row in reg_map['calc'].values(): + info_id = row['reg'] + result = row['func'](self, row['params']) + yield from self.__update_val(node_id, info_id, result) + def __update_val(self, node_id, info_id, result): + keys, level, unit, must_incr = self._key_obj(info_id) + if keys: + name, update = self.update_db(keys, must_incr, result) + yield keys[0], update if update: self.tracer.log(level, f'[{node_id}] GEN3PLUS: {name}' f' : {result}{unit}') diff --git a/app/src/infos.py b/app/src/infos.py index 2212d78..2e752d8 100644 --- a/app/src/infos.py +++ b/app/src/infos.py @@ -127,10 +127,10 @@ class Register(Enum): BATT_PV2_CUR = 1003 BATT_38 = 1004 BATT_3a = 1005 - BATT_3c = 1006 - BATT_3e = 1007 - BATT_40 = 1010 - BATT_42 = 1011 + BATT_STATUS_1 = 1006 + BATT_STATUS_2 = 1007 + BATT_VOLT = 1010 + BATT_CUR = 1011 BATT_SOC = 1012 BATT_46 = 1013 BATT_48 = 1014 @@ -140,13 +140,17 @@ class Register(Enum): BATT_66 = 1018 BATT_68 = 1019 BATT_6a = 1020 - BATT_6c = 1021 - BATT_6e = 1022 + BATT_OUT_VOLT = 1021 + BATT_OUT_CUR = 1022 BATT_70 = 1023 BATT_72 = 1024 BATT_74 = 1025 BATT_76 = 1026 BATT_78 = 1027 + BATT_PV_PWR = 1040 + BATT_PWR = 1041 + BATT_OUT_PWR = 1042 + VALUE_1 = 9000 TEST_REG1 = 10000 TEST_REG2 = 10001 @@ -157,7 +161,10 @@ class Fmt: def get_value(buf: bytes, idx: int, row: dict): '''Get a value from buf and interpret as in row defined''' fmt = row['fmt'] - res = struct.unpack_from(fmt, buf, idx) + try: + res = struct.unpack_from(fmt, buf, idx) + except Exception: + return None result = res[0] if isinstance(result, (bytearray, bytes)): result = result.decode().split('\x00')[0] @@ -572,12 +579,12 @@ class Infos: Register.BATT_PV2_VOLT: {'name': ['batterie', 'pv2', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_pv2_', 'val_tpl': "{{ (value_json['pv2']['Voltage'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_PV2_CUR: {'name': ['batterie', 'pv2', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'bat_inp_pv2', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_pv2_', 'val_tpl': "{{ (value_json['pv2']['Current'] | float)}}", 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_38: {'name': ['batterie', 'Reg_38'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_38_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_3a: {'name': ['batterie', 'Reg_3a'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3a_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_3c: {'name': ['batterie', 'Reg_3c'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3c_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_3e: {'name': ['batterie', 'Reg_3e'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3e_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_40: {'name': ['batterie', 'Reg_40'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_40_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_42: {'name': ['batterie', 'Reg_42'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_42_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_SOC: {'name': ['batterie', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'fmt': FMT_FLOAT, 'name': 'State of Charge', 'icon': 'mdi:battery-90'}}, # noqa: E501 + Register.BATT_3a: {'name': ['batterie', 'Reg_3a'], 'level': logging.INFO, 'unit': 'kWh', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_3a_', 'fmt': FMT_FLOAT, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_STATUS_1: {'name': ['batterie', 'Status_1'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status1_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_STATUS_2: {'name': ['batterie', 'Status_2'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'status2_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_VOLT: {'name': ['batterie', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'volt_bat_', 'fmt': FMT_FLOAT, 'name': 'Bat Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_CUR: {'name': ['batterie', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'cur_bat_', 'fmt': FMT_FLOAT, 'name': 'Bat Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_SOC: {'name': ['batterie', 'SOC'], 'level': logging.INFO, 'unit': '%', 'ha': {'dev': 'batterie', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'soc_', 'fmt': FMT_FLOAT, 'name': 'State of Charge (SOC)', 'icon': 'mdi:battery-90'}}, # noqa: E501 # Register.BATT_46: {'name': ['batterie', 'Reg_46'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_46_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 # Register.BATT_48: {'name': ['batterie', 'Reg_48'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_48_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 # Register.BATT_4a: {'name': ['batterie', 'Reg_4a'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_4a_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 @@ -587,13 +594,16 @@ class Infos: Register.BATT_66: {'name': ['batterie', 'Reg_66'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_66_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_68: {'name': ['batterie', 'Reg_68'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_68_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_6a: {'name': ['batterie', 'Reg_6a'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_6a_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_6c: {'name': ['batterie', 'Reg_6c'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_6c_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.BATT_6e: {'name': ['batterie', 'Reg_6e'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_6e_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_OUT_VOLT: {'name': ['batterie', 'out', 'Voltage'], 'level': logging.INFO, 'unit': 'V', 'ha': {'dev': 'batterie', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id': 'out_volt_', 'val_tpl': "{{ (value_json['out']['Voltage'] | float)}}", 'name': 'Out Voltage', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_OUT_CUR: {'name': ['batterie', 'out', 'Current'], 'level': logging.INFO, 'unit': 'A', 'ha': {'dev': 'batterie', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'out_cur_', 'val_tpl': "{{ (value_json['out']['Current'] | float)}}", 'name': 'Out Current', 'icon': GAUGE, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_70: {'name': ['batterie', 'Reg_70'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_70_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_72: {'name': ['batterie', 'Reg_72'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_72_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_74: {'name': ['batterie', 'Reg_74'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_74_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_76: {'name': ['batterie', 'Reg_76'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_76_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.BATT_78: {'name': ['batterie', 'Reg_78'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'batt_78_', 'fmt': FMT_INT, 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.BATT_PV_PWR: {'name': ['batterie', 'PV_Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'pv_power_', 'fmt': FMT_INT, 'name': 'PV Power'}}, # noqa: E501 + Register.BATT_PWR: {'name': ['batterie', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'power_', 'fmt': FMT_INT, 'name': 'Batterie Power'}}, # noqa: E501 + Register.BATT_OUT_PWR: {'name': ['batterie', 'out', 'Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'batterie', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'out_power_', 'val_tpl': "{{ (value_json['out']['Power'] | int)}}", 'name': 'Out Power'}}, # noqa: E501 } @property diff --git a/app/tests/test_infos_g3p.py b/app/tests/test_infos_g3p.py index f49cb50..366743d 100644 --- a/app/tests/test_infos_g3p.py +++ b/app/tests/test_infos_g3p.py @@ -70,6 +70,28 @@ def inverter_data(): # 0x4210 ftype: 0x01 msg += b'\x00\x00\x00\x00' return msg +@pytest.fixture +def batterie_data(): # 0x4210 ftype: 0x01 + msg = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x26\x30\xc7\xde' + msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00' + msg += b'\x34\x31\x30\x31\x32\x34\x30\x37\x30\x31\x34\x39\x30\x33\x31\x34' + msg += b'\x0d\x3a\x00\x70\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00' + msg += b'\x14\x0e\xff\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89' + msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89' + msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e\x00\x00' + msg += b'\x00\x00\x00\x0f\x00\x00\x02\x05\x02\x01' + return msg + +@pytest.fixture +def batterie_data2(): # 0x4210 ftype: 0x01 + msg = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x26\x30\xc7\xde' + msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00' + msg += b'\x34\x31\x30\x31\x32\x34\x30\x37\x30\x31\x34\x39\x30\x33\x31\x34' + msg += b'\x0d\x3a\x00\x70\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00' + msg += b'\x14\x0e\xff\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89' + msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89' + msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e' + return msg def test_default_db(): i = InfosG3P(client_mode=False) @@ -101,7 +123,7 @@ def test_build_4110(str_test_ip, device_data: bytes): build_msg[i] = device_data[i] assert device_data == build_msg -def test_parse_4210(inverter_data: bytes): +def test_parse_4210_02b0(inverter_data: bytes): i = InfosG3P(client_mode=False) i.db.clear() @@ -123,6 +145,46 @@ def test_parse_4210(inverter_data: bytes): "other": {"Output_Shutdown": 65535, "Rated_Level": 3, "Grid_Volt_Cal_Coef": 1024, "Prod_Compliance_Type": 6} }) +def test_parse_4210_3026(batterie_data: bytes): + i = InfosG3P(client_mode=False) + i.db.clear() + + for key, update in i.parse (batterie_data, 0x42, 1, 0x3026): + pass # side effect is calling generator i.parse() + + assert json.dumps(i.db) == json.dumps({ + "controller": {"Sensor_List": "3026", "Power_On_Time": 4684}, + "inverter": {"Serial_Number": "4101240701490314"}, + "batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12}, + "pv2": {"Voltage": 33.72, "Current": 0.0}, + "Reg_38": 0, "Reg_3a": 20.8, "Status_1": 0, "Status_2": 0, + "Voltage": 51.34, "Current": -0.02, "SOC": 10.0, "Reg_66": 15, + "Reg_68": 15, "Reg_6a": 15, + "out": {"Voltage": 0.14, "Current": 0.0, "Power": 0.0}, + "Reg_70": 0, "Reg_72": 15, "Reg_74": 0, "Reg_76": 517, "Reg_78": 513, + "PV_Power": 37.9232, "Power": -1.0268000000000002}, + }) + +def test_parse_4210_3026_incomplete(batterie_data2: bytes): + i = InfosG3P(client_mode=False) + i.db.clear() + + for key, update in i.parse (batterie_data2, 0x42, 1, 0x3026): + pass # side effect is calling generator i.parse() + + assert json.dumps(i.db) == json.dumps({ + "controller": {"Sensor_List": "3026", "Power_On_Time": 4684}, + "inverter": {"Serial_Number": "4101240701490314"}, + "batterie": {"pv1": {"Voltage": 33.86, "Current": 1.12}, + "pv2": {"Voltage": 33.72, "Current": 0.0}, + "Reg_38": 0, "Reg_3a": 20.8, "Status_1": 0, "Status_2": 0, + "Voltage": 51.34, "Current": -0.02, "SOC": 10.0, "Reg_66": 15, + "Reg_68": 15, "Reg_6a": 15, + "out": {"Voltage": 0.14, "Current": None, "Power": None}, + "Reg_70": None, "Reg_72": None, "Reg_74": None, "Reg_76": None, "Reg_78": None, + "PV_Power": 37.9232, "Power": -1.0268000000000002}, + }) + def test_build_4210(inverter_data: bytes): i = InfosG3P(client_mode=False) i.db.clear() @@ -294,25 +356,29 @@ def test_build_ha_conf5(): for d_json, comp, node_id, id in i.ha_confs(ha_prfx="tsun/", node_id="garagendach/", snr='123'): if id == 'out_power_123': - assert False + assert comp == 'sensor' + assert d_json == json.dumps({"name": "Out Power", "stat_t": "tsun/garagendach/batterie", "dev_cla": "power", "stat_cla": "measurement", "uniq_id": "out_power_123", "val_tpl": "{{ (value_json['out']['Power'] | int)}}", "unit_of_meas": "W", "dev": {"name": "Batterie", "sa": "Batterie", "via_device": "controller_123", "mdl": "TSOL-MSxx00", "mf": "TSUN", "ids": ["batterie_123"]}, "o": {"name": "proxy", "sw": "unknown"}}) + tests +=1 elif id == 'daily_gen_123': assert False - elif id == 'power_pv1_123': - assert False - elif id == 'power_pv2_123': - assert False - elif id == 'power_pv3_123': - assert False - elif id == 'power_pv4_123': - assert False + elif id == 'volt_pv1_123': + assert comp == 'sensor' + assert d_json == json.dumps({"name": "Voltage", "stat_t": "tsun/garagendach/batterie", "dev_cla": "voltage", "stat_cla": "measurement", "uniq_id": "volt_pv1_123", "val_tpl": "{{ (value_json['pv1']['Voltage'] | float)}}", "unit_of_meas": "V", "ic": "mdi:gauge", "ent_cat": "diagnostic", "dev": {"name": "Module PV1", "sa": "Module PV1", "via_device": "batterie_123", "ids": ["bat_inp_pv1_123"]}, "o": {"name": "proxy", "sw": "unknown"}}) + tests +=1 + elif id == 'volt_pv2_123': + assert comp == 'sensor' + assert d_json == json.dumps({"name": "Voltage", "stat_t": "tsun/garagendach/batterie", "dev_cla": "voltage", "stat_cla": "measurement", "uniq_id": "volt_pv2_123", "val_tpl": "{{ (value_json['pv2']['Voltage'] | float)}}", "unit_of_meas": "V", "ic": "mdi:gauge", "ent_cat": "diagnostic", "dev": {"name": "Module PV2", "sa": "Module PV2", "via_device": "batterie_123", "ids": ["bat_inp_pv2_123"]}, "o": {"name": "proxy", "sw": "unknown"}}) + tests +=1 elif id == 'signal_123': assert comp == 'sensor' assert d_json == json.dumps({}) tests +=1 elif id == 'inv_count_456': assert False + else: + print(id) - assert tests==1 + assert tests==4 def test_exception_and_calc(inverter_data: bytes): diff --git a/system_tests/test_tcp_socket_v2.py b/system_tests/test_tcp_socket_v2.py index 4bf904b..94816fd 100644 --- a/system_tests/test_tcp_socket_v2.py +++ b/system_tests/test_tcp_socket_v2.py @@ -151,7 +151,7 @@ def dcu_data_ind_msg(): # 0x4210 msg = b'\xa5\x6f\x00\x10\x42\x92\x02' +get_dcu_sn() +b'\x01\x26\x30\xc7\xde' msg += b'\x2d\x32\x28\x00\x00\x00\x84\x17\x79\x35\x01\x00\x4c\x12\x00\x00' msg += get_dcu_no() - msg += b'\x0d\x3a\x00\x00\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00' + msg += b'\x0d\x3a\x00\x0a\x0d\x2c\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00' msg += b'\x14\x0e\xff\xfe\x03\xe8\x0c\x89\x0c\x89\x0c\x89\x0c\x8a\x0c\x89' msg += b'\x0c\x89\x0c\x8a\x0c\x89\x0c\x89\x0c\x8a\x0c\x8a\x0c\x89\x0c\x89' msg += b'\x0c\x89\x0c\x89\x0c\x88\x00\x0f\x00\x0f\x00\x0f\x00\x0e\x00\x00'