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