emhass 0.13.2__py3-none-any.whl → 0.13.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -122,13 +122,14 @@
122
122
  },
123
123
  "lp_solver": {
124
124
  "friendly_name": "Linear programming solver",
125
- "Description": "Set the name of the linear programming solver that will be used. Defaults to ‘COIN_CMD’. The options are ‘PULP_CBC_CMD’, ‘GLPK_CMD and ‘COIN_CMD’.",
125
+ "Description": "Set the name of the linear programming solver that will be used. Defaults to ‘COIN_CMD’. The options are ‘PULP_CBC_CMD’, ‘GLPK_CMD’, ‘HiGHS’, and ‘COIN_CMD’.",
126
126
  "input": "select",
127
127
  "select_options": [
128
128
  "default",
129
129
  "COIN_CMD",
130
130
  "PULP_CBC_CMD",
131
- "GLPK_CMD"
131
+ "GLPK_CMD",
132
+ "HiGHS"
132
133
  ],
133
134
  "default_value": "COIN_CMD"
134
135
  },
@@ -138,6 +139,12 @@
138
139
  "input": "text",
139
140
  "default_value": "/usr/bin/cbc"
140
141
  },
142
+ "num_threads": {
143
+ "friendly_name": "Number of threads to use for the LP solver",
144
+ "Description": "Set the number of threads for the LP solver to use, when supported by the solver. Defaults to 0 (autodetect)",
145
+ "input": "int",
146
+ "default_value": 0
147
+ },
141
148
  "lp_solver_timeout": {
142
149
  "friendly_name": "Linear programming solver timeout",
143
150
  "Description": "Set the maximum time (in seconds) for the LP solver. Defaults to 45.",
@@ -180,6 +187,30 @@
180
187
  "input": "boolean",
181
188
  "default_value": false
182
189
  },
190
+ "inverter_ac_output_max": {
191
+ "friendly_name": "Max hybrid inverter AC output power",
192
+ "Description": "Maximum hybrid inverter output power from combined PV and battery discharge.",
193
+ "input": "int",
194
+ "default_value": 0
195
+ },
196
+ "inverter_ac_input_max": {
197
+ "friendly_name": "Max hybrid inverter AC input power",
198
+ "Description": "Maximum hybrid inverter input power from grid to charge battery.",
199
+ "input": "int",
200
+ "default_value": 0
201
+ },
202
+ "inverter_efficiency_dc_ac": {
203
+ "friendly_name": "Hybrid inverter efficency DC to AC",
204
+ "Description": "Hybrid inverter efficiency from the DC bus to AC output. (percentage/100)",
205
+ "input": "float",
206
+ "default_value": 1.0
207
+ },
208
+ "inverter_efficiency_ac_dc": {
209
+ "friendly_name": "Hybrid inverter efficency AC to DC",
210
+ "Description": "Hybrid inverter efficiency when charging from the AC input to DC bus. (percentage/100)",
211
+ "input": "float",
212
+ "default_value": 1.0
213
+ },
183
214
  "compute_curtailment": {
184
215
  "friendly_name": "Set compute curtailment (grid export limit)",
185
216
  "Description": "Set to True to compute a special PV curtailment variable (Default False)",
@@ -477,6 +508,12 @@
477
508
  "Description": "The desired battery state of charge at the end of each optimization cycle. (percentage/100)",
478
509
  "input": "float",
479
510
  "default_value": 0.6
511
+ },
512
+ "ignore_pv_feedback_during_curtailment": {
513
+ "friendly_name": "Ignore PV feedback during curtailment",
514
+ "Description": "When set to true, prevents PV forecast from being updated with real PV data, avoiding flip-flop behavior during curtailment operations",
515
+ "input": "bool",
516
+ "default_value": false
480
517
  }
481
518
  }
482
519
  }
emhass/utils.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python3
2
1
  from __future__ import annotations
3
2
 
4
3
  import ast
@@ -120,12 +119,12 @@ def get_forecast_dates(
120
119
 
121
120
  """
122
121
  freq = pd.to_timedelta(freq, "minutes")
123
- start_forecast = pd.Timestamp(datetime.now()).replace(
124
- hour=0, minute=0, second=0, microsecond=0
125
- )
126
- end_forecast = (start_forecast + pd.Timedelta(days=delta_forecast)).replace(
127
- microsecond=0
122
+ start_forecast = (
123
+ pd.Timestamp(datetime.now(), tz=time_zone)
124
+ .replace(microsecond=0)
125
+ .floor(freq=freq)
128
126
  )
127
+ end_forecast = start_forecast + pd.Timedelta(days=delta_forecast)
129
128
  forecast_dates = (
130
129
  pd.date_range(
131
130
  start=start_forecast,
@@ -409,11 +408,29 @@ def treat_runtimeparams(
409
408
  runtimeparams.get("delta_forecast_daily", None) is not None
410
409
  or runtimeparams.get("delta_forecast", None) is not None
411
410
  ):
412
- delta_forecast = int(
413
- runtimeparams.get(
414
- "delta_forecast_daily", runtimeparams["delta_forecast"]
411
+ # Use old param name delta_forecast (if provided) for backwards compatibility
412
+ delta_forecast = runtimeparams.get("delta_forecast", None)
413
+ # Prefer new param name delta_forecast_daily
414
+ delta_forecast = runtimeparams.get("delta_forecast_daily", delta_forecast)
415
+ # Ensure delta_forecast is numeric and at least 1 day
416
+ if delta_forecast is None:
417
+ logger.warning("delta_forecast_daily is missing so defaulting to 1 day")
418
+ delta_forecast = 1
419
+ else:
420
+ try:
421
+ delta_forecast = int(delta_forecast)
422
+ except ValueError:
423
+ logger.warning(
424
+ "Invalid delta_forecast_daily value (%s) so defaulting to 1 day",
425
+ delta_forecast,
426
+ )
427
+ delta_forecast = 1
428
+ if delta_forecast <= 0:
429
+ logger.warning(
430
+ "delta_forecast_daily is too low (%s) so defaulting to 1 day",
431
+ delta_forecast,
415
432
  )
416
- )
433
+ delta_forecast = 1
417
434
  params["optim_conf"]["delta_forecast_daily"] = pd.Timedelta(
418
435
  days=delta_forecast
419
436
  )
@@ -574,27 +591,49 @@ def treat_runtimeparams(
574
591
  # Loop forecasts, check if value is a list and greater than or equal to forecast_dates
575
592
  for method, forecast_key in enumerate(list_forecast_key):
576
593
  if forecast_key in runtimeparams.keys():
577
- if isinstance(runtimeparams[forecast_key], list) and len(
578
- runtimeparams[forecast_key]
579
- ) >= len(forecast_dates):
580
- params["passed_data"][forecast_key] = runtimeparams[forecast_key]
594
+ forecast_input = runtimeparams[forecast_key]
595
+ if isinstance(forecast_input, dict):
596
+ forecast_data_df = pd.DataFrame.from_dict(
597
+ forecast_input, orient="index"
598
+ ).reset_index()
599
+ forecast_data_df.columns = ["time", "value"]
600
+ forecast_data_df["time"] = pd.to_datetime(
601
+ forecast_data_df["time"], format="ISO8601", utc=True
602
+ ).dt.tz_convert(time_zone)
603
+
604
+ # align index with forecast_dates
605
+ forecast_data_df = (
606
+ forecast_data_df.resample(
607
+ pd.to_timedelta(optimization_time_step, "minutes"),
608
+ on="time",
609
+ )
610
+ .aggregate({"value": "mean"})
611
+ .reindex(forecast_dates, method="nearest")
612
+ )
613
+ forecast_data_df["value"] = (
614
+ forecast_data_df["value"].ffill().bfill()
615
+ )
616
+ forecast_input = forecast_data_df["value"].tolist()
617
+ if isinstance(forecast_input, list) and len(forecast_input) >= len(
618
+ forecast_dates
619
+ ):
620
+ params["passed_data"][forecast_key] = forecast_input
581
621
  params["optim_conf"][forecast_methods[method]] = "list"
582
622
  else:
583
623
  logger.error(
584
- f"ERROR: The passed data is either not a list or the length is not correct, length should be {str(len(forecast_dates))}"
624
+ f"ERROR: The passed data is either the wrong type or the length is not correct, length should be {str(len(forecast_dates))}"
585
625
  )
586
626
  logger.error(
587
627
  f"Passed type is {str(type(runtimeparams[forecast_key]))} and length is {str(len(runtimeparams[forecast_key]))}"
588
628
  )
589
629
  # Check if string contains list, if so extract
590
- if isinstance(runtimeparams[forecast_key], str):
591
- if isinstance(ast.literal_eval(runtimeparams[forecast_key]), list):
592
- runtimeparams[forecast_key] = ast.literal_eval(
593
- runtimeparams[forecast_key]
594
- )
630
+ if isinstance(forecast_input, str):
631
+ if isinstance(ast.literal_eval(forecast_input), list):
632
+ forecast_input = ast.literal_eval(forecast_input)
633
+ runtimeparams[forecast_key] = forecast_input
595
634
  list_non_digits = [
596
635
  x
597
- for x in runtimeparams[forecast_key]
636
+ for x in forecast_input
598
637
  if not (isinstance(x, int) or isinstance(x, float))
599
638
  ]
600
639
  if len(list_non_digits) > 0:
@@ -1638,6 +1677,7 @@ def build_params(
1638
1677
  "end_timesteps_of_each_deferrable_load": None,
1639
1678
  "alpha": None,
1640
1679
  "beta": None,
1680
+ "ignore_pv_feedback_during_curtailment": None,
1641
1681
  }
1642
1682
 
1643
1683
  return params
emhass/web_server.py CHANGED
@@ -10,10 +10,10 @@ import threading
10
10
  from importlib.metadata import PackageNotFoundError, version
11
11
  from pathlib import Path
12
12
 
13
+ import jinja2
13
14
  import yaml
14
15
  from flask import Flask, make_response, request
15
16
  from flask import logging as log
16
- from jinja2 import Environment, PackageLoader
17
17
  from waitress import serve
18
18
 
19
19
  from emhass.command_line import (
@@ -50,6 +50,10 @@ params_secrets = {}
50
50
  continual_publish_thread = []
51
51
  injection_dict = {}
52
52
 
53
+ templates = jinja2.Environment(
54
+ loader=jinja2.PackageLoader("emhass", "templates"),
55
+ )
56
+
53
57
 
54
58
  def create_app(settings_override=None):
55
59
  """
@@ -137,14 +141,6 @@ def index():
137
141
 
138
142
  """
139
143
  app.logger.info("EMHASS server online, serving index.html...")
140
- # Load HTML template
141
- file_loader = PackageLoader("emhass", "templates")
142
- env = Environment(loader=file_loader)
143
- # check if index.html exists
144
- if "index.html" not in env.list_templates():
145
- app.logger.error("Unable to find index.html in emhass module")
146
- return make_response(["ERROR: unable to find index.html in emhass module"], 404)
147
- template = env.get_template("index.html")
148
144
  # Load cached dict (if exists), to present generated plot tables
149
145
  if (emhass_conf["data_path"] / "injection_dict.pkl").exists():
150
146
  with open(str(emhass_conf["data_path"] / "injection_dict.pkl"), "rb") as fid:
@@ -159,6 +155,7 @@ def index():
159
155
  # basename = request.headers.get("X-Ingress-Path", "")
160
156
  # return make_response(template.render(injection_dict=injection_dict, basename=basename))
161
157
 
158
+ template = templates.get_template("index.html")
162
159
  return make_response(template.render(injection_dict=injection_dict))
163
160
 
164
161
 
@@ -174,16 +171,8 @@ def configuration():
174
171
  if (emhass_conf["data_path"] / "params.pkl").exists():
175
172
  with open(str(emhass_conf["data_path"] / "params.pkl"), "rb") as fid:
176
173
  emhass_conf["config_path"], params = pickle.load(fid)
177
- # Load HTML template
178
- file_loader = PackageLoader("emhass", "templates")
179
- env = Environment(loader=file_loader)
180
- # check if configuration.html exists
181
- if "configuration.html" not in env.list_templates():
182
- app.logger.error("Unable to find configuration.html in emhass module")
183
- return make_response(
184
- ["ERROR: unable to find configuration.html in emhass module"], 404
185
- )
186
- template = env.get_template("configuration.html")
174
+
175
+ template = templates.get_template("configuration.html")
187
176
  return make_response(template.render(config=params))
188
177
 
189
178
 
@@ -195,15 +184,6 @@ def template_action():
195
184
 
196
185
  """
197
186
  app.logger.info(" >> Sending rendered template table data")
198
- file_loader = PackageLoader("emhass", "templates")
199
- env = Environment(loader=file_loader)
200
- # Check if template.html exists
201
- if "template.html" not in env.list_templates():
202
- app.logger.error("Unable to find template.html in emhass module")
203
- return make_response(
204
- ["WARNING: unable to find template.html in emhass module"], 404
205
- )
206
- template = env.get_template("template.html")
207
187
  if (emhass_conf["data_path"] / "injection_dict.pkl").exists():
208
188
  with open(str(emhass_conf["data_path"] / "injection_dict.pkl"), "rb") as fid:
209
189
  injection_dict = pickle.load(fid)
@@ -211,6 +191,8 @@ def template_action():
211
191
  app.logger.warning("Unable to obtain plot data from injection_dict.pkl")
212
192
  app.logger.warning("Try running an launch an optimization task")
213
193
  injection_dict = {}
194
+
195
+ template = templates.get_template("template.html")
214
196
  return make_response(template.render(injection_dict=injection_dict))
215
197
 
216
198
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emhass
3
- Version: 0.13.2
3
+ Version: 0.13.4
4
4
  Summary: An Energy Management System for Home Assistant
5
5
  Project-URL: Homepage, https://github.com/davidusb-geek/emhass
6
6
  Project-URL: Source, https://github.com/davidusb-geek/emhass
@@ -24,6 +24,7 @@ Requires-Python: <3.13,>=3.10
24
24
  Requires-Dist: flask>=3.1.0
25
25
  Requires-Dist: gunicorn>=23.0.0
26
26
  Requires-Dist: h5py>=3.12.1
27
+ Requires-Dist: highspy>=1.10.0
27
28
  Requires-Dist: numpy<2.3.0,>=2.0.0
28
29
  Requires-Dist: pandas>=2.2.0
29
30
  Requires-Dist: plotly>=6.0.0
@@ -117,17 +118,10 @@ Description-Content-Type: text/markdown
117
118
  </div>
118
119
 
119
120
  <br>
120
- <p align="center">
121
- If you like this work please consider buying a coffee ;-)
122
- </p>
123
- <p align="center">
124
- <a href="https://www.buymeacoffee.com/davidusbgeek" target="_blank">
125
- <img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
126
- </a>
121
+ <p align="left">
122
+ EMHASS is a Python module designed to optimize your home energy interfacing with Home Assistant.
127
123
  </p>
128
124
 
129
- EHMASS is a Python module designed to optimize your home energy interfacing with Home Assistant.
130
-
131
125
  ## Introduction
132
126
 
133
127
  EMHASS (Energy Management for Home Assistant) is an optimization tool designed for residential households. The package uses a Linear Programming approach to optimize energy usage while considering factors such as electricity prices, power generation from solar panels, and energy storage from batteries. EMHASS provides a high degree of configurability, making it easy to integrate with Home Assistant and other smart home systems. Whether you have solar panels, energy storage, or just a controllable load, EMHASS can provide an optimized daily schedule for your devices, allowing you to save money and minimize your environmental impact.
@@ -196,12 +190,13 @@ _Note: Both EMHASS via Docker and EMHASS-Add-on contain the same Docker image. T
196
190
 
197
191
  ### Method 2) Running EMHASS in Docker
198
192
 
199
- You can also install EMHASS using Docker as a container. This can be in the same machine as Home Assistant (if your running Home Assistant as a Docker container) or in a different distant machine. To install first pull the latest image:
193
+ You can also install EMHASS using Docker as a container. This can be in the same machine as Home Assistant (if your running Home Assistant as a Docker container) or in a different distant machine. The "share" folder is where EMHASS stores the config.json file. In the examples below adjust the "-v" volume mappings to reflect where your path to the local host directory needs to be mapped to.
194
+ To install first pull the latest image:
200
195
  ```bash
201
196
  # pull Docker image
202
197
  docker pull ghcr.io/davidusb-geek/emhass:latest
203
- # run Docker image, mounting config.json and secrets_emhass.yaml from host
204
- docker run --rm -it --restart always -p 5000:5000 --name emhass-container -v ./config.json:/share/config.json -v ./secrets_emhass.yaml:/app/secrets_emhass.yaml ghcr.io/davidusb-geek/emhass:latest
198
+ # run Docker image, mounting the dir storing config.json and secrets_emhass.yaml from host
199
+ docker run --rm -it --restart always -p 5000:5000 --name emhass-container -v /emhass/share:/share/ -v /emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml ghcr.io/davidusb-geek/emhass:latest
205
200
  ```
206
201
  *Note it is not recommended to install the latest EMHASS image with `:latest` *(as you would likely want to control when you update EMHASS version)*. Instead, find the [latest version tag](https://github.com/davidusb-geek/emhass/pkgs/container/emhass) (E.g: `v0.2.1`) and replace `latest`*
207
202
 
@@ -215,7 +210,7 @@ cd emhass
215
210
  # may need to set architecture tag (docker build --build-arg TARGETARCH=amd64 -t emhass-local .)
216
211
  docker build -t emhass-local .
217
212
  # run built Docker image, mounting config.json and secrets_emhass.yaml from host
218
- docker run --rm -it -p 5000:5000 --name emhass-container -v ./config.json:/share/config.json -v ./secrets_emhass.yaml:/app/secrets_emhass.yaml emhass-local
213
+ docker run --rm -it -p 5000:5000 --name emhass-container -v /emhass/share:/share -v /emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml emhass-local
219
214
  ```
220
215
 
221
216
  Before running the docker container, make sure you have a designated folder for emhass on your host device and a `secrets_emhass.yaml` file. You can get a example of the secrets file from [`secrets_emhass(example).yaml`](https://github.com/davidusb-geek/emhass/blob/master/secrets_emhass(example).yaml) file on this repository.
@@ -231,23 +226,23 @@ Latitude: 45.83
231
226
  Longitude: 6.86
232
227
  Altitude: 4807.8
233
228
  EOT
234
- docker run --rm -it --restart always -p 5000:5000 --name emhass-container -v ./config.json:/share/config.json -v ./secrets_emhass.yaml:/app/secrets_emhass.yaml ghcr.io/davidusb-geek/emhass:latest
229
+ docker run --rm -it --restart always -p 5000:5000 --name emhass-container -v /emhass/share:/share -v /emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml ghcr.io/davidusb-geek/emhass:latest
235
230
  ```
236
231
 
237
232
  #### Docker, things to note
238
233
 
239
- - You can create a `config.json` file prior to running emhass. *(obtain a example from: [config_defaults.json](https://github.com/davidusb-geek/emhass/blob/enhass-standalone-addon-merge/src/emhass/data/config_defaults.json)* Alteratively, you can insert your parameters into the configuration page on the EMHASS web server. (for EMHASS to auto create a config.json) With either option, the volume mount `-v ./config.json:/share/config.json` should be applied to make sure your config is stored on the host device. (to be not deleted when the EMHASS container gets removed/image updated)*
234
+ - You can create a `config.json` file prior to running emhass. *(obtain a example from: [config_defaults.json](https://github.com/davidusb-geek/emhass/blob/enhass-standalone-addon-merge/src/emhass/data/config_defaults.json)* Alteratively, you can insert your parameters into the configuration page on the EMHASS web server. (for EMHASS to auto create a config.json) With either option, the volume mount `-v /emhass/share:/share` should be applied to make sure your config is stored on the host device. (to be not deleted when the EMHASS container gets removed/image updated)*
240
235
 
241
236
  - If you wish to keep a local, semi-persistent copy of the EMHASS-generated data, create a local folder on your device, then mount said folder inside the container.
242
237
  ```bash
243
238
  #create data folder
244
239
  mkdir -p ~/emhass/data
245
- docker run -it --restart always -p 5000:5000 -e LOCAL_COSTFUN="profit" -v ~/emhass/config.json:/app/config.json -v ~/emhass/data:/data -v ~/emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml --name DockerEMHASS <REPOSITORY:TAG>
240
+ docker run -it --restart always -p 5000:5000 -e LOCAL_COSTFUN="profit" -v /emhass/share:/share -v /emhass/data:/data -v /emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml --name DockerEMHASS <REPOSITORY:TAG>
246
241
  ```
247
242
 
248
243
  - If you wish to set the web_server's homepage optimization diagrams to a timezone other than UTC, set `TZ` environment variable on docker run:
249
244
  ```bash
250
- docker run -it --restart always -p 5000:5000 -e TZ="Europe/Paris" -v ~/emhass/config.json:/app/config.json -v ~/emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml --name DockerEMHASS <REPOSITORY:TAG>
245
+ docker run -it --restart always -p 5000:5000 -e TZ="Europe/Paris" -v /emhass/share:/share -v /emhass/secrets_emhass.yaml:/app/secrets_emhass.yaml --name DockerEMHASS <REPOSITORY:TAG>
251
246
  ```
252
247
  ### Method 3) Legacy method using a Python virtual environment *(Legacy CLI)*
253
248
  If you wish to run EMHASS optimizations with cli commands. *(no persistent web server session)* you can run EMHASS via the python package alone *(not wrapped in a Docker container)*.
@@ -319,12 +314,22 @@ Additional optimization strategies were developed later, that can be used in com
319
314
 
320
315
  ### Dayahead Optimization - Method 1) Add-on and docker standalone
321
316
 
322
- In `configuration.yaml`:
317
+ We can use the `shell_command` integration in `configuration.yaml`:
323
318
  ```yaml
324
319
  shell_command:
325
320
  dayahead_optim: "curl -i -H \"Content-Type:application/json\" -X POST -d '{}' http://localhost:5000/action/dayahead-optim"
326
321
  publish_data: "curl -i -H \"Content-Type:application/json\" -X POST -d '{}' http://localhost:5000/action/publish-data"
327
322
  ```
323
+ An alternative that will be useful when passing data at runtime (see dedicated section), we can use the the `rest_command` instead:
324
+ ```yaml
325
+ rest_command:
326
+ url: http://127.0.0.1:5000/action/dayahead-optim
327
+ method: POST
328
+ headers:
329
+ content-type: application/json
330
+ payload: >-
331
+ {}
332
+ ```
328
333
  ### Dayahead Optimization - Method 2) Legacy method using a Python virtual environment
329
334
 
330
335
  In `configuration.yaml`:
@@ -387,8 +392,8 @@ In `automations.yaml`:
387
392
  ```
388
393
  in configuration page/`config.json`
389
394
  ```json
390
- 'method_ts_round': "first"
391
- 'continual_publish': true
395
+ "method_ts_round": "first"
396
+ "continual_publish": true
392
397
  ```
393
398
  In this automation, the day-ahead optimization is performed once a day, every day at 5:30am.
394
399
  If the `optimization_time_step` parameter is set to `30` *(default)* in the configuration, the results of the day-ahead optimization will generate 48 values *(for each entity)*, a value for every 30 minutes in a day *(i.e. 24 hrs x 2)*.
@@ -542,7 +547,7 @@ For users who wish to have full control of exactly when they would like to run a
542
547
 
543
548
  in configuration page/`config.json` :
544
549
  ```json
545
- 'continual_publish': false
550
+ "continual_publish": false
546
551
  ```
547
552
  POST action :
548
553
  ```bash
@@ -666,6 +671,25 @@ curl -i -H 'Content-Type:application/json' -X POST -d '{"pv_power_forecast":[0,
666
671
  curl -i -H 'Content-Type:application/json' -X POST -d '{"pv_power_forecast":[0, 70, 141.22, 246.18, 513.5, 753.27, 1049.89, 1797.93, 1697.3, 3078.93], "prediction_horizon":10, "soc_init":0.5,"soc_final":0.6,"operating_hours_of_each_deferrable_load":[1,3],"start_timesteps_of_each_deferrable_load":[0,3],"end_timesteps_of_each_deferrable_load":[0,6]}' http://localhost:5000/action/naive-mpc-optim
667
672
  ```
668
673
 
674
+ For a more readable option we can use the `rest_command` integration:
675
+ ```yaml
676
+ rest_command:
677
+ url: http://127.0.0.1:5000/action/dayahead-optim
678
+ method: POST
679
+ headers:
680
+ content-type: application/json
681
+ payload: >-
682
+ {
683
+ "pv_power_forecast": [0, 70, 141.22, 246.18, 513.5, 753.27, 1049.89, 1797.93, 1697.3, 3078.93],
684
+ "prediction_horizon":10,
685
+ "soc_init":0.5,
686
+ "soc_final":0.6,
687
+ "operating_hours_of_each_deferrable_load":[1,3],
688
+ "start_timesteps_of_each_deferrable_load":[0,3],
689
+ "end_timesteps_of_each_deferrable_load":[0,6]
690
+ }
691
+ ```
692
+
669
693
  ## A machine learning forecaster
670
694
 
671
695
  Starting in v0.4.0 a new machine learning forecaster class was introduced.
@@ -680,7 +704,7 @@ Pull requests are very much accepted on this project. For development, you can f
680
704
 
681
705
  Some problems may arise from solver-related issues in the Pulp package. It was found that for arm64 architectures (ie. Raspberry Pi4, 64 bits) the default solver is not available. A workaround is to use another solver. The `glpk` solver is an option.
682
706
 
683
- This can be controlled in the configuration file with parameters `lp_solver` and `lp_solver_path`. The options for `lp_solver` are: 'PULP_CBC_CMD', 'GLPK_CMD' and 'COIN_CMD'. If using 'COIN_CMD' as the solver you will need to provide the correct path to this solver in parameter `lp_solver_path`, ex: '/usr/bin/cbc'.
707
+ This can be controlled in the configuration file with parameters `lp_solver` and `lp_solver_path`. The options for `lp_solver` are: 'PULP_CBC_CMD', 'GLPK_CMD', 'HiGHS', and 'COIN_CMD'. If using 'COIN_CMD' as the solver you will need to provide the correct path to this solver in parameter `lp_solver_path`, ex: '/usr/bin/cbc'.
684
708
 
685
709
 
686
710
  ## License
@@ -1,16 +1,16 @@
1
1
  emhass/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- emhass/command_line.py,sha256=sJIpI11BAJi1Ao7ck4B_zbr6dD1V7VY3S6UmxqRFRcE,75857
3
- emhass/forecast.py,sha256=lEBKnzJSxpbAYQ-OiW_qnKTTj8cl95yk4Ggkyk_rpyo,83892
4
- emhass/machine_learning_forecaster.py,sha256=zr5BczdsvoUCKpxV3XL4Ts-IWcS6zuhXYdeQwBD5gE8,16282
2
+ emhass/command_line.py,sha256=XrD4uOONtaCDUQ3TMjJwDDIuOjyO_K8BZH3r_TBN1Eg,76048
3
+ emhass/forecast.py,sha256=hLau1KjvwHM6jRQtWyhFLMf3fehdHIQlWG7A_inToKI,85951
4
+ emhass/machine_learning_forecaster.py,sha256=tRC9P94-gMAPJsxWilT_jeful1Xmcev4PfMmuGFdzIk,16258
5
5
  emhass/machine_learning_regressor.py,sha256=Ih1q-vUWHWbGFxv9F12omwgyMRp-iaMU_m-yploVbyU,9532
6
- emhass/optimization.py,sha256=_uKG7QKVtdpbv4U4Y_R9xLdWR17lB4YQWAuuONqk8ng,67947
7
- emhass/retrieve_hass.py,sha256=KZQ6esRYq0Typp7yyZUwEdYKHFPqDmnsuVxuDhBdWc0,29444
8
- emhass/utils.py,sha256=UysLZJ-TzsWvkNyihXkPwcf_qGUpxN_HfnAVcb0KWkY,73889
9
- emhass/web_server.py,sha256=xOgM3lVwXAN6Ctoi5in21ImeSvx6-wDNtgYZqLQN01I,29153
10
- emhass/data/associations.csv,sha256=pFbL3LosAhWc4SmHWZGQa-2ykwmFAqhV1nmd4hTYNKU,4144
6
+ emhass/optimization.py,sha256=iusC3BBbCHDDPiD-QzOq27mv7nernCtuh3kRTwHU0Jw,73793
7
+ emhass/retrieve_hass.py,sha256=FPWK43NOD8Hq-oLbrJ_M1Sh8h5rOLwfkL1zpRWVBLoE,29593
8
+ emhass/utils.py,sha256=95IjexSlUQbzkovIUQizzHzXdxQGdYGjeWZy8rwKAvA,75940
9
+ emhass/web_server.py,sha256=fwdGHPPu3_wJ3bqrQVctK357iW4Gz57-mVSfIluRs88,28075
10
+ emhass/data/associations.csv,sha256=BIQNjKpr-QC3cMJIRzJ7F2eMGNVubDe0544dYWMIJw4,4418
11
11
  emhass/data/cec_inverters.pbz2,sha256=ca-dO6sv38_FI2w_6fkAIzcrEqzFBkG8MHKNGbCZPow,189400
12
12
  emhass/data/cec_modules.pbz2,sha256=Y639TNqhaIxh2Ec7AUPxy8k4lQugY5rURVVVexj0fMU,1885444
13
- emhass/data/config_defaults.json,sha256=J1hgdA6D9mliPABbSaGqdO4rG3Xr5-9nI-jIWqrRylA,3128
13
+ emhass/data/config_defaults.json,sha256=9GUT1zjEIMxijbLXRjO4_VAoi_x0tsq2pczAQoHuwoI,3287
14
14
  emhass/img/emhass_icon.png,sha256=Kyx6hXQ1huJLHAq2CaBfjYXR25H9j99PSWHI0lShkaQ,19030
15
15
  emhass/static/advanced.html,sha256=gAhsd14elDwh1Ts4lf9wn_ZkczzzObq5qOimi_la3Ic,2067
16
16
  emhass/static/basic.html,sha256=ro2WwWgJyoUhqx_nJFzKCEG8FA8863vSHLmrjGYcEgs,677
@@ -18,15 +18,15 @@ emhass/static/configuration_list.html,sha256=i4v83RVduWjdjkjPhA74e-j8NSUpFzqMGU3
18
18
  emhass/static/configuration_script.js,sha256=Ek0Ry1Ae6ZGMl28mYxno6bPTwY4rK7AHcL58C6T6qUo,31727
19
19
  emhass/static/script.js,sha256=-JYS8fHjchrMi1hYYKMd9p7vZvPcnYiY8NNuRC99fJM,16323
20
20
  emhass/static/style.css,sha256=a_8YlGubn1zoF5RTLJ_Qkrb8tAjUY9p7oAKxhCvJY2s,19288
21
- emhass/static/data/param_definitions.json,sha256=GAXsnpdg9F5zbl7McdUoiiAfjwjRgQ24sYhovEv9sEI,21692
21
+ emhass/static/data/param_definitions.json,sha256=aKqXH4Cd3cucAIG2gs2AADNDsTxipDHY0SZ9lxRAqHQ,23330
22
22
  emhass/static/img/emhass_icon.png,sha256=Kyx6hXQ1huJLHAq2CaBfjYXR25H9j99PSWHI0lShkaQ,19030
23
23
  emhass/static/img/emhass_logo_short.svg,sha256=yzMcqtBRCV8rH84-MwnigZh45_f9Eoqwho9P8nCodJA,66736
24
24
  emhass/static/img/feather-sprite.svg,sha256=VHjMJQg88wXa9CaeYrKGhNtyK0xdd47zCqwSIa-hxo8,60319
25
25
  emhass/templates/configuration.html,sha256=M-_L__juYzcdGDaryGrz6LG2mguW2f1Sx6k01YfG7Dc,2885
26
26
  emhass/templates/index.html,sha256=1V44c0yyliu_z8inl0K-zmmmkhQumH3Bqk8Jj1YJPzY,3076
27
27
  emhass/templates/template.html,sha256=TkGgMecQEbFUZA4ymPwMUzNjKHsENvCgroUWbPt7G4Y,158
28
- emhass-0.13.2.dist-info/METADATA,sha256=iJQCKI1fRrYBS4VFqomje9VAXF_-tZ6Fy09kCa2MFno,51493
29
- emhass-0.13.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- emhass-0.13.2.dist-info/entry_points.txt,sha256=6Bp1NFOGNv_fSTxYl1ke3K3h3aqAcBxI-bgq5yq-i1M,52
31
- emhass-0.13.2.dist-info/licenses/LICENSE,sha256=1X3-S1yvOCBDBeox1aK3dq00m7dA8NDtcPrpKPISzbE,1077
32
- emhass-0.13.2.dist-info/RECORD,,
28
+ emhass-0.13.4.dist-info/METADATA,sha256=HdwXErVla8BAOCAUcAb_Y3KBTzv6RnpP3sFPGu4FupE,52124
29
+ emhass-0.13.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ emhass-0.13.4.dist-info/entry_points.txt,sha256=6Bp1NFOGNv_fSTxYl1ke3K3h3aqAcBxI-bgq5yq-i1M,52
31
+ emhass-0.13.4.dist-info/licenses/LICENSE,sha256=1X3-S1yvOCBDBeox1aK3dq00m7dA8NDtcPrpKPISzbE,1077
32
+ emhass-0.13.4.dist-info/RECORD,,