Lewati ke isi

Simulasi MQTT dengan Wokwi

Pada pertemuan kali ini akan membahas simulasi IoT menggunakan platform Wokwi untuk testing MQTT tanpa hardware fisik. Mahasiswa akan mempelajari cara menggunakan Wokwi simulator, membuat virtual ESP32 dengan sensor DHT22 dan LED, publish data sensor ke MQTT broker, subscribe command untuk kontrol LED, serta monitoring dengan MQTTX.

Alat dan Bahan

Simulator:

  • Wokwi Online Platform (https://wokwi.com)
  • Akun Wokwi (gratis, bisa login dengan Google/GitHub)

Software:

  • Web Browser (Chrome, Firefox, Edge)
  • MQTTX Desktop Client (https://mqttx.app/)
  • Text Editor untuk mencatat konfigurasi

MQTT Broker:

  • EMQX Public Broker (broker.emqx.io)
  • Port: 1883 (non-SSL)
  • Tidak perlu username/password
  • Gratis untuk testing

Network:

  • Koneksi Internet untuk akses Wokwi dan EMQX broker
  • WiFi connection akan di-mock oleh Wokwi simulator

Bagian 1: Pengenalan Wokwi dan Setup Project

1.1 Apa itu Wokwi?

Wokwi adalah platform simulasi hardware IoT berbasis web yang memungkinkan kita mendesain, coding, dan testing rangkaian elektronik tanpa memerlukan hardware fisik.

Keuntungan menggunakan Wokwi: - Tidak perlu hardware fisik - semua simulasi di cloud - Real-time simulation - behavior seperti hardware asli - Support ESP32 - cocok untuk project IoT dengan WiFi/MQTT - Built-in code editor - coding langsung di browser - Serial Monitor - debugging output program - Visual circuit diagram - lihat rangkaian secara visual - Gratis untuk pembelajaran - tidak ada biaya - Collaborative - bisa share project dengan link

Workflow development dengan Wokwi:

1. Design circuit di Wokwi simulator
2. Write code dan test dengan Serial Monitor
3. Connect ke MQTT broker (EMQX)
4. Monitor data dengan MQTTX
5. Deploy ke hardware asli (optional)

1.2 Membuat Project Wokwi Pertama

Praktikum 1.1: Setup Project Wokwi

Langkah 1: Akses dan Login Wokwi

  1. Buka browser dan akses: https://wokwi.com
  2. Klik tombol "Sign In" di pojok kanan atas
  3. Pilih metode login:
  4. Sign in with Google (recommended untuk mahasiswa)
  5. Sign in with GitHub (jika punya akun GitHub)
  6. Ikuti proses autentikasi
  7. Setelah login, akan masuk ke halaman dashboard

Langkah 2: Buat Project Baru ESP32

  1. Di dashboard Wokwi, klik tombol "New Project"
  2. Akan muncul dialog "Create New Project"
  3. Scroll dan pilih template "ESP32"
  4. Klik template tersebut
  5. Tunggu 10-15 detik hingga editor loading
  6. Berikan nama project: klik "Untitled Project" → ganti jadi "MQTT LED DHT22"

Langkah 3: Mengenal Interface Wokwi

Setelah project terbuka, akan melihat interface dengan beberapa area:

┌─────────────────────────────────────────────────┐
│  [Play] [Stop] [Share]        MQTT LED DHT22    │ ← Toolbar
├──────────────────┬──────────────────────────────┤
│                  │                              │
│  CODE EDITOR     │    CIRCUIT DIAGRAM           │
│  (main.py)       │    (Visual ESP32)            │
│                  │                              │
│  - Line numbers  │    - ESP32 board             │
│  - Syntax color  │    - Components              │
│  - Auto-complete │    - Wiring                  │
│                  │                              │
├──────────────────┴──────────────────────────────┤
│  SERIAL MONITOR                                 │
│  (Output console)                               │
└─────────────────────────────────────────────────┘

Penjelasan area: - Toolbar (atas): Tombol Play/Stop untuk run simulasi, Share untuk bagikan project - Code Editor (kiri): Tempat menulis kode MicroPython - Circuit Diagram (kanan): Tampilan visual ESP32 dan komponen - Serial Monitor (bawah): Console output dari program

Langkah 4: File Structure Project

Wokwi otomatis membuat files:

Project Files:
├── main.py          # File code MicroPython utama
├── diagram.json     # Konfigurasi hardware dan wiring
└── wokwi.toml       # Metadata project (optional)

Langkah 5: Test Run Pertama

Mari test bahwa simulator berfungsi dengan baik.

  1. Klik tab "main.py" di code editor (biasanya sudah terbuka)
  2. Hapus semua code yang ada (jika ada)
  3. Copy-paste code test ini:
# Test code untuk verifikasi Wokwi
import time

print("="*40)
print("Wokwi ESP32 Simulator - Test Run")
print("="*40)
print("MicroPython is running!")
print("Simulator: OK")
print("="*40)

counter = 0
while True:
    counter += 1
    print(f"Loop {counter} - Time: {time.time():.1f}s")
    time.sleep(2)
  1. Klik tombol "Play" (segitiga hijau) di toolbar atas
  2. Tunggu 3-5 detik hingga simulator starting
  3. Lihat output di Serial Monitor (area bawah)

Output yang diharapkan:

========================================
Wokwi ESP32 Simulator - Test Run
========================================
MicroPython is running!
Simulator: OK
========================================
Loop 1 - Time: 0.0s
Loop 2 - Time: 2.0s
Loop 3 - Time: 4.0s
...

  1. Jika output muncul seperti di atas, simulator berhasil!
  2. Klik tombol "Stop" (kotak merah) untuk stop simulasi

Troubleshooting: - Jika tidak ada output: Pastikan Serial Monitor terbuka (klik tab "Serial" di bawah) - Jika error "Failed to start": Refresh browser dan coba lagi - Jika lambat: Tutup tab browser lain untuk free up memory

1.3 Arsitektur Sistem MQTT

Sebelum mulai praktikum, penting memahami alur komunikasi MQTT di project ini.

Diagram Arsitektur:

┌─────────────────────────────────────┐
│   WOKWI SIMULATOR (ESP32)           │
│                                     │
│   ┌──────────┐      ┌──────────┐   │
│   │  DHT22   │      │   LED    │   │
│   │  Sensor  │      │  Actuator│   │
│   └────┬─────┘      └────┬─────┘   │
│        │                 │          │
│   ┌────▼─────────────────▼─────┐   │
│   │   MicroPython Program      │   │
│   │   - Read sensor            │   │
│   │   - MQTT publish           │   │
│   │   - MQTT subscribe         │   │
│   │   - Control LED            │   │
│   └────────────┬───────────────┘   │
│                │                    │
└────────────────┼────────────────────┘
                 │ WiFi (simulated)
┌─────────────────────────────────────┐
│   EMQX BROKER (Cloud)               │
│   broker.emqx.io:1883               │
│                                     │
│   Topics:                           │
│   ├─ sensor/dht22/temperature       │
│   ├─ sensor/dht22/humidity          │
│   └─ device/led/command             │
│                                     │
└────────┬──────────────┬─────────────┘
         │              │
         ▼              ▼
┌─────────────┐  ┌──────────────┐
│   MQTTX     │  │  Dashboard   │
│  (Monitor)  │  │  (Optional)  │
└─────────────┘  └──────────────┘

Alur Data:

1. PUBLISH (ESP32 → Broker):

DHT22 sensor dibaca → Format JSON → MQTT publish → 
EMQX Broker → Forward ke subscribers (MQTTX)

2. SUBSCRIBE (Broker → ESP32):

MQTTX publish command → EMQX Broker → 
ESP32 subscribe → Callback → Control LED

Topics yang digunakan:

Topic Arah Payload Fungsi
sensor/dht22/temperature ESP32 → Broker {"temp": 25.5, "humidity": 60.2} Kirim data sensor
sensor/dht22/humidity ESP32 → Broker {"humidity": 60.2} Kirim humidity saja
device/led/command Broker → ESP32 {"action": "on"} Kontrol LED
device/led/status ESP32 → Broker {"status": "ON"} Status LED

Bagian 2: Hardware Setup - Rangkaian di Wokwi

Pada bagian ini kita akan merangkai ESP32 dengan sensor DHT22 dan LED di Wokwi simulator.

2.1 Memahami Komponen

ESP32 DevKit V1

  • Microcontroller dengan WiFi built-in
  • 30 GPIO pins
  • Support MicroPython
  • Voltage: 3.3V logic

DHT22 Temperature & Humidity Sensor

  • Sensor digital temperature dan humidity
  • Range: -40°C to 80°C, 0-100% RH
  • 3 pins: VCC, GND, DATA
  • Protocol: One-wire digital signal

LED (Light Emitting Diode)

  • Indikator visual output
  • 2 pins: Anode (+, kaki panjang), Cathode (-, kaki pendek)
  • Perlu resistor 220Ω-1kΩ untuk limit current

2.2 Diagram Wiring

Praktikum 2.1: Merangkai Komponen di Wokwi

Langkah 1: Buka Diagram Editor

  1. Di project Wokwi, lihat area Circuit Diagram (kanan)
  2. Seharusnya sudah ada ESP32 board di tengah canvas
  3. Jika belum ada, klik "+ Add part" → Search "ESP32" → Pilih "ESP32 DevKit V1"

Langkah 2: Tambahkan DHT22 Sensor

  1. Klik tombol "+" (Add part) di atas diagram
  2. Di search box, ketik: "DHT22"
  3. Klik komponen "DHT22" dari hasil pencarian
  4. DHT22 akan muncul di canvas
  5. Drag DHT22 ke posisi di sebelah kanan ESP32

Langkah 3: Tambahkan LED

  1. Klik tombol "+" lagi
  2. Search: "LED"
  3. Pilih "Red LED" (atau warna lain sesuai selera)
  4. Drag LED ke posisi di bawah ESP32

Langkah 4: Tambahkan Resistor

  1. Klik "+"
  2. Search: "Resistor"
  3. Pilih resistor, akan muncul dialog
  4. Atur nilai: 220 Ω (atau 330Ω, 1kΩ juga OK)
  5. Klik "OK"
  6. Posisikan resistor dekat LED

Langkah 5: Wiring DHT22 ke ESP32

Sekarang kita akan hubungkan pin DHT22 ke ESP32.

Cara membuat koneksi: 1. Hover mouse di atas pin yang mau dihubungkan 2. Pin akan berubah warna (highlight) 3. Klik dan drag dari pin tersebut 4. Lepas di pin tujuan 5. Wire (kabel) akan terbentuk otomatis

Koneksi DHT22:

DHT22 Pin ESP32 Pin Keterangan
VCC (pin 1, kiri) 3V3 Power supply 3.3V
DATA (pin 2, tengah) D15 (GPIO 15) Data signal
GND (pin 3, kanan) GND Ground

Langkah 6: Wiring LED dan Resistor ke ESP32

Koneksi LED:

LED Pin Tujuan ESP32 Pin Keterangan
Anode (+, kaki panjang) → Resistor - Positif LED
Resistor D2 (GPIO 2) Output signal
Cathode (-, kaki pendek) GND Ground

Langkah 7: Verifikasi Wiring

Setelah semua terhubung, diagram seharusnya terlihat seperti ini:

        ┌─────────────┐
        │   DHT22     │
        │  ┌─┬─┬─┐    │
        └──┼─┼─┼──────┘
           │ │ │
       VCC │ │ └── GND
           │ └──── DATA
    ┌──────┴───────────────┐
    │                      │
    │      ESP32           │
    │    DevKit V1         │
    │                      │
    │  3V3  D15  GND  D2   │
    └───┬───┬────┬────┬────┘
        │   │    │    │
        │   │    │    └────┐
        │   │    │         │
        │   │    │      ┌──▼──┐
        │   │    │      │ Res │ 220Ω
        │   │    │      └──┬──┘
        │   │    │         │
        │   │    │      ┌──▼──┐
        │   │    │      │ LED │
        │   │    │      └──┬──┘
        │   │    │         │
        │   │    └─────────┴── GND

Langkah 8: Lihat File diagram.json

Wokwi otomatis generate file JSON yang describe rangkaian.

  1. Klik tab "diagram.json" di code editor
  2. Akan melihat JSON seperti ini:
{
  "version": 1,
  "author": "Your Name",
  "editor": "wokwi",
  "parts": [
    {
      "type": "board-esp32-devkit-c-v4",
      "id": "esp",
      "top": 0,
      "left": 0,
      "attrs": { "env": "micropython-20231227-v1.22.0" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": 217.2,
      "left": 272.6,
      "attrs": { "color": "red" }
    },
    { "type": "wokwi-dht22", "id": "dht1", "top": -38.1, "left": 253.8, "attrs": {} },
    {
      "type": "wokwi-resistor",
      "id": "r1",
      "top": 234.35,
      "left": 134.4,
      "attrs": { "value": "220" }
    }
  ],
  "connections": [
    [ "esp:TX", "$serialMonitor:RX", "", [] ],
    [ "esp:RX", "$serialMonitor:TX", "", [] ],
    [ "esp:3V3", "dht1:VCC", "red", [ "h0" ] ],
    [ "dht1:SDA", "esp:15", "yellow", [ "v0" ] ],
    [ "dht1:GND", "esp:GND.3", "black", [ "v0" ] ],
    [ "led1:C", "r1:2", "green", [ "v0" ] ],
    [ "r1:1", "esp:2", "green", [ "v0" ] ],
    [ "led1:A", "esp:GND.3", "black", [ "v0" ] ]
  ],
  "dependencies": {}
}

File ini bisa di-edit manual jika perlu, tapi lebih mudah pakai visual editor.

Langkah 9: Save Project

Wokwi auto-save, tapi bisa manual save juga: 1. Tekan Ctrl+S (Windows/Linux) atau Cmd+S (Mac) 2. Atau klik icon "Save" jika ada

Project sekarang sudah siap untuk coding!


Bagian 3: WiFi Connection dan MQTT Setup

3.1 Memahami WiFi di Wokwi

Wokwi simulator memiliki WiFi virtual yang bisa connect ke internet real. Ini memungkinkan ESP32 simulasi untuk: - Connect ke MQTT broker di cloud (EMQX) - Publish dan subscribe data real-time - Testing IoT application tanpa hardware

Penting: WiFi di Wokwi adalah mock/simulated, tapi koneksi network-nya real. Jadi bisa benar-benar komunikasi dengan broker MQTT eksternal.

3.2 Setup WiFi dan MQTT Library

Praktikum 3.1: Code Inisialisasi WiFi dan MQTT

Langkah 1: Import Libraries

Buka file main.py dan hapus semua isi sebelumnya, lalu mulai dengan import libraries:

# ============================================
# MQTT IoT Simulator - ESP32 with DHT22 & LED
# Platform: Wokwi Simulator
# ============================================

# Library imports
import network
import time
from umqtt.simple import MQTTClient
import json
from machine import Pin
import dht

print("\n" + "="*50)
print("MQTT IoT Simulator Starting...")
print("Platform: Wokwi ESP32")
print("="*50)

Penjelasan imports: - network: Library untuk WiFi connection - time: Untuk timing dan delay - umqtt.simple: MQTT client library (built-in MicroPython) - json: Untuk format data JSON - machine.Pin: Untuk kontrol GPIO pins - dht: Library untuk sensor DHT22

Langkah 2: Konfigurasi WiFi dan MQTT

Tambahkan konfigurasi di bawah imports:

# ============================================
# CONFIGURATION
# ============================================

# WiFi Configuration
# Note: Wokwi simulator akan mock WiFi connection
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""

# MQTT Broker Configuration
# Menggunakan EMQX public broker (gratis)
MQTT_BROKER = "broker.emqx.io"
MQTT_PORT = 1883
MQTT_CLIENT_ID = "wokwi-esp32-001"  # Harus unique per device

# MQTT Topics
TOPIC_TEMPERATURE = "sensor/dht22/temperature"
TOPIC_HUMIDITY = "sensor/dht22/humidity"
TOPIC_LED_COMMAND = "device/led/command"
TOPIC_LED_STATUS = "device/led/status"

# Timing Configuration
PUBLISH_INTERVAL = 5  # Publish sensor data setiap 5 detik

print("[CONFIG] Configuration loaded")
print(f"[CONFIG] MQTT Broker: {MQTT_BROKER}:{MQTT_PORT}")
print(f"[CONFIG] Client ID: {MQTT_CLIENT_ID}")
print(f"[CONFIG] Publish interval: {PUBLISH_INTERVAL}s")

Penjelasan konfigurasi:

  • WIFI_SSID & PASSWORD: Di Wokwi, gunakan "Wokwi-GUEST" (WiFi mock)
  • MQTT_BROKER: broker.emqx.io adalah public broker gratis dari EMQX
  • MQTT_PORT: 1883 adalah port standar MQTT (non-SSL)
  • MQTT_CLIENT_ID: ID unik untuk identify device ini. Harus berbeda untuk setiap device
  • Topics: Naming convention menggunakan hierarki (sensor/device/measurement)

Best Practice untuk Topic Naming:

sensor/<device>/<measurement>  # Untuk sensor data
device/<device>/<control>      # Untuk control command
system/<device>/<status>       # Untuk status system

Langkah 3: Hardware Pin Setup

Tambahkan setup untuk LED dan DHT22:

# ============================================
# HARDWARE SETUP
# ============================================

# LED setup - GPIO 2
led = Pin(2, Pin.OUT)
led.value(0)  # Initial state: OFF
print("[HARDWARE] LED initialized on GPIO 2")

# DHT22 setup - GPIO 15
dht_sensor = dht.DHT22(Pin(15))
print("[HARDWARE] DHT22 sensor initialized on GPIO 15")

# State variables
led_state = False
last_publish_time = 0

Penjelasan: - Pin(2, Pin.OUT): GPIO 2 sebagai output untuk LED - led.value(0): Set LED OFF di awal (0 = LOW, 1 = HIGH) - dht.DHT22(Pin(15)): Initialize DHT22 di GPIO 15 - State variables untuk tracking timing dan status

3.3 WiFi Connection Function

Praktikum 3.2: Implement WiFi Connection

Langkah 1: Fungsi Connect WiFi

Tambahkan fungsi untuk connect WiFi:

# ============================================
# WIFI CONNECTION
# ============================================

def connect_wifi():
    """Connect to WiFi - Optimized for Wokwi simulator"""
    print("\n[WIFI] Initializing WiFi for Wokwi simulator...")
    print(f"[WIFI] SSID: {WIFI_SSID}")

    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)

    # Wokwi: Sometimes need to disconnect first
    try:
        wlan.disconnect()
        time.sleep(0.5)
    except:
        pass

    # Connect
    wlan.connect(WIFI_SSID, WIFI_PASSWORD)
    print("[WIFI] Connecting...")

    # Wait for connection with Wokwi-specific status handling
    max_wait = 20
    while max_wait > 0:
        status = wlan.status()

        # Standard MicroPython status codes
        if status == 3:  # STAT_GOT_IP
            print("[WIFI] ✓ Connected successfully!")
            ifconfig = wlan.ifconfig()
            print(f"[WIFI] IP Address: {ifconfig[0]}")
            return True

        # Wokwi-specific status codes (1000-1010 range)
        # These are internal Wokwi states, not standard MicroPython
        if status >= 1000 and status <= 1010:
            # Still connecting in Wokwi
            if max_wait % 5 == 0:  # Print every 5 seconds
                print(f"[WIFI] Wokwi connecting... ({max_wait}s remaining)")

        # Error states
        elif status < 0:
            print(f"[WIFI] Connection failed with status: {status}")
            break

        max_wait -= 1
        time.sleep(1)

    # Wokwi quirk: Even if status != 3, network might work
    print("[WIFI] ⚠ Connection status ambiguous in Wokwi")
    print("[WIFI] Attempting to proceed - network may still work...")
    return True  # Proceed anyway for Wokwi testing

Penjelasan code: 1. network.WLAN(network.STA_IF): Create WiFi station interface 2. wlan.active(True): Activate WiFi 3. wlan.connect(): Mulai connection process 4. while max_wait > 0: Loop untuk wait connection (timeout 10 detik) 5. wlan.status(): Check status (3 = connected) 6. wlan.ifconfig(): Get IP address info

WiFi Status Codes: - 0: STAT_IDLE (idle) - 1: STAT_CONNECTING (sedang connect) - 2: STAT_WRONG_PASSWORD (password salah) - 3: STAT_GOT_IP (connected, dapat IP) - -1: STAT_NO_AP_FOUND (SSID tidak ketemu) - -2: STAT_CONNECT_FAIL (gagal connect)

3.4 MQTT Connection Function

Praktikum 3.3: Implement MQTT Connection

Langkah 1: Fungsi Connect MQTT

Tambahkan fungsi untuk connect ke MQTT broker:

# ============================================
# MQTT CONNECTION
# ============================================

def connect_mqtt():
    """
    Connect ke MQTT broker dan setup subscriptions
    """
    print("\n[MQTT] Connecting to MQTT broker...")
    print(f"[MQTT] Broker: {MQTT_BROKER}:{MQTT_PORT}")

    try:
        # Create MQTT client instance
        client = MQTTClient(
            client_id=MQTT_CLIENT_ID,
            server=MQTT_BROKER,
            port=MQTT_PORT,
            keepalive=60  # Send ping setiap 60 detik
        )

        # Set callback untuk handle incoming messages
        client.set_callback(mqtt_callback)

        # Connect ke broker
        client.connect()
        print("[MQTT] ✓ Connected to broker successfully!")

        # Subscribe ke command topics
        client.subscribe(TOPIC_LED_COMMAND)
        print(f"[MQTT] ✓ Subscribed to: {TOPIC_LED_COMMAND}")

        return client

    except Exception as e:
        print(f"[MQTT] ✗ Connection failed: {e}")
        return None

Penjelasan: - MQTTClient(): Create MQTT client instance - client_id: Unique identifier untuk device - keepalive=60: Ping interval untuk maintain connection - set_callback(): Set function yang dipanggil saat terima message - connect(): Establish connection ke broker - subscribe(): Subscribe ke topic untuk receive messages

Langkah 2: Callback Function untuk Handle Messages

Tambahkan fungsi callback yang akan dipanggil saat ada message masuk:

def mqtt_callback(topic, msg):
    """
    Callback function dipanggil saat menerima MQTT message
    Args:
        topic: Topic dari message (bytes)
        msg: Payload message (bytes)
    """
    global led_state

    # Convert bytes ke string
    topic_str = topic.decode()
    msg_str = msg.decode()

    print(f"\n[MQTT] Message received!")
    print(f"[MQTT]   Topic: {topic_str}")
    print(f"[MQTT]   Payload: {msg_str}")

    # Handle LED command
    if topic_str == TOPIC_LED_COMMAND:
        try:
            # Parse JSON payload
            data = json.loads(msg_str)
            action = data.get("action", "").lower()

            if action == "on":
                led.value(1)  # Turn ON LED
                led_state = True
                print("[LED] ✓ Turned ON")

                # Publish status update
                publish_led_status(True)

            elif action == "off":
                led.value(0)  # Turn OFF LED
                led_state = False
                print("[LED] ✓ Turned OFF")

                # Publish status update
                publish_led_status(False)

            else:
                print(f"[LED] ✗ Unknown action: {action}")

        except Exception as e:
            print(f"[LED] ✗ Error processing command: {e}")

Penjelasan callback: 1. Function dipanggil otomatis saat message diterima 2. topic dan msg dalam bentuk bytes, perlu decode ke string 3. Parse JSON untuk extract command 4. Control LED based on action ("on" atau "off") 5. Publish status update setelah action


Bagian 4: Sensor Reading dan MQTT Publish

4.1 Read Sensor DHT22

Praktikum 4.1: Fungsi Baca Sensor

Langkah 1: Fungsi Read DHT22

Tambahkan fungsi untuk baca sensor:

# ============================================
# SENSOR FUNCTIONS
# ============================================

def read_dht22():
    """
    Baca temperature dan humidity dari sensor DHT22
    Returns:
        dict: {'temperature': float, 'humidity': float, 'success': bool}
    """
    try:
        # Trigger sensor measurement
        dht_sensor.measure()

        # Wait sebentar untuk measurement selesai
        time.sleep(0.5)

        # Read values
        temperature = dht_sensor.temperature()
        humidity = dht_sensor.humidity()

        # Validation
        if temperature is None or humidity is None:
            print("[SENSOR] ✗ Failed to read sensor (None values)")
            return None

        # Format data
        data = {
            'temperature': round(temperature, 1),
            'humidity': round(humidity, 1),
            'success': True
        }

        print(f"[SENSOR] ✓ DHT22 read: Temp={data['temperature']}°C, Humidity={data['humidity']}%")
        return data

    except OSError as e:
        print(f"[SENSOR] ✓ DHT22 read: Temp={data['temperature']}°C, Humidity={data['humidity']}%")
        return data

    except OSError as e:
        print(f"[SENSOR] ✗ Sensor error: {e}")
        return None
    except Exception as e:
        print(f"[SENSOR] ✗ Unexpected error: {e}")
        return None

Penjelasan: - dht_sensor.measure(): Trigger sensor untuk mulai measurement - time.sleep(0.5): Wait 500ms untuk sensor selesai baca - dht_sensor.temperature(): Get temperature value - dht_sensor.humidity(): Get humidity value - round(value, 1): Round ke 1 decimal untuk format yang rapi - Error handling untuk handle sensor failure

Common DHT22 Errors: - OSError: [Errno 110] ETIMEDOUT: Sensor tidak response (cek wiring) - None values: Sensor belum ready atau rusak - Reading too fast: Tunggu minimal 2 detik antar reading

4.2 MQTT Publish Functions

Praktikum 4.2: Implement Publish Functions

Langkah 1: Fungsi Publish Sensor Data

Tambahkan fungsi untuk publish data sensor:

# ============================================
# MQTT PUBLISH FUNCTIONS
# ============================================

def publish_sensor_data(client, sensor_data):
    """
    Publish sensor data ke MQTT broker
    Args:
        client: MQTT client instance
        sensor_data: Dict dengan temperature dan humidity
    """
    if sensor_data is None or not sensor_data.get('success'):
        print("[MQTT] ✗ Cannot publish - invalid sensor data")
        return False

    try:
        # Prepare payload dengan timestamp
        payload = {
            'temperature': sensor_data['temperature'],
            'humidity': sensor_data['humidity'],
            'timestamp': time.time(),
            'device_id': MQTT_CLIENT_ID
        }

        # Convert ke JSON string
        payload_json = json.dumps(payload)

        # Publish ke topic temperature
        client.publish(TOPIC_TEMPERATURE, payload_json)
        print(f"[MQTT] ✓ Published to {TOPIC_TEMPERATURE}")
        print(f"[MQTT]   Data: {payload_json}")

        # Optional: Publish humidity ke topic terpisah
        humidity_payload = {
            'humidity': sensor_data['humidity'],
            'timestamp': time.time(),
            'device_id': MQTT_CLIENT_ID
        }
        client.publish(TOPIC_HUMIDITY, json.dumps(humidity_payload))
        print(f"[MQTT] ✓ Published to {TOPIC_HUMIDITY}")

        return True

    except Exception as e:
        print(f"[MQTT] ✗ Publish error: {e}")
        return False

def publish_led_status(status):
    """
    Publish LED status ke MQTT broker
    Args:
        status: Boolean (True=ON, False=OFF)
    """
    try:
        payload = {
            'status': 'ON' if status else 'OFF',
            'timestamp': time.time(),
            'device_id': MQTT_CLIENT_ID
        }

        payload_json = json.dumps(payload)
        mqtt_client.publish(TOPIC_LED_STATUS, payload_json)
        print(f"[MQTT] ✓ Published LED status: {payload['status']}")

    except Exception as e:
        print(f"[MQTT] ✗ Failed to publish LED status: {e}")

Penjelasan: - Payload structure: Include data, timestamp, dan device_id untuk traceability - JSON format: Standard format untuk MQTT payload, mudah di-parse - Multiple topics: Temperature dan humidity bisa di-publish ke topic terpisah - Error handling: Catch exception untuk prevent program crash

Best Practice Payload Format:

{
    "temperature": 25.5,
    "humidity": 60.2,
    "timestamp": 1698765432,
    "device_id": "wokwi-esp32-001"
}

Include timestamp membantu untuk: - Data synchronization - Troubleshooting delay - Historical data analysis


Bagian 5: Main Loop - Integration

5.1 Main Program Loop

Praktikum 5.1: Complete Main Program

Langkah 1: Fungsi Main dengan Loop

Tambahkan main function yang integrate semua components:

# ============================================
# MAIN PROGRAM
# ============================================

def main():
    """
    Main program loop
    """
    global mqtt_client, last_publish_time

    print("\n" + "="*50)
    print("Starting MQTT IoT Application")
    print("="*50)

    # Step 1: Connect WiFi
    if not connect_wifi():
        print("[ERROR] WiFi connection failed - stopping")
        return

    time.sleep(2)  # Wait sebentar setelah WiFi connect

    # Step 2: Connect MQTT
    mqtt_client = connect_mqtt()
    if mqtt_client is None:
        print("[ERROR] MQTT connection failed - stopping")
        return

    print("\n" + "="*50)
    print("System Ready!")
    print("="*50)
    print(f"[INFO] Publishing sensor data every {PUBLISH_INTERVAL} seconds")
    print("[INFO] Listening for LED commands...")
    print("[INFO] Press STOP button to exit")
    print("="*50 + "\n")

    # Initialize timing
    last_publish_time = time.time()
    loop_count = 0

    # Main loop
    while True:
        try:
            loop_count += 1
            current_time = time.time()

            # Check for incoming MQTT messages
            # Note: check_msg() adalah non-blocking
            mqtt_client.check_msg()

            # Publish sensor data berdasarkan interval
            if (current_time - last_publish_time) >= PUBLISH_INTERVAL:
                print(f"\n--- Loop {loop_count} ---")

                # Read sensor
                sensor_data = read_dht22()

                # Publish jika reading berhasil
                if sensor_data and sensor_data.get('success'):
                    publish_sensor_data(mqtt_client, sensor_data)
                else:
                    print("[WARNING] Skipping publish - sensor read failed")

                # Update timing
                last_publish_time = current_time

            # Small delay untuk prevent CPU overload
            time.sleep(0.1)

        except KeyboardInterrupt:
            print("\n[INFO] Program interrupted by user")
            break

        except Exception as e:
            print(f"[ERROR] Main loop error: {e}")
            print("[INFO] Attempting to reconnect...")

            # Try reconnect MQTT
            try:
                mqtt_client = connect_mqtt()
                if mqtt_client is None:
                    print("[ERROR] Reconnection failed - stopping")
                    break
            except:
                print("[ERROR] Reconnection failed - stopping")
                break

            time.sleep(5)

    # Cleanup
    print("\n[INFO] Cleaning up...")
    try:
        mqtt_client.disconnect()
        print("[INFO] MQTT disconnected")
    except:
        pass

    led.value(0)  # Turn off LED
    print("[INFO] LED turned off")
    print("[INFO] Program ended")
    print("="*50)

# ============================================
# ENTRY POINT
# ============================================

# Run main program
if __name__ == "__main__":
    main()

Penjelasan Main Loop:

  1. Initialization Phase:
  2. Connect WiFi
  3. Connect MQTT broker
  4. Setup timing variables

  5. Main Loop:

  6. check_msg(): Check incoming MQTT messages (non-blocking)
  7. Timer-based publish: Publish sensor data setiap interval
  8. Error handling: Catch exception dan attempt reconnect

  9. Cleanup:

  10. Disconnect MQTT gracefully
  11. Turn off LED
  12. Print exit message

Langkah 2: Test Run Complete Code

  1. Pastikan semua code sudah di-copy ke main.py
  2. Verify wiring di diagram masih benar
  3. Klik tombol "Play" (▶)
  4. Tunggu 5-10 detik untuk initialization
  5. Monitor output di Serial Monitor

Expected Output:

==================================================
MQTT IoT Simulator Starting...
Platform: Wokwi ESP32
==================================================
[CONFIG] Configuration loaded
[CONFIG] MQTT Broker: broker.emqx.io:1883
[CONFIG] Client ID: wokwi-esp32-001
[CONFIG] Publish interval: 5s
[HARDWARE] LED initialized on GPIO 2
[HARDWARE] DHT22 sensor initialized on GPIO 15

[WIFI] Connecting to WiFi...
[WIFI] SSID: Wokwi-GUEST
[WIFI] ✓ Connected successfully!
[WIFI] IP Address: 192.168.1.100

[MQTT] Connecting to MQTT broker...
[MQTT] Broker: broker.emqx.io:1883
[MQTT] ✓ Connected to broker successfully!
[MQTT] ✓ Subscribed to: device/led/command

==================================================
System Ready!
==================================================
[INFO] Publishing sensor data every 5 seconds
[INFO] Listening for LED commands...
[INFO] Press STOP button to exit
==================================================

--- Loop 1 ---
[SENSOR] ✓ DHT22 read: Temp=24.5°C, Humidity=55.3%
[MQTT] ✓ Published to sensor/dht22/temperature
[MQTT]   Data: {"temperature": 24.5, "humidity": 55.3, "timestamp": 123456, "device_id": "wokwi-esp32-001"}
[MQTT] ✓ Published to sensor/dht22/humidity

--- Loop 2 ---
[SENSOR] ✓ DHT22 read: Temp=24.6°C, Humidity=55.1%
[MQTT] ✓ Published to sensor/dht22/temperature
[MQTT]   Data: {"temperature": 24.6, "humidity": 55.1, "timestamp": 123461, "device_id": "wokwi-esp32-001"}
[MQTT] ✓ Published to sensor/dht22/humidity
  1. Jika melihat output seperti di atas, simulator berhasil!

Troubleshooting:

Error Penyebab Solusi
MQTT connection failed Broker tidak reachable Check internet connection, try broker lain
Sensor error: ETIMEDOUT DHT22 wiring salah Verify wiring DATA ke GPIO 15
None values Sensor belum ready Tambah delay setelah measure()
Memory error Code terlalu besar Simplify code, hapus print tidak perlu

Bagian 6: Testing dengan MQTTX

Sekarang kita akan monitor dan control ESP32 menggunakan MQTTX desktop client.

6.1 Setup MQTTX

Praktikum 6.1: Install dan Configure MQTTX

Langkah 1: Download dan Install MQTTX

  1. Buka browser, akses: https://mqttx.app/
  2. Klik "Download"
  3. Pilih sesuai OS:
  4. Windows: Download installer .exe
  5. macOS: Download .dmg
  6. Linux: Download .AppImage atau .deb
  7. Install MQTTX:
  8. Windows: Double-click installer, follow wizard
  9. macOS: Drag ke Applications folder
  10. Linux: chmod +x dan run, atau sudo dpkg -i
  11. Launch MQTTX

Langkah 2: Create New Connection ke EMQX Broker

Setelah MQTTX terbuka, akan melihat window dengan sidebar kiri.

  1. Klik tombol "+ New Connection" (pojok kiri atas)
  2. Form "New Connection" akan muncul di kanan
  3. Isi form dengan detail berikut:

Connection Settings:

Field Value Keterangan
Name EMQX Wokwi Test Nama connection (bebas)
Client ID (sesuaikan ditampilan) Unique ID untuk MQTTX
Host broker.emqx.io EMQX public broker
Port 1883 MQTT port (non-SSL)
Username (kosongkan) Public broker tidak perlu auth
Password (kosongkan) Public broker tidak perlu auth
SSL/TLS OFF Tidak pakai encryption
MQTT Version 3.1.1 Version default
  1. Setelah selesai isi, klik tombol "Connect" (pojok kanan atas)
  2. Status akan berubah jadi "Connected" dengan dot hijau
  3. Bottom panel akan show "Connection successful"

6.2 Subscribe ke Sensor Topics

Praktikum 6.2: Monitor Sensor Data dari ESP32

Langkah 1: Create Subscription untuk Temperature

  1. Di MQTTX window, pastikan connection EMQX Wokwi Test sudah selected (highlight)
  2. Klik tombol "+ New Subscription" (di area subscription)
  3. Dialog "Add Subscription" akan muncul
  4. Isi form:
Field Value
Topic sensor/dht22/temperature
QoS 1
Color Blue (optional, untuk visual)
  1. Klik "Confirm"
  2. Subscription akan muncul di list dengan badge count "0"

Langkah 2: Create Subscription untuk Humidity

Repeat langkah di atas untuk humidity:

  1. Klik "+ New Subscription" lagi
  2. Isi form:
Field Value
Topic sensor/dht22/humidity
QoS 1
Color Green
  1. Klik "Confirm"

Langkah 3: Create Subscription untuk LED Status

  1. Klik "+ New Subscription" lagi
  2. Isi:
Field Value
Topic device/led/status
QoS 1
Color Yellow
  1. Klik "Confirm"

Langkah 4: Monitor Incoming Messages

Sekarang MQTTX sudah subscribe ke 3 topics. Mari verify data masuk:

  1. Pastikan Wokwi simulator masih running (jika belum, klik Play)
  2. Di MQTTX, lihat area "Messages" (tengah bawah)
  3. Setiap 5 detik, seharusnya melihat message baru muncul

Expected messages:

Topic: sensor/dht22/temperature
Time: 10:15:23
QoS: 1
Payload:
{
  "temperature": 24.5,
  "humidity": 55.3,
  "timestamp": 1698765432,
  "device_id": "wokwi-esp32-001"
}
Topic: sensor/dht22/humidity
Time: 10:15:23
QoS: 1
Payload:
{
  "humidity": 55.3,
  "timestamp": 1698765432,
  "device_id": "wokwi-esp32-001"
}
  1. Badge count di subscription akan increment (1, 2, 3, ...)
  2. Klik message untuk see full detail di right panel

Langkah 5: Verify Data Flow

Untuk verify data real-time:

  1. Lihat Serial Monitor di Wokwi - seharusnya show publish logs
  2. Lihat MQTTX Messages - seharusnya receive data yang sama
  3. Compare timestamp - delay harusnya < 1 detik

Diagram data flow:

Wokwi ESP32                 EMQX Broker              MQTTX
    |                            |                       |
    |--- Publish temperature --->|                       |
    |    (every 5 seconds)       |                       |
    |                            |--- Forward message -->|
    |                            |                       |
    |                            |<--- Subscribed to ----|

6.3 Publish Command ke ESP32

Praktikum 6.3: Control LED dari MQTTX

Sekarang kita akan send command dari MQTTX ke ESP32 untuk control LED.

Langkah 1: Prepare Publish Panel

  1. Di MQTTX window (connection EMQX Wokwi Test selected)
  2. Lihat area "Publish" di bottom (below subscriptions)
  3. Ada form dengan fields: Topic, QoS, Payload

Langkah 2: Turn ON LED

  1. Di field "Topic", ketik: device/led/command
  2. Di dropdown "QoS", pilih: 1
  3. Di field "Payload", ketik JSON command:
    {"action": "on"}
    
  4. Klik tombol "Publish" (atau tekan Enter)

Langkah 3: Verify LED ON

Setelah publish:

  1. Di MQTTX: Message akan appear di sent messages (abu-abu)
  2. Di Wokwi Simulator:
  3. Lihat diagram - LED seharusnya menyala merah
  4. Lihat Serial Monitor - akan show log:
    [MQTT] Message received!
    [MQTT]   Topic: device/led/command
    [MQTT]   Payload: {"action": "on"}
    [LED] ✓ Turned ON
    [MQTT] ✓ Published LED status: ON
    
  5. Di MQTTX Messages: Akan receive message di topic device/led/status:
    {
      "status": "ON",
      "timestamp": 1698765500,
      "device_id": "wokwi-esp32-001"
    }
    

Langkah 4: Turn OFF LED

Repeat untuk turn off:

  1. Topic: device/led/command
  2. Payload:
    {"action": "off"}
    
  3. Klik "Publish"
  4. Verify:
  5. LED di Wokwi mati
  6. Serial Monitor show "Turned OFF"
  7. MQTTX receive status "OFF"

Langkah 5: Test Multiple Commands

Test rapid toggle:

  1. Publish {"action": "on"} - wait 2 detik
  2. Publish {"action": "off"} - wait 2 detik
  3. Publish {"action": "on"} - wait 2 detik
  4. Publish {"action": "off"}

Setiap command seharusnya: - ✓ Toggle LED state di Wokwi - ✓ Show log di Serial Monitor - ✓ Publish status update yang diterima MQTTX

Langkah 6: Test Invalid Command

Test error handling:

  1. Publish dengan payload invalid:
    {"action": "invalid"}
    
  2. Di Serial Monitor, seharusnya show:
    [LED] ✗ Unknown action: invalid
    
  3. LED state tidak berubah

Command Summary:

Command Payload Expected Result
Turn ON {"action": "on"} LED menyala, status "ON" published
Turn OFF {"action": "off"} LED mati, status "OFF" published
Invalid {"action": "xyz"} Error message, no state change
Malformed {invalid json} JSON parse error

6.4 Advanced MQTTX Features

Praktikum 6.4: Monitoring dan Analysis

Langkah 1: View Message Statistics

  1. Di MQTTX, klik tab "Statistics" (jika ada)
  2. Atau lihat badge counts di subscriptions
  3. Akan show:
  4. Total messages received
  5. Messages per topic
  6. Message rate (msg/sec)

Langkah 2: Search dan Filter Messages

  1. Di area Messages, ada search box
  2. Ketik: temperature - akan filter messages yang contain kata itu
  3. Clear search untuk show all messages again

Langkah 3: Export Messages

Untuk save messages ke file:

  1. Right-click di message
  2. Pilih "Copy" atau "Export"
  3. Paste ke text editor
  4. Save sebagai reference

Langkah 4: Monitor Connection Quality

Indicator connection quality:

  • Green dot: Connected, good
  • Yellow dot: Connected, warning (high latency)
  • Red dot: Disconnected
  • Gray dot: Connecting

Jika connection unstable: - Check internet connection - Try restart MQTTX - Verify broker address