Домашняя метеостанция с графиками: ESP32 + InfluxDB + Grafana

Создаём домашнюю метеостанцию на ESP32 с хранением данных в InfluxDB и наглядными графиками в Grafana.
Всем привет! Сегодня мы соберём проект, который идеально сочетает DIY-электронику и визуализацию данных — полноценную домашнюю метеостанцию. Мы не просто получим текущие показания, а построим исторические графики температуры, влажности и давления, которые будут храниться годами. Всё это на базе доступного микроконтроллера ESP32 и мощной, но бесплатной связки InfluxDB и Grafana, развернутой на одноплатном компьютере.
Зачем это нужно? Погодные сайты и умные колонки дают общую картину по району. Наша же станция покажет микроклимат именно в вашей квартире, на балконе или в гараже. Вы увидите, как работает отопление, где скапливается сырость, как меняется давление. Это не только увлекательно, но и практично.
Что нам понадобится
Аппаратная часть
- Плата ESP32 (любая, например, DevKit V1). Отличный выбор благодаря встроенному Wi-Fi и достаточной мощности. Если вы в раздумьях, что взять, у меня есть подробное сравнение ESP32 vs ESP8266: Что выбрать для своего DIY-проекта в 2024 году.
- Датчик BME280. Компактный и точный сенсор, измеряющий температуру, влажность и атмосферное давление по цифровому интерфейсу I2C (или SPI). Это наш «метеорологический центр». Кстати, если хотите глубже погрузиться в работу с этим датчиком, посмотрите статью ESP32 и три в одном: измеряем температуру, влажность и давление на одной плате.
- Макетная плата и провода для соединений.
- Одноплатник для сервера (Raspberry Pi, Orange Pi, NanoPi). На нём будут работать база данных и система графиков. Для такого проекта хватит даже маломощной платы вроде Orange Pi Zero 3.
Программная часть
- InfluxDB 2.x — высокопроизводительная база данных, созданная специально для хранения временных рядов (time-series data). Идеальна для показаний датчиков.
- Grafana — платформа для аналитики и визуализации. С её помощью мы создадим красивые и информативные дашиборды.
- Arduino IDE или PlatformIO для программирования ESP32.
Схема подключения
Подключение датчика BME280 по интерфейсу I2C очень простое. Нам нужно всего 4 провода.
ESP32 (DevKit) -> BME280
3.3V (3V3) -> VCC
GND -> GND
GPIO 21 -> SDA
GPIO 22 -> SCL
Важно: Датчик BME280 питается от 3.3В! Подача 5В его убьёт. Убедитесь, что вы подключили VCC к правильному пину на ESP32.
Часть 1: Настройка сервера (InfluxDB + Grafana)
Я буду использовать для примера Raspberry Pi с установленной ОС Raspberry Pi OS (Debian). Для других одноплатников на базе Arm, таких как Orange Pi или NanoPi, процесс будет аналогичным, особенно если вы используете Armbian: универсальная ОС для одноплатников — установка и настройка.
Установка InfluxDB 2.x
Открываем терминал на нашем одноплатнике и выполняем команды.
# Добавляем репозиторий InfluxData
wget -q https://repos.influxdata.com/influxdata-archive.key
echo '23a1c8836f0afc5ed24e0486339d7cc8f6790b83886c4c96995b88a061c5bb5d influxdata-archive.key' | sha256sum -c && cat influxdata-archive.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/influxdata-archive.gpg > /dev/null
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main' | sudo tee /etc/apt/sources.list.d/influxdata.list
# Обновляем список пакетов и устанавливаем InfluxDB 2
sudo apt update
sudo apt install influxdb2 -y
# Запускаем службу и добавляем в автозагрузку
sudo systemctl start influxdb
sudo systemctl enable influxdb
Проверяем, что служба работает:
sudo systemctl status influxdb
Вы должны увидеть статус active (running).
Теперь нужно завершить первоначальную настройку. Откройте браузер и перейдите по адресу http://ВАШ_IP_ОДНОПЛАТНИКА:8086.
- Создайте первого пользователя (username, password).
- Создайте первую организацию (например,
home) и бакет (bucket). Бакет — это контейнер для данных. Назовём егоsensors_data. - Запишите или сгенерируйте Токен (Token). Он понадобится ESP32 для записи данных. Сохраните его в надёжном месте!
Установка Grafana
Установка также выполняется из официального репозитория.
# Устанавливаем необходимые зависимости
sudo apt install -y software-properties-common wget
# Добавляем ключ и репозиторий Grafana
sudo wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
# Устанавливаем Grafana
sudo apt update
sudo apt install grafana -y
# Запускаем службу и добавляем в автозагрузку
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
Проверяем статус:
sudo systemctl status grafana-server
Теперь Grafana доступна по адресу http://ВАШ_IP_ОДНОПЛАТНИКА:3000. Стандартные логин и пароль — admin / admin. Система сразу попросит их сменить.
Часть 2: Прошивка для ESP32
Мы напишем скетч, который будет считывать данные с BME280 и отправлять их в InfluxDB по протоколу HTTP API (InfluxDB Line Protocol).
Подготовка среды и библиотек
- В Arduino IDE добавьте поддержку плат ESP32 через
Файл->Настройки->Дополнительные ссылки для менеджера плат. - Установите необходимые библиотеки через
Инструменты->Управлять библиотеками...:- Adafruit BME280 Library (для работы с датчиком)
- Adafruit Unified Sensor (зависимость для BME280)
- WiFi (встроенная)
- HTTPClient (встроенная)
Код прошивки (скетч)
Создайте новый скетч и полностью замените его содержимое на код ниже. Не забудьте подставить свои данные!
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
// ========== НАСТРОЙКИ ==========
// 1. Данные вашей Wi-Fi сети
const char* ssid = "ВАШ_SSID";
const char* password = "ВАШ_ПАРОЛЬ";
// 2. Данные вашего InfluxDB 2.x
const char* influxDBUrl = "http://ВАШ_IP_ОДНОПЛАТНИКА:8086"; // Адрес сервера
const char* influxDBToken = "ВАШ_ТОКЕН_ПОЛЬЗОВАТЕЛЯ"; // Токен с правами записи
const char* influxDBOrg = "home"; // Название организации
const char* influxDBBucket = "sensors_data"; // Название бакета
// 3. Настройки датчика и интервалов
#define SEALEVELPRESSURE_HPA (1013.25) // Давление на уровне моря для расчёта высоты
#define SENSOR_ID "esp32_balcony" // Уникальное имя для этой метеостанции
#define MEASUREMENT_INTERVAL 60000 // Интервал отправки данных в миллисекундах (60 сек)
// ===============================
// Объект датчика
Adafruit_BME280 bme;
// Таймер для отслеживания интервала
unsigned long lastSendTime = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("n=== Запуск домашней метеостанции ===");
// Инициализация датчика BME280
bool bme_status = bme.begin(0x76); // Адрес 0x76. Если не работает, попробуйте 0x77
if (!bme_status) {
Serial.println("ОШИБКА: Не удалось найти датчик BME280! Проверьте схему подключения.");
while (1); // Останавливаем выполнение
}
Serial.println("Датчик BME280 инициализирован.");
// Подключение к Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Подключение к Wi-Fi ");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("nПодключено к Wi-Fi!");
Serial.print("IP-адрес: ");
Serial.println(WiFi.localIP());
}
void loop() {
// Проверяем, пришло ли время отправлять данные
if (millis() - lastSendTime >= MEASUREMENT_INTERVAL) {
// Считываем данные с датчика
float temperature = bme.readTemperature();
float humidity = bme.readHumidity();
float pressure_hPa = bme.readPressure() / 100.0F;
float altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
// Формируем строку данных в формате InfluxDB Line Protocol
// Формат: measurement,tag_set field_set timestamp
String dataToSend = "environment,sensor_id=";
dataToSend += SENSOR_ID;
dataToSend += " temperature=";
dataToSend += String(temperature);
dataToSend += ",humidity=";
dataToSend += String(humidity);
dataToSend += ",pressure=";
dataToSend += String(pressure_hPa);
dataToSend += ",altitude=";
dataToSend += String(altitude);
// Timestamp добавляется сервером автоматически
// Отправляем данные в InfluxDB
sendToInfluxDB(dataToSend);
// Обновляем время последней отправки
lastSendTime = millis();
}
// Небольшая задержка для стабильности
delay(100);
}
void sendToInfluxDB(String payload) {
// Проверяем подключение к Wi-Fi
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// Формируем полный URL для записи в API v2
String fullUrl = String(influxDBUrl);
fullUrl += "/api/v2/write?org=";
fullUrl += influxDBOrg;
fullUrl += "&bucket=";
fullUrl += influxDBBucket;
fullUrl += "&precision=s";
http.begin(fullUrl);
http.addHeader("Content-Type", "text/plain");
http.addHeader("Authorization", "Token " + String(influxDBToken));
Serial.print("Отправка данных: ");
Serial.println(payload);
int httpResponseCode = http.POST(payload);
if (httpResponseCode > 0) {
Serial.print("Код ответа HTTP: ");
Serial.println(httpResponseCode);
if (httpResponseCode == 204) { // 204 No Content - успешная запись
Serial.println("Данные успешно отправлены в InfluxDB!");
}
} else {
Serial.print("ОШИБКА при отправке: ");
Serial.println(httpResponseCode);
Serial.println(http.errorToString(httpResponseCode));
}
http.end();
} else {
Serial.println("ОШИБКА: Нет подключения к Wi-Fi.");
}
}
Пояснения и типичные ошибки
- Адрес датчика (
0x76или0x77): У BME280 может быть два адреса. Если датчик не инициализируется, закомментируйте строку с0x76и раскомментируйте следующую (обычно она есть в примерах библиотеки Adafruit) или просто попробуйте0x77. - Токен InfluxDB: Убедитесь, что токен имеет права на запись в указанный бакет (
sensors_data). Ошибка401 Unauthorizedговорит о проблеме с токеном. - Блокировка брандмауэра: Если ESP32 не может подключиться к порту
8086, проверьте настройки брандмауэра на одноплатнике (sudo ufw status). Нужно разрешить порт:sudo ufw allow 8086/tcp. - Стабильность Wi-Fi: В коде нет жёсткой перезагрузки при потере связи. В реальном проекте стоит добавить проверку
WiFi.status()и переподключение.
Загрузите скетч в ESP32 и откройте Монитор порта (Serial Monitor). Вы должны увидеть процесс подключения и периодические сообщения об успешной отправке данных.
Часть 3: Настройка дашборда в Grafana
Данные летят в базу. Самое время создать для них красивое представление.
-
Добавьте источник данных (Data Source).
- В Grafana перейдите в
Configuration(значок шестерёнки) ->Data Sources. - Нажмите
Add data sourceи выберите InfluxDB. - Выберите метод доступа Flux (актуально для InfluxDB 2.x).
- В настройках укажите:
- URL:
http://localhost:8086(если Grafana на том же сервере). - Organization:
home - Token: тот же токен, что использовали для ESP32.
- Нажмите
Save & test. Должно появиться сообщение об успешном подключении.
- URL:
- В Grafana перейдите в
-
Создайте новый дашборд (Dashboard).
- Нажмите
Create(знак плюса) ->Dashboard. - Нажмите
Add visualization.
- Нажмите
-
Напишите первый запрос (Query) на языке Flux.
- В выпадающем списке выберите ваш источник данных InfluxDB.
- В редакторе запросов вставьте следующий Flux-запрос для температуры:
from(bucket: "sensors_data")
|> range(start: -1h)
|> filter(fn: (r) => r["_measurement"] == "environment")
|> filter(fn: (r) => r["sensor_id"] == "esp32_balcony")
|> filter(fn: (r) => r["_field"] == "temperature")
|> aggregateWindow(every: 1m, fn: mean, createEmpty: false)
|> yield(name: "mean")
Что делает этот запрос:
* from(bucket: "sensors_data") — выбирает наш бакет.
* range(start: -1h) — берёт данные за последний час.
* Три фильтра filter — выбирают нужное измерение, конкретный датчик и поле "температура".
* aggregateWindow(...) — усредняет значения за каждую минуту для сглаживания графика.
* yield(...) — выводит результат.
-
Настройте визуализацию.
- В правой панели в разделе
VisualizationвыберитеTime series. - Во вкладке
Panel optionsзадайте понятное название, например, "Температура на балконе". - Во вкладке
Fieldможно настроить единицы измерения (°C) и количество десятичных знаков.
- В правой панели в разделе
-
Добавьте остальные графики.
- Нажмите кнопку
Addв верхней панели дашборда и выберитеVisualization. - Создайте новые панели для влажности (
humidity) и давления (pressure), скопировав запрос и изменив поле в фильтреfilter(fn: (r) => r["_field"] == "humidity"). - Расположите панели на дашборде удобным образом.
- Нажмите кнопку
-
Сохраните дашборд. Нажмите
Saveв верхней панели и дайте ему имя, например, "Домашняя метеостанция".
Проверка результата
После того как всё настроено и ESP32 работает несколько минут, выполните финальную проверку:
-
В InfluxDB UI (
http://IP:8086):- Перейдите в раздел
Data Explorer. - Выберите бакет
sensors_data. - Выполните простой запрос:
from(bucket: "sensors_data") |> range(start: -5m). Вы должны увидеть сырые данные, поступающие от ESP32.
- Перейдите в раздел
-
В Grafana:
- Обновите ваш дашборд. На графиках должны появиться линии с данными.
- Поиграйте с диапазоном времени (правый верхний угол дашборда). Посмотрите данные за 6
Понравилась статья?
Поставьте лайк и сохраните полезный материал в закладки.
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
Мониторинг качества воздуха: CO2, PM2.5 и VOC своими руками на ESP32
Как печатать резьбу на 3D-принтере: зазоры, допуски и настройки для болтов и гаек
DIY умный звонок с камерой на ESP32-CAM и Home Assistant
Умный аквариум своими руками: автодолив, контроль температуры и освещение по расписанию
Умная теплица на ESP32 и Raspberry Pi: автоматизация от А до Я
Умный счётчик электроэнергии своими руками: мониторинг потребления в реальном времени