diff --git a/BaseConfig.h b/BaseConfig.h new file mode 100644 index 0000000..e203d16 --- /dev/null +++ b/BaseConfig.h @@ -0,0 +1,32 @@ +/* + R. J. Tidey 2019/12/30 + Basic config +*/ +#define FILESYSTYPE 1 + +/* +Wifi Manager Web set up +*/ +#define WM_NAME "uselessbox" +#define WM_PASSWORD "password" + +//Update service set up +String host = "uselessbox"; +const char* update_password = "password"; + +//define actions during setup +//define any call at start of set up +#define SETUP_START 1 +//define config file name if used +#define CONFIG_FILE "/uselessConfig.txt" +//set to 1 if SPIFFS or LittleFS used +#define SETUP_FILESYS 1 +//define to set up server and reference any extra handlers required +#define SETUP_SERVER 1 +//call any extra setup at end +#define SETUP_END 1 + +// comment out this define unless using modified WifiManager with fast connect support +#define FASTCONNECT true + +#include "BaseSupport.h" diff --git a/README.md b/README.md index 79a728e..c2643b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,48 @@ -# Smart Useless Box with ESP8266 and Gesture Sensor +# Smart Useless Box with ESP8266 and Gesture Sensor modified + +This is a modification of the excellent Useless Box from balassy. + +https://github.com/balassy/useless-box + +The enclosure is the same but the software now has following additions. + +- Wifi support via WifiManager +- SPIFFS support with filing and uploads +- Configuration via a file in SPIFFS +- Software update via OTA web browser +- Modfied schematic with an amplifier and loudspeaker to give speech responses +- Audio output via a software DAC using ESP8266Audio library + +The SPIFFS config file controls +- servo positions and speeds +- Actions are defined in the config file as sequences of base commands which control servo movements, delays, audio responses and sensor control +- Sensor audio responses may be varied +- Comments in the example config file list possible commands to be used in the sequences. +- Sequences can either run one after another or can be selected at random. + +For my hardware I used an ESP-12F rather than the Wemos but that is a personal preference. +The speaker in my case was a 21mm diameter but larger ones can be used. +I made the switch a bit easier to toggle by taking 1mm off the internal spindle to reduce spring tension. + +![Schematic](./wiring/Schematic_UselessBox.jpg) + +[![Smart Useless Box in Action](./media/Useless-Box1Preview.jpg)](https://youtu.be/ker99iGVxNo "Smart Useless Box in Action") + +##Set up Notes +- Use BaseSupprt library at https://github.com/roberttidey/BaseSupport +- Modify passwords for Wifimanager and firmware updates in BasicConfig.h.ino +- Compile and serial upload using Arduino ESP8266 IDE. Code / SPIFFS split needs to be 2MB/2MB to allow for OTA to work. +- WifiManager will start an AP portal when first used to set local wifi parameters. After that it will hook into local network. +- Browse to the device using its IPaddress/upload and upload from data director (edit.htm.gz, favicon.ico, graphs.js.gz). From then on IPaddress/edit may be used to manage SPIFFs content +- Upload uselessConfig.txt, index.html, and .mp3 audio files to SPIFFs +- You can customise these as required. Audio files can be created using an online text to audio service like Notevibes. +- Simple test of servos and audio may be done from base index page at IPaddress/edit +- OTA updates may be done by exporting a compiled binary in Arduino IDE and then browsing to IPAddress/firmware + + +The following is directly from balassy README + +## Smart Useless Box with ESP8266 and Gesture Sensor modified A useless box made smarter with an ESP8266 microcontroller on a Wemos D1 Mini board and an APDS-9960 proximity sensor to give more funny responses. diff --git a/config.h b/config.h index 4775cd3..c81f8f8 100644 --- a/config.h +++ b/config.h @@ -1,18 +1,11 @@ -const char* APP_VERSION = "0.0.1"; +//const char* APP_VERSION = "0.0.1"; #ifndef LED_BUILTIN -#define LED_BUILTIN D4 +#define LED_BUILTIN 2 #endif -const int PIN_LID_SERVO = D8; // The GPIO number of the pin where the lid opener servo is connected. -const int PIN_SWITCH_SERVO = D0; // The GPIO number of the pin where the switch manipulator servo is connected. -const int PIN_SWITCH = D5; // The GPIO number of the pin where the switch is connected. -const int PIN_SENSOR_SDA = D2; // The GPIO number of the pin where the SDA pin of the APDS-9660 sensor is connected. -const int PIN_SENSOR_SCL = D1; // The GPIO number of the pin where the SCL pin of the APDS-9660 sensor is connected. -const uint8_t SENSOR_TRIGGER_THRESHOLD = 100; // The proximity value level that triggers a lid opening. (lower=brighter, higher=darker) - -const int LID_START_POSITION = 90; -const int LID_END_POSITION = 40; -const int SWITCH_START_POSITION = 0; -const int SWITCH_END_POSITION = 145; -const int SWITCH_HALF_POSITION = 90; +const int PIN_LID_SERVO = 12; // The GPIO number of the pin where the lid opener servo is connected. +const int PIN_SWITCH_SERVO = 5; // The GPIO number of the pin where the switch manipulator servo is connected. +const int PIN_SWITCH = 4; // The GPIO number of the pin where the switch is connected. +const int PIN_SENSOR_SDA = 13; // The GPIO number of the pin where the SDA pin of the APDS-9660 sensor is connected. +const int PIN_SENSOR_SCL = 14; // The GPIO number of the pin where the SCL pin of the APDS-9660 sensor is connected. diff --git a/data/00.mp3 b/data/00.mp3 new file mode 100644 index 0000000..bca20b2 Binary files /dev/null and b/data/00.mp3 differ diff --git a/data/01.mp3 b/data/01.mp3 new file mode 100644 index 0000000..a9d74be Binary files /dev/null and b/data/01.mp3 differ diff --git a/data/02.mp3 b/data/02.mp3 new file mode 100644 index 0000000..b04fb86 Binary files /dev/null and b/data/02.mp3 differ diff --git a/data/03.mp3 b/data/03.mp3 new file mode 100644 index 0000000..a40d401 Binary files /dev/null and b/data/03.mp3 differ diff --git a/data/04.mp3 b/data/04.mp3 new file mode 100644 index 0000000..a9eb37d Binary files /dev/null and b/data/04.mp3 differ diff --git a/data/05.mp3 b/data/05.mp3 new file mode 100644 index 0000000..1a0205d Binary files /dev/null and b/data/05.mp3 differ diff --git a/data/06.mp3 b/data/06.mp3 new file mode 100644 index 0000000..1aac03d Binary files /dev/null and b/data/06.mp3 differ diff --git a/data/07.mp3 b/data/07.mp3 new file mode 100644 index 0000000..54b1d69 Binary files /dev/null and b/data/07.mp3 differ diff --git a/data/08.mp3 b/data/08.mp3 new file mode 100644 index 0000000..645d100 Binary files /dev/null and b/data/08.mp3 differ diff --git a/data/09.mp3 b/data/09.mp3 new file mode 100644 index 0000000..059bbe6 Binary files /dev/null and b/data/09.mp3 differ diff --git a/data/10.mp3 b/data/10.mp3 new file mode 100644 index 0000000..ca10451 Binary files /dev/null and b/data/10.mp3 differ diff --git a/data/11.mp3 b/data/11.mp3 new file mode 100644 index 0000000..0522ea4 Binary files /dev/null and b/data/11.mp3 differ diff --git a/data/12.mp3 b/data/12.mp3 new file mode 100644 index 0000000..49b5a85 Binary files /dev/null and b/data/12.mp3 differ diff --git a/data/audio.txt b/data/audio.txt new file mode 100644 index 0000000..1336ae7 --- /dev/null +++ b/data/audio.txt @@ -0,0 +1,16 @@ +00 a-round-of-applause-for-trying-again1574765538 +01 back-and-forth-back-and-forth-never1574765904 +02 cant-quite-make-it-lets-try-again1574765609 +03 cant-you-read-the-instructions1574765146 +04 i-am-getting-bored-with-this1574765806 +05 i-said-i-was-useless1574764811 +06 i-told-you-not-to1574764680 +07 my-arm-is-getting-tired1574765448 +08 slow-slow-quick-quick-slow1574765781 +09 you-are-wasting-your-time-here1574765348 +10 you-did-it-again +11 This is fun. Not. +12 Here we go again. + + +sensor Naughty. Naughty. diff --git a/data/edit.htm.gz b/data/edit.htm.gz new file mode 100644 index 0000000..69ce414 Binary files /dev/null and b/data/edit.htm.gz differ diff --git a/data/favicon.ico b/data/favicon.ico new file mode 100644 index 0000000..71b25fe Binary files /dev/null and b/data/favicon.ico differ diff --git a/data/graphs.js.gz b/data/graphs.js.gz new file mode 100644 index 0000000..7243544 Binary files /dev/null and b/data/graphs.js.gz differ diff --git a/data/index.htm b/data/index.htm new file mode 100644 index 0000000..dc55d78 --- /dev/null +++ b/data/index.htm @@ -0,0 +1,30 @@ + + + + +ESP8266 Useless test + + + +

Useless

+
+

+Switch Position
+ +

+
+
+

+Lid Position
+ +

+
+
+

+Audio File
+ +

+
+ \ No newline at end of file diff --git a/data/sensor1.mp3 b/data/sensor1.mp3 new file mode 100644 index 0000000..df129af Binary files /dev/null and b/data/sensor1.mp3 differ diff --git a/data/sensor2.mp3 b/data/sensor2.mp3 new file mode 100644 index 0000000..49b5a85 Binary files /dev/null and b/data/sensor2.mp3 differ diff --git a/data/uselessConfig.txt b/data/uselessConfig.txt new file mode 100644 index 0000000..4fd41b9 --- /dev/null +++ b/data/uselessConfig.txt @@ -0,0 +1,38 @@ +#Config file for weather / train access +# lines are +#host;switchStart;switchHalf;switchEnd;switchFast;switchSlow;lidStart;lidEnd;lidSlow;lidFast +#sensorTriggerThreshold (0= no sensor) +#mode (0=sequence, 1=random) +#audioGain (0-39) +#modeLines made up following actions +#SS switch start slow;SF witch start fast;HS switch half slow;HF switch half fast;ES switch end slow;EF switch end fast +#CS lid close slow;CF lid close fast;OS lid open slow;OF lid open fast +#XSSPPP switch move to PPP with speed factor SS +#YSSPPP lid move to PPP with speed factor SS +#M0 proximity monitor off;M1 proximity monitor on +#P0 mode to sequential;P1 mode to random +#Afilename play audio from filename +esp8266-useless +0 +90 +118 +5 +15 +90 +50 +5 +15 +190 +0 +25 +OS,A05,ES,SS,CS +OS,A06,ES,SS,CS,M0 +D5000,OF,A10,EF,SF,CF +OF,A03,EF,SF,CF +OF,A09,EF,SF,CF,OF,CF,M1 +OS,A04,D2000,CS,D2000,OF,EF,SF,CF,M0 +OF,HS,A02,D3000,SS,D3000,EF,SF,CF +OS,A01,D4000,EF,SF,CF,M0 +OF,A00,CF,OF,CF,OF,CF,OF,CF,OF,EF,SF,CF,M2 +OF,HS,A07,D3000,EF,SF,CS,M0 +OS,A08,HS,EF,SF,CS,P1 \ No newline at end of file diff --git a/media/Useless-Box1.jpg b/media/Useless-Box1.jpg new file mode 100644 index 0000000..25fc573 Binary files /dev/null and b/media/Useless-Box1.jpg differ diff --git a/media/Useless-Box1Preview.jpg b/media/Useless-Box1Preview.jpg new file mode 100644 index 0000000..9ae7402 Binary files /dev/null and b/media/Useless-Box1Preview.jpg differ diff --git a/speed-servo.cpp b/speed-servo.cpp index 577cbbe..2772d9c 100644 --- a/speed-servo.cpp +++ b/speed-servo.cpp @@ -1,41 +1,24 @@ #include "speed-servo.h" -const int SLOW_MOVE_DELAY = 15; -const int Fast_MOVE_DELAY = 2; - void SpeedServo::attach(uint8_t pin) { - _servo.attach(pin); -} - -// Valid position: 0-180. -void SpeedServo::moveNowTo(int newPosition) { - _lastPosition = newPosition; - _servo.write(newPosition); + _servo.attach(pin); } // Valid position: 0-180. -void SpeedServo::moveFastTo(int newPosition) { - _moveTo(newPosition, Fast_MOVE_DELAY); -} - -// Valid position: 0-180. -void SpeedServo::moveSlowTo(int newPosition) { - _moveTo(newPosition, SLOW_MOVE_DELAY); -} - -// Valid position: 0-180. -void SpeedServo::_moveTo(int newPosition, unsigned long stepDelay) { - if(newPosition > _lastPosition) { - for (int pos = _lastPosition; pos <= newPosition; pos++) { - _servo.write(pos); - delay(stepDelay); - } - } else { - for (int pos = _lastPosition; pos >= newPosition; pos--) { - _servo.write(pos); - delay(stepDelay); - } - } - - _lastPosition = newPosition; +void SpeedServo::moveTo(int newPosition, unsigned long stepDelay) { + if(stepDelay == 0) { + _lastPosition = newPosition; + _servo.write(newPosition); + } else if(newPosition > _lastPosition) { + for (int pos = _lastPosition; pos <= newPosition; pos++) { + _servo.write(pos); + delay(stepDelay); + } + } else { + for (int pos = _lastPosition; pos >= newPosition; pos--) { + _servo.write(pos); + delay(stepDelay); + } + } + _lastPosition = newPosition; } diff --git a/speed-servo.h b/speed-servo.h index 0429716..80d617e 100644 --- a/speed-servo.h +++ b/speed-servo.h @@ -7,14 +7,11 @@ class SpeedServo { public: void attach(uint8_t pin); - void moveNowTo(int position); - void moveFastTo(int position); - void moveSlowTo(int position); + void moveTo(int newPosition, unsigned long stepDelay); private: Servo _servo; int _lastPosition; - void _moveTo(int newPosition, unsigned long stepDelay); }; #endif /* speed_servo_h */ diff --git a/useless-box.ino b/useless-box.ino index 2c2e433..840df05 100644 --- a/useless-box.ino +++ b/useless-box.ino @@ -1,217 +1,351 @@ // Platform libraries. #include // To add IntelliSense for platform constants. +#include "BaseConfig.h" // Third-party libraries. +#include "AudioFileSourceSPIFFS.h" +#include "AudioFileSourceID3.h" +#include "AudioGeneratorMP3.h" +#include "AudioOutputI2SNoDAC.h" // My classes. #include "speed-servo.h" #include "status-led.h" #include "proximity-sensor.h" - #include "config.h" // To store configuration and secrets. + +int timeInterval = 250; +unsigned long elapsedTime; +#define MAX_ACTIONS 25 + +int switchStart = 0; +int switchHalf = 50; +int switchEnd = 118; +int switchFast = 5; +int switchSlow = 15; +int lidStart = 90; +int lidEnd = 40; +int lidFast = 5; +int lidSlow = 1; +int sensorTriggerThreshold = 100; +int mode = 0; +int actionCount= 0; +String actions[MAX_ACTIONS]; + SpeedServo lidServo; SpeedServo switchServo; StatusLed led; ProximitySensor sensor; int lastSwitchState = 0; -long playCount = 0; +long actionIndex = 0; bool isLidOpen = false; -bool monitorSensor = false; - -void setup() { - initSerial(); - initServos(); - initLed(); - initSensor(); - pinMode(PIN_SWITCH, INPUT); - - Serial.printf("Application version: %s\n", APP_VERSION); - Serial.println("Setup completed."); +int monitorSensor = 0; + +#define START_AUDIO "/start.mp3" +#define SENSOR_AUDIO "/sensor" + +AudioGeneratorMP3 *mp3; +AudioFileSourceSPIFFS *file; +AudioOutputI2SNoDAC *out; +AudioFileSourceID3 *id3; + +#define MAX_FILES 10 +char filename[8] = "/00.mp3"; +int fileIndex = 0; +float audioGain = 3.9; + +// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc. +void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string) { + (void)cbData; + Serial.printf("ID3 callback for: %s = '", type); + + if (isUnicode) { + string += 2; + } + + while (*string) { + char a = *(string++); + if (isUnicode) { + string++; + } + Serial.printf("%c", a); + } + Serial.println(); + Serial.flush(); } -void initSerial() { - Serial.begin(115200); - Serial.println(); - Serial.println("Initializing serial connection DONE."); +void handleAudio() { + String filename = server.arg("audio"); + if(filename.length()) { + playAudio("/" + filename + ".mp3"); + } + server.send(200, "text/json", "audio was requested"); } -void initServos() { - lidServo.attach(PIN_LID_SERVO); - lidServo.moveNowTo(LID_START_POSITION); - - switchServo.attach(PIN_SWITCH_SERVO); - switchServo.moveNowTo(SWITCH_START_POSITION); +void handleLid() { + String pos = server.arg("pos"); + if(pos.length()) { + lidServo.moveTo(pos.toInt(), lidSlow); + } + server.send(200, "text/json", "lid servo to " + pos); } -void initLed() { - led.setPin(LED_BUILTIN); - led.turnOff(); +void handleSwitch() { + String pos = server.arg("pos"); + if(pos.length()) { + switchServo.moveTo(pos.toInt(), switchSlow); + } + server.send(200, "text/json", "switch servo to " + pos); } -void initSensor() { - sensor.attach(PIN_SENSOR_SDA, PIN_SENSOR_SCL, SENSOR_TRIGGER_THRESHOLD); +void handleProximity() { + String pos = server.arg("pos"); + if(pos.length()) { + switchServo.moveTo(pos.toInt(), switchSlow); + } + server.send(200, "text/json", "Proximity = " + String(sensor.getProximity())); } -void loop() { - int switchState = digitalRead(PIN_SWITCH); - boolean isSwitchTurnedOn = (switchState != lastSwitchState) && (switchState == LOW); - - if (isSwitchTurnedOn) { - led.turnOn(); - run(); - isLidOpen = false; - led.turnOff(); - } else { - // Check the proximity sensor. - if (sensor.isInRange()) { - if (!isLidOpen && monitorSensor) { - openLidFast(); - isLidOpen = true; - } - } else { - if (isLidOpen) { - closeLidFast(); - isLidOpen = false; - } - } - } - - lastSwitchState = switchState; - - // Wait 250 ms before next reading (required for the sensor). - delay(250); -} - -void run() { - switch (playCount % 10) { - case 0: - case 1: - runSlow(); - break; - case 2: - runWaitThenFast(); - break; - case 3: - runFast(); - break; - case 4: - runFastThenClap(); - monitorSensor = true; - break; - case 5: - runOpenCloseThenFast(); - monitorSensor = false; - break; - case 6: - runPeekThenFast(); - break; - case 7: - runFastWithDelay(); - monitorSensor = true; - break; - case 8: - runClap(); - monitorSensor = false; - break; - case 9: - runHalf(); - break; - default: - break; - } - - playCount++; -} - -void runSlow() { - openLidSlow(); - flipSwitchSlow(); - closeLidSlow(); -} - -void runWaitThenFast() { - delay(5000); - flipSwitchFast(); -} - -void runFast() { - flipSwitchFast(); -} - -void runFastThenClap() { - flipSwitchFast(); - clapLid(); -} - -void runOpenCloseThenFast() { - openLidSlow(); - delay(2000); - closeLidSlow(); - delay(2000); - flipSwitchFast(); -} - -void runPeekThenFast() { - switchServo.moveSlowTo(SWITCH_HALF_POSITION); - delay(3000); - switchServo.moveFastTo(SWITCH_START_POSITION); - delay(3000); - flipSwitchFast(); -} +/* + load config +*/ +void loadConfig() { + String line = ""; + int config = 0; + + actionCount = 0; + File f = SPIFFS.open(CONFIG_FILE, "r"); + if(f) { + while(f.available()) { + line =f.readStringUntil('\n'); + line.replace("\r",""); + if(line.length() > 0 && line.charAt(0) != '#') { + switch(config) { + case 0: host = line; break; + case 1: switchStart = line.toInt(); break; + case 2: switchHalf = line.toInt(); break; + case 3: switchEnd = line.toInt(); break; + case 4: switchFast = line.toInt(); break; + case 5: switchSlow = line.toInt(); break; + case 6: lidStart = line.toInt(); break; + case 7: lidEnd = line.toInt(); break; + case 8: lidFast = line.toInt(); break; + case 9: lidSlow = line.toInt(); break; + case 10: sensorTriggerThreshold = line.toInt();break; + case 11: mode = line.toInt(); break; + case 12: audioGain = line.toInt()/10; break; + default : + if(actionCount < MAX_ACTIONS) { + actions[actionCount] = line; + actionCount++; + } + break; + } + config++; + } + } + f.close(); + Serial.println(F("Config loaded")); + Serial.print(F("host:"));Serial.println(host); + Serial.print(F("switchStart:"));Serial.println(String(switchStart)); + Serial.print(F("switchHalf:"));Serial.println(String(switchHalf)); + Serial.print(F("switchEnd:"));Serial.println(String(switchEnd)); + Serial.print(F("switchFast:"));Serial.println(String(switchFast)); + Serial.print(F("switchSlow:"));Serial.println(String(switchSlow)); + Serial.print(F("lidStart:"));Serial.println(String(lidStart)); + Serial.print(F("lidEnd:"));Serial.println(String(lidEnd)); + Serial.print(F("lidFast:"));Serial.println(String(lidFast)); + Serial.print(F("lidSlow:"));Serial.println(String(lidSlow)); + Serial.print(F("sensorTriggerThreshold:"));Serial.println(String(sensorTriggerThreshold)); + Serial.print(F("mode:"));Serial.println(String(mode)); + Serial.print(F("audioGain:"));Serial.println(String(audioGain)); + Serial.print(String(actionCount));Serial.println(F(" Actions loaded")); + } else { + Serial.println(String(CONFIG_FILE) + " not found"); + } +} -void runFastWithDelay() { - openLidSlow(); - delay(4000); - flipSwitchFast(); - closeLidFast(); +void updateactionIndex() { + if(mode == 0) { + actionIndex++; + actionIndex = actionIndex % actionCount; + } else { + actionIndex = random(actionCount); + } } -void runClap() { - clapLid(); - clapLid(); - clapLid(); - clapLid(); - openLidFast(); - flipSwitchFast(); - closeLidFast(); +void playAudio(String filename) { + Serial.println("Play " + filename); + if(SPIFFS.exists(filename)) { + file = new AudioFileSourceSPIFFS(filename.c_str()); + id3 = new AudioFileSourceID3(file); + id3->RegisterMetadataCB(MDCallback, (void*)"ID3TAG"); + out = new AudioOutputI2SNoDAC(); + mp3 = new AudioGeneratorMP3(); + delay(100); + out->SetGain(audioGain); + mp3->begin(id3, out); + while(mp3->isRunning()) { + if (!mp3->loop()) {delay(500);mp3->stop();} + } + delete mp3; + delete out; + delete id3; + delete file; + } } -void runHalf() { - switchServo.moveSlowTo(SWITCH_HALF_POSITION); - delay(3000); - switchServo.moveFastTo(SWITCH_END_POSITION); - switchServo.moveFastTo(SWITCH_START_POSITION); +void runEx() { + int i = 0; + int j = 0; + int servo; + int position; + int speed; + String action; + unsigned long t = millis(); + String msg; + char actionChar; + char actionChar1; + + Serial.println("run " + actions[actionIndex]); + while(j < actions[actionIndex].length()) { + msg = String((millis() -t)) + " "; + j = actions[actionIndex].indexOf(',', i); + if(j < 0) j = actions[actionIndex].length(); + servo = 0; + action = actions[actionIndex].substring(i,j); + actionChar = action.charAt(0); + action = action.substring(1); + if(actionChar == 'D') { + //delay + delay(action.toInt()); + msg += "Delay " + action; + } else if(actionChar == 'A') { + //Audio + msg += "AudioPlay \/" + action + ".mp3"; + Serial.println(msg); + playAudio("/" + action + ".mp3"); + msg = ""; + } else if(actionChar == 'X' || actionChar == 'Y') { + speed = action.substring(0,2).toInt(); + position = action.substring(3).toInt(); + if(actionChar == 'X') { + servo = 1; + position = switchStart + (switchEnd - switchStart) * position / 100; + + } else { + position = lidStart + (lidEnd - lidStart) * position / 100; + servo = 2; + } + } else if(actionChar == 'S') { + position = switchStart; + speed = (action == "S") ? switchSlow : switchFast; + servo = 1; + } else if(actionChar == 'H') { + position = switchHalf; + speed = (action == "S") ? switchSlow : switchFast; + servo = 1; + } else if(actionChar == 'E') { + position = switchEnd; + speed = (action == "S") ? switchSlow : switchFast; + servo = 1; + } else if(actionChar == 'C') { + position = lidStart; + speed = (action == "S") ? lidSlow : lidFast; + servo = 2; + } else if(actionChar == 'O') { + position = lidEnd; + speed = (action == "S") ? lidSlow : lidFast; + servo = 2; + } else if(actionChar == 'M') { + monitorSensor = action.toInt(); + msg+= "monitorSensor " + action; + } else if(actionChar == 'P') { + mode = action.toInt(); + msg+= "mode " + action; + } + if(servo == 1) { + switchServo.moveTo(position, speed); + msg += "switch to " + String(position) + " speed " + String(speed); + } else if (servo == 2) { + lidServo.moveTo(position, speed); + msg += "lid to " + String(position) + " speed " + String(speed); + } + if(msg != "") Serial.println(msg); + i = j + 1; + } } -void openLidSlow() { - lidServo.moveSlowTo(LID_END_POSITION); +void initServos() { + lidServo.attach(PIN_LID_SERVO); + lidServo.moveTo(lidStart, 0); + + switchServo.attach(PIN_SWITCH_SERVO); + switchServo.moveTo(switchStart, 0); } -void openLidFast() { - lidServo.moveFastTo(LID_END_POSITION); +void initLed() { + led.setPin(LED_BUILTIN); + led.turnOff(); } -void closeLidSlow() { - lidServo.moveSlowTo(LID_START_POSITION); +void initSensor() { + sensor.attach(PIN_SENSOR_SDA, PIN_SENSOR_SCL, sensorTriggerThreshold); } -void closeLidFast() { - lidServo.moveFastTo(LID_START_POSITION); +void setupStart() { + audioLogger = &Serial; } -void clapLid() { - openLidFast(); - closeLidFast(); +void extraHandlers() { + server.on("/audio", HTTP_GET, handleAudio); + server.on("/lid", HTTP_GET, handleLid); + server.on("/switch", HTTP_GET, handleSwitch); + server.on("/proximity", HTTP_GET, handleProximity); } -void flipSwitchSlow() { - switchServo.moveSlowTo(SWITCH_END_POSITION); - switchServo.moveSlowTo(SWITCH_START_POSITION); +void setupEnd() { + initServos(); + initLed(); + initSensor(); + randomSeed(analogRead(0)); + pinMode(PIN_SWITCH, INPUT_PULLUP); + playAudio(START_AUDIO); } -void flipSwitchFast() { - switchServo.moveFastTo(SWITCH_END_POSITION); - switchServo.moveFastTo(SWITCH_START_POSITION); +void loop() { + int switchState = digitalRead(PIN_SWITCH); + boolean isSwitchTurnedOn = (switchState != lastSwitchState) && (switchState == LOW); + + if (isSwitchTurnedOn) { + led.turnOn(); + runEx(); + updateactionIndex(); + isLidOpen = false; + led.turnOff(); + } else { + // Check the proximity sensor. + if (sensorTriggerThreshold && sensor.isInRange()) { + if (!isLidOpen && monitorSensor) { + lidServo.moveTo(lidEnd, lidFast); + playAudio(SENSOR_AUDIO + String(monitorSensor) + ".mp3"); + isLidOpen = true; + } + } else { + if (isLidOpen) { + lidServo.moveTo(lidStart, lidFast); + isLidOpen = false; + } + } + } + + lastSwitchState = switchState; + + // Wait 250 ms before next reading (required for the sensor). + delay(timeInterval); + elapsedTime++; + server.handleClient(); } + diff --git a/wiring/Schematic_UselessBox.jpg b/wiring/Schematic_UselessBox.jpg new file mode 100644 index 0000000..5c84e49 Binary files /dev/null and b/wiring/Schematic_UselessBox.jpg differ