API reference
Complete API reference for the SiFi Bridge Python package (sifi_bridge_py), version 2.0.
SiFi Bridge 2.0 reworked the Python API. The most common breaking changes:
| 1.x | 2.0 |
|---|---|
SifiBridge(publishers=...) | Removed. Use the CLI's --tcp-out/--udp-out, or use_lsl=True. |
sb.send_command(DeviceCommand.X) | Removed, along with the DeviceCommand enum. Each command is now its own method (set_led(), set_motor(), power_off(), …). |
sb.create_device(name) / delete_device() | Removed. connect() creates a real session keyed by the device's BLE id; select_device() switches between them. |
sb.show() | sb.info() |
sb.configure_ecg(state=True, ...) | configure_sensors(ecg=True) turns the sensor on; configure_ecg() only sets parameters. |
sb.configure_imu(gyro_range=...) | Removed — see configure_imu(). |
sb.set_filters(...) | set_onboard_filtering() |
sb.configure_sampling_freqs(...) | Removed. Use the per-sensor configure_* methods. |
sb.get_data_with_key(...) | Removed. Use get_data() or the per-sensor getters. |
sb.start_memory_download() / is_memory_download_completed() | download_memory_ble() / download_memory_serial(), which block until done and export for you. |
packet field timestamp | received_at |
SifiBridge class
The main class for interacting with SiFi devices.
Constructor
SifiBridge(use_lsl=False)
Spawn a sifibridge subprocess and connect to its data channel. The
constructor launches the bundled CLI and starts background threads that
read its responses and its data stream.
Parameters:
use_lsl(bool): IfTrue, pass--lslsosifibridgealso streams data to Lab Streaming Layer outlets.
SiFi Bridge publishes one outlet per channel, not one per sensor — a
fully-enabled BioPoint surfaces 15 outlets, because the IMU is split into
seven (ax, ay, az, qw, qx, qy, qz) and the PPG into four
(ir, r, g, b). Outlets are named <device id>:<channel>. See the
CLI's transports page for the full stream layout.
Example:
import sifi_bridge_py as sbp
# Packets are read with sb.get_data().
sb = sbp.SifiBridge()
# Also publish the data stream to Lab Streaming Layer outlets.
sb = sbp.SifiBridge(use_lsl=True)
SifiBridge is a context manager, which is the recommended way to use
it — the subprocess is shut down for you on exit:
with sbp.SifiBridge() as sb:
sb.connect()
...
The constructor uses the sifibridge binary bundled with the
sifibridge_bin package. No separate installation is required.
Targeting multiple devices
One SifiBridge instance can manage several connected devices. Call
connect() once per device; each one gets a session keyed by
its stable BLE id. Commands apply to the active device (the most
recently connected, or whichever you pass to
select_device()) unless you widen the target:
all=True— apply to every managed devicedevices="handle"ordevices=["h1", "h2"]— apply to a specific subset
Every method that acts on hardware accepts both. When you target several devices, the return value is a list of per-device responses instead of a single payload.
sb.connect("BioPoint_EF05")
sb.connect("BioPoint_AB12")
sb.start(all=True) # both
sb.set_led(1, True, devices="BioPoint_EF05") # just one
Connection methods
connect()
connect(handle=None, timeout=10.0) -> bool
Connect to a SiFi device. On success a session is created and becomes the active device.
Parameters:
handle(str | None): Device name, MAC address (Windows/Linux) or UUID (macOS).Noneauto-connects to the first device found.timeout(float): Seconds to wait for the connection.
Returns: True if the connection succeeded.
Example:
sb.connect() # first available device
sb.connect("BioPoint_EF05") # by name
sb.connect("FA:31:9F:7E:6A:A9") # by MAC (Windows/Linux)
disconnect()
disconnect() -> bool
Disconnect the active device and remove its session. Buffered
acquisitions are retained — use buffer_clear() to drop
them.
list_devices()
list_devices(source) -> list[dict]
List devices from a given source.
Parameters:
source(ListSources | str): One ofListSources.BLE(scan for BLE devices),ListSources.SERIAL(serial ports), orListSources.DEVICES(currently connected sessions).
Returns: A list of dicts with name and id keys.
Example:
for dev in sb.list_devices(sbp.ListSources.BLE):
print(dev["name"], dev["id"])
select_device()
select_device(name) -> str
Choose which connected device subsequent commands target.
Parameters:
name(str): Device id or local name.
get_active_device()
get_active_device() -> str
Return the id of the currently selected device.
rename_device()
rename_device(name=None) -> dict
Rename the active device. Names are limited to 14 bytes of ASCII.
Parameters:
name(str | None): The new name.Noneresets the device to its factory default name.
Device information
info()
info() -> dict
Return everything the bridge knows about the active device: its id,
name, model, connection state, and a nested configuration block with
the full sensor configuration.
Example:
info = sb.info()
print(info["name"], info["device"])
print(info["configuration"]["ecg"]["fs"])
get_configuration()
get_configuration() -> dict
Return just the configuration block from info() — the
applied sampling rates, filters, memory mode, and so on.
get_sensors()
get_sensors() -> dict
Return the enabled/disabled state of every sensor, including
temperature.
get_sensor_states()
get_sensor_states() -> dict
Return the enabled/disabled state of the five configurable biosignal
sensors (ecg, emg, eda, imu, ppg).
get_device_state()
get_device_state() -> str | None
Return the device's reported state string (e.g.
"connected_memory_ble_working"), or None if it is not yet known.
get_battery()
get_battery() -> int | None
Return the last reported battery percentage, or None if no status
packet has arrived yet.
Battery level arrives in status packets. Enable them with
set_status_updates(True) and allow a packet to
arrive before reading, otherwise this returns None.
Sensor configuration methods
Sensors are turned on and off with
configure_sensors(). The per-sensor
configure_* methods only set parameters — they do not enable the
sensor.
Every parameter of every configure_* method is optional and defaults
to None, meaning "leave this setting as it is". configure_ecg(fs=1000)
changes only the sampling rate and preserves the filters you set earlier.
configure_sensors()
configure_sensors(ecg=None, emg=None, eda=None, imu=None, ppg=None,
all=False, devices=None)
Enable or disable sensors. A sensor left as None keeps its current
state, so configure_sensors(ppg=True) enables PPG without disturbing
the others.
Example:
sb.configure_sensors(ecg=True, imu=True)
sb.configure_sensors(ppg=False) # turn PPG off, leave the rest alone
configure_ecg()
configure_ecg(fs=None, dc_notch=None, mains_notch=None, bandpass=None,
flo=None, fhi=None, all=False, devices=None)
Parameters:
fs(int): Sampling rate in Hz —250,500,1000,2000.dc_notch(bool): Enable the DC notch filter.mains_notch(int | str): Mains notch frequency —50or60. Pass"off"(or0/False) to disable,Noneto leave unchanged.bandpass(bool): Enable the bandpass filter.flo(int): Bandpass lower cutoff in Hz.fhi(int): Bandpass higher cutoff in Hz.
Example:
sb.configure_sensors(ecg=True)
sb.configure_ecg(fs=500, mains_notch=60, bandpass=True, flo=0, fhi=30)
configure_emg()
configure_emg(fs=None, dc_notch=None, mains_notch=None, bandpass=None,
flo=None, fhi=None, all=False, devices=None)
Same parameters as configure_ecg(), except:
fs(int): Sampling rate in Hz —500,1000,1600,2000.
Example:
sb.configure_sensors(emg=True)
sb.configure_emg(fs=2000, mains_notch=60, bandpass=True, flo=20, fhi=450)
configure_eda()
configure_eda(fs=None, dc_notch=None, mains_notch=None, bandpass=None,
flo=None, fhi=None, freq=None, all=False, devices=None)
Same parameters as configure_ecg(), plus:
fs(int): Sampling rate in Hz —5,25,50,100.freq(int): Excitation signal frequency in Hz.0for DC.
Example:
sb.configure_sensors(eda=True)
sb.configure_eda(fs=50, freq=0)
configure_ppg()
configure_ppg(sps=None, ir=None, red=None, green=None, blue=None,
sens=None, avg=None, all=False, devices=None)
Parameters:
sps(int): Raw AFE sample rate in Hz —50,100,200,400,800.ir,red,green,blue(int): LED drive current in mA (0–50).sens(PpgSensitivity | str): Photodiode sensitivity —low,medium,high,max.avg(int): Averaging factor —1,2,4,8,16,32.
The effective output rate is sps / avg — sps=400 with avg=4 yields
100 Hz — and is reported live in each packet's sample_rate.
Raises: ValueError if avg is not positive, or if sps / avg
exceeds 200 Hz.
configure_ppg() rejects any sps/avg pair whose effective rate
exceeds 200 Hz, even though the CLI itself accepts up to 800 Hz.
Setting only one of the two is fine — the other is read back from the
device so the cap can still be checked.
Example:
sb.configure_sensors(ppg=True)
sb.configure_ppg(sps=400, avg=4, ir=9, red=9, sens=sbp.PpgSensitivity.MEDIUM)
configure_ppg_fs()
configure_ppg_fs(fs, avg=None, ir=None, red=None, green=None, blue=None,
sens=None, all=False, devices=None)
Configure PPG by the output rate you want, rather than by sps.
This works out an sps/avg pair that delivers fs and hands it to
configure_ppg().
By default it picks the pair with the most averaging — the highest sps
that still divides down to fs — since more raw samples per delivered
sample means a cleaner signal, at the cost of running the LEDs harder.
Pass avg explicitly to choose the trade-off yourself.
Parameters:
fs(int): Wanted output rate in Hz, up to 200.avg(int): Averaging factor to use. Defaults to the largest that can deliverfs.- Remaining parameters are as in
configure_ppg().
Raises: ValueError if no sps/avg pair delivers fs, or if fs
exceeds the 200 Hz cap. The message lists the reachable rates.
Example:
sb.configure_ppg_fs(100) # picks sps=800, avg=8
sb.configure_ppg_fs(100, avg=1) # picks sps=100, avg=1
configure_imu()
configure_imu(fs=None, accel_range=None, all=False, devices=None)
Parameters:
fs(int): Sampling rate in Hz —25,50,100,200.accel_range(int): Accelerometer range in g —8or16.
Raises: ValueError if accel_range is not 8 or 16.
SiFi Bridge 2.0 removed the gyroscope range setting. The firmware reads
the IMU through its 20-bit high-resolution FIFO, which pins the
gyroscope full scale per IMU part, so the setting never changed the
delivered range. The IMU part is reported as chip in
info(), and the pinned full scale for each part is in the
device spec sheet.
Example:
sb.configure_sensors(imu=True)
sb.configure_imu(fs=100, accel_range=8)
configure_temperature()
configure_temperature(fs=None, all=False, devices=None)
Parameters:
fs(float): Sampling rate in Hz —0.1,1,2,10.
Device configuration methods
set_onboard_filtering()
set_onboard_filtering(enable, all=False, devices=None)
Enable or disable on-board filtering for all sensors.
set_high_gain()
set_high_gain(enable, all=False, devices=None)
Enable high gain on the ECG and EMG ADC. High gain uses more of the dynamic range but saturates more easily.
set_ble_power()
set_ble_power(power, all=False, devices=None)
Parameters:
power(BleTxPower | str):LOW,MEDIUM, orHIGH.
set_memory_mode()
set_memory_mode(memory_config, all=False, devices=None)
Parameters:
memory_config(MemoryMode | str):STREAMING,DEVICE, orBOTH.
SiFiBand only supports STREAMING.
set_low_latency_mode()
set_low_latency_mode(on, all=False, devices=None)
Pack data from multiple sensors into each BLE packet, reducing per-sensor latency at the cost of roughly 10% BLE bandwidth overhead. Enabled by default.
set_night_mode()
set_night_mode(enable, all=False, devices=None)
Disable the device LEDs during an acquisition (e.g. for sleep studies).
set_status_updates()
set_status_updates(on, all=False, devices=None)
Start or stop periodic status packets, which carry battery level,
used memory, and device state.
Device control methods
set_led()
set_led(index, on, all=False, devices=None)
Parameters:
index(int): LED to set —1or2.on(bool):Trueto turn on.
Raises: ValueError if index is not 1 or 2.
set_motor()
set_motor(on, all=False, devices=None)
Start or stop the vibration motor.
set_motor_intensity()
set_motor_intensity(level, all=False, devices=None)
Set the vibration motor intensity. The motor only vibrates while it is running; the intensity persists until changed.
Parameters:
level(int): Intensity, 1 to 10.
Raises: ValueError if level is not between 1 and 10.
Example:
sb.set_motor_intensity(5)
sb.set_motor(True)
time.sleep(1)
sb.set_motor(False)
power_off()
power_off(all=False, devices=None)
Power the device off. Connect it via USB to power it back on.
dfu()
dfu(package, handle=None, resume=False, timeout=1800.0) -> dict
Update a device's firmware over BLE.
Parameters:
package(str): Path to the DFU zip package. Paths with spaces are fine; the wrapper quotes them.handle(str | None): Device to update. Defaults to the active device.resume(bool): Resume a DFU that was interrupted.timeout(float): How long to wait for the update to finish.
Raises: SifiBridgeError if the bridge returns an error response.
Data acquisition methods
start()
start(all=False, devices=None, set_default=False)
Start data acquisition, pushing the staged configuration to the device.
Parameters:
set_default(bool): Also store the current configuration as the device's default, used for button-initiated acquisitions.
stop()
stop(all=False, devices=None)
Stop data acquisition.
send_event()
send_event(all=False, devices=None)
Generate a software event, inserting an event marker into the data stream.
get_data()
get_data(timeout=None) -> dict
Pop the next sensor-data packet of any type.
Parameters:
timeout(float | None): Seconds to wait.Noneblocks indefinitely.
Returns: A packet dict, or {} if the timeout elapses.
Each packet is queued both in the generic queue and in its sensor
queue, so interleaving get_data() with get_ecg(), get_emg() and
friends on the same instance returns duplicates. Pick one style per
SifiBridge instance.
get_ecg() / get_emg() / get_eda() / get_imu() / get_ppg() / get_temperature() / get_event()
get_ecg(timeout=None) -> dict
Pop the next packet for one specific sensor, ignoring all others.
Each takes the same optional timeout and returns {} on expiry.
clear_data_buffer()
clear_data_buffer() -> int
Discard any packets currently sitting in the bridge's internal queues.
Useful right after start() to drop startup transients before the
recording window begins.
Returns: The number of packets discarded.
close()
close() -> None
Shut down the sifibridge subprocess and its worker threads. Called
automatically when used as a context manager.
Buffer methods
SiFi Bridge buffers every acquisition, so data can be queried after the fact and exported to disk. See the CLI's Buffering page for how buffers are filled and retained.
buffer_list()
buffer_list(device=None) -> list[dict]
List acquisitions and their status.
buffer_info()
buffer_info(device=None, acquisition_id=None) -> dict
Get acquisition details, including the device configuration used.
acquisition_id defaults to the latest acquisition.
buffer_pull()
buffer_pull(sensor, device=None, acquisition_id=None,
last_seconds=None, from_=None, to=None) -> list[dict]
Pull buffered sensor data out of an acquisition.
Parameters:
sensor(str | list[str]): Sensor type, or list of them —ecg,emg,emg_armband,eda,imu,ppg,temperature,event.device(str | None): Device id or name. Defaults to the active device.acquisition_id(int | None): Defaults to the latest acquisition.last_seconds(float | None): Pull only the last N seconds. Mutually exclusive withfrom_/to.from_(float | None): Start of a relative time range, in seconds since recording start. Requiresto.to(float | None): End of that range. Requiresfrom_.
Returns: A list of per-sensor dicts with keys sensor, timestamps
and values (channel name → samples).
Raises: ValueError if the time-range arguments are combined illegally.
Example:
[ecg] = sb.buffer_pull("ecg", last_seconds=10)
print(len(ecg["timestamps"]), "samples")
both = sb.buffer_pull(["ecg", "imu"], from_=5.0, to=15.0)
buffer_export()
buffer_export(fmt="csv", output_dir=".", device=None) -> dict
Export a device's buffered acquisitions to file.
Parameters:
fmt(str):"csv"or"hdf5".output_dir(str): Directory to write to. Paths with spaces are fine; the wrapper quotes them.device(str | None): Defaults to the active device.
buffer_clear()
buffer_clear(device=None, acquisition_id=None, all=False) -> dict
Clear buffered data — one acquisition, one device's acquisitions, or
everything with all=True.
Memory management methods
download_memory_ble()
download_memory_ble(output_dir, fmt="csv", timeout=43200) -> dict
Download the active device's onboard memory over BLE and export it.
In 2.0 the bridge's download-memory loads recordings into the
buffering subsystem rather than writing files, so this blocks until the
download completes and then runs buffer_export() for
you.
Parameters:
output_dir(str): Directory to save the exported data.fmt(str):"csv"or"hdf5".timeout(float): How long to wait. Downloading a full flash over BLE takes hours, hence the very long default.
Raises: SifiBridgeTimeout if the download does not finish in time.
download_memory_serial()
download_memory_serial(port, output_dir, fmt="csv", timeout=14400) -> dict
The same, over a serial port — significantly faster than BLE.
Parameters:
port(str): Serial port, e.g."COM3"or"/dev/ttyACM0".
erase_onboard_memory()
erase_onboard_memory(format=False, all=False, devices=None)
Erase the recordings stored in the device's on-board memory.
Parameters:
format(bool): Fully format the flash instead of only erasing stored recordings. Takes longer, but leaves the memory completely clear.
Exceptions
SifiBridgeError
class SifiBridgeError(RuntimeError)
Raised when sifibridge returns an error response.
SifiBridgeTimeout
class SifiBridgeTimeout(SifiBridgeError)
Raised when a command or download does not complete within its timeout.
Enumerations
DeviceType
Device models reported in the device field.
class DeviceType(Enum):
BIOPOINT = "BioPoint"
SIFIBAND = "SiFiBand"
SIFIBAND_FOCUS = "SiFiBandFocus"
BIOPOINT_V1_1 = "BioPoint_v1_1"
BIOPOINT_V1_2 = "BioPoint_v1_2"
BIOPOINT_V1_3 = "BioPoint_v1_3"
INVALID = "Invalid"
PacketType
Data packet types delivered by the bridge.
class PacketType(Enum):
ECG = "ecg"
EMG = "emg"
EDA = "eda"
IMU = "imu"
PPG = "ppg"
EMG_ARMBAND = "emg_armband"
TEMPERATURE = "temperature"
MEMORY = "memory"
STATUS = "status"
START_TIME = "start_time"
EVENT = "event"
INVALID = "invalid"
The bridge's own packet-type schema declares three values this enum is
missing — device_info, low_latency and start_packet — and
device_info is emitted in practice, once per connection. So
PacketType(packet["packet_type"]) # ValueError on a device_info packet
will raise. Compare against the string, or guard the conversion:
try:
ptype = PacketType(packet["packet_type"])
except ValueError:
ptype = None # a packet type this wrapper version doesn't model
PacketStatus
Packet status values.
class PacketStatus(Enum):
OK = "ok"
RECORDING = "recording"
MEMORY_DOWNLOAD_COMPLETED = "memory_download_completed"
MEMORY_ERASED = "memory_erased"
INVALID_DATETIME = "invalid_datetime"
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"
EVENT = "event"
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)
BioChannel
Every individual channel name the bridge can emit, including the
status-packet fields. Useful when iterating over data generically.
| Member | Value | Member | Value |
|---|---|---|---|
ECG | ecg | EMG0–EMG7 | emg0–emg7 |
EMG | emg | TEMPERATURE | temperature |
EDA | eda | EVENT | event |
IMU | imu | BATTERY | battery_% |
AX, AY, AZ | ax, ay, az | MEMORY_USED_KBYTES | memory_used_kbytes |
QW, QX, QY, QZ | qw, qx, qy, qz | YEAR, MONTH, DAY | year, month, day |
PPG | ppg | HOUR, MINUTE, SECOND | hour, minute, second |
IR, RED, GREEN, BLUE | ir, r, g, b |
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" # Scan for Bluetooth devices
SERIAL = "serial" # Serial / USB ports
DEVICES = "devices" # Currently connected device sessions
Data packet structure
All sensor packets follow the same general shape:
{
'device': str, # Device model, e.g. 'BioPoint'
'id': str, # Device id, e.g. 'BP_EF05'
'name': str, # BLE local name, e.g. 'BioPoint_EF05'
'mac': str, # Device MAC address or UUID
'packet_type': str, # One of PacketType
'status': str, # One of PacketStatus
'received_at': float, # Packet time of arrival (Unix epoch seconds)
'sample_rate': float, # Measured effective rate for this sensor (Hz)
'timestamps': [float], # Per-sample times, in seconds since acquisition start
'data': { # Sensor-specific samples
'<channel>': [float, ...],
...
},
}
timestamps and the per-channel sample arrays inside data always have
the same length: one timestamp per sample.
device, id, name, mac, packet_type, status and received_at
are always present. The rest are optional, and some packet types carry
extra fields — start_time packets add start_time, status packets
add device_state, memory-download packets add download_progress, and
any packet may carry samples_lost. See the CLI's
Data output page for the full field reference.
sample_rate is measured by SiFi Bridge from inter-packet timing, so
the very first packet of each sensor arrives without it. Treat it as
optional:
rate = packet.get("sample_rate")
It converges on the configured rate and may oscillate slightly around it
because of Bluetooth jitter. status and start_time packets never
carry one.
ECG packet
{
'device': 'BioPoint', 'id': 'BP_EF05', 'name': 'BioPoint_EF05',
'mac': 'FA:31:9F:7E:6A:A9',
'packet_type': 'ecg', 'status': 'ok',
'received_at': 1790040045.074,
'sample_rate': 500.25,
'timestamps': [0.0, 0.002, 0.004, ...],
'data': {'ecg': [0.00123, 0.00119, ...]},
}
EMG packet (BioPoint)
A single EMG channel.
{
'packet_type': 'emg', 'status': 'ok',
'sample_rate': 2000.9,
'timestamps': [0.0, 0.0005, 0.001, ...],
'data': {'emg': [0.00012, 0.00015, ...]},
}
EMG packet (SiFiBand)
The 8-channel array, delivered as emg_armband.
{
'packet_type': 'emg_armband', 'status': 'ok',
'timestamps': [0.0, 0.000625, ...],
'data': {
'emg0': [...], 'emg1': [...], 'emg2': [...], 'emg3': [...],
'emg4': [...], 'emg5': [...], 'emg6': [...], 'emg7': [...],
},
}
EDA packet
{
'packet_type': 'eda', 'status': 'ok',
'sample_rate': 50.03,
'timestamps': [0.0, 0.02],
'data': {'eda': [0.0, 0.0]},
}
IMU packet
Quaternion orientation and acceleration in g.
{
'packet_type': 'imu', 'status': 'ok',
'sample_rate': 100.0,
'timestamps': [0.0, 0.01, 0.02],
'data': {
'qw': [0.892717, ...], 'qx': [-0.417280, ...],
'qy': [0.170099, ...], 'qz': [0.0, ...],
'ax': [-2.045347, ...], 'ay': [-5.017566, ...],
'az': [3.999683, ...],
},
}
PPG packet
{
'packet_type': 'ppg', 'status': 'ok',
'sample_rate': 100.05,
'timestamps': [0.0, 0.01],
'data': {
'ir': [7243.27, ...], 'r': [8071.35, ...],
'g': [8063.50, ...], 'b': [8083.54, ...],
},
}
Temperature packet
Skin temperature in °C.
{
'packet_type': 'temperature', 'status': 'ok',
'sample_rate': 1.0,
'timestamps': [0.0, 1.0],
'data': {'temperature': [24.281916, 24.281916]},
}
Status packet
Emitted about once a second while
set_status_updates(True) is on.
{
'packet_type': 'status', 'status': 'recording',
'received_at': 1790040045.433,
'timestamps': [1790040045.433],
'data': {
'temperature': [0.0],
'battery_%': [85.0],
'memory_used_kbytes': [37336.625],
},
'device_state': 'connected_memory_ble_working',
}
Start-time packet
Sent once at the beginning of an acquisition, giving the wall-clock time the recording started.
{
'packet_type': 'start_time', 'status': 'ok',
'timestamps': [1790040045.044],
'data': {
'year': [2026.0], 'month': [9.0], 'day': [21.0],
'hour': [21.0], 'minute': [20.0], 'second': [45.0],
},
'start_time': 1790040045.0,
}
Event packet
Emitted by send_event(), and readable with
get_event().
{
'packet_type': 'event', 'status': 'ok',
'timestamps': [1.51],
'data': {'event': [2.0]},
}
The value in data['event'] is a counter that increments with each
event in the acquisition, and timestamps places it relative to the
recording start.