aboutsummaryrefslogtreecommitdiff
path: root/sensor/sensor.ino
blob: f144ef4059d8a8137fb1df790aec28814327f4fb (plain)
  1. // SPDX-FileCopyrightText: 2025 Amal Mazrah <mazrah@ruc.dk>
  2. // SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
  3. // SPDX-FileCopyrightText: 2025 Mennatullah Hatim Kassim <stud-mennatulla@ruc.dk>
  4. // SPDX-FileCopyrightText: 2025 Noor Ahmad <noora@ruc.dk>
  5. // SPDX-FileCopyrightText: 2025 Tanishka Suwalka <tanishkas@ruc.dk>
  6. // SPDX-License-Identifier: GPL-3.0-or-later
  7. /// Sensor mussel - an Arduino sketch to emulate a mussel biosensor
  8. ///
  9. /// * v0.0.3
  10. /// * rewrite sensor as sketch,
  11. /// using ESP32 LEDC, Touch sensor and Logging library
  12. ///
  13. /// * v0.0.2
  14. /// * rewrite attitude #2 to also handle button press
  15. /// * add voting functions and example
  16. ///
  17. /// * v0.0.1
  18. /// * initial release to radicle
  19. ///
  20. /// @version 0.0.3
  21. /// @see <https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z2tFBF4gN7ziG9oXtUytVQNYe3VhQ/tree/Mussel/README.md>
  22. /// @see <https://moodle.ruc.dk/course/view.php?id=23504>
  23. // arduino-esp32 Logging system
  24. // activate in Arduino IDE: Tools -> Core Debug Level
  25. // tip: set log level to Error for plot-friendly output
  26. #define CONFIG_ARDUHAL_ESP_LOG 1
  27. #define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
  28. #include <esp32-hal-log.h>
  29. #undef ARDUHAL_LOG_FORMAT
  30. #define ARDUHAL_LOG_FORMAT(letter, format) \
  31. ARDUHAL_LOG_COLOR_##letter "[" #letter "] %s(): " format \
  32. ARDUHAL_LOG_RESET_COLOR "\r\n", __FUNCTION__
  33. // arduino-esp32 Bluetooth Low Energy (BLE) networking stack
  34. #include "BLEDevice.h"
  35. #include "BLEBeacon.h"
  36. #include "BLEAdvertising.h"
  37. #include "BLEEddystoneTLM.h"
  38. // Adjust these for production use
  39. //
  40. // * BEACON_NAME must be unique within deployment
  41. // * BEACON_UUID should be unique for each deployment
  42. //
  43. // @see https://www.uuidgenerator.net/
  44. #define BEACON_NAME "Dummy mussel sensor"
  45. #define BEACON_UUID "00000000-0000-0000-0000-000000000000"
  46. // maximum accumulated stress
  47. #define STRESS_MAX 50
  48. // arduino-esp32 Touch sensor
  49. #define TOUCH_PIN T0 // T0 is GPIO4
  50. #define TOUCH_THRESHOLD 40
  51. // arduino-esp32 LED PWM Controller (LEDC) as pacemaker for gaping rhythm
  52. #define LED_PIN LED_BUILTIN
  53. #define LEDC_BITS 7
  54. #define LEDC_FREQ 500
  55. #define LEDC_START_DUTY 0
  56. #define LEDC_TARGET_DUTY 90
  57. #define LEDC_CALM_PACE 3000
  58. #define LEDC_STRESSED_PACE 400
  59. // pacemaker variables
  60. int stress = 0;
  61. bool touch_detected = false;
  62. int pace = LEDC_STRESSED_PACE;
  63. bool fade_ended = false;
  64. bool fade_in = true;
  65. // pointer to control Bluetooth networking
  66. BLEAdvertising *pAdvertising;
  67. // Touch sensor callback
  68. void gotTouch() {
  69. // keepPace();
  70. touch_detected = true;
  71. pace = LEDC_STRESSED_PACE;
  72. }
  73. // pacemaker end-of-fade Interrupt Service Routine (ISR) a.k.a. callback
  74. void ARDUINO_ISR_ATTR LED_FADE_ISR() {
  75. fade_ended = true;
  76. keepPace();
  77. }
  78. // stress-inducing touch callback
  79. void beginTouchDetection() {
  80. touchAttachInterrupt(TOUCH_PIN, gotTouch, TOUCH_THRESHOLD);
  81. log_d("touch detected");
  82. }
  83. // pacemaker initialization
  84. void beginPace() {
  85. // Setup pacemaker timer
  86. ledcAttach(LED_PIN, LEDC_FREQ, LEDC_BITS);
  87. // fade in once uncontrolled and then begin fade out with ISR
  88. ledcFade(LED_PIN, LEDC_START_DUTY, LEDC_TARGET_DUTY, pace);
  89. delay(pace);
  90. ledcFadeWithInterrupt(LED_PIN, LEDC_TARGET_DUTY, LEDC_START_DUTY,
  91. pace, LED_FADE_ISR);
  92. }
  93. // pacemaker maintenance
  94. void keepPace() {
  95. // if (fade_ended || touch_detected) {
  96. if (fade_ended) {
  97. fade_ended = false;
  98. // stress management
  99. if (touch_detected) {
  100. touch_detected = false;
  101. log_i("Stressed by touch!");
  102. if (stress < STRESS_MAX) {
  103. stress = stress + 10;
  104. }
  105. } else if (stress > 0) {
  106. stress--;
  107. if (stress <= 0) {
  108. pace = LEDC_CALM_PACE;
  109. log_i("Calmed down...");
  110. } else {
  111. log_i("Still stressed...");
  112. }
  113. } else {
  114. pace = LEDC_CALM_PACE;
  115. }
  116. // begin fade at decided direction and pace
  117. ledcFadeWithInterrupt(LED_PIN,
  118. fade_in ? LEDC_START_DUTY : LEDC_TARGET_DUTY,
  119. fade_in ? LEDC_TARGET_DUTY : LEDC_START_DUTY,
  120. pace, LED_FADE_ISR);
  121. // remember next fade direction
  122. fade_in = !fade_in;
  123. }
  124. }
  125. // read fake gape angle sensor from pacemaker
  126. int getGapeAngle() {
  127. return ledcRead(LED_PIN);
  128. }
  129. // Encode static Bluetooth beacon advertisement data
  130. void setBeaconAdvertisement() {
  131. BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
  132. oAdvertisementData.setName(BEACON_NAME);
  133. pAdvertising->setAdvertisementData(oAdvertisementData);
  134. }
  135. // Encode variable Bluetooth beacon service data
  136. void setBeaconServiceData(int angle) {
  137. BLEEddystoneTLM EddystoneTLM;
  138. EddystoneTLM.setTemp(angle);
  139. log_i("Gape angle: %.2f°", EddystoneTLM.getTemp());
  140. BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
  141. oScanResponseData.setServiceData(
  142. BLEUUID((uint16_t)0xFEAA),
  143. String(
  144. EddystoneTLM.getData().c_str(),
  145. EddystoneTLM.getData().length()));
  146. pAdvertising->setScanResponseData(oScanResponseData);
  147. }
  148. void setup() {
  149. // enable logging to serial
  150. Serial.begin(115200);
  151. esp_log_level_set("*", ESP_LOG_DEBUG);
  152. if (BEACON_UUID == "00000000-0000-0000-0000-000000000000")
  153. Serial.println("Please set a deployment-wide unique BEACON_UUID");
  154. beginPace();
  155. beginTouchDetection();
  156. // setup Bluetooth
  157. BLEDevice::init(BEACON_NAME);
  158. pAdvertising = BLEDevice::getAdvertising();
  159. setBeaconAdvertisement();
  160. setBeaconServiceData(getGapeAngle());
  161. pAdvertising->start();
  162. }
  163. void loop() {
  164. // update Bluetooth beacon service data
  165. setBeaconServiceData(getGapeAngle());
  166. // misuse error-only log level for plot-friendly output
  167. #if ARDUHAL_LOG_LEVEL == ARDUHAL_LOG_LEVEL_ERROR
  168. Serial.printf("gape_angle:%d\n",
  169. getGapeAngle());
  170. #endif
  171. delay(500);
  172. }