EMHASS: An Energy Management for Home Assistant

I made the the no var sensor today. Looks like it’s recording, but maybe not enough information yet?

Correct, you need a minimum of 48 hours.

Btw, it’s negative. That is not what I would expect for Load.

I think that it’s because different sensors are refreshing in different times probably. I have two Shelly EM (main power and heat pump power) and one shelly plug for EV charger. And then template:

  - platform: template
    sensors:
      power_load_no_var_loads:
        friendly_name: "Power Load No Var Loads"
        unit_of_measurement: "W" 
        value_template: >-
          {{ (states('sensor.total_main_power') | float - 
              states('sensor.heat_pump_power') | float - 
              states('sensor.ev_charger_power_3') | float) | round(2) }}
        availability_template: >-
          {{
            is_number(states('sensor.total_main_power')) and
            is_number(states('sensor.heat_pump_power')) and
            is_number(states('sensor.ev_charger_power_3'))
          }}

And during summer the main power will be negative, when PV power is greater than own usage. Negative number means that i will sell back to grid,

I’m also using dynamic prices from entso-e. Those prices are published around 13:00 hours.
What time do you publish your forecast?

alias: EMHASS Entso-e forcast optimization
description: ""
trigger:
  - platform: time
    at: "14:55:00"
condition: []
action:
  - service: shell_command.post_entsoe_forcast
    data: {}

Yes, but the sensor should exclude PV. It represents your load excluding deferrables

Every hour with a dynamic prediction horizon depending on the available observations

trigger_forecast: "curl -i -H \"Content-Type: application/json\" -X POST -d '{
  \"load_cost_forecast\":{{((state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list))[now().hour:][:24] }},
  \"prod_price_forecast\":{{((state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list))[now().hour:][:24] }},
  \"prediction_horizon\":{{min(24, ((state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_today') | map(attribute='price') | list  + state_attr('sensor.entso_e_api_average_electricity_price_today', 'prices_tomorrow') | map(attribute='price') | list)[now().hour:][:24]|list|length))}},
  \"soc_init\":{{((states('sensor.growatt_growatt_battery_soc') | float(0))) / 100 }},
  \"soc_final\":0.10,
  \"def_total_hours\":[2],
  \"pv_power_forecast\":{{([states('sensor.solcast_pv_forecast_power_now')|int(0)] + state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list + state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list)| tojson}}
  }' http://localhost:5000/action/naive-mpc-optim"
1 Like

Load is always positive or zero and this load should be minus your deferrable loads that EMHASS is controlling but still always positive or 0 but rarely 0.

You need to also take your produced PV power into account. This is my template sensor for the household power usage:

    - name: "Household power consumption"
      unique_id: "household_power_consumption"
      state: "{{ [(states('sensor.pv_ac_power')|int(0) + states('sensor.power_consumption')|float(0)*1000 - states('sensor.power_production')|float(0)*1000)|int, 0]|max }}"
      device_class: power
      unit_of_measurement: W
      state_class: measurement

I also had the issue with it going negative sometimes because of not measuring at the same time, that’s why I clamp it to 0.

Also the PV power measurement is not completely accurate (too low), which could also cause the calculation to go negative.

Thanks @Kars and @rcruikshank ! I) somehow missed the fact that PC is deferrable as well, and setting the minimum of 0 for the template that calculates it makes sense.

Came up with this template sensor for household power consumption:

sensor:
  - platform: template
    sensors:
      household_total_power_consumption:
        friendly_name: "Household Total Power Consumption"
        unit_of_measurement: "W"
        value_template: >-
          {% set main_power = states('sensor.total_main_power') | float %}
          {% set inverter_power = states('sensor.inverter_active_power') | float %}
          {% if main_power >= 0 %}
            {% set total_power = main_power + inverter_power %}
          {% else %}
            {% set total_power = inverter_power - main_power %}
          {% endif %}
          {{ [total_power, 0] | max }}
        availability_template: >-
          {{
            is_number(states('sensor.total_main_power')) and
            is_number(states('sensor.inverter_active_power'))
          }}

Also did the sensor without defferable loads:

  - platform: template
    sensors:
      power_load_no_var_loads:
        friendly_name: "Power Load No Var Loads"
        unit_of_measurement: "W" 
        value_template: >-
          {{ [(
            states('sensor.household_total_power_consumption') | float - 
            states('sensor.heat_pump_power') | float - 
            states('sensor.ev_charger_power_3') | float
          ), 0] | max | round(2) }}
        availability_template: >-
          {{
            is_number(states('sensor.household_total_power_consumption')) and
            is_number(states('sensor.heat_pump_power')) and
            is_number(states('sensor.ev_charger_power_3'))
          }}

Questtion - sensors can go unavailable for brief moments (shelly issues). How does it affect emhass if the values are unavailablbe sometimes? Should i do so that value will be 0 if unavailable? Can this 0 values have bad impact?

Another question about Solcast forecast. At the moment i have set up it to use rest api:

  - platform: rest
    name: "Solcast Forecast East"
    json_attributes:
      - forecasts
    resource: https://api.solcast.com.au/rooftop_sites/e41e-fdc6-cd7f-a7c7/forecasts?format=json&api_key=Y_ymAJBO_Zjfc_FyTmYiVgWCNGO_cJz8&hours=24
    method: GET
    value_template: "{{ (value_json.forecasts[0].pv_estimate)|round(2) }}"
    unit_of_measurement: "kW"
    device_class: power
    scan_interval: 86400
    force_update: true

  - platform: rest
    name: "Solcast Forecast West"
    json_attributes:
      - forecasts
    resource: https://api.solcast.com.au/rooftop_sites/4547-08b6-b3fd-2ca0/forecasts?format=json&api_key=Y_ymAJBO_Zjfc_FyTmYiVgWCNGO_cJz8&hours=24
    method: GET
    value_template: "{{ (value_json.forecasts[0].pv_estimate)|round(2) }}"
    unit_of_measurement: "kW"
    device_class: power
    scan_interval: 86400
    force_update: true

But i added the Solcast integration to Home Assitant which have more data and better API call handling to use the 10 API calls per day.

Sensor sensor.solcast_pv_forecast_forecast_today has attributes:

DetailedForecast
- period_start: '2023-11-29T00:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T00:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T01:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T01:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T02:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T02:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T03:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T03:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T04:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T04:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T05:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T05:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T06:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T06:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T07:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T07:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T08:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T08:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T09:00:00+02:00'
  pv_estimate: 0.0558
  pv_estimate10: 0.0348
  pv_estimate90: 0.0698
- period_start: '2023-11-29T09:30:00+02:00'
  pv_estimate: 0.1259
  pv_estimate10: 0.0839
  pv_estimate90: 0.1498
- period_start: '2023-11-29T10:00:00+02:00'
  pv_estimate: 0.191
  pv_estimate10: 0.1246
  pv_estimate90: 0.2193
- period_start: '2023-11-29T10:30:00+02:00'
  pv_estimate: 0.228
  pv_estimate10: 0.1515
  pv_estimate90: 0.2488
- period_start: '2023-11-29T11:00:00+02:00'
  pv_estimate: 0.2943
  pv_estimate10: 0.2152
  pv_estimate90: 0.3156
- period_start: '2023-11-29T11:30:00+02:00'
  pv_estimate: 0.3179
  pv_estimate10: 0.2394
  pv_estimate90: 0.3338
- period_start: '2023-11-29T12:00:00+02:00'
  pv_estimate: 0.3226
  pv_estimate10: 0.2368
  pv_estimate90: 0.3387
- period_start: '2023-11-29T12:30:00+02:00'
  pv_estimate: 0.3137
  pv_estimate10: 0.2066
  pv_estimate90: 0.3231
- period_start: '2023-11-29T13:00:00+02:00'
  pv_estimate: 0.2564
  pv_estimate10: 0.1686
  pv_estimate90: 0.2784
- period_start: '2023-11-29T13:30:00+02:00'
  pv_estimate: 0.2141
  pv_estimate10: 0.132
  pv_estimate90: 0.2475
- period_start: '2023-11-29T14:00:00+02:00'
  pv_estimate: 0.1538
  pv_estimate10: 0.0916
  pv_estimate90: 0.1925
- period_start: '2023-11-29T14:30:00+02:00'
  pv_estimate: 0.0924
  pv_estimate10: 0.052
  pv_estimate90: 0.1153
- period_start: '2023-11-29T15:00:00+02:00'
  pv_estimate: 0.0254
  pv_estimate10: 0.0112
  pv_estimate90: 0.0333
- period_start: '2023-11-29T15:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T16:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T16:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T17:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T17:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T18:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T18:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T19:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T19:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T20:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T20:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T21:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T21:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T22:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T22:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T23:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T23:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
DetailedHourly
- period_start: '2023-11-29T00:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T01:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T02:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T03:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T04:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T05:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T06:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T07:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T08:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T09:00:00+02:00'
  pv_estimate: 0.0909
  pv_estimate10: 0.0593
  pv_estimate90: 0.1098
- period_start: '2023-11-29T10:00:00+02:00'
  pv_estimate: 0.2095
  pv_estimate10: 0.1381
  pv_estimate90: 0.234
- period_start: '2023-11-29T11:00:00+02:00'
  pv_estimate: 0.3061
  pv_estimate10: 0.2273
  pv_estimate90: 0.3247
- period_start: '2023-11-29T12:00:00+02:00'
  pv_estimate: 0.3181
  pv_estimate10: 0.2217
  pv_estimate90: 0.3309
- period_start: '2023-11-29T13:00:00+02:00'
  pv_estimate: 0.2353
  pv_estimate10: 0.1503
  pv_estimate90: 0.263
- period_start: '2023-11-29T14:00:00+02:00'
  pv_estimate: 0.1231
  pv_estimate10: 0.0718
  pv_estimate90: 0.1539
- period_start: '2023-11-29T15:00:00+02:00'
  pv_estimate: 0.0127
  pv_estimate10: 0.0056
  pv_estimate90: 0.0167
- period_start: '2023-11-29T16:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T17:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T18:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T19:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T20:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T21:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T22:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-29T23:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
Dayname
Wednesday
DataCorrect
true

Sensor sensor.solcast_pv_forecast_forecast_tomorrow has attributes:

DetailedForecast
- period_start: '2023-11-30T00:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T00:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T01:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T01:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T02:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T02:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T03:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T03:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T04:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T04:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T05:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T05:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T06:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T06:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T07:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T07:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T08:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T08:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T09:00:00+02:00'
  pv_estimate: 0.021
  pv_estimate10: 0.0104
  pv_estimate90: 0.0384
- period_start: '2023-11-30T09:30:00+02:00'
  pv_estimate: 0.0628
  pv_estimate10: 0.028
  pv_estimate90: 0.1036
- period_start: '2023-11-30T10:00:00+02:00'
  pv_estimate: 0.1012
  pv_estimate10: 0.0454
  pv_estimate90: 0.1566
- period_start: '2023-11-30T10:30:00+02:00'
  pv_estimate: 0.1326
  pv_estimate10: 0.0628
  pv_estimate90: 0.2083
- period_start: '2023-11-30T11:00:00+02:00'
  pv_estimate: 0.1604
  pv_estimate10: 0.0768
  pv_estimate90: 0.2577
- period_start: '2023-11-30T11:30:00+02:00'
  pv_estimate: 0.1744
  pv_estimate10: 0.0838
  pv_estimate90: 0.2992
- period_start: '2023-11-30T12:00:00+02:00'
  pv_estimate: 0.1794
  pv_estimate10: 0.0838
  pv_estimate90: 0.3099
- period_start: '2023-11-30T12:30:00+02:00'
  pv_estimate: 0.1678
  pv_estimate10: 0.0786
  pv_estimate90: 0.2977
- period_start: '2023-11-30T13:00:00+02:00'
  pv_estimate: 0.1464
  pv_estimate10: 0.0642
  pv_estimate90: 0.2487
- period_start: '2023-11-30T13:30:00+02:00'
  pv_estimate: 0.1142
  pv_estimate10: 0.05
  pv_estimate90: 0.1899
- period_start: '2023-11-30T14:00:00+02:00'
  pv_estimate: 0.082
  pv_estimate10: 0.0356
  pv_estimate90: 0.1376
- period_start: '2023-11-30T14:30:00+02:00'
  pv_estimate: 0.0428
  pv_estimate10: 0.0178
  pv_estimate90: 0.0798
- period_start: '2023-11-30T15:00:00+02:00'
  pv_estimate: 0.0108
  pv_estimate10: 0.0036
  pv_estimate90: 0.0178
- period_start: '2023-11-30T15:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T16:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T16:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T17:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T17:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T18:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T18:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T19:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T19:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T20:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T20:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T21:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T21:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T22:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T22:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T23:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T23:30:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
DetailedHourly
- period_start: '2023-11-30T00:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T01:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T02:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T03:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T04:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T05:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T06:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T07:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T08:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T09:00:00+02:00'
  pv_estimate: 0.0419
  pv_estimate10: 0.0192
  pv_estimate90: 0.071
- period_start: '2023-11-30T10:00:00+02:00'
  pv_estimate: 0.1169
  pv_estimate10: 0.0541
  pv_estimate90: 0.1825
- period_start: '2023-11-30T11:00:00+02:00'
  pv_estimate: 0.1674
  pv_estimate10: 0.0803
  pv_estimate90: 0.2784
- period_start: '2023-11-30T12:00:00+02:00'
  pv_estimate: 0.1736
  pv_estimate10: 0.0812
  pv_estimate90: 0.3038
- period_start: '2023-11-30T13:00:00+02:00'
  pv_estimate: 0.1303
  pv_estimate10: 0.0571
  pv_estimate90: 0.2193
- period_start: '2023-11-30T14:00:00+02:00'
  pv_estimate: 0.0624
  pv_estimate10: 0.0267
  pv_estimate90: 0.1087
- period_start: '2023-11-30T15:00:00+02:00'
  pv_estimate: 0.0054
  pv_estimate10: 0.0018
  pv_estimate90: 0.0089
- period_start: '2023-11-30T16:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T17:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T18:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T19:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T20:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T21:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T22:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
- period_start: '2023-11-30T23:00:00+02:00'
  pv_estimate: 0
  pv_estimate10: 0
  pv_estimate90: 0
Dayname
Thursday
DataCorrect
true

How can I have this information from the two sensors to EMHASS?

Asking and answering myself. Actually @RT1080 had the answer few post back:

\"pv_power_forecast\":{{([states('sensor.solcast_pv_forecast_power_now')|int(0)] + state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list + state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list)| tojson}}"

But i still have issues loading nordpool. My current shell command is:

  trigger_emhass_forecast: "curl -i -H \"Content-Type:application/json\" -X POST -d '{
    \"load_cost_forecast\":{{((state_attr('sensor.nordpool_kwh_ee_eur_3_05_02', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_05_02', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }},
    \"prod_price_forecast\":{{((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }}, 
    \"prediction_horizon\":{{min(24, ((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value') | list)[now().hour:][:24]|list|length))}},    
    \"pv_power_forecast\":{{([states('sensor.solcast_pv_forecast_power_now')|int(0)] + state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list + state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list)| tojson}}
    }' http://192.168.1.35:5001/action/dayahead-optim"

Log

2023-11-29 09:56:10,406 - web_server - INFO - Setting up needed data
2023-11-29 09:56:10,408 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 24
2023-11-29 09:56:10,408 - web_server - ERROR - Passed type is <class 'list'> and length is 13
2023-11-29 09:56:10,408 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 24
2023-11-29 09:56:10,408 - web_server - ERROR - Passed type is <class 'list'> and length is 13
2023-11-29 09:56:10,410 - web_server - INFO - Retrieving weather forecast data using method = list
2023-11-29 09:56:10,412 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2023-11-29 09:56:10,412 - web_server - INFO - Retrieve hass get data method initiated...
2023-11-29 09:56:11,505 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2023-11-29 09:56:11,505 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2023-11-29 09:56:11,505 - web_server - ERROR - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1455, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 869, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 867, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 852, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "src/emhass/web_server.py", line 179, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
  File "/usr/local/lib/python3.8/site-packages/emhass-0.5.1-py3.8.egg/emhass/command_line.py", line 91, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'])
  File "/usr/local/lib/python3.8/site-packages/emhass-0.5.1-py3.8.egg/emhass/forecast.py", line 585, in get_load_forecast
    rh.get_data(days_list, var_list)
  File "/usr/local/lib/python3.8/site-packages/emhass-0.5.1-py3.8.egg/emhass/retrieve_hass.py", line 147, in get_data
    self.df_final = pd.concat([self.df_final, df_day], axis=0)
UnboundLocalError: local variable 'df_day' referenced before assignment

So i guess that the issue is that Nordpool sensor has only today’s hourly values, until end of today 13 in total. They will post tomorrro’s values around 13:00, which is 1 hour to go.

please try this:

  "prediction_horizon": {{
      min(24, (((state_attr('sensor.nordpool_purchase_price', 'raw_today')|map(attribute='value')|list + state_attr('sensor.nordpool_purchase_price', 'raw_tomorrow') | map(attribute='value')| list)[now().hour:][:24]|list|length)))
    }},

Same:

2023-11-29 11:00:08,310 - web_server - INFO - Setting up needed data
2023-11-29 11:00:08,312 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 24
2023-11-29 11:00:08,312 - web_server - ERROR - Passed type is <class 'list'> and length is 11
2023-11-29 11:00:08,312 - web_server - ERROR - ERROR: The passed data is either not a list or the length is not correct, length should be 24
2023-11-29 11:00:08,312 - web_server - ERROR - Passed type is <class 'list'> and length is 11
2023-11-29 11:00:08,315 - web_server - INFO - Retrieving weather forecast data using method = list
2023-11-29 11:00:08,316 - web_server - INFO - Retrieving data from hass for load forecast using method = naive
2023-11-29 11:00:08,317 - web_server - INFO - Retrieve hass get data method initiated...
2023-11-29 11:00:08,679 - web_server - ERROR - The retrieved JSON is empty, check that correct day or variable names are passed
2023-11-29 11:00:08,680 - web_server - ERROR - Either the names of the passed variables are not correct or days_to_retrieve is larger than the recorded history of your sensor (check your recorder settings)
2023-11-29 11:00:08,680 - web_server - ERROR - Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1455, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 869, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 867, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 852, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "src/emhass/web_server.py", line 179, in action_call
    input_data_dict = set_input_data_dict(config_path, str(data_path), costfun,
  File "/usr/local/lib/python3.8/site-packages/emhass-0.5.1-py3.8.egg/emhass/command_line.py", line 91, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'])
  File "/usr/local/lib/python3.8/site-packages/emhass-0.5.1-py3.8.egg/emhass/forecast.py", line 585, in get_load_forecast
    rh.get_data(days_list, var_list)
  File "/usr/local/lib/python3.8/site-packages/emhass-0.5.1-py3.8.egg/emhass/retrieve_hass.py", line 147, in get_data
    self.df_final = pd.concat([self.df_final, df_day], axis=0)
UnboundLocalError: local variable 'df_day' referenced before assignment

tested the templates in home assitant.

{{min(24, ((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value') | list)[now().hour:][:24]|list|length))}}

Result: 11
{{((state_attr('sensor.nordpool_kwh_ee_eur_3_05_02', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_05_02', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }}

Result:
[
  0.157,
  0.196,
  0.182,
  0.3,
  0.24,
  0.3,
  0.3,
  0.24,
  0.193,
  0.167,
  0.154
]
{{((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }}

Result:
[
  0.131,
  0.164,
  0.152,
  0.25,
  0.2,
  0.25,
  0.25,
  0.2,
  0.161,
  0.139,
  0.129
]
{{([states('sensor.solcast_pv_forecast_power_now')|int(0)] + state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list + state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list)| tojson}}

Result:
[
  256,
  123,
  12,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  41,
  116,
  167,
  173,
  130,
  62,
  5,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0
]

Maybe something to do with my config?

# Configuration file for EMHASS

retrieve_hass_conf:
  - freq: 60 # The time step to resample retrieved data from hass in minutes
  - days_to_retrieve: 2 # We will retrieve data from now and up to days_to_retrieve days
  - var_PV: 'sensor.inverter_active_power' # Photovoltaic produced power sensor in Watts
  - var_load: 'sensor.power_load_no_var_loads' # Household power consumption sensor in Watts (deferrable loads should be substracted)
  - load_negative: False # Set to True if the retrived load variable is negative by convention
  - set_zero_min: True # A special treatment for a minimum value saturation to zero. Values below zero are replaced by nans
  - var_replace_zero: # A list of retrived variables that we would want  to replace nans with zeros
    - 'sensor.inverter_active_power'
  - var_interp: # A list of retrived variables that we would want to interpolate nan values using linear interpolation
    - 'sensor.inverter_active_power'
    - 'sensor.power_load_no_var_load'
  - method_ts_round: 'nearest' # Set the method for timestamp rounding, options are: first, last and nearest

optim_conf:
  - set_use_battery: False # consider a battery storage
  - delta_forecast: 1 # days
  - num_def_loads: 2
  - P_deferrable_nom: # Watts
    - 2700.0
    - 4000.0
  - def_total_hours: # hours
    - 4
    - 10
  - treat_def_as_semi_cont: # treat this variable as semi continuous 
    - True
    - True
  - set_def_constant: # set as a constant fixed value variable with just one startup for each 24h
    - False
    - False
  - weather_forecast_method: 'scrapper' # options are 'scrapper' and 'csv'
  - load_forecast_method: 'naive' # options are 'csv' to load a custom load forecast from a CSV file or 'naive' for a persistance model
  - load_cost_forecast_method: 'hp_hc_periods' # options are 'hp_hc_periods' for peak and non-peak hours contracts and 'csv' to load custom cost from CSV file 
  - list_hp_periods: # list of different tariff periods (only needed if load_cost_forecast_method='hp_hc_periods')
    - period_hp_1:
      - start: '02:54'
      - end: '15:24'
    - period_hp_2:
      - start: '17:24'
      - end: '20:24'
  - load_cost_hp: 0.1907 # peak hours load cost in €/kWh (only needed if load_cost_forecast_method='hp_hc_periods')
  - load_cost_hc: 0.1419 # non-peak hours load cost in €/kWh (only needed if load_cost_forecast_method='hp_hc_periods')
  - prod_price_forecast_method: 'constant' # options are 'constant' for constant fixed value or 'csv' to load custom price forecast from a CSV file
  - prod_sell_price: 0.065 # power production selling price in €/kWh (only needed if prod_price_forecast_method='constant')
  - set_total_pv_sell: False # consider that all PV power is injected to the grid (self-consumption with total sell)
  - lp_solver: 'PULP_CBC_CMD' # set the name of the linear programming solver that will be used
  - lp_solver_path: 'empty' # set the path to the LP solver
  - set_nocharge_from_grid: False # avoid battery charging from the grid
  - set_nodischarge_to_grid: True # avoid battery discharging to the grid
  - set_battery_dynamic: False # add a constraint to limit the dynamic of the battery power in power per time unit
  - battery_dynamic_max: 0.9 # maximum dynamic positive power variation in percentage of battery maximum power
  - battery_dynamic_min: -0.9 # minimum dynamic negative power variation in percentage of battery maximum power

plant_conf:
  - P_grid_max: 10000 # The maximum power that can be supplied by the utility grid in Watts
  - module_model: # The PV module model
    - 'CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M'
  - inverter_model: # The PV inverter model
    - 'Fronius_International_GmbH__Fronius_Primo_5_0_1_208_240__240V_'
  - surface_tilt: # The tilt angle of your solar panels
    - 30
  - surface_azimuth: # The azimuth angle of your PV installation
    - 205
  - modules_per_string: # The number of modules per string
    - 16 
  - strings_per_inverter: # The number of used strings per inverter
    - 1
  - Pd_max: 1000 # If your system has a battery (set_use_battery=True), the maximum discharge power in Watts
  - Pc_max: 1000 # If your system has a battery (set_use_battery=True), the maximum charge power in Watts
  - eta_disch: 0.95 # If your system has a battery (set_use_battery=True), the discharge efficiency
  - eta_ch: 0.95 # If your system has a battery (set_use_battery=True), the charge efficiency
  - Enom: 5000 # If your system has a battery (set_use_battery=True), the total capacity of the battery stack in Wh
  - SOCmin: 0.3 # If your system has a battery (set_use_battery=True), the minimun allowable battery state of charge
  - SOCmax: 0.9 # If your system has a battery (set_use_battery=True), the minimun allowable battery state of charge
  - SOCtarget: 0.6 # If your system has a battery (set_use_battery=True), the desired battery state of charge at the end of each optimization cycle

Here’s my dayahead jinja code.

{
  "load_cost_forecast": {{
    ([states('sensor.cecil_st_general_price')|float(0)] + 
    state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) 
    | tojson 
  }},
  "prod_price_forecast": {{
    ([states('sensor.cecil_st_feed_in_price')|float(0)] +
    (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list))
    | tojson 
  }},
  "pv_power_forecast": {{
    ([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +
    state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list +
    state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list
    )| tojson
  }},
  "num_def_loads": 2,
  "def_total_hours": [3, 3],
  "P_deferrable_nom":  [1300, 2300],
  "treat_def_as_semi_cont": [1, 0]  
}

This code produces the following when you test it in developers tools:

{
  "load_cost_forecast": [0.16, 0.15, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.15, 0.15, 0.15, 0.14, 0.15, 0.16, 0.16, 0.16, 0.15, 0.13, 0.1, 0.09, 0.09, 0.09, 0.06, 0.05, 0.07, 0.06, 0.06, 0.07, 0.07, 0.07, 0.1, 0.35, 0.36, 0.36, 0.36, 0.36, 0.37, 0.37, 0.38, 0.41, 0.41, 0.42, 0.42, 0.2, 0.19, 0.16, 0.16, 0.16],
  "prod_price_forecast": [0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.06, 0.06, 0.06, 0.05, 0.04, 0.01, -0.0, 0.0, 0.0, -0.02, -0.06, -0.04, -0.05, -0.05, -0.04, -0.04, -0.04, -0.01, 0.27, 0.28, 0.28, 0.28, 0.28, 0.28, 0.28, 0.3, 0.32, 0.32, 0.33, 0.33, 0.09, 0.09, 0.07, 0.07, 0.06],
  "pv_power_forecast": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 81, 177, 577, 1047, 1555, 2097, 2564, 2965, 3261, 3336, 3363, 3407, 3400, 3383, 3287, 3118, 2925, 2694, 2435, 2162, 1878, 1591, 1310, 1003, 654, 305, 82, 7, 0, 0, 0, 0, 0, 0, 0, 0],
  "num_def_loads": 2,
  "def_total_hours": [3, 3],
  "P_deferrable_nom":  [1300, 2300],
  "treat_def_as_semi_cont": [1, 0]  
}

I post this using node-red flow:

Here’s the JSON code for this flow:

[{"id":"962843add2ce0c1c","type":"debug","z":"65840aa926d9c567","name":"debug Day Ahead POST","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1130,"y":1160,"wires":[]},{"id":"b3613da7047487af","type":"http request","z":"65840aa926d9c567","name":"POST Day Ahead","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":770,"y":1100,"wires":[["962843add2ce0c1c","710a3b34e8103b99"]]},{"id":"6cfcb69f84018e45","type":"inject","z":"65840aa926d9c567","d":true,"name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"59 03 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":170,"y":1100,"wires":[["5e6c81ecba2fb539"]]},{"id":"61cffcb335f42876","type":"change","z":"65840aa926d9c567","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"http://192.168.99.17:5000/action/dayahead-optim","tot":"str"},{"t":"set","p":"method","pt":"msg","to":"POST","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"Content-Type: application/json","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":1100,"wires":[["b3613da7047487af"]]},{"id":"aa71f4422db79ef8","type":"comment","z":"65840aa926d9c567","name":"Testing dayahead POST","info":"","x":210,"y":1060,"wires":[]},{"id":"7e925a1388464de2","type":"change","z":"65840aa926d9c567","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"http://192.168.99.17:5000/action/publish-data","tot":"str"},{"t":"set","p":"method","pt":"msg","to":"POST","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"Content-Type: application/json","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":1160,"wires":[["43cfe6b46818abdf"]]},{"id":"43cfe6b46818abdf","type":"http request","z":"65840aa926d9c567","name":"POST Publish data","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":770,"y":1160,"wires":[["710a3b34e8103b99","962843add2ce0c1c"]]},{"id":"710a3b34e8103b99","type":"function","z":"65840aa926d9c567","name":"POST return != 201","func":"var forecastData = flow.get('forecastData');\nvar status = msg.statusCode;\nif(status != 201)\n{\n    var timestamp = new Date().toISOString();\n    var newpayload = [timestamp, msg.statusCode, msg.url, msg.payload, forecastData];\n    msg.payload = newpayload;\n\n    return msg;\n}\nelse\nreturn;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1150,"y":1100,"wires":[["d1c6b5976c8967e6","3034893cf2f75e12"]]},{"id":"d1c6b5976c8967e6","type":"api-call-service","z":"65840aa926d9c567","name":"Notify Robert's iPhones","server":"afc27684.cf6ed8","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_robsiphone","areaId":[],"deviceId":[],"entityId":[],"data":"{\"title\":\"POST to EMHASS service failed\",\"message\":\"error: '{{statusCode}}' URL: '{{responseUrl}}'\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1470,"y":1060,"wires":[[]]},{"id":"3034893cf2f75e12","type":"file","z":"65840aa926d9c567","name":"write error","filename":"/share/EMHASSDayAheadPostError.log","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":1430,"y":1140,"wires":[[]]},{"id":"25a81a7ad77094cb","type":"inject","z":"65840aa926d9c567","d":true,"name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"300","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":1160,"wires":[["7e925a1388464de2"]]},{"id":"5e6c81ecba2fb539","type":"api-render-template","z":"65840aa926d9c567","name":"Day Ahead","server":"afc27684.cf6ed8","version":0,"template":"{\n  \"load_cost_forecast\": {{\n    ([states('sensor.cecil_st_general_price')|float(0)] + \n    state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) \n    | tojson \n  }},\n  \"prod_price_forecast\": {{\n    ([states('sensor.cecil_st_feed_in_price')|float(0)] +\n    (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list))\n    | tojson \n  }},\n  \"pv_power_forecast\": {{\n    ([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +\n    state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list +\n    state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list\n    )| tojson\n  }},\n  \"num_def_loads\": 2,\n  \"def_total_hours\": [3, 3],\n  \"P_deferrable_nom\":  [1300, 2300],\n  \"treat_def_as_semi_cont\": [1, 0]  \n}","resultsLocation":"payload","resultsLocationType":"msg","templateLocation":"","templateLocationType":"none","x":390,"y":1100,"wires":[["61cffcb335f42876"]]},{"id":"afc27684.cf6ed8","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

I’m using "load_cost_forecast" in my conf and you are using “load_cost_forecast”, could the different format have something to do with it?

My jinja:

{
    \"load_cost_forecast\":{{((state_attr('sensor.nordpool_kwh_ee_eur_3_05_02', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_05_02', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }},
    \"prod_price_forecast\":{{((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today') | map(attribute='value') | list  + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value') | list))[now().hour:][:24] }}, 
    \"prediction_horizon\":{{min(24, (((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today')|map(attribute='value')|list + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value')| list)[now().hour:][:24]|list|length)))}},    
    \"pv_power_forecast\":{{([states('sensor.solcast_pv_forecast_power_now')|int(0)] + state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list + state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedHourly')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list)| tojson}}
    }

And developer tools:

{
    \"load_cost_forecast\":[0.157, 0.196, 0.182, 0.3, 0.24, 0.3, 0.3, 0.24, 0.193, 0.167, 0.154],
    \"prod_price_forecast\":[0.131, 0.164, 0.152, 0.25, 0.2, 0.25, 0.25, 0.2, 0.161, 0.139, 0.129], 
    \"prediction_horizon\":11,    
    \"pv_power_forecast\":[214, 123, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 116, 167, 173, 130, 62, 5, 0, 0, 0, 0, 0, 0, 0, 0]
    }

Looks quite ok

I don’t use prediction_horizon in dayahead, only in naive-mpc-optim which I run every 60 seconds.

{
  "prod_price_forecast": {{
    ([states('sensor.cecil_st_feed_in_price')|float(0)] +
    (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list))
    | tojson 
  }},
  "load_cost_forecast": {{
    ([states('sensor.cecil_st_general_price')|float(0)] + 
    state_attr('sensor.cecil_st_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) 
    | tojson 
  }},
  "pv_power_forecast": {{
    ([states('sensor.sonnenbatterie_84324_production_w')|int(0)] +
    state_attr('sensor.solcast_pv_forecast_forecast_today', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list +
    state_attr('sensor.solcast_pv_forecast_forecast_tomorrow', 'detailedForecast')|selectattr('period_start','gt',utcnow()) | map(attribute='pv_estimate')|map('multiply',1000)|map('int')|list
    )| tojson
  }},
  "prediction_horizon": {{
    min(48, (state_attr('sensor.cecil_st_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)
  }},
  "num_def_loads": 2,
  "def_total_hours": [
    {%- if is_state('sensor.openweathermap_forecast_condition', ['rainy']) -%}
      0
    {%- elif is_state('sensor.season', 'winter') -%}
      2
    {%- elif is_state('sensor.season', 'summer') -%}
      4
    {%- else -%}
      3
    {%- endif -%},
    {%- if is_state('device_tracker.ynot_location_tracker', ['home']) -%}
      {%- if is_state('cover.ynot_charger_door', ['open']) -%}
        {{ ((90-(states('sensor.ynot_battery')|int(0)))/30*3)|int(0) }}
      {%- else -%} 
        0
      {%- endif -%}
    {%- else -%} 
      0
    {%- endif -%}
    ],
  "P_deferrable_nom": [1300, 7360],
  "treat_def_as_semi_cont": [1, 0],
  "set_def_constant": [0, 0],
  "soc_init": {{ (states('sensor.sonnenbatterie_84324_state_charge_user')|int(0))/100 }},
  "soc_final": 0.03,
  "alpha": 0.25,
  "beta": 0.75
}

This produces the following, note this is where I include prediction_horizon:

{
  "prod_price_forecast": [0.07, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.05, 0.05, 0.05, 0.05, 0.05, 0.06, 0.06, 0.06, 0.05, 0.04, 0.02, -0.0, 0.01, 0.0, -0.02, -0.06, -0.04, -0.05, -0.04, -0.04, -0.04, -0.04, -0.04, 0.27, 0.29, 0.28, 0.28, 0.28, 0.28, 0.28, 0.3, 0.32, 0.32, 0.33, 0.33, 0.09, 0.09, 0.07, 0.07, 0.06],
  "load_cost_forecast": [0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.15, 0.15, 0.15, 0.15, 0.15, 0.16, 0.16, 0.16, 0.15, 0.13, 0.11, 0.09, 0.1, 0.09, 0.06, 0.05, 0.07, 0.06, 0.07, 0.07, 0.07, 0.07, 0.07, 0.35, 0.37, 0.36, 0.36, 0.36, 0.37, 0.37, 0.38, 0.41, 0.41, 0.42, 0.42, 0.2, 0.19, 0.16, 0.16, 0.16],
  "pv_power_forecast": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 81, 177, 577, 1047, 1555, 2097, 2564, 2965, 3261, 3336, 3363, 3407, 3400, 3383, 3287, 3118, 2925, 2694, 2435, 2162, 1878, 1591, 1310, 1003, 654, 305, 82, 7, 0, 0, 0, 0, 0, 0, 0, 0],
  "prediction_horizon": 48,
  "num_def_loads": 2,
  "def_total_hours": [0,0],
  "P_deferrable_nom": [1300, 7360],
  "treat_def_as_semi_cont": [1, 0],
  "set_def_constant": [0, 0],
  "soc_init": 0.1,
  "soc_final": 0.03,
  "alpha": 0.25,
  "beta": 0.75
}
1 Like

Dynamic prediction_horizon is configured, because Nordpool next day hourly prices will be given around 1PM, but it can take even longer for the HA integration to get them. So this template will check how many hours of data is available:

{{min(24, (((state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_today')|map(attribute='value')|list + state_attr('sensor.nordpool_kwh_ee_eur_3_10_0', 'raw_tomorrow') | map(attribute='value')| list)[now().hour:][:24]|list|length)))}}

And set the prediction_horizon accordingly. With this you can run the shell command and not be worried of errors.

But back to my case. I think the issue at the moment is that I don’t have enough data on the sensor:

var_load: 'sensor.power_load_no_var_loads'

I changed the calculation behind it and this zeroed the history. So to my understanding i just have to wait for 48 hours now. I can probably check that if i change it to some other power reading which has history in HA

1 Like

I’m with amber electric here in Australia. Amber publishes 24h Forecast after 12:30 each day with 48x30 minute forecasts until 03:30 after which the forecasts stop. So, between 03:30 and 12:30 you have incrementally less than 48 forecasts. At 12:00 you have the smallest number of forecasts 12:00-03:30 the next day which is 33x30 minute forecasts.

However I only run dayahead once a day at 03:59 (if I’m not using MPC for some reason) so I guess this doesn’t need a rediction horizon set.

My power_load_no_var_loads is taken from my sonnen battery using a custom integration.

# Calculate power consumption for cecil st less the deferrable appliances
  - platform: template
    sensors:
      house_power_consumption_less_deferrables:
        unique_id: house_power_consumption_less_deferrables
        unit_of_measurement: W
        device_class: power
        value_template: >-
          {% set consumption = states('sensor.sonnenbatterie_84324_consumption_w') | float(0) %}
          {% if is_state('switch.garage_power_point_l1', 'on') %}
            {# If the pool light is on subtract 11 watts #}
              {% set deferrable0 = states('sensor.garage_power_point_power') | float(0) - 11 %}
          {% else %}
              {% set deferrable0 = states('sensor.garage_power_point_power') | float(0) %}
          {% endif %}
          {% set deferrable1 = states('sensor.ynot_home_charge') | float(0) if is_state('device_tracker.ynot_location_tracker', 'home') else 0 %}
          {# below code stops resulte dropping below 0 when consumption hasn't cought up #}
          {% if (consumption - (deferrable0 + deferrable1)) | float(0) <= 0 %}
            {{ consumption | float(0) }}
          {% else %}
            {{ consumption - (deferrable0 + deferrable1) | float(0) }}
          {% endif %}

I still get some negative values:

You can use the max function to ensure that the final output is always zero or a positive number. Here’s the updated template:

- platform: template
  sensors:
    house_power_consumption_less_deferrables:
      unique_id: house_power_consumption_less_deferrables
      unit_of_measurement: "W"
      device_class: power
      value_template: >-
        {% set consumption = states('sensor.sonnenbatterie_84324_consumption_w') | float(0) %}
        {% if is_state('switch.garage_power_point_l1', 'on') %}
          {% set deferrable0 = states('sensor.garage_power_point_power') | float(0) - 11 %}
        {% else %}
          {% set deferrable0 = states('sensor.garage_power_point_power') | float(0) %}
        {% endif %}
        {% set deferrable1 = states('sensor.ynot_home_charge') | float(0) if is_state('device_tracker.ynot_location_tracker', 'home') else 0 %}
        {% set total_deferrables = deferrable0 + deferrable1 %}
        {% set net_consumption = consumption - total_deferrables %}
        {{ [net_consumption, 0] | max }}

2 Likes