#include <ESP32Servo.h>
#include <ESP32Time.h>
#include <WiFi.h>
#include "time.h"
#include <ezButton.h>
#include <iostream>
const char* ssid = "Wokwi-GUEST"; // change this to your wifi name
const char* password = ""; // change this to your wifi password
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -14400; // offset to GMT-4
const int daylightOffset_sec = 0;
unsigned long timeSinceStart = 0;
struct tm accelerationStart; // will be used to store the start time of acceleration
int servoPin1 = 18;
int servoPin2 = 19;
int servoPin3 = 23;
int buttonPin = 5;
Servo hourArm;
Servo zeroArm;
Servo minuteArm;
ezButton button(buttonPin); // attach button to button pin
struct tm getCurrTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
}
return timeinfo;
}
struct tm getAcceleratedTime(struct tm accelerationStart, unsigned long timeSinceStart){
// https://forum.arduino.cc/t/sketch-to-convert-milliseconds-to-hours-minutes-and-seconds-hh-mm-ss/636386
unsigned long seconds = timeSinceStart / 1000; // turn milliseconds into seconds passed
unsigned long minutes = seconds / 60; // turn seconds into minutes passed
unsigned long hours = minutes / 60; // turn minutes into hours passed
unsigned long days = hours / 24;
seconds %= 60; // get the leftover seconds
minutes %= 60; // get the leftover minutes
hours %= 24; // get the leftover hours
struct tm acceleratedTime = accelerationStart;
long currSeconds = acceleratedTime.tm_sec + seconds; // increment acceleration start second
long currMin = acceleratedTime.tm_min + minutes + currSeconds / 60; // increment acceleration start minute
long currHour = acceleratedTime.tm_hour + hours + currMin / 60; // increment acceleration start hour
acceleratedTime.tm_sec = currSeconds % 60; // make sure second is not over 60
acceleratedTime.tm_min = currMin % 60; // make sure minute is not over 60
acceleratedTime.tm_hour = currHour % 24; // make sure hour is not over 24
return acceleratedTime;
}
void tapArmOnce(Servo& arm) // tap the servo arm once
{
for (int pos = 90; pos <= 120; pos += 1) { // goes from 90 degrees to 120 degrees
// in steps of 1 degree
arm.write(pos);
delay(5); // waits for the servo to reach the position
}
for (int pos = 120; pos >= 90; pos -= 1) { // goes from 120 degrees back to 90 degrees
arm.write(pos);
delay(5);
}
Serial.println("moved servo arm");
}
void tapArmMultipleTimes(Servo& arm, int num) // tap the servo arm num times
{
Serial.print("moving arm to represent: ");
Serial.println(num);
int tenthDigit = (num / 10) % 10;
int lastDigit = num % 10;
// tap tenthDigit times
Serial.print("moving for ");
Serial.println(tenthDigit);
if (tenthDigit == 0){
tapArmOnce(zeroArm);
}
for (int i = 0; i < tenthDigit; i++){
tapArmOnce(arm);
}
delay(1000); // pause a bit for the next digit
// tap lastDigit times
Serial.print("moving for ");
Serial.println(lastDigit);
if (lastDigit == 0){
tapArmOnce(zeroArm);
}
for (int i = 0; i < lastDigit; i++){
tapArmOnce(arm);
}
delay(1000); // pause a bit for the next digit
}
void reportTime(struct tm currTime){ // tell time by tapping servo arms
tapArmMultipleTimes(hourArm, currTime.tm_hour);
tapArmMultipleTimes(minuteArm, currTime.tm_min);
}
void setup() {
hourArm.attach(servoPin1);
zeroArm.attach(servoPin2);
minuteArm.attach(servoPin3);
//connect to WiFi to get current local time
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
accelerationStart = getCurrTime();
//deviceSetupTime = currTime;
timeSinceStart = millis(); // record milliseconds passed since device started,happens before device gets set up
//disconnect WiFi as it's no longer needed
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
Serial.begin(115200);
}
void loop()
{
// https://esp32io.com/tutorials/esp32-switch
button.loop(); // MUST call the loop() function first
if(button.isPressed()){
Serial.println("The button is pressed, acceleration: OFF -> ON");
}
if(button.isReleased()){
Serial.println("The button is released, acceleration: ON -> OFF");
}
Serial.print("the button is ");
if (button.getState()){
Serial.println("UP, acceleration: OFF");
// report time without acceleration
struct tm currTime = getCurrTime();
timeSinceStart = millis(); // update the start time of
reportTime(currTime);
} else {
Serial.println("DOWN, acceleration: ON");
unsigned long timePassed = millis() - timeSinceStart; // update milliseconds passed since acceleration was turned on
Serial.print("milliseconds passed since acceleration turned on: ");
Serial.println(timePassed);
struct tm currTime = getCurrTime();
Serial.print("actual time: ");
Serial.println(&currTime, "%A, %B %d %Y %H:%M:%S");
struct tm acceleratedTime = getAcceleratedTime(accelerationStart, timePassed * 120); // multiply by 120 to accelerate time passed by 120x, 1 second is equal to 2 minutes
Serial.print("accelerated time: ");
Serial.println(&acceleratedTime, "%A, %B %d %Y %H:%M:%S");
reportTime(acceleratedTime);
}
delay(5000); // pause for 5 seconds to report time every 5 seconds
}