From 480f85b6231c3b765a04451cee4e95d3fa163046 Mon Sep 17 00:00:00 2001 From: kratochvil Date: Tue, 15 Oct 2024 17:16:33 +0200 Subject: [PATCH 1/3] Disabled initializing modbus cache before switch to async mode --- evok/modbus_slave.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/evok/modbus_slave.py b/evok/modbus_slave.py index 72dd1ce..63db751 100644 --- a/evok/modbus_slave.py +++ b/evok/modbus_slave.py @@ -178,7 +178,7 @@ def get(self): def switch_to_async(self, loop: IOLoop): self.loop = loop - loop.add_callback(lambda: self.readboards()) + self.readboards() async def set(self, print_log=None): if print_log is not None and print_log != 0: @@ -187,7 +187,7 @@ async def set(self, print_log=None): else: return "" - async def readboards(self): + def readboards(self): logger.info(f"Initial reading the Modbus board on Modbus address {self.modbus_address}\t({self.circuit})") self.boards = list() try: @@ -195,7 +195,7 @@ async def readboards(self): raise KeyError(f"readboards: Unsupported device model {self.device_model}! (check HW definitions)") self.hw_board_dict = self.hw_dict.definitions[self.device_model] board = Board(self.evok_config, self.circuit, self.modbus_address, self) - await board.parse_definition(self.hw_dict) + board.parse_definition(self.hw_dict) self.boards.append(board) except ConnectionException as E: logger.error(f"No board detected on Modbus {self.modbus_address}\t({type(E).__name__}:{E})") @@ -508,11 +508,10 @@ def parse_feature(self, m_feature): else: logging.warning("Unknown feature: " + str(m_feature['type']) + " at board: " + str(self.major_group)) - async def parse_definition(self, hw_dict): + def parse_definition(self, hw_dict): try: for defin_name, defin in hw_dict.definitions.items(): if defin and (self.modbus_slave.device_model == defin_name): - await self.initialise_cache(defin) for m_feature in defin['modbus_features']: self.parse_feature(m_feature) return From 844582821678a0fadb1aad05239ee0e18933b11c Mon Sep 17 00:00:00 2001 From: kratochvil Date: Wed, 16 Oct 2024 17:30:48 +0200 Subject: [PATCH 2/3] Add initialization modbus map automatically in first packet. --- evok/modbus_slave.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/evok/modbus_slave.py b/evok/modbus_slave.py index 63db751..6ab0e95 100644 --- a/evok/modbus_slave.py +++ b/evok/modbus_slave.py @@ -105,16 +105,17 @@ async def do_scan(self, slave=0, initial=False) -> bool: m_reg_group['values'] = vals.registers # call force update callbacks in registered devices and check differences - for device in self.modbus_slave.eventable_devices: - try: - if await device.check_new_data() is True: - changeset.append(device) - except Exception as E: - m = (f"Error while checking new data in device '{device.devtype}" - f"_{device.circuit}': {E}") - logger.error(m) - if logger.level == logging.DEBUG: - traceback.print_exc() + if not initial: + for device in self.modbus_slave.eventable_devices: + try: + if await device.check_new_data() is True: + changeset.append(device) + except Exception as E: + m = (f"Error while checking new data in device '{device.devtype}" + f"_{device.circuit}': {E}") + logger.error(m) + if logger.level == logging.DEBUG: + traceback.print_exc() # reset communication flags self.last_comm_time = time.time() @@ -164,6 +165,7 @@ def __init__(self, client: Union[EvokModbusTcpClient, EvokModbusSerialClient], self.circuit: Union[None, str] = circuit self.modbus_type = 'UNKNOWN' self.modbus_spec = 'UNKNOWN' + self._initialized = False if type(self.client) in [EvokModbusTcpClient]: self.client: EvokModbusTcpClient self.modbus_type = 'TCP' @@ -188,7 +190,7 @@ async def set(self, print_log=None): return "" def readboards(self): - logger.info(f"Initial reading the Modbus board on Modbus address {self.modbus_address}\t({self.circuit})") + logger.info(f"Initialing Modbus board on Modbus address {self.modbus_address}\t({self.circuit})") self.boards = list() try: if self.device_model not in self.hw_dict.definitions: @@ -220,10 +222,11 @@ async def scan_boards(self, invoc=False): return try: if self.modbus_cache_map is not None: - if await self.modbus_cache_map.do_scan(slave=self.modbus_address) is True: + if await self.modbus_cache_map.do_scan(slave=self.modbus_address, initial=not self._initialized) is True: if self.scan_errors: logger.info(f"Communication with device is back: '{self.circuit}'") self.scan_errors = 0 + self._initialized = True except Exception as E: if not self.scan_errors: logger.error(f"{self.circuit}: Error while scanning: {E}") @@ -295,16 +298,10 @@ async def set(self, alias=None): Devices.set_alias(alias, self) return await self.full() - async def initialise_cache(self, cache_definition): + def initialise_cache(self, cache_definition): if 'modbus_register_blocks' in cache_definition: if self.modbus_slave.modbus_cache_map is None: self.modbus_slave.modbus_cache_map = ModbusCacheMap(cache_definition['modbus_register_blocks'], self.modbus_slave) - await self.modbus_slave.modbus_cache_map.do_scan(initial=True, slave=self.modbus_address) - await self.modbus_slave.modbus_cache_map.sem.acquire() - self.modbus_slave.modbus_cache_map.sem.release() - else: - await self.modbus_slave.modbus_cache_map.sem.acquire() - self.modbus_slave.modbus_cache_map.sem.release() else: raise Exception("HW Definition %s requires Modbus register blocks to be specified" % cache_definition['type']) @@ -513,6 +510,7 @@ def parse_definition(self, hw_dict): for defin_name, defin in hw_dict.definitions.items(): if defin and (self.modbus_slave.device_model == defin_name): for m_feature in defin['modbus_features']: + self.initialise_cache(defin) self.parse_feature(m_feature) return logging.error(f"Not found type '{self.modbus_slave.device_model}' in loaded hw-definitions.") From 445ff9d95a1233a67829b13ec1bc56fbb7d54891 Mon Sep 17 00:00:00 2001 From: kratochvil Date: Thu, 17 Oct 2024 15:08:28 +0200 Subject: [PATCH 3/3] Move initialization check to modbus cache map. --- evok/modbus_slave.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/evok/modbus_slave.py b/evok/modbus_slave.py index 6ab0e95..a86cade 100644 --- a/evok/modbus_slave.py +++ b/evok/modbus_slave.py @@ -39,10 +39,11 @@ def __init__(self, modbus_reg_map, modbus_slave): self.modbus_slave: ModbusSlave = modbus_slave self.sem = Semaphore(1) self.frequency = {} - self.initial_read = True + self._initialized = False for m_reg_group in self.modbus_reg_map: self.frequency[m_reg_group['start_reg']] = 10000001 # frequency less than 1/10 million are not read on start m_reg_group['values'] = [None for i in range(m_reg_group['count'])] + m_reg_group['initialised'] = False def __get_reg_group(self, index: int, is_input: bool): group = None @@ -81,8 +82,8 @@ async def get_register_async(self, count, index, slave=0, is_input=False): group[group_index + i] = val.registers[i] return val.registers - async def do_scan(self, slave=0, initial=False) -> bool: - if initial: + async def do_scan(self, slave=0) -> bool: + if not self._initialized: await self.sem.acquire() changeset = [] @@ -105,7 +106,7 @@ async def do_scan(self, slave=0, initial=False) -> bool: m_reg_group['values'] = vals.registers # call force update callbacks in registered devices and check differences - if not initial: + if self._initialized: for device in self.modbus_slave.eventable_devices: try: if await device.check_new_data() is True: @@ -116,6 +117,8 @@ async def do_scan(self, slave=0, initial=False) -> bool: logger.error(m) if logger.level == logging.DEBUG: traceback.print_exc() + else: + m_reg_group['initialised'] = True # reset communication flags self.last_comm_time = time.time() @@ -128,7 +131,8 @@ async def do_scan(self, slave=0, initial=False) -> bool: proxy = Proxy(set(changeset)) # print(f"changeset: {changeset}") devents.status(proxy) - if initial: + if not self._initialized: + self._initialized = all([m['initialised'] for m in self.modbus_reg_map]) self.sem.release() return scanned @@ -165,7 +169,6 @@ def __init__(self, client: Union[EvokModbusTcpClient, EvokModbusSerialClient], self.circuit: Union[None, str] = circuit self.modbus_type = 'UNKNOWN' self.modbus_spec = 'UNKNOWN' - self._initialized = False if type(self.client) in [EvokModbusTcpClient]: self.client: EvokModbusTcpClient self.modbus_type = 'TCP' @@ -222,11 +225,10 @@ async def scan_boards(self, invoc=False): return try: if self.modbus_cache_map is not None: - if await self.modbus_cache_map.do_scan(slave=self.modbus_address, initial=not self._initialized) is True: + if await self.modbus_cache_map.do_scan(slave=self.modbus_address) is True: if self.scan_errors: logger.info(f"Communication with device is back: '{self.circuit}'") self.scan_errors = 0 - self._initialized = True except Exception as E: if not self.scan_errors: logger.error(f"{self.circuit}: Error while scanning: {E}")