Automated home heat pump according to price/temperature. Room for improvement?

I am hoping to find some ways to improve the automation I wrote for my home heating pump system. I would really appreciate any tips on how I could improve these. Some background (forgive me if I give too much info, I’m sure you could gather most of what I say below by looking through the YAML):

Last fall I switched to a time-based electric contract last fall and pay the market price for each kWh I use. I have been using Home Assistant to shift as much of the electric usage from my heat pump (IVT 402) to those times when it is the least expensive. IVT has its own app which can be used to supposedly accomplish this but it appears to reduce the temperature up to 1 degree and I think more advantages could be achieved by taking advantage of my home’s relatively good insulation and the built-in hot water tank to act as heat batteries when the price is low. The heat pump also has an outdoor temperature sensor which can be accessed through the Bosch component.

Instead, I have created some automation using the Bosch thermostats component (home-assistant-bosch-custom-component) to talk to the heat pump, the Tibber integration to receive hourly price values (published daily at 1300l for the following day) and levels (see PriceLevel), and the Sector Alarm integration to pull room temperature data from the motion sensors installed around my house.

The automation is split into 5 separate automations in HA which adjust the temperature based on the price levels provided by the Tibber integration plus 1 to avoid high room temperature.

The full reference for the Tibber Api can be seen here but below are the definitions of each PriceLevel.

PriceLevel

Price level based on trailing price average (3 days for hourly values and 30 days for daily values)

Value Description
NORMAL The price is greater than 90 % and smaller than 115 % compared to average price.
CHEAP The price is greater than 60 % and smaller or equal to 90 % compared to average price.
VERY_CHEAP The price is smaller or equal to 60 % compared to average price.
EXPENSIVE The price is greater or equal to 115 % and smaller than 140 % compared to average price.
VERY_EXPENSIVE The price is greater or equal to 140 % compared to average price.

Here are the automations starting with the Very_Expensive price level (I have changed the sensor IDs for my security):

alias: Price Level - VERY_EXPENSIVE
description: ''
trigger:
  - platform: state
    entity_id: sensor.electricity_price_streetname_123
    attribute: price_level
    to: VERY_EXPENSIVE
condition:
  - condition: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    above: '19.5'
action:
  - service: climate.set_temperature
    data:
      temperature: 19
    target:
      device_id: 123456a1234
  - service: water_heater.set_operation_mode
    data:
      operation_mode: eco
    target:
      entity_id: water_heater.dhw1
mode: queued
alias: Price Level - EXPENSIVE
description: ''
trigger:
  - platform: state
    entity_id: sensor.electricity_price_streetname_123
    attribute: price_level
    to: EXPENSIVE
condition:
  - condition: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    above: '19.5'
action:
  - service: climate.set_temperature
    data:
      temperature: 20
    target:
      device_id: 123456a1234
  - service: water_heater.set_operation_mode
    data:
      operation_mode: eco
    target:
      entity_id: water_heater.dhw1
mode: queued
alias: Price Level - NORMAL
description: ''
trigger:
  - platform: state
    entity_id: sensor.electricity_price_streetname_123
    attribute: price_level
    to: NORMAL
  - platform: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    below: '19.5'
condition:
  - condition: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    below: '22'
  - condition: not
    conditions:
      - condition: state
        entity_id: sensor.electricity_price_streetname_123
        attribute: price_level
        state: CHEAP
  - condition: not
    conditions:
      - condition: state
        entity_id: sensor.electricity_price_streetname_123
        attribute: price_level
        state: VERY_CHEAP
action:
  - service: climate.set_temperature
    data:
      temperature: 20.5
    target:
      device_id: 123456a1234
  - service: water_heater.set_operation_mode
    data:
      operation_mode: eco
    target:
      entity_id: water_heater.dhw1
mode: queued
alias: Price Level - CHEAP
description: ''
trigger:
  - platform: state
    entity_id: sensor.electricity_price_streetname_123
    attribute: price_level
    to: CHEAP
    for:
      hours: 0
      minutes: 0
      seconds: 0
  - platform: numeric_state
    entity_id: sensor.electricity_price_streetname_123
    below: '.5'
    for:
      hours: 0
      minutes: 0
      seconds: 0
  - platform: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    below: '19.5'
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition:
  - condition: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    below: '22'
  - condition: numeric_state
    entity_id: sensor.electricity_price_streetname_123
    below: '.4'
  - condition: or
    conditions:
      - condition: state
        entity_id: sensor.electricity_price_streetname_123
        attribute: price_level
        state: CHEAP
      - condition: state
        entity_id: sensor.electricity_price_streetname_123
        attribute: price_level
        state: VERY_CHEAP
action:
  - service: climate.set_temperature
    data:
      temperature: 21
    target:
      device_id: 123456a1234
  - service: water_heater.set_operation_mode
    data:
      operation_mode: eco
    target:
      entity_id: water_heater.dhw1
mode: queued
alias: Price Level - VERY_CHEAP
description: ''
trigger:
  - platform: state
    entity_id: sensor.electricity_price_streetname_123
    attribute: price_level
    to: VERY_CHEAP
  - platform: numeric_state
    entity_id: sensor.electricity_price_streetname_123
    below: '.25'
condition:
  - condition: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    below: '22'
  - condition: state
    entity_id: sensor.electricity_price_streetname_123
    attribute: price_level
    state: VERY_CHEAP
  - condition: numeric_state
    entity_id: sensor.electricity_price_streetname_123
    below: '.25'
action:
  - service: climate.set_temperature
    data:
      temperature: 22
    target:
      device_id: 123456a1234
  - service: water_heater.set_operation_mode
    data:
      operation_mode: 'on'
    target:
      entity_id: water_heater.dhw1
mode: queued
alias: Avoid high room temp
description: ''
trigger:
  - platform: numeric_state
    entity_id: sensor.sector_living_room_motion_sensor_123456a1234
    above: '23'
condition:
  - condition: numeric_state
    entity_id: sensor.hc1_current_room_setpoint
    above: '20'
action:
  - service: climate.set_temperature
    data:
      temperature: 20
    target:
      device_id: 123456a1234
  - service: water_heater.set_operation_mode
    data:
      operation_mode: eco
    target:
      entity_id: water_heater.dhw1
mode: single
7 Likes

I’ve made a couple of changes and additions to this but something I am interested in adding now is making adjustments to the hot water circuit based on upcoming prices. For example, if the price will rise dramatically in a couple of hours the hot water should be set to reach its maximum temperature before then.

What I could use help with is making some sensor templates that either give the price level x number of hours from now and/or the price x number of hours from now. Tibber provides HA with the data for the next 24 hours (released around 1300 each day) but I don’t know how to create a template to make use of it.

Nice work. So many ideas. Not enough time and skills (my skills).
Soon I have Solar panels and batteries also. Would be so nice to have automation that can take that into account as well. Controlling what source is used based on price. When to charge batteries, when to use heaters etc. and when it is most beneficial to sell electricity.

Nicely done! I’m in Sweden using a similar setup, with a Bosch 3800i heat pump, Tibber, Home assistant and room heat sensors through Telldus.

Being an amateur and trying to program something similar, I’m using the visual automation editor in Home Assistant. However, choosing the heat circuit the only action possible is set it to “heat”. In my dashboard I can set the temperature, not sure why this isn’t an option in the automation. Was climate.set_temparature an option for you to choose or how did you get there?

I believe the 3800i is the same as the ivt 402. I used the 3800 installer manual to understand some of the menus on my IVT pump itself. If you use climate.set_temperature in your automation you can then select the device climate.hc1 as the target.

1 Like

Thanks, I had no idea they were the same. I’m trying out some stuff, but it’s not completely intuitive. This is an example of the code I’d like to use:

alias: EXPENSIVE
description: Trying tibber price levels
trigger:
  - platform: state
    entity_id:
      - sensor.electricity_price_street_name
    attribute: price_level
    to: EXPENSIVE
condition: []
action:
  - service: climate.set_aux_heat
    data:
      aux_heat: false
    target:
      entity_id: climate.hc1
  - service: water_heater.turn_off
    data: {}
mode: queued

To me this means that the auxiliary heater (electricity) is turned off, and the water heater is turned off. I haven’t been able to see it work in practice like that though, since the water heater and the aux heater are turned off most of the time, and the switches in my dashboard doesn’t seem to correspond correctly.

Also, I’d like to be able use the actual numeric price as a trigger, but since that doesn’t seem to be a parameter I’m not sure how to go about it.

Let me know if you have any thoughts and I’ll post when I figure stuff out. My idea is to use either the tibber price levels or real numeric price levels to do:

  • (Very) Expensive price: turn off all the electrical heating, but max out on the heat pump otherwise, therefore not so keen on lowering the target temp since that might actually waste heat.
  • Normal: normal mode
  • Cheap: Run water heater up to >60 degrees C if that hasn’t been done in two weeks (Listeria program), otherwise to 55. Use rum temperature sensors to increase heat to 21 degrees with electricity if needed.

Also, I’d like to look ahead at prices, and if it’s expensive and no decrease in price for - say - the next 24 hours, to still use heating and water heater, otherwise it might be turned off for days.

Not sure if all this is possible, but it really should be looking at all the parameters from the heat pump.

I don’t think that service is working because climate.hc1 probably doesn’t contain an operation mode to disable aux heating. You should explore each device under the Bosch Thermostat integration and see what controls and operating modes are available. This will give you a better idea of what things you can change. For me, it is not possible to disable the aux heater using the Bosch integration.

To set a numeric price as a trigger you or condition you need to use the entity “Electricity price name

You won’t be able to disable the electric supplemental heater using the integration as this is not a control available in any of the entities (at least on my IVT pump which is very similar to yours). This can only be done in the installer menu on the heat pump itself (or by physically disabling the line feeds to the immersion heater). I’m not sure how you conclude that lowering the target temp will waste heat??

You can set the Operation mode of the water heater to Eco, On, or High Demand (this corresponds to Eco+, Eco, and Comfort on my IVT pump). Additionally, you can use the Charge switch to activate the Extra hot water program, as well as the temperature and duration of the charge mode. All of these are controls available in the Water heater dwh1 device. I suspect this can be useful as a heat battery since the dhw and heating water cylinders surround one another.

Look ahead prices are something I am also looking into but haven’t had the time and don’t have the programming knowledge to create these sensors.

1 Like

Thanks, great reply.

I thought the services provided under climate were specific for the heat pump, but perhaps they are standard ones in home assistant. I suspect the latter now that I realize that I had to choose target when using climate.set_aux_heat. Then, yea, I guess I really have to use the reference to see what services are provided (although I think the service did something, because it resulted in some kind of alarm on the heat pump after a couple of hours…).

Assuming now that only the services starting with “bosch” are specific to things actually provided by the interface with the heat pump.

Regarding if lowering temp will waste heat, here’s my thinking: the heat pump uses a compressor to exchange outgoing heat, and then adds electrical heating if that’s not enough. My question is if it always using ALL the energy it gathers? Or could there be a case where both the house and the water is warm enough even before using all the heat gathered from the compressor? If so, that would be the possible case where lowering the target temperature would waste some of the heat it gets from the compressor, since the heat pump would deem it’s “not needed”.

Thank you for posting!

It got me inspired to steel with pride and modify. I ended up with a slightly different implementation that I wish to share for further feedback, refinement and maybe inspiration.

We have two Mitsubishi heat pumps that I’ve hacked with Wemos D1 mini’s on the serial port inside the units. This allows me to integrate them nicely with HA. It also allows me to feedback any temperature sensor in the house to the PID-loop of the heat pumps. This feature is very convenient since winter and summer conditions are too different to stay with one sensor position throughout the year.

I’ve used two helpers with input numbers to be used as setpoints for the climate, see image below. I’ve added template sensors that extracts the attribute price_level as well as the heat pump action for the two pumps.
image

These template sensors allows me to visualize whether the pumps can idle throughout the expensive parts of the day. An example from today is shown below.

This solution is supported by five automations that adjusts the setpoint of each heat pump up and down in 0.5 degC steps based on current price level. The automations also trigger on input from the input numbers so that I don’t have to wait for a price level change to change the heat pump setpoint.
image

The figure shows that this allowed letting the pumps idle during expensive and very expensive hours today. It remains to study how well this works during a February cold spell, but under current conditions the temperature variations seems acceptable.

Let me know if you have questions or ideas for improving this further!

2 Likes

You could use an add-on that I created to automate and most importantly optimize all this: GitHub - davidusb-geek/emhass: emhass: Energy Management for Home Assistant, is a Python module designed to optimize your home energy interfacing with Home Assistant.

1 Like

Hi David,

I’ve already got your code running. My plan is to rely on it when our energy storage system is delivered together with solar panels.

Are you saying that your system also allows handling manipulation of heat pump setpoints to achieve the effect I’ve achieved above? These are not deferrable loads from what I can see.

Cheers, Per

I like your template sensor. Have you posted it somewhere? Are the sensors named Hallway/Recreation room heat pump current temperature providing the current room temp or current setpoint? That would be useful (maybe with outdoor temp also overlayed) to visualize heat loss when the automation lowers the setpoint.

Could you explain how you have the automation trigger on input numbers?

I will check this out. It seems like it could be run without any pv producers is that right?

I don’t see why we cannot treat the heat pumps as deferrable loads. Then use the optimized schedule to define your setpoints. But you will need to map the heat pump power consumption with the temperature setpoint. This can be done either with an identified function or with a bunch of automation rules similar to what you have already done.

Yeah sure, no need to have a PV production. The most basic setup is when you just have a single deferrable load that you want to optimize. There is an example on the documentation to achieve this.

Hi cttime,

Glad to hear you like my solution. I’ll try to explain in more detail how I’ve set things up.

My two Mitsubishi heat pumps are controlled via ESPHome using Wemos D1 minis connected to the serial port inside the heat pumps. Very cute with no noticeable hardware visible on the outside.

Below in an example for one of them:

substitutions:
   devicename: Hallway heat pump
   
esphome:
  name: hallway-heat-pump
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Hallway Heat Pump"
    password: "-"

captive_portal:

# Enable logging
logger:
  # ESP8266 only - disable serial port logging, as the HeatPump component
  # needs the sole hardware UART on the ESP8266
  baud_rate: 0

# Enable Home Assistant API
api:
  services:
    - service: set_remote_temperature
      variables:
        temperature: float
      then:
        - lambda: 'id(hp).set_remote_temperature(temperature);'

    - service: use_internal_temperature
      then:
        - lambda: 'id(hp).set_remote_temperature(0);'

ota:

# Enable Web server.
web_server:
  port: 80

  # Sync time with Home Assistant.
time:
  - platform: homeassistant
    id: homeassistant_time

# Text sensors with general information.
text_sensor:
  # Expose ESPHome version as sensor.
  - platform: version
    name: ${devicename} version
  # Expose WiFi information as sensors.
  - platform: wifi_info
    ip_address:
      name: ${devicename} ip
    ssid:
      name: ${devicename} ssid
    bssid:
      name: ${devicename} bssid

# Sensors with general information.
sensor:
  # Uptime sensor.
  - platform: uptime
    name: ${devicename} uptime

  # WiFi Signal sensor.
  - platform: wifi_signal
    name: ${devicename} wifi signal
    update_interval: 60s

external_components:
  - source: github://geoffdavis/esphome-mitsubishiheatpump

climate:
  - platform: mitsubishi_heatpump
    name: ${devicename}
    id: hp
    
switch:
  - platform: restart
    name: ${devicename} restart

The heat pump get the readback value from a remote sensor that I can select from a drop down list in HA using an input_select in configuration.yaml. I’ve fallen in love with the Aqara Zigbee temperature sensors powered by 2032 cells. They last 12-18 months on one battery.

input_select:
  hallway_heat_pump_sensor:
    name: Hallway heat pump sensor
    options:
      - Bedroom
      - Kitchen
      - Library
      - Living room
      - Guest room 1
      - Guest room 2

The input_select controls which sensor that should be used as feedback for the PID loop of the heat pump. I’ve created a few template sensors for the heat pump that is useful.

- platform: template
  sensors:
    hallway_heat_pump_hvac_action:
      friendly_name: "Hallway heat pump action"
      value_template: "{{ state_attr('climate.hallway_heat_pump', 'hvac_action') }}"
      availability_template: >
        {{states('climate.hallway_heat_pump') not in ['unknown','unavailable']}}

    hallway_heat_pump_current_temperature:
      friendly_name: "Hallway heat pump current temperature"
      unit_of_measurement: "°C"
      value_template: "{{ state_attr('climate.hallway_heat_pump', 'current_temperature') }}"
      availability_template: >
        {{states('climate.hallway_heat_pump') not in ['unknown','unavailable']}}

    hallway_heat_pump_sensor:
      unit_of_measurement: "°C"
      value_template: >
        {% if is_state('input_select.hallway_heat_pump_sensor', 'Bedroom') %}
        {{ states('sensor.bedroom_temperature') }}
        {% elif is_state('input_select.hallway_heat_pump_sensor', 'Kitchen') %}
        {{ states('sensor.kitchen_temperature') }}
        {% elif is_state('input_select.hallway_heat_pump_sensor', 'Library') %}
        {{ states('sensor.library_temperature') }}
        {% elif is_state('input_select.hallway_heat_pump_sensor', 'Living room') %}
        {{ states('sensor.living_room_temperature') }}
        {% elif is_state('input_select.hallway_heat_pump_sensor', 'Guest room 1') %}
        {{ states('sensor.guest_room_1_temperature') }}
        {% elif is_state('input_select.hallway_heat_pump_sensor', 'Guest room 2') %}
        {{ states('sensor.guest_room_2_temperature') }}
        {% endif %}
      availability_template: >
        {% set items = ['sensor.bedroom_temperature', 'sensor.kitchen_temperature', 'sensor.library_temperature', 'sensor.living_room_temperature', 'sensor.guest_room_1_temperature', 'sensor.guest_room_2_temperature'] %}
        {{expand(items)|rejectattr('state','in',['unknown','unavailable'])
          |list|count == items|count}}

The heat pumps need to get updated values from the selected temperature sensors via an automation:

alias: Update heat pumps external sensors
description: ""
trigger:
  - platform: time_pattern
    minutes: /1
condition: []
action:
  - service: esphome.hallway_heat_pump_set_remote_temperature
    data_template:
      temperature: "{{states.sensor.hallway_heat_pump_sensor.state}}"
  - service: esphome.recreation_room_heat_pump_set_remote_temperature
    data_template:
      temperature: "{{states.sensor.recreation_room_heat_pump_sensor.state}}"
mode: single

I’ve created a setpoint for the heat pumps using a helper in Lovelace.

I use the input_number setpoint to manipulate the ESPHome integration for the heat pumps using the price level and 5 automations. The example below is for when it is very expensive in which case I lower the setpoint by 1.0 degrees.

alias: Heat pump - Very expensive
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.electricity_price_level
    to: VERY_EXPENSIVE
  - platform: state
    entity_id:
      - input_number.hallway_heat_pump_setpoint
      - input_number.recreation_room_heat_pump_setpoint
condition:
  - condition: state
    entity_id: sensor.electricity_price_level
    state: VERY_EXPENSIVE
action:
  - service: climate.set_temperature
    data:
      temperature: "{{ states('input_number.hallway_heat_pump_setpoint') | float -1.0 }}"
    target:
      entity_id: climate.hallway_heat_pump
  - service: climate.set_temperature
    data:
      temperature: >-
        {{ states('input_number.recreation_room_heat_pump_setpoint') | float
        -1.0 }}
    target:
      entity_id: climate.recreation_room_heat_pump
mode: single

The elecricity price level sensor is using the Nordpool integration sensor and is defined as below:

- platform: template
  sensors:
    electricity_price_level:
      friendly_name: "Electricity price level"
      value_template: >-
        {% set price_cur = states('sensor.nordpool_kwh_se3_sek_3_10_025') | float(0) %}
        {% set price_avg = state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'average') | float(0) %}
        {% if price_cur == 0 or price_avg == 0 %}
          unknown
        {% else %}
          {% set price_ratio = (price_cur / price_avg) %}
          {% if price_ratio >= 1.4 %}
            VERY_EXPENSIVE
          {% elif price_ratio >= 1.15 %}
            EXPENSIVE
          {% elif price_ratio <= 0.6 %}
            VERY_CHEAP
          {% elif price_ratio <= 0.9 %}
            CHEAP
          {% else %}
            NORMAL
          {% endif %}
        {% endif %}
      availability_template: >
        {{states('sensor.nordpool_kwh_se3_sek_3_10_025') not in ['unknown','unavailable']}}

My user interface has setpoints for the heat pumps as shown below:

And I can monitor how the price level affect the HVAC state during the day and how the climate varies over time:

I also have automations that detect if we use our fireplaces and automatically switch our heat pumps to fan mode to keep circulating the air instead of just turning off when the temperature goes up.

The two fire place automations for the hallway pump are shown below:

alias: >-
  Switch hallway heat pump from heating to fan only if (current temperature -
  setpoint) > 2 degrees
description: ""
trigger:
  - platform: template
    value_template: >-
      {% if not state_attr('climate.hallway_heat_pump',
      'current_temperature')|float(default=0) and
      state_attr('climate.hallway_heat_pump', 'temperature')|float(default=0) %}
        False
      {% else %}
        {{ (state_attr('climate.hallway_heat_pump', 'current_temperature')|float(default=0) - state_attr('climate.hallway_heat_pump', 'temperature')|float(default=0)) > 2 }}
      {% endif %}
condition:
  - condition: state
    entity_id: climate.hallway_heat_pump
    state: idle
    attribute: hvac_action
  - condition: state
    entity_id: input_boolean.hallway_fireplace_automation
    state: "on"
action:
  - service: climate.set_hvac_mode
    data:
      hvac_mode: fan_only
    target:
      entity_id:
        - climate.hallway_heat_pump
mode: single

and

alias: >-
  Switch hallway heat pump from fan only to heating if (current temperature -
  setpoint) < 2 degrees
description: ""
trigger:
  - platform: template
    value_template: >-
      {% if not state_attr('climate.hallway_heat_pump',
      'current_temperature')|float(default=0) and
      state_attr('climate.hallway_heat_pump', 'temperature')|float(default=0) %}
        False
      {% else %}
        {{ (state_attr('climate.hallway_heat_pump', 'current_temperature')|float(default=0) - state_attr('climate.hallway_heat_pump', 'temperature')|float(default=0)) < 2 }}
      {% endif %}
condition:
  - condition: state
    entity_id: climate.hallway_heat_pump
    state: fan
    attribute: hvac_action
  - condition: state
    entity_id: input_boolean.hallway_fireplace_automation
    state: "on"
action:
  - service: climate.set_hvac_mode
    data:
      hvac_mode: heat
    target:
      entity_id:
        - climate.hallway_heat_pump
mode: single

The heat pump for the recreation room has identical automations to handle the basement fireplace.

I hope this help you towards adapting it for your purposes. Let me know if anything is unclear or if you find an improvement that you want to share!

Warmly, Per

Hi davidusb,

I probably could do it the way you’re suggesting. However, I don’t have the energy consumption for the pumps measured by a sensor. In addition, these air-to-air heat pumps have PID loops and they don’t draw constant current while they are heating. It depends on the difference between readback and setpoint.

My guess is that if I were to treat them as deferable loads it could lead to larger temperature variations than what the members of the household can accept. The scheme I’m using now accepts defeat in case the temperature drops to much even if the price is expensive, which is sort of what I want.

I’m eager to hear if you think this makes sense or if there is more to be had treating the pumps as deferrable loads!

My energy storage installation is coming up this weekend and based on the simulations I’ve been running using EMHASS I expect to see instant savings using the batteries. I’m still hoping that you will consider adding a way to differentiate between production price for PV and batteries to account for wear of the cells, but I understand the challenge in doing so.

:slight_smile:

Cheers, Per

I was trying to get this setup using the shell explained here EMHASS: An Energy Management for Home Assistant - #113 by haraldov in my config.yaml but I don’t understand how to make EMHASS use this in its optimization.

Here is my config setup:

hass_url: empty
long_lived_token: empty
costfun: cost
optimization_time_step: 30
historic_days_to_retrieve: 2
method_ts_round: nearest
set_total_pv_sell: false
lp_solver: COIN_CMD
lp_solver_path: /usr/bin/cbc
sensor_power_photovoltaics: sensor.power_photovoltaics
sensor_power_load_no_var_loads: sensor.power_load_no_var_loads
number_of_deferrable_loads: 2
list_nominal_power_of_deferrable_loads:
  - nominal_power_of_deferrable_loads: 12000
  - nominal_power_of_deferrable_loads: 750
list_operating_hours_of_each_deferrable_load:
  - operating_hours_of_each_deferrable_load: 5
  - operating_hours_of_each_deferrable_load: 8
list_peak_hours_periods_start_hours:
  - peak_hours_periods_start_hours: "02:54"
  - peak_hours_periods_start_hours: "17:24"
list_peak_hours_periods_end_hours:
  - peak_hours_periods_end_hours: "15:24"
  - peak_hours_periods_end_hours: "20:24"
list_treat_deferrable_load_as_semi_cont:
  - treat_deferrable_load_as_semi_cont: true
  - treat_deferrable_load_as_semi_cont: true
load_peak_hours_cost: 0.1
load_offpeak_hours_cost: 0
photovoltaic_production_sell_price: 0
maximum_power_from_grid: 13800
list_pv_module_model:
  - pv_module_model: CSUN_Eurasia_Energy_Systems_Industry_and_Trade_CSUN295_60M
list_pv_inverter_model:
  - pv_inverter_model: Fronius_International_GmbH__Fronius_Primo_5_0_1_208_240__240V_
list_surface_tilt:
  - surface_tilt: 30
list_surface_azimuth:
  - surface_azimuth: 205
list_modules_per_string:
  - modules_per_string: 16
list_strings_per_inverter:
  - strings_per_inverter: 1
set_use_battery: false
battery_discharge_power_max: 1000
battery_charge_power_max: 1000
battery_discharge_efficiency: 0.95
battery_charge_efficiency: 0.95
battery_nominal_energy_capacity: 5000
battery_minimum_state_of_charge: 0.3
battery_maximum_state_of_charge: 0.9
battery_target_state_of_charge: 0.6

Note that I do not have any PV or battery and am trying to use Nordpool for my dayahead load forecast.

So you if you have the add-on running, you just set your configuration and save it directly on the add-on configuration pane.
Then with the shell commands configured you should set up the automations to trigger the optimization when you want. When doing this check that the optimization is launched using the add-on log pane.
From your message is not completely clear to me what you have already done and at what point you are stuck.

I have set the configuration as shown and added the shell commands (below) in my configuration.yaml. When I then try to see the optimization it doesn’t show any dayahead forecast.

#EMHASS Day ahead price publishing
shell_command:
  publish_data: "curl -i -H 'Content-Type:application/json' -X POST -d '{}' http://localhost:5000/action/publish-data"
  
  post_nordpool_forecast: "curl -i -H 'Content-Type: application/json' -X POST -d '{\"load_cost_forecast\":{{(
        (state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'raw_tomorrow')|map(attribute='value')|list)[:24])
        }},\"prod_price_forecast\":{{(
        (state_attr('sensor.nordpool_kwh_se3_sek_3_10_025', 'raw_tomorrow')|map(attribute='value')|list)[:24])}}}' http://localhost:5000/action/dayahead-optim"
        
  dayahead_optim: "curl -i -H 'Content-Type: application/json' -X POST -d '{'def_total_hours':{{states('sensor.list_operating_hours_of_each_deferrable_load')}}}' http://localhost:5000/action/dayahead-optim"

Here is what I get from the add on log page:

s6-rc: info: service s6rc-oneshot-runner: starting
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service legacy-services: starting
services-up: info: copying legacy longrun emhass (no readiness notification)
s6-rc: info: service legacy-services successfully started
[2022-12-11 14:21:48,115] INFO in web_server: Launching the emhass webserver at: http://0.0.0.0:5000
[2022-12-11 14:21:48,115] INFO in web_server: Home Assistant data fetch will be performed using url: http://supervisor/core/api
[2022-12-11 14:21:48,115] INFO in web_server: The base path is: /usr/src
[2022-12-11 14:21:48,119] INFO in web_server: Using core emhass version: 0.3.21
[2022-12-11 14:22:24,559] INFO in web_server: EMHASS server online, serving index.html...
[2022-12-11 14:22:39,295] INFO in command_line: Setting up needed data
[2022-12-11 14:22:39,484] INFO in forecast: Retrieving weather forecast data using method = scrapper
[2022-12-11 14:22:43,460] INFO in command_line: Setting up needed data
[2022-12-11 14:22:43,475] INFO in web_server:  >> Publishing data...
[2022-12-11 14:22:43,482] INFO in command_line: Publishing data to HASS instance
[2022-12-11 14:22:43,689] INFO in retrieve_hass: Successfully posted value in a newly created entity_id
[2022-12-11 14:22:43,775] INFO in retrieve_hass: Successfully posted value in a newly created entity_id
[2022-12-11 14:22:43,859] INFO in retrieve_hass: Successfully posted value in a newly created entity_id
[2022-12-11 14:22:43,923] INFO in retrieve_hass: Successfully posted value in a newly created entity_id
[2022-12-11 14:22:43,991] INFO in retrieve_hass: Successfully posted value in a newly created entity_id
[2022-12-11 14:22:44,074] INFO in retrieve_hass: Successfully posted value in a newly created entity_id
[2022-12-11 14:22:45,743] INFO in forecast: Retrieving data from hass for load forecast using method = naive
[2022-12-11 14:22:45,745] INFO in retrieve_hass: Retrieve hass get data method initiated...
[2022-12-11 14:22:45,820] ERROR in retrieve_hass: The retrieved JSON is empty, check that correct day or variable names are passed
[2022-12-11 14:22:45,820] ERROR in retrieve_hass: 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)
[2022-12-11 14:22:45,821] ERROR in app: Exception on /action/dayahead-optim [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/dist-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/usr/local/lib/python3.9/dist-packages/emhass/web_server.py", line 134, in action_call
    input_data_dict = set_input_data_dict(config_path, str(config_path.parent), costfun,
  File "/usr/local/lib/python3.9/dist-packages/emhass/command_line.py", line 79, in set_input_data_dict
    P_load_forecast = fcst.get_load_forecast(method=optim_conf['load_forecast_method'])
  File "/usr/local/lib/python3.9/dist-packages/emhass/forecast.py", line 538, in get_load_forecast
    rh.get_data(days_list, var_list)
  File "/usr/local/lib/python3.9/dist-packages/emhass/retrieve_hass.py", line 144, in get_data
    self.df_final = pd.concat([self.df_final, df_day], axis=0)
UnboundLocalError: local variable 'df_day' referenced before assignment

I think I must have missed something