#include <ArduinoJson.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <DHT.h>
#define WIFI_AP "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#define TOKEN "HdcoXBs4dLF2icCa13Yj"
#define GPIO0 0
#define GPIO2 2
#define GPIO0_PIN 3
#define GPIO2_PIN 5
#define BUTTON_PIN 22
char thingsboardServer[] = "demo.thingsboard.io";
WiFiClient wifiClient;
PubSubClient client(wifiClient);
int status = WL_IDLE_STATUS;
// We assume that all GPIOs are LOW
boolean gpioState[] = {false, false};
boolean buttonPressed = false;
// DHT Sensor Configuration
#define DHTPIN 4 // Pin data DHT22 dihubungkan ke pin 4
#define DHTTYPE DHT22 // Jenis sensor DHT yang digunakan
DHT dht(DHTPIN, DHTTYPE);
// Millis untuk pembacaan suhu dan kelembaban
unsigned long lastDHTRead = 0;
const long DHT_INTERVAL = 1000; // Interval pembacaan DHT22 (ms)
// Millis untuk fungsi button fisik
unsigned long lastButtonRead = 0;
const long BUTTON_INTERVAL = 500; // Interval pembacaan tombol (ms)
unsigned long subscribeInterval = 1000; // Interval waktu untuk subscribe (dalam milidetik)
unsigned long lastSubscribeTime = 0;
void setup() {
Serial.begin(115200);
// Set output mode for all GPIO pins
pinMode(GPIO0, OUTPUT);
pinMode(GPIO2, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
dht.begin();
delay(10);
InitWiFi();
client.setServer( thingsboardServer, 1883 );
client.setCallback(on_message);
}
void loop() {
if ( !client.connected() ) {
reconnect();
}
// Jika tombol ditekan (buttonState LOW), hidupkan GPIO0
if (millis() - lastButtonRead >= BUTTON_INTERVAL) {
buttonFunction();
lastButtonRead = millis();
}
// Pembacaan suhu dan kelembaban setiap 10 detik
if (millis() - lastDHTRead >= DHT_INTERVAL) {
readDHT();
lastDHTRead = millis();
}
client.loop();
}
void buttonFunction() {
if (digitalRead(BUTTON_PIN) == HIGH && !buttonPressed) {
digitalWrite(GPIO0, HIGH);
gpioState[0] = true;
// Update status ke ThingsBoard
client.publish("v1/devices/me/attributes", get_gpio_status().c_str());
buttonPressed = true;
} else if(digitalRead(BUTTON_PIN) == LOW && buttonPressed == true) {
digitalWrite(GPIO0, LOW);
gpioState[0] = false;
// Update status ke ThingsBoard
client.publish("v1/devices/me/attributes", get_gpio_status().c_str());
buttonPressed = false;
}
}
// Pembacaan suhu dan kelembaban dari sensor DHT22
void readDHT() {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (!isnan(humidity) && !isnan(temperature)) {
// Kirim data suhu dan kelembaban ke ThingsBoard
String attributes = "{\"temperature\": " + String(temperature) + ", \"humidity\": " + String(humidity) + "}";
client.publish("v1/devices/me/telemetry", attributes.c_str());
Serial.println("Temperature: " + String(temperature) + "°C, Humidity: " + String(humidity) + "%");
} else {
Serial.println("Failed to read from DHT sensor");
}
}
// The callback for when a PUBLISH message is received from the server.
void on_message(const char* topic, byte* payload, unsigned int length) {
Serial.println("On message");
char json[length + 1];
strncpy (json, (char*)payload, length);
json[length] = '\0';
Serial.print("Topic: ");
Serial.println(topic);
Serial.print("Message: ");
Serial.println(json);
// Decode JSON request
StaticJsonDocument<200> data;
//JsonObject& data = jsonBuffer.parseObject((char*)json);
DeserializationError error = deserializeJson(data, json);
// // Check for parsing errors
// if (error) {
// Serial.print("deserializeJson() failed: ");
// Serial.println(error.c_str());
// return;
// }
// Check request method
String methodName = String((const char*)data["method"]);
if (methodName.equals("getGpioStatus")) {
// Reply with GPIO status
String responseTopic = String(topic);
responseTopic.replace("request", "response");
client.publish(responseTopic.c_str(), get_gpio_status().c_str());
} else if (methodName.equals("setGpioStatus")) {
// Update GPIO status and reply
set_gpio_status(data["params"]["pin"], data["params"]["enabled"]);
String responseTopic = String(topic);
responseTopic.replace("request", "response");
client.publish(responseTopic.c_str(), get_gpio_status().c_str());
client.publish("v1/devices/me/attributes", get_gpio_status().c_str());
}
}
String get_gpio_status() {
// Prepare gpios JSON payload string
StaticJsonDocument<200> data;
data[String(GPIO0_PIN)] = gpioState[0] ? true : false;
data[String(GPIO2_PIN)] = gpioState[1] ? true : false;
char payload[256];
String strPayload = String(payload);
serializeJson(data, strPayload);
Serial.print("Get gpio status: ");
Serial.println(strPayload);
return strPayload;
}
void set_gpio_status(int pin, boolean enabled) {
if (pin == GPIO0_PIN) {
digitalWrite(GPIO0, enabled ? HIGH : LOW);
gpioState[0] = enabled;
} else if (pin == GPIO2_PIN) {
digitalWrite(GPIO2, enabled ? HIGH : LOW);
gpioState[1] = enabled;
}
}
void InitWiFi() {
Serial.println("Connecting to AP ...");
WiFi.begin(WIFI_AP, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
void reconnect() {
while (!client.connected()) {
status = WiFi.status();
if ( status != WL_CONNECTED) {
WiFi.begin(WIFI_AP, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to AP");
}
Serial.print("Connecting to ThingsBoard node ...");
if ( client.connect("ESP8266 Device", TOKEN, NULL) ) {
Serial.println( "[DONE]" );
// Subscribing to receive RPC requests
client.subscribe("v1/devices/me/rpc/request/+");
// Sending current GPIO status
Serial.println("Sending current GPIO status ...");
client.publish("v1/devices/me/attributes", get_gpio_status().c_str());
} else {
Serial.print( "[FAILED] [ rc = " );
Serial.print( client.state() );
Serial.println( " : retrying in 5 seconds]" );
// Wait 5 seconds before retrying
delay( 5000 );
}
}
}