141 lines
3.1 KiB
Markdown
141 lines
3.1 KiB
Markdown
|
|
# Pilot Bio-Data — Pulse Oximeter Logger
|
||
|
|
|
||
|
|
Receives real-time **heart rate (BPM)** and **blood-oxygen (SpO₂)** readings
|
||
|
|
from the Controlytics AI pulse oximeter over a wired Ethernet connection and
|
||
|
|
logs them to a timestamped CSV file.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Hardware
|
||
|
|
|
||
|
|
| Item | Detail |
|
||
|
|
|---|---|
|
||
|
|
| Device | Controlytics AI Pulse Oximeter v1.0.0 |
|
||
|
|
| Interface | Ethernet (UDP) |
|
||
|
|
| Device Ethernet IP | `192.168.1.2` |
|
||
|
|
| Device WiFi AP | `PULSE_OXI_WIFI` / password `controlytics` |
|
||
|
|
| Device config page | `http://192.168.4.1` (Admin / Admin) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Network Setup
|
||
|
|
|
||
|
|
The device sends UDP packets to a configured destination address.
|
||
|
|
The one-time setup below is already done; repeat only if hardware changes.
|
||
|
|
|
||
|
|
### Computer (receiver)
|
||
|
|
|
||
|
|
Assign a static IP to the Ethernet interface connected to the device:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sudo ip addr add 192.168.1.100/24 dev <eth-interface>
|
||
|
|
```
|
||
|
|
|
||
|
|
On this machine the interface is `enp1s0`:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sudo ip addr add 192.168.1.100/24 dev enp1s0
|
||
|
|
```
|
||
|
|
|
||
|
|
### Device configuration
|
||
|
|
|
||
|
|
Connect to `PULSE_OXI_WIFI`, open `http://192.168.4.1`, log in, and set:
|
||
|
|
|
||
|
|
| Field | Value |
|
||
|
|
|---|---|
|
||
|
|
| IP | `192.168.1.2` |
|
||
|
|
| Gateway | `192.168.1.1` |
|
||
|
|
| Subnet | `255.255.255.0` |
|
||
|
|
| Destination address | `192.168.1.100` |
|
||
|
|
| Destination port | `5005` |
|
||
|
|
| Send interval (ms) | `500` |
|
||
|
|
|
||
|
|
Submit and restart the device (Log Out button).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Requirements
|
||
|
|
|
||
|
|
Python 3.10 or later. No third-party packages — only the standard library is used.
|
||
|
|
|
||
|
|
```bash
|
||
|
|
python3 --version # 3.10+
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Running
|
||
|
|
|
||
|
|
```bash
|
||
|
|
python3 receive.py
|
||
|
|
```
|
||
|
|
|
||
|
|
Place the pilot's index finger on the sensor with light, steady pressure.
|
||
|
|
Hold still for a few seconds for the reading to stabilise.
|
||
|
|
|
||
|
|
### Example output
|
||
|
|
|
||
|
|
```
|
||
|
|
Listening on UDP 0.0.0.0:5005 | Logging to readings.csv
|
||
|
|
TIME BPM SpO2 % STATUS
|
||
|
|
----------------------------------------------------
|
||
|
|
11:34:00.464 92 97 OK
|
||
|
|
11:34:00.965 92 97 OK
|
||
|
|
11:34:01.466 74 97 OK
|
||
|
|
11:34:22.034 87 98 OK
|
||
|
|
11:35:14.207 --- --- No finger
|
||
|
|
```
|
||
|
|
|
||
|
|
Press `Ctrl+C` to stop.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Output — readings.csv
|
||
|
|
|
||
|
|
Every packet is appended to `readings.csv` in the same directory.
|
||
|
|
Rows where no finger is detected have empty `bpm` and `spo2` fields.
|
||
|
|
|
||
|
|
| Column | Description |
|
||
|
|
|---|---|
|
||
|
|
| `timestamp` | ISO-8601 local timestamp |
|
||
|
|
| `bpm` | Heart rate in beats per minute (empty if no finger) |
|
||
|
|
| `spo2` | Blood-oxygen saturation % (empty if no finger) |
|
||
|
|
| `raw` | Raw JSON packet from device |
|
||
|
|
|
||
|
|
### Example rows
|
||
|
|
|
||
|
|
```
|
||
|
|
timestamp,bpm,spo2,raw
|
||
|
|
2026-06-12T11:34:00.464000,92,97,"{""bpm"":92,""spo2"":97}"
|
||
|
|
2026-06-12T11:34:01.466000,74,97,"{""bpm"":74,""spo2"":97}"
|
||
|
|
2026-06-12T11:35:14.207000,,,"{""bpm"":-1,""spo2"":-1}"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Packet Format
|
||
|
|
|
||
|
|
The device sends a UDP JSON payload every 500 ms:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{"bpm": 92, "spo2": 97}
|
||
|
|
```
|
||
|
|
|
||
|
|
Values of `-1` indicate no finger is on the sensor.
|
||
|
|
The parser also accepts `key=value` and bare CSV formats for forward compatibility.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Project Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
pilot_bio_data/
|
||
|
|
├── receive.py # UDP listener and CSV logger
|
||
|
|
├── readings.csv # Auto-generated log (appended on each run)
|
||
|
|
└── README.md
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
*Axial Aero — Internal tooling*
|