Skip to main content

Quick start

Get up and running with SiFi Bridge Python in just a few minutes. This guide covers the essential steps to connect to a device and start acquiring data.

Basic workflow​

Working with SiFi Bridge Python follows this pattern:

  1. Create a SifiBridge instance
  2. Connect to a device
  3. Configure sensors
  4. Start data acquisition
  5. Read data packets
  6. Stop and disconnect

Your first connection​

Here's a minimal example to connect and stream ECG data:

import time
import sifi_bridge_py as sbp

# Create bridge instance
sb = sbp.SifiBridge()

# Connect to the first available SiFi device (BioPoint or SiFi Band)
sb.connect()

# Sensors are off by default. Turn the ECG sensor on, then set its
# filter parameters (500 Hz sampling rate).
sb.configure_sensors(ecg=True)
sb.configure_ecg(fs=500)

# Start acquisition
sb.start()

# Collect for 10 seconds
start_time = time.time()
data_buffer = []

try:
while time.time() - start_time < 10:
packet = sb.get_data() # Get any packet
data_buffer.append(packet)
print(f"Received {packet['packet_type']} packet")

except KeyboardInterrupt:
print("Stopped by user")

finally:
sb.stop()
sb.disconnect()
print(f"Collected {len(data_buffer)} packets")

Understanding data packets​

Sensor data has the exact same structure as SiFi Bridge's, deserialized as a dictionary:

{
'device': 'BioPoint', # Device model
'id': 'BP_EF05', # Device identifier
'name': 'BioPoint_EF05', # BLE local name
'mac': 'FA:31:9F:7E:6A:A9', # Device MAC address (UUID on macOS)
'packet_type': 'ecg', # Type of data (ecg, emg, imu, ppg, etc.)
'status': 'ok', # Packet status
'received_at': 1790040045.074, # Packet arrival time (Unix epoch seconds)
'sample_rate': 500.25, # Measured sample rate of this sensor (Hz)
'timestamps': [0.198, 0.2, ...], # Per-sample times relative to acquisition start (s)
'data': {
'ecg': [0.001, 0.002, ...] # Sensor data arrays, one entry per timestamp
}
}
sample_rate is absent from the first packet

It is measured from inter-packet timing, so the first packet of each sensor arrives without it. Read it with packet.get("sample_rate").

Connect to a specific device​

connect() accepts either the device's name or its MAC address (Linux/Windows) / UUID (macOS):

import sifi_bridge_py as sbp

sb = sbp.SifiBridge()

# Scan. Each result carries the device's name and its id (MAC on
# Windows/Linux, UUID on macOS).
devices = sb.list_devices(sbp.ListSources.BLE)
print(f"Found devices: {devices}")
# [{'name': 'BioPoint_EF05', 'id': 'FA:31:9F:7E:6A:A9'}]

if not devices:
raise SystemExit("No SiFi device found — is it powered on and in range?")

# Connect to the first one found, by name...
sb.connect(devices[0]["name"])

# ...or by id, which is unambiguous when several devices share a name.
# sb.connect(devices[0]["id"])

connect() raises SifiBridgeError if the handle doesn't match a device in range, so pass a name or id you got from the scan rather than a hard-coded one.

Use sb.rename_device("MyBioPoint") once connected to give a device a memorable name so you can target it by name later. The custom name should not have space and be 14 characters maximum

Configure multiple sensors​

Enable and configure multiple sensors at once. configure_sensors() turns sensors on/off; each sensor's own configure_<sensor>() call sets its sampling rate and filter parameters:

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

# Set each sensor's sampling rate / filters
sb.configure_ecg(fs=500)
sb.configure_emg(fs=2000)
sb.configure_imu(fs=100)

# Start acquisition
sb.start()

# Read data from any sensor
ecg_packet = sb.get_ecg()
emg_packet = sb.get_emg()
imu_packet = sb.get_imu()

Simple data collection loop​

Collect data continuously with a loop:

import sifi_bridge_py as sbp
import time

sb = sbp.SifiBridge()
sb.connect()

# Enable sensors
sb.configure_sensors(ecg=True, emg=True, imu=True)

sb.start()

# Collect for 10 seconds
start_time = time.time()
data_buffer = []

try:
while time.time() - start_time < 10:
packet = sb.get_data() # Get any packet
data_buffer.append(packet)
print(f"Received {packet['packet_type']} packet")

except KeyboardInterrupt:
print("Stopped by user")

finally:
sb.stop()
sb.disconnect()
print(f"Collected {len(data_buffer)} packets")

Using threading​

Since get_data() blocks, use threading for responsive applications:

import time
import threading
import sifi_bridge_py as sbp

def data_collection_thread(sb):
"""Background thread for data collection"""
while running:
packet = sb.get_data(timeout=1.0)
if packet:
# Process packet
print(f"Got {packet['packet_type']}")

# Setup
sb = sbp.SifiBridge()
sb.connect()
sb.configure_sensors(ecg=True)
sb.start()

# Start background thread
running = True
thread = threading.Thread(target=data_collection_thread, args=(sb,))
thread.start()

# Do other work in main thread
time.sleep(30)

# Cleanup
running = False
thread.join()
sb.stop()
sb.disconnect()

Common patterns​

Check connection status​

info() raises SifiBridgeError if no device is currently connected, rather than returning a "not connected" status:

try:
info = sb.info()
print(f"Connected to {info['device']}")
except sbp.SifiBridgeError:
print("Not connected")

Retry connection​

import time

max_retries = 5
for attempt in range(max_retries):
if sb.connect():
print("Connected!")
break
print(f"Retry {attempt + 1}/{max_retries}")
time.sleep(2)

Wait for a packet with a timeout​

By default the get_* methods block indefinitely. Pass timeout (seconds) to give up and get {} back instead:

ecg_packet = sb.get_ecg(timeout=5.0)
if not ecg_packet:
print("No ECG packet received within 5 seconds")

Error handling​

Always include error handling for robust applications:

import sifi_bridge_py as sbp

try:
sb = sbp.SifiBridge()

# Try to connect
if not sb.connect():
raise ConnectionError("Failed to connect to device")

sb.configure_sensors(ecg=True)
sb.configure_ecg(fs=500)
sb.start()

# Collect data
for _ in range(100):
packet = sb.get_ecg()
# Process packet...

except ConnectionError as e:
# Also raised by connect() itself if Bluetooth is off
print(f"Connection error: {e}")
except KeyboardInterrupt:
print("Interrupted by user")
finally:
# Always cleanup. stop()/disconnect() block until the device
# confirms, so no extra sleep is needed here.
try:
sb.stop()
sb.disconnect()
except Exception:
pass

Quick reference​

# Import
import time
import sifi_bridge_py as sbp

# Create bridge
sb = sbp.SifiBridge()

try:
# Connection
sb.connect() # Connect to the first available device
sb.connect("MAC_OR_UUID") # Connect to a specific device by address
sb.disconnect() # Disconnect
# Configuration
sb.configure_sensors(ecg=True, emg=True) # Enable sensors (off by default)
sb.configure_ecg(fs=500, dc_notch=True, mains_notch=50, bandpass=True, flo=0, fhi=30) # Set ECG sampling rate / filters
sb.configure_emg(fs=2000, dc_notch=True, mains_notch=50, bandpass=True, flo=20, fhi=450) # Set EMG sampling rate / filters
sb.set_low_latency_mode(True) # Toggle low-latency mode (on by default, tradeoff between latency and bandwidth use)

# Control
sb.start() # Start acquisition
sb.stop() # Stop acquisition

# Data
packet = sb.get_data() # Get the next packet of any type
ecg = sb.get_ecg() # Get the next ECG packet
emg = sb.get_emg() # Get the next EMG packet
imu = sb.get_imu() # Get the next IMU packet

# Device commands
sb.set_led(1, True) # Turn LED 1 on
sb.set_motor(True) # Start the vibration motor
time.sleep(1)
sb.set_motor_intensity(10) # Set vibration motor intensity to 10
time.sleep(1)
sb.set_motor_intensity(5) # Set vibration motor intensity to 5
time.sleep(1)
sb.set_motor(False) # Stop the vibration motor
sb.set_led(1, False) # Turn LED 1 off
finally:
sb.stop()
sb.disconnect()