Last active
March 24, 2024 15:04
-
-
Save MRezaNasirloo/338ea03f52cec6ef5c6b277e40f800da to your computer and use it in GitHub Desktop.
a cat toy, rotates a servo randomly, display info and ota updates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Wire.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
#include <ESP8266WiFi.h> | |
#include <ESP8266mDNS.h> | |
#include <WiFiUdp.h> | |
#include <ArduinoOTA.h> | |
#include <Servo.h> | |
#include <ESP8266WebServer.h> | |
#include <ArduinoJson.h> | |
#define SCREEN_WIDTH 128 // OLED display width, in pixels | |
#define SCREEN_HEIGHT 64 // OLED display height, in pixels | |
#define SCREEN_ADDRESS 0x3C // Address of the OLED display | |
#define SDA_PIN 14 // SDA pin for I2C communication | |
#define SCL_PIN 12 // SCL pin for I2C communication | |
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) | |
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); | |
Servo servo; // create servo object to control a servo | |
int speed = 100; // starting speed | |
bool enable = true; | |
bool bothDirections = true; | |
unsigned long lastMoveTime = 0; | |
unsigned long nextMoveInterval = 0; | |
unsigned long rotationStartTime = 0; | |
unsigned long waitStartTime = 0; | |
unsigned long maxDuration = 3000; | |
unsigned long minDuration = 1000; | |
unsigned long maxWait = 7000; | |
unsigned long minWait = 3000; | |
int mod = 2; | |
ESP8266WebServer server(80); | |
void setup() { | |
Serial.begin(115200); | |
// Initialize WiFi | |
WiFi.begin("wifi", "pass"); | |
while (WiFi.waitForConnectResult() != WL_CONNECTED) { | |
Serial.println("Connection Failed! Rebooting..."); | |
delay(5000); | |
ESP.restart(); | |
} | |
// web server | |
server.on("/", handleRoot); | |
server.on("/settings", handleSettings); // Handle form submission | |
server.begin(); | |
Serial.println("HTTP server started"); | |
ArduinoOTA.onStart([]() { | |
String type; | |
if (ArduinoOTA.getCommand() == U_FLASH) { | |
type = "sketch"; | |
} else { // U_SPIFFS | |
type = "filesystem"; | |
} | |
Serial.println("Start updating " + type); | |
}); | |
ArduinoOTA.onEnd([]() { | |
Serial.println("\nEnd"); | |
}); | |
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { | |
Serial.printf("Progress: %u%%\r", (progress / (total / 100))); | |
}); | |
ArduinoOTA.onError([](ota_error_t error) { | |
Serial.printf("Error[%u]: ", error); | |
if (error == OTA_AUTH_ERROR) { | |
Serial.println("Auth Failed"); | |
} else if (error == OTA_BEGIN_ERROR) { | |
Serial.println("Begin Failed"); | |
} else if (error == OTA_CONNECT_ERROR) { | |
Serial.println("Connect Failed"); | |
} else if (error == OTA_RECEIVE_ERROR) { | |
Serial.println("Receive Failed"); | |
} else if (error == OTA_END_ERROR) { | |
Serial.println("End Failed"); | |
} | |
}); | |
ArduinoOTA.begin(); | |
servo.attach(D8); // attaches the servo on pin to the servo object | |
randomSeed(analogRead(0)); // Initialize random number generator | |
Wire.begin(SDA_PIN, SCL_PIN); // Specify SDA and SCL pins explicitly | |
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { | |
Serial.println(F("SSD1306 allocation failed")); | |
for (;;); | |
} | |
display.display(); // Clear display buffer | |
delay(2000); // Delay for 2 seconds | |
display.clearDisplay(); // Clear the display buffer | |
} | |
void handleRoot() { | |
String htmlPage = "<!DOCTYPE html>" | |
"<html>" | |
"<head>" | |
" <title>Device Control</title>" | |
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" | |
" <style>" | |
" body {" | |
" font-size: 16px;" | |
" padding: 10px;" | |
" }" | |
" input[type='number'], input[type='checkbox'] {" | |
" width: 100%;" | |
" margin-bottom: 10px;" | |
" }" | |
" input[type='submit'] {" | |
" width: 100%;" | |
" }" | |
" </style>" | |
"</head>" | |
"<body>" | |
" <h1>Device Settings</h1>" | |
" <form action=\"/settings\" method=\"POST\">" | |
" <label for=\"durationMin\">Duration Min:</label><br>" | |
" <input type=\"number\" id=\"durationMin\" name=\"durationMin\" min=\"0\" value=\"" + String(minDuration) + "\"><br>" | |
" <label for=\"durationMax\">Duration Max:</label><br>" | |
" <input type=\"number\" id=\"durationMax\" name=\"durationMax\" min=\"0\" value=\"" + String(maxDuration) + "\"><br>" | |
" <label for=\"waitMin\">Wait Min:</label><br>" | |
" <input type=\"number\" id=\"waitMin\" name=\"waitMin\" min=\"0\" value=\"" + String(minWait) + "\"><br>" | |
" <label for=\"waitMax\">Wait Max:</label><br>" | |
" <input type=\"number\" id=\"waitMax\" name=\"waitMax\" min=\"0\" value=\"" + String(maxWait) + "\"><br>" | |
" <label for=\"enable\">Enable:</label><br>" | |
" <input type=\"checkbox\" id=\"enable\" name=\"enable\"" + String(enable ? " checked" : "") + "><br>" | |
" <label for=\"bothDirections\">Both Directions:</label><br>" | |
" <input type=\"checkbox\" id=\"bothDirections\" name=\"bothDirections\"" + String(mod == 2 ? " checked" : "") + "><br>" | |
" <input type=\"submit\" value=\"Submit\">" | |
" </form>" | |
" <script>" | |
" const form = document.querySelector('form');" | |
" form.addEventListener('submit', (event) => {" | |
" event.preventDefault();" | |
" const durationMin = document.getElementById('durationMin').value;" | |
" const durationMax = document.getElementById('durationMax').value;" | |
" const waitMin = document.getElementById('waitMin').value;" | |
" const waitMax = document.getElementById('waitMax').value;" | |
" const enable = document.getElementById('enable').checked;" | |
" const bothDirections = document.getElementById('bothDirections').checked;" | |
" fetch('/settings', {" | |
" method: 'POST'," | |
" headers: {" | |
" 'Content-Type': 'application/json'" | |
" }," | |
" body: JSON.stringify({ durationMin, durationMax, waitMin, waitMax, enable, bothDirections })" | |
" });" | |
" });" | |
" </script>" | |
"</body>" | |
"</html>"; | |
server.send(200, "text/html", htmlPage); | |
} | |
void handleSettings() { | |
if (server.method() == HTTP_POST) { | |
// Parse JSON body | |
JsonDocument doc; // Adjust size if needed | |
DeserializationError error = deserializeJson(doc, server.arg("plain")); | |
if (error) { | |
Serial.println("Failed to parse JSON"); | |
Serial.println(error.c_str()); | |
server.send(400, "text/plain", "Invalid JSON data"); | |
return; | |
} | |
// Extract values | |
minDuration = doc["durationMin"].as<int>(); | |
maxDuration = doc["durationMax"].as<int>(); | |
minWait = doc["waitMin"].as<int>(); | |
maxWait = doc["waitMax"].as<int>(); | |
enable = doc["enable"].as<bool>(); | |
bothDirections = doc["bothDirections"].as<bool>(); | |
if(bothDirections) { | |
mod = 2; | |
} else { | |
mod = 1; | |
} | |
// Use these settings to control your device | |
Serial.println("Args count:"); | |
Serial.println(server.args()); | |
Serial.println("Duration Min:"); | |
Serial.println(minDuration); | |
Serial.println("Duration Max:"); | |
Serial.println(maxDuration); | |
Serial.println("Wait Min:"); | |
Serial.println(minWait); | |
Serial.println("Wait Max:"); | |
Serial.println(maxWait); | |
Serial.println("Enable:"); | |
Serial.println(enable); | |
Serial.println("Both Directions:"); | |
Serial.println(bothDirections); | |
server.send(200, "text/plain", "Settings received!"); | |
} | |
} | |
void loop() { | |
ArduinoOTA.handle(); | |
server.handleClient(); | |
if (!enable) { | |
// Stop servo after rotation | |
servo.writeMicroseconds(1500); | |
return; | |
} | |
unsigned long currentMillis = millis(); | |
if (currentMillis - lastMoveTime >= nextMoveInterval) { | |
int randomDirection = random(1, 12); // Generate random move | |
int rotationDuration = random(minDuration, maxDuration); | |
if (randomDirection == 5) { | |
rotationDuration = 3000; | |
} | |
int waitTime = random(minWait, maxWait); // Generate random wait time between 3 and 7 seconds | |
// int speed = random(1000, 2000); | |
// Display rotation information | |
display.clearDisplay(); | |
display.setTextColor(SSD1306_WHITE); | |
display.setCursor(0, 0); | |
display.println("Next move:"); | |
if (randomDirection == 5) { | |
display.println("Wiggle"); | |
} else { | |
display.print("Rotate "); | |
display.println(randomDirection % mod == 0 ? "Left" : "Right"); | |
} | |
display.print("Duration: "); | |
display.print(rotationDuration / 1000); // Convert milliseconds to seconds | |
display.println(" seconds"); | |
display.display(); | |
// Start rotating | |
rotationStartTime = millis(); | |
while (millis() - rotationStartTime < rotationDuration) { | |
// Update countdown display for rotation | |
int remainingTime = rotationDuration - (millis() - rotationStartTime); | |
display.setRotation(0); | |
display.setTextSize(1); | |
display.setTextColor(SSD1306_WHITE); | |
display.setCursor(0, 40); | |
display.fillRect(0, 40, SCREEN_WIDTH, 16, SSD1306_BLACK); | |
display.print("Until: "); | |
display.print(remainingTime / 1000); | |
display.print("s"); | |
display.display(); | |
// Perform rotation | |
if (randomDirection == 5) { | |
wiggle(servo, rotationDuration); | |
} else if (randomDirection % mod == 0) { | |
servo.writeMicroseconds(random(1250, 1400)); // Rotate left | |
} else { | |
servo.writeMicroseconds(random(1600, 1750)); // Rotate right | |
} | |
} | |
// Stop servo after rotation | |
servo.writeMicroseconds(1500); | |
// Display wait time information | |
display.clearDisplay(); | |
display.setTextColor(SSD1306_WHITE); | |
display.setCursor(0, 0); | |
display.println("Next move:"); | |
display.println("Waiting"); | |
display.print("Wait time: "); | |
display.print(waitTime / 1000); // Convert milliseconds to seconds | |
display.println(" seconds"); | |
display.display(); | |
// Start waiting | |
waitStartTime = millis(); | |
while (millis() - waitStartTime < waitTime) { | |
// Update countdown display for wait time | |
int remainingTime = waitTime - (millis() - waitStartTime); | |
display.setRotation(0); | |
display.setTextSize(1); | |
display.setTextColor(SSD1306_WHITE); | |
display.setCursor(0, 40); | |
display.fillRect(0, 40, SCREEN_WIDTH, 16, SSD1306_BLACK); | |
display.print("Until: "); | |
display.print(remainingTime / 1000); | |
display.print("s"); | |
display.display(); | |
} | |
lastMoveTime = currentMillis; | |
nextMoveInterval = waitTime; | |
} | |
} | |
void wiggle(Servo &servo, int duration) { | |
unsigned long startTime = millis(); | |
while (millis() - startTime < duration) { | |
servo.writeMicroseconds(1250); // Rotate left | |
delay(100); // Adjust this delay for the speed of the wiggle | |
servo.writeMicroseconds(1750); // Rotate right | |
delay(100); // Adjust this delay for the speed of the wiggle | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment