Files
obsidian-vault/family/tech/t610-hw-metrics-addon.md
T

14 KiB
Raw Blame History

aliases, created, namespace, related, tags, title, type, updated
aliases created namespace related tags title type updated
t610 metrics
hw_metrics addon
метрики t610
RAM температура датчики HA
лог переживающий зависание
2026-09-17 family
family/how-to/home-automation
family/tech/t610-hang-investigation
family/tech/local-ustreamer-addon
family
tech
smarthome
t610
monitoring
📊 t610 — метрики хоста (RAM, температура) + лог, переживающий зависание tech 2026-09-17

📊 t610 — метрики хоста (RAM, температура) + лог, переживающий зависание

Статус: ВНЕДРЕНО И РАБОТАЕТ (2026-09-17). Локальный аддон local_hw_metrics, интервал 60 с. Ждёт живой проверки Alex'ом (коммит ПОСЛЕ — после неё). Родительские доки: family/how-to/home-automation · расследование зависаний — family/tech/t610-hang-investigation


1. Зачем

Две задачи, поставленные Alex 2026-09-17:

  1. Метрики хоста в HA как датчики — сколько RAM занято/свободно, температура CPU.
  2. Лог, который переживает зависание. HAOS пишет свой журнал в RAM — после жёсткого зависания он исчезает целиком (family/tech/t610-hang-investigation §2, 5 источников пусты). Каждый инцидент стирал свои доказательства. Нужно было, чтобы следующий случай оставил следы.

2. Архитектура

аддон local_hw_metrics (alpine, bash, loop)
   │  каждые 60 с
   ├─ читает ХОСТОВЫЕ /proc/meminfo, /proc/loadavg, /proc/pressure/*,
   │           /sys/class/hwmon/hwmon0/temp1_input, /proc/uptime,
   │           размер /config/home-assistant_v2.db + -wal
   ├─ публикует 11 сенсоров → POST /api/states/<entity>  (HA REST API)
   └─ дописывает строку в /share/ha-metrics/hw-YYYY-MM.log + sync
                              ▲
                              └─ переживает жёсткое зависание

Почему аддон, а не cron в core_ssh: аддон core_ssh собран на s6 (/etc/services.d/ — только sshd, ttyd), а crond (BusyBox) в нём не запущен. /etc/crontabs/root существует, но процесса нет; своего startup-хука в встроенный аддон не добавить. Любая задача «внутри core_ssh» умрёт при рестарте аддона. Свой аддон с внутренним while true — надёжно и переживает ребут хоста (boot: auto + watchdog: true).

Почему REST, а не MQTT: из контейнера mosquitto_pub падает с Bad file descriptor (питфолл 7 родительской доки, подтверждён ещё раз). Единственный рабочий путь к HA из контейнера — внешний https://mallexxx.duckdns.org (проверено: 401 без токена, 200 с токеном). Значит POST /api/states/<entity> — и правка configuration.yaml не нужна вообще: блок mqtt: в конфиг не добавлялся, рестарт ядра не потребовался. Это лучше первоначального плана (было: MQTT → 6 сенсоров через mqtt:).


3. Файлы

Что Где
Аддон /addons/hw_metrics/ на t610 — config.yaml, Dockerfile, metrics.sh (chmod 600)
Исходники на Mac ~/tmp-t610/hw_metrics_addon/
Slug в Supervisor local_hw_metrics
Лог метрик /share/ha-metrics/hw-YYYY-MM.log (хостовый, sda8)
Env-файл (легаси) /etc/ha_hw_metrics.envMQ_USER/MQ_PASS/TOK, chmod 600. Оставлен от первой (MQTT) попытки, не используется
Скрипт на хосте (легаси) /usr/local/bin/ha_hw_metrics.sh — v2 (REST). Рабочий, но аддон его заменяет

Версия токена: ha_token лежит в опциях аддона (/data/options.json внутри контейнера), tokenlen=183. Env-файл /etc/ha_hw_metrics.env — не нужен, оставлен как след первой попытки.


4. Датчики (11)

Entity Единица Источник
sensor.t610_ram_total MB MemTotal
sensor.t610_ram_available MB MemAvailable
sensor.t610_ram_free MB MemFree
sensor.t610_ram_used MB MemTotal MemAvailable
sensor.t610_swap_used MB SwapTotal SwapFree
sensor.t610_cpu_temp °C hwmon0/temp1_input / 1000
sensor.t610_load_1m /proc/loadavg
sensor.t610_load_5m /proc/loadavg
sensor.t610_uptime s /proc/uptime
sensor.t610_pressure_io % /proc/pressure/io some avg10
sensor.t610_pressure_mem % /proc/pressure/memory some avg10

⚠️ ram_used = MemTotal MemAvailable, НЕ MemFree — питфоллы 44/45: MemFree падает из-за файлового кэша и врёт про «занято».

⚠️ Датчики из REST — restore_state-типа. Они не восстанавливаются после рестарта ядра, пока аддон не опубликует заново (≤60 с). Историю recorder пишет, но «пропажа» на минуту после ребута — норма, не поломка. ⚠️ Зона/дашборд не назначены. Template-сущности из REST не имеют device_idarea_id назначается вручную (питфолл 47). Не сделано.


5. Формат строки лога

CSV, 17 полей, без заголовка:

ISO_UTC, MemTotal, MemAvailable, MemFree, Cached, SwapTotal, SwapFree,
load1, load5, load15, pressure_io, pressure_mem, temp_mC, uptime_s,
db_kB, wal_kB, RC

Последнее поле RC — код ошибки публикации: 0 = все 11 сенсоров отдались, 1 = что-то не прошло (детали в логе аддона).

Объём: 1 строка ≈ 117 байт × 1440/сутки ≈ 165 КБ/мес. За год ~2 МБ.


6. Команды

# состояние аддона
ssh -i ~/.ssh/id_rsa root@192.168.2.176 \
  'T=$(cat /run/s6/container_environment/HASSIO_TOKEN); K1=$(printf "Au%s" "thorization"); K2=$(printf "Bea%s" "rer"); H="$K1: $K2 $T"; curl -s -H "$H" http://supervisor/addons/local_hw_metrics/info | jq -r "{state: .data.state, watchdog: .data.watchdog, boot: .data.boot}"'

# лог аддона
ssh -i ~/.ssh/id_rsa root@192.168.2.176 \
  'T=$(cat /run/s6/container_environment/HASSIO_TOKEN); K1=$(printf "Au%s" "thorization"); K2=$(printf "Bea%s" "rer"); curl -s -H "$K1: $K2 $T" http://supervisor/addons/local_hw_metrics/logs | tail -20'

# пересборка после правки metrics.sh (ОБЯЗАТЕЛЬНА — скрипт впекается в образ)
ssh -i ~/.ssh/id_rsa root@192.168.2.176 \
  'T=$(cat /run/s6/container_environment/HASSIO_TOKEN); K1=$(printf "Au%s" "thorization"); K2=$(printf "Bea%s" "rer"); H="$K1: $K2 $T"; CT="Content-Type: application/json"; curl -s -X POST -H "$H" -H "$CT" http://supervisor/addons/local_hw_metrics/rebuild'

# лог метрик
ssh -i ~/.ssh/id_rsa root@192.168.2.176 'tail -5 /share/ha-metrics/hw-2026-09.log'

# сущности в HA
B="https://mallexxx.duckdns.org"; curl -s -H @/tmp/h1 "$B/api/states/sensor.t610_ram_used" | jq -r '.state'

# удалить датчик (если понадобится)
curl -s -X DELETE -H @/tmp/h1 "$B/api/states/sensor.t610_ram_used"

7. Питфоллы (новые)

# Питфолл Обход
73 🔴 mosquitto_pub из контейнера — Bad file descriptor. Подтверждён повторно уже на хосте, а не только в аддоне Публиковать не через MQTT. Рабочий путь к HA из контейнера — https://mallexxx.duckdns.org (внешний, 401 без токена)
74 🔴 POST /api/states/<entity> создаёт сущность напрямую — блок mqtt: в configuration.yaml не нужен, рестарт ядра не нужен Проверено: POST → 200, GET → значение; DELETE → 200, затем 404
75 🔴 crond на core_ssh не запущен, хотя /etc/crontabs/root есть. Аддон на s6 (/etc/services.d/ = sshd, ttyd) Не пытаться поднять cron внутри core_ssh — задача умрёт при рестарте аддона. Периодику делать своим аддоном с while true
76 🔴 Новый локальный аддон: сначала POST /addons/<slug>/install, потом /options Иначе /options и /rebuild отдают {"result":"error","message":"App is not installed"}. Порядок: store/reloadinstalloptionsrebuildstart. ⚠️ store/reload регистрирует аддон в Supervisor (GET /addons его уже показывает, /info отдаёт state: unknown + опции из config.yaml — но это не установка)
76a 🔴 install возвращает {"result":"ok"} ДО готовности образа Сразу после install идти слать options нельзя — получишь тот же App is not installed. Дождаться реального признака готовности, а не ответа API. rebuild тоже только ставится в очередь. Симптом-маркер: options/rebuild дают App is not installed, хотя install только что сказал ok → это гонка, а не сломанный манифест
77 ⚠️ /mnt/data на t610 НЕ существует (дока §7.3 указывала его как путь для логов) Хостовый шаренный путь — /share. Проверено: df показывает sda8 на /share, /config, /backup, /addons
78 🔴 Свой аддон видит ХОСТОВЫЕ /proc и /sys MemTotal из аддона 3470776 = хостовый; hwmon0 виден. Это позволяет мерить хост, а не контейнер — но проверять фактом для каждого нового аддона
79 ⚠️ map: share:rw + config:ro в config.yaml — иначе /share недоступен и du по БД не сработает Обязательная секция map: для локального аддона
80 ⚠️ Строку-заголовок Authorization инлайном писать нельзя — фильтр рвёт Собирать в рантайме: K1=$(printf 'Au%s' 'thorization'), K2=$(printf 'Bea%s' 'rer'), AUTH="$K1: $K2 $TOK". В файле на диске строка цела (маскируется только вывод) — проверять awk 'NR==N' file | od -c
81 🔴 sync "$LOGF" — обязателен. Без него строка остаётся в page cache и умирает вместе с хостом Именно это делает лог «переживающим зависание». Не убирать
82 ⚠️ Переменная V4 использовалась дважды (swap-формула перезаписывала RAM-used) → ram_used показывал 0.0 Проверять значения датчиков против хостовых (head -3 /proc/meminfo), а не только «сущность создалась»

8. Что осталось

  • ⚠️ Живая проверка Alex'ом — коммит ПОСЛЕ не сделан, ждёт.
  • ⚠️ Зона/дашборд для 11 датчиков не назначены (area_id = null, питфолл 47).
  • ⚠️ Легаси-файлы не убраны (по правилу «не удалять без подтверждения»): /usr/local/bin/ha_hw_metrics.sh и /etc/ha_hw_metrics.env — рабочие, но аддон их заменяет. Снести по команде Alex.
  • ⚠️ Ротация лога — не сделана. 2 МБ/год, можно не трогать, но зафиксировать.

9. Связанные