{
  "$schema": "https://eheuristics.com/api/gateway.json",
  "name": "PHOA Water Meter Gateway",
  "codename": "WaterMeterGateway_CT62",
  "role": "mesh_hub",
  "firmware_version": "0.1.36",
  "manufacturer": "Competition Software",
  "copyright": "© 2026 Competition Software. Firmware is proprietary.",
  "summary": "ESP32 + CC1101 mesh hub that aggregates Badger ORION water-meter readings forwarded by Node devices and uploads them via HTTP to a Windows / FastAPI ingest service on the local LAN. Provides a fallback WiFi AP, optional W5500 Ethernet uplink, daily 'By Node' email summaries, and remote mesh commands.",
  "hardware": {
    "mcu": "ESP32 dual-core (Heltec CT62 footprint)",
    "mesh_radio": "CC1101 @ 433.92 MHz, 2-FSK, multi-hop, ACKed",
    "uplink": {
      "primary": "WiFi 802.11 b/g/n (2.4 GHz)",
      "optional": "Wiznet W5500 Ethernet on secondary SPI bus (CS=GPIO5, RST=GPIO22), enabled with #define HAVE_W5500"
    },
    "fallback_ap": {
      "purpose": "Lets distant Nodes that can't reach the home AP still associate and relay readings via the Gateway",
      "credentials": "shown on the Gateway's /setup page; not published here"
    }
  },
  "ingest": {
    "target_url": "http://<pc-ip>:41290/ingest",
    "transport": "HTTP POST batched JSON",
    "retry_policy": "Local queue buffers when PC is offline; drains on reconnect; no readings dropped",
    "queue_visibility": "/api/gw-diag exposes queue depth, dropped count, last HTTP code"
  },
  "features": [
    "CC1101 mesh hub for up to 32 nodes with multi-hop relay and ACKs",
    "HTTP ingest with retry buffer: batched JSON POST to a Windows ingest service on LAN port 41290",
    "Optional W5500 Ethernet uplink (compile flag), falls back to WiFi if link is down",
    "Always-on fallback WiFi AP (PHOAthree / PHOAwater1) for stranded nodes",
    "Live dashboard with client roster (chip, fw, RSSI, LQI, last seen), queue depth, drop counter",
    "Remote mesh commands: reboot, clear-db, set-default-meter, ping, query-status, set-sampling — targetable by node_id",
    "Daily 'By Node' email reports with per-meter volumes, configurable schedule and recipients",
    "Keepalive pings every 60 seconds to keep CC1101 PLLs warm and surface dead nodes early",
    "Flow-rate synthesis: computes interval-average gpm from consecutive volume readings"
  ],
  "endpoints": [
    { "method": "GET",  "path": "/",                          "purpose": "HTML dashboard" },
    { "method": "GET",  "path": "/setup",                     "purpose": "Configuration + command cards + email settings" },
    { "method": "POST", "path": "/update",                    "purpose": "Firmware upload (multipart)" },
    { "method": "GET",  "path": "/api/gw-diag",               "purpose": "JSON: fw, Ethernet link, ingest health, queue depth, mesh counters" },
    { "method": "GET",  "path": "/api/clients",               "purpose": "JSON: connected nodes with chip, fw, RSSI, LQI, count, last seen" },
    { "method": "POST", "path": "/api/cmd/{op}",              "purpose": "Remote mesh command. op = reboot | clear-db | set-default-meter | ping | query-status | set-sampling. Optional JSON body {\"node_id\": N}." },
    { "method": "GET",  "path": "/api/email",                 "purpose": "JSON: schedule configuration" },
    { "method": "POST", "path": "/api/email",                 "purpose": "Update schedule (interval, send hour/minute)" },
    { "method": "POST", "path": "/api/email/add_recip",       "purpose": "Add an email recipient" },
    { "method": "POST", "path": "/api/email/del_recip",       "purpose": "Remove an email recipient" },
    { "method": "POST", "path": "/api/email/send_now",        "purpose": "Trigger immediate 'By Node' email" }
  ],
  "live_example": {
    "ip": "192.168.0.102",
    "active_clients": 5,
    "readings_sent": 317,
    "screenshot": "/assets/dashboard-gateway.png"
  }
}
