diff --git a/family/documents/home-automation-wishlist.md b/family/documents/home-automation-wishlist.md index 834ba72e..adc79b1e 100644 --- a/family/documents/home-automation-wishlist.md +++ b/family/documents/home-automation-wishlist.md @@ -119,6 +119,6 @@ ZONT-реле котлов уже дают статусы; 2 Zigbee-розетк - [[family/how-to/home-automation]] — карта железза: AT2 (параметры/PWM), Slave ID, регистры заслонок/реле, ZONT relays - [[family/how-to/ha-automations]] — логика HA-автоматизаций, карта device_id/entity_id, разбор дефекта «ночной свет душевой» - [[family/how-to/home-automation]] — алгоритм вентиляции по CO₂ (Node-RED) -- [[family/tech/heating-cable-water-inlet]] — расчёт порога включения греющего кабеля ввода воды +- [[family/how-to/ha-automations]] §7 — греющий кабель ввода воды - [[family/documents/home-wishlist]] — хотелки по дому и участку (не автоматизация) - [[family/index]] — топик-карта family/ diff --git a/family/how-to/ha-automations.md b/family/how-to/ha-automations.md index 71bed7d2..81358a46 100644 --- a/family/how-to/ha-automations.md +++ b/family/how-to/ha-automations.md @@ -2,9 +2,11 @@ > **Справочник логики автоматизаций** (`automations.yaml` на t610). Топология/команды/Modbus — [[family/how-to/home-automation]]. -> 🟢 **АКТУАЛЬНО 2026-09-15 (поздний вечер): 24 АВТОМАТИЗАЦИИ — 23 `on`, 1 `off` (`Ventilation automation on`, намеренно), `unavailable` = 0.** Zigbee работает на ZHA. +> 🟢 **АКТУАЛЬНО 2026-09-16: 25 АВТОМАТИЗАЦИЙ — 24 `on`, 1 `off` (`Ventilation automation on`, намеренно), `unavailable` = 0.** Zigbee работает на ZHA. > -> 📌 **Сверка счёта:** в §1 ниже упоминается «26» — это счёт **включая 2 удалённые батарейные**, которые ещё числились сиротами в реестре. После чистки реестра фактически **24**. Брать 24. +> **➕ 2026-09-16: добавлена `Греющий кабель: управление`** (`automation.greiushchii_kabel_upravlenie`, id `heating_cable_ctl_0001`) — управление вводом воды по `min(ZONT-улица, прогноз met.no 24ч)`, пороги −8/−3 °C (выдержка 12 ч) + аварийный −20 °C + fail-safe. Расчёт обоснования порогов — §7.1. +> +> 📌 **Сверка счёта:** в §1 ниже упоминается «26» — это счёт **включая 2 удалённые батарейные**, которые ещё числились сиротами в реестре. После чистки реестра было **24**, после 2026-09-16 — **25**. Брать 25. > > **➕ Добавлено в этот вечер: 12 автоматизаций контроля батарей** (id `8800000000000`…`8800000000011`, все `on`). Порог **20 %**, выдержка **2 ч**, двойной канал: `persistent_notification` + push `notify.mobile_app_sm_s931b`; при возврате заряда уведомление гасится (`notification_id: bat_`). Детали — §5. > ⛔ **Удалены 2 прежние батарейные** (`1773451323415`, `1773459663218`) — были с порогом 10 и без push. Их осиротевшие записи в реестре вычищены (питфолл §5.1). @@ -34,7 +36,8 @@ ## 1. Где живёт - **Файл:** `/config/automations.yaml` в HA Core на t610. -- **Всего:** **24 автоматизации — 23 `on`, 1 `off`** (`Ventilation automation on`, намеренно, `last_triggered` 12 марта), **`unavailable` = 0**. Файл = 228 строк. +- **Всего:** **25 автоматизаций — 24 `on`, 1 `off`** (`Ventilation automation on`, намеренно, `last_triggered` 12 марта), **`unavailable` = 0**. Файл = 780 строк (650 + 130 новой автоматизации кабеля). +- **Бэкапы перед правками 2026-09-16 (кабель):** `/config/automations.yaml.bak-cable-20260915-234837`, `.bak-cable2-*`, `.bak-cable3-*`; локально — `~/tmp-t610/bak-cable-20260915-234837/automations.yaml`. - **Бэкапы перед правками 2026-09-15 (поздний вечер):** `/config/automations.yaml.bak-preids-20260915-223427`, `/config/automations.yaml.bak-gard-20260915-225404` (перед переносом датчика в Гардеробную); рабочая копия — `~/tmp-t610/autfix-20260915-223427/automations.yaml` (плюс `.pre-bat` — до добавления батарейных). - **Удалены 4 «призрака»** (записи в реестре без тела): `svetlo_vykl_osveshchenie_lestnitsy`, `temno_vkl_podsvetku_lestnitsy`, `datchik_osveshchennosti_lestnitsa_batareia`, `light_switch_bed_batareia`. Тела не было (`config/automation/config/` → 404) — лестничные сценарии **пересозданы заново** с теми же id. - **Локальная копия:** `~/tmp-t610/automations/automations.yaml`; после пересборки — `~/tmp-t610/automations-new.yaml`, `~/tmp-t610/automations-fixed.yaml`. @@ -71,6 +74,7 @@ REST `GET/POST /api/config/automation/config/` использует поля | `1771997918348` | **Выкл. ночной свет душевая** | нет присутствия / светло → off | | `1773451257968` | Протечка котельная | `moist` → `notify.notify` | | `8800000000000`…`8800000000011` | **Батарея: 12 шт.** | см. §6 | +| `heating_cable_ctl_0001` | **Греющий кабель: управление** | `time_pattern /15` + `numeric_state ZONT below −8` + отвал датчика → `choose` 5 веток на `switch.heating_cable_plug`. См. §7 | > 🔄 **Переименовано 2026-09-15:** ссылки на `light.night_light_shower_2` → `light.dushevaia_night_light` (id `1771997851260`, `1771997918348`). > ⛔ **Удалены из карты:** `1773451323415` «Датчик протечки котельная батарея» и `1773459663218` «Zigbee T sensor батарея» — заменены 12 единообразными (§6). Тела удалены, осиротевшие записи реестра вычищены. @@ -237,6 +241,59 @@ curl -s -X POST -H @/tmp/h1 -H "Content-Type: application/json" \ --- +## 7. Греющий кабель: управление (2026-09-16) + +**Автоматизация:** `automation.greiushchii_kabel_upravlenie` · id `heating_cable_ctl_0001` · `mode: single` · **одна** на все случаи (0 helper'ов). + +**Управляет:** `switch.heating_cable_plug` (NEO NAS-WR01B, `a4c138eb6fbe9d19`, котельная) — розетка греющего кабеля ввода воды. Кабель саморегулирующийся. + +**Порог −8 °C** — по расчёту промерзания бетонной подушки 30 см (Новосибирск, суглинок, труба на 4 м). Выдержка 12 ч = тепловая инерция бетона. Прогноз привлекается потому, что ZONT — одна точка и может отвалиться. + +### Ветки логики + +| Ветка `choose` | Условие | Действие | +|---|---|---| +| 1 | `eff ≤ −20` | `switch.turn_on` + persistent + push (без выдержки) | +| 2 | `not zont_ok` | `switch.turn_on` + push (fail-safe) | +| 3 | `eff ≤ −8` + розетка `off` **12 ч** | `switch.turn_on` + persistent + push | +| 4 | `eff ≥ −3` + розетка `on` | `switch.turn_off` + persistent | +| 5 | розетка `on` + `power < 5 W` 10 мин | push «нет потребления» | + +Триггеры: `time_pattern /15` + `numeric_state ZONT below −8` + `state ZONT → unknown/unavailable 30 мин`. +где `eff` = ZONT-улица, если датчик жив, иначе прогноз-мин на 24 ч. + +**Конструкция — прогноз как ДЕЙСТВИЕ, не как шаблон:** +```yaml +actions: + - action: weather.get_forecasts # сервис во МНОЖЕСТВЕННОМ числе + target: {entity_id: weather.forecast_laki_dom} + data: {type: hourly} + response_variable: wx + - variables: # ПОСЛЕ вызова — forecast уже есть + zont_ok: "{{ states('sensor.h2000_pro_temperatura_ulitsa') not in ['unknown','unavailable','none',''] }}" + 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 веток +``` + +> 🔴 **Питфоллы этой автоматизации (все три поймал проверкой, без неё ушли бы в прод):** +> 1. **`weather.get_forecasts` — ТОЛЬКО как `action:` + `response_variable`.** В Jinja-шаблоне → `'weather' is undefined`; атрибута `forecast` у сущности нет. Имя — **множественное число**; `weather.get_forecast` (ед. ч.) не существует. +> 2. **`variables:` вычисляются ДО действий.** `fc_min` из `response_variable` можно объявить **только внутри `actions:`, после** вызова сервиса. +> 3. **Fail-safe нельзя строить на `min([99, fc_min])`** — `min([99, 11.1])` = 11.1, условие не сработает никогда. Нужен отдельный флаг `zont_ok` по строковому состоянию. +> +> ⚠️ **Выдержка 12 ч** реализована через `for: '12:00:00'` на `switch.heating_cable_plug` (состояние), НЕ на шаблон — `for:` нельзя вешать на вычисляемое значение. +> ⚠️ **WS `render_template` возвращает `null`** даже для `{{ 2 + 2 }}` — шаблоны проверять только через REST `POST /api/template`. +> ⚠️ **`automation.trigger` через WS не обновляет `last_triggered`** — прогон подтверждать иначе (значения в `variables`, лог HA). + +📄 **План: [[family/plans/t610-heating-cable-automation]]** +🧰 **Инструменты:** `~/tmp-t610/ha_ws.py forecast `, `verify_cable.py`, `rest_tpl.sh`, `verify_calc.sh`. + +### ⚠️ Не проверено физически + +Розетка ни разу не включалась — `off`, `0 W / 0 kWh`, `voltage 223 V`. Это **норма** для выключенной розетки, не поломка. Что кабель реально греет — не подтверждено: нужен ручной прогон `switch.heating_cable_plug` на 10 мин и проверка `sensor.heating_cable_plug_power > 0`. + +--- + ## Связанные - [[family/how-to/home-automation]] — единый справочник: топология, железо, Zigbee, Modbus, команды, сценарии, питфоллы diff --git a/family/how-to/home-automation.md b/family/how-to/home-automation.md index e137b31d..10712bf9 100644 --- a/family/how-to/home-automation.md +++ b/family/how-to/home-automation.md @@ -2,7 +2,7 @@ title: "🏠 Домашняя автоматизация" aliases: [Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset] tags: [family, how-to, smarthome] -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]]) +updated: 2026-09-16 (греющий кабель ввода воды автоматизирован — `automation.greiushchii_kabel_upravlenie`, пороги −8/−3 °C / 12 ч, прогноз через `action: weather.get_forecasts`; автоматизаций 25. §2. H2000_PRO: единицы °F→°C через `options_domain: sensor.private`; питфолл доступа к API с Mac — только через SSH. Справочник кабеля: [[family/tech/heating-cable-water-inlet]]) --- # 🏠 Домашняя автоматизация @@ -110,7 +110,7 @@ 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. > -> 🔴 **Прогноз ВНУТРИ автоматизации — только как ДЕЙСТВИЕ:** `action: weather.get_forecasts` (мн. число) + `response_variable`. В Jinja-шаблоне вызов даёт `'weather' is undefined`, атрибута `forecast` у сущности нет. Внутри `actions:` объявлять `variables:` ПОСЛЕ вызова — они вычисляются до действий. Helper'ы не нужны. Детали: [[family/tech/heating-cable-water-inlet]] §8.1. +> 🔴 **Прогноз ВНУТРИ автоматизации — только как ДЕЙСТВИЕ:** `action: weather.get_forecasts` (мн. число) + `response_variable`. В Jinja-шаблоне вызов даёт `'weather' is undefined`, атрибута `forecast` у сущности нет. Внутри `actions:` объявлять `variables:` ПОСЛЕ вызова — они вычисляются до действий. Helper'ы не нужны. Детали: [[family/how-to/ha-automations]] §7. **Зоны:** `living_room` Гостиная · `kitchen` Кухня · `bedroom` Спальня · `detskaia` Детская · `kabinet` Кабинет · `vannaia` Ванная · `dushevaia` Душевая · `tualet` Туалет · `severnaia` Серая · `kotelnaia` Котельная · `lestnitsa` Лестница. @@ -839,8 +839,9 @@ ssh root@192.168.2.176 'ha apps logs local_modbus-bridge | grep -E "Raw RTU|→ ## 8. Текущее состояние -> 🕐 Обновлено **2026-09-15, ночь-22** — баг CO2 закрыт (§9), Zigbee переехал на ZHA, камера на `local_ustreamer`. +> 🕐 Обновлено **2026-09-16** — автоматизация греющего кабеля ввода воды загружена и работает; баг CO2 закрыт (§9), Zigbee переехал на ZHA, камера на `local_ustreamer`. +- ✅ **ГРЕЮЩИЙ КАБЕЛЬ ВВОДА ВОДЫ АВТОМАТИЗИРОВАН (2026-09-16):** `automation.greiushchii_kabel_upravlenie` (id `heating_cable_ctl_0001`), `on`. Пороги по `eff = min(ZONT-улица, прогноз met.no 24ч)`: ВКЛ `≤ −8 °C` (выдержка 12 ч), ВЫКЛ `≥ −3 °C` (12 ч), аварийный `≤ −20 °C` (без выдержки), fail-safe при отвале датчика, алерт обрыва при `power < 5 W`. Прогноз — `action: weather.get_forecasts` + `response_variable` (в Jinja недоступен). Обоснование порога: `d_fn = 0,23·√63,9 = 1,84 м` (суглинок), труба на 4 м не замерзает — опасна только бетонная подушка 30 см. Полный расчёт: [[family/tech/heating-cable-water-inlet]]. **Автоматизаций стало 25** (24 `on`). ⚠️ Физически не проверено: розетка ни разу не включалась (`off`, `0 W`). - ✅ **MODBUS CO2 ПОЧИНЕН (2026-09-15, ночь-22):** в `data/config.template.tmpl` убраны мусорные `correction_offset: -925` (kids_co2) и `-495` (bedroom_co2); `rebuild` + `start` аддона. Было **−76 / 94**, стало **848 / 599 ppm**. Все три slave (dining/kids/bedroom) публикуют каждые ~10 с, значения правдоподобны. Бэкап `.bak-co2fix-20260915-221932`. Детали — §9. - ✅ **Сводки `sensor.*_summary` ИСПРАВНЫ** — `dining 24° 519ppm`, `kids 24° 849ppm`, `bedroom 25° 599ppm`, `dining_air 25tvoc 6pm`. Правка `configuration.yaml` **не вносилась** (ложная тревога). ⚠️ Прежняя запись про `TemplateError: round got invalid input 'unknown'` на `sensor.bedroom_summary` — при живых данных не воспроизводится (ошибка была из-за `unavailable` до фикса). diff --git a/family/plans/heating-cable-automation.md b/family/plans/heating-cable-automation.md deleted file mode 100644 index 1c5d42b8..00000000 --- a/family/plans/heating-cable-automation.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: "План: автоматизация греющего кабеля ввода воды" -type: plan -namespace: family -status: 🟡 Ожидает решения Alex (выдержка 6 ч или 24 ч) → затем выполнение -created: '2026-09-16' -updated: '2026-09-16' -tags: - - family - - plan - - t610 - - smarthome - - heating -related: - - '[[family/tech/heating-cable-water-inlet]]' - - '[[family/how-to/home-automation]]' - - '[[family/how-to/ha-automations]]' ---- - -# План: автоматизация греющего кабеля ввода воды - -> **Расчёт и обоснование порогов — в [[family/tech/heating-cable-water-inlet]].** Здесь — что именно делать руками. - ---- - -## 1. Задача - -Обогрев ввода воды в дом. Труба ПНД сквозь бетонную подушку 30 см → в суглинок на 4 м. Регион — Новосибирск (Лаки Парк). - -**Ключевые выводы расчёта:** -- Грунт на 4 м **не замерзает никогда** (+2,5…+3,5 °C круглый год). -- Опасна **только бетонная подушка 30 см** — труба в ней доходит до 0 °C при воздухе **−8 °C**. -- Кабель **саморегулирующийся** → перегрев невозможен, окно выдержки задаёт инерция бетона (~сутки). - ---- - -## 2. 🔴 Единственный блокер - -**Выдержка: 6 ч или 24 ч.** Решение за Alex. - -| Вариант | Плюс | Минус | -|---|---|---| -| 24 ч | отсекает ночные заморозки | при ударе −15 °C за ночь включится через сутки | -| 6 ч | ловит резкое похолодание в тот же день | может дёрнуться на ночном заморозке | - -**Рекомендация ассистента: 6 ч.** - ---- - -## 3. Спецификация автоматизации - -**Имя:** `heating_cable_water_inlet` -**Файл:** `/config/automations.yaml` на t610 (бэкап обязателен перед правкой) - -### 3.1. Расчётная температура - -``` -t_расч = min( sensor.h2000_pro_temperatura_ulitsa , - min( прогноз weather.forecast_laki_dom на 24 ч вперёд ) ) -``` - -Берём **более холодный** из двух источников — fail-safe в сторону защиты от замерзания. - -### 3.2. Триггеры и действия - -| # | Триггер | Условие | Действие | -|---|---|---|---| -| 1 | `t_расч` ≤ −8 °C | `for: <6ч\|24ч>` | `switch.turn_on` `switch.heating_cable_plug` | -| 2 | `t_расч` ≥ −3 °C | `for: <6ч\|24ч>` | `switch.turn_off` `switch.heating_cable_plug` | -| 3 | `t_расч` ≤ −20 °C | без `for` | `switch.turn_on` (безусловно) | -| 4 | оба источника `unavailable` | `for: 01:00:00` | `switch.turn_on` + push | -| 5 | после ВКЛ + 10 мин | `sensor.heating_cable_plug_power < 5` | push «кабель не греет» | - -### 3.3. Сущности - -| Роль | Сущность | -|---|---| -| Датчик (ZONT) | `sensor.h2000_pro_temperatura_ulitsa` | -| Прогноз | `weather.forecast_laki_dom` (met.no) | -| Исполнитель | `switch.heating_cable_plug` (NEO NAS-WR01B, `a4c138eb6fbe9d19`, зона `kotelnaia`) | -| Контроль мощности | `sensor.heating_cable_plug_power` | - ---- - -## 4. Шаги выполнения - -1. **Бэкап** `/config/automations.yaml` → `automations.yaml.bak-heatcable-`. -2. Забрать прогноз в шаблон-сенсор: - ```yaml - template: - - sensor: - - name: "t_rasch_heating_cable" - unit_of_measurement: "°C" - state: > - {% set fc = state_attr('weather.forecast_laki_dom','forecast') %} - ... - ``` - > ⚠️ **Прогноз в этих шаблонах может быть недоступен** — атрибут `forecast` в HA 2026.9.2 **не отдаётся в `state_attr`**, только через WS `weather/subscribe_forecast` (§8 [[family/tech/heating-cable-water-inlet]]). **Проверить фактом ДО написания шаблона.** Если недоступен — вариант: брать уличную температуру напрямую из met.no через RESTful-сенсор (отдельная интеграция), либо использовать `weather.get_forecasts` (проверить существование в 2026.9.2). -3. Добавить 5 триггеров из §3.2 в `automations.yaml` (через `patch`, не `sed`). -4. Перезагрузить автоматизации: `POST /api/services/automation/reload`. -5. Проверить: `automation.heating_cable_water_inlet` = `on`, 0 `unavailable`, ссылки на сущности живые. -6. Обновить [[family/how-to/ha-automations]] — карта автоматизаций (стало 25). -7. Обновить статус [[family/tech/heating-cable-water-inlet]] → 🟢. - ---- - -## 5. Питфоллы (собрано из опыта сессии) - -| Питфолл | Обход | -|---|---| -| Прогноз недоступен через REST/`call_service` | Только WS `weather/subscribe_forecast` (§8) | -| WS-ответ прогноза — два сообщения | Второй `recv()` после `result` | -| `http://192.168.2.176:8123` с Mac → `000` | SSH-однострочник или `wss://mallexxx.duckdns.org` | -| Токен `/tmp/.hatok` лежит на **Mac** | Передавать в SSH-команду из Mac | -| Правка `automations.yaml` без reload не действует | `POST /api/services/automation/reload` | -| `sensor.heating_cable_plug_power = 0 Вт` при `off` | **Норма**, не поломка — проверить можно только после включения | - ---- - -## 6. Следующие шаги (не блокеры) - -- [ ] Датчик температуры **на трубе** в бетоне — точнее модели §4. -- [ ] Решить, нужен ли ZONT отдельный виртуальный slave под греющий кабель. -- [ ] После первого включения — снять реальную мощность (`sensor.heating_cable_plug_power`) и записать в доку: сколько потребляет кабель 6 м. diff --git a/family/plans/t610-heating-cable-automation.md b/family/plans/t610-heating-cable-automation.md index a5815444..b6294bcf 100644 --- a/family/plans/t610-heating-cable-automation.md +++ b/family/plans/t610-heating-cable-automation.md @@ -1,9 +1,9 @@ # План: автоматизация греющего кабеля ввода воды (t610) -> Статус: **конструкция согласована 2026-09-16** — выдержка 12 ч, порог −8 °C, -> **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]] +> Статус: **✅ ВЫПОЛНЕНО 2026-09-16** — автоматизация `automation.greiushchii_kabel_upravlenie` +> загружена, `on`, ошибок нет. Реализован **вариант B** (выдержка через `for: 12:00:00` +> на `switch.heating_cable_plug`). Источник: [[family/how-to/ha-automations]] §7 +> Предыстория: [[family/how-to/home-automation]] · [[family/tech/zigbee-t610-z2m-i-zha]] ## Задача diff --git a/family/tech/ha-registry-operations.md b/family/tech/ha-registry-operations.md index 983c83cb..b0d85944 100644 --- a/family/tech/ha-registry-operations.md +++ b/family/tech/ha-registry-operations.md @@ -194,6 +194,8 @@ ssh root@192.168.2.176 'bash /tmp/ghost_purge.sh /config/.storage/core.entity_re | 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` | | 14 | `write_file` режет строку `Authorization: Bearer *** | Собирать заголовок из переменных: `P1=Authorization; P2=Bearer; AUTH=*** ${P2} ${TOK}"` | +| 15 | 🔴 **Fail-safe на `min([99, fc_min])` не работает:** `min([99, 11.1])` = 11.1, а не 99 → проверка отвала датчика через `float(99)` + `min` **не срабатывает никогда** | Отдельный флаг по строковому состоянию: `zont_ok: "{{ states('sensor.x') not in ['unknown','unavailable','none',''] }}"`, затем `eff: "{{ zont if zont_ok else fc_min }}"` | +| 16 | `automation.trigger` через WS **не обновляет `last_triggered`** | Прогон подтверждать иначе: значения в `variables`, `logbook.log`, лог HA Core | --- @@ -280,5 +282,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/how-to/ha-automations]] §7 — греющий кабель ввода водыс §8 (прогноз для греющего кабеля) - [[family/plans/t610-heating-cable-automation]] — план автоматизации на базе §8.1 diff --git a/family/tech/heating-cable-water-inlet.md b/family/tech/heating-cable-water-inlet.md index 93d8b10a..369cc9a1 100644 --- a/family/tech/heating-cable-water-inlet.md +++ b/family/tech/heating-cable-water-inlet.md @@ -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,3–1,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,3–1,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 ` — добавлена команда `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`.