// Pill dispenser // Inspired by article "Blink Without Delay" // https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay // Inspired by basic usage documentation of GEM library // https://github.com/Spirik/GEM #include #include const int longpress_duration = 2000; // time in milliseconds // use built-in buttons and LEDs when possible #if defined(ESP32) // dirty hack: assume that any ESP32 board is a Lilygo T5 V2.2 #define LILYGO_T5_V22 #include "boards.h" // source: https://github.com/lewisxhe/GxEPD/blob/master/src/boards.h #define HAS_DISPLAY const byte BUTTON_PIN_MOVE = BUTTON_1; const byte BUTTON_PIN_SELECT = BUTTON_2; BlinkControl led(LED_PIN); #else const byte BUTTON_PIN_MOVE = 2; const byte BUTTON_PIN_SELECT = 3; BlinkControl led(LED_BUILTIN); // pin 13 is built-in LED on many Arduino boards #endif // serial port speed #define BAUDRATE 115200 EasyButton button_move(BUTTON_PIN_MOVE); EasyButton button_select(BUTTON_PIN_SELECT); #if defined(HAS_DISPLAY) #define ENABLE_GxEPD2_GFX 1 #include #include // source: https://github.com/ZinggJM/GxEPD2/blob/master/examples/GxEPD2_Example/GxEPD2_display_selection.h#L192 GxEPD2_BW displayEPaper(GxEPD2_290(EPD_CS, EPD_DC, EPD_RSET, EPD_BUSY)); #include // Create variables that will be editable through the menu and assign them initial values int number = -512; boolean enablePrint = false; // Create two menu item objects of class GEMItem, linked to number and enablePrint variables GEMItem menuItemInt("Number:", number); GEMItem menuItemBool("Enable print:", enablePrint); // Create menu button that will trigger printData() function. It will print value of our number variable // to Serial monitor if enablePrint is true. We will write (define) this function later. However, we should // forward-declare it in order to pass to GEMItem constructor void printData(); // Forward declaration GEMItem menuItemButton("Print", printData); // Create menu page object of class GEMPage. Menu page holds menu items (GEMItem) and represents menu level. // Menu can have multiple menu pages (linked to each other) with multiple menu items each GEMPage menuPageMain("Main Menu"); GEM_adafruit_gfx menu(displayEPaper, GEM_POINTER_ROW, GEM_ITEMS_COUNT_AUTO); #endif void setup() { Serial.begin(BAUDRATE); while (!Serial) { ; } Serial.println(); button_move.begin(); button_select.begin(); button_move.onPressed(onButtonMovePressed); button_move.onPressedFor(longpress_duration, onButtonMoveLongpressed); button_select.onPressed(onButtonSelectPressed); led.begin(); led.breathe(2000); displayEPaper.init(115200, true, 2, false); displayEPaper.setTextColor(GxEPD_BLACK); displayEPaper.firstPage(); do { displayEPaper.fillScreen(GxEPD_WHITE); // comment out next line to have no or minimal Adafruit_GFX code displayEPaper.print("Hello World!"); } while (displayEPaper.nextPage()); menu.init(); setupMenu(); menu.drawMenu(); } void loop() { led.loop(); button_move.read(); button_select.read(); } #if (ESP32) IRAM_ATTR // avoid crash e.g. when other code reads SD card #endif void onButtonMovePressed() { Serial.println("button MOVE clicked"); led.blink2(); } #if (ESP32) IRAM_ATTR // avoid crash e.g. when other code reads SD card #endif void onButtonMoveLongpressed() { Serial.println("button MOVE long-clicked"); led.off(); } #if (ESP32) IRAM_ATTR // avoid crash e.g. when other code reads SD card #endif void onButtonSelectPressed() { Serial.println("button SELECT clicked"); led.on(); } void setupMenu() { // Add menu items to menu page menuPageMain.addMenuItem(menuItemInt); menuPageMain.addMenuItem(menuItemBool); menuPageMain.addMenuItem(menuItemButton); // Add menu page to menu and set it as current menu.setMenuPageCurrent(menuPageMain); } void printData() { // If enablePrint flag is set to true (checkbox on screen is checked)... if (enablePrint) { // ...print the number to Serial Serial.print("Number is: "); Serial.println(number); } else { Serial.println("Printing is disabled, sorry:("); } }