254 lines
7.0 KiB
C++
254 lines
7.0 KiB
C++
#include <Adafruit_NeoPixel.h>
|
|
#include <Arduino.h>
|
|
#include <hp_BH1750.h>
|
|
#include "Seeed_Arduino_mmWave.h"
|
|
|
|
/* ========================= WIFI + MQTT ========================= */
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
#include <WiFi.h>
|
|
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
|
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
|
#include <ESP8266WiFi.h>
|
|
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
|
|
#elif defined(ARDUINO_UNOWIFIR4)
|
|
#include <WiFiS3.h>
|
|
#else
|
|
#include <WiFiNINA.h>
|
|
#endif
|
|
#include <PubSubClient.h>
|
|
|
|
// WiFiManager akan menangani kredensial WiFi
|
|
// Tidak perlu lagi WIFI_SSID dan WIFI_PASS yang di-hardcode
|
|
|
|
const char* MQTT_HOST = "103.106.72.181";
|
|
const uint16_t MQTT_PORT = 1883;
|
|
const char* MQTT_USER = "capstone";
|
|
const char* MQTT_PASSW = "hint12345";
|
|
const char* MQTT_TOPIC = "hitam";
|
|
|
|
const char* ROOM_ID = "SUITE-5";
|
|
const int NILAI_SENSOR = 0;
|
|
|
|
WiFiClient wifiClient;
|
|
PubSubClient mqttClient(wifiClient);
|
|
WiFiManager wifiManager;
|
|
|
|
/* ========================= WIFI AUTO RECOVERY ========================= */
|
|
unsigned long lastWifiCheck = 0;
|
|
|
|
void wifi_connect() {
|
|
// Set hostname untuk identifikasi lebih mudah
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
WiFi.setHostname("MR60FDA2-EXEC3");
|
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
|
WiFi.hostname("MR60FDA2-EXEC3");
|
|
#endif
|
|
|
|
// WiFiManager akan membuat AP dengan nama "MR60FDA2-AutoConnect"
|
|
// Jika tidak bisa connect ke WiFi tersimpan, akan membuat portal konfigurasi
|
|
wifiManager.setConfigPortalTimeout(180); // Timeout 3 menit untuk portal konfigurasi
|
|
|
|
// Custom parameters (opsional - untuk konfigurasi tambahan)
|
|
// WiFiManagerParameter custom_mqtt_server("server", "mqtt server", MQTT_HOST, 40);
|
|
// wifiManager.addParameter(&custom_mqtt_server);
|
|
|
|
if (!wifiManager.autoConnect("MR60FDA2-SUITE5", "12345678")) {
|
|
Serial.println("Failed to connect and hit timeout");
|
|
// Reset dan coba lagi
|
|
delay(3000);
|
|
ESP.restart();
|
|
}
|
|
|
|
Serial.println("\nWiFi connected!");
|
|
Serial.print("IP address: ");
|
|
Serial.println(WiFi.localIP());
|
|
}
|
|
|
|
void ensure_wifi() {
|
|
if (millis() - lastWifiCheck < 5000) return;
|
|
lastWifiCheck = millis();
|
|
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
Serial.println("WiFi lost, reconnecting...");
|
|
WiFi.disconnect(true);
|
|
delay(500);
|
|
wifi_connect();
|
|
}
|
|
}
|
|
|
|
// Fungsi untuk reset WiFi settings (panggil jika ingin clear kredensial)
|
|
void reset_wifi_settings() {
|
|
Serial.println("Resetting WiFi settings...");
|
|
wifiManager.resetSettings();
|
|
delay(1000);
|
|
ESP.restart();
|
|
}
|
|
/* =============================================================== */
|
|
|
|
String makeClientId() {
|
|
String cid = "MR60FDA2-";
|
|
#if defined(ARDUINO_ARCH_ESP32)
|
|
cid += String((uint32_t)ESP.getEfuseMac(), HEX);
|
|
#elif defined(ARDUINO_ARCH_ESP8266)
|
|
cid += String(ESP.getChipId(), HEX);
|
|
#else
|
|
cid += String(millis(), HEX);
|
|
#endif
|
|
return cid;
|
|
}
|
|
|
|
void mqtt_callback(char* topic, byte* payload, unsigned int length);
|
|
|
|
void mqtt_reconnect() {
|
|
if (WiFi.status() != WL_CONNECTED) return;
|
|
|
|
while (!mqttClient.connected()) {
|
|
if (mqttClient.connect(makeClientId().c_str(), MQTT_USER, MQTT_PASSW)) {
|
|
mqttClient.subscribe(MQTT_TOPIC);
|
|
Serial.println("MQTT connected");
|
|
} else {
|
|
Serial.println("MQTT retry...");
|
|
delay(3000);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ========================= HARDWARE ========================= */
|
|
#ifdef ESP32
|
|
#include <HardwareSerial.h>
|
|
HardwareSerial mmwaveSerial(0);
|
|
#else
|
|
#define mmwaveSerial Serial1
|
|
#endif
|
|
|
|
#define LIGHT_GPIO D0
|
|
|
|
hp_BH1750 BH1750;
|
|
SEEED_MR60FDA2 mmWave;
|
|
Adafruit_NeoPixel pixels(1, D1, NEO_GRB + NEO_KHZ800);
|
|
|
|
void relay_init() { pinMode(LIGHT_GPIO, OUTPUT); }
|
|
void relay_on() { digitalWrite(LIGHT_GPIO, HIGH); }
|
|
void relay_off() { digitalWrite(LIGHT_GPIO, LOW); }
|
|
|
|
/* ========================= SENSOR PARAM ========================= */
|
|
uint32_t sensitivity = 10;
|
|
float height = 2.8, threshold = 0.8;
|
|
const uint8_t dark_lux = 10;
|
|
|
|
typedef enum { PEOPLE, NO_PEOPLE, PEOPLE_FALL } MMWAVE_STATUS;
|
|
MMWAVE_STATUS status = NO_PEOPLE, last_status = NO_PEOPLE;
|
|
|
|
float lux = 100;
|
|
|
|
/* ========================= SETUP ========================= */
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
delay(1000);
|
|
|
|
Serial.println("\n\nStarting MR60FDA2 System...");
|
|
|
|
mmWave.begin(&mmwaveSerial);
|
|
|
|
relay_init();
|
|
|
|
pixels.begin();
|
|
pixels.setBrightness(50);
|
|
pixels.setPixelColor(0, pixels.Color(125,125,125));
|
|
pixels.show();
|
|
|
|
BH1750.begin(BH1750_TO_GROUND);
|
|
BH1750.start(BH1750_QUALITY_HIGH2, 254);
|
|
|
|
mmWave.setInstallationHeight(height);
|
|
mmWave.setThreshold(threshold);
|
|
mmWave.setSensitivity(sensitivity);
|
|
|
|
// WiFiManager setup
|
|
Serial.println("Connecting to WiFi...");
|
|
Serial.println("If first time, connect to AP: MR60FDA2-AutoConnect");
|
|
Serial.println("Password: 12345678");
|
|
|
|
wifi_connect();
|
|
|
|
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
|
mqttClient.setCallback(mqtt_callback);
|
|
mqtt_reconnect();
|
|
|
|
Serial.println("Setup complete!");
|
|
}
|
|
|
|
/* ========================= LOOP ========================= */
|
|
void loop() {
|
|
ensure_wifi();
|
|
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
if (!mqttClient.connected()) mqtt_reconnect();
|
|
mqttClient.loop();
|
|
}
|
|
|
|
if (mmWave.update(100)) {
|
|
bool h, f;
|
|
mmWave.getHuman(h);
|
|
mmWave.getFall(f);
|
|
status = (!h && !f) ? NO_PEOPLE : (f ? PEOPLE_FALL : PEOPLE);
|
|
}
|
|
|
|
/* ===== EVENT-BASED MQTT ===== */
|
|
if (status != last_status) {
|
|
pixels.setPixelColor(0,
|
|
status == PEOPLE ? pixels.Color(0,255,0) :
|
|
status == PEOPLE_FALL ? pixels.Color(255,0,0) :
|
|
pixels.Color(0,0,255));
|
|
pixels.show();
|
|
|
|
String eventPayload = String("{\"event\":\"status_change\",\"room_id\":\"") + ROOM_ID +
|
|
"\",\"nilai_sensor\":" + NILAI_SENSOR +
|
|
",\"status\":\"" +
|
|
(status==PEOPLE?"PEOPLE":status==PEOPLE_FALL?"PEOPLE_FALL":"NO_PEOPLE") +
|
|
"\"}";
|
|
|
|
mqttClient.publish(MQTT_TOPIC, eventPayload.c_str());
|
|
last_status = status;
|
|
}
|
|
|
|
/* ===== LUX UPDATE ===== */
|
|
if (BH1750.hasValue()) {
|
|
lux = BH1750.getLux();
|
|
BH1750.start(BH1750_QUALITY_HIGH2, 254);
|
|
}
|
|
|
|
/* ===== TELEMETRY 15 DETIK ===== */
|
|
static unsigned long lastPub = 0;
|
|
if (millis() - lastPub > 15000) {
|
|
lastPub = millis();
|
|
|
|
String telemetry = String("{\"telemetry\":true,\"room_id\":\"") + ROOM_ID +
|
|
"\",\"nilai_sensor\":" + NILAI_SENSOR +
|
|
",\"status\":\"" +
|
|
(status==PEOPLE?"PEOPLE":status==PEOPLE_FALL?"PEOPLE_FALL":"NO_PEOPLE") +
|
|
"\",\"lux\":" + String(lux,1) +
|
|
",\"rssi\":" + WiFi.RSSI() + "}";
|
|
|
|
mqttClient.publish(MQTT_TOPIC, telemetry.c_str());
|
|
}
|
|
|
|
/* ===== RELAY CONTROL ===== */
|
|
if ((status == PEOPLE || status == PEOPLE_FALL) && lux < dark_lux) relay_on();
|
|
else relay_off();
|
|
}
|
|
|
|
/* ========================= MQTT CALLBACK ========================= */
|
|
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
|
String msg;
|
|
for (uint8_t i = 0; i < length; i++) msg += (char)payload[i];
|
|
|
|
if (msg.indexOf("relay_on") != -1) relay_on();
|
|
if (msg.indexOf("relay_off") != -1) relay_off();
|
|
|
|
// Tambahan: command untuk reset WiFi settings
|
|
if (msg.indexOf("reset_wifi") != -1) {
|
|
reset_wifi_settings();
|
|
}
|
|
}
|