Case study · Academic
Patient monitoring simulation on ESP32
ESP32 boards stream SpO2, heart rate, temperature and skin-response readings over MQTT to a Node-RED dashboard, with an on-device TinyML classification experiment.
In brief
- Course project simulating bedside monitoring: three ESP32 boards with biomedical sensors, an MQTT topic design and a shared ON/OFF system state.
- I wrote the three final firmwares, the FreeRTOS status tasks, the TinyML inference task and the Node-RED flow that stores readings in InfluxDB.
- A learning simulation, not a medical device: the classifier's input scaling was left uncalibrated, which is the first thing I would fix.
Key facts
- Role
- Developer
- Team
- Team of 3 (labs in pairs)
- Period
- –
- Status
- Course project submitted in December 2025
- AI assistance
- none No trace of an AI coding assistant in the repositories.
- Stack
Context
IoT course at ISIS (2025–2026): lab sessions on ESP32 boards, MQTT, Node-RED and FreeRTOS, followed by a final group project. The final project simulates hospital patient monitoring with biomedical sensors.
Problem
Simulate a small monitoring network: several boards read physiological signals, publish them to a central dashboard, react to remote commands and signal their own state, with one board trying to classify a signal on the device itself.
My role, the team and AI assistance
Lab work in pairs, then a group of 3 for the final project. I wrote the three final firmwares (main sensor board, TinyML sensor node, speaker node), the FreeRTOS status tasks and the final clean-up that integrated the TinyML model, and I added the Node-RED flow of the final submission. My teammates worked on the I2C exchange, the sensor tests and the training data. The repositories show no trace of an AI coding assistant.
Constraints
- Hardware: DFRobot FireBeetle ESP32 boards and low-cost sensors (DFRobot SpO2/heart-rate/temperature sensor, KY-039 pulse sensor, galvanic skin response sensor).
- Real time: sensor reading, network and status display must run side by side on a microcontroller.
- Memory: the classifier has to fit and run on the ESP32 alongside the network stack.
- Course timing: about one term, from the first labs to the final submission.
Solution and architecture
- Main sensor board: reads the SpO2, heart-rate and temperature sensor over I2C and publishes a JSON biometrics payload over MQTT every 2 seconds, plus its button states.
- TinyML node: a dedicated FreeRTOS task samples the skin-response signal at 62.5 Hz (125-sample window) and runs an Edge Impulse classifier with 3 classes (fear, neutral, surprised); the predicted label is published over MQTT.
- Speaker node: subscribes to play, music and loop topics and plays one of 3 melodies in a task created on demand.
- Shared state: a common
system/statetopic switches the whole system ON or OFF; FreeRTOS tasks pinned to one core drive status LEDs that blink differently for network loss, system OFF and invalid readings. - Dashboard: a Node-RED flow with charts and gauges subscribes to the sensor and classification topics, sends commands to the boards and writes measurements to InfluxDB.
Stack
C++ on the Arduino framework with PlatformIO, ESP32, FreeRTOS, MQTT (PubSubClient), I2C, Edge Impulse (TensorFlow Lite Micro), Node-RED and Node-RED Dashboard, InfluxDB.
Quality and verification
Testing was manual, on the bench: serial logs, MQTT messages watched on the broker, and the dashboard. The repository has no automated tests. The labs that came before were built step by step: MAC and IP reading, MQTT with a temperature sensor, a button and an LED, a Node-RED dashboard, a two-task FreeRTOS demo, then I2C master/slave exchange.
Results and status
The final project was submitted in December 2025. It is a learning simulation, not a medical device: the measurements were not compared with reference equipment and the classifier was not validated.
What I would do differently
- Calibrate the classifier input so the sensor values match the scale of the training data (the conversion was left as a placeholder), then measure accuracy on held-out data.
- Keep network settings out of the code, in an untracked configuration file.
- Write a README with a wiring diagram, the topic list and photos of the setup.
- Add a simple automated check of the MQTT payload format.
Links
- Source code: lab and final-project repositories, to be cleaned before they are linked here.