Skip to content

About

Open-source desktop app for real-time BITalino biosignal acquisition over BLE. Currently supports EDA on A3 with Raw EDA, SCL, and SCR visualization and CSV recording, providing a foundation for feature extraction and future stress-classification workflows.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

BITalino Signal Reader

English | Bahasa Indonesia

Tests Python 3.11–3.13 License: MIT Developed with OpenAI Codex

BITalino SignalsReader is an open-source desktop application for acquiring BITalino biosignals over Bluetooth Low Energy. The current implementation focuses on EDA from analog channel A3, providing real-time visualization of Raw EDA, SCL, and SCR while preserving both raw and processed data in CSV recordings. The application serves as a foundation for biosignal analysis pipelines, particularly for preparing data for feature extraction and future stress-classification development.

Validation status: simulation mode and the protocol can be tested without a device. Hardware connectivity, throughput, and data quality must not be considered validated until they have been tested with a physical BITalino board.

This is an open-source project released under the MIT License. It may be used, studied, modified, and redistributed under the license terms. The current implementation is focused on EDA, but its separated acquisition, protocol, processing, recording, and GUI layers provide a foundation for adding other biosignals or data sources.

BITalino Signal Reader is an independent, unofficial project and is not affiliated with or endorsed by PLUX Wireless Biosignals.

Signal support

Signal or source Status
EDA on analog channel A3 Implemented
EDA Raw, SCL, and SCR plots Implemented
ECG Not implemented
EMG Not implemented
Accelerometer Not implemented
Other analog-channel combinations Not implemented

Hardware and configuration

  • Board: BITalino Plugged.
  • Sensor: Electrodermal Activity (EDA) for BITalino.
  • Connect the EDA sensor output to analog channel A3.
  • Acquisition enables only A3 at 100 Hz; all other analog and digital channels remain disabled.
  • A3 uses a 10-bit ADC with a range of 0–1023.
  • No device address is embedded in the public source. An optional preferred address can be supplied through BITALINO_PREFERRED_ADDRESS.
  • Disconnect OpenSignals Mobile and other BLE applications before connecting with this application. A device can generally maintain only one active connection.

BITalino devices may be supplied with Bluetooth Classic or Bluetooth Low Energy connectivity. This application requires a BLE-equipped board that exposes the official Exchange Data Service; it does not support the Bluetooth Classic transport.

Hardware setup

BITalino EDA hardware configuration connected to a computer

BITalino EDA sensor connected to analog channel A3 and streamed to the desktop application over BLE at 100 Hz.

Installation (PowerShell)

Use 64-bit Python 3.11, 3.12, or 3.13:

git clone https://github.com/farrellaa/BITalino-signalsReader.git
cd BITalino-signalsReader
py -3.13 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -e ".[dev]"
python -m pytest

If the PowerShell execution policy blocks activation, run Set-ExecutionPolicy -Scope Process Bypass in the same terminal, or invoke .venv\Scripts\python.exe directly.

For an installation that reproduces the exact dependency versions used during development:

pip install -r requirements-dev.txt
pip install -e . --no-deps
python -m pytest -p no:cacheprovider

requirements.txt pins runtime dependencies and requirements-dev.txt adds testing tools. pyproject.toml remains the canonical package metadata and accepts compatible versions within its declared ranges.

Running the application

Simulation mode (without Bluetooth):

python -m bitalino_reader --simulate

Click Start Acquisition to run the synthetic 100 Hz EDA source. This signal is intended only as a smoke test for the UI, buffers, plots, and recorder; it is not a hardware test result.

Hardware mode:

python -m bitalino_reader

Optionally prioritize a known device for the current terminal session:

$env:BITALINO_PREFERRED_ADDRESS = "AA:BB:CC:DD:EE:FF"
python -m bitalino_reader

This setting only changes scan ordering/candidate recognition. The BLE service validation, connection sequence, GATT characteristics, and acquisition commands remain unchanged.

  1. Make sure Windows Bluetooth is enabled and OpenSignals Mobile is disconnected.
  2. Click Scan and wait approximately five seconds.
  3. Select a BITalino candidate. Other BLE devices are hidden to prevent accidental connections.
  4. Click Connect. The application performs a fresh discovery, reads GATT without using the Windows cache, validates the service and characteristics, and then enables Frames notifications.
  5. Click Start Acquisition. The transmitted byte sequence is stop, a 50 ms delay, 100 Hz configuration, another 50 ms delay, and start A3. Recording starts automatically.
  6. Click Stop Acquisition to stop the stream and finalize the recording files. When the application closes, it also attempts to stop acquisition, disable notifications, disconnect, and shut down the worker.

Screenshots

Connection and acquisition controls

Dark mode Light mode
BITalino Reader connection and acquisition menu in dark mode BITalino Reader connection and acquisition menu in light mode

Real-time EDA plots

Dark mode Light mode
Raw EDA, SCL, and SCR plots in dark mode Raw EDA, SCL, and SCR plots in light mode

The screenshots show the same acquisition workflow in both themes. Plot interpolation, time window, and Y-range controls remain available in either mode.

Display and recording

Three synchronized plots display Raw EDA, SCL (tonic component), and SCR (phasic component) in µS. The GUI refreshes at approximately 20 Hz while the data source remains at 100 Hz. The internal buffer retains up to 120 seconds, with display windows of 10, 30, or 60 seconds. The default Auto Range Y setting makes small variations easier to see. Fixed ranges uses 0–25 µS for Raw/SCL and −2.5–2.5 µS for SCR.

The main-window contents can be scrolled on shorter screens. The information panel uses two columns and the plot area has a minimum height, preventing labels and axes across the three plots from overlapping.

The Theme selector at the top provides Dark and Light modes. The theme controls the widgets, panels, scrollbars, status bar, plot backgrounds, axes, and curve colors. The last selection is saved and restored the next time the application starts.

The Interpolation control provides Raw samples, Cubic smooth (4×), and Catmull–Rom smooth (6×). Cubic mode uses shape-preserving Hermite interpolation to avoid overshoot on monotonic segments. Catmull–Rom uses continuous tangents for rounder and smoother curves, but it may slightly overshoot between samples. Both modes pass through every original sample. Interpolation is applied only during rendering; acquisition data, SCL/SCR decomposition, and values written to CSV remain unchanged. The last selected mode is also saved.

The visual decomposition is causal so it can run in real time: SCL uses a first-order 0.05 Hz low-pass filter, while SCR is calculated by subtracting SCL from a 5 Hz low-pass signal (an effective range of approximately 0.05–5 Hz). Filter state is initialized from the first sample, preventing a false SCR transient when acquisition starts. These SCL/SCR results are intended for exploratory visualization, not clinical diagnosis.

Recording starts automatically with acquisition and stops automatically when acquisition stops. Files are always stored under bitalino-signal-reader/recordings/, independently of the terminal's working directory, and are written by a separate thread. Recording files are ignored by Git by default to protect research data. The CSV contains these columns:

sample_index,device_sequence,elapsed_s,host_monotonic_ns,eda_adc_raw,eda_us,eda_scl_us,eda_scr_us

A timestamp-matched JSON sidecar stores:

  • device_address, sensor, and channel;
  • sampling_rate_hz, adc_resolution_bits, and vcc;
  • transfer_function and start_time;
  • valid-frame, CRC-error, and estimated-dropped-frame counters;
  • the software version.

The eda_adc_raw value is never replaced by a converted or filtered value. The original six columns retain their order; eda_scl_us and eda_scr_us are appended at the end. The application does not currently implement artifact removal, peak detection, or stress classification.

BLE protocol

Exchange Data Service:

c566488a-0882-4e1b-a6d0-0b717e652234

Commands characteristic:

4051eb11-bf0a-4c74-8730-a48f4193fcea

Frames characteristic:

40fdba6b-672e-47c4-808a-e529adff3633

Command bytes used by the application:

Operation Calculation Byte
Sampling at 100 Hz (2 << 6) | 0x03 0x83
Start live A3 (0x04 << 2) | 0x01 0x11
Stop — 0x00

Bitmap 0x3F is not used. With one channel enabled, each frame is three bytes long. A BLE callback may contain a fragment or multiple frames; the decoder maintains a receive buffer, validates the 4-bit CRC, and resynchronizes by one byte when a candidate frame is invalid. Samples with an invalid CRC are excluded from both plots and recordings.

EDA conversion

Following the EDA rev-B datasheet for 10-bit A3 and 3.3 V VCC:

eda_us = eda_adc_raw * 3.3 / (1024 * 0.132)
# equivalent:
eda_us = eda_adc_raw * 25.0 / 1024.0

ADC 0 produces 0 µS and ADC 1023 produces approximately 24.9756 µS. No -0.574 offset is applied.

Architecture

Bleak callback / simulator (100 Hz)
        │
        ├─ protocol receive buffer → CRC → sequence/drop counter
        │
        ▼
thread-safe sample queue
        │
        ▼
Qt QTimer (~20 Hz) → signal profile → processed sample
                                      ├─ dynamic PlotStack → PyQtGraph
                                      └─ versioned schema → background CSV writer
  • protocol.py: command builder, CRC, frame decoding, conversion, and stream resynchronization; independent of Qt and BLE.
  • ble_client.py: persistent asyncio event loop in a worker thread; scan/connect/write/notification operations do not block the main thread.
  • simulator.py: synthetic EDA source using the same queue, plots, and recorder.
  • configuration.py: validated plot and EDA filter configuration, separate from transport and GUI code.
  • signals/base.py: transport-neutral contracts for signal profiles, real-time values, plot series, and processed samples.
  • signals/eda.py: current A3 EDA profile, including decomposition, labels, metadata, and the versioned CSV schema.
  • recorder.py: schema-aware CSV and JSON writer running in a separate thread.
  • signal_processing.py: real-time decomposition of EDA into SCL and SCR.
  • gui/plot_stack.py: dynamic synchronized plots and per-series ring buffers created from profile declarations.
  • gui/main_window.py: generic Qt orchestration that consumes a source and an injected signal profile.

Adapting the project to other data

The application can be extended for another biosignal, BITalino channel, or non-BITalino source. This is an extensibility foundation rather than built-in support: BLE acquisition and protocol decoding deliberately remain fixed to the validated A3 EDA behavior in this release.

A new implementation should:

  1. implement the SignalProfile contract in signals/base.py;
  2. declare real-time fields and any number of PlotSeriesSpec entries instead of editing MainWindow;
  3. provide a versioned RecordingSchema and serialize the matching record values;
  4. keep filter settings in a validated configuration object and expose them in recording metadata;
  5. inject the profile through MainWindow(..., signal_profile=...);
  6. implement a compatible QueuedSampleSource only when the new data requires different acquisition; and
  7. add protocol, conversion, profile, recording, and GUI tests.

Keep raw values separate from filtered or derived values. Keep every output schema explicit and versioned, and do not silently reinterpret the existing EDA CSV columns. Supporting other BITalino channel combinations will also require a separately tested frame decoder because the current connection path intentionally continues to send the proven 100 Hz A3 commands.

Troubleshooting Windows BLE

  • Disconnect OpenSignals Mobile and other applications from BITalino; temporarily disable Bluetooth on nearby phones if necessary.
  • Make sure Bluetooth is enabled in Windows Settings and the board is nearby.
  • Scanning shows only devices named BITalino, the optional preferred address, or devices advertising the official Exchange Data Service.
  • During connection, the application searches for the latest advertisement by address and uses the BITalino name as a fallback if its private BLE address has changed.
  • If the connection succeeds but the service or characteristics are missing, make sure the board uses the BITalino BLE block rather than a classic Bluetooth module. Power-cycle the board, click Scan, and then click Connect again.
  • A write error explains whether the characteristic lacks write or write-without-response; the application determines the response mode from the discovered GATT properties.
  • If notifications stop, click Stop and Disconnect, power-cycle the board, scan again, and reconnect.
  • After an unexpected disconnection, the UI returns to the disconnected state. The application attempts a fresh discovery on the next connection; scan again if the board is no longer advertising.
  • GATT services are read without the Windows cache to avoid an outdated service tree or one belonging to the wrong device.

Implementation references

Hardware validation checklist

Testing with a physical board must still verify that:

  • the target appears during scanning and all three official UUIDs are found;
  • connection succeeds, notifications are enabled, and commands 0x83 and 0x11 are transmitted;
  • Frames notifications arrive and A3 ADC values always remain within 0–1023;
  • EDA remains within the theoretical range of 0–25 µS and the sample rate is close to 100 Hz;
  • plots update in real time and the CRC/drop counters are reasonable;
  • Stop transmits 0x00;
  • disconnecting and reconnecting works without restarting the application.

License

This project is available under the MIT License. Contributions and adaptations for other scientific data sources are welcome; see CONTRIBUTING.md and SECURITY.md.

About

Open-source desktop app for real-time BITalino biosignal acquisition over BLE. Currently supports EDA on A3 with Raw EDA, SCL, and SCR visualization and CSV recording, providing a foundation for feature extraction and future stress-classification workflows.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages