Compare commits

...

74 Commits

Author SHA1 Message Date
Stefan Allius
1f4d3740d6 Merge branch 'dev-0.12' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-11-14 19:38:18 +01:00
Stefan Allius
abdc323dc6 Merge branch 'dev-0.12' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-11-02 15:40:32 +01:00
Stefan Allius
35efa65410 apdate start_reg 2024-10-23 19:10:28 +02:00
Stefan Allius
399d0b58ff fix testcase 2024-10-22 00:08:05 +02:00
Stefan Allius
2b4bd2922c don't scan sensor list type 0x02b0 2024-10-22 00:07:36 +02:00
Stefan Allius
3eba999a2b fix _send_modbus_cmd calls 2024-10-22 00:06:31 +02:00
Stefan Allius
ad8a902ac6 configure scan increment 2024-10-20 16:52:30 +02:00
Stefan Allius
fda4008036 update start reg 2024-10-18 23:47:44 +02:00
Stefan Allius
e7e693c0b6 Merge branch 'dev-0.12' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-10-17 23:33:05 +02:00
Stefan Allius
98665b3aac log valid modbus responses for all inverter 2024-10-16 23:48:54 +02:00
Stefan Allius
6b488e5269 Merge branch 'dev-0.12' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-10-16 23:33:06 +02:00
Stefan Allius
010ae2b2c7 Merge branch 'dev-0.12' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-10-15 22:18:30 +02:00
Stefan Allius
24840e67c0 adapt start_reg 2024-10-13 22:38:21 +02:00
Stefan Allius
2dd89d3174 git push 2024-10-13 19:45:11 +02:00
Stefan Allius
c84b610229 also scan GEN3(PLUS) inverters 2024-10-13 09:33:23 +02:00
Stefan Allius
5dc890dde0 Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-10-11 20:30:09 +02:00
Stefan Allius
0c10cc32dc update changelog 2024-10-11 20:29:20 +02:00
Stefan Allius
71f581eb0b add more unittests 2024-10-10 22:41:13 +02:00
Stefan Allius
a4acddd769 remove obsolete tx_get method 2024-10-10 00:30:10 +02:00
Stefan Allius
724f6f3b22 simplify heartbeat handler 2024-10-10 00:00:32 +02:00
Stefan Allius
18c3020282 increase tes coverage 2024-10-09 23:59:56 +02:00
Stefan Allius
e127716317 increase test coverage 2024-10-08 23:48:49 +02:00
Stefan Allius
5790b657d0 update start-REG 2024-10-07 23:20:21 +02:00
Stefan Allius
5d4ff9051d Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-10-06 21:28:12 +02:00
Stefan Allius
595b68ba03 reduce cognitive complexity 2024-10-06 21:20:53 +02:00
Stefan Allius
d7628689f0 icrease test coverage 2024-10-06 21:15:46 +02:00
Stefan Allius
e074a39f5a add unit tests for AsyncStream class 2024-10-06 17:43:40 +02:00
Stefan Allius
9852f44dfa use ProtocolIfc class 2024-10-05 21:11:42 +02:00
Stefan Allius
c7d0a91371 add more testcases 2024-10-05 01:35:04 +02:00
Stefan Allius
5b68610f78 move class InverterIfc into a separate file 2024-10-05 01:34:03 +02:00
Stefan Allius
0b79a37fe7 fix typo 2024-10-05 01:33:05 +02:00
Stefan Allius
00e9a4534d rename class Inverter into Proxy 2024-10-04 23:37:05 +02:00
Stefan Allius
3a94afb48d fix sonar qube warnings 2024-10-04 01:50:24 +02:00
Stefan Allius
949f3c9608 initial commit 2024-10-04 01:41:25 +02:00
Stefan Allius
cd2f41a713 add abstract inverter interface class 2024-10-04 01:35:44 +02:00
Stefan Allius
84034127e3 remove test_inverter_base.py 2024-10-03 15:11:22 +02:00
Stefan Allius
22d59ed659 move more code into InverterBase class 2024-10-03 15:08:07 +02:00
Stefan Allius
cfe2c9cb9d remove connection classes 2024-10-02 23:40:42 +02:00
Stefan Allius
39aba31bbd refactor close handling 2024-10-01 19:50:42 +02:00
Stefan Allius
a1441fb4fd add close callback 2024-09-30 19:17:06 +02:00
Stefan Allius
f2ade43410 fixes
- fixes null pointer accesses
- initalize AsyncStreamClient with proper
  StreamPtr instance
2024-09-30 19:14:50 +02:00
Stefan Allius
8f695518bd update class diagramm 2024-09-30 19:13:29 +02:00
Stefan Allius
b3068a256c don't overwrite self.remote in constructor 2024-09-30 19:12:49 +02:00
Stefan Allius
2336955bb8 fix client loop closing 2024-09-29 21:11:53 +02:00
Stefan Allius
8a745b2d10 Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-09-29 20:52:08 +02:00
Stefan Allius
518375e8a8 fix server connections 2024-09-29 20:49:08 +02:00
Stefan Allius
b57ded1a73 Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-09-29 20:27:28 +02:00
Stefan Allius
41aeac4168 resolution of connection classes
- remove ConnectionG3Client
- remove ConnectionG3Server
- remove ConnectionG3PClient
- remove ConnectionG3PServer
2024-09-29 20:08:04 +02:00
Stefan Allius
5a0ef30ceb move StremPtr instances into Inverter class 2024-09-29 15:31:14 +02:00
Stefan Allius
4c15495670 update start register 2024-09-29 14:30:33 +02:00
Stefan Allius
ca610b15ff Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-09-29 10:23:04 +02:00
Stefan Allius
0c824b4a2a reduce code duplication 2024-09-29 10:15:38 +02:00
Stefan Allius
95f817a92b Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-09-28 23:31:02 +02:00
Stefan Allius
2ef7a7e201 remove duplicated imports 2024-09-28 23:30:23 +02:00
Stefan Allius
2be0ef67af refactor server creation 2024-09-28 22:43:29 +02:00
Stefan Allius
43700b3da8 Merge branch 'refactoring-async-stream' of https://github.com/s-allius/tsun-gen3-proxy into titan-scan 2024-09-27 19:28:39 +02:00
Stefan Allius
7b6810cb46 update class diagramm 2024-09-27 19:25:40 +02:00
Stefan Allius
aa7c1832ef split ConnectionG3(P) in server and client class 2024-09-27 00:47:44 +02:00
Stefan Allius
73526b7dc6 split AsyncStream in two classes 2024-09-26 23:04:11 +02:00
Stefan Allius
b6761e7517 FIX update_header_cb handling 2024-09-26 00:14:51 +02:00
Stefan Allius
209956865b add two more callbacks 2024-09-26 00:11:11 +02:00
Stefan Allius
bc54944077 add two more callbacks 2024-09-25 22:41:01 +02:00
Stefan Allius
37c977c2fe avoid mqtt handling for invalid serial numbers 2024-09-25 00:11:39 +02:00
Stefan Allius
d5c369e5fe refactoring 2024-09-24 21:12:51 +02:00
Stefan Allius
89c2c11ed9 refactoring 2024-09-24 21:10:58 +02:00
Stefan Allius
eea725b8da remove _forward_buffer 2024-09-22 15:00:53 +02:00
Stefan Allius
0b437cf3bc - refactoring
- remove _forward_buffer
- make async_write private
2024-09-22 14:59:18 +02:00
Stefan Allius
ae4bcee41f experimental modbus scan 2024-09-22 10:56:48 +02:00
Stefan Allius
edc0f7a6af Merge branch 'dev-0.11' of https://github.com/s-allius/tsun-gen3-proxy into refactoring-async-stream 2024-09-22 10:51:41 +02:00
Stefan Allius
9ffcfbc9ce declare more methods as classmethods 2024-09-22 10:42:48 +02:00
Stefan Allius
b7c63b5cf8 use AsyncIfc class with FIFO 2024-09-22 10:40:30 +02:00
Stefan Allius
af81aef07c add object factory 2024-09-22 10:29:38 +02:00
Stefan Allius
f216c2434e introduce ifc with FIFOs 2024-09-22 10:28:36 +02:00
Stefan Allius
39540678fb GEN3: Invalid Contact Info Msg
Fixes #191
2024-09-18 22:07:26 +02:00
5 changed files with 76 additions and 16 deletions

View File

@@ -186,9 +186,11 @@ class Talent(Message):
if 2 == (exp_cnt % 30): if 2 == (exp_cnt % 30):
# logging.info("Regular Modbus Status request") # logging.info("Regular Modbus Status request")
self._send_modbus_cmd(Modbus.READ_REGS, 0x2000, 96, logging.DEBUG) self._send_modbus_cmd(Modbus.INV_ADDR, Modbus.READ_REGS, 0x2000,
96, logging.DEBUG)
else: else:
self._send_modbus_cmd(Modbus.READ_REGS, 0x3000, 48, logging.DEBUG) self._send_modbus_cmd(Modbus.INV_ADDR, Modbus.READ_REGS, 0x3000,
48, logging.DEBUG)
def _init_new_client_conn(self) -> bool: def _init_new_client_conn(self) -> bool:
contact_name = self.contact_name contact_name = self.contact_name

View File

@@ -253,7 +253,8 @@ class SolarmanBase(Message):
class SolarmanV5(SolarmanBase): class SolarmanV5(SolarmanBase):
AT_CMD = 1 AT_CMD = 1
MB_RTU_CMD = 2 MB_RTU_CMD = 2
MB_CLIENT_DATA_UP = 30 '''regular Modbus polling time in server mode'''
MB_CLIENT_DATA_UP = 10
'''Data up time in client mode''' '''Data up time in client mode'''
HDR_FMT = '<BLLL' HDR_FMT = '<BLLL'
'''format string for packing of the header''' '''format string for packing of the header'''
@@ -328,7 +329,11 @@ class SolarmanV5(SolarmanBase):
if 'at_acl' in g3p_cnf: # pragma: no cover if 'at_acl' in g3p_cnf: # pragma: no cover
self.at_acl = g3p_cnf['at_acl'] self.at_acl = g3p_cnf['at_acl']
self.sensor_list = 0 self.sensor_list = 0x0000
self.mb_start_reg = 0x0001 # 0x7001
self.mb_incr_reg = 0x100 # 4
self.mb_inv_no = 144 # 3
self.mb_scan_len = 4
''' '''
Our puplic methods Our puplic methods
@@ -364,7 +369,23 @@ class SolarmanV5(SolarmanBase):
self.new_data['controller'] = True self.new_data['controller'] = True
self.state = State.up self.state = State.up
self._send_modbus_cmd(Modbus.READ_REGS, 0x3000, 48, logging.DEBUG) # self.__build_header(0x1710)
# self.ifc.write += struct.pack('<B', 0)
# self.__finish_send_msg()
# hex_dump_memory(logging.INFO, f'Send StartCmd:{self.addr}:',
# self.ifc.write, len(self.ifc.write))
# self.writer.write(self.ifc.write)
# self.ifc.write = bytearray(0) # self.ifc.write[sent:]
if self.sensor_list != 0x02b0:
self._send_modbus_cmd(self.mb_inv_no, Modbus.READ_REGS,
self.mb_start_reg, self.mb_scan_len,
logging.INFO)
else:
self.mb_inv_no = Modbus.INV_ADDR
self._send_modbus_cmd(self.mb_inv_no, Modbus.READ_REGS, 0x3000,
48, logging.DEBUG)
self.mb_timer.start(self.mb_timeout) self.mb_timer.start(self.mb_timeout)
def new_state_up(self): def new_state_up(self):
@@ -467,12 +488,29 @@ class SolarmanV5(SolarmanBase):
def mb_timout_cb(self, exp_cnt): def mb_timout_cb(self, exp_cnt):
self.mb_timer.start(self.mb_timeout) self.mb_timer.start(self.mb_timeout)
if self.sensor_list != 0x02b0:
self.mb_start_reg += self.mb_incr_reg
if self.mb_start_reg > 0xffff:
self.mb_start_reg = self.mb_start_reg & 0xffff
self.mb_inv_no += 1
logging.info(f"Next Round: inv:{self.mb_inv_no}"
f" reg:{self.mb_start_reg:04x}")
if (self.mb_start_reg & 0xfffc) % 0x80 == 0:
logging.info(f"Scan info: inv:{self.mb_inv_no}"
f" reg:{self.mb_start_reg:04x}")
self._send_modbus_cmd(self.mb_inv_no, Modbus.READ_REGS,
self.mb_start_reg, self.mb_scan_len,
logging.INFO)
else:
self._send_modbus_cmd(Modbus.INV_ADDR, Modbus.READ_REGS, 0x3000,
48, logging.DEBUG)
self._send_modbus_cmd(Modbus.READ_REGS, 0x3000, 48, logging.DEBUG) if 1 == (exp_cnt % 30):
# logging.info("Regular Modbus Status request")
if 1 == (exp_cnt % 30): self._send_modbus_cmd(Modbus.INV_ADDR, Modbus.READ_REGS,
# logging.info("Regular Modbus Status request") 0x5000, 8, logging.DEBUG)
self._send_modbus_cmd(Modbus.READ_REGS, 0x2000, 96, logging.DEBUG) self._send_modbus_cmd(Modbus.INV_ADDR, Modbus.READ_REGS,
0x2000, 96, logging.DEBUG)
def at_cmd_forbidden(self, cmd: str, connection: str) -> bool: def at_cmd_forbidden(self, cmd: str, connection: str) -> bool:
return not cmd.startswith(tuple(self.at_acl[connection]['allow'])) or \ return not cmd.startswith(tuple(self.at_acl[connection]['allow'])) or \
@@ -685,6 +723,21 @@ class SolarmanV5(SolarmanBase):
if valid == 1 and modbus_msg_len > 4: if valid == 1 and modbus_msg_len > 4:
# logger.info(f'first byte modbus:{data[14]}') # logger.info(f'first byte modbus:{data[14]}')
inv_update = self.__parse_modbus_rsp(data) inv_update = self.__parse_modbus_rsp(data)
self.modbus_elms = 0
if (self.sensor_list != 0x02b0 and data[15] != 0):
logging.info('Valid MODBUS data '
f'(inv:{self.mb_inv_no} '
f'reg: 0x{self.mb.last_reg:04x}):')
hex_dump_memory(logging.INFO, 'Valid MODBUS data '
f'(reg: 0x{self.mb.last_reg:04x}):',
data[14:], modbus_msg_len)
for key, update, _ in self.mb.recv_resp(self.db, data[14:]):
self.modbus_elms += 1
if update:
if key == 'inverter':
inv_update = True
self._set_mqtt_timestamp(key, self._timestamp())
self.new_data[key] = True
if inv_update: if inv_update:
self.__build_model_name() self.__build_model_name()

View File

@@ -95,7 +95,7 @@ class Message(ProtocolIfc):
'''maximum default time without a received msg in sec''' '''maximum default time without a received msg in sec'''
MB_START_TIMEOUT = 40 MB_START_TIMEOUT = 40
'''start delay for Modbus polling in server mode''' '''start delay for Modbus polling in server mode'''
MB_REGULAR_TIMEOUT = 60 MB_REGULAR_TIMEOUT = 20
'''regular Modbus polling time in server mode''' '''regular Modbus polling time in server mode'''
def __init__(self, node_id, ifc: "AsyncIfc", server_side: bool, def __init__(self, node_id, ifc: "AsyncIfc", server_side: bool,
@@ -168,15 +168,15 @@ class Message(ProtocolIfc):
to = self.MAX_DEF_IDLE_TIME to = self.MAX_DEF_IDLE_TIME
return to return to
def _send_modbus_cmd(self, func, addr, val, log_lvl) -> None: def _send_modbus_cmd(self, mb_no, func, addr, val, log_lvl) -> None:
if self.state != State.up: if self.state != State.up:
logger.log(log_lvl, f'[{self.node_id}] ignore MODBUS cmd,' logger.log(log_lvl, f'[{self.node_id}] ignore MODBUS cmd,'
' as the state is not UP') ' as the state is not UP')
return return
self.mb.build_msg(Modbus.INV_ADDR, func, addr, val, log_lvl) self.mb.build_msg(mb_no, func, addr, val, log_lvl)
async def send_modbus_cmd(self, func, addr, val, log_lvl) -> None: async def send_modbus_cmd(self, func, addr, val, log_lvl) -> None:
self._send_modbus_cmd(func, addr, val, log_lvl) self._send_modbus_cmd(Modbus.INV_ADDR, func, addr, val, log_lvl)
''' '''
Our puplic methods Our puplic methods

View File

@@ -103,8 +103,8 @@ class Modbus():
'''Response handler to forward the response''' '''Response handler to forward the response'''
self.timeout = timeout self.timeout = timeout
'''MODBUS response timeout in seconds''' '''MODBUS response timeout in seconds'''
self.max_retries = 1 self.max_retries = 0
'''Max retransmit for MODBUS requests''' '''Max retransmit for MODBU requests'''
self.retry_cnt = 0 self.retry_cnt = 0
self.last_req = b'' self.last_req = b''
self.counter = {} self.counter = {}

View File

@@ -1730,6 +1730,7 @@ async def test_modbus_polling(config_tsun_inv1, heartbeat_ind_msg, heartbeat_rsp
assert asyncio.get_running_loop() == m.mb_timer.loop assert asyncio.get_running_loop() == m.mb_timer.loop
m.db.stat['proxy']['Unknown_Ctrl'] = 0 m.db.stat['proxy']['Unknown_Ctrl'] = 0
assert m.mb_timer.tim == None assert m.mb_timer.tim == None
m.read() # read complete msg, and dispatch msg m.read() # read complete msg, and dispatch msg
assert not m.header_valid # must be invalid, since msg was handled and buffer flushed assert not m.header_valid # must be invalid, since msg was handled and buffer flushed
assert m.msg_count == 1 assert m.msg_count == 1
@@ -1767,6 +1768,10 @@ async def test_start_client_mode(config_tsun_inv1, str_test_ip):
_ = config_tsun_inv1 _ = config_tsun_inv1
assert asyncio.get_running_loop() assert asyncio.get_running_loop()
m = MemoryStream(b'') m = MemoryStream(b'')
m.mb_start_reg = 0x3000
m.mb_incr_reg = 0x00 # 4
m.mb_scan_len = 48
assert m.state == State.init assert m.state == State.init
assert m.no_forwarding == False assert m.no_forwarding == False
assert m.mb_timer.tim == None assert m.mb_timer.tim == None