Compare commits
4 Commits
fafcf116be
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e3b9b123f2 | |||
| b7006c5f41 | |||
| 3355f0dda8 | |||
| c8ab66caf3 |
@@ -0,0 +1,57 @@
|
|||||||
|
# vex configuration — https://github.com/tenatarika/vex
|
||||||
|
#
|
||||||
|
# Place this file in your project root as .vex.toml
|
||||||
|
|
||||||
|
# Glob patterns to exclude from indexing (gitignore syntax, on top of .gitignore)
|
||||||
|
# exclude = [
|
||||||
|
# "vendor/**",
|
||||||
|
# "node_modules/**",
|
||||||
|
# "*.generated.go",
|
||||||
|
# "dist/**",
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# Default output format: "text", "json", or "compact"
|
||||||
|
# format = "text"
|
||||||
|
|
||||||
|
# Enable semantic embeddings by default (slower indexing, enables meaning-based search)
|
||||||
|
semantic = true
|
||||||
|
|
||||||
|
# Automatically run `vex update` before search if the index is stale
|
||||||
|
auto_update = true
|
||||||
|
|
||||||
|
# Embedder used for semantic indexing. Known IDs: minilm-l6-v2 (default).
|
||||||
|
# Changing the embedder requires a full reindex.
|
||||||
|
# embedder = "minilm-l6-v2"
|
||||||
|
|
||||||
|
# Cache directory override. Defaults to the platform cache location.
|
||||||
|
# macOS: ~/Library/Caches/vex
|
||||||
|
# Linux: $XDG_CACHE_HOME/vex (fallback: ~/.cache/vex)
|
||||||
|
# Windows: %LOCALAPPDATA%\vex (fallback: %USERPROFILE%\AppData\Local\vex)
|
||||||
|
# Accepts absolute paths, "~/..." or paths relative to this file (e.g. "./.vex/cache").
|
||||||
|
# Can also be overridden per-invocation with --cache-dir or $VEX_CACHE_DIR.
|
||||||
|
# cache_dir = "./.vex/cache"
|
||||||
|
|
||||||
|
# Store the index inside the project as `<project>/.vex_cache/`. Useful when
|
||||||
|
# the cache should travel with the project (e.g. on a moved or renamed
|
||||||
|
# directory). vex writes a `.gitignore` inside it so contents are not
|
||||||
|
# committed. Overridden by `cache_dir`, `--cache-dir`, or $VEX_CACHE_DIR.
|
||||||
|
# local_cache = false
|
||||||
|
|
||||||
|
# Thread count for parallel indexing (index/update/watch).
|
||||||
|
# * unset — 80% of available cores, rounded up (default, leaves headroom)
|
||||||
|
# * 0 — use all cores (explicit opt-in to max throughput)
|
||||||
|
# * N — exactly N workers
|
||||||
|
# Overridable per-invocation with `-j/--jobs` or $VEX_JOBS.
|
||||||
|
# jobs = 4
|
||||||
|
|
||||||
|
# Build the persistent call-graph section. Disabling falls back to live-scan
|
||||||
|
# for `vex callers`/`vex callees` (slower per-query, but saves indexing
|
||||||
|
# time on large monorepos). The opt-out is persisted in the manifest so
|
||||||
|
# `vex update` does not silently re-add the section.
|
||||||
|
# Per-invocation override: `vex index --no-call-graph`.
|
||||||
|
# call_graph = true
|
||||||
|
|
||||||
|
# Build the BM25 channel. Disabling drops the third RRF channel and keeps
|
||||||
|
# only structural (+ semantic). Same persistence rules as `call_graph`.
|
||||||
|
# Per-invocation override: `vex index --no-bm25`.
|
||||||
|
# bm25 = true
|
||||||
+124
-17
@@ -8,8 +8,10 @@ Sends customizable notifications for Dreame vacuum events. Requires the [Dreame
|
|||||||
- Consumable end-of-life alerts (brush, filter, mop pad, sensor, etc.)
|
- Consumable end-of-life alerts (brush, filter, mop pad, sensor, etc.)
|
||||||
- Device warning and error notifications
|
- Device warning and error notifications
|
||||||
- Informational alerts (e.g., action blocked by Do Not Disturb)
|
- Informational alerts (e.g., action blocked by Do Not Disturb)
|
||||||
|
- Friendly, readable labels for cleaning mode and status (raw enum names are translated)
|
||||||
|
- Optional localization: override any label, and map numeric codes to your own text
|
||||||
- Individual toggle for each event type
|
- Individual toggle for each event type
|
||||||
- Per-code filter lists for silencing routine warnings, errors, or info messages
|
- Per-code/per-type filter lists for silencing routine warnings, errors, or info messages
|
||||||
- Customizable message templates
|
- Customizable message templates
|
||||||
- Multiple notification targets
|
- Multiple notification targets
|
||||||
|
|
||||||
@@ -25,12 +27,16 @@ The blueprint listens to events fired by the Dreame Vacuum integration:
|
|||||||
| `dreame_vacuum_error` | Device fault |
|
| `dreame_vacuum_error` | Device fault |
|
||||||
| `dreame_vacuum_information` | Action blocked by user settings |
|
| `dreame_vacuum_information` | Action blocked by user settings |
|
||||||
|
|
||||||
Events are filtered by the configured vacuum:
|
### Matching the configured vacuum
|
||||||
|
|
||||||
1. If the event payload includes `device_id`, it must match the device of the configured vacuum entity. This is the most reliable match.
|
The integration fires every event with an `entity_id` that it derives from the vacuum's **device name** (via `generate_entity_id()`); events do **not** carry a `device_id`. Matching therefore accepts:
|
||||||
2. Otherwise the entity_id in the event must equal the configured one, or equal it followed by a purely numeric suffix (e.g., `vacuum.dreame_x10_2`). The integration uses `generate_entity_id()`, so a numeric suffix can appear when the base entity_id is taken.
|
|
||||||
|
|
||||||
This avoids false positives when two vacuums share an entity_id prefix (e.g., `vacuum.dreame_x10` vs. `vacuum.dreame_x10_pro`).
|
1. The event `entity_id` exactly equal to the configured entity.
|
||||||
|
2. The configured entity followed by a purely numeric suffix (e.g. `vacuum.dreame_x10_2`) — `generate_entity_id()` adds such a suffix when the base id is already taken.
|
||||||
|
|
||||||
|
Non-numeric suffixes (e.g. `_pro`) are rejected, so `vacuum.dreame_x10` will not match `vacuum.dreame_x10_pro`.
|
||||||
|
|
||||||
|
> **Note:** because the fired `entity_id` is derived from the device name, if you rename the vacuum's entity_id in Home Assistant so it no longer matches the auto-generated id, matching can fail and notifications stop. Keep the integration-generated entity_id (or rename the *device* instead of the entity) for reliable matching.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
@@ -39,12 +45,15 @@ This avoids false positives when two vacuums share an entity_id prefix (e.g., `v
|
|||||||
| **Vacuum Entity** | The Dreame vacuum entity to monitor |
|
| **Vacuum Entity** | The Dreame vacuum entity to monitor |
|
||||||
| **Notification Targets** | One or more `notify` entities |
|
| **Notification Targets** | One or more `notify` entities |
|
||||||
| **Event Toggles** | Enable/disable each event type independently |
|
| **Event Toggles** | Enable/disable each event type independently |
|
||||||
| **Filtering** | Lists of warning/error/information codes to silence |
|
| **Filtering** | Lists of warning/error codes and information types to silence |
|
||||||
| **Message Templates** | Customizable message for each event type |
|
| **Message Templates** | Customizable message for each event type |
|
||||||
|
| **Localization** | Optional label and code translation tables (see [Localization](#localization)) |
|
||||||
|
|
||||||
### Filtering
|
### Filtering
|
||||||
|
|
||||||
Each filter input is a list of codes (as strings) that should not produce a notification. The blueprint compares the event's `code` field (cast to string) against the list. Use this to suppress noisy routine events while keeping critical ones.
|
- **Warning Codes / Error Codes to Ignore** — compared against the event's numeric `code`. Enter the code as text (e.g. `68`).
|
||||||
|
- **Information Types to Ignore** — information events carry a *type id*, not a numeric code; enter the id (`dust_collection`, `cleaning_paused`).
|
||||||
|
- The two temporary-map warnings (new-map / replace-temporary-map) carry **no** code. The spurious "map cleared" warning is suppressed automatically; the genuine "new map generated" warning can be filtered by its text if needed.
|
||||||
|
|
||||||
## Message Template Variables
|
## Message Template Variables
|
||||||
|
|
||||||
@@ -53,16 +62,16 @@ Each filter input is a list of codes (as strings) that should not produce a noti
|
|||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `{vacuum_name}` | Friendly name of the vacuum |
|
| `{vacuum_name}` | Friendly name of the vacuum |
|
||||||
| `{cleaning_mode}` | Cleaning mode (e.g., sweeping, mopping) |
|
| `{cleaning_mode}` | Cleaning mode, friendly-formatted (e.g., Sweeping, Mopping, Sweeping & Mopping) |
|
||||||
| `{status}` | Current status |
|
| `{status}` | Current status, friendly-formatted (e.g., Cleaning, Room cleaning) |
|
||||||
|
|
||||||
### Cleaning Completed
|
### Cleaning Completed
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `{vacuum_name}` | Friendly name of the vacuum |
|
| `{vacuum_name}` | Friendly name of the vacuum |
|
||||||
| `{cleaning_mode}` | Cleaning mode used |
|
| `{cleaning_mode}` | Cleaning mode used, friendly-formatted |
|
||||||
| `{status}` | Final status |
|
| `{status}` | Final status, friendly-formatted |
|
||||||
| `{cleaned_area}` | Area cleaned (m²) |
|
| `{cleaned_area}` | Area cleaned (m²) |
|
||||||
| `{cleaning_time}` | Cleaning duration (minutes) |
|
| `{cleaning_time}` | Cleaning duration (minutes) |
|
||||||
|
|
||||||
@@ -78,16 +87,18 @@ Each filter input is a list of codes (as strings) that should not produce a noti
|
|||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `{vacuum_name}` | Friendly name of the vacuum |
|
| `{vacuum_name}` | Friendly name of the vacuum |
|
||||||
| `{warning}` | Warning description |
|
| `{warning}` | Warning description (already human-readable English from the integration) |
|
||||||
| `{code}` | Warning code |
|
| `{code}` | Numeric warning code (empty for the temporary-map warning) |
|
||||||
|
| `{code_name}` | Optional label for the code — empty unless you fill the code table (see [Localization](#localization)) |
|
||||||
|
|
||||||
### Error
|
### Error
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `{vacuum_name}` | Friendly name of the vacuum |
|
| `{vacuum_name}` | Friendly name of the vacuum |
|
||||||
| `{error}` | Error description |
|
| `{error}` | Error description (already human-readable English from the integration) |
|
||||||
| `{code}` | Error code |
|
| `{code}` | Numeric error code |
|
||||||
|
| `{code_name}` | Optional label for the code — empty unless you fill the code table (see [Localization](#localization)) |
|
||||||
|
|
||||||
### Information
|
### Information
|
||||||
|
|
||||||
@@ -95,12 +106,108 @@ Each filter input is a list of codes (as strings) that should not produce a noti
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `{vacuum_name}` | Friendly name of the vacuum |
|
| `{vacuum_name}` | Friendly name of the vacuum |
|
||||||
| `{information}` | Information message (e.g., Dust Collection, Cleaning Paused) |
|
| `{information}` | Information message (e.g., Dust Collection, Cleaning Paused) |
|
||||||
| `{code}` | Information code |
|
|
||||||
|
> The default warning/error templates show `(code: {code})`. When an event has no code, the blueprint automatically strips the empty `(code: )` parenthetical.
|
||||||
|
|
||||||
|
## Friendly Labels
|
||||||
|
|
||||||
|
`{cleaning_mode}` and `{status}` arrive from the integration as raw `UPPER_SNAKE_CASE` enum names; the blueprint translates them to readable text. Any value not in the tables below falls back to a generic humanizer (underscores → spaces, capitalized). All labels can be overridden — see [Localization](#localization).
|
||||||
|
|
||||||
|
### Cleaning Mode (`{cleaning_mode}`)
|
||||||
|
|
||||||
|
| Raw enum | Friendly label |
|
||||||
|
| --- | --- |
|
||||||
|
| `UNKNOWN` | Unknown |
|
||||||
|
| `SWEEPING` | Sweeping |
|
||||||
|
| `MOPPING` | Mopping |
|
||||||
|
| `SWEEPING_AND_MOPPING` | Sweeping & Mopping |
|
||||||
|
|
||||||
|
### Status (`{status}`)
|
||||||
|
|
||||||
|
| Raw enum | Friendly label |
|
||||||
|
| --- | --- |
|
||||||
|
| `IDLE` | Idle |
|
||||||
|
| `PAUSED` | Paused |
|
||||||
|
| `CLEANING` | Cleaning |
|
||||||
|
| `BACK_HOME` | Returning to dock |
|
||||||
|
| `PART_CLEANING` | Spot cleaning |
|
||||||
|
| `FOLLOW_WALL` | Following wall |
|
||||||
|
| `CHARGING` | Charging |
|
||||||
|
| `OTA` | Updating firmware |
|
||||||
|
| `WIFI_SET` | Wi-Fi setup |
|
||||||
|
| `POWER_OFF` | Powered off |
|
||||||
|
| `ERROR` | Error |
|
||||||
|
| `REMOTE_CONTROL` | Remote control |
|
||||||
|
| `SLEEPING` | Sleeping |
|
||||||
|
| `STANDBY` | Standby |
|
||||||
|
| `SEGMENT_CLEANING` | Room cleaning |
|
||||||
|
| `ZONE_CLEANING` | Zone cleaning |
|
||||||
|
| `SPOT_CLEANING` | Spot cleaning |
|
||||||
|
| `FAST_MAPPING` | Mapping |
|
||||||
|
| `MONITOR_CRUISE` | Patrolling |
|
||||||
|
| `MONITOR_SPOT` | Spot monitoring |
|
||||||
|
| `SUMMON_CLEAN` | Summon clean |
|
||||||
|
|
||||||
|
(Also mapped: `FCT`, `FACTORY`, `SELF_TEST`, `FACTORY_FUNCION_TEST` — diagnostic states.)
|
||||||
|
|
||||||
|
### Consumable (`{consumable}`) and Information (`{information}`)
|
||||||
|
|
||||||
|
| Raw id | Friendly label |
|
||||||
|
| --- | --- |
|
||||||
|
| `main_brush` | Main Brush |
|
||||||
|
| `side_brush` | Side Brush |
|
||||||
|
| `filter` | Filter |
|
||||||
|
| `sensor` | Sensor |
|
||||||
|
| `mop_pad` | Mop Pad |
|
||||||
|
| `silver_ion` | Silver Ion |
|
||||||
|
| `detergent` | Detergent |
|
||||||
|
| `dust_collection` | Dust Collection |
|
||||||
|
| `cleaning_paused` | Cleaning Paused |
|
||||||
|
|
||||||
|
## Localization
|
||||||
|
|
||||||
|
Two optional inputs (under **Localization**) let you relabel or translate any value without editing the blueprint. Both are entered as YAML key/value pairs (the object selector).
|
||||||
|
|
||||||
|
**Label Overrides** — keys are the raw values the integration emits (cleaning-mode/status are `UPPER_SNAKE` enum names; consumable/information are lower-case ids). Applied to `{cleaning_mode}`, `{status}`, `{consumable}`, and `{information}`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
SWEEPING_AND_MOPPING: Подметание и мытьё
|
||||||
|
CLEANING: Уборка
|
||||||
|
BACK_HOME: Возврат на базу
|
||||||
|
dust_collection: Очистка контейнера
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warning/Error Code Labels** — keys are numeric codes (unquoted); the value is exposed as `{code_name}`. Leave empty to omit `{code_name}`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
68: Снять швабру
|
||||||
|
47: Робот застрял
|
||||||
|
```
|
||||||
|
|
||||||
|
Lookup order for every value is: your override → built-in friendly label → generic humanizer.
|
||||||
|
|
||||||
|
A ready-to-paste **Russian** starter table (all statuses, modes, consumables, information types, and warning/error codes) is provided in [localization.ru.yaml](localization.ru.yaml) — copy each section into the matching Localization input. To show fully Russian warning/error text, reference `{code_name}` in your warning/error templates instead of the English `{warning}`/`{error}`.
|
||||||
|
|
||||||
|
> No built-in numeric-code → name table is shipped, because code meanings can differ between integration versions. The `{warning}` / `{error}` text already comes from your installed integration (so it is always correct); use `{code_name}` only if you want a short, localized tag for specific codes.
|
||||||
|
|
||||||
|
### Warning vs. Error Codes
|
||||||
|
|
||||||
|
The integration classifies a fault as a dismissible **warning** only for the codes below; every other fault with a positive code (except battery-low) is reported as an **error** and carries a numeric `{code}` you can paste into **Error Codes to Ignore**.
|
||||||
|
|
||||||
|
| Code | Name |
|
||||||
|
| --- | --- |
|
||||||
|
| 47 | Blocked |
|
||||||
|
| 68 | Remove mop |
|
||||||
|
| 70 | Mop removed |
|
||||||
|
| 71 | Mop pad stopped rotating |
|
||||||
|
| 72 | Mop pad stopped rotating |
|
||||||
|
| 107 | Water tank dry |
|
||||||
|
| 114 | Clean mop pad |
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- The default messages contain emojis. Most modern notify integrations (Mobile App, Telegram, Discord) render them correctly; legacy SMS-based integrations may not.
|
- The default messages contain emojis. Most modern notify integrations (Mobile App, Telegram, Discord) render them correctly; legacy SMS-based integrations may not.
|
||||||
- `notify.send_message` requires Home Assistant 2024.7 or newer.
|
- `notify.send_message` requires Home Assistant 2024.7 or newer. It accepts only a `message` (no title/tag); put any emphasis directly in the message text.
|
||||||
|
|
||||||
## Debug Mode
|
## Debug Mode
|
||||||
|
|
||||||
|
|||||||
@@ -123,9 +123,11 @@ blueprint:
|
|||||||
multiple: true
|
multiple: true
|
||||||
|
|
||||||
information_codes_ignore:
|
information_codes_ignore:
|
||||||
name: Information Codes to Ignore
|
name: Information Types to Ignore
|
||||||
description: >
|
description: >
|
||||||
List of information codes to silence (one entry per code, as text).
|
List of information message types to silence (one entry per type).
|
||||||
|
Information events carry a type id, not a numeric code.
|
||||||
|
Valid values: dust_collection, cleaning_paused.
|
||||||
default: []
|
default: []
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
@@ -173,7 +175,7 @@ blueprint:
|
|||||||
name: "Warning Message"
|
name: "Warning Message"
|
||||||
description: >
|
description: >
|
||||||
Message sent for device warnings.
|
Message sent for device warnings.
|
||||||
Variables: `{vacuum_name}`, `{warning}`, `{code}`
|
Variables: `{vacuum_name}`, `{warning}`, `{code}`, `{code_name}`
|
||||||
default: "⚠️ {vacuum_name} warning: {warning} (code: {code})."
|
default: "⚠️ {vacuum_name} warning: {warning} (code: {code})."
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
@@ -183,7 +185,7 @@ blueprint:
|
|||||||
name: "Error Message"
|
name: "Error Message"
|
||||||
description: >
|
description: >
|
||||||
Message sent for device errors.
|
Message sent for device errors.
|
||||||
Variables: `{vacuum_name}`, `{error}`, `{code}`
|
Variables: `{vacuum_name}`, `{error}`, `{code}`, `{code_name}`
|
||||||
default: "❌ {vacuum_name} error: {error} (code: {code})."
|
default: "❌ {vacuum_name} error: {error} (code: {code})."
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
@@ -193,12 +195,48 @@ blueprint:
|
|||||||
name: "Information Message"
|
name: "Information Message"
|
||||||
description: >
|
description: >
|
||||||
Message sent for informational alerts.
|
Message sent for informational alerts.
|
||||||
Variables: `{vacuum_name}`, `{information}`, `{code}`
|
Variables: `{vacuum_name}`, `{information}`
|
||||||
default: "ℹ️ {vacuum_name}: {information}."
|
default: "ℹ️ {vacuum_name}: {information}."
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
multiline: true
|
multiline: true
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Localization / Label Overrides
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
localization_group:
|
||||||
|
name: "Localization"
|
||||||
|
collapsed: true
|
||||||
|
input:
|
||||||
|
label_overrides:
|
||||||
|
name: "Label Overrides"
|
||||||
|
description: >
|
||||||
|
Optional translation/relabel table for dynamic values, as YAML
|
||||||
|
key/value pairs. Keys are the raw values the integration emits
|
||||||
|
(cleaning mode / status are UPPER_SNAKE enum names; consumable /
|
||||||
|
information are lower-case ids); values are your preferred text in
|
||||||
|
any language. Applied to {cleaning_mode}, {status}, {consumable}
|
||||||
|
and {information}. Example:
|
||||||
|
SWEEPING_AND_MOPPING: Подметание и мытьё
|
||||||
|
CLEANING: Уборка
|
||||||
|
BACK_HOME: Возврат на базу
|
||||||
|
dust_collection: Очистка контейнера
|
||||||
|
default: {}
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
|
||||||
|
code_label_overrides:
|
||||||
|
name: "Warning/Error Code Labels"
|
||||||
|
description: >
|
||||||
|
Optional table mapping a numeric warning/error code to a short
|
||||||
|
label, exposed as the {code_name} placeholder. Leave empty to omit
|
||||||
|
{code_name}. Use unquoted numbers as keys. Example:
|
||||||
|
68: Снять швабру
|
||||||
|
47: Робот застрял
|
||||||
|
default: {}
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Debug
|
# Debug
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
@@ -215,9 +253,10 @@ blueprint:
|
|||||||
selector:
|
selector:
|
||||||
boolean:
|
boolean:
|
||||||
|
|
||||||
# Queued mode to avoid dropping rapid events
|
# Queued mode to avoid dropping rapid events. A single cleanup-completion pass
|
||||||
|
# can fire up to 8 events (1 task_status + 7 consumables), so queue up to 10.
|
||||||
mode: queued
|
mode: queued
|
||||||
max: 5
|
max: 10
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# TRIGGERS
|
# TRIGGERS
|
||||||
@@ -254,13 +293,12 @@ trigger:
|
|||||||
variables:
|
variables:
|
||||||
# Bumped whenever event-handling logic changes; surfaced in debug output
|
# Bumped whenever event-handling logic changes; surfaced in debug output
|
||||||
# so users can confirm which revision is running.
|
# so users can confirm which revision is running.
|
||||||
blueprint_version: "1.1.1"
|
blueprint_version: "1.2.1"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Input References
|
# Input References
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
vacuum_entity: !input vacuum_entity
|
vacuum_entity: !input vacuum_entity
|
||||||
notify_targets: !input notify_targets
|
|
||||||
enable_debug_notifications: !input enable_debug_notifications
|
enable_debug_notifications: !input enable_debug_notifications
|
||||||
|
|
||||||
# Event toggles
|
# Event toggles
|
||||||
@@ -284,39 +322,128 @@ variables:
|
|||||||
message_error_template: !input message_error
|
message_error_template: !input message_error
|
||||||
message_information_template: !input message_information
|
message_information_template: !input message_information
|
||||||
|
|
||||||
|
# Localization overrides (dicts; default to empty mappings)
|
||||||
|
label_overrides: !input label_overrides
|
||||||
|
code_label_overrides: !input code_label_overrides
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Vacuum Info
|
# Vacuum Info
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
vacuum_name: "{{ state_attr(vacuum_entity, 'friendly_name') | default(vacuum_entity) }}"
|
# Prefer the device name (clean, single) over the entity's friendly_name.
|
||||||
vacuum_device: "{{ device_id(vacuum_entity) | default('', true) }}"
|
# The Dreame integration names the vacuum entity " <device name>" (leading
|
||||||
|
# space) which Home Assistant composes into the friendly_name, so
|
||||||
|
# friendly_name renders the device name twice (e.g. "Z10 Pro Z10 Pro").
|
||||||
|
# Use the device's user-set/original name; fall back to friendly_name, then
|
||||||
|
# the entity_id.
|
||||||
|
vacuum_name: >
|
||||||
|
{%- set did = device_id(vacuum_entity) -%}
|
||||||
|
{%- set dname = (device_attr(did, 'name_by_user') or device_attr(did, 'name')) if did else none -%}
|
||||||
|
{{ dname if dname else (state_attr(vacuum_entity, 'friendly_name') | default(vacuum_entity, true)) }}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Event Data (flat structure — fields are directly on trigger.event.data)
|
# Event Data (flat structure — fields are directly on trigger.event.data)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
event_entity_id: "{{ trigger.event.data.entity_id | default('') }}"
|
event_entity_id: "{{ trigger.event.data.entity_id | default('') }}"
|
||||||
event_device_id: "{{ trigger.event.data.device_id | default('') }}"
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Friendly label maps
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# The integration emits cleaning_mode and status as raw UPPER_SNAKE enum
|
||||||
|
# names (e.g. SWEEPING_AND_MOPPING, SEGMENT_CLEANING). These maps translate
|
||||||
|
# them to readable text. Lookup order at the call site is:
|
||||||
|
# user label_overrides -> built-in map below -> generic humanizer.
|
||||||
|
cleaning_mode_labels:
|
||||||
|
UNKNOWN: "Unknown"
|
||||||
|
SWEEPING: "Sweeping"
|
||||||
|
MOPPING: "Mopping"
|
||||||
|
SWEEPING_AND_MOPPING: "Sweeping & Mopping"
|
||||||
|
status_labels:
|
||||||
|
UNKNOWN: "Unknown"
|
||||||
|
IDLE: "Idle"
|
||||||
|
PAUSED: "Paused"
|
||||||
|
CLEANING: "Cleaning"
|
||||||
|
BACK_HOME: "Returning to dock"
|
||||||
|
PART_CLEANING: "Spot cleaning"
|
||||||
|
FOLLOW_WALL: "Following wall"
|
||||||
|
CHARGING: "Charging"
|
||||||
|
OTA: "Updating firmware"
|
||||||
|
FCT: "Factory check"
|
||||||
|
WIFI_SET: "Wi-Fi setup"
|
||||||
|
POWER_OFF: "Powered off"
|
||||||
|
FACTORY: "Factory mode"
|
||||||
|
ERROR: "Error"
|
||||||
|
REMOTE_CONTROL: "Remote control"
|
||||||
|
SLEEPING: "Sleeping"
|
||||||
|
SELF_TEST: "Self test"
|
||||||
|
FACTORY_FUNCION_TEST: "Factory function test"
|
||||||
|
STANDBY: "Standby"
|
||||||
|
SEGMENT_CLEANING: "Room cleaning"
|
||||||
|
ZONE_CLEANING: "Zone cleaning"
|
||||||
|
SPOT_CLEANING: "Spot cleaning"
|
||||||
|
FAST_MAPPING: "Mapping"
|
||||||
|
MONITOR_CRUISE: "Patrolling"
|
||||||
|
MONITOR_SPOT: "Spot monitoring"
|
||||||
|
SUMMON_CLEAN: "Summon clean"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# Task status fields
|
# Task status fields
|
||||||
task_cleaning_mode: "{{ trigger.event.data.cleaning_mode | default('unknown') }}"
|
# ---------------------------------------------------------------------------
|
||||||
task_status_value: "{{ trigger.event.data.status | default('unknown') }}"
|
# Raw enum names as fired by the integration.
|
||||||
task_completed: "{{ trigger.event.data.completed | default(false) }}"
|
task_cleaning_mode_raw: "{{ trigger.event.data.cleaning_mode | default('UNKNOWN') }}"
|
||||||
|
task_status_raw: "{{ trigger.event.data.status | default('UNKNOWN') }}"
|
||||||
|
# Friendly values: override -> built-in map -> generic humanizer fallback.
|
||||||
|
task_cleaning_mode: "{{ (label_overrides or {}).get(task_cleaning_mode_raw, cleaning_mode_labels.get(task_cleaning_mode_raw, task_cleaning_mode_raw | replace('_', ' ') | title)) }}"
|
||||||
|
task_status_value: "{{ (label_overrides or {}).get(task_status_raw, status_labels.get(task_status_raw, task_status_raw | replace('_', ' ') | title)) }}"
|
||||||
|
# Coerce to a real bool so the started/completed dispatch stays correct.
|
||||||
|
task_completed: "{{ trigger.event.data.completed | default(false) | bool(false) }}"
|
||||||
task_cleaned_area: "{{ trigger.event.data.cleaned_area | default(0) }}"
|
task_cleaned_area: "{{ trigger.event.data.cleaned_area | default(0) }}"
|
||||||
task_cleaning_time: "{{ trigger.event.data.cleaning_time | default(0) }}"
|
task_cleaning_time: "{{ trigger.event.data.cleaning_time | default(0) }}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# Consumable fields
|
# Consumable fields
|
||||||
consumable_name: "{{ (trigger.event.data.consumable | default('unknown')) | replace('_', ' ') | title }}"
|
# ---------------------------------------------------------------------------
|
||||||
|
consumable_name: "{{ (label_overrides or {}).get(trigger.event.data.consumable | default('unknown'), (trigger.event.data.consumable | default('unknown')) | replace('_', ' ') | title) }}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# Warning fields
|
# Warning fields
|
||||||
warning_description: "{{ trigger.event.data.warning | default('unknown') }}"
|
# ---------------------------------------------------------------------------
|
||||||
|
# Most warnings carry a short English description; the temporary-map events
|
||||||
|
# instead carry a bare snake id or a markdown blob. Humanize a bare id (and
|
||||||
|
# honor overrides) while leaving descriptive text / markdown untouched.
|
||||||
|
warning_description: >
|
||||||
|
{%- set w = trigger.event.data.warning | default('unknown') -%}
|
||||||
|
{%- if w and ' ' not in w and '#' not in w -%}{{ (label_overrides or {}).get(w, w | replace('_', ' ') | title) }}{%- else -%}{{ w }}{%- endif -%}
|
||||||
warning_code: "{{ trigger.event.data.code | default('') }}"
|
warning_code: "{{ trigger.event.data.code | default('') }}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# Error fields
|
# Error fields
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
error_description: "{{ trigger.event.data.error | default('unknown') }}"
|
error_description: "{{ trigger.event.data.error | default('unknown') }}"
|
||||||
error_code: "{{ trigger.event.data.code | default('') }}"
|
error_code: "{{ trigger.event.data.code | default('') }}"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Code label (optional, localized)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Numeric warning/error code as fired (empty for code-less events). code_name
|
||||||
|
# is the localized label for that code, exposed as {code_name}: a user override
|
||||||
|
# if present, otherwise the integration's own English description, otherwise
|
||||||
|
# empty. No built-in numeric code table is shipped, so there is no risk of
|
||||||
|
# stale labels across integration versions.
|
||||||
|
event_code: "{{ trigger.event.data.code | default('') }}"
|
||||||
|
code_name: >
|
||||||
|
{%- set lbl = (code_label_overrides or {}).get(event_code, (code_label_overrides or {}).get(event_code | string, '')) -%}
|
||||||
|
{%- if lbl -%}{{ lbl }}
|
||||||
|
{%- elif trigger.id == 'warning' -%}{{ warning_description }}
|
||||||
|
{%- elif trigger.id == 'error' -%}{{ error_description }}
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
# Information fields
|
# Information fields
|
||||||
information_description: "{{ (trigger.event.data.information | default('unknown')) | replace('_', ' ') | title }}"
|
# ---------------------------------------------------------------------------
|
||||||
information_code: "{{ trigger.event.data.code | default('') }}"
|
information_description: "{{ (label_overrides or {}).get(trigger.event.data.information | default('unknown'), (trigger.event.data.information | default('unknown')) | replace('_', ' ') | title) }}"
|
||||||
|
# Information events carry a type id (e.g. dust_collection), never a numeric
|
||||||
|
# code — this raw id drives the Information ignore filter.
|
||||||
|
information_code: "{{ trigger.event.data.information | default('') }}"
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Event Dispatch
|
# Event Dispatch
|
||||||
@@ -337,11 +464,13 @@ variables:
|
|||||||
# Whether this event should produce a notification, given user toggles
|
# Whether this event should produce a notification, given user toggles
|
||||||
# and any per-code filter lists. Coerce with `| bool(false)` at the
|
# and any per-code filter lists. Coerce with `| bool(false)` at the
|
||||||
# consumer because folded scalars can render as the string "True"/"False".
|
# consumer because folded scalars can render as the string "True"/"False".
|
||||||
|
# The warning branch also drops the integration's spurious "replace_temporary_map"
|
||||||
|
# clear event (fired with no code, including on every restart).
|
||||||
event_enabled: >
|
event_enabled: >
|
||||||
{%- if event_kind == 'cleaning_started' -%}{{ enable_cleaning_started }}
|
{%- if event_kind == 'cleaning_started' -%}{{ enable_cleaning_started }}
|
||||||
{%- elif event_kind == 'cleaning_completed' -%}{{ enable_cleaning_completed }}
|
{%- elif event_kind == 'cleaning_completed' -%}{{ enable_cleaning_completed }}
|
||||||
{%- elif event_kind == 'consumable' -%}{{ enable_consumable }}
|
{%- elif event_kind == 'consumable' -%}{{ enable_consumable }}
|
||||||
{%- elif event_kind == 'warning' -%}{{ enable_warning and (warning_code | string) not in warning_codes_ignore }}
|
{%- elif event_kind == 'warning' -%}{{ enable_warning and (trigger.event.data.warning | default('')) != 'replace_temporary_map' and (warning_code | string) not in warning_codes_ignore }}
|
||||||
{%- elif event_kind == 'error' -%}{{ enable_error and (error_code | string) not in error_codes_ignore }}
|
{%- elif event_kind == 'error' -%}{{ enable_error and (error_code | string) not in error_codes_ignore }}
|
||||||
{%- elif event_kind == 'information' -%}{{ enable_information and (information_code | string) not in information_codes_ignore }}
|
{%- elif event_kind == 'information' -%}{{ enable_information and (information_code | string) not in information_codes_ignore }}
|
||||||
{%- else -%}False
|
{%- else -%}False
|
||||||
@@ -359,12 +488,14 @@ variables:
|
|||||||
|
|
||||||
# Render the message. Placeholders that don't apply to this event are
|
# Render the message. Placeholders that don't apply to this event are
|
||||||
# absent from the chosen template, so `replace()` is a no-op for them.
|
# absent from the chosen template, so `replace()` is a no-op for them.
|
||||||
|
# {vacuum_name} is substituted last (it is the only user-controlled value)
|
||||||
|
# so a friendly name containing a literal token cannot be re-expanded. The
|
||||||
|
# final regex strips an empty "(label: )" parenthetical in any language left
|
||||||
|
# by a code-less event, e.g. "(code: )" or "(код предупреждения: )".
|
||||||
message: >
|
message: >
|
||||||
{%- set code_for_event = warning_code if event_kind == 'warning'
|
{%- set code_for_event = warning_code if event_kind == 'warning'
|
||||||
else (error_code if event_kind == 'error'
|
else (error_code if event_kind == 'error' else '') -%}
|
||||||
else (information_code if event_kind == 'information' else '')) -%}
|
{%- set rendered = message_template
|
||||||
{{ message_template
|
|
||||||
| replace('{vacuum_name}', vacuum_name)
|
|
||||||
| replace('{cleaning_mode}', task_cleaning_mode)
|
| replace('{cleaning_mode}', task_cleaning_mode)
|
||||||
| replace('{status}', task_status_value)
|
| replace('{status}', task_status_value)
|
||||||
| replace('{cleaned_area}', task_cleaned_area | string)
|
| replace('{cleaned_area}', task_cleaned_area | string)
|
||||||
@@ -373,24 +504,25 @@ variables:
|
|||||||
| replace('{warning}', warning_description)
|
| replace('{warning}', warning_description)
|
||||||
| replace('{error}', error_description)
|
| replace('{error}', error_description)
|
||||||
| replace('{information}', information_description)
|
| replace('{information}', information_description)
|
||||||
| replace('{code}', code_for_event | string) }}
|
| replace('{code_name}', code_name)
|
||||||
|
| replace('{code}', code_for_event | string)
|
||||||
|
| replace('{vacuum_name}', vacuum_name) -%}
|
||||||
|
{{ rendered | regex_replace('\\s*\\(\\s*[^():]*:\\s*\\)', '') }}
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# CONDITIONS
|
# CONDITIONS
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
condition:
|
condition:
|
||||||
# Only process events from the configured vacuum.
|
# Only process events from the configured vacuum. The integration fires every
|
||||||
# Prefer device_id matching when the event payload carries it (most
|
# event with an `entity_id` derived from the device NAME via generate_entity_id()
|
||||||
# reliable across firmware revisions and avoids prefix collisions when
|
# — events never carry a `device_id`, so matching is entity_id based.
|
||||||
# multiple Dreame vacuums share an entity_id stem).
|
# generate_entity_id() may append a purely numeric suffix (e.g. `_2`) when the
|
||||||
# Fall back to entity_id matching: the integration uses generate_entity_id(),
|
# base id is already taken, so we accept the configured entity_id exactly, or
|
||||||
# which may append a numeric suffix (e.g., `_2`) when the base entity_id
|
# followed by a purely-numeric suffix, and reject non-numeric suffixes (e.g. `_pro`).
|
||||||
# is taken — so we accept the configured entity_id with an optional
|
|
||||||
# purely numeric suffix and reject non-numeric suffixes (e.g., `_pro`).
|
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: >
|
||||||
{%- if event_device_id != '' and vacuum_device != '' -%}
|
{%- if event_entity_id == '' -%}
|
||||||
{{ event_device_id == vacuum_device }}
|
false
|
||||||
{%- elif event_entity_id == vacuum_entity -%}
|
{%- elif event_entity_id == vacuum_entity -%}
|
||||||
true
|
true
|
||||||
{%- elif event_entity_id.startswith(vacuum_entity ~ '_') -%}
|
{%- elif event_entity_id.startswith(vacuum_entity ~ '_') -%}
|
||||||
@@ -407,11 +539,10 @@ action:
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Debug Logging
|
# Debug Logging
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
- choose:
|
- if:
|
||||||
- conditions:
|
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ enable_debug_notifications }}"
|
value_template: "{{ enable_debug_notifications }}"
|
||||||
sequence:
|
then:
|
||||||
- action: persistent_notification.create
|
- action: persistent_notification.create
|
||||||
data:
|
data:
|
||||||
notification_id: "dreame_vacuum_debug_{{ vacuum_entity }}"
|
notification_id: "dreame_vacuum_debug_{{ vacuum_entity }}"
|
||||||
@@ -422,7 +553,6 @@ action:
|
|||||||
**Event kind:** {{ event_kind }}
|
**Event kind:** {{ event_kind }}
|
||||||
**Enabled:** {{ event_enabled }}
|
**Enabled:** {{ event_enabled }}
|
||||||
**Entity:** {{ event_entity_id }}
|
**Entity:** {{ event_entity_id }}
|
||||||
**Device:** {{ event_device_id }}
|
|
||||||
**Vacuum:** {{ vacuum_name }}
|
**Vacuum:** {{ vacuum_name }}
|
||||||
**Event Data:** {{ trigger.event.data }}
|
**Event Data:** {{ trigger.event.data }}
|
||||||
|
|
||||||
@@ -431,13 +561,12 @@ action:
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Single dispatch — message and the enable decision are computed in the
|
# Single dispatch — message and the enable decision are computed in the
|
||||||
# variables block above. We just gate on the resolved flags here.
|
# variables block above. We just gate on the resolved flags here.
|
||||||
- choose:
|
- if:
|
||||||
- conditions:
|
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{{ event_kind != 'none' and (event_enabled | bool(false)) }}"
|
value_template: "{{ event_kind != 'none' and (event_enabled | bool(false)) }}"
|
||||||
sequence:
|
then:
|
||||||
- action: notify.send_message
|
- action: notify.send_message
|
||||||
target:
|
target:
|
||||||
entity_id: "{{ notify_targets }}"
|
entity_id: !input notify_targets
|
||||||
data:
|
data:
|
||||||
message: "{{ message }}"
|
message: "{{ message }}"
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
# Russian (русский) starter localization for the Dreame Vacuum Notifications blueprint.
|
||||||
|
#
|
||||||
|
# HOW TO USE
|
||||||
|
# When configuring the automation from the blueprint, open the "Localization"
|
||||||
|
# section and paste:
|
||||||
|
# * the mapping under `label_overrides:` -> into the "Label Overrides" input
|
||||||
|
# * the mapping under `code_label_overrides:` -> into the "Warning/Error Code Labels" input
|
||||||
|
# (Paste the key/value lines themselves; the object selector takes the mapping.)
|
||||||
|
#
|
||||||
|
# {cleaning_mode} / {status} / {consumable} / {information} use label_overrides.
|
||||||
|
# {code_name} uses code_label_overrides. To show fully Russian warning/error
|
||||||
|
# text, use {code_name} in your warning/error templates instead of the
|
||||||
|
# integration-supplied English {warning}/{error}, e.g.:
|
||||||
|
# message_warning: "⚠️ {vacuum_name}: {code_name} (код {code})."
|
||||||
|
#
|
||||||
|
# Tweak any wording to taste. Anything you leave out falls back to the built-in
|
||||||
|
# English label, then to a generic humanizer.
|
||||||
|
|
||||||
|
label_overrides:
|
||||||
|
# --- Cleaning mode ({cleaning_mode}) ---
|
||||||
|
UNKNOWN: Неизвестно
|
||||||
|
SWEEPING: Подметание
|
||||||
|
MOPPING: Мытьё
|
||||||
|
SWEEPING_AND_MOPPING: Подметание и мытьё
|
||||||
|
|
||||||
|
# --- Status ({status}) ---
|
||||||
|
IDLE: Ожидание
|
||||||
|
PAUSED: Пауза
|
||||||
|
CLEANING: Уборка
|
||||||
|
BACK_HOME: Возврат на базу
|
||||||
|
PART_CLEANING: Точечная уборка
|
||||||
|
FOLLOW_WALL: Уборка вдоль стен
|
||||||
|
CHARGING: Зарядка
|
||||||
|
OTA: Обновление прошивки
|
||||||
|
FCT: Заводская проверка
|
||||||
|
WIFI_SET: Настройка Wi-Fi
|
||||||
|
POWER_OFF: Выключен
|
||||||
|
FACTORY: Заводской режим
|
||||||
|
ERROR: Ошибка
|
||||||
|
REMOTE_CONTROL: Ручное управление
|
||||||
|
SLEEPING: Сон
|
||||||
|
SELF_TEST: Самодиагностика
|
||||||
|
FACTORY_FUNCION_TEST: Заводской тест функций
|
||||||
|
STANDBY: Режим ожидания
|
||||||
|
SEGMENT_CLEANING: Уборка комнат
|
||||||
|
ZONE_CLEANING: Уборка зон
|
||||||
|
SPOT_CLEANING: Точечная уборка
|
||||||
|
FAST_MAPPING: Построение карты
|
||||||
|
MONITOR_CRUISE: Патрулирование
|
||||||
|
MONITOR_SPOT: Видеонаблюдение
|
||||||
|
SUMMON_CLEAN: Уборка по вызову
|
||||||
|
|
||||||
|
# --- Consumables ({consumable}) ---
|
||||||
|
main_brush: Основная щётка
|
||||||
|
side_brush: Боковая щётка
|
||||||
|
filter: Фильтр
|
||||||
|
secondary_filter: Вторичный фильтр
|
||||||
|
sensor: Датчики
|
||||||
|
mop_pad: Насадка для мытья
|
||||||
|
silver_ion: Серебряный ионизатор
|
||||||
|
detergent: Моющее средство
|
||||||
|
|
||||||
|
# --- Information ({information}) ---
|
||||||
|
dust_collection: Очистка пылесборника
|
||||||
|
cleaning_paused: Уборка приостановлена
|
||||||
|
|
||||||
|
code_label_overrides:
|
||||||
|
# Numeric warning/error code -> short Russian label ({code_name}).
|
||||||
|
# Warnings: 47, 68, 70, 71, 72, 107, 114. Everything else is an error.
|
||||||
|
1: Колёса вывешены
|
||||||
|
2: Ошибка датчика обрыва
|
||||||
|
3: Заклинило датчик столкновения
|
||||||
|
4: Робот наклонён
|
||||||
|
5: Заклинило датчик столкновения
|
||||||
|
6: Колёса вывешены
|
||||||
|
7: Ошибка оптического датчика
|
||||||
|
8: Не установлен пылесборник
|
||||||
|
9: Не установлен бак для воды
|
||||||
|
10: Бак для воды пуст
|
||||||
|
11: Фильтр влажный или забит
|
||||||
|
12: Намотка на основную щётку
|
||||||
|
13: Намотка на боковую щётку
|
||||||
|
14: Фильтр влажный или забит
|
||||||
|
15: Заблокировано левое колесо
|
||||||
|
16: Заблокировано правое колесо
|
||||||
|
17: Робот застрял (не может повернуть)
|
||||||
|
18: Робот застрял (не может ехать)
|
||||||
|
19: Не найдена база
|
||||||
|
21: Ошибка зарядки
|
||||||
|
23: Внутренняя ошибка
|
||||||
|
24: Ошибка датчика навигации
|
||||||
|
25: Ошибка датчика перемещения
|
||||||
|
26: Ошибка оптического датчика
|
||||||
|
27: Помеха ИК-датчику
|
||||||
|
28: На базу не подаётся питание
|
||||||
|
29: Ошибка температуры батареи
|
||||||
|
30: Ошибка датчика вентилятора
|
||||||
|
31: Заблокировано левое колесо
|
||||||
|
32: Заблокировано правое колесо
|
||||||
|
33: Ошибка акселерометра
|
||||||
|
34: Ошибка гироскопа
|
||||||
|
35: Ошибка гироскопа
|
||||||
|
36: Ошибка левого магнитного датчика
|
||||||
|
37: Ошибка правого магнитного датчика
|
||||||
|
38: Ошибка датчика потока
|
||||||
|
39: Ошибка ИК-датчика
|
||||||
|
40: Ошибка камеры
|
||||||
|
41: Сильное магнитное поле
|
||||||
|
42: Ошибка водяного насоса
|
||||||
|
43: Ошибка часов (RTC)
|
||||||
|
44: Внутренняя ошибка
|
||||||
|
45: Внутренняя ошибка
|
||||||
|
46: Внутренняя ошибка
|
||||||
|
47: Маршрут заблокирован
|
||||||
|
48: Ошибка лазерного дальномера
|
||||||
|
49: Заклинило бампер лидара
|
||||||
|
50: Ошибка водяного насоса
|
||||||
|
51: Фильтр влажный или забит
|
||||||
|
54: Ошибка краевого датчика
|
||||||
|
55: Под роботом обнаружен ковёр
|
||||||
|
56: Ошибка датчика обхода препятствий
|
||||||
|
57: Ошибка краевого датчика
|
||||||
|
58: Ошибка ультразвукового датчика
|
||||||
|
59: Запретная зона или виртуальная стена
|
||||||
|
61: Не удаётся достичь зоны
|
||||||
|
62: Не удаётся достичь зоны
|
||||||
|
63: Маршрут заблокирован
|
||||||
|
64: Маршрут заблокирован
|
||||||
|
65: Робот в запретной зоне
|
||||||
|
66: Робот в запретной зоне
|
||||||
|
67: Робот в запретной зоне
|
||||||
|
68: Снимите и промойте швабру
|
||||||
|
69: Отсоединилась насадка для мытья
|
||||||
|
70: Отсоединилась насадка для мытья
|
||||||
|
71: Насадка для мытья не вращается
|
||||||
|
72: Насадка для мытья не вращается
|
||||||
|
101: Мешок для пыли заполнен или забит воздуховод
|
||||||
|
102: Крышка базы открыта или нет мешка
|
||||||
|
103: Крышка базы открыта или нет мешка
|
||||||
|
104: Мешок для пыли заполнен или забит воздуховод
|
||||||
|
105: Не установлен бак чистой воды
|
||||||
|
106: Бак грязной воды полон или не установлен
|
||||||
|
107: Мало чистой воды
|
||||||
|
108: Бак грязной воды полон или не установлен
|
||||||
|
109: Засор бака грязной воды
|
||||||
|
110: Ошибка насоса грязной воды
|
||||||
|
111: Неправильно установлен лоток мойки
|
||||||
|
112: Очистите лоток мойки
|
||||||
|
114: Очистите лоток мойки швабры
|
||||||
|
116: Долейте чистую воду
|
||||||
|
118: Бак грязной воды переполнен
|
||||||
|
119: Высокий уровень воды в лотке мойки
|
||||||
@@ -553,15 +553,17 @@ variables:
|
|||||||
and run_state not in non_running_state_ids
|
and run_state not in non_running_state_ids
|
||||||
and run_state != preparation_state_id
|
and run_state != preparation_state_id
|
||||||
and run_state != run_state_completion_id
|
and run_state != run_state_completion_id
|
||||||
and remaining not in ['unknown', 'unavailable'] }}
|
and (remaining | string | trim) not in ['unknown', 'unavailable', 'none', '-', ''] }}
|
||||||
|
|
||||||
# Parse remaining time string (hh:mm:ss) to total minutes
|
# Parse remaining time string (hh:mm:ss) to total minutes.
|
||||||
|
# Use int(0) defaults so a partially invalid sensor value (e.g.
|
||||||
|
# 'unavailable:00:00') degrades to 0 instead of raising.
|
||||||
remaining_time_in_minutes: >
|
remaining_time_in_minutes: >
|
||||||
{% if remaining not in ['unknown', 'unavailable', '-'] %}
|
{% set r = remaining | string | trim %}
|
||||||
{% set parts = remaining.split(':') %}
|
{% if r not in ['unknown', 'unavailable', 'none', '-', ''] %}
|
||||||
|
{% set parts = r.split(':') %}
|
||||||
{% if parts | length >= 2 %}
|
{% if parts | length >= 2 %}
|
||||||
{% set total = parts[0]|int * 60 + parts[1]|int %}
|
{{ parts[0] | int(0) * 60 + parts[1] | int(0) }}
|
||||||
{{ total }}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ 0 }}
|
{{ 0 }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -571,11 +573,12 @@ variables:
|
|||||||
|
|
||||||
# Calculate estimated end time from remaining time
|
# Calculate estimated end time from remaining time
|
||||||
estimated_end_time: >
|
estimated_end_time: >
|
||||||
{% if remaining not in ['unknown', 'unavailable', '-'] %}
|
{% set r = remaining | string | trim %}
|
||||||
{% set parts = remaining.split(':') %}
|
{% if r not in ['unknown', 'unavailable', 'none', '-', ''] %}
|
||||||
|
{% set parts = r.split(':') %}
|
||||||
{% if parts | length >= 2 %}
|
{% if parts | length >= 2 %}
|
||||||
{% set hours = parts[0] | int %}
|
{% set hours = parts[0] | int(0) %}
|
||||||
{% set minutes = parts[1] | int %}
|
{% set minutes = parts[1] | int(0) %}
|
||||||
{% set end_time = now() + timedelta(hours=hours, minutes=minutes) %}
|
{% set end_time = now() + timedelta(hours=hours, minutes=minutes) %}
|
||||||
{{ end_time.strftime('%H:%M') }}
|
{{ end_time.strftime('%H:%M') }}
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -739,7 +742,7 @@ action:
|
|||||||
value_template: >
|
value_template: >
|
||||||
{{ not is_running
|
{{ not is_running
|
||||||
and automation_state.get(state_notification_about_start_sent, false)
|
and automation_state.get(state_notification_about_start_sent, false)
|
||||||
and (states(run_state_sensor) in [run_state_completion_id, 'unknown', '-'] or states(remaining_time_sensor) in ['unknown', '-']) }}
|
and (states(run_state_sensor) in [run_state_completion_id, 'unknown', 'unavailable', '-'] or states(remaining_time_sensor) in ['unknown', 'unavailable', '-']) }}
|
||||||
sequence:
|
sequence:
|
||||||
- variables:
|
- variables:
|
||||||
# Calculate energy consumption
|
# Calculate energy consumption
|
||||||
@@ -891,7 +894,7 @@ action:
|
|||||||
|
|
||||||
- variables:
|
- variables:
|
||||||
# Calculate minutes for the template
|
# Calculate minutes for the template
|
||||||
minutes: "{{ remaining.split(':')[1] | int }}"
|
minutes: "{{ remaining.split(':')[1] | int(0) if ':' in (remaining | string) else 0 }}"
|
||||||
# Render the message template with available variables
|
# Render the message template with available variables
|
||||||
message: >
|
message: >
|
||||||
{% set tpl = message_almost_done_template %}
|
{% set tpl = message_almost_done_template %}
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"version": "2.13.0"
|
"version": "2.14.2"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user