Choose a sink#
A sink is where collected samples land. BdfCsvSink (one BDF file for one test object) is the default and right for most bench work; battfeed ships three more for the cases it is not.
One stream, many objects: RoutingSink#
When one connection yields samples from several physical objects or test runs — a fleet gateway, per-flight logs — sources stamp two reserved keys that say where a sample belongs rather than what was measured: series_id (which object) and run_id (which test-run segment). RoutingSink demultiplexes on them: it sanitises raw device serials into safe BDF cell names, opens each object’s file lazily on its first sample, optionally rotates by time or row count, and reports what it wrote via files_by_series.
from battfeed import Harvester, RoutingSink
sink = RoutingSink(out_dir="fleet", institution="SINTEF")
Harvester().collect("my-gateway", duration_s=3600, interval_s=5, sink=sink)
print(sink.files_by_series)
A source that emits routing keys must supply its own test_time_second, zero-based per (series_id, run_id) — the harvester’s shared elapsed-collection clock is wrong for an object that appears mid-run. Note the split in key handling: BdfCsvSink strips routing keys (they are never BDF columns), while the Parquet and HTTP sinks keep them so downstream code can group by object and run.
Feed a server: HttpPushSink#
POSTs samples as gzipped newline-delimited JSON to any HTTP endpoint on a time cadence, stdlib-only. Delivery is at-least-once: rows are kept on a failed POST and spooled to a loadable .spool.ndjson if the endpoint stays down, so a dead server costs you latency, never data. Use it to feed a registry or lab server; it is a sink, not a hosted service — battfeed runs no server (why). Put the endpoint token in a config file.
Analyze in pandas/Polars/DuckDB: ParquetSink#
pip install "battfeed[parquet]"
One Parquet file (plus the same .meta.json sidecar) per bounded capture. Use it for finite analytical captures, not unbounded telemetry — that is RoutingSink + BDF.
Rules that hold for every sink#
Whatever the sink, the sidecar contract is the same (finalized flips true only on clean close), the sign convention is BDF’s (positive current charges), and the harvester’s error policy stands between the source and the sink. The full output contract is in the reference.