EMHASS: An Energy Management for Home Assistant

Thank you for this input.

That kind of forecast data can be shipped in a json and passed to EMHASS as a data parameter. I’m working on this so that users can be able to pass this kind of data.

What you’re describing is a rule-based approach to energy management. This is totally valid and based on the complexity of the rules it can be an efficient and robust approach. However, my claim with EMHASS, is that that kind of approach is by definition sub-optimal. In your case you are considering the load price forecast, so that’s great. But what about the PV power production in the future, or the house load demand, or the selling price evolution of excess PV power to the grid, the presence of a real battery like a power wall ??? All these are complex uncertainties. The goal of EMHASS is to propose an optimized approach to deal with all this complexity.

In EMHASS we have basically 4 forecasts to deal with:

  • PV power production forecast (internally based on the weather forecast and the characteristics of your PV plant)
  • Load power forecast: how much power on 30min blocks your house will demand on the next 24h
  • PV production selling price forecast: at what price are you selling your excess PV production on the next 24h
  • Load cost forecast: the price of the energy from the grid on the next 24h (the data that you already have)

The results of the optimization from EHMASS should help you to optimize even further your rule-based approach.

This further optimization based on forecast is needed the most when your system is complex, when you have storage devices and EVs and variable costs in time. The forecast will enable us to take action in advance in order to maximize profit or maximize auto-consumption from PV, etc.

3 Likes

I am looking forward to the further optimization that the LP model will provide, the rules based approach is OK, but the complexity is getting difficult to manage and I currently have no way to consider future PV production, so the price might be right to turn on a deferable load, but I may not have sufficient PV at that time to switch on without drawing from the grid.

HA has been really good in bringing together disparate systems, which goes a long way towards populating the EMHASS model.

  • PV power production forecast (internally based on the weather forecast and the characteristics of your PV plant)

SolCast & Forecast Solar gives me good hourly forecasts with 10/50/90 percentiles:

  • ‘06:00’:
    pv_estimate: 52.7
    pv_estimate10: 24.1
    pv_estimate90: 55.3
  • ‘07:00’:
    pv_estimate: 852.6
    pv_estimate10: 347.3
    pv_estimate90: 895.2
  • ‘08:00’:
    pv_estimate: 2440.2
    pv_estimate10: 1318.5
    pv_estimate90: 2542.2
  • Load power forecast: how much power on 30min blocks your house will demand on the next 24h

This is the tricky one.

I know what I used yesterday and last week, but a bit more difficult to predict tomorrow as this is a function of how many people are going to be home over what times, external climate, km driven in my EV,…

  • PV production selling price forecast: at what price are you selling your excess PV production on the next 24h

Feed In Forecasts Price
state_attr(‘sensor.amber_feed_in_forecast’, ‘forecasts’) |map(attribute=‘per_kwh’)|list}}

[0.22, 0.32, 0.29, 0.32, 0.32, 0.27, 0.21, 0.27, 0.21, 0.21, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.13, 0.21, 0.25, 0.32, 0.32, 0.29, 0.3, 0.29, 0.13, 0.21, 0.13, 0.11, 0.1, 0.1, 0.1, 0.1, 0.11, 0.11, 0.1, 0.13, 0.29, 0.32, 0.32, 0.32, 0.29, 0.33, 0.37, 0.51, 0.51, 0.37, 0.37, 0.37]

  • Load cost forecast: the price of the energy from the grid on the next 24h (the data that you already have)

General Price Forecasts
state_attr(‘sensor.amber_general_forecast’, ‘forecasts’) |map(attribute=‘per_kwh’)|list}}

[0.33, 0.44, 0.42, 0.44, 0.44, 0.39, 0.33, 0.39, 0.33, 0.33, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.24, 0.33, 0.38, 0.44, 0.44, 0.42, 0.42, 0.42, 0.24, 0.33, 0.24, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.21, 0.24, 0.42, 0.44, 0.45, 0.44, 0.42, 0.46, 0.5, 0.66, 0.66, 0.5, 0.5, 0.5]

1 Like

HA has been really good in bringing together disparate systems, which goes a long way towards populating the EMHASS model.

Agree…

SolCast & Forecast Solar gives me good hourly forecasts with 10/50/90 percentiles

I’m using a scrapping method on the clearoutside webpage. From what I see they are using the same weather forcast data from Forecsat solar, dar sky, etc… So that’s ok. The advantage that I see with EMHASS is that I’m using PVLib, which is proven to work really well using the actual physical model of I-V curves for PV modules and the actual inverter efficiency curve. So the converted PV power from EMHASS will be more precise at least than Forecast Solar. For SolCast I don’t know.

This is the tricky one.

Yes this is the tricky one!
For now as I said I’m just using the persistence model. It is far from perfect but is giving me some decent results. This is a very complex task what I’m willing to give it a shot to provide my own load forecast service. The good thing is that the framework to do it is there: the add-on environment with Python + a good forecast module. I’ve tried to achieve this with facebook prophet module with mitigated results and at the end not better than the persistance model. My conclusion at the time was that I needed to provide the forecast model with more regression variables, such as those that you cited: km driven with EV, expected number of people at home, the date (week-days/week-end), etc etc… I will try in the near future to obtain better load forecast results with this package: Time Series Made Easy in Python — darts documentation
It seems nice an very intuitive.

In any case for each of these 4 forecasts, the user will be able to directly provide their forecasts using other services and passing the data using json to EMHASS.

By the way with new version 0.1.17 you will be able to access the web ui from outside your LAN.

Hi; version v0.1.18 of this add-on is out.
You should be able to pass all your own forecast data from other HA services. The data can be simply passed as a numeric list using json data. Take a look at the add-on documentation for more information on how to achieve this.
Leave a message or open an issue on github if you encounter any problem.

Hi. I just released v0.1.19. Fixed a bunch of errors.
Enjoy!

thanks! Can you post a screenshot? Why would i want to use yours over the built in energy tab?

Hi! Just because they are not at all the same thing. You may find an explanation of what is this in the add-on documentation. There is also a screenshot of the web ui. Take a look here:

Essentially the built-in energy tab is just a dashboard of yours different power flows and energies. It will help you to visualize and understand how is the energy flow in your house at each hour of the day. You can then possibly build some automation rules to try to optimize you energy bill. This is however manual and the optimality is not guaranteed.

The emhass package and the add-on perform an actual mathematical optimization of the future energy flow of your home using linear programming. Is an optimal dispatch of your home energy. This is interesting as your home system will be more complex and a bunch of manual automations won’t guarantee you the best optimal solution. As an input you can provide your home load forecast, your PV power production forecast, your energy prices forecasts (consumed and produced), your systems characteristics, etc. As an output emhass will give you the optimal dispatch of your defined deferrable loads, for example: hot water rod, pool pump, storage battery, etc.

1 Like

New improved v0.1.24: Release EMHASS add-on v0.1.24 · davidusb-geek/emhass-add-on · GitHub

Just working my way through the PVLib settings.

I have two SolarEdge 7 kW 3 phase inverters model SE7K-AUBTEBEU4
and 18.5 kW of panels (50x370W Winaico panels) arranged in four strings east/ west facing on 10 deg tilts.

I have checked in the pvlib library and cannot see these models:

How can I specify generic system parameters on the add-on configuration dialog/ yaml?

Hi, if you cannot find your exact models then just pick one with similar nominal power sizes for both the inverter and the panels. You should be able to find this. This is not ideal but it will still be much better than simpler PV modeling approaches. For our purposes PV panels IV curves and power inverters efficiencies curves are fairly similar from one model to another.
These libraries are regularly updated and they add the new inverters and panels models. So let’s hope that they include yours in a next update.

BTW v0.1.38 is released: Release EMHASS add-on v0.1.38 · davidusb-geek/emhass-add-on · GitHub

Hi, in your case you should be almost good with this model from the PVLib CEC database: SolarEdge Technologies Ltd : SE7600A-US [240V]

There are two important things that will be considered when modeling the PV array:

  1. The inverter efficiency. In this case if you choose a similar inverter from the same manufacturer and in a similar power range it should be good enough. The efficiency curve as a function of the inverter power will be fairly similar.

  2. The maximum AC output from the inverter. This should be a little bit more problematic because a different max nominal power will mean that the simulation may throw a higher (or lower) power output that you may actually get on your real system. I can see that for the present model on the CEC database it will differ from yours on roughly 625W. That may not be much and for our purposes sufficiently low to get some good usable results from this simulation. I may introduce a user given max PV output parameter to the add-on configuration to deal with these special cases.

1 Like

Thanks,

I ended up with that model. The trick is getting all the special characters and replacing them with ‘_’.

I have two inverters each with one string of 25 panels on each, challenge is I have 21 panels East facing and 29 West facing, so it doesn’t exactly line up with my strings as SolarEdge uses optimisers so each panel more or less runs independently. You can see here inverter 1 is not reporting.

I have Winaico 370W mono panels so I just picked something close and set up with 21 & 29 panels on each string, which seems to give pretty close results.

pv_module_model: Advance_Power_API_M370,Advance_Power_API_M370
pv_inverter_model: >-
  SolarEdge_Technologies_Ltd___SE7600A_US__208V_,SolarEdge_Technologies_Ltd___SE7600A_US__208V_
surface_tilt: 10,10
surface_azimuth: 90,270
modules_per_string: 29,21
strings_per_inverter: 1,1
1 Like

This emhass module is now on its version >> v0.3.11: Release EMHASS version 0.3.11 · davidusb-geek/emhass · GitHub

Lots of improvements since v0.3.0… A new docker standalone mode is now fully functional.

I have started using ApexCharts card - A highly customizable graph card to visualise some of the EMHASS data as an alternative to the local UI.

@kc_au @ThirtyDursty @madpilot

image

type: custom:apexcharts-card
span:
  start: minute
header:
  show: true
  title: EMHASS Forecasts
  show_states: true
  colorize_states: true
now:
  show: true
  label: now
series:
  - entity: sensor.p_pv_forecast
    curve: stepline
    show:
      in_header: before_now
    stroke_width: 1
    data_generator: |
      return entity.attributes.forecasts.map((entry) => {
        return [new Date(entry.date), entry.p_pv_forecast];
      });
  - entity: sensor.p_batt_forecast
    curve: stepline
    show:
      in_header: before_now
    stroke_width: 1
    data_generator: |
      return entity.attributes.forecasts.map((entry) => {
        return [new Date(entry.date), entry.p_batt_forecast];
      });
  - entity: sensor.p_load_forecast
    curve: stepline
    show:
      in_header: before_now
    stroke_width: 1
    data_generator: |
      return entity.attributes.forecasts.map((entry) => {
        return [new Date(entry.date), entry.p_load_forecast];
      });
  - entity: sensor.p_deferrable0
    curve: stepline
    stroke_width: 1
    show:
      in_header: before_now
    data_generator: |
      return entity.attributes.deferrables_schedule.map((entry) => {
        return [new Date(entry.date), entry.p_deferrable0];
      });
  - entity: sensor.p_deferrable1
    curve: stepline
    stroke_width: 1
    show:
      in_header: before_now
    data_generator: |
      return entity.attributes.deferrables_schedule.map((entry) => {
        return [new Date(entry.date), entry.p_deferrable1];
      });

Works well for my energy provider as well:

image

type: custom:apexcharts-card
experimental:
  color_threshold: true
graph_span: 24h
span:
  start: minute
header:
  show: true
  title: Amber Electricty Forecast
  show_states: true
  colorize_states: true
series:
  - entity: sensor.amber_general_forecast
    float_precision: 2
    show:
      in_header: after_now
    color_threshold:
      - value: 0
        color: cyan
      - value: 0.16
        color: green
      - value: 0.2
        color: yellow
      - value: 0.3
        color: red
    name: price kwh
    data_generator: |
      return entity.attributes.forecasts.map((entry) => {
        return [new Date(entry.start_time), entry.per_kwh];
      });
yaxis:
  - min: 0
    max: 1
    decimals: 2
    apex_config:
      forceNiceScale: true

My EMHASS config file:

web_ui_url: 0.0.0.0
hass_url: empty
long_lived_token: empty
costfun: profit
optimization_time_step: 30
historic_days_to_retrieve: 2
method_ts_round: first
set_total_pv_sell: false
lp_solver: COIN_CMD
lp_solver_path: /usr/bin/cbc
sensor_power_photovoltaics: sensor.apf_generation_entity
sensor_power_load_no_var_loads: sensor.power_load_no_var_loads
number_of_deferrable_loads: 4
list_nominal_power_of_deferrable_loads:
  - nominal_power_of_deferrable_loads: 1500
  - nominal_power_of_deferrable_loads: 5500
  - nominal_power_of_deferrable_loads: 11500
  - nominal_power_of_deferrable_loads: 2400
list_operating_hours_of_each_deferrable_load:
  - operating_hours_of_each_deferrable_load: 4
  - operating_hours_of_each_deferrable_load: 2
  - operating_hours_of_each_deferrable_load: 2
  - operating_hours_of_each_deferrable_load: 1
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
  - treat_deferrable_load_as_semi_cont: false
  - treat_deferrable_load_as_semi_cont: false
load_peak_hours_cost: 0.1907
load_offpeak_hours_cost: 0.1419
photovoltaic_production_sell_price: 0.065
maximum_power_from_grid: 30000
list_pv_module_model:
  - pv_module_model: Advance_Power_API_M370
  - pv_module_model: Advance_Power_API_M370
list_pv_inverter_model:
  - pv_inverter_model: SolarEdge_Technologies_Ltd___SE7600A_US__208V_
  - pv_inverter_model: SolarEdge_Technologies_Ltd___SE7600A_US__208V_
list_surface_tilt:
  - surface_tilt: 18
  - surface_tilt: 10
list_surface_azimuth:
  - surface_azimuth: 90
  - surface_azimuth: 270
list_modules_per_string:
  - modules_per_string: 29
  - modules_per_string: 21
list_strings_per_inverter:
  - strings_per_inverter: 1
  - strings_per_inverter: 1
set_use_battery: true
battery_discharge_power_max: 5264
battery_charge_power_max: 5000
battery_discharge_efficiency: 0.95
battery_charge_efficiency: 0.95
battery_nominal_energy_capacity: 13500
battery_minimum_state_of_charge: 0.05
battery_maximum_state_of_charge: 1
battery_target_state_of_charge: 0.1
nominal_power_of_deferrable_loads: 5500,1500,7000,3000
operating_hours_of_each_deferrable_load: 10,16,3,1
peak_hours_periods_start_hours: 02:54,17:24
peak_hours_periods_end_hours: 15:24,20:24
pv_module_model: Advance_Power_API_M370,Advance_Power_API_M370
pv_inverter_model: >-
  SolarEdge_Technologies_Ltd___SE7600A_US__208V_,SolarEdge_Technologies_Ltd___SE7600A_US__208V_
surface_tilt: 10,10
surface_azimuth: 90,270
modules_per_string: 29,21
strings_per_inverter: 1,1
4 Likes

Here are some of my configurations to get EMHASS working with Amber Electric (Australia) Custom Component.

@madpilot @kc_au @ThirtyDursty

The magic happens in the shell commands:

shell_command:
  dayahead_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{}' http://localhost:5000/action/dayahead-optim"
  publish_data: "curl -i -H \"Content-Type: application/json\" -X POST -d '{}' http://localhost:5000/action/publish-data "
  post_amber_forecast: "curl -i -H 'Content-Type: application/json' -X POST -d '{\"prod_price_forecast\":{{(
          state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)
          }},\"load_cost_forecast\":{{(
          state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)
          }}}' http://localhost:5000/action/dayahead-optim"
  post_emhass_forecast: "curl -i -H 'Content-Type: application/json' -X POST -d '{\"prod_price_forecast\":{{(
          state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)
          }},{{states('sensor.solcast_24hrs_forecast')}},\"load_cost_forecast\":{{(
          state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)
          }}}' http://localhost:5000/action/dayahead-optim"

  post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":{{(
          ([states('sensor.amber_general_price')|float(0)] +
          state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)[:48])
          }}, \"prod_price_forecast\":{{(
          ([states('sensor.amber_feed_in_price')|float(0)] +
          state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)[:48]) 
          }}, \"prediction_horizon\":{{min(48,
          (state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)
          }},\"soc_init\":{{states('sensor.powerwall_charge')|float(0)/100}},\"soc_final\":0.05,\"def_total_hours\":[8,3,2,2]}' http://localhost:5000/action/naive-mpc-optim"

But let me unpack this for you first, I recommend you do a lot of work in the Developer Tools Template first.

{{state_attr('sensor.p_batt_forecast', 'forecasts')|map(attribute='p_batt_forecast')|list|length}}
{{state_attr('sensor.p_batt_forecast', 'forecasts')|map(attribute='p_batt_forecast')|list}}

"soc_init":{{states('sensor.powerwall_charge')|float(0)/100}}
"prediction_horizon":{{min(48,state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length+1)}}
"load_cost_forecast":{{([states('sensor.amber_general_price')|float] + 
                         state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)[:48]}}
"prod_price_forecast":{{([states('sensor.amber_feed_in_price')|float] + 
                         state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)[:48]}}
"load_now": {{(states('sensor.powerwall_load_now')|float(0)*1000)|round(0)}}
"pv_now": {{(states('sensor.powerwall_solar_now')|float(0)*1000)|round(0)}}
"def_total_hours [EV 11 kW]": {{ state_attr('sensor.duka_charging_rate_sensor','time_left')|int(2)}}
"def_total_hours [Pool Filter 1.4 kW]": 4
"def_total_hours [HVAC humidity 4 kW]": {{max(0,(state_attr('climate.family','current_humidity')|int(0) - 60)/10)|int(0)}}
"def_total_hours [HVAC temp 4 kW]": {{max(0,(state_attr('climate.bedroom','current_temperature')|float(0) -
                                        state_attr('climate.daikin_ap46401','temperature')|float))}}
"def_total_hours [HVAC No People 4 kW]": {{states('zone.home')}}
"def_total_hours [Pool Heater 5 kW]": {{states('input_number.pool_temperature_set_point')|int - 
                                   states('input_number.pool_temperature')|int}}

curl -i -H "Content-Type: application/json" -X POST -d '{"prod_price_forecast":{{(
             (state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list) )
          }},"load_cost_forecast":{{(
             (state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list) )
          }},"prediction_horizon":{{(state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)
          }},"soc_init":{{states('sensor.powerwall_charge')|float(0)/100
          }},"soc_final":0.05,"def_total_hours":[4,5,3,1]}' http://localhost:5000/action/naive-mpc-optim

  post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"prod_price_forecast\":{{(
          [states('sensor.amber_feed_in_price')|float(0)] +
          (state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)[:47]) 
          }},\"load_cost_forecast\":{{(
          [states('sensor.amber_general_price')|float(0)] +
          (state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)[:47])
          }},\"prediction_horizon\":{{min(48,
          (state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)
          }},\"soc_init\":{{states('sensor.powerwall_charge')|float(0)/100}},\"soc_final\":0.05,\"def_total_hours\":[4,5]}' http://localhost:5000/action/naive-mpc-optim"

My Automations, either a single day-ahead optimisation or MPC running every minute.

alias: EMHASS day-ahead optimization
description: ''
trigger:
  - platform: time_pattern
    minutes: '25'
    hours: '5'
condition: []
action:
  - service: shell_command.post_amber_forecast
    data: {}
  - service: shell_command.publish_data
    data: {}
mode: single
alias: EMHASS MPC optimization
description: ''
trigger:
  - platform: time_pattern
    minutes: /1
condition: []
action:
  - service: shell_command.post_mpc_optim
    data: {}
  - service: shell_command.publish_data
    data: {}
mode: single
alias: p_deferable1 automation
description: ''
trigger:
  - platform: numeric_state
    entity_id: sensor.p_deferrable1
    above: '0.1'
    for:
      hours: 0
      minutes: 2
      seconds: 0
  - platform: numeric_state
    entity_id: sensor.p_deferrable1
    for:
      hours: 0
      minutes: 2
      seconds: 0
    below: '0.1'
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_deferrable1
            above: '0.1'
        sequence:
          - type: turn_on
            device_id: 03a766ec3275e2c80020c5f5a3d8e603
            entity_id: switch.pool_heater_pump
            domain: switch
          - service: notify.mobile_app_pixel_6
            data:
              message: Pool Heater on
    default:
      - type: turn_off
        device_id: 03a766ec3275e2c80020c5f5a3d8e603
        entity_id: switch.pool_heater_pump
        domain: switch
      - service: notify.mobile_app_pixel_6
        data:
          message: Pool Heater off
mode: single
alias: p_batt automation
description: ''
trigger:
  - platform: numeric_state
    entity_id: sensor.p_batt_forecast
    below: '-4000'
condition: []
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            below: '-3000'
        sequence:
          - service: notify.mobile_app_pixel_6
            data:
              title: p_batt alert {{states('sensor.p_batt_forecast')}} - mode:backup
              message: d{{states('sensor.amber_general_price')}} $/kWh
          - service: tesla_gateway.set_operation
            data:
              real_mode: backup
      - conditions:
          - condition: numeric_state
            entity_id: sensor.p_batt_forecast
            above: '4900'
        sequence:
          - service: tesla_gateway.set_operation
            data:
              real_mode: autonomous
              backup_reserve_percent: 1
          - service: notify.mobile_app_pixel_6
            data:
              title: >-
                p_batt alert {{states('sensor.p_batt_forecast')}} -
                mode:autonomous
              message: d{{states('sensor.amber_general_price')}} $/kWh
    default:
      - service: notify.mobile_app_pixel_6
        data:
          title: >-
            p_batt alert {{states('sensor.p_batt_forecast')}} -
            mode:self_consumption
          message: d{{states('sensor.amber_general_price')}} $/kWh
      - service: tesla_gateway.set_operation
        data:
          real_mode: self_consumption
          backup_reserve_percent: 2
mode: single
6 Likes

Automation to get Tesla Powerwall Gateway to discharge to grid at 0700 and 1700 for 60 minutes (during sunrise/ sunset peak) for maximum FIT and to help the grid when under stress.

I recommend getting the excellent TeslaPy libray talking to your powerwall first. (You need the cache.json anyway)

Update: this can all now be controlled with Tesla Custom Integration

You need to do some setup first:

Tonight during the price spike event I had Home Assistant switch PW2 to Time Based Control and my battery started exporting at 5 kW, until 1800 when HA switched the PW2 back to self powered mode and stopped exporting. Needs the following TOU settings to be pre-loaded to PW2, but I find the highest FIT has been occuring around this time regularly so I can automate with HA to control the mode switching.

I do the following to discharge PW2 at 5 kW during peak FIT between 5pm - 6pm.

Setup time of use settings and prices per the attached screenshot.

Switch battery to Self-Powered and it will store and consume excess solar to match household production and load.

Switch to Time-Based Control and the Battery will charge from the grid during off peak window and discharge to the grid during peak (and sometimes mid peak).

So at 6am this morning TBC mode discharged the battery to get maximum FIT. At 1030 it started consuming excess solar and charging from the grid (upto 5 kW). At 1330 it (generally) stops charging from the grid but still charges off excess solar. At 1700 ideally your battery is at 100% and it will start discharging at 5kW as it tries to empty battery before next off peak window at 1800 to gain maximum FIT for the day.

The next step is very important, before 1800 switch back to self-consumption mode otherwise it will start charging from the grid at a very expensive price. There are some new advanced grid controls that would mitigate this.

You can edit the price schedule in the app to extend discharging window. Best I have done is $60 credit during price spike event. But be aware changing the schedule doesn’t take effect immediately I find changes take effect after the next quarter hour block (IE minute 0,15,30 or 45).

If you are uncomfortable with what the battery is doing, put it back into self-powered mode and it should settle within seconds.

You can tell battery to charge at any time by increasing reserve % (albeit slower at 3.3 kW).

I find this method extends the charging/ discharging windows for longer than SmartShift, if that is what you want. Works well with Amber pricing being so different at different times.

Home Assistant/ python scripts allow you to change between modes; self_consumption, backup (100% reserve) and autonomous (time based control) or set reserve % directly, so you can automate the above process based off your own rules. Home Assistant doesn’t allow you to change your tou windows.

This is actually quite helpful as it is supplying extra capacity to the grid when grid is under stress and you gain access to higher FIT and the financial benefits.

3 Likes

Nice setup, thanks for the sharing. This can be really helpful for Amber AU users :+1:

1 Like

Nice graphics also with the ApexCharts! There is also the option of the Plotly card from HACS. The local UI is using the Plolty library for Python charts… That local UI is just intended for debugging when setting up emhass.

HI @markpurcell , I cant send you enough Thank You’s and if I ever meet you, beers are on me!

I will have a few questions, but here is my first:

Your calling “sensor.solcast_24hrs_forecast”. What value are you populating here? I am using the HACS Solcast Integration and my options are Forecast Today, Forecast Today Remaining or Forecast Tomorrow. All returns a single instance value ie/ 40KW for today. Are you derving this value in YAML or how are you collecting this info? Are you using the core Solcast HACS or are you using another version?

2 Likes

Ah, you found that one…

I would focus on just getting amber buy/sell prices first and use the inbuild pvlib estimation for solar production which is pretty good. post_amber_forecast

You don’t need to use all of those scripts at the same time, rather they are different ways to populate the future forecasts.

I have a vision of submitting both actual current and forecast pv production, which is where that is going.

Unfortunately the solcast integration only provides 60 minute resolution and I wanted to run emhass on 30 minute resolution to match the amber pricing windows.

A lot of great discussion and visualisation for SolCast here: REST API command/platform fails on POST to external URL (solcast) - #132 by safepay

Something like this to grab the solcast data direct, I still need to convert kW to W and get into correct sensor (note sensors have 255 character limits - which can be exceeded when having a full list of 24 hrs - hence the use of attributes):

- platform: rest
  name: "Solcast Forecast Data"
  json_attributes:
    - forecasts
  resource: https://api.solcast.com.au/rooftop_sites/SOLCAST_RESOURCE_ID/forecasts?format=json&api_key=SOLCAST_API_KEY&hours=24
  method: GET
  value_template: "{{ value_json.forecasts[0].pv_estimate|round(2) }}"
  unit_of_measurement: "W"
  device_class: power
  scan_interval: 00:30
  force_update: true