Skip to content

Commit 1beefb3

Browse files
author
NOisi-X
committed
refactor(zeo): return None from the Zeo settings setters
The settings setters are fire-and-forget — send_decoded_command() only publishes the payload — so returning the internal DPS frame implies a confirmation the device never sends. Drop the return value from the 34 public setters (set_*/save_*/load_*) and the _send/_set_enum/_set_bool helpers; they now return None. start_with/preset_with/start_with_custom_mode keep returning the frame: they take an arbitrary parameter combination and the frame also carries DPs the method adds on its own (auto-dosing 211/212, feature-gated 255/258), which the caller cannot derive from the arguments. Addresses the review feedback on #897.
1 parent 9004bcc commit 1beefb3

1 file changed

Lines changed: 74 additions & 74 deletions

File tree

‎roborock/devices/traits/a01/settings.py‎

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,11 @@ def auto_softener(self) -> bool | None:
182182
return self.softener_type is not None and self.softener_type != ZeoSoftenerType.empty
183183
return self.softener_set
184184

185-
async def _set_enum(self, dp: RoborockZeoProtocol, enum_cls: type[_T], value: _T) -> dict[RoborockZeoProtocol, Any]:
185+
async def _set_enum(self, dp: RoborockZeoProtocol, enum_cls: type[_T], value: _T) -> None:
186186
"""Validate *value* against *enum_cls* and send it to the device."""
187187
if not isinstance(value, enum_cls):
188188
raise TypeError(f"Expected {enum_cls.__name__}, got {type(value).__name__}")
189-
return await self._send({dp: int(value)})
189+
await self._send({dp: int(value)})
190190

191191
# -- Start-parameter setters (TEST-ONLY) --------------------------------
192192
#
@@ -201,51 +201,51 @@ async def _set_enum(self, dp: RoborockZeoProtocol, enum_cls: type[_T], value: _T
201201
#
202202
# They are retained purely as a test/debug convenience.
203203

204-
async def set_mode(self, mode: ZeoMode) -> dict[RoborockZeoProtocol, Any]:
204+
async def set_mode(self, mode: ZeoMode) -> None:
205205
"""Set the current mode (DP 204). Test-only: carried by START."""
206-
return await self._set_enum(RoborockZeoProtocol.MODE, ZeoMode, mode)
206+
await self._set_enum(RoborockZeoProtocol.MODE, ZeoMode, mode)
207207

208-
async def set_program(self, program: ZeoProgram) -> dict[RoborockZeoProtocol, Any]:
208+
async def set_program(self, program: ZeoProgram) -> None:
209209
"""Set the current programme (DP 205). Test-only: carried by START."""
210-
return await self._set_enum(RoborockZeoProtocol.PROGRAM, ZeoProgram, program)
210+
await self._set_enum(RoborockZeoProtocol.PROGRAM, ZeoProgram, program)
211211

212212
# -- Washer-specific setters --------------------------------------------
213213

214-
async def set_temperature(self, temperature: ZeoTemperature) -> dict[RoborockZeoProtocol, Any]:
214+
async def set_temperature(self, temperature: ZeoTemperature) -> None:
215215
"""Set the wash temperature (DP 207). Test-only: carried by START."""
216-
return await self._set_enum(RoborockZeoProtocol.TEMP, ZeoTemperature, temperature)
216+
await self._set_enum(RoborockZeoProtocol.TEMP, ZeoTemperature, temperature)
217217

218-
async def set_rinse(self, rinse: ZeoRinse) -> dict[RoborockZeoProtocol, Any]:
218+
async def set_rinse(self, rinse: ZeoRinse) -> None:
219219
"""Set the rinse count (DP 208). Test-only: carried by START."""
220-
return await self._set_enum(RoborockZeoProtocol.RINSE_TIMES, ZeoRinse, rinse)
220+
await self._set_enum(RoborockZeoProtocol.RINSE_TIMES, ZeoRinse, rinse)
221221

222-
async def set_spin(self, spin: ZeoSpin) -> dict[RoborockZeoProtocol, Any]:
222+
async def set_spin(self, spin: ZeoSpin) -> None:
223223
"""Set the spin speed (DP 209). Test-only: carried by START."""
224-
return await self._set_enum(RoborockZeoProtocol.SPIN_LEVEL, ZeoSpin, spin)
224+
await self._set_enum(RoborockZeoProtocol.SPIN_LEVEL, ZeoSpin, spin)
225225

226-
async def set_drying_mode(self, drying_mode: ZeoDryingMode) -> dict[RoborockZeoProtocol, Any]:
226+
async def set_drying_mode(self, drying_mode: ZeoDryingMode) -> None:
227227
"""Set the drying mode (DP 210). Test-only: carried by START."""
228-
return await self._set_enum(RoborockZeoProtocol.DRYING_MODE, ZeoDryingMode, drying_mode)
228+
await self._set_enum(RoborockZeoProtocol.DRYING_MODE, ZeoDryingMode, drying_mode)
229229

230-
async def set_soak(self, soak: ZeoSoak) -> dict[RoborockZeoProtocol, Any]:
230+
async def set_soak(self, soak: ZeoSoak) -> None:
231231
"""Set the soak level (DP 233). Test-only: carried by START."""
232-
return await self._set_enum(RoborockZeoProtocol.SOAK, ZeoSoak, soak)
232+
await self._set_enum(RoborockZeoProtocol.SOAK, ZeoSoak, soak)
233233

234-
async def set_dry_and_care(self, dry_and_care: ZeoDryAndCare) -> dict[RoborockZeoProtocol, Any]:
234+
async def set_dry_and_care(self, dry_and_care: ZeoDryAndCare) -> None:
235235
"""Set the dry-and-care mode (DP 244). Test-only: carried by START."""
236-
return await self._set_enum(RoborockZeoProtocol.DRY_CARE_MODE, ZeoDryAndCare, dry_and_care)
236+
await self._set_enum(RoborockZeoProtocol.DRY_CARE_MODE, ZeoDryAndCare, dry_and_care)
237237

238238
# -- Dryer-specific setters ---------------------------------------------
239239

240-
async def set_drying_method(self, drying_method: ZeoDryingMethod) -> dict[RoborockZeoProtocol, Any]:
240+
async def set_drying_method(self, drying_method: ZeoDryingMethod) -> None:
241241
"""Set the drying method (DP 256). Test-only: carried by START."""
242-
return await self._set_enum(RoborockZeoProtocol.DRYING_METHOD, ZeoDryingMethod, drying_method)
242+
await self._set_enum(RoborockZeoProtocol.DRYING_METHOD, ZeoDryingMethod, drying_method)
243243

244-
async def set_steam_volume(self, steam_volume: ZeoSteamVolume) -> dict[RoborockZeoProtocol, Any]:
244+
async def set_steam_volume(self, steam_volume: ZeoSteamVolume) -> None:
245245
"""Set the steam volume (DP 257). Test-only: carried by START."""
246-
return await self._set_enum(RoborockZeoProtocol.STEAM_VOLUME, ZeoSteamVolume, steam_volume)
246+
await self._set_enum(RoborockZeoProtocol.STEAM_VOLUME, ZeoSteamVolume, steam_volume)
247247

248-
async def set_detergent_type(self, detergent_type: ZeoDetergentType) -> dict[RoborockZeoProtocol, Any]:
248+
async def set_detergent_type(self, detergent_type: ZeoDetergentType) -> None:
249249
"""Set the detergent type (DP 213), optionally toggling auto-dosing."""
250250
e = int(detergent_type)
251251
dps: dict[RoborockZeoProtocol, Any]
@@ -264,9 +264,9 @@ async def set_detergent_type(self, detergent_type: ZeoDetergentType) -> dict[Rob
264264
RoborockZeoProtocol.DETERGENT_SET: 0 if e == 0 else 1,
265265
RoborockZeoProtocol.DETERGENT_TYPE: e,
266266
}
267-
return await self._send(dps)
267+
await self._send(dps)
268268

269-
async def set_softener_type(self, softener_type: ZeoSoftenerType) -> dict[RoborockZeoProtocol, Any]:
269+
async def set_softener_type(self, softener_type: ZeoSoftenerType) -> None:
270270
"""Set the softener type (DP 214)."""
271271
e = int(softener_type)
272272
dps: dict[RoborockZeoProtocol, Any]
@@ -285,60 +285,60 @@ async def set_softener_type(self, softener_type: ZeoSoftenerType) -> dict[Roboro
285285
RoborockZeoProtocol.SOFTENER_SET: 0 if e == 0 else 1,
286286
RoborockZeoProtocol.SOFTENER_TYPE: e,
287287
}
288-
return await self._send(dps)
288+
await self._send(dps)
289289

290-
async def set_detergent_box_type(self, expansion_type: ZeoDetergentExpansionType) -> dict[RoborockZeoProtocol, Any]:
290+
async def set_detergent_box_type(self, expansion_type: ZeoDetergentExpansionType) -> None:
291291
"""Set the detergent expansion type (DP 248)."""
292292
dps = {RoborockZeoProtocol.DETERGENT_EXPANSION_TYPE: int(expansion_type)}
293-
return await self._send(dps)
293+
await self._send(dps)
294294

295-
async def set_softener_box_type(self, expansion_type: ZeoSoftenerExpansionType) -> dict[RoborockZeoProtocol, Any]:
295+
async def set_softener_box_type(self, expansion_type: ZeoSoftenerExpansionType) -> None:
296296
"""Set the softener expansion type (DP 245)."""
297297
dps = {RoborockZeoProtocol.SOFTENER_EXPANSION_TYPE: int(expansion_type)}
298-
return await self._send(dps)
298+
await self._send(dps)
299299

300300
async def set_cleanser_config(
301301
self,
302302
auto_detergent: bool,
303303
auto_softener: bool,
304304
detergent_type: ZeoDetergentType,
305305
softener_type: ZeoSoftenerType,
306-
) -> dict[RoborockZeoProtocol, Any]:
306+
) -> None:
307307
"""Set the full cleanser config in one command (DP 211/212/213/214)."""
308308
dps: dict[RoborockZeoProtocol, Any] = {
309309
RoborockZeoProtocol.DETERGENT_SET: 1 if auto_detergent else 0,
310310
RoborockZeoProtocol.SOFTENER_SET: 1 if auto_softener else 0,
311311
RoborockZeoProtocol.DETERGENT_TYPE: int(detergent_type),
312312
RoborockZeoProtocol.SOFTENER_TYPE: int(softener_type),
313313
}
314-
return await self._send(dps)
314+
await self._send(dps)
315315

316-
async def set_voice_volume(self, volume: int) -> dict[RoborockZeoProtocol, Any]:
316+
async def set_voice_volume(self, volume: int) -> None:
317317
"""Set the voice volume (DP 10009)."""
318318
dps = {RoborockZeoProtocol.VOICE_VOLUME: json.dumps({"snd_volume": volume})}
319-
return await self._send(dps)
319+
await self._send(dps)
320320

321-
async def set_voice_switch(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
321+
async def set_voice_switch(self, enabled: bool) -> None:
322322
"""Enable/disable voice assistant (DP 10301)."""
323323
dps = {RoborockZeoProtocol.VOICE_SWITCH: json.dumps({"speech_switch": 1 if enabled else 0})}
324-
return await self._send(dps)
324+
await self._send(dps)
325325

326-
async def delete_voice_record(self, record_id: str) -> dict[RoborockZeoProtocol, Any]:
326+
async def delete_voice_record(self, record_id: str) -> None:
327327
"""Delete a voice record by id (DP 10304)."""
328328
dps = {RoborockZeoProtocol.VOICE_RECORD_DELETE: json.dumps({"dialog_delete": record_id})}
329-
return await self._send(dps)
329+
await self._send(dps)
330330

331-
async def set_sound_package(self, package: dict[str, Any]) -> dict[RoborockZeoProtocol, Any]:
331+
async def set_sound_package(self, package: dict[str, Any]) -> None:
332332
"""Set the sound package (DP 10003)."""
333333
dps = {RoborockZeoProtocol.SET_SOUND_PACKAGE: json.dumps(package)}
334-
return await self._send(dps)
334+
await self._send(dps)
335335

336336
async def set_silent_mode(
337337
self,
338338
enabled: bool,
339339
start_time: datetime.time,
340340
end_time: datetime.time,
341-
) -> dict[RoborockZeoProtocol, Any]:
341+
) -> None:
342342
"""Enable or disable silent mode with the given quiet hours.
343343
344344
The three DPs (240/241/242) must be sent together.
@@ -354,7 +354,7 @@ async def set_silent_mode(
354354
RoborockZeoProtocol.SILENT_MODE_START_TIME: start_time.hour * 60 + start_time.minute,
355355
RoborockZeoProtocol.SILENT_MODE_END_TIME: end_time.hour * 60 + end_time.minute,
356356
}
357-
return await self._send(dps)
357+
await self._send(dps)
358358

359359
# -- Plain boolean switch setters ---------------------------------------
360360
#
@@ -364,110 +364,110 @@ async def set_silent_mode(
364364
# corresponding feature bit (or series whitelist); gated setters raise
365365
# :class:`ValueError` when the device does not support the feature.
366366

367-
async def _set_bool(self, dp: RoborockZeoProtocol, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
367+
async def _set_bool(self, dp: RoborockZeoProtocol, enabled: bool) -> None:
368368
"""Send a boolean DP as its integer ``1``/``0`` (confirmed wire format)."""
369-
return await self._send({dp: 1 if enabled else 0})
369+
await self._send({dp: 1 if enabled else 0})
370370

371-
async def set_child_lock(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
371+
async def set_child_lock(self, enabled: bool) -> None:
372372
"""Enable/disable the child lock (DP 206)."""
373-
return await self._set_bool(RoborockZeoProtocol.CHILD_LOCK, enabled)
373+
await self._set_bool(RoborockZeoProtocol.CHILD_LOCK, enabled)
374374

375-
async def set_sound(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
375+
async def set_sound(self, enabled: bool) -> None:
376376
"""Enable/disable the audible beeper (DP 223)."""
377-
return await self._set_bool(RoborockZeoProtocol.SOUND_SET, enabled)
377+
await self._set_bool(RoborockZeoProtocol.SOUND_SET, enabled)
378378

379-
async def set_dirt_detection(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
379+
async def set_dirt_detection(self, enabled: bool) -> None:
380380
"""Enable/disable dirt detection (DP 215).
381381
382382
Requires the ``dirt_detection`` feature bit.
383383
"""
384384
features = self._features()
385385
if features is not None and not features.dirt_detection:
386386
raise ValueError("This device does not support dirt detection")
387-
return await self._set_bool(RoborockZeoProtocol.DIRT_DETECTION_SWITCH, enabled)
387+
await self._set_bool(RoborockZeoProtocol.DIRT_DETECTION_SWITCH, enabled)
388388

389-
async def set_default_setting(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
389+
async def set_default_setting(self, enabled: bool) -> None:
390390
"""Set the default setting (DP 225)."""
391-
return await self._set_bool(RoborockZeoProtocol.DEFAULT_SETTING, enabled)
391+
await self._set_bool(RoborockZeoProtocol.DEFAULT_SETTING, enabled)
392392

393-
async def set_uv_light(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
393+
async def set_uv_light(self, enabled: bool) -> None:
394394
"""Enable/disable the UV light (DP 228).
395395
396396
Requires UV-light support for the device series.
397397
"""
398398
if not supports_uv_light(self._model):
399399
raise ValueError("This device does not support UV light")
400-
return await self._set_bool(RoborockZeoProtocol.UV_LIGHT, enabled)
400+
await self._set_bool(RoborockZeoProtocol.UV_LIGHT, enabled)
401401

402-
async def set_smart_hosting(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
402+
async def set_smart_hosting(self, enabled: bool) -> None:
403403
"""Enable/disable smart hosting (DP 235).
404404
405405
Requires the ``smart_hosting`` feature bit.
406406
"""
407407
features = self._features()
408408
if features is not None and not features.smart_hosting:
409409
raise ValueError("This device does not support smart hosting")
410-
return await self._set_bool(RoborockZeoProtocol.SMART_HOSTING, enabled)
410+
await self._set_bool(RoborockZeoProtocol.SMART_HOSTING, enabled)
411411

412-
async def set_smile_light(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
412+
async def set_smile_light(self, enabled: bool) -> None:
413413
"""Enable/disable the smile light (DP 247).
414414
415415
Requires the ``smile_light`` feature bit.
416416
"""
417417
features = self._features()
418418
if features is not None and not features.smile_light:
419419
raise ValueError("This device does not support smile light")
420-
return await self._set_bool(RoborockZeoProtocol.SMILE_LIGHT_STATUS, enabled)
420+
await self._set_bool(RoborockZeoProtocol.SMILE_LIGHT_STATUS, enabled)
421421

422-
async def set_fluff_cleaned(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
422+
async def set_fluff_cleaned(self, enabled: bool) -> None:
423423
"""Mark the fluff filter as cleaned (DP 249).
424424
425425
Requires the ``fluff_clean_notification`` feature bit.
426426
"""
427427
features = self._features()
428428
if features is not None and not features.fluff_clean_notification:
429429
raise ValueError("This device does not support fluff cleaning")
430-
return await self._set_bool(RoborockZeoProtocol.FLUFF_CLEANED, enabled)
430+
await self._set_bool(RoborockZeoProtocol.FLUFF_CLEANED, enabled)
431431

432-
async def set_power_light(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
432+
async def set_power_light(self, enabled: bool) -> None:
433433
"""Enable/disable the power-button indicator light (DP 251).
434434
435435
Requires the ``power_button_indicator_light`` feature bit.
436436
"""
437437
features = self._features()
438438
if features is not None and not features.power_button_indicator_light:
439439
raise ValueError("This device does not support the power indicator light")
440-
return await self._set_bool(RoborockZeoProtocol.POWER_LIGHT, enabled)
440+
await self._set_bool(RoborockZeoProtocol.POWER_LIGHT, enabled)
441441

442-
async def set_ion_deodorization(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
442+
async def set_ion_deodorization(self, enabled: bool) -> None:
443443
"""Enable/disable ion deodorization (DP 258). Test-only: carried by START.
444444
445445
Requires the ``ion_deodorization`` feature bit.
446446
"""
447447
features = self._features()
448448
if features is not None and not features.ion_deodorization:
449449
raise ValueError("This device does not support ion deodorization")
450-
return await self._set_bool(RoborockZeoProtocol.ION_DEODORIZATION, enabled)
450+
await self._set_bool(RoborockZeoProtocol.ION_DEODORIZATION, enabled)
451451

452-
async def set_wash_dry_linked(self, enabled: bool) -> dict[RoborockZeoProtocol, Any]:
452+
async def set_wash_dry_linked(self, enabled: bool) -> None:
453453
"""Enable/disable the wash-dry linkage (DP 255). Test-only: carried by START.
454454
455455
Requires the ``wash_dry_linkage`` feature bit.
456456
"""
457457
features = self._features()
458458
if features is not None and not features.wash_dry_linkage:
459459
raise ValueError("This device does not support wash-dry linkage")
460-
return await self._set_bool(RoborockZeoProtocol.WASH_DRY_LINKED, enabled)
460+
await self._set_bool(RoborockZeoProtocol.WASH_DRY_LINKED, enabled)
461461

462462
async def _send(
463463
self,
464464
dps: dict[RoborockZeoProtocol, Any],
465465
qos: MqttQos = MqttQos.AT_MOST_ONCE,
466-
) -> dict[RoborockZeoProtocol, Any]:
466+
) -> None:
467467
"""Send already wire-formatted DPs over the device channel."""
468-
return await send_decoded_command(self._channel, dps, value_encoder=lambda x: x, qos=qos)
468+
await send_decoded_command(self._channel, dps, value_encoder=lambda x: x, qos=qos)
469469

470-
async def save_cloud_program(self, params: ZeoStartParams) -> dict[RoborockZeoProtocol, Any]:
470+
async def save_cloud_program(self, params: ZeoStartParams) -> None:
471471
"""Save the current programme parameters as a cloud custom program.
472472
473473
Sends Mode/Program (and the optional Soak/Temperature/Rinse/Spin/
@@ -482,24 +482,24 @@ async def save_cloud_program(self, params: ZeoStartParams) -> dict[RoborockZeoPr
482482
dps[RoborockZeoProtocol.SAVE_ADAPTED_CLOUD_PROGRAM] = 1
483483
else:
484484
dps[RoborockZeoProtocol.CUSTOM_PARAM_SAVE] = 1
485-
return await self._send(dps, MqttQos.AT_LEAST_ONCE)
485+
await self._send(dps, MqttQos.AT_LEAST_ONCE)
486486

487-
async def save_panel_program(self, params: ZeoStartParams) -> dict[RoborockZeoProtocol, Any]:
487+
async def save_panel_program(self, params: ZeoStartParams) -> None:
488488
"""Save the current programme parameters as a panel program (DP 252).
489489
490490
Same parameter set as :meth:`save_cloud_program`, but the trigger
491491
signal is ``PanelProgramParamsSet``(252) instead.
492492
"""
493493
dps = build_param_dps(params)
494494
dps[RoborockZeoProtocol.PANEL_PROGRAM_PARAMS_SET] = 1
495-
return await self._send(dps, MqttQos.AT_LEAST_ONCE)
495+
await self._send(dps, MqttQos.AT_LEAST_ONCE)
496496

497-
async def load_cloud_program(self) -> dict[RoborockZeoProtocol, Any]:
497+
async def load_cloud_program(self) -> None:
498498
"""Apply the currently saved cloud custom program (DP 222 = 1).
499499
500500
This only sends the trigger signal ``CUSTOM_PARAM_GET``(222) with an
501501
integer ``1``. The device responds by pushing the current program's
502502
32-bit bitfield back on DP 222 (see ``ZeoCustomMode.from_raw``).
503503
"""
504504
dps: dict[RoborockZeoProtocol, Any] = {RoborockZeoProtocol.CUSTOM_PARAM_GET: 1}
505-
return await self._send(dps, MqttQos.AT_LEAST_ONCE)
505+
await self._send(dps, MqttQos.AT_LEAST_ONCE)

0 commit comments

Comments
 (0)