- Published on
Communication Module Design (WiFi, MQTT, OTA) yang Tidak Coupled
- Authors
π Artikel 6: Communication Module Design (WiFi, MQTT, OTA) yang Tidak Coupled
Posisi: Artikel 6 dari 8 Domain Keputusan: Communication Architecture Status Lock: π Communication Boundary & State Machine Freeze Entry Context: IndustrialNode/IndustrialNode.ino
- π Artikel 6: Communication Module Design (WiFi, MQTT, OTA) yang Tidak Coupled
1. Problem Reality
Setelah Artikel 5:
- Dependency sudah terkendali.
- Memory sudah disiplin.
- Concurrency sudah dibatasi.
- Layering sudah terkunci.
Masalah baru muncul saat komunikasi ditambahkan.
Pada Artikel 5, eksekusi firmware sudah dipisahkan menjadi beberapa task:
ControlTask β menjalankan application
CommTask β menangani komunikasi
ISR β hanya notify
Struktur layer tetap:
app_ β svc_ β drv_
Namun komunikasi memperkenalkan karakteristik baru:
event asynchronous dari luar sistem
(network, broker, OTA server)
Event ini masuk melalui:
- MQTT callback
- WiFi event handler
- OTA trigger
Semua berjalan di context CommTask / network stack, bukan ControlTask.
Jika tidak dikontrol, maka:
CommTask bisa langsung memanggil svc_ atau bahkan drv_
Artinya:
execution melanggar flow:
Task β app_ β svc_ β drv_
Inilah sumber masalah komunikasi.
Gejala yang sering terjadi:
- WiFi event handler mengubah state aplikasi langsung.
- MQTT callback memanggil
ActuatorService. - OTA logic tersebar di beberapa file.
- Reconnect logic copy-paste.
- Credential literal tersebar di banyak file.
Contoh klasik:
void onMqttMessage(...) {
actuator.setRelay(true); // - β bypass boundary
}
Atau:
if (!client.connected()) {
client.connect("node01"); // reconnect logic tersebar - β
}
Akibat produksi:
- Device stuck di reconnect loop.
- Control terganggu saat TLS handshake.
- OTA gagal β device brick.
- Bug hanya muncul saat broker restart.
Masalahnya bukan MQTT.
Masalahnya:
Communication berjalan di task terpisah, tetapi tidak mengikuti boundary layer dan execution yang sudah dikunci.
2. Root Cause Analysis
Akar masalah komunikasi spaghetti biasanya:
2.1 Transport Bercampur Business Logic
MQTT callback langsung memanggil service.
Transport layer tahu detail aplikasi.
Boundary hilang.
2.2 Tidak Ada State Machine Formal
Reconnect dilakukan dengan:
if (!client.connected()) {
reconnect();
}
State implicit.
Tidak ada mode eksplisit seperti:
- WIFI_CONNECTING
- MQTT_CONNECTING
- ERROR_BACKOFF
Akibatnya:
- Reconnect loop liar.
- Hard to debug.
2.3 Credential Tersebar
WiFi.begin("myssid", "mypassword");
client.connect("node01", "user", "pass");
Credential ada di banyak tempat.
Security risk. Hard to rotate.
2.4 Callback Mengontrol Hardware
Dependency menjadi:
MQTT callback β ActuatorService
WiFi event β ControlApp
OTA event β global flag
Communication menjadi pusat coupling baru.
π Visualisasi Coupling Tanpa Comm Boundary
Tanpa CommManager:
- Callback bisa menyentuh semua layer.
- Dependency kembali cyclic.
3. Design Principle (Rule yang Dikunci)
Artikel 6 mengunci arsitektur komunikasi final.
π Rule 1 β CommManager Mandatory
Semua komunikasi harus melalui:
svc_CommManager
Tidak boleh:
- Application publish langsung.
- Service subscribe langsung.
CommManager adalah satu-satunya gateway.
π Rule 2 β Transport β Business Logic
Pisahkan:
- Transport (WiFi, MQTT client)
- Protocol parsing
- Business command handling
CommManager expose interface netral:
void publishTelemetry(const TelemetryData& data);
void registerCommandHandler(ICommandHandler& handler);
App tidak tahu topic detail.
π Rule 3 β State Machine Wajib
State minimal:
INIT
β WIFI_CONNECTING
β WIFI_CONNECTED
β MQTT_CONNECTING
β MQTT_CONNECTED
β ERROR_BACKOFF
Tidak boleh implicit state.
Reconnect harus berbasis state machine eksplisit.
π Rule 4 β Offline-Safe Policy
Jika WAN down:
- Control loop tetap berjalan.
- Telemetry dibuffer (fixed-size).
- Tidak blocking ControlTask.
π Rule 5 β Credential Encapsulation
Credential hanya di satu tempat:
sys_Config.hatau secure storage.- Tidak literal tersebar.
- Tidak bisa diakses sembarang layer.
π Rule 6 β OTA Guarded Execution
OTA hanya boleh:
- Di-trigger via CommManager.
- Diverifikasi.
- Tidak langsung apply tanpa guard.
Setelah Artikel 6:
- β Tidak boleh reconnect tersebar
- β Tidak boleh business logic tahu MQTT detail
- β Tidak boleh bypass CommManager
- β Tidak boleh credential tersebar
Communication boundary final.
4. Implementation Pattern (ESP32 Arduino Context)
4.1 CommManager Skeleton
CommManager bukan sekadar class service.
CommManager adalah:
execution unit yang berjalan di CommTask
Artinya:
CommManager::run()dipanggil oleh CommTask- Bukan oleh ControlTask
- Bukan oleh ISR
Sehingga:
CommTask β svc_CommManager β (internal state machine)
class CommManager {
public:
void init();
void run();
void publishTelemetry(const TelemetryData& data);
void registerCommandHandler(ICommandHandler& handler);
private:
void handleStateMachine();
void handleMqttMessage(char* topic, byte* payload, unsigned int length);
ConnectionState state_;
};
State machine dikelola internal.
Namun yang penting:
CommManager tidak boleh langsung mengontrol application
Ia hanya:
mengubah state internal komunikasi
mengirim event / command ke application
4.2 Command Handling Interface
Interface ini adalah boundary antara:
CommTask (communication context)
dan
ControlTask (application context)
Flow lengkap:
MQTT callback (CommTask)
β CommManager parse
β enqueue command
β ControlTask ambil command
β app_ memproses
Yang penting:
callback tidak pernah menyentuh service langsung
class ICommandHandler {
public:
virtual void onCommand(const Command& cmd) = 0;
};
Flow:
MQTT payload β CommManager parse β Handler di Application layer
Callback tidak menyentuh service langsung.
4.3 Offline Buffer (Fixed Size)
Buffer ini berada di dalam CommManager (CommTask).
Fungsinya:
menyerap ketidakstabilan network
tanpa mengganggu ControlTask
Tanpa ini:
ControlTask bisa terblokir oleh publish
Dengan ini:
ControlTask tetap deterministic
CommTask menangani backlog
#define TELEMETRY_BACKLOG_SIZE 10
TelemetryData backlog[TELEMETRY_BACKLOG_SIZE];
uint8_t backlogHead;
uint8_t backlogCount;
Bounded. No dynamic allocation.
Semua pattern di atas menjaga satu hal:
CommTask tidak boleh mengontrol sistem langsung
Alur final harus tetap:
CommTask β CommManager β (queue/event)
β ControlTask β app_ β svc_ β drv_
Dengan ini:
- komunikasi tetap asynchronous
- control tetap deterministic
- layering tetap utuh
5. Constraint & Embedded Impact
Communication adalah domain paling βrakus resourceβ di ESP32.
Jika tidak dikontrol, ia merusak determinism dan memory discipline.
5.1 RAM Impact
Komponen yang memakan RAM besar:
- WiFi stack internal
- TCP/IP buffer
- TLS (mbedTLS)
- MQTT buffer
Jika CommManager:
- Tidak membatasi backlog
- Menggunakan
String - Menggunakan buffer dinamis
Maka:
- Heap minimum turun.
- TLS handshake gagal.
- OTA gagal.
Dengan:
- Fixed-size telemetry backlog
- Static buffer parsing
- Tidak ada dynamic allocation
RAM menjadi predictable.
5.2 Stack Impact
Callback MQTT bisa membawa payload besar.
Jika parsing JSON dilakukan di callback dan object lokal besar dibuat:
- Stack overflow.
- Crash sporadis.
Dengan design:
- Callback hanya enqueue raw payload (bounded).
- Parsing dilakukan di CommTask context.
Stack terisolasi.
5.3 Determinism Impact
Jika reconnect dilakukan di ControlTask:
- Control jitter.
- Watchdog reset.
Dengan separation:
- CommTask handle reconnect.
- ControlTask tetap periodik.
Determinism tetap terjaga.
5.4 Network Instability Impact
WAN tidak stabil adalah kondisi normal, bukan exception.
Comm architecture harus mengasumsikan:
- Broker restart
- WiFi flapping
- ISP latency spike
Tanpa state machine eksplisit:
- Reconnect loop liar.
- Device stuck.
Dengan state machine:
Transisi eksplisit β audit-able.
π Visualisasi State Machine Connection


State harus eksplisit. Bukan implicit if-else tersebar.
6. Failure Scenario
Communication failure sering muncul hanya di lapangan.
Scenario 1 β Broker Restart
Tanpa state machine:
if (!client.connected()) {
client.connect(...);
}
Reconnect dipanggil terus-menerus.
Akibat:
- CPU spike
- Heap churn
- Device stuck
Dengan state machine:
- Transisi ke ERROR_BACKOFF
- Delay exponential
- Retry terkontrol
Scenario 2 β MQTT Callback Mengubah Relay
Callback langsung:
actuator.setRelay(true);
Jika ControlTask juga mengubah relay:
- Conflict
- Relay chatter
Dengan architecture freeze:
Callback β CommandHandler β ControlTask Single decision point.
Scenario 3 β WAN Down Lama
WiFi down 30 menit.
Jika telemetry publish blocking:
- ControlTask delay
- Watchdog reset
Jika backlog growable:
- RAM habis
Dengan offline-safe policy:
- Telemetry masuk ring buffer bounded
- Data lama drop terkontrol
- Control tetap jalan
Scenario 4 β OTA Tanpa Guard
OTA dipanggil langsung dari callback.
Jika firmware corrupt:
- Device brick
- Tidak ada rollback
Dengan rule:
- OTA hanya via CommManager
- Verify checksum
- Trigger reboot terkendali
7. Anti-Pattern
Daftar merah Artikel 6:
- β App publish langsung MQTT client
- β Service subscribe topic langsung
- β Reconnect logic copy-paste
- β Credential literal tersebar
- β OTA dipanggil dari callback
- β Callback memodifikasi hardware langsung
- β Tidak ada state machine eksplisit
Dampak:
- Coupling tinggi
- Security risk
- Redesign mahal
- Device stuck di lapangan
8. Freeze Point
Setelah Artikel 6, keputusan berikut dianggap final:
- Semua komunikasi lewat
svc_CommManager. - State machine eksplisit wajib.
- Offline buffering bounded dan fixed-size.
- Credential encapsulated di satu tempat.
- OTA guarded via CommManager.
- Tidak ada business logic di transport callback.
Communication architecture tidak boleh berubah.
Artikel 7β8 harus patuh pada boundary ini.
9. Engineering Checklist
Audit sebelum release:
- Apakah ada publish langsung tanpa CommManager?
- Apakah reconnect tersebar di banyak file?
- Apakah credential tersebar literal?
- Apakah callback menyentuh hardware?
- Apakah state machine eksplisit?
- Apakah backlog bounded?
Jika satu saja βyaβ β melanggar Artikel 6.
10. Summary (5 Bullet Maksimal)
- Communication harus domain terisolasi.
- CommManager adalah gateway tunggal.
- State machine eksplisit mencegah reconnect chaos.
- Offline-safe policy wajib untuk produksi.
- Communication tidak boleh mengganggu control determinism.
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.