-
Notifications
You must be signed in to change notification settings - Fork 19
Description
🎯 Goal
Add a pathway for custom data sources beyond the BACnet driver by supporting an AWS Lambda–style “handler” that a user can upload as a .zip. The handler should fetch data from an external source, sync values into the Open-FDD database/time-series layer, and attach them to the existing site data model (points).
This enables:
- custom drivers (weather, utility APIs, vendor clouds, Modbus gateways, CSV pullers, etc.)
- future “cloud export” or “cloud ingest” workflows using the same plugin mechanism
🛠 What To Do
- Define a minimal driver plugin contract (Lambda-like):
- A Python entrypoint function (e.g.,
handler(event, context)) - A structured return payload that Open-FDD can ingest
- A Python entrypoint function (e.g.,
- Implement a basic backend endpoint + loader concept (MVP):
- Accept a
.zipupload (containinghandler.py+requirements.txtoptional) - Store it for execution (local dev is fine; sandboxing can be later)
- Allow running it on demand OR on a simple schedule (hourly) (MVP can be manual trigger)
- Accept a
- Demonstrate the system with a weather API custom driver.
✅ “Dirt Simple” Example Handler (Weather)
Below is an example handler.py that calls a free weather API (Open-Meteo) once per run and returns values in a simple structure.
Note: this is a demo driver; it’s okay if the MVP just prints/returns values and the Open-FDD backend wires storage later.
# handler.py
import json
import urllib.request
from datetime import datetime, timezone
def handler(event, context=None):
# event should provide lat/lon and a site_id, but defaults are fine for demo
lat = float(event.get("lat", 43.0389)) # Madison-ish default
lon = float(event.get("lon", -89.4012))
site_id = event.get("site_id", "demo_site")
url = (
"https://api.open-meteo.com/v1/forecast"
f"?latitude={lat}&longitude={lon}"
"¤t=temperature_2m,relative_humidity_2m,wind_speed_10m"
)
with urllib.request.urlopen(url, timeout=10) as resp:
data = json.loads(resp.read().decode("utf-8"))
current = data.get("current", {})
now = datetime.now(timezone.utc).isoformat()
# Return a normalized payload that Open-FDD can ingest.
# "points" keys should match timeseries keys or model point identifiers.
return {
"site_id": site_id,
"timestamp": current.get("time", now),
"points": {
"weather_oat_c": current.get("temperature_2m"),
"weather_rh_pct": current.get("relative_humidity_2m"),
"weather_wind_mps": current.get("wind_speed_10m"),
},
"meta": {
"source": "open-meteo",
"lat": lat,
"lon": lon,
},
}To zip it:
zip -r openfdd_weather_driver.zip handler.py🔌 Expected Integration (MVP)
-
Open-FDD stores the handler zip and can execute it with an
eventpayload like:site_id,lat,lon
-
The handler returns
{site_id, timestamp, points{...}} -
Open-FDD writes:
- points into time-series storage (Timescale or whatever is configured)
- optional mapping metadata so these points can be attached to the data model (Brick tagging later)
📎 Deliverable
-
A short doc describing the driver plugin contract (inputs/outputs)
-
Minimal backend wiring to upload and execute a zipped driver (manual trigger is OK)
-
A working demo using the included weather handler:
- run once and persist at least 1–3 values into the database/time-series
- show a screenshot or query output proving the write happened