Thiết bị không phải lúc nào cũng online. Vì vậy ngoài realtime MQTT, bạn cần thêm khả năng ghi log vào thẻ nhớ MicroSD để:
- Lưu dữ liệu khi mất WiFi/MQTT
- Ghi lịch sử để debug
- Đồng bộ lại khi online (sẽ làm sâu hơn ở các bài store-and-forward)
Bài này gồm 2 phần code:
- Ghi log CSV vào thẻ MicroSD
- Vừa ghi log vừa publish MQTT realtime lên IoTLabs Cloud
1. MicroSD trong IoT dùng để làm gì?
MicroSD thường dùng cho:
- Data logger (nhiệt độ, độ ẩm, áp suất…)
- Lưu event (RFID scan, door open…)
- Lưu cấu hình/backup
- Lưu “queue” dữ liệu để sync sau
👉 Đây là nền tảng để thiết bị chạy bền – không mất dữ liệu.
2. Chuẩn bị phần cứng & lưu ý quan trọng
Thiết bị
- ESP32-C3 SuperMini
- Module MicroSD (SPI)
- Thẻ MicroSD (FAT32)
Lưu ý nguồn
- MicroSD có thể “hút dòng” lúc ghi → nếu reset ngẫu nhiên:
- dùng nguồn ổn định
- dây ngắn, GND tốt
- thêm tụ 100µF gần module (nếu cần)
3. Nối dây MicroSD (SPI)
MicroSD module thường có các chân: CS, SCK, MOSI, MISO, VCC, GND
Kết nối SPI (theo cùng nhóm với bài RC522 để dễ nhớ):
| MicroSD | ESP32-C3 |
|---|---|
| CS | GPIO10 |
| SCK | GPIO6 |
| MOSI | GPIO7 |
| MISO | GPIO2 |
| VCC | 3.3V |
| GND | GND |
📌 Nếu bạn đang dùng RC522 cùng SPI: phải dùng CS khác nhau (mỗi thiết bị 1 CS).
4. Format log đề xuất (CSV)
Mỗi dòng = 1 bản ghi:
ts,temperature,humidity,note
1760000000,26.8,63.2,ok
CSV có lợi:
- Mở bằng Excel nhanh
- Debug dễ
- Nhẹ và phù hợp IoT
5. Ví dụ 1: Ghi log vào MicroSD (CSV)
#include <SPI.h>
#include <SD.h>
#define SD_CS 10
bool sdReady = false;
void setup() {
Serial.begin(115200);
SPI.begin(6, 2, 7, SD_CS); // SCK, MISO, MOSI, SS/CS
if (!SD.begin(SD_CS)) {
Serial.println("SD init failed");
return;
}
sdReady = true;
Serial.println("SD ready");
// Tạo header nếu file chưa có
if (!SD.exists("/log.csv")) {
File f = SD.open("/log.csv", FILE_WRITE);
if (f) {
f.println("ts,temperature,humidity,note");
f.close();
}
}
}
void loop() {
if (!sdReady) {
delay(2000);
return;
}
long ts = millis() / 1000; // demo: sau sẽ thay bằng RTC
float temperature = random(200, 350) / 10.0;
float humidity = random(400, 800) / 10.0;
String line = String(ts) + "," +
String(temperature, 1) + "," +
String(humidity, 1) + ",ok";
File f = SD.open("/log.csv", FILE_APPEND);
if (f) {
f.println(line);
f.close();
Serial.println("Wrote: " + line);
} else {
Serial.println("Open file failed");
}
delay(5000);
}
6. Chuẩn dữ liệu realtime MQTT (nhắc lại)
{
"ts": 1760000000,
"metrics": {
"temperature": 26.8,
"humidity": 63.2
}
}
7. Ví dụ 2: Vừa ghi log MicroSD vừa publish MQTT realtime
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <SD.h>
#define SD_CS 10
// ===== WIFI / MQTT CONFIG =====
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_PASS";
const char* MQTT_HOST = "mqtt.iotlabs.vn";
const int MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_MQTT_USER";
const char* MQTT_PASS = "YOUR_MQTT_PASS";
const char* MQTT_TOPIC =
"iotlabs/<orgId>/devices/<deviceId>/telemetry";
WiFiClientSecure net;
PubSubClient mqtt(net);
bool sdReady = false;
unsigned long lastSend = 0;
void connectWiFi() {
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
}
void connectMQTT() {
net.setInsecure();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
while (!mqtt.connected()) {
mqtt.connect("esp32c3-sdlog", MQTT_USER, MQTT_PASS);
delay(1000);
}
}
void setupSD() {
SPI.begin(6, 2, 7, SD_CS);
if (!SD.begin(SD_CS)) {
Serial.println("SD init failed");
return;
}
sdReady = true;
if (!SD.exists("/log.csv")) {
File f = SD.open("/log.csv", FILE_WRITE);
if (f) {
f.println("ts,temperature,humidity");
f.close();
}
}
Serial.println("SD ready");
}
void appendCSV(long ts, float t, float h) {
if (!sdReady) return;
String line = String(ts) + "," + String(t, 1) + "," + String(h, 1);
File f = SD.open("/log.csv", FILE_APPEND);
if (f) {
f.println(line);
f.close();
}
}
void setup() {
Serial.begin(115200);
setupSD();
connectWiFi();
connectMQTT();
}
void loop() {
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
if (millis() - lastSend > 5000) {
lastSend = millis();
long ts = millis() / 1000; // demo: bài sau sẽ thay bằng DS3231
float t = random(200, 350) / 10.0;
float h = random(400, 800) / 10.0;
// 1) Log vào SD
appendCSV(ts, t, h);
// 2) Publish realtime
String payload = "{";
payload += "\"ts\":" + String(ts) + ",";
payload += "\"metrics\":{";
payload += "\"temperature\":" + String(t, 1) + ",";
payload += "\"humidity\":" + String(h, 1);
payload += "}}";
mqtt.publish(MQTT_TOPIC, payload.c_str());
Serial.println(payload);
}
}
8. Kinh nghiệm thực tế để log ổn định
- Dùng FAT32, format thẻ trước khi test
- Ghi theo chu kỳ (5–60s) thay vì ghi liên tục
- Tránh mở/đóng file quá thường xuyên (bài tối ưu sau)
- Nếu cần độ tin cậy cao:
- thêm RTC DS3231 để timestamp “đúng”
- chuẩn bị “queue file” để sync khi online
9. Tổng kết
Sau bài này, bạn đã:
- Biết dùng MicroSD để ghi log dữ liệu
- Kết hợp log offline + MQTT realtime
- Có nền tảng để làm bước tiếp theo: store-and-forward
👉 Gợi ý mở rộng:
- “Đồng bộ log MicroSD lên Cloud khi có mạng”
- “Thiết kế queue file chống mất dữ liệu”


