// Library
#include <ESP32Servo.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include "HX711.h"
#include "ArduinoJson.h"
#include <HTTPClient.h>
// Variables
Servo servoFood;
Servo servoDoor;
HX711 scale;
const int LOADCELL_DOUT_PIN = 21;
const int LOADCELL_SCK_PIN = 19;
int servoFoodPin = 13;
int servoDoorPin = 12;
int buzzerPin = 33;
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "broker.hivemq.com";
int port = 1883;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
// Test food amount
int food = 0;
// Internet connection
void wifiConnect() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected!");
}
void mqttConnect() {
while(!mqttClient.connected()) {
Serial.println("Attemping MQTT connection...");
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
if(mqttClient.connect(clientId.c_str())) {
Serial.print("Connected!");
//***Subscribe all topic you need***
mqttClient.subscribe("21127345/DoAnCuoiKiInput");
}
else {
Serial.println("Try again in 5 seconds");
delay(5000);
}
}
}
//MQTT Receiver
void callback(char* topic, byte* message, unsigned int length) {
Serial.println(topic);
String strMsg;
for(int i=0; i<length; i++) {
strMsg += (char)message[i];
}
Serial.println(strMsg);
int num = 0;
//***Code here to process the received package**
// Json code is from: https://www.youtube.com/watch?v=iuHxPQB6Rx4 (Applying for version 5)
// Upgrading to version 6 is seen in this link: https://arduinojson.org/v6/doc/upgrade/
StaticJsonDocument<300> doc;
auto error = deserializeJson(doc, strMsg);
// Give errors when there is parsing error
if (error) {
Serial.print(F("deserializeJson() failed with code "));
Serial.println(error.c_str());
return;
}
// Take data from input JSON
int phanAn = doc["PhanAn"];
Serial.println(phanAn);
bool batLoa = doc["BatLoa"];
// Check if there is still food
if (food <= 0) {
return;
}
// Feeding servo
for (int i = 0; i < phanAn; i++) {
if (checkServoFood()) {
food = scale.get_units() / 2100 * 5000; // Dòng này là dùng để cập nhật lại lượng thức ăn
remainFoodNotif();
}
else {
return;
}
}
// Servo for door
if (phanAn) {
if (!servoDoorWork()) {
return;
}
// Buzzer
if (batLoa) {
buzzerWork();
}
}
}
void setup() {
Serial.begin(9600);
configTime(7 * 3600, 0, "pool.ntp.org");
// Internet setup
Serial.print("Connecting to WiFi");
wifiConnect();
mqttClient.setServer(mqttServer, port);
mqttClient.setCallback(callback);
mqttClient.setKeepAlive( 90 );
// Servo setup
servoDoor.attach(servoDoorPin);
servoFood.attach(servoFoodPin);
servoFood.write(0);
servoDoor.write(180);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
}
void loop() {
// Internet
if(!mqttClient.connected()) {
mqttConnect();
}
mqttClient.loop();
// Update food
food = scale.get_units() / 2100 * 5000;
remainFoodNotif();
delay(3000);
}
// Functions
/* Servo quay phần đồ ăn
- Đầu tiên hàm sẽ kiểm tra xem servo đang ở góc nhiêu độ
- Nếu là 180 độ thì quay về 0, còn nếu là 0 thì quay 180
- Sau khi quay, kiểm tra xem liệu quay đủ chưa, chưa đủ thì báo kẹt*/
bool checkServoFood() {
if (servoFood.read() > 175) {
servoFood.write(0);
delay(2000);
// Kiểm tra kẹt
if (servoFood.read() > 5 || servoFood.read() < -5) {
mqttClient.publish("21127345/MachineAlert", "Servo quay phần đồ ăn bị kẹt");
return 0;
}
}
else {
servoFood.write(180);
delay(2000);
// Kiểm tra kẹt
if (servoFood.read() > 185 || servoFood.read() < 175) {
mqttClient.publish("21127345/MachineAlert", "Servo quay phần đồ ăn bị kẹt");
return 0;
}
}
mqttClient.publish("21127345/MachineAlert", "");
return 1;
}
bool servoDoorWork() {
servoDoor.write(90);
delay(5000);
// Kiểm tra kẹt
if (servoDoor.read() < 120) {
servoDoor.write(180);
delay(2000);
if (servoDoor.read() < 175) {
mqttClient.publish("21127345/MachineAlert", "Servo cửa đóng chưa chặt");
return 0;
}
}
else {
mqttClient.publish("21127345/MachineAlert", "Servo cửa bị kẹt");
return 0;
}
return 1;
}
void buzzerWork() {
for (int i = 0; i < 5; i++) {
tone(buzzerPin, 262, 1000);
}
noTone(buzzerPin);
}
void remainFoodNotif() {
char buffer[10];
sprintf(buffer, "%s", String(food));
mqttClient.publish("21127345/FoodNotif", buffer);
if (food < 100) {
mqttClient.publish("21127345/FoodAlert", "Vui lòng nạp thêm thức ăn vào máy");
HTTPClient http;
String event = "send_emer_food";
String apiKey = "bSK-eSTNQ1pneR465knJhu"; // Thay YOUR_API_KEY_HERE bằng API Key của bạn
String url = "https://maker.ifttt.com/trigger/" + event + "/with/key/" + apiKey;
url += "?value1=" + String(food);
http.begin(url);
int httpResponseCode = http.POST(""); // Gửi POST request mà không cần dữ liệu
http.end();
}
else if (food < 1000) {
mqttClient.publish("21127345/FoodAlert", "Sắp hết thức ăn");
}
else {
mqttClient.publish("21127345/FoodAlert", "");
}
}