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ủ.

Khi ESP32 chạy pin ở chỗ không có ổ điện (vườn, kho, bể nước trên mái), cần biết pin còn bao nhiêu và tụt nhanh hay chậm. ThingSpeak là dịch vụ IoT của MathWorks: ESP32 gửi số liệu bằng một lệnh HTTPS, ThingSpeak tự lưu và vẽ đồ thị, xem được trên điện thoại. Bài này dựng một mạch ESP32 chạy pin 18650: mỗi 10 phút thức dậy, đo điện áp pin, gửi lên ThingSpeak rồi ngủ sâu; kèm cách tạo kênh, ước tính pin chạy được bao lâu và những chỗ làm hao pin khi ngủ.

1. Vì sao phải cho ESP32 ngủ sâu

Đồ thị dòng tiêu thụ một chu kỳ: thức 4 giây khoảng 110 mA để đo pin, vào Wi-Fi, gửi HTTPS, rồi ngủ sâu 596 giây khoảng 0,15 mA; đường đứt nét cho mạch có chip USB ngủ vẫn tốn vài mA
Dòng tiêu thụ trong một chu kỳ 10 phút, số giả định (hình minh họa).

Khi Wi-Fi bật, ESP32 tốn khoảng 80–150 mA. Một pin 18650 2600 mAh chỉ nuôi được chưa tới một ngày. Ở chế độ ngủ sâu (Deep Sleep), gần như toàn bộ chip tắt, chỉ còn bộ hẹn giờ RTC chạy để đánh thức. Thời gian thức mỗi lần chỉ vài giây, nên dòng trung bình giảm hàng trăm lần.

Ước tính thời gian chạy pin 18650: luôn bật Wi-Fi khoảng 19 giờ; ngủ sâu trên mạch có chip USB và đèn nguồn khoảng 10 ngày; ngủ sâu trên mạch tối ưu khoảng 98 ngày
Thời gian chạy ước tính cho ba trường hợp, số liệu giả định (hình minh họa).

Hình trên cho thấy điều quan trọng nhất: khi đã cho chip ngủ, dòng lúc ngủ của cả mạch quyết định pin chạy được bao lâu. ESP32 DevKit có chip chuyển USB, mạch ổn áp và đèn nguồn luôn sáng; các linh kiện này vẫn tốn dòng khi chip ESP32 đã ngủ. Cách tính: dòng trung bình = (dòng lúc thức × thời gian thức + dòng lúc ngủ × thời gian ngủ) / chu kỳ; số giờ chạy = dung lượng dùng được / dòng trung bình. Muốn biết chính xác, đo dòng bằng đồng hồ vạn năng mắc nối tiếp với pin.

2. Chuẩn bị

3. Mạch đo điện áp pin

Cực dương pin nối qua điện trở 100 kΩ tới GPIO35, từ GPIO35 qua điện trở 100 kΩ thứ hai xuống GND; GND của pin và ESP32 nối chung. Pin đầy 4,2 V thì GPIO35 nhận 2,1 V; chương trình nhân lại 2. Hình sơ đồ và cách đọc ADC xem bài đo điện áp pin 18650 bằng ADC và bài ghi dữ liệu lên Google Sheets cùng loạt (cùng mạch). Cách nối pin với ESP32 xem bài cấp nguồn ESP32 bằng pin 18650.

4. Tạo kênh ThingSpeak

Bốn bước tạo kênh ThingSpeak: tạo tài khoản, New Channel, bật 4 trường, chép Write API Key; bảng field1 Pin V, field2 Wi-Fi dBm, field3 số lần thức, field4 thời gian kết nối ms
Bốn bước tạo kênh và bốn trường dữ liệu của chương trình mẫu (hình minh họa).
  1. Đăng ký tài khoản tại thingspeak.mathworks.com (dùng chung tài khoản MathWorks).
  2. Vào Channels > My Channels > New Channel, đặt tên kênh.
  3. Đánh dấu Field 1 đến Field 4, đặt tên lần lượt: Pin (V), Wi-Fi (dBm), Số lần thức, Kết nối (ms). Bấm Save Channel.
  4. Mở thẻ API Keys, chép Write API Key dán vào hằng WRITE_API_KEY.

Gói miễn phí cho tối đa 4 kênh, mỗi kênh ghi cách nhau ít nhất 15 giây, khoảng 3 triệu bản ghi mỗi năm và chỉ dùng cho mục đích phi thương mại. Mỗi 10 phút một bản ghi là khoảng 52 500 bản ghi một năm, còn rất xa giới hạn.

5. Chương trình

Chương trình chỉ dùng thư viện có sẵn trong gói esp32 (bài dùng phiên bản 3.3.10). Điền Wi-Fi 2,4 GHz và Write API Key, chọn bo ESP32 Dev Module rồi nạp.

// PYWORLD.VN - ESP32 chạy pin 18650: thức dậy mỗi 10 phút, gửi điện áp pin lên ThingSpeak rồi ngủ sâu
// Bo mạch: ESP32 DevKit V1 hoặc mạch ESP32 tích hợp pin 18650; cầu phân áp 100 kΩ / 100 kΩ đo pin ở GPIO35
// Gửi bằng HTTPClient (HTTPS) tới api.thingspeak.com/update, mỗi lần thức một bản ghi gồm 4 trường

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <esp_sleep.h>

const char *TEN_WIFI = "TEN_WIFI";
const char *MAT_KHAU_WIFI = "MAT_KHAU_WIFI";
const char *WRITE_API_KEY = "MA_GHI_CUA_KENH";  // Thẻ API Keys của kênh ThingSpeak, mục Write API Key

const uint8_t CHAN_PIN = 35;
const float HE_SO_CAU = 2.0;                   // Cầu 100 kΩ / 100 kΩ
const uint32_t NGU_BINH_THUONG_PHUT = 10;       // Thức dậy mỗi 10 phút
const uint32_t NGU_PIN_YEU_PHUT = 60;           // Pin yếu: thưa ra để kéo dài thời gian chạy
const uint32_t NGUONG_PIN_YEU_MV = 3400;
const uint32_t CHO_WIFI_MS = 15000;             // Không vào được Wi-Fi sau 15 giây thì ngủ tiếp, đỡ hao pin

RTC_DATA_ATTR uint32_t soLanThuc = 0;  // Biến trong bộ nhớ RTC: còn giữ qua mỗi lần ngủ sâu, mất khi mất nguồn

uint32_t docPinMv() {
  uint32_t tong = 0;
  for (uint8_t i = 0; i < 16; i++) tong += analogReadMilliVolts(CHAN_PIN);
  return (uint32_t)(tong / 16 * HE_SO_CAU);
}

void diNgu(uint32_t phut) {
  Serial.printf("Ngu %u phut\n", (unsigned)phut);
  Serial.flush();
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  esp_sleep_enable_timer_wakeup((uint64_t)phut * 60ULL * 1000000ULL);  // Đơn vị micro giây
  esp_deep_sleep_start();                                               // Sau khi thức, chương trình chạy lại từ setup()
}

void setup() {
  unsigned long batDau = millis();
  Serial.begin(115200);
  soLanThuc++;
  uint32_t pinMv = docPinMv();  // Đo trước khi bật Wi-Fi: lúc phát sóng, điện áp pin tụt tạm thời
  Serial.printf("Lan thuc %u, pin %u mV\n", (unsigned)soLanThuc, (unsigned)pinMv);

  WiFi.mode(WIFI_STA);
  WiFi.begin(TEN_WIFI, MAT_KHAU_WIFI);
  while (WiFi.status() != WL_CONNECTED && millis() - batDau < CHO_WIFI_MS) {
    delay(100);
  }
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Khong vao duoc Wi-Fi");
    diNgu(NGU_BINH_THUONG_PHUT);
  }
  uint32_t msKetNoi = millis() - batDau;

  WiFiClientSecure tls;
  tls.setInsecure();  // Có mã hóa nhưng không kiểm tra chứng chỉ (xem giải thích trong bài)
  HTTPClient http;
  char url[200];
  snprintf(url, sizeof(url), "https://api.thingspeak.com/update?api_key=%s&field1=%.2f&field2=%d&field3=%u&field4=%u",
           WRITE_API_KEY, pinMv / 1000.0, (int)WiFi.RSSI(), (unsigned)soLanThuc, (unsigned)msKetNoi);
  http.begin(tls, url);
  int ma = http.GET();
  String traVe = (ma > 0) ? http.getString() : HTTPClient::errorToString(ma);
  http.end();
  Serial.printf("ThingSpeak: HTTP %d, ma ban ghi %s\n", ma, traVe.c_str());  // 0 nghĩa là bị từ chối

  diNgu(pinMv < NGUONG_PIN_YEU_MV ? NGU_PIN_YEU_PHUT : NGU_BINH_THUONG_PHUT);
}

void loop() {
  // Không dùng: ESP32 ngủ sâu ở cuối setup(), thức dậy thì chạy lại setup()
}

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

Mọi việc nằm trong setup()

Thức dậy sau ngủ sâu, ESP32 chạy lại từ đầu như vừa bật nguồn: setup() chạy, làm hết việc rồi gọi diNgu(); loop() không bao giờ được chạy tới. Biến thường mất hết mỗi lần ngủ, trừ biến khai báo RTC_DATA_ATTR nằm trong bộ nhớ RTC: soLanThuc tăng dần qua các lần thức và chỉ về 0 khi mất nguồn hẳn.

Đo pin trước khi bật Wi-Fi

Lúc ESP32 phát sóng, dòng tăng vọt làm điện áp pin tụt tạm thời vài chục mV. Đo trước khi bật Wi-Fi cho số liệu ổn định, so sánh được giữa các lần.

Giới hạn thời gian chờ Wi-Fi

Modem mất điện hay ở xa thì ESP32 có thể chờ mãi và cạn pin. Chương trình chỉ chờ 15 giây (CHO_WIFI_MS), không được thì ngủ tiếp. Trường field4 ghi thời gian vào Wi-Fi để biết mạch có đang chờ lâu bất thường không; đặt IP tĩnh theo bài kết nối Wi-Fi trên ESP32 thường rút ngắn được thời gian này.

Gửi lên ThingSpeak

Một lệnh GET tới https://api.thingspeak.com/update?api_key=…&field1=… là ghi xong một bản ghi. ThingSpeak trả về số thứ tự bản ghi; trả về 0 nghĩa là bị từ chối (sai khóa, hoặc ghi lại trong vòng 15 giây). Kết nối dùng HTTPS với setInsecure(): có mã hóa nhưng không kiểm tra chứng chỉ máy chủ, đổi lại kém an toàn trước mạng Wi-Fi không tin cậy.

Ngủ và pin yếu

esp_sleep_enable_timer_wakeup() nhận thời gian tính bằng micro giây, nên 10 phút là 600 000 000; chương trình nhân bằng số 64 bit để không bị tràn. Khi pin dưới 3400 mV, chương trình chuyển sang thức mỗi 60 phút để kéo dài thời gian còn lại. Pin Li-ion không nên xả quá sâu; mạch quản lý pin thường tự ngắt ở khoảng 2,5–3 V.

7. Kết quả

Đồ thị điện áp pin trường field1 trong 48 giờ, giảm dần từ khoảng 4,10 V xuống 3,91 V
Đồ thị trường Pin (V) sau hai ngày, số liệu minh họa.
Serial Monitor: mỗi lần thức in số lần thức và điện áp pin, kết quả gửi ThingSpeak với mã bản ghi, rồi ngủ 10 phút; trường hợp mã 0 và pin yếu ngủ 60 phút
Serial Monitor ở tốc độ 115200 (số liệu ví dụ).

Mở kênh trên ThingSpeak, thẻ Private View có sẵn bốn đồ thị, tự thêm điểm mới mỗi lần ESP32 gửi. Muốn người khác xem mà không cần đăng nhập, bật thẻ Public View. Khi chạy pin thật, Serial Monitor không cần thiết; cắm USB để xem chỉ khi thử chương trình.

8. Giảm dòng lúc ngủ

  • Chọn mạch phù hợp: mạch không có đèn nguồn sáng liên tục, chip USB không lấy nguồn từ pin. Với ESP32 DevKit, có thể cắt đèn nguồn; chip USB và mạch ổn áp vẫn tốn dòng nên không đạt mức của mạch tối ưu.
  • Cầu phân áp lớn hơn: 1 MΩ + 1 MΩ chỉ hao khoảng 2 µA, nên thêm tụ 100 nF từ GPIO35 xuống GND để ADC đọc ổn định.
  • Thức ngắn hơn: IP tĩnh, gửi ít dữ liệu, chu kỳ dài hơn khi không cần dữ liệu dày.
  • Đo thật: đồng hồ vạn năng thang mA mắc nối tiếp với pin, đọc lúc ngủ và lúc thức, rồi tính lại theo công thức ở mục 1.

Cơ chế ngủ sâu, các cách đánh thức (hẹn giờ, nút nhấn, chân cảm ứng) xem bài Deep Sleep tiết kiệm pin.

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

Hiện tượngNguyên nhân thường gặpCách xử lý
"ma ban ghi 0"Sai Write API Key (lấy nhầm Read Key), hoặc hai lần ghi cách nhau dưới 15 giâyChép lại Write API Key; khi thử, đừng bấm EN liên tục
HTTP số âm, ví dụ -1Wi-Fi yếu, mạng chặn HTTPSXem trường field2 (RSSI), đưa mạch lại gần modem
"Khong vao duoc Wi-Fi" liên tụcSai mật khẩu, modem phát 5 GHz, hoặc pin yếu làm ESP32 không phát nổiKiểm tra Wi-Fi 2,4 GHz; sạc pin
Số lần thức về 1Mạch mất nguồn hẳn (pin cạn, lỏng tiếp xúc) hoặc vừa nạp lại chương trìnhKiểm tra pin và khay; biến RTC chỉ giữ qua ngủ sâu, không giữ qua mất nguồn
Pin cạn nhanh hơn ước tính nhiềuDòng lúc ngủ của mạch lớn (đèn nguồn, chip USB, mạch ổn áp)Đo dòng lúc ngủ, xem mục 8
Điện áp pin đo saiCầu phân áp chưa nối đúng, thiếu GND chungĐo điểm giữa cầu bằng đồng hồ: phải bằng nửa điện áp pin

10. Xem thêm


Tin tức liên quan

Cánh tay robot 4 servo với ESP32: điều khiển bằng biến trở, ghi nhớ và phát lại động tác
Cánh tay robot 4 servo với ESP32: điều khiển bằng biến trở, ghi nhớ và phát lại động tác

Làm cánh tay robot 4 servo với ESP32: điều khiển từng khớp bằng biến trở, nhấn nút ghi tư thế, phát lại chuỗi động tác mượt, lưu vào flash khi mất điện và gợi ý STEM.

Phát hiện chuyển động bằng sóng Wi-Fi (CSI) trên ESP32: không cần cảm biến
Phát hiện chuyển động bằng sóng Wi-Fi (CSI) trên ESP32: không cần cảm biến

Giải thích Wi-Fi CSI và hướng dẫn dùng ESP32 phát hiện người di chuyển trong phòng chỉ bằng sóng Wi-Fi từ router: lấy dữ liệu CSI, tính điểm chuyển động, đặt ngưỡng và xem trên Serial Plotter.

Hướng dẫn sử dụng màn hình LCD 1602 I2C với Arduino Uno
Hướng dẫn sử dụng màn hình LCD 1602 I2C với Arduino Uno

Hướng dẫn nối màn hình LCD 1602 I2C với Arduino Uno, cài thư viện LiquidCrystal_I2C, chạy code hiển thị và quét địa chỉ I2C 0x27/0x3F.

Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano
Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano

Hướng dẫn nối màn hình OLED 0.96 inch SSD1306 (I2C) với Arduino Nano, cài thư viện Adafruit, hiện chữ nhiều cỡ, vẽ thanh mức theo điện áp và lưu ý về bộ nhớ RAM.

Đế ra chân ESP32 30 chân: cấp nguồn DC 6,5–16 V, hàng chân G V S và jumper chọn 5 V hay 3,3 V
Đế ra chân ESP32 30 chân: cấp nguồn DC 6,5–16 V, hàng chân G V S và jumper chọn 5 V hay 3,3 V

Cách dùng đế ra chân ESP32 30 chân: cấu tạo, cắm ESP32 đúng chiều, cấp nguồn jack DC 6,5–16 V và tính nhiệt IC ổn áp, hàng G V S, jumper 5V/3.3V, ví dụ relay và nút nhấn.

Hướng dẫn dùng màn hình OLED 1.3 inch SH1106 với ESP32
Hướng dẫn dùng màn hình OLED 1.3 inch SH1106 với ESP32

Hướng dẫn nối màn hình OLED 1.3 inch SH1106 với ESP32 DevKit V1 qua I2C, cài thư viện Adafruit SH110X, chạy code hiển thị chữ và xử lý lỗi thường gặp.

ESP32 điều khiển động cơ bước 28BYJ-48 với ULN2003: nửa bước, quay đúng góc, kim giây
ESP32 điều khiển động cơ bước 28BYJ-48 với ULN2003: nửa bước, quay đúng góc, kim giây

Hướng dẫn điều khiển động cơ bước 28BYJ-48 bằng ESP32 qua mạch ULN2003: chế độ nửa bước, 4076 bước một vòng, quay đúng góc theo lệnh, kim giây đồng hồ và thí nghiệm STEM.

Làm gateway LoRa sang MQTT bằng ESP32: node cảm biến chạy pin gửi dữ liệu về broker
Làm gateway LoRa sang MQTT bằng ESP32: node cảm biến chạy pin gửi dữ liệu về broker

Hướng dẫn làm hệ thống LoRa hoàn chỉnh với ESP32 và SX1278: node chạy pin đo điện áp, gửi gói rồi ngủ sâu; gateway nhận gói LoRa và publish dữ liệu JSON lên broker MQTT qua Wi-Fi.


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