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
- 1. Vì sao phải cho ESP32 ngủ sâu
- 2. Chuẩn bị
- 3. Mạch đo điện áp pin
- 4. Tạo kênh ThingSpeak
- 5. Chương trình
- 6. Giải thích các phần chính
- Mọi việc nằm trong setup()
- Đo pin trước khi bật Wi-Fi
- Giới hạn thời gian chờ Wi-Fi
- Gửi lên ThingSpeak
- Ngủ và pin yếu
- 7. Kết quả
- 8. Giảm dòng lúc ngủ
- 9. Xử lý lỗi thường gặp
- 10. Xem thêm
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

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.

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ị
- Mạch ESP32 tích hợp pin 18650 và mạch quản lý pin, hoặc ESP32 DevKit V1 cấp nguồn bằng mô đun pin 18650.
- Pin Li-ion 18650 và khay pin nếu dùng pin rời.
- Hai điện trở 100 kΩ làm cầu phân áp đo pin.
- Tài khoản ThingSpeak (miễn phí cho mục đích phi thương mại).
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

- Đăng ký tài khoản tại thingspeak.mathworks.com (dùng chung tài khoản MathWorks).
- Vào Channels > My Channels > New Channel, đặt tên kênh.
- Đá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.
- 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ả


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ượng | Nguyên nhân thường gặp | Cá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ây | Chép lại Write API Key; khi thử, đừng bấm EN liên tục |
| HTTP số âm, ví dụ -1 | Wi-Fi yếu, mạng chặn HTTPS | Xem trường field2 (RSSI), đưa mạch lại gần modem |
| "Khong vao duoc Wi-Fi" liên tục | Sai mật khẩu, modem phát 5 GHz, hoặc pin yếu làm ESP32 không phát nổi | Kiểm tra Wi-Fi 2,4 GHz; sạc pin |
| Số lần thức về 1 | Mạ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ình | Kiể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ều | Dò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 sai | Cầ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
- Mạch ESP32 tích hợp OLED 0.96 và pin 18650: sơ đồ chân, sạc pin
- Cấp nguồn cho ESP32 đúng cách
- Các bài cùng loạt: ghi dữ liệu lên Google Sheets, gửi cảnh báo qua Telegram khi pin yếu.
Xem thêm