- // Pill dispenser
- // Requires libraries EasyButton, BlinkControl, FastLED, ServoEasing
- // Optionally requires libraries GxEPD2, GEM
- #include <EasyButton.h>
- #include <BlinkControl.h>
- 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;
- const byte BUTTON_PIN_ACTION = BUTTON_3;
- BlinkControl led(LED_PIN);
- #define LEDS_PIN 12
- #define SERVO_PIN 5 // see ServoEasing PinDefinitionsAndMore.h
- #else
- const byte BUTTON_PIN_MOVE = 4;
- const byte BUTTON_PIN_SELECT = 5;
- const byte BUTTON_PIN_ACTION = 2;
- BlinkControl led(LED_BUILTIN); // pin 13 is built-in LED on many Arduino boards
- #define LEDS_PIN 6
- #define SERVO_PIN 9 // see ServoEasing PinDefinitionsAndMore.h
- #endif
- #define LEDS_AMOUNT 10
- // serial port speed
- #define BAUDRATE 115200
- EasyButton button_move(BUTTON_PIN_MOVE);
- EasyButton button_select(BUTTON_PIN_SELECT);
- EasyButton button_action(BUTTON_PIN_ACTION);
- #include <FastLED.h>
- CRGB leds[LEDS_AMOUNT];
- #if defined(HAS_DISPLAY)
- #define ENABLE_GxEPD2_GFX 0
- #include <GxEPD2_BW.h>
- #include <Fonts/FreeMonoBold9pt7b.h>
- // source: https://github.com/ZinggJM/GxEPD2/blob/master/examples/GxEPD2_Example/GxEPD2_display_selection.h#L192
- GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> displayEPaper(GxEPD2_290(EPD_CS, EPD_DC, EPD_RSET, EPD_BUSY));
- // FIXME: really disable GLCD, since it cannot build on ESP32
- // as dirty workaround, edit file `libraries/GEM/src/config.h`
- #define GEM_DISABLE_GLCD 1
- #include <GEM_adafruit_gfx.h>
- // 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
- #define MAX_EASING_SERVOS 1
- #include "ServoEasing.hpp"
- ServoEasing servo;
- #define SERVO_POS_INIT 60
- #define SERVO_POS_MAX 100
- volatile int pills_requested = 0;
- void setup() {
- Serial.begin(BAUDRATE);
- while (!Serial) {
- ;
- }
- Serial.println();
- button_move.begin();
- button_select.begin();
- button_action.begin();
- button_move.onPressed(onButtonMovePressed);
- button_move.onPressedFor(longpress_duration, onButtonMoveLongpressed);
- button_select.onPressed(onButtonSelectPressed);
- button_action.onPressed(onButtonActionPressed);
- led.begin();
- led.breathe(2000);
- FastLED.addLeds<NEOPIXEL, LEDS_PIN>(leds, LEDS_AMOUNT);
- #if defined(HAS_DISPLAY)
- 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();
- #endif
- Serial.println(F("Attach servo at pin " STR(SERVO_PIN)));
- if (servo.attach(SERVO_PIN, SERVO_POS_INIT) == INVALID_SERVO) {
- led.blink2();
- Serial.println(F("Error attaching servo"));
- }
- // Wait for servo to reach start position.
- delay(500);
- servo.setSpeed(90); // This speed is taken if no further speed argument is given.
- }
- void loop() {
- led.loop();
- button_move.read();
- button_select.read();
- button_action.read();
- servoLoop();
- }
- #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();
- }
- #if (ESP32)
- IRAM_ATTR // avoid crash e.g. when other code reads SD card
- #endif
- void onButtonActionPressed() {
- Serial.println("button ACTION clicked");
- led.fastBlinking();
- pills_requested++;
- rolling_green();
- }
- void rolling_green() {
- for (int dot = 0; dot < LEDS_AMOUNT; dot++) {
- leds[dot] = CRGB::Green;
- FastLED.show();
- // clear this LED for the next time around the loop
- leds[dot] = CRGB::White;
- delay(60);
- }
- }
- #if defined(HAS_DISPLAY)
- 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:(");
- }
- }
- #endif
- // source: https://robojax.com/learn/arduino/?vid=robojax_Servo_PB1_move_return
- void servoLoop() {
- if (pills_requested > 1) {
- servo.easeTo(SERVO_POS_MAX);
- delay(500);
- servo.easeTo(SERVO_POS_INIT);
- pills_requested--;
- }
- }
|