"""Session 9 - refresh data.json from the farm database every 10 s so index.html shows live readings. python export_json.py --db ../smart-farm/farm.db --node greenhouse_01 Then open index.html with VS Code "Live Server" (it must be served over http://, not file://). """ import argparse import json import sqlite3 import time from pathlib import Path ap = argparse.ArgumentParser() ap.add_argument("--db", default=str(Path(__file__).resolve().parent.parent / "smart-farm" / "farm.db")) ap.add_argument("--node", default="greenhouse_01") ap.add_argument("--once", action="store_true") a = ap.parse_args() out = Path(__file__).resolve().parent / "data.json" while True: con = sqlite3.connect(a.db) con.row_factory = sqlite3.Row rows = con.execute("SELECT ts, air_temp_c, air_humidity_pct, soil_moisture_pct FROM readings " "WHERE node_id=? AND air_temp_c IS NOT NULL ORDER BY ts DESC LIMIT 24", (a.node,)).fetchall() con.close() if rows: latest = dict(rows[0]) data = {"latest": {"node_id": a.node, **{k: latest[k] for k in ("air_temp_c", "air_humidity_pct", "soil_moisture_pct")}}, "history": [{"t": r["ts"][11:16], "soil": r["soil_moisture_pct"]} for r in reversed(rows)]} tmp = out.with_suffix(".tmp") tmp.write_text(json.dumps(data, ensure_ascii=False, indent=1), encoding="utf-8") tmp.replace(out) # atomic: the browser never reads a half-written file print(time.strftime("%H:%M:%S"), "updated", data["latest"]) else: print("no readings yet for", a.node) if a.once: break time.sleep(10)