Python library for Sartorius balances (xBPI and SBI over serial).
Project description
sartoriuslib
Async-first Python driver for Sartorius lab
balances over RS-232 / USB. Speaks both wire protocols the hardware exposes —
xBPI (binary, length-prefixed, checksum-protected, SBN-addressed) and
SBI (ASCII command/response and autoprint) — behind a single semantic
Balance API that decodes to the same typed Reading either way.
Built as a sibling to
alicatlib: the same async
core, sync facade, multi-device manager, fake transport, acquisition helpers,
and pluggable sinks.
Status: alpha. Architecture is frozen and the public API is stable. Both protocol clients, the
Balancefacade,SartoriusManager, the recorder, all first-party sinks, the sync facade, and thesarto-*CLIs all ship in the base install. Hardware-coverage breadth and documentation polish are the active work; see the CHANGELOG.
Highlights
- One protocol-neutral API.
Balance.poll(),tare(),zero(),identify(),status(), parameter R/W — the same calls work over xBPI and SBI, decoding to identicalReading/BalanceStatus/DeviceInfomodels. - Auto-detect.
open_device(..., protocol=ProtocolKind.AUTO)does passive autoprint sniff → xBPI probe → SBI probe and reports clearly when nothing answers. - Typed end to end.
Unit.G,FilterMode.STABLE,Capability.HIRES_WEIGHT, frozen-dataclass responses,py.typed,mypy --strictclean. - Typed errors.
SartoriusErrorroot with structuredErrorContext; every xBPI0x01error subtype maps to a distinct exception. - Safety gates. Persistent and destructive operations require
confirm=True. Family/capability mismatches are soft by default (warn + attempt); opt in tostrict=Truefor pre-I/O refusal. - Multi-device.
SartoriusManagerruns many balances concurrently — same-port requests serialize, different ports run in parallel. - Acquisition built in.
record(...)drives one or many devices on an absolute-target cadence into pluggable sinks:InMemorySink,CsvSink,JsonlSink,SqliteSinkin core, plusParquetSinkandPostgresSinkbehind extras. - Swappable transports.
SerialTransportfor hardware,FakeTransportfor tests, fixture-backed transports for regression goldens. - Sync or async. Async core on
anyio; complete sync facade atsartoriuslib.syncvia a blocking portal — every async method has a sync parity. - CLI tooling.
sarto-read,sarto-discover,sarto-capture,sarto-raw,sarto-decode,sarto-configure, and thesarto-diagreverse-engineering namespace. - Lean core.
pip install sartoriuslibpulls inanyioandanyserial— nothing else.
Install
pip install sartoriuslib
# optional sinks
pip install 'sartoriuslib[parquet]' # ParquetSink (pyarrow)
pip install 'sartoriuslib[postgres]' # PostgresSink (asyncpg)
Requires Python 3.13+. Linux, macOS, BSD, and Windows are supported via
anyserial. On Linux, the user
running sarto-* needs read/write access to the serial device — usually by
joining the dialout group.
Quickstart (async)
import anyio
from sartoriuslib import open_device
async def main() -> None:
async with await open_device("/dev/ttyUSB0") as bal:
reading = await bal.poll()
print(reading.value, reading.unit, "stable" if reading.stable else "unstable")
await bal.tare()
anyio.run(main)
Sartorius balances ship from the factory speaking SBI. Pass
protocol=ProtocolKind.SBI (or ProtocolKind.AUTO) on first contact;
xBPI is a configuration choice you make on the device. See the
troubleshooting guide.
Quickstart (sync)
from sartoriuslib.sync import Sartorius
with Sartorius.open("/dev/ttyUSB0") as bal:
print(bal.poll())
bal.tare()
Multi-device acquisition
import anyio
from sartoriuslib import SartoriusManager
from sartoriuslib.streaming import record
from sartoriuslib.sinks import CsvSink, pipe
async def main() -> None:
async with SartoriusManager() as mgr:
await mgr.add("bal1", "/dev/ttyUSB0")
await mgr.add("bal2", "/dev/ttyUSB1")
async with (
record(mgr, rate_hz=10, duration=60) as stream,
CsvSink("run.csv") as sink,
):
await pipe(stream, sink)
anyio.run(main)
The recorder runs on an absolute target cadence (drift-free), batches
samples per tick, and reports send/receive timing on every Sample. See
examples/ for a runnable script that streams an Alicat MFC
and a Sartorius balance into one shared SQLite database concurrently.
Command-line tools
sarto-discover /dev/ttyUSB0 # probe + identify
sarto-read /dev/ttyUSB0 --protocol auto # one decoded poll
sarto-capture /dev/ttyUSB0 --rate 10 --duration 60 --out run.csv
sarto-decode --xbpi 02 02 48 ... # offline frame decode
sarto-raw /dev/ttyUSB0 --xbpi 0x02 --confirm # raw escape hatch
sarto-configure switch-protocol /dev/ttyUSB0 --confirm
sarto-diag snapshot /dev/ttyUSB0 --out diag.json # reverse-engineering aids
All CLIs accept --fixture FILE to drive a scripted FakeTransport, so
end-to-end tests and demos work without hardware.
Documentation
Full docs live at https://GraysonBellamy.github.io/sartoriuslib/. Useful entry points:
- Async quickstart / Sync quickstart
- Balances and capabilities
- Commands and safety tiers / Safety
- Streaming and acquisition / Logging
- Wire protocol reference
- Testing —
FakeTransport, fixtures, hardware tiers - Architecture (design doc)
Development
uv for env and lock management,
hatchling + hatch-vcs for builds, ruff for format and lint, mypy --strict and pyright for types, AnyIO's pytest plugin for the test
suite (parametrised across asyncio, asyncio+uvloop, and trio).
uv sync --all-extras --dev
uv run pre-commit install
uv run pytest
uv run ruff format --check .
uv run ruff check .
uv run mypy
Hardware tests are gated behind SARTORIUSLIB_ENABLE_STATEFUL_TESTS=1 and
SARTORIUSLIB_ENABLE_DESTRUCTIVE_TESTS=1 and require a connected balance.
See CONTRIBUTING.md for the workflow and SECURITY.md for the disclosure policy.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sartoriuslib-0.1.0.tar.gz.
File metadata
- Download URL: sartoriuslib-0.1.0.tar.gz
- Upload date:
- Size: 388.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c95e7954b4df1928d507f858e249cac7325e68a1973a42794c0f40524fbaf68b
|
|
| MD5 |
be80a0294d154b17b48b8496e652504c
|
|
| BLAKE2b-256 |
a2573210e974b6b9412103a7355c7d9b23d9947aea29671db7cb7d0394bb0eb9
|
Provenance
The following attestation bundles were made for sartoriuslib-0.1.0.tar.gz:
Publisher:
release.yml on GraysonBellamy/sartoriuslib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sartoriuslib-0.1.0.tar.gz -
Subject digest:
c95e7954b4df1928d507f858e249cac7325e68a1973a42794c0f40524fbaf68b - Sigstore transparency entry: 1383649172
- Sigstore integration time:
-
Permalink:
GraysonBellamy/sartoriuslib@99cd33976a7e228f626426898930b93c5cce754f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GraysonBellamy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@99cd33976a7e228f626426898930b93c5cce754f -
Trigger Event:
release
-
Statement type:
File details
Details for the file sartoriuslib-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sartoriuslib-0.1.0-py3-none-any.whl
- Upload date:
- Size: 213.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73cad07c19569a9ec4d641a387ea5f4ce2c48d406a24fe94203dfd7f1e3d0f1a
|
|
| MD5 |
f763e9274eba1e5af60f84b2372b9137
|
|
| BLAKE2b-256 |
77b678a4c641cc112f52b7e22b3c2f9852f8f1fb9863f3561c4f68e5d8895354
|
Provenance
The following attestation bundles were made for sartoriuslib-0.1.0-py3-none-any.whl:
Publisher:
release.yml on GraysonBellamy/sartoriuslib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sartoriuslib-0.1.0-py3-none-any.whl -
Subject digest:
73cad07c19569a9ec4d641a387ea5f4ce2c48d406a24fe94203dfd7f1e3d0f1a - Sigstore transparency entry: 1383649226
- Sigstore integration time:
-
Permalink:
GraysonBellamy/sartoriuslib@99cd33976a7e228f626426898930b93c5cce754f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GraysonBellamy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@99cd33976a7e228f626426898930b93c5cce754f -
Trigger Event:
release
-
Statement type: