[2026-09-15] eagle: family/how-to/home-automation.md family/plans/t610-heating-cable-automation.md family/tech/ha-registry-operations.md family/tech/heating-cable-water-inlet.md
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
title: "🏠 Домашняя автоматизация"
|
title: "🏠 Домашняя автоматизация"
|
||||||
aliases: [Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset]
|
aliases: [Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset]
|
||||||
tags: [family, how-to, smarthome]
|
tags: [family, how-to, smarthome]
|
||||||
updated: 2026-09-16 (H2000_PRO: единицы °F→°C через `options_domain: sensor.private`; питфолл доступа к API с Mac — только через SSH. §2. Греющий кабель ввода воды — расчёт готов, тип = саморег, ждёт выдержки 6/24 ч: [[family/tech/heating-cable-water-inlet]])
|
updated: 2026-09-16 (H2000_PRO: единицы °F→°C через `options_domain: sensor.private`; питфолл доступа к API с Mac — только через SSH. §2. Греющий кабель ввода воды — расчёт готов, саморег, выдержка **12 ч**, конструкция: прогноз через `action: weather.get_forecasts` + `response_variable`, **0 helper'ов**: [[family/tech/heating-cable-water-inlet]])
|
||||||
---
|
---
|
||||||
|
|
||||||
# 🏠 Домашняя автоматизация
|
# 🏠 Домашняя автоматизация
|
||||||
@@ -109,6 +109,8 @@ python3 ha_ws.py forecast weather.forecast_laki_dom daily # прогноз п
|
|||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ **Прогноз — ТОЛЬКО WS `weather/subscribe_forecast`.** REST `weather/get_forecast` → 400, WS `weather/forecast` → `unknown_command`. Ответ приходит **двумя** сообщениями (`result` + `event`) — клиент, ждущий только `result`, получит 0 точек. Подробно: [[family/tech/ha-registry-operations]] §8.
|
> ⚠️ **Прогноз — ТОЛЬКО WS `weather/subscribe_forecast`.** REST `weather/get_forecast` → 400, WS `weather/forecast` → `unknown_command`. Ответ приходит **двумя** сообщениями (`result` + `event`) — клиент, ждущий только `result`, получит 0 точек. Подробно: [[family/tech/ha-registry-operations]] §8.
|
||||||
|
>
|
||||||
|
> 🔴 **Прогноз ВНУТРИ автоматизации — только как ДЕЙСТВИЕ:** `action: weather.get_forecasts` (мн. число) + `response_variable`. В Jinja-шаблоне вызов даёт `'weather' is undefined`, атрибута `forecast` у сущности нет. Внутри `actions:` объявлять `variables:` ПОСЛЕ вызова — они вычисляются до действий. Helper'ы не нужны. Детали: [[family/tech/heating-cable-water-inlet]] §8.1.
|
||||||
|
|
||||||
**Зоны:** `living_room` Гостиная · `kitchen` Кухня · `bedroom` Спальня · `detskaia` Детская · `kabinet` Кабинет · `vannaia` Ванная · `dushevaia` Душевая · `tualet` Туалет · `severnaia` Серая · `kotelnaia` Котельная · `lestnitsa` Лестница.
|
**Зоны:** `living_room` Гостиная · `kitchen` Кухня · `bedroom` Спальня · `detskaia` Детская · `kabinet` Кабинет · `vannaia` Ванная · `dushevaia` Душевая · `tualet` Туалет · `severnaia` Серая · `kotelnaia` Котельная · `lestnitsa` Лестница.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# План: автоматизация греющего кабеля ввода воды (t610)
|
# План: автоматизация греющего кабеля ввода воды (t610)
|
||||||
|
|
||||||
> Статус: **согласован 2026-09-16** — выдержка 12 ч, порог −8 °C.
|
> Статус: **конструкция согласована 2026-09-16** — выдержка 12 ч, порог −8 °C,
|
||||||
> Предыстория: [[family/how-to/home-automation]] · [[family/tech/zigbee-t610-z2m-i-zha]]
|
> **0 helper'ов** (прогноз через `action:` + `response_variable`).
|
||||||
|
> ⏳ Ждёт отмашки: как реализовать выдержку 12 ч (вариант A или B, см. ниже).
|
||||||
|
> Предыстория: [[family/how-to/home-automation]] · [[family/tech/zigbee-t610-z2m-i-zha]] · [[family/tech/heating-cable-water-inlet]]
|
||||||
|
|
||||||
## Задача
|
## Задача
|
||||||
|
|
||||||
@@ -85,69 +87,108 @@ ZONT — одна точка, может врать или отвалиться
|
|||||||
|
|
||||||
1. Бэкап `automations.yaml` — ✅ `automations.yaml.bak-cable-20260915-234837`
|
1. Бэкап `automations.yaml` — ✅ `automations.yaml.bak-cable-20260915-234837`
|
||||||
(локально: `~/tmp-t610/bak-cable-20260915-234837/automations.yaml`, 650 строк)
|
(локально: `~/tmp-t610/bak-cable-20260915-234837/automations.yaml`, 650 строк)
|
||||||
2. **Создать 6 объектов** (см. раздел «Конструкция» ниже) — ⏳ не начато
|
2. **Конструкция определена** — ✅ `action: weather.get_forecasts` +
|
||||||
3. `reload automations` и проверить `on` + отсутствие ошибок
|
`response_variable`, 1 автоматизация, 0 helper'ов. YAML-заготовка готова:
|
||||||
4. Проверить, что сущности существуют в runtime
|
`~/tmp-t610/new_cable_autos.yaml`
|
||||||
5. Обновить `family/how-to/home-automation.md` — раздел про ввод воды
|
3. ⏳ **Решить выдержку 12 ч** (вариант A или B) — ждёт Alex
|
||||||
6. Записать питфоллы (WS `weather/subscribe_forecast`) в доки
|
4. Создать автоматизацию, `reload automations`, проверить `on` + отсутствие ошибок
|
||||||
|
5. Проверить, что сущности существуют в runtime
|
||||||
|
6. Обновить `family/how-to/home-automation.md` — раздел про ввод воды
|
||||||
|
7. Записать питфоллы (WS `weather/subscribe_forecast`) в доки
|
||||||
|
|
||||||
## 🔴 Конструкция: прогноз НЕЛЬЗЯ получить из шаблона
|
## 🔴 Конструкция: прогноз через ДЕЙСТВИЕ автоматизации (не через шаблон)
|
||||||
|
|
||||||
**Открытие 2026-09-16.** Прогноз в этой версии HA недоступен шаблону — проверено
|
**Открытие 2026-09-16 (две итерации).** Первый вывод — «прогноз недоступен из
|
||||||
четырьмя способами:
|
шаблона» — **верен, но неполон**. Второй вывод, «нужен `input_number` +
|
||||||
|
обновлятор» — **НЕВЕРЕН, отменён**. Итоговая конструкция проще: **0 helper'ов**.
|
||||||
|
|
||||||
|
### Что проверено фактом
|
||||||
|
|
||||||
| Способ | Результат |
|
| Способ | Результат |
|
||||||
|---|---|
|
|---|---|
|
||||||
| атрибут `forecast` у `weather.forecast_laki_dom` | **`None`** |
|
| атрибут `forecast` у `weather.forecast_laki_dom` | **`None`** — прогноза в атрибутах нет |
|
||||||
| `weather.get_forecasts(...)` в Jinja | **`'weather' is undefined`** |
|
| `weather.get_forecasts(...)` в Jinja-шаблоне | **`'weather' is undefined`** |
|
||||||
|
| `weather.get_forecasts` как **действие** (`action:` + `response_variable`) | ✅ **работает** — 48 точек |
|
||||||
| сервис `weather.get_forecasts` (REST/WS, мн. число) | ✅ работает, 48 ч + 6 дней |
|
| сервис `weather.get_forecasts` (REST/WS, мн. число) | ✅ работает, 48 ч + 6 дней |
|
||||||
| WS `weather/subscribe_forecast` | ✅ работает |
|
| WS `weather/subscribe_forecast` | ✅ работает (для стрима/CLI) |
|
||||||
|
|
||||||
**Следствие:** пороги нельзя написать шаблоном «на лету» — прогноз надо
|
> ✅ **ГЛАВНОЕ: `weather.get_forecasts` вызывается как ДЕЙСТВИЕ автоматизации
|
||||||
**материализовать в сущность**. Иначе в триггер автоматизации его не подставить.
|
> с `response_variable`.** Внутри action-блока `forecast` доступен последующим
|
||||||
|
> `variables:` и `choose:`. Это штатный, документированный путь.
|
||||||
|
>
|
||||||
|
> 🔴 **Ошибка, которую я допустил:** проверил только Jinja-форму
|
||||||
|
> `{{ weather.get_forecasts(...) }}` → `'weather' is undefined` — и сделал вывод
|
||||||
|
> «нельзя, нужен helper». На самом деле в `action:` он работает. Alex поймал это
|
||||||
|
> вопросом «Ты серьезно?!». **Урок: прежде чем строить обходной слой, проверь
|
||||||
|
> штатный путь целиком — не только удобную форму вызова.**
|
||||||
|
|
||||||
**Решение — слой обновления:**
|
### Порядок в автоматизации (критично)
|
||||||
|
|
||||||
```
|
```yaml
|
||||||
automation.heating_cable_forecast_update (каждый час)
|
actions:
|
||||||
→ weather.get_forecasts('weather.forecast_laki_dom','hourly')
|
- action: weather.get_forecasts # 1. ПЕРВЫМ действием
|
||||||
→ min(map(attribute='temperature')[:24])
|
target:
|
||||||
→ input_number.heating_cable_forecast_min
|
entity_id: weather.forecast_laki_dom
|
||||||
|
data:
|
||||||
sensor.heating_cable_outside_min_24h (template)
|
type: hourly
|
||||||
→ min( sensor.h2000_pro_temperatura_ulitsa ,
|
response_variable: wx
|
||||||
input_number.heating_cable_forecast_min )
|
- variables: # 2. ПОСЛЕ него — forecast уже есть
|
||||||
|
zont: "{{ states('sensor.h2000_pro_temperatura_ulitsa') | float(99) }}"
|
||||||
|
fc_min: >-
|
||||||
|
{{ wx['weather.forecast_laki_dom']['forecast'][:24]
|
||||||
|
| map(attribute='temperature') | min | default(99) | float(99) }}
|
||||||
|
eff: "{{ [zont, fc_min] | min }}"
|
||||||
|
- choose: [...] # 3. решения по eff
|
||||||
```
|
```
|
||||||
|
|
||||||
Триггеры ВКЛ/ВЫКЛ/авария вешаются **на template-сенсор** — он числовой и всегда
|
> 🔴 **`variables:` вычисляются ДО действий.** Если объявить `fc_min` в
|
||||||
доступен. Исходный вариант (триггер прямо на прогноз) был нерабочим.
|
> `variables:` на верхнем уровне автоматизации, `forecast` там ещё не существует.
|
||||||
|
> **Обязательно:** `variables:` — внутри `actions:`, ПОСЛЕ вызова сервиса.
|
||||||
|
|
||||||
### Что создать (6 объектов)
|
**Путь до данных:** `response_variable` = `result.response` целиком, поэтому
|
||||||
|
`wx['weather.forecast_laki_dom']['forecast']` (проверено: ключи
|
||||||
|
`['weather.forecast_laki_dom']` → `['forecast']` → 48 точек с полем `temperature`).
|
||||||
|
|
||||||
| № | Объект | Тип | Назначение |
|
### Что создаётся — 3 автоматизации, 0 новых сущностей
|
||||||
|
|
||||||
|
| № | Объект | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | `automation.heating_cable_ctl` | **одна** автоматизация: `time_pattern /15` + `numeric_state` + `state` (отвал) → `choose` с 5 ветками |
|
||||||
|
|
||||||
|
**Ветки `choose`:**
|
||||||
|
|
||||||
|
| # | Условие | Действие |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | `eff <= -20` | ВКЛ + persistent + push (без выдержки) |
|
||||||
|
| 2 | `zont == 99` (датчик недоступен) | ВКЛ + push (fail-safe) |
|
||||||
|
| 3 | `eff <= -8 and not cable_on` | ВКЛ + persistent + push |
|
||||||
|
| 4 | `eff >= -3 and cable_on` | ВЫКЛ + persistent |
|
||||||
|
| 5 | `cable_on and cable_power < 5` | push «нет потребления» |
|
||||||
|
|
||||||
|
**Плюс** финальное действие `logbook.log` с `zont / fc24 / eff / on / P` —
|
||||||
|
для диагностики срабатываний в UI.
|
||||||
|
|
||||||
|
Файл с заготовкой: `~/tmp-t610/new_cable_autos.yaml` (YAML валиден).
|
||||||
|
|
||||||
|
### ⏳ Не решено: как реализовать выдержку 12 ч
|
||||||
|
|
||||||
|
`for: '12:00:00'` нельзя повесить на вычисляемый шаблон `eff` — только на реальную
|
||||||
|
сущность. Два варианта:
|
||||||
|
|
||||||
|
| | Как | Плюс | Минус |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 1 | `input_number.heating_cable_forecast_min` | helper | мин. прогноз на 24 ч |
|
| **A** | `numeric_state` + `for: 12:00:00` на `sensor.h2000_pro_temperatura_ulitsa`, отдельный триггер на прогноз | честные 12 ч по температуре | выдержка только по ZONT, прогноз учитывается иначе |
|
||||||
| 2 | `sensor.heating_cable_outside_min_24h` | template | `min(ZONT, прогноз)` |
|
| **B** ⭐ | `time_pattern` + `for: '12:00:00'` на `switch.heating_cable_plug` в условии включения | одна автоматизация, всё работает | выдержка отсчитывается от состояния розетки, а не от температуры |
|
||||||
| 3 | `automation.heating_cable_forecast_update` | automation | обновляет №1 раз в час |
|
|
||||||
| 4 | `automation.heating_cable_on` | automation | ВКЛ при ≤ −8 °C / 12 ч |
|
|
||||||
| 5 | `automation.heating_cable_off` | automation | ВЫКЛ при ≥ −3 °C / 12 ч |
|
|
||||||
| 6 | `automation.heating_cable_emergency` | automation | ≤ −20 °C, fail-safe, обрыв |
|
|
||||||
|
|
||||||
### Открытый вопрос (не решён)
|
**Рекомендация:** **B** — включение срабатывает, только если порог держится 12 ч,
|
||||||
|
а розетка всё это время выключена. **Ждёт отмашки Alex.**
|
||||||
**Где создавать helper №1** — Storage (UI, правится мышкой, но значение не
|
|
||||||
попадает в док) или YAML (`configuration.yaml`, версионируется, но правка только
|
|
||||||
файлом)? Alex не ответил.
|
|
||||||
|
|
||||||
Смежный вопрос: пороги −8/−3/−20 сейчас зашиты в YAML автоматизаций. Если Alex
|
|
||||||
захочет пороги из UI — нужно 4 helper'а вместо одного.
|
|
||||||
|
|
||||||
Файл с заготовкой: `~/tmp-t610/new_cable_autos.yaml` (3 автоматизации, YAML валиден).
|
|
||||||
|
|
||||||
## Питфоллы
|
## Питфоллы
|
||||||
|
|
||||||
- 🔴 **`weather.get_forecasts` — ТОЛЬКО как сервис, не в Jinja.** В шаблоне даёт
|
- 🔴 **`weather.get_forecasts` работает как ДЕЙСТВИЕ (`response_variable`), но
|
||||||
`'weather' is undefined` (вызов сервисов из шаблонов убран). Проверено фактом.
|
НЕ как Jinja-функция.** В шаблоне даёт `'weather' is undefined`. Проверено фактом.
|
||||||
|
- 🔴 **`variables:` вычисляются до `actions:`** — объявлять вычисления от
|
||||||
|
`response_variable` только ВНУТРИ `actions:`, после вызова сервиса.
|
||||||
- **Имя сервиса — множественное число** `weather.get_forecasts`. Единственное
|
- **Имя сервиса — множественное число** `weather.get_forecasts`. Единственное
|
||||||
`weather.get_forecast` **не существует** → `not_found`.
|
`weather.get_forecast` **не существует** → `not_found`.
|
||||||
- **WS-команда — `weather/subscribe_forecast`**, поле `forecast_type` (не `type`).
|
- **WS-команда — `weather/subscribe_forecast`**, поле `forecast_type` (не `type`).
|
||||||
@@ -156,20 +197,24 @@ sensor.heating_cable_outside_min_24h (template)
|
|||||||
- Результат WS-подписки приходит **двумя сообщениями**: сначала `result`, потом
|
- Результат WS-подписки приходит **двумя сообщениями**: сначала `result`, потом
|
||||||
`event`. WS-хелпер, ждущий только `result`, вернёт пустой прогноз.
|
`event`. WS-хелпер, ждущий только `result`, вернёт пустой прогноз.
|
||||||
- 🔴 **`render_template` по WebSocket возвращает `null`** даже для `{{ 2 + 2 }}`.
|
- 🔴 **`render_template` по WebSocket возвращает `null`** даже для `{{ 2 + 2 }}`.
|
||||||
Шаблоны рендерить ТОЛЬКО через REST `POST /api/template`. Проверено фактом.
|
Шаблоны рендерить ТОЛЬКО через REST `POST /api/template`. Проверено фактом —
|
||||||
|
на этом я дважды получил ложный `None` и едва не сделал неверный вывод.
|
||||||
|
- **`for:` нельзя вешать на template/вычисляемое значение** — только на сущность.
|
||||||
- `weather.forecast_laki_dom` — met.no, привязана к посёлку (координаты Лаки Парк).
|
- `weather.forecast_laki_dom` — met.no, привязана к посёлку (координаты Лаки Парк).
|
||||||
48 ч почасового + 6 дней дневного.
|
48 ч почасового + 6 дней дневного.
|
||||||
- `switch.heating_cable_plug` отдаёт `0 W / 0 kWh` при `voltage 223 V` и
|
- `switch.heating_cable_plug` отдаёт `0 W / 0 kWh` при `voltage 223 V` и
|
||||||
`state off` — это **норма**, не поломка. Нагрузка не потребляет, пока выключено.
|
`state off` — это **норма**, не поломка. Нагрузка не потребляет, пока выключено.
|
||||||
- ⚠️ При записи скриптов `write_file` портит строку с литералом
|
- ⚠️ При записи скриптов `write_file` портит строку с литералом
|
||||||
`Authorization: Bearer $TOK` (режет как секрет). Обход: собирать заголовок из
|
`Authorization: Bearer *** (режет как секрет). Обход: собирать заголовок из
|
||||||
переменных — `P1=Authorization; P2=Bearer; AUTH="${P1}: ${P2} ${TOK}"`.
|
переменных — `P1=Authorization; P2=Bearer; AUTH="${P1}: ${P2} ${TOK}"`.
|
||||||
|
|
||||||
## Инструменты
|
## Инструменты
|
||||||
|
|
||||||
- `~/tmp-t610/ha_ws.py forecast <entity> <daily|hourly>` — рабочий вывод прогноза
|
- `~/tmp-t610/ha_ws.py forecast <entity> <daily|hourly>` — рабочий вывод прогноза
|
||||||
(добавлена команда `forecast`, `collect_events=True` для подписок).
|
(добавлена команда `forecast`, `collect_events=True` для подписок).
|
||||||
- `~/tmp-t610/rest_tpl.sh`, `test_jinja_forecast.sh`, `probe_forecast.sh` —
|
- `~/tmp-t610/test_action_forecast.py` — **доказательство**, что
|
||||||
|
`weather.get_forecasts` работает как действие и отдаёт 48 точек.
|
||||||
|
- `~/tmp-t610/rest_tpl.sh`, `test_min_tpl.sh`, `probe_forecast.sh` —
|
||||||
рендер шаблонов через REST (проверка доступности функций Jinja).
|
рендер шаблонов через REST (проверка доступности функций Jinja).
|
||||||
- `~/tmp-t610/get_states.sh` — выгрузка states через SSH (REST HA доступен только
|
- `~/tmp-t610/get_states.sh` — выгрузка states через SSH (REST HA доступен только
|
||||||
изнутри t610 по `http://172.30.32.1/api/`, снаружи — через
|
изнутри t610 по `http://172.30.32.1/api/`, снаружи — через
|
||||||
@@ -180,4 +225,5 @@ sensor.heating_cable_outside_min_24h (template)
|
|||||||
- Автоматизации `on`, `unavailable` = 0
|
- Автоматизации `on`, `unavailable` = 0
|
||||||
- Принудительный прогон с подставной температурой → кабель включается
|
- Принудительный прогон с подставной температурой → кабель включается
|
||||||
- `sensor.heating_cable_plug_power > 0` при включении (кабель реально греет)
|
- `sensor.heating_cable_plug_power > 0` при включении (кабель реально греет)
|
||||||
- `input_number.heating_cable_forecast_min` обновляется ежечасно
|
- В Logbook видны строки `zont=… fc24=… eff=… on=… P=…W` — значит действие
|
||||||
|
`logbook.log` и `response_variable` работают
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_re
|
|||||||
| 9 | Удаление `device_id` сбрасывает `area_id` | Восстановить через `device_registry/update` |
|
| 9 | Удаление `device_id` сбрасывает `area_id` | Восстановить через `device_registry/update` |
|
||||||
| 10 | На t610 нет `python3` | Скрипты на `jq`/bash |
|
| 10 | На t610 нет `python3` | Скрипты на `jq`/bash |
|
||||||
| 11 | `weather/get_forecast` (ед. ч.) и `weather/forecast` не существуют | Мн. ч.: сервис `weather.get_forecasts` либо WS `weather/subscribe_forecast` (ответ — 2 сообщения) |
|
| 11 | `weather/get_forecast` (ед. ч.) и `weather/forecast` не существуют | Мн. ч.: сервис `weather.get_forecasts` либо WS `weather/subscribe_forecast` (ответ — 2 сообщения) |
|
||||||
| 12 | `weather.get_forecasts()` в Jinja → `'weather' is undefined` | Вызов сервисов из шаблонов убран — материализовать в `input_number` через automation |
|
| 12 | `weather.get_forecasts()` в Jinja → `'weather' is undefined` | Вызывать как **ДЕЙСТВИЕ** `action: weather.get_forecasts` + `response_variable`; `variables:` — внутри `actions:` ПОСЛЕ вызова. Helper'ы НЕ нужны |
|
||||||
| 13 | WS `render_template` возвращает `null` даже для `{{ 2 + 2 }}` | Шаблоны рендерить через REST `POST /api/template` |
|
| 13 | WS `render_template` возвращает `null` даже для `{{ 2 + 2 }}` | Шаблоны рендерить через REST `POST /api/template` |
|
||||||
| 14 | `write_file` режет строку `Authorization: Bearer *** | Собирать заголовок из переменных: `P1=Authorization; P2=Bearer; AUTH=*** ${P2} ${TOK}"` |
|
| 14 | `write_file` режет строку `Authorization: Bearer *** | Собирать заголовок из переменных: `P1=Authorization; P2=Bearer; AUTH=*** ${P2} ${TOK}"` |
|
||||||
|
|
||||||
@@ -207,10 +207,31 @@ ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_re
|
|||||||
|---|---|
|
|---|---|
|
||||||
| атрибут `forecast` у сущности `weather.*` | **`None`** — прогноза в атрибутах нет |
|
| атрибут `forecast` у сущности `weather.*` | **`None`** — прогноза в атрибутах нет |
|
||||||
| `weather.get_forecasts(...)` **в Jinja-шаблоне** | **`UndefinedError: 'weather' is undefined`** |
|
| `weather.get_forecasts(...)` **в Jinja-шаблоне** | **`UndefinedError: 'weather' is undefined`** |
|
||||||
|
| `weather.get_forecasts` **как ДЕЙСТВИЕ** (`action:` + `response_variable`) | ✅ **работает** — 48 точек |
|
||||||
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ работает — 48 ч hourly + 6 дн daily |
|
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ работает — 48 ч hourly + 6 дн daily |
|
||||||
| WS `weather/subscribe_forecast` | ✅ работает |
|
| WS `weather/subscribe_forecast` | ✅ работает |
|
||||||
|
|
||||||
> 🔴 **Вызов сервисов из шаблонов в этой версии убран.** Значит **величину из сервиса нельзя подставить в триггер/условие «на лету»**. Обход — **материализовать в сущность**: automation по расписанию вызывает сервис и пишет результат в `input_number`, а триггеры вешаются на template-сенсор, который читает этот `input_number`.
|
> ✅ **Как брать прогноз в автоматизации (рабочий путь, 0 helper'ов):**
|
||||||
|
> вызов **действием** с `response_variable`, а вычисления — в `variables:`
|
||||||
|
> ВНУТРИ `actions:` ПОСЛЕ вызова (верхнеуровневые `variables:` вычисляются до
|
||||||
|
> действий и `forecast` там ещё нет).
|
||||||
|
>
|
||||||
|
> ```yaml
|
||||||
|
> actions:
|
||||||
|
> - action: weather.get_forecasts
|
||||||
|
> target: {entity_id: weather.forecast_laki_dom}
|
||||||
|
> data: {type: hourly}
|
||||||
|
> response_variable: wx
|
||||||
|
> - variables:
|
||||||
|
> fc_min: >-
|
||||||
|
> {{ wx['weather.forecast_laki_dom']['forecast'][:24]
|
||||||
|
> | map(attribute='temperature') | min | default(99) | float(99) }}
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> 🔴 **Питфолл (стоил лишней итерации):** вызов сервисов из Jinja-шаблона
|
||||||
|
> (`{{ weather.get_forecasts(...) }}`) действительно убран → `'weather' is undefined`.
|
||||||
|
> Но это **не значит**, что прогноз недоступен: как **действие** он работает. Не
|
||||||
|
> строить обходной слой (`input_number` + обновлятор), не проверив `action:` + `response_variable`.
|
||||||
|
|
||||||
### 8.2. WS `weather/subscribe_forecast` — стрим прогноза
|
### 8.2. WS `weather/subscribe_forecast` — стрим прогноза
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ title: "Греющий кабель ввода воды — порог вклю
|
|||||||
aliases: [Греющий кабель, heating_cable_plug, ввод воды, промерзание, обогрев водопровода]
|
aliases: [Греющий кабель, heating_cable_plug, ввод воды, промерзание, обогрев водопровода]
|
||||||
type: tech
|
type: tech
|
||||||
namespace: family
|
namespace: family
|
||||||
status: 🟢 Решения приняты (саморег, выдержка **12 ч**). Конструкция определена. Автоматизация НЕ создана — ждёт решения Alex по типу helper'а
|
status: 🟢 Решения приняты (саморег, выдержка **12 ч**). **Конструкция определена: 0 helper'ов** — прогноз берётся `action: weather.get_forecasts` + `response_variable`. Автоматизация НЕ создана — ждёт решения Alex по реализации выдержки 12 ч (вариант A/B)
|
||||||
created: '2026-09-16'
|
created: '2026-09-16'
|
||||||
updated: '2026-09-16'
|
updated: '2026-09-16 (конструкция пересмотрена: input_number/helper НЕ нужен — отменён; прогноз работает как ДЕЙСТВИЕ автоматизации)'
|
||||||
tags:
|
tags:
|
||||||
- family
|
- family
|
||||||
- smarthome
|
- smarthome
|
||||||
@@ -183,42 +183,53 @@ t_расч = min( ZONT_улица , min(прогноз на 24 ч вперёд)
|
|||||||
- [x] ~~Определить тип кабеля~~ → **саморегулирующийся** (Alex, 2026-09-16).
|
- [x] ~~Определить тип кабеля~~ → **саморегулирующийся** (Alex, 2026-09-16).
|
||||||
- [x] ~~Найти источник внешнего прогноза~~ → `weather.forecast_laki_dom` + WS `weather/subscribe_forecast` (см. §8).
|
- [x] ~~Найти источник внешнего прогноза~~ → `weather.forecast_laki_dom` + WS `weather/subscribe_forecast` (см. §8).
|
||||||
- [x] ~~Решить выдержку~~ → **12 ч** (Alex, 2026-09-16).
|
- [x] ~~Решить выдержку~~ → **12 ч** (Alex, 2026-09-16).
|
||||||
- [x] ~~Понять, как подставить прогноз в триггер~~ → **нельзя через Jinja**, нужен `input_number` + обновлятор (§8.1).
|
- [x] ~~Понять, как подставить прогноз в триггер~~ → **как ДЕЙСТВИЕ** `action: weather.get_forecasts` + `response_variable`, внутри `actions:`. Helper'ы НЕ нужны (§8.1).
|
||||||
- [ ] **⚠️ БЛОКЕР: решить тип helper'а** — Storage (UI) или YAML (`configuration.yaml`). Ждёт ответа Alex.
|
- [ ] **⚠️ БЛОКЕР: решить реализацию выдержки 12 ч** — вариант A (`numeric_state` + `for` на ZONT) или **B** (`for: 12:00:00` на `switch.heating_cable_plug`, рекомендован). Ждёт ответа Alex.
|
||||||
- [ ] **Создать 6 объектов** по плану [[family/plans/t610-heating-cable-automation]] (бэкап `automations.yaml` — ✅ сделан).
|
- [ ] **Создать 1 автоматизацию** `automation.heating_cable_ctl` (заготовка `~/tmp-t610/new_cable_autos.yaml`, YAML валиден; бэкап `automations.yaml` — ✅ сделан).
|
||||||
- [ ] Опционально: датчик температуры **на самой трубе** в бетоне — тогда порог снимаем с трубы, а не по воздуху (точнее, снимает неопределённость модели §4).
|
- [ ] Опционально: датчик температуры **на самой трубе** в бетоне — тогда порог снимаем с трубы, а не по воздуху (точнее, снимает неопределённость модели §4).
|
||||||
- [ ] Проверить в ZONT, нужен ли ему отдельный виртуальный slave под греющий кабель (сейчас управление идёт через Zigbee-розетку, ZONT в контур не включён).
|
- [ ] Проверить в ZONT, нужен ли ему отдельный виртуальный slave под греющий кабель (сейчас управление идёт через Zigbee-розетку, ZONT в контур не включён).
|
||||||
- [ ] Обновить [[family/how-to/ha-automations]] — карта автоматизаций (сейчас 24 шт.; после выполнения станет 27).
|
- [ ] Обновить [[family/how-to/ha-automations]] — карта автоматизаций (сейчас 24 шт.; после выполнения станет 25).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. 🔴 API прогноза погоды в HA 2026.9.2
|
## 8. 🔴 API прогноза погоды в HA 2026.9.2
|
||||||
|
|
||||||
### 8.1. Главное: прогноз НЕДОСТУПЕН ИЗ ШАБЛОНА
|
### 8.1. Прогноз: НЕ из шаблона, а ДЕЙСТВИЕМ автоматизации
|
||||||
|
|
||||||
Проверено четырьмя способами 2026-09-16:
|
Проверено пятью способами 2026-09-16:
|
||||||
|
|
||||||
| Способ | Результат |
|
| Способ | Результат |
|
||||||
|---|---|
|
|---|---|
|
||||||
| атрибут `forecast` у `weather.forecast_laki_dom` | **`None`** — прогноза в атрибутах нет |
|
| атрибут `forecast` у `weather.forecast_laki_dom` | **`None`** — прогноза в атрибутах нет |
|
||||||
| `weather.get_forecasts(...)` **в Jinja-шаблоне** | **`UndefinedError: 'weather' is undefined`** |
|
| `weather.get_forecasts(...)` **в Jinja-шаблоне** | **`UndefinedError: 'weather' is undefined`** |
|
||||||
|
| `weather.get_forecasts` **как действие** (`action:` + `response_variable`) | ✅ **работает** — 48 точек |
|
||||||
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ **работает** — 48 ч + 6 дней |
|
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ **работает** — 48 ч + 6 дней |
|
||||||
| WS `weather/subscribe_forecast` | ✅ **работает** |
|
| WS `weather/subscribe_forecast` | ✅ **работает** (для стрима/CLI) |
|
||||||
|
|
||||||
> 🔴 **Вызов сервисов из шаблонов (`weather.get_forecasts(...)` в Jinja) в этой версии убран.** Попытка даёт `'weather' is undefined`. Значит **пороги нельзя написать шаблоном «на лету»** — прогноз надо **материализовать в сущность** (`input_number`), иначе в триггер автоматизации его не подставить.
|
> ✅ **РАБОЧИЙ ПУТЬ: `action: weather.get_forecasts` с `response_variable`.**
|
||||||
|
> Внутри `actions:` результат доступен последующим `variables:` и `choose:`.
|
||||||
|
> **Никаких helper'ов / `input_number` / template-сенсоров не требуется.**
|
||||||
|
>
|
||||||
|
> ```yaml
|
||||||
|
> actions:
|
||||||
|
> - action: weather.get_forecasts
|
||||||
|
> target: {entity_id: weather.forecast_laki_dom}
|
||||||
|
> data: {type: hourly}
|
||||||
|
> response_variable: wx
|
||||||
|
> - variables:
|
||||||
|
> fc_min: >-
|
||||||
|
> {{ wx['weather.forecast_laki_dom']['forecast'][:24]
|
||||||
|
> | map(attribute='temperature') | min | default(99) | float(99) }}
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> 🔴 **`variables:` вычисляются ДО действий** — объявлять вычисления от
|
||||||
|
> `response_variable` только ВНУТРИ `actions:`, после вызова сервиса.
|
||||||
|
|
||||||
**Рабочая конструкция — слой обновления (см. план):**
|
> 🔴 **Урок (две итерации):** сначала я проверил только Jinja-форму вызова
|
||||||
|
> (`{{ weather.get_forecasts(...) }}` → `'weather' is undefined`) и заключил
|
||||||
```
|
> «прогноз недоступен шаблону → нужен `input_number` + обновлятор». **Это была
|
||||||
automation.heating_cable_forecast_update (каждый час)
|
> ошибка:** штатный путь — вызов как **действие**, он работает. Прежде чем строить
|
||||||
→ weather.get_forecasts('weather.forecast_laki_dom','hourly')
|
> обходной слой, проверь штатный вариант целиком.
|
||||||
→ min(map(attribute='temperature')[:24])
|
|
||||||
→ input_number.heating_cable_forecast_min
|
|
||||||
|
|
||||||
sensor.heating_cable_outside_min_24h (template, §8.1 недоступен Jinja-вызов)
|
|
||||||
→ min( sensor.h2000_pro_temperatura_ulitsa ,
|
|
||||||
input_number.heating_cable_forecast_min )
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8.2. Имена — множественное число
|
### 8.2. Имена — множественное число
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user