solax has no hold charge freeze charge or freeze discharge
when predbat goes into holdcharge mode on the plan it switches a solax inverter into charge mode causing it to charge on higher rate slots that you dont want it to. Im not sure if there there is a way to make the inverter hold charge on solax could be added ? as the only commands solax have are is “force charge” (from grid) “force discharge” (to grid) “stop charge and discharge” (stops using battery) “back up mode” (using battery or charging battery from solar) “Feed in priority” ( prioritizes exporting excess solar energy to the grid, even if the battery could be charged,) Could there be a way to use these commands on apps yaml? I have the charge start service using “force charge” and then discharge service using “force discharge” and the stop services using “back up”. But for solax this does not make hold charge work it just makes the inverter charge switching to “force charge”
ive pasted my apps.yaml which all works apart from the hold service is there a way wit solax to make the hold service work?
pred_bat:
module: predbat
class: PredBat
# Sets the prefix for all created entities in HA - only change if you want to run more than once instance
prefix: predbat
# Timezone to work in
timezone: Europe/London
# XXX: Template configuration, delete this line once you have set up for your system
# If you are using Predbat outside of HA then set the HA URL and Key (long lived access token here)
#ha_url: 'http://homeassistant.local:8123'
#ha_key: 'xxx'
# Currency, symbol for main currency second symbol for 1/100s e.g. $ c or £ p or e c
currency_symbols:
- '£'
- 'p'
# Number of threads to use in plan calculation
# Can be auto for automatic, 0 for off or values 1-N for a fixed number
threads: auto
#
# Sensors, currently more than one can be specified and they will be summed up automatically
# however if you have two inverters only set one of them as they will both read the same.
#
inverter_type: "SX4"
num_inverters: 1
#
# Controls/status - must by 1 per inverter
#
# Max inverter power from battery
battery_rate_max:
- 8000
# Battery capacity in kWh
soc_max:
- 14.87
# Solis specific parameters (these are based on https://github.com/wills106/homeassistant-solax-modbus)
load_today:
- sensor.solax_today_house_load
import_today:
- sensor.solax_today_s_import_energy
export_today:
- sensor.solax_today_s_export_energy
pv_today:
- sensor.solax_today_s_solar_energy
battery_voltage:
- sensor.solax_battery_voltage_charge
# This is disabled by default in the Solax integration so it must be manually enabled.
inverter_time:
- sensor.solax_rtc
# This is disabled by default in the Solax integration so it must be manually enabled.
battery_power:
- sensor.solax_battery_power_charge
pv_power:
- sensor.solax_pv_power_total
# For Solis inverters we need to add the bypass (backup) load to the main house load. If not used the load_power_1 can be commented out
load_power:
- sensor.solax_house_load
#load_power_1:
# - sensor.solis_bypass_load
soc_percent:
- sensor.solax_battery_capacity
reserve:
- number.solax_backup_discharge_min_soc
battery_min_soc:
- number.solax_feedin_discharge_min_soc
# With the Solax integration we need to press a button to send the time to
charge_discharge_update_button:
- button.solax_battery_awaken
#timed_charge_current:
# - number.solis_timed_charge_current
#charge_start_hour:
# - number.solis_timed_charge_start_hours
#charge_start_minute:
# - number.solis_timed_charge_start_minutes
#charge_end_hour:
# - number.solis_timed_charge_end_hours
#charge_end_minute:
# - number.solis_timed_charge_end_minutes
#timed_discharge_current:
# - number.solis_timed_discharge_current
#discharge_start_hour:
# - number.solis_timed_discharge_start_hours
#discharge_start_minute:
# - number.solis_timed_discharge_start_minutes
#discharge_end_hour:
# - number.solis_timed_discharge_end_hours
#discharge_end_minute:
# - number.solis_timed_discharge_end_minutes
energy_control_switch:
- select.solax_remotecontrol_power_control
# Service for start/stop
charge_start_service:
- service: select.select_option
entity_id: select.solax_charger_use_mode
option: "Manual Mode"
- service: select.select_option
entity_id: select.solax_manual_mode_select
option: "Force Charge"
charge_stop_service:
service: select.select_option
entity_id: select.solax_charger_use_mode
option: "Back Up Mode"
discharge_start_service:
- service: select.select_option
entity_id: select.solax_charger_use_mode
option: "Manual Mode"
- service: select.select_option
entity_id: select.solax_manual_mode_select
option: "Force Discharge"
discharge_stop_service:
service: select.select_option
entity_id: select.solax_charger_use_mode
option: "Back Up Mode"
# Inverter max AC limit (one per inverter)
# If you have a second inverter for PV only please add the two values together
inverter_limit: 8000
# Export limit is a software limit set on your inverter that prevents exporting above a given level
# When enabled Predbat will model this limit
#export_limit:
# - 3600
# - 3600
#
# The maximum rate the inverter can charge and discharge the battery can be overwritten, this will change
# the register programming and thus cap the max rates. The default is to use the maximum supported rates (recommended)
#
#inverter_limit_charge:
# - 2000
#inverter_limit_discharge:
# - 2600
# Some inverters don't turn off when the rate is set to 0, still charge or discharge at around 200w
# The value can be set here in watts to model this (doesn't change operation)
#inverter_battery_rate_min:
# - 100
# Some batteries tail off their charge rate at high soc%
# enter the charging curve here as a % of the max charge rate for each soc percentage.
# the default is 1.0 (full power)
#battery_charge_power_curve:
# 91 : 0.91
# 92 : 0.81
# 93 : 0.71
# 94 : 0.62
# 95 : 0.52
# 96 : 0.43
# 97 : 0.33
# 98 : 0.24
# 99 : 0.24
# 100 : 0.24
# Inverter clock skew in minutes, e.g. 1 means it's 1 minute fast and -1 is 1 minute slow
# Separate start and end options are applied to the start and end time windows, mostly as you want to start late (not early) and finish early (not late)
# Separate discharge skew for discharge windows only
inverter_clock_skew_start: 0
inverter_clock_skew_end: 0
inverter_clock_skew_discharge_start: 0
inverter_clock_skew_discharge_end: 0
# Clock skew adjusts the Appdaemon time
# This is the time that Predbat takes actions like starting discharge/charging
# Only use this for workarounds if your inverter time is correct but Predbat is somehow wrong (AppDaemon issue)
# 1 means add 1 minute to AppDaemon time, -1 takes it away
clock_skew: 0
# Solcast cloud interface, set this or the local interface below
#solcast_host: 'https://api.solcast.com.au/'
#solcast_api_key: 'xxxx'
#solcast_poll_hours: 8
# Set these to match solcast sensor names if not using the cloud interface
# The regular expression (re:) makes the solcast bit optional
# If these don't match find your own names in Home Assistant
pv_forecast_today: re:(sensor.(solcast_|)(pv_forecast_|)forecast_today)
pv_forecast_tomorrow: re:(sensor.(solcast_|)(pv_forecast_|)forecast_tomorrow)
pv_forecast_d3: re:(sensor.(solcast_|)(pv_forecast_|)forecast_(day_3|d3))
pv_forecast_d4: re:(sensor.(solcast_|)(pv_forecast_|)forecast_(day_4|d4))
# car_charging_energy defines an incrementing sensor which measures the charge added to your car
# is used for car_charging_hold feature to filter out car charging from the previous load data
# Automatically set to detect Wallbox and Zappi, if it doesn't match manually enter your sensor name
# Also adjust car_charging_energy_scale if it's not in kwH to fix the units
car_charging_energy:
're:(sensor.myenergi_zappi_[0-9a-z]+_charge_added_session)'
num_cars: 1
# car_charging_planned is set to a sensor which when positive indicates the car will charged in the upcoming low rate slots
# This should not be needed if you use Octopus Intelligent Slots which will take priority if enabled
# The list of possible values is in car_charging_planned_response
# Auto matches Zappi and Wallbox, or change it for your own
car_charging_planned:
- 're:(sensor.myenergi_zappi_[0-9a-z]+_plug_status)'
- 'connected'
car_charging_planned_response:
- 'yes'
- 'on'
- 'true'
- 'connected'
- 'ev connected'
- 'charging'
- 'paused'
- 'waiting for car demand'
- 'waiting for ev'
- 'scheduled'
- 'enabled'
- 'latched'
- 'locked'
- 'plugged in'
# To make planned car charging more accurate, either using car_charging_planned or Octopus Intelligent
# specify your battery size in kwh, charge limit % and current car battery soc % sensors/values
# If you have intelligent the battery size and limit will be extracted from Intelligent directly
# Set the car SOC% if you have it to give an accurate forecast of the cars battery levels
# One entry per car if you have multiple cars
car_charging_battery_size:
- 64
# car_charging_limit:
# - 're:number.tsunami_charge_limit'
# car_charging_soc:
# - 're:sensor.tsunami_battery'
# If you have Octopus intelligent, enable the intelligent slot information to add to pricing
# Will automatically disable if not found, or comment out to disable fully
# When enabled it overrides the 'car_charging_planned' feature and predict the car charging based on the intelligent plan (unless octopus intelligent charging is False)
# This matches either the intelligent slot from the Octopus Plugin or from the Intelligent plugin
# octopus_intelligent_slot: 're:(binary_sensor.octopus_intelligent_slot|re:binary_sensor.octopus_energy_intelligent_dispatching)'
# octopus_intelligent_slot: 're:binary_sensor.octopus_energy_a_02a2c7d0_intelligent_dispatching'
# octopus_ready_time: 're:time.octopus_energy_a_02a2c7d0_intelligent_target_time'
# octopus_charge_limit: 're:number.octopus_energy_a_02a2c7d0_intelligent_charge_target'
# Energy rates
# Please set one of these three, if multiple are set then Octopus is used first, second rates_import/rates_export and latest basic metric
# Set import and export entity to point to the Octopus Energy plugin
# automatically matches your meter number assuming you have only one
# Will be ignored if you don't have the sensor
# Or manually set it to the correct sensor names e.g:
# sensor.octopus_energy_electricity_xxxxxxxxxx_xxxxxxxxxxxxx_current_rate
# sensor.octopus_energy_electricity_xxxxxxxxxx_xxxxxxxxxxxxx_export_current_rate
metric_octopus_import: 're:(sensor.octopus_energy_electricity_22e1034737_1100002737690_current_rate)'
metric_octopus_export: 're:(sensor.octopus_energy_electricity_22e1034737_1170001721258_export_current_rate)'
# Standing charge can be set to a sensor (e.g. Octopus) or manually entered in pounds here (e.g. 0.50 is 50p)
metric_standing_charge: 're:(sensor.octopus_energy_electricity_22e1034737_1100002737690_current_standing_charge)'
# Or set your actual rates across time for import and export
# If start/end is missing it's assumed to be a fixed rate
# Gaps are filled with 0
# rates_import:
# - start: "23:30:00"
# end: "05:30:00"
# rate: 7.5
# - start: "05:30:00"
# end: "23:30:00"
# rate: 30.0
# rates_export:
# - rate: 15.0
# Can be used instead of the plugin to get import rates directly online
# Overrides metric_octopus_import and rates_import
# rates_import_octopus_url : "https://api.octopus.energy/v1/products/FLUX-IMPORT-23-02-14/electricity-tariffs/E-1R-FLUX-IMPORT-23-02-14-A/standard-unit-rates"
# rates_import_octopus_url : "https://api.octopus.energy/v1/products/AGILE-FLEX-BB-23-02-08/electricity-tariffs/E-1R-AGILE-FLEX-BB-23-02-08-A/standard-unit-rates"
# Overrides metric_octopus_export and rates_export
# rates_export_octopus_url: "https://api.octopus.energy/v1/products/FLUX-EXPORT-BB-23-02-14/electricity-tariffs/E-1R-FLUX-EXPORT-BB-23-02-14-A/standard-unit-rates"
# rates_export_octopus_url: "https://api.octopus.energy/v1/products/AGILE-OUTGOING-BB-23-02-28/electricity-tariffs/E-1R-AGILE-OUTGOING-BB-23-02-28-A/standard-unit-rates/"
# rates_export_octopus_url: "https://api.octopus.energy/v1/products/OUTGOING-FIX-12M-BB-23-02-09/electricity-tariffs/E-1R-OUTGOING-FIX-12M-BB-23-02-09-A/standard-unit-rates/"
# Import rates can be overridden with rate_import_override
# Export rates can be overridden with rate_export_override
# Use the same format as above, but a date can be included if it just applies for a set day (e.g. Octopus power ups)
# This will override even the Octopus plugin rates if enabled
#
#rates_import_override:
# - date: '2023-09-10'
# start: '14:00:00'
# end: '14:30:00'
# rate: 5
# For pv estimate, leave blank for central estimate, or add 10 for 10% curve (worst case) or 90 or 90% curve (best case)
# If you use 10 then disable pv_metric10_weight below
# pv_estimate: 10
# Days previous is the number of days back to find historical load data
# Recommended is 7 to capture day of the week but 1 can also be used
# if you have more history you could use 7 and 14 (in a list) but the standard data in HA only lasts 10 days
days_previous:
- 7
# Days previous weight can be used to control the weighting of the previous load points, the values are multiplied by their
# weights and then divided through by the total weight. E.g. if you used 1 and 0.5 then the first value would have 2/3rd of the weight and the second 1/3rd
days_previous_weight:
- 1
# Number of hours forward to forecast, best left as-is unless you have specific reason
forecast_hours: 48
# The number of hours ahead to count in charge planning (for cost estimates)
# It's best to set this on your charge window repeat cycle (24) but you may want to set it higher for more variable
# tariffs like Agile
forecast_plan_hours: 24
# Specify the devices that notifies are sent to, the default is 'notify' which goes to all
#notify_devices:
# - mobile_app_treforsiphone12_2
# Set the frequency in minutes that this plugin is run
# recommend something that divides by 60 (5, 10 or 15) or you won't trigger at the start of energy price slots
run_every: 5
# Battery scaling makes the battery smaller (e.g. 0.9) or bigger than its reported
# If you have an 80% DoD battery that falsely reports it's kwh then set it to 0.8 to report the real figures
battery_scaling: 1.0
# Can be used to scale import and export data, used for workarounds
import_export_scaling: 1.0
# Export triggers:
# For each trigger give a name, the minutes of export needed and the energy required in that time
# Multiple triggers can be set at once so in total you could use too much energy if all run
# Creates an entity called 'binary_sensor.predbat_export_trigger_<name>' which will be turned On when the condition is valid
# connect this to your automation to start whatever you want to trigger
export_triggers:
- name: 'large'
minutes: 60
energy: 1.0
- name: 'small'
minutes: 15
energy: 0.25
# If you have a sensor that gives the energy consumed by your solar diverter then add it here
# this will make the predictions more accurate. It should be an incrementing sensor, it can reset at midnight or not
# It's assumed to be in Kwh but scaling can be applied if need be
#iboost_energy_today: 'sensor.xxxxx'
#iboost_energy_scaling: 1.0
Did you mean to close this issue without comment?
The code is meant to change between charging and discharging based on the current SOC level, can you share a logfile where it doesn't do this?
Additonal config for investigation. Mine uses solax_modbus in modbus remote control mode (no EEPROM writes, instant control) and I think the implementations of the freeze service calls work when called.
## Need expert mode enabled to configure battery cycle cost and self-sufficiency bias, which are then set through the UI
expert_mode: True
# Inverter
# JT - combined our two as one; trying to have two was tricky and we can't ignore the non-battery one else predbat doesn't see the true load
inverter_type: "SX4"
num_inverters: 1
output_charge_control: "power"
# solax_modbus_new: true
##JT shouldn't need this if using direct control rather than setting time periods, but it errors without it
inverter_time: sensor.solax_rtc
#
# Controls/status - must by 1 per inverter
#
# Max inverter power from battery
battery_rate_max:
# per Solax docs for the T58
- 4000
# Battery capacity in kWh
soc_max:
- 5.8
# Solis specific parameters (these are based on https://github.com/wills106/homeassistant-solax-modbus)
load_today:
- sensor.house_power_consumed_today
import_today:
- sensor.solax_today_s_import_energy
export_today:
- sensor.solax_today_s_export_energy
pv_today:
- sensor.solar_yield_today
battery_voltage:
- sensor.solax_battery_voltage_charge
inverter_time:
- sensor.solax_rtc
battery_power:
- sensor.solax_battery_power_charge
pv_power:
- sensor.solax_pv_power_total
# For Solis inverters we need to add the bypass (backup) load to the main house load. If not used the load_power_1 can be commented out
load_power:
- sensor.solar_ac_power
soc_percent:
- sensor.solax_battery_capacity
reserve:
- number.solax_backup_discharge_min_soc
battery_min_soc:
- number.solax_feedin_discharge_min_soc
## JT - Predbat errors without this, so we have a dummy one when using services
# charge_discharge_update_button:
# - input_button.predbat_dummy_button
## JT - Services for start/stop - needed for SolaX as the supposed SX4 controls don't seem to achieve anything
charge_start_service:
# force charge from grid + solar
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Charge"
charge_stop_service:
# return to normal operation (self-use mode)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Self-use"
charge_freeze_service:
# Charge freeze: NO discharge, NO grid charge, ALLOW solar to charge battery.
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Charge freeze"
discharge_freeze_service:
# Export freeze: ALLOW discharge to load (but don't force export), NO grid charge, NO solar charge.
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Discharge freeze"
discharge_start_service:
# force discharge (i.e., force export)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Discharge"
discharge_stop_service:
# return to normal operation (self-use mode)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Self-use"
# Inverter max AC limit (one per inverter)
# If you have a second inverter for PV only please add the two values together
inverter_limit:
## JT - 5k + 2k
- 7000
# Export limit is a software limit set on your inverter that prevents exporting above a given level
# When enabled Predbat will model this limit
export_limit:
## JT - 7200 is our G99 export limit from the grid/DNO
- 7200
# Some inverters don't turn off when the rate is set to 0, still charge or discharge at around 200w
# The value can be set here in watts to model this (doesn't change operation)
# inverter_battery_rate_min:
# - 100
## JT - this is a rough observation; need to put it into forced charge and watch to get a better curve
## this may taper much earlier - at 92%, I'm seeing 2.7kW which is ~55%!
## It's supposed to calculate this from historical data, so let's leave it out and see how it fares!
# battery_charge_power_curve:
# 95 : 0.80
# 96 : 0.60
# 97 : 0.40
# 98 : 0.30
# 99 : 0.20
# 100 : 0.10
# Battery min SoC
set_reserve_min: 10
# Inverter efficiency
## JT 5% vs default 4%, battery figures are default 3%
battery_loss: 0.03
battery_loss_discharge: 0.03
inverter_loss: 0.05
# Octoplus saving sessions & free energy events - predbat will decide whether to charge and dump
octopus_saving_session: binary_sensor.octopus_energy_a_39001cba_octoplus_saving_sessions
octopus_free_session: 're:(event.octopus_energy_([0-9a-z_]+|)_octoplus_free_electricity_session_events)'
# Energy rates
# Set import and export entity to point to the Octopus Energy plugin
# automatically matches your meter number assuming you have only one
# Or manually set it to the correct sensor names e.g:
# sensor.octopus_energy_electricity_xxxxxxxxxx_xxxxxxxxxxxxx_current_rate
# sensor.octopus_energy_electricity_xxxxxxxxxx_xxxxxxxxxxxxx_export_current_rate
metric_octopus_import: 're:(sensor.(octopus_energy_|)electricity_[0-9a-z]+_[0-9a-z]+_current_rate)'
metric_octopus_export: 're:(sensor.(octopus_energy_|)electricity_[0-9a-z]+_[0-9a-z]+_export_current_rate)'
# Standing charge can be set to a sensor (e.g. Octopus) or manually entered in pounds here (e.g. 0.50 is 50p)
metric_standing_charge: 're:(sensor.(octopus_energy_|)electricity_[0-9a-z]+_[0-9a-z]+_current_standing_charge)'
# For pv estimate, leave blank for central estimate, or add 10 for 10% curve (worst case) or 90 or 90% curve (best case)
# If you use 10 then disable pv_metric10_weight below
# pv_estimate: 10
# Days previous is the number of days back to find historical load data
# Recommended is 7 to capture day of the week but 1 can also be used
# if you have more history you could use 7 and 14 (in a list) but the standard data in HA only lasts 10 days
## JT - tried averaging this day last week (usage pattern) and yesterday (weather/time of year effects), but that caused Monday afternoon to look rather high because of Sunday laundry.
## So, back to just same day last week.
days_previous:
- 1
- 7
- 14
# Days previous weight can be used to control the weighting of the previous load points, the values are multiplied by their
# weights and then divided through by the total weight. E.g. if you used 1 and 0.5 then the first value would have 2/3rd of the weight and the second 1/3rd
## JT - bias to same day last week, with a smattering of earlier weeks and the last 2 days
days_previous_weight:
- 35
- 50
- 15
# Number of hours forward to forecast, best left as-is unless you have specific reason (default is 48)
forecast_hours: 48
# The number of hours ahead to count in charge planning (for cost estimates)
# It's best to set this on your charge window repeat cycle (24) but you may want to set it higher for more variable
# tariffs like Agile
## JT - Agile. 36 hrs is about the most we can ever see rates for and covers overnight into the next day
forecast_plan_hours: 36
## How often to reevaulate the plan
calculate_plan_every: 10
# Specify the devices that notifies are sent to, the default is 'notify' which goes to all
#notify_devices:
# - mobile_app_treforsiphone12_2
# Set the frequency in minutes that this plugin is run
# recommend something that divides by 60 (5, 10 or 15) or you won't trigger at the start of energy price slots
## JT - default 5, I think 10 is often enough. Not sure this does anything as we're running predbat in a docker not through the HA plugin
run_every: 10
# Solcast cloud interface, set this or the local interface below
#solcast_host: 'https://api.solcast.com.au/'
#solcast_api_key: '7F6SvLJMOIinITEfqHFdG7eqC0PcIrsJ'
#solcast_poll_hours: 8
# Set these to match solcast sensor names if not using the cloud interface
# The regular expression (re:) makes the solcast bit optional
# If these don't match find your own names in Home Assistant
pv_forecast_today: re:(sensor.(solcast_|)(pv_forecast_|)forecast_today)
pv_forecast_tomorrow: re:(sensor.(solcast_|)(pv_forecast_|)forecast_tomorrow)
pv_forecast_d3: re:(sensor.(solcast_|)(pv_forecast_|)forecast_(day_3|d3))
pv_forecast_d4: re:(sensor.(solcast_|)(pv_forecast_|)forecast_(day_4|d4))
# Battery scaling makes the battery smaller (e.g. 0.9) or bigger than its reported
# If you have an 80% DoD battery that falsely reports it's kwh then set it to 0.8 to report the real figures
battery_scaling: 1.0
# Can be used to scale import and export data, used for workarounds
import_export_scaling: 1.0
# Inverter clock skew in minutes, e.g. 1 means it's 1 minute fast and -1 is 1 minute slow
# Separate start and end options are applied to the start and end time windows, mostly as you want to start late (not early) and finish early (not late)
# Separate discharge skew for discharge windows only
inverter_clock_skew_start: 0
inverter_clock_skew_end: 0
inverter_clock_skew_discharge_start: 0
inverter_clock_skew_discharge_end: 0
# Clock skew adjusts the Appdaemon time
# This is the time that Predbat takes actions like starting discharge/charging
# Only use this for workarounds if your inverter time is correct but Predbat is somehow wrong (AppDaemon issue)
# 1 means add 1 minute to AppDaemon time, -1 takes it away
clock_skew: 0
#
# Car charging
#
# How many cars?
num_cars: 1
car_charging_exclusive:
- True
# JT - set switch.predbat_car_charging_hold ON in HA (or its equivalent in the predbat UI config page) to remove car charging from the house load data
car_charging_energy:
- sensor.evc_charge_added
# might need to be the cumulative one, not sure.
# EVC bounces to zero quite a bit during charging. Possible need to smooth this out? See how it fares.
car_charging_battery_size:
- 58
car_charging_planned:
# A sensor that says 'we'd like to charge'
# Could be simply, is there something attached to the charger... or some composite of the charger mode and the car 'charger connected' sensor?
# The EVC seems to have nothing to say it's connected, so going with the car for now.
- binary_sensor.id_3_charging_cable_connected
car_charging_planned_reponse:
- 'on'
- 'true'
# ID.3 state value is on/off, although shows up in UI as 'Plugged in'/'Unplugged', include just in case
- 'Plugged in'
car_charging_limit:
- sensor.id_3_battery_target_charge_level
car_charging_soc:
- sensor.id_3_battery_level
The issue for me, is that I have a plan showing 'hold chrg', with a target to reduce the battery SoC, but predbat is calling the 'charge' service! I wonder whether using the SX4 inverter type (Solax in the other control mode has no 'freeze' modes) stops it recognising that I have the freeze services available...
The issue is there is no support charge hold option its always assumed to be working.
Can you add a logfile of the problem?
The issue is there is no support charge hold option its always assumed to be working.
Can you add a logfile of the problem? The situation I posted on the FB group around 20:20 on 05/04/25 (calling charge when it needs to be 'charge stop' to select self-use mode to power the house until target SoC is reached), should be in this log file. Plan debug wasn't on. If you'd like a log with plan debug, I'll create one next time I see a hold with a target SoC <100%
So in the logfile it says '2025-04-05 20:20:03.625381: Current SOC 100% is greater than Target SOC 10. Grid Charge disabled.' At this point it should set timed_charge_current to a value of 0 which should hold the charge, but for some reason this is commented out in the template so it does nothing
So in the logfile it says '2025-04-05 20:20:03.625381: Current SOC 100% is greater than Target SOC 10. Grid Charge disabled.' At this point it should set timed_charge_current to a value of 0 which should hold the charge, but for some reason this is commented out in the template so it does nothing
If timed_charge_current is a parameter to be sent to the inverter, then that would make sense - Solax in standard control mode doesn't support that. I'll have a look at whether I can adapt the SX4 to create a SX4-modbus-RC; the modbus remote control mode can set the power (not current).
So, I've set up my SX4 like this: config.py:
"SX4": {
"name": "Solax Gen4 (Modbus Remote Control JT)",
"has_rest_api": False,
"has_mqtt_api": False,
#NEW
"has_service_api": True,
#
"output_charge_control": "power",
"charge_control_immediate": True,
"has_charge_enable_time": False,
"has_discharge_enable_time": False,
"has_target_soc": False,
"has_reserve_soc": False,
"has_timed_pause": False,
"charge_time_format": "S",
"charge_time_entity_is_option": False,
"soc_units": "%",
"num_load_entities": 1,
"has_ge_inverter_mode": False,
"time_button_press": True,
"clock_time_format": "%Y-%m-%d %H:%M:%S",
"write_and_poll_sleep": 4,
"has_time_window": False,
#CHANGE
"support_charge_freeze": True,
"support_discharge_freeze": True,
#
"has_idle_time": False,
"can_span_midnight": True,
"charge_discharge_with_rate": False,
},
and apps.yaml:
## JT - Services for start/stop - needed for SolaX as the supposed SX4 controls don't seem to achieve anything
charge_start_service:
# force charge from grid + solar
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Charge"
repeat: true
charge_stop_service:
# return to normal operation (self-use mode)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Self-use"
repeat: true
charge_freeze_service:
# Charge freeze: per Trefor, NO discharge to load or export, NO grid charge, ALLOW solar to charge battery.
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Charge freeze"
repeat: true
discharge_freeze_service:
# Export freeze: per Trefor, ALLOW discharge to load (but don't force export), NO grid charge, NO solar charge.
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Discharge freeze"
repeat: true
discharge_start_service:
# force discharge (i.e., force export)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Discharge"
repeat: true
discharge_stop_service:
# return to normal operation (self-use mode)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Self-use"
repeat: true
The input_select changing triggers a HA script that sets the multiple modbus parameters needed to make things happen. If this works, I'll move the code of that script into the service call definitions in apps.yaml.
I switched predbat from monitor into control charge/discharge mode. Initially it went to 'HoldChrg' and made a 'start_charge' service call, which didn't look good. Then it recalculated and is now in self-use (stop charge), which seems reasonable for 4:40pm with a full battery and sunshine. I've got a mix of 'HoldChrg' with a reducing SoC target, 'FrzChrg' at min SoC and 'HoldChrg' at min SoC (what's the difference?!) late this evening. Most of the 'holdchrg' slots look like they really could be 'demand' mode - discharge to the load, use solar if there's any going. I've set the script to alert me to changes, so we'll see what it does! I shouldn't see 'charge' mode for real until 05:30 tomorrow.
Okay, I'm pretty confused now! All evening until about 21:00, I've had a plan saying 'hold charge' with a reducing SoC target. Every 5 minutes, predbat has called first start_charge then immediately stop_charge (or possibly stop_discharge, can't which). Now we're in the first of the 'freeze charge' periods - not sure why, we're already at min SoC so it makes no difference - and it called charge_freeze then immediately one of the stop_* services. I'm not sure how many calls it's actually making - just noticed that the log has 40+ instances of 'script already running' errors too.
@springfall2008 Any idea what's causing that? I would only expect one service to be called each time, not two different ones.
I beleive the Solis inverters use essentially the same software, certainly solax_modbus talks to my Solis S6 99% of the registers.
On the Solis and I believe the Solax will be the same, "Charge Hold" is achieved by requesting "charge" and setting the target SOC to a value less than or equal to the current SOC, this causes the inverter to stop charging the battery and the house load will be fed from the grid.
So, I've set up my SX4 like this: config.py:
The input_select changing triggers a HA script that sets the multiple modbus parameters needed to make things happen. If this works, I'll move the code of that script into the service call definitions in apps.yaml.
That looks useful, what is in the HA script you used to set the modbus parameters?
I had managed to control it so far using these service calls to the modbus API's:
energy_control_switch:
- select.solax_remotecontrol_power_control
charge_start_service:
- service: input_number.set_value
entity_id: input_number.battery_state
value: "2"
- service: number.set_value
entity_id: number.solax_remotecontrol_active_power
value: "4000"
- service: select.select_option
entity_id: select.solax_remotecontrol_power_control
option: Enabled Battery Control
- service: number.set_value
entity_id: number.solax_remotecontrol_duration
value: "300"
- service: number.set_value
entity_id: number.solax_remotecontrol_autorepeat_duration
value: "28800"
- service: button.press
entity_id: button.solax_remotecontrol_trigger
data: {}
charge_stop_service:
- service: number.set_value
entity_id: input_number.battery_state
value: "1"
- service: number.set_value
entity_id: number.solax_remotecontrol_active_power
value: "4000"
- service: select.select_option
entity_id: select.solax_remotecontrol_power_control
option: Disabled
- service: number.set_value
entity_id: number.solax_remotecontrol_duration
value: "300"
- service: number.set_value
entity_id: number.solax_remotecontrol_autorepeat_duration
value: "28800"
- service: button.press
entity_id: button.solax_remotecontrol_trigger
data: {}
discharge_start_service:
- service: number.set_value
entity_id: input_number.battery_state
value: "3"
- service: number.set_value
entity_id: number.solax_remotecontrol_active_power
value: "-4000"
- service: select.select_option
entity_id: select.solax_remotecontrol_power_control
option: Enabled Battery Control
- service: number.set_value
entity_id: number.solax_remotecontrol_duration
value: "300"
- service: number.set_value
entity_id: number.solax_remotecontrol_autorepeat_duration
value: "28800"
- service: button.press
entity_id: button.solax_remotecontrol_trigger
data: {}
Though when I try to use the {power} attribute the services fail to run so it is using an arbitrary value at the moment and I had to create a service to disable the charge if it reaches 100% so that the solar panels do not stop operating.
So, I've set up my SX4 like this: config.py:
The input_select changing triggers a HA script that sets the multiple modbus parameters needed to make things happen. If this works, I'll move the code of that script into the service call definitions in apps.yaml.
That looks useful, what is in the HA script you used to set the modbus parameters?
I had managed to control it so far using these service calls to the modbus API's:
energy_control_switch: - select.solax_remotecontrol_power_control charge_start_service: - service: input_number.set_value entity_id: input_number.battery_state value: "2" - service: number.set_value entity_id: number.solax_remotecontrol_active_power value: "4000" - service: select.select_option entity_id: select.solax_remotecontrol_power_control option: Enabled Battery Control - service: number.set_value entity_id: number.solax_remotecontrol_duration value: "300" - service: number.set_value entity_id: number.solax_remotecontrol_autorepeat_duration value: "28800" - service: button.press entity_id: button.solax_remotecontrol_trigger data: {} charge_stop_service: - service: number.set_value entity_id: input_number.battery_state value: "1" - service: number.set_value entity_id: number.solax_remotecontrol_active_power value: "4000" - service: select.select_option entity_id: select.solax_remotecontrol_power_control option: Disabled - service: number.set_value entity_id: number.solax_remotecontrol_duration value: "300" - service: number.set_value entity_id: number.solax_remotecontrol_autorepeat_duration value: "28800" - service: button.press entity_id: button.solax_remotecontrol_trigger data: {} discharge_start_service: - service: number.set_value entity_id: input_number.battery_state value: "3" - service: number.set_value entity_id: number.solax_remotecontrol_active_power value: "-4000" - service: select.select_option entity_id: select.solax_remotecontrol_power_control option: Enabled Battery Control - service: number.set_value entity_id: number.solax_remotecontrol_duration value: "300" - service: number.set_value entity_id: number.solax_remotecontrol_autorepeat_duration value: "28800" - service: button.press entity_id: button.solax_remotecontrol_trigger data: {}Though when I try to use the {power} attribute the services fail to run so it is using an arbitrary value at the moment and I had to create a service to disable the charge if it reaches 100% so that the solar panels do not stop operating.
My script looks like this:
alias: Solar modbus control
sequence:
- choose:
- conditions:
- condition: state
entity_id: input_select.solar_control_mode
state: Charge
for:
hours: 0
minutes: 0
seconds: 0
sequence:
- action: select.select_option
metadata: {}
data:
option: Enabled Power Control
target:
entity_id: select.solax_remotecontrol_power_control
- action: number.set_value
metadata: {}
data:
value: "5000"
target:
entity_id: number.solax_remotecontrol_active_power
- action: number.set_value
metadata: {}
data:
value: "10000"
target:
entity_id: number.solax_remotecontrol_import_limit
- conditions:
- condition: state
entity_id: input_select.solar_control_mode
state: Self-use
for:
hours: 0
minutes: 0
seconds: 0
sequence:
- action: select.select_option
metadata: {}
data:
option: Enabled Self Use
target:
entity_id: select.solax_remotecontrol_power_control
- action: number.set_value
metadata: {}
data:
value: "5000"
target:
entity_id: number.solax_remotecontrol_active_power
- action: number.set_value
metadata: {}
data:
value: "10000"
target:
entity_id: number.solax_remotecontrol_import_limit
- conditions:
- condition: state
entity_id: input_select.solar_control_mode
state: Discharge
for:
hours: 0
minutes: 0
seconds: 0
sequence:
- action: select.select_option
metadata: {}
data:
option: Enabled Power Control
target:
entity_id: select.solax_remotecontrol_power_control
- action: number.set_value
metadata: {}
data:
value: "-5000"
target:
entity_id: number.solax_remotecontrol_active_power
- conditions:
- condition: state
entity_id: input_select.solar_control_mode
state: Charge freeze
for:
hours: 0
minutes: 0
seconds: 0
sequence:
- action: select.select_option
metadata: {}
data:
option: Enabled Power Control
target:
entity_id: select.solax_remotecontrol_power_control
- action: number.set_value
metadata: {}
data:
value: "0"
target:
entity_id: number.solax_remotecontrol_active_power
- action: number.set_value
metadata: {}
data:
value: "10000"
target:
entity_id: number.solax_remotecontrol_import_limit
- conditions:
- condition: state
entity_id: input_select.solar_control_mode
state: Discharge freeze
for:
hours: 0
minutes: 0
seconds: 0
sequence:
- action: select.select_option
metadata: {}
data:
option: Enabled Battery Control
target:
entity_id: select.solax_remotecontrol_power_control
- action: number.set_value
metadata: {}
data:
value: "0"
target:
entity_id: number.solax_remotecontrol_active_power
- action: number.set_value
metadata: {}
data:
value: "10000"
target:
entity_id: number.solax_remotecontrol_import_limit
- conditions:
- condition: state
entity_id: input_select.solar_control_mode
state: "OFF"
for:
hours: 0
minutes: 0
seconds: 0
sequence:
- action: select.select_option
metadata: {}
data:
option: Enabled Battery Control
target:
entity_id: select.solax_remotecontrol_power_control
- action: button.press
metadata: {}
data: {}
target:
entity_id: button.solax_system_off
- action: number.set_value
metadata: {}
data:
value: "30"
target:
entity_id: number.solax_remotecontrol_duration
- action: number.set_value
metadata: {}
data:
value: "660"
target:
entity_id: number.solax_remotecontrol_autorepeat_duration
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
- action: button.press
metadata: {}
data: {}
target:
entity_id: button.solax_remotecontrol_trigger
description: Reads solar control mode helper, sets solax_modbus controls accordingly.
icon: mdi:sun-wireless-outline
mode: queued
max: 2
apps.yaml uses them thus:
## JT - Services for start/stop - needed for SolaX as the supposed SX4 controls don't seem to achieve what we need
charge_start_service:
# force charge from grid + solar
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Charge"
repeat: true
charge_stop_service:
# return to normal operation (self-use mode)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Self-use"
repeat: true
charge_freeze_service:
# Charge freeze: NO discharge, NO grid charge, ALLOW solar to charge battery.
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Charge freeze"
repeat: true
discharge_freeze_service:
# Export freeze: ALLOW discharge to load (but don't force export), NO grid charge, NO solar charge.
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Discharge freeze"
repeat: true
discharge_start_service:
# force discharge (i.e., force export)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Discharge"
repeat: true
discharge_stop_service:
# return to normal operation (self-use mode)
service: input_select.select_option
entity_id: input_select.solar_control_mode
option: "Self-use"
repeat: true
I think I have the right modbus actions for each predbat service call, although it may be that for some, predbat really wants to specify a SoC. That would need more work; target SoC isn't implemented in the modbus code so it might need work there or a combination of the script and a HA automation to monitor SoC vs target and change state.
What's bugging me, though, is that predbat appears to be calling the wrong service for what the plan says it wants to achieve!
I did begin looking through PredBat's plan class with the idea of hooking it up to some dummy data and looking at the plan output and seeing if I could optimise the code further as it is proposing some weird things at times for me ... but I got lost in the code ... there are some incredibly loooooooong methods in the class, my mum always told me any method longer than a page needed refactoring, so I've made a start on that, but I really do need to hang a few more unit tests around it.
Another sequence of madness... Predbat seems to issue multiple service calls, some of them completely contrary to what it plans to be doing. Perhaps the inverters it was written for, need to be told 'stop this, do that' rather than just 'now do that', but some of these sequences of service calls don't make sense even then!
This is it trying to set charge mode:
And this is coming out of charge, back into demand/self-use:
Both are just way too many calls. The first wants to be simply 'charge' and the second, 'stop charge'.
Another sequence of madness... Predbat seems to issue multiple service calls, some of them completely contrary to what it plans to be doing. Perhaps the inverters it was written for, need to be told 'stop this, do that' rather than just 'now do that', but some of these sequences of service calls don't make sense even then! Both are just way too many calls. The first wants to be simply 'charge' and the second, 'stop charge'.
I noticed the same thing, it results in the predbat Plan stating charge but the battery not charging. I guess it is a bug.
It also shows in the logs:
2025-05-03 16:09:10.751486: Adjust demand (idle) time computed is 16:00:00-23:59:00
2025-05-03 16:09:10.751671: Inverter 0 current discharge rate is 2600.0W and new target is 5000W
2025-05-03 16:09:10.751739: Setting charging SOC to 100 as per target
2025-05-03 16:09:10.751809: Inverter 0 adjust target soc for charge to 100.0% based on requested all inverter soc 100%
2025-05-03 16:09:10.751882: Inverter 0 Current Target SOC is 100%, already at target
2025-05-03 16:09:10.751992: Current SOC 91% is less than Target SOC 100. Grid charging enabled with charge current set to 65.00
2025-05-03 16:09:10.752198: Inverter 0 Calling service discharge_stop_service domain discharge service_name input_select/select_option with data {'entity_id': 'input_select.solar_control_mode', 'option': 'Self-use'}
2025-05-03 16:09:10.822819: Inverter 0 Calling service charge_start_service domain charge service_name input_select/select_option with data {'entity_id': 'input_select.solar_control_mode', 'option': 'Charge'}
2025-05-03 16:09:10.870794: Inverter 0 Calling service discharge_stop_service domain discharge service_name input_select/select_option with data {'entity_id': 'input_select.solar_control_mode', 'option': 'Self-use'}
2025-05-03 16:09:10.935046: Inverter 0 count register writes 0
2025-05-03 16:09:11.092165: Total inverter register writes now 0
2025-05-03 16:09:41.273027: Wrote debug yaml to /addon_configs/6adb4f0d_predbat/debug/predbat_debug_15_55_00.yaml
2025-05-03 16:09:41.274036: Completed run status Charging
2025-05-03 16:09:41.320800: Info: record_status Charging target 91%-100%
I'm going to close this. There hasn't been any movement on it for 6+ months and #2839 is actively being progressed for refinements and improvements to Solax with Predbat, so any remaining discussion can carry on over there