Compare commits

...

5 Commits

Author SHA1 Message Date
Stefan Allius
264cc52ce7 change the PV module handling
- in default we set the number of modules now to
  two. So with the first data from the inverter
  we only register two modules. After we determine
  the inverter module, the number can increase to
  four and more PV modules will be registered.

  With the default value of 4, we register always
  4 modules and can't reduce the number of areas
  when we detect that the inverter only supoorts
  two PV modules
2025-05-24 22:59:20 +02:00
Stefan Allius
f0c8a851bc increase test coverage 2025-05-22 21:50:38 +02:00
Stefan Allius
df356fdc86 fix unit test 2025-05-22 21:34:55 +02:00
Stefan Allius
a470635a7c Merge branch 'main' of https://github.com/s-allius/tsun-gen3-proxy into s-allius/issue421 2025-05-22 21:32:14 +02:00
Stefan Allius
e2ff27d58f set no of pv modules for MS800 GEN3PLUS inverters 2025-05-22 21:05:58 +02:00
5 changed files with 63 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased] ## [unreleased]
- set no of pv modules for MS800 GEN3PLUS inverters
- fix the paths to copy the config.example.toml file during proxy start - fix the paths to copy the config.example.toml file during proxy start
- add MQTT topic `dcu_power` for setting output power on DCUs - add MQTT topic `dcu_power` for setting output power on DCUs
- Update ghcr.io/hassio-addons/base Docker tag to v17.2.5 - Update ghcr.io/hassio-addons/base Docker tag to v17.2.5

View File

@@ -216,7 +216,7 @@ class InfosG3P(Infos):
self.set_db_def_value(Register.MANUFACTURER, 'TSUN') self.set_db_def_value(Register.MANUFACTURER, 'TSUN')
self.set_db_def_value(Register.EQUIPMENT_MODEL, 'TSOL-MSxx00') self.set_db_def_value(Register.EQUIPMENT_MODEL, 'TSOL-MSxx00')
self.set_db_def_value(Register.CHIP_TYPE, 'IGEN TECH') self.set_db_def_value(Register.CHIP_TYPE, 'IGEN TECH')
self.set_db_def_value(Register.NO_INPUTS, 4) self.set_db_def_value(Register.NO_INPUTS, 2)
def __hide_topic(self, row: dict) -> bool: def __hide_topic(self, row: dict) -> bool:
if 'dep' in row: if 'dep' in row:

View File

@@ -562,12 +562,17 @@ class SolarmanV5(SolarmanBase):
rated = db.get_db_value(Register.RATED_POWER, 0) rated = db.get_db_value(Register.RATED_POWER, 0)
model = None model = None
if max_pow == 2000: if max_pow == 2000:
db.set_db_def_value(Register.NO_INPUTS, 4)
if rated == 800 or rated == 600: if rated == 800 or rated == 600:
model = f'TSOL-MS{max_pow}({rated})' model = f'TSOL-MS{max_pow}({rated})'
else: else:
model = f'TSOL-MS{max_pow}' model = f'TSOL-MS{max_pow}'
elif max_pow == 1800 or max_pow == 1600: elif max_pow == 1800 or max_pow == 1600:
db.set_db_def_value(Register.NO_INPUTS, 4)
model = f'TSOL-MS{max_pow}' model = f'TSOL-MS{max_pow}'
elif max_pow <= 800:
model = f'TSOL-MS{max_pow}'
if model: if model:
logger.info(f'Model: {model}') logger.info(f'Model: {model}')
self.db.set_db_def_value(Register.EQUIPMENT_MODEL, model) self.db.set_db_def_value(Register.EQUIPMENT_MODEL, model)

View File

@@ -109,7 +109,7 @@ def test_default_db():
i = InfosG3P(client_mode=False) i = InfosG3P(client_mode=False)
assert json.dumps(i.db) == json.dumps({ assert json.dumps(i.db) == json.dumps({
"inverter": {"Manufacturer": "TSUN", "Equipment_Model": "TSOL-MSxx00", "No_Inputs": 4}, "inverter": {"Manufacturer": "TSUN", "Equipment_Model": "TSOL-MSxx00", "No_Inputs": 2},
"collector": {"Chip_Type": "IGEN TECH"}, "collector": {"Chip_Type": "IGEN TECH"},
}) })
@@ -271,7 +271,7 @@ def test_build_ha_conf1():
elif id == 'inv_count_456': elif id == 'inv_count_456':
assert False assert False
assert tests==7 assert tests==5
def test_build_ha_conf2(): def test_build_ha_conf2():
i = InfosG3P(client_mode=False) i = InfosG3P(client_mode=False)
@@ -346,7 +346,7 @@ def test_build_ha_conf3():
elif id == 'inv_count_456': elif id == 'inv_count_456':
assert False assert False
assert tests==7 assert tests==5
def test_build_ha_conf4(): def test_build_ha_conf4():
i = InfosG3P(client_mode=True) i = InfosG3P(client_mode=True)

View File

@@ -462,6 +462,39 @@ def inverter_ind_msg800(): # 0x4210 rated Power 800W
msg += b'\x15' msg += b'\x15'
return msg return msg
@pytest.fixture
def inverter_ind_msg900(): # 0x4210 rated Power 900W
msg = b'\xa5\x99\x01\x10\x42\xe6\x9e' +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'
msg += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\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'\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
msg += b'\x40\x10\x08\xc8\x00\x49\x13\x8d\x00\x36\x00\x00\x03\x84\x06\x7a'
msg += b'\x01\x61\x00\xa8\x02\x54\x01\x5a\x00\x8a\x01\xe4\x01\x5a\x00\xbd'
msg += b'\x02\x8f\x00\x11\x00\x01\x00\x00\x00\x0b\x00\x00\x27\x98\x00\x04'
msg += b'\x00\x00\x0c\x04\x00\x03\x00\x00\x0a\xe7\x00\x05\x00\x00\x0c\x75'
msg += b'\x00\x00\x00\x00\x06\x16\x02\x00\x00\x00\x55\xaa\x00\x01\x00\x00'
msg += b'\x00\x00\x00\x00\xff\xff\x03\x84\x00\x03\x04\x00\x04\x00\x04\x00'
msg += b'\x04\x00\x00\x01\xff\xff\x00\x01\x00\x06\x00\x68\x00\x68\x05\x00'
msg += b'\x09\xcd\x07\xb6\x13\x9c\x13\x24\x00\x01\x07\xae\x04\x0f\x00\x41'
msg += b'\x00\x0f\x0a\x64\x0a\x64\x00\x06\x00\x06\x09\xf6\x12\x8c\x12\x8c'
msg += b'\x00\x10\x00\x10\x14\x52\x14\x52\x00\x10\x00\x10\x01\x51\x00\x05'
msg += b'\x04\x00\x00\x01\x13\x9c\x0f\xa0\x00\x4e\x00\x66\x03\xe8\x04\x00'
msg += b'\x09\xce\x07\xa8\x13\x9c\x13\x26\x00\x00\x00\x00\x00\x00\x00\x00'
msg += b'\x00\x00\x00\x00\x04\x00\x04\x00\x00\x00\x00\x00\xff\xff\x00\x00'
msg += b'\x00\x00\x00\x00'
msg += correct_checksum(msg)
msg += b'\x15'
return msg
@pytest.fixture @pytest.fixture
def inverter_ind_msg_81(): # 0x4210 fcode 0x81 def inverter_ind_msg_81(): # 0x4210 fcode 0x81
msg = b'\xa5\x99\x01\x10\x42\x02\x03' +get_sn() +b'\x81\xb0\x02\xbc\xc8' msg = b'\xa5\x99\x01\x10\x42\x02\x03' +get_sn() +b'\x81\xb0\x02\xbc\xc8'
@@ -1435,6 +1468,7 @@ async def test_build_modell_600(my_loop, config_tsun_allow_all, inverter_ind_msg
m.read() # read complete msg, and dispatch msg m.read() # read complete msg, and dispatch msg
assert 2000 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert 2000 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
assert 600 == m.db.get_db_value(Register.RATED_POWER, 0) assert 600 == m.db.get_db_value(Register.RATED_POWER, 0)
assert 4 == m.db.get_db_value(Register.NO_INPUTS, 0)
assert 'TSOL-MS2000(600)' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0) assert 'TSOL-MS2000(600)' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0)
assert '02b0' == m.db.get_db_value(Register.SENSOR_LIST, None) assert '02b0' == m.db.get_db_value(Register.SENSOR_LIST, None)
assert 0 == m.sensor_list # must not been set by an inverter data ind assert 0 == m.sensor_list # must not been set by an inverter data ind
@@ -1454,6 +1488,7 @@ async def test_build_modell_1600(my_loop, config_tsun_allow_all, inverter_ind_ms
m.read() # read complete msg, and dispatch msg m.read() # read complete msg, and dispatch msg
assert 1600 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert 1600 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
assert 1600 == m.db.get_db_value(Register.RATED_POWER, 0) assert 1600 == m.db.get_db_value(Register.RATED_POWER, 0)
assert 4 == m.db.get_db_value(Register.NO_INPUTS, 0)
assert 'TSOL-MS1600' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0) assert 'TSOL-MS1600' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0)
m.close() m.close()
@@ -1467,6 +1502,7 @@ async def test_build_modell_1800(my_loop, config_tsun_allow_all, inverter_ind_ms
m.read() # read complete msg, and dispatch msg m.read() # read complete msg, and dispatch msg
assert 1800 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert 1800 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
assert 1800 == m.db.get_db_value(Register.RATED_POWER, 0) assert 1800 == m.db.get_db_value(Register.RATED_POWER, 0)
assert 4 == m.db.get_db_value(Register.NO_INPUTS, 0)
assert 'TSOL-MS1800' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0) assert 'TSOL-MS1800' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0)
m.close() m.close()
@@ -1480,6 +1516,7 @@ async def test_build_modell_2000(my_loop, config_tsun_allow_all, inverter_ind_ms
m.read() # read complete msg, and dispatch msg m.read() # read complete msg, and dispatch msg
assert 2000 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert 2000 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
assert 2000 == m.db.get_db_value(Register.RATED_POWER, 0) assert 2000 == m.db.get_db_value(Register.RATED_POWER, 0)
assert 4 == m.db.get_db_value(Register.NO_INPUTS, 0)
assert 'TSOL-MS2000' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0) assert 'TSOL-MS2000' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0)
m.close() m.close()
@@ -1493,6 +1530,21 @@ async def test_build_modell_800(my_loop, config_tsun_allow_all, inverter_ind_msg
m.read() # read complete msg, and dispatch msg m.read() # read complete msg, and dispatch msg
assert 800 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0) assert 800 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
assert 800 == m.db.get_db_value(Register.RATED_POWER, 0) assert 800 == m.db.get_db_value(Register.RATED_POWER, 0)
assert 2 == m.db.get_db_value(Register.NO_INPUTS, 0)
assert 'TSOL-MS800' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0)
m.close()
@pytest.mark.asyncio
async def test_build_modell_900(my_loop, config_tsun_allow_all, inverter_ind_msg900):
_ = config_tsun_allow_all
m = MemoryStream(inverter_ind_msg900, (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 900 == m.db.get_db_value(Register.MAX_DESIGNED_POWER, 0)
assert 900 == m.db.get_db_value(Register.RATED_POWER, 0)
assert 2 == m.db.get_db_value(Register.NO_INPUTS, 0)
assert 'TSOL-MSxx00' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0) assert 'TSOL-MSxx00' == m.db.get_db_value(Register.EQUIPMENT_MODEL, 0)
m.close() m.close()
@@ -2542,6 +2594,7 @@ async def test_proxy_dcu_cmd(my_loop, config_tsun_dcu1, patch_open_connection, d
assert l.db.stat['proxy']['AT_Command'] == 0 assert l.db.stat['proxy']['AT_Command'] == 0
assert l.db.stat['proxy']['AT_Command_Blocked'] == 0 assert l.db.stat['proxy']['AT_Command_Blocked'] == 0
assert l.db.stat['proxy']['Modbus_Command'] == 0 assert l.db.stat['proxy']['Modbus_Command'] == 0
assert 2 == l.db.get_db_value(Register.NO_INPUTS, 0)
l.append_msg(dcu_command_rsp_msg) l.append_msg(dcu_command_rsp_msg)
l.read() # read at resp l.read() # read at resp