Проект способен автономно работать длительное время, компенсировать температурный дрейф тензодатчиков заранее откалиброванной моделью, отправлять данные в чат ВКонтакте, самостоятельно принимать действия по утранению возникающих неисправностей и сигнализировать о своем состоянии в компактной форме.
При дополнительной настройке возможно абсолютно бесплатное расширение: подключение к экосистеме Yandex IoT Core, накапливание данных в Yandex DataBase, отображение гибконастраиваемых графиков за любой период и с любыми показателями, а так же отправка Email-писем с расшифровкой всей диагностической информации к вам на почту.
- ESP32-S3 N16R8 в качестве основного микроконтроллера с light sleep для экономии заряда батареи
- Взвешивание через тензодатчики с 24-битным АЦП HX711
- Температурный датчик DS18B20 и адаптивная компенсация температурного дрейфа тензодатчиков через рекуррентный МНК с автоматическим выбором лучшей полиномиальной модели
- Передача данных через GSM-модем SIM800L; данные принимает VK, Callback API проксирует их в Yandex Cloud Function
- Хранение данных в Yandex Database с визуализацией в Yandex DataLens
- Оповещение по email при аномалиях через Yandex Cloud Function
- Поддержка работы через WiFi (в разработке)
- Адаптивные модели поведения при неисправностях датчиков и модема
- Многорежимная индикация на встроенном WS2812 RGB-светодиоде
Important
Проект в разработке, как и его документация!
- Архитектура системы
- Компоненты
- Принцип работы
- Алгоритм компенсации температурного дрейфа
- Световая индикация
- Управление
- Поведение при ошибках
- Настройка проекта
- Облачная часть
- Зависимости
┌──────────────────────────────────────────────────┐
│ ESP32-S3 N16R8 │
│ + │
│ HX711 + тензодатчики │
│ DS18B20 │
│ Кнопка/переключатели │
└──────────────────────────┬───────────────────────┘
│
PPP
│
▼
┌─────────────────┐
│ SIM800L │
└────────┬────────┘
│
HTTPS
│
▼
┌─────────────────┐ ┌───────────┐
│ VK API │─────►| Сообщения |
└────────┬────────┘ | в чате |
│ └───────────┘
VK Callback API
│
▼
┌────────────────────────────┐
│ Yandex Cloud Function │
└────────────┬───┬───────────┘
┌────────────┘ └──────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ Yandex DataBase │ │ Email-оповещения │
└────────┬────────┘ └─────────────────────┘
│
▼
┌─────────────────┐
│ Yandex DataLens │
└─────────────────┘
— Тут будет схема подключения/разводки платы —
| Компонент | Описание |
|---|---|
| ESP32-S3 N16R8 | Основной контроллер (16 МБ Flash, 8 МБ PSRAM) |
| HX711 | 24-битный АЦП для тензодатчиков |
| Тензодатчики | Весовые датчики (тип и диапазон — на ваш выбор) |
| DS18B20 | Цифровой термометр |
| SIM800L | GSM-модем для передачи данных через мобильную сеть |
| WS2812 | Встроенный RGB-светодиод (пин 48 на ESP32-S3-DevKit) |
Прошивка реализована в виде конечного автомата (FSM). Устройство большую часть времени проводит в режиме light sleep (по умолчанию 30 секунд), периодически просыпаясь для измерений и отправки данных раз в 90 минут (при нормальной работе и 30 минут в режиме калибровки, данные по умолчанию).
Цикл работы:
WAKEUP_SENSORS— пробуждение HX711 и ожидание его инициализацииMEASURE— снятие показаний весов и температуры, обновление EMA-фильтров, диагностика датчиковSTART_MODEM— инициализация SIM800L, установка GSM-соединения (через PPP)DATA_SEND— отправка HTTPS-запроса к VK API с данными о весе, температуре и напряжении батареи + системная информация при надобностиSLEEP_MODEM— корректное выключение модемаERROR_HANDLING— анализ накопленных ошибок, логика их устраненияSLEEP_SENSORS— перевод HX711 в сон, настройка источников пробуждения GPIO/таймер, уход в light sleep
Между 90-минутными (default значение) циклами отправки устройство остаётся в измерительной петле (WAKEUP → MEASURE → SLEEP) без включения модема.
Пример сообщения в VK:
Отчет от весов:
Текущий вес: 12.34 кг
Температура: 23.5 °C
Напряжение батареи: 4.12В
[SC:1 E:00 RB:3]
Note
Мета-тег [SC:N E:HH M:N/N RB:N] в конце сообщения содержит диагностическую информацию (при наличии):
SC— причина последнего выключения (esp_reset_reason())E— маска накопленных ошибок в hex (см. Поведение при ошибках)M— состояние FSM и шаг модема на момент краша (только при аварийном перезапуске)RB— оставшийся бюджет перезагрузок
Тензодатчики подвержены температурному дрейфу: при изменении температуры показания смещаются даже без изменения нагрузки. Для компенсации реализован класс AdaptiveRLS — адаптивный рекуррентный МНК (RLS) с автовыбором модели. Дрейф нуля решается пользователем: перед использованием рекомендуется нагрузить весы на некоторое время рабочим/чуть большим весом в выключенном состоянии.
Как работает:
- Переключите тумблер
CALIB_SWITCH_PINв режим калибровки. На весах должен находиться известный эталонный груз. - Прошивка параллельно обучает три регрессионные модели: линейную, квадратичную и кубическую — на парах (вес, температура), поступающих каждые 30 секунд.
- Каждые 30 минут в VK приходит диагностическое сообщение с прогрессом калибровки: количество точек, диапазон температур, текущая неопределённость модели.
- Контролируйте показатель "неуверенности" в чате ВК/на графике Yandex Data Lens: низкий показатель в течении длительного времени и стабильная близость к эталонному весу (т.е. изначальной массе груза не весах. НЕ "текущий вес"!. Эта строчка в сообщениях и график на дашборде - показатель эталонной массы + влияние дрейфа!) - повод завершить калибровку. Важно: калибровка должна "пройти" весь температурных диапазон будущего использования весов - иначе коменсация в экстраполирующем диапазоне будет некорректной.
- Переключите тумблер обратно для завершения. Прошивка автоматически выбирает наилучшую модель (по средней абсолютной ошибке leave-one-out с штрафами за сложность).
- Параметры модели сохраняются в LittleFS (
/calib.dat) и применяются при каждом измерении и после перезагрузки.
Note
Если при переключении тумблера в начальное положение «Калибровка» данных накоплено недостаточно (мало точек или слишком малый диапазон температур) — модель не будет сохранена, что отобразится в светодиодной индикации и сообщении в VK.
Индикация реализована на встроенном WS2812 и управляется тумблером LED_SWITCH_PIN (при выключенном тумблере светодиод не работает для экономии энергии в автономном режиме). Очередь из 5 отчётов в программе позволяет сохранять результаты нескольких последовательных событий. Например, в конце каждог полного цикла (измерения датчиков + работа модема) происходит индикация как статуса работы датчиков, так и модема, последовательно, разделяя события паузой. См. расшифроку кодов индикации в следующем разделе.
Дыхание (пока происходит длительный процесс):
| Цвет | Событие |
|---|---|
| Синий | Инициализация и настройка SIM800L |
| Оранжевый | Подключение к сети (PPP/GPRS) |
| Пурпурный | HTTPS-запрос к VK API |
| Жёлтый | WiFi: режим точки доступа (в разработке) |
| Зелёный | WiFi: подключение к сети (в разработке) |
Вспышки (короткий отчёт по результату события):
| Цвет | Количество | Событие |
|---|---|---|
| Зелёный | 1 | Датчики: всё ОК |
| Красный | 1 | Датчики: ошибка DS18B20 или HX711 |
| Зелёный | 2 | Модем: успешная отправка данных |
| Красный | 2 | Модем: аппаратная ошибка (SIM800L не ответил) |
| Красный | 3 | Модем: ошибка сети (PPP не поднялся) |
| Красный | 4 | Модем: ошибка сервера (VK API или HTTPS) |
| Голубой | 3 (быстро) | Тарирование выполнено успешно |
| Оранжевый | 3 (быстро) | Тарирование: ошибка (датчик не готов или высокий шум) |
| Белый | 2 | Калибровка: начата |
| Белый | 1 (длинная) | Калибровка: модель сохранена |
| Красный | 4 (быстро) | Калибровка: ошибка (мало точек или малый диапазон температур) |
| Синий | 1 (длинная) | Данные модели выведены в Serial |
Кнопка (пин BUTT_PIN). Подключается на INPUT_PULLUP:
| Ввод | Действие |
|---|---|
| Удержание | Тарирование (обнуление весов) |
| 1 нажатие + удержание | Принудительная внеплановая отправка данных |
| 2 нажатия + удержание | Вывод параметров сохранённой модели калибровки в Serial |
| 3 нажатия + удержание | Сброс данных калибровки из LittleFS |
Тумблер режима (пин CALIB_SWITCH_PIN):
| Положение | Действие |
|---|---|
| Выкл | Штатный режим измерений |
| Вкл | Режим калибровки температурного дрейфа |
Тумблер индикации (пин LED_SWITCH_PIN):
| Положение | Действие |
|---|---|
| Вкл | Светодиодная индикация активна |
| Выкл | Светодиод отключён |
Note
Тарирование отклоняется при повторном вызове в течение 5 секунд (защита от удержания кнопки). Новый оффсет сохраняется в LittleFS (/offset.dat) только после успешной проверки тишины сигнала.
При любой ошибке устанавливается соответствующий бит в маске rtc_error_mask, которая хранится в RTC-памяти и переживает light sleep и перезагрузки. Маска включается в мета-тег следующего сообщения.
Коды ошибок (биты маски, hex):
| Бит | Значение |
|---|---|
0 (0x01) |
Ошибка DS18B20 |
1 (0x02) |
Ошибка HX711 |
2 (0x04) |
Аппаратная ошибка модема |
3 (0x08) |
Ошибка сети (PPP timeout) |
4 (0x10) |
Принудительная перезагрузка |
5 (0x20) |
Ошибка сервера (VK API / HTTPS) |
Бюджет перезагрузок (reboot_budget = 3):
- Ошибки связи — включается
is_retry_mode: повторные попытки каждые 5 минут вместо 90. - Каждые 3 цикла с ошибками или при зависании датчиков тратится одна «жизнь» и выполняется
ESP.restart(). - После исчерпания бюджета устройство продолжает работу по стандартному таймеру без перезагрузок.
- При успешном цикле без ошибок счётчики и маска сбрасываются, бюджет восстанавливается до 3.
Скопируйте include/Secrets/Secrets-example.h в include/Secrets/Secrets.h и заполните:
#define FUNCTION_ADDRESS "https://..." // URL Yandex Cloud Function (для VK Callback API)
constexpr const char* VK_TOKEN = "vk1.a...."; // токен доступа VK API
constexpr const char* VK_PEER_ID = "123456789"; // ID получателя сообщений в VKImportant
Secrets.h добавлен в .gitignore, чтобы не попадать в коммиты.
#define SCL_PIN 18 // SCL пин HX711
#define DT_PIN 8 // DT пин HX711
#define DS_PIN 47 // пин DS18B20
#define BUTT_PIN 1 // пин кнопки
#define LED_PIN 48 // пин WS2812 (встроенный на ESP32-S3-DevKit)
#define LED_SWITCH_PIN 10 // тумблер включения индикации
#define CALIB_SWITCH_PIN 2 // тумблер режима калибровки
#define MODEM_PWR_PIN 5 // управление питанием SIM800L (через транзистор)
#define MODEM_RST_PIN 4 // пин RST SIM800L
#define MODEM_TX_PIN 17 // подключён к RX SIM800L
#define MODEM_RX_PIN 16 // подключён к TX SIM800L
#define BATT_PIN 9 // АЦП для измерения напряжения батареи#define SLEEP_TIME_SEC 30 // период light sleep между измерениями (секунды)
constexpr uint32_t DATA_SEND_PERIOD = 90*60*1000UL; // период отправки данных (90 минут)
constexpr uint32_t DATA_SEND_PERIOD_CALIB = 30*60*1000UL; // период в режиме калибровки (30 минут)
#define DATA_RETRY_PERIOD 5UL*60*1000 // интервал повторных попыток при ошибках связи (5 минут)
#define INVERT_WEIGHT_SIGN true // инвертировать знак показаний HX711
#define STANDART_NOISE 100 // амплитуда стандартного шума (в сырых единицах HX711)
#define WDT_TIMEOUT_MS 25000 // таймаут watchdog (миллисекунды)
#define SENSOR_ERROR_THRESHOLD 10 // циклов подряд с ошибкой датчика до аппаратного сброса
#define R1 470000.0f // верхний резистор делителя батареи (Ом)
#define R2 100000.0f // нижний резистор делителя (Ом)В src/main.cpp при создании объекта ScalesManager первым аргументом передаётся calibration_factor — коэффициент перевода сырых единиц HX711 в граммы:
ScalesManager scales(6.7, DT_PIN, SCL_PIN); // 6.7 — calibration_factor, подбирается вручнуюДля подбора коэффициента включите соответствующий режим в Config.h:
#define WEIGHT_KOEFF_SELECTION 1 // 1 — режим подбора коэффициента, 0 — выклВ include/Sim800LManager.h задаётся APN для SIM-карты:
constexpr const char* APN = "internet"; // замените на APN вашего оператора при необходимостиРаскомментируйте строку в начале Config.h:
#define USE_LOG Serial // вывод отладочных сообщений в Serial (9600 baud)| Окружение | Описание |
|---|---|
esp32-s3-SIM800L |
Основное: подключение через GSM-модем SIM800L |
esp32-s3-WiFi |
WiFi-подключение: в разработке |
— раздел в разработке —
Устройство отправляет данные в VK через API (messages.send). VK Callback API получает событие и перенаправляет его в Yandex Cloud Function. Функция:
- Сохраняет данные в Yandex Database (YDB)
- Отправляет оповещения по email при аномальных значениях
- Данные из YDB используются Yandex DataLens для построения графиков KPI
Здесь будет код Cloud Function и инструкция по настройке Yandex IoT Core.
lib_deps =
GyverLibs/GyverHX711 ; драйвер АЦП HX711
GyverLibs/GyverDS18 ; драйвер DS18B20
GyverLibs/FileData ; работа с переменными в LittleFS
GyverLibs/uButton ; обработка кнопки (мультиклики, удержание)
; Только для env:esp32-s3-WiFi:
mathieucarbou/ESPAsyncWebServer
mathieucarbou/AsyncTCPИспользуемая платформа: pioarduino/platform-espressif32