Эта статья служит отправной точкой для понимания архитектуры моей локальной IoT-системы. Некоторое время проект был в состоянии «заморозки», и сейчас я постепенно восстанавливаю в памяти, как всё устроено — где лежат ключевые файлы, как они взаимодействуют и за что отвечают. Git, к сожалению, освоил не до конца, поэтому документация особенно актуальна.
В ближайшее время я планирую выложить все исходники и проставить внутренние ссылки, чтобы получилось хоть какое-то подобие структурированной документации. Код за время разработки заметно «распух», и без карты уже трудно разобраться.
Цель статьи — создать своего рода «дорожную карту» архитектуры: краткое описание основных компонентов, их назначения и связей между ними. Это поможет не только мне быстро вспомнить устройство системы спустя месяцы, но и может оказаться полезным для тех, кто ищет пример полностью локального IoT-решения для умного дома — без облачных сервисов, сторонних зависимостей и избыточной сложности.
Система лёгкая и ненасыщенная: она не требует ресурсов дата-центра и способна работать даже на таких скромных устройствах, как Raspberry Pi Zero или смарт-часы. Иными словами — функциональность без наворотов.
Основные компоненты системы
- MQTT-брокер — Mosquitto, принимает данные от датчиков (Zigbee2MQTT и др.)
- База данных — MySQL (база
iot_db)
- Серверная логика — PHP-скрипты
- Веб-интерфейс — главный файл
/index.php
- Автоматизация — правила, триггеры и расписания, хранимые в БД
- Мониторинг Raspberry Pi — сбор системных метрик (температура, CPU, диск и т.д.)
- Графики — Chart.js + API для получения исторических данных
Ключевые файлы проекта
/index.php — основной веб-интерфейс
Это главная страница системы. Он:
- Подключается к БД
iot_db.
- Забирает последние значения датчиков из таблицы
sensor_data.
- Читает информацию о датчиках из таблицы
sensor_info (название, комната, иконка и т.д.).
- Получает активные автоматизации из таблицы
automations:
- Запланированные (daily/weekly)
- Триггерные (по условию с топика)
- Анализирует исторические данные из
sensor_history на предмет резких изменений (температура, напряжение, батарейка).
- Считывает последнее состояние Raspberry Pi из таблицы rpi_monitor.
- Проверяет статус системных сервисов через
systemctl.
- Формирует HTML-страницу с карточками, кнопками управления, графиками и статусами.
- Использует JavaScript для:
- Автоматического обновления страницы каждые 30 секунд.
- Отправки команд в MQTT через /admin/send_mqtt.php.
- Отрисовки графиков с помощью Chart.js, получая данные из ">/api/history.php.
- Сворачивания/разворачивания групп датчиков.
Принимает GET-параметры topic и payload, формирует MQTT-сообщение и отправляет его через mosquitto_pub. Используется кнопками «ВКЛ/ВЫКЛ» из index.php.
Возвращает JSON с историей значений конкретного топика из таблицы sensor_history. Используется Chart.js в index.php для отрисовки графиков.
Daemon-скрипт (запускается как mqtt-to-mysql.service). Подписывается на все топики, получает сообщения от датчиков и записывает их в:
sensor_data — текущее значение (обновляется)
sensor_history — архив всех значений с метками времени
Запускается по cron каждую минуту (или как iot-automation.service). Проверяет:
- Наступило ли время для запланированных задач (daily/weekly)
- Выполняются ли условия триггерных правил (сравнивает последние значения из
sensor_data с условиями)
- Если да — отправляет команды в MQTT через /admin/send_mqtt.php или напрямую
- Логирует срабатывания и ошибки в БД (
last_triggered, failure_count)
Запускается по cron. Собирает:
- температуру CPU
- загрузку CPU
- использование памяти и диска
- напряжение ядра
- IP-адреса и uptime
Результаты отправляются в MQTT и сохраняются в таблицу rpi_monitor.
Раз в час анализирует системные или прикладные логи, ищет ключевые слова (ошибки, перезагрузки и т.д.), агрегирует счётчики и сохраняет в таблицу log_stats.
Структура базы данных (iot_db)
sensor_data — актуальные значения датчиков (topic, value, timestamp)
sensor_history — архив значений (для анализа и графиков)
sensor_info — метаданные: имя, комната, группа, иконка
automations — правила автоматизации (расписание, триггеры, действия)
rpi_monitor — системные метрики Raspberry Pi
log_stats — статистика по ключевым словам в логах
daily_resets — флаги сброса ежедневных задач (чтобы не запускать дважды)
Как работает управление устройствами
Когда пользователь нажимает «ВКЛ» на карточке клапана:
- JavaScript в
index.php формирует MQTT-топик замены: /status → /set
- Отправляется GET-запрос к
/admin/send_mqtt.php?topic=...&payload=...
- Скрипт публикует команду в MQTT
- Устройство (например, Zigbee-клапан) получает команду и меняет состояние
- Новое состояние публикуется обратно в MQTT → попадает в БД → обновляется в интерфейсе (через автообновление страницы)
Папки проекта
/admin
Содержит административные скрипты и файлы, доступные только авторизованным пользователям.
- logic.php — основная логика для обработки запросов.
- logout.php — выход из системы.
send_mqtt.php — отправка команд в MQTT (уже описан выше).
- sensors.php — работа с датчиками, возможно, для управления их настройками.
- Скрипт mqtt_listener.php сервис автоматизации iot-automation.service
/api
Содержит API-эндпоинты, используемые веб-интерфейсом.
control.php — вероятно, API для управления устройствами (не используется в основном index.php).
history.php — API для получения истории значений (уже описан выше).
- live_data.php — API для получения актуальных данных в реальном времени (используется в
index.php для обновления данных без перезагрузки страницы).
/css
Содержит CSS-стили для веб-интерфейса.
style.css — основной файл стилей.
/scripts
Содержит фоновые скрипты, запускаемые по cron или как systemd-сервисы.
- mqtt-to-mysql — слушатель MQTT (уже описан выше). Этот скрипт на Python служит мостом между MQTT-брокером и базой данных MySQL в системе Интернета вещей (IoT). Он автоматически получает телеметрию с датчиков и устройств (например, через Zigbee2MQTT), обрабатывает её и сохраняет в две таблицы MySQL: основную и историческую.
iot-automation.php — движок автоматизации (уже описан выше).
- rpi-monitor.sh — сбор системных метрик (уже описан выше).
- log-analyzer.sh — парсинг логов (уже описан выше).
🔌 Как добавить новое Zigbee-устройство в домашнюю IoT-систему
Когда вы подключаете новое Zigbee-устройство (розетку, реле, датчик и т.д.) через Zigbee2MQTT,
важно убедиться, что оно не только сопряглось, но и корректно передаёт данные в вашу систему.
Ниже — проверенный рабочий алгоритм от сопряжения до отображения на панели.
1. Сопряжение устройства
- Зайдите в веб-интерфейс Zigbee2MQTT (обычно
http://ваш_сервер:8080).
- Нажмите «Add new device» и следуйте инструкциям для вашего устройства (часто — удержание кнопки при подаче питания).
- После сопряжения устройству присвоится MAC-адрес вида
0xa4c1385d1ba39457.
2. Задайте понятное имя
Откройте файл конфигурации Zigbee2MQTT — обычно /opt/zigbee2mqtt/data/configuration.yaml — и добавьте:
devices:
'0xa4c1385d1ba39457':
friendly_name: fish_light
Перезапустите службу: sudo systemctl restart zigbee2mqtt.
3. Проверьте MQTT-трафик в реальном времени
Выполните в терминале:
mosquitto_sub -h localhost -t "zigbee2mqtt/#" -v
Теперь включите/выключите устройство. Вы должны увидеть сообщения вида:
zigbee2mqtt/fish_light {"state_l1":"OFF","state_l2":"OFF","state_l3":"OFF","linkquality":210}
Если JSON содержит нужные поля (state, temperature, state_l1 и т.д.) — устройство работает.
4. Убедитесь, что данные сохраняются в базу
Ваш логгер (например, mqtt-to-mysql.py) должен «разворачивать» JSON и сохранять каждое поле отдельно:
zigbee2mqtt/fish_light/state_l1 → OFF
zigbee2mqtt/fish_light/state_l2 → OFF
Проверьте в MySQL:
SELECT topic, value FROM sensor_data
WHERE topic LIKE '%fish_light%'
ORDER BY timestamp DESC LIMIT 5;
Если записей нет — обновите логгер, чтобы он сохранял все ключи, кроме служебных (linkquality, last_seen и т.д.).
5. Добавьте устройство на панель
Выполните в базе данных:
INSERT INTO sensor_info (topic, name, room, group_name, icon) VALUES
('zigbee2mqtt/fish_light/state_l1', 'Кормушка 1', 'Аквариум', 'Реле', '🔌'),
('zigbee2mqtt/fish_light/state_l2', 'Кормушка 2', 'Аквариум', 'Реле', '🔌'),
('zigbee2mqtt/fish_light/state_l3', 'Кормушка 3', 'Аквариум', 'Реле', '🔌');
6. Настройте управление
Убедитесь, что ваша панель распознаёт state_l1 как управляемый переключатель. В PHP-коде должно быть:
$type = basename($row['topic']);
if ($type === 'status' || preg_match('/^state_l\d+$/', $type)) {
$type = 'valve';
}
А в JS-функции отправки команды — корректная обработка каналов:
// Пример для топика zigbee2mqtt/fish_light/state_l1
const match = decodedTopic.match(/^(zigbee2mqtt\/[^\/]+)\/state_(l\d+)$/);
if (match) {
payload[match[2]] = command; // → {"l1": "ON"}
}
💡 Советы
- Если устройство не публикует
state_l1, а только status — используйте общий режим управления через {"state": "ON"}.
- Не забудьте обновить автоматизации: старые правила с MAC-адресом перестанут работать после смены имени.
- Регулярно очищайте таблицу
sensor_data — иначе сайт начнёт тормозить. Достаточно оставлять данные за последние 3–7 дней.
После этих шагов ваше устройство будет полноценно интегрировано в систему: вы сможете управлять им с панели,
строить графики и создавать автоматизации.
Комментарии
Пока нет комментариев. Будьте первым!