Vendor-neutral building-automation-system trend analysis: FDD, M&V, and retro-commissioning
Project description
CAMBER
Commissioning, Analytics & M&V for Building Energy Re-tuning
A vendor-neutral Python toolkit for analyzing Building Automation System (BAS) trend data — fault detection & diagnostics (FDD), measurement & verification (M&V), and retro-commissioning (RCx) — across any building, independent of the BAS vendor.
The core idea: points are mapped to a small vocabulary of vendor-neutral roles
(HEAT_VALVE, SUPPLY_AIR_TEMP, OAT, …), and every diagnostic is written
against those roles. Map a building's tags once and the whole rule set runs on it
— one rule, all equipment, any BAS.
What it does
- Ingest — adapters for per-point CSV exports, wide/tabular CSV, and a Project
Haystack
hisReadclient (behind an injectable transport). - Semantic model — a role vocabulary + mapping provider, plus a site/equipment
/point entity model with completeness validation (which analytics a
building's instrumentation can support). Brick interop: derive the
point→role mapping automatically from a building's Brick (
.ttl) model. - FDD — a rule engine implementing ASHRAE Guideline 36 AFDD (operating states, fault conditions FC#1–15, trim-and-respond resets) and PNNL Building Re-tuning diagnostics (simultaneous heat/cool, reheat penalty, SAT/CHW reset, economizer, boiler lockout, overcooling, setback, OA fraction incl. under-ventilation, leaking valves, static/pump resets). Plus impact prioritization, fault-lifecycle tracking, and an FDD-accuracy benchmark harness (scored against labeled data).
- M&V — IPMVP / ASHRAE Guideline 14 change-point inverse models (2P–5P plus heating-zero variants) and the LBNL Time-of-Week & Temperature (TOWT) model for schedule-driven loads, CV(RMSE)/NMBE statistics and fractional savings uncertainty, CUSUM savings tracking, weather normalization (TMY/EPW), and rate/energy-aware resampling.
- Cost & carbon — utility cost accounting (energy + demand + time-of-use, and tiered water/wastewater with marginal vs. average rates) and GHG emissions (eGRID/EIA factors → CO₂e and intensity).
- Water — irrigation water budgets (ETo / landscape coefficient / efficiency / effective precipitation), cooling-tower makeup (cycles of concentration, gal/ton-hr), and leak detection (minimum night flow, flow duration, leak cost).
- Load profiling — peak / near-peak / base, base-to-peak ratio, load factor, load-duration curve, and weekday/weekend daily shapes.
- On-site systems — PV performance ratio, specific yield, and net/self- consumption energy; lighting operational efficiency vs. installed power with controls-fault flags (failed setback, no turndown).
- Comfort — Fanger PMV/PPD per ASHRAE Standard 55 / ISO 7730.
- Reporting — ASHRAE/ACCA Standard 211 audit deliverables (benchmark + prioritized findings + ECM table) to text/HTML, and a fleet/portfolio rollup (cross-sectional EUI benchmarking + fleet-wide fault counts).
- Storage — a Parquet time-series store keyed to the entity model, with tag-filtered reads.
- Quality — per-point data-quality scoring (robust outliers, flatline/gap detection) with an auditable cleaning trail.
- Integration — findings → CMMS-ticket records and a pluggable notifier; a
read-only HTTP API over the store (
python -m camber.api.server <store> [port]:/sites,/points,/history).
Install
Python 3.10+. The PyPI distribution name is camber-toolkit (it imports as camber).
pip install camber-toolkit # from PyPI
pip install "camber-toolkit[brick]" # + rdflib, for robust Brick-model parsing (optional)
From source (for development):
pip install -e . # the package (editable)
pip install -e .[dev] # + pytest, for development
pip install -e .[brick] # + rdflib, for robust Brick-model parsing (optional)
pip install -e .[haystack] # + a Haystack client (phable / pyhaystack) (optional)
Quickstart
python -m pytest -q # run the test suite
python examples/synthetic_demo.py # data-free FDD demo on generated trends
Usage
Everything runs on role-named frames — a DataFrame whose columns are
vendor-neutral Roles. Map a building's tags to roles once, then every diagnostic
and model runs on it.
Fault detection — run a diagnostic, get a structured Finding:
import numpy as np, pandas as pd
from camber.model.roles import Role
from camber.rules.simul_hc import SimultaneousHeatCool
idx = pd.date_range("2025-07-07", periods=24 * 7, freq="1h")
frame = pd.DataFrame({
Role.OAT: 90 + 10 * np.sin((idx.hour - 9) / 24 * 2 * np.pi),
Role.COOL_VALVE: 70.0, # cooling all day
Role.HEAT_VALVE: np.where((idx.dayofweek < 5) & idx.hour.isin([11, 12, 13, 14]),
40.0, 0.0), # midday reheat — a fault
}, index=idx)
f = SimultaneousHeatCool().analyze("AHU_1", frame)
print(f.severity, f.metrics["simultaneous_hc_pct"]) # -> fault 36.36
Measurement & verification — fit a change-point baseline and score it:
import numpy as np
from camber.mandv.models import best_model, N_PARAMS
from camber.mandv.stats import fit_stats
oat = np.linspace(35, 100, 120)
energy = 50 + np.clip(oat - 65, 0, None) * 3 + np.random.default_rng(0).normal(0, 2, 120)
m = best_model(oat, energy) # picks the inverse model
st = fit_stats(energy, m.predict(oat), N_PARAMS[m.kind])
print(m.kind, round(st.r2, 2), f"{st.cv_rmse:.0%}") # -> 3PC 1.0 2%
Your own building — map point names → roles in a small JSON config (or derive
it from a Brick model with camber.interop.brick), then resolve() assembles the
role-frames. See examples/ for end-to-end runs on public datasets.
Reproducible runs — describe a whole analysis (source → mapping → equipment → rules → report) in one JSON config and run it without a script:
python -m camber.config run.json # discovers equipment, runs the rules, writes the report
Docker
docker build -t camber .
docker run --rm camber # runs the test suite as a clean-build proof
docker run --rm -it camber bash # interactive shell
Mount a building's CSV export at /data to run analytics on real trends.
Public datasets
The toolkit is data-agnostic. Two open datasets are wired as runnable examples (referenced + fetched, not bundled):
- LBNL Fault Detection and Diagnostics Datasets
(CC-BY) — labeled single-duct-AHU data.
examples/lbnl_fdd/maps its point names to roles, validates completeness, round-trips through the Parquet store, and detects a labeled stuck-damper fault (OAF ~21% baseline → ~100% fault). - Building Data Genome Project 2
(CC-BY) — 3,053 whole-building hourly meters.
examples/bdg2/fits the G14/IPMVP change-point engine (textbook 3PC on cooling energy, R² 0.78–0.94) and ingests the portfolio into the store.
Each example has a fetch.py (downloads to the git-ignored examples/_data/) and
a runnable script. See the per-example READMEs.
Contributing
Contributions are welcome — new diagnostics, ingest adapters, M&V models, ontology interop, docs, and fixes. See CONTRIBUTING.md for the dev setup and conventions, docs/ARCHITECTURE.md for the layered design, ROADMAP.md for what's planned and where to help, docs/ECOSYSTEM.md for the OSS-integration strategy, and the Code of Conduct. Security reports: see SECURITY.md.
Provenance
This is a clean-room implementation. Algorithms are reimplemented from public standards — ASHRAE Guideline 36, Guideline 14, Standard 55, Standard 211; IPMVP; PNNL Building Re-tuning; NIST APAR. No third-party source code is included.
License
Apache-2.0. See LICENSE and NOTICE.
Status: pre-release (v0.x). APIs may change.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file camber_toolkit-0.1.0.tar.gz.
File metadata
- Download URL: camber_toolkit-0.1.0.tar.gz
- Upload date:
- Size: 215.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ea068a6a4b655bc8a4cdcfc06e87ee8027d18afa8fcf10b53cd965c539cae0a
|
|
| MD5 |
cbe0e653b55e0ea69f26becca473af3d
|
|
| BLAKE2b-256 |
de993b25cba75c4f184aa9754cc26f8ea66183dcd6f0588d32eec27c86048cf8
|
Provenance
The following attestation bundles were made for camber_toolkit-0.1.0.tar.gz:
Publisher:
release.yml on yroussev/camber
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
camber_toolkit-0.1.0.tar.gz -
Subject digest:
9ea068a6a4b655bc8a4cdcfc06e87ee8027d18afa8fcf10b53cd965c539cae0a - Sigstore transparency entry: 1809596981
- Sigstore integration time:
-
Permalink:
yroussev/camber@b4ee67210a3d8cba2e71e4dbfe557ee7556566d4 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yroussev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b4ee67210a3d8cba2e71e4dbfe557ee7556566d4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file camber_toolkit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: camber_toolkit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 275.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e883223e4f6ef23ddced9af55a216299f11fc4a1a3a1b60e2d99eafd6237b28
|
|
| MD5 |
6f66d8b37f02466c4ba3173cc9598649
|
|
| BLAKE2b-256 |
78a0ca8674108514c8286039ce93a921addfd5e44cefa5e2b8f7326102a3e81b
|
Provenance
The following attestation bundles were made for camber_toolkit-0.1.0-py3-none-any.whl:
Publisher:
release.yml on yroussev/camber
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
camber_toolkit-0.1.0-py3-none-any.whl -
Subject digest:
5e883223e4f6ef23ddced9af55a216299f11fc4a1a3a1b60e2d99eafd6237b28 - Sigstore transparency entry: 1809596989
- Sigstore integration time:
-
Permalink:
yroussev/camber@b4ee67210a3d8cba2e71e4dbfe557ee7556566d4 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yroussev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b4ee67210a3d8cba2e71e4dbfe557ee7556566d4 -
Trigger Event:
push
-
Statement type: