[2026-09-17] eagle: family/how-to/home-automation.md family/how-to/rasputin-router.md family/tech/haos-local-addon-publish-sensors.md family/tech/t610-hang-investigation.md family/tech/t610-hw-metrics-addon.md
This commit is contained in:
@@ -453,7 +453,9 @@ ha apps restart 45df7312_zigbee2mqtt # под
|
||||
|
||||
### Температура CPU
|
||||
|
||||
> ✅ **2026-09-17: заведено как датчик HA — `sensor.t610_cpu_temp`** через аддон `local_hw_metrics` (вместе с RAM/load/pressure). Разбор — [[family/tech/t610-hw-metrics-addon]]. Ниже — ручной способ через SSH (остаётся рабочим).
|
||||
> ✅ **2026-09-17: заведено как датчик HA — `sensor.t610_t610_cpu_temp`** (отображаемое имя `t610 CPU temp`) через аддон `local_hw_metrics` (вместе с RAM/load/pressure).
|
||||
> ⚠️ `entity_id` с **двойным префиксом** `t610_t610_` — известный дефект, не переименовывается ([[family/tech/t610-hw-metrics-addon]] §8). В UI видно корректно.
|
||||
> Разбор аддона: [[family/tech/t610-hw-metrics-addon]]. Ниже — ручной способ через SSH (остаётся рабочим).
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa root@192.168.2.176 \
|
||||
@@ -765,7 +767,7 @@ Hz:PWM 0:0 1:0 2:0 3:0 4:48 5:55 6:63 7:70 8:78 9:85 10:92 11:97 12:102 13:107 1
|
||||
| 4 | Automation API: **`triggers`/`conditions`/`actions`** (мн.ч.) | Читать конфиг обратно и сверять |
|
||||
| 5 | z2m перезапишет `configuration.yaml` из `database.db` при рестарте | Переименование — только `bridge/request/device/rename` |
|
||||
| 6 | После смены имени z2m HA держит старые сущности | Удалить retained `homeassistant/<domain>/<old_ieee>/*/config`, рестарт z2m |
|
||||
| 7 | `mosquitto_sub`/`pub` в аддоне → `Bad file descriptor` | Публиковать из HA; подписка — с Mac |
|
||||
| 7 | `mosquitto_sub`/`pub` в контейнере → `Bad file descriptor` — ⚠️ **ТОЛЬКО на неверном адресе** | ⛔ Прежняя формулировка «MQTT из контейнера не работает» **опровергнута 2026-09-17**: работает, если адресовать **`core-mosquitto`** (Docker DNS, IPv6 `fd0c:ac1e:2100::7`). Падает на `127.0.0.1` и `192.168.2.176` — там свой netns, 1883 не слушается. Проверка: `getent hosts core-mosquitto` + `nc -z core-mosquitto 1883`. Разбор — [[family/tech/t610-hw-metrics-addon]] §7 |
|
||||
| 8 | `ha apps logs <slug>` — старый буфер | Живой лог только через API / файл |
|
||||
| 9 | `ha core stop` из SSH рубит соединение | Через API |
|
||||
| 10 | Два CH340 неразличимы по by-id | Только by-path |
|
||||
@@ -818,11 +820,14 @@ Hz:PWM 0:0 1:0 2:0 3:0 4:48 5:55 6:63 7:70 8:78 9:85 10:92 11:97 12:102 13:107 1
|
||||
| 58 | 🎯 **Симптом-матч с форума ≠ доказанная причина** — тред HA `1025213` (та же версия стека, `sqlite3.OperationalError: disk I/O error`) | Это **сильнейший кандидат**, но закрывать только фактом: `smartctl` + `dmesg`. [[family/tech/t610-hang-investigation]] §5 |
|
||||
| 59 | 🔴 **Порядок разбора инцидента: ФАКТЫ → версия, НЕ версия → проверка** | Сессия 2026-09-17: три «версии» подряд (template-сенсоры → swap/cache → UMA → бэкап) сняты Alex'ом одной репликой каждая. Сначала e820/BIOS/SMART/метрики — потом формулировать |
|
||||
| 60 | 🔴 **«Система дропнула память в процессе работы» — физически невозможно** | Объём виден ядру **один раз** при загрузке через BIOS, не пересчитывается. «Дропнула память» = **зависла**. Режим отказа — **нестабильная планка**: иногда не детектится, иногда ребут, иногда зависон под нагрузкой |
|
||||
| 61 | 🔴 **`mosquitto_pub` из контейнера — `Bad file descriptor`** (питфолл 7, подтверждён повторно) | Публиковать **не через MQTT**. Рабочий путь к HA из контейнера — внешний `https://mallexxx.duckdns.org`. Разбор — [[family/tech/t610-hw-metrics-addon]] §7 |
|
||||
| 61 | 🔴 **`mosquitto_pub` в контейнере падает — НО только на неверном адресе** | ⛔ Формулировка «MQTT из контейнера не работает» **опровергнута**: адресовать **`core-mosquitto`** (Docker DNS), а **НЕ** `127.0.0.1`/`192.168.2.176` (свой netns, 1883 не слушается). Разбор — [[family/tech/t610-hw-metrics-addon]] §7 |
|
||||
| 62 | 🔴 **`crond` на `core_ssh` НЕ запущен** (аддон на s6: `/etc/services.d/` = `sshd`, `ttyd`) | Периодику делать **своим локальным аддоном** с `while true`, не cron'ом в `core_ssh` — задача умрёт при рестарте аддона |
|
||||
| 63 | 🔴 **`/mnt/data` на t610 НЕ существует** (прежняя дока §7.3 указывала его как путь для метрик) | Хостовый шаренный путь — **`/share`** (`sda8`). Проверено `df` |
|
||||
| 64 | ⚠️ **Новый локальный аддон: `install` ДО `options`/`rebuild`** | Иначе `{"result":"error","message":"App is not installed"}`. Порядок: `store/reload` → `install` → `options` → `rebuild` → `start` |
|
||||
| 65 | 🔴 **`POST /api/states/<entity>` создаёт сущность в HA напрямую** | Блок `mqtt:` в `configuration.yaml` и рестарт ядра **не нужны** вообще. Проверено: POST → `200`, DELETE → `200` затем `404` |
|
||||
| 64 | ⚠️ **Новый локальный аддон: `install` ДО `options`/`rebuild`** | Иначе `{"result":"error","message":"App is not installed"}`. Порядок: `store/reload` → `install` → `options` → `rebuild` → `start`. ⚠️ `install` отдаёт `ok` **до** готовности — сразу слать `options` нельзя (гонка) |
|
||||
| 65 | 🔴 **`POST /api/states/<entity>` создаёт сущность, которой НЕТ в `entity_registry`** | Блок `mqtt:` и рестарт ядра не нужны — но такая сущность **невидима для зон и дашбордов** (нет `unique_id`/`device`/`area_id`). Для UI — только **MQTT discovery** или `configuration.yaml` |
|
||||
| 66 | 🔴 **MQTT discovery: кириллица в `device.name` + `object_id` → транслитерированный `entity_id`** | `device.name` — только латиницей, `object_id` **не задавать**. `entity_id` = `<device.name>_<name>`, поэтому префикс в `name` даёт **двойной** (`sensor.t610_t610_*`) |
|
||||
| 67 | 🔴 **`id_reuse: Identifier values have to increase` запирает `entity_registry/update` и `/remove`** | Воспроизведено на переименовании, `name`, `area_id`, удалении, смене `unique_id`. Промежуточные имена, `name_by_user`, удаление device, рестарт ядра — **не помогают**. **Не тратить время**: единственный рабочий путь — новый `unique_id` + сброс retained-топиков |
|
||||
| 68 | 🔴 **Сброс retained discovery-топика (`-m "" -r`) удаляет сущность из HA и снимает `id_reuse`** | Штатный способ пересоздать MQTT-сущности: очистить `homeassistant/sensor/<dev>/<key>/config` → HA удалит сущность → переопубликовать конфиг |
|
||||
|
||||
---
|
||||
|
||||
@@ -922,7 +927,7 @@ ssh root@192.168.2.176 'ha apps logs local_modbus-bridge | grep -E "Raw RTU|→
|
||||
- 🔴 **ЗАВИСАНИЯ ХОСТА — причина не установлена** (2026-09-17). Единственный незакрытый вопрос — интервал между зависаниями (стабильный аптайм = софт; хаотично = железо). Полностью: [[family/tech/t610-hang-investigation]].
|
||||
> ✅ **2026-09-17: сбор метрик внедрён** — аддон `local_hw_metrics`, 11 датчиков + лог на диск со `sync` ([[family/tech/t610-hw-metrics-addon]]). Теперь следующий инцидент оставит следы.
|
||||
- 🔴 **`recorder:` блока в `configuration.yaml` НЕТ ВООБЩЕ** — HA пишет всё подряд, дефолтные 10 дней, без `exclude`. БД 77 МБ + WAL 4.4 МБ. Кандидат на оптимизацию (НЕ «фикс зависания» — связь не доказана). Введение `exclude` ждёт апрува Alex.
|
||||
- 🔴 **`MemTotal` живой = 1.44 ГБ**, в §3.9 зафиксировано 3.31 ГБ. Расхождение не объяснено, проверка (`dmesg e820` / `dmidecode`) не запущена. См. §3.9 и [[family/tech/t610-hang-investigation]] §3.1.
|
||||
- 🔴 **`MemTotal` меняется между загрузками** — 2026-09-17 утром живой замер дал **1.44 ГБ**, вечером (~13:11, аптайм 6 мин после ребута) — **3.31 ГБ**. Это **подтверждение** описанного механизма «ступенька» ([[family/tech/t610-hang-investigation]] §3.1.2, §5.1 п.2), не новое открытие. Причину вечернего ребута не выясняли. См. §3.9 и [[family/tech/t610-hw-metrics-addon]] §10.
|
||||
- 🔴 **Ориентация кадра камеры** — в `/addons/ustreamer/` стоит `transpose=1` (90° по часовой), счётчик лежит на бок. Нужен `transpose=2` + rebuild аддона.
|
||||
- 🔴 **Камера в HA не обновляется** — Generic Camera (`entry_id 01M2FX50K72X2RSYY549QSG3XP`, `camera.192_168_2_176`) смотрит на мёртвые адреса удалённого go2rtc: `still_image_url = http://192.168.2.176:1984/api/frame.jpeg` и `stream_source = rtsp://192.168.2.176:8554/...`. Менять на `http://192.168.2.176:8090/frame`, `stream_source` — пусто. Живёт в `/config/.storage/core.config_entries`, **не в `configuration.yaml`**. См. §4.
|
||||
- ⚠️ **Осиротевший `/config/go2rtc.yaml`** (1085 байт) — go2rtc удалён, читать нечем.
|
||||
|
||||
@@ -39,14 +39,22 @@ LAN clients
|
||||
-> selected exceptions: table main -> WAN device
|
||||
```
|
||||
|
||||
WAN is currently represented by both `eth0` and `usb0` in the `wan` firewall zone. At capture time, `eth0` had no carrier, while `usb0` was up and had the default route.
|
||||
WAN devices are `eth0` and `usb0` in the `wan` firewall zone. **As of 2026-09-17 `eth0` is the active WAN** (it carries the default route); `usb0` is idle. At the 2026-07-22 capture this was inverted — `eth0` had no carrier and `usb0` held the default route.
|
||||
|
||||
Current default route:
|
||||
Default route at the 2026-07-22 capture (historical, no longer active):
|
||||
|
||||
```text
|
||||
default via 10.252.240.133 dev usb0 src 10.252.240.230
|
||||
```
|
||||
|
||||
Current default route (2026-09-17):
|
||||
|
||||
```text
|
||||
default via 192.168.2.2 dev eth0 proto static src 192.168.2.157
|
||||
```
|
||||
|
||||
That is, Rasputin gets `192.168.2.157/24` from the upstream router `192.168.2.2` and reaches the internet through it; `192.168.2.2` in turn sits behind GPON `192.168.0.1`.
|
||||
|
||||
VPN table:
|
||||
|
||||
```text
|
||||
@@ -314,6 +322,7 @@ Meaning:
|
||||
- Mac Wi-Fi `192.168.6.173` UDP/7844 goes direct through `main`.
|
||||
- Mac Ethernet `192.168.6.104` UDP/7844 goes direct through `main`.
|
||||
- Traffic to upstream LAN `192.168.2.0/24` goes direct through `main`.
|
||||
- 🔴 Traffic to the GPON segment `192.168.0.0/24` is **NOT** covered by rule `100` (2026-09-17) → falls through to rule `101` → `table vpn` → `tun0`. Доступ к GPON-сегменту из LAN `192.168.6.0/24` не работает. See the «🔴 Транзит Rasputin → 192.168.0.0/24» section.
|
||||
- All other traffic entering from LAN bridge `br-lan` uses `table vpn`.
|
||||
- `table vpn` sends default traffic through `tun0`.
|
||||
|
||||
@@ -327,6 +336,8 @@ ip rule add to 192.168.2.0/24 lookup main priority 100
|
||||
exit 0
|
||||
```
|
||||
|
||||
⚠️ Здесь только `192.168.2.0/24`. Строки для `192.168.0.0/24` нет — это и есть корневая причина сломанного транзита в GPON-сегмент. После ребута текущий `ip rule 100` пересоздаётся именно из этого файла.
|
||||
|
||||
## Firewall Model
|
||||
|
||||
Default firewall policy:
|
||||
@@ -421,6 +432,15 @@ firewall.@rule[10].target='ACCEPT'
|
||||
firewall.@rule[10].dest_ip='192.168.2.0/24' '192.168.0.1'
|
||||
```
|
||||
|
||||
⚠️ **Порядковый номер изменился (2026-09-17).** Актуальное правило — `firewall.@rule[0].name='Allow-upstream-LAN'`, и `dest_ip` расширен до GPON-сегмента. Его nft-реализация в `forward_lan` — **две отдельные строки, `tcp` и `udp`, без `icmp`**:
|
||||
|
||||
```text
|
||||
meta l4proto tcp ip daddr { 192.168.0.1, 192.168.0.50, 192.168.2.0/24 } counter packets 19 bytes 1216 jump accept_to_wan comment "!fw4: Allow-upstream-LAN"
|
||||
meta l4proto udp ip daddr { 192.168.0.1, 192.168.0.50, 192.168.2.0/24 } counter packets 0 bytes 0 jump accept_to_wan comment "!fw4: Allow-upstream-LAN"
|
||||
```
|
||||
|
||||
Практическое следствие: `forward` в GPON-сегмент разрешён, но без NAT ответ не вернётся, а ICMP вообще не проходит. Полный разбор — в разделе «🔴 Транзит Rasputin → 192.168.0.0/24» ниже.
|
||||
|
||||
---
|
||||
|
||||
## 🔴 ICMP к недоступному хосту в 192.168.2.0/24 отдаёт `Destination Port Unreachable` от САМОГО роутера
|
||||
@@ -456,6 +476,10 @@ Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
|
||||
|
||||
> ⚠️ Проверять достижимость узлов `192.168.2.0/24` из `192.168.6.0/24` надёжнее всего **тем же каналом, которым потом будете работать**: SSH по ключу. `ssh -o ConnectTimeout=10 -o BatchMode=yes root@192.168.2.176 'uptime'` — если отвечает, хост жив, и всё дальнейшее снимается через него. Пинг/веб-порты могут врать (см. `Reject to LAN` ниже), SSH — нет.
|
||||
|
||||
> 🔴 **Проверка 2026-09-17: 5 из 5 ICMP-попыток к `192.168.2.2` отбиты роутером** (`Destination Port Unreachable` от `192.168.6.1`), при том что с самого Rasputin `192.168.2.2` пингуется **0% loss, 0.75–0.84 ms**. То есть эхо-запрос из LAN до шлюза не доходит вообще — отбой происходит локально. Практический вывод: **отсутствие пинга к `192.168.2.x` НЕ говорит о том, что хост/шлюз недоступен.** Единственный вывод — «ICMP из LAN до этого адреса зарезан». Никогда не строить на пинге вывод о состоянии аплинка; проверять TCP-каналом, которым будете работать.
|
||||
|
||||
> ⚠️ Ещё один контр-пример к пингу как индикатору (2026-09-17, `192.168.0.50`): с Мака — 100% loss **и без** `Destination Port Unreachable` (обычный timeout), а с Rasputin — 0% loss. Здесь пинг отражает реальную поломку policy routing, но **не** показывает, жив ли хост. Различить «хост мёртв» и «транзит сломан» можно одним дешёвым шагом: пингануть ту же цель **с самого Rasputin**. Роутер видит, клиент — нет ⇒ проблема в транзите, не в хосте.
|
||||
|
||||
**Границы прав внутри сегментов (напоминание):**
|
||||
- Router transit `192.168.6.0/24 ↔ 192.168.2.0/24` — разрешён правилами выше.
|
||||
- Между сегментами есть санитарный `Reject to LAN` в `forward_lan` → произвольные порты не пройдут, ICMP-эхо тоже.
|
||||
@@ -767,7 +791,11 @@ uci commit dhcp
|
||||
- `ip rule` can match `ipproto udp dport 7844` on this OpenWrt build; this was tested and confirmed before making the persistent change.
|
||||
- The firewall allow alone would not be sufficient, because policy routing rule `101` sends LAN ingress to `table vpn`. The direct `ip rule`s at priorities `98` and `99` must remain before priority `101`.
|
||||
- Rule order in `forward_lan` matters: Cloudflare direct allow must stay above `KillSwitch`.
|
||||
- `eth0` was down at the 2026-07-22 capture; `usb0` was active and part of the `wan` firewall zone.
|
||||
- `eth0` is the **active** WAN as of 2026-09-17 (`192.168.2.157/24`, gw `192.168.2.2`); `usb0` is idle. At the 2026-07-22 capture this was inverted (`eth0` down, `usb0` carrying the default route). Do not trust the old banner — re-read `ip route` before assuming which WAN is live.
|
||||
- 🔴 **Транзит из LAN `192.168.6.0/24` в GPON-сегмент `192.168.0.0/24` НЕ работает (2026-09-17).** Причин три: `ip rule 100` не покрывает `192.168.0.0/24`; нет NAT/masq для этого направления; ICMP не разрешён в `Allow-upstream-LAN`. План ремонта — в одноимённом разделе. **Пока не применён.**
|
||||
- 🔴 **ICMP не является индикатором доступности `192.168.0.0/24` — и подавно.** `Allow-upstream-LAN` создан только для `tcp`+`udp`, поэтому эхо-запросы из LAN падают в `KillSwitch` и роутер отвечает `Destination Port Unreachable` от себя. Проверять TCP-портом (`nc -zv 192.168.0.50 80`) или SSH.
|
||||
- Различай два похожих симптома: `Destination Port Unreachable` **от роутера `192.168.6.1`** = локальное отбивание ICMP/firewall-ом, а не закрытый порт на хосте. Признак живости — ответ на TCP/SSH, а не текст ICMP-ошибки.
|
||||
- 🔴 **Ping from Mac to an unreachable `192.168.2.x` host returns `Destination Port Unreachable` from `rasputin.lan (192.168.6.1)`, NOT a plain timeout.** This is the router rejecting the attempt — it does **not** mean the host is up with a closed port. Use `arp (incomplete)` + `100% packet loss` as the liveness signal. Confirmed 2026-09-15 (see the dedicated section above).
|
||||
- Liveness of `192.168.2.0/24` hosts is best verified with the channel you intend to work through: key-based SSH (`ssh -o BatchMode=yes root@192.168.2.176 'uptime'`). Ping and web ports can mislead; an answered SSH session cannot.
|
||||
- **Дешёвый способ развести «хост мёртв» и «транзит сломан»:** пингануть цель *с самого Rasputin* (`ssh root@192.168.6.1 'ping -c2 <target>'`). Если роутер видит хост, а LAN-клиент — нет, проблема в policy routing/firewall, а не в хосте. Именно так 2026-09-17 локализовали GPON-проблему.
|
||||
- Secrets are redacted here intentionally. Consult the live router files only when the actual VLESS or Cloudflare credentials are needed.
|
||||
|
||||
Reference in New Issue
Block a user