Comments (11)
Yes, I don't see any problem with doing this. I'll just need to look how to do it but I guess that it can't be hard to pass a list of values as an attribute to a sensor. I'll look into that
from emhass.
Hi, I just published a new version where this was added. Test it to see if it fits your needs.
from emhass.
I tried this block of code:
forecast_list = copy.deepcopy(data_df).loc[data_df.index[idx]:].reset_index()
forecast_list.columns = ['timestamps', entity_id]
ts_list = [str(i) for i in forecast_list['timestamps'].tolist()]
vals_list = [np.round(i) for i in forecast_list[entity_id].tolist()]
forecast_list = [{'timestamp': ts_list[i], entity_id.split('sensor.')[1]: vals_list[i]} for i in range(len(ts_list))]
But this is the result, not quite what a typical forecast sensor shows:
from emhass.
Ok just found how they are doing it in Amber: https://github.com/home-assistant/core/blob/dev/homeassistant/components/amberelectric/sensor.py
I will update that for the next release...
from emhass.
Great, I can see the values there now, so can do something with them.
I would be good if you can get into a similar structure as amber integration as that is quite easy to work with using map(attribute):
post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"prod_price_forecast\":{{(
(state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list))
}},\"load_cost_forecast\":{{(
(state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list))
}},\"prediction_horizon\":{{(
(state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length))
}},\"soc_init\":{{states('sensor.powerwall_charge')|float(0)/100}},\"soc_final\":0.01,\"def_total_hours\":[4,5,3,1]}' http://localhost:5000/action/naive-mpc-optim"
post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"prod_price_forecast\":[0.28, 0.33, 0.37, 0.32, 0.31, 0.31, 0.28, 0.27, 0.37, 0.46, 0.46, 0.46, 0.46, 0.46, 0.33, 0.33, 0.46, 0.46, 0.46, 0.37, 0.33, 0.33, 0.32, 0.3, 0.3, 0.31, 0.46, 0.33, 0.31, 0.3, 0.31, 0.3, 0.31, 0.3, 0.3, 0.26, 0.26, 0.26],\"load_cost_forecast\":[0.4, 0.45, 0.51, 0.45, 0.44, 0.44, 0.4, 0.4, 0.51, 0.61, 0.61, 0.61, 0.61, 0.61, 0.46, 0.46, 0.6, 0.61, 0.61, 0.5, 0.46, 0.45, 0.45, 0.43, 0.43, 0.44, 0.61, 0.46, 0.44, 0.42, 0.44, 0.42, 0.43, 0.43, 0.42, 0.38, 0.38, 0.38],\"prediction_horizon\":38,\"soc_init\":0.85,\"soc_final\":0.01,\"def_total_hours\":[4,5,3,1]}' http://localhost:5000/action/naive-mpc-optim"
from emhass.
Yes I will update this for the next release. That's a nice implementation of the shell command using templates and mapping the attributes. Do you mind if I borrow your code to put it as an example in the docs? It could help people with similar integrations.
A side comment on the values that you're passing for soc_final
and def_total_hours
. For the SOC if you do this at each iteration of the MPC it will always look to empty the battery. I think that you may lose optimality doing this. An idea could be to run the dayahead optimization just once at the beginning of a new day and set the battery optimal power and SOC trajectories for the day. Then launch the MPC iteratively at a relative high frequency (10min?) and fix that final SOC to match the optimal trajectory for whole day computed with the dayahead optimization. The MPC will still let you optimize your system on short term uncertainties, but you will keep an optimal goal for your complete day. As for the def_total_hours
what I'm doing is that I defined sensors for my deferrable loads that give me the current time in hours that those loads have done on the current day. So that when I perform the MPC optimization I'm passing the difference of the daily goal and the total hours ran for each deferrable load. Be careful because it doesn't make much sense to keep def_total_hours
at fixed values as shown in your code snippet.
Below is the code I use to compute running hours sensor for one of my deferrable loads, the water heater:
- platform: history_stats
name: Water Heater running today
entity_id: sensor.water_heater_status
state: 'Running'
type: time
start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
end: '{{ now() }}'
- platform: template
sensors:
water_heater_status:
value_template: '{% if is_state("switch.water_heater_switch", "on") %}Running{% else %}Stopped{% endif %}'
friendly_name: 'Water Heater Status'
icon_template: mdi:play-pause
water_heater_time_on:
value_template: '{{ states("sensor.water_heater_running_today") | float }}'
friendly_name: 'Water Heater Hours Running'
icon_template: mdi:timer
from emhass.
Documentation for examples is going to be very important. I have already had a few requests to publish my configuration as others are wanting to utilise the benefits of emhass. Things are still moving quite quickly with your development so maybe the GitHub wiki could be a good place to document different configurations.
I did contemplate what values to use for soc_final as it very much drives behaviour at the end of the cycle. If it is too high it will artificially charge or as you say too low and it will fully discharge. My observations are that it only really effects the final set of time periods in an optimisation.
I chose the minimum for soc_final as a fully discharged battery at the end of the cycle does represent the maximum achievable total value of the cost function. Additionally as I'm running MPC optimisation every 5 minutes the actual effects of the soc_final are never actually realised in the posted values for the controlling functions, for my forecasts this is always 30-48 time slots in the future.
I understand this makes the actual run hours not deterministic and have been using this sliding window approach both with emhass and my prior rules based approach. I have observed that if you have a bizzare set of forecasts that continually increase or decrease between optimisations you can end up running for more or less than the desired hours. Given some of the other estimations in the system if I get an extra or hour or less for pool pump or EV charging it isn't a disaster.
I also have some working formula for the run time if deferrable loads, but I wanted to get the basics running first.
amber_lowest_cost:
friendly_name: "Lowest Cost 90 mins"
unit_of_measurement: $/kWh
value_template: "{{ (state_attr('sensor.amber_general_forecast', 'forecasts') | map(attribute='per_kwh')|list|sort).4}}"
amber_highest_price:
friendly_name: "Highest Price 90 minutes"
unit_of_measurement: $/kWh
value_template: "{{ (state_attr('sensor.amber_feed_in_forecast', 'forecasts') | map(attribute='per_kwh')|list|sort(reverse=true)).4}}"
ev_charging_30mins:
value_template : "{{(((90-states('sensor.duka_battery_sensor')|int(0)) / 100 * 8* 2)|int(0))}}"
from emhass.
Yes thanks for your input. I need to work the documentation with better explanation, graphics and more practical examples. Yes the wiki can be an option as well as readthedocs as it is published automatically ;-)
I see the thing with your MPC implementation is that you're using a prediction_horizon
that is always the size of your available forecast list. So in this case it makes sense to fix those values and the whole is valid on a sliding window. But this is as doing a dayahead optimization repeatedly every 5mins. You can still use it like this I think is totally valid, but the main goal of the MPC is to tame variability and uncertainties at short frequency and with shorter prediction_horizon
. This may give you the opportunity to reduced your optimization time step and have a gain in precision. This could be interesting specially for the load consumption forecast. For now this forecast is just a naive persistence approach in emhass. The goal is to improve this in the near future to provide better load consumption forecast. Then the MPC could use more precise short term load consumption forecast to optimize at higher frequencies. Again I need to work the docs to explain all this... It is in progress...
from emhass.
Lots of possibilities.
I am envisioning a MPC optimisation called every 5 minutes (or less) with the first method_ts_round with actual current values for PV, load, buy & sell and forecasts for dayahead optimisation. timestep stays at 30 minutes as I cannot get finer resolution for my buy/ sell.
The desired effect is if the sun goes behind a big cloud, load jumps up or down unexpectedly or price/ cost change radically in the 5 minutes. It maybe optimal to change battery or deferrable load activity. Of course you don't want to switch these large loads to quickly otherwise relays and the like will burn out. But it may make sense to switch loads inside the 30 minute window based off actual measured values.
Similarly for variable (semi continuous) loads, my battery will match excess solar curves for charging and I have scripts to match EV charging to excess solar. But for those to be > 85% effective you need minute or second resolution. My battery gives me second resolution to match solar/ load to +/- 5 kW and my EV charging gives me minute resolution for 0-12 kW. So the big deferrable loads (water heating, HVAC, pool pump) only need to be in the ball park -5 kW to +17 kW to still be optimal, as the batteries can be the shock absorber for external variations.
from emhass.
Nice, I can visualize this very nicely within lovelace and it updates in 'real' time.
type: custom:apexcharts-card
experimental:
color_threshold: true
graph_span: 24h
span:
start: minute
header:
show: true
title: EMHASS Forecasts
show_states: false
colorize_states: true
series:
- entity: sensor.p_pv_forecast
name: pv
data_generator: |
return entity.attributes.forecasts.map((entry) => {
return [new Date(entry.date), entry.p_pv_forecast];
});
- entity: sensor.p_batt_forecast
name: p_batt
data_generator: |
return entity.attributes.forecasts.map((entry) => {
return [new Date(entry.date), entry.p_batt_forecast];
});
- entity: sensor.p_load_forecast
name: p_load
data_generator: |
return entity.attributes.forecasts.map((entry) => {
return [new Date(entry.date), entry.p_load_forecast];
});
- entity: sensor.p_deferrable0
name: p_deferable0
data_generator: |
return entity.attributes.deferrables_schedule.map((entry) => {
return [new Date(entry.date), entry.p_deferrable0];
});
- entity: sensor.p_deferrable1
name: p_deferable1
data_generator: |
return entity.attributes.deferrables_schedule.map((entry) => {
return [new Date(entry.date), entry.p_deferrable1];
});
yaxis:
- apex_config:
forceNiceScale: true
from emhass.
Nice, very cool visualizations...
from emhass.
Related Issues (20)
- Feature request: Add a published parameter with the status of latest optimization HOT 2
- Feature request, use cost of ware on battery in optimization HOT 3
- Controlling a heat pump HOT 4
- Initial and target SOC HOT 2
- not a valid add-on repository HOT 2
- Question - how to install latest version into Home Assistant? HOT 2
- Error running forecast-model-tune after updating to 0.4.2 HOT 3
- Feature Request: Time windows for deferrable loads HOT 3
- CPU and memory usage increases when solver cannot find a solution HOT 21
- If too few days are available from HA recorder, data fetch fails HOT 1
- Timezone issue due Winter/Summer time switch HOT 8
- Dynamic current control loop for inverter heat pump HOT 1
- Timezone not respected when using mlforecaster HOT 7
- Feature Request: Add possibility to add minimum power in P_deferrable_nom HOT 1
- BUG: def_total_hours: 24 and set_def_constant: 1 cause tons on power on 1 hour HOT 2
- timeslots round to nearest 30 minute HOT 2
- Wrong objective formula in case of "grid cost" cost function HOT 1
- Error logger - server not responding HOT 5
- 0.5.2 unaccepted optimisation behaviour
- Type of self-consumption optimization is always bigm, never maxmin HOT 2
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.