Add network monitoring, dashboard, and Home Assistant MQTT publishing
Keep /alive unchanged and serve a dashboard at / with status cards, latency graphs, an event timeline, and a Wi-Fi section. Background monitors on configurable intervals: TCP reachability, DNS resolution, public IP change detection, host reboot detection, Wi-Fi link quality, and Wi-Fi scan of networks in range via iw. The Wi-Fi interface is selected with WIFI_INTERFACE; the page lists visible interfaces and reports when none is available. Scan results stay in memory, other metrics go to SQLite on a mounted volume. Optional MQTT publishing with Home Assistant discovery groups all sensors under one device per host. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TdvJYoY8kc8bmBck89U2i6
This commit is contained in:
1 parent
aace768660
commit
7206e0c4db
13 files changed
+1509
-6
No files matched your search
@@ -0,0 +1,113 @@
|
||||
# healthcheck-container
|
||||
|
||||
Small Flask service for remote devices (Raspberry Pi in Docker) that answers
|
||||
`/alive` for container monitoring and, on top of that, watches the network the
|
||||
device sits on: internet reachability, DNS, public IP changes, Wi-Fi link
|
||||
quality, Wi-Fi networks in range, and host reboots. Metrics go to SQLite and
|
||||
are shown on a dashboard at `/`. Optionally the same values are published to an
|
||||
MQTT broker with Home Assistant discovery, so each device shows up in Home
|
||||
Assistant as a device with sensors and no manual configuration.
|
||||
|
||||
## Endpoints
|
||||
|
||||
| Path | Purpose |
|
||||
| --- | --- |
|
||||
| `/alive` | Unchanged health check, returns `{"alive": true}` |
|
||||
| `/` | Dashboard: status, Wi-Fi, graphs, timeline |
|
||||
| `/api/status` | Latest state of every monitor as JSON |
|
||||
| `/api/wifi` | Interface list, link details, last scan results |
|
||||
| `/api/events?limit=200` | Timeline events, newest first |
|
||||
| `/api/samples?prefix=reach.&range=3600` | Bucketed samples for graphs |
|
||||
|
||||
## Running
|
||||
|
||||
```sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Then open `http://<device>:9999/`.
|
||||
|
||||
Wi-Fi needs two things from Docker:
|
||||
|
||||
- `network_mode: host`, otherwise the container has no wireless interface at all.
|
||||
- `cap_add: NET_ADMIN`, otherwise link and interface info work but scanning fails
|
||||
with a permission error that is shown on the dashboard.
|
||||
|
||||
Without `WIFI_INTERFACE` the dashboard lists the interfaces it can see and
|
||||
nothing is scanned. Set the variable to one of the listed wireless interfaces
|
||||
and restart the container.
|
||||
|
||||
## Storage
|
||||
|
||||
Samples and events are stored in SQLite at `DB_PATH` (default
|
||||
`/data/healthcheck.db`). The compose file mounts a named volume at `/data`, so
|
||||
the database survives `docker compose down`, image rebuilds and `up -d`. Only
|
||||
`docker compose down -v` or `docker volume rm` deletes it. A bind mount works
|
||||
as well, for example `- /opt/healthcheck:/data`.
|
||||
|
||||
Samples older than `SAMPLE_RETENTION_DAYS` (default 7) are deleted hourly.
|
||||
Events are kept. Wi-Fi scan results are held in memory only and never written.
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings are environment variables. Intervals are in seconds.
|
||||
|
||||
| Variable | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `PORT` | `9999` | HTTP port |
|
||||
| `DB_PATH` | `/data/healthcheck.db` | SQLite file |
|
||||
| `SAMPLE_RETENTION_DAYS` | `7` | How long graph samples are kept |
|
||||
| `DEVICE_NAME` | hostname | Shown on the dashboard and in Home Assistant |
|
||||
| `DEVICE_ID` | slug of `DEVICE_NAME` | Used in MQTT topics and unique ids |
|
||||
| `REACH_TARGETS` | `1.1.1.1:443,8.8.8.8:443,9.9.9.9:443` | TCP connect targets, `host:port` |
|
||||
| `REACH_INTERVAL` | `30` | |
|
||||
| `REACH_TIMEOUT` | `3` | Connect timeout per target |
|
||||
| `DNS_NAME` | `cloudflare.com` | Name resolved through the system resolver |
|
||||
| `DNS_INTERVAL` | `60` | |
|
||||
| `PUBLIC_IP_URLS` | ipify, ifconfig.me, icanhazip | Tried in order, first answer wins |
|
||||
| `PUBLIC_IP_INTERVAL` | `300` | |
|
||||
| `PUBLIC_IP_TIMEOUT` | `5` | |
|
||||
| `UPTIME_INTERVAL` | `60` | Reboot detection via `/proc/uptime` |
|
||||
| `WIFI_INTERFACE` | empty | Wireless interface to use, empty disables Wi-Fi |
|
||||
| `WIFI_LINK_INTERVAL` | `30` | Signal, bitrate, retries of the current link |
|
||||
| `WIFI_SCAN_INTERVAL` | `60` | Scan for networks in range |
|
||||
| `MQTT_HOST` | empty | Broker host, empty disables MQTT |
|
||||
| `MQTT_PORT` | `1883` | |
|
||||
| `MQTT_USERNAME` | empty | |
|
||||
| `MQTT_PASSWORD` | empty | |
|
||||
| `MQTT_DISCOVERY_PREFIX` | `homeassistant` | Must match the MQTT integration setting |
|
||||
| `LOG_LEVEL` | `INFO` | |
|
||||
|
||||
## Events on the timeline
|
||||
|
||||
- Internet unreachable / reachable again (all targets failed, then any succeeded)
|
||||
- DNS resolution failed / working again
|
||||
- Public IP is X, Public IP changed from X to Y
|
||||
- Wi-Fi connected, disconnected, roamed to another BSSID
|
||||
- Host rebooted
|
||||
- Health check service started
|
||||
|
||||
## Home Assistant
|
||||
|
||||
Set `MQTT_HOST` (and credentials if the broker needs them). On connect the
|
||||
service publishes retained discovery messages under
|
||||
`homeassistant/<component>/healthcheck_<device_id>/<key>/config`, all pointing
|
||||
to one device, then publishes state to `healthcheck/<device_id>/state` and
|
||||
availability to `healthcheck/<device_id>/availability`. When Home Assistant
|
||||
restarts it announces itself on `homeassistant/status` and the service
|
||||
re-publishes discovery.
|
||||
|
||||
Entities per device:
|
||||
|
||||
- Internet, DNS, Wi-Fi (binary sensors, `connectivity` class)
|
||||
- Internet latency, DNS latency (ms)
|
||||
- Public IP
|
||||
- Host uptime
|
||||
- Wi-Fi SSID, BSSID, channel, signal (dBm), TX bitrate (Mbit/s), networks in range
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
python3 -m unittest discover -s tests
|
||||
DB_PATH=./data/hc.db python3 app.py
|
||||
```
|
||||
Reference in new issue
Block a user