Energy database: hierarchy + series metadata on Postgres, bitemporal I/O via timedb
Project description
EnergyDB extends TimeDB with persistent storage for EnergyDataModel hierarchies — portfolios, sites, and assets — links them to time series with full auditability, and models grid topology via typed edges.
🏗️ How It Works
EnergyDB bridges two libraries:
- EnergyDataModel defines energy assets in Python (wind turbines, solar PV, batteries, etc.) organized into hierarchies (Portfolio → Site → Asset → TimeSeries), plus grid topology (JunctionPoint → Line → JunctionPoint).
- TimeDB stores time series in PostgreSQL with three-dimensional temporal tracking (valid time, knowledge time, change time).
EnergyDB adds node and edge tables to the same PostgreSQL database and links them to TimeDB's time series, enabling SQL joins across both.
Portfolio
└── Site "Offshore-1"
├── WindTurbine "T01" ← static: capacity, hub_height, ...
│ ├── TimeSeries "active_power" ← stored in TimeDB
│ └── TimeSeries "wind_speed" ← stored in TimeDB
├── WindTurbine "T02"
├── JunctionPoint "BusA"
└── JunctionPoint "BusB"
└── Line "Cable-1" (BusA → BusB) ← edge with own TimeSeries
🚀 Quick Start
1. Installation
pip install energydb
Requires Python 3.9+ and a PostgreSQL database (e.g., Neon, local Postgres, or any hosted provider).
2. Usage Example
Structure and data live in two separate calls so each can be re-run on its own
cadence. Identity is a UUID7 generated on every Element at construction; that same
UUID is the row PK in Postgres, so renames / moves / property edits round-trip in
place.
from datetime import UTC, datetime
import energydb as edb
import pandas as pd
client = edb.Client() # reads TIMEDB_PG_DSN / TIMEDB_CH_URL from env
client.create() # PG schema + CH series_values table
# 1. Declare each WindTurbine with its TimeSeriesDescriptors.
# Descriptors are structure-only (schema); data lands later via write().
t01 = edb.wind.WindTurbine(
name="T01", lat=55.01, lon=3.02, capacity=3.5, hub_height=80,
timeseries=[
edb.TimeSeriesDescriptor(name="power", unit="MW", data_type=edb.DataType.ACTUAL),
edb.TimeSeriesDescriptor(
name="power", unit="MW",
data_type=edb.DataType.FORECAST,
timeseries_type=edb.TimeSeriesType.OVERLAPPING,
),
],
)
t02 = edb.wind.WindTurbine(
name="T02", lat=55.01, lon=3.04, capacity=3.5, hub_height=80,
timeseries=[
edb.TimeSeriesDescriptor(name="power", unit="MW", data_type=edb.DataType.ACTUAL),
],
)
# 2. Group turbines under a Site.
offshore_1 = edb.Site(name="Offshore-1", lat=55.0, lon=3.0, members=[t01, t02])
# 3. Same pattern for the second site: PV system + battery.
pv01 = edb.solar.PVSystem(
name="PV01", capacity=10, surface_tilt=25, surface_azimuth=180,
timeseries=[
edb.TimeSeriesDescriptor(name="power", unit="MW", data_type=edb.DataType.ACTUAL),
],
)
b01 = edb.battery.Battery(name="B01", storage_capacity=1000, max_charge=500)
rooftop_1 = edb.Site(name="Rooftop-1", lat=52.0, lon=4.5, members=[pv01, b01])
# 4. Assemble the portfolio.
portfolio = edb.Portfolio(name="my-portfolio", members=[offshore_1, rooftop_1])
# 5. Persist the structure + series schemas. Idempotent.
client.register_tree(portfolio)
# 6. Write a day of hourly values for one series.
start = datetime(2026, 1, 1, tzinfo=UTC)
hours = pd.date_range(start, periods=24, freq="1h", tz="UTC")
df = pd.DataFrame({"valid_time": hours, "value": [2.5 + 0.05 * i for i in range(24)]})
client.get_node("my-portfolio", "Offshore-1", "T01").write(
df, name="power", data_type="actual",
)
# 7. Read with the fluent API — single asset, single series.
client.get_node("my-portfolio", "Offshore-1", "T01").read(
data_type="actual", name="power",
)
# Subtree read — all actuals for 'power' across the portfolio.
client.get_node("my-portfolio").read(data_type="actual", name="power")
# Filter descendants by EDM type.
client.get_node("my-portfolio").where(type="WindTurbine").read(data_type="actual", name="power")
# 8. Reconstruct the full EDM tree from the database.
tree = client.get_tree("my-portfolio", include_series=True)
3. Read → modify → write back
Because identity is the UUID, the round-trip preserves it. Renames, moves, and property edits become silent UPDATEs; explicit confirmation gates destructive ops.
tree = client.get_tree("my-portfolio") # uuids populated from PG
tree.members[0].name = "Renamed-Site" # silent rename
tree.members[0].members[0].capacity = 4.0 # silent property edit
del tree.members[0].members[1] # remove a turbine
# Preview before applying
diff = client.register_tree(
tree, mode="replace_subtree", allow_delete=True, dry_run=True,
)
diff.print()
# Apply
client.register_tree(tree, mode="replace_subtree", allow_delete=True)
🧪 Try It in Google Colab
Want to try EnergyDB without a local setup? Open our Quickstart in Colab.
Note: Data persists only within the active Colab session. Additional notebooks are available in the
examples/directory.
📦 Related Projects
| Project | Description |
|---|---|
| TimeDB | Time series database with auditability and overlapping forecast support |
| TimeDataModel | Pythonic data model for time series |
| EnergyDataModel | Data model for energy assets (solar, wind, battery, grid, ...) |
🤝 Contributing
Contributions are welcome! If you're interested in improving EnergyDB, please open an issue or pull request.
Licensed under the Apache-2.0 License.
Find a bug or have a feature request? Open an Issue.
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 energydb-0.3.1.tar.gz.
File metadata
- Download URL: energydb-0.3.1.tar.gz
- Upload date:
- Size: 59.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95a7269cf407eb75263aa3db3522107c7959d2c853966c7bfa7cf0afed44c996
|
|
| MD5 |
753e8e065d5abd7765ee16d6a11e447a
|
|
| BLAKE2b-256 |
19374ef5c512e96259af3666326795a1bd0d9b7d454059eb4a7049fc27c82e88
|
Provenance
The following attestation bundles were made for energydb-0.3.1.tar.gz:
Publisher:
publish.yml on rebase-energy/energydb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
energydb-0.3.1.tar.gz -
Subject digest:
95a7269cf407eb75263aa3db3522107c7959d2c853966c7bfa7cf0afed44c996 - Sigstore transparency entry: 1447951508
- Sigstore integration time:
-
Permalink:
rebase-energy/energydb@9114c955210f32f97e4e2e562ad060bab2677227 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/rebase-energy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9114c955210f32f97e4e2e562ad060bab2677227 -
Trigger Event:
release
-
Statement type:
File details
Details for the file energydb-0.3.1-py3-none-any.whl.
File metadata
- Download URL: energydb-0.3.1-py3-none-any.whl
- Upload date:
- Size: 44.5 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 |
0173100d05a42a9d482823b60038fd1303854d8c847cea37a4f5693711e299b2
|
|
| MD5 |
34f0f0c09f701e4510624c567bfc8ded
|
|
| BLAKE2b-256 |
880dd03730ff497c037b65558dfc28765603e8b3f48059ef3ccdcabcbfc9bad6
|
Provenance
The following attestation bundles were made for energydb-0.3.1-py3-none-any.whl:
Publisher:
publish.yml on rebase-energy/energydb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
energydb-0.3.1-py3-none-any.whl -
Subject digest:
0173100d05a42a9d482823b60038fd1303854d8c847cea37a4f5693711e299b2 - Sigstore transparency entry: 1447951639
- Sigstore integration time:
-
Permalink:
rebase-energy/energydb@9114c955210f32f97e4e2e562ad060bab2677227 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/rebase-energy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9114c955210f32f97e4e2e562ad060bab2677227 -
Trigger Event:
release
-
Statement type: