API Reference#
emhass.command_line module#
- class emhass.command_line.OptimizationCache#
Bases:
objectIn-memory cache for Optimization objects to enable warm-starting.
Warm-starting reuses the previous solution as a starting point for the solver, which can significantly speed up repeated MPC optimizations where consecutive problems are similar.
The cache is invalidated when configuration changes that affect the optimization structure (number of variables, constraints, etc.).
Thread-safe: Uses a lock to prevent race conditions when multiple optimizations run concurrently in async code.
- classmethod clear(logger: Logger | None = None) None#
Clear the cache (e.g., for testing or explicit invalidation). Thread-safe.
- classmethod get(optim_conf: dict, plant_conf: dict, costfun: str, retrieve_hass_conf: dict, logger: Logger, num_timesteps: int | None = None) Optimization | None#
Get cached Optimization object if configuration matches.
Returns None if cache is empty or configuration has changed. Thread-safe via internal locking.
- classmethod get_stats() dict#
Get cache statistics for debugging. Thread-safe.
- classmethod put(opt: Optimization, optim_conf: dict, plant_conf: dict, costfun: str, retrieve_hass_conf: dict, logger: Logger, num_timesteps: int | None = None) None#
Store Optimization object in cache. Thread-safe via internal locking.
- class emhass.command_line.OptimizationCacheKey(number_of_deferrable_loads: int, set_use_battery: bool, set_use_pv: bool, treat_deferrable_load_as_semi_cont: tuple, set_deferrable_load_single_constant: tuple, set_deferrable_startup_penalty: tuple, deferrable_load_max_cost: tuple, set_deferrable_max_startups: tuple, set_deferrable_load_as_timeseries: tuple, nominal_power_of_deferrable_loads: tuple, def_load_config_structure: tuple, deferrable_load_groups: tuple, shared_thermal_tanks: tuple, is_electric_load: tuple, inverter_is_hybrid: bool, compute_curtailment: bool, optimization_time_step_s: float | None, delta_forecast_daily_s: float | None, num_timesteps: int | None, costfun: str, plant_conf_hash: str, optim_conf_structural_hash: str)#
Bases:
objectFrozen dataclass representing configuration fields that affect optimization structure.
Changes to any of these fields require rebuilding the optimization problem. Using a frozen dataclass makes the cache key explicit, hashable, and easy to extend.
- compute_curtailment: bool#
- costfun: str#
- def_load_config_structure: tuple#
- deferrable_load_groups: tuple#
- deferrable_load_max_cost: tuple#
- delta_forecast_daily_s: float | None#
- inverter_is_hybrid: bool#
- is_electric_load: tuple#
- nominal_power_of_deferrable_loads: tuple#
- num_timesteps: int | None#
- number_of_deferrable_loads: int#
- optim_conf_structural_hash: str#
- optimization_time_step_s: float | None#
- plant_conf_hash: str#
- set_deferrable_load_as_timeseries: tuple#
- set_deferrable_load_single_constant: tuple#
- set_deferrable_max_startups: tuple#
- set_deferrable_startup_penalty: tuple#
- set_use_battery: bool#
- set_use_pv: bool#
- treat_deferrable_load_as_semi_cont: tuple#
- class emhass.command_line.PublishContext(input_data_dict: dict, params: dict, idx: int, common_kwargs: dict, logger: Logger)#
Bases:
objectContext object for data publishing helpers.
- Attributes:
- input_data_dict (dict): Dictionary containing input data with keys βrhβ (RetrieveHass),
βoptβ (Optimization - may be None for publish-data), and βfcstβ (Forecast) objects.
params (dict): Parameters dictionary for publishing configuration. idx (int): Index identifier for the current publishing operation. common_kwargs (dict): Common keyword arguments shared across publishing helpers. logger (logging.Logger): Logger instance for recording publishing operations.
- common_kwargs: dict#
- idx: int#
- input_data_dict: dict#
- logger: Logger#
- property opt: Optimization#
- property optim_conf: dict#
Access optim_conf directly from input_data_dict (works even when opt is None).
- params: dict#
- property plant_conf: dict#
Access plant_conf directly from input_data_dict (works even when opt is None).
- property rh: RetrieveHass#
- class emhass.command_line.SetupContext(retrieve_hass_conf: dict, optim_conf: dict, plant_conf: dict, emhass_conf: dict, params: dict, logger: Logger, get_data_from_file: bool, rh: RetrieveHass, fcst: Forecast | None = None)#
Bases:
objectA dataclass that serves as a context container for optimization preparation helpers. This context object encapsulates all necessary configuration and utility objects required for setting up and preparing optimization tasks.
- Attributes:
retrieve_hass_conf (dict): Configuration dictionary for Home Assistant data retrieval. optim_conf (dict): Configuration dictionary for optimization parameters. plant_conf (dict): Configuration dictionary for plant/system parameters. emhass_conf (dict): Configuration dictionary for EMHASS settings. params (dict): Additional parameters dictionary. logger (logging.Logger): Logger instance for logging messages. get_data_from_file (bool): Flag indicating whether to retrieve data from file instead of live source. rh (RetrieveHass): RetrieveHass instance for retrieving Home Assistant data. fcst (Forecast | None): Optional Forecast object for weather or energy forecasting. Defaults to None.
- emhass_conf: dict#
- get_data_from_file: bool#
- logger: Logger#
- optim_conf: dict#
- params: dict#
- plant_conf: dict#
- retrieve_hass_conf: dict#
- rh: RetrieveHass#
- async emhass.command_line.adjust_pv_forecast(logger: Logger, fcst: Forecast, p_pv_forecast: Series, get_data_from_file: bool, retrieve_hass_conf: dict, optim_conf: dict, rh: RetrieveHass, emhass_conf: dict, test_df_literal: DataFrame) Series#
Adjust the photovoltaic (PV) forecast using historical data and a regression model.
This method retrieves historical data, prepares it for model fitting, trains a regression model, and adjusts the provided PV forecast based on the trained model.
- Parameters:
logger (logging.Logger) β Logger object for logging information and errors.
fcst (Forecast) β Forecast object used for PV forecast adjustment.
p_pv_forecast (pd.Series) β The initial PV forecast to be adjusted.
get_data_from_file (bool) β Whether to retrieve data from a file instead of Home Assistant.
retrieve_hass_conf (dict) β Configuration dictionary for retrieving data from Home Assistant.
optim_conf (dict) β Configuration dictionary for optimization settings.
rh (RetrieveHass) β RetrieveHass object for interacting with Home Assistant.
emhass_conf (dict) β Configuration dictionary for emhass paths and settings.
test_df_literal (pd.DataFrame) β DataFrame containing test data for debugging purposes.
- Returns:
The adjusted PV forecast as a pandas Series.
- Return type:
pd.Series
- async emhass.command_line.continual_publish(input_data_dict: dict, entity_path: Path, logger: Logger)#
If continual_publish is true and a entity file saved in /data_path/entities, continually publish sensor on freq rate, updating entity current state value based on timestamp
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
entity_path (Path) β Path for entities folder in data_path
logger (logging.Logger) β The passed logger object
- async emhass.command_line.dayahead_forecast_optim(input_data_dict: dict, logger: Logger, save_data_to_file: bool | None = False, debug: bool | None = False) DataFrame#
Perform a call to the day-ahead optimization routine.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging object) β The passed logger object
save_data_to_file (bool, optional) β Save optimization results to CSV file
debug (bool, optional) β A debug option useful for unittests
- Returns:
The output data of the optimization
- Return type:
pd.DataFrame
- async emhass.command_line.export_influxdb_to_csv(input_data_dict: dict | None, logger: Logger, emhass_conf: dict | None = None, params: str | None = None, runtimeparams: str | None = None) bool#
Export data from InfluxDB to CSV file.
This function can be called in two ways: 1. With input_data_dict (from web_server via set_input_data_dict) 2. Without input_data_dict (direct call from command line or web_server before set_input_data_dict)
- Parameters:
input_data_dict (dict | None) β Dictionary containing configuration and parameters (optional)
logger (logging.Logger) β Logger object
emhass_conf (dict | None) β Dictionary containing EMHASS configuration paths (used when input_data_dict is None)
params (str | None) β JSON string of params (used when input_data_dict is None)
runtimeparams (str | None) β JSON string of runtime parameters (used when input_data_dict is None)
- Returns:
Success status
- Return type:
bool
- async emhass.command_line.forecast_model_fit(input_data_dict: dict, logger: Logger, debug: bool | None = False) tuple[DataFrame, DataFrame, MLForecaster]#
Perform a forecast model fit from training data retrieved from Home Assistant.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging.Logger) β The passed logger object
debug (Optional[bool], optional) β True to debug, useful for unit testing, defaults to False
- Returns:
The DataFrame containing the forecast data results without and with backtest and the mlforecaster object
- Return type:
Tuple[pd.DataFrame, pd.DataFrame, mlforecaster]
- async emhass.command_line.forecast_model_predict(input_data_dict: dict, logger: Logger, use_last_window: bool | None = True, debug: bool | None = False, mlf: MLForecaster | None = None) DataFrame#
Perform a forecast model predict using a previously trained skforecast model.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging.Logger) β The passed logger object
use_last_window (Optional[bool], optional) β True if the βlast_windowβ option should be used for the custom machine learning forecast model. The βlast_window=Trueβ means that the data that will be used to generate the new forecast will be freshly retrieved from Home Assistant. This data is needed because the forecast model is an auto-regressive model with lags. If βFalseβ then the data using during the model train is used. Defaults to True
debug (Optional[bool], optional) β True to debug, useful for unit testing, defaults to False
mlf (Optional[mlforecaster], optional) β The βmlforecasterβ object previously trained. This is mainly used for debug and unit testing. In production the actual model will be read from a saved pickle file. Defaults to None
- Returns:
The DataFrame containing the forecast prediction data
- Return type:
pd.DataFrame
- async emhass.command_line.forecast_model_tune(input_data_dict: dict, logger: Logger, debug: bool | None = False, mlf: MLForecaster | None = None) tuple[DataFrame, MLForecaster]#
Tune a forecast model hyperparameters using bayesian optimization.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging.Logger) β The passed logger object
debug (Optional[bool], optional) β True to debug, useful for unit testing, defaults to False
mlf (Optional[mlforecaster], optional) β The βmlforecasterβ object previously trained. This is mainly used for debug and unit testing. In production the actual model will be read from a saved pickle file. Defaults to None
- Returns:
The DataFrame containing the forecast data results using the optimized model
- Return type:
pd.DataFrame
- emhass.command_line.is_model_outdated(model_path: Path, max_age_hours: int, logger: Logger) bool#
Check if the saved model file is outdated based on its modification time.
- Parameters:
model_path (pathlib.Path) β Path to the saved model file.
max_age_hours (int) β Maximum age in hours before model is considered outdated.
logger (logging.Logger) β Logger object for logging information.
- Returns:
True if model is outdated or doesnβt exist, False otherwise.
- Return type:
bool
- async emhass.command_line.main()#
Define the main command line entry function.
This function may take several arguments as inputs. You can type emhass βhelp to see the list of options:
action: Set the desired action, options are: perfect-optim, dayahead-optim, naive-mpc-optim, publish-data, forecast-model-fit, forecast-model-predict, forecast-model-tune
config: Define path to the config.yaml file
costfun: Define the type of cost function, options are: profit, cost, self-consumption
log2file: Define if we should log to a file or not
params: Configuration parameters passed from data/options.json if using the add-on
runtimeparams: Pass runtime optimization parameters as dictionnary
debug: Use True for testing purposes
- emhass.command_line.main_sync()#
Sync wrapper for async main function - used as CLI entry point.
- async emhass.command_line.naive_mpc_optim(input_data_dict: dict, logger: Logger, save_data_to_file: bool | None = False, debug: bool | None = False) DataFrame#
Perform a call to the naive Model Predictive Controller optimization routine.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging object) β The passed logger object
save_data_to_file (bool, optional) β Save optimization results to CSV file
debug (bool, optional) β A debug option useful for unittests
- Returns:
The output data of the optimization
- Return type:
pd.DataFrame
- async emhass.command_line.perfect_forecast_optim(input_data_dict: dict, logger: Logger, save_data_to_file: bool | None = True, debug: bool | None = False) DataFrame#
Perform a call to the perfect forecast optimization routine.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging object) β The passed logger object
save_data_to_file (bool, optional) β Save optimization results to CSV file
debug (bool, optional) β A debug option useful for unittests
- Returns:
The output data of the optimization
- Return type:
pd.DataFrame
- emhass.command_line.prepare_forecast_and_weather_data(input_data_dict: dict, logger: Logger, warn_on_resolution: bool = False) DataFrame | bool#
Prepare forecast data with load costs, production prices, outdoor temperature, and GHI.
This helper function eliminates duplication between dayahead_forecast_optim and naive_mpc_optim.
- Parameters:
input_data_dict (dict) β Dictionary with forecast and input data
logger (logging.Logger) β Logger object
warn_on_resolution (bool) β Whether to warn about GHI resolution mismatch
- Returns:
Prepared DataFrame or False on error
- Return type:
pd.DataFrame | bool
- async emhass.command_line.publish_data(input_data_dict: dict, logger: Logger, save_data_to_file: bool | None = False, opt_res_latest: DataFrame | None = None, entity_save: bool | None = False, dont_post: bool | None = False) DataFrame#
Publish the data obtained from the optimization results.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging object) β The passed logger object
save_data_to_file (bool, optional) β If True we will read data from optimization results in dayahead CSV file
entity_save (bool, optional) β Save built entities to data_path/entities
dont_post (bool, optional) β Do not post to Home Assistant. Works with entity_save
- Returns:
The output data of the optimization readed from a CSV file in the data folder
- Return type:
pd.DataFrame
- async emhass.command_line.publish_json(entity: dict, input_data_dict: dict, entity_path: Path, logger: Logger, reference: str | None = '')#
Extract saved entity data from .json (in data_path/entities), build entity, post results to post_data
- Parameters:
entity (dict) β json file containing entity data
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
entity_path (Path) β Path for entities folder in data_path
logger (logging.Logger) β The passed logger object
reference (str, optional) β String for identifying who ran the function
- async emhass.command_line.regressor_model_fit(input_data_dict: dict, logger: Logger, debug: bool | None = False) MLRegressor#
Perform a forecast model fit from training data retrieved from Home Assistant.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging.Logger) β The passed logger object
debug (Optional[bool], optional) β True to debug, useful for unit testing, defaults to False
- async emhass.command_line.regressor_model_predict(input_data_dict: dict, logger: Logger, debug: bool | None = False, mlr: MLRegressor | None = None) ndarray#
Perform a prediction from csv file.
- Parameters:
input_data_dict (dict) β A dictionnary with multiple data used by the action functions
logger (logging.Logger) β The passed logger object
debug (Optional[bool], optional) β True to debug, useful for unit testing, defaults to False
- async emhass.command_line.retrieve_home_assistant_data(set_type: str, get_data_from_file: bool, retrieve_hass_conf: dict, optim_conf: dict, rh: RetrieveHass, emhass_conf: dict, test_df_literal: str, logger: Logger | None = None) tuple[bool, DataFrame | None, list | None]#
Retrieve data from Home Assistant or file and prepare it for optimization.
- async emhass.command_line.set_input_data_dict(emhass_conf: dict, costfun: str, params: str, runtimeparams: str, set_type: str, logger: Logger, get_data_from_file: bool | None = False) dict#
Set up some of the data needed for the different actions.
- Parameters:
emhass_conf (dict) β Dictionary containing the needed emhass paths
costfun (str) β The type of cost function to use for optimization problem
params (str) β Configuration parameters passed from data/options.json
runtimeparams (str) β Runtime optimization parameters passed as a dictionary
set_type (str) β Set the type of setup based on following type of optimization
logger (logging object) β The passed logger object
get_data_from_file (bool, optional) β Use data from saved CSV file (useful for debug)
- Returns:
A dictionnary with multiple data used by the action functions
- Return type:
dict
- async emhass.command_line.weather_forecast_cache(emhass_conf: dict, params: str, runtimeparams: str, logger: Logger) bool#
Perform a call to get forecast function, intend to save results to cache.
- Parameters:
emhass_conf (dict) β Dictionary containing the needed emhass paths
params (str) β Configuration parameters passed from data/options.json
runtimeparams (str) β Runtime optimization parameters passed as a dictionary
logger (logging object) β The passed logger object
- Returns:
A bool for function completion
- Return type:
bool
emhass.forecast module#
- class emhass.forecast.Forecast(retrieve_hass_conf: dict, optim_conf: dict, plant_conf: dict, params: str, emhass_conf: dict, logger: Logger, opt_time_delta: int | None = 24, get_data_from_file: bool | None = False)#
Bases:
objectGenerate weather, load and costs forecasts needed as inputs to the optimization.
In EMHASS we have basically 4 forecasts to deal with:
PV power production forecast (internally based on the weather forecast and the characteristics of your PV plant). This is given in Watts.
Load power forecast: how much power your house will demand on the next 24h. This is given in Watts.
PV production selling price forecast: at what price are you selling your excess PV production on the next 24h. This is given in EUR/kWh.
Load cost forecast: the price of the energy from the grid on the next 24h. This is given in EUR/kWh.
There are methods that are generalized to the 4 forecast needed. For all there forecasts it is possible to pass the data either as a passed list of values or by reading from a CSV file. With these methods it is then possible to use data from external forecast providers.
Then there are the methods that are specific to each type of forecast and that proposed forecast treated and generated internally by this EMHASS forecast class. For the weather forecast a first method (open-meteo) uses a open-meteos API proposing detailed forecasts based on Lat/Lon locations. This method seems stable but as with any scrape method it will fail if any changes are made to the webpage API. Another method (solcast) is using the SolCast PV production forecast service. A final method (solar.forecast) is using another external service: Solar.Forecast, for which just the nominal PV peak installed power should be provided. Search the forecast section on the documentation for examples on how to implement these different methods.
The get_power_from_weather method is proposed here to convert from irradiance data to electrical power. The PVLib module is used to model the PV plant.
The specific methods for the load forecast are a first method (naive) that uses a naive approach, also called persistance. It simply assumes that the forecast for a future period will be equal to the observed values in a past period. The past period is controlled using parameter delta_forecast. A second method (mlforecaster) uses an internal custom forecasting model using machine learning. There is a section in the documentation explaining how to use this method.
Note
This custom machine learning model is introduced from v0.4.0. EMHASS proposed this new mlforecaster class with fit, predict and tune methods. Only the predict method is used here to generate new forecasts, but it is necessary to previously fit a forecaster model and it is a good idea to optimize the model hyperparameters using the tune method. See the dedicated section in the documentation for more help.
For the PV production selling price and Load cost forecasts the privileged method is a direct read from a user provided list of values. The list should be passed as a runtime parameter during the curl to the EMHASS API.
I reading from a CSV file, it should contain no header and the timestamped data should have the following format: 2021-04-29 00:00:00+00:00,287.07 2021-04-29 00:30:00+00:00,274.27 2021-04-29 01:00:00+00:00,243.38 β¦
The data columns in these files will correspond to the data in the units expected for each forecasting method.
- adjust_pv_forecast_data_prep(data: DataFrame) DataFrame#
Prepare data for adjusting the photovoltaic (PV) forecast.
This method aligns the actual PV production data with the forecasted data, adds additional features for analysis, and separates the predictors (X) from the target variable (y).
- Parameters:
data (pd.DataFrame) β A DataFrame containing the actual PV production data and the forecasted PV production data.
- Returns:
DataFrame with data for adjusted PV model train.
- async adjust_pv_forecast_fit(n_splits: int = 5, regression_model: str = 'LassoRegression', debug: bool | None = False) DataFrame#
Fit a regression model to adjust the photovoltaic (PV) forecast.
This method uses historical actual and forecasted PV production data, along with additional solar and date features, to train a regression model. The model is optimized using a grid search with time-series cross-validation.
- Parameters:
n_splits (int, optional) β The number of splits for time-series cross-validation, defaults to 5.
regression_model (str, optional) β The type of regression model to use. See REGRESSION_METHODS in machine_learning_regressor.py for the authoritative list of supported models. Currently: βLinearRegressionβ, βRidgeRegressionβ, βLassoRegressionβ, βElasticNetβ, βKNeighborsRegressorβ, βDecisionTreeRegressorβ, βSVRβ, βRandomForestRegressorβ, βExtraTreesRegressorβ, βGradientBoostingRegressorβ, βAdaBoostRegressorβ, βMLPRegressorβ. Defaults to βLassoRegressionβ.
debug (bool, optional) β If True, the model is not saved to disk, useful for debugging, defaults to False.
- Returns:
A DataFrame containing the adjusted PV forecast.
- Return type:
pd.DataFrame
- adjust_pv_forecast_predict(forecasted_pv: DataFrame | None = None) DataFrame#
Predict the adjusted photovoltaic (PV) forecast.
This method uses the trained regression model to predict the adjusted PV forecast based on either the validation data stored in self or a new forecasted PV data passed as input. It applies additional features such as date and solar angles to the forecasted PV production data before making predictions. The solar elevation is used to avoid negative values and to fix values at the beginning and end of the day.
- Parameters:
forecasted_pv (pd.DataFrame, optional) β Optional. A DataFrame containing the forecasted PV production data. It must have a DateTime index and a column named βforecastβ. If not provided, the method will use self.p_pv_forecast_validation.
- Returns:
A DataFrame containing the adjusted PV forecast with additional features.
- Return type:
pd.DataFrame
- cloud_cover_to_irradiance(cloud_cover: Series, offset: int | None = 35) DataFrame#
Estimates irradiance from cloud cover in the following steps.
Determine clear sky GHI using Ineichen model and climatological turbidity.
Estimate cloudy sky GHI using a function of cloud_cover
Estimate cloudy sky DNI using the DISC model.
Calculate DHI from DNI and GHI.
(This function was copied and modified from PVLib)
- Parameters:
cloud_cover (pd.Series) β Cloud cover in %.
offset (Optional[int], optional) β Determines the minimum GHI., defaults to 35
- Returns:
Estimated GHI, DNI, and DHI.
- Return type:
pd.DataFrame
- static compute_solar_angles(df: DataFrame, latitude: float, longitude: float) DataFrame#
Compute solar angles (elevation, azimuth) based on timestamps and location.
- Parameters:
df β DataFrame with a DateTime index.
latitude β Latitude of the PV system.
longitude β Longitude of the PV system.
- Returns:
DataFrame with added solar elevation and azimuth.
- async get_cached_forecast_data(w_forecast_cache_path) DataFrame | None#
Get cached weather forecast data from file.
- Parameters:
w_forecast_cache_path β the path to file.
- Returns:
The DataFrame containing the forecasted data, or
Nonewhen the cache is corrupt/missing or was intentionally deleted (e.g. stale Open-Meteo cache). Callers must handle theNonecase.- Return type:
pd.DataFrame | None
- async get_cached_open_meteo_forecast_json(max_age: int | None = 30, forecast_days: int = 3) dict#
Get weather forecast json from Open-Meteo and cache it for re-use. The response json is cached in the local file system and returned on subsequent calls until it is older than max_age, at which point attempts will be made to replace it with a new version. The cached version will not be overwritten until a new version has been successfully fetched from Open-Meteo. In the event of connectivity issues, the cached version will continue to be returned until such time as a new version can be successfully fetched from Open-Meteo. If you want to force reload, pass max_age value of zero.
- Parameters:
max_age (int, optional) β The maximum age of the cached json file, in minutes, before it is discarded and a new version fetched from Open-Meteo. Defaults to 30 minutes.
forecast_days (int, optional) β The number of days of forecast data required from Open-Meteo. One additional day is always fetched from Open-Meteo so there is an extra data in the cache. Defaults to 2 days (3 days fetched) to match the prior default.
- Returns:
The json containing the Open-Meteo forecast data
- Return type:
dict
- get_forecast_days_csv(timedelta_days: int | None = 1) date_range#
Get the date range vector of forecast dates that will be used when loading a CSV file.
- Returns:
The forecast dates vector
- Return type:
pd.date_range
- get_forecast_out_from_csv_or_list(df_final: DataFrame, forecast_dates_csv: date_range, csv_path: str, data_list: list | None = None, list_and_perfect: bool | None = False) DataFrame#
Get the forecast data as a DataFrame from a CSV file.
The data contained in the CSV file should be a 24h forecast with the same frequency as the main βoptimization_time_stepβ parameter in the configuration file. The timestamp will not be used and a new DateTimeIndex is generated to fit the timestamp index of the input data in βdf_finalβ.
- Parameters:
df_final (pd.DataFrame) β The DataFrame containing the input data.
forecast_dates_csv (pd.date_range) β The forecast dates vector
csv_path (str) β The path to the CSV file
- Returns:
The data from the CSV file
- Return type:
pd.DataFrame
- get_load_cost_forecast(df_final: DataFrame, method: str | None = 'hp_hc_periods', csv_path: str | None = 'data_load_cost_forecast.csv', list_and_perfect: bool | None = False) DataFrame#
Get the unit cost for the load consumption based on multiple tariff periods. This is the cost of the energy from the utility in a vector sampled at the fixed freq value.
- Parameters:
df_final (pd.DataFrame) β The DataFrame containing the input data.
method (str, optional) β The method to be used to generate load cost forecast, the options are βhp_hc_periodsβ for peak and non-peak hours contractsand βcsvβ to load a CSV file, defaults to βhp_hc_periodsβ
csv_path (str, optional) β The path to the CSV file used when method = βcsvβ, defaults to βdata_load_cost_forecast.csvβ
- Returns:
The input DataFrame with one additionnal column appended containing the load cost for each time observation.
- Return type:
pd.DataFrame
- async get_load_forecast(days_min_load_forecast: int | None = 3, method: str | None = 'typical', csv_path: str | None = 'data_load_forecast.csv', set_mix_forecast: bool | None = False, df_now: DataFrame | None = Empty DataFrame Columns: [] Index: [], use_last_window: bool | None = True, mlf: MLForecaster | None = None, debug: bool | None = False) Series#
Get and generate the load forecast data.
- Parameters:
days_min_load_forecast (int, optional) β The number of last days to retrieve that will be used to generate a naive forecast, defaults to 3
method (str, optional) β The method to be used to generate load forecast, the options are βtypicalβ for a typical household load consumption curve, are βnaiveβ for a persistence model, βmlforecasterβ for using a custom previously fitted machine learning model, βcsvβ to read the forecast from a CSV file and βlistβ to use data directly passed at runtime as a list of values. Defaults to βtypicalβ.
csv_path (str, optional) β The path to the CSV file used when method = βcsvβ, defaults to β/data/data_load_forecast.csvβ
set_mix_forecast (Bool, optional) β Use a mixed forecast strategy to integrate now/current values.
df_now (pd.DataFrame, optional) β The DataFrame containing the now/current data.
use_last_window (Bool, optional) β True if the βlast_windowβ option should be used for the custom machine learning forecast model. The βlast_window=Trueβ means that the data that will be used to generate the new forecast will be freshly retrieved from Home Assistant. This data is needed because the forecast model is an auto-regressive model with lags. If βFalseβ then the data using during the model train is used.
mlf (mlforecaster, optional) β The βmlforecasterβ object previously trained. This is mainly used for debug and unit testing. In production the actual model will be read from a saved pickle file.
debug (Bool, optional) β The DataFrame containing the now/current data.
- Returns:
The DataFrame containing the electrical load power in Watts
- Return type:
pd.DataFrame
- static get_mix_forecast(df_now: DataFrame, df_forecast: DataFrame, alpha: float, beta: float, col: str, ignore_pv_feedback: bool = False) DataFrame#
A simple correction method for forecasted data using the current real values of a variable.
- Parameters:
df_now (pd.DataFrame) β The DataFrame containing the current/real values
df_forecast (pd.DataFrame) β The DataFrame containing the forecast data
alpha (float) β A weight for the forecast data side
beta (float) β A weight for the current/real values sied
col (str) β The column variable name
ignore_pv_feedback (bool) β If True, bypass mixing and return original forecast (used during curtailment)
- Returns:
The output DataFrame with the corrected values
- Return type:
pd.DataFrame
- get_power_from_weather(df_weather: DataFrame, set_mix_forecast: bool | None = False, df_now: DataFrame | None = Empty DataFrame Columns: [] Index: []) Series#
Convert weather forecast data into electrical power.
- Parameters:
df_weather (pd.DataFrame) β The DataFrame containing the weather forecasted data. This DF should be generated by the βget_weather_forecastβ method or at least contain the same columns names filled with proper data.
set_mix_forecast (Bool, optional) β Use a mixed forecast strategy to integrate now/current values.
df_now (pd.DataFrame) β The DataFrame containing the now/current data.
- Returns:
The DataFrame containing the electrical power in Watts
- Return type:
pd.DataFrame
- get_prod_price_forecast(df_final: DataFrame, method: str | None = 'constant', csv_path: str | None = 'data_prod_price_forecast.csv', list_and_perfect: bool | None = False) DataFrame#
Get the unit power production price for the energy injected to the grid.This is the price of the energy injected to the utility in a vector sampled at the fixed freq value.
- Parameters:
df_input_data (pd.DataFrame) β The DataFrame containing all the input data retrieved from hass
method (str, optional) β The method to be used to generate the production price forecast, the options are βconstantβ for a fixed constant value and βcsvβto load a CSV file, defaults to βconstantβ
csv_path (str, optional) β The path to the CSV file used when method = βcsvβ, defaults to β/data/data_load_cost_forecast.csvβ
- Returns:
The input DataFrame with one additionnal column appended containing the power production price for each time observation.
- Return type:
pd.DataFrame
- static get_typical_load_forecast(data, forecast_date)#
Forecast the load profile for the next day based on historic data.
- Parameters:
data (pd.DataFrame) β A DataFrame with a DateTimeIndex containing the historic load data. Must include a βloadβ column.
forecast_date (pd.Timestamp) β The date for which the forecast will be generated.
- Returns:
A Series with the forecasted load profile for the next day and a list of days used to calculate the forecast.
- Return type:
tuple (pd.Series, list)
- async get_weather_forecast(method: str | None = 'open-meteo', csv_path: str | None = 'data_weather_forecast.csv', use_legacy_pvlib: bool | None = False) DataFrame#
Get and generate weather forecast data.
- Parameters:
method (str, optional) β The desired method, options are βopen-meteoβ, βcsvβ, βlistβ, βsolcastβ and βsolar.forecastβ. Defaults to βopen-meteoβ.
- Returns:
The DataFrame containing the forecasted data
- Return type:
pd.DataFrame
- static resample_data(data, freq, current_freq)#
Resample a DataFrame with a custom frequency.
- Parameters:
data (pd.DataFrame) β Original time series data with a DateTimeIndex.
freq (pd.Timedelta) β Desired frequency for resampling (e.g., pd.Timedelta(β10minβ)).
- Returns:
Resampled data at the specified frequency.
- Return type:
pd.DataFrame
- async set_cached_forecast_data(w_forecast_cache_path, data) DataFrame#
Set generated weather forecast data to file. Trim data to match the original requested forecast dates
- Parameters:
w_forecast_cache_path β the path to file.
- Param:
The DataFrame containing the forecasted data
- Type:
pd.DataFrame
- Returns:
The DataFrame containing the forecasted data
- Return type:
pd.DataFrame
emhass.machine_learning_forecaster module#
- class emhass.machine_learning_forecaster.MLForecaster(data: DataFrame, model_type: str, var_model: str, sklearn_model: str, num_lags: int, emhass_conf: dict, logger: Logger)#
Bases:
objectA forecaster class using machine learning models with auto-regressive approach and featuresbased on timestamp information (hour, day, week, etc).
This class uses the skforecast module and the machine learning models are from scikit-learn.
It exposes three main methods:
fit: to train a model with the passed data.
predict: to obtain a forecast from a pre-trained model.
tune: to optimize the models hyperparameters using bayesian optimization.
- async fit(split_date_delta: str | None = '48h', perform_backtest: bool | None = False) tuple[DataFrame, DataFrame]#
The fit method to train the ML model.
- Parameters:
split_date_delta (Optional[str], optional) β The delta from now to split_date_delta that will be used as the test period to evaluate the model, defaults to β48hβ
perform_backtest (Optional[bool], optional) β If True then a back testing routine is performed to evaluate the performance of the model on the complete train set, defaults to False
- Returns:
The DataFrame containing the forecast data results without and with backtest
- Return type:
Tuple[pd.DataFrame, pd.DataFrame]
- async static generate_exog(data_last_window, periods, var_name)#
Generate the exogenous data for future timestamps.
- static get_lags_list_from_frequency(freq: Timedelta) list[int]#
Calculate appropriate lag values based on data frequency.
The lags represent different time horizons (6h, 12h, 1d, 1.5d, 2d, 2.5d, 3d). This method scales these horizons according to the actual data frequency.
- Parameters:
freq (pd.Timedelta) β The frequency of the data as a pandas Timedelta
- Returns:
A list of lag values appropriate for the data frequency
- Return type:
list[int]
- async static interpolate_async(data: DataFrame) DataFrame#
Interpolate missing values asynchronously.
- static neg_r2_score(y_true, y_pred)#
The negative of the r2 score.
- async predict(data_last_window: DataFrame | None = None) Series#
The predict method to generate forecasts from a previously fitted ML model.
- Parameters:
data_last_window (Optional[pd.DataFrame], optional) β The data that will be used to generate the new forecast, this will be freshly retrieved from Home Assistant. This data is needed because the forecast model is an auto-regressive model with lags. If not passed then the data used during the model train is used, defaults to None
- Returns:
A pandas series containing the generated forecasts.
- Return type:
pd.Series
- async tune(split_date_delta: str | None = '48h', n_trials: int = 10, debug: bool | None = False) DataFrame#
Tuning a previously fitted model using bayesian optimization.
- Parameters:
split_date_delta (Optional[str], optional) β The delta from now to split_date_delta that will be used as the test period to evaluate the model, defaults to β48hβ. This define the training/validation split for the tuning process.
debug (Optional[bool], optional) β Set to True for testing and faster optimizations, defaults to False
n_trials (Optional[int], optional) β Number of trials for bayesian optimization, defaults to 10
- Returns:
The DataFrame with the forecasts using the optimized model.
- Return type:
pd.DataFrame
emhass.optimization module#
- class emhass.optimization.Optimization(retrieve_hass_conf: dict, optim_conf: dict, plant_conf: dict, var_load_cost: str, var_prod_price: str, costfun: str, emhass_conf: dict, logger: Logger, opt_time_delta: int | None = 24, num_timesteps: int | None = None)#
Bases:
objectOptimize the deferrable load and battery energy dispatch problem using the linear programming optimization technique. All equipement equations, including the battery equations are hence transformed in a linear form.
This class methods are:
perform_optimization
perform_perfect_forecast_optim
perform_dayahead_forecast_optim
perform_naive_mpc_optim
- perform_dayahead_forecast_optim(df_input_data: DataFrame, p_pv: Series, p_load: Series, stage_times: dict[str, float] | None = None) DataFrame#
Perform a day-ahead optimization task using real forecast data. This type of optimization is intented to be launched once a day.
- Parameters:
df_input_data (pandas.DataFrame) β A DataFrame containing all the input data used for the optimization, notably the unit load cost for power consumption.
p_pv (pandas.DataFrame) β The forecasted PV power production.
p_load (pandas.DataFrame) β The forecasted Load power consumption. This power should not include the power from the deferrable load that we want to find.
stage_times (dict, optional) β Optional dict to record nested sub-stage timings (
optim_solve.build/optim_solve.solve/optim_solve.extract).
- Returns:
opt_res: A DataFrame containing the optimization results
- Return type:
pandas.DataFrame
- perform_naive_mpc_optim(df_input_data: DataFrame, p_pv: Series, p_load: Series, prediction_horizon: int, soc_init: float | None = None, soc_final: float | None = None, def_total_hours: list | None = None, def_total_timestep: list | None = None, def_start_timestep: list | None = None, def_end_timestep: list | None = None, stage_times: dict[str, float] | None = None) DataFrame#
Perform a naive approach to a Model Predictive Control (MPC). This implementaion is naive because we are not using the formal formulation of a MPC. Only the sense of a receiding horizon is considered here. This optimization is more suitable for higher optimization frequency, ex: 5min.
- Parameters:
df_input_data (pandas.DataFrame) β A DataFrame containing all the input data used for the optimization, notably the unit load cost for power consumption.
p_pv (pandas.DataFrame) β The forecasted PV power production.
p_load (pandas.DataFrame) β The forecasted Load power consumption. This power should not include the power from the deferrable load that we want to find.
prediction_horizon (int) β The prediction horizon of the MPC controller in number of optimization time steps.
soc_init (float) β The initial battery SOC for the optimization. This parameter is optional, if not given soc_init = soc_final = soc_target from the configuration file.
soc_final β The final battery SOC for the optimization. This parameter is optional, if not given soc_init = soc_final = soc_target from the configuration file.
def_total_timestep (list) β The functioning timesteps for this iteration for each deferrable load. (For continuous deferrable loads: functioning timesteps at nominal power)
def_total_hours (list) β The functioning hours for this iteration for each deferrable load. (For continuous deferrable loads: functioning hours at nominal power)
def_start_timestep (list) β The timestep as from which each deferrable load is allowed to operate.
def_end_timestep (list) β The timestep before which each deferrable load should operate.
- Returns:
opt_res: A DataFrame containing the optimization results
- Return type:
pandas.DataFrame
- perform_optimization(data_opt: DataFrame, p_pv: array, p_load: array, unit_load_cost: array, unit_prod_price: array, soc_init: float | None = None, soc_final: float | None = None, def_total_hours: list | None = None, def_total_timestep: list | None = None, def_start_timestep: list | None = None, def_end_timestep: list | None = None, def_init_temp: list | None = None, min_power_of_deferrable_loads: list | None = None, debug: bool | None = False, stage_times: dict[str, float] | None = None) DataFrame#
Perform the actual optimization using Convex Programming (CVXPY). Includes automatic fallback to relaxed LP if MILP fails or times out.
If
stage_timesis provided, the wall-clock duration of three internal phases is recorded under the keysoptim_solve.build,optim_solve.solveandoptim_solve.extract. These nest under the existingoptim_solveparent timer incommand_line.pyand sum to it within a few milliseconds.
- perform_perfect_forecast_optim(df_input_data: DataFrame, days_list: date_range) DataFrame#
Perform an optimization on historical data (perfectly known PV production).
- Parameters:
df_input_data (pandas.DataFrame) β A DataFrame containing all the input data used for the optimization, notably photovoltaics and load consumption powers.
days_list (list) β A list of the days of data that will be retrieved from hass and used for the optimization task. We will retrieve data from now and up to days_to_retrieve days
- Returns:
opt_res: A DataFrame containing the optimization results
- Return type:
pandas.DataFrame
- update_battery_power_limits(plant_conf: dict) None#
Update battery charge/discharge power-limit Parameters from plant_conf.
Called on cache hit to sync runtime power-limit values without rebuilding constraints. Mirrors update_thermal_start_temps.
- Parameters:
plant_conf β The plant configuration containing battery_charge_power_max / battery_discharge_power_max
- update_thermal_params(optim_conf: dict, data_opt: DataFrame, p_load: ndarray) None#
Update all thermal parameters from optim_conf and data_opt.
Called on cache hit to sync all runtime thermal parameters without rebuilding constraints. This includes start_temperature, outdoor_temp forecasts, min/max temps, and derived values like thermal_losses, heating_demand, and heatpump_cops.
- Parameters:
optim_conf β The optimization configuration containing def_load_config
data_opt β DataFrame with forecast data (outdoor_temperature_forecast, ghi, etc.)
p_load β Load power forecast array (for internal gains calculation)
- update_thermal_start_temps(optim_conf: dict) None#
Update thermal start temperature parameters from optim_conf.
Called on cache hit to sync runtime thermal parameters without rebuilding constraints. This is a convenience wrapper that only updates start_temp. For full updates including forecasts, use update_thermal_params().
- Parameters:
optim_conf β The optimization configuration containing def_load_config
- static validate_def_timewindow(start: int, end: int, min_steps: int, window: int) tuple[int, int, str]#
Helper function to validate (and if necessary: correct) the defined optimization window of a deferrable load.
- Parameters:
start (int) β Start timestep of the optimization window of the deferrable load
end (int) β End timestep of the optimization window of the deferrable load
min_steps (int) β Minimal timesteps during which the load should operate (at nominal power)
window (int) β Total number of timesteps in the optimization window
- Returns:
start_validated: Validated start timestep of the optimization window of the deferrable load
- Return type:
int
- Returns:
end_validated: Validated end timestep of the optimization window of the deferrable load
- Return type:
int
- Returns:
warning: Any warning information to be returned from the validation steps
- Return type:
string
emhass.retrieve_hass module#
- class emhass.retrieve_hass.RetrieveHass(hass_url: str, long_lived_token: str, freq: Timedelta, time_zone: timezone, params: str, emhass_conf: dict, logger: Logger, get_data_from_file: bool | None = False)#
Bases:
objectRetrieve data from Home Assistant using the restful API.
This class allows the user to retrieve data from a Home Assistant instance using the provided restful API (https://developers.home-assistant.io/docs/api/rest/)
This class methods are:
get_data: to retrieve the actual data from hass
prepare_data: to apply some data treatment in preparation for the optimization task
post_data: Post passed data to hass
- async close() None#
Close the persistent HTTP session.
Should be called when the RetrieveHass instance is no longer needed to properly release resources.
- static get_attr_data_dict(data_df: DataFrame, idx: int, entity_id: str, device_class: str, unit_of_measurement: str, friendly_name: str, list_name: str, state: float, decimals: int = 2) dict#
- async get_data(days_list: date_range, var_list: list, minimal_response: bool | None = False, significant_changes_only: bool | None = False, test_url: str | None = 'empty') None#
Retrieve the actual data from hass.
- Parameters:
days_list (pandas.date_range) β A list of days to retrieve. The ISO format should be used and the timezone is UTC. The frequency of the data_range should be freq=βDβ
var_list (list) β The list of variables to retrive from hass. These should be the exact name of the sensor in Home Assistant. For example: [βsensor.home_loadβ, βsensor.home_pvβ]
minimal_response (bool, optional) β Retrieve a minimal response using the hass restful API, defaults to False
significant_changes_only (bool, optional) β Retrieve significant changes only using the hass restful API, defaults to False
- Returns:
The DataFrame populated with the retrieved data from hass
- Return type:
pandas.DataFrame
- get_data_influxdb(days_list: date_range, var_list: list) bool#
Retrieve data from InfluxDB database.
This method provides an alternative data source to Home Assistant API, enabling longer historical data retention for better machine learning model training.
- Parameters:
days_list (pandas.date_range) β A list of days to retrieve data for
var_list (list) β List of sensor entity IDs to retrieve
- Returns:
Success status of data retrieval
- Return type:
bool
- async get_data_websocket(days_list: date_range, var_list: list[str]) bool#
Retrieve the actual data from hass.
- Parameters:
days_list (pandas.date_range) β A list of days to retrieve. The ISO format should be used and the timezone is UTC. The frequency of the data_range should be freq=βDβ
var_list (list) β The list of variables to retrive from hass. These should be the exact name of the sensor in Home Assistant. For example: [βsensor.home_loadβ, βsensor.home_pvβ]
- Returns:
The DataFrame populated with the retrieved data from hass
- Return type:
pandas.DataFrame
- async get_ha_config()#
Extract some configuration data from HA.
- Return type:
bool
- async get_ha_config_websocket() dict[str, Any]#
Get Home Assistant configuration.
- async post_data(data_df: DataFrame, idx: int, entity_id: str, device_class: str, unit_of_measurement: str, friendly_name: str, type_var: str, publish_prefix: str | None = '', save_entities: bool | None = False, logger_levels: str | None = 'info', dont_post: bool | None = False) None#
Post passed data to hass using REST API.
Note
This method ALWAYS uses the REST API for posting data to Home Assistant, regardless of the use_websocket setting. WebSocket is only used for data retrieval, not for publishing/posting data.
- Parameters:
data_df (pd.DataFrame) β The DataFrame containing the data that will be posted to hass. This should be a one columns DF or a series.
idx (int) β The int index of the location of the data within the passed DataFrame. We will post just one value at a time.
entity_id (str) β The unique entity_id of the sensor in hass.
device_class (str) β The HASS device class for the sensor.
unit_of_measurement (str) β The units of the sensor.
friendly_name (str) β The friendly name that will be used in the hass frontend.
type_var (str) β A variable to indicate the type of variable: power, SOC, etc.
publish_prefix (str, optional) β A common prefix for all published data entity_id.
save_entities (bool, optional) β if entity data should be saved in data_path/entities
logger_levels (str, optional) β set logger level, info or debug, to output
dont_post (bool, optional) β dont post to HA
- prepare_data(var_load: str, load_negative: bool, set_zero_min: bool, var_replace_zero: list[str], var_interp: list[str], skip_renaming: bool = False) bool#
Apply some data treatment in preparation for the optimization task.
- Parameters:
var_load (str) β The name of the variable for the household load consumption.
load_negative (bool, optional) β Set to True if the retrived load variable is negative by convention, defaults to False
set_zero_min (bool, optional) β A special treatment for a minimum value saturation to zero. Values below zero are replaced by nans, defaults to True
var_replace_zero (list, optional) β A list of retrived variables that we would want to replace nans with zeros, defaults to None
var_interp (list, optional) β A list of retrived variables that we would want to interpolate nan values using linear interpolation, defaults to None
- Returns:
The DataFrame populated with the retrieved data from hass and after the data treatment
- Return type:
pandas.DataFrame
emhass.utils module#
- emhass.utils.add_date_features(data: DataFrame, timestamp: str | None = None, date_features: list[str] | None = None) DataFrame#
Add date-related features from a DateTimeIndex or a timestamp column.
- Parameters:
data (pd.DataFrame) β The input DataFrame.
timestamp (Optional[str]) β The column containing the timestamp (optional if DataFrame has a DateTimeIndex).
date_features (Optional[List[str]]) β List of date features to extract (default: all).
- Returns:
The DataFrame with added date features.
- Return type:
pd.DataFrame
- emhass.utils.apply_heating_curve(heating_curve: dict, outdoor_temperature_forecast: ndarray | Series) ndarray#
Compute per-slot supply temperature from a weather-compensated heating curve.
A heating curve specifies how the heat source modulates its supply temperature in response to outdoor temperature, the way every modern boiler / heat pump controller does. The linear form supported here:
T_supply(t) = clip(offset - slope * T_outdoor(t), min_supply, max_supply)
- Parameters:
heating_curve β dict with required
slopeandoffset(both Β°C), plus optionalmin_supply(default 25Β°C) andmax_supply(default 70Β°C).outdoor_temperature_forecast β Per-slot outdoor temperature in Β°C.
- Returns:
Per-slot supply temperature array in Β°C.
- async emhass.utils.build_config(emhass_conf: dict, logger: Logger, defaults_path: str, config_path: str | None = None, legacy_config_path: str | None = None) dict#
Retrieve parameters from configuration files. priority order (low - high) = defaults_path, config_path legacy_config_path
- Parameters:
emhass_conf (dict) β Dictionary containing the needed emhass paths
logger (logging.Logger) β The logger object
defaults_path (str) β path to config file for parameter defaults (config_defaults.json)
config_path (str) β path to the main configuration file (config.json)
legacy_config_path (str) β path to legacy config file (config_emhass.yaml)
- Returns:
The built config dictionary
- Return type:
dict
- async emhass.utils.build_legacy_config_params(emhass_conf: dict[str, Path], legacy_config: dict[str, str], logger: Logger) dict[str, str]#
Build a config dictionary with legacy config_emhass.yaml file. Uses the associations file to convert parameter naming conventions (to config.json/config_defaults.json). Extracts the parameter values and formats to match config.json.
- Parameters:
emhass_conf (dict) β Dictionary containing the needed emhass paths
legacy_config (dict) β The legacy config dictionary
logger (logging.Logger) β The logger object
- Returns:
The built config dictionary
- Return type:
dict
- async emhass.utils.build_params(emhass_conf: dict[str, Path], params_secrets: dict[str, str | float], config: dict[str, str], logger: Logger) dict[str, dict]#
Build the main params dictionary from the config and secrets Appends configuration catagories used by emhass to the parameters. (with use of the associations file as a reference)
- Parameters:
emhass_conf (dict[str, pathlib.Path]) β Dictionary containing the needed emhass paths
params_secrets (dict[str, str | float]) β The dictionary containing the built secret variables
config (dict[str, str]) β The dictionary of built config parameters
logger (logging.Logger) β The logger object
- Returns:
The built param dictionary
- Return type:
dict[str, dict]
- async emhass.utils.build_secrets(emhass_conf: dict[str, Path], logger: Logger, argument: dict[str, str] | None = None, options_path: str | None = None, secrets_path: str | None = None, no_response: bool = False) tuple[dict[str, Path], dict[str, str | float]]#
Retrieve and build parameters from secrets locations (ENV, ARG, Secrets file (secrets_emhass.yaml/options.json) and/or Home Assistant (via API)) priority order (lwo to high) = Defaults (written in function), ENV, Options json file, Home Assistant API, Secrets yaml file, Arguments
- Parameters:
emhass_conf (dict) β Dictionary containing the needed emhass paths
logger (logging.Logger) β The logger object
argument (dict) β dictionary of secrets arguments passed (url,key)
options_path (str) β path to the options file (options.json) (usually provided by EMHASS-Add-on)
secrets_path (str) β path to secrets file (secrets_emhass.yaml)
no_response (bool) β bypass get request to Home Assistant (json response errors)
- Returns:
Updated emhass_conf, the built secrets dictionary
- Return type:
Tuple[dict, dict]:
- emhass.utils.calculate_cop_heatpump(supply_temperature: float | ndarray | Series, carnot_efficiency: float, outdoor_temperature_forecast: ndarray | Series, mode: str = 'heat') ndarray#
Calculate heat pump Coefficient of Performance (COP) for each timestep in the prediction horizon.
The COP is calculated using a Carnot-based formula. Two modes are supported:
mode='heat'(default):\[COP_{heat}(h) = \eta_{carnot} \times \frac{T_{supply\_K}}{T_{supply\_K} - T_{outdoor\_K}(h)}\]mode='cool':\[COP_{cool}(h) = \eta_{carnot} \times \frac{T_{supply\_K}}{T_{outdoor\_K}(h) - T_{supply\_K}}\]
Where temperatures are converted to Kelvin (K = Β°C + 273.15).
This formula models real heat pump behavior where COP decreases as the temperature lift (difference between supply and outdoor temperature) increases. The carnot_efficiency factor represents the real-world efficiency as a fraction of the ideal Carnot cycle efficiency.
- Parameters:
supply_temperature (float or np.ndarray or pd.Series) β The heat pump supply temperature in degrees Celsius. Can be a scalar (constant supply T) or an array/Series matching the length of
outdoor_temperature_forecastfor weather-compensated supply T (heating curve). Typical scalar values: 30-40Β°C for underfloor heating, 50-70Β°C for radiator systems.carnot_efficiency (float) β Real-world efficiency factor as fraction of ideal Carnot cycle. Typical range: 0.35-0.50 (35-50%). Default in thermal battery config: 0.4 (40%). Higher values represent more efficient heat pumps.
outdoor_temperature_forecast (np.ndarray or pd.Series) β Array of outdoor temperature forecasts in degrees Celsius, one value per timestep in the prediction horizon.
mode (str) β Operating mode, either
"heat"or"cool". In cooling mode, the Carnot lift usesT_outdoor - T_supplyso warm weather no longer collapses to COP=1.0 as in heating-only validation.
- Returns:
Array of COP values for each timestep, same length as outdoor_temperature_forecast. Typical COP range: 2-6 for normal operating conditions.
- Return type:
np.ndarray
- Example:
>>> supply_temp = 35.0 # Β°C, underfloor heating >>> carnot_eff = 0.4 # 40% of ideal Carnot efficiency >>> outdoor_temps = np.array([0.0, 5.0, 10.0, 15.0, 20.0]) >>> cops = calculate_cop_heatpump(supply_temp, carnot_eff, outdoor_temps) >>> cops array([3.521..., 4.108..., 4.926..., 6.163..., 8.217...]) >>> # At 5Β°C outdoor: COP = 0.4 Γ 308.15K / 30K = 4.11
- emhass.utils.calculate_heating_demand(specific_heating_demand: float, floor_area: float, outdoor_temperature_forecast: ndarray | Series, base_temperature: float = 18.0, annual_reference_hdd: float = 3000.0, optimization_time_step: int | None = None) ndarray#
Calculate heating demand per timestep based on heating degree days method.
Uses heating degree days (HDD) to calculate heating demand based on outdoor temperature forecast, specific heating demand, and floor area. The specific heating demand should be calibrated to the annual reference HDD value.
- Parameters:
specific_heating_demand (float) β Specific heating demand in kWh/mΒ²/year (calibrated to annual_reference_hdd)
floor_area (float) β Floor area in mΒ²
outdoor_temperature_forecast (np.ndarray | pd.Series) β Outdoor temperature forecast in Β°C for each timestep
base_temperature (float, optional) β Base temperature for HDD calculation in Β°C, defaults to 18.0 (European standard)
annual_reference_hdd (float, optional) β Annual reference HDD value for normalization, defaults to 3000.0 (Central Europe)
optimization_time_step (int | None, optional) β Optimization time step in minutes. If None, automatically infers from pandas Series DatetimeIndex frequency. Falls back to 30 minutes if not inferrable.
- Returns:
Array of heating demand values (kWh) per timestep
- Return type:
np.ndarray
- emhass.utils.calculate_heating_demand_physics(u_value: float, envelope_area: float, ventilation_rate: float, heated_volume: float, indoor_target_temperature: float, outdoor_temperature_forecast: ndarray | Series, optimization_time_step: int, solar_irradiance_forecast: ndarray | Series | None = None, window_area: float | None = None, shgc: float = 0.6, internal_gains_forecast: ndarray | Series | None = None, internal_gains_factor: float = 0.0) ndarray#
Calculate heating demand per timestep based on building physics heat loss model.
More accurate than HDD method as it directly calculates transmission and ventilation losses based on building thermal properties. Optionally accounts for solar gains through windows to reduce heating demand.
- Parameters:
u_value (float) β Overall thermal transmittance (U-value) in W/(mΒ²Β·K). Typical values: - 0.2-0.3: Well-insulated modern building - 0.4-0.6: Average insulation - 0.8-1.2: Poor insulation / old building
envelope_area (float) β Total building envelope area (walls + roof + floor + windows) in mΒ²
ventilation_rate (float) β Air changes per hour (ACH). Typical values: - 0.3-0.5: Well-sealed modern building with controlled ventilation - 0.5-1.0: Average building - 1.0-2.0: Leaky old building
heated_volume (float) β Total heated volume in mΒ³
indoor_target_temperature (float) β Target indoor temperature in Β°C
outdoor_temperature_forecast (np.ndarray | pd.Series) β Outdoor temperature forecast in Β°C for each timestep
optimization_time_step (int) β Optimization time step in minutes
solar_irradiance_forecast (np.ndarray | pd.Series | None, optional) β Global Horizontal Irradiance (GHI) in W/mΒ² for each timestep. If provided along with window_area, solar gains will be subtracted from heating demand.
window_area (float | None, optional) β Total window area in mΒ². If provided along with solar_irradiance_forecast, solar gains will reduce heating demand. Typical values: 15-25% of floor area.
shgc (float, optional) β Solar Heat Gain Coefficient (dimensionless, 0-1). Fraction of solar radiation that becomes heat inside the building. Typical values: - 0.5-0.6: Modern low-e double-glazed windows - 0.6-0.7: Standard double-glazed windows - 0.7-0.8: Single-glazed windows Default: 0.6
internal_gains_forecast (np.ndarray | pd.Series | None, optional) β Electrical load power forecast in W for each timestep. If provided along with internal_gains_factor > 0, internal gains from electrical appliances will be subtracted from heating demand.
internal_gains_factor (float, optional) β Factor (0-1) representing what fraction of electrical load becomes useful internal heat gains. Typical values: - 0.0: No internal gains considered (default, backwards compatible) - 0.5-0.7: Conservative estimate (some heat lost to ventilation/drains) - 0.8-0.9: Most electrical energy becomes heat (well-insulated building) - 1.0: All electrical energy becomes internal heat (theoretical maximum) Default: 0.0
- Returns:
Array of heating demand values (kWh) per timestep
- Return type:
np.ndarray
- Example:
>>> outdoor_temps = np.array([5, 8, 12, 15]) >>> ghi = np.array([0, 100, 400, 600]) # W/mΒ² >>> demand = calculate_heating_demand_physics( ... u_value=0.3, ... envelope_area=400, ... ventilation_rate=0.5, ... heated_volume=250, ... indoor_target_temperature=20, ... outdoor_temperature_forecast=outdoor_temps, ... optimization_time_step=30, ... solar_irradiance_forecast=ghi, ... window_area=50, ... shgc=0.6 ... )
- emhass.utils.calculate_surface_solar_gain(hc: dict, ghi_forecast: ndarray | None, optimization_time_step_minutes: float, length: int | None = None) ndarray | None#
Compute per-timestep solar energy absorbed by an exposed thermal mass surface.
Intended for thermal_battery configs that model a thermal store exposed directly to sunlight (a pool, an outdoor tank, a solar-thermal collector routed into a buffer). The gain is independent of the heater and acts as a negative term on heating_demand (i.e. the optimizer needs less pumped heat to maintain temperature when there is solar gain).
Reuses the existing GHI forecast that EMHASS already fetches for PV. No second weather API call is required.
- Parameters:
hc β
The thermal_battery sub-config dict. Reads two keys: - solar_absorption_area: effective horizontal absorption surface (mΒ²). - solar_absorption_factor: fraction of GHI absorbed by the thermal
mass (typical pool with no cover: 0.7-0.9; covered pool: 0.2-0.4). Defaults to 0.7 if absent.
ghi_forecast β Global horizontal irradiance forecast in W/mΒ² per timestep. Pass None or zero-length array to skip gain.
optimization_time_step_minutes β Timestep duration in minutes.
length β Truncate / pad the returned array to this length.
- Returns:
Solar gain in kWh per timestep, or None if not applicable.
- emhass.utils.calculate_thermal_loss_signed(outdoor_temperature_forecast: ndarray | Series, indoor_temperature: float, base_loss: float) ndarray#
Calculate signed thermal loss factor based on indoor/outdoor temperature difference.
SIGN CONVENTION: - Positive (+loss): outdoor < indoor β heat loss, building cools, heating required - Negative (-loss): outdoor β₯ indoor β heat gain, building warms passively
Formula: loss * (1 - 2 * Hot(h)), where Hot(h) = 1 if outdoor β₯ indoor, else 0. Based on Langer & Volling (2020) Equation B.13.
- Parameters:
outdoor_temperature_forecast (np.ndarray or pd.Series) β Outdoor temperature forecast (Β°C)
indoor_temperature (float) β Indoor/target temperature threshold (Β°C)
base_loss (float) β Base thermal loss coefficient in kW
- Returns:
Signed loss array (positive = heat loss, negative = heat gain)
- Return type:
np.ndarray
- emhass.utils.check_def_loads(num_def_loads: int, parameter: list[dict], default: str | float, parameter_name: str, logger: Logger) list[dict]#
Check parameter lists with deferrable loads number, if they do not match, enlarge to fit.
- Parameters:
num_def_loads (int) β Total number deferrable loads
parameter (list[dict]) β parameter config dict containing paramater
default (str | int | float) β default value for parameter to pad missing
parameter_name (str) β name of parameter
logger (logging.Logger) β The logger object
- Returns:
parameter list
- Return type:
list[dict]
- emhass.utils.clean_sensor_column_names(df: DataFrame, timestamp_col: str) DataFrame#
Clean sensor column names by removing βsensor.β prefix.
- Parameters:
df (pd.DataFrame) β Input DataFrame with sensor columns
timestamp_col (str) β Name of timestamp column to preserve
- Returns:
DataFrame with cleaned column names
- Return type:
pd.DataFrame
- emhass.utils.compile_heat_topology(topology: dict) dict#
Compile a heat-topology graph descriptor into flat optim_conf fields.
The graph model lets users declare a small directed graph of sources, storage, consumers, flows, and actuator_groups. This function translates that high-level descriptor into the primitives the optimizer already understands:
Each flow (source, storage) becomes one deferrable load with a thermal_source block in def_load_config.
Each storage becomes one entry in shared_thermal_tanks with load_ids pointing at the deferrable loads feeding it.
Each consumer is folded into its target storage (its profile or building model populates the storageβs draw_off_demand / u_value etc.).
Each actuator_group becomes one entry in deferrable_load_groups.
Each sourceβs cost_track reference resolves to an entry in cost_forecast_per_deferrable_load.
- Returns a dict of optim_conf fields to merge into the live optim_conf:
number_of_deferrable_loads, nominal_power_of_deferrable_loads, minimum_power_of_deferrable_loads, treat_deferrable_load_as_semi_cont, operating_hours_of_each_deferrable_load, def_load_config, shared_thermal_tanks, deferrable_load_groups, cost_forecast_per_deferrable_load.
Validation: missing source/storage references, duplicated ids, and consumers targeting unknown storage all raise ValueError with the offending field path.
- emhass.utils.get_days_list(days_to_retrieve: int) DatetimeIndex#
Get list of past days from today to days_to_retrieve.
- Parameters:
days_to_retrieve (int) β Total number of days to retrieve from the past
- Returns:
The list of days
- Return type:
pd.DatetimeIndex
- emhass.utils.get_forecast_dates(freq: int, delta_forecast: int, time_zone: tzinfo, timedelta_days: int | None = 0) DatetimeIndex#
Get the date_range list of the needed future dates using the delta_forecast parameter.
- Parameters:
freq (int) β Optimization time step.
delta_forecast (int) β Number of days to forecast in the future to be used for the optimization.
timedelta_days (Optional[int], optional) β Number of truncated days needed for each optimization iteration, defaults to 0
- Returns:
A list of future forecast dates.
- Return type:
pd.core.indexes.datetimes.DatetimeIndex
- emhass.utils.get_injection_dict(df: DataFrame, plot_size: int | None = 1366) dict#
Build a dictionary with graphs and tables for the webui.
- Parameters:
df (pd.DataFrame) β The optimization result DataFrame
plot_size (Optional[int], optional) β Size of the plot figure in pixels, defaults to 1366
- Returns:
A dictionary containing the graphs and tables in html format
- Return type:
dict
- emhass.utils.get_injection_dict_forecast_model_fit(df_fit_pred: pd.DataFrame, mlf: MLForecaster) dict#
Build a dictionary with graphs and tables for the webui for special MLF fit case.
- Parameters:
df_fit_pred (pd.DataFrame) β The fit result DataFrame
mlf (MLForecaster) β The MLForecaster object
- Returns:
A dictionary containing the graphs and tables in html format
- Return type:
dict
- emhass.utils.get_injection_dict_forecast_model_tune(df_pred_optim: pd.DataFrame, mlf: MLForecaster) dict#
Build a dictionary with graphs and tables for the webui for special MLF tune case.
- Parameters:
df_pred_optim (pd.DataFrame) β The tune result DataFrame
mlf (MLForecaster) β The MLForecaster object
- Returns:
A dictionary containing the graphs and tables in html format
- Return type:
dict
- emhass.utils.get_keys_to_mask() list[str]#
Return a list of sensitive configuration keys that should be masked in logs or treated specially in the UI (e.g., secrets).
- emhass.utils.get_logger(fun_name: str, emhass_conf: dict[str, Path], save_to_file: bool = True, logging_level: str = 'DEBUG') tuple[Logger, StreamHandler]#
Create a simple logger object.
- Parameters:
fun_name (str) β The Python function object name where the logger will be used
emhass_conf (dict) β Dictionary containing the needed emhass paths
save_to_file (bool, optional) β Write log to a file, defaults to True
- Returns:
The logger object and the handler
- Return type:
object
- emhass.utils.get_root(file: str, num_parent: int = 3) str#
Get the root absolute path of the working directory.
- Parameters:
file β The passed file path with __file__
num_parent (int, optional) β The number of parents levels up to desired root folder
- Returns:
The root path
- Return type:
str
- emhass.utils.get_yaml_parse(params: str | dict, logger: Logger) tuple[dict, dict, dict]#
Perform parsing of the params into the configuration catagories
- Parameters:
params (str or dict) β Built configuration parameters
logger (logging.Logger) β The logger object
- Returns:
A tuple with the dictionaries containing the parsed data
- Return type:
tuple(dict)
- emhass.utils.handle_nan_values(df: DataFrame, handle_nan: str, timestamp_col: str, logger: Logger) DataFrame#
Handle NaN values in DataFrame according to specified strategy.
- Parameters:
df (pd.DataFrame) β Input DataFrame
handle_nan (str) β Strategy for handling NaN values
timestamp_col (str) β Name of timestamp column to exclude from processing
logger (logging.Logger) β Logger object
- Returns:
DataFrame with NaN values handled
- Return type:
pd.DataFrame
- emhass.utils.log_runtime_banner(logger, optim_conf: dict | None = None)#
Log a single INFO line with EMHASS/Python/CVXPY/platform info for bug-report reproducibility.
When
optim_confis provided, the configured solver (or the EMHASS defaultHighswhen the key is absent) is shown β this matches the solver the LP actually uses (seeoptimization.pyconstructor). Whenoptim_confis missing entirely (early-fail paths), falls back tocvxpy.installed_solvers()[0].
- emhass.utils.normalize_heat_cool_mode(value: str, *, field_name: str = 'mode', context: str | None = None) str#
Normalize heat/cool mode values and raise on invalid input.
- emhass.utils.param_to_config(param: dict[str, dict], logger: Logger) dict[str, str]#
A function that extracts the parameters from param back to the config.json format. Extracts parameters from config catagories. Attempts to exclude secrets hosed in retrieve_hass_conf.
- Parameters:
params β Built configuration parameters
logger (logging.Logger) β The logger object
- Returns:
The built config dictionary
- Return type:
dict[str, str]
- emhass.utils.parse_export_time_range(start_time: str, end_time: str | None, time_zone: <property object at 0x7f83edd613a0>, logger: Logger) tuple[Timestamp, Timestamp] | tuple[bool, bool]#
Parse and validate start_time and end_time for export operations.
- Parameters:
start_time (str) β Start time string in ISO format
end_time (str | None) β End time string in ISO format (optional)
time_zone (pd.Timestamp.tz) β Timezone for localization
logger (logging.Logger) β Logger object
- Returns:
Tuple of (start_dt, end_dt) or (False, False) on error
- Return type:
tuple[pd.Timestamp, pd.Timestamp] | tuple[bool, bool]
- emhass.utils.resample_and_filter_data(df: DataFrame, start_dt: Timestamp, end_dt: Timestamp, resample_freq: str, logger: Logger) DataFrame | bool#
Filter DataFrame to time range and resample to specified frequency.
- Parameters:
df (pd.DataFrame) β Input DataFrame with datetime index
start_dt (pd.Timestamp) β Start datetime for filtering
end_dt (pd.Timestamp) β End datetime for filtering
resample_freq (str) β Resampling frequency string (e.g., β1hβ, β30minβ)
logger (logging.Logger) β Logger object
- Returns:
Resampled DataFrame or False on error
- Return type:
pd.DataFrame | bool
- emhass.utils.resolve_min_temperatures(config: dict, outdoor_temperature_forecast: ndarray | Series | list | None, length: int) list[float]#
Compute the effective per-slot lower temperature bound for a storage tank.
Combines two sources, taking the element-wise max so the more conservative floor always wins:
Static
min_temperatures(ormin_temperature) list - an absolute weather-independent floor for safety / comfort. Always respected.min_temperature_curvedict - a weather-compensated floor matching the radiator emission law. Same shape asheating_curve:T = clip(offset - slope * T_outdoor, min_supply, max_supply).
When only one is set, that one is used. When neither is set, returns an empty list (caller decides how to react).
- Parameters:
config β Tank or thermal_battery dict potentially carrying
min_temperaturesand/ormin_temperature_curve.outdoor_temperature_forecast β Per-slot outdoor temperature. May be
Nonewhen only the static floor is configured.length β Optimization horizon length.
- Returns:
List of per-slot minimum temperatures (length =
length).
- emhass.utils.resolve_thermal_battery_cop(hc: dict, outdoor_temperature_forecast: Sequence[float] | ndarray | Series | None, length: int | None = None) ndarray#
Resolve the per-timestep energy-conversion factor for a thermal_battery heat source.
The thermal_battery model treats the conversion factor uniformly as a COP-like multiplier on input power: Q_thermal = COP * P_in / 1000 * dt. Two source types are supported:
- Heat pump (default): COP is computed via the Carnot formula and varies with
the outdoor temperature. Requires supply_temperature in hc; uses carnot_efficiency (default 0.4). If sense is set to βcoolβ, cooling Carnot lift is used (T_outdoor - T_supply).
Constant-efficiency source (gas boiler, oil burner, district heating, etc.): efficiency in hc is used as a flat conversion factor for every timestep. supply_temperature is not required and outdoor temperature is ignored. The constant value passes through Carnot bounds intentionally (typical 0.85-0.95 for combustion sources).
- Parameters:
hc β The thermal_battery sub-config dict from def_load_config.
outdoor_temperature_forecast β Outdoor temperature forecast in degrees Celsius. Required in heat-pump mode. In constant-efficiency mode it is ignored and may be
Noneprovidedlengthis given explicitly.length β Number of timesteps in the returned array. Mandatory when
outdoor_temperature_forecastisNone; otherwise truncates or passes through the forecast length when set, or returns the full forecast length when unset.
- Returns:
Numpy array of conversion factors, one per timestep.
- emhass.utils.set_df_index_freq(df: DataFrame) DataFrame#
Set the freq of a DataFrame DateTimeIndex.
- Parameters:
df (pd.DataFrame) β Input DataFrame
- Returns:
Input DataFrame with freq defined
- Return type:
pd.DataFrame
- emhass.utils.stage_timer(stage_times: dict, name: str, logger: Logger | None = None)#
Record wall-clock elapsed time of a block in
stage_times[name].Emits one DEBUG line per stage when
loggeris provided. Works acrossawaitbecausetime.perf_counter()is a plain monotonic read.
- async emhass.utils.treat_runtimeparams(runtimeparams: str, params: dict[str, dict], retrieve_hass_conf: dict[str, str], optim_conf: dict[str, str], plant_conf: dict[str, str], set_type: str, logger: Logger, emhass_conf: dict[str, Path]) tuple[str, dict[str, dict]]#
Treat the passed optimization runtime parameters.
- Parameters:
runtimeparams (str) β Json string containing the runtime parameters dict.
params (str) β Built configuration parameters
retrieve_hass_conf (dict) β Config dictionary for data retrieving parameters.
optim_conf (dict) β Config dictionary for optimization parameters.
plant_conf (dict) β Config dictionary for technical plant parameters.
set_type (str) β The type of action to be performed.
logger (logging.Logger) β The logger object.
emhass_conf (dict) β Dictionary containing the needed emhass paths
- Returns:
Returning the params and optimization parameter container.
- Return type:
Tuple[str, dict]