Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
195 commits
Select commit Hold shift + click to select a range
7b8dbf4
feat: added HomeLoadEnergyInterval and HomeLoadPowerPoint
markoceri Oct 17, 2025
03bc8a4
feat: add EnergyLoadHistoryProviderAdapter
markoceri Oct 17, 2025
72fa3a5
feat: implement EnergyLoadHistoryProviderPort for historical energy l…
markoceri Oct 17, 2025
d116600
refactor: fix HomeForecastProviderPort constructor and improved funct…
markoceri Oct 17, 2025
38ff095
feat: enhance HomeLoadsProfileRepository with CRUD methods and detail…
markoceri Oct 17, 2025
62a8123
feat: add home_forecast_provider_id to LoadDevice entity for home for…
markoceri Oct 17, 2025
9caa8bb
feat: add EnergyLoadHistoryProviderError and EnergyLoadHistoryProvide…
markoceri Oct 17, 2025
136c864
feat: refactored ConsumptionForecast with avg_energy and avg_power co…
markoceri Oct 17, 2025
d61f0a8
refactor: change devices type from Dict to List in HomeLoadsProfile
markoceri Oct 17, 2025
6ee0899
feat: add home_loads_profile assignment method and update entity refe…
markoceri Oct 17, 2025
ed8af4e
feat: enhance DummyHomeForecastProvider with history-based prediction…
markoceri Oct 17, 2025
6686f89
feat: implement Home Assistant API Energy Load History provider with …
markoceri Oct 17, 2025
7b8be7f
feat: add EnergyLoadHistoryAdapterFactory for energy load history ada…
markoceri Oct 17, 2025
f3160cf
feat: add EnergyLoadHistoryProviderConfig interface for energy load h…
markoceri Oct 17, 2025
b754814
feat: add EnergyLoadHistoryProviderHomeAssistantAPIConfig for Home As…
markoceri Oct 17, 2025
7a22a12
feat: add EntityState enum for representing different states of an Ho…
markoceri Oct 17, 2025
b60b3d7
feat: add get_entity_history method to retrieve Home Assistant entity…
markoceri Oct 17, 2025
9e459fc
feat: add data models for Home Assistant entity history
markoceri Oct 17, 2025
3ce92c4
feat: add abstract methods for managing home loads profiles and load …
markoceri Oct 17, 2025
709a835
feat: enhance optimization service to manage home loads profiles and …
markoceri Oct 17, 2025
2a71a71
feat: add validation schemas for home load domain entities and config…
markoceri Oct 17, 2025
21e5416
feat: add FastAPI adapter for Home load domain API
markoceri Oct 17, 2025
58ef311
feat: add custom exceptions for home loads profiles management
markoceri Nov 6, 2025
e881539
feat: add LoadDeviceCategory enum for categorizing load devices by co…
markoceri Nov 6, 2025
95a54c2
feat: update LoadDevice entity to include category and enabled attrib…
markoceri Nov 6, 2025
cf9accf
feat: refactor add_load_device_to_profile method to accept LoadDevice…
markoceri Nov 6, 2025
28ad9b8
feat: rename HomeForecastProvider to EnergyLoadForecastProvider and u…
markoceri Nov 7, 2025
405ba1b
feat: moved dummy home forecast provider and add energy load history …
markoceri Nov 7, 2025
6736e5b
fix: correct import path for DummyHomeForecastProvider in adapter_ser…
markoceri Nov 7, 2025
7c17d18
feat: add EnergyLoadHistoryProvider entity and update imports in enti…
markoceri Nov 7, 2025
41eef51
fix: update import statements and class inheritance for DummyHomeFore…
markoceri Nov 7, 2025
c0eeb19
refactor: rename DummyHomeForecastProvider to EnergyLoadForecastProvi…
markoceri Nov 7, 2025
c018346
refactor: removed history_provider parameter from EnergyLoadForecastP…
markoceri Nov 10, 2025
a217743
refactor: update get_consumption_forecast method to include consumpti…
markoceri Nov 11, 2025
abd6687
refactor: rename ConsumptionForecast class to LoadEnergyConsumption a…
markoceri Nov 11, 2025
7ac341e
feat: add EnergyLoadHistoryRepository with methods for store HomeLoad…
markoceri Nov 11, 2025
a5ad6e5
refactor: add reference to the history provider for LoadDevice
markoceri Nov 11, 2025
69f1ad2
refactor: update EnergyLoadHistoryProviderPort constructor to include…
markoceri Nov 11, 2025
e106c04
fix: declared EnergyLoadHistoryRepository first for injection into En…
markoceri Nov 11, 2025
f19a771
feat: add API router for home load domain and integrate with main app…
markoceri Apr 21, 2026
64a5494
Merge remote-tracking branch 'origin/dev' into home-load-api
markoceri Apr 21, 2026
fe231ad
refactor: rename home forecast exceptions to energy load forecast exc…
markoceri Apr 21, 2026
4cf544a
refactor: rename HomeForecastProviderConfig to EnergyLoadForecastProv…
markoceri Apr 21, 2026
b6b38b9
Refactor home load schemas and entities to support energy load foreca…
markoceri Apr 21, 2026
821104f
refactor: remove assign_home_forecast_provider method from EnergyOpti…
markoceri Apr 22, 2026
82e85e9
refactor: remove home_forecast_provider_id from SqliteOptimizationUni…
markoceri Apr 22, 2026
3b57bf8
refactor: rename home_forecast_providers to energy_load_forecast_prov…
markoceri Apr 22, 2026
6c82080
refactor: rename home_forecast_provider to energy_load_forecast_provi…
markoceri Apr 22, 2026
a44bfa8
refactor: update home load forecast provider references to energy loa…
markoceri Apr 22, 2026
76d10f7
refactor: rename home forecast provider references to energy load for…
markoceri Apr 22, 2026
c5501ff
refactor: rename DummyHomeForecastProvider to DummyEnergyLoadForecast…
markoceri Apr 22, 2026
691dd08
refactor: remove home_forecast_provider_id column from optimization_u…
markoceri Apr 22, 2026
5ec12c9
refactor: remove home_forecast_provider_id from EnergyOptimizationUni…
markoceri Apr 22, 2026
ccd0831
refactor: rename home forecast provider references to energy load for…
markoceri Apr 22, 2026
e652f85
refactor: remove home_forecast_provider_id from optimization unit add…
markoceri Apr 22, 2026
b66e5c4
refactor: remove home_forecast_provider_id from optimization unit com…
markoceri Apr 22, 2026
adbf332
refactor: rename home forecast provider to energy load forecast provi…
markoceri Apr 22, 2026
464ab6a
refactor: rename home forecast provider references to energy load for…
markoceri Apr 22, 2026
1b9b9f4
refactor: update method docstrings and parameter names in EnergyLoadF…
markoceri Apr 22, 2026
84e5388
refactor: enhance HomeLoadsProfileRepository with additional methods …
markoceri Apr 22, 2026
a30d6d2
refactor: update LoadDevice serialization to handle lists and enhance…
markoceri Apr 22, 2026
6d83a84
refactor: enhance ConfigurationService with HomeLoadsProfile manageme…
markoceri Apr 22, 2026
a209f75
refactor: rename delete_home_loads_profile method to remove_home_load…
markoceri Apr 22, 2026
cbc6fe7
refactor: enhance LoadEnergyConsumption and add LoadDeviceConsumption…
markoceri Apr 22, 2026
2e52927
refactor: enhance HomeLoadsProfile with device management methods and…
markoceri Apr 22, 2026
5e40075
refactor: update home loads profile methods to raise errors on missin…
markoceri Apr 22, 2026
81bbaec
refactor: update DecisionalContext to use HomeLoadsConsumption instea…
markoceri Apr 22, 2026
96c8a1e
refactor: implement home loads consumption aggregation and device man…
markoceri Apr 22, 2026
35cf585
refactor: simplify DummyEnergyLoadForecastProvider by removing histor…
markoceri Apr 22, 2026
f791785
refactor: add LoadDeviceConsumptionSchema and HomeLoadsConsumptionSch…
markoceri Apr 22, 2026
87740e3
refactor: rename home_load_forecast to home_load in DecisionalContext…
markoceri Apr 22, 2026
81e4c4b
refactor: enhance EnergyLoadHistoryRepository and EnergyLoadHistoryPr…
markoceri Apr 22, 2026
fb078a6
refactor: enhance EnergyLoadHistoryAdapterFactory with device-scoped …
markoceri Apr 22, 2026
d400138
refactor: enhance HomeAssistantAPIEnergyLoadHistoryProvider with impr…
markoceri Apr 22, 2026
0e2ce2c
refactor: implement EnergyLoadHistoryRepository with in-memory and SQ…
markoceri Apr 22, 2026
efc5e49
refactor: add HomeLoadPowerPoint table for device-scoped time series …
markoceri Apr 22, 2026
600b2f3
refactor: add EnergyLoadHistoryRepository to bootstrap and infrastruc…
markoceri Apr 22, 2026
156ff0c
refactor: add home_load_power_points table for device-scoped power po…
markoceri Apr 22, 2026
14d2c1b
refactor: update EnergyLoadHistoryProvider to use correct configurati…
markoceri Apr 22, 2026
9393d00
fix: update EnergyLoadHistoryProviderRepository to use correct entity…
markoceri Apr 22, 2026
810abc6
refactor: update EnergyLoadHistoryProviderError to inherit from HomeL…
markoceri Apr 22, 2026
baf33bf
refactor: add EnergyLoadHistoryProviderAdapter and related configurat…
markoceri Apr 22, 2026
e6dae27
refactor: include EnergyLoadHistoryProvider in ExternalServiceLinkedE…
markoceri Apr 22, 2026
fd52265
refactor: add EnergyLoadHistoryProviderRepository to PersistenceSettings
markoceri Apr 22, 2026
c7067b9
feat: add get_home_load_history_provider method to AdapterServiceInte…
markoceri Apr 22, 2026
e35b015
feat: add energy load history provider support to AdapterService
markoceri Apr 22, 2026
213e950
feat: add EnergyLoadHistoryProvider management methods to Configurati…
markoceri Apr 22, 2026
e570932
feat: add EnergyLoadHistoryProvider table and mapping with serializat…
markoceri Apr 22, 2026
9beed27
feat: implement EnergyLoadHistoryProvider repository with in-memory a…
markoceri Apr 22, 2026
6f3877d
refactor: replace internal grouping method with helper function for p…
markoceri Apr 22, 2026
73705cc
feat: add helper function to group power points into 1-hour intervals
markoceri Apr 22, 2026
d22156d
feat: implement DummyEnergyLoadHistoryProvider for cached power point…
markoceri Apr 22, 2026
db305ae
feat: add EnergyLoadHistoryProvider support in bootstrap configuration
markoceri Apr 22, 2026
5bc9c19
feat: add EnergyLoadHistoryProvider schemas for entity management
markoceri Apr 22, 2026
05519e6
feat: add EnergyLoadHistoryProviderSchema to ExternalServiceLinkedEnt…
markoceri Apr 22, 2026
ac86bc9
feat: add energy_load_history_providers table with schema and index
markoceri Apr 22, 2026
266c58f
feat: add endpoints for managing energy load history providers
markoceri Apr 22, 2026
0cae608
feat: add energy_load_history_provider_repo to mock persistence and t…
markoceri Apr 22, 2026
e771001
feat: integrate energy load history providers into optimization service
markoceri Apr 22, 2026
e0ccf59
feat: add LoadConsumptionHistoryCollectedEvent and LoadConsumptionHis…
markoceri Apr 22, 2026
6b29231
feat: add HomeLoadHistoryServiceInterface for home load history inges…
markoceri Apr 22, 2026
df01122
feat: add HomeLoadHistoryServiceInterface to Services for home load m…
markoceri Apr 22, 2026
e9eadf3
feat: implement HomeLoadHistoryService for collecting and purging hom…
markoceri Apr 22, 2026
c973690
feat: update scheduler settings for history ingestion and retention i…
markoceri Apr 22, 2026
91089e6
feat: enhance AutomationScheduler to include history collection and p…
markoceri Apr 22, 2026
816b323
feat: integrate HomeLoadHistoryService into dependency configuration
markoceri Apr 22, 2026
3b4dabc
feat: inject HomeLoadHistoryService into main_async for enhanced func…
markoceri Apr 22, 2026
b0ae450
feat: add new energy load forecast provider types for enhanced foreca…
markoceri Apr 22, 2026
0d603d5
feat: implement NaiveLastHourForecastProvider for energy load forecas…
markoceri Apr 22, 2026
d4c0c3a
feat: add SeasonalBaselineForecastProvider for energy load forecasting
markoceri Apr 22, 2026
09c28a5
feat: add NaiveLastHourForecastProvider and SeasonalBaselineForecastP…
markoceri Apr 22, 2026
348e31e
feat: add NaiveLastHour and SeasonalBaseline forecast provider config…
markoceri Apr 22, 2026
3f18724
feat: update home load adapter maps to include NaiveLastHour and Seas…
markoceri Apr 22, 2026
a083185
feat: add schemas for NaiveLastHour and SeasonalBaseline EnergyLoadFo…
markoceri Apr 22, 2026
c5e11b6
feat: add EnergyLoadForecastAdapterFactory for energy load forecasting
markoceri Apr 22, 2026
88a501d
feat: add factories for Dummy, NaiveLastHour, and SeasonalBaseline fo…
markoceri Apr 22, 2026
4af1a18
feat: refactor adapter service to use factory classes for energy load…
markoceri Apr 22, 2026
db277fc
feat: add pre-computed window properties for LoadEnergyConsumption
markoceri Apr 22, 2026
589f4fc
feat: enhance _get_field_value to support dict key lookup and improve…
markoceri Apr 22, 2026
62373fc
feat: update home load forecast fields in mining rules for improved a…
markoceri Apr 22, 2026
4cec270
feat: add tests for dict key lookup in _get_field_value and condition…
markoceri Apr 22, 2026
3c79615
feat: add configurations for Statsmodels and XGBoost forecast providers
markoceri Apr 22, 2026
fc9eb36
feat: add LoadConsumptionModelRepository for managing LoadConsumption…
markoceri Apr 22, 2026
9b6f7cf
feat: add LoadConsumptionModel entity for ML model management in fore…
markoceri Apr 22, 2026
cde7be4
feat: add LoadConsumptionModelRepository and LoadForecastModelTrainin…
markoceri Apr 22, 2026
0207c96
feat: implement LoadForecastModelTrainingService for training ML mode…
markoceri Apr 22, 2026
7693a6d
feat: add Statsmodels and XGBoost forecast provider factories to Adap…
markoceri Apr 22, 2026
59b0916
feat: add Statsmodels and XGBoost forecast provider implementations f…
markoceri Apr 22, 2026
f4fb886
feat: add in-memory LoadConsumptionModel repository and integrate int…
markoceri Apr 22, 2026
0605eed
feat: add schemas for Statsmodels and XGBoost EnergyLoadForecastProvi…
markoceri Apr 22, 2026
009dd3c
feat: add model training job to AutomationScheduler for nightly ML mo…
markoceri Apr 22, 2026
408e419
feat: integrate load forecast training service into main_async function
markoceri Apr 22, 2026
cc41282
feat: add ML dependencies for scikit-learn, statsmodels, and xgboost
markoceri Apr 22, 2026
ab9b4aa
feat: add load_consumption_models table and mapping for ML model storage
markoceri Apr 22, 2026
db1ec09
feat: implement SQLite and SQLAlchemy repositories for LoadConsumptio…
markoceri Apr 22, 2026
cff0bce
feat: add LoadConsumptionModelRepository to persistence configuration
markoceri Apr 22, 2026
d3f59b8
feat: implement energy load forecast provider management in configura…
markoceri Apr 23, 2026
777a461
feat: implement energy load forecast provider management in configura…
markoceri Apr 23, 2026
806b7b8
feat: add energy load history provider ID to LoadDevice schema and va…
markoceri Apr 23, 2026
93027f0
feat: update load device to handle UUIDs for energy load forecast and…
markoceri Apr 23, 2026
9e2befb
feat: add method to retrieve all LoadConsumptionModels in LoadConsump…
markoceri Apr 23, 2026
4b934d7
feat: add get_all method to LoadConsumptionModelRepository implementa…
markoceri Apr 23, 2026
f82cb8c
feat: enhance home load services with device history retrieval and mo…
markoceri Apr 23, 2026
34577c6
feat: update load forecast training service interface reference in in…
markoceri Apr 23, 2026
fb46072
feat: add schemas for LoadConsumptionModel and HomeLoadPowerPoint ent…
markoceri Apr 23, 2026
bf74fdd
feat: add device history retrieval and training endpoints to home loa…
markoceri Apr 23, 2026
4d97e39
feat: add dependency injection for HomeLoadHistoryService and LoadFor…
markoceri Apr 23, 2026
2a71c38
feat: add unit tests for HomeLoadHistoryService.get_device_history
markoceri Apr 23, 2026
4ed4d65
feat: add unit tests for LoadForecastModelTrainingService methods
markoceri Apr 23, 2026
519a3d8
feat: add unit tests for InMemoryLoadConsumptionModelRepository.get_a…
markoceri Apr 23, 2026
5c43e51
feat: add initial test files for home load domain adapters
markoceri Apr 23, 2026
6a952a4
feat: add unit tests for home load API endpoints including device his…
markoceri Apr 23, 2026
bde4c9c
feat: update schemas and router to use WattHours and LoadDeviceCatego…
markoceri Apr 23, 2026
7e75ad6
feat: update home load history provider methods to support async oper…
markoceri Apr 24, 2026
bd4c7c5
feat: update imports in interfaces.py to include Timestamp and remove…
markoceri Apr 24, 2026
32077fa
feat: update collect_for_device method to support async history provi…
markoceri Apr 24, 2026
32b8609
feat: add endpoints for collecting device history and triggering hist…
markoceri Apr 24, 2026
fc3b88a
feat: add methods to retrieve external service adapters for energy lo…
markoceri Apr 24, 2026
6ea5c40
feat: add endpoints to retrieve external service types for energy loa…
markoceri Apr 24, 2026
2c652bb
feat: update timestamp handling to use datetime.now() for accurate ti…
markoceri Apr 24, 2026
32ff828
feat: refactor Home Assistant API methods to support async operations…
markoceri Apr 24, 2026
54e08b6
feat: add abstract method to clear device history in EnergyLoadHistor…
markoceri Apr 24, 2026
493d0f8
feat: add clear_device_history method to EnergyLoadHistoryRepository …
markoceri Apr 24, 2026
4ba0f49
feat: implement clear_device_history method in HomeLoadHistoryService
markoceri Apr 24, 2026
1701c65
feat: add endpoint to delete device history for home loads profiles
markoceri Apr 24, 2026
731ff0b
feat: add timezone support for datetime in home load history services…
markoceri Apr 24, 2026
4e73187
feat: fix datetime handling for Home Assistant API queries to ensure …
markoceri Apr 24, 2026
5c74a30
feat: add lookback_hours parameter to history collection methods for …
markoceri Apr 24, 2026
b485a9b
feat: add endpoint to retrieve energy consumption forecast for specif…
markoceri Apr 24, 2026
e889a07
feat: update datetime handling to ensure UTC consistency across forec…
markoceri Apr 24, 2026
6428576
feat: improve error handling in StatsmodelsForecastProvider for missi…
markoceri Apr 24, 2026
d79336f
feat: implement min_required_history_hours property for energy load f…
markoceri Apr 24, 2026
8cd9785
feat: update default history_hours parameter to 72 for device forecast
markoceri Apr 24, 2026
72775f7
feat: add delete_model method to LoadForecastTrainingServiceInterface…
markoceri Apr 24, 2026
38db142
feat: add endpoint to delete trained ML models by ID
markoceri Apr 24, 2026
8b3bc66
feat: implement α/β blending for load forecast with last real measure…
markoceri Apr 24, 2026
077cbe9
feat: add properties for next and last time intervals in LoadEnergyCo…
markoceri Apr 24, 2026
520fad7
feat: add unit tests for LoadEnergyConsumption extended window proper…
markoceri Apr 24, 2026
6aea6f7
feat: implement NaivePersistence forecast provider for energy load co…
markoceri Apr 24, 2026
7bf5200
feat: add TypicalProfile forecast provider for energy load consumption
markoceri Apr 24, 2026
c00863e
feat: add Skforecast forecast provider for energy load consumption
markoceri Apr 24, 2026
ebb183e
fix: update parameter name for ForecasterRecursive instantiation in S…
markoceri Apr 24, 2026
a938728
fix: update parameter name from 'regressor' to 'estimator' in Forecas…
markoceri Apr 24, 2026
6404cc6
feat: implement Optuna hyperparameter tuning for SkforecastForecastPr…
markoceri Apr 25, 2026
77e4946
feat: add rolling-window backtesting functionality to SkforecastForec…
markoceri Apr 25, 2026
e129182
feat: add documentation for Home Load Forecast Providers
markoceri Apr 25, 2026
c105464
feat: add tuning and backtesting columns to load_consumption_models
markoceri Apr 25, 2026
603e137
feat: add ML model competition and promotion process to home load for…
markoceri Apr 25, 2026
5d71003
fix: database path for alembic configuration
markoceri Apr 27, 2026
978b025
feat: add home loads profile functionality to optimization units
markoceri Apr 28, 2026
81be37b
feat: add home loads profile ID to optimization unit creation and upd…
markoceri Apr 29, 2026
5cbe190
feat: add debug logging for history and forecast provider issues in o…
markoceri May 6, 2026
f3d312a
feat: enhance home load functionality with DecisionalContext integrat…
markoceri May 6, 2026
f66cf9d
Merge remote-tracking branch 'origin/dev' into feat/home-load
markoceri May 6, 2026
89ff777
feat: update DecisionalContext and enhance test cases for TypicalProf…
markoceri May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.1.0-rev3]

### Added

- **Mining Performance Analysis Domain** (`edge_mining/domain/performance/`):
- Value objects: `MiningReward`, `PoolWorkerStats`, `PoolStats`, `PayoutSchedule` in `value_objects.py` (renamed from misspelled `values_objects.py`)
- Entity `MiningSession` for tracking aggregated mining activity (`entities.py`)
Expand Down Expand Up @@ -61,12 +64,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Tests** — 107 new unit tests across tracker adapters, configuration service, REST router, and CLI commands
- **Tests** — 15 new unit tests for `CachedRateLimitedTrackerBase` (cache hit/miss, TTL expiry, backoff progression, stale-while-error, retry-after handling, cache invalidation) plus 429-detection tests for the Ocean and Braiins adapters

- **Home Load — Phase 3: DecisionalContext Integration**
- Extended field resolver (`helpers.py`) with dict key lookup for `home_load.devices.<name>.*` paths and `None` guard for `Optional` intermediate fields
- Pre-computed window properties on `LoadEnergyConsumption`: `next_1h`, `next_2h`, `next_4h`, `last_1h`, `last_4h`, `last_24h`
- Example YAML rules: `home_load_start_rules.yaml` (3 rules), `home_load_stop_rules.yaml` (4 rules)
- Fixed existing rules from `home_load_forecast` → `home_load.total_forecast.next_2h.avg_power`
- 5 new unit tests for dict resolver

- **Home Load — Phase 4: ML Forecast Providers (Statsmodels + XGBoost)**
- ML optional dependencies: `scikit-learn>=1.5.0`, `statsmodels>=0.14.0`, `xgboost>=2.0.0` in `[ml]` extras
- `EnergyLoadForecastProviderAdapter.STATSMODELS` and `.XGBOOST` enum values
- Config dataclasses: `EnergyLoadForecastProviderStatsmodelsConfig`, `EnergyLoadForecastProviderXGBoostConfig`
- Feature engineering utilities (`features.py`): `intervals_to_hourly_series()`, `fill_missing_hours()`, `build_calendar_features()`, `build_lag_features()`, `prepare_supervised_dataset()`
- `LoadConsumptionModel` entity with `model_bytes` (serialized pickle), MAE/RMSE metrics, `is_active` flag
- `LoadConsumptionModelRepository` port + three implementations: InMemory, SQLite, SQLAlchemy
- `load_consumption_models` database table with composite index on `(adapter_type, device_id, is_active)`
- Alembic migration `c3d4e5f6a7b8` for `load_consumption_models` table
- `StatsmodelsForecastProvider` (Holt-Winters exponential smoothing) with factory, lazy import
- `XGBoostForecastProvider` (gradient boosting with calendar + lag features) with factory, lazy import
- `LoadForecastModelTrainingService`: nightly batch training with holdout evaluation + best model promotion
- Pydantic schemas: `EnergyLoadForecastProviderStatsmodelsConfigSchema`, `EnergyLoadForecastProviderXGBoostConfigSchema`
- Scheduler cron job at 04:00 for nightly ML model training

- **Home Load — API Completion**
- `ConfigurationServiceInterface`: 10 new abstract CRUD methods for `EnergyLoadForecastProvider` (5) and `EnergyLoadHistoryProvider` (5)
- `ConfigurationService`: implemented `add_`, `get_`, `list_`, `update_`, `remove_energy_load_forecast_provider`
- Completed 5 forecast provider REST endpoints (previously stubs returning 501/empty):
- `GET /energy-load-forecast-providers` — list all providers
- `POST /energy-load-forecast-providers` — create and persist provider
- `GET /energy-load-forecast-providers/{id}` — get provider by ID
- `PUT /energy-load-forecast-providers/{id}` — update provider with config deserialization
- `DELETE /energy-load-forecast-providers/{id}` — remove provider

### Changed
- `MiningPerformanceTrackerPort` methods are now `async`; the dummy tracker adapter has been adapted accordingly
- `OptimizationService` now awaits `get_current_hashrate` calls to match the async port contract, and consolidates the three tracker calls behind a new private helper `_build_mining_performance_snapshot` that returns a single `MiningPerformanceSnapshot`
- Replaced `DecisionalContext.tracker_current_hashrate: Optional[HashRate]` with `mining_performance: Optional[MiningPerformanceSnapshot]`; `DecisionalContextSchema` and the rule engine `OPERATOR_EXAMPLES[LTE]` example updated accordingly (new field path: `mining_performance.current_hashrate.value`)
- Interactive CLI main menu: "Run all optimization units" shifted from option 8 to 9 to accommodate the new tracker menu at option 8
- Replaced per-module `_utc_now_timestamp()` helpers in `domain/performance/entities.py` and `domain/performance/value_objects.py` with the shared `utc_now_timestamp()` from `domain/common.py`
- `AdapterService`: new factory branches for STATSMODELS and XGBOOST with `model_repo` injection
- `PersistenceSettings`: added `load_consumption_model_repo` field
- `Services` dataclass: added `load_forecast_training_service` field
- `AutomationScheduler`: accepts optional `load_forecast_training_service`, schedules nightly training
- `bootstrap.py`: `LoadConsumptionModelRepository` wired in all three persistence branches (InMemory/SQLite/SQLAlchemy)

### Fixed
- Replaced latent `default_factory=Timestamp(datetime.now())` bugs (which froze a single timestamp at class-definition time) with the proper callable `utc_now_timestamp`, producing a fresh timestamp per instance
Expand Down
2 changes: 1 addition & 1 deletion alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ path_separator = os
# database URL. This is consumed by the user-maintained env.py script only.
# other means of configuring database URLs may be customized within the env.py
# file.
sqlalchemy.url = sqlite:///./edgemining.db
sqlalchemy.url = sqlite:///data/db/edgemining.db


[post_write_hooks]
Expand Down
32 changes: 22 additions & 10 deletions alembic/versions/4e55fe6113c7_initial_schema_with_all_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ def upgrade() -> None:
)
op.create_index(op.f("ix_forecast_providers_id"), "forecast_providers", ["id"], unique=False)
op.create_table(
"home_forecast_providers",
"energy_load_forecast_providers",
sa.Column("id", sa.String(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("adapter_type", sa.String(), nullable=False),
sa.Column(
"config", edge_mining.adapters.domain.home_load.tables.HomeForecastProviderConfigType(), nullable=True
"config", edge_mining.adapters.domain.home_load.tables.EnergyLoadForecastProviderConfigType(), nullable=True
),
sa.Column("external_service_id", sa.String(), nullable=True),
sa.ForeignKeyConstraint(
Expand All @@ -112,7 +112,9 @@ def upgrade() -> None:
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_home_forecast_providers_id"), "home_forecast_providers", ["id"], unique=False)
op.create_index(
op.f("ix_energy_load_forecast_providers_id"), "energy_load_forecast_providers", ["id"], unique=False
)
op.create_table(
"miner_controllers",
sa.Column("id", sa.String(), nullable=False),
Expand Down Expand Up @@ -206,7 +208,6 @@ def upgrade() -> None:
"target_miner_ids", edge_mining.adapters.domain.optimization_unit.tables.EntityIdListType(), nullable=False
),
sa.Column("energy_source_id", sa.String(), nullable=True),
sa.Column("home_forecast_provider_id", sa.String(), nullable=True),
sa.Column("performance_tracker_id", sa.String(), nullable=True),
sa.Column(
"notifier_ids", edge_mining.adapters.domain.optimization_unit.tables.EntityIdListType(), nullable=False
Expand All @@ -215,23 +216,34 @@ def upgrade() -> None:
["energy_source_id"],
["energy_sources.id"],
),
sa.ForeignKeyConstraint(
["home_forecast_provider_id"],
["home_forecast_providers.id"],
),
sa.ForeignKeyConstraint(
["performance_tracker_id"],
["mining_performance_trackers.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_optimization_units_id"), "optimization_units", ["id"], unique=False)
op.create_table(
"home_load_power_points",
sa.Column("device_id", sa.String(), nullable=False),
sa.Column("timestamp", sa.DateTime(timezone=True), nullable=False),
sa.Column("power", sa.Float(), nullable=False),
sa.PrimaryKeyConstraint("device_id", "timestamp"),
)
op.create_index(
"ix_home_load_power_points_device_ts",
"home_load_power_points",
["device_id", "timestamp"],
unique=False,
)
# ### end Alembic commands ###


def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index("ix_home_load_power_points_device_ts", table_name="home_load_power_points")
op.drop_table("home_load_power_points")
op.drop_index(op.f("ix_optimization_units_id"), table_name="optimization_units")
op.drop_table("optimization_units")
op.drop_index(op.f("ix_miners_id"), table_name="miners")
Expand All @@ -244,8 +256,8 @@ def downgrade() -> None:
op.drop_table("mining_performance_trackers")
op.drop_index(op.f("ix_miner_controllers_id"), table_name="miner_controllers")
op.drop_table("miner_controllers")
op.drop_index(op.f("ix_home_forecast_providers_id"), table_name="home_forecast_providers")
op.drop_table("home_forecast_providers")
op.drop_index(op.f("ix_energy_load_forecast_providers_id"), table_name="energy_load_forecast_providers")
op.drop_table("energy_load_forecast_providers")
op.drop_index(op.f("ix_forecast_providers_id"), table_name="forecast_providers")
op.drop_table("forecast_providers")
op.drop_index(op.f("ix_energy_monitors_id"), table_name="energy_monitors")
Expand Down
56 changes: 56 additions & 0 deletions alembic/versions/b2c3d4e5f6a7_add_energy_load_history_providers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Add energy_load_history_providers table

Revision ID: b2c3d4e5f6a7
Revises: a1b2c3d4e5f6
Create Date: 2026-04-22 10:00:00.000000

"""

from typing import Sequence, Union

import sqlalchemy as sa

import edge_mining.adapters.domain.home_load.tables
from alembic import op

# revision identifiers, used by Alembic.
revision: str = "b2c3d4e5f6a7"
down_revision: Union[str, Sequence[str], None] = "a1b2c3d4e5f6"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
"""Add energy_load_history_providers table."""
op.create_table(
"energy_load_history_providers",
sa.Column("id", sa.String(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("adapter_type", sa.String(), nullable=False),
sa.Column(
"config",
edge_mining.adapters.domain.home_load.tables.EnergyLoadHistoryProviderConfigType(),
nullable=True,
),
sa.Column("external_service_id", sa.String(), nullable=True),
sa.ForeignKeyConstraint(
["external_service_id"],
["external_services.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_energy_load_history_providers_id"),
"energy_load_history_providers",
["id"],
unique=False,
)


def downgrade() -> None:
"""Remove energy_load_history_providers table."""
op.drop_index(
op.f("ix_energy_load_history_providers_id"),
table_name="energy_load_history_providers",
)
op.drop_table("energy_load_history_providers")
47 changes: 47 additions & 0 deletions alembic/versions/c3d4e5f6a7b8_add_load_consumption_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Add load_consumption_models table

Revision ID: c3d4e5f6a7b8
Revises: b2c3d4e5f6a7
Create Date: 2026-04-22 14:00:00.000000

"""

from typing import Sequence, Union

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "c3d4e5f6a7b8"
down_revision: Union[str, None] = "b2c3d4e5f6a7"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.create_table(
"load_consumption_models",
sa.Column("id", sa.String(), nullable=False),
sa.Column("device_id", sa.String(), nullable=True),
sa.Column("adapter_type", sa.String(), nullable=False),
sa.Column("trained_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("mae", sa.Float(), nullable=True),
sa.Column("rmse", sa.Float(), nullable=True),
sa.Column("samples_used", sa.Integer(), nullable=False, server_default="0"),
sa.Column("is_active", sa.Boolean(), nullable=False, server_default="0"),
sa.Column("model_bytes", sa.LargeBinary(), nullable=True),
sa.PrimaryKeyConstraint("id"),
)
op.create_index("ix_load_consumption_models_id", "load_consumption_models", ["id"])
op.create_index(
"ix_load_consumption_models_active",
"load_consumption_models",
["adapter_type", "device_id", "is_active"],
)


def downgrade() -> None:
op.drop_index("ix_load_consumption_models_active", table_name="load_consumption_models")
op.drop_index("ix_load_consumption_models_id", table_name="load_consumption_models")
op.drop_table("load_consumption_models")
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Add tuning and backtesting columns to load_consumption_models

Revision ID: d4e5f6a7b8c9
Revises: c3d4e5f6a7b8
Create Date: 2026-04-25 10:00:00.000000

"""

from typing import Sequence, Union

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "d4e5f6a7b8c9"
down_revision: Union[str, None] = "c3d4e5f6a7b8"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
with op.batch_alter_table("load_consumption_models") as batch_op:
batch_op.add_column(sa.Column("tuning_params", sa.Text(), nullable=True))
batch_op.add_column(sa.Column("backtest_mae", sa.Float(), nullable=True))
batch_op.add_column(sa.Column("backtest_rmse", sa.Float(), nullable=True))
batch_op.add_column(sa.Column("backtest_folds", sa.Integer(), nullable=False, server_default="0"))


def downgrade() -> None:
with op.batch_alter_table("load_consumption_models") as batch_op:
batch_op.drop_column("backtest_folds")
batch_op.drop_column("backtest_rmse")
batch_op.drop_column("backtest_mae")
batch_op.drop_column("tuning_params")
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Add home_loads_profile to optimization_units

Revision ID: e5f6a7b8c9d0
Revises: d4e5f6a7b8c9
Create Date: 2026-04-29 12:00:00.000000

"""

from typing import Sequence, Union

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "e5f6a7b8c9d0"
down_revision: Union[str, None] = "d4e5f6a7b8c9"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
with op.batch_alter_table("optimization_units") as batch_op:
batch_op.add_column(sa.Column("home_loads_profile", sa.String(), nullable=True))


def downgrade() -> None:
with op.batch_alter_table("optimization_units") as batch_op:
batch_op.drop_column("home_loads_profile")
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ stop_rules:
description: Stop mining during high home energy demand periods
conditions:
all_of:
- field: home_load_forecast
- field: home_load.total_forecast.next_2h.avg_power
operator: gt
value: 2800
- field: timestamp.hour
Expand All @@ -136,6 +136,6 @@ stop_rules:
enabled: true
metadata:
author: Edge Mining User
version: 5
version: 6
created: '2025-08-04'
last_modified: '2026-01-18'
last_modified: '2026-04-22'
4 changes: 2 additions & 2 deletions data/examples/rules/start/advanced_start_rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ rules:
- field: "energy_state.battery.state_of_charge"
operator: "gt"
value: 60
- field: "home_load_forecast"
- field: "home_load.total_forecast.next_2h.avg_power"
operator: "lt"
value: 2000 # Low expected home consumption
value: 2000 # Low expected home consumption (next 2h average)
- any_of:
- field: "energy_state.production"
operator: "gt"
Expand Down
Loading