API reference
Complete API reference for the SiFi Bridge Python package (sifi_bridge_py) 1.3.0,
which pairs with the SiFi Bridge CLI 1.3.
SiFi Bridge 2.0 reworked this API substantially — sensors are enabled
differently, filters take explicit cutoffs, send_command() was replaced
by individual methods, and the packet field timestamp became
received_at. If you are on 2.0 or later, see the
current API reference.
Version pairing
sifi_bridge_py downloads a matching CLI binary on first use: it picks the
newest SiFi Bridge release
whose major and minor version match the Python package. So
sifi_bridge_py 1.3.0 runs the CLI 1.3 — 1.3.4 at the time of writing.
No separate install is needed, but the machine needs network access the
first time.
SifiBridge class
Constructor
SifiBridge(publishers=None, use_lsl=False)
Create a SiFi Bridge instance, launching the sifibridge CLI as a
subprocess.
Parameters:
publishers(str | Iterable[str] | None): Additional data output destinations, passed through to the CLI's output flags."tcp://ip:port"— send packets to a TCP port (--tcp-out)"udp://ip:port"— send packets to a UDP port (--udp-out)"csv://dir"— write packets to CSV files in a directory (--csv-out)
use_lsl(bool): IfTrue, also publish the data stream to Lab Streaming Layer (--lsl).
csv:// directory must already existThe CLI panics and exits if the --csv-out directory is missing, which
takes the subprocess down with it — the next call then fails on a closed
pipe, typically surfacing as OSError: [Errno 22] Invalid argument from
inside connect(). Create the directory before constructing SifiBridge:
import os
os.makedirs("./data", exist_ok=True)
sb = sbp.SifiBridge(publishers="csv://./data/")
Example:
import sifi_bridge_py as sbp
sb = sbp.SifiBridge()
sb = sbp.SifiBridge(publishers="tcp://127.0.0.1:9001")
sb = sbp.SifiBridge(publishers=["tcp://127.0.0.1:9001", "csv://./data"])
sb = sbp.SifiBridge(use_lsl=True)
Device managers
1.3 organises work around device managers: named slots, each handling
one device. The CLI creates a default manager called default-1 at
startup (its own help text says device-1, but default-1 is what it
actually creates). Commands apply to the active manager only.
2.0 replaced managers with real sessions keyed by the device's BLE id —
connect() creates the session and create_device()/delete_device() no
longer exist.
create_device()
create_device(name, select=True)
Create a device manager, optionally selecting it.
Parameters:
name(str): Manager name. Must not contain spaces.select(bool): Select it after creation.
Raises: ValueError if name contains spaces.
delete_device()
delete_device(name)
Delete a device manager. If it was active, another becomes active. The last remaining manager cannot be deleted.
select_device()
select_device(name)
Select which manager subsequent commands apply to.
Connection methods
connect()
connect(handle=None) -> bool
Connect to a device over BLE.
Parameters:
handle(DeviceType | str | None): BLE device name (e.g."BioArmband"), MAC address (Windows/Linux), or UUID (macOS).Noneauto-connects to the first device found.
Returns: True on success.
DeviceTypeThe signature accepts DeviceType | str | None, but passing a DeviceType
does not work: connect() matches the handle against the device's
advertised BLE name, and a device type value such as "BioPoint_v1_3" is
not that name — a BioPoint advertising as BioPoint_EF05 will not match.
The call returns False rather than raising, so the failure is silent and
the next blocking read hangs forever.
sb.connect(sbp.DeviceType.BIOPOINT_V1_3) # -> False, never connects
sb.connect() # -> True, first device found
sb.connect("BioPoint_EF05") # -> True, by BLE name
sb.connect("FA:31:9F:7E:6A:A9") # -> True, by MAC
Always check the return value.
connect() in 1.3 takes no timeout. It was added in 2.0.
disconnect()
disconnect()
Disconnect from the current device.
list_devices()
list_devices(source) -> list[dict]
List devices from a given source.
Parameters:
source(ListSources | str):BLE,SERIAL, orDEVICES.
Returns: a list of dicts with name and id keys, e.g.
[{'name': 'BioPoint_EF', 'id': 'FA:31:9F:7E:6A:A9'}]. Note the package
annotates this as list[str], but it returns dicts.
Example:
for dev in sb.list_devices(sbp.ListSources.BLE):
print(dev["name"], dev["id"])
show()
show()
Return information about the current device, including its configuration.
This method is called info() from 2.0 onwards.
Configuration methods
set_channels()
set_channels(ecg=False, emg=False, eda=False, imu=False, ppg=False)
Select which biochannels are enabled. Every parameter defaults to
False, so this call states the complete set: any channel you do not pass
as True is disabled.
Example:
# ECG and IMU on, everything else off.
sb.set_channels(ecg=True, imu=True)
2.0 calls this configure_sensors(), and there omitted parameters keep
their current state instead of being disabled.
configure_ecg()
configure_ecg(bandpass_freqs=(0, 30))
Configure the ECG bandpass filter. Also enables on-board filtering, as if
set_filters(True) had been called.
Parameters:
bandpass_freqs(tuple):(low, high)cutoff frequencies in Hz.
Example:
sb.configure_ecg(bandpass_freqs=(0, 30))
configure_emg()
configure_emg(bandpass_freqs=(20, 450), notch_freq=50)
Configure the EMG filters. Also enables on-board filtering.
Parameters:
bandpass_freqs(tuple):(low, high)cutoff frequencies in Hz.notch_freq(int | None): Mains notch frequency —50or60.None, or any other value, disables it.
configure_eda()
configure_eda(bandpass_freqs=(0, 5), signal_freq=0)
Configure the EDA filters and excitation frequency. Also enables on-board filtering.
Parameters:
bandpass_freqs(tuple):(low, high)cutoff frequencies in Hz.signal_freq(int): Excitation signal frequency in Hz.0for DC.
configure_ppg()
configure_ppg(ir=9, red=9, green=9, blue=9, sens=PpgSensitivity.MEDIUM)
Configure PPG LED currents and photodiode sensitivity. Also enables on-board filtering.
Parameters:
ir,red,green,blue(int): LED drive current in mA (1–50).sens(PpgSensitivity | str):LOW,MEDIUM,HIGH, orMAX.
The IMU is enabled with set_channels(imu=True) and has no
per-sensor configuration method. configure_imu() arrives in 2.0.
configure_sampling_freqs()
configure_sampling_freqs(ecg=500, emg=2000, eda=40, imu=50, ppg=50)
The package's own docstring marks it "Currently unused". It accepts the
values and returns a configuration response, but the device keeps its
default sampling rates. Per-sensor sampling rates only became settable in
2.0, via the fs parameter of each configure_* method.
set_filters()
set_filters(enable)
Enable or disable on-board filtering for all biochannels. Note the
configure_ecg/emg/eda/ppg methods already enable it.
Called set_onboard_filtering() from 2.0 onwards.
set_memory_mode()
set_memory_mode(memory_config)
Parameters:
memory_config(MemoryMode | str):STREAMING,DEVICE, orBOTH.
set_low_latency_mode()
set_low_latency_mode(on)
set_ble_power()
set_ble_power(power)
Parameters:
power(BleTxPower | str):LOW,MEDIUM, orHIGH.
Acquisition and data
start() / stop()
start() -> bool
stop() -> bool
Start and stop acquisition.
get_data()
get_data() -> dict
Wait for the next packet. Blocking — 1.3 has no timeout parameter,
so this call waits indefinitely if no packet arrives. The timeout
parameter was added in 2.0.
get_data_with_key()
get_data_with_key(keys) -> dict
Block until a packet containing the given key, or nested path of keys, arrives.
Parameters:
keys(str | Iterable[str]): A key, or a sequence describing a nested path.
Example:
packet = sb.get_data_with_key("ecg")
packet = sb.get_data_with_key(["data", "ecg"])
Use get_data() or the per-sensor getters instead.
get_ecg() / get_emg() / get_eda() / get_imu() / get_ppg() / get_temperature()
get_ecg()
Return the next packet for one specific sensor. None of these take a
timeout in 1.3.
Device commands
send_command()
send_command(command) -> bool
Send a command to the active device. This one method covers everything that
2.0 splits into individual methods (set_led(), set_motor(),
power_off(), and so on).
Parameters:
command(DeviceCommand | str): The command to send.
Example:
sb.send_command(sbp.DeviceCommand.OPEN_LED_1)
sb.send_command(sbp.DeviceCommand.START_MOTOR)
sb.send_command(sbp.DeviceCommand.POWER_OFF)
start_memory_download()
start_memory_download() -> int
Begin downloading the device's on-board memory.
Returns: the number of kilobytes to download.
Raises: ConnectionError if not connected; TypeError if the device
does not support memory download.
Depending on the output transport you either keep calling get_data()
(stdout, the default) or wait for a memory packet whose status is
MemoryDownloadCompleted.
Example:
kb = sb.start_memory_download()
print(f"Downloading {kb} kB...")
while True:
packet = sb.get_data()
if packet.get("packet_type") == "memory" and \
packet.get("status") == "MemoryDownloadCompleted":
break
2.0 provides download_memory_ble() / download_memory_serial(), which
block until the download finishes and export the data for you.
Enumerations
DeviceCommand
Commands accepted by send_command().
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"
The CLI additionally accepts test-memory and invalid, which this enum
does not model. Some commands are firmware-gated: set-eda-freq and
set-eda-gain need firmware 1.1+, stop-status-update needs 1.3+, and
download-memory-serial is firmware 1.2 only and unused.
DeviceType
class DeviceType(Enum):
BIOPOINT_V1_1 = "BioPoint_v1_1"
BIOPOINT_V1_2 = "BioPoint_v1_2"
BIOPOINT_V1_3 = "BioPoint_v1_3"
BIOARMBAND = "BioArmband"
SIFIBAND = "SiFiBand"
BleTxPower
class BleTxPower(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
MemoryMode
class MemoryMode(Enum):
STREAMING = "streaming" # Stream via BLE only
DEVICE = "device" # Save to device memory only
BOTH = "both" # Stream and save
PpgSensitivity
class PpgSensitivity(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
MAX = "max"
ListSources
class ListSources(Enum):
BLE = "ble" # Bluetooth devices
SERIAL = "serial" # Serial / USB devices
DEVICES = "devices" # Device managers
sifi_bridge_py 1.3.0 exports only the six enums above. PacketType,
PacketStatus, SensorChannel, BioChannel and DataPacket were all
introduced in 2.0 — in 1.3, packet fields are plain strings.