Skip to main content

An asynchronous SCPI device manager and logger built on ZeroMQ.

Project description

Hermes Device Manager (hermes-dm)

License: Zlib

CI Documentation Status

PyPI version Python Versions PyPI Wheel

pre-commit Ruff

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_thread and custom ThreadPoolExecutor instances) 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.

  1. 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
    
  2. Create a virtual environment:

    python -m venv .venv
    
  3. Activate the environment:

    • Linux / macOS: source .venv/bin/activate
    • Windows (Cmd): .venv\Scripts\activate.bat
    • Windows (PowerShell): .venv\Scripts\Activate.ps1
  4. 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]"
    
  5. 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-commit intercepts 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 .rst design 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.html in your browser to preview the output.

  • Executing a Release Version Bump: To safely increment versions across your pyproject.toml and package __init__.py while 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 stray breakpoint() 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 build pipeline, verifies package architecture integrity via twine 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hermes_dm-0.0.1a1.tar.gz (25.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hermes_dm-0.0.1a1-py3-none-any.whl (24.2 kB view details)

Uploaded Python 3

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

Hashes for hermes_dm-0.0.1a1.tar.gz
Algorithm Hash digest
SHA256 c0cc8c35375f9da7048b82d136eb4af1433b6ba11a7b68416a5d5d3278ca6e5c
MD5 8e33bfa646d5beff48e347f25b21418c
BLAKE2b-256 4e80489904858752c633556986fa2b4db0e8c8deaaeed2a43a8e63cba09bdf4e

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_dm-0.0.1a1.tar.gz:

Publisher: ci.yml on cbeiraod/hermes-dm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for hermes_dm-0.0.1a1-py3-none-any.whl
Algorithm Hash digest
SHA256 4389ac1255037cd90929e386dca0aca464b88a1527a4c08ff78980a87928c0da
MD5 65055b5bc0fe48517d4e60b98d4fa50c
BLAKE2b-256 b54868a7f5e0c8b7488f0c8e60b1d2b175b50800abc731012664b4666c44a1ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for hermes_dm-0.0.1a1-py3-none-any.whl:

Publisher: ci.yml on cbeiraod/hermes-dm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page