- Published on
Communication & State Thinking on ESP32
- Authors
π Foundation Article 7: Communication & State Thinking on ESP32
Track: C++ Firmware Engineering Foundations for ESP32 Environment: ESP32 + VSCode + Arduino Community Edition Project Base: IndustrialNode/IndustrialNode.ino Use Case: Generic Sensor + Relay Node
- π Foundation Article 7: Communication & State Thinking on ESP32
- 1οΈβ£ Komunikasi: Sumber Coupling Paling Sering
- 2οΈβ£ Communication Bukan Sekadar Publish/Subscribe
- 3οΈβ£ Visual: State Machine Konseptual
- 4οΈβ£ Event-Driven Thinking
- 5οΈβ£ Sensor + Relay Node dengan Komunikasi
- 6οΈβ£ Reconnect Chaos Tanpa Struktur
- 7οΈβ£ Transport β Business Logic
- 8οΈβ£ Implicit State vs Explicit State
- 9οΈβ£ Network Latency & Control Stability
- π Communication sebagai Layer Terpisah
- 11οΈβ£ Mental Model yang Harus Dikunci
1οΈβ£ Komunikasi: Sumber Coupling Paling Sering
Firmware kecil stabil tanpa komunikasi.
Masalah mulai muncul saat:
- WiFi ditambahkan
- MQTT ditambahkan
- OTA ditambahkan
- Remote config ditambahkan
Contoh klasik:
void callback(char* topic, byte* payload, unsigned int length) {
if (payload[0] == '1') {
digitalWrite(5, HIGH);
} else {
digitalWrite(5, LOW);
}
}
Masalah fundamental:
- Callback menyentuh hardware langsung.
- Tidak ada service boundary.
- Tidak ada domain guard.
- Tidak ada state awareness.
- Tidak ada arbitration dengan control loop.
Sekarang komunikasi menjadi:
Jalur pintas melanggar seluruh arsitektur.
Layering runtuh di satu callback.
Failure Model β Callback Menjadi God Function
Ketika fitur bertambah, callback berubah menjadi:
callback()
ββ parse payload
ββ set relay
ββ update threshold
ββ save config
ββ publish ack
ββ trigger OTA
ββ reset device
Sekarang:
- Business logic bercampur.
- Transport bercampur.
- Hardware bercampur.
- State tidak eksplisit.
- Debug menjadi sulit.
Komunikasi adalah sumber coupling paling sering karena ia menyentuh banyak domain sekaligus.
2οΈβ£ Communication Bukan Sekadar Publish/Subscribe
Engineer sering melihat komunikasi sebagai:
subscribe β callback β selesai
Padahal komunikasi memiliki lifecycle kompleks.
Lifecycle Nyata (ESP32 + WiFi + MQTT)
INIT
β
WIFI_CONNECTING
β
WIFI_CONNECTED
β
MQTT_CONNECTING
β
MQTT_CONNECTED
β
ERROR
β
BACKOFF
β
RETRY
Ini bukan teori. Ini realitas runtime.
Jika lifecycle tidak eksplisit:
- Reconnect tersebar.
- Flag global bermunculan.
- Behavior tidak deterministik.
- Race dengan control loop muncul.
3οΈβ£ Visual: State Machine Konseptual




Model konseptual yang sehat:
[INIT]
β
[WIFI_CONNECTING]
β
[WIFI_CONNECTED]
β
[MQTT_CONNECTING]
β
[MQTT_CONNECTED]
β
[ERROR_BACKOFF]
βΊ
Tanpa state machine eksplisit, developer sering menulis:
if (!wifiConnected) ...
if (!mqttConnected) ...
if (retryCount > 5) ...
Ini bukan state machine. Ini kondisi implisit yang saling tumpang tindih.
4οΈβ£ Event-Driven Thinking
Komunikasi menghasilkan event, bukan aksi langsung.
Daripada:
callback() β relay.set()
Lebih aman:
MQTT Callback β Event β Service β Driver
Pattern Sehat
void mqttCallback(...) {
commManager.handleIncoming(payload);
}
Lalu:
// di svc_CommManager
void CommManager::handleIncoming(...) {
eventQueue.push(Command::RelayOn);
}
Kemudian:
// di ControlService
void ControlService::processEvent(Command cmd) {
if (cmd == Command::RelayOn) {
relay_.set(true);
}
}
Sekarang:
- Transport tidak menyentuh hardware.
- Domain memutuskan aksi.
- Layering tetap utuh.
5οΈβ£ Sensor + Relay Node dengan Komunikasi
Mari kita lihat sistem kita.
Tanpa komunikasi:
loop()
β
app_ControlApp
β
svc_ControlService
β
drv_RelayDriver
Dengan komunikasi yang benar:
MQTT Task
β
svc_CommManager (state owner)
β
Event Queue
β
svc_ControlService
β
drv_RelayDriver
Komunikasi tidak boleh memotong langsung ke driver.
Kenapa Ini Penting?
Karena komunikasi:
- Asynchronous.
- Bisa delay.
- Bisa retry.
- Bisa duplicate (retain).
- Bisa reconnect.
- Bisa timeout.
Jika callback langsung menyentuh hardware:
Determinism kontrol rusak.
6οΈβ£ Reconnect Chaos Tanpa Struktur
Reconnect sering ditulis seperti ini:
if (WiFi.status() != WL_CONNECTED) {
WiFi.begin(ssid, password);
}
if (!client.connected()) {
reconnectMqtt();
}
Dan di tempat lain:
retryCount++;
if (retryCount > 5) ESP.restart();
Masalah:
- Logic tersebar.
- Tidak ada single state owner.
- Tidak ada transisi formal.
- Tidak ada guard antar state.
Ini bukan reconnect strategy. Ini reconnect reaksi spontan.
Dampak Nyata
Kasus nyata di lapangan:
- Broker restart β reconnect spam.
- WiFi drop β MQTT reconnect tetap jalan.
- TLS fail β retry tanpa backoff.
- Backoff tidak konsisten.
Hasilnya:
- Heap spike.
- Fragmentasi meningkat.
- Watchdog reset.
- Sistem tidak deterministik.
Reconnect tanpa struktur = chaos sistemik.
7οΈβ£ Transport β Business Logic
Transport layer adalah:
- WiFi.begin()
- WiFi.status()
- client.connect()
- client.publish()
- client.subscribe()
Business logic adalah:
- Threshold sensor.
- Mode manual / auto.
- Safety guard.
- Fail-safe behavior.
Jika business logic tahu:
if (topic == "node/relay")
Maka domain Anda sudah tergantung pada MQTT topic.
Itu coupling.
Model yang Sehat
Transport menerima payload β ubah menjadi Command domain.
Contoh:
Command cmd = parser.parse(payload);
controlService.processCommand(cmd);
ControlService tidak tahu MQTT. Ia hanya tahu Command.
Transport adalah adapter.
Bukan decision maker.
8οΈβ£ Implicit State vs Explicit State
Implicit state:
bool wifiConnected;
bool mqttConnected;
bool reconnecting;
bool updating;
Masalah:
- Kombinasi flag bisa tidak valid.
- Tidak jelas state aktif sebenarnya.
- Debug sulit.
Explicit State
enum class CommState {
INIT,
WIFI_CONNECTING,
WIFI_CONNECTED,
MQTT_CONNECTING,
MQTT_CONNECTED,
ERROR_BACKOFF
};
Sekarang:
- Hanya satu state aktif.
- Transisi jelas.
- Logging jelas.
- Telemetry jelas.
- Reconnect terstruktur.
Contoh Transisi Terkontrol
void CommManager::update() {
switch (state_) {
case CommState::INIT:
startWifi();
state_ = CommState::WIFI_CONNECTING;
break;
case CommState::WIFI_CONNECTED:
startMqtt();
state_ = CommState::MQTT_CONNECTING;
break;
case CommState::ERROR_BACKOFF:
if (backoffExpired()) {
state_ = CommState::WIFI_CONNECTING;
}
break;
default:
break;
}
}
Sekarang reconnect bukan reaksi. Ia transisi formal.
9οΈβ£ Network Latency & Control Stability
Kita kembali ke sistem sensor + relay.
Loop kontrol 100ms.
Jika MQTT publish blocking 300ms:
- Loop tertunda.
- Relay update terlambat.
- Sampling tidak stabil.
- Jitter meningkat.
Masalah bukan MQTT.
Masalahnya:
Komunikasi masuk ke jalur kontrol.
Separation of Critical Path
Critical path:
Sensor β Control β Relay
Non-critical path:
Telemetry β MQTT publish
Jika kedua path bercampur, determinism hilang.
Prinsip Penting
Kontrol tidak boleh tergantung network.
Jika broker mati:
- Kontrol tetap stabil.
- Relay tetap bekerja.
- Sensor tetap sampling.
Network adalah fitur tambahan, bukan pusat sistem.
π Communication sebagai Layer Terpisah
Dalam struktur kita:
IndustrialNode/
βββ app_ControlApp
βββ svc_ControlService
βββ svc_CommManager
βββ drv_RelayDriver
svc_CommManager bertanggung jawab atas:
- WiFi lifecycle
- MQTT lifecycle
- State komunikasi
- Event publish
- Command parsing
Ia tidak:
- Mengontrol relay.
- Mengubah threshold.
- Menentukan rule.
Ia hanya:
Communication state owner + adapter.
Alur Sehat Final
MQTT Callback
β
svc_CommManager (parse + validate)
β
Command
β
svc_ControlService
β
drv_RelayDriver
Semua rule tetap di domain.
11οΈβ£ Mental Model yang Harus Dikunci
Setelah artikel ini, engineer harus memahami:
1οΈβ£ Komunikasi memiliki lifecycle
Ia bukan sekadar publish/subscribe.
2οΈβ£ Callback bukan tempat business logic
Callback hanya entry point.
3οΈβ£ State harus eksplisit
Flag tersebar = chaos.
4οΈβ£ Reconnect harus terpusat
Satu state owner. Satu mekanisme transisi.
5οΈβ£ Transport harus dipisahkan dari domain
Topic MQTT β business rule.
6οΈβ£ Network latency memengaruhi determinism
Critical path harus terisolasi.
7οΈβ£ Event-driven lebih aman daripada shared mutable
Message passing > global flag.
Penutup
Komunikasi adalah titik di mana firmware sederhana mulai runtuh.
Bukan karena WiFi buruk. Bukan karena MQTT salah.
Tetapi karena:
- State implisit.
- Callback menyentuh hardware.
- Reconnect logic tersebar.
- Transport bercampur domain.
Communication discipline adalah jembatan antara:
- RTOS model
- Memory discipline
- OOP boundary
- Layering architecture
Catatan Penyusunan Artikel ini disusun sebagai materi edukasi dan referensi umum berdasarkan berbagai sumber pustaka, praktik lapangan, serta bantuan alat penulisan. Pembaca disarankan untuk melakukan verifikasi lanjutan dan penyesuaian sesuai dengan kondisi serta kebutuhan masing-masing sistem.