-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Planning for heating/cooling systems #278
Comments
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. |
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. |
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? |
On Fri, 10 May 2024 at 15:07, Mark Purcell ***@***.***> wrote:
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
412518624_10161048683055281_976229614539365053_n.jpg (view on web)
<https://github.com/davidusb-geek/emhass/assets/79175134/4538e424-e7ab-4c3b-88b4-782a89aaedc9>
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.
I see, I’ve just been ignoring total_hours and using “must have predicted
temperature > X” as the constraint.
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?
Nothing so complex. I’m just turning the air conditioner on with a set
point of 24 when the plan calls for heating, and turning it off when the
planned use is 0 and I’m not home or upstairs.
This has so far been good enough for my use case of pre heating the house
ahead of any price spikes.
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?
This is a pain, I ended up including it in the overall automation
https://gist.github.com/werdnum/8d15a5dbcdf5c6e535bdcffb9888a7b5
|
Hi. Nice feature again!
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 |
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 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.
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. |
There are certainly better ways of implementing this. Your solution might be an option.
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
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. |
Can this be helpful to find the thermal model for your house? |
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 |
Yeah of course, I don't mean to "lick the cookie" and delay you. I have
some fixes locally, which I'll try to push today. It's close, I just
haven't got around to unit tests. I've been using it locally for a month or
two.
I was also looking into penalizing rather than constraining - I'm finding
locally that I get too many "infeasible" results from cases where the
thermal model thinks it's impossible to meet the thermal constraint.
— Andrew Garrett
…On Sun, 7 Jul 2024 at 07:40, David ***@***.***> wrote:
Hi @werdnum <https://github.com/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
—
Reply to this email directly, view it on GitHub
<#278 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACCFXR5TTW3AZQNEIQUJELZLBP47AVCNFSM6AAAAABHP5ACDSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJRHE3TOMBWGY>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
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 |
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). |
How are you configuring this?
This means that you have 3 deferrable loads and only the third one is a thermal load with those configuration options? |
Ok, just answering myself for this part, I just saw in your first post that these are defined in the automation template |
On Mon, 8 Jul 2024 at 06:03, David ***@***.***> wrote:
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?
Correct
I'm trying to understand the concept of overshoot_temperature.
Basically it's a safeguard max temperature. I’m just trying to make sure
the system doesn’t try to heat the house to 30°, the thermal parameters are
only really valid for a certain temperature range and also generally it
seems like a bad idea.
|
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) |
Those unit tests will be welcomed when you have the time. |
This model was released, the documentation is here: https://emhass.readthedocs.io/en/latest/thermal_model.html. |
Thanks so much for polishing this up, sorry that I wasn't able to be more
helpful. So glad this has made it into mainline!
— Andrew Garrett
…On Sun, 14 Jul 2024 at 09:25, David ***@***.***> wrote:
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
—
Reply to this email directly, view it on GitHub
<#278 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACCFXUGWHYNAOUOGQDB54TZMGZOJAVCNFSM6AAAAABHP5ACDSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRXGEZTMMJXGI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
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. |
Heating/cooling systems have different dynamics, as 'integrating processes' (by analogy to the PID model concept) where you can pre-heat or pre-cool to ride out periods of higher demand.
It would be neat to have some way of doing this with EMHASS.
I have something like this implemented and working in a branch, which I want to clean up before sending a
CLPR.The text was updated successfully, but these errors were encountered: