#include <ESP32Servo.h> // Library for servomotor on ESP32
#include <NewPing.h> // Library for ultrasonic sensor
#include <LiquidCrystal_I2C.h> // Library for LCD
#include <DHT.h> // Library for DHT sensor
#include <Wire.h>
#include <MPU6050.h> // Library for MPU6050 sensor
#include <WiFi.h> // ESP32 WiFi library
#include <WebServer.h> // Library for Web server
#include <HTTPClient.h> // Library for HTTP client
#define DHTPIN 4 // Pin where the DHT22 is connected
#define DHTTYPE DHT22 // DHT22 sensor type
const char* ssid = "Wokwi-GUEST"; // Wokwi WiFi network SSID
const char* password = ""; // Wokwi WiFi network password
DHT dht(DHTPIN, DHTTYPE); // Initialize DHT sensor
MPU6050 mpu; // Initialize MPU6050 sensor
NewPing sonar(12, 13, 200); // Setup NewPing. Pin 12 = trigger out, pin 13 = echo in, max. distance 200cm
Servo servo; // Define object servo
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows
WebServer server(80); // Create a web server object that listens for HTTP request on port 80
const int distMax = 30; // Maximum distance
const int distMin = 10; // Minimum distance
const int angleMax = 180; // Maximum servo angle
const int angleMin = 0; // Minimum servo angle
const int k = ((angleMax - angleMin) / (distMax - distMin)); // K factor for scaling
const int b = (angleMin - k * distMin); // Angle when the distance is at its minimum
const int midpointDistance = (distMax + distMin) / 2; // Define midpoint distance
const int midpointAngle = k * midpointDistance + b; // Calculate midpoint angle
String googleScriptID = "https://script.google.com/macros/s/AKfycbyxDOybEByuNJ8SgKFbvQRXnKS5DtnSJzuXl-rkJQmfdLs_mIscnIJ-F45U9Y9x9dc1-A/exec";
void setup() {
// Initialize Serial communication
Serial.begin(115200);
// Connect to WiFi network
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("WiFi connected, IP address: ");
Serial.println(WiFi.localIP());
servo.attach(14); // Connect servo to pin 14
lcd.init(); // Initialize LCD
lcd.backlight(); // Backlight on
dht.begin(); // Initialize DHT sensor
Wire.begin(21, 22); // Initialize I2C with default SDA and SCL pins on ESP32
mpu.initialize(); // Initialize MPU6050 sensor
// Define web server routes
server.on("/", handleRoot); // Route for the root / web page
server.on("/servo", handleServoControl); // Route for controlling servo
server.on("/data", handleSensorData); // Route for sensor data
server.begin(); // Start the server
Serial.println("HTTP server started");
}
void loop() {
server.handleClient(); // Handle client requests
// Update sensor data and servo control in the background
int dist = sonar.ping_cm(); // Measure distance in cm to variable dist
int angle; // Define angle variable
// Check if distance is within limits
if ((dist >= distMin) && (dist <= distMax)) {
// If within limits, servo angle is proportional to distance
angle = k * dist + b;
} else {
// If outside limits, set servo angle to extremes
if (dist > distMax) {
angle = angleMax; // Set servo angle to maximum
} else {
angle = angleMin; // Set servo angle to minimum
}
}
// Set servo angle to the midpoint when distance matches midpoint distance
if (dist == midpointDistance) {
servo.write(midpointAngle);
} else {
servo.write(angle); // Set servo angle
}
// Read temperature and humidity from DHT22
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Read acceleration and gyroscope data from MPU6050
int16_t ax, ay, az, gx, gy, gz;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
float accelX = ax / 16384.0;
float accelY = ay / 16384.0;
float accelZ = az / 16384.0;
float gyroX = gx / 131.0;
float gyroY = gy / 131.0;
float gyroZ = gz / 131.0;
// Display data on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Distance: " + String(dist) + "cm");
lcd.setCursor(0, 1);
if ((dist < distMin) || (dist > distMax)) {
lcd.print("Outside limits");
} else {
lcd.print("Within limits");
}
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Angle: " + String(angle) + "deg");
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temp: " + String(temperature) + "C");
lcd.setCursor(0, 1);
lcd.print("Humidity: " + String(humidity) + "%");
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("AccelX: " + String(accelX));
lcd.setCursor(0, 1);
lcd.print("AccelY: " + String(accelY));
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("AccelZ: " + String(accelZ));
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("GyroX: " + String(gyroX));
lcd.setCursor(0, 1);
lcd.print("GyroY: " + String(gyroY));
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("GyroZ: " + String(gyroZ));
delay(1000);
// Send data to Google Sheets
sendDataToGoogleSheets(temperature, humidity, accelX, accelY, accelZ, gyroX, gyroY, gyroZ);
}
void handleRoot() {
String html = "<html>\
<head>\
<title>ESP32 Web Server</title>\
<style>\
body { font-family: Arial; text-align: center; }\
.button { padding: 10px 20px; margin: 10px; }\
</style>\
</head>\
<body>\
<h1>ESP32 Web Server</h1>\
<button class=\"button\" onclick=\"sendServoCommand(0)\">0°</button>\
<button class=\"button\" onclick=\"sendServoCommand(90)\">90°</button>\
<button class=\"button\" onclick=\"sendServoCommand(180)\">180°</button>\
<br>\
<button class=\"button\" onclick=\"getSensorData()\">Get Sensor Data</button>\
<div id=\"sensorData\"></div>\
<script>\
function sendServoCommand(angle) {\
fetch('/servo?angle=' + angle);\
}\
function getSensorData() {\
fetch('/data').then(response => response.json()).then(data => {\
document.getElementById('sensorData').innerHTML = JSON.stringify(data);\
});\
}\
</script>\
</body>\
</html>";
server.send(200, "text/html", html);
}
void handleServoControl() {
if (server.hasArg("angle")) {
int angle = server.arg("angle").toInt();
servo.write(angle);
server.send(200, "text/plain", "Servo angle set to " + String(angle));
} else {
server.send(400, "text/plain", "Angle parameter missing");
}
}
void handleSensorData() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
int16_t ax, ay, az, gx, gy, gz;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
float accelX = ax / 16384.0;
float accelY = ay / 16384.0;
float accelZ = az / 16384.0;
float gyroX = gx / 131.0;
float gyroY = gy / 131.0;
float gyroZ = gz / 131.0;
String data = "{";
data += "\"temperature\":" + String(temperature) + ",";
data += "\"humidity\":" + String(humidity) + ",";
data += "\"accelX\":" + String(accelX) + ",";
data += "\"accelY\":" + String(accelY) + ",";
data += "\"accelZ\":" + String(accelZ) + ",";
data += "\"gyroX\":" + String(gyroX) + ",";
data += "\"gyroY\":" + String(gyroY) + ",";
data += "\"gyroZ\":" + String(gyroZ);
data += "}";
server.send(200, "application/json", data);
}
void sendDataToGoogleSheets(float temperature, float humidity, float accelX, float accelY, float accelZ, float gyroX, float gyroY, float gyroZ) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = googleScriptID + "?temperature=" + String(temperature) + "&humidity=" + String(humidity) + "&accelX=" + String(accelX) + "&accelY=" + String(accelY) + "&accelZ=" + String(accelZ) + "&gyroX=" + String(gyroX) + "&gyroY=" + String(gyroY) + "&gyroZ=" + String(gyroZ);
http.begin(url);
http.setTimeout(10000); // Set timeout to 10 seconds
int httpCode = http.GET();
if (httpCode > 0) {
Serial.println("HTTP Request Sent");
String payload = http.getString();
Serial.println("Response: " + payload);
} else {
Serial.print("Error on HTTP request: ");
Serial.println(httpCode); // Print HTTP error code
}
http.end();
} else {
Serial.println("WiFi not connected");
}
}