|
| 1 | +# connectivity.py — Universal ConnectivityManager for MicroPythonOS |
| 2 | +# Works on ESP32, ESP8266, Unix/Desktop, and anything else |
| 3 | + |
| 4 | +import sys |
| 5 | +import time |
| 6 | +import requests |
| 7 | +import usocket |
| 8 | +from machine import Timer |
| 9 | + |
| 10 | +try: |
| 11 | + import network |
| 12 | + HAS_NETWORK_MODULE = True |
| 13 | +except ImportError: |
| 14 | + HAS_NETWORK_MODULE = False |
| 15 | + |
| 16 | +class ConnectivityManager: |
| 17 | + _instance = None |
| 18 | + |
| 19 | + def __init__(self): |
| 20 | + #print("connectivity_manager.py init") |
| 21 | + if ConnectivityManager._instance: |
| 22 | + return |
| 23 | + ConnectivityManager._instance = self |
| 24 | + |
| 25 | + self.can_check_network = HAS_NETWORK_MODULE |
| 26 | + |
| 27 | + if self.can_check_network: |
| 28 | + self.wlan = network.WLAN(network.STA_IF) |
| 29 | + else: |
| 30 | + self.wlan = None |
| 31 | + |
| 32 | + self.is_connected = False # Local network (Wi-Fi/AP) connected |
| 33 | + self._is_online = False # Real internet reachability |
| 34 | + self.callbacks = [] |
| 35 | + |
| 36 | + if not self.can_check_network: |
| 37 | + self.is_connected = True # If there's no way to check, then assume we're always "connected" and online |
| 38 | + |
| 39 | + # Start periodic validation timer (only on real embedded targets) |
| 40 | + self._check_timer = Timer(1) # 0 is already taken by task_handler.py |
| 41 | + self._check_timer.init(period=8000, mode=Timer.PERIODIC, callback=self._periodic_check_connected) |
| 42 | + |
| 43 | + self._periodic_check_connected(notify=False) |
| 44 | + #print("init done") |
| 45 | + |
| 46 | + @classmethod |
| 47 | + def get(cls): |
| 48 | + if cls._instance is None: |
| 49 | + cls._instance = cls() |
| 50 | + #print("returning...") |
| 51 | + return cls._instance |
| 52 | + |
| 53 | + def register_callback(self, callback): |
| 54 | + if callback not in self.callbacks: |
| 55 | + self.callbacks.append(callback) |
| 56 | + |
| 57 | + def unregister_callback(self, callback): |
| 58 | + self.callbacks = [cb for cb in self.callbacks if cb != callback] |
| 59 | + |
| 60 | + def _notify(self, now_online): |
| 61 | + for cb in self.callbacks: |
| 62 | + try: |
| 63 | + cb(now_online) |
| 64 | + except Exception as e: |
| 65 | + print("[Connectivity] Callback error:", e) |
| 66 | + |
| 67 | + def _periodic_check_connected(self, notify=True): |
| 68 | + #print("_periodic_check_connected") |
| 69 | + was_online = self._is_online |
| 70 | + if not self.can_check_network: |
| 71 | + self._is_online = True |
| 72 | + else: |
| 73 | + if self.wlan.isconnected(): |
| 74 | + self._is_online = True |
| 75 | + else: |
| 76 | + self._is_online = False |
| 77 | + |
| 78 | + if self._is_online != was_online: |
| 79 | + status = "ONLINE" if self._is_online else "OFFLINE" |
| 80 | + print(f"[Connectivity] Internet => {status}") |
| 81 | + if notify: |
| 82 | + self._notify(self._is_online) |
| 83 | + |
| 84 | + # === Public Android-like API === |
| 85 | + def is_online(self): |
| 86 | + return self._is_online |
| 87 | + |
| 88 | + def is_wifi_connected(self): |
| 89 | + return self.is_connected |
| 90 | + |
| 91 | + def wait_until_online(self, timeout=60): |
| 92 | + if not self.can_check_network: |
| 93 | + return True |
| 94 | + start = time.time() |
| 95 | + while time.time() - start < timeout: |
| 96 | + if self.is_online: |
| 97 | + return True |
| 98 | + time.sleep(1) |
| 99 | + return False |
0 commit comments