def __init__( self, addr_conn: "ModuleConnection", num_tries: int = 3, timeout_msec: int = 1500, ): """Initialize class instance.""" self.addr_conn = addr_conn self.trh = TimeoutRetryHandler(num_tries, timeout_msec) self.trh.set_timeout_callback(self.timeout) # callback addr_conn.register_for_inputs(self.process_input)
class RequestHandler: """Base RequestHandler class.""" def __init__( self, addr_conn: "ModuleConnection", num_tries: int = 3, timeout_msec: int = 1500, ): """Initialize class instance.""" self.addr_conn = addr_conn self.trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout_msec) self.trh.set_timeout_callback(self.timeout) # callback addr_conn.register_for_inputs(self.process_input) @property def task_registry(self) -> TaskRegistry: """Get the task registry.""" return self.addr_conn.task_registry async def request(self) -> Any: """Request information from module.""" raise NotImplementedError() def process_input(self, inp: inputs.Input) -> None: """Create a task to process the input object concurrently.""" self.task_registry.create_task(self.async_process_input(inp)) async def async_process_input(self, inp: inputs.Input) -> None: """Process incoming input object. Method to handle incoming commands for this request handler. """ raise NotImplementedError() async def timeout(self, failed: bool = False) -> None: """Is called on serial request timeout.""" raise NotImplementedError() async def cancel(self) -> None: """Cancel request.""" await self.trh.cancel()
def __init__( self, addr_conn: "ModuleConnection", num_tries: int = 3, timeout_msec: int = 1500, ): """Initialize class instance.""" self._oem_text: List[Optional[str]] = [None] * 4 self.oem_text_known = asyncio.Event() super().__init__(addr_conn, num_tries, timeout_msec) self.trhs = [] for block_id in range(4): trh = TimeoutRetryHandler(self.task_registry, num_tries, timeout_msec) trh.set_timeout_callback(self.timeout, block_id=block_id) self.trhs.append(trh)
def __init__(self, addr_conn: "ModuleConnection"): """Construct StatusRequestHandler instance.""" self.addr_conn = addr_conn self.settings = addr_conn.conn.settings self.last_requested_var_without_type_in_response = lcn_defs.Var.UNKNOWN self.last_var_lock = asyncio.Lock() # Output-port request status (0..3) self.request_status_outputs = [] for output_port in range(4): trh = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"], ) trh.set_timeout_callback(self.request_status_outputs_timeout, output_port) self.request_status_outputs.append(trh) # Relay request status (all 8) self.request_status_relays = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]) self.request_status_relays.set_timeout_callback( self.request_status_relays_timeout) # Binary-sensors request status (all 8) self.request_status_bin_sensors = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]) self.request_status_bin_sensors.set_timeout_callback( self.request_status_bin_sensors_timeout) # Variables request status. # Lazy initialization: Will be filled once the firmware version is # known. self.request_status_vars = {} for var in lcn_defs.Var: if var != lcn_defs.Var.UNKNOWN: self.request_status_vars[var] = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"], ) self.request_status_vars[var].set_timeout_callback( self.request_status_var_timeout, var=var) # LEDs and logic-operations request status (all 12+4). self.request_status_leds_and_logic_ops = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]) self.request_status_leds_and_logic_ops.set_timeout_callback( self.request_status_leds_and_logic_ops_timeout) # Key lock-states request status (all tables, A-D). self.request_status_locked_keys = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]) self.request_status_locked_keys.set_timeout_callback( self.request_status_locked_keys_timeout)
class StatusRequestsHandler: """Manages all status requests for variables, software version, ...""" def __init__(self, addr_conn: "ModuleConnection"): """Construct StatusRequestHandler instance.""" self.addr_conn = addr_conn self.settings = addr_conn.conn.settings self.last_requested_var_without_type_in_response = lcn_defs.Var.UNKNOWN self.last_var_lock = asyncio.Lock() # Output-port request status (0..3) self.request_status_outputs = [] for output_port in range(4): trh = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"], ) trh.set_timeout_callback(self.request_status_outputs_timeout, output_port) self.request_status_outputs.append(trh) # Relay request status (all 8) self.request_status_relays = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]) self.request_status_relays.set_timeout_callback( self.request_status_relays_timeout) # Binary-sensors request status (all 8) self.request_status_bin_sensors = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"]) self.request_status_bin_sensors.set_timeout_callback( self.request_status_bin_sensors_timeout) # Variables request status. # Lazy initialization: Will be filled once the firmware version is # known. self.request_status_vars = {} for var in lcn_defs.Var: if var != lcn_defs.Var.UNKNOWN: self.request_status_vars[var] = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"], ) self.request_status_vars[var].set_timeout_callback( self.request_status_var_timeout, var=var) # LEDs and logic-operations request status (all 12+4). self.request_status_leds_and_logic_ops = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]) self.request_status_leds_and_logic_ops.set_timeout_callback( self.request_status_leds_and_logic_ops_timeout) # Key lock-states request status (all tables, A-D). self.request_status_locked_keys = TimeoutRetryHandler( self.task_registry, -1, self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"]) self.request_status_locked_keys.set_timeout_callback( self.request_status_locked_keys_timeout) @property def task_registry(self) -> TaskRegistry: """Get the task registry.""" return self.addr_conn.task_registry def preprocess_modstatusvar(self, inp: inputs.ModStatusVar) -> inputs.Input: """Fill typeless response with last requested variable type.""" if inp.orig_var == lcn_defs.Var.UNKNOWN: # Response without type (%Msssaaa.wwwww) inp.var = self.last_requested_var_without_type_in_response self.last_requested_var_without_type_in_response = lcn_defs.Var.UNKNOWN if self.last_var_lock.locked(): self.last_var_lock.release() else: # Response with variable type (%Msssaaa.Avvvwww) inp.var = inp.orig_var return inp async def request_status_outputs_timeout(self, failed: bool = False, output_port: int = 0) -> None: """Is called on output status request timeout.""" if not failed: await self.addr_conn.send_command( False, PckGenerator.request_output_status(output_port)) async def request_status_relays_timeout(self, failed: bool = False) -> None: """Is called on relay status request timeout.""" if not failed: await self.addr_conn.send_command( False, PckGenerator.request_relays_status()) async def request_status_bin_sensors_timeout(self, failed: bool = False) -> None: """Is called on binary sensor status request timeout.""" if not failed: await self.addr_conn.send_command( False, PckGenerator.request_bin_sensors_status()) async def request_status_var_timeout( self, failed: bool = False, var: Optional[lcn_defs.Var] = None) -> None: """Is called on variable status request timeout.""" assert var is not None # Detect if we can send immediately or if we have to wait for a # "typeless" response first has_type_in_response = lcn_defs.Var.has_type_in_response( var, self.addr_conn.software_serial) if not has_type_in_response: # Use the chance to remove a failed "typeless variable" request try: await asyncio.wait_for(self.last_var_lock.acquire(), timeout=3.0) except asyncio.TimeoutError: pass self.last_requested_var_without_type_in_response = var # Send variable request await self.addr_conn.send_command( False, PckGenerator.request_var_status(var, self.addr_conn.software_serial), ) async def request_status_leds_and_logic_ops_timeout( self, failed: bool = False) -> None: """Is called on leds/logical ops status request timeout.""" if not failed: await self.addr_conn.send_command( False, PckGenerator.request_leds_and_logic_ops()) async def request_status_locked_keys_timeout(self, failed: bool = False) -> None: """Is called on locked keys status request timeout.""" if not failed: await self.addr_conn.send_command( False, PckGenerator.request_key_lock_status()) async def activate(self, item: Any) -> None: """Activate status requests for given item.""" await self.addr_conn.conn.segment_scan_completed_event.wait() # handle variables independently if (item in lcn_defs.Var) and (item != lcn_defs.Var.UNKNOWN): # wait until we know the software version await self.addr_conn.serial_known if self.addr_conn.software_serial >= 0x170206: timeout_msec = self.settings[ "MAX_STATUS_EVENTBASED_VALUEAGE_MSEC"] else: timeout_msec = self.settings["MAX_STATUS_POLLED_VALUEAGE_MSEC"] self.request_status_vars[item].set_timeout_msec(timeout_msec) self.request_status_vars[item].activate() elif item in lcn_defs.OutputPort: self.request_status_outputs[item.value].activate() elif item in lcn_defs.RelayPort: self.request_status_relays.activate() elif item in lcn_defs.MotorPort: self.request_status_relays.activate() elif item in lcn_defs.BinSensorPort: self.request_status_bin_sensors.activate() elif item in lcn_defs.LedPort: self.request_status_leds_and_logic_ops.activate() elif item in lcn_defs.Key: self.request_status_locked_keys.activate() async def cancel(self, item: Any) -> None: """Cancel status request for given item.""" # handle variables independently if (item in lcn_defs.Var) and (item != lcn_defs.Var.UNKNOWN): await self.request_status_vars[item].cancel() self.last_requested_var_without_type_in_response = lcn_defs.Var.UNKNOWN elif item in lcn_defs.OutputPort: await self.request_status_outputs[item.value].cancel() elif item in lcn_defs.RelayPort: await self.request_status_relays.cancel() elif item in lcn_defs.MotorPort: await self.request_status_relays.cancel() elif item in lcn_defs.BinSensorPort: await self.request_status_bin_sensors.cancel() elif item in lcn_defs.LedPort: await self.request_status_leds_and_logic_ops.cancel() elif item in lcn_defs.Key: await self.request_status_locked_keys.cancel() async def activate_all(self, activate_s0: bool = False) -> None: """Activate all status requests.""" await self.addr_conn.conn.segment_scan_completed_event.wait() for item in (list(lcn_defs.OutputPort) + list(lcn_defs.RelayPort) + list(lcn_defs.BinSensorPort) + list(lcn_defs.LedPort) + list(lcn_defs.Key) + list(lcn_defs.Var)): if isinstance(item, lcn_defs.Var) and item == lcn_defs.Var.UNKNOWN: continue if ((not activate_s0) and isinstance(item, lcn_defs.Var) and (item in lcn_defs.Var.s0s) # type: ignore ): continue await self.activate(item) async def cancel_all(self) -> None: """Cancel all status requests.""" for item in (list(lcn_defs.OutputPort) + list(lcn_defs.RelayPort) + list(lcn_defs.BinSensorPort) + list(lcn_defs.LedPort) + list(lcn_defs.Key) + list(lcn_defs.Var)): if isinstance(item, lcn_defs.Var) and item == lcn_defs.Var.UNKNOWN: continue await self.cancel(item)