first self-sufficient island support

- add Sequence class to handle the sequence of packets
- send response for received packets directly
- don't forward responses anymore
- addapt tests to new behavior
This commit is contained in:
Stefan Allius
2024-04-12 18:57:48 +02:00
parent 22f68ab330
commit 1d3a44c9f0
2 changed files with 151 additions and 83 deletions

View File

@@ -1,4 +1,7 @@
import pytest, json
import pytest
import struct
import time
from datetime import datetime
from app.src.gen3plus.solarman_v5 import SolarmanV5
from app.src.config import Config
from app.src.infos import Infos, Register
@@ -6,6 +9,9 @@ from app.src.infos import Infos, Register
# initialize the proxy statistics
Infos.static_init()
timestamp = int(time.time()) # 1712861197
heartbeat = 60
class MemoryStream(SolarmanV5):
def __init__(self, msg, chunks = (0,), server_side: bool = True):
super().__init__(server_side)
@@ -19,6 +25,12 @@ class MemoryStream(SolarmanV5):
self.db.stat['proxy']['Invalid_Msg_Format'] = 0
self.db.stat['proxy']['AT_Command'] = 0
def _timestamp(self):
return timestamp
def _heartbeat(self) -> int:
return heartbeat
def append_msg(self, msg):
self.__msg += msg
@@ -42,9 +54,6 @@ class MemoryStream(SolarmanV5):
pass
return copied_bytes
def _timestamp(self):
return 1700260990000
def _SolarmanV5__flush_recv_msg(self) -> None:
super()._SolarmanV5__flush_recv_msg()
self.msg_count += 1
@@ -60,6 +69,16 @@ def get_inv_no() -> bytes:
def get_invalid_sn():
return b'R170000000000002'
def total():
ts = timestamp
# convert int to little-endian bytes
return struct.pack('<L',ts)
def hb():
hb = heartbeat
# convert int to little-endian bytes
return struct.pack('<L',hb)
def correct_checksum(buf):
checksum = sum(buf[1:]) & 0xff
return checksum.to_bytes(length=1)
@@ -90,8 +109,9 @@ def DeviceIndMsg(): # 0x4110
@pytest.fixture
def DeviceRspMsg(): # 0x1110
msg = b'\xa5\x0a\x00\x10\x11\x10\x84' +get_sn() +b'\x01\x01\x69\x6f\x09'
msg += b'\x66\x78\x00\x00\x00'
msg = b'\xa5\x0a\x00\x10\x11\x01\x01' +get_sn() +b'\x02\x01'
msg += total()
msg += hb()
msg += correct_checksum(msg)
msg += b'\x15'
return msg
@@ -158,7 +178,7 @@ def InvalidChecksum(): # 0x4110
@pytest.fixture
def InverterIndMsg(): # 0x4210
msg = b'\xa5\x99\x01\x10\x42\xe6\x9e' +get_sn() +b'\x01\xb0\x02\xbc\xc8'
msg = b'\xa5\x99\x01\x10\x42\x01\x02' +get_sn() +b'\x01\xb0\x02\xbc\xc8'
msg += b'\x24\x32\x6c\x1f\x00\x00\xa0\x47\xe4\x33\x01\x00\x03\x08\x00\x00'
msg += b'\x59\x31\x37\x45\x37\x41\x30\x46\x30\x31\x30\x42\x30\x31\x33\x45'
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
@@ -290,8 +310,9 @@ def InverterIndMsg2000(): # 0x4210 rated Power 2000W
@pytest.fixture
def InverterRspMsg(): # 0x1210
msg = b'\xa5\x0a\x00\x10\x12\x10\x84' +get_sn() +b'\x01\x01\x69\x6f\x09'
msg += b'\x66\x78\x00\x00\x00'
msg = b'\xa5\x0a\x00\x10\x12\x02\02' +get_sn() +b'\x01\x01'
msg += total()
msg += hb()
msg += correct_checksum(msg)
msg += b'\x15'
return msg
@@ -314,8 +335,9 @@ def HeartbeatIndMsg(): # 0x4710
@pytest.fixture
def HeartbeatRspMsg(): # 0x1710
msg = b'\xa5\x0a\x00\x10\x17\x10\x84' +get_sn() +b'\x00\x01\x22\x71\x09'
msg += b'\x66\x78\x00\x00\x00'
msg = b'\xa5\x0a\x00\x10\x17\x11\x84' +get_sn() +b'\x00\x01'
msg += total()
msg += hb()
msg += correct_checksum(msg)
msg += b'\x15'
return msg
@@ -349,7 +371,7 @@ def test_read_message(DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == None
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -370,7 +392,7 @@ def test_invalid_start_byte(InvalidStartByte, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == 0
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -390,7 +412,7 @@ def test_invalid_stop_byte(InvalidStopByte):
assert m.snr == 2070233889
assert m.unique_id == 0
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -410,7 +432,7 @@ def test_invalid_stop_byte2(InvalidStopByte, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == 0
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==DeviceIndMsg
assert m._send_buffer==b''
@@ -424,7 +446,7 @@ def test_invalid_stop_byte2(InvalidStopByte, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == None
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -446,7 +468,7 @@ def test_invalid_stop_start_byte(InvalidStopByte, InvalidStartByte):
assert m.snr == 2070233889
assert m.unique_id == 0
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -466,7 +488,7 @@ def test_invalid_checksum(InvalidChecksum, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == 0
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==DeviceIndMsg
assert m._send_buffer==b''
@@ -480,7 +502,7 @@ def test_invalid_checksum(InvalidChecksum, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == None
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -488,7 +510,7 @@ def test_invalid_checksum(InvalidChecksum, DeviceIndMsg):
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 1
m.close()
def test_read_message_twice(ConfigNoTsunInv1, DeviceIndMsg):
def test_read_message_twice(ConfigNoTsunInv1, DeviceIndMsg, DeviceRspMsg):
ConfigNoTsunInv1
m = MemoryStream(DeviceIndMsg, (0,))
m.append_msg(DeviceIndMsg)
@@ -499,10 +521,13 @@ def test_read_message_twice(ConfigNoTsunInv1, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:01'
assert m.data_len == 0xd4
assert m._send_buffer==DeviceRspMsg
assert m._forward_buffer==b''
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m._send_buffer = bytearray(0) # clear send buffer for next test
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
@@ -510,8 +535,9 @@ def test_read_message_twice(ConfigNoTsunInv1, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:01'
assert m.data_len == 0xd4
assert m._send_buffer==DeviceRspMsg
assert m._forward_buffer==b''
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.close()
@@ -528,7 +554,7 @@ def test_read_message_in_chunks(DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == 0 # should be None ?
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:00'
assert m.data_len == 0xd4
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.read() # read rest of message
@@ -552,7 +578,7 @@ def test_read_message_in_chunks2(ConfigTsunInv1, DeviceIndMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:01'
assert m.data_len == 0xd4
assert m.msg_count == 1
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
@@ -563,7 +589,7 @@ def test_read_message_in_chunks2(ConfigTsunInv1, DeviceIndMsg):
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.close()
def test_read_two_messages(ConfigTsunAllowAll, DeviceIndMsg, InverterIndMsg):
def test_read_two_messages(ConfigTsunAllowAll, DeviceIndMsg, DeviceRspMsg, InverterIndMsg, InverterRspMsg):
ConfigTsunAllowAll
m = MemoryStream(DeviceIndMsg, (0,))
m.append_msg(InverterIndMsg)
@@ -574,14 +600,13 @@ def test_read_two_messages(ConfigTsunAllowAll, DeviceIndMsg, InverterIndMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x4110
assert m.serial == 0x0100
assert str(m.seq) == '01:01'
assert m.data_len == 0xd4
assert m.msg_count == 1
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
assert m._forward_buffer==DeviceIndMsg
assert m._send_buffer==b''
# assert m._send_buffer==MsgContactResp
assert m._send_buffer==DeviceRspMsg
m._send_buffer = bytearray(0) # clear send buffer for next test
m._init_new_client_conn()
assert m._send_buffer==b''
@@ -597,11 +622,11 @@ def test_read_two_messages(ConfigTsunAllowAll, DeviceIndMsg, InverterIndMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x4210
assert m.serial == 0x9ee6
assert str(m.seq) == '02:02'
assert m.data_len == 0x199
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
assert m._forward_buffer==InverterIndMsg
assert m._send_buffer==b''
assert m._send_buffer==InverterRspMsg
m._send_buffer = bytearray(0) # clear send buffer for next test
m._init_new_client_conn()
@@ -618,7 +643,7 @@ def test_unkown_message(ConfigTsunInv1, UnknownMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x5110
assert m.serial == 0x8410
assert str(m.seq) == '84:10'
assert m.data_len == 0x0a
assert m._recv_buffer==b''
assert m._send_buffer==b''
@@ -636,11 +661,11 @@ def test_device_rsp(ConfigTsunInv1, DeviceRspMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x1110
assert m.serial == 0x8410
assert str(m.seq) == '01:01'
assert m.data_len == 0x0a
assert m._recv_buffer==b''
assert m._send_buffer==b''
assert m._forward_buffer==DeviceRspMsg
assert m._forward_buffer==b'' # DeviceRspMsg
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.close()
@@ -654,15 +679,15 @@ def test_inverter_rsp(ConfigTsunInv1, InverterRspMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x1210
assert m.serial == 0x8410
assert str(m.seq) == '02:02'
assert m.data_len == 0x0a
assert m._recv_buffer==b''
assert m._send_buffer==b''
assert m._forward_buffer==InverterRspMsg
assert m._forward_buffer==b'' # InverterRspMsg
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.close()
def test_heartbeat_ind(ConfigTsunInv1, HeartbeatIndMsg):
def test_heartbeat_ind(ConfigTsunInv1, HeartbeatIndMsg, HeartbeatRspMsg):
ConfigTsunInv1
m = MemoryStream(HeartbeatIndMsg, (0,))
m.read() # read complete msg, and dispatch msg
@@ -672,10 +697,10 @@ def test_heartbeat_ind(ConfigTsunInv1, HeartbeatIndMsg):
assert m.snr == 2070233889
# assert m.unique_id == '2070233889'
assert m.control == 0x4710
assert m.serial == 0x8410
assert str(m.seq) == '84:11' # value after sending response
assert m.data_len == 0x01
assert m._recv_buffer==b''
assert m._send_buffer==b''
assert m._send_buffer==HeartbeatRspMsg
assert m._forward_buffer==HeartbeatIndMsg
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.close()
@@ -690,11 +715,11 @@ def test_heartbeat_rsp(ConfigTsunInv1, HeartbeatRspMsg):
assert m.snr == 2070233889
assert m.unique_id == '2070233889'
assert m.control == 0x1710
assert m.serial == 0x8410
assert str(m.seq) == '11:84' # value after sending response
assert m.data_len == 0x0a
assert m._recv_buffer==b''
assert m._send_buffer==b''
assert m._forward_buffer==HeartbeatRspMsg
assert m._forward_buffer==b'' # HeartbeatRspMsg
assert m.db.stat['proxy']['Invalid_Msg_Format'] == 0
m.close()
@@ -708,7 +733,7 @@ def test_at_command_ind(ConfigTsunInv1, AtCommandIndMsg):
assert m.snr == 2070233889
# assert m.unique_id == '2070233889'
assert m.control == 0x4510
assert m.serial == 0x8410
assert str(m.seq) == '84:10'
assert m.data_len == 0x01
assert m._recv_buffer==b''
assert m._send_buffer==b''