#include <DHTesp.h> // DHT for ESP32 library
#include <WiFi.h> // WiFi control for ESP32
#include "Thingsboard.h"
#include <ESP32Servo.h>
#include <RTClib.h>
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define WIFI_AP_NAME "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#define THINGSBOARD_SERVER "thingsboardcloud.adamrabbani.com"
#define THINGSBOARD_ACCESSTOKEN "WsussnQmR9CeapYT2Xjh"
WiFiClient espClient;
ThingsBoard tb(espClient);
int status = WL_IDLE_STATUS;
uint8_t pin_control[] = { 2, 4, 5 };
DHTesp dht;
#define DHT_PIN 15
// send message delay
int quant = 10;
int send_delay = 1000;
int send_time_passed = 0;
bool subscribed = false;
float temperature = 0;
bool is_heater_on = false;
//============================================================//
Servo myservo;
#define Servo_PIN 26
// servo delay
const long servo_delay = 3000;
int servo_time_passed = 0;
int recent_servo_open = -1;
bool cmd_servo_open = false;
bool control_auto = false;
bool servo_lamp = 0;
#define trigPin 13
#define echoPin 12
int foodTankPercentage = 0;
#define phPIN 34
int phValue = 0;
RTC_DS1307 rtc;
RPC_Response processSetSwitchAuto(const RPC_Data &data)
{
Serial.println("processSetSwitchAuto");
control_auto = data;
Serial.println(control_auto);
return String(control_auto);
}
RPC_Response processGetSwitchAuto(const RPC_Data &data)
{
Serial.println("processGetSwitchAuto");
return String(control_auto);
}
RPC_Response processSwitchManualFeeder(const RPC_Data &data)
{
Serial.println("processSwitchManualFeeder");
cmd_servo_open = true;
Serial.println(cmd_servo_open);
return String(cmd_servo_open);
}
// RPC callback handlers
RPC_Callback callbacks[] = {
{ "setSwitchAuto", processSetSwitchAuto },
{ "getSwitchAuto", processGetSwitchAuto },
{ "setSwitchManualFeeder", processSwitchManualFeeder },
};
int measureFoodTank(){
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = duration * 0.034 / 2;
int value = map(distance, 0, 400, 0, 100);
return value;
}
int measurePH(){
int ph = analogRead(phPIN);
int value = map(ph, 0, 4095, 0, 14);
return value;
}
void checkConditionTemp(){
if(temperature < 20 ){
is_heater_on = true;
}else{
is_heater_on = false;
}
}
void setup() {
Serial.begin(115200);
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
myservo.attach(Servo_PIN);
myservo.write(0);
int i = 0;
for (size_t i = 0; i < COUNT_OF(pin_control); ++i) {
pinMode(pin_control[i], OUTPUT);
}
dht.setup(DHT_PIN, DHTesp::DHT22);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
connectWifi();
}
void loop()
{
delay(quant);
send_time_passed += quant;
foodTankPercentage = measureFoodTank();
phValue = measurePH();
checkConditionTemp();
// Reconnect to WiFi, if needed
if (WiFi.status() != WL_CONNECTED) {
connectWifi();
return;
}
if (!tb.connected()) {
subscribed = false;
Serial.print("Koneksi ke: ");
Serial.print(THINGSBOARD_SERVER);
Serial.print(" dengan token ");
Serial.println(THINGSBOARD_ACCESSTOKEN);
if (!tb.connect(THINGSBOARD_SERVER, THINGSBOARD_ACCESSTOKEN)) {
Serial.println("gagal terhubung");
return;
}
}
// Subscribe for RPC, if needed
if (!subscribed) {
Serial.println("Subscribing for RPC... ");
if (!tb.RPC_Subscribe(callbacks, COUNT_OF(callbacks))) {
Serial.println("Failed to subscribe for RPC");
return;
}
Serial.println("Subscribe done");
subscribed = true;
}
digitalWrite(pin_control[0], control_auto);
digitalWrite(pin_control[1], servo_lamp);
digitalWrite(pin_control[2], is_heater_on);
if (send_time_passed > send_delay) {
Serial.println();
Serial.print("Sending data... ");
TempAndHumidity dHT22Values = dht.getTempAndHumidity();
if (isnan(dHT22Values.humidity) || isnan(dHT22Values.temperature)) {
Serial.println("Gagal membaca sensor!");
} else {
temperature = dHT22Values.temperature;
tb.sendTelemetryFloat("suhu", temperature);
Serial.print("Suhu: ");
Serial.print(temperature);
}
tb.sendAttributeBool("servoIndicator", servo_lamp);
tb.sendTelemetryInt("foodTankValue", foodTankPercentage);
tb.sendTelemetryInt("phValue", phValue);
tb.sendAttributeBool("heaterIndicator", is_heater_on);
Serial.print("foodTankPercentage: ");
Serial.println(foodTankPercentage);
Serial.print("phValue: ");
Serial.println(phValue);
send_time_passed = 0;
}
if(cmd_servo_open && !control_auto){
openServoFeeder(-1);
}else if(control_auto){
feederScheduler();
}else{
myservo.write(0);
cmd_servo_open = false;
}
tb.loop();
}
void connectWifi()
{
Serial.println("Koneksi ke AP ...");
WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Terkoneksi ke AP");
}
void openServoFeeder(int open_time){
servo_time_passed += quant;
myservo.write(90);
servo_lamp = true;
if (servo_time_passed > servo_delay) {
myservo.write(0);
servo_lamp = false;
cmd_servo_open = servo_lamp;
recent_servo_open = open_time;
servo_time_passed = 0;
}
}
void feederScheduler(){
DateTime now = rtc.now();
Serial.print(now.hour());
Serial.print(':');
Serial.print(now.minute());
Serial.print(':');
Serial.print(now.second());
Serial.println();
if (now.hour() == 8 && recent_servo_open != 8) {
openServoFeeder(8);
}else if (now.hour() == 12 && recent_servo_open != 12) {
openServoFeeder(12);
}else if (now.hour() == 16 && recent_servo_open != 16){
openServoFeeder(16);
}
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND
led1:A
led1:C
led4:A
led4:C
ultrasonic1:VCC
ultrasonic1:TRIG
ultrasonic1:ECHO
ultrasonic1:GND
servo1:GND
servo1:V+
servo1:PWM
pot1:VCC
pot1:SIG
pot1:GND
rtc1:GND
rtc1:5V
rtc1:SDA
rtc1:SCL
rtc1:SQW
led2:A
led2:C