It's made up of a custom sensor, two input number and 3 separate automations.
How does it work?
Well in a nutshell, you choose a target SoC level that you want and when the set time arrives (usually the start of an off-peak period like Octopus Go or IO), it will set a controlled charge.
It works out the optimum charge rate (A) required to charge the batteries to the desired SoC over a charge time set by you (usually the duration of an off-peak period but can be less if you want to charge faster).
Once the charge time has run its course, the charging will stop and another automation will hold the charge until the settings are reset at a later set time (usually the end of an off-peak period).
If you set a desired SoC level that is below the current SoC at the start of the charge period - it will allow the batteries to discharge to the desired level and then hold until the end of the charge cycle.
During the winter, I have the setting permanently set at 100% and I rely on this automation to charge to 100% at the optimum charge rate to utilise the full off-peak period.
During the summer, there is usually enough solar generated to charge the battery during the day - so depending on the forecasted solar, I might set it lower to leave enough battery space to store the solar without the risk of exporting.
Let's say the next day is forecasted to fill my battery, I might set a low SoC and the automation will control the discharge down to the desired level.
Conversely if the next day isn't as bright but I still want to add some charge, it will work out the optimum charge rate when adding the desired amount.
For example, if I only wanted to add 20% charge over 5 hours, it would set the charge rate to 2.2A in my case.
If I wanted to charge from 10% to 100% over 5 hours, it would set the charge rate to 9A.
You get the picture
That being said, it could be argued that now Octopus pay double the the import rate to export - you may find that it's worth going to 100% anyway and simply export the excess. So the charge setting may become redundant and locked to 100%.
--------------------------------
Let's get set up...
You'll need:
- The FoxESS - Modbus integration (by Nathan Marlor)
- An input number for the SoC level you want.
- An input number for the amount of time you want to charge over.
- A custom sensor to calculate the charge rate (A) required depending on desired charge amount and charge time.
- An automation to set the overnight charge at a specific time (usually the start of an off-peak period).
- An automation to reset the charge settings at a specific time (usually at the end of an off-peak period).
- An automation that monitors for when the charge reaches the desired level and then sets the battery to hold.
1) Set up an input number and name it "Fox Battery Overnight Setting".
Copy the settings in the image below.
You can modify the step size if you want more precise control over the SoC - I've set 5% as the step size personally.
2) Set up an input number and name it "Charge Hours".
Copy the settings in the image below.
You can amend the hours accordingly for the slider - I have it set from 0.5 hours to 6 hours which is more than enough for most off-peak periods.
3) Copy the sensor YAML into your configuration file under one of your templates.
This is a "new" style sensor format so will need to be placed carefully in your YAML to group with existing sensors under the new format. If you use the old style format, make sure this is placed above the row that says "sensor:".
Just make sure that the sensors and input numbers in this code match what you have for your HA.
If you have just one inverter, have Nathan Marlors FoxESS Modbus integration and have the above two input sensors set up - then this code should match perfectly.
Code: Select all
template:
- sensor:
- name: "Charge Rate (A)"
unit_of_measurement: "A"
state: >
{% if states('sensor.battery_soc') in ['unknown', 'unavailable'] %}
{{ 0 }}
{% else %}
{% if (states('sensor.battery_soc')|float > (states('input_number.fox_battery_overnight_setting')|float * 100)) %}
{{ 0 | float }}
{% else %}
{% set batneeded = ((states('input_number.fox_battery_overnight_setting') | float - states('sensor.battery_soc') | float) / 100) %}
{% set batcapacity = ((states('sensor.bms_kwh_remaining')|float / states('sensor.battery_soc')|float) * 100) %}
{% set chargeneeded = ((batcapacity * 1000) * batneeded) %}
{% set ampscalc = (chargeneeded / states('sensor.batvolt')|float) |round(0,default=0) %}
{% set outcome = (ampscalc / states('input_number.charge_hours')|float) |round(1,default=0) %}
{% set result = 25 if outcome > 25 else outcome %}
{{ result }}
{% endif %}
{% endif %}
You'll need to do/check the following:
- Check that the trigger time is suitable - I have the IO tariff, so it starts at 11.30PM.
- You'll need to find the inverter ID for your own inverter - easiest way to do this is to set it using the visual editor after copying the YAML code into place.
- You'll also need to check the charge times you need - I have two set up as my off-peak period goes over midnight - however with Go, you can just have one set up and delete the other.
Code: Select all
alias: Set FoxESS Behaviour Overnight
description: ""
trigger:
- platform: time
at: "23:30:00"
condition: []
action:
- if:
- condition: numeric_state
entity_id: sensor.battery_soc
below: input_number.fox_battery_overnight_setting
then:
- service: automation.turn_on
data: {}
target:
entity_id: automation.check_for_battery_soc_reached
- service: number.set_value
target:
entity_id: number.max_charge_current
data:
value: "{{ (states('sensor.charge_rate_a') | float) }}"
- service: foxess_modbus.update_charge_period
data:
inverter: 6be5bb4feedac189c5bf85cac8ea83f0
enable_force_charge: true
enable_charge_from_grid: true
start: "23:30:00"
end: "23:59:00"
charge_period: "1"
- service: foxess_modbus.update_charge_period
data:
inverter: 6be5bb4feedac189c5bf85cac8ea83f0
enable_force_charge: true
enable_charge_from_grid: true
start: "00:01:00"
end: "05:30:00"
charge_period: "2"
- service: number.set_value
target:
entity_id: number.max_soc
data:
value: "{{ (states('input_number.fox_battery_overnight_setting') | int(0)) }}"
- service: number.set_value
target:
entity_id: number.min_soc_on_grid
data:
value: "{{ (states('input_number.fox_battery_overnight_setting') | int(0)) }}"
mode: single
5) Copy the second automation that resets the inverter back to normal settings for day use.
You'll need to do/check the following:
- Check that the trigger time is suitable - I have the IO tariff, so it ends at 05:30AM.
- You'll need to find the inverter ID for your own inverter - easiest way to do this is to set it using the visual editor after copying the YAML code into place.
- You'll also need to check the charge times reflect the previous automation - if you only have one window set then you need only one window in this automation too.
Code: Select all
alias: Reset Inverter Settings at Peak
description: ""
trigger:
- platform: time
at: "05:30:00"
condition: []
action:
- device_id: 6be5bb4feedac189c5bf85cac8ea83f0
domain: number
entity_id: number.min_soc_on_grid
type: set_value
value: 10
- device_id: 6be5bb4feedac189c5bf85cac8ea83f0
domain: number
entity_id: number.max_soc
type: set_value
value: 100
- service: foxess_modbus.update_charge_period
data:
enable_force_charge: false
enable_charge_from_grid: false
start: "00:00:00"
end: "00:30:00"
charge_period: "1"
inverter: 6be5bb4feedac189c5bf85cac8ea83f0
- service: foxess_modbus.update_charge_period
data:
enable_force_charge: false
enable_charge_from_grid: false
start: "00:00:00"
end: "00:30:00"
charge_period: "2"
inverter: 6be5bb4feedac189c5bf85cac8ea83f0
- service: automation.turn_off
data:
stop_actions: true
target:
entity_id: automation.check_for_battery_soc_reached
- service: number.set_value
target:
entity_id: number.max_charge_current
data:
value: "25"
mode: single
6) Copy the third and final automation that is enabled by the first automation when the desired SoC is higher that the current SoC.
You'll need to do/check the following:
- Make sure this is disabled as soon as you create it.
- You'll need to find the inverter ID for your own inverter - easiest way to do this is to set it using the visual editor after copying the YAML code into place.
- You'll also need to check the charge times reflect the first automation - if you only have one window set then you need only one window in this automation too.
Code: Select all
alias: Check for Battery SoC Reached
description: ""
trigger:
- platform: time_pattern
seconds: /30
condition:
- condition: or
conditions:
- condition: numeric_state
entity_id: sensor.battery_soc
above: input_number.fox_battery_overnight_setting
action:
- service: foxess_modbus.update_charge_period
data:
enable_force_charge: true
enable_charge_from_grid: false
start: "23:30:00"
end: "23:59:00"
charge_period: "1"
inverter: 6be5bb4feedac189c5bf85cac8ea83f0
- service: foxess_modbus.update_charge_period
data:
enable_force_charge: true
enable_charge_from_grid: false
start: "00:01:00"
end: "05:30:00"
charge_period: "2"
inverter: 6be5bb4feedac189c5bf85cac8ea83f0
- device_id: 6be5bb4feedac189c5bf85cac8ea83f0
domain: number
entity_id: number.min_soc_on_grid
type: set_value
value: 10
- device_id: 6be5bb4feedac189c5bf85cac8ea83f0
domain: number
entity_id: number.max_soc
type: set_value
value: 100
mode: single
That should be it - I'd monitor that the automation is up and works the first time it's due to trigger.
There are some warnings:
- If the HA is down or if the automation fails for any reason (mine has never failed aside from HA being unavailable due to an internet problem a while back) then the charge automation won't trigger.
- Similarly, if it has been trigger and something happens to HA, then it will not revert back to normal settings and your inverter SoC will continue to be held and your home will pull from the grid.
If you want to have the card in the image below on your desktop - create one with the YAML code below.
You can also create buttons that trigger the first two automations and force them to run if needed during the day.
Code: Select all
type: entities
entities:
- entity: input_number.fox_battery_overnight_setting
- entity: input_number.charge_hours
- entity: sensor.charge_rate_a
- entity: number.max_charge_current
- entity: number.max_discharge_current
- entity: number.min_soc
- entity: number.min_soc_on_grid
- entity: number.max_soc
- entity: select.work_mode
Any issues, questions or suggestions - don't hesitate to leave a message below or get in touch on Facebook