--- title: "🍳 Вытяжка кухни — смена домена light → fan (`fan.kitchen_hood`, 3 скорости)" aliases: - kitchen hood - kitchen_hood - вытяжка домен - вытяжка категория свет - TS0003 fan - hood light to fan - fan.kitchen_hood - kitchen-hood-domain-conversion - kitchen-hood-fan-template created: '2026-09-16' updated: 2026-09-16 note: "✅ ЗАКРЫТО полностью: fan.kitchen_hood создан, зона назначена, свет и диагностика скрыты, ссылка в карте этажей home_plan переведена с мёртвого fan.fan_3 на fan.kitchen_hood" type: tech namespace: family status: "🟢 РАБОТАЕТ. fan.kitchen_hood (3 скорости, speed_count: 3) поверх light.kitchen_hood_light[,_2,_3]. Три света + 13 сущностей диагностики скрыты. План этажей починен. Проверено фактом 2026-09-16. ⚠️ Порядок скоростей ждёт физической проверки — §10." tags: - family - tech - smarthome - home-assistant - t610 - haos - zigbee - zha - template related: - '[[family/how-to/home-automation]]' - '[[family/how-to/ha-automations]]' - '[[family/tech/zigbee-t610-z2m-i-zha]]' - '[[family/tech/ha-registry-operations]]' - '[[family/documents/home-automation-wishlist]]' --- # 🍳 Вытяжка кухни — смена домена (light → fan) > **Задача Alex (2026-09-16):** «можно всё-таки кухонную вытяжку перевести из категории свет в другую?» → ответ: прямого способа нет; сделан `fan.kitchen_hood` Template-хелпером поверх трёх реле, свет спрятан. > > **Единственная дока по вытяжке.** Раньше было две (`kitchen-hood-domain-conversion` — исследование, `kitchen-hood-fan-template` — реализация) — сведены сюда 2026-09-16. Оба имени оставлены в `aliases`. --- ## 1. Ответ на исходный вопрос: «никак нельзя» **Прямого способа сменить домен `light.` → `switch.`/`fan.` у существующей сущности в HA НЕТ.** Проверено по всем четырём путям: | Путь | Результат | |---|---| | **UI «Показать как»** (`device_class`) | ❌ Домена не меняет. Для `light` вообще не применимо | | **Реестр сущностей** (`config/entity_registry/update` + `new_entity_id`) | ❌ Домен менять нельзя, только имя внутри домена. ⚠️ Питфолл 4 в [[family/tech/zigbee-t610-z2m-i-zha]]: «Переименование `light.` → `switch.` запрещено HA» | | **`switch_as_x`** (офиц. хелпер «Change device type of a switch») | ❌ **Источник — только `switch`.** Конвертирует в Light/Cover/Fan/Lock/Siren/Valve, но `light` на вход НЕ принимает. Для ZHA-вытяжки бесполезен | | **Кастомный quirk в `zhaquirks`** | ⚠️ Технически возможно (подменить Light-cluster на Switch), но ломается при каждом обновлении HA + переименование сущностей рвёт все ссылки. Отвергнуто | | **`homeassistant: customize:`** | ❌ Меняет только атрибуты (device_class/icon), **не домен**. `light.` останется `light.` | > 📄 `switch_as_x` — https://www.home-assistant.io/integrations/switch_as_x/ > Ключевая цитата доки: «lets you convert any Home Assistant **switch** into a Home Assistant Light, Cover, Fan, Lock, Siren, or Valve». **Работает только обход:** Template-хелпер создаёт **новую** сущность рядом, оригинальные прячутся. > ⚠️ **Почему Template работает там, где `switch_as_x` пасует:** у Template-сущности блок `action:` может звать **любой** сервис (`light.turn_on`), тогда как `switch_as_x` жёстко ограничен источником-`switch`. Это и есть обход ограничения домена. ### Варианты, которые рассматривались | # | Что | Итог | |---|---|---| | **A** | Template `fan` поверх **одного** `light_2` | промежуточный; отвергнут — не даёт 3 скоростей | | **B** | Template `switch` (без `percentage`) | если скорость не нужна, нужен просто «не свет» | | **C** | Три `fan`/`switch` + автоматизация взаимоблокировки / `input_select` | ⭐ **не понадобился** — `set_percentage` с `choose` дал то же самое в одной сущности | --- ## 2. Железо и что отдаёт ZHA **Устройство:** `kitchen_hood` · IEEE `a4:c1:38:07:b6:4c:7f:d4` · `_TZ3000_odzoiovu` · **TS0003** (3-gang реле) · Router · зона `kitchen` · device_id `200ea4fb25daaa907279045e47a330b5` **ZHA отдаёт реле как `light`, не `switch`:** | Сущность | Роль | Состояние до работ | |---|---|---| | `light.kitchen_hood_light` | скорость 1 (33 %) | `on` | | `light.kitchen_hood_light_2` | скорость 2 (66 %) | `off` | | `light.kitchen_hood_light_3` | скорость 3 (100 %) | `off` | Все три: `supported_color_modes: ["onoff"]`, `supported_features: 8`, платформа `zha`. > 🔑 **`supported_features: 8` + `supported_color_modes: ["onoff"]` = чистое реле без яркости.** Именно поэтому HA-логика «это лампа» здесь ложная, а переклассификация в `fan` осмысленна. > 🔑 **Ключевое для понимания:** TS0003 — это **три независимых реле**, а «3 скорости вытяжки» на железе = три провода, из которых активен ровно один. Поэтому HA изначально показала их как три света, а не как одну вентиляционную сущность. Один `fan` с процентами склеивает их логически. **Прочие сущности того же устройства** (позже скрыты, см. §8): `select.kitchen_hood_indicator_mode` (`LightWhenOn`), `select.kitchen_hood_power_outage_memory` (`Off`), `sensor.kitchen_hood_power` / `_voltage` / `_current` / `_energy` (все `0.0`), `button.kitchen_hood_identify`, `update.kitchen_hood_firmware`, `sensor.kitchen_hood_lqi` / `_rssi`. > 🔴 **`sensor.kitchen_hood_lqi` / `_rssi` → HTTP 404 через `/api/states`.** Это **норма**: `disabled_by: integration` — сущности в реестре есть, в runtime их нет. **Не считать поломкой.** --- ## 3. Что сделано — шаг 1: Template-фан ### 3.1. Бэкап ``` /config/configuration.yaml.bak-fanhood-20260916-081926 (30108 байт) ``` ### 3.2. Новый блок `template:` в `/config/configuration.yaml` Добавлен **16-м** блоком `template:` (после `fan_3`), перед `- cover:`. `speed_count: 3` → шаг 33 % в UI. ```yaml - fan: - name: Kitchen hood unique_id: kitchen_hood_fan default_entity_id: fan.kitchen_hood speed_count: 3 state: > {{ is_state('light.kitchen_hood_light','on') or is_state('light.kitchen_hood_light_2','on') or is_state('light.kitchen_hood_light_3','on') }} percentage: > {% if is_state('light.kitchen_hood_light_3','on') %}100 {% elif is_state('light.kitchen_hood_light_2','on') %}66 {% elif is_state('light.kitchen_hood_light','on') %}33 {% else %}0 {% endif %} turn_on: - action: light.turn_on target: entity_id: light.kitchen_hood_light turn_off: - action: light.turn_off target: entity_id: - light.kitchen_hood_light - light.kitchen_hood_light_2 - light.kitchen_hood_light_3 set_percentage: - action: light.turn_off target: entity_id: - light.kitchen_hood_light - light.kitchen_hood_light_2 - light.kitchen_hood_light_3 - choose: - conditions: - condition: template value_template: "{{ percentage | int(0) > 0 and percentage | int(0) <= 33 }}" sequence: - action: light.turn_on target: entity_id: light.kitchen_hood_light - conditions: - condition: template value_template: "{{ percentage | int(0) > 33 and percentage | int(0) <= 66 }}" sequence: - action: light.turn_on target: entity_id: light.kitchen_hood_light_2 - conditions: - condition: template value_template: "{{ percentage | int(0) > 66 and percentage | int(0) <= 100 }}" sequence: - action: light.turn_on target: entity_id: light.kitchen_hood_light_3 ``` **Логика:** `set_percentage` сначала гасит **все три** реле, затем зажигает одно нужное → **взаимоисключение гарантировано**, состояние «две скорости одновременно» невозможно by design. > 🔴 **ИСПРАВЛЕНО 2026-09-16 (было ошибочно в первой версии доки):** ранняя версия утверждала, что «Template-fan с `percentage` не даст настоящую скорость — он включит одно реле». **Факт опроверг:** один Template-fan с `set_percentage` + `choose` **даёт полноценные 3 скорости** — 33/66/100 % выбирают нужное реле, `percentage` читается обратно из состояния. Взаимоблокировку обеспечивает `set_percentage`, отдельная автоматизация и `input_select` **не нужны**. Проверено живым прогоном — §4. **Порядок применения:** правка YAML → локальный парс → `scp` на t610 → `check_config` → **`homeassistant.restart`** (не reload!) → `RUNNING`. ### 3.3. Скрытие света Три сущности скрыты через WS `config/entity_registry/update` с `hidden_by: "user"`. Скрипт: `~/tmp-t610/hood_hide.py` (возврат — тот же скрипт с `--unhide`). --- ## 4. ✅ Проверка на живом железе | Шаг | `fan.kitchen_hood` | light_1 | light_2 | light_3 | |---|---|---|---|---| | baseline | `off / 0` | off | off | off | | `set_percentage 33` | `on / 33` | **on** | off | off | | `set_percentage 66` | `on / 66` | off | **on** | off | | `set_percentage 100` | `on / 100` | off | off | **on** | | `turn_off` | `off / 0` | off | off | off | `fan.kitchen_hood`: `supported_features: 49` = TURN_ON | TURN_OFF | SET_SPEED ✅ > ℹ️ `speed_count` **не отдаётся** как атрибут состояния — HA его не публикует. Шаги ползунка считаются из `percentage_step`. Это норма, не дефект. --- ## 5. 🔴 Шаг 2: доводка UI — «вижу показатели kitchen hood и нет нового вентилятора» **Симптом Alex:** «Я в кухне до сих пор вижу показатели kitchen hood и нет нового вентилятора». **Две причины, обе найдены фактом:** | # | Причина | Факт | |---|---|---| | 1 | **`fan.kitchen_hood` создан без зоны** — Template-сущность из YAML не привязана к устройству → `area_id: null`, на кухне не видна | WS-реестр: `area=null`. У `fan.fan_3` зона `kitchen` **была** → он и торчал на кухне вместо нового | | 2 | **Диагностика устройства не скрыта** — «показатели kitchen hood» = 4 сенсора + 2 select + update + button, все `hidden_by=None` | Найдено сканом `config/entity_registry/list` | **Фикс — скрипт `~/tmp-t610/hood_cleanup.py`** (обратимо флагом `--unhide`): 1. `fan.kitchen_hood` → `area_id: kitchen` ✅ 2. Скрыто `hidden_by: user` — **13 сущностей**: - `fan.fan_3` (мёртвый template-фан «Вытяжка Кухня») - `switch.fan_3_low` / `_medium` / `_high` + `script.set_fan_3_speed` — подтверждены `unavailable` (slave 10 / AT2 офлайн) - `sensor.kitchen_hood_energy` / `_power` / `_voltage` / `_current` - `select.kitchen_hood_indicator_mode` / `_power_outage_memory` - `update.kitchen_hood_firmware` - `button.kitchen_hood_identify` **Проверено чтением обратно:** все 13 → `hidden_by=user`; `fan.kitchen_hood` → `area=kitchen`, `hidden_by=None`. --- ## 6. 🔴 Шаг 3: настоящая причина «он не открыт» — карта этажей **Симптом Alex:** «Нихуя он не открыт!» — на кухне в UI по-прежнему старая вытяжка, новый `fan.kitchen_hood` отсутствует. **Причина — дашборд `home_plan` ссылался руками на мёртвую сущность.** Дашборд `home_plan` (storage-mode, `/config/.storage/lovelace.home_plan`) содержит `picture-elements` с иконкой: ```json { "type": "state-icon", "entity": "fan.fan_3", "tap_action": {"action": "more-info"}, "style": {"top": "18.0%", "left": "86.3%"} } ``` `fan.fan_3` = мёртвый template-фан (источник `switch.fan_3_*` закомментирован, slave 10 офлайн). Иконка на кухне вела на него. **Диагностика — как найти мёртвую ссылку:** ```bash # все entity, на которые ссылается план jq -r '.. | objects | select(.entity? != null) | .entity' /config/.storage/lovelace.home_plan | sort -u # что из них реально живо — сверить со /api/states ``` > 🔴 **`hidden_by: user` НЕ влияет на дашборды со storage-mode.** Ссылки в `.storage/lovelace.*` вписаны руками — скрытие сущности их не трогает. Тот же класс проблемы, что питфолл «план этажей ссылался на снесённого призрака `light.smart_light_stairs_l1`» ([[family/tech/zigbee-t610-z2m-i-zha]] §13.3). > 🔴 **Второе:** `hidden_by` не влияет и на `area_entities()` в шаблонах. `area_entities("kitchen")` продолжает отдавать скрытые сущности — это два независимых механизма. Если сущность нужна «невидимой» реально, её надо `disabled_by`, либо убрать ссылку из дашборда. **Фикс — скрипт `~/tmp-t610/fix_plan_hood.py`** (dry-run по умолчанию, `--apply` для записи): 1. Рекурсивный обход JSON плана → замена `fan.fan_3` → `fan.kitchen_hood` 2. `assert` что `fan.fan_3` не осталось в выводе 3. Бэкап remote → `scp` на t610 **Результат:** заменено **1** вхождение (`.data.config.views[0].sections[0].cards[0].elements[6]`). Бэкап `lovelace.home_plan.bak-hoodfan-20260916-074008`. **Проверено фактом на t610:** `fan.fan_3` в плане = **0**, `fan.kitchen_hood` = есть, `jq -e .` → JSON валиден. > ⚠️ Дашборд читает `.storage` при загрузке страницы → нужен **hard-refresh (Cmd+Shift+R)**, обычный F5 может отдать кэш. ### 6.1. Итоговая цепочка причин (три штуки, каждая выглядела как «не работает») | # | Что было | Как выглядело | Фикс | |---|---|---|---| | 1 | `fan.kitchen_hood` без зоны (`area_id: null`) | «на кухне нет нового вентилятора» | WS `area_id: kitchen` | | 2 | диагностика реле не скрыта | «вижу показатели kitchen hood» | 8 сущностей → `hidden_by: user` | | 3 | **план этажей ссылался на `fan.fan_3`** | «старая вытяжка вместо новой» | `fix_plan_hood.py --apply` | > 🔑 **ГЛАВНЫЙ УРОК:** «создал сущность» ≠ «пользователь её видит». Проверять **четыре** вещи: > 1. `/api/states/` отвечает > 2. `area_id` в реестре не `null` (Template-сущности из YAML зону **не получают** — нет `device_id` → назначать вручную WS `config/entity_registry/update` с `area_id`) > 3. диагностика устройства скрыта (`hidden_by: user`) > 4. **дашборды/план этажей не ссылаются на мёртвые сущности** (`jq` по `.storage/lovelace.*`) --- ## 7. Питфоллы | # | Питфолл | Обход | |---|---|---| | 1 | **`switch_as_x` не принимает `light`** | Источник только `switch`. Для ZHA-light бесполезен — нужен Template | | 2 | **Домен сущности сменить нельзя** | Только Template-хелпер рядом + скрыть оригинал | | 3 | **`!include` ломает `yaml.safe_load`** при локальной проверке | Заглушка: `L.add_multi_constructor('!', ...)` — иначе проверка конфига локально невозможна | | 4 | 🔴 **`check_config` через сервис отдаёт `[]`** | Это **не** ошибка — сервис не возвращает тело. Проверять `GET /api/config` → `.state` или `/api/template` | | 5 | **`_1`/`_2`/`_3` ≠ порядок скоростей автоматически** | ZHA нумерует по endpoint'ам, не по физической скорости. ⚠️ Требует физической проверки — §10 | | 6 | **Template `turn_on` без аргумента** | `fan.turn_on` без `percentage` → скорость 1 (33 %). Задано явно | | 7 | 🔴 **Правка `configuration.yaml` требует `restart` HA Core** | `automation reload` здесь **не** поможет — новый template-блок не подхватится | | 8 | 🔴 **REST `POST` без `-H "Content-Type: application/json"` → пустой ответ** | Всегда ставить заголовок | | 9 | 🔴 **Заголовок авторизации рвётся маскировщиком Hermes** в скриптах | Собирать по частям либо Python + `urllib` (пример — `hood_scan.py`, `hood_hide.py`, `hood_cleanup.py`) | | 10 | **`sensor.kitchen_hood_lqi` / `_rssi` → 404 в `/api/states`** | `disabled_by: integration` — норма, не поломка | | 11 | 🔴 **Template-сущность из YAML не получает `area_id`** → «создал, а в UI нет» | Назначать зону вручную WS `config/entity_registry/update` | | 12 | 🔴 **`hidden_by: user` не влияет на дашборды и `area_entities()`** | Правки кэширует UI → hard-refresh; ссылки в `.storage/lovelace.*` править руками | | 13 | 🔴 **Правка `.storage/lovelace*` вступает в силу только при загрузке страницы** | Hard-refresh (Cmd+Shift+R), F5 может отдать кэш | --- ## 8. Итоговое состояние кухни (вытяжка) | Видно пользователю | Скрыто (`hidden_by: user`) | |---|---| | `fan.kitchen_hood` (зона `kitchen`) | `fan.fan_3`, `switch.fan_3_low/medium/high`, `script.set_fan_3_speed` | | `light.kitchen_hood_light` / `_2` / `_3` | `sensor.kitchen_hood_energy/power/voltage/current` | | | `select.kitchen_hood_indicator_mode` / `_power_outage_memory` | | | `update.kitchen_hood_firmware`, `button.kitchen_hood_identify` | > `sensor.kitchen_hood_lqi` / `_rssi` — `disabled_by: integration`, не отображаются нигде (норма). **Карта этажей `home_plan`:** иконка на кухне (`elements[6]`, 18 %/86.3 %) переведена на `fan.kitchen_hood`. **`fan.fan_3` не удалён** — только скрыт. Возврат: `hood_cleanup.py --unhide`. --- ## 9. Роадмап вентиляции [[family/documents/home-automation-wishlist]] §2 п.1 ожидает **«Kitchen Hood»** как конечный узел алгоритма вентиляции по CO₂ (Node-RED: `Demand Aggregator → Intake Allocation → Discretization → Damper Outputs → Exhaust Arbitration → Fans → Kitchen Hood`). Ранее узел был мёртв вместе с контуром AT2 — теперь у вытяжки есть **рабочая сущность `fan.kitchen_hood`**, на которую можно вешать автоматику. Ждёт решения по slave 10 (AT2 снят Alex'ом). --- ## 10. ⚠️ ОТКРЫТО — требует проверки Alex 1. 🔴 **Порядок скоростей не подтверждён физически.** Принято как `_1`=33 / `_2`=66 / `_3`=100, но какое **реле** = какая **скорость** — не проверялось. Нужно встать у вытяжки: поставить 33 % и 100 %, убедиться что низкая/высокая. **Если перепутано — правка трёх строк** в `percentage` и `set_percentage`. 2. ⚠️ **`light.kitchen_hood_light` мог быть лампой подсветки, а не скоростью.** До работ он был `on` (горел), после рестарта HA стал `off`. Если это **лампа подсветки вытяжки** — вынести отдельно, фан её не должен гасить. > 📌 **Проверка для будущей сессии (одной командой):** поставить `fan.set_percentage` на 33 и на 100 и сравнить, какое реле зажглось и **что физически слышно**. Маппинг в коде — три строки в `percentage` и три ветки `choose` в `set_percentage`. --- ## 11. Артефакты | Файл | Назначение | |---|---| | `~/tmp-t610/configuration.yaml.current` | рабочая копия конфига (с новым блоком) | | `~/tmp-t610/hood_scan.py` | read-only скан: devices + entities + device_class + area + states | | `~/tmp-t610/hood_hide.py` | скрыть/показать три `light.*` (`--unhide`) | | `~/tmp-t610/hood_cleanup.py` | зона `kitchen` + скрытие 13 сущностей (`--unhide`) | | `~/tmp-t610/fix_plan_hood.py` | правка ссылки в `home_plan` (dry-run / `--apply`) | | `~/tmp-t610/home_plan.json` | локальная копия карты этажей | **Бэкапы на t610:** `configuration.yaml.bak-fanhood-20260916-081926` · `lovelace.home_plan.bak-hoodfan-20260916-074008` --- ## Связанные - [[family/how-to/home-automation]] — топология, t610, Zigbee, команды, питфоллы - [[family/tech/zigbee-t610-z2m-i-zha]] — ZHA, реестры, переименование, питфолл «домен менять нельзя», §13.3 план этажей - [[family/tech/ha-registry-operations]] — реестры HA: переименование, опции, призраки - [[family/how-to/ha-automations]] — автоматизации, справочник - [[family/documents/home-automation-wishlist]] — роадмап автоматизаций (Kitchen Hood как узел CO₂)