Integration overhaul: modernization, robustness, event-loop hygiene, 66% coverage#28
Conversation
|
Warning Review limit reached
Next review available in: 41 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (94)
📝 WalkthroughWalkthroughThis PR overhauls the dreame_vacuum integration: entity services move to a dedicated services.py registered from async_setup; the options flow modernizes to OptionsFlowWithReload with HA selectors; camera rendering offloads to executor threads; the map optimizer drops its pure-Python fallback for JS-only execution; map manager, protocol, and resilience code gain reliability fixes; exceptions and resources are trimmed; translations add new services/options across 20 locales; documentation, quality-scale metadata, and a large characterization test suite are added. ChangesCore Integration Refactor
Dreame Engine Reliability Fixes
Translation Updates
Documentation and Project Metadata
Test Suite Additions
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
||
| def test_default_map_image_deterministic_bytes(self) -> None: | ||
| renderer = DreameVacuumMapDataJsonRenderer() | ||
| assert renderer.default_map_image == renderer.default_map_image |
| patch.object(type(entity), "map_data_json", new=property(lambda self: False)), | ||
| patch.object(entity, "_get_proxy_image", return_value=b"IMG") as proxy, | ||
| ): | ||
| result = await entity.history_map_image(2, False, True, False, True, False) |
| d._message_callback(msg) | ||
|
|
||
| d._handle_properties.assert_called_once() | ||
| (properties_arg,), _kwargs = d._handle_properties.call_args |
b648462 to
bc26d79
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
pyproject.toml (1)
3-3: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick winVersion mismatch failing CI.
Pipeline logs show the version-consistency check failing:
pyproject.tomlversion (6.5.3) does not matchcustom_components/dreame_vacuum/manifest.json. This blocks CI/lint and must be reconciled before merge.🔍 Verification script
#!/bin/bash # Compare pyproject.toml and manifest.json versions rg -n '"version"' custom_components/dreame_vacuum/manifest.json rg -n '^version' pyproject.toml🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pyproject.toml` at line 3, The project version is inconsistent between pyproject.toml and custom_components/dreame_vacuum/manifest.json, causing the CI version check to fail. Update the version value in pyproject.toml and the manifest.json version field so they match exactly, using the existing package/version constants for dreame_vacuum as the source of truth. Re-run the version-consistency check to confirm both files report the same version before merging.Source: Pipeline failures
custom_components/dreame_vacuum/coordinator.py (1)
699-711: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winAlways forward update errors to the base coordinator
async_set_update_error()skipssuper().async_set_update_error(ex)once_availableis alreadyFalse, so the coordinator stops refreshinglast_exceptionand notifying listeners for later device errors. Keep the transition log guarded, but call the base method for every error.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@custom_components/dreame_vacuum/coordinator.py` around lines 699 - 711, In async_set_update_error on the Dreame coordinator, the base coordinator update error handler is only called when _available is currently true, which prevents later errors from updating last_exception and notifying listeners. Keep the availability change and LOGGER.warning guard inside the _available transition logic, but always invoke super().async_set_update_error(ex) for every error regardless of the current availability state so the coordinator continues to record and propagate update failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@custom_components/dreame_vacuum/services.py`:
- Around line 402-410: The schema for async_remote_control_move_step in
services.py allows wider values than the documented
vacuum_remote_control_move_step ranges, so update the vol.Clamp bounds for
INPUT_VELOCITY and INPUT_ROTATION to match the translated service descriptions
and keep the validation consistent with the advertised limits. Use the
SERVICE_MOVE_REMOTE_CONTROL_STEP registration and the
async_remote_control_move_step handler as the key places to adjust so the
accepted schema matches the documented range exactly.
In `@custom_components/dreame_vacuum/services.yaml`:
- Around line 653-669: The `vacuum_set_property.value` field is marked optional,
but `async_set_property` still requires a `value` argument. Either update the
service definition in `vacuum_set_property` to make `value` required, or change
the `async_set_property` signature in `vacuum.py` to accept a default of `None`
so the service can be called without it; keep the schema and handler behavior
aligned.
In `@custom_components/dreame_vacuum/translations/pt-BR.json`:
- Around line 117-118: The pt-BR translation for data_description.square is
still in English, so update the square string in both the config options section
and the options-flow init section to a proper Portuguese translation, keeping it
consistent with the nearby square/vector_rooms entries. Use the existing
translation keys in the pt-BR JSON (including data_description.square) to find
and replace both occurrences.
In `@docs/overhaul/ha-backend-state-of-art-2026-07-02.md`:
- Around line 12-205: The markdown content in this document still triggers
codespell, so normalize the prose to remove or correct misspelled terms and
nonstandard spellings throughout the affected sections, using the document’s
existing headings and lists as anchors. Check the repeated technical phrases and
acronyms in the overview and quality-scale sections, and if any intentional
domain terms must remain, add them to the repo’s codespell whitelist or
exclusion rather than leaving raw failures in the text.
In `@tests/test_map_decoder_paths.py`:
- Around line 588-607: The inline comment in
test_decode_legacy_funiture_info_format is being misread by the
python-use-type-annotations hook as an old-style type comment. Reword or remove
the phrasing in that assertion comment so it no longer starts with “type 8,”
while keeping the note that legacy furniture type 8 maps to ROUND_COFFEE_TABLE.
Focus on the comment text only; no test logic changes are needed.
---
Outside diff comments:
In `@custom_components/dreame_vacuum/coordinator.py`:
- Around line 699-711: In async_set_update_error on the Dreame coordinator, the
base coordinator update error handler is only called when _available is
currently true, which prevents later errors from updating last_exception and
notifying listeners. Keep the availability change and LOGGER.warning guard
inside the _available transition logic, but always invoke
super().async_set_update_error(ex) for every error regardless of the current
availability state so the coordinator continues to record and propagate update
failures.
In `@pyproject.toml`:
- Line 3: The project version is inconsistent between pyproject.toml and
custom_components/dreame_vacuum/manifest.json, causing the CI version check to
fail. Update the version value in pyproject.toml and the manifest.json version
field so they match exactly, using the existing package/version constants for
dreame_vacuum as the source of truth. Re-run the version-consistency check to
confirm both files report the same version before merging.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9cc0d9fd-df1b-4d38-88aa-68a144e769f9
📒 Files selected for processing (93)
.codespellrcARCHITECTURE.mdCHANGELOG.mdCI_STATUS.mdREADME.mdcustom_components/dreame_vacuum/__init__.pycustom_components/dreame_vacuum/binary_sensor.pycustom_components/dreame_vacuum/button.pycustom_components/dreame_vacuum/camera.pycustom_components/dreame_vacuum/config_flow.pycustom_components/dreame_vacuum/const.pycustom_components/dreame_vacuum/coordinator.pycustom_components/dreame_vacuum/dreame/__init__.pycustom_components/dreame_vacuum/dreame/const.pycustom_components/dreame_vacuum/dreame/device_info.pycustom_components/dreame_vacuum/dreame/device_setters.pycustom_components/dreame_vacuum/dreame/device_status/_core.pycustom_components/dreame_vacuum/dreame/exceptions.pycustom_components/dreame_vacuum/dreame/map_data_json_renderer.pycustom_components/dreame_vacuum/dreame/map_decoder.pycustom_components/dreame_vacuum/dreame/map_manager.pycustom_components/dreame_vacuum/dreame/map_optimizer.pycustom_components/dreame_vacuum/dreame/map_renderer/_core.pycustom_components/dreame_vacuum/dreame/protocol.pycustom_components/dreame_vacuum/dreame/resilience.pycustom_components/dreame_vacuum/dreame/resources.pycustom_components/dreame_vacuum/entity.pycustom_components/dreame_vacuum/icons.jsoncustom_components/dreame_vacuum/manifest.jsoncustom_components/dreame_vacuum/number.pycustom_components/dreame_vacuum/quality_scale.yamlcustom_components/dreame_vacuum/recorder.pycustom_components/dreame_vacuum/select.pycustom_components/dreame_vacuum/services.pycustom_components/dreame_vacuum/services.yamlcustom_components/dreame_vacuum/strings.jsoncustom_components/dreame_vacuum/switch.pycustom_components/dreame_vacuum/translations/ca.jsoncustom_components/dreame_vacuum/translations/cs.jsoncustom_components/dreame_vacuum/translations/de.jsoncustom_components/dreame_vacuum/translations/en.jsoncustom_components/dreame_vacuum/translations/es.jsoncustom_components/dreame_vacuum/translations/fr.jsoncustom_components/dreame_vacuum/translations/hu.jsoncustom_components/dreame_vacuum/translations/it.jsoncustom_components/dreame_vacuum/translations/ko.jsoncustom_components/dreame_vacuum/translations/nl.jsoncustom_components/dreame_vacuum/translations/pl.jsoncustom_components/dreame_vacuum/translations/pt-BR.jsoncustom_components/dreame_vacuum/translations/pt.jsoncustom_components/dreame_vacuum/translations/ro.jsoncustom_components/dreame_vacuum/translations/ru.jsoncustom_components/dreame_vacuum/translations/sl.jsoncustom_components/dreame_vacuum/translations/sv.jsoncustom_components/dreame_vacuum/translations/uk.jsoncustom_components/dreame_vacuum/translations/zh-Hans.jsoncustom_components/dreame_vacuum/translations/zh-Hant.jsoncustom_components/dreame_vacuum/vacuum.pydocs/overhaul/ha-backend-state-of-art-2026-07-02.mddocs/overhaul/perf-after-2026-07-02.txtdocs/overhaul/perf-before-2026-07-02.txtdocs/overhaul/uids-after-2026-07-02.txtdocs/overhaul/uids-before-2026-07-02.txthacs.jsonpyproject.tomlrequirements-dev.txtrequirements_dev.txttests/conftest.pytests/test_camera.pytests/test_camera_views.pytests/test_config_flow.pytests/test_device_actions.pytests/test_device_core.pytests/test_device_map_ops.pytests/test_device_setters.pytests/test_device_status.pytests/test_device_status_core.pytests/test_diagnostics.pytests/test_exceptions.pytests/test_init.pytests/test_map_data_json_renderer.pytests/test_map_decoder.pytests/test_map_decoder_paths.pytests/test_map_editor.pytests/test_map_manager.pytests/test_map_optimizer.pytests/test_map_renderer.pytests/test_platform_setup.pytests/test_protocol_mihome.pytests/test_resilience.pytests/test_select.pytests/test_services.pytests/test_vacuum.py
💤 Files with no reviewable changes (10)
- CI_STATUS.md
- custom_components/dreame_vacuum/dreame/init.py
- custom_components/dreame_vacuum/const.py
- requirements_dev.txt
- tests/test_diagnostics.py
- custom_components/dreame_vacuum/dreame/resources.py
- custom_components/dreame_vacuum/dreame/exceptions.py
- tests/test_map_decoder.py
- custom_components/dreame_vacuum/dreame/device_setters.py
- custom_components/dreame_vacuum/dreame/device_status/_core.py
| register( | ||
| SERVICE_MOVE_REMOTE_CONTROL_STEP, | ||
| { | ||
| vol.Required(INPUT_VELOCITY): vol.All(vol.Coerce(int), vol.Clamp(min=-600, max=600)), | ||
| vol.Required(INPUT_ROTATION): vol.All(vol.Coerce(int), vol.Clamp(min=-360, max=360)), | ||
| vol.Optional("prompt"): cv.boolean, | ||
| }, | ||
| "async_remote_control_move_step", | ||
| ) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Clamp bounds wider than documented service ranges.
vol.Clamp(min=-600, max=600) for velocity and min=-360, max=360 for rotation don't match the translated field descriptions ("100 to -300" for velocity, "-128 to 128" for rotation in vacuum_remote_control_move_step). Since vol.Clamp silently clamps rather than rejecting, users following the documented range see correct behavior, but anyone reading the schema/passing edge values gets a much wider accepted range than advertised.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@custom_components/dreame_vacuum/services.py` around lines 402 - 410, The
schema for async_remote_control_move_step in services.py allows wider values
than the documented vacuum_remote_control_move_step ranges, so update the
vol.Clamp bounds for INPUT_VELOCITY and INPUT_ROTATION to match the translated
service descriptions and keep the validation consistent with the advertised
limits. Use the SERVICE_MOVE_REMOTE_CONTROL_STEP registration and the
async_remote_control_move_step handler as the key places to adjust so the
accepted schema matches the documented range exactly.
| vacuum_set_property: | ||
| target: | ||
| entity: | ||
| integration: dreame_vacuum | ||
| domain: vacuum | ||
| fields: | ||
| key: | ||
| example: suction_level | ||
| required: true | ||
| selector: | ||
| text: | ||
| value: | ||
| example: 2 | ||
| required: false | ||
| selector: | ||
| text: | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win
vacuum_set_property.value marked optional but implementation requires it.
async_set_property(self, key: Any, value: Any) in vacuum.py has no default for value, unlike every other optional field in this file (which all have matching Python defaults, e.g. map_id: Any = None). Calling vacuum_set_property without value — a normal usage per required: false — will raise TypeError: async_set_property() missing 1 required positional argument: 'value'.
🐛 Proposed fix (pick one)
Option A — make the schema match current behavior:
value:
example: 2
- required: false
+ required: true
selector:
text:Option B — make the implementation match the schema (requires editing vacuum.py, outside this diff):
- async def async_set_property(self, key: Any, value: Any) -> None:
+ async def async_set_property(self, key: Any, value: Any = None) -> None:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| vacuum_set_property: | |
| target: | |
| entity: | |
| integration: dreame_vacuum | |
| domain: vacuum | |
| fields: | |
| key: | |
| example: suction_level | |
| required: true | |
| selector: | |
| text: | |
| value: | |
| example: 2 | |
| required: false | |
| selector: | |
| text: | |
| vacuum_set_property: | |
| target: | |
| entity: | |
| integration: dreame_vacuum | |
| domain: vacuum | |
| fields: | |
| key: | |
| example: suction_level | |
| required: true | |
| selector: | |
| text: | |
| value: | |
| example: 2 | |
| required: true | |
| selector: | |
| text: |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@custom_components/dreame_vacuum/services.yaml` around lines 653 - 669, The
`vacuum_set_property.value` field is marked optional, but `async_set_property`
still requires a `value` argument. Either update the service definition in
`vacuum_set_property` to make `value` required, or change the
`async_set_property` signature in `vacuum.py` to accept a default of `None` so
the service can be called without it; keep the schema and handler behavior
aligned.
| "square": "Display the map as a square instead of its original aspect ratio.", | ||
| "vector_rooms": "Anti-aliasing das bordas diagonais de cômodos e paredes para um mapa mais limpo e refinado." |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Untranslated square description in pt-BR.
data_description.square is left in English ("Display the map as a square instead of its original aspect ratio.") in both the config options step and the options-flow init step, while its sibling square/vector_rooms strings are translated.
🌐 Suggested translation
- "square": "Display the map as a square instead of its original aspect ratio.",
+ "square": "Exibir o mapa como um quadrado em vez de sua proporção original.",(apply to both occurrences: line 117 and line 1437)
Also applies to: 1437-1438
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@custom_components/dreame_vacuum/translations/pt-BR.json` around lines 117 -
118, The pt-BR translation for data_description.square is still in English, so
update the square string in both the config options section and the options-flow
init section to a proper Portuguese translation, keeping it consistent with the
nearby square/vector_rooms entries. Use the existing translation keys in the
pt-BR JSON (including data_description.square) to find and replace both
occurrences.
| - **Version stable actuelle : Home Assistant Core 2026.7** — "Automations that speak your language", | ||
| sortie le **1er juillet 2026**. (https://www.home-assistant.io/blog/2026/07/01/release-20267/) | ||
| - Cadence mensuelle inchangée (release le 1er jeudi/vendredi du mois, patchs `.1`, `.2`… ensuite). | ||
| - 3 dernières stables : | ||
| 1. **2026.7** (2026-07-01) — renommage massif de triggers/conditions "purpose-specific" | ||
| (`battery.low`→`battery.became_low`, `vacuum.docked`→`vacuum.returned_to_dock`, etc.), timeline | ||
| Activity/logbook refaite. | ||
| 2. **2026.6** (2026-06-03) — "Pick a card, any card" : nouveau card picker, migration de plusieurs | ||
| checks Quality Scale de hassfest vers pylint (`parallel-updates`, `diagnostics`, | ||
| `config-entry-unloading`, `reauthentication-flow`), renommage des comportements de triggers Labs | ||
| (`any`→`each`, `last`→`all`), Bluetooth scanning mode par défaut passé à `Auto`. | ||
| 3. **2026.5** (2026-05-06) — "We're on the same frequency now" : support RF (radio-fréquence) pour | ||
| stores/portails, nouveau dashboard Maintenance (suivi batteries), suppression des triggers/conditions | ||
| `entered home`/`left home`/`is home`/`is not home` sur Person/Device Tracker. | ||
| - **Constat important** : depuis courant 2025, les *release notes* utilisateur (home-assistant.io/blog) | ||
| ne contiennent plus de section "For developers" détaillée — elles renvoient systématiquement vers le | ||
| **developer blog** (https://developers.home-assistant.io/blog/) pour tout ce qui concerne le | ||
| développement d'intégrations. C'est désormais la source de vérité à surveiller en continu. | ||
|
|
||
| --- | ||
|
|
||
| ## 2. Dépréciations ACTIVES à corriger (avec version de retrait) | ||
|
|
||
| Classées par urgence pour ce refactor. **Beaucoup de délais sont déjà expirés** vu que hacs.json cible | ||
| encore HA 2023.6.0 — l'intégration tourne probablement déjà en mode dégradé/warnings sur une install à jour. | ||
|
|
||
| | # | Dépréciation | Déprécié depuis | Retrait prévu | Statut au 2026-07-02 | Action | | ||
| |---|---|---|---|---|---| | ||
| | 1 | `StateVacuumEntity` : constantes `STATE_*` pour l'état → **`VacuumActivity` enum** + propriété `activity` (au lieu de `state`) | 2025.1 | **2026.1** | **DÉJÀ RETIRÉ** (6 mois) | Urgent : si le code fixe encore `self._attr_state = STATE_CLEANING` ou équivalent, ça ne fonctionne plus du tout sur HA récent | | ||
| | 2 | `StateVacuumEntity` : constantes de feature flags → **`VacuumEntityFeature` enum** | 2024.10 (période "officielle"; dépréciation technique dès 2022.5 sans annonce propre) | 2025.10 | **DÉJÀ RETIRÉ** | Urgent : vérifier `SUPPORT_*` remplacés par `VacuumEntityFeature.*` | | ||
| | 3 | `StateVacuumEntity.battery_level` / `battery_icon` (properties) | **2025.8** | **2026.8** (dans ~1 mois) | ACTIF, retrait imminent | Remplacer par une entité `sensor` séparée `device_class: battery` (+ éventuellement un `binary_sensor` `device_class: charging`) | | ||
| | 4 | Camera : `frontend_stream_type` (property), `async_handle_web_rtc_offer`, `async_register_rtsp_to_web_rtc_provider` | 2024.12 | 2025.6 | **DÉJÀ RETIRÉ** | Si la plateforme camera fait du WebRTC (flux caméra embarquée du robot), migrer vers `async_handle_async_webrtc_offer` / `async_register_webrtc_provider`, utiliser le WS `camera/capabilities` côté frontend | | ||
| | 5 | `OptionsFlow` : assignation manuelle de `self.config_entry` dans `__init__` du flow / `OptionsFlowWithConfigEntry` | annoncé 2024.11 | avertissement jusqu'à **2025.12**, retrait non daté précisément mais **la fenêtre d'avertissement est déjà passée** | ACTIF — logge un warning demandant d'ouvrir une issue sur le repo custom si toujours assigné manuellement | Supprimer le paramètre `config_entry` du constructeur d'`OptionsFlowHandler`, utiliser `self.config_entry` / `self._config_entry_id` fournis nativement | | ||
| | 6 | Combiner un **config entry update listener** (`add_update_listener`) avec des méthodes de reload dans le config flow (`async_update_reload_and_abort`, `reload_on_update` implicite) | **2026.6** (ce mois-ci) | **2026.12** | TRÈS RÉCENT, ACTIF | Risque de reload en double / race condition. Choisir une seule stratégie : soit retirer le listener, soit `async_update_and_abort()`, soit `reload_on_update=False` sur `_abort_if_unique_id_configured()` | | ||
| | 7 | `quality_scale` déclaré comme clé dans `manifest.json` | changement de mécanisme depuis **2024.11.20** | pas un retrait à proprement parler pour les intégrations custom (non validé par hassfest hors core), mais c'est l'ancien pattern | À migrer par bonne pratique | Le nouveau modèle est un fichier **`quality_scale.yaml`** à la racine de l'intégration listant chaque règle avec statut (`done`/`exempt`+raison/`todo`). Pour une intégration custom ce fichier n'a pas d'effet runtime mais sert de checklist/preuve vis-à-vis de HACS et des reviewers | | ||
| | 8 | `FlowHandler.show_advanced_options` / `context['show_advanced_options']` | **2026.5** | **2027.6** | ACTIF, marge confortable | Remplacer le gating par "advanced mode" par une organisation en *sections* dans le config/options flow | | ||
| | 9 | `paho-mqtt` `CallbackAPIVersion.VERSION1` (API historique de callbacks) | dépréciée côté lib paho-mqtt (pas HA) | retrait prévu en **paho-mqtt 3.0** | À surveiller | Migrer les callbacks (`on_connect`, `on_message`, etc.) vers `CallbackAPIVersion.VERSION2`, plus cohérent MQTT 3.x/5.x | | ||
| | 10 | Détection des appels bloquants dans l'event loop (`requests`, `urllib`, `time.sleep`, I/O fichier sync) | renforcée depuis **2024.7** | pas une deadline unique — mais les logs `Detected blocking call to X inside the event loop by custom integration 'dreame_vacuum'` sont visibles par tous les utilisateurs et nourrissent les demandes HACS/quality-scale. Certains cas (import bloquant, sleep bloquant) sont déjà remontés comme quasi-erreurs bloquantes selon les composants internes | ACTIF EN PERMANENCE | `requests` est **structurellement incompatible** avec la règle Platinum `async-dependency` et dégrade l'expérience (warnings visibles, potentiel throttling futur). Tout appel `requests.get/post` doit passer par `hass.async_add_executor_job(...)` a minima, et à terme être remplacé par `aiohttp`/`httpx` async natif | | ||
|
|
||
| **Non trouvé de dépréciation spécifique 2024-2026 sur** : `DataUpdateCoordinator` (API stable, juste enrichie, | ||
| voir §3), `EntityDescription`/`_attr_has_entity_name` (pattern stable depuis 2023, toujours recommandé, | ||
| `has-entity-name` reste une règle Bronze obligatoire), `select`/`number`/`button`/`time`/`switch` platforms | ||
| (pas de breaking change identifié sur la période). | ||
|
|
||
| --- | ||
|
|
||
| ## 3. Nouvelles API à adopter (avec version d'introduction) | ||
|
|
||
| | API / pattern | Introduit en | Ce que ça apporte pour `dreame_vacuum` | | ||
| |---|---|---| | ||
| | **`ConfigEntry.runtime_data`** (ConfigEntry générique typé, `type MyConfigEntry = ConfigEntry[MyData]`) | 2024.4 (blog 2024-04-30), usage généralisé dès 2024.6-2024.8 | Remplace `hass.data[DOMAIN][entry.entry_id]`. C'est aussi la règle **Bronze `runtime-data`** — actuellement quasi-certainement non respectée vu le manifest `quality_scale: gold` déclaré avec une base HA 2023.6 | | ||
| | **`DataUpdateCoordinator._async_setup()`** | 2024.8 (blog 2024-08-05) | Hook async dédié appelé une fois via `async_config_entry_first_refresh()`, pour init unique (ex: découverte des appareils MQTT, fetch config initiale) sans polluer `_async_update_data` avec des flags `if not initialized` | | ||
| | **Helpers reauth/reconfigure** : `self._get_reauth_entry()`, `self._get_reconfigure_entry()`, `self._abort_if_unique_id_mismatch()`, `async_update_reload_and_abort(..., data_updates=...)` | 2024.10-2024.11 (blog 2024-10-21, 2024-11-04) | Pattern standard pour la règle Silver `reauthentication-flow` et Gold `reconfiguration-flow`. Entries doivent être liées via `entry_id` et récupérées localement à chaque step, pas cachées en attribut de classe | | ||
| | **OptionsFlow natif** : `self.config_entry` fourni automatiquement, `self._config_entry_id` | 2024.11 (blog 2024-11-12) | Supprimer le paramètre `config_entry` du `__init__` de l'OptionsFlowHandler | | ||
| | **Config Subentries** (`ConfigSubentryFlow`) | 2025.2 (blog 2025-02-16), ajustements 2025-03-24 | Pertinent si un compte cloud Dreame gère plusieurs robots/hubs — permettrait de modéliser chaque robot comme sous-entrée plutôt qu'un flot config unique | | ||
| | **`service.async_register_platform_entity_service`** appelé depuis `async_setup` de l'intégration (plus depuis le platform setup) | 2025.9 (blog 2025-09-25) | Remplace `platform.async_register_entity_service` historique ; découple l'enregistrement des services (actions) du timing de setup des plateformes — pertinent pour les actions custom vacuum (ex: `go_to`, `clean_zone`, `clean_segment`) | | ||
| | **Description placeholders pour traductions d'actions de service** | 2025.11 (blog 2025-11-27) | Permet des messages d'erreur/traductions d'actions plus riches — aligné avec la règle Gold `exception-translations` | | ||
| | **DataUpdateCoordinator "Retry-After"** | 2025.11 (blog 2025-11-17) | Le coordinator respecte un `retry_after` renvoyé par l'API cloud lors d'un throttle — utile pour l'API cloud Dreame | | ||
| | **Coordinator retriggering** | 2025.10 (blog 2025-10-05) | Permet de forcer un refresh coordonné depuis un event MQTT push sans dupliquer la logique | | ||
| | **Terminologie "services → actions"**, icônes via `icons.json` (depuis 2024.2, schéma étendu 2024-08-27) | 2024.7 (services→actions), 2024.2/2024.8 (icons.json) | `services.yaml` reste le nom de fichier technique mais toute la doc/UX parle d'"actions" ; les icônes d'entités/services doivent passer par `icons.json` plutôt que la property `icon` codée en dur | | ||
| | **`prek`** remplace `pre-commit` comme runner de hooks | 2026.1 (blog 2026-01-13) | Déjà fait côté ce repo (commit `81794d8` "adopt prek as the pre-commit hook runner", `f4ee2d5` "migrate to prek-only") — rien à faire | | ||
| | **Quality Scale : migration de checks hassfest → pylint** (`parallel-updates`, `diagnostics`, `config-entry-unloading`, `reauthentication-flow`) | 2026.6 | Pour du custom (hors core), hassfest/pylint core ne s'appliquent pas directement, mais les mêmes règles de style doivent être répliquées manuellement / via `quality_scale.yaml` en checklist | | ||
|
|
||
| --- | ||
|
|
||
| ## 4. Règles Quality Scale du jour (liste complète des identifiants, par palier) | ||
|
|
||
| Source : https://developers.home-assistant.io/docs/core/integration-quality-scale/rules/ (état au 2026-07-02) | ||
|
|
||
| ### 🥉 Bronze | ||
| 1. `action-setup` — Les actions de service sont enregistrées dans `async_setup` | ||
| 2. `appropriate-polling` — Intervalle de polling approprié (si intégration à polling) | ||
| 3. `brands` — Assets de branding disponibles | ||
| 4. `common-modules` — Patterns communs dans des modules communs | ||
| 5. `config-flow-test-coverage` — Couverture de test complète du config flow | ||
| 6. `config-flow` — Configurable via l'UI | ||
| 7. `dependency-transparency` — Transparence des dépendances | ||
| 8. `docs-actions` — Doc décrit les actions de service fournies | ||
| 9. `docs-triggers` — Doc décrit les triggers fournis | ||
| 10. `docs-conditions` — Doc décrit les conditions fournies | ||
| 11. `docs-high-level-description` — Description haut niveau de la marque/produit/service | ||
| 12. `docs-installation-instructions` — Instructions d'installation pas-à-pas + prérequis | ||
| 13. `docs-removal-instructions` — Instructions de suppression | ||
| 14. `entity-event-setup` — Abonnement aux events dans les bonnes méthodes de cycle de vie | ||
| 15. `entity-unique-id` — Entités avec unique ID | ||
| 16. `has-entity-name` — Entités avec `has_entity_name = True` | ||
| 17. `runtime-data` — Usage de `ConfigEntry.runtime_data` | ||
| 18. `test-before-configure` — Test de connexion dans le config flow | ||
| 19. `test-before-setup` — Vérification à l'init que le setup est possible | ||
| 20. `unique-config-entry` — Empêche le double setup du même device/service | ||
|
|
||
| ### 🥈 Silver | ||
| 1. `action-exceptions` — Les actions lèvent des exceptions en cas d'échec | ||
| 2. `config-entry-unloading` — Support du unload du config entry | ||
| 3. `docs-configuration-parameters` — Doc décrit toutes les options de config | ||
| 4. `docs-installation-parameters` — Doc décrit tous les paramètres d'installation | ||
| 5. `entity-unavailable` — Entité marquée indisponible si pertinent | ||
| 6. `integration-owner` — Un owner d'intégration désigné | ||
| 7. `log-when-unavailable` — Log une fois à la perte de connexion, une fois à la reconnexion | ||
| 8. `parallel-updates` — `PARALLEL_UPDATES` spécifié | ||
| 9. `reauthentication-flow` — Réauthentification disponible via l'UI | ||
| 10. `test-coverage` — >95% de couverture de test sur tous les modules | ||
|
|
||
| ### 🥇 Gold | ||
| 1. `devices` — Crée des devices | ||
| 2. `diagnostics` — Implémente les diagnostics | ||
| 3. `discovery-update-info` — Utilise les infos de discovery pour mettre à jour les infos réseau | ||
| 4. `discovery` — Devices découvrables | ||
| 5. `docs-data-update` — Doc décrit comment les données sont mises à jour | ||
| 6. `docs-examples` — Doc fournit des exemples d'automatisation | ||
| 7. `docs-known-limitations` — Doc décrit les limitations connues | ||
| 8. `docs-supported-devices` — Doc décrit devices supportés/non supportés | ||
| 9. `docs-supported-functions` — Doc décrit fonctionnalités/entités supportées | ||
| 10. `docs-troubleshooting` — Doc fournit infos de dépannage | ||
| 11. `docs-use-cases` — Doc décrit les cas d'usage | ||
| 12. `dynamic-devices` — Devices ajoutés après le setup initial de l'intégration | ||
| 13. `entity-category` — Entités avec `EntityCategory` approprié | ||
| 14. `entity-device-class` — Entités avec device class quand possible | ||
| 15. `entity-disabled-by-default` — Entités peu utiles/bruyantes désactivées par défaut | ||
| 16. `entity-translations` — Noms d'entités traduits | ||
| 17. `exception-translations` — Messages d'exception traduisibles | ||
| 18. `icon-translations` — Icônes via traductions (`icons.json`) | ||
| 19. `reconfiguration-flow` — Flow de reconfiguration disponible | ||
| 20. `repair-issues` — Repair issues / repair flows utilisés quand une intervention est nécessaire | ||
| 21. `stale-devices` — Suppression des devices obsolètes | ||
|
|
||
| ### 🏆 Platinum | ||
| 1. `async-dependency` — La dépendance externe est async | ||
| 2. `inject-websession` — La dépendance supporte l'injection d'une websession | ||
| 3. `strict-typing` — Typage strict (mypy) | ||
|
|
||
| **Point critique pour ce refactor** : `paho-mqtt` (thread-based, non-asyncio natif) et `requests` (100% | ||
| sync) rendent `async-dependency` et `inject-websession` **non atteignables tels quels**. Pour viser | ||
| Platinum il faudrait soit un wrapper asyncio-natif autour de paho-mqtt (ou migrer vers une lib MQTT async | ||
| type `aiomqtt`), soit au minimum isoler tous les appels bloquants dans l'executor et documenter | ||
| l'exemption dans `quality_scale.yaml` avec justification. `quality_scale: gold` déclaré dans le manifest | ||
| actuel est donc probablement **non tenable en l'état** tant que `requests` reste sur le chemin critique | ||
| (cf. règle Gold implicite de stabilité/robustesse — pas listée nommément mais couverte par | ||
| `action-exceptions`, `entity-unavailable`, `log-when-unavailable`). | ||
|
|
||
| --- | ||
|
|
||
| ## 5. Points spécifiques vacuum / camera / mqtt / requests-sync | ||
|
|
||
| ### Vacuum | ||
| - **Obligatoire dès maintenant** (fenêtres déjà expirées) : propriété `activity` retournant un | ||
| `VacuumActivity` (pas `state`), et `VacuumEntityFeature` pour les feature flags. Si le fork n'a pas | ||
| encore été migré, c'est la priorité n°1 — l'entité vacuum est probablement cassée ou en fallback dégradé | ||
| sur toute install HA ≥ 2026.1. | ||
| - `battery_level`/`battery_icon` sur l'entité vacuum : à sortir vers un `sensor` `device_class: battery` | ||
| dédié + `binary_sensor` `device_class: charging` avant **2026.8** (dans ~1 mois). C'est un changement | ||
| d'UX visible (l'indicateur batterie quitte la carte vacuum pour devenir une entité séparée) — à | ||
| documenter dans le changelog utilisateur du fork. | ||
| - Pas de nouvelle contrainte identifiée sur `map_data`/coordonnées de carte, actions `clean_zone`/`clean_segment`/`go_to` au-delà du pattern générique "services → actions" et `async_register_platform_entity_service`. | ||
|
|
||
| ### Camera | ||
| - Si `dreame_vacuum` expose un flux caméra embarquée (certains robots ont une caméra), toute logique | ||
| WebRTC doit être sur `async_handle_async_webrtc_offer` / `async_register_webrtc_provider` | ||
| (les anciennes méthodes sont retirées depuis 2025.6). | ||
| - Le rendu de carte (pillow/numpy) via `camera.Image` / `async_camera_image` doit rester **dans | ||
| l'executor** (`hass.async_add_executor_job`) — Pillow/numpy sont CPU-bound et synchrones, donc jamais | ||
| d'appel direct dans une coroutine du event loop. | ||
|
|
||
| ### MQTT (paho-mqtt) | ||
| - Vérifier la version de `paho-mqtt` épinglée dans `manifest.json` → `requirements`. Si `< 2.0`, | ||
| planifier la migration `CallbackAPIVersion.VERSION1` → `VERSION2` (retrait prévu en paho-mqtt 3.0, | ||
| côté lib externe, pas HA). | ||
| - Paho-mqtt fonctionne avec sa propre boucle réseau en thread — s'assurer que tous les callbacks | ||
| (`on_message`, `on_connect`, etc.) qui touchent l'état HA passent bien par | ||
| `hass.loop.call_soon_threadsafe(...)` ou `async_add_executor_job`, jamais d'appel direct à des | ||
| coroutines/`hass.states` depuis le thread paho. | ||
| - C'est ce pattern (dépendance non-async) qui bloque structurellement la règle Platinum | ||
| `async-dependency` (cf. §4). | ||
|
|
||
| ### `requests` (sync) | ||
| - Incompatible avec les bonnes pratiques asyncio de HA depuis toujours, mais la détection des appels | ||
| bloquants dans l'event loop s'est **renforcée depuis 2024.7** (logs `Detected blocking call to X | ||
| inside the event loop by custom integration 'dreame_vacuum'` visibles par tous les utilisateurs dans | ||
| leurs logs HA — mauvais pour la réputation/HACS). | ||
| - Recommandation minimale immédiate : englober tout appel `requests.*` dans | ||
| `await hass.async_add_executor_job(...)`. | ||
| - Recommandation cible : migrer vers `aiohttp` (déjà une dépendance systématique de HA, réutilisable via | ||
| `aiohttp_client.async_get_clientsession(hass)`) ou `httpx.AsyncClient`, ce qui débloque aussi | ||
| `inject-websession` (Platinum) et simplifie les tests (mock de session). | ||
|
|
||
| ### Divers pertinents (hub / multi-device) | ||
| - `integration_type: hub` + potentiellement plusieurs robots par compte cloud → évaluer **Config | ||
| Subentries** (2025.2) pour modéliser chaque robot, au lieu d'un unique config entry monolithique. | ||
| - `hacs.json` : `homeassistant >= 2023.6.0` est très en retard par rapport à toutes les API listées | ||
| ci-dessus (runtime_data 2024.4, coordinator `_async_setup` 2024.8, reauth/reconfigure helpers | ||
| 2024.10-11, OptionsFlow natif 2024.11, subentries 2025.2, service registration API 2025.9). Si le | ||
| refactor adopte ces patterns, il faut remonter le minimum HA en conséquence (au minimum | ||
| 2024.11/2025.1, idéalement une version 2025.x-2026.x récente) — sinon le fork ne sera plus installable | ||
| correctement sur les anciennes versions déclarées compatibles. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Fix the codespell failures before merge.
This document still trips the pre-commit codespell stage across multiple sections, so CI will stay red until the prose is normalized or the file is explicitly excluded/whitelisted.
🧰 Tools
🪛 GitHub Actions: CI / 2_Pre-commit (prek).txt
[error] 14-14: codespell found potential spelling issue. 'patchs' => 'patches, paths'.
[error] 40-40: codespell found potential spelling issue. 'fixe' => 'fixed, fixes, fix, fixme, fixer'.
[error] 41-41: codespell found potential spelling issue. 'annonce' => 'announce'.
[error] 45-46: codespell found potential spelling issues. 'implicite' => 'implicit, implicitly'; 'raison' => 'reason, raisin'.
[error] 47-47: codespell found potential spelling issues. 'marge' => 'merge'; 'confortable' => 'comfortable'.
[error] 49-49: codespell found potential spelling issues. 'visibles' => 'visible'; 'composants' => 'components'; 'potentiel' => 'potential'.
[error] 62-64: codespell found potential spelling issues. 'Remplace' => 'Replace'; 'mattribut' => 'attribute'.
[error] 67-72: codespell found potential spelling issues. 'Remplace' => 'Replace'; 'remplace' => 'replace'.
[error] 95-95: codespell found potential spelling issue. 'vie' => 'via'.
[error] 99-110: codespell found potential spelling issues. 'connexion' => 'connection' (occurs at lines 99 and 110).
[error] 121-121: codespell found potential spelling issue. 'exemples' => 'examples'.
[error] 140-140: codespell found potential spelling issue. 'supporte' => 'supported, supporter'.
[error] 149-149: codespell found potential spelling issue. 'implicite' => 'implicit, implicitly'.
[error] 189-191: codespell found potential spelling issues. 'visibles' => 'visible'; 'Recommandation' => 'Recommendation'.
[error] 193-193: codespell found potential spelling issue. 'Recommandation' => 'Recommendation'.
🪛 GitHub Actions: CI / Pre-commit (prek)
[error] 14-14: codespell failed (exit code 65). Replace "patchs" with "patches, paths".
[error] 40-40: codespell failed (exit code 65). Replace "fixe" with "fixed, fixes, fix, fixme, fixer".
[error] 41-41: codespell failed (exit code 65). Replace "annonce" with "announce".
[error] 45-45: codespell failed (exit code 65). Replace "implicite" with "implicit, implicitly".
[error] 46-46: codespell failed (exit code 65). Replace "raison" with "reason, raisin".
[error] 47-47: codespell failed (exit code 65). Replace "marge" with "merge".
[error] 47-47: codespell failed (exit code 65). Replace "confortable" with "comfortable".
[error] 49-49: codespell failed (exit code 65). Replace "visibles" with "visible".
[error] 49-49: codespell failed (exit code 65). Replace "composants" with "components".
[error] 49-49: codespell failed (exit code 65). Replace "visibles" with "visible".
[error] 49-49: codespell failed (exit code 65). Replace "potentiel" with "potential".
[error] 62-62: codespell failed (exit code 65). Replace "Remplace" with "Replace".
[error] 64-64: codespell failed (exit code 65). Replace "attribut" with "attribute".
[error] 64-64: codespell failed (exit code 65). Replace "classe" with "class, classes".
[error] 67-67: codespell failed (exit code 65). Replace "Remplace" with "Replace".
[error] 72-72: codespell failed (exit code 65). Replace "remplace" with "replace".
[error] 95-95: codespell failed (exit code 65). Replace "vie" with "via".
[error] 99-99: codespell failed (exit code 65). Replace "connexion" with "connection".
[error] 110-110: codespell failed (exit code 65). Replace "connexion" with "connection".
[error] 121-121: codespell failed (exit code 65). Replace "exemples" with "examples".
[error] 140-140: codespell failed (exit code 65). Replace "supporte" with "supported, supporter".
[error] 149-149: codespell failed (exit code 65). Replace "implicite" with "implicit, implicitly".
[error] 189-189: codespell failed (exit code 65). Replace "visibles" with "visible".
[error] 191-191: codespell failed (exit code 65). Replace "Recommandation" with "Recommendation".
[error] 193-193: codespell failed (exit code 65). Replace "Recommandation" with "Recommendation".
🪛 LanguageTool
[typographical] ~14-~14: Caractère d’apostrophe incorrect.
Context: ...e le 1er jeudi/vendredi du mois, patchs .1, .2… ensuite). - 3 dernières stables ...
(APOS_INCORRECT)
[typographical] ~14-~14: Caractère d’apostrophe incorrect.
Context: ...er jeudi/vendredi du mois, patchs .1, .2… ensuite). - 3 dernières stables : 1....
(APOS_INCORRECT)
[style] ~15-~15: Il est déconseillé de placer des chiffres en début de phrase. Souhaitez-vous reformuler la phrase ?
Context: ...du mois, patchs .1, .2… ensuite). - 3 dernières stables : 1. 2026.7 (20...
(NOMBRES_EN_LETTRES)
[typographical] ~17-~17: Caractère d’apostrophe incorrect.
Context: ...ers/conditions "purpose-specific" (battery.low→battery.became_low, vacuum.docked→`...
(APOS_INCORRECT)
[typographical] ~17-~17: Caractère d’apostrophe incorrect.
Context: ... "purpose-specific" (battery.low→battery.became_low, vacuum.docked→`vacuum.returned_to_do...
(APOS_INCORRECT)
[typographical] ~17-~17: Caractère d’apostrophe incorrect.
Context: ... (battery.low→battery.became_low, vacuum.docked→vacuum.returned_to_dock, etc.), timel...
(APOS_INCORRECT)
[typographical] ~17-~17: Caractère d’apostrophe incorrect.
Context: ...→battery.became_low, vacuum.docked→vacuum.returned_to_dock`, etc.), timeline Activity/logbook ...
(APOS_INCORRECT)
[typographical] ~20-~20: Caractère d’apostrophe incorrect.
Context: ...s Quality Scale de hassfest vers pylint (parallel-updates, diagnostics, `...
(APOS_INCORRECT)
[typographical] ~20-~20: Caractère d’apostrophe incorrect.
Context: ...ssfest vers pylint (parallel-updates, diagnostics, config-entry-unloading, `reauth...
(APOS_INCORRECT)
[typographical] ~20-~20: Caractère d’apostrophe incorrect.
Context: ...int (parallel-updates, diagnostics, config-entry-unloading, reauthentication-flow), renommage de...
(APOS_INCORRECT)
[typographical] ~21-~21: Caractère d’apostrophe incorrect.
Context: ...ostics, config-entry-unloading, reauthentication-flow`), renommage des comportements de trigge...
(APOS_INCORRECT)
[typographical] ~22-~22: Caractère d’apostrophe incorrect.
Context: ...des comportements de triggers Labs (any→each, last→all), Bluetooth sc...
(APOS_INCORRECT)
[typographical] ~22-~22: Caractère d’apostrophe incorrect.
Context: ...mportements de triggers Labs (any→each, last→all), Bluetooth scanning...
(APOS_INCORRECT)
[typographical] ~22-~22: Caractère d’apostrophe incorrect.
Context: ...ts de triggers Labs (any→each, last→all), Bluetooth scanning mode par déf...
(APOS_INCORRECT)
[typographical] ~22-~22: Caractère d’apostrophe incorrect.
Context: ...riggers Labs (any→each, last→all), Bluetooth scanning mode par défaut pa...
(APOS_INCORRECT)
[typographical] ~22-~22: Caractère d’apostrophe incorrect.
Context: ...etooth scanning mode par défaut passé à Auto. 3. 2026.5 (2026-05-06) — "We're ...
(APOS_INCORRECT)
[typographical] ~23-~23: Les deux parties de ce mot peuvent s’unir.
Context: ...n the same frequency now" : support RF (radio-fréquence) pour stores/portails, nouveau das...
(FR_SPLIT_WORDS_HYPHEN)
[typographical] ~24-~24: Caractère d’apostrophe incorrect.
Context: ...s), suppression des triggers/conditions entered home/left home/is home/is not home sur...
(APOS_INCORRECT)
[typographical] ~25-~25: Caractère d’apostrophe incorrect.
Context: ...triggers/conditions entered home/left home/is home/is not home sur Person/Devi...
(APOS_INCORRECT)
[typographical] ~25-~25: Caractère d’apostrophe incorrect.
Context: ...ditions entered home/left home/is home/is not home sur Person/Device Tracker...
(APOS_INCORRECT)
[style] ~28-~28: Cette structure peut être omise afin d’alléger la phrase.
Context: ...evelopers.home-assistant.io/blog/) pour tout ce qui concerne le développement d'intégrations. C'est d...
(TOUT_CE_QUI_CONCERNE)
[style] ~35-~35: Une autre structure plus directe dynamisera votre phrase.
Context: ...Beaucoup de délais sont déjà expirés* vu que hacs.json cible encore HA 2023.6.0 — l'...
(VU_QUE)
[style] ~39-~39: Un tiret long peut sembler plus approprié.
Context: ...révu | Statut au 2026-07-02 | Action | |---|---|---|---|---|---| | 1 | `StateVacuum...
(TIRET_LONG_1)
[style] ~39-~39: Un tiret long peut sembler plus approprié.
Context: ... | Statut au 2026-07-02 | Action | |---|---|---|---|---|---| | 1 | `StateVacuumEnti...
(TIRET_LONG_1)
[style] ~39-~39: Un tiret long peut sembler plus approprié.
Context: ...tatut au 2026-07-02 | Action | |---|---|---|---|---|---| | 1 | StateVacuumEntity ...
(TIRET_LONG_1)
[style] ~39-~39: Un tiret long peut sembler plus approprié.
Context: ...t au 2026-07-02 | Action | |---|---|---|---|---|---| | 1 | StateVacuumEntity : co...
(TIRET_LONG_1)
[style] ~39-~39: Un tiret long peut sembler plus approprié.
Context: ... 2026-07-02 | Action | |---|---|---|---|---|---| | 1 | StateVacuumEntity : consta...
(TIRET_LONG_1)
[style] ~39-~39: Un tiret long peut sembler plus approprié.
Context: ...6-07-02 | Action | |---|---|---|---|---|---| | 1 | StateVacuumEntity : constantes...
(TIRET_LONG_1)
[typographical] ~40-~40: Caractère d’apostrophe incorrect.
Context: ...y: constantesSTATE_* pour l'état → **VacuumActivityenum** + propriétéacti...
(APOS_INCORRECT)
[typographical] ~40-~40: Caractère d’apostrophe incorrect.
Context: ...um** + propriété activity (au lieu de state) | 2025.1 | 2026.1 | *DÉJÀ RETIRÉ...
(APOS_INCORRECT)
[typographical] ~41-~41: Caractère d’apostrophe incorrect.
Context: ...Entity : constantes de feature flags → **VacuumEntityFeature` enum** | 2024.10 (p...
(APOS_INCORRECT)
[typographical] ~42-~42: Caractère d’apostrophe incorrect.
Context: ...y(+ éventuellement unbinary_sensor device_class: charging) | | 4 | Camera : frontend_stream_type...
(APOS_INCORRECT)
[typographical] ~43-~43: Caractère d’apostrophe incorrect.
Context: ...ra : frontend_stream_type (property), async_handle_web_rtc_offer, `async_register_rtsp_to_web_rtc_provid...
(APOS_INCORRECT)
[typographical] ~43-~43: Caractère d’apostrophe incorrect.
Context: ...ers async_handle_async_webrtc_offer / async_register_webrtc_provider, utiliser le WS camera/capabilities c...
(APOS_INCORRECT)
[typographical] ~44-~44: Caractère d’apostrophe répété.
Context: ...aramètre config_entry du constructeur d'OptionsFlowHandler, utiliser `self.conf...
(APOS_INCORRECT)
[typographical] ~45-~45: Caractère d’apostrophe incorrect.
Context: ...ner un config entry update listener (add_update_listener) avec des méthodes ...
(APOS_INCORRECT)
[typographical] ~45-~45: Caractère d’apostrophe incorrect.
Context: ... méthodes de reload dans le config flow (async_update_reload_and_abort, `reload_...
(APOS_INCORRECT)
[typographical] ~45-~45: Caractère d’apostrophe incorrect.
Context: ...atégie : soit retirer le listener, soit async_update_and_abort(), soit reload_on_update=False sur `_ab...
(APOS_INCORRECT)
[typographical] ~46-~46: Caractère d’apostrophe incorrect.
Context: ...ique | Le nouveau modèle est un fichier quality_scale.yaml à la racine de l'i...
(APOS_INCORRECT)
[typographical] ~46-~46: Caractère d’apostrophe incorrect.
Context: ...ration listant chaque règle avec statut (done/exempt+raison/todo). Pour une ...
(APOS_INCORRECT)
[typographical] ~46-~46: Caractère d’apostrophe incorrect.
Context: ...listant chaque règle avec statut (done/exempt+raison/todo). Pour une intégra...
(APOS_INCORRECT)
[typographical] ~46-~46: Caractère d’apostrophe incorrect.
Context: ...ègle avec statut (done/exempt+raison/todo). Pour une intégration custom ce f...
(APOS_INCORRECT)
[style] ~46-~46: Une modification de la structure de la négation apportera de la légèreté et de la précision à cette phrase.
Context: ... Pour une intégration custom ce fichier n'a pas d'effet runtime mais sert de checklist/pre...
(NEGATION_AVOIR)
[typographical] ~48-~48: Caractère d’apostrophe incorrect.
Context: ...* | À surveiller | Migrer les callbacks (on_connect, on_message, etc.) vers `C...
(APOS_INCORRECT)
[typographical] ~48-~48: Caractère d’apostrophe incorrect.
Context: ...r | Migrer les callbacks (on_connect, on_message, etc.) vers `CallbackAPIVersion.VERSION...
(APOS_INCORRECT)
[typographical] ~48-~48: Caractère d’apostrophe incorrect.
Context: ...(on_connect, on_message, etc.) vers CallbackAPIVersion.VERSION2, plus cohérent MQTT 3.x/5.x | | 10 | Dé...
(APOS_INCORRECT)
[typographical] ~49-~49: Caractère d’apostrophe incorrect.
Context: ... des appels bloquants dans l'event loop (requests, urllib, time.sleep, I/O f...
(APOS_INCORRECT)
[typographical] ~49-~49: Caractère d’apostrophe incorrect.
Context: ...loquants dans l'event loop (requests, urllib, time.sleep, I/O fichier sync) | renf...
(APOS_INCORRECT)
[typographical] ~49-~49: Caractère d’apostrophe incorrect.
Context: ...ans l'event loop (requests, urllib, time.sleep, I/O fichier sync) | renforcée depuis *...
(APOS_INCORRECT)
[style] ~49-~49: Un autre verbe peut sembler plus formel et professionnel.
Context: ...r). Tout appel requests.get/post doit passer par hass.async_add_executor_job(...) a mi...
(PASSER_PAR)
[typographical] ~49-~49: Caractère d’apostrophe incorrect.
Context: ... a minima, et à terme être remplacé par aiohttp/httpx async natif | **Non trouvé de ...
(APOS_INCORRECT)
[typographical] ~52-~52: Caractère d’apostrophe incorrect.
Context: ... (API stable, juste enrichie, voir §3), EntityDescription/_attr_has_entity_name (pattern stable...
(APOS_INCORRECT)
[typographical] ~53-~53: Caractère d’apostrophe incorrect.
Context: ...ereste une règle Bronze obligatoire),select/number/button/time/switch` platf...
(APOS_INCORRECT)
[typographical] ~53-~53: Caractère d’apostrophe incorrect.
Context: ...une règle Bronze obligatoire), select/number/button/time/switch platforms (pas...
(APOS_INCORRECT)
[typographical] ~53-~53: Caractère d’apostrophe incorrect.
Context: ... Bronze obligatoire), select/number/button/time/switch platforms (pas de break...
(APOS_INCORRECT)
[typographical] ~53-~53: Caractère d’apostrophe incorrect.
Context: ...bligatoire), select/number/button/time/switch platforms (pas de breaking cha...
(APOS_INCORRECT)
[style] ~61-~61: Un tiret long peut sembler plus approprié.
Context: ... que ça apporte pour dreame_vacuum | |---|---|---| | **ConfigEntry.runtime_data...
(TIRET_LONG_1)
[style] ~61-~61: Un tiret long peut sembler plus approprié.
Context: ... ça apporte pour dreame_vacuum | |---|---|---| | ConfigEntry.runtime_data (...
(TIRET_LONG_1)
[style] ~61-~61: Un tiret long peut sembler plus approprié.
Context: ...apporte pour dreame_vacuum | |---|---|---| | ConfigEntry.runtime_data (Conf...
(TIRET_LONG_1)
[typographical] ~62-~62: Caractère d’apostrophe incorrect.
Context: ... pour dreame_vacuum | |---|---|---| | ConfigEntry.runtime_data (ConfigEntry...
(APOS_INCORRECT)
[typographical] ~62-~62: Caractère d’apostrophe incorrect.
Context: ...me_data** (ConfigEntry générique typé, type MyConfigEntry = ConfigEntry[MyData]`) | 2024.4 (blog 2024-04-30), usage géné...
(APOS_INCORRECT)
[typographical] ~62-~62: Caractère d’apostrophe incorrect.
Context: ...généralisé dès 2024.6-2024.8 | Remplace hass.data[DOMAIN][entry.entry_id]. C'est aussi la règle **Bronze `runtime...
(APOS_INCORRECT)
[typographical] ~62-~62: Caractère d’apostrophe incorrect.
Context: ...try_id]. C'est aussi la règle **Bronze runtime-data`** — actuellement quasi-certainement non...
(APOS_INCORRECT)
[typographical] ~63-~63: Caractère d’apostrophe incorrect.
Context: ...ld déclaré avec une base HA 2023.6 | | **DataUpdateCoordinator._async_setup()`** ...
(APOS_INCORRECT)
[typographical] ~63-~63: Caractère d’apostrophe incorrect.
Context: ... | Hook async dédié appelé une fois via async_config_entry_first_refresh(), pour init unique (ex: découverte des a...
(APOS_INCORRECT)
[typographical] ~64-~64: Caractère d’apostrophe incorrect.
Context: ...d| | **Helpers reauth/reconfigure** :self._get_reauth_entry(), self._get_reconfigure_entry(), self...
(APOS_INCORRECT)
[typographical] ~64-~64: Caractère d’apostrophe incorrect.
Context: ...nfigure** : self._get_reauth_entry(), self._get_reconfigure_entry(), self._abort_if_unique_id_mismatch(),...
(APOS_INCORRECT)
[typographical] ~64-~64: Caractère d’apostrophe incorrect.
Context: ...ry(), self._get_reconfigure_entry(), self._abort_if_unique_id_mismatch(), async_update_reload_and_abort(..., da...
(APOS_INCORRECT)
[typographical] ~64-~64: Caractère d’apostrophe incorrect.
Context: ... Silver reauthentication-flow et Gold reconfiguration-flow. Entries doivent être liées via `entry_...
(APOS_INCORRECT)
[typographical] ~66-~66: Caractère d’apostrophe incorrect.
Context: ...nsFlowHandler | | Config Subentries (ConfigSubentryFlow) | 2025.2 (blog 2025...
(APOS_INCORRECT)
[style] ~66-~66: Ce verbe peut être considéré comme familier dans un contexte formel.
Context: ...4 | Pertinent si un compte cloud Dreame gère plusieurs robots/hubs — permettrait de ...
(VERBES_FAMILIERS_PREMIUM)
[style] ~66-~66: Cette formulation peut être allégée afin de faciliter la lisibilité.
Context: ...oud Dreame gère plusieurs robots/hubs — permettrait de modéliser chaque robot comme sous-entrée plutôt q...
(PERMETTRAIT_DE_V_INF)
[typographical] ~67-~67: Caractère d’apostrophe incorrect.
Context: ...rée plutôt qu'un flot config unique | | **`service.async_register_platform_entity_s...
(APOS_INCORRECT)
[typographical] ~67-~67: Caractère d’apostrophe incorrect.
Context: ...ent pour les actions custom vacuum (ex: go_to, clean_zone, clean_segment) | | **D...
(APOS_INCORRECT)
[typographical] ~67-~67: Caractère d’apostrophe incorrect.
Context: ...les actions custom vacuum (ex: go_to, clean_zone, clean_segment) | | **Description pla...
(APOS_INCORRECT)
[typographical] ~67-~67: Caractère d’apostrophe incorrect.
Context: ...stom vacuum (ex: go_to, clean_zone, clean_segment) | | **Description placeholders pour tr...
(APOS_INCORRECT)
[style] ~71-~71: Un autre verbe peut sembler plus formel et professionnel.
Context: ...; les icônes d'entités/services doivent passer par icons.json plutôt que la property `ic...
(PASSER_PAR)
[typographical] ~72-~72: Caractère d’apostrophe incorrect.
Context: ...que la property icon codée en dur | | prek remplace pre-commit comme runn...
(APOS_INCORRECT)
[typographical] ~72-~72: L’écriture de cette unité de mesure semble inhabituelle.
Context: ...01-13) | Déjà fait côté ce repo (commit 81794d8 "adopt prek as the pre-commit hook run...
(ESPACE_UNITES)
[typographical] ~73-~73: Caractère d’apostrophe incorrect.
Context: ...migration de checks hassfest → pylint** (parallel-updates, diagnostics, `confi...
(APOS_INCORRECT)
[typographical] ~73-~73: Caractère d’apostrophe incorrect.
Context: ...assfest → pylint** (parallel-updates, diagnostics, config-entry-unloading, `reauthentic...
(APOS_INCORRECT)
[typographical] ~73-~73: Caractère d’apostrophe incorrect.
Context: ...t** (parallel-updates, diagnostics, config-entry-unloading, reauthentication-flow) | 2026.6 | Po...
(APOS_INCORRECT)
[typographical] ~73-~73: Caractère d’apostrophe incorrect.
Context: ...diagnostics, config-entry-unloading, reauthentication-flow`) | 2026.6 | Pour du custom (hors core),...
(APOS_INCORRECT)
[style] ~73-~73: Une phrase longue peut induire une perte de sens pour le lecteur. Celle-ci peut donc être divisée afin d’apporter de la clarté et du rythme.
Context: ...int core ne s'appliquent pas directement, mais les mêmes règles de style doivent être répl...
(POINT_MAIS)
[typographical] ~113-~113: Souhaitez-vous écrire une flèche ou le symbole « ≥ » ?
Context: ...disponible via l'UI 10. test-coverage — >95% de couverture de test sur tous les m...
(FLECHES)
[style] ~118-~118: Un autre mot peut sembler plus précis et percutant.
Context: ...— Utilise les infos de discovery pour mettre à jour les infos réseau 4.discovery` — Devic...
(METTRE_A_JOUR)
[style] ~122-~122: Un autre mot peut être plus précis.
Context: ...ocs-known-limitations— Doc décrit les limitations connues 8.docs-supported-devices` — Doc décri...
(CELEBRE)
[typographical] ~133-~133: Caractère d’apostrophe incorrect.
Context: ...-translations — Icônes via traductions (icons.json) 19. reconfiguration-flow` ...
(APOS_INCORRECT)
[typographical] ~146-~146: Caractère d’apostrophe incorrect.
Context: ...(ou migrer vers une lib MQTT async type aiomqtt), soit au minimum isoler tous les appel...
(APOS_INCORRECT)
[typographical] ~147-~147: Caractère d’apostrophe incorrect.
Context: ...quality_scale.yamlavec justification.quality_scale: gold` déclaré dans le man...
(APOS_INCORRECT)
[typographical] ~149-~149: Caractère d’apostrophe incorrect.
Context: ... pas listée nommément mais couverte par action-exceptions, entity-unavailable, `log-when-unavai...
(APOS_INCORRECT)
[typographical] ~150-~150: Caractère d’apostrophe incorrect.
Context: ... mais couverte par action-exceptions, entity-unavailable, log-when-unavailable). --- ## 5. P...
(APOS_INCORRECT)
[typographical] ~150-~150: Caractère d’apostrophe incorrect.
Context: ...tion-exceptions, entity-unavailable, log-when-unavailable`). --- ## 5. Points spécifiques vacuum...
(APOS_INCORRECT)
[typographical] ~158-~158: Caractère d’apostrophe incorrect.
Context: ...retournant un VacuumActivity(passtate), et VacuumEntityFeature` pour les fea...
(APOS_INCORRECT)
[style] ~159-~159: Ce mot apparaît déjà dans l’une des phrases précédant immédiatement celle-ci. Utilisez un synonyme pour apporter plus de variété à votre texte, excepté si la répétition est intentionnelle.
Context: ...t la priorité n°1 — l'entité vacuum est probablement cassée ou en fallback dégradé sur tou...
(FR_REPEATEDWORDS_PROBABLEMENT)
[typographical] ~161-~161: Caractère d’apostrophe incorrect.
Context: ...e install HA ≥ 2026.1. - battery_level/battery_icon sur l'entité vacuum : à so...
(APOS_INCORRECT)
[typographical] ~165-~165: Caractère d’apostrophe incorrect.
Context: ...s de nouvelle contrainte identifiée sur map_data/coordonnées de carte, actions `clean_zo...
(APOS_INCORRECT)
[typographical] ~165-~165: Caractère d’apostrophe incorrect.
Context: ...map_data/coordonnées de carte, actions clean_zone/clean_segment/go_to` au-delà du patt...
(APOS_INCORRECT)
[typographical] ~165-~165: Caractère d’apostrophe incorrect.
Context: ...rdonnées de carte, actions clean_zone/clean_segment/go_to au-delà du pattern générique "s...
(APOS_INCORRECT)
[typographical] ~165-~165: Caractère d’apostrophe incorrect.
Context: ...ttern générique "services → actions" et async_register_platform_entity_service. ### Camera - Si dreame_vacuum expos...
(APOS_INCORRECT)
[typographical] ~171-~171: Il manque une espace après le point.
Context: ... - Le rendu de carte (pillow/numpy) via camera.Image / async_camera_image doit rester **d...
(ESPACE_APRES_POINT)
[typographical] ~172-~172: Caractère d’apostrophe incorrect.
Context: ...mage doit rester **dans l'executor** (hass.async_add_executor_job`) — Pillow/n...
(APOS_INCORRECT)
[typographical] ~176-~176: Caractère d’apostrophe incorrect.
Context: ...o-mqttépinglée dansmanifest.json→requirements. Si < 2.0, planifier la migration ...
(APOS_INCORRECT)
[typographical] ~176-~176: Caractère d’apostrophe incorrect.
Context: ...ns manifest.json → requirements. Si < 2.0, planifier la migration `CallbackAPIV...
(APOS_INCORRECT)
[typographical] ~180-~180: Caractère d’apostrophe incorrect.
Context: ...ad — s'assurer que tous les callbacks (on_message, on_connect, etc.) qui tou...
(APOS_INCORRECT)
[typographical] ~180-~180: Caractère d’apostrophe incorrect.
Context: ...que tous les callbacks (on_message, on_connect, etc.) qui touchent l'état HA passent b...
(APOS_INCORRECT)
[typographical] ~181-~181: Caractère d’apostrophe incorrect.
Context: ...hass.loop.call_soon_threadsafe(...)ouasync_add_executor_job`, jamais d'appel direct à des coroutin...
(APOS_INCORRECT)
[typographical] ~182-~182: Il manque une espace après le point.
Context: ...amais d'appel direct à des coroutines/hass.states depuis le thread paho. - C'est ce patt...
(ESPACE_APRES_POINT)
[typographical] ~191-~191: Caractère d’apostrophe incorrect.
Context: ...: englober tout appel requests.* dans await hass.async_add_executor_job(...). - Recommandation cible : migrer vers `...
(APOS_INCORRECT)
[typographical] ~193-~193: Caractère d’apostrophe incorrect.
Context: ...ce systématique de HA, réutilisable via aiohttp_client.async_get_clientsession(hass)) ou httpx.AsyncClient, ce qui débloqu...
(APOS_INCORRECT)
[typographical] ~194-~194: Caractère d’apostrophe incorrect.
Context: ...ient.async_get_clientsession(hass)) ou httpx.AsyncClient, ce qui débloque aussi inject-webses...
(APOS_INCORRECT)
[style] ~203-~203: Préférez la voix active à une structure impersonnelle pour apporter du rythme à votre phrase.
Context: .... Si le refactor adopte ces patterns, il faut remonter le minimum HA en conséquence (au minimu...
(IL_FAUT_QUE)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/overhaul/ha-backend-state-of-art-2026-07-02.md` around lines 12 - 205,
The markdown content in this document still triggers codespell, so normalize the
prose to remove or correct misspelled terms and nonstandard spellings throughout
the affected sections, using the document’s existing headings and lists as
anchors. Check the repeated technical phrases and acronyms in the overview and
quality-scale sections, and if any intentional domain terms must remain, add
them to the repo’s codespell whitelist or exclusion rather than leaving raw
failures in the text.
Source: Pipeline failures
| def test_decode_legacy_funiture_info_format(): | ||
| """The legacy 'funiture_info' payload (furniture_version=1) swaps type 8<->25 and reads absolute rect fields.""" | ||
| header = build_header(width=0, height=0) | ||
| furniture = [11, 8, 3, 40, 60, 0, 500, 600, 0, 45.0, 0, 0, 1.5, 2] | ||
| partial = make_partial(header, b"", {"funiture_info": [furniture]}) | ||
|
|
||
| map_data, _ = DreameVacuumMapDecoder.decode_map_data_from_partial(partial, False) | ||
|
|
||
| assert map_data.furniture_version == 1 | ||
| f = map_data.saved_furnitures[1] | ||
| assert (f.x, f.y) == (500, 600) | ||
| assert (f.x0, f.y0) == (480, 570) | ||
| assert (f.width, f.height) == (40, 60) | ||
| assert f.type == FurnitureType.ROUND_COFFEE_TABLE # type 8 swapped to 25 | ||
| assert f.size_type == 2 | ||
| assert f.angle == 45.0 | ||
| assert f.scale == 1.5 | ||
| assert f.furniture_id == 11 | ||
| assert f.segment_id == 3 | ||
|
|
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Pre-commit CI failure: comment triggers python-use-type-annotations hook.
Line 601's # type 8 swapped to 25 comment is flagged by the pre-commit hook as an old-style type comment, failing CI. Reword the comment to avoid the pattern.
🔧 Proposed fix
- assert f.type == FurnitureType.ROUND_COFFEE_TABLE # type 8 swapped to 25
+ assert f.type == FurnitureType.ROUND_COFFEE_TABLE # furniture code 8 remapped to 25📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def test_decode_legacy_funiture_info_format(): | |
| """The legacy 'funiture_info' payload (furniture_version=1) swaps type 8<->25 and reads absolute rect fields.""" | |
| header = build_header(width=0, height=0) | |
| furniture = [11, 8, 3, 40, 60, 0, 500, 600, 0, 45.0, 0, 0, 1.5, 2] | |
| partial = make_partial(header, b"", {"funiture_info": [furniture]}) | |
| map_data, _ = DreameVacuumMapDecoder.decode_map_data_from_partial(partial, False) | |
| assert map_data.furniture_version == 1 | |
| f = map_data.saved_furnitures[1] | |
| assert (f.x, f.y) == (500, 600) | |
| assert (f.x0, f.y0) == (480, 570) | |
| assert (f.width, f.height) == (40, 60) | |
| assert f.type == FurnitureType.ROUND_COFFEE_TABLE # type 8 swapped to 25 | |
| assert f.size_type == 2 | |
| assert f.angle == 45.0 | |
| assert f.scale == 1.5 | |
| assert f.furniture_id == 11 | |
| assert f.segment_id == 3 | |
| def test_decode_legacy_funiture_info_format(): | |
| """The legacy 'funiture_info' payload (furniture_version=1) swaps type 8<->25 and reads absolute rect fields.""" | |
| header = build_header(width=0, height=0) | |
| furniture = [11, 8, 3, 40, 60, 0, 500, 600, 0, 45.0, 0, 0, 1.5, 2] | |
| partial = make_partial(header, b"", {"funiture_info": [furniture]}) | |
| map_data, _ = DreameVacuumMapDecoder.decode_map_data_from_partial(partial, False) | |
| assert map_data.furniture_version == 1 | |
| f = map_data.saved_furnitures[1] | |
| assert (f.x, f.y) == (500, 600) | |
| assert (f.x0, f.y0) == (480, 570) | |
| assert (f.width, f.height) == (40, 60) | |
| assert f.type == FurnitureType.ROUND_COFFEE_TABLE # furniture code 8 remapped to 25 | |
| assert f.size_type == 2 | |
| assert f.angle == 45.0 | |
| assert f.scale == 1.5 | |
| assert f.furniture_id == 11 | |
| assert f.segment_id == 3 |
🧰 Tools
🪛 GitHub Actions: CI / 2_Pre-commit (prek).txt
[error] 601-601: pre-commit hook 'python-use-type-annotations' failed (exit code 1). Type annotations are required at: 'assert f.type == FurnitureType.ROUND_COFFEE_TABLE # type 8 swapped to 25'.
🪛 GitHub Actions: CI / Pre-commit (prek)
[error] 601-601: pre-commit hook python-use-type-annotations (type annotations not comments) failed (exit code 1). Offending code: "assert f.type == FurnitureType.ROUND_COFFEE_TABLE # type 8 swapped to 25".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/test_map_decoder_paths.py` around lines 588 - 607, The inline comment
in test_decode_legacy_funiture_info_format is being misread by the
python-use-type-annotations hook as an old-style type comment. Reword or remove
the phrasing in that assertion comment so it no longer starts with “type 8,”
while keeping the note that legacy furniture type 8 maps to ROUND_COFFEE_TABLE.
Focus on the comment text only; no test logic changes are needed.
Source: Pipeline failures
- Migrate OptionsFlow to OptionsFlowWithReload (native config_entry property, automatic reload), replacing the deprecated constructor pattern and the manual add_update_listener/update_listener combo - Unsubscribe dynamic-entity coordinator listeners on unload via entry.async_on_unload (number, button, select, camera) — previously leaked across config entry reloads
- map_optimizer: drop the never-invoked pure-Python fallback (~1200 lines duplicating the MiniRacer JS algorithm) and the js_optimizer parameter; the JS path is the only production path - map_manager: drop unused _request_t_map/_request_w_map, harmonize threading.Timer import - resources: drop unused clear_cache/get_cache_stats - device_setters: drop dead _update_self_clean_time twin and the commented-out AI privacy block - device_status/_core: drop unused _LOGGER and 24 no-op 'if value is not None: pass' vestiges - const: drop unused CONF_TYPE; dreame/const: drop duplicated CLEAN_TANK_LEVEL mapping entry - device_info: place module docstring before __future__ import so it is an actual docstring - recorder: fix carpet_sensivity_list typo (exclusion was inoperative) - vacuum: extract the 32 entity-service registrations into _async_register_services() (async_setup_entry 471 -> 12 lines) - repo: delete obsolete CI_STATUS.md, merge requirements_dev.txt into requirements-dev.txt
- protocol: fix set_credentials bytes-vs-str comparison that reset the local connection on every call even with identical credentials - protocol: add jitter to the retry backoff via a shared resilience.backoff_delay() (was duplicated inline 4x without jitter) - protocol: truncate HTTP failure bodies in DEBUG logs (2 sites) - map_manager: release _request_queue keys on failure (a failed map_id/frame_id request could never be retried) - map_manager: one corrupted saved map no longer aborts the whole map-list processing (return -> continue, 2 sites) - map_manager: purge expired entries from the _file_urls cache (unbounded growth, object names change with every map update) - map_decoder: stop logging full raw maps / map JSON payloads in DEBUG - map_data_json_renderer: guard against KeyError when the IMAGE layer has not been built yet - map_optimizer: add close() and release the V8 context on unload - resilience/exceptions: drop dead CircuitBreaker.check(), retry_with_backoff(), AuthenticationError, InvalidResponseError, CircuitOpenError (never raised/called anywhere) - manifest: pin paho-mqtt<3.0 (CallbackAPIVersion.VERSION1 is removed in paho 3.0; VERSION2 migration deliberately deferred)
- camera: run device.get_map_for_render (may trigger the V8 map optimizer and deep copies) in the executor on all 4 async call sites (live image, history, recovery, wifi map) - map_renderer: cache the encoded PNG of default_map_image and disconnected_map_image; both properties are read from the event loop and previously re-encoded (and re-blurred) on every access - binary_sensor: fix overlong comment (last ruff E501) Verified: battery is already exposed as a dedicated battery-class sensor and the vacuum entity never sets battery_level, so the HA 2026.8 StateVacuumEntity.battery_level removal does not affect this integration.
- config_flow: replace bare voluptuous markers with modern selectors (TextSelector, password-typed credential fields, dropdown SelectSelector for countries/color schemes/icon sets/devices, multi-select SelectSelector for notifications/hidden map objects, BooleanSelector for toggles) - translations: add the 7 missing keys (vector_rooms option, segments_changed repair issue) to the 18 out-of-sync languages with native translations; all 20 languages now at strict key parity with strings.json
- add 41 missing docstrings across the HA layer (camera, coordinator, config_flow, vacuum, select, number, button, entity) - add quality_scale.yaml with honest per-rule statuses (documented todos: action-setup, lib test-coverage, full strict-typing; justified exemptions: discovery, async-dependency) - hacs.json: raise minimum Home Assistant to 2025.8.0 (OptionsFlowWithReload) - dreame/const: add Final to the 5 remaining module-level mappings - ruff format drift fixed on 4 files Validated: ruff check+format clean, mypy ratchet green (51 files), hassfest 0 invalid, 972 tests green
- camera: 63% -> 100% (all 7 HTTP views with real aiohttp response assertions, still stream, proxy caches, extra_state_attributes) - new test_device_setters (90) / test_device_actions (44): optimistic update + rollback semantics, reflection dispatch, HH:MM parsing, zone/segment/spot payloads, all 14 consumable resets - new test_map_manager (11) / test_map_optimizer (9): lock the Phase 4 fixes (request-queue release on failure, expired URL purge, corrupted-map continue, optimizer.close) and exercise the real V8 optimize path - suite hygiene: drop dead conftest fixtures, ~25 existence-only tests, the never-injected mock_device_for_status fixture; replace with real device_status behaviour tests; platform imports now fail loudly instead of silently skipping - coverage: 38.5% -> 46.0% global, HA layer 100% everywhere (entity.py 99%); raise coverage fail_under 35 -> 45
- CHANGELOG: full [Unreleased] section covering the overhaul - ARCHITECTURE: coverage figures updated (HA layer 100%), executor invariant of the V8/PIL map pipeline documented, quality_scale.yaml referenced - README: fix the iot_class description (cloud push over MQTT, not cloud polling) - docs/overhaul: archive after-measurements (perf, unique_ids) - remove the overhaul working-state file
- new services.py: all 39 entity services (34 vacuum, 4 select, 1 camera) registered once from the integration's async_setup via service.async_register_platform_entity_service (HA 2025.9+), with entity methods referenced by name so no platform module is imported at setup time - vacuum/select/camera platform setups no longer register services - __init__: add async_setup + CONFIG_SCHEMA (config-entry-only) - declare the previously undocumented vacuum_set_property and vacuum_call_action services in services.yaml, strings.json, icons.json and all 20 translations (native wording) - quality_scale.yaml: action-setup -> done - tests: new test_services.py (6 tests incl. services.yaml parity); platform tests updated
- Client is created with VERSION2; the dead paho 1.x branch is gone - on_connect/on_disconnect use the v2 signatures and ReasonCode - the auth-refused relogin moved from on_disconnect (where the v3->v5 mapping collapses everything to 'Unspecified error') to on_connect, where 'Not authorized' (135) is precise - keep paho-mqtt pinned <3.0 until 3.0 ships and is validated Verified live on HA dev 2026.7: MQTT connects (paho v2 thread), subscribes and receives map pushes; 0 errors.
- test_device_status_core.py: 331 cases over the 198 status properties (_core 63%, _consumables 100%, _station 100%) - test_map_renderer.py: full render_map pipeline on synthetic maps with exact RGBA pixel asserts (_core 38%, _helpers 95%, _shapes 98%, _objects 59%), byte-cache identity checks for default/disconnected images - test_map_data_json_renderer.py: Valetudo JSON in zTXt chunk verified point by point incl. exact RLE arrays (100%), KeyError regression locked
- test_map_decoder_paths.py: 43 tests on synthetic wire-format payloads (struct header + zlib + base64, AES-CBC path included) — decoder 18% -> 81% - test_map_editor.py (51) / test_device_map_ops.py (79): optimistic map edits, merge/split on real numpy grids, get_map_for_render branches, CRUD delegations — editor 9% -> 50%, map ops 6% -> 45% - test_device_core.py (85): listeners/debounce, 50-item property batching, dynamic update intervals, credential redaction (caplog), consumable request paths — device.py 24% -> 50% - coverage: global 46% -> 66%; raise fail_under 45 -> 65
- HA >= 2025.8 requires Python >= 3.13; on 3.12 pip resolves an older Home Assistant lacking async_register_platform_entity_service - the mypy job must match HA's target runtime (3.14 resolves an HA build with 3.14-only syntax that mypy python_version 3.13 rejects) - codespell: skip docs/overhaul in both walk and explicit-path modes - reword a comment that tripped python-use-type-annotations
bc26d79 to
6221fa8
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Résumé
Remise à niveau complète de l'intégration (15 commits, passes successives déployées et vérifiées une à une sur HA dev 2026.7) :
Modernisation HA
OptionsFlowWithReload(pattern déprécié supprimé), selectors modernes sur tout le config flowasync_setup(règleaction-setup, API 2025.9) —vacuum_set_property/vacuum_call_actionenfin déclarés et traduitsCallbackAPIVersion.VERSION2(vérifié en direct)quality_scale.yamlavec statuts honnêtes ; HA min : 2023.6 → 2025.8Robustesse & bugs
set_credentialsbytes≠str, 4 listeners fuités au reload, KeyError du renderer JSON, typo recorder, PNG ré-encodé sur l'event loop,optimize()V8 inline en coroutine (×4)Nettoyage
Tests
Garanties
Baselines et mesures archivées dans
docs/overhaul/.Summary by CodeRabbit
New Features
Bug Fixes