Files
franklinwh-agate-client/franklinwh_agate_client/__init__.py
T
kfj001 9e69f07636 Correct wire format to disassembly: raw S1||crypt(S2), radix 32, int snno/seconds, decryptData response parser, --probe
- envelope: 7 fixed keys + conditional dataArea, no data key; int
  type/snno, seconds timestamp, data setter auto len/crc (CRC32 upper);
  SequenceNumber 1..9999 (increaseSN)
- crypto: encrypt is plaintext-header-first a||transform(b), key radix 32
  at both tryParse sites; decrypt_data ports decryptData (dual-0x58
  markers, s+'}' equipNo probe, s+','+T return); decrypt_request kept
  for the device-side known-header split
- socket: raw send (no length prefix), accumulate-and-try receive
- battery: queryAPowerData shape (data={'update':2}), radix default 32,
  --probe prints exact TX/RX bytes per variant; device_local.send_probe
- docs: RE_DART_FINDINGS ss3/5/8 + open items, BATTERY_POC host recipe
- tests: 19 new protocol tests, suite 44/44 green
2026-10-15 23:01:58 +00:00

55 lines
1.3 KiB
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",
"extract_soc",
"get_battery",
"probe_device",
"SOCKET_PORT_CANDIDATES",
"DEVICE_GATEWAY_IP",
"FALLBACK_PASSWORD",
"VALID_SN_LENGTH",
]
def __getattr__(name: str):
# Lazy so `python -m franklinwh_agate_client.battery` does not import
# the submodule twice (avoids a runpy RuntimeWarning).
if name in {"extract_soc", "get_battery", "probe_device",
"SOCKET_PORT_CANDIDATES"}:
from . import battery as _battery
return getattr(_battery, name)
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")