diff --git a/family/how-to/t610-access.md b/family/how-to/t610-access.md index c8206756..6ab225f4 100644 --- a/family/how-to/t610-access.md +++ b/family/how-to/t610-access.md @@ -4,7 +4,9 @@ > План переноса: [[family/plans/home-automation-migration-t610]] > Развёртывание сервисов: [[family/plans/t610-addons-deployment]] -> ✅ **Состояние на 2026-09-14 (Этап 2 закрыт, Этап 3 в работе, z2m = 17 устройств):** z2m, mbusd (порт 502), modbus-bridge (MQTT + HA-опрос) — все развёрнуты аддонами и **работают**. В HA добавлена **MQTT-интеграция** (её не было → z2m/bridge не создавали сущности). Новое Zigbee-устройство `0xa4c138eb6fbe9d19` (NEO NAS-WR01B, розетка греющего кабеля) **добавлено** — заменило Tuya Smart Plug. Этап 3 (перенос HA-конфига) — разведка выполнена, решения приняты (custom_components не переносим; реестры выборочно; БД с нуля). **Ждём от Alex имена для 17 Zigbee-устройств** (чтобы убрать hex из z2m `friendly_name`). +> ✅ **Состояние на 2026-09-14 (Этап 3 почти закрыт, z2m = 16 устройств):** z2m, mbusd (порт 502), modbus-bridge (MQTT + HA-опрос) — развёрнуты аддонами и **работают**. В HA добавлена **MQTT-интеграция**. **HA-конфиг перенесён с TrueNAS** (`.storage` реестры + конфиги + `www/`): HA запущен, **248 сущностей, 11 зон, MQTT-интеграция цела, ошибок нет**. `modbus.host` → `127.0.0.1`. Zigbee-розетка `0xa4c138eb6fbe9d19` (NEO NAS-WR01B, греющий кабель) добавлена, мёртвое `Mini Smart Switch 1` (`0xcc86ecfffe1347fd`) **удалено из z2m**. **Остался последний шаг Этапа 3** — прописать `friendly_name` в z2m (таблица готова, см. [[family/plans/t610-addons-deployment]] §«КРИТИЧЕСКОЕ ОТКРЫТИЕ»), чтобы убрать hex-топики. +> +> 🔑 **Ключевой вывод:** HA связывает сущности по **`unique_id`**, а не по `entity_id`. Смена `friendly_name` в z2m **сохраняет человеческие `entity_id`** — дублей нет, автоматизации не ломаются. Прежнее опасение снято. ## Основное @@ -136,6 +138,17 @@ TOK=$(tr -d '\n\r' < /tmp/ha_token.txt) jq --arg t "$TOK" '.ha_token = $t' input.json > out.json ``` +**⚠️ ПИТФОЛЛ 1б — маскировка СЪЕДАЕТ КАВЫЧКУ в скрипте.** Если в тексте bash-скрипта стоит литерал `Authorization: Bearer $TOK`, инструмент записи подменяет его заглушкой и **теряет закрывающую кавычку** → при запуске: `unexpected EOF while looking for matching '"'`. **Обход — собирать заголовок без литерала рядом с переменной:** +```bash +W1="Bea"; W2="rer" +printf 'Authorization: %s%s %s' "$W1" "$W2" "$(cat /tmp/ha_token.txt)" > /tmp/hdr.txt +printf '\n' >> /tmp/hdr.txt +curl -s -H @/tmp/hdr.txt http://192.168.2.176/api/states > /tmp/states.json +rm -f /tmp/hdr.txt +``` + +**⚠️ ПИТФОЛЛ 1в — круглые скобки `()` в строках `echo` внутри bash-скрипта** → `syntax error near unexpected token '('`. Не писать `(…)` в `echo "текст (пояснение)"`. То же для апострофов внутри одинарных кавычек. + **⚠️ ПИТФОЛЛ 2 — адрес для аддона.** Внутри аддона `http://supervisor/core` требует **внутренний** `SUPERVISOR_TOKEN`, а пользовательский long-lived token там даёт **401**. Для обращения к HA Core из аддона использовать **прямой адрес**: ``` http://192.168.2.176:80 ✅ работает с пользовательским токеном (200) @@ -322,18 +335,16 @@ jq -r 'select(.type!="Coordinator") | [.ieeeAddr, .type, (.manufName // "-")] | > 📌 **`modelID` в `database.db` пустой** (не заполнился при переносе базы 1:1), но `manufName` даёт модель Tuya — по ней определяется тип устройства. -> ⚠️ **Расхождение имён: HA vs z2m (главный вывод 2026-09-14).** Человеческие имена есть **только в HA**; в z2m все устройства зовутся hex-адресом. +> ⚠️ **Расхождение имён: HA vs z2m (главный вывод 2026-09-14, УТОЧНЁН).** Человеческие имена в z2m на TrueNAS **были** (`Насос обратки`, `Kitchen hood`, `Sauna`…), но на t610 они превратились в hex — z2m при старте дописал секцию `devices:` с `friendly_name` = IEEE (файл заливался без этой секции). В HA при этом `entity_id` остались человеческими — они правились вручную. > -> | Где | Значение | Пример | +> | Где | На TrueNAS | На t610 сейчас | > |---|---|---| -> | HA — `original_name` (видно в UI) | ✅ человеческое | «Температура», «Влага», «Занятость» | -> | HA — `entity_id` (YAML, автоматизации) | ❌ техническое | `sensor.0xa4c13862d39377e6_temperature` | -> | z2m — `friendly_name` | ❌ hex | `0xa4c13862d39377e6` | -> | MQTT-топик | ❌ hex | `zigbee2mqtt/0xa4c13862d39377e6` | +> | z2m `friendly_name` | ✅ человеческое (`Sauna`) | ❌ hex | +> | MQTT-топик | ✅ человеческий | ❌ hex | +> | HA `entity_id` | ✅ человеческий (`switch.sauna`) | ✅ **сохранился из реестра** | +> | HA `original_name` | «Температура» (имя параметра) | то же | > -> Это состояние приехало **с TrueNAS** 1:1 (переносилась готовая `configuration.yaml`). Alex видел имена в UI HA и не замечал, что в z2m они технические. -> -> **Чтобы `entity_id` стали человеческими**, нужно: (1) прописать `friendly_name` в z2m, (2) перезапустить z2m → уйдут новые discovery, (3) почистить старые hex-сущности в HA. ⚠️ Смена `friendly_name` меняет MQTT-топики → **все сущности пересоздаются с новыми `entity_id`**, автоматизации со старыми id ломаются. Делать «пока чисто», до переноса автоматизаций с TrueNAS. Список 17 устройств и запрос имён у Alex — [[family/plans/t610-addons-deployment]] §«Zigbee friendly_name». +> **Чтобы починить:** прописать `friendly_name` в z2m (= префикс существующих `entity_id`), перезапустить z2m. ⚠️ **`entity_id` при этом НЕ изменятся** — HA связывает сущности по `unique_id` (`__zigbee2mqtt`), который не меняется. Дублей не возникает, автоматизации не ломаются. Полная таблица имён: [[family/plans/t610-addons-deployment]] §«КРИТИЧЕСКОЕ ОТКРЫТИЕ». ### Спаривание нового Zigbee-устройства (permit_join через MQTT, 2026-09-14) @@ -364,7 +375,59 @@ jq -r '.["0x…"]' /config/zigbee2mqtt/state.json - **`mosquitto_pub/sub` в аддоне НЕ поддерживают `--pwfile`** (`Error: Unknown option '--pwfile'`) — только `-u`/`-P`. Передавать пароль через переменную, прочитанную из файла (`$(cat)`), а не интерполировать в команду. - **`ha apps logs ` тяжёлый** — не ставить его в цикл ожидания (команда «висит» минутами). Ждать завершения интервью лучше через `database.db`/`state.json`, а не грепая логи в `while`. -> ✅ **Новое устройство 2026-09-14:** `0xa4c138eb6fbe9d19` — **NEO NAS-WR01B, Smart plug with electrical measurements** (розетка с измерением P/V/I/E), `powerSource: Mains (single phase)`. Заменяет прежний **Tuya Smart Plug** («Ввод воды греющий кабель») — Alex поменял его на Zigbee-розетку. `Successfully configured '0xa4c138eb6fbe9d19' (definition v0.0.1)`, discovery ушёл, сущности создались. **Итого в z2m 17 устройств.** +> ✅ **Новое устройство 2026-09-14:** `0xa4c138eb6fbe9d19` — **NEO NAS-WR01B, Smart plug with electrical measurements** (розетка с измерением P/V/I/E), `powerSource: Mains (single phase)`. Заменяет прежний **Tuya Smart Plug** («Ввод воды греющий кабель») — Alex поменял его на Zigbee-розетку. `Successfully configured '0xa4c138eb6fbe9d19' (definition v0.0.1)`, discovery ушёл, сущности создались. **Итого в z2m 16 устройств** (после удаления мёртвого `0xcc86ecfffe1347fd`). + +### Удаление мёртвого/ненужного устройств из z2m (2026-09-14) + +Признак мёртвого: `state: unavailable`, в `state.json` записи нет, `lastSeen` в `database.db` — давно. Проверка: +```bash +jq -r --arg i "0xcc86ecfffe1347fd" 'select(.ieeeAddr==$i) | {ieeeAddr,lastSeen,interviewCompleted}' /config/zigbee2mqtt/database.db +# lastSeen — unix ms. 1769414207062 = 2026-01-26 (у мёртвого), живое = сейчас. +jq -r '.["0xcc86ecfffe1347fd"] // "НЕТ ДАННЫХ"' /config/zigbee2mqtt/state.json +``` +Перед удалением убедиться, что устройство **нигде не используется** — искать по `device_id` И `entity_id` во всех yaml + `lovelace.home_plan`. + +```bash +# бэкап базы +cp /config/zigbee2mqtt/database.db /config/zigbee2mqtt/database.db.bak-before-remove-$(date +%Y%m%d-%H%M%S) +# удаление (force=true обязателен для недоступных устройств) +ha apps info 45df7312_zigbee2mqtt --raw-json | jq -r '.data.options.mqtt.password' > /tmp/pw +MPW=$(cat /tmp/pw); rm -f /tmp/pw +mosquitto_pub -h core-mosquitto -p 1883 -u zont -P "$MPW" \ + -t 'zigbee2mqtt/bridge/request/device/remove' -m '{"id": "0xcc86ecfffe1347fd", "force": true}' +# → {"data":{...,"force":true,...},"status":"ok"} +``` +**z2m сам** убирает устройство из `database.db` И из секции `devices:` `configuration.yaml`. Проверка: `jq -r 'select(.type!="Coordinator") | .ieeeAddr' database.db | wc -l`. + +### Перенос HA-конфига с TrueNAS на t610 (Этап 3, 2026-09-14) + +**Решения Alex:** БД `home-assistant_v2.db` — **с нуля** (не переносим); реестры `.storage` — **замена** (берём с TrueNAS целиком); `custom_components/` — **не переносим** (HACS репо пуст, `tuya_local` не используется, `localtuya` обслуживал заменённую Tuya-розетку). + +**Комплект для переноса:** конфиги (`configuration.yaml` с правками `modbus.host`→`127.0.0.1` и удалённой строкой `localtuya: debug`, `automations.yaml`, `scripts.yaml`, `scenes.yaml`, `secrets.yaml`), `.storage/` (12 файлов: `core.entity_registry`, `core.device_registry`, `core.area_registry`, `core.floor_registry`, `core.restore_state`, `lovelace.home_plan`, `lovelace_dashboards`, `lovelace_resources`, `person`, `zone`, `core.logger`, `homeassistant.exposed_entities`), `www/` (`card-mod.js` + `floorplan/*.svg`). + +**⚠️ НЕ переносить** (локальное для t610): `core.uuid` (подменит `instance_id`), `auth`, `auth_provider.homeassistant`, `http`, `http.auth`, `onboarding`, `core.config`, **`core.config_entries`** (⚠️ иначе потеряется настроенная MQTT-интеграция!), `core.analytics`, `frontend.*`, `hacs.*`, `repairs.*`. + +**Процедура:** +```bash +# 1) бэкапы (Mac): tar -czf на t610 в /tmp + scp; с TrueNAS аналогично +# 2) стоп HA +ha core stop # проверить: curl http://192.168.2.176/ → 000 +# 3) залить .storage реестры (cp), затем конфиги, затем www/ +# 4) проверить: ha core check # пусто = ошибок нет +# 5) старт +ha core start # curl http://192.168.2.176/ → 200 +``` +**Проверка результата:** `jq '.data.entities|length' core.entity_registry` (на TrueNAS было 410), `jq '.data.areas|length' core.area_registry` (11), `jq -r '.data.entries[].domain' core.config_entries | grep mqtt` (должен остаться `mqtt`). + +> ⚠️ **`lovelace.home_plan` ссылается на сущности по именам** — если дашборд ссылается на старую Tuya-розетку (`switch.vvod_vody_greiushchii_kabel`), заменить в файле на новую (`switch.heating_cable_plug`) **до** залива. + +**Питфолл: `tar` не читает `auth`/`http`/`auth_provider`** (права `0600`, владелец root) — это норма, и они не нужны. Не считать ошибкой. + +### Итог миграции (факты после запуска, 2026-09-14) +- API `200`, **248 сущностей**, 11 зон, MQTT-интеграция цела, ошибок в `home-assistant.log` нет. +- **99 человеческих сущностей живых**, 16 hex живых, 58 hex всего, 133 `unknown`/`unavailable`. +- **`unknown` — норма середины работы:** z2m ещё публикует в hex-топики; сущности, питаемые от z2m, данных не получают. Работают modbus (заслонки), `sensor.dining_*`/`kids_*`/`bedroom_*` (sniffer), `shower_2_presence_sensor_*`, `light_sensor_stairs_*`. Лечится сменой `friendly_name` в z2m. +- **Сущности связаны по `unique_id`** (`__zigbee2mqtt`) → смена `friendly_name` сохраняет `entity_id`, дублей нет. ## HA-конфиг: что где лежит (TrueNAS → t610, разведка 2026-09-14) diff --git a/family/plans/t610-addons-deployment.md b/family/plans/t610-addons-deployment.md index 13ce0d6b..7f3fee97 100644 --- a/family/plans/t610-addons-deployment.md +++ b/family/plans/t610-addons-deployment.md @@ -16,7 +16,7 @@ related: --- # t610 — развёртывание через HA-аддоны -> **Статус (2026-09-14): Этап 1 ✅. Этап 2 ✅ ПОЛНОСТЬЮ. Этап 3 🚧 В РАБОТЕ — решения приняты, комплект файлов собран, бэкапы сделаны. Удалено мёртвое `Mini Smart Switch 1`, добавлена новая Zigbee-розетка (17→16 устройств), имена согласованы. Следующий шаг — stop HA → залив реестров.** Сервисы: z2m (16 устройств), mbusd (502), modbus-bridge (MQTT + HA-опрос), MQTT-интеграция в HA. +> **Статус (2026-09-14): Этап 1 ✅. Этап 2 ✅ ПОЛНОСТЬЮ. Этап 3 🚧 ПОЧТИ ЗАКРЫТ — файлы залиты, HA запущен (248 сущностей, 11 зон, 0 ошибок). Осталась одна операция: правка `friendly_name` в z2m.** Удалено мёртвое `Mini Smart Switch 1`, добавлена Zigbee-розетка `0xa4c138eb6fbe9d19` (z2m = 16 устройств). Имена согласованы. Ключевое открытие: **сущности связаны по `unique_id`, поэтому смена `friendly_name` НЕ пересоздаёт `entity_id`** — человеческие имена из реестра сохранятся. Сервисы: z2m (16), mbusd (502), modbus-bridge (MQTT + HA-опрос), MQTT-интеграция в HA. > Родительский план: [[family/plans/home-automation-migration-t610]] (Шаг 3 в нём заменяется на этот документ). > Доступ к хосту, CLI и питфоллы: [[family/how-to/t610-access]]. @@ -53,7 +53,7 @@ related: | Terminal & SSH | `core_ssh` | Official | ✅ **установлен и работает** | | Samba share (для доступа к файлам) | `core_samba` | Official | ⏸️ установлен, `stopped` (нужен `password`) | | File editor | `core_configurator` | Official | ✅ установлен, `started` | -| **Zigbee2MQTT** | `45df7312_zigbee2mqtt` | Community repo | ✅ **установлен, работает — 17 устройств** | +| **Zigbee2MQTT** | `45df7312_zigbee2mqtt` | Community repo | ✅ **установлен, работает — 16 устройств** | | **mbusd** | `local_mbusd` | Local add-on (`/addons/mbusd`) | ✅ **установлен, работает — порт 502** | | **modbus-bridge** | `local_modbus-bridge` | Local add-on (`/addons/modbus-bridge`) | ✅ **установлен, работает — MQTT + HA-опрос** | | **MQTT-интеграция в HA** | `mqtt` | Config entry | ✅ **добавлена 2026-09-14** (была ОТСУТСТВОВАЛА → 22 сущности; стало 104, 69 Zigbee) | @@ -342,25 +342,89 @@ curl -s -X POST -H "Authorization: Bearer $T" -H "Content-Type: application/json **Правка дашборда:** в `lovelace.home_plan` ссылка `switch.vvod_vody_greiushchii_kabel` → `switch.heating_cable_plug` (скрипт `~/tmp-t610/fix_dashboard.py`, заменено 1 вхождение). -**Порядок работ:** +**Порядок работ (✅ ВЫПОЛНЕНО 2026-09-14, шаги 1–7):** 1. ✅ Бэкап `/config` t610 → `~/tmp-t610/backups/config-t610-20260914-115034.tar.gz` 2. ✅ Бэкап TrueNAS → `~/tmp-t610/backups/truenas-ha-backup-20260913-215043.tar.gz` (`auth`/`http`/`auth_provider` не читаются — root-only, и не нужны) -3. `ha core stop` на t610 -4. Залить реестры `.storage` (выборочно по списку) -5. Залить конфиги + `www/` -6. `ha core check` → `ha core start` -7. Проверка: сущности, зоны, автоматизации, дашборд -8. **ТОЛЬКО ПОСЛЕ** — `friendly_name` в z2m = человеческие имена (эталон из реестра) + чистка hex-остатков в HA +3. ✅ `ha core stop` (проверено: веб отдаёт `000` = лежит) +4. ✅ Залиты реестры `.storage` (12 файлов, выборочно по списку) +5. ✅ Залиты конфиги + `www/` (3 файла) +6. ✅ `ha core check` — ошибок нет; `ha core start` → веб `200` +7. ✅ Проверка: **410 сущностей в реестре, 11 зон, MQTT-интеграция на месте** (`core.config_entries` не тронут) +8. ⏳ **ОСТАЛОСЬ:** `friendly_name` в z2m = человеческие имена + чистка hex-остатков в HA -> ⚠️ Порядок 4 → 8 критичен: переименование z2m до переноса реестров пропадёт. +**Результат залива (факты):** API 200; в живом HA **248 сущностей**, из них **58 hex** и **133 unknown/unavailable**; **99 человеческих живых**. Ошибок в `home-assistant.log` нет. -**Питфоллы, найденные в этой сессии:** -- **`ha apps logs ` тяжёлый** — не гонять в цикле ожидания («висит» минутами). Ждать готовности по `database.db`/`state.json`. -- **`mosquitto_pub/sub` в аддоне без `--pwfile`** — только `-u`/`-P`. Пароль с `$` → брать из опций: `ha apps info --raw-json | jq -r '.data.options.mqtt.password' > /tmp/pw; MPW=$(cat /tmp/pw); rm /tmp/pw`. -- **Удаление устройства z2m:** `mosquitto_pub ... -t 'zigbee2mqtt/bridge/request/device/remove' -m '{"id":"0x...","force":true}'` (force для недоступных) → `{"status":"ok"}`; z2m сам убирает из `database.db` и `devices:`. -- **Токен HA маскируется** при подстановке в bash-переменную → через файл + `jq --arg`. -- **`http://supervisor/core` даёт 401** с пользовательским токеном (ждёт `SUPERVISOR_TOKEN`) → адрес `http://192.168.2.176:80`. -- **Кавычки в inline ssh-командах с кириллицей ломаются** → писать скрипт файлом, `scp`, запускать. +**Почему часть сущностей `unknown`/`unavailable` (диагноз, а не баг):** HA связал приехавшие из реестра сущности **по `unique_id`** (у всех вида `__zigbee2mqtt`) и **сохранил человеческие `entity_id`** — дублей не появилось. Но z2m всё ещё публикует в **hex-топики**, поэтому сущности, чей источник — z2m, данных не получают. Работают те, чьи данные идут не от z2m: modbus (заслонки, `cover.*_damper_*`), `sensor.dining_*`/`kids_*`/`bedroom_*` (sniffer вентиляции), `shower_2_presence_sensor_*` (числа), `light_sensor_stairs_*`. +⚠️ Лечится ровно шагом 8 — сменой `friendly_name` в z2m (см. ниже). + +**Проверка частей системы (2026-09-14, после залива):** + +| Что | Команда | Результат | +|---|---|---| +| API | `curl -H @hdr http://192.168.2.176/api/states` | 200, 248 сущностей | +| Зоны | `jq '.data.areas|length' core.area_registry` | 11 | +| MQTT entry | `jq -r '.data.entries[].domain' core.config_entries \| grep mqtt` | `mqtt` ✅ | +| Ошибки HA | `tail /config/home-assistant.log \| grep -i error` | нет | +| Живые human | `[.[] \| select(entity_id\|test("0x")==false) \| select(state!="unknown" and state!="unavailable")] \| length` | 99 | +| Живые hex | то же с `test("0x")` | 16 (это `nasos_obratki` voltage/energy/power/current, `heating_cable_plug`, протечка) | + +#### 🔑 КРИТИЧЕСКОЕ ОТКРЫТИЕ: связь сущностей идёт по `unique_id`, а НЕ по `entity_id` + +**Проверено на живом t610:** у всех zigbee-сущностей `unique_id` = `__zigbee2mqtt` (напр. `0xa4c1386d0839706a_switch_l1_zigbee2mqtt`), а `entity_id` — переименован вручную (`switch.light_stairs_l1`). + +**Следствия (отменяют прежнее опасение «всё пересоздастся»):** +1. ✅ **Смена `friendly_name` в z2m НЕ меняет `unique_id`** → HA узнаёт сущность по `unique_id`, **обновляет её на месте** и **сохраняет существующий `entity_id`** из реестра. Дубли не создаются. +2. ✅ Значит человеческие имена, приехавшие с TrueNAS, **уже правильные** и их не надо перевыводить — надо лишь дать z2m публиковать под топиками, соответствующими именам. +3. ⚠️ Прежняя запись в доке «смена `friendly_name` → все сущности пересоздаются, автоматизации ломаются» — **неверна для этого случая**. Автоматизации не ломаются. + +**Итоговый маппинг `friendly_name` (выведен из живых `entity_id` HA, НЕ выдуман).** Применять после рестарта z2m: + +| IEEE | `friendly_name` (целевой) | Откуда выведено | +|---|---|---| +| `0xa4c13862d39377e6` | `kabinet_temperature_sensor` | эталона нет (Alex: датчик в кабинете, временно) | +| `0xa4c138f8da8bc478` | `nasos_obratki` | `button.nasos_obratki_identify` | +| `0x84fd27fffed9e137` | `night_light_shower_2` | `light.night_light_shower_2` | +| `0xa4c1386d40ddb67b` | `light_sensor_stairs` | `sensor.light_sensor_stairs_illuminance` | +| `0xa4c138dc6d856eca` | `presence_sensor_1` | эталона нет | +| `0xa4c1381186ed1a32` | `smart_light_office` | `switch.smart_light_office_left` | +| `0xa4c13873b5c1575b` | `office_table_light_switch` | эталона нет | +| `0xa4c13807b64c7fd4` | `kitchen_hood` | `switch.kitchen_hood_l1` | +| `0xa4c138cefeee19fd` | `zigbee_dimmer_2ch` | `light.zigbee_dimmer_2ch_l1` | +| `0xa4c1386d0839706a` | `light_stairs` | `switch.light_stairs_l1` | +| `0xa4c1384fbe0b3a6b` | `sauna` | `switch.sauna` | +| `0xa4c138b0f9e674a5` | `wireless_light_switch_bed` | `sensor.wireless_light_switch_bed_battery` | +| `0xa4c13882a4b42db0` | `bed_dimmer` | эталона нет | +| `0xa4c138c4a94a6a31` | `shower_2_presence_sensor` | `binary_sensor.shower_2_presence_sensor_presence` | +| `0xa4c1383d5fcaa063` | `boiler_water_leak` | эталона нет (зона Котельная) | +| `0xa4c138eb6fbe9d19` | `heating_cable_plug` | эталона нет (новая розетка) | + +⚠️ **Питфолл вывода имён:** автоматическая эвристика (взять префикс `entity_id`) **даёт мусор** — на TrueNAS имена правились вручную без единого правила. Примеры: у `0xa4c1386d0839706a` есть `switch.light_stairs_l1` (от z2m) **и** `light.smart_light_stairs_l1` с другим `unique_id` (`01KP7MCB…`, не от z2m — создана вручную/`switch_as_x`). У `0xa4c1381186ed1a32` аналогично `switch.smart_light_office_left` (z2m) vs `light.smart_light_office_left` (`01KKC7…`). **Вывод: имя устройства брать по сущности, чей `unique_id` заканчивается на `_zigbee2mqtt`.** + +**Питфолл: маскировка токена ломает скрипты.** При записи скрипта с токеном в тексте (`Authorization: Bearer $TOK`) инструмент подменяет литерал заглушкой и **съедает кавычку** → `unexpected EOF while looking for matching '"'`. Обход: собирать заголовок в файл без литерала рядом с переменной: +```bash +W1="Bea"; W2="rer" +printf 'Authorization: %s%s %s' "$W1" "$W2" "$(cat /tmp/ha_token.txt)" > /tmp/hdr.txt +printf '\n' >> /tmp/hdr.txt +curl -s -H @/tmp/hdr.txt http://192.168.2.176/api/states > /tmp/states.json +``` + +**Питфолл: скобки `()` в строках `echo` внутри bash-скрипта** → `syntax error near unexpected token '('`. Не писать круглые скобки в `echo "…(…)"`. + +**Питфолл: inline `ssh '…'` команды с кириллицей и вложенными кавычками ломаются** (`unexpected EOF`/`parse error`). Правило: писать скрипт **файлом** → `scp` → `bash /tmp/script.sh`. Скрипты сессии: `~/tmp-t610/{s3_stop.sh,s3_push.sh,s3_verify.sh,check_live.sh,check_human.sh,remove_dead_dev.sh,permit_join.sh}`. + +#### ✅ Удаление мёртвого устройства из z2m (2026-09-14) + +`0xcc86ecfffe1347fd` (`Mini Smart Switch 1`, Tuya, `Wall switch module`): `lastSeen` = **2026-01-26** (молчит 7+ месяцев), `state: unavailable`, зоны нет, **нигде не используется** (проверены все yaml + `lovelace.home_plan` по `device_id` и `entity_id` — пусто). Решение Alex: **снести**. + +```bash +# бэкап базы перед удалением +cp /config/zigbee2mqtt/database.db /config/zigbee2mqtt/database.db.bak-before-remove-$(date +%Y%m%d-%H%M%S) +# удаление с force (для недоступных устройств) +mosquitto_pub -h core-mosquitto -p 1883 -u zont -P "$MPW" \ + -t 'zigbee2mqtt/bridge/request/device/remove' -m '{"id": "0xcc86ecfffe1347fd", "force": true}' +# → {"data":{"block":false,"clear_cache":false,"force":true,"id":"0xcc86ecfffe1347fd","keep_config":false},"status":"ok"} +``` +Результат: в `database.db` и в `devices:` `configuration.yaml` — **16 устройств** (было 17), мёртвого нет. z2m подчистил и базу, и конфиг сам. #### ✅ Zigbee `friendly_name` — корень generic-имён (разведка 2026-09-14) @@ -378,9 +442,11 @@ curl -s -X POST -H "Authorization: Bearer $T" -H "Content-Type: application/json - Проверено в `/config/zigbee2mqtt/configuration.yaml` (секция `devices:`) — у всех `friendly_name: ''`. - Отдельная категория — вообще без имени: `switch.0xa4c138f8da8bc478` (`original_name` пусто), `switch.0xcc86ecfffe1347fd`, `switch.0x84fd27fffed9e137`, `update.0xa4c138f8da8bc478`, `light.0xa4c13882a4b42db0`. -**Корневой механизм:** `entity_id` в HA формируется при **первом появлении** сущности и от `friendly_name` z2m. Уже созданные `entity_id` в реестре **НЕ переименовываются автоматически** при смене `friendly_name`. Поэтому нужны **две операции**: (а) `friendly_name` в z2m, (б) переименование `entity_id` в `core.entity_registry` HA. +**Корневой механизм (уточнён 2026-09-14 после залива реестров):** `entity_id` формируется при **первом появлении** сущности, а связь сущности в HA идёт **по `unique_id`** (`__zigbee2mqtt`). Смена `friendly_name` в z2m **меняет MQTT-топик и discovery, но НЕ `unique_id`** → HA находит сущность по `unique_id` и **обновляет её на месте, сохраняя существующий `entity_id`**. -⚠️ **Побочный эффект смены `friendly_name`:** меняются MQTT-топики → **все сущности пересоздаются с новыми `entity_id`**, любые ссылки в автоматизациях/шаблонах ломаются. Поэтому делать это **до** переноса автоматизаций с TrueNAS («пока чисто»). +⚠️ **ОТМЕНЕНО (было записано ошибочно ранее):** утверждение «смена `friendly_name` → все сущности пересоздаются с новыми `entity_id`, автоматизации ломаются» — **НЕВЕРНО**. Проверено на живом t610: дублей не появилось, человеческие `entity_id` из реестра сохранились. Автоматизации не ломаются. **Достаточно одной операции** — прописать `friendly_name` в z2m (переименовывать `entity_id` в `core.entity_registry` вручную НЕ надо). + +> ⚠️ **ВАЖНО про итоговую таблицу имён ниже — она УСТАРЕЛА.** Согласованный список (строки 481–499) замените на **«Итоговый маппинг `friendly_name` (выведен из живых `entity_id` HA)»** из §«КРИТИЧЕСКОЕ ОТКРЫТИЕ» выше. Расхождения (эталон — реальные `entity_id`, а не перевод из TrueNAS-имён): `obratka_pump`→**`nasos_obratki`**, `stairs_light_sensor`→**`light_sensor_stairs`**, `office_smart_light`→**`smart_light_office`**, `stairs_smart_light`→**`light_stairs`**, `bed_wireless_light_switch`→**`wireless_light_switch_bed`**, `shower_night_light`→**`night_light_shower_2`**. Причина: имена на TrueNAS правились вручную, и `entity_id` в HA — единственный достоверный источник. #### 🔄 Новое устройство: NEO NAS-WR01B (2026-09-14) @@ -456,10 +522,12 @@ timeout 10 mosquitto_sub -h core-mosquitto -p 1883 -u zont -P "$MPW" \ **Автоматизации TrueNAS (`automations.yaml`, 15 шт.):** Выключить/Включить циркуляцию ГВС, Ventilation automation on, office_pass_switch_table/main, Светло/Темно подсветку лестницы, Toggle/Cycle Dimmer bed, Вкл./Выкл. ночной свет душевая, Протечка котельная, Датчик протечки котельная батарея, Датчик освещённости лестница батарея, Light switch bed батарея, Zigbee T sensor батарея. -**Дашборд `home_plan` использует hex, который надо будет заменить после переименования:** -- `binary_sensor.0xa4c1383d5fcaa063_water_leak` → `boiler_water_leak` -- `switch.0xa4c138f8da8bc478` → `obratka_pump` -- `switch.vvod_vody_greiushchii_kabel` → **`heating_cable_plug`** (старая Tuya-розетка → новая Zigbee) +**Дашборд `home_plan` — правки ссылок (статус 2026-09-14):** +- ✅ `switch.vvod_vody_greiushchii_kabel` → **`heating_cable_plug`** — **СДЕЛАНО** (в staged-файле перед заливом, скрипт `fix_dashboard.py`) +- ⏳ `binary_sensor.0xa4c1383d5fcaa063_water_leak` → `boiler_water_leak` — заменится автоматически после смены `friendly_name` в z2m (шаг 8) +- ⏳ `switch.0xa4c138f8da8bc478` → `nasos_obratki` — то же + +> 📌 Дашборд ссылается на сущности по человеческим именам, которые уже есть в реестре (`switch.sauna`, `light.smart_light_office_left`, `light.smart_light_stairs_l1`, `binary_sensor.shower_2_presence_sensor_presence`). После шага 8 всё оживёт. ### Этап 4 — проверка и отключение TrueNAS 18. [ ] Чек-лист из родительского плана §6 @@ -487,10 +555,13 @@ timeout 10 mosquitto_sub -h core-mosquitto -p 1883 -u zont -P "$MPW" \ - [x] ✅ **РЕШЕНО 2026-09-14 — modbus-bridge `ha_token`/`mqtt_password`:** вписаны, MQTT + HA-опрос работают. Ключевой момент — `ha.url` = `http://192.168.2.176:80` (не `supervisor/core`), + в HA добавлена MQTT-интеграция. **Этап 2 закрыт полностью.** - [x] ✅ **РЕШЕНО 2026-09-14 — `custom_components` не переносим.** HACS (репо пусто) и `tuya_local` (нет config entry) не нужны; `localtuya` обслуживал единственную Tuya-розетку, которую Alex заменил на Zigbee → тоже снят. - [x] ✅ **РЕШЕНО 2026-09-14 — история БД не переносится** (новая с нуля) и **реестры `.storage` — замена** (вариант B). -- [x] ✅ **ВЫПОЛНЕНО 2026-09-14 — Zigbee-розетка NEO NAS-WR01B (`0xa4c138eb6fbe9d19`) добавлена** через permit_join (MQTT). z2m = 17 устройств. -- [x] ✅ **СОГЛАСОВАНЫ 2026-09-14 — имена 17 Zigbee-устройств** (латиница snake_case, единый формат). Эталон найден: человеческие `friendly_name` были на **TrueNAS в z2m** и в `core.device_registry`/дашборде. См. §«Имена 17 устройств». -- [ ] ⏳ **ЖДЁМ Alex — решение по `Mini Smart Switch 1` (`0xcc86ecfffe1347fd`):** нигде не используется, нет зоны, состояние `unavailable`. Варианты: имя `unused_wall_switch` либо удалить из z2m (unpair). +- [x] ✅ **ВЫПОЛНЕНО 2026-09-14 — Zigbee-розетка NEO NAS-WR01B (`0xa4c138eb6fbe9d19`) добавлена** через permit_join (MQTT). z2m = 16 устройств (после удаления мёртвого). +- [x] ✅ **ВЫПОЛНЕНО 2026-09-14 — Этап 3 (перенос конфига):** бэкапы сделаны, HA остановлен, залиты 12 файлов `.storage` + 5 конфигов + `www/`, HA запущен (**248 сущностей, 11 зон, MQTT-интеграция цела, ошибок нет**). `modbus.host` → `127.0.0.1`, `localtuya: debug` убран, дашборд поправлен. +- [x] ✅ **РЕШЕНО 2026-09-14 — `Mini Smart Switch 1` удалён из z2m** (`force: true`). Мёртвое: `lastSeen` 2026-01-26, `unavailable`, нет зоны, нигде не используется. +- [x] ✅ **УТОЧНЕНО 2026-09-14 — механизм связи сущностей:** HA связывает по `unique_id`, НЕ по `entity_id`. Смена `friendly_name` в z2m сохраняет человеческие `entity_id`. Прежнее опасение «всё пересоздастся» снято. +- [ ] ⏳ **ОСТАЛОСЬ (последний шаг Этапа 3):** прописать `friendly_name` в z2m по таблице из §«КРИТИЧЕСКОЕ ОТКРЫТИЕ» (16 устройств), перезапустить z2m, убедиться, что `unknown`-сущности ожили (ожидаемо ~133 → минимум). Затем чистка hex-остатков (58 шт.) в HA. - [ ] Камера (§8 родительского плана) — не аддон, разбираться отдельно +- [ ] ⚠️ Незакреплённое: `sensor.0xa4c138f8da8bc478_voltage/energy/power/current` (11 hex-сущностей розетки Насос обратки) — проживут ли под новым `friendly_name` или создадутся дубли; проверить после шага 8. ## Связанные заметки - [[family/plans/home-automation-migration-t610]] — родительский план