Skip to main content

SLM Open API Package

Python helpers for streaming measurements and audio from an HBK sound level meter (SLM) through WebXi.

This PyPI package is made for the Open Interface for Sound Level Meter repository. Refer to that repository for more detailed usage information and additional examples.

Install

pip install slm_open_api_package

Or add it to an uv project:

uv add slm_open_api_package

The package requires Python 3.12 or newer and a network connection to a compatible SLM.

Connect To A Device

Give every stream one host, either an IP address or host name:

host = "192.168.1.183"

The bundled examples use set_host() to read a host from a local slm_ip file. If the file is missing, it prompts once and creates it:

from slm_api.helpers import webxi_helper_functions as webxi_helper

host = webxi_helper.set_host(__file__)

Basic Leq Stream

WebXiStreamHandler is the main API. mode="leq" is the default and streams one sequence selected by sequenceID.

from slm_api.enums.sequence_id_enum import SequenceIdEnums
from slm_api.helpers.stream_handlers import WebXiStreamHandler

streamer = WebXiStreamHandler(
	host="192.168.1.183",
	sequenceID=SequenceIdEnums.LAeq.value,
	mode="leq",
	saving="csv",
	saving_path="saved_data/laeq",
)

try:
	streamer.startStream()
except KeyboardInterrupt:
	streamer.stopStream()

JSON and CSV process pending batches in a background worker, normally once per second, and release saved records from memory. CSV combines consecutive measurements per host and timestamp into wide rows, such as host,timestamp,LAeq,LCeq, with only fields actually supplied. With timestamps disabled, the layout is host,LAeq,LCeq; a repeated measurement name starts the next row. CSV retains the latest row per host across batches until the timestamp changes, a measurement name repeats, or close() flushes it. Vectors and structured fields are JSON-encoded cells. Newly encountered columns trigger an atomic, streaming rewrite of the existing CSV header and rows; otherwise completed rows are appended. Existing plot readers accept this wide layout. JSON writes a sibling .jsonl journal during recording. On close(), it converts the journal to the original host-grouped .json layout with two-space indentation, merging consecutive named values per host and timestamp across batch boundaries. Conversion spools records to temporary files per host and keeps only one output row at a time in memory, rather than loading the recording. The final JSON is replaced only after conversion succeeds, then the JSONL journal is deleted. If writing or conversion fails, the journal remains for recovery. If journal deletion fails, calling close() again retries deletion without reconverting the JSON. Each handler starts a new recording rather than resuming an existing file with the same name. Do not share an output path between handlers.

Construct JsonDataHandler(path, snapshot_interval=2.0, max_pending_records=10000) or CsvDataHandler(...) and attach it with setDataHandler() to adjust batching and the pending-record limit. At the limit, handle() raises BufferError and does not accept the incoming record; accepted records remain buffered. This bounds the number of queued records, not their individual byte sizes; CSV additionally retains one incomplete row per host and the column names. close() waits up to five seconds for the worker and flushes remaining records; final disk writes and JSON conversion can still take longer. WAV still appends each audio chunk without buffering the recording in memory. Measurement saving formats are "csv" and "json"; audio uses "wav". File extensions are added automatically.

If appending raises PermissionError (for example, a CSV is locked in Excel), the worker warns once per failure episode and retries at the next interval. Partial appends are truncated back to the previous batch boundary before retrying; failure to roll back is fatal. Close the program holding the output file open, or correct its permissions, to allow saving to resume. A lock still present at close() raises an error; unsaved records only remain in memory while the process is alive. Other background write failures are reported on subsequent updates and on close. A process crash can still leave an incomplete final batch, so this is not a transactional storage format. stopStream() still attempts device cleanup if closing the saving handler fails.

Multiple Sequences

Based on example_multi.py, use mode="multi" for several enabled broadband sequences in a single stream:

from slm_api.helpers.data_handler import DataHandler
from slm_api.helpers.stream_handlers import WebXiStreamHandler


class PrintHandler(DataHandler):
	def handle(self, *, host, name, value, **data):
		print(f"{host} {name}: {value}")


streamer = WebXiStreamHandler(
	host="192.168.1.183",
	sequenceNames=["LAeq", "LCeq", "LAF"],
	mode="multi",
	saving="json",
	saving_path="saved_data/broadband",
)
streamer.setDataHandler(PrintHandler())

try:
	streamer.startStream()
except KeyboardInterrupt:
	streamer.stopStream()

Enable the requested sequences and frequency weightings on the SLM before starting the stream. Each DataHandler.handle() call receives the source host, name, and value. The saving= handler continues saving when a custom handler is attached.

Fast Logging

Based on fast_log_example.py, use mode="fast_logging" for fast broadband samples:

from slm_api.enums.fast_log_intervals_enum import FastLogInterval
from slm_api.enums.sequence_id_enum import SequenceIdEnums
from slm_api.helpers.stream_handlers import WebXiStreamHandler

streamer = WebXiStreamHandler(
	host="192.168.1.183",
	sequenceID=SequenceIdEnums.FastLAF.value,
	mode="fast_logging",
	fast_logging_interval=FastLogInterval.interval_1000ms.value,
	saving="csv",
	saving_path="saved_data/fast_laf",
)

try:
	streamer.startStream()
except KeyboardInterrupt:
	streamer.stopStream()

Audio

Use the MP3 or FLAC examples for decoded audio samples:

from slm_api.enums.sequence_id_enum import SequenceIdEnums
from slm_api.helpers.stream_handlers import WebXiStreamHandler

streamer = WebXiStreamHandler(
	host="192.168.1.183",
	sequenceID=SequenceIdEnums.MP3Signal.value,
	mode="mp3",
	saving="wav",
	saving_path="saved_data/audio",
)

try:
	streamer.startStream()
except KeyboardInterrupt:
	streamer.stopStream()

The matching flac form uses SequenceIdEnums.FLACSignal.value and mode="flac". Audio setup is enabled by the handler. The SLM can take a few seconds to initialize audio recording when its quality setting changes.

For GUI plots, check the read-only streamer.audio_ready property in the plot's timer callback before reading DataBuffer. It becomes True after the first nonempty decoded audio has been written to the buffer, without requiring a custom DataHandler or event. It resets when the streaming session starts, when a stop is requested, and when the session exits. This is a startup gate, not a full-window availability check or a detector for stalled streams. Keep running the GUI event loop while waiting for audio.

WAV saving appends decoded mono samples as recording happens, updating the file header after each chunk so the file is readable before shutdown. Saving happens after decoding and calibration to pascals. Samples are divided by the fixed full-scale pressure calibrationFactor * (2**23 - 1) and saved as PCM_24, not peak-normalized per chunk. The filename includes _fullscale-<value>Pa.wav. To recover pressure values, multiply floating-point samples read from the WAV by that full-scale value (within 24-bit quantization accuracy). Samples outside the calibrated range produce a clipping warning; this scaling cannot repair upstream clipping. MP3 uses the decoded sample rate; the current FLAC decoder uses 65536 Hz. JSON and CSV saving are rejected for audio modes, and WAV saving is rejected for measurement modes. Run uv sync to install the soundfile dependency used for progressive WAV writing.

To attach the handler directly, use WavDataHandler("saved_data/audio", sample_rate=65536, full_scale_pa=calibrationFactor * (2**23 - 1)) from slm_api.helpers.data_handler, using the device's actual calibration factor. You can instead supply sample_rate and full_scale_pa to handle(); the stream supplies both automatically. Call close() when finished. Use a separate WAV handler and output path for each device. Existing float32 pressure WAVs are unchanged; this format applies to new recordings.

Synchronized Multi-Device Stream

Based on multi_device_flac.py, pass multi_device=True and start/stop the group through the synchronized helpers:

from slm_api.enums.sequence_id_enum import SequenceIdEnums
from slm_api.helpers.stream_handlers import WebXiStreamHandler, start_all_synced, stop_all

hosts = ["192.168.1.183", "192.168.1.216"]
streams = [
	WebXiStreamHandler(
		host=host,
		sequenceID=SequenceIdEnums.MP3Signal.value,
		mode="mp3",
		streamName=f"Audio_{host}",
		multi_device=True,
		saving="wav",
		saving_path=f"saved_data/{host}",
	)
	for host in hosts
]

start_all_synced(streams)

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    stop_all(streams)

stop_all() synchronizes the device measurement stops, flushes saving handlers, and removes each device stream.

Modes

Mode Use
"leq" One broadband sequence; this is the default.
"multi" Several named broadband sequences.
"cpb" Constant-percentage-band data.
"fast_logging" Fast broadband samples.
"flac" / "mp3" Decoded audio samples.
"screen_record" Latest SLM screen image in streamer.image_bytes.

Legacy flags such as mp3=True remain supported, but mode= is preferred. Only select one mode per stream.


## Troubleshooting

- **No values arrive:** Confirm the requested sequences are enabled on the SLM.
- **Audio returns no samples after first enable:** Allow the SLM a few seconds to initialize audio recording before retrying.
- **Saved file is missing:** Files are written when the handler first receives data (nonempty samples for WAV). Check the saving path and that the stream is delivering data. Still call `stopStream()` or `stop_all()` to clean up recording resources.

Metadata

Release files for slm_open_api_package 0.2.15

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for slm_open_api_package 0.2.15
File Size Uploaded Provenance
slm_open_api_package-0.2.15.tar.gz 45.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for slm_open_api_package 0.2.15
File Interpreter ABI Platform
slm_open_api_package-0.2.15-py3-none-any.whl Python 3 none any Details

Total release size: 102.5 kB

Release files / slm_open_api_package-0.2.15.tar.gz

Download URL slm_open_api_package-0.2.15.tar.gz
Size 45.5 kB
Tags Source
SHA-256 checksum
How to use checksums
aa9d64fabfd0a392384e11ee90c9c814555871d93264b46bb85ab14c94888f99
BLAKE2b-256 checksum
How to use checksums
0d2bfd6d525361367584692445bb0a844fefcb4d1c38e75cb342075ad20bd294
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / slm_open_api_package-0.2.15-py3-none-any.whl

Download URL slm_open_api_package-0.2.15-py3-none-any.whl
Size 57.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
05707d1ce9cdec14a5bb19ea527faa5047519c8db70fc543ccb2e8a618029c8b
BLAKE2b-256 checksum
How to use checksums
8230ef89b8a06655304a1fe88a3869ab5627d46fdc31cc8c687f6ed31ded2f75
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for slm_open_api_package 0.2.15

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page