Skip to content

Instantly share code, notes, and snippets.

@jamesbulpin
Last active December 19, 2018 16:53
Show Gist options
  • Save jamesbulpin/d25403d56798013fd5015db49d822826 to your computer and use it in GitHub Desktop.
Save jamesbulpin/d25403d56798013fd5015db49d822826 to your computer and use it in GitHub Desktop.
Sketch for the Christmas countdown bauble
// Christmas tree bauble countdown timer for ESP8266 with 128x32 OLED display
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include "SSD1306.h"
#include <ArduinoJson.h>
#define API_ENDPOINT "https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/default/baubleblog" // TODO - set this to your API URL
#define API_ENDPOINT_CERT_FINGERPRINT "7b c9 47 ae f4 1e f6 79 f9 b5 40 29 07 61 7b 66 93 17 5b 68" // TODO - set this to your cert fingerprint
#define USE_SERIAL Serial
ESP8266WiFiMulti WiFiMulti;
SSD1306 display(0x3c, SDA, SCL, OLED_RST, GEOMETRY_128_32);
void startWiFi() {
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
// From https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino
int n = WiFi.scanNetworks();
USE_SERIAL.println("scan done");
if (n == 0) {
USE_SERIAL.println("no networks found");
} else {
USE_SERIAL.print(n);
USE_SERIAL.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
USE_SERIAL.print(i + 1);
USE_SERIAL.print(": ");
USE_SERIAL.print(WiFi.SSID(i));
USE_SERIAL.print(" (");
USE_SERIAL.print(WiFi.RSSI(i));
USE_SERIAL.print(")");
USE_SERIAL.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*");
delay(10);
}
}
USE_SERIAL.println("");
delay(1000);
WiFiMulti.addAP("<SSID>", "<PSK>"); // TODO - fill this in
// Wait for WiFi connection
while (WiFiMulti.run() != WL_CONNECTED) {
delay(250);
USE_SERIAL.print('.');
}
USE_SERIAL.println();
USE_SERIAL.print("SSID: ");
USE_SERIAL.println(WiFi.SSID());
USE_SERIAL.print("IP: ");
USE_SERIAL.println(WiFi.localIP());
USE_SERIAL.print("MAC: ");
USE_SERIAL.println(WiFi.macAddress());
}
void setup() {
USE_SERIAL.begin(115200);
// Initialise the OLED display and show the Citrix logo
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_16);
display.display();
delay(1000);
startWiFi();
USE_SERIAL.print("API: ");
USE_SERIAL.println(API_ENDPOINT);
}
// Interval definitions
unsigned long intervalHTTP = 60000;
unsigned long prevHTTP = 0;
unsigned long intervalDisplay = 250;
unsigned long prevDisplay = 0;
// Target for parsing the JSON object fetched from the cloud service
StaticJsonBuffer<200> jsonBuffer;
// The time of the event we're counting down to expressed as
// the seconds equivalent of a call to millis()
unsigned long timerTarget = 0;
// Buffer to hold the event description string
char description[20];
// Buffer to build strings to display
char remainingText[50];
void loop() {
unsigned long currentMillis = millis();
unsigned long currentSecs = currentMillis / 1000;
static boolean wifiConnected = false;
static boolean lastFlip = true;
// Refresh the display event 250ms
if (currentMillis - prevDisplay > intervalDisplay) {
prevDisplay = currentMillis;
// Only update the display if we have a valid event description and target time
display.clear();
if ((strlen(description) > 0) && (timerTarget > 0)) {
// Show a countdown timer and the event description
unsigned long remaining = (timerTarget < currentSecs)?0:(timerTarget - currentSecs);
unsigned long days = remaining/86400;
unsigned long hours = (remaining%86400)/3600;
unsigned long minutes = (remaining%3600)/60;
unsigned long seconds = remaining%60;
sprintf(remainingText, "%u %s %u:%02u", days, (days==1)?"day":"days", hours, minutes);
display.setFont(ArialMT_Plain_16);
display.drawString(0, 0, remainingText);
int16_t x = display.getStringWidth(remainingText);
display.setFont(ArialMT_Plain_10);
sprintf(remainingText, ":%02u", seconds);
display.drawString(x, 3, remainingText);
display.drawString(0, 19, "Until");
int indent = display.getStringWidth("Until ");
display.setFont(ArialMT_Plain_16);
display.drawString(indent, 16, description);
}
display.display();
}
// Refetch the event description and remaining time every minute
if ((currentMillis - prevHTTP > intervalHTTP) || (prevHTTP == 0)) {
wifiConnected = (WiFiMulti.run() == WL_CONNECTED);
if (wifiConnected) {
USE_SERIAL.print("SSID: ");
USE_SERIAL.println(WiFi.SSID());
USE_SERIAL.print("IP: ");
USE_SERIAL.println(WiFi.localIP());
prevHTTP = currentMillis;
HTTPClient http;
// The second argument here is the SSL fingerprint
http.begin(API_ENDPOINT, API_ENDPOINT_CERT_FINGERPRINT);
int httpCode = http.GET();
if (httpCode > 0) {
USE_SERIAL.printf("HTTP GET code: %d\n", httpCode);
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
USE_SERIAL.println(payload);
jsonBuffer.clear();
// Todo - check for buffer overrun for jsonBuffer
JsonObject& root = jsonBuffer.parseObject(payload);
if (!root.success()) {
USE_SERIAL.println("parseObject() failed");
}
else {
if (root.containsKey("description")) {
strncpy(description, root["description"], 19);
// The service returns the number of seconds until the event. Add the number of seconds
// returned by millis() to get our target time. This avaoid us having to know the
// actual time.
timerTarget = root["remaining"].as<unsigned long>() + currentMillis/1000;
display.display();
}
}
}
} else {
USE_SERIAL.printf("HTTP GET failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
}
delay(10);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment