Grafana – визуализация данных

Веб-сервер, интернет вещей

Есть у меня сервис по визуализации данных с моих датчиков и устройств. Лично я считаю, что интереснее реализованы некоторые функции, которые в пользовательском интерфейсе Grafana или ESPHome сделаны исходя из совсем других удобств.

Так, несмотря на появление принципов ООП еще в 1960 годах, о нем многие из нас начали слышать лишь в году так 2010. Многие программисты писали методы и функции без разделения кода, но оказалось, что намного интереснее ориентироваться на живой мир, когда с разработкой четко видишь и осознаешь, что вот этот текст в программе – код человека как законченного объекта исследований с его инкапсулированными методами, например, а вот тот фрагмент – это тот же человек, но с наследованием родительского класса… Он уже не просто человек, но специалист, например, в программировании.

Итак, в интерфейсе своего приложения стало интересно оттолкнуться от реального объекта в моем окружении – от фермы на балконе, где выращиваются клубника и микрозелень. И первым вопросом было явно не то, а как и каким инструментом визуализировать данные с датчиков на этом мини-огороде. Ну окей, самым первым  вопросом было, конечно, это. Но когда я накидал график и get-запросом начал переключаться между датчиками, понял, что мне не очень понятно среди этого множества графиков, как вообще управлять всем этим делом и не запутаться.

Вот на подоконнике я точно понимаю, что есть коричневый ящик, а с его правого края находятся два датчика влаги.  Но когда я забыл о ферме на полгода, а потом вдруг решил вспомнить, мне что, надо копаться и вспоминать, где именно эти два датчика?

Я пошел от другого подхода, который в целом можно реализовать и средствами визуализации Grafane, но нужно прямо красивое средство с самого начала сделать все правильным путем. И тут налицо парадигма из ООП. Ведь если есть горшок, то начать стоит с него. Это должно быть понятно и максимально прозрачно в интерфейсе. Ты понимаешь, где какой горшок и что там примерно сидит. И только тогда есть смысл уже перейти к тому, а что в горшке… А в нем – датчики, которые выглядят явно не голой надписью вида  “датчик влаги №12”. Они – типовые элементы, у которых есть красивая фотография крупным планом.

Поэтому я реализовал механизм, где сначала ты обозначаешь проект, например, – ферма на подоконнике. Ферма на балконе – это другой мир, хоть и “братственный” тому, что возле окна. Но можно делать и в одном проекте, в котором выбирать подпроекты. Затем в проекте уже есть резон добавлять в проект конкретные датчики. Причем я должен видеть, в каком они устройстве, какие пины подключения к ESP32. Итого получается довольно интересный интерфейс.

https://habrastorage.org/r/w1560/getpro/habr/upload_files/483/5e9/582/4835e9582bcbf2d94c2b401d4b501073.png
Сервер Интернета Вещей (VS Grafana)

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

Методы и инструменты для оптимизации очевидны: алгоритмы для временных рядов вида LTTB (Largest Triangle Three Buckets), Min/Max per Pixel (LTTB с сохранением экстремумов), правильный выбор библиотеки для отрисовки графиков, WebGL. Хотя все это не так важно, когда не охота строить прямо много точек, а хочется просто на разных масштабах хорошо понимать ситуацию без анализа выбросов и аномалий: работал ли датчик в течение недели, переставал ли функционировать за тот или иной день.

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

https://habrastorage.org/r/w1560/getpro/habr/upload_files/7ae/8ce/00b/7ae8ce00b2b5d750f40766a26f6d666e.png
Значения с датчика

Очевидно, что готовыми и, тем более, OpenSource-решениями пренебрегать не то чтобы не стоит, но их надо постоянно в таком самодельном приложении иметь в арсенале. Многие бы сказали, что “просто перейди на эти решения, добавь их в стек технологий проекта”. Но я поэтому несколькими абзацами ранее и расписал концепцию с тем, как я хочу видеть сам проект. И можно ли видеть его таким через Grafana – один из вопросов данной статьи.

Hello, Grafana! Визуализация в Grafana значений с виртуального датчика DHT22.

Итак,  когда начал искать решение, наткнулся на Опенсорсный проект Grafana и сразу решил попробовать в действии.

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

Пишут, что можно просто поставить решение в таком виде:

brew update 
brew install grafana

Затем следует запустить сервис командой brew services start grafana, в браузере перейти по адресу localhost:3000 и ввести там типовые логин: admin, пароль: admin для перехода к интерфейсу веб-приложения по визуализации данных. 

Но в итоге мне показалось более правильным и интересным расписать решение, которое будет с docker-compose.yaml файлом и которое можно будет видеть в папочке своих микросервисов и запускать командой

docker-compose up

Задал в конфигурации свой логин и пароль, настроил порты, так как и 8000, и 3000 уже заняты другими приложениями, например, RedMine, который использую для своих целей, уже висит на 3000 порту, он будет конфликтовать, если не сменить порт, например, на 3001.

Получившаяся структура проекта для эксперимента с Grafana
Получившаяся структура проекта для эксперимента с Grafana

В качестве источника данных можно выбрать хоть табличные данные из MySQL / Postgres, хоть Prometheus. Мой Hello World – это именно Prometheus, на который мой скрипт шлет данные, имитируя датчик.

https://habrastorage.org/r/w1560/getpro/habr/upload_files/4c0/ceb/017/4c0ceb01763d082e758ca25d5c0e9221.png
Выбор Prometheus в источнике данных

Таким образом, можно вообще не привязываться к моему проекту и с нуля собирать данные через Prometeus, для этого надо перейти в Connections > Data Sources > Add Source и выбрать Prometeus.

Код полученного микросервиса состоит из 3 файлов:

1) docker-compose.yml

Показывает содержимое создаваемого Docker-контейнера. Используется сервер сбора метрик Prometheus, Grafana как средство визуализации данных. Обозначается скрипт, который имитирует датчик температуры (temp_explorer.py). 

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: iot-prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'

  grafana:
    image: grafana/grafana-oss:latest
    container_name: iot-grafana
    restart: unless-stopped
    ports:
      - "3001:3001"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin999
      - GF_USERS_ALLOW_SIGN_UP=false

  temp-exporter:
    image: python:3.11-slim
    container_name: iot-temp-exporter
    restart: unless-stopped
    working_dir: /app
    volumes:
      - ./temp_exporter.py:/app/temp_exporter.py
    command: >
      sh -c "pip install --no-cache-dir prometheus_client && python /app/temp_exporter.py"
    ports:
      - "8001:8001"

volumes:
  prometheus-data:
  Grafana-data:

2) Prometheus.yml

Конфигурация самого сервера Prometheus. Слушает результаты скрипта симуляции датчика температуры, опрашивает датчик раз в 5 секунд.

global:
  scrape_interval: 5s        # Как часто опрашивать датчики
  evaluation_interval: 5s

scrape_configs:
  # Сам Prometheus (его внутренние метрики)
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # Наш виртуальный датчик температуры
  - job_name: 'temperature_sensor'
    static_configs:
      - targets: ['temp-exporter:8001']
        labels:
          location: 'living_room'
          sensor: 'dht22_virtual'

3) temp_exporter.py

Имитатор датчиков. Создает 2 метрики типа Gauge: температура и влажность (по аналогии со значениями, которые выдает реальный датчик DHT22). Формат как раз подходит для Prometheus.

#!/usr/bin/env python3

"""

🌡️ Простой экспортер температуры для Prometheus

Отдает метрики на http://localhost:8001/metrics

"""

import time

import math

import random

from datetime import datetime

from prometheus_client import start_http_server, Gauge




# Создаем метрику температуры

temperature = Gauge(

    'room_temperature_celsius',

    'Temperature in the living room',

    ['location', 'sensor']

)




humidity = Gauge(

    'room_humidity_percent',

    'Humidity in the living room',

    ['location', 'sensor']

)




def generate_realistic_values():

    """Генерирует реалистичные показания датчика"""

    now = datetime.now()

    hour = now.hour + now.minute / 60.0

    # Суточный цикл: прохладно ночью, тепло днем

    base_temp = 21.5 + 2.5  math.sin((hour - 9)  math.pi / 12)

    temp = base_temp + random.gauss(0, 0.15)

    # Влажность обратно пропорциональна температуре

    base_humidity = 55 - 2  math.sin((hour - 9)  math.pi / 12)

    hum = base_humidity + random.gauss(0, 1.5)

    return round(temp, 2), round(max(20, min(90, hum)), 1)




if name == '__main__':

    print("🌡️ Запуск экспортера температуры на порту 8001...")

    print("📊 Prometheus будет забирать данные с http://temp-exporter:8001/metrics")

    # Запускаем HTTP-сервер для Prometheus

    start_http_server(8001)

    while True:

        temp, hum = generate_realistic_values()

        temperature.labels(location='living_room', sensor='dht22_virtual').set(temp)

        humidity.labels(location='living_room', sensor='dht22_virtual').set(hum)

        print(f"[{datetime.now().strftime('%H:%M:%S')}] 🌡️ {temp}°C | 💧 {hum}%")

        time.sleep(5)  # Обновляем значения каждые 5 секунд

Запускается это все командой 

docker-compose up -d

Логин и пароль при таком подходе можно сконфигурировать в коде:

 environment:
    - GF_SECURITY_ADMIN_PASSWORD=admin999

  И вот у Вас уже 3 сервиса внутри единого тестового решения вида “Hello, Grafana”, где эмулятор датчика опрашивается Prometheus раз в 5 секунд, в результате чего подхватываются значения, которые Grafana может визуализировать. 

https://habrastorage.org/r/w1560/getpro/habr/upload_files/438/ff8/4e9/438ff84e9bf690a1110aecf51eabaaee.png
Значения с датчика температуры

Еще раз резюмирую: для создания графика в Grafana нужно добавить Dashboard, в источнике указывается “Prometheus”.

Интерфейс Дашбордов Grafana
Интерфейс Дашбордов Grafana

Можно добавлять разные Дашборды, по разному их называть, добавлять на них графики. Всю самописную логику вида “Если влажность низкая, включить помпу для полива” записывать нужно явно не в Grafana. Хотя там есть Alerting для этих целей, который может отправить Webhook на ваш самописный сервер. Здесь, однако, – именно мощный инструмент для просмотра значений в заданный период времени, интерфейс в целом позволяет удобно задавать этот диапазон.

Интерфейс выбора интервала времени в Grafana
Интерфейс выбора интервала времени в Grafana

Визуализация данных с сервера

Когда совсем не смотрел на то, что выдает датчик, либо в моменте он все показывал хорошо, но особо не заморачивался с его анализом в разных масштабах времени, интересно посмотреть на те данные, которые в итоге накопились.

Надо создать новый дашборд, но в источнике указать базу, у меня это – mySQL. Как добавить MySQL в Grafana: Connections → Data Sources → Add data source → MySQL

Визуализация данных из базы MySQL
Визуализация данных из базы MySQL

Но при этом еще нужно запустить запрос:

SELECT

 datetime AS "time",

 val AS "Значение датчика",

 sensor_id AS "Датчик"

FROM vals

WHERE user_id = 44

 AND sensor_id = 16

 AND datetime >= NOW() - INTERVAL 365 DAY

ORDER BY datetime ASC

Здесь user_id – это идентификатор пользователя в базе данных, у которого есть датчики с разными ID. А sensor_id  – именно тот датчик, значения которого надо взять из базы и визуализировать.

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

Вердикт на тему “Стоит ли подключить Grafana как основной / дополнительный инструмент на моем сервере Интернета вещей”

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

Данный инструмент Grafana ориентирован на то, что нужно руками сидеть и подключать датчики, которые у тебя есть в базе данных, а не на то, что ты создашь цифрового клона своей домашней фермы на подоконнике, а тебе сразу магическим образом предоставляются графики и показатели этой фермы. В Grafana таких чудес нет, потому что как минимум надо прописывать нестандартный скрипт, который свяжет ее с показателями из базы данных, а ведь нужно еще и соображать, где какой датчик находится в реальности, а не на Дашборде. Есть удобные фичи вида “Alerting”, “Variables”, но они решают вопрос ценой совсем другого уровня удобства программирования.

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

Was this article helpful?
YesNo

от Евгений Рычков

Основатель сообщества разработчиков Технофея, фулстек-программист, тим лидер, инженер 1 категории, в прошлом главный специалист по робототехнике в Кванториум Мосгормаш,

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x