Показываем данные с MQTT на Grafana
После того как мы завели наш датчик и начали делиться его показаниями с HomeKit, то хорошо бы отправить эти данные куда либо во внешний интернет, дабы любоваться ими не только в пределах домашней сети. Для этой цели идеально подойдет дашборд метрик Grafana.
Для того чтобы начать отправлять данные, нам не обязательно иметь настроенный Homebridge, необходим только MQTT брокер и сервер с Docker-ом.
Данные мы будем хранить в InfluxDB, она специально была создана для подобных задач. Сервер БД можно завести и в домашней сети, но не советую это делать на RaspberryPi, большое количество чтение/записи может быстро израсходовать лимит вашей SD-карты.
Начнем с того, что зайдем на наш сервер и заведем папку где будем хранить файлы БД, например в /var/influxdb
sudo mkdir /var/influxdb
И создадим базу данных. Это можно сделать командой:
docker run --rm \
-e INFLUXDB_DB=<имя базы данных> \
-e INFLUXDB_ADMIN_ENABLED=true \
-e INFLUXDB_ADMIN_USER=admin \
-e INFLUXDB_ADMIN_PASSWORD=<Пароль администратора> \
-e INFLUXDB_USER=<Имя пользователя> \
-e INFLUXDB_USER_PASSWORD=<Пароль пользователя> \
-v /var/influxdb:/var/lib/influxdb \
influxdb /init-influxdb.sh
Теперь создадим папку для хранения файлов grafana. Например, /var/grafana
sudo mkdir /var/grafana
Т.к. в докере grafana не работает от root, то она не будет иметь прав на запись в папках которые ей по сути не принадлежат, права можно выдать через chmod, но можно сменить владельца и не выдавать лишних прав другим пользователям. Для этого необходимо зайти в терминал через контейнер grafana
docker run -ti --user root --volume /var/grafana:/var/lib/grafana --entrypoint bash grafana/grafana
И поменять владельца
chown -R root:root /etc/grafana && \
chmod -R a+r /etc/grafana && \
chown -R grafana:grafana /var/lib/grafana && \
chown -R grafana:grafana /usr/share/grafana
Исчерпывающую информацию к более детальной настройки Grafana можно найти в документации https://grafana.com/docs/grafana/latest/installation/docker/
Далее можно запускать DB и Grafana.
docker run -d \
-p 8086:8086 \
-v /var/influxdb:/var/lib/influxdb \
--name influxdb \
influxdb
docker run -d \
-p 3000:3000 \
-e GF_SERVER_ROOT_URL="<адрес хоста>" \
-e GF_SECURITY_ADMIN_PASSWORD="<пароль администратора>" \
-v /var/grafana:/var/lib/grafana \
--name grafana \
grafana/grafana
Все что нам осталось, так это зайти на сервер по порту 3000, авторизоваться с указанным вами паролем и выполнять инструкции по настройке указанные в сервисе.
Теперь как же отправить данные на InfluxDB с нашего домашнего сервера? Для этого необходимо маршрутизировать данные с MQTT брокера на сервер. Предлагаю воспользоваться уже готовым решением https://github.com/Kichix/WlanThermoMeterGrafana/tree/master/02-bridge
Для конфигурации которая была описана в предыдущем посте необходимо слегка видоизменить main.py:
#!/usr/bin/env python3
"""A MQTT to InfluxDB Bridge
This script receives MQTT data and saves those to InfluxDB.
"""
import re
from typing import NamedTuple
import paho.mqtt.client as mqtt
from influxdb import InfluxDBClient
INFLUXDB_ADDRESS = '<Адрес хоста с БД>'
INFLUXDB_USER = '<Имя пользователя от БД>'
INFLUXDB_PASSWORD = '<Пароль от БД>'
INFLUXDB_DATABASE = '<Имя базы данных>'
MQTT_ADDRESS = '<Адрес MQTT брокера>'
MQTT_TOPIC = '+/+' # [temperature|humidity|battery|status]/[id]
MQTT_REGEX = '([^/]+)/([^/]+)'
MQTT_CLIENT_ID = 'MQTTInfluxDBBridge'
influxdb_client = InfluxDBClient(INFLUXDB_ADDRESS, 8086, INFLUXDB_USER, INFLUXDB_PASSWORD, None)
class SensorData(NamedTuple):
location: str
measurement: str
value: float
def on_connect(client, userdata, flags, rc):
""" The callback for when the client receives a CONNACK response from the server."""
print('Connected with result code ' + str(rc))
client.subscribe(MQTT_TOPIC)
def on_message(client, userdata, msg):
"""The callback for when a PUBLISH message is received from the server."""
print(msg.topic + ' ' + str(msg.payload))
sensor_data = _parse_mqtt_message(msg.topic, msg.payload.decode('utf-8'))
if sensor_data is not None:
_send_sensor_data_to_influxdb(sensor_data)
def _parse_mqtt_message(topic, payload):
match = re.match(MQTT_REGEX, topic)
if match:
measurement = match.group(1)
location = match.group(2)
if measurement == 'status':
return None
return SensorData(location, measurement, float(payload))
else:
return None
def _send_sensor_data_to_influxdb(sensor_data):
json_body = [
{
'measurement': sensor_data.measurement,
'tags': {
'location': sensor_data.location
},
'fields': {
'value': sensor_data.value
}
}
]
influxdb_client.write_points(json_body)
def _init_influxdb_database():
databases = influxdb_client.get_list_database()
if len(list(filter(lambda x: x['name'] == INFLUXDB_DATABASE, databases))) == 0:
influxdb_client.create_database(INFLUXDB_DATABASE)
influxdb_client.switch_database(INFLUXDB_DATABASE)
def main():
_init_influxdb_database()
mqtt_client = mqtt.Client(MQTT_CLIENT_ID)
#mqtt_client.username_pw_set(MQTT_USER, MQTT_PASSWORD)
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.connect(MQTT_ADDRESS, 1883)
mqtt_client.loop_forever()
if __name__ == '__main__':
print('MQTT to InfluxDB bridge')
В оригинальном коде происходила авторизация на брокер по логин/пароль, возможно это и более безопасно, но почему то для своей сети я решил этим не заморачиваться и было изменено определение источника и типа измерения. Автор кода принимал сначала id источника, а потом идентификатор измерения, в моем же варианте наоборот. Так же автор предлагает запускать скрипт в докере, но память RaspberryPi не резиновая и устанавливать на него Docker мне лично кажется неразумным. Поэтому необходимо будет написать конфигурацию сервиса чтобы настроить автозапуск скрипта при старте RaspberryPi. Создадим файл mqtt-influxdb-bridge.service
:
[Unit]
Description=MQTT InfluxDB Bridge
After=syslog.target network-online.target
[Service]
Type=simple
User=pi
ExecStart=/usr/bin/python3 /home/pi/mqtt-influxdb-bridge/main.py
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
Создадим папку для хранения бриджа на RaspberryPi
mkdir ~/mqtt-influxdb-bridge
И отправим requirements.txt, модифицированый main.py
и mqtt-influxdb-bridge.service
на наш RaspberryPi
scp main.py pi@raspberrypi:~/mqtt-influxdb-bridge/.
scp requirements.txt pi@raspberrypi:~/mqtt-influxdb-bridge/.
scp mqtt-influxdb-bridge.service pi@raspberrypi:~/mqtt-influxdb-bridge/.
Установите python3 если он еще не установлен на ваш RaspberryPi и начните забирать зависимости из папки ~/mqtt-influxdb-bridge
pip3 install -r requirements.txt
Далее скопируем конфигурацию сервиса в /lib/systemd/system/
sudo cp mqtt-influxdb-bridge.service /lib/systemd/system/.
Не забудьте исправить полный путь ExecStart
в mqtt-influxdb-bridge.service
к файлу скрипта main.py
если он отличается от настоящего.
Наконец то можно запускать скрипт
systemctl daemon-reload
systemctl enable mqtt-influxdb-bridge
systemctl start mqtt-influxdb-bridge
Данные должны начать отправляться на вашу БД. Можете начать настраивать индикаторы в Grafana и наслаждаться плодами трудов.