Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Quick hack of a cat feeder. ESP01
Author | Message | ||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Occasionally I need to go away for a day or two. The dog goes to the doggy hotel for a couple nights, and the cat stays at home. Usually I put down enough cat food for the duration, but he eats it all in one go, then finds somewhere on the carpet to vomit it all up. I was given a broken cat feeder. It has multiple issues, and instead of trying to fix it, I decided to hack it with a arduino. Opened it up and removed the main control board. The feeder uses a motor to spin a paddle wheel to basically throw out some cat food. I used a ESP01 plus relay board as the brains, mounted on a piece of veroboard with a couple caps, power socket, etc. Its powered by a 9v adaptor. Spent a couple hours with ChatGPT to come up with the basic code, then modified it to add a few features. It connects to my wifi, and serves a web page to let you configure the feeder. I have two feeding times, and a duration to spin the motor for. It connects to a NTP server to get the actual time. Settings are saved in EEPROM. The cats name is Alf #include <EEPROM.h> #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <time.h> // NTP time library // EEPROM Addresses for storing data const int EEPROM_SIZE = 10; // Enough space for 4 integers (start hour, start minute, start second, and duration) // WiFi credentials const char* ssid = "Removed"; const char* password = "Removed"; IPAddress local_IP(192, 168, 178, 50); // Set your desired IP address here IPAddress gateway(192, 168, 178, 1); // Set your gateway (usually the router's IP) IPAddress subnet(255, 255, 255, 0); // Subnet mask IPAddress dns(192, 168, 178, 1); // NTP Server const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 36000; // Set to your time zone's GMT offset (in seconds) const int daylightOffset_sec = 0; // Set to 0 if no daylight savings // Pin configuration const int relayPin = 0; // GPIO0 for relay control // Web server running on port 80 ESP8266WebServer server(80); // Variables to store relay control time and duration int startHour1 = 0, startMinute1 = 0, startSecond = 0; int startHour2 = 0, startMinute2 = 0; int durationSeconds = 5; bool relayOn = false; bool manualTest = false; // Flag for manual test void setup() { Serial.begin(115200); pinMode(relayPin, OUTPUT); digitalWrite(relayPin, HIGH); // Relay off by default EEPROM.begin(EEPROM_SIZE); loadTimerSettings(); // Load saved timer settings from EEPROM // Connect to WiFi if (!WiFi.config(local_IP, gateway, subnet, dns)) { Serial.println("Failed to configure Static IP"); } WiFi.begin(ssid, password); WiFi.hostname("CatFeeder"); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected to WiFi!"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); Serial.print("Hostname: "); Serial.println(WiFi.hostname()); // Initialize NTP configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); server.on("/", handleRoot); server.on("/setTime", handleSetTime); server.on("/manualTest", handleManualTest); // Manual test button server.begin(); Serial.println("Web server started."); } void loop() { server.handleClient(); // Get the current time time_t now = time(nullptr); struct tm* currentTime = localtime(&now); int currentHour = currentTime->tm_hour; int currentMinute = currentTime->tm_min; int currentSecond = currentTime->tm_sec; // Check if the relay should be on if (((currentHour == startHour1 && currentMinute == startMinute1 && currentSecond == 0) || (currentHour == startHour2 && currentMinute == startMinute2 && currentSecond == 0)) && !relayOn && !manualTest) { digitalWrite(relayPin, LOW); // Turn on the relay relayOn = true; startSecond=currentSecond; Serial.println("Relay turned on!"); } // Turn off the relay after the specified duration if (relayOn && (currentSecond - startSecond) >= durationSeconds ) { digitalWrite(relayPin, HIGH); // Turn off the relay relayOn = false; manualTest = false; // Reset manual test flag after operation Serial.println("Relay turned off!"); } } void loadTimerSettings() { startHour1 = EEPROM.read(0); startMinute1 = EEPROM.read(1); startHour2 = EEPROM.read(2); startMinute2 = EEPROM.read(3); durationSeconds = EEPROM.read(4) | (EEPROM.read(5) << 8); // Combine the two bytes of duration Serial.println("Timer settings loaded from EEPROM."); } void saveTimerSettings() { EEPROM.write(0, startHour1); EEPROM.write(1, startMinute1); EEPROM.write(2, startHour2); EEPROM.write(3, startMinute2); EEPROM.write(4, durationSeconds & 0xFF); // Lower byte of duration EEPROM.write(5, (durationSeconds >> 8) & 0xFF); // Higher byte of duration EEPROM.commit(); Serial.println("Timer settings saved to EEPROM."); } void handleRoot() { time_t now = time(nullptr); struct tm* currentTime = localtime(&now); // Format current time as HH:MM:SS String currentTimeStr = String(currentTime->tm_hour) + ":" + String(currentTime->tm_min) + ":" + String(currentTime->tm_sec); // Format scheduled time for the relay as HH:MM:SS String scheduledTimeStr1 = String(startHour1) + ":" + String(startMinute1) + ":00"; String scheduledTimeStr2 = String(startHour2) + ":" + String(startMinute2) + ":00"; // HTML content String html = "<html><body><h1>Alf Feeder</h1><hr/>"; html += "<p>Current Time: " + currentTimeStr + "</p>"; html += "<p>Feed Scheduled Time 1 : " + scheduledTimeStr1 + "</p>"; html += "<p>Feed Scheduled Time 2 : " + scheduledTimeStr2 + "</p>"; html += "<p>Relay Duration: " + String(durationSeconds) + " seconds</p>"; html += "<fieldset><legend>Settings</legend><form action=\"/setTime\" method=\"GET\">"; html += "Feed Time 1: <input type=\"number\" name=\"hour1\" min=\"0\" max=\"23\" value=\"" + String(startHour1) +"\">H : <input type=\"number\" name=\"minute1\" min=\"0\" max=\"59\" value=\"" + String(startMinute1) +"\">M<br>"; html += "Feed Time 2: <input type=\"number\" name=\"hour2\" min=\"0\" max=\"23\" value=\"" + String(startHour2) +"\">H : <input type=\"number\" name=\"minute2\" min=\"0\" max=\"59\" value=\"" + String(startMinute2) +"\">M<br>"; html += "Duration (seconds): <input type=\"number\" name=\"duration\" min=\"0\" max=\"3600\" value=\"" + String(durationSeconds) + "\"><br>"; html += "<input type=\"submit\" value=\"Set Time\">"; html += "</form></fieldset>"; html += "<form action=\"/manualTest\" method=\"GET\">"; html += "<input type=\"submit\" value=\"Test Relay\">"; html += "</form>"; html += "</body></html>"; server.send(200, "text/html", html); } // Handle setTime page void handleSetTime() { if (server.hasArg("hour1") && server.hasArg("minute1") && server.hasArg("hour2") && server.hasArg("minute2") && server.hasArg("duration")) { startHour1 = server.arg("hour1").toInt(); startMinute1 = server.arg("minute1").toInt(); startHour2 = server.arg("hour2").toInt(); startMinute2 = server.arg("minute2").toInt(); durationSeconds = server.arg("duration").toInt(); saveTimerSettings(); server.send(200, "text/html", "Time set! Go <a href=\"/\">back</a>."); Serial.print("Time 1 set to: "); Serial.print(startHour1); Serial.print(":"); Serial.print(startMinute1); Serial.print(" Time 2 set to: "); Serial.print(startHour2); Serial.print(":"); Serial.print(startMinute2); Serial.print(" for "); Serial.print(durationSeconds); Serial.println(" seconds."); } else { server.send(400, "text/html", "Invalid request."); } } // Handle manual test button void handleManualTest() { if (!relayOn) { digitalWrite(relayPin, LOW); // Turn on the relay relayOn = true; manualTest = true; // Set manual test flag startSecond = second(); // Start the manual timer server.send(200, "text/html", "Manual test activated! Relay on for set duration. Go <a href=\"/\">back</a>."); Serial.println("Manual test: Relay turned on!"); } else { server.send(200, "text/html", "Relay already active. Go <a href=\"/\">back</a>."); } } int second() { time_t now = time(nullptr); struct tm* currentTime = localtime(&now); return currentTime->tm_sec; } The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
PhenixRising Guru Joined: 07/11/2023 Location: United KingdomPosts: 855 |
A couple of hours?!?!?! |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4219 |
Nice work Gizmo !! I am going to study your C code. I think this could also be a nice project for a WebMite (I think it has the commands/functions to do this). But this (total cost around 3-4 dollar ?) is cheaper than the Webmite alone.... Volhout PicomiteVGA PETSCII ROBOTS |
||||
Mixtel90 Guru Joined: 05/10/2019 Location: United KingdomPosts: 6764 |
That's a really cool project. :) Actually, I think it's the first time I've seen the 01 used in a "proper" project rather than just a breadboard demo. Going off on one of my rambles.... I've just been playing with a node MCU board, which uses the ESP-12E (a modern version with more IO). I loaded it with ESP BASIC as I just couldn't figure out node MCU and I hate C. It's interesting, to say the least. ESP BASIC has some odd quirks and quite a few limitations but it's very usable. Some bits are genius: a = pin(pi, 7) will read the state of GPIO7 pin(po, 7) = 1 will set GPIO7 to 1 pin(pw, 7) = 50 will set PWM on GPIO7 to 50 a = pin(ai) will read the (only) analogue input No setpin needed, it's done on the fly. Quotes in strings can be | or " so print "I said |Hello|" prints I said "Hello" as does |I said "Hello"| Unfortunately you have to write "print" in full. Arrays are only single-dimensional. All programming is via a web browser. There can be a serial interface to the chip but it's not needed - and I don't think you can load programs through it anyway. It's quite a nice IDE in many ways. It will run on a ESP8266-01S but the real-time debugger and variables dump are omitted. I'm not sure if he's still developing for that platform now though. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Yeah I've learned to embrace ChatGPT for stuff like this. I just ask a series of questions, it generates code, then I ask it to add another feature, it adds the code, etc. It does the bulk of the work, then I go and debug it, make modifications, etc. In this case, its code was for only one event a day, I added extra code for 2 events. Its EEPROM code was wrong, fixed that. I also tidied up the HTML page a little, added the test relay button and code. And lastly it was pulling the relay output high, but it needed to be low, to activate the relay. If I had to do everything from scratch, it would be a couple days at least. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Volhout Guru Joined: 05/03/2018 Location: NetherlandsPosts: 4219 |
Hi Gizmo, Are you using a Fritzbox router ? 192.168.178.xx Volhout PicomiteVGA PETSCII ROBOTS |
||||
PhenixRising Guru Joined: 07/11/2023 Location: United KingdomPosts: 855 |
Same here but with the ESP32. I don't have a ChatGPT subscription and so it turns out that there is a daily allowance. I switched to Copilot and there's no limit when it comes to code-assist. I have since realised that it only pulls-in sample code from the web because I have found the exact same stuff...but it's certainly quick. Got my knickers in a twist because my fresh install was the latest Core 3+ Arduino and a few things, such as timer-related functions have changed and are no-longer compatible. Switched back to Core 2+ and everything is fine. Now I have learned enough that I can switch back to Core 3+. The problem was that; ChatGPT and Copilot were grabbing the Core 2+ stuff and I just happened to be needing the timer functions. I am racing through this stuff with surprising ease and can now come-up with peripheral for the Mites. I now have the ESP32 as my Bluetooth device, connected to a PicoMite and it's rock-solid. Don't really need WiFi yet but that and Ethernet seem pretty straightforward, as does ESP-NOW. Fun, fun, fun |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Are you using a Fritzbox router ? 192.168.178.xx Volhout I did once. When I bought a new router, I decided to keep the same number scheme. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Print this page |