[2026-09-15] eagle: family/how-to/home-automation.md family/plans/heating-cable-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:
Alexey Martemyanov
2026-09-15 23:52:12 +06:00
parent 508652fae0
commit 174d7104ed
5 changed files with 526 additions and 17 deletions
+65
View File
@@ -14,6 +14,7 @@ tags:
related:
- '[[family/tech/zigbee-t610-z2m-i-zha]]'
- '[[family/how-to/home-automation]]'
- '[[family/tech/heating-cable-water-inlet]]'
---
# Реестры Home Assistant — операции
@@ -189,6 +190,68 @@ ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_re
| 8 | После сноса призраков дашборд ругается | Проверить ссылки дашбордов (§5) |
| 9 | Удаление `device_id` сбрасывает `area_id` | Восстановить через `device_registry/update` |
| 10 | На t610 нет `python3` | Скрипты на `jq`/bash |
| 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 |
| 13 | WS `render_template` возвращает `null` даже для `{{ 2 + 2 }}` | Шаблоны рендерить через REST `POST /api/template` |
| 14 | `write_file` режет строку `Authorization: Bearer *** | Собирать заголовок из переменных: `P1=Authorization; P2=Bearer; AUTH=*** ${P2} ${TOK}"` |
---
## 8. 🔴 Прогноз погоды и шаблоны (HA 2026.9.2)
### 8.1. Прогноз НЕДОСТУПЕН ИЗ ШАБЛОНА — главное
Проверено четырьмя способами 2026-09-16:
| Способ | Результат |
|---|---|
| атрибут `forecast` у сущности `weather.*` | **`None`** — прогноза в атрибутах нет |
| `weather.get_forecasts(...)` **в Jinja-шаблоне** | **`UndefinedError: 'weather' is undefined`** |
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ работает — 48 ч hourly + 6 дн daily |
| WS `weather/subscribe_forecast` | ✅ работает |
> 🔴 **Вызов сервисов из шаблонов в этой версии убран.** Значит **величину из сервиса нельзя подставить в триггер/условие «на лету»**. Обход — **материализовать в сущность**: automation по расписанию вызывает сервис и пишет результат в `input_number`, а триггеры вешаются на template-сенсор, который читает этот `input_number`.
### 8.2. WS `weather/subscribe_forecast` — стрим прогноза
```python
{"type": "weather/subscribe_forecast",
"entity_id": "weather.forecast_laki_dom",
"forecast_type": "daily"} # ⚠️ именно forecast_type, НЕ type; или "hourly"
```
| Способ | Результат |
|---|---|
| `POST /api/services/weather/get_forecast` (ед. ч., REST) | **400 Bad Request** |
| WS `call_service` → `weather.get_forecast` (ед. ч.) | `not_found` |
| WS `weather/forecast` | `unknown_command` |
| сервис **`weather.get_forecasts`** (мн. ч.) | ✅ работает |
| WS **`weather/subscribe_forecast`** | ✅ работает |
> 🔴 **ПИТФОЛЛ: ответ подписки приходит ДВУМЯ сообщениями** — сначала `result` (с `result: null`), затем отдельное `event` с `forecast`. Клиент, читающий только `result`, вернёт **0 точек**.
> Реализация: `~/tmp-t610/ha_ws.py forecast <entity> <hourly|daily>` (флаг `collect_events=True` → второй `recv()`).
> ⚠️ Версия WS-команды зависит от версии HA — при апгрейде перепроверять.
### 8.3. 🔴 `render_template` по WebSocket НЕ работает
> 🔴 **WS `render_template` возвращает `null` даже для `{{ 2 + 2 }}`** — проверено фактом. Это не ошибка шаблона, а неподдерживаемый метод.
> ✅ **Шаблоны рендерить ТОЛЬКО через REST** `POST /api/template`, тело `{"template": "..."}`. Через REST: `{{ 2 + 2 }}` → `4`, `{{ states('sensor.x') }}` → значение.
>
> ```bash
> jq -n --arg t '{{ 2 + 2 }}' '{template: $t}' > /tmp/tpl.json
> # затем POST /api/template (с t610 изнутри: http://172.30.32.1/api/template)
> ```
### 8.4. ⚠️ Питфолл окружения: `write_file` портит строку с `Bearer`
> ⚠️ При генерации скриптов **`write_file` режет литерал `Authorization: Bearer $TOK`** — строка приходит битой и скрипт не парсится (`unexpected EOF while looking for matching quote`). Обход — собирать заголовок из переменных:
>
> ```bash
> TOK=$(cat /tmp/.hatok)
> P1=Authorization
> P2=Bearer
> AUTH_HDR=*** ${P2} ${TOK}"
> ```
---
@@ -196,3 +259,5 @@ ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_re
- [[family/tech/zigbee-t610-z2m-i-zha]] — Zigbee на ZHA, §13 вычистка призраков
- [[family/how-to/home-automation]] — t610: топология, аддоны, доступ
- [[family/tech/heating-cable-water-inlet]] — практический кейс §8 (прогноз для греющего кабеля)
- [[family/plans/t610-heating-cable-automation]] — план автоматизации на базе §8.1
+150 -16
View File
@@ -3,7 +3,7 @@ title: "Греющий кабель ввода воды — порог вклю
aliases: [Греющий кабель, heating_cable_plug, ввод воды, промерзание, обогрев водопровода]
type: tech
namespace: family
status: 🟡 Расчёт выполнен, автоматизация НЕ создана (ждёт решения Alex по типу кабеля)
status: 🟢 Решения приняты (саморег, выдержка **12 ч**). Конструкция определена. Автоматизация НЕ создана ждёт решения Alex по типу helper'а
created: '2026-09-16'
updated: '2026-09-16'
tags:
@@ -16,6 +16,8 @@ related:
- '[[family/how-to/home-automation]]'
- '[[family/how-to/ha-automations]]'
- '[[family/documents/home-automation-wishlist]]'
- '[[family/plans/t610-heating-cable-automation]]'
- '[[family/tech/ha-registry-operations]]'
---
# Греющий кабель ввода воды — порог включения
@@ -28,15 +30,47 @@ related:
## 1. ИТОГ — пороги автоматизации
**Тип кабеля: САМОРЕГУЛИРУЮЩИЙСЯ** (подтверждено Alex 2026-09-16). Это меняет логику:
- перегрев не грозит (сам сбрасывает мощность при нагреве) → **нет смысла ждать, цель — успеть до промерзания бетона**;
- работа вхолостую стоит копейки → не экономим циклы, а защищаемся от замерзания;
- размер окна выдержки задаёт **тепловая инерция бетона (~сутки)**, а не риск для кабеля.
| Параметр | Значение | Обоснование |
|---|---|---|
| **ВКЛ** | улица**8 °C**, выдержка **≥ 30 мин** | при −8 °C труба в бетоне достигает 0 °C (см. §4) |
| **ВЫКЛ** | улица**3 °C**, выдержка **≥ 30 мин** | гистерезис 5 °C — бетон оттаивает медленно |
| **Безусловный ВКЛ** | улица**−20 °C** | игнорирует выдержку и гистерезис |
| **Алерт обрыва** | включили + 5 мин → `power < 5 W` | кабель/нагрузка не подключены |
| **ВКЛ** | `t_расч`**8 °C**, выдержка **12 ч** | при −8 °C труба в бетоне достигает 0 °C (§4); 12 ч отсекают ночные заморозки |
| **ВЫКЛ** | `t_расч`**3 °C**, выдержка **12 ч** | гистерезис 5 °C — бетон оттаивает медленно |
| **Безусловный ВКЛ** | `t_расч`**−20 °C** | игнорирует выдержку и гистерезис |
| **Fail-safe** | оба источника `unavailable` > 1 ч | ВКЛ + push (замёрзшая труба дороже лишних кВт) |
| **Алерт обрыва** | включили + 10 мин → `power < 5 W` | кабель/нагрузка не подключены |
**Датчик-триггер:** `sensor.h2000_pro_temperatura_ulitsa` (ZONT H2000_PRO, ZONT-шина).
**Исполнитель:** `switch.heating_cable_plug` (розетка NEO NAS-WR01B, Zigbee `a4c138eb6fbe9d19`, зона `kotelnaia`).
### 🔴 `t_расч` — расчётная температура по двум источникам
```
t_расч = min( ZONT_улица , min(прогноз на 24 ч вперёд) )
```
**Зачем второй источник:** уличный датчик ZONT — одна точка и может врать/отвалиться (реальный случай 2026-09-16: отдавал °F из-за ручного override, см. [[family/tech/ha-registry-operations]] §4). Если он замолчит в −25 °C, автоматизация промолчит в самый опасный момент. Внешний прогноз — независимый канал.
**Правило конфликта:** берём **более холодный** из двух. Fail-safe смещён в сторону защиты от замерзания, а не экономии.
**Источники:**
- **Датчик:** `sensor.h2000_pro_temperatura_ulitsa` (ZONT H2000_PRO, ZONT-шина).
- **Прогноз:** `weather.forecast_laki_dom` (met.no, привязан к посёлку Лаки Парк; 48 ч почасового + 6 дней).
- **Исполнитель:** `switch.heating_cable_plug` (розетка NEO NAS-WR01B, Zigbee `a4c138eb6fbe9d19`, зона `kotelnaia`).
> 🔴 **API прогноза в HA 2026.9.2 — только WS-команда `weather/subscribe_forecast`.** Подробности и точный вызов — §8.
### ✅ Выдержка — РЕШЕНО: 12 ч (Alex, 2026-09-16)
Обсуждались 6 ч / 12 ч / 24 ч. Alex выбрал **12 ч** — «ни нашим ни нашим».
| Вариант | Плюс | Минус |
|---|---|---|
| 24 ч | отсекает все ночные заморозки, минимум ложных включений | при резком ударе мороза (−15 °C за ночь) кабель включится только через сутки |
| **12 ч** ✅ | компромисс: ночные заморозки отсекаются, резкое похолодание ловится в тот же день | не крайний ни в одну сторону |
| 6 ч | ловит резкое похолодание в тот же день | может дёрнуться на ночном заморозке в сентябре |
Бетон за сутки не промёрзнет в любом варианте.
---
@@ -111,12 +145,19 @@ related:
---
## 5. Почему выдержка 30 мин, а не мгновенное включение
## 5. Почему выдержка в часах, а не мгновенное включение
Бетон — тепловая масса. Промерзает за часы/сутки, а не за минуту.
- Кратковременные −10 °C ночью в сентябре **не опасны**.
Бетон — тепловая масса. Промерзает за **сутки**, а не за минуту или час.
- Кратковременные −10 °C ночью в сентябре **не опасны** — за ночь бетон не промёрзнет.
- При затяжном похолодании выдержка уже прошла → кабель включён **до** того, как бетон успеет охладиться.
- **Инерция бетона ≈ сутки — это и есть верхняя граница окна.** Нижняя — время, за которое бетон успевает остыть до 0 °C при −8 °C на улице.
- После оттепели бетон оттаивает медленно → выключение с той же выдержкой.
- Инерция работает в обе стороны.
- **Итог: 12 ч** (выбор Alex). Отсекает одиночные ночные заморозки, но не пропускает резкое похолодание на весь день.
> 🔴 **Исправление первой версии расчёта:** изначально стояло «30 мин». Это была ошибка — при инерции бетона в сутки выдержка 30 мин пропускает ночные заморозки и даёт лишние включения. Далее обсуждались 6/12/24 ч; принято **12 ч**.
>
> **Важно:** выдержку задаёт **инерция бетона**, а не защита кабеля. Для саморег-кабеля перегрев невозможен, поэтому «греть подольше» не вредит — наоборот, выгоднее.
---
@@ -139,18 +180,111 @@ related:
## 7. Что НЕ сделано (следующие шаги)
- [ ] **Автоматизация не создана.** Ждёт ответа на вопрос: **саморегулирующийся кабель или резистивный?**
- Саморег — можно не гистерезить, сам сбрасывает мощность;
- Резистивный — обязателен термостат/гистерезис, иначе перегрев.
- Дефолт безопасен для обоих типов: **гистерезис 8/3**.
- [x] ~~Определить тип кабеля~~**саморегулирующийся** (Alex, 2026-09-16).
- [x] ~~Найти источник внешнего прогноза~~`weather.forecast_laki_dom` + WS `weather/subscribe_forecast` (см. §8).
- [x] ~~Решить выдержку~~**12 ч** (Alex, 2026-09-16).
- [x] ~~Понять, как подставить прогноз в триггер~~**нельзя через Jinja**, нужен `input_number` + обновлятор (§8.1).
- [ ] **⚠️ БЛОКЕР: решить тип helper'а** — Storage (UI) или YAML (`configuration.yaml`). Ждёт ответа Alex.
- [ ] **Создать 6 объектов** по плану [[family/plans/t610-heating-cable-automation]] (бэкап `automations.yaml` — ✅ сделан).
- [ ] Опционально: датчик температуры **на самой трубе** в бетоне — тогда порог снимаем с трубы, а не по воздуху (точнее, снимает неопределённость модели §4).
- [ ] Проверить в ZONT, нужен ли ему отдельный виртуальный slave под греющий кабель (сейчас управление идёт через Zigbee-розетку, ZONT в контур не включён).
- [ ] Обновить [[family/how-to/ha-automations]] — карта автоматизаций (сейчас 24 шт.; после выполнения станет 27).
---
## 8. 🔴 API прогноза погоды в HA 2026.9.2
### 8.1. Главное: прогноз НЕДОСТУПЕН ИЗ ШАБЛОНА
Проверено четырьмя способами 2026-09-16:
| Способ | Результат |
|---|---|
| атрибут `forecast` у `weather.forecast_laki_dom` | **`None`** — прогноза в атрибутах нет |
| `weather.get_forecasts(...)` **в Jinja-шаблоне** | **`UndefinedError: 'weather' is undefined`** |
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ **работает** — 48 ч + 6 дней |
| WS `weather/subscribe_forecast` | ✅ **работает** |
> 🔴 **Вызов сервисов из шаблонов (`weather.get_forecasts(...)` в Jinja) в этой версии убран.** Попытка даёт `'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. Имена — множественное число
> 🔴 **Сервис называется `weather.get_forecasts` (МНОЖЕСТВЕННОЕ число).** Единственное `weather.get_forecast` **не существует** → `not_found: Service weather.get_forecast not found`.
```python
# ✅ работает (REST / WS call_service)
{"domain":"weather","service":"get_forecasts",
"service_data":{"entity_id":"weather.forecast_laki_dom","type":"daily"},
"return_response": True}
```
### 8.3. WS-подписка — единственный путь для стрима
```python
{"type": "weather/subscribe_forecast",
"entity_id": "weather.forecast_laki_dom",
"forecast_type": "daily"} # ⚠️ именно forecast_type, НЕ type; или "hourly"
```
**Что НЕ работает (проверено фактом):**
| Способ | Результат |
|---|---|
| WS `weather/forecast` | `unknown_command` |
| WS `call_service``weather.get_forecast` (ед. ч.) | `not_found` |
| `POST /api/services/weather/get_forecast` (ед. ч.) | **400 Bad Request** |
> 🔴 **Питфолл: ответ подписки приходит ДВУМЯ сообщениями.** Сначала `{"type":"result","success":true,"result":null}`, затем отдельным сообщением `{"type":"event","event":{"type":"daily","forecast":[...]}}`. Наивный WS-клиент, ждущий только `result`, вернёт **0 точек** — прогноз надо читать вторым `recv()`.
### 8.4. 🔴 `render_template` по WebSocket НЕ работает
> 🔴 **WS `render_template` возвращает `null` даже для `{{ 2 + 2 }}`** — проверено фактом. Шаблоны рендерить **ТОЛЬКО через REST** `POST /api/template` с телом `{"template": "..."}`. Через REST работает и `{{ 2 + 2 }}` → `4`, и `{{ states('sensor...') }}`.
**Что отдаёт `weather.forecast_laki_dom` (met.no):**
- **Атрибут** `temperature` = текущая (11.8 °C на момент проверки);
- **`hourly`** — 48 точек (достаточно для окна 24 ч);
- **`daily`** — 6 точек, поле `templow` (минимум ночи) + `temperature` (максимум дня).
**Инструмент:** `~/tmp-t610/ha_ws.py forecast <entity> <hourly|daily>` — добавлена команда `forecast` (реализация: `collect_events=True` — второй `recv()` после `result`).
```bash
cd ~/tmp-t610 && python3 ha_ws.py forecast weather.forecast_laki_dom daily
```
> ⚠️ **`ha_ws.py` ходит через внешний `wss://mallexxx.duckdns.org` и работает с Mac.** Локальный `http://192.168.2.176` с Mac недоступен (000), а `http://172.30.32.1` доступен только с t610 по SSH. Для REST-запросов — SSH-туннель (см. [[family/how-to/home-automation]] §2).
### 8.5. ⚠️ Питфолл окружения: `write_file` портит строку с `Bearer`
> ⚠️ При генерации скриптов **`write_file` режет литерал `Authorization: Bearer $TOK`** — строка приходит битой, скрипт не парсится (`unexpected EOF while looking for matching quote`). **Обход:** собирать заголовок из переменных:
>
> ```bash
> TOK=$(cat /tmp/.hatok)
> P1=Authorization
> P2=Bearer
> AUTH_HDR="${P1}: ${P2} ${TOK}"
> ```
>
> Тот же эффект — на строках с `suggested_unit_of_measurement` из §4 реестровых операций.
---
## Связанные заметки
- [[family/plans/t610-heating-cable-automation]] — **план выполнения автоматизации** (шаги, конструкция, питфоллы)
- [[family/how-to/home-automation]] — топология t610, ZONT, Modbus, Zigbee
- [[family/how-to/ha-automations]] — логика и карта автоматизаций
- [[family/documents/home-automation-wishlist]] — роадмап (§7 энергетика)
- [[family/tech/ha-registry-operations]] — правка опций сущности (кейс °F→°C для H2000_PRO)
- [[family/tech/ha-registry-operations]] — правка опций сущности (кейс °F→°C для H2000_PRO), §8 прогноз погоды