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
89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
import os
|
|
import re
|
|
import socket
|
|
|
|
|
|
def _int(name, default):
|
|
raw = os.environ.get(name)
|
|
if raw is None or raw.strip() == "":
|
|
return default
|
|
try:
|
|
return int(raw)
|
|
except ValueError:
|
|
return default
|
|
|
|
|
|
def _float(name, default):
|
|
raw = os.environ.get(name)
|
|
if raw is None or raw.strip() == "":
|
|
return default
|
|
try:
|
|
return float(raw)
|
|
except ValueError:
|
|
return default
|
|
|
|
|
|
def _list(name, default):
|
|
raw = os.environ.get(name, default)
|
|
return [item.strip() for item in raw.split(",") if item.strip()]
|
|
|
|
|
|
def _slug(value):
|
|
return re.sub(r"[^a-z0-9_-]+", "_", value.lower()).strip("_") or "device"
|
|
|
|
|
|
class Config:
|
|
def __init__(self):
|
|
env = os.environ
|
|
hostname = socket.gethostname()
|
|
|
|
self.port = _int("PORT", 9999)
|
|
self.log_level = env.get("LOG_LEVEL", "INFO")
|
|
self.db_path = env.get("DB_PATH", "/data/healthcheck.db")
|
|
self.sample_retention_days = _int("SAMPLE_RETENTION_DAYS", 7)
|
|
|
|
self.device_name = env.get("DEVICE_NAME", hostname)
|
|
self.device_id = _slug(env.get("DEVICE_ID", self.device_name))
|
|
|
|
self.reach_targets = _list("REACH_TARGETS", "1.1.1.1:443,8.8.8.8:443,9.9.9.9:443")
|
|
self.reach_interval = _int("REACH_INTERVAL", 30)
|
|
self.reach_timeout = _float("REACH_TIMEOUT", 3.0)
|
|
|
|
self.dns_name = env.get("DNS_NAME", "cloudflare.com")
|
|
self.dns_interval = _int("DNS_INTERVAL", 60)
|
|
|
|
self.public_ip_urls = _list(
|
|
"PUBLIC_IP_URLS",
|
|
"https://api.ipify.org,https://ifconfig.me/ip,https://icanhazip.com",
|
|
)
|
|
self.public_ip_interval = _int("PUBLIC_IP_INTERVAL", 300)
|
|
self.public_ip_timeout = _float("PUBLIC_IP_TIMEOUT", 5.0)
|
|
|
|
self.uptime_interval = _int("UPTIME_INTERVAL", 60)
|
|
|
|
self.wifi_interface = env.get("WIFI_INTERFACE", "").strip()
|
|
self.wifi_link_interval = _int("WIFI_LINK_INTERVAL", 30)
|
|
self.wifi_scan_interval = _int("WIFI_SCAN_INTERVAL", 60)
|
|
|
|
self.mqtt_host = env.get("MQTT_HOST", "").strip()
|
|
self.mqtt_port = _int("MQTT_PORT", 1883)
|
|
self.mqtt_username = env.get("MQTT_USERNAME", "")
|
|
self.mqtt_password = env.get("MQTT_PASSWORD", "")
|
|
self.mqtt_discovery_prefix = env.get("MQTT_DISCOVERY_PREFIX", "homeassistant")
|
|
|
|
def public(self):
|
|
return {
|
|
"device_name": self.device_name,
|
|
"device_id": self.device_id,
|
|
"reach_targets": self.reach_targets,
|
|
"reach_interval": self.reach_interval,
|
|
"dns_name": self.dns_name,
|
|
"dns_interval": self.dns_interval,
|
|
"public_ip_interval": self.public_ip_interval,
|
|
"wifi_interface": self.wifi_interface,
|
|
"wifi_link_interval": self.wifi_link_interval,
|
|
"wifi_scan_interval": self.wifi_scan_interval,
|
|
"sample_retention_days": self.sample_retention_days,
|
|
"mqtt_enabled": bool(self.mqtt_host),
|
|
}
|