diff --git a/app/src/gen3plus/solarman_v5.py b/app/src/gen3plus/solarman_v5.py index 3e4715d..72b2172 100644 --- a/app/src/gen3plus/solarman_v5.py +++ b/app/src/gen3plus/solarman_v5.py @@ -55,8 +55,8 @@ class SolarmanV5(Message): # # AT cmd - 0x4510: self.msg_unknown, # from server - 0x1510: self.msg_forward, # from inverter + 0x4510: self.at_command_ind, # from server + 0x1510: self.msg_forward, # from inverter } ''' @@ -329,3 +329,7 @@ class SolarmanV5(Message): dt = datetime.fromtimestamp(ts) logger.info(f'ts: {dt.strftime("%Y-%m-%d %H:%M:%S")}') self.forward(self._recv_buffer, self.header_len+self.data_len+2) + + def at_command_ind(self): + self.inc_counter('AT_Command') + self.msg_forward() diff --git a/app/src/infos.py b/app/src/infos.py index d4be504..2f85c1e 100644 --- a/app/src/infos.py +++ b/app/src/infos.py @@ -26,6 +26,7 @@ class Register(Enum): OTA_START_MSG = 56 SW_EXCEPTION = 57 INVALID_MSG_FMT = 58 + AT_COMMAND = 59 OUTPUT_POWER = 83 RATED_POWER = 84 INVERTER_TEMP = 85 @@ -154,6 +155,7 @@ class Infos: Register.OTA_START_MSG: {'name': ['proxy', 'OTA_Start_Msg'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'ota_start_cmd_', 'fmt': '| int', 'name': 'OTA Start Cmd', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.SW_EXCEPTION: {'name': ['proxy', 'SW_Exception'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'sw_exception_', 'fmt': '| int', 'name': 'Internal SW Exception', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501 Register.INVALID_MSG_FMT: {'name': ['proxy', 'Invalid_Msg_Format'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'inv_msg_fmt_', 'fmt': '| int', 'name': 'Invalid Message Format', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501 + Register.AT_COMMAND: {'name': ['proxy', 'AT_Command'], 'singleton': True, 'ha': {'dev': 'proxy', 'comp': 'sensor', 'dev_cla': None, 'stat_cla': None, 'id': 'at_cmd_', 'fmt': '| int', 'name': 'AT Command', 'icon': 'mdi:counter', 'ent_cat': 'diagnostic'}}, # noqa: E501 # 0xffffff03: {'name':['proxy', 'Voltage'], 'level': logging.DEBUG, 'unit': 'V', 'ha':{'dev':'proxy', 'dev_cla': 'voltage', 'stat_cla': 'measurement', 'id':'proxy_volt_', 'fmt':'| float','name': 'Grid Voltage'}}, # noqa: E501 # events diff --git a/app/tests/test_infos.py b/app/tests/test_infos.py index e3750ff..f833e0e 100644 --- a/app/tests/test_infos.py +++ b/app/tests/test_infos.py @@ -410,13 +410,13 @@ def test_statistic_counter(): assert val == None or val == 0 i.static_init() # initialize counter - assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0}}) + assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 0, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0}}) val = i.dev_value(Register.INVERTER_CNT) # valid and initiliazed addr assert val == 0 i.inc_counter('Inverter_Cnt') - assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 1, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0}}) + assert json.dumps(i.stat) == json.dumps({"proxy": {"Inverter_Cnt": 1, "Unknown_SNR": 0, "Unknown_Msg": 0, "Invalid_Data_Type": 0, "Internal_Error": 0,"Unknown_Ctrl": 0, "OTA_Start_Msg": 0, "SW_Exception": 0, "Invalid_Msg_Format": 0, "AT_Command": 0}}) val = i.dev_value(Register.INVERTER_CNT) assert val == 1 diff --git a/app/tests/test_solarman.py b/app/tests/test_solarman.py index 7cd11a7..52de01c 100644 --- a/app/tests/test_solarman.py +++ b/app/tests/test_solarman.py @@ -17,6 +17,7 @@ class MemoryStream(SolarmanV5): self.msg_count = 0 self.addr = 'Test: SrvSide' self.db.stat['proxy']['Invalid_Msg_Format'] = 0 + self.db.stat['proxy']['AT_Command'] = 0 def append_msg(self, msg): @@ -220,6 +221,14 @@ def HeartbeatRspMsg(): # 0x1710 msg += b'\x15' return msg +@pytest.fixture +def AtCommandIndMsg(): # 0x4510 + msg = b'\xa5\x01\x00\x10\x45\x10\x84' +get_sn() + msg += b'\x00' + msg += correct_checksum(msg) + msg += b'\x15' + return msg + @pytest.fixture def ConfigTsunAllowAll(): Config.config = {'solarman':{'enabled': True}, 'inverters':{'allow_all':True}} @@ -589,3 +598,22 @@ def test_heartbeat_rsp(ConfigTsunInv1, HeartbeatRspMsg): assert m._forward_buffer==HeartbeatRspMsg assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0 m.close() + +def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg): + ConfigTsunInv1 + m = MemoryStream(AtCommandIndMsg, (0,)) + m.read() # read complete msg, and dispatch msg + 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 == 0x4510 + assert m.serial == 0x8410 + assert m.data_len == 0x01 + assert m._recv_buffer==b'' + assert m._send_buffer==b'' + assert m._forward_buffer==AtCommandIndMsg + assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0 + assert m.db.stat['proxy']['AT_Command'] == 1 + m.close()