Skip to content

Instantly share code, notes, and snippets.

@MRezaNasirloo
Last active March 24, 2024 15:04
Show Gist options
  • Save MRezaNasirloo/338ea03f52cec6ef5c6b277e40f800da to your computer and use it in GitHub Desktop.
Save MRezaNasirloo/338ea03f52cec6ef5c6b277e40f800da to your computer and use it in GitHub Desktop.
a cat toy, rotates a servo randomly, display info and ota updates
#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