wifi.py presented itself as a join/leave abstraction but provided no real
behavior: the default backend was a no-op, the facade never verified the
association, and the nmcli queries were wrong. This makes the module do what
it claims, verified end-to-end against the recovered protocol and nmcli 1.52.
wifi.py
- WifiManager: join now verifies the association by polling
backend.is_connected against a settle_timeout (fail-closed). An
unverified join raises HotspotJoinError and leaves connected=False;
verify=False restores fire-and-forget. Tracks last_profile and adds
gateway_ip().
- NmcliWifiBackend: the association check now uses the ACTIVE column
(`device wifi list -f SSID,ACTIVE`). The old `device wifi show` was a
prefix-match accident onto `show-password` and reported in-range APs, not
the associated one. get_ip() queries per-Wi-Fi-interface IP4.ADDRESS
(preferring the 10.100 aGate subnet) instead of the unfiltered all-device
dump that would return a wired/VPN address. Signal is read from the active
AP; the dead ipcmd param is removed; leave() is best-effort.
- WifiBackend: documented the fail-closed contract and added get_signal()
so the manager no longer reaches into a private _run via isinstance.
- NoOpWifiBackend: added assume_connected() for manual/external joins.
client.py
- AgateClient now owns a WifiManager and exposes join_hotspot(),
leave_hotspot(), and attach_local() (join + verify + LocalDeviceClient
aimed at the device gateway). LocalDeviceClient is imported lazily so the
package still works without `requests`.
__init__.py
- Export the backends, HotspotProfile, HotspotJoinError, the SN-derivation
helper, and the module constants.
tests/test_wifi.py (new)
- 20 stdlib-unittest cases: SN derivation, verify pass/fail, fail-closed
behavior, the in-range-but-not-associated regression, IP preference,
tolerant leave, and the client wiring. No radio or pytest required.
Also:
- README: documented the local-connect (device hotspot) flow.
- .gitignore: ignore Python build/cache artifacts.
40 lines
856 B
Python
40 lines
856 B
Python
"""
|
|
FranklinWH AGATE Device Client
|
|
|
|
Reverse engineered from com.Franklinwh.FamilyEnergy Android app.
|
|
Provides access to Bluetooth and Wi-Fi network I/O stack for AGATE devices.
|
|
"""
|
|
|
|
from .client import AgateClient
|
|
from .bluetooth import BluetoothManager
|
|
from .wifi import (
|
|
DEVICE_GATEWAY_IP,
|
|
FALLBACK_PASSWORD,
|
|
VALID_SN_LENGTH,
|
|
HotspotJoinError,
|
|
HotspotProfile,
|
|
NoOpWifiBackend,
|
|
NmcliWifiBackend,
|
|
WifiBackend,
|
|
WifiManager,
|
|
derive_hotspot_credentials,
|
|
)
|
|
from .api import ApiClient
|
|
|
|
__version__ = "0.1.0"
|
|
__all__ = [
|
|
"AgateClient",
|
|
"BluetoothManager",
|
|
"ApiClient",
|
|
"WifiManager",
|
|
"WifiBackend",
|
|
"NmcliWifiBackend",
|
|
"NoOpWifiBackend",
|
|
"HotspotProfile",
|
|
"HotspotJoinError",
|
|
"derive_hotspot_credentials",
|
|
"DEVICE_GATEWAY_IP",
|
|
"FALLBACK_PASSWORD",
|
|
"VALID_SN_LENGTH",
|
|
]
|