Умный дом давно перебрался из выставочных стендов в обычные квартиры: датчики климата, реле, термостаты и умные розетки продаются в любом магазине электроники. Владелец дома хочет не крутить настройки, а одним взглядом понимать, что происходит дома: какая температура в детской, не пересохла ли рассада на балконе, работает ли обогрев гаража. Дашборд в браузере закрывает эту потребность без установки приложений: страница открывается на планшете у входа или на телефоне в отъезде, и картина дома всегда под рукой.

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

Путь телеметрии от радиодатчика до браузерной страницы по цепочке звеньев

Типичный температурный датчик не умеет говорить с браузером напрямую: у него батарейка, радио и экономия каждого джоуля. Путь показаний всегда многоступенчатый: датчик шлёт значения по радио Zigbee или Wi-Fi, шлюз публикует их брокеру MQTT, сервер подписан на нужные топики и раздаёт браузеру по WebSocket. За каждым звеном стоит своя логика: Zigbee держит батарейные датчики годами на одном элементе питания, Wi-Fi берёт скорость и вычислительную мощь у домашней розетки, а прошивка ESPHome оживляет дешёвые платы ESP32 и ESP8266, и те публикуют телеметрию сразу в MQTT, минуя лишних посредников. Платформа Zigbee2MQTT переводит радиосеть Zigbee на язык топиков брокера и поддерживает тысячи моделей устройств, поэтому редкий датчик остаётся за бортом. Устройства на розеточном питании с прошивкой Tasmota умеют то же самое без шлюза вообще. Главное правило звучит просто: браузер никогда не лезет в радио напрямую, он всегда читает уже собранную и опубликованную телеметрию. Выбор между локальным и облачным контуром висит на шлюзе: локальный не зависит от провайдера, облачный удобнее для доступа, зрелая схема держит локальный контур основным, а наружу выпускает только читателя.

Шлюз в этой цепочке не просто переводчик с радио на брокер. Он держит сеть устройств, хранит их состояние и переживает пропажу интернета: автоматика продолжает работать, даже когда страница недоступна. За автономность шлюза и платят, потому что умный дом, засыпающий вместе с роутером провайдера, умным не считается.

MQTT топики QoS и завещание брокера как язык общения устройств и сайта

MQTT это протокол публикации и подписки с брокером в центре. Устройства публикуют сообщения в топики, пути со слешами вроде home/livingroom/temperature, а сервер дашборда подписывается на нужные маски, например home/+/temperature, где плюс подменяет один уровень. Гарантии передачи регулируются уровнями QoS: нулевой шлёт сообщение не более одного раза и годится для потока телеметрии, первый доставляет минимум один раз и уместен для команд переключения, второй гарантирует ровно одну передачу и почти не нужен в доме. Флаг retain велит брокеру хранить последнее сообщение топика и сразу выдавать его новому подписчику, поэтому плитка показывает значение сразу после загрузки, а не ждёт следующего цикла датчика. Особый подарок это завещание, Last Will: клиент при подключении оставляет сообщение на случай внезапной потери связи, и брокер публикует его сам, благодаря чему дашборд честно показывает датчик оффлайн, а не зависшее старое значение.

Схема топиков заслуживает проектирования заранее. Рабочий порядок такой: по каждому устройству два топика, state для фактического состояния и set для команд, а слева направо читается иерархия: home, комната, тип, имя устройства. Полезная нагрузка в JSON с полем времени и значением читается и людьми, и машинами, а единая схема делает дашборд предсказуемым: новая лампочка в детской ложится на плитку без новой строки кода, маска подписки уже накрывает её путь.

Подключение из браузера идёт по WebSocket поверх TLS, у брокера Mosquitto для этого отдельный слушатель, обычно на порту 9001:

import mqtt from "mqtt";

const client = mqtt.connect("wss://broker.example.net:9001", {
  username: "dash",
  password: "w7xQp2m",
  reconnectPeriod: 2000
});

client.subscribe("home/+/temperature");

client.on("message", (topic, payload) => {
  updateTile(topic, JSON.parse(payload.toString()));
});

WebSocket и SSE против опроса в передаче живых показаний на дашборд

Способов доставить значение в браузер три, и у каждого свой характер. Опрос по таймеру это запрос раз в несколько секунд: просто, но баланс между мусорным трафиком и свежестью не сходится, а между опросами плитка молча врёт старым значением. Server-Sent Events держат однонаправленный канал от сервера: браузерный EventSource подключается одной строкой, сервер лишь толкает события, а переподключение встроено в сам API. WebSocket это полный дуплекс: сервер шлёт телеметрию, страница отдаёт команды, один канал закрывает все потребности. Практичная гибридная схема: поток измерений идёт через MQTT поверх WebSocket или через SSE, команды управления через тот же канал в обратную сторону. Переподключение обязательно с экспоненциальной паузой, иначе тысяча открытых страниц после сбоя сети ударит по брокеру одновременно и положит его на полминуты. И маленькая вежливость к батареям: когда вкладка не видна, поток разумно притормозить до всплытия, невидимому дашборду свежие цифры не нужны.

Экономия байтов здесь не жадность, а гигиена. Сообщение с одной температурой в JSON весит десятки байтов, поток десятка датчиков с минутным интервалом скромен, но при открытии страницы каждая крупица ложится на канал. Разумно обновлять только изменившиеся плитки, слать дельту, а не весь массив, и держать графики ленивыми, чтобы экран с двумя сотнями плиток не дёргался целиком из-за одного датчика.

Хранение истории измерений и агрегация рядов для графиков без тормозов

Для графиков нужен склад истории, и обычная реляционная таблица с наивным индексом быстро выдыхается на миллионах точек. Специализированные хранилища рядов решают это из коробки: TimescaleDB расширяет PostgreSQL гипертаблицами с автосегментацией по времени, InfluxDB держит собственную модель измерений, и обе умеют сжимать старое и подчищать его политиками хранения. Правило агрегации продиктовано здравым смыслом: сырые точки за последний день, пятиминутные средние за неделю, часовые за год, и запрос на длинном диапазоне трогает тысячи строк вместо миллионов.

Цена вопроса смешная: год показаний десяти датчиков с минутным интервалом это около пяти миллионов точек, единицы гигабайт даже без сжатия, а политики хранения и компрессия урезают объём в разы. Дороже обходится отсутствие истории: без неё нет ни графиков, ни понимания, сколько реально работал обогрев, ни честной стрелки тренда. Два самых частых запроса это последнее значение и час спарклайна, оба обязаны отвечать за миллисекунды, поэтому индексы по времени и устройству закладывают сразу.

В TimescaleDB агрегация выглядит так:

SELECT time_bucket('5 minutes', ts) AS bucket,
       avg(temperature) AS t
FROM readings
WHERE device = 'livingroom'
  AND ts > now() - interval '7 days'
GROUP BY bucket
ORDER BY bucket;

Для отрисовки хватает зрелых библиотек вроде Chart.js и Apache ECharts, а спарклайны на плитках разумно рисовать на SVG вообще без зависимостей: двадцать точек линии не заслуживают мегабайта графики.

Содержание плиток дашборда от текущего значения до стрелки тренда и нормы

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

Отдельный слой содержания это оповещения. Значение вне нормы дольше получаса должно само найти владельца, а не ждать его визита на страницу: уведомление о протечке теряет смысл к утру. Отсюда дополнительный вопрос к содержанию: что должно случиться, когда значение уйдёт из нормы. А над всеми плитками держится сводка по дому одной строкой, всё ли зелёное и где отклонение, чтобы заходить глубже только по необходимости.

Управление устройствами с мгновенным откликом и честным откатом при таймауте

Нажатие должно ощущаться мгновенным, и у интерфейсов есть старое правило: реакция до десятой доли секунды воспринимается как отклик, до секунды как заметная задержка. Радио, брокер и устройство в цепочку не всегда успевают за сотню миллисекунд, поэтому честнее схема optimistic UI: плитка перекрашивается сразу в момент клика, команда уходит с QoS 1, а сервер слушает state-топик устройства и сверяет фактическое состояние. Если за три секунды подтверждение не пришло, интерфейс откатывает плитку и сообщает о проблеме, вместо фантомного включения. Команды лучше посылать целевым состоянием on и off, а не переключением: повторная передача тогда не выключит свет, который только что включили, и идемпотентность спасает ровно там, где радио теряет пакеты.

async function setRelay(deviceId, target) {
  const tile = optimisticFlip(deviceId, target);
  client.publish(`home/${deviceId}/set`, target, { qos: 1 });
  const confirmed = await waitForState(deviceId, target, 3000);
  if (!confirmed) rollbackTile(tile);
}

Когда управлением пользуются несколько человек, побеждает не тот, кто нажал последним, а правда из state-топика: устройство само подтверждает финальное состояние, и две одновременные команды не оставляют на плитке спорный результат. Права полезно расслоить: гостевой профиль с чтением без кнопок, детский с замком на опасных реле, полный доступ только владельцу. Простая мера экономит больше нервов, чем любой красивый график.

Готовые платформы и свой код Home Assistant Node-RED Grafana и ESPHome

Собирать всё с нуля не обязательно, и чаще всего не нужно. Home Assistant собирает сотни интеграций и позволяет сложить дашборд из карточек мышкой, разумный старт, когда важна скорость. Node-RED хорош для потоков автоматизации и простых панелей, Grafana заточена на ряды и панели графиков, ESPHome закрывает потребность в собственных датчиках на ESP32 с прошивкой из пары строк YAML. Свой код оправдан, когда нужен интерфейс с собственным брендом, нестандартная логика или встраивание панели в продукт, и в этом случае стек из MQTT.js, TimescaleDB и любого фронтенд-фреймворка собирается за пару недель.

Безопасность в этой архитектуре держится на трёх китах: TLS на каждом звене, авторизация на брокере со списками прав по учёткам и закрытый наружный контур. Брокер, торчащий в публичную сеть без надобности, это приглашение к плохим экспериментам, а локальный контур с контролируемым наружным доступом сохраняет и приватность, и управление из отъезда. Отдельные учётки для сервера дашборда и для каждого устройства дают точечное отключение без остановки всей системы.

Путь внедрения одинаков для любого выбора:

  1. вывести все датчики в единый брокер MQTT с понятной схемой топиков;
  2. поднять канал в браузер, WebSocket или SSE, с переподключением и паузами;
  3. собрать склад истории на TimescaleDB или InfluxDB с политиками хранения;
  4. описать плитки по комнатам и типам, добавив нормы и время последнего обновления;
  5. повесить команды на MQTT с QoS 1 и optimistic UI с откатом;
  6. закрыть канал TLS и авторизацией, добавить гостевой режим только для чтения;
  7. настроить агрегацию рядов и проверить графики на годовом диапазоне.

Хороший дашборд умного дома это не максимум цифр, а быстрый ответ на один вопрос: всё ли дома в порядке. Цепочка радиосигнал, брокер, канал, график стала скучной и предсказуемой, и именно эта скучность делает её надёжной: каждый протокол на своём месте, каждая плитка отвечает на свой вопрос, а человек получает картину дома за один взгляд. И если однажды плитка сообщит о протечке раньше, чем вода дойдёт до ноутбука, вся цепочка окупится целиком.