InfluxDB в Home Assistant (Часть 1)

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

  1. Подключение InfluxDB как аддона для hassio, использование Grafana для визуализации данных, встраивание графиков в карточки Lovelace (эта заметка)
  2. Использование Telegraf для сбора произвольных метрик (например, загрузка процессора и использование памяти каждым из контейнеров Hass.io или температура жёстких дисков в RAID массиве), а также долговременное хранение собранных данных, эффективное с точки зрения занимаемого дискового пространства
  3. Централизованный сбор и просмотр логов со всех контейнеров Hass.io, а также любого из устройств умного дома, поддерживающего протокол syslog (включая ESP** устройства с прошивками Tasmota и ESPEasy на борту). А также автоматическое определение аномалий с отправкой нотификаций (например, о повторяющихся ошибках).

Преимущества InfluxDB

  • Скромные требования к процессору и памяти по сравнению, например, с Elastic Search
  • Позволяет хранить исторические данные сколь угодно долго, при этом быстро их возвращать с помощью т.н. continuous queries (о них будет отдельная статья). В SQLite базе данных Home Assistant увеличение числа дней для хранения данных может привести к плачевному результату с точки зрения производительности
  • Позволяет подключить Grafana для вывода красивых графиков, а также имеет “встроенный” dashboard под названием Chronograf
  • С помощью родного “агента” telegraf (микроскопическая и очень шустрая программа на языке Go) можно собирать в InfluxDB метрики буквально со всего, что движется с помощью огромного списка плагинов
  • Имеет “встроенный” сервис Capacitor для определения аномалий, позволяющий мониторить данные и отправлять алерты в случае чрезвычайных ситуаций, в том числе через MQTT

InfluxDB - достаточно зрелая TimeSeries база данных, появившаяся на свет где-то в 2013 году. TimeSeries означает, что она оптимизирована для хранения данных, привязанных ко времени. Например, нагрузки процессора, пропускной способности сети, температуры жесткого диска или объёма свободной памяти. Написанная на современном языке Go, InfluxDB способна обрабатывать огромное количество данных при весьма скромных аппетитах к процессору и памяти. Я долгое время эксплуатировал её на 512Мб дроплете, на котором в других контейнерах крутилось ещё несколько сервисов без всяких проблем. В то же время, попытка установить ElasticSearch закончилась фиаско - в течение считанных минут вся память была забита и всё на дроплете стало еле-еле ворочаться. Да, кто-то возразит, что Эластику можно урезать аппетиты настройками виртуальной машины Java, но факт остаётся фактом - память оно любит.

Немного скучной теории - терминология InfluxDB

Если вы собираетесь доверить свои данные InfluxDB, имеет смысл освоить хотя бы базовую терминологию. Полный список понятий и определений можно найти на сайте InfluxDB, мы же остановимся только на тех, с которыми так или иначе придётся столкнуться при формировании запросов и рисовании графиков. Рассматривать базовые понятия будем на примере данных от датчика температуры под названием sensor.bedroom_temperature.

Timestamp domain entity_id friendly_name_str value
2019-01-09T21:19:00.314567936Z sensor bedroom_temperature Bedroom Temperature 20.5
2019-01-09T21:20:00.332456192Z sensor bedroom_temperature Bedroom Temperature 20.4
2019-01-09T21:23:00.390132992Z sensor bedroom_temperature Bedroom Temperature 20.3
2019-01-09T21:25:00.430054912Z sensor bedroom_temperature Bedroom Temperature 20.4
2019-01-09T21:28:00.485129984Z sensor bedroom_temperature Bedroom Temperature 20.3

Retention Policy

Правила, определяющие длительность хранения данных в базе (например, 7 дней или бесконечно), а также несколько других не интересных нам параметров, влияющих на конфигурацию кластера. К каждой базе данных по умолчанию создаётся retention policy под названием autogen. Причём в интерфейсе Capacitor и в запросах InfluxQL название базы данных почти всегда включает в себя retention policy, отделённую точкой, например: home_assistant.autogen.

Database

База данных, схожа с таковыми в реляционных БД. База данных содержит данные наших сенсоров, а также подчиняется Retention Policy, заданной при её создании. В InfluxDB может быть произвольное количество баз данных. По умолчанию, компонент InfluxDB в Home Assistant использует базу под названием home_assistant.

Timestamp

Временная метка, то есть время получения данных. Все данные в InfluxDB привязаны ко времени, поэтому она называется Time Series база данных. Timestamp-ы всегда сохраняются в UTC и переводятся в локальное время в зависимости от часового пояса клиентского устройства.

Field

Любая пара ключ:значение, хранящая данные ваших сенсоров. В таблице выше, “полями“ являются value и friendly_name_str. Любое “поле” также включает Timestamp.

Tag

Тэгами в примере выше являются domain и entity_id. Тэги - это текстовые поля, принимающие ограниченный набор значений. Являются опциональными, одно из применений - возможность оптимизировать запросы по тегу на основе заранее построенных индексов, т.е. выборка по тегу работает очень быстро на любом объёме данных.

Measurement

Measurement - это способ разделять внутри базы данных наборы тэгов, полей и временных меток. Звучит сложно, но по сути measurements позволяют иметь базу внутри базы со своим названием. Например, можно завести measurement для температуры, для влажности, measurement для показаний электроэнергии и т.п. Каждый measurement может быть связан с одной или несколькими Retention Policy.

По умолчанию компонент InfluxDB для home_assistant создаёт measurements для каждой из единиц измерения, в которых возвращают данные датчики. Это поведение может быть переопределено с помощью параметра конфигурации override_measurement (см. раздел Конфигурация компонента).

Посмотрим, какие measurements сейчас есть в моей БД home_assistant:

> show measurements
name: measurements
name
----
binary
downsampled_temp
energy
humidity
temperature
state

Видим, что компонент создал несколько measurements - для показаний температуры и влажности и одно под названием state для сущностей без единиц измерений (например, выключателей). Группировка данных сущностей без единиц измерения в measurement state достигается установкой параметра default_measurement в конфигурации компонента InfluxDB (см. раздел Конфигурация компонента).

Одно из полезных применений measurements - разделение данных по времени хранения или по интервалу выборки. Данные для долгосрочного хранения, усреднённые по часовому интервалу, занимают в 60 раз меньше места, чем данные, сохраняемые каждую минуту. Долговременному хранению данных будет посвящена вторая часть данного опуса.

Установка и первоначальная настройка

Самый простой и безболезненный вариант установки InfluxDB для Home Assistant - комьюнити аддон для Hass.io. Для сильных духом можно попробовать ручную установку InfluxDB, например, на RaspberryPi, при этом придётся искать соответствующую версию для архитектуры ARM, даже если мы устанавливаем её в Docker конейнер. В то же время авторы аддона уже позаботились об этом и в случае установки как часть Hass.io будет выбрана и установлена нужная версия контейнера.

Мы будем рассматривать установку и настройку InfluxDB только в виде аддона для hassio. Отчаянные парни, сознательно выбравшие установку HA в контейнер или в окружение virtualenv, достаточно продвинуты, чтобы самостоятельно установить InfluxDB в отдельный docker контейнер по вкусу или следовать инструкции по установке, доступной на официальном сайте.

Установка аддона

Для установки аддона открываем hassio, закладка ADD ON STORE, убеждаемся, что в списке аддонов присутствует раздел Community Hass.io Add-ons.

1547064517965

Если его нет, в поле Add new repository by URL добавляем адрес: https://github.com/hassio-addons/repository и нажимаем “Сохранить”. Находим и устанавливаем интересующий нас аддон InfluxDB:

1547064679886

После того, как аддон установлен, нужно модифицировать его конфигурацию следующим образом и перезапустить:

{
  "log_level": "error",
  "auth": true,
  "reporting": false,
  "ssl": false,
  "certfile": "",
  "keyfile": ""
}

Благодаря технологии Ingress, появившейся в Home Asisstant версии 0.91.3, внедрение аддонов в боковую панель больше не требует танцев с файлами конфигурации и защитой портов - все делается одним переключателем в конфигурации аддона Show in sidebar. Эта супертехнология также освобождает нас от необходимости вводить логин/пароль для аддонов, которые поддерживают Ingress.

1547065321806

Создание базы данных и пользователя

Для работы плагина нужно создать пользователя InfluxDB. Открываем веб-интерфейс InfluxDB (Chronograf). В левом меню выбираем InfluxDB Admin->Users->Create user, назовём его homeassistant, после создания указываем Permissions: ALL.

1547065949785

Далее создадим базу данных. По умолчанию, компонент InfluxDB в Home Assistant использует имя базы данных home_assistant, если название по какой-то причине не подходит, его можно переопределить в configuration.yaml. Переходим на вкладку Databases и создаём нашу БД:

1547066100779

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

Теперь настало время активации компонента InfluxDB в Home Assistant:

Конфигурация Home Assistant

influxdb:
  username: homeassistant
  password: !secret influxdb_password
  max_retries: 3
  default_measurement: state
  include:
    entities:
      - sensor.bedroom_humidity
      - sensor.bedroom_temperature

В секции include можно указать, какие объекты мы хотим сохранять в базе данных. Более подробно конфигурация компонента описана здесь: https://www.home-assistant.io/components/influxdb/

Параметр default_measurement: здесь можно указать название measurement, в который будут сохраняться данные сущностей, не имеющих единиц измерения. Как например, выключателей.

Параметр override_measurement: данные всех сущностей Home Assistant будут сохраняться в единственный measurement. Если вы часто делаете запросы вручную, может быть удобнее использовать имя вроде temperature вместо °C.

Называем measurements правильно

Оно мне нужно?

Данный тюнинг опционален, если вы не планируете писать Continuous Queries, про которые речь пойдёт во второй части, а будете пользоваться исключительно визуальными конструкторами запросов Grafana или Capacitor. Если же вы планируете хотя бы одним глазом взглянуть на то, что это такое и какие преимущества даёт, имеет смысл сразу сделать всё правильно.

В чём проблема?

По умолчанию каждый measurement в InfluxDB получает имя по названию единицы измерения сенсора в Home Assistant. Например, показания влажности будут попадать в measurement по названием %, показания температуры - в measurement с именем °C и т.п. Мне это кажется жутко неудобным по нескольким причинам:

  • при ручном написании запроса в InfluxDB нужно откуда-то копировать символ градуса, специальные символы вроде % экранировать кавычками, чтобы парсер не считал их ошибкой
  • данные с одинаковыми единицами измерения, но разным смыслом попадают в один measurement. Например, показания влажности и заряд батареи сенсора в процентах
  • данные сущностей без единиц измерения (счётчики, переключатели и пр.) складываются либо в measurement по названию сущности, либо в общий measurement, определённый конфигурационным параметром default_measurement.

К счастью, названия measurements можно переопределить как для отдельной сущности типа конкретного сенсора со своим ID, так и для доменов вроде sensor и даже глобально для всех сущностей Home Assistant. Документация компонента InfluxDB скупо упоминает, что это можно сделать, но не даёт никаких примеров использования. К счастью, PR на гитхабе содержит достаточно информации, чтобы поэкспериментировать и понять как этого достичь.

В примере ниже мы назначаем measurement с именем литры (lt) для конкретной сущности - счётчика counter.hotw. За это отвечает секция component_config. Также мы предписываем InfluxDB сохранять показания всех сенсоров, ID которых заканчивается на temperature в одноимённый measurement, аналогично поступаем с сенсорами влажности. Глобальные кастомизации описываются в секции component_config_glob.

Для нашего примера конфигурация компонента InfluxDB будет выглядеть так:

influxdb:
  username: hass
  password: !secret influxdb_password
  max_retries: 3
  default_measurement: state
  include:
    entities:
      - sensor.bedroom_humidity
      - sensor.bedroom_temperature
  component_config:
    counter.hotw:
      override_measurement: lt
  component_config_glob:
    sensor.*humidity:
      override_measurement: humidity
    sensor.*temperature:
      override_measurement: temperature

Проверяем данные в InfluxDB

После того, как конфигурация была сохранена и Home Assistant перезагружен, имеет смысл заглянуть в логи самого HA, чтобы убедиться, что компонент InfluxDB подключился и работает как надо.

Если ошибок нет, откроем веб-интерфейс InfluxDB и перейдём на закладку Explore. В списке баз данных слева внизу выберем нашу home_assistant.autogen. Как уже говорилось раньше, autogen - это название Retention Policy, назначаемой базе данных по умолчанию.

В списке Measurements & Tags мы должны увидеть список (%, °C, state или, если вы настроили компонент в соответствии с моими рекомендациями, что-то вроде temperature, humidity, lt и пр). Выберем, например, °C. В открывшемся списке будет дан перечень тегов (tags), доступных для данного measurement. Нас интересует тэг entity_id, так как он содержит идентификатор нашего сенсора. Раскроем его и увидим имя нашего датчика (bedroom_temperature). В списке Fields справа выберем value, это поле, по значению которого будет строиться график. Если датчик с градусами цельсия у нас только один, entity_id можно не указывать, а сразу выбрать поле value в правом списке полей. В таком случае запрос вернёт все записи с полем value независимо от идентификатора датчика.

Щелкнем на кнопке Submit Query. Должен показаться график с нашими данными.

1547108372130

Подключаем Grafana

При всём уважении к парням из InfluxData, Chronograf (встроенное средство для визуализации накопленных данных) пока не дотягивает по функциям до их заклятого друга Grafana. Я не нашёл возможности указывать две разные оси Y (может быть полезно при наложении графиков температуры и влажности), а также возможности встраивать графики на свои страницы. Последняя фича заявлена, но нигде не сказано как её использовать.

Ставим аддон Grafana

Выбираем аддон Grafana в списке hassio Community Addons и устанавливаем его. Конфигурация аддона максимально простая:

{
  "log_level": "error",
  "ssl": false,
  "certfile": "",
  "keyfile": "",
  "plugins": [],
  "env_vars": []
}

После сохранения конфигурации аддон нужно перезапустить, после чего он будет готов к использованию.

  1. Создаём пользователя для Grafana в InfluxDB, либо же используем ранее созданного для Home Assistant.
  2. Авторизуемся в Grafana под учётными данными admin/hassio и создаём новый источник данных (Configuration->Data Sources->Add Data Source)
  3. Выбираем тип БД: InfluxDB
  4. В появившемcя диалоге в поле Name указываем имя источника данных, какое нам нравится
  5. В поле URL указываем http://a0d7b954-influxdb:8086 (это внутреннее имя контейнера в docker сети hassio)
  6. В разделе InfluxDB details прописываем имя базы данных Home Assistant, имя пользователя и пароль.

1547243506959

Остальные поля оставляем со значениями по умолчанию и сохраняем конфигурацию.

Теперь можно создать наш первый график.

Создаём график в Grafana

  1. В боковом меню выбираем + -> Create Dashboard -> Add query.
  2. Чтобы открыть конструктор запросов в базу данных, нужно навести указатель мыши на название панели (Panel Title, если вы его не изменяли) и в выпадающем списке выбрать Edit, откроется окно редактирования графика:1547244254180
  3. В нижней части видим конструктор запросов. Щёлкаем по select measurement и выбираем ту единицу измерения, которой соответствует наш датчик, например, temperature, в поле WHERE выбираем entity_id и затем имя нашего сенсора: 1547551828523
  4. В графе GROUP BY указываем fill(none). На этом этапе должен появиться наш график температуры.
  5. Добавим второй график, у меня это будет влажность, этот шаг можно опустить. Для этого нажимаем Add Query и повторяем шаги 1 и 2, только в качестве measurement указываем humidity.
  6. В поле ALIAS BY можно ввести название показателя, например температура или влажность. Под этим именем он будет отображаться в легенде графика.
  7. Чтобы Grafana поняла, что данные этих двух графиков используют разные единицы измерения, щёлкаем по тонкой цветной линии в углу графика, обозначающей влажность (где легенда) и во всплывающем окне выбираем Y Axis: Right 1547244831320
  8. После чего график приобретает примерно такой вид: 1547245027627
  9. Сохраним наш график на дэшбоарде с помощью функции Save Dashboard в верхнем ряду кнопок.

Добавим наш график в интерфейс Lovelace, для этого создаём карточку типа iframe:

- type: iframe
  id: graf1
  url: http://192.168.1.200:3000/d-solo/e5Rz-eUmz/new-dashboard-copy?orgId=1&panelId=2
  aspect_ratio: 65%

В параметр URL нам нужно вписать ссылку на график, которую можно получить с помощью функции Share (находится в том же выпадающем меню под названием панели, где и пункт Edit). Кнопка Share dashboard не подойдёт! В открывшемся диалоге нужно открыть закладку Embed.

Нам необходимо убрать галку с пункта Current time range и скопировать полученный URL в буфер обмена.

1547581107850

Откроем Lovelace и полюбуемся на результат:

1547582305019

Вы великолепны!

Светлая тема

А? Что? Говорите, темная цветовая схема графика немного выбивается из общего фона? Это легко поправить. Добавим к URL графика дополнительный параметр &theme=light . Итоговая ссылка должна выглядеть так:

http://192.168.1.200:3000/d-solo/e5Rz-eUmz/new-dashboard-copy?orgId=1&panelId=2&theme=light

Теперь совсем другое дело!

1547582208956

Из графика можно сделать вывод, что колебания температуры и влажности в нашей комнате очень значительные, хотя на самом деле температура, например, колеблется в пределах одного градуса. Чтобы сделать графики более соответствующими реальности, проставим минимальные и максимальные значения по шкалам Y исходя из здравого смысла. В левом меню выбираем Visualization, листаем до Axis:

1547581990100

Не забываем нажать кнопку с изображением 3.5” дискетки для сохранения изменений. Кто спросил как выглядит 3.5 дюймовая дискетка? Не благодарите:

1547582998054

После сохранения изменений наш график больше не заставляет хвататься за сердце при каждом взгляде на экран:

1547583158268

Частота обновления встроенных графиков Grafana

Параметр refresh в URL позволяет указать интервал, через который график на нашей карточке должен автоматически обновляться:

http://192.168.1.200:3000/d-solo/OGR_Smwik/new-dashboard-copy?panelId=2&orgId=1&theme=light&refresh=1m

Этот параметр также можно добавить к URL графика автоматически, когда мы изменяем параметр Refresh any NN в правом верхнем углу экрана Grafana и сохраняем график. Дискеткой, да-да.

Временной диапазон встраиваемых графиков Grafana

Для указания периода времени для отрисовки графика существует специальная кнопка, которая в интерфейсе Grafana выглядит примерно так:

1547583668391

Тонкость в том, что выбранный период игнорируется графиком, встроенном через URL в Lovуlace. Я нашёл два способа указания относительного времени для встраивамого графика:

  1. На закладке Time Range редактора графика заполнить поле Override relative time. Например, указать 8h. После сохранения графика и обновления карточки Lovelace диаграмма должна использовать нужный нам промежуток времени.
  2. Использовать дополнительные параметры в URL графика, как указано в тикете. В примере ниже мы определяем промежуток времени 8 часов для нашего графика:
http://192.168.1.200:3000/d-solo/OGR_Smwik/new-dashboard-copy?panelId=2&orgId=1&from=now-8h&to=now&refresh=5m&theme=light

Второй способ позволяет нам с помощью одной и той же ссылки создать несколько графиков с разным временными диапазонами. Или даже автоматизировать переключение режимов в Lovelace, написав собственную custom card.

Заключение

Мы научились сохранять данные из Home Assistant в InfluxDB, рисовать красивые графики в Grafanа и встраивать их в карточки Lovelace. Во второй части будет рассказано про Continuous Queries, которые позволяют хранить данные “вечно” без замедления работы InfluxDB, а также про использование telegraf для сбора метрик системы, недоступных в существующих компонентах Home Assistant.