Dev 0.9 (#115)
* make timestamp handling stateless * adapt tests for stateless timestamp handling * initial version * add more type annotations * add more type annotations * fix Generator annotation for ha_proxy_confs * fix names of issue branches * add more type annotations * don't use depricated varn anymore * don't mark all test as async * fix imports * fix solarman unit tests - fake Mqtt class * print image build time during proxy start * update changelog * fix pytest collect warning * cleanup msg_get_time handler * addapt unit test * label debug images with debug * dump droped packages * fix warnings * add systemtest with invalid start byte * update changelog * update changelog * add exposed ports and healthcheck * add wget for healthcheck * add aiohttp * use config validation for healthcheck * add http server for healthcheck * calculate msg prossesing time * add healthy check methods * fix typo * log ConfigErr with DEBUG level * Update async_stream.py - check if processing time is < 5 sec * add a close handler to release internal resources * call modbus close hanlder on a close call * add exception handling for forward handler * update changelog * isolate Modbus fix * cleanup * update changelog * add heaithy handler * log unrelease references * add healtcheck * complete exposed port list * add wget for healtcheck * add aiohttp * use Enum class for State * calc processing time for healthcheck * add HTTP server for healthcheck * cleanup * Update CHANGELOG.md * updat changelog * add docstrings to state enum * set new state State.received * add healthy method * log healthcheck infos with DEBUG level * update changelog * S allius/issue100 (#101) * detect dead connections - disconnect connection on Msg receive timeout - improve connection trace (add connection id) * update changelog * fix merge conflict * fix unittests * S allius/issue108 (#109) * add more data types * adapt unittests * improve test coverage * fix linter warning * update changelog * S allius/issue102 (#110) * hotfix: don't send two MODBUS commands together * fix unit tests * remove read loop * optional sleep between msg read and sending rsp * wait after read 0.5s before sending a response * add pending state * fix state definitions * determine the connection timeout by the conn state * avoid sending MODBUS cmds in the inverter's reporting phase * update changelog * S allius/issue111 (#112) Synchronize regular MODBUS commands with the status of the inverter to prevent the inverter from crashing due to unexpected packets. * inital checkin * remove crontab entry for regular MODBUS cmds * add timer for regular MODBUS polling * fix Stop method call for already stopped timer * optimize MB_START_TIMEOUT value * cleanup * update changelog * fix buildx warnings * fix timer cleanup * fix Config.class_init() - return error string or None - release Schema structure after building thr config * add quit flag to docker push * fix timout calculation * rename python to debugpy * add asyncio log * cleanup shutdown - stop webserver on shutdown - enable asyncio debug mode for debug versions * update changelog * update changelog * fix exception in MODBUS timeout callback * update changelog
This commit is contained in:
@@ -4,6 +4,7 @@ from app.src.gen3.talent import Talent, Control
|
||||
from app.src.config import Config
|
||||
from app.src.infos import Infos, Register
|
||||
from app.src.modbus import Modbus
|
||||
from app.src.messages import State
|
||||
|
||||
|
||||
pytest_plugins = ('pytest_asyncio',)
|
||||
@@ -60,7 +61,8 @@ class MemoryStream(Talent):
|
||||
return copied_bytes
|
||||
|
||||
def _timestamp(self):
|
||||
return 1700260990000
|
||||
# return 1700260990000
|
||||
return 1691246944000
|
||||
|
||||
def createClientStream(self, msg, chunks = (0,)):
|
||||
c = MemoryStream(msg, chunks, False)
|
||||
@@ -113,6 +115,10 @@ def MsgGetTime(): # Get Time Request message
|
||||
def MsgTimeResp(): # Get Time Resonse message
|
||||
return b'\x00\x00\x00\x1b\x10R170000000000001\x91\x22\x00\x00\x01\x89\xc6\x63\x4d\x80'
|
||||
|
||||
@pytest.fixture
|
||||
def MsgTimeRespInv(): # Get Time Resonse message
|
||||
return b'\x00\x00\x00\x17\x10R170000000000001\x91\x22\x00\x00\x01\x89'
|
||||
|
||||
@pytest.fixture
|
||||
def MsgTimeInvalid(): # Get Time Request message
|
||||
return b'\x00\x00\x00\x13\x10R170000000000001\x94\x22'
|
||||
@@ -129,6 +135,18 @@ def MsgControllerInd(): # Data indication from the controller
|
||||
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 MsgControllerIndTsOffs(): # 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 MsgControllerAck(): # Get Time Request message
|
||||
return b'\x00\x00\x00\x14\x10R170000000000001\x99\x71\x01'
|
||||
@@ -145,6 +163,92 @@ def MsgInverterInd(): # Data indication from the controller
|
||||
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 MsgInverterIndTsOffs(): # 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 MsgInverterIndNew(): # 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 MsgInverterAck(): # Get Time Request message
|
||||
return b'\x00\x00\x00\x14\x10R170000000000001\x99\x04\x01'
|
||||
@@ -331,8 +435,7 @@ def test_read_message_in_chunks2(MsgContactInfo):
|
||||
assert int(m.ctrl)==145
|
||||
assert m.msg_id==0
|
||||
assert m.msg_count == 1
|
||||
while m.read(): # read rest of message
|
||||
pass
|
||||
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()
|
||||
@@ -471,9 +574,10 @@ def test_msg_get_time(ConfigTsunInv1, MsgGetTime):
|
||||
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._forward_buffer==MsgGetTime
|
||||
assert m._send_buffer==b''
|
||||
assert m._send_buffer==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00'
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -489,9 +593,10 @@ def test_msg_get_time_autark(ConfigNoTsunInv1, MsgGetTime):
|
||||
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._forward_buffer==b''
|
||||
assert m._send_buffer==b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x8b\xdfs\xcc0'
|
||||
assert m._send_buffer==bytearray(b'\x00\x00\x00\x1b\x10R170000000000001\x91"\x00\x00\x01\x89\xc6,_\x00')
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
@@ -507,8 +612,9 @@ def test_msg_time_resp(ConfigTsunInv1, MsgTimeResp):
|
||||
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._forward_buffer==MsgTimeResp
|
||||
assert m._forward_buffer==b''
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
@@ -525,12 +631,32 @@ def test_msg_time_resp_autark(ConfigNoTsunInv1, MsgTimeResp):
|
||||
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._forward_buffer==b''
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_time_inv_resp(ConfigTsunInv1, MsgTimeRespInv):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgTimeRespInv, (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._forward_buffer==MsgTimeRespInv
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_time_invalid(ConfigTsunInv1, MsgTimeInvalid):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgTimeInvalid, (0,), False)
|
||||
@@ -543,6 +669,7 @@ def test_msg_time_invalid(ConfigTsunInv1, MsgTimeInvalid):
|
||||
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._forward_buffer==MsgTimeInvalid
|
||||
assert m._send_buffer==b''
|
||||
@@ -560,6 +687,7 @@ def test_msg_time_invalid_autark(ConfigNoTsunInv1, MsgTimeInvalid):
|
||||
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._forward_buffer==b''
|
||||
@@ -567,7 +695,7 @@ def test_msg_time_invalid_autark(ConfigNoTsunInv1, MsgTimeInvalid):
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
def test_msg_cntrl_ind(ConfigTsunInv1, MsgControllerInd, MsgControllerAck):
|
||||
def test_msg_cntrl_ind(ConfigTsunInv1, MsgControllerInd, MsgControllerIndTsOffs, MsgControllerAck):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgControllerInd, (0,))
|
||||
m.db.stat['proxy']['Unknown_Ctrl'] = 0
|
||||
@@ -580,7 +708,12 @@ def test_msg_cntrl_ind(ConfigTsunInv1, MsgControllerInd, MsgControllerAck):
|
||||
assert m.msg_id==113
|
||||
assert m.header_len==23
|
||||
assert m.data_len==284
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgControllerInd
|
||||
m.ts_offset = -4096
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgControllerIndTsOffs
|
||||
assert m._send_buffer==MsgControllerAck
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
@@ -616,12 +749,17 @@ def test_msg_cntrl_invalid(ConfigTsunInv1, MsgControllerInvalid):
|
||||
assert m.msg_id==113
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgControllerInvalid
|
||||
m.ts_offset = -4096
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgControllerInvalid
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_ind(ConfigTsunInv1, MsgInverterInd, MsgInverterAck):
|
||||
def test_msg_inv_ind(ConfigTsunInv1, MsgInverterInd, MsgInverterIndTsOffs, MsgInverterAck):
|
||||
ConfigTsunInv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(MsgInverterInd, (0,))
|
||||
@@ -635,11 +773,62 @@ def test_msg_inv_ind(ConfigTsunInv1, MsgInverterInd, MsgInverterAck):
|
||||
assert m.msg_id==4
|
||||
assert m.header_len==23
|
||||
assert m.data_len==120
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgInverterInd
|
||||
m.ts_offset = +256
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgInverterIndTsOffs
|
||||
assert m._send_buffer==MsgInverterAck
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
m.close()
|
||||
|
||||
|
||||
def test_msg_inv_ind2(ConfigTsunInv1, MsgInverterIndNew, MsgInverterIndTsOffs, MsgInverterAck):
|
||||
ConfigTsunInv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(MsgInverterIndNew, (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._forward_buffer)
|
||||
assert m._forward_buffer==MsgInverterIndNew
|
||||
assert m._send_buffer==MsgInverterAck
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_ind2(ConfigTsunInv1, MsgInverterIndNew, MsgInverterIndTsOffs, MsgInverterAck):
|
||||
ConfigTsunInv1
|
||||
tracer.setLevel(logging.DEBUG)
|
||||
m = MemoryStream(MsgInverterIndNew, (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._forward_buffer)
|
||||
assert m._forward_buffer==MsgInverterIndNew
|
||||
assert m._send_buffer==MsgInverterAck
|
||||
m.close()
|
||||
|
||||
def test_msg_inv_ack(ConfigTsunInv1, MsgInverterAck):
|
||||
ConfigTsunInv1
|
||||
tracer.setLevel(logging.ERROR)
|
||||
@@ -673,6 +862,11 @@ def test_msg_inv_invalid(ConfigTsunInv1, MsgInverterInvalid):
|
||||
assert m.msg_id==4
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgInverterInvalid
|
||||
m.ts_offset = 256
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgInverterInvalid
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
@@ -692,6 +886,11 @@ def test_msg_ota_req(ConfigTsunInv1, MsgOtaReq):
|
||||
assert m.msg_id==19
|
||||
assert m.header_len==23
|
||||
assert m.data_len==259
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgOtaReq
|
||||
m.ts_offset = 4096
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgOtaReq
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
@@ -714,6 +913,11 @@ def test_msg_ota_ack(ConfigTsunInv1, MsgOtaAck):
|
||||
assert m.msg_id==19
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgOtaAck
|
||||
m.ts_offset = 256
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgOtaAck
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 0
|
||||
@@ -734,7 +938,12 @@ def test_msg_ota_invalid(ConfigTsunInv1, MsgOtaInvalid):
|
||||
assert m.msg_id==19
|
||||
assert m.header_len==23
|
||||
assert m.data_len==1
|
||||
m.ts_offset = 0
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._forward_buffer==MsgOtaInvalid
|
||||
m.ts_offset = 4096
|
||||
assert m._forward_buffer==MsgOtaInvalid
|
||||
m._update_header(m._forward_buffer)
|
||||
assert m._send_buffer==b''
|
||||
assert m.db.stat['proxy']['Unknown_Ctrl'] == 1
|
||||
assert m.db.stat['proxy']['OTA_Start_Msg'] == 0
|
||||
@@ -847,7 +1056,7 @@ def test_msg_modbus_req(ConfigTsunInv1, MsgModbusCmd):
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(b'')
|
||||
m.id_str = b"R170000000000001"
|
||||
m.state = m.STATE_UP
|
||||
m.state = State.up
|
||||
|
||||
c = m.createClientStream(MsgModbusCmd)
|
||||
|
||||
@@ -953,6 +1162,29 @@ def test_msg_modbus_rsp1(ConfigTsunInv1, MsgModbusRsp):
|
||||
assert m.db.stat['proxy']['Modbus_Command'] == 0
|
||||
m.close()
|
||||
|
||||
def test_msg_modbus_cloud_rsp(ConfigTsunInv1, MsgModbusRsp):
|
||||
'''Modbus response from TSUN without a valid Modbus request must be dropped'''
|
||||
ConfigTsunInv1
|
||||
m = MemoryStream(MsgModbusRsp, (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._forward_buffer==b''
|
||||
assert m._send_buffer==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(ConfigTsunInv1, MsgModbusResp20):
|
||||
'''Modbus response with a valid Modbus request must be forwarded'''
|
||||
ConfigTsunInv1
|
||||
@@ -1097,7 +1329,7 @@ async def test_msg_build_modbus_req(ConfigTsunInv1, MsgModbusCmd):
|
||||
assert m._send_buffer == b''
|
||||
assert m.writer.sent_pdu == b''
|
||||
|
||||
m.state = m.STATE_UP
|
||||
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._forward_buffer == b''
|
||||
@@ -1127,21 +1359,21 @@ def test_zombie_conn(ConfigTsunInv1, MsgInverterInd):
|
||||
m3 = MemoryStream(MsgInverterInd, (0,))
|
||||
assert MemoryStream._RefNo == 3 + start_val
|
||||
assert m3.RefNo == 3 + start_val
|
||||
assert m1.state == m1.STATE_INIT
|
||||
assert m2.state == m2.STATE_INIT
|
||||
assert m3.state == m3.STATE_INIT
|
||||
assert m1.state == m1.State.init
|
||||
assert m2.state == m2.State.init
|
||||
assert m3.state == m3.State.init
|
||||
m1.read() # read complete msg, and set unique_id
|
||||
assert m1.state == m1.STATE_UP
|
||||
assert m2.state == m2.STATE_INIT
|
||||
assert m3.state == m3.STATE_INIT
|
||||
assert m1.state == m1.State.up
|
||||
assert m2.state == m2.State.init
|
||||
assert m3.state == m3.State.init
|
||||
m2.read() # read complete msg, and set unique_id
|
||||
assert m1.state == m1.STATE_CLOSED
|
||||
assert m2.state == m2.STATE_UP
|
||||
assert m3.state == m3.STATE_INIT
|
||||
assert m1.state == m1.State.closed
|
||||
assert m2.state == m2.State.up
|
||||
assert m3.state == m3.State.init
|
||||
m3.read() # read complete msg, and set unique_id
|
||||
assert m1.state == m1.STATE_CLOSED
|
||||
assert m2.state == m2.STATE_CLOSED
|
||||
assert m3.state == m3.STATE_UP
|
||||
assert m1.state == m1.State.closed
|
||||
assert m2.state == m2.State.closed
|
||||
assert m3.state == m3.State.up
|
||||
m1.close()
|
||||
m2.close()
|
||||
m3.close()
|
||||
|
||||
Reference in New Issue
Block a user