This commit is contained in:
1 parent
9e0230731b
commit
e7905c667d
10 files changed
+224
-27
No files matched your search
+34
-3
@@ -94,14 +94,31 @@ def boiler_readings(response, pin):
|
||||
return {"boiler_enabled": state["state"], "boiler_reason": reason}
|
||||
|
||||
|
||||
def boiler_threshold(response, pin):
|
||||
"""GEN24's UI reads rules.<pin>.thresholdOn from /api/config/emrs, in watts.
|
||||
|
||||
In pgrid mode, negative thresholds denote surplus exported to the grid.
|
||||
The UI displays their absolute magnitude as the switch-on threshold.
|
||||
"""
|
||||
rule = response.get("rules", {}).get(pin)
|
||||
if not isinstance(rule, dict):
|
||||
raise ValueError("Boiler threshold rule is missing")
|
||||
value = _number(rule.get("thresholdOn"))
|
||||
if value is not None and rule.get("mode") == "pgrid":
|
||||
value = abs(value)
|
||||
if value is None or not 0 < value <= 99_999_999.99:
|
||||
raise ValueError("Boiler switch-on threshold is missing or invalid")
|
||||
return value
|
||||
|
||||
|
||||
class FroniusClient:
|
||||
def __init__(self, config: InverterConfig, *, http=None):
|
||||
self.config = config
|
||||
self.http = http or JsonHttp(config.request_timeout_seconds, local=True)
|
||||
self.last_request_started = None
|
||||
|
||||
def _read(self, path):
|
||||
for attempt in range(REQUEST_RETRIES + 1):
|
||||
def _read(self, path, retries=REQUEST_RETRIES):
|
||||
for attempt in range(retries + 1):
|
||||
if self.last_request_started is not None:
|
||||
wait = self.config.min_request_interval_seconds - (time.monotonic() - self.last_request_started)
|
||||
if wait > 0:
|
||||
@@ -110,7 +127,7 @@ class FroniusClient:
|
||||
try:
|
||||
return self.http.request(self.config.base_url.rstrip("/") + path)
|
||||
except TransportError as error:
|
||||
if attempt == REQUEST_RETRIES:
|
||||
if attempt == retries:
|
||||
raise
|
||||
LOG.warning("Fronius GET %s failed (%s); retry %d/%d", path, error, attempt + 1, REQUEST_RETRIES)
|
||||
|
||||
@@ -151,4 +168,18 @@ class FroniusClient:
|
||||
sample["source_timestamps"][name] = timestamp
|
||||
except (TransportError, ValueError, KeyError, TypeError, AttributeError) as error:
|
||||
sample["errors"][name] = str(error)
|
||||
# These settings may require inverter authentication (HTTP 401). A failed
|
||||
# settings read must not turn a valid boiler state into a missing sample.
|
||||
sample["readings"]["boiler_threshold_w"] = self.config.boiler_threshold_w
|
||||
sample["readings"]["boiler_threshold_source"] = "config"
|
||||
try:
|
||||
response = self._read("/api/config/emrs", retries=0)
|
||||
threshold = boiler_threshold(response, self.config.boiler_pin)
|
||||
sample["readings"]["boiler_threshold_w"] = threshold
|
||||
sample["readings"]["boiler_threshold_source"] = "api"
|
||||
# Keep only the relevant load-management settings, never an authentication response.
|
||||
rule = response["rules"][self.config.boiler_pin]
|
||||
sample["raw"]["boiler_config"] = {"thresholdOn": rule["thresholdOn"], "mode": rule.get("mode")}
|
||||
except (TransportError, ValueError, KeyError, TypeError, AttributeError):
|
||||
pass
|
||||
return sample
|
||||
Reference in new issue
Block a user