# test_with_pytest.py import pytest, logging, asyncio from math import isclose from async_stream import AsyncIfcImpl, StreamPtr from gen3.talent import Talent, Control from cnf.config import Config from infos import Infos, Register from modbus import Modbus from messages import State from mock import patch pytest_plugins = ('pytest_asyncio',) # initialize the proxy statistics Infos.static_init() tracer = logging.getLogger('tracer') class FakeIfc(AsyncIfcImpl): def __init__(self): super().__init__() self.remote = StreamPtr(None) class MemoryStream(Talent): def __init__(self, msg, chunks = (0,), server_side: bool = True): self.ifc = FakeIfc() super().__init__(None, ('test.local', 1234), self.ifc, server_side) if server_side: self.mb.timeout = 0.4 # overwrite for faster testing self.mb_first_timeout = 0.5 self.mb_timeout = 0.5 self.sent_pdu = b'' self.ifc.tx_fifo.reg_trigger(self.write_cb) self.__msg = msg self.__msg_len = len(msg) self.__chunks = chunks self.__offs = 0 self.__chunk_idx = 0 self.msg_count = 0 self.addr = 'Test: SrvSide' self.send_msg_ofs = 0 self.msg_recvd = [] def write_cb(self): self.sent_pdu = self.ifc.tx_fifo.get() def append_msg(self, msg): self.__msg += msg self.__msg_len += len(msg) def _read(self) -> int: copied_bytes = 0 try: if (self.__offs < self.__msg_len): chunk_len = self.__chunks[self.__chunk_idx] self.__chunk_idx += 1 if chunk_len!=0: self.ifc.rx_fifo += self.__msg[self.__offs:chunk_len] copied_bytes = chunk_len - self.__offs self.__offs = chunk_len else: self.ifc.rx_fifo += self.__msg[self.__offs:] copied_bytes = self.__msg_len - self.__offs self.__offs = self.__msg_len except Exception: pass # ignore exceptions here return copied_bytes def _timestamp(self): return 1691246944000 def _utc(self): return 1691239744.0 def createClientStream(self, msg, chunks = (0,)): c = MemoryStream(msg, chunks, False) self.ifc.remote.stream = c c.ifc.remote.stream = self return c def _Talent__flush_recv_msg(self) -> None: self.msg_recvd.append( { 'ctrl': int(self.ctrl), 'msg_id': self.msg_id, 'header_len': self.header_len, 'data_len': self.data_len } ) super()._Talent__flush_recv_msg() self.msg_count += 1 @pytest.fixture def msg_contact_info(): # Contact Info message return b'\x00\x00\x00\x2c\x10R170000000000001\x91\x00\x08solarhub\x0fsolarhub\x40123456' @pytest.fixture def msg_contact_info_empty(): # Contact Info message with empty string return b'\x00\x00\x00\x15\x10R170000000000001\x91\x00\x00\x00' @pytest.fixture def msg_contact_info_long_id(): # Contact Info message with longer ID Config.act_config = {'tsun':{'enabled': True}} return b'\x00\x00\x00\x2d\x11R1700000000000011\x91\x00\x08solarhub\x0fsolarhub\x40123456' @pytest.fixture def msg_contact_info_broken(): # Contact Info message with invalid string coding return b'\x00\x00\x00\x2a\x10R170000000000001\x91\x00solarhubsolarhub\x40123456' @pytest.fixture def msg2_contact_info(): # two Contact Info messages return b'\x00\x00\x00\x2c\x10R170000000000001\x91\x00\x08solarhub\x0fsolarhub\x40123456\x00\x00\x00\x2c\x10R170000000000002\x91\x00\x08solarhub\x0fsolarhub\x40123456' @pytest.fixture def msg_contact_rsp(): # Contact Response message return b'\x00\x00\x00\x14\x10R170000000000001\x91\x00\x01' @pytest.fixture def msg_contact_rsp2(): # Contact Response message return b'\x00\x00\x00\x14\x10R170000000000002\x91\x00\x01' @pytest.fixture def msg_contact_invalid(): # Contact Response message return b'\x00\x00\x00\x14\x10R170000000000001\x93\x00\x01' @pytest.fixture def msg_get_time(): # Get Time Request message return b'\x00\x00\x00\x13\x10R170000000000001\x91\x22' @pytest.fixture def msg_time_rsp(): # Get Time Resonse message return b'\x00\x00\x00\x1b\x10R170000000000001\x91\x22\x00\x00\x01\x89\xc6\x63\x4d\x80' @pytest.fixture def msg_time_rsp_inv(): # Get Time Resonse message return b'\x00\x00\x00\x17\x10R170000000000001\x91\x22\x00\x00\x01\x89' @pytest.fixture def msg_time_invalid(): # Get Time Request message return b'\x00\x00\x00\x13\x10R170000000000001\x94\x22' @pytest.fixture def msg_act_time(): # Act Time Indication message return b'\x00\x00\x00\x1c\x10R170000000000001\x91\x99\x01\x00\x00\x01\x89\xc6\x53\x4d\x80' @pytest.fixture def msg_act_time_ofs(): # Act Time Indication message withoffset 3600 return b'\x00\x00\x00\x1c\x10R170000000000001\x91\x99\x01\x00\x00\x01\x89\xc6\x53\x5b\x90' @pytest.fixture def msg_act_time_ack(): # Act Time Response message return b'\x00\x00\x00\x14\x10R170000000000001\x99\x99\x02' @pytest.fixture def msg_act_time_cmd(): # Act Time Response message return b'\x00\x00\x00\x14\x10R170000000000001\x70\x99\x02' @pytest.fixture def msg_act_time_inv(): # Act Time Indication message withoffset 3600 return b'\x00\x00\x00\x1b\x10R170000000000001\x91\x99\x00\x00\x01\x89\xc6\x53\x5b\x90' @pytest.fixture def msg_controller_ind(): # Data indication from the controller msg = b'\x00\x00\x01\x2f\x10R170000000000001\x91\x71\x0e\x10\x00\x00\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x55\x50' 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' msg += b'\x00\x00\x64\x00\x0c\x96\xa8\x49\x00\x00\x00\x1d\x00\x0c\x7f\x38\x49\x00\x00\x00\x01\x00\x0c\xfc\x38\x49\x00\x00\x00\x01\x00\x0c\xf8\x50\x49\x00\x00\x01\x2c\x00\x0c\x63\xe0\x49' msg += b'\x00\x00\x00\x00\x00\x0c\x67\xc8\x49\x00\x00\x00\x00\x00\x0c\x50\x58\x49\x00\x00\x00\x01\x00\x09\x5e\x70\x49\x00\x00\x13\x8d\x00\x09\x5e\xd4\x49\x00\x00\x13\x8d\x00\x09\x5b\x50' msg += b'\x49\x00\x00\x00\x02\x00\x0d\x04\x08\x49\x00\x00\x00\x00\x00\x07\xa1\x84\x49\x00\x00\x00\x01\x00\x0c\x50\x59\x49\x00\x00\x00\x4c\x00\x0d\x1f\x60\x49\x00\x00\x00\x00' return msg @pytest.fixture def msg_controller_ind_ts_offs(): # Data indication from the controller - offset 0x1000 msg = b'\x00\x00\x01\x2f\x10R170000000000001\x91\x71\x0e\x10\x00\x00\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x45\x50' 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' msg += b'\x00\x00\x64\x00\x0c\x96\xa8\x49\x00\x00\x00\x1d\x00\x0c\x7f\x38\x49\x00\x00\x00\x01\x00\x0c\xfc\x38\x49\x00\x00\x00\x01\x00\x0c\xf8\x50\x49\x00\x00\x01\x2c\x00\x0c\x63\xe0\x49' msg += b'\x00\x00\x00\x00\x00\x0c\x67\xc8\x49\x00\x00\x00\x00\x00\x0c\x50\x58\x49\x00\x00\x00\x01\x00\x09\x5e\x70\x49\x00\x00\x13\x8d\x00\x09\x5e\xd4\x49\x00\x00\x13\x8d\x00\x09\x5b\x50' msg += b'\x49\x00\x00\x00\x02\x00\x0d\x04\x08\x49\x00\x00\x00\x00\x00\x07\xa1\x84\x49\x00\x00\x00\x01\x00\x0c\x50\x59\x49\x00\x00\x00\x4c\x00\x0d\x1f\x60\x49\x00\x00\x00\x00' return msg @pytest.fixture def msg_controller_ack(): # Get Time Request message return b'\x00\x00\x00\x14\x10R170000000000001\x99\x71\x01' @pytest.fixture def msg_controller_invalid(): # Get Time Request message return b'\x00\x00\x00\x14\x10R170000000000001\x92\x71\x01' @pytest.fixture def msg_inverter_ind(): # Data indication from the controller msg = b'\x00\x00\x00\x8b\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x61\x08' 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 msg_inverter_ind_ts_offs(): # Data indication from the controller + offset 256 msg = b'\x00\x00\x00\x8b\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x62\x08' 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 msg_inverter_ind2(): # Data indication from the controller msg = b'\x00\x00\x05\x02\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x61\x08' 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' msg += b'\x00\x00\x00\x00\x01\x9e\x53\x00\x00\x00\x00\x01\x9f\x53\x00\x00\x00\x00\x01\xa0\x53\x00\x00\x00\x00\x01\xf4\x49\x00\x00\x00\x00\x00\x00\x01\xf5\x53\x00\x00\x00\x00' msg += b'\x01\xf6\x53\x00\x00\x00\x00\x01\xf7\x53\x00\x00\x00\x00\x01\xf8\x53\x00\x00\x00\x00\x01\xf9\x53\x00\x00\x00\x00\x01\xfa\x53\x00\x00\x00\x00\x01\xfb\x53\x00\x00\x00' msg += b'\x00\x01\xfc\x53\x00\x00\x00\x00\x01\xfd\x53\x00\x00\x00\x00\x01\xfe\x53\x00\x00\x00\x00\x01\xff\x53\x00\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x01\x53\x00\x00' msg += b'\x00\x00\x02\x02\x53\x00\x00\x00\x00\x02\x03\x53\x00\x00\x00\x00\x02\x04\x53\x00\x00\x00\x00\x02\x58\x49\x00\x00\x00\x00\x00\x00\x02\x59\x53\x00\x00\x00\x00\x02\x5a' msg += b'\x53\x00\x00\x00\x00\x02\x5b\x53\x00\x00\x00\x00\x02\x5c\x53\x00\x00\x00\x00\x02\x5d\x53\x00\x00\x00\x00\x02\x5e\x53\x00\x00\x00\x00\x02\x5f\x53\x00\x00\x00\x00\x02' msg += b'\x60\x53\x00\x00\x00\x00\x02\x61\x53\x00\x00\x00\x00\x02\x62\x53\x00\x00\x00\x00\x02\x63\x53\x00\x00\x00\x00\x02\x64\x53\x00\x00\x00\x00\x02\x65\x53\x00\x00\x00\x00' msg += b'\x02\x66\x53\x00\x00\x00\x00\x02\x67\x53\x00\x00\x00\x00\x02\x68\x53\x00\x00\x00\x00\x02\xbc\x49\x00\x00\x00\x00\x00\x00\x02\xbd\x53\x00\x00\x00\x00\x02\xbe\x53\x00' msg += b'\x00\x00\x00\x02\xbf\x53\x00\x00\x00\x00\x02\xc0\x53\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02\xc2\x53\x00\x00\x00\x00\x02\xc3\x53\x00\x00\x00\x00\x02\xc4\x53' msg += b'\x00\x00\x00\x00\x02\xc5\x53\x00\x00\x00\x00\x02\xc6\x53\x00\x00\x00\x00\x02\xc7\x53\x00\x00\x00\x00\x02\xc8\x53\x00\x00\x00\x00\x02\xc9\x53\x00\x00\x00\x00\x02\xca' msg += b'\x53\x00\x00\x00\x00\x02\xcb\x53\x00\x00\x00\x00\x02\xcc\x53\x00\x00\x00\x00\x03\x20\x53\x00\x00\x00\x00\x03\x84\x53\x50\x11\x00\x00\x03\xe8\x46\x43\x61\x66\x66\x00' msg += b'\x00\x04\x4c\x46\x3e\xeb\x85\x1f\x00\x00\x04\xb0\x46\x42\x48\x14\x7b\x00\x00\x05\x14\x53\x00\x17\x00\x00\x05\x78\x53\x00\x00\x00\x00\x05\xdc\x53\x02\x58\x00\x00\x06' msg += b'\x40\x46\x42\xd3\x66\x66\x00\x00\x06\xa4\x46\x42\x06\x66\x66\x00\x00\x07\x08\x46\x3f\xf4\x7a\xe1\x00\x00\x07\x6c\x46\x42\x81\x00\x00\x00\x00\x07\xd0\x46\x42\x06\x00' msg += b'\x00\x00\x00\x08\x34\x46\x3f\xae\x14\x7b\x00\x00\x08\x98\x46\x42\x36\xcc\xcd\x00\x00\x08\xfc\x46\x00\x00\x00\x00\x00\x00\x09\x60\x46\x00\x00\x00\x00\x00\x00\x09\xc4' msg += b'\x46\x00\x00\x00\x00\x00\x00\x0a\x28\x46\x00\x00\x00\x00\x00\x00\x0a\x8c\x46\x00\x00\x00\x00\x00\x00\x0a\xf0\x46\x00\x00\x00\x00\x00\x00\x0b\x54\x46\x3f\xd9\x99\x9a' msg += b'\x00\x00\x0b\xb8\x46\x41\x8a\xe1\x48\x00\x00\x0c\x1c\x46\x3f\x8a\x3d\x71\x00\x00\x0c\x80\x46\x41\x1b\xd7\x0a\x00\x00\x0c\xe4\x46\x3f\x1e\xb8\x52\x00\x00\x0d\x48\x46' msg += b'\x40\xf3\xd7\x0a\x00\x00\x0d\xac\x46\x00\x00\x00\x00\x00\x00\x0e\x10\x46\x00\x00\x00\x00\x00\x00\x0e\x74\x46\x00\x00\x00\x00\x00\x00\x0e\xd8\x46\x00\x00\x00\x00\x00' msg += b'\x00\x0f\x3c\x53\x00\x00\x00\x00\x0f\xa0\x53\x00\x00\x00\x00\x10\x04\x53\x55\xaa\x00\x00\x10\x68\x53\x00\x00\x00\x00\x10\xcc\x53\x00\x00\x00\x00\x11\x30\x53\x00\x00' msg += b'\x00\x00\x11\x94\x53\x00\x00\x00\x00\x11\xf8\x53\xff\xff\x00\x00\x12\x5c\x53\xff\xff\x00\x00\x12\xc0\x53\x00\x02\x00\x00\x13\x24\x53\xff\xff\x00\x00\x13\x88\x53\xff' msg += b'\xff\x00\x00\x13\xec\x53\xff\xff\x00\x00\x14\x50\x53\xff\xff\x00\x00\x14\xb4\x53\xff\xff\x00\x00\x15\x18\x53\xff\xff\x00\x00\x15\x7c\x53\x00\x00\x00\x00\x27\x10\x53' msg += b'\x00\x02\x00\x00\x27\x74\x53\x00\x3c\x00\x00\x27\xd8\x53\x00\x68\x00\x00\x28\x3c\x53\x05\x00\x00\x00\x28\xa0\x46\x43\x79\x00\x00\x00\x00\x29\x04\x46\x43\x48\x00\x00' msg += b'\x00\x00\x29\x68\x46\x42\x48\x33\x33\x00\x00\x29\xcc\x46\x42\x3e\x3d\x71\x00\x00\x2a\x30\x53\x00\x01\x00\x00\x2a\x94\x46\x43\x37\x00\x00\x00\x00\x2a\xf8\x46\x42\xce' msg += b'\x00\x00\x00\x00\x2b\x5c\x53\x00\x96\x00\x00\x2b\xc0\x53\x00\x10\x00\x00\x2c\x24\x46\x43\x90\x00\x00\x00\x00\x2c\x88\x46\x43\x95\x00\x00\x00\x00\x2c\xec\x53\x00\x06' msg += b'\x00\x00\x2d\x50\x53\x00\x06\x00\x00\x2d\xb4\x46\x43\x7d\x00\x00\x00\x00\x2e\x18\x46\x42\x3d\xeb\x85\x00\x00\x2e\x7c\x46\x42\x3d\xeb\x85\x00\x00\x2e\xe0\x53\x00\x03' msg += b'\x00\x00\x2f\x44\x53\x00\x03\x00\x00\x2f\xa8\x46\x42\x4d\xeb\x85\x00\x00\x30\x0c\x46\x42\x4d\xeb\x85\x00\x00\x30\x70\x53\x00\x03\x00\x00\x30\xd4\x53\x00\x03\x00\x00' msg += b'\x31\x38\x46\x42\x08\x00\x00\x00\x00\x31\x9c\x53\x00\x05\x00\x00\x32\x00\x53\x04\x00\x00\x00\x32\x64\x53\x00\x01\x00\x00\x32\xc8\x53\x13\x9c\x00\x00\x33\x2c\x53\x0f' msg += b'\xa0\x00\x00\x33\x90\x53\x00\x4f\x00\x00\x33\xf4\x53\x00\x66\x00\x00\x34\x58\x53\x03\xe8\x00\x00\x34\xbc\x53\x04\x00\x00\x00\x35\x20\x53\x00\x00\x00\x00\x35\x84\x53' msg += b'\x00\x00\x00\x00\x35\xe8\x53\x00\x00\x00\x00\x36\x4c\x53\x00\x00\x00\x01\x38\x80\x53\x00\x02\x00\x01\x38\x81\x53\x00\x01\x00\x01\x38\x82\x53\x00\x01\x00\x01\x38\x83' msg += b'\x53\x00\x00' return msg @pytest.fixture def msg_inverter_ind_new(): # Data indication from DSP V5.0.17 msg = b'\x00\x00\x04\xa0\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01' msg += b'\x90\x31\x4d\x68\x78\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' msg += b'\x00\x00\x00\x01\x91\x53\x00\x00\x00\x00\x01\x90\x53\x00\x00\x00' msg += b'\x00\x01\x91\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01' msg += b'\x95\x53\x00\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53' msg += b'\x00\x00\x00\x00\x01\x80\x53\x00\x00\x00\x00\x01\x90\x41\x00\x00' msg += b'\x01\x94\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x96' msg += b'\x53\x00\x00\x00\x00\x01\x98\x53\x00\x00\x00\x00\x01\xa0\x53\x00' msg += b'\x00\x00\x00\x01\xf0\x41\x00\x00\x01\xf1\x53\x00\x00\x00\x00\x01' msg += b'\xf4\x53\x00\x00\x00\x00\x01\xf5\x53\x00\x00\x00\x00\x01\xf8\x53' msg += b'\x00\x00\x00\x00\x01\xf9\x53\x00\x00\x00\x00\x00\x00\x53\x00\x00' msg += b'\x00\x00\x00\x01\x53\x00\x00\x00\x00\x00\x00\x53\x00\x00\x00\x00' msg += b'\x00\x01\x53\x00\x00\x00\x00\x00\x04\x53\x00\x00\x00\x00\x00\x58' msg += b'\x41\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x00\x53\x00\x00\x00' msg += b'\x00\x02\x02\x53\x00\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02' msg += b'\x04\x53\x00\x00\x00\x00\x02\x58\x41\x00\x00\x02\x59\x53\x00\x00' msg += b'\x00\x00\x02\x40\x53\x00\x00\x00\x00\x02\x41\x53\x00\x00\x00\x00' msg += b'\x02\x40\x53\x00\x00\x00\x00\x02\x41\x53\x00\x00\x00\x00\x02\x44' msg += b'\x53\x00\x00\x00\x00\x02\x45\x53\x00\x00\x00\x00\x02\x60\x53\x00' msg += b'\x00\x00\x00\x02\x61\x53\x00\x00\x00\x00\x02\x60\x53\x00\x00\x00' msg += b'\x00\x02\x20\x41\x00\x00\x02\x24\x53\x00\x00\x00\x00\x02\x24\x53' msg += b'\x00\x00\x00\x00\x02\x26\x53\x00\x00\x00\x00\x02\x40\x53\x00\x00' msg += b'\x00\x00\x02\x40\x53\x00\x00\x00\x00\x02\x80\x41\x00\x00\x02\x81' msg += b'\x53\x00\x00\x00\x00\x02\x84\x53\x00\x00\x00\x00\x02\x85\x53\x00' msg += b'\x00\x00\x00\x02\xc0\x53\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00' msg += b'\x00\x02\xc0\x53\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02' msg += b'\xc0\x53\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02\xc4\x53' msg += b'\x00\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x80\x53\x00\x00' msg += b'\x00\x00\x02\xc8\x42\x00\x00\x00\x00\x48\x42\x00\x00\x00\x00\x80' msg += b'\x42\x00\x00\x00\x00\x04\x53\x00\x00\x00\x00\x01\x20\x53\x00\x00' msg += b'\x00\x00\x01\x84\x53\x00\x10\x00\x00\x02\x40\x46\x00\x00\x00\x00' msg += b'\x00\x00\x04\x04\x46\x02\x00\x46\x02\x00\x00\x04\x00\x46\x00\x00' msg += b'\x00\x00\x00\x00\x05\x04\x42\x00\x00\x00\x05\x50\x42\x00\x00\x00' msg += b'\x00\x14\x42\x00\x00\x00\x00\x00\x46\x00\x00\x00\x00\x00\x00\x00' msg += b'\xa4\x46\x00\x00\x00\x00\x00\x00\x01\x00\x46\x00\x00\x00\x00\x00' msg += b'\x00\x01\x44\x46\x00\x00\x00\x00\x00\x00\x02\x00\x46\x00\x00\x00' msg += b'\x00\x00\x00\x08\x04\x46\x00\x00\x00\x00\x00\x00\x08\x90\x46\x00' msg += b'\x00\x00\x00\x00\x00\x08\x54\x46\x00\x00\x00\x00\x00\x00\x09\x20' msg += b'\x46\x00\x00\x00\x00\x00\x00\x08\x04\x46\x00\x00\x00\x00\x00\x00' msg += b'\x08\x00\x46\x00\x00\x00\x00\x00\x00\x08\x84\x46\x00\x00\x00\x00' msg += b'\x00\x00\x08\x40\x46\x00\x00\x00\x00\x00\x00\x09\x04\x46\x00\x00' msg += b'\x00\x00\x00\x00\x0a\x10\x46\x00\x00\x00\x00\x00\x00\x0c\x14\x46' msg += b'\x00\x00\x00\x00\x00\x00\x0c\x80\x46\x00\x00\x00\x00\x00\x00\x0c' msg += b'\x24\x42\x00\x00\x00\x0d\x00\x42\x00\x00\x00\x00\x04\x42\x00\x00' msg += b'\x00\x00\x00\x42\x00\x00\x00\x00\x44\x42\x00\x00\x00\x00\x10\x42' msg += b'\x00\x00\x00\x01\x14\x53\x00\x00\x00\x00\x01\xa0\x53\x00\x00\x00' msg += b'\x00\x10\x04\x53\x55\xaa\x00\x00\x10\x40\x53\x00\x00\x00\x00\x10' msg += b'\x04\x53\x00\x00\x00\x00\x11\x00\x53\x00\x00\x00\x00\x11\x84\x53' msg += b'\x00\x00\x00\x00\x10\x50\x53\xff\xff\x00\x00\x10\x14\x53\x03\x20' msg += b'\x00\x00\x10\x00\x53\x00\x00\x00\x00\x11\x24\x53\x00\x00\x00\x00' msg += b'\x03\x00\x53\x00\x00\x00\x00\x03\x64\x53\x00\x00\x00\x00\x04\x50' msg += b'\x53\x00\x00\x00\x00\x00\x34\x53\x00\x00\x00\x00\x00\x00\x42\x02' msg += b'\x00\x00\x01\x04\x42\x00\x00\x00\x21\x00\x42\x00\x00\x00\x21\x44' msg += b'\x42\x00\x00\x00\x22\x10\x53\x00\x00\x00\x00\x28\x14\x42\x01\x00' msg += b'\x00\x28\xa0\x46\x42\x48\x00\x00\x00\x00\x29\x04\x42\x00\x00\x00' msg += b'\x29\x40\x42\x00\x00\x00\x28\x04\x46\x42\x10\x00\x00\x00\x00\x28' msg += b'\x00\x42\x00\x00\x00\x28\x84\x42\x00\x00\x00\x28\x50\x42\x00\x00' msg += b'\x00\x29\x14\x42\x00\x00\x00\x2a\x00\x42\x00\x00\x00\x2c\x24\x46' msg += b'\x42\x10\x00\x00\x00\x00\x2c\x80\x42\x00\x00\x00\x2c\x44\x53\x00' msg += b'\x02\x00\x00\x2d\x00\x42\x00\x00\x00\x20\x04\x46\x42\x4d\x00\x00' msg += b'\x00\x00\x20\x10\x42\x00\x00\x00\x20\x54\x42\x00\x00\x00\x20\x20' msg += b'\x42\x00\x00\x00\x21\x04\x53\x00\x01\x00\x00\x22\x00\x42\x00\x00' msg += b'\x00\x30\x04\x42\x00\x00\x00\x30\x40\x53\x00\x00\x00\x00\x30\x04' msg += b'\x53\x00\x00\x00\x00\x31\x10\x42\x00\x00\x00\x31\x94\x53\x00\x04' msg += b'\x00\x00\x30\x00\x53\x00\x00\x00\x00\x30\x24\x53\x00\x00\x00\x00' msg += b'\x30\x00\x53\x00\x00\x00\x00\x31\x04\x53\x00\x00\x00\x00\x31\x80' msg += b'\x53\x00\x00\x00\x00\x32\x44\x53\x00\x00\x00\x00\x30\x00\x53\x00' msg += b'\x00\x00\x00\x30\x80\x53\x00\x00\x00\x00\x30\x00\x53\x00\x00\x00' msg += b'\x00\x30\x80\x53\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00' msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x03\x00' msg += b'\x00\x00\x00\x00' return msg @pytest.fixture def msg_inverter_ind_new2(): # Data indication from DSP V5.0.17 msg = b'\x00\x00\x04\xf4\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01' msg += b'\x86\x98\x55\xe7\x48\x00\x00\x00\xa3\x00\x00\x01\x93\x53\x00\x00' msg += b'\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00' msg += b'\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00\x00\x00\x00\x01\x98' msg += b'\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00' msg += b'\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00' msg += b'\x00\x01\x9d\x53\x00\x00\x00\x00\x01\x9e\x53\x00\x00\x00\x00\x01' msg += b'\x9f\x53\x00\x00\x00\x00\x01\xa0\x53\x00\x00\x00\x00\x01\xf4\x49' msg += b'\x00\x00\x00\x00\x00\x00\x01\xf5\x53\x00\x00\x00\x00\x01\xf6\x53' msg += b'\x00\x00\x00\x00\x01\xf7\x53\x00\x00\x00\x00\x01\xf8\x53\x00\x00' msg += b'\x00\x00\x01\xf9\x53\x00\x00\x00\x00\x01\xfa\x53\x00\x00\x00\x00' msg += b'\x01\xfb\x53\x00\x00\x00\x00\x01\xfc\x53\x00\x00\x00\x00\x01\xfd' msg += b'\x53\x00\x00\x00\x00\x01\xfe\x53\x00\x00\x00\x00\x01\xff\x53\x00' msg += b'\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x01\x53\x00\x00\x00' msg += b'\x00\x02\x02\x53\x00\x00\x00\x00\x02\x03\x53\x00\x00\x00\x00\x02' msg += b'\x04\x53\x00\x00\x00\x00\x02\x58\x49\x00\x00\x00\x00\x00\x00\x02' msg += b'\x59\x53\x00\x00\x00\x00\x02\x5a\x53\x00\x00\x00\x00\x02\x5b\x53' msg += b'\x00\x00\x00\x00\x02\x5c\x53\x00\x00\x00\x00\x02\x5d\x53\x00\x00' msg += b'\x00\x00\x02\x5e\x53\x00\x00\x00\x00\x02\x5f\x53\x00\x00\x00\x00' msg += b'\x02\x60\x53\x00\x00\x00\x00\x02\x61\x53\x00\x00\x00\x00\x02\x62' msg += b'\x53\x00\x00\x00\x00\x02\x63\x53\x00\x00\x00\x00\x02\x64\x53\x00' msg += b'\x00\x00\x00\x02\x65\x53\x00\x00\x00\x00\x02\x66\x53\x00\x00\x00' msg += b'\x00\x02\x67\x53\x00\x00\x00\x00\x02\x68\x53\x00\x00\x00\x00\x02' msg += b'\xbc\x49\x00\x00\x00\x00\x00\x00\x02\xbd\x53\x00\x00\x00\x00\x02' msg += b'\xbe\x53\x00\x00\x00\x00\x02\xbf\x53\x00\x00\x00\x00\x02\xc0\x53' msg += b'\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02\xc2\x53\x00\x00' msg += b'\x00\x00\x02\xc3\x53\x00\x00\x00\x00\x02\xc4\x53\x00\x00\x00\x00' msg += b'\x02\xc5\x53\x00\x00\x00\x00\x02\xc6\x53\x00\x00\x00\x00\x02\xc7' msg += b'\x53\x00\x00\x00\x00\x02\xc8\x53\x00\x00\x00\x00\x02\xc9\x53\x00' msg += b'\x00\x00\x00\x02\xca\x53\x00\x00\x00\x00\x02\xcb\x53\x00\x00\x00' msg += b'\x00\x02\xcc\x53\x00\x00\x00\x00\x03\x20\x53\x00\x00\x00\x00\x03' msg += b'\x84\x53\x50\x11\x00\x00\x03\xe8\x46\x43\x65\xcc\xcd\x00\x00\x04' msg += b'\x4c\x46\x40\x0c\xcc\xcd\x00\x00\x04\xb0\x46\x42\x47\xd7\x0a\x00' msg += b'\x00\x05\x14\x53\x00\x35\x00\x00\x05\x78\x53\x00\x00\x00\x00\x05' msg += b'\xdc\x53\x03\x20\x00\x00\x06\x40\x46\x43\xfd\x4c\xcd\x00\x00\x06' msg += b'\xa4\x46\x42\x18\x00\x00\x00\x00\x07\x08\x46\x40\xde\x14\x7b\x00' msg += b'\x00\x07\x6c\x46\x43\x84\x33\x33\x00\x00\x07\xd0\x46\x42\x1a\x00' msg += b'\x00\x00\x00\x08\x34\x46\x40\xda\x8f\x5c\x00\x00\x08\x98\x46\x43' msg += b'\x83\xb3\x33\x00\x00\x08\xfc\x46\x00\x00\x00\x00\x00\x00\x09\x60' msg += b'\x46\x00\x00\x00\x00\x00\x00\x09\xc4\x46\x00\x00\x00\x00\x00\x00' msg += b'\x0a\x28\x46\x00\x00\x00\x00\x00\x00\x0a\x8c\x46\x00\x00\x00\x00' msg += b'\x00\x00\x0a\xf0\x46\x00\x00\x00\x00\x00\x00\x0b\x54\x46\x40\x9c' msg += b'\xcc\xcd\x00\x00\x0b\xb8\x46\x43\xea\xb5\xc3\x00\x00\x0c\x1c\x46' msg += b'\x40\x1e\xb8\x52\x00\x00\x0c\x80\x46\x43\x6d\x2b\x85\x00\x00\x0c' msg += b'\xe4\x46\x40\x1a\xe1\x48\x00\x00\x0d\x48\x46\x43\x68\x40\x00\x00' msg += b'\x00\x0d\xac\x46\x00\x00\x00\x00\x00\x00\x0e\x10\x46\x00\x00\x00' msg += b'\x00\x00\x00\x0e\x74\x46\x00\x00\x00\x00\x00\x00\x0e\xd8\x46\x00' msg += b'\x00\x00\x00\x00\x00\x0f\x3c\x53\x00\x00\x00\x00\x0f\xa0\x53\x00' msg += b'\x00\x00\x00\x10\x04\x53\x55\xaa\x00\x00\x10\x68\x53\x00\x01\x00' msg += b'\x00\x10\xcc\x53\x00\x00\x00\x00\x11\x30\x53\x00\x00\x00\x00\x11' msg += b'\x94\x53\x00\x00\x00\x00\x11\xf8\x53\xff\xff\x00\x00\x12\x5c\x53' msg += b'\xff\xff\x00\x00\x12\xc0\x53\x00\x00\x00\x00\x13\x24\x53\xff\xff' msg += b'\x00\x00\x13\x88\x53\xff\xff\x00\x00\x13\xec\x53\xff\xff\x00\x00' msg += b'\x14\x50\x53\xff\xff\x00\x00\x14\xb4\x53\xff\xff\x00\x00\x15\x18' msg += b'\x53\xff\xff\x00\x00\x15\x7c\x53\x00\x00\x00\x00\x27\x10\x53\x00' msg += b'\x02\x00\x00\x27\x74\x53\x00\x3c\x00\x00\x27\xd8\x53\x00\x68\x00' msg += b'\x00\x28\x3c\x53\x05\x00\x00\x00\x28\xa0\x46\x43\x79\x00\x00\x00' msg += b'\x00\x29\x04\x46\x43\x48\x00\x00\x00\x00\x29\x68\x46\x42\x48\x33' msg += b'\x33\x00\x00\x29\xcc\x46\x42\x3e\x3d\x71\x00\x00\x2a\x30\x53\x00' msg += b'\x01\x00\x00\x2a\x94\x46\x43\x37\x00\x00\x00\x00\x2a\xf8\x46\x42' msg += b'\xce\x00\x00\x00\x00\x2b\x5c\x53\x00\x96\x00\x00\x2b\xc0\x53\x00' msg += b'\x10\x00\x00\x2c\x24\x46\x43\x90\x00\x00\x00\x00\x2c\x88\x46\x43' msg += b'\x95\x00\x00\x00\x00\x2c\xec\x53\x00\x06\x00\x00\x2d\x50\x53\x00' msg += b'\x06\x00\x00\x2d\xb4\x46\x43\x7d\x00\x00\x00\x00\x2e\x18\x46\x42' msg += b'\x3d\xeb\x85\x00\x00\x2e\x7c\x46\x42\x3d\xeb\x85\x00\x00\x2e\xe0' msg += b'\x53\x00\x03\x00\x00\x2f\x44\x53\x00\x03\x00\x00\x2f\xa8\x46\x42' msg += b'\x4d\xeb\x85\x00\x00\x30\x0c\x46\x42\x4d\xeb\x85\x00\x00\x30\x70' msg += b'\x53\x00\x03\x00\x00\x30\xd4\x53\x00\x03\x00\x00\x31\x38\x46\x42' msg += b'\x08\x00\x00\x00\x00\x31\x9c\x53\x00\x05\x00\x00\x32\x00\x53\x04' msg += b'\x00\x00\x00\x32\x64\x53\x00\x01\x00\x00\x32\xc8\x53\x13\x9c\x00' msg += b'\x00\x33\x2c\x53\x0f\xa0\x00\x00\x33\x90\x53\x00\x4f\x00\x00\x33' msg += b'\xf4\x53\x00\x66\x00\x00\x34\x58\x53\x03\xe8\x00\x00\x34\xbc\x53' msg += b'\x04\x00\x00\x00\x35\x20\x53\x00\x00\x00\x00\x35\x84\x53\x00\x00' msg += b'\x00\x00\x35\xe8\x53\x00\x00\x00\x00\x36\x4c\x53\x00\x00\x00\x01' msg += b'\x38\x80\x53\x00\x02\x00\x01\x38\x81\x53\x00\x01\x00\x01\x38\x82' msg += b'\x53\x00\x01\x00\x01\x38\x83\x53\x00\x00\x00\x00\x00\x0a\x08\x00' msg += b'\x00\x00\x00\x00\x00\x00\x00\x14\x04\x00\x00\x00\x00\x00\x00\x00' msg += b'\x00\x1e\x07\x00\x00\x00\x00\x00' return msg @pytest.fixture def msg_inverter_ind_0w(): # Data indication with 0.5W grid output msg = b'\x00\x00\x05\x02\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01' msg += b'\x90\x31\x4d\x68\x78' 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' msg += b'\x00\x00\x00\x00\x01\x9e\x53\x00\x00\x00\x00\x01\x9f\x53\x00\x00\x00\x00\x01\xa0\x53\x00\x00\x00\x00\x01\xf4\x49\x00\x00\x00\x00\x00\x00\x01\xf5\x53\x00\x00\x00\x00' msg += b'\x01\xf6\x53\x00\x00\x00\x00\x01\xf7\x53\x00\x00\x00\x00\x01\xf8\x53\x00\x00\x00\x00\x01\xf9\x53\x00\x00\x00\x00\x01\xfa\x53\x00\x00\x00\x00\x01\xfb\x53\x00\x00\x00' msg += b'\x00\x01\xfc\x53\x00\x00\x00\x00\x01\xfd\x53\x00\x00\x00\x00\x01\xfe\x53\x00\x00\x00\x00\x01\xff\x53\x00\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x01\x53\x00\x00' msg += b'\x00\x00\x02\x02\x53\x00\x00\x00\x00\x02\x03\x53\x00\x00\x00\x00\x02\x04\x53\x00\x00\x00\x00\x02\x58\x49\x00\x00\x00\x00\x00\x00\x02\x59\x53\x00\x00\x00\x00\x02\x5a' msg += b'\x53\x00\x00\x00\x00\x02\x5b\x53\x00\x00\x00\x00\x02\x5c\x53\x00\x00\x00\x00\x02\x5d\x53\x00\x00\x00\x00\x02\x5e\x53\x00\x00\x00\x00\x02\x5f\x53\x00\x00\x00\x00\x02' msg += b'\x60\x53\x00\x00\x00\x00\x02\x61\x53\x00\x00\x00\x00\x02\x62\x53\x00\x00\x00\x00\x02\x63\x53\x00\x00\x00\x00\x02\x64\x53\x00\x00\x00\x00\x02\x65\x53\x00\x00\x00\x00' msg += b'\x02\x66\x53\x00\x00\x00\x00\x02\x67\x53\x00\x00\x00\x00\x02\x68\x53\x00\x00\x00\x00\x02\xbc\x49\x00\x00\x00\x00\x00\x00\x02\xbd\x53\x00\x00\x00\x00\x02\xbe\x53\x00' msg += b'\x00\x00\x00\x02\xbf\x53\x00\x00\x00\x00\x02\xc0\x53\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02\xc2\x53\x00\x00\x00\x00\x02\xc3\x53\x00\x00\x00\x00\x02\xc4\x53' msg += b'\x00\x00\x00\x00\x02\xc5\x53\x00\x00\x00\x00\x02\xc6\x53\x00\x00\x00\x00\x02\xc7\x53\x00\x00\x00\x00\x02\xc8\x53\x00\x00\x00\x00\x02\xc9\x53\x00\x00\x00\x00\x02\xca' msg += b'\x53\x00\x00\x00\x00\x02\xcb\x53\x00\x00\x00\x00\x02\xcc\x53\x00\x00\x00\x00\x03\x20\x53\x00\x00\x00\x00\x03\x84\x53\x50\x11\x00\x00\x03\xe8\x46\x43\x61\x66\x66\x00' msg += b'\x00\x04\x4c\x46\x3e\xeb\x85\x1f\x00\x00\x04\xb0\x46\x42\x48\x14\x7b\x00\x00\x05\x14\x53\x00\x17\x00\x00\x05\x78\x53\x00\x00\x00\x00\x05\xdc\x53\x02\x58\x00\x00\x06' msg += b'\x40\x46\x3f\x00\x00\x00\x00\x00\x06\xa4\x46\x42\x06\x66\x66\x00\x00\x07\x08\x46\x3f\xf4\x7a\xe1\x00\x00\x07\x6c\x46\x42\x81\x00\x00\x00\x00\x07\xd0\x46\x42\x06\x00' msg += b'\x00\x00\x00\x08\x34\x46\x3f\xae\x14\x7b\x00\x00\x08\x98\x46\x42\x36\xcc\xcd\x00\x00\x08\xfc\x46\x00\x00\x00\x00\x00\x00\x09\x60\x46\x00\x00\x00\x00\x00\x00\x09\xc4' msg += b'\x46\x00\x00\x00\x00\x00\x00\x0a\x28\x46\x00\x00\x00\x00\x00\x00\x0a\x8c\x46\x00\x00\x00\x00\x00\x00\x0a\xf0\x46\x00\x00\x00\x00\x00\x00\x0b\x54\x46\x3f\xd9\x99\x9a' msg += b'\x00\x00\x0b\xb8\x46\x41\x8a\xe1\x48\x00\x00\x0c\x1c\x46\x3f\x8a\x3d\x71\x00\x00\x0c\x80\x46\x41\x1b\xd7\x0a\x00\x00\x0c\xe4\x46\x3f\x1e\xb8\x52\x00\x00\x0d\x48\x46' msg += b'\x40\xf3\xd7\x0a\x00\x00\x0d\xac\x46\x00\x00\x00\x00\x00\x00\x0e\x10\x46\x00\x00\x00\x00\x00\x00\x0e\x74\x46\x00\x00\x00\x00\x00\x00\x0e\xd8\x46\x00\x00\x00\x00\x00' msg += b'\x00\x0f\x3c\x53\x00\x00\x00\x00\x0f\xa0\x53\x00\x00\x00\x00\x10\x04\x53\x55\xaa\x00\x00\x10\x68\x53\x00\x00\x00\x00\x10\xcc\x53\x00\x00\x00\x00\x11\x30\x53\x00\x00' msg += b'\x00\x00\x11\x94\x53\x00\x00\x00\x00\x11\xf8\x53\xff\xff\x00\x00\x12\x5c\x53\xff\xff\x00\x00\x12\xc0\x53\x00\x02\x00\x00\x13\x24\x53\xff\xff\x00\x00\x13\x88\x53\xff' msg += b'\xff\x00\x00\x13\xec\x53\xff\xff\x00\x00\x14\x50\x53\xff\xff\x00\x00\x14\xb4\x53\xff\xff\x00\x00\x15\x18\x53\xff\xff\x00\x00\x15\x7c\x53\x00\x00\x00\x00\x27\x10\x53' msg += b'\x00\x02\x00\x00\x27\x74\x53\x00\x3c\x00\x00\x27\xd8\x53\x00\x68\x00\x00\x28\x3c\x53\x05\x00\x00\x00\x28\xa0\x46\x43\x79\x00\x00\x00\x00\x29\x04\x46\x43\x48\x00\x00' msg += b'\x00\x00\x29\x68\x46\x42\x48\x33\x33\x00\x00\x29\xcc\x46\x42\x3e\x3d\x71\x00\x00\x2a\x30\x53\x00\x01\x00\x00\x2a\x94\x46\x43\x37\x00\x00\x00\x00\x2a\xf8\x46\x42\xce' msg += b'\x00\x00\x00\x00\x2b\x5c\x53\x00\x96\x00\x00\x2b\xc0\x53\x00\x10\x00\x00\x2c\x24\x46\x43\x90\x00\x00\x00\x00\x2c\x88\x46\x43\x95\x00\x00\x00\x00\x2c\xec\x53\x00\x06' msg += b'\x00\x00\x2d\x50\x53\x00\x06\x00\x00\x2d\xb4\x46\x43\x7d\x00\x00\x00\x00\x2e\x18\x46\x42\x3d\xeb\x85\x00\x00\x2e\x7c\x46\x42\x3d\xeb\x85\x00\x00\x2e\xe0\x53\x00\x03' msg += b'\x00\x00\x2f\x44\x53\x00\x03\x00\x00\x2f\xa8\x46\x42\x4d\xeb\x85\x00\x00\x30\x0c\x46\x42\x4d\xeb\x85\x00\x00\x30\x70\x53\x00\x03\x00\x00\x30\xd4\x53\x00\x03\x00\x00' msg += b'\x31\x38\x46\x42\x08\x00\x00\x00\x00\x31\x9c\x53\x00\x05\x00\x00\x32\x00\x53\x04\x00\x00\x00\x32\x64\x53\x00\x01\x00\x00\x32\xc8\x53\x13\x9c\x00\x00\x33\x2c\x53\x0f' msg += b'\xa0\x00\x00\x33\x90\x53\x00\x4f\x00\x00\x33\xf4\x53\x00\x66\x00\x00\x34\x58\x53\x03\xe8\x00\x00\x34\xbc\x53\x04\x00\x00\x00\x35\x20\x53\x00\x00\x00\x00\x35\x84\x53' msg += b'\x00\x00\x00\x00\x35\xe8\x53\x00\x00\x00\x00\x36\x4c\x53\x00\x00\x00\x01\x38\x80\x53\x00\x02\x00\x01\x38\x81\x53\x00\x01\x00\x01\x38\x82\x53\x00\x01\x00\x01\x38\x83' msg += b'\x53\x00\x00' return msg @pytest.fixture def msg_inverter_ack(): # Get Time Request message return b'\x00\x00\x00\x14\x10R170000000000001\x99\x04\x01' @pytest.fixture def msg_inverter_invalid(): # Get Time Request message return b'\x00\x00\x00\x14\x10R170000000000001\x92\x04\x01' @pytest.fixture def msg_unknown(): # Get Time Request message return b'\x00\x00\x00\x17\x10R170000000000001\x91\x17\x01\x02\x03\x04' @pytest.fixture def config_tsun_allow_all(): Config.act_config = {'tsun':{'enabled': True}, 'inverters':{'allow_all':True}} @pytest.fixture def config_no_tsun_inv1(): Config.act_config = {'tsun':{'enabled': False},'inverters':{'R170000000000001':{'node_id':'inv1', 'sensor_list': 0, 'modbus_polling': True, 'suggested_area':'roof'}}} @pytest.fixture def config_tsun_inv1(): Config.act_config = {'tsun':{'enabled': True},'inverters':{'R170000000000001':{'node_id':'inv1', 'sensor_list': 0x01900001, 'modbus_polling': True, 'suggested_area':'roof'}}} @pytest.fixture def config_no_modbus_poll(): Config.act_config = {'tsun':{'enabled': True},'inverters':{'R170000000000001':{'node_id':'inv1', 'sensor_list': 0, 'modbus_polling': False, 'suggested_area':'roof'}}} @pytest.fixture def msg_ota_req(): # Over the air update request from tsun cloud msg = b'\x00\x00\x01\x16\x10R170000000000001\x70\x13\x01\x02\x76\x35\x70\x68\x74\x74\x70' msg += b'\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x61\x6c\x65\x6e\x74\x2d\x6d\x6f' msg += b'\x6e\x69\x74\x6f\x72\x69\x6e\x67\x2e\x63\x6f\x6d\x3a\x39\x30\x30' msg += b'\x32\x2f\x70\x72\x6f\x64\x2d\x61\x70\x69\x2f\x72\x6f\x6d\x2f\x75' msg += b'\x70\x64\x61\x74\x65\x2f\x64\x6f\x77\x6e\x6c\x6f\x61\x64\x3f\x76' msg += b'\x65\x72\x3d\x56\x31\x2e\x30\x30\x2e\x31\x37\x26\x6e\x61\x6d\x65' msg += b'\x3d\x47\x33\x2d\x57\x69\x46\x69\x2b\x2d\x56\x31\x2e\x30\x30\x2e' msg += b'\x31\x37\x2d\x4f\x54\x41\x26\x65\x78\x74\x3d\x30\x60\x68\x74\x74' msg += b'\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x61\x6c\x65\x6e\x74\x2d\x6d' msg += b'\x6f\x6e\x69\x74\x6f\x72\x69\x6e\x67\x2e\x63\x6f\x6d\x3a\x39\x30' msg += b'\x30\x32\x2f\x70\x72\x6f\x64\x2d\x61\x70\x69\x2f\x72\x6f\x6d\x2f' msg += b'\x75\x70\x64\x61\x74\x65\x2f\x63\x61\x6c\x6c\x62\x61\x63\x6b\x3f' msg += b'\x71\x69\x64\x3d\x31\x35\x30\x33\x36\x32\x26\x72\x69\x64\x3d\x32' msg += b'\x32\x39\x26\x64\x69\x64\x3d\x31\x33\x34\x32\x32\x35\x20\x36\x35' msg += b'\x66\x30\x64\x37\x34\x34\x62\x66\x33\x39\x61\x62\x38\x32\x34\x64' msg += b'\x32\x38\x62\x38\x34\x64\x31\x39\x65\x64\x33\x31\x31\x63\x06\x34' msg += b'\x36\x38\x36\x33\x33\x01\x31\x01\x30\x00' return msg @pytest.fixture def msg_ota_ack(): # Over the air update rewuest from tsun cloud return b'\x00\x00\x00\x14\x10R170000000000001\x91\x13\x01' @pytest.fixture def msg_ota_invalid(): # Get Time Request message return b'\x00\x00\x00\x14\x10R170000000000001\x99\x13\x01' @pytest.fixture def msg_modbus_cmd(): msg = b'\x00\x00\x00\x20\x10R170000000000001' msg += b'\x70\x77\x00\x01\xa3\x28\x08\x01\x06\x20\x08' msg += b'\x00\x00\x03\xc8' return msg @pytest.fixture def msg_modbus_cmd_crc_err(): msg = b'\x00\x00\x00\x20\x10R170000000000001' msg += b'\x70\x77\x00\x01\xa3\x28\x08\x01\x06\x20\x08' msg += b'\x00\x00\x04\xc8' return msg @pytest.fixture def msg_modbus_rsp(): msg = b'\x00\x00\x00\x20\x10R170000000000001' msg += b'\x91\x77\x17\x18\x19\x1a\x08\x01\x06\x20\x08' msg += b'\x00\x00\x03\xc8' return msg @pytest.fixture def msg_modbus_inv(): msg = b'\x00\x00\x00\x20\x10R170000000000001' msg += b'\x99\x77\x17\x18\x19\x1a\x08\x01\x06\x20\x08' msg += b'\x00\x00\x03\xc8' return msg @pytest.fixture def msg_modbus_rsp20(): msg = b'\x00\x00\x00\x45\x10R170000000000001' msg += b'\x91\x77\x17\x18\x19\x1a\x2d\x01\x03\x28\x51' msg += b'\x09\x08\xd3\x00\x29\x13\x87\x00\x3e\x00\x00\x01\x2c\x03\xb4\x00' msg += b'\x08\x00\x00\x00\x00\x01\x59\x01\x21\x03\xe6\x00\x00\x00\x00\x00' msg += b'\x00\x00\x00\x00\x00\x00\x00\xdb\x6b' return msg @pytest.fixture def msg_modbus_rsp21(): msg = b'\x00\x00\x00\x45\x10R170000000000001' msg += b'\x91\x77\x17\x18\x19\x1a\x2d\x01\x03\x28\x51' msg += b'\x0e\x08\xd3\x00\x29\x13\x87\x00\x3e\x00\x00\x01\x2c\x03\xb4\x00' msg += b'\x08\x00\x00\x00\x00\x01\x59\x01\x21\x03\xe6\x00\x00\x00\x00\x00' msg += b'\x00\x00\x00\x00\x00\x00\x00\xe6\xef' return msg @pytest.fixture def msg_modbus_cmd_new(): msg = b'\x00\x00\x00\x20\x10R170000000000001' msg += b'\x70\x77\x00\x01\xa3\x28\x08\x01\x03\x30\x00' msg += b'\x00\x30\x4a\xde' return msg @pytest.fixture def msg_modbus_rsp20_new(): msg = b'\x00\x00\x00\x7e\x10R170000000000001' msg += b'\x91\x87\x00\x01\xa3\x28\x00\x65\x01\x03\x60' msg += b'\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' msg += b'\x51\x09\x09\x17\x00\x17\x13\x88\x00\x40\x00\x00\x02\x58\x02\x23' msg += b'\x00\x07\x00\x00\x00\x00\x01\x4f\x00\xab\x02\x40\x00\x00\x00\x00' msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\xc0\x93\x00\x00' msg += b'\x00\x00\x33\xad\x00\x09\x00\x00\x98\x1c\x00\x00\x00\x00\x00\x00' msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' msg += b'\xa7\xab' return msg @pytest.fixture def broken_recv_buf(): # There are two message in the buffer, but the second has overwritten the first partly msg = b'\x00\x00\x05\x02\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x61\x08' msg += b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01' msg += b'\x00\x00\x00\xc8\x53\x00\x00\x00\x00\x01\x2c\x53\x00\x02\x00\x00' msg += b'\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00\x00\x00' msg += b'\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94' msg += b'\x53\x00\x00\x00\x00\x00\x05\x02\x10\x52\x31\x37\x45\x37\x33\x30' msg += b'\x37\x30\x32\x31\x44\x30\x30\x36\x41\x91\x04\x01\x90\x00\x01\x10' msg += b'\x54\x31\x37\x45\x37\x33\x30\x37\x30\x32\x31\x44\x30\x30\x36\x41' msg += b'\x01\x00\x00\x01\x91\x1c\xe6\x80\xd0\x00\x00\x00\xa3\x00\x00\x00' msg += b'\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x00\x00\x00\x01\x2c\x53' msg += b'\x00\x02\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53' msg += b'\x00\x00\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00' msg += b'\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00' msg += b'\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00\x00\x00\x00\x01\x98' msg += b'\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00' msg += b'\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00' msg += b'\x00\x01\x9d\x53\x00\x00\x00\x00\x01\x9e\x53\x00\x00\x00\x00\x01' msg += b'\x9f\x53\x00\x00\x00\x00\x01\xa0\x53\x00\x00\x00\x00\x01\xf4\x49' msg += b'\x00\x00\x00\x00\x00\x00\x01\xf5\x53\x00\x00\x00\x00\x01\xf6\x53' msg += b'\x00\x00\x00\x00\x01\xf7\x53\x00\x00\x00\x00\x01\xf8\x53\x00\x00' msg += b'\x00\x00\x01\xf9\x53\x00\x00\x00\x00\x01\xfa\x53\x00\x00\x00\x00' msg += b'\x01\xfb\x53\x00\x00\x00\x00\x01\xfc\x53\x00\x00\x00\x00\x01\xfd' msg += b'\x53\x00\x00\x00\x00\x01\xfe\x53\x00\x00\x00\x00\x01\xff\x53\x00' msg += b'\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x01\x53\x00\x00\x00' msg += b'\x00\x02\x02\x53\x00\x00\x00\x00\x02\x03\x53\x00\x00\x00\x00\x02' msg += b'\x04\x53\x00\x00\x00\x00\x02\x58\x49\x00\x00\x00\x00\x00\x00\x02' msg += b'\x59\x53\x00\x00\x00\x00\x02\x5a\x53\x00\x00\x00\x00\x02\x5b\x53' msg += b'\x00\x00\x00\x00\x02\x5c\x53\x00\x00\x00\x00\x02\x5d\x53\x00\x00' msg += b'\x00\x00\x02\x5e\x53\x00\x00\x00\x00\x02\x5f\x53\x00\x00\x00\x00' msg += b'\x02\x60\x53\x00\x00\x00\x00\x02\x61\x53\x00\x00\x00\x00\x02\x62' msg += b'\x53\x00\x00\x00\x00\x02\x63\x53\x00\x00\x00\x00\x02\x64\x53\x00' msg += b'\x00\x00\x00\x02\x65\x53\x00\x00\x00\x00\x02\x66\x53\x00\x00\x00' msg += b'\x00\x02\x67\x53\x00\x00\x00\x00\x02\x68\x53\x00\x00\x00\x00\x02' msg += b'\xbc\x49\x00\x00\x00\x00\x00\x00\x02\xbd\x53\x00\x00\x00\x00\x02' msg += b'\xbe\x53\x00\x00\x00\x00\x02\xbf\x53\x00\x00\x00\x00\x02\xc0\x53' msg += b'\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02\xc2\x53\x00\x00' msg += b'\x00\x00\x02\xc3\x53\x00\x00\x00\x00\x02\xc4\x53\x00\x00\x00\x00' msg += b'\x02\xc5\x53\x00\x00\x00\x00\x02\xc6\x53\x00\x00\x00\x00\x02\xc7' msg += b'\x53\x00\x00\x00\x00\x02\xc8\x53\x00\x00\x00\x00\x02\xc9\x53\x00' msg += b'\x00\x00\x00\x02\xca\x53\x00\x00\x00\x00\x02\xcb\x53\x00\x00\x00' msg += b'\x00\x02\xcc\x53\x00\x00\x00\x00\x03\x20\x53\x00\x00\x00\x00\x03' msg += b'\x84\x53\x51\x09\x00\x00\x03\xe8\x46\x43\x62\xb3\x33\x00\x00\x04' msg += b'\x4c\x46\x3e\xc2\x8f\x5c\x00\x00\x04\xb0\x46\x42\x48\x00\x00\x00' msg += b'\x00\x05\x14\x53\x00\x18\x00\x00\x05\x78\x53\x00\x00\x00\x00\x05' msg += b'\xdc\x53\x02\x58\x00\x00\x06\x40\x46\x42\xae\xcc\xcd\x00\x00\x06' msg += b'\xa4\x46\x3f\x4c\xcc\xcd\x00\x00\x07\x08\x46\x00\x00\x00\x00\x00' msg += b'\x00\x07\x6c\x46\x00\x00\x00\x00\x00\x00\x07\xd0\x46\x42\x0a\x66' msg += b'\x66\x00\x00\x08\x34\x46\x40\x2a\x3d\x71\x00\x00\x08\x98\x46\x42' msg += b'\xb8\x33\x33\x00\x00\x08\xfc\x46\x00\x00\x00\x00\x00\x00\x09\x60' msg += b'\x46\x00\x00\x00\x00\x00\x00\x09\xc4\x46\x00\x00\x00\x00\x00\x00' msg += b'\x0a\x28\x46\x00\x00\x00\x00\x00\x00\x0a\x8c\x46\x00\x00\x00\x00' msg += b'\x00\x00\x0a\xf0\x46\x00\x00\x00\x00\x00\x00\x0b\x54\x46\x3e\x05' msg += b'\x1e\xb8\x00\x00\x0b\xb8\x46\x43\xe2\x42\x8f\x00\x00\x0c\x1c\x46' msg += b'\x00\x00\x00\x00\x00\x00\x0c\x80\x46\x43\x04\x4a\x3d\x00\x00\x0c' msg += b'\xe4\x46\x3e\x0f\x5c\x29\x00\x00\x0d\x48\x46\x43\xad\x48\xf6\x00' msg += b'\x00\x0d\xac\x46\x00\x00\x00\x00\x00\x00\x0e\x10\x46\x00\x00\x00' msg += b'\x00\x00\x00\x0e\x74\x46\x00\x00\x00\x00\x00\x00\x0e\xd8\x46\x00' msg += b'\x00\x00\x00\x00\x00\x0f\x3c\x53\x00\x00\x00\x00\x0f\xa0\x53\x00' msg += b'\x00\x00\x00\x10\x04\x53\x55\xaa\x00\x00\x10\x68\x53\x00\x01\x00' msg += b'\x00\x10\xcc\x53\x00\x00\x00\x00\x11\x30\x53\x00\x00\x00\x00\x11' msg += b'\x94\x53\x00\x00\x00\x00\x11\xf8\x53\xff\xff\x00\x00\x12\x5c\x53' msg += b'\x03\x20\x00\x00\x12\xc0\x53\x00\x02\x00\x00\x13\x24\x53\x04\x00' msg += b'\x00\x00\x13\x88\x53\x04\x00\x00\x00\x13\xec\x53\x04\x00\x00\x00' msg += b'\x14\x50\x53\x04\x00\x00\x00\x14\xb4\x53\x00\x01\x00\x00\x15\x18' msg += b'\x53\x08\x04\x00\x00\x15\x7c\x53\x00\x00\x00\x00\x27\x10\x53\x00' msg += b'\x02\x00\x00\x27\x74\x53\x00\x3c\x00\x00\x27\xd8\x53\x00\x68\x00' msg += b'\x00\x28\x3c\x53\x05\x00\x00\x00\x28\xa0\x46\x43\x79\x00\x00\x00' msg += b'\x00\x29\x04\x46\x43\x48\x00\x00\x00\x00\x29\x68\x46\x42\x48\x33' msg += b'\x33\x00\x00\x29\xcc\x46\x42\x3e\x3d\x71\x00\x00\x2a\x30\x53\x00' msg += b'\x01\x00\x00\x2a\x94\x46\x43\x37\x00\x00\x00\x00\x2a\xf8\x46\x42' msg += b'\xce\x00\x00\x00\x00\x2b\x5c\x53\x00\x96\x00\x00\x2b\xc0\x53\x00' msg += b'\x10\x00\x00\x2c\x24\x46\x43\x90\x00\x00\x00\x00\x2c\x88\x46\x43' msg += b'\x95\x00\x00\x00\x00\x2c\xec\x53\x00\x06\x00\x00\x2d\x50\x53\x00' msg += b'\x06\x00\x00\x2d\xb4\x46\x43\x7d\x00\x00\x00\x00\x2e\x18\x46\x42' msg += b'\x3d\xeb\x85\x00\x00\x2e\x7c\x46\x42\x3d\xeb\x85\x00\x00\x2e\xe0' msg += b'\x53\x00\x03\x00\x00\x2f\x44\x53\x00\x03\x00\x00\x2f\xa8\x46\x42' msg += b'\x4d\xeb\x85\x00\x00\x30\x0c\x46\x42\x4d\xeb\x85\x00\x00\x30\x70' msg += b'\x53\x00\x03\x00\x00\x30\xd4\x53\x00\x03\x00\x00\x31\x38\x46\x42' msg += b'\x08\x00\x00\x00\x00\x31' return msg @pytest.fixture def multiple_recv_buf(): # There are three message in the buffer, but the second has overwritten the first partly msg = b'\x00\x00\x05\x02\x10R170000000000001\x91\x04\x01\x90\x00\x01\x10R170000000000001' msg += b'\x01\x00\x00\x01\x89\xc6\x63\x61\x08' msg += b'\x00\x00\x00\xa3\x00\x00\x00\x64\x53\x00\x01' msg += b'\x00\x00\x00\xc8\x53\x00\x00\x00\x00\x01\x2c\x53\x00\x02\x00\x00' # | ....S.....,S.... msg += b'\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00\x00\x00' # | ..I........S.... msg += b'\x13\x10\x52\x31\x37\x45\x37\x33\x30\x37\x30\x32\x31\x44\x30\x30' # | ..R17E7307021D00 msg += b'\x36\x41\x91\x22\x00\x00\x03\xbf\x10\x52\x31\x37\x45\x37\x33\x30' # | 6A.".....R17E730 msg += b'\x37\x30\x32\x31\x44\x30\x30\x36\x41\x91\x71\x0e\x10\x00\x00\x10' # | 7021D006A.q..... msg += b'\x52\x31\x37\x45\x37\x33\x30\x37\x30\x32\x31\x44\x30\x30\x36\x41' # | R17E7307021D006A msg += b'\x01\x00\x00\x01\x91\xa3\xfe\xaf\x98\x00\x00\x00\x35\x00\x09\x2b' # | ............5..+ msg += b'\xa8\x54\x10\x52\x53\x57\x5f\x34\x30\x30\x5f\x56\x31\x2e\x30\x30' # | .T.RSW_400_V1.00 msg += b'\x2e\x31\x37\x00\x09\x27\xc0\x54\x06\x52\x61\x79\x6d\x6f\x6e\x00' # | .17..'.T.Raymon. msg += b'\x09\x2f\x90\x54\x0b\x52\x53\x57\x2d\x31\x2d\x31\x30\x30\x30\x31' # | ./.T.RSW-1-10001 msg += b'\x00\x09\x5a\x88\x54\x0f\x74\x2e\x72\x61\x79\x6d\x6f\x6e\x69\x6f' # | ..Z.T.t.raymonio msg += b'\x74\x2e\x63\x6f\x6d\x00\x09\x5a\xec\x54\x1c\x6c\x6f\x67\x67\x65' # | t.com..Z.T.logge msg += b'\x72\x2e\x74\x61\x6c\x65\x6e\x74\x2d\x6d\x6f\x6e\x69\x74\x6f\x72' # | r.talent-monitor msg += b'\x69\x6e\x67\x2e\x63\x6f\x6d\x00\x0d\x2f\x00\x54\x10\xff\xff\xff' # | ing.com../.T.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x32' # | ...............2 msg += b'\xe8\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .T.............. msg += b'\xff\xff\xff\x00\x0d\x36\xd0\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .....6.T........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x3a\xb8\x54\x10\xff' # | ...........:.T.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x3e\xa0\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .>.T............ msg += b'\xff\xff\xff\xff\xff\x00\x0d\x42\x88\x54\x10\xff\xff\xff\xff\xff' # | .......B.T...... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x46\x70\x54' # | .............FpT msg += b'\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\x00\x0d\x4a\x58\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ...JXT.......... msg += b'\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x4e\x40\x54\x10\xff\xff\xff' # | .........N@T.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x52' # | ...............R msg += b'\x28\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | (T.............. msg += b'\xff\xff\xff\x00\x0d\x56\x10\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .....V.T........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x59\xf8\x54\x10\xff' # | ...........Y.T.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x5d\xe0\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .].T............ msg += b'\xff\xff\xff\xff\xff\x00\x0d\x61\xc8\x54\x10\xff\xff\xff\xff\xff' # | .......a.T...... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x65\xb0\x54' # | .............e.T msg += b'\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\x00\x0d\x69\x98\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ...i.T.......... msg += b'\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x6d\x80\x54\x10\xff\xff\xff' # | .........m.T.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x71' # | ...............q msg += b'\x68\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | hT.............. msg += b'\xff\xff\xff\x00\x0d\x75\x50\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .....uPT........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x79\x38\x54\x10\xff' # | ...........y8T.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x7d\x20\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .} T............ msg += b'\xff\xff\xff\xff\xff\x00\x0d\x81\x08\x54\x10\xff\xff\xff\xff\xff' # | .........T...... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x84\xf0\x54' # | ...............T msg += b'\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\x00\x0d\x88\xd8\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .....T.......... msg += b'\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x8c\xc0\x54\x10\xff\xff\xff' # | ...........T.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x90' # | ................ msg += b'\xa8\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .T.............. msg += b'\xff\xff\xff\x00\x0d\x94\x90\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .......T........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x98\x78\x54\x10\xff' # | ............xT.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x00\x20\x49\x00\x00\x00\x01\x00\x0c\x35\x00\x49\x00\x00\x00' # | .. I......5.I... msg += b'\x28\x00\x0c\x96\xa8\x49\x00\x00\x01\x69\x00\x0c\x7f\x38\x49\x00' # | (....I...i...8I. msg += b'\x00\x00\x01\x00\x0c\xfc\x38\x49\x00\x00\x00\x01\x00\x0c\xf8\x50' # | ......8I.......P msg += b'\x49\x00\x00\x01\x2c\x00\x0c\x63\xe0\x49\x00\x00\x00\x00\x00\x0c' # | I...,..c.I...... msg += b'\x67\xc8\x49\x00\x00\x00\x00\x00\x0c\x50\x58\x49\x00\x00\x00\x01' # | g.I......PXI.... msg += b'\x00\x09\x5e\x70\x49\x00\x00\x13\x8d\x00\x09\x5e\xd4\x49\x00\x00' # | ..^pI......^.I.. msg += b'\x13\x8d\x00\x09\x5b\x50\x49\x00\x00\x00\x02\x00\x0d\x04\x08\x49' # | ....[PI........I msg += b'\x00\x00\x00\x00\x00\x07\xa1\x84\x49\x00\x00\x00\x01\x00\x0c\x50' # | ........I......P msg += b'\x59\x49\x00\x00\x00\x3e\x00\x0d\x1f\x60\x49\x00\x00\x00\x00\x00' # | YI...>...`I..... msg += b'\x0d\x23\x48\x49\xff\xff\xff\xff\x00\x0d\x27\x30\x49\xff\xff\xff' # | .#HI......'0I... msg += b'\xff\x00\x0d\x2b\x18\x4c\x00\x00\x00\x00\xff\xff\xff\xff\x00\x0c' # | ...+.L.......... msg += b'\xa2\x60\x49\x00\x00\x00\x00\x00\x00\x05\x02\x10\x52\x31\x37\x45' # | .`I.........R17E msg += b'\x37\x33\x30\x37\x30\x32\x31\x44\x30\x30\x36\x41\x91\x04\x01\x90' # | 7307021D006A.... msg += b'\x00\x01\x10\x54\x31\x37\x45\x37\x33\x30\x37\x30\x32\x31\x44\x30' # | ...T17E7307021D0 msg += b'\x30\x36\x41\x01\x00\x00\x01\x91\xa3\xfe\xb3\x80\x00\x00\x00\xa3' # | 06A............. msg += b'\x00\x00\x00\x64\x53\x00\x01\x00\x00\x00\xc8\x53\x00\x00\x00\x00' # | ...dS......S.... msg += b'\x01\x2c\x53\x00\x02\x00\x00\x01\x90\x49\x00\x00\x00\x00\x00\x00' # | .,S......I...... msg += b'\x01\x91\x53\x00\x00\x00\x00\x01\x92\x53\x00\x00\x00\x00\x01\x93' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x01\x94\x53\x00\x00\x00\x00\x01\x95\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x01\x96\x53\x00\x00\x00\x00\x01\x97\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x01\x98\x53\x00\x00\x00\x00\x01\x99\x53\x00\x00\x00\x00\x01' # | ...S......S..... msg += b'\x9a\x53\x00\x00\x00\x00\x01\x9b\x53\x00\x00\x00\x00\x01\x9c\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x01\x9d\x53\x00\x00\x00\x00\x01\x9e\x53\x00\x00' # | ......S......S.. msg += b'\x00\x00\x01\x9f\x53\x00\x00\x00\x00\x01\xa0\x53\x00\x00\x00\x00' # | ....S......S.... msg += b'\x01\xf4\x49\x00\x00\x00\x00\x00\x00\x01\xf5\x53\x00\x00\x00\x00' # | ..I........S.... msg += b'\x01\xf6\x53\x00\x00\x00\x00\x01\xf7\x53\x00\x00\x00\x00\x01\xf8' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x01\xf9\x53\x00\x00\x00\x00\x01\xfa\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x01\xfb\x53\x00\x00\x00\x00\x01\xfc\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x01\xfd\x53\x00\x00\x00\x00\x01\xfe\x53\x00\x00\x00\x00\x01' # | ...S......S..... msg += b'\xff\x53\x00\x00\x00\x00\x02\x00\x53\x00\x00\x00\x00\x02\x01\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x02\x02\x53\x00\x00\x00\x00\x02\x03\x53\x00\x00' # | ......S......S.. msg += b'\x00\x00\x02\x04\x53\x00\x00\x00\x00\x02\x58\x49\x00\x00\x00\x00' # | ....S.....XI.... msg += b'\x00\x00\x02\x59\x53\x00\x00\x00\x00\x02\x5a\x53\x00\x00\x00\x00' # | ...YS.....ZS.... msg += b'\x02\x5b\x53\x00\x00\x00\x00\x02\x5c\x53\x00\x00\x00\x00\x02\x5d' # | .[S.....\S.....] msg += b'\x53\x00\x00\x00\x00\x02\x5e\x53\x00\x00\x00\x00\x02\x5f\x53\x00' # | S.....^S....._S. msg += b'\x00\x00\x00\x02\x60\x53\x00\x00\x00\x00\x02\x61\x53\x00\x00\x00' # | ....`S.....aS... msg += b'\x00\x02\x62\x53\x00\x00\x00\x00\x02\x63\x53\x00\x00\x00\x00\x02' # | ..bS.....cS..... msg += b'\x64\x53\x00\x00\x00\x00\x02\x65\x53\x00\x00\x00\x00\x02\x66\x53' # | dS.....eS.....fS msg += b'\x00\x00\x00\x00\x02\x67\x53\x00\x00\x00\x00\x02\x68\x53\x00\x00' # | .....gS.....hS.. msg += b'\x00\x00\x02\xbc\x49\x00\x00\x00\x00\x00\x00\x02\xbd\x53\x00\x00' # | ....I........S.. msg += b'\x00\x00\x02\xbe\x53\x00\x00\x00\x00\x02\xbf\x53\x00\x00\x00\x00' # | ....S......S.... msg += b'\x02\xc0\x53\x00\x00\x00\x00\x02\xc1\x53\x00\x00\x00\x00\x02\xc2' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x02\xc3\x53\x00\x00\x00\x00\x02\xc4\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x02\xc5\x53\x00\x00\x00\x00\x02\xc6\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x02\xc7\x53\x00\x00\x00\x00\x02\xc8\x53\x00\x00\x00\x00\x02' # | ...S......S..... msg += b'\xc9\x53\x00\x00\x00\x00\x02\xca\x53\x00\x00\x00\x00\x02\xcb\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x02\xcc\x53\x00\x00\x00\x00\x03\x20\x53\x00\x00' # | ......S..... S.. msg += b'\x00\x00\x03\x84\x53\x51\x09\x00\x00\x03\xe8\x46\x43\x65\x99\x9a' # | ....SQ.....FCe.. msg += b'\x00\x00\x04\x4c\x46\x3e\xd7\x0a\x3d\x00\x00\x04\xb0\x46\x42\x48' # | ...LF>..=....FBH msg += b'\x28\xf6\x00\x00\x05\x14\x53\x00\x1f\x00\x00\x05\x78\x53\x00\x00' # | (.....S.....xS.. msg += b'\x00\x00\x05\xdc\x53\x02\x58\x00\x00\x06\x40\x46\x42\xc1\x33\x33' # | ....S.X...@FB.33 msg += b'\x00\x00\x06\xa4\x46\x3f\x33\x33\x33\x00\x00\x07\x08\x46\x00\x00' # | ....F?333....F.. msg += b'\x00\x00\x00\x00\x07\x6c\x46\x00\x00\x00\x00\x00\x00\x07\xd0\x46' # | .....lF........F msg += b'\x42\x05\x99\x9a\x00\x00\x08\x34\x46\x40\x41\xeb\x85\x00\x00\x08' # | B......4F@A..... msg += b'\x98\x46\x42\xcb\x66\x66\x00\x00\x08\xfc\x46\x00\x00\x00\x00\x00' # | .FB.ff....F..... msg += b'\x00\x09\x60\x46\x00\x00\x00\x00\x00\x00\x09\xc4\x46\x00\x00\x00' # | ..`F........F... msg += b'\x00\x00\x00\x0a\x28\x46\x00\x00\x00\x00\x00\x00\x0a\x8c\x46\x00' # | ....(F........F. msg += b'\x00\x00\x00\x00\x00\x0a\xf0\x46\x00\x00\x00\x00\x00\x00\x0b\x54' # | .......F.......T msg += b'\x46\x3f\x19\x99\x9a\x00\x00\x0b\xb8\x46\x43\xf3\x95\xc3\x00\x00' # | F?.......FC..... msg += b'\x0c\x1c\x46\x00\x00\x00\x00\x00\x00\x0c\x80\x46\x43\x04\x4a\x3d' # | ..F........FC.J= msg += b'\x00\x00\x0c\xe4\x46\x3f\x23\xd7\x0a\x00\x00\x0d\x48\x46\x43\xbf' # | ....F?#.....HFC. msg += b'\x9e\xb8\x00\x00\x0d\xac\x46\x00\x00\x00\x00\x00\x00\x0e\x10\x46' # | ......F........F msg += b'\x00\x00\x00\x00\x00\x00\x0e\x74\x46\x00\x00\x00\x00\x00\x00\x0e' # | .......tF....... msg += b'\xd8\x46\x00\x00\x00\x00\x00\x00\x0f\x3c\x53\x00\x00\x00\x00\x0f' # | .F.......=q..* msg += b'\x30\x53\x00\x01\x00\x00\x2a\x94\x46\x43\x37\x00\x00\x00\x00\x2a' # | 0S....*.FC7....* msg += b'\xf8\x46\x42\xce\x00\x00\x00\x00\x2b\x5c\x53\x00\x96\x00\x00\x2b' # | .FB.....+\S....+ msg += b'\xc0\x53\x00\x10\x00\x00\x2c\x24\x46\x43\x90\x00\x00\x00\x00\x2c' # | .S....,$FC....., msg += b'\x88\x46\x43\x95\x00\x00\x00\x00\x2c\xec\x53\x00\x06\x00\x00\x2d' # | .FC.....,.S....- msg += b'\x50\x53\x00\x06\x00\x00\x2d\xb4\x46\x43\x7d\x00\x00\x00\x00\x2e' # | PS....-.FC}..... msg += b'\x18\x46\x42\x3d\xeb\x85\x00\x00\x2e\x7c\x46\x42\x3d\xeb\x85\x00' # | .FB=.....|FB=... msg += b'\x00\x2e\xe0\x53\x00\x03\x00\x00\x2f\x44\x53\x00\x03\x00\x00\x2f' # | ...S..../DS..../ msg += b'\xa8\x46\x42\x4d\xeb\x85\x00\x00\x30\x0c\x46\x42\x4d\xeb\x85\x00' # | .FBM....0.FBM... msg += b'\x00\x30\x70\x53\x00\x03\x00\x00\x30\xd4\x53\x00\x03\x00\x00\x31' # | .0pS....0.S....1 msg += b'\x38\x46\x42\x08\x00\x00\x00\x00\x31\x9c\x53\x00\x05\x00\x00\x32' # | 8FB.....1.S....2 msg += b'\x00\x53\x01\x61\x00\x00\x32\x64\x53\x00\x01\x00\x00\x32\xc8\x53' # | .S.a..2dS....2.S msg += b'\x13\x9c\x00\x00\x33\x2c\x53\x0f\xa0\x00\x00\x33\x90\x53\x00\x4f' # | ....3,S....3.S.O msg += b'\x00\x00\x33\xf4\x53\x00\x66\x00\x00\x34\x58\x53\x03\xe8\x00\x00' # | ..3.S.f..4XS.... msg += b'\x34\xbc\x53\x04\x00\x00\x00\x35\x20\x53\x09\xc4\x00\x00\x35\x84' # | 4.S....5 S....5. msg += b'\x53\x07\xc6\x00\x00\x35\xe8\x53\x13\x8c\x00\x00\x36\x4c\x53\x12' # | S....5.S....6LS. msg += b'\x94\x00\x01\x38\x80\x53\x00\x02\x00\x01\x38\x81\x53\x00\x01\x00' # | ...8.S....8.S... msg += b'\x01\x38\x82\x53\x00\x01\x00\x01\x38\x83\x53\x00\x00\x00\x00\x00' # | .8.S....8.S..... msg += b'\x8b\x10\x52\x31\x37\x45\x37\x33\x30\x37\x30\x32\x31\x44\x30\x30' # | ..R17E7307021D00 msg += b'\x36\x41\x91\x04\x01\x90\x00\x01\x10\x54\x31\x37\x45\x37\x33\x30' # | 6A.......T17E730 msg += b'\x37\x30\x32\x31\x44\x30\x30\x36\x41\x01\x00\x00\x01\x91\xa3\xfe' # | 7021D006A....... msg += b'\xb3\x80\x00\x00\x00\x06\x00\x00\x00\x0a\x54\x08\x4d\x69\x63\x72' # | ..........T.Micr msg += b'\x6f\x69\x6e\x76\x00\x00\x00\x14\x54\x04\x54\x53\x55\x4e\x00\x00' # | oinv....T.TSUN.. msg += b'\x00\x1e\x54\x07\x56\x35\x2e\x31\x2e\x30\x39\x00\x00\x00\x28\x54' # | ..T.V5.1.09...(T msg += b'\x10\x54\x31\x37\x45\x37\x33\x30\x37\x30\x32\x31\x44\x30\x30\x36' # | .T17E7307021D006 msg += b'\x41\x00\x00\x00\x32\x54\x0a\x54\x53\x4f\x4c\x2d\x4d\x53\x36\x30' # | A...2T.TSOL-MS60 msg += b'\x30\x00\x00\x00\x3c\x54\x05\x41\x2c\x42\x2c\x43' # | 0....T msg += b'\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\x00\x0d\x42\x88\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ...B.T.......... msg += b'\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x46\x70\x54\x10\xff\xff\xff' # | .........FpT.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x4a' # | ...............J msg += b'\x58\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | XT.............. msg += b'\xff\xff\xff\x00\x0d\x4e\x40\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .....N@T........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x52\x28\x54\x10\xff' # | ...........R(T.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x56\x10\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .V.T............ msg += b'\xff\xff\xff\xff\xff\x00\x0d\x59\xf8\x54\x10\xff\xff\xff\xff\xff' # | .......Y.T...... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x5d\xe0\x54' # | .............].T msg += b'\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\x00\x0d\x61\xc8\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ...a.T.......... msg += b'\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x65\xb0\x54\x10\xff\xff\xff' # | .........e.T.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x69' # | ...............i msg += b'\x98\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .T.............. msg += b'\xff\xff\xff\x00\x0d\x6d\x80\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .....m.T........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x71\x68\x54\x10\xff' # | ...........qhT.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x75\x50\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .uPT............ msg += b'\xff\xff\xff\xff\xff\x00\x0d\x79\x38\x54\x10\xff\xff\xff\xff\xff' # | .......y8T...... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x7d\x20\x54' # | .............} T msg += b'\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\x00\x0d\x81\x08\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .....T.......... msg += b'\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x84\xf0\x54\x10\xff\xff\xff' # | ...........T.... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x88' # | ................ msg += b'\xd8\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | .T.............. msg += b'\xff\xff\xff\x00\x0d\x8c\xc0\x54\x10\xff\xff\xff\xff\xff\xff\xff' # | .......T........ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x90\xa8\x54\x10\xff' # | .............T.. msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00' # | ................ msg += b'\x0d\x94\x90\x54\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ...T............ msg += b'\xff\xff\xff\xff\xff\x00\x0d\x98\x78\x54\x10\xff\xff\xff\xff\xff' # | ........xT...... msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x0d\x9c\x60\x54' # | ..............`T msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' # | ................ msg += b'\x00\x0d\x00\x20\x49\x00\x00\x00\x01\x00\x0c\x35\x00\x49\x00\x00' # | ... I......5.I.. msg += b'\x00\x62\x00\x0c\x96\xa8\x49\x00\x00\x01\x4f\x00\x0c\x7f\x38\x49' # | .b....I...O...8I msg += b'\x00\x00\x00\x01\x00\x0c\xfc\x38\x49\x00\x00\x00\x01\x00\x0c\xf8' # | .......8I....... msg += b'\x50\x49\x00\x00\x01\x2c\x00\x0c\x63\xe0\x49\x00\x00\x00\x00\x00' # | PI...,..c.I..... msg += b'\x0c\x67\xc8\x49\x00\x00\x00\x00\x00\x0c\x50\x58\x49\x00\x00\x00' # | .g.I......PXI... msg += b'\x01\x00\x09\x5e\x70\x49\x00\x00\x13\x8d\x00\x09\x5e\xd4\x49\x00' # | ...^pI......^.I. msg += b'\x00\x13\x8d\x00\x09\x5b\x50\x49\x00\x00\x00\x02\x00\x0d\x04\x08' # | .....[PI........ msg += b'\x49\x00\x00\x00\x00\x00\x07\xa1\x84\x49\x00\x00\x00\x01\x00\x0c' # | I........I...... msg += b'\x50\x59\x49\x00\x00\x00\x2d\x00\x0d\x1f\x60\x49\x00\x00\x00\x00' # | PYI...-...`I.... msg += b'\x00\x0d\x23\x48\x49\xff\xff\xff\xff\x00\x0d\x27\x30\x49\xff\xff' # | ..#HI......'0I.. msg += b'\xff\xff\x00\x0d\x2b\x18\x4c\x00\x00\x00\x00\xff\xff\xff\xff\x00' # | ....+.L......... msg += b'\x0c\xa2\x60\x49\x00\x00\x00\x00\x00\x0d\xa0\x48\x49\x00\x00\x00' # | ..`I.......HI... msg += b'\x00\x00\x0d\xa4\x30\x49\x00\x00\x00\xff\x00\x0d\xa8\x18\x49\x00' # | ....0I........I. msg += b'\x00\x00\xff' return msg @pytest.fixture def msg_inverter_ms3000_ind(): # Data indication from the controller msg = b'\x00\x00\x08\xff\x10R170000000000001\x91\x04\x01\x90\x00\x00\x10R170000000000001' msg += b'\x01\x00\x00\x01' msg += b'\x95\x18\x5e\x1d\x80\x00\x00\x01\x2c\x00\x00\x00\x64\x53\x00\x00' # | ..^.....,...dS.. msg += b'\x00\x00\x00\xc8\x53\x44\x00\x00\x00\x01\x2c\x53\x00\x00\x00\x00' # | ....SD....,S.... msg += b'\x01\x90\x49\x00\x00\x00\x00\x00\x00\x01\x91\x53\x00\x00\x00\x00' # | ..I........S.... msg += b'\x01\x92\x53\x00\x00\x00\x00\x01\x93\x53\x00\x00\x00\x00\x01\x94' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x01\x95\x53\x00\x00\x00\x00\x01\x96\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x01\x97\x53\x00\x00\x00\x00\x01\x98\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x01\x99\x53\x00\x00\x00\x00\x01\x9a\x53\x00\x00\x00\x00\x01' # | ...S......S..... msg += b'\x9b\x53\x00\x00\x00\x00\x01\x9c\x53\x00\x00\x00\x00\x01\x9d\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x01\x9e\x53\x00\x00\x00\x00\x01\x9f\x53\x00\x00' # | ......S......S.. msg += b'\x00\x00\x01\xa0\x53\x00\x00\x00\x00\x01\xf4\x49\x00\x00\x00\x00' # | ....S......I.... msg += b'\x00\x00\x01\xf5\x53\x00\x00\x00\x00\x01\xf6\x53\x00\x00\x00\x00' # | ....S......S.... msg += b'\x01\xf7\x53\x00\x00\x00\x00\x01\xf8\x53\x00\x00\x00\x00\x01\xf9' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x01\xfa\x53\x00\x00\x00\x00\x01\xfb\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x01\xfc\x53\x00\x00\x00\x00\x01\xfd\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x01\xfe\x53\x00\x00\x00\x00\x01\xff\x53\x00\x00\x00\x00\x02' # | ...S......S..... msg += b'\x00\x53\x00\x00\x00\x00\x02\x01\x53\x00\x00\x00\x00\x02\x02\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x02\x03\x53\x00\x00\x00\x00\x02\x04\x53\x00\x00' # | ......S......S.. msg += b'\x00\x00\x02\x58\x49\x00\x00\x00\x00\x00\x00\x02\x59\x53\x00\x00' # | ...XI.......YS.. msg += b'\x00\x00\x02\x5a\x53\x00\x00\x00\x00\x02\x5b\x53\x00\x00\x00\x00' # | ...ZS.....[S.... msg += b'\x02\x5c\x53\x00\x00\x00\x00\x02\x5d\x53\x00\x00\x00\x00\x02\x5e' # | .\S.....]S.....^ msg += b'\x53\x00\x00\x00\x00\x02\x5f\x53\x00\x00\x00\x00\x02\x60\x53\x00' # | S....._S.....`S. msg += b'\x00\x00\x00\x02\x61\x53\x00\x00\x00\x00\x02\x62\x53\x00\x00\x00' # | ....aS.....bS... msg += b'\x00\x02\x63\x53\x00\x00\x00\x00\x02\x64\x53\x00\x00\x00\x00\x02' # | ..cS.....dS..... msg += b'\x65\x53\x00\x00\x00\x00\x02\x66\x53\x00\x00\x00\x00\x02\x67\x53' # | eS.....fS.....gS msg += b'\x00\x00\x00\x00\x02\x68\x53\x00\x00\x00\x00\x02\xbc\x49\x00\x00' # | .....hS......I.. msg += b'\x00\x00\x00\x00\x02\xbd\x53\x00\x00\x00\x00\x02\xbe\x53\x00\x00' # | ......S......S.. msg += b'\x00\x00\x02\xbf\x53\x00\x00\x00\x00\x02\xc0\x53\x00\x00\x00\x00' # | ....S......S.... msg += b'\x02\xc1\x53\x00\x00\x00\x00\x02\xc2\x53\x00\x00\x00\x00\x02\xc3' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x02\xc4\x53\x00\x00\x00\x00\x02\xc5\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x02\xc6\x53\x00\x00\x00\x00\x02\xc7\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x02\xc8\x53\x00\x00\x00\x00\x02\xc9\x53\x00\x00\x00\x00\x02' # | ...S......S..... msg += b'\xca\x53\x00\x00\x00\x00\x02\xcb\x53\x00\x00\x00\x00\x02\xcc\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x03\x20\x53\x00\x01\x00\x00\x03\x84\x53\x11\x68' # | ..... S......S.h msg += b'\x00\x00\x03\xe8\x46\x44\x23\xd1\xec\x00\x00\x04\x4c\x46\x43\xa3' # | ....FD#.....LFC. msg += b'\xb3\x33\x00\x00\x04\xb0\x46\x00\x00\x00\x00\x00\x00\x05\x14\x46' # | .3....F........F msg += b'\x43\x6e\x80\x00\x00\x00\x05\x78\x46\x3d\x4c\xcc\xcd\x00\x00\x05' # | Cn.....xF=L..... msg += b'\xdc\x46\x00\x00\x00\x00\x00\x00\x06\x40\x46\x42\x48\x00\x00\x00' # | .F.......@FBH... msg += b'\x00\x06\xa4\x53\x00\x03\x00\x00\x07\x08\x53\x00\x0c\x00\x00\x07' # | ...S......S..... msg += b'\x6c\x53\x00\x50\x00\x00\x07\xd0\x46\x43\xa3\xb3\x33\x00\x00\x08' # | lS.P....FC..3... msg += b'\x34\x53\x0b\xb8\x00\x00\x08\x98\x46\x00\x00\x00\x00\x00\x00\x08' # | 4S......F....... msg += b'\xfc\x46\x00\x00\x00\x00\x00\x00\x09\x60\x46\x41\xee\xe1\x48\x00' # | .F.......`FA..H. msg += b'\x00\x09\xc4\x53\x00\x00\x00\x00\x0a\x28\x46\x41\xf2\x00\x00\x00' # | ...S.....(FA.... msg += b'\x00\x0a\x8c\x46\x3f\xac\x28\xf6\x00\x00\x0a\xf0\x53\x00\x0c\x00' # | ...F?.(.....S... msg += b'\x00\x0b\x54\x53\x00\x00\x00\x00\x0b\xb8\x53\x00\x00\x00\x00\x0c' # | ..TS......S..... msg += b'\x1c\x53\x00\x00\x00\x00\x0c\x80\x53\x00\x00\x00\x00\x0c\xe4\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x0d\x48\x53\x00\x00\x00\x00\x0d\xac\x53\x00\x00' # | .....HS......S.. msg += b'\x00\x00\x0e\x10\x53\x00\x00\x00\x00\x0e\x74\x53\x00\x00\x00\x00' # | ....S.....tS.... msg += b'\x0e\xd8\x53\x00\x00\x00\x00\x0f\x3c\x53\x00\x00\x00\x00\x0f\xa0' # | ..S.....S.....?S.... msg += b'\x18\x40\x53\x00\x00\x00\x00\x18\x41\x53\x00\x00\x00\x00\x18\x42' # | .@S.....AS.....B msg += b'\x53\x00\x00\x00\x00\x18\x43\x53\x00\x00\x00\x00\x18\x44\x53\x00' # | S.....CS.....DS. msg += b'\x00\x00\x00\x18\x45\x53\x00\x00\x00\x00\x18\x46\x53\x00\x00\x00' # | ....ES.....FS... msg += b'\x00\x18\x47\x53\x00\x00\x00\x00\x18\x48\x53\x00\x00\x00\x00\x18' # | ..GS.....HS..... msg += b'\x9c\x46\x42\x6b\x33\x33\x00\x00\x19\x00\x46\x00\x00\x00\x00\x00' # | .FBk33....F..... msg += b'\x00\x19\x64\x46\x00\x00\x00\x00\x00\x00\x19\xc8\x46\x42\xdc\x00' # | ..dF........FB.. msg += b'\x00\x00\x00\x1a\x2c\x53\x00\x00\x00\x00\x1a\x90\x53\x00\x00\x00' # | ....,S......S... msg += b'\x00\x1a\xf4\x53\x00\x00\x00\x00\x1a\xf5\x53\x00\x00\x00\x00\x1a' # | ...S......S..... msg += b'\xf6\x53\x00\x00\x00\x00\x1a\xf7\x53\x00\x00\x00\x00\x1a\xf8\x53' # | .S......S......S msg += b'\x00\x00\x00\x00\x1a\xf9\x53\x00\x00\x00\x00\x1a\xfa\x53\x00\x00' # | ......S......S.. msg += b'\x00\x00\x1a\xfb\x53\x00\x00\x00\x00\x1a\xfc\x53\x00\x00\x00\x00' # | ....S......S.... msg += b'\x1a\xfd\x53\x00\x00\x00\x00\x1a\xfe\x53\x00\x00\x00\x00\x1a\xff' # | ..S......S...... msg += b'\x53\x00\x00\x00\x00\x1b\x00\x53\x00\x00\x00\x00\x1b\x01\x53\x00' # | S......S......S. msg += b'\x00\x00\x00\x1b\x02\x53\x00\x00\x00\x00\x1b\x03\x53\x00\x00\x00' # | .....S......S... msg += b'\x00\x1b\x04\x53\x00\x00\x00\x00\x1b\x58\x53\x00\x00\x00\x00\x1b' # | ...S.....XS..... msg += b'\xbc\x53\x11\x3d\x00\x00\x1c\x20\x46\x3c\x23\xd7\x0a\x00\x00\x1c' # | .S.=... F<#..... msg += b'\x84\x46\x00\x00\x00\x00\x00\x00\x1c\xe8\x46\x42\x04\x00\x00\x00' # | .F........FB.... msg += b'\x00\x1d\x4c\x46\x00\x00\x00\x00\x00\x00\x1d\xb0\x46\x00\x00\x00' # | ..LF........F... msg += b'\x00\x00\x00\x1e\x14\x53\x00\x02\x00\x00\x1e\x78\x46\x41\x8b\x33' # | .....S.....xFA.3 msg += b'\x33\x00\x00\x1e\xdc\x46\x3c\xa3\xd7\x0a\x00\x00\x1f\x40\x46\x3e' # | 3....F<......@F> msg += b'\x99\x99\x9a\x00\x00\x1f\xa4\x46\x40\x99\x99\x9a\x00\x00\x20\x08' # | .......F@..... . msg += b'\x53\x00\x00\x00\x00\x20\x6c\x53\x00\x00\x00\x00\x20\xd0\x53\x05' # | S.... lS.... .S. msg += b'\x00\x00\x00\x20\xd1\x53\x00\x00\x00\x00\x20\xd2\x53\x00\x00\x00' # | ... .S.... .S... msg += b'\x00\x20\xd3\x53\x00\x00\x00\x00\x20\xd4\x53\x00\x00\x00\x00\x20' # | . .S.... .S.... msg += b'\xd5\x53\x00\x00\x00\x00\x20\xd6\x53\x00\x00\x00\x00\x20\xd7\x53' # | .S.... .S.... .S msg += b'\x00\x00\x00\x00\x20\xd8\x53\x00\x00\x00\x00\x20\xd9\x53\x00\x01' # | .... .S.... .S.. msg += b'\x00\x00\x20\xda\x53\x00\x00\x00\x00\x20\xdb\x53\x00\x01\x00\x00' # | .. .S.... .S.... msg += b'\x20\xdc\x53\x00\x00\x00\x00\x20\xdd\x53\x00\x00\x00\x00\x20\xde' # | .S.... .S.... . msg += b'\x53\x00\x00\x00\x00\x20\xdf\x53\x00\x00\x00\x00\x20\xe0\x53\x00' # | S.... .S.... .S. msg += b'\x00\x00\x00\x21\x34\x46\x00\x00\x00\x00\x00\x00\x21\x98\x46\x00' # | ...!4F......!.F. msg += b'\x00\x00\x00\x00\x00\x21\xfc\x46\x00\x00\x00\x00\x00\x00\x22\x60' # | .....!.F......"` msg += b'\x46\x00\x00\x00\x00\x00\x00\x22\xc4\x53\x00\x00\x00\x00\x23\x28' # | F......".S....#( msg += b'\x53\x00\x00\x00\x00\x23\x8c\x53\x00\x00\x00\x00\x23\x8d\x53\x00' # | S....#.S....#.S. msg += b'\x00\x00\x00\x23\x8e\x53\x00\x00\x00\x00\x23\x8f\x53\x00\x00\x00' # | ...#.S....#.S... msg += b'\x00\x23\x90\x53\x00\x00\x00\x00\x23\x91\x53\x00\x00\x00\x00\x23' # | .#.S....#.S....# msg += b'\x92\x53\x00\x00\x00\x00\x23\x93\x53\x00\x00\x00\x00\x23\x94\x53' # | .S....#.S....#.S msg += b'\x00\x00\x00\x00\x23\x95\x53\x00\x00\x00\x00\x23\x96\x53\x00\x00' # | ....#.S....#.S.. msg += b'\x00\x00\x23\x97\x53\x00\x00\x00\x00\x23\x98\x53\x00\x00\x00\x00' # | ..#.S....#.S.... msg += b'\x23\x99\x53\x00\x00\x00\x00\x23\x9a\x53\x00\x00\x00\x00\x23\x9b' # | #.S....#.S....#. msg += b'\x53\x00\x00\x00\x00\x23\x9c\x53\x00\x00\x00\x00\x23\xf0\x46\x00' # | S....#.S....#.F. msg += b'\x00\x00\x00\x00\x00\x24\x54\x46\x00\x00\x00\x00\x00\x00\x24\xb8' # | .....$TF......$. msg += b'\x46\x00\x00\x00\x00\x00\x00\x25\x1c\x46\x00\x00\x00\x00\x00\x00' # | F......%.F...... msg += b'\x25\x80\x53\x00\x00\x00\x00\x25\xe4\x53\x00\x00\x00\x00\x26\x48' # | %.S....%.S....&H msg += b'\x53\x00\x00\x00\x00\x26\x49\x53\x00\x00\x00\x00\x26\x4a\x53\x00' # | S....&IS....&JS. msg += b'\x00\x00\x00\x26\x4b\x53\x00\x00\x00\x00\x26\x4c\x53\x00\x00\x00' # | ...&KS....&LS... msg += b'\x00\x26\x4d\x53\x00\x00\x00\x00\x26\x4e\x53\x00\x00\x00\x00\x26' # | .&MS....&NS....& msg += b'\x4f\x53\x00\x00\x00\x00\x26\x50\x53\x00\x00\x00\x00\x26\x51\x53' # | OS....&PS....&QS msg += b'\x00\x00\x00\x00\x26\x52\x53\x00\x00\x00\x00\x26\x53\x53\x00\x00' # | ....&RS....&SS.. msg += b'\x00\x00\x26\x54\x53\x00\x00\x00\x00\x26\x55\x53\x00\x00\x00\x00' # | ..&TS....&US.... msg += b'\x26\x56\x53\x00\x00\x00\x00\x26\x57\x53\x00\x00\x00\x00\x26\x58' # | &VS....&WS....&X msg += b'\x53\x00\x00\x00\x00\x26\xac\x53\x00\x00\x00\x00\x27\x10\x53\x11' # | S....&.S....'.S. msg += b'\x3d\x00\x00\x27\x74\x46\x00\x00\x00\x00\x00\x00\x27\xd8\x46\x00' # | =..'tF......'.F. msg += b'\x00\x00\x00\x00\x00\x28\x3c\x46\x42\x03\xf5\xc3\x00\x00\x28\xa0' # | .....(L.... msg += b'\x32\x00\x46\x3e\x4c\xcc\xcd\x00\x00\x32\x64\x46\x42\x4c\x14\x7b' # | 2.F>L....2dFBL.{ msg += b'\x00\x00\x32\xc8\x46\x42\x4d\xeb\x85\x00\x00\x33\x2c\x46\x3e\x4c' # | ..2.FBM....3,F>L msg += b'\xcc\xcd\x00\x00\x33\x90\x46\x3e\x4c\xcc\xcd\x00\x00\x33\xf4\x53' # | ....3.F>L....3.S msg += b'\x00\x00\x00\x00\x34\x58\x53\x00\x00\x00\x00\x34\xbc\x53\x04\x00' # | ....4XS....4.S.. msg += b'\x00\x00\x35\x20\x53\x00\x01\x00\x00\x35\x84\x53\x13\x9c\x00\x00' # | ..5 S....5.S.... msg += b'\x35\xe8\x53\x0f\xa0\x00\x00\x36\x4c\x53\x00\x00\x00\x00\x36\xb0' # | 5.S....6LS....6. msg += b'\x53\x00\x66' # | S.f' return msg def test_read_message(msg_contact_info): Config.act_config = {'tsun':{'enabled': True}} m = MemoryStream(msg_contact_info, (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.id_str == b"R170000000000001" assert m.unique_id == None assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==25 assert m.ifc.rx_get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.ifc.fwd_fifo.get()==b'' m.close() def test_read_message_twice(config_no_tsun_inv1, msg_inverter_ind): _ = config_no_tsun_inv1 m = MemoryStream(msg_inverter_ind, (0,)) m.append_msg(msg_inverter_ind) 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 == 2 assert m.msg_recvd[0]['ctrl']==145 assert m.msg_recvd[0]['msg_id']==4 assert m.msg_recvd[0]['header_len']==23 assert m.msg_recvd[0]['data_len']==120 assert m.msg_recvd[1]['ctrl']==145 assert m.msg_recvd[1]['msg_id']==4 assert m.msg_recvd[1]['header_len']==23 assert m.msg_recvd[1]['data_len']==120 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert m.ifc.fwd_fifo.get()==b'' m.close() def test_read_message_long_id(msg_contact_info_long_id): m = MemoryStream(msg_contact_info_long_id, (23,24)) m.read() # read 23 bytes, one is missing assert not m.header_valid # must be invalid, since header not complete assert m.msg_count == 0 m.read() # read the missing byte assert m.header_valid # must be valid, since header is complete but not the msg assert m.msg_count == 0 assert m.id_str == b"R1700000000000011" assert m.unique_id == 0 assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==24 assert m.data_len==25 m.read() # try to read rest of message, but there is no chunk available assert m.header_valid # must be valid, since header is complete but not the msg assert m.msg_count == 0 m.close() def test_read_message_in_chunks(msg_contact_info): Config.act_config = {'tsun':{'enabled': True}} m = MemoryStream(msg_contact_info, (4,23,0)) m.read() # read 4 bytes, header incomplere assert not m.header_valid # must be invalid, since header not complete assert m.msg_count == 0 m.read() # read missing bytes for complete header assert m.header_valid # must be valid, since header is complete but not the msg assert m.msg_count == 0 assert m.id_str == b"R170000000000001" assert m.unique_id == 0 assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==25 m.read() # read rest of message assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 1 m.close() def test_read_message_in_chunks2(msg_contact_info): Config.act_config = {'tsun':{'enabled': True}} m = MemoryStream(msg_contact_info, (4,10,0)) m.read() # read 4 bytes, header incomplere assert not m.header_valid assert m.msg_count == 0 m.read() # read 6 more bytes, header incomplere assert not m.header_valid assert m.msg_count == 0 m.read() # read rest of message assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.header_len==23 assert m.data_len==25 assert m.id_str == b"R170000000000001" assert m.unique_id == None assert int(m.ctrl)==145 assert m.msg_id==0 assert m.msg_count == 1 m.read() # read rest of message assert m.msg_count == 1 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed m.close() def test_read_two_messages(config_tsun_allow_all, msg2_contact_info,msg_contact_rsp,msg_contact_rsp2): _ = config_tsun_allow_all m = MemoryStream(msg2_contact_info, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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 == 2 assert m.id_str == b"R170000000000002" assert m.unique_id == 'R170000000000002' m.contact_name = b'solarhub' m.contact_mail = b'solarhub@123456' assert m.msg_recvd[0]['ctrl']==145 assert m.msg_recvd[0]['msg_id']==0 assert m.msg_recvd[0]['header_len']==23 assert m.msg_recvd[0]['data_len']==25 assert m.msg_recvd[1]['ctrl']==145 assert m.msg_recvd[1]['msg_id']==0 assert m.msg_recvd[1]['header_len']==23 assert m.msg_recvd[1]['data_len']==25 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==msg_contact_rsp + msg_contact_rsp2 assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.ifc.tx_clear() # clear send buffer for next test m.contact_name = b'solarhub' m.contact_mail = b'solarhub@123456' m._init_new_client_conn() assert m.ifc.tx_fifo.get()==b'\x00\x00\x00,\x10R170000000000002\x91\x00\x08solarhub\x0fsolarhub@123456' m.close() def test_conttact_req(config_tsun_allow_all, msg_contact_info, msg_contact_rsp): _ = config_tsun_allow_all m = MemoryStream(msg_contact_info, (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.id_str == b"R170000000000001" assert m.contact_name == b'solarhub' assert m.contact_mail == b'solarhub@123456' assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==25 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==msg_contact_rsp m.close() def test_contact_broken_req(config_tsun_allow_all, msg_contact_info_broken, msg_contact_rsp): _ = config_tsun_allow_all m = MemoryStream(msg_contact_info_broken, (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.id_str == b"R170000000000001" assert m.contact_name == b'' assert m.contact_mail == b'' assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==23 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==msg_contact_rsp m.close() def test_conttact_req(config_tsun_allow_all, msg_contact_info, msg_contact_rsp): _ = config_tsun_allow_all m = MemoryStream(msg_contact_info, (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.id_str == b"R170000000000001" assert m.contact_name == b'solarhub' assert m.contact_mail == b'solarhub@123456' assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==25 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==msg_contact_rsp m.close() def test_contact_broken_req(config_tsun_allow_all, msg_contact_info_broken, msg_contact_rsp): _ = config_tsun_allow_all m = MemoryStream(msg_contact_info_broken, (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.id_str == b"R170000000000001" assert m.contact_name == b'' assert m.contact_mail == b'' assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==23 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==msg_contact_rsp m.close() def test_msg_contact_resp(config_tsun_inv1, msg_contact_rsp): _ = config_tsun_inv1 m = MemoryStream(msg_contact_rsp, (0,), False) m.await_conn_resp_cnt = 1 m.db.stat['proxy']['Unknown_Ctrl'] = 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.await_conn_resp_cnt == 0 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_contact_resp_2(config_tsun_inv1, msg_contact_rsp): _ = config_tsun_inv1 m = MemoryStream(msg_contact_rsp, (0,), False) m.await_conn_resp_cnt = 0 m.db.stat['proxy']['Unknown_Ctrl'] = 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.await_conn_resp_cnt == 0 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==msg_contact_rsp assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_contact_resp_3(config_tsun_inv1, msg_contact_rsp): _ = config_tsun_inv1 m = MemoryStream(msg_contact_rsp, (0,), True) m.await_conn_resp_cnt = 0 m.db.stat['proxy']['Unknown_Ctrl'] = 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.await_conn_resp_cnt == 0 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==msg_contact_rsp assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_contact_invalid(config_tsun_inv1, msg_contact_invalid): _ = config_tsun_inv1 m = MemoryStream(msg_contact_invalid, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==147 assert m.msg_id==0 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==msg_contact_invalid assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 m.close() def test_msg_get_time(config_tsun_inv1, msg_get_time): _ = config_tsun_inv1 m = MemoryStream(msg_get_time, (0,)) m.state = State.up m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==0 assert m.data_len==0 assert m.state==State.pend assert m.ifc.fwd_fifo.get()==msg_get_time assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_get_time_autark(config_no_tsun_inv1, msg_get_time): _ = config_no_tsun_inv1 m = MemoryStream(msg_get_time, (0,)) m.state = State.received m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==0 assert m.data_len==0 assert m.state==State.received assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==bytearray(b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00') assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_time_resp(config_tsun_inv1, msg_time_rsp): # test if ts_offset will be set on client and server side _ = config_tsun_inv1 m = MemoryStream(msg_time_rsp, (0,), False) s = MemoryStream(b'', (0,), True) assert s.ts_offset==0 m.ifc.remote.stream = s m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==3600000 assert s.ts_offset==3600000 assert m.data_len==8 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.ifc.remote.stream = None s.close() m.close() def test_msg_time_resp_autark(config_no_tsun_inv1, msg_time_rsp): _ = config_no_tsun_inv1 m = MemoryStream(msg_time_rsp, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==3600000 assert m.data_len==8 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_time_inv_resp(config_tsun_inv1, msg_time_rsp_inv): _ = config_tsun_inv1 m = MemoryStream(msg_time_rsp_inv, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==0 assert m.data_len==4 assert m.ifc.fwd_fifo.get()==msg_time_rsp_inv assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_time_invalid(config_tsun_inv1, msg_time_invalid): _ = config_tsun_inv1 m = MemoryStream(msg_time_invalid, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==148 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==0 assert m.data_len==0 assert m.ifc.fwd_fifo.get()==msg_time_invalid assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 m.close() def test_msg_time_invalid_autark(config_no_tsun_inv1, msg_time_invalid): _ = config_no_tsun_inv1 m = MemoryStream(msg_time_invalid, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==148 assert m.msg_id==34 assert m.ts_offset==0 assert m.header_len==23 assert m.data_len==0 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 m.close() def test_msg_act_time(config_no_modbus_poll, msg_act_time, msg_act_time_ack): _ = config_no_modbus_poll m = MemoryStream(msg_act_time, (0,)) m.ts_offset=0 m.mb_timeout = 124 m.db.set_db_def_value(Register.POLLING_INTERVAL, 125) m.state = State.received m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==153 assert m.ts_offset==0 assert m.header_len==23 assert m.data_len==9 assert m.state == State.up assert m.ifc.fwd_fifo.get()==msg_act_time assert m.ifc.tx_fifo.get()==msg_act_time_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert 125 == m.db.get_db_value(Register.POLLING_INTERVAL, 0) m.close() def test_msg_act_time2(config_tsun_inv1, msg_act_time, msg_act_time_ack): _ = config_tsun_inv1 m = MemoryStream(msg_act_time, (0,)) m.ts_offset=0 m.modbus_polling = True m.mb_timeout = 123 m.db.set_db_def_value(Register.POLLING_INTERVAL, 125) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==153 assert m.ts_offset==0 assert m.header_len==23 assert m.data_len==9 assert m.ifc.fwd_fifo.get()==msg_act_time assert m.ifc.tx_fifo.get()==msg_act_time_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert 123 == m.db.get_db_value(Register.POLLING_INTERVAL, 0) m.close() def test_msg_act_time_ofs(config_tsun_inv1, msg_act_time, msg_act_time_ofs, msg_act_time_ack): _ = config_tsun_inv1 m = MemoryStream(msg_act_time, (0,)) m.ts_offset=3600 m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==153 assert m.ts_offset==3600 assert m.header_len==23 assert m.data_len==9 assert m.ifc.fwd_fifo.get()==msg_act_time_ofs assert m.ifc.tx_fifo.get()==msg_act_time_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_act_time_ofs2(config_tsun_inv1, msg_act_time, msg_act_time_ofs, msg_act_time_ack): _ = config_tsun_inv1 m = MemoryStream(msg_act_time_ofs, (0,)) m.ts_offset=-3600 m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==153 assert m.ts_offset==-3600 assert m.header_len==23 assert m.data_len==9 assert m.ifc.fwd_fifo.get()==msg_act_time assert m.ifc.tx_fifo.get()==msg_act_time_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_act_time_autark(config_no_tsun_inv1, msg_act_time, msg_act_time_ack): _ = config_no_tsun_inv1 m = MemoryStream(msg_act_time, (0,)) m.ts_offset=0 m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==153 assert m.ts_offset==0 assert m.header_len==23 assert m.data_len==9 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==msg_act_time_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_act_time_ack(config_tsun_inv1, msg_act_time_ack): _ = config_tsun_inv1 m = MemoryStream(msg_act_time_ack, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==153 assert m.msg_id==153 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_act_time_cmd(config_tsun_inv1, msg_act_time_cmd): _ = config_tsun_inv1 m = MemoryStream(msg_act_time_cmd, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==112 assert m.msg_id==153 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==msg_act_time_cmd assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 m.close() def test_msg_act_time_inv(config_tsun_inv1, msg_act_time_inv): _ = config_tsun_inv1 m = MemoryStream(msg_act_time_inv, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==153 assert m.header_len==23 assert m.data_len==8 assert m.ifc.fwd_fifo.get()==msg_act_time_inv assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_cntrl_ind(config_tsun_inv1, msg_controller_ind, msg_controller_ind_ts_offs, msg_controller_ack): _ = config_tsun_inv1 m = MemoryStream(msg_controller_ind, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==113 assert m.header_len==23 assert m.data_len==284 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_controller_ind m.ts_offset = -4096 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_controller_ind_ts_offs assert m.ifc.tx_fifo.get()==msg_controller_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_cntrl_ack(config_tsun_inv1, msg_controller_ack): _ = config_tsun_inv1 m = MemoryStream(msg_controller_ack, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==153 assert m.msg_id==113 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_cntrl_invalid(config_tsun_inv1, msg_controller_invalid): _ = config_tsun_inv1 m = MemoryStream(msg_controller_invalid, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==146 assert m.msg_id==113 assert m.header_len==23 assert m.data_len==1 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_controller_invalid m.ts_offset = -4096 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_controller_invalid assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 m.close() def test_msg_inv_ind(config_tsun_inv1, msg_inverter_ind, msg_inverter_ind_ts_offs, msg_inverter_ack): _ = config_tsun_inv1 tracer.setLevel(logging.DEBUG) m = MemoryStream(msg_inverter_ind, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==120 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_inverter_ind m.ts_offset = +256 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_ind_ts_offs assert m.ifc.tx_fifo.get()==msg_inverter_ack assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_inv_ind1(config_tsun_inv1, msg_inverter_ind2, msg_inverter_ind_ts_offs, msg_inverter_ack): _ = config_tsun_inv1 tracer.setLevel(logging.DEBUG) m = MemoryStream(msg_inverter_ind2, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 0 m.read() # read complete msg, and dispatch msg assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 0 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 1 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==1263 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_ind2 assert m.ifc.tx_fifo.get()==msg_inverter_ack assert m.db.get_db_value(Register.TS_GRID) == 1691243349 m.close() def test_msg_inv_ind2(config_tsun_inv1, msg_inverter_ind_new, msg_inverter_ind_ts_offs, msg_inverter_ack): _ = config_tsun_inv1 tracer.setLevel(logging.DEBUG) m = MemoryStream(msg_inverter_ind_new, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 0 m.read() # read complete msg, and dispatch msg assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 0 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 1 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==1165 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_ind_new assert m.ifc.tx_fifo.get()==msg_inverter_ack assert m.db.get_db_value(Register.INVERTER_STATUS) == None assert m.db.get_db_value(Register.TS_GRID) == None m.db.db['grid'] = {'Output_Power': 100} m.close() assert m.db.get_db_value(Register.INVERTER_STATUS) == None def test_msg_inv_ind3(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ack): '''test that after close the invert_status will be resetted if the grid power is <2W''' _ = config_tsun_inv1 tracer.setLevel(logging.DEBUG) m = MemoryStream(msg_inverter_ind_0w, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 0 m.read() # read complete msg, and dispatch msg assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 0 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 1 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==1263 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_ind_0w assert m.ifc.tx_fifo.get()==msg_inverter_ack assert m.db.get_db_value(Register.INVERTER_STATUS) == 1 assert isclose(m.db.db['grid']['Output_Power'], 0.5) m.close() assert m.db.get_db_value(Register.INVERTER_STATUS) == 0 def test_msg_inv_ind4(config_tsun_inv1, msg_inverter_ms3000_ind, msg_inverter_ack): '''Check sonar_lists of MS-3000 inverter''' _ = config_tsun_inv1 tracer.setLevel(logging.DEBUG) with patch.object(logging, 'warning') as spy: m = MemoryStream(msg_inverter_ms3000_ind, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 0 m.read() # read complete msg, and dispatch msg spy.assert_not_called() assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 0 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 1 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==2284 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_ms3000_ind assert m.ifc.tx_fifo.get()==msg_inverter_ack assert m.db.get_db_value(Register.INVERTER_STATUS) == 0 assert m.db.get_db_value(Register.TS_GRID) == 1739866976 m.db.db['grid'] = {'Output_Power': 100} m.close() def test_msg_inv_ind5(config_tsun_inv1, msg_inverter_ms3000_ind, msg_inverter_ack): '''Check that unexpected sonar_lists will log a warning''' _ = config_tsun_inv1 tracer.setLevel(logging.DEBUG) with patch.object(logging, 'warning') as spy: m = MemoryStream(msg_inverter_ms3000_ind, (0,)) m.sensor_list = 0x01900002 # change the expected sensor_list m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 0 m.read() # read complete msg, and dispatch msg spy.assert_called() assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 0 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 1 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==2284 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_ms3000_ind assert m.ifc.tx_fifo.get()==msg_inverter_ack assert m.db.get_db_value(Register.INVERTER_STATUS) == 0 assert m.db.get_db_value(Register.TS_GRID) == 1739866976 m.db.db['grid'] = {'Output_Power': 100} m.close() def test_msg_inv_ack(config_tsun_inv1, msg_inverter_ack): _ = config_tsun_inv1 tracer.setLevel(logging.ERROR) m = MemoryStream(msg_inverter_ack, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==153 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==1 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() def test_msg_inv_invalid(config_tsun_inv1, msg_inverter_invalid): _ = config_tsun_inv1 m = MemoryStream(msg_inverter_invalid, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==146 assert m.msg_id==4 assert m.header_len==23 assert m.data_len==1 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_inverter_invalid m.ts_offset = 256 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_inverter_invalid assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 m.close() def test_build_modell_3000(config_tsun_allow_all, msg_inverter_ms3000_ind): _ = config_tsun_allow_all m = MemoryStream(msg_inverter_ms3000_ind, (0,)) assert 0 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert None == m.db.get_db_value(Register.RATED_POWER, None) assert None == m.db.get_db_value(Register.INVERTER_TEMP, None) m.read() # read complete msg, and dispatch msg assert 3000 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert 0 == m.db.get_db_value(Register.RATED_POWER, 0) assert 'TSOL-MS3000' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0) m.close() def test_msg_ota_req(config_tsun_inv1, msg_ota_req): _ = config_tsun_inv1 m = MemoryStream(msg_ota_req, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['OTA_Start_Msg'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==112 assert m.msg_id==19 assert m.header_len==23 assert m.data_len==259 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_ota_req m.ts_offset = 4096 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_ota_req assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['OTA_Start_Msg'] == 1 m.close() def test_msg_ota_ack(config_tsun_inv1, msg_ota_ack): _ = config_tsun_inv1 tracer.setLevel(logging.ERROR) m = MemoryStream(msg_ota_ack, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['OTA_Start_Msg'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==19 assert m.header_len==23 assert m.data_len==1 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_ota_ack m.ts_offset = 256 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.get()==msg_ota_ack assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['OTA_Start_Msg'] == 0 m.close() def test_msg_ota_invalid(config_tsun_inv1, msg_ota_invalid): _ = config_tsun_inv1 m = MemoryStream(msg_ota_invalid, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['OTA_Start_Msg'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==153 assert m.msg_id==19 assert m.header_len==23 assert m.data_len==1 m.ts_offset = 0 m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.fwd_fifo.peek()==msg_ota_invalid m.ts_offset = 4096 assert m.ifc.fwd_fifo.get()==msg_ota_invalid m._update_header(m.ifc.fwd_fifo.peek()) assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 assert m.db.stat['proxy']['OTA_Start_Msg'] == 0 m.close() def test_msg_unknown(config_tsun_inv1, msg_unknown): _ = config_tsun_inv1 m = MemoryStream(msg_unknown, (0,), False) m.db.stat['proxy']['Unknown_Msg'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==23 assert m.header_len==23 assert m.data_len==4 assert m.ifc.fwd_fifo.get()==msg_unknown assert m.ifc.tx_fifo.get()==b'' assert 1 == m.db.stat['proxy']['Unknown_Msg'] m.close() def test_ctrl_byte(): c = Control(0x70) assert not c.is_ind() assert not c.is_resp() assert c.is_req() c = Control(0x91) assert not c.is_req() assert c.is_ind() assert not c.is_resp() c = Control(0x99) assert not c.is_req() assert not c.is_ind() assert c.is_resp() def test_msg_iterator(): m1 = Talent(None, ('test1.local', 1234), ifc=AsyncIfcImpl(), server_side=True) m2 = Talent(None, ('test2.local', 1234), ifc=AsyncIfcImpl(), server_side=True) m3 = Talent(None, ('test3.local', 1234), ifc=AsyncIfcImpl(), server_side=True) m3.close() del m3 test1 = 0 test2 = 0 for key in Talent: if key == m1: test1+=1 elif key == m2: test2+=1 elif type(key) != Talent: continue else: assert False assert test1 == 1 assert test2 == 1 def test_timestamp_cnv(): '''test converting inverter timestamps into utc''' 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 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 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 isclose(utc, m._utcfromts(ts)) m.close() def test_proxy_counter(): Infos.stat['proxy']['Modbus_Command'] = 1 m = MemoryStream(b'') m.id_str = b"R170000000000001" c = m.createClientStream(b'') assert m.new_data == {} m.db.stat['proxy']['Unknown_Msg'] = 0 c.db.stat['proxy']['Unknown_Msg'] = 0 Infos.new_stat_data['proxy'] = False m.inc_counter('Unknown_Msg') m.close() m = MemoryStream(b'') assert m.new_data == {} assert Infos.new_stat_data == {'proxy': True} assert m.db.new_stat_data == {'proxy': True} assert c.db.new_stat_data == {'proxy': True} assert 1 == m.db.stat['proxy']['Unknown_Msg'] assert 1 == c.db.stat['proxy']['Unknown_Msg'] Infos.new_stat_data['proxy'] = False c.inc_counter('Unknown_Msg') assert m.new_data == {} assert Infos.new_stat_data == {'proxy': True} assert m.db.new_stat_data == {'proxy': True} assert c.db.new_stat_data == {'proxy': True} assert 2 == m.db.stat['proxy']['Unknown_Msg'] assert 2 == c.db.stat['proxy']['Unknown_Msg'] Infos.new_stat_data['proxy'] = False c.inc_counter('Modbus_Command') assert m.new_data == {} assert Infos.new_stat_data == {'proxy': True} assert m.db.new_stat_data == {'proxy': True} assert c.db.new_stat_data == {'proxy': True} assert 2 == m.db.stat['proxy']['Modbus_Command'] assert 2 == c.db.stat['proxy']['Modbus_Command'] Infos.new_stat_data['proxy'] = False m.dec_counter('Unknown_Msg') assert m.new_data == {} assert Infos.new_stat_data == {'proxy': True} assert 1 == m.db.stat['proxy']['Unknown_Msg'] m.close() def test_msg_modbus_req(config_tsun_inv1, msg_modbus_cmd): _ = config_tsun_inv1 m = MemoryStream(b'') m.id_str = b"R170000000000001" m.state = State.up c = m.createClientStream(msg_modbus_cmd) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 0 m.db.stat['proxy']['Invalid_Msg_Format'] = 0 c.read() # read complete msg, and dispatch msg assert not c.header_valid # must be invalid, since msg was handled and buffer flushed assert c.msg_count == 1 assert c.id_str == b"R170000000000001" assert c.unique_id == 'R170000000000001' assert int(c.ctrl)==112 assert c.msg_id==119 assert c.header_len==23 assert c.data_len==13 assert c.ifc.fwd_fifo.get()==b'' assert c.ifc.tx_fifo.get()==b'' assert m.id_str == b"R170000000000001" assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.sent_pdu == msg_modbus_cmd assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 1 assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0 m.close() def test_msg_modbus_req2(config_tsun_inv1, msg_modbus_cmd): _ = config_tsun_inv1 m = MemoryStream(b'') m.id_str = b"R170000000000001" c = m.createClientStream(msg_modbus_cmd) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 0 m.db.stat['proxy']['Invalid_Msg_Format'] = 0 c.read() # read complete msg, and dispatch msg assert not c.header_valid # must be invalid, since msg was handled and buffer flushed assert c.msg_count == 1 assert c.id_str == b"R170000000000001" assert c.unique_id == 'R170000000000001' assert int(c.ctrl)==112 assert c.msg_id==119 assert c.header_len==23 assert c.data_len==13 assert c.ifc.fwd_fifo.get()==b'' assert c.ifc.tx_fifo.get()==b'' assert m.id_str == b"R170000000000001" assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.sent_pdu == b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 1 assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0 m.close() def test_msg_modbus_req3(config_tsun_inv1, msg_modbus_cmd_crc_err): _ = config_tsun_inv1 m = MemoryStream(b'') m.id_str = b"R170000000000001" c = m.createClientStream(msg_modbus_cmd_crc_err) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 0 m.db.stat['proxy']['Invalid_Msg_Format'] = 0 c.read() # read complete msg, and dispatch msg assert not c.header_valid # must be invalid, since msg was handled and buffer flushed assert c.msg_count == 1 assert c.id_str == b"R170000000000001" assert c.unique_id == 'R170000000000001' assert int(c.ctrl)==112 assert c.msg_id==119 assert c.header_len==23 assert c.data_len==13 assert c.ifc.fwd_fifo.get()==b'' assert c.ifc.tx_fifo.get()==b'' assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.sent_pdu ==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 0 assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1 m.close() def test_msg_modbus_rsp1(config_tsun_inv1, msg_modbus_rsp): '''Modbus response without a valid Modbus request must be dropped''' _ = config_tsun_inv1 m = MemoryStream(msg_modbus_rsp) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==119 assert m.header_len==23 assert m.data_len==13 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 0 m.close() def test_msg_modbus_cloud_rsp(config_tsun_inv1, msg_modbus_rsp): '''Modbus response from TSUN without a valid Modbus request must be dropped''' _ = config_tsun_inv1 m = MemoryStream(msg_modbus_rsp, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Unknown_Msg'] = 0 m.db.stat['proxy']['Modbus_Command'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==119 assert m.header_len==23 assert m.data_len==13 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Msg'] == 1 assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 0 m.close() def test_msg_modbus_rsp2(config_tsun_inv1, msg_modbus_rsp20): '''Modbus response with a valid Modbus request must be forwarded''' _ = config_tsun_inv1 m = MemoryStream(msg_modbus_rsp20) m.append_msg(msg_modbus_rsp20) m.mb.rsp_handler = m.msg_forward m.mb.last_addr = 1 m.mb.last_fcode = 3 m.mb.last_len = 20 m.mb.last_reg = 0x3008 m.mb.req_pend = True m.mb.err = 0 assert m.db.db == {} m.new_data['inverter'] = False 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.mb.err == 5 assert m.msg_count == 2 assert m.ifc.fwd_fifo.get()==msg_modbus_rsp20 assert m.ifc.tx_fifo.get()==b'' assert m.db.db == {'collector': {'Serial_Number': 'R170000000000001'}, 'inverter': {'Version': 'V5.1.09', 'Rated_Power': 300}, 'grid': {'Timestamp': m._utc(), 'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'Timestamp': m._utc(), 'pv1': {'Voltage': 0.8, 'Current': 0.0, 'Power': 0.0}, 'pv2': {'Voltage': 34.5, 'Current': 2.89, 'Power': 99.8}, 'pv3': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}, 'pv4': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}}} assert m.db.get_db_value(Register.VERSION) == 'V5.1.09' assert m.db.get_db_value(Register.TS_GRID) == m._utc() assert m.new_data['inverter'] == True m.close() def test_msg_modbus_rsp3(config_tsun_inv1, msg_modbus_rsp21): '''Modbus response with a valid Modbus request must be forwarded''' _ = config_tsun_inv1 m = MemoryStream(msg_modbus_rsp21) m.append_msg(msg_modbus_rsp21) m.mb.rsp_handler = m.msg_forward m.mb.last_addr = 1 m.mb.last_fcode = 3 m.mb.last_len = 20 m.mb.last_reg = 0x3008 m.mb.req_pend = True m.mb.err = 0 assert m.db.db == {} m.new_data['inverter'] = False 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.mb.err == 5 assert m.msg_count == 2 assert m.ifc.fwd_fifo.get()==msg_modbus_rsp21 assert m.ifc.tx_fifo.get()==b'' assert m.db.db == {'collector': {'Serial_Number': 'R170000000000001'}, 'inverter': {'Version': 'V5.1.0E', 'Rated_Power': 300}, 'grid': {'Timestamp': m._utc(), 'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'Timestamp': m._utc(), 'pv1': {'Voltage': 0.8, 'Current': 0.0, 'Power': 0.0}, 'pv2': {'Voltage': 34.5, 'Current': 2.89, 'Power': 99.8}, 'pv3': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}, 'pv4': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}}} assert m.db.get_db_value(Register.VERSION) == 'V5.1.0E' assert m.db.get_db_value(Register.TS_GRID) == m._utc() assert m.new_data['inverter'] == True m.close() def test_msg_modbus_rsp4(config_tsun_inv1, msg_modbus_rsp21): '''Modbus response with a valid Modbus but no new values request must be forwarded''' _ = config_tsun_inv1 m = MemoryStream(msg_modbus_rsp21) m.mb.rsp_handler = m.msg_forward m.mb.last_addr = 1 m.mb.last_fcode = 3 m.mb.last_len = 20 m.mb.last_reg = 0x3008 m.mb.req_pend = True m.mb.err = 0 db_values = {'collector': {'Serial_Number': 'R170000000000001'}, 'inverter': {'Version': 'V5.1.0E', 'Rated_Power': 300}, 'grid': {'Timestamp': m._utc(), 'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'Timestamp': m._utc(), 'pv1': {'Voltage': 0.8, 'Current': 0.0, 'Power': 0.0}, 'pv2': {'Voltage': 34.5, 'Current': 2.89, 'Power': 99.8}, 'pv3': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}, 'pv4': {'Voltage': 0.0, 'Current': 0.0, 'Power': 0.0}}} m.db.db = db_values m.new_data['inverter'] = False 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.mb.err == 0 assert m.msg_count == 1 assert m.ifc.fwd_fifo.get()==msg_modbus_rsp21 assert m.modbus_elms == 19 assert m.ifc.tx_fifo.get()==b'' assert m.db.db == db_values assert m.db.get_db_value(Register.VERSION) == 'V5.1.0E' assert m.db.get_db_value(Register.TS_GRID) == m._utc() assert m.new_data['inverter'] == False m.close() def test_msg_modbus_rsp_new(config_tsun_inv1, msg_modbus_rsp20_new): '''Modbus response in new format with a valid Modbus request must be forwarded''' _ = config_tsun_inv1 m = MemoryStream(msg_modbus_rsp20_new) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==135 assert m.header_len==23 assert m.data_len==107 assert m.ifc.fwd_fifo.get()==b'' assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 0 m.close() def test_msg_modbus_invalid(config_tsun_inv1, msg_modbus_inv): _ = config_tsun_inv1 m = MemoryStream(msg_modbus_inv, (0,), False) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==153 assert m.msg_id==119 assert m.header_len==23 assert m.data_len==13 assert m.ifc.fwd_fifo.get()==msg_modbus_inv assert m.ifc.tx_fifo.get()==b'' assert m.db.stat['proxy']['Unknown_Ctrl'] == 1 assert m.db.stat['proxy']['Modbus_Command'] == 0 m.close() def test_msg_modbus_fragment(config_tsun_inv1, msg_modbus_rsp20): _ = config_tsun_inv1 # receive more bytes than expected (7 bytes from the next msg) m = MemoryStream(msg_modbus_rsp20+b'\x00\x00\x00\x45\x10\x52\x31', (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Modbus_Command'] = 0 m.mb.rsp_handler = m.msg_forward m.mb.last_addr = 1 m.mb.last_fcode = 3 m.mb.last_len = 20 m.mb.last_reg = 0x3008 m.mb.req_pend = True m.mb.err = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl) == 0x91 assert m.msg_id == 119 assert m.header_len == 23 assert m.data_len == 50 assert m.ifc.fwd_fifo.get()==msg_modbus_rsp20 assert m.ifc.tx_fifo.get() == b'' assert m.mb.err == 0 assert m.modbus_elms == 20-1 # register 0x300d is unknown, so one value can't be mapped assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Modbus_Command'] == 0 m.close() @pytest.mark.asyncio async def test_msg_build_modbus_req(config_tsun_inv1, msg_modbus_cmd): _ = config_tsun_inv1 m = MemoryStream(b'', (0,), True) m.id_str = b"R170000000000001" await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG) assert 0 == m.send_msg_ofs assert m.ifc.fwd_fifo.get() == b'' assert m.ifc.tx_fifo.get() == b'' assert m.sent_pdu == b'' m.state = State.up await m.send_modbus_cmd(Modbus.WRITE_SINGLE_REG, 0x2008, 0, logging.DEBUG) assert 0 == m.send_msg_ofs assert m.ifc.fwd_fifo.get() == b'' assert m.ifc.tx_fifo.get() == b'' assert m.sent_pdu == msg_modbus_cmd m.close() def test_modbus_no_polling(config_no_modbus_poll, msg_get_time): _ = config_no_modbus_poll m = MemoryStream(msg_get_time, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.modbus_polling = False 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==34 assert m.header_len==23 assert m.ts_offset==0 assert m.data_len==0 assert m.ifc.fwd_fifo.get()==msg_get_time assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.close() @pytest.mark.asyncio async def test_modbus_polling(config_tsun_inv1, msg_inverter_ind): _ = config_tsun_inv1 assert asyncio.get_running_loop() m = MemoryStream(msg_inverter_ind, (0,)) assert asyncio.get_running_loop() == m.mb_timer.loop m.db.stat['proxy']['Unknown_Ctrl'] = 0 assert m.mb_timer.tim == None 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert int(m.ctrl)==145 assert m.msg_id==4 assert m.header_len==23 assert m.ts_offset==0 assert m.data_len==120 assert m.ifc.fwd_fifo.get()==msg_inverter_ind assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x14\x10R170000000000001\x99\x04\x01' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.ifc.tx_clear() # clear send buffer for next test assert isclose(m.mb_timeout, 0.5) assert next(m.mb_timer.exp_count) == 0 await asyncio.sleep(0.5) assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x030\x00\x000J\xde' assert m.ifc.tx_fifo.get()==b'' await asyncio.sleep(0.5) assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x030\x00\x000J\xde' assert m.ifc.tx_fifo.get()==b'' await asyncio.sleep(0.5) assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x03\x20\x00\x00`N"' assert m.ifc.tx_fifo.get()==b'' assert next(m.mb_timer.exp_count) == 4 m.close() @pytest.mark.asyncio async def test_modbus_scaning(config_tsun_inv1, msg_inverter_ind, msg_modbus_rsp21): _ = config_tsun_inv1 assert asyncio.get_running_loop() m = MemoryStream(msg_inverter_ind, (0x8f,0)) m.append_msg(msg_modbus_rsp21) m.mb_scan = True m.mb_start_reg = 0x4560 m.mb_bytes = 0x14 assert asyncio.get_running_loop() == m.mb_timer.loop m.db.stat['proxy']['Unknown_Ctrl'] = 0 assert m.mb_timer.tim == None 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert m.msg_recvd[0]['ctrl']==145 assert m.msg_recvd[0]['msg_id']==4 assert m.msg_recvd[0]['header_len']==23 assert m.msg_recvd[0]['data_len']==120 assert m.ifc.fwd_fifo.get()==msg_inverter_ind assert m.ifc.tx_fifo.get()==b'\x00\x00\x00\x14\x10R170000000000001\x99\x04\x01' assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 m.ifc.tx_clear() # clear send buffer for next test assert isclose(m.mb_timeout, 0.5) assert next(m.mb_timer.exp_count) == 0 await asyncio.sleep(0.5) assert m.sent_pdu==b'\x00\x00\x00 \x10R170000000000001pw\x00\x01\xa3(\x08\x01\x03\x45\x60\x00\x14\x50\xd7' assert m.ifc.tx_fifo.get()==b'' 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 == 2 assert m.msg_recvd[1]['ctrl']==145 assert m.msg_recvd[1]['msg_id']==119 assert m.msg_recvd[1]['header_len']==23 assert m.msg_recvd[1]['data_len']==50 assert m.mb.last_addr == 1 assert m.mb.last_fcode == 3 assert m.mb.last_reg == 0x4560 assert m.mb.last_len == 20 assert m.mb.err == 0 assert next(m.mb_timer.exp_count) == 2 m.close() def test_broken_recv_buf(config_tsun_allow_all, broken_recv_buf): _ = config_tsun_allow_all m = MemoryStream(broken_recv_buf, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert m.msg_recvd[0]['ctrl']==145 assert m.msg_recvd[0]['msg_id']==4 assert m.msg_recvd[0]['header_len']==23 assert m.msg_recvd[0]['data_len']==1263 assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 1 m.close() def test_multiiple_recv_buf(config_tsun_allow_all, multiple_recv_buf): _ = config_tsun_allow_all m = MemoryStream(multiple_recv_buf, (0,)) m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Msg_Format'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 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.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert m.msg_recvd[0]['ctrl']==145 assert m.msg_recvd[0]['msg_id']==4 assert m.msg_recvd[0]['header_len']==23 assert m.msg_recvd[0]['data_len']==1263 assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1 assert m.db.stat['proxy']['Invalid_Data_Type'] == 1 m.close() def test_timeout(config_tsun_inv1): _ = config_tsun_inv1 m = MemoryStream(b'') assert m.state == State.init assert Talent.MAX_START_TIME == m._timeout() m.state = State.up m.modbus_polling = True assert Talent.MAX_INV_IDLE_TIME == m._timeout() m.modbus_polling = False assert Talent.MAX_DEF_IDLE_TIME == m._timeout() m.close() def test_msg_inv_replay(config_tsun_inv1, msg_inverter_ind_0w, msg_inverter_ind_new2): '''replay must be ignores, since HA only supports realtime values''' _ = config_tsun_inv1 m = MemoryStream(msg_inverter_ind_0w, (0,)) # realtime msg with 0.5W Output Power m.append_msg(msg_inverter_ind_new2) # replay msg with 506.6W Output Power m.db.db['grid'] = {'Output_Power': 100} m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Invalid_Data_Type'] = 0 m.read() # read complete msg, and dispatch msg assert m.db.stat['proxy']['Unknown_Ctrl'] == 0 assert m.db.stat['proxy']['Invalid_Data_Type'] == 0 assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert m.msg_count == 2 assert m.msg_recvd[0]['ctrl']==145 assert m.msg_recvd[0]['msg_id']==4 assert m.msg_recvd[0]['header_len']==23 assert m.msg_recvd[0]['data_len']==1263 assert m.msg_recvd[1]['ctrl']==145 assert m.msg_recvd[1]['msg_id']==4 assert m.msg_recvd[1]['header_len']==23 assert m.msg_recvd[1]['data_len']==1249 assert m.id_str == b"R170000000000001" assert m.unique_id == 'R170000000000001' assert m.db.get_db_value(Register.INVERTER_STATUS) == 1 assert isclose(m.db.db['grid']['Output_Power'], 0.5) # must be 0.5W not 100W nor 506.6W m.close() assert m.db.get_db_value(Register.INVERTER_STATUS) == 0