Per-pack BMS queries (id arg): batSoc source + host_probe7
This commit is contained in:
1 parent
62e0fd649b
commit
3d59a75f14
5 files changed
+223
-13
No files matched your search
@@ -30,7 +30,11 @@ log = logging.getLogger(__name__)
|
||||
SOCKET_PORT_CANDIDATES: Tuple[int, ...] = (9000, 18000)
|
||||
|
||||
#: Reply keys searched for the aggregate percentage, in priority order.
|
||||
SOC_KEYS: Tuple[str, ...] = ("currentBatterySoc", "soc", "batterySoc", "vppSoc")
|
||||
#: ``batSoc`` is the per-pack charge from the BMS socket query
|
||||
#: (``queryBmsInfoBySocket`` passes ``arguments={"id": pack}`` — without
|
||||
#: the pack id the device answers the all-zero ``id: 0`` slot).
|
||||
SOC_KEYS: Tuple[str, ...] = ("currentBatterySoc", "soc", "batSoc",
|
||||
"batterySoc", "vppSoc")
|
||||
|
||||
|
||||
def _as_dict(data: Any) -> Optional[Dict[str, Any]]:
|
||||
@@ -131,12 +135,14 @@ def get_battery(
|
||||
"""Query the aggregate charge percentage over the local TCP socket.
|
||||
|
||||
Mirrors the app's ``queryAPowerData`` first (``DEVICE_APOWER_INFO`` with
|
||||
``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.
|
||||
``data={"opt": 0, "update": 2}``), then per-pack ``BMS`` socket queries
|
||||
(``queryBmsInfoBySocket`` passes the pack ``id`` — ``batSoc`` is the
|
||||
pack charge), then ``EMS`` as a fallback, 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:
|
||||
@@ -150,11 +156,13 @@ def get_battery(
|
||||
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 (
|
||||
attempts: Tuple[Tuple[CommunicationCmd, Any], ...] = (
|
||||
(CommunicationCmd.DEVICE_APOWER_INFO, {"update": 2}),
|
||||
(CommunicationCmd.BMS, None),
|
||||
(CommunicationCmd.BMS, {"id": 1}),
|
||||
(CommunicationCmd.BMS, {"id": 2}),
|
||||
(CommunicationCmd.EMS, None),
|
||||
):
|
||||
)
|
||||
for cmd, data in attempts:
|
||||
try:
|
||||
reply = client.send_rpc(cmd, data=data)
|
||||
except (ConnectionError, socket.error, TimeoutError) as exc:
|
||||
@@ -181,7 +189,8 @@ PROBE_VARIANTS: Tuple[Tuple[str, CommunicationCmd, Any], ...] = (
|
||||
("apower/none", CommunicationCmd.DEVICE_APOWER_INFO, None),
|
||||
("apower/empty", CommunicationCmd.DEVICE_APOWER_INFO, {}),
|
||||
("queryDeviceInfo/none", CommunicationCmd.QUERY_DEVICE_INFO, None),
|
||||
("bms/none", CommunicationCmd.BMS, None),
|
||||
("bms/id1", CommunicationCmd.BMS, {"id": 1}),
|
||||
("bms/id2", CommunicationCmd.BMS, {"id": 2}),
|
||||
("ems/none", CommunicationCmd.EMS, None),
|
||||
)
|
||||
|
||||
|
||||
@@ -285,8 +285,14 @@ class LocalDeviceClient:
|
||||
def query_device_info(self) -> Dict[str, Any]:
|
||||
return self.send_rpc(CommunicationCmd.QUERY_DEVICE_INFO)
|
||||
|
||||
def query_bms_info(self) -> Dict[str, Any]:
|
||||
return self.send_rpc(CommunicationCmd.BMS)
|
||||
def query_bms_info(self, pack_id: int = 1) -> Dict[str, Any]:
|
||||
"""``queryBmsInfoBySocket`` — BMS pack query (``arguments={"id"}``).
|
||||
|
||||
The pack index selects the battery (``BMS_SN`` ``…B1``/``…B2`` in
|
||||
the device-info reply); omitting it yields the all-zero ``id: 0``
|
||||
slot. ``batSoc``/``batSoh`` carry the pack charge/health.
|
||||
"""
|
||||
return self.send_rpc(CommunicationCmd.BMS, data={"id": int(pack_id)})
|
||||
|
||||
def query_mppt_info(self) -> Dict[str, Any]:
|
||||
return self.send_rpc(CommunicationCmd.MPPT)
|
||||
|
||||
Reference in new issue
Block a user