Radix 16 (live-verified), universal reply splitter, golden capture vectors, host_probe6
This commit is contained in:
1 parent
0cd6b34a2e
commit
62e0fd649b
10 files changed
+418
-82
No files matched your search
@@ -125,16 +125,18 @@ def get_battery(
|
||||
sn: str,
|
||||
host: str = "10.100.1.1",
|
||||
ports: Tuple[int, ...] = SOCKET_PORT_CANDIDATES,
|
||||
key_radix: int = 32,
|
||||
key_radix: int = 16,
|
||||
timeout: float = 5.0,
|
||||
) -> Dict[str, Any]:
|
||||
"""Query the aggregate charge percentage over the local TCP socket.
|
||||
|
||||
Mirrors the app's ``queryAPowerData`` first (``DEVICE_APOWER_INFO`` with
|
||||
``data={"update": 2}``), then ``BMS`` and ``EMS`` as fallbacks, probing
|
||||
each candidate port. Returns the ``extract_soc`` dict plus
|
||||
``cmd``/``port``/``reply`` context. Raises the last socket error if no
|
||||
port answers.
|
||||
``data={"opt": 0, "update": 2}``), then ``BMS`` and ``EMS`` as fallbacks,
|
||||
probing each candidate port. Like the app's direct-connect flow, a
|
||||
discovery query (``QUERY_DEVICE_INFO``, empty serial) opens each port's
|
||||
sequence — its reply also confirms two-way crypto before the battery
|
||||
read. Returns the ``extract_soc`` dict plus ``cmd``/``port``/``reply``
|
||||
context. Raises the last socket error if no port answers.
|
||||
"""
|
||||
last_err: Optional[Exception] = None
|
||||
for port in ports:
|
||||
@@ -142,6 +144,12 @@ def get_battery(
|
||||
sn=sn, host=host, socket_port=port,
|
||||
key_radix=key_radix, timeout=timeout,
|
||||
)
|
||||
try:
|
||||
client.send_rpc(CommunicationCmd.QUERY_DEVICE_INFO,
|
||||
equip_no="",
|
||||
data={"minProtocolVer": "V1.00.00"})
|
||||
except Exception as exc: # discovery is best-effort; keep going
|
||||
log.debug("port %d discovery failed: %s", port, exc)
|
||||
for cmd, data in (
|
||||
(CommunicationCmd.DEVICE_APOWER_INFO, {"update": 2}),
|
||||
(CommunicationCmd.BMS, None),
|
||||
@@ -182,7 +190,7 @@ def probe_device(
|
||||
sn: str,
|
||||
host: str = "10.100.1.1",
|
||||
ports: Tuple[int, ...] = SOCKET_PORT_CANDIDATES,
|
||||
key_radix: int = 32,
|
||||
key_radix: int = 16,
|
||||
timeout: float = 5.0,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Send every :data:`PROBE_VARIANTS` envelope; return exact TX/RX bytes."""
|
||||
@@ -251,7 +259,7 @@ def probe_transport(
|
||||
sn: str,
|
||||
host: str = "10.100.1.1",
|
||||
ports: Tuple[int, ...] = (9000,),
|
||||
key_radix: int = 32,
|
||||
key_radix: int = 16,
|
||||
timeout: float = 5.0,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Transport-level probes against one service port.
|
||||
@@ -323,7 +331,7 @@ def main(argv: Optional[List[str]] = None) -> int:
|
||||
"--ports", default=",".join(map(str, SOCKET_PORT_CANDIDATES)),
|
||||
help="comma-separated socket ports to probe",
|
||||
)
|
||||
parser.add_argument("--key-radix", type=int, default=32, choices=(16, 32))
|
||||
parser.add_argument("--key-radix", type=int, default=16, choices=(16, 32))
|
||||
parser.add_argument("--timeout", type=float, default=5.0)
|
||||
parser.add_argument("--show-hotspot", action="store_true",
|
||||
help="print derived AP SSID/password and exit")
|
||||
|
||||
Reference in new issue
Block a user