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 beforeSifiBridgeis 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://orlsl://publisher in this API. Useuse_lsl=Truefor LSL output.
use_lsl(bool): IfTrue, 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)
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.DeviceTypeenum - 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, or60.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, or60.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, or60.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).0for DC measurement (EDA); a non-zero value enables BIOZ at that frequency.
Returns: Configuration response.
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):Trueto enable,Falseto 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, orHIGH.
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.
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):Trueto 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):Trueto 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.
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.Noneblocks 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:
ConnectionErrorif the device is not connected.TypeErrorif 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 byget_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): IfTrue, makes the new device active. IfFalse, 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)
}
}