summaryrefslogtreecommitdiff
path: root/main.ino
blob: 6ce93d2dd1021b55dfa5b5c9f4769f9b2b774eef (plain)
  1. // Pill dispenser
  2. // Inspired by article "Blink Without Delay"
  3. // https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay
  4. // Inspired by basic usage documentation of GEM library
  5. // https://github.com/Spirik/GEM
  6. #include <EasyButton.h>
  7. #include <BlinkControl.h>
  8. const int longpress_duration = 2000; // time in milliseconds
  9. // use built-in buttons and LEDs when possible
  10. #if defined(ESP32)
  11. // dirty hack: assume that any ESP32 board is a Lilygo T5 V2.2
  12. #define LILYGO_T5_V22
  13. #include "boards.h" // source: https://github.com/lewisxhe/GxEPD/blob/master/src/boards.h
  14. #define HAS_DISPLAY
  15. const byte BUTTON_PIN_MOVE = BUTTON_1;
  16. const byte BUTTON_PIN_SELECT = BUTTON_2;
  17. const byte BUTTON_PIN_ACTION = BUTTON_3;
  18. BlinkControl led(LED_PIN);
  19. #define SERVO_PIN 3
  20. #else
  21. const byte BUTTON_PIN_MOVE = 4;
  22. const byte BUTTON_PIN_SELECT = 5;
  23. const byte BUTTON_PIN_ACTION = 2;
  24. BlinkControl led(LED_BUILTIN); // pin 13 is built-in LED on many Arduino boards
  25. #define SERVO_PIN 3
  26. #endif
  27. #define LEDS_PIN 6
  28. #define LEDS_AMOUNT 10
  29. // serial port speed
  30. #define BAUDRATE 115200
  31. EasyButton button_move(BUTTON_PIN_MOVE);
  32. EasyButton button_select(BUTTON_PIN_SELECT);
  33. EasyButton button_action(BUTTON_PIN_ACTION);
  34. #include <FastLED.h>
  35. CRGB leds[LEDS_AMOUNT];
  36. #if defined(HAS_DISPLAY)
  37. #define ENABLE_GxEPD2_GFX 0
  38. #include <GxEPD2_BW.h>
  39. #include <Fonts/FreeMonoBold9pt7b.h>
  40. // source: https://github.com/ZinggJM/GxEPD2/blob/master/examples/GxEPD2_Example/GxEPD2_display_selection.h#L192
  41. GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> displayEPaper(GxEPD2_290(EPD_CS, EPD_DC, EPD_RSET, EPD_BUSY));
  42. // FIXME: really disable GLCD, since it cannot build on ESP32
  43. // as dirty workaround, edit file `libraries/GEM/src/config.h`
  44. #define GEM_DISABLE_GLCD 1
  45. #include <GEM_adafruit_gfx.h>
  46. // Create variables that will be editable through the menu and assign them initial values
  47. int number = -512;
  48. boolean enablePrint = false;
  49. // Create two menu item objects of class GEMItem, linked to number and enablePrint variables
  50. GEMItem menuItemInt("Number:", number);
  51. GEMItem menuItemBool("Enable print:", enablePrint);
  52. // Create menu button that will trigger printData() function. It will print value of our number variable
  53. // to Serial monitor if enablePrint is true. We will write (define) this function later. However, we should
  54. // forward-declare it in order to pass to GEMItem constructor
  55. void printData(); // Forward declaration
  56. GEMItem menuItemButton("Print", printData);
  57. // Create menu page object of class GEMPage. Menu page holds menu items (GEMItem) and represents menu level.
  58. // Menu can have multiple menu pages (linked to each other) with multiple menu items each
  59. GEMPage menuPageMain("Main Menu");
  60. GEM_adafruit_gfx menu(displayEPaper, GEM_POINTER_ROW, GEM_ITEMS_COUNT_AUTO);
  61. #endif
  62. #include <Servo.h>
  63. Servo servo;
  64. int servo_angle = 89;
  65. int servo_angle_delta = 3;
  66. const int servo_angle_min = 0;
  67. const int servo_angle_max = 90;
  68. const int servo_mode = 1;
  69. int servo_should_move = 0;
  70. void setup() {
  71. Serial.begin(BAUDRATE);
  72. while (!Serial) {
  73. ;
  74. }
  75. Serial.println();
  76. button_move.begin();
  77. button_select.begin();
  78. button_action.begin();
  79. button_move.onPressed(onButtonMovePressed);
  80. button_move.onPressedFor(longpress_duration, onButtonMoveLongpressed);
  81. button_select.onPressed(onButtonSelectPressed);
  82. button_action.onPressed(onButtonActionPressed);
  83. led.begin();
  84. led.breathe(2000);
  85. FastLED.addLeds<NEOPIXEL, LEDS_PIN>(leds, LEDS_AMOUNT);
  86. #if defined(HAS_DISPLAY)
  87. displayEPaper.init(115200, true, 2, false);
  88. displayEPaper.setTextColor(GxEPD_BLACK);
  89. displayEPaper.firstPage();
  90. do
  91. {
  92. displayEPaper.fillScreen(GxEPD_WHITE);
  93. // comment out next line to have no or minimal Adafruit_GFX code
  94. displayEPaper.print("Hello World!");
  95. }
  96. while (displayEPaper.nextPage());
  97. menu.init();
  98. setupMenu();
  99. menu.drawMenu();
  100. #endif
  101. servo.attach(SERVO_PIN);
  102. servo.write(servo_angle); // place serve at initial position
  103. }
  104. void loop() {
  105. led.loop();
  106. button_move.read();
  107. button_select.read();
  108. button_action.read();
  109. servoLoop();
  110. }
  111. #if (ESP32)
  112. IRAM_ATTR // avoid crash e.g. when other code reads SD card
  113. #endif
  114. void onButtonMovePressed() {
  115. Serial.println("button MOVE clicked");
  116. led.blink2();
  117. }
  118. #if (ESP32)
  119. IRAM_ATTR // avoid crash e.g. when other code reads SD card
  120. #endif
  121. void onButtonMoveLongpressed() {
  122. Serial.println("button MOVE long-clicked");
  123. led.off();
  124. }
  125. #if (ESP32)
  126. IRAM_ATTR // avoid crash e.g. when other code reads SD card
  127. #endif
  128. void onButtonSelectPressed() {
  129. Serial.println("button SELECT clicked");
  130. led.on();
  131. }
  132. #if (ESP32)
  133. IRAM_ATTR // avoid crash e.g. when other code reads SD card
  134. #endif
  135. void onButtonActionPressed() {
  136. Serial.println("button ACTION clicked");
  137. led.fastBlinking();
  138. servo_should_move = 1;
  139. rolling_green();
  140. }
  141. void rolling_green() {
  142. for (int dot = 0; dot < LEDS_AMOUNT; dot++) {
  143. leds[dot] = CRGB::Green;
  144. FastLED.show();
  145. // clear this LED for the next time around the loop
  146. leds[dot] = CRGB::White;
  147. delay(60);
  148. }
  149. }
  150. #if defined(HAS_DISPLAY)
  151. void setupMenu() {
  152. // Add menu items to menu page
  153. menuPageMain.addMenuItem(menuItemInt);
  154. menuPageMain.addMenuItem(menuItemBool);
  155. menuPageMain.addMenuItem(menuItemButton);
  156. // Add menu page to menu and set it as current
  157. menu.setMenuPageCurrent(menuPageMain);
  158. }
  159. void printData() {
  160. // If enablePrint flag is set to true (checkbox on screen is checked)...
  161. if (enablePrint) {
  162. // ...print the number to Serial
  163. Serial.print("Number is: ");
  164. Serial.println(number);
  165. } else {
  166. Serial.println("Printing is disabled, sorry:(");
  167. }
  168. }
  169. #endif
  170. void servoLoop() {
  171. if (servo_should_move == 1) {
  172. servo_angle = servo_angle + servo_angle_delta;
  173. if (servo_angle >= servo_angle_max) {
  174. servo_angle_delta = -servo_angle_delta;
  175. if (servo_mode == 1) {
  176. servo_should_move = 0;
  177. }
  178. }
  179. if (servo_angle <= servo_angle_min) {
  180. servo_angle_delta = -servo_angle_delta;
  181. if (servo_mode == 2) {
  182. servo_should_move = 0;
  183. }
  184. }
  185. servo.write(servo_angle);
  186. delay(10);
  187. }
  188. }