J. Rogers, SE Ohio
1. Overview
Pico devices – run the lightweight framework, read sensors, serve current data (/api/data), and serve a static graph specification (/graphlout/). They donot store history or render graphs.Bridge – a persistent process on a local machine (discovered via mDNS) that polls each Pico’s data, logs it according to the graph specification, and serves SVG graphs on demand.
Discovery: Bridge discovers Pico via mDNS and fetches its manifest and the graph specification from /graphlout/.IP Storage: Pico records the bridge’s IP address (from the HTTP request or via a separate discovery response).Bridge Setup: Bridge parses the JSON, creates database tables for each named graph, and starts logging polled values.Page Generation: When a client requests a page from the Pico, the Pico’s web server generates HTML. For each graph widget (as defined in the Pico’s layout table), it inserts an <img> tag with src pointing to http://<bridge-ip>/graph/<graph_name>?range=....Graph Serving: Browser requests the SVG from the bridge; the bridge queries its stored data, renders the graph per the specification, and returns the SVG.
2. Graph Specification Endpoint
3. JSON Schema
3.1 Root Object
3.2 Graph Definition Object
3.2.1 data_sources object
3.2.2 scale object
3.2.3 axes object
3.3 Example
{
"device": "weather_station_1",
"graphs": [
{
"name": "pressure_24h",
"title": "Barometric Pressure (24h)",
"data_sources": [
{
"id": "pressure",
"label": "Pressure",
"color": "#1f77b4",
"unit": "inHg",
"scale": {
"min": 28.5,
"max": 31.5
}
}
],
"time_range": "24h",
"sampling_interval": 300,
"retention": "30d",
"axes": {
"x": {
"label": "Time",
"tick_format": "%H:%M",
"grid": true
},
"y_left": {
"label": "Pressure (inHg)",
"tick_format": ".2f"
}
},
"width": 800,
"height": 400
},
{
"name": "temp_humidity_week",
"title": "Temperature & Humidity (7 days)",
"data_sources": [
{
"id": "temp_a",
"label": "Temperature",
"color": "#d62728",
"unit": "°F",
"y_axis": "left"
},
{
"id": "humidity_a",
"label": "Humidity",
"color": "#2ca02c",
"unit": "%",
"y_axis": "right"
}
],
"time_range": "7d",
"sampling_interval": 600,
"retention": "90d",
"axes": {
"x": {
"label": "Date",
"tick_format": "%m-%d"
},
"y_left": {
"label": "Temperature (°F)",
"min": 0,
"max": 120,
"grid": true
},
"y_right": {
"label": "Humidity (%)",
"min": 0,
"max": 100,
"grid": false
}
}
}
]
}4. Bridge Behavior
Fetches http://<pico-ip>/graph_definitions/. Parses the JSON. For each graph: Creates a time‑series table (or InfluxDB measurement, etc.) with appropriate retention policy. Starts logging the listed data sources at the requested sampling_interval (or every poll if omitted).
Serves SVG graphs at http://<bridge-ip>:<port>/<pico host name>/<name of graph>.svg. Supported query parameters: Other parameters may be added as needed.
Retrieves the stored spec for that graph. Queries the logged data for the requested time range. Applies scaling, axis formatting, and styling from the spec. Renders an SVG (e.g., using a library like svgwrite or matplotlib). Returns the SVG with Content-Type: image/svg+xml.
5. Pico Behavior
Serve the static JSON spec from /graphlout/. The spec is defined in the application code (e.g., as a constant string or generated by a function). This spec contains the graph name, data sources, sampling interval, retention period, and the time range to display (e.g., 24 hours, 100 days). Store the bridge IP address when the bridge first contacts it. This can be done by recording the source IP of the HTTP request to /graph_defintion/ (the bridge's IP).When generating HTML pages (based on its internal layout table), for any graph widget, embed an <img> tag with src pointing to: http://<stored-bridge-ip>:port/<pico-hostname>/<graph_name>.svgThe graph name comes from the graph definition. The time range is not included in the URL—it is already defined in the graph specification that the bridge fetched from /graphlout/. The bridge uses that stored range when rendering the SVG.
<img src="http://192.168.1.100:5001/weather_pico/pressure_24h.svg">
6. Discovery and IP Storage Details
Option A: Bridge fetches /graphlout/; the Pico records the remote IP from the TCP connection. This requires the bridge to be on the same network and the request to come directly.Option B: Bridge announces itself via mDNS (e.g., _pico-bridge._tcp). Pico listens for these announcements and stores the IP.Option C: Pico provides an endpoint /api/bridge that the bridge can POST its IP to after discovery.
7. Embedding Graphs in Pages
Iterates through layout containers and maps. For each MAP with widget type GRAPH, it finds the corresponding graph definition by name (the graph name is stored in the map or derived from the registry ID). It then generates an <img> tag using the stored bridge IP, the graph name, and the default time range from the spec. The resulting HTML is sent to the client.
No comments:
Post a Comment