From 6b34ebccc767f33d060ed40b5c46ebb4ee34ca2f Mon Sep 17 00:00:00 2001 From: Aditya Mehra Date: Fri, 27 May 2022 18:12:21 +0930 Subject: [PATCH] Adapt and port to wifi plugin --- ovos_PHAL_plugin_balena_wifi/__init__.py | 197 +++++++++++------------ 1 file changed, 91 insertions(+), 106 deletions(-) diff --git a/ovos_PHAL_plugin_balena_wifi/__init__.py b/ovos_PHAL_plugin_balena_wifi/__init__.py index 0a0f64d..8f80c0d 100644 --- a/ovos_PHAL_plugin_balena_wifi/__init__.py +++ b/ovos_PHAL_plugin_balena_wifi/__init__.py @@ -1,102 +1,98 @@ -from os.path import join, dirname +import random +from os.path import dirname, join +from time import sleep import pexpect -import random -import subprocess from mycroft_bus_client.message import Message, dig_for_message from ovos_plugin_manager.phal import PHALPlugin -from ovos_utils import create_daemon -from ovos_utils.enclosure.api import EnclosureAPI from ovos_utils.gui import GUIInterface from ovos_utils.log import LOG -from ovos_utils.network_utils import is_connected -from time import sleep class BalenaWifiSetupPlugin(PHALPlugin): def __init__(self, bus=None, config=None): super().__init__(bus=bus, name="ovos-PHAL-plugin-balena-wifi", config=config) - self.monitoring = False + self.gui = GUIInterface(bus=self.bus, skill_id=self.name) + self.client_active = False + self.client_id = None + self.registered = False self.in_setup = False - self.connected = False + self.wifi_process = None - self.debug = False # dev setting, VERY VERBOSE DIALOGS + self.debug = True # dev setting, VERY VERBOSE DIALOGS self.ssid = "OVOS" self.pswd = None - self.grace_period = 45 - self.time_between_checks = 30 # seconds - self.mycroft_ready = False self.wifi_command = "sudo /usr/local/sbin/wifi-connect --portal-ssid {ssid}" if self.pswd: self.wifi_command += " --portal-passphrase {pswd}" self.color = "#FF0000" - self.stop_on_internet = False - self.timeout_after_internet = 90 - - self.bus.on("mycroft.internet.connected", self.handle_internet_connected) - - self.enclosure = EnclosureAPI(bus=self.bus, skill_id=self.name) - self.gui = GUIInterface(bus=self.bus, skill_id=self.name) - self.start_internet_check() - - # internet watchdog - def start_internet_check(self): - create_daemon(self._watchdog) - - def stop_internet_check(self): - self.monitoring = False - - def _watchdog(self): - try: - self.monitoring = True - LOG.info("Wifi watchdog started") - output = subprocess.check_output("nmcli connection show", - shell=True).decode("utf-8") - if "wifi" in output: - LOG.info("Detected previously configured wifi, starting " - "grace period to allow it to connect") - sleep(self.grace_period) - while self.monitoring: - if self.in_setup: - sleep(1) # let setup do it's thing - continue - - if not is_connected(): - LOG.info("NO INTERNET") - if not self.is_connected_to_wifi(): - LOG.info("LAUNCH SETUP") - try: - self.launch_wifi_setup() # blocking - except Exception as e: - LOG.exception(e) - else: - LOG.warning("CONNECTED TO WIFI, BUT NO INTERNET!!") - - sleep(self.time_between_checks) - except Exception as e: - LOG.error("Wifi watchdog crashed unexpectedly") - LOG.exception(e) - - # wifi setup - @staticmethod - def get_wifi_ssid(): - SSID = None - try: - SSID = subprocess.check_output(["iwgetid", "-r"]).strip() - except subprocess.CalledProcessError: - # If there is no connection subprocess throws a 'CalledProcessError' - pass - return SSID - - @staticmethod - def is_connected_to_wifi(): - return BalenaWifiSetupPlugin.get_wifi_ssid() is not None - - def launch_wifi_setup(self): - if not self.in_setup: - self.bus.emit(Message("ovos.wifi.setup.started")) - self.stop_setup() + + # WIFI Plugin Registeration and Activation Specific Events + self.bus.on("ovos.phal.wifi.plugin.stop.setup.event", self.handle_stop_setup) + self.bus.on("ovos.phal.wifi.plugin.client.registered", self.handle_registered) + self.bus.on("ovos.phal.wifi.plugin.client.deregistered", self.handle_deregistered) + self.bus.on("ovos.phal.wifi.plugin.client.registration.failure", self.handle_registration_failure) + + # Try Register the Client with WIFI Plugin on Startup + self.register_client() + + # Wifi Plugin Registeration Handling + def register_client(self): + self.bus.emit(Message("ovos.phal.wifi.plugin.register.client", { + "client": self.name, + "type": "Remote", + "display_text": "On Mobile Setup", + "has_gui": True, + "requires_input": False + })) + + def handle_registered(self, message=None): + get_client = message.data.get("client", "") + if get_client == self.name: + get_id = message.data.get("id", "") + self.client_id = get_id + self.registered = True + self.bus.on(f"ovos.phal.wifi.plugin.activate.{self.client_id}", self.handle_activate_client_request) + self.bus.on(f"ovos.phal.wifi.plugin.deactivate.{self.client_id}", self.handle_deactivate_client_request) + LOG.info(f"Client Registered with WIFI Plugin: {self.client_id}") + + def handle_deregistered(self, message=None): + self.registered = False + self.bus.remove(f"ovos.phal.wifi.plugin.activate.{self.client_id}", self.handle_active_client_request) + self.bus.remove(f"ovos.phal.wifi.plugin.deactivate.{self.client_id}", self.handle_deactivate_client_request) + self.client_id = None + + def handle_registration_failure(self, message=None): + if not self.registered: + error = message.data.get("error", "") + LOG.info(f"Registration Failure: {error}") + # Try to Register the Client with WIFI Plugin Again + self.register_client() + + def handle_activate_client_request(self, message=None): + LOG.info("Balena Wifi Plugin Activated") + self.client_active = True + self.display_network_setup() + + def handle_deactivate_client_request(self, message=None): + LOG.info("Balena Wifi Plugin Deactivated") + self.cleanup_wifi_process() + self.client_active = False + self.gui.release() + + def request_deactivate(self, message=None): + self.bus.emit(Message("ovos.phal.wifi.plugin.remove.active.client", { + "client": "ovos-PHAL-plugin-balena-wifi"})) + LOG.info("Balena Wifi Plugin Deactivation Requested") + + def display_network_setup(self): + LOG.info("Balena Wifi In Network Setup") + if self.in_setup: + # Always start with a clean slate + self.cleanup_wifi_process() + self.in_setup = True + self.wifi_process = pexpect.spawn( self.wifi_command.format(ssid=self.ssid) ) @@ -180,24 +176,16 @@ def launch_wifi_setup(self): except Exception as e: LOG.exception(e) break - self.stop_setup() + self.handle_stop_setup() + if restart: # handle bugs in balena, sometimes it fails to come back up # seems to happen on # Error: Getting access points failed - self.launch_wifi_setup() + self.display_network_setup() elif self.debug: self.speak_dialog("debug_end_setup") - # bus events - def handle_internet_connected(self, message=None): - """System came online later after booting.""" - self.enclosure.mouth_reset() - # sync clock as soon as we have internet - self.bus.emit(Message("system.ntp.sync")) - self.stop_setup() # just in case - self.gui.release() - # GUI events def prompt_to_join_ap(self, message=None): """Provide instructions for setting up wifi.""" @@ -215,18 +203,11 @@ def prompt_to_select_network(self, message=None): def report_setup_complete(self, message=None): """Wifi setup complete, network is connected.""" - # once first connected to internet increase time between checks - self.connected = True - self.time_between_checks = self.timeout_after_internet - # stop watchdog on internet connection - if self.stop_on_internet: - self.monitoring = False self.manage_setup_display("setup-completed", "status") # allow GUI to linger around for a bit, will block the wifi setup loop sleep(5) - self.bus.emit(Message("ovos.wifi.setup.completed")) - # pairing skill should take over now - self.gui.release() + self.client_active = False + self.request_deactivate() def report_setup_failed(self, message=None): """Wifi setup failed""" @@ -234,6 +215,8 @@ def report_setup_failed(self, message=None): self.speak_dialog("debug_wifi_error") # allow GUI to linger around for a bit, will block the wifi setup loop sleep(2) + self.in_setup = False + self.display_network_setup() def manage_setup_display(self, state, page_type): self.gui.clear() @@ -268,7 +251,8 @@ def manage_setup_display(self, state, page_type): self.gui.show_page(page, override_animations=True) # cleanup - def stop_setup(self): + def cleanup_wifi_process(self): + self.in_setup = False if self.wifi_process is not None: try: if self.wifi_process.isalive(): @@ -289,13 +273,14 @@ def stop_setup(self): LOG.debug('wifi setup exited gracefully.') except Exception as e: LOG.exception(e) - self.wifi_process = None - self.in_setup = False - + else: + return + + def handle_stop_setup(self, message=None): + self.request_deactivate() + def shutdown(self): - self.monitoring = False - self.bus.remove("mycroft.internet.connected", self.handle_internet_connected) - self.stop_setup() + self.handle_stop_setup() super().shutdown() # speech