Категории
Умный дом на Raspberry Pi: разложили 123 датчика по полкам
28.10.2026 | из категории: IOT умный дом
Домашняя автоматизация на zigbee2mqtt, Mosquitto, MariaDB и самописной PHP-панели доросла до состояния, когда в интерфейсе стало невозможно найти нужный датчик. Рассказываю, как из одной простыни карточек получились группы, что именно пришлось менять в коде и почему это не «косметика», а вопрос удобства эксплуатации.
1. Что было не так
Система собиралась годами, и в базе накопилось 123 разных MQTT-топика. Панель честно показывала их все — сеткой карточек, одну за другой. Проблема не в том, что карточек много, а в том, что большинство из них — не датчики.
zigbee2mqtt с настройкой output: json публикует одно сообщение на устройство,
а логгер раскладывает JSON на поля: temperature, humidity,
battery, но вместе с ними — linkquality, indicator_mode,
power_on_behavior, калибровки, режимы, интервалы опроса и даже сами команды
.../set. В справочнике это всё выглядело как равноправные «датчики».
Второй слой той же проблемы — правила автоматизации. Их 18, и они лежали точно так же: списком, где «Нагрев_РЫБ_вкл», «земляника подсветка вкл 8:00» и «Защита от заливания» стоят подряд. Найти нужное правило, чтобы поправить порог, — это чтение всего списка глазами.
2. Датчики: группы и «Служебные»
Страница датчиков (/admin/sensors.php) теперь состоит из сворачиваемых групп:
- Аквариум — нагрев, свет, реле;
- Растения — горшки, влажность почвы, подсветка земляники;
- Полив — садовый кран, кран SONOFF, состояние;
- Климат — спальня, качество воздуха, CO₂, ЛОС;
- Свет — присутствие, освещённость, реле коридора;
- Безопасность — протечка, вибрация/дверь;
- Розетки — умные розетки;
- Служебные — те самые 63 технических топика. Скрыты по умолчанию.
Каждая группа — обычный <details> со счётчиком датчиков. Состояние
«свернуто/развёрнуто» запоминается в браузере, так что при следующем заходе страница выглядит
так, как её оставили. Есть кнопки «Раскрыть все / Свернуть все» и поиск по имени, комнате или
топику — при поиске нужные группы раскрываются сами.
Возраст значения в карточке
К каждой карточке добавилось последнее значение и когда оно пришло: «23.4 · 5 мин назад», «— · 18 дн назад». Это закрывает старую ловушку самописных систем: строка в таблице последних значений живёт вечно, поэтому устройство, которое молчит неделю, в интерфейсе выглядит бодрым. Теперь молчание видно сразу, и это повод проверить связь, а не менять батарейку наугад.
3. Правила: группы и счётчики
В таблицу automations добавилась колонка group_name. Правила
разложены по группам, у каждой в заголовке — счётчик вида «✅ 6 / ❌ 0»: сколько включено и
сколько выключено. Выключенные правила в самописных системах копятся и забываются, а теперь
они видны в своей группе, а не растворяются в общем списке.
| Группа правил | Правил | Что внутри |
|---|---|---|
| Аквариум | 6 | нагрев по температуре, свет аквариума по расписанию |
| Свет | 4 | коридор по движению, выключение через 60 с, подсветка земляники |
| Полив | 3 | полив по влажности почвы, страховка от заливания |
| Климат | 2 | тревоги по PM2.5 и ЛОС с письмом |
| Безопасность | 1 | протечка в ванной — включить свет |
| Тесты | 2 | старые черновики, выключены |
В форме правила появилось поле «Группа правила» с подсказками. Сохранение проверил живьём: создал правило с группой, перенёс в другую группу, удалил — всё отработало, в базе снова 18 правил.
4. Как это устроено внутри
Группа датчика не задаётся вручную для 123 топиков
Прописывать группу каждому топику — это работа на вечер и вечная поддержка. Логика получилась трёхступенчатая:
- поле «Группа» в справочнике датчиков (если заполнено — оно главное);
- иначе — группа любого другого поля того же устройства: поставил группу батарейке датчика, и все поля этого устройства переехали туда же;
- иначе — комната из справочника, и только потом «Без группы» (эта секция всегда внизу).
Отдельно решается судьба технических топиков: функция iot_is_service() считает
служебными полный JSON устройства (тема без третьего сегмента), всё, что содержит
/set, и перечисленные поля вроде linkquality или калибровок.
Важная деталь: state в этот список не входит — у реле и розетки это главное
значение, а не мусор.
$devFallback, а имена вида
zigbee2mqtt/0x… автоматически относятся к «Розеткам».
Сворачивание без JavaScript-библиотек
Основа — нативный <details>/<summary>: свёрнутость работает даже если
скрипты не загрузились. JavaScript добавляет только две вещи: запоминание состояния в
localStorage и фильтрацию карточек по подстроке.
<details class="sensor-group" data-group="Аквариум" open>
<summary>📁 Аквариум <span>9</span></summary>
<div class="sensors-grid">…карточки…</div>
</details>
Миграция базы
Колонку добавлял администратор базы, а не приложение: у прикладной учётки нет права
ALTER — и это правильно. Перед изменением снят дамп таблицы правил, чтобы откат был
не «по памяти», а по файлу.
ALTER TABLE automations
ADD COLUMN group_name VARCHAR(64) NULL DEFAULT NULL AFTER name;
UPDATE automations SET group_name='Аквариум' WHERE id IN (151,152,170,171,196,197);
-- и так далее по группам
5. Чем проверяли
Правки в работающей системе проверяются не «на глаз», а гейтами:
php -lна оба изменённых файла — синтаксис чист;- страницы отдают 200 с настоящей сессией, в HTML нет
Fatal error; - на странице датчиков — 8 секций групп, на странице правил — 6;
- все шесть служб (
iot-automation,mqtt-to-mysql,mosquitto,zigbee2mqtt,mariadb,nginx) в состоянииactive; - создание/изменение/удаление правила с группой — через живые POST-запросы панели;
- бэкап исходных файлов и дамп таблиц — до правок, в отдельном каталоге.
6. Что осталось
- Мобильная вёрстка групп. На узком экране счётчики в заголовках могут переноситься — надо посмотреть на телефоне.
- Названия групп. Разбивка сделана по смыслу устройств; если захочется делить по комнатам — это одна колонка и один запрос.
- Сведение cron-автоматики в движок. Часть логики (кормушка, нагрев, свет) до сих пор живёт в отдельных cron-скриптах, то есть в двух местах. Это следующий архитектурный шаг: одно место для правил проще отлаживать.
project.html рядом с этой статьёй.
iot-smart-home-2026-10-28.zip (полный архив проекта 28.10.2026) ссылка действует до 07.2027