Clone
4
test.php
willwheeler edited this page 2026-06-18 20:49:00 +00:00

<-- Home

BAS Forecast & Dashboard

Python forecasting scripts plus a browser dashboard for validating BACnet trend charts and forecast overlays. Runs offline first on sample JS files, then optionally against live getData from BasData.


On this page


Overview & quick start

Component Description
forecast.py Train models, backtest on last 20%, write forecast_output.json
forecast_comp.py Compare target-only vs target + extra points (console MAE)
forecast_output.json Predictions + MAE per point for the dashboard
test.php ApexCharts lab: sparks, heatmap, line, phases, HVAC, forecast overlay
js/test.js Chart colors, wordbank, point → chart mapping
js/veris-sample.js Veris meter sample data
js/rtu-sample.js RTU sample data

Install & run

pip install pandas scikit-learn skforecast
python forecast.py

View in browser

/test.php?sample=1&forecast=1

Or open test.php, load sample or live data, then click Load forecast.

Default forecast points (forecast.pyJOBS)

Sample file Points
js/veris-sample.js P, Ia, Ib, Ic
js/rtu-sample.js ServRmTmp

test.php URL flags

Parameter Example Effect
sample=1 ?sample=1 Use sample JS; no live fetch
forecast=1 ?forecast=1 Auto-load forecast_output.json
interval=N ?interval=24 Live trend window (8-36 hours)
keyid=N ?keyid=1 Override automation-server id
embed=1 ?embed=1 Minimal header (iframe)

Main BasData app (context)

Page Role
index.php Production viewer + getData API
reports.php Report JSON builder
test.php Chart/forecast lab before shipping to reports/index

Pipeline

veris-sample.js / rtu-sample.js
        │
        ▼
   forecast.py  ──►  forecast_output.json
        │
        ▼
    test.php  ◄──  (optional) live getData from index.php
        │
        ▼
   ApexCharts (dashed forecast on P line + phase compare)

forecast_comp.py  →  console MAE only (experiments, no JSON)

forecast.py

Trains one time-series model per BACnet point, evaluates MAE on the last 20% of history, predicts 100 steps ahead, writes forecast_output.json.

Run

python forecast.py

No CLI args — edit constants at the top of the file.

Settings

Constant Default Meaning
FUTURE_STEPS 100 How many future readings to predict
LAGS 25 How many past readings the model uses each step
JOBS veris + rtu List of (js_file, [point_names])

Default JOBS:

JOBS = [
    ("js/veris-sample.js", ["P", "Ia", "Ib", "Ic"]),
    ("js/rtu-sample.js", ["ServRmTmp"]),
]

Algorithm (per point)

  1. Load — Parse var xxxData = { ... }; from the .js file.
  2. Series — pandas Series indexed by timestamp (x = ms, y = float).
  3. Resample — Even spacing from median step; interpolate gaps.
  4. Backtest — First 80% train, last 20% predict → MAE printed.
  5. Forecast — Retrain on full series → FUTURE_STEPS ahead.
  6. Write{ "mae", "future": [{x,y},...] } per point to JSON.

Model stack

  • skforecast ForecasterRecursive
  • sklearn Ridge
  • Metric: mean absolute error on the hidden 20%

Console example

P — 432 readings
  MAE (last 20%): 11.17

Saved forecasts for: P, Ia, Ib, Ic, ServRmTmp

forecast_comp.py

Research script: does adding other points improve predictions for a target?

Compares two models on the same 80/20 backtest:

Model Inputs
A — alone Target point history only
B — combined Target + WITH_POINTS at each timestamp

Does not write JSON or change charts.

Run

python forecast_comp.py

Settings (top of file)

Constant Example Meaning
JS_FILE js/rtu-sample.js Sample data source
TARGET RaTmp Point to predict
WITH_POINTS ["FanCmdOvr"] Extra columns for model B
LAGS 26 Lag window

Output example

Backtest on last 20% of sample data:
  RaTmp only:                    MAE = 1.24
  RaTmp + [FanCmdOvr]:           MAE = 0.89

Extra points helped — about 0.35 better on average.

Quality warnings

Script warns when MAE is misleading:

  • Flat target in test slice (MAE ≈ 0, model learned nothing useful)
  • Exog column identical or nearly identical to target
  • Exog fully determines target (lookup table)
  • Flat exog in test slice

Use forecast_comp.py to experiment; use forecast.py to ship JSON to the dashboard.


forecast_output.json

Generated by forecast.py. Loaded by test.php for dashed forecast overlays.

Schema

{
  "P": {
    "mae": 11.17,
    "future": [
      { "x": 1781713080000, "y": 19.05 },
      { "x": 1781713200000, "y": 19.04 }
    ]
  }
}
Field Meaning
mae Backtest error on last 20% (same units as point)
future Predicted readings after last historical sample
x Unix time in milliseconds (matches sample JS / getData)
y Predicted value (2 decimals)

Keys (default JOBS)

Key Source Dashboard use
P veris-sample.js Power line chart
Ia, Ib, Ic veris-sample.js Phase compare
ServRmTmp rtu-sample.js In JSON; RTU chart overlay TBD

How test.php uses it

  1. fetch("forecast_output.json")basForecastData
  2. basForecastSeries(actualData, pointName) → last real point + future array
  3. ApexCharts: dashed red series, "Forecast →" at last live timestamp

Charts with forecast today: Line P, Phase compare.

mae is stored but not shown in UI yet.


test.php dashboard

Device Snapshot — ApexCharts lab for BasData chart prototyping.

Modes

Mode How
Live Log in on index.php → pick office / building / asp → open test.php
Sample ?sample=1 loads rtu-sample.js + veris-sample.js
Forecast ?forecast=1 or Load forecast (needs chart data loaded first)

Hardcoded devices (for now): RTU_3, VerisMeter.

Charts

Toolbar slot Chart Typical points
sparks Fan / room / power mini charts FanSts, ServRmTmp, P
heatmap All Veris points all keys in bundle
lineP Power trend (+ forecast) P, Demand
phaseCompare Ia / Ib / Ic (+ forecast) Ia, Ib, Ic
hvacMode HVAC mode timeline HVACMode
trigger Fan start counts per bucket FanSts
radialBar Temp vs setpoint ServRmTmp + setpoint pair

Toggle charts with toolbar checkboxes. Point → slot mapping: js/test.jsBAS_CHART_SLOTS, basResolveDashboard().

Live data flow

test.php  --POST-->  index.php (getData=true&keyid=&name=&interval=&tstamp=)
         <--JSON--  { PointName: [{x,y}, ...], ... }
         -->  basApplyDashboard(rtu, veris)

Same contract as the index sidebar.

Header buttons

Button Action
Load sample data Offline JS bundles
Load forecast Fetch JSON, redraw P + phase charts
Status bar Loading / ok / partial fail / errors

Troubleshooting

Problem Likely cause Fix
"No forecast_output.json" File missing Run python forecast.py from project root
Forecast button, no lines No chart data ?sample=1 or log in and load live data first
MAE ≈ 0 in comp script Flat or duplicate data Read warnings in console output
Live RTU charts empty Long interval, huge payload Shorter window; see server memory notes
Point missing from JSON Not in JOBS Add to forecast.py and re-run

BasData forecast & dashboard wiki — single-page reference.