Умный дом на Raspberry Pi · раздел батареек · 27 сентября 2026

Батарейки в умном доме: какие садятся, какие уже мертвы — и почему для этого нужны типы элементов

Девять устройств в доме живут на батарейках. Три из них — «таблетки» CR2032 на 3,0 В, остальные — AAA или AA. Одинаковый порог «менять при 20 %» для всех даёт ерунду: шкалы у элементов разные. Поэтому появился справочник типов элементов, карточка на главной, отдельная страница и починенный ночной cron. Ниже — что сделано, почему именно так, и что осталось на тебе.

1. Что видно прямо сейчас

Фактическое состояние на момент написания — из базы дома, не выдумано:

УстройствоЭлементЗарядНапряжениеСостояние
Датчик протечки (ванная)CR2032 ×1 (3,0 В)75 %2500 мВ пора менять напряжение дошло до порога 2,70 В
Кран SONOFF SWVAA ×4 (6,0 В)84 %не отдаёт нет связи молчит 18 дн — цифры устарели
Датчик освещённостиCR2032 ×1 (3,0 В)100 %3000 мВ нет связи молчит 18 дн — цифры устарели
Садовый кран PushOkAAA ×2 (3,0 В)83 %2700 мВ в норме до порога 2,60 В запас есть
Датчик почвы (большой горшок)AAA ×2 (3,0 В)92,5 %2900 мВ в норме
Спальня: темп/влажностьCR2032 ×1 (3,0 В)100 %2900 мВ в норме
Датчик вибрации/двериCR2032 ×1 (3,0 В)100 %не отдаёт в норме
Датчик почвы (земляника)AAA ×2 (3,0 В)100 %не отдаёт в норме
Датчик присутствия (mmWave)AAA (3,0 В)100 %не отдаёт в норме
Единственное реальное действие сейчас — батарейка в датчике протечки. 75 % по проценту и 2500 мВ по напряжению: для CR2032 это глубокий разряд, порог «менять» — 2,70 В. Остальные можно не трогать.

2. Почему нельзя было просто взять один порог

Первая мысль — «взять все топики, где есть battery, и сравнить с числом». Не работает по трём причинам, и каждую пришлось закрыть отдельно.

Причина 1. Элементы разные, шкалы разные

CR2032 — это одна таблетка на 3,0 В. Кран полива — четыре батарейки AA, то есть 6,0 В. Порог 2,7 В осмыслен для таблетки и бессмыслен для крана (у которого 6 В — это норма). Поэтому пороги живут в справочнике, по устройству.

Причина 2. Процент врёт, а напряжение — нет

Процент считает не устройство, а zigbee2mqtt — по приблизительной кривой разряда. Кривая ступенчатая, и на краях диапазона врёт: видел датчики, которые месяц показывают «100 %», а потом сразу падают в ноль. Напряжение же приходит с устройства как есть. Поэтому состояние берётся по худшему из двух сигналов: если вольтаж уже ушёл ниже порога, а процент ещё бодрый — всё равно «пора менять».

Причина 3. Милливольты против вольт — та самая засада

Это главная тонкость дома, и на ней легко ошибиться. У батарейных устройств поле voltage — это милливольты (2500, 2900, 3000). У розетки с измерением мощности то же самое поле voltage — это вольты сети (207…253). Два следствия: Именно на этом я и поймал себя: первый прогон показал «вышли из строя: 0», хотя датчик протечки уже был ниже порога.

3. Что добавлено — по частям

Справочник элементов: таблица battery_spec

Одна строка на устройство. Это единственное место, где правятся пороги — код их не дублирует. Хочешь поменять порог или добавить новое устройство: одна строка в базе, страницы трогать не нужно.

CR2032 (1 шт., 3,0 В)     менять ≤ 2,70 В или 20 %   ·  мёртвая ≤ 2,40 В или 5 %
AAA    (2 шт., 3,0 В)     менять ≤ 2,60 В или 20 %   ·  мёртвая ≤ 2,20 В или 5 %
AA     (4 шт., 6,0 В)     менять ≤ 5,20 В или 20 %   ·  мёртвая ≤ 4,40 В или 5 %

Карточка на главной странице

Показывает только то, что требует внимания: «вышли из строя», «пора менять», «нет связи». Если всё хорошо — одна зелёная строка «Все 9 устройств в норме», чтобы не мозолила глаза.

🔋 Батарейки ⛔ вышли из строя: 0 🟠 пора менять: 1
Так это выглядит на главной (пример с фактическими данными)
🟠 Датчик протечки (ванная) пора менять · 75 % · 2 500 мВ
CR2032 ×1 (3,0 В) — напряжение 2500 мВ дошло до порога 2.70 В
🕓 Кран SONOFF SWV нет связи · 84 %
AA ×4 (6,0 В) — нет данных 18 дн. — цифры устарели, проверь связь
🔎 Все устройства, пороги и история напряжений

Страница /admin/batteries.php

Полная таблица: устройство, комната, элемент, заряд, напряжение, пороги, когда обновлялось, тренд за 7 суток. Ссылка — в верхнем меню (значок 🔋) и из карточки на главной. Открывается только после входа в панель, как остальная админка.

История напряжений — теперь копится

Раньше история писалась только для температуры и влажности: у батарейных топиков стоял флаг save_history = 0. То есть видеть «сейчас» можно было, а «как падало за месяц» — нет. Включено для 14 топиков. Розетку намеренно не включал: там сетевое напряжение, оно и так в истории.

Первые точки уже пошли. Полноценный тренд будет через несколько дней: батарейные сообщения приходят редко (раз в часы), а некоторые датчики пишут вообще раз в сутки.

Cron: починен и переписан

Что было сломано. Задание 0 9 * * * check_battery.py падало каждый день. В логе — Access denied for user 'iot_user'@'localhost': скрипт ходил в базу под старой учёткой, а пароли давно вынесены в /etc/iot/credentials.env. Плюс он сравнивал процент с одним порогом 11 % для всех устройств подряд — не различая таблетку и четыре AA. И писал лог в /var/log/battery_check.log, который принадлежит www-data: из-под mazzick туда писать нельзя, поэтому лог и выглядел битым.

Теперь скрипт берёт пороги из того же справочника, что панель, читает секреты из /etc/iot/credentials.env, пишет лог в свою папку. Учитывает процент, напряжение и флаг battery_low, который некоторые устройства ставят сами.

Чтобы письмо не приходило каждый день. Скрипт запоминает «подпись» состояния в ~/.battery_state.json и шлёт письмо только если состояние изменилось — или раз в 7 дней, пока проблема не устранена. Иначе ежедневное «всё в норме» через неделю уходит в спам вместе с настоящими тревогами. Проверено: второй запуск печатает «состояние не менялось ... молчу» и письма не шлёт.

Попутно: раздел батареек в общей проверке healthcheck.sh

Общая проверка дома теперь показывает сводку по батарейкам. Добавлена как информационная, а не как ошибка: про разряженные элементы уже пишет утреннее письмо, и второе уведомление о том же было бы дублем.

И ещё одна находка — не про батарейки. Проверка дома жаловалась двумя ошибками на модуль аномалий, и сторож каждый час слал письмо «ПРОБЛЕМЫ (2)». При этом модуль выключен сознательно: в /etc/iot/credentials.ini стоит [ai] enabled = 0 (нет ключа нейросети), поэтому все карточки наблюдения выключены и точки не собираются. Это не поломка, но проверка этого не знала — и одинаковое письмо через неделю ушло бы в спам. Теперь проверка различает: если выключены и карточки, и нейросеть — печатается [SKIP] и счётчик ошибок не растёт. Общий итог: «ЗДОРОВ, ошибок 0», сторож молчит.

4. Что осталось на тебе

  1. Поменять батарейку в датчике протечки (ванная) — единственное срочное. CR2032, любая нормальная (энерджайзер, варта и подобные).
  2. Проверить кран SONOFF и датчик освещённости. Оба молчат 18 дней. Возможно, просто потеря связи или сдох элемент. Первым делом — нажать кнопку на устройстве: если проснётся и данные пойдут, дело было в связи; если нет — менять элемент (в кране 4 × AA).
  3. Уточнить число элементов у датчика присутствия. В справочнике стоит «AAA», количество не указано — это единственное место, где данные неполные. Посмотреть в корпусе при следующей замене и поправить строку.

5. Как этим пользоваться дальше

Изменить порог или добавить устройство

Через SSH на малину (или в любой консоли MySQL):
mysql iot_db -e "SELECT device, battery_type, cells, warn_v, dead_v FROM battery_spec ORDER BY sort_order;"
Правка одной строки:
mysql iot_db -e "UPDATE battery_spec SET warn_v=2.65 WHERE device='bedroom_sensor';"
Новое устройство — INSERT INTO battery_spec (device, title, battery_type, cells, nominal_v, warn_v, dead_v, has_voltage) VALUES (...). Важно: device — это friendly_name из zigbee2mqtt (то, что видно в панели), а has_voltage=1 только если устройство действительно отдаёт поле voltage в милливольтах.

Проверить вручную, не дожидаясь утра

# прогон проверки батареек (письмо уйдёт только если состояние изменилось)
/home/mazzick/check_battery.py

# полная проверка дома
/home/mazzick/healthcheck.sh

# состояние всех устройств прямо в консоли
php -r "require '/var/www/html/iot/config/iot_config.php'; require '/var/www/html/iot/public_html/include/battery_lib.php'; print_r(iot_battery_status(iot_pdo()));"

Где что лежит

ЧтоГде
Справочник элементов и пороговтаблица battery_spec в базе iot_db
Логика расчёта (одна на всех)/var/www/html/iot/public_html/include/battery_lib.php
Страница батареек/var/www/html/iot/public_html/admin/batteries.php
Карточка на главнойindex.php, блок перед вкладкой «Cron Задачи»
Ночная проверка с письмом/home/mazzick/check_battery.py + cron в 09:00
Память о прошлом письме/home/mazzick/.battery_state.json
Лог проверки/home/mazzick/battery_check.log
Бэкапы всех правок/home/mazzick/przorka_backup/battery_20260927/
Общая проверка дома/home/mazzick/healthcheck.sh (раздел 10 — батарейки)

Если что-то пошло не так — откат

Все исходные версии файлов сохранены до правок. Вернуть страницу главную:

cp /home/mazzick/przorka_backup/battery_20260927/index.php.orig /var/www/html/iot/public_html/index.php
cp /home/mazzick/przorka_backup/battery_20260927/links_panel.php.orig /var/www/html/iot/public_html/include/links_panel.php
cp /home/mazzick/przorka_backup/battery_20260927/check_battery.py.orig /home/mazzick/check_battery.py
cp /home/mazzick/przorka_backup/battery_20260927/healthcheck.sh.orig /home/mazzick/healthcheck.sh

Таблицы battery_spec и включённую историю можно убрать одной командой, панель от этого работать не перестанет:

mysql iot_db -e "DROP TABLE battery_spec;"
mysql iot_db -e "UPDATE sensor_info SET save_history=0 WHERE topic LIKE 'zigbee2mqtt/%/battery';"