Skip to content

Commit 31db44f

Browse files
author
NOisi-X
committed
fix(zeo): use elif for zeo start, narrow timeout exception, add FEATURE_BITS skip list
device.py: if self.zeo → elif self.zeo (reviewer consistency request) _discover_features: except RoborockException → except RoborockTimeout Discovered via Bundle analysis: a63 (H1) and a90 (H1 Lite) don't support DP 237 — skip query entirely for these models. query_values: remove cache write-back (deferred to PR4)
1 parent fa44017 commit 31db44f

2 files changed

Lines changed: 17 additions & 16 deletions

File tree

roborock/devices/device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ async def connect(self) -> None:
202202
await self.v1_properties.start()
203203
elif self.b01_q10_properties is not None:
204204
await self.b01_q10_properties.start()
205-
if self.zeo is not None:
205+
elif self.zeo is not None:
206206
await self.zeo.start()
207207
except RoborockException:
208208
# Expected: start() can fail transiently. Unsubscribe before propagating

roborock/devices/traits/a01/__init__.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
from roborock.devices.traits import Trait
5555
from roborock.devices.traits.common import TraitUpdateListener
5656
from roborock.devices.transport.mqtt_channel import MqttChannel
57-
from roborock.exceptions import RoborockException
57+
from roborock.exceptions import RoborockException, RoborockTimeout
5858
from roborock.protocols.a01_protocol import decode_rpc_response
5959
from roborock.roborock_message import (
6060
RoborockDyadDataProtocol,
@@ -104,6 +104,12 @@
104104
RoborockDyadDataProtocol.PRODUCT_INFO: lambda val: DyadProductInfo.from_dict(val),
105105
}
106106

107+
# Devices known to lack FEATURE_BITS (DP 237).
108+
_UNSUPPORTED_FEATURE_BITS: frozenset[str] = frozenset({
109+
"roborock.wm.a63", # H1
110+
"roborock.wm.a90", # H1 Lite
111+
})
112+
107113
ZEO_PROTOCOL_ENTRIES: dict[RoborockZeoProtocol, Callable] = {
108114
# read-only
109115
RoborockZeoProtocol.STATE: lambda val: ZeoState(val).name,
@@ -173,13 +179,14 @@ class ZeoApi(Trait, TraitUpdateListener):
173179

174180
name = "zeo"
175181

176-
def __init__(self, channel: MqttChannel) -> None:
182+
def __init__(self, channel: MqttChannel, product_id: str | None = None) -> None:
177183
"""Initialize the Zeo API."""
178184
TraitUpdateListener.__init__(self, _LOGGER)
179185
self._channel = channel
180186
self._dps_cache: dict[int, Any] = {}
181187
self._dps_unsub: Callable[[], None] | None = None
182188
self._feature_bits: int = 0
189+
self._product_id = product_id
183190

184191
async def start(self) -> None:
185192
"""Subscribe to MQTT push and discover device features.
@@ -205,20 +212,17 @@ async def _ensure_subscribed(self) -> None:
205212
async def _discover_features(self) -> None:
206213
"""Query FEATURE_BITS to wake the device and cache capabilities.
207214
208-
Sending an RPC query after subscribing triggers the device to
209-
start pushing its full state — equivalent to how V1's
210-
``discover_features()`` uses ``device_features.refresh()`` to
211-
initiate the push cycle.
212-
213215
Only devices that support the FeatureBits DP will respond;
214-
older or unsupported devices return nothing.
215-
A failed query defaults to 0 — all feature-gated DPs are
216-
disabled and the device operates in basic mode.
216+
For devices known to lack this DP
217+
the query is skipped entirely; for all other devices a
218+
timeout propagates as a connection error.
217219
"""
220+
if self._product_id in _UNSUPPORTED_FEATURE_BITS:
221+
return
218222
try:
219223
result = await self.query_values([RoborockZeoProtocol.FEATURE_BITS])
220224
self._feature_bits = result.get(RoborockZeoProtocol.FEATURE_BITS, 0)
221-
except RoborockException:
225+
except RoborockTimeout:
222226
self._feature_bits = 0
223227

224228
def supports(self, feature: ZeoFeatureBits) -> bool:
@@ -250,9 +254,6 @@ async def query_values(self, protocols: list[RoborockZeoProtocol]) -> dict[Robor
250254
{RoborockZeoProtocol.ID_QUERY: protocols},
251255
value_encoder=json.dumps,
252256
)
253-
for protocol, value in response.items():
254-
if value is not None:
255-
self._dps_cache[int(protocol)] = value
256257
return {protocol: convert_zeo_value(protocol, response.get(protocol)) for protocol in protocols}
257258

258259
async def set_value(self, protocol: RoborockZeoProtocol, value: Any) -> dict[RoborockZeoProtocol, Any]:
@@ -267,6 +268,6 @@ def create(product: HomeDataProduct, mqtt_channel: MqttChannel) -> DyadApi | Zeo
267268
case RoborockCategory.WET_DRY_VAC:
268269
return DyadApi(mqtt_channel)
269270
case RoborockCategory.WASHING_MACHINE:
270-
return ZeoApi(mqtt_channel)
271+
return ZeoApi(mqtt_channel, product_id=product.id)
271272
case _:
272273
raise NotImplementedError(f"Unsupported category {product.category}")

0 commit comments

Comments
 (0)