Deploy 0.18.0 to master #193
@@ -71,8 +71,8 @@ energy only; the framework adds markup and taxes, as for `generic_dayahead`.
|
||||
"static_profile is empty" warning, so no notification (round 2's *Fixed
|
||||
tariff not used* was false and fired on every sound start; round 3 removed
|
||||
it). Instead one INFO line at start (English, as every log line) and an info
|
||||
note beside the setting (EN and NL), saying "Fixed tariff is only used if no
|
||||
prices are available.", both
|
||||
note beside the setting (EN and NL, "With the price service, the fixed
|
||||
tariff is only used if no prices are available."), both
|
||||
only with a non-blank `static_profile` (whitespace counts as blank). At
|
||||
start the add-on dismisses the old notification id, in case a pre-release
|
||||
build raised it.
|
||||
|
||||
@@ -369,7 +369,7 @@ def prices_back() -> Dismiss:
|
||||
|
||||
|
||||
# PRICE-01: a fixed tariff beside the price service. One true sentence, for the
|
||||
# start-up log and the settings page (neither has a Dutch layer).
|
||||
# start-up log (English only, as every log line) and the settings page (EN, NL).
|
||||
FIXED_TARIFF_LOG = "Fixed tariff is only used if no prices are available."
|
||||
FIXED_TARIFF_NOTE = ("With the price service, the fixed tariff is only used if "
|
||||
"no prices are available.")
|
||||
|
||||
@@ -416,8 +416,10 @@ def put_in_charge(c, which, hours_ago, open_min):
|
||||
|
||||
def notes(h):
|
||||
# Not the dismiss of PRICE-01's old fixed-tariff card, which every start sends.
|
||||
# Only that dismiss: a `create` with the old id would still be counted.
|
||||
return [x for x in h.calls if x[0] == "persistent_notification"
|
||||
and x[2].get("notification_id") != "goodwe_fixed_tariff_unused"]
|
||||
and not (x[1] == "dismiss"
|
||||
and x[2].get("notification_id") == "goodwe_fixed_tariff_unused")]
|
||||
|
||||
|
||||
for cheap in (True, False):
|
||||
|
||||
@@ -358,7 +358,46 @@ async def named_scenario():
|
||||
check("the price token is hidden by name even when the schema does not mark "
|
||||
"it as a password", TOKEN not in asyncio.run(named_scenario()))
|
||||
|
||||
print("\n5. the shipped config.yaml")
|
||||
print("\n5. PRICE-01 round 3: the fixed-tariff note on the real validate route")
|
||||
_PROFILE = json.dumps({"periods": [
|
||||
{"name": "all", "days": "all", "from": "00:00", "to": "24:00",
|
||||
"eur_per_kwh": 0.25}]})
|
||||
_NOTE = {"en": ("With the price service, the fixed tariff is only used if no "
|
||||
"prices are available."),
|
||||
"nl": ("Met de prijsdienst wordt het vaste tarief alleen gebruikt als "
|
||||
"er geen prijzen zijn.")}
|
||||
|
||||
|
||||
async def note_scenario(site):
|
||||
runner, root = await serve(Sup(site))
|
||||
out = {}
|
||||
try:
|
||||
async with ClientSession() as s:
|
||||
for lang in ("en", "nl"):
|
||||
async with s.get(root + f"config/model?lang={lang}") as r:
|
||||
m = await r.json()
|
||||
async with s.post(root + "config/validate",
|
||||
json={"model": m["ui"], "lang": lang}) as r:
|
||||
b = await r.json()
|
||||
out[lang] = [x for x in b.get("messages", [])
|
||||
if x["text"] in _NOTE.values()]
|
||||
finally:
|
||||
await runner.cleanup()
|
||||
return out
|
||||
|
||||
|
||||
_with = asyncio.run(note_scenario(dict(SITE, static_profile=_PROFILE)))
|
||||
check("an English page gets the note in English, as info, beside a field",
|
||||
[(x["text"], x["tier"]) for x in _with["en"]] == [(_NOTE["en"], "info")]
|
||||
and _with["en"][0]["field"])
|
||||
check("...and a Dutch page gets it in Dutch, beside the same field",
|
||||
[(x["text"], x["tier"]) for x in _with["nl"]] == [(_NOTE["nl"], "info")]
|
||||
and _with["nl"][0]["field"] == _with["en"][0]["field"])
|
||||
_blank = asyncio.run(note_scenario(dict(SITE, static_profile=" ")))
|
||||
check("a spaces-only fixed tariff: no note on either page",
|
||||
_blank == {"en": [], "nl": []})
|
||||
|
||||
print("\n6. the shipped config.yaml")
|
||||
cfg = open(os.path.join(HERE, "config.yaml"), encoding="utf-8").read()
|
||||
schema_text = cfg[cfg.index("\nschema:"):]
|
||||
pw = {line.split(":")[0].strip() for line in schema_text.splitlines()
|
||||
|
||||
@@ -1536,6 +1536,35 @@ for _label, _kw in (("no profile", {}),
|
||||
_off_s, _, _ = run(_scenario_fixed(price_provider="off",
|
||||
static_profile=_PROFILE))
|
||||
check("provider off with a profile: no log line", _off_s == [])
|
||||
|
||||
|
||||
async def _scenario_fixed_level_and_raise():
|
||||
"""The line's level, and a dismiss that raises: the cycle goes on."""
|
||||
with Wired(NOW, static_profile=_PROFILE) as W:
|
||||
real = W.ctl.hass.call
|
||||
|
||||
async def call(domain, service, data):
|
||||
if service == "dismiss" and data.get("notification_id") == _OLD_ID:
|
||||
raise RuntimeError("Home Assistant said no")
|
||||
return await real(domain, service, data)
|
||||
W.ctl.hass.call = call
|
||||
before = mark()
|
||||
await W.refresh()
|
||||
try:
|
||||
for k in range(2):
|
||||
await W.tick(NOW + timedelta(seconds=30 * k))
|
||||
done = True
|
||||
except Exception as e: # noqa: BLE001 - the check reports it
|
||||
done = repr(e)
|
||||
mine = [(r.levelno, r.getMessage()) for r in TAP.records[before:]
|
||||
if "only used if no prices" in r.getMessage()]
|
||||
return done, mine
|
||||
|
||||
|
||||
_done, _lvl = run(_scenario_fixed_level_and_raise())
|
||||
check(f"the start line is INFO, not a warning ({_lvl})",
|
||||
_lvl == [(logging.INFO, _LINE)])
|
||||
check(f"a dismiss that raises does not stop the cycle ({_done})", _done is True)
|
||||
check("the log line is the same words as the note's second half",
|
||||
_NOTE.endswith(_LINE[0].lower() + _LINE[1:]))
|
||||
|
||||
|
||||
@@ -455,8 +455,10 @@ check("the saved blob passes the normal gate: no refusal, not setup-only",
|
||||
print("\n after the restart, on the saved settings:")
|
||||
rc, ev, err, files = run_child("after", SAVED or {}, SAVED_STATE)
|
||||
# Not the dismiss of PRICE-01's old fixed-tariff card, sent at every start.
|
||||
# Only that dismiss: a `create` with the old id would still be counted.
|
||||
services = [e for e in ev if e[0] == "SERVICE"
|
||||
and e[3].get("notification_id") != "goodwe_fixed_tariff_unused"]
|
||||
and not (e[1:3] == ["persistent_notification", "dismiss"]
|
||||
and e[3].get("notification_id") == "goodwe_fixed_tariff_unused")]
|
||||
writes = [e[3].get("value") for e in services
|
||||
if e[1:3] == ["number", "set_value"]]
|
||||
print(f" after: exit {rc}, {len(services)} service calls, set_value "
|
||||
|
||||
@@ -1112,10 +1112,16 @@ check("...and it is still commanding 0 W on the far side of the restart",
|
||||
_b.target == 0.0 and "circulation" in _b.reason)
|
||||
|
||||
# Not the dismiss of PRICE-01's old fixed-tariff card, sent at every start.
|
||||
# Only that dismiss: a `create` with the old id would still be counted.
|
||||
def _not_old_dismiss(c):
|
||||
return not (c[1] == "dismiss"
|
||||
and c[2].get("notification_id") == "goodwe_fixed_tariff_unused")
|
||||
|
||||
|
||||
_notes1 = [c for c in _h1.calls if c[0] == "persistent_notification"
|
||||
and c[2].get("notification_id") != "goodwe_fixed_tariff_unused"]
|
||||
and _not_old_dismiss(c)]
|
||||
_notes2 = [c for c in _h2.calls if c[0] == "persistent_notification"
|
||||
and c[2].get("notification_id") != "goodwe_fixed_tariff_unused"]
|
||||
and _not_old_dismiss(c)]
|
||||
print(f" notifications raised: {len(_notes1)} before the restart, "
|
||||
f"{len(_notes2)} after it")
|
||||
check("the alarm was raised in the first process", len(_notes1) >= 1)
|
||||
|
||||
Reference in New Issue
Block a user