Files
jbod-monitor/README.md
adam d41e3838d5 Add per-enclosure temperature metrics + Home Assistant MQTT publisher
- enclosure: fetch SES element descriptor page (0x07) and label temp/fan/
  psu/voltage elements with human-readable names
- temps service + /api/temps: per-enclosure hotspot (max across SES sensors
  and housed drive temps) plus named SES sensor list
- mqtt_publisher: paho-mqtt with HA discovery (device per enclosure, hotspot
  + per-sensor entities), LWT availability, opt-in via MQTT_HOST
- secrets: OpenBao KV v2 reader; MQTT creds sourced from secret/home_assistant
  with env fallback
- compose/requirements/README updated
2026-06-16 04:45:32 +00:00

4.2 KiB

JBOD Monitor

REST API for monitoring drive health in JBOD enclosures on Linux.

Auto-discovers SES enclosures via sysfs, maps drives to physical slots, and exposes SMART health data.

Prerequisites

  • Linux with SAS/SATA JBODs connected via HBA
  • smartmontools — for smartctl (SMART data)
  • sg3-utils — for sg_ses (SES enclosure data)
  • Python 3.11+
# Debian/Ubuntu
apt install smartmontools sg3-utils

# RHEL/Fedora
dnf install smartmontools sg3_utils

Install

pip install -r requirements.txt

Run

The API needs root access for smartctl to query drives:

sudo uvicorn main:app --host 0.0.0.0 --port 8000

API Endpoints

Endpoint Description
GET /api/health Service health + tool availability
GET /api/enclosures List all discovered SES enclosures
GET /api/enclosures/{id}/drives List drive slots for an enclosure
GET /api/drives/{device} SMART detail for a block device
GET /api/overview Aggregate enclosure + drive health
GET /api/temps Per-enclosure temperatures: named SES sensors + hotspot
GET /docs Interactive API docs (Swagger UI)

Home Assistant (MQTT)

The monitor can publish per-enclosure temperatures to Home Assistant over MQTT using HA discovery — no HA YAML required. Each enclosure becomes a device with:

  • a Hotspot sensor — the hottest reading across all SES temperature sensors and the drives housed in that enclosure (drive temps are usually the real hotspot); drive_max_c and drive_temp_count are exposed as attributes.
  • one sensor per named SES temperature element (e.g. Temp Inlet, Temp Outlet), labelled from the SES element descriptor page.

Publishing is opt-in: set MQTT_HOST to enable it.

Variable Default Description
MQTT_HOST (unset) Broker host. Unset → MQTT disabled.
MQTT_PORT 1883 Broker port
MQTT_USERNAME / MQTT_PASSWORD (unset) Broker credentials (fallback if OpenBao unused/unavailable)
MQTT_DISCOVERY_PREFIX homeassistant HA discovery topic prefix
MQTT_BASE_TOPIC jbod-monitor State/availability topic root
MQTT_PUBLISH_INTERVAL 60 Seconds between publishes
MQTT_NODE_ID (hostname) Stable id for this monitor (disambiguates multiple hosts)
MQTT_CLIENT_ID jbod-monitor-<node> MQTT client id

Credentials via OpenBao

Broker credentials are sourced from OpenBao at startup rather than stored in plaintext (matching the homelab runtime-secret pattern). Set MQTT_SECRET_PATH to a KV v2 path holding username/password; the app reads <OPENBAO_ADDR>/v1/<OPENBAO_MOUNT>/data/<MQTT_SECRET_PATH> with the token from OPENBAO_TOKEN_FILE (or OPENBAO_TOKEN). If the read fails, it falls back to the MQTT_USERNAME/MQTT_PASSWORD env vars.

Variable Default Description
MQTT_SECRET_PATH (unset) KV v2 path holding the broker creds (e.g. home_assistant). Unset → use env creds.
MQTT_SECRET_USER_KEY username Key within the secret for the broker username
MQTT_SECRET_PASS_KEY password Key within the secret for the broker password
OPENBAO_ADDR https://vault.adamksmith.xyz OpenBao API base URL
OPENBAO_MOUNT secret KV v2 mount point
OPENBAO_TOKEN_FILE (unset) Path to a file containing the OpenBao token (preferred; mount read-only)
OPENBAO_TOKEN (unset) OpenBao token (used if no token file)

The deployed compose reads the broker user/pass from secret/home_assistant (keys mqtt_user/mqtt_pass) using the read-only claude-read token mounted at /run/secrets/openbao-token.

Topics (defaults):

homeassistant/sensor/<node>_enc<id>/hotspot/config   # retained discovery
homeassistant/sensor/<node>_enc<id>/temp<n>/config    # retained discovery
jbod-monitor/<node>/status                            # online | offline (LWT)
jbod-monitor/<node>/enclosure/<id>/state              # {"hotspot_c":42.0, "sensor_0":28.5, ...}

Availability is tracked via an MQTT LWT, so entities show unavailable in HA if the monitor stops.