aboutsummaryrefslogtreecommitdiff
path: root/sensor
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2025-04-15 12:02:50 +0200
committerJonas Smedegaard <dr@jones.dk>2025-04-15 12:04:34 +0200
commit818722baf294c9f7d1b9422bf1f2a3066cb2c9cf (patch)
treef2a8436eddb38a8b78914bb5e6ff7057bc96ddf6 /sensor
parent2b55b35b3be6b42400359f6e816705efc530508a (diff)
add sensor as non-library sketch
Diffstat (limited to 'sensor')
-rw-r--r--sensor/Mussel_Sensor_Beacon.md35
-rw-r--r--sensor/mylog.h37
-rw-r--r--sensor/sensor.ino186
-rw-r--r--sensor/sensor.puml26
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