Praktikum IoT Tahan Putus: ESP32 Preferences, Pending Telemetry, dan Retry MQTT
Latihan membuat node ESP32 lebih resilien: simpan telemetry pending di NVS Preferences, retry MQTT terjadwal, dan kirim ulang setelah koneksi pulih.
Artikel ini disusun sebagai panduan teknis Ruang IoT. Gunakan daftar isi untuk berpindah antarbagian dan ikuti langkah secara berurutan ketika artikel memuat praktik atau konfigurasi.
Koneksi Wi-Fi dan MQTT tidak selalu tersedia. Node IoT yang baik harus dapat membedakan kegagalan jaringan dari kegagalan sensor dan tidak kehilangan seluruh konteks ketika restart. Praktikum ini menunjukkan pola sederhana: simpan satu sampel telemetry yang belum terkirim ke NVS menggunakan Preferences, lakukan reconnect dengan interval, dan hapus data pending hanya setelah publish berhasil.
Tujuan praktikum
- Memahami fungsi NVS/Preferences untuk data kecil yang bertahan setelah restart.
- Menghindari reconnect loop yang terlalu agresif.
- Menyimpan satu telemetry pending ketika broker tidak tersedia.
- Mengirim ulang setelah koneksi pulih.
Catatan desain
Preferences cocok untuk nilai kecil, bukan untuk log telemetry berukuran besar. Praktikum ini hanya menyimpan satu sampel terakhir yang belum terkirim. Jika Anda membutuhkan antrean panjang, gunakan filesystem, database lokal, atau arsitektur buffer yang memang dirancang untuk write endurance dan volume data tersebut.
Program penyimpanan pending sample
#include <Preferences.h>
Preferences prefs;
void savePending(float value) {
prefs.begin("telemetry", false);
prefs.putBool("pending", true);
prefs.putFloat("value", value);
prefs.putULong("sample_ms", millis());
prefs.end();
}
bool loadPending(float &value, uint32_t &sampleMs) {
prefs.begin("telemetry", true);
bool pending = prefs.getBool("pending", false);
if (pending) {
value = prefs.getFloat("value", NAN);
sampleMs = prefs.getULong("sample_ms", 0);
}
prefs.end();
return pending;
}
void clearPending() {
prefs.begin("telemetry", false);
prefs.putBool("pending", false);
prefs.end();
}Gabungkan dengan MQTT
unsigned long nextReconnectAt = 0;
const unsigned long RETRY_MS = 5000;
void serviceMqtt() {
if (mqtt.connected()) {
mqtt.loop();
return;
}
if (millis() < nextReconnectAt) return;
nextReconnectAt = millis() + RETRY_MS;
if (mqtt.connect("esp32-resilient")) {
float v; uint32_t sampleMs;
if (loadPending(v, sampleMs)) {
char payload[96];
snprintf(payload, sizeof(payload),
"{\"value\":%.2f,\"sample_ms\":%lu,\"replayed\":true}",
v, sampleMs);
if (mqtt.publish("lab/resilient/telemetry", payload)) {
clearPending();
}
}
}
}
void sendSample(float value) {
char payload[64];
snprintf(payload, sizeof(payload), "{\"value\":%.2f}", value);
if (!mqtt.connected() || !mqtt.publish("lab/resilient/telemetry", payload)) {
savePending(value);
}
}Skenario uji gangguan
- Jalankan node dengan broker aktif dan pastikan publish normal.
- Matikan koneksi Wi-Fi atau broker.
- Buat satu sampel baru; pastikan program menyimpannya sebagai pending.
- Restart ESP32 ketika jaringan masih putus.
- Pulihkan jaringan dan pastikan sample pending dikirim ulang.
- Periksa bahwa flag pending dihapus hanya setelah publish sukses.
Keterbatasan yang harus dipahami
Sampel ini menyimpan millis(), yang hanya menunjukkan waktu relatif sejak boot dan tidak sama dengan waktu kalender. Bila butuh timestamp absolut, gunakan sinkronisasi waktu (misalnya NTP) dan simpan epoch timestamp. Selain itu, pola satu-slot akan mengganti data pending lama bila banyak sampel dihasilkan selama offline; untuk kebutuhan itu Anda memerlukan queue.
Kriteria keberhasilan
Sensor tetap dapat bekerja saat jaringan putus, loop tidak macet pada reconnect tanpa batas, satu sample pending bertahan setelah restart, dan data hanya dihapus setelah server menerima publish yang dianggap sukses oleh client.
Referensi resmi dan bacaan lanjut
Gunakan dokumentasi resmi berikut untuk memeriksa API, kompatibilitas board, dan perubahan versi library:
Sudah memahami alurnya?
Praktikkan konsep yang baru dipelajari melalui project, perangkat ESP32, telemetry, dashboard, atau Virtual Lab di Ruang IoT.