- 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
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— forsmartctl(SMART data)sg3-utils— forsg_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_canddrive_temp_countare 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.