Skip to main content

API Reference

Complete API reference for the SiFi Bridge Python package.

SifiBridge Class

The main class for interacting with SiFi devices.

Constructor

SifiBridge(publishers=None, use_lsl=False)

Create a SiFi Bridge instance. The constructor launches the bundled sifibridge CLI as a subprocess and starts background threads to read its stdout and stderr.

Parameters:

  • publishers (str | Iterable[str] | None): Additional data output destinations.
    • "tcp://ip:port" - Stream as JSON over TCP. The bridge connects out to the address as a TCP client, so a TCP server must be listening at that address before SifiBridge is constructed.
    • "udp://ip:port" - Send each packet as a UDP datagram.
    • Multiple publishers can be supplied as a list, e.g. ["tcp://127.0.0.1:5000", "udp://127.0.0.1:5001"].
    • Note: there is no csv:// or lsl:// publisher in this API. Use use_lsl=True for LSL output.
  • use_lsl (bool): If True, the bridge also exposes one Lab Streaming Layer outlet per enabled sensor.

Example:

import sifi_bridge_py as sbp

# Basic instance (stdout only — packets are read with sb.get_data()).
sb = sbp.SifiBridge()

# Mirror packets to a TCP subscriber.
sb = sbp.SifiBridge(publishers="tcp://127.0.0.1:9001")

# Multiple network outputs.
sb = sbp.SifiBridge(publishers=["tcp://127.0.0.1:9001",
"udp://127.0.0.1:9002"])

# Expose every enabled sensor as an LSL outlet.
sb = sbp.SifiBridge(use_lsl=True)
info

The constructor uses the sifibridge binary bundled with the sifibridge_bin package. No separate installation is required.


Connection Methods

connect()

connect(handle=None) -> bool

Connect to a SiFi device.

Parameters:

  • handle (DeviceType | str | None): Device to connect to.
    • None - Connect to any available device.
    • DeviceType enum - Connect by device name (e.g. DeviceType.BIOPOINT_V1_3).
    • String - MAC address (Linux/Windows) or UUID (macOS).

Returns: True if connected, False otherwise.

Raises: ConnectionError if Bluetooth is disabled.

Examples:

# Connect to any device.
sb.connect()

# Connect to a specific device type.
sb.connect(sbp.DeviceType.BIOPOINT_V1_3)

# Connect by MAC/UUID.
sb.connect("XX:XX:XX:XX:XX:XX")

disconnect()

disconnect() -> bool

Disconnect from the active device.

Returns: Connection status from the bridge response. After a clean disconnect this is False.

list_devices()

list_devices(source) -> list[str]

List available devices.

Parameters:

  • source (ListSources | str): Source to list from.
    • ListSources.BLE - Bluetooth devices.
    • ListSources.SERIAL - Serial/USB devices.
    • ListSources.DEVICES - All virtual devices managed by the bridge.

Returns: List of device identifiers.

Raises: ConnectionError if Bluetooth is disabled.

Example:

ble_devices = sb.list_devices(sbp.ListSources.BLE)
print(f"Found: {ble_devices}")

serial_devices = sb.list_devices(sbp.ListSources.SERIAL)

show()

show() -> dict

Get information about the currently active device.

Returns: Dictionary with the device's identifier, MAC, connection status, and a nested device block describing all sensor configuration.

Example:

info = sb.show()
print(f"Connected: {info['connected']}")
print(f"MAC: {info.get('mac')}")

get_active_device()

get_active_device() -> str

Return the name of the currently selected virtual device.


Sensor Configuration Methods

configure_sensors()

configure_sensors(ecg=False, emg=False, eda=False, imu=False, ppg=False) -> dict

Enable or disable multiple sensors at once. This is the on/off switch — anything not listed as True is disabled. Use this in combination with the per-sensor configure_* methods, which set sampling rate, filters, and gain.

Parameters:

  • ecg, emg, eda, imu, ppg (bool): Enable each respective sensor.

Returns: Configuration response.

Example:

# Enable ECG and IMU only.
sb.configure_sensors(ecg=True, imu=True)

configure_ecg()

configure_ecg(
state=True,
fs=500,
dc_notch=True,
mains_notch=50,
bandpass=True,
flo=0,
fhi=30,
) -> dict

Configure ECG sensor parameters.

Parameters:

  • state (bool): Enable / disable the sensor.
  • fs (int): Sampling rate in Hz (e.g. 250, 500, 1000).
  • dc_notch (bool): Enable the DC-offset removal filter.
  • mains_notch (int | None): Mains notch filter — None, 50, or 60.
  • bandpass (bool): Enable the bandpass filter.
  • flo (int): Lower cutoff frequency (Hz).
  • fhi (int): Higher cutoff frequency (Hz).

Returns: Configuration response.

Example:

# Standard ECG configuration (North America).
sb.configure_ecg(state=True, fs=500, mains_notch=60,
bandpass=True, flo=0, fhi=30)

configure_emg()

configure_emg(
state=True,
fs=2000,
dc_notch=True,
mains_notch=50,
bandpass=True,
flo=20,
fhi=450,
) -> dict

Configure EMG sensor parameters.

Parameters:

  • state (bool): Enable / disable the sensor.
  • fs (int): Sampling rate in Hz (e.g. 1000, 2000).
  • dc_notch (bool): Enable the DC-offset removal filter.
  • mains_notch (int | None): Mains notch filter — None, 50, or 60.
  • bandpass (bool): Enable the bandpass filter.
  • flo (int): Lower cutoff frequency (Hz).
  • fhi (int): Higher cutoff frequency (Hz).

Returns: Configuration response.

Example:

# Standard surface-EMG band.
sb.configure_emg(state=True, fs=2000,
bandpass=True, flo=20, fhi=450)

configure_eda()

configure_eda(
state=True,
fs=50,
dc_notch=True,
mains_notch=50,
bandpass=True,
flo=0,
fhi=5,
freq=0,
) -> dict

Configure EDA / BIOZ sensor parameters.

Parameters:

  • state (bool): Enable / disable the sensor.
  • fs (int): Sampling rate in Hz (e.g. 50, 100).
  • dc_notch (bool): Enable the DC-offset removal filter.
  • mains_notch (int | None): Mains notch filter — None, 50, or 60.
  • bandpass (bool): Enable the bandpass filter.
  • flo (int): Lower cutoff frequency (Hz).
  • fhi (int): Higher cutoff frequency (Hz).
  • freq (int): EDA / BIOZ excitation frequency (Hz). 0 for DC measurement (EDA); a non-zero value enables BIOZ at that frequency.

Returns: Configuration response.

warning

Enabling BIOZ (freq > 0) and ECG / EMG simultaneously may cause interference and degrade the quality of the ECG / EMG signals.

Example:

# DC EDA measurement.
sb.configure_eda(state=True, fs=50, freq=0)

configure_ppg()

configure_ppg(
state=True,
fs=100,
ir=9,
red=9,
green=9,
blue=9,
sens=PpgSensitivity.MEDIUM,
avg=1,
) -> dict

Configure PPG sensor parameters.

Parameters:

  • state (bool): Enable / disable the sensor.
  • fs (int): Sampling rate in Hz: 50, 100, 200, 400, 800, 1000, 1600, or 3200.
  • ir, red, green, blue (int): Per-LED current in mA (1–50).
  • sens (PpgSensitivity): Photodiode sensitivity.
  • avg (int): Signal averaging factor (1, 2, 4, 8, 16, or 32).

Returns: Configuration response.

Example:

# PPG for heart-rate monitoring at the wrist.
sb.configure_ppg(state=True, fs=100,
ir=7, red=7, green=9, blue=9,
sens=sbp.PpgSensitivity.MEDIUM)

configure_imu()

configure_imu(
state=True,
fs=100,
accel_range=2,
gyro_range=16,
) -> dict

Configure IMU sensor parameters.

Parameters:

  • state (bool): Enable / disable the sensor.
  • fs (int): Sampling rate in Hz: 50, 100, 200, 400, 800, 1000, 1600, or 3200.
  • accel_range (int): Accelerometer full-scale range in ±g (2, 4, 8, 16).
  • gyro_range (int): Gyroscope full-scale range in ±deg/s (16, 31, 63, 125, 250, 500, 1000, 2000).

Returns: Configuration response.

Example:

# IMU for motion tracking.
sb.configure_imu(state=True, fs=200,
accel_range=4, gyro_range=500)

configure_sampling_freqs()

configure_sampling_freqs(ecg=500, emg=2000, eda=50, imu=100, ppg=100) -> dict

Set the sampling frequencies for all biosignal sensors in a single call, without changing their other parameters.


Device Configuration Methods

set_filters()

set_filters(enable) -> dict

Enable or disable onboard filtering for all sensors.

Parameters:

  • enable (bool): True to enable, False to disable.

Returns: Configuration response.

set_ble_power()

set_ble_power(power) -> dict

Set the Bluetooth transmission power.

Parameters:

  • power (BleTxPower | str): Power level — LOW, MEDIUM, or HIGH.

Returns: Configuration response.

Example:

# Increase range and connection stability.
sb.set_ble_power(sbp.BleTxPower.HIGH)

set_memory_mode()

set_memory_mode(memory_config) -> dict

Configure how the device handles its data: BLE streaming, onboard flash, or both.

Parameters:

  • memory_config (MemoryMode | str): Memory mode.
    • MemoryMode.STREAMING - BLE streaming only (default).
    • MemoryMode.DEVICE - Save to onboard flash only.
    • MemoryMode.BOTH - Stream and save.

Returns: Configuration response.

info

SiFi Band does not support onboard memory; this parameter is ignored on that device.

Example:

# Record offline to flash.
sb.set_memory_mode(sbp.MemoryMode.DEVICE)

set_low_latency_mode()

set_low_latency_mode(on) -> dict

Enable low-latency packet mode (sends packets faster, with samples from every sensor as they come in, instead of one biosignal-batch per packet). Only supported on select BioPoint versions — contact SiFi Labs if you need to use it.

Parameters:

  • on (bool): True to enable.

Returns: Configuration response.

set_night_mode()

set_night_mode(enable) -> dict

Enable or disable night mode. When enabled, device LEDs are turned off during acquisition. Useful for sleep studies, covert monitoring, and extending battery life.

Parameters:

  • enable (bool): True to enable night mode.

Returns: Configuration response.

set_motor_intensity()

set_motor_intensity(level) -> dict

Set the vibration motor intensity. The motor only vibrates while it is running (between START_MOTOR and STOP_MOTOR).

Parameters:

  • level (int): Intensity level (1–10, where 10 is maximum).

Returns: Configuration response.

Raises: ValueError if level is not between 1 and 10.

Example:

sb.set_motor_intensity(5)
sb.send_command(sbp.DeviceCommand.START_MOTOR)

Data Acquisition Methods

start()

start() -> bool

Start data acquisition.

Returns: True if the command was sent successfully.

Raises: ConnectionError if the device is not connected.

stop()

stop() -> bool

Stop data acquisition.

Returns: True if the command was sent successfully.

info

stop() does not wait for the device to confirm. Allow ~1 second for the BLE command to land before destroying the SifiBridge instance.

get_data()

get_data(timeout=None) -> dict

Block until any packet arrives.

Parameters:

  • timeout (float | None): Timeout in seconds. None blocks indefinitely.

Returns: Packet as a dictionary, or an empty dict on timeout.

Example:

# Block until a packet arrives.
packet = sb.get_data()

# Wait up to 2 seconds for one.
packet = sb.get_data(timeout=2.0)
if packet:
print(packet['packet_type'])

get_data_with_key()

get_data_with_key(keys) -> dict

Block until a packet containing the specified key (or nested keys) arrives.

Parameters:

  • keys (str | Iterable[str]): A single key, or a sequence of keys describing a nested path that must exist in the returned packet.

Returns: The first packet that satisfies the requirement.

Example:

# Wait for the next packet with a 'timestamp' field.
packet = sb.get_data_with_key("timestamp")

# Wait for a packet that has data['ecg'].
packet = sb.get_data_with_key(["data", "ecg"])

clear_data_buffer()

clear_data_buffer() -> int

Discard any packets currently sitting in the bridge's internal queue. Useful right after start() to drop startup transients before the recording window begins.

Returns: Number of packets discarded.

Example:

sb.start()
time.sleep(1.0) # let the front-end settle
n = sb.clear_data_buffer() # drop the settle-period packets
print(f"Discarded {n} packets")
packet = sb.get_ecg() # fresh data

get_ecg()

get_ecg() -> dict

Block until the next ECG packet arrives.

get_emg()

get_emg() -> dict

Block until the next EMG packet arrives. Matches both 'emg' (BioPoint) and 'emg_armband' (SiFi Band) packet types.

get_eda()

get_eda() -> dict

Block until the next EDA / BIOZ packet arrives.

get_imu()

get_imu() -> dict

Block until the next IMU packet arrives.

get_ppg()

get_ppg() -> dict

Block until the next PPG packet arrives.

get_temperature()

get_temperature() -> dict

Block until the next temperature packet arrives.

send_event()

send_event() -> dict

Inject an event marker into the data stream. The device echoes the event back as a regular packet with packet_type='event', carrying a device-side timestamp under 'timestamps' and a marker value under data['event'].

Returns: The bridge's response confirming the event was sent.

Example:

# Mark a stimulus onset; the event packet will appear in the data stream.
sb.send_event()

Memory Management Methods

start_memory_download()

start_memory_download() -> int

Start downloading data from the device's onboard memory.

Returns: Number of kilobytes to download.

Raises:

  • ConnectionError if the device is not connected.
  • TypeError if the device does not support memory download.

Example:

kb = sb.start_memory_download()
print(f"Downloading {kb} kB...")

while True:
packet = sb.get_data()
if sb.is_memory_download_completed(packet):
break
# Process memory packet...

download_memory_serial()

download_memory_serial(port, output_dir, format="csv") -> bool

Download device memory via a serial port (much faster than BLE for long recordings) and export it to disk.

Parameters:

  • port (str): Serial port (e.g. "COM3", "/dev/ttyUSB0").
  • output_dir (str): Directory to write the exported file(s) to.
  • format (str): Output format — "csv" or "hdf5".

Returns: True if the download completed successfully.

is_memory_download_completed()

is_memory_download_completed(packet) -> bool

Check if a packet indicates that memory download has finished. Use this as the termination condition for a download loop.

Parameters:

  • packet (dict): A packet returned by get_data().

Returns: True if the packet is a memory packet whose status is memory_download_completed.


Device Control Methods

send_command()

send_command(command) -> bool

Send a command to the active device.

Parameters:

  • command (DeviceCommand | str): Command to send.

Returns: True if the command was sent successfully.

Example:

# Control LEDs.
sb.send_command(sbp.DeviceCommand.OPEN_LED_1)
sb.send_command(sbp.DeviceCommand.CLOSE_LED_1)

# Motor control. Set intensity first, then start / stop the motor.
sb.set_motor_intensity(5)
sb.send_command(sbp.DeviceCommand.START_MOTOR)
time.sleep(1)
sb.send_command(sbp.DeviceCommand.STOP_MOTOR)

# Power management.
sb.send_command(sbp.DeviceCommand.POWER_OFF)

Multi-Device Management

A single SifiBridge instance can manage multiple physical devices by creating one named virtual device per unit and switching between them with select_device(). All commands (connect, configure, start, stop, disconnect) act on whichever virtual device is currently selected.

create_device()

create_device(name, select=True) -> str

Create a new virtual device entry.

Parameters:

  • name (str): Device name (no spaces allowed).
  • select (bool): If True, makes the new device active. If False, the previously active device remains selected.

Returns: Name of the active device after the call.

Raises: ValueError if name contains spaces.

select_device()

select_device(name) -> str

Switch to a different virtual device.

Parameters:

  • name (str): Name of the device to select.

Returns: Name of the active device after the call.

delete_device()

delete_device(name) -> str

Delete a virtual device entry. The bridge automatically selects another device after deletion.

Parameters:

  • name (str): Name of the device to delete.

Returns: Name of the newly active device.


Enumerations

DeviceType

Supported device types for connection.

class DeviceType(Enum):
BIOPOINT_V1_1 = "BioPoint_v1_1"
BIOPOINT_V1_2 = "BioPoint_v1_2"
BIOPOINT_V1_3 = "BioPoint_v1_3"
SIFIBAND = "SiFiBand"

DeviceCommand

Commands that can be sent to devices.

class DeviceCommand(Enum):
START_ACQUISITION = "start-acquisition"
STOP_ACQUISITION = "stop-acquisition"
SET_BLE_POWER = "set-ble-power"
SET_ONBOARD_FILTERING = "set-filtering"
ERASE_ONBOARD_MEMORY = "erase-memory"
DOWNLOAD_ONBOARD_MEMORY = "download-memory"
START_STATUS_UPDATE = "start-status-update"
STOP_STATUS_UPDATE = "stop-status-update"
OPEN_LED_1 = "open-led1"
OPEN_LED_2 = "open-led2"
CLOSE_LED_1 = "close-led1"
CLOSE_LED_2 = "close-led2"
START_MOTOR = "start-motor"
STOP_MOTOR = "stop-motor"
POWER_OFF = "power-off"
POWER_DEEP_SLEEP = "deep-sleep"
SET_PPG_CURRENTS = "set-ppg-currents"
SET_PPG_SENSITIVITY = "set-ppg-sensitivity"
SET_EMG_MAINS_NOTCH = "set-emg-mains-notch"
SET_EDA_FREQUENCY = "set-eda-freq"
SET_EDA_GAIN = "set-eda-gain"
DOWNLOAD_MEMORY_SERIAL = "download-memory-serial"

PacketType

Data packet types delivered by the bridge.

class PacketType(Enum):
ECG = "ecg"
EMG = "emg"
EMG_ARMBAND = "emg_armband"
EDA = "eda"
IMU = "imu"
PPG = "ppg"
STATUS = "status"
MEMORY = "memory"
TEMPERATURE = "temperature"
START_TIME = "start_time"

Note that event markers also arrive in the data stream, with packet_type equal to 'event'.

PacketStatus

Packet status values.

class PacketStatus(Enum):
OK = "ok"
LOST_DATA = "lost_data"
RECORDING = "recording"
MEMORY_DOWNLOAD_COMPLETED = "memory_download_completed"
MEMORY_ERASED = "memory_erased"
INVALID = "invalid"

SensorChannel

Sensor channel names used inside the data field of each packet.

class SensorChannel(Enum):
ECG = "ecg"
EMG = "emg"
EMG_ARMBAND = ("emg0", "emg1", "emg2", "emg3",
"emg4", "emg5", "emg6", "emg7")
EDA = "eda"
IMU = ("qw", "qx", "qy", "qz", "ax", "ay", "az")
PPG = ("ir", "r", "g", "b")
TEMPERATURE = "temperature"

Example:

packet = sb.get_imu()
imu_data = packet['data']

# Access specific IMU channels via the enum.
qw = imu_data[sbp.SensorChannel.IMU.value[0]] # quaternion W
ax = imu_data[sbp.SensorChannel.IMU.value[4]] # accel X (g)

BleTxPower

Bluetooth transmission power levels.

class BleTxPower(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"

MemoryMode

Device memory configuration modes.

class MemoryMode(Enum):
STREAMING = "streaming" # Stream via BLE only
DEVICE = "device" # Save to device memory only
BOTH = "both" # Stream and save

PpgSensitivity

PPG photodiode sensitivity levels.

class PpgSensitivity(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
MAX = "max"

ListSources

Sources for list_devices().

class ListSources(Enum):
BLE = "ble" # Bluetooth devices
SERIAL = "serial" # Serial / USB devices
DEVICES = "devices" # Virtual device entries managed by the bridge

Data Packet Structure

All sensor packets follow the same general shape:

{
'device': str, # Device model (e.g. 'BioPointV1_3')
'id': str, # Virtual-device name (e.g. 'device')
'mac': str, # Device MAC address
'packet_type': str, # One of PacketType values, or 'event'
'status': str, # One of PacketStatus values
'timestamp': float, # Unix timestamp of packet reception (s)
'sample_rate': float, # Estimated rate for this packet (Hz)
'timestamps': [float, ...], # Per-sample timestamps relative to the
# stream start (s)
'data': { # Sensor-specific samples
'<channel>': [float, ...],
...
},
}

timestamps and the per-channel sample arrays inside data always have the same length: one timestamp per sample. sample_rate is estimated from inter-sample intervals and may fluctuate slightly from packet to packet — use it as a diagnostic, not as ground truth.

ECG Packet

{
'packet_type': 'ecg',
'data': {
'ecg': [float, ...] # voltage values
}
}

EMG Packet (BioPoint)

{
'packet_type': 'emg',
'data': {
'emg': [float, ...] # voltage values
}
}

EMG Packet (SiFi Band)

{
'packet_type': 'emg_armband',
'data': {
'emg0': [float, ...],
'emg1': [float, ...],
'emg2': [float, ...],
'emg3': [float, ...],
'emg4': [float, ...],
'emg5': [float, ...],
'emg6': [float, ...],
'emg7': [float, ...],
}
}

EDA Packet

{
'packet_type': 'eda',
'data': {
'eda': [float, ...] # conductance / impedance values
}
}

IMU Packet

{
'packet_type': 'imu',
'data': {
'qw': [float, ...], # quaternion W
'qx': [float, ...], # quaternion X
'qy': [float, ...], # quaternion Y
'qz': [float, ...], # quaternion Z
'ax': [float, ...], # acceleration X (g)
'ay': [float, ...], # acceleration Y (g)
'az': [float, ...], # acceleration Z (g)
}
}

PPG Packet

{
'packet_type': 'ppg',
'data': {
'ir': [float, ...], # infrared channel
'r': [float, ...], # red channel
'g': [float, ...], # green channel
'b': [float, ...], # blue channel
}
}

Temperature Packet

{
'packet_type': 'temperature',
'data': {
'temperature': [float, ...] # skin temperature (°C)
}
}

Event Packet

Emitted in response to sb.send_event(). Looks just like a sensor packet — same timestamp, same per-sample timestamps array — so it can be routed in the same dispatch loop as the others:

{
'packet_type': 'event',
'timestamps': [float], # device-time of the event (s since stream start)
'data': {
'event': [float], # marker value (default 1.0, increments each call)
}
}