commit 62d5adbd7613ae77c566af11d38b67cf61482ab2 Author: Ultrablob Date: Mon Jan 20 10:58:40 2025 -0500 initial commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..848d59c Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..504ff5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.pio +.vscode/ +Documents/ +CAD/ \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..930ff05 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.tcc": "cpp" + } +} \ No newline at end of file diff --git a/diagram.json b/diagram.json new file mode 100644 index 0000000..424d280 --- /dev/null +++ b/diagram.json @@ -0,0 +1,51 @@ +{ + "version": 1, + "author": "Anonymous maker", + "editor": "wokwi", + "parts": [ + { "type": "board-esp32-devkit-c-v4", "id": "esp", "top": -38.4, "left": 81.64, "attrs": {} }, + { + "type": "wokwi-pushbutton", + "id": "btn1", + "top": 6.2, + "left": -115.2, + "attrs": { "color": "red" } + }, + { + "type": "wokwi-pushbutton", + "id": "btn2", + "top": 54.2, + "left": -115.2, + "attrs": { "color": "yellow" } + }, + { + "type": "wokwi-pushbutton", + "id": "btn3", + "top": 102.2, + "left": -115.2, + "attrs": { "color": "green" } + }, + { + "type": "wokwi-lcd2004", + "id": "lcd1", + "top": -281.6, + "left": 53.6, + "attrs": { "pins": "i2c" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "btn2:2.r", "esp:27", "gold", [ "h0" ] ], + [ "btn1:2.r", "esp:CMD", "black", [ "h9.8", "v0.2" ] ], + [ "esp:CMD", "btn2:1.r", "black", [ "h-124.65", "v-86.4" ] ], + [ "btn3:1.r", "esp:CMD", "black", [ "v0", "h9.8", "v38.4" ] ], + [ "btn3:2.r", "esp:14", "green", [ "h67.4", "v0.2" ] ], + [ "btn1:1.r", "esp:26", "#8f4814", [ "v0", "h19.4", "v57.6" ] ], + [ "lcd1:GND", "esp:CMD", "black", [ "h-48", "v403.2", "h-28.8" ] ], + [ "lcd1:VCC", "esp:3V3", "red", [ "h-38.4", "v0.1" ] ], + [ "lcd1:SDA", "esp:21", "green", [ "h-28.8", "v173", "h172.8", "v48" ] ], + [ "lcd1:SCL", "esp:22", "green", [ "h-19.2", "v153.9", "h172.8", "v67.2" ] ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/display.ino b/display.ino new file mode 100644 index 0000000..9ecb20e --- /dev/null +++ b/display.ino @@ -0,0 +1,67 @@ +// GxEPD2_HelloWorld.ino by Jean-Marc Zingg +// +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: https://www.good-display.com/companyfile/32/ +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +// Supporting Arduino Forum Topics (closed, read only): +// Good Display ePaper for Arduino: https://forum.arduino.cc/t/good-display-epaper-for-arduino/419657 +// Waveshare e-paper displays with SPI: https://forum.arduino.cc/t/waveshare-e-paper-displays-with-spi/467865 +// +// Add new topics in https://forum.arduino.cc/c/using-arduino/displays/23 for new questions and issues + +// see GxEPD2_wiring_examples.h for wiring suggestions and examples +// if you use a different wiring, you need to adapt the constructor parameters! + +// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX +//#include + +#include +#include + +// alternately you can copy the constructor from GxEPD2_display_selection.h or GxEPD2_display_selection_added.h to here +// e.g. for Wemos D1 mini: +GxEPD2_BW display(GxEPD2_750_T7(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); + +// for handling alternative SPI pins (ESP32, RP2040) see example GxEPD2_Example.ino +char HelloWorld[] = "Hello World!"; + +void setup() +{ + delay(1000); + //display.init(115200); // default 10ms reset pulse, e.g. for bare panels with DESPI-C02 + display.init(115200, true, 2, false); // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse + updateMessage(HelloWorld); + display.hibernate(); +} + + +void updateMessage(char text[]) +{ + display.setRotation(0); + display.setFont(&FreeMonoBold24pt7b); + display.setTextColor(GxEPD_BLACK); + int16_t tbx, tby; uint16_t tbw, tbh; + display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); + // center the bounding box by transposition of the origin: + uint16_t x = ((display.width() - tbw) / 2) - tbx; + uint16_t y = ((display.height() - tbh) / 2) - tby; + display.setFullWindow(); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.print(text); + } + while (display.nextPage()); +} + +void loop() {}; \ No newline at end of file diff --git a/libraries.txt b/libraries.txt new file mode 100644 index 0000000..f3422db --- /dev/null +++ b/libraries.txt @@ -0,0 +1,4 @@ +# Wokwi Library List +# See https://docs.wokwi.com/guides/libraries + +LiquidCrystal I2C diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..f458a7d --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32] +platform = espressif32 +framework = arduino +board = esp32dev +lib_deps = + zinggjm/GxEPD2 + ; marcoschwartz/LiquidCrystal_I2C@^1.1.4 + ncmreynolds/wordwrap + blynkkk/Blynk \ No newline at end of file diff --git a/sketch.backup b/sketch.backup new file mode 100644 index 0000000..53c0707 --- /dev/null +++ b/sketch.backup @@ -0,0 +1,232 @@ +#define BLYNK_PRINT Serial +#define BLYNK_TEMPLATE_ID "TMPL2TbG1EPUc" +#define BLYNK_TEMPLATE_NAME "Feedback Machine" +#define BLYNK_AUTH_TOKEN "X0ZcPLZjfDvRN1SsEFzvfGG91iKy4mlQ" + +#include +#include + +#include +#include "Wire.h" + +#define GOOD 14 +#define OK 27 +#define BAD 26 + +LiquidCrystal_I2C lcd(0x27, 20, 4); + +#define SSID "Wokwi-GUEST" +#define PASSWORD "" + +String question = "Generic Question"; + +int positiveFeedback = 0; +int negativeFeedback = 0; + +bool blynkConnected = false; + +Preferences preferences; + + +void setup() { + + pinMode(BAD, INPUT_PULLUP); + pinMode(OK, INPUT_PULLUP); + pinMode(GOOD, INPUT_PULLUP); + + Serial.begin(115200); + + preferences.begin("feedback", false); + + lcd.init(); + + + lcd.print("Connecting to WIFI"); + + Blynk.begin(BLYNK_AUTH_TOKEN, SSID, PASSWORD); + + + while (!blynkConnected) { + delay(100); + } + + lcd.setCursor(0,0); + lcd.print("Initializing Data "); + + preferences.putInt("bad", 0); + preferences.putInt("ok", 0); + preferences.putInt("good", 0); + +} + +void loop() { + //wait for a second + while (true) { + delay(10); + if (digitalRead(GOOD) == LOW) { + preferences.putInt("good", preferences.getInt("good") + 1); + Blynk.virtualWrite(V0, preferences.getInt("good")); + break; + } else if (digitalRead(OK) == LOW) { + preferences.putInt("ok", preferences.getInt("ok") + 1); + Blynk.virtualWrite(V1, preferences.getInt("ok")); + break; + } else if (digitalRead(BAD) == LOW) { + preferences.putInt("bad", preferences.getInt("bad") + 1); + Blynk.virtualWrite(V2, preferences.getInt("bad")); //! fix this duplication later + break; + } + Blynk.run(); + } + // tell the screen to write on the top row + lcd.setCursor(0,3); + lcd.print("Feedback sent!"); + delay(1000); + lcd.setCursor(0,3); + lcd.print(" "); +} + +BLYNK_CONNECTED() +{ + blynkConnected = true; + Blynk.syncVirtual(V10); +} + +BLYNK_WRITE(V10) { + lcd.clear(); + String newQuestion = param.asString(); + + if (newQuestion.length() > 20) { + lcd.print(newQuestion.substring(0, 20)); + lcd.setCursor(0,1); + lcd.print(newQuestion.substring(20)); + } else { + lcd.println(newQuestion); + } + + if (!blynkConnected) { + return; + } + preferences.putInt("bad", 0); + preferences.putInt("ok", 0); + preferences.putInt("good", 0); + Blynk.virtualWrite(V0, 0); + Blynk.virtualWrite(V1, 0); + Blynk.virtualWrite(V2, 0); +} + +#define BLYNK_TEMPLATE_ID "TMPL2TbG1EPUc" +#define BLYNK_TEMPLATE_NAME "Feedback Machine" +#define BLYNK_AUTH_TOKEN "X0ZcPLZjfDvRN1SsEFzvfGG91iKy4mlQ" + +#include +#include +#include + +#include +#include "Wire.h" + +#define GOOD 14 +#define OK 27 +#define BAD 26 + +GxEPD2_BW display(GxEPD2_750_T7(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); + +#define SSID "Wokwi-GUEST" +#define PASSWORD "" + +String question = "Generic Question"; + +int positiveFeedback = 0; +int negativeFeedback = 0; + +bool blynkConnected = false; + +Preferences preferences; + + +void setup() { + + pinMode(BAD, INPUT_PULLUP); + pinMode(OK, INPUT_PULLUP); + pinMode(GOOD, INPUT_PULLUP); + + Serial.begin(115200); + + preferences.begin("feedback", false); + + display.init(115200, true, 2, false); // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse + + updateMessage("Initializing..."); + + Blynk.begin(BLYNK_AUTH_TOKEN, SSID, PASSWORD); + + preferences.putInt("bad", 0); + preferences.putInt("ok", 0); + preferences.putInt("good", 0); + +} + +void loop() { + //wait for a second + while (true) { + delay(10); + if (digitalRead(GOOD) == LOW) { + preferences.putInt("good", preferences.getInt("good") + 1); + Blynk.virtualWrite(V0, preferences.getInt("good")); + break; + } else if (digitalRead(OK) == LOW) { + preferences.putInt("ok", preferences.getInt("ok") + 1); + Blynk.virtualWrite(V1, preferences.getInt("ok")); + break; + } else if (digitalRead(BAD) == LOW) { + preferences.putInt("bad", preferences.getInt("bad") + 1); + Blynk.virtualWrite(V2, preferences.getInt("bad")); //! fix this duplication later + break; + } + Blynk.run(); + } + delay(1000); +} + +void updateMessage(const char text[]) +{ + display.setRotation(0); + display.setFont(&FreeMonoBold24pt7b); + display.setTextColor(GxEPD_BLACK); + int16_t tbx, tby; uint16_t tbw, tbh; + display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); + // center the bounding box by transposition of the origin: + uint16_t x = ((display.width() - tbw) / 2) - tbx; + uint16_t y = ((display.height() - tbh) / 2) - tby; + display.setFullWindow(); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.print(text); + } + while (display.nextPage()); +} + +BLYNK_CONNECTED() +{ + blynkConnected = true; + Blynk.syncVirtual(V10); +} + +BLYNK_WRITE(V10) { + updateMessage(param.asStr()); + display.hibernate(); + + if (!blynkConnected) { + return; + } + preferences.putInt("bad", 0); + preferences.putInt("ok", 0); + preferences.putInt("good", 0); + Blynk.virtualWrite(V0, 0); + Blynk.virtualWrite(V1, 0); + Blynk.virtualWrite(V2, 0); +} \ No newline at end of file diff --git a/src/sketch.ino b/src/sketch.ino new file mode 100644 index 0000000..88823a4 --- /dev/null +++ b/src/sketch.ino @@ -0,0 +1,211 @@ +#define BLYNK_TEMPLATE_ID "TMPL2TbG1EPUc" +#define BLYNK_TEMPLATE_NAME "Feedback Machine" +#define BLYNK_AUTH_TOKEN "X0ZcPLZjfDvRN1SsEFzvfGG91iKy4mlQ" + +#include +#include +#include +#include + +#include +#include "Wire.h" + +#include + +#define GOOD 13 +#define OK 12 +#define BAD 14 + +GxEPD2_BW display(GxEPD2_750_T7(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); + +#define SSID "IHDSB.CA" +#define PASSWORD "HDSBsecure" + +String question = "Generic Question"; + +bool blynkConnected = false; +bool disabled = false; + +Preferences preferences; + + +void setup() { + + pinMode(BAD, INPUT_PULLUP); + pinMode(OK, INPUT_PULLUP); + pinMode(GOOD, INPUT_PULLUP); + + preferences.begin("feedback", false); + + wordwrap.crlf = false; + + display.init(115200, true, 2, false); // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse + + updateMessage("Connecting to WiFi..."); + + Blynk.begin(BLYNK_AUTH_TOKEN, SSID, PASSWORD); + + + int retries = 0; + + while (!Blynk.connected()) { + delay(100); + retries++; + + if (retries == 600) { + updateSubtitle("Error 23"); + } + } + + if (retries >= 600) { + clearSubtitle(); + } + + // preferences.putInt("bad", 0); + // preferences.putInt("ok", 0); + // preferences.putInt("good", 0); + + delay(2000); +} + +void loop() { + //wait for a second + while (true) { + delay(10); + + if (disabled) { + continue; + } + + if (digitalRead(GOOD) == LOW) { + preferences.putInt("good", preferences.getInt("good") + 1); + Blynk.virtualWrite(V0, preferences.getInt("good")); + break; + } else if (digitalRead(OK) == LOW) { + preferences.putInt("ok", preferences.getInt("ok") + 1); + Blynk.virtualWrite(V1, preferences.getInt("ok")); + break; + } else if (digitalRead(BAD) == LOW) { + preferences.putInt("bad", preferences.getInt("bad") + 1); + Blynk.virtualWrite(V2, preferences.getInt("bad")); //! fix this duplication later + break; + } + Blynk.run(); + } + + updateSubtitle("Thank you for your feedback!"); + delay(1000); + clearSubtitle(); + +} + +void updateSubtitle(const char message[]) { + display.setPartialWindow(0, 440, display.width(), 40); + display.firstPage(); + + int16_t tbx, tby; + uint16_t tbw, tbh; + display.getTextBounds(message, 0, 0, &tbx, &tby, &tbw, &tbh); + + + + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(((display.width() - tbw) / 2) - tbx, 460); + display.setFont(&FreeMonoBold12pt7b); + display.print(message); + + } while (display.nextPage()); + +} + +void clearSubtitle() +{ + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + } while (display.nextPage()); +} + +void updateMessage(const char text[]) +{ + // Define the maximum number of characters per line + const int maxLineLength = 25; + char wrappedText[128]; // Adjust size as needed + + wordwrap.wrap(text, maxLineLength).toCharArray(wrappedText, 128); + + display.setRotation(0); + display.setFont(&FreeMonoBold24pt7b); + display.setTextColor(GxEPD_BLACK); + + // Calculate the bounding box for the entire wrapped text + int16_t tbx, tby; + uint16_t tbw, tbh; + display.getTextBounds(wrappedText, 0, 0, &tbx, &tby, &tbw, &tbh); + + // Calculate the x-coordinate to center the text + uint16_t x = ((display.width() - tbw) / 2) - tbx; + + // Calculate the y-coordinate for the first line + uint16_t y = ((display.height() - tbh) / 2) - tby; + + display.setFullWindow(); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + + // Print each line separately + char *line = strtok(wrappedText, "\n"); + uint16_t lineHeight = 40; // Adjust this value based on your font size + + while (line != NULL) + { + display.setCursor(x, y); + display.print(line); + y += lineHeight; // Move y-coordinate down for the next line + line = strtok(NULL, "\n"); + } + } + while (display.nextPage()); +} + +BLYNK_CONNECTED() +{ + Blynk.syncVirtual(V10); +} + +BLYNK_WRITE(V10) { + + if (strlen(param.asStr()) > 100) { + updateSubtitle("Error 31"); + return; + } + + updateMessage(param.asStr()); + + preferences.putInt("bad", 0); + preferences.putInt("ok", 0); + preferences.putInt("good", 0); + Blynk.virtualWrite(V0, 0); + Blynk.virtualWrite(V1, 0); + Blynk.virtualWrite(V2, 0); +} + +BLYNK_WRITE(V9) { + + if (param.asInt() == 0) { + disabled = false; + clearSubtitle(); + } + + if (param.asInt() == 1) { + disabled = true; + updateMessage("Out of Order"); + updateSubtitle("Error 42"); + } + +} \ No newline at end of file diff --git a/wokwi.toml b/wokwi.toml new file mode 100644 index 0000000..f74185d --- /dev/null +++ b/wokwi.toml @@ -0,0 +1,4 @@ +[wokwi] +version = 1 +elf = ".pio/build/esp32/firmware.elf" +firmware = ".pio/build/esp32/firmware.bin" \ No newline at end of file