Đưa ESP32 và relay 4 kênh vào Home Assistant bằng MQTT discovery, không viết YAML

ESP32 tự gửi tin cấu hình MQTT discovery, Home Assistant tạo 4 công tắc relay và cảm biến Wi-Fi; Mosquitto, tài khoản, di chúc, retain và bảng xử lý lỗi.

Home Assistant là phần mềm nhà thông minh mã nguồn mở, chạy trên máy trong nhà (Raspberry Pi, máy tính mini, máy ảo), gom thiết bị của nhiều hãng vào một ứng dụng. Cách đơn giản để đưa một mạch ESP32 tự làm vào Home Assistant là MQTT kèm chức năng discovery: ESP32 tự gửi tin mô tả mình có những công tắc, cảm biến nào, Home Assistant đọc và tạo thiết bị, không phải viết cấu hình YAML. Bài này dùng ESP32 và module relay 4 kênh: 4 kênh hiện thành 4 công tắc, kèm cảm biến cường độ Wi-Fi và trạng thái kết nối, nút nhấn tại chỗ vẫn dùng được và Home Assistant cập nhật theo.

1. ESP32, máy chủ MQTT và Home Assistant

Sơ đồ khối ESP32, máy chủ MQTT Mosquitto và Home Assistant, mũi tên cấu hình trạng thái và lệnh ON OFF; bảng các chủ đề MQTT bài dùng
Hai bên cùng gửi, nhận tin qua máy chủ MQTT; bảng là các chủ đề bài dùng.

MQTT hoạt động theo kiểu đăng và nhận tin theo chủ đề (topic) qua một máy chủ trung gian (broker). Cơ bản về MQTT và thư viện PubSubClient có trong bài dùng MQTT với ESP32. Trong bài này:

  • Máy chủ MQTT là Mosquitto cài ngay trong Home Assistant.
  • Khi kết nối, ESP32 gửi 5 tin cấu hình vào các chủ đề homeassistant/…/config: 4 công tắc và 1 cảm biến. Home Assistant theo dõi các chủ đề này và tạo thiết bị.
  • Bấm công tắc trên Home Assistant: Home Assistant gửi ON hoặc OFF vào chủ đề lệnh của kênh đó. ESP32 đổi relay rồi gửi lại trạng thái thật vào chủ đề trạng thái.

2. Chuẩn bị

3. Sơ đồ nối

Sơ đồ nối module relay 4 kênh IN1 IN2 IN3 IN4 vào GPIO32 33 26 27 của ESP32 DevKit V1, VCC vào VIN, GND chung, nút nhấn từ GPIO4 xuống GND; bảng nối dây
Cùng sơ đồ với các bài relay khác trong loạt; D21, D22 để trống cho màn hình OLED.

Relay đóng cắt điện 220 V phải lắp trong hộp kín, dây lưới điện có cầu chì và đủ tiết diện; khi chưa quen làm điện, chỉ thử với đèn LED hoặc tải điện áp thấp.

4. Cài máy chủ MQTT và tài khoản trên Home Assistant

  1. Cài Mosquitto: trong Home Assistant vào Settings › Add-ons (bản mới đổi tên thành Apps), mở cửa hàng, tìm Mosquitto broker, bấm Install rồi Start. Mục này chỉ có ở bản Home Assistant OS; bản chạy bằng Docker thì cài Mosquitto riêng.
  2. Bật tích hợp MQTT: vào Settings › Devices & services. Home Assistant tự phát hiện MQTT; bấm thêm vào và xác nhận. Từ đây Home Assistant lắng nghe các tin cấu hình trong homeassistant/….
  3. Tạo tài khoản cho thiết bị: Mosquitto trong Home Assistant không cho kết nối ẩn danh, nhưng nhận tài khoản người dùng của Home Assistant. Vào Settings › People, thêm một người dùng riêng cho các mạch ESP32 (bật cho phép đăng nhập, đặt tên đăng nhập và mật khẩu). Không dùng tài khoản quản trị của mình cho thiết bị.

5. Chương trình

Cần hai thư viện cài từ Library Manager của Arduino IDE: PubSubClient (Nick O'Leary) và ArduinoJson (Benoit Blanchon, bản 7). Trước khi nạp, sửa:

  • TEN_WIFI, MAT_KHAU_WIFI: Wi-Fi nhà (2,4 GHz).
  • MQTT_MAY_CHU: IP của máy chạy Home Assistant.
  • MQTT_TAI_KHOAN, MQTT_MAT_KHAU: tài khoản vừa tạo ở bước 4.
// PYWORLD.VN - Đưa ESP32 và relay 4 kênh vào Home Assistant bằng MQTT discovery
// Home Assistant tự tạo 4 công tắc và cảm biến cường độ Wi-Fi, không phải viết cấu hình YAML
// Thư viện: PubSubClient 2.8, ArduinoJson 7; máy chủ MQTT là Mosquitto chạy cùng Home Assistant

#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

const char *TEN_WIFI = "TEN_WIFI";
const char *MAT_KHAU_WIFI = "MAT_KHAU_WIFI";
const char *MQTT_MAY_CHU = "192.168.1.20";       // Địa chỉ IP của máy chạy Home Assistant
const uint16_t MQTT_CONG = 1883;
const char *MQTT_TAI_KHOAN = "TAI_KHOAN_MQTT";   // Tài khoản người dùng Home Assistant dành cho thiết bị
const char *MQTT_MAT_KHAU = "MAT_KHAU_MQTT";

const uint8_t RELAY_PINS[4] = {32, 33, 26, 27};  // IN1, IN2, IN3, IN4
const bool RELAY_ACTIVE_LOW = true;              // Module kích mức thấp: IN = LOW thì relay đóng
const uint8_t NUT = 4;                           // Nút nhấn nối GPIO4 xuống GND, đảo kênh 1
const unsigned long CHU_KY_RSSI_MS = 60000;      // Gửi cường độ Wi-Fi mỗi phút

WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
char maThietBi[20];  // pw_relay_ + 6 ký tự cuối của địa chỉ MAC, cũng là client ID của MQTT
bool relayBat[4] = {false, false, false, false};
bool henGuiCauHinh = false;
unsigned long lucHen = 0, treHen = 0;

// Mọi chủ đề của thiết bị nằm dưới pyworld/<mã thiết bị>/
String chuDe(const String &duoi) {
  return String("pyworld/") + maThietBi + "/" + duoi;
}

void datRelay(uint8_t kenh, bool bat) {
  relayBat[kenh] = bat;
  bool muc = RELAY_ACTIVE_LOW ? !bat : bat;
  digitalWrite(RELAY_PINS[kenh], muc ? HIGH : LOW);
  Serial.printf("Relay K%u: %s\n", (unsigned)(kenh + 1), bat ? "BAT" : "TAT");
}

// Trạng thái gửi kèm cờ retain: Home Assistant khởi động lại vẫn biết relay đang bật hay tắt
void guiTrangThaiRelay(uint8_t kenh) {
  mqtt.publish(chuDe("relay" + String(kenh + 1) + "/trang_thai").c_str(), relayBat[kenh] ? "ON" : "OFF", true);
}

void guiRssi() {
  mqtt.publish(chuDe("rssi").c_str(), String(WiFi.RSSI()).c_str());
}

// Phần "device" giống nhau ở mọi thực thể: Home Assistant gom chúng vào một thiết bị
void themThietBi(JsonDocument &doc) {
  doc["availability_topic"] = chuDe("ket_noi");
  JsonObject dev = doc["device"].to<JsonObject>();
  dev["identifiers"].add(maThietBi);
  dev["name"] = "Relay PYWORLD";
  dev["model"] = "ESP32 DevKit V1 + relay 4 kênh";
  dev["sw_version"] = "1.0";
  doc["origin"]["name"] = "pyworld.vn ESP32 MQTT";
}

bool guiCauHinhMot(const String &chuDeCauHinh, JsonDocument &doc) {
  char buf[700];
  size_t n = serializeJson(doc, buf, sizeof(buf));
  if (n >= sizeof(buf) - 1) {
    Serial.println("Cau hinh qua dai, tang kich thuoc buf");
    return false;
  }
  return mqtt.publish(chuDeCauHinh.c_str(), (const uint8_t *)buf, n, false);
}

// Discovery: mỗi thực thể một tin cấu hình tại homeassistant/<loại>/<mã thiết bị>/<tên>/config
void guiCauHinh() {
  uint8_t dat = 0;
  for (uint8_t i = 0; i < 4; i++) {
    JsonDocument doc;
    String k = String(i + 1);
    doc["name"] = "Kênh " + k;
    doc["unique_id"] = String(maThietBi) + "_relay" + k;
    doc["command_topic"] = chuDe("relay" + k + "/dat");
    doc["state_topic"] = chuDe("relay" + k + "/trang_thai");
    themThietBi(doc);
    if (guiCauHinhMot(String("homeassistant/switch/") + maThietBi + "/relay" + k + "/config", doc)) dat++;
  }
  JsonDocument doc;
  doc["name"] = "Cường độ Wi-Fi";
  doc["unique_id"] = String(maThietBi) + "_rssi";
  doc["state_topic"] = chuDe("rssi");
  doc["device_class"] = "signal_strength";
  doc["unit_of_measurement"] = "dBm";
  doc["state_class"] = "measurement";
  doc["entity_category"] = "diagnostic";
  themThietBi(doc);
  if (guiCauHinhMot(String("homeassistant/sensor/") + maThietBi + "/rssi/config", doc)) dat++;
  Serial.printf("Da gui cau hinh discovery: %u/5 thuc the\n", (unsigned)dat);
  for (uint8_t i = 0; i < 4; i++) guiTrangThaiRelay(i);
  guiRssi();
}

void nhanTin(char *topic, byte *payload, unsigned int dai) {
  String t(topic);
  String noiDung;
  for (unsigned int i = 0; i < dai; i++) noiDung += (char)payload[i];
  Serial.printf("Nhan %s: %s\n", topic, noiDung.c_str());

  // Home Assistant vừa khởi động (hoặc vừa nối lại máy chủ MQTT): gửi lại cấu hình sau một khoảng ngẫu nhiên
  if (t == "homeassistant/status") {
    if (noiDung == "online") {
      henGuiCauHinh = true;
      lucHen = millis();
      treHen = random(500, 3000);
    }
    return;
  }
  for (uint8_t i = 0; i < 4; i++) {
    if (t == chuDe("relay" + String(i + 1) + "/dat")) {
      if (noiDung == "ON") datRelay(i, true);
      else if (noiDung == "OFF") datRelay(i, false);
      guiTrangThaiRelay(i);  // Báo lại trạng thái thật để công tắc trên Home Assistant khớp với relay
    }
  }
}

void ketNoiMqtt() {
  static unsigned long lanThu = 0;
  static bool lanDau = true;
  if (!lanDau && millis() - lanThu < 5000) return;  // Lỗi thì 5 giây sau thử lại, không chặn vòng lặp lâu
  lanDau = false;
  lanThu = millis();
  Serial.printf("Ket noi MQTT %s:%u...\n", MQTT_MAY_CHU, (unsigned)MQTT_CONG);
  // Di chúc (last will): mất kết nối thì máy chủ MQTT tự đăng "offline", Home Assistant báo thiết bị không khả dụng
  if (mqtt.connect(maThietBi, MQTT_TAI_KHOAN, MQTT_MAT_KHAU, chuDe("ket_noi").c_str(), 0, true, "offline")) {
    Serial.printf("MQTT da ket noi, ma thiet bi %s\n", maThietBi);
    mqtt.publish(chuDe("ket_noi").c_str(), "online", true);
    mqtt.subscribe("homeassistant/status");
    mqtt.subscribe(chuDe("+/dat").c_str());
    guiCauHinh();
  } else {
    Serial.printf("MQTT loi %d, thu lai sau 5 giay\n", mqtt.state());
  }
}

// Nút nhấn tại chỗ đảo trạng thái K1, vẫn dùng được khi mất mạng
void kiemTraNut() {
  static bool docTruoc = HIGH, onDinh = HIGH;
  static unsigned long lucDoi = 0;
  bool doc = digitalRead(NUT);
  if (doc != docTruoc) {
    docTruoc = doc;
    lucDoi = millis();
  }
  if (millis() - lucDoi > 30 && doc != onDinh) {  // Chống dội 30 ms
    onDinh = doc;
    if (onDinh == LOW) {
      datRelay(0, !relayBat[0]);
      if (mqtt.connected()) guiTrangThaiRelay(0);
    }
  }
}

void setup() {
  Serial.begin(115200);
  for (uint8_t i = 0; i < 4; i++) {
    pinMode(RELAY_PINS[i], INPUT);                               // Chân chưa xuất tín hiệu
    digitalWrite(RELAY_PINS[i], RELAY_ACTIVE_LOW ? HIGH : LOW);  // Ghi sẵn mức tắt
    pinMode(RELAY_PINS[i], OUTPUT);                              // Bật ngõ ra, relay vẫn tắt
  }
  pinMode(NUT, INPUT_PULLUP);

  WiFi.mode(WIFI_STA);
  String mac = WiFi.macAddress();  // Dạng AA:BB:CC:DD:EE:FF
  mac.replace(":", "");
  mac.toLowerCase();
  snprintf(maThietBi, sizeof(maThietBi), "pw_relay_%s", mac.substring(6).c_str());

  WiFi.begin(TEN_WIFI, MAT_KHAU_WIFI);
  mqtt.setServer(MQTT_MAY_CHU, MQTT_CONG);
  mqtt.setBufferSize(1024);  // Mặc định 256 byte, không đủ cho tin cấu hình discovery
  mqtt.setCallback(nhanTin);
  Serial.println("Dang ket noi Wi-Fi...");
}

void loop() {
  kiemTraNut();
  if (WiFi.status() != WL_CONNECTED) return;
  static bool daBaoIp = false;
  if (!daBaoIp) {
    daBaoIp = true;
    Serial.printf("Da vao Wi-Fi, IP %s\n", WiFi.localIP().toString().c_str());
  }
  if (!mqtt.connected()) {
    ketNoiMqtt();
    return;
  }
  mqtt.loop();
  if (henGuiCauHinh && millis() - lucHen > treHen) {
    henGuiCauHinh = false;
    guiCauHinh();
  }
  static unsigned long lucGuiRssi = 0;
  if (millis() - lucGuiRssi > CHU_KY_RSSI_MS) {
    lucGuiRssi = millis();
    guiRssi();
  }
}

6. Giải thích các phần chính

Tin cấu hình discovery của công tắc Kênh 2: chủ đề homeassistant switch, các khóa name, unique_id, command_topic, state_topic, availability_topic, device, origin; ghi chú về kích thước bộ đệm
Tin cấu hình của một công tắc (mã thiết bị là ví dụ).

Tin cấu hình discovery

Mỗi thực thể một tin, chủ đề dạng homeassistant/<loại>/<mã thiết bị>/<tên>/config. Loại switch là công tắc, sensor là cảm biến. Các khóa chính:

  • unique_id: mã riêng của thực thể, không được trùng và không được đổi; nhờ nó mới đổi tên, đổi biểu tượng thực thể trên Home Assistant được.
  • device: cả 5 tin có cùng identifiers nên Home Assistant gom vào một thiết bị tên "Relay PYWORLD".
  • command_topic, state_topic: nơi nhận lệnh và nơi báo trạng thái. Lệnh mặc định là ON/OFF.
  • Cảm biến có device_class: signal_strength và đơn vị dBm; entity_category: diagnostic đưa nó vào nhóm chẩn đoán, không chen vào bảng điều khiển.

Mã thiết bị ghép từ 6 ký tự cuối địa chỉ MAC (pw_relay_…), nên nạp cùng chương trình cho nhiều mạch thì mỗi mạch là một thiết bị riêng. Tin cấu hình dài gần 400 byte, lớn hơn bộ đệm 256 byte mặc định của PubSubClient, vì vậy phải có mqtt.setBufferSize(1024).

Trạng thái kết nối và di chúc (last will)

Lúc kết nối, ESP32 gửi kèm "di chúc": chủ đề ket_noi, nội dung offline. Nếu ESP32 mất điện hoặc mất Wi-Fi, máy chủ MQTT tự đăng tin này, Home Assistant chuyển các thực thể sang không khả dụng thay vì hiện trạng thái cũ như thể vẫn đúng. Kết nối lại thì ESP32 đăng online.

Giữ lại trạng thái, gửi lại cấu hình khi Home Assistant khởi động

  • Tin trạng thái relay và ket_noi gửi với cờ retain: máy chủ giữ tin cuối, Home Assistant khởi động lại là có ngay trạng thái.
  • Tin cấu hình gửi không có retain. Thay vào đó ESP32 theo dõi homeassistant/status: mỗi lần Home Assistant khởi động, nó đăng online, ESP32 chờ ngẫu nhiên 0,5–3 giây rồi gửi lại cấu hình. Tài liệu MQTT của Home Assistant khuyên cách này hơn tin cấu hình có retain, vì tin cấu hình bị giữ lại trên máy chủ dễ làm thực thể đã xóa tự hiện lại.

Sau khi mất điện

ESP32 khởi động với mọi relay tắt và báo OFF lên Home Assistant. Muốn relay về trạng thái cũ, có thể lưu trạng thái bằng Preferences như bài lưu dữ liệu khi mất điện, rồi gửi trạng thái đó lên khi kết nối.

7. Kết quả

Trang thiết bị Relay PYWORLD vẽ kiểu chung: thông tin thiết bị, 4 công tắc Relay PYWORLD Kênh 1 đến 4, cảm biến cường độ Wi-Fi -58 dBm trong nhóm chẩn đoán
Thiết bị trong Home Assistant (vẽ kiểu chung, không phải ảnh chụp giao diện).

Vài giây sau khi ESP32 kết nối, vào Settings › Devices & services › MQTT sẽ thấy thiết bị "Relay PYWORLD". Tên thực thể là tên thiết bị cộng tên kênh, ví dụ "Relay PYWORLD Kênh 1", mã thực thể thường là switch.relay_pyworld_kenh_1. Các công tắc dùng được ngay trong bảng điều khiển, trên ứng dụng điện thoại và trong tự động hóa (ví dụ bật Kênh 1 lúc mặt trời lặn, tắt lúc 23 giờ).

Serial Monitor: kết nối Wi-Fi, kết nối MQTT, gửi cấu hình discovery 5 trên 5 thực thể, nhận lệnh bật Kênh 2, nút nhấn bật Kênh 1, Home Assistant khởi động lại thì gửi lại cấu hình; khung thứ hai báo MQTT lỗi 5 khi sai tài khoản
Serial Monitor ở tốc độ 115200 (số liệu ví dụ).

Muốn xem các tin đang đi qua máy chủ, trong trang cấu hình của tích hợp MQTT có mục nghe một chủ đề (Listen to a topic): gõ pyworld/# để xem mọi tin của các mạch trong bài.

8. Lưu ý

  • Chỉ dùng trong mạng nhà: cổng 1883 không mã hóa. Không mở cổng này ra Internet trên modem; điều khiển từ xa thì dùng cách truy cập từ xa của Home Assistant.
  • Xóa thiết bị: có thể xóa thiết bị MQTT trong trang thiết bị của Home Assistant, nhưng ESP32 còn chạy thì lần kết nối sau nó gửi lại cấu hình và thiết bị hiện lại. Muốn bỏ hẳn thì tháo mạch hoặc nạp chương trình khác.
  • Đổi tên kênh: đổi ngay trên Home Assistant (nhờ unique_id), không phải sửa chương trình. Đổi unique_id trong code sẽ tạo thực thể mới.
  • Máy chủ MQTT khác: Home Assistant yêu cầu máy chủ hỗ trợ MQTT 5; Mosquitto 2 có hỗ trợ và vẫn nhận các mạch dùng MQTT 3.1.1 như PubSubClient.

9. Xử lý lỗi thường gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Serial báo "MQTT loi 4" hoặc "MQTT loi 5"Sai tên đăng nhập, mật khẩu, hoặc tài khoản không được phépKiểm tra tài khoản ở bước 4; thử đăng nhập Home Assistant bằng tài khoản đó
Serial báo "MQTT loi -2"Sai IP máy chủ, Mosquitto chưa chạy, khác mạngKiểm tra IP máy Home Assistant, trạng thái Mosquitto, ESP32 và máy chủ cùng mạng
Kết nối được nhưng Home Assistant không hiện thiết bịChưa thêm tích hợp MQTT, hoặc tin cấu hình không gửi đượcThêm tích hợp MQTT; nghe chủ đề homeassistant/# xem tin có tới không; giữ setBufferSize(1024)
Thực thể hiện "không khả dụng"ESP32 mất kết nối, máy chủ đã đăng tin di chúcXem Serial Monitor; kiểm tra Wi-Fi tại chỗ đặt mạch
Bấm công tắc, relay không đổiSai chân, module chưa có nguồn 5 V, chủ đề lệnh khácXem Serial có dòng "Nhan …/dat" không; kiểm tra dây IN và VCC
Hai mạch giành nhau một thiết bị, liên tục mất kết nốiHai mạch cùng client ID (đã sửa tay mã thiết bị giống nhau)Giữ mã thiết bị theo địa chỉ MAC như chương trình

10. Xem thêm


Tin tức liên quan

Hướng dẫn bắt đầu MicroPython trên ESP32 Lite với Thonny
Hướng dẫn bắt đầu MicroPython trên ESP32 Lite với Thonny

Hướng dẫn cài driver, cài Thonny và nạp firmware MicroPython cho mạch ESP32 Lite, dùng REPL, nháy LED, lưu main.py, đọc nút nhấn, quét I2C và xử lý lỗi thường gặp.

Xe robot ESP32 điều khiển bằng điện thoại qua Wi-Fi: không cần router, không cần cài ứng dụng
Xe robot ESP32 điều khiển bằng điện thoại qua Wi-Fi: không cần router, không cần cài ứng dụng

Làm xe robot hai bánh với ESP32 và L298N, điều khiển bằng trình duyệt điện thoại qua Wi-Fi do ESP32 phát ra: bố trí, nối dây, code web, tự dừng khi mất sóng, lái vi sai, STEM.

DHT11 và DHT22 với ESP32: đọc nhiệt độ, độ ẩm không cần thư viện, giao thức 40 bit và điểm sương
DHT11 và DHT22 với ESP32: đọc nhiệt độ, độ ẩm không cần thư viện, giao thức 40 bit và điểm sương

So sánh DHT11 và DHT22, nối dây với ESP32, giải thích giao thức một dây 40 bit và checksum, chương trình đọc nhiệt độ, độ ẩm không cần thư viện, kèm điểm sương và bảng lỗi.

Từ breadboard đến thiết bị dùng thật: đưa ESP32 vào hộp, khoan lỗ jack Type-C, GX16, jack DC
Từ breadboard đến thiết bị dùng thật: đưa ESP32 vào hộp, khoan lỗ jack Type-C, GX16, jack DC

Đưa dự án ESP32 từ breadboard vào hộp: cấp nguồn USB 5 V hoặc adapter 12 V qua LM2596, bố trí linh kiện, khoan lỗ jack Type-C, jack DC, GX16 và chương trình hộp relay có nút nhấn.

Phát hiện chuyển động bằng cảm biến PIR HC-SR501 với ESP32: tự bật đèn qua relay
Phát hiện chuyển động bằng cảm biến PIR HC-SR501 với ESP32: tự bật đèn qua relay

Hướng dẫn dùng cảm biến chuyển động PIR HC-SR501 với ESP32: nguyên lý, cách chỉnh module, đọc tín hiệu bằng ngắt và ghép relay làm đèn tự bật khi có người, tự tắt sau 60 giây.

LED ma trận MAX7219 và LED 7 đoạn TM1637 với ESP32: chữ chạy 32 × 8 và đồng hồ, không cần thư viện
LED ma trận MAX7219 và LED 7 đoạn TM1637 với ESP32: chữ chạy 32 × 8 và đồng hồ, không cần thư viện

So sánh LED ma trận MAX7219 và LED 7 đoạn TM1637, nối với ESP32 an toàn mức điện áp, giải thích khung 16 bit và ba lệnh TM1637, hai chương trình chữ chạy và đồng hồ không cần thư viện.

ESPHome cho ESP32: đưa relay 4 kênh vào Home Assistant không cần viết code Arduino
ESPHome cho ESP32: đưa relay 4 kênh vào Home Assistant không cần viết code Arduino

Dùng ESPHome Device Builder khai báo relay 4 kênh, nút nhấn, cảm biến Wi-Fi bằng YAML; nạp lần đầu qua USB, sau đó qua Wi-Fi; so sánh với cách Arduino + MQTT.

Vẽ đồ thị dữ liệu ESP32 trên ThingSpeak: theo dõi pin 18650, ngủ sâu và ước tính thời gian chạy pin
Vẽ đồ thị dữ liệu ESP32 trên ThingSpeak: theo dõi pin 18650, ngủ sâu và ước tính thời gian chạy pin

ESP32 chạy pin 18650 thức dậy mỗi 10 phút, đo điện áp pin, gửi lên ThingSpeak rồi ngủ sâu; cách tạo kênh, ước tính thời gian chạy pin và giảm dòng lúc ngủ.


Bình luận
Đã thêm vào giỏ hàng