diff options
author | Jonas Smedegaard <dr@jones.dk> | 2025-04-15 12:02:50 +0200 |
---|---|---|
committer | Jonas Smedegaard <dr@jones.dk> | 2025-04-15 12:04:34 +0200 |
commit | 818722baf294c9f7d1b9422bf1f2a3066cb2c9cf (patch) | |
tree | f2a8436eddb38a8b78914bb5e6ff7057bc96ddf6 /sensor | |
parent | 2b55b35b3be6b42400359f6e816705efc530508a (diff) |
add sensor as non-library sketch
Diffstat (limited to 'sensor')
-rw-r--r-- | sensor/Mussel_Sensor_Beacon.md | 35 | ||||
-rw-r--r-- | sensor/mylog.h | 37 | ||||
-rw-r--r-- | sensor/sensor.ino | 186 | ||||
-rw-r--r-- | sensor/sensor.puml | 26 |
4 files changed, 284 insertions, 0 deletions
diff --git a/sensor/Mussel_Sensor_Beacon.md b/sensor/Mussel_Sensor_Beacon.md new file mode 100644 index 0000000..89beeec --- /dev/null +++ b/sensor/Mussel_Sensor_Beacon.md @@ -0,0 +1,35 @@ +# Mussel Sensor Beacon + +1. Reads sensors. + +2. Normalises sensor data as a gape angle in the range of 0°-90°. + +3. Broadcasts normalised sensor data as a beacon on a bluetooth network. + +## Scanner apps + +These Android apps have been found usable +for monitoring this type of sensor: + + * FeasyBeacon on Play store + * NanoBeacon BLE Scanner on Play store + * decodes Eddystone TLM temperature as Fahrenheit + * does not decode Eddystone URL + * SemBeacon on Play store + * detects URL-only but not TLM-only Eddystone Beacon + * too aggressive caching misses changing data + * UI optimized for SemBeacon + * nRF Connect for Mobile on Play store + * misses changing data + * UI not specific to beacons + +These Android apps are potentially interesting as well: + + * Beacon Locator on F-droid + * unreliable detection + * active development + * BLE Radar on F-droid + * detects URL-only but not TLM-only Eddystone Beacon + * UI not specific to beacons + * AltBeacon Loc on Play store + * detects URL-only but not TLM-only Eddystone Beacon diff --git a/sensor/mylog.h b/sensor/mylog.h new file mode 100644 index 0000000..43e3c91 --- /dev/null +++ b/sensor/mylog.h @@ -0,0 +1,37 @@ +/* +Origin: https://forum.arduino.cc/t/esp-log-level-set-is-not-working/1298369/5 + +Changes 2025-04-15 by Jonas Smedegaard <dr@jones.dk>: + * adjust ARDUHAL_LOG_FORMAT to include letter and newline +*/ + +#ifndef MYLOG_H +#define MYLOG_H + +// Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/include/log/include/ +#include <esp_log.h> +// Library/Arduino15/packages/esp32/hardware/esp32/3.0.7/cores/esp32/esp32-hal-log.h +#include <esp32-hal-log.h> + + +#undef CONFIG_LOG_MAXIMUM_LEVEL +#define CONFIG_LOG_MAXIMUM_LEVEL CORE_DEBUG_LEVEL + +#undef ESP_LOGE +#undef ESP_LOGW +#undef ESP_LOGI +#undef ESP_LOGD +#undef ESP_LOGV + +#define ESP_LOGE( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, tag, ARDUHAL_LOG_FORMAT(E, format) __VA_OPT__(,) __VA_ARGS__) +#define ESP_LOGW( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, tag, ARDUHAL_LOG_FORMAT(W, format) __VA_OPT__(,) __VA_ARGS__) +#define ESP_LOGI( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, tag, ARDUHAL_LOG_FORMAT(I, format) __VA_OPT__(,) __VA_ARGS__) +#define ESP_LOGD( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, tag, ARDUHAL_LOG_FORMAT(D, format) __VA_OPT__(,) __VA_ARGS__) +#define ESP_LOGV( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, tag, ARDUHAL_LOG_FORMAT(V, format) __VA_OPT__(,) __VA_ARGS__) + +#undef ARDUHAL_LOG_FORMAT +#define ARDUHAL_LOG_FORMAT(letter, format) \ + ARDUHAL_LOG_COLOR_##letter "[" #letter "] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", \ + __FUNCTION__ + +#endif // MYLOG_H diff --git a/sensor/sensor.ino b/sensor/sensor.ino new file mode 100644 index 0000000..a05d6cc --- /dev/null +++ b/sensor/sensor.ino @@ -0,0 +1,186 @@ +// 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 "mylog.h" +#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() { + BLEEddystoneTLM EddystoneTLM; + EddystoneTLM.setTemp(getGapeAngle()); + 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 (when also raised in IDE: Tools -> Core Debug Level) + Serial.begin(115200); + esp_log_level_set("*", ESP_LOG_DEBUG); + + Serial.begin(115200); + 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(); + pAdvertising->start(); +} + +void loop() { +// keepPace(); +// Serial.println(getGapeAngle()); + setBeacon(); + delay(500); +} diff --git a/sensor/sensor.puml b/sensor/sensor.puml new file mode 100644 index 0000000..3f033d1 --- /dev/null +++ b/sensor/sensor.puml @@ -0,0 +1,26 @@ +@startuml +'start +:instantiate mussel object; +:instantiate bluetooth object; +group init +:setup mussel sensors; +:setup bluetooth beacon; +end group +split +while (each 500ms) +group loop { +:read sensors; +:normalize sensor data +as a gape angle; +:add gape angle to beacon; +end group +endwhile +-[hidden]-> +kill +split again +while (each 100ms) +:broadcast beacon; +endwhile +-[hidden]-> +kill +@enduml |