Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with freeze charge not freezing #446

Merged
merged 3 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,6 @@
{"name": "car_charging_from_battery", "friendly_name": "Allow car to charge from battery", "type": "switch", "default": False},
{"name": "calculate_discharge_oncharge", "friendly_name": "Calculate Discharge on charge slots", "type": "switch", "enable": "expert_mode", "default": True},
{"name": "calculate_second_pass", "friendly_name": "Calculate second pass (slower)", "type": "switch", "enable": "expert_mode", "default": False},
{"name": "calculate_tweak_plan", "friendly_name": "Calculate tweak plan (faster second pass)", "type": "switch", "enable": "expert_mode", "default": False},
{"name": "calculate_inday_adjustment", "friendly_name": "Calculate in-day adjustment", "type": "switch", "enable": "expert_mode", "default": True},
{
"name": "calculate_plan_every",
Expand Down Expand Up @@ -7591,14 +7590,14 @@ def fetch_pv_forecast(self):
# Work out data scale factor so it adds up (New Solcast is in kw but old was kWH)
factor = 1.0
if pv_forecast_total_data > 0.0 and pv_forecast_total_sensor > 0.0:
factor = self.dp2(pv_forecast_total_data / pv_forecast_total_sensor)
factor = self.dp2(pv_forecast_total_data / pv_forecast_total_sensor + 0.005)
# We want to divide the data into single minute slots
divide_by = self.dp2(30 * factor)

if factor != 1.0 and factor != 2.0:
self.log(
"WARN: PV Forecast data adds up to {} kWh but total sensors add up to {} KWh, this is unexpected and hence data maybe misleading".format(
pv_forecast_total_data, pv_forecast_total_sensor
"WARN: PV Forecast data adds up to {} kWh but total sensors add up to {} KWh, this is unexpected and hence data maybe misleading (factor {})".format(
pv_forecast_total_data, pv_forecast_total_sensor, factor
)
)

Expand Down Expand Up @@ -8132,6 +8131,8 @@ def execute_plan(self):
and self.set_reserve_enable
and self.set_reserve_hold
and (status == "Charging")
and (not self.set_charge_freeze)
or (self.charge_limit_best[0] > self.reserve)
and ((inverter.soc_percent + 1) >= self.charge_limit_percent_best[0])
):
status = "Hold charging"
Expand Down Expand Up @@ -8283,6 +8284,7 @@ def execute_plan(self):
):
if self.set_charge_freeze and (self.charge_limit_best[0] == self.reserve):
# In charge freeze hold the target SOC at the current value
self.log("Within charge freeze setting target soc to current soc {}".format(inverter.soc_percent))
inverter.adjust_battery_target(inverter.soc_percent)
else:
inverter.adjust_battery_target(self.charge_limit_percent_best[0])
Expand Down Expand Up @@ -8318,7 +8320,10 @@ def execute_plan(self):
if self.set_soc_enable and self.set_reserve_enable and not setReserve:
# In the window then set it, otherwise put it back
if self.charge_limit_best and (self.minutes_now < inverter.charge_end_time_minutes) and (self.minutes_now >= inverter.charge_start_time_minutes):
if inverter.soc_percent >= self.charge_limit_percent_best[0]:
if self.set_charge_freeze and (self.charge_limit_best[0] == self.reserve):
self.log("Adjust reserve to hold current soc {} % (set_reserve_enable is true)".format(inverter.soc_percent))
inverter.adjust_reserve(min(inverter.soc_percent + 1, 100))
elif inverter.soc_percent >= self.charge_limit_percent_best[0]:
self.log("Adjust reserve to hold target charge {} % (set_reserve_enable is true)".format(self.charge_limit_percent_best[0]))
inverter.adjust_reserve(min(self.charge_limit_percent_best[0] + 1, 100))
else:
Expand Down Expand Up @@ -8346,6 +8351,9 @@ def fetch_octopus_rates(self, entity_id, adjust_key=None):
# From 9.0.0 of the Octopus plugin the data is split between previous rate, current rate and next rate
# and the sensor is replaced with an event - try to support the old settings and find the new events

if self.debug_enable:
self.log("Info: Fetch Octopus rates from {}".format(entity_id))

# Previous rates
if "_current_rate" in entity_id:
# Try as event
Expand All @@ -8358,16 +8366,24 @@ def fetch_octopus_rates(self, entity_id, adjust_key=None):
data_import = self.get_state(entity_id=prev_rate_id, attribute="all_rates")
if data_import:
data_all += data_import
else:
self.log("WARN: No Octopus data in sensor {} attribute 'all_rates'".format(prev_rate_id))

# Current rates
current_rate_id = entity_id.replace("_current_rate", "_current_day_rates").replace("sensor.", "event.")
if "_current_rate" in entity_id:
current_rate_id = entity_id.replace("_current_rate", "_current_day_rates").replace("sensor.", "event.")
else:
current_rate_id = entity_id

data_import = self.get_state(entity_id=current_rate_id, attribute="rates")
if data_import:
data_all += data_import
else:
data_import = self.get_state(entity_id=entity_id, attribute="all_rates")
data_import = self.get_state(entity_id=current_rate_id, attribute="all_rates")
if data_import:
data_all += data_import
else:
self.log("WARN: No Octopus data in sensor {} attribute 'all_rates'".format(current_rate_id))

# Next rates
if "_current_rate" in entity_id:
Expand All @@ -8380,6 +8396,8 @@ def fetch_octopus_rates(self, entity_id, adjust_key=None):
data_import = self.get_state(entity_id=next_rate_id, attribute="all_rates")
if data_import:
data_all += data_import
else:
self.log("WARN: No Octopus data in sensor {} attribute 'all_rates'".format(next_rate_id))

if data_all:
rate_key = "rate"
Expand Down Expand Up @@ -9010,7 +9028,7 @@ def fetch_config_options(self):
self.calculate_discharge_oncharge = self.get_arg("calculate_discharge_oncharge")
self.calculate_second_pass = self.get_arg("calculate_second_pass")
self.calculate_inday_adjustment = self.get_arg("calculate_inday_adjustment")
self.calculate_tweak_plan = self.get_arg("calculate_tweak_plan")
self.calculate_tweak_plan = False

self.balance_inverters_enable = self.get_arg("balance_inverters_enable")
self.balance_inverters_charge = self.get_arg("balance_inverters_charge")
Expand Down
2 changes: 1 addition & 1 deletion docs/config-yml-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ is the suggested amount (to match energy rate cycles)

## Inverter information

The following are entity names in HA for GivTCP, assuming you only have one inverter and the entity names are standard then it will be auto discovered.
The following are entity names in HA for GivTCP, assuming you only have one inverter and the entity names are standard then it will be auto discovered.
For other brands of inverter see [Other Inverters](other-inverters.md)

- **num_inverters** - If you increase this above 1 you must provide multiple of each of these entities
Expand Down
6 changes: 0 additions & 6 deletions docs/customisation.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,6 @@ NOTE: This feature is quite slow and so may need a higher performance machine
This can help to slightly improve the plan for tariffs like Agile but can make it worse in some fixed rate tariffs which
you want to discharge late.

**switch.calculate_tweak_plan** (_expert mode_) When True causes Predbat to optimise the next 8 charge/discharge windows
in time order as a second pass and after every 5 minutes even when the full plan is not re-calculated.

This can help to slightly improve the plan for tariffs like Agile but can make it worse in some fixed rate tariffs
which you want to discharge late.

## Battery margins and metrics options

**best_soc_keep** is minimum battery level to try to keep above during the whole period of the simulation time,
Expand Down