Skip to content

Commit

Permalink
Automatic charge curve calculation: allow for gaps in battery SOC % (#…
Browse files Browse the repository at this point in the history
…680)

* Charge curve, allow for gaps in battery SOC %

#666

* [pre-commit.ci lite] apply automatic fixes

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
  • Loading branch information
springfall2008 and pre-commit-ci-lite[bot] authored Jan 31, 2024
1 parent 26a0358 commit 13567c4
Showing 1 changed file with 51 additions and 33 deletions.
84 changes: 51 additions & 33 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import os
import yaml

THIS_VERSION = "v7.15.8"
THIS_VERSION = "v7.15.9"
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
TIME_FORMAT_SECONDS = "%Y-%m-%dT%H:%M:%S.%f%z"
TIME_FORMAT_OCTOPUS = "%Y-%m-%d %H:%M:%S%z"
Expand Down Expand Up @@ -1046,41 +1046,59 @@ def find_charge_curve(self):
soc_percent[minute] = int((soc_kwh[minute] / self.soc_max) * 100.0 + 0.5)

# Find 100% end points
data_point = 99
for minute in range(0, min_len):
if soc_percent.get(minute, 0) == data_point and predbat_status[minute] == "Charging" and charge_rate[minute] == max_power and battery_power[minute] <= 0:
total_power = 0
for target_minute in range(minute + 1, min_len):
if predbat_status[target_minute] != "Charging" or charge_rate[minute] != max_power or battery_power[minute] > 0:
break
total_power += abs(battery_power[minute])
this_soc = soc_percent.get(target_minute, 0)
if (this_soc == (data_point - 1)) or (this_soc == (data_point - 2)) and total_power > 0:
this_diff = data_point - this_soc
time_diff = target_minute - minute
from_soc = soc_kwh[minute]
to_soc = soc_kwh[target_minute]
soc_charged = from_soc - to_soc
average_power = total_power / time_diff
charge_curve = round(min(average_power / max_power / self.base.battery_loss, 1.0), 2)
self.log(
"Charge Curve Percent: {} at {} took {} minutes charged {} curve {} average_power {}".format(
data_point, self.base.time_abs_str(self.base.minutes_now - minute), time_diff, round(soc_charged, 2), charge_curve, average_power
for data_point in range(99, 85, -1):
found = False
for minute in range(0, min_len):
# Start trigger is when the SOC just increased above the data point
if (
soc_percent.get(minute - 1, 0) == (data_point + 1)
and soc_percent.get(minute, 0) == data_point
and predbat_status[minute] == "Charging"
and charge_rate[minute] == max_power
and battery_power[minute] < 0
):
total_power = 0
# Find a period where charging was at full rate and the SOC just drops below the data point
for target_minute in range(minute + 1, min_len):
if predbat_status[target_minute] != "Charging" or charge_rate[minute] != max_power or battery_power[minute] >= 0:
break
total_power += abs(battery_power[minute])
this_soc = soc_percent.get(target_minute, 0)
if (this_soc < data_point) and total_power > 0:
# So the power for this data point average has been stored, it's possible we spanned more than one data point
# if not all SOC %'s are represented for this battery size
this_diff = data_point - this_soc
time_diff = target_minute - minute
from_soc = soc_kwh[minute]
to_soc = soc_kwh[target_minute]
soc_charged = from_soc - to_soc
average_power = total_power / time_diff
charge_curve = round(min(average_power / max_power / self.base.battery_loss, 1.0), 2)
self.log(
"Charge Curve Percent: {}-{} at {} took {} minutes charged {} curve {} average_power {}".format(
data_point,
this_soc + 1,
self.base.time_abs_str(self.base.minutes_now - minute),
time_diff,
round(soc_charged, 2),
charge_curve,
average_power,
)
)
)
final_curve[data_point] = charge_curve
if data_point == 99:
final_curve[100] = charge_curve
if this_diff == 2:
final_curve[data_point - 1] = charge_curve
data_point -= 1
data_point -= 1
break
if data_point < 89:
break
# Store data points
for point in range(this_soc + 1, 101):
if point not in final_curve:
final_curve[point] = charge_curve

found = True
break
# Found this data point so stop looking
if found:
break
if final_curve:
self.log("Charge curve before adjustment is: {}".format(final_curve))
found_required = True
for required in range(90, 100):
for required in range(90, 101):
if required not in final_curve:
found_required = False

Expand Down

0 comments on commit 13567c4

Please sign in to comment.