From e37f1c777a9416c15527656e6c0eae452553b921 Mon Sep 17 00:00:00 2001 From: Neale Pickett Date: Sat, 19 Oct 2019 22:41:01 -0600 Subject: [PATCH] First working version --- Makefile | 7 + badge.ino | 422 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 429 insertions(+) create mode 100644 Makefile create mode 100644 badge.ino diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f3f34e0 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +BOARD = --board esp8266:esp8266:nodemcuv2 + +verify: hello.ino + arduino --verify $(BOARD) $< + +install: hello.ino + arduino --upload $(BOARD) $< diff --git a/badge.ino b/badge.ino new file mode 100644 index 0000000..5610ea2 --- /dev/null +++ b/badge.ino @@ -0,0 +1,422 @@ +/* e-paper display lib */ +#include +//Use the GxGDEW029T5 class if you have Badgy Rev 2C. Make sure you are on GxEPD 3.05 or above +#include +#include +#include + +#include +#include +#include + +/* WiFi libs*/ +#include +#include +#include +#include +#include +#include + +#define len(a) (sizeof(a) / sizeof(*a)) + +char *badges[][4] = { + { + "Neale", "Pickett", + "Los Alamos National Laboratory", + "Cyber Fire Lead", + }, + { + "Neale", "Pickett", + "Cybersecurity Educator", + "Los Alamos National Laboratory", + }, + { + "Neale", "Pickett", + "", + "", + }, + NULL +}; + +int badgeno = 0; + + +struct Room { + char *title; + char *description; + int north, west, east, south; +}; + +struct Room rooms[] = { + { + // 0 + "West of House", + ( + "You are standing in an open field west of a\n" + "white house, with a boarded front door." + ), + 1, -1, -1, 2, + }, + { + // 1 + "North of House", + ( + "You are facing the north side of a white house.\n" + "There is no door here, and all the windows are\n" + "boarded up. To the north a narrow path winds\n" + "through the trees." + ), + 6, 0, 3, -1, + }, + { + // 2 + "South of House", + ( + "You are facing the south side of a white house.\n" + "There is no door here, and all the windows are\n" + "boarded." + ), + -1, 0, 3, 8, + }, + { + // 3 + "Behind House", + ( + "You are behind the white house. A path leads\n" + "into the forest to the east. In one corner of\n" + "the house there is a small window which is open." + ), + 1, 4, 7, 2, + }, + { + // 4 + "Kitchen", + ( + "You are in the kitchen of the white house. A\n" + "table seems to have been used recently for the\n" + "preparation of food. A passage leads to the\n" + "west and a dark staircase can be seen leading\n" + "upward. A dark chimney leads down and to the\n" + "east is a small window which is open." + ), + 14, 5, 3, -1, + }, + { + // 5 + "Living Room", + ( + "You are in the living room. There is a doorway\n" + "to the east, a wooden door with strange gothic\n" + "lettering to the west, which appears to be nailed\n" + "shut, a trophy case, and a large oriental rug in\n" + "the center of the room.\n" + "\n" + "Above the trophy case hangs an elvish sword of\n" + "great antiquity.\n" + "\n" + "A battery-powered brass lantern is on the trophy\n" + "case." + ), + -1, -1, 4, -1, + }, + { + // 6 + "Forest Path", + ( + "This is a path winding through a dimly lit\n" + "forest. The path heads north-south here. One\n" + "particularly large tree with some low branches\n" + "stands at the edge of the path." + ), + 7, 8, 9, 1, + }, + { + // 7 + "Clearing", + ( + "You are in a clearing, with a forest\n" + "surrounding you on all sides. A path leads\n" + "south." + ), + -1, 8, 9, 6, + }, + { + // 8 + "Forest", // West + ( + "This is a forest, with trees in all directions.\n" + "To the east, there appears to be sunlight." + ), + 7, -1, 6, 10, + }, + { + // 9 + "Forest", // East + ( + "This is a dimly lit forest, with large trees\n" + "all around." + ), + 7, 6, 11, 12, + }, + { + // 10 + "Forest", // South + ( + "This is a dimly lit forest, with large trees\n" + "all around." + ), + 12, 8, 13, -1, + }, + { + // 11 + "Forest", // Far East + ( + "The forest thins out, revealing impassable\n" + "mountains." + ), + 9, 9, -1, 9, + }, + { + // 12 + "Clearing", // West + ( + "You are in a small clearing in a well marked\n" + "forest path that extends to the east and west." + ), + 9, 3, 13, 10, + }, + { + // 13 + "Canyon View", + ( + "You are at the top of the Great Canyon on its\n" + "west wall. From here there is a marvelous view\n" + "of the canyon and parts of the Frigid River\n" + "upstream. Across the canyon, the walls of the\n" + "White Cliffs join the mighty ramparts of the\n" + "Flathead Mountains to the east. Following the\n" + "Canyon upstream to the north, Aragain Falls may\n" + "be seen, complete with rainbow. The mighty Frigid\n" + "River flows out from a great dark cavern. To the\n" + "west and south can be seen an immense forest,\n" + "stretching for miles around. A path leads north." + ), + 12, 10, -1, -1, + }, + { + // 14 + "Dark Place", + ( + "It is pitch black. You are likely to be eaten\n" + "by a grue." + ), + -1, -1, -1, 4, + }, + { + // 15 + "Neale Pickett", + ( + "YOU ARE LIKELY TO BE\n" + "EATEN BY A GRUE\n" + "\n" + "IF THIS PREDICAMENT SEEMS PARTICULARLY\n" + "CRUEL..\n" + "\n" + "CONSIDER WHOSE FAULT IT COULD BE..\n" + "NOT A TORCH OR A MATCH\n" + "IN YOUR INVENTORY....\n" + "\n" + "]" + ), + 0, 0, 0, 0, + }, +}; + +const int start = 15; +int where = start; + + +/* Always include the update server, or else you won't be able to do OTA updates! */ +/**/const int port = 8888; +/**/ESP8266WebServer httpServer(port); +/**/ESP8266HTTPUpdateServer httpUpdater; +/* */ + +/* Configure pins for display */ +GxIO_Class io(SPI, SS, 0, 2); +GxEPD_Class display(io); // default selection of D4, D2 + +/* A single byte is used to store the button states for debouncing */ +byte buttonState = 0; +byte lastButtonState = 0; //the previous reading from the input pin +unsigned long lastDebounceTime = 0; //the last time the output pin was toggled +unsigned long debounceDelay = 50; //the debounce time + +void setup() +{ + display.init(); + + pinMode(1,INPUT_PULLUP); //down + pinMode(3,INPUT_PULLUP); //left + pinMode(5,INPUT_PULLUP); //center + pinMode(12,INPUT_PULLUP); //right + pinMode(10,INPUT_PULLUP); //up + + /* Enter OTA mode if the center button is pressed */ + if(digitalRead(5) == 0){ + /* WiFi Manager automatically connects using the saved credentials, if that fails it will go into AP mode */ + WiFiManager wifiManager; + wifiManager.setAPCallback(configModeCallback); + wifiManager.autoConnect("Badgy AP"); + /* Once connected to WiFi, startup the OTA update server if the center button is held on boot */ + httpUpdater.setup(&httpServer); + httpServer.begin(); + showIP(); + while(1){ + httpServer.handleClient(); + } + } + showBadge(); //show "Hello my name is" immediately on boot +} + +void loop() +{ + byte reading = (digitalRead(1) == 0 ? 0 : (1<<0)) | //down + (digitalRead(3) == 0 ? 0 : (1<<1)) | //left + (digitalRead(5) == 0 ? 0 : (1<<2)) | //center + (digitalRead(12) == 0 ? 0 : (1<<3)) | //right + (digitalRead(10) == 0 ? 0 : (1<<4)); //up + + if(reading != lastButtonState){ + lastDebounceTime = millis(); + } + if ((millis() - lastDebounceTime) > debounceDelay) { + if (reading != buttonState) { + buttonState = reading; + int next = -1; + + for (int i = 0; i < 5; i++) { + if (bitRead(buttonState, i) == 0) { + switch(i){ + case 0: // down + next = rooms[where].south; + break; + case 1: // left + next = rooms[where].west; + break; + case 2: // center + if (where == 14) { + // Easter egg! + next = start; + } else { + // Cycle through badges + badgeno += 1; + if (badges[badgeno][0] == NULL) { + badgeno = 0; + } + showBadge(); + where = start; + next = -1; + } + break; + case 3: // right + next = rooms[where].east; + break; + case 4: // up + next = rooms[where].north; + break; + default: + break; + } + } + } + + if (next > -1) { + where = next; + showRoom(); + } + } + } + lastButtonState = reading; +} + +void configModeCallback (WiFiManager *myWiFiManager){ + display.setRotation(3); //even = portrait, odd = landscape + display.fillScreen(GxEPD_WHITE); + display.setTextColor(GxEPD_BLACK); + display.setFont(&FreeSans9pt7b); + display.setCursor(0, 50); + display.println("Connect to Badgy AP"); + display.println("to setup your WiFi!"); + display.update(); +} + +void showText(char *text) { + display.setRotation(3); //even = portrait, odd = landscape + display.fillScreen(GxEPD_WHITE); + display.setTextColor(GxEPD_BLACK); + display.setFont(&FreeSans9pt7b); + display.setCursor(10, 70); + display.println(text); + display.update(); +} + +void showRoom() { + display.setRotation(3); + display.fillScreen(GxEPD_WHITE); + + display.fillRect(0, 0, display.width(), 20, GxEPD_BLACK); + display.setTextColor(GxEPD_WHITE); + display.setFont(&FreeSans9pt7b); + display.setCursor(20, 15); + display.println(rooms[where].title); + + display.setTextColor(GxEPD_BLACK); + display.setFont(); + display.setCursor(0, 30); + display.println(rooms[where].description); + display.update(); +} + +void showIP() { + display.setRotation(3); //even = portrait, odd = landscape + display.fillScreen(GxEPD_WHITE); + display.setTextColor(GxEPD_BLACK); + display.setFont(&FreeSans9pt7b); + display.setCursor(0, 10); + + String url = WiFi.localIP().toString() + ":"+String(port)+"/update"; + byte charArraySize = url.length() + 1; + char urlCharArray[charArraySize]; + url.toCharArray(urlCharArray, charArraySize); + + display.println("You are now connected!"); + display.println(""); + display.println("Go to:"); + display.println(urlCharArray); + display.println("to upload a new sketch."); + display.update(); +} + +void showBadge() +{ + display.setRotation(3); //even = portrait, odd = landscape + display.fillScreen(GxEPD_WHITE); + + display.setTextColor(GxEPD_BLACK); + + display.setFont(&FreeSansBold24pt7b); + display.setCursor(30, 35); + display.println(badges[badgeno][0]); + + display.setFont(&FreeSansBold12pt7b); + display.setCursor(30, 65); + display.println(badges[badgeno][1]); + + display.setFont(&FreeSans9pt7b); + display.setCursor(0, 100); + display.println(badges[badgeno][2]); + display.println(badges[badgeno][3]); + + display.update(); +}