Skip to content
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
44 changes: 33 additions & 11 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2225,7 +2225,7 @@ def press_and_poll_button(self, entity_id):
self.base.record_status(f"Warn: Inverter {self.id} Trying to press {entity_id} didn't complete")
return False

def rest_readData(self, api="readData"):
def rest_readData(self, api="readData", retry=True):
"""
Get inverter status

Expand All @@ -2244,9 +2244,13 @@ def rest_readData(self, api="readData"):
if "Control" in json:
return json
else:
self.base.log("WARN: Inverter {} read bad REST data from {} - REST will be disabled".format(self.id, url))
self.base.record_status("Inverter {} read bad REST data from {} - REST will be disabled".format(self.id, url), had_errors=True)
return None
if retry:
# If this is the first call in error then try to re-read the data
return self.rest_runAll()
else:
self.base.log("WARN: Inverter {} read bad REST data from {} - REST will be disabled".format(self.id, url))
self.base.record_status("Inverter {} read bad REST data from {} - REST will be disabled".format(self.id, url), had_errors=True)
return None
else:
self.base.log("WARN: Inverter {} unable to read REST data from {} - REST will be disabled".format(self.id, url))
self.base.record_status("Inverter {} unable to read REST data from {} - REST will be disabled".format(self.id, url), had_errors=True)
Expand All @@ -2256,7 +2260,7 @@ def rest_runAll(self, old_data=None):
"""
Updated and get inverter status
"""
new_data = self.rest_readData(api="runAll")
new_data = self.rest_readData(api="runAll", retry=False)
if new_data:
return new_data
else:
Expand Down Expand Up @@ -5210,8 +5214,18 @@ def basic_rates(self, info, rtype, prev=None):
self.record_status("Bad date {} provided in energy rates".format(this_rate["date"]), had_errors=True)
continue

rate = this_rate.get("rate", 0.0)
# Support increment to existing rates (for override)
if "rate" in this_rate:
rate = this_rate.get("rate", 0.0)
rate_increment = False
elif "rate_increment" in this_rate:
rate = this_rate.get("rate_increment", 0.0)
rate_increment = True

# Resolve any sensor links
rate = self.resolve_arg("rate", rate, 0.0)

# Ensure the end result is a float
try:
rate = float(rate)
except ValueError:
Expand All @@ -5223,7 +5237,11 @@ def basic_rates(self, info, rtype, prev=None):
start_minutes = max(self.minutes_to_time(start, midnight), 0)
end_minutes = min(self.minutes_to_time(end, midnight), 24 * 60 - 1)

self.log("Adding rate {} => {} to {} @ {} date {}".format(this_rate, self.time_abs_str(start_minutes), self.time_abs_str(end_minutes), rate, date))
self.log(
"Adding rate {} => {} to {} @ {} date {} increment {}".format(
this_rate, self.time_abs_str(start_minutes), self.time_abs_str(end_minutes), rate, date, rate_increment
)
)

# Make end > start
if end_minutes <= start_minutes:
Expand All @@ -5238,14 +5256,18 @@ def basic_rates(self, info, rtype, prev=None):
# Store rates against range
if end_minutes >= 0 and start_minutes < max_minute:
for minute in range(start_minutes, end_minutes):
minute_mod = minute % max_minute
if (not date) or (minute >= 0 and minute < max_minute):
rates[minute % max_minute] = rate
if rate_increment:
rates[minute_mod] = rates.get(minute % max_minute, 0.0) + rate
else:
rates[minute_mod] = rate
if load_scaling is not None:
self.load_scaling_dynamic[minute % max_minute] = load_scaling
self.load_scaling_dynamic[minute_mod] = load_scaling
if not date and not prev:
rates[(minute % max_minute) + max_minute] = rate
rates[minute_mod + max_minute] = rate
if load_scaling is not None:
self.load_scaling_dynamic[(minute % max_minute) + max_minute] = load_scaling
self.load_scaling_dynamic[minute_mod + max_minute] = load_scaling

return rates

Expand Down
21 changes: 19 additions & 2 deletions docs/energy-rates.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,25 @@ rates_import_override:

Would say that during a 1 hour period at 5:30-6:30pm on 21st of Jan set the import rate to 150p and assume our load will be 80% of normal (20% lower).

**date** is in the date format of "YYYY-MM-DD" e.g. "2023-09-09", **start** and **end** in "HH:MM:SS" time format e.g. "12:30:00", and **rate** in pence.
**load_scaling** is a factor, where 1.0 would be no change, 0.8 is 80% of nominal.
You can also make relative adjustments to your energy rates, e.g. if you want to avoid exporting during peak periods to improve your energy
saving session results you could make a relative adjustment your export rates using **rate_increment**.
The reason not to just set **rate** is then when an energy saving session is active you do not want to ignore the higher export take.

In this example we subtract 10p from our export rate during the period that saving sessions normally fall within and thus steer Predbat away from
force exporting during that time. The saving session will still work correctly as a 10p adjustment on rates >100p will have little/no impact.

```yaml
rates_export_override:
- start: '17:00:00'
end: '19:00:00'
rate_increment: -10
```

You can also use rate_increment with load_scaling, e.g. a rate_increment of 0 can be used to just apply load scaling to certain defined periods.

- **date** is in the date format of "YYYY-MM-DD" e.g. "2023-09-09", **start** and **end** in "HH:MM:SS" time format e.g. "12:30:00", and **rate** in pence.
- **load_scaling** is a factor, where 1.0 would be no change, 0.8 is 80% of nominal.
- **rate_increment** is the number of pence to add to the reported energy rates during this period

## Rate offsets

Expand Down