EMHASS: An Energy Management for Home Assistant

Hi, I’ve just updated this in the documentation.

Hi David,

Thank you for a very cool project!

I’ve followed the example from haraldov to get a list from Nordpool as well as the example in The forecast module — emhass 0.3.18 documentation to get SolCast forecast data.

I’ve defined these shell_commands:

post_nordpool_forecast:
‘curl -i -H ‘‘Content-Type: application/json’’ -X POST -d ‘’{“load_cost_forecast”:{{(
(state_attr(’‘sensor.nordpool’’, ‘‘raw_tomorrow’’)|map(attribute=’‘value’’)|list)[:24])
}},“prod_price_forecast”:{{(
(state_attr(’‘sensor.nordpool’’, ‘‘raw_tomorrow’’)|map(attribute=’‘value’’)|list)[:24])}}}’’ http://localhost:5000/action/dayahead-optim

post_mpc_optim_solcast:
‘curl -i -H ‘‘Content-Type: application/json’’ -X POST -d ‘’{“load_cost_forecast”:{{(
(state_attr(’‘sensor.nordpool’’, ‘‘raw_tomorrow’’)|map(attribute=’‘value’’)|list)[:24])
}},“prod_price_forecast”:{{(
(state_attr(’‘sensor.nordpool’’, ‘‘raw_tomorrow’’)|map(attribute=’‘value’’)|list)[:24])
}}, “pv_power_forecast”:{{states(’‘sensor.solcast_24hrs_forecast’’)
}}}’’ http://localhost:5000/action/naive-mpc-optim

When I use the shell_command post_nordpool_forecast it seems to work and I get a list for the entire , but when I use post_mpc_optim_solcast the list stops at 10 am. I have a feeling it has to do with the fact that solcast sends 48 values, but Nordpool only sends 24 values, but I’m not sure.

Is there a way to combine Nordpool data with solcast forecast data?

Warmly, Per Takman

Hi, what do you mean by combine? Nordpool is giving you load cost and production prices forecasts in currency units while Solcast is giving you PV power forecast in Watts. How to combine different quantities? Or I don’t understand your problem with that.

The data is being truncated when using MPC because of the working principle of that algorithm and the prediction horizon parameter.

To control that you need to define additional parameters when using MPC, for example :

"prediction_horizon":10,soc_init":0.5,"soc_final":0.6,"def_total_hours":[1,3]

…if you have a battery and two deferrable loads.

Hi! I was not referring to combining price with watts. :slight_smile: I thought something was wrong becuase I did not see a result that covered the entire next day. My assumption was that 24 datapoints from Nordpool vs. 48 datapoints from solcast caused the problem.

From your answer I take it that MPC does not offer a prediction for the entire next day. Sounds like I need to study this in more detail.

@per.takman

Nordpool publish tomorrow power prices every day at 13:00. Sometimes the Nordpool plugin do not update the prices. I use a automation which trigger the shell command at 23:57 every day. I then get the prices from 00:00 the next day in emhass.

alias: EMHASS day-ahead optimization

description: ""
trigger:
  - platform: time
    at: "23:57:00"
condition: []
action:
  - service: shell_command.post_nordpool_forecast
    data: {}
mode: single

You can see if the tomorrow price data is available with Developer Tools->State:

image
If you are sending emty raw_tomorrow list the column unit_load_cost and the cost_profit in the emhass webpage do not update. If it work check also the price data are in the correct time index.

The shell_command I use now is this one:

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'', ''raw_tomorrow'')|map(attribute=''value'')|list)[:24])

    }},"prod_price_forecast":{{(

    (state_attr(''sensor.nordpool'', ''raw_tomorrow'')|map(attribute=''value'')|list)[:24])}}}'' http://localhost:5000/action/dayahead-optim'

Hi again,

Sorry about not being clear in my first post. I believe that I’ve followed the instruction now, but I still think that the fact that Nordpool publish 24 values and solcast publish 48 values cause a problem. Please bear with me.

After stumbling a bit on the syntax in Studio Code Server I now have the following shell commands:

dayahead_optim:
  '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'

mpc_optim:
  '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])
  }}, "pv_power_forecast":{{states(''sensor.solcast_24hrs_forecast'')
  }}, "prediction_horizon":48,"soc_init":{{(states(''sensor.r2_d2_battery_level'')|float(0))/100
  }},"soc_final":0.05,"def_total_hours":[2]}'' http://localhost:5000/action/naive-mpc-optim'

publish_data: "curl -i -H 'Content-Type:application/json' -X POST -d '{}' http://localhost:5000/action/publish-data"

dayahead_optim and publish_data both execute sucessfully, but mpc_optim generate the following log trace in the EMHASS add-on:

[2022-09-12 22:57:35,264] INFO in command_line: Setting up needed data
[2022-09-12 22:57:35,272] INFO in retrieve_hass: Retrieve hass get data method initiated...
[2022-09-12 22:57:36,221] INFO in forecast: Retrieving weather forecast data using method = list
[2022-09-12 22:57:36,231] INFO in forecast: Retrieving data from hass for load forecast using method = naive
[2022-09-12 22:57:36,233] INFO in retrieve_hass: Retrieve hass get data method initiated...
[2022-09-12 22:57:39,148] ERROR in app: Exception on /action/naive-mpc-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 112, in set_input_data_dict
    df_input_data_dayahead = copy.deepcopy(df_input_data_dayahead)[df_input_data_dayahead.index[0]:df_input_data_dayahead.index[prediction_horizon-1]]
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/indexes/base.py", line 5039, in __getitem__
    return getitem(key)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/arrays/datetimelike.py", line 341, in __getitem__
    "Union[DatetimeLikeArrayT, DTScalarOrNaT]", super().__getitem__(key)
  File "/usr/local/lib/python3.9/dist-packages/pandas/core/arrays/_mixins.py", line 272, in __getitem__
    result = self._ndarray[key]
IndexError: index 47 is out of bounds for axis 0 with size 24
  1. Is there a way to use MPC together with data from Nordpool? Should I be using a different service for pv_power_forecast with 60 minute intervals?
  2. Is it sufficient to only use dayahead_optim once a day and then publish every 5 minutes?
  3. Does anybody have good example how to control battery based on sensor.p_batt_forecast?

Cheers, Per Takman

You need to ensure that the data you pass have the same number of elements.

Either 24 x60 minute intervals or 48 x30 minute intervals you can’t mix 24 values for price and 48 values for production.

I would suggest you just focus on price only and use the internal pvlib solar forecast to start.

In your case you have 24 x60 price forecasts so you need to change your time interval to 60 minutes.

Using the internal pvlib solar forecast is reasonable, but don’t worry if you don’t have exact models to match.

Once you get EMHASS writing with price forecasts, then as a second stage you can look to integrate the external solar forecasts.

Hi Mark,

I’ve already set the optimization time step to 60 to make Nordpool with their 24 data points work.

Your suggestion to use the internal pvlib solar forecast sounds good. Can I do this by simply removing the line

  }}, "pv_power_forecast":{{states(''sensor.solcast_24hrs_forecast'')

in my shell command mpc_optim?

The new shell command would then be:

mpc_optim:
  '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])
  }}, "prediction_horizon":48,"soc_init":{{(states(''sensor.r2_d2_battery_level'')|float(0))/100
  }},"soc_final":0.05,"def_total_hours":[2]}'' http://localhost:5000/action/naive-mpc-optim'

Thank you in advance!

/Perr

Yes that is looking simpler, which is easier to debug.

You should also change prediction_horizon from 48 to 24 to match the 24 elements you are passing.

It really depends on which battery you have and the controls available to you in Home Assistant.

I have a Tesla powerwall2 and use the Tesla Gateway custom integration.

One automation that sets backup_reserve_percent based off the EMHASS state of charge forecast:

alias: Battery SOC Forecast
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.soc_batt_forecast
condition: []
action:
  - service: tesla_gateway.set_reserve
    data:
      backup_reserve_percent: "{{states('sensor.soc_batt_forecast')|int(0)-5}}"
mode: single

I also have an alternative method by changing the battery modes, which roughly does the right thing. This also has some alerts so I can monitor the mode changes.

alias: p_batt automation
description: ""
trigger:
  - platform: numeric_state
    entity_id: sensor.p_batt_forecast
    below: "-1000"
  - platform: numeric_state
    entity_id: sensor.p_batt_forecast
    above: "-1000"
    below: "4900"
  - platform: numeric_state
    entity_id: sensor.p_batt_forecast
    above: "4900"
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            below: "-1000"
        sequence:
          - service: notify.mobile_app_pixel_6
            data:
              title: p_batt alert {{states('sensor.p_batt_forecast')}} - mode:backup
              message: price:{{states('sensor.amber_general_price')}} $/kWh
          - service: tesla_gateway.set_operation
            data:
              real_mode: backup
              backup_reserve_percent: 3
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: "4900"
            enabled: false
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: autonomous
              backup_reserve_percent: 1
            enabled: false
          - service: notify.mobile_app_pixel_6
            data:
              title: >-
                p_batt alert {{states('sensor.p_batt_forecast')}} - consider
                mode:autonomous
              message: Price:{{states('sensor.amber_general_price')}} $/kWh
    default:
      - service: tesla_gateway.set_operation
        data:
          real_mode: self_consumption
          backup_reserve_percent: 2
      - service: notify.mobile_app_pixel_6
        data:
          title: >-
            p_batt  alert {{states('sensor.p_batt_forecast')}} -
            mode:self_consumption
          message: Price:{{states('sensor.amber_general_price')}} $/kWh
mode: single

Thank you Mark!

I no longer get errors after reducing the prediction horizon to 24 instead of 48 regardless of whether I use mpc_optim or mpc_optim3 where I use solcast_24hrs_forecast. However, I get the impression that I either should not run it directly after a dayahead_optim or that something else is wrong.

mpc_optim:
  '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])
  }}, "prediction_horizon":24,"soc_init":{{(states(''sensor.r2_d2_battery_level'')|float(0))/100
  }},"soc_final":0.05,"def_total_hours":[2]}'' http://localhost:5000/action/naive-mpc-optim'

mpc_optim3:
  '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])
  }}, "pv_power_forecast":{{states(''sensor.solcast_24hrs_forecast'')
  }}, "prediction_horizon":24,"soc_init":{{(states(''sensor.r2_d2_battery_level'')|float(0))/100
  }},"soc_final":0.05,"def_total_hours":[2]}'' http://localhost:5000/action/naive-mpc-optim'

The EMHASS log looks like below:

[2022-09-12 23:46:04,315] INFO in command_line: Setting up needed data
[2022-09-12 23:46:04,326] INFO in retrieve_hass: Retrieve hass get data method initiated...
[2022-09-12 23:46:05,427] INFO in forecast: Retrieving weather forecast data using method = list
[2022-09-12 23:46:05,436] INFO in forecast: Retrieving data from hass for load forecast using method = naive
[2022-09-12 23:46:05,438] INFO in retrieve_hass: Retrieve hass get data method initiated...
[2022-09-12 23:46:08,698] INFO in web_server:  >> Performing naive MPC optimization...
[2022-09-12 23:46:08,698] INFO in command_line: Performing naive MPC optimization
[2022-09-12 23:46:08,726] INFO in optimization: Perform an iteration of a naive MPC controller
[2022-09-12 23:46:08,896] INFO in optimization: Status: Infeasible
[2022-09-12 23:46:08,897] INFO in optimization: Total value of the Cost function = 0.0

What does Status: Infeasible mean? The total value of the cost function is zero.

My understanding is the nordpool pricing is only updated once a day. There are some considerations you need to take into effect.

You will get a reasonable optimisation from EMHASS if you only call the optimisation once a day as well. For debugging purposes you can call many times whilst trying to setup.

Can you drop your shell command into the developer template section so we can see the expansion of variables.

Whilst you are setting up, drop def_hours to 0 until you get the basic functionality working.

EMHASS expects the list of prices to be relative to the current time. Thus the first price in the list should correspond to the first timeslot (ie next 60 minutes), the second element in the list should correspond to the next timeslot and so on. So if you call the optimisation at 09:45, it is expecting to see the prices for 10:00, 11:00, and so on.

My understanding is the nordpool sensor is only updated every 24 hrs. I’m not sure what time reference they use, but for example if the nordpool data always starts at midnight, the first element in the list will always refer to 01:00, the second element 02:00 and so on. It is upto you to ensure the data fed to EMHASS referes to the correct time slot, alternatively you can call the optimisation once a day at the correct time.

Can you also share what you see at http://homeassistant.local:5000 which should show the results after an optimisation.

Nordpool offers todays prices starting from 00 to 01 and so on. In addition, they publish next day prices at 13 every day. This means that the first element in the list I’m sending is for 00 to 01.

To me it sounds like I should stick with the dayahead_optim and skip MPC for now.

That sounds sensible.

MPC only improves the optimisation when your variables are changing very quickly.

My energy provider updates and changes their prices every 5 minutes, based off the national energy market wholesale bidding prices so for me the added complexity of getting MPC functional had a lot of benefits.

I’m still in the plan and prepare phase for our solar panel and battery storage investment, which is why I’m playing around with this add-on.

One thing I’ve been wondering is how people with battery storage solutions factor in the cost of using the battery for a charge/discharge cycle. Some days are more profitable than others and some days the savings may not justify using the battery due to battery aging.The storage system has an investment cost and a finite lifetime.

Do you somehow factor in the cost of using a kWh in EMHASS or do you simply hope that the difference in price between charge/discharge exceed the cost of the investment per kWh every day?

Warmly, Per

EMHASS doesn’t currently take into account battery degradation in its costing model. I suppose you could use a lower efficiency value to represent a reduced value. EMHASS is really good for doing what if analysis for the impact if you double battery size or solar array size.

EMHASS does take account of the cost to charge and discharge, including efficiency and depending on the cost model you select will only charge/ discharge your battery if it meets the objectives of maximise profit or self consumption.

Have a look at the Web UI, to see the details for each time period.

.

I do have some templates that calculate the daily savings from battery and solar. But that is interested to EMHASS.

that

I just cant get into the web-ui.
What am I doing wrong :stuck_out_tongue: Yeah I know, how could you guys know…
But, I was hoping it was a known issue with noobs like me.

The log says everything starts OK, but the web-ui just wont show up.
I have uninstalled the addon, and installed it again, still not working.

Any ideas, or any special information you need from me to help me out?

Hi, just install the latest version of the add-on and with the add-on running go to: https://<your_ha_device_ip_address>:5000

Yeah. i found another address that worked (the button navigates to a url that wont work for me.).
Thank you !

Hi, great work on this add-on. I’m configuring it for my setup and I’ve got a question about the configuration. How do I setup multiple PV inverters and multiple batteries? I see I can add the config for one PV plant but I have two and they have different orientation, panels and inverters. For the batteries the same. I have home batteries and an EV.