Automated Octopus Saving Sessions with Solax X1 Hybrid G4

Having done a few automations for my solar & battery setup (Solax X1 Hybrid G4 (local & cloud API)) last year, I’ve set myself another challenge: Octopus Saving Sessions.

What’s important this year, we can also get rewarded for exported electricity rather than just reducing import. With that in mind, I successfully supported the first 4 sessions by manually following all the steps:

  1. Joining the session
  2. Pre-charging or topping up the battery (if required)
    • Enabling second charging period
    • Updating the forced charge stop to just before the Saving Session start time
  3. Forcing discharge
    • Setting inverter to Manual mode
    • Setting the Manual mode behaviour to Forced Discharge
  4. Re-setting back to normal operation
    • Disabling the second charging period
    • Setting the interter back to Self Use mode

Having confidence these steps had the expected effect, it was time to automate!

I’m sharing this so that you can use these automations as is or try to improve them further, as I’m sure there is probably an easier and better way to achieve this.

Screenshots

Waiting for a session:

Upcoming session:

Duing a session:

After a session

Design

Before jumping into describing each of the automations, I want to first explain the concepts and thinking behind this.

Assuming a Saving Session has already been joined, the next thing is to determine if there is a session later in the day - this is required to top up the battery ahead of the session start.

In addition, a number of other automations get enabled:

  • Start watching for session start
  • Start watching battery % (SOC) and inverter mode - one of the triggers to resume normal operation once battery has discharged

The two helper fields (Saving Session Start time and the Saving Session Today are not only to help with automations, but also provide ability to overide these values manually if required.

Configuration files

For all my setup, including the configs and automations used in this article, please see my github repo .

Automations

Joining a session

Luckily, there is a great HACS integration for Octopus: GitHub - BottlecapDave/HomeAssistant-OctopusEnergy: Unofficial Home Assistant integration for interacting with Octopus Energy, with an automation for joining Saving Sessions: Services - Home Assistant Octopus Energy, so that’s step 1 done!

Is there a Saving Session today?

To simplify my automations, I’m consolidating the Current joined event start and Next joined event start from the mentioned HACS integration into a single datetime value (current with fallback to next). I’m doing this because once the session becomes active, the Next joined event start turns null. If both are null, I’m assuming a week from now so that there is alreays a datetime available. This is stored in input_datetime.saving_session_start.

Then I check if the session starts later the same day (using day number to compare datetimes) and store the result in input_select.saving_session_today:

{{ 'yes' if (upcoming_event != None and upcoming_event.strftime('%j') == now().strftime('%j')) else 'no' }}

I use this flag to drive forced charging ahead of the session start.

Configuring battery top-up (forced charge)

This automation configures the second charge/discharge period (specific to Solax) so not to mess up your main settings (in my case aligned with Octopus Intelligent Go off-peak). I have the forced charge start set to 13:00, while the forced charge end is being set dynamically to one minute before the session start. This tries to align with a typical early afternoon dip in demand for electricity.

      - service: rest_command.solax_local_set_period2_enable
        data:
          # 1 = enabled, 0 = disabled
          enabled: >
            {{ 1 }}
      - service: rest_command.solax_local_set_forced_charge_stop2
        data:
          # Switch off forced charge 1 minute before session start
          value: >-
            {% set end_time = as_datetime(state_attr('input_datetime.saving_session_start', 'timestamp') - 60) %}
            {{ end_time.hour + end_time.minute * 256 }}

The second charge/discharge period is then switched off at the end of the day.

Set manual mode and forced discharge

This automation runs every minute (when enabled) and checks for the following condition:

{{ states('input_select.saving_session_today') == 'yes' and as_datetime(states('input_datetime.saving_session_start')).timestamp() < now().timestamp() }}

and if this evaluates to true, inverter settings are updated to start forced export:

      - service: rest_command.solax_local_set_inverter_mode
        data:
          # 0: self use, 1: feed in priority, 2: back up, 3: manual
          value: >
            {{ 3 }}
      - service: rest_command.solax_local_set_manual_mode_behaviour
        data:
          # 0: do nothing, 1: forced charge, 2: forced discharge
          value: >
            {{ 2 }}

Return to normal operation

Once the battery is at 10% for a few minutes, the automation sets the inverter back to Self Use mode:

trigger:
  - platform: numeric_state
    entity_id: sensor.solax_local_battery_soc
    below: 11
    for:
      hours: 0
      minutes: 5
      seconds: 0
  - platform: state
    entity_id:
      - binary_sensor.octopus_energy_a_5790678f_octoplus_saving_sessions
    from: "on"
    to: "off"
    for:
      hours: 0
      minutes: 1
      seconds: 0
  condition: 
  - condition: template
    value_template: >-
      {{ (states('sensor.solax_local_inverter_mode') == 'Manual' or states('sensor.solax_local_battery_chd2_enabled')|bool==true) }}    
  action:
  - repeat:
      sequence:
      - service: rest_command.solax_local_set_inverter_mode
        data:
          # 0: self use, 1: feed in priority, 2: back up, 3: manual
          value: >
            {{ 0 }}
      - delay:
          hours: 0
          minutes: 0
          seconds: 15
          milliseconds: 0
      - service: rest_command.solax_local_set_period2_enable
        data:
          # 1 = enabled, 0 = disabled
          enabled: >
            {{ 0 }}
      - delay:
          hours: 0
          minutes: 0
          seconds: 15
          milliseconds: 0    
      - service: homeassistant.update_entity
        entity_id: sensor.solax_rest_local_settings

      until:
      - condition: template
        # Try up to 3 times if the updated setting doen't reflect the target
        value_template: >-
            {{ (states('sensor.solax_local_battery_chd2_enabled')|bool==false and states('sensor.solax_local_inverter_mode') == 'Self Use') or repeat.index == 3 }}

Summary

I’ve yet to test this fully during upcoming Saving Sessions, but sharing this early to get feedback and allow you to do something similar if you wish. Any thoughts or comments will be hugely appreciated.

UPDATE 19/12/2023: All automations worked as expected and no manual input was required :slight_smile: I’ve also made some further improvements and simplifications so the screenshots will need updating.

4 Likes

Good Idea. I need to try this on my HA.

I already have Intelligent Octopus integration up and running :confused:

This is one of the first truly smart automations I have come across. Yes we all trigger lights with sensors or turn the Christmas lights off at 10pm but this is real :smiley:

I previously had two date helpers setup for the start and end of saving period and had automations trigger based on those times which turned off/on several things (primarily the car charger). Thanks so much for the pointer that the Octopus integration has functionality to automatically sign up to saving sessions and also a boolean sensor to trigger the turning on/odd of devices.

Not as advanced as your setup but take out a few more manual steps which is great.

2 Likes

Thank you! I’ll definitely give it a Go!

Thanks for starting me off looking into automating all this. I’ve set up the same auto-optin that you linked to and added a mobile device notification so I’m made aware when it’s opted in just so I can verify. Hope it’s ok to share my automations here.

I use the Solax integration through pocket WiFi module so set up my automation using the visual editor. After my first session all worked great except I forgot to change my export control to discharge at full power so wasted a while at 750Wh rather than 7.5kWh. The second session then didn’t stop at my desired SOC and drained my battery down to 10%, which then put my batteries in idle so couldn’t switch back to discharge without making several option edits till it came back alive. Thankfully was out for my work Xmas party so saw the battery charge hadn’t started (never up that late haha) and could get it working again.

I have 3 automations in total and I’m certain there will be an easier way, but this is what I’ve done below. I’ve added comments to explain what the devices are as may be different on yours.

Start battery export when saving session starts/changes to on:

alias: Saving Session Force Discharge
description: During Saving Session force discharge
trigger:
  - platform: state
    entity_id:
      - binary_sensor.octopus_energy_[Octopus_ID]_octoplus_saving_sessions
    from: null #this is from any state ignoring attribute changes
    to: "on"
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition:
  - condition: numeric_state
    entity_id: sensor.solax_battery_capacity
    above: 39
action:
  - device_id: c03651dc448c1d5a0d49acf33a955d40 #Solax Inverter
    domain: select
    entity_id: 641e93ec4878af470616100bc2048620 #Change SolaX Charger Use Mode option
    type: select_option
    option: Manual Mode
  - device_id: c03651dc448c1d5a0d49acf33a955d40 #Solax Inverter
    domain: select
    entity_id: c68c9148a102e04155c2bd49ccf7fc4b #Change SolaX Manual Mode Select option
    type: select_option
    option: Force Discharge
  - device_id: 63b5116d046a355f7fd67fa98a5fcaa1 #My phone
    domain: mobile_app
    type: notify
    message: Mode changed to manual and batteries exporting to grid
    title: Batteries exporting
mode: single

Stop export when savings session changes to off. I’ve been caught out by it changing from on to unknown to off so used the 'Any state ignoring attribute changes:

alias: Savings Session Ended
description: Saving Session ended, return to self-use
trigger:
  - platform: state
    entity_id:
      - binary_sensor.octopus_energy_[Octopus ID]_octoplus_saving_sessions
    from: null
    to: "off"
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition: []
action:
  - device_id: c03651dc448c1d5a0d49acf33a955d40 #Solax Inverter
    domain: select
    entity_id: 641e93ec4878af470616100bc2048620 #Change SolaX Charger Use Mode option
    type: select_option
    option: Self Use Mode
  - device_id: 63b5116d046a355f7fd67fa98a5fcaa1 #My phone
    domain: mobile_app
    type: notify
    message: Returned to self-use mode, batteries no longer exporting
    title: Batteries no longer exporting
mode: single

And finally to stop export if battery drops below 30% as this will get me to the end of day. This is personal preference as you might want to make as much £’s from the session and just use the rest of the day from the grid but I like to keep some aside.

alias: Saving Session Stopped <30
description: Saving Session ended due to battery capacity
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.solax_battery_capacity
    for:
      hours: 0
      minutes: 0
      seconds: 5
    below: "31"
condition:
  - condition: state
    entity_id: binary_sensor.octopus_energy_[Octopus ID]_octoplus_saving_sessions
    state: "on"
action:
  - device_id: c03651dc448c1d5a0d49acf33a955d40 #Solax Inverter
    domain: select
    entity_id: 641e93ec4878af470616100bc2048620 #Change SolaX Charger Use Mode option
    type: select_option
    option: Self Use Mode
  - device_id: 63b5116d046a355f7fd67fa98a5fcaa1 #My phone
    domain: mobile_app
    type: notify
    message: Returned to self-use mode, batteries no longer exporting
    title: Batteries under 30pc no longer exporting
mode: single
3 Likes

This is something I want to achieve with Intelligent Octopus and my new Luna2000 Inverter (I think). Charge the house batteries, during the extended off peak car charging windows.

Thanks for posting.

Hi Kamil,

Thanks for your work on this. Can I please ask, as someone who doesn’t code YAML, how do I use the following code snippet?

{{ 'yes' if (upcoming_event != None and upcoming_event.strftime('%j') == now().strftime('%j')) else 'no' }}

I tried adding it as code pasted into the “Confirm State” condition in one of my automations but it barfed at the code. What am I missing?

@Whoarewe, probably best to try it out in the Template editor in Developer Tools. It should then tell you what might be wrong…

Thank you for sharing your automations @alexvs!

1 Like

I did that just now and it says “‘upcoming_event’ is undefined”

Does this mean I need to wait for another Octopus saving session to be announced in order to troubleshoot this?

great job! I’m a bit concerned about the force charging the battery for the event. Does it have any financial profits to do that during day time, and if yes, then what tariff are you on?

thanks for everything!
Did you know what is the setting for the charging limit?
I have 6kw of inverter but 3kw from grid… if i set to recharge from grid i got a little too much power :smiley:
I have to limit the charging from grid at 1/1,5kw…

Typically Octopus pays £2.25 per kWh for exporting during a saving session, so it will be very profitable to top-up your battery beforehand. E.G. if a saving session lasts for 1 hour and your inverter can export at 5kW then you want at least 5kWh in your battery at the start of the session. Your 5kWh export then earns you £2.25 x 5 (£11.25) which is way less than you paid to import that 5kWh.

1 Like

There is a saving session today (17/01/2024) and I have just borrowed your automations and will keep a close eye on them, thank you.

1 Like

@kamilb

I wonder if you might be able to help me. We had a saving session yesterday, and my template, designed to work out how many hours until the start of the saving session, didn’t work.

I tried to use the following template code:

{{ (state_attr("binary_sensor.octopus_energy_[ac_no]_octoplus_saving_sessions","next_joined_event_start"))-now() }}

But, for some reason, it didn’t report a time back, and just showed “unknown”.

Would you know what I need to do to the data format, to enable this parameter, to be used to compare to the current time now? My aim is to use this parameter, to pause my battery discharge, 3 hours before the Saving Session starts.

Thanks

On a couple of sessions I’ve got a message that they don’t know what are my numbers for the session :thinking:

@robbo100 There should be a few datetime conversations in my automations so please take a look. I always try to test it out with HA developer tools ans the template editor.

1 Like

Thanks @kamilb, and sorry for the slow reply.

I ended up using:

{{ (as_timestamp(state_attr('binary_sensor.octopus_energy_X_XXXXXXX_octoplus_saving_sessions', 'next_joined_event_start')) - as_timestamp(now()))/3600 }}

Which gave me the number of hours.

It now works a treat

@kamilb - I have a quick question about the saving sessions, and how Octopus calculate the “saving”.

I recently got the results for my first saving session for when I pushed the battery to the grid (17th Jan). When I got the result, Octopus told me that I only saved 0.28 kWh, despite me exporting approx 4.5 kWh to the grid during this session.

Am I correct in thinking that the system should calculate the net difference between normal usage (in my case, I averaged about 0.28 kWh import during this time, over the previous 10 days) and the actual energy imported or exported during the saving session (On this occasion I exported 4.5 kWh during the saving session).

So, am I right in thinking that I should have been credited to a value of £2.25 x (0.28 + 4.5) = £10.75

It feels to me, that OE haven’t registered my export on their system, during the saving session, and have only recorded the difference between normal usage, and zero.

Or have I completely misunderstood how the saving sessions work?

Thanks

Hi!
I have Tesla Powerwall 2 system and would like to automate the forced discharge in the savings sessions too. Does anyone have any knowledge on this as I am a total novice to coding. I have managed to set up the @bottlecapdave Octopus energy saving sessions automation and get it working, now would like to automate the Powerwall discharge in the savings sessions.
Any help or pointers will be greatly appreciated.