Metadata-Version: 2.4
Name: open-fdd
Version: 2.0.13
Summary: Fault Detection and Diagnostics for HVAC systems — config-driven, pandas-based
Author-email: Ben Bartling <ben.bartling@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/bbartling/open-fdd
Project-URL: Documentation, https://bbartling.github.io/open-fdd/
Project-URL: Repository, https://github.com/bbartling/open-fdd
Keywords: hvac,fdd,fault-detection,building-automation,pandas,brick
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas
Requires-Dist: pyyaml
Requires-Dist: PyJWT>=2.0
Requires-Dist: argon2-cffi>=21.0
Provides-Extra: dev
Requires-Dist: aiohttp; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: black[jupyter]; extra == "dev"
Requires-Dist: pre-commit; extra == "dev"
Requires-Dist: httpx; extra == "dev"
Requires-Dist: psycopg2-binary; extra == "dev"
Requires-Dist: requests; extra == "dev"
Requires-Dist: pydantic-settings; extra == "dev"
Requires-Dist: fastapi; extra == "dev"
Requires-Dist: uvicorn[standard]; extra == "dev"
Requires-Dist: python-multipart; extra == "dev"
Requires-Dist: rdflib<8,>=7.5.0; extra == "dev"
Requires-Dist: pyparsing<3.2,>=2.1.0; extra == "dev"
Requires-Dist: openai>=1.0; extra == "dev"
Requires-Dist: ipykernel; extra == "dev"
Requires-Dist: matplotlib; extra == "dev"
Provides-Extra: test
Requires-Dist: aiohttp; extra == "test"
Requires-Dist: pytest; extra == "test"
Requires-Dist: black[jupyter]; extra == "test"
Requires-Dist: pre-commit; extra == "test"
Requires-Dist: httpx; extra == "test"
Requires-Dist: psycopg2-binary; extra == "test"
Requires-Dist: requests; extra == "test"
Requires-Dist: pydantic-settings; extra == "test"
Requires-Dist: fastapi; extra == "test"
Requires-Dist: uvicorn[standard]; extra == "test"
Requires-Dist: python-multipart; extra == "test"
Requires-Dist: rdflib<8,>=7.5.0; extra == "test"
Requires-Dist: pyparsing<3.2,>=2.1.0; extra == "test"
Requires-Dist: openai>=1.0; extra == "test"
Requires-Dist: ipykernel; extra == "test"
Requires-Dist: matplotlib; extra == "test"
Provides-Extra: e2e
Requires-Dist: selenium>=4.0; extra == "e2e"
Requires-Dist: webdriver-manager>=4.0; extra == "e2e"
Provides-Extra: viz
Requires-Dist: matplotlib; extra == "viz"
Provides-Extra: brick
Requires-Dist: rdflib<8,>=7.5.0; extra == "brick"
Requires-Dist: pyparsing<3.2,>=2.1.0; extra == "brick"
Provides-Extra: docx
Requires-Dist: python-docx; extra == "docx"
Provides-Extra: platform
Requires-Dist: psycopg2-binary; extra == "platform"
Requires-Dist: requests; extra == "platform"
Requires-Dist: httpx; extra == "platform"
Requires-Dist: pydantic-settings; extra == "platform"
Requires-Dist: fastapi; extra == "platform"
Requires-Dist: uvicorn[standard]; extra == "platform"
Requires-Dist: python-multipart; extra == "platform"
Requires-Dist: openai>=1.0; extra == "platform"
Provides-Extra: bacnet
Requires-Dist: bacpypes3; extra == "bacnet"
Requires-Dist: ifaddr; extra == "bacnet"
Requires-Dist: httpx; extra == "bacnet"
Provides-Extra: monitoring
Requires-Dist: docker; extra == "monitoring"
Dynamic: license-file

# Open-FDD

[![Discord](https://img.shields.io/badge/Discord-Join%20Server-5865F2.svg?logo=discord&logoColor=white)](https://discord.gg/Ta48yQF8fC)
[![CI](https://github.com/bbartling/open-fdd/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/bbartling/open-fdd/actions/workflows/ci.yml)
![MIT License](https://img.shields.io/badge/license-MIT-green.svg)
![Development Status](https://img.shields.io/badge/status-Beta-blue)
![Python](https://img.shields.io/badge/Python-3.9+-blue?logo=python&logoColor=white)
![BACnet](https://img.shields.io/badge/Protocol-BACnet-003366)
![TimescaleDB](https://img.shields.io/badge/TimescaleDB-compatible-FDB515?logo=timescale&logoColor=black)
![Grafana](https://img.shields.io/badge/Grafana-supported-F46800?logo=grafana&logoColor=white)
[![PyPI](https://img.shields.io/pypi/v/open-fdd?label=PyPI)](https://pypi.org/project/open-fdd/)


<div align="center">

![open-fdd logo](https://raw.githubusercontent.com/bbartling/open-fdd/master/image.png)

</div>

Open-FDD is an open-source knowledge graph fault-detection platform for HVAC systems that helps facilities optimize their energy usage and cost-savings. Because it runs on-prem, facilities never have to worry about a vendor hiking prices, going dark, or walking away with their data. The platform is an AFDD stack designed to run inside the building, behind the firewall, under the owner’s control. It transforms operational data into actionable, cost-saving insights and provides a secure integration layer that any cloud platform can use without vendor lock-in. U.S. Department of Energy research reports median energy savings of roughly 8–9% from FDD programs—meaningful annual savings depending on facility size and energy spend.

The building is modeled in a **unified graph**: Brick (sites, equipment, points), BACnet discovery RDF, platform config, and—as the project evolves—other ontologies such as ASHRAE 223P, in one semantic model queried via SPARQL and serialized to `config/data_model.ttl`.

---

## Quick Starts

### Open-FDD Engine-only (rules engine, no Docker) PyPi

If you only want the Python rules engine (without the full platform stack), you can use it in standard Python environments.

```bash
pip install open-fdd
```


### Open-FDD AFDD Platform Manually by the Human

Open-FDD uses Docker and Docker Compose to orchestrate and manage all platform services within a unified containerized environment. The bootstrap script (`./scripts/bootstrap.sh`) is **Linux-only** and intended for IoT edge applications using Docker exclusively.

### Debian / Ubuntu setup

- **Git:** Install Git if needed, e.g. `sudo apt update && sudo apt install git`.
- **Docker:** Follow the official guide to install Docker Engine (and Compose): [Install Docker Engine on Ubuntu](https://docs.docker.com/engine/install/ubuntu/).

### Prerequisites (Ubuntu / Debian-style)

After Docker is installed, add your Linux user to the **`docker`** group so you can run `docker` without `sudo` (log out and back in, or use `newgrp`, for the group change to apply):

```bash
sudo usermod -aG docker "$USER"
newgrp docker
docker ps
```

Create a Python virtual environment and install **`argon2-cffi`** (used to hash passwords for bootstrap):

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install argon2-cffi
```

Clone the repository:

```bash
git clone https://github.com/bbartling/open-fdd.git
```

### Standard HTTP bootstrap (no TLS) and app login

The `--bacnet-address` value is the static bind address for BACnet, which is the usual setup for BACnet/IP on operations technology (OT) LANs. Bootstrap supports **dual-NIC** hosts: use this address on the OT interface; your other interface can use DHCP for outbound internet access.

```bash
cd open-fdd

printf '%s' 'YourSecurePassword' | ./scripts/bootstrap.sh \
  --bacnet-address 192.168.204.16/24:47808 \
  --bacnet-instance 12345 \
  --user ben \
  --password-stdin
```

> **NOTE:** Both the DIY BACnet server and Open-FDD API in the **Standard HTTP bootstrap (no TLS)** configuration still require bearer tokens for authorization. These are defined in `open-fdd/stack/.env` and are set during the bootstrapping process.


### Standard hardened stack — self-signed TLS (Caddy) and app login

Open-FDD runs over TLS with self-signed certificates, and there is no access to the Open-FDD API or the DIY BACnet server Docker container APIs.


```bash
cd open-fdd

printf '%s' 'YourSecurePassword' | ./scripts/bootstrap.sh \
  --bacnet-address 192.168.204.16/24:47808 \
  --bacnet-instance 12345 \
  --user ben \
  --password-stdin \
  --caddy-self-signed
```

### Bootstrap Troubleshooting

```bash
./scripts/bootstrap.sh --doctor
```


Also available is the **partial stack** mode: `./scripts/bootstrap.sh --mode collector`, `--mode model`, or `--mode engine`. See the `Docs` below for more information.

---


## The open-fdd Pyramid


If OpenFDD nails the ontology, the project will be a huge success: an open-source knowledge graph for buildings. Everything else is just a nice add-on.

![Open-FDD system pyramid](https://raw.githubusercontent.com/bbartling/open-fdd/master/OpenFDD_system_pyramid.png)

---

## Online Documentation

- 📖 [**Docs**](https://bbartling.github.io/open-fdd/) — GitHub Pages (Linux quick start, stack, reference).
- 📕 [**Documentation PDF**](https://github.com/bbartling/open-fdd/blob/master/pdf/open-fdd-docs.pdf) — offline, Kindle-friendly documentation
- ✨ [**LLM prompt (copy/paste template)**](https://bbartling.github.io/open-fdd/modeling/llm_workflow#copy-paste-prompt-template-recommended) — export the data model (knowledge graph) as JSON, run an **external** LLM-assisted tagging workflow outside Open‑FDD, then re-import the JSON; the backend parses it on import.
- 🤖 [**Open‑Claw / external agents**](https://bbartling.github.io/open-fdd/openclaw_integration) — `GET /model-context/docs`, `GET /mcp/manifest`, data-model export/import for your own OpenAI-compatible stack.

---


## Dependencies

Authoritative lists and version pins: [`pyproject.toml`](pyproject.toml) (`dependencies` and `[project.optional-dependencies]`).

**Core** (installed with `pip install open-fdd`): [pandas](https://github.com/pandas-dev/pandas) · [PyYAML](https://github.com/yaml/pyyaml) · [PyJWT](https://github.com/jpadilla/pyjwt) · [argon2-cffi](https://github.com/hynek/argon2-cffi) (password hashing for auth).

**Platform / API** (extras e.g. `pip install "open-fdd[platform]"` or `.[dev]` in a clone): [FastAPI](https://fastapi.tiangolo.com/) · [Uvicorn](https://www.uvicorn.org/) · [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) · [httpx](https://www.python-httpx.org/) · [python-multipart](https://github.com/Kludex/python-multipart) · [psycopg2-binary](https://github.com/psycopg/psycopg2) · [requests](https://github.com/psf/requests) · [openai](https://github.com/openai/openai-python) (optional AI client).

**Brick / SPARQL / TTL** (extra `[brick]` or bundled in `.[dev]`): [rdflib](https://github.com/RDFLib/rdflib) · [pyparsing](https://github.com/pyparsing/pyparsing) (pinned range for SPARQL compatibility).

**BACnet** (extra `[bacnet]`): [bacpypes3](https://github.com/JoelBender/bacpypes3) · [ifaddr](https://github.com/pydron/ifaddr) · httpx.

**Viz** (extra `[viz]`): [matplotlib](https://github.com/matplotlib/matplotlib).

---

## Contributing

Open PRs against the **current integration branch** (e.g. **`develop`** or **`develop/vX.Y.Z`**), not **`master`** — **`master`** is release-only and protected.

**Tests:** `./scripts/bootstrap.sh --test` (frontend + pytest + Caddy; frontend tries Docker then host `npm`), or from repo root:

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest -v
```

**`.[dev]`** pulls in the full Python test deps; `pyproject.toml` sets default test paths. More detail: [docs/contributing.md](docs/contributing.md). Ask in **`#dev-chat`** on Discord if the active integration branch is unclear.

**Fork sync** (once add `upstream`, then as needed):

```bash
git remote add upstream https://github.com/bbartling/open-fdd.git
git fetch upstream && git checkout develop && git merge upstream/develop && git push origin develop
```

(Use your real integration branch name instead of `develop` if the project is on a versioned line.)

---

## License

MIT
