Автономное IoT устройство на ESP32-C3-super mini

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-интеграция делают систему гибкой и масштабируемой.

 

комментария 3

  1. Спасибо за статью! В моей копии платы светодиод питания горит даже в глубоком сне. Также при подключении к пину на 5 вольт работает регулятор напряжения. Подскажите, что вы делали, чтобы светодиод не горел. Вы его сожгли или изначально он выключался при глубоком сне? Правильно ли предполагаю, что лучше подключать питание к 3.3, чтобы не работал регулятор напряжения?

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

  2. Спасибо за статью. На схеме неверно подключен аккумулятор (переполюсован или УГО неверно отрисовано).

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.