ESP32-C3 — энергоэффективный микроконтроллер на новой архитектуре RISC-V с поддержкой Wi-Fi и BLE, хорошо подходящий для diy IoT-устройств. Чип обладает низким энергопотреблением в режиме глубокого сна до 44 мкА. В данной статье мы будем подключать не самый распространённый датчик HTU21D температуры и влажности. Рассмотрим реализацию проекта с использованием режима глубокого сна, измерение напряжения аккумулятора LIPO и отправкой данных с датчика на MQTT-сервер Home Assistan.

Подключение датчика
Схема подключения датчика и аккумулятора. Обратите внимание что I2C используется не аппаратный. Это связано с тем что пины GPIO8 и GPIO9 платы ESP32c3 super mini подтянуты к линии питания 3.3в из за этого на датчик в режиме глубокого сна поступает питание батареи это способствует дополнительной разрядки. Поэтому в коде используется переопределение пинов SDA и SCL на GPIO6, GPIO7. Библиотека Adafruit_HTU21DF упрощает чтение данных:
Adafruit_HTU21DF HTU = Adafruit_HTU21DF(); // Определяем датчик HTU21D TwoWire I2CHTU = TwoWire(0); #define I2C_SDA 6 #define I2C_SCL 7 I2CHTU.begin(I2C_SDA, I2C_SCL, 100000);//Определяем новые пины шины I2C HTU.begin(&I2CHTU);
Делитель напряжения
ESP32-C3 имеет встроенный АЦП, но его входное напряжение не должно превышать 3.3 В. Для измерения напряжения батареи (например, Li-Ion 3.7 В) используется делитель напряжения. На схеме применяется мостовой делитель 1:1 (два резистора номиналом R1 = R2), подключенные к GPIO0(A0), что снижает напряжение в 2 раза. Формула расчета:
uint32_t Vb = 0;
for (int i = 0; i < 16; i++){
Vb += analogReadMilliVolts(A0); // коррекция ADC
}
float Vbatt = 2 * Vb / 16 / 1000.0; // переводим в вольты
uint8_t batt_percent = (uint8_t)mapPercent(Vbatt, minV, maxV);
Пояснение:
analogReadMilliVolts(A0)возвращает значение в мВ на делителе используя коррекцию ADC.- Умножение на 2 компенсирует деление напряжения.
- Функция
mapPercent()преобразует напряжение в проценты заряда.
Режим глубокого сна
Режим глубокого сна (Deep Sleep) ESP32-C3 отключает большинство компонентов, оставляя активным только RTC (Real-Time Clock), что снижает энергопотребление до 44 микроампер. В коде время сна задано как TIME_TO_SLEEP 300 * 1000000 мкс (5 минут). Для пробуждения используется аппаратный таймер. После отправки данных на сервер, микроконтроллер уходит в режим глубокого сна, экономя заряд батареи.
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP); esp_deep_sleep_start();
Отправляем и принимаем данные
Используем стандартные настройки подключения к WiFi сети любых модулей ESP32. Для передачи данных на MQTT сервер применяется библиотека <PubSubClient.h>. Для формирования JSON пакета библиотека <ArduinoJson.h>. После считывания данных с датчиков формируем правильный JSON и отправляем в топик MQTT сервера Home Assistan. Структура MQTT-сообщения выглядит следующим образом. ESP32-C3 отправляет JSON в топик ESP32_c3_mini/sensor:
{
"temperature": 25.5,
"humidity": 60,
"battery": 75,
"voltage": 3.6,
"rssi": -65
}
На стороне Home Assistan происходит парсинг JSON. Каждый сенсор использует value_template для извлечения данных:
value_template: "{{ value_json.temperature }}" # Доступ к полю "temperature"
Дополнительные параметры:
unique_id: Уникальный идентификатор для интеграции.device_class: Определяет тип данных для автоматической иконки и логики.unit_of_measurement: Единица измерения.
Настройка файла configuration.yaml в Home Assistan для наших 5 датчиков: температура, влажность, заряд батареи, напряжение батареи, уровень сигнала WiFi выглядит следующим образом:
mqtt:
sensor:
# Температура
- name: "ESP32-C3 Temperature"
unique_id: "esp32c3_temperature"
state_topic: "ESP32_c3_mini/sensor"
unit_of_measurement: "°C"
device_class: "temperature"
value_template: "{{ value_json.temperature }}"
# Влажность
- name: "ESP32-C3 Humidity"
unique_id: "esp32c3_humidity"
state_topic: "ESP32_c3_mini/sensor"
unit_of_measurement: "%"
device_class: "humidity"
value_template: "{{ value_json.humidity }}"
# Заряд батареи
- name: "ESP32-C3 Battery"
unique_id: "esp32c3_battery"
state_topic: "ESP32_c3_mini/sensor"
unit_of_measurement: "%"
device_class: "battery"
value_template: "{{ value_json.battery }}"
# Напряжение
- name: "ESP32-C3 Voltage"
unique_id: "esp32c3_voltage"
state_topic: "ESP32_c3_mini/sensor"
unit_of_measurement: "V"
device_class: "voltage"
value_template: "{{ value_json.voltage }}"
# Уровень сигнала Wi-Fi
- name: "ESP32-C3 RSSI"
unique_id: "esp32c3_rssi"
state_topic: "ESP32_c3_mini/sensor"
unit_of_measurement: "dBm"
device_class: "signal_strength"
value_template: "{{ value_json.rssi }}"
Код программы для ESP32c3 super mini написан в Code Visual Studio доступен на github https://github.com/lvs-vladimir/esp32_c3_deep_sleep
#include <Arduino.h>
#include <timer2Minim.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_HTU21DF.h>
#include <ArduinoJson.h>
#include <Wire.h>
WiFiClient espClient;
PubSubClient client(espClient);
timerMinim TimerToSleep(2000);
Adafruit_HTU21DF HTU = Adafruit_HTU21DF(); // Определяем датчик HTU21D
TwoWire I2CHTU = TwoWire(0);
#define TIME_TO_SLEEP 310 * 1000000 // 5 минут Время в спящем режиме в микросекундах
#define I2C_SDA 6
#define I2C_SCL 7
const char *ssid = "";
const char *password = "";
const char *mqtt_server = "";
const char *mqttUser = "";
const char *mqttPassword = "";
const float minV = 3.0;//Минимальное значение напряжение при котором будет работать esp32c3
const float maxV = 4.0;//Максимальное значение аккумулятора
float mapPercent(float x, float min, float max){//Функция mapPercent выполняет линейное преобразование значения x
return (x - min) * (100) / (max - min);//из исходного диапазона [min, max] в новый диапазон от 0 до 100.
}
void setup(){
pinMode(A0, INPUT);
pinMode(10, OUTPUT);
digitalWrite(10, HIGH);//включаем питание датчика
I2CHTU.begin(I2C_SDA, I2C_SCL, 100000);//Инициализируем программные пины I2C
HTU.begin(&I2CHTU);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED){
delay(500);
}
WiFi.macAddress();
uint32_t Vb = 0;
for (int i = 0; i < 16; i++){
Vb += analogReadMilliVolts(A0); // коррекция ADC
}
float Vbatt = 2 * Vb / 16 / 1000.0; // переводим в вольты
uint8_t batt_percent = (uint8_t)mapPercent(Vbatt, minV, maxV);
client.setServer(mqtt_server, 1883);
client.connect(WiFi.macAddress().c_str(), mqttUser, mqttPassword);
JsonDocument doc;
doc["temperature"] = HTU.readTemperature();
doc["humidity"] = HTU.readHumidity();
doc["battery"] = batt_percent;
doc["voltage"] = Vbatt;
doc["rssi"] = WiFi.RSSI();
char output[128];
serializeJson(doc, output);
client.publish("ESP32_c3_mini/sensor", output);
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP);
TimerToSleep.start();
}
void loop(){
if (TimerToSleep.isReady()){
digitalWrite(10, LOW);
client.disconnect();
WiFi.disconnect();
esp_deep_sleep_start();
}
}
Потребления тока в режиме глубокого сна составляет примерно 50 мкА, что соответствует заявленным производителем характеристикам:

Во время загрузки и подключения к WiFi сети наблюдается кратковременный всплеск до 90мА потом потребление стабилизируется до 32 мА:

ESP32-C3 в связке с HTU21D позволяет создавать автономные IoT-устройства с минимальным энергопотреблением. Режим глубокого сна и MQTT-интеграция делают систему гибкой и масштабируемой.

Спасибо за статью! В моей копии платы светодиод питания горит даже в глубоком сне. Также при подключении к пину на 5 вольт работает регулятор напряжения. Подскажите, что вы делали, чтобы светодиод не горел. Вы его сожгли или изначально он выключался при глубоком сне? Правильно ли предполагаю, что лучше подключать питание к 3.3, чтобы не работал регулятор напряжения?
Приветствую! К сожалению, я не нашёл способов программного отключения светодиодов-индикаторов питания (что удивительно для позиционирования Экспрессиф этих модулей как суперэкономичных). Посему просто нагреваем светодиод заострённым жалом паяльника и сковыриваем его нафиг .
P.S. Заинтересовало замечание автора темы про использование «программного» I2C. Возможно, это брак в конкретных платах, т.к. программно переопределяются только GPIO (методом мультиплексирования).
В целом материал интересный. Вероятно стОит рассмотреть и использование упрощенного протокола ESP NOW от Экспрессифф.