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