#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <U8g2lib.h>
// Pin & konfigurasi
#define DHTPIN 12
#define DHTTYPE DHT22
#define LDR_PIN 34
#define RELAY_PIN 26
#define LED_PIN 27
// Konfigurasi WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Konfigurasi MQTT
const char* clientId = "clientId-KlvPo5xGXv"; // Ganti dengan ID unik jika perlu
const char* mqttServer = "broker.hivemq.com";
const int mqttPort = 1883;
const char* mqttUser = "";
const char* mqttPassword = "";
// MQTT Topics
const char* mqttTopicSensor = "magang/praktik/iot/sensor";
const char* mqttTopicControl = "magang/praktik/iot/control";
const char* mqttTopicStatus = "magang/praktik/iot/status";
// Bitmaps untuk Ikon
static const unsigned char image_bluetooth_bits[] = {
0x80,0x00,0x40,0x01,0x40,0x02,0x44,0x04,0x48,0x04,0x50,0x02,0x60,0x01,0xc0,0x00,0x60,0x01,0x50,0x02,0x48,0x04,0x44,0x04,0x40,0x02,0x40,0x01,0x80,0x00,0x00,0x00};
static const unsigned char image_bluetooth_not_connected_bits[] = {0x40,0x00,0xc1,0x00,0x42,0x01,0x44,0x02,0x48,0x04,0x10,0x04,0x20,0x02,0x40,0x00,0xa0,0x00,0x50,0x01,0x48,0x02,0x44,0x04,0x40,0x0a,0x40,0x11,0x80,0x20,0x00,0x00};
static const unsigned char image_Layer_10_1_bits[] = {};
static const unsigned char image_Layer_10_bits[] = {0x01,0x10,0x01,0x10,0x06,0x0c,0xf8,0x03};
static const unsigned char image_wifi_full_bits[] = {0x80,0x0f,0x00,0xe0,0x3f,0x00,0x78,0xf0,0x00,0x9c,0xcf,0x01,0xee,0xbf,0x03,0xf7,0x78,0x07,0x3a,0xe7,0x02,0xdc,0xdf,0x01,0xe8,0xb8,0x00,0x70,0x77,0x00,0xa0,0x2f,0x00,0xc0,0x1d,0x00,0x80,0x0a,0x00,0x00,0x07,0x00,0x00,0x02,0x00,0x00,0x00,0x00};
static const unsigned char image_wifi_not_connected_bits[] = {0x84,0x0f,0x00,0x68,0x30,0x00,0x10,0xc0,0x00,0xa4,0x0f,0x01,0x42,0x30,0x02,0x91,0x40,0x04,0x08,0x85,0x00,0xc4,0x1a,0x01,0x20,0x24,0x00,0x10,0x4a,0x00,0x80,0x15,0x00,0x40,0x20,0x00,0x00,0x42,0x00,0x00,0x85,0x00,0x00,0x02,0x01,0x00,0x00,0x00};
// Inisialisasi
DHT dht(DHTPIN, DHTTYPE);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
WiFiClient wifiClient;
PubSubClient client(wifiClient);
// Variabel global
int thresholdTemp = 30;
unsigned long lastDisplayUpdate = 0;
unsigned long lastMqttPublish = 0;
String inputString = "";
void setup() {
Serial.begin(115200);
u8g2.begin();
// connectToWiFi();
// client.setServer(mqttServer, mqttPort);
// client.setCallback(mqttCallback);
dht.begin();
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
void loop() {
// if (!client.connected()) {
// reconnectMQTT();
// }
// client.loop();
if (millis() - lastDisplayUpdate > 1000) {
displayUI();
lastDisplayUpdate = millis();
}
// if (millis() - lastMqttPublish > 10000) {
// publishSensorData();
// printToSerial();
// lastMqttPublish = millis();
// }
readSerialCommand();
}
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 Volt : "); Serial.println(ldr);
Serial.print("Relay : "); Serial.println(digitalRead(RELAY_PIN) ? "ON" : "OFF");
Serial.print("Threshold : "); Serial.println(thresholdTemp);
Serial.println("------------------------");
}
void publishSensorData() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
float voltage = analogRead(LDR_PIN) * (3.3 / 4095.0);
float resistance = (voltage > 0) ? (3.3 - voltage) * 10000 / voltage : 0;
float lux = (resistance > 0) ? 500 / (resistance / 1000) : 0;
bool relayState = digitalRead(RELAY_PIN);
StaticJsonDocument<256> 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);
client.publish(mqttTopicSensor, sensorPayload.c_str());
}
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");
}
}
void connectToWiFi() {
Serial.print("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected to WiFi!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("Connecting to MQTT...");
if (client.connect(clientId, mqttUser, mqttPassword)) {
Serial.println("Connected to MQTT!");
client.subscribe(mqttTopicControl);
Serial.println("Subscribed to: " + String(mqttTopicControl));
} else {
Serial.print("Failed, rc=");
Serial.print(client.state());
delay(5000);
}
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println("Pesan MQTT diterima: " + message);
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, message);
if (error) {
message.trim();
message.toLowerCase();
if (message == "on") {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
publishStatusUpdate();
} else if (message == "off") {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
publishStatusUpdate();
}
return;
}
if (doc.containsKey("relay")) {
String relayCmd = doc["relay"];
if (relayCmd.equalsIgnoreCase("on")) {
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
} else if (relayCmd.equalsIgnoreCase("off")) {
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
publishStatusUpdate();
}
if (doc.containsKey("threshold")) {
thresholdTemp = doc["threshold"];
publishStatusUpdate();
}
}
void publishStatusUpdate() {
StaticJsonDocument<128> statusDoc;
statusDoc["relay"] = digitalRead(RELAY_PIN) ? "ON" : "OFF";
statusDoc["threshold"] = thresholdTemp;
statusDoc["updated"] = "via_mqtt";
String statusPayload;
serializeJson(statusDoc, statusPayload);
client.publish(mqttTopicStatus, statusPayload.c_str());
Serial.println("Status update dikirim: " + statusPayload);
}
void displayUI() {
// Ambil data sensor
float temp = dht.readTemperature();
float hum = dht.readHumidity();
float voltage = analogRead(LDR_PIN) * (3.3 / 4095.0);
float resistance = (voltage > 0) ? (3.3 - voltage) * 10000 / voltage : 0;
float lux = (resistance > 0) ? 500 / (resistance / 1000) : 0;
bool relayState = digitalRead(RELAY_PIN);
// Siapkan buffer untuk mengubah angka menjadi teks
char tempStr[6], humStr[6], luxStr[6], thStr[4];
dtostrf(temp, 4, 1, tempStr);
dtostrf(hum, 4, 1, humStr);
dtostrf(lux, 5, 0, luxStr);
itoa(thresholdTemp, thStr, 10);
u8g2.clearBuffer();
u8g2.setFontMode(1);
u8g2.setBitmapMode(1);
// Bagian Header
u8g2.drawFrame(3, 3, 122, 11);
u8g2.setFont(u8g2_font_4x6_tr); // Font dikecilkan agar pas
u8g2.drawStr(33, 10, "SMART MONITORING");
// Box Kiri (WiFi & MQTT)
u8g2.drawFrame(4, 19, 43, 41);
// Ikon status WiFi (kondisional)
if (WiFi.status() == WL_CONNECTED) {
u8g2.drawXBM(8, 23, 19, 16, image_wifi_full_bits);
} else {
u8g2.drawXBM(7, 23, 19, 16, image_wifi_not_connected_bits);
}
u8g2.drawXBM(29, 23, 14, 16, image_bluetooth_not_connected_bits);
// Label MQTT
u8g2.setFont(u8g2_font_t0_13_tr);
u8g2.drawStr(12, 56, "MQTT");
if(!client.connected()){
u8g2.drawLine(11, 44, 40, 56);
}
// gambar senyum
u8g2.drawEllipse(65, 29, 12, 12);
u8g2.drawXBM(59, 33, 13, 4, image_Layer_10_bits);
u8g2.drawEllipse(60, 26, 2, 2);
u8g2.drawEllipse(70, 26, 2, 2);
// Box Tengah (Status Relay)
u8g2.drawFrame(50, 45, 30, 15);
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.drawStr(57, 56, relayState ? "ON" : "OFF");
// Box Kanan (Data Sensor)
u8g2.drawFrame(83, 19, 42, 41);
u8g2.setFont(u8g2_font_4x6_tr);
u8g2.drawStr(86, 30, "Temp:");
u8g2.drawStr(108, 30, tempStr);
u8g2.drawStr(86, 38, "TH :");
u8g2.drawStr(108, 38, thStr);
u8g2.drawStr(86, 46, "Hum :");
u8g2.drawStr(108, 46, humStr);
u8g2.drawStr(86, 53, "LDR :");
u8g2.drawStr(100, 53, luxStr);
u8g2.sendBuffer();
}