Milan PandurovandClaude Fable 5.1 7206e0c4db 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
2026-09-17 15:42:09 +02:00

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

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

python3 -m unittest discover -s tests
DB_PATH=./data/hc.db python3 app.py
S
Description
While running, container will respond to HTTP API call with true. Used to monitor if container service is actually running.
Readme
75 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 71.4%
HTML 28.3%
Dockerfile 0.3%