summaryrefslogtreecommitdiff
path: root/src/src.ino
diff options
context:
space:
mode:
Diffstat (limited to 'src/src.ino')
-rw-r--r--src/src.ino222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/src.ino b/src/src.ino
new file mode 100644
index 0000000..fe80680
--- /dev/null
+++ b/src/src.ino
@@ -0,0 +1,222 @@
+// 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--;
+ }
+}