Back at one of Veracode’s Hackathons, I published the video below.
My Original Weasley Clock
The New and Improved Weasley Clock(s)
(Original post is here.) I was determined to update the code to use WiFi, and make some other improvements, so finally rewrote it. Here’s the first major revision:
#include#include "Adafruit_IO_Client.h" #include /** * https://www.amazon.com/gp/product/B015RQ97W8/ref=oh_aui_search_detailpage?ie=UTF8&psc=1 * 5-wire unipolar steppers with controller * Longruner 5x Geared Stepper Motor 28byj 48 Uln2003 5v Stepper Motor Uln2003 Driver * Board for arduino LK67 * * AWESOME details on these motors/controllers: * https://arduino-info.wikispaces.com/SmallSteppers * * Much Better than standard stepper library: AccelStepper * http://www.airspayce.com/mikem/arduino/AccelStepper/classAccelStepper.html * * Weasley Clock * ------------- * * Created by Doug "LegoDoug" Wilcox for Veracode Hackathon IX. * * Video of the completed project is at https://www.youtube.com/embed/oRUViFnxKsg. * * "Share and enjoy." */ /************************* WiFi Access Point *********************************/ #define WLAN_SSID "DefinitelyNotMySSID" // "...your SSID..." Amusingly, the cannot contains spaces or hyphens. #define WLAN_PASS "TotallyNotTheRealPassword" // "...your password..." /************************* Adafruit.io Setup *********************************/ #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 // use 8883 for SSL, otherwise use 1883 #define AIO_USERNAME "TotallyNotMyAdaFruitIOUser" // "...your AIO username (see https://accounts.adafruit.com)..." #define AIO_KEY "TotallyNotMyAdafruitIOKey" // "...your AIO key..." #define AIO_FEED_PATH "/feeds/" #define AIO_PUBLISH_FEED "weasleyclockposition" #define AIO_SUBSCRIBE_FEED "weasleyclockstatus" // Motor pin definitions #define motorPin1 14 // IN1 on the ULN2003 driver 1 #define motorPin2 12 // IN2 on the ULN2003 driver 1 #define motorPin3 13 // IN3 on the ULN2003 driver 1 #define motorPin4 15 // IN4 on the ULN2003 driver 1 #define DELAY 1 #define HALFSTEP 8 /************ Global State (you don't need to change this!) ******************/ // Create an ESP8266 WiFiClient class to connect to the WiFi network. WiFiClient client; // or... use WiFiFlientSecure for SSL // WiFiClientSecure client; // Create an Adafruit IO Client instance. Notice that this needs to take a // WiFiClient object as the first parameter, and as the second parameter a // default Adafruit IO key to use when accessing feeds (however each feed can // override this default key value if required, see further below). Adafruit_IO_Client aio = Adafruit_IO_Client(client, AIO_KEY); // Alternatively to access a feed with a specific key: Adafruit_IO_Feed clockFeed = aio.getFeed(AIO_SUBSCRIBE_FEED, AIO_KEY); // States const String LD_HOME = "ld_na"; const String LD_TRAVELING = "ld_tr"; const String LD_VERACODE = "ld_of"; const String LD_CHURCH = "ld_ch"; const String LD_MORTAL_PERIL = "ld_mp"; const String LD_GLOUCESTER = "ld_gl"; const String PLUS_ONE = "plus_1"; const String MINUS_ONE = "minus_1"; const String PLUS_FIVE = "plus_5"; const String MINUS_FIVE = "minus_5"; const String NO_MOVEMENT = "none"; // Steps const int STEPS_HOME = 0; const int STEPS_TRAVELING = 600; const int STEPS_VERACODE = 1250; const int STEPS_CHURCH = 1900; const int STEPS_MORTAL_PERIL = 2600; const int STEPS_GLOUCESTER = 3450; const int STEPS_ONE = 32; const int STEPS_FIVE = 5 * 32; String fValue = ""; const unsigned long requestInterval = 5000L; // delay between updates, in milliseconds void stepBySteps(int newPosition, boolean resetWhenDone = false); AccelStepper clockStepper(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); void setup() { Serial.begin(115200); delay(10); // Connect to WiFi access point. Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(WLAN_SSID); WiFi.begin(WLAN_SSID, WLAN_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); clockStepper.setMaxSpeed(1000.0); clockStepper.setAcceleration(100.0); clockStepper.setSpeed(200); clockStepper.setCurrentPosition(0); } void loop() { // Wait for a bit and read the current feed value. Serial.println(F("Waiting ...")); delay(requestInterval); // To read the latest feed value call the receive function on the feed. // The returned object will be a FeedData instance and you can check if it's // valid (i.e. was successfully read) by calling isValid(), and then get the // value either as a text value, or converted to an int, float, etc. Serial.println(F("Checking feed ...")); FeedData latest = clockFeed.receive(); if (latest.isValid()) { Serial.print(F("Received value from feed: ")); Serial.println(latest); // By default the received feed data item has a string value, however you // can use the following functions to attempt to convert it to a numeric // value like an int or float. Each function returns a boolean that indicates // if the conversion succeeded, and takes as a parameter by reference the // output value. Also, beware. There seems to be a limit on how long the // feed value can be. I had trouble when "minus_five" was used, which makes // me think the limit is 8 characters. // Want some fun? Learng about "conversion from 'FeedData' to non-scalar type 'String' requested" the hard way. fValue = latest; if(fValue == LD_HOME) { Serial.println("Nashua"); stepBySteps(STEPS_HOME); } if(fValue == LD_TRAVELING) { Serial.println("Traveling"); stepBySteps(STEPS_TRAVELING); } if(fValue == LD_VERACODE) { Serial.println("Veracode"); stepBySteps(STEPS_VERACODE); } if(fValue == LD_CHURCH) { Serial.println("Church"); stepBySteps(STEPS_CHURCH); } if(fValue == LD_MORTAL_PERIL) { Serial.println("Mortal Peril!"); stepBySteps(STEPS_MORTAL_PERIL); } if(fValue == LD_GLOUCESTER) { Serial.println("Glostah"); stepBySteps(STEPS_GLOUCESTER); } if(fValue == PLUS_ONE) { Serial.println("Forward one."); stepBySteps(clockStepper.currentPosition() + STEPS_ONE, true); } if(fValue == MINUS_ONE) { Serial.println("Back one."); stepBySteps(clockStepper.currentPosition() - STEPS_ONE, true); } if(fValue == PLUS_FIVE) { Serial.println("Forward five."); stepBySteps(clockStepper.currentPosition() + STEPS_FIVE, true); } if(fValue == MINUS_FIVE) { Serial.println("Back five."); stepBySteps(clockStepper.currentPosition() - STEPS_FIVE, true); } if(fValue == NO_MOVEMENT || fValue == "") { Serial.println("Not moving."); } } else { Serial.print(F("Failed to receive the latest feed value!")); } } void stepBySteps(int newPosition, boolean resetWhenDone) { clockStepper.enableOutputs(); clockStepper.moveTo(newPosition); while (clockStepper.isRunning()) { clockStepper.run(); delay(DELAY); } clockStepper.disableOutputs(); if (resetWhenDone) { clockStepper.setCurrentPosition(0); } }
Still to come, if I ever get around to it:
- Alternative methodologies for reading the feed (publish/subscribe).
- Secure WiFi communication.
- Adjustment (such as after power disconnect) via an induction sensor.