- // SPDX-FileCopyrightText: 2025 Amal Mazrah <mazrah@ruc.dk>
- // SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
- // SPDX-FileCopyrightText: 2025 Mennatullah Hatim Kassim <stud-mennatulla@ruc.dk>
- // SPDX-FileCopyrightText: 2025 Noor Ahmad <noora@ruc.dk>
- // SPDX-FileCopyrightText: 2025 Tanishka Suwalka <tanishkas@ruc.dk>
- // SPDX-License-Identifier: GPL-3.0-or-later
- /// Sensor mussel - an Arduino sketch to emulate a mussel biosensor
- ///
- /// * v0.0.3
- /// * rewrite sensor as sketch,
- /// using ESP32 LEDC, Touch sensor and Logging library
- ///
- /// * v0.0.2
- /// * rewrite attitude #2 to also handle button press
- /// * add voting functions and example
- ///
- /// * v0.0.1
- /// * initial release to radicle
- ///
- /// @version 0.0.3
- /// @see <https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z2tFBF4gN7ziG9oXtUytVQNYe3VhQ/tree/Mussel/README.md>
- /// @see <https://moodle.ruc.dk/course/view.php?id=23504>
- // include and refine ESP32 Logging system
- // activate in Arduino IDE: Tools -> Core Debug Level
- #define CONFIG_ARDUHAL_ESP_LOG 1
- #define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
- #include <esp32-hal-log.h>
- #undef ARDUHAL_LOG_FORMAT
- #define ARDUHAL_LOG_FORMAT(letter, format) \
- ARDUHAL_LOG_COLOR_##letter "[" #letter "] %s(): " format \
- ARDUHAL_LOG_RESET_COLOR "\r\n", __FUNCTION__
- #include "BLEDevice.h"
- #include "BLEBeacon.h"
- #include "BLEAdvertising.h"
- #include "BLEEddystoneTLM.h"
- // Adjust these for production use
- //
- // * BEACON_UUID should be unique for each deployment
- // * INSTANCE_ID should be unique for each sensor
- //
- // @see https://www.uuidgenerator.net/
- #define BEACON_NAME "Dummy mussel sensor"
- #define BEACON_UUID "00000000-0000-0000-0000-000000000000"
- #define INSTANCE_ID "0xbeac0101"
- #define STRESS_MAX 50
- // touch sensor using ESP32 Touch sensor
- // https://docs.espressif.com/projects/arduino-esp32/en/latest/api/touch.html
- #define TOUCH_PIN T0 // T0 is GPIO4
- #define TOUCH_THRESHOLD 40
- // pacemaker using ESP32 LED PWM Controller (LEDC)
- // https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html
- #define LED_PIN LED_BUILTIN
- #define LEDC_BITS 7
- #define LEDC_FREQ 500
- #define LEDC_START_DUTY 0
- #define LEDC_TARGET_DUTY 90
- #define LEDC_CALM_PACE 3000
- #define LEDC_STRESSED_PACE 400
- // Bluetooth beacon
- #define BEACON_POWER ESP_PWR_LVL_N12
- int stress = 0;
- bool touch_detected = false;
- int pace = LEDC_STRESSED_PACE;
- bool fade_ended = false;
- bool fade_in = true;
- BLEAdvertising *pAdvertising;
- // Touch sensor callback
- void gotTouch() {
- // keepPace();
- touch_detected = true;
- pace = LEDC_STRESSED_PACE;
- }
- // pacemaker Interrupt Service Routine (ISR)
- void ARDUINO_ISR_ATTR LED_FADE_ISR() {
- fade_ended = true;
- keepPace();
- }
- void beginTouchDetection() {
- touchAttachInterrupt(TOUCH_PIN, gotTouch, TOUCH_THRESHOLD);
- log_d("touch detected");
- }
- // pacemaker initialization
- void beginPace() {
- // Setup pacemaker timer
- ledcAttach(LED_PIN, LEDC_FREQ, LEDC_BITS);
- // fade in once supervised and then begin fade out with ISR
- ledcFade(LED_PIN, LEDC_START_DUTY, LEDC_TARGET_DUTY, pace);
- delay(pace);
- ledcFadeWithInterrupt(LED_PIN, LEDC_TARGET_DUTY, LEDC_START_DUTY,
- pace, LED_FADE_ISR);
- }
- // pacemaker maintenance
- void keepPace() {
- // if (fade_ended || touch_detected) {
- if (fade_ended) {
- fade_ended = false;
- // stress management
- if (touch_detected) {
- touch_detected = false;
- log_i("Stressed by touch!");
- if (stress < STRESS_MAX) {
- stress = stress + 10;
- }
- } else if (stress > 0) {
- stress--;
- if (stress <= 0) {
- pace = LEDC_CALM_PACE;
- log_i("Calmed down...");
- } else {
- log_i("Still stressed...");
- }
- } else {
- pace = LEDC_CALM_PACE;
- }
- // begin fade in opposite direction at decided pace
- ledcFadeWithInterrupt(LED_PIN,
- fade_in ? LEDC_START_DUTY : LEDC_TARGET_DUTY,
- fade_in ? LEDC_TARGET_DUTY : LEDC_START_DUTY,
- pace, LED_FADE_ISR);
- fade_in = !fade_in;
- }
- }
- // Sensor reading
- int getGapeAngle() {
- return ledcRead(LED_PIN);
- }
- // Construct Bluetooth beacon
- void setBeacon(int angle) {
- BLEEddystoneTLM EddystoneTLM;
- EddystoneTLM.setTemp(angle);
- log_i("Gape angle: %.2f°", EddystoneTLM.getTemp());
- BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
- BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
- oScanResponseData.setServiceData(BLEUUID(
- (uint16_t)0xFEAA),
- String(EddystoneTLM.getData().c_str(),
- EddystoneTLM.getData().length()));
- oAdvertisementData.setName(BEACON_NAME);
- pAdvertising->setAdvertisementData(oAdvertisementData);
- pAdvertising->setScanResponseData(oScanResponseData);
- }
- void setup() {
- // enable logging to serial
- Serial.begin(115200);
- esp_log_level_set("*", ESP_LOG_DEBUG);
- beginPace();
- beginTouchDetection();
- // setup Bluetooth
- if (BEACON_UUID == "00000000-0000-0000-0000-000000000000")
- log_w("Please set a unique BEACON_UUID");
- BLEDevice::init("TLMBeacon");
- BLEDevice::setPower(BEACON_POWER);
- pAdvertising = BLEDevice::getAdvertising();
- setBeacon(getGapeAngle());
- pAdvertising->start();
- }
- void loop() {
- setBeacon(getGapeAngle());
- delay(500);
- }
|