An asynchronous SCPI device manager and logger built on ZeroMQ.
Project description
Hermes Device Manager (hermes-dm)
Hermes-DM is a lightweight, high-performance, and asynchronous device manager that provides a native, modern software interface for classic test and measurement hardware.
By leveraging ZeroMQ (ZMQ) for swift, non-blocking message passing and SCPI (Standard Commands for Programmable Instruments) for hardware communication, Hermes allows you to seamlessly control, monitor, and log data from generic lab instruments.
Features
- Asynchronous Architecture: Built on top of ZeroMQ for high-throughput, low-latency telemetry logging.
- Generic SCPI Support: Easily extensible to any programmable instrument (Power supplies, Oscilloscopes, DMMs, etc.).
- Decoupled Logging: Devices stream data asynchronously, isolating measurement constraints from data storage layers.
- Lightweight Footprint: Avoids heavy industrial middleware framework bloat.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ BACKGROUND DAEMON (hermes-daemon) │
│ │
│ [ SCPI Instruments ] ◄──── (PyVISA) ────► [ Async Server ] │
│ │ │ │
│ [ SQLite DB Logs ] ◄────── (Database) ─────────┘ │ │
└───────────────────────────────────────────────────────┼─────┘
│
(ZeroMQ: Ports 5555 REP & 5556 PUB)
│
┌───────────────────────────────────────────────────────▼─────┐
│ USER ENVIRONMENT (hermes_dm.client) │
│ │
│ [ HermesClient Library ] │
│ │ │
│ ▼ │
│ [ Standalone Scripts | Jupyter Notebooks | GUI App ] │
└─────────────────────────────────────────────────────────────┘
Installation
pip install hermes-dm
Quick Start
Hermes operates on a robust Client-Server architecture to ensure your hardware polling never blocks your user interfaces or scripts.
1. Start the Background Daemon
Run this in your terminal to start the background hardware manager:
hermes-daemon --db-dir ./lab_data --cmd-port 5555
2. Control via Python Script
In a separate terminal, Jupyter notebook, or GUI, use the client library to issue commands to the daemon:
from hermes_dm.client import HermesClient
# Connect to the background daemon
client = HermesClient(host="localhost", port=5555)
# Connect the hardware (driver logic is handled by the daemon)
client.connect_device(
name="Main_PSU",
model="Keithley2410",
identifier="TCPIP::111.222.33.44::INSTR"
)
# Configure the instrument
client.configure_device("Main_PSU", {"source_mode": "VOLT", "output_enabled": True})
# Start continuous asynchronous logging to SQLite
client.start_logging()
Developer Guide
Welcome! This section covers everything you need to know to set up a local development environment, understand the underlying architecture, and contribute to hermes-dm.
System Architecture Overview
hermes-dm uses a decoupled, event-driven, client-server architecture designed for high-performance, non-blocking laboratory hardware control.
- The Hermes Client: A lightweight, synchronous Python API exposed to user scripts or notebooks. It handles telemetry requests, sends command packets over ZeroMQ, and translates backend JSON error states back into native Python exceptions.
- The Hermes Daemon: A persistent, asynchronous background process (
asyncio) handling incoming network traffic via ZeroMQ. - Isolated Thread Pools: To prevent slow hardware I/O (like instrument connection scans or legacy GPIB commands) from locking up the main asynchronous network event loop, the daemon uses dedicated OS thread pools (
asyncio.to_threadand customThreadPoolExecutorinstances) to isolate synchronous PyVISA drivers.
Environment Setup
Follow these steps to set up an isolated development environment running your code in editable mode with all developer tools active.
-
Clone the repository and navigate to the root directory:
git clone [https://github.com/cbeiraod/hermes-dm.git](https://github.com/cbeiraod/hermes-dm.git) cd hermes-dm
-
Create a virtual environment:
python -m venv .venv
-
Activate the environment:
- Linux / macOS:
source .venv/bin/activate - Windows (Cmd):
.venv\Scripts\activate.bat - Windows (PowerShell):
.venv\Scripts\Activate.ps1
- Linux / macOS:
-
Install the package in editable mode with development extras:
pip install -e ".[dev]"
Note: If you are using Zsh, make sure to wrap the target in quotes:
pip install -e ".[dev]"Optionally, install the package in editable mode with development, testing, and documentation extras:
pip install -e ".[dev,docs]"
-
Install the local Git hooks:
python -m pre_commit install
Development Tools Stack
We use a modern, consolidated tool stack to enforce code quality, verify async test patterns, and automate package distribution.
| Tool | Purpose | Standalone Command |
|---|---|---|
| Pytest | Test runner for client, server routing, and database logs | pytest |
| Ruff | Lightning-fast linter, formatter, and import sorter | ruff check (lint) ruff format (style) |
| Pre-commit | Framework managing local Git hooks and code safety | python -m pre_commit run --all-files |
| Sphinx | Documentation generator extracting structural Python docstrings | sphinx-build -b html docs/ docs/_build/html |
| Bump-my-version | Automated single-source-of-truth version bumping | bump-my-version bump [patch|minor|major] |
| Build | Creates standard PEP 517 source archives and wheels | python -m build |
| Twine | Securely uploads distribution wheels to PyPI | twine upload dist/* |
Running Tools Standalone
-
Running the Test Suite: To execute all test suites with verbose execution details:
pytest -v -
Running Linter/Formatter Manually: While
pre-commitintercepts formatting issues during git tracking, you can trigger individual sweeps manually:ruff check --fix # Evaluates code quality rules and auto-fixes violations ruff format # Enforces your project's code style rules across all files
-
Simulating a Pre-commit Run: If you want to evaluate all files against the entire pre-commit stack (including trailing whitespace, end-of-file fixers, and forgotten debug statements) without committing code:
python -m pre_commit run --all-files
-
Building Documentation Locally: To compile your
.rstdesign layout and extract code docstrings via Sphinx into a responsive, dark-mode-ready static HTML site using the Furo theme:python -m sphinx -b html docs/ docs/_build/html
After compilation, open
docs/_build/html/index.htmlin your browser to preview the output. -
Executing a Release Version Bump: To safely increment versions across your
pyproject.tomland package__init__.pywhile auto-generating tracking commits and release candidate tags:bump-my-version bump minor
CI/CD Infrastructure (GitHub Actions)
Automation pipelines are tracked inside .github/workflows/. They isolate compute footprints to keep automation efficient and free.
1. Continuous Integration (ci.yml)
Triggers automatically on every push to main, pull request tracking, or creation of version tags (v*.*.*).
- Fail-Fast Lint Gate: Automatically triggers a clean cloud environment to test the full codebase against
pre-commit. If formatting is irregular or a straybreakpoint()is exposed, the job drops immediately. - Linux Test Core: Executes the complete async test matrix under an optimized caching system to evaluate package installs in seconds.
- Extended Multi-OS Testing: To control costs, tests targeting Windows and macOS runners are restricted. They execute only when a formal version release tag (e.g.,
v0.2.0) is discovered or when manually requested via the GitHub Actions UI.
2. PyPI Package Deployment (Coming Soon)
- Triggers exclusively on published GitHub Releases.
- Automatically triggers the
buildpipeline, verifies package architecture integrity viatwine check, and deploys clean production wheels securely onto the Python Package Index (PyPI).
License
This project is licensed under the zlib/libpng License - see the LICENSE file for details.
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 hermes_dm-0.0.1a1.tar.gz.
File metadata
- Download URL: hermes_dm-0.0.1a1.tar.gz
- Upload date:
- Size: 25.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0cc8c35375f9da7048b82d136eb4af1433b6ba11a7b68416a5d5d3278ca6e5c
|
|
| MD5 |
8e33bfa646d5beff48e347f25b21418c
|
|
| BLAKE2b-256 |
4e80489904858752c633556986fa2b4db0e8c8deaaeed2a43a8e63cba09bdf4e
|
Provenance
The following attestation bundles were made for hermes_dm-0.0.1a1.tar.gz:
Publisher:
ci.yml on cbeiraod/hermes-dm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hermes_dm-0.0.1a1.tar.gz -
Subject digest:
c0cc8c35375f9da7048b82d136eb4af1433b6ba11a7b68416a5d5d3278ca6e5c - Sigstore transparency entry: 1723218630
- Sigstore integration time:
-
Permalink:
cbeiraod/hermes-dm@f8640c6692cc9c2936a421944e561821f4e2b64f -
Branch / Tag:
refs/tags/v0.0.1a1 - Owner: https://github.com/cbeiraod
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@f8640c6692cc9c2936a421944e561821f4e2b64f -
Trigger Event:
push
-
Statement type:
File details
Details for the file hermes_dm-0.0.1a1-py3-none-any.whl.
File metadata
- Download URL: hermes_dm-0.0.1a1-py3-none-any.whl
- Upload date:
- Size: 24.2 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 |
4389ac1255037cd90929e386dca0aca464b88a1527a4c08ff78980a87928c0da
|
|
| MD5 |
65055b5bc0fe48517d4e60b98d4fa50c
|
|
| BLAKE2b-256 |
b54868a7f5e0c8b7488f0c8e60b1d2b175b50800abc731012664b4666c44a1ce
|
Provenance
The following attestation bundles were made for hermes_dm-0.0.1a1-py3-none-any.whl:
Publisher:
ci.yml on cbeiraod/hermes-dm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hermes_dm-0.0.1a1-py3-none-any.whl -
Subject digest:
4389ac1255037cd90929e386dca0aca464b88a1527a4c08ff78980a87928c0da - Sigstore transparency entry: 1723218719
- Sigstore integration time:
-
Permalink:
cbeiraod/hermes-dm@f8640c6692cc9c2936a421944e561821f4e2b64f -
Branch / Tag:
refs/tags/v0.0.1a1 - Owner: https://github.com/cbeiraod
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@f8640c6692cc9c2936a421944e561821f4e2b64f -
Trigger Event:
push
-
Statement type: