#include <Arduino.h>
#include "esp_sleep.h"
/* ================= MODE ================= */
// 1 = simulasi Wokwi
// 0 = hardware ESP32-C3 asli
#define SIM_WOKWI 1
#if !SIM_WOKWI
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#endif
/* ================= PIN ================= */
#define PIN_BUTTON 5 // D3
#define PIN_ADC 2 // A0
#define LED_R 20 // D7
#define LED_G 21 // D6
#define LED_Y 7 // D5
#define LED_W 6 // D4
#define LED_B 8 // D8
/* ================= STATE ================= */
enum State {
IDLE,
WARMUP,
RUN,
OFF
};
State state = IDLE;
/* ================= TIMER ================= */
const unsigned long WARMUP_TIME = 10000;
const unsigned long RUN_TIME = 80000;
const unsigned long BLE_INTERVAL = 1000;
unsigned long startTime = 0;
unsigned long lastBle = 0;
/* ================= BLE ================= */
#if !SIM_WOKWI
BLECharacteristic* txChar;
bool bleConnected = false;
class ServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer*) override {
bleConnected = true;
Serial.println("BLE connected");
}
void onDisconnect(BLEServer* server) override {
bleConnected = false;
Serial.println("BLE disconnected");
server->startAdvertising();
}
};
#endif
/* ================= HELPER ================= */
void setColor(bool r, bool g, bool y) {
digitalWrite(LED_R, r);
digitalWrite(LED_G, g);
digitalWrite(LED_Y, y);
}
/* ================= BLE SEND ================= */
void sendBLE(const String& msg) {
#if SIM_WOKWI
Serial.println("[BLE SIM] " + msg);
#else
if (bleConnected) {
txChar->setValue(msg.c_str());
txChar->notify();
}
#endif
}
/* ================= BLE FILE SEND ================= */
void sendFileBLE(const uint8_t* data, size_t length) {
const size_t CHUNK_SIZE = 180;
size_t offset = 0;
#if SIM_WOKWI
Serial.println("[BLE SIM] SEND FILE START");
Serial.print("SIZE: ");
Serial.println(length);
Serial.println("[BLE SIM] SEND FILE END");
#else
if (!bleConnected) return;
while (offset < length) {
size_t chunkLen = min(CHUNK_SIZE, length - offset);
txChar->setValue((uint8_t*)(data + offset), chunkLen);
txChar->notify();
offset += chunkLen;
delay(20);
}
#endif
}
/* ================= BLE SETUP ================= */
#if !SIM_WOKWI
void setupBLE() {
BLEDevice::init("XIAO-GAS");
BLEServer* server = BLEDevice::createServer();
server->setCallbacks(new ServerCallbacks());
BLEService* service = server->createService(
"12345678-1234-1234-1234-1234567890ab"
);
txChar = service->createCharacteristic(
"abcd1234-1a2b-3c4d-5e6f-abcdefabcdef",
BLECharacteristic::PROPERTY_NOTIFY
);
txChar->addDescriptor(new BLE2902());
service->start();
server->getAdvertising()->start();
Serial.println("BLE READY");
}
#endif
/* ================= SETUP ================= */
void setup() {
Serial.begin(115200);
pinMode(PIN_BUTTON, INPUT_PULLUP);
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_Y, OUTPUT);
pinMode(LED_W, OUTPUT);
pinMode(LED_B, OUTPUT);
analogReadResolution(12);
#if SIM_WOKWI
Serial.println("MODE SIMULASI WOKWI");
#else
setupBLE();
#endif
Serial.println("SYSTEM SIAP");
}
/* ================= LOOP ================= */
void loop() {
unsigned long now = millis();
switch (state) {
case IDLE:
setColor(0,0,0);
digitalWrite(LED_W, LOW);
digitalWrite(LED_B, LOW);
if (digitalRead(PIN_BUTTON) == LOW) {
delay(300);
state = WARMUP;
startTime = now;
Serial.println("MEMANASKAN SENSOR...");
}
break;
case WARMUP:
digitalWrite(LED_W, (now / 500) % 2);
if (now - startTime >= WARMUP_TIME) {
state = RUN;
startTime = now;
Serial.println("SENSOR SIAP");
}
break;
case RUN: {
digitalWrite(LED_B, HIGH);
int value = analogRead(PIN_ADC);
if (now - lastBle >= BLE_INTERVAL) {
sendBLE("ADC=" + String(value));
lastBle = now;
}
if (value >= 3700) {
Serial.println("BAHAYA");
setColor(1,0,0);
} else if (value >= 2700) {
Serial.println("WASPADA");
setColor(0,0,1);
} else if (value >= 844) {
Serial.println("AMAN");
setColor(0,1,0);
} else {
Serial.println("SENSOR TIDAK MENDETEKSI");
setColor(0,0,0);
}
if (now - startTime >= RUN_TIME) {
state = OFF;
}
break;
}
case OFF: {
setColor(0,0,0);
sendBLE("STATE=off");
/* contoh file */
const char fileData[] = "LOG DATA SENSOR\nEND\n";
sendFileBLE((uint8_t*)fileData, sizeof(fileData));
#if SIM_WOKWI
if (digitalRead(PIN_BUTTON) == LOW) {
delay(300);
state = IDLE;
}
#else
delay(2000);
esp_sleep_enable_gpio_wakeup();
gpio_wakeup_enable((gpio_num_t)PIN_BUTTON, GPIO_INTR_LOW_LEVEL);
esp_deep_sleep_start();
#endif
break;
}
}
delay(100);
}
Loading
xiao-esp32-c3
xiao-esp32-c3