Comments (21)
from emhass.
oke, I would like to help to build the thermal model, I have a bit of experience with machine learning and python, but have no clue how to implement this in a program like emhass. This is the model I have so far with a mae of .11 over 72 hours and a mape of 0.005 for my own house.
from emhass.
Hi @werdnum, do you mind if I try to implement your thermal modeling proposition from your branch in the following EMHASS release? I'm planning on doing this very soon, so I can propose a PR to implement this using your branch changes and if you are willing to take a look and comment that PR it would be great. What do you think? A simple linear thermal model like this seems perfect for me
from emhass.
Great news and quite a bit of interest, can you describe how your model is working and what parameters are required to be set.
I can see immediate application with my space heating and cooling (HVAC) systems. But also future application with my domestic and pool hot water heat pump systems.
from emhass.
I am adding a new constraint to the linear model.
The temperature at time T is modelled as (temperature at time T-1) - (cooling_constant * (indoor_temp - outdoor_temp)) + (heating_is_on * heating_constant).
You pass in the start temperature, the desired temperature per timestep, and the forecast outdoor temperature per timestep.
I did some number crunching in my own home and determined values of 0.1 degrees per hour per degree for the cooling constant and 5.5 degrees per hour for the heating constant. That is, if I leave the heating off, the house cools down by 0.1 degrees per hour for every degree that the house is cooler than the ambient temperature outside. Similarly, if the heating is on, the house warms up by approximately one degree per hour.
Feel free to take a look at my branch if you want to find out more.
My configuration is as follows:
def_load_config:
- {}
- {}
- thermal_config:
heating_rate: 5.0
cooling_constant: 0.1
overshoot_temperature: 24.0
And in Home Assistant:
rest_command:
emhass_forecast:
url: http://emhass.homeassistant.svc.cluster.local:5000/action/naive-mpc-optim
method: post
timeout: 300
payload: |
{% macro time_to_timestep(time) -%}
{{ (((today_at(time) - now()) / timedelta(minutes=30)) | round(0, 'ceiling')) % 48 }}
{%- endmacro -%}
{%- set horizon = (state_attr('sensor.electricity_price_forecast', 'forecasts')|length) -%}
{%- set heated_intervals = [[time_to_timestep("06:30")|int, time_to_timestep("07:30")|int], [time_to_timestep("17:30")|int, time_to_timestep("23:00")|int]] -%}
{
"prediction_horizon": {{ horizon }},
"def_total_hours": [
{{ max(0, float(states("input_number.pool_pump_required_run_time")) - float(states("sensor.pool_pump_run_time"))) | float }},
{{ max(0, (states("input_number.car_target_soc")|int) - (states("sensor.car_battery_soc")|int)) * 64 / 100.0 / 7 | float }},
0
],
"def_end_timestep": [
{{ time_to_timestep("23:59") }},
{{ min(time_to_timestep("07:30"), time_to_timestep("16:30") ) }},
0
],
"load_cost_forecast":
{{
(
(
[states('sensor.general_price')|float(0)]
+ state_attr('sensor.electricity_price_forecast', 'forecasts')
|map(attribute='per_kwh')
|list
)[:horizon]
)
}},
"prod_price_forecast":
{{
(
(
[state_attr('sensor.general_price', 'spot_per_kwh')|float(0)]
+ state_attr('sensor.electricity_price_forecast', 'forecasts')
|map(attribute='spot_per_kwh')
|list
)[:horizon]
)
}},
"heater_start_temperatures": [0, 0, {{state_attr("climate.living", "current_temperature")}}],
"heater_desired_temperatures": [[], [], [{% set comma = joiner(", ") %}
{%- for i in range(horizon) -%}
{%- set timestep = i -%}
{{comma()}}
{% for interval in heated_intervals if timestep >= interval[0] and timestep <= interval[1] -%}
21
{%- else -%}
0
{%- endfor -%}
{% endfor %}]],
"pv_power_forecast": [
{% set comma = joiner(", ") -%}
{%- for _ in range(horizon) %}{{comma()}}0{% endfor %}
],
"outdoor_temperature_forecast": [
{%- set comma = joiner(", ") -%}
{%- for fc in weather_forecasts['weather.openweathermap'].forecast if (fc.datetime|as_datetime) > now() and (fc.datetime|as_datetime) - now() < timedelta(hours=24) -%}
{%- if loop.index0 * 2 < horizon -%}
{{comma()}}{{fc.temperature}}
{%- if loop.index0 * 2 + 1 < horizon -%}
{{comma()}}{{fc.temperature}}
{%- endif -%}
{%- endif -%}
{%- endfor %}]
}
.. but obviously this has a lot that's specific to my setup.
from emhass.
Nice,
I have done some similar calculations for my household and have a cooling factor of 1500 W/ deg C, but I should be able to convert to your schema. I also had a template sensor to calculate the expected Power requirements profile per timestep for my HVAC, but getting it included as a constraint was well beyond my abilities, which you seem to have resolved. https://community.home-assistant.io/t/running-devices-when-energy-is-cheaper-and-greener/380011/26?u=markpurcell
I have also been adjusting p_nom depending on the desired set point and total_hours based on the number of forecast temps above the setpoint.
A couple of questions:
Does your HVAC automation then change the setpoint to ramp up and ramp down, or are you controlling power consumption in a different fashion?
Is your weather_forecasts['weather.openweathermap'].forecast a local macro, I still haven't made the shift since they removed forecasts as attributes from the weather entities?
from emhass.
from emhass.
Hi. Nice feature again!
I always thought that a simple linear model would be more that enough for our use cases, but never took the time to actually implement this.
Please go ahead with the PR and let's add this.
Same comments as in #261:
- Hard to find a trade-off between the number of configurable parameters and then the increased complexity to setup things when starting with EMHASS.
- Don't forget to add some testing lines, to make this more easy to maintain and evolve in the future.
Another side comment, I saw in your branch that you add the possibility to pass the outdoor temperature, this is good and a needed option, but there is also the option to use the readily available outdoor temperature when using the scrapper
weather forecast method, the outdoor temperature is there in the DataFrame as temp_air
column name.
from emhass.
Thanks, @davidusb-geek.
One thing I haven't figured out how to implement yet is that I'd like to export the temperature forecast to HA as well - this would help setting the setpoint in automations, to keep the heating/cooling usage in sync with what EMHASS is planning.
I notice that post_data
only wants the single data series (planned electricity usage), but I'd like to pass along the predicted temperature based on the plan as an attribute:
emhass/src/emhass/retrieve_hass.py
Line 321 in 6abb8a1
Wondering if your preference is to pass them along in the same dataframe, or as a separate parameter.
Relatedly, I am having a bit of trouble making heads or tails of this code
I'm wondering if this would be a simpler way of writing that method:
@staticmethod
def get_attr_data_dict(
data_df: pd.DataFrame,
idx: int,
entity_id: str,
unit_of_measurement: str,
friendly_name: str,
list_name: str,
state: float,
) -> dict:
list_df = data_df.copy().loc[data_df.index[idx] :]
forecast_list = []
for ts, row in list_df.itertuples():
datum = {}
datum["date"] = ts.isoformat()
datum[entity_id.split("sensor.")[1]] = np.round(row[entity_id], 2)
forecast_list.append(datum)
data = {
"state": "{:.2f}".format(state),
"attributes": {
"unit_of_measurement": unit_of_measurement,
"friendly_name": friendly_name,
list_name: forecast_list,
},
}
return data
... if I do it that way, then it becomes much more straightforward to pass along that 'ancillary' data like predicted temperature.
Hard to find a trade-off between the number of configurable parameters and then the increased complexity to setup things when starting with EMHASS.
It's your call of course, but my idea here was to move the configuration format away from a bunch of parallel lists, which can be hard to manage, to a single list of dicts (in fact, you can see this in my overall design, because it was becoming unmanageable to put in so many parallel lists for all the different thermal configuration parameters).
Backwards compatibility is definitely a concern, but you could add in some logic to 'copy' the old-style parallel lists into the list of dicts so people don't have things break underneath them.
Overall my problem in terms of ease of use is that the example configuration has so many different mandatory fields that it's hard to keep track of everything (c.f. #262).
I don't want to inundate you with ideas/suggestions/questions/requests, but EMHASS is the first truly 'magical' home automation I've put together and I'd be excited to work with you on some of the ideas and pain points I've encountered.
from emhass.
... if I do it that way, then it becomes much more straightforward to pass along that 'ancillary' data like predicted temperature.
There are certainly better ways of implementing this. Your solution might be an option.
If its more efficient, useful for what you want to achieve and even more readable then go ahead and update that. No problem for me. Just be careful to modify accordingly where this is used, most notable in command_line.py
.
And just test your modification using the unit testing platform.
Overall my problem in terms of ease of use is that the example configuration has so many different mandatory fields that it's hard to keep track of everything (c.f. #262).
We recently decided to go ahead with a single configuration file in the form of the json file obtained when using the add-on: the options.json
.
Those parallel list were inherited from the initial choice of using the yaml format.
I don't want to inundate you with ideas/suggestions/questions/requests, but EMHASS is the first truly 'magical' home automation I've put together and I'd be excited to work with you on some of the ideas and pain points I've encountered.
Like the suggestion about simplifying the configuration I am always open to new ideas to improve all this, make it more efficient, easy to configure and setup and add new features. All contributions are welcomed, given a prior discussion like we had here for heating/cooling systems.
from emhass.
Can this be helpful to find the thermal model for your house?
https://github.com/czagoni/darkgreybox
from emhass.
Ok looking forward for your fixes. I'll take a look but at first glance it seems that you are not ignoring the constraint for def_total_hours[k]*self.optim_conf['P_deferrable_nom'][k]
when the deferrable load has a thermal config. So this may cause un compatible unfeasible constraints. Of course converting this to penalties could be a workaround.
from emhass.
Ok looking forward for your fixes. I'll take a look but at first glance it seems that you are not ignoring the constraint for
def_total_hours[k]*self.optim_conf['P_deferrable_nom'][k]
when the deferrable load has a thermal config. So this may cause un compatible unfeasible constraints. Of course converting this to penalties could be a workaround.
I think I tried to make it a >= or ignore it, I forget which one I did.
I think my eventual vision would be that you have a range of options for your 'demand' side (i.e. whatever it is that tells the model not to just leave the load off all the time). A specific number of hours is one option, a constraint is another, and a third option that I was thinking about for EV charging is a benchmark price (i.e. my average cost to charge my EV is 27c/kWh, so run the charger whenever electricity is cheaper than that).
from emhass.
How are you configuring this?
In your original post you said:
def_load_config:
- {}
- {}
- thermal_config:
heating_rate: 5.0
cooling_constant: 0.1
overshoot_temperature: 24.0
This means that you have 3 deferrable loads and only the third one is a thermal load with those configuration options?
I'm trying to understand the concept of overshoot_temperature
.
Also there are other missing paramters used in the code start_temperature
, desired_temperature
, etc., you are setting those up directly at runtime?
from emhass.
Also there are other missing paramters used in the code start_temperature, desired_temperature, etc., you are setting those up directly at runtime?
Ok, just answering myself for this part, I just saw in your first post that these are defined in the automation template
from emhass.
from emhass.
I pushed my bugfixes to my branch - I think it was a merge conflict issue in the end.
Would still like to throw together some unit tests but haven't had the chance to really poke at this in some time (little kids, school holidays and so on)
from emhass.
Those unit tests will be welcomed when you have the time.
I have tested this and found some inconsistencies when defining the constraints.
The way that I made it work properly was as it is shown here in this banch: https://github.com/davidusb-geek/emhass/tree/davidusb-geek/dev/thermal_model
from emhass.
This model was released, the documentation is here: https://emhass.readthedocs.io/en/latest/thermal_model.html.
Feel free to test and open new issues if having problems implementing this.
I have tested and it works fine. I also added a unittest.
Closing this as completed for now
from emhass.
from emhass.
Andrew, David, thank you both for this addition to EMHASS, this is providing a major functionality increase which has very broad application.
I might setup a Thermal Setup HOWTO in the Discussions so we can document our configurations and get a few use cases that can then be transferred to the documentation as configuration isn't working smoothly for me.
from emhass.
Related Issues (20)
- Data posted via home assistant is different to what appears in the EMHASS logs HOT 6
- Infeasible result with 0.10.1, optimal with 0.9.1 HOT 4
- Feature request: Provide p_hybrid_inverter as a sensor HOT 2
- Sensor unit: Unit is missing for 'Total cost function value' HOT 1
- load_cast_forecast nordpool fails, HOT 7
- pv_forecast is not aligning with JSON input for naive-mpc-optim command HOT 4
- Unable to connect to home assistant HOT 2
- Warning: deprecated lags_grid argument HOT 1
- Feature Request: Pd_max/Pc_max as runtime parameters HOT 3
- 400 error on call HOT 1
- Feature Request: Support solcast/Forecast.Solar
- Feature Request: Support dynamic electricity prices HOT 4
- Custom machine learning forecast model predict HOT 1
- Solcast shows values at night HOT 4
- Optimisation at times exceeds p_nom for deferrable loads HOT 1
- Cannot install add-on HOT 4
- Feature request: minimum continous runtime for each deferrable load HOT 1
- Same as 328 - missing image update to0.10.6 HOT 12
- sometimes error since 0.10.6 MPC HOT 1
- Feature Request: Cost/profit comparison
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from emhass.