[2026-09-16] eagle: family/documents/home-automation-wishlist.md family/how-to/ha-automations.md 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-16 00:02:25 +06:00
parent 82e5cb2640
commit 6a350cc802
7 changed files with 190 additions and 409 deletions
+118 -273
View File
@@ -1,301 +1,146 @@
---
title: "Греющий кабель ввода воды — порог включения (расчёт)"
aliases: [Греющий кабель, heating_cable_plug, ввод воды, промерзание, обогрев водопровода]
type: tech
namespace: family
status: 🟢 Решения приняты (саморег, выдержка **12 ч**). **Конструкция определена: 0 helper'ов** — прогноз берётся `action: weather.get_forecasts` + `response_variable`. Автоматизация НЕ создана — ждёт решения Alex по реализации выдержки 12 ч (вариант A/B)
created: '2026-09-16'
updated: '2026-09-16 (конструкция пересмотрена: input_number/helper НЕ нужен — отменён; прогноз работает как ДЕЙСТВИЕ автоматизации)'
tags:
- family
- smarthome
- t610
- heating
- zimnik
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]]'
---
# Греющий кабель ввода воды (t610)
# Греющий кабель ввода воды — порог включения
> Справочник: расчёт порогов и автоматизация обогрева ввода воды.
> **Задача:** определить, при какой уличной температуре включать греющий кабель, обогревающий ввод воды в дом.
> **Конструкция:** труба (ПНД) уходит сквозь бетонную фундамент-подушку **30 см** и далее в грунт (**суглинок**) на глубину **~4 м**.
> **Регион:** Новосибирск, ДНП «Лаки Парк» (55.257328, 83.048234).
## 1. Исходные данные
---
## 1. ИТОГ — пороги автоматизации
**Тип кабеля: САМОРЕГУЛИРУЮЩИЙСЯ** (подтверждено Alex 2026-09-16). Это меняет логику:
- перегрев не грозит (сам сбрасывает мощность при нагреве) → **нет смысла ждать, цель — успеть до промерзания бетона**;
- работа вхолостую стоит копейки → не экономим циклы, а защищаемся от замерзания;
- размер окна выдержки задаёт **тепловая инерция бетона (~сутки)**, а не риск для кабеля.
| Параметр | Значение | Обоснование |
|---|---|---|
| **ВКЛ** | `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` | кабель/нагрузка не подключены |
### 🔴 `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 ч | ловит резкое похолодание в тот же день | может дёрнуться на ночном заморозке в сентябре |
Бетон за сутки не промёрзнет в любом варианте.
---
## 2. Климатология (СП 131.13330.2020, табл. 5.1 — Новосибирск)
| Месяц | t, °C | | Месяц | t, °C |
|---|---|---|---|---|
| янв | 17,6 | | июл | +19,4 |
| фев | 15,4 | | авг | +16,4 |
| мар | 7,7 | | сен | +9,9 |
| апр | +2,3 | | окт | +1,5 |
| май | +11,0 | | ноя | 7,9 |
| июн | +17,3 | | дек | 15,3 |
- **Сумма среднемесячных отрицательных** `Mt = 17,6 + 15,4 + 7,7 + 7,9 + 15,3 = 63,9`
- **Среднегодовая t воздуха** = +1,2 °C
- Минимальная температура (СП 20.13330, карта 4) = 45 °C
---
## 3. Глубина промерзания и что творится на 4 м
**Формула СП 22.13330:** `d_fn = d0 · √Mt`, где `d0` зависит от грунта.
| Грунт | `d0` | `d_fn` |
|---|---|---|
| **Суглинок / глина** | 0,23 | **1,84 м** |
| Супесь, песок мелкий/пылеватый | 0,28 | 2,24 м |
| Песок гравелистый/крупный | 0,30 | 2,40 м |
| Крупнообломочный | 0,34 | 2,72 м |
**Наш случай — суглинок:** `d_fn = 0,23 × √63,9 = 1,84 м` (открытая поверхность, без снега).
**Под снегом 30–40 см** реальное промерзание меньше: **1,31,6 м**.
### Грунт на глубине трубы (4 м)
Температуропроводность суглинка: `a = λ / C = 1,4 / 2,5e6 ≈ 5,6e-7 м²/с`.
Глубина затухания волны в `e` раз: `z_зат = √(a·T/π)`
| Волна | Период | `z_зат` |
|---|---|---|
| Суточная | 86 400 с | **0,12 м** |
| Годовая | 365 сут | **2,37 м** |
**Амплитуда годового хода на 4 м:** `19,0 × exp(4,0/2,37) = ±3,5 °C` от среднегодовой.
> ✅ **ГЛАВНЫЙ ВЫВОД: труба на 4 м НЕ ЗАМЕРЗАЕТ ФИЗИЧЕСКИ.**
> Там круглый год **+2,5…+3,5 °C** — грунт практически изотермичен.
> Зона промерзания (до 1,84 м) заканчивается задолго до трубы.
---
## 4. Критичная точка — бетонная подушка 30 см
Единственное место, где есть риск. Причина: **бетон — теплопроводный мост**.
- `λ_бетона ≈ 1,7` Вт/(м·К) против `λ_суглинка ≈ 1,4` — на 21 % выше;
- сверху нет снеговой шубы, как над грунтом;
- на бетон приходится **72,6 %** перепада температуры (расчёт через термические сопротивления: `R_возд = 1/15 = 0,067`, `R_бет = 0,30/1,7 = 0,177`).
| Улица | Труба в бетоне | |
|---|---|---|
| 6 °C | +0,5 °C | |
| **8 °C** | **0,1 °C** | ⬅ **ПОРОГ** |
| 10 °C | 0,6 °C | |
| 12 °C | 1,1 °C | |
| 15 °C | 1,9 °C | |
| 20 °C | 3,1 °C | |
| 25 °C | 4,4 °C | |
| 30 °C | 5,6 °C | |
---
## 5. Почему выдержка в часах, а не мгновенное включение
Бетон — тепловая масса. Промерзает за **сутки**, а не за минуту или час.
- Кратковременные −10 °C ночью в сентябре **не опасны** — за ночь бетон не промёрзнет.
- При затяжном похолодании выдержка уже прошла → кабель включён **до** того, как бетон успеет охладиться.
- **Инерция бетона ≈ сутки — это и есть верхняя граница окна.** Нижняя — время, за которое бетон успевает остыть до 0 °C при −8 °C на улице.
- После оттепели бетон оттаивает медленно → выключение с той же выдержкой.
- **Итог: 12 ч** (выбор Alex). Отсекает одиночные ночные заморозки, но не пропускает резкое похолодание на весь день.
> 🔴 **Исправление первой версии расчёта:** изначально стояло «30 мин». Это была ошибка — при инерции бетона в сутки выдержка 30 мин пропускает ночные заморозки и даёт лишние включения. Далее обсуждались 6/12/24 ч; принято **12 ч**.
>
> **Важно:** выдержку задаёт **инерция бетона**, а не защита кабеля. Для саморег-кабеля перегрев невозможен, поэтому «греть подольше» не вредит — наоборот, выгоднее.
---
## 6. Состояние железа (проверено 2026-09-16)
| Сущность | Значение | Комментарий |
|---|---|---|
| `switch.heating_cable_plug` | `off` | розетка живёт, выключена |
| `sensor.heating_cable_plug_voltage` | `223 V` | напряжение в розетке есть |
| `sensor.heating_cable_plug_power` | `0.0 W` | **ожидаемо при `off`** |
| `sensor.heating_cable_plug_energy` | `0.0 kWh` | |
| `sensor.h2000_pro_temperatura_ulitsa` | `12.8 °C` | после фикса °F→°C 2026-09-16 |
> ⚠️ **`0 Вт` — это норма, пока `switch` = `off`, а не поломка.** Ранее (2026-09-15) в [[family/documents/home-automation-wishlist]] §7 это было записано как подозрение на мёртвый мониторинг. **Уточнение:** напряжение `223 V` присутствует → розетка работает; нулевая мощность при выключенном реле ожидаема. Проверка живости нагрузки возможна только после первого включения.
> 💡 Отсюда — **алерт обрыва в автоматизации:** включили → через 5 мин ждём `power > 5 W`; если ноль — кабель не подключён либо перебит.
**Наличие кабеля:** в закупках зафиксировано «Греющий кабель в ПНД × 6 м» + «Ввод греющего кабеля» ([[family/documents/lerua-shopping]]).
---
## 7. Что НЕ сделано (следующие шаги)
- [x] ~~Определить тип кабеля~~**саморегулирующийся** (Alex, 2026-09-16).
- [x] ~~Найти источник внешнего прогноза~~`weather.forecast_laki_dom` + WS `weather/subscribe_forecast` (см. §8).
- [x] ~~Решить выдержку~~**12 ч** (Alex, 2026-09-16).
- [x] ~~Понять, как подставить прогноз в триггер~~**как ДЕЙСТВИЕ** `action: weather.get_forecasts` + `response_variable`, внутри `actions:`. Helper'ы НЕ нужны (§8.1).
- [ ] **⚠️ БЛОКЕР: решить реализацию выдержки 12 ч** — вариант A (`numeric_state` + `for` на ZONT) или **B** (`for: 12:00:00` на `switch.heating_cable_plug`, рекомендован). Ждёт ответа Alex.
- [ ] **Создать 1 автоматизацию** `automation.heating_cable_ctl` (заготовка `~/tmp-t610/new_cable_autos.yaml`, YAML валиден; бэкап `automations.yaml` — ✅ сделан).
- [ ] Опционально: датчик температуры **на самой трубе** в бетоне — тогда порог снимаем с трубы, а не по воздуху (точнее, снимает неопределённость модели §4).
- [ ] Проверить в ZONT, нужен ли ему отдельный виртуальный slave под греющий кабель (сейчас управление идёт через Zigbee-розетку, ZONT в контур не включён).
- [ ] Обновить [[family/how-to/ha-automations]] — карта автоматизаций (сейчас 24 шт.; после выполнения станет 25).
---
## 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` **как действие** (`action:` + `response_variable`) | ✅ **работает** — 48 точек |
| сервис `weather.get_forecasts` (мн. число), REST/WS | ✅ **работает** — 48 ч + 6 дней |
| WS `weather/subscribe_forecast` | ✅ **работает** (для стрима/CLI) |
| Регион | Новосибирск, Лаки Парк (55.257328, 83.048234) |
| Грунт | суглинок |
| Глубина трубы в грунте | ~4 м |
| Бетонная подушка фундамента | 30 см |
| Тип кабеля | саморегулирующийся |
| Управление | `switch.heating_cable_plug` (NEO NAS-WR01B, `a4c138eb6fbe9d19`, котельная) |
| Уличный датчик | `sensor.h2000_pro_temperatura_ulitsa` (ZONT H2000_PRO) |
| Внешний прогноз | `weather.forecast_laki_dom` (met.no, координаты посёлка) |
| Автоматизация | `automation.greiushchii_kabel_upravlenie` |
> ✅ **РАБОЧИЙ ПУТЬ: `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:`, после вызова сервиса.
## 2. Расчёт промерзания (СП 131.13330.2020)
> 🔴 **Урок (две итерации):** сначала я проверил только Jinja-форму вызова
> (`{{ weather.get_forecasts(...) }}` → `'weather' is undefined`) и заключил
> «прогноз недоступен шаблону → нужен `input_number` + обновлятор». **Это была
> ошибка:** штатный путь — вызов как **действие**, он работает. Прежде чем строить
> обходной слой, проверь штатный вариант целиком.
Отрицательные среднемесячные Новосибирска: `янв −17,6 · фев −15,4 · мар −7,7 · ноя −7,9 · дек −15,3`**Mt = 63,9**
### 8.2. Имена — множественное число
```
d_fn = d0 · √Mt = 0,23 · √63,9 = 1,84 м (суглинок, открытая поверхность)
```
Под снегом 30–40 см реально **1,31,6 м**.
> 🔴 **Сервис называется `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}
Затухание годовой волны (`a = λ/C = 1,4 / 2,5·10⁶ = 5,6·10⁻⁷ м²/с`):
```
z_damp = √(a·T/π) = 2,37 м
A(4 м) = 19 · e^(4/2,37) = ±3,5 °C
```
### 8.3. WS-подписка — единственный путь для стрима
**Труба на 4 м не замерзает физически** — грунт там +2,5…+3,5 °C круглый год.
```python
{"type": "weather/subscribe_forecast",
"entity_id": "weather.forecast_laki_dom",
"forecast_type": "daily"} # ⚠️ именно forecast_type, НЕ type; или "hourly"
## 3. Критичная точка — бетонная подушка 30 см
Бетон промерзает быстрее грунта: `λ = 1,7` против `1,4`, снеговой шубы нет.
```
R_возд = 1/15 = 0,067 (м²·К)/Вт
R_бетон = 0,30/1,7 = 0,176 (м²·К)/Вт
→ 72 % перепада падает на бетон
```
**Что НЕ работает (проверено фактом):**
| Способ | Результат |
| Улица | Труба в бетоне |
|---|---|
| WS `weather/forecast` | `unknown_command` |
| WS `call_service``weather.get_forecast` (ед. ч.) | `not_found` |
| `POST /api/services/weather/get_forecast` (ед. ч.) | **400 Bad Request** |
| 6 °C | +0,5 °C |
| **8 °C** | **−0,1 °C** ← порог включения |
| 10 °C | 0,6 °C |
| 15 °C | 1,9 °C |
| 20 °C | 3,1 °C |
| 25 °C | 4,4 °C |
> 🔴 **Питфолл: ответ подписки приходит ДВУМЯ сообщениями.** Сначала `{"type":"result","success":true,"result":null}`, затем отдельным сообщением `{"type":"event","event":{"type":"daily","forecast":[...]}}`. Наивный WS-клиент, ждущий только `result`, вернёт **0 точек** — прогноз надо читать вторым `recv()`.
## 4. Пороги
### 8.4. 🔴 `render_template` по WebSocket НЕ работает
| Событие | Условие | Выдержка |
|---|---|---|
| ВКЛ | `eff ≤ 8 °C` | 12 ч |
| ВЫКЛ | `eff ≥ 3 °C` | 12 ч |
| Аварийный ВКЛ | `eff ≤ 20 °C` | без выдержки |
| Fail-safe | ZONT `unknown`/`unavailable` | ВКЛ |
| Обрыв | розетка `on`, `power < 5 W` | push |
> 🔴 **WS `render_template` возвращает `null` даже для `{{ 2 + 2 }}`** — проверено фактом. Шаблоны рендерить **ТОЛЬКО через REST** `POST /api/template` с телом `{"template": "..."}`. Через REST работает и `{{ 2 + 2 }}` → `4`, и `{{ states('sensor...') }}`.
`eff` = ZONT, если датчик жив; иначе прогноз-мин на 24 ч.
**Что отдаёт `weather.forecast_laki_dom` (met.no):**
- **Атрибут** `temperature` = текущая (11.8 °C на момент проверки);
- **`hourly`** — 48 точек (достаточно для окна 24 ч);
- **`daily`** — 6 точек, поле `templow` (минимум ночи) + `temperature` (максимум дня).
**Почему 12 ч:** тепловая инерция бетонной подушки ~сутки. 12 ч отсекает одиночные ночные заморозки, но ловит затяжное похолодание в тот же день.
**Инструмент:** `~/tmp-t610/ha_ws.py forecast <entity> <hourly|daily>` — добавлена команда `forecast` (реализация: `collect_events=True` — второй `recv()` после `result`).
**Почему саморег:** кабель сбрасывает мощность при нагреве сам, перегрев невозможен. Задержка нужна не «чтобы не спалить», а чтобы не дёргать реле на каждую холодную ночь.
**Почему прогноз:** ZONT — одна точка, может врать или отвалиться. Прогноз — независимый канал; при отвале датчика переключаемся на него, а не остаёмся без защиты.
## 5. Автоматизация
**Триггеры:** `time_pattern /15` + `numeric_state ZONT below 8` + `state ZONT → unknown/unavailable 30 мин`
**Файл:** `/config/automations.yaml` · `mode: single`
```yaml
actions:
- action: weather.get_forecasts # ПЕРВЫМ действием
target: {entity_id: weather.forecast_laki_dom}
data: {type: hourly}
response_variable: wx
- variables: # ПОСЛЕ вызова — wx уже определён
zont_ok: "{{ states('sensor.h2000_pro_temperatura_ulitsa') not in ['unknown','unavailable','none',''] }}"
zont: "{{ states('sensor.h2000_pro_temperatura_ulitsa') | float(-100) }}"
fc_min: "{{ wx['weather.forecast_laki_dom']['forecast'][:24] | map(attribute='temperature') | min | float(-100) }}"
eff: "{{ zont if zont_ok else fc_min }}"
- choose: [...] # 5 веток: авария / fail-safe / ВКЛ / ВЫКЛ / обрыв
```
Выдержка 12 ч — через `for: '12:00:00'` на `switch.heating_cable_plug` в условии включения (на вычисляемый `eff` вешать нельзя).
## 6. Проверка
```bash
cd ~/tmp-t610 && python3 ha_ws.py forecast weather.forecast_laki_dom daily
cd ~/tmp-t610
python3 ha_ws.py forecast weather.forecast_laki_dom hourly # прогноз
python3 verify_cable.py # расчёт eff + пороги
```
> ⚠️ **`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).
В Logbook видны строки `zont=… fc24=… eff=… on=… P=…W`.
### 8.5. ⚠️ Питфолл окружения: `write_file` портит строку с `Bearer`
## 7. Питфоллы
> ⚠️ При генерации скриптов **`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 реестровых операций.
### 7.1 Прогноз в HA: как НЕ работает и как работает
---
| Способ | Результат |
|---|---|
| Атрибут `state_attr('weather.x','forecast')` | `None` — прогноза в атрибутах нет |
| `weather.get_forecasts(...)` в Jinja | `'weather' is undefined` |
| REST `POST /api/services/weather/get_forecast` | `400` |
| WS `{"type":"weather/forecast"}` | `unknown_command` |
| WS `{"type":"weather/subscribe_forecast", forecast_type: …}` | ✅ работает |
| **`action: weather.get_forecasts` в автоматизации** | ✅ работает |
## Связанные заметки
Сервис — **`weather.get_forecasts`** (множественное число). В автоматизации вызывается как `action:` с `response_variable`; данные — `wx['weather.forecast_laki_dom']['forecast']`.
- [[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), §8 прогноз погоды
### 7.2 `variables:` вычисляются ДО действий
Объявлять `variables:` с данными от `response_variable` только **внутри `actions:`, после вызова сервиса**. На верхнем уровне автоматизации `wx` ещё не существует.
### 7.3 `min([99, fc_min])` ломает fail-safe
Наивная проверка отвала датчика через `float(99)` + `min` не работает: `min([99, 11.1])` = 11.1, условие `eff == 99` не сработает никогда.
Правильно — отдельный флаг по строковому состоянию:
```jinja
zont_ok: "{{ states('sensor.h2000_pro_temperatura_ulitsa') not in ['unknown','unavailable','none',''] }}"
eff: "{{ zont if zont_ok else fc_min }}"
```
### 7.4 WS-подписки на прогноз приходят двумя сообщениями
Сначала `result`, затем `event` с прогнозом. Клиент, ждущий только `result`, получит **0 точек** — нужен `collect_events=True`.
### 7.5 `switch.heating_cable_plug` = `0 W` при `off` — это норма
`voltage 223 V`, `state off`, `power 0.0 W`. Нагрузка не потребляет, пока выключено. Не поломка.
### 7.6 Доступ к API
- С Mac: только `https://mallexxx.duckdns.org`. Raw-IP + plain HTTP → апрув на каждую команду.
- `http://192.168.2.176:8123` с Mac → `000`, соединения нет.
- `http://172.30.32.1/api/` — только изнутри t610, порт **80**.
- WS `render_template` возвращает `null` даже для `2+2` — шаблоны рендерить только через REST `POST /api/template`.