microgrid 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- microgrid-0.1.0/.gitignore +37 -0
- microgrid-0.1.0/CHANGELOG.md +67 -0
- microgrid-0.1.0/LICENSE +21 -0
- microgrid-0.1.0/PKG-INFO +106 -0
- microgrid-0.1.0/README.md +78 -0
- microgrid-0.1.0/examples/dataset/engine.toml +3 -0
- microgrid-0.1.0/examples/dataset/expected/ledger-2026-10-21.txt +6 -0
- microgrid-0.1.0/examples/dataset/expected/live-2026-10-25.txt +49 -0
- microgrid-0.1.0/examples/dataset/expected/replay-2026-10-22.txt +21 -0
- microgrid-0.1.0/examples/dataset/expected/value-2026-10-22T13-03.txt +290 -0
- microgrid-0.1.0/examples/dataset/expected/value-2026-10-25T02-30.txt +275 -0
- microgrid-0.1.0/examples/dataset/forecasts/load_forecast.json +1 -0
- microgrid-0.1.0/examples/dataset/forecasts/prices.json +1 -0
- microgrid-0.1.0/examples/dataset/forecasts/pv_forecast.json +1 -0
- microgrid-0.1.0/examples/dataset/manifest.json +70 -0
- microgrid-0.1.0/examples/dataset/plant.toml +35 -0
- microgrid-0.1.0/examples/dataset/series/battery.json +1 -0
- microgrid-0.1.0/examples/dataset/series/battery_first.json +1 -0
- microgrid-0.1.0/examples/dataset/series/export_price.json +1 -0
- microgrid-0.1.0/examples/dataset/series/grid.json +1 -0
- microgrid-0.1.0/examples/dataset/series/heartbeat.json +1 -0
- microgrid-0.1.0/examples/dataset/series/house.json +1 -0
- microgrid-0.1.0/examples/dataset/series/import_price.json +1 -0
- microgrid-0.1.0/examples/dataset/series/inverter.json +1 -0
- microgrid-0.1.0/examples/dataset/series/pv.json +1 -0
- microgrid-0.1.0/examples/dataset/series/soc.json +1 -0
- microgrid-0.1.0/pyproject.toml +123 -0
- microgrid-0.1.0/scripts/ci_local.sh +49 -0
- microgrid-0.1.0/scripts/griffe_microgrid.py +83 -0
- microgrid-0.1.0/scripts/install-hooks.sh +41 -0
- microgrid-0.1.0/scripts/make_example_dataset.py +249 -0
- microgrid-0.1.0/scripts/make_expected_outputs.py +55 -0
- microgrid-0.1.0/scripts/mkdocs_hooks.py +19 -0
- microgrid-0.1.0/src/microgrid/__init__.py +12 -0
- microgrid-0.1.0/src/microgrid/_checks.py +29 -0
- microgrid-0.1.0/src/microgrid/cli/__init__.py +35 -0
- microgrid-0.1.0/src/microgrid/cli/check_plant.py +171 -0
- microgrid-0.1.0/src/microgrid/cli/dataset.py +463 -0
- microgrid-0.1.0/src/microgrid/cli/evaluation.py +375 -0
- microgrid-0.1.0/src/microgrid/cli/fit_battery.py +430 -0
- microgrid-0.1.0/src/microgrid/cli/history.py +457 -0
- microgrid-0.1.0/src/microgrid/cli/inputs.py +248 -0
- microgrid-0.1.0/src/microgrid/cli/main.py +572 -0
- microgrid-0.1.0/src/microgrid/cli/offline.py +464 -0
- microgrid-0.1.0/src/microgrid/cli/replay.py +176 -0
- microgrid-0.1.0/src/microgrid/cli/sources/__init__.py +39 -0
- microgrid-0.1.0/src/microgrid/cli/sources/config.py +499 -0
- microgrid-0.1.0/src/microgrid/cli/sources/emhass.py +122 -0
- microgrid-0.1.0/src/microgrid/cli/sources/entity.py +133 -0
- microgrid-0.1.0/src/microgrid/cli/sources/fetch.py +119 -0
- microgrid-0.1.0/src/microgrid/cli/sources/home_assistant.py +153 -0
- microgrid-0.1.0/src/microgrid/cli/sources/predbat.py +99 -0
- microgrid-0.1.0/src/microgrid/cli/sources/read.py +254 -0
- microgrid-0.1.0/src/microgrid/cli/sources/solcast.py +147 -0
- microgrid-0.1.0/src/microgrid/cli/sources/tariffkit.py +147 -0
- microgrid-0.1.0/src/microgrid/cli/toml_text.py +75 -0
- microgrid-0.1.0/src/microgrid/engine/__init__.py +126 -0
- microgrid-0.1.0/src/microgrid/engine/_api.py +1289 -0
- microgrid-0.1.0/src/microgrid/engine/_assess.py +77 -0
- microgrid-0.1.0/src/microgrid/engine/_engine_config.py +214 -0
- microgrid-0.1.0/src/microgrid/engine/_inputs.py +108 -0
- microgrid-0.1.0/src/microgrid/engine/_live.py +305 -0
- microgrid-0.1.0/src/microgrid/engine/_stored.py +142 -0
- microgrid-0.1.0/src/microgrid/engine/_supply.py +138 -0
- microgrid-0.1.0/src/microgrid/engine/_surplus.py +146 -0
- microgrid-0.1.0/src/microgrid/engine/_timeline.py +40 -0
- microgrid-0.1.0/src/microgrid/engine/_value.py +1101 -0
- microgrid-0.1.0/src/microgrid/engine/analysis/__init__.py +2 -0
- microgrid-0.1.0/src/microgrid/engine/analysis/ground_truth.py +549 -0
- microgrid-0.1.0/src/microgrid/engine/analysis/scoring.py +334 -0
- microgrid-0.1.0/src/microgrid/engine/extend.py +66 -0
- microgrid-0.1.0/src/microgrid/engine/ledger.py +450 -0
- microgrid-0.1.0/src/microgrid/engine/py.typed +0 -0
- microgrid-0.1.0/src/microgrid/engine/schemas/valuation-2.schema.json +375 -0
- microgrid-0.1.0/src/microgrid/engine/series.py +821 -0
- microgrid-0.1.0/src/microgrid/engine/testing.py +284 -0
- microgrid-0.1.0/src/microgrid/engine/units.py +125 -0
- microgrid-0.1.0/src/microgrid/plant/__init__.py +74 -0
- microgrid-0.1.0/src/microgrid/plant/_battery.py +235 -0
- microgrid-0.1.0/src/microgrid/plant/_config.py +1249 -0
- microgrid-0.1.0/src/microgrid/plant/_meters.py +241 -0
- microgrid-0.1.0/src/microgrid/plant/_paths.py +1455 -0
- microgrid-0.1.0/src/microgrid/plant/_plant.py +456 -0
- microgrid-0.1.0/src/microgrid/plant/examples.py +162 -0
- microgrid-0.1.0/src/microgrid/plant/flows.py +417 -0
- microgrid-0.1.0/src/microgrid/plant/port.py +241 -0
- microgrid-0.1.0/src/microgrid/py.typed +0 -0
- microgrid-0.1.0/tests/architecture.py +610 -0
- microgrid-0.1.0/tests/cli/makeup/engine.toml +6 -0
- microgrid-0.1.0/tests/cli/makeup/live-2026-10-25.txt +49 -0
- microgrid-0.1.0/tests/cli/makeup/replay-2026-10-22.txt +21 -0
- microgrid-0.1.0/tests/cli/makeup/value-2026-10-22T13-03.txt +290 -0
- microgrid-0.1.0/tests/cli/makeup/value-2026-10-25T02-30.txt +275 -0
- microgrid-0.1.0/tests/cli/test_dataset.py +457 -0
- microgrid-0.1.0/tests/cli/test_end_to_end.py +51 -0
- microgrid-0.1.0/tests/cli/test_evaluation_properties.py +33 -0
- microgrid-0.1.0/tests/cli/test_fit_battery.py +32 -0
- microgrid-0.1.0/tests/cli/test_history.py +126 -0
- microgrid-0.1.0/tests/cli/test_main.py +444 -0
- microgrid-0.1.0/tests/cli/test_sources.py +464 -0
- microgrid-0.1.0/tests/engine_fixtures.py +404 -0
- microgrid-0.1.0/tests/legacy_dispatch.py +572 -0
- microgrid-0.1.0/tests/test_api.py +284 -0
- microgrid-0.1.0/tests/test_architecture.py +271 -0
- microgrid-0.1.0/tests/test_assess.py +18 -0
- microgrid-0.1.0/tests/test_by_source.py +406 -0
- microgrid-0.1.0/tests/test_config.py +732 -0
- microgrid-0.1.0/tests/test_dc_loads.py +540 -0
- microgrid-0.1.0/tests/test_dispatch_parts.py +354 -0
- microgrid-0.1.0/tests/test_engine_config.py +342 -0
- microgrid-0.1.0/tests/test_examples.py +141 -0
- microgrid-0.1.0/tests/test_ground_truth.py +429 -0
- microgrid-0.1.0/tests/test_inputs.py +407 -0
- microgrid-0.1.0/tests/test_internals.py +89 -0
- microgrid-0.1.0/tests/test_ledger.py +506 -0
- microgrid-0.1.0/tests/test_ledger_properties.py +114 -0
- microgrid-0.1.0/tests/test_limits.py +293 -0
- microgrid-0.1.0/tests/test_live_core.py +226 -0
- microgrid-0.1.0/tests/test_meters.py +509 -0
- microgrid-0.1.0/tests/test_models.py +105 -0
- microgrid-0.1.0/tests/test_outputs.py +105 -0
- microgrid-0.1.0/tests/test_paths.py +974 -0
- microgrid-0.1.0/tests/test_plant.py +314 -0
- microgrid-0.1.0/tests/test_plant_properties.py +186 -0
- microgrid-0.1.0/tests/test_port.py +841 -0
- microgrid-0.1.0/tests/test_projection.py +189 -0
- microgrid-0.1.0/tests/test_pv_per_array.py +319 -0
- microgrid-0.1.0/tests/test_rule_on_port.py +458 -0
- microgrid-0.1.0/tests/test_scoring.py +500 -0
- microgrid-0.1.0/tests/test_series.py +484 -0
- microgrid-0.1.0/tests/test_stored_cost.py +368 -0
- microgrid-0.1.0/tests/test_supply_properties.py +231 -0
- microgrid-0.1.0/tests/test_timeline_properties.py +63 -0
- microgrid-0.1.0/tests/test_units.py +115 -0
- microgrid-0.1.0/tests/test_value.py +367 -0
- microgrid-0.1.0/tests/test_without_battery_or_pv.py +544 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Secrets: never commit.
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
|
|
6
|
+
# Python
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
.venv/
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.coverage
|
|
14
|
+
.coverage.*
|
|
15
|
+
coverage.xml
|
|
16
|
+
htmlcov/
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.mypy_cache/
|
|
19
|
+
.ruff_cache/
|
|
20
|
+
.hypothesis/
|
|
21
|
+
|
|
22
|
+
# The documentation site's build (mkdocs.yml)
|
|
23
|
+
/site/
|
|
24
|
+
|
|
25
|
+
# Runtime
|
|
26
|
+
/tmp/
|
|
27
|
+
*.log
|
|
28
|
+
|
|
29
|
+
# Agent worktrees (Claude Code)
|
|
30
|
+
.claude/worktrees/
|
|
31
|
+
|
|
32
|
+
# Development records: kept locally, never published (the decisions, the research,
|
|
33
|
+
# their index and notes).
|
|
34
|
+
/docs/adr/
|
|
35
|
+
/docs/research/
|
|
36
|
+
/docs/INDEX.md
|
|
37
|
+
/docs/load-forecast.md
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Each user-visible change, under the release it ships in.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-10-18
|
|
8
|
+
|
|
9
|
+
The first version, under the MIT license.
|
|
10
|
+
|
|
11
|
+
### Added (library)
|
|
12
|
+
|
|
13
|
+
- **The plant model, `microgrid.plant`.** A plant described as data (`plant/2`): PV
|
|
14
|
+
arrays of either coupling, a battery on its own inverter or on a hybrid's DC bus,
|
|
15
|
+
loads on either bus, the grid's limits, grid-charge and export windows, hold rules
|
|
16
|
+
and the meters. `Plant.project` runs it slot by slot. It stands alone: importing it
|
|
17
|
+
loads none of the price code. Four example plants (`microgrid.plant.examples`), and
|
|
18
|
+
a port for a plant model of your own (`microgrid.plant.port`: `PlantModel`,
|
|
19
|
+
`Storage`), checked by `microgrid.engine.testing.assert_plant_model_contract`.
|
|
20
|
+
- **The price model, `microgrid.engine`.** Marginal prices from inputs given as time
|
|
21
|
+
series (`Inputs`: prices, PV forecast quantiles, the load forecast, the SOC, the
|
|
22
|
+
battery's lots). For each slot it gives:
|
|
23
|
+
- the marginal cost, and the same for a dull day (the PV forecast's p10);
|
|
24
|
+
- the regime, the certainties and the surplus;
|
|
25
|
+
- the supply stack;
|
|
26
|
+
- the value of a PV kWh and of a battery kWh diverted to a flexible load.
|
|
27
|
+
|
|
28
|
+
`Engine.value` gives these as a valuation (`valuation/2`). `Engine.live_session`
|
|
29
|
+
gives a live value between valuations.
|
|
30
|
+
- **A battery kWh** is priced at the running average cost of what the battery holds
|
|
31
|
+
(`Pricing.battery_value = "stored_cost"`), or by the make-up rule (`"replacement"`).
|
|
32
|
+
- **Missing or stale inputs** move values toward the import price, and the valuation
|
|
33
|
+
names them in `degraded`.
|
|
34
|
+
- **Configuration:** `engine/2`.
|
|
35
|
+
- **Series and units** (`microgrid.engine.series`, `microgrid.engine.units`).
|
|
36
|
+
- Forecasts are series of issues, read as a client had them at a moment.
|
|
37
|
+
- Units are converted at the edge.
|
|
38
|
+
- Money is in the prices' currency, never converted, and no name says one.
|
|
39
|
+
- **The battery's lots** (`microgrid.engine.ledger`): what the battery holds by source,
|
|
40
|
+
and what it cost.
|
|
41
|
+
- **Analysis** (`microgrid.engine.analysis`): the plant model scored against its meters,
|
|
42
|
+
and valuations scored against what each kWh realised.
|
|
43
|
+
|
|
44
|
+
### Added (command)
|
|
45
|
+
|
|
46
|
+
- **`microgrid` on a dataset** (`dataset/1`): `value`, `live`, `replay`, `check-plant`,
|
|
47
|
+
`ledger`, `fit-battery`, `config check` and `schema`. A dataset whose prices name two
|
|
48
|
+
currencies is refused.
|
|
49
|
+
- **`microgrid` on live sources** (`sources/1`, the `sources` extra): `sources`, `now` and
|
|
50
|
+
`fetch`. Each input comes from a provider's Home Assistant integration (TariffKit,
|
|
51
|
+
Solcast, EMHASS, Predbat) or an entity.
|
|
52
|
+
- **The example dataset** (`examples/dataset`): a synthetic week of an example plant in
|
|
53
|
+
Europe/Berlin, across the DST change, with the outputs it is expected to give.
|
|
54
|
+
|
|
55
|
+
### Added (releases)
|
|
56
|
+
|
|
57
|
+
- **Versions and releases:** semantic versioning, explained beside the formats', the
|
|
58
|
+
API's and the model's versions (`docs/reference/versions.md`); `microgrid --version`
|
|
59
|
+
prints the release with the API (`engine-api/5`) and the model (`pricing/1.3`) it
|
|
60
|
+
carries. Releases are published to
|
|
61
|
+
PyPI from a tag (`vX.Y.Z`).
|
|
62
|
+
|
|
63
|
+
### Added (documentation)
|
|
64
|
+
|
|
65
|
+
- **The documentation:** the methodology and the library's requirements (R-1 to R-9),
|
|
66
|
+
the concepts, how-to guides and the reference, published with each release at
|
|
67
|
+
`https://eman.github.io/microgrid/`.
|
microgrid-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Emmanuel Levijarvi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
microgrid-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: microgrid
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A plant model and marginal energy prices for a solar + battery microgrid: data in, data out
|
|
5
|
+
Project-URL: Homepage, https://github.com/eman/microgrid
|
|
6
|
+
Project-URL: Documentation, https://eman.github.io/microgrid/
|
|
7
|
+
Project-URL: Source, https://github.com/eman/microgrid
|
|
8
|
+
Project-URL: Changelog, https://github.com/eman/microgrid/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/eman/microgrid/issues
|
|
10
|
+
Author-email: Emmanuel Levijarvi <emansl@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: battery,energy,home energy,marginal price,microgrid,solar
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.14
|
|
24
|
+
Provides-Extra: sources
|
|
25
|
+
Requires-Dist: httpx>=0.28; extra == 'sources'
|
|
26
|
+
Requires-Dist: pydantic>=2.11; extra == 'sources'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# microgrid
|
|
30
|
+
|
|
31
|
+
`microgrid` is a library that models a solar + battery plant (`microgrid.plant`) and
|
|
32
|
+
produces **marginal energy prices** from it (`microgrid.engine`): what one more kWh
|
|
33
|
+
costs, slot by slot over a horizon, and the value of energy by source. The plant model
|
|
34
|
+
also stands alone, without the price code.
|
|
35
|
+
|
|
36
|
+
- **Data in, data out.** No I/O: a client hands in the plant's configuration
|
|
37
|
+
(`plant/2`) and its inputs as time series (prices, PV and load forecasts, the
|
|
38
|
+
meters), and gets prices, regimes, certainties and surplus back.
|
|
39
|
+
- **The plant model** takes its topology as configuration: PV of either coupling,
|
|
40
|
+
a battery on its own inverter or on a hybrid's DC bus, loads on either bus, the
|
|
41
|
+
grid's limits and charge windows.
|
|
42
|
+
|
|
43
|
+
The documentation is in [`docs/`](https://github.com/eman/microgrid/blob/main/docs/index.md),
|
|
44
|
+
published with each release at `https://eman.github.io/microgrid/`:
|
|
45
|
+
how the prices are made, the concepts, how-to guides and the reference.
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
pip install microgrid # or: uv add microgrid
|
|
51
|
+
pip install "microgrid[sources]" # with the readers of live sources (Home Assistant)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Python 3.14 or later. Before 1.0 a minor release may change a format, the API or the
|
|
55
|
+
model: pin the minor release you tested with (`microgrid ~= 0.1.0`,
|
|
56
|
+
[Versions](https://github.com/eman/microgrid/blob/main/docs/reference/versions.md)).
|
|
57
|
+
|
|
58
|
+
## The command
|
|
59
|
+
|
|
60
|
+
`microgrid` (`microgrid.cli`, installed with the library) runs it on a dataset
|
|
61
|
+
(`dataset/1`: a directory of series and the plant's and engine's files), so it needs no
|
|
62
|
+
plant at hand. `microgrid.cli` reads the files; the engine still does no I/O. The example
|
|
63
|
+
dataset (`examples/dataset`) is one synthetic week of the library's example plant in
|
|
64
|
+
Europe/Berlin, the DST change on 2026-10-25 inside it:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
uv run microgrid value --data examples/dataset --at 2026-10-22T13:00 # one valuation
|
|
68
|
+
uv run microgrid live --data examples/dataset --from 2026-10-22T06:00 --to 2026-10-22T20:00
|
|
69
|
+
uv run microgrid replay --data examples/dataset --from 2026-10-22 --to 2026-10-25
|
|
70
|
+
# valuations scored against the meters
|
|
71
|
+
uv run microgrid check-plant --data examples/dataset --from 2026-10-21 --to 2026-10-27
|
|
72
|
+
# the plant model against its meters
|
|
73
|
+
uv run microgrid ledger --data examples/dataset --from 2026-10-21 --to 2026-10-27
|
|
74
|
+
# the battery's lots and their cost split
|
|
75
|
+
uv run microgrid fit-battery --data examples/dataset --end 2026-10-28 --days 7
|
|
76
|
+
# the battery's conversion, fitted
|
|
77
|
+
uv run microgrid config check --data examples/dataset # its plant/2 and engine/2
|
|
78
|
+
uv run microgrid schema # the outputs' schema
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
With a `sources/1` file naming a provider per input (any of several, none assumed; the
|
|
82
|
+
`sources` extra, `microgrid[sources]`), it reads live inputs instead of a dataset:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
uv run microgrid sources --sources sources.toml # what each input is read from, or why not
|
|
86
|
+
uv run microgrid now --sources sources.toml # a valuation now; --save DIR keeps the inputs
|
|
87
|
+
uv run microgrid fetch --sources sources.toml --from 2026-10-01 --to 2026-10-08 --out DIR
|
|
88
|
+
# what was measured, as a dataset
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A time without an offset is the plant's local time (an hour that repeats, the first
|
|
92
|
+
time; one the clocks skip is refused).
|
|
93
|
+
|
|
94
|
+
## Development
|
|
95
|
+
|
|
96
|
+
Python 3.14, uv. See [AGENTS.md](https://github.com/eman/microgrid/blob/main/AGENTS.md) for the rules and conventions.
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
uv sync # .venv with the library and the dev tools
|
|
100
|
+
scripts/install-hooks.sh # pre-push runs the local gate
|
|
101
|
+
scripts/ci_local.sh # ruff, format, mypy --strict, the docs, pytest + coverage
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT: see [LICENSE](https://github.com/eman/microgrid/blob/main/LICENSE).
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# microgrid
|
|
2
|
+
|
|
3
|
+
`microgrid` is a library that models a solar + battery plant (`microgrid.plant`) and
|
|
4
|
+
produces **marginal energy prices** from it (`microgrid.engine`): what one more kWh
|
|
5
|
+
costs, slot by slot over a horizon, and the value of energy by source. The plant model
|
|
6
|
+
also stands alone, without the price code.
|
|
7
|
+
|
|
8
|
+
- **Data in, data out.** No I/O: a client hands in the plant's configuration
|
|
9
|
+
(`plant/2`) and its inputs as time series (prices, PV and load forecasts, the
|
|
10
|
+
meters), and gets prices, regimes, certainties and surplus back.
|
|
11
|
+
- **The plant model** takes its topology as configuration: PV of either coupling,
|
|
12
|
+
a battery on its own inverter or on a hybrid's DC bus, loads on either bus, the
|
|
13
|
+
grid's limits and charge windows.
|
|
14
|
+
|
|
15
|
+
The documentation is in [`docs/`](https://github.com/eman/microgrid/blob/main/docs/index.md),
|
|
16
|
+
published with each release at `https://eman.github.io/microgrid/`:
|
|
17
|
+
how the prices are made, the concepts, how-to guides and the reference.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
pip install microgrid # or: uv add microgrid
|
|
23
|
+
pip install "microgrid[sources]" # with the readers of live sources (Home Assistant)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Python 3.14 or later. Before 1.0 a minor release may change a format, the API or the
|
|
27
|
+
model: pin the minor release you tested with (`microgrid ~= 0.1.0`,
|
|
28
|
+
[Versions](https://github.com/eman/microgrid/blob/main/docs/reference/versions.md)).
|
|
29
|
+
|
|
30
|
+
## The command
|
|
31
|
+
|
|
32
|
+
`microgrid` (`microgrid.cli`, installed with the library) runs it on a dataset
|
|
33
|
+
(`dataset/1`: a directory of series and the plant's and engine's files), so it needs no
|
|
34
|
+
plant at hand. `microgrid.cli` reads the files; the engine still does no I/O. The example
|
|
35
|
+
dataset (`examples/dataset`) is one synthetic week of the library's example plant in
|
|
36
|
+
Europe/Berlin, the DST change on 2026-10-25 inside it:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
uv run microgrid value --data examples/dataset --at 2026-10-22T13:00 # one valuation
|
|
40
|
+
uv run microgrid live --data examples/dataset --from 2026-10-22T06:00 --to 2026-10-22T20:00
|
|
41
|
+
uv run microgrid replay --data examples/dataset --from 2026-10-22 --to 2026-10-25
|
|
42
|
+
# valuations scored against the meters
|
|
43
|
+
uv run microgrid check-plant --data examples/dataset --from 2026-10-21 --to 2026-10-27
|
|
44
|
+
# the plant model against its meters
|
|
45
|
+
uv run microgrid ledger --data examples/dataset --from 2026-10-21 --to 2026-10-27
|
|
46
|
+
# the battery's lots and their cost split
|
|
47
|
+
uv run microgrid fit-battery --data examples/dataset --end 2026-10-28 --days 7
|
|
48
|
+
# the battery's conversion, fitted
|
|
49
|
+
uv run microgrid config check --data examples/dataset # its plant/2 and engine/2
|
|
50
|
+
uv run microgrid schema # the outputs' schema
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
With a `sources/1` file naming a provider per input (any of several, none assumed; the
|
|
54
|
+
`sources` extra, `microgrid[sources]`), it reads live inputs instead of a dataset:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
uv run microgrid sources --sources sources.toml # what each input is read from, or why not
|
|
58
|
+
uv run microgrid now --sources sources.toml # a valuation now; --save DIR keeps the inputs
|
|
59
|
+
uv run microgrid fetch --sources sources.toml --from 2026-10-01 --to 2026-10-08 --out DIR
|
|
60
|
+
# what was measured, as a dataset
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
A time without an offset is the plant's local time (an hour that repeats, the first
|
|
64
|
+
time; one the clocks skip is refused).
|
|
65
|
+
|
|
66
|
+
## Development
|
|
67
|
+
|
|
68
|
+
Python 3.14, uv. See [AGENTS.md](https://github.com/eman/microgrid/blob/main/AGENTS.md) for the rules and conventions.
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
uv sync # .venv with the library and the dev tools
|
|
72
|
+
scripts/install-hooks.sh # pre-push runs the local gate
|
|
73
|
+
scripts/ci_local.sh # ruff, format, mypy --strict, the docs, pytest + coverage
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT: see [LICENSE](https://github.com/eman/microgrid/blob/main/LICENSE).
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
the battery's lots, 2026-10-21 00:00 CEST to 2026-10-28 00:00 CET (1014 slots)
|
|
2
|
+
source charged kWh cost USD to load kWh USD exported kWh held kWh USD USD/kWh
|
|
3
|
+
unknown 0.000 0.000 6.000 0.000 0.000 0.000 0.000 -
|
|
4
|
+
pv 40.497 2.968 34.184 2.505 0.000 6.397 0.469 0.0733
|
|
5
|
+
grid 15.249 2.902 15.249 2.902 0.000 0.000 0.000 -
|
|
6
|
+
unexplained: 0.084 kWh (the meters against the SOC)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
at marginal import surplus kW regime degraded
|
|
2
|
+
2026-10-25 01:00:00 CEST 0.1800 0.1800 0.000 import -
|
|
3
|
+
2026-10-25 01:05:00 CEST 0.1800 0.1800 0.000 import -
|
|
4
|
+
2026-10-25 01:10:00 CEST 0.1800 0.1800 0.000 import -
|
|
5
|
+
2026-10-25 01:15:00 CEST 0.1800 0.1800 0.000 import -
|
|
6
|
+
2026-10-25 01:20:00 CEST 0.1800 0.1800 0.000 import -
|
|
7
|
+
2026-10-25 01:25:00 CEST 0.1800 0.1800 0.000 import -
|
|
8
|
+
2026-10-25 01:30:00 CEST 0.1800 0.1800 0.000 import -
|
|
9
|
+
2026-10-25 01:35:00 CEST 0.1800 0.1800 0.000 import -
|
|
10
|
+
2026-10-25 01:40:00 CEST 0.1800 0.1800 0.000 import -
|
|
11
|
+
2026-10-25 01:45:00 CEST 0.1800 0.1800 0.000 import -
|
|
12
|
+
2026-10-25 01:50:00 CEST 0.1800 0.1800 0.000 import -
|
|
13
|
+
2026-10-25 01:55:00 CEST 0.1800 0.1800 0.000 import -
|
|
14
|
+
2026-10-25 02:00:00 CEST 0.1800 0.1800 0.000 import -
|
|
15
|
+
2026-10-25 02:05:00 CEST 0.1800 0.1800 0.000 import -
|
|
16
|
+
2026-10-25 02:10:00 CEST 0.1800 0.1800 0.000 import -
|
|
17
|
+
2026-10-25 02:15:00 CEST 0.1800 0.1800 0.000 import -
|
|
18
|
+
2026-10-25 02:20:00 CEST 0.1800 0.1800 0.000 import -
|
|
19
|
+
2026-10-25 02:25:00 CEST 0.1800 0.1800 0.000 import -
|
|
20
|
+
2026-10-25 02:30:00 CEST 0.1800 0.1800 0.000 import -
|
|
21
|
+
2026-10-25 02:35:00 CEST 0.1800 0.1800 0.000 import -
|
|
22
|
+
2026-10-25 02:40:00 CEST 0.1800 0.1800 0.000 import -
|
|
23
|
+
2026-10-25 02:45:00 CEST 0.1800 0.1800 0.000 import -
|
|
24
|
+
2026-10-25 02:50:00 CEST 0.1800 0.1800 0.000 import -
|
|
25
|
+
2026-10-25 02:55:00 CEST 0.1800 0.1800 0.000 import -
|
|
26
|
+
2026-10-25 02:00:00 CET 0.1800 0.1800 0.000 import -
|
|
27
|
+
2026-10-25 02:05:00 CET 0.1800 0.1800 0.000 import -
|
|
28
|
+
2026-10-25 02:10:00 CET 0.1800 0.1800 0.000 import -
|
|
29
|
+
2026-10-25 02:15:00 CET 0.1800 0.1800 0.000 import -
|
|
30
|
+
2026-10-25 02:20:00 CET 0.1800 0.1800 0.000 import -
|
|
31
|
+
2026-10-25 02:25:00 CET 0.1800 0.1800 0.000 import -
|
|
32
|
+
2026-10-25 02:30:00 CET 0.1800 0.1800 0.000 import -
|
|
33
|
+
2026-10-25 02:35:00 CET 0.1800 0.1800 0.000 import -
|
|
34
|
+
2026-10-25 02:40:00 CET 0.1800 0.1800 0.000 import -
|
|
35
|
+
2026-10-25 02:45:00 CET 0.1800 0.1800 0.000 import -
|
|
36
|
+
2026-10-25 02:50:00 CET 0.1800 0.1800 0.000 import -
|
|
37
|
+
2026-10-25 02:55:00 CET 0.1800 0.1800 0.000 import -
|
|
38
|
+
2026-10-25 03:00:00 CET 0.1800 0.1800 0.000 import -
|
|
39
|
+
2026-10-25 03:05:00 CET 0.1800 0.1800 0.000 import -
|
|
40
|
+
2026-10-25 03:10:00 CET 0.1800 0.1800 0.000 import -
|
|
41
|
+
2026-10-25 03:15:00 CET 0.1800 0.1800 0.000 import -
|
|
42
|
+
2026-10-25 03:20:00 CET 0.1800 0.1800 0.000 import -
|
|
43
|
+
2026-10-25 03:25:00 CET 0.1800 0.1800 0.000 import -
|
|
44
|
+
2026-10-25 03:30:00 CET 0.1800 0.1800 0.000 import -
|
|
45
|
+
2026-10-25 03:35:00 CET 0.1800 0.1800 0.000 import -
|
|
46
|
+
2026-10-25 03:40:00 CET 0.1800 0.1800 0.000 import -
|
|
47
|
+
2026-10-25 03:45:00 CET 0.1800 0.1800 0.000 import -
|
|
48
|
+
2026-10-25 03:50:00 CET 0.1800 0.1800 0.000 import -
|
|
49
|
+
2026-10-25 03:55:00 CET 0.1800 0.1800 0.000 import -
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
48 valuations every 1:00:00 scored, 7053 slots inside the span; fell back (not scored): 0; no prices: 0
|
|
2
|
+
|
|
3
|
+
surplus kW against the PV exported or curtailed, by hours ahead:
|
|
4
|
+
bucket n bias MAE p10 n p10 met
|
|
5
|
+
0-1h 288 +0.016 0.019 27 100.0%
|
|
6
|
+
1-3h 558 +0.026 0.029 47 100.0%
|
|
7
|
+
3-12h 2214 -0.006 0.038 105 100.0%
|
|
8
|
+
12-48h 3993 -0.020 0.074 126 100.0%
|
|
9
|
+
|
|
10
|
+
marginal cost against the price a kWh realised (USD/kWh), by hours ahead:
|
|
11
|
+
bucket n outcomes bias MAE off
|
|
12
|
+
0-1h 246 11 -0.0007 0.0043 2.4%
|
|
13
|
+
1-3h 474 11 -0.0011 0.0047 6.3%
|
|
14
|
+
3-12h 1836 10 -0.0002 0.0041 16.5%
|
|
15
|
+
12-48h 2610 6 +0.0022 0.0032 2.9%
|
|
16
|
+
|
|
17
|
+
regime against the metered regime:
|
|
18
|
+
0-1h 278 of 288 agreed
|
|
19
|
+
1-3h 540 of 558 agreed
|
|
20
|
+
3-12h 2170 of 2214 agreed
|
|
21
|
+
12-48h 3907 of 3993 agreed
|