#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ArduinoJson.h>
// ===== WiFi Config =====
const char* ssid = "Wokwi-GUEST"; // ganti dengan WiFi Anda
const char* password = "";
// ===== ThingsBoard Config =====
const char* mqtt_server = "thingsboard.cloud"; // server ThingsBoard
const int mqtt_port = 1883;
const char* access_token = "yjisll1rfplofacx7a2e"; // token device dari ThingsBoard
WiFiClient espClient;
PubSubClient client(espClient);
// ===== Pin Config =====
const int potPin = 34; // Potentiometer pin (ADC)
const int servo1Pin = 18;
const int servo2Pin = 19;
Servo servo1;
Servo servo2;
// ===== OLED Config =====
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ===== Variabel kontrol =====
int virtualPotValue = -1; // -1 = pakai potensiometer fisik
// ===== MQTT Callback =====
void callback(char* topic, byte* message, unsigned int length) {
String msg;
for (unsigned int i = 0; i < length; i++) {
msg += (char)message[i];
}
Serial.printf("Message arrived [%s] %s\n", topic, msg.c_str());
if (String(topic).startsWith("v1/devices/me/rpc/request/")) {
DynamicJsonDocument doc(256);
deserializeJson(doc, msg);
String method = doc["method"];
if (method == "setState") {
int value = doc["params"];
virtualPotValue = constrain(value, 0, 180);
servo1.write(virtualPotValue);
servo2.write(virtualPotValue);
Serial.printf("Servo angle via setState: %d\n", virtualPotValue);
}
if (method == "getState") {
String responseTopic = String("v1/devices/me/rpc/response/") +
String(topic).substring(String(topic).lastIndexOf("/") + 1);
String payload = String(virtualPotValue);
client.publish(responseTopic.c_str(), payload.c_str());
Serial.printf("Responding getState: %d\n", virtualPotValue);
}
}
} // <<<=== KURUNG callback() HARUS DITUTUP DI SINI
// ===== MQTT Reconnect =====
void reconnect() {
while (!client.connected()) {
Serial.print("Connecting to ThingsBoard...");
if (client.connect("ESP32Client", access_token, NULL)) {
Serial.println("connected");
// Subscribe RPC request ThingsBoard
client.subscribe("v1/devices/me/rpc/request/+");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
delay(2000);
}
}
}
void setup() {
Serial.begin(115200);
// Servo init
servo1.attach(servo1Pin);
servo2.attach(servo2Pin);
// OLED init
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Berhenti kalau gagal
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("ESP32 Servo Monitor");
display.display();
// WiFi init
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
// MQTT init
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
// Servo ke posisi awal
int initialServo = 90;
servo1.write(initialServo);
servo2.write(initialServo);
// kirim nilai awal ke ThingsBoard
String payload = String("{\"servo\":") + initialServo + "}";
client.publish("v1/devices/me/telemetry", payload.c_str());
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Tentukan angle berdasarkan RPC atau potensiometer fisik
int angle;
if (virtualPotValue >= 0) {
angle = virtualPotValue; // nilai dari ThingsBoard
} else {
int potValue = analogRead(potPin); // nilai fisik
angle = map(potValue, 0, 4095, 0, 180);
}
// Gerakkan servo
servo1.write(angle);
servo2.write(angle);
// Tampilkan ke OLED
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("ESP32 Servo Monitor");
display.drawLine(0, 10, SCREEN_WIDTH, 10, SSD1306_WHITE);
display.setCursor(0, 20);
display.println("Angle Servo:");
display.setTextSize(2);
display.setCursor(0, 35);
display.printf("%d deg", angle);
display.display();
// Kirim telemetry ke ThingsBoard
String payload = String("{\"angle\":") + angle + "}";
client.publish("v1/devices/me/telemetry", payload.c_str());
Serial.printf("Published angle: %d\n", angle);
delay(2000);
}