From 7d0ea41728a077ce78eb8401b4208deb00895155 Mon Sep 17 00:00:00 2001 From: Stefan Allius Date: Thu, 17 Oct 2024 23:20:13 +0200 Subject: [PATCH] reduce code duplications --- app/src/gen3/talent.py | 30 +++----------------------- app/src/gen3plus/solarman_v5.py | 32 ++------------------------- app/src/messages.py | 38 +++++++++++++++++++++++++++++---- app/tests/test_async_stream.py | 9 +++++--- 4 files changed, 45 insertions(+), 64 deletions(-) diff --git a/app/src/gen3/talent.py b/app/src/gen3/talent.py index a0af3cd..57f875c 100644 --- a/app/src/gen3/talent.py +++ b/app/src/gen3/talent.py @@ -8,7 +8,6 @@ if __name__ == "app.src.gen3.talent": from app.src.async_ifc import AsyncIfc from app.src.messages import Message, State from app.src.modbus import Modbus - from app.src.my_timer import Timer from app.src.config import Config from app.src.gen3.infos_g3 import InfosG3 from app.src.infos import Register @@ -16,7 +15,6 @@ else: # pragma: no cover from async_ifc import AsyncIfc from messages import Message, State from modbus import Modbus - from my_timer import Timer from config import Config from gen3.infos_g3 import InfosG3 from infos import Register @@ -42,19 +40,18 @@ class Control: class Talent(Message): - MB_START_TIMEOUT = 40 - MB_REGULAR_TIMEOUT = 60 TXT_UNKNOWN_CTRL = 'Unknown Ctrl' def __init__(self, addr, ifc: "AsyncIfc", server_side: bool, client_mode: bool = False, id_str=b''): - super().__init__(server_side, self.send_modbus_cb, mb_timeout=15) + super().__init__('G3', ifc, server_side, self.send_modbus_cb, + mb_timeout=15) ifc.rx_set_cb(self.read) ifc.prot_set_timeout_cb(self._timeout) ifc.prot_set_init_new_client_conn_cb(self._init_new_client_conn) ifc.prot_set_update_header_cb(self._update_header) + self.addr = addr - self.ifc = ifc self.conn_no = ifc.get_conn_no() self.await_conn_resp_cnt = 0 self.id_str = id_str @@ -86,38 +83,17 @@ class Talent(Message): 0x87: self.get_modbus_log_lvl, 0x04: logging.INFO, } - self.modbus_elms = 0 # for unit tests - self.node_id = 'G3' # will be overwritten in __set_serial_no - self.mb_timer = Timer(self.mb_timout_cb, self.node_id) - self.mb_timeout = self.MB_REGULAR_TIMEOUT - self.mb_first_timeout = self.MB_START_TIMEOUT - self.modbus_polling = False ''' Our puplic methods ''' def close(self) -> None: logging.debug('Talent.close()') - if self.server_side: - # set inverter state to offline, if output power is very low - logging.debug('close power: ' - f'{self.db.get_db_value(Register.OUTPUT_POWER, -1)}') - if self.db.get_db_value(Register.OUTPUT_POWER, 999) < 2: - self.db.set_db_def_value(Register.INVERTER_STATUS, 0) - self.new_data['env'] = True - # we have references to methods of this class in self.switch # so we have to erase self.switch, otherwise this instance can't be # deallocated by the garbage collector ==> we get a memory leak self.switch.clear() self.log_lvl.clear() - self.state = State.closed - self.mb_timer.close() - self.ifc.rx_set_cb(None) - self.ifc.prot_set_timeout_cb(None) - self.ifc.prot_set_init_new_client_conn_cb(None) - self.ifc.prot_set_update_header_cb(None) - self.ifc = None super().close() def __set_serial_no(self, serial_no: str): diff --git a/app/src/gen3plus/solarman_v5.py b/app/src/gen3plus/solarman_v5.py index bae555c..191dcf9 100644 --- a/app/src/gen3plus/solarman_v5.py +++ b/app/src/gen3plus/solarman_v5.py @@ -8,7 +8,6 @@ if __name__ == "app.src.gen3plus.solarman_v5": from app.src.async_ifc import AsyncIfc from app.src.messages import hex_dump_memory, Message, State from app.src.modbus import Modbus - from app.src.my_timer import Timer from app.src.config import Config from app.src.gen3plus.infos_g3p import InfosG3P from app.src.infos import Register @@ -17,7 +16,6 @@ else: # pragma: no cover from messages import hex_dump_memory, Message, State from config import Config from modbus import Modbus - from my_timer import Timer from gen3plus.infos_g3p import InfosG3P from infos import Register @@ -53,10 +51,6 @@ class Sequence(): class SolarmanV5(Message): AT_CMD = 1 MB_RTU_CMD = 2 - MB_START_TIMEOUT = 40 - '''start delay for Modbus polling in server mode''' - MB_REGULAR_TIMEOUT = 60 - '''regular Modbus polling time in server mode''' MB_CLIENT_DATA_UP = 30 '''Data up time in client mode''' HDR_FMT = ' None: logging.debug('Solarman.close()') - if self.server_side: - # set inverter state to offline, if output power is very low - logging.debug('close power: ' - f'{self.db.get_db_value(Register.OUTPUT_POWER, -1)}') - if self.db.get_db_value(Register.OUTPUT_POWER, 999) < 2: - self.db.set_db_def_value(Register.INVERTER_STATUS, 0) - self.new_data['env'] = True - # we have references to methods of this class in self.switch # so we have to erase self.switch, otherwise this instance can't be # deallocated by the garbage collector ==> we get a memory leak self.switch.clear() self.log_lvl.clear() - self.state = State.closed - self.mb_timer.close() - self.ifc.rx_set_cb(None) - self.ifc.prot_set_timeout_cb(None) - self.ifc.prot_set_init_new_client_conn_cb(None) - self.ifc.prot_set_update_header_cb(None) - self.ifc = None super().close() async def send_start_cmd(self, snr: int, host: str, diff --git a/app/src/messages.py b/app/src/messages.py index ccb8f3d..7b691f2 100644 --- a/app/src/messages.py +++ b/app/src/messages.py @@ -5,13 +5,17 @@ from enum import Enum if __name__ == "app.src.messages": + from app.src.async_ifc import AsyncIfc from app.src.protocol_ifc import ProtocolIfc from app.src.infos import Infos, Register from app.src.modbus import Modbus + from app.src.my_timer import Timer else: # pragma: no cover + from async_ifc import AsyncIfc from protocol_ifc import ProtocolIfc from infos import Infos, Register from modbus import Modbus + from my_timer import Timer logger = logging.getLogger('msg') @@ -89,9 +93,14 @@ class Message(ProtocolIfc): '''maximum time without a received msg from the inverter in sec''' MAX_DEF_IDLE_TIME = 360 '''maximum default time without a received msg in sec''' + MB_START_TIMEOUT = 40 + '''start delay for Modbus polling in server mode''' + MB_REGULAR_TIMEOUT = 60 + '''regular Modbus polling time in server mode''' - def __init__(self, server_side: bool, send_modbus_cb: - Callable[[bytes, int, str], None], mb_timeout: int): + def __init__(self, node_id, ifc: "AsyncIfc", server_side: bool, + send_modbus_cb: Callable[[bytes, int, str], None], + mb_timeout: int): self._registry.append(weakref.ref(self)) self.server_side = server_side @@ -99,16 +108,22 @@ class Message(ProtocolIfc): self.mb = Modbus(send_modbus_cb, mb_timeout) else: self.mb = None - + self.ifc = ifc + self.node_id = node_id self.header_valid = False self.header_len = 0 self.data_len = 0 self.unique_id = 0 - self._node_id = '' self.sug_area = '' self.new_data = {} self.state = State.init self.shutdown_started = False + self.modbus_elms = 0 # for unit tests + self.mb_timer = Timer(self.mb_timout_cb, self.node_id) + self.mb_timeout = self.MB_REGULAR_TIMEOUT + self.mb_first_timeout = self.MB_START_TIMEOUT + '''timer value for next Modbus polling request''' + self.modbus_polling = False @property def node_id(self): @@ -166,6 +181,21 @@ class Message(ProtocolIfc): Our puplic methods ''' def close(self) -> None: + if self.server_side: + # set inverter state to offline, if output power is very low + logging.debug('close power: ' + f'{self.db.get_db_value(Register.OUTPUT_POWER, -1)}') + if self.db.get_db_value(Register.OUTPUT_POWER, 999) < 2: + self.db.set_db_def_value(Register.INVERTER_STATUS, 0) + self.new_data['env'] = True + self.state = State.closed + self.mb_timer.close() + self.ifc.rx_set_cb(None) + self.ifc.prot_set_timeout_cb(None) + self.ifc.prot_set_init_new_client_conn_cb(None) + self.ifc.prot_set_update_header_cb(None) + self.ifc = None + if self.mb: self.mb.close() self.mb = None diff --git a/app/tests/test_async_stream.py b/app/tests/test_async_stream.py index d7dcf12..d1d5911 100644 --- a/app/tests/test_async_stream.py +++ b/app/tests/test_async_stream.py @@ -17,10 +17,13 @@ pytest_plugins = ('pytest_asyncio',) Infos.static_init() class FakeProto(Message): - def __init__(self, server_side): - super().__init__(server_side, None, 10) + def __init__(self, ifc, server_side): + super().__init__('G3F', ifc, server_side, None, 10) self.conn_no = 0 + def mb_timout_cb(self, exp_cnt): + pass # empty callback + def fake_reader_fwd(): reader = FakeReader() reader.test = FakeReader.RD_TEST_13_BYTES @@ -349,7 +352,7 @@ def create_remote(remote, test_type, with_close_hdr:bool = False): FakeReader(), FakeWriter(), StreamPtr(None), close_hndl) remote.ifc.prot_set_update_header_cb(update_hdr) remote.ifc.prot_set_init_new_client_conn_cb(callback) - remote.stream = FakeProto(False) + remote.stream = FakeProto(remote.ifc, False) @pytest.mark.asyncio async def test_forward():