#include <Wire.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <LiquidCrystal_I2C.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#define ssid "Wokwi-GUEST"
#define password ""
#define channel 6
const char *mqtt_server = "test.mosquitto.org";
WiFiClient espClient;
PubSubClient client(espClient);
#define ULTRASONIC_TOPIC "ultrasonic/room"
#define SOIL_TOPIC "soil/room"
#define ULTRASONIC_TOPIC_CHECK "ultrasonic/check"
#define SOIL_TOPIC_CHECK "soil/check"
char msg[20];
long lastMsg = 0;
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define LED_ON HIGH
#define LED_OFF LOW
const int trigPin = 13;
const int echoPin = 12;
const int led_ultrasonic_work = 27;
const int led_ultrasonic_fail = 14;
const int led_soil_work = 2;
const int led_soil_fail = 15;
// define sound speed in cm/uS
#define SOUND_SPEED 0.034
#define CM_TO_INCH 0.393701
long duration;
float distanceCm;
float distanceInch;
SemaphoreHandle_t xMutex;
void ultrasonicTask(void *pvParameters)
{
while (1)
{
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculate the distance
distanceCm = duration * SOUND_SPEED / 2;
// Convert to inches
distanceInch = distanceCm * CM_TO_INCH;
// Use the mutex to protect LCD printing
if (xSemaphoreTake(xMutex, portMAX_DELAY))
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Soil: ");
lcd.print(analogRead(34));
lcd.setCursor(0, 1);
lcd.print("Level: ");
lcd.print(distanceCm);
lcd.print(" cm");
xSemaphoreGive(xMutex);
}
delay(500);
}
}
void mqttTask(void *pvParameters)
{
while (1)
{
if (!client.connected())
{ /* try to reconnect */
mqttconnect();
}
client.loop(); /* listen for incoming subscribed receivedCallback */
long now = millis();
if (now - lastMsg > 500)
{
lastMsg = now;
snprintf(msg, sizeof(msg), "%.2f", distanceCm);
client.publish(ULTRASONIC_TOPIC, msg);
snprintf(msg, sizeof(msg), "%d", analogRead(34));
client.publish(SOIL_TOPIC, msg);
}
delay(500);
}
}
void receivedCallback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message received: ");
Serial.println(topic);
Serial.print("payload: ");
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
// Check the topic and perform actions accordingly
if (strcmp(topic, ULTRASONIC_TOPIC_CHECK) == 0)
{
if ((char)payload[0] == '1')
{
digitalWrite(led_ultrasonic_work, LED_ON);
digitalWrite(led_ultrasonic_fail, LED_OFF);
}
else if ((char)payload[0] == '0')
{
digitalWrite(led_ultrasonic_work, LED_OFF);
digitalWrite(led_ultrasonic_fail, LED_ON);
}
}
else if (strcmp(topic, SOIL_TOPIC_CHECK) == 0)
{
if ((char)payload[0] == '1')
{
digitalWrite(led_soil_work, LED_ON);
digitalWrite(led_soil_fail, LED_OFF);
}
else if ((char)payload[0] == '0')
{
digitalWrite(led_soil_work, LED_OFF);
digitalWrite(led_soil_fail, LED_ON);
}
}
}
void mqttconnect()
{
/* Loop until reconnected */
while (!client.connected())
{
Serial.print("MQTT connecting ...");
/* client ID */
String clientId = "BigClient"; //ESP32Client
/* connect now */
if (client.connect(clientId.c_str()))
{
Serial.println("connected");
/* subscribe topic with default QoS 0*/
client.subscribe(ULTRASONIC_TOPIC);
client.subscribe(SOIL_TOPIC);
client.subscribe(ULTRASONIC_TOPIC_CHECK);
client.subscribe(SOIL_TOPIC_CHECK);
}
else
{
Serial.print("failed, status code =");
Serial.print(client.state());
Serial.println("try again in 5 seconds");
/* Wait 5 seconds before retrying */
delay(5000);
}
}
}
void setup()
{
Serial.begin(9600);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password, channel);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
client.setServer(mqtt_server, 1883);
client.setCallback(receivedCallback);
Wire.begin(23, 22);
lcd.init();
lcd.backlight();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(led_ultrasonic_work, OUTPUT);
pinMode(led_ultrasonic_fail, OUTPUT);
pinMode(led_soil_work, OUTPUT);
pinMode(led_soil_fail, OUTPUT);
// Create a mutex to protect LCD printing
xMutex = xSemaphoreCreateMutex();
// Create FreeRTOS tasks
xTaskCreate(ultrasonicTask, "UltrasonicTask", 4096, NULL, 1, NULL);
xTaskCreate(mqttTask, "MqttTask", 4096, NULL, 1, NULL);
Serial.println("");
delay(100);
}
void loop()
{
// This loop is intentionally left empty as the tasks handle the functionality
}
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
ultrasonic1:VCC
ultrasonic1:TRIG
ultrasonic1:ECHO
ultrasonic1:GND
esp1:VIN
esp1:GND.2
esp1:D13
esp1:D12
esp1:D14
esp1:D27
esp1:D26
esp1:D25
esp1:D33
esp1:D32
esp1:D35
esp1:D34
esp1:VN
esp1:VP
esp1:EN
esp1:3V3
esp1:GND.1
esp1:D15
esp1:D2
esp1:D4
esp1:RX2
esp1:TX2
esp1:D5
esp1:D18
esp1:D19
esp1:D21
esp1:RX0
esp1:TX0
esp1:D22
esp1:D23
chip1:GND
chip1:VCC
chip1:A0
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C