import logging import time from flask import Flask, jsonify, render_template, request from config import Config from monitors import State, build_monitors from storage import Storage cfg = Config() logging.basicConfig(level=cfg.log_level, format="%(asctime)s %(levelname)s %(name)s: %(message)s") log = logging.getLogger("app") storage = Storage(cfg.db_path) state = State() publisher = None app = Flask(__name__) WIFI_KEYS = ("wifi_interface", "wifi_interfaces", "wifi_status", "wifi_error", "wifi_link", "wifi_link_checked_at", "wifi_link_error", "wifi_scan", "wifi_scan_error") @app.route('/alive', methods=['GET']) def get_healthcheck(): response = { "alive": True } return jsonify(response) @app.route('/') def index(): return render_template("index.html") @app.route('/api/status') def api_status(): snapshot = state.snapshot() snapshot.pop("wifi_scan", None) snapshot["now"] = time.time() snapshot["config"] = cfg.public() return jsonify(snapshot) @app.route('/api/wifi') def api_wifi(): snapshot = state.snapshot() result = {key: snapshot.get(key) for key in WIFI_KEYS} result["now"] = time.time() result["scan_interval"] = cfg.wifi_scan_interval return jsonify(result) @app.route('/api/mqtt') def api_mqtt(): result = publisher.diagnostics() if publisher else {"enabled": False} result["now"] = time.time() return jsonify(result) @app.route('/api/mqtt/probe', methods=['POST']) def api_mqtt_probe(): if not publisher: return jsonify({"error": "MQTT is not configured"}), 404 return jsonify(publisher.run_probe()) @app.route('/api/events') def api_events(): limit = min(max(request.args.get("limit", 200, type=int), 1), 1000) return jsonify(storage.events(limit)) @app.route('/api/samples') def api_samples(): prefix = request.args.get("prefix", "") span = min(max(request.args.get("range", 3600, type=int), 60), cfg.sample_retention_days * 86400) bucket = max(10, span // 400) since = time.time() - span return jsonify({"since": since, "bucket": bucket, "series": storage.samples_by_prefix(prefix, since, bucket)}) def start_background(): global publisher storage.add_event("service_started", "Health check service started") storage.prune_samples(cfg.sample_retention_days) if cfg.mqtt_host: from hamqtt import HomeAssistantPublisher publisher = HomeAssistantPublisher(cfg, storage) state.on_change(publisher.publish_state) publisher.start() for monitor in build_monitors(cfg, state, storage): monitor.start() log.info("started monitor %s every %ss", monitor.name, monitor.interval) if __name__ == "__main__": start_background() app.run(host="0.0.0.0", port=cfg.port)