/**
* This code snippet demonstrates a basic implementation for an IoT device using an ESP32 microcontroller,
* capable of connecting to a WiFi network and communicating with an MQTT broker.
*
* It includes necessary libraries such as PubSubClient for MQTT communication, WiFi for network connectivity,
* and Servo for controlling a servo motor.
*
* The purpose of the code is to establish a connection to a MQTT broker, read messages from subscribed topics,
* and control a servo motor based on received commands.
*
* The main functionalities of the code include setting up the MQTT connection, connecting to the WiFi network,
* and controlling the servo motor based on MQTT messages received. Additionally, it handles communication with
* the MQTT broker and updates servo control parameters based on incoming messages.
*
* This code serves as a foundation for building more complex IoT applications where ESP32 devices need to interact
* with remote systems via MQTT for tasks such as home automation, remote sensing, or control systems.
*/
#include <PubSubClient.h>
#include <WiFi.h>
#include <Servo.h>
// Pin definitions
#define LDR_RIGHT 32 // Pin connected to the right LDR sensor
#define LDR_LEFT 33 // Pin connected to the left LDR sensor
#define SERVO_PIN 27 // Pin connected to the servo motor
// Constants for default control parameters
#define D_RIGHT 0.5 // Default value for D when right LDR detects high intensity
#define D_LEFT 1.5 // Default value for D when left LDR detects high intensity
// Initialize necessary objects
WiFiClient espClient;
PubSubClient mqttClient(espClient);
Servo servo;
// Variables for light intensity and servo control
float left_intensity;
float right_intensity;
float angle_offset;
float controlling_factor;
// Flag for scheduled ON control
bool isScheduledON = false;
unsigned long scheduledOnTime;
/**
* Main loop function that handles MQTT connection, measures light intensity, and controls the servo motor.
*/
void loop() {
if (!mqttClient.connected()) {
connectToBroker(); // Reconnect to the MQTT broker if not connected
}
mqttClient.loop(); // Maintain the MQTT connection
measure_light_intensity(); // Measure light intensity using LDR sensors
servo_controller(); // Control the servo motor based on measured light intensity
delay(1000);
}
/**
* Initialize the initial angle for the servo motor and set up the WiFi and MQTT connections.
*/
void setup() {
angle_offset = 30; // Initial angle offset for the servo motor
controlling_factor = 0.75; // Initial controlling factor for servo motor movement
Serial.begin(9600);
setupWifi(); // Initialize WiFi connection
setupMqtt(); // Initialize MQTT connection
servo.attach(SERVO_PIN); // Attach servo to specified pin
servo.write(angle_offset); // Set initial angle for servo motor
}
/**
* Function to set up the MQTT connection.
* Configures the MQTT client with the server address and port,
* and sets the callback function for handling incoming MQTT messages.
*/
void setupMqtt() {
mqttClient.setServer("test.mosquitto.org", 1883); // Set MQTT server address and port
mqttClient.setCallback(receiveCallBack); // Set callback function for MQTT message reception
}
/**
* Function to set up the WiFi connection.
* Connects to the specified WiFi network and waits until the connection is established.
* Once connected, prints the local IP address to the serial monitor.
*/
void setupWifi() {
WiFi.begin("Wokwi-GUEST", ""); // Connect to WiFi network with provided SSID and password
while (WiFi.status() != WL_CONNECTED) { // Wait until WiFi connection is established
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address : ");
Serial.println(WiFi.localIP()); // Print local IP address
}
/**
* Function to establish a connection with the MQTT broker.
* Attempts to connect to the broker and subscribes to relevant topics.
* If the connection is successful, publishes initial control factor and offset angle values.
* If the connection fails, prints the failure status to the serial monitor and retries after a delay.
*/
void connectToBroker() {
while (!mqttClient.connected()) {
Serial.print("Attempting MQTT connection...");
if (mqttClient.connect("ESP32-4654564645645")) { // Attempt MQTT connection with client ID
Serial.println("connected"); // Print connection status
// Subscribe to control factor and offset angle topics
mqttClient.subscribe("My-Medibox-control-factor");
mqttClient.subscribe("My-Medibox-offset-angle");
// Publish initial control factor and offset angle values
char control_factor[6];
char min_angle[6];
String(angle_offset).toCharArray(min_angle, 6); // Convert angle offset to char array
String(controlling_factor).toCharArray(control_factor, 6); // Convert controlling factor to char array
mqttClient.publish("My-Medibox-control-factor", control_factor); // Publish initial control factor
mqttClient.publish("My-Medibox-offset-angle", min_angle); // Publish initial offset angle
} else {
Serial.println("failed"); // Print connection failure status
Serial.println(mqttClient.state()); // Print MQTT client state
delay(500); // Delay before retrying connection
}
}
}
/**
* Callback function invoked upon receiving MQTT messages.
* Handles incoming messages and updates relevant parameters accordingly.
* Receives the topic and payload of the message, processes them, and takes appropriate actions.
* If the message pertains to the control factor, updates the controlling factor and adjusts servo control.
* If the message pertains to the offset angle, updates the offset angle and adjusts servo control.
*
* @param topic The topic of the received MQTT message.
* @param payload The payload of the received MQTT message.
* @param length The length of the payload.
*/
void receiveCallBack(char *topic, byte *payload, unsigned int length) {
Serial.print("Message has Arrived");
Serial.print(topic);
Serial.print("]");
char payloadCharAr[length]; // Character array to hold the payload
// Iterate over the payload bytes to construct a character array
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
payloadCharAr[i] = (char)payload[i];
}
Serial.println();
// Check if the message topic is related to controlling factor
if (strcmp(topic, "My-Medibox-control-factor") == 0) {
controlling_factor = atof(payloadCharAr); // Update the controlling factor from the message
Serial.println(controlling_factor); // Print the updated controlling factor
servo_controller(); // Adjust servo control based on the updated parameters
}
// Check if the message topic is related to offset angle
else if (strcmp(topic, "My-Medibox-offset-angle") == 0) {
angle_offset = atof(payloadCharAr); // Update the offset angle from the message
Serial.println(angle_offset); // Print the updated offset angle
servo_controller(); // Adjust servo control based on the updated parameters
}
}
/**
* Control the servo motor based on the measured light intensity.
* Adjusts the servo angle according to the intensity readings from the LDR sensors.
* Calculates the desired angle using a combination of fixed parameters and the measured intensities,
* then sets the servo to that angle.
*/
void servo_controller() {
float D = 0; // Initialization of D parameter for servo control
// Determine the value of D based on the light intensity readings from the LDR sensors
if (left_intensity > 0.95) {
D = D_LEFT; // Set D to the left value if left intensity is high
} else if (right_intensity > 0.95) {
D = D_RIGHT; // Set D to the right value if right intensity is high
}
// Calculate the desired servo angle based on D, intensity values, and control parameters
int angle = min(int((angle_offset * D) + ((180 - angle_offset) * max(left_intensity, right_intensity) * controlling_factor)), 180);
servo.write(angle); // Set the servo angle to the calculated value
}
/**
* Measure the light intensity using the LDR sensors.
* Read analog values from the sensors, convert them to light intensity,
* and publish the results to the MQTT broker.
*/
void measure_light_intensity() {
analogReadResolution(10); // Set resolution to 10 bits (0-1023)
right_intensity = analogRead(LDR_RIGHT);
left_intensity = analogRead(LDR_LEFT);
// Convert analog readings to light intensity values (normalized between 0 and 1)
right_intensity = 1 - (right_intensity / 1023);
left_intensity = 1 - (left_intensity / 1023);
// Print the measured light intensities to the serial monitor
Serial.println("Left light intensity : " + String(left_intensity));
Serial.println("Right light intensity : " + String(right_intensity));
// Determine which LDR has the highest intensity and prepare the message accordingly
char light_intensity[6];
String highest_intensity_ldr;
if (left_intensity >= right_intensity) {
highest_intensity_ldr = "Left";
String(left_intensity).toCharArray(light_intensity, 6);
} else {
highest_intensity_ldr = "Right";
String(right_intensity).toCharArray(light_intensity, 6);
}
// Publish the light intensity values and the highest intensity LDR to the MQTT broker
mqttClient.publish("My-Medibox-light-intensity", light_intensity);
mqttClient.publish("My-Medibox-highest-intensity", highest_intensity_ldr.c_str());
}