From c5f184a7302fe9c090bd654161072363c7a45b26 Mon Sep 17 00:00:00 2001 From: Stefan Allius Date: Wed, 16 Oct 2024 23:20:23 +0200 Subject: [PATCH] improve setting the node_id in the modbus --- app/src/gen3/talent.py | 5 +++-- app/src/gen3plus/solarman_v5.py | 2 ++ app/src/modbus.py | 7 ++++--- app/tests/test_modbus.py | 35 +++++++++++++++++++++------------ 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/app/src/gen3/talent.py b/app/src/gen3/talent.py index 522f4d0..0081742 100644 --- a/app/src/gen3/talent.py +++ b/app/src/gen3/talent.py @@ -135,6 +135,8 @@ class Talent(Message): self.modbus_polling = inv['modbus_polling'] logger.debug(f'SerialNo {serial_no} allowed! area:{self.sug_area}') # noqa: E501 self.db.set_pv_module_details(inv) + if self.mb: + self.mb.set_node_id(self.node_id) else: self.node_id = '' self.sug_area = '' @@ -590,8 +592,7 @@ class Talent(Message): return for key, update, _ in self.mb.recv_resp(self.db, data[ - hdr_len:], - self.node_id): + hdr_len:]): if update: self._set_mqtt_timestamp(key, self._utc()) self.new_data[key] = True diff --git a/app/src/gen3plus/solarman_v5.py b/app/src/gen3plus/solarman_v5.py index 51eb3a1..0a64764 100644 --- a/app/src/gen3plus/solarman_v5.py +++ b/app/src/gen3plus/solarman_v5.py @@ -208,6 +208,8 @@ class SolarmanV5(Message): self.sug_area = inv['suggested_area'] self.modbus_polling = inv['modbus_polling'] self.sensor_list = inv['sensor_list'] + if self.mb: + self.mb.set_node_id(self.node_id) def __set_serial_no(self, snr: int): '''check the serial number and configure the inverter connection''' diff --git a/app/src/modbus.py b/app/src/modbus.py index 028699d..d186ba7 100644 --- a/app/src/modbus.py +++ b/app/src/modbus.py @@ -117,6 +117,9 @@ class Modbus(): while not self.que.empty(): self.que.get_nowait() + def set_node_id(self, node_id: str): + self.node_id = node_id + def build_msg(self, addr: int, func: int, reg: int, val: int, log_lvl=logging.DEBUG) -> None: """Build MODBUS RTU request frame and add it to the tx queue @@ -160,14 +163,13 @@ class Modbus(): return True - def recv_resp(self, info_db, buf: bytes, node_id: str) -> \ + def recv_resp(self, info_db, buf: bytes) -> \ Generator[tuple[str, bool, int | float | str], None, None]: """Generator which check and parse a received MODBUS response. Keyword arguments: info_db: database for info lockups buf: received Modbus RTU response frame - node_id: string for logging which identifies the slave Returns on error and set Self.err to: 1: CRC error @@ -177,7 +179,6 @@ class Modbus(): 5: No MODBUS request pending """ # logging.info(f'recv_resp: first byte modbus:{buf[0]} len:{len(buf)}') - self.node_id = node_id fcode = buf[1] data_available = self.last_addr == self.INV_ADDR and \ diff --git a/app/tests/test_modbus.py b/app/tests/test_modbus.py index d0e321e..53e735f 100644 --- a/app/tests/test_modbus.py +++ b/app/tests/test_modbus.py @@ -77,9 +77,10 @@ def test_recv_resp_crc_err(): mb.last_fcode = 3 mb.last_reg = 0x300e mb.last_len = 2 + mb.set_node_id('test') # check matching response, but with CRC error call = 0 - for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf3', 'test'): + for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf3'): call += 1 assert mb.err == 1 assert 0 == call @@ -97,10 +98,11 @@ def test_recv_resp_invalid_addr(): mb.last_fcode = 3 mb.last_reg = 0x300e mb.last_len = 2 + mb.set_node_id('test') # check not matching response, with wrong server addr call = 0 - for key, update in mb.recv_resp(mb.db, b'\x02\x03\x04\x01\x2c\x00\x46\x88\xf4', 'test'): + for key, update in mb.recv_resp(mb.db, b'\x02\x03\x04\x01\x2c\x00\x46\x88\xf4'): call += 1 assert mb.err == 2 assert 0 == call @@ -120,7 +122,8 @@ def test_recv_recv_fcode(): # check not matching response, with wrong function code call = 0 - for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4', 'test'): + mb.set_node_id('test') + for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4'): call += 1 assert mb.err == 3 @@ -142,7 +145,8 @@ def test_recv_resp_len(): # check not matching response, with wrong data length call = 0 - for key, update, _ in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4', 'test'): + mb.set_node_id('test') + for key, update, _ in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4'): call += 1 assert mb.err == 4 @@ -161,7 +165,8 @@ def test_recv_unexpect_resp(): # check unexpected response, which must be dropped call = 0 - for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4', 'test'): + mb.set_node_id('test') + for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4'): call += 1 assert mb.err == 5 @@ -177,8 +182,9 @@ def test_parse_resp(): assert mb.req_pend call = 0 + mb.set_node_id('test') 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'): + 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'): if key == 'grid': assert update == True elif key == 'inverter': @@ -226,8 +232,9 @@ def test_queue2(): assert mb.send_calls == 1 assert mb.pdu == b'\x01\x030\x07\x00\x06{\t' call = 0 + mb.set_node_id('test') 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'): + 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'): if key == 'grid': assert update == True elif key == 'inverter': @@ -245,14 +252,14 @@ def test_queue2(): assert mb.send_calls == 2 assert mb.pdu == b'\x01\x06\x20\x08\x00\x04\x02\x0b' - for key, update, val in mb.recv_resp(mb.db, b'\x01\x06\x20\x08\x00\x04\x02\x0b', 'test'): + for key, update, val in mb.recv_resp(mb.db, b'\x01\x06\x20\x08\x00\x04\x02\x0b'): pass # call generator mb.recv_resp() assert mb.que.qsize() == 0 assert mb.send_calls == 3 assert mb.pdu == b'\x01\x030\x07\x00\x06{\t' call = 0 - 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'): + 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'): call += 1 assert 0 == mb.err assert 5 == call @@ -276,8 +283,9 @@ def test_queue3(): assert mb.recv_responses == 0 call = 0 + mb.set_node_id('test') 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'): + 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'): if key == 'grid': assert update == True elif key == 'inverter': @@ -296,7 +304,7 @@ def test_queue3(): assert mb.send_calls == 2 assert mb.pdu == b'\x01\x06\x20\x08\x00\x04\x02\x0b' - for key, update, val in mb.recv_resp(mb.db, b'\x01\x06\x20\x08\x00\x04\x02\x0b', 'test'): + for key, update, val in mb.recv_resp(mb.db, b'\x01\x06\x20\x08\x00\x04\x02\x0b'): pass # no code in loop is OK; calling the generator is the purpose assert 0 == mb.err assert mb.recv_responses == 2 @@ -305,7 +313,7 @@ def test_queue3(): assert mb.send_calls == 3 assert mb.pdu == b'\x01\x030\x07\x00\x06{\t' call = 0 - 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'): + 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'): call += 1 assert 0 == mb.err assert mb.recv_responses == 2 @@ -373,7 +381,8 @@ def test_recv_unknown_data(): # check matching response, but with CRC error call = 0 - for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4', 'test'): + mb.set_node_id('test') + for key, update, val in mb.recv_resp(mb.db, b'\x01\x03\x04\x01\x2c\x00\x46\xbb\xf4'): call += 1 assert mb.err == 0 assert 0 == call