This commit is contained in:
1 parent
9e0230731b
commit
e7905c667d
10 files changed
+224
-27
No files matched your search
+18
-2
@@ -1,9 +1,10 @@
|
||||
"""Retryable delivery with explicit per-sample acknowledgement."""
|
||||
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
|
||||
from .config import UploadConfig
|
||||
from .config import InverterConfig, UploadConfig
|
||||
from .http import JsonHttp, TransportError
|
||||
from .storage import Store
|
||||
|
||||
@@ -15,7 +16,7 @@ class UploadError(Exception):
|
||||
|
||||
|
||||
class Uploader:
|
||||
def __init__(self, config: UploadConfig, store: Store, *, token=None, http=None):
|
||||
def __init__(self, config: UploadConfig, store: Store, *, token=None, http=None, boiler_threshold_w=None):
|
||||
if not config.url:
|
||||
raise ValueError("Set upload.url to the website's ingestion endpoint first")
|
||||
self.config = config
|
||||
@@ -24,17 +25,32 @@ class Uploader:
|
||||
if not isinstance(self.token, str) or not self.token or any(ord(c) < 33 or ord(c) > 126 for c in self.token):
|
||||
raise ValueError(f"Set upload.token in config.toml or {config.token_env} to a nonempty bearer token without whitespace")
|
||||
self.http = http or JsonHttp(config.request_timeout_seconds)
|
||||
self.boiler_threshold_w = InverterConfig().boiler_threshold_w if boiler_threshold_w is None else boiler_threshold_w
|
||||
if (isinstance(self.boiler_threshold_w, bool) or not isinstance(self.boiler_threshold_w, (int, float))
|
||||
or not math.isfinite(self.boiler_threshold_w) or not 0 < self.boiler_threshold_w <= 99_999_999.99):
|
||||
raise ValueError("Invalid fallback boiler threshold")
|
||||
|
||||
def upload_once(self) -> int:
|
||||
batch = self.store.pending(self.config.batch_size)
|
||||
if not batch:
|
||||
return 0
|
||||
# Older retained samples contain the switch state only. Supply the configured
|
||||
# fallback on delivery; never replace thresholds already recorded with a sample.
|
||||
for sample in batch:
|
||||
readings = sample.get("readings", {})
|
||||
if isinstance(readings.get("boiler_enabled"), bool) and "boiler_threshold_w" not in readings:
|
||||
readings["boiler_threshold_w"] = self.boiler_threshold_w
|
||||
readings["boiler_threshold_source"] = "config"
|
||||
try:
|
||||
response = self.http.request(
|
||||
self.config.url, payload={"schema_version": 1, "samples": batch}, token=self.token,
|
||||
)
|
||||
except TransportError as error:
|
||||
raise UploadError(str(error)) from None
|
||||
if "result" in response:
|
||||
if response["result"] != "success" or not isinstance(response.get("data"), dict):
|
||||
raise UploadError("Receiver returned an unsuccessful or malformed result")
|
||||
response = response["data"]
|
||||
accepted = response.get("accepted_ids")
|
||||
if not isinstance(accepted, list) or not all(isinstance(value, str) for value in accepted):
|
||||
raise UploadError("Receiver must return an accepted_ids array")
|
||||
|
||||
Reference in new issue
Block a user