# 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+ ```bash # Debian/Ubuntu apt install smartmontools sg3-utils # RHEL/Fedora dnf install smartmontools sg3_utils ``` ## Install ```bash pip install -r requirements.txt ``` ## Run The API needs root access for `smartctl` to query drives: ```bash 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](https://www.home-assistant.io/integrations/mqtt/#mqtt-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-` | 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 `/v1//data/` 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/_enc/hotspot/config # retained discovery homeassistant/sensor/_enc/temp/config # retained discovery jbod-monitor//status # online | offline (LWT) jbod-monitor//enclosure//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.