From 963647a708ff56c950b625ad371d61dd5fd77d89 Mon Sep 17 00:00:00 2001 From: Mike Langmayr <1809691+mikelangmayr@users.noreply.github.com> Date: Mon, 12 Oct 2026 12:09:26 -0700 Subject: [PATCH 1/9] Operate the daemons with the shared instrumentctl CLI --- README.md | 24 ++++++++++++- config/lris2_keygrabber.yaml | 40 ++++++++++++++++++++++ daemons/keygrabber | 11 ++++++ pyproject.toml | 9 ++++- src/cli/__init__.py | 20 +++++++++++ src/cli/instrument.toml | 8 +++++ systemd/README.md | 59 ++++++++++++++++++++++++++++++++ systemd/install.sh | 38 ++++++++++++++++++++ systemd/instances/keygrabber.env | 11 ++++++ systemd/instances/rcryo.env | 8 +++++ systemd/instances/rpress.env | 8 +++++ 11 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 config/lris2_keygrabber.yaml create mode 100755 daemons/keygrabber create mode 100644 src/cli/__init__.py create mode 100644 src/cli/instrument.toml create mode 100644 systemd/README.md create mode 100755 systemd/install.sh create mode 100644 systemd/instances/keygrabber.env create mode 100644 systemd/instances/rcryo.env create mode 100644 systemd/instances/rpress.env diff --git a/README.md b/README.md index 3a03d56..dbe4ea9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ LRIS2 Instrument Control Software ## Structure -- `daemons/` – mKTL service daemons +- `daemons/` – libby hardware daemons, one script per device type +- `config/` – one YAML per daemon instance, named for its `peer_id` +- `systemd/` – per-instance env files and the host setup script - `gui/` – Graphical interfaces (`slitmaskgui`, `demo`) - `scripts/` – AIT and utility scripts - `src/driver/` – Hardware driver submodules @@ -84,6 +86,26 @@ git add .gitmodules . git commit -m "Update submodules to latest on main" ``` +## Running the daemons + +Each daemon takes its config with `-c` and serves keywords over libby +(RabbitMQ by default), addressed as `lris2..`: + +```bash +daemons/vacuum-gauge -c config/lris2_rpress.yaml +libby show lris2.rpress.pressure1 +``` + +The `libby` CLI reads `~/.libby/cli_config.yaml`; on the instrument host it +needs only: + +```yaml +transport: rabbitmq +rabbitmq_url: amqp://localhost +``` + +For running daemons as services, see [`systemd/README.md`](systemd/README.md). + ## Testing Tests mirror the `src/` layout under `tests/`. diff --git a/config/lris2_keygrabber.yaml b/config/lris2_keygrabber.yaml new file mode 100644 index 0000000..d962b27 --- /dev/null +++ b/config/lris2_keygrabber.yaml @@ -0,0 +1,40 @@ +# Keyword archiver: polls the LRIS2 daemons and writes to InfluxDB for Grafana +# +# Usage: +# daemons/keygrabber -c config/lris2_keygrabber.yaml +# +# The InfluxDB token comes from the environment variable named in token_env. + +peer_id: keygrabber +group_id: lris2 + +sink: + type: influxdb + url: http://meridian.caltech.edu:8086 + org: coo + bucket: lris2 + token_env: LRIS2_INFLUX_TOKEN + +# Reads run concurrently across peers; a single daemon still answers one at a time +workers: 4 + +defaults: + interval_s: 30.0 + timeout_s: 2.0 + refresh_s: 300.0 + +# "%" takes everything readable except uptime and lasterror, which libby excludes +collections: + + # Vacuum and cryo: slow-moving, the trend over a cooldown is the point + rpress: + peer: lris2.rpress + keywords: ["%"] + interval_s: 60.0 + rcryo: + peer: lris2.rcryo + keywords: ["%"] + interval_s: 60.0 + +logging: + level: INFO diff --git a/daemons/keygrabber b/daemons/keygrabber new file mode 100755 index 0000000..0690c47 --- /dev/null +++ b/daemons/keygrabber @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +"""Keyword archiver: polls the LRIS2 daemons into InfluxDB for Grafana. + +The daemon lives in libby; this shim lets the systemd template launch it like +any other LRIS2 daemon. +""" + +from libby.keygrabber.main import main + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/pyproject.toml b/pyproject.toml index 0e7b681..ea25e16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,10 +13,14 @@ authors = [ license = {text = "MIT"} readme = "README.md" dependencies = [ + "instrumentctl@git+https://github.com/CaltechOpticalObservatories/instrumentctl.git", "pyserial", "pyyaml", ] +[project.scripts] +lris2 = "lris2.cli:main" + [project.optional-dependencies] dev = [ "pytest", @@ -32,7 +36,10 @@ camera = [ lris2 = "src" [tool.setuptools] -packages = ["lris2", "lris2.driver"] +packages = ["lris2", "lris2.cli", "lris2.driver"] + +[tool.setuptools.package-data] +"lris2.cli" = ["instrument.toml"] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/src/cli/__init__.py b/src/cli/__init__.py new file mode 100644 index 0000000..721be22 --- /dev/null +++ b/src/cli/__init__.py @@ -0,0 +1,20 @@ +"""``lris2``: deploy, run and inspect the LRIS2 daemons on this host. + +Every command comes from instrumentctl, which is shared with the other +instruments. All that is specific to LRIS2 is ``instrument.toml`` beside this +file. +""" + +from importlib import resources +from pathlib import Path +from typing import List, Optional + +from instrumentctl import run + + +def main(argv: Optional[List[str]] = None) -> int: + """Entry point for the ``lris2`` console script.""" + config = resources.files(__package__).joinpath("instrument.toml") + # Locates the checkout under an editable install, which is what lets the + # deployed CLI follow a git pull + return run(config, repo_hint=Path(__file__).resolve().parents[2], argv=argv) diff --git a/src/cli/instrument.toml b/src/cli/instrument.toml new file mode 100644 index 0000000..83b9db0 --- /dev/null +++ b/src/cli/instrument.toml @@ -0,0 +1,8 @@ +[instrument] +name = "lris2" +display_name = "LRIS2" +env_prefix = "LRIS2" + +[help] +example_instance = "rpress" +example_subsystem = "r" diff --git a/systemd/README.md b/systemd/README.md new file mode 100644 index 0000000..bee3288 --- /dev/null +++ b/systemd/README.md @@ -0,0 +1,59 @@ +# Running daemons under systemd + +Operated with the `lris2` command, which comes from +[instrumentctl](https://github.com/CaltechOpticalObservatories/instrumentctl) +and is shared with the other instruments. All that is specific to LRIS2 is +`src/cli/instrument.toml`. + +One template unit, `lris2@.service`, runs any `daemons/