#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// Pin & konfigurasi
#define DHTPIN 12
#define DHTTYPE DHT22
#define LDR_PIN 34
#define BTN_MODE 14
#define RELAY_PIN 26
#define LED_PIN 27
// Konfigurasi WiFi
const char* ssid = "Wokwi-GUEST"; // default wokwi
const char* password = "";
// Konfigurasi MQTT
const char* clientId = "clientId-KlvPo5xGXv";
const char* mqttServer = "mqtt-dashboard.com";
const int mqttPort = 1883;
const char* mqttUser = "";
const char* mqttPassword = "";
// MQTT Topics
const char* mqttTopicSensor = "magang/praktik/iot/sensor"; // Untuk mengirim data sensor
const char* mqttTopicControl = "magang/praktik/iot/control"; // Untuk menerima perintah
const char* mqttTopicStatus = "magang/praktik/iot/status"; // Untuk mengirim status relay
// Inisialisasi
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(128, 64, &Wire, -1);
WiFiClient wifiClient;
PubSubClient client(wifiClient);
// Variabel global
int mode = 1;
int thresholdTemp = 30;
unsigned long lastDebounce = 0;
unsigned long lastSerialPrint = 0;
unsigned long lastMqttPublish = 0;
String inputString = "";
void setup() {
Serial.begin(115200);
connectToWiFi();
client.setServer(mqttServer, mqttPort);
client.setCallback(mqttCallback);
dht.begin();
pinMode(BTN_MODE, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
}
void loop() {
// Cek koneksi MQTT
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
// Tombol ganti mode
if (digitalRead(BTN_MODE) == LOW && millis() - lastDebounce > 300) {
mode++;
if (mode > 3) mode = 1;
lastDebounce = millis();
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
switch (mode) {
case 1: showSensorData(); break;
case 2: showRelayStatus(); break;
case 3: showThresholdControl(); break;
}
display.display();
// Tampilkan data ke Serial setiap 5 detik
if (millis() - lastSerialPrint > 5000) {
printToSerial();
lastSerialPrint = millis();
}
// Kirim data sensor ke MQTT setiap 10 detik
if (millis() - lastMqttPublish > 10000) {
publishSensorData();
lastMqttPublish = millis();
}
// Terima command dari Serial Monitor
readSerialCommand();
delay(200);
}
void showSensorData() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
float voltage = analogRead(LDR_PIN) * (3.3 / 4095.0);
float resistance = (3.3 - voltage) * 10000 / voltage;
float lux = 500 / (resistance / 1000); // estimasi lux
display.setCursor(0, 0);
display.println("Mode 1: Sensor");
display.print("Temp: "); display.print(temp); display.println(" C");
display.print("Hum : "); display.print(hum); display.println(" %");
display.print("Lux : "); display.println(lux);
display.println("MQTT: Connected");
if (temp > thresholdTemp) {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
display.println("Relay ON");
} else {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
display.println("Relay OFF");
}
}
void showRelayStatus() {
float temp = dht.readTemperature();
display.setCursor(0, 0);
display.println("Mode 2: Relay");
bool state = digitalRead(RELAY_PIN);
display.print("Relay: ");
display.println(state ? "ON" : "OFF");
display.println("Control via MQTT:");
display.println("on / off");
if (temp > thresholdTemp) {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
display.println("Relay ON");
} else {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
display.println("Relay OFF");
}
}
void showThresholdControl() {
float temp = dht.readTemperature();
display.setCursor(0, 0);
display.println("Mode 3: Threshold");
display.print("Batas: "); display.print(thresholdTemp); display.println(" C");
display.print("Suhu : "); display.print(temp); display.println(" C");
if (temp > thresholdTemp) {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
display.println("Relay ON");
} else {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
display.println("Relay OFF");
}
}
void printToSerial() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
float ldr = analogRead(LDR_PIN) * (3.3 / 4095.0);
Serial.println("----- Sensor Data -----");
Serial.print("Temp : "); Serial.print(temp); Serial.println(" C");
Serial.print("Humidity : "); Serial.print(hum); Serial.println(" %");
Serial.print("LDR : "); Serial.println(ldr);
Serial.print("Relay : "); Serial.println(digitalRead(RELAY_PIN) ? "ON" : "OFF");
Serial.print("Threshold : "); Serial.println(thresholdTemp);
Serial.println("------------------------");
}
// Fungsi untuk mengirim data sensor ke MQTT
void publishSensorData() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
float voltage = analogRead(LDR_PIN) * (3.3 / 4095.0);
float resistance = (3.3 - voltage) * 10000 / voltage;
float lux = 500 / (resistance / 1000);
bool relayState = digitalRead(RELAY_PIN);
// Membuat JSON untuk data sensor
StaticJsonDocument<200> sensorDoc;
sensorDoc["temperature"] = temp;
sensorDoc["humidity"] = hum;
sensorDoc["lux"] = lux;
sensorDoc["relay_state"] = relayState;
sensorDoc["threshold"] = thresholdTemp;
sensorDoc["timestamp"] = millis();
String sensorPayload;
serializeJson(sensorDoc, sensorPayload);
// Publish data sensor
if (client.publish(mqttTopicSensor, sensorPayload.c_str())) {
Serial.println("Data sensor berhasil dikirim ke MQTT");
Serial.println("Payload: " + sensorPayload);
} else {
Serial.println("Gagal mengirim data sensor ke MQTT");
}
// Kirim status relay terpisah
StaticJsonDocument<100> statusDoc;
statusDoc["relay"] = relayState ? "ON" : "OFF";
statusDoc["threshold"] = thresholdTemp;
statusDoc["auto_mode"] = (mode == 3);
String statusPayload;
serializeJson(statusDoc, statusPayload);
if (client.publish(mqttTopicStatus, statusPayload.c_str())) {
Serial.println("Status berhasil dikirim ke MQTT");
}
}
// Fungsi membaca perintah dari Serial Monitor
void readSerialCommand() {
while (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
processSerialCommand(inputString);
inputString = "";
} else {
inputString += c;
}
}
}
void processSerialCommand(String cmd) {
cmd.trim();
if (cmd.startsWith("threshold:")) {
int val = cmd.substring(10).toInt();
thresholdTemp = val;
Serial.println("Threshold diubah ke: " + String(thresholdTemp));
}
else if (cmd == "on") {
digitalWrite(RELAY_PIN, HIGH);
Serial.println("Relay ON via Serial");
}
else if (cmd == "off") {
digitalWrite(RELAY_PIN, LOW);
Serial.println("Relay OFF via Serial");
}
else {
Serial.println("Perintah tidak dikenali");
}
}
// Fungsi untuk menghubungkan ke WiFi
void connectToWiFi() {
Serial.print("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("Connected to WiFi!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
// Fungsi untuk menghubungkan ke MQTT Broker
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect(clientId, mqttUser, mqttPassword)) {
Serial.println("Connected to MQTT!");
// Subscribe ke topic control untuk menerima perintah
client.subscribe(mqttTopicControl);
Serial.println("Subscribed to: " + String(mqttTopicControl));
} else {
Serial.print("Failed, rc=");
Serial.print(client.state());
delay(5000);
}
}
}
// Callback untuk menerima pesan MQTT
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// Convert payload to string
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println("Pesan MQTT diterima:");
Serial.println("Topic: " + String(topic));
Serial.println("Message: " + message);
// Parse JSON message
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, message);
if (error) {
Serial.println("Error parsing JSON, mencoba perintah teks biasa...");
// Jika bukan JSON, coba sebagai perintah teks biasa
message.trim();
message.toLowerCase();
if (message == "on") {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
Serial.println("Relay ON via MQTT");
publishStatusUpdate();
}
else if (message == "off") {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
Serial.println("Relay OFF via MQTT");
publishStatusUpdate();
}
else {
Serial.println("Perintah MQTT tidak dikenali: " + message);
}
return;
}
// Process JSON commands
if (doc.containsKey("relay")) {
String relayCmd = doc["relay"];
relayCmd.toLowerCase();
if (relayCmd == "on") {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
Serial.println("Relay ON via MQTT JSON");
}
else if (relayCmd == "off") {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
Serial.println("Relay OFF via MQTT JSON");
}
publishStatusUpdate();
}
if (doc.containsKey("threshold")) {
int newThreshold = doc["threshold"];
if (newThreshold > 0 && newThreshold < 100) {
thresholdTemp = newThreshold;
Serial.println("Threshold diubah via MQTT ke: " + String(thresholdTemp));
publishStatusUpdate();
}
}
if (doc.containsKey("mode")) {
int newMode = doc["mode"];
if (newMode >= 1 && newMode <= 3) {
mode = newMode;
Serial.println("Mode diubah via MQTT ke: " + String(mode));
}
}
}
// Fungsi untuk mengirim update status setelah perubahan
void publishStatusUpdate() {
StaticJsonDocument<150> statusDoc;
statusDoc["relay"] = digitalRead(RELAY_PIN) ? "ON" : "OFF";
statusDoc["threshold"] = thresholdTemp;
statusDoc["mode"] = mode;
statusDoc["updated"] = "via_mqtt";
String statusPayload;
serializeJson(statusDoc, statusPayload);
client.publish(mqttTopicStatus, statusPayload.c_str());
Serial.println("Status update dikirim: " + statusPayload);
}