Metadata-Version: 2.5
Name: signalino
Version: 0.1.2
Summary: Python API for Signalino EEG devices, powered by BrainFlow
Project-URL: Homepage, https://github.com/JABarios/signalino-python
Project-URL: Repository, https://github.com/JABarios/signalino-python
Project-URL: Issues, https://github.com/JABarios/signalino-python/issues
Author: Scignals
License-Expression: MIT
License-File: LICENSE
Keywords: BCI,BrainFlow,EEG,LSL,MNE,Signalino
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Requires-Dist: brainflow-signalino==0.1.0; sys_platform == 'linux'
Requires-Dist: brainflow; sys_platform != 'linux'
Requires-Dist: numpy>=1.26
Requires-Dist: pyserial<4,>=3.5
Provides-Extra: all
Requires-Dist: matplotlib<4,>=3.9; extra == 'all'
Requires-Dist: mne<2,>=1.12; extra == 'all'
Requires-Dist: pylsl<2,>=1.18.2; extra == 'all'
Provides-Extra: dev
Requires-Dist: build<2,>=1.3; extra == 'dev'
Requires-Dist: pytest-cov<8,>=6; extra == 'dev'
Requires-Dist: pytest<10,>=8.4; extra == 'dev'
Requires-Dist: ruff<1,>=0.12; extra == 'dev'
Requires-Dist: twine<8,>=7; extra == 'dev'
Provides-Extra: lsl
Requires-Dist: pylsl<2,>=1.18.2; extra == 'lsl'
Provides-Extra: mne
Requires-Dist: mne<2,>=1.12; extra == 'mne'
Provides-Extra: viewer
Requires-Dist: matplotlib<4,>=3.9; extra == 'viewer'
Description-Content-Type: text/markdown

# signalino

`signalino` is the high-level Python API for Signalino 4 EEG devices. It wraps
the Signalino board implemented in BrainFlow and adds a non-destructive sample
buffer, typed battery and impedance results, Lab Streaming Layer publishing,
and conversion to MNE-Python.

> This is research software. It is not a medical device and must not be used
> for diagnosis or patient monitoring.

## Installation

### Linux x86_64 (Intel/AMD 64-bit)

Python 3.10+ and glibc 2.35+ are required for the current Linux wheels.

```sh
python -m pip install --upgrade signalino
```

Starting with 0.1.2, this installs `brainflow-signalino==0.1.0` automatically.
It contains the compiled Signalino driver and uses the `brainflow_signalino`
Python module, so it can coexist with official `brainflow` without overwriting
files. No compiler, CMake or private repository access is required.
ARM/Raspberry Pi, Alpine/musl and older glibc are not covered by these wheels.
USB/RFCOMM permissions and Bluetooth adapter setup remain host OS requirements.

### macOS and Windows

Precompiled `brainflow-signalino` wheels are not available for these platforms
in this release. Keep using the existing Signalino-enabled BrainFlow build from
[JABarios/brainflow-signalino](https://github.com/JABarios/brainflow-signalino).
The wrapper uses the existing `brainflow` module on these platforms. Official
BrainFlow alone does not yet include board 69; a matching native build is needed.

### Optional integrations and examples

```sh
python -m pip install 'signalino[viewer]'
python -m pip install 'signalino[lsl]'
python -m pip install 'signalino[mne]'
```

Examples live in this repository's `examples/` directory and are not included
in the installed wheel. `examples/check_import.py` does not connect hardware.

For development, install `.[dev,all]` and run `pytest`.

## USB

```python
import time

from signalino import Signalino

with Signalino.usb() as device:  # Automatically chooses the most probable port
    device.start_streaming()
    time.sleep(2)
    eeg_uv = device.get_data()

print(eeg_uv.shape)  # (8, approximately 500)
```

Use `COM3`-style names on Windows and `/dev/ttyACM0`-style names on Linux.
Pass one explicitly as `Signalino.usb("/dev/cu.usbmodem1101")` when needed.
Discovery only examines port names and USB descriptors; it does not open ports.
Use `find_usb_ports()` to display every probable candidate. If two devices are
equally likely, automatic selection refuses to guess.

## Bluetooth LE

```python
from signalino import Signalino

device = Signalino.ble("Signalino-852960")
device.connect()
device.start_streaming()
```

When only one Signalino is advertising, `Signalino.ble()` lets BrainFlow choose
it automatically. Provide the advertised name whenever multiple devices may be
present.

## Bluetooth Classic

Signalino devices fitted with an HC-06 appear as a serial port after pairing.
The example can locate a probable paired port automatically:

```bash
python examples/basic_classic_bluetooth.py
```

The example automatically selects a probable Signalino port. Pass the port as
an argument if several paired devices are plausible. On Linux the port is
commonly `/dev/rfcomm0`; on Windows it is a `COM` port. On macOS the example
uses the RFCOMM bridge bundled with Signalino Suite.

Measure the effective rate and detect packet-counter gaps over 30 seconds:

```bash
python examples/measure_classic_bluetooth.py
```

## Live viewer

Install the viewer extra and open the eight-channel rolling display:

```bash
python -m pip install "matplotlib>=3.9,<4"
python examples/live_viewer.py
```

Bluetooth Classic is selected by default. Use `--transport usb` or
`--transport ble` for the other connections. Press Space to pause the display
without stopping acquisition, and press `Q` or Escape to close it.

## Data

`get_data()` returns a NumPy array in microvolts with shape
`(channels, samples)`. Data is consumed oldest first by default:

```python
latest_copy = device.get_data(250, clear=False)
oldest_consumed = device.get_data(250)
```

For timestamps, use `get_data_batch()`:

```python
batch = device.get_data_batch()
print(batch.samples_uv.shape)
print(batch.timestamps)
```

The package continuously drains BrainFlow into its own bounded buffer. LSL and
`get_data()` therefore receive the same samples without stealing data from one
another.

## Public API

The stable top-level API is:

```text
Signalino.usb(...) / Signalino.ble(...)
find_usb_port() / find_usb_ports()
connect() / disconnect()
start_streaming() / stop_streaming()
get_data() / get_data_batch() / clear_data()
battery() / impedance()
start_lsl() / stop_lsl()
to_mne()
```

Public result types and exceptions are importable directly from `signalino`.
Implementation modules whose names begin with an underscore are private.

## Battery

```python
status = device.battery()
print(status.volts, status.percent, status.charging)
```

With the current USB BrainFlow bridge, battery replies cannot be collected
while binary EEG is streaming. Stop USB streaming before refreshing the value.
BLE uses a separate control characteristic and can refresh battery state while
EEG is active.

## Impedance

```python
reading = device.impedance()
print(reading.kiloohms)
```

The ADS1299 cannot emit normal EEG while measuring impedance. If streaming is
active, `impedance()` pauses EEG, takes one reading, exits impedance mode, and
restores both EEG acquisition and the previous LSL outlet. This produces a
short, timestamp-visible gap by design.

## LSL

```python
device.start_streaming()
stream = device.start_lsl()
print(stream.name, stream.source_id)
```

The outlet contains eight `float32` EEG channels in microvolts. It is closed
automatically before acquisition stops, so Signalino never leaves an advertised
but empty LSL stream behind.

## MNE

```python
raw = device.to_mne(clear=False)
print(raw.info["sfreq"])
```

MNE stores EEG in volts; conversion from Signalino's microvolts is automatic.
Pass an MNE montage with `device.to_mne(montage=montage)` when channel names have
been assigned to physical electrode positions.

## Development and release checks

```bash
ruff check .
ruff format --check .
pytest --cov=signalino
python -m build
python -m twine check dist/*
```

Building creates an sdist and a platform-independent wheel. Publishing is
deliberately not part of the build process.

## License

MIT
