from .protocol import ( make_status_request, make_set_relay, is_status_response, is_relay_response, is_error, ) class CommunicationService: def __init__( self, uart_client, app_state, http_client=None, clock=None, timeout_seconds=5, ): self.uart_client = uart_client self.http_client = http_client self.app_state = app_state self.clock = clock self.timeout_seconds = timeout_seconds self.last_messages = [] self.use_http_fallback = False self.last_status_received_at = None def now(self): if self.clock: return self.clock() try: import time return time.time() except ImportError: return 0 def request_status(self): if self.use_http_fallback and self.http_client: message = self.http_client.get_status() self.handle_message(message) return message self.uart_client.send_message(make_status_request()) return None def set_relay(self, relay, enabled): if self.use_http_fallback and self.http_client: message = self.http_client.set_relay(relay, enabled) self.handle_message(message) return message self.uart_client.send_message(make_set_relay(relay, enabled)) return None def poll(self): messages = self.uart_client.read_available_messages() self.last_messages = messages for message in messages: self.handle_message(message) self.update_connection_state() return messages def update_connection_state(self): if self.last_status_received_at is None: self.app_state.network["uart_connected"] = False return age = self.now() - self.last_status_received_at self.app_state.network["uart_connected"] = age <= self.timeout_seconds def should_use_http_fallback(self): return ( self.http_client is not None and not self.app_state.network.get("uart_connected", False) ) def auto_select_transport(self): self.use_http_fallback = self.should_use_http_fallback() return self.use_http_fallback def enable_http_fallback(self): self.use_http_fallback = True def disable_http_fallback(self): self.use_http_fallback = False def handle_message(self, message): if is_status_response(message): self.last_status_received_at = self.now() self.app_state.update_from_status(message) self.app_state.network["uart_connected"] = True return if is_relay_response(message): self.app_state.update_from_relay_response(message) return if is_error(message): self.app_state.set_error(message) return self.app_state.set_error({ "type": "error", "message": "unknown_message_type", "raw": message, })