diff --git a/CHANGELOG.md b/CHANGELOG.md index aa817e7..3c82430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +- MODBUS: the last digit of the inverter version is a hexadecimal number [#119](https://github.com/s-allius/tsun-gen3-proxy/issues/119) - GEN3PLUS: add client_mode connection on port 8899 [#117](https://github.com/s-allius/tsun-gen3-proxy/issues/117) ## [0.9.0] - 2024-07-01 diff --git a/app/src/modbus.py b/app/src/modbus.py index 2b3a335..63c2d19 100644 --- a/app/src/modbus.py +++ b/app/src/modbus.py @@ -44,7 +44,7 @@ class Modbus(): 0x203e: {'reg': Register.NO_INPUTS, 'fmt': '!H', 'ratio': 1/256}, # noqa: E501 0x3000: {'reg': Register.INVERTER_STATUS, 'fmt': '!H'}, # noqa: E501 - 0x3008: {'reg': Register.VERSION, 'fmt': '!H', 'eval': "f'V{(result>>12)}.{(result>>8)&0xf}.{(result>>4)&0xf}{result&0xf}'"}, # noqa: E501 + 0x3008: {'reg': Register.VERSION, 'fmt': '!H', 'eval': "f'V{(result>>12)}.{(result>>8)&0xf}.{(result>>4)&0xf}{result&0xf:1X}'"}, # noqa: E501 0x3009: {'reg': Register.GRID_VOLTAGE, 'fmt': '!H', 'ratio': 0.1}, # noqa: E501 0x300a: {'reg': Register.GRID_CURRENT, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501 0x300b: {'reg': Register.GRID_FREQUENCY, 'fmt': '!H', 'ratio': 0.01}, # noqa: E501 diff --git a/app/tests/test_modbus.py b/app/tests/test_modbus.py index 0009182..16cb7ce 100644 --- a/app/tests/test_modbus.py +++ b/app/tests/test_modbus.py @@ -32,7 +32,12 @@ def test_modbus_crc(): assert mb._Modbus__check_crc(b'\x01\x06\x20\x08\x00\x00\x03\xc8') assert 0x5c75 == mb._Modbus__calc_crc(b'\x01\x03\x08\x01\x2c\x00\x2c\x02\x2c\x2c\x46') - + msg = b'\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' + assert 0 == mb._Modbus__calc_crc(msg) + def test_build_modbus_pdu(): '''Check building and sending a MODBUS RTU''' mb = ModbusTestHelper() @@ -173,7 +178,7 @@ def test_parse_resp(): assert mb.req_pend call = 0 - exp_result = ['V0.0.212', 4.4, 0.7, 0.7, 30] + exp_result = ['V0.0.2C', 4.4, 0.7, 0.7, 30] for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x0c\x01\x2c\x00\x2c\x00\x2c\x00\x46\x00\x46\x00\x46\x32\xc8', 'test'): if key == 'grid': assert update == True @@ -222,7 +227,7 @@ def test_queue2(): assert mb.send_calls == 1 assert mb.pdu == b'\x01\x030\x07\x00\x06{\t' call = 0 - exp_result = ['V0.0.212', 4.4, 0.7, 0.7, 30] + exp_result = ['V0.0.2C', 4.4, 0.7, 0.7, 30] for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x0c\x01\x2c\x00\x2c\x00\x2c\x00\x46\x00\x46\x00\x46\x32\xc8', 'test'): if key == 'grid': assert update == True @@ -272,7 +277,7 @@ def test_queue3(): assert mb.recv_responses == 0 call = 0 - exp_result = ['V0.0.212', 4.4, 0.7, 0.7, 30] + exp_result = ['V0.0.2C', 4.4, 0.7, 0.7, 30] for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x0c\x01\x2c\x00\x2c\x00\x2c\x00\x46\x00\x46\x00\x46\x32\xc8', 'test'): if key == 'grid': assert update == True diff --git a/app/tests/test_talent.py b/app/tests/test_talent.py index f8efca0..5997cd8 100644 --- a/app/tests/test_talent.py +++ b/app/tests/test_talent.py @@ -339,6 +339,15 @@ def MsgModbusResp20(): msg += b'\x00\x00\x00\x00\x00\x00\x00\xdb\x6b' return msg +@pytest.fixture +def MsgModbusResp21(): + 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 + def test_read_message(MsgContactInfo): m = MemoryStream(MsgContactInfo, (0,)) m.read() # read complete msg, and dispatch msg @@ -1226,11 +1235,11 @@ def test_msg_modbus_rsp2(ConfigTsunInv1, MsgModbusResp20): m.close() -def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusResp20): +def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusResp21): '''Modbus response with a valid Modbus request must be forwarded''' ConfigTsunInv1 - m = MemoryStream(MsgModbusResp20) - m.append_msg(MsgModbusResp20) + m = MemoryStream(MsgModbusResp21) + m.append_msg(MsgModbusResp21) m.mb.rsp_handler = m.msg_forward m.mb.last_addr = 1 @@ -1247,10 +1256,10 @@ def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusResp20): 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._forward_buffer==MsgModbusResp20 + assert m._forward_buffer==MsgModbusResp21 assert m._send_buffer==b'' - assert m.db.db == {'inverter': {'Version': 'V5.1.09', 'Rated_Power': 300}, 'grid': {'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'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.db == {'inverter': {'Version': 'V5.1.0E', 'Rated_Power': 300}, 'grid': {'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'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.new_data['inverter'] == True m.new_data['inverter'] = False assert m.mb.req_pend == False @@ -1259,10 +1268,10 @@ def test_msg_modbus_rsp3(ConfigTsunInv1, MsgModbusResp20): 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._forward_buffer==MsgModbusResp20 + assert m._forward_buffer==MsgModbusResp21 assert m._send_buffer==b'' - assert m.db.db == {'inverter': {'Version': 'V5.1.09', 'Rated_Power': 300}, 'grid': {'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'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.db == {'inverter': {'Version': 'V5.1.0E', 'Rated_Power': 300}, 'grid': {'Voltage': 225.9, 'Current': 0.41, 'Frequency': 49.99, 'Output_Power': 94.8}, 'env': {'Inverter_Temp': 22}, 'input': {'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.new_data['inverter'] == False m.close()