Fase 2 ยท Minggu 6

Dashboard Sensor Real-time via USB

Baca data sensor dari ESP32, tampilkan chart real-time di Flutter menggunakan fl_chart.

ESP32: Kirim Data Sensor Periodik

ESP32 membaca sensor DHT11 dan LDR, lalu mengirim data JSON setiap detik.

C++ (Arduino)#include <ArduinoJson.h>
#include <DHT.h>

#define DHT_PIN  4
#define DHT_TYPE DHT11
#define LDR_PIN  34
#define LED_PIN  2

DHT dht(DHT_PIN, DHT_TYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  // Baca sensor
  float suhu = dht.readTemperature();
  float kelembaban = dht.readHumidity();
  int cahaya = analogRead(LDR_PIN);

  // Buat JSON
  JsonDocument doc;
  doc["type"] = "sensor_data";
  doc["suhu"] = isnan(suhu) ? 0.0 : suhu;
  doc["kelembaban"] = isnan(kelembaban) ? 0.0 : kelembaban;
  doc["cahaya"] = cahaya;
  doc["led"] = digitalRead(LED_PIN) ? "ON" : "OFF";
  doc["uptime"] = millis() / 1000;

  serializeJson(doc, Serial);
  Serial.println();

  // Cek perintah masuk
  if (Serial.available()) {
    String input = Serial.readStringUntil('\n');
    JsonDocument cmd;
    if (!deserializeJson(cmd, input)) {
      const char* command = cmd["command"];
      if (strcmp(command, "ON") == 0) digitalWrite(LED_PIN, HIGH);
      if (strcmp(command, "OFF") == 0) digitalWrite(LED_PIN, LOW);
    }
  }

  delay(1000);
}
DHT11 GPIO 4 LDR GPIO 34 ESP32 JSON every 1s USB Serial Flutter Dashboard ๐Ÿ“Š Chart Data JSON: {"suhu": 27.5, "kelembaban": 65, "cahaya": 2048, "led": "OFF"}

Arsitektur: Sensor โ†’ ESP32 โ†’ USB โ†’ Flutter Dashboard

Setup Flutter: fl_chart Package

Tambahkan fl_chart untuk visualisasi data sensor.

YAML โ€” pubspec.yamldependencies:
  flutter:
    sdk: flutter
  usb_serial: ^0.5.1
  fl_chart: ^0.68.0
Terminalflutter pub get

Flutter: Sensor Dashboard App

App Flutter yang menerima data sensor dan menampilkan gauge + line chart real-time.

Dart โ€” lib/main.dart (ringkasan)import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:usb_serial/usb_serial.dart';
import 'package:fl_chart/fl_chart.dart';

class SensorDashboard extends StatefulWidget {
  const SensorDashboard({super.key});
  @override
  State<SensorDashboard> createState() => _SensorDashboardState();
}

class _SensorDashboardState extends State<SensorDashboard> {
  UsbPort? _port;
  double suhu = 0, kelembaban = 0;
  int cahaya = 0;
  List<FlSpot> suhuHistory = [];
  int tick = 0;

  @override
  void initState() {
    super.initState();
    _connect();
  }

  Future<void> _connect() async {
    var devices = await UsbSerial.listDevices();
    if (devices.isEmpty) return;

    _port = await devices[0].create();
    await _port!.open();
    await _port!.setPortParameters(
      115200, UsbPort.DATABITS_8,
      UsbPort.STOPBITS_1, UsbPort.PARITY_NONE);

    String buffer = '';
    _port!.inputStream?.listen((Uint8List data) {
      buffer += String.fromCharCodes(data);
      while (buffer.contains('\n')) {
        int idx = buffer.indexOf('\n');
        String line = buffer.substring(0, idx).trim();
        buffer = buffer.substring(idx + 1);
        _processData(line);
      }
    });
  }

  void _processData(String line) {
    try {
      var json = jsonDecode(line);
      setState(() {
        suhu = (json['suhu'] ?? 0).toDouble();
        kelembaban = (json['kelembaban'] ?? 0).toDouble();
        cahaya = json['cahaya'] ?? 0;
        suhuHistory.add(FlSpot(tick.toDouble(), suhu));
        if (suhuHistory.length > 30) {
          suhuHistory.removeAt(0);
        }
        tick++;
      });
    } catch (_) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Sensor Dashboard')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(children: [
          // Sensor cards row
          Row(children: [
            _sensorCard('๐ŸŒก๏ธ Suhu', '${suhu.toStringAsFixed(1)}ยฐC',
                Colors.orange),
            const SizedBox(width: 12),
            _sensorCard('๐Ÿ’ง Kelembaban', '${kelembaban.toStringAsFixed(1)}%',
                Colors.blue),
            const SizedBox(width: 12),
            _sensorCard('โ˜€๏ธ Cahaya', '$cahaya',
                Colors.amber),
          ]),
          const SizedBox(height: 24),
          // Chart
          Expanded(
            child: LineChart(LineChartData(
              lineBarsData: [
                LineChartBarData(
                  spots: suhuHistory,
                  isCurved: true,
                  color: Colors.orange,
                  barWidth: 2,
                  dotData: const FlDotData(show: false),
                ),
              ],
            )),
          ),
        ]),
      ),
    );
  }

  Widget _sensorCard(String label, String value, Color color) {
    return Expanded(
      child: Container(
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(
          color: color.withAlpha(25),
          borderRadius: BorderRadius.circular(12),
          border: Border.all(color: color.withAlpha(100)),
        ),
        child: Column(children: [
          Text(label, style: TextStyle(color: color, fontSize: 14)),
          const SizedBox(height: 8),
          Text(value, style: TextStyle(
            color: color, fontSize: 24, fontWeight: FontWeight.bold)),
        ]),
      ),
    );
  }
}
Sensor Dashboard ๐ŸŒก๏ธ Suhu 27.5ยฐC ๐Ÿ’ง Kelembaban 65.2% โ˜€๏ธ Cahaya 2048 Suhu History (30 data points)

Preview: Sensor Dashboard dengan card + line chart real-time

Checklist Minggu 6

๐Ÿ’ก Selesai Fase 2! Kamu sudah bisa menghubungkan Flutter โ†” ESP32 via kabel USB. Minggu depan kita mulai koneksi wireless via Bluetooth! ๐ŸŽ‰