From ef8a461569d9d2361563cfe2f30d5f1724edb08d Mon Sep 17 00:00:00 2001 From: Stefan Allius Date: Mon, 1 Apr 2024 20:05:51 +0200 Subject: [PATCH] build gen 3 inverter modell name --- app/src/gen3plus/infos_g3p.py | 2 +- app/src/gen3plus/solarman_v5.py | 24 +++++++++++++++++++++++- app/src/infos.py | 19 +++++++++++++++++-- app/tests/test_solarman.py | 31 ++++++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/app/src/gen3plus/infos_g3p.py b/app/src/gen3plus/infos_g3p.py index 3920486..fddc4b4 100644 --- a/app/src/gen3plus/infos_g3p.py +++ b/app/src/gen3plus/infos_g3p.py @@ -76,7 +76,7 @@ class InfosG3P(Infos): def __init__(self): super().__init__() self.set_db_def_value(Register.MANUFACTURER, 'TSUN') - self.set_db_def_value(Register.EQUIPMENT_MODEL, 'TSOL-MS2000') + self.set_db_def_value(Register.EQUIPMENT_MODEL, 'TSOL-MSxx00') self.set_db_def_value(Register.CHIP_TYPE, 'IGEN TECH') def ha_confs(self, ha_prfx: str, node_id: str, snr: str, diff --git a/app/src/gen3plus/solarman_v5.py b/app/src/gen3plus/solarman_v5.py index c58b51a..1016382 100644 --- a/app/src/gen3plus/solarman_v5.py +++ b/app/src/gen3plus/solarman_v5.py @@ -1,4 +1,5 @@ import struct +# import json import logging # import time from datetime import datetime @@ -7,10 +8,12 @@ if __name__ == "app.src.gen3plus.solarman_v5": from app.src.messages import hex_dump_memory, Message from app.src.config import Config from app.src.gen3plus.infos_g3p import InfosG3P + from app.src.infos import Register else: # pragma: no cover from messages import hex_dump_memory, Message from config import Config from gen3plus.infos_g3p import InfosG3P + from infos import Register # import traceback logger = logging.getLogger('msg') @@ -76,7 +79,7 @@ class SolarmanV5(Message): inverters = Config.get('inverters') # logger.debug(f'Inverters: {inverters}') - for key, inv in inverters.items(): + for inv in inverters.values(): # logger.debug(f'key: {key} -> {inv}') if (type(inv) is dict and 'monitor_sn' in inv and inv['monitor_sn'] == snr): @@ -300,11 +303,30 @@ class SolarmanV5(Message): self.forward(self._recv_buffer, self.header_len+self.data_len+2) def __process_data(self, ftype): + inv_update = False msg_type = self.control >> 8 for key, update in self.db.parse(self._recv_buffer, msg_type, ftype): if update: + if key == 'inverter': + inv_update = True self.new_data[key] = True + if inv_update: + db = self.db + MaxPow = db.get_db_value(Register.MAX_DESIGNED_POWER, 0) + Rated = db.get_db_value(Register.RATED_POWER, 0) + Model = None + if MaxPow == 2000: + if Rated == 800 or Rated == 600: + Model = f'TSOL-MS{MaxPow}({Rated})' + else: + Model = f'TSOL-MS{MaxPow}' + elif MaxPow == 1800 or MaxPow == 1600: + Model = f'TSOL-MS{MaxPow}' + if Model: + logger.info(f'Model: {Model}') + self.db.set_db_def_value(Register.EQUIPMENT_MODEL, Model) + def msg_data_rsp(self): self.msg_response() diff --git a/app/src/infos.py b/app/src/infos.py index f72661d..3a9640a 100644 --- a/app/src/infos.py +++ b/app/src/infos.py @@ -148,6 +148,8 @@ class Infos: Register.SERIAL_NUMBER: {'name': ['inverter', 'Serial_Number'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501 Register.EQUIPMENT_MODEL: {'name': ['inverter', 'Equipment_Model'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501 Register.NO_INPUTS: {'name': ['inverter', 'No_Inputs'], 'level': logging.DEBUG, 'unit': ''}, # noqa: E501 + Register.MAX_DESIGNED_POWER: {'name': ['inverter', 'Max_Designed_Power'], 'level': logging.DEBUG, 'unit': 'W', 'ha': {'dev': 'inverter', 'dev_cla': None, 'stat_cla': None, 'id': 'designed_power_', 'fmt': '| string + " W"', 'name': 'Max Designed Power', 'icon': 'mdi:lightning-bolt', 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.RATED_POWER: {'name': ['inverter', 'Rated_Power'], 'level': logging.DEBUG, 'unit': 'W', 'ha': {'dev': 'inverter', 'dev_cla': None, 'stat_cla': None, 'id': 'rated_power_', 'fmt': '| string + " W"', 'name': 'Rated Power', 'icon': 'mdi:lightning-bolt', 'ent_cat': 'diagnostic'}}, # noqa: E501 # proxy: Register.INVERTER_CNT: {'name': ['proxy', 'Inverter_Cnt'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_count_', 'fmt': '| int', 'name': 'Active Inverter Connections', 'icon': 'mdi:counter'}}, # noqa: E501 @@ -185,8 +187,6 @@ class Infos: Register.GRID_CURRENT: {'name': ['grid', 'Current'], 'level': logging.DEBUG, 'unit': 'A', 'ha': {'dev': 'inverter', 'dev_cla': 'current', 'stat_cla': 'measurement', 'id': 'out_cur_', 'fmt': '| float', 'name': 'Grid Current', 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.GRID_FREQUENCY: {'name': ['grid', 'Frequency'], 'level': logging.DEBUG, 'unit': 'Hz', 'ha': {'dev': 'inverter', 'dev_cla': 'frequency', 'stat_cla': 'measurement', 'id': 'out_freq_', 'fmt': '| float', 'name': 'Grid Frequency', 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.OUTPUT_POWER: {'name': ['grid', 'Output_Power'], 'level': logging.INFO, 'unit': 'W', 'ha': {'dev': 'inverter', 'dev_cla': 'power', 'stat_cla': 'measurement', 'id': 'out_power_', 'fmt': '| float', 'name': 'Power'}}, # noqa: E501 - Register.RATED_POWER: {'name': ['env', 'Rated_Power'], 'level': logging.DEBUG, 'unit': 'W', 'ha': {'dev': 'inverter', 'dev_cla': None, 'stat_cla': None, 'id': 'rated_power_', 'fmt': '| string + " W"', 'name': 'Rated Power', 'icon': 'mdi:lightning-bolt', 'ent_cat': 'diagnostic'}}, # noqa: E501 - Register.MAX_DESIGNED_POWER: {'name': ['env', 'Max_Designed_Power'], 'level': logging.DEBUG, 'unit': 'W', 'ha': {'dev': 'inverter', 'dev_cla': None, 'stat_cla': None, 'id': 'designed_power_', 'fmt': '| string + " W"', 'name': 'Max Designed Power', 'icon': 'mdi:lightning-bolt', 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.INVERTER_TEMP: {'name': ['env', 'Inverter_Temp'], 'level': logging.DEBUG, 'unit': '°C', 'ha': {'dev': 'inverter', 'dev_cla': 'temperature', 'stat_cla': 'measurement', 'id': 'temp_', 'fmt': '| int', 'name': 'Temperature'}}, # noqa: E501 Register.VALUE_1: {'name': ['env', 'Value_1'], 'level': logging.INFO, 'unit': '', 'ha': {'dev': 'inverter', 'dev_cla': None, 'stat_cla': 'measurement', 'id': 'value_1_', 'fmt': '| int', 'name': 'Value 1', 'ent_cat': 'diagnostic'}}, # noqa: E501 @@ -441,6 +441,21 @@ class Infos: keys = row['name'] self.update_db(keys, False, value) + def get_db_value(self, id, not_found_result=None): + '''get database value''' + row = self.info_defs[id] + if isinstance(row, dict): + keys = row['name'] + elm = self.db + for key in keys[:-1]: + if key not in elm: + return not_found_result + elm = elm[key] + + if keys[-1] in elm: + return elm[keys[-1]] + return not_found_result + def ignore_this_device(self, dep: dict) -> bool: '''Checks the equation in the dep dict diff --git a/app/tests/test_solarman.py b/app/tests/test_solarman.py index 52de01c..ebf57c1 100644 --- a/app/tests/test_solarman.py +++ b/app/tests/test_solarman.py @@ -1,7 +1,7 @@ import pytest, json from app.src.gen3plus.solarman_v5 import SolarmanV5 from app.src.config import Config -from app.src.infos import Infos +from app.src.infos import Infos, Register # initialize the proxy statistics Infos.static_init() @@ -617,3 +617,32 @@ def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg): assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0 assert m.db.stat['proxy']['AT_Command'] == 1 m.close() + +def test_build_modell(ConfigTsunAllowAll, InverterIndMsg): + ConfigTsunAllowAll + m = MemoryStream(InverterIndMsg, (0,)) + assert m.db.db['inverter']['Equipment_Model'] == 'TSOL-MSxx00' + assert 'Max_Designed_Power' not in m.db.db['inverter'] + assert 'Rated_Power' not in m.db.db['inverter'] + m.read() # read complete msg, and dispatch msg + assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0 + assert not m.header_valid # must be invalid, since msg was handled and buffer flushed + assert m.msg_count == 1 + assert m.header_len==11 + assert m.snr == 2070233889 + assert m.unique_id == '2070233889' + assert m.control == 0x4210 + assert m.serial == 0x9ee6 + assert m.data_len == 0x199 + assert m._forward_buffer==InverterIndMsg + assert m._send_buffer==b'' + assert m.db.db['inverter']['Max_Designed_Power'] == 2000 + assert 2000 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) + assert m.db.db['inverter']['Rated_Power'] == 600 + assert 600 == m.db.get_db_value(Register.RATED_POWER, 0) + assert m.db.db['inverter']['Equipment_Model'] == 'TSOL-MS2000(600)' + + m._send_buffer = bytearray(0) # clear send buffer for next test + m._init_new_client_conn() + assert m._send_buffer==b'' + m.close()