From 29ca9b5157cd9f80969844818f6fae9418aedbbb Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 24 Sep 2026 23:24:50 +0200 Subject: [PATCH 001/105] DOC-1: operator docs name the real P1 entity and a roster that starts - DOCS.md / config.yaml: the watchdog's P1 age entity is sensor.goodwe_p1_sample_age (device "GoodWe" + "P1 sample age", as app/mqtt.py announces and the live install recorded), not sensor.p1_sample_age_s. - DOCS.md: the inverters: example and per-entry table carry the required bms_soc_floor (and capacity_kwh); config.yaml's schema comment says four required keys, not three. - Field guide: marked v0.1.0/outdated; slew_w row no longer recommends the 1000 W that SAFETY-39 now refuses. HTML regenerated; the PDF is NOT rebuilt (no Chrome here). README/DOCS pointers fixed. - test_docs.py: the documented roster must pass app/validate.py and the schema's per-entry keys; the documented entity id must equal the id composed from app/mqtt.py; the wrong id may appear in no shipped doc. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- FIELD-GUIDE.md | 7 +- README.md | 6 +- docs/build_guide.py | 4 +- docs/field-guide.html | 4 +- goodwe_controller/DOCS.md | 23 ++-- goodwe_controller/config.yaml | 11 +- goodwe_controller/test_docs.py | 210 +++++++++++++++++++++++++++++++++ 7 files changed, 243 insertions(+), 22 deletions(-) create mode 100644 goodwe_controller/test_docs.py diff --git a/FIELD-GUIDE.md b/FIELD-GUIDE.md index 2f0f486..1d71b4b 100644 --- a/FIELD-GUIDE.md +++ b/FIELD-GUIDE.md @@ -4,6 +4,10 @@ The guide technicians carry is the PDF: **`docs/GoodWe-RS485-Field-Guide.pdf`** — 10 pages, A4, print it double-sided. +⚠️ **Outdated: it is v0.1.0.** Its `slew_w` row is corrected in `build_guide.py` +and `field-guide.html`, but the PDF has not been rebuilt (see below). Where the +guide disagrees with `goodwe_controller/DOCS.md`, DOCS.md wins. + It covers, in the order the work is done: pre-visit checks, hardware, firmware, add-on install and configuration, how to read the Web UI, the six commissioning gates, the e-stop (and the statement a site without one must sign), proving a @@ -18,7 +22,8 @@ copy cannot drift from the PDF someone is holding in a cellar. python3 docs/build_guide.py # regenerates field-guide.html and the PDF ``` -Requires Chrome or Chromium (used headless for print-to-PDF). Screenshots live +Requires Chrome or Chromium (used headless for print-to-PDF); `CHROME` in the +script is a Windows path, so edit it on any other machine. Screenshots live in `docs/img/` and are base64-embedded, so `field-guide.html` is standalone. ⚠️ **Every section must stay under the A4 printable height** (1039 px at 96 dpi diff --git a/README.md b/README.md index cd500c7..037f702 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ goodwe_controller/ the add-on returns, run against its own release image firmware/goodwe-master.yaml ESPHome config for the T-CAN485 estop/rs485_log.py optional RS485 e-stop / bus witness -docs/GoodWe-RS485-Field-Guide.pdf the guide techs carry (10pp, A4) +docs/GoodWe-RS485-Field-Guide.pdf the guide techs carry (10pp, A4; outdated) docs/build_guide.py its single source - rebuilds the HTML and PDF FIELD-GUIDE.md how to edit and rebuild the guide docs/RELEASE.md how a change reaches the battery - `master` is @@ -79,8 +79,8 @@ machine itself dying: 2. **Wind-down before firmware updates** — 0 W written before the update starts. 3. **RS485 e-stop (optional)** — writes 0 W after 30 s of total bus silence. -Sites sold without the e-stop must have the acknowledgement in `FIELD-GUIDE.md` -§10 signed. +Sites sold without the e-stop must have the client acknowledgement in the field +guide (Step 7b) signed. ## Development diff --git a/docs/build_guide.py b/docs/build_guide.py index 82f80a8..f006f71 100644 --- a/docs/build_guide.py +++ b/docs/build_guide.py @@ -95,7 +95,7 @@ figcaption { font-size:9pt; color:#5b6169; margin-top:1.2mm; }

GoodWe RS485 Controller

-
Field installation & commissioning guide — v0.1.0
+
Field installation & commissioning guide — v0.1.0, outdated: where it disagrees with DOCS.md, DOCS.md wins
Installer copy
@@ -503,7 +503,7 @@ figcaption { font-size:9pt; color:#5b6169; margin-top:1.2mm; } - + diff --git a/docs/field-guide.html b/docs/field-guide.html index ddbb264..77570b2 100644 --- a/docs/field-guide.html +++ b/docs/field-guide.html @@ -60,7 +60,7 @@ figcaption { font-size:9pt; color:#5b6169; margin-top:1.2mm; }

GoodWe RS485 Controller

-
Field installation & commissioning guide — v0.1.0
+
Field installation & commissioning guide — v0.1.0, outdated: where it disagrees with DOCS.md, DOCS.md wins
Installer copy
@@ -468,7 +468,7 @@ figcaption { font-size:9pt; color:#5b6169; margin-top:1.2mm; }
SettingValueReason
gain0.6Inverter needs 3–6 s to settle (1.4 s dead time, 94 % by 3.3 s) against a ~5 s cycle. At the limit — do not raise
slew_w1000Most of a correction in the first cycle without running far ahead of the hardware
slew_w00 follows the rail (max_w / 9). A faster fixed value is refused at startup (SAFETY-39) — see DOCS.md
deadband_w15Measured residual: mean 15.4 W, max 27 W. At 10 W the command never rests
saturation_w / cycles500 / 3Divergence = inverter at a limit → magnitude may fall, never rise. The 3-cycle term is essential: tested instantly it fires on every large correction
step_w10Register is 1 W but response lands on a ~17.6 W ladder. Finer is meaningless
- + diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 0ca2edb..837742b 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -4,8 +4,8 @@ Drives a GoodWe ES/BP battery inverter over its RS485 meter bus: holds net grid exchange at zero, and runs a monthly battery maintenance cycle so the BMS can balance cells and recalibrate its coulomb counter. -Installers: read `FIELD-GUIDE.md` in the repository. It is not optional reading — -it contains the commissioning gates and the failure modes. +Installers: the printed field guide (`docs/GoodWe-RS485-Field-Guide.pdf`) is +v0.1.0 and outdated; where it disagrees with this page, this page wins. ## Before you start @@ -165,12 +165,14 @@ inverters: soc_entity: sensor.goodwe_a_soc batt_entity: sensor.goodwe_a_battery_power max_w: 5000 + bms_soc_floor: 10 capacity_kwh: 15.36 - name: inverter-b setpoint_entity: number.goodwe_b_setpoint_w soc_entity: sensor.goodwe_b_soc batt_entity: sensor.goodwe_b_battery_power max_w: 4600 + bms_soc_floor: 10 capacity_kwh: 20.48 ``` @@ -190,16 +192,18 @@ inverter's own **AC** power. If it is DC the AC-side ceiling is nearer 4324 W. | `name` | yes | Short identifier. It namespaces this unit's SAFETY-02 latch, heartbeat and write bookkeeping in the add-on's state file, so **two units may not share one** | | `setpoint_entity` | yes | This inverter's own ESPHome `number.*_goodwe_setpoint_w` | | `max_w` | yes | The supervised cap on what may be written to **this** inverter. The site's ceiling is the **sum** | +| `bms_soc_floor` | yes | This pack's own BMS cut-out percent (SAFETY-32). See [`bms_soc_floor`](#tariff-all-optional) | | `soc_entity` | | This pack's state of charge | | `batt_entity` | | This unit's battery power, `+` = discharging | | `batt_invert` | | Flip if needed | +| `capacity_kwh` | | This pack's usable capacity. State it on every entry or on none — see [OPT-09](#how-the-site-target-is-divided-between-the-packs-opt-09) | ⚠️ **Nothing is inherited.** An entry that leaves out `soc_entity` has **no SoC sensor** — it does *not* fall back to the flat one. That is deliberate: every per-device value became per-instance in 0.5.x precisely so that no inverter is ever graded against a sibling's numbers, and a silent fallback would rebuild -that in YAML. `name`, `setpoint_entity` and `max_w` are required of every entry -for the same reason: there is no rating to borrow. +that in YAML. `name`, `setpoint_entity`, `max_w` and `bms_soc_floor` are required +of every entry for the same reason: there is no rating or cut-out to borrow. ⚠️ **Clear the flat `setpoint_entity` when you declare a roster,** or the add-on refuses to start and says so. It is the single-inverter form and it is not read @@ -600,7 +604,7 @@ than in YAML nobody reviews underneath a safety input. > `ha_signed`.** It reads the same meter and produces the same numbers, but it > polls the meter directly instead of watching a Home Assistant entity — and > that is the difference between an age sensor a watchdog can threshold and one -> it cannot. See "`sensor.p1_sample_age_s`" below; `ha_signed` remains for +> it cannot. See "`sensor.goodwe_p1_sample_age`" below; `ha_signed` remains for > installs where the meter is only reachable through Home Assistant. > ⚠️ **`ha_dsmr` and `mqtt_p1` have never processed a telegram from real @@ -755,7 +759,7 @@ connection-level reading is still accepted on its own. **Why this mode exists:** every HTTP response is an *arrival*. The meter answered, now, with its current reading — whether or not the number moved. That -is the signal `sensor.p1_sample_age_s` needs and the one Home Assistant cannot +is the signal `sensor.goodwe_p1_sample_age` needs and the one Home Assistant cannot give it at all (see the note below). It is also simply fewer moving parts: the five-second cadence is the meter's own, rather than an integration's polling of it re-published as a state change. @@ -792,12 +796,13 @@ as `… 4 rejected, measurement unchanged for 312 s`. On a house drawing real power that figure stays in the seconds; minutes of it while the load is clearly not near zero is the meter to go and look at. -#### `sensor.p1_sample_age_s` +#### `sensor.goodwe_p1_sample_age` Published over MQTT discovery whenever a broker is available: **seconds since the newest accepted telegram**, refreshed every second rather than only when a telegram lands. The ESP32's stale-input watchdog subscribes to this exact entity -id, so do not rename it. +id; do not rename the `GoodWe` device or this entity, since HA composes the id +from both (see [What appears in Home Assistant at two inverters](#what-appears-in-home-assistant-at-two-inverters)). The reason it is recomputed against the clock is that Home Assistant only pushes a state when the state *changes*. A meter sitting at a genuinely constant reading @@ -833,7 +838,7 @@ behind it would trip the firmware watchdog on a system that is working fine. > went **42.2 s and 97.0 s** between changes, and 23 Aug peaks at 29.1 s — all > past the default `meter_max_age_s` of 30. > -> So `sensor.p1_sample_age_s` on `ha_signed` is safe to *read*, and it is +> So `sensor.goodwe_p1_sample_age` on `ha_signed` is safe to *read*, and it is > correct whenever the value is moving, but it must not yet be thresholded by > the ESP32 stale-input watchdog: a quiet house would trip the battery to 0 W. > Raising `meter_max_age_s` is **not** the fix — the two conditions produce an diff --git a/goodwe_controller/config.yaml b/goodwe_controller/config.yaml index 2e301b3..d3a9493 100644 --- a/goodwe_controller/config.yaml +++ b/goodwe_controller/config.yaml @@ -93,7 +93,7 @@ options: # against a sibling's numbers; an entry silently inheriting `soc_entity` would # rebuild that defect in YAML. `name`, `setpoint_entity`, `max_w` and # `bms_soc_floor` are therefore REQUIRED of every entry (the schema below enforces it, and - # validate.py rule 9 enforces it again for the callers the Supervisor never + # validate.py rules 8 and 9 enforce it again for the callers the Supervisor never # sees). An omitted `soc_entity`/`batt_entity` means THIS UNIT HAS NO SUCH # SENSOR - `inputs_ok` already stops the site for that - and never means # "use the other one's". @@ -224,7 +224,7 @@ options: # ha_signed reads ONE signed HA entity (+ import / - export), which is what a # HomeWizard P1 publishes and what ha_dsmr cannot consume. # homewizard_local skips Home Assistant entirely and polls the meter's own - # local API. ⚠️ It is the ONLY mode whose sensor.p1_sample_age_s measures when + # local API. ⚠️ It is the ONLY mode whose sensor.goodwe_p1_sample_age measures when # the meter REPORTED rather than when the value last CHANGED - HA emits # nothing at all for a repeated reading - so it is the only mode a firmware # watchdog may threshold. See DOCS.md. @@ -916,12 +916,13 @@ schema: # batteries, whereas an absent capacity has an honest answer - no opinion # about the split, every unit weighs 1.0, which is what shipped. # - # ⚠️ THREE KEYS ARE REQUIRED PER ENTRY AND THAT IS DELIBERATE. An entry with + # ⚠️ FOUR KEYS ARE REQUIRED PER ENTRY AND THAT IS DELIBERATE. An entry with # no `name` has no Store namespace and would share another unit's SAFETY-02 # latch; one with no `setpoint_entity` is a unit nothing can command; one with # no `max_w` would have to borrow a rating, which is the sibling-grading - # defect DEV-02 removed. The optional pair is the sensors, whose absence - # honestly means "this unit reports none". + # defect DEV-02 removed; `bms_soc_floor` is SAFETY-32's (options block above). + # The optional keys are the sensors, whose absence honestly means "this unit + # reports none", and `capacity_kwh`. # # ⚠️ THIS BLOCK IS DECLARED BEFORE `max_w:` ON PURPOSE. `max_w` now appears # TWICE under `schema:` - once nested here, once flat below - and a reader diff --git a/goodwe_controller/test_docs.py b/goodwe_controller/test_docs.py new file mode 100644 index 0000000..43fe729 --- /dev/null +++ b/goodwe_controller/test_docs.py @@ -0,0 +1,210 @@ +"""Runnable check that the operator docs say what the code does. `python3 test_docs.py` + +DOC-1. Two things the docs got wrong and an installer would have copied: + +1. The `inverters:` example in DOCS.md must be ACCEPTED by the shipped + validator (`app/validate.py`) and carry every key config.yaml's schema + requires per entry. It omitted `bms_soc_floor` and would not start. +2. The P1 age entity the ESP32 watchdog subscribes to must be documented under + the id Home Assistant composes from what `app/mqtt.py` announces, and the + old wrong id must appear in no shipped doc. + +Each part also runs its own mutation (habit 1 of MUTATION.md): the spoilt input +must turn it red, or the green above it means nothing. +""" + +import os +import re +import sys + +from app import mqtt +from app.validate import validate_startup_config + +HERE = os.path.dirname(os.path.abspath(__file__)) +REPO = os.path.dirname(HERE) + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def read(*parts): + with open(os.path.join(*parts), encoding="utf-8") as fh: + return fh.read() + + +DOCS = read(HERE, "DOCS.md") +CFG = read(HERE, "config.yaml") + + +# --------------------------------------------------------------------------- # +# A reader for the two YAML shapes used here. No PyYAML in the checks image +# (test_defaults_pin.py says why), so this is by hand, and part 1a checks it +# actually found something. +def scalar(raw): + raw = raw.split("#", 1)[0].strip() + if raw[:1] in "\"'" and raw[-1:] == raw[:1] and len(raw) >= 2: + return raw[1:-1] + if raw in ("true", "false"): + return raw == "true" + if raw == "[]": + return [] + for cast in (int, float): + try: + return cast(raw) + except ValueError: + pass + return raw + + +def parse_example(text): + """Top-level `key: value` lines plus one list of flat mappings.""" + out, cur_list, cur = {}, None, None + for line in text.splitlines(): + if not line.split("#", 1)[0].strip(): + continue + m = re.match(r"^([a-z0-9_]+):\s*(.*)$", line) + if m: + if m.group(2).split("#", 1)[0].strip(): + out[m.group(1)] = scalar(m.group(2)) + cur_list = None + else: + cur_list = out[m.group(1)] = [] + continue + m = re.match(r"^\s+-\s+([a-z0-9_]+):\s*(.*)$", line) + if m and cur_list is not None: + cur = {m.group(1): scalar(m.group(2))} + cur_list.append(cur) + continue + m = re.match(r"^\s+([a-z0-9_]+):\s*(.*)$", line) + if m and cur is not None: + cur[m.group(1)] = scalar(m.group(2)) + continue + raise ValueError(f"unparsed line in the DOCS.md example: {line!r}") + return out + + +# --------------------------------------------------------------------------- # +print("DOC-1 - the docs say what the code does\n") +print("1. the `inverters:` example in DOCS.md starts") + +section = DOCS[DOCS.index("### More than one inverter (`inverters`)"):] +section = section[:section.index("\n### ", 1)] +block = re.search(r"```yaml\n(.*?)```", section, re.S).group(1) +example = parse_example(block) +entries = example.get("inverters") or [] + +# The options a fresh install is given, from config.yaml itself: the example is +# pasted on top of these, exactly as an installer does. +opts_block = CFG[CFG.index("\noptions:"):CFG.index("\nschema:")] +shipped = {m.group(1): scalar(m.group(2)) + for m in re.finditer(r"^ ([a-z0-9_]+): *(.*)$", opts_block, re.M)} + +# config.yaml's per-entry schema: required keys are the ones without `?`. +schema_block = CFG[CFG.index("\nschema:"):] +inv_schema = re.search(r"^ inverters:\n((?: .*\n)+)", schema_block, re.M).group(1) +schema_keys = dict(re.findall(r"^ -? ?\s*([a-z0-9_]+): *(\S+)", inv_schema, re.M)) +required = sorted(k for k, t in schema_keys.items() if not t.endswith("?")) + +check(f"1a. the reader found the example: {len(entries)} entries, " + f"{len(shipped)} shipped options, schema keys {sorted(schema_keys)}", + len(entries) == 2 and all(len(e) >= 4 for e in entries) + and len(shipped) > 50 and "bms_soc_floor" in required) + +missing = [(e.get("name"), k) for e in entries for k in required if k not in e] +check(f"1b. every entry carries every key the schema requires {required} " + f"(missing: {missing})", not missing) + +unknown = [(e.get("name"), k) for e in entries for k in e if k not in schema_keys] +check(f"1c. no entry uses a key the schema does not declare (found: {unknown})", + not unknown) + + +def with_example(ex): + opts = dict(shipped) + opts.update(ex) + return opts + + +problems = validate_startup_config(with_example(example)) +for p in problems: + print(f" refused: {p[:160]}") +check("1d. the shipped validator accepts the example as documented", problems == []) + +# Precondition: the example clears the flat setpoint_entity, so without its +# roster there is no actuator. If this passed, 1d graded the flat keys, not the +# roster. +flat_only = {k: v for k, v in example.items() if k != "inverters"} +check("1e. ...and it is the ROSTER that 1d graded (the example without it is " + "refused)", validate_startup_config(with_example(flat_only)) != []) + +# The mutation this card is about: the key the docs used to leave out. +spoilt = dict(example, inverters=[ + {k: v for k, v in e.items() if k != "bms_soc_floor"} for e in entries]) +sp = validate_startup_config(with_example(spoilt)) +check("1f. MUTATION: the example with `bms_soc_floor` removed is refused, " + "and the refusal names it", + sp != [] and any("bms_soc_floor" in p for p in sp)) + +# --------------------------------------------------------------------------- # +print("\n2. the P1 age entity is documented under its real id") + + +def compose(device_name, entity_name): + """HA's entity_id from device name + entity name (mqtt.py's note on + DEVICE). Written here, not borrowed from mqtt._slug, so a change to that + helper cannot move both sides of the comparison.""" + s = re.sub(r"[^a-z0-9]+", "_", f"{device_name} {entity_name}".lower()) + return "sensor." + s.strip("_") + + +p1_rows = [r for r in mqtt.SENSORS if r[0] == "p1_age"] +check("2a. mqtt.py announces exactly one `p1_age` sensor", len(p1_rows) == 1) +real_id = compose(mqtt.DEVICE["name"], p1_rows[0][2]) if p1_rows else "" +print(f" composed from mqtt.py: {real_id}") + +# Anchor outside mqtt.py: the id recorded from the live install. +recorded = read(HERE, "tools", "rehearsal", "announced-reference.txt") +check("2b. ...and that composes to the id recorded from the live install " + "(tools/rehearsal/announced-reference.txt)", + re.search(rf"^{re.escape(real_id)}\s+goodwe_ctl_p1_age\b", recorded, re.M) + is not None) + +m = re.search(r"^#### `(sensor\.[a-z0-9_]+)`\n\n(?:.*\n){0,6}?.*stale-input watchdog", + DOCS, re.M) +documented = m.group(1) if m else None +check(f"2c. DOCS.md's watchdog-entity section is headed with that id " + f"(found {documented!r})", documented == real_id) + +# The wrong id, anywhere an installer reads. CHANGELOG.md and DECISIONS/ are +# history and keep what was said at the time. +SHIPPED_DOCS = [ + os.path.join(HERE, "DOCS.md"), os.path.join(HERE, "config.yaml"), + os.path.join(REPO, "README.md"), os.path.join(REPO, "FIELD-GUIDE.md"), + os.path.join(REPO, "docs", "build_guide.py"), + os.path.join(REPO, "docs", "field-guide.html"), +] +WRONG = "p1_sample_age_s" +hits = [] +for path in SHIPPED_DOCS: + for n, line in enumerate(read(path).splitlines(), 1): + if WRONG in line: + hits.append(f"{os.path.relpath(path, REPO)}:{n}") +check(f"2d. `{WRONG}` appears in no shipped doc (hits: {hits})", not hits) + +# MUTATION: the old heading must fail 2c's comparison. +bad = DOCS.replace(f"#### `{real_id}`", f"#### `sensor.{WRONG}`") +mb = re.search(r"^#### `(sensor\.[a-z0-9_]+)`\n\n(?:.*\n){0,6}?.*stale-input watchdog", + bad, re.M) +check("2e. MUTATION: the old heading is found and does not match", + mb is not None and mb.group(1) != real_id) + +print() +if fails: + print(f"FAILED: {len(fails)}") + sys.exit(1) +print("all ok") -- 2.54.0 From f4f72211a9c77f1705c9c476cc051272b117c7ec Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Thu, 24 Sep 2026 23:27:50 +0200 Subject: [PATCH 002/105] SAFETY-60/62: operator tools refuse input they cannot read predeploy_check.py and rehearse_roster.py now assert a positive property of their input (a JSON object, most of whose top-level keys are known option or store keys) and refuse anything else with the shape named. The `ha apps info --raw-json` wrapper, a truncated or list-wrapped state file and a wrapped config no longer produce "CLEARED" / "NO FINDINGS" with exit 0. Also: a clean --no-live-entities rehearsal exits 3, not 0; alloc_sim.py exits 1 when split-invariance FAILS; decode_bus_capture.py takes several paths and exits 1 on a file that is mostly not frames. Graded by the new test_tool_inputs.py; DOCS.md says to pass .data.options. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- goodwe_controller/DOCS.md | 10 +- goodwe_controller/test_rehearse.py | 16 +- goodwe_controller/test_tool_inputs.py | 255 ++++++++++++++++++ goodwe_controller/tools/alloc_sim.py | 9 +- goodwe_controller/tools/decode_bus_capture.py | 29 +- goodwe_controller/tools/predeploy_check.py | 51 +++- goodwe_controller/tools/rehearse_roster.py | 45 +++- 7 files changed, 390 insertions(+), 25 deletions(-) create mode 100644 goodwe_controller/test_tool_inputs.py diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 0ca2edb..c16476e 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2843,7 +2843,8 @@ check, **before** the roster is declared: 2. **The options blob**, as `--before`. It is not reachable through the Home Assistant REST API and no entity carries it; export it from the Supervisor, - the same way `tools/predeploy_check.py` needs it. Write the roster you intend + the same way `tools/predeploy_check.py` needs it: the bare options object, + not the `ha apps info` wrapper, which is refused. Write the roster you intend to deploy into a second file and pass it as `--after`. 3. **The entity list**, as `--live-entities` — one entity id per line: @@ -2857,7 +2858,8 @@ check, **before** the roster is declared: hand back a clean bill of health for a half of the transition it did not check. If you genuinely have to run without it, pass `--no-live-entities`: the run then carries a standing banner in the report header **and** on the - exit line saying the orphan check was not graded. The asymmetry used to be + exit line saying the orphan check was not graded, and a clean result exits + 3, not 0. The asymmetry used to be the other way round — an unreadable file refused, a missing flag passed with exit 0 and no disclosure at all — and the owner runs this once, at commissioning, under time pressure. @@ -3005,7 +3007,9 @@ Run it inside the container, so the validator half actually runs: --deployed-version 0.7.0 --options /w/live-options.json Export `live-options.json` from the Supervisor first — the options blob is not -reachable through the Home Assistant REST API, and no entity carries it. +reachable through the Home Assistant REST API, and no entity carries it. Pass the +bare object (`ha apps info --raw-json | jq .data.options`); the wrapped +output is refused. **Exit codes.** `0` cleared · `1` REFUSED, do not deploy · `2` NOT CLEARED, meaning a check did not run. ⚠️ **2 is not a pass.** On a bare host without the diff --git a/goodwe_controller/test_rehearse.py b/goodwe_controller/test_rehearse.py index fa924e1..ded905a 100644 --- a/goodwe_controller/test_rehearse.py +++ b/goodwe_controller/test_rehearse.py @@ -75,9 +75,10 @@ print("1. the harness's own preconditions") sys.path.insert(0, str(HERE / "tools")) import rehearse_roster as RR # noqa: E402 -check("the tool refuses rather than passing when it cannot run: its three exit " - "codes are distinct and 2 is not 0", - (RR.EXIT_OK, RR.EXIT_FINDING, RR.EXIT_COULD_NOT_RUN) == (0, 1, 2)) +check("the tool refuses rather than passing when it cannot run: its four exit " + "codes are distinct and only 0 is a pass", + (RR.EXIT_OK, RR.EXIT_FINDING, RR.EXIT_COULD_NOT_RUN, + RR.EXIT_DEGRADED) == (0, 1, 2, 3)) # ⚠️ THE ANCHOR. `app/mqtt.py` records `sensor.goodwe_p1_sample_age` as VERIFIED # against the live system on 2026-08-26, and the ESP32's ingest guard subscribes @@ -204,6 +205,10 @@ def mutant_tree(edits) -> str: shutil.copytree(FIX, dest / "tools" / "rehearsal", ignore=ignore) shutil.copyfile(HERE / "tools" / "rehearse_roster.py", dest / "tools" / "rehearse_roster.py") + # The input-shape gate (SAFETY-62) and the option names it checks against. + shutil.copyfile(HERE / "tools" / "predeploy_check.py", + dest / "tools" / "predeploy_check.py") + shutil.copyfile(HERE / "config.yaml", dest / "config.yaml") for rel, old, new in edits: path = dest / rel text = path.read_text(encoding="utf-8") @@ -356,8 +361,9 @@ check("omitting --live-entities REFUSES with exit 2 rather than reporting a " _no_code == RR.EXIT_COULD_NOT_RUN and "REFUSED" in _no_out + _no_err) _deg_code, _deg_out, _ = raw("--no-live-entities") -check("...and the explicit opt-out RUNS, so the escape hatch exists", - _deg_code in (RR.EXIT_OK, RR.EXIT_FINDING)) +check("...and the explicit opt-out RUNS, so the escape hatch exists - but a " + "clean degraded run is exit 3, never 0 (SAFETY-62)", + _deg_code == RR.EXIT_DEGRADED and "NO FINDINGS" in _deg_out) check("⚠️ ...carrying a standing banner in the report HEADER and again in " "the closing block, because a report is skimmed from the bottom", _deg_out.count("DEGRADED RUN") >= 2 diff --git a/goodwe_controller/test_tool_inputs.py b/goodwe_controller/test_tool_inputs.py new file mode 100644 index 0000000..2ab834d --- /dev/null +++ b/goodwe_controller/test_tool_inputs.py @@ -0,0 +1,255 @@ +"""SAFETY-60/62: the operator tools refuse input they cannot read. `python3 test_tool_inputs.py` + +Each tool is driven as the operator runs it, first on good input (the accepted +baseline, MUTATION.md habit 7) and then on the shapes that used to pass. +""" +import contextlib +import copy +import importlib.util +import io +import json +import os +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +TOOLS = HERE / "tools" +FIX = TOOLS / "rehearsal" +CAPTURE = HERE / "scenarios" / "safety57-2026-09-21" / \ + "bus-a-2026-09-21-1030-1110.log.gz" +TMP = tempfile.mkdtemp(prefix="test_tool_inputs.") +ENV = {**os.environ, "PYTHONDONTWRITEBYTECODE": "1"} + +fails = [] + + +def check(name, ok): + print(f" {'ok ' if ok else 'FAIL'} {name}") + if not ok: + fails.append(name) + + +def dump(name, obj=None, text=None): + p = Path(TMP) / name + p.write_text(text if text is not None else json.dumps(obj, indent=1), + encoding="utf-8") + return str(p) + + +def tool(script, *args): + r = subprocess.run([sys.executable, str(TOOLS / script), *args], + capture_output=True, text=True, env=ENV) + return r.returncode, r.stdout + r.stderr + + +def ha_apps_info(options): + """What `ha apps info --raw-json` prints: the options sit under data.options.""" + text = {"en": ("Setpoint entity", "The ESPHome number carrying the setpoint."), + "nl": ("Setpoint-entiteit", "Het ESPHome-getal met het setpoint.")} + return {"result": "ok", "data": { + "name": "GoodWe RS485 Controller", "slug": "local_goodwe_controller", + "version": "0.12.0", "version_latest": "0.12.0", "state": "started", + "boot": "auto", "ingress": True, "hassio_api": True, + "options": copy.deepcopy(options), + "schema": [{"name": k, "required": True, "optional": False, + "type": "string"} for k in options], + "translations": {lang: {"configuration": { + "setpoint_entity": {"name": name, "description": desc}, + "inverters": {"name": "Inverters", "description": "Roster.", + "fields": {"setpoint_entity": { + "name": name, "description": f"{desc} (per unit)"}}}}} + for lang, (name, desc) in text.items()}}} + + +# --------------------------------------------------------------------------- # +print("1. predeploy_check.py --options (SAFETY-60)") +# --------------------------------------------------------------------------- # +# A deployed version that differs from the shipped one, so only the options half decides. +BARE = {"setpoint_entity": "number.goodwe_setpoint_w", "inverters": [], + "max_w": 5000, "slew_w": 0, "gain": 0.6, "target_grid_w": -10, + "deadband_w": 15, "meter_source": "off", "log_level": "info"} +NOREPO = tempfile.mkdtemp(prefix="norepo.", dir=TMP) + + +def gate(opts_path): + return tool("predeploy_check.py", "--deployed-version", "0.0.0-test", + "--repo", NOREPO, "--options", opts_path) + + +code, out = gate(dump("bare.json", BARE)) +print(f" bare options -> exit {code}") +check("baseline: the bare options object is CLEARED (exit 0)", + code == 0 and "CLEARED for deploy" in out) +code, out = gate(dump("bare-bad.json", dict(BARE, slew_w=5000))) +check("baseline: the bare object with slew_w 5000 is REFUSED by the validator", + code == 1 and "slew_w is 5000 W" in out) + +for label, doc in (("wrapped", ha_apps_info(BARE)), + ("wrapped, slew_w 5000", ha_apps_info(dict(BARE, slew_w=5000)))): + code, out = gate(dump("wrapped.json", doc)) + print(f" {label} -> exit {code}") + check(f"the `ha apps info` capture ({label}) is REFUSED, exit 1", + code == 1 and "CLEARED" not in out) + check("...naming the shape and the fix, not a validator rule", + "0 of 2 top-level key(s) recognised" in out and ".data.options" in out + and "VALIDATOR" not in out) + +from app.validate import actuator_writers, validate_startup_config # noqa: E402 +_w = ha_apps_info(dict(BARE, slew_w=5000)) +print(f" (for reference: the validator alone, handed that capture, finds " + f"{len(validate_startup_config(_w))} problem(s) and " + f"{len(actuator_writers(_w))} 'actuators' - the gate has to refuse it)") + +code, out = gate(dump("list.json", [BARE])) +check("a list-wrapped options object is REFUSED, naming the type", + code == 1 and "is a JSON list, not an object" in out) +code, out = gate(dump("mostly-foreign.json", + {"setpoint_entity": "number.x", "a": 1, "b": 2})) +check("an object with fewer than half its keys recognised is REFUSED", + code == 1 and "1 of 3 top-level key(s) recognised" in out) + +# --------------------------------------------------------------------------- # +print("\n2. rehearse_roster.py --state/--before/--after (SAFETY-62)") +# --------------------------------------------------------------------------- # +sys.path.insert(0, str(TOOLS)) +import rehearse_roster as RR # noqa: E402 + +STATE = FIX / "state-legacy.json" +LIVE = ["--live-entities", str(FIX / "live-entities-recorded.txt"), + "--reference", str(FIX / "announced-reference.txt")] + + +def rehearse(state=str(STATE), before=str(FIX / "flat.yaml"), + after=str(FIX / "roster.yaml"), extra=LIVE): + return tool("rehearse_roster.py", "--state", state, "--before", before, + "--after", after, *extra) + + +code, out = rehearse() +print(f" control -> exit {code}") +check("baseline: the control run reports its 2 findings, exit 1", + code == RR.EXIT_FINDING and "2 FINDING(S)" in out) +code, out = rehearse(state=str(FIX / "state-fresh.json")) +check("baseline: a fresh (comment-only) state file still runs clean, exit 0", + code == RR.EXIT_OK and "NO FINDINGS" in out) + +raw = STATE.read_text(encoding="utf-8") +state = json.loads(raw) +cases = { + "wrapped": (dump("s-wrapped.json", {"result": "ok", "data": state}), + "0 of 2 top-level key(s) recognised"), + "truncated by 20 bytes": (dump("s-trunc.json", text=raw[:-20]), + "not a readable JSON state file"), + "list-wrapped": (dump("s-list.json", [state]), + "is a JSON list, not an object"), +} +for label, (path, words) in cases.items(): + code, out = rehearse(state=path) + print(f" state {label} -> exit {code}") + check(f"state {label}: REFUSED with exit 2 and the reason", + code == RR.EXIT_COULD_NOT_RUN and words in out + and "NO FINDINGS" not in out) + +flat = RR.load_options(str(FIX / "flat.yaml")) +roster = RR.load_options(str(FIX / "roster.yaml")) +for side, kw in (("--before", {"before": dump("b.json", ha_apps_info(flat))}), + ("--after", {"after": dump("a.json", ha_apps_info(roster))})): + code, out = rehearse(**kw) + print(f" {side} wrapped -> exit {code}") + check(f"{side} as an `ha apps info` capture: REFUSED with exit 2", + code == RR.EXIT_COULD_NOT_RUN and ".data.options" in out + and "NO FINDINGS" not in out) + +code, out = rehearse(after=str(FIX / "roster-inverter-a.yaml"), + extra=["--no-live-entities", "--reference", + str(FIX / "announced-reference.txt")]) +check("a clean --no-live-entities run is exit 3, not 0", + code == RR.EXIT_DEGRADED and "NO FINDINGS" in out) + +# --------------------------------------------------------------------------- # +print("\n3. alloc_sim.py - the split-invariance verdict reaches the exit code") +# --------------------------------------------------------------------------- # +spec = importlib.util.spec_from_file_location("_alloc_sim", TOOLS / "alloc_sim.py") +AS = importlib.util.module_from_spec(spec) +spec.loader.exec_module(AS) + + +class _Run: + """One rig run, reduced to what `splits()` reads.""" + + def __init__(self, grid): + self.samples = [{"shares": [1000.0, 1000.0]}] + self._grid = grid + + def grids(self): + return self._grid + + def targets(self): + return [2000.0] * len(self._grid) + + +class _Sitesim: + def load_addon(self, *_): + return None + + +def alloc_main(same): + """`main(--splits)` with the rig stubbed; the real `splits()` grades the traces.""" + seen = [] + + def fake(_sitesim, _control, mode, *a, **kw): + seen.append(mode) + return _Run([0.0, 1.0] if same or len(seen) == 1 else [0.0, 2.0]) + + AS.find_sim = lambda: Path("/nonexistent-rig") + AS.load = lambda _sim: (None, _Sitesim(), None, None) + AS.run_site_feedback = fake + os.environ["GOODWE_ADDON_REPO"] = str(HERE.parent) + sys.argv = ["alloc_sim.py", "--splits"] + buf = io.StringIO() + with contextlib.redirect_stdout(buf): + rc = AS.main() + return rc, buf.getvalue() + + +rc, out = alloc_main(same=True) +check("baseline: identical traces HOLD, exit 0", + rc == 0 and "split-invariance HOLDS" in out) +rc, out = alloc_main(same=False) +print(f" differing traces -> exit {rc}") +check("differing traces FAIL, exit 1", + rc == 1 and "split-invariance FAILS" in out) + +# --------------------------------------------------------------------------- # +print("\n4. decode_bus_capture.py - a file that is not a capture") +# --------------------------------------------------------------------------- # +code, out = tool("decode_bus_capture.py", str(CAPTURE)) +check("baseline: the committed capture decodes, exit 0", + code == 0 and "writes 1200" in out and "REFUSED" not in out) +junk = dump("junk.log", text="hello\nthis is not a capture\n") +code, out = tool("decode_bus_capture.py", junk) +print(f" junk -> exit {code}") +check("a junk file is REFUSED, exit 1", + code == 1 and "REFUSED" in out and "0 of 2 line(s) decoded" in out) +code, out = tool("decode_bus_capture.py", dump("empty.log", text="")) +check("an empty file is REFUSED, exit 1", + code == 1 and "0 of 0 line(s) decoded" in out) +code, out = tool("decode_bus_capture.py", str(CAPTURE), junk) +check("several paths, as the docstring's glob passes them: each is decoded and " + "one bad file makes the run exit 1", + code == 1 and f"== {CAPTURE}" in out and f"== {junk}" in out) +code, out = tool("decode_bus_capture.py", str(CAPTURE), str(CAPTURE)) +check("...and two good files exit 0", code == 0 and out.count("REFUSED") == 0) + +shutil.rmtree(TMP, ignore_errors=True) +print() +if fails: + print(f"FAILED: {len(fails)}") + for f in fails: + print(f" - {f}") + sys.exit(1) +print("all tool-input checks passed") diff --git a/goodwe_controller/tools/alloc_sim.py b/goodwe_controller/tools/alloc_sim.py index 1e16dfc..f257d6d 100644 --- a/goodwe_controller/tools/alloc_sim.py +++ b/goodwe_controller/tools/alloc_sim.py @@ -6,6 +6,8 @@ python3 tools/alloc_sim.py --sweep # AC 3: gain to 1.0 at every split python3 tools/alloc_sim.py --all + Exit 0 only if every split-invariance run HOLDS; 1 if one FAILS; 2 if no rig. + # DEV-02: the split-invariance finding ALLOC-01's review handed on, and the # sensing change that closed it. The two rows are the evidence. python3 tools/alloc_sim.py --splits --gain 0.4 --feedback unit # 250 W apart @@ -279,13 +281,14 @@ def main(): if a.table or a.all: table(sitesim, control, watchdog, a.cycles, a.load) print() + held = True if a.splits or a.all: - splits(sitesim, control, watchdog, a.cycles, a.load, a.gain, - a.feedback) + held = splits(sitesim, control, watchdog, a.cycles, a.load, a.gain, + a.feedback) print() if a.sweep or a.all: sweep(sitesim, control, watchdog, a.cycles, a.load) - return 0 + return 0 if held else 1 if __name__ == "__main__": diff --git a/goodwe_controller/tools/decode_bus_capture.py b/goodwe_controller/tools/decode_bus_capture.py index 18f56fb..a9a8c33 100644 --- a/goodwe_controller/tools/decode_bus_capture.py +++ b/goodwe_controller/tools/decode_bus_capture.py @@ -195,14 +195,37 @@ def _hms(t): return f"{int(t // 3600):02d}:{int(t % 3600 // 60):02d}:{t % 60:06.3f}" +def unreadable(stats): + """Why a capture decoded to too little to trust, or None: most lines must be frames.""" + framed = sum(stats[k] for k in ("requests", "responses", "writes", + "write_echoes")) + if framed > 0 and stats["lines"] - framed <= framed: + return None + return (f"{framed} of {stats['lines']} line(s) decoded as frames " + f"(unparsed {stats['unparsed']}, bad_crc {stats['bad_crc']}, " + f"unknown {stats['unknown']}) - not a capture this decoder can read") + + def main(argv): - if len(argv) != 2: + """Decode each capture named; exit 1 if any is unreadable, 2 on no argument.""" + if len(argv) < 2: print(__doc__.splitlines()[2].strip()) return 2 - events, stats = decode(argv[1]) - print(f"== {argv[1]}") + rc = 0 + for path in argv[1:]: + rc |= _report(path) + return rc + + +def _report(path): + events, stats = decode(path) + print(f"== {path}") for k, v in stats.items(): print(f" {k:14} {v}") + bad = unreadable(stats) + if bad: + print(f"REFUSED: {path}: {bad}") + return 1 for kind in ("setpoint_w", "batt_w", "soc_pct"): rows = series(events, kind) if not rows: diff --git a/goodwe_controller/tools/predeploy_check.py b/goodwe_controller/tools/predeploy_check.py index cc718af..f72f16a 100644 --- a/goodwe_controller/tools/predeploy_check.py +++ b/goodwe_controller/tools/predeploy_check.py @@ -39,8 +39,10 @@ and not at merge. The check belongs where the mistake is made. ⚠️ WHAT THIS DOES NOT DO. It does not read the live box. The options blob is reachable only through the Supervisor API, which needs a supervisor token, so -the operator exports it and passes `--options`. Without that flag the validator -half is SKIPPED and says so - a skipped check must never look like a passed one. +the operator exports it and passes `--options` - the bare options object +(`.data.options` of `ha apps info --raw-json`); any other shape is +refused. Without that flag the validator half is SKIPPED and says so - a +skipped check must never look like a passed one. """ import argparse import json @@ -79,6 +81,43 @@ def shipped_version(tree=ADDON): return m.group(1) if m else None +def option_keys(addon=ADDON): + """Top-level option names in `addon`'s config.yaml `options:`/`schema:` blocks.""" + keys, section = set(), None + with open(os.path.join(addon, "config.yaml"), encoding="utf-8") as fh: + for line in fh: + if not line.strip() or line.startswith("#"): + continue + if not line[0].isspace(): + section = line.split(":", 1)[0].strip() + continue + m = re.match(r" ([A-Za-z_][A-Za-z0-9_]*):", line) + if m and section in ("options", "schema"): + keys.add(m.group(1)) + return keys + + +def shape_problem(doc, known, what, allow_empty=False): + """Why `doc` is not a document of `known` keys, or None (SAFETY-60/62). + + Positive property: a JSON object, at least half of whose top-level keys + (`_`-prefixed comments aside) `known(key)` recognises. + """ + if not isinstance(doc, dict): + return f"{what} is a JSON {type(doc).__name__}, not an object" + keys = [k for k in doc if not str(k).startswith("_")] + hits = [k for k in keys if known(k)] + if (keys or allow_empty) and len(hits) * 2 >= len(keys): + return None + msg = (f"{what} is not the expected document: {len(hits)} of {len(keys)} " + f"top-level key(s) recognised {sorted(map(str, keys))[:8]}") + inner = doc.get("data") + if isinstance(inner, dict) and isinstance(inner.get("options"), dict): + msg += ("; this is `ha apps info --raw-json` output - pass its " + "`.data.options` instead") + return msg + + def is_runtime(path): return any(path == p or path.startswith(p) for p in RUNTIME) @@ -256,6 +295,12 @@ def main(): except (json.JSONDecodeError, OSError, UnicodeDecodeError) as exc: problems.append(f"--options file could not be read as JSON " f"({type(exc).__name__}: {exc}); the config was NOT checked") + # SAFETY-60: the validator accepts any dict, so the shape is checked here. + bad = (shape_problem(opts, option_keys().__contains__, "--options") + if opts is not None else None) + if bad: + problems.append(f"{bad}; the config was NOT checked") + opts = None if a.options and opts is not None: try: from app.validate import validate_startup_config @@ -281,7 +326,7 @@ def main(): print(f" - {p}") else: print(" live options pass this version's validator") - else: + elif not a.options: skipped.append("--options was not given, so the live config was NEVER CHECKED " "against this version's validator. A config refused at startup is " "exit 78. Export the options and re-run before deploying.") diff --git a/goodwe_controller/tools/rehearse_roster.py b/goodwe_controller/tools/rehearse_roster.py index 418f44e..f37cb28 100644 --- a/goodwe_controller/tools/rehearse_roster.py +++ b/goodwe_controller/tools/rehearse_roster.py @@ -46,8 +46,11 @@ EXIT CODES 1 ⭐ AT LEAST ONE OF THOSE HAPPENED. This is the code that must be reachable: `test_rehearse.py` mutates the shipped migration nine different ways and requires this exit code for each. - 2 the rehearsal could not be performed (bad file, unparseable config, the - entity-id model failed its own anchor). ⚠️ NOT A PASS. + 2 the rehearsal could not be performed (bad file, unparseable config, a + state or options file of the wrong shape, the entity-id model failed + its own anchor). ⚠️ NOT A PASS. + 3 no findings, but --no-live-entities: the orphan check was not graded + against the install. ⚠️ NOT A PASS. """ import argparse @@ -64,10 +67,12 @@ from app.inverter import UNIT_A, UNIT_STORE_KEYS, Inverter, roster_names # noqa from app.main import Controller # noqa: E402 from app import mqtt # noqa: E402 from app.p1 import is_enabled # noqa: E402 -from app.store import (DEFAULTS, MAINT_UNIT_KEYS, Store, # noqa: E402 - unit_key) +from app.store import (DEFAULTS, MAINT_SCHEMA_KEY, MAINT_UNIT_KEYS, # noqa: E402 + SCHEMA_KEY, Store, unit_key) +from predeploy_check import option_keys, shape_problem # noqa: E402 -EXIT_OK, EXIT_FINDING, EXIT_COULD_NOT_RUN = 0, 1, 2 +EXIT_OK, EXIT_FINDING, EXIT_COULD_NOT_RUN, EXIT_DEGRADED = 0, 1, 2, 3 +ADDON = Path(__file__).resolve().parent.parent class Refused(Exception): @@ -184,8 +189,29 @@ def load_options(path: str) -> dict: obj = _mini_yaml(text) else: obj = yaml.safe_load(text) - if not isinstance(obj, dict): - raise Refused(f"{path}: options must be a mapping, got {type(obj).__name__}") + # SAFETY-62: a wrapped export is a dict too, so assert the keys are options. + bad = shape_problem(obj, option_keys(str(ADDON)).__contains__, path) + if bad: + raise Refused(bad) + return obj + + +_UNIT_PREFIX = unit_key("\0", "").split("\0")[0] +_STORE_KEYS = {*DEFAULTS, *MAINT_UNIT_KEYS, SCHEMA_KEY, MAINT_SCHEMA_KEY} + + +def load_state(path: str) -> dict: + """Refuse a state file `Store.load()` would silently start fresh on (SAFETY-62).""" + try: + obj = json.loads(Path(path).read_text(encoding="utf-8")) + except ValueError as err: + raise Refused(f"{path}: not a readable JSON state file ({err}); " + "Store.load() would start fresh and grade an empty store") + bad = shape_problem( + obj, lambda k: k in _STORE_KEYS or str(k).startswith(_UNIT_PREFIX), + path, allow_empty=True) + if bad: + raise Refused(bad) return obj @@ -1061,6 +1087,7 @@ def main(argv=None) -> int: if args.live_entities else None) if not Path(args.state).is_file(): raise Refused(f"{args.state}: not a file") + load_state(args.state) except (OSError, Refused) as err: print(f"REFUSED: {err}", file=sys.stderr) return EXIT_COULD_NOT_RUN @@ -1179,7 +1206,9 @@ def main(argv=None) -> int: print(" the install's own entity list. This result does not cover " "orphaned entities.") print("=" * 78) - return EXIT_FINDING if findings else EXIT_OK + if findings: + return EXIT_FINDING + return EXIT_DEGRADED if degraded else EXIT_OK if __name__ == "__main__": -- 2.54.0 From 71d2d4a37a68fd5de64e371b4a83820756d2b16c Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Thu, 24 Sep 2026 23:52:42 +0200 Subject: [PATCH 003/105] SAFETY-61: the control task's death ends the process, after the wind-down A done-callback on run_control()'s task logs the traceback at the death and sets `stop`; amain() runs the ordinary wind-down (shutdown() -> command_site_zero()) and main() exits 70 (EX_SOFTWARE). Normal stops and run_control()'s refusal path are ignored by the callback (still 0 / 78). hass.py: a malformed JSON body, a JSON non-object, and an undecodable error body are an absence / a failed write, not an exception into the loop. checks() gains a first "control loop" row, red past FIRMWARE_INGEST_VETO_S. Why exit rather than restart in-process, and what the Supervisor actually does on exit (restarts only with the per-install Watchdog toggle on, default off): DECISIONS/SAFETY-61-control-task-death.md. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- .../DECISIONS/SAFETY-61-control-task-death.md | 106 +++++ goodwe_controller/app/hass.py | 14 +- goodwe_controller/app/main.py | 64 ++- goodwe_controller/test_control_task.py | 373 ++++++++++++++++++ 4 files changed, 551 insertions(+), 6 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-61-control-task-death.md create mode 100644 goodwe_controller/test_control_task.py diff --git a/goodwe_controller/DECISIONS/SAFETY-61-control-task-death.md b/goodwe_controller/DECISIONS/SAFETY-61-control-task-death.md new file mode 100644 index 0000000..950fe27 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-61-control-task-death.md @@ -0,0 +1,106 @@ +# SAFETY-61 — the control task's death ends the process + +## 0. The defect + +`amain()` started `run_control()` as a bare task and waited on `stop`. Nothing +watched the task. An uncaught exception in `read_inputs()`, `cycle()` or +`publish()` ended the task silently, and `stop` was never set. The web UI, P1 +and tariff tasks kept running, and the Supervisor saw a healthy container. The +traceback appeared only at shutdown. The ESP32's layer-1 veto zeroed the +inverter about 30 s later, so the hardware was safe. The pack then sat at 0 W +indefinitely while the add-on showed green. + +`test_control_task.py` reproduces this on the pre-fix tree. The child process +reaches its 40 s deadline, has written no 0 W, and has logged nothing. + +## 1. Decision: exit with status 70 after the ordinary wind-down + +A done-callback on the control task (`control_task_done()`) handles the death. +It logs the traceback at CRITICAL at the moment of death, then sets `stop`. +`amain()` then runs the same wind-down that SIGTERM runs (`shutdown()` → +`command_site_zero()`, then cancel, then clean up). After that it raises +`ControlTaskDied`, and `main()` turns that into `SystemExit(70)` (sysexits +EX_SOFTWARE). A normal stop and `run_control()`'s own refusal path both set +`stop` before the task ends, so the callback ignores them. The refusal still +exits with 78. + +**Why not restart the loop in the same process:** + +* `cycle()` writes controller state before its awaits: `cycle_at`, + `peak_guard`, `allocation`, then `target`/`reason`, then the writes. An + exception between those steps leaves the controller half-updated. A loop + restarted in the same process would continue from a state that no boot ever + produces. A process restart rebuilds the controller from the Store, which is + the path every boot already runs. +* An unbounded retry is the invisible spin the card forbids. A bounded retry + would reimplement the Supervisor watchdog's own throttle: 10 restarts per + 30 min, and 5 attempts with backoff (`apps/const.py`). + +## 2. What happens after the exit, verified rather than assumed + +* **Exit status reaches Docker.** The add-on image (s6-overlay, `init: false`, + `CMD /run.sh`) was run with `exec python3 -c 'raise SystemExit(70)'`. + `docker inspect` gave ExitCode 70. The same test with exit 0 gave 0, and an + uncaught exception gave 1. +* **Supervisor 2026.08.0** (`ghcr.io/home-assistant/amd64-hassio-supervisor`, + source read from the image): + * A non-zero container exit is recorded as `ContainerState.FAILED` + (`docker/monitor.py`). The Supervisor logs *"App … exited with non-zero + exit code 70"* at ERROR (`apps/app.py container_state_changed`). + * The Supervisor restarts the add-on **only if the per-install Watchdog + toggle is on**. `watchdog_container()` returns when `not self.watchdog`. + The toggle defaults to **off** (`apps/validate.py`: + `vol.Optional(ATTR_WATCHDOG, default=False)`). + * Add-on containers get **no Docker restart policy**. The only + `restart_policy=` in the Supervisor belongs to the observer. + * `boot: auto` in `config.yaml` only controls starting at host boot. The + `watchdog:` key in `config.yaml` is a health-check URL, not a restart + policy, and this add-on does not set it. +* **So on a default install the add-on stays stopped after this exit.** The UI + shows it as stopped, its log holds the traceback, and the Supervisor log holds + an ERROR line. The pack is at 0 W, which is the same physical state as before + this card. The difference is that 0 W is written immediately instead of after + the ~30 s veto, and the add-on no longer shows green. With the Watchdog toggle + on, the Supervisor restarts the add-on. +* **Not verified:** an actual restart by a running Supervisor. That would need a + live Supervisor, and the only one available is the live house. + +## 3. Left open for the owner + +* Whether `DOCS.md` should tell installers to enable Watchdog. DOCS.md is not + this card's file. +* Setting the Watchdog toggle from inside the add-on (`/addons/self/options`) + was rejected here, because it would change a user setting without the user + knowing. + +## 4. Scope: the siblings, and why they are not supervised + +* `run_tariff_refresh()` and the P1 HTTP and HA transports already catch + `Exception` inside their loops by design, and the values they feed are + age-bounded downstream. +* The P1 MQTT source *returns* on purpose when it is misconfigured. Making every + long-lived task's end exit the process would turn that deliberate fail-safe + into a restart loop. +* Only the control task is supervised. + +## 5. `hass.py`: an undecodable body is an absence + +A non-JSON `200` served as `text/html` was **already** treated as an absence, +because aiohttp's `ContentTypeError` is a `ClientError`. The reads that actually +escaped were these three: + +* a malformed body labelled `application/json`, which raises `JSONDecodeError` + (a `ValueError`); +* a JSON body that is not an object, which raises `AttributeError` in + `number()` and `limits()`; +* an undecodable error body in `call()`, which raises `UnicodeDecodeError`. + +All three were measured against aiohttp 3.13.5. The first two now read as +`None`, and the third is now a failed write (`False`). + +## 6. Status row + +`checks()` now starts with a *control loop* row showing how long ago the loop +last completed a pass. The row turns red once that age exceeds +`FIRMWARE_INGEST_VETO_S`. The heartbeat is sent from this loop, so past that age +layer 1 has zeroed the inverter. diff --git a/goodwe_controller/app/hass.py b/goodwe_controller/app/hass.py index 7ea8bb1..c4925db 100644 --- a/goodwe_controller/app/hass.py +++ b/goodwe_controller/app/hass.py @@ -61,10 +61,17 @@ class HomeAssistant: if resp.status == 404: return None resp.raise_for_status() - return await resp.json() - except (aiohttp.ClientError, TimeoutError) as err: + obj = await resp.json() + # SAFETY-61: an undecodable body is an absence like any other failed + # read, never an exception into the control loop. + except (aiohttp.ClientError, TimeoutError, ValueError) as err: self._moan(f"read:{entity_id}", "read %s failed: %s", entity_id, err) return None + if not isinstance(obj, dict): + self._moan(f"shape:{entity_id}", "read %s: not a state object: %.80r", + entity_id, obj) + return None + return obj async def number(self, entity_id: str, invert: bool = False) -> float | None: """Numeric state, or None. Never substitutes a default.""" @@ -117,7 +124,8 @@ class HomeAssistant: domain, service, resp.status, body[:200]) return False return True - except (aiohttp.ClientError, TimeoutError) as err: + # ValueError: an undecodable error body (SAFETY-61) is a failed write. + except (aiohttp.ClientError, TimeoutError, ValueError) as err: self._moan(f"svcerr:{domain}.{service}", "service %s.%s failed: %s", domain, service, err) return False diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 71bf8d3..fb97350 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -25,9 +25,11 @@ battery to zero on its own. Never "hold the last value to be safe". import asyncio import contextlib +import functools import json import logging import signal +import time from datetime import datetime, timedelta, timezone import aiohttp @@ -74,8 +76,8 @@ from .price_history import PriceHistory from .static_tariff import resolve_tariff, static_status from .tariff import PeakStore, PeakTracker from .store import migrate_maint_keys, migrate_unit_keys -from .validate import (ConfigRefused, refuse, validate_startup_config, - validate_unit_ranges) +from .validate import (FIRMWARE_INGEST_VETO_S, ConfigRefused, refuse, + validate_startup_config, validate_unit_ranges) from .watchdog import ( AGAINST_METER, AGAINST_OWN_POWER, SIGN_OPTION_DEFAULTS, SignWatchdog, SignWatchdogConfig, loop_is_following, @@ -985,6 +987,8 @@ class Controller: # the value a clamp bit is a value written to ONE device. self.loop_clamped: tuple[bool, str] = (False, "") self.stopping = False + # SAFETY-61. time.monotonic() at the end of the last run_control() pass. + self.loop_pass_mono = None # -- helpers ------------------------------------------------------------- def log_event(self, msg: str) -> None: @@ -4397,6 +4401,7 @@ class Controller: await self.send_heartbeats(asyncio.get_running_loop().time(), heartbeat) self.publish() + self.loop_pass_mono = time.monotonic() await asyncio.sleep(1) async def send_heartbeats(self, loop_now: float, heartbeat_s: float) -> None: @@ -4596,6 +4601,22 @@ class Controller: """ o = self.o out = [] + # SAFETY-61. First, so a stalled loop is the headline: the heartbeat is + # sent from this loop, so past layer 1's veto the inverter is at 0 W. + if self.loop_pass_mono is None: + out.append({"ok": True, "warn": False, + "text": "control loop: starting"}) + else: + _pass_age = time.monotonic() - self.loop_pass_mono + if _pass_age > FIRMWARE_INGEST_VETO_S: + out.append({"ok": False, "warn": False, + "text": f"control loop: NO PASS FOR {_pass_age:.0f} s" + f" (layer 1 zeroes the inverter after " + f"{FIRMWARE_INGEST_VETO_S:.0f} s without a " + f"heartbeat)"}) + else: + out.append({"ok": True, "warn": False, + "text": f"control loop: last pass {_pass_age:.0f} s ago"}) if self.p1_enabled: age = self.p1.published_age_s if self.p1.stale: @@ -5449,6 +5470,30 @@ class Controller: return None +# SAFETY-61. Exit status when the control task dies; 70 is sysexits(3) +# EX_SOFTWARE. See DECISIONS/SAFETY-61-control-task-death.md. +EXIT_CONTROL_DIED = 70 + + +class ControlTaskDied(RuntimeError): + """The control task ended while nothing had asked it to stop.""" + + +def control_task_done(task: asyncio.Task, *, controller, stop: asyncio.Event, + died: list) -> None: + """Done-callback on the control task: log its death now and wake amain() + to wind down and exit (SAFETY-61, see its DECISIONS record).""" + if stop.is_set() or controller.stopping: + return # the normal wind-down, or run_control()'s refusal path + exc = None if task.cancelled() else task.exception() + _LOG.critical("CONTROL LOOP DIED (%s) - commanding 0 W and exiting with " + "status %d", "cancelled" if task.cancelled() else + (repr(exc) if exc else "returned"), EXIT_CONTROL_DIED, + exc_info=exc) + died.append(exc) + stop.set() + + async def amain() -> None: opts = load_options() logging.basicConfig( @@ -5546,7 +5591,13 @@ async def amain() -> None: with contextlib.suppress(NotImplementedError): loop.add_signal_handler(sig, stop.set) - tasks = [asyncio.create_task(controller.run_control())] + # SAFETY-61: the control task's death ends the process, after the + # wind-down below. See DECISIONS/SAFETY-61-control-task-death.md. + died: list = [] + control = asyncio.create_task(controller.run_control()) + control.add_done_callback(functools.partial( + control_task_done, controller=controller, stop=stop, died=died)) + tasks = [control] # OPT-04. The tariff refresh runs as its OWN long-lived task, for the # reason P1 ingestion does and then some: `resolve_tariff()` may open an @@ -5581,10 +5632,14 @@ async def amain() -> None: for task in tasks: task.cancel() for task in tasks: + if task is control and died: + continue # already logged by control_task_done() with contextlib.suppress(asyncio.CancelledError): await task await runner.cleanup() _LOG.info("stopped") + if died: + raise ControlTaskDied(died[0]) # The late-arriving-device refusal from run_control(). Re-raised only # now, so the wind-down above still ran and the inverter is at 0 W. if controller.refused: @@ -5603,6 +5658,9 @@ def main() -> None: # EX_CONFIG, so even a script reading the exit status can tell a bad # config from a bug. raise SystemExit(78) + except ControlTaskDied: + # No second traceback: control_task_done() logged it at the death. + raise SystemExit(EXIT_CONTROL_DIED) if __name__ == "__main__": diff --git a/goodwe_controller/test_control_task.py b/goodwe_controller/test_control_task.py new file mode 100644 index 0000000..2947e1c --- /dev/null +++ b/goodwe_controller/test_control_task.py @@ -0,0 +1,373 @@ +"""Runnable check for SAFETY-61: the control task's death. `python3 test_control_task.py` + +If `run_control()` raised, nothing noticed: the task ended, `stop` was never +set, the web UI kept serving and the Supervisor saw a healthy container. The +card's fix and its reasons are in DECISIONS/SAFETY-61-control-task-death.md. + +Parts 1-3 drive the REAL `app.main.main()` - the process entry point - in a +child process (this file re-invoked with `--driver`), with only the outside +world faked: options, Home Assistant, the store, the web server and the core +API probe. The child's exit status is the real one. Each child runs under a +deadline, because the defect this card closes is a HANG (MUTATION.md habit 5). + +Takes ~15 s. Purge `__pycache__` before a mutation run (MUTATION.md). +""" + +import asyncio +import json +import os +import signal +import subprocess +import sys +import time + +HERE = os.path.dirname(os.path.abspath(__file__)) +FAULT = "injected SAFETY-61 fault" +DEADLINE_S = 40 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +# --------------------------------------------------------------------------- # +# The child: the real main() with the outside world faked. +# --------------------------------------------------------------------------- # +BASE = {"setpoint_entity": "number.sp", "meter_entity": "sensor.grid", + "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", + "meter_source": "off", "max_w": 2000, "gain": 0.6, "slew_w": 0, + "deadband_w": 15, "target_grid_w": -10, "step_w": 10, + "heartbeat_s": 10, "stale_input_s": 15, "cycle_floor_s": 1, + "auto_start": True} + + +def driver(scenario): + import aiohttp + import app.main as M + import app.store + import app.web + + def event(*e): + """Streamed as it happens, so a child killed at the deadline or by + os._exit() still reports what it did.""" + print("EV " + json.dumps(list(e)), flush=True) + t0 = time.monotonic() + + class FakeHass: + def __init__(self): + self.batt = 0.0 + self.limit_calls = 0 + + async def limits(self, entity): + self.limit_calls += 1 + # "refuse": ESPHome not up at the startup gate, then a rating + # below max_w once run_control() re-reads it -> its refusal path. + if scenario == "refuse": + return (None, None, None) if self.limit_calls == 1 else (-1000.0, 1000.0, 1.0) + return (-5000.0, 5000.0, 1.0) + + async def number(self, entity, invert=False): + if entity == "sensor.grid": + # a steady 600 W import, alternating by 1 W so every pass cycles + return 600.0 + (int(time.monotonic() - t0) % 2) + if entity == "sensor.batt": + return self.batt + if entity == "sensor.soc": + return 50.0 + return None + + async def state(self, entity): + return None + + async def set_number(self, entity, value): + event("w", float(value)) + self.batt = float(value) + return True + + async def call(self, *a, **k): + return True + + async def mqtt_service(self): + raise RuntimeError("no broker in this test") + + class _Store: + data = {} + + def get(self, key, default=None): + return default + + def set(self, *a, **k): + pass + + class _Runner: + async def cleanup(self): + event("cleanup") + + async def _web_start(controller, port=8099, selfcfg=None): + return _Runner() + + class _NoProbeSession: + """The core API probe in amain() must not touch a network.""" + async def __aenter__(self): + return self + + async def __aexit__(self, *a): + return False + + def get(self, *a, **k): + raise OSError("no network in this test") + + M.load_options = lambda: dict(BASE) + M.HomeAssistant = lambda session: FakeHass() + app.store.Store = _Store + app.web.start = _web_start + aiohttp.ClientSession = _NoProbeSession + + real_cycle = M.Controller.cycle + n = {"cycles": 0} + + async def cycle(self): + n["cycles"] += 1 + if scenario == "fault" and n["cycles"] == 4: + event("fault") + raise RuntimeError(FAULT) + await real_cycle(self) + if scenario == "clean" and n["cycles"] == 4: + os.kill(os.getpid(), signal.SIGTERM) # the Supervisor's stop + + M.Controller.cycle = cycle + M.main() + + +def run_child(scenario): + env = dict(os.environ, PYTHONDONTWRITEBYTECODE="1") + try: + p = subprocess.run([sys.executable, "-B", __file__, "--driver", scenario], + cwd=HERE, env=env, capture_output=True, text=True, + timeout=DEADLINE_S) + except subprocess.TimeoutExpired as e: + rc, out, err = None, e.stdout or "", e.stderr or "" + else: + rc, out, err = p.returncode, p.stdout, p.stderr + out = out.decode() if isinstance(out, bytes) else out + err = err.decode() if isinstance(err, bytes) else err + events = [json.loads(ln[3:]) for ln in out.splitlines() if ln.startswith("EV ")] + return rc, out, err, events + + +def tail(text, n=15): + return "\n".join(" | " + ln for ln in text.splitlines()[-n:]) + + +if len(sys.argv) == 3 and sys.argv[1] == "--driver": + driver(sys.argv[2]) + sys.exit(0) # unreachable in every scenario: main() exits itself + + +# --------------------------------------------------------------------------- # +print("1. an exception inside cycle() - the real main(), in a child process") +rc, out, err, ev = run_child("fault") +print(f" exit status {rc}; events {ev}") +check(f"the process ENDS inside {DEADLINE_S} s rather than sitting there " + "healthy (the defect is a hang)", rc is not None) +check("exit status is 70 (EX_SOFTWARE), not 0 and not an unhandled crash's 1", + rc == 70) +fault_at = ev.index(["fault"]) if ["fault"] in ev else None +before = [e[1] for e in ev[:fault_at] if e[0] == "w"] if fault_at is not None else [] +after = [e[1] for e in ev[fault_at + 1:] if e[0] == "w"] if fault_at is not None else [] +# Precondition (habit 23): the inverter was holding a NON-ZERO command when the +# fault hit, so a 0 W write afterwards is evidence of the wind-down, not rest. +check("precondition: the fault hit while the last command was non-zero " + f"(last before fault = {before[-1] if before else None})", + fault_at is not None and bool(before) and before[-1] != 0.0) +check(f"the wind-down ran: 0 W written AFTER the fault (writes after = {after})", + after == [0.0]) +check("the web runner was cleaned up, i.e. the ordinary shutdown path ran", + ["cleanup"] in ev[(fault_at or 0):]) +died_line = next((i for i, ln in enumerate(err.splitlines()) + if "CONTROL LOOP DIED (RuntimeError('" + FAULT + "'))" in ln), None) +wind_line = next((i for i, ln in enumerate(err.splitlines()) + if "shutting down - commanding 0 W" in ln), None) +check("a CRITICAL line names the exception and the exit status", + died_line is not None + and "CRITICAL" in err.splitlines()[died_line] + and "commanding 0 W and exiting with status 70" in err.splitlines()[died_line]) +check("the traceback is logged, down to the frame that raised", + "Traceback (most recent call last)" in err + and f"RuntimeError: {FAULT}" in err and "in cycle" in err) +check("it is logged AT THE DEATH, before the wind-down - not only at exit", + died_line is not None and wind_line is not None and died_line < wind_line) +check("exactly one traceback: main() does not print a second one", + err.count("Traceback (most recent call last)") == 1) +if fails: + print(tail(err, 30)) + +# --------------------------------------------------------------------------- # +print("2. the same entry point stopped by SIGTERM - the callback must stay quiet") +rc2, out2, err2, ev2 = run_child("clean") +print(f" exit status {rc2}; events {ev2}") +check("an ordinary stop still exits 0", rc2 == 0) +check("an ordinary stop logs no CONTROL LOOP DIED", "CONTROL LOOP DIED" not in err2) +check("an ordinary stop still winds down to 0 W, from a non-zero command", + any(e[0] == "w" and e[1] != 0.0 for e in ev2) + and [e for e in ev2 if e[0] == "w"][-1:] == [["w", 0.0]]) + +# --------------------------------------------------------------------------- # +print("3. run_control()'s own refusal path returns on purpose - still exit 78") +rc3, out3, err3, ev3 = run_child("refuse") +print(f" exit status {rc3}") +check("a late-arriving device rating refusal exits 78 (EX_CONFIG), not 70", + rc3 == 78) +check("and is not reported as a death", "CONTROL LOOP DIED" not in err3) +if rc3 != 78: + print(tail(err3)) + +# --------------------------------------------------------------------------- # +print("4. hass.py: a body that is not a state object is an ABSENCE") +import aiohttp # noqa: E402 +from aiohttp import web as aioweb # noqa: E402 + +import app.hass as H # noqa: E402 + + +async def hass_cases(): + async def handler(req): + k = req.match_info["k"] + if k == "sensor.good": + return aioweb.json_response({"entity_id": k, "state": "42"}) + if k == "sensor.badjson": + return aioweb.Response(text="{not json", content_type="application/json") + if k == "sensor.list": + return aioweb.Response(text="[1, 2]", content_type="application/json") + if k == "sensor.html": + return aioweb.Response(text="", content_type="text/html") + return aioweb.Response(status=404) + + async def svc(req): + return aioweb.Response(body=b"\xff\xfe\xfa", status=400, + headers={"Content-Type": "text/plain; charset=utf-8"}) + + app_ = aioweb.Application() + app_.router.add_get("/states/{k}", handler) + app_.router.add_post("/services/{d}/{s}", svc) + runner = aioweb.AppRunner(app_) + await runner.setup() + site = aioweb.TCPSite(runner, "127.0.0.1", 0) + await site.start() + port = site._server.sockets[0].getsockname()[1] + H.CORE_API = f"http://127.0.0.1:{port}" + got = {} + try: + async with aiohttp.ClientSession() as session: + h = H.HomeAssistant(session, token="t") + for e in ("sensor.good", "sensor.badjson", "sensor.list", "sensor.html"): + try: + got[e] = ("ok", await h.number(e)) + except Exception as err: # noqa: BLE001 + got[e] = ("raised", type(err).__name__) + try: + got["call"] = ("ok", await h.set_number("number.sp", 0)) + except Exception as err: # noqa: BLE001 + got["call"] = ("raised", type(err).__name__) + finally: + await runner.cleanup() + return got + +got = asyncio.run(hass_cases()) +print(f" {got}") +check("baseline: a well-formed state reads as its value (42.0)", + got["sensor.good"] == ("ok", 42.0)) +check("a malformed JSON body labelled application/json reads as None, not a raise", + got["sensor.badjson"] == ("ok", None)) +check("a JSON body that is not an object reads as None, not a raise", + got["sensor.list"] == ("ok", None)) +check("a text/html 200 reads as None (already true before SAFETY-61)", + got["sensor.html"] == ("ok", None)) +check("a rejected write with an undecodable body is a failed write (False)", + got["call"] == ("ok", False)) + +# --------------------------------------------------------------------------- # +print("5. the control-loop status row") +from app.main import Controller # noqa: E402 + + +class _Pub: + enabled = False + + def publish(self, *a, **k): + pass + + def close(self): + pass + + +class _Store: + data = {} + + def set(self, *a, **k): + pass + + +class _RowHass: + async def limits(self, entity): + return (-5000.0, 5000.0, 1.0) + + async def number(self, entity, invert=False): + return {"sensor.grid": 600.0, "sensor.soc": 50.0}.get(entity, 0.0) + + async def state(self, entity): + return None + + async def set_number(self, entity, value): + return True + + async def call(self, *a, **k): + return True + + +def rows_for(pass_age): + c = Controller(dict(BASE), _RowHass(), _Store(), _Pub(), stop=asyncio.Event()) + c.loop_pass_mono = None if pass_age is None else time.monotonic() - pass_age + return c.checks() + + +r_new, r_29, r_31 = rows_for(None), rows_for(29), rows_for(31) +print(f" {r_new[0]} | {r_29[0]} | {r_31[0]}") +check("before the first pass the row is ok and says 'starting'", + r_new[0] == {"ok": True, "warn": False, "text": "control loop: starting"}) +check("29 s after a pass it is ok", + r_29[0] == {"ok": True, "warn": False, + "text": "control loop: last pass 29 s ago"}) +check("31 s after a pass it is RED and first, naming the age and the veto", + r_31[0] == {"ok": False, "warn": False, + "text": "control loop: NO PASS FOR 31 s (layer 1 zeroes the " + "inverter after 30 s without a heartbeat)"}) + + +async def one_pass(): + c = Controller(dict(BASE), _RowHass(), _Store(), _Pub(), stop=asyncio.Event()) + c.auto = True + before = getattr(c, "loop_pass_mono", "absent") + t = asyncio.create_task(c.run_control()) + await asyncio.sleep(2.5) + c.stopping = True + await asyncio.wait_for(t, timeout=10) + return before, getattr(c, "loop_pass_mono", None) + +_before, _after = asyncio.run(one_pass()) +print(f" stamp before run: {_before}; age after 2.5 s: " + f"{None if _after is None else round(time.monotonic() - _after, 2)} s") +check("the real run_control() stamps each pass", + _before is None and _after is not None and time.monotonic() - _after < 3) + +print() +if fails: + print(f"FAILED: {len(fails)}") + for f in fails: + print(f" - {f}") + sys.exit(1) +print("all SAFETY-61 checks passed") -- 2.54.0 From b06f1fad5fcd556e91495cf7fec03dc66b4e5793 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 00:00:55 +0200 Subject: [PATCH 004/105] SAFETY-62 review: DOCS exit 3 at the command block (R1); recognise the `auto` store key (R2) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- goodwe_controller/DOCS.md | 4 ++-- goodwe_controller/test_tool_inputs.py | 7 +++++++ goodwe_controller/tools/rehearse_roster.py | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index c16476e..c8a54f1 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2820,8 +2820,8 @@ a **copy** of the state file and reports the difference. --live-entities /w/live-entities.txt \ --reverse --round-trip' -Exit `0` clean · `1` at least one finding · `2` could not run. ⚠️ **`2` is not a -pass.** +Exit `0` clean · `1` at least one finding · `2` could not run · `3` clean but +degraded (`--no-live-entities`). ⚠️ **`2` and `3` are not a pass.** ### The owner steps, because this session could not take them diff --git a/goodwe_controller/test_tool_inputs.py b/goodwe_controller/test_tool_inputs.py index 2ab834d..9a8628d 100644 --- a/goodwe_controller/test_tool_inputs.py +++ b/goodwe_controller/test_tool_inputs.py @@ -154,6 +154,13 @@ for label, (path, words) in cases.items(): code == RR.EXIT_COULD_NOT_RUN and words in out and "NO FINDINGS" not in out) +try: + _auto = RR.load_state(dump("s-auto.json", {"auto": True})) +except RR.Refused as err: + _auto = str(err) +check("a state holding only the Automatic toggle (`auto`, app/main.py) is " + "recognised as a store", _auto == {"auto": True}) + flat = RR.load_options(str(FIX / "flat.yaml")) roster = RR.load_options(str(FIX / "roster.yaml")) for side, kw in (("--before", {"before": dump("b.json", ha_apps_info(flat))}), diff --git a/goodwe_controller/tools/rehearse_roster.py b/goodwe_controller/tools/rehearse_roster.py index f37cb28..ebe8452 100644 --- a/goodwe_controller/tools/rehearse_roster.py +++ b/goodwe_controller/tools/rehearse_roster.py @@ -197,7 +197,8 @@ def load_options(path: str) -> dict: _UNIT_PREFIX = unit_key("\0", "").split("\0")[0] -_STORE_KEYS = {*DEFAULTS, *MAINT_UNIT_KEYS, SCHEMA_KEY, MAINT_SCHEMA_KEY} +# "auto" is the Automatic toggle, written by app/main.py outside DEFAULTS. +_STORE_KEYS = {*DEFAULTS, *MAINT_UNIT_KEYS, SCHEMA_KEY, MAINT_SCHEMA_KEY, "auto"} def load_state(path: str) -> dict: -- 2.54.0 From 770988c9026739d7c2c8e5abfa4ba5e74d924096 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 00:06:58 +0200 Subject: [PATCH 005/105] TEST-26: a missing value in a check is a named FAIL, not a traceback Checks and prints that indexed an empty list, exhausted next(), or formatted None killed the rest of their file (FCST-06). Read them through the new named_absence.py (nth/first/field/given/present) and conjoin a presence term. - every site in the brief, plus the family the new scan and a sweep found - test_named_absence.py: scans every test_*.py for unguarded filtered-list indexing, next() without a default and numeric formats on maybe-None names; proven to bite; prints what it cannot see, counted - test_price.py 16a: the `_T17_CAPS is _T17_CAPS` tautology now grades the two assemble() calls' arguments - test_control.py: coverage table re-measured on runs graded to the end Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- goodwe_controller/named_absence.py | 99 ++++++ goodwe_controller/test_arbitrage.py | 24 +- goodwe_controller/test_clamp.py | 17 +- goodwe_controller/test_control.py | 107 ++---- goodwe_controller/test_delivery.py | 10 +- goodwe_controller/test_freeze.py | 6 +- goodwe_controller/test_freshness.py | 81 +++-- goodwe_controller/test_inverter.py | 9 +- goodwe_controller/test_named_absence.py | 426 +++++++++++++++++++++++ goodwe_controller/test_p1.py | 4 +- goodwe_controller/test_packshare.py | 11 +- goodwe_controller/test_peakguard.py | 155 +++++---- goodwe_controller/test_price.py | 51 ++- goodwe_controller/test_price_forecast.py | 9 +- goodwe_controller/test_price_history.py | 19 +- goodwe_controller/test_pv.py | 38 +- goodwe_controller/test_static_tariff.py | 7 +- goodwe_controller/test_tariff.py | 44 +-- goodwe_controller/test_watchdog.py | 22 +- 19 files changed, 853 insertions(+), 286 deletions(-) create mode 100644 goodwe_controller/named_absence.py create mode 100644 goodwe_controller/test_named_absence.py diff --git a/goodwe_controller/named_absence.py b/goodwe_controller/named_absence.py new file mode 100644 index 0000000..eb78d36 --- /dev/null +++ b/goodwe_controller/named_absence.py @@ -0,0 +1,99 @@ +"""Read a value a check prints or grades without raising (TEST-26). + +Each test file is one script, so an IndexError in a print or a check name +kills every check after it (MUTATION.md, FCST-06). Read through these instead, +and conjoin `present(x)` in the check so the absence grades as a named FAIL. + +`ABSENT` values never raise: they format as `` under any spec, +index and attribute to themselves, compare unequal AND not-unequal, and are +falsy. `not x`, `"a" not in x` and `all(... for _ in x)` are therefore TRUE of +one, which is why the check needs the `present()` term. `int()`, `range()` and +use as a list index still raise: guard those with `present()`. +""" + +_NAN = float("nan") + + +class Absent: + __slots__ = ("what",) + + def __init__(self, what): + object.__setattr__(self, "what", what) + + def __repr__(self): + return f"" + + __str__ = __repr__ + + def __format__(self, spec): + return repr(self) + + def __bool__(self): + return False + + def __eq__(self, other): + return False + + __ne__ = __lt__ = __le__ = __gt__ = __ge__ = __eq__ + + def __hash__(self): + return id(self) + + def __getitem__(self, _): + return self + + def __getattr__(self, _): + return self + + def __call__(self, *_a, **_k): + return self + + def __len__(self): + return 0 + + def __iter__(self): + return iter(()) + + def __contains__(self, _): + return False + + def __float__(self): + return _NAN + + def _same(self, *_): + return self + + __add__ = __radd__ = __sub__ = __rsub__ = __mul__ = __rmul__ = _same + __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = _same + __mod__ = __rmod__ = __neg__ = __pos__ = __abs__ = __round__ = _same + + +def present(*xs): + """True when none of `xs` is an ABSENT stand-in.""" + return not any(isinstance(x, Absent) for x in xs) + + +def nth(seq, i=0, what=None): + """`seq[i]`, or an ABSENT saying how many items there were.""" + n = 0 if seq is None else len(seq) + if -n <= i < n: + return seq[i] + return Absent(what or f"[{i}] of {n} item(s)") + + +def first(it, what="no match"): + """`next(it)`, or ABSENT when it is exhausted.""" + return next(iter(it), Absent(what)) + + +def field(mapping, key, what=None): + """`mapping[key]`, or ABSENT when the key (or the mapping) is missing.""" + try: + return mapping[key] + except (KeyError, IndexError, TypeError): + return Absent(what or f"key {key!r}") + + +def given(x, what="None"): + """`x`, or ABSENT when it is None - so `:.2f` and arithmetic cannot raise.""" + return Absent(what) if x is None else x diff --git a/goodwe_controller/test_arbitrage.py b/goodwe_controller/test_arbitrage.py index 737ef3d..89dd3f3 100644 --- a/goodwe_controller/test_arbitrage.py +++ b/goodwe_controller/test_arbitrage.py @@ -79,6 +79,7 @@ import sys from datetime import datetime, timedelta, timezone from app import arbitrage as _arb +from named_absence import first from app import main as _main from app import peakguard as _pg from app.arbiter import ( @@ -933,12 +934,12 @@ check("main.py passes the guard's OWN measured headroom at its one " # once in `__init__` and never refreshed would satisfy the pin above and would # size every trade from the guard decision of whatever cycle happened to run # last - which is the defect the hoist's own comment warns about, one level up. -_s45_cycle = next(n for n in ast.walk(_S45_MAIN_TREE) - if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) - and n.name == "cycle" - and any(isinstance(c, ast.Call) - and ast.unparse(c.func).endswith("arbitrage.decide") - for c in ast.walk(n))) +_s45_cycle = first((n for n in ast.walk(_S45_MAIN_TREE) + if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) + and n.name == "cycle" + and any(isinstance(c, ast.Call) + and ast.unparse(c.func).endswith("arbitrage.decide") + for c in ast.walk(n))), "no cycle() calling arbitrage.decide") check("...and the assignment is INSIDE the same `cycle()` that makes the call, " "so the headroom the trade is sized from is this cycle's guard decision " "and not one carried from an arbitrary earlier one", @@ -1069,22 +1070,23 @@ def s45_loop(*, sized: bool, cap_w=S45_CAP_W, load_w=S45_LOAD_W, res = resolve(claims) target = res.target_w head_w = _pg.charge_headroom_w(pk) if sized else HEADROOM_CLEAR - rec.append(dict( + row = dict( t_s=t, action=arb.action, power_w=arb.power_w, reason=arb.reason, price=arb.price_now_eur_kwh, spread=arb.spread_eur_kwh, winner=res.winner, target_w=float(res.target_w), headroom_w=head_w, engaged=bool(pk.engaged), sized_from_meter=_arb.sized_from_meter( - arb, head_w, winner=res.winner))) + arb, head_w, winner=res.winner)) + rec.append(row) if shadow: # --- TRANSCRIBED 1/3: `_shadow_settle()`'s record, taken # BEFORE the re-seed destroys its evidence. - rec[-1]["would_w"] = float(res.target_w) - rec[-1]["row"] = _shadow.words( + row["would_w"] = float(res.target_w) + row["row"] = _shadow.words( {"shadow_mode": "on"}, control_started=False, would_w=float(res.target_w), - sized_from_meter=rec[-1]["sized_from_meter"], + sized_from_meter=row["sized_from_meter"], reason=res.explain()) # --- TRANSCRIBED 2/3: `_write_unit()`'s substitution - the # plant below is driven from WIRE_W, not from the decision. diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index 8659611..dc033a2 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -78,6 +78,8 @@ import re import sys from datetime import datetime, timedelta, timezone +from named_absence import given, nth, present + from app.clamp import ( CLEAR_CYCLES, REASON_CODE, REASSERT_S, SUSTAINED_CYCLES, ClampWatchdog, clamp_to_rating, @@ -322,15 +324,15 @@ _esc_fires = [5.0 * (CLEAR_CYCLES + 2 + _j) T0 + timedelta(seconds=5.0 * (CLEAR_CYCLES + 2 + _j)))] _esc_delay = _esc_fires[0] - _RUNAWAY_AT if _esc_fires else None print(f" budget spent by a benign episode, then a continuous runaway from " - f"t={_RUNAWAY_AT:.0f}s: first alarm at t={_esc_fires[0]:.0f}s " - f"(delay {_esc_delay:.0f}s)") + f"t={_RUNAWAY_AT:.0f}s: first alarm at t={nth(_esc_fires, 0):.0f}s " + f"(delay {given(_esc_delay):.0f}s)") check(f"⚠️ a SUSTAINED runaway speaks even when an earlier, unrelated episode " - f"spent the budget - it is not held for REASSERT_S ({_esc_delay:.0f}s " + f"spent the budget - it is not held for REASSERT_S ({given(_esc_delay):.0f}s " f"delay, escalation is {SUSTAINED_CYCLES} cycles)", _esc_delay is not None and _esc_delay < REASSERT_S / 2) check("...and it speaks at the escalation boundary rather than immediately, " "which is what keeps the scattered flood suppressed", - _esc_delay >= 5.0 * (SUSTAINED_CYCLES - 1)) + _esc_delay is not None and _esc_delay >= 5.0 * (SUSTAINED_CYCLES - 1)) # ⚠️ `last_alarm` SURVIVING THE DE-ASSERT IS NOW LOAD-BEARING, AND NOTHING # PINNED IT. Review built the mutation: if the de-assert path ALSO refreshed @@ -523,7 +525,7 @@ check(f"a long winding episode does NOT flood the 40-row event log " f"({len(rows_l)} rows for {ctl_l.clamp_wd.engagements} engagements)", ctl_l.clamp_wd.engagements > 40 and len(rows_l) <= ctl_l.clamp_wd.episodes) check("...and the count in the row is the counter's, so nothing is lost", - f"{ctl_l.clamp_wd.engagements} engagement(s)" in rows_l[-1]) + f"{ctl_l.clamp_wd.engagements} engagement(s)" in nth(rows_l, -1)) # The RED row exists only while engaged, and the episode above is short, so it # is captured mid-run rather than asserted after the hysteresis has cleared it. check("the status page goes red WHILE it is engaged", @@ -1093,7 +1095,8 @@ check("...and the TRANSPOSED sentence appears on NEITHER surface, so the two " not any(f"the computed setpoint {_sent_x:+.0f} W was clamped to " f"{_asked_x:+.0f} W" in e for e in _rows_x) and f"the computed setpoint {_sent_x:+.0f} W was clamped to " - f"{_asked_x:+.0f} W" not in notes_x[0]["message"]) + f"{_asked_x:+.0f} W" not in nth(notes_x, 0)["message"] + and present(nth(notes_x, 0))) # The DEVICE bound, off part 6c's controller: same sentence, other stage. The # unit of coverage is the call site, and `bound` is the only thing that differs # between the two rows an operator can receive. @@ -1105,7 +1108,7 @@ check("...and the same ordered pair holds on the DEVICE-bound row, where the " and any(f"the computed setpoint {_asked_w:+.0f} W was clamped to " f"{_sent_w:+.0f} W" in e for e in ctl_w.events) and f"the computed setpoint {_asked_w:+.0f} W was clamped to " - f"{_sent_w:+.0f} W" in notes_w[0]["message"]) + f"{_sent_w:+.0f} W" in nth(notes_w, 0)["message"]) # ============================================================================== diff --git a/goodwe_controller/test_control.py b/goodwe_controller/test_control.py index 08c79ac..46a3085 100644 --- a/goodwe_controller/test_control.py +++ b/goodwe_controller/test_control.py @@ -17,6 +17,7 @@ Read MUTATION.md before you report a survivor. import sys +from named_absence import nth from app.control import (LOOP_TICK_S, PLANT_SETTLE_DOWN_S, PLANT_SETTLE_S, SETTLE_CYCLES, SLEW_RAIL_FRAC, Tuning, compute, slew_limit_w, unasked_power, @@ -59,68 +60,34 @@ def check(name, cond): # stopped testing anything is precisely the failure this ticket exists to fix. # A comment cannot go stale-green, because it never claims to be running. # -# Measured at 389d9ec. Numbers are the lead's independent reproduction. -# ⚠️ THE SAFETY-13 ROWS WERE RE-MEASURED IN ROUND 2 AND THREE OF THEM WERE -# WRONG AS FIRST WRITTEN. Every figure below marked (S13) was taken by deleting -# the mechanism, purging __pycache__, running this file in the CI image and -# counting `FAIL` lines, on THIS tree; the release/1.0 comparison figures were -# taken the same way on a pristine c8dcb38 worktree. +# Measured at TEST-26 on a purged tree in the CI image, each run graded to the +# end of the file (98/99 where the `if _bad:` check is skipped). Before TEST-26 +# the rows marked * killed the file with an IndexError or ZeroDivisionError in +# a check, so their earlier figures were short; those checks now fail by name. # -# - `output freeze` was written as 11. The mutation form its own note -# describes - the whole `target = min(...)/max(...)` line removed, `reason` -# left alone - gives 6 on this tree AND 6 on the first SAFETY-13 commit, -# against 2 on release/1.0. 11 is not reproducible by that form, or by -# removing the line and its `reason` (4), or by swapping min/max (12). The -# row is 6. -# - `saturation detector, saturated_now = False` was left at 11 while the -# SAFETY-13 section added checks that grade it. It is 15. -# - the footnote's `frozen = False` figure was left at 10 for the same -# reason. It is 13. -# -# The rows below `output freeze` are this ticket's own mechanisms: removing the -# EXIT restores release/1.0's unbounded freeze; making `unasked_power()` return -# True gives an exit to the limit case as well, which is the half of the -# decision that has to stay unbounded; deriving SETTLE_CYCLES from -# PLANT_SETTLE_S (18 s, the UP ramp) instead of PLANT_SETTLE_DOWN_S (23 s) is -# the round-1 defect itself; and pinning `_SAT_COUNT_CAP` back at release/1.0's -# literal 10 caps the counter below the bound and deletes the exit silently. -# -# ⚠️ ONLY THE ROWS THIS BRANCH MOVES WERE RE-MEASURED. Everything not marked -# (S13) still carries 389d9ec's figures and was not re-run here. -# -# ⚠️ THE SLEW ROWS WERE RE-MEASURED AT SAFETY-39 AND ONE OF THEM MOVED: the -# slew limit was 4 and is now 5, because the SAFETY-39 section grades it too. -# The new row is the RAIL DEFAULT specifically - `slew_limit_w()` reduced to -# `return abs(float(tuning.slew_w))`, which leaves the limit intact and only -# removes the 0-means-the-rail resolution. Three checks notice, which is over -# the invariant's floor of two. Both figures were reproduced by deleting the -# mechanism, running this file and counting, on a tree with __pycache__ purged. -# -# mechanism in compute() checks that fail when deleted -# ------------------------------------------ ----------------------------- -# integrator freeze (AC 3) 2 -# integrator clamp (AC 1) 6 -# integrator bound follows max_w 4 -# output clamp 3 -# slew limit 5 -# slew follows the rail (SAFETY-39), `slew_w` read raw 3 -# output freeze (S13) 6 -# the output freeze's EXIT (S13), freeze made unconditional again 4 -# `unasked_power()` discriminates, replaced by `return True` (S13) 6 -# SETTLE_CYCLES from PLANT_SETTLE_S, not _DOWN_S (S13) 9 -# `_SAT_COUNT_CAP` pinned back at release/1.0's 10 (S13) 6 -# deadband 5 -# quantisation 2 -# saturation detector, `saturated_now = False` (S13) 15 -# saturation duration (AC 2), fires instantly 2 -# sat counter reset on a good cycle 6 -# target_grid_w bias 3 -# i_w=None seeding from prev_w 6 -# -# The detector figure is for the `saturated_now = False` form specifically; -# disabling it further down as `frozen = False` is a weaker mutation and gives -# 13 on this tree (10 on release/1.0). Reproduce the same form or the number -# will not match. +# mechanism in compute(), and the exact form deleted checks that fail +# --------------------------------------------------------- ---------------- +# integrator freeze: `if not frozen or i_w == 0.0` -> `if True` 6 +# integrator clamp: `bounded = i_w` 6 +# integrator bound follows max_w: default `limit = 5000.0` 3 +# output clamp: `target = want` 3 +# slew limit: `slewed = target` 17 +# slew follows the rail (SAFETY-39): `slew_limit_w()` returns +# `abs(float(tuning.slew_w))` * 9 +# output freeze: the `target = min(...)/max(...)` line removed 7 +# output freeze: `if frozen:` -> `if False:` * 14 +# the output freeze's EXIT (S13): its `if` -> `if False` * 11 +# `unasked_power()` returns True (S13) 6 +# SETTLE_CYCLES from PLANT_SETTLE_S, not _DOWN_S (S13) 9 +# `_SAT_COUNT_CAP = 10`, release/1.0's literal (S13) * 11 +# deadband: its `if` -> `if False` 7 +# quantisation: `target = target` 4 +# saturation detector: `saturated_now = False` * 27 +# saturation detector: `frozen = False` * 25 +# saturation duration fires instantly: `sat_count >= 1` 5 +# sat counter not reset on a good cycle: `else sat_count` 5 +# target_grid_w bias: `error = grid_w` 5 +# i_w=None seeding from prev_w: `i_w = 0.0` 11 # # ⚠️ IT HAS FOUND A DEAD MECHANISM TWICE, BOTH THE SAME WAY: a clamp standing in # for the mechanism under test. Deleting the integrator freeze once failed @@ -142,10 +109,9 @@ def check(name, cond): # mutation run always has one, because the previous run wrote it. -B is still # worth passing, for the NEXT edit rather than this one. # -# The error is one-directional - stale bytecode can only under-report - so -# every figure above is a lower bound at worst, and the two zeros ever recorded -# were both confirmed by fixing them and watching the count rise, which a -# caching artefact cannot do. +# Two things under-report a figure here, both in the same direction: stale +# bytecode, and a check that raises and stops the file before the rest are +# graded (MUTATION.md, FCST-06). The second is what the * rows above had. # --------------------------------------------------------------------------- print("control law") @@ -520,7 +486,7 @@ for _ in range(20): rows.append((prev, d.target_w, d.i_w, d.reason)) prev, i_w, sat = d.target_w, d.i_w, d.sat_count pinned = [r for r in rows if r[3] == "saturated-freeze"] -check(f"non-zero prev_w, another writer: pinned at {pinned[0][1]:.0f} W...", +check(f"non-zero prev_w, another writer: pinned at {nth(pinned, 0)[1]:.0f} W...", pinned and all(r[1] == -800.0 for r in pinned)) # ⚠️ SAFETY-48 MOVED THIS NUMBER FROM -2390 W TO -1200 W, DELIBERATELY, AND # THE PROPERTY IT IS HERE FOR IS UNCHANGED. The release lets the command walk @@ -550,9 +516,9 @@ for c in range(24): cmds.append(d.target_w) prev, i_w, sat = d.target_w, d.i_w, d.sat_count check("the card's case: the block does hold at first, at 0 W", - cmds[6] == 0.0 and cmds[7] == 0.0) + nth(cmds, 6) == 0.0 and nth(cmds, 7) == 0.0) started = [i for i, c in enumerate(cmds) if c != 0.0] -check(f"the card's case: the charge starts at cycle {started[0]}" +check(f"the card's case: the charge starts at cycle {nth(started, 0)}" f" instead of never", bool(started)) # ⚠️ AND IT STOPS AT THE FROZEN INTEGRATOR, NOT AT THE RAIL. This is AC 4: the # integrator moved while the output was blocked, and the release must not turn @@ -991,7 +957,8 @@ check("the shipped Tuning default is 0, i.e. the rail, so the law carries no " # serial, per goodwe/NOTES.md §1.1b. It is here because the ARITHMETIC is what # is being graded, and the arithmetic does not care. _rails = [100.0, 500.0, 1500.0, 2000.0, 5000.0, 9600.0, 10000.0] -_ticks = {r: r / slew_limit_w(Tuning(max_w=r)) for r in _rails} +# A zero limit grades as nan ticks (a named FAIL), not a ZeroDivisionError. +_ticks = {r: r / (slew_limit_w(Tuning(max_w=r)) or float("nan")) for r in _rails} print(" ticks to cross the rail at the default, by rail: " + ", ".join(f"{r:.0f}W={t:.1f}" for r, t in _ticks.items())) check("⭐ AT EVERY RAIL THE DEFAULT TAKES THE SAME NUMBER OF TICKS TO CROSS IT - " @@ -1010,7 +977,7 @@ check("...and that is the same as saying the crossing takes the plant's own " # refuses on, and it is asserted HERE too so that the law and the gate cannot # drift apart - the rule can only ever refuse what this ratio says is too fast. _broken = Tuning(max_w=5000.0, slew_w=1000.0) -_broken_s = 5000.0 / slew_limit_w(_broken) * LOOP_TICK_S +_broken_s = 5000.0 / (slew_limit_w(_broken) or float("nan")) * LOOP_TICK_S print(f" the 2026-09-05 configuration (max_w 5000, slew_w 1000) crosses its " f"rail in {_broken_s:.0f} s against a plant measured at {PLANT_SETTLE_S:.0f} s") check("⭐ RESTORING slew_w 1000 AT max_w 5000 IS FASTER THAN THE PLANT, and by " diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index f7cf11e..29d3068 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -31,6 +31,8 @@ import re import sys from datetime import datetime, timedelta, timezone +from named_absence import given, present + from app.control import Tuning from app.delivery import ( DELIVERY_OPTION_DEFAULTS, DELIVERY_SHARE_FRACTION, REASON_CODE, @@ -738,8 +740,8 @@ async def _at_saturation_w(sat, b_frac=_SAT_B_FRAC): _c_ship, _r_ship = asyncio.run(_at_saturation_w(_SAT_SHIPPED)) _c_up, _r_up = asyncio.run(_at_saturation_w(_SAT_RAISED)) _b_ship, _b_up = _c_ship.inverters[1], _c_up.inverters[1] -_gap_ship = short_by(_b_ship.standing_w(), _b_ship.batt) -_gap_up = short_by(_b_up.standing_w(), _b_up.batt) +_gap_ship = given(short_by(_b_ship.standing_w(), _b_ship.batt), "B not short") +_gap_up = given(short_by(_b_up.standing_w(), _b_up.batt), "B not short") check(f"the raised threshold is a config an operator can actually enter: " f"{_SAT_RAISED} W is inside the shipped schema " @@ -762,7 +764,7 @@ check("the raised arm REACHED the comparison: B was asked for a discharge " "share, is short of it, is live, is not parked, and NOTHING accounts for " "it - the only thing standing between this unit and an alarm is the " "configured watts", - float(_b_up.standing_w()) > 0 and _gap_up is not None + float(_b_up.standing_w()) > 0 and present(_gap_up) and not _b_up.sign_wd.tripped and account(live=True, parked=False, soc=_b_up.soc, bms_floor=_b_up.bms_soc_floor) is None) @@ -780,7 +782,7 @@ check("...and SAFETY-43's RELATIVE arm is silent on both arms of this fixture, " check("...and its shortfall lands STRICTLY BETWEEN the two configured " "thresholds, which is the one place the two answers can differ. Part 4's " "fixtures are all above both, which is exactly why they cannot see this", - _gap_up is not None and float(_SAT_SHIPPED) < _gap_up < float(_SAT_RAISED)) + present(_gap_up) and float(_SAT_SHIPPED) < _gap_up < float(_SAT_RAISED)) check("AT THE SHIPPED THRESHOLD THE UNIT IS NAMED", _r_ship[-1]["named"] == ("inverter-b",)) diff --git a/goodwe_controller/test_freeze.py b/goodwe_controller/test_freeze.py index cdd6cd7..63f30e3 100644 --- a/goodwe_controller/test_freeze.py +++ b/goodwe_controller/test_freeze.py @@ -821,9 +821,9 @@ all_notes = all_notes_of(hass_f) # the whole surface # install has. Flipped here rather than plumbing a whole P1 transport in - the # row's own content is what is under test. ctl_f.p1_enabled = True -rows = [c for c in ctl_f.checks() if "METER MAY BE FROZEN" in c["text"]] +frozen_rows = [c for c in ctl_f.checks() if "METER MAY BE FROZEN" in c["text"]] print(f" frozen at +4000 W: command ran to {ctl_f.target:.0f} W, " - f"{len(notes)} notification(s), {len(rows)} red status row(s)") + f"{len(notes)} notification(s), {len(frozen_rows)} red status row(s)") # SURFACE-WIDE, deliberately, and the second guard has now landed. SAFETY-03 # ships `goodwe_output_clamp`, and this scenario - a runaway loop winding into # the rail - raises it legitimately: the loop asks for more than the rating and @@ -849,7 +849,7 @@ check("...with a fixed notification_id so repeats replace, not stack", check("...and it says the controller is still running", bool(notes) and "STILL RUNNING" in notes[0]["message"]) check("the status page carries a failed row saying so", - len(rows) == 1 and not rows[0]["ok"] and not rows[0]["warn"]) + len(frozen_rows) == 1 and not frozen_rows[0]["ok"] and not frozen_rows[0]["warn"]) check("the event log names it", any("METER FROZEN" in e for e in ctl_f.events)) # ⚠️ NOTIFY, NOT TRIP. If a later cut turns this into a trip it must come here # and change this expectation deliberately, not discover it in the field. diff --git a/goodwe_controller/test_freshness.py b/goodwe_controller/test_freshness.py index e04f6ab..89f9005 100644 --- a/goodwe_controller/test_freshness.py +++ b/goodwe_controller/test_freshness.py @@ -69,6 +69,7 @@ from datetime import datetime, timezone from pathlib import Path from app import freshness as F +from named_absence import first, given, nth, present from app.circulation import circulating_w from app.freshness import BOUNDS, BATT_OBLIGED_S, BATT_UNCHANGED_S, MOVE_W, Freshness from app.inverter import Inverter @@ -253,11 +254,12 @@ check("FRESH AND UNCHANGED is not stale. Forty identical readings over 39 s " check("⚠️ STALE IS. The same forty readings, the same instants, the same " "numbers - and the command moved 2500 W underneath them. The reading " "becomes None to its consumers, which is the whole card", - _stale.stale and _stale_read[-1] is None) + _stale.stale and bool(_stale_read) and _stale_read[-1] is None) check("...and it becomes None at the BOUND, not before: 35.0 s of unchanged " "arrivals, so the last fresh verdict is at t=34 and the first None at " "t=35", - _stale_read[34] == A_FROZEN_W and _stale_read[35] is None + len(_stale_read) > 35 + and _stale_read[34] == A_FROZEN_W and _stale_read[35] is None and BATT_UNCHANGED_S == 35.0) check("...and NEVER a held number and never a zero - `reading()` has exactly " "two shapes, the arrived value or None", @@ -449,14 +451,14 @@ _cu, _circu, _tripu, _standu, _ = run(_cycles(False)) _WD_S = 2.0 # `unit_sign_disagree_s` as this fixture sets it, above print(f" standing on A (gated): {[round(v) for v in _standg]}") print(f" gated : sign trip tick={_tripg} circ={_circg[:6]}...") -print(f" gate closed after {_tgate:.2f} s of WALL clock, against the " - f"{_WD_S:.0f} s watchdog window ({_WD_S / _tgate:.1f}x margin)") +print(f" gate closed after {given(_tgate):.2f} s of WALL clock, against the " + f"{_WD_S:.0f} s watchdog window ({_WD_S / given(_tgate):.1f}x margin)") print(f" counterfact: sign trip tick={_tripu} circ={_circu[:6]}...") check("⚠️ PRECONDITION ON THE WALL CLOCK, AND IT IS A CHECK RATHER THAN AN " "ASSUMPTION (CI-06). The gate closes on the INJECTED clock, the watchdog " "on the real one, so this fixture only means something while the gate " - f"closes well inside the window: it closed at {_tgate:.2f} s against " + f"closes well inside the window: it closed at {given(_tgate):.2f} s against " f"{_WD_S:.0f} s. If this fails the machine was slow, not the code - and " "saying so here is what stops that being read as a defect", _tgate is not None and _tgate < 0.5 * _WD_S) @@ -667,13 +669,13 @@ print("6. THE BOUNDS, graded against the SHIPPED config.yaml at BOTH ends") def option_default(key): - """`key`'s default out of config.yaml's `options:` block, at two spaces.""" + """`key`'s default out of config.yaml's `options:` block, at two spaces - or ABSENT.""" body = io.open(HERE / "config.yaml", encoding="utf-8").read() body = body[body.index("\noptions:"):body.index("\nschema:")] for line in body.splitlines(): if line.startswith(f" {key}:") and not line[2:3].isspace(): return float(line.split(":", 1)[1].strip()) - return None + return given(None, f"{key} not in config.yaml options") _circ_hold = option_default("circulation_hold_s") @@ -922,11 +924,11 @@ for _day in _loop_days: _prev8b = _f8b.stale _t += 1.0 _waits.sort() -_p50 = _waits[len(_waits) // 2] +_p50 = nth(_waits, len(_waits) // 2) print(f" {len(_loop_days)} days replayed at 1 Hz in " f"{time.monotonic() - _t8b:.1f}s: {_trips8b} trips") print(f" wait for the register's next change after a trip: " - f"min {_waits[0]:.1f} s median {_p50:.1f} s max {_waits[-1]:.1f} s; " + f"min {nth(_waits, 0):.1f} s median {_p50:.1f} s max {nth(_waits, -1):.1f} s; " f"{sum(1 for w in _waits if w >= 710.0)} at or over the live episode's " f"710 s") @@ -940,7 +942,7 @@ check("⚠️ THE OLD EXIT WAS NOT RARE AND IT WAS NOT SHORT. Ninety-three trips "143.4 s and as long as 21440.1 s. Seventeen of the ninety-three are at " "or beyond the 710 s the live site was parked for on 2026-09-21", _trips8b == 93 and abs(_p50 - 143.4) < 0.1 - and abs(_waits[-1] - 21440.1) < 0.1 + and abs(nth(_waits, -1) - 21440.1) < 0.1 and sum(1 for w in _waits if w >= 710.0) == 17) check("⚠️ AND THAT DISTRIBUTION IS A PROPERTY OF THIS BMS, NOT OF THIS CODE - " "which is the whole reason the exit could not stay as it was. The short " @@ -1072,6 +1074,8 @@ def _decoder(): def hms(t): + if not present(t): + return repr(t) return f"{int(t // 3600):02d}:{int(t % 3600 // 60):02d}:{int(t % 60):02d}" @@ -1241,9 +1245,9 @@ _holds = [(_bt_moves[i + 1][0] - _bt_moves[i][0], _bt_moves[i][0], _bt_moves[i + 1][0], _bt_moves[i][1]) for i in range(len(_bt_moves) - 1)] _HOLD_S, _HOLD_FROM, _REG_MOVES, _HOLD_W = max(_holds) -_TRIP = next(t for t, s, _h, _sw, _r in _rows_after if s and t > _HOLD_FROM) -_PARK = next(t for t, v in _sp if t > _TRIP and v == 0.0) -_HUMAN = next(t for t, v in _sp if t > _PARK and v != 0.0) +_TRIP = first((t for t, s, _h, _sw, _r in _rows_after if s and t > _HOLD_FROM), "no trip") +_PARK = first((t for t, v in _sp if t > _TRIP and v == 0.0), "no 0 W after the trip") +_HUMAN = first((t for t, v in _sp if t > _PARK and v != 0.0), "no command after the park") _blips = [t for t, s, _h, _sw, _r in _edges(_rows_after) if s and t < _HOLD_FROM] print(f" longest register hold {_HOLD_S:.1f} s at {_HOLD_W:+.0f} W, " @@ -1259,8 +1263,8 @@ def _first_clear_after(rows, t_from): return next((t for t, s, _h, _sw, _r in rows if t > t_from and not s), None) -_clear_before = _first_clear_after(_rows_before, _TRIP) -_clear_after = _first_clear_after(_rows_after, _TRIP) +_clear_before = given(_first_clear_after(_rows_before, _TRIP), "no clear") +_clear_after = given(_first_clear_after(_rows_after, _TRIP), "no clear") print(f" BEFORE (release_s=inf): stale {hms(_TRIP)} -> clear " f"{hms(_clear_before)} {_clear_before - _TRIP:.0f} s") print(f" AFTER (release_s={BOUNDS['batt'].release_s:.0f}): stale " @@ -1279,7 +1283,8 @@ check("PRECONDITION: the episode is in the capture where the manifest says it " "several. 0x0518 answers -3 W for 850.0 s from 10:51:24, the gate arms " "at 10:52:00, the site's own 0 W reaches the wire at 10:52:21, and " "nothing else moves until a human does at 11:05:31", - abs(_HOLD_S - 850.0) < 0.1 and _HOLD_W == -3.0 + present(_TRIP, _PARK, _HUMAN) + and abs(_HOLD_S - 850.0) < 0.1 and _HOLD_W == -3.0 and hms(_HOLD_FROM) == "10:51:24" and hms(_TRIP) == "10:52:00" and hms(_PARK) == "10:52:21" and hms(_HUMAN) == "11:05:31" and hms(_REG_MOVES) == "11:05:34" @@ -1310,7 +1315,7 @@ check("⚠️ GREEN AFTER, AND THE REGISTER NEVER MOVES - THIS IS THE CARD. The < _PARK + BOUNDS["batt"].release_s + 1.0 and hms(_clear_after) == "10:52:39" and _f_after.releases >= 1 and _D.held_at(_bt, _clear_after) == _D.held_at(_bt, _TRIP) == -3.0 - and next(r for r in _rows_after if r[0] == _clear_after)[2] == -3.0) + and first(r for r in _rows_after if r[0] == _clear_after)[2] == -3.0) check("...and the recovery is worth 776 s of this one episode: the site is " "handed its telemetry back at 10:52:39 instead of at 11:05:35, and 772 " "of those seconds are BEFORE the human touched anything. That is the " @@ -1555,8 +1560,9 @@ async def _wired_release(): _c57, _seen57 = run(_wired_release()) -_trip57 = next(t for t, b, _ok in _seen57 if b is None) -_back57 = next(t for t, b, _ok in _seen57 if t > _trip57 and b is not None) +_trip57 = first((t for t, b, _ok in _seen57 if b is None), "batt never None") +_back57 = first((t for t, b, _ok in _seen57 if t > _trip57 and b is not None), + "batt never back") print(f" real read path: batt None from t={_trip57}, a number again at " f"t={_back57}, register held {A_FROZEN_W:+.0f} throughout") check("⚠️ THROUGH THE SHIPPED READ PATH, NOT THE POLICY OBJECT. " @@ -1581,12 +1587,12 @@ check("⚠️ A LATCH THAT LETS GO ON A TIMER AND SAYS NOTHING IS ONE NO OPERATO "the event log and the logger, in order, naming the unit", len(_ev57) == 2 and "STALE inverter-a" in _ev57[1] and "STALE WITHDRAWN inverter-a" in _ev57[0] - and len(_rel57) == 1 and "inverter-a" in _rel57[0]) + and len(_rel57) == 1 and "inverter-a" in nth(_rel57, 0)) check("⚠️ AND THE RELEASE LINE REFUSES TO CLAIM A RECOVERY, because none has " "happened: it says in its own words that nothing has been learned about " "the register, and it prints the value the register is STILL holding", - "NOTHING HAS BEEN LEARNED ABOUT THE REGISTER" in _rel57[0] - and f"still holding {A_FROZEN_W:+.0f}" in _rel57[0]) + "NOTHING HAS BEEN LEARNED ABOUT THE REGISTER" in nth(_rel57, 0) + and f"still holding {A_FROZEN_W:+.0f}" in nth(_rel57, 0)) # --- 10h. the two sentences, as ORDERED PAIRS (habit 14) --------------------- @@ -1596,7 +1602,7 @@ check("⚠️ AND THE RELEASE LINE REFUSES TO CLAIM A RECOVERY, because none has # escape clause, and 250 W and 17.0 s again in the release note - so each is # asserted with its value embedded in its own literal position. _stale57 = [m for m in _msgs57 if "SAFETY-37" in m] -print(f" escape clause: ...{_stale57[0][-150:]}") +print(f" escape clause: ...{nth(_stale57, 0)[-150:]}") check("⚠️ THE STALE LINE'S PROMISE IS NOW TRUE, AND IT IS PINNED AS AN ORDERED " "PAIR. It used to end 'It clears itself the moment the register reports " "a different value.' - which was FALSE, because the 0 W in the sentence " @@ -1604,16 +1610,16 @@ check("⚠️ THE STALE LINE'S PROMISE IS NOW TRUE, AND IT IS PINNED AS AN ORDER "17 s in the TIME slot and 250 W in the POWER slot; swapped, this goes " "red", f"failing that {BOUNDS['batt'].release_s:.0f} s after the standing " - f"command falls below {BOUNDS['batt'].move_w:.0f} W" in _stale57[0]) + f"command falls below {BOUNDS['batt'].move_w:.0f} W" in nth(_stale57, 0)) check("...and the release note names 250 W in the POWER slot and 17 s in the " "TIME slot, in that order, which is the reverse arrangement of the same " "two numbers", f"sat below {BOUNDS['batt'].move_w:.0f} W for " - f"{BOUNDS['batt'].release_s:.0f} s" in _rel57[0]) + f"{BOUNDS['batt'].release_s:.0f} s" in nth(_rel57, 0)) check("...and the 35.0 s the register is re-graded over is named in the note " "too, because it is what the operator is being told to wait out", f"re-graded over a fresh {BOUNDS['batt'].unchanged_s:.0f} s window" - in _rel57[0]) + in nth(_rel57, 0)) check("⚠️ AND THE DIAGNOSIS HALF IS SAFETY-56'S AND HAS NOW BEEN REWRITTEN, " "WHICH IS WHAT THIS CHECK WAS FOR. It used to require 'battery-power " "register is not following its own command' to still be present, so " @@ -1622,7 +1628,8 @@ check("⚠️ AND THE DIAGNOSIS HALF IS SAFETY-56'S AND HAS NOW BEEN REWRITTEN, "requirement is now the inverse: the accusation is GONE from this line " "and part 11 grades what replaced it. The escape clause above is " "SAFETY-57's and is untouched by it", - "battery-power register is not following its own command" + present(nth(_stale57, 0)) + and "battery-power register is not following its own command" not in _stale57[0] and "did not move under a command that did" in _stale57[0]) check("...and a re-trip's reason names the TWO durations separately, each " @@ -1678,11 +1685,11 @@ print("11. SAFETY-56: the sentence this gate can honestly say") # story. Every boundary is derived in part 10b from the register's own longest # hold; nothing here is typed. _S56_CMDS_HELD = sorted({_D.held_at(_sp, t) - for t in range(int(_HOLD_FROM), int(_PARK))}) + for t in range(int(_HOLD_FROM), int(_PARK) if present(_PARK) else 0)}) _S56_SOC_HELD = sorted({_D.held_at(_soc, t) - for t in range(int(_HOLD_FROM), int(_HUMAN))}) -_S56_CHARGE_T, _S56_CHARGE_W = next((t, v) for t, v in _sp - if t > _PARK and v < 0.0) + for t in range(int(_HOLD_FROM), int(_HUMAN) if present(_HUMAN) else 0)}) +_S56_CHARGE = first(((t, v) for t, v in _sp if t > _PARK and v < 0.0), "no charge command") +_S56_CHARGE_T, _S56_CHARGE_W = _S56_CHARGE[0], _S56_CHARGE[1] _S56_AFTER = _D.held_at(_bt, _REG_MOVES + 5.0) print(f" during the 850 s hold: commands {_S56_CMDS_HELD} W, " f"SoC {_S56_SOC_HELD} %, register {_HOLD_W:+.0f} W") @@ -1695,7 +1702,7 @@ check("11a. ⚠️ THE OLD DIAGNOSIS WAS FALSE ON THE ONE SITE IT WAS EVER " "-3 W. Then the first CHARGE command arrives and it moves within ONE " "17.0 s obligation window. A register that answers a reversed command in " "one window had not stopped reporting; what would not move was the PACK", - all(v > 0.0 for v in _S56_CMDS_HELD) + bool(_S56_CMDS_HELD) and all(v > 0.0 for v in _S56_CMDS_HELD) and min(_S56_CMDS_HELD) == 260.0 and max(_S56_CMDS_HELD) == 1060.0 and _S56_SOC_HELD == [11.0] and _HOLD_W == -3.0 and _S56_CHARGE_W < 0.0 @@ -1711,7 +1718,7 @@ check("...and the gate was RIGHT to fire anyway, which is why this card touches and BOUNDS["batt"].move_w == MOVE_W and BOUNDS["batt"].release_s == F.BATT_OBLIGED_S and hms(_TRIP) == "10:52:00" and _f_after.releases == 1 - and next(r for r in _rows_after if r[0] == _TRIP)[1] is True) + and first(r for r in _rows_after if r[0] == _TRIP)[1] is True) # --- 11b. two worlds, one published stream, one verdict ---------------------- # ⚠️ GROUND TRUTH IS WRITTEN DOWN, NOT DERIVED FROM THE PUBLISHED STREAM @@ -1817,10 +1824,10 @@ def _s56_row(c): retried rather than read. Measured: 0 named reds before, 2 after. """ hits = [r for r in c.checks() if r["text"].startswith("battery power")] - if len(hits) != 1: - return {"ok": None, "warn": None, - "text": f""} - return hits[0] + if len(hits) == 1: + return hits[0] + return {"ok": None, "warn": None, + "text": f""} _row56_ref = _s56_row(_c56_ref) diff --git a/goodwe_controller/test_inverter.py b/goodwe_controller/test_inverter.py index 066051c..5e2e622 100644 --- a/goodwe_controller/test_inverter.py +++ b/goodwe_controller/test_inverter.py @@ -73,6 +73,8 @@ import time from datetime import datetime, timedelta, timezone from pathlib import Path +from named_absence import first, given, nth, present + from app import main as app_main from app.inverter import LINK_STALE_S, UNIT_A, Inverter, build_roster from app.main import WRITE_BUDGET_S, Controller @@ -993,8 +995,9 @@ _compute_calls = [n for n in ast.walk(MAIN_AST) and n.func.id == "compute"] check("main.py has exactly ONE `compute(` call site, so the argument graded " "below is unambiguously the shipped one", len(_compute_calls) == 1) -_actual_src = ast.unparse( - next(k.value for k in _compute_calls[0].keywords if k.arg == "actual_w")) +_actual_kw = first((k.value for k in nth(_compute_calls, 0).keywords if k.arg == "actual_w"), + "no actual_w= keyword") +_actual_src = ast.unparse(_actual_kw) if present(_actual_kw) else repr(_actual_kw) _site_batt_assign = [ast.unparse(n.value) for n in ast.walk(CTRL) if isinstance(n, ast.Assign) and len(n.targets) == 1 and isinstance(n.targets[0], ast.Name) @@ -1073,7 +1076,7 @@ print("6. AC 6: independent heartbeats, with the hang INJECTED") # # Two things fix it and both are graded: the writes go out CONCURRENTLY, and # each one is bounded by `WRITE_BUDGET_S`. -_HB_MAX = read_schema_max("heartbeat_s") +_HB_MAX = given(read_schema_max("heartbeat_s"), "heartbeat_s bound") print(f" WRITE_BUDGET_S {WRITE_BUDGET_S:.0f} s + the schema's largest " f"heartbeat_s {_HB_MAX:.0f} s = {WRITE_BUDGET_S + _HB_MAX:.0f} s, against " f"layer 1's {FIRMWARE_INGEST_VETO_S:.0f} s veto") diff --git a/goodwe_controller/test_named_absence.py b/goodwe_controller/test_named_absence.py new file mode 100644 index 0000000..416fee8 --- /dev/null +++ b/goodwe_controller/test_named_absence.py @@ -0,0 +1,426 @@ +"""Runnable check for TEST-26 - a missing value must be a NAMED red. `python3 test_named_absence.py` + +Every test file here is one script. A check or print that RAISES on a missing +value (an empty list indexed, `next()` exhausted, `:.0f` on None) kills every +check after it: the mutation it should name shows up as one unnamed traceback, +and the checks below it are never graded (MUTATION.md, FCST-06). + +1. `named_absence.py`, the shared non-raising accessors. +2. A scan of every `test_*.py` for the shapes that raise, which must find none. +3. What the scan cannot see, counted on every run. +""" +import ast +import sys +from collections import Counter +from pathlib import Path + +from named_absence import field, first, given, nth, present + +HERE = Path(__file__).resolve().parent + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +# ============================================================================== +print("1. the accessors never raise, and an absence is never a pass") +# ============================================================================== +_a = nth([], 0) +_b = first(x for x in (1, 2) if x > 5) +_c = field({"a": 1}, "pv") +_d = given(None) +print(f" {_a!r} {_b!r} {_c!r} {_d!r}") +check("each accessor hands back the value when it is there", + nth([7, 8], -1) == 8 and first(iter([3])) == 3 + and field({"pv": 0.0}, "pv") == 0.0 and given(0.0) == 0.0 + and present(0.0, None, "", [])) +check("...and a stand-in that says what was missing when it is not", + repr(_a) == "" and repr(_c) == "" + and not present(_a) and not present(1, _b) and not present(_c, _d)) +check("formatting, indexing, attributes and arithmetic do not raise", + f"{_a:.2f}|{_a[2]['x']:+.0f}|{_d.attr.get('k'):,}|{_d / 2 - 1:.1f}" + == "|".join([""] * 2 + [""] * 2)) +check("an absence is never equal, unequal, ordered or truthy - so `==`, `!=` " + "and `<` grade it FAIL", + not (_a == 0) and not (_a != 0) and not (_a < 1) and not (_a >= 1) + and not bool(_a) and not (_a == _a)) + + +# ============================================================================== +print() +print("2. no test file reads a possibly-missing value in a way that raises") +# ============================================================================== +# The scan flags, anywhere in a file: +# index `name[k]` (constant k) where `name` holds a FILTERED list - a +# comprehension with an `if`, `filter()`, or an accumulator started +# as `[]` - directly or as returned by a function in the same file; +# next `next(it)` without a default; +# format a numeric format spec on a name that may be None - assigned None, +# an `... else None`, a one-argument `.get()`, or tested `is None`. +# A site is guarded when an earlier operand of the same `and`/`or`, or the +# test of an enclosing `if`/`while`/conditional expression, names the value, +# or it sits in a `try`. A check's NAME is evaluated before its condition, so +# a guard in the condition does not guard the name. +_NUMFMT = set("fdeEgGn%xXbo") +_FUNCS = (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda) +_COMPS = (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp) + + +def _filtered(rhs, returns): + if isinstance(rhs, (ast.ListComp, ast.GeneratorExp)): + return any(g.ifs for g in rhs.generators) + if isinstance(rhs, ast.List): + return not rhs.elts + if isinstance(rhs, ast.Call) and isinstance(rhs.func, ast.Name): + f = rhs.func.id + if f == "filter": + return True + if f in ("list", "sorted", "tuple") and rhs.args: + return _filtered(rhs.args[0], returns) + return "listy" in returns.get((f, None), ()) + return False + + +def _maybe_none(rhs, returns): + if isinstance(rhs, ast.Constant): + return rhs.value is None + if isinstance(rhs, ast.IfExp): + return _maybe_none(rhs.body, returns) or _maybe_none(rhs.orelse, returns) + if isinstance(rhs, ast.Call): + if isinstance(rhs.func, ast.Attribute) and rhs.func.attr == "get": + return len(rhs.args) == 1 or (len(rhs.args) == 2 and _maybe_none(rhs.args[1], returns)) + if isinstance(rhs.func, ast.Name): + return "noney" in returns.get((rhs.func.id, None), ()) + return False + + +class _Scope: + def __init__(self, node, parent): + self.node, self.parent = node, parent + self.bound, self.listy, self.noney = set(), set(), set() + + +def _dump(n): + return ast.dump(n) + + +def _mentions(expr, base): + """`base` appears in `expr` other than as the thing being indexed, so + `x[0] == 1 and x[1]` does not count as guarding `x[1]`.""" + b = _dump(base) + inner = {id(n.value) for n in ast.walk(expr) if isinstance(n, ast.Subscript)} + return any(_dump(x) == b and id(x) not in inner for x in ast.walk(expr)) + + +def _exits_on(st, base): + """`if not x: return` (or continue/break/raise) - x is guarded below it.""" + return (isinstance(st, ast.If) and _mentions(st.test, base) and st.body + and isinstance(st.body[-1], (ast.Return, ast.Continue, ast.Break, ast.Raise))) + + +def scan(src, census=None): + """[(line, kind, text)] for every unguarded raising read in `src`.""" + tree = ast.parse(src) + parent = {c: p for p in ast.walk(tree) for c in ast.iter_child_nodes(p)} + + def scope_node(n): + p = parent.get(n) + while p is not None and not isinstance(p, _FUNCS + _COMPS + (ast.Module,)): + p = parent.get(p) + return p + + scopes = {tree: _Scope(tree, None)} + for n in ast.walk(tree): + if isinstance(n, _FUNCS + _COMPS): + scopes[n] = None + for n in list(scopes): + if n is not tree: + scopes[n] = _Scope(n, None) + for n, s in scopes.items(): + if n is not tree: + s.parent = scopes[scope_node(n)] + + def targets(t): + if isinstance(t, ast.Name): + yield t + elif isinstance(t, (ast.Tuple, ast.List)): + for e in t.elts: + yield from targets(e) + elif isinstance(t, ast.Starred): + yield from targets(t.value) + + for n in ast.walk(tree): + if isinstance(n, _FUNCS): + a = n.args + for arg in a.posonlyargs + a.args + a.kwonlyargs + [a.vararg, a.kwarg]: + if arg is not None: + scopes[n].bound.add(arg.arg) + elif isinstance(n, ast.comprehension): + for t in targets(n.target): + scopes[scope_node(n)].bound.add(t.id) + elif isinstance(n, (ast.For, ast.AsyncFor, ast.With, ast.AugAssign, ast.NamedExpr)): + ts = ([n.target] if not isinstance(n, ast.With) + else [i.optional_vars for i in n.items if i.optional_vars]) + for t0 in ts: + for t in targets(t0): + scopes[scope_node(n)].bound.add(t.id) + + # `x = if x is None else x` makes x not-None: a scope that + # normalises x this way does not get x marked by its `is None` tests. + normalised = set() + for n in ast.walk(tree): + if (isinstance(n, ast.Assign) and isinstance(n.value, ast.IfExp) + and isinstance(n.value.test, ast.Compare)): + for t in n.targets: + if isinstance(t, ast.Name) and any(isinstance(x, ast.Name) and x.id == t.id + for x in ast.walk(n.value.test)): + normalised.add((scope_node(n), t.id)) + + # Two passes, so a function's return shape is known before its callers. + returns = {} + for _ in range(2): + for n in ast.walk(tree): + if isinstance(n, (ast.Assign, ast.AnnAssign)) and n.value is not None: + s = scopes[scope_node(n)] + for t0 in (n.targets if isinstance(n, ast.Assign) else [n.target]): + if isinstance(t0, ast.Name): + s.bound.add(t0.id) + if _filtered(n.value, returns): + s.listy.add(t0.id) + if _maybe_none(n.value, returns): + s.noney.add(t0.id) + elif (isinstance(t0, ast.Tuple) and isinstance(n.value, ast.Tuple) + and len(t0.elts) == len(n.value.elts)): + for e, v in zip(t0.elts, n.value.elts): + for t in targets(e): + s.bound.add(t.id) + if _filtered(v, returns): + s.listy.add(t.id) + if _maybe_none(v, returns): + s.noney.add(t.id) + elif (isinstance(t0, ast.Tuple) and isinstance(n.value, ast.Call) + and isinstance(n.value.func, ast.Name)): + for i, e in enumerate(t0.elts): + for t in targets(e): + s.bound.add(t.id) + got = returns.get((n.value.func.id, i), ()) + if "listy" in got: + s.listy.add(t.id) + if "noney" in got: + s.noney.add(t.id) + else: + for t in targets(t0): + s.bound.add(t.id) + elif (isinstance(n, ast.Compare) + and any(isinstance(o, (ast.Is, ast.IsNot)) for o in n.ops) + and any(isinstance(c, ast.Constant) and c.value is None + for c in [n.left] + n.comparators)): + for x in [n.left] + n.comparators: + if isinstance(x, ast.Name) and (scope_node(n), x.id) not in normalised: + s = scopes[scope_node(n)] + while s.parent is not None and x.id not in s.bound: + s = s.parent + s.noney.add(x.id) + for fn in tree.body: + if not isinstance(fn, (ast.FunctionDef, ast.AsyncFunctionDef)): + continue + s = scopes[fn] + for r in ast.walk(fn): + if not isinstance(r, ast.Return) or r.value is None or scope_node(r) is not fn: + continue + vals = r.value.elts if isinstance(r.value, ast.Tuple) else [r.value] + for i, v in enumerate(vals): + key = (fn.name, i if isinstance(r.value, ast.Tuple) else None) + tags = returns.setdefault(key, set()) + if isinstance(v, ast.Name) and v.id in s.listy or _filtered(v, returns): + tags.add("listy") + if isinstance(v, ast.Name) and v.id in s.noney or _maybe_none(v, returns): + tags.add("noney") + + def resolve(name_node, attr): + s = scopes[scope_node(name_node)] + while s is not None: + if name_node.id in s.bound or name_node.id in getattr(s, attr): + return name_node.id in getattr(s, attr) + s = s.parent + return False + + def guarded(node, base): + ch, p = node, parent.get(node) + while p is not None: + if isinstance(p, ast.BoolOp) and ch in p.values: + if any(_mentions(v, base) for v in p.values[:p.values.index(ch)]): + return True + elif isinstance(p, (ast.IfExp, ast.If, ast.While)): + if ch is not p.test and _mentions(p.test, base): + return True + elif isinstance(p, (ast.ListComp, ast.GeneratorExp, ast.SetComp)): + if ch is p.elt and any(_mentions(i, base) for g in p.generators for i in g.ifs): + return True + elif isinstance(p, ast.Try) and ch in p.body: + return True + for field_ in ("body", "orelse"): + block = getattr(p, field_, None) + if (isinstance(block, list) and ch in block + and any(_exits_on(st, base) for st in block[:block.index(ch)])): + return True + if isinstance(p, _FUNCS): + return False + ch, p = p, parent.get(p) + return False + + out = [] + for n in ast.walk(tree): + if (isinstance(n, ast.Subscript) and isinstance(n.ctx, ast.Load) + and isinstance(n.value, ast.Name)): + k = n.slice + if isinstance(k, ast.UnaryOp) and isinstance(k.op, ast.USub): + k = k.operand + if (isinstance(k, ast.Constant) and type(k.value) is int + and resolve(n.value, "listy") and not guarded(n, n.value)): + out.append((n.lineno, "index", ast.unparse(n))) + elif (isinstance(n, ast.Call) and isinstance(n.func, ast.Name) + and n.func.id == "next" and len(n.args) == 1 and not n.keywords): + if not guarded(n, n.args[0]): + out.append((n.lineno, "next", ast.unparse(n)[:60])) + elif (isinstance(n, ast.FormattedValue) and n.format_spec is not None + and isinstance(n.value, ast.Name)): + spec = "".join(v.value for v in n.format_spec.values + if isinstance(v, ast.Constant)) + if (spec and (spec[-1] in _NUMFMT or "," in spec) + and resolve(n.value, "noney") and not guarded(n, n.value)): + out.append((n.lineno, "format", f"{{{n.value.id}:{spec}}}")) + if census is not None: + _count_blind(tree, resolve, census) + return sorted(set(out)) + + +def _count_blind(tree, resolve, census): + """Count, inside check() and print() arguments, the forms part 2 skips.""" + for call in ast.walk(tree): + if not (isinstance(call, ast.Call) and isinstance(call.func, ast.Name) + and call.func.id in ("check", "print")): + continue + for n in (x for a in call.args for x in ast.walk(a)): + if isinstance(n, ast.Subscript) and isinstance(n.ctx, ast.Load): + k = n.slice.operand if isinstance(n.slice, ast.UnaryOp) else n.slice + if not isinstance(k, ast.Constant): + continue + if isinstance(k.value, str): + census["key"] += 1 + elif isinstance(n.value, ast.Name): + if not resolve(n.value, "listy"): + census["name-list"] += 1 + elif isinstance(n.value, ast.Attribute): + census["attr-list"] += 1 + else: + census["other-index"] += 1 + elif isinstance(n, ast.FormattedValue) and n.format_spec is not None: + if not isinstance(n.value, ast.Name): + census["format-expr"] += 1 + elif not resolve(n.value, "noney"): + census["format-name"] += 1 + elif isinstance(n, ast.BinOp) and isinstance(n.op, (ast.Div, ast.FloorDiv)): + census["division"] += 1 + + +# The scan must bite before its silence means anything: one planted site of +# each kind, and the guarded spelling of each, which must NOT be flagged. +_PLANTED = ''' +def run(): + seen = [] + t_gate = None + return seen, t_gate +rows = [r for r in range(3) if r > 9] +seen, t_gate = run() +waits, n = [], 0 +check(f"first {rows[0]}", bool(rows)) +print(waits[0]) +check("pair", rows[0] == 1 and rows[1] == 2) +print(seen[-1]) +print(f"{t_gate:.2f}") +print(next(r for r in rows)) +''' +_GUARDED = ''' +def run(): + seen = [] + t_gate = None + return seen, t_gate +rows = [r for r in range(3) if r > 9] +seen, t_gate = run() +check("first", bool(rows) and rows[0] == 1) +print(seen[-1] if seen else "-") +check("pair", len(rows) == 2 and rows[0] < rows[1]) +print(f"{t_gate:.2f}" if t_gate is not None else "-") +print(next((r for r in rows), None)) +def show(rows): + print(rows[0]) +def head(): + if not rows: + return None + return rows[0] +''' +_hit = scan(_PLANTED) +print(f" planted: {_hit}") +check("the scan flags a planted site of each kind - a filtered list indexed in " + "a check NAME whose condition guards it, an accumulator bound in a tuple " + "and one returned from a function, a maybe-None formatted, and next() " + "without a default", + [(k, t) for _l, k, t in _hit] == [ + ("index", "rows[0]"), ("index", "waits[0]"), ("index", "rows[0]"), + ("index", "rows[1]"), ("index", "seen[-1]"), + ("format", "{t_gate:.2f}"), + ("next", "next((r for r in rows))")]) +check("...and flags none of the guarded spellings - `and`, a conditional, " + "an early return, a default - nor a parameter that shadows a filtered " + "name", scan(_GUARDED) == []) + +_SUITES = sorted(HERE.glob("test_*.py")) +_found = {p.name: scan(p.read_text(encoding="utf-8")) for p in _SUITES} +_all = [(f, *h) for f, hs in _found.items() for h in hs] +for f, line, kind, text in _all: + print(f" {f}:{line} {kind:6} {text}") +check(f"no unguarded raising read in any of the {len(_SUITES)} test files " + f"({len(_all)} found) - read it through named_absence.py and conjoin " + f"present() in the check", _all == [] and len(_SUITES) >= 30) + + +# ============================================================================== +print() +print("3. what part 2 cannot see, counted - these can still raise") +# ============================================================================== +# The scan knows a list is filtered, or a name may be None, only from its own +# file's syntax. Each form below can still raise and is NOT graded; the counts +# are of every such site in check() and print() arguments, largest first. +_BLIND = { + "key": "`x['k']` - a dict key the code under test may omit", + "name-list": "`x[k]` on a list the scan cannot see is filtered - returned " + "by another module or a method, or of a fixed length", + "format-name": "a numeric format on a name the scan has no reason to think " + "is None - e.g. set from another module's function", + "format-expr": "a numeric format on an attribute, subscript or call", + "attr-list": "`obj.items[k]` - an attribute list", + "other-index": "`x[k]` on a call, a slice or a nested subscript", + "division": "`/` or `//` by a value that can be 0", +} +_census = Counter() +for p in _SUITES: + scan(p.read_text(encoding="utf-8"), _census) +for k, why in sorted(_BLIND.items(), key=lambda kv: -_census[kv[0]]): + print(f" {_census[k]:5d} {why}") +print(" never counted: these forms outside check()/print() arguments; " + "attribute access, iteration, int() or range() on a None or an ABSENT; " + "a raise inside a fixture function or inside app/.") +check("every counted form is in the printed table", set(_census) <= set(_BLIND)) + + +print() +if fails: + print(f"{len(fails)} CHECK(S) FAILED") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/test_p1.py b/goodwe_controller/test_p1.py index 4983200..ed83cda 100644 --- a/goodwe_controller/test_p1.py +++ b/goodwe_controller/test_p1.py @@ -1320,8 +1320,8 @@ check("homewizard_local is enabled here too", row = [s for s in SENSORS if s[0] == "p1_age"] check("the age sensor is declared exactly once", len(row) == 1) check("its object_id pins entity_id to sensor.p1_sample_age_s", - row[0][1] == "p1_sample_age_s") -check("it is published in seconds", row[0][3] == "s") + len(row) == 1 and row[0][1] == "p1_sample_age_s") +check("it is published in seconds", len(row) == 1 and row[0][3] == "s") class _RecordingClient: diff --git a/goodwe_controller/test_packshare.py b/goodwe_controller/test_packshare.py index 19dfcc3..561e9ad 100644 --- a/goodwe_controller/test_packshare.py +++ b/goodwe_controller/test_packshare.py @@ -36,6 +36,7 @@ from math import inf from pathlib import Path from app import arbitrage, packshare +from named_absence import first, nth, present from app.allocator import plan from app.arbiter import ( ACTUATOR_SITE, CLAIM_SCOPE, P_LOOP, P_SAFETY, SCOPE_UNIT, Claim, resolve, @@ -347,12 +348,12 @@ check("...and the shipped behaviour really was the other one, so the line " "above is not vacuous: an equal split of 1500 W is 750/750, and 750 W is " "what a pack at its cut-out was being told to produce", _r_now.shares == {A: 750, Bee: 750}) -_plan_a = next(p for p in _r_opt.allocation.plans if p.unit == A) +_plan_a = first((p for p in _r_opt.allocation.plans if p.unit == A), "no plan for A") print(f" {_plan_a.explain()}") check("...and the RECORD says why, in the line an operator is already reading. " "`UnitPlan.within_envelope` is asked rather than assumed, and SAFETY-28's " "write gate refuses a record that contradicts itself", - _plan_a.within_envelope and _plan_a.share_w == 0 + present(_plan_a) and _plan_a.within_envelope and _plan_a.share_w == 0 and _plan_a.hi == 0.0 and _r_opt.allocated) check("a pack at 100 % is not allocated a CHARGE either, and the sibling takes " "the whole of it - the same sentence in the other direction", @@ -477,12 +478,12 @@ check("...and the two halves are separated from EACH OTHER as well: on a pack " "grades the ENVELOPE. Case three - both packs with room, nothing closed - " "is the one that can only be the WEIGHTS", _env_only.shares == {A: 0, Bee: 1500} - and _broken[2][1] != _broken[2][2]) + and len(_broken) > 2 and _broken[2][1] != _broken[2][2]) check("...and the third case is the one that isolates the WEIGHTS from the " "ENVELOPE: both packs have room, no interval is closed, nothing is " "refused - and the split still moves from 500/500 to 97/903 because the " "energy headroom says so", - _broken[2][1] == {A: 97, Bee: 903} and _broken[2][2] == {A: 500, Bee: 500}) + nth(_broken, 2)[1] == {A: 97, Bee: 903} and nth(_broken, 2)[2] == {A: 500, Bee: 500}) # ============================================================================== @@ -1156,7 +1157,7 @@ check("⚠️ MAIN.PY ACTUALLY PASSES `weights=`, AND IT PASSES THE METHOD RATHE # reads the allocation's own `unmet_w`, is EDGE-TRIGGERED against the previous # cycle's value, and logs. What it does NOT grade is the sentence it logs or # that a real cycle reaches it; that is stated here rather than implied. -_cycle_src = next( +_cycle_src = first( f for cls in ast.walk(ast.parse( (Path(__file__).resolve().parent / "app" / "main.py") .read_text(encoding="utf-8"))) diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index a90b20d..9f19bd9 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -115,6 +115,12 @@ from math import inf, isinf from pathlib import Path from app import peakguard +from named_absence import first, given, nth, present + + +def _src(node): + """`ast.unparse(node)`, or what was there instead - never a raise.""" + return ast.unparse(node) if isinstance(node, ast.AST) else repr(node) # ⚠️ THE DROP AND REFUSAL REASONS ARE IMPORTED, NOT TRANSCRIBED. A check that # matched the English would stay green against an allocator that renamed the # case out from under it, which is this repository's own named failure mode. @@ -265,18 +271,18 @@ def _schema_bound(key: str, which: int): # Everything numeric below is read out of the shipped file, not typed here. -CAP_W = read_option("peak_cap_w") -MAX_HOLD_S = read_option("meter_max_age_s") -FREEZE_S = read_option("meter_freeze_s") -CYCLE_S = read_option("cycle_floor_s") +CAP_W = given(read_option("peak_cap_w"), "peak_cap_w not in config.yaml") +MAX_HOLD_S = given(read_option("meter_max_age_s"), "meter_max_age_s not in config.yaml") +FREEZE_S = given(read_option("meter_freeze_s"), "meter_freeze_s not in config.yaml") +CYCLE_S = given(read_option("cycle_floor_s"), "cycle_floor_s not in config.yaml") # The live install runs max_w 5000 (NOTES.md, freeze.py). That is also the schema # ceiling and the GW5000S-BP's rating, which is why the two agree - so the # device figure is taken from the schema rather than typed. -LIVE_MAX_W = read_schema_max("max_w") +LIVE_MAX_W = given(read_schema_max("max_w"), "max_w not in config.yaml") # SAFETY-24's two options, out of the shipped file for the same reason. -SOC_FLOOR = read_option("peak_soc_floor") -BMS_FLOOR = read_option("bms_soc_floor") -MAINT_FLOOR = read_option("maintenance_soc_floor") +SOC_FLOOR = given(read_option("peak_soc_floor"), "peak_soc_floor not in config.yaml") +BMS_FLOOR = given(read_option("bms_soc_floor"), "bms_soc_floor not in config.yaml") +MAINT_FLOOR = given(read_option("maintenance_soc_floor"), "maintenance_soc_floor not in config.yaml") # A state of charge that comfortably permits a forced discharge, DERIVED from # the floor rather than typed: every part of this file that is not about # SAFETY-24 has to grade SAFETY-07's behaviour at a SoC where the new floor is @@ -291,8 +297,8 @@ print(f" read from config.yaml: peak_cap_w {CAP_W:.0f} W, " print(f" ...and peak_soc_floor {SOC_FLOOR:.0f} %, bms_soc_floor " f"{BMS_FLOOR:.0f} %, maintenance_soc_floor {MAINT_FLOOR:.0f} %") check("every threshold this check grades against came out of config.yaml", - None not in (CAP_W, MAX_HOLD_S, FREEZE_S, CYCLE_S, LIVE_MAX_W, - SOC_FLOOR, BMS_FLOOR, MAINT_FLOOR)) + present(CAP_W, MAX_HOLD_S, FREEZE_S, CYCLE_S, LIVE_MAX_W, + SOC_FLOOR, BMS_FLOOR, MAINT_FLOOR)) check("...and the SoC these checks use as 'plenty of battery' is comfortably " "clear of the floor, so nothing outside part 9 is silently grading " "SAFETY-24 instead of SAFETY-07", SOC_OK > SOC_FLOOR + 10.0) @@ -437,7 +443,7 @@ print(f" five cycles with the inverter not following: delivered-power floor " check("a floor sized from DELIVERED battery power is stationary while the " "inverter fails to follow; one sized from the standing command winds up", len(set(f"{v:.3f}" for v in delivered_floor)) == 1 - and intent_floor[-1] > intent_floor[0] * 4) + and nth(intent_floor, -1) > nth(intent_floor, 0) * 4) # ============================================================================== @@ -796,7 +802,7 @@ def replay(path, *, guarded: bool, cap_w=CAP_W, max_w=LIVE_MAX_W, pack=None, """ ing = P1Ingest(phases=1, max_age_s=MAX_HOLD_S) store = fresh_store(f"{path.stem}-{'g' if guarded else 'u'}" - f"{'' if pack is None else f'-p{soc_floor:.0f}'}") + f"{'' if pack is None else f'-p{given(soc_floor):.0f}'}") tracker = PeakTracker(store, cap_w=cap_w) batt = 0.0 # delivered discharge, W (positive) next_cycle = None @@ -1049,7 +1055,7 @@ c_off.auto, c_off.soc, c_off.batt, c_off.grid = True, 55.0, 0.0, -6000.0 asyncio.get_event_loop_policy().new_event_loop().run_until_complete(c_off.cycle()) off_rows = [r for r in c_off.checks() if "peak guard" in r["text"]] print(f" meter_source off: guard={c_off.peak_guard}, wrote " - f"{hass_off.writes[-1]:+.0f} W") + f"{nth(hass_off.writes, -1):+.0f} W") print(" status row: " + (off_rows[0]["text"] if off_rows else "(none)")) check("with no P1 the guard does not run at all - it files nothing, and the " "legacy path can still charge", c_off.peak_guard is None @@ -1242,7 +1248,7 @@ check("...once per episode, not once per cycle", hass2.notifications.count("goodwe_peak_saturated") == 1) check("...and the command is still bounded by the rating, so a saturated guard " "never asks the hardware for more than it has", - abs(hass2.writes[-1]) <= LIVE_MAX_W + 1e-6) + bool(hass2.writes) and abs(hass2.writes[-1]) <= LIVE_MAX_W + 1e-6) # ============================================================================== # THE WIRING'S OWN MUTATIONS. Everything above this line grades `peakguard.py`, @@ -1439,7 +1445,7 @@ check("...and the consequence is the wind-up part 1 demonstrates, now on the " "REAL controller's own projection: the intent-sized floor re-adds its own " "unmet ask every cycle and reaches the rail SATURATED, while the " "delivered-power floor does not move at all", - _i_sat_at is not None and _i_track[-1] > _i_track[0] + _i_sat_at is not None and len(_i_track) > 1 and _i_track[-1] > _i_track[0] and len({f"{v:.3f}" for v in _d_track}) == 1 and not b3.peak_guard.saturated) # Graded on the parsed call syntax too, so a rename cannot quietly reintroduce @@ -1456,9 +1462,9 @@ _peak_calls = [n for n in ast.walk(ast.parse(_mainsrc)) and n.func.attr == "decide" and isinstance(n.func.value, ast.Name) and n.func.value.id == "peakguard"] -_call = _peak_calls[0] -_batt_src = ast.unparse(next(k.value for k in _call.keywords if k.arg == "batt_w")) -_soc_src = ast.unparse(next(k.value for k in _call.keywords if k.arg == "soc")) +_call = nth(_peak_calls, 0, "peakguard.decide() call in main.py") +_batt_src = _src(first(k.value for k in _call.keywords if k.arg == "batt_w")) +_soc_src = _src(first(k.value for k in _call.keywords if k.arg == "soc")) print(f" main.py's decide(batt_w=...) is `{_batt_src}`, decide(soc=...) is " f"`{_soc_src}`") check("...and the call site says so in the source: the argument is the measured " @@ -1497,8 +1503,8 @@ check(f"...and main.py has exactly ONE `peakguard.decide(` call site (it has " # no fixture separated them - which is exactly the coupling the card forbids and # exactly the kind of survivor a value-based check cannot see. This grades the # NAME, and part 9 below now also separates them behaviourally. -_floor_src = ast.unparse(next(k.value for k in _call.keywords - if k.arg == "soc_floor")).replace("'", '"') +_floor_src = _src(first(k.value for k in _call.keywords + if k.arg == "soc_floor")).replace("'", '"') print(f" main.py's decide(soc_floor=...) is `{_floor_src}`") check("...and the floor comes from `peak_soc_floor`, defaulted from the ONE " "mirror - not from `maintenance_soc_floor` (a drain target, not a spend " @@ -1535,8 +1541,9 @@ check("SAFETY-24 adds exactly the two keys it names and no more: §14's kW/W " # Graded on the parsed call syntax, not on the text: the module docstring names # `peak_cap_w` while arguing that it does not read it, so a grep would be # satisfied by deleting the explanation and would fail on writing one. -_decide = next(n for n in ast.walk(ast.parse(src)) - if isinstance(n, ast.FunctionDef) and n.name == "decide") +_decide = first((n for n in ast.walk(ast.parse(src)) + if isinstance(n, ast.FunctionDef) and n.name == "decide"), + "def decide in peakguard.py") _DECIDE_ARGS = [a.arg for a in _decide.args.args + _decide.args.kwonlyargs] _getters = [n for n in ast.walk(ast.parse(src)) if isinstance(n, ast.Call) and isinstance(n.func, ast.Attribute) @@ -2010,7 +2017,8 @@ check("...while one point above is accepted, so this refuses the disarmed case " "only and not 'close to the limit'", above == []) check("...and the refusal NAMES BOTH NUMBERS and the shipped default, so the " "operator can act on it without reading the source", - f"{BMS_FLOOR:.0f} %" in below[0] + len(below) == 1 + and f"{BMS_FLOOR:.0f} %" in below[0] and f"{BMS_FLOOR - 5:.0f} %" in below[0] and f"{PEAK_OPTION_DEFAULTS['peak_soc_floor']:.0f} %" in below[0]) check("...and a non-numeric floor is refused rather than defaulted, for the " @@ -2245,7 +2253,7 @@ def replay_loop(window, *, start_soc, soc_floor, usable_wh=REF_PACK_WH): # measuring something else. EVE = evening(19, 24) EVE_W = [w for _, w in EVE] -print(f" the evening of 2026-08-20, {EVE[0][0]:%H:%M}-{EVE[-1][0]:%H:%M} UTC: " +print(f" the evening of 2026-08-20, {nth(EVE, 0)[0]:%H:%M}-{nth(EVE, -1)[0]:%H:%M} UTC: " f"{len(EVE)} telegrams, mean {sum(EVE_W) / len(EVE_W):.0f} W, " f"min {min(EVE_W):.0f} W, max {max(EVE_W):.0f} W") check("the window really is a SUSTAINED-LOAD evening and not a quiet one - " @@ -2324,7 +2332,7 @@ check("...and the sweep spans the whole schema range, rule 8's refused low end " HOT = evening(15, 17) HOT_R = replay_loop(HOT, start_soc=SOC_FLOOR - 1.0, soc_floor=SOC_FLOOR) print(f" the same day's high-load block " - f"{HOT[0][0]:%H:%M}-{HOT[-1][0]:%H:%M} UTC, pack started one point BELOW " + f"{nth(HOT, 0)[0]:%H:%M}-{nth(HOT, -1)[0]:%H:%M} UTC, pack started one point BELOW " f"the floor:") print(f" {HOT_R['limited']} cycles reporting PEAK GUARD FLOOR-LIMITED, " f"{HOT_R['limited_discharging']} of them with the loop simultaneously " @@ -2492,13 +2500,14 @@ print(f" banner ({len(_pay25['banner'])} chars): {_pay25['banner']}") # The guard's own line, which the banner has always carried and which is not # this card's to shorten: `explain()` is SAFETY-24's sentence about a quarter # that is going over the ceiling. -_expl25 = rows25[0]["text"].split(". NOTE:")[0] +_expl25 = nth(rows25, 0)["text"].split(". NOTE:")[0] check("the NOT READY banner is the guard's own line plus a SHORT scope tag - " "under 90 characters of it - and NOT the row's whole paragraph repeated " "at the top of the page. A headline that is a paragraph is a headline " "nobody reads, and this one is followed three lines later by the same " "text verbatim", - _pay25["level"] == "bad" + present(_expl25) + and _pay25["level"] == "bad" and _pay25["banner"].startswith("NOT READY") and _expl25 in _pay25["banner"] and "BOUNDS THE PEAK GUARD ONLY" in _pay25["banner"].upper() @@ -2507,7 +2516,8 @@ check("the NOT READY banner is the guard's own line plus a SHORT scope tag - " check("...and shortening the banner did NOT shorten the row: the full AC 3 " "sentence is still what the checks list carries, which is the surface the " "operator reads to find out what the floor does not bound", - len(rows25[0]["text"]) > 300 + len(rows25) == 1 + and len(rows25[0]["text"]) > 300 and "not a pack-wide reserve" in rows25[0]["text"] and "BMS cut-out" in rows25[0]["text"]) @@ -2627,12 +2637,13 @@ CLAIM_SOURCES = {"device", "supervised", "failsafe", "safety", "peak", CLAIM_BUILDERS = {"peak_claim": "peak", "arb_claim": "arbitrage"} _main_tree = ast.parse((HERE / "app" / "main.py").read_text(encoding="utf-8")) -_cycle_def = next( +_cycle_def = first(( f for cls in ast.walk(_main_tree) if isinstance(cls, ast.ClassDef) and cls.name == "Controller" for f in cls.body - if isinstance(f, (ast.FunctionDef, ast.AsyncFunctionDef)) and f.name == "cycle") + if isinstance(f, (ast.FunctionDef, ast.AsyncFunctionDef)) and f.name == "cycle"), + "Controller.cycle in main.py") def claim_source(node): @@ -2957,9 +2968,7 @@ def append_actuator(node): dynamic check in this file is blind to the swap at N=1. """ kw = [k for k in node.keywords if k.arg == "actuator"] - if len(kw) != 1: - return None - return ast.unparse(kw[0].value) + return ast.unparse(kw[0].value) if len(kw) == 1 else None # The appends that BUILD their claim in place - the nine whose routing is @@ -3959,8 +3968,8 @@ check("...and with the key absent entirely the one pack takes the SHIPPED " # the floor comes from is a claim genuinely about the code's shape and is pinned # on the source in part 4, where it already lives; what is graded here is the # VALUE that reaches `decide()`. -_floor_call = ast.unparse(next(k.value for k in _call.keywords - if k.arg == "soc_floor")) +_floor_call = _src(first(k.value for k in _call.keywords + if k.arg == "soc_floor")) print(f" main.py's decide(soc_floor=...) is `{_floor_call}`") @@ -4243,12 +4252,12 @@ check("...and the baseline the table is measured against is the shipped call " # rewritten as `self.inverters[:2]` leaves this expression identical, and it is # the three-pack runs' `len(ctl.packs) == 3` that goes red on it. And it cannot # see the reduction INSIDE `binding_soc_floor()` at all; that is 12c2's. -_floor_node = next(k.value for k in _call.keywords if k.arg == "soc_floor") +_floor_node = first(k.value for k in _call.keywords if k.arg == "soc_floor") _floor_roster_arg = (_floor_node.args[0] if isinstance(_floor_node, ast.Call) and _floor_node.args else None) print(f" the ROSTER argument main.py reduces is " - f"`{ast.unparse(_floor_roster_arg)}`, an AST " + f"`{_src(_floor_roster_arg)}`, an AST " f"{type(_floor_roster_arg).__name__}") check("⚠️ THE STRUCTURAL HALF, AND IT IS EXACT RATHER THAN A SUBSTRING. The " "roster handed to `binding_soc_floor()` is the WHOLE property " @@ -4744,28 +4753,31 @@ check("⚠️ THE NONE GUARD IS THE SAME FAMILY. One silent pack at ANY position # killed by the roster set), it cannot see `inv.soc` become `inv.bms_soc_floor` # (killed by the runs' held-flat cut-outs), and it cannot see a change inside # `Inverter.soc` at all. -_pfs_fn = next(n for n in ast.walk(ast.parse(_mainsrc)) - if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) - and n.name == "pack_floor_soc") -_pfs_vals = next(n.value for n in _pfs_fn.body - if isinstance(n, ast.Assign) - and [ast.unparse(t) for t in n.targets] == ["vals"]) +_pfs_fn = first((n for n in ast.walk(ast.parse(_mainsrc)) + if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) + and n.name == "pack_floor_soc"), "def pack_floor_soc in main.py") +_pfs_vals = first((n.value for n in _pfs_fn.body + if isinstance(n, ast.Assign) + and [ast.unparse(t) for t in n.targets] == ["vals"]), + "`vals = ...` in pack_floor_soc") def _gen_iter_of(fn_node, name): """The iterable of the comprehension inside the single `name(...)` call.""" - call = next(n for n in ast.walk(fn_node) - if isinstance(n, ast.Call) and isinstance(n.func, ast.Name) - and n.func.id == name) - comp = call.args[0] - return comp.generators[0].iter if len(comp.generators) == 1 else None + call = first((n for n in ast.walk(fn_node) + if isinstance(n, ast.Call) and isinstance(n.func, ast.Name) + and n.func.id == name), f"{name}() call") + comp = nth(call.args, 0) + gens = getattr(comp, "generators", []) + return gens[0].iter if len(gens) == 1 else None _pfs_min_iter = _gen_iter_of(_pfs_fn, "min") +_pfs_vals_iter = nth(getattr(_pfs_vals, "generators", []), 0).iter _pfs_any_iter = _gen_iter_of(_pfs_fn, "any") -print(f" pack_floor_soc reduces: list over `{ast.unparse(_pfs_vals.generators[0].iter)}`" - f", any() over `{ast.unparse(_pfs_any_iter)}`, min() over " - f"`{ast.unparse(_pfs_min_iter)}`") +print(f" pack_floor_soc reduces: list over `{_src(_pfs_vals_iter)}`" + f", any() over `{_src(_pfs_any_iter)}`, min() over " + f"`{_src(_pfs_min_iter)}`") check("⚠️ THE STRUCTURAL HALF, EXACT RATHER THAN A SUBSTRING. `min()` reduces " "the WHOLE list `vals` - a bare Name, not a Subscript, not a call, not a " "second comprehension - and `vals` is built by ONE comprehension over the " @@ -4777,7 +4789,7 @@ check("⚠️ THE STRUCTURAL HALF, EXACT RATHER THAN A SUBSTRING. `min()` reduce "to length 12. This grades the code's SHAPE and nothing about the values; " "what the expression MEANS is graded by the runs", isinstance(_pfs_min_iter, ast.Name) and _pfs_min_iter.id == "vals" - and ast.unparse(_pfs_min_iter) == "vals" + and _src(_pfs_min_iter) == "vals" and isinstance(_pfs_vals, ast.ListComp) and len(_pfs_vals.generators) == 1 and not _pfs_vals.generators[0].ifs @@ -4785,13 +4797,13 @@ check("⚠️ THE STRUCTURAL HALF, EXACT RATHER THAN A SUBSTRING. `min()` reduce and isinstance(_pfs_vals.generators[0].iter.value, ast.Name) and _pfs_vals.generators[0].iter.value.id == "self" and _pfs_vals.generators[0].iter.attr == "inverters" - and ast.unparse(_pfs_vals.generators[0].iter) == "self.inverters") + and _src(_pfs_vals_iter) == "self.inverters") check("...and the NONE GUARD reduces that same whole list, pinned the same way. " "`any(v is None for v in vals[:1])` is +4 bytes and leaves every other " "line in this file identical; the sweep above reaches it up to length 12 " "and this reaches it at every length", isinstance(_pfs_any_iter, ast.Name) and _pfs_any_iter.id == "vals" - and ast.unparse(_pfs_any_iter) == "vals") + and _src(_pfs_any_iter) == "vals") check("...and the counterfactual that shows these pins are not vacuous (habit " "7): the very slices they exist for really do unparse to something else, " "so the equalities above are doing work rather than being trivially true " @@ -4813,8 +4825,8 @@ _arb_calls = [n for n in ast.walk(ast.parse(_mainsrc)) and n.func.attr == "decide" and isinstance(n.func.value, ast.Name) and n.func.value.id == "arbitrage"] -_arb_soc = ast.unparse(next(k.value for k in _arb_calls[0].keywords - if k.arg == "soc")) +_arb_soc = _src(first(k.value for k in nth(_arb_calls, 0).keywords + if k.arg == "soc")) print(f" main.py's arbitrage.decide(soc=...) is `{_arb_soc}` " f"({len(_arb_calls)} call site)") check("⚠️ AND THE SECOND CONSUMER OF THE SAME REDUCTION. `arbitrage.decide()` " @@ -5688,8 +5700,8 @@ MUT.append(("`binding_soc_floor()` reduced over a WINDOW - `max(floors[-2:])` - # cut-out at index 0, 1 and 2 reach it. MUT.append(("main.py grading the site against a WINDOW of roster positions - " "`self.packs[:2]` - ROUND 3 SURVIVOR 2, +4 bytes", - _g3_runs[2][3].soc_floor == float(_G3_DEEP_SIM) - and binding_soc_floor(_g3_runs[2][2].packs[:2], SOC_FLOOR) + nth(_g3_runs, 2)[3].soc_floor == float(_G3_DEEP_SIM) + and binding_soc_floor(nth(_g3_runs, 2)[2].packs[:2], SOC_FLOOR) == float(SOC_FLOOR) and all(r[3].soc_floor == float(_G3_DEEP_SIM) for r in _g3_runs) and all(_slice_kills.values()), @@ -5711,7 +5723,7 @@ MUT.append(("main.py grading the site against a WINDOW of roster positions - " MUT.append(("main.py grading the site against a THREE-wide window - " "`self.packs[:3]` / `self.packs[-3:]`, found by THIS round's " "battery, invisible to every behavioural run in this file", - ast.unparse(_floor_roster_arg) == "self.packs" + _src(_floor_roster_arg) == "self.packs" and isinstance(_floor_roster_arg, ast.Attribute) and all(binding_soc_floor(ctl.packs[:3], SOC_FLOOR) == dec.soc_floor and binding_soc_floor(ctl.packs[-3:], SOC_FLOOR) @@ -5758,7 +5770,7 @@ MUT.append(("`pack_floor_soc` reduced over a WINDOW - `vals[:2]` (+4 bytes) or " MUT.append(("`pack_floor_soc` reduced over a THREE-wide window - `vals[:3]` / " "`vals[-3:]` - invisible to every cycle in this file", _s_head_kill[3] and _s_tail_kill[3] - and ast.unparse(_pfs_min_iter) == "vals", + and _src(_pfs_min_iter) == "vals", "part 12i's LENGTH SWEEP (widths 1-11, on the REAL property over " "rosters of 1 to 12 real inverters) and its STRUCTURAL PIN. The " "six real cycles cannot see it - three packs is the longest roster " @@ -5777,7 +5789,7 @@ MUT.append(("`pack_floor_soc` reduced with `max()` - the FULLEST pack, which is MUT.append(("`pack_floor_soc`'s NONE GUARD narrowed to a slice - " "`any(v is None for v in vals[:1])`, +4 bytes", all(g is None for _n, _p, g in _s_none_rows) - and ast.unparse(_pfs_any_iter) == "vals", + and _src(_pfs_any_iter) == "vals", "part 12i's NONE-GUARD SWEEP - one silent pack at every position of " "every length 1..12 - and the same structural pin. ⚠️ 12d's " "two-pack fixture silences the SECOND pack only, so a guard " @@ -5786,7 +5798,7 @@ MUT.append(("`pack_floor_soc`'s NONE GUARD narrowed to a slice - " # 32. and the roster the list itself is built from. MUT.append(("`pack_floor_soc` building `vals` from a SLICE of the roster - " "`[inv.soc for inv in self.inverters[:2]]`, +4 bytes", - ast.unparse(_pfs_vals.generators[0].iter) == "self.inverters" + _src(_pfs_vals_iter) == "self.inverters" and _s_head_kill[2] and not _SLICED, "part 12i's sweep reads the REAL property on real rosters so it " "sees this too, its pin is on the comprehension's own iterable, " @@ -5818,7 +5830,7 @@ check("...and the seventh is honestly reported as not caught, because it cannot "the expression rather than by a check. THAT is why the ceiling is a max " "and not a subtraction - `headroom = cap - peak` would have turned the " "same zero into FULL freedom, which part 3 shows is why headroom_w() is " - "not consumed here", not MUT[6][1] + "not consumed here", present(nth(MUT, 6)) and not MUT[6][1] and quarter_ceiling_w(CAP_W, _zero_peak)[0] == CAP_W) check("...and SAFETY-32's own eight defeats are each caught too - the flat " "cut-out inherited, the site floor graded in place of the pack's, the " @@ -5851,7 +5863,7 @@ check("...⚠️ AND ONE IS RECORDED AS NOT CAUGHT, which is the only honest row "pin would refuse honest refactors, so the hole is reported with its size " "instead of hidden. THIS is the row that a fifth review should argue " "with, and it exists to be argued with", - not MUT[27][1] + present(nth(MUT, 27)) and not MUT[27][1] and all(_head_kill[w] and _tail_kill[w] for w in range(1, _SWEEP_N))) check("...⚠️ AND ROUND 4's SIX, WHICH ARE THE SAME FAMILY AT THE SIBLING " "ARGUMENT OF THE SAME CALL. `pack_floor_soc` is the MINIMUM over the " @@ -5873,7 +5885,7 @@ check("...and so is the last one, which is not a defeat at all but the EDGE OF " "and a `lo` limit cannot cap a discharge. Saying so here is worth more " "than a green line that would be untrue - and part 10 now says it with a " "number instead of a sentence, which is worth more again", - not MUT[12][1] and EV["min_soc"] <= BMS_FLOOR + 0.05) + present(nth(MUT, 12)) and not MUT[12][1] and EV["min_soc"] <= BMS_FLOOR + 0.05) # ============================================================================== @@ -5953,7 +5965,8 @@ check("⚠️ ...AND THE SAME ORDERED PAIR ON THE STATUS PAGE (main.py:3313), re check("...and the row is green and un-warned, which is what makes the " "transposed version dangerous rather than merely untidy: an OK row " "carrying a projection 2713 W OVER its own ceiling is the one an " - "operator scrolls past", _rows38[0]["ok"] and not _rows38[0]["warn"] + "operator scrolls past", len(_rows38) == 1 + and _rows38[0]["ok"] and not _rows38[0]["warn"] and _S38_CEIL_W - _S38_PROJ.projected_w == 2713.0) # ============================================================================== @@ -6211,8 +6224,9 @@ check("a FLOOR-LIMITED decision - the guard wanted a discharge and SoC refused " # been inverted. _H45_SRC = (HERE / "app" / "peakguard.py").read_text(encoding="utf-8") _H45_TREE = ast.parse(_H45_SRC) -_h45_fn = next(n for n in ast.walk(_H45_TREE) - if isinstance(n, ast.FunctionDef) and n.name == "decide") +_h45_fn = first((n for n in ast.walk(_H45_TREE) + if isinstance(n, ast.FunctionDef) and n.name == "decide"), + "def decide in peakguard.py") _H45_RUNG = [n for n in ast.walk(_h45_fn) if isinstance(n, ast.If) and ast.unparse(n.test) == "wanted <= 0.0"] check("the `wanted <= 0.0` rung is still in decide(), spelled exactly that " @@ -6223,8 +6237,9 @@ check("...and it still DISENGAGES rather than merely reporting: the fixture " "13a is built on reaches it and files no claim, so the pin above is not " "grading a rung that has been inverted under it", peakguard.claim(_h45_idle) is None) -_h45_head_fn = next(n for n in _H45_TREE.body if isinstance(n, ast.FunctionDef) - and n.name == "charge_headroom_w") +_h45_head_fn = first((n for n in _H45_TREE.body if isinstance(n, ast.FunctionDef) + and n.name == "charge_headroom_w"), + "def charge_headroom_w in peakguard.py") check("...and charge_headroom_w() is a PURE READ of the decision - one " "positional parameter, no projection, no clock and no options - so it " "cannot become a second answer to the question decide() already answers", diff --git a/goodwe_controller/test_price.py b/goodwe_controller/test_price.py index b544281..0925e84 100644 --- a/goodwe_controller/test_price.py +++ b/goodwe_controller/test_price.py @@ -60,6 +60,8 @@ import os import re import shutil import sys + +from named_absence import first, nth import tempfile from datetime import date, datetime, timedelta, timezone from textwrap import dedent @@ -310,8 +312,10 @@ check("...and every one of them is in the schema block too", _unschemad == []) # it. So the schema is deliberately WIDER than the registry, by exactly # RETIRED_PROVIDERS and by nothing else. Both halves are graded: an id that is # in neither set, and a retired id that has gone missing. -_line = next(ln for ln in _schema_block if ln.startswith(" price_provider:")) -_schema_ids = set(_line.split("list(", 1)[1].rstrip(")").split("|")) +_line = first((ln for ln in _schema_block if ln.startswith(" price_provider:")), + "price_provider in the schema") +_schema_ids = (set(_line.split("list(", 1)[1].rstrip(")").split("|")) + if "list(" in _line else set()) _wanted = set(PROVIDERS) | set(RETIRED_PROVIDERS) | {"off"} check(f"the schema offers exactly the registered plugins, the retired ids and " f"'off' {sorted(_schema_ids)}", @@ -954,7 +958,7 @@ def asked_url(since, until, extra=None): t = canned(_REAL[_TD]) o = opts(price_provider="generic_dayahead", **(extra or {})) run(load_prices(o, since, until, transport=t)) - return t.calls[0][0] + return nth(t.calls, 0)[0] # The expectation is built HERE, from the window, by different arithmetic than @@ -2069,7 +2073,7 @@ check(f"every networked plugin declares at least one host, and manual_csv " check("the timeout the plugin passes to the transport is the configured one, " "not a hardcoded default", (lambda t: (load("generic_dayahead", {"price_timeout_s": 7}, - transport=t), t.calls[0][1] == 7.0)[1])( + transport=t), nth(t.calls, 0)[1] == 7.0)[1])( canned(columnar_feed(EPEX_EUR_MWH)))) @@ -2477,9 +2481,9 @@ def _started(sites, opts): _MAIN_TREE = derived(lambda: ast.parse(open(os.path.join(_APP, "main.py"), encoding="utf-8").read())) -_AMAIN = derived(lambda: next(n for n in ast.walk(_MAIN_TREE) - if isinstance(n, ast.AsyncFunctionDef) - and n.name == "amain")) +_AMAIN = derived(lambda: next((n for n in ast.walk(_MAIN_TREE) + if isinstance(n, ast.AsyncFunctionDef) + and n.name == "amain"), None)) _SITES = derived(lambda: _task_sites(_AMAIN)) _GRAPH = derived(lambda: _call_graph(_APP)) _FETCH_ENTRY = "resolve_tariff" @@ -3491,8 +3495,8 @@ _cf_t = canned(_REAL[_TD]) run(load_prices(opts(price_provider="custom_formula", **_CF_OPTS), _w0, _w0 + timedelta(hours=48), transport=_cf_t)) check(f"...and asks for the same Brussels range generic_dayahead asks for " - f"{_cf_t.calls[0][0]!r}", - _cf_t.calls[0][0] == asked_url(_w0, _w0 + timedelta(hours=48))) + f"{nth(_cf_t.calls, 0)[0]!r}", + nth(_cf_t.calls, 0)[0] == asked_url(_w0, _w0 + timedelta(hours=48))) # The price at each instant is the document's own index through the card's # arithmetic - computed HERE from the captured bytes, by different arithmetic. @@ -4684,9 +4688,25 @@ _T17_TAB_OUT = derived(lambda: assemble(_T17_CAPS, _T17_RAW, MARKUP, _T17_TABLE)) check("the table parses, through static_tariff's OWN grammar", not isinstance(_T17_TABLE, _Raised)) +# Graded on this file's own two calls: the arms may differ only in `taxes`. +_T17_ARMS = {t.id: [ast.unparse(a) for a in n.value.args[0].body.args] + for n in ast.parse(open(__file__, encoding="utf-8").read()).body + if isinstance(n, ast.Assign) and isinstance(n.value, ast.Call) + and isinstance(n.value.func, ast.Name) + and n.value.func.id == "derived" and n.value.args + and isinstance(n.value.args[0], ast.Lambda) + and isinstance(n.value.args[0].body, ast.Call) + for t in n.targets if isinstance(t, ast.Name) + and t.id in ("_T17_FLAT_OUT", "_T17_TAB_OUT")} +print(f" arms: {_T17_ARMS}") check(f"the two arms are the same feed: same caps, same {len(_T17_RAW)} " - f"RawPoints and the same markup {MARKUP}, by IDENTITY and not by value", - _T17_CAPS is _T17_CAPS and _T17_RAW is _T17_RAW) + f"RawPoints and the same markup {MARKUP} - the two `assemble()` calls " + f"share their first three arguments by NAME and differ only in the fourth", + sorted(_T17_ARMS) == ["_T17_FLAT_OUT", "_T17_TAB_OUT"] + and [len(v) for v in _T17_ARMS.values()] == [4, 4] + and _T17_ARMS["_T17_FLAT_OUT"][:3] == _T17_ARMS["_T17_TAB_OUT"][:3] + == ["_T17_CAPS", "_T17_RAW", "MARKUP"] + and _T17_ARMS["_T17_FLAT_OUT"][3] != _T17_ARMS["_T17_TAB_OUT"][3]) _T17_BANDS = derived(lambda: sorted({p.eur_per_kwh for p in _T17_TABLE.periods})) check(f"...and the table is genuinely hour-varying: {_T17_BANDS} EUR/kWh, two " @@ -5562,10 +5582,11 @@ print("17f. the SCALAR path is unchanged - arithmetically, not merely in " # ⚠️ THE ACCEPTANCE CRITERION TARIFF-17 GRADED THE SAME WAY (16f). A site with # a flat injection price is every site that exists today, and "we did not mean # to change it" is not a measurement. -_T16_OLD_SCALAR = [ast.unparse(n) for n in ast.walk(next( - n for n in ast.parse(open(os.path.join(HERE, "app", "price.py"), - encoding="utf-8").read()).body - if isinstance(n, ast.FunctionDef) and n.name == "export_price_eur_kwh")) +_T16_OLD_SCALAR = [ast.unparse(n) for n in ast.walk(first( + (n for n in ast.parse(open(os.path.join(HERE, "app", "price.py"), + encoding="utf-8").read()).body + if isinstance(n, ast.FunctionDef) and n.name == "export_price_eur_kwh"), + "def export_price_eur_kwh in price.py")) if isinstance(n, ast.Return)] check(f"`export_price_eur_kwh()`'s BODY is still the single expression it has " f"always been, pinned on the AST rather than on the source text: " diff --git a/goodwe_controller/test_price_forecast.py b/goodwe_controller/test_price_forecast.py index 77f9617..9ec5298 100644 --- a/goodwe_controller/test_price_forecast.py +++ b/goodwe_controller/test_price_forecast.py @@ -62,6 +62,8 @@ import inspect import itertools import os import sys + +from named_absence import first, nth from datetime import datetime, timedelta, timezone from app import price as _price @@ -638,7 +640,7 @@ _late = fill_from_yesterday( series_of(DAY, lambda u: t_price(brussels(u).hour), PriceProduct.DAY_AHEAD, "generic_dayahead", provisional=False), yesterday=YESTERDAY, since=D0, until=D1, stamp=D1) -_h20 = DAY[20] +_h20 = nth(DAY, 20) _before = derived(lambda: FILLED.at(_h20)) _after = derived(lambda: _late.at(_h20)) check("before the print, hour 20 is provisional and carries YESTERDAY's number", @@ -728,7 +730,8 @@ check("an action that commits nothing is not an irreversible one and cannot be " # prices that were published for the morning and guessed for the evening. _m = maint() _gate_bad = derived(lambda: begin_phase(_m, START, FILLED, MAINTENANCE_DRAIN)) -_first_prov = derived(lambda: next(u for u in _hours if FILLED.at(u).provisional)) +_first_prov = derived(lambda: first((u for u in _hours if FILLED.at(u).provisional), + "a carried hour in the window")) check("the drain's window really does reach past the published hours while " "staying INSIDE the series, so the refusal below is about provenance and " "not about a short series", @@ -743,7 +746,7 @@ check("...and the phase machine did not move: it is still idle, so the " check("...and the reason names §8.3, the offending hour, and when the real " "price is expected", "§8.3" in _gate_bad.reason - and _first_prov.isoformat() in _gate_bad.reason + and bool(_first_prov) and _first_prov.isoformat() in _gate_bad.reason and "14-16" in _gate_bad.reason) # The positive arm, so the block above is discriminating rather than universal. diff --git a/goodwe_controller/test_price_history.py b/goodwe_controller/test_price_history.py index 9a3c733..488731d 100644 --- a/goodwe_controller/test_price_history.py +++ b/goodwe_controller/test_price_history.py @@ -104,6 +104,8 @@ import json import os import shutil import sys + +from named_absence import first, nth import tempfile from datetime import datetime, timedelta, timezone @@ -239,7 +241,8 @@ YDAY_H = bday_hours(YDAY_D) def at_local(bdate: str, hh: int) -> datetime: """The UTC instant whose Brussels wall clock reads hh:00 on `bdate`.""" - return next(u for u in bday_hours(bdate) if brussels(u).hour == hh) + return first((u for u in bday_hours(bdate) if brussels(u).hour == hh), + f"{bdate} {hh:02d}:00 Brussels") # ⚠️ AND IT IS NOT ON THE HOUR. A controller's `now` is @@ -791,7 +794,7 @@ print("2b. a QUARTER-HOURLY feed keeps every print, and its spread with them") _QSTEP_MIN = 15 _qrows = [] for _n in range(len(TODAY_H) * (60 // _QSTEP_MIN)): - _qu = TODAY_H[0] + timedelta(minutes=_QSTEP_MIN * _n) + _qu = nth(TODAY_H, 0) + timedelta(minutes=_QSTEP_MIN * _n) # A spiky within-the-hour profile, so decimation is visible in the SPREAD # and not only in a count. _qrows.append((_qu, @@ -2009,9 +2012,9 @@ check("...so calling it without one is a TypeError, not a quiet regression", _MAIN = open(os.path.join(_APP, "main.py"), encoding="utf-8").read() _main_tree = ast.parse(_MAIN) -_refresh = next(n for n in ast.walk(_main_tree) - if isinstance(n, ast.AsyncFunctionDef) - and n.name == "run_tariff_refresh") +_refresh = first((n for n in ast.walk(_main_tree) + if isinstance(n, ast.AsyncFunctionDef) + and n.name == "run_tariff_refresh"), "run_tariff_refresh in main.py") _kw = [k.arg for n in ast.walk(_refresh) if isinstance(n, ast.Call) for k in n.keywords] check(f"the shipped refresh task passes a history {_kw} - the wiring is what " @@ -2033,9 +2036,9 @@ check("...and `words` reaches the STATUS PAGE as its own row, so what the fill " "has to carry from is a fact an operator can read rather than one that " "only exists in a log line", '("Price history", self.price_history.words)' in _MAIN) -_rows_fn = next(n for n in ast.walk(_main_tree) - if isinstance(n, ast.FunctionDef) - and n.name == "status_payload") +_rows_fn = first((n for n in ast.walk(_main_tree) + if isinstance(n, ast.FunctionDef) + and n.name == "status_payload"), "status_payload in main.py") _row_labels = [e.elts[0].value for e in ast.walk(_rows_fn) if isinstance(e, ast.Tuple) and len(e.elts) == 2 and isinstance(e.elts[0], ast.Constant) diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 2d83c83..044490a 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -69,6 +69,7 @@ import sys from pathlib import Path from app import mqtt, pv +from named_absence import field, nth, present from app.main import Controller HERE = Path(__file__).resolve().parent @@ -348,12 +349,12 @@ check("...and a kW sensor is read in kW: 3.21 kW is 3210 W, not 3.21 W. There " # ⚠️ THE ONE THAT SEPARATES "ABSENT" FROM "STALE", AND IT NEEDS TWO CYCLES. c_drop, _, p_drop = run(cycles=2, states=[state("4100", "W"), None], **PV_ON) -print(f" published pv by cycle: {[f['pv'] for f in p_drop.frames]}") +print(f" published pv by cycle: {[field(f, 'pv') for f in p_drop.frames]}") check("⭐ A FAILED READ CLEARS THE PREVIOUS GOOD ONE. The cycle after a 4100 W " "reading disappears publishes an ABSENCE, not 4100 W again - a value " "that survives its own sensor is indistinguishable from a real one at " "the moment somebody is working out whether the sun was shining", - [f["pv"] for f in p_drop.frames] == [4100.0, None] + [field(f, "pv") for f in p_drop.frames] == [4100.0, None] and c_drop.pv_w is None and "no state" in c_drop.pv_why) @@ -378,9 +379,9 @@ def wire(values, include=("pv",)): return pub.client.msgs -_zero = run(cycles=1, states=[state("0", "W")], **PV_ON)[2].frames[-1] -_absent = run(cycles=1, states=[None], **PV_ON)[2].frames[-1] -_nosrc = p_off.frames[-1] +_zero = nth(run(cycles=1, states=[state("0", "W")], **PV_ON)[2].frames, -1) +_absent = nth(run(cycles=1, states=[None], **PV_ON)[2].frames, -1) +_nosrc = nth(p_off.frames, -1) print(f" no source : 'pv' in frame = {'pv' in _nosrc}") def pv_msg(values): """The `goodwe_ctl/pv` message the shipped publisher emits, or None.""" @@ -388,17 +389,17 @@ def pv_msg(values): return got[0] if got else None -print(f" no reading: {_absent['pv']!r} -> wire {pv_msg(_absent)}") -print(f" zero watts: {_zero['pv']!r} -> wire {pv_msg(_zero)}") +print(f" no reading: {field(_absent, 'pv')!r} -> wire {pv_msg(_absent)}") +print(f" zero watts: {field(_zero, 'pv')!r} -> wire {pv_msg(_zero)}") check("NO SOURCE: an install that never set `pv_entity` publishes no `pv` key " "at all - there is no entity to feed, so feeding one would be a topic " "nothing announced", - "pv" not in _nosrc) + present(_nosrc) and "pv" not in _nosrc) check("NO READING: the key is PRESENT and its value is None, which is a " "different frame from the one above. 'the option is off' and 'the sensor " "did not answer' are two facts and one field cannot carry both", "pv" in _absent and _absent["pv"] is None) -check("ZERO WATTS: 0.0, published as a number", _zero["pv"] == 0.0) +check("ZERO WATTS: 0.0, published as a number", field(_zero, "pv") == 0.0) check("⭐ AND ON THE WIRE THE LAST TWO ARE DIFFERENT BYTES ON THE SAME TOPIC: " "`None` - which is Home Assistant's own payload for 'this sensor has no " "value', so the entity goes to `unknown` and the recorder records a GAP " @@ -441,7 +442,7 @@ def announced(opts): check("with a source: `pv` is announced AND published", "pv" in announced(PV_ON) and "pv" in _absent) check("without one: announced by nothing and published by nothing", - "pv" not in announced({}) and "pv" not in _nosrc) + "pv" not in announced({}) and present(_nosrc) and "pv" not in _nosrc) check("...and the predicate is ONE expression, `mqtt.optional_keys()`, read by " "the announcement and by `Controller.publish()` alike - two spellings is " "how an entity gets announced that nothing feeds", @@ -473,7 +474,7 @@ _a1 = mqtt.discovery_payloads(include=mqtt.optional_keys(PV_ON)) _a2 = mqtt.discovery_payloads(include=mqtt.optional_keys(PV_ON)) _pv_cfg = [c for _t, c in _a1 if c["unique_id"] == "goodwe_ctl_pv"] print(f" composed entity_id: " - f"{compose(mqtt.DEVICE['name'], _pv_cfg[0]['name'])}") + f"{compose(mqtt.DEVICE['name'], nth(_pv_cfg, 0)['name'])}") check("a restart re-announces the SAME bytes, so Home Assistant sees the entity " "it already has rather than a new one beside a dead one - the history is " "continuous across a restart of the add-on", @@ -483,7 +484,8 @@ check("a restart re-announces the SAME bytes, so Home Assistant sees the entity check("...and the id Home Assistant composes for it is " "`sensor.goodwe_pv_power`, which is what DOCS.md tells an operator to put " "on a dashboard - device name plus entity name, NOT the object_id", - compose(mqtt.DEVICE["name"], _pv_cfg[0]["name"]) + len(_pv_cfg) == 1 + and compose(mqtt.DEVICE["name"], _pv_cfg[0]["name"]) == "sensor.goodwe_pv_power" and _pv_cfg[0]["state_topic"] == "goodwe_ctl/pv") @@ -536,7 +538,8 @@ check("⭐ ...and it is a CAUTION, never a `bad` row: `status_payload()` builds "NOT READY out of rows that are neither ok nor warn, and a telemetry " "channel that could put a battery site into NOT READY would be " "observability with a foot in the control path", - _bad_row[0] == {"ok": False, "warn": True, "text": _bad_row[0]["text"]} + len(_bad_row) == 1 + and _bad_row[0] == {"ok": False, "warn": True, "text": _bad_row[0]["text"]} and not c_bad.status_payload()["banner"].startswith("NOT READY") and c_bad.status_payload()["level"] != "bad" and c_bad.status_payload()["banner"] @@ -867,8 +870,8 @@ print("9. ⭐ publication at a roster of three, as PAYLOAD BYTES") # Part 3 did this for one entity. The new state is "several configured, one of # them gone", and the number that must NOT appear on the topic is a specific # plausible number rather than a wrong shape. -_m_full = run(cycles=1, by_entity=FULL, **PV_MANY)[2].frames[-1] -print(f" 3 healthy : {_m_full['pv']!r} -> wire {pv_msg(_m_full)}") +_m_full = nth(run(cycles=1, by_entity=FULL, **PV_MANY)[2].frames, -1) +print(f" 3 healthy : {field(_m_full, 'pv')!r} -> wire {pv_msg(_m_full)}") check("⭐ THREE HEALTHY: one topic, one number, the SITE total - 3750.0. There " "is deliberately no per-entity topic: the recorder statistic OPT-10 reads " "back is the site figure, and a per-inverter breakdown is a dashboard " @@ -878,7 +881,7 @@ check("⭐ THREE HEALTHY: one topic, one number, the SITE total - 3750.0. There == [pv_msg(_m_full)]) _holed = [] for _miss, (_script, _partial) in HOLES.items(): - _fr = run(cycles=1, by_entity=_script, **PV_MANY)[2].frames[-1] + _fr = nth(run(cycles=1, by_entity=_script, **PV_MANY)[2].frames, -1) _msg = pv_msg(_fr) print(f" {_miss} dead -> wire {_msg} (partial would have been " f"{_partial:.0f} W -> {str(_partial)!r})") @@ -950,7 +953,8 @@ check("⭐ ...and it is a CAUTION, never a `bad` row, at a roster exactly as at "neither ok nor warn, and a telemetry channel that could put a battery " "site into NOT READY would be observability with a foot in the control " "path", - _gap_row[0] == {"ok": False, "warn": True, "text": _gap_row[0]["text"]} + len(_gap_row) == 1 + and _gap_row[0] == {"ok": False, "warn": True, "text": _gap_row[0]["text"]} and _c_gap.status_payload()["level"] != "bad" and _c_gap.status_payload()["banner"] == c_off.status_payload()["banner"]) diff --git a/goodwe_controller/test_static_tariff.py b/goodwe_controller/test_static_tariff.py index d5d6d38..4078ae5 100644 --- a/goodwe_controller/test_static_tariff.py +++ b/goodwe_controller/test_static_tariff.py @@ -63,6 +63,8 @@ import ast import gzip import json import sys + +from named_absence import first from datetime import datetime, timedelta, timezone from pathlib import Path @@ -1213,8 +1215,9 @@ check("...and the pin is not vacuous: each of those names really is a " def _t17_sig(module, name): tree = ast.parse((HERE / "app" / module).read_text(encoding="utf-8")) - fn = next(n for n in tree.body - if isinstance(n, ast.FunctionDef) and n.name == name) + fn = first((n for n in tree.body + if isinstance(n, ast.FunctionDef) and n.name == name), + f"def {name} in {module}") return [a.arg for a in fn.args.args] diff --git a/goodwe_controller/test_tariff.py b/goodwe_controller/test_tariff.py index e18a076..9511151 100644 --- a/goodwe_controller/test_tariff.py +++ b/goodwe_controller/test_tariff.py @@ -114,6 +114,8 @@ import tempfile from datetime import datetime, timedelta, timezone from pathlib import Path +from named_absence import given, nth, present + from app.main import Controller from app.p1 import P1Ingest, QuarterAverager, QUARTER_S, make_sample, split_signed from app.tariff import ( @@ -260,7 +262,7 @@ deg = QuarterAverager(phases=1, max_hold_s=MAX_HOLD_S) deg_closed = [] for i in range(0, QUARTER_S + 1, 5): deg_closed += deg.add(sample(B + timedelta(seconds=i), HELD_W)) -d_block = deg_closed[0].offtake_avg_w +d_block = nth(deg_closed, 0).offtake_avg_w deg2 = QuarterAverager(phases=1, max_hold_s=MAX_HOLD_S) LAST_S = QUARTER_S - 5 for i in range(0, LAST_S + 1, 5): @@ -311,7 +313,7 @@ def feed(avg, t0_s, t1_s, w=RUN_W): # (a) the control: no restart at all. ctrl = QuarterAverager(phases=1, max_hold_s=MAX_HOLD_S) ctrl_closed = feed(ctrl, 0, QUARTER_S) -CTRL_W = ctrl_closed[0].offtake_avg_w +CTRL_W = nth(ctrl_closed, 0).offtake_avg_w # (b) restarted at minute 10, checkpoint restored through a real SQLite file. st = fresh_store("restart") @@ -332,8 +334,8 @@ a3 = QuarterAverager(phases=1, max_hold_s=MAX_HOLD_S) n_closed = feed(a3, RESTART_AT_S + STEP_S, QUARTER_S) NORESTORE_W = n_closed[0].offtake_avg_w if n_closed else None -print(f" uninterrupted {CTRL_W:.2f} W | restored {RESTART_W:.2f} W | " - f"restart with no restore {NORESTORE_W:.2f} W") +print(f" uninterrupted {CTRL_W:.2f} W | restored {given(RESTART_W):.2f} W | " + f"restart with no restore {given(NORESTORE_W):.2f} W") check(f"a restart at {RESTART_AT_S} s lands on the SAME billed block as an " f"uninterrupted run", near(RESTART_W, CTRL_W, 1e-6)) check("...and without the restore it lands LOWER - so 'the restore works' is " @@ -357,18 +359,18 @@ o_closed = feed(a4, RESTART_AT_S + OUTAGE_S, QUARTER_S) OUTAGE_UNCOVERED_S = OUTAGE_S - MAX_HOLD_S print(f" a {OUTAGE_S} s outage inside the quarter, of which " f"{OUTAGE_UNCOVERED_S:.0f} s is past the {MAX_HOLD_S:.0f} s hold: " - f"{o_closed[0].offtake_avg_w:.2f} W") + f"{nth(o_closed, 0).offtake_avg_w:.2f} W") check(f"...reads lower than the uninterrupted block by exactly the uncovered " f"seconds ({RUN_W * OUTAGE_UNCOVERED_S / QUARTER_S:.2f} W) - a gap is " f"never held forward across the whole outage", - near(CTRL_W - o_closed[0].offtake_avg_w, + near(CTRL_W - nth(o_closed, 0).offtake_avg_w, RUN_W * OUTAGE_UNCOVERED_S / QUARTER_S, 1e-6)) # (e) double counting is answered by the primary key, not by care. st5 = fresh_store("dedupe") -st5.record_block(ctrl_closed[0]) -st5.record_block(ctrl_closed[0]) -st5.record_block(ctrl_closed[0]) +if ctrl_closed: + for _ in range(3): + st5.record_block(ctrl_closed[0]) rows = st5.blocks_in(month_key(B)) check("banking the same quarter three times leaves ONE row - quarter_start is " "the primary key, so a replay or a restart cannot double-count", @@ -376,7 +378,9 @@ check("banking the same quarter three times leaves ONE row - quarter_start is " # ...and a later pass with LESS coverage may not lower a banked figure. from app.tariff import _ClosedBlock as _CB -st5.record_block(_CB(start=B, offtake_avg_w=CTRL_W / 2, per_phase_offtake_avg_w=None)) +if present(CTRL_W): + st5.record_block(_CB(start=B, offtake_avg_w=CTRL_W / 2, + per_phase_offtake_avg_w=None)) after = st5.blocks_in(month_key(B)) check(f"...and re-banking the same quarter at half the figure leaves it at " f"{CTRL_W:.0f} W - a restart's partial re-run must never lower a " @@ -665,10 +669,10 @@ u = QuarterAverager(phases=3, max_hold_s=MAX_HOLD_S) u_closed = [] for i in range(0, QUARTER_S + 1, 5): u_closed += u.add(sample(B + timedelta(seconds=i), NET, phases=3, phase_net=PH)) -blk = u_closed[0] +blk = nth(u_closed, 0) vals = {p: billed_w(blk, p) for p in (POLICY_NET, POLICY_SUM, POLICY_MAX)} print(f" phases {PH} (net {NET:+.0f} W) -> " - + ", ".join(f"{k}={v:.0f} W" for k, v in vals.items())) + + ", ".join(f"{k}={given(v):.0f} W" for k, v in vals.items())) check(f"the NET policy bills the connection's net offtake ({NET:.0f} W)", near(vals[POLICY_NET], NET, 1e-6)) check(f"the SUM policy clips each phase first, so the exporting phase does not " @@ -687,7 +691,7 @@ b_closed = [] for i in range(0, QUARTER_S + 1, 5): b_closed += bal.add(sample(B + timedelta(seconds=i), 3000.0, phases=3, phase_net=(1000.0, 1000.0, 1000.0))) -b_vals = {p: billed_w(b_closed[0], p) for p in (POLICY_NET, POLICY_SUM, POLICY_MAX)} +b_vals = {p: billed_w(nth(b_closed, 0), p) for p in (POLICY_NET, POLICY_SUM, POLICY_MAX)} check(f"...and on a BALANCED load NET and SUM coincide ({b_vals[POLICY_NET]:.0f} W), " f"so a balanced fixture could not have told them apart", near(b_vals[POLICY_NET], b_vals[POLICY_SUM], 1e-6)) @@ -746,7 +750,7 @@ check(f"...and record_block() with NO policy argument banks the NET figure " # fixture change ever made two of these coincide, the triple above would start # passing under a hardcoded policy and would be silently back where it started. print(f" banked through the store: " - + ", ".join(f"{k}={v:.0f} W" for k, v in _banked.items())) + + ", ".join(f"{k}={given(v):.0f} W" for k, v in _banked.items())) check("the three BANKED figures are three distinct numbers, so this triple is " "not itself degenerate - it can only pass if the argument is read", len({round(v, 6) for v in _banked.values() if v is not None}) == 3) @@ -855,16 +859,16 @@ for path in REPLAY: print(f" {path.name}: {span_h:.1f} h, {len(qs)} closed quarters, " f"month peak {peak:.0f} W, " f"{ok_q}/{len(qs)} = {100.0 * ok_q / max(len(qs), 1):.1f} % under the " - f"{SHIPPED_CAP_W:.0f} W soft limit") + f"{given(SHIPPED_CAP_W):.0f} W soft limit") check(f"{path.name}: the month's peak equals its own largest quarter", - near(st9.peak(month=sorted(months)[0]).peak_w, peak, 1e-9)) + bool(months) and near(st9.peak(month=sorted(months)[0]).peak_w, peak, 1e-9)) check(f"{path.name}: a full day of real telegrams produces ~96 quarters, " f"got {len(qs)}", 90 <= len(qs) <= 96) PCT = 100.0 * under / max(total_q, 1) print() print(f" AC 3 MEASURED: {under}/{total_q} quarters = {PCT:.1f} % under the " - f"{SHIPPED_CAP_W:.0f} W soft limit, over {replay_days:.1f} DAYS of " + f"{given(SHIPPED_CAP_W):.0f} W soft limit, over {replay_days:.1f} DAYS of " f"replay, UNCONTROLLED (no peak shaving was running on either day).") print(f" AC 3 ASKS FOR 30 DAYS and this run is {replay_days:.1f}, so it " f"does not settle it either way. The 30 days DO now exist - " @@ -928,7 +932,7 @@ def built(db_path, opts=None): c = built(TMP / "wired.db") check(f"a Controller built with peak_cap_w ABSENT takes the SHIPPED " - f"{SHIPPED_CAP_W:.0f} W, so config.yaml and main.py's fallback cannot " + f"{given(SHIPPED_CAP_W):.0f} W, so config.yaml and main.py's fallback cannot " f"drift apart unnoticed", c.peak.cap_w == SHIPPED_CAP_W) # Drive one real quarter through the real ingest, then the real cycle's sync. @@ -981,7 +985,7 @@ check("the status page carries exactly one capacity-tariff peak row", check("...naming the peak, the soft limit and a coverage figure, all derived " "from the controller that was actually built", bool(peak_rows) and "4998 W" in peak_rows[0]["text"] - and f"{SHIPPED_CAP_W:.0f} W soft limit" in peak_rows[0]["text"] + and f"{given(SHIPPED_CAP_W):.0f} W soft limit" in peak_rows[0]["text"] and "quarter(s) banked" in peak_rows[0]["text"]) # ⚠️ AND THE COVERAGE FIGURE IN THAT ROW IS SCOPED TO THE LIVE BILLING MONTH, @@ -1006,7 +1010,7 @@ check("the row's coverage figure is the LIVE month's tally - graded against a " bool(peak_rows) and f"; {_live_rows} quarter(s) banked" in peak_rows[0]["text"]) check("...and it is FLAGGED, because 4998 W is over §9.1's 80 % warning point " - f"on a {SHIPPED_CAP_W:.0f} W limit", + f"on a {given(SHIPPED_CAP_W):.0f} W limit", bool(peak_rows) and not peak_rows[0]["ok"] and peak_rows[0]["warn"]) # The half that matters: the same page with a store that cannot answer. diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 8ec0ea0..8d8cf38 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -20,6 +20,8 @@ Read MUTATION.md before you report a survivor. import sys from datetime import datetime, timedelta, timezone +from named_absence import nth, present + from app.watchdog import ( SignWatchdog, SignWatchdogConfig, loop_is_following, ) @@ -1102,7 +1104,7 @@ check("...under a fixed notification_id of its own, so a second episode " all(c[2]["notification_id"] == "goodwe_circulating_power" for c in _notes1 + _notes2) and len({c[2]["notification_id"] for c in _notes1 + _notes2}) == 1) -_msg = _notes2[0][2]["message"] +_msg = nth(_notes2, 0)[2]["message"] check("...and the message tells the operator the three things only this alarm " "can: that the meter cannot see it, that control has been stopped, and " "that if the grid reading does not move afterwards one inverter is no " @@ -1706,7 +1708,7 @@ print(f" {_b30.sign_wd.reason!r}") # the objects - and not off the fixture's constants, so the check cannot be # satisfied by two numbers the fixture happens to hold anyway (habit 2). _preb30 = [x for x in _s30 if not x["b"]] -_midb30 = _preb30[-1] +_midb30 = nth(_preb30, -1, "no cycle before B latched") print(f" last cycle before B latched: B stood " f"{_midb30['stood'][1]:+.0f} W, B measured {_midb30['meas'][1]:+.0f} W") check("⚠️ ...AND THE ORDERED PAIR, on the ONE SIGN-DISAGREEMENT SENTENCE A " @@ -1840,7 +1842,7 @@ _c31, _h31, _s31 = asyncio.run(_site_reversed()) # stopped. This is `Run.p2p_between`'s lesson from the rig, in a unit test: name # the window rather than inferring it. _pre31 = [x for x in _s31 if not x["site"]] -_mid31 = _pre31[-1] +_mid31 = nth(_pre31, -1, "no cycle before the trip") print(f" last cycle before the trip: stood " f"{[round(x) for x in _mid31['stood']]} " f"measured {[round(x) for x in _mid31['meas']]} " @@ -1849,7 +1851,8 @@ check("PRECONDITION: EVERY inverter is obeying - each unit's measured power " "agrees in sign with its own share - and the site is still charging into " "an importing house. Without this the site trip below could be a " "per-unit fault in disguise", - all(s * m > 0 for s, m in zip(_mid31["stood"], _mid31["meas"])) + present(_mid31) + and all(s * m > 0 for s, m in zip(_mid31["stood"], _mid31["meas"])) and sum(_mid31["stood"]) * _mid31["grid"] < 0) check("⚠️ AC 3. THE SITE WATCHDOG TRIPS AND NOT ONE PER-UNIT WATCHDOG DOES. " "That asymmetry is the card: the fault is in the number the site was " @@ -2053,7 +2056,7 @@ check("...the reason sentence still says 'a meter reading', word for word - it " # consecutive commands IDENTICAL; at a rail-following slew the loop ramps and # they differ by exactly one step, which is how this was found. _first1s = [x for x in _seen1s if x["tripped"]] -_mid1s = _first1s[0] +_mid1s = nth(_first1s, 0, "no tripped cycle") print(f" the cycle the latch happened on: stood {_mid1s['stood']:+.0f} W, " f"meter {_mid1s['grid']:+.0f} W") print(f" {_inv1.sign_wd.reason!r}") @@ -2501,13 +2504,13 @@ _c38, _s38seen = asyncio.run(_s38_site()) # The last sample BEFORE the trip, named rather than indexed - part 5's lesson. # After the trip every command is 0 W, so a fixed index reads the REMEDY. _pre38 = [x for x in _s38seen if not x["site"]] -_mid38 = _pre38[-1] +_mid38 = nth(_pre38, -1, "no cycle before the trip") _GATE38 = _c38.site_sign_wd.cfg.min_w _share38 = list(_mid38["stood"]) _red38 = {"sum": sum(_share38), "mean": sum(_share38) / max(1, len(_share38)), - "max(key=abs)": max(_share38, key=abs), - "[0]": _share38[0]} + "max(key=abs)": max(_share38, key=abs, default=nth([], 0)), + "[0]": nth(_share38, 0)} print(f" last cycle before the trip: stood " f"{[round(x) for x in _share38]} measured " f"{[round(x) for x in _mid38['meas']]} meter {_mid38['grid']:+.0f} W") @@ -2538,7 +2541,8 @@ check("PRECONDITION: EVERY inverter is obeying - each unit's measured power " "agrees in sign with its own share - and the site is charging into an " "importing house. Without this the trip below could be a per-unit fault " "in disguise rather than the site fault this grades", - all(s * m > 0 for s, m in zip(_mid38["stood"], _mid38["meas"])) + present(_mid38) + and all(s * m > 0 for s, m in zip(_mid38["stood"], _mid38["meas"])) and sum(_mid38["stood"]) * _mid38["grid"] < 0 and _mid38["following"] is True) check("⚠️ THE SITE WATCHDOG TRIPS ON THE SUM, and no per-unit watchdog does. " -- 2.54.0 From 02a822af9829e2efa3ecb11dd9a3b15ecf64afde Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 00:20:52 +0200 Subject: [PATCH 006/105] DOC-5: tell installers to turn on the Supervisor Watchdog Since SAFETY-61 a dead control loop writes 0 W and exits 70. The Supervisor restarts a stopped add-on only when the per-install Watchdog toggle is on, and it defaults to off. One step in DOCS.md "Before you start", with a pointer to the DECISIONS file. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- goodwe_controller/DOCS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 837742b..d925b8d 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -16,6 +16,11 @@ You need: - A T-CAN485 (ESP32) flashed with `firmware/goodwe-master.yaml` - A grid-power sensor already working in Home Assistant, updating every ~5–10 s +After installing, turn on **Watchdog** on the add-on's Info tab. A crashed +control loop stops the add-on at 0 W, and the Supervisor restarts it only when +Watchdog is on (it is off by default). See +`DECISIONS/SAFETY-61-control-task-death.md`. + ## The safety model, in short The inverter **holds its last command forever** — it has no meter-timeout. So: -- 2.54.0 From 7559d21eda3129e3dcae97df376d770f18532230 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 00:25:24 +0200 Subject: [PATCH 007/105] TEL-14: PV sign declared per entity (pv_invert_entities) Some PV entities (kWh meters, ESPHome clamps in the PV circuit) read positive for consumption and negative for production. `pv_invert_entities` lists the ones to flip; the flip is applied per member inside pv.total(), before the sum, so the MQTT `pv` row and the status page carry the corrected figure. Default [] is byte-identical to 0.12.0. Shape measured in supervisor_shape_probe.py section H (Supervisor 2026.08.0): a parallel list validates the 0.12.0 blob unchanged and renders as its own translated repeatable field; dicts on pv_entities refuse 0.12.0's stored strings; a prefix is invisible syntax; a global bool cannot describe a mixed roster. Status page marks flipped entities and cautions per entity below -50 W, saying ADD or REMOVE. Telemetry only: control documents unchanged. Record: DECISIONS/TEL-14-pv-sign.md (reverses TEL-11 section 2). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- .../DECISIONS/TEL-11-pv-production.md | 2 + goodwe_controller/DECISIONS/TEL-14-pv-sign.md | 85 +++++++ goodwe_controller/DOCS.md | 23 +- goodwe_controller/app/main.py | 34 ++- goodwe_controller/app/pv.py | 49 ++-- goodwe_controller/config.yaml | 18 +- goodwe_controller/test_pv.py | 223 +++++++++++++++++- .../tools/supervisor_shape_probe.py | 66 ++++++ goodwe_controller/translations/en.yaml | 5 +- goodwe_controller/translations/nl.yaml | 5 +- 10 files changed, 462 insertions(+), 48 deletions(-) create mode 100644 goodwe_controller/DECISIONS/TEL-14-pv-sign.md diff --git a/goodwe_controller/DECISIONS/TEL-11-pv-production.md b/goodwe_controller/DECISIONS/TEL-11-pv-production.md index a941683..f5802c0 100644 --- a/goodwe_controller/DECISIONS/TEL-11-pv-production.md +++ b/goodwe_controller/DECISIONS/TEL-11-pv-production.md @@ -38,6 +38,8 @@ the trade [[product-not-one-house]] names. ## 2. The sign convention: **positive is production**, and there is no `pv_invert` +> Reversed by TEL-14 (flag and negative caution): `DECISIONS/TEL-14-pv-sign.md`. + ### The convention is derived, not assumed Two sign rules already ship, and both are recorded in `DOCS.md`'s *Sources* diff --git a/goodwe_controller/DECISIONS/TEL-14-pv-sign.md b/goodwe_controller/DECISIONS/TEL-14-pv-sign.md new file mode 100644 index 0000000..d9a9b81 --- /dev/null +++ b/goodwe_controller/DECISIONS/TEL-14-pv-sign.md @@ -0,0 +1,85 @@ +# TEL-14 — the PV sign, declared per entity + +Owner report on 0.12.0: `sensor.espressif_vermogen` (ESPHome clamp) and +`sensor.kwh_meter_actueel_vermogen` (kWh meter in the PV circuit) read +**positive for consumption, negative for production**. At night the page said +"✓ PV production: 13 W" — standby draw. By day production would publish negative. + +## 1. This reverses TEL-11 §2, and why + +TEL-11 §2 refused a `pv_invert` because (1) PV is read by nothing in the control +path, and (2) a reversed sensor "announces itself as −4 kW at noon" and should be +"fixed where it is produced". (1) still holds: the flip is applied inside +`pv.total()`, which only feeds the MQTT `pv` row and the status page; +`test_pv.py` part 12 re-runs part 6's 40-cycle identity with a flip set, and +`tools/tel11_pv_trace.py` on release/1.0 vs this tree gives identical `control` +documents for `unset`, `one` and `multi`; the only telemetry change is the new +caution in the `negative` (−4200 W) cells. Its `--compare` verdict itself now +REFUSES on any honest run, because both trees know `pv_entities` — TEL-12 §3's +discriminator has aged out, as TEL-11's did; not fixed here. (2) did +not survive contact with a real site: these sensors are not *wrong*, they +follow a different convention; at night they read a plausible small positive +number, so nothing announces anything; and "fix it where it is produced" means a +template sensor, which TEL-12 §2 already names as the place an `unavailable` +source goes quietly wrong. + +## 2. The shape: a parallel list, `pv_invert_entities` — measured + +`tools/supervisor_shape_probe.py` §H, Supervisor 2026.08.0, against a 0.12.0 +blob (`pv_entities` set, no new key): + +``` +== H. TEL-14: the SHAPE of a per-entity PV sign option == + PASS (a) PREFIX: `-sensor.pv_meter` validates under the shipped `- str` - Supervisor does not look inside the string, ... + PASS (b) ⭐ PARALLEL LIST, SHIPPED: the 0.12.0 blob (no `pv_invert_entities` key) validates unchanged and the new key defaults to [] + PASS ...and one entity marked inverted validates + PASS ⭐ ...and the shipped `options:` block with ONLY `pv_invert_entities` removed is REFUSED BY NAME ... + Missing option 'pv_invert_entities' in root in GoodWe RS485 Controller (local_goodwe_controller) + PASS ...and the Configuration tab renders it as a REPEATABLE string field with its own top-level (translated) label + [{"name": "pv_invert_entities", "multiple": true, "required": true, "type": "string"}] + PASS (c) LIST OF DICTS ON `pv_entities`: the STRINGS a 0.12.0 install stored are REFUSED ... + Invalid dict for option 'pv_entities' in GoodWe RS485 Controller (local_goodwe_controller) + PASS (c2) ...as a THIRD key it validates, but renders as a type-schema repeatable section whose per-entry keys reach the screen RAW ... + PASS (d) GLOBAL `pv_invert: bool` validates too - it loses on SEMANTICS (one sign for a mixed roster), not on the schema +== all cases passed == +``` + +| shape | schema | why it lost / won | +|---|---|---| +| (a) `-sensor.x` prefix | accepted | invisible: the sign is a syntax only the description explains, in a field an installer fills with the entity picker's text | +| (b) parallel list | accepted, 0.12.0 blob unchanged | **ships**: its own labelled, translated field ("PV entities whose sign is reversed"); an installer lists the odd ones out | +| (c) dicts on `pv_entities` | **refuses 0.12.0's stored strings** | bricks the upgrade — TEL-12's trap again | +| (c2) dicts as a third key | accepted | per-entry labels render raw (`entity`, `invert`) — §F; and a third PV surface | +| (d) global bool | accepted | one sign cannot describe inverter + meter in one roster | + +(b)'s known cost is a typo in the second list: `pv.stray_inverts()` turns it into +a named caution. `[]` in `options:` is load-bearing (§H, isolated counterfactual). +Default `[]` flips nothing, so every 0.12.0 install is byte-identical (part 12). + +## 3. The negative caution: per entity, below −50 W + +The owner's two meters draw ~13 W at night, so a *correctly* signed meter reads +about −13 W then. −50 W clears that with room for a few such devices behind one +entity; a reversed sensor by day reads hundreds to thousands of watts below +zero. It is tested **per entity, not on the total** (a deviation from the brief): +three correct meters at −20 W sum to −60 W and must stay quiet, while a reversed +−1500 W hidden inside a positive total must not. It is a caution, never `bad`; +a wrong threshold costs a spurious or missed caution, never data. The text says +ADD (unflipped) or REMOVE (already flipped). + +## 4. History + +OPT-10's `sensor.goodwe_pv_power` recorded since 2026-09-24 on an install with +such sensors carries the old sign; nothing rewrites it. + +## 5. CHANGELOG entry for the next PKG cut + +Not written into `CHANGELOG.md`: `test_version_gate.py` 11b/11d refuse an +`## Unreleased` heading (measured on this branch: 4 reds). For PKG to paste: + +> **`pv_invert_entities` (TEL-14).** A PV sensor that reads negative while +> producing — typically a kWh meter or power clamp in the PV circuit — can now +> be listed under *PV entities whose sign is reversed* in the Configuration tab; +> its sign is flipped before the sum and the status page marks it. Empty (the +> default) changes nothing. ⚠️ PV history recorded before you set it keeps the +> old sign. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 837742b..7f462bd 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -141,6 +141,7 @@ either direction, and the check is mutation-tested both ways. | `setpoint_entity` | yes | The ESPHome `number.*_goodwe_setpoint_w` | | `pv_entity` | | Optional. **One** solar inverter's power sensor, `+` = producing. Measurement only — it changes no control behaviour. See [PV production](#pv-production-pv_entity-tel-11) | | `pv_entities` | | Optional. **Several** solar inverters, one row each — use this instead of `pv_entity` when your roof has more than one. Setting it **ignores** `pv_entity`. See [Several PV inverters](#several-pv-inverters-pv_entities-tel-12) | +| `pv_invert_entities` | | Optional. The PV entities above that read **negative** while producing; each one's sign is flipped. See [The sign](#the-sign-and-pv_invert_entities-tel-14) | Use the ESP32's readings rather than the inverter's cloud or dongle sensors: those serve cached values, and a stale reading here ends the maintenance charge @@ -456,21 +457,15 @@ Only the third is a software defect, and **none of them can be told apart without a record of production.** This entity is that record. The attribution itself is OPT-10's, with a week of history behind it. -#### The sign, and why there is no `pv_invert` +#### The sign, and `pv_invert_entities` (TEL-14) -**Positive must mean producing.** That is the same convention as the two sign -rules the add-on already ships — `meter_entity` is positive when **importing** -and `batt_entity` is positive when **discharging**, both of which are "power -arriving at the house" — and production arrives there too. - -`meter_invert` and `batt_invert` exist because those two quantities are -**bipolar and are read by the control path**: a reversed battery sensor is a -perfectly plausible number that the per-inverter sign failsafe then acts on. -Production is unipolar and is read by **nothing**, so a reversed sensor here -cannot mislead a decision — and it announces itself immediately as −4 kW at -noon in the very history this entity creates. A flag would only hide it, so -there is not one. If your sensor really is inverted, fix it where it is -produced. +**Positive must mean producing.** Some sensors — typically a kWh meter or an +ESPHome power clamp in the PV circuit — read negative while producing and a few +watts positive at night: list each of those in `pv_invert_entities`, spelled as +in `pv_entity`/`pv_entities`, and its sign is flipped before the sum; the status +page marks it `[sign inverted]` and cautions on any entity reading below −50 W. +History recorded before you set it keeps the old sign. See +`DECISIONS/TEL-14-pv-sign.md`. #### The unit is read off the entity diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index fb97350..114677c 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -1726,7 +1726,7 @@ class Controller: states = await asyncio.gather( *(self.hass.state(entity) for entity in roster)) self.pv_w, self.pv_why, self.pv_parts = pv_read.total( - list(zip(roster, states))) + list(zip(roster, states)), pv_read.inverted(self.o)) async def read_inputs(self, now_mono: float | None = None) -> None: """Every input this cycle needs, and SAFETY-37's freshness verdict. @@ -5075,6 +5075,13 @@ class Controller: # have to say something the single-entity ones never could. roster = self.pv_roster if roster: + # TEL-14: each flipped entity is marked where its watts are printed; + # an unflipped one gets "", so 0.12.0's sentences are unchanged. + flip = pv_read.inverted(self.o) + + def inv(ent): + return " [sign inverted]" if ent in flip else "" + if len(roster) == 1: if self.pv_w is None: out.append({"ok": False, "warn": True, @@ -5089,7 +5096,7 @@ class Controller: out.append({"ok": True, "warn": False, "text": f"PV production: {self.pv_w:.0f} W " f"from {roster[0]} (reported " - f"in {self.pv_why})"}) + f"in {self.pv_why})" + inv(roster[0])}) elif self.pv_w is None: # ⚠️ THE ROW THAT SAYS THERE IS NO TOTAL, AND IT SAYS IT IN # THOSE WORDS. `pv.total()`'s note is the argument; this is @@ -5104,7 +5111,7 @@ class Controller: "text": "PV production: NO SITE TOTAL - " + self.pv_why + ". Reporting: " + (", ".join( - f"{ent} {watt:.0f} W" + f"{ent} {watt:.0f} W" + inv(ent) for ent, watt, _y in self.pv_parts if watt is not None) or "nothing")}) else: @@ -5117,6 +5124,7 @@ class Controller: f"{len(self.pv_parts)} entities (" + ", ".join( f"{ent} {watt:.0f} W in {why}" + + inv(ent) for ent, watt, why in self.pv_parts) + ")"}) # ⚠️ AND WHEN BOTH KEYS ARE SET, WHICH ONE WON IS STATED. `pv.py`'s @@ -5136,6 +5144,26 @@ class Controller: f"{len(roster)} entities in the " "list are what is summed. Clear " "`pv_entity` to remove this caution"}) + # TEL-14: a sign that looks reversed, per entity rather than on the + # total - see `pv.NEGATIVE_W` and DECISIONS/TEL-14-pv-sign.md §3. + for ent, watt, _y in self.pv_parts: + if watt is not None and watt < pv_read.NEGATIVE_W: + out.append({"ok": False, "warn": True, + "text": f"PV production: {ent} reads " + f"{watt:.0f} W - far below zero, so " + f"its sign is probably reversed. If " + f"it is producing now, " + + ("REMOVE it from " + "`pv_invert_entities`" + if ent in flip else + "ADD it to `pv_invert_entities`") + + " in the Configuration tab"}) + for ent in pv_read.stray_inverts(self.o): + out.append({"ok": False, "warn": True, + "text": f"PV production: `pv_invert_entities` " + f"names {ent}, which is not a PV entity in " + f"use, so it flips nothing - check the " + f"spelling against `pv_entities`"}) return out def status_payload(self) -> dict: diff --git a/goodwe_controller/app/pv.py b/goodwe_controller/app/pv.py index 2a01f65..71c3691 100644 --- a/goodwe_controller/app/pv.py +++ b/goodwe_controller/app/pv.py @@ -50,21 +50,10 @@ SITE figure, and it publishes as an absence. A partial sum is a second way of reporting 0-where-there-was-production, one layer up, and it is refused for the same reason. -THE SIGN CONVENTION: POSITIVE IS PRODUCTION. Derived from the two conventions -this add-on already ships rather than assumed: - - `meter_entity` positive = IMPORTING from the grid (DOCS.md, Sources) - `batt_entity` positive = DISCHARGING the pack (DOCS.md, Sources) - -Both are "positive = power arriving at the house's AC bus", and production -arrives there too. There is deliberately NO `pv_invert` to go with -`meter_invert` and `batt_invert`: those two quantities are BIPOLAR and are READ -BY THE CONTROL PATH - a reversed `batt_entity` feeds SAFETY-30's per-unit sign -check and SAFETY-31's circulating-power sensor with a plausible number the site -then acts on - whereas production is unipolar and is read by nothing. A reversed -PV sensor announces itself as -4 kW at noon in the very history this card -creates, and flipping it here would only hide it. See -`DECISIONS/TEL-11-pv-production.md` §2. +THE SIGN CONVENTION: POSITIVE IS PRODUCTION, as for `meter_entity` and +`batt_entity` ("power arriving at the house's AC bus"). TEL-14: a kWh meter or +power clamp in the PV circuit reads the other way, so `pv_invert_entities` +flips the sign per entity. See `DECISIONS/TEL-14-pv-sign.md`. """ from .hass import BAD_STATES @@ -193,7 +182,28 @@ def entity_is_ignored(opts: dict) -> bool: if str(x or "").strip()]) -def total(readings) -> tuple: +def inverted(opts: dict) -> frozenset: + """The entity ids `pv_invert_entities` flips. TEL-14.""" + return frozenset(e for e in (str(x or "").strip() + for x in (opts.get("pv_invert_entities") or [])) + if e) + + +def stray_inverts(opts: dict) -> list: + """`pv_invert_entities` entries naming no entity in the roster - a typo + that would otherwise leave a sign unflipped with nothing said. TEL-14.""" + roster = set(entities(opts)) + return sorted(e for e in inverted(opts) if e not in roster) + + +# TEL-14: a reading below this is not standby draw. A correctly signed meter in +# the PV circuit reads a few watts NEGATIVE at night (the owner's: 13 W); -50 W +# clears that with room for a couple of such devices on one entity, while a +# reversed sensor in daylight reads hundreds to thousands of watts below zero. +NEGATIVE_W = -50.0 + + +def total(readings, flip=frozenset()) -> tuple: """`(watts, why, parts)` - the SITE's production, or an ABSENCE. TEL-12. `readings` is `[(entity_id, state), ...]` in `entities()` order, one entry @@ -237,8 +247,13 @@ def total(readings) -> tuple: site: shading, a tripped string and nightfall are all real 0s, and a roster that went to `unknown` whenever one member read zero would report an absence on every clear evening and defeat the channel from the other end. + + ⚠️ TEL-14: `flip` is `inverted(opts)`; each member's sign is applied HERE, + before the sum, so every surface reads the corrected figure. `0.0 - w` + rather than `-w`, so a flipped 0 W is `0.0` and never `-0.0` on the wire. """ - parts = [(ent, *watts(st)) for ent, st in readings] + parts = [(ent, w if w is None or ent not in flip else 0.0 - w, why) + for ent, (w, why) in ((e, watts(st)) for e, st in readings)] if not parts: # No roster. `Controller` does not call this in that state - the gate is # `pv_roster` - but a reader of `parts` should never have to wonder. diff --git a/goodwe_controller/config.yaml b/goodwe_controller/config.yaml index d3a9493..3f560ae 100644 --- a/goodwe_controller/config.yaml +++ b/goodwe_controller/config.yaml @@ -159,12 +159,8 @@ options: # So this takes whatever `sensor.*` the site's PV integration provides, any # brand Home Assistant can read. # - # ⚠️ POSITIVE IS PRODUCTION, and there is deliberately no `pv_invert` beside - # `meter_invert` and `batt_invert`. Those two quantities are bipolar AND are - # read by the control path, so a reversed sensor there is a plausible number - # the site acts on; production is unipolar and is read by nothing, so a - # reversed sensor announces itself as -4 kW at noon in the history this key - # exists to create. See DECISIONS/TEL-11-pv-production.md. + # POSITIVE IS PRODUCTION. An entity that reads the other way round goes in + # `pv_invert_entities` below - see DECISIONS/TEL-14-pv-sign.md. # # ⚠️ THE ENTITY'S OWN `unit_of_measurement` IS WHAT IS BELIEVED - W, kW, MW # and the rest of Home Assistant's power units. A sensor with no unit, or with @@ -215,6 +211,12 @@ options: # which is also empty" - i.e. no PV channel at all, which is every install. pv_entities: [] + # TEL-14. Every PV entity listed here (in `pv_entity` or `pv_entities`) has + # its sign flipped, for a kWh meter or power clamp that reads production as + # negative. Per entity, because one roster can mix both conventions. `[]` is + # load-bearing like `pv_entities: []`; see DECISIONS/TEL-14-pv-sign.md. + pv_invert_entities: [] + # ========================================================================== # METER - where the grid reading comes from # ========================================================================== @@ -972,6 +974,10 @@ schema: # `p1_phase_import_entities` is the shipped precedent for the pair. pv_entities: - str + # TEL-14. A parallel list, not a prefix or a dict: measured by + # tools/supervisor_shape_probe.py section H, DECISIONS/TEL-14-pv-sign.md. + pv_invert_entities: + - str # ========================================================================== # METER - where the grid reading comes from diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 2d83c83..1c3b9fa 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -56,7 +56,8 @@ absence every clear evening. Part 8 ⭐⭐ THE SUM, AND WHAT ONE ABSENT MEMBER DOES TO IT. Part 9 ⭐ publication at a roster of three, as payload bytes. Part 10 the operator surfaces at three - and 0.11.0's, unchanged, at one. - Part 11 what this file cannot see, with sizes, and both mutation tables. + Part 11 what this file cannot see, with sizes, and the mutation tables. + Part 12 TEL-14: the sign, declared per entity (runs before part 11). ⚠️ MUTATING A MODULE THIS FILE GRADES? PURGE `__pycache__` FIRST - or run `tools/mutation_run.sh`, which does. `python3 -B` alone does NOT save you: it @@ -663,7 +664,9 @@ NEEDLES = ("pv_entity", "pv_w", "pv_why", "optional_keys", "ABSENT_AS_UNKNOWN", # TEL-12's own names. `pv_entities` and `pv_entity` share a prefix so # the first would have caught it anyway; spelled out because a scope # that only works by accident stops working when a name is renamed. - "pv_entities", "pv_parts", "pv_roster", "entity_is_ignored") + "pv_entities", "pv_parts", "pv_roster", "entity_is_ignored", + # TEL-14's. + "pv_invert_entities", "stray_inverts", "NEGATIVE_W") def touches(src: str) -> bool: @@ -1016,6 +1019,193 @@ check("...and an install with NO PV roster still adds no row of any kind - the " and run(cycles=1, pv_entities=[" "])[1].state_calls == []) +# ============================================================================== +print() +print("12. TEL-14: the sign, declared PER ENTITY") +# ============================================================================== +# Some installs' PV entities read POSITIVE for consumption and NEGATIVE for +# production (a kWh meter or an ESPHome clamp in the PV circuit). The fixture is +# a MIXED roster, because that is the case a global flag gets wrong: +# E1 an inverter, positive = producing 1200 W -> 1200 +# E2 a meter, NEGATIVE = producing, flipped -2.1 kW -> 2100 +# E3 a meter at night, correctly signed, NOT flipped: -30 W standby -> -30 +# and the values keep every wrong reduction apart: +# right 3270; no flip -930; flip all 930; abs() of every member 3330; +# flip E3 instead of E2 -870. +# ⚠️ EVERY CHECK BELOW READS THROUGH `_at`/`_row` AND NEVER INDEXES BLIND, so a +# missing value is a NAMED FAIL rather than a traceback that hides the rest. + + +def _at(seq, i): + """`seq[i]`, or None when there is no such element.""" + try: + return seq[i] + except (IndexError, KeyError, TypeError): + return None + + +def _row(c, needle): + """Every status-row dict whose text contains `needle` (a list, maybe []).""" + try: + return [r for r in c.checks() if needle in r.get("text", "")] + except Exception as e: # noqa: BLE001 - named, below + return [{"text": f"checks() raised {e!r}", "ok": None, "warn": None}] + + +MIX = {E1: [state("1200", "W")], E2: [state("-2.1", "kW")], + E3: [state("-30", "W")]} +MIX_TOTAL = 3270.0 +_MIX_WRONG = {"no flip": -930.0, "flip all": 930.0, "abs": 3330.0, + "flip E3 not E2": -870.0} +PV_FLIP = dict(PV_MANY, pv_invert_entities=[E2]) +check(f"PRECONDITION: the mixed fixture's right answer {MIX_TOTAL:g} W is apart " + f"from every wrong reduction {_MIX_WRONG}", + MIX_TOTAL not in _MIX_WRONG.values() + and len(set(_MIX_WRONG.values())) == len(_MIX_WRONG)) + +# --- the option --------------------------------------------------------------- +check("inverted() is the stripped, non-empty entries of `pv_invert_entities`, " + "and a 0.12.0 blob (no key at all) flips nothing", + pv.inverted({"pv_invert_entities": [" sensor.a ", "", None, "sensor.b"]}) + == frozenset({"sensor.a", "sensor.b"}) + and pv.inverted({}) == frozenset() + and pv.inverted({"pv_invert_entities": None}) == frozenset()) + +# --- the arithmetic ----------------------------------------------------------- +_t_mix = pv.total([(e, _at(MIX[e], 0)) for e in (E1, E2, E3)], + pv.inverted(PV_FLIP)) +_t_raw = pv.total([(e, _at(MIX[e], 0)) for e in (E1, E2, E3)]) +print(f" mixed, E2 flipped: {_t_mix[0]} no flip: {_t_raw[0]}") +check(f"⭐ A MIXED ROSTER: only the listed entity is flipped, before the sum - " + f"{MIX_TOTAL:g} W, not any of {_MIX_WRONG}", + _t_mix[0] == MIX_TOTAL + and [w for _e, w, _y in _t_mix[2]] == [1200.0, 2100.0, -30.0]) +check("⭐ DEFAULT IS 0.12.0: with no flip `total()` answers exactly what it " + "always did - the raw sum, the same `why`, the same parts", + _t_raw == (-930.0, "3 entities", + [(E1, 1200.0, "W"), (E2, -2100.0, "kW"), (E3, -30.0, "W")])) +_t_zero = pv.total([(E2, state("0", "W"))], frozenset({E2})) +check("a flipped 0 W is +0.0, never -0.0 - so the wire says `0.0` and the page " + "says `0 W`, not `-0`", + _t_zero[0] == 0.0 and str(_t_zero[0]) == "0.0" + and f"{_t_zero[0]:.0f}" == "0") +_t_gone = pv.total([(E1, state("1200")), (E2, None)], frozenset({E2})) +check("a flipped member that is ABSENT is still an absence of the total - the " + "flip never turns None into a number", + _t_gone[0] is None and _at(_at(_t_gone[2], 1), 1) is None) +check("a single flipped entity keeps 0.11.0's pass-through `why` (the unit)", + pv.total([(E2, state("-13", "W"))], frozenset({E2})) + == (13.0, "W", [(E2, 13.0, "W")])) + +# --- the read path, the wire and the page ------------------------------------- +_c_mix, _, _p_mix = run(cycles=1, by_entity=MIX, **PV_FLIP) +_f_mix = _at(_p_mix.frames, -1) or {} +print(f" controller pv_w {_c_mix.pv_w} wire {pv_msg(_f_mix)}") +check("⭐ END TO END: the controller reads the option, and the MQTT `pv` row " + "carries the corrected site total", + _c_mix.pv_w == MIX_TOTAL + and pv_msg(_f_mix) == ("goodwe_ctl/pv", "3270.0", False)) +_mix_row = [r["text"] for r in _row(_c_mix, "W from 3 entities")] +print(f" {_mix_row}") +check("the status row prints each entity's watts AFTER the sign and marks " + "ONLY the flipped one", + _mix_row == [f"PV production: 3270 W from 3 entities ({E1} 1200 W in W, " + f"{E2} 2100 W in kW [sign inverted], {E3} -30 W in W)"]) +check("...and the page's PV row is the corrected total", + ("PV", "3 270 W") in page_rows(_c_mix)) +_c_hole_f, _, _ = run(cycles=1, by_entity=dict(MIX, **{E1: [None]}), **PV_FLIP) +check("a holed roster's 'Reporting:' list marks the flipped entity too", + [r["text"] for r in _row(_c_hole_f, "Reporting:")] + and f"{E2} 2100 W [sign inverted]" in + (_at(_row(_c_hole_f, "Reporting:"), 0) or {}).get("text", "")) + +# The owner's report, at a roster of one: a meter reading +13 W at night. +_OWN = "sensor.pv_meter_power" +_c_own, _, _ = run(cycles=1, by_entity={_OWN: [state("13", "W")]}, + pv_entity=_OWN, pv_invert_entities=[_OWN]) +_c_own0, _, _ = run(cycles=1, by_entity={_OWN: [state("13", "W")]}, + pv_entity=_OWN) +check("⭐ THE REPORTED CASE: 13 W of night-time standby on a reversed meter is " + "-13 W once flipped, the row says so and marks it - and it raises NO " + "negative caution, because -13 W is standby and not a reversed sign", + _c_own.pv_w == -13.0 + and [r["text"] for r in _row(_c_own, "PV production: -13 W")] + == [f"PV production: -13 W from {_OWN} (reported in W) [sign inverted]"] + and _row(_c_own, "probably reversed") == []) +check("...and WITHOUT the option it is 0.12.0's row, byte for byte", + [r["text"] for r in _row(_c_own0, "PV production:")] + == [f"PV production: 13 W from {_OWN} (reported in W)"]) + +# --- the negative caution ------------------------------------------------------- +def _neg(watts_by_entity, flip=()): + opts = dict(PV_MANY, pv_invert_entities=list(flip)) + c, _, _ = run(cycles=1, by_entity={e: [state(str(w), "W")] + for e, w in watts_by_entity.items()}, + **opts) + return _row(c, "probably reversed") + + +_n_add = _neg({E1: 1200, E2: -1500, E3: 450}) +_n_rm = _neg({E1: 1200, E2: 1500, E3: 450}, flip=[E2]) +print(f" {[r['text'] for r in _n_add + _n_rm]}") +check("⭐ AN UNFLIPPED ENTITY FAR BELOW ZERO gets a caution that names it, its " + "watts, and says to ADD it to `pv_invert_entities`", + [r["text"] for r in _n_add] + == [f"PV production: {E2} reads -1500 W - far below zero, so its sign " + "is probably reversed. If it is producing now, ADD it to " + "`pv_invert_entities` in the Configuration tab"]) +check("...and a FLIPPED one far below zero is told to REMOVE it instead", + len(_n_rm) == 1 and "REMOVE it from `pv_invert_entities`" + in (_at(_n_rm, 0) or {}).get("text", "")) +check("⭐ ...and it is a CAUTION, never a `bad` row - a telemetry sign cannot " + "put a battery site into NOT READY", + bool(_n_add) and all(r.get("ok") is False and r.get("warn") is True + for r in _n_add + _n_rm)) +check(f"the threshold is {pv.NEGATIVE_W:g} W per ENTITY: -50 W is standby and " + "stays quiet, -51 W cautions", + pv.NEGATIVE_W == -50.0 + and _neg({E1: -50, E2: 0, E3: 0}) == [] + and len(_neg({E1: -51, E2: 0, E3: 0})) == 1) +check("⭐ ...PER ENTITY, NOT ON THE TOTAL: three correctly signed meters at " + "-20 W standby each (total -60 W) raise nothing, and a reversed -1500 W " + "hidden in a positive total (+1650 W) is still caught", + _neg({E1: -20, E2: -20, E3: -20}) == [] + and len(_neg({E1: 2700, E2: -1500, E3: 450})) == 1) + +# --- the stray entry ------------------------------------------------------------ +_c_typo, _, _ = run(cycles=1, by_entity=FULL, + **dict(PV_MANY, pv_invert_entities=["sensor.pv_wset"])) +check("a `pv_invert_entities` entry naming no PV entity in use is a named " + "caution (a typo would otherwise leave the sign silently unflipped)", + [(r["text"], r.get("ok"), r.get("warn")) + for r in _row(_c_typo, "flips nothing")] + == [("PV production: `pv_invert_entities` names sensor.pv_wset, which " + "is not a PV entity in use, so it flips nothing - check the " + "spelling against `pv_entities`", False, True)] + and _row(_c_mix, "flips nothing") == []) + +# --- default: byte-identical to 0.12.0 ------------------------------------------ +_c_d0, _, _p_d0 = run(cycles=1, by_entity=MIX, **PV_MANY) +_c_d1, _, _p_d1 = run(cycles=1, by_entity=MIX, + **dict(PV_MANY, pv_invert_entities=[])) +check("⭐ DEFAULT: `pv_invert_entities: []` and a 0.12.0 blob with no such key " + "give the same rows, the same frame and the raw sum", + [r["text"] for r in _c_d0.checks()] == [r["text"] for r in _c_d1.checks()] + and _at(_p_d0.frames, -1) == _at(_p_d1.frames, -1) + and _c_d0.pv_w == -930.0) + +# --- still not a control input -------------------------------------------------- +_BIG_FLIP = {E1: [state("1500", "W")], E2: [state("-4.5", "kW")], + E3: [state("2000", "W")]} +_c_bf, _h_bf, _ = run(**_stim, by_entity=_BIG_FLIP, + **dict(PV_MANY, pv_invert_entities=[E2])) +check("⭐ NOT A CONTROL INPUT, WITH A FLIP: 40 cycles against the settled 600 W " + "import write exactly what `unset` writes, and the flip really did move " + "the reading (8000 W, part 6's shift precondition)", + _h_bf.writes == _w_none and _c_bf.target == _c_none.target + and _c_bf.pv_w == BIG_TOTAL) + + # ============================================================================== print() print("11. what this file CANNOT see, with sizes - and the mutation table") @@ -1028,10 +1218,9 @@ for line in [ " (mqtt/const.py PAYLOAD_NONE, mqtt/sensor.py's `_message_received`,", " retrieved 2026-09-24) and quoted in app/mqtt.py. No HA runs in this", " suite, so what is graded here is the BYTES this add-on publishes.", - "Whether the operator's PV sensor is telling the truth. A sensor wired", - " backwards reads -4 kW at noon; this file asserts that the sign is", - " published unchanged, never that it is right. That is what the history", - " the card creates is FOR - see DECISIONS/TEL-11-pv-production.md §2.", + "Whether the operator's PV sensor is telling the truth. TEL-14 lets the", + " installer declare a reversed one; this file grades the flip and the", + " -50 W caution, never that the declaration is right.", "The control-path claim OUTSIDE app/. `tools/`, the ESPHome firmware and", " the ingress page are not scanned by part 6's census.", "A roster of more than one INVERTER (CFG-04's battery kind). Every", @@ -1138,6 +1327,28 @@ print(" time - see DECISIONS/TEL-11-pv-production.md §5 for the transcript." print(" ⚠️ A RED COUNT IS A PROPERTY OF THE SUITE AS MUCH AS OF THE MUTATION:") print(" these name THIS tree. Re-measure rather than inherit.") +# --- TEL-14's battery: fresh copy each, no __pycache__, CI image, :ro, -------- +# --network none. Every red is a NAMED check in part 12; no traceback. +print() +print(" TEL-14 mutation bytes reds") +print(" ------------------------------------------------ ----- --------") +for row in [ + ("T1 the flip ignored in total()", "-45 B", "9 here"), + ("T2 the flip applied to EVERY member", "-7 B", "6 here"), + ("T3 `0.0 - w` -> `-w` (a -0.0 leaks)", "-5 B", "1 here"), + ("T4 the flip written as abs()", "-1 B", "2 here"), + ("T5 _read_pv() stops passing the flip", "-26 B", "7 here"), + ("T6 caution threshold -50 W -> 0 W", "-17 B", "3 here"), + ("T7 the [sign inverted] marker dropped", "-39 B", "3 here"), + ("T8 the negative caution made `bad`", "+1 B", "1 here"), + ("T9 stray_inverts() always empty", "-50 B", "1 here"), + ("T10 inverted() stops stripping", "-8 B", "1 here"), + ("T11 ADD/REMOVE advice swapped", "+4 B", "2 here"), + ("T12 `pv_invert_entities: []` deleted from options:", "-25 B", + "2 test_translations + 17 probe"), +]: + print(f" {row[0]:<48} {row[1]:>5} {row[2]}") + print() if fails: print(f"{len(fails)} FAILED:") diff --git a/goodwe_controller/tools/supervisor_shape_probe.py b/goodwe_controller/tools/supervisor_shape_probe.py index 90e8e01..702dc73 100644 --- a/goodwe_controller/tools/supervisor_shape_probe.py +++ b/goodwe_controller/tools/supervisor_shape_probe.py @@ -683,6 +683,72 @@ except vol.Invalid as e: str(e)) +print("\n== H. TEL-14: the SHAPE of a per-entity PV sign option ==") +# Four candidate shapes, each against a 0.12.0 blob (`pv_entities` set, no new +# key). Transcript and decision: DECISIONS/TEL-14-pv-sign.md. +PV12 = {"pv_entity": "", "pv_entities": ["sensor.pv_inverter", "sensor.pv_meter"]} +_pv12 = MERGER.merge(copy.deepcopy(defaults), copy.deepcopy(PV12)) +_nk = "pv_invert_entities" + + +def _ui_of(sch, name): + return [e for e in UiOptions(None)(sch) if e.get("name") == name] + + +# (a) a `-` prefix on a list item, under the shipped `- str`. +ok_a, out_a = validate(dict(_pv12, pv_entities=["sensor.pv_inverter", + "-sensor.pv_meter"])) +show("(a) PREFIX: `-sensor.pv_meter` validates under the shipped `- str` - " + "Supervisor does not look inside the string, so the sign would live in a " + "syntax that only the description text explains", + ok_a and out_a.get("pv_entities") == ["sensor.pv_inverter", + "-sensor.pv_meter"], + "" if ok_a else out_a) + +# (b) a parallel list - THE SHIPPED SHAPE. +ok_b, out_b = validate(_pv12) +show("(b) ⭐ PARALLEL LIST, SHIPPED: the 0.12.0 blob (no `pv_invert_entities` " + "key) validates unchanged and the new key defaults to []", + ok_b and out_b.get(_nk) == [] + and out_b.get("pv_entities") == PV12["pv_entities"], + "" if ok_b else out_b) +ok_b2, out_b2 = validate(dict(_pv12, **{_nk: ["sensor.pv_meter"]})) +show("...and one entity marked inverted validates", + ok_b2 and out_b2.get(_nk) == ["sensor.pv_meter"], "" if ok_b2 else out_b2) +ok_b3, out_b3 = validate({k: v for k, v in defaults.items() if k != _nk}) +show("⭐ ...and the shipped `options:` block with ONLY `pv_invert_entities` " + "removed is REFUSED BY NAME - its `[]` default is load-bearing, as " + "`pv_entities: []` is", + (not ok_b3) and f"Missing option '{_nk}' in root" in str(out_b3), out_b3) +_ui_b = _ui_of(schema, _nk) +show("...and the Configuration tab renders it as a REPEATABLE string field " + "with its own top-level (translated) label", + len(_ui_b) == 1 and _ui_b[0].get("multiple") is True + and _ui_b[0].get("type") == "string", json.dumps(_ui_b)) + +# (c) a list of dicts - on `pv_entities` itself, and as a new key. +_s_dicts = dict(schema, pv_entities=[{"entity": "str", "invert": "bool?"}]) +ok_c, out_c = validate_with(_s_dicts, _pv12) +show("(c) LIST OF DICTS ON `pv_entities`: the STRINGS a 0.12.0 install stored " + "are REFUSED - that shape would stop the add-on starting on upgrade", + (not ok_c) and "pv_entities" in str(out_c), out_c) +_s_src = dict(schema, pv_sources=[{"entity": "str", "invert": "bool?"}]) +ok_c2, out_c2 = validate_with(_s_src, dict(_pv12, pv_sources=[])) +_ui_c = _ui_of(_s_src, "pv_sources") +show("(c2) ...as a THIRD key it validates, but renders as a type-schema " + "repeatable section whose per-entry keys reach the screen RAW " + "(`entity`, `invert`) on this frontend - see section F", + ok_c2 and len(_ui_c) == 1 and _ui_c[0].get("type") == "schema" + and _ui_c[0].get("multiple") is True, + json.dumps(_ui_c)[:200] if ok_c2 else out_c2) + +# (d) one global bool. +_s_bool = dict(schema, pv_invert="bool") +ok_d, out_d = validate_with(_s_bool, dict(_pv12, pv_invert=False)) +show("(d) GLOBAL `pv_invert: bool` validates too - it loses on SEMANTICS (one " + "sign for a mixed roster), not on the schema", ok_d, "" if ok_d else out_d) + + # ⚠️ THE EXIT CODE IS PART OF THE INSTRUMENT. Without it the probe prints FAIL # and still succeeds, and a transcript is only evidence if a wrong answer is # distinguishable from a right one by something other than reading it. diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index 1a03e6c..658fb3b 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -86,10 +86,13 @@ configuration: description: "Whether the RS485 emergency stop is physically installed. It only drives the warning banner on the status page; it changes no control behaviour." pv_entity: name: "Hardware · PV production entity (W)" - description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Point it at your solar inverter's own power sensor (any brand Home Assistant reads; it does not have to be on the RS485 bus) and the add-on records production beside the grid and battery figures, so a day of unstored surplus can be told apart from a day with no sun. POSITIVE MUST MEAN PRODUCING. The unit is read from the entity itself - W, kW and the rest of Home Assistant's power units - so a sensor with no unit is refused rather than guessed at, and the status page says so. Leave it empty and nothing is read, nothing is published and nothing is shown." + description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Point it at your solar inverter's own power sensor (any brand Home Assistant reads; it does not have to be on the RS485 bus) and the add-on records production beside the grid and battery figures, so a day of unstored surplus can be told apart from a day with no sun. POSITIVE MUST MEAN PRODUCING - if yours reads negative while producing, list it under 'sign is reversed' below. The unit is read from the entity itself - W, kW and the rest of Home Assistant's power units - so a sensor with no unit is refused rather than guessed at, and the status page says so. Leave it empty and nothing is read, nothing is published and nothing is shown." pv_entities: name: "Hardware · PV production entities, one per inverter (W)" description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Use this instead of the single entity above when your roof has SEVERAL solar inverters: add one row per inverter, pointing at each one's own power sensor, and the add-on records the SITE total. Each entity's own unit is read, so a kW inverter beside a W one adds up correctly. ⚠️ SETTING THIS IGNORES THE SINGLE ENTITY ABOVE - clear that one when you fill this in, or you will see a caution on the status page saying so. ⚠️ AND IF ANY ONE OF THESE STOPS REPORTING THERE IS NO SITE TOTAL: the sensor goes to 'unknown' and the history records a gap, rather than publishing the sum of the ones that did answer. Two inverters out of three add up to a smaller number that looks exactly like a real one, and a week later that reads as 'there was less sun than there was' - which is the one conclusion this recording exists to test. The status page names which entity is missing, why, and what the others reported. Leave it empty and nothing is read, nothing is published and nothing is shown." + pv_invert_entities: + name: "Hardware · PV entities whose sign is reversed" + description: "Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a power clamp in the PV circuit - read NEGATIVE while producing and a few watts POSITIVE at night. Add each such entity here, spelled exactly as it is above, and its sign is flipped before it is added up; leave the others out. The status page marks every flipped entity. History recorded before you set this keeps the old sign." meter_source: name: "Meter · Where the meter reading comes from" description: "'off' keeps the single Home Assistant entity below, which is what an existing installation runs on until you choose otherwise. ha_dsmr subscribes to the DSMR integration; mqtt_p1 reads an MQTT topic; ha_signed reads one signed entity, which is what a HomeWizard P1 publishes; homewizard_local polls the meter's own local API and skips Home Assistant entirely. ⚠️ Only homewizard_local can tell 'the meter has not answered' apart from 'the value has not changed', so it is the only source on which the frozen-meter alarm means anything." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index 50fc5d4..d1424af 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -66,10 +66,13 @@ configuration: description: "Of de RS485-noodstop fysiek geïnstalleerd is. Dit stuurt alleen de waarschuwingsbalk op de statuspagina aan en verandert niets aan de regeling." pv_entity: name: "Hardware · Zonneproductie-entiteit (W)" - description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Verwijs naar de vermogenssensor van je omvormer (elk merk dat Home Assistant kan lezen; hij hoeft niet op de RS485-bus te zitten) en de add-on registreert de productie naast de meter- en batterijwaarden, zodat een dag met niet-opgeslagen overschot te onderscheiden is van een dag zonder zon. POSITIEF MOET PRODUCEREN BETEKENEN. De eenheid wordt van de entiteit zelf gelezen - W, kW en de overige vermogenseenheden van Home Assistant - dus een sensor zonder eenheid wordt geweigerd in plaats van geraden, en de statuspagina zegt waarom. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." + description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Verwijs naar de vermogenssensor van je omvormer (elk merk dat Home Assistant kan lezen; hij hoeft niet op de RS485-bus te zitten) en de add-on registreert de productie naast de meter- en batterijwaarden, zodat een dag met niet-opgeslagen overschot te onderscheiden is van een dag zonder zon. POSITIEF MOET PRODUCEREN BETEKENEN - leest de uwe negatief tijdens productie, zet hem dan ook bij 'teken omgekeerd' hieronder. De eenheid wordt van de entiteit zelf gelezen - W, kW en de overige vermogenseenheden van Home Assistant - dus een sensor zonder eenheid wordt geweigerd in plaats van geraden, en de statuspagina zegt waarom. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." pv_entities: name: "Hardware · Zonneproductie-entiteiten, één per omvormer (W)" description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Gebruik dit in plaats van de losse entiteit hierboven wanneer uw dak MEERDERE zonne-omvormers heeft: voeg één rij per omvormer toe, elk verwijzend naar haar eigen vermogenssensor, en de add-on registreert het totaal van de installatie. De eenheid van elke entiteit wordt afzonderlijk gelezen, dus een omvormer in kW naast een in W telt correct op. ⚠️ ALS U DIT INVULT WORDT DE LOSSE ENTITEIT HIERBOVEN GENEGEERD - maak die leeg, anders verschijnt er een waarschuwing op de statuspagina die dat meldt. ⚠️ EN ALS ÉÉN VAN DEZE ENTITEITEN NIETS MEER DOORGEEFT, IS ER GEEN TOTAAL: de sensor gaat naar 'unknown' en de geschiedenis bewaart een gat, in plaats van de som van de entiteiten die wél antwoordden te publiceren. Twee omvormers van de drie tellen op tot een kleiner getal dat precies op een echt getal lijkt, en een week later leest dat als 'er was minder zon dan er was' - net de conclusie die deze registratie moet kunnen testen. De statuspagina noemt welke entiteit ontbreekt, waarom, en wat de andere doorgaven. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." + pv_invert_entities: + name: "Hardware · Zonneproductie-entiteiten met omgekeerd teken" + description: "Optioneel, UITSLUITEND EEN METING. Sommige sensoren - meestal een kWh-meter of een stroomtang in het PV-circuit - lezen NEGATIEF tijdens productie en 's nachts enkele watt POSITIEF. Zet elke zulke entiteit hier, exact gespeld zoals hierboven, en haar teken wordt omgedraaid vóór het optellen; laat de andere weg. De statuspagina markeert elke omgedraaide entiteit. Geschiedenis van vóór deze instelling behoudt het oude teken." meter_source: name: "Meter · Waar de meterstand vandaan komt" description: "'off' houdt de losse Home Assistant-entiteit hieronder aan, waar een bestaande installatie op draait tot u iets anders kiest. ha_dsmr luistert mee met de DSMR-integratie; mqtt_p1 leest een MQTT-topic; ha_signed leest één entiteit met teken, wat een HomeWizard P1 publiceert; homewizard_local bevraagt de lokale API van de meter zelf en slaat Home Assistant helemaal over. ⚠️ Alleen homewizard_local kan 'de meter heeft niet geantwoord' onderscheiden van 'de waarde is niet veranderd', en is dus de enige bron waarop het alarm voor een vastgelopen meter iets betekent." -- 2.54.0 From 6dbe06e32e21d55e7715c0cb5b65ea350a928195 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 00:30:44 +0200 Subject: [PATCH 008/105] DOC-5: add the Watchdog step to README's Install section One line after the install step, linking to the DOCS.md paragraph that gives the reason. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 037f702..c341fb3 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,9 @@ https://gittea.kammenstraatha.duckdns.org/admin/goodwe-addon then install **GoodWe RS485 Controller**. +Then turn on **Watchdog** on the add-on's Info tab — see +[Before you start](goodwe_controller/DOCS.md#before-you-start). + ⚠️ **The repository must be PUBLIC for this to work.** Home Assistant clones it anonymously; against a private repo the store shows nothing and gives no useful error. If it must stay private, install locally instead: copy -- 2.54.0 From 93f349a6aff6dbab74ad9c222b71df1eeb37783e Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 25 Sep 2026 01:10:13 +0200 Subject: [PATCH 009/105] TEL-14 B1: pin stray caution on the reported case and whitespace normalisation end to end Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- goodwe_controller/test_pv.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 1c3b9fa..71385bc 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -1127,15 +1127,31 @@ _c_own0, _, _ = run(cycles=1, by_entity={_OWN: [state("13", "W")]}, pv_entity=_OWN) check("⭐ THE REPORTED CASE: 13 W of night-time standby on a reversed meter is " "-13 W once flipped, the row says so and marks it - and it raises NO " - "negative caution, because -13 W is standby and not a reversed sign", + "negative caution, because -13 W is standby and not a reversed sign - " + "and NO stray caution, because a lone `pv_entity` is in the roster", _c_own.pv_w == -13.0 and [r["text"] for r in _row(_c_own, "PV production: -13 W")] == [f"PV production: -13 W from {_OWN} (reported in W) [sign inverted]"] - and _row(_c_own, "probably reversed") == []) + and _row(_c_own, "probably reversed") == [] + and _row(_c_own, "flips nothing") == []) check("...and WITHOUT the option it is 0.12.0's row, byte for byte", [r["text"] for r in _row(_c_own0, "PV production:")] == [f"PV production: 13 W from {_OWN} (reported in W)"]) +# Whitespace: the roster entry and the invert entry differ only by padding. Both +# sides must normalise the same way, or the read path leaves the sign unflipped +# while the page marks it, or the page calls a flipped entity a stray. +_c_pad, _, _ = run(cycles=1, by_entity=MIX, + pv_entities=[E1, f" {E2}", E3], + pv_invert_entities=[f"{E2} "]) +check("⭐ PADDING: ` sensor.x` in the roster and `sensor.x ` in " + "`pv_invert_entities` are the same entity - flipped on the read path, " + "marked on the page, and no stray caution", + _c_pad.pv_w == MIX_TOTAL + and f"{E2} 2100 W in kW [sign inverted]" + in (_at(_row(_c_pad, "W from 3 entities"), 0) or {}).get("text", "") + and _row(_c_pad, "flips nothing") == []) + # --- the negative caution ------------------------------------------------------- def _neg(watts_by_entity, flip=()): opts = dict(PV_MANY, pv_invert_entities=list(flip)) -- 2.54.0 From 7fa045af85aedb3616ff7f5e9f28074522209968 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 25 Sep 2026 01:11:40 +0200 Subject: [PATCH 010/105] =?UTF-8?q?TEL-14=20N1:=20trim=20DECISIONS=20(drop?= =?UTF-8?q?=20probe=20transcript,=20=C2=A71=20to=20the=20reason),=20move?= =?UTF-8?q?=20the=20mutation=20ledger=20there=20with=20M2/M5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_pv.py part 11 now prints a one-line pointer instead of the 12-row table. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU --- goodwe_controller/DECISIONS/TEL-14-pv-sign.md | 72 +++++++++---------- goodwe_controller/test_pv.py | 22 +----- 2 files changed, 37 insertions(+), 57 deletions(-) diff --git a/goodwe_controller/DECISIONS/TEL-14-pv-sign.md b/goodwe_controller/DECISIONS/TEL-14-pv-sign.md index d9a9b81..8325099 100644 --- a/goodwe_controller/DECISIONS/TEL-14-pv-sign.md +++ b/goodwe_controller/DECISIONS/TEL-14-pv-sign.md @@ -7,49 +7,24 @@ Owner report on 0.12.0: `sensor.espressif_vermogen` (ESPHome clamp) and ## 1. This reverses TEL-11 §2, and why -TEL-11 §2 refused a `pv_invert` because (1) PV is read by nothing in the control -path, and (2) a reversed sensor "announces itself as −4 kW at noon" and should be -"fixed where it is produced". (1) still holds: the flip is applied inside -`pv.total()`, which only feeds the MQTT `pv` row and the status page; -`test_pv.py` part 12 re-runs part 6's 40-cycle identity with a flip set, and -`tools/tel11_pv_trace.py` on release/1.0 vs this tree gives identical `control` -documents for `unset`, `one` and `multi`; the only telemetry change is the new -caution in the `negative` (−4200 W) cells. Its `--compare` verdict itself now -REFUSES on any honest run, because both trees know `pv_entities` — TEL-12 §3's -discriminator has aged out, as TEL-11's did; not fixed here. (2) did -not survive contact with a real site: these sensors are not *wrong*, they -follow a different convention; at night they read a plausible small positive -number, so nothing announces anything; and "fix it where it is produced" means a -template sensor, which TEL-12 §2 already names as the place an `unavailable` -source goes quietly wrong. +TEL-11 §2 refused a `pv_invert` on two grounds. "PV is read by nothing in the +control path" still holds: the flip lives in `pv.total()`, and `test_pv.py` +part 12 re-runs part 6's 40-cycle identity with a flip set. "A reversed sensor +announces itself" did not survive a real site: these sensors follow a different +convention, read a plausible small positive number at night, and the only other +fix is a template sensor, the place TEL-12 §2 says goes quietly wrong. -## 2. The shape: a parallel list, `pv_invert_entities` — measured +## 2. The shape: a parallel list, `pv_invert_entities` -`tools/supervisor_shape_probe.py` §H, Supervisor 2026.08.0, against a 0.12.0 -blob (`pv_entities` set, no new key): - -``` -== H. TEL-14: the SHAPE of a per-entity PV sign option == - PASS (a) PREFIX: `-sensor.pv_meter` validates under the shipped `- str` - Supervisor does not look inside the string, ... - PASS (b) ⭐ PARALLEL LIST, SHIPPED: the 0.12.0 blob (no `pv_invert_entities` key) validates unchanged and the new key defaults to [] - PASS ...and one entity marked inverted validates - PASS ⭐ ...and the shipped `options:` block with ONLY `pv_invert_entities` removed is REFUSED BY NAME ... - Missing option 'pv_invert_entities' in root in GoodWe RS485 Controller (local_goodwe_controller) - PASS ...and the Configuration tab renders it as a REPEATABLE string field with its own top-level (translated) label - [{"name": "pv_invert_entities", "multiple": true, "required": true, "type": "string"}] - PASS (c) LIST OF DICTS ON `pv_entities`: the STRINGS a 0.12.0 install stored are REFUSED ... - Invalid dict for option 'pv_entities' in GoodWe RS485 Controller (local_goodwe_controller) - PASS (c2) ...as a THIRD key it validates, but renders as a type-schema repeatable section whose per-entry keys reach the screen RAW ... - PASS (d) GLOBAL `pv_invert: bool` validates too - it loses on SEMANTICS (one sign for a mixed roster), not on the schema -== all cases passed == -``` +Measured by `tools/supervisor_shape_probe.py` §H (Supervisor 2026.08.0, against +a 0.12.0 blob); re-run it for the transcript. | shape | schema | why it lost / won | |---|---|---| | (a) `-sensor.x` prefix | accepted | invisible: the sign is a syntax only the description explains, in a field an installer fills with the entity picker's text | | (b) parallel list | accepted, 0.12.0 blob unchanged | **ships**: its own labelled, translated field ("PV entities whose sign is reversed"); an installer lists the odd ones out | | (c) dicts on `pv_entities` | **refuses 0.12.0's stored strings** | bricks the upgrade — TEL-12's trap again | -| (c2) dicts as a third key | accepted | per-entry labels render raw (`entity`, `invert`) — §F; and a third PV surface | +| (c2) dicts as a third key | accepted | per-entry labels render raw (`entity`, `invert`) — probe §F; and a third PV surface | | (d) global bool | accepted | one sign cannot describe inverter + meter in one roster | (b)'s known cost is a typo in the second list: `pv.stray_inverts()` turns it into @@ -67,12 +42,35 @@ three correct meters at −20 W sum to −60 W and must stay quiet, while a reve a wrong threshold costs a spurious or missed caution, never data. The text says ADD (unflipped) or REMOVE (already flipped). -## 4. History +## 4. Mutations + +Fresh `cp -a` each, `__pycache__` purged, CI image, `:ro`, `--network none`; +`test_pv.py` only unless stated. T1-T12 at 7559d21; M2/M5 are review #1628's, +red since B1 (merged into release/1.0 @ 43b2740). + +| # | mutation | bytes | reds | +|---|---|---|---| +| T1 | flip ignored in `total()` | −45 | 9 | +| T2 | flip applied to every member | −7 | 6 | +| T3 | `0.0 - w` → `-w` | −5 | 1 | +| T4 | flip written as `abs()` | −1 | 2 | +| T5 | `_read_pv()` stops passing the flip | −26 | 7 | +| T6 | caution threshold −50 → 0 W | −17 | 3 | +| T7 | `[sign inverted]` marker dropped | −39 | 3 | +| T8 | negative caution made `bad` | +1 | 1 | +| T9 | `stray_inverts()` always empty | −50 | 1 | +| T10 | `inverted()` stops stripping | −8 | 1 | +| T11 | ADD/REMOVE advice swapped | +4 | 2 | +| T12 | `pv_invert_entities: []` deleted from `options:` | −25 | 2 test_translations + 17 probe | +| M2 | `stray_inverts()` roster ignores `pv_entity` | +15 | 2 (REPORTED CASE, PADDING) | +| M5 | `_read_pv()` flip set not stripped | +25 | 1 (PADDING) | + +## 5. History OPT-10's `sensor.goodwe_pv_power` recorded since 2026-09-24 on an install with such sensors carries the old sign; nothing rewrites it. -## 5. CHANGELOG entry for the next PKG cut +## 6. CHANGELOG entry for the next PKG cut Not written into `CHANGELOG.md`: `test_version_gate.py` 11b/11d refuse an `## Unreleased` heading (measured on this branch: 4 reds). For PKG to paste: diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 71385bc..59408ec 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -1343,27 +1343,9 @@ print(" time - see DECISIONS/TEL-11-pv-production.md §5 for the transcript." print(" ⚠️ A RED COUNT IS A PROPERTY OF THE SUITE AS MUCH AS OF THE MUTATION:") print(" these name THIS tree. Re-measure rather than inherit.") -# --- TEL-14's battery: fresh copy each, no __pycache__, CI image, :ro, -------- -# --network none. Every red is a NAMED check in part 12; no traceback. print() -print(" TEL-14 mutation bytes reds") -print(" ------------------------------------------------ ----- --------") -for row in [ - ("T1 the flip ignored in total()", "-45 B", "9 here"), - ("T2 the flip applied to EVERY member", "-7 B", "6 here"), - ("T3 `0.0 - w` -> `-w` (a -0.0 leaks)", "-5 B", "1 here"), - ("T4 the flip written as abs()", "-1 B", "2 here"), - ("T5 _read_pv() stops passing the flip", "-26 B", "7 here"), - ("T6 caution threshold -50 W -> 0 W", "-17 B", "3 here"), - ("T7 the [sign inverted] marker dropped", "-39 B", "3 here"), - ("T8 the negative caution made `bad`", "+1 B", "1 here"), - ("T9 stray_inverts() always empty", "-50 B", "1 here"), - ("T10 inverted() stops stripping", "-8 B", "1 here"), - ("T11 ADD/REMOVE advice swapped", "+4 B", "2 here"), - ("T12 `pv_invert_entities: []` deleted from options:", "-25 B", - "2 test_translations + 17 probe"), -]: - print(f" {row[0]:<48} {row[1]:>5} {row[2]}") +print(" TEL-14: 14 mutations, all red, no survivors - bytes and named reds in") +print(" DECISIONS/TEL-14-pv-sign.md §4.") print() if fails: -- 2.54.0 From 6e3399322ac1f41a7942821e04b056eb908eeb9d Mon Sep 17 00:00:00 2001 From: CI-12 dev agent <1+admin@noreply.localhost> Date: Fri, 25 Sep 2026 01:57:04 +0200 Subject: [PATCH 011/105] CI-12: CI grades test_freeze.py against the real hwsim at a pinned admin/goodwe - .gitea/infra-pin: the one place the admin/goodwe commit is pinned. - checks.yml: checks out admin/goodwe at the pin as the sibling test_freeze.py looks for; any failure fails the job. Tests run with GOODWE_REQUIRE_HWSIM=1, and `CI: ` lines are echoed on PASS so the log shows which transport ran. - test_freeze.py: GOODWE_REQUIRE_HWSIM refuses the stub; a local stub run prints a STUB USED line. - infra-pin.yml: a separate, non-required check that goes red naming both SHAs when admin/goodwe master has moved past the pin. - README: when and how to bump the pin. Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 ++ .gitea/workflows/checks.yml | 36 +++++++++++++++++++++--------- .gitea/workflows/infra-pin.yml | 38 ++++++++++++++++++++++++++++++++ README.md | 5 +++++ goodwe_controller/test_freeze.py | 15 +++++++++++-- 5 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 .gitea/infra-pin create mode 100644 .gitea/workflows/infra-pin.yml diff --git a/.gitea/infra-pin b/.gitea/infra-pin new file mode 100644 index 0000000..97dc92a --- /dev/null +++ b/.gitea/infra-pin @@ -0,0 +1,2 @@ +# The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe master HEAD (README.md, "CI and the infra pin"). +a783602ea131d49bc0c904333c1ccb101aac02d0 diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index 44709c0..56427fd 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -488,6 +488,26 @@ jobs: fi echo "OK: the \`on:\` block of the merged checks.yml carries no event filter." + # CI-12: the infra repo at the ONE pinned commit in .gitea/infra-pin (read + # from the merged tree), as the sibling test_freeze.py looks for. Any + # failure here fails the job; the tests step below refuses the stub. + - name: check out admin/goodwe at the pin in .gitea/infra-pin + env: + URL: ${{ github.server_url }}/admin/goodwe.git + TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eu + PIN=$(grep -v '^#' "$WS/goodwe-addon/.gitea/infra-pin" | tr -d '[:space:]') + echo "$PIN" | grep -Eq '^[0-9a-f]{40}$' || { echo "FAIL: .gitea/infra-pin holds '$PIN', not a full 40-hex SHA."; exit 1; } + rm -rf "$WS/goodwe" && mkdir -p "$WS/goodwe" && cd "$WS/goodwe" + git init -q . + git remote add origin "$(echo "$URL" | sed "s#://#://x-access-token:${TOKEN}@#")" + git fetch -q origin "$PIN" || { echo "FAIL: could not fetch admin/goodwe at $PIN."; exit 1; } + git -c advice.detachedHead=false checkout -qf FETCH_HEAD + test "$(git rev-parse HEAD)" = "$PIN" + test -f sim/hwsim.py || { echo "FAIL: admin/goodwe@$PIN has no sim/hwsim.py."; exit 1; } + echo "infra: admin/goodwe @ $(git log --oneline -1)" + - name: build the test image (shipped deps, from apk - see .gitea/ci/Dockerfile) run: | set -eu @@ -508,16 +528,9 @@ jobs: # shorter timeout - a 60 s limit was tried during CI-01 and reported # exactly the false hang the docstring predicts. # - # ⚠️ WHAT THIS RUN DOES NOT COVER, stated because a pass here would - # otherwise over-claim. test_freeze.py's third section wants the infra - # repo's `sim/hwsim.py` to drive a real HTTP meter through the real - # transport. admin/goodwe is PRIVATE (checked via the API) and this - # workflow's GITHUB_TOKEN is minted for THIS repository only, so hwsim is - # absent here and `find_hwsim()` returns None. The rest of the file runs - # and passes. It does so SILENTLY - the file prints nothing to say the - # hwsim section was skipped - so "test_freeze.py: PASS" below is a weaker - # claim than it looks. That belongs to whoever owns test_freeze.py next; - # naming it here is the least this gate can do about it. + # test_freeze.py part 3 runs against the real `sim/hwsim.py` from the + # checkout above; GOODWE_REQUIRE_HWSIM=1 makes it fail rather than use its + # stub (CI-12). Lines a test prints with a `CI: ` prefix are echoed on PASS. # ⚠️ PYTHONDONTWRITEBYTECODE=1 IS BELT AND BRACES, NOT A FIX FOR A LIVE # HOLE. TEST-15 measured this runner's actual exposure and found none: the # checkout below is bind mounted `:ro`, so the interpreter physically @@ -533,7 +546,7 @@ jobs: - name: the add-on's own tests run: | set -eu - docker run --rm -e PYTHONDONTWRITEBYTECODE=1 -v "$WS:/w:ro" goodwe-addon-checks:1 sh -eu -c ' + docker run --rm -e PYTHONDONTWRITEBYTECODE=1 -e GOODWE_REQUIRE_HWSIM=1 -v "$WS:/w:ro" goodwe-addon-checks:1 sh -eu -c ' cd /w/goodwe-addon/goodwe_controller set -- test_*.py if [ "$1" = "test_*.py" ]; then @@ -546,6 +559,7 @@ jobs: start=$(date +%s) if python3 "$f" > /tmp/out 2>&1; then echo "PASS $f ($(( $(date +%s) - start ))s)" + grep "^CI: " /tmp/out || true else echo "FAIL $f ($(( $(date +%s) - start ))s)" tail -40 /tmp/out diff --git a/.gitea/workflows/infra-pin.yml b/.gitea/workflows/infra-pin.yml new file mode 100644 index 0000000..5d4e4e9 --- /dev/null +++ b/.gitea/workflows/infra-pin.yml @@ -0,0 +1,38 @@ +# CI-12: goes red when admin/goodwe master has moved past .gitea/infra-pin, so +# the pin cannot go stale silently. Deliberately NOT a required check: it +# reports; `checks / unit` stays the only gate. How to bump: README.md, +# "CI and the infra pin". +name: infra-pin + +on: + pull_request: + push: + branches: [release/1.0] + +jobs: + fresh: + runs-on: [self-hosted, goodwe-rig] + timeout-minutes: 30 # seconds of work; the rest is queueing for the shared slot + steps: + - name: compare .gitea/infra-pin with admin/goodwe master + env: + SELF: ${{ github.server_url }}/${{ github.repository }}.git + INFRA: ${{ github.server_url }}/admin/goodwe.git + TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -eu + auth() { echo "$1" | sed "s#://#://x-access-token:${TOKEN}@#"; } + D=$(mktemp -d) && cd "$D" + git init -q . && git remote add origin "$(auth "$SELF")" + # The pin of the commit this event is about (the PR head, or the push). + git fetch -q --depth 1 origin "$GITHUB_SHA" + PIN=$(git show FETCH_HEAD:.gitea/infra-pin | grep -v '^#' | tr -d '[:space:]') + HEAD=$(git ls-remote "$(auth "$INFRA")" refs/heads/master | cut -f1) + cd / && rm -rf "$D" + test -n "$HEAD" || { echo "FAIL: could not read admin/goodwe master."; exit 1; } + if [ "$PIN" != "$HEAD" ]; then + echo "STALE: .gitea/infra-pin is $PIN but admin/goodwe master is $HEAD." + echo " Test against $HEAD and bump the pin (README.md, \"CI and the infra pin\")." + exit 1 + fi + echo "OK: .gitea/infra-pin $PIN is admin/goodwe master HEAD." diff --git a/README.md b/README.md index c341fb3..d2a9799 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,11 @@ has the mechanism, the measurement, and what the flags do not do. They are not u each assertion corresponds to a rule whose absence produced an observed failure on real hardware, and the comments in `control.py` say which. +### CI and the infra pin + +CI (`.gitea/workflows/checks.yml`) runs every `test_*.py`, with `admin/goodwe` checked out next to this repo at the commit in `.gitea/infra-pin`, so `test_freeze.py` grades against the real `sim/hwsim.py`. If that checkout fails, the job fails. The local stub is used only in local runs, and it prints `STUB USED` when it is. +**Bump the pin** whenever `infra-pin / fresh` is red, which happens once `admin/goodwe` master has moved past the pin. Set `.gitea/infra-pin` to the new master SHA (`git ls-remote /admin/goodwe.git refs/heads/master`) in a PR, and let `checks / unit` grade the tests against it. + ## Compatibility **Check the serial number, not the model name.** Characters 6-8 of the serial are diff --git a/goodwe_controller/test_freeze.py b/goodwe_controller/test_freeze.py index 63f30e3..a5e0f00 100644 --- a/goodwe_controller/test_freeze.py +++ b/goodwe_controller/test_freeze.py @@ -19,7 +19,8 @@ shipped `meter_freeze_s` itself: a check that calls the predicate directly would not be testing the thing that ships. Uses the rig's own `sim/hwsim.py --fault freeze` when the infra repo is next to this one (or `$GOODWE_SIM`), and an equivalent local stub - otherwise. Both are exercised; the run says which one it used. + otherwise. Both are exercised; the run says which one it used. CI sets + `GOODWE_REQUIRE_HWSIM=1`, which refuses the stub (CI-12). 4. THE WIRING: the real `Controller.cycle()`, asserted on the service call that leaves the process; @@ -600,6 +601,15 @@ hw = find_hwsim() # that cannot fail, from the other end. PART3_TRANSPORT = f"the rig hwsim at {hw}" if hw else "the local stub" print(f"frozen meter over HTTP - using {PART3_TRANSPORT}") +# CI-12: CI sets GOODWE_REQUIRE_HWSIM=1, so a missing infra checkout fails here +# instead of passing on the stub. Local runs may still use the stub, and say so. +if not hw: + if os.environ.get("GOODWE_REQUIRE_HWSIM"): + print("FAIL: GOODWE_REQUIRE_HWSIM is set but sim/hwsim.py was not found " + "(sibling ../goodwe or $GOODWE_SIM) - refusing to fall back to the stub") + sys.exit(1) + print("STUB USED: part 3 ran against the local stub, NOT the infra repo's " + "sim/hwsim.py - not a CI-grade result") if hw: def argv_for(mode): return [HWSIM_DRIVER, "8791" if mode == "freeze" else "8792", mode, @@ -1263,7 +1273,8 @@ check("a Controller built with the key absent lands on the SHIPPED hold, so " _ctl_c.freeze_wd.cfg.hold_s == SHIPPED_HOLD_S) print() -print(f"part 3 (the live HTTP transport) ran against: {PART3_TRANSPORT}") +# `CI: ` lines are echoed into the CI log even on a pass (checks.yml). +print(f"CI: test_freeze part 3 (the live HTTP transport) ran against: {PART3_TRANSPORT}") if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") sys.exit(1) -- 2.54.0 From fe8004723584edd15e05e76ba8549172ab2e3470 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 16:08:55 +0200 Subject: [PATCH 012/105] CI-12 round 2: INFRA_READ_TOKEN for admin/goodwe; the pin tracks release/1.0 - checks.yml's infra checkout and infra-pin.yml's admin/goodwe ls-remote use the INFRA_READ_TOKEN secret; the self fetch keeps GITHUB_TOKEN. - infra-pin.yml compares against admin/goodwe refs/heads/release/1.0; STALE message, comments and README follow. - test_control.py / test_alloc.py: drop the claim that CI cannot reach admin/goodwe. - .gitea/infra-pin is DELIBERATELY one release/1.0 merge behind (d84ac01) for the "infra-pin / fresh goes red" proof; the next commit sets it to HEAD. Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 4 ++-- .gitea/workflows/checks.yml | 3 ++- .gitea/workflows/infra-pin.yml | 18 ++++++++++-------- README.md | 3 ++- goodwe_controller/test_alloc.py | 8 +++----- goodwe_controller/test_control.py | 12 +++++------- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index 97dc92a..be5adc0 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ -# The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe master HEAD (README.md, "CI and the infra pin"). -a783602ea131d49bc0c904333c1ccb101aac02d0 +# The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). +d84ac01b09c53af5de8029c1125bd4d4cfc7b3cd diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index 56427fd..70b15f5 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -494,7 +494,8 @@ jobs: - name: check out admin/goodwe at the pin in .gitea/infra-pin env: URL: ${{ github.server_url }}/admin/goodwe.git - TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Read access to admin/goodwe only; this job's own token cannot see it. + TOKEN: ${{ secrets.INFRA_READ_TOKEN }} run: | set -eu PIN=$(grep -v '^#' "$WS/goodwe-addon/.gitea/infra-pin" | tr -d '[:space:]') diff --git a/.gitea/workflows/infra-pin.yml b/.gitea/workflows/infra-pin.yml index 5d4e4e9..8c2dafb 100644 --- a/.gitea/workflows/infra-pin.yml +++ b/.gitea/workflows/infra-pin.yml @@ -1,5 +1,6 @@ -# CI-12: goes red when admin/goodwe master has moved past .gitea/infra-pin, so -# the pin cannot go stale silently. Deliberately NOT a required check: it +# CI-12: goes red when admin/goodwe release/1.0 has moved past .gitea/infra-pin. +# It runs on add-on activity only; admin/goodwe's own `addon-pin` workflow +# covers a move of release/1.0 there. Deliberately NOT a required check: it # reports; `checks / unit` stays the only gate. How to bump: README.md, # "CI and the infra pin". name: infra-pin @@ -14,25 +15,26 @@ jobs: runs-on: [self-hosted, goodwe-rig] timeout-minutes: 30 # seconds of work; the rest is queueing for the shared slot steps: - - name: compare .gitea/infra-pin with admin/goodwe master + - name: compare .gitea/infra-pin with admin/goodwe release/1.0 env: SELF: ${{ github.server_url }}/${{ github.repository }}.git INFRA: ${{ github.server_url }}/admin/goodwe.git TOKEN: ${{ secrets.GITHUB_TOKEN }} + INFRA_TOKEN: ${{ secrets.INFRA_READ_TOKEN }} # admin/goodwe is private run: | set -eu - auth() { echo "$1" | sed "s#://#://x-access-token:${TOKEN}@#"; } + auth() { echo "$1" | sed "s#://#://x-access-token:${2:-$TOKEN}@#"; } D=$(mktemp -d) && cd "$D" git init -q . && git remote add origin "$(auth "$SELF")" # The pin of the commit this event is about (the PR head, or the push). git fetch -q --depth 1 origin "$GITHUB_SHA" PIN=$(git show FETCH_HEAD:.gitea/infra-pin | grep -v '^#' | tr -d '[:space:]') - HEAD=$(git ls-remote "$(auth "$INFRA")" refs/heads/master | cut -f1) + HEAD=$(git ls-remote "$(auth "$INFRA" "$INFRA_TOKEN")" refs/heads/release/1.0 | cut -f1) cd / && rm -rf "$D" - test -n "$HEAD" || { echo "FAIL: could not read admin/goodwe master."; exit 1; } + test -n "$HEAD" || { echo "FAIL: could not read admin/goodwe release/1.0."; exit 1; } if [ "$PIN" != "$HEAD" ]; then - echo "STALE: .gitea/infra-pin is $PIN but admin/goodwe master is $HEAD." + echo "STALE: .gitea/infra-pin is $PIN but admin/goodwe release/1.0 is $HEAD." echo " Test against $HEAD and bump the pin (README.md, \"CI and the infra pin\")." exit 1 fi - echo "OK: .gitea/infra-pin $PIN is admin/goodwe master HEAD." + echo "OK: .gitea/infra-pin $PIN is admin/goodwe release/1.0 HEAD." diff --git a/README.md b/README.md index d2a9799..2004b50 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,8 @@ on real hardware, and the comments in `control.py` say which. ### CI and the infra pin CI (`.gitea/workflows/checks.yml`) runs every `test_*.py`, with `admin/goodwe` checked out next to this repo at the commit in `.gitea/infra-pin`, so `test_freeze.py` grades against the real `sim/hwsim.py`. If that checkout fails, the job fails. The local stub is used only in local runs, and it prints `STUB USED` when it is. -**Bump the pin** whenever `infra-pin / fresh` is red, which happens once `admin/goodwe` master has moved past the pin. Set `.gitea/infra-pin` to the new master SHA (`git ls-remote /admin/goodwe.git refs/heads/master`) in a PR, and let `checks / unit` grade the tests against it. +The pin tracks `admin/goodwe` **release/1.0**, not master. Two non-required checks go red when release/1.0 has moved past the pin: `infra-pin / fresh` here, on any add-on PR or push to release/1.0, and `addon-pin / fresh` in `admin/goodwe`, on every push to its release/1.0. +**Bump the pin** whenever either is red. Set `.gitea/infra-pin` to the new release/1.0 SHA (`git ls-remote /admin/goodwe.git refs/heads/release/1.0`) in a PR, and let `checks / unit` grade the tests against it. CI reads `admin/goodwe` with the Actions secret `INFRA_READ_TOKEN`. ## Compatibility diff --git a/goodwe_controller/test_alloc.py b/goodwe_controller/test_alloc.py index 517d826..fcda789 100644 --- a/goodwe_controller/test_alloc.py +++ b/goodwe_controller/test_alloc.py @@ -10,12 +10,10 @@ IN FULL. ⚠️ WHAT THIS FILE CAN AND CANNOT CLAIM, SAID BEFORE THE FIRST CHECK. The two-master rig lives in admin/goodwe (TEST-19, `sim/sitesim.py`), where `compute()` closes the loop against `plantsim.Plant` with the firmware's own -encoder on the wire. That repository is PRIVATE and this repository's CI token -is minted for this one, so the rig is not reachable from the gate - and a test -file that needed it would either fail the gate or, like test_freeze.py's hwsim -section, pass SILENTLY having checked nothing. +encoder on the wire. CI checks admin/goodwe out at `.gitea/infra-pin` (CI-12), +but this file does not import the rig. -So the split is deliberate: +The split: * `tools/alloc_sim.py` drives the REAL rig, and its output is quoted in the pull request. It is where "no limit cycle" is a claim about the shipped diff --git a/goodwe_controller/test_control.py b/goodwe_controller/test_control.py index 46a3085..14cec8e 100644 --- a/goodwe_controller/test_control.py +++ b/goodwe_controller/test_control.py @@ -990,13 +990,11 @@ check("⭐ RESTORING slew_w 1000 AT max_w 5000 IS FASTER THAN THE PLANT, and by # # ⚠️ THE PLANT BELOW IS MODELLED HERE AND IS NOT THE RIG. admin/goodwe's # `plantsim.Plant` is the battery model this project grades control changes -# against, and this repository's CI cannot reach it - that repository is private -# and this job's token is minted for this one (see .gitea/workflows/checks.yml). -# So the rig evidence lives in `tools/slew_sim.py`, is quoted in the pull -# request and in DECISIONS/SAFETY-39-slew-against-the-rail.md, and what runs -# HERE is a first-order lag with the time constant that reproduces §5.10's -# measured ~18 s to the deadband. test_alloc.py makes the same split for the -# same reason and says so in the same words. +# against. CI checks admin/goodwe out at `.gitea/infra-pin` (CI-12), but this +# file does not import `plantsim`. The rig evidence lives in `tools/slew_sim.py`, +# is quoted in the pull request and in DECISIONS/SAFETY-39-slew-against-the-rail.md, +# and what runs HERE is a first-order lag with the time constant that reproduces +# §5.10's measured ~18 s to the deadband. test_alloc.py makes the same split. # # ⚠️ AND IT CANNOT SHOW A BATTERY ABOVE ITS RATING, WHICH IS SAID BEFORE THE # RESULT RATHER THAN AFTER IT. Neither this model nor `plantsim.Plant` lets the -- 2.54.0 From d0891a6bca65dfa03b60d563767a12a5e1609bb4 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 16:10:47 +0200 Subject: [PATCH 013/105] CI-12: .gitea/infra-pin to admin/goodwe release/1.0 HEAD (56a933e), restoring the proof pin Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index be5adc0..08db2c9 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -d84ac01b09c53af5de8029c1125bd4d4cfc7b3cd +56a933e1466f3fa2d8a3ca5d12c9161d9f037195 -- 2.54.0 From c493a6d67ad9966e9f830cb5d3a4a560d53019ab Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 17:27:06 +0200 Subject: [PATCH 014/105] CI-12: test_tariff.py no longer says CI cannot see the infra repo Co-Authored-By: Claude Opus 5.5 --- goodwe_controller/test_tariff.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/goodwe_controller/test_tariff.py b/goodwe_controller/test_tariff.py index 9511151..4f40ea0 100644 --- a/goodwe_controller/test_tariff.py +++ b/goodwe_controller/test_tariff.py @@ -90,9 +90,9 @@ guard has to improve on, which is the useful thing a 2-day replay can say. The two days are committed here as `scenarios/p1-net-.jsonl.gz` (`{"t": iso8601, "w": signed_watts}` per line, derived from the HA recorder -export) for the reason `scenarios/p1-age-2026-08-26.jsonl.gz` already is: the -infra repo is private, CI's token is minted for this repository only, and a -regression fixture that CI cannot see is not a regression fixture. +export), as `scenarios/p1-age-2026-08-26.jsonl.gz` already is. When they were +committed, CI could not see the infra repo; since CI-12 it checks admin/goodwe +out at `.gitea/infra-pin`, but these fixtures stay here with the tests. The recorder's window rolls: 2026-08-01 leaves it around 2026-09-15, which is why the committed copy is the artefact and not the API call. -- 2.54.0 From 54cc5263fb535f770675fe39c297d6c8f4a767b3 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 17:36:36 +0200 Subject: [PATCH 015/105] THROWAWAY (CI-12 proof 2): pin one release/1.0 merge behind (d84ac01); reverted next Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index 08db2c9..be5adc0 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -56a933e1466f3fa2d8a3ca5d12c9161d9f037195 +d84ac01b09c53af5de8029c1125bd4d4cfc7b3cd -- 2.54.0 From c63eda0b0f94c20807f8601920512b6b5a0ea75a Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 17:45:36 +0200 Subject: [PATCH 016/105] CI-12: restore .gitea/infra-pin to admin/goodwe release/1.0 HEAD (56a933e) This reverts commit 54cc5263fb535f770675fe39c297d6c8f4a767b3 (the proof-2 throwaway). Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index be5adc0..08db2c9 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -d84ac01b09c53af5de8029c1125bd4d4cfc7b3cd +56a933e1466f3fa2d8a3ca5d12c9161d9f037195 -- 2.54.0 From 841424463abecab129e1cf77728a49a897784246 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 18:01:15 +0200 Subject: [PATCH 017/105] CI-12 review: INFRA_READ_TOKEN via an env-set header, not a remote URL The long-lived token no longer lands in $WS/goodwe/.git/config (mounted into the tests' container, left behind by a failed job) or in git's argv. A missing secret (fork PR) fails with its own message. README: addon-pin is not re-run after a bump. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- .gitea/workflows/checks.yml | 7 +++++-- .gitea/workflows/infra-pin.yml | 8 +++++--- README.md | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index 70b15f5..5db6bb5 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -500,10 +500,13 @@ jobs: set -eu PIN=$(grep -v '^#' "$WS/goodwe-addon/.gitea/infra-pin" | tr -d '[:space:]') echo "$PIN" | grep -Eq '^[0-9a-f]{40}$' || { echo "FAIL: .gitea/infra-pin holds '$PIN', not a full 40-hex SHA."; exit 1; } + test -n "$TOKEN" || { echo "FAIL: secret INFRA_READ_TOKEN is not available to this run (a fork PR?)."; exit 1; } rm -rf "$WS/goodwe" && mkdir -p "$WS/goodwe" && cd "$WS/goodwe" git init -q . - git remote add origin "$(echo "$URL" | sed "s#://#://x-access-token:${TOKEN}@#")" - git fetch -q origin "$PIN" || { echo "FAIL: could not fetch admin/goodwe at $PIN."; exit 1; } + # The token goes in a header via env: not in argv, and not in .git/config, + # which is mounted into the tests' container and outlives a failed job. + GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraHeader GIT_CONFIG_VALUE_0="Authorization: token $TOKEN" \ + git fetch -q "$URL" "$PIN" || { echo "FAIL: could not fetch admin/goodwe at $PIN."; exit 1; } git -c advice.detachedHead=false checkout -qf FETCH_HEAD test "$(git rev-parse HEAD)" = "$PIN" test -f sim/hwsim.py || { echo "FAIL: admin/goodwe@$PIN has no sim/hwsim.py."; exit 1; } diff --git a/.gitea/workflows/infra-pin.yml b/.gitea/workflows/infra-pin.yml index 8c2dafb..133ef90 100644 --- a/.gitea/workflows/infra-pin.yml +++ b/.gitea/workflows/infra-pin.yml @@ -23,13 +23,15 @@ jobs: INFRA_TOKEN: ${{ secrets.INFRA_READ_TOKEN }} # admin/goodwe is private run: | set -eu - auth() { echo "$1" | sed "s#://#://x-access-token:${2:-$TOKEN}@#"; } D=$(mktemp -d) && cd "$D" - git init -q . && git remote add origin "$(auth "$SELF")" + git init -q . && git remote add origin "$(echo "$SELF" | sed "s#://#://x-access-token:${TOKEN}@#")" # The pin of the commit this event is about (the PR head, or the push). git fetch -q --depth 1 origin "$GITHUB_SHA" PIN=$(git show FETCH_HEAD:.gitea/infra-pin | grep -v '^#' | tr -d '[:space:]') - HEAD=$(git ls-remote "$(auth "$INFRA" "$INFRA_TOKEN")" refs/heads/release/1.0 | cut -f1) + test -n "$INFRA_TOKEN" || { echo "FAIL: secret INFRA_READ_TOKEN is not available to this run (a fork PR?)."; exit 1; } + # Header via env, as in checks.yml: the token stays out of argv. + HEAD=$(GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraHeader GIT_CONFIG_VALUE_0="Authorization: token $INFRA_TOKEN" \ + git ls-remote "$INFRA" refs/heads/release/1.0 | cut -f1) cd / && rm -rf "$D" test -n "$HEAD" || { echo "FAIL: could not read admin/goodwe release/1.0."; exit 1; } if [ "$PIN" != "$HEAD" ]; then diff --git a/README.md b/README.md index 2004b50..53438fc 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ on real hardware, and the comments in `control.py` say which. ### CI and the infra pin CI (`.gitea/workflows/checks.yml`) runs every `test_*.py`, with `admin/goodwe` checked out next to this repo at the commit in `.gitea/infra-pin`, so `test_freeze.py` grades against the real `sim/hwsim.py`. If that checkout fails, the job fails. The local stub is used only in local runs, and it prints `STUB USED` when it is. -The pin tracks `admin/goodwe` **release/1.0**, not master. Two non-required checks go red when release/1.0 has moved past the pin: `infra-pin / fresh` here, on any add-on PR or push to release/1.0, and `addon-pin / fresh` in `admin/goodwe`, on every push to its release/1.0. +The pin tracks `admin/goodwe` **release/1.0**, not master. Two non-required checks go red when release/1.0 has moved past the pin: `infra-pin / fresh` here, on any add-on PR or push to release/1.0, and `addon-pin / fresh` in `admin/goodwe`, on every push to its release/1.0. Nothing re-runs `addon-pin` after a bump, so it stays red on that admin/goodwe commit; `infra-pin / fresh` green on the bump is the all-clear. **Bump the pin** whenever either is red. Set `.gitea/infra-pin` to the new release/1.0 SHA (`git ls-remote /admin/goodwe.git refs/heads/release/1.0`) in a PR, and let `checks / unit` grade the tests against it. CI reads `admin/goodwe` with the Actions secret `INFRA_READ_TOKEN`. ## Compatibility -- 2.54.0 From 8ff42ea85df53cb78171e4f2c74d7b4476f85a58 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 18:10:28 +0200 Subject: [PATCH 018/105] CI-12: .gitea/infra-pin to admin/goodwe release/1.0 HEAD (2d026df, goodwe#56 merged) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index 08db2c9..fa4f56f 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -56a933e1466f3fa2d8a3ca5d12c9161d9f037195 +2d026dfa7c425f462c6969b2f7cdfddc17b17a81 -- 2.54.0 From 550bd6fa529ed75ece2519b0778489b4bbe64c37 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 19:07:34 +0200 Subject: [PATCH 019/105] TOOL-9: pin checks print their FAIL line under pipefail; job tokens via header A missing or comment-only .gitea/infra-pin now ends on the workflow's own FAIL line instead of git's `fatal: path ... does not exist` (still red). Every x-access-token remote URL becomes an env-set Authorization header, so no token lands in .git/config or argv; the pin workflows' temp dir is removed by an EXIT trap, also on failure. Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/checks.yml | 8 +++++--- .gitea/workflows/infra-pin.yml | 16 ++++++++++------ goodwe_controller/test_ci_gate.py | 7 +++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.gitea/workflows/checks.yml b/.gitea/workflows/checks.yml index 5db6bb5..4cffd72 100644 --- a/.gitea/workflows/checks.yml +++ b/.gitea/workflows/checks.yml @@ -286,8 +286,9 @@ jobs: run: | set -eu rm -rf "$WS" && mkdir -p "$WS/goodwe-addon" && cd "$WS/goodwe-addon" - git init -q . - git remote add origin "$(echo "$URL" | sed "s#://#://x-access-token:${TOKEN}@#")" + git init -q . && git remote add origin "$URL" + # Token as an env-set header: not in argv or .git/config (TOOL-9). + export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraHeader GIT_CONFIG_VALUE_0="Authorization: token $TOKEN" if [ -n "$PRNUM" ]; then # Two fetches, not one, so that a failure to reach either ref fails # HERE with the ref in the message, rather than inside the merge @@ -498,7 +499,8 @@ jobs: TOKEN: ${{ secrets.INFRA_READ_TOKEN }} run: | set -eu - PIN=$(grep -v '^#' "$WS/goodwe-addon/.gitea/infra-pin" | tr -d '[:space:]') + # `|| true`: under pipefail a missing or comment-only pin would skip the FAIL line (TOOL-9). + PIN=$(grep -v '^#' "$WS/goodwe-addon/.gitea/infra-pin" | tr -d '[:space:]') || true echo "$PIN" | grep -Eq '^[0-9a-f]{40}$' || { echo "FAIL: .gitea/infra-pin holds '$PIN', not a full 40-hex SHA."; exit 1; } test -n "$TOKEN" || { echo "FAIL: secret INFRA_READ_TOKEN is not available to this run (a fork PR?)."; exit 1; } rm -rf "$WS/goodwe" && mkdir -p "$WS/goodwe" && cd "$WS/goodwe" diff --git a/.gitea/workflows/infra-pin.yml b/.gitea/workflows/infra-pin.yml index 133ef90..e39cd02 100644 --- a/.gitea/workflows/infra-pin.yml +++ b/.gitea/workflows/infra-pin.yml @@ -23,16 +23,20 @@ jobs: INFRA_TOKEN: ${{ secrets.INFRA_READ_TOKEN }} # admin/goodwe is private run: | set -eu - D=$(mktemp -d) && cd "$D" - git init -q . && git remote add origin "$(echo "$SELF" | sed "s#://#://x-access-token:${TOKEN}@#")" + D=$(mktemp -d) && trap 'cd / && rm -rf "$D"' EXIT && cd "$D" + git init -q . # The pin of the commit this event is about (the PR head, or the push). - git fetch -q --depth 1 origin "$GITHUB_SHA" - PIN=$(git show FETCH_HEAD:.gitea/infra-pin | grep -v '^#' | tr -d '[:space:]') + # Token as an env-set header: not in argv or .git/config (TOOL-9). + GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraHeader GIT_CONFIG_VALUE_0="Authorization: token $TOKEN" \ + git fetch -q --depth 1 "$SELF" "$GITHUB_SHA" || { echo "FAIL: could not fetch $GITHUB_SHA here."; exit 1; } + # `|| true`: under the runner's pipefail a missing or comment-only pin + # would stop here on git's error instead of the FAIL line below (TOOL-9). + PIN=$(git show FETCH_HEAD:.gitea/infra-pin | grep -v '^#' | tr -d '[:space:]') || true + test -n "$PIN" || { echo "FAIL: .gitea/infra-pin is missing at $GITHUB_SHA, or holds only comments."; exit 1; } test -n "$INFRA_TOKEN" || { echo "FAIL: secret INFRA_READ_TOKEN is not available to this run (a fork PR?)."; exit 1; } # Header via env, as in checks.yml: the token stays out of argv. HEAD=$(GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraHeader GIT_CONFIG_VALUE_0="Authorization: token $INFRA_TOKEN" \ - git ls-remote "$INFRA" refs/heads/release/1.0 | cut -f1) - cd / && rm -rf "$D" + git ls-remote "$INFRA" refs/heads/release/1.0 | cut -f1) || true test -n "$HEAD" || { echo "FAIL: could not read admin/goodwe release/1.0."; exit 1; } if [ "$PIN" != "$HEAD" ]; then echo "STALE: .gitea/infra-pin is $PIN but admin/goodwe release/1.0 is $HEAD." diff --git a/goodwe_controller/test_ci_gate.py b/goodwe_controller/test_ci_gate.py index 03c9d1a..1d88981 100644 --- a/goodwe_controller/test_ci_gate.py +++ b/goodwe_controller/test_ci_gate.py @@ -62,10 +62,9 @@ the step it wants: if checks.yml is restructured so that the step cannot be found, this file goes RED rather than quietly grading nothing. ⚠️ NEEDS `git`, which is why .gitea/ci/Dockerfile installs it. No network: the -fixtures are local repositories built in a temp directory, and the workflow's -`git remote add origin "$(echo "$URL" | sed "s#://#://x-access-token:...@#")"` -is a no-op substitution on a path with no `://` in it, which is what lets the -shipped line be used verbatim. +fixtures are local repositories built in a temp directory; the workflow's +token header (TOOL-9) is ignored for a local path, which is what lets the +shipped lines be used verbatim. ⚠️ This file writes only under a temporary directory. It must stay that way: CI mounts the checkout READ-ONLY. -- 2.54.0 From a2c571b20e7a23bc9eeeda6101b6eb5ea4bb3511 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 19:08:22 +0200 Subject: [PATCH 020/105] THROWAWAY (TOOL-9 proof, reverted next): remove .gitea/infra-pin Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitea/infra-pin diff --git a/.gitea/infra-pin b/.gitea/infra-pin deleted file mode 100644 index fa4f56f..0000000 --- a/.gitea/infra-pin +++ /dev/null @@ -1,2 +0,0 @@ -# The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -2d026dfa7c425f462c6969b2f7cdfddc17b17a81 -- 2.54.0 From b963153de65e238846a37f2072c6beb32f993fc0 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 19:20:19 +0200 Subject: [PATCH 021/105] Restore .gitea/infra-pin (revert the TOOL-9 proof throwaway) Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitea/infra-pin diff --git a/.gitea/infra-pin b/.gitea/infra-pin new file mode 100644 index 0000000..fa4f56f --- /dev/null +++ b/.gitea/infra-pin @@ -0,0 +1,2 @@ +# The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). +2d026dfa7c425f462c6969b2f7cdfddc17b17a81 -- 2.54.0 From 00e9a7b4e1124528a954a1b8ca76f0347b106a3e Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Fri, 25 Sep 2026 20:42:44 +0200 Subject: [PATCH 022/105] CI: bump infra pin to a1d0618 (admin/goodwe#57, TOOL-9) Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index fa4f56f..9991555 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -2d026dfa7c425f462c6969b2f7cdfddc17b17a81 +a1d0618eb339b1d4841cd31d6399b67a22b9dfee -- 2.54.0 From 6028e21298960cd1e33f4bf54c16bca910ee4478 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sat, 26 Sep 2026 12:37:47 +0200 Subject: [PATCH 023/105] SAFETY-34: re-assert latched alarms, because a Core restart keeps the add-on A Core-only restart wipes persistent_notification and does NOT restart the add-on (measured on TEST-23: the add-on's SAFETY-31 card was gone 4 min after `docker restart test23-ha`, add-on StartedAt unchanged). The latched SAFETY-31 and SAFETY-42 cards were re-raised only on add-on start, so they stayed gone. They are now re-asserted every REANNOUNCE_S = 300 s while tripped (same notification_id, so it replaces). test_watchdog part 6 and test_delivery part 8b grade it with the same process across the "restart"; red on the old code. The docstrings that said the add-on restarts with HA are corrected. Record: goodwe docs/DECISIONS.md, SAFETY-34 D4. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- goodwe_controller/app/main.py | 35 +++++++++++++++++++++------ goodwe_controller/test_delivery.py | 38 ++++++++++++++++++++++++++++-- goodwe_controller/test_watchdog.py | 26 ++++++++++++++++++-- 3 files changed, 88 insertions(+), 11 deletions(-) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 114677c..6a19576 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -113,6 +113,12 @@ __all__ = ["UNIT_A", "Controller", "amain", "main"] # the re-issue happens by itself) than hold the control loop for ten seconds. WRITE_BUDGET_S = 4.0 +# SAFETY-34: a Core-only restart wipes persistent_notification and does NOT +# restart this add-on (measured on TEST-23), so a latched alarm is re-asserted +# this often. Why: goodwe docs/DECISIONS.md, SAFETY-34. +REANNOUNCE_S = 300.0 +_mono = time.monotonic # patched by the checks; asyncio keeps the real one + # --------------------------------------------------------------------------- # # OPT-04: THE BACKGROUND TARIFF REFRESH, AND WHY IT IS NOT OPTIONAL # @@ -691,6 +697,9 @@ class Controller: # does, so the latch alone is not the alarm - re-raising it is. # `run_control()` does that, once, before the first cycle. self._circ_announced = False + # SAFETY-34: when each latched alarm was last put in front of HA, by + # notification_id - see REANNOUNCE_S. + self._announced_mono = {} if self.circ_wd.tripped: _LOG.error( "SAFETY-31 was TRIPPED before this restart and stays tripped: " @@ -3943,15 +3952,17 @@ class Controller: The latch says "this site is tripped"; the flag says "this process has put that in front of a human". A restart clears the flag and keeps the latch, so the notification is RE-RAISED on the first cycle after every - add-on start - which is also the first cycle after a Home Assistant - restart, because the add-on is restarted with it. + add-on start. A Core-only restart does NOT restart the add-on, so it is + also re-asserted every REANNOUNCE_S (SAFETY-34). ⚠️ ONE CODE PATH FOR BOTH, ON PURPOSE. A fresh trip and a restart into an existing trip raise the alarm through these same lines. Two paths would be two chances for the restart one to rot unnoticed, and the restart one is the case nobody exercises by hand. """ - if not self.circ_wd.tripped or self._circ_announced: + if not self.circ_wd.tripped: + return + if self._circ_announced and not self._reannounce_due("goodwe_circulating_power"): return # Set BEFORE the await. `hass.call()` can raise or hang, and a retry # every cycle for a broker that is down would be an alarm storm on the @@ -3959,6 +3970,7 @@ class Controller: # already durable and the log line above already fired; this surface is # best-effort by design. self._circ_announced = True + self._announced_mono["goodwe_circulating_power"] = _mono() names = self.units pos, neg = opposing([inv.batt for inv in self.inverters], min_w=self.circ_wd.cfg.min_w / 2.0) @@ -3993,6 +4005,11 @@ class Controller: f"know why two inverters were opposing."), }) + def _reannounce_due(self, notification_id: str) -> bool: + """SAFETY-34: has this latched alarm gone REANNOUNCE_S without being re-asserted?""" + t = self._announced_mono.get(notification_id) + return t is None or _mono() - t >= REANNOUNCE_S + async def check_not_delivering(self) -> None: """SAFETY-42 + SAFETY-34. The alarm, and it must survive a restart. @@ -4012,8 +4029,8 @@ class Controller: not persisted. The latch says "this unit is tripped"; membership says "this process has put that in front of a human". A restart empties the set and keeps the latch, so the notification is RE-RAISED on the first - cycle after every add-on start - which is also the first cycle after a - Home Assistant restart, because the add-on is restarted with it. + cycle after every add-on start, and re-asserted every REANNOUNCE_S + because a Core-only restart does not restart the add-on (SAFETY-34). ⚠️ ONE CODE PATH FOR BOTH, ON PURPOSE - `check_circulating()`'s argument. A fresh trip and a restart into an existing trip raise the @@ -4031,7 +4048,10 @@ class Controller: names = self.units slugs = unit_slugs(names) for inv, slug in zip(self.inverters, slugs): - if not inv.delivery_wd.tripped or inv.name in self._delivery_announced: + nid = f"goodwe_not_delivering_{slug}" + if not inv.delivery_wd.tripped: + continue + if inv.name in self._delivery_announced and not self._reannounce_due(nid): continue # Added BEFORE the await, for `check_circulating()`'s reason: # `hass.call()` can raise or hang, and a retry every cycle for a @@ -4039,9 +4059,10 @@ class Controller: # latch is already durable and the log line already fired; this # surface is best-effort by design. self._delivery_announced.add(inv.name) + self._announced_mono[nid] = _mono() peers = ", ".join(n for n in names if n != inv.name) or "no sibling" await self.hass.call("persistent_notification", "create", { - "notification_id": f"goodwe_not_delivering_{slug}", + "notification_id": nid, "title": f"GoodWe: {inv.name} is not delivering its share", "message": ( f"{inv.delivery_wd.reason}\n\nWHY NOTHING ELSE SAID SO. A " diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index 29d3068..6e53bb1 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -1195,8 +1195,8 @@ async def _restart(): c1 = _ctrl(h1, store=shared) await _drive(c1) # A NEW process, a NEW HomeAssistant object (so the in-memory notification - # is gone with it), the SAME durable file. That is what a Home Assistant - # restart is from this add-on's point of view: the add-on goes with it. + # is gone with it), the SAME durable file: an ADD-ON restart. A Core-only + # restart keeps the process; graded in part 8b (SAFETY-34). h2 = _DeliveryHass(b_soc=50.0) c2 = _ctrl(h2, store=shared) await c2.check_not_delivering() @@ -1250,6 +1250,40 @@ check("the operator's START press is the only way out, and it clears the " and _rs.data.get(unit_key("inverter-b", "delivery_reason")) == "" and _r2._delivery_announced == set()) +print() +print("8b. SAFETY-34: a Core-only restart - same add-on process, HA's memory wiped") +import app.main as _main_mod # noqa: E402 + + +async def _core_restart(): + shared = _MemStore() + c = _ctrl(_DeliveryHass(b_soc=50.0), store=shared) + await _drive(c) + return c + + +_c = asyncio.run(_core_restart()) +_real_mono, _clock = _main_mod._mono, [_main_mod._mono()] +_main_mod._mono = lambda: _clock[0] +try: + _c.hass = _DeliveryHass(b_soc=50.0) + asyncio.run(_c.check_not_delivering()) + _early = [x for x in _c.hass.calls + if "not_delivering" in str(x[2].get("notification_id", ""))] + _clock[0] += _main_mod.REANNOUNCE_S + asyncio.run(_c.check_not_delivering()) + _late = [x for x in _c.hass.calls + if "not_delivering" in str(x[2].get("notification_id", ""))] +finally: + _main_mod._mono = _real_mono +check("SAFETY-34: the latch tripped in this process", + _c.inverters[1].delivery_wd.tripped) +check("SAFETY-34: inside REANNOUNCE_S the same process does not re-raise", + len(_early) == 0) +check("SAFETY-34: after REANNOUNCE_S the SAME process re-asserts the card, " + "because a Core-only restart wiped it and did not restart the add-on", + len(_late) == 1 and "inverter_b" in _late[0][2]["notification_id"]) + print() if fails: diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 8d8cf38..2decd04 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -1055,8 +1055,8 @@ async def _circ_restart(): await a.read_inputs() await a.cycle() await asyncio.sleep(0.25) - # THE RESTART. Same store, brand new Controller and Hass - which is exactly - # what a Home Assistant restart does to this add-on. The house has stopped + # THE RESTART. Same store, brand new Controller and Hass - an ADD-ON + # restart. A Core-only restart keeps the process; graded below (SAFETY-34). The house has stopped # circulating in the meantime, so nothing in the new process's own # measurements could re-derive the trip. h2 = _CircHass(a_w=0.0, b_w=0.0) @@ -1116,6 +1116,28 @@ check("...and it does not raise the same card on every cycle - a per-PROCESS " "this' a different question from 'is this site tripped'", len(_notes2) == 1) +# SAFETY-34: a Core-ONLY restart. The add-on process lives on (measured on +# TEST-23), HA's memory is wiped, so the SAME process must re-assert the card. +import app.main as _main_mod # noqa: E402 +_real_mono, _clock = _main_mod._mono, [_main_mod._mono()] +_main_mod._mono = lambda: _clock[0] +try: + _h3 = _CircHass(a_w=0.0, b_w=0.0) + _b.hass = _h3 + asyncio.run(_b.check_circulating()) + _early = [c for c in _h3.calls if c[0] == "persistent_notification"] + _clock[0] += _main_mod.REANNOUNCE_S + asyncio.run(_b.check_circulating()) + _late = [c for c in _h3.calls if c[0] == "persistent_notification"] +finally: + _main_mod._mono = _real_mono +check("SAFETY-34: inside REANNOUNCE_S the same process does not re-raise - no " + "storm on the event bus", len(_early) == 0) +check("SAFETY-34: a Core-only restart wipes the card and the add-on process " + "survives it, so after REANNOUNCE_S the SAME process re-asserts it", + len(_late) == 1 + and _late[0][2]["notification_id"] == "goodwe_circulating_power") + print() print("6a. AC 4: THE ALARM NAMES WHICH PACKS, AND WHICH WAY ROUND") -- 2.54.0 From f37268f3e4df5130a069b34a976579e01af8e795 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sat, 26 Sep 2026 16:05:02 +0200 Subject: [PATCH 024/105] CI: bump infra pin to 7689816 (admin/goodwe#58, SAFETY-34) Co-Authored-By: Claude Opus 5.5 --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index 9991555..ee1edd3 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -a1d0618eb339b1d4841cd31d6399b67a22b9dfee +76898164b56190f0aa6f7a15be9ce6302c958ce5 -- 2.54.0 From fd14569a712f916c5c3ed3cc70a3024619fddebc Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sat, 26 Sep 2026 22:37:01 +0200 Subject: [PATCH 025/105] SAFETY-40: the integrator bound is not a BUG SIGNAL; numbers from the clamp tick The clamp alarm gave `i_clamped` (normal anti-windup) the over-rating BUG SIGNAL text, printed `Decision.i_w` as "the loop asked for", and printed `self.target` (after slew/freeze) as "was clamped to". - clamp.loop_clamp_note(): i_clamped says "the loop's integrator reached its N W anti-windup bound" with this tick's command; clamped keeps BUG SIGNAL with the requested command and the clamp's own result. - Decision carries i_bound_w / requested_w / clamped_w, set at the clamp. - i_clamped still counts and notifies (same id, cadence, SAFETY-41 escalation) but as a WARNING, amber row, plain title. A bug has its own notification budget and its text is not overwritten within an episode. - test_clamp.py part 9: red on the old code per defect; 5 mutations killed. - DOCS.md alarm section (and its stale 30 s cadence), DECISIONS/SAFETY-40. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- ...TY-40-the-integrator-bound-is-not-a-bug.md | 26 +++ goodwe_controller/DOCS.md | 21 +- goodwe_controller/app/clamp.py | 86 ++++++-- goodwe_controller/app/control.py | 11 +- goodwe_controller/app/main.py | 61 ++++-- goodwe_controller/test_clamp.py | 189 +++++++++++++++++- 6 files changed, 340 insertions(+), 54 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md diff --git a/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md b/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md new file mode 100644 index 0000000..2a41f95 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md @@ -0,0 +1,26 @@ +# SAFETY-40: the integrator bound is not a bug + +**Decision.** `i_clamped` (the integrator reaching `integrator_max_w`, i.e. +anti-windup) keeps alarming through the same `ClampWatchdog`: it is counted, +notified on the same id and cadence, and escalates on a sustained run +(SAFETY-41). It gets its own text, a `WARNING` and an amber status row. Only +`clamped` (a command over `max_w`) and write-path clamps keep the BUG SIGNAL, +the `ERROR` and the red row. + +**Why it still notifies.** On a default install `clamped` is unreachable +(`control.py`, at the integrator bound), so the integrator bound is the only +loop-side signal of a runaway such as the 14 768 W one. Silencing it would +remove that. The card says the same: "the fix is to say the true thing, not to +say less." + +**Why a bug has its own budget.** A genuine over-rating must not wait up to +`REASSERT_S` behind anti-windup notices. `ClampWatchdog` tracks a separate +`last_bug_alarm`, and a bug's text is never overwritten by later anti-windup +text within an episode. With only bug engagements, the cadence is the same as +before (`test_clamp.py` part 9). + +**Numbers.** They come from the `Decision` of the clamping tick (`i_bound_w`, +`requested_w`, `clamped_w`, `target_w`), not from `i_w` or `self.target`. + +**Open for the owner.** Whether scattered one-cycle anti-windup episodes should +notify at all, or only log and count. They notify now, as before. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index f0076f3..ecdd5cc 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1630,7 +1630,9 @@ share no reason code, no notification id, no status row and no counter. running - this is not the sign-disagreement failsafe, which commands 0 W. You get a persistent notification (`goodwe_output_clamp`, replaced rather than stacked), an `ERROR` in the log with the reason code `OUTPUT_CLAMP`, a row in -the event list, and a red status banner while it is engaged. Once it clears, a +the event list, and a red status banner while it is engaged. The message quotes +the command the loop computed and the value it was clamped to, both from the +cycle that clamped. Once it clears, a warning row keeps the engagement count so the evidence does not vanish with the condition. Consecutive engagements share one event row carrying the exact count, because the event list keeps only 40 rows and a row per cycle would flush every @@ -1639,9 +1641,11 @@ other guard's entries out of it. **There is nothing to configure**, deliberately. The bound is `max_w`, which you already set; giving the guard a limit of its own would be a second number that can disagree with the first, which is exactly the failure the startup validation -exists to prevent. The alarm's cadence - first engagement, then re-asserted every -30 s while it persists, cleared after 3 clean cycles - is fixed for the same -reason `RAIL_FRAC` is: it describes the notification bus, not the plant. +exists to prevent. The alarm's cadence - at most one notification per 150 s +(an episode that has not yet notified does so once it has engaged 3 cycles in +a row), cleared after 3 clean +cycles - is fixed for the same reason `RAIL_FRAC` is: it describes the +notification bus, not the plant. WARNING: **on a default install the engagement you will see is the integrator's, not the output's.** The control law bounds the integrator to `max_w` and *then* @@ -1650,6 +1654,15 @@ rating unless `integrator_max_w` has been deliberately raised above `max_w`. Both are watched. A guard that watched only the emitted value would be silent on every standard configuration. +**The integrator bound is not a bug, and it is reported as what it is.** It +reads *"the loop's integrator reached its +5000 W anti-windup bound; the loop's +command this cycle was +2000 W"*, titled *"the control loop is at its integrator +bound"*, logged as a `WARNING`, with an amber (not red) status row. Brief +engagements after a large load or solar step are normal. If it stays engaged, +check that the battery is following its commands. Only a command over the rating +carries the BUG SIGNAL text, and it never waits behind integrator-bound notices. +Why: [`DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md`](DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md). + ### The frozen-meter alarm A meter that has died is easy — it stops answering, the sample age climbs past diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index d787108..e25a704 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -73,6 +73,7 @@ An alarm wired only to this module's `ClampResult.engaged` would therefore be silent on the exact configuration the whole ticket is about. The winding is visible one layer up, at the integrator bound, and that is why `Decision` now carries `i_clamped` / `clamped` BOOLEANS and the caller ORs them in here. +They alarm in different words: see `loop_clamp_note()` (SAFETY-40). AND WHY BOOLEANS RATHER THAN `Decision.reason`. `reason` is a single string that later stages overwrite: a cycle that clamps the integrator and is then slew @@ -200,9 +201,8 @@ REASON_CODE = "OUTPUT_CLAMP" # ceiling rests on one number a test author chose; if that number is ever # revisited, this constant moves with it. # -# ⚠️ THIS IS A STOP-GAP AND DOES NOT MAKE THE ALARM CORRECT. The message still -# calls the integrator bound a BUG SIGNAL and still pairs a request from one -# moment with a `self.target` read at another - SAFETY-40. Nothing here is +# ⚠️ THIS WAS A STOP-GAP; the wording and the numbers were SAFETY-40's, fixed +# in `loop_clamp_note()` below. Nothing here is # suppressed: every engagement is still counted, the action-log row is written on # every engaged cycle regardless, and the rising edge of every episode alarms # unconditionally, so no alarm is DROPPED - only delayed. @@ -234,6 +234,31 @@ CLEAR_CYCLES = 3 SUSTAINED_CYCLES = 3 +BUG_SIGNAL = ("This is a BUG SIGNAL, not a limit being used: something " + "upstream computed a setpoint the actuator cannot deliver.") + + +def loop_clamp_note(d) -> str: + """The loop-side alarm text for one `control.Decision`, or "". + + SAFETY-40: the integrator bound is anti-windup doing its job and says so; + only a command over the rating is a BUG SIGNAL. Every number is the + decision's own, i.e. from the tick that clamped. + """ + if d.clamped: + return (f"{REASON_CODE}: the loop computed {d.requested_w:+.0f} W, over " + f"the {abs(d.clamped_w):.0f} W rating, and it was clamped to " + f"{d.clamped_w:+.0f} W; the loop's command this cycle was " + f"{d.target_w:+.0f} W. {BUG_SIGNAL}") + if d.i_clamped: + return (f"{REASON_CODE}: the loop's integrator reached its " + f"{d.i_bound_w:+.0f} W anti-windup bound; the loop's command " + f"this cycle was {d.target_w:+.0f} W. Brief " + f"engagements after a large load or solar step are normal. If it " + f"persists, check that the battery is following its commands.") + return "" + + @dataclass(frozen=True) class ClampResult: """What the guard did, with the RAW value preserved. @@ -342,23 +367,51 @@ class ClampWatchdog: # spoken yet - the two the escalation clause needs. self.run_len = 0 self.spoken = False + # SAFETY-40. Did this episode include a genuine over-rating (`bug`), and + # has THAT spoken? A bug has its own budget, so anti-windup notices can + # never delay it; with bug=True throughout, cadence is as before. + self.bug = False + self.bug_spoken = False + self.last_bug_alarm: datetime | None = None - def note(self, engaged: bool, reason: str, now: datetime) -> bool: + def _due(self, last, now) -> bool: + return last is None or (now - last).total_seconds() >= REASSERT_S + + def _speak(self, now, bug) -> bool: + self.last_alarm = now + self.spoken = True + if bug: + self.last_bug_alarm = now + self.bug_spoken = True + return True + + def note(self, engaged: bool, reason: str, now: datetime, + bug: bool = True) -> bool: """Advance one cycle. True when the caller should raise the alarm. `now` is the caller's clock, the same discipline as - `SignWatchdog.evaluate()` and `FreezeWatchdog.evaluate()`. + `SignWatchdog.evaluate()` and `FreezeWatchdog.evaluate()`. `bug` False + is the integrator bound (SAFETY-40): counted and notified like the + rest, but it never replaces a bug's text within an episode. """ if engaged: self.engagements += 1 self.clean_cycles = 0 - self.reason = reason self.run_len += 1 - if not self.active: + rising = not self.active + if rising: self.active = True self.since = now self.episodes += 1 self.spoken = False + self.bug = False + self.bug_spoken = False + if bug or not self.bug: + self.reason = reason + self.bug = self.bug or bug + if bug and not self.bug_spoken and self._due(self.last_bug_alarm, now): + return self._speak(now, True) + if rising: # ⚠️ SAFETY-41. THE RISING EDGE IS RATE-LIMITED TOO, and it did # not used to be. It fired unconditionally, so a condition that # engages and clears repeatedly raised one notification PER @@ -384,11 +437,8 @@ class ClampWatchdog: # still written on every engaged cycle, and a genuine runaway - # which by definition keeps engaging - is picked up by the # re-assert path within REASSERT_S. Delay, not loss. - if (self.last_alarm is None - or (now - self.last_alarm).total_seconds() >= REASSERT_S): - self.last_alarm = now - self.spoken = True - return True + if self._due(self.last_alarm, now): + return self._speak(now, self.bug) return False # ⚠️ THE ESCALATION. An episode that has not yet spoken because the # budget was spent by an EARLIER, unrelated episode speaks anyway @@ -396,15 +446,10 @@ class ClampWatchdog: # engages every cycle and reaches it; the scattered one-cycle # railing that produced the live flood never does. if not self.spoken and self.run_len >= SUSTAINED_CYCLES: - self.last_alarm = now - self.spoken = True - return True + return self._speak(now, self.bug) # Still engaged: re-assert on the slow cadence, not every cycle. - if (self.last_alarm is None - or (now - self.last_alarm).total_seconds() >= REASSERT_S): - self.last_alarm = now - self.spoken = True - return True + if self._due(self.last_alarm, now): + return self._speak(now, self.bug) return False self.run_len = 0 @@ -420,5 +465,6 @@ class ClampWatchdog: # above. The episode ends; the notification budget does not reset # with it. self.reason = "" + self.bug = False self.clean_cycles = 0 return False diff --git a/goodwe_controller/app/control.py b/goodwe_controller/app/control.py index fa89464..9a6cfda 100644 --- a/goodwe_controller/app/control.py +++ b/goodwe_controller/app/control.py @@ -340,6 +340,12 @@ class Decision: # the comment at the bound below, and clamp.py. i_clamped: bool = False clamped: bool = False + # SAFETY-40. The alarm's numbers, taken at the clamp so they are one tick's: + # the bound the integrator reached, and the command before/after the + # rating clamp. `target_w` is this tick's emitted command. + i_bound_w: float = 0.0 + requested_w: float = 0.0 + clamped_w: float = 0.0 def slew_limit_w(tuning: Tuning) -> float: @@ -563,6 +569,7 @@ def compute( # winding, "clamped" is a command that came out over the rating anyway. reason = "i-clamped" i_w = bounded + i_bound_w = bounded if i_clamped else 0.0 want = i_w # ⚠️ Maintenance shaping (charge-only, cheap-window floor) used to live @@ -574,6 +581,7 @@ def compute( # An early draft applied a floor after the clamp and let demand escape it. target = max(-tuning.max_w, min(tuning.max_w, want)) clamped = target != want + clamped_w = target if clamped: reason = "clamped" @@ -740,7 +748,8 @@ def compute( target = round(target / step) * step return Decision(float(target), sat_count, frozen, reason, float(i_w), - i_clamped, clamped) + i_clamped, clamped, float(i_bound_w), float(want), + float(clamped_w)) def maintenance_charge_floor( diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 6a19576..a60afb5 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -49,7 +49,8 @@ from .circulation import ( circulating_w, opposing, ) from .clamp import ( - REASON_CODE as CLAMP_REASON, ClampWatchdog, clamp_to_rating, is_commandable, + BUG_SIGNAL as CLAMP_BUG_SIGNAL, REASON_CODE as CLAMP_REASON, ClampWatchdog, + clamp_to_rating, is_commandable, loop_clamp_note, ) from . import freshness from .freeze import ( @@ -994,7 +995,8 @@ class Controller: # the counterpart to `clamp_last` moving onto the Inverter: the integrator # that wound is the SITE integrator, of which there is exactly one, while # the value a clamp bit is a value written to ONE device. - self.loop_clamped: tuple[bool, str] = (False, "") + # (engaged, note, over_rating) - SAFETY-40 splits the last one out. + self.loop_clamped: tuple[bool, str, bool] = (False, "", False) self.stopping = False # SAFETY-61. time.monotonic() at the end of the last run_control() pass. self.loop_pass_mono = None @@ -3271,11 +3273,12 @@ class Controller: # it - so a string test is silent on the two cases a winding loop # most often presents as. These flags are set where the clamp # happens and nothing downstream touches them. + # SAFETY-40: every number comes from THIS decision, at clamp time, + # never from `self.target` after slew/freeze/arbiter rewrote it. self.loop_clamped = ( decision.i_clamped or decision.clamped, - (f"the loop asked for {decision.i_w:+.0f} W" - + (" (integrator bound)" if decision.i_clamped else "") - + (" (output bound)" if decision.clamped else "")), + loop_clamp_note(decision), + decision.clamped, ) # SITE. compute() regulates `grid_w` - the P1 measurement - to # zero. Its subject is the meter, and §6.2's architecture is ONE @@ -3299,7 +3302,7 @@ class Controller: # A loop that is not running cannot be winding. Clearing this here # rather than letting the last value stand is what makes the alarm # de-assert when control is stopped. - self.loop_clamped = (False, "") + self.loop_clamped = (False, "", False) # SAFETY-28. A new resolution is a new tick, and the previous record is # stale from this line onwards. Incremented BEFORE resolve() so that the @@ -3716,20 +3719,17 @@ class Controller: clamped_units = [inv for inv in self.inverters if inv.clamp_last is not None and inv.clamp_last.engaged] engaged_write = bool(clamped_units) - engaged_loop, loop_note = self.loop_clamped + engaged_loop, loop_note, loop_bug = self.loop_clamped engaged = engaged_write or engaged_loop - if engaged: - where = (", ".join(f"{inv.name}: {inv.clamp_last.describe()}" - for inv in clamped_units) if engaged_write - else f"{CLAMP_REASON}: {loop_note}, above the " - f"{self.site_max_w:.0f} W rating, and " - f"was clamped to {self.target:+.0f} W") - reason = (f"{where}. This is a BUG SIGNAL, not a limit being used: " - f"something upstream computed a setpoint the actuator " - f"cannot deliver.") + # SAFETY-40: only an over-rating is a bug; the integrator bound is not. + bug = engaged_write or loop_bug + if engaged_write: + reason = (", ".join(f"{inv.name}: {inv.clamp_last.describe()}" + for inv in clamped_units) + ". " + CLAMP_BUG_SIGNAL) else: - reason = "" - fired = self.clamp_wd.note(engaged, reason, datetime.now(timezone.utc)) + reason = loop_note if engaged else "" + fired = self.clamp_wd.note(engaged, reason, datetime.now(timezone.utc), + bug=bug) # --- THE ACTION LOG, AND IT IS COALESCED PER EPISODE ------------------ # Every engagement is recorded, but consecutive ones are recorded by @@ -3760,6 +3760,18 @@ class Controller: self.log_event(row) if not fired: return + if not self.clamp_wd.bug: + # SAFETY-40: the integrator bound is anti-windup, not a bug - a + # WARNING and a plainly titled notice, same id and cadence. + _LOG.warning("SAFETY-03 - %s Engagements so far: %d.", + self.clamp_wd.reason, self.clamp_wd.engagements) + await self.hass.call("persistent_notification", "create", { + "notification_id": "goodwe_output_clamp", + "title": "GoodWe: the control loop is at its integrator bound", + "message": (f"{self.clamp_wd.reason}\n\nNo command exceeded " + f"the rating and the controller is STILL RUNNING."), + }) + return _LOG.error( "SAFETY-03 - %s Silently clipping this is how a winding integrator " "reached 14 768 W on this project before: the clamp makes every " @@ -4893,16 +4905,21 @@ class Controller: out.append({"ok": False, "warn": "NOT COMMANDABLE" not in note, "text": note}) - # SAFETY-03. Red while a clamp is engaged, and the engagement COUNT is - # shown even after it clears - a loop that wound once and stopped is - # still a bug, and a row that vanishes with the condition takes the + # SAFETY-03. Red while an over-rating clamp is engaged (amber for the + # integrator bound, SAFETY-40), and the engagement COUNT is shown even + # after it clears - a row that vanishes with the condition takes the # evidence with it. Reported only when there is something to report: # unlike the freeze detector this guard has no "not covered" state, it # runs on every write on every transport. - if self.clamp_wd.active: + if self.clamp_wd.active and self.clamp_wd.bug: out.append({"ok": False, "warn": False, "text": "OUTPUT CLAMP ENGAGED - " + self.clamp_wd.reason + f" Engagements: {self.clamp_wd.engagements}."}) + elif self.clamp_wd.active: + # SAFETY-40: the integrator bound alone is amber, not red. + out.append({"ok": False, "warn": True, + "text": "LOOP AT INTEGRATOR BOUND - " + self.clamp_wd.reason + + f" Engagements: {self.clamp_wd.engagements}."}) elif self.clamp_wd.engagements: out.append({"ok": False, "warn": True, "text": f"output clamp: not engaged now, but it has " diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index dc033a2..be9df87 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -38,6 +38,9 @@ acceptance criteria; part 6 is TEST-11's and part 7 is SAFETY-28's: the check that replaced a config-shape proxy: `ACTUATOR_WRITE_KEYS` graded how many option KEYS exist, which stays 1 while a per-inverter config adds a second real writer. + 9. SAFETY-40. The integrator bound (normal anti-windup) is reported in its + own words and never as a BUG SIGNAL; the over-rating keeps it; and every + number in either message is the clamp tick's own Decision. ------------------------------------------------------------------------------ WHY PART 4 ALSO ASSERTS ON `Decision`'s BOOLEANS AND NOT ON `reason` @@ -501,8 +504,11 @@ check("...with its own notification_id, not shared with any other guard", all(d["notification_id"] == CLAMP_ID for d in notes_r)) check("...one episode, re-asserted rather than one per cycle", ctl_r.clamp_wd.episodes == 1 and len(notes_r) < ctl_r.clamp_wd.engagements) -check("...and it names itself a bug signal, not a limit in use", - bool(notes_r) and "out of range" in notes_r[0]["message"]) +# SAFETY-40: on a default install this runaway is the INTEGRATOR bound, so it +# says so, and does not call anti-windup a bug (part 8 grades the wording). +check("...and it names the integrator bound, not a BUG SIGNAL", + bool(notes_r) and "anti-windup bound" in notes_r[0]["message"] + and "BUG SIGNAL" not in notes_r[0]["message"]) rows_r = [e for e in ctl_r.events if REASON_CODE in e] check(f"the action log records every engagement, coalesced into one row per " f"episode ({len(rows_r)} row(s), {ctl_r.clamp_wd.engagements} " @@ -528,8 +534,9 @@ check("...and the count in the row is the counter's, so nothing is lost", f"{ctl_l.clamp_wd.engagements} engagement(s)" in nth(rows_l, -1)) # The RED row exists only while engaged, and the episode above is short, so it # is captured mid-run rather than asserted after the hysteresis has cleared it. -check("the status page goes red WHILE it is engaged", - any(not c["ok"] and not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] +check("the status page flags it WHILE it is engaged - amber, since it is the " + "integrator bound (SAFETY-40; red is part 9's over-rating case)", + any(not c["ok"] and c["warn"] and "LOOP AT INTEGRATOR BOUND" in c["text"] for c in ctl_r.red_snapshot)) check("...and once clear, a warn row still says how many times it engaged", any(c["warn"] and f"{ctl_r.clamp_wd.engagements} time(s)" in c["text"] @@ -806,11 +813,11 @@ class _SpyWatchdog(ClampWatchdog): self.seen = [] # clamp_last.requested_w at each consultation self.seen_write = [] # was the WRITE-path half engaged, per cycle - def note(self, engaged, reason, now): + def note(self, engaged, reason, now, **kw): cl = self.owner.clamp_last self.seen.append(None if cl is None else cl.requested_w) self.seen_write.append(bool(cl and cl.engaged)) - return super().note(engaged, reason, now) + return super().note(engaged, reason, now, **kw) def probed(cls=Controller, grid=9000.0, cycles=5, **over): @@ -986,7 +993,7 @@ check("PRECONDITION: the write really did clamp, on the DEVICE bound", and hass_w.writes[-1] == 2500.0) check("...and the loop-side half is SILENT here, so self.clamp_last is the " "only evidence that this happened at all", - ctl_w.loop_clamped == (False, "")) + ctl_w.loop_clamped == (False, "", False)) check("AC 3: the guard alarmed on write-path evidence alone", ctl_w.clamp_wd.engagements == 1 and len(notes_w) == 1) check("...and the operator is told WHICH bound bit, so a device-rating clamp " @@ -1858,6 +1865,174 @@ check("...EDGE-logged, not level-logged: 25 cycles did not flush the 40-row " len(_shadow_lines) < 25 and len(_shad_c.events) <= 40) +# ============================================================================== +print() +print("9. SAFETY-40: the integrator bound is not a BUG SIGNAL, and the numbers " + "are the clamp tick's own") +# Three defects, each graded on the wired Controller.cycle() with compute() +# spied, so every number is compared with the Decision of the SAME tick: +# 1. `i_clamped` (normal anti-windup) used the over-rating BUG SIGNAL text; +# 2. "the loop asked for" printed `Decision.i_w`, the integrator, as a request; +# 3. "was clamped to" printed `self.target`, read after slew/freeze rewrote it. +# The fixtures are chosen so the numbers the old text used DIFFER from the true +# ones (MUTATION.md habit 4); the PRECONDITION checks pin that. +import logging +import app.main as _main_mod + +_real_compute = _main_mod.compute + + +class _LogCap(logging.Handler): + def __init__(self): + super().__init__() + self.records = [] + + def emit(self, record): + self.records.append(record) + + +def s40_run(grid, cycles, track, **over): + """Per tick: (Decision, self.target, clamp_wd.reason, engaged) + hass + log.""" + ticks, decisions = [], [] + + def spy(*a, **k): + d = _real_compute(*a, **k) + decisions.append(d) + return d + + cap = _LogCap() + lg = logging.getLogger("goodwe") + lg.addHandler(cap) + _main_mod.compute = spy + + async def go(): + hass = _Hass(grid, track=track) + c = Controller(dict( + {"setpoint_entity": "number.sp", "meter_entity": "sensor.grid", + "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", + "meter_source": "off", "max_w": LIVE_MAX_W, "gain": 0.6, + "slew_w": 1000, "deadband_w": 15, "target_grid_w": 0, + "step_w": 10, "heartbeat_s": 10, "stale_input_s": 15}, + **over), hass, _Store(), _Pub(), stop=asyncio.Event()) + c.auto = True + c.dev_min, c.dev_max = -LIVE_MAX_W, LIVE_MAX_W + red = [] + for _ in range(cycles): + n = len(decisions) + before = c.clamp_wd.engagements + await c.read_inputs() + await c.cycle() + d = decisions[-1] if len(decisions) > n else None + ticks.append((d, c.target, c.clamp_wd.reason, + c.clamp_wd.engagements > before)) + if c.clamp_wd.active and not red: + red = c.checks() + return hass, c, red + + try: + hass, c, red = asyncio.run(go()) + finally: + _main_mod.compute = _real_compute + lg.removeHandler(cap) + return ticks, hass, c, red, cap.records + + +def _f(d, name): + """A Decision field, NaN when absent - so an old tree goes red, not crashes.""" + return getattr(d, name, float("nan")) + + +# --- 9a. default install: only the INTEGRATOR bound can engage --------------- +ticks_i, hass_i, ctl_i, red_i, log_i = s40_run(6000.0, 20, track=False) +wind = [(d, t, r) for d, t, r, e in ticks_i + if e and d is not None and d.i_clamped and not d.clamped] +for d, t, r in wind: + print(f" tick: bound {_f(d, 'i_bound_w'):+.0f} i_w {d.i_w:+.0f} command " + f"{d.target_w:+.0f} self.target {t:+.0f}\n -> {r}") +check("PRECONDITION: the integrator bound engaged, and on a tick where the " + "carried integrator AND the emitted command both differ from the bound", + any(d.i_w != _f(d, 'i_bound_w') and d.target_w != _f(d, 'i_bound_w') + for d, t, r in wind)) +check("defect 1: the integrator bound is NOT reported as a BUG SIGNAL", + wind and all("BUG SIGNAL" not in r for d, t, r in wind)) +check("defect 1: ...it names the anti-windup bound, from the same tick", + wind and all(f"its {_f(d, 'i_bound_w'):+.0f} W anti-windup bound" in r + for d, t, r in wind)) +check("defect 2: the integrator accumulator is not printed as a request", + wind and all(f"{d.i_w:+.0f} W" not in r and "asked for" not in r + for d, t, r in wind)) +check("the command quoted is that tick's Decision, not a later read", + wind and all(f"command this cycle was {d.target_w:+.0f} W" in r + for d, t, r in wind)) +check("at the bound nothing is described as 'above' or 'over' the rating", + wind and all(" above " not in r and " over " not in r + for d, t, r in wind)) +notes_i = clamp_notes(hass_i) +check("it still NOTIFIES (not suppressed), under a title that claims no bug", + notes_i and all("integrator bound" in n["title"] + and "exceeded" not in n["title"] for n in notes_i)) +check("...logged as a WARNING, not an ERROR", + any(x.levelno == logging.WARNING and "anti-windup" in x.getMessage() + for x in log_i) + and not any(x.levelno >= logging.ERROR and "OUTPUT_CLAMP" in x.getMessage() + for x in log_i)) +check("...and the status row is amber, not red", + any(c["warn"] and "LOOP AT INTEGRATOR BOUND" in c["text"] for c in red_i) + and not any(not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] + for c in red_i)) + +# --- 9b. the genuine over-rating: integrator_max_w above max_w ---------------- +ticks_o, hass_o, ctl_o, red_o, log_o = s40_run(9000.0, 12, track=True, + integrator_max_w=9000) +over = [(d, t, r) for d, t, r, e in ticks_o + if e and d is not None and d.clamped] +for d, t, r in over[:2]: + print(f" tick: requested {_f(d, 'requested_w'):+.0f} clamped {_f(d, 'clamped_w'):+.0f}" + f" i_w {d.i_w:+.0f} self.target {t:+.0f}\n -> {r}") +check("PRECONDITION: the output clamp engaged on a tick where the slew limit " + "rewrote the command AND the integrator differs from the request", + any(t != _f(d, 'clamped_w') and d.i_w != _f(d, 'requested_w') for d, t, r in over)) +check("the over-rating KEEPS the BUG SIGNAL", + over and all("BUG SIGNAL" in r for d, t, r in over)) +check("defect 2: it quotes the requested COMMAND of that tick, not i_w", + over and all(f"computed {_f(d, 'requested_w'):+.0f} W" in r for d, t, r in over)) +check("defect 3: 'clamped to' is the clamp's own result, not self.target", + over and all(f"clamped to {_f(d, 'clamped_w'):+.0f} W" in r for d, t, r in over)) +check("...and the 14 768 W rationale is still in its ERROR", + any(x.levelno == logging.ERROR and "14 768 W" in x.getMessage() + for x in log_o)) +check("...under the 'exceeded the rating' title, with a red status row", + clamp_notes(hass_o) + and all("exceeded the rating" in n["title"] for n in clamp_notes(hass_o)) + and any(not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] + for c in red_o)) + +# --- 9c. the text, directly, and the two budgets ------------------------------- +from app.clamp import loop_clamp_note # noqa: E402 + +d_at = compute(prev_w=1000.0, grid_w=9000.0, actual_w=1000.0, + tuning=Tuning(max_w=5000.0, slew_w=1000.0, gain=0.6), i_w=4500.0) +check(f"exactly at the rating ({d_at.i_bound_w:+.0f} W) is 'reached', never " + f"'above' - {loop_clamp_note(d_at)!r}", + d_at.i_clamped and not d_at.clamped and abs(d_at.i_bound_w) == 5000.0 + and "above" not in loop_clamp_note(d_at)) +check("a healthy decision produces no text", + loop_clamp_note(compute(0.0, 100.0, 0.0, Tuning(max_w=5000.0))) == "") + +# Anti-windup notices must never spend the budget a BUG SIGNAL needs. +wd = ClampWatchdog() +fired_w = wd.note(True, "wind", T0, bug=False) +fired_b = wd.note(True, "bug", T0 + timedelta(seconds=5), bug=True) +wd.note(True, "wind again", T0 + timedelta(seconds=10), bug=False) +check("an anti-windup notice does not delay a bug in the same episode, and " + "does not overwrite its text", + fired_w and fired_b and wd.bug and wd.reason == "bug") +wd2 = ClampWatchdog() +seq = [wd2.note(True, "b", T0 + timedelta(seconds=5 * i)) for i in range(40)] +check("bug-only cadence is unchanged: rising edge, then every REASSERT_S", + seq[0] and sum(seq) == 1 + int(5 * 39 // REASSERT_S)) + + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") -- 2.54.0 From 55a6d5dcdb01eb50614f0271d0656df12e14172f Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sat, 26 Sep 2026 23:08:44 +0200 Subject: [PATCH 026/105] SAFETY-40 review: integrator-bound WARNING gets its own notification id A later anti-windup notice could replace a write-path BUG SIGNAL notice under the shared goodwe_output_clamp id (escalation ignores the budget). The WARNING now uses goodwe_integrator_bound and points to DOCS; the cadence sentence in DOCS is corrected. Tests pin both ids (red on fd14569). Co-Authored-By: Claude Opus 5.5 --- ...AFETY-40-the-integrator-bound-is-not-a-bug.md | 6 ++++-- goodwe_controller/DOCS.md | 14 ++++++++------ goodwe_controller/app/main.py | 9 ++++++--- goodwe_controller/test_clamp.py | 16 ++++++++++++---- goodwe_controller/test_freeze.py | 5 +++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md b/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md index 2a41f95..521c806 100644 --- a/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md +++ b/goodwe_controller/DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md @@ -2,7 +2,7 @@ **Decision.** `i_clamped` (the integrator reaching `integrator_max_w`, i.e. anti-windup) keeps alarming through the same `ClampWatchdog`: it is counted, -notified on the same id and cadence, and escalates on a sustained run +notified on the same cadence, and escalates on a sustained run (SAFETY-41). It gets its own text, a `WARNING` and an amber status row. Only `clamped` (a command over `max_w`) and write-path clamps keep the BUG SIGNAL, the `ERROR` and the red row. @@ -16,7 +16,9 @@ say less." **Why a bug has its own budget.** A genuine over-rating must not wait up to `REASSERT_S` behind anti-windup notices. `ClampWatchdog` tracks a separate `last_bug_alarm`, and a bug's text is never overwritten by later anti-windup -text within an episode. With only bug engagements, the cadence is the same as +text within an episode. Across episodes the WARNING uses its own +notification id (`goodwe_integrator_bound`), so it cannot replace a BUG SIGNAL +notice still on screen (review of #130). With only bug engagements, the cadence is the same as before (`test_clamp.py` part 9). **Numbers.** They come from the `Decision` of the clamping tick (`i_bound_w`, diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index ecdd5cc..a4a7faf 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1641,10 +1641,10 @@ other guard's entries out of it. **There is nothing to configure**, deliberately. The bound is `max_w`, which you already set; giving the guard a limit of its own would be a second number that can disagree with the first, which is exactly the failure the startup validation -exists to prevent. The alarm's cadence - at most one notification per 150 s -(an episode that has not yet notified does so once it has engaged 3 cycles in -a row), cleared after 3 clean -cycles - is fixed for the same reason `RAIL_FRAC` is: it describes the +exists to prevent. The alarm's cadence - normally at most one notification per +150 s (an episode that has not yet notified does so once it has engaged 3 +cycles in a row, and an over-rating has its own 150 s budget), cleared after 3 +clean cycles - is fixed for the same reason `RAIL_FRAC` is: it describes the notification bus, not the plant. WARNING: **on a default install the engagement you will see is the integrator's, @@ -1657,10 +1657,12 @@ every standard configuration. **The integrator bound is not a bug, and it is reported as what it is.** It reads *"the loop's integrator reached its +5000 W anti-windup bound; the loop's command this cycle was +2000 W"*, titled *"the control loop is at its integrator -bound"*, logged as a `WARNING`, with an amber (not red) status row. Brief +bound"*, logged as a `WARNING`, with an amber (not red) status row and its own +notification (`goodwe_integrator_bound`), so it never replaces a BUG SIGNAL +notice still on screen. Brief engagements after a large load or solar step are normal. If it stays engaged, check that the battery is following its commands. Only a command over the rating -carries the BUG SIGNAL text, and it never waits behind integrator-bound notices. +carries the BUG SIGNAL text, and it has its own notification budget. Why: [`DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md`](DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md). ### The frozen-meter alarm diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index a60afb5..e8160d4 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -3762,14 +3762,17 @@ class Controller: return if not self.clamp_wd.bug: # SAFETY-40: the integrator bound is anti-windup, not a bug - a - # WARNING and a plainly titled notice, same id and cadence. + # WARNING and a plainly titled notice, same cadence. Its OWN id, so + # it can never replace a BUG SIGNAL notice still on screen. _LOG.warning("SAFETY-03 - %s Engagements so far: %d.", self.clamp_wd.reason, self.clamp_wd.engagements) await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_output_clamp", + "notification_id": "goodwe_integrator_bound", "title": "GoodWe: the control loop is at its integrator bound", "message": (f"{self.clamp_wd.reason}\n\nNo command exceeded " - f"the rating and the controller is STILL RUNNING."), + f"the rating and the controller is STILL RUNNING. " + f"See the add-on documentation, 'The winding-loop " + f"alarm'."), }) return _LOG.error( diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index be9df87..d6dcdf6 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -102,6 +102,9 @@ T0 = datetime(2026, 8, 30, 9, 0, 0, tzinfo=timezone.utc) # which is also the device rating, so this is the bound the alarm is written at. LIVE_MAX_W = 5000.0 CLAMP_ID = "goodwe_output_clamp" +# SAFETY-40: the integrator-bound WARNING has its own id, so it can never +# replace a BUG SIGNAL notice still on screen. +BOUND_ID = "goodwe_integrator_bound" def check(name, cond): @@ -461,7 +464,7 @@ def wired(grid, cycles=40, batt=0.0, track=True, **over): def clamp_notes(hass): return [d for dom, svc, d in hass.calls if (dom, svc) == ("persistent_notification", "create") - and d.get("notification_id") == CLAMP_ID] + and d.get("notification_id") in (CLAMP_ID, BOUND_ID)] # THE 10.3 RUNAWAY, replayed. "With the inverter switched off entirely, an @@ -500,8 +503,9 @@ print(f" the loop clamped on {ctl_r.clamp_wd.engagements} of {60} cycles, " f"notification(s)") check("AC 3: and it ALARMED - silently clipping this is the defect", ctl_r.clamp_wd.engagements > 0 and len(notes_r) >= 1) -check("...with its own notification_id, not shared with any other guard", - all(d["notification_id"] == CLAMP_ID for d in notes_r)) +check("...with its own notification_id, not shared with any other guard - " + "on a default install the integrator bound's (SAFETY-40)", + all(d["notification_id"] == BOUND_ID for d in notes_r)) check("...one episode, re-asserted rather than one per cycle", ctl_r.clamp_wd.episodes == 1 and len(notes_r) < ctl_r.clamp_wd.engagements) # SAFETY-40: on a default install this runaway is the INTEGRATOR bound, so it @@ -1971,6 +1975,9 @@ notes_i = clamp_notes(hass_i) check("it still NOTIFIES (not suppressed), under a title that claims no bug", notes_i and all("integrator bound" in n["title"] and "exceeded" not in n["title"] for n in notes_i)) +check("...under its OWN notification_id, so it cannot replace a BUG SIGNAL " + "notice still on screen", + notes_i and all(n["notification_id"] == BOUND_ID for n in notes_i)) check("...logged as a WARNING, not an ERROR", any(x.levelno == logging.WARNING and "anti-windup" in x.getMessage() for x in log_i) @@ -2003,7 +2010,8 @@ check("...and the 14 768 W rationale is still in its ERROR", for x in log_o)) check("...under the 'exceeded the rating' title, with a red status row", clamp_notes(hass_o) - and all("exceeded the rating" in n["title"] for n in clamp_notes(hass_o)) + and all("exceeded the rating" in n["title"] + and n["notification_id"] == CLAMP_ID for n in clamp_notes(hass_o)) and any(not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] for c in red_o)) diff --git a/goodwe_controller/test_freeze.py b/goodwe_controller/test_freeze.py index a5e0f00..661113d 100644 --- a/goodwe_controller/test_freeze.py +++ b/goodwe_controller/test_freeze.py @@ -835,7 +835,8 @@ frozen_rows = [c for c in ctl_f.checks() if "METER MAY BE FROZEN" in c["text"]] print(f" frozen at +4000 W: command ran to {ctl_f.target:.0f} W, " f"{len(notes)} notification(s), {len(frozen_rows)} red status row(s)") # SURFACE-WIDE, deliberately, and the second guard has now landed. SAFETY-03 -# ships `goodwe_output_clamp`, and this scenario - a runaway loop winding into +# ships `goodwe_output_clamp` (and, for the integrator bound on a default +# install, `goodwe_integrator_bound` - SAFETY-40), and this scenario - a runaway loop winding into # the rail - raises it legitimately: the loop asks for more than the rating and # is clamped. So the answer to "is this scenario still meant to raise exactly # one alarm" is NO, it raises exactly two, and BOTH ARE NAMED here rather than @@ -846,7 +847,7 @@ _ids = sorted(d.get("notification_id") for d in all_notes) print(f" the whole notification surface this run: {_ids}") check("the whole notification surface carried exactly two alarms this run - " "SAFETY-18's and SAFETY-03's, both named", - _ids == ["goodwe_meter_frozen", "goodwe_output_clamp"]) + _ids == ["goodwe_integrator_bound", "goodwe_meter_frozen"]) # THIS GUARD'S, keyed on the id. check("...and the freeze detector is the one that raised it", len(notes) == 1) # ⚠️ Selected by TEXT, not by id - see notes_by_text_of(). One of the two -- 2.54.0 From 50ccea3dd711efd5f2dbb2a408f87271ef6d4d30 Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Sun, 27 Sep 2026 01:00:54 +0200 Subject: [PATCH 027/105] UX-08 phase 2a: short, plain notifications, and a ratchet for the rest Every HA notification the add-on raises now has a title of at most 5 everyday words and a one-sentence body; a red alarm may use three so no action is lost. The texts live in app/messages.py, the rule in STYLE.md, and the detail that moved out in DOCS.md "Notifications", which each body links to. No notification_id, trigger or cadence changed. test_messages.py enforces the rule on every notification, fails any notification worded outside app/messages.py, and ratchets the kinds not yet rewritten (rows, banners, refusals, logs, options) through a shrinking allowlist of 200. Six tests re-pinned from prose to meaning. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 48 +++ .../DECISIONS/UX-08-short-notifications.md | 14 + goodwe_controller/DOCS.md | 113 +++++ goodwe_controller/app/clamp.py | 7 +- goodwe_controller/app/main.py | 177 ++------ goodwe_controller/app/messages.py | 245 +++++++++++ goodwe_controller/test_clamp.py | 51 ++- goodwe_controller/test_delivery.py | 3 +- goodwe_controller/test_freeze.py | 18 +- goodwe_controller/test_messages.py | 402 ++++++++++++++++++ goodwe_controller/test_peakguard.py | 37 +- goodwe_controller/test_watchdog.py | 33 +- goodwe_controller/ux08_allowlist.txt | 207 +++++++++ 13 files changed, 1170 insertions(+), 185 deletions(-) create mode 100644 STYLE.md create mode 100644 goodwe_controller/DECISIONS/UX-08-short-notifications.md create mode 100644 goodwe_controller/app/messages.py create mode 100644 goodwe_controller/test_messages.py create mode 100644 goodwe_controller/ux08_allowlist.txt diff --git a/STYLE.md b/STYLE.md new file mode 100644 index 0000000..f5ea0d5 --- /dev/null +++ b/STYLE.md @@ -0,0 +1,48 @@ +# STYLE.md - how user-facing text is written (UX-08) + +This applies to everything a home owner or installer reads: notifications, phone pushes, the add-on page, refusals, add-on log lines at WARNING and above, and the names and descriptions of options. It is enforced by `goodwe_controller/test_messages.py`. Kinds that have not been rewritten yet are on its allowlist, and that allowlist only shrinks. + +## 1. Shape +- **Title**: at most 5 everyday words. It says what is wrong ("Meter reading may be stuck"). No "GoodWe:" prefix, no full stop. +- **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. +- **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. +- **Status row**: at most 15 words. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. +- **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. +- **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets. These translate well into Dutch and French. + +## 2. Numbers +Use a number only if it helps the reader act, for example the peak limit, or what was asked and what was sent in a fault report. Write it the way `app/messages.py` does: `5 000 W`, `20 %`, `10 minutes`, `14:05`. + +## 3. Severity +Severity is shown by the title and the colour, never by CAPITALS or by words like "BUG SIGNAL". + +| Level | Colour | When | +|---|---|---| +| alarm | red | Control stopped, money or energy lost now, a fault, or a person must act now. Up to 3 sentences. | +| warning | orange | Control is still running, but something needs a look. 1 sentence. | +| info | grey | No action needed. 1 sentence. | +| resolved | green | An earlier alarm or warning has cleared. 1 sentence. | + +A rewrite never changes an alarm's severity, `notification_id` or cadence. + +## 4. Words - the same word for the same thing everywhere +| Say | Not | +|---|---| +| battery | pack, BMS pack | +| inverter, or its name | unit, device, actuator | +| controller | loop, planner | +| meter | P1 feed, telegram | +| peak limit / this month's peak | ceiling, capaciteitstarief, billed quarter | +| 15-minute period | quarter | +| battery level | SoC, state of charge | +| cut-out level | BMS floor, `bms_soc_floor` | +| peak reserve | `peak_soc_floor`, EMS floor | +| inverter rating | `max_w`, rail | +| control is stopped / every inverter is set to 0 W | failsafe, trip, latch, parked | +| software fault | BUG SIGNAL | +| control board | master, ESP32 | +| shadow mode | a mode that makes every decision but commands 0 W. The name is kept. | + +**Banned in titles and bodies** (the test fails on them): SAFETY-/TARIFF-/TEL-/CFG-/FW-/HW-nn and other card ids, integrator, anti-windup, windup, clamp, clamped, saturated, BUG SIGNAL, latch, latched, arbiter, allocator, register, `0x…`, layer 1/2/3, heartbeat, watchdog, telegram, ACK, CRC, OTA, Modbus, planner, `§n`, file names, IP addresses, option keys in snake_case, **HA entity ids**, and runs of 2 or more CAPITALISED words. + +HA entity ids are allowed only in refusals and validator messages, where the installer has to find that entity. They are never allowed in alarms or status rows. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md new file mode 100644 index 0000000..ce6648f --- /dev/null +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -0,0 +1,14 @@ +# UX-08 phase 2a: short notifications, and what moved out of them + +The owner decided on 2026-09-27: a title of at most about 5 everyday words and a one-sentence body. A red safety alarm may use up to 3 sentences, so no action-relevant information is lost. Titles are neutral, with no "GoodWe:" prefix. HA entity ids appear only in refusals. The rule is `STYLE.md` at the repository root, the texts are in `app/messages.py`, and `test_messages.py` enforces both. The detail each notification used to carry is in DOCS.md under "Notifications", and the body links to it. + +**Unchanged:** every `notification_id`, every trigger and cadence (edges, SAFETY-34 re-announce, per-unit ids), every log line and every status row. The status banner and rows are phase 2b, refusals and option texts 2c, logs 2d; `ux08_allowlist.txt` lists them until then. + +## Where a choice was made +1. **Severity of "not delivering" (SAFETY-42).** The notification is an *alarm*, so it may use 3 sentences. Its log line is ERROR and the alarm is latched. The page banner stays amber, as SAFETY-42 decided, because control keeps running. The three checks stay in their original order. +2. **Figures left the bodies** of the frozen-meter card (the rail and the command), the circulating-power card (the watts and the time window) and the peak cards (the projection). None of them is needed to act, and all of them are still in the reason text that the log line and the status row carry. `test_freeze.py` and `test_watchdog.py` now pin that. The frozen-meter card can therefore no longer quote a wrong rail (SAFETY-20), because it quotes none. +3. **The over-rating alarm keeps its numbers** (asked, sent, and which limit cut it), because they are what a fault report needs. `ClampWatchdog.facts` carries them under the same keep-the-bug rule as `reason`, so the words and the numbers always describe the same tick, with asked before sent (SAFETY-40, `test_clamp.py` part 6). +4. **SAFETY-25 stays in the peak-reserve alarm** as its last sentence ("the reserve only limits peak shaving … down to its cut-out level"). The alarm now gives each branch its own action: at the reserve, lower it; reserve not set, set one; battery level unread, check the sensor. Before, every branch said "lower peak_soc_floor". +5. **SAFETY-32 at a roster of one.** The body no longer ends in a separate "WHICH PACK" paragraph. The pack's name is part of the first sentence ("The battery of inverter-b …"), and at a roster of one that is the only difference. +6. **Dropped as background, now in DOCS:** "charging stays blocked" (peak reserve), "why no other guard fired" (circulating power, not delivering), and the saturation-freeze distinction (over-rating). "The meter cannot see this" stays in the circulating-power card, as the owner asked. +7. **The Details link** opens the add-on's documentation page (`/hassio/addon/<slug>/documentation`, with the slug taken from the container hostname) and names the section, because Home Assistant does not render heading anchors there. Outside an add-on container it names the section without a link. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index a4a7faf..5c9cda5 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2802,6 +2802,119 @@ it. | `estop_fitted` | Whether the RS485 e-stop is installed. Drives the warning banner | | `log_level` | `trace`/`debug`/`info`/`warning`/`error` | +## Notifications + +Each Home Assistant notification this add-on raises has a short title, one +sentence (a red alarm may use three), and a **Details** link to the add-on +documentation that names the section below. This section holds what the +notification leaves out. The wording rule is `STYLE.md` in the repository; the +texts live in `app/messages.py`. Every notification keeps a fixed +`notification_id`, so a repeat replaces the card instead of adding one. + +| Title | Severity | id | +|---|---|---| +| Battery is not keeping up | warning | `goodwe_integrator_bound` | +| Power request too high | alarm | `goodwe_output_clamp` | +| Load too high for battery | alarm | `goodwe_peak_saturated` | +| Battery at its peak reserve | alarm | `goodwe_peak_soc_floor` | +| Inverters working against each other | alarm | `goodwe_circulating_power` | +| *name* is not delivering | alarm | `goodwe_not_delivering_<name>` | +| Meter reading may be stuck | alarm | `goodwe_meter_frozen` | + +### Battery is not keeping up + +The grid-following loop's integrator reached its anti-windup bound +(`integrator_max_w`): the controller has been asking for more than the battery +delivers for a while. This is SAFETY-40, and it is **not** a fault. No command +went over the rating and control keeps running. Short spells after a big load +or solar step are normal. If it keeps coming back, check that the battery +follows its commands. The bound and the command of that tick are in the add-on +log (WARNING, reason code `OUTPUT_CLAMP`). See *The winding-loop alarm* for the +full story. + +### Power request too high + +The controller computed a command above a limit, and the command was cut to that +limit before it was written. The notification names what was asked, what was +sent, and which limit cut it: the configured inverter rating (`max_w`), the +inverter's own limit (the setpoint device's range), or the inverter rating on +the loop side. Asked always comes first. This is a **software fault** (the old +wording was "BUG SIGNAL"). It is not the inverter failing to follow a legal +command, which is the saturation freeze and does not alarm. Control keeps +running. Report it with the add-on log, whose ERROR line carries the reason code +`OUTPUT_CLAMP` and the full figures. See *The winding-loop alarm*. + +### Load too high for battery + +The capacity-peak guard (SAFETY-07) is asking for everything the inverter can +discharge, and the running 15-minute average is still projected over the peak +limit. That 15-minute period will set or raise the month's billed peak +(capaciteitstarief). The controller is not at fault: the house load is larger +than the inverter. Switching off load in the next few minutes is the only thing +that still changes the bill. The projection and the watts are in the add-on log +and on the status page. See *The capacity-peak guard*. + +### Battery at its peak reserve + +The peak guard wanted to discharge to hold the 15-minute peak, but it may not go +below the peak reserve (`peak_soc_floor`, SAFETY-24). It also stops when the +battery level cannot be read, or when no reserve is set. So this 15-minute +period will go over the peak limit and set or raise the month's billed peak. +Charging from the grid stays blocked meanwhile. On a site with several inverters +the notification names the battery at its limit (SAFETY-32): each battery is +graded against its own cut-out level (`bms_soc_floor`), and raising the other +batteries' settings will not change this one. + +⚠️ **The reserve binds the peak guard only (SAFETY-25).** It is not a +whole-battery reserve. Ordinary self-consumption has no such floor and goes on +discharging below it, down to the battery's own cut-out level. See *What +`peak_soc_floor` does not protect*. + +### Inverters working against each other + +Two inverters were pushing power into each other: one discharging while another +charged (SAFETY-31). **The meter cannot see this.** The two flows cancel at the +P1 meter, so the site reads idle while both batteries cycle through two +conversion stages. Every other guard reads that net figure, so none of them +fires. The add-on has **stopped control and commands 0 W on every inverter**. +If the grid reading does not move after that, one inverter is no longer +listening to the add-on; this has happened on this hardware, once for +6 h 25 min. Switch the inverters off at the isolator. The alarm is latched: a +Home Assistant or add-on restart does not clear it, and the card is raised +again every 5 min until you start control on the add-on page. The watts and the time +window are in the add-on log and on the status page. See *The circulating-power +alarm*. + +### An inverter is not delivering + +One inverter has stood well short of its share of the site target for longer +than the hold time (SAFETY-42), while the others have not. No other check sees +this. A unit at 0 W is absent rather than pushing the wrong way, so the per-unit +sign check and the circulation check stay quiet. **Nothing is commanded +differently.** The guard only reports: commanding an inverter that has stopped +listening achieves nothing, and the only fallback the add-on has is +all-or-nothing. The other inverters keep regulating, and the site is short by up +to the missing unit's rating. Check, in this order: + +1. Is the inverter answering on RS485 at all? +2. Is its battery colder or emptier than its configured cut-out level + (`bms_soc_floor`) says? If so, that setting does not describe this battery. +3. Is anything else writing to it? + +The alarm is latched and survives restarts; start control on the add-on page +once you know why. See *A unit that stops DELIVERING is a third fault again*. + +### Meter reading may be stuck + +The meter keeps answering, but its value has not changed for longer than the +hold time while the command stands at the power limit (SAFETY-18). The loop is +regulating against a number that has stopped moving. The age is still fresh, so +no other guard stops it. This is an alarm only: control keeps running and keeps +following the reading. Held for a whole 15-minute period, it can set the month's +billed peak. Check the meter; if it is stuck, stop control on the add-on page. +The limit and command figures are in the add-on log and on the status page. See +*The frozen-meter alarm*. + ## The Web UI The ingress panel shows live values, why the controller is commanding what it diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index e25a704..9f8bda7 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -362,6 +362,9 @@ class ClampWatchdog: self.since: datetime | None = None self.last_alarm: datetime | None = None self.reason = "" + # UX-08: the numbers behind `reason`, for the notification - set under + # the same rule as `reason`, so both always describe the same tick. + self.facts = () self.clean_cycles = 0 # SAFETY-41. Consecutive engaged cycles, and whether THIS episode has # spoken yet - the two the escalation clause needs. @@ -386,7 +389,7 @@ class ClampWatchdog: return True def note(self, engaged: bool, reason: str, now: datetime, - bug: bool = True) -> bool: + bug: bool = True, facts=()) -> bool: """Advance one cycle. True when the caller should raise the alarm. `now` is the caller's clock, the same discipline as @@ -408,6 +411,7 @@ class ClampWatchdog: self.bug_spoken = False if bug or not self.bug: self.reason = reason + self.facts = tuple(facts) self.bug = self.bug or bug if bug and not self.bug_spoken and self._due(self.last_bug_alarm, now): return self._speak(now, True) @@ -465,6 +469,7 @@ class ClampWatchdog: # above. The episode ends; the notification budget does not reset # with it. self.reason = "" + self.facts = () self.bug = False self.clean_cycles = 0 return False diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index e8160d4..85115f4 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -53,6 +53,7 @@ from .clamp import ( clamp_to_rating, is_commandable, loop_clamp_note, ) from . import freshness +from . import messages from .freeze import ( FreezeWatchdog, FreezeWatchdogConfig, looks_frozen, rail_unreachable, rail_w, ) @@ -997,6 +998,8 @@ class Controller: # the value a clamp bit is a value written to ONE device. # (engaged, note, over_rating) - SAFETY-40 splits the last one out. self.loop_clamped: tuple[bool, str, bool] = (False, "", False) + # UX-08: the numbers of a loop-side over-rating, for the notification. + self.loop_clamp_facts: tuple = () self.stopping = False # SAFETY-61. time.monotonic() at the end of the last run_control() pass. self.loop_pass_mono = None @@ -3280,6 +3283,9 @@ class Controller: loop_clamp_note(decision), decision.clamped, ) + self.loop_clamp_facts = ( + (messages.Clamp(None, decision.requested_w, decision.clamped_w, + "rating"),) if decision.clamped else ()) # SITE. compute() regulates `grid_w` - the P1 measurement - to # zero. Its subject is the meter, and §6.2's architecture is ONE # integrator on P1 whose output is then SPLIT. This is the claim the @@ -3303,6 +3309,7 @@ class Controller: # rather than letting the last value stand is what makes the alarm # de-assert when control is stopped. self.loop_clamped = (False, "", False) + self.loop_clamp_facts = () # SAFETY-28. A new resolution is a new tick, and the previous record is # stale from this line onwards. Incremented BEFORE resolve() so that the @@ -3726,10 +3733,17 @@ class Controller: if engaged_write: reason = (", ".join(f"{inv.name}: {inv.clamp_last.describe()}" for inv in clamped_units) + ". " + CLAMP_BUG_SIGNAL) + _named = len(self.inverters) > 1 + facts = [messages.Clamp(inv.name if _named else None, + inv.clamp_last.requested_w, + inv.clamp_last.applied_w, + inv.clamp_last.bound) + for inv in clamped_units] else: reason = loop_note if engaged else "" + facts = self.loop_clamp_facts if engaged else () fired = self.clamp_wd.note(engaged, reason, datetime.now(timezone.utc), - bug=bug) + bug=bug, facts=facts) # --- THE ACTION LOG, AND IT IS COALESCED PER EPISODE ------------------ # Every engagement is recorded, but consecutive ones are recorded by @@ -3766,14 +3780,8 @@ class Controller: # it can never replace a BUG SIGNAL notice still on screen. _LOG.warning("SAFETY-03 - %s Engagements so far: %d.", self.clamp_wd.reason, self.clamp_wd.engagements) - await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_integrator_bound", - "title": "GoodWe: the control loop is at its integrator bound", - "message": (f"{self.clamp_wd.reason}\n\nNo command exceeded " - f"the rating and the controller is STILL RUNNING. " - f"See the add-on documentation, 'The winding-loop " - f"alarm'."), - }) + await self.hass.call("persistent_notification", "create", + messages.loop_bound().data()) return _LOG.error( "SAFETY-03 - %s Silently clipping this is how a winding integrator " @@ -3785,16 +3793,10 @@ class Controller: # A fixed notification_id, for the reason check_meter_frozen() gives - # and a DIFFERENT one from every other alarm this add-on raises, because # a clamp is not a frozen meter and neither is a saturation freeze. - await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_output_clamp", - "title": "GoodWe: a computed setpoint exceeded the rating", - "message": ( - f"{self.clamp_wd.reason}\n\nThe command has been clamped and " - f"the controller is STILL RUNNING. This is NOT the inverter " - f"failing to follow a legal command (that is the saturation " - f"freeze, which is normal and does not alarm) - the value asked " - f"for was itself out of range."), - }) + # UX-08: the words are messages.output_clamp()'s; the numbers are the + # ones `reason` was written from (ClampWatchdog.facts), asked first. + await self.hass.call("persistent_notification", "create", + messages.output_clamp(self.clamp_wd.facts).data()) async def check_peak_saturated(self) -> None: """SAFETY-07. Alarm ONLY when the guard has run out of inverter. @@ -3836,18 +3838,8 @@ class Controller: # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A saturated peak guard # is not a frozen meter and is not an out-of-range setpoint. - await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_peak_saturated", - "title": "GoodWe: the capacity-peak guard has run out of inverter", - "message": ( - f"{g.reason}.\n\nThe battery is being commanded to everything " - f"it can give and the quarter is STILL projected over the " - f"{g.ceiling_w:.0f} W ceiling, so this quarter will set or raise " - f"the month's billed capaciteitstarief peak. This is not a " - f"controller fault - the load is simply larger than the " - f"inverter. Shedding load in the next few minutes is the only " - f"thing that changes the bill."), - }) + await self.hass.call("persistent_notification", "create", + messages.peak_saturated(g.ceiling_w).data()) async def check_peak_floor_limited(self) -> None: """SAFETY-24. Alarm when the EMS SoC floor stops the guard shaving. @@ -3912,45 +3904,23 @@ class Controller: # think the pack is AT it. `decide()` guards its own reason string the # same way; a f-string that formats a None here would turn the one # notification that matters into a traceback. - _at_floor = ("at the floor" if g.soc_floor is None - else f"at {float(g.soc_floor):.0f} %") # ⚠️ SAFETY-32. WHICH PACK STOPPED THE SITE. `g.soc_floor` is the floor # the decision was actually taken with, so this re-grades nothing and # cannot disagree with the alarm it is printed inside. At a roster of one - # the sentence is omitted entirely and this notification is byte-for-byte - # what SAFETY-25 shipped - there is exactly one pack and naming it would - # be noise on every existing install. + # no pack is named - there is exactly one. _blocked = [name for name, why in peakguard.pack_permissions(self.packs, g.soc_floor) if why is not None] - _which = ("" if len(self.inverters) < 2 else - f"\n\nSAFETY-32 - WHICH PACK: this is graded per pack against " - f"that pack's own BMS cut-out (bms_soc_floor), and the " - f"pack(s) at or below their own floor right now are " - f"{', '.join(_blocked) if _blocked else '(none - see the reason above)'}" - f". The other packs on the roster are not the reason the guard " - f"stopped and raising their cut-out will not change this.") - await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_peak_soc_floor", - "title": "GoodWe: the capacity-peak guard has run out of battery", - "message": ( - f"{g.reason}.\n\nTHIS QUARTER WILL GO OVER THE " - f"{g.ceiling_w:.0f} W ceiling and will set or raise the " - f"month's billed capaciteitstarief peak, because the peak guard " - f"is not allowed to discharge any further: {g.soc_floor_reason}." - f" This is not a controller fault - it is the EMS-side energy " - f"floor (peak_soc_floor) doing what it is set to do, and it sits " - f"deliberately above the pack's own BMS cut-out. Charging stays " - f"blocked. Shedding load is the only thing that changes the bill " - f"now; if this pack can afford a deeper discharge, lower " - f"peak_soc_floor.\n\nSAFETY-25 - WHAT THIS FLOOR IS NOT: " - f"peak_soc_floor bounds THE PEAK GUARD ONLY. It is not a " - f"pack-wide reserve, and the battery is NOT being held " - f"{_at_floor} - ordinary self-consumption has no SoC " - f"floor at all and will go on discharging past it, down to the " - f"pack's own BMS cut-out. What has stopped is the guard buying " - f"you a lower bill, not the pack being spent." + _which), - }) + # ⚠️ SAFETY-25's sentence (the reserve binds the peak guard only) is + # part of messages.peak_reserve() on every branch, the unreadable-SoC + # one included. + await self.hass.call("persistent_notification", "create", + messages.peak_reserve( + g.ceiling_w, soc_unread=g.soc is None, + reserve_unset=(g.soc is not None + and g.soc_floor is None), + packs=(_blocked if len(self.inverters) > 1 + else ())).data()) async def check_circulating(self) -> None: """SAFETY-31 + SAFETY-34. The alarm, and it must survive a restart. @@ -3989,36 +3959,13 @@ class Controller: names = self.units pos, neg = opposing([inv.batt for inv in self.inverters], min_w=self.circ_wd.cfg.min_w / 2.0) - who = "" - if pos and neg: - who = ("\n\nRight now " + ", ".join(names[i] for i in pos) - + " is discharging while " + ", ".join(names[i] for i in neg) - + " charges.") # A fixed notification_id, and a DIFFERENT one from every other alarm - # this add-on raises - check_meter_frozen() gives the reasoning. A - # circulating loop is not a frozen meter, is not an out-of-range - # setpoint and is not a saturated peak guard. - await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_circulating_power", - "title": "GoodWe: the inverters are pushing against each other", - "message": ( - f"{self.circ_wd.reason}{who}\n\nTHE METER CANNOT SEE THIS. " - f"Circulating power nets to zero at P1, so the site reads idle " - f"while the packs are cycled through two conversion stages " - f"continuously. Every other guard in this add-on is a consumer " - f"of that net figure, which is why none of them fired.\n\n" - f"CONTROL HAS BEEN STOPPED - every inverter is commanded 0 W " - f"and held there. That removes this controller as one of the " - f"two participants, and it makes anything still happening " - f"VISIBLE at the meter instead of cancelled at it.\n\n" - f"⚠️ IF THE GRID READING DOES NOT MOVE AFTER THIS, one inverter " - f"is no longer listening to this add-on and no command will " - f"reach it - that has happened twice on this hardware, once for " - f"6 h 25 m. The remaining actuator is a human at the isolator.\n" - f"\nThis alarm survives a Home Assistant restart. Restarting " - f"will not clear it; start control from the add-on UI once you " - f"know why two inverters were opposing."), - }) + # this add-on raises - check_meter_frozen() gives the reasoning. + await self.hass.call("persistent_notification", "create", + messages.circulating( + [names[i] for i in pos] if pos and neg else (), + [names[i] for i in neg] if pos and neg else (), + ).data()) def _reannounce_due(self, notification_id: str) -> bool: """SAFETY-34: has this latched alarm gone REANNOUNCE_S without being re-asserted?""" @@ -4075,38 +4022,8 @@ class Controller: # surface is best-effort by design. self._delivery_announced.add(inv.name) self._announced_mono[nid] = _mono() - peers = ", ".join(n for n in names if n != inv.name) or "no sibling" - await self.hass.call("persistent_notification", "create", { - "notification_id": nid, - "title": f"GoodWe: {inv.name} is not delivering its share", - "message": ( - f"{inv.delivery_wd.reason}\n\nWHY NOTHING ELSE SAID SO. A " - f"unit sitting at 0 W against a non-zero share is not " - f"pushing the wrong way, it is ABSENT: the per-unit sign " - f"check needs opposition on both sides of " - f"{self.unit_sign_cfg.min_w:.0f} W and never opens, the " - f"site sum still agrees with the meter in " - f"direction, and circulating power is exactly zero when one " - f"unit does nothing. The only other trace is a saturation " - f"freeze, which this add-on's own code calls an alarm " - f"operators learn to ignore.\n\nNOTHING HAS BEEN COMMANDED " - f"DIFFERENTLY. This guard reports and does not act. " - f"Commanding an inverter that has stopped listening " - f"achieves nothing - that has happened on this hardware, " - f"once for 6 h 25 m - and the only re-allocation this " - f"add-on can express is all-or-nothing, which would throw " - f"away the output of a unit that is delivering PART of its " - f"share. So {peers} is still regulating and the site is " - f"short by up to {inv.rating_w():.0f} W until somebody " - f"looks at {inv.name}.\n\nWHAT TO CHECK, in order: is " - f"{inv.name} answering on RS485 at all; is its pack colder " - f"or emptier than its configured bms_soc_floor says (if it " - f"is, that setting does not describe this battery and this " - f"alarm is telling you so); and is anything else writing to " - f"it.\n\nThis alarm survives a Home Assistant restart. " - f"Restarting will not clear it; start control from the " - f"add-on UI once you know why."), - }) + await self.hass.call("persistent_notification", "create", + messages.not_delivering(inv.name, slug).data()) async def check_meter_frozen(self) -> None: """SAFETY-18. Alarm on a meter that answers forever without changing. @@ -4144,14 +4061,8 @@ class Controller: # ⚠️ A fixed notification_id, so a second episode REPLACES the first # rather than stacking. An operator who has to dismiss eleven identical # notifications learns to dismiss the twelfth without reading it. - await self.hass.call("persistent_notification", "create", { - "notification_id": "goodwe_meter_frozen", - "title": "GoodWe: the P1 meter may be frozen", - "message": ( - f"{self.freeze_wd.reason}.\n\nThe controller is STILL RUNNING " - f"and still following this reading. Check the meter; if it is " - f"stuck, stop control from the add-on UI."), - }) + await self.hass.call("persistent_notification", "create", + messages.meter_frozen(unchanged).data()) # -- tasks --------------------------------------------------------------- # -- OPT-04: the background tariff refresh ------------------------------- diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py new file mode 100644 index 0000000..38501c9 --- /dev/null +++ b/goodwe_controller/app/messages.py @@ -0,0 +1,245 @@ +"""Every Home Assistant notification this add-on raises, in plain words (UX-08). + +The rule is `STYLE.md` at the repository root; `test_messages.py` enforces it. +Titles, bodies and severities live here and nowhere else, so `main.py` only +decides WHEN to raise a notice and this file decides WHAT it says. The detail +that used to fill the bodies is in DOCS.md, under "Notifications", one section +per title; the body ends with a link to it. +""" + +import os +import re +from dataclasses import dataclass + +# Severity (STYLE.md section 3). An ALARM may use up to three sentences so +# that no action a person must take is lost; everything else gets one. +ALARM, WARNING, INFO, RESOLVED = "alarm", "warning", "info", "resolved" + +DOCS_SECTION = "Notifications" + + +def watts(value) -> str: + """`7412` -> `7 412 W`: a magnitude, grouped for reading, no sign.""" + return f"{abs(float(value)):,.0f} W".replace(",", " ") + + +def duration(seconds) -> str: + s = float(seconds) + if s < 120: + return f"{s:.0f} seconds" + return f"{s / 60:.0f} minutes" + + +def names(items) -> str: + items = list(items) + if len(items) <= 1: + return "".join(items) + return ", ".join(items[:-1]) + " and " + items[-1] + + +def addon_slug() -> str | None: + """This add-on's Supervisor slug, from the container hostname. + + The Supervisor names an add-on's host after its slug with `_` spelled `-` + (`local_goodwe_controller` -> `local-goodwe-controller`). Anything else, + e.g. a test run, gets no link rather than a wrong one. + """ + host = os.environ.get("HOSTNAME", "") + if re.fullmatch(r"[a-z0-9]+-goodwe-controller", host): + return host.replace("-", "_") + return None + + +def details(title: str) -> str: + where = f"section “{title}” under {DOCS_SECTION}" + slug = addon_slug() + if slug is None: + return f"Details: add-on documentation, {where}." + return (f"Details: [add-on documentation](/hassio/addon/{slug}/documentation)," + f" {where}.") + + +@dataclass(frozen=True) +class Notice: + id: str + severity: str + title: str + body: str + section: str = "" # the DOCS.md heading, when it is not the title itself + + @property + def docs(self) -> str: + return self.section or self.title + + def data(self) -> dict: + """The `persistent_notification.create` payload.""" + return {"notification_id": self.id, "title": self.title, + "message": f"{self.body}\n\n{details(self.docs)}"} + + +# --- the catalogue ---------------------------------------------------------- +# Each title below is also a DOCS.md heading (test_messages.py checks it). + +T_LOOP_BOUND = "Battery is not keeping up" +T_OUTPUT_CLAMP = "Power request too high" +T_PEAK_SATURATED = "Load too high for battery" +T_PEAK_RESERVE = "Battery at its peak reserve" +T_CIRCULATING = "Inverters working against each other" +T_NOT_DELIVERING = "{unit} is not delivering" +S_NOT_DELIVERING = "An inverter is not delivering" +T_METER_FROZEN = "Meter reading may be stuck" + +ID_LOOP_BOUND = "goodwe_integrator_bound" +ID_OUTPUT_CLAMP = "goodwe_output_clamp" +ID_PEAK_SATURATED = "goodwe_peak_saturated" +ID_PEAK_RESERVE = "goodwe_peak_soc_floor" +ID_CIRCULATING = "goodwe_circulating_power" +ID_NOT_DELIVERING = "goodwe_not_delivering_{slug}" +ID_METER_FROZEN = "goodwe_meter_frozen" + +# Which limit cut a command (clamp.ClampResult.bound, plus the loop's own). +LIMIT_WORDS = { + "max_w": "the configured inverter rating", + "device": "the inverter's own limit", + "max_w+device": "the configured inverter rating and the inverter's own limit", + "rating": "the inverter rating", +} + + +def loop_bound() -> Notice: + """SAFETY-40: the integrator bound. Normal in short bursts; not a fault.""" + return Notice(ID_LOOP_BOUND, WARNING, T_LOOP_BOUND, + "The battery is not following the controller; short moments " + "are normal, repeated ones need a check.") + + +@dataclass(frozen=True) +class Clamp: + """One command that was cut: what was asked, what was sent, and by what.""" + unit: str | None + asked_w: float + sent_w: float + limit: str # a key of LIMIT_WORDS + + +def output_clamp(clamps) -> Notice: + """SAFETY-03: a computed command above the limit. A software fault. + + Asked comes before sent, always - reading them the other way round turns + the alarm backwards (test_clamp.py part 6). + """ + if not clamps: + return Notice(ID_OUTPUT_CLAMP, ALARM, T_OUTPUT_CLAMP, + "The controller asked for more power than the inverter " + "rating and was cut back. Control is still running. This " + "is a software fault, so please report it to your " + "installer.") + c = clamps[0] + who = f"For {c.unit}, the" if c.unit else "The" + others = [x.unit for x in clamps[1:] if x.unit] + also = (f"; {names(others)} {'was' if len(others) == 1 else 'were'} cut too" + if others else "") + return Notice(ID_OUTPUT_CLAMP, ALARM, T_OUTPUT_CLAMP, + f"{who} controller asked for {watts(c.asked_w)}, above " + f"{LIMIT_WORDS.get(c.limit, LIMIT_WORDS['rating'])}, and sent " + f"{watts(c.sent_w)} instead{also}. Control is still running. " + f"This is a software fault, so please report it to your " + f"installer.") + + +def peak_saturated(ceiling_w) -> Notice: + """SAFETY-07: the battery gives all it can and the peak still goes up.""" + return Notice(ID_PEAK_SATURATED, ALARM, T_PEAK_SATURATED, + f"The battery is giving all it can, but this 15-minute period " + f"will still go over your {watts(ceiling_w)} peak limit and " + f"raise this month's peak. Switch off large loads in the next " + f"few minutes. This is not a fault: the load is bigger than " + f"the inverter.") + + +def peak_reserve(ceiling_w, *, soc_unread: bool, reserve_unset: bool, + packs=()) -> Notice: + """SAFETY-24/25/32: the peak guard may not discharge any further. + + The last sentence is SAFETY-25 and must stay: the reserve binds the peak + guard only, and normal home use goes on discharging below it. + `packs` names the batteries at their limit, only on a site with several. + """ + if soc_unread: + why = "The battery level cannot be read" + act = "Switch off large loads, and check the battery level sensor." + elif reserve_unset: + why = "No peak reserve is set" + act = "Switch off large loads, and set a peak reserve in the settings." + else: + why = (f"The battery of {names(packs)} is at its peak reserve" if packs + else "The battery is at its peak reserve") + act = ("Switch off large loads, or lower the peak reserve if the " + "battery allows it.") + return Notice(ID_PEAK_RESERVE, ALARM, T_PEAK_RESERVE, + f"{why}, so this 15-minute period will go over your " + f"{watts(ceiling_w)} peak limit and raise this month's peak. " + f"{act} The reserve only limits peak shaving: normal home use " + f"can still discharge the battery below it, down to its " + f"cut-out level.") + + +def circulating(discharging=(), charging=()) -> Notice: + """SAFETY-31: the inverters push power round each other. Control stopped.""" + if discharging and charging: + what = (f"{names(discharging)} was discharging while " + f"{names(charging)} was charging, and your meter cannot see " + f"this.") + else: + what = ("One inverter was charging from another, and your meter " + "cannot see this.") + return Notice(ID_CIRCULATING, ALARM, T_CIRCULATING, + f"{what} Control is stopped and every inverter is set to " + f"0 W; if the grid power does not change now, switch the " + f"inverters off at the isolator. A restart does not clear " + f"this: start control on the add-on page once you know why.") + + +def not_delivering(unit: str, slug: str) -> Notice: + """SAFETY-42: one inverter gives less than its share. Reports, never acts.""" + return Notice( + ID_NOT_DELIVERING.format(slug=slug), ALARM, + T_NOT_DELIVERING.format(unit=unit), + f"{unit} gives less power than it is asked for, so the site is short; " + f"nothing was changed and control keeps running. Check that {unit} is " + f"on and connected, that its battery is not empty or cold, and that " + f"nothing else controls it. A restart does not clear this: start " + f"control on the add-on page once you know why.", + section=S_NOT_DELIVERING) + + +def meter_frozen(unchanged_s) -> Notice: + """SAFETY-18: the meter answers but its value does not move.""" + return Notice(ID_METER_FROZEN, ALARM, T_METER_FROZEN, + f"The meter has shown the same value for " + f"{duration(unchanged_s)} while the controller asks the " + f"battery for full power. Control is still running and still follows this " + f"reading. Check the meter; if it is stuck, stop control on " + f"the add-on page.") + + +def samples() -> list: + """One rendering of every notice, with realistic values, for the test.""" + return [ + loop_bound(), + output_clamp([Clamp(None, 7412, 5000, "rating")]), + output_clamp(()), + output_clamp([Clamp("inverter-a", -3000, -2500, "device"), + Clamp("inverter-b", 6000, 4600, "max_w+device")]), + peak_saturated(5000), + peak_reserve(5000, soc_unread=False, reserve_unset=False), + peak_reserve(5000, soc_unread=False, reserve_unset=False, + packs=["inverter-b"]), + peak_reserve(5000, soc_unread=True, reserve_unset=False), + peak_reserve(5000, soc_unread=False, reserve_unset=True), + circulating(["inverter-a"], ["inverter-b"]), + circulating(), + not_delivering("inverter-b", "inverter_b"), + meter_frozen(600), + meter_frozen(90), + ] diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index d6dcdf6..f4e4cda 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -83,6 +83,7 @@ from datetime import datetime, timedelta, timezone from named_absence import given, nth, present +from app import messages from app.clamp import ( CLEAR_CYCLES, REASON_CODE, REASSERT_S, SUSTAINED_CYCLES, ClampWatchdog, clamp_to_rating, @@ -510,9 +511,9 @@ check("...one episode, re-asserted rather than one per cycle", ctl_r.clamp_wd.episodes == 1 and len(notes_r) < ctl_r.clamp_wd.engagements) # SAFETY-40: on a default install this runaway is the INTEGRATOR bound, so it # says so, and does not call anti-windup a bug (part 8 grades the wording). -check("...and it names the integrator bound, not a BUG SIGNAL", - bool(notes_r) and "anti-windup bound" in notes_r[0]["message"] - and "BUG SIGNAL" not in notes_r[0]["message"]) +check("...and it is the integrator-bound notice, which calls nothing a fault", + bool(notes_r) and notes_r[0]["title"] == messages.T_LOOP_BOUND + and "fault" not in notes_r[0]["message"]) rows_r = [e for e in ctl_r.events if REASON_CODE in e] check(f"the action log records every engagement, coalesced into one row per " f"episode ({len(rows_r)} row(s), {ctl_r.clamp_wd.engagements} " @@ -1002,7 +1003,9 @@ check("AC 3: the guard alarmed on write-path evidence alone", ctl_w.clamp_wd.engagements == 1 and len(notes_w) == 1) check("...and the operator is told WHICH bound bit, so a device-rating clamp " "is not reported as a max_w one", - bool(notes_w) and "device bound" in notes_w[0]["message"]) + bool(notes_w) + and messages.LIMIT_WORDS["device"] in notes_w[0]["message"] + and messages.LIMIT_WORDS["max_w"] not in notes_w[0]["message"]) check("...and the action log carries the row, written by write_setpoint()", any(REASON_CODE in e and "device bound" in e for e in ctl_w.events)) @@ -1094,19 +1097,24 @@ check("⚠️ THE ORDERED PAIR IN THE §15 ACTION-LOG ROW (main.py:1366). The " "reading backwards on the one line an operator is woken by", any(f"the computed setpoint {_asked_x:+.0f} W was clamped to " f"{_sent_x:+.0f} W" in e for e in _rows_x)) -check("⚠️ ...AND IN THE ClampWatchdog NOTIFICATION REASON (main.py:2452), " - "which is a SECOND surface off the same sentence and has to be pinned " - "separately - SAFETY-38 round 3's whole lesson was that pinning one call " - "site leaves the other shipping", - bool(notes_x) - and f"the computed setpoint {_asked_x:+.0f} W was clamped to " - f"{_sent_x:+.0f} W" in notes_x[0]["message"]) +# UX-08: the notification is a SECOND surface off the same numbers, in its own +# words (messages.output_clamp): asked first, sent second. +def _asked_then_sent(msg, asked, sent): + return (f"asked for {messages.watts(asked)}," in msg + and f"and sent {messages.watts(sent)} instead" in msg + and msg.index(messages.watts(asked)) < msg.index("and sent")) + + +check("⚠️ ...AND IN THE ClampWatchdog NOTIFICATION, which is a SECOND surface " + "off the same numbers and has to be pinned separately - SAFETY-38 round " + "3's whole lesson was that pinning one call site leaves the other " + "shipping", + bool(notes_x) and _asked_then_sent(notes_x[0]["message"], _asked_x, _sent_x)) check("...and the TRANSPOSED sentence appears on NEITHER surface, so the two " "checks above discriminate rather than decorate", not any(f"the computed setpoint {_sent_x:+.0f} W was clamped to " f"{_asked_x:+.0f} W" in e for e in _rows_x) - and f"the computed setpoint {_sent_x:+.0f} W was clamped to " - f"{_asked_x:+.0f} W" not in nth(notes_x, 0)["message"] + and not _asked_then_sent(nth(notes_x, 0)["message"], _sent_x, _asked_x) and present(nth(notes_x, 0))) # The DEVICE bound, off part 6c's controller: same sentence, other stage. The # unit of coverage is the call site, and `bound` is the only thing that differs @@ -1118,8 +1126,7 @@ check("...and the same ordered pair holds on the DEVICE-bound row, where the " f"{_asked_w:+.0f}" != f"{_sent_w:+.0f}" and any(f"the computed setpoint {_asked_w:+.0f} W was clamped to " f"{_sent_w:+.0f} W" in e for e in ctl_w.events) - and f"the computed setpoint {_asked_w:+.0f} W was clamped to " - f"{_sent_w:+.0f} W" in nth(notes_w, 0)["message"]) + and _asked_then_sent(nth(notes_w, 0)["message"], _asked_w, _sent_w)) # ============================================================================== @@ -1973,8 +1980,8 @@ check("at the bound nothing is described as 'above' or 'over' the rating", for d, t, r in wind)) notes_i = clamp_notes(hass_i) check("it still NOTIFIES (not suppressed), under a title that claims no bug", - notes_i and all("integrator bound" in n["title"] - and "exceeded" not in n["title"] for n in notes_i)) + notes_i and all(n["title"] == messages.T_LOOP_BOUND + and "fault" not in n["message"] for n in notes_i)) check("...under its OWN notification_id, so it cannot replace a BUG SIGNAL " "notice still on screen", notes_i and all(n["notification_id"] == BOUND_ID for n in notes_i)) @@ -2008,10 +2015,14 @@ check("defect 3: 'clamped to' is the clamp's own result, not self.target", check("...and the 14 768 W rationale is still in its ERROR", any(x.levelno == logging.ERROR and "14 768 W" in x.getMessage() for x in log_o)) -check("...under the 'exceeded the rating' title, with a red status row", +check("...under the over-rating title, quoting a tick's own asked and sent " + "numbers in that order, with a red status row", clamp_notes(hass_o) - and all("exceeded the rating" in n["title"] - and n["notification_id"] == CLAMP_ID for n in clamp_notes(hass_o)) + and all(n["title"] == messages.T_OUTPUT_CLAMP + and n["notification_id"] == CLAMP_ID + and any(_asked_then_sent(n["message"], _f(d, 'requested_w'), + _f(d, 'clamped_w')) for d, t, r in over) + for n in clamp_notes(hass_o)) and any(not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] for c in red_o)) diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index 6e53bb1..b387b0a 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -33,6 +33,7 @@ from datetime import datetime, timedelta, timezone from named_absence import given, present +from app import messages from app.control import Tuning from app.delivery import ( DELIVERY_OPTION_DEFAULTS, DELIVERY_SHARE_FRACTION, REASON_CODE, @@ -1232,7 +1233,7 @@ check("the notification NAMES THE UNIT - in its id, its title and its body - " check("...and it says, in the operator's own sentence, that nothing has been " "commanded differently. An alarm that let somebody believe the add-on " "had handled it would be worse than no alarm", - "NOTHING HAS BEEN COMMANDED DIFFERENTLY" in _note[2]["message"]) + "nothing was changed and control keeps running" in _note[2]["message"]) print(f" id={_note[2]['notification_id']!r} title={_note[2]['title']!r}") _before_calls = len(_rh2.calls) await_again = asyncio.run(_r2.check_not_delivering()) diff --git a/goodwe_controller/test_freeze.py b/goodwe_controller/test_freeze.py index 661113d..a10166e 100644 --- a/goodwe_controller/test_freeze.py +++ b/goodwe_controller/test_freeze.py @@ -85,6 +85,7 @@ from pathlib import Path import aiohttp +from app import messages from app.control import Tuning, compute from app.freeze import ( RAIL_FRAC, FreezeWatchdog, FreezeWatchdogConfig, looks_frozen, @@ -773,7 +774,7 @@ def _is_freeze_note(d): calls itself frozen, which would be a confusable alarm on its own account. """ return (d.get("notification_id") == FREEZE_NOTE_ID - or "frozen" in str(d.get("title", "")).lower()) + or d.get("title") == messages.T_METER_FROZEN) def notes_of(hass): @@ -788,7 +789,7 @@ def notes_by_text_of(hass): both would be true by construction. """ return [d for d in all_notes_of(hass) - if "frozen" in str(d.get("title", "")).lower()] + if d.get("title") == messages.T_METER_FROZEN] def wired(unchanged_s, grid, cycles=60, dev=(-5000.0, 5000.0), **over): @@ -858,7 +859,7 @@ check("...with a fixed notification_id so repeats replace, not stack", [d.get("notification_id") for d in notes_by_text_of(hass_f)] == [FREEZE_NOTE_ID]) check("...and it says the controller is still running", - bool(notes) and "STILL RUNNING" in notes[0]["message"]) + bool(notes) and "Control is still running" in notes[0]["message"]) check("the status page carries a failed row saying so", len(frozen_rows) == 1 and not frozen_rows[0]["ok"] and not frozen_rows[0]["warn"]) check("the event log names it", any("METER FROZEN" in e for e in ctl_f.events)) @@ -1180,11 +1181,16 @@ check("...and at or above the device rail, which is why it must", check("THE ALARM FIRES through the real cycle() - the rating reaches the " "predicate from the controller, not just from a unit call", len(_n20) == 1 and _c20.freeze_wd.active) -check("...and the notification the operator gets quotes the capped rail, " - "not the max_w one", +# UX-08: the notification no longer quotes a rail at all (the reader's action +# is "check the meter"), so it cannot quote the wrong one; the capped rail is +# still what the reason - the log line and the status row - carries. +check("...and the notification the operator gets names no max_w rail, and the " + "reason behind it quotes the capped rail", bool(_n20) + and f"{rail_w(LIVE_INSTALL_MAX_W):.0f} W" + not in str(_n20[0].get("message", "")) and f"{rail_w(LIVE_INSTALL_MAX_W, dev_min=-4700.0, dev_max=4700.0):.0f} W" - in str(_n20[0].get("message", ""))) + in _c20.freeze_wd.reason) # p1_enabled is what a homewizard_local install has - set by hand here for the # same reason part 4 sets it, see freeze_rows(). _c20.p1_enabled = True diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py new file mode 100644 index 0000000..4918ea8 --- /dev/null +++ b/goodwe_controller/test_messages.py @@ -0,0 +1,402 @@ +"""UX-08: user-facing text follows STYLE.md. RUN: python3 -B test_messages.py + +1. Every notification in `app/messages.py` obeys the rule. The test renders + each one with realistic values and checks the title length, the number of + sentences and words for its severity, the banned terms, the entity ids and + the Details line. +2. No notification is worded anywhere else. An AST scan of `app/` fails any + `persistent_notification` call whose payload is not built by + `app/messages.py`. +3. THE RATCHET for the kinds not rewritten yet. Every status-row and banner + literal, every validator refusal, every WARNING+ log line and every option + name and description in `translations/en.yaml` must either obey its limit + or appear in `ux08_allowlist.txt`. A new string that breaks the rule and is + not listed goes red. So does a listed entry that no longer matches a + failing string, so the list can only shrink: remove the line when you + rewrite the string. +4. DOCS.md has a section for every notification, under "## Notifications". +5. Mutations: each rule is shown to catch a spoiled input (habit 1 of + MUTATION.md). + +Run `python3 -B test_messages.py --violations` to print what part 3 sees. +""" + +import ast +import hashlib +import os +import re +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE / "tools")) + +from app import messages # noqa: E402 +import translations_lint as TL # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +# --- the rule (STYLE.md sections 1 and 4) -------------------------------------- +BANNED = re.compile( + r"\b(?:(?:SAFETY|TARIFF|TEL|CFG|FCST|OPT|UX|HW|FW|WITNESS|PKG|ARCH)-\d+|" + r"integrator|anti-?windup|windup|clamp(?:ed|s)?|i_clamped|saturat\w*|" + r"BUG SIGNAL|latch(?:ed)?|arbiter|allocator|registers?|0x[0-9A-Fa-f]+|" + r"layer [123]|heartbeat|watchdog|telegrams?|ACKs?|CRC|OTA|Modbus|planner|" + r"capaciteitstarief|journalctl|ssh|grep|" + r"\d+\.\d+\.\d+\.\d+|[\w-]+\.(?:py|md|yaml|json|db))\b|§\s?\d", re.I) +ENTITY = re.compile(r"\b(?:sensor|number|binary_sensor|input_\w+|switch|select)" + r"\.[a-z0-9_*]+") +SNAKE = re.compile(r"\b[a-z0-9]+(?:_[a-z0-9]+)+\b") +SHOUT = re.compile(r"\b[A-Z]{2,}[A-Z0-9]*(?:[\s-]+[A-Z]{2,}[A-Z0-9]*)+\b") +PLACEHOLDER = re.compile(r"\{[^{}]*\}|%[-+ #0-9.]*[sdrfgx%]") + + +def words(text): + return [w for w in re.findall(r"\S+", PLACEHOLDER.sub("X", text)) + if re.search(r"[A-Za-z0-9]", w)] + + +def sentences(text): + """Sentence count: a stop followed by a space and a capital, or the end.""" + t = PLACEHOLDER.sub("X", text.strip()) + t = re.sub(r"\b(e\.g|i\.e|etc)\.", "eg", t) + return len([s for s in re.split(r"[.!?](?:\s+|$)", t) if s.strip()]) + + +def title_problems(title): + out = [] + if len(words(title)) > 5: + out.append(f"title over 5 words ({len(words(title))})") + if title.lower().startswith("goodwe"): + out.append("title carries a GoodWe prefix") + if title.rstrip().endswith("."): + out.append("title ends in a full stop") + return out + text_problems(title, keys=False, entities=False) + + +def text_problems(text, *, keys, entities): + t = PLACEHOLDER.sub("X", text) + out = [] + hit = sorted({m.group(0) for m in BANNED.finditer(t)}) + if hit: + out.append("banned: " + ", ".join(hit[:4])) + if not entities and ENTITY.search(t): + out.append("entity id: " + ENTITY.search(t).group(0)) + if not keys and SNAKE.search(ENTITY.sub("", t)): + out.append("option key: " + SNAKE.search(ENTITY.sub("", t)).group(0)) + if SHOUT.search(t): + out.append("capitals: " + SHOUT.search(t).group(0)) + return out + + +def body_problems(body, severity): + out = [] + n_s, n_w = sentences(body), len(words(body)) + if severity == messages.ALARM: + if n_s > 3: + out.append(f"alarm body over 3 sentences ({n_s})") + if n_w > 70: + out.append(f"alarm body over 70 words ({n_w})") + long = [s for s in re.split(r"(?<=[.!?])\s+", body) if len(words(s)) > 30] + if long: + out.append(f"sentence over 30 words ({len(words(long[0]))})") + else: + if n_s > 1: + out.append(f"{severity} body over 1 sentence ({n_s})") + if n_w > 25: + out.append(f"{severity} body over 25 words ({n_w})") + return out + text_problems(body, keys=False, entities=False) + + +def notice_problems(n): + out = [] + if n.severity not in (messages.ALARM, messages.WARNING, messages.INFO, + messages.RESOLVED): + out.append(f"unknown severity {n.severity!r}") + out += title_problems(n.title) + body_problems(n.body, n.severity) + if not ends_in_details(n.data()["message"], n.docs): + out.append("message does not end in its Details line") + return out + + +def ends_in_details(message, docs): + return message.endswith("\n\n" + messages.details(docs)) + + +# ============================================================================== # +print("1. every notification obeys the rule") +SAMPLES = messages.samples() +for n in SAMPLES: + p = notice_problems(n) + check(f"{n.severity:8} {n.title!r}: {len(words(n.body))} words, " + f"{sentences(n.body)} sentence(s){' - ' + '; '.join(p) if p else ''}", + not p) +ids = {v for k, v in vars(messages).items() if k.startswith("ID_")} +seen = {re.sub(r"inverter_b$", "{slug}", n.id) for n in SAMPLES} +check(f"the samples cover every notification id in the catalogue " + f"(missing: {sorted(ids - seen)})", ids <= seen) +check("the payload carries exactly the three keys Home Assistant accepts", + all(set(n.data()) == {"notification_id", "title", "message"} + for n in SAMPLES)) +os.environ["HOSTNAME"] = "abcd1234-goodwe-controller" +check("inside the add-on the Details line links to its documentation page", + "(/hassio/addon/abcd1234_goodwe_controller/documentation)" + in SAMPLES[0].data()["message"]) +os.environ["HOSTNAME"] = "some-laptop" +check("...and anywhere else it names the section without a guessed link", + "](" not in SAMPLES[0].data()["message"] + and "under Notifications" in SAMPLES[0].data()["message"]) +del os.environ["HOSTNAME"] +check("the output-clamp alarm quotes asked before sent", + messages.output_clamp([messages.Clamp(None, 7412, 5000, "rating")]).body + .index("7 412 W") < messages.output_clamp( + [messages.Clamp(None, 7412, 5000, "rating")]).body.index("5 000 W")) + + +# ============================================================================== # +print("\n2. no notification is worded outside app/messages.py") +APP = HERE / "app" + + +def render(node): + """A string expression as text, placeholders as {expr}; None otherwise.""" + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value + if isinstance(node, ast.JoinedStr): + return "".join(v.value if isinstance(v, ast.Constant) + else "{" + ast.unparse(v.value) + "}" for v in node.values) + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add): + a, b = render(node.left), render(node.right) + if a is None and b is None: + return None + return (a if a is not None else "{…}") + (b if b is not None else "{…}") + if isinstance(node, ast.IfExp): + a, b = render(node.body), render(node.orelse) + if a is None and b is None: + return None + return (a or "") + " / " + (b or "") + return None + + +def notification_calls(tree): + for node in ast.walk(tree): + if (isinstance(node, ast.Call) and node.args + and ast.unparse(node.func).endswith("call") + and render(node.args[0]) == "persistent_notification"): + yield node + + +bad_calls, n_calls = [], 0 +for f in sorted(APP.glob("*.py")): + for call in notification_calls(ast.parse(f.read_text(encoding="utf-8"))): + n_calls += 1 + payload = call.args[2] if len(call.args) > 2 else None + ok = (isinstance(payload, ast.Call) + and isinstance(payload.func, ast.Attribute) + and payload.func.attr == "data" + and "messages." in ast.unparse(payload.func.value)) + if not ok: + bad_calls.append(f"{f.name}:{call.lineno}") +check(f"the scan found the add-on's notification calls ({n_calls})", n_calls >= 7) +check(f"every one is built by app/messages.py (not: {bad_calls})", not bad_calls) + + +# ============================================================================== # +print("\n3. the ratchet: other user-facing text obeys its limit or is listed") + +LIMITS = { # kind: (words, keys ok, entity ids ok) + "row": (15, False, False), + "banner": (12, False, False), + "refusal": (30, True, True), + "log": (25, True, True), + "option-name": (6, False, False), + "option-desc": (30, True, True), +} +LOG_CALL = re.compile(r"(?:^|\.)(?:_LOG|log|logger|LOG)\.(warning|error|critical|exception)$") + + +def strings_in(node): + """Top-level string expressions inside `node` (not their parts).""" + t = render(node) + if t is not None: + yield node, t + return + for child in ast.iter_child_nodes(node): + yield from strings_in(child) + + +def collect(): + """(kind, where, text) for every user-facing literal of a ratcheted kind.""" + out = [] + for f in sorted(APP.glob("*.py")): + if f.name == "messages.py": + continue + tree = ast.parse(f.read_text(encoding="utf-8")) + for node in ast.walk(tree): + if isinstance(node, ast.Dict): + for k, v in zip(node.keys, node.values): + key = render(k) if k is not None else None + if key in ("text", "banner"): + for n, t in strings_in(v): + out.append(("row" if key == "text" else "banner", + f"{f.name}:{n.lineno}", t)) + elif isinstance(node, ast.Assign) and f.name == "main.py": + tgt = ast.unparse(node.targets[0]).replace(" ", "").strip("()") + if tgt in ("level,banner", "banner"): + for n, t in strings_in(node.value): + if len(words(t)) > 1: + out.append(("banner", f"{f.name}:{n.lineno}", t)) + elif isinstance(node, ast.Call): + name = ast.unparse(node.func) + if LOG_CALL.search(name) or name.endswith("._moan"): + arg = node.args[1 if name.endswith("._moan") else 0] \ + if node.args else None + if arg is not None: + for n, t in strings_in(arg): + out.append(("log", f"{f.name}:{n.lineno}", t)) + elif re.search(r"problems\.(append|extend)$", name): + for a in node.args: + for n, t in strings_in(a): + if len(words(t)) > 1: + out.append(("refusal", f"{f.name}:{n.lineno}", t)) + tr = TL.parse_translation_file(HERE / "translations" / "en.yaml") + + def walk(conf, path): + for key, v in (conf or {}).items(): + if not isinstance(v, dict): + continue + if isinstance(v.get("name"), str): + out.append(("option-name", f"en.yaml:{path}{key}", + v["name"].split("·")[-1].strip())) + if isinstance(v.get("description"), str): + out.append(("option-desc", f"en.yaml:{path}{key}", + v["description"])) + if isinstance(v.get("fields"), dict): + walk(v["fields"], f"{path}{key}.") + walk(tr.get("configuration"), "") + return out + + +def problems_of(kind, text): + lim, keys, ents = LIMITS[kind] + p = [] + if len(words(text)) > lim: + p.append(f"over {lim} words ({len(words(text))})") + return p + text_problems(text, keys=keys, entities=ents) + + +def key_of(kind, text): + return f"{kind} {hashlib.sha1(text.encode('utf-8')).hexdigest()[:12]}" + + +ALLOW_FILE = HERE / "ux08_allowlist.txt" +# The allowlist may never grow: lower this number when you delete lines. +ALLOWLIST_MAX = 200 + + +def read_allowlist(path): + keys = set() + for line in path.read_text(encoding="utf-8").splitlines(): + line = line.split("#", 1)[0].strip() + if line: + keys.add(" ".join(line.split()[:2])) + return keys + + +found = collect() +violating = {} +for kind, where, text in found: + p = problems_of(kind, text) + if p: + violating.setdefault(key_of(kind, text), (kind, where, text, p)) +if "--violations" in sys.argv: + for k, (kind, where, text, p) in sorted(violating.items(), + key=lambda kv: kv[1][:2]): + print(f"{k} # {where} {'; '.join(p)} :: {text[:70]!r}") + sys.exit(0) + +allow = read_allowlist(ALLOW_FILE) +by_kind = {} +for kind, *_ in found: + by_kind[kind] = by_kind.get(kind, 0) + 1 +check(f"the scan found every ratcheted kind ({by_kind})", + all(by_kind.get(k, 0) >= 5 for k in LIMITS)) +new = sorted(k for k in violating if k not in allow) +for k in new: + kind, where, text, p = violating[k] + print(f" NEW {where}: {'; '.join(p)} :: {text[:90]!r}\n" + f" (rewrite it to STYLE.md; listing it needs a reason)") +check(f"no new string breaks the rule ({len(new)} new)", not new) +stale = sorted(k for k in allow if k not in violating) +for k in stale: + print(f" STALE {k} - that string now obeys the rule or is gone: " + f"delete its line from ux08_allowlist.txt") +check(f"no allowlist entry is stale, so the list only shrinks " + f"({len(stale)} stale)", not stale) +check(f"the allowlist has not grown ({len(allow)} entries, cap {ALLOWLIST_MAX})", + len(allow) <= ALLOWLIST_MAX) +print(f"CI: UX-08 allowlist {len(allow)} entries " + + ", ".join(f"{k} {sum(1 for x in allow if x.startswith(k + ' '))}" + for k in LIMITS)) + + +# ============================================================================== # +print("\n4. DOCS.md holds the detail of every notification") +DOCS = (HERE / "DOCS.md").read_text(encoding="utf-8") +part = DOCS.split("\n## Notifications\n", 1) +check("DOCS.md has a '## Notifications' section", len(part) == 2) +section = part[-1].split("\n## ", 1)[0] if len(part) == 2 else "" +heads = set(re.findall(r"^### (.+)$", section, re.M)) +missing = sorted({n.docs for n in SAMPLES} - heads) +check(f"...with a heading for every Details line (missing: {missing})", not missing) + + +# ============================================================================== # +print("\n5. mutations: each rule catches a spoiled input") +N = messages.Notice +check("a six-word title is refused", + bool(title_problems("The meter reading may be stuck"))) +check("a GoodWe prefix is refused", bool(title_problems("GoodWe: meter stuck"))) +check("a second sentence in a warning is refused", + bool(body_problems("The battery lags. Check it.", messages.WARNING))) +check("a fourth sentence in an alarm is refused", + bool(body_problems("One. Two. Three. Four.", messages.ALARM))) +check("an internal name is refused", bool(body_problems( + "The integrator reached its bound.", messages.WARNING))) +check("a card id is refused", bool(body_problems( + "See SAFETY-25.", messages.WARNING))) +check("shouting is refused", bool(body_problems( + "Control is STILL RUNNING.", messages.WARNING))) +check("an entity id in an alarm is refused", bool(body_problems( + "Check sensor.battery_power now.", messages.ALARM))) +check("...but allowed in a refusal", not problems_of( + "refusal", "Check sensor.battery_power in Developer Tools.")) +check("an option key in an alarm is refused", bool(body_problems( + "Lower peak_soc_floor.", messages.ALARM))) +check("a message that lost its Details line is refused", + ends_in_details(N("x", messages.WARNING, "Meter stuck", "It is.") + .data()["message"], "Meter stuck") + and not ends_in_details("It is.", "Meter stuck")) +_fake = " x = {'text': 'THE METER IS FROZEN AND NOTHING WORKS AT ALL'}\n" +_n = [t for node in ast.walk(ast.parse(_fake.strip())) + if isinstance(node, ast.Dict) for _, t in strings_in(node.values[0])] +check("a new shouting status row is seen by the scan and is not listed", + _n and problems_of("row", _n[0]) + and key_of("row", _n[0]) not in allow) +_bad = ast.parse("await self.hass.call('persistent_notification', 'create', " + "{'title': 'x', 'message': 'y'})", mode="exec") +check("a hand-written notification payload is seen by part 2", + any(not (isinstance(c.args[2], ast.Call)) for c in notification_calls(_bad))) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 9f19bd9..483fd67 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -114,6 +114,7 @@ from datetime import datetime, timedelta, timezone from math import inf, isinf from pathlib import Path +from app import messages from app import peakguard from named_absence import first, given, nth, present @@ -2522,13 +2523,21 @@ check("...and shortening the banner did NOT shorten the row: the full AC 3 " and "BMS cut-out" in rows25[0]["text"]) _body25 = hass25.last_message("goodwe_peak_soc_floor") + + +def _says_scope(body): + """SAFETY-25 in messages.peak_reserve()'s words: the reserve binds the peak + guard only, and home use goes on discharging below it to the cut-out.""" + return ("The reserve only limits peak shaving" in body + and "normal home use can still discharge the battery below it" in body + and "down to its cut-out level" in body) + + print(f" notification body tail: ...{_body25[-180:]}") check("...and so does the persistent notification, which outlives the page and " "is the thing an operator reads on a phone at 19:00. It names what has " "stopped - the guard buying a lower bill - and what has not", - "peak_soc_floor bounds THE PEAK GUARD ONLY" in _body25 - and "not a" in _body25 and "pack-wide reserve" in _body25 - and "BMS cut-out" in _body25) + _says_scope(_body25)) # --- 10f. THE CLAIM-SOURCE SET, PINNED -------------------------------------- @@ -4332,8 +4341,8 @@ check("the notification an operator reads at 19:00 NAMES THE PACK that stopped " "the site, and names only that one. 'the battery is at its floor' on a " "site with two batteries is an instruction to go and look at both, and " "the wrong one is the one that is fine", - "SAFETY-32" in _body32 and "inverter-b" in _body32 - and "inverter-a" not in _body32.split("WHICH PACK")[-1]) + "The battery of inverter-b is at its peak reserve" in _body32 + and "inverter-a" not in _body32) # The mirror again, on the SoC axis: swap which pack is empty and the name # swaps. A hardwired `self.inverters[1].name` passes the line above. _body32b = asyncio.get_event_loop_policy().new_event_loop().run_until_complete( @@ -4341,8 +4350,8 @@ _body32b = asyncio.get_event_loop_policy().new_event_loop().run_until_complete( check("...and with the SAME two readings swapped between the packs it names " "inverter-a instead - so the sentence follows the measurement rather " "than a position in the roster", - "inverter-a" in _body32b - and "inverter-b" not in _body32b.split("WHICH PACK")[-1]) + "The battery of inverter-a is at its peak reserve" in _body32b + and "inverter-b" not in _body32b) # ⚠️ AC 5, THE OTHER HALF: THE SAME METHOD ON A ROSTER OF ONE MUST PRINT WHAT IT @@ -4366,13 +4375,14 @@ async def _notify32_one(): _body32one = asyncio.get_event_loop_policy().new_event_loop().run_until_complete( _notify32_one()) -check("⚠️ AC 5. At a roster of ONE the same notification carries NO per-pack " - "sentence at all - byte for byte the message SAFETY-25 shipped. There is " +check("⚠️ AC 5. At a roster of ONE the same notification names NO pack - " + "byte for byte the two-pack message minus the name (UX-08). There is " "one battery, naming it is noise, and this alarm reaches every existing " "install", - "SAFETY-32" not in _body32one and "WHICH PACK" not in _body32one - and _body32one == _body32.split("\n\nSAFETY-32")[0] - and "peak_soc_floor bounds THE PEAK GUARD ONLY" in _body32one) + "inverter-" not in _body32one + and _body32one == _body32.replace("The battery of inverter-b is", + "The battery is") + and _says_scope(_body32one)) # --- 12i. THE SIBLING ARGUMENT: `pack_floor_soc`, THE OTHER HALF OF THE PAIR -- @@ -5604,8 +5614,7 @@ MUT.append(("rule 8's refusal naming a hardwired inverter", # 21. the notification naming a fixed roster position rather than the pack that # is actually at its floor. MUT.append(("the per-pack notification naming a fixed roster position", - "inverter-a" in _body32b - and "inverter-b" not in _body32b.split("WHICH PACK")[-1], + "inverter-a" in _body32b and "inverter-b" not in _body32b, "part 12h: the same two readings swapped between the packs")) # ---- the two PR #48 SURVIVORS, and why they survived ------------------------- diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 2decd04..98558d1 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -22,6 +22,7 @@ from datetime import datetime, timedelta, timezone from named_absence import nth, present +from app import messages # noqa: E402 from app.watchdog import ( SignWatchdog, SignWatchdogConfig, loop_is_following, ) @@ -1105,12 +1106,22 @@ check("...under a fixed notification_id of its own, so a second episode " for c in _notes1 + _notes2) and len({c[2]["notification_id"] for c in _notes1 + _notes2}) == 1) _msg = nth(_notes2, 0)[2]["message"] + + +def _says_three(m): + """UX-08: the three things only this alarm can say, in its plain words + (messages.circulating): the meter cannot see it, control is stopped at + 0 W, and if the grid does not move a person at the isolator is next.""" + return ("meter cannot see this" in m and "Control is stopped" in m + and "every inverter is set to 0 W" in m and "isolator" in m + and "if the grid power does not change" in m) + + check("...and the message tells the operator the three things only this alarm " "can: that the meter cannot see it, that control has been stopped, and " "that if the grid reading does not move afterwards one inverter is no " "longer listening and a human at the isolator is the last actuator", - "METER CANNOT SEE" in _msg and "CONTROL HAS BEEN STOPPED" in _msg - and "isolator" in _msg) + _says_three(_msg)) check("...and it does not raise the same card on every cycle - a per-PROCESS " "flag, deliberately not persisted, is what makes 'has a human been shown " "this' a different question from 'is this site tripped'", @@ -1262,8 +1273,8 @@ check("PRECONDITION: both runs actually tripped and actually raised the card, " and len(_notes_g) == 1 and len(_notes_s) == 1) # --- AC 4: THE ATTRIBUTION ITSELF ------------------------------------------- -_WHO_G = "Right now garage is discharging while shed charges." -_WHO_S = "Right now shed is discharging while garage charges." +_WHO_G = "garage was discharging while shed was charging" +_WHO_S = "shed was discharging while garage was charging" check("⚠️ THE ALARM NAMES THE TWO PACKS AND SAYS WHICH WAY EACH ONE IS PULLING. " "`circulation.py` calls this the first thing somebody woken at 3 a.m. " "needs and impossible to reconstruct from the watts alone, and until this " @@ -1284,12 +1295,14 @@ check("...and the RESTING pack is not named. `cellar` is on the roster, is read "beside a 6 kW loop is not reported as one of its two participants", "cellar" not in _msg_g and "cellar" not in _msg_s and _cg.inverters[2].batt == _REST_W) -check("...and the sentence sits with the figure, not instead of it: the same " - "card still carries the watts, the window and the three things only this " - "alarm can say", - all("CIRCULATING_POWER" in m and "METER CANNOT SEE" in m - and "CONTROL HAS BEEN STOPPED" in m and "isolator" in m - for m in (_msg_g, _msg_s))) +# UX-08: the watts and the window moved out of the card into the reason the +# log line and the status row carry; the card keeps the three things. +check("...and the sentence sits with the three things only this alarm can say, " + "while the watts and the window stay in the reason behind it", + all(_says_three(m) for m in (_msg_g, _msg_s)) + and all("CIRCULATING_POWER" in c.circ_wd.reason + and "W measured going round" in c.circ_wd.reason + for c in (_cg, _cs))) print() print(" the operator's press is the only way out, and it clears BOTH halves") diff --git a/goodwe_controller/ux08_allowlist.txt b/goodwe_controller/ux08_allowlist.txt new file mode 100644 index 0000000..94ea509 --- /dev/null +++ b/goodwe_controller/ux08_allowlist.txt @@ -0,0 +1,207 @@ +# UX-08 ratchet (test_messages.py part 3). Each line is a user-facing string that +# does not follow STYLE.md yet: "<kind> <sha1-12 of its text> # where :: start". +# These are waiting for phase 2b (row, banner), 2c (refusal, option-name, +# option-desc) and 2d (log). Delete the line when you rewrite the string, because +# a stale line fails the test. Never add a line for a new string: write the new +# string to STYLE.md instead. + +banner c185022e391f # main.py banned: SAFETY-25; option key: peak_soc_floor; capitals: THE PEAK GUARD ONLY :: '{…} - and peak_soc_floor bounds THE PEAK GUARD ONLY (SAFETY-25, see be' +banner 4a246fc26def # main.py over 12 words (14); capitals: CIRCULATING POWER :: 'CIRCULATING POWER — the inverters were pushing against each other. Sit' +banner 750ccd4f2126 # main.py over 12 words (14) :: "FAILSAFE — the site's total command opposed the meter. Every inverter " +banner 637f334f130a # main.py over 12 words (26) :: 'FAILSAFE — the command opposed the meter. Inverter held at 0 W. / FAIL' +banner 0a3d2d9c4232 # main.py capitals: NOT READY :: "NOT READY — {bad[0].get('banner') or bad[0]['text']}" +banner dbcc227a9589 # main.py over 12 words (26); capitals: NOT DELIVERING :: 'NOT DELIVERING — {_nd} is standing at a share it is not producing. The' +log a5e99679fd80 # main.py banned: SAFETY-02, latch :: 'SAFETY-02: the per-inverter store migration did not verify (%s). The l' +log 128b18b32d86 # main.py over 25 words (41); banned: LATCHED, SAFETY-44, latched :: 'SAFETY-44: this store carries a LATCHED sign-disagreement failsafe und' +log f60446541ae5 # main.py over 25 words (83); banned: LATCH, LATCHED, SAFETY-02, latch; capitals: LATCH GUARD :: 'SAFETY-02 LATCH GUARD: this store carries a LATCHED sign-disagreement ' +log 04d06bf223c8 # main.py over 25 words (73); banned: REGISTER, SAFETY-37, SAFETY-57, register; capitals: WHICH IS NOT BY ITSELF :: 'SAFETY-37: %s battery-power reading did not move under a command that ' +log aec01642bd07 # main.py banned: SAFETY-57 :: 'SAFETY-57: %s' +log aebbca17acb3 # main.py over 25 words (52); banned: allocator :: 'write_setpoint() was asked to put %+.0f W on every one of %d inverters' +log b74c3018461e # main.py over 25 words (30); banned: SAFETY-28, allocator :: 'SAFETY-28 REFUSED a write of %+.0f W to %s: %s. Commanding 0 W instead' +log cefffafa8b27 # main.py over 25 words (31) :: 'the write of %+.0f W to %s (%s) did not complete in %.0f s and was aba' +log 1001c6250b85 # main.py over 25 words (29); banned: SAFETY-02 :: 'SAFETY-02 TRIPPED on %s - %s. Commanding 0 W on that inverter and hold' +log 8252ef5eefad # main.py over 25 words (48); banned: SAFETY-30 :: 'SAFETY-30 TRIPPED at the SITE - %s. That is the SUM of every standing ' +log 8a65cf945e00 # main.py over 25 words (32); banned: SAFETY-31 :: 'SAFETY-31 TRIPPED - %s. Commanding 0 W on every inverter and holding i' +log 5d2beed2f1a2 # main.py over 25 words (65); banned: HW-01, SAFETY-42; capitals: NOTHING IS COMMANDED DIFFERENTLY :: 'SAFETY-42 TRIPPED on %s - %s. NOTHING IS COMMANDED DIFFERENTLY: this g' +log d50b775b9cd4 # main.py banned: ARBITER; capitals: ARBITER SCOPE :: 'ARBITER SCOPE: %s' +log 749c2c6fe81d # main.py over 25 words (26); banned: SAFETY-10, heartbeat; capitals: SHADOW MODE IS ON :: 'SAFETY-10 SHADOW MODE IS ON. The full decision path runs and NOTHING i' +log 4d271dfc6f1c # main.py banned: SAFETY-10 :: 'SAFETY-10 shadow mode is OFF. This controller is commanding the batter' +log 730387e0da2b # main.py banned: SAFETY-03 :: 'SAFETY-03 - %s Engagements so far: %d.' +log 3bf899e99297 # main.py over 25 words (56); banned: SAFETY-03, clamp, clamped, integrator; capitals: STILL RUNNING :: 'SAFETY-03 - %s Silently clipping this is how a winding integrator reac' +log 78cb6bd09633 # main.py over 25 words (48); banned: SAFETY-07; capitals: STILL RUNNING :: 'SAFETY-07 - %s. The guard is asking for everything the inverter has an' +log cc735997adc7 # main.py over 25 words (44); banned: SAFETY-24; capitals: STILL RUNNING :: 'SAFETY-24 - %s. The controller is STILL RUNNING and charging is still ' +log ebcb428a70d0 # main.py over 25 words (70); banned: SAFETY-18, arbiter, watchdog; capitals: CHECK THE METER :: 'SAFETY-18 - %s. The grid-following loop is regulating against a number' +log 38018b887495 # main.py over 25 words (43) :: 'tariff refresh degraded (%s); KEEPING the plan resolved at %s, %.0f s ' +log 0eab1ec96fe8 # main.py capitals: CONTROL LOOP DIED :: 'CONTROL LOOP DIED (%s) - commanding 0 W and exiting with status %d' +log db529f2c419d # main.py over 25 words (40); banned: SAFETY-02 :: 'SAFETY-02 was TRIPPED on %s before this restart and stays tripped: %s.' +log c5aadd5c8bf9 # main.py over 25 words (45); banned: SAFETY-42; capitals: NOTHING IS BEING COMMANDED DIFFERENTLY :: 'SAFETY-42 was TRIPPED on %s before this restart and stays tripped: %s.' +log d72bbdb7e595 # main.py over 25 words (39); banned: SAFETY-30 :: 'SAFETY-30 (site) was TRIPPED before this restart and stays tripped: %s' +log 8b880e65a7c3 # main.py over 25 words (38); banned: SAFETY-31 :: 'SAFETY-31 was TRIPPED before this restart and stays tripped: %s. Every' +log 23f58b7f305c # p1.py:1264 over 25 words (30) :: 'meter_poll_s %.1f leaves no room under meter_max_age_s %.1f: one misse' +log 88a7251e842b # p1.py:470 banned: telegram :: 'P1 telegram rejected: %s' +log 0dd83d6dfaf4 # price.py over 25 words (30) :: 'the feed published no price for %d of %d instants (index %s); those in' +log bcfd7062e28e # price.py over 25 words (79); banned: §8 :: 'price_feed_url is set, so %s is requesting %s exactly as given and is ' +log b57bc6de4a6b # price.py over 25 words (47); banned: validate.py :: 'price_taxes_profile cannot be used (%s: %s), so this fetch has NO tax ' +log d5595aaaacc4 # price_history.py banned: §8 :: 'price history at %s is %s - starting from empty. §8.3 carry-forward ha' +log dbed0b8e35ea # static_tariff.py banned: validate.py :: 'static_profile is unusable (%s); no cheap window. This should have bee' +log 8fbe9f5407ea # static_tariff.py over 25 words (28); banned: §1, §6 :: '§11.4: %s, and no static_profile is configured to fall back to. The pl' +log 4ce29e043d89 # static_tariff.py banned: §1 :: '§11.4: %s - falling back to the static profile, plan marked PROVISIONA' +log a3c7c9719ed2 # store.py capitals: LOST STATE :: 'per-inverter store migration LOST STATE and has not been marked done: ' +log 5b537a77052b # validate.py over 25 words (41); banned: arbiter, saturation :: 'integrator_max_w %.0f W is above max_w %.0f W. Not refused - the arbit' +log 12ae40f9d289 # validate.py over 25 words (73); banned: arbiter, clamp, clamps :: 'maintenance_discharge_w %.0f W is above max_w%s %.0f W. Not refused - ' +log c6dc799502cf # validate.py over 25 words (32) :: '%s carries negative levies %s EUR/kWh. That is accepted, but a tax com' +log 1688a7478ceb # validate.py over 25 words (36) :: 'price_formula is filled in but price_provider is %r, so the coefficien' +log f37f9fce4433 # validate.py over 25 words (96) :: '%s has no "card" block, so its coefficients are UNGRADED: nothing reco' +log 396fbdd009c2 # validate.py over 25 words (52); banned: §1 :: "price_provider is %r but static_profile is empty. §11.4's degradation " +log 37bba6ed37e3 # validate.py capitals: REFUSING TO START :: 'REFUSING TO START: the add-on configuration is not usable.' +option-desc b927826d01f0 # en.yaml over 30 words (112); capitals: LEAVING IT OFF DOES NOT TURN THE PRICE FEED OFF :: 'Charge in the cheapest published hour and discharge in the dearest, bu' +option-desc b98c42e34df7 # en.yaml over 30 words (34) :: 'The reserve price trading may not spend. Deliberately not the same key' +option-desc 84e054da385b # en.yaml over 30 words (39) :: 'Off by default. Leave it off until the site has been commissioned: wit' +option-desc 0f55d3b37afa # en.yaml over 30 words (38); banned: 0x0518, register, watchdog :: "The sensor that reports this inverter's own battery power, positive wh" +option-desc 307afdd74f84 # en.yaml over 30 words (98); banned: 0x0560, Register; capitals: GW5000S-BP :: "MEASURED, not chosen: the percent at which the pack's OWN battery mana" +option-desc 4da37ff6250d # en.yaml over 30 words (66); banned: SAFETY-31; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. DERIVED (SAFETY-31): 75 s is fifteen contr' +option-desc db464169ed66 # en.yaml over 30 words (144); banned: SAFETY-31; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY; with one inverter the quantity is identica' +option-desc df9735452fa1 # en.yaml over 30 words (88); banned: OPT-08; capitals: THIS ONE IS NOT DERIVED FROM :: 'What one full round trip costs per kWh: wear on the pack plus conversi' +option-desc 8147a82a437e # en.yaml over 30 words (51) :: 'A deadline on the gap between cycles, reset by every cycle. On a healt' +option-desc cb66f230ef63 # en.yaml over 30 words (45); banned: register :: 'Errors smaller than this are ignored. ⚠️ The deadband is a one-way rat' +option-desc 4167af90cfc2 # en.yaml over 30 words (288); banned: SAFETY-42, delivery_window.py, saturation; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY; with one inverter this check cannot fire a' +option-desc 3c0898cc1149 # en.yaml over 30 words (63) :: 'What you are paid for feeding a kWh back into the grid, all in. One nu' +option-desc 05560996cb2e # en.yaml capitals: MEASURED ON REAL HARDWARE :: 'How much of the remaining error the loop corrects each cycle. MEASURED' +option-desc f225d7a8f3a5 # en.yaml over 30 words (32); banned: watchdog :: 'How often the setpoint is rewritten even when it has not changed. It m' +option-desc ef70d16a93bd # en.yaml over 30 words (98); banned: clamp, saturation :: 'Caps how much stale error can be waiting to unwind when the sign flips' +option-desc bde7357af38d # en.yaml over 30 words (107); capitals: EMPTY DOES NOT MEAN :: 'Leave this empty unless the site really has more than one inverter. EM' +option-desc 217c5ae9599c # en.yaml over 30 words (66); banned: 0x0560, register :: "The percent at which THIS pack's own battery management system cuts ou" +option-desc 746a0f9ae506 # en.yaml over 30 words (143) :: "THIS pack's usable capacity in kilowatt-hours, from its datasheet or i" +option-desc cb6ad204f59d # en.yaml over 30 words (52) :: 'The supervised ceiling on what may be written to THIS inverter; the si' +option-desc 46142bcc1ab1 # en.yaml over 30 words (36); banned: heartbeat, latch :: 'A short identifier for this inverter, for example inverter-a. It gives' +option-desc d787e9f2454d # en.yaml over 30 words (63); banned: arbiter; capitals: MUST STAY AT OR BELOW :: '⚠️ MUST STAY AT OR BELOW the inverter rating, and the add-on refuses t' +option-desc a90fced63631 # en.yaml over 30 words (52); banned: CLAMPED :: 'How fast the cycle drains the pack; the surplus is exported. Above the' +option-desc ab58c8fae4fb # en.yaml over 30 words (57); capitals: THIS IS NOT THE PEAK GUARD :: 'The depth the monthly recalibration deliberately goes to, once a month' +option-desc 73f51bdd3d6e # en.yaml over 30 words (83); capitals: THIS IS YOUR NUMBER :: 'THIS IS YOUR NUMBER, not a derived one: the hard ceiling on what may e' +option-desc dd9023e6c812 # en.yaml over 30 words (45); capitals: POSITIVE MUST MEAN DRAWING FROM THE GRID :: "The net grid power sensor, used when the meter source is 'off'. POSITI" +option-desc aa5b929f3c22 # en.yaml over 30 words (114); banned: SAFETY-18, latch; capitals: NOT CHOSEN :: 'MEASURED, NOT CHOSEN (SAFETY-18). How long the meter may keep answerin' +option-desc 1b3038c5c9e5 # en.yaml over 30 words (46) :: 'Beyond this the grid figure counts as missing. On its own it does not ' +option-desc bbf26329f056 # en.yaml over 30 words (48); banned: telegram, telegrams :: 'Must match your connection. A telegram whose phase count disagrees is ' +option-desc 92da72e54e77 # en.yaml over 30 words (52) :: "For meter source homewizard_local only. 5 s is the meter's own update " +option-desc 24f329136309 # en.yaml over 30 words (84) :: "'off' keeps the single Home Assistant entity below, which is what an e" +option-desc 47e5fa0dba52 # en.yaml banned: register :: 'The UNSIGNED injection register, the counterpart of the import registe' +option-desc 9b8f5ea6c656 # en.yaml banned: 192.168.2.250 :: "For meter source homewizard_local only: the meter's own address on you" +option-desc d5d3e30ac4d2 # en.yaml over 30 words (37); banned: register :: 'The UNSIGNED consumption register. Do not point this at a signed templ' +option-desc 0b05d89400ba # en.yaml over 30 words (39) :: 'For meter source ha_signed only. ONE signed sensor: positive is drawn ' +option-desc e74a5db257e1 # en.yaml over 30 words (46) :: 'For meter source ha_signed only. Optional, in L1..L3 order, each signe' +option-desc 3f07a88a61fd # en.yaml over 30 words (34); capitals: THIS IS YOUR NUMBER :: 'THIS IS YOUR NUMBER: the quarter-hour average demand the peak guard tr' +option-desc 6ec195081ef9 # en.yaml over 30 words (112); banned: SAFETY-24; capitals: IT BOUNDS THE PEAK GUARD ONLY :: 'DERIVED, not picked (SAFETY-24): the reference pack holds 13.8 kWh usa' +option-desc 228fdc168458 # en.yaml over 30 words (270); capitals: INJECTION IS EXEMPT FROM VAT :: 'Optional, and only if your supplier pays you a price that moves with t' +option-desc 98987808a7f0 # en.yaml over 30 words (98); capitals: WHAT YOU TYPE IS SENT EXACTLY AS WRITTEN :: "Leave empty to use the chosen source's own feed. Only a host that sour" +option-desc 26f17751b2f7 # en.yaml over 30 words (234); capitals: IN THE UNITS THE CARD PRINTS :: "For price source custom_formula only: your own contract's two coeffici" +option-desc 011841a82d7d # en.yaml over 30 words (34) :: "Your supplier's margin. The add-on adds it ONLY when the chosen price " +option-desc d34ef16ba99a # en.yaml over 30 words (63) :: 'The older way of getting a price, kept because retiring it would take ' +option-desc c70929091e71 # en.yaml over 30 words (252); capitals: SWITCHING THIS ON IS WHAT STARTS THE PRICE FETCH :: "Where day-ahead or real-time prices come from. 'off' is what ships, an" +option-desc a62e17ccf445 # en.yaml over 30 words (230); banned: TARIFF-18; capitals: THIS NUMBER IS NOT :: 'Everything on your bill that is not the energy itself - distribution, ' +option-desc 56d56f58c43e # en.yaml over 30 words (206); capitals: THE NUMBERS HERE ARE THE LEVIES ALONE :: 'Leave this empty unless your network tariff really does charge a diffe' +option-desc 313bdd035b0b # en.yaml over 30 words (193); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' +option-desc 4172d9920d65 # en.yaml over 30 words (128); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' +option-desc 09ceba2c6afb # en.yaml over 30 words (70); banned: clamp; capitals: MEASUREMENT ONLY :: 'Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a ' +option-desc 42a7eaac6ff1 # en.yaml banned: saturated :: 'How many consecutive saturated cycles before the loop stops winding up' +option-desc 12b0dffec9dd # en.yaml over 30 words (42) :: 'The gap between what was commanded and what the inverter delivers that' +option-desc 91fd58c08a59 # en.yaml over 30 words (54) :: 'The ESPHome number entity this add-on writes the power setpoint to, no' +option-desc 01e1af709cd5 # en.yaml over 30 words (201); banned: arbiter, clamps, heartbeat, latch :: 'Runs the whole decision path — strategies, arbiter, clamps and guards ' +option-desc 96b077d4e2e9 # en.yaml over 30 words (72); banned: SAFETY-02; capitals: NOT CHOSEN :: 'MEASURED, NOT CHOSEN (SAFETY-02). How long the setpoint and the meter ' +option-desc addf5c495ae8 # en.yaml over 30 words (90); banned: SAFETY-02, watchdog; capitals: NOT CHOSEN :: 'MEASURED, NOT CHOSEN (SAFETY-02). Both the setpoint being emitted and ' +option-desc 0a66ac772b27 # en.yaml over 30 words (117); banned: SAFETY-30; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS (S' +option-desc c0deabb69ab6 # en.yaml over 30 words (60); banned: SAFETY-30; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. The same 300 W as the single-inverter thre' +option-desc 7d7272743277 # en.yaml over 30 words (123); banned: SAFETY-39; capitals: MEANS FOLLOW THE INVERTER RATING :: 'How far the setpoint may move in one control cycle. ⚠️ 0 MEANS FOLLOW ' +option-desc 436efca21a7d # en.yaml over 30 words (31) :: "The sensor that reports the pack's state of charge in percent. Use the" +option-desc 9ac8a3b21a1e # en.yaml over 30 words (43) :: 'How long the inputs may be missing before the add-on commands 0 W. Wit' +option-desc 86cbfd6a5693 # en.yaml over 30 words (130); capitals: RECOMMENDED EVEN ON :: 'Your fixed or day/night contract, written as a single line of JSON. RE' +option-desc 996dffbf563d # en.yaml over 30 words (74); banned: register :: 'What the meter should sit at when nothing is happening; negative means' +option-desc faf346256008 # en.yaml over 30 words (52); banned: SAFETY-30; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS (S' +option-desc 5323134f3131 # en.yaml over 30 words (95); banned: SAFETY-30, saturation; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY; with one inverter this setting does nothin' +option-name ca3a62bb8260 # en.yaml over 6 words (7) :: 'Circulating-power hold (s) — derived, do not change' +option-name edee163fdc2b # en.yaml over 6 words (7) :: 'Circulating-power threshold (W) — measured, do not change' +option-name 99b3beeab621 # en.yaml over 6 words (7) :: 'Cost of one full charge/discharge cycle (EUR/kWh)' +option-name cccd8a42f51a # en.yaml over 6 words (8) :: 'Not-delivering report after (s) — derived, do not change' +option-name 989891e2ce23 # en.yaml over 6 words (10); banned: Integrator :: 'Integrator bound (W, 0 means the same as the rating)' +option-name 42c6b595320c # en.yaml over 6 words (9) :: 'Inverter list (leave empty if you have one inverter)' +option-name 230e6dc9d872 # en.yaml over 6 words (7) :: 'Hour of day a due cycle starts' +option-name 18e1de907c54 # en.yaml over 6 words (8) :: 'Frozen-meter alarm after (s) — measured, do not change' +option-name 9071c4cfa460 # en.yaml over 6 words (7) :: 'A reading counts as stale after (s)' +option-name e3d06ed93e2e # en.yaml banned: register :: 'Export register entity (W)' +option-name a0f59ea5de36 # en.yaml banned: register :: 'Import register entity (W)' +option-name ed757924f40f # en.yaml over 6 words (7) :: 'Per-phase signed net entities (L1, L2, L3)' +option-name 52d03808da01 # en.yaml over 6 words (8) :: 'Your own INJECTION formula (one line of JSON)' +option-name bf22f2121af4 # en.yaml over 6 words (8) :: 'Your own tariff formula (one line of JSON)' +option-name 5593992fcf5b # en.yaml over 6 words (7) :: 'How far ahead to fetch prices (hours)' +option-name d9fee5514a4b # en.yaml over 6 words (11) :: 'Levies and VAT by time of day (one line of JSON)' +option-name 7d8d691905e0 # en.yaml over 6 words (7) :: 'PV production entities, one per inverter (W)' +option-name eac7ee084aaa # en.yaml banned: Saturated :: 'Saturated cycles before freezing (count)' +option-name 5c6bbc5cab40 # en.yaml banned: Saturation :: 'Saturation threshold (W)' +option-name 99a1ec154d36 # en.yaml over 6 words (7) :: 'Shadow mode — run every decision, command nothing' +option-name 82fcd0faa687 # en.yaml over 6 words (8); banned: watchdog :: 'Sign watchdog hold (s) — measured, do not change' +option-name 8fc34172dc01 # en.yaml over 6 words (8); banned: watchdog :: 'Sign watchdog threshold (W) — measured, do not change' +option-name 8516934704f5 # en.yaml over 6 words (8) :: 'Site-wide sign hold (s) — derived, do not change' +option-name 2b8278ab2b16 # en.yaml over 6 words (8) :: 'Site-wide sign threshold (W) — measured, do not change' +option-name bd52e795ea97 # en.yaml over 6 words (8) :: 'Command 0 W after inputs missing for (s)' +option-name 9e33febf4481 # en.yaml over 6 words (8) :: 'Fixed or day/night tariff (one line of JSON)' +option-name 40e1e3ba3841 # en.yaml over 6 words (8) :: 'Per-inverter sign hold (s) — derived, do not change' +option-name 4ba7087578dc # en.yaml over 6 words (8) :: 'Per-inverter sign threshold (W) — derived, do not change' +refusal 87620efa0704 # p1.py:1176 banned: telegram :: 'p1_phase_net_entities has {len(phase_net)} entities but meter_phases i' +refusal 5d1b8147792b # p1.py:1186 banned: 192.168.2.250 :: "meter_source {SOURCE_HOMEWIZARD} needs p1_host (the meter's own addres" +refusal 701db346696d # validate.py over 30 words (85); banned: SAFETY-30, watchdog :: 'unit_sign_disagree_w is {unit_sign_w} W but max_w{unit_where} is {weak' +refusal 710b4d89a9d7 # validate.py over 30 words (88); banned: ARBITER, arbiter; capitals: THE CEILING WINS :: 'maintenance_charge_w is {charge_w} W but max_w{maint_where} is {maint_' +refusal 16d40434116b # validate.py over 30 words (193); banned: NOTES.md, §5; capitals: THE PLANT WINS :: 'slew_w is {slew_w} W against a site rail of {rail} W, so the loop cros' +refusal 613375fb6b5f # validate.py over 30 words (107); banned: SAFETY-07; capitals: THE BMS WINS :: "peak_soc_floor is {soc_floor} % but the pack's own cut-out (bms_soc_fl" +refusal ba21c5ba8c0d # validate.py over 30 words (224); banned: TARIFF-07, §1; capitals: IT HAS NEVER FETCHED :: 'price_provider is {pid}, which WAS a shipped plugin and has been WITHD' +refusal de8df32186b6 # validate.py over 30 words (46); banned: §1 :: 'price_provider is {pid}, which is not a shipped plugin. The ids that e' +refusal 0ee7c15eafef # validate.py over 30 words (103); banned: arbitrage.py, main.py, static_tariff.py; capitals: THE HOME ASSISTANT ENTITIES WIN :: "price_provider is {pid} AND {' and '.join(ha_price)} {'is' if len(ha_p" +refusal c4149a762c39 # validate.py over 30 words (62); banned: main.py; capitals: THE HOME ASSISTANT ENTITIES WIN :: "static_profile is set AND {' and '.join(ha_price)} {'is' if len(ha_pri" +refusal 6af34466bbc2 # validate.py over 30 words (83); capitals: THE TABLE WINS :: '{TAXES_PROFILE_OPTION} is set AND price_taxes_eur_kwh is {scalar} rath' +refusal 8f69bdbbf3fc # validate.py over 30 words (55) :: '{TAXES_PROFILE_OPTION} carries {steep} EUR/kWh. Belgian levies and dis' +refusal 96a090d2ad97 # validate.py over 30 words (72); banned: DOCS.md, §1 :: "price_provider is 'custom_formula' but price_formula is empty, so the " +refusal db9d0d53c4f1 # validate.py over 30 words (45); banned: §1 :: "cycle_cost_threshold_eur is {opts.get('cycle_cost_threshold_eur')} and" +refusal 58ccb3bbd560 # validate.py over 30 words (63); banned: §1; capitals: NO PRICES AT ALL :: "arbitrage_enabled is on but price_provider is 'off' and static_profile" +refusal 780592c897fb # validate.py over 30 words (85); banned: arbitrage.py, telegram, §9 :: "arbitrage_enabled is on but meter_source is 'off', so there is no P1 t" +refusal 4f80c091ca95 # validate.py over 30 words (69) :: 'arbitrage_soc_floor is {floor} % and arbitrage_soc_ceiling is {ceiling' +refusal 0c089bb2f200 # validate.py over 30 words (57); banned: §1 :: "price_provider is 'manual_csv' but price_csv_path is empty, so the off" +refusal 152dfec79224 # validate.py over 30 words (48); banned: SAFETY-02, heartbeat, latch :: '{where} has no name. Every inverter needs one: the Store namespaces th' +refusal eb14af760f5c # validate.py over 30 words (51); banned: SAFETY-02, heartbeat, latch :: '{where} and {seen[name]} are both called {name}. The Store keys every ' +refusal 36f53c989b4a # validate.py over 30 words (55) :: '{who} has no setpoint_entity, so this add-on cannot command it. It wou' +refusal c98c6ab66e9f # validate.py over 30 words (56) :: "{who} has no usable max_w (got {entry.get('max_w')}). It is the superv" +refusal 5ca16a4d0a1e # validate.py over 30 words (71) :: '{who} has capacity_kwh {raw}, which is not a usable number of kilowatt' +refusal 63a864d2e0a3 # validate.py over 30 words (73) :: "capacity_kwh is stated on {', '.join(stated)} and left empty on {', '." +refusal 8d82500ecb1d # validate.py over 30 words (64) :: 'setpoint_entity is set to {flat_sp} AND an inverters list of {len(entr' +refusal 3d778e0ab5e1 # validate.py over 30 words (36); capitals: THE DEVICE WINS :: '{name}: max_w is {cap} W but {entity} accepts at most {float(dev_max)}' +refusal ecd0883f5649 # validate.py over 30 words (36); capitals: THE DEVICE WINS :: '{name}: max_w is {cap} W, so this controller may command {-cap} W, but' +refusal eff7efac51f8 # validate.py over 30 words (56); banned: heartbeat :: 'setpoint_entity is not set, so this add-on has no actuator: every writ' +refusal b126f1a88b77 # validate.py over 30 words (76); banned: §1 :: '{len(who)} configured writers can reach the one actuator {actuator}: {' +refusal 07a88756c864 # validate.py over 30 words (48); banned: arbiter :: 'max_w is {max_w} W and must be positive - it is a magnitude, not a sig' +refusal c4a1d0371e31 # validate.py over 30 words (42); capitals: THE DEVICE WINS :: "max_w is {max_w} W but {opts.get('setpoint_entity') or 'the setpoint d" +refusal a15624d1aa10 # validate.py over 30 words (33); capitals: THE DEVICE WINS :: 'max_w is {max_w} W, so this controller may command {-max_w} W, but {op' +refusal 26d0602c32d7 # validate.py over 30 words (79); capitals: THE FIRMWARE WINS :: 'meter_max_age_s is {max_age_s} s but the ESP32 firmware vetoes any P1 ' +refusal 2ade09aaa579 # validate.py over 30 words (73); banned: SAFETY-02, arbiter, watchdog :: 'sign_disagree_w is {sign_w} W but max_w{where} is {weakest} W, so the ' +row c24ab8bd9cb3 # main.py over 15 words (18); banned: heartbeat, layer 1; capitals: NO PASS FOR :: 'control loop: NO PASS FOR {_pass_age} s (layer 1 zeroes the inverter a' +row c771d4bc1e0a # main.py over 15 words (17); banned: telegrams :: "P1 meter ({o.get('meter_source')}): {self.p1.net_w} W, {age} s old, {s" +row f6195fee8575 # main.py over 15 words (33); capitals: METER MAY BE FROZEN :: 'METER MAY BE FROZEN - {…}. The loop is STILL FOLLOWING it and is still' +row db05be7cd99c # main.py over 15 words (16); option key: meter_source; capitals: NOT COVERED :: "freeze detector: NOT COVERED on meter_source {o.get('meter_source')} -" +row 9a21960bbbe8 # main.py capitals: NOT COVERED :: 'freeze detector: NOT COVERED - {…}' +row c38b746a6585 # main.py banned: SATURATED; capitals: PEAK GUARD SATURATED :: 'PEAK GUARD SATURATED - {…}' +row dd0629834473 # main.py over 15 words (36); banned: SAFETY-25; option key: peak_soc_floor; capitals: THE PEAK GUARD ONLY :: '{…}. NOTE: peak_soc_floor bounds THE PEAK GUARD ONLY - it is not a pac' +row 4132e246e675 # main.py over 15 words (26); banned: telegrams; option key: meter_source; capitals: NOT COVERED :: "peak guard: NOT COVERED on meter_source {o.get('meter_source')} - the " +row 7b34b16d8bb2 # main.py over 15 words (61) :: '{label}: no usable value this cycle from {entity} - and this row canno' +row 04e0381f16c2 # main.py banned: CLAMP; capitals: OUTPUT CLAMP ENGAGED :: 'OUTPUT CLAMP ENGAGED - {…} Engagements: {self.clamp_wd.engagements}.' +row 9f8b8adcbc6c # main.py banned: INTEGRATOR; capitals: LOOP AT INTEGRATOR BOUND :: 'LOOP AT INTEGRATOR BOUND - {…} Engagements: {self.clamp_wd.engagements' +row f00cc9688eca # main.py over 15 words (20); banned: clamp :: 'output clamp: not engaged now, but it has engaged {self.clamp_wd.engag' +row a44333431331 # main.py over 15 words (31); capitals: SIGN-DISAGREEMENT FAILSAFEX :: 'SIGN-DISAGREEMENT FAILSAFE{tag} - {…}. The inverter is held at 0 W. Fi' +row 3ef4e60f2328 # main.py over 15 words (17) :: 'sign watchdog{tag}: armed{vs} (trips after {inv.sign_wd.cfg.hold_s} s ' +row 9f879b339282 # main.py over 15 words (50); banned: integrator; capitals: SITE SIGN-DISAGREEMENT FAILSAFE :: 'SITE SIGN-DISAGREEMENT FAILSAFE - {…}. EVERY inverter is held at 0 W. ' +row 96e93e34bdbf # main.py over 15 words (24); banned: watchdog :: 'site sign watchdog: armed against the sum of the commands (trips after' +row 9ee8d293fea5 # main.py over 15 words (38); capitals: CIRCULATING POWER :: 'CIRCULATING POWER - {…}. EVERY inverter is held at 0 W. The meter cann' +row 55eb950acd5f # main.py over 15 words (17); banned: watchdog :: 'circulation watchdog: armed (trips after {self.circ_wd.cfg.hold_s} s o' +row 1817192a7f1c # main.py over 15 words (42); capitals: NOT DELIVERINGX :: 'NOT DELIVERING{tag} - {…}. Nothing has been commanded differently and ' +row 685c1416364b # main.py over 15 words (26) :: 'delivery watchdog{tag}: armed (reports after {inv.delivery_wd.cfg.hold' +row d3cd52827dd0 # main.py over 15 words (29); banned: watchdog :: 'delivery watchdog: n/a at one inverter - a unit short of its share is ' +row d6981c8d7b56 # main.py banned: latched :: 'no e-stop fitted: if this host dies the battery stays latched at its l' +row 685c8f02c97a # main.py capitals: NO SITE TOTAL :: 'PV production: NO SITE TOTAL - {…}. Reporting: {…}' +row abef339bf192 # main.py over 15 words (25); option key: pv_entities :: 'PV production: `pv_entities` is set, so `pv_entity` is IGNORED - the {' +row 514511bd0a93 # main.py over 15 words (32); option key: pv_invert_entities :: 'PV production: {ent} reads {watt} W - far below zero, so its sign is p' +row 328abd6171ce # main.py over 15 words (22); option key: pv_invert_entities :: 'PV production: `pv_invert_entities` names {ent}, which is not a PV ent' -- 2.54.0 From 7b65a3e69a1eb78454c45ce7f347afcfda22fc58 Mon Sep 17 00:00:00 2001 From: review-agent <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 01:18:55 +0200 Subject: [PATCH 028/105] UX-08 review: tighter notification texts, and two meaning fixes - not delivering: the body said control keeps running and then "start control"; clearing it takes stop then start, and it now says so. - peak reserve: the "reserve not set" branch is really soc_floor None, i.e. an inverter's cut-out level missing; it now names that. The title is true on all three branches ("Battery stopped limiting the peak"). - no semicolon run-ons in bodies (STYLE.md + test); loop-bound, circulating, meter-frozen and multi-unit over-rating bodies rewritten to match. - allowlist cap is now exact, so a shrink cannot leave room to regrow. - DOCS names the settings behind "peak reserve" and "cut-out level"; DECISIONS no longer states the HA anchor behaviour as fact. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 6 +- goodwe_controller/DOCS.md | 17 ++++-- goodwe_controller/app/main.py | 2 +- goodwe_controller/app/messages.py | 57 ++++++++++--------- goodwe_controller/test_messages.py | 13 ++++- goodwe_controller/test_peakguard.py | 2 +- goodwe_controller/test_watchdog.py | 4 +- 8 files changed, 61 insertions(+), 42 deletions(-) diff --git a/STYLE.md b/STYLE.md index f5ea0d5..7bbb891 100644 --- a/STYLE.md +++ b/STYLE.md @@ -8,7 +8,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. - **Status row**: at most 15 words. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. - **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. -- **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets. These translate well into Dutch and French. +- **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. ## 2. Numbers Use a number only if it helps the reader act, for example the peak limit, or what was asked and what was sent in a fault report. Write it the way `app/messages.py` does: `5 000 W`, `20 %`, `10 minutes`, `14:05`. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index ce6648f..488a082 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -5,10 +5,10 @@ The owner decided on 2026-09-27: a title of at most about 5 everyday words and a **Unchanged:** every `notification_id`, every trigger and cadence (edges, SAFETY-34 re-announce, per-unit ids), every log line and every status row. The status banner and rows are phase 2b, refusals and option texts 2c, logs 2d; `ux08_allowlist.txt` lists them until then. ## Where a choice was made -1. **Severity of "not delivering" (SAFETY-42).** The notification is an *alarm*, so it may use 3 sentences. Its log line is ERROR and the alarm is latched. The page banner stays amber, as SAFETY-42 decided, because control keeps running. The three checks stay in their original order. +1. **Severity of "not delivering" (SAFETY-42).** The notification is an *alarm*, so it may use 3 sentences. Its log line is ERROR and the alarm is latched. The page banner stays amber, as SAFETY-42 decided, because control keeps running; the two answer different questions (is control running / must a person act) and HA shows no colour on a notification. The three checks stay in their original order. Clearing it takes stop then start, and the body says so. 2. **Figures left the bodies** of the frozen-meter card (the rail and the command), the circulating-power card (the watts and the time window) and the peak cards (the projection). None of them is needed to act, and all of them are still in the reason text that the log line and the status row carry. `test_freeze.py` and `test_watchdog.py` now pin that. The frozen-meter card can therefore no longer quote a wrong rail (SAFETY-20), because it quotes none. 3. **The over-rating alarm keeps its numbers** (asked, sent, and which limit cut it), because they are what a fault report needs. `ClampWatchdog.facts` carries them under the same keep-the-bug rule as `reason`, so the words and the numbers always describe the same tick, with asked before sent (SAFETY-40, `test_clamp.py` part 6). -4. **SAFETY-25 stays in the peak-reserve alarm** as its last sentence ("the reserve only limits peak shaving … down to its cut-out level"). The alarm now gives each branch its own action: at the reserve, lower it; reserve not set, set one; battery level unread, check the sensor. Before, every branch said "lower peak_soc_floor". +4. **SAFETY-25 stays in the peak-reserve alarm** as its last sentence ("the reserve only limits peak shaving … down to its cut-out level"). The alarm now gives each branch its own action: at the reserve, lower it; battery level unread, check the sensor; floor unknown, set the cut-out level. That last branch is `soc_floor is None`, which happens when an inverter's cut-out level is missing, not the peak reserve (that option always has a value). Before, every branch said "lower peak_soc_floor". The title, "Battery stopped limiting the peak", is true on all three branches. 5. **SAFETY-32 at a roster of one.** The body no longer ends in a separate "WHICH PACK" paragraph. The pack's name is part of the first sentence ("The battery of inverter-b …"), and at a roster of one that is the only difference. 6. **Dropped as background, now in DOCS:** "charging stays blocked" (peak reserve), "why no other guard fired" (circulating power, not delivering), and the saturation-freeze distinction (over-rating). "The meter cannot see this" stays in the circulating-power card, as the owner asked. -7. **The Details link** opens the add-on's documentation page (`/hassio/addon/<slug>/documentation`, with the slug taken from the container hostname) and names the section, because Home Assistant does not render heading anchors there. Outside an add-on container it names the section without a link. +7. **The Details link** opens the add-on's documentation page (`/hassio/addon/<slug>/documentation`, with the slug taken from the container hostname) and names the section. A `#heading` anchor was not used because nobody has checked that Home Assistant's documentation tab renders heading ids; if it does, adding one is a one-line change. Outside an add-on container it names the section without a link. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 5c9cda5..6260c62 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2816,7 +2816,7 @@ texts live in `app/messages.py`. Every notification keeps a fixed | Battery is not keeping up | warning | `goodwe_integrator_bound` | | Power request too high | alarm | `goodwe_output_clamp` | | Load too high for battery | alarm | `goodwe_peak_saturated` | -| Battery at its peak reserve | alarm | `goodwe_peak_soc_floor` | +| Battery stopped limiting the peak | alarm | `goodwe_peak_soc_floor` | | Inverters working against each other | alarm | `goodwe_circulating_power` | | *name* is not delivering | alarm | `goodwe_not_delivering_<name>` | | Meter reading may be stuck | alarm | `goodwe_meter_frozen` | @@ -2854,11 +2854,17 @@ than the inverter. Switching off load in the next few minutes is the only thing that still changes the bill. The projection and the watts are in the add-on log and on the status page. See *The capacity-peak guard*. -### Battery at its peak reserve +### Battery stopped limiting the peak + +Two words in this notification are settings. The **peak reserve** is +*Peak guard will not discharge below (%)* (`peak_soc_floor`). The +**cut-out level** is *Battery cut-out level (%)* (`bms_soc_floor`), where the +battery's own system stops discharging. The peak guard wanted to discharge to hold the 15-minute peak, but it may not go below the peak reserve (`peak_soc_floor`, SAFETY-24). It also stops when the -battery level cannot be read, or when no reserve is set. So this 15-minute +battery level cannot be read, or when an inverter's cut-out level is not set, +because the reserve is graded against it. So this 15-minute period will go over the peak limit and set or raise the month's billed peak. Charging from the grid stays blocked meanwhile. On a site with several inverters the notification names the battery at its limit (SAFETY-32): each battery is @@ -2901,8 +2907,9 @@ to the missing unit's rating. Check, in this order: (`bms_soc_floor`) says? If so, that setting does not describe this battery. 3. Is anything else writing to it? -The alarm is latched and survives restarts; start control on the add-on page -once you know why. See *A unit that stops DELIVERING is a third fault again*. +The alarm is latched and survives restarts. Control is still running, so to +clear it, press *Start / stop control* twice (stop, then start) once you know +why. See *A unit that stops DELIVERING is a third fault again*. ### Meter reading may be stuck diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 85115f4..0a10050 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -3917,7 +3917,7 @@ class Controller: await self.hass.call("persistent_notification", "create", messages.peak_reserve( g.ceiling_w, soc_unread=g.soc is None, - reserve_unset=(g.soc is not None + floor_unknown=(g.soc is not None and g.soc_floor is None), packs=(_blocked if len(self.inverters) > 1 else ())).data()) diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 38501c9..b1682d7 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -83,7 +83,7 @@ class Notice: T_LOOP_BOUND = "Battery is not keeping up" T_OUTPUT_CLAMP = "Power request too high" T_PEAK_SATURATED = "Load too high for battery" -T_PEAK_RESERVE = "Battery at its peak reserve" +T_PEAK_RESERVE = "Battery stopped limiting the peak" T_CIRCULATING = "Inverters working against each other" T_NOT_DELIVERING = "{unit} is not delivering" S_NOT_DELIVERING = "An inverter is not delivering" @@ -109,8 +109,8 @@ LIMIT_WORDS = { def loop_bound() -> Notice: """SAFETY-40: the integrator bound. Normal in short bursts; not a fault.""" return Notice(ID_LOOP_BOUND, WARNING, T_LOOP_BOUND, - "The battery is not following the controller; short moments " - "are normal, repeated ones need a check.") + "The battery cannot give what the controller asks, which is " + "normal for a moment but needs a check if it keeps happening.") @dataclass(frozen=True) @@ -137,12 +137,13 @@ def output_clamp(clamps) -> Notice: c = clamps[0] who = f"For {c.unit}, the" if c.unit else "The" others = [x.unit for x in clamps[1:] if x.unit] - also = (f"; {names(others)} {'was' if len(others) == 1 else 'were'} cut too" - if others else "") + running = (f"{names(others)} {'was' if len(others) == 1 else 'were'} cut " + f"too, and control is still running." if others + else "Control is still running.") return Notice(ID_OUTPUT_CLAMP, ALARM, T_OUTPUT_CLAMP, f"{who} controller asked for {watts(c.asked_w)}, above " f"{LIMIT_WORDS.get(c.limit, LIMIT_WORDS['rating'])}, and sent " - f"{watts(c.sent_w)} instead{also}. Control is still running. " + f"{watts(c.sent_w)} instead. {running} " f"This is a software fault, so please report it to your " f"installer.") @@ -157,20 +158,24 @@ def peak_saturated(ceiling_w) -> Notice: f"the inverter.") -def peak_reserve(ceiling_w, *, soc_unread: bool, reserve_unset: bool, +def peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, packs=()) -> Notice: """SAFETY-24/25/32: the peak guard may not discharge any further. The last sentence is SAFETY-25 and must stay: the reserve binds the peak guard only, and normal home use goes on discharging below it. `packs` names the batteries at their limit, only on a site with several. + `floor_unknown`: the floor the guard grades against is None, which at a + roster means some inverter's cut-out level is missing (the peak reserve + itself always has a value) - so the action names the cut-out level. """ if soc_unread: why = "The battery level cannot be read" act = "Switch off large loads, and check the battery level sensor." - elif reserve_unset: - why = "No peak reserve is set" - act = "Switch off large loads, and set a peak reserve in the settings." + elif floor_unknown: + why = "The cut-out level of a battery is not known" + act = ("Switch off large loads, and set each battery's cut-out level " + "in the settings.") else: why = (f"The battery of {names(packs)} is at its peak reserve" if packs else "The battery is at its peak reserve") @@ -179,7 +184,7 @@ def peak_reserve(ceiling_w, *, soc_unread: bool, reserve_unset: bool, return Notice(ID_PEAK_RESERVE, ALARM, T_PEAK_RESERVE, f"{why}, so this 15-minute period will go over your " f"{watts(ceiling_w)} peak limit and raise this month's peak. " - f"{act} The reserve only limits peak shaving: normal home use " + f"{act} The reserve only applies to keeping the peak down: normal home use " f"can still discharge the battery below it, down to its " f"cut-out level.") @@ -194,10 +199,10 @@ def circulating(discharging=(), charging=()) -> Notice: what = ("One inverter was charging from another, and your meter " "cannot see this.") return Notice(ID_CIRCULATING, ALARM, T_CIRCULATING, - f"{what} Control is stopped and every inverter is set to " - f"0 W; if the grid power does not change now, switch the " - f"inverters off at the isolator. A restart does not clear " - f"this: start control on the add-on page once you know why.") + f"{what} Every inverter is set to 0 W: if the grid power does " + f"not change now, switch the inverters off at the isolator. " + f"Control stays stopped, even after a restart, until you " + f"start it on the add-on page once you know why.") def not_delivering(unit: str, slug: str) -> Notice: @@ -205,11 +210,11 @@ def not_delivering(unit: str, slug: str) -> Notice: return Notice( ID_NOT_DELIVERING.format(slug=slug), ALARM, T_NOT_DELIVERING.format(unit=unit), - f"{unit} gives less power than it is asked for, so the site is short; " - f"nothing was changed and control keeps running. Check that {unit} is " + f"{unit} gives less power than it is asked for, but nothing was " + f"changed and control keeps running. Check that {unit} is " f"on and connected, that its battery is not empty or cold, and that " - f"nothing else controls it. A restart does not clear this: start " - f"control on the add-on page once you know why.", + f"nothing else controls it. A restart does not clear this: once you " + f"know why, stop and start control on the add-on page.", section=S_NOT_DELIVERING) @@ -218,9 +223,9 @@ def meter_frozen(unchanged_s) -> Notice: return Notice(ID_METER_FROZEN, ALARM, T_METER_FROZEN, f"The meter has shown the same value for " f"{duration(unchanged_s)} while the controller asks the " - f"battery for full power. Control is still running and still follows this " - f"reading. Check the meter; if it is stuck, stop control on " - f"the add-on page.") + f"battery for full power. Control is still running and still " + f"follows this reading. Check the meter, and if it is stuck, " + f"stop control on the add-on page.") def samples() -> list: @@ -232,11 +237,11 @@ def samples() -> list: output_clamp([Clamp("inverter-a", -3000, -2500, "device"), Clamp("inverter-b", 6000, 4600, "max_w+device")]), peak_saturated(5000), - peak_reserve(5000, soc_unread=False, reserve_unset=False), - peak_reserve(5000, soc_unread=False, reserve_unset=False, + peak_reserve(5000, soc_unread=False, floor_unknown=False), + peak_reserve(5000, soc_unread=False, floor_unknown=False, packs=["inverter-b"]), - peak_reserve(5000, soc_unread=True, reserve_unset=False), - peak_reserve(5000, soc_unread=False, reserve_unset=True), + peak_reserve(5000, soc_unread=True, floor_unknown=False), + peak_reserve(5000, soc_unread=False, floor_unknown=True), circulating(["inverter-a"], ["inverter-b"]), circulating(), not_delivering("inverter-b", "inverter_b"), diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 4918ea8..46582bc 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -112,6 +112,8 @@ def body_problems(body, severity): out.append(f"{severity} body over 1 sentence ({n_s})") if n_w > 25: out.append(f"{severity} body over 25 words ({n_w})") + if ";" in body: + out.append("semicolon: split it into sentences or drop a clause") return out + text_problems(body, keys=False, entities=False) @@ -297,7 +299,9 @@ def key_of(kind, text): ALLOW_FILE = HERE / "ux08_allowlist.txt" -# The allowlist may never grow: lower this number when you delete lines. +# The allowlist may never grow. The test demands the list be exactly this long, +# so deleting lines means lowering this number in the same change, and adding +# one means raising it where a reviewer sees it. ALLOWLIST_MAX = 200 @@ -340,8 +344,9 @@ for k in stale: f"delete its line from ux08_allowlist.txt") check(f"no allowlist entry is stale, so the list only shrinks " f"({len(stale)} stale)", not stale) -check(f"the allowlist has not grown ({len(allow)} entries, cap {ALLOWLIST_MAX})", - len(allow) <= ALLOWLIST_MAX) +check(f"the allowlist is exactly its cap ({len(allow)} entries, cap " + f"{ALLOWLIST_MAX}): lower the cap when you delete lines", + len(allow) == ALLOWLIST_MAX) print(f"CI: UX-08 allowlist {len(allow)} entries " + ", ".join(f"{k} {sum(1 for x in allow if x.startswith(k + ' '))}" for k in LIMITS)) @@ -366,6 +371,8 @@ check("a six-word title is refused", check("a GoodWe prefix is refused", bool(title_problems("GoodWe: meter stuck"))) check("a second sentence in a warning is refused", bool(body_problems("The battery lags. Check it.", messages.WARNING))) +check("a semicolon run-on is refused, in an alarm too", + bool(body_problems("It stopped; check it.", messages.ALARM))) check("a fourth sentence in an alarm is refused", bool(body_problems("One. Two. Three. Four.", messages.ALARM))) check("an internal name is refused", bool(body_problems( diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 483fd67..1884bbd 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2528,7 +2528,7 @@ _body25 = hass25.last_message("goodwe_peak_soc_floor") def _says_scope(body): """SAFETY-25 in messages.peak_reserve()'s words: the reserve binds the peak guard only, and home use goes on discharging below it to the cut-out.""" - return ("The reserve only limits peak shaving" in body + return ("The reserve only applies to keeping the peak down" in body and "normal home use can still discharge the battery below it" in body and "down to its cut-out level" in body) diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 98558d1..77ca082 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -1112,8 +1112,8 @@ def _says_three(m): """UX-08: the three things only this alarm can say, in its plain words (messages.circulating): the meter cannot see it, control is stopped at 0 W, and if the grid does not move a person at the isolator is next.""" - return ("meter cannot see this" in m and "Control is stopped" in m - and "every inverter is set to 0 W" in m and "isolator" in m + return ("meter cannot see this" in m and "Control stays stopped" in m + and "Every inverter is set to 0 W" in m and "isolator" in m and "if the grid power does not change" in m) -- 2.54.0 From 24f955cb26ae1512c7a45a812fffb9e78cb7d446 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 01:31:35 +0200 Subject: [PATCH 029/105] CI: bump infra pin to 7081df4 (admin/goodwe#59, UX-08) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index ee1edd3..de4eb22 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -76898164b56190f0aa6f7a15be9ce6302c958ce5 +7081df4276ad3cf788355b97a3b3f40ea28d72bd -- 2.54.0 From d017fc67bf7dd4551537ec75a4d8b732d7089261 Mon Sep 17 00:00:00 2001 From: dev-agent <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 02:12:10 +0200 Subject: [PATCH 030/105] UX-08 phase 2b: short, plain status rows and page banners Every Commissioning row and every page banner is now worded in app/messages.py (row_*, banner_*): one sentence of at most 15 words, a red row up to three sentences so a latch still says how it clears, banners at most 12 words. No row names a Home Assistant entity: sensors by their setting, solar sources by their place in the list. Reason codes and limits stay on the log line and event list; rows keep the numbers a reader acts on. UX-07 item 1: ClampWatchdog counts over-rating and integrator-bound engagements separately, and after an episode each count shows under its own alarm's title instead of both under "output clamp". No row colour, visibility or banner order changed. Rows carry an "id" so the tests pin meaning rather than wording. The row and banner kinds leave the allowlist (200 -> 168, cap equal). DOCS.md gains "Status page"; choices are in DECISIONS/UX-08-short-notifications.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 14 + goodwe_controller/DOCS.md | 65 ++- goodwe_controller/app/clamp.py | 8 + goodwe_controller/app/main.py | 483 +++++++----------- goodwe_controller/app/messages.py | 410 +++++++++++++++ goodwe_controller/test_clamp.py | 39 +- goodwe_controller/test_control_task.py | 16 +- goodwe_controller/test_delivery.py | 15 +- goodwe_controller/test_freeze.py | 72 +-- goodwe_controller/test_freshness.py | 25 +- goodwe_controller/test_inverter.py | 14 +- goodwe_controller/test_messages.py | 70 ++- goodwe_controller/test_p1.py | 2 +- goodwe_controller/test_peakguard.py | 72 +-- goodwe_controller/test_pv.py | 175 +++---- goodwe_controller/test_tariff.py | 2 +- goodwe_controller/test_watchdog.py | 45 +- goodwe_controller/ux08_allowlist.txt | 38 +- 19 files changed, 989 insertions(+), 578 deletions(-) diff --git a/STYLE.md b/STYLE.md index 7bbb891..34af509 100644 --- a/STYLE.md +++ b/STYLE.md @@ -6,7 +6,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Title**: at most 5 everyday words. It says what is wrong ("Meter reading may be stuck"). No "GoodWe:" prefix, no full stop. - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. -- **Status row**: at most 15 words. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. +- **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. - **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index 488a082..da54cb9 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -12,3 +12,17 @@ The owner decided on 2026-09-27: a title of at most about 5 everyday words and a 5. **SAFETY-32 at a roster of one.** The body no longer ends in a separate "WHICH PACK" paragraph. The pack's name is part of the first sentence ("The battery of inverter-b …"), and at a roster of one that is the only difference. 6. **Dropped as background, now in DOCS:** "charging stays blocked" (peak reserve), "why no other guard fired" (circulating power, not delivering), and the saturation-freeze distinction (over-rating). "The meter cannot see this" stays in the circulating-power card, as the owner asked. 7. **The Details link** opens the add-on's documentation page (`/hassio/addon/<slug>/documentation`, with the slug taken from the container hostname) and names the section. A `#heading` anchor was not used because nobody has checked that Home Assistant's documentation tab renders heading ids; if it does, adding one is a one-line change. Outside an add-on container it names the section without a link. + +# Phase 2b: status rows and page banners + +Every row of the Commissioning list and every banner is now in `app/messages.py` (`row_*`, `banner_*`), and `test_messages.py` checks a rendering of each. The row and banner kinds are gone from `ux08_allowlist.txt` (200 → 168 entries). DOCS.md "Status page" explains the rows. **Unchanged:** every row's colour (ok / warn / bad), which rows show when, and the banner cascade order. + +## Where a choice was made +1. **A red row may use 3 sentences (30 words).** STYLE.md gave rows 15 words; the owner allows red safety states 3 sentences. A red row needs room for what happened, the state (0 W) and how it clears. STYLE.md now says so, and the test applies it by colour. +2. **Figures left the rows, not the product.** The reason texts (freeze, sign, circulating, delivery, peak guard) carry reason codes and limits; they stay on the ERROR/WARNING log line and the event list, as before. Rows keep the numbers a reader acts on: the stall age and the 0 W deadline, the meter age and limit, asked and sent for an over-rating, the peak limit, and "opposite for 12 of 60 seconds" while a check counts. So 2a item 2 ("also on the status row") no longer holds, and DOCS.md says "in the add-on log". +3. **No entity id on any row**, even the green ones that used to print `sensor.x = 54`. The sensor rows name the setting (*Battery power for inverter-b*). Solar sources are numbered in the order of the settings list (*source 2 of 3*, *entry 1 of the reversed-sign list*). This retires TEL-12's rule that a one-entity site reads 0.11.0's sentence byte for byte. A `tools/tel11_pv_trace.py --compare` against a pre-UX-08 tree therefore shows the PV rows as changed telemetry, and the control documents stay equal. The per-source watts and units left the multi-source row. The total, the count and which source is missing remain. +4. **UX-07 item 1.** `ClampWatchdog` now also counts `over_rating` and `bound` separately. After an episode, each count shows under its own alarm's title ("Power request too high: 2 times since start, not now", "Battery is not keeping up: …"). A site with both gets two amber rows where it had one. +5. **The "Not ready" banner** is the first red row's own `banner`, or else its first sentence. The peak-reserve and over-rating rows set `banner` to their notification title. The three trips keep their own banner branches, reworded (e.g. "Inverters worked against each other. Every inverter is set to 0 W."). +6. **How a latch clears stays on the row**, shortened: "Only starting control clears this", "A restart does not clear this", "only stopping and starting control clears this" (not delivering). SAFETY-25's sentence stays on the peak-reserve row. +7. **Rows got an `id`** (`meter_frozen`, `direction`, `pv`, …), so tests find a row by what it is, not by its words. The page ignores it. +8. **Left for later:** texts that rows embed from other modules and that were not flagged as rows (the month-peak line, `peakguard.explain()`, the liveness and stale notes, `shadow.banner()`). The month-peak row only lost its semicolons. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 6260c62..fbd8814 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -477,7 +477,7 @@ History recorded before you set it keeps the old sign. See The add-on reads your entity's own `unit_of_measurement` and converts: `mW`, `W`, `kW`, `MW`, `GW`, `TW` — Home Assistant's own power units. A sensor with **no** unit, or with a unit that is not one of those, is **refused**, and the -status page says which entity and which unit. That is deliberate: there is no +status page says so (*the sensor has no unit*). That is deliberate: there is no magnitude test that can separate 30 W of dusk from 30 kW of noon, so a guess here would be a silent factor of 1000 in the one channel that exists to be believed a week later. @@ -534,7 +534,7 @@ about: |---|---|---| | all three reporting 1200 / 2100 / 450 W | `3750.0` | `PV 3 750 W` | | all three reporting, one of them **0 W** | `1650.0` | `PV 1 650 W` | -| one of the three `unavailable` | `unknown` | `PV —`, plus a caution naming which entity, why, and what the others reported | +| one of the three `unavailable` | `unknown` | `PV —`, plus a caution naming which source is missing | | all three gone | `unknown` | as above | **It does not publish the sum of the ones that answered.** Two inverters out of @@ -546,8 +546,8 @@ it say something false. So the total goes to `unknown` and the recorder stores a gap, exactly as it does for a single dead sensor. The diagnostic is not thrown away — it is put where a person will see it. The -status page names the entity that is missing, the reason, **and** what the -others reported. That page is read live by a human who wants to fix something; +status page names the missing source by its place in the `pv_entities` list +(*source 2 of 3*). That page is read live by a human who wants to fix something; the recorded number is read cold by an analysis that would believe it. Note the **third row against the second**: a member honestly reporting `0 W` is @@ -569,7 +569,7 @@ It is **instrumentation**. It is not an input to the control law, the allocator, the arbiter, the peak guard, the maintenance cycle or any watchdog; it is not part of `inputs_ok`, so a PV integration that breaks cannot stop the battery being regulated; and its status row is a **caution**, never a -`NOT READY`. Wiring production into the control law would be a behaviour change +*Not ready*. Wiring production into the control law would be a behaviour change on a system driving a real battery — and it would destroy the measurement, because the loop would then be reacting to the thing being measured. @@ -791,8 +791,8 @@ repeats. Thresholding that at 30 s would rebuild the false-trip limit cycle at the exact operating point the controller aims for. Freeze detection is a separate problem and needs the low-power case solved first. -You read it yourself instead: the add-on's status page shows it on the P1 line, -as `… 4 rejected, measurement unchanged for 312 s`. On a house drawing real +You read it yourself instead: the add-on's status page shows it on the Meter +row, as `… 4 readings refused, unchanged for 5 minutes`. On a house drawing real power that figure stays in the seconds; minutes of it while the load is clearly not near zero is the meter to go and look at. @@ -1050,9 +1050,9 @@ If the setpoint this add-on is emitting and the grid figure it is regulating on point **opposite ways** — charging the battery while the house imports, or discharging it while the house exports — with both over `sign_disagree_w`, for `sign_disagree_s` **continuously**, the add-on commands **0 W** and holds it -there. The banner reads `FAILSAFE`, the commissioning list says which two -numbers disagreed and for how long, and the `Controller status` entity reports -`failsafe`. +there. The banner reads *Command and meter point opposite ways*, the add-on +log says which two numbers disagreed and for how long, and the `Controller +status` entity reports `failsafe`. #### ⚠️ At two or more inverters this is TWO checks, not one (SAFETY-30) @@ -1194,7 +1194,8 @@ start, because a `persistent_notification` is in memory and that is precisely ho the 2026-09-02 outage went unseen. It is cleared by pressing **Start**, like the other latches. -The banner reads **`NOT DELIVERING — <unit> …`** as a *warning*, not a failure, +The banner reads **`<unit> is not delivering. Control keeps running.`** as a +*warning*, not a failure, and it **displaces** `Running — holding grid at zero`. That last sentence is a claim the site cannot make while a unit is absent, and a page that goes on reading healthy while the fault runs is the whole shape this check exists to @@ -1428,7 +1429,7 @@ What exists today, and what does not: | SoC guard on the loop | ❌ — the BMS is the only energy backstop | On the legacy `meter_source: off` path there are no P1 telegrams, so there is no -quarter-hour average to guard, and the status page says **NOT COVERED**. There +quarter-hour average to guard, and the status page says *Peak guard: off*. There the mitigation is still operational: set `max_w` no higher than the loop actually needs (the tuning was measured at 2000 W and a 1.78 kW load step is tracked fine there), fit the e-stop, and watch for the alarm. @@ -1712,13 +1713,13 @@ the add-on UI. ⚠️ **Only `meter_source: homewizard_local` is covered.** It is the only transport that reads the meter's own document; on `ha_dsmr`, `mqtt_p1`, `ha_signed` and -`off` there is no signal to threshold and the status page says **NOT COVERED** -rather than pretending the guard is armed. +`off` there is no signal to threshold and the status page says *Stuck-meter +check: off* rather than pretending the guard is armed. The same row appears for a second reason: a setpoint device that reports a range from which no command magnitude is available in both directions leaves no rail to measure at all, and a 0 W rail would be satisfied by *every* command. That is -reported as **NOT COVERED** too, and the detector stays silent rather than +reported as *off* too, and the detector stays silent rather than degenerating into the bare "unchanged for N seconds" rule this design exists to avoid. @@ -2851,8 +2852,8 @@ discharge, and the running 15-minute average is still projected over the peak limit. That 15-minute period will set or raise the month's billed peak (capaciteitstarief). The controller is not at fault: the house load is larger than the inverter. Switching off load in the next few minutes is the only thing -that still changes the bill. The projection and the watts are in the add-on log -and on the status page. See *The capacity-peak guard*. +that still changes the bill. The projection and the watts are in the add-on +log. See *The capacity-peak guard*. ### Battery stopped limiting the peak @@ -2888,8 +2889,8 @@ listening to the add-on; this has happened on this hardware, once for 6 h 25 min. Switch the inverters off at the isolator. The alarm is latched: a Home Assistant or add-on restart does not clear it, and the card is raised again every 5 min until you start control on the add-on page. The watts and the time -window are in the add-on log and on the status page. See *The circulating-power -alarm*. +window are in the add-on log; the *Circulating* line on the status page shows the +live watts. See *The circulating-power alarm*. ### An inverter is not delivering @@ -2919,7 +2920,7 @@ regulating against a number that has stopped moving. The age is still fresh, so no other guard stops it. This is an alarm only: control keeps running and keeps following the reading. Held for a whole 15-minute period, it can set the month's billed peak. Check the meter; if it is stuck, stop control on the add-on page. -The limit and command figures are in the add-on log and on the status page. See +The limit and command figures are in the add-on log. See *The frozen-meter alarm*. ## The Web UI @@ -2935,6 +2936,30 @@ inverter.** The configuration page reads and writes the add-on's own settings and can restart the add-on; the set of commands that reach the hardware is exactly the three buttons it always had. +## Status page + +The banner at the top says in one line what matters most now. Below it, the +**Commissioning** list has one short row per check: ✓ green is fine, ! amber +needs a look, ✗ red needs action. The rows name settings in words, never a Home +Assistant entity id. The full figures of any alarm are in the add-on log, on the +ERROR or WARNING line of that alarm. The texts are in `app/messages.py`. + +| Row starts with | What it tells you | +|---|---| +| Controller | When the controller last ran. Red when it has stalled: the control board then sets the inverter to 0 W. | +| Meter | The grid reading, its age, readings refused, and how long its value has not changed. | +| Stuck-meter check | Whether the frozen-meter alarm can run. It needs the HomeWizard local source (`homewizard_local`), an inverter rating, and a power range the inverter can reach. *The inverter's own limit* means the setpoint device's range sets the threshold, below `max_w`. | +| Meter reading may be stuck | The frozen-meter alarm is on. See *Meter reading may be stuck* under Notifications. | +| *month*: peak … | This month's peak, and how close it is to the soft limit. | +| Peak guard, Load too high, Battery at its peak reserve | What the capacity-peak guard is doing. *Peak guard: off* means `meter_source` is `off`, so there is no 15-minute average to guard. | +| Battery level, Battery power, Grid power | The reading of that sensor. *No usable reading* means the sensor is missing **or** its reading is held back as too old (a separate stale-reading row then says so). Check it in Developer Tools before replacing it. | +| Inverter control | The setpoint entity, and the power range the inverter accepts. | +| Power request too high, Battery is not keeping up | The two loop alarms, each with its own count since start. After an episode clears, the count stays, ending in *not now*. See *The winding-loop alarm*. | +| Direction check, Site direction check | The sign checks (SAFETY-02/30). *Opposite for 12 of 60 seconds* counts toward a stop. When it trips, the inverter, or every inverter for the site check, is set to 0 W until you start control. | +| Circulating power check, Inverters worked against each other | SAFETY-31, only with several inverters. | +| Delivery check, *name* is not delivering | SAFETY-42, only with several inverters. | +| Solar production | The PV reading. Sources are numbered in the order of `pv_entities`. The *reversed-sign list* is `pv_invert_entities`. A strongly negative reading by day means that source's sign is reversed. | + ## Status entities If an MQTT broker is available the add-on publishes setpoint, grid power, diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index 9f8bda7..f321e93 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -358,6 +358,10 @@ class ClampWatchdog: def __init__(self): self.active = False self.engagements = 0 # every engagement, never deduplicated + # UX-08: the same count split by alarm type, so the status page names + # each with its own alarm's title after the episode clears. + self.over_rating = 0 # bug=True: "Power request too high" + self.bound = 0 # bug=False: "Battery is not keeping up" self.episodes = 0 # rising edges self.since: datetime | None = None self.last_alarm: datetime | None = None @@ -399,6 +403,10 @@ class ClampWatchdog: """ if engaged: self.engagements += 1 + if bug: + self.over_rating += 1 + else: + self.bound += 1 self.clean_cycles = 0 self.run_len += 1 rising = not self.active diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 0a10050..ffb9ce4 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -4551,27 +4551,24 @@ class Controller: # SAFETY-61. First, so a stalled loop is the headline: the heartbeat is # sent from this loop, so past layer 1's veto the inverter is at 0 W. if self.loop_pass_mono is None: - out.append({"ok": True, "warn": False, - "text": "control loop: starting"}) + out.append({"ok": True, "warn": False, "id": "controller", + "text": messages.row_controller_starting()}) else: _pass_age = time.monotonic() - self.loop_pass_mono if _pass_age > FIRMWARE_INGEST_VETO_S: - out.append({"ok": False, "warn": False, - "text": f"control loop: NO PASS FOR {_pass_age:.0f} s" - f" (layer 1 zeroes the inverter after " - f"{FIRMWARE_INGEST_VETO_S:.0f} s without a " - f"heartbeat)"}) + out.append({"ok": False, "warn": False, "id": "controller", + "text": messages.row_controller_stalled( + _pass_age, FIRMWARE_INGEST_VETO_S)}) else: - out.append({"ok": True, "warn": False, - "text": f"control loop: last pass {_pass_age:.0f} s ago"}) + out.append({"ok": True, "warn": False, "id": "controller", + "text": messages.row_controller_ran(_pass_age)}) if self.p1_enabled: age = self.p1.published_age_s if self.p1.stale: - out.append({"ok": False, "warn": False, - "text": f"P1 meter ({o.get('meter_source')}): no reading for " - f"{age:.0f} s (limit {self.p1.max_age_s:.0f} s)" - + (f" - last error: {self.p1.last_error}" - if self.p1.last_error else "")}) + # The last error is on the add-on log's WARNING line (p1.py). + out.append({"ok": False, "warn": False, "id": "meter", + "text": messages.row_meter_stale( + age, self.p1.max_age_s)}) else: # ⚠️ unchanged_s is REPORTED, never thresholded and never folded # into the age - see HomeWizardLocalSource.unchanged_s for why @@ -4583,33 +4580,26 @@ class Controller: # only homewizard_local has one, and p1_source is None until # amain() builds the transport. unchanged = getattr(self.p1_source, "unchanged_s", None) - out.append({"ok": True, "warn": False, - "text": f"P1 meter ({o.get('meter_source')}): {self.p1.net_w:g} W, " - f"{age:.0f} s old, {self.p1.samples} telegrams, " - f"{self.p1.parse_errors} rejected" - + (f", measurement unchanged for {unchanged:.0f} s" - if unchanged is not None else "")}) + out.append({"ok": True, "warn": False, "id": "meter", + "text": messages.row_meter( + self.p1.net_w, age, self.p1.parse_errors, + unchanged)}) # SAFETY-18. Reported in both states, for the reason SAFETY-02 is: # a detector nobody can see is armed is a detector nobody trusts # when it fires. ok=False/warn=False so the banner goes red - this # is an alarm, and the banner is the loudest surface we own. It # changes NOTHING about control; see check_meter_frozen(). if self.freeze_wd.active: - out.append({"ok": False, "warn": False, - "text": "METER MAY BE FROZEN - " + self.freeze_wd.reason - + ". The loop is STILL FOLLOWING it and is " - "still running. Check the meter. Held here " - "for a quarter of an hour this sets the " - "month's billed capacity peak."}) + # The figures are in `freeze_wd.reason`, on the log and the + # event list (check_meter_frozen()). + out.append({"ok": False, "warn": False, "id": "meter_frozen", + "text": messages.row_meter_frozen()}) elif getattr(self.p1_source, "unchanged_s", None) is None: # Not "armed". Every transport but homewizard_local is invisible # to this check, and saying "armed" there would be a lie the # status page tells on behalf of a guard that cannot run. - out.append({"ok": False, "warn": True, - "text": f"freeze detector: NOT COVERED on " - f"meter_source {o.get('meter_source')} - only " - f"homewizard_local sees whether the meter's own " - f"document changes"}) + out.append({"ok": False, "warn": True, "id": "freeze_check", + "text": messages.row_freeze_off("source")}) elif rail_unreachable(self.site_max_w, dev_min=self.site_dev_bound("dev_min"), dev_max=self.site_dev_bound("dev_max")): @@ -4619,12 +4609,11 @@ class Controller: # and an operator does not need to learn two vocabularies for # it. What differs is only which term is missing: there, # `unchanged_s`; here, a rail the command could ever stand at. - out.append({"ok": False, "warn": True, - "text": f"freeze detector: NOT COVERED - " - + rail_unreachable( - self.site_max_w, - dev_min=self.site_dev_bound("dev_min"), - dev_max=self.site_dev_bound("dev_max"))}) + _no_rating = (not self.site_max_w + or not is_commandable(self.site_max_w)) + out.append({"ok": False, "warn": True, "id": "freeze_check", + "text": messages.row_freeze_off( + "rating" if _no_rating else "range")}) else: # ⚠️ SAFETY-20. THE RAIL PRINTED HERE IS THE RAIL THE PREDICATE # USES, device range included. This row used to interpolate @@ -4643,17 +4632,12 @@ class Controller: # reads `min` and `max` independently and returns None for # whichever attribute is missing or unparseable - so this # renders whatever is there rather than formatting a None. - _cap = ("" if _rail >= rail_w(self.site_max_w) - else " - below max_w because " - + "; ".join( - f"{inv.setpoint_entity or inv.name} accepts " - f"only {inv.dev_min}...{inv.dev_max} W" - for inv in self.inverters)) - out.append({"ok": True, "warn": False, - "text": f"freeze detector: armed (alerts after " - f"{self.freeze_wd.cfg.hold_s:.0f} s unchanged " - f"while the command is over " - f"{_rail:.0f} W{_cap})"}) + # UX-08: "the inverter's own limit" says the device set it; which + # inverter and its range are DOCS and the settings, not entity ids. + out.append({"ok": True, "warn": False, "id": "freeze_check", + "text": messages.row_freeze_on( + self.freeze_wd.cfg.hold_s, _rail, + own_limit=_rail < rail_w(self.site_max_w))}) # TARIFF-01. The month's billed peak, and - the load-bearing half - # a DIFFERENT row when the store could not answer. "no peak yet" is @@ -4673,8 +4657,8 @@ class Controller: "text": _pk.explain() + f" - {_frac * 100:.0f} % of the " f"{self.peak.cap_w:.0f} W soft limit" - + f"; {self.peak.recorded} quarter(s) banked" - + f"; on start: {self.peak.restore_state}"}) + + f", {self.peak.recorded} quarter(s) banked" + + f", on start: {self.peak.restore_state}"}) # SAFETY-07. Three rows, not one, because "idle" and "cannot see" # are opposite states and a page that spelled them the same way @@ -4684,12 +4668,12 @@ class Controller: # decision that has not been taken. _pg = self.peak_guard if _pg is None: - out.append({"ok": True, "warn": True, + out.append({"ok": True, "warn": True, "id": "peak_guard", "text": "peak guard: no decision yet - the first " "control cycle has not run"}) elif _pg.saturated: - out.append({"ok": False, "warn": False, - "text": "PEAK GUARD SATURATED - " + _pg.reason}) + out.append({"ok": False, "warn": False, "id": "peak_guard", + "text": messages.row_peak_saturated(_pg.ceiling_w)}) elif _pg.floor_limited: # SAFETY-24. NOT ok, like saturation: in both states the money # is going to be spent and a human is the only actuator left. A @@ -4713,22 +4697,27 @@ class Controller: # the whole sentence, because the row is where an operator # reads what the floor does and does not bound. Shortening the # ROW instead would be weakening AC 3. - out.append({"ok": False, "warn": False, - "banner": _pg.explain() - + " - and peak_soc_floor bounds THE PEAK " - "GUARD ONLY (SAFETY-25, see below)", - "text": _pg.explain() - + ". NOTE: peak_soc_floor bounds THE PEAK " - "GUARD ONLY - it is not a pack-wide " - "reserve, and ordinary self-consumption " - "has no SoC floor, so the battery may " - "keep discharging below this level down " - "to the BMS cut-out (SAFETY-25)"}) + # UX-08: the same three branches, and the same pack naming, as + # check_peak_floor_limited()'s notification. The figures stay in + # `_pg.reason`, on the log and the event list. + _blocked = [name for name, why + in peakguard.pack_permissions(self.packs, + _pg.soc_floor) + if why is not None] + out.append({"ok": False, "warn": False, "id": "peak_guard", + "banner": messages.banner_peak_reserve(), + "text": messages.row_peak_reserve( + _pg.ceiling_w, soc_unread=_pg.soc is None, + floor_unknown=(_pg.soc is not None + and _pg.soc_floor is None), + packs=(_blocked if len(self.inverters) > 1 + else ()))}) elif _pg.blind: - out.append({"ok": False, "warn": True, "text": _pg.explain()}) + out.append({"ok": False, "warn": True, "id": "peak_guard", + "text": _pg.explain()}) else: out.append({"ok": not _pg.engaged, "warn": _pg.engaged, - "text": _pg.explain()}) + "id": "peak_guard", "text": _pg.explain()}) else: # ⚠️ OUTSIDE the `p1_enabled` block, and that placement is the point. # SAFETY-07 is NOT COVERED on the legacy single-entity path - the @@ -4737,11 +4726,8 @@ class Controller: # leave the one install that is unprotected showing nothing at all. # Same answer, same reason, as the freeze detector's NOT COVERED row # a few lines up. - out.append({"ok": False, "warn": True, - "text": f"peak guard: NOT COVERED on meter_source " - f"{o.get('meter_source')} - the quarter-hour " - f"average is measured from P1 telegrams and this " - f"path has none, so a runaway cannot be capped"}) + out.append({"ok": False, "warn": True, "id": "peak_guard", + "text": messages.row_peak_guard_off()}) # ⚠️ ONE PAIR OF ROWS PER INVERTER, NAMED. A single "battery SoC" row on # a site with two packs is a page that shows one pack and calls it the @@ -4749,17 +4735,21 @@ class Controller: # that is what an existing install reads. rows = [] for inv in self.inverters: - tag = "" if len(self.inverters) == 1 else f" ({inv.name})" - rows.append((f"battery SoC{tag}", inv.soc, inv.soc_entity)) - rows.append((f"battery power{tag}", inv.batt, inv.batt_entity)) + unit = None if len(self.inverters) == 1 else inv.name + rows.append((messages.LABEL_SOC, unit, inv.soc, inv.soc_entity)) + rows.append((messages.LABEL_BATTERY, unit, inv.batt, + inv.batt_entity)) if not self.p1_enabled: # In P1 mode the check above replaces this one; leaving both in # would report "no entity configured" for a meter_entity that is # correctly unused, i.e. a permanent false NOT READY. - rows.insert(0, ("grid power", self.grid, o.get("meter_entity"))) - for label, value, entity in rows: + rows.insert(0, (messages.LABEL_GRID, None, self.grid, + o.get("meter_entity"))) + # UX-08: the rows name the setting, never the entity id (STYLE.md). + for label, unit, value, entity in rows: if not entity: - out.append({"ok": False, "warn": False, "text": f"{label}: no entity configured"}) + out.append({"ok": False, "warn": False, "id": "sensor", + "text": messages.row_sensor_unset(label, unit)}) elif value is None: # ⚠️ SAFETY-56. THIS ROW ASSERTED A FALSE FACT ABOUT A NAMED # ENTITY, WHICH IS THE WORST THING A DIAGNOSTIC CAN DO. It read @@ -4783,32 +4773,25 @@ class Controller: # pre-empting the answer. Same reason the wording is not shared # with `freshness._grade()`: that one is a log line about a # BEHAVIOUR, this one is a banner about an ENTITY. - out.append({"ok": False, "warn": False, - "text": f"{label}: no usable value this cycle from " - f"{entity} - and this row cannot tell which " - f"of two things that is: the entity is " - f"missing or not numeric, or it is " - f"publishing a number that this controller " - f"is withholding (a freshness gate does " - f"exactly that, and names itself in a row " - f"of its own). Confirm the entity in " - f"Developer Tools before replacing it"}) + out.append({"ok": False, "warn": False, "id": "sensor", + "text": messages.row_sensor_unusable(label, unit)}) else: - out.append({"ok": True, "warn": False, "text": f"{label}: {entity} = {value:g}"}) + out.append({"ok": True, "warn": False, "id": "sensor", + "text": messages.row_sensor(label, value, unit)}) for inv in self.inverters: sp = inv.setpoint_entity - tag = "" if len(self.inverters) == 1 else f" [{inv.name}]" + unit = None if len(self.inverters) == 1 else inv.name if not sp: - out.append({"ok": False, "warn": False, - "text": f"setpoint entity not configured{tag}"}) + out.append({"ok": False, "warn": False, "id": "control", + "text": messages.row_control_unset(unit)}) elif inv.dev_max is None: - out.append({"ok": False, "warn": False, - "text": f"setpoint entity {sp} not found"}) + out.append({"ok": False, "warn": False, "id": "control", + "text": messages.row_control_missing(unit)}) else: - out.append({"ok": True, "warn": False, - "text": f"setpoint {sp} (range {inv.dev_min:g}…" - f"{inv.dev_max:g} W)"}) + out.append({"ok": True, "warn": False, "id": "control", + "text": messages.row_control(inv.dev_min, + inv.dev_max, unit)}) # DEV-02. Whether this controller can still put a number on each # inverter, and it is reported in the ONE state that matters: a unit @@ -4825,28 +4808,35 @@ class Controller: # evidence with it. Reported only when there is something to report: # unlike the freeze detector this guard has no "not covered" state, it # runs on every write on every transport. - if self.clamp_wd.active and self.clamp_wd.bug: - out.append({"ok": False, "warn": False, - "text": "OUTPUT CLAMP ENGAGED - " + self.clamp_wd.reason - + f" Engagements: {self.clamp_wd.engagements}."}) - elif self.clamp_wd.active: + # UX-07 item 1 / UX-08: each count is shown under ITS alarm's name - + # over-rating cuts as "Power request too high", integrator-bound cycles + # as "Battery is not keeping up" - never the two summed under one. + _cw = self.clamp_wd + if _cw.active and _cw.bug: + out.append({"ok": False, "warn": False, "id": "power_too_high", + "banner": messages.banner_power_too_high(), + "text": messages.row_power_too_high(_cw.facts, + _cw.over_rating)}) + elif _cw.active: # SAFETY-40: the integrator bound alone is amber, not red. - out.append({"ok": False, "warn": True, - "text": "LOOP AT INTEGRATOR BOUND - " + self.clamp_wd.reason - + f" Engagements: {self.clamp_wd.engagements}."}) - elif self.clamp_wd.engagements: - out.append({"ok": False, "warn": True, - "text": f"output clamp: not engaged now, but it has " - f"engaged {self.clamp_wd.engagements} time(s) in " - f"{self.clamp_wd.episodes} episode(s) since " - f"start - see the event log"}) + out.append({"ok": False, "warn": True, "id": "not_keeping_up", + "text": messages.row_not_keeping_up(_cw.bound)}) + else: + if _cw.over_rating: + out.append({"ok": False, "warn": True, "id": "power_too_high", + "text": messages.row_before( + messages.T_OUTPUT_CLAMP, _cw.over_rating)}) + if _cw.bound: + out.append({"ok": False, "warn": True, "id": "not_keeping_up", + "text": messages.row_before( + messages.T_LOOP_BOUND, _cw.bound)}) for inv in self.inverters: if inv.last_write_ok is False: - tag = "" if len(self.inverters) == 1 else f" ({inv.name})" - out.append({"ok": False, "warn": False, - "text": f"last write to the inverter{tag} was " - f"REJECTED - check the log"}) + out.append({"ok": False, "warn": False, "id": "write", + "text": messages.row_write_refused( + None if len(self.inverters) == 1 + else inv.name)}) # SAFETY-02. Reported in both states: a watchdog nobody can see is armed # is a watchdog nobody trusts when it fires. @@ -4861,7 +4851,7 @@ class Controller: # inverter's own power sensor. `sign_wd.against` is the same string the # trip sentence uses, so the two cannot drift apart. for inv in self.inverters: - tag = "" if len(self.inverters) == 1 else f" [{inv.name}]" + unit = None if len(self.inverters) == 1 else inv.name # ⚠️ ADDED ONLY WHEN THERE IS SOMETHING TO DISAMBIGUATE. At the # shipped roster of one the two sentences below are the ones that # have always been on the page, word for word - AC 8 is about what @@ -4870,25 +4860,16 @@ class Controller: # somebody has learned to recognise. At N>=2 the noun is load- # bearing: the row would otherwise send them to look at P1 for a # fault that is visible only on one inverter's own power sensor. - vs = ("" if len(self.inverters) == 1 - else f" against {inv.sign_wd.against}") + # UX-08: at N>=2 `unit` is set, and the row says "its own power". + # The figures stay in `sign_wd.reason`, on the log and event list. if inv.sign_wd.tripped: - what = ("the meter" if len(self.inverters) == 1 - else inv.sign_wd.against) - out.append({"ok": False, "warn": False, - "text": f"SIGN-DISAGREEMENT FAILSAFE{tag} - " - + inv.sign_wd.reason - + f". The inverter is held at 0 W. Find out why the " - f"command opposed {what} before starting control " - "again; starting clears this. Restarting the " - "add-on does NOT clear it."}) + out.append({"ok": False, "warn": False, "id": "direction", + "text": messages.row_direction_trip(unit)}) else: held = inv.sign_wd.held_s(datetime.now(timezone.utc)) - out.append({"ok": True, "warn": False, - "text": f"sign watchdog{tag}: armed{vs} (trips after " - f"{inv.sign_wd.cfg.hold_s:.0f} s opposed, both over " - f"{inv.sign_wd.cfg.min_w:.0f} W)" - + (f" - opposed for {held:.0f} s now" if held else "")}) + out.append({"ok": True, "warn": False, "id": "direction", + "text": messages.row_direction_check( + held, inv.sign_wd.cfg.hold_s, unit)}) # --- SAFETY-30: the SITE row ----------------------------------------- # ⚠️ ONLY AT N>=2, and the absence at N=1 is the honest report rather @@ -4898,25 +4879,13 @@ class Controller: # operator learns to skim the list. if len(self.inverters) > 1: if self.site_sign_wd.tripped: - out.append({"ok": False, "warn": False, - "text": "SITE SIGN-DISAGREEMENT FAILSAFE - " - + self.site_sign_wd.reason - + ". EVERY inverter is held at 0 W. This is the " - "SUM of the commands against the meter, so it is " - "not one inverter's fault to find - look at the " - "loop, the integrator and whatever won the " - "arbitration. Starting control clears this; " - "restarting the add-on does NOT."}) + out.append({"ok": False, "warn": False, "id": "site_direction", + "text": messages.row_site_direction_trip()}) else: _sheld = self.site_sign_wd.held_s(datetime.now(timezone.utc)) - out.append({"ok": True, "warn": False, - "text": f"site sign watchdog: armed against the sum of " - f"the commands (trips after " - f"{self.site_sign_wd.cfg.hold_s:.0f} s opposed, " - f"both over " - f"{self.site_sign_wd.cfg.min_w:.0f} W)" - + (f" - opposed for {_sheld:.0f} s now" - if _sheld else "")}) + out.append({"ok": True, "warn": False, "id": "site_direction", + "text": messages.row_site_direction_check( + _sheld, self.site_sign_wd.cfg.hold_s)}) # --- SAFETY-31 ----------------------------------------------------- # ⚠️ SITE-LEVEL, WHERE THE ROWS ABOVE ARE PER-INVERTER, and the row says @@ -4924,28 +4893,20 @@ class Controller: # here would invite the operator to clear "the other one". _circ = self.site_circulating_w if self.circ_wd.tripped: - out.append({"ok": False, "warn": False, - "text": "CIRCULATING POWER - " + self.circ_wd.reason - + ". EVERY inverter is held at 0 W. The meter " - "cannot see this fault, which is why nothing " - "else reported it. Starting control clears " - "this; restarting the add-on does NOT, and " - "neither does restarting Home Assistant."}) + out.append({"ok": False, "warn": False, "id": "circulating", + "text": messages.row_circulating_trip()}) elif len(self.inverters) <= 1: # AC 5. At the shipped roster the quantity is identically zero for # every value of every reading, so "armed" would be a claim to be # watching something that cannot happen. Say what is true instead. - out.append({"ok": True, "warn": False, - "text": "circulating power: n/a at one inverter - " - "sum(|Bi|) - |sum(Bi)| is identically zero"}) + out.append({"ok": True, "warn": False, "id": "circulating", + "text": messages.row_one_inverter( + "Circulating power check")}) else: held = self.circ_wd.held_s(datetime.now(timezone.utc)) - out.append({"ok": True, "warn": False, - "text": "circulation watchdog: armed (trips after " - f"{self.circ_wd.cfg.hold_s:.0f} s over " - f"{self.circ_wd.cfg.min_w:.0f} W)" - + (f" - now {_circ:.0f} W" if _circ else "") - + (f", opposed for {held:.0f} s" if held else "")}) + out.append({"ok": True, "warn": False, "id": "circulating", + "text": messages.row_circulating_check( + _circ, held, self.circ_wd.cfg.hold_s)}) # --- SAFETY-42 ------------------------------------------------------- # ⚠️ PER INVERTER, AND WARN RATHER THAN BAD, WHICH IS THE ONE PLACE THE @@ -4958,42 +4919,26 @@ class Controller: # caution is what a fault nobody is acting on actually is. if len(self.inverters) > 1: for inv in self.inverters: - tag = f" ({inv.name})" if inv.delivery_wd.tripped: - out.append({"ok": False, "warn": True, - "text": f"NOT DELIVERING{tag} - " - + inv.delivery_wd.reason - + ". Nothing has been commanded differently and " - "the rest of the roster is still regulating, " - "so the site is short by this unit's share. " - "Starting control clears this row; restarting " - "the add-on does NOT, and neither does " - "restarting Home Assistant."}) + out.append({"ok": False, "warn": True, "id": "delivery", + "text": messages.row_not_delivering(inv.name)}) else: _dheld = inv.delivery_wd.held_s(datetime.now(timezone.utc)) - out.append({"ok": True, "warn": False, - "text": f"delivery watchdog{tag}: armed (reports after " - f"{inv.delivery_wd.cfg.hold_s:.0f} s short of " - f"its share by over " - f"{self.tuning.saturation_w:.0f} W, with a " - f"sibling that is not)" - + (f" - short for {_dheld:.0f} s now" - if _dheld else "")}) + out.append({"ok": True, "warn": False, "id": "delivery", + "text": messages.row_delivery_check( + inv.name, _dheld, + inv.delivery_wd.cfg.hold_s)}) else: # AC 5, and the same honesty `circulating power: n/a` uses one block # up. At one inverter the reduction this check is has no proper # subset to find, for EVERY input, so "armed" would be a claim to be # watching something that cannot happen. - out.append({"ok": True, "warn": False, - "text": "delivery watchdog: n/a at one inverter - a unit " - "short of its share is indistinguishable from a " - "plant that cannot deliver until there is a " - "sibling to compare it with"}) + out.append({"ok": True, "warn": False, "id": "delivery", + "text": messages.row_one_inverter("Delivery check")}) if not o.get("estop_fitted", False): - out.append({"ok": False, "warn": True, - "text": "no e-stop fitted: if this host dies the battery stays " - "latched at its last command"}) + out.append({"ok": False, "warn": True, "id": "estop", + "text": messages.row_no_estop()}) else: out.append({"ok": True, "warn": False, "text": "e-stop fitted"}) @@ -5017,105 +4962,54 @@ class Controller: # control path. The reason comes from `pv.watts()` rather than being # re-derived here, so the page cannot disagree with the reading. # - # --- TEL-12: AND AT A ROSTER OF ONE THESE TWO SENTENCES ARE 0.11.0's -- - # ⚠️ THE `len(...) == 1` BRANCH IS 0.11.0's CODE UNCHANGED, DOWN TO THE - # f-string, so an install that set `pv_entity` reads the row it already - # reads. That is an ACCEPTANCE CRITERION rather than a courtesy, and it - # is graded across trees by `tools/tel11_pv_trace.py` rather than argued - # here: `pv.total()` passes a single entity's `why` through verbatim for - # exactly this reason. Multi-entity sentences are separate BECAUSE they - # have to say something the single-entity ones never could. + # TEL-12 kept 0.11.0's single-entity sentences word for word. UX-08 + # replaced them on purpose (DECISIONS/UX-08-short-notifications.md), so + # a `tools/tel11_pv_trace.py` compare against a pre-UX-08 tree shows + # these rows as changed telemetry; the control documents stay equal. roster = self.pv_roster if roster: - # TEL-14: each flipped entity is marked where its watts are printed; - # an unflipped one gets "", so 0.12.0's sentences are unchanged. + # UX-08: sources are numbered in the order of the settings list, + # never named by entity id (STYLE.md). The per-source figures and + # units are what `pv.total()` returns; they stay in `pv_parts`. flip = pv_read.inverted(self.o) - - def inv(ent): - return " [sign inverted]" if ent in flip else "" - - if len(roster) == 1: - if self.pv_w is None: - out.append({"ok": False, "warn": True, - "text": f"PV production: no reading from " - f"{roster[0]} - {self.pv_why}"}) - else: - # habit 14: the value sits inside its own literal text, in - # its own slot, beside the entity it was read from and the - # unit it was read in - so a transposition of any two of the - # three is visible in the sentence rather than merely - # present in it. - out.append({"ok": True, "warn": False, - "text": f"PV production: {self.pv_w:.0f} W " - f"from {roster[0]} (reported " - f"in {self.pv_why})" + inv(roster[0])}) + n_src = len(roster) + if self.pv_w is None and n_src == 1: + out.append({"ok": False, "warn": True, "id": "pv", + "text": messages.row_pv_none(self.pv_why)}) elif self.pv_w is None: # ⚠️ THE ROW THAT SAYS THERE IS NO TOTAL, AND IT SAYS IT IN - # THOSE WORDS. `pv.total()`'s note is the argument; this is - # where the operator meets it. The partial information is NOT - # thrown away - every entity that reported is named with its - # watts and every one that did not is named with its reason - - # because this surface is read LIVE by a human who wants the - # diagnostic, whereas the MQTT row is read back COLD a week - # later by an attribution that would believe a smaller number. - # Different reader, different instant, different rule. - out.append({"ok": False, "warn": True, - "text": "PV production: NO SITE TOTAL - " - + self.pv_why + ". Reporting: " - + (", ".join( - f"{ent} {watt:.0f} W" + inv(ent) - for ent, watt, _y in self.pv_parts - if watt is not None) or "nothing")}) + # THOSE WORDS - and which sources are missing, by position. + out.append({"ok": False, "warn": True, "id": "pv", + "text": messages.row_pv_partial( + [i + 1 for i, (_e, watt, _y) + in enumerate(self.pv_parts) if watt is None], + n_src)}) else: - # habit 14 at a roster: the total in its own slot, then EVERY - # contributor in its own slot with its own watts and its own - # unit. A sum that disagrees with the addends it is printed - # beside is visible in the sentence. - out.append({"ok": True, "warn": False, - "text": f"PV production: {self.pv_w:.0f} W from " - f"{len(self.pv_parts)} entities (" - + ", ".join( - f"{ent} {watt:.0f} W in {why}" - + inv(ent) - for ent, watt, why in self.pv_parts) - + ")"}) + out.append({"ok": True, "warn": False, "id": "pv", + "text": messages.row_pv( + self.pv_w, n_src, + n_src == 1 and roster[0] in flip)}) # ⚠️ AND WHEN BOTH KEYS ARE SET, WHICH ONE WON IS STATED. `pv.py`'s # `entities()` makes `pv_entities` REPLACE `pv_entity`, which is the - # right rule (its docstring says why) and is also the rule an - # operator upgrading from 0.11.0 is most likely to trip over: they - # add all their inverters to the new field and the old key is left - # standing, doing nothing. A replacement nobody is told about is the - # "one of which silently wins" `config.yaml` refuses elsewhere - and - # refusing to START over a telemetry key would be observability with - # a foot in the control path, so this is a CAUTION and never a `bad` - # row. + # rule an operator upgrading from 0.11.0 is most likely to trip + # over. A CAUTION and never a `bad` row: telemetry must not stop + # control. if pv_read.entity_is_ignored(self.o): - out.append({"ok": False, "warn": True, - "text": "PV production: `pv_entities` is set, so " - "`pv_entity` is IGNORED - the " - f"{len(roster)} entities in the " - "list are what is summed. Clear " - "`pv_entity` to remove this caution"}) + out.append({"ok": False, "warn": True, "id": "pv", + "text": messages.row_pv_single_ignored()}) # TEL-14: a sign that looks reversed, per entity rather than on the # total - see `pv.NEGATIVE_W` and DECISIONS/TEL-14-pv-sign.md §3. - for ent, watt, _y in self.pv_parts: + for i, (ent, watt, _y) in enumerate(self.pv_parts): if watt is not None and watt < pv_read.NEGATIVE_W: - out.append({"ok": False, "warn": True, - "text": f"PV production: {ent} reads " - f"{watt:.0f} W - far below zero, so " - f"its sign is probably reversed. If " - f"it is producing now, " - + ("REMOVE it from " - "`pv_invert_entities`" - if ent in flip else - "ADD it to `pv_invert_entities`") - + " in the Configuration tab"}) + out.append({"ok": False, "warn": True, "id": "pv", + "text": messages.row_pv_negative( + i + 1, n_src, watt, ent in flip)}) + _inv_list = [str(x or "").strip() + for x in (self.o.get("pv_invert_entities") or [])] for ent in pv_read.stray_inverts(self.o): - out.append({"ok": False, "warn": True, - "text": f"PV production: `pv_invert_entities` " - f"names {ent}, which is not a PV entity in " - f"use, so it flips nothing - check the " - f"spelling against `pv_entities`"}) + out.append({"ok": False, "warn": True, "id": "pv", + "text": messages.row_pv_stray( + _inv_list.index(ent) + 1)}) return out def status_payload(self) -> dict: @@ -5145,9 +5039,7 @@ class Controller: # is the fault the operator has NO OTHER WAY of learning about: a # sign disagreement is visible at the meter and on every dashboard # in the house, and circulating power is visible nowhere at all. - level, banner = "bad", ("CIRCULATING POWER — the inverters were " - "pushing against each other. Site held at " - "0 W.") + level, banner = "bad", messages.banner_circulating() elif self.site_sign_wd.tripped and len(self.inverters) > 1: # SAFETY-30's site half, ABOVE the per-unit rows below and below # circulating power above, and the ordering is the same argument @@ -5156,28 +5048,23 @@ class Controller: # inverter is parked and the fault is in what the site was asking # for, not in one device - naming a unit here would send an operator # to swap the wrong box. - level, banner = "bad", ("FAILSAFE — the site's total command " - "opposed the meter. Every inverter held at " - "0 W.") + level, banner = "bad", messages.banner_site_direction() elif any(i.sign_wd.tripped for i in self.inverters): - # Outranks "NOT READY": nothing is missing, something went wrong. - # ⚠️ THE SENTENCE IS UNCHANGED AT A ROSTER OF ONE, where "the meter" - # is what the unit was graded against. At N>=2 it is that unit's own - # power, so the banner says so - see checks() on why the noun is - # load-bearing rather than cosmetic. - level, banner = "bad", ( - "FAILSAFE — the command opposed the meter. " - "Inverter held at 0 W." if len(self.inverters) == 1 else - "FAILSAFE — an inverter's command opposed its own measured " - "power. That inverter held at 0 W.") + # Outranks "Not ready": nothing is missing, something went wrong. + # At a roster of one the unit was graded against the meter; at N>=2 + # against its own power, so the banner says so - see checks() on + # why the noun is load-bearing rather than cosmetic. + level, banner = "bad", messages.banner_direction( + len(self.inverters) > 1) elif bad: # ⚠️ `banner` IF THE ROW OFFERS ONE, `text` OTHERWISE. A row may # need to say more to an operator reading the checks list than fits # in the one line at the top of the page - SAFETY-25's floor-limited # row is the case that forced this - and a headline that is a full # paragraph, repeated verbatim by the row underneath it, is a - # headline nobody reads. Rows without the key are unaffected. - level, banner = "bad", f"NOT READY — {bad[0].get('banner') or bad[0]['text']}" + # headline nobody reads. UX-08: without the key, the banner takes + # the row's first sentence, so it stays a headline. + level, banner = "bad", messages.banner_not_ready(bad[0]) elif not self.auto: level, banner = "warn", "Stopped — inverter commanded to 0 W" elif any(i.delivery_wd.tripped for i in self.inverters): @@ -5194,12 +5081,8 @@ class Controller: # precisely the shape this whole card exists to remove. It sits # BELOW "Stopped" because a stopped site is the more urgent fact and # the banner carries one sentence. - _nd = ", ".join(i.name for i in self.inverters - if i.delivery_wd.tripped) - level, banner = "warn", ( - f"NOT DELIVERING — {_nd} is standing at a share it is not " - f"producing. The site is still running and short by it; " - f"nothing has been commanded differently.") + level, banner = "warn", messages.banner_not_delivering( + [i.name for i in self.inverters if i.delivery_wd.tripped]) elif self.maint.phase != IDLE: # ⚠️ THE PACK IS NAMED ONLY WHEN THERE IS MORE THAN ONE. At a roster # of one this is the string it has always been, character for diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index b1682d7..619192c 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -228,6 +228,416 @@ def meter_frozen(unchanged_s) -> Notice: f"stop control on the add-on page.") +# --- the status page (UX-08 phase 2b) ---------------------------------------- +# The rows of the Commissioning list and the banner at the top of the add-on +# page. `main.py` decides WHEN a row shows and its colour (ok / warn / bad); +# these decide WHAT it says. A row is one sentence of at most 15 words; a red +# row may use up to 3 sentences and 30 words. A banner is at most 12 words. +# Rows never name a Home Assistant entity: they name the setting in words. +# DOCS.md, "Status page", explains every row. + +NOT_READY = "Not ready" +DOCS_STATUS = "Status page" + + +def signed_watts(value) -> str: + """`-1200` -> `-1 200 W`: like `watts()`, but the sign is kept.""" + return f"{float(value):,.0f} W".replace(",", " ") + + +def seconds(value) -> str: + """Always in seconds, for a live count set against its limit.""" + n = f"{float(value):.0f}" + return f"{n} second" if n == "1" else f"{n} seconds" + + +def times(n) -> str: + return "1 time" if int(n) == 1 else f"{int(n)} times" + + +def for_unit(unit) -> str: + """` for inverter-b` on a site with several inverters, else nothing.""" + return f" for {unit}" if unit else "" + + +def headline(text: str) -> str: + """The first sentence of a row, for the banner when the row has no own.""" + first = re.split(r"(?<=[.!?])\s+(?=[A-Z0-9])", text.strip(), maxsplit=1)[0] + return first.rstrip(".") + + +# Banners (the headline at the top of the page). +def banner_not_ready(row: dict) -> str: + return f"{NOT_READY} — {row.get('banner') or headline(row['text'])}" + + +def banner_circulating() -> str: + return "Inverters worked against each other. Every inverter is set to 0 W." + + +def banner_site_direction() -> str: + return "Total command and meter point opposite ways. All inverters at 0 W." + + +def banner_direction(several: bool) -> str: + if several: + return "Inverter and own power point opposite ways. It is at 0 W." + return "Command and meter point opposite ways. Inverter set to 0 W." + + +def banner_not_delivering(units) -> str: + units = list(units) + verb = "are" if len(units) > 1 else "is" + return f"{names(units)} {verb} not delivering. Control keeps running." + + +# Rows: the controller and the meter. +def row_controller_starting() -> str: + return "Controller: starting" + + +def row_controller_ran(age_s) -> str: + return f"Controller: last ran {seconds(age_s)} ago" + + +def row_controller_stalled(age_s, veto_s) -> str: + return (f"Controller has not run for {seconds(age_s)}. The control board " + f"sets the inverter to 0 W after {seconds(veto_s)}.") + + +def row_meter_stale(age_s, limit_s) -> str: + return (f"Meter: no reading for {seconds(age_s)}, limit " + f"{seconds(limit_s)}. The add-on log shows why.") + + +def row_meter(net_w, age_s, rejected=0, unchanged_s=None) -> str: + return (f"Meter: {signed_watts(net_w)}, {seconds(age_s)} old" + + (f", {rejected} readings refused" if rejected else "") + + ("" if unchanged_s is None + else f", unchanged for {duration(unchanged_s)}")) + + +def row_meter_frozen() -> str: + return (f"{T_METER_FROZEN}. Control still follows it. Check the meter, " + f"and stop control if it is stuck.") + + +FREEZE_OFF = { + "source": "it only works with the HomeWizard local meter source", + "rating": "the inverter rating is not set", + "range": "the inverter reports no usable power range", +} + + +def row_freeze_off(why: str) -> str: + """`why` is a key of FREEZE_OFF: why the stuck-meter check cannot run.""" + return f"Stuck-meter check: off, {FREEZE_OFF[why]}" + + +def row_freeze_on(hold_s, rail_w, own_limit: bool) -> str: + return (f"Stuck-meter check: alerts after {duration(hold_s)} unchanged " + f"above {watts(rail_w)}" + + (", the inverter's own limit" if own_limit else "")) + + +# Rows: the peak guard. +def row_peak_saturated(ceiling_w) -> str: + return (f"{T_PEAK_SATURATED}. Switch off large loads to stay under the " + f"{watts(ceiling_w)} peak limit.") + + +def row_peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, + packs=()) -> str: + """SAFETY-24/25/32. The second sentence is SAFETY-25 and must stay.""" + if soc_unread: + why = "Battery level cannot be read" + elif floor_unknown: + why = "A battery cut-out level is not set" + else: + why = (f"{names(packs)} battery at its peak reserve" if packs + else "Battery at its peak reserve") + return (f"{why}, so the {watts(ceiling_w)} peak limit will be passed. Home " + f"use still discharges below the reserve, down to the cut-out level.") + + +def row_peak_guard_off() -> str: + """No meter source: the 15-minute average cannot be measured.""" + return ("Peak guard: off, it needs a meter source instead of the grid " + "power sensor") + + +def banner_peak_reserve() -> str: + return T_PEAK_RESERVE + + +# Rows: the sensors and the inverter control. +LABEL_SOC = "Battery level" +LABEL_BATTERY = "Battery power" +LABEL_GRID = "Grid power" + + +def row_sensor(label, value, unit=None) -> str: + shown = f"{float(value):g} %" if label.startswith(LABEL_SOC) \ + else signed_watts(value) + return f"{label}{for_unit(unit)}: {shown}" + + +def row_sensor_unset(label, unit=None) -> str: + return f"{label}{for_unit(unit)}: no sensor set in the settings" + + +def row_sensor_unusable(label, unit=None) -> str: + """SAFETY-56: it may be missing OR held back as stale; say both.""" + return (f"{label}{for_unit(unit)}: no usable reading. The sensor may be " + f"missing, or its reading is held back as too old. Check it in " + f"Developer Tools before replacing it.") + + +def row_control_unset(unit=None) -> str: + return f"Inverter control{for_unit(unit)}: not set in the settings" + + +def row_control_missing(unit=None) -> str: + return f"Inverter control{for_unit(unit)}: not found in Home Assistant" + + +def row_control(lo_w, hi_w, unit=None) -> str: + def w(v): + return "?" if v is None else signed_watts(v) + return f"Inverter control{for_unit(unit)}: ready, from {w(lo_w)} to {w(hi_w)}" + + +# Rows: the two loop alarms. The names are the notification titles, so the +# row and the card always call the same thing by the same name (UX-07 item 1). +def row_power_too_high(clamps, count) -> str: + c = clamps[0] if clamps else None + what = (f"asked {watts(c.asked_w)}{for_unit(c.unit)}, sent " + f"{watts(c.sent_w)}. Cut back" if c else "cut back") + return (f"{T_OUTPUT_CLAMP}: {what} {times(count)} since start. This is a " + f"software fault, so please report it.") + + +def banner_power_too_high() -> str: + return T_OUTPUT_CLAMP + + +def row_not_keeping_up(count) -> str: + return f"{T_LOOP_BOUND}: {times(count)} since start" + + +def row_before(title, count) -> str: + """After an episode clears: how often it happened, so the evidence stays.""" + return f"{title}: {times(count)} since start, not now" + + +def row_write_refused(unit=None) -> str: + return (f"{unit or 'The inverter'} refused the last command. Check the " + f"add-on log.") + + +# Rows: the direction checks (SAFETY-02/30). +def row_direction_trip(unit=None) -> str: + """Per inverter. `unit` only at several inverters, graded on its own power.""" + what = (f"{unit}: command and its own power point opposite ways, so it is" + if unit else "Command and meter point opposite ways, so the " + "inverter is") + return (f"{what} set to 0 W. Find out why, then start control. A restart " + f"does not clear this.") + + +def row_direction_check(held_s, hold_s, unit=None) -> str: + who = (f"Direction check for {unit}, against its own power" if unit + else "Direction check") + if held_s: + return f"{who}: opposite for {held_s:.0f} of {seconds(hold_s)}" + return f"{who}: on" + + +def row_site_direction_trip() -> str: + return ("Total command and meter point opposite ways, so every inverter is " + "set to 0 W. The cause is the total, not one inverter. Only starting " + "control clears this.") + + +def row_site_direction_check(held_s, hold_s) -> str: + if held_s: + return (f"Site direction check: opposite for {held_s:.0f} of " + f"{seconds(hold_s)}") + return "Site direction check: on, against the meter" + + +# Rows: circulating power (SAFETY-31) and delivery (SAFETY-42). +def row_circulating_trip() -> str: + return ("Inverters worked against each other, so every inverter is set to " + "0 W. The meter cannot see this. Only starting control clears this.") + + +def row_circulating_check(now_w, held_s, hold_s) -> str: + return ("Circulating power check: on" + + (f", now {watts(now_w)}" if now_w else "") + + (f", for {held_s:.0f} of {seconds(hold_s)}" if held_s else "")) + + +def row_one_inverter(check: str) -> str: + return f"{check}: not needed with one inverter" + + +def row_not_delivering(unit) -> str: + return (f"{unit} is not delivering, and only stopping and starting control " + f"clears this") + + +def row_delivery_check(unit, short_s, hold_s) -> str: + if short_s: + return (f"Delivery check for {unit}: short for {short_s:.0f} of " + f"{seconds(hold_s)}") + return f"Delivery check for {unit}: on" + + +def row_no_estop() -> str: + return ("No emergency stop fitted: if this computer fails, the battery " + "keeps its last command") + + +# Rows: solar production (TEL-11/12/14). Sources are numbered in the order of +# the solar sensor list in the settings. +def source(n, of) -> str: + return "the sensor" if of == 1 else f"source {n}" + + +def pv_problem(why: str) -> str: + """`pv.watts()`'s reason, in plain words.""" + w = str(why) + if w.startswith("no state"): + return "the sensor is missing" + if w.startswith("entity is"): + return "the sensor is unavailable" + if w.endswith("is not numeric"): + return "the reading is not a number" + if w.startswith("no unit"): + return "the sensor has no unit" + if w.startswith("unit "): + return "the sensor's unit is not a power unit" + return "the reading is not usable" + + +def row_pv(total_w, count, reversed_=False) -> str: + return (f"Solar production: {signed_watts(total_w)}" + + (f" from {count} sources" if count > 1 else "") + + (", sign reversed" if reversed_ else "")) + + +def row_pv_none(why) -> str: + return f"Solar production: no reading, {pv_problem(why)}" + + +def row_pv_partial(missing, count) -> str: + """`missing` are the 1-based positions of the sources that did not report.""" + which = names([str(n) for n in missing]) + return (f"Solar production: no total, source{'s' if len(missing) > 1 else ''} " + f"{which} of {count} {'have' if len(missing) > 1 else 'has'} no " + f"reading") + + +def row_pv_single_ignored() -> str: + return ("Solar production: clear the single sensor setting, the list " + "replaces it") + + +def row_pv_negative(n, count, value_w, flipped: bool) -> str: + fix = ("remove it from" if flipped else "add it to") + who = source(n, count) + return (f"Solar production: {who} reads {signed_watts(value_w)}, " + f"so {fix} the reversed-sign list") + + +def row_pv_stray(n) -> str: + return (f"Solar production: entry {n} of the reversed-sign list is not a " + f"solar sensor in use") + + +RED, AMBER, GREEN = "bad", "warn", "ok" + + +def status_samples() -> list: + """`(function name, colour, text)` for every row and banner, for the test. + + The colour is the one main.py gives the row; a red row may use three + sentences. Banners are listed with the colour None. + """ + clamp = [Clamp(None, 7412, 5000, "rating")] + return [ + ("banner_not_ready", None, banner_not_ready( + {"text": row_meter_frozen()})), + ("banner_not_ready", None, banner_not_ready( + {"text": "x", "banner": banner_peak_reserve()})), + ("banner_circulating", None, banner_circulating()), + ("banner_site_direction", None, banner_site_direction()), + ("banner_direction", None, banner_direction(False)), + ("banner_direction", None, banner_direction(True)), + ("banner_not_delivering", None, banner_not_delivering(["inverter-b"])), + ("banner_peak_reserve", None, banner_peak_reserve()), + ("banner_power_too_high", None, banner_power_too_high()), + ("row_controller_starting", GREEN, row_controller_starting()), + ("row_controller_ran", GREEN, row_controller_ran(2)), + ("row_controller_stalled", RED, row_controller_stalled(45, 30)), + ("row_meter_stale", RED, row_meter_stale(40, 10)), + ("row_meter", GREEN, row_meter(-350, 2, 3, 340)), + ("row_meter_frozen", RED, row_meter_frozen()), + *(("row_freeze_off", AMBER, row_freeze_off(k)) for k in FREEZE_OFF), + ("row_freeze_on", GREEN, row_freeze_on(600, 4465, True)), + ("row_peak_saturated", RED, row_peak_saturated(5000)), + ("row_peak_guard_off", AMBER, row_peak_guard_off()), + ("row_peak_reserve", RED, row_peak_reserve( + 5000, soc_unread=False, floor_unknown=False, packs=["inverter-b"])), + ("row_peak_reserve", RED, row_peak_reserve( + 5000, soc_unread=True, floor_unknown=False)), + ("row_peak_reserve", RED, row_peak_reserve( + 5000, soc_unread=False, floor_unknown=True)), + ("row_sensor", GREEN, row_sensor(LABEL_SOC, 54, "inverter-b")), + ("row_sensor", GREEN, row_sensor(LABEL_BATTERY, -1200.0, "inverter-b")), + ("row_sensor_unset", RED, row_sensor_unset(LABEL_GRID)), + ("row_sensor_unusable", RED, row_sensor_unusable(LABEL_BATTERY, + "inverter-b")), + ("row_control_unset", RED, row_control_unset("inverter-b")), + ("row_control_missing", RED, row_control_missing("inverter-b")), + ("row_control", GREEN, row_control(-5000, 5000, "inverter-b")), + ("row_power_too_high", RED, row_power_too_high(clamp, 3)), + ("row_power_too_high", RED, row_power_too_high( + [Clamp("inverter-b", 6000, 4600, "max_w+device")], 12)), + ("row_power_too_high", RED, row_power_too_high((), 1)), + ("row_not_keeping_up", AMBER, row_not_keeping_up(48)), + ("row_before", AMBER, row_before(T_OUTPUT_CLAMP, 2)), + ("row_before", AMBER, row_before(T_LOOP_BOUND, 1)), + ("row_write_refused", RED, row_write_refused("inverter-b")), + ("row_direction_trip", RED, row_direction_trip()), + ("row_direction_trip", RED, row_direction_trip("inverter-b")), + ("row_direction_check", GREEN, row_direction_check(0, 60)), + ("row_direction_check", GREEN, row_direction_check(12, 60, + "inverter-b")), + ("row_site_direction_trip", RED, row_site_direction_trip()), + ("row_site_direction_check", GREEN, row_site_direction_check(0, 60)), + ("row_site_direction_check", GREEN, row_site_direction_check(5, 60)), + ("row_circulating_trip", RED, row_circulating_trip()), + ("row_circulating_check", GREEN, row_circulating_check(1200, 20, 60)), + ("row_one_inverter", GREEN, row_one_inverter("Delivery check")), + ("row_not_delivering", AMBER, row_not_delivering("inverter-b")), + ("row_delivery_check", GREEN, row_delivery_check("inverter-b", 30, 120)), + ("row_delivery_check", GREEN, row_delivery_check("inverter-b", 0, 120)), + ("row_no_estop", AMBER, row_no_estop()), + ("row_pv", GREEN, row_pv(3200, 2)), + ("row_pv", GREEN, row_pv(1800, 1, True)), + ("row_pv_none", AMBER, row_pv_none("no unit_of_measurement on the " + "entity - it cannot be read in watts")), + ("row_pv_partial", AMBER, row_pv_partial([2, 3], 3)), + ("row_pv_partial", AMBER, row_pv_partial([2], 2)), + ("row_pv_single_ignored", AMBER, row_pv_single_ignored()), + ("row_pv_negative", AMBER, row_pv_negative(2, 3, -1500, False)), + ("row_pv_negative", AMBER, row_pv_negative(1, 1, -1500, True)), + ("row_pv_stray", AMBER, row_pv_stray(2)), + ] + + def samples() -> list: """One rendering of every notice, with realistic values, for the test.""" return [ diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index f4e4cda..92e4bdb 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -541,11 +541,24 @@ check("...and the count in the row is the counter's, so nothing is lost", # is captured mid-run rather than asserted after the hysteresis has cleared it. check("the status page flags it WHILE it is engaged - amber, since it is the " "integrator bound (SAFETY-40; red is part 9's over-rating case)", - any(not c["ok"] and c["warn"] and "LOOP AT INTEGRATOR BOUND" in c["text"] + any(not c["ok"] and c["warn"] and c.get("id") == "not_keeping_up" + and c["text"].startswith(messages.T_LOOP_BOUND) for c in ctl_r.red_snapshot)) -check("...and once clear, a warn row still says how many times it engaged", - any(c["warn"] and f"{ctl_r.clamp_wd.engagements} time(s)" in c["text"] - for c in ctl_r.checks())) +check("...and once clear, a warn row still says how many times it engaged, " + "under the integrator bound's own title", + any(c["warn"] and c.get("id") == "not_keeping_up" + and c["text"].startswith(messages.T_LOOP_BOUND) + and messages.times(ctl_r.clamp_wd.bound) in c["text"] + and "not now" in c["text"] for c in ctl_r.checks())) +# UX-07 item 1: the after-episode row used to say "output clamp ... engaged N +# time(s)" for integrator-bound cycles. Each count now sits under its own name. +check("UX-07 item 1: bound-only engagements are counted as the bound, and no " + "row calls them 'Power request too high'", + ctl_r.clamp_wd.bound == ctl_r.clamp_wd.engagements > 0 + and ctl_r.clamp_wd.over_rating == 0 + and not any(c.get("id") == "power_too_high" + or messages.T_OUTPUT_CLAMP in c["text"] + for c in ctl_r.checks())) # ⚠️ NOT A TRIP. 11.2's action is "clamp and alarm"; the loop keeps running and # keeps writing the clamped value. If a later cut changes that it must come here. @@ -592,7 +605,8 @@ check("AC 2: the clamp counted ZERO engagements", ctl_s.clamp_wd.engagements == check("AC 2: no OUTPUT_CLAMP row in the action log", not [e for e in ctl_s.events if REASON_CODE in e]) check("AC 2: and no clamp row on the status page", - not [c for c in ctl_s.checks() if "output clamp" in c["text"].lower()]) + not [c for c in ctl_s.checks() + if c.get("id") in ("power_too_high", "not_keeping_up")]) print(" ...and the two alarms do not share a notification_id") ids_clamp = {d["notification_id"] for d in clamp_notes(hass_r)} @@ -1991,8 +2005,8 @@ check("...logged as a WARNING, not an ERROR", and not any(x.levelno >= logging.ERROR and "OUTPUT_CLAMP" in x.getMessage() for x in log_i)) check("...and the status row is amber, not red", - any(c["warn"] and "LOOP AT INTEGRATOR BOUND" in c["text"] for c in red_i) - and not any(not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] + any(c["warn"] and c.get("id") == "not_keeping_up" for c in red_i) + and not any(not c["warn"] and c.get("id") == "power_too_high" for c in red_i)) # --- 9b. the genuine over-rating: integrator_max_w above max_w ---------------- @@ -2023,8 +2037,17 @@ check("...under the over-rating title, quoting a tick's own asked and sent " and any(_asked_then_sent(n["message"], _f(d, 'requested_w'), _f(d, 'clamped_w')) for d, t, r in over) for n in clamp_notes(hass_o)) - and any(not c["warn"] and "OUTPUT CLAMP ENGAGED" in c["text"] + and any(not c["warn"] and c.get("id") == "power_too_high" + and c["text"].startswith(messages.T_OUTPUT_CLAMP) for c in red_o)) +# The red row quotes the same tick's numbers as the card, asked before sent. +_row_o = [c["text"] for c in red_o if c.get("id") == "power_too_high"] +check("...and the red row quotes asked before sent, from one of those ticks", + _row_o and any( + f"asked {messages.watts(_f(d, 'requested_w'))}" in _row_o[0] + and f"sent {messages.watts(_f(d, 'clamped_w'))}" in _row_o[0] + and _row_o[0].index("asked") < _row_o[0].index("sent") + for d, t, r in over)) # --- 9c. the text, directly, and the two budgets ------------------------------- from app.clamp import loop_clamp_note # noqa: E402 diff --git a/goodwe_controller/test_control_task.py b/goodwe_controller/test_control_task.py index 2947e1c..ed1f8b0 100644 --- a/goodwe_controller/test_control_task.py +++ b/goodwe_controller/test_control_task.py @@ -337,15 +337,19 @@ def rows_for(pass_age): r_new, r_29, r_31 = rows_for(None), rows_for(29), rows_for(31) print(f" {r_new[0]} | {r_29[0]} | {r_31[0]}") +# UX-08: the wording is app/messages.py's; these pin the meaning - which row, +# its colour, and the two numbers (age, veto) an operator acts on. check("before the first pass the row is ok and says 'starting'", - r_new[0] == {"ok": True, "warn": False, "text": "control loop: starting"}) + r_new[0]["id"] == "controller" and r_new[0]["ok"] and not r_new[0]["warn"] + and "starting" in r_new[0]["text"]) check("29 s after a pass it is ok", - r_29[0] == {"ok": True, "warn": False, - "text": "control loop: last pass 29 s ago"}) + r_29[0]["id"] == "controller" and r_29[0]["ok"] and not r_29[0]["warn"] + and "29 seconds ago" in r_29[0]["text"]) check("31 s after a pass it is RED and first, naming the age and the veto", - r_31[0] == {"ok": False, "warn": False, - "text": "control loop: NO PASS FOR 31 s (layer 1 zeroes the " - "inverter after 30 s without a heartbeat)"}) + r_31[0]["id"] == "controller" and not r_31[0]["ok"] + and not r_31[0]["warn"] + and "not run for 31 seconds" in r_31[0]["text"] + and "0 W after 30 seconds" in r_31[0]["text"]) async def one_pass(): diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index b387b0a..da20040 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -930,14 +930,18 @@ check("...but the banner does NOT go on saying 'Running - holding grid at " "zero'. That sentence is a claim the site cannot make while a unit is " "absent, and 'the page reads healthy while the fault runs' is the shape " "this whole card exists to remove. It names the unit and stays a WARNING", - _pay["level"] == "warn" and "NOT DELIVERING" in _pay["banner"] + _pay["level"] == "warn" and "is not delivering" in _pay["banner"] and "inverter-b" in _pay["banner"] and "holding grid at zero" not in _pay["banner"]) print(f" banner: {_pay['level']!r} / {_pay['banner']!r}") -_row = [r for r in _cw.checks() if "NOT DELIVERING" in r["text"]] +_row = [r for r in _cw.checks() + if r.get("id") == "delivery" and "not delivering" in r["text"]] check("the status page carries it as a CAUTION, not a failure: the site is " "still running and short, which a red cross would misdescribe", - len(_row) == 1 and _row[0]["ok"] is False and _row[0]["warn"] is True) + len(_row) == 1 and _row[0]["ok"] is False and _row[0]["warn"] is True + and "inverter-b" in _row[0]["text"]) +check("...and the row says how it clears: a stop and start of control", + bool(_row) and "stopping and starting control" in _row[0]["text"]) # =========================================================================== @@ -1173,10 +1177,11 @@ check("...and no store key was written, so a one-inverter install's state file " "is byte-identical to what it was before this card", unit_key(_only.name, "delivery_tripped") not in _st1.data and unit_key(_only.name, "delivery_reason") not in _st1.data) -_n1row = [r for r in _c1.checks() if "delivery watchdog" in r["text"]] +_n1row = [r for r in _c1.checks() if r.get("id") == "delivery"] check("...and the status page says n/a rather than 'armed', which would be a " "claim to be watching something that cannot happen", - len(_n1row) == 1 and _n1row[0]["ok"] and "n/a at one inverter" in _n1row[0]["text"]) + len(_n1row) == 1 and _n1row[0]["ok"] + and "not needed with one inverter" in _n1row[0]["text"]) check("...no persistent notification of this kind was raised either", not [c for c in _h1.calls if "not_delivering" in str(c[2].get("notification_id", ""))]) diff --git a/goodwe_controller/test_freeze.py b/goodwe_controller/test_freeze.py index a10166e..e182920 100644 --- a/goodwe_controller/test_freeze.py +++ b/goodwe_controller/test_freeze.py @@ -832,7 +832,7 @@ all_notes = all_notes_of(hass_f) # the whole surface # install has. Flipped here rather than plumbing a whole P1 transport in - the # row's own content is what is under test. ctl_f.p1_enabled = True -frozen_rows = [c for c in ctl_f.checks() if "METER MAY BE FROZEN" in c["text"]] +frozen_rows = [c for c in ctl_f.checks() if c.get("id") == "meter_frozen"] print(f" frozen at +4000 W: command ran to {ctl_f.target:.0f} W, " f"{len(notes)} notification(s), {len(frozen_rows)} red status row(s)") # SURFACE-WIDE, deliberately, and the second guard has now landed. SAFETY-03 @@ -862,6 +862,9 @@ check("...and it says the controller is still running", bool(notes) and "Control is still running" in notes[0]["message"]) check("the status page carries a failed row saying so", len(frozen_rows) == 1 and not frozen_rows[0]["ok"] and not frozen_rows[0]["warn"]) +check("...and the row says control still follows the reading and what to do", + bool(frozen_rows) and "still follows it" in frozen_rows[0]["text"] + and "Check the meter" in frozen_rows[0]["text"]) check("the event log names it", any("METER FROZEN" in e for e in ctl_f.events)) # ⚠️ NOTIFY, NOT TRIP. If a later cut turns this into a trip it must come here # and change this expectation deliberately, not discover it in the field. @@ -1106,8 +1109,7 @@ def freeze_rows(unchanged_s, grid, **over): # p1_enabled is what a homewizard_local install has; the row's own content # is what is under test, not the transport that feeds it. ctl.p1_enabled = True - return ctl, [r for r in ctl.checks() - if r["text"].startswith("freeze detector")] + return ctl, [r for r in ctl.checks() if r.get("id") == "freeze_check"] _ctl_u, _rows_u = freeze_rows(None, 4000.0, meter_source="ha_dsmr") @@ -1116,30 +1118,31 @@ print(f" uncovered: {_rows_u[0]['text'] if _rows_u else '(no row at all)'}") print(f" covered: {_rows_c[0]['text'] if _rows_c else '(no row at all)'}") check("an uncovered transport gets exactly one freeze-detector row", len(_rows_u) == 1) -check("...and it says NOT COVERED", - bool(_rows_u) and "NOT COVERED" in _rows_u[0]["text"]) +# UX-08: the row says the check is off and which source it needs, in words +# (STYLE.md: no option values). DOCS.md "Status page" maps them to the keys. +check("...and it says the check is off", + bool(_rows_u) and ": off" in _rows_u[0]["text"]) check("...and it does NOT claim the guard is armed - that would be the status " "page lying on behalf of a guard that cannot run", - bool(_rows_u) and "armed" not in _rows_u[0]["text"]) -check("...and it names the meter_source it is not covering, so the operator " - "knows which install this is", - bool(_rows_u) and "ha_dsmr" in _rows_u[0]["text"]) -check("...and it names homewizard_local as the transport that would be covered", - bool(_rows_u) and "homewizard_local" in _rows_u[0]["text"]) + bool(_rows_u) and "alerts after" not in _rows_u[0]["text"]) +check("...and it names HomeWizard local as the source that would be covered", + bool(_rows_u) and "HomeWizard local" in _rows_u[0]["text"]) check("...flagged as a warning rather than a silent ok", bool(_rows_u) and not _rows_u[0]["ok"] and _rows_u[0]["warn"]) check("a COVERED transport gets exactly one freeze-detector row", len(_rows_c) == 1) -check("...and that one DOES say armed - without this, 'the uncovered row does " - "not say armed' is satisfied by deleting the armed branch", - bool(_rows_c) and "armed" in _rows_c[0]["text"] - and "NOT COVERED" not in _rows_c[0]["text"]) +check("...and that one DOES say it is on - without this, 'the uncovered row " + "does not say armed' is satisfied by deleting the armed branch", + bool(_rows_c) and "alerts after" in _rows_c[0]["text"] + and ": off" not in _rows_c[0]["text"]) check("...and it quotes the hold and the rail it is armed at, derived from the " "config the controller was actually built with", bool(_rows_c) - and f"{_ctl_c.freeze_wd.cfg.hold_s:.0f} s unchanged" in _rows_c[0]["text"] - and f"{rail_w(LIVE_INSTALL_MAX_W):.0f} W" in _rows_c[0]["text"]) + and f"{messages.duration(_ctl_c.freeze_wd.cfg.hold_s)} unchanged" + in _rows_c[0]["text"] + and f"above {messages.watts(rail_w(LIVE_INSTALL_MAX_W))}" + in _rows_c[0]["text"]) check("...as an ok row, since a covered armed guard is not a warning", bool(_rows_c) and _rows_c[0]["ok"] and not _rows_c[0]["warn"]) @@ -1196,7 +1199,8 @@ check("...and the notification the operator gets names no max_w rail, and the " _c20.p1_enabled = True check("...and the red status row is up too, so the page and the notification " "agree", - any("METER MAY BE FROZEN" in r["text"] for r in _c20.checks())) + any(r.get("id") == "meter_frozen" and not r["ok"] and not r["warn"] + for r in _c20.checks())) # --------------------------------------------------------------------------- # @@ -1222,23 +1226,25 @@ check("a device smaller than max_w still gets exactly one freeze-detector row", check("...and the page does NOT print the max_w rail the command can never " "reach - THE DEFECT, in one assertion", bool(_rows_s) - and f"{rail_w(LIVE_INSTALL_MAX_W):.0f} W" not in _rows_s[0]["text"]) + and messages.watts(rail_w(LIVE_INSTALL_MAX_W)) not in _rows_s[0]["text"]) check("...it prints the rail the predicate actually uses", bool(_rows_s) - and f"{rail_w(LIVE_INSTALL_MAX_W, dev_min=-4700.0, dev_max=4700.0):.0f} W" - in _rows_s[0]["text"]) -check("...and it names the device range as the reason, since the operator " - "configured max_w and is owed the reason the guard is armed elsewhere", - bool(_rows_s) and "4700" in _rows_s[0]["text"] - and "max_w" in _rows_s[0]["text"]) + and messages.watts(rail_w(LIVE_INSTALL_MAX_W, dev_min=-4700.0, + dev_max=4700.0)) in _rows_s[0]["text"]) +check("...and it names the inverter's own limit as the reason, since the " + "operator configured max_w and is owed the reason the guard is armed " + "elsewhere", + bool(_rows_s) and "the inverter's own limit" in _rows_s[0]["text"]) +check("...and it does not say so when max_w itself sets the rail", + bool(_rows_c) and "own limit" not in _rows_c[0]["text"]) # ⚠️ THE NUMBER IS TAKEN OFF THE ROW AND FED BACK INTO THE SHIPPED PREDICATE. # Asserting the page against `rail_w(...)` alone proves the two agree, which a # revert of BOTH to bare max_w also satisfies. What a revert cannot satisfy is # this: the rail the page advertises has to be a magnitude the wire can carry, # and the wire stops at the device rating. -_m = re.search(r"command is over (\d+(?:\.\d+)?) W", _rows_s[0]["text"]) if _rows_s else None -_page_rail = float(_m.group(1)) if _m else None +_m = re.search(r"above (\d[\d ]*) W", _rows_s[0]["text"]) if _rows_s else None +_page_rail = float(_m.group(1).replace(" ", "")) if _m else None print(f" the page advertises a rail of {_page_rail} W against a device that " f"stops at {_ctl_s.dev_max:.0f} W") check("...the row states a rail in watts at all, so the parse below means " @@ -1256,11 +1262,13 @@ check("...as an ok row - a guard armed at a lower rail is still armed, not a " "warning", bool(_rows_s) and _rows_s[0]["ok"] and not _rows_s[0]["warn"]) check("a device with no commandable range gets exactly one row", len(_rows_z) == 1) -check("...and it says NOT COVERED - the rail is not merely low there, it is " - "0 W, which would be TRUE of every command including a parked one", - bool(_rows_z) and "NOT COVERED" in _rows_z[0]["text"]) -check("...and it NEVER says armed", - bool(_rows_z) and "armed" not in _rows_z[0]["text"]) +check("...and it says the check is off for the power range - the rail is not " + "merely low there, it is 0 W, which would be TRUE of every command " + "including a parked one", + bool(_rows_z) and ": off" in _rows_z[0]["text"] + and "power range" in _rows_z[0]["text"]) +check("...and it NEVER says armed", + bool(_rows_z) and "alerts after" not in _rows_z[0]["text"]) check("...flagged as a warning rather than a silent ok, like the uncovered " "transport row it shares", bool(_rows_z) and not _rows_z[0]["ok"] and _rows_z[0]["warn"]) diff --git a/goodwe_controller/test_freshness.py b/goodwe_controller/test_freshness.py index 89f9005..dcc36d2 100644 --- a/goodwe_controller/test_freshness.py +++ b/goodwe_controller/test_freshness.py @@ -69,6 +69,7 @@ from datetime import datetime, timezone from pathlib import Path from app import freshness as F +from app import messages from named_absence import first, given, nth, present from app.circulation import circulating_w from app.freshness import BOUNDS, BATT_OBLIGED_S, BATT_UNCHANGED_S, MOVE_W, Freshness @@ -1823,7 +1824,8 @@ def _s56_row(c): a red with no name attached, which reads like broken infrastructure and gets retried rather than read. Measured: 0 named reds before, 2 after. """ - hits = [r for r in c.checks() if r["text"].startswith("battery power")] + hits = [r for r in c.checks() if r.get("id") == "sensor" + and r["text"].startswith(messages.LABEL_BATTERY)] if len(hits) == 1: return hits[0] return {"ok": None, "warn": None, @@ -1933,14 +1935,17 @@ check("⚠️ AND THE VERDICT IS UNCHANGED BY THIS CARD - both rows are still " _row56_ref["ok"] is False and _row56_ref["warn"] is False and _row56_abs["ok"] is False and _row56_abs["warn"] is False and _row56_ref["text"] == _row56_abs["text"]) -check("...and what it says instead is the observation plus BOTH causes, with " - f"{_BATT_ENT} in its own slot - `label` and `entity` are two " - f"interpolations in one sentence and swapping them costs zero bytes, so " - f"the literal around each is pinned (habit 14)", - f"battery power: no usable value this cycle from {_BATT_ENT} - and this " - f"row cannot tell which of two things that is" in _row56_ref["text"] - and "the entity is missing or not numeric" in _row56_ref["text"] - and "a number that this controller is withholding" in _row56_ref["text"]) +# UX-08: the row names the setting by its label, never the entity id +# (STYLE.md), so there is no second interpolation left to transpose. +check("...and what it says instead is the observation plus BOTH causes, under " + "its own label, and the check to make before replacing the sensor - with " + f"no entity id ({_BATT_ENT}) on the page row", + _row56_ref["text"].startswith(f"{messages.LABEL_BATTERY}: no usable " + f"reading") + and "may be missing" in _row56_ref["text"] + and "held back as too old" in _row56_ref["text"] + and "Developer Tools before replacing it" in _row56_ref["text"] + and _BATT_ENT not in _row56_ref["text"]) check("⚠️ AND THE DISCRIMINATOR IT POINTS AT EXISTS AND IS SELECTIVE, which is " "why the row does not need to ask `batt_fresh.stale` itself: `checks()` " "carries a STALE_READING row in REFUSED and NONE in ABSENT, so 'is that " @@ -1957,7 +1962,7 @@ check("...and the row's wording is NOT shared with the log line's, which is a " "other caller does not need", _S56_EXPLANATIONS[0][1] not in _row56_ref["text"] and _S56_EXPLANATIONS[1][1] not in _row56_ref["text"] - and "no usable value this cycle" not in _r56_ref) + and "no usable reading" not in _r56_ref) # --- 11e. what part 11 does NOT grade, with its shape (habit 13) ------------- # * It does not show the live episode was a BMS refusal beyond doubt. 11a diff --git a/goodwe_controller/test_inverter.py b/goodwe_controller/test_inverter.py index 5e2e622..110bf2b 100644 --- a/goodwe_controller/test_inverter.py +++ b/goodwe_controller/test_inverter.py @@ -811,9 +811,11 @@ check("...and the status page shows BOTH per-inverter rows - one latched, one " "'the sign watchdog is armed' printed over a latched sibling is the page " "lying", len([r for r in _c3r.checks() - if r["text"].startswith("sign watchdog [")]) == 1 + if r.get("id") == "direction" and r["ok"] + and "inverter-a" in r["text"]]) == 1 and len([r for r in _c3r.checks() - if "SIGN-DISAGREEMENT FAILSAFE [" in r["text"]]) == 1) + if r.get("id") == "direction" and not r["ok"] + and not r["warn"] and "inverter-b" in r["text"]]) == 1) check("⚠️ AND SAFETY-30's SITE ROW IS THERE BESIDE THEM, EXACTLY ONCE. At two " "inverters there are three sign questions on this page and they are three " "rows: is A doing what it was told, is B, and is the SITE'S TOTAL " @@ -823,15 +825,15 @@ check("⚠️ AND SAFETY-30's SITE ROW IS THERE BESIDE THEM, EXACTLY ONCE. At tw "per-unit rows would be advertising two guards where the install has " "three", len([r for r in _c3r.checks() - if r["text"].startswith("site sign watchdog:")]) == 1) + if r.get("id") == "site_direction"]) == 1) check("...and the per-inverter rows now say WHAT the unit was compared " "against, because at a roster of two it is no longer the meter. A row " "still reading 'the command opposed the meter' would send an operator to " "look at P1 for a fault that is visible only on one inverter's own power " "sensor", - all("its own measured power" in r["text"] for r in _c3r.checks() - if r["text"].startswith(("sign watchdog [", - "SIGN-DISAGREEMENT FAILSAFE [")))) + len([r for r in _c3r.checks() if r.get("id") == "direction"]) == 2 + and all("its own power" in r["text"] for r in _c3r.checks() + if r.get("id") == "direction")) # The operator's clear, which is one button and has to reach every latch. run(_c3r.handle_action("auto_toggle")) # -> stopped diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 46582bc..6d278de 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -7,8 +7,11 @@ 2. No notification is worded anywhere else. An AST scan of `app/` fails any `persistent_notification` call whose payload is not built by `app/messages.py`. -3. THE RATCHET for the kinds not rewritten yet. Every status-row and banner - literal, every validator refusal, every WARNING+ log line and every option +3. The status page. Every row and banner in `app/messages.py` obeys the rule + for its colour: a row one sentence of at most 15 words, a red row up to 3 + sentences and 30 words, a banner at most 12 words. + THE RATCHET for the kinds not rewritten yet. Every status-row and banner + literal left in `app/`, every validator refusal, every WARNING+ log line and every option name and description in `translations/en.yaml` must either obey its limit or appear in `ux08_allowlist.txt`. A new string that breaks the rule and is not listed goes red. So does a listed entry that no longer matches a @@ -302,7 +305,7 @@ ALLOW_FILE = HERE / "ux08_allowlist.txt" # The allowlist may never grow. The test demands the list be exactly this long, # so deleting lines means lowering this number in the same change, and adding # one means raising it where a reviewer sees it. -ALLOWLIST_MAX = 200 +ALLOWLIST_MAX = 168 def read_allowlist(path): @@ -326,10 +329,57 @@ if "--violations" in sys.argv: print(f"{k} # {where} {'; '.join(p)} :: {text[:70]!r}") sys.exit(0) +STATUS = messages.status_samples() + + +def row_problems(colour, text): + """STYLE.md section 1 for a status row (by colour) or a banner (None).""" + n_s, n_w = sentences(text), len(words(text)) + out = [] + if colour is None: + if n_w > 12: + out.append(f"banner over 12 words ({n_w})") + elif colour == messages.RED: + if n_s > 3: + out.append(f"red row over 3 sentences ({n_s})") + if n_w > 30: + out.append(f"red row over 30 words ({n_w})") + else: + if n_s > 1: + out.append(f"{colour} row over 1 sentence ({n_s})") + if n_w > 15: + out.append(f"{colour} row over 15 words ({n_w})") + if ";" in text: + out.append("semicolon: split it into sentences or drop a clause") + return out + text_problems(text, keys=False, entities=False) + + +for fn, colour, text in STATUS: + p = row_problems(colour, text) + check(f"{colour or 'banner':6} {text!r}{' - ' + '; '.join(p) if p else ''}", + not p) +_catalogue = {k for k, v in vars(messages).items() + if callable(v) and k.startswith(("row_", "banner_"))} +_missing = sorted(_catalogue - {fn for fn, _c, _t in STATUS}) +check(f"the samples cover every row and banner in the catalogue " + f"(missing: {_missing})", not _missing) +# A red row with no banner of its own heads the page as "Not ready - <its first +# sentence>". The three trips have their own branch in status_payload(), and +# main.py gives the other two a "banner" key (both are sampled above). +_own_banner = {"row_direction_trip", "row_site_direction_trip", + "row_circulating_trip", "row_peak_reserve", "row_power_too_high"} +_long = [t for fn, c, t in STATUS if c == messages.RED and fn not in _own_banner + and len(words(messages.banner_not_ready({"text": t}))) > 12] +check(f"every other red row makes a 'Not ready' banner of at most 12 words " + f"(too long: {_long})", not _long) + allow = read_allowlist(ALLOW_FILE) by_kind = {} for kind, *_ in found: by_kind[kind] = by_kind.get(kind, 0) + 1 +for _fn, colour, _t in STATUS: + kind = "row" if colour else "banner" + by_kind[kind] = by_kind.get(kind, 0) + 1 check(f"the scan found every ratcheted kind ({by_kind})", all(by_kind.get(k, 0) >= 5 for k in LIMITS)) new = sorted(k for k in violating if k not in allow) @@ -361,6 +411,8 @@ section = part[-1].split("\n## ", 1)[0] if len(part) == 2 else "" heads = set(re.findall(r"^### (.+)$", section, re.M)) missing = sorted({n.docs for n in SAMPLES} - heads) check(f"...with a heading for every Details line (missing: {missing})", not missing) +check("DOCS.md explains the status page rows under " + f"'## {messages.DOCS_STATUS}'", f"\n## {messages.DOCS_STATUS}\n" in DOCS) # ============================================================================== # @@ -394,6 +446,18 @@ check("a message that lost its Details line is refused", _fake = " x = {'text': 'THE METER IS FROZEN AND NOTHING WORKS AT ALL'}\n" _n = [t for node in ast.walk(ast.parse(_fake.strip())) if isinstance(node, ast.Dict) for _, t in strings_in(node.values[0])] +check("a second sentence in an amber row is refused", + bool(row_problems(messages.AMBER, "Meter stuck. Check it."))) +check("a fourth sentence in a red row is refused", + bool(row_problems(messages.RED, "One. Two. Three. Four."))) +check("a 16-word green row is refused", + bool(row_problems(messages.GREEN, " ".join(["word"] * 16)))) +check("a 13-word banner is refused", + bool(row_problems(None, " ".join(["word"] * 13)))) +check("an entity id in a status row is refused", + bool(row_problems(messages.GREEN, "Battery level: sensor.soc = 54"))) +check("a semicolon in a status row is refused", + bool(row_problems(messages.RED, "It stopped; check it."))) check("a new shouting status row is seen by the scan and is not listed", _n and problems_of("row", _n[0]) and key_of("row", _n[0]) not in allow) diff --git a/goodwe_controller/test_p1.py b/goodwe_controller/test_p1.py index ed83cda..99fe896 100644 --- a/goodwe_controller/test_p1.py +++ b/goodwe_controller/test_p1.py @@ -1432,7 +1432,7 @@ def p1_rows(ctl): a traceback instead of reddening the check that names the rule. """ try: - return [c["text"] for c in ctl.checks() if c["text"].startswith("P1 meter")] + return [c["text"] for c in ctl.checks() if c.get("id") == "meter"] except Exception as err: # noqa: BLE001 - a raise here is itself the failure print(f" checks() raised {type(err).__name__}: {err}") return err diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 1884bbd..cb25739 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1038,7 +1038,7 @@ check(f"a Controller built with peak_cap_w ABSENT takes the shipped " c.peak.cap_w == CAP_W) check("...and before the first cycle the guard has NO decision, which the " "status page must not spell as 'idle'", c.peak_guard is None) -pre = [r for r in c.checks() if "peak guard" in r["text"]] +pre = [r for r in c.checks() if r.get("id") == "peak_guard"] print(" status row before the first cycle: " + (pre[0]["text"] if pre else "(none)")) check("the status page says so in its own row", @@ -1054,17 +1054,20 @@ c_off, hass_off = built(TMP / "legacy.db", {"meter_source": "off", "meter_entity": "sensor.grid"}) c_off.auto, c_off.soc, c_off.batt, c_off.grid = True, 55.0, 0.0, -6000.0 asyncio.get_event_loop_policy().new_event_loop().run_until_complete(c_off.cycle()) -off_rows = [r for r in c_off.checks() if "peak guard" in r["text"]] +off_rows = [r for r in c_off.checks() if r.get("id") == "peak_guard"] print(f" meter_source off: guard={c_off.peak_guard}, wrote " f"{nth(hass_off.writes, -1):+.0f} W") print(" status row: " + (off_rows[0]["text"] if off_rows else "(none)")) check("with no P1 the guard does not run at all - it files nothing, and the " "legacy path can still charge", c_off.peak_guard is None and hass_off.writes and hass_off.writes[-1] < 0) -check("...and the status page says NOT COVERED rather than 'idle' or a green " - "row, which is the same answer SAFETY-18 already gives on a transport " - "that cannot see it", len(off_rows) == 1 - and "NOT COVERED" in off_rows[0]["text"] and off_rows[0]["warn"]) +check("...and the status page says the guard is off, and why, rather than " + "'idle' or a green row - the same answer SAFETY-18 already gives on a " + "transport that cannot see it", len(off_rows) == 1 + and ": off" in off_rows[0]["text"] + and "meter source" in off_rows[0]["text"] + and "idle" not in off_rows[0]["text"] + and not off_rows[0]["ok"] and off_rows[0]["warn"]) # ⚠️ THE FIXTURE MUST LAND IN THE CURRENT QUARTER, AND THAT IS NOT PEDANTRY. # `cycle()` reads the real clock, and `project()` measures the open block against @@ -1214,7 +1217,7 @@ check("the real cycle files the peak claim and the real arbiter binds the real " and not c.peak_guard.saturated and "peak" in (c.reason or "")) check("...and the number written to the inverter is the guard's floor", hass.writes and near(hass.writes[-1], c.peak_guard.floor_w, 1.5)) -rows = [r for r in c.checks() if "peak guard" in r["text"].lower()] +rows = [r for r in c.checks() if r.get("id") == "peak_guard"] print(" status row: " + (rows[0]["text"] if rows else "(none)")) check("the status page carries exactly one peak-guard row, flagged", len(rows) == 1 and rows[0]["warn"]) @@ -1922,12 +1925,12 @@ asyncio.get_event_loop_policy().new_event_loop().run_until_complete(c24.cycle()) check("...once per episode, not once per cycle - a quarter of an hour of " "identical cards is how an operator learns to dismiss the one that " "mattered", hass24.notifications.count("goodwe_peak_soc_floor") == 1) -rows24 = [r for r in c24.checks() if "peak guard" in r["text"].lower()] +rows24 = [r for r in c24.checks() if r.get("id") == "peak_guard"] print(" status row: " + (rows24[0]["text"] if rows24 else "(none)")) check("the status page carries exactly one peak-guard row and it is NOT ok - " "the money is going to be spent and a human is the only actuator left", - len(rows24) == 1 and not rows24[0]["ok"] - and "FLOOR-LIMITED" in rows24[0]["text"]) + len(rows24) == 1 and not rows24[0]["ok"] and not rows24[0]["warn"] + and "peak limit will be passed" in rows24[0]["text"]) check("...and it reaches the action log too", any("FLOOR-LIMITED" in e for e in c24.events)) # A missing SoC sensor, through the same real cycle. `inputs_ok` stops the loop @@ -2479,17 +2482,23 @@ check("...and DOCS.md sends the reader to it rather than leaving the open " # comment is a scope sentence the operator never sees. c25, hass25, NET25, _ = wired_over_limit( TMP / "soc25.db", LIVE_MAX_W * 0.3, soc=SOC_FLOOR - 1.0) -rows25 = [r for r in c25.checks() if "peak guard" in r["text"].lower()] +rows25 = [r for r in c25.checks() if r.get("id") == "peak_guard"] + + +def _row_scope(text): + """SAFETY-25 in messages.row_peak_reserve()'s words.""" + return ("Home use still discharges below the reserve" in text + and "down to the cut-out level" in text) + + print(" status row: " + (rows25[0]["text"] if rows25 else "(none)")) check("the STATUS PAGE row for a floor-limited guard says the floor bounds the " "guard only and that self-consumption may keep discharging below it. " "Without that sentence the page implies a pack-wide reserve at the exact " "moment the replay above says the loop is still emptying the pack", len(rows25) == 1 - and "PEAK GUARD FLOOR-LIMITED" in rows25[0]["text"] - and "BOUNDS THE PEAK GUARD ONLY" in rows25[0]["text"].upper() - and "not a pack-wide reserve" in rows25[0]["text"] - and "BMS cut-out" in rows25[0]["text"]) + and "at its peak reserve" in rows25[0]["text"] + and _row_scope(rows25[0]["text"])) # ⚠️ THE ROW KEEPS THE WHOLE SENTENCE; THE BANNER DOES NOT. status_payload() # renders the first not-ok/not-warn row as the page headline, so before this the # loudest element on the page was the same 550-character paragraph the row three @@ -2501,26 +2510,19 @@ print(f" banner ({len(_pay25['banner'])} chars): {_pay25['banner']}") # The guard's own line, which the banner has always carried and which is not # this card's to shorten: `explain()` is SAFETY-24's sentence about a quarter # that is going over the ceiling. -_expl25 = nth(rows25, 0)["text"].split(". NOTE:")[0] -check("the NOT READY banner is the guard's own line plus a SHORT scope tag - " - "under 90 characters of it - and NOT the row's whole paragraph repeated " - "at the top of the page. A headline that is a paragraph is a headline " - "nobody reads, and this one is followed three lines later by the same " - "text verbatim", - present(_expl25) - and _pay25["level"] == "bad" - and _pay25["banner"].startswith("NOT READY") - and _expl25 in _pay25["banner"] - and "BOUNDS THE PEAK GUARD ONLY" in _pay25["banner"].upper() - and "not a pack-wide reserve" not in _pay25["banner"] - and len(_pay25["banner"]) - len(_expl25) < 90) -check("...and shortening the banner did NOT shorten the row: the full AC 3 " +# UX-08: the banner is the notification's own title, and the row below keeps +# the SAFETY-25 sentence. +check("the Not ready banner is a short headline - the notification's title - " + "and NOT the row repeated at the top of the page. A headline that is a " + "paragraph is a headline nobody reads", + _pay25["level"] == "bad" + and _pay25["banner"] == (f"{messages.NOT_READY} — " + f"{messages.T_PEAK_RESERVE}") + and not _row_scope(_pay25["banner"])) +check("...and shortening the banner did NOT shorten the row: the SAFETY-25 " "sentence is still what the checks list carries, which is the surface the " - "operator reads to find out what the floor does not bound", - len(rows25) == 1 - and len(rows25[0]["text"]) > 300 - and "not a pack-wide reserve" in rows25[0]["text"] - and "BMS cut-out" in rows25[0]["text"]) + "operator reads to find out what the reserve does not bound", + len(rows25) == 1 and _row_scope(rows25[0]["text"])) _body25 = hass25.last_message("goodwe_peak_soc_floor") @@ -5964,7 +5966,7 @@ check("...and the row still names WHERE the ceiling came from, which is the " # main.py:1951 is what the release edge writes. _c38, _h38 = built(TMP / "s38pin.db") _c38.peak_guard = _S38_IDLE -_rows38 = [r for r in _c38.checks() if "peak guard" in r["text"]] +_rows38 = [r for r in _c38.checks() if r.get("id") == "peak_guard"] print(" status row: " + (_rows38[0]["text"] if _rows38 else "(none)")) check("⚠️ ...AND THE SAME ORDERED PAIR ON THE STATUS PAGE (main.py:3313), read " "off the shipped `checks()` rather than off `explain()` a second time. " diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 089ee06..d6d5233 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -69,7 +69,7 @@ import asyncio import sys from pathlib import Path -from app import mqtt, pv +from app import messages, mqtt, pv from named_absence import field, nth, present from app.main import Controller @@ -499,6 +499,11 @@ def rows_of(c): return [r["text"] for r in c.checks()] +def pv_rows(c): + """The solar rows of the status page (UX-08: selected by id, not wording).""" + return [r for r in c.checks() if r.get("id") == "pv"] + + def page_rows(c): return c.status_payload()["rows"] @@ -510,38 +515,39 @@ check("⚠️ AN UNSET OPTION ADDS NO STATUS ROW AND NO PAGE ROW - not a caution "is unset, because an unset forecast leaves a money guard without an " "input; this is instrumentation and a permanent caution on every install " "that never asked for it is the warning spam the card forbids", - not [t for t in _off_rows if "PV" in t] + not pv_rows(c_off) and not [r for r in page_rows(c_off) if r[0] == "PV"]) check("...and the whole row list is otherwise the same length, so nothing else " "moved either", len(_on_rows) == len(_off_rows) + 1) -_pv_row = [t for t in _on_rows if t.startswith("PV production")] +_pv_row = [r["text"] for r in pv_rows(c_on)] print(f" {_pv_row}") -# habit 14: the ordered pair - value, entity and unit each in its OWN slot in -# the literal sentence, so a transposition is visible rather than merely -# present. -check("a good read says the watts, the entity it came from and the unit it was " - "reported in, each in its own slot", - _pv_row == ["PV production: 3210 W from sensor.pv_power " - "(reported in W)"] +# UX-08: the row says the watts, and no entity id (STYLE.md). The unit it was +# read in is DEBUG detail; a refused unit still gets its own caution below. +check("a good read says the watts, as a green row, and names no entity id", + _pv_row == [f"Solar production: {messages.signed_watts(3210)}"] + and "sensor." not in _pv_row[0] + and pv_rows(c_on)[0]["ok"] is True and ("PV", "3 210 W") in page_rows(c_on)) c_bad, _, _ = run(cycles=1, states=[state("1234", "%")], **PV_ON) -_bad_row = [r for r in c_bad.checks() if r["text"].startswith("PV production")] +_bad_row = pv_rows(c_bad) print(f" {[r['text'] for r in _bad_row]}") -check("a refused read says WHICH refusal, and names the entity - 'no reading' " - "on its own sends an operator to look at a working sensor", +check("a refused read says WHICH refusal - 'no reading' on its own sends an " + "operator to look at a working sensor", len(_bad_row) == 1 - and _bad_row[0]["text"] == ("PV production: no reading from " - "sensor.pv_power - unit '%' is not one of " - "mW, W, kW, MW, GW, TW - it cannot be read " - "in watts")) + and _bad_row[0]["text"] == ("Solar production: no reading, the sensor's " + "unit is not a power unit")) +check("...and every refusal pv.watts() can give has its own plain words", + len({messages.pv_problem(pv.watts(st)[1]) for st in ( + None, state("unavailable", "W"), state("abc", "W"), + state("12", ""), state("12", "%"))}) == 5) check("⭐ ...and it is a CAUTION, never a `bad` row: `status_payload()` builds " "NOT READY out of rows that are neither ok nor warn, and a telemetry " "channel that could put a battery site into NOT READY would be " "observability with a foot in the control path", len(_bad_row) == 1 - and _bad_row[0] == {"ok": False, "warn": True, "text": _bad_row[0]["text"]} - and not c_bad.status_payload()["banner"].startswith("NOT READY") + and _bad_row[0]["ok"] is False and _bad_row[0]["warn"] is True + and not c_bad.status_payload()["banner"].startswith(messages.NOT_READY) and c_bad.status_payload()["level"] != "bad" and c_bad.status_payload()["banner"] == c_off.status_payload()["banner"]) @@ -923,41 +929,32 @@ print() print("10. the operator surfaces at a roster of three - and 0.11.0 at one") # ============================================================================== _c_many, _, _ = run(cycles=1, by_entity=FULL, **PV_MANY) -_many_row = [t for t in rows_of(_c_many) if t.startswith("PV production")] +_many_row = [r["text"] for r in pv_rows(_c_many)] print(f" {_many_row}") -# habit 14 at a roster: the total in its own slot and EVERY contributor in its -# own slot with its own watts and its own unit, so a sum that disagrees with the -# addends printed beside it is visible in the sentence. -check("a healthy roster says the SITE total, how many entities it came from, " - "and then every entity with its own watts and its own unit - so a total " - "that disagrees with the numbers printed beside it is visible rather than " - "merely present", - _many_row == ["PV production: 3750 W from 3 entities " - f"({E1} 1200 W in W, {E2} 2100 W in kW, " - f"{E3} 450 W in W)"] +# UX-08: the row carries the site total and the number of sources; the +# per-source figures are DOCS/DEBUG detail (DECISIONS/UX-08-short-notifications). +check("a healthy roster says the SITE total and how many sources it came from", + _many_row == [f"Solar production: {messages.signed_watts(3750)} from 3 " + f"sources"] and ("PV", "3 750 W") in page_rows(_c_many)) _c_gap, _, _ = run(cycles=1, by_entity=HOLES[E2][0], **PV_MANY) -_gap_row = [r for r in _c_gap.checks() if r["text"].startswith("PV production")] +_gap_row = pv_rows(_c_gap) print(f" {[r['text'] for r in _gap_row]}") -check("⭐ A HOLED ROSTER SAYS THERE IS NO SITE TOTAL, IN THOSE WORDS, names the " - "entity that is missing and why - AND names what the others reported. The " - "partial information is not thrown away, it is put where a HUMAN reading " +check("⭐ A HOLED ROSTER SAYS THERE IS NO SITE TOTAL, IN THOSE WORDS, and names " + "the missing source by its place in the list - put where a HUMAN reading " "the page live will see it, and kept out of the number a recorder hands " "back cold a week later", len(_gap_row) == 1 - and _gap_row[0]["text"] == ( - "PV production: NO SITE TOTAL - only 2 of 3 entities are reporting " - "and a partial sum would understate production: " - f"{E2} - no state (entity missing, or the read failed). " - f"Reporting: {E1} 1200 W, {E3} 450 W")) + and _gap_row[0]["text"] == ("Solar production: no total, source 2 of 3 " + "has no reading")) check("⭐ ...and it is a CAUTION, never a `bad` row, at a roster exactly as at " "one entity: `status_payload()` builds NOT READY out of rows that are " "neither ok nor warn, and a telemetry channel that could put a battery " "site into NOT READY would be observability with a foot in the control " "path", len(_gap_row) == 1 - and _gap_row[0] == {"ok": False, "warn": True, "text": _gap_row[0]["text"]} + and _gap_row[0]["ok"] is False and _gap_row[0]["warn"] is True and _c_gap.status_payload()["level"] != "bad" and _c_gap.status_payload()["banner"] == c_off.status_payload()["banner"]) @@ -974,27 +971,24 @@ _c_one_new, _, _ = run(cycles=3, by_entity={E1: [state("3210", "W")]}, pv_entities=[E1]) print(f" one entity via pv_entities : " f"{[t for t in rows_of(_c_one_new) if 'PV' in t]}") -check("⭐ ONE ENTITY IS 0.11.0's PATH, however it was declared: the status " - "sentence, the page row and the published value are the same shape " - "through `pv_entity` and through a one-member `pv_entities`, and the " - "sentence is 0.11.0's own - `(reported in W)`, not `from 1 entities`", - [t.replace(E1, "sensor.pv_power") - for t in rows_of(_c_one_new) if "PV" in t] - == [t for t in rows_of(c_on) if "PV" in t] - == ["PV production: 3210 W from sensor.pv_power (reported in W)"] +check("⭐ ONE ENTITY IS ONE PATH, however it was declared: the status " + "sentence, the page row and the published value are the same through " + "`pv_entity` and through a one-member `pv_entities` - no `from 1 sources`", + [r["text"] for r in pv_rows(_c_one_new)] + == [r["text"] for r in pv_rows(c_on)] + == [f"Solar production: {messages.signed_watts(3210)}"] and page_rows(_c_one_new)[[r[0] for r in page_rows(_c_one_new)] .index("PV")] == ("PV", "3 210 W")) -check("...and a refused read at a roster of one is 0.11.0's refusal sentence " - "too, not the roster one - `no reading from <entity> - <reason>`", - [r["text"] for r in run(cycles=1, pv_entities=[E1], - by_entity={E1: [state("1234", "%")]})[0].checks() - if r["text"].startswith("PV production")] - == [f"PV production: no reading from {E1} - unit '%' is not one of " - "mW, W, kW, MW, GW, TW - it cannot be read in watts"]) +check("...and a refused read at a roster of one is the one-sensor refusal " + "too, not the roster one - `no reading, <reason>`", + [r["text"] for r in pv_rows(run(cycles=1, pv_entities=[E1], + by_entity={E1: [state("1234", "%")]})[0])] + == [r["text"] for r in _bad_row]) # ⚠️ AND THE REPLACEMENT IS STATED RATHER THAN SILENT. _c_both, _, _ = run(cycles=1, by_entity=FULL, **dict(PV_ON, **PV_MANY)) -_ign = [r for r in _c_both.checks() if "IGNORED" in r["text"]] +_IGN = messages.row_pv_single_ignored() +_ign = [r for r in _c_both.checks() if r["text"] == _IGN] print(f" {[r['text'] for r in _ign]}") check("⭐ BOTH KEYS SET: the page SAYS `pv_entity` is ignored and how many " "entities are summed instead. `entities()` REPLACES rather than unions - " @@ -1002,20 +996,17 @@ check("⭐ BOTH KEYS SET: the page SAYS `pv_entity` is ignored and how many " "key still names - but a replacement nobody is told about is the 'one of " "which silently wins' this config refuses elsewhere", len(_ign) == 1 and _ign[0]["ok"] is False and _ign[0]["warn"] is True - and _ign[0]["text"] == ("PV production: `pv_entities` is set, so " - "`pv_entity` is IGNORED - the 3 entities in the " - "list are what is summed. Clear `pv_entity` to " - "remove this caution") + and "clear the single sensor setting" in _ign[0]["text"] and _c_both.pv_w == 3750.0) check("...and that caution appears ONLY when both are set - not on the 0.11.0 " "configuration, not on a list-only one, and not on an install with " "neither", - not [r for r in c_on.checks() if "IGNORED" in r["text"]] - and not [r for r in _c_many.checks() if "IGNORED" in r["text"]] - and not [r for r in c_off.checks() if "IGNORED" in r["text"]]) + not [r for r in c_on.checks() if r["text"] == _IGN] + and not [r for r in _c_many.checks() if r["text"] == _IGN] + and not [r for r in c_off.checks() if r["text"] == _IGN]) check("...and an install with NO PV roster still adds no row of any kind - the " "whole of TEL-12 is invisible at the shipped default", - not [t for t in rows_of(c_off) if "PV" in t] + not pv_rows(c_off) and not [r for r in page_rows(c_off) if r[0] == "PV"] and len(rows_of(_c_many)) == len(rows_of(c_off)) + 1 and run(cycles=1)[1].state_calls == [] @@ -1109,19 +1100,18 @@ check("⭐ END TO END: the controller reads the option, and the MQTT `pv` row " "carries the corrected site total", _c_mix.pv_w == MIX_TOTAL and pv_msg(_f_mix) == ("goodwe_ctl/pv", "3270.0", False)) -_mix_row = [r["text"] for r in _row(_c_mix, "W from 3 entities")] +_mix_row = [r["text"] for r in _row(_c_mix, "from 3 sources")] print(f" {_mix_row}") -check("the status row prints each entity's watts AFTER the sign and marks " - "ONLY the flipped one", - _mix_row == [f"PV production: 3270 W from 3 entities ({E1} 1200 W in W, " - f"{E2} 2100 W in kW [sign inverted], {E3} -30 W in W)"]) +check("the status row prints the total AFTER the sign", + _mix_row == [f"Solar production: {messages.signed_watts(MIX_TOTAL)} " + f"from 3 sources"]) check("...and the page's PV row is the corrected total", ("PV", "3 270 W") in page_rows(_c_mix)) _c_hole_f, _, _ = run(cycles=1, by_entity=dict(MIX, **{E1: [None]}), **PV_FLIP) -check("a holed roster's 'Reporting:' list marks the flipped entity too", - [r["text"] for r in _row(_c_hole_f, "Reporting:")] - and f"{E2} 2100 W [sign inverted]" in - (_at(_row(_c_hole_f, "Reporting:"), 0) or {}).get("text", "")) +check("a holed roster with a flipped member names the missing source, not " + "the flipped one", + [r["text"] for r in _row(_c_hole_f, "no total")] + == ["Solar production: no total, source 1 of 3 has no reading"]) # The owner's report, at a roster of one: a meter reading +13 W at night. _OWN = "sensor.pv_meter_power" @@ -1134,13 +1124,11 @@ check("⭐ THE REPORTED CASE: 13 W of night-time standby on a reversed meter is "negative caution, because -13 W is standby and not a reversed sign - " "and NO stray caution, because a lone `pv_entity` is in the roster", _c_own.pv_w == -13.0 - and [r["text"] for r in _row(_c_own, "PV production: -13 W")] - == [f"PV production: -13 W from {_OWN} (reported in W) [sign inverted]"] - and _row(_c_own, "probably reversed") == [] - and _row(_c_own, "flips nothing") == []) -check("...and WITHOUT the option it is 0.12.0's row, byte for byte", - [r["text"] for r in _row(_c_own0, "PV production:")] - == [f"PV production: 13 W from {_OWN} (reported in W)"]) + and [r["text"] for r in pv_rows(_c_own)] + == ["Solar production: -13 W, sign reversed"] + and _row(_c_own, "reversed-sign list") == []) +check("...and WITHOUT the option it is the plain row", + [r["text"] for r in pv_rows(_c_own0)] == ["Solar production: 13 W"]) # Whitespace: the roster entry and the invert entry differ only by padding. Both # sides must normalise the same way, or the read path leaves the sign unflipped @@ -1152,9 +1140,7 @@ check("⭐ PADDING: ` sensor.x` in the roster and `sensor.x ` in " "`pv_invert_entities` are the same entity - flipped on the read path, " "marked on the page, and no stray caution", _c_pad.pv_w == MIX_TOTAL - and f"{E2} 2100 W in kW [sign inverted]" - in (_at(_row(_c_pad, "W from 3 entities"), 0) or {}).get("text", "") - and _row(_c_pad, "flips nothing") == []) + and _row(_c_pad, "reversed-sign list") == []) # --- the negative caution ------------------------------------------------------- def _neg(watts_by_entity, flip=()): @@ -1162,20 +1148,20 @@ def _neg(watts_by_entity, flip=()): c, _, _ = run(cycles=1, by_entity={e: [state(str(w), "W")] for e, w in watts_by_entity.items()}, **opts) - return _row(c, "probably reversed") + return _row(c, "reads ") _n_add = _neg({E1: 1200, E2: -1500, E3: 450}) _n_rm = _neg({E1: 1200, E2: 1500, E3: 450}, flip=[E2]) print(f" {[r['text'] for r in _n_add + _n_rm]}") -check("⭐ AN UNFLIPPED ENTITY FAR BELOW ZERO gets a caution that names it, its " - "watts, and says to ADD it to `pv_invert_entities`", +check("⭐ AN UNFLIPPED ENTITY FAR BELOW ZERO gets a caution that names it by " + "its place in the list, its watts, and says to ADD it to the " + "reversed-sign list (`pv_invert_entities`)", [r["text"] for r in _n_add] - == [f"PV production: {E2} reads -1500 W - far below zero, so its sign " - "is probably reversed. If it is producing now, ADD it to " - "`pv_invert_entities` in the Configuration tab"]) + == ["Solar production: source 2 reads -1 500 W, so add it to the " + "reversed-sign list"]) check("...and a FLIPPED one far below zero is told to REMOVE it instead", - len(_n_rm) == 1 and "REMOVE it from `pv_invert_entities`" + len(_n_rm) == 1 and "remove it from the reversed-sign list" in (_at(_n_rm, 0) or {}).get("text", "")) check("⭐ ...and it is a CAUTION, never a `bad` row - a telemetry sign cannot " "put a battery site into NOT READY", @@ -1198,11 +1184,10 @@ _c_typo, _, _ = run(cycles=1, by_entity=FULL, check("a `pv_invert_entities` entry naming no PV entity in use is a named " "caution (a typo would otherwise leave the sign silently unflipped)", [(r["text"], r.get("ok"), r.get("warn")) - for r in _row(_c_typo, "flips nothing")] - == [("PV production: `pv_invert_entities` names sensor.pv_wset, which " - "is not a PV entity in use, so it flips nothing - check the " - "spelling against `pv_entities`", False, True)] - and _row(_c_mix, "flips nothing") == []) + for r in _row(_c_typo, "not a solar sensor in use")] + == [("Solar production: entry 1 of the reversed-sign list is not a " + "solar sensor in use", False, True)] + and _row(_c_mix, "not a solar sensor in use") == []) # --- default: byte-identical to 0.12.0 ------------------------------------------ _c_d0, _, _p_d0 = run(cycles=1, by_entity=MIX, **PV_MANY) diff --git a/goodwe_controller/test_tariff.py b/goodwe_controller/test_tariff.py index 4f40ea0..981412f 100644 --- a/goodwe_controller/test_tariff.py +++ b/goodwe_controller/test_tariff.py @@ -1008,7 +1008,7 @@ check("the row's coverage figure is the LIVE month's tally - graded against a " "row count taken straight from quarter_blocks, so this pins the gap " "rather than restating the property that produces it", bool(peak_rows) - and f"; {_live_rows} quarter(s) banked" in peak_rows[0]["text"]) + and f", {_live_rows} quarter(s) banked" in peak_rows[0]["text"]) check("...and it is FLAGGED, because 4998 W is over §9.1's 80 % warning point " f"on a {given(SHIPPED_CAP_W):.0f} W limit", bool(peak_rows) and not peak_rows[0]["ok"] and peak_rows[0]["warn"]) diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 77ca082..648370c 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -369,10 +369,12 @@ check("0 W actually reached the device", 0.0 in hass.writes) check("and it got there through the failsafe claim, not by accident", "failsafe" in ctrl.reason) print(f" status line: {ctrl.reason!r}") -check("the status page says so in words", - any("SIGN-DISAGREEMENT FAILSAFE" in c["text"] for c in ctrl.checks())) +check("the status page says so in words: a red row, at 0 W, cleared by start", + any(c.get("id") == "direction" and not c["ok"] and not c["warn"] + and "set to 0 W" in c["text"] and "start control" in c["text"] + for c in ctrl.checks())) check("the banner leads with it", - "FAILSAFE" in ctrl.status_payload()["banner"]) + ctrl.status_payload()["banner"] == messages.banner_direction(False)) check("it stays at 0 W on later cycles too", hass.writes[-1] == 0.0 and hass.writes.count(0.0) >= 1) @@ -479,7 +481,7 @@ check("...commands 0 W from its very first cycle", post.target == 0.0) check("...and never commanded anything else after the restart", hass2.writes != [] and set(hass2.writes) == {0.0}) check("the banner still leads with the failsafe", - "FAILSAFE" in post.status_payload()["banner"]) + post.status_payload()["banner"] == messages.banner_direction(False)) # ⚠️ TWO PRESSES, and the first one must NOT clear it. `auto` is True while # tripped, so the first press stops control; only the transition back to True # clears. That is the documented behaviour and it is worth an assertion, because @@ -952,12 +954,12 @@ check("...and it got there through the `circulation` claim, by name, rather " "circulation" in _c.reason) print(f" status line: {_c.reason!r}") check("the status page says so in words, and says the meter cannot see it", - any("CIRCULATING POWER" in ck["text"] and "meter cannot see" in ck["text"] - for ck in _c.checks())) + any(ck.get("id") == "circulating" and not ck["ok"] and not ck["warn"] + and "meter cannot see" in ck["text"] for ck in _c.checks())) check("the banner leads with it - above the sign failsafe, because a sign " "disagreement is visible on every dashboard in the house and this is " "visible nowhere at all", - "CIRCULATING POWER" in _c.status_payload()["banner"]) + _c.status_payload()["banner"] == messages.banner_circulating()) _pub = {} _c.mqtt = type("P", (), {"enabled": True, "publish": lambda _s, v: _pub.update(v), @@ -1028,7 +1030,8 @@ check("...no `circulation` claim is ever filed, so the arbitration is " check("...and the status page says n/a rather than claiming to watch something " "that cannot happen - an 'armed' row for an identically-zero quantity is " "a guard advertising work it is not doing", - any("circulating power: n/a at one inverter" in ck["text"] + any(ck.get("id") == "circulating" and ck["ok"] + and "not needed with one inverter" in ck["text"] for ck in _c1.checks())) _pub1 = {} _c1.mqtt = type("P", (), {"enabled": True, @@ -1911,9 +1914,11 @@ check("...the latch is FLAT - `site_sign_tripped`, beside SAFETY-31's pair - " check("the status page carries a SITE row of its own, and the banner says the " "site's TOTAL command opposed the meter rather than naming an inverter - " "naming one would send an operator to swap the wrong box", - any("SITE SIGN-DISAGREEMENT FAILSAFE" in ck["text"] + any(ck.get("id") == "site_direction" and not ck["ok"] + and not ck["warn"] and "every inverter" in ck["text"] for ck in _c31.checks()) - and "total command" in _c31.status_payload()["banner"]) + and "Total command" in _c31.status_payload()["banner"] + and "inverter-" not in _c31.status_payload()["banner"]) _pub30 = {} _c31.mqtt = type("P", (), {"enabled": True, "publish": lambda _s, v: _pub30.update(v), @@ -2142,16 +2147,16 @@ check("⚠️ ...AND THE SITE DETECTOR IS NEVER ARMED. Not 'did not trip', and n _n1_site_calls == [] and not _c1s.site_sign_wd.tripped and _c1s.site_sign_wd.disagree_since is None) -check("...the banner is the sentence that shipped", - _c1s.status_payload()["banner"] - == "FAILSAFE — the command opposed the meter. Inverter held at 0 W.") +check("...the banner is the one-inverter sentence, naming the meter", + _c1s.status_payload()["banner"] == messages.banner_direction(False) + and "meter" in messages.banner_direction(False)) check("...the status page carries ONE sign row, with no unit tag and no site " "row - an extra row for an identically-duplicated question is a page " "advertising two guards where the install has one", - len([ck for ck in _c1s.checks() - if "sign watchdog" in ck["text"] or "SIGN-DISAGREEMENT" in ck["text"] - ]) == 1 - and not any("site sign" in ck["text"].lower() for ck in _c1s.checks())) + len([ck for ck in _c1s.checks() if ck.get("id") == "direction"]) == 1 + and not any(ck.get("id") == "site_direction" for ck in _c1s.checks()) + and not any("inverter-" in ck["text"] for ck in _c1s.checks() + if ck.get("id") == "direction")) check("...and no `sign_site` claim can be filed at a roster of one, so the " "arbitration is byte-identical to what shipped", "sign_site" not in _c1s.reason) @@ -2323,12 +2328,12 @@ check("⚠️ AND THE BANNER LEADS WITH THE FAILSAFE WHICHEVER UNIT IS LATCHED, "the page then leads with whatever the next branch says", _bn_b["level"] == _bn_a["level"] == "bad" and _bn_b["banner"] == _bn_a["banner"] - and _bn_b["banner"].startswith("FAILSAFE") - and "its own measured power" in _bn_b["banner"]) + and _bn_b["banner"] == messages.banner_direction(True) + and "own power" in _bn_b["banner"]) check("...and the counterfactual again: the same site with nothing latched " "carries neither that level nor that sentence, so the banner really is " "being produced by the reduction under test", - not _bn_n["banner"].startswith("FAILSAFE") + _bn_n["banner"] != messages.banner_direction(True) and _bn_n["banner"] != _bn_b["banner"]) diff --git a/goodwe_controller/ux08_allowlist.txt b/goodwe_controller/ux08_allowlist.txt index 94ea509..4ea0bfa 100644 --- a/goodwe_controller/ux08_allowlist.txt +++ b/goodwe_controller/ux08_allowlist.txt @@ -1,16 +1,10 @@ # UX-08 ratchet (test_messages.py part 3). Each line is a user-facing string that # does not follow STYLE.md yet: "<kind> <sha1-12 of its text> # where :: start". -# These are waiting for phase 2b (row, banner), 2c (refusal, option-name, -# option-desc) and 2d (log). Delete the line when you rewrite the string, because -# a stale line fails the test. Never add a line for a new string: write the new +# These are waiting for phase 2c (refusal, option-name, option-desc) and 2d +# (log); phase 2b emptied the row and banner kinds. Delete the line when you +# rewrite the string, because a stale line fails the test. Never add a line for a new string: write the new # string to STYLE.md instead. -banner c185022e391f # main.py banned: SAFETY-25; option key: peak_soc_floor; capitals: THE PEAK GUARD ONLY :: '{…} - and peak_soc_floor bounds THE PEAK GUARD ONLY (SAFETY-25, see be' -banner 4a246fc26def # main.py over 12 words (14); capitals: CIRCULATING POWER :: 'CIRCULATING POWER — the inverters were pushing against each other. Sit' -banner 750ccd4f2126 # main.py over 12 words (14) :: "FAILSAFE — the site's total command opposed the meter. Every inverter " -banner 637f334f130a # main.py over 12 words (26) :: 'FAILSAFE — the command opposed the meter. Inverter held at 0 W. / FAIL' -banner 0a3d2d9c4232 # main.py capitals: NOT READY :: "NOT READY — {bad[0].get('banner') or bad[0]['text']}" -banner dbcc227a9589 # main.py over 12 words (26); capitals: NOT DELIVERING :: 'NOT DELIVERING — {_nd} is standing at a share it is not producing. The' log a5e99679fd80 # main.py banned: SAFETY-02, latch :: 'SAFETY-02: the per-inverter store migration did not verify (%s). The l' log 128b18b32d86 # main.py over 25 words (41); banned: LATCHED, SAFETY-44, latched :: 'SAFETY-44: this store carries a LATCHED sign-disagreement failsafe und' log f60446541ae5 # main.py over 25 words (83); banned: LATCH, LATCHED, SAFETY-02, latch; capitals: LATCH GUARD :: 'SAFETY-02 LATCH GUARD: this store carries a LATCHED sign-disagreement ' @@ -179,29 +173,3 @@ refusal c4a1d0371e31 # validate.py over 30 words (42); capitals: THE DEVICE WIN refusal a15624d1aa10 # validate.py over 30 words (33); capitals: THE DEVICE WINS :: 'max_w is {max_w} W, so this controller may command {-max_w} W, but {op' refusal 26d0602c32d7 # validate.py over 30 words (79); capitals: THE FIRMWARE WINS :: 'meter_max_age_s is {max_age_s} s but the ESP32 firmware vetoes any P1 ' refusal 2ade09aaa579 # validate.py over 30 words (73); banned: SAFETY-02, arbiter, watchdog :: 'sign_disagree_w is {sign_w} W but max_w{where} is {weakest} W, so the ' -row c24ab8bd9cb3 # main.py over 15 words (18); banned: heartbeat, layer 1; capitals: NO PASS FOR :: 'control loop: NO PASS FOR {_pass_age} s (layer 1 zeroes the inverter a' -row c771d4bc1e0a # main.py over 15 words (17); banned: telegrams :: "P1 meter ({o.get('meter_source')}): {self.p1.net_w} W, {age} s old, {s" -row f6195fee8575 # main.py over 15 words (33); capitals: METER MAY BE FROZEN :: 'METER MAY BE FROZEN - {…}. The loop is STILL FOLLOWING it and is still' -row db05be7cd99c # main.py over 15 words (16); option key: meter_source; capitals: NOT COVERED :: "freeze detector: NOT COVERED on meter_source {o.get('meter_source')} -" -row 9a21960bbbe8 # main.py capitals: NOT COVERED :: 'freeze detector: NOT COVERED - {…}' -row c38b746a6585 # main.py banned: SATURATED; capitals: PEAK GUARD SATURATED :: 'PEAK GUARD SATURATED - {…}' -row dd0629834473 # main.py over 15 words (36); banned: SAFETY-25; option key: peak_soc_floor; capitals: THE PEAK GUARD ONLY :: '{…}. NOTE: peak_soc_floor bounds THE PEAK GUARD ONLY - it is not a pac' -row 4132e246e675 # main.py over 15 words (26); banned: telegrams; option key: meter_source; capitals: NOT COVERED :: "peak guard: NOT COVERED on meter_source {o.get('meter_source')} - the " -row 7b34b16d8bb2 # main.py over 15 words (61) :: '{label}: no usable value this cycle from {entity} - and this row canno' -row 04e0381f16c2 # main.py banned: CLAMP; capitals: OUTPUT CLAMP ENGAGED :: 'OUTPUT CLAMP ENGAGED - {…} Engagements: {self.clamp_wd.engagements}.' -row 9f8b8adcbc6c # main.py banned: INTEGRATOR; capitals: LOOP AT INTEGRATOR BOUND :: 'LOOP AT INTEGRATOR BOUND - {…} Engagements: {self.clamp_wd.engagements' -row f00cc9688eca # main.py over 15 words (20); banned: clamp :: 'output clamp: not engaged now, but it has engaged {self.clamp_wd.engag' -row a44333431331 # main.py over 15 words (31); capitals: SIGN-DISAGREEMENT FAILSAFEX :: 'SIGN-DISAGREEMENT FAILSAFE{tag} - {…}. The inverter is held at 0 W. Fi' -row 3ef4e60f2328 # main.py over 15 words (17) :: 'sign watchdog{tag}: armed{vs} (trips after {inv.sign_wd.cfg.hold_s} s ' -row 9f879b339282 # main.py over 15 words (50); banned: integrator; capitals: SITE SIGN-DISAGREEMENT FAILSAFE :: 'SITE SIGN-DISAGREEMENT FAILSAFE - {…}. EVERY inverter is held at 0 W. ' -row 96e93e34bdbf # main.py over 15 words (24); banned: watchdog :: 'site sign watchdog: armed against the sum of the commands (trips after' -row 9ee8d293fea5 # main.py over 15 words (38); capitals: CIRCULATING POWER :: 'CIRCULATING POWER - {…}. EVERY inverter is held at 0 W. The meter cann' -row 55eb950acd5f # main.py over 15 words (17); banned: watchdog :: 'circulation watchdog: armed (trips after {self.circ_wd.cfg.hold_s} s o' -row 1817192a7f1c # main.py over 15 words (42); capitals: NOT DELIVERINGX :: 'NOT DELIVERING{tag} - {…}. Nothing has been commanded differently and ' -row 685c1416364b # main.py over 15 words (26) :: 'delivery watchdog{tag}: armed (reports after {inv.delivery_wd.cfg.hold' -row d3cd52827dd0 # main.py over 15 words (29); banned: watchdog :: 'delivery watchdog: n/a at one inverter - a unit short of its share is ' -row d6981c8d7b56 # main.py banned: latched :: 'no e-stop fitted: if this host dies the battery stays latched at its l' -row 685c8f02c97a # main.py capitals: NO SITE TOTAL :: 'PV production: NO SITE TOTAL - {…}. Reporting: {…}' -row abef339bf192 # main.py over 15 words (25); option key: pv_entities :: 'PV production: `pv_entities` is set, so `pv_entity` is IGNORED - the {' -row 514511bd0a93 # main.py over 15 words (32); option key: pv_invert_entities :: 'PV production: {ent} reads {watt} W - far below zero, so its sign is p' -row 328abd6171ce # main.py over 15 words (22); option key: pv_invert_entities :: 'PV production: `pv_invert_entities` names {ent}, which is not a PV ent' -- 2.54.0 From 571b8843156c3f17a67e8dcf1f5b666df3c96017 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 03:10:25 +0200 Subject: [PATCH 031/105] UX-08 phase 2b review: keep over-rating evidence, pin latch clearing, plainer rows - During a bound episode an earlier over-rating count stays on the page (amber, under its own title); test_clamp pins it. - test_messages pins that every latch row says how it clears. - pv_entities description no longer claims the page names the entity (en, nl); allowlist hash updated for that option-desc line. - Plainer texts: multi-inverter direction banner, "fine now" after an episode, and the e-stop, peak-forecast and peak-guard-waiting rows move to messages.py. - TEL-12 DECISIONS points to UX-08 item 3 for the retired row rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/TEL-12-several-pv-inverters.md | 2 ++ goodwe_controller/DOCS.md | 2 +- goodwe_controller/app/main.py | 16 ++++++++++----- goodwe_controller/app/messages.py | 20 +++++++++++++++++-- goodwe_controller/test_clamp.py | 16 ++++++++++++++- goodwe_controller/test_messages.py | 11 ++++++++++ goodwe_controller/translations/en.yaml | 2 +- goodwe_controller/translations/nl.yaml | 2 +- goodwe_controller/ux08_allowlist.txt | 2 +- 9 files changed, 61 insertions(+), 12 deletions(-) diff --git a/goodwe_controller/DECISIONS/TEL-12-several-pv-inverters.md b/goodwe_controller/DECISIONS/TEL-12-several-pv-inverters.md index e880727..b7ac7e0 100644 --- a/goodwe_controller/DECISIONS/TEL-12-several-pv-inverters.md +++ b/goodwe_controller/DECISIONS/TEL-12-several-pv-inverters.md @@ -357,3 +357,5 @@ the bump is PKG's call. The material an entry needs is this file. The option surface moves **76 keys → 77**, one new optional key, `pv_entities`, empty on every install that does not set it. + +**Superseded in part (UX-08, 2026-09-27):** the PV status rows no longer read 0.11.0's sentences at one entity. The owner ruled out entity ids on status rows, so 2/5 now holds for the control document only. See `UX-08-short-notifications.md`, phase 2b item 3. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index fbd8814..104ef6a 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2954,7 +2954,7 @@ ERROR or WARNING line of that alarm. The texts are in `app/messages.py`. | Peak guard, Load too high, Battery at its peak reserve | What the capacity-peak guard is doing. *Peak guard: off* means `meter_source` is `off`, so there is no 15-minute average to guard. | | Battery level, Battery power, Grid power | The reading of that sensor. *No usable reading* means the sensor is missing **or** its reading is held back as too old (a separate stale-reading row then says so). Check it in Developer Tools before replacing it. | | Inverter control | The setpoint entity, and the power range the inverter accepts. | -| Power request too high, Battery is not keeping up | The two loop alarms, each with its own count since start. After an episode clears, the count stays, ending in *not now*. See *The winding-loop alarm*. | +| Power request too high, Battery is not keeping up | The two loop alarms, each with its own count since start. After an episode clears, the count stays, ending in *fine now*. See *The winding-loop alarm*. | | Direction check, Site direction check | The sign checks (SAFETY-02/30). *Opposite for 12 of 60 seconds* counts toward a stop. When it trips, the inverter, or every inverter for the site check, is set to 0 W until you start control. | | Circulating power check, Inverters worked against each other | SAFETY-31, only with several inverters. | | Delivery check, *name* is not delivering | SAFETY-42, only with several inverters. | diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ffb9ce4..53cd63c 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -4669,8 +4669,7 @@ class Controller: _pg = self.peak_guard if _pg is None: out.append({"ok": True, "warn": True, "id": "peak_guard", - "text": "peak guard: no decision yet - the first " - "control cycle has not run"}) + "text": messages.row_peak_guard_waiting()}) elif _pg.saturated: out.append({"ok": False, "warn": False, "id": "peak_guard", "text": messages.row_peak_saturated(_pg.ceiling_w)}) @@ -4821,6 +4820,12 @@ class Controller: # SAFETY-40: the integrator bound alone is amber, not red. out.append({"ok": False, "warn": True, "id": "not_keeping_up", "text": messages.row_not_keeping_up(_cw.bound)}) + # No over-rating in THIS episode (`bug` would be set), so any count + # is from an earlier one: keep that software-fault evidence shown. + if _cw.over_rating: + out.append({"ok": False, "warn": True, "id": "power_too_high", + "text": messages.row_before( + messages.T_OUTPUT_CLAMP, _cw.over_rating)}) else: if _cw.over_rating: out.append({"ok": False, "warn": True, "id": "power_too_high", @@ -4940,13 +4945,14 @@ class Controller: out.append({"ok": False, "warn": True, "id": "estop", "text": messages.row_no_estop()}) else: - out.append({"ok": True, "warn": False, "text": "e-stop fitted"}) + out.append({"ok": True, "warn": False, "id": "estop", + "text": messages.row_estop_fitted()}) if not o.get("peak_forecast_entity"): # ok=False + warn=True renders as a caution, not a pass. A check that # is both is a check nobody reads. - out.append({"ok": False, "warn": True, - "text": "no peak forecast: maintenance charging is not capacity-capped"}) + out.append({"ok": False, "warn": True, "id": "peak_forecast", + "text": messages.row_no_peak_forecast()}) # --- TEL-11 ---------------------------------------------------------- # ⚠️ NO ROW AT ALL WHEN THE ROSTER IS EMPTY, AND THAT IS A DELIBERATE # DIFFERENCE FROM THE PEAK-FORECAST CAUTION DIRECTLY ABOVE. That one diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 619192c..1e7bb9d 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -281,7 +281,7 @@ def banner_site_direction() -> str: def banner_direction(several: bool) -> str: if several: - return "Inverter and own power point opposite ways. It is at 0 W." + return "An inverter's own power opposes its command. It is at 0 W." return "Command and meter point opposite ways. Inverter set to 0 W." @@ -427,7 +427,7 @@ def row_not_keeping_up(count) -> str: def row_before(title, count) -> str: """After an episode clears: how often it happened, so the evidence stays.""" - return f"{title}: {times(count)} since start, not now" + return f"{title}: {times(count)} since start, fine now" def row_write_refused(unit=None) -> str: @@ -494,6 +494,19 @@ def row_delivery_check(unit, short_s, hold_s) -> str: return f"Delivery check for {unit}: on" +def row_estop_fitted() -> str: + return "Emergency stop: fitted" + + +def row_no_peak_forecast() -> str: + return ("No peak forecast set, so maintenance charging is not kept under " + "the peak limit") + + +def row_peak_guard_waiting() -> str: + return "Peak guard: no decision yet, control has not run" + + def row_no_estop() -> str: return ("No emergency stop fitted: if this computer fails, the battery " "keeps its last command") @@ -625,6 +638,9 @@ def status_samples() -> list: ("row_delivery_check", GREEN, row_delivery_check("inverter-b", 30, 120)), ("row_delivery_check", GREEN, row_delivery_check("inverter-b", 0, 120)), ("row_no_estop", AMBER, row_no_estop()), + ("row_estop_fitted", GREEN, row_estop_fitted()), + ("row_no_peak_forecast", AMBER, row_no_peak_forecast()), + ("row_peak_guard_waiting", AMBER, row_peak_guard_waiting()), ("row_pv", GREEN, row_pv(3200, 2)), ("row_pv", GREEN, row_pv(1800, 1, True)), ("row_pv_none", AMBER, row_pv_none("no unit_of_measurement on the " diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index 92e4bdb..a9fd6e4 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -549,7 +549,7 @@ check("...and once clear, a warn row still says how many times it engaged, " any(c["warn"] and c.get("id") == "not_keeping_up" and c["text"].startswith(messages.T_LOOP_BOUND) and messages.times(ctl_r.clamp_wd.bound) in c["text"] - and "not now" in c["text"] for c in ctl_r.checks())) + and "fine now" in c["text"] for c in ctl_r.checks())) # UX-07 item 1: the after-episode row used to say "output clamp ... engaged N # time(s)" for integrator-bound cycles. Each count now sits under its own name. check("UX-07 item 1: bound-only engagements are counted as the bound, and no " @@ -559,6 +559,20 @@ check("UX-07 item 1: bound-only engagements are counted as the bound, and no " and not any(c.get("id") == "power_too_high" or messages.T_OUTPUT_CLAMP in c["text"] for c in ctl_r.checks())) +# ...and an earlier over-rating count stays on the page while a LATER bound +# episode runs: it is the software-fault evidence, and that episode (bug False) +# cannot have added to it, so "fine now" is true of it. +_w = ctl_r.clamp_wd +_saved = (_w.active, _w.bug, _w.over_rating) +_w.active, _w.bug, _w.over_rating = True, False, 2 +_rows = ctl_r.checks() +_w.active, _w.bug, _w.over_rating = _saved +check("UX-07 item 1: during a bound episode an earlier over-rating count is " + "still shown, amber, under its own title", + any(c.get("id") == "not_keeping_up" for c in _rows) + and any(c.get("id") == "power_too_high" and c["warn"] and not c["ok"] + and c["text"] == messages.row_before(messages.T_OUTPUT_CLAMP, 2) + for c in _rows)) # ⚠️ NOT A TRIP. 11.2's action is "clamp and alarm"; the loop keeps running and # keeps writing the clamped value. If a later cut changes that it must come here. diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 6d278de..c2e7771 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -373,6 +373,17 @@ _long = [t for fn, c, t in STATUS if c == messages.RED and fn not in _own_banner check(f"every other red row makes a 'Not ready' banner of at most 12 words " f"(too long: {_long})", not _long) +# A latch row must say how it clears: that is the one action it exists for. +_clears = { + "row_direction_trip": "A restart does not clear this", + "row_site_direction_trip": "Only starting control clears this", + "row_circulating_trip": "Only starting control clears this", + "row_not_delivering": "only stopping and starting control clears this", +} +_unclear = [fn for fn, _c, t in STATUS if fn in _clears and _clears[fn] not in t] +check(f"every latch row says how it clears (missing: {_unclear})", + not _unclear and {fn for fn, _c, _t in STATUS} >= set(_clears)) + allow = read_allowlist(ALLOW_FILE) by_kind = {} for kind, *_ in found: diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index 658fb3b..ce55375 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -89,7 +89,7 @@ configuration: description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Point it at your solar inverter's own power sensor (any brand Home Assistant reads; it does not have to be on the RS485 bus) and the add-on records production beside the grid and battery figures, so a day of unstored surplus can be told apart from a day with no sun. POSITIVE MUST MEAN PRODUCING - if yours reads negative while producing, list it under 'sign is reversed' below. The unit is read from the entity itself - W, kW and the rest of Home Assistant's power units - so a sensor with no unit is refused rather than guessed at, and the status page says so. Leave it empty and nothing is read, nothing is published and nothing is shown." pv_entities: name: "Hardware · PV production entities, one per inverter (W)" - description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Use this instead of the single entity above when your roof has SEVERAL solar inverters: add one row per inverter, pointing at each one's own power sensor, and the add-on records the SITE total. Each entity's own unit is read, so a kW inverter beside a W one adds up correctly. ⚠️ SETTING THIS IGNORES THE SINGLE ENTITY ABOVE - clear that one when you fill this in, or you will see a caution on the status page saying so. ⚠️ AND IF ANY ONE OF THESE STOPS REPORTING THERE IS NO SITE TOTAL: the sensor goes to 'unknown' and the history records a gap, rather than publishing the sum of the ones that did answer. Two inverters out of three add up to a smaller number that looks exactly like a real one, and a week later that reads as 'there was less sun than there was' - which is the one conclusion this recording exists to test. The status page names which entity is missing, why, and what the others reported. Leave it empty and nothing is read, nothing is published and nothing is shown." + description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Use this instead of the single entity above when your roof has SEVERAL solar inverters: add one row per inverter, pointing at each one's own power sensor, and the add-on records the SITE total. Each entity's own unit is read, so a kW inverter beside a W one adds up correctly. ⚠️ SETTING THIS IGNORES THE SINGLE ENTITY ABOVE - clear that one when you fill this in, or you will see a caution on the status page saying so. ⚠️ AND IF ANY ONE OF THESE STOPS REPORTING THERE IS NO SITE TOTAL: the sensor goes to 'unknown' and the history records a gap, rather than publishing the sum of the ones that did answer. Two inverters out of three add up to a smaller number that looks exactly like a real one, and a week later that reads as 'there was less sun than there was' - which is the one conclusion this recording exists to test. The status page says which one is missing, by its place in this list. Leave it empty and nothing is read, nothing is published and nothing is shown." pv_invert_entities: name: "Hardware · PV entities whose sign is reversed" description: "Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a power clamp in the PV circuit - read NEGATIVE while producing and a few watts POSITIVE at night. Add each such entity here, spelled exactly as it is above, and its sign is flipped before it is added up; leave the others out. The status page marks every flipped entity. History recorded before you set this keeps the old sign." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index d1424af..79b1828 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -69,7 +69,7 @@ configuration: description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Verwijs naar de vermogenssensor van je omvormer (elk merk dat Home Assistant kan lezen; hij hoeft niet op de RS485-bus te zitten) en de add-on registreert de productie naast de meter- en batterijwaarden, zodat een dag met niet-opgeslagen overschot te onderscheiden is van een dag zonder zon. POSITIEF MOET PRODUCEREN BETEKENEN - leest de uwe negatief tijdens productie, zet hem dan ook bij 'teken omgekeerd' hieronder. De eenheid wordt van de entiteit zelf gelezen - W, kW en de overige vermogenseenheden van Home Assistant - dus een sensor zonder eenheid wordt geweigerd in plaats van geraden, en de statuspagina zegt waarom. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." pv_entities: name: "Hardware · Zonneproductie-entiteiten, één per omvormer (W)" - description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Gebruik dit in plaats van de losse entiteit hierboven wanneer uw dak MEERDERE zonne-omvormers heeft: voeg één rij per omvormer toe, elk verwijzend naar haar eigen vermogenssensor, en de add-on registreert het totaal van de installatie. De eenheid van elke entiteit wordt afzonderlijk gelezen, dus een omvormer in kW naast een in W telt correct op. ⚠️ ALS U DIT INVULT WORDT DE LOSSE ENTITEIT HIERBOVEN GENEGEERD - maak die leeg, anders verschijnt er een waarschuwing op de statuspagina die dat meldt. ⚠️ EN ALS ÉÉN VAN DEZE ENTITEITEN NIETS MEER DOORGEEFT, IS ER GEEN TOTAAL: de sensor gaat naar 'unknown' en de geschiedenis bewaart een gat, in plaats van de som van de entiteiten die wél antwoordden te publiceren. Twee omvormers van de drie tellen op tot een kleiner getal dat precies op een echt getal lijkt, en een week later leest dat als 'er was minder zon dan er was' - net de conclusie die deze registratie moet kunnen testen. De statuspagina noemt welke entiteit ontbreekt, waarom, en wat de andere doorgaven. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." + description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Gebruik dit in plaats van de losse entiteit hierboven wanneer uw dak MEERDERE zonne-omvormers heeft: voeg één rij per omvormer toe, elk verwijzend naar haar eigen vermogenssensor, en de add-on registreert het totaal van de installatie. De eenheid van elke entiteit wordt afzonderlijk gelezen, dus een omvormer in kW naast een in W telt correct op. ⚠️ ALS U DIT INVULT WORDT DE LOSSE ENTITEIT HIERBOVEN GENEGEERD - maak die leeg, anders verschijnt er een waarschuwing op de statuspagina die dat meldt. ⚠️ EN ALS ÉÉN VAN DEZE ENTITEITEN NIETS MEER DOORGEEFT, IS ER GEEN TOTAAL: de sensor gaat naar 'unknown' en de geschiedenis bewaart een gat, in plaats van de som van de entiteiten die wél antwoordden te publiceren. Twee omvormers van de drie tellen op tot een kleiner getal dat precies op een echt getal lijkt, en een week later leest dat als 'er was minder zon dan er was' - net de conclusie die deze registratie moet kunnen testen. De statuspagina zegt welke ontbreekt, met zijn plaats in deze lijst. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." pv_invert_entities: name: "Hardware · Zonneproductie-entiteiten met omgekeerd teken" description: "Optioneel, UITSLUITEND EEN METING. Sommige sensoren - meestal een kWh-meter of een stroomtang in het PV-circuit - lezen NEGATIEF tijdens productie en 's nachts enkele watt POSITIEF. Zet elke zulke entiteit hier, exact gespeld zoals hierboven, en haar teken wordt omgedraaid vóór het optellen; laat de andere weg. De statuspagina markeert elke omgedraaide entiteit. Geschiedenis van vóór deze instelling behoudt het oude teken." diff --git a/goodwe_controller/ux08_allowlist.txt b/goodwe_controller/ux08_allowlist.txt index 4ea0bfa..3c9ea58 100644 --- a/goodwe_controller/ux08_allowlist.txt +++ b/goodwe_controller/ux08_allowlist.txt @@ -93,7 +93,7 @@ option-desc d34ef16ba99a # en.yaml over 30 words (63) :: 'The older way of gett option-desc c70929091e71 # en.yaml over 30 words (252); capitals: SWITCHING THIS ON IS WHAT STARTS THE PRICE FETCH :: "Where day-ahead or real-time prices come from. 'off' is what ships, an" option-desc a62e17ccf445 # en.yaml over 30 words (230); banned: TARIFF-18; capitals: THIS NUMBER IS NOT :: 'Everything on your bill that is not the energy itself - distribution, ' option-desc 56d56f58c43e # en.yaml over 30 words (206); capitals: THE NUMBERS HERE ARE THE LEVIES ALONE :: 'Leave this empty unless your network tariff really does charge a diffe' -option-desc 313bdd035b0b # en.yaml over 30 words (193); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' +option-desc 0b7ea32cf8d0 # en.yaml over 30 words (193); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' option-desc 4172d9920d65 # en.yaml over 30 words (128); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' option-desc 09ceba2c6afb # en.yaml over 30 words (70); banned: clamp; capitals: MEASUREMENT ONLY :: 'Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a ' option-desc 42a7eaac6ff1 # en.yaml banned: saturated :: 'How many consecutive saturated cycles before the loop stops winding up' -- 2.54.0 From 00e3ee9de870af82de7ece8b90803993ea64f9a4 Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 04:10:39 +0200 Subject: [PATCH 032/105] UX-09: Details link for current HA, "would" in shadow mode, plain terms - Details link: /config/app/<slug>/documentation on HA 2026.2+ (the old /hassio/addon path is a 404 from 2026.5), /hassio/addon on 2026.1 and older. Slug from GET /addons/self/info, version from GET /info, hostname as fallback. - Shadow mode: the over-rating alarm and row say what would have been sent, the peak alarm no longer says the battery is giving all it can. - "controller" -> "the add-on" / "control". Settings named by their labels; four labels changed to match (Peak reserve, Battery level entity, Solar production ..., Reversed-sign solar entities). - Shadow banner and inverter link notes moved to messages.py and checked. - DOCS Notifications and Status page rewritten for home owners, with a "For installers" part each. Allowlist 168 -> 167. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 19 +- .../DECISIONS/UX-08-short-notifications.md | 9 + goodwe_controller/DOCS.md | 299 +++++++++++------- goodwe_controller/app/inverter.py | 21 +- goodwe_controller/app/main.py | 51 ++- goodwe_controller/app/messages.py | 268 +++++++++++----- goodwe_controller/app/shadow.py | 26 +- goodwe_controller/test_clamp.py | 60 +++- goodwe_controller/test_inverter.py | 2 +- goodwe_controller/test_messages.py | 124 +++++++- goodwe_controller/test_peakguard.py | 8 +- goodwe_controller/test_pv.py | 24 +- goodwe_controller/test_watchdog.py | 4 +- goodwe_controller/translations/en.yaml | 12 +- goodwe_controller/translations/nl.yaml | 2 +- goodwe_controller/ux08_allowlist.txt | 1 - 16 files changed, 666 insertions(+), 264 deletions(-) diff --git a/STYLE.md b/STYLE.md index 34af509..4117dfc 100644 --- a/STYLE.md +++ b/STYLE.md @@ -26,22 +26,29 @@ Severity is shown by the title and the colour, never by CAPITALS or by words lik A rewrite never changes an alarm's severity, `notification_id` or cadence. ## 4. Words - the same word for the same thing everywhere +A setting is named by its label in `translations/en.yaml`, in quotes when it sits mid-sentence (“Inverter rating”). The words below match those labels. If a label changes, change it here and in `app/messages.py` in the same change. + | Say | Not | |---|---| +| the add-on (who decides), control (what it does: "start control", "Control: last ran …") | controller, loop, planner | | battery | pack, BMS pack | | inverter, or its name | unit, device, actuator | -| controller | loop, planner | | meter | P1 feed, telegram | | peak limit / this month's peak | ceiling, capaciteitstarief, billed quarter | | 15-minute period | quarter | -| battery level | SoC, state of charge | -| cut-out level | BMS floor, `bms_soc_floor` | -| peak reserve | `peak_soc_floor`, EMS floor | -| inverter rating | `max_w`, rail | +| battery level (setting: “Battery level entity”) | SoC, state of charge, charge level | +| battery cut-out level, or cut-out level next to "battery" (setting: “Battery cut-out level”) | BMS floor, `bms_soc_floor` | +| peak reserve (setting: “Peak reserve”) | `peak_soc_floor`, EMS floor, "peak guard will not discharge below" | +| “Inverter rating” (the setting) | `max_w`, rail, inverter rating as a fact about the hardware | +| solar production, solar entity (settings: “Solar production entity”, “Solar production entities, per inverter”, “Reversed-sign solar entities”) | PV, reversed-sign list, single sensor setting | +| “Where the meter reading comes from” | meter source | +| “Grid power entity”; entity for any Home Assistant sensor a setting points at | grid power sensor, sensor setting | +| draw the battery down, give power | discharge, discharging | | control is stopped / every inverter is set to 0 W | failsafe, trip, latch, parked | +| safety stop (a stop that only starting control clears) | failsafe latch | | software fault | BUG SIGNAL | | control board | master, ESP32 | -| shadow mode | a mode that makes every decision but commands 0 W. The name is kept. | +| shadow mode | a mode that makes every decision but commands 0 W. The name is kept. In shadow mode a text says what the add-on **would** send, never that it sent it. | **Banned in titles and bodies** (the test fails on them): SAFETY-/TARIFF-/TEL-/CFG-/FW-/HW-nn and other card ids, integrator, anti-windup, windup, clamp, clamped, saturated, BUG SIGNAL, latch, latched, arbiter, allocator, register, `0x…`, layer 1/2/3, heartbeat, watchdog, telegram, ACK, CRC, OTA, Modbus, planner, `§n`, file names, IP addresses, option keys in snake_case, **HA entity ids**, and runs of 2 or more CAPITALISED words. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index da54cb9..16718e5 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -26,3 +26,12 @@ Every row of the Commissioning list and every banner is now in `app/messages.py` 6. **How a latch clears stays on the row**, shortened: "Only starting control clears this", "A restart does not clear this", "only stopping and starting control clears this" (not delivering). SAFETY-25's sentence stays on the peak-reserve row. 7. **Rows got an `id`** (`meter_frozen`, `direction`, `pv`, …), so tests find a row by what it is, not by its words. The page ignores it. 8. **Left for later:** texts that rows embed from other modules and that were not flagged as rows (the month-peak line, `peakguard.explain()`, the liveness and stale notes, `shadow.banner()`). The month-peak row only lost its semicolons. + +# UX-09: fixes after the phase 2a test + +1. **The Details link follows the Home Assistant version.** HA 2026.2 added the built-in `app` panel (core #157554, frontend #28245), whose add-on pages are `/config/app/<slug>/documentation`. 2026.5 stopped registering the `hassio` panel, so `/hassio/addon/<slug>/documentation` is a 404 there (TEST-23, HA 2026.9.1). 2026.1 and older have only the old path. The one path valid on both, `/_my_redirect/supervisor_addon?addon=<slug>`, opens the Info tab, not Documentation. So the add-on reads its slug (`GET /addons/self/info`) and the HA version (`GET /info`) at start, and picks the path. An unknown version gets the current path. The hostname stays as a fallback for the slug. Phase 2a item 7 is replaced by this. +2. **Shadow mode says "would".** The over-rating alarm and row said "sent X W" while 0 W was on the wire, and the peak alarm said "the battery is giving all it can". Both now take `shadow=`, and in shadow mode say what would have been sent and that the inverters stay at 0 W. Severity, id and cadence do not change with the mode. +3. **"Controller" is gone from texts.** "The add-on" names who decides, and "control" names what it does, as in the existing "start control". The add-on is what the reader sees in Home Assistant, and "controller" was easy to confuse with the control board. +4. **One term per setting, matching its label.** Four labels changed instead of the texts, because the texts' words were plainer: “Peak reserve (%)” (was "Peak guard will not discharge below"), “Battery level entity (%)” (was "Battery charge level"), and “Solar production entity / entities, per inverter / Reversed-sign solar entities” (was "PV …"). The Dutch labels already said "Zonneproductie". Option descriptions are phase 2c and were not changed, so some still say "PV". +5. **The shadow banner and the inverter notes** are now `messages.banner_shadow()` and `row_no_setpoint` / `row_not_controllable` / `row_commands_refused`, so `test_messages.py` checks them. The red shadow banner no longer lists the latches, because 12 words cannot carry them. It says a safety stop stays on, and each latch keeps its own red row, which names it and says how it clears. The colour of a liveness row now comes from `is_live()`, not from matching "NOT COMMANDABLE" in the text. +6. **DOCS "Notifications" and "Status page"** are written for a home owner, and the card ids, keys and log detail moved to a "For installers" part of each. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 104ef6a..67605c0 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2805,123 +2805,170 @@ it. ## Notifications -Each Home Assistant notification this add-on raises has a short title, one -sentence (a red alarm may use three), and a **Details** link to the add-on -documentation that names the section below. This section holds what the -notification leaves out. The wording rule is `STYLE.md` in the repository; the -texts live in `app/messages.py`. Every notification keeps a fixed -`notification_id`, so a repeat replaces the card instead of adding one. +The add-on tells you about a problem with a Home Assistant notification. Each +one has a short title, one to three sentences, and a **Details** link to this +page. The link opens the add-on's Documentation tab. Look for the section with +the same name as the notification title below. A repeat of the same problem +replaces the notification rather than adding a new one. -| Title | Severity | id | -|---|---|---| -| Battery is not keeping up | warning | `goodwe_integrator_bound` | -| Power request too high | alarm | `goodwe_output_clamp` | -| Load too high for battery | alarm | `goodwe_peak_saturated` | -| Battery stopped limiting the peak | alarm | `goodwe_peak_soc_floor` | -| Inverters working against each other | alarm | `goodwe_circulating_power` | -| *name* is not delivering | alarm | `goodwe_not_delivering_<name>` | -| Meter reading may be stuck | alarm | `goodwe_meter_frozen` | +In **shadow mode** the add-on makes every decision but sends nothing: every +inverter stays at 0 W. Notifications then say what the add-on *would* have +sent. ### Battery is not keeping up -The grid-following loop's integrator reached its anti-windup bound -(`integrator_max_w`): the controller has been asking for more than the battery -delivers for a while. This is SAFETY-40, and it is **not** a fault. No command -went over the rating and control keeps running. Short spells after a big load -or solar step are normal. If it keeps coming back, check that the battery -follows its commands. The bound and the command of that tick are in the add-on -log (WARNING, reason code `OUTPUT_CLAMP`). See *The winding-loop alarm* for the -full story. +The battery gives less power than the add-on asks for. This is normal for a +short time, for example just after a large load switches on or the sun comes +out. It is not a fault, and control keeps running. If it keeps coming back, +check that the battery is switched on, and that it is not empty (when it should +give power) or full (when it should charge). ### Power request too high -The controller computed a command above a limit, and the command was cut to that -limit before it was written. The notification names what was asked, what was -sent, and which limit cut it: the configured inverter rating (`max_w`), the -inverter's own limit (the setpoint device's range), or the inverter rating on -the loop side. Asked always comes first. This is a **software fault** (the old -wording was "BUG SIGNAL"). It is not the inverter failing to follow a legal -command, which is the saturation freeze and does not alarm. Control keeps -running. Report it with the add-on log, whose ERROR line carries the reason code -`OUTPUT_CLAMP` and the full figures. See *The winding-loop alarm*. +The add-on worked out a power request above what is allowed, and cut it back +before sending it. The notification shows what was asked and what was sent, +and which limit cut it: the “Inverter rating” setting, or the inverter's own +limit. In shadow mode it shows what *would* have been sent. Control keeps +running. This should never happen, so it is a software fault: please send the +notification and the add-on log to your installer. ### Load too high for battery -The capacity-peak guard (SAFETY-07) is asking for everything the inverter can -discharge, and the running 15-minute average is still projected over the peak -limit. That 15-minute period will set or raise the month's billed peak -(capaciteitstarief). The controller is not at fault: the house load is larger -than the inverter. Switching off load in the next few minutes is the only thing -that still changes the bill. The projection and the watts are in the add-on -log. See *The capacity-peak guard*. +Your home uses more power than the battery can supply, so this 15-minute +period will go over your peak limit and raise this month's peak. The battery +is already giving all it can. This is not a fault. Switch off large loads, +such as an oven, a car charger or a heat pump, for the next few minutes. In +shadow mode the battery gives nothing, so this can happen with a much smaller +load. ### Battery stopped limiting the peak -Two words in this notification are settings. The **peak reserve** is -*Peak guard will not discharge below (%)* (`peak_soc_floor`). The -**cut-out level** is *Battery cut-out level (%)* (`bms_soc_floor`), where the -battery's own system stops discharging. +The add-on stopped using the battery to keep your peak down, so this +15-minute period will go over your peak limit and raise this month's peak. +Switch off large loads for the next few minutes. The notification says why, +and what to do: -The peak guard wanted to discharge to hold the 15-minute peak, but it may not go -below the peak reserve (`peak_soc_floor`, SAFETY-24). It also stops when the -battery level cannot be read, or when an inverter's cut-out level is not set, -because the reserve is graded against it. So this 15-minute -period will go over the peak limit and set or raise the month's billed peak. -Charging from the grid stays blocked meanwhile. On a site with several inverters -the notification names the battery at its limit (SAFETY-32): each battery is -graded against its own cut-out level (`bms_soc_floor`), and raising the other -batteries' settings will not change this one. +- **The battery is at its peak reserve.** The “Peak reserve” setting keeps + that much charge back from peak limiting. Lower it if you accept a lower + battery level. +- **The battery level cannot be read.** Check the “Battery level entity” + setting and that sensor in Home Assistant. +- **A battery cut-out level is not known.** Fill in “Battery cut-out level” + for each inverter in the settings. -⚠️ **The reserve binds the peak guard only (SAFETY-25).** It is not a -whole-battery reserve. Ordinary self-consumption has no such floor and goes on -discharging below it, down to the battery's own cut-out level. See *What -`peak_soc_floor` does not protect*. +The peak reserve only applies to keeping the peak down. Normal home use can +still draw the battery below it, down to the battery cut-out level, where the +battery switches itself off. ### Inverters working against each other -Two inverters were pushing power into each other: one discharging while another -charged (SAFETY-31). **The meter cannot see this.** The two flows cancel at the -P1 meter, so the site reads idle while both batteries cycle through two -conversion stages. Every other guard reads that net figure, so none of them -fires. The add-on has **stopped control and commands 0 W on every inverter**. -If the grid reading does not move after that, one inverter is no longer -listening to the add-on; this has happened on this hardware, once for -6 h 25 min. Switch the inverters off at the isolator. The alarm is latched: a -Home Assistant or add-on restart does not clear it, and the card is raised -again every 5 min until you start control on the add-on page. The watts and the time -window are in the add-on log; the *Circulating* line on the status page shows the -live watts. See *The circulating-power alarm*. +With several inverters, one was charging its battery from another. Your meter +cannot see this, because the two flows cancel out, but it wastes energy. The +add-on has stopped control and set every inverter to 0 W. If the grid power +does not change after that, switch the inverters off at the isolator. A +restart does not clear this. Find out why, then start control on the add-on +page. ### An inverter is not delivering -One inverter has stood well short of its share of the site target for longer -than the hold time (SAFETY-42), while the others have not. No other check sees -this. A unit at 0 W is absent rather than pushing the wrong way, so the per-unit -sign check and the circulation check stay quiet. **Nothing is commanded -differently.** The guard only reports: commanding an inverter that has stopped -listening achieves nothing, and the only fallback the add-on has is -all-or-nothing. The other inverters keep regulating, and the site is short by up -to the missing unit's rating. Check, in this order: +With several inverters, one gives much less power than it is asked for, while +the others do. Nothing is changed: control keeps running, and the other +inverters carry on. Check, in this order: -1. Is the inverter answering on RS485 at all? -2. Is its battery colder or emptier than its configured cut-out level - (`bms_soc_floor`) says? If so, that setting does not describe this battery. -3. Is anything else writing to it? +1. Is the inverter on and connected? +2. Is its battery empty or cold? If it is emptier than its “Battery cut-out + level” says, that setting does not match this battery. +3. Is anything else controlling it? -The alarm is latched and survives restarts. Control is still running, so to -clear it, press *Start / stop control* twice (stop, then start) once you know -why. See *A unit that stops DELIVERING is a third fault again*. +A restart does not clear this. Once you know why, stop and then start control +on the add-on page. ### Meter reading may be stuck -The meter keeps answering, but its value has not changed for longer than the -hold time while the command stands at the power limit (SAFETY-18). The loop is -regulating against a number that has stopped moving. The age is still fresh, so -no other guard stops it. This is an alarm only: control keeps running and keeps -following the reading. Held for a whole 15-minute period, it can set the month's -billed peak. Check the meter; if it is stuck, stop control on the add-on page. -The limit and command figures are in the add-on log. See -*The frozen-meter alarm*. +The meter keeps answering, but its value has not changed for a long time while +the add-on asks the battery for full power. That usually means the meter +reading is stuck. Control keeps running and keeps following the reading, so a +stuck reading can raise this month's peak. Check the meter. If it is stuck, +stop control on the add-on page. + +### For installers: notifications + +This part is for installers. The texts live in `app/messages.py` and follow +`STYLE.md`. Every notification keeps a fixed `notification_id`, so a repeat +replaces the card. The full figures and reason codes are on the ERROR or +WARNING line of the add-on log. + +| Title | Severity | id | Card | +|---|---|---|---| +| Battery is not keeping up | warning | `goodwe_integrator_bound` | SAFETY-40 | +| Power request too high | alarm | `goodwe_output_clamp` | SAFETY-03 | +| Load too high for battery | alarm | `goodwe_peak_saturated` | SAFETY-07 | +| Battery stopped limiting the peak | alarm | `goodwe_peak_soc_floor` | SAFETY-24/25/32 | +| Inverters working against each other | alarm | `goodwe_circulating_power` | SAFETY-31 | +| *name* is not delivering | alarm | `goodwe_not_delivering_<name>` | SAFETY-42 | +| Meter reading may be stuck | alarm | `goodwe_meter_frozen` | SAFETY-18 | + +**The Details link.** Home Assistant 2026.2 and newer show add-on pages at +`/config/app/<slug>/documentation`; 2026.5 removed the old +`/hassio/addon/<slug>/documentation`, which 2026.1 and older still use. At +start the add-on reads its slug from `GET /addons/self/info` and the Home +Assistant version from `GET /info`, and builds the link for that version. If +the version cannot be read it uses the new path. If the slug cannot be read it +falls back to the container hostname, and outside an add-on the line names the +section without a link. The documentation tab adds no heading anchors, so the +link cannot jump to the section. + +**Battery is not keeping up.** The grid-following loop's integrator reached its +anti-windup bound (`integrator_max_w`, SAFETY-40). No command went over the +rating. The log line is a WARNING with reason code `OUTPUT_CLAMP`. See *The +winding-loop alarm*. + +**Power request too high.** A computed command above a limit was cut before it +was written (SAFETY-03). The limits are `max_w` (label “Inverter rating”), the +setpoint device's own range, or the rating on the loop side. Asked always comes +first. The old wording was "BUG SIGNAL". It is not the inverter failing to +follow a legal command, which is the saturation freeze and does not alarm. In +shadow mode the clamp still grades the decision (SAFETY-10), so the alarm can +fire while 0 W is on the wire, and the text says "would have sent". ERROR line, +reason code `OUTPUT_CLAMP`. + +**Load too high for battery.** The capacity-peak guard (SAFETY-07) asks for +everything the inverter can discharge and the running 15-minute average is +still projected over the peak limit, so the month's billed peak +(capaciteitstarief) goes up. In shadow mode the guard's projection is made on a +plant that did not respond (SAFETY-47), and the text says so. See *The +capacity-peak guard*. + +**Battery stopped limiting the peak.** The peak guard may not discharge below +`peak_soc_floor` (label “Peak reserve”, SAFETY-24). It also stops when the +state of charge is unread, or when an inverter's `bms_soc_floor` (label +“Battery cut-out level”) is missing, because the reserve is graded against it. +Charging from the grid stays blocked meanwhile. With several inverters the +notification names the battery at its limit (SAFETY-32), each graded against +its own cut-out level. ⚠️ **The reserve binds the peak guard only +(SAFETY-25).** Self-consumption has no such floor. See *What `peak_soc_floor` +does not protect*. + +**Inverters working against each other.** SAFETY-31. The flows cancel at the +P1 meter, so every other guard, which reads that net figure, stays quiet. This +has happened on this hardware once for 6 h 25 min. The alarm is latched, +survives restarts, and is raised again every 5 min until control is started. +The watts and the time window are in the log; the *Circulating power check* +row shows the live watts. See *The circulating-power alarm*. + +**An inverter is not delivering.** SAFETY-42. The unit stood well short of its +share of the site target for longer than `delivery_hold_s`. A unit at 0 W is +absent rather than pushing the wrong way, so the per-unit sign check and the +circulation check stay quiet. The guard only reports: commanding an inverter +that has stopped listening achieves nothing. Check first whether it answers on +RS485. The alarm is latched and survives restarts; stop then start clears it. +See *A unit that stops DELIVERING is a third fault again*. + +**Meter reading may be stuck.** SAFETY-18. The value has not changed for +longer than `meter_freeze_s` while the command stands at the power limit, and +the age is still fresh, so no other guard stops it. Only `meter_source: +homewizard_local` can tell a silent meter from an unchanged value. The limit +and command figures are in the log. See *The frozen-meter alarm*. ## The Web UI @@ -2938,27 +2985,61 @@ exactly the three buttons it always had. ## Status page -The banner at the top says in one line what matters most now. Below it, the -**Commissioning** list has one short row per check: ✓ green is fine, ! amber -needs a look, ✗ red needs action. The rows name settings in words, never a Home -Assistant entity id. The full figures of any alarm are in the add-on log, on the -ERROR or WARNING line of that alarm. The texts are in `app/messages.py`. +The add-on page shows a banner at the top and a **Commissioning** list below +it. The banner says in one line what matters most now. Each row of the list is +one check: ✓ green is fine, ! amber needs a look, ✗ red needs action. Rows name +settings by their label, never by a Home Assistant entity id. + +In **shadow mode** the banner says so first, whatever else is going on: the +add-on makes every decision but the battery is not controlled, and every +inverter stays at 0 W. If the banner is red and says a safety stop stays on, +one of the red rows below is a stop that will still be there when shadow mode +ends. That row says how to clear it. | Row starts with | What it tells you | |---|---| -| Controller | When the controller last ran. Red when it has stalled: the control board then sets the inverter to 0 W. | -| Meter | The grid reading, its age, readings refused, and how long its value has not changed. | -| Stuck-meter check | Whether the frozen-meter alarm can run. It needs the HomeWizard local source (`homewizard_local`), an inverter rating, and a power range the inverter can reach. *The inverter's own limit* means the setpoint device's range sets the threshold, below `max_w`. | -| Meter reading may be stuck | The frozen-meter alarm is on. See *Meter reading may be stuck* under Notifications. | -| *month*: peak … | This month's peak, and how close it is to the soft limit. | -| Peak guard, Load too high, Battery at its peak reserve | What the capacity-peak guard is doing. *Peak guard: off* means `meter_source` is `off`, so there is no 15-minute average to guard. | -| Battery level, Battery power, Grid power | The reading of that sensor. *No usable reading* means the sensor is missing **or** its reading is held back as too old (a separate stale-reading row then says so). Check it in Developer Tools before replacing it. | -| Inverter control | The setpoint entity, and the power range the inverter accepts. | -| Power request too high, Battery is not keeping up | The two loop alarms, each with its own count since start. After an episode clears, the count stays, ending in *fine now*. See *The winding-loop alarm*. | -| Direction check, Site direction check | The sign checks (SAFETY-02/30). *Opposite for 12 of 60 seconds* counts toward a stop. When it trips, the inverter, or every inverter for the site check, is set to 0 W until you start control. | -| Circulating power check, Inverters worked against each other | SAFETY-31, only with several inverters. | -| Delivery check, *name* is not delivering | SAFETY-42, only with several inverters. | -| Solar production | The PV reading. Sources are numbered in the order of `pv_entities`. The *reversed-sign list* is `pv_invert_entities`. A strongly negative reading by day means that source's sign is reversed. | +| Control | When control last ran. Red when it has stopped running: the control board then sets the inverter to 0 W. | +| Meter | The grid reading, its age, how many readings were refused, and how long its value has not changed. | +| Stuck-meter check | Whether the add-on can warn you about a stuck meter. | +| Meter reading may be stuck | See *Meter reading may be stuck* under Notifications. | +| *month*: peak … | This month's peak, and how close it is to your peak limit. | +| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. | +| Battery level, Battery power, Grid power | The reading of that entity. *No usable reading* means the entity is missing, or its reading is too old. Check it in Developer Tools before replacing it. | +| Inverter control | Whether the inverter can be controlled, and the power range it accepts. | +| *name*: … cannot be controlled, commands refused, “Setpoint entity” is not set | Whether each inverter still takes commands. | +| Power request too high, Battery is not keeping up | See those titles under Notifications. Each shows how often it happened since the add-on started, and *fine now* once it has cleared. In shadow mode the row says what *would* have been sent. | +| Direction check, Site direction check | Whether each inverter's power goes the way it is told. *Opposite for 12 of 60 seconds* counts toward a stop. When it stops, the inverter, or every inverter, is set to 0 W until you start control. | +| Circulating power check, Inverters worked against each other | Only with several inverters. See *Inverters working against each other*. | +| Delivery check, *name* is not delivering | Only with several inverters. See *An inverter is not delivering*. | +| Solar production | Your solar production. Sources are numbered in the order of “Solar production entities, per inverter”. A strongly negative reading by day means that entity reads the wrong way round: add it to “Reversed-sign solar entities”. | + +### For installers: status page + +The texts are in `app/messages.py`. The full figures of any alarm are on its +ERROR or WARNING line in the add-on log. + +- **Stuck-meter check: off** needs `meter_source: homewizard_local` (label + “Where the meter reading comes from”), a `max_w` (“Inverter rating”) and a + power range the inverter can reach. *The inverter's own limit* means the + setpoint device's range sets the threshold, below `max_w`. +- **Peak guard: off** means `meter_source` is `off`, so there is no 15-minute + average to guard. +- **Battery level / Battery power / Grid power** are `soc_entity`, + `batt_entity` and `meter_entity`. *No usable reading* is SAFETY-56: missing + **or** held back as stale, and a separate stale-reading row then says which. +- **Inverter control** is the `setpoint_entity` and the range it accepts. +- ***name* cannot be controlled** (red): every write was rejected for + `LINK_STALE_S`, so the unit is dropped and the others carry its share + (DEV-02). ***name*: commands refused** (amber) is the same before that limit. + ***name*: “Setpoint entity” is not set** (amber): a roster entry nobody can + write, so the site refuses to run at part strength and holds 0 W. +- **Direction check, Site direction check** are the sign checks (SAFETY-02/30). + **Circulating power check** is SAFETY-31, **Delivery check** SAFETY-42. +- **Solar production** reads `pv_entity` or `pv_entities` (TEL-11/12). The + *Reversed-sign solar entities* setting is `pv_invert_entities` (TEL-14). +- **Shadow mode** (SAFETY-10): the banner turns red when a latch is up + (circulating power, or a site or per-inverter sign trip), and that latch keeps + its own red row. ## Status entities diff --git a/goodwe_controller/app/inverter.py b/goodwe_controller/app/inverter.py index eb886f7..d62f236 100644 --- a/goodwe_controller/app/inverter.py +++ b/goodwe_controller/app/inverter.py @@ -123,6 +123,7 @@ from datetime import datetime from .clamp import ClampResult from .delivery import DeliveryConfig, DeliveryWatchdog +from . import messages # SAFETY-37. The freshness policy, and the ONE place its bounds are written. # freshness.py imports nothing from this package, so the direction is one-way. from .freshness import BOUNDS, Freshness @@ -410,18 +411,20 @@ class Inverter: return self.batt_fresh.note(self.name) def link_note(self, now: datetime) -> str: - """One line for the status page. Empty when there is nothing to say.""" + """One line for the status page. Empty when there is nothing to say. + + The words are `app/messages.py`'s (UX-09). main.py colours the row red + exactly when `is_live()` is False. + """ if not self.has_writer(): - return (f"{self.name}: NO SETPOINT ENTITY - this controller cannot " - f"command it, and the site refuses rather than running at " - f"part strength") - live, why = self.is_live(now) + return messages.row_no_setpoint(self.name) + live, _why = self.is_live(now) + held = (0.0 if self.rejected_since is None + else (now - self.rejected_since).total_seconds()) if not live: - return f"{self.name}: NOT COMMANDABLE - {why}" + return messages.row_not_controllable(self.name, held, LINK_STALE_S) if self.rejected_since is not None: - held = (now - self.rejected_since).total_seconds() - return (f"{self.name}: writes rejected for {held:.0f} s - still " - f"commandable until {LINK_STALE_S:.0f} s") + return messages.row_commands_refused(self.name, held, LINK_STALE_S) return "" def __repr__(self) -> str: diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 53cd63c..6f40b67 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -3796,7 +3796,8 @@ class Controller: # UX-08: the words are messages.output_clamp()'s; the numbers are the # ones `reason` was written from (ClampWatchdog.facts), asked first. await self.hass.call("persistent_notification", "create", - messages.output_clamp(self.clamp_wd.facts).data()) + messages.output_clamp(self.clamp_wd.facts, + shadow=self.shadow).data()) async def check_peak_saturated(self) -> None: """SAFETY-07. Alarm ONLY when the guard has run out of inverter. @@ -3839,7 +3840,8 @@ class Controller: # here - check_meter_frozen() gives the reasoning. A saturated peak guard # is not a frozen meter and is not an out-of-range setpoint. await self.hass.call("persistent_notification", "create", - messages.peak_saturated(g.ceiling_w).data()) + messages.peak_saturated( + g.ceiling_w, shadow=self.shadow).data()) async def check_peak_floor_limited(self) -> None: """SAFETY-24. Alarm when the EMS SoC floor stops the guard shaving. @@ -4797,9 +4799,14 @@ class Controller: # `live_units()` has stopped listing has had its share handed to its # siblings, or - at a roster of one - has taken the site to 0 W. A # dropped link that shows nothing on the page reads as a healthy site. - for note in self.liveness_notes(): - out.append({"ok": False, "warn": "NOT COMMANDABLE" not in note, - "text": note}) + # Red only for a unit that is no longer live; the rest are amber. + # The same notes, in the same order, as `liveness_notes()`. + _now = datetime.now(timezone.utc) + for inv in self.inverters: + for note, red in ((inv.link_note(_now), not inv.is_live(_now)[0]), + (inv.stale_note(), False)): + if note: + out.append({"ok": False, "warn": not red, "text": note}) # SAFETY-03. Red while an over-rating clamp is engaged (amber for the # integrator bound, SAFETY-40), and the engagement COUNT is shown even @@ -4814,8 +4821,8 @@ class Controller: if _cw.active and _cw.bug: out.append({"ok": False, "warn": False, "id": "power_too_high", "banner": messages.banner_power_too_high(), - "text": messages.row_power_too_high(_cw.facts, - _cw.over_rating)}) + "text": messages.row_power_too_high( + _cw.facts, _cw.over_rating, shadow=self.shadow)}) elif _cw.active: # SAFETY-40: the integrator bound alone is amber, not red. out.append({"ok": False, "warn": True, "id": "not_keeping_up", @@ -5363,6 +5370,30 @@ def control_task_done(task: asyncio.Task, *, controller, stop: asyncio.Event, stop.set() +async def docs_link_facts(session, token: str) -> dict: + """`{slug, ha_version}` from the Supervisor, each None when unreadable. + + `GET /addons/self/info` and `GET /info` are on the Supervisor's bypass + list for an add-on's own token, so they need no role (see selfconfig.py). + """ + out = {"slug": None, "ha_version": None} + for key, url, field in (("slug", "http://supervisor/addons/self/info", + "slug"), + ("ha_version", "http://supervisor/info", + "homeassistant")): + try: + async with session.get(url, timeout=10, headers={ + "Authorization": f"Bearer {token}"}) as r: + body = await r.json(content_type=None) + data = body.get("data", body) if isinstance(body, dict) else {} + out[key] = data.get(field) if isinstance(data, dict) else None + except Exception as err: # noqa: BLE001 - a link, never a stop + _LOG.info("docs link: %s unreadable (%s)", url, err) + _LOG.info("docs link: slug %s, Home Assistant %s", out["slug"], + out["ha_version"]) + return out + + async def amain() -> None: opts = load_options() logging.basicConfig( @@ -5394,6 +5425,12 @@ async def amain() -> None: except Exception as _e: # noqa: BLE001 _LOG.error("core api probe failed: %s", _e) + # UX-09: the Details link in every notification needs this add-on's + # slug and Home Assistant's version (see messages.docs_url()). Both + # are best effort: without them the link falls back to the hostname, + # or to naming the section only. + messages.set_site(**await docs_link_facts(session, _tok)) + # ⚠️ THE STARTUP GATE (CFG-01). Nothing below this line may run on a # configuration validate.py rejects - specs §1.5: a config the system # cannot honour is refused at startup, not survived at runtime. diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 1e7bb9d..44dd295 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -37,25 +37,60 @@ def names(items) -> str: return ", ".join(items[:-1]) + " and " + items[-1] -def addon_slug() -> str | None: - """This add-on's Supervisor slug, from the container hostname. +# The Details link (UX-09). Home Assistant 2026.2 added the built-in `app` +# panel (core #157554, frontend #28245), whose add-on pages are +# /config/app/<slug>/<tab>. 2026.5 dropped the old `hassio` panel, so +# /hassio/addon/<slug>/<tab> is a 404 there; 2026.1 and older have only that +# one. No path reaches the Documentation tab on both, so the link follows the +# Home Assistant version, and an unknown version gets the current path. +DOCS_PATH = "/config/app/{slug}/documentation" +DOCS_PATH_OLD = "/hassio/addon/{slug}/documentation" +APP_PANEL_SINCE = (2026, 2) +_SLUG = re.compile(r"[a-z0-9]+_goodwe_controller") +_site = {"slug": None, "ha": None} - The Supervisor names an add-on's host after its slug with `_` spelled `-` - (`local_goodwe_controller` -> `local-goodwe-controller`). Anything else, - e.g. a test run, gets no link rather than a wrong one. + +def set_site(slug=None, ha_version=None) -> None: + """What main.py read from the Supervisor at start: our slug, HA's version.""" + _site["slug"] = slug if isinstance(slug, str) and _SLUG.fullmatch(slug) \ + else None + _site["ha"] = ha_version if isinstance(ha_version, str) else None + + +def ha_release(version) -> tuple | None: + """`"2026.9.1"` -> `(2026, 9)`; None when it cannot be read.""" + m = re.match(r"(\d{4})\.(\d{1,2})\b", str(version or "")) + return (int(m.group(1)), int(m.group(2))) if m else None + + +def addon_slug() -> str | None: + """This add-on's Supervisor slug, or None outside an add-on. + + The Supervisor's own answer (`GET /addons/self/info`) first. Failing that, + the container hostname, which the Supervisor names after the slug with `_` + spelled `-` (`local-goodwe-controller`). Anything else gets no link rather + than a wrong one. """ + if _site["slug"]: + return _site["slug"] host = os.environ.get("HOSTNAME", "") if re.fullmatch(r"[a-z0-9]+-goodwe-controller", host): return host.replace("-", "_") return None +def docs_url(slug: str, ha_version=None) -> str: + release = ha_release(ha_version) + old = release is not None and release < APP_PANEL_SINCE + return (DOCS_PATH_OLD if old else DOCS_PATH).format(slug=slug) + + def details(title: str) -> str: where = f"section “{title}” under {DOCS_SECTION}" slug = addon_slug() if slug is None: return f"Details: add-on documentation, {where}." - return (f"Details: [add-on documentation](/hassio/addon/{slug}/documentation)," + return (f"Details: [add-on documentation]({docs_url(slug, _site['ha'])})," f" {where}.") @@ -98,19 +133,22 @@ ID_NOT_DELIVERING = "goodwe_not_delivering_{slug}" ID_METER_FROZEN = "goodwe_meter_frozen" # Which limit cut a command (clamp.ClampResult.bound, plus the loop's own). +# The setting is named by its label, "Inverter rating (W)". +RATING = "the “Inverter rating” setting" LIMIT_WORDS = { - "max_w": "the configured inverter rating", + "max_w": RATING, "device": "the inverter's own limit", - "max_w+device": "the configured inverter rating and the inverter's own limit", - "rating": "the inverter rating", + "max_w+device": f"{RATING} and the inverter's own limit", + "rating": RATING, } def loop_bound() -> Notice: """SAFETY-40: the integrator bound. Normal in short bursts; not a fault.""" return Notice(ID_LOOP_BOUND, WARNING, T_LOOP_BOUND, - "The battery cannot give what the controller asks, which is " - "normal for a moment but needs a check if it keeps happening.") + "The battery does less than asked, which is normal briefly, " + "but if this keeps happening, check that it is on and not " + "empty or full.") @dataclass(frozen=True) @@ -122,77 +160,98 @@ class Clamp: limit: str # a key of LIMIT_WORDS -def output_clamp(clamps) -> Notice: +def output_clamp(clamps, *, shadow: bool = False) -> Notice: """SAFETY-03: a computed command above the limit. A software fault. Asked comes before sent, always - reading them the other way round turns - the alarm backwards (test_clamp.py part 6). + the alarm backwards (test_clamp.py part 6). In shadow mode the cut command + never reached the inverter, so the text says "would have" (UX-09). """ + fault = "This is a software fault, so please report it to your installer." if not clamps: + cut = ("would have been cut back" if shadow else "was cut back") + state = ("Shadow mode is on, so every inverter stays at 0 W." if shadow + else "Control is still running.") return Notice(ID_OUTPUT_CLAMP, ALARM, T_OUTPUT_CLAMP, - "The controller asked for more power than the inverter " - "rating and was cut back. Control is still running. This " - "is a software fault, so please report it to your " - "installer.") + f"The add-on asked for more power than {RATING} allows " + f"and {cut}. {state} {fault}") c = clamps[0] who = f"For {c.unit}, the" if c.unit else "The" others = [x.unit for x in clamps[1:] if x.unit] - running = (f"{names(others)} {'was' if len(others) == 1 else 'were'} cut " - f"too, and control is still running." if others - else "Control is still running.") + sent = "would have sent" if shadow else "sent" + if others: + verb = "was" if len(others) == 1 else "were" + state = (f"{names(others)} would have been cut too, and shadow mode " + f"keeps every inverter at 0 W." if shadow else + f"{names(others)} {verb} cut too, and control is still " + f"running.") + else: + state = ("Shadow mode is on, so the inverter stays at 0 W." if shadow + else "Control is still running.") return Notice(ID_OUTPUT_CLAMP, ALARM, T_OUTPUT_CLAMP, - f"{who} controller asked for {watts(c.asked_w)}, above " - f"{LIMIT_WORDS.get(c.limit, LIMIT_WORDS['rating'])}, and sent " - f"{watts(c.sent_w)} instead. {running} " - f"This is a software fault, so please report it to your " - f"installer.") + f"{who} add-on asked for {watts(c.asked_w)}, above " + f"{LIMIT_WORDS.get(c.limit, RATING)}, and {sent} " + f"{watts(c.sent_w)} instead. {state} {fault}") -def peak_saturated(ceiling_w) -> Notice: - """SAFETY-07: the battery gives all it can and the peak still goes up.""" +def peak_saturated(ceiling_w, *, shadow: bool = False) -> Notice: + """SAFETY-07: the battery gives all it can and the peak still goes up. + + In shadow mode the battery gives nothing, so the text says what the add-on + would ask and that the peak may rise (UX-09). + """ + act = "Switch off large loads in the next few minutes." + if shadow: + return Notice(ID_PEAK_SATURATED, ALARM, T_PEAK_SATURATED, + f"The add-on would ask the battery for all it can give, " + f"and this 15-minute period is heading over your " + f"{watts(ceiling_w)} peak limit. Shadow mode is on, so " + f"the battery gives nothing and this month's peak may " + f"rise. {act}") return Notice(ID_PEAK_SATURATED, ALARM, T_PEAK_SATURATED, f"The battery is giving all it can, but this 15-minute period " f"will still go over your {watts(ceiling_w)} peak limit and " - f"raise this month's peak. Switch off large loads in the next " - f"few minutes. This is not a fault: the load is bigger than " - f"the inverter.") + f"raise this month's peak. {act} This is not a fault: the " + f"load is more than the battery can supply.") def peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, packs=()) -> Notice: - """SAFETY-24/25/32: the peak guard may not discharge any further. + """SAFETY-24/25/32: the peak guard may not draw the battery any lower. The last sentence is SAFETY-25 and must stay: the reserve binds the peak - guard only, and normal home use goes on discharging below it. + guard only, and normal home use goes on drawing the battery below it. `packs` names the batteries at their limit, only on a site with several. `floor_unknown`: the floor the guard grades against is None, which at a roster means some inverter's cut-out level is missing (the peak reserve itself always has a value) - so the action names the cut-out level. + Both are named by their setting labels, "Peak reserve (%)" and "Battery + cut-out level (%)". """ if soc_unread: why = "The battery level cannot be read" - act = "Switch off large loads, and check the battery level sensor." + act = ("Switch off large loads, and check the “Battery level entity” " + "setting.") elif floor_unknown: - why = "The cut-out level of a battery is not known" - act = ("Switch off large loads, and set each battery's cut-out level " - "in the settings.") + why = "A battery cut-out level is not known" + act = ("Switch off large loads, and set “Battery cut-out level” for " + "each inverter.") else: why = (f"The battery of {names(packs)} is at its peak reserve" if packs else "The battery is at its peak reserve") - act = ("Switch off large loads, or lower the peak reserve if the " - "battery allows it.") + act = "Switch off large loads, or lower the peak reserve." return Notice(ID_PEAK_RESERVE, ALARM, T_PEAK_RESERVE, f"{why}, so this 15-minute period will go over your " f"{watts(ceiling_w)} peak limit and raise this month's peak. " - f"{act} The reserve only applies to keeping the peak down: normal home use " - f"can still discharge the battery below it, down to its " - f"cut-out level.") + f"{act} The reserve only applies to keeping the peak down: " + f"normal home use can still draw the battery below it, down " + f"to the battery cut-out level.") def circulating(discharging=(), charging=()) -> Notice: """SAFETY-31: the inverters push power round each other. Control stopped.""" if discharging and charging: - what = (f"{names(discharging)} was discharging while " + what = (f"{names(discharging)} was giving power while " f"{names(charging)} was charging, and your meter cannot see " f"this.") else: @@ -222,7 +281,7 @@ def meter_frozen(unchanged_s) -> Notice: """SAFETY-18: the meter answers but its value does not move.""" return Notice(ID_METER_FROZEN, ALARM, T_METER_FROZEN, f"The meter has shown the same value for " - f"{duration(unchanged_s)} while the controller asks the " + f"{duration(unchanged_s)} while the add-on asks the " f"battery for full power. Control is still running and still " f"follows this reading. Check the meter, and if it is stuck, " f"stop control on the add-on page.") @@ -291,17 +350,31 @@ def banner_not_delivering(units) -> str: return f"{names(units)} {verb} not delivering. Control keeps running." -# Rows: the controller and the meter. +def banner_shadow(latched: bool) -> str: + """SAFETY-10: first in the cascade, never displaced by another banner. + + With a safety stop standing it goes red and says the stop outlasts shadow + mode. Each stop has its own red row below, which names it and says how it + clears. + """ + if latched: + return ("Shadow mode, battery not controlled. A safety stop stays on, " + "see below.") + return "Shadow mode: the battery is not controlled. Inverters stay at 0 W." + + +# Rows: control and the meter. "Control" is what the add-on does, as in +# "start control" (STYLE.md section 4). def row_controller_starting() -> str: - return "Controller: starting" + return "Control: starting" def row_controller_ran(age_s) -> str: - return f"Controller: last ran {seconds(age_s)} ago" + return f"Control: last ran {seconds(age_s)} ago" def row_controller_stalled(age_s, veto_s) -> str: - return (f"Controller has not run for {seconds(age_s)}. The control board " + return (f"Control has not run for {seconds(age_s)}. The control board " f"sets the inverter to 0 W after {seconds(veto_s)}.") @@ -322,9 +395,12 @@ def row_meter_frozen() -> str: f"and stop control if it is stuck.") +# Settings are named by their labels in translations/en.yaml. +METER_SOURCE = "“Where the meter reading comes from”" + FREEZE_OFF = { - "source": "it only works with the HomeWizard local meter source", - "rating": "the inverter rating is not set", + "source": f"it needs {METER_SOURCE} set to HomeWizard local", + "rating": "“Inverter rating” is not set", "range": "the inverter reports no usable power range", } @@ -357,13 +433,12 @@ def row_peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, why = (f"{names(packs)} battery at its peak reserve" if packs else "Battery at its peak reserve") return (f"{why}, so the {watts(ceiling_w)} peak limit will be passed. Home " - f"use still discharges below the reserve, down to the cut-out level.") + f"use still draws the battery below it, down to the cut-out level.") def row_peak_guard_off() -> str: - """No meter source: the 15-minute average cannot be measured.""" - return ("Peak guard: off, it needs a meter source instead of the grid " - "power sensor") + """`meter_source` is off: the 15-minute average cannot be measured.""" + return f"Peak guard: off, set {METER_SOURCE} to anything but off" def banner_peak_reserve() -> str: @@ -383,24 +458,49 @@ def row_sensor(label, value, unit=None) -> str: def row_sensor_unset(label, unit=None) -> str: - return f"{label}{for_unit(unit)}: no sensor set in the settings" + """The setting is "<label> entity" (e.g. "Grid power entity (W)").""" + return f"{label}{for_unit(unit)}: “{label} entity” is not set" def row_sensor_unusable(label, unit=None) -> str: """SAFETY-56: it may be missing OR held back as stale; say both.""" - return (f"{label}{for_unit(unit)}: no usable reading. The sensor may be " + return (f"{label}{for_unit(unit)}: no usable reading. The entity may be " f"missing, or its reading is held back as too old. Check it in " f"Developer Tools before replacing it.") +def setpoint_label(unit=None) -> str: + """The label: "Setpoint entity" in the inverter list, else its long form.""" + return "“Setpoint entity”" if unit else "“Inverter setpoint entity”" + + def row_control_unset(unit=None) -> str: - return f"Inverter control{for_unit(unit)}: not set in the settings" + return f"Inverter control{for_unit(unit)}: {setpoint_label(unit)} is not set" def row_control_missing(unit=None) -> str: return f"Inverter control{for_unit(unit)}: not found in Home Assistant" +# Rows: whether each inverter can still be controlled (DEV-02). `name` is +# always given: these rows came with the inverter list. +def row_no_setpoint(name) -> str: + """Amber. The site refuses to run at part strength, so all stay at 0 W.""" + return f"{name}: “Setpoint entity” is not set, so every inverter stays at 0 W" + + +def row_not_controllable(name, held_s, limit_s) -> str: + """Red. The inverter is dropped and the others carry its share.""" + return (f"{name} cannot be controlled. Every command was refused for " + f"{seconds(held_s)}, limit {seconds(limit_s)}.") + + +def row_commands_refused(name, held_s, limit_s) -> str: + """Amber. Refused, but not for long enough to be dropped yet.""" + return (f"{name}: commands refused for {seconds(held_s)}, left out of " + f"control after {seconds(limit_s)}") + + def row_control(lo_w, hi_w, unit=None) -> str: def w(v): return "?" if v is None else signed_watts(v) @@ -409,12 +509,15 @@ def row_control(lo_w, hi_w, unit=None) -> str: # Rows: the two loop alarms. The names are the notification titles, so the # row and the card always call the same thing by the same name (UX-07 item 1). -def row_power_too_high(clamps, count) -> str: +def row_power_too_high(clamps, count, *, shadow: bool = False) -> str: + """In shadow mode nothing was sent, so it says "would send" (UX-09).""" c = clamps[0] if clamps else None - what = (f"asked {watts(c.asked_w)}{for_unit(c.unit)}, sent " - f"{watts(c.sent_w)}. Cut back" if c else "cut back") - return (f"{T_OUTPUT_CLAMP}: {what} {times(count)} since start. This is a " - f"software fault, so please report it.") + head = f"{T_OUTPUT_CLAMP}{' in shadow mode' if shadow else ''}" + what = (f"asked {watts(c.asked_w)}{for_unit(c.unit)}, " + f"{'would send' if shadow else 'sent'} {watts(c.sent_w)}. Cut back" + if c else "cut back") + return (f"{head}: {what} {times(count)} since start. Software fault, " + f"please report it.") def banner_power_too_high() -> str: @@ -513,24 +616,29 @@ def row_no_estop() -> str: # Rows: solar production (TEL-11/12/14). Sources are numbered in the order of -# the solar sensor list in the settings. +# "Solar production entities, per inverter". The settings are named by their +# labels in translations/en.yaml. +PV_ONE = "“Solar production entity”" +PV_REVERSED = "“Reversed-sign solar entities”" + + def source(n, of) -> str: - return "the sensor" if of == 1 else f"source {n}" + return "the entity" if of == 1 else f"source {n}" def pv_problem(why: str) -> str: """`pv.watts()`'s reason, in plain words.""" w = str(why) if w.startswith("no state"): - return "the sensor is missing" + return "the entity is missing" if w.startswith("entity is"): - return "the sensor is unavailable" + return "the entity is unavailable" if w.endswith("is not numeric"): return "the reading is not a number" if w.startswith("no unit"): - return "the sensor has no unit" + return "the entity has no unit" if w.startswith("unit "): - return "the sensor's unit is not a power unit" + return "the entity's unit is not a power unit" return "the reading is not usable" @@ -553,20 +661,19 @@ def row_pv_partial(missing, count) -> str: def row_pv_single_ignored() -> str: - return ("Solar production: clear the single sensor setting, the list " - "replaces it") + return f"Solar production: clear {PV_ONE}, the per-inverter list replaces it" def row_pv_negative(n, count, value_w, flipped: bool) -> str: fix = ("remove it from" if flipped else "add it to") who = source(n, count) return (f"Solar production: {who} reads {signed_watts(value_w)}, " - f"so {fix} the reversed-sign list") + f"{fix} {PV_REVERSED}") def row_pv_stray(n) -> str: - return (f"Solar production: entry {n} of the reversed-sign list is not a " - f"solar sensor in use") + return (f"Solar production: entry {n} of {PV_REVERSED} is not a solar " + f"entity in use") RED, AMBER, GREEN = "bad", "warn", "ok" @@ -591,6 +698,8 @@ def status_samples() -> list: ("banner_not_delivering", None, banner_not_delivering(["inverter-b"])), ("banner_peak_reserve", None, banner_peak_reserve()), ("banner_power_too_high", None, banner_power_too_high()), + ("banner_shadow", None, banner_shadow(False)), + ("banner_shadow", None, banner_shadow(True)), ("row_controller_starting", GREEN, row_controller_starting()), ("row_controller_ran", GREEN, row_controller_ran(2)), ("row_controller_stalled", RED, row_controller_stalled(45, 30)), @@ -615,10 +724,19 @@ def status_samples() -> list: ("row_control_unset", RED, row_control_unset("inverter-b")), ("row_control_missing", RED, row_control_missing("inverter-b")), ("row_control", GREEN, row_control(-5000, 5000, "inverter-b")), + ("row_control_unset", RED, row_control_unset()), + ("row_no_setpoint", AMBER, row_no_setpoint("inverter-b")), + ("row_not_controllable", RED, row_not_controllable("inverter-b", 45, + 30)), + ("row_commands_refused", AMBER, row_commands_refused("inverter-b", 12, + 30)), ("row_power_too_high", RED, row_power_too_high(clamp, 3)), ("row_power_too_high", RED, row_power_too_high( [Clamp("inverter-b", 6000, 4600, "max_w+device")], 12)), ("row_power_too_high", RED, row_power_too_high((), 1)), + ("row_power_too_high", RED, row_power_too_high( + [Clamp("inverter-b", 6000, 4600, "max_w+device")], 12, + shadow=True)), ("row_not_keeping_up", AMBER, row_not_keeping_up(48)), ("row_before", AMBER, row_before(T_OUTPUT_CLAMP, 2)), ("row_before", AMBER, row_before(T_LOOP_BOUND, 1)), @@ -662,7 +780,13 @@ def samples() -> list: output_clamp(()), output_clamp([Clamp("inverter-a", -3000, -2500, "device"), Clamp("inverter-b", 6000, 4600, "max_w+device")]), + output_clamp([Clamp(None, 7412, 5000, "rating")], shadow=True), + output_clamp((), shadow=True), + output_clamp([Clamp("inverter-a", -3000, -2500, "device"), + Clamp("inverter-b", 6000, 4600, "max_w+device")], + shadow=True), peak_saturated(5000), + peak_saturated(5000, shadow=True), peak_reserve(5000, soc_unread=False, floor_unknown=False), peak_reserve(5000, soc_unread=False, floor_unknown=False, packs=["inverter-b"]), diff --git a/goodwe_controller/app/shadow.py b/goodwe_controller/app/shadow.py index 7cd020f..c82c6ad 100644 --- a/goodwe_controller/app/shadow.py +++ b/goodwe_controller/app/shadow.py @@ -279,6 +279,8 @@ that write is issued rather than skipped as unchanged. """ from __future__ import annotations +from . import messages + # ⚠️ CFG-03's mirror. `test_defaults_pin.py` part 2 discovers every # module-level name ending in OPTION_DEFAULTS and asserts each value # reproduces config.yaml EXACTLY, so this table cannot drift from the shipped @@ -471,25 +473,17 @@ def log_line(*, would_w: float, reason: str, sized_from_meter: bool) -> str: def banner(opts: dict, *, control_started: bool, latched: tuple = ()) -> tuple: """`(level, text)` for the top of the status page, or `None` when live. - ⚠️ IT NAMES A STANDING LATCH AND GOES RED FOR ONE. The shadow banner sits - ABOVE every other branch of the cascade, because "the battery is not being - controlled" is the one sentence that may never be displaced - but a - failsafe latch that is up while the controller is inert is up when it - stops being inert, and an operator who turns shadow mode off without - clearing it gets a battery that will not move and a green page that - never mentioned why. So the latch is carried INTO the shadow banner - rather than losing its own. + ⚠️ IT GOES RED FOR A STANDING LATCH. The shadow banner sits ABOVE every + other branch of the cascade, because "the battery is not controlled" is + the one sentence that may never be displaced - but a failsafe latch that + is up while the controller is inert is up when it stops being inert. So the + banner says a safety stop outlasts shadow mode, and each latch keeps its + own red row below, which names it and says how it clears. The words are + `messages.banner_shadow()`'s (UX-09); `latched` names them for callers. """ if not engaged(opts, control_started=control_started): return None - text = ("SHADOW MODE - the battery is NOT being controlled. Every " - f"inverter is held at {WIRE_W:.0f} W and nothing this add-on " - "decides reaches the inverter.") - if latched: - return ("bad", text + " ⚠️ A FAILSAFE LATCH IS STILL UP (" - + ", ".join(latched) + ") and it will still be up when shadow " - "mode is turned off.") - return ("warn", text) + return ("bad" if latched else "warn", messages.banner_shadow(bool(latched))) def problems(opts: dict) -> list: diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index a9fd6e4..51da777 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -85,7 +85,8 @@ from named_absence import given, nth, present from app import messages from app.clamp import ( - CLEAR_CYCLES, REASON_CODE, REASSERT_S, SUSTAINED_CYCLES, ClampWatchdog, + CLEAR_CYCLES, REASON_CODE, REASSERT_S, SUSTAINED_CYCLES, ClampResult, + ClampWatchdog, clamp_to_rating, is_commandable, ) @@ -1751,6 +1752,35 @@ check("SAFETY-28's gate still OBSERVES too - it refused nothing on this run, " "implemented by making every write unauthorised", not [e for e in _cl_c.events if "WRITE REFUSED" in e]) +# UX-09: what the over-rating alarm and its row SAY in each mode. The loop +# bounds the command before the write clamp here, so an over-rating is injected +# as the write path records one, and check_output_clamp() is run on it. Nothing +# reaches the wire in shadow mode, so neither text may claim a command was sent. +def _said(mode): + h, c = _s10(mode, cycles=2) + c.inverters[0].clamp_last = ClampResult(7412.0, 5000.0, 5000.0, True, + "max_w") + asyncio.run(c.check_output_clamp()) + notes = [d["message"] for d in clamp_notes(h) + if d["notification_id"] == CLAMP_ID] + rows = [r["text"] for r in c.checks() if r.get("id") == "power_too_high"] + return notes, rows + + +_ux_live, _ux_shad = _said("off"), _said("on") +print(f" over-rating, live: {_ux_live}\n over-rating, shadow: {_ux_shad}") +check("UX-09: live, the over-rating alarm and row say what was SENT", + _ux_live[0] and all(" and sent 5 000 W" in m for m in _ux_live[0]) + and _ux_live[1] and all("sent 5 000 W" in t and "would" not in t + for t in _ux_live[1])) +check("...in shadow mode they say what WOULD have been sent and that the " + "inverter stays at 0 W, never that it was sent", + _ux_shad[0] and all("would have sent 5 000 W" in m + and " and sent " not in m and "stays at 0 W" in m + for m in _ux_shad[0]) + and _ux_shad[1] and all("would send 5 000 W" in t and " sent " not in t + for t in _ux_shad[1])) + # ⚠️ AND SAFETY-18 IS GRADED ON WHAT IT WAS HANDED, WHICH IS AN ORDERING # CLAIM. `check_meter_frozen()` takes `self.target` - the arbiter's RESOLVED # INTENT - and `_shadow_settle()` re-seeds that to 0 W at the very end of the @@ -1835,15 +1865,15 @@ check("the status page has a Shadow mode row in BOTH states, so its ABSENCE is " _ROW in _shad_rows and _ROW in _live_rows) check("AC 3: the banner states plainly that the battery is not being " "controlled", - "SHADOW MODE" in _shad_pay["banner"] - and "NOT being controlled" in _shad_pay["banner"]) + "Shadow mode" in _shad_pay["banner"] + and "not controlled" in _shad_pay["banner"]) check("...and it is not green. A page that reads `ok` while nothing is being " "commanded is the 'looks healthy but is inert' failure itself", _shad_pay["level"] == "warn") check("...and it is FIRST in the cascade: the same controller has other " "conditions to report and none of them displaces this sentence", _live_pay["banner"] != _shad_pay["banner"] - and "SHADOW MODE" not in _live_pay["banner"]) + and "Shadow mode" not in _live_pay["banner"]) _slot = re.search(r"WOULD HAVE COMMANDED ([-+][\d ]+) W, inverter held at " r"([-\d]+) W", _shad_rows[_ROW]) check("the row answers 'what would it have done' with a NUMBER in its own " @@ -1869,22 +1899,26 @@ check("with shadow mode off the row says so, and says what follows from it - " and "DOES reach the inverter" in _live_rows[_ROW] and "WOULD HAVE COMMANDED" not in _live_rows[_ROW]) -# ⚠️ A STANDING LATCH IS NAMED RATHER THAN HIDDEN. The shadow banner sits above -# the three `bad` branches, so it has to carry what they would have said - a +# ⚠️ A STANDING LATCH IS SHOWN RATHER THAN HIDDEN. The shadow banner sits above +# the three `bad` branches, so it has to say what they would have said - a # latch that is up while the controller is inert is up the moment it stops -# being inert. +# being inert. UX-09: the banner (12 words) says a safety stop outlasts shadow +# mode, and the latch's own red row, still on the list, names it. _shad_c.inverters[0].sign_wd.tripped = True _latched = _shad_c.status_payload() print(f" banner with a latch up: {_latched['banner']!r}") -check("a failsafe latch that is standing is NAMED in the shadow banner and " - "turns it red, so nobody turns shadow mode off into a battery that will " - "not move and a page that never mentioned why", +check("a failsafe latch that is standing turns the shadow banner red and the " + "banner says a safety stop stays on, so nobody turns shadow mode off " + "into a battery that will not move and a page that never mentioned why", _latched["level"] == "bad" - and "LATCH IS STILL UP" in _latched["banner"] - and _shad_c.inverters[0].name in _latched["banner"]) + and "safety stop stays on" in _latched["banner"]) +check("...and the latch is NAMED on its own red row, which says how it clears", + any(not r["ok"] and not r["warn"] and r.get("id") == "direction" + and "A restart does not clear this" in r["text"] + for r in _shad_c.checks())) check("...and it still says the battery is not being controlled, so the latch " "has not displaced the sentence that may never be displaced", - "NOT being controlled" in _latched["banner"]) + "not controlled" in _latched["banner"]) _shad_c.inverters[0].sign_wd.tripped = False # --- 8i. THE RECORD A LATER ANALYSIS READS ---------------------------------- diff --git a/goodwe_controller/test_inverter.py b/goodwe_controller/test_inverter.py index 110bf2b..d9aae7c 100644 --- a/goodwe_controller/test_inverter.py +++ b/goodwe_controller/test_inverter.py @@ -1356,7 +1356,7 @@ check("⚠️ AND A UNIT WITH NO `setpoint_entity` IS DELIBERATELY STILL LIVE HE inverter_b(setpoint="").is_live(_now)[0] is True) check("...and the status page says so in its own row, which is the surface an " "operator actually reads", - any("NO SETPOINT ENTITY" in n for n in + any("“Setpoint entity” is not set" in n for n in built(store=MemStore(), second=inverter_b(setpoint=""))[0] .liveness_notes())) check("...and a healthy site adds NO liveness rows at all, so the page is not " diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index c2e7771..30b77ee 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -150,15 +150,129 @@ check(f"the samples cover every notification id in the catalogue " check("the payload carries exactly the three keys Home Assistant accepts", all(set(n.data()) == {"notification_id", "title", "message"} for n in SAMPLES)) +# The Details link (UX-09). Home Assistant 2026.2+ serves add-on pages at +# /config/app/<slug>/<tab> and 2026.5 dropped /hassio/addon/<slug>/<tab>, so +# the path follows the version the Supervisor reports; unknown means current. +_LINE = ("Details: [add-on documentation](/config/app/local_goodwe_controller/" + "documentation), section “Battery is not keeping up” under " + "Notifications.") +os.environ["HOSTNAME"] = "3f2a9c1b7d4e" # a container id, as on TEST-23 +messages.set_site("local_goodwe_controller", "2026.9.1") +check("with the Supervisor's slug the Details line is exactly the current-HA " + "link plus the section by name, even when the hostname is a container id", + SAMPLES[0].data()["message"].endswith("\n\n" + _LINE)) +_link = {v: messages.docs_url("local_goodwe_controller", v) + for v in ("2026.1.3", "2026.2.0", "2026.4.2", "2026.10.0b1", + "2025.12.5", None, "rubbish")} +check(f"Home Assistant 2026.1 and older get the old /hassio path, 2026.2 and " + f"newer and an unknown version the /config/app path ({_link})", + _link == { + "2026.1.3": "/hassio/addon/local_goodwe_controller/documentation", + "2025.12.5": "/hassio/addon/local_goodwe_controller/documentation", + "2026.2.0": "/config/app/local_goodwe_controller/documentation", + "2026.4.2": "/config/app/local_goodwe_controller/documentation", + "2026.10.0b1": "/config/app/local_goodwe_controller/documentation", + None: "/config/app/local_goodwe_controller/documentation", + "rubbish": "/config/app/local_goodwe_controller/documentation"}) +messages.set_site("../../etc", "2026.9.1") +check("a slug that is not this add-on's shape is not put in a link", + "](" not in SAMPLES[0].data()["message"]) +messages.set_site(None, None) os.environ["HOSTNAME"] = "abcd1234-goodwe-controller" -check("inside the add-on the Details line links to its documentation page", - "(/hassio/addon/abcd1234_goodwe_controller/documentation)" +check("without the Supervisor's answer the slug comes from a Supervisor-style " + "hostname", + "(/config/app/abcd1234_goodwe_controller/documentation)" in SAMPLES[0].data()["message"]) os.environ["HOSTNAME"] = "some-laptop" check("...and anywhere else it names the section without a guessed link", - "](" not in SAMPLES[0].data()["message"] - and "under Notifications" in SAMPLES[0].data()["message"]) + SAMPLES[0].data()["message"].endswith( + "\n\nDetails: add-on documentation, section “Battery is not keeping " + "up” under Notifications.")) del os.environ["HOSTNAME"] + +# Where the slug and the version come from: the Supervisor, read once at start. +import asyncio # noqa: E402 +from app.main import docs_link_facts # noqa: E402 + + +class _Resp: + def __init__(self, body): + self.body = body + + async def __aenter__(self): + if isinstance(self.body, Exception): + raise self.body + return self + + async def __aexit__(self, *a): + return False + + async def json(self, content_type=None): + return self.body + + +class _Session: + def __init__(self, answers): + self.answers, self.asked = answers, [] + + def get(self, url, **kw): + self.asked.append((url, kw.get("headers", {}).get("Authorization"))) + return _Resp(self.answers[url]) + + +_ok = _Session({ + "http://supervisor/addons/self/info": {"result": "ok", "data": { + "slug": "local_goodwe_controller", "version": "0.12.0"}}, + "http://supervisor/info": {"result": "ok", "data": { + "homeassistant": "2026.9.1", "supervisor": "2026.08.0"}}}) +_down = _Session({"http://supervisor/addons/self/info": OSError("refused"), + "http://supervisor/info": ValueError("not json")}) +check("at start the add-on asks the Supervisor for its slug and HA's version, " + "with its own token", + asyncio.run(docs_link_facts(_ok, "tok")) == { + "slug": "local_goodwe_controller", "ha_version": "2026.9.1"} + and all(a == "Bearer tok" for _u, a in _ok.asked)) +check("...and a Supervisor that does not answer costs the link, never the " + "start", + asyncio.run(docs_link_facts(_down, "tok")) == { + "slug": None, "ha_version": None}) + +# Shadow mode (UX-09): nothing the add-on decides reaches the inverter, so no +# text may say a command was sent or that the battery is giving power. +_c1 = [messages.Clamp(None, 7412, 5000, "rating")] +_c2 = [messages.Clamp("inverter-a", -3000, -2500, "device"), + messages.Clamp("inverter-b", 6000, 4600, "max_w+device")] +_live = [messages.output_clamp(c).body for c in (_c1, _c2, ())] +_shad = [messages.output_clamp(c, shadow=True).body for c in (_c1, _c2, ())] +check("live, the over-rating alarm says what was sent and that control runs", + " and sent 5 000 W" in _live[0] and " and sent 2 500 W" in _live[1] + and all("Control is still running" in b or "control is still running" + in b for b in _live)) +check("in shadow mode it says what would have been sent, and that the " + "inverters stay at 0 W", + "would have sent 5 000 W" in _shad[0] + and "would have sent 2 500 W" in _shad[1] + and "would have been cut back" in _shad[2] + and all(" sent" not in b.replace("would have sent", "") for b in _shad) + and all("0 W" in b and "hadow mode" in b for b in _shad)) +_row_live = messages.row_power_too_high(_c1, 3) +_row_shad = messages.row_power_too_high(_c1, 3, shadow=True) +check("the over-rating row says 'sent' live and 'would send' in shadow mode", + "sent 5 000 W" in _row_live and "would" not in _row_live + and "would send 5 000 W" in _row_shad and " sent" not in _row_shad + and "shadow mode" in _row_shad) +_sat = messages.peak_saturated(5000, shadow=True).body +check("in shadow mode the peak alarm does not claim the battery is giving " + "power, and keeps its action", + "giving all it can" not in _sat and "gives nothing" in _sat + and "Switch off large loads" in _sat + and "giving all it can" in messages.peak_saturated(5000).body) +check("shadow mode changes no notification's id or severity", + all(messages.output_clamp(c, shadow=True).id == messages.ID_OUTPUT_CLAMP + and messages.output_clamp(c, shadow=True).severity == messages.ALARM + for c in (_c1, _c2, ())) + and messages.peak_saturated(1, shadow=True).id == messages.ID_PEAK_SATURATED + and messages.peak_saturated(1, shadow=True).severity == messages.ALARM) check("the output-clamp alarm quotes asked before sent", messages.output_clamp([messages.Clamp(None, 7412, 5000, "rating")]).body .index("7 412 W") < messages.output_clamp( @@ -305,7 +419,7 @@ ALLOW_FILE = HERE / "ux08_allowlist.txt" # The allowlist may never grow. The test demands the list be exactly this long, # so deleting lines means lowering this number in the same change, and adding # one means raising it where a reviewer sees it. -ALLOWLIST_MAX = 168 +ALLOWLIST_MAX = 167 def read_allowlist(path): diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index cb25739..65b5bee 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1065,7 +1065,7 @@ check("...and the status page says the guard is off, and why, rather than " "'idle' or a green row - the same answer SAFETY-18 already gives on a " "transport that cannot see it", len(off_rows) == 1 and ": off" in off_rows[0]["text"] - and "meter source" in off_rows[0]["text"] + and "Where the meter reading comes from" in off_rows[0]["text"] and "idle" not in off_rows[0]["text"] and not off_rows[0]["ok"] and off_rows[0]["warn"]) @@ -2487,7 +2487,7 @@ rows25 = [r for r in c25.checks() if r.get("id") == "peak_guard"] def _row_scope(text): """SAFETY-25 in messages.row_peak_reserve()'s words.""" - return ("Home use still discharges below the reserve" in text + return ("Home use still draws the battery below it" in text and "down to the cut-out level" in text) @@ -2531,8 +2531,8 @@ def _says_scope(body): """SAFETY-25 in messages.peak_reserve()'s words: the reserve binds the peak guard only, and home use goes on discharging below it to the cut-out.""" return ("The reserve only applies to keeping the peak down" in body - and "normal home use can still discharge the battery below it" in body - and "down to its cut-out level" in body) + and "normal home use can still draw the battery below it" in body + and "down to the battery cut-out level" in body) print(f" notification body tail: ...{_body25[-180:]}") diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index d6d5233..20f282c 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -535,7 +535,7 @@ print(f" {[r['text'] for r in _bad_row]}") check("a refused read says WHICH refusal - 'no reading' on its own sends an " "operator to look at a working sensor", len(_bad_row) == 1 - and _bad_row[0]["text"] == ("Solar production: no reading, the sensor's " + and _bad_row[0]["text"] == ("Solar production: no reading, the entity's " "unit is not a power unit")) check("...and every refusal pv.watts() can give has its own plain words", len({messages.pv_problem(pv.watts(st)[1]) for st in ( @@ -996,7 +996,7 @@ check("⭐ BOTH KEYS SET: the page SAYS `pv_entity` is ignored and how many " "key still names - but a replacement nobody is told about is the 'one of " "which silently wins' this config refuses elsewhere", len(_ign) == 1 and _ign[0]["ok"] is False and _ign[0]["warn"] is True - and "clear the single sensor setting" in _ign[0]["text"] + and "clear “Solar production entity”" in _ign[0]["text"] and _c_both.pv_w == 3750.0) check("...and that caution appears ONLY when both are set - not on the 0.11.0 " "configuration, not on a list-only one, and not on an install with " @@ -1126,7 +1126,7 @@ check("⭐ THE REPORTED CASE: 13 W of night-time standby on a reversed meter is _c_own.pv_w == -13.0 and [r["text"] for r in pv_rows(_c_own)] == ["Solar production: -13 W, sign reversed"] - and _row(_c_own, "reversed-sign list") == []) + and _row(_c_own, "Reversed-sign solar entities") == []) check("...and WITHOUT the option it is the plain row", [r["text"] for r in pv_rows(_c_own0)] == ["Solar production: 13 W"]) @@ -1140,7 +1140,7 @@ check("⭐ PADDING: ` sensor.x` in the roster and `sensor.x ` in " "`pv_invert_entities` are the same entity - flipped on the read path, " "marked on the page, and no stray caution", _c_pad.pv_w == MIX_TOTAL - and _row(_c_pad, "reversed-sign list") == []) + and _row(_c_pad, "Reversed-sign solar entities") == []) # --- the negative caution ------------------------------------------------------- def _neg(watts_by_entity, flip=()): @@ -1156,12 +1156,12 @@ _n_rm = _neg({E1: 1200, E2: 1500, E3: 450}, flip=[E2]) print(f" {[r['text'] for r in _n_add + _n_rm]}") check("⭐ AN UNFLIPPED ENTITY FAR BELOW ZERO gets a caution that names it by " "its place in the list, its watts, and says to ADD it to the " - "reversed-sign list (`pv_invert_entities`)", + "setting 'Reversed-sign solar entities' (`pv_invert_entities`)", [r["text"] for r in _n_add] - == ["Solar production: source 2 reads -1 500 W, so add it to the " - "reversed-sign list"]) + == ["Solar production: source 2 reads -1 500 W, add it to " + "“Reversed-sign solar entities”"]) check("...and a FLIPPED one far below zero is told to REMOVE it instead", - len(_n_rm) == 1 and "remove it from the reversed-sign list" + len(_n_rm) == 1 and "remove it from “Reversed-sign solar entities”" in (_at(_n_rm, 0) or {}).get("text", "")) check("⭐ ...and it is a CAUTION, never a `bad` row - a telemetry sign cannot " "put a battery site into NOT READY", @@ -1184,10 +1184,10 @@ _c_typo, _, _ = run(cycles=1, by_entity=FULL, check("a `pv_invert_entities` entry naming no PV entity in use is a named " "caution (a typo would otherwise leave the sign silently unflipped)", [(r["text"], r.get("ok"), r.get("warn")) - for r in _row(_c_typo, "not a solar sensor in use")] - == [("Solar production: entry 1 of the reversed-sign list is not a " - "solar sensor in use", False, True)] - and _row(_c_mix, "not a solar sensor in use") == []) + for r in _row(_c_typo, "not a solar entity in use")] + == [("Solar production: entry 1 of “Reversed-sign solar entities” is " + "not a solar entity in use", False, True)] + and _row(_c_mix, "not a solar entity in use") == []) # --- default: byte-identical to 0.12.0 ------------------------------------------ _c_d0, _, _p_d0 = run(cycles=1, by_entity=MIX, **PV_MANY) diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 648370c..982fa97 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -1276,8 +1276,8 @@ check("PRECONDITION: both runs actually tripped and actually raised the card, " and len(_notes_g) == 1 and len(_notes_s) == 1) # --- AC 4: THE ATTRIBUTION ITSELF ------------------------------------------- -_WHO_G = "garage was discharging while shed was charging" -_WHO_S = "shed was discharging while garage was charging" +_WHO_G = "garage was giving power while shed was charging" +_WHO_S = "shed was giving power while garage was charging" check("⚠️ THE ALARM NAMES THE TWO PACKS AND SAYS WHICH WAY EACH ONE IS PULLING. " "`circulation.py` calls this the first thing somebody woken at 3 a.m. " "needs and impossible to reconstruct from the watts alone, and until this " diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index ce55375..e31e42c 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -45,7 +45,7 @@ configuration: name: "Hardware · Inverter setpoint entity" description: "The ESPHome number entity this add-on writes the power setpoint to, normally number.*_goodwe_setpoint_w. This is the only thing the add-on commands. Leave it empty if you fill in the inverter list below: a site with a roster must not also name one loose actuator, and the add-on refuses to start when both are set." soc_entity: - name: "Hardware · Battery charge level entity (%)" + name: "Hardware · Battery level entity (%)" description: "The sensor that reports the pack's state of charge in percent. Use the ESP32's own reading, not a figure computed somewhere else. The maintenance cycle and every charge-level floor read this." batt_entity: name: "Hardware · Battery power entity (W)" @@ -70,7 +70,7 @@ configuration: name: "Battery cut-out level (%)" description: "The percent at which THIS pack's own battery management system cuts out. Read it off the pack that is actually installed (register 0x0560) before that pack is ever commanded; do not copy another unit's figure. Required of every entry, deliberately: an optional one would be a defaulted one, and one default for two batteries of different models protects the shallower pack with the deeper pack's number." soc_entity: - name: "Battery charge level entity (%) (optional)" + name: "Battery level entity (%) (optional)" description: "This pack's own state of charge. Leave it empty if this unit reports none - that is what it means, and it never falls back to another unit's sensor." batt_entity: name: "Battery power entity (W) (optional)" @@ -85,13 +85,13 @@ configuration: name: "Hardware · RS485 emergency stop is fitted" description: "Whether the RS485 emergency stop is physically installed. It only drives the warning banner on the status page; it changes no control behaviour." pv_entity: - name: "Hardware · PV production entity (W)" + name: "Hardware · Solar production entity (W)" description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Point it at your solar inverter's own power sensor (any brand Home Assistant reads; it does not have to be on the RS485 bus) and the add-on records production beside the grid and battery figures, so a day of unstored surplus can be told apart from a day with no sun. POSITIVE MUST MEAN PRODUCING - if yours reads negative while producing, list it under 'sign is reversed' below. The unit is read from the entity itself - W, kW and the rest of Home Assistant's power units - so a sensor with no unit is refused rather than guessed at, and the status page says so. Leave it empty and nothing is read, nothing is published and nothing is shown." pv_entities: - name: "Hardware · PV production entities, one per inverter (W)" + name: "Hardware · Solar production entities, per inverter (W)" description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Use this instead of the single entity above when your roof has SEVERAL solar inverters: add one row per inverter, pointing at each one's own power sensor, and the add-on records the SITE total. Each entity's own unit is read, so a kW inverter beside a W one adds up correctly. ⚠️ SETTING THIS IGNORES THE SINGLE ENTITY ABOVE - clear that one when you fill this in, or you will see a caution on the status page saying so. ⚠️ AND IF ANY ONE OF THESE STOPS REPORTING THERE IS NO SITE TOTAL: the sensor goes to 'unknown' and the history records a gap, rather than publishing the sum of the ones that did answer. Two inverters out of three add up to a smaller number that looks exactly like a real one, and a week later that reads as 'there was less sun than there was' - which is the one conclusion this recording exists to test. The status page says which one is missing, by its place in this list. Leave it empty and nothing is read, nothing is published and nothing is shown." pv_invert_entities: - name: "Hardware · PV entities whose sign is reversed" + name: "Hardware · Reversed-sign solar entities" description: "Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a power clamp in the PV circuit - read NEGATIVE while producing and a few watts POSITIVE at night. Add each such entity here, spelled exactly as it is above, and its sign is flipped before it is added up; leave the others out. The status page marks every flipped entity. History recorded before you set this keeps the old sign." meter_source: name: "Meter · Where the meter reading comes from" @@ -148,7 +148,7 @@ configuration: name: "Limits · Quarter-hour demand forecast entity (W)" description: "Optional. A forecast of the current billing quarter's average demand. Leave it empty and there is no capacity cap at all." peak_soc_floor: - name: "Limits · Peak guard will not discharge below (%)" + name: "Limits · Peak reserve (%)" description: "DERIVED, not picked (SAFETY-24): the reference pack holds 13.8 kWh usable and the worst modelled peak-shaving day asks for 878 Wh, which is 6.4 %, so 20 % sits ten points above the pack's own cut-out and still leaves the guard about 1.6 of its worst observed days of room. ⚠️ IT BOUNDS THE PEAK GUARD ONLY. It is not a reserve for the whole pack: ordinary self-consumption discharges straight past it and goes on down to the battery cut-out, and raising this number does not change that by a tenth of a percent. It must stay strictly above the battery cut-out or the add-on refuses to start. Do not change it without re-deriving it." price_provider: name: "Tariff · Dynamic price source" diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index 79b1828..2818589 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -128,7 +128,7 @@ configuration: name: "Grenzen · Entiteit met de kwartierprognose (W)" description: "Optioneel. Een prognose van het gemiddelde vermogen in het lopende factuurkwartier. Laat u dit leeg, dan is er helemaal geen piekbegrenzing." peak_soc_floor: - name: "Grenzen · Piekbewaking ontlaadt niet onder (%)" + name: "Grenzen · Piekreserve (%)" description: "AFGELEID, niet gekozen (SAFETY-24): de referentiebatterij heeft 13,8 kWh bruikbaar en de zwaarste doorgerekende afvlakdag vraagt 878 Wh, oftewel 6,4 %, dus 20 % ligt tien punten boven de uitschakelgrens van de batterij zelf en laat de bewaking nog ongeveer 1,6 van haar zwaarste waargenomen dagen speling. ⚠️ DIT BEGRENST ALLEEN DE PIEKBEWAKING. Het is geen reserve voor de hele batterij: gewoon eigenverbruik ontlaadt er dwars doorheen en gaat door tot aan de uitschakelgrens van de batterij, en dit getal verhogen verandert daar geen tiende procent aan. Het moet strikt boven de uitschakelgrens van de batterij blijven, anders start de add-on niet op. Verander het niet zonder de afleiding opnieuw te maken." price_provider: name: "Tarief · Bron van dynamische prijzen" diff --git a/goodwe_controller/ux08_allowlist.txt b/goodwe_controller/ux08_allowlist.txt index 3c9ea58..5de744e 100644 --- a/goodwe_controller/ux08_allowlist.txt +++ b/goodwe_controller/ux08_allowlist.txt @@ -127,7 +127,6 @@ option-name 52d03808da01 # en.yaml over 6 words (8) :: 'Your own INJECTION form option-name bf22f2121af4 # en.yaml over 6 words (8) :: 'Your own tariff formula (one line of JSON)' option-name 5593992fcf5b # en.yaml over 6 words (7) :: 'How far ahead to fetch prices (hours)' option-name d9fee5514a4b # en.yaml over 6 words (11) :: 'Levies and VAT by time of day (one line of JSON)' -option-name 7d8d691905e0 # en.yaml over 6 words (7) :: 'PV production entities, one per inverter (W)' option-name eac7ee084aaa # en.yaml banned: Saturated :: 'Saturated cycles before freezing (count)' option-name 5c6bbc5cab40 # en.yaml banned: Saturation :: 'Saturation threshold (W)' option-name 99a1ec154d36 # en.yaml over 6 words (7) :: 'Shadow mode — run every decision, command nothing' -- 2.54.0 From 63dee6db1e0e1745f45507a12568c1e50f84b636 Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 04:45:06 +0200 Subject: [PATCH 033/105] UX-09 review: short start-up timeout, latch rows pinned in shadow, plainer rows The Supervisor questions for the Details link are asked together with a 3 s budget instead of one after the other at 10 s each, so a hung Supervisor cannot hold control start for 20 s. In shadow mode the circulating and site-direction latches are pinned to keep their own red row that says how they clear. Plainer inverter and battery wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/app/main.py | 23 ++++++++++++++--------- goodwe_controller/app/messages.py | 12 ++++++------ goodwe_controller/test_messages.py | 7 ++++++- goodwe_controller/test_watchdog.py | 25 +++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 6f40b67..7ff0cfe 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -5370,27 +5370,32 @@ def control_task_done(task: asyncio.Task, *, controller, stop: asyncio.Event, stop.set() +DOCS_LINK_TIMEOUT_S = 3 + + async def docs_link_facts(session, token: str) -> dict: """`{slug, ha_version}` from the Supervisor, each None when unreadable. `GET /addons/self/info` and `GET /info` are on the Supervisor's bypass list for an add-on's own token, so they need no role (see selfconfig.py). + Asked together with a 3 s budget: a link may never hold up control start. """ - out = {"slug": None, "ha_version": None} - for key, url, field in (("slug", "http://supervisor/addons/self/info", - "slug"), - ("ha_version", "http://supervisor/info", - "homeassistant")): + async def ask(url, field): try: - async with session.get(url, timeout=10, headers={ + async with session.get(url, timeout=DOCS_LINK_TIMEOUT_S, headers={ "Authorization": f"Bearer {token}"}) as r: body = await r.json(content_type=None) data = body.get("data", body) if isinstance(body, dict) else {} - out[key] = data.get(field) if isinstance(data, dict) else None + return data.get(field) if isinstance(data, dict) else None except Exception as err: # noqa: BLE001 - a link, never a stop _LOG.info("docs link: %s unreadable (%s)", url, err) - _LOG.info("docs link: slug %s, Home Assistant %s", out["slug"], - out["ha_version"]) + return None + + slug, ha = await asyncio.gather( + ask("http://supervisor/addons/self/info", "slug"), + ask("http://supervisor/info", "homeassistant")) + out = {"slug": slug, "ha_version": ha} + _LOG.info("docs link: slug %s, Home Assistant %s", slug, ha) return out diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 44dd295..24f6868 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -146,9 +146,9 @@ LIMIT_WORDS = { def loop_bound() -> Notice: """SAFETY-40: the integrator bound. Normal in short bursts; not a fault.""" return Notice(ID_LOOP_BOUND, WARNING, T_LOOP_BOUND, - "The battery does less than asked, which is normal briefly, " - "but if this keeps happening, check that it is on and not " - "empty or full.") + "The battery gives less than asked, which is normal for a " + "moment, but if it lasts, check it is on and not empty " + "or full.") @dataclass(frozen=True) @@ -358,7 +358,7 @@ def banner_shadow(latched: bool) -> str: clears. """ if latched: - return ("Shadow mode, battery not controlled. A safety stop stays on, " + return ("Shadow mode: battery not controlled. A safety stop stays on, " "see below.") return "Shadow mode: the battery is not controlled. Inverters stay at 0 W." @@ -491,8 +491,8 @@ def row_no_setpoint(name) -> str: def row_not_controllable(name, held_s, limit_s) -> str: """Red. The inverter is dropped and the others carry its share.""" - return (f"{name} cannot be controlled. Every command was refused for " - f"{seconds(held_s)}, limit {seconds(limit_s)}.") + return (f"{name} cannot be controlled. It refused every command for " + f"{seconds(held_s)}, so control leaves it out.") def row_commands_refused(name, held_s, limit_s) -> str: diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 30b77ee..fd94efd 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -213,10 +213,11 @@ class _Resp: class _Session: def __init__(self, answers): - self.answers, self.asked = answers, [] + self.answers, self.asked, self.timeouts = answers, [], [] def get(self, url, **kw): self.asked.append((url, kw.get("headers", {}).get("Authorization"))) + self.timeouts.append(kw.get("timeout")) return _Resp(self.answers[url]) @@ -236,6 +237,10 @@ check("...and a Supervisor that does not answer costs the link, never the " "start", asyncio.run(docs_link_facts(_down, "tok")) == { "slug": None, "ha_version": None}) +check("...and each question has a short timeout, so a Supervisor that hangs " + f"delays control start by seconds, not minutes ({_ok.timeouts})", + len(_ok.timeouts) == 2 + and all(isinstance(t, (int, float)) and 0 < t <= 3 for t in _ok.timeouts)) # Shadow mode (UX-09): nothing the add-on decides reaches the inverter, so no # text may say a command was sent or that the battery is giving power. diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 982fa97..9c71f42 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -960,6 +960,19 @@ check("the banner leads with it - above the sign failsafe, because a sign " "disagreement is visible on every dashboard in the house and this is " "visible nowhere at all", _c.status_payload()["banner"] == messages.banner_circulating()) +# UX-09: the red shadow banner no longer names the latch, so the latch's own +# red row must stay on the list in shadow mode, name it and say how it clears. +_c_mode = _c.o.get("shadow_mode") +_c.o["shadow_mode"] = "on" +check("in shadow mode the banner goes red and says a safety stop stays on, and " + "the circulating row is still red and says only starting control clears " + "it", + _c.status_payload()["level"] == "bad" + and "safety stop" in _c.status_payload()["banner"] + and any(ck.get("id") == "circulating" and not ck["ok"] and not ck["warn"] + and "Only starting control clears this" in ck["text"] + for ck in _c.checks())) +_c.o["shadow_mode"] = _c_mode _pub = {} _c.mqtt = type("P", (), {"enabled": True, "publish": lambda _s, v: _pub.update(v), @@ -1919,6 +1932,18 @@ check("the status page carries a SITE row of its own, and the banner says the " for ck in _c31.checks()) and "Total command" in _c31.status_payload()["banner"] and "inverter-" not in _c31.status_payload()["banner"]) +_c31_mode = _c31.o.get("shadow_mode") +_c31.o["shadow_mode"] = "on" +check("UX-09: in shadow mode the banner goes red and says a safety stop stays " + "on, and the site row is still red and says only starting control " + "clears it", + _c31.status_payload()["level"] == "bad" + and "safety stop" in _c31.status_payload()["banner"] + and any(ck.get("id") == "site_direction" and not ck["ok"] + and not ck["warn"] + and "Only starting control clears this" in ck["text"] + for ck in _c31.checks())) +_c31.o["shadow_mode"] = _c31_mode _pub30 = {} _c31.mqtt = type("P", (), {"enabled": True, "publish": lambda _s, v: _pub30.update(v), -- 2.54.0 From 2c516a032c85334e63e779d61400ab18cc87d7cf Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 05:55:45 +0200 Subject: [PATCH 034/105] UX-08 2c: short refusals, error texts and option texts Validator refusals name the setting by its label and key, say what is wrong and what to change, and keep the rejected value and limit. Option names and descriptions are short in en and nl; citations moved to DOCS "For installers" and the test_translations citation check now pins the instruction on the tab and the record in DOCS. No rule, key, schema, default or exit code changed. Allowlist 167 -> 43 (log lines only). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 9 + goodwe_controller/DOCS.md | 144 +++++- goodwe_controller/app/arbitrage.py | 6 +- goodwe_controller/app/custom_formula.py | 267 +++-------- goodwe_controller/app/messages.py | 48 ++ goodwe_controller/app/p1.py | 54 ++- goodwe_controller/app/price.py | 24 +- goodwe_controller/app/shadow.py | 9 +- goodwe_controller/app/static_tariff.py | 55 +-- goodwe_controller/app/validate.py | 437 ++++++------------ goodwe_controller/test_arbitrage.py | 6 +- goodwe_controller/test_inverter.py | 31 +- goodwe_controller/test_messages.py | 35 +- goodwe_controller/test_peakguard.py | 34 +- goodwe_controller/test_price.py | 99 ++-- goodwe_controller/test_selfconfig.py | 13 +- goodwe_controller/test_static_tariff.py | 4 +- goodwe_controller/test_tool_inputs.py | 2 +- goodwe_controller/test_translations.py | 159 ++++--- goodwe_controller/test_validate.py | 125 ++--- goodwe_controller/test_version_gate.py | 2 +- goodwe_controller/test_watchdog.py | 4 +- goodwe_controller/translations/en.yaml | 268 ++++++----- goodwe_controller/translations/nl.yaml | 297 ++++++------ goodwe_controller/ux08_allowlist.txt | 128 +---- 26 files changed, 1026 insertions(+), 1236 deletions(-) diff --git a/STYLE.md b/STYLE.md index 4117dfc..0a470e9 100644 --- a/STYLE.md +++ b/STYLE.md @@ -6,7 +6,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Title**: at most 5 everyday words. It says what is wrong ("Meter reading may be stuck"). No "GoodWe:" prefix, no full stop. - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. -- **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. +- **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w). **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. - **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index 16718e5..5e56830 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -35,3 +35,12 @@ Every row of the Commissioning list and every banner is now in `app/messages.py` 4. **One term per setting, matching its label.** Four labels changed instead of the texts, because the texts' words were plainer: “Peak reserve (%)” (was "Peak guard will not discharge below"), “Battery level entity (%)” (was "Battery charge level"), and “Solar production entity / entities, per inverter / Reversed-sign solar entities” (was "PV …"). The Dutch labels already said "Zonneproductie". Option descriptions are phase 2c and were not changed, so some still say "PV". 5. **The shadow banner and the inverter notes** are now `messages.banner_shadow()` and `row_no_setpoint` / `row_not_controllable` / `row_commands_refused`, so `test_messages.py` checks them. The red shadow banner no longer lists the latches, because 12 words cannot carry them. It says a safety stop stays on, and each latch keeps its own red row, which names it and says how it clears. The colour of a liveness row now comes from `is_live()`, not from matching "NOT COMMANDABLE" in the text. 6. **DOCS "Notifications" and "Status page"** are written for a home owner, and the card ids, keys and log detail moved to a "For installers" part of each. + +# UX-08 phase 2c: refusals, error texts and option texts + +Validator refusals, the parse errors they carry, and every option name and description are now short. No rule, key, schema, default or exit code changed. Over 36 spoiled configurations the old and new validators refuse the same number of times. The allowlist went from 167 entries to 43, and only log lines (phase 2d) remain on it. + +1. **A refusal names the setting by its label and then its key**, as `messages.setting()` writes it: “Inverter rating” (max_w). The key has to stay, because `configui.problems_by_field()` shows a reason beside every key its text names. A test checks each label against en.yaml. A few reasons no longer mention keys they only named in passing, such as `price_markup_eur_kwh` in the withdrawn-provider reason, so the panel shows those reasons beside fewer settings. +2. **Citations moved to DOCS.** Option descriptions say "Measured value, leave it unchanged" or similar, and the record behind the value is under "For installers: where the numbers come from". The UX-01 citation check in `test_translations.py` now checks the tab for that instruction and DOCS for the record. +3. **What left the refusals:** the shipped default in the peak-reserve reason, the superseded-default note in the levy-table reason (DOCS already covers it), the endpoints of the withdrawn providers (DOCS "Energy price providers"), the plant measurement behind `slew_w` (DOCS, beside the setting), and the leg-specific paragraphs of the tariff-formula errors. Each reason keeps the rejected value, the limit and what to change. +4. **Not rewritten:** errors that only a code defect can raise, such as plugin-contract and argument-type checks in `price.py`, `price_forecast.py`, `static_tariff.py`, `arbitrage.py` and `main.py`, which a home owner never reads. INFO lines such as the tariff-formula preview were also left. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 67605c0..c4b1cb2 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -125,7 +125,7 @@ whole rendered list, in both languages. | **Order comes from `schema:`** | `App.schema_ui` is `UiOptions(...)(data["schema"])`, so the **schema half** of `config.yaml` decides the order the tab renders in — not the `options:` half | | **There are no section headers** | Add-on options are a flat list: no header primitive, no per-option advanced flag, no units on the input, no sliders. Grouping is approximated by **order** plus the `Group · ` prefix in each label, and by nothing else | | **Groups, in task order** | Hardware → Meter → Limits → Tariff → Maintenance → Safety → Advanced | -| **The description says whether to touch it** | A number that was **derived** names the campaign it came from and says not to change it without re-deriving; a number that is genuinely yours (`max_w`, `peak_cap_w`) says **"THIS IS YOUR NUMBER"**; and `cycle_cost_threshold_eur`, which is neither, says it is an open product question | +| **The description says whether to touch it** | One or two plain sentences. A measured or derived value says "leave it unchanged", a number that is genuinely yours (`max_w`, `peak_cap_w`) says "Your own number", and `cycle_cost_threshold_eur` says it is a product choice. Where each number comes from is under [For installers](#for-installers-where-the-numbers-come-from) | | **Dutch falls back per key** | `translations[your language]?.name \|\| translations["en"]?.name \|\| the raw key`. A key missing from `nl.yaml` degrades to English; a key present but wrong does not degrade at all | | **⚠️ The per-entry keys inside `inverters:` still render raw** | Measured, and negative. A list-of-objects becomes an `object` selector with `multiple: true`, and `ha-selector-object` labels its fields `fields[name].label \|\| name` — the converter sets no `label` and no `translation_key`. The `fields:` translations are shipped and validated (they are the shape Supervisor's own schema defines) but on frontend 20250925.1 they do **not** reach the screen. The `inverters` label and description themselves do | @@ -133,6 +133,148 @@ whole rendered list, in both languages. option that does not exist, or an option with no translation, fails CI — in either direction, and the check is mutation-tested both ways. +### Settings at a glance + +The label and description each setting shows on the Configuration tab, in tab order. `translations/en.yaml` is the source, and `test_translations.py` keeps this table in step with it. + +| Group | Setting | Key | What it does | +|---|---|---|---| +| Hardware | Inverter setpoint entity | `setpoint_entity` | The ESPHome number entity the add-on writes the inverter's power to. Leave it empty when you fill in the inverter list. | +| Hardware | Battery level entity (%) | `soc_entity` | The sensor with the battery level in percent. Use the control board's own reading. | +| Hardware | Battery power entity (W) | `batt_entity` | The sensor with this inverter's battery power. Positive must mean the battery is giving power. | +| Hardware | Battery power sign is reversed | `batt_invert` | Switch this on only if your battery power sensor shows giving power as a negative number. | +| Hardware | Inverter list | `inverters` | Leave it empty if you have one inverter. With two or more, add one entry per inverter, which replaces the inverter settings above. | +| Hardware · Inverter list | Name | `inverters.name` | A short, unique name for this inverter, for example inverter-a. | +| Hardware · Inverter list | Setpoint entity | `inverters.setpoint_entity` | This inverter's own ESPHome setpoint entity. Two entries may not use the same one. | +| Hardware · Inverter list | Inverter rating (W) | `inverters.max_w` | The most power the add-on may ask of this inverter. The site total is the sum of the list. | +| Hardware · Inverter list | Battery cut-out level (%) | `inverters.bms_soc_floor` | The level at which this battery's own management system stops giving power. Read it off the battery that is installed. | +| Hardware · Inverter list | Battery level entity (%) (optional) | `inverters.soc_entity` | This battery's own level sensor. Leave it empty if this inverter has none. | +| Hardware · Inverter list | Battery power entity (W) (optional) | `inverters.batt_entity` | This inverter's own battery power sensor. Leave it empty if it has none. | +| Hardware · Inverter list | Battery power sign is reversed (optional) | `inverters.batt_invert` | Switch this on if this inverter's sensor shows giving power as a negative number. | +| Hardware · Inverter list | Usable battery capacity (kWh) (optional) | `inverters.capacity_kwh` | This battery's usable capacity from its datasheet. Fill it in on every inverter or on none, and the work is then shared by energy left. | +| Hardware | RS485 emergency stop is fitted | `estop_fitted` | Switch this on if the emergency stop is installed. It only changes a warning on the status page. | +| Hardware | Solar production entity (W) | `pv_entity` | Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control. | +| Hardware | Solar production entities, per inverter (W) | `pv_entities` | Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded. | +| Hardware | Reversed-sign solar entities | `pv_invert_entities` | Optional. Add each solar entity above that reads negative while producing, spelled the same way. Its sign is flipped before adding up. | +| Meter | Where the meter reading comes from | `meter_source` | How the add-on reads your meter. 'off' uses “Grid power entity” below, and only homewizard_local can spot a stuck meter. | +| Meter | Grid power entity (W) | `meter_entity` | Used when the meter source is 'off'. Positive must mean drawing from the grid. | +| Meter | Grid power sign is reversed | `meter_invert` | Switch this on if your grid sensor shows drawing from the grid as a negative number. | +| Meter | Number of phases (1 or 3) | `meter_phases` | Must match your grid connection. Meter readings with a different number of phases are rejected. | +| Meter | HomeWizard P1 address | `p1_host` | For homewizard_local only. The meter's address on your network, as host or host:port. | +| Meter | Time between meter reads (s) | `meter_poll_s` | For homewizard_local only. The meter updates every 5 s, so lower gains nothing. Keep it well below “Reading too old after”. | +| Meter | Reading too old after (s) | `meter_max_age_s` | After this a meter reading counts as missing. The “Missing inputs time limit” starts only after this one runs out. | +| Meter | MQTT topic | `meter_mqtt_topic` | For mqtt_p1 only. The topic your meter readings are published on. | +| Meter | Grid import entity (W) | `p1_import_entity` | The sensor for power drawn from the grid, never negative. The add-on works out the net value itself. | +| Meter | Grid export entity (W) | `p1_export_entity` | The sensor for power fed into the grid, never negative. It pairs with “Grid import entity”. | +| Meter | Signed net power entity (W) | `p1_net_entity` | For ha_signed only. One sensor that is positive when drawing from the grid and negative when feeding in. | +| Meter | Import entities per phase (L1-L3) | `p1_phase_import_entities` | Optional, in L1, L2, L3 order. Needed for the peak limit on a three-phase connection, one entry per phase. | +| Meter | Export entities per phase (L1-L3) | `p1_phase_export_entities` | Optional, in L1, L2, L3 order, next to the import entities per phase. One entry per phase. | +| Meter | Net entities per phase (L1-L3) | `p1_phase_net_entities` | For ha_signed only. Optional, in L1, L2, L3 order, signed like “Signed net power entity”, one entry per phase. | +| Limits | Inverter rating (W) | `max_w` | Your own number: the most power the add-on may ever ask of the inverter. Start low and raise it after commissioning. | +| Limits | Battery cut-out level (%) | `bms_soc_floor` | The level where the battery's own management system stops giving power. Read it off your battery rather than copying a figure. | +| Limits | Peak limit (W) | `peak_cap_w` | Your own number: the 15-minute average power the add-on keeps the grid under. Take it from your grid contract. | +| Limits | 15-minute demand forecast entity (W) | `peak_forecast_entity` | Optional. A forecast of this 15-minute period's average power. Leave it empty and there is no peak limit. | +| Limits | Peak reserve (%) | `peak_soc_floor` | Peak limiting will not draw the battery below this level, but ordinary use can. Derived value, leave it unchanged. | +| Tariff | Dynamic price source | `price_provider` | Where prices come from. Choosing a source starts the price fetch, even with trading off. | +| Tariff | Supplier markup (EUR/kWh) | `price_markup_eur_kwh` | Your supplier's margin. It is added only when the price source does not already include it. | +| Tariff | Distribution, levies and VAT (EUR/kWh) | `price_taxes_eur_kwh` | Grid costs, levies and VAT per kWh, preset for Flanders. Check it against your own grid operator's rates. | +| Tariff | Injection price (EUR/kWh) | `export_price_eur_kwh` | What you are paid per kWh fed into the grid, all in. It may be negative. | +| Tariff | Fixed or day/night tariff (JSON) | `static_profile` | Your fixed or day/night contract as one line of JSON, prices all in. Fill it in even on a dynamic contract, as the fallback when the price feed fails. | +| Tariff | Day/night levies and VAT (JSON) | `price_taxes_profile` | Leave it empty unless your grid operator charges a different day and night rate, as in Wallonia and Brussels. Set this or the flat figure above, not both. | +| Tariff | Your own tariff formula (JSON) | `price_formula` | For custom_formula only. Type the numbers from your supplier's tariff card as one line of JSON, and the add-on checks them against the card. | +| Tariff | Your own injection formula (JSON) | `price_export_formula` | Optional. The injection formula from your tariff card, in the same shape as your own tariff formula. Leave it empty to use the flat injection price. | +| Tariff | Price CSV file | `price_csv_path` | For manual_csv only. Where in /share the add-on reads your price file. | +| Tariff | Price feed URL override | `price_feed_url` | Leave it empty to use the source's own feed. An override is sent exactly as typed and often returns only one day. | +| Tariff | Price look-ahead (hours) | `price_horizon_h` | How many hours of prices to ask the source for. | +| Tariff | Price request timeout (s) | `price_timeout_s` | How long one request to the price source may take before it is given up. | +| Tariff | Current price entity (older) | `price_now_entity` | The older way to get a price, used only to charge in a cheap window during maintenance. Do not combine it with a dynamic price source. | +| Tariff | Average price entity (older) | `price_avg_entity` | The average the current price is compared with. Use it only with the current price entity, not with a dynamic price source. | +| Tariff | Trade on the price spread | `arbitrage_enabled` | Charge in the cheapest hour and draw the battery down in the dearest, when the spread covers the cost. Turning it off does not turn the price feed off. | +| Tariff | Battery cycle cost (EUR/kWh) | `cycle_cost_threshold_eur` | What one full battery cycle costs per kWh. A smaller price spread is not traded, and the value is a product choice, not a measured one. | +| Tariff | Trading keeps at least (%) | `arbitrage_soc_floor` | Price trading will not draw the battery below this level. It is separate from the maintenance settings. | +| Tariff | Trading charges at most (%) | `arbitrage_soc_ceiling` | Price trading will not charge the battery above this level. | +| Maintenance | Run the monthly battery cycle | `maintenance_enabled` | Once a month, empty the battery deeply, charge it full and hold it there, so its level reading stays accurate. Off by default. | +| Maintenance | Minimum days between cycles | `maintenance_interval_days` | The shortest gap between two maintenance cycles. | +| Maintenance | Start hour | `maintenance_start_hour` | The local hour, 0 to 23, at which a due cycle starts. | +| Maintenance | Draw-down rate (W) | `maintenance_discharge_w` | How fast the cycle empties the battery. Above “Inverter rating” it is cut back to the rating, and the cycle just takes longer. | +| Maintenance | Recharge rate (W) | `maintenance_charge_w` | How fast the cycle recharges the battery. It must be at or below “Inverter rating”, or the add-on will not start. | +| Maintenance | Draw down to (%) | `maintenance_soc_floor` | The level the monthly cycle empties the battery to. It is not the “Peak reserve”, and the two differ on purpose. | +| Maintenance | Recharge up to (%) | `maintenance_soc_target` | The level the recharge aims for before the hold starts. | +| Maintenance | Hold at full for (minutes) | `maintenance_hold_min` | How long the battery stays full so its cells can balance. | +| Safety | Wrong-direction threshold (W) | `sign_disagree_w` | A wrong direction counts only when the command and the meter reading both exceed this. Measured value, leave it unchanged. | +| Safety | Wrong-direction time (s) | `sign_disagree_s` | How long a wrong direction may last before a safety stop sets every inverter to 0 W. Measured value, leave it unchanged. | +| Safety | Per-inverter wrong-direction threshold (W) | `unit_sign_disagree_w` | For two or more inverters: the wrong-direction threshold for each inverter. Derived value, leave it unchanged. | +| Safety | Per-inverter wrong-direction time (s) | `unit_sign_disagree_s` | For two or more inverters: how long one inverter may push the wrong way before it is set to 0 W. Derived value, leave it unchanged. | +| Safety | Site wrong-direction threshold (W) | `site_sign_disagree_w` | For two or more inverters: the wrong-direction threshold for the whole site. Measured value, leave it unchanged. | +| Safety | Site wrong-direction time (s) | `site_sign_disagree_s` | For two or more inverters: how long the whole site may push the wrong way before a safety stop. Derived value, leave it unchanged. | +| Safety | Stuck meter alarm after (s) | `meter_freeze_s` | An alarm when the meter repeats one reading this long while the command is at full power, with homewizard_local only. Measured value, leave it unchanged. | +| Safety | Opposing inverters threshold (W) | `circulation_w` | For two or more inverters: how much power one may push against another before it counts. Measured value, leave it unchanged. | +| Safety | Opposing inverters time (s) | `circulation_hold_s` | For two or more inverters: how long they may push against each other before a safety stop. Derived value, leave it unchanged. | +| Safety | Not delivering alarm after (s) | `delivery_hold_s` | For two or more inverters: how long one may fall short of its share before an alarm, which changes nothing. Derived value, leave it unchanged. | +| Safety | Shadow mode | `shadow_mode` | The add-on makes every decision but keeps every inverter at 0 W. 'auto' does this while control is stopped, 'on' always, 'off' never. | +| Advanced | Start control on boot | `auto_start` | Off by default. Leave it off until the site is commissioned, so someone presses Start after each restart. | +| Advanced | Control gain | `gain` | How much of the remaining error control corrects each cycle. Measured on real hardware, do not raise it. | +| Advanced | Largest change per cycle (W) | `slew_w` | How far the command may move in one cycle. 0 follows “Inverter rating” and is recommended. | +| Advanced | Ignore errors below (W) | `deadband_w` | Errors smaller than this are ignored. Keep it small, since any resting point inside it holds. | +| Advanced | Meter resting point (W) | `target_grid_w` | What the meter should show when nothing happens. A slight export avoids paying for tiny imports all day. | +| Advanced | Command rounding (W) | `step_w` | The command is rounded to a multiple of this, so noise does not change it every cycle. | +| Advanced | Inverter at limit gap (W) | `saturation_w` | When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this. | +| Advanced | Cycles at limit before freezing | `saturation_cycles` | How many cycles in a row at the limit before control stops building up error. Do not set it to 1. | +| Advanced | Error build-up limit (W) | `integrator_max_w` | Limits how much old error control can carry, and 0 means “Inverter rating”. Do not raise it above the rating. | +| Advanced | Command refresh interval (s) | `heartbeat_s` | How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit. | +| Advanced | Missing inputs time limit (s) | `stale_input_s` | How long inputs may be missing before every inverter is set to 0 W. With a P1 meter it starts after “Reading too old after”. | +| Advanced | Longest time between cycles (s) | `cycle_floor_s` | A deadline between control cycles that a healthy meter never reaches. Raise it only for a meter slower than about 10 s. | +| Advanced | Log level | `log_level` | How much detail the add-on writes to its log. 'debug' and 'trace' are for finding a problem. | + +### For installers: where the numbers come from + +The Configuration tab keeps each description to one or two sentences. The detail that used to sit there is here, one entry per setting. A value marked *measured* or *derived* in its description came from the record named below; change it only after re-deriving it from a new measurement. + +When the add-on refuses to start, each reason names the setting by its label and then its key, for example “Inverter rating” (max_w), and adds the inverter's name when there is a list. The configuration panel shows a reason beside every setting it names. + +- **Battery power entity** (`batt_entity`): on the reference installation this is holding register 0x0518, read by the control board. The wrong-direction checks and the opposing-inverters alarm both grade each inverter against it. +- **Inverter list** (`inverters`): empty means the single-inverter settings describe the one inverter you have. Filled in, the list replaces them and nothing is inherited: each entry names its own setpoint entity, rating and cut-out level, so no inverter is judged by another's numbers. “Inverter setpoint entity” must then be empty, and the add-on refuses to start when both are set. Each entry's name keys its own safety stop and records in the add-on's state, so two entries may not share one. +- **Usable battery capacity** (`inverters.capacity_kwh`): read only to share the site target by the energy each battery has left rather than by its rating. The reference batteries are 5000 W with 15.36 kWh and 4600 W with 20.48 kWh, so the two ways of sharing give the work to different batteries. Stated on some entries and not others, the add-on refuses to start. +- **Solar production entities** (`pv_entity`, `pv_entities`, `pv_invert_entities`): measurement only, no control behaviour changes. The unit is read off each entity, so a sensor without one is refused rather than guessed. With several entities, one that stops reporting gives no site total at all, because a partial sum looks like a real one. Setting `pv_entities` ignores `pv_entity`. +- **Where the meter reading comes from** (`meter_source`): 'off' keeps “Grid power entity”. ha_dsmr follows the DSMR integration, mqtt_p1 reads an MQTT topic, ha_signed reads one signed entity (what a HomeWizard P1 publishes), and homewizard_local polls the meter's own local API. Only homewizard_local can tell "the meter did not answer" from "the value did not change", so the stuck-meter alarm only means something there. +- **Grid import and export entities** (`p1_import_entity`, `p1_export_entity`, `p1_net_entity`): the add-on computes net power itself, so the sign convention lives in tested code rather than in a template sensor. +- **Number of phases** (`meter_phases`): a reading whose phase count disagrees is rejected and logged as it arrives, so a wrong value shows up at once. The range accepts 2, which is not a real Belgian connection. +- **Time between meter reads, Reading too old after** (`meter_poll_s`, `meter_max_age_s`): the add-on refuses to start if the poll interval is at or above the age limit. 30 s is six polls of headroom at the default 5 s. The reading-age limit on its own does not command 0 W. “Missing inputs time limit” starts after it, so the two add up. +- **Inverter rating** (`max_w`): your own number, not a derived one. It is not read when the inverter list is filled in, since each entry carries its own and the site limit is their sum. Several safety thresholds must stay below it, and the add-on refuses to start if one does not. +- **Battery cut-out level** (`bms_soc_floor`, `inverters.bms_soc_floor`): measured, not chosen. Register 0x0560 reads 10 % on the reference GW5000S-BP. It exists so the add-on can refuse a “Peak reserve” at or below it, which could never take effect. Each inverter entry states its own, because one default for two different batteries protects the shallower one with the deeper one's number. +- **Peak limit** (`peak_cap_w`): your own number, from your grid contract. In Belgium it is the capacity-tariff peak your distribution charge is billed on. +- **Peak reserve** (`peak_soc_floor`): derived, not picked (SAFETY-24). The reference battery holds 13.8 kWh usable and the worst modelled peak day asks for 878 Wh, or 6.4 %. 20 % sits ten points above the cut-out level and leaves about 1.6 worst days of room. It bounds peak limiting only: ordinary use goes on down to the cut-out level. It must stay above “Battery cut-out level”. +- **Dynamic price source** (`price_provider`): selecting a provider is what starts the fetch, every half hour, whether or not trading is on. It may not be combined with the two older price entities. engie_dynamic, totalenergies_dynamic and eneco_eddy are withdrawn and refuse to start: their endpoints never existed. They stay in the list only so such a site gets that explanation. +- **Supplier markup** (`price_markup_eur_kwh`): under manual_csv, whose prices are all in, it is ignored and logged as ignored. +- **Distribution, levies and VAT** (`price_taxes_eur_kwh`): 0.11736 EUR/kWh, derived in TARIFF-18 from the Eneco residential card for Flanders of September 2026 with 6 % VAT: Fluvius distribution for Antwerpen 5,35 plus excise 4,876 plus green power and CHP levy 1,51 c/kWh. Check it against your own DSO: across the eight Fluvius areas distribution runs from 5,28 to 6,70 c/kWh, so the Flemish total runs from about 0.117 to 0.131. Changing it moves no trading decision, because the same amount lands on every hour. It does move every price shown, and the rule that refuses to draw the battery down into an hour priced below zero. See [What `price_taxes_eur_kwh` is made of](#what-price_taxes_eur_kwh-is-made-of-and-why-yours-is-different-tariff-18). +- **Day/night levies and VAT** (`price_taxes_profile`): for Wallonia and Brussels, where distribution has a day and a night rate (ORES 13,27 against 7,39 c/kWh, AIESH 15,17 against 8,21, Sibelga 9,39 against 7,10). The figures are levies alone, added to the market price. The add-on refuses to start if it and the flat figure disagree. See [Levies and VAT by time of day](#levies-and-vat-by-time-of-day-price_taxes_profile). +- **Injection price** (`export_price_eur_kwh`): one number because no supplier here publishes a dynamic injection curve. In Belgium it is often near zero, and at a sunny midday it can be negative. +- **Fixed or day/night tariff** (`static_profile`): the periods must cover every day type exactly once with no gap and no overlap, and a gap is refused rather than filled. A window 22:00-07:00 on mon-fri does not cover Saturday morning, so a weekend row is required. See [Static day/night and fully-fixed tariffs](#static-daynight-and-fully-fixed-tariffs-static_profile). +- **Your own tariff and injection formula** (`price_formula`, `price_export_formula`): type the card's numbers in the card's units. The `card` block is required on the tariff formula: the add-on recomputes the card's example price and refuses to start if it does not come out. Injection is VAT-exempt in Belgium, so `vat_pct` there is normally 0. See [Your own tariff formula](#your-own-tariff-formula-custom_formula) and [`price_export_formula`, field by field](#price_export_formula-field-by-field). +- **Price feed URL override** (`price_feed_url`): only a host the chosen source declares is accepted. Nothing is added to the URL, not even the date range, so an override often returns one day and the rest of the plan is carried over and excluded from trading. The log warns on every refresh. +- **Current and average price entities** (`price_now_entity`, `price_avg_entity`): kept because removing them would take the maintenance cycle's only price signal away from a live site. +- **Trade on the price spread** (`arbitrage_enabled`): off as shipped, on purpose, because it moves energy against the meter by design. It needs a price source and a P1 meter, and the add-on refuses combinations that cannot work. +- **Battery cycle cost** (`cycle_cost_threshold_eur`): wear plus conversion losses. It is not derived from a measurement: 0.10 is a product decision still open with the owner (OPT-08). At this value a fixed day/night site does not trade, since a realistic Belgian day/night spread is about 0.08 EUR/kWh. +- **Trading keeps at least, Trading charges at most** (`arbitrage_soc_floor`, `arbitrage_soc_ceiling`): kept apart from the maintenance levels, so one setting does not couple two unrelated policies. +- **Draw-down and recharge rate** (`maintenance_discharge_w`, `maintenance_charge_w`): the draw-down rate above the rating is cut back, not refused. A recharge rate above the rating would ask for more than the limit allows and resolve to 0 W, so maintenance would never charge. That is why the add-on refuses it. +- **Draw down to** (`maintenance_soc_floor`): the monthly cycle goes this deep on purpose, while “Peak reserve” is a depth peak limiting never reaches. 11 % against 20 % is why they are two settings. +- **Wrong-direction threshold and time** (`sign_disagree_w`, `sign_disagree_s`): measured, not chosen (SAFETY-02). On the captured healthy day (2026-08-23) signs agree on 93.4 % of gated samples, on the fault day (2026-08-20) 0.0-10.5 %, with opposed runs up to 1752 s. The longest legitimate opposed run is 30 s, and the fault day still trips 13 times at 300 s, so 180 s sits in a wide gap. The threshold must stay below “Inverter rating”. +- **Per-inverter wrong-direction threshold and time** (`unit_sign_disagree_w`, `unit_sign_disagree_s`): two or more inverters only. Derived from 1890 closed-loop test runs (SAFETY-30) with nothing faulty. 250 W is half the at-limit gap. 85 s is 8.5 times the worst legitimate opposition (10.0 s) and 2.8 times the control board's 30 s link limit. +- **Site wrong-direction threshold** (`site_sign_disagree_w`): the single-inverter 300 W carried across deliberately (SAFETY-30), because near zero the sign is noise whatever is behind the one meter. +- **Site wrong-direction time** (`site_sign_disagree_s`): derived from the same 1890 runs (SAFETY-30). The worst legitimate opposition at 300 W is 110 s with one inverter and 215 s with two, so 180 s would false-trip. 325 s is 1.51 times that and inside the 900 s billing period. +- **Stuck meter alarm after** (`meter_freeze_s`): measured, not chosen (SAFETY-18). Over 2399 s of this house at its operating point, the longest run without a new reading is 15.4 s, and 300 s is 19.5 times that. It raises an alarm only and does not set 0 W. +- **Opposing inverters threshold** (`circulation_w`): measured on 924 closed-loop test runs (SAFETY-31). The worst legitimate opposition drops from 505 s at 100 W to 5 s at 400 W, the lowest value accepted. 700 W is 1.75 times that knee, with margin because the second inverter is still a copy of the first. +- **Opposing inverters time** (`circulation_hold_s`): derived (SAFETY-31). 75 s is fifteen control cycles, 15 times the worst legitimate episode, and 2.5 times the control board's 30 s link limit. +- **Not delivering alarm after** (`delivery_hold_s`): two or more inverters only. It reports only (SAFETY-42): nothing is commanded differently. Derived from 2640 closed-loop test runs with nothing faulty. The worst legitimate episode is 35.0 s and 185 s is 5.29 times that. The schema allows 30 s, below that, so expect false reports there. A battery at or below its own cut-out level is never reported. Re-derive with admin/goodwe `sim/delivery_window.py --campaign --blag`. +- **Shadow mode** (`shadow_mode`): the whole decision path runs and nothing reaches the inverter. The status page and action log show what would have been sent. A safety stop that is already up stays up. See [Shadow mode](#shadow-mode-shadow_mode-safety-10). +- **Control gain** (`gain`): measured on real hardware and already at the limit. +- **Largest change per cycle** (`slew_w`): 0 means follow the rating: about a ninth of it, derived (SAFETY-39) from a measured ~18 s step response against a 2 s meter tick. A fixed value faster than the rating allows is refused. At 1000 W against a 5000 W rating control swung the meter from 3.4 kW export to 2.8 kW import on 2026-09-05. +- **Ignore errors below, Meter resting point** (`deadband_w`, `target_grid_w`): the meter's import counter bills every positive watt, so a resting point at 0 W leaks about half the deadband as billed import, roughly 0.2-0.35 kWh a day at 15 W. -10 W moves that leak to export. +- **Inverter at limit gap** (`saturation_w`): the per-inverter wrong-direction threshold is derived as half of it, so moving this moves that argument too. +- **Error build-up limit** (`integrator_max_w`): measured on the closed-loop simulator with a 4000 W load dropped to zero: at a limit equal to the rating the command is 1000 W two cycles later, at 1.5 times the rating 1800 W. Lowering it is the useful direction. +- **Command refresh interval** (`heartbeat_s`): the control board refuses a link that has been quiet for 30 s. +- **Longest time between cycles** (`cycle_floor_s`): keep it under “Reading too old after”, since past that there is no reading left to act on. + ### Sources | option | required | meaning | diff --git a/goodwe_controller/app/arbitrage.py b/goodwe_controller/app/arbitrage.py index ff417f1..da18309 100644 --- a/goodwe_controller/app/arbitrage.py +++ b/goodwe_controller/app/arbitrage.py @@ -262,10 +262,8 @@ def threshold_eur_kwh(opts: dict) -> float: v = float(price_option(opts, "cycle_cost_threshold_eur")) if not math.isfinite(v) or v < 0: raise ValueError( - f"cycle_cost_threshold_eur is {v!r}. It is what a round trip COSTS, " - f"in EUR/kWh, so it is non-negative and finite - a negative " - f"threshold is one every spread clears, which is arbitrage with the " - f"brake removed.") + f"“Battery cycle cost” (cycle_cost_threshold_eur) is {v!r}. Set " + f"it to 0 or more, in EUR/kWh.") return v diff --git a/goodwe_controller/app/custom_formula.py b/goodwe_controller/app/custom_formula.py index 2ee0069..fcd2285 100644 --- a/goodwe_controller/app/custom_formula.py +++ b/goodwe_controller/app/custom_formula.py @@ -199,7 +199,7 @@ RESOLUTIONS: tuple = ("hourly", "quarter_hourly") # index id -> the human name of the series it refers to. One entry today; a # second index is a new row here plus a fetch path, not a new grammar. INDEXES: dict = { - "epex_be": "EPEX BE day-ahead, EUR/MWh", + "epex_be": "Belgian day-ahead price, EUR/MWh", } # ⚠️ 0.01 IN THE CARD'S OWN UNITS, WHICH IS THE LAST DIGIT BOTH REAL CARDS @@ -285,87 +285,29 @@ _LEGS = { '"offset":1.00,"units":"c_eur_per_kwh","vat_pct":6,' '"card":{"month":"2026-09","index_eur_per_mwh":133.9905,' '"expect_incl_vat":15.55}}'), - when="Leave it empty unless price_provider is 'custom_formula'.", - zero_factor=("every spread is exactly 0, and arbitrage can never " - "clear any threshold - a strategy that silently never " - "fires rather than one that is off"), - flat=("that is `static_profile` with a single period covering " - "00:00-24:00 on all days and price_provider 'off'; the add-on " - "then says so at startup instead of leaving you to find out " - "from a year of unchanged bills"), - neg_factor=("No consumption tariff is indexed negatively; if your " - "card shows a minus sign it is on the OFFSET (`A`), " - "which is allowed here and common on injection"), + when=("Leave it empty unless “Dynamic price source” (price_provider) " + "is 'custom_formula'."), + zero_factor=" and trading never finds a price difference", + flat="use “Fixed or day/night tariff” (static_profile) instead", + neg_factor="Put the minus sign on the offset, not on the factor", card_required=True, - card_note=("It is the only thing that can tell a correct pair of " - "coefficients from a plausible-looking wrong one"), - card_causes=( - "or - the expensive one - network charges, levies or excise " - "folded into `offset`. ⚠️ THEY DO NOT BELONG THERE: a Belgian " - "card's Tariefformule line is the ENERGY component alone (Eneco " - "tabulates network tariffs and levies separately; ENGIE says in " - "so many words that the formula excludes network, distribution, " - "transport, levies and excise), the add-on adds " - "price_taxes_eur_kwh on top of it, and folding ~12 c EUR/kWh of " - "network charge into `offset` bills you for it twice. That is " - "the error this check exists to catch, and it is why it cannot " - "be switched off."), + card_note="The add-on needs it to check your two numbers", + card_causes="that network charges are not in the offset", ), EXPORT_FORMULA_OPTION: _Leg( option=EXPORT_FORMULA_OPTION, what="injection", - # ⚠️ NO `card` BLOCK IN THE EXAMPLE, because Eneco's injection line has - # none to copy - the formula is printed with no price beside it. An - # example carrying one would invite an operator to compute the figure - # themselves, which is the one thing this leg must not encourage. example=('{"index":"epex_be","resolution":"hourly","factor":0.1,' '"offset":-1.188,"units":"c_eur_per_kwh","vat_pct":0}'), - when=("Leave it empty unless your supplier pays you an injection " - "price that moves with the market; a flat one is " - "export_price_eur_kwh. ⚠️ This option is read whatever " - "price_provider is set to - it is the leg you are PAID on, not " - "the one you buy on."), - zero_factor=("every hour pays the same, which is a FLAT injection " - "price written as a formula. ⚠️ Note this is NOT the " - "arbitrage argument the consumption leg gives: no " - "strategy in this add-on reads an injection price at " - "all, so a flat one here fires nothing and declines " - "nothing - it is simply the wrong option"), - flat=("that is `export_price_eur_kwh`, the flat injection scalar, " - "which is what every site used before this option existed and " - "which still answers when this one is empty"), - neg_factor=("No Belgian injection tariff is indexed negatively - you " - "are paid MORE when the market is dearer, not less. The " - "minus sign on an injection card is on the OFFSET (`A`): " - "Eneco prints `0,1 x BELPEX-H - 1,188` and Aspiravi " - "`0,07 x Belpex - 2`, and a negative offset is accepted " - "here"), + when=("Fill it in only if your injection price follows the market. It " + "is used whatever the price source is."), + zero_factor="", + flat="use “Injection price” (export_price_eur_kwh) instead", + neg_factor="Put the minus sign on the offset, not on the factor", card_required=False, - card_note=( - "⚠️ IT IS OPTIONAL ON THIS LEG, AND THAT IS A STATED GAP RATHER " - "THAN A RELAXED RULE. A Belgian card prints the CONSUMPTION " - "formula with the reference index and the resulting price beside " - "it, which is what makes `price_formula`'s self-check possible. " - "Eneco's injection line has NO printed price beside it, so on " - "that card there is nothing to grade against and requiring a " - "`card` block would make the market's own published formula " - "inexpressible - or, worse, invite an operator to compute the " - "estimate themselves, at which point the check grades the " - "coefficients against arithmetic done with the same coefficients. " - "Supply it if YOUR card prints one; when it is absent the add-on " - "says at startup that this leg is UNGRADED and the two " - "coefficient bounds below are all there is"), - card_causes=( - "or VAT added where there is none. ⚠️ INJECTION IS VAT-EXEMPT IN " - "BELGIUM - \"Injectietarieven zijn vrijgesteld van btw\" - while " - "consumption is at 6%, so `vat_pct` on THIS option is 0 on every " - "Belgian card the research found, and a 6 typed here because it " - "is 6 on the consumption leg is a ratio of exactly 1.06. Nothing " - "is added to this leg by the framework: price_taxes_eur_kwh is a " - "CONSUMPTION component and is not applied to what you are paid " - "for export, so an offset carrying network charges is a " - "different error here than it is on price_formula and this " - "check cannot tell you which one you made."), + card_note=("It is optional here. Without it the add-on only checks " + "the size of your two numbers"), + card_causes="that vat_pct is 0 for injection", ), } @@ -488,16 +430,12 @@ def _finite(value, field: str, option: str = "price_formula") -> float: """ if isinstance(value, bool) or not isinstance(value, (int, float)): raise FormulaInvalid( - f"{option}.{field} is {value!r}, which is not a number. " - f"Write the coefficient as a bare JSON number - 0.102, not " - f"\"0.102\" and not an expression: this provider takes FIXED " - f"coefficients and evaluates nothing.") + f"{option}.{field} is {value!r}, which is not a number. Write a " + f"plain number, for example 0.102.") if not math.isfinite(float(value)): raise FormulaInvalid( - f"{option}.{field} is {value!r}, which is not finite. A NaN " - f"or an infinity here makes every price NaN, every price " - f"comparison False, and an arbitrage strategy that never fires " - f"while reporting that it is armed.") + f"{option}.{field} is {value!r}, which is not finite. Write a " + f"plain number, for example 0.102.") return float(value) @@ -517,11 +455,8 @@ def _card(raw, leg: _Leg = None) -> tuple: if not leg.card_required: return ("", None, None) raise FormulaInvalid( - f"{leg.option} has no \"card\" block, and it is REQUIRED. " - f"{leg.card_note}: the add-on recomputes your " - "supplier's own printed example from the numbers you typed and " - "refuses to start if it does not come out. Copy the three figures " - "off the same tariff card as the coefficients: " + f"{leg.option} has no \"card\" block. {leg.card_note}. Copy " + "the three figures from your tariff card, for example " "{\"month\": \"2026-09\", \"index_eur_per_mwh\": 133.9905, " "\"expect_incl_vat\": 15.55}.") if not isinstance(raw, dict): @@ -531,16 +466,13 @@ def _card(raw, leg: _Leg = None) -> tuple: unknown = sorted(set(raw) - set(_CARD_KEYS)) if unknown: raise FormulaInvalid( - f"{leg.option}.card has no field(s) {unknown}. The fields it " - f"takes are {list(_CARD_KEYS)}; a key that is merely ignored is a " - f"number the operator believes took effect.") + f"{leg.option}.card has unknown field(s) {unknown}. It takes " + f"only {list(_CARD_KEYS)}.") month = str(raw.get("month", "") or "").strip() if not _month_date(month): raise FormulaInvalid( - f"{leg.option}.card.month is {raw.get('month')!r}; write the " - f"month the card is dated as \"YYYY-MM\", e.g. \"2026-09\". It is " - f"not used in any price - it is what lets the add-on tell you " - f"your card has gone stale.") + f"{leg.option}.card.month is {raw.get('month')!r}. Write the " + f"month of the card as \"YYYY-MM\", for example \"2026-09\".") return (month, _finite(raw.get("index_eur_per_mwh"), "card.index_eur_per_mwh", leg.option), @@ -594,8 +526,8 @@ def parse_price_formula(value, *, option: str = "price_formula"): value = json.loads(text) except ValueError as e: raise FormulaInvalid( - f"{option} is not valid JSON ({e}). It is a JSON object " - f"on one line, e.g.\n" + f"{option} is not valid JSON ({e}). Write it on one line, for " + f"example\n" f" {leg.example}\n" f"{leg.when}") if not isinstance(value, dict): @@ -612,34 +544,21 @@ def parse_price_formula(value, *, option: str = "price_formula"): unknown = sorted(set(value) - set(_TOP_KEYS)) if unknown: raise FormulaInvalid( - f"{option} has no field(s) {unknown}. The fields it takes " - f"are {list(_TOP_KEYS)}. ⚠️ There is deliberately NO field that " - f"takes an expression: this provider multiplies and adds two " - f"FIXED coefficients and evaluates nothing, because two " - f"coefficients can be graded against your card's printed price " - f"and an arbitrary expression cannot be graded against anything. " - f"If your contract needs a shape this cannot express, it needs a " - f"new named field here - say which shape.") + f"{option} has unknown field(s) {unknown}. It takes only " + f"{list(_TOP_KEYS)}.") index = str(value.get("index", "") or "").strip() if index not in INDEXES: raise FormulaInvalid( - f"{option}.index is {value.get('index')!r}. The reference " - f"series this add-on can fetch are " - f"{', '.join(f'{k!r} ({v})' for k, v in sorted(INDEXES.items()))}. " - f"If your card names a different index, the add-on cannot get it " - f"and guessing which series your supplier meant would price your " - f"battery against the wrong curve.") + f"{option}.index is {value.get('index')!r}. The add-on can only " + f"fetch " + f"{', '.join(f'{k!r} ({v})' for k, v in sorted(INDEXES.items()))}.") resolution = str(value.get("resolution", "") or "").strip() if resolution not in RESOLUTIONS: raise FormulaInvalid( - f"{option}.resolution is {value.get('resolution')!r}; it " - f"must be one of {list(RESOLUTIONS)}. Belgium has been on a " - f"15-minute MTU since 2025-10-01 and the feed publishes 96 points " - f"a day; a contract written against the HOURLY series is priced " - f"on the mean of each hour's quarters. Which one your contract " - f"uses is on your card and cannot be inferred from the feed.") + f"{option}.resolution is {value.get('resolution')!r}. Choose one " + f"of {list(RESOLUTIONS)}, as your tariff card says.") # ⚠️ `units` IS REQUIRED AND HAS NO DEFAULT. A default here would be the # factor-1000 class with a friendly face: the add-on would silently assume @@ -648,12 +567,8 @@ def parse_price_formula(value, *, option: str = "price_formula"): units = str(value.get("units", "") or "").strip() if units not in UNITS: raise FormulaInvalid( - f"{option}.units is {value.get('units')!r} and is REQUIRED - " - f"there is no default, on purpose. It must be one of " - f"{sorted(UNITS)}. Your card prints the formula in ONE of these " - f"and two suppliers use two different conventions for the same " - f"shape, so assuming one would be a factor of 100 or 1000 on " - f"every hour with nothing able to notice.") + f"{option}.units is {value.get('units')!r}. Choose one of " + f"{sorted(UNITS)}, as printed beside the formula on your card.") factor = _finite(value.get("factor"), "factor", option) offset = _finite(value.get("offset"), "offset", option) @@ -667,10 +582,8 @@ def parse_price_formula(value, *, option: str = "price_formula"): # the operator at it rather than let them build it by accident. if factor == 0.0: raise FormulaInvalid( - f"{option}.factor is 0, so the index would not enter the " - "price at all: every hour of every day comes out at " - f"{offset:g} x (1 + {vat_pct:g}/100), {leg.zero_factor}. If " - f"your {leg.what} tariff really is one flat price, {leg.flat}.") + f"{option}.factor is 0, so every hour gets the same {leg.what} " + f"price{leg.zero_factor}. For one flat price, {leg.flat}.") # ⚠️ A NEGATIVE FACTOR INVERTS THE MARKET, and the direction is the danger: # the dearest hour becomes the cheapest one, so the battery is told to @@ -678,22 +591,16 @@ def parse_price_formula(value, *, option: str = "price_formula"): # mispriced site, it is a site actively trading against itself. if factor < 0.0: raise FormulaInvalid( - f"{option}.factor is {factor:g}, which is NEGATIVE. That " - f"inverts the market: the dearest hour of the day comes out as " - f"the cheapest one, so the battery would charge at the evening " - f"peak and discharge at 03:00 - trading against itself on every " - f"cycle. {leg.neg_factor}.") + f"{option}.factor is {factor:g}, which turns the market upside " + f"down. {leg.neg_factor}.") # ⚠️ 0 IS LEGITIMATE AND MUST STAY SO: injection is VAT-exempt in Belgium, # and some cards are already quoted VAT-inclusive. The bound exists for the # 106 / 1.06 / 6 confusion, not to make VAT compulsory. if not 0.0 <= vat_pct <= 30.0: raise FormulaInvalid( - f"{option}.vat_pct is {vat_pct:g} and must be between 0 and " - f"30. It is a PERCENTAGE, so Belgian residential electricity is " - f"6, not 0.06 and not 106. Zero is legitimate and is not refused: " - f"injection is VAT-exempt, and a card that already quotes " - f"VAT-inclusive coefficients needs no second multiplication.") + f"{option}.vat_pct is {vat_pct:g}. Write a percentage between 0 " + f"and 30, for example 6.") month, card_index, card_expect = _card(value.get("card"), leg) spec = FormulaSpec(index=index, resolution=resolution, factor=factor, @@ -777,27 +684,11 @@ def card_refusal(spec: FormulaSpec, delta: float) -> str: exists at all. """ got = in_card_units(spec, spec.card_index_eur_per_mwh) - ratio = (got / spec.card_expect_incl_vat - if spec.card_expect_incl_vat else float("inf")) leg = _LEGS[spec.option] return ( - f"{spec.option} does not reproduce its own card, so the add-on will " - f"NOT start on it. Your contract's arithmetic is " - f"price = (factor x index_eur_per_mwh + offset) x (1 + vat_pct/100); " - f"on the card's own index that is " - f"({spec.factor:g} x {spec.card_index_eur_per_mwh:g} + " - f"{spec.offset:g}) x (1 + {spec.vat_pct:g}/100) = {got:.4f} " - f"{spec.units}, but card.expect_incl_vat says " - f"{spec.card_expect_incl_vat:g} - OUT BY {delta:+.4f} {spec.units} " - f"(ratio {ratio:.4g}; the tolerance is {CARD_TOLERANCE}, which is the " - f"last digit a card prints). One of the two sides is wrong and the " - f"add-on cannot tell which, so it refuses rather than price a battery " - f"on it. The usual causes, in the order they happen: the coefficients " - f"and the expected price are in DIFFERENT units (ratio 10, 100 or " - f"1000 - `units` must be the one the formula line is printed in); VAT " - f"left out or applied twice (ratio 1.06 or 1/1.06); a transposed " - f"digit; the two sides copied off DIFFERENT cards or different " - f"months; {leg.card_causes}") + f"{spec.option} does not match its own card: it gives {got:.4f} " + f"{spec.units} and the card says {spec.card_expect_incl_vat:g}. Check " + f"the units, the VAT and {leg.card_causes}.") # --------------------------------------------------------------------------- # @@ -852,20 +743,10 @@ def implausible_all_in(spec: FormulaSpec, taxes_eur_kwh: float): if energy >= PLAUSIBLE_LO_EUR_KWH and all_in <= PLAUSIBLE_HI_EUR_KWH: return None return ( - f"{spec.option}'s own card works out at {energy:.5f} EUR/kWh of " - f"energy ({spec.card_expect_incl_vat:g} {spec.units} as the card " - f"prints it) and {all_in:.5f} EUR/kWh all-in once " - f"price_taxes_eur_kwh is added, which is outside the plausible band " - f"{PLAUSIBLE_LO_EUR_KWH}-{PLAUSIBLE_HI_EUR_KWH} EUR/kWh for a Belgian " - f"retail tariff. The card self-check passed, so the coefficients and " - f"the printed price AGREE - they simply agree on a number no Belgian " - f"bill carries, which is what a whole card read in the wrong units " - f"looks like (a factor of 10, 100 or 1000 applied to BOTH sides at " - f"once cancels out of that check and cannot cancel out of this one). " - f"Check `units` against the unit printed beside your formula. " - f"⚠️ This bounds the CARD'S OWN POINT, not every hour: a live hour may " - f"legitimately fall outside the band, and a negative day-ahead hour - " - f"the best charging opportunity of the year - is never refused.") + f"{spec.option} gives {energy:.5f} EUR/kWh for energy and " + f"{all_in:.5f} EUR/kWh in total on its own card, outside the " + f"plausible band of {PLAUSIBLE_LO_EUR_KWH}-{PLAUSIBLE_HI_EUR_KWH} " + f"EUR/kWh. Check \"units\" against the unit beside your formula.") def implausible_injection(spec: FormulaSpec): @@ -914,36 +795,16 @@ def implausible_injection(spec: FormulaSpec): """ if not PASSTHROUGH_LO <= spec.passthrough <= PASSTHROUGH_HI: return ( - f"{spec.option}.factor is {spec.factor:g} {spec.units} per " - f"EUR/MWh, which passes through {spec.passthrough:.4g}x the " - f"wholesale price - outside the plausible " - f"{PASSTHROUGH_LO}-{PASSTHROUGH_HI}x for an injection tariff. A " - f"Belgian injection formula pays a share of the market price a " - f"little under or about equal to it: Eneco's " - f"`0,1 x BELPEX-H - 1,188` c EUR/kWh is 1.00x and Aspiravi's " - f"`0,07 x Belpex - 2` is 0.70x. {spec.passthrough:.4g}x is what a " - f"factor typed in the wrong units looks like - check `units` " - f"({spec.units!r}) against the unit printed beside your formula, " - f"because the card self-check cannot see a factor of 10, 100 or " - f"1000 applied to BOTH sides at once. ⚠️ This bounds the " - f"COEFFICIENT and not the price: an injection price below zero is " - f"accepted and is the real market - Eneco's goes negative under " - f"11.88 EUR/MWh of BELPEX-H, which is the middle of a sunny day.") + f"{spec.option}.factor passes through {spec.passthrough:.4g}x the " + f"market price, outside {PASSTHROUGH_LO}-{PASSTHROUGH_HI}x. Check " + f"\"units\" ({spec.units!r}) against the unit beside your " + f"formula.") if abs(spec.offset_eur_kwh) > INJECTION_OFFSET_MAX_EUR_KWH: return ( - f"{spec.option}.offset is {spec.offset:g} {spec.units} = " - f"{spec.offset_eur_kwh:+.5f} EUR/kWh, and |offset| above " - f"{INJECTION_OFFSET_MAX_EUR_KWH} EUR/kWh is not a Belgian " - f"injection tariff in either direction. The published ones are " - f"small and NEGATIVE - Eneco -1,188 c EUR/kWh (-0.01188), " - f"Aspiravi -2 c (-0.02) - so a minus sign here is expected and is " - f"not what this refuses; a MAGNITUDE two orders out is. The usual " - f"cause is the offset typed in a different unit from `units` " - f"({spec.units!r}), or a consumption offset copied onto the " - f"injection leg: they are different numbers on the same card. " - f"⚠️ Network charges and levies do not belong here either - " - f"nothing is added to what you are PAID for export, so an offset " - f"carrying them is simply wrong rather than double-counted.") + f"{spec.option}.offset is {spec.offset:g} {spec.units}, which is " + f"{spec.offset_eur_kwh:+.5f} EUR/kWh and larger than " + f"{INJECTION_OFFSET_MAX_EUR_KWH} EUR/kWh either way. Check its " + f"unit.") return None @@ -957,15 +818,9 @@ def stale_card(spec: FormulaSpec, today=None): if dated is None or (now - dated).days <= CARD_STALE_DAYS: return None return ( - f"{spec.option}'s card is dated {spec.card_month}, which is " - f"{(now - dated).days} days ago. Suppliers reprice: if your contract " - f"has been renewed or rolled over since then, the coefficients here " - f"are last year's and every price this add-on computes is wrong by " - f"however far they moved - and the card self-check cannot see it, " - f"because it grades your coefficients against the card you typed, not " - f"the card against your current contract. Not refused: ENGIE freezes " - f"coefficients for the contract's duration, so an old card is often " - f"exactly right. Worth re-reading your klantenzone once.") + f"{spec.option}'s card is dated {spec.card_month}, " + f"{(now - dated).days} days ago. The add-on still starts, but if your " + f"contract changed since, copy the new figures from your supplier.") # --------------------------------------------------------------------------- # diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 24f6868..462bc7c 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -798,3 +798,51 @@ def samples() -> list: meter_frozen(600), meter_frozen(90), ] + + +# --- refusals (UX-08 phase 2c) -------------------------------------------------- +# A refusal names a setting by its label on the Configuration tab and then by its +# key, because an installer editing in YAML needs the key. The label is the +# en.yaml name without its group prefix and unit; test_messages.py checks that. +LABELS = { + "setpoint_entity": "Inverter setpoint entity", + "max_w": "Inverter rating", + "bms_soc_floor": "Battery cut-out level", + "capacity_kwh": "Usable battery capacity", + "inverters": "Inverter list", + "name": "Name", + "meter_source": "Where the meter reading comes from", + "meter_phases": "Number of phases", + "p1_host": "HomeWizard P1 address", + "meter_poll_s": "Time between meter reads", + "meter_max_age_s": "Reading too old after", + "meter_mqtt_topic": "MQTT topic", + "p1_import_entity": "Grid import entity", + "p1_export_entity": "Grid export entity", + "p1_net_entity": "Signed net power entity", + "p1_phase_net_entities": "Net entities per phase", + "peak_soc_floor": "Peak reserve", + "price_provider": "Dynamic price source", + "price_taxes_eur_kwh": "Distribution, levies and VAT", + "static_profile": "Fixed or day/night tariff", + "price_taxes_profile": "Day/night levies and VAT", + "price_formula": "Your own tariff formula", + "price_export_formula": "Your own injection formula", + "price_csv_path": "Price CSV file", + "price_now_entity": "Current price entity", + "price_avg_entity": "Average price entity", + "arbitrage_enabled": "Trade on the price spread", + "cycle_cost_threshold_eur": "Battery cycle cost", + "arbitrage_soc_floor": "Trading keeps at least", + "arbitrage_soc_ceiling": "Trading charges at most", + "maintenance_charge_w": "Recharge rate", + "sign_disagree_w": "Wrong-direction threshold", + "unit_sign_disagree_w": "Per-inverter wrong-direction threshold", + "slew_w": "Largest change per cycle", + "shadow_mode": "Shadow mode", +} + + +def setting(key: str, unit: str = "") -> str: + """`max_w` -> `“Inverter rating” (max_w)`, plus ` for inverter-b` in a list.""" + return f"“{LABELS[key]}” ({key})" + (f" for {unit}" if unit else "") diff --git a/goodwe_controller/app/p1.py b/goodwe_controller/app/p1.py index 6d23f34..181eec7 100644 --- a/goodwe_controller/app/p1.py +++ b/goodwe_controller/app/p1.py @@ -47,6 +47,10 @@ from datetime import datetime, timezone import aiohttp +from . import messages + +_S = messages.setting # a refusal names the setting by its label (UX-08) + try: import paho.mqtt.client as mqtt except ImportError: # pragma: no cover - container always has it @@ -180,7 +184,8 @@ def make_sample(source: str, import_w, export_w, *, phases: int, # already applied a sign we are about to apply again - reject it rather # than silently double-signing the control loop. if imp < 0 or exp < 0: - raise P1Error(f"unsigned registers cannot be negative (import={imp:g} export={exp:g})") + raise P1Error(f"import and export readings cannot be negative " + f"(import={imp:g} export={exp:g})") per_phase = per_phase_import = None if phase_import_w is not None or phase_export_w is not None: @@ -188,8 +193,8 @@ def make_sample(source: str, import_w, export_w, *, phases: int, pe = list(phase_export_w or [0.0] * len(pi)) if len(pi) != phases or len(pe) != phases: raise P1Error( - f"phase count mismatch: telegram has {len(pi)} import / {len(pe)} export " - f"phases, meter_phases is {phases}") + f"the meter sent {len(pi)} import and {len(pe)} export phases, " + f"but {_S('meter_phases')} is {phases}") vals = [_watts(a, f"L{i + 1} import") - _watts(b, f"L{i + 1} export") for i, (a, b) in enumerate(zip(pi, pe))] per_phase = tuple(vals) @@ -1160,37 +1165,37 @@ def validate_meter_options(opts: dict, phases: int, max_age_s: float) -> list[st exp = str(opts.get("p1_export_entity", "") or "").strip() if not imp or not exp: problems.append( - f"meter_source {SOURCE_HA} needs both p1_import_entity and " - f"p1_export_entity (got {imp or '<blank>'!r} / {exp or '<blank>'!r})") + f"{_S('meter_source')} is {SOURCE_HA!r}, so it needs " + f"{_S('p1_import_entity')} and {_S('p1_export_entity')}. They " + f"are {imp or '<blank>'!r} and {exp or '<blank>'!r}.") elif source == SOURCE_HA_SIGNED: net = str(opts.get("p1_net_entity", "") or "").strip() phase_net = [str(e).strip() for e in (opts.get("p1_phase_net_entities") or []) if str(e).strip()] if not net: problems.append( - f"meter_source {SOURCE_HA_SIGNED} needs p1_net_entity " - "(sensor.p1_sample_age_s would otherwise be announced with " - "nothing feeding it)") + f"{_S('meter_source')} is {SOURCE_HA_SIGNED!r}, so it needs " + f"{_S('p1_net_entity')}.") if phase_net and len(phase_net) != phases: problems.append( - f"p1_phase_net_entities has {len(phase_net)} entities but " - f"meter_phases is {phases} - every telegram would be rejected " - "on the phase-count check") + f"{_S('p1_phase_net_entities')} has {len(phase_net)} entities, " + f"but {_S('meter_phases')} is {phases}. Make them match.") elif source == SOURCE_MQTT: if not str(opts.get("meter_mqtt_topic", "") or "").strip(): - problems.append(f"meter_source {SOURCE_MQTT} needs meter_mqtt_topic") + problems.append(f"{_S('meter_source')} is {SOURCE_MQTT!r}, so it " + f"needs {_S('meter_mqtt_topic')}.") elif source == SOURCE_HOMEWIZARD: host, port_s = homewizard_host_port(opts) if not host: problems.append( - f"meter_source {SOURCE_HOMEWIZARD} needs p1_host (the meter's " - "own address, e.g. 192.168.2.250)") + f"{_S('meter_source')} is {SOURCE_HOMEWIZARD!r}, so it needs " + f"{_S('p1_host')}, the meter's address on your network.") if port_s: try: int(port_s) except ValueError: - problems.append(f"p1_host {opts.get('p1_host')!r} has an " - "unparseable port") + problems.append(f"{_S('p1_host')} is {opts.get('p1_host')!r}, and " + "its port is not a number.") try: # ⚠️ Not `or 5`: that turns an explicit 0 into the default, and a # cadence of 0 is a misconfiguration that must be reported, not @@ -1198,23 +1203,26 @@ def validate_meter_options(opts: dict, phases: int, max_age_s: float) -> list[st raw = opts.get("meter_poll_s", 5) poll_s = float(5 if raw is None or raw == "" else raw) except (TypeError, ValueError): - problems.append(f"meter_poll_s {opts.get('meter_poll_s')!r} is not a number") + problems.append(f"{_S('meter_poll_s')} is " + f"{opts.get('meter_poll_s')!r}, which is not a " + "number.") else: if poll_s <= 0: - problems.append("meter_poll_s must be positive") + problems.append(f"{_S('meter_poll_s')} must be above 0.") # ⚠️ The age can never be fresher than the poll interval. At or past # max_age_s every reading is stale before its successor arrives, so # the controller would sit permanently on missing inputs while the # meter is perfectly healthy - refuse it rather than ship that. elif poll_s >= max_age_s: problems.append( - f"meter_poll_s {poll_s:.1f} is not under meter_max_age_s " - f"{max_age_s:.1f} - every reading would go stale before the " - "next poll") + f"{_S('meter_poll_s')} is {poll_s:.1f}, not below " + f"{_S('meter_max_age_s')} at {max_age_s:.1f}. Poll more " + "often, or every reading goes stale.") else: problems.append( - f"meter_source {source!r} is not one of " - + ", ".join((SOURCE_HA, SOURCE_MQTT, SOURCE_HA_SIGNED, SOURCE_HOMEWIZARD))) + f"{_S('meter_source')} is {source!r}. Choose one of: off, " + + ", ".join((SOURCE_HA, SOURCE_MQTT, SOURCE_HA_SIGNED, SOURCE_HOMEWIZARD)) + + ".") return problems diff --git a/goodwe_controller/app/price.py b/goodwe_controller/app/price.py index f3d0db3..864dfe0 100644 --- a/goodwe_controller/app/price.py +++ b/goodwe_controller/app/price.py @@ -1453,9 +1453,8 @@ def _validate_raw(points, caps): if abs(p.eur_per_kwh) > MAX_PLAUSIBLE_EUR_KWH: raise SourceUnavailable( f"point at {p.start.isoformat()} is {p.eur_per_kwh} EUR/kWh, " - f"beyond +-{MAX_PLAUSIBLE_EUR_KWH} - the usual cause is a feed " - f"in EUR/MWh being read as EUR/kWh, which is a factor of 1000 " - f"and would make every hour look like an emergency") + f"beyond +-{MAX_PLAUSIBLE_EUR_KWH}, so the feed is probably in " + f"EUR/MWh") u = p.start.astimezone(timezone.utc) if seen is not None and u <= seen: raise SourceUnavailable( @@ -1708,18 +1707,13 @@ def _points_from_columnar_json(body, expect_unit, scale, if len(times) != len(prices): raise SourceUnavailable( f"{COLUMNAR_TIME_KEY} has {len(times)} entries and " - f"{COLUMNAR_PRICE_KEY} has {len(prices)}; refusing to zip them. " - f"The short array would truncate the series silently, and a price " - f"series missing its last hours is one missing the evening peak - " - f"traded on as if complete, where no data at all would have " - f"switched arbitrage off (§11.4)") + f"{COLUMNAR_PRICE_KEY} has {len(prices)}, so the feed is cut short " + f"and none of it is used") unit = _columnar_unit(doc.get(COLUMNAR_UNIT_KEY, "")) if unit != _columnar_unit(expect_unit): raise SourceUnavailable( f"the feed reports {doc.get(COLUMNAR_UNIT_KEY)!r}, not " - f"{expect_unit!r}. This provider converts with a fixed factor of " - f"{scale}, so a changed unit is a factor of 1000 on every price " - f"with nothing downstream able to notice it") + f"{expect_unit!r}, so its prices cannot be converted") if doc.get("deprecated"): # Not a refusal: today's prices are still prices. But §11.4 makes a # dead feed look exactly like a quiet one, so the warning that the @@ -2011,11 +2005,9 @@ class CustomFormula(PriceProvider): raise SourceUnavailable(f"price_formula: {e}") if spec is None: raise SourceUnavailable( - "price_provider is 'custom_formula' but price_formula is " - "empty, so there are no coefficients to price anything with. " - "validate.py refuses this configuration at startup; reaching " - "it here means the options blob changed under a running " - "add-on") + "“Dynamic price source” (price_provider) is 'custom_formula', " + "but “Your own tariff formula” (price_formula) is empty. " + "Restart the add-on to check the settings again") url = dayahead_feed_url(self.id, opts, since, until, self.FEED_BASE, self.BZN) check_egress(url, self.capabilities()) diff --git a/goodwe_controller/app/shadow.py b/goodwe_controller/app/shadow.py index c82c6ad..9e36c94 100644 --- a/goodwe_controller/app/shadow.py +++ b/goodwe_controller/app/shadow.py @@ -504,9 +504,6 @@ def problems(opts: dict) -> list: text = str("" if raw is None else raw).strip().lower() if text in MODES: return [] - return [f"shadow_mode is {raw!r}, which is not one of " - + ", ".join(f"'{m}'" for m in MODES) - + ". 'auto' leaves the battery alone while control is stopped and " - "commands it once control is started; 'on' records every " - "decision and commands nothing at all; 'off' is ordinary " - "control."] + return [f"{messages.setting('shadow_mode')} is {raw!r}. Choose " + + ", ".join(f"'{m}'" for m in MODES[:-1]) + + f" or '{MODES[-1]}'."] diff --git a/goodwe_controller/app/static_tariff.py b/goodwe_controller/app/static_tariff.py index 69e11c9..93b96c2 100644 --- a/goodwe_controller/app/static_tariff.py +++ b/goodwe_controller/app/static_tariff.py @@ -262,9 +262,8 @@ def _minutes(value, field: str) -> int: parts = text.split(":") if len(parts) != 2: raise ProfileInvalid( - f"{field} is {value!r}; it must be \"HH:MM\" local Belgian time, " - f"e.g. \"22:00\". A bare hour or a decimal is refused rather than " - f"guessed at - 7.5 could be 07:30 or 07:50.") + f"{field} is {value!r}. Write it as \"HH:MM\" in Belgian time, " + f"for example \"22:00\".") try: h, m = int(parts[0]), int(parts[1]) except ValueError: @@ -272,9 +271,8 @@ def _minutes(value, field: str) -> int: f"integers, e.g. \"07:00\"") if not (0 <= m < 60) or not (0 <= h <= 24) or (h == 24 and m != 0): raise ProfileInvalid( - f"{field} is {value!r}, which is not a time of day. Hours run 0-23, " - f"minutes 0-59; \"24:00\" is accepted only as an END meaning " - f"midnight at the end of the day.") + f"{field} is {value!r}, which is not a time of day. Use 00:00 to " + f"23:59, or \"24:00\" as an end time.") return h * 60 + m @@ -286,11 +284,8 @@ def _days(value, field: str) -> frozenset: """ if value is None: raise ProfileInvalid( - f"{field} is missing. Name the days this period applies to - " - f"\"mon-fri\", \"sat,sun\" or \"all\". It is required rather than " - f"defaulted to every day, because a Belgian night tariff that " - f"silently covered the weekend too would misprice 48 h a week with " - f"nothing reporting it.") + f"{field} is missing. Name the days, for example \"mon-fri\", " + f"\"sat,sun\" or \"all\".") tokens = [] if isinstance(value, (list, tuple)): for item in value: @@ -367,10 +362,8 @@ def _price(value, field: str, means: str = None) -> float: raise ProfileInvalid(f"{field} is {value!r}, which is not finite") if abs(out) > MAX_PLAUSIBLE_EUR_KWH: raise ProfileInvalid( - f"{field} is {out} EUR/kWh, beyond +-{MAX_PLAUSIBLE_EUR_KWH}. The " - f"usual cause is a figure in cents or in EUR/MWh - 34 instead of " - f"0.34 - which would make every hour look like an emergency. Same " - f"bound the fetched feeds are held to (price.py `_validate_raw`).") + f"{field} is {out} EUR/kWh, beyond +-{MAX_PLAUSIBLE_EUR_KWH}. " + f"Write the price in EUR/kWh, for example 0.34 and not 34.") return out @@ -422,9 +415,8 @@ class StaticProfile: self.option = option if not self.periods: raise ProfileInvalid( - f"{option} has no periods. A profile with no periods is " - f"not a fixed tariff, it is an absent one - leave the option " - f"empty to say that on purpose (§11.4 then applies).") + f"{option} has no periods. Add at least one, or leave the " + f"setting empty.") _check_tiling(self.periods, option=option) # -- what kind of tariff this is, DERIVED -------------------------------- @@ -558,10 +550,7 @@ def _raise_gap(weekday, start, end, option="static_profile"): raise ProfileInvalid( f"{option} leaves {DAY_NAMES[weekday]} " f"{_hhmm(start)}-{_hhmm(end)} with no period, so those hours have no " - f"price. Refused rather than defaulted: an invented price is one an " - f"optimiser would trade on, and §11.4 already says what a missing price " - f"means. Add a period covering it - remember a window written " - f"\"22:00-07:00 mon-fri\" does NOT cover Saturday morning.") + f"price. Add a period that covers them.") def _raise_overlap(weekday, over, end, periods, option="static_profile"): @@ -569,9 +558,8 @@ def _raise_overlap(weekday, over, end, periods, option="static_profile"): names = [p.name for p in periods if p.covers(weekday, start)] raise ProfileInvalid( f"{option} gives {DAY_NAMES[weekday]} {_hhmm(start)}-" - f"{_hhmm(end)} {n} prices at once ({', '.join(names)}). Two prices for " - f"one hour means one of them silently wins on list order. Narrow one of " - f"the windows or split the day selector.") + f"{_hhmm(end)} {n} prices at once ({', '.join(names)}). Make the " + f"periods stop overlapping.") def parse_static_profile(value, *, option: str = "static_profile", @@ -609,28 +597,23 @@ def parse_static_profile(value, *, option: str = "static_profile", value = json.loads(text) except ValueError as e: raise ProfileInvalid( - f"{option} is not valid JSON ({e}). It is a JSON object " - f"with a \"periods\" list, on one line, e.g.\n" + f"{option} is not valid JSON ({e}). Write it on one line with " + f"a \"periods\" list, for example\n" f' {{"periods": [{{"name":"day","from":"07:00","to":"22:00",' f'"days":"mon-fri","eur_per_kwh":0.34}}, ...]}}\n' - f"Leave it empty for a dynamic-only or price-free site.") + f"Leave it empty if you have no fixed tariff.") if isinstance(value, dict): tz = str(value.get("timezone", "") or "").strip().lower() if tz not in SUPPORTED_TZ: raise ProfileInvalid( f"{option}.timezone is {value.get('timezone')!r}. Only " - f"Europe/Brussels is supported: the shipped image carries no tz " - f"database (see app/price.py), so any other zone could not be " - f"honoured and would be silently treated as Brussels - which is " - f"wrong by an hour for part of the year.") + f"Europe/Brussels is supported.") rows = value.get("periods") if rows is None: raise ProfileInvalid( - f"{option} has no \"periods\" list. Even a fully-fixed " - f"tariff is written as one period covering 00:00-24:00 all days " - f"- one shape for both products, so nothing downstream branches " - f"on which kind of site this is.") + f"{option} has no \"periods\" list. A fixed price is one " + f"period from 00:00 to 24:00 on all days.") else: rows = value diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index e0627fd..da3ad67 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -322,6 +322,7 @@ WHAT IS DELIBERATELY *NOT* REFUSED, because it is untidy rather than unsafe: import logging +from . import messages from .arbitrage import enabled as arbitrage_on from .control import SLEW_RAIL_FRAC, LOOP_TICK_S, PLANT_SETTLE_S from .custom_formula import ( @@ -571,6 +572,17 @@ def _unit_label(opts: dict, index: int) -> str: return f" ({name or f'inverters[{index}]'})" +def S(key: str, where: str = "") -> str: + """A setting as a refusal names it; `where` is `_unit_label()`'s " (name)".""" + return messages.setting(key, where.strip().strip("()")) + + +def _labels(keys, joiner: str = "and") -> str: + """Several settings, each with its key: the config panel files a refusal + under every key it names (`configui.problems_by_field()`).""" + return f" {joiner} ".join(S(k) for k in keys) + + def _roster_problems(opts: dict) -> list[str]: """Rule 9 (CFG-04): the `inverters:` roster, refused where it cannot mean what it says. @@ -625,11 +637,9 @@ def _roster_problems(opts: dict) -> list[str]: if raw is None or raw == "" or raw == []: return problems if not isinstance(raw, (list, tuple)): - return [f"inverters is {type(raw).__name__} {raw!r}, and it must be a " - "LIST of inverter objects - one per inverter, each naming its " - "own name, setpoint_entity and max_w. A single inverter needs " - "no list at all: leave `inverters` empty and the flat " - "setpoint_entity/soc_entity/batt_entity/max_w keys describe it."] + return [f"{S('inverters')} is {type(raw).__name__} {raw!r}, not a list. " + "Add one entry per inverter, or leave it empty for a single " + "inverter."] entries = roster_entries(opts) seen: dict = {} @@ -637,45 +647,31 @@ def _roster_problems(opts: dict) -> list[str]: where = f"inverters[{i}]" if not isinstance(entry, dict): problems.append( - f"{where} is {type(entry).__name__} {entry!r}, and every entry " - "must be an object with at least name, setpoint_entity and " - "max_w.") + f"{where} in the “Inverter list” is {entry!r}. Each entry needs " + "a name, a setpoint entity and an inverter rating.") continue name = str(entry.get("name") or "").strip() if not name: problems.append( - f"{where} has no name. Every inverter needs one: the Store " - "namespaces this unit's SAFETY-02 latch, its heartbeat and its " - "write bookkeeping under it, so two unnamed units would share " - "one namespace and a trip caused by one would latch the other. " - "Any short identifier works - inverter-a, inverter-b, garage.") + f"{where} in the “Inverter list” has no name. Give every " + "inverter a short name, for example inverter-a.") elif name in seen: problems.append( - f"{where} and {seen[name]} are both called {name!r}. The Store " - "keys every per-unit latch under the unit's name, so two units " - "with one name share one SAFETY-02 latch and one heartbeat " - "deadline - a trip caused by either would stop both, and an " - "operator clearing it would clear both. Give them different " - "names.") + f"{where} and {seen[name]} are both called {name!r}. Give every " + "inverter its own name.") else: seen[name] = where who = f"{where} ({name})" if name else where if not str(entry.get("setpoint_entity") or "").strip(): problems.append( - f"{who} has no setpoint_entity, so this add-on cannot command " - "it. It would sit in the roster, take a share of the site " - "target every cycle and deliver none of it, while the status " - "page showed a site running at full strength. Give it the " - "ESPHome number entity that carries ITS setpoint, or remove " - "the entry.") + f"{who} has no {S('setpoint_entity')}, so the add-on cannot " + "control it. Set its ESPHome number entity, or remove the " + "entry.") if _number(entry, "max_w", None) is None or (_number(entry, "max_w", None) or 0) <= 0: problems.append( - f"{who} has no usable max_w (got {entry.get('max_w')!r}). It is " - "the supervised cap on what may be written to THIS inverter, it " - "is not shared with any other unit and it is deliberately not " - "inherited from the flat max_w - a rating borrowed from a " - "sibling is exactly what DEV-02 removed. State this unit's own " - "rating in watts.") + f"{who} has no usable {S('max_w')}: it is " + f"{entry.get('max_w')!r}. Set this inverter's own rating in " + "watts.") # --- (f) and (g): OPT-09's capacity, which is optional but not partial --- stated, blank = [], [] @@ -694,35 +690,21 @@ def _roster_problems(opts: dict) -> list[str]: val = None if val is None or not (val > 0.0): problems.append( - f"{who} has capacity_kwh {raw!r}, which is not a usable number " - "of kilowatt-hours. It is THIS pack's usable capacity and it is " - "read to weight the split of the site target by ENERGY headroom " - "rather than by power rating; a zero or an unparseable value is " - "a pack the split would quietly stop preferring while the box " - "still shows a value. State it in kWh, or leave it empty on " - "every entry.") + f"{who} has {S('capacity_kwh')} {raw!r}, which is not a usable " + "number. Set it in kWh, or leave it empty on every inverter.") else: stated.append(who) if stated and blank: problems.append( - f"capacity_kwh is stated on {', '.join(stated)} and left empty on " - f"{', '.join(blank)}. It is OPTIONAL but it is not PARTIAL: the " - "split weights one pack's energy headroom against another's, so a " - "pack measured in kWh beside a sibling that weighs a dimensionless " - "1.0 is not a comparison - the add-on answers 'no opinion' for the " - "whole roster and the value you filled in changes nothing. State a " - "capacity for every inverter, or for none of them.") + f"{S('capacity_kwh')} is set on {', '.join(stated)} but empty on " + f"{', '.join(blank)}. Set it on every inverter, or on none.") flat_sp = str(opts.get("setpoint_entity") or "").strip() if entries and flat_sp: problems.append( - f"setpoint_entity is set to {flat_sp} AND an inverters list of " - f"{len(entries)} is declared. The flat setpoint_entity/soc_entity/" - "batt_entity/max_w keys are the SINGLE-inverter shape and are not " - "read at all once a roster exists, so this config declares an " - "actuator that nothing will ever write - a site running quietly " - "smaller than its own configuration. Move that inverter into the " - "list as its own entry and clear setpoint_entity.") + f"{S('setpoint_entity')} is set to {flat_sp}, but the " + f"{S('inverters')} has {len(entries)} entries. Move that inverter " + "into the list and clear this setting.") return problems @@ -760,17 +742,14 @@ def validate_unit_ranges(units, *, skip_entity: str = "") -> list[str]: name = getattr(unit, "name", entity) if dev_max is not None and cap > float(dev_max): problems.append( - f"{name}: max_w is {cap:.0f} W but {entity} accepts at most " - f"{float(dev_max):.0f} W - THE DEVICE WINS, so the {cap:.0f} W " - f"configured for this inverter would silently never happen. " - f"Lower this entry's max_w to {float(dev_max):.0f} W or less.") + f"{name}: {S('max_w')} is {cap:.0f} W, but {entity} accepts at " + f"most {float(dev_max):.0f} W. Lower this inverter's rating to " + f"{float(dev_max):.0f} W or less.") elif dev_min is not None and -cap < float(dev_min): problems.append( - f"{name}: max_w is {cap:.0f} W, so this controller may command " - f"{-cap:.0f} W, but {entity} accepts no less than " - f"{float(dev_min):.0f} W - THE DEVICE WINS on the charge side. " - f"Lower this entry's max_w to {abs(float(dev_min)):.0f} W or " - "less.") + f"{name}: {S('max_w')} is {cap:.0f} W, but {entity} accepts no " + f"less than {float(dev_min):.0f} W when charging. Lower this " + f"inverter's rating to {abs(float(dev_min)):.0f} W or less.") return problems @@ -803,11 +782,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] writers = actuator_writers(opts) if not writers: problems.append( - "setpoint_entity is not set, so this add-on has no actuator: every " - "write is a no-op, the device's own rating is never read, and the " - "ESP32 heartbeat that holds off the layer-1 failsafe never happens. " - "It would run, look healthy, and move no energy at all. Set it to " - "the ESPHome number entity that carries the setpoint.") + f"{S('setpoint_entity')} is empty, so the add-on cannot control the " + "inverter. Set it to the ESPHome number entity for the setpoint.") # SAFETY-28. The §1.5 non-goal, graded on the writers rather than on the # count of option keys. Read `actuator_writers()` for why the old check went # green on the very config this one is here to refuse. @@ -822,15 +798,9 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] for actuator, who in sorted(writers.items()): if len(who) > 1: problems.append( - f"{len(who)} configured writers can reach the one actuator " - f"{actuator}: {', '.join(who)}. specs §1.5 makes any " - "configuration in which two writers can reach one actuator a " - "non-goal - two independent setpoints on one inverter is the " - "arbitration problem this add-on refuses to have, and at " - "runtime it is a meter-emulation target being written twice a " - "second by two strategies that cannot see each other. Give " - "each actuator exactly one writer, or point the second one at " - "its own entity.") + f"{len(who)} settings point at the same inverter entity " + f"{actuator}: {', '.join(who)}. Give each inverter its own " + "setpoint entity.") # --- 9. CFG-04's roster, graded BEFORE anything reads a per-unit number -- # ⚠️ FIRST, THOUGH IT IS THE NEWEST RULE. Rules 5 and 6 below now ask the @@ -861,7 +831,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] # has answered; it is not called from here because at startup no device has. max_w = _number(opts, "max_w", 2000.0) if max_w is None: - problems.append(f"max_w {opts.get('max_w')!r} is not a number") + problems.append(f"{S('max_w')} is {opts.get('max_w')!r}, which is not " + "a number. Set it in watts.") # ⚠️ config.yaml's int(100,5000) already blocks this on a real install, so # the check is not for the Supervisor path - it is because # validate_startup_config() is now also sim/inject.py's entry point and can @@ -872,24 +843,19 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] # nonsense config it is. elif max_w <= 0: problems.append( - f"max_w is {max_w:.0f} W and must be positive - it is a magnitude, " - "not a signed setpoint. At or below zero the arbiter's supervised " - f"limit becomes lo={-max_w:.0f} / hi={max_w:.0f}, which is a " - "contradiction it resolves to 0 W, so the controller would look " - "like it was tripping rather than misconfigured.") + f"{S('max_w')} is {max_w:.0f} W. Set it above 0 W.") elif dev_max is not None and max_w > dev_max: problems.append( - f"max_w is {max_w:.0f} W but {opts.get('setpoint_entity') or 'the setpoint device'} accepts at " - f"most {dev_max:.0f} W - THE DEVICE WINS, so the {max_w:.0f} W you " - f"configured would silently never happen. Lower max_w to " - f"{dev_max:.0f} W or less, or point setpoint_entity at a device that " - f"can take {max_w:.0f} W.") + f"{S('max_w')} is {max_w:.0f} W, but " + f"{opts.get('setpoint_entity') or 'the setpoint entity'} accepts at " + f"most {dev_max:.0f} W. Lower the rating to {dev_max:.0f} W or " + "less.") elif dev_min is not None and -max_w < dev_min: problems.append( - f"max_w is {max_w:.0f} W, so this controller may command " - f"{-max_w:.0f} W, but {opts.get('setpoint_entity') or 'the setpoint device'} accepts no less " - f"than {dev_min:.0f} W - THE DEVICE WINS on the charge side. Lower " - f"max_w to {abs(dev_min):.0f} W or less.") + f"{S('max_w')} is {max_w:.0f} W, but " + f"{opts.get('setpoint_entity') or 'the setpoint entity'} accepts no " + f"less than {dev_min:.0f} W when charging. Lower the rating to " + f"{abs(dev_min):.0f} W or less.") # --- 3. a meter that can actually read ----------------------------------- # ⚠️ Not a second copy of these rules - p1.py owns them, because @@ -898,9 +864,10 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] phases = _number(opts, "meter_phases", 1.0) max_age_s = _number(opts, "meter_max_age_s", 30.0) if phases is None or max_age_s is None: - problems.append("meter_phases and meter_max_age_s must both be numbers " - f"(got {opts.get('meter_phases')!r} / " - f"{opts.get('meter_max_age_s')!r})") + problems.append(f"{S('meter_phases')} and {S('meter_max_age_s')} must " + f"both be numbers. They are " + f"{opts.get('meter_phases')!r} and " + f"{opts.get('meter_max_age_s')!r}.") else: problems.extend(validate_meter_options(opts, int(phases), max_age_s)) @@ -921,15 +888,9 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] if (is_enabled(opts) and max_age_s is not None and max_age_s > FIRMWARE_INGEST_VETO_S): problems.append( - f"meter_max_age_s is {max_age_s:.0f} s but the ESP32 firmware vetoes " - f"any P1 sample at {FIRMWARE_INGEST_VETO_S:.0f} s and forces the " - "layer-1 failsafe - THE FIRMWARE WINS, and it wins silently. This " - f"add-on would treat a {max_age_s - 1:.0f} s reading as fresh and " - "keep commanding, while the inverter sat at 0 W with a healthy-" - "looking meter on the status page. Lower meter_max_age_s to " - f"{FIRMWARE_INGEST_VETO_S:.0f} s or less (30 s is the tested value), " - "or rebuild the firmware with a matching max_age_s and update " - "validate.FIRMWARE_INGEST_VETO_S.") + f"{S('meter_max_age_s')} is {max_age_s:.0f} s, but the control " + f"board stops the inverter after {FIRMWARE_INGEST_VETO_S:.0f} s. " + f"Set it to {FIRMWARE_INGEST_VETO_S:.0f} s or less.") # --- 5. a sign watchdog that can actually fire --------------------------- # ⚠️ Strictly `>=`, matching the predicate exactly: watchdog.py tests @@ -956,19 +917,15 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] caps = [cap for _, cap in caps_ix] weakest = min(caps) if caps else None if sign_w is None: - problems.append(f"sign_disagree_w {opts.get('sign_disagree_w')!r} is not a number") + problems.append(f"{S('sign_disagree_w')} is " + f"{opts.get('sign_disagree_w')!r}, which is not a " + "number. Set it back to 300 W.") elif weakest is not None and weakest > 0 and sign_w >= weakest: where = _unit_label(opts, min(caps_ix, key=lambda p: p[1])[0]) problems.append( - f"sign_disagree_w is {sign_w:.0f} W but max_w{where} is " - f"{weakest:.0f} W, so " - "the SAFETY-02 sign-disagreement watchdog can never fire: the " - "arbiter never lets a command exceed max_w, and the watchdog needs " - f"a command over {sign_w:.0f} W. It would sit there reporting " - "'armed' on the status page while being incapable of tripping - the " - f"one runaway failure mode this system has actually observed. Lower " - f"sign_disagree_w below {weakest:.0f} W (300 W is the measured " - "default), or raise max_w.") + f"{S('sign_disagree_w')} is {sign_w:.0f} W, but the " + f"{S('max_w', where)} is {weakest:.0f} W, so this check can never " + f"trip. Lower it below {weakest:.0f} W, or raise the rating.") # ⚠️ AND THE SAME RULE FOR SAFETY-30's PER-UNIT THRESHOLD, WHICH IS A # SEPARATE COMPARISON AND THEREFORE A SEPARATE WAY TO DISARM. It grades a @@ -1014,20 +971,16 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] unit_where = (_unit_label(opts, min(caps_ix, key=lambda p: p[1])[0]) if caps_ix else "") if unit_sign_w is None: - problems.append(f"unit_sign_disagree_w " - f"{opts.get('unit_sign_disagree_w')!r} is not a number") + problems.append(f"{S('unit_sign_disagree_w')} is " + f"{opts.get('unit_sign_disagree_w')!r}, which is not a " + "number. Set it back to " + f"{SIGN_OPTION_DEFAULTS['unit_sign_disagree_w']:.0f} W.") elif weakest is not None and weakest > 0 and unit_sign_w >= weakest: problems.append( - f"unit_sign_disagree_w is {unit_sign_w:.0f} W but max_w{unit_where}" - f" is {weakest:.0f} W, so the SAFETY-30 per-inverter sign-disagreement " - "watchdog can never fire: no inverter is ever commanded past max_w, " - f"and the watchdog needs a command over {unit_sign_w:.0f} W. At two " - "inverters that is the guard which catches a unit doing the " - "OPPOSITE of what it was told while its sibling covers for it at " - "the meter - the case the site-level watchdog is structurally " - f"blind to. Lower unit_sign_disagree_w below {weakest:.0f} W " - f"({SIGN_OPTION_DEFAULTS['unit_sign_disagree_w']:.0f} W is the " - "measured default), or raise max_w.") + f"{S('unit_sign_disagree_w')} is {unit_sign_w:.0f} W, but the " + f"{S('max_w', unit_where)} is {weakest:.0f} W, so this check can " + f"never trip. Lower it below {weakest:.0f} W, or raise the " + "rating.") # --- 6. a maintenance charge the ceiling can actually accommodate -------- # ⚠️ Strictly `>`, matching the arbiter exactly. The shaping is @@ -1100,18 +1053,14 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] maint_where = _unit_label(opts, maint_index) if charge_w is None: problems.append( - f"maintenance_charge_w {opts.get('maintenance_charge_w')!r} is not a number") + f"{S('maintenance_charge_w')} is " + f"{opts.get('maintenance_charge_w')!r}, which is not a number. Set " + "it in watts.") elif maint_cap is not None and maint_cap > 0 and charge_w > maint_cap: problems.append( - f"maintenance_charge_w is {charge_w:.0f} W but max_w{maint_where} is " - f"{maint_cap:.0f} W, so a maintenance charge in a cheap window can " - "never happen: the shaping asks the arbiter for at most " - f"{-charge_w:.0f} W while the supervised limit allows no less than " - f"{-maint_cap:.0f} W, which is a contradiction it resolves to 0 W - " - "THE CEILING WINS, and what you would see is an ARBITER " - "CONTRADICTION line that reads like a bug rather than like these " - f"two numbers. Lower maintenance_charge_w to {maint_cap:.0f} W or " - f"less, or raise max_w to at least {charge_w:.0f} W.") + f"{S('maintenance_charge_w')} is {charge_w:.0f} W, but the " + f"{S('max_w', maint_where)} is {maint_cap:.0f} W, so the monthly " + f"recharge cannot run. Lower it to {maint_cap:.0f} W or less.") # --- 10. a slew rate the plant can actually follow ----------------------- # ⚠️ SAFETY-39. The one rule here that grades a RATIO rather than a @@ -1140,34 +1089,19 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] slew_w = _number(opts, "slew_w", 0.0) rail = site_rail_w(opts) if slew_w is None: - problems.append(f"slew_w {opts.get('slew_w')!r} is not a number") + problems.append(f"{S('slew_w')} is {opts.get('slew_w')!r}, which is " + "not a number. Set it to 0 to follow the inverter " + "rating.") elif slew_w < 0: problems.append( - f"slew_w is {slew_w:.0f} W and must not be negative - it is a " - "magnitude, and 0 means 'follow max_w' (the recommended setting).") + f"{S('slew_w')} is {slew_w:.0f} W and cannot be negative. Set it to " + "0 to follow the inverter rating.") elif slew_w and rail is not None and rail > 0: bound = SLEW_RAIL_FRAC * rail if slew_w > bound + 1.0: - ticks = rail / slew_w problems.append( - f"slew_w is {slew_w:.0f} W against a site rail of {rail:.0f} W, " - f"so the loop crosses its whole output range in {ticks:.1f} " - f"cycles - {ticks * LOOP_TICK_S:.0f} s at the {LOOP_TICK_S:.0f} s " - f"tick this site was measured running - while the plant takes " - f"{PLANT_SETTLE_S:.0f} s to settle (goodwe/NOTES.md §5.10, a " - "1.78 kW step). The controller would command its entire range " - "before it could observe its answer to the first step, which is " - "not a slow loop, it is a loop that MANUFACTURES the error it " - "then chases: measured on this system 2026-09-05, a 3.4 kW " - "export drove the setpoint 380 -> 5000 W in five ticks, the " - "battery to -5154 W past a 5000 VA rating, and the grid from " - "3.4 kW of export to 2.8 kW of import. The stated limit - the " - "command moves at most slew_w per cycle, so it cannot jump " - "ahead of the inverter - is untrue at this rail; THE PLANT " - f"WINS, and it has no status row. Set slew_w to 0, which means " - f"'follow the rail' and resolves to {bound:.0f} W here and " - "moves on its own if the rail does, or write a value at or " - f"below {bound:.0f} W. Lower is always accepted.") + f"{S('slew_w')} is {slew_w:.0f} W, too fast for a {rail:.0f} W " + f"site. Set it to 0 or to at most {bound:.0f} W.") # --- 7. two price sources on one site ------------------------------------ problems.extend(_price_problems(opts)) @@ -1198,22 +1132,15 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] where = _unit_label(opts, _ix) if soc_floor is None or bms_floor is None: problems.append( - f"peak_soc_floor and bms_soc_floor{where} must both be numbers " - f"(got {opts.get('peak_soc_floor')!r} / {_raw!r})") + f"{S('peak_soc_floor')} and {S('bms_soc_floor', where)} must " + f"both be numbers. They are {opts.get('peak_soc_floor')!r} and " + f"{_raw!r}.") elif soc_floor <= bms_floor: problems.append( - f"peak_soc_floor is {soc_floor:.0f} % but the pack's own cut-out " - f"(bms_soc_floor{where}) is {bms_floor:.0f} %, so SAFETY-07's forced " - "discharge has no EMS-side bound at all - THE BMS WINS, and it is " - "the pack's protection rather than yours. The guard would report a " - "SoC floor on its status page while being incapable of ever being " - "the thing that stops the discharge, and the symptom of that is a " - "battery repeatedly sitting at the BMS limit with no record of why " - f"- which looks exactly like the SoC drift the maintenance cycle " - f"exists to correct. Raise peak_soc_floor above {bms_floor:.0f} % " - f"(the shipped default is " - f"{PEAK_OPTION_DEFAULTS['peak_soc_floor']:.0f} %), or correct " - f"bms_soc_floor{where} if it does not match this pack.") + f"{S('peak_soc_floor')} is {soc_floor:.0f} %, not above the " + f"{S('bms_soc_floor', where)} of {bms_floor:.0f} %. Raise the " + f"reserve above {bms_floor:.0f} %, or correct the cut-out " + "level.") # --- warnings: real, but not worth refusing over ------------------------- integ = opts.get("integrator_max_w") @@ -1306,43 +1233,19 @@ def _price_problems(opts: dict) -> list[str]: # fall back to, the site has had no tariff at all - a worse state, and # one this message must not paper over. been_running = ( - f"the static day/night tariff in static_profile" + f"the {S('static_profile')}" if str(opts.get("static_profile", "") or "").strip() - else "NOTHING AT ALL - static_profile is empty too, so there was " - "no tariff to fall back to either") + else "no tariff at all") problems.append( - f"price_provider is {pid!r}, which WAS a shipped plugin and has " - f"been WITHDRAWN (TARIFF-07). This is not a typo and you did not " - f"mistype it - the add-on offered this id, accepted it, and has " - f"said nothing at every startup since. " - f"⚠️ IT HAS NEVER FETCHED A PRICE, HERE OR ANYWHERE: " - f"{RETIRED_PROVIDERS[pid]}. Every fetch it ever made ended in " - f"SourceUnavailable, and §11.4 turns that into a SILENT fall back " - f"- so what this site has actually been running since the day the " - f"id was set is {been_running}. Nothing you could see would have " - f"differed from a working provider that simply never found a cheap " - f"hour, which is why you are being told now rather than left on " - f"it. WHAT TO DO: set price_provider to 'generic_dayahead' for the " - f"wholesale EPEX BE day-ahead curve, to which the add-on adds your " - f"price_markup_eur_kwh and price_taxes_eur_kwh - that APPROXIMATES " - f"a Belgian dynamic tariff and cannot reproduce your supplier's " - f"B x spot + A formula, so the level will be off even when the " - f"shape is right; or 'manual_csv' to enter all-in prices you " - f"compute yourself; or 'off' to run on static_profile " - f"deliberately. There is deliberately NO alias to your old " - f"supplier: aliasing would need your contract's own two " - f"coefficients, which live behind your klantenzone login and are " - f"in no public index, so the add-on would have to invent the " - f"numbers it prices your battery against.") + f"{S('price_provider')} is {pid!r}, which was withdrawn and never " + f"fetched a price. This site ran on {been_running}. Choose " + "'generic_dayahead', 'manual_csv' or 'off'.") return problems # nothing below can be judged against a dead id if pid != "off" and pid not in PROVIDERS: problems.append( - f"price_provider is {pid!r}, which is not a shipped plugin. The " - f"ids that exist are: off, {', '.join(sorted(PROVIDERS))}. " - "Refused rather than defaulted, per the §14 warning box - a " - "silent fall back to 'off' would look exactly like a working " - "provider that happens never to find a cheap hour.") + f"{S('price_provider')} is {pid!r}, which does not exist. Choose " + f"one of: off, {', '.join(sorted(PROVIDERS))}.") return problems # nothing below can be judged against an unknown id # ⚠️ THE HA-SIDE OVERLAP THE PM TOLD US TO DECIDE ABOUT, DECIDED HERE. @@ -1386,19 +1289,10 @@ def _price_problems(opts: dict) -> list[str]: if str(opts.get(k, "") or "").strip()] if pid != "off" and ha_price: problems.append( - f"price_provider is {pid!r} AND {' and '.join(ha_price)} " - f"{'is' if len(ha_price) == 1 else 'are'} set, which is two price " - "sources on one site. THE HOME ASSISTANT ENTITIES WIN: they are " - "what main.py reduces to the `cheap` flag the maintenance cycle " - "reads, and read_inputs() never looks at the other source once " - "they are set. The provider series is consumed - " - "app/static_tariff.py builds a tariff plan and an arbitrage " - "verdict, and app/arbitrage.py trades on it off a background " - "refresh - but the `cheap` flag those entities own is a separate " - "decision they would silently keep. Clear " - "price_now_entity and price_avg_entity to use the " - f"{pid!r} plugin, or set price_provider to 'off' to keep the " - "Home Assistant sensors.") + f"{S('price_provider')} is {pid!r}, but {_labels(ha_price)} " + f"{'is' if len(ha_price) == 1 else 'are'} also set and would win. " + f"Clear {'it' if len(ha_price) == 1 else 'them'}, or set the price " + "source to 'off'.") # ⚠️ THE SAME RULE FOR THE SOURCE TARIFF-03 ADDED, AND THIS ONE IS A LIVE # CONFLICT RATHER THAN A LATENT ONE. main.py's read_inputs() takes `cheap` @@ -1407,14 +1301,9 @@ def _price_problems(opts: dict) -> list[str]: # day/night tariff has no way to see that it lost. if ha_price and str(opts.get("static_profile", "") or "").strip(): problems.append( - f"static_profile is set AND {' and '.join(ha_price)} " - f"{'is' if len(ha_price) == 1 else 'are'} set, which is two " - "tariff sources feeding one cheap-window flag. THE HOME ASSISTANT " - "ENTITIES WIN: main.py reads them first and never looks at the " - "static profile, so the day/night tariff you typed would decide " - "nothing and nothing would say so. Clear price_now_entity and " - "price_avg_entity to use static_profile, or clear static_profile " - "to keep the Home Assistant sensors.") + f"{S('static_profile')} and {_labels(ha_price)} are both set, and " + "only the Home Assistant price entities would count. Clear one of " + "the two.") # ⚠️ THE PROFILE ITSELF, PARSED AT STARTUP RATHER THAN AT 02:00. A profile # that does not tile the day has hours with no price, and the only ways to @@ -1427,7 +1316,7 @@ def _price_problems(opts: dict) -> list[str]: profile = parse_static_profile(raw_profile) except ProfileInvalid as e: profile = None - problems.append(f"static_profile cannot be used: {e}") + problems.append(f"“{messages.LABELS['static_profile']}” cannot be used. {e}") if profile is not None and profile.product is not None \ and len(set(profile.prices)) == 1: _LOG.info( @@ -1452,7 +1341,7 @@ def _price_problems(opts: dict) -> list[str]: try: taxes_table = parse_taxes_profile(raw_taxes_profile) except ProfileInvalid as e: - problems.append(f"{TAXES_PROFILE_OPTION} cannot be used: {e}") + problems.append(f"“{messages.LABELS[TAXES_PROFILE_OPTION]}” cannot be used. {e}") if taxes_table is not None: # ⚠️ TWO WRITERS OF ONE QUANTITY, ONE OF WHICH SILENTLY LOSES - the @@ -1482,21 +1371,13 @@ def _price_problems(opts: dict) -> list[str]: PRICE_OPTION_DEFAULTS["price_taxes_eur_kwh"]) shipped = PRICE_OPTION_DEFAULTS["price_taxes_eur_kwh"] untouched = (shipped,) + tuple(SUPERSEDED_TAXES_DEFAULTS_EUR_KWH) - superseded = ", ".join( - str(u) for u in SUPERSEDED_TAXES_DEFAULTS_EUR_KWH) if scalar is not None \ and not any(abs(scalar - u) <= 1e-12 for u in untouched): problems.append( - f"{TAXES_PROFILE_OPTION} is set AND price_taxes_eur_kwh is " - f"{scalar} rather than its shipped {shipped}. THE TABLE WINS: " - f"the add-on reads the per-period figures and never looks at " - f"the scalar, so the number you typed there would decide " - f"nothing and nothing would say so. Set price_taxes_eur_kwh " - f"back to {shipped}, or clear {TAXES_PROFILE_OPTION} to keep " - f"the flat figure. (A scalar still sitting on a SUPERSEDED " - f"default - {superseded} - is accepted and NOT refused: " - f"that is a number this add-on wrote into your options " - f"blob, not one you typed.)") + f"{S(TAXES_PROFILE_OPTION)} is set, so " + f"{S('price_taxes_eur_kwh')} is not used, but it reads {scalar} " + f"instead of {shipped}. Set it back to {shipped}, or clear the " + "table.") # ⚠️ THE UNITS RUNG, AND IT IS A SECOND QUANTITY RATHER THAN A # RESTATEMENT. Every Belgian DSO prints these bands in c EUR/kWh @@ -1511,13 +1392,8 @@ def _price_problems(opts: dict) -> list[str]: if abs(p.eur_per_kwh) >= 1.0}) if steep: problems.append( - f"{TAXES_PROFILE_OPTION} carries {steep} EUR/kWh. Belgian " - f"levies and distribution run about 0.05-0.25 EUR/kWh, so " - f"these are almost certainly the CENT figures off the tariff " - f"card (ORES prints `13,27`, which is 0.1327 EUR/kWh) typed " - f"without the conversion - a factor of 100 that would make " - f"every hour look like an emergency. Divide by 100, or clear " - f"the option.") + f"{S(TAXES_PROFILE_OPTION)} has {steep} EUR/kWh, which looks " + "like cents. Divide the figures by 100, or clear this setting.") negative = sorted({p.eur_per_kwh for p in taxes_table.periods if p.eur_per_kwh < 0}) if negative: @@ -1567,25 +1443,15 @@ def _price_problems(opts: dict) -> list[str]: or isinstance(raw_formula, dict) if pid == "custom_formula" and not has_formula: problems.append( - "price_provider is 'custom_formula' but price_formula is empty, " - "so the add-on has no coefficients to price anything with. Every " - "fetch would return no-price-data and §11.4 would fall back " - "silently - which is the shape of defect this provider exists to " - "remove, arrived at by leaving one field blank. Copy the " - "Tariefformule line off your supplier's tariff card, e.g. " - "{\"index\":\"epex_be\",\"resolution\":\"hourly\"," - "\"factor\":0.102,\"offset\":1.00," - "\"units\":\"c_eur_per_kwh\",\"vat_pct\":6," - "\"card\":{\"month\":\"2026-09\"," - "\"index_eur_per_mwh\":133.9905,\"expect_incl_vat\":15.55}} " - "- see DOCS.md. Or set price_provider to 'generic_dayahead' for " - "the wholesale curve with a flat markup.") + f"{S('price_provider')} is 'custom_formula', but " + f"{S('price_formula')} is empty. Copy the formula from your " + "supplier's tariff card, or choose 'generic_dayahead'.") elif has_formula: try: spec = parse_price_formula(raw_formula) except FormulaInvalid as e: spec = None - problems.append(f"price_formula cannot be used: {e}") + problems.append(f"“{messages.LABELS['price_formula']}” cannot be used. {e}") if spec is not None and pid != "custom_formula": # ⚠️ A WARNING AND NOT A REFUSAL. This is not two price sources # fighting over one flag - it is one that is simply not wired to @@ -1639,7 +1505,7 @@ def _price_problems(opts: dict) -> list[str]: xspec = parse_export_formula(raw_export) except FormulaInvalid as e: xspec = None - problems.append(f"{EXPORT_FORMULA_OPTION} cannot be used: {e}") + problems.append(f"“{messages.LABELS[EXPORT_FORMULA_OPTION]}” cannot be used. {e}") if xspec is not None: # ⚠️ THE 6% ASYMMETRY, PRINTED RATHER THAN ASSUMED. The two legs # carry INDEPENDENT `vat_pct` values and a Belgian site's are 6 and @@ -1732,62 +1598,39 @@ def _price_problems(opts: dict) -> list[str]: PRICE_OPTION_DEFAULTS["cycle_cost_threshold_eur"]) if thresh is None or thresh < 0: problems.append( - f"cycle_cost_threshold_eur is " - f"{opts.get('cycle_cost_threshold_eur')!r} and must be a " - f"non-negative number of EUR/kWh - it is what one round trip COSTS " - f"(§10.1). A negative threshold is one that every spread clears, " - f"including a spread of nothing, which is arbitrage with the brake " - f"removed rather than arbitrage tuned aggressively.") + f"{S('cycle_cost_threshold_eur')} is " + f"{opts.get('cycle_cost_threshold_eur')!r}. Set it to 0 or more, " + "in EUR/kWh.") if arbitrage_on(opts): if pid == "off" and not str(opts.get("static_profile", "") or "").strip(): problems.append( - "arbitrage_enabled is on but price_provider is 'off' and " - "static_profile is empty, so this site has NO PRICES AT ALL. " - "§10.1's priority 3 is 'charge cheap, discharge expensive' and " - "there is nothing here to tell cheap from expensive, so the " - "strategy would refuse on every cycle forever while the " - "configuration said it was running. Configure a price_provider " - "or a static_profile, or turn arbitrage_enabled off.") + f"{S('arbitrage_enabled')} is on, but the site has no prices. " + f"Set {_labels(['price_provider', 'static_profile'], 'or')}, " + "or turn trading off.") if not is_enabled(opts): problems.append( - "arbitrage_enabled is on but meter_source is 'off', so there " - "is no P1 telegram stream, the capacity-tariff peak guard " - "never runs, and nothing measures the 15-minute average this " - "strategy's charging would land in. §9.1 gives peak shaving " - "priority over arbitrage; an unmeasured peak cannot be shaved, " - "so arbitrage would be deliberately creating the billed " - "quantity with the one guard that limits it switched off. " - "app/arbitrage.py refuses to trade in that state anyway - this " - "refuses the configuration that asks it to. Set meter_source, " - "or turn arbitrage_enabled off.") + f"{S('arbitrage_enabled')} is on, but no meter is set in " + f"{S('meter_source')}. Choose a meter, or turn trading off.") floor = _number(opts, "arbitrage_soc_floor", PRICE_OPTION_DEFAULTS["arbitrage_soc_floor"]) ceiling = _number(opts, "arbitrage_soc_ceiling", PRICE_OPTION_DEFAULTS["arbitrage_soc_ceiling"]) if floor is None or ceiling is None: problems.append( - f"arbitrage_soc_floor {opts.get('arbitrage_soc_floor')!r} and " - f"arbitrage_soc_ceiling {opts.get('arbitrage_soc_ceiling')!r} " - f"must both be numbers - they are percentages of pack charge.") + f"{S('arbitrage_soc_floor')} and {S('arbitrage_soc_ceiling')} " + "must both be numbers, in %.") elif floor >= ceiling: problems.append( - f"arbitrage_soc_floor is {floor:g} % and arbitrage_soc_ceiling " - f"is {ceiling:g} %, so there is no band left between them: " - f"every state of charge is either at or under the floor (no " - f"discharge) or at or over the ceiling (no charge), and the " - f"strategy can never act. The floor is the reserve it may not " - f"spend and the ceiling is the headroom it may not overfill, " - f"so the floor must be the SMALLER number.") + f"{S('arbitrage_soc_floor')} is {floor:g} %, not below " + f"{S('arbitrage_soc_ceiling')} at {ceiling:g} %. Make the lower " + "limit the smaller number.") if pid == "manual_csv" and not str(opts.get("price_csv_path", "") or "").strip(): problems.append( - "price_provider is 'manual_csv' but price_csv_path is empty, so " - "the offline fallback has no file to read. Every fetch would " - "return no-price-data with a filesystem error as its reason - " - "which is §11.4 behaviour arrived at by accident rather than by " - "configuration. Point it at the CSV, or set price_provider to " - "'off', which says the same thing on purpose.") + f"{S('price_provider')} is 'manual_csv', but " + f"{S('price_csv_path')} is empty. Set the path to the CSV file, or " + "choose 'off'.") return problems diff --git a/goodwe_controller/test_arbitrage.py b/goodwe_controller/test_arbitrage.py index 89dd3f3..714839c 100644 --- a/goodwe_controller/test_arbitrage.py +++ b/goodwe_controller/test_arbitrage.py @@ -2609,7 +2609,7 @@ check("arbitrage on with NO price source at all is refused - a strategy that " "must refuse on every cycle forever looks exactly like one that is " "running and finding nothing", why(validate_startup_config(vbase(arbitrage_enabled=True, **P1_ON), - -5000, 5000), "NO PRICES AT ALL")) + -5000, 5000), "the site has no prices")) check("arbitrage on with meter_source off is refused - §9.1 puts peak shaving " "above arbitrage and an unmeasured peak cannot be shaved", why(validate_startup_config( @@ -2620,7 +2620,7 @@ check("a floor at or above the ceiling is refused - there is no band left " why(validate_startup_config( vbase(arbitrage_enabled=True, price_provider="generic_dayahead", arbitrage_soc_floor=90, arbitrage_soc_ceiling=90, **P1_ON), - -5000, 5000), "no band left")) + -5000, 5000), "Make the lower limit the smaller number")) check("...and the same numbers the right way round start", validate_startup_config( vbase(arbitrage_enabled=True, price_provider="generic_dayahead", @@ -2629,7 +2629,7 @@ check("...and the same numbers the right way round start", check("a NEGATIVE cycle_cost_threshold_eur is refused even with arbitrage OFF " "- it is a cost, and a negative one is a threshold every spread clears", why(validate_startup_config(vbase(cycle_cost_threshold_eur=-0.01), - -5000, 5000), "non-negative") + -5000, 5000), "Set it to 0 or more") and raises(lambda: threshold_eur_kwh({"cycle_cost_threshold_eur": -1}), ValueError)) # Rule 7's wording, which OPT-04 had to update because it named what main.py diff --git a/goodwe_controller/test_inverter.py b/goodwe_controller/test_inverter.py index d9aae7c..8fdc26a 100644 --- a/goodwe_controller/test_inverter.py +++ b/goodwe_controller/test_inverter.py @@ -1629,7 +1629,7 @@ check("⚠️ AC 5: two inverters naming the SAME setpoint_entity are REFUSED. " "life of this add-on because the schema had exactly one such key; this " "is the first configuration in which it is expressible, and it is the " "first time that guarantee has had to be a check", - _why(_p_same, "one actuator") and _why(_p_same, "number.sp_a")) + _why(_p_same, "point at the same inverter entity") and _why(_p_same, "number.sp_a")) check("...and case-folded, so the hazard cannot be smuggled past on " "NUMBER.SP_A versus number.sp_a - which is exactly how it would be " "written by someone copying an entity id out of the HA UI", @@ -1653,7 +1653,7 @@ check("a flat setpoint_entity left set BESIDE a declared roster is refused. It " "names an actuator the roster does not, so nothing would ever write it - " "a site running quietly smaller than its own configuration, which is the " "'silently a different config' outcome this card ranks below a refusal", - _why(_p_flat, "AND an inverters list")) + _why(_p_flat, "but the “Inverter list” (inverters) has")) _p_dup = validate_startup_config(_opts(setpoint_entity="", inverters=[ dict(name="twin", setpoint_entity="number.sp_a", max_w=A_RATING), dict(name="twin", setpoint_entity="number.sp_b", @@ -1666,13 +1666,14 @@ for _what, _bad, _needle in ( ("with no name at all", dict(setpoint_entity="number.sp_b", max_w=3000), "has no name"), ("this controller cannot command", - dict(name="inverter-b", max_w=3000), "has no setpoint_entity"), + dict(name="inverter-b", max_w=3000), + "has no “Inverter setpoint entity” (setpoint_entity)"), ("with no rating", dict(name="inverter-b", setpoint_entity="number.sp_b"), - "no usable max_w"), + "no usable “Inverter rating” (max_w)"), ("whose rating is not a number", dict(name="inverter-b", setpoint_entity="number.sp_b", max_w="lots"), - "no usable max_w")): + "no usable “Inverter rating” (max_w)")): check(f"an entry {_what} is refused, and the refusal says which entry and " f"which key ({_needle!r}) rather than that something is wrong", _why(validate_startup_config(_opts(setpoint_entity="", @@ -1680,7 +1681,7 @@ for _what, _bad, _needle in ( check("`inverters` that is not a list at all is refused with the shape it " "should have been, rather than crashing inside build_roster()", _why(validate_startup_config(_opts(inverters="number.sp_b")), - "must be a\nLIST".replace("\n", " "))) + "(inverters) is str 'number.sp_b', not a list")) # --- the permissive readers INSIDE validate.py -------------------------------- # ⚠️ RUN BOTH WAYS, WHICH IS MUTATION.md's RULE. A check that only asserts the @@ -1738,8 +1739,8 @@ check("the fixture actually desynchronises the two lists, or the two checks " check("⚠️ RULE 5 NAMES THE UNIT THE NUMBER CAME OFF. The weakest cap is " "inverter-c's 1000 W; it sits at caps index 1, and `_unit_label(opts, 1)` " "is inverter-B. The refusal says inverter-c", - _why(_p_skew, "max_w (inverter-c) is 1000 W") - and not _why(_p_skew, "max_w (inverter-b) is 1000 W")) + _why(_p_skew, "(max_w) for inverter-c is 1000 W") + and not _why(_p_skew, "(max_w) for inverter-b is 1000 W")) # ⚠️ MAINT-05 MOVED RULE 6's SUBJECT, AND THIS CHECK MOVED WITH IT. It used to # assert the refusal named inverter-b, because rule 6 graded the FIRST entry # with a usable cap - `Controller.maint_unit` was `inverters[0]` and the shaping @@ -1753,15 +1754,15 @@ check("⚠️ RULE 6 TOO, AND SINCE MAINT-05 IT IS THE WEAKEST PACK IT NAMES. " "inverter-c's 1000 W sits at caps index 1, and `_unit_label(opts, 1)` is " "inverter-B - so a caps index leaking into a roster index would say " "inverter-b here. The refusal says inverter-c, with inverter-c's number", - _why(_p_skew, "maintenance_charge_w is 3000 W but max_w (inverter-c) is " - "1000 W") - and not _why(_p_skew, "maintenance_charge_w is 3000 W but max_w " - "(inverter-b)")) + _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for " + "inverter-c is 1000 W") + and not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for " + "inverter-b")) check("...and it is no longer graded against the FIRST usable cap at all, which " "is the behaviour change MAINT-05 makes here: inverter-b's 2000 W was the " "pre-card answer and appears nowhere in the maintenance refusal now", - not _why(_p_skew, "maintenance_charge_w is 3000 W but max_w " - "(inverter-b) is 2000 W")) + not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for " + "inverter-b is 2000 W")) check("...and the counterfactual, so this is not a check that would pass on a " "validator that named nothing: the OLD expressions still evaluate, on " "this same config, to the wrong names", @@ -1784,7 +1785,7 @@ check("⚠️ A READER THAT SILENTLY PINNED INVERTER #1, IN main.py. run_control "unit's max_w was graded against the device it is written to, and the " "skip was silent. The per-unit form catches B against B's own ESPHome", len(_p_rng) == 1 and _why(_p_rng, "inverter-b") - and _why(_p_rng, "THE DEVICE WINS")) + and _why(_p_rng, "Lower this inverter's rating to")) check("...and it says INVERTER-B, not 'the setpoint device' - a site with " "three inverters and one bad rating needs to be told which one", _why(_p_rng, "number.sp_b") and not _why(_p_rng, "inverter-a")) diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index fd94efd..66eb2a6 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -413,6 +413,8 @@ def problems_of(kind, text): p = [] if len(words(text)) > lim: p.append(f"over {lim} words ({len(words(text))})") + if kind != "log" and ";" in text: # logs are phase 2d + p.append("semicolon") return p + text_problems(text, keys=keys, entities=ents) @@ -424,7 +426,7 @@ ALLOW_FILE = HERE / "ux08_allowlist.txt" # The allowlist may never grow. The test demands the list be exactly this long, # so deleting lines means lowering this number in the same change, and adding # one means raising it where a reviewer sees it. -ALLOWLIST_MAX = 167 +ALLOWLIST_MAX = 43 def read_allowlist(path): @@ -527,6 +529,32 @@ check(f"no allowlist entry is stale, so the list only shrinks " check(f"the allowlist is exactly its cap ({len(allow)} entries, cap " f"{ALLOWLIST_MAX}): lower the cap when you delete lines", len(allow) == ALLOWLIST_MAX) + +# A refusal names a setting by its Configuration-tab label (UX-08 2c). The +# catalogue's labels must be the en.yaml names without group prefix and unit. +_TR = TL.parse_translation_file(HERE / "translations" / "en.yaml")["configuration"] + + +def _label_stems(key): + names = [c[key]["name"] for c in (_TR, _TR["inverters"]["fields"]) + if isinstance(c.get(key), dict)] + out = set() + for n in names: + n = n.split("·")[-1].strip() + while re.search(r"\s*\([^()]*\)$", n): + n = re.sub(r"\s*\([^()]*\)$", "", n) + out.add(n) + return out + + +_drift = sorted(f"{k}: {v!r}" for k, v in messages.LABELS.items() + if v not in _label_stems(k)) +check(f"every label a refusal quotes is the setting's name in en.yaml " + f"(drifted: {_drift})", not _drift) +check("...and a refusal quotes the label and then the key, so the config " + "panel still files it under that setting", + messages.setting("max_w", "inverter-b") + == "“Inverter rating” (max_w) for inverter-b") print(f"CI: UX-08 allowlist {len(allow)} entries " + ", ".join(f"{k} {sum(1 for x in allow if x.startswith(k + ' '))}" for k in LIMITS)) @@ -567,6 +595,11 @@ check("an entity id in an alarm is refused", bool(body_problems( "Check sensor.battery_power now.", messages.ALARM))) check("...but allowed in a refusal", not problems_of( "refusal", "Check sensor.battery_power in Developer Tools.")) +check("a semicolon in a refusal or an option text is refused", + bool(problems_of("refusal", "It is wrong; fix it.")) + and bool(problems_of("option-desc", "It is wrong; fix it."))) +check("a label that drifted from en.yaml is caught", + "Inverter power" not in _label_stems("max_w")) check("an option key in an alarm is refused", bool(body_problems( "Lower peak_soc_floor.", messages.ALARM))) check("a message that lost its Details line is refused", diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 65b5bee..08e5bc5 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2019,12 +2019,13 @@ check("...and so is a floor EXACTLY AT it, which is the interesting case: equal "it leaves none", len(equal) == 1) check("...while one point above is accepted, so this refuses the disarmed case " "only and not 'close to the limit'", above == []) -check("...and the refusal NAMES BOTH NUMBERS and the shipped default, so the " - "operator can act on it without reading the source", +# UX-08 2c: the shipped default left the sentence (it is on the option's +# description). The two numbers the operator acts on stay. +check("...and the refusal NAMES BOTH NUMBERS, so the operator can act on it " + "without reading the source", len(below) == 1 and f"{BMS_FLOOR:.0f} %" in below[0] - and f"{BMS_FLOOR - 5:.0f} %" in below[0] - and f"{PEAK_OPTION_DEFAULTS['peak_soc_floor']:.0f} %" in below[0]) + and f"{BMS_FLOOR - 5:.0f} %" in below[0]) check("...and a non-numeric floor is refused rather than defaulted, for the " "reason every read in this file is: a value that cannot be parsed is not " "an observation of anything", @@ -3894,13 +3895,12 @@ check("⚠️ AC 3. Rule 8 grades EVERY unit: a roster whose SECOND pack has a " "inverter-b. Under the flat key this config STARTED, and the guard would " "then have commanded a forced discharge that pack B's BMS - not the " "operator's floor - is the thing that stops", - len(_r_second) == 1 and "(inverter-b)" in _msg(_r_second) - and "(inverter-a)" not in _msg(_r_second)) -check("...and it names BOTH numbers and the shipped default, so the operator " - "can act on it without reading the source", + len(_r_second) == 1 and " for inverter-b" in _msg(_r_second) + and " for inverter-a" not in _msg(_r_second)) +check("...and it names BOTH numbers, so the operator can act on it without " + "reading the source", f"{B_PACK_FLOOR_DEEP_SIM:.0f} %" in _msg(_r_second) - and f"{SOC_FLOOR:.0f} %" in _msg(_r_second) - and f"{PEAK_OPTION_DEFAULTS['peak_soc_floor']:.0f} %" in _msg(_r_second)) + and f"{SOC_FLOOR:.0f} %" in _msg(_r_second)) # The mirror. A grader hardwired to index 1 - or one that reports the LAST # offender - passes the check above and fails this one. _r_first = rule8(validate_startup_config( @@ -3908,8 +3908,8 @@ _r_first = rule8(validate_startup_config( check("...and with the SAME two numbers in the OTHER ORDER it names " "inverter-a instead. The pair of checks is what makes this an index " "check: one of them goes red for any hardwired position", - len(_r_first) == 1 and "(inverter-a)" in _msg(_r_first) - and "(inverter-b)" not in _msg(_r_first)) + len(_r_first) == 1 and " for inverter-a" in _msg(_r_first) + and " for inverter-b" not in _msg(_r_first)) # And both at once, because a loop that `break`s on the first offender reports # one refusal for a config with two. _r_both = rule8(validate_startup_config( @@ -3917,8 +3917,8 @@ _r_both = rule8(validate_startup_config( check("...and a roster where BOTH packs offend is refused TWICE, once per unit " "and each naming its own - so an operator with two wrong packs is not " "told about one of them and left to discover the other on the next boot", - len(_r_both) == 2 and "(inverter-a)" in _msg(_r_both, 0) - and "(inverter-b)" in _msg(_r_both, 1)) + len(_r_both) == 2 and " for inverter-a" in _msg(_r_both, 0) + and " for inverter-b" in _msg(_r_both, 1)) # A missing per-entry cut-out is refused BY NAME rather than defaulted. _r_missing = rule8(validate_startup_config(_roster32(A_PACK_FLOOR, None))) print(f" entry with no bms_soc_floor -> {_msg(_r_missing)[:120] or '(none)'}...") @@ -3927,7 +3927,7 @@ check("...and an entry that states NO `bms_soc_floor` is refused by name rather "cut-out this add-on invented for a battery it has not been told about, " "which is the same wrong number the flat key produced. See " "DECISIONS/SAFETY-32-per-pack-bms-floor.md", - len(_r_missing) == 1 and "(inverter-b)" in _msg(_r_missing) + len(_r_missing) == 1 and " for inverter-b" in _msg(_r_missing) and "must both be numbers" in _msg(_r_missing)) # --- 12f. nothing is inherited, with the flat key SET AND DIFFERENT ---------- @@ -5601,7 +5601,7 @@ MUT.append(("an unstated per-entry cut-out defaulted to 0 %", # 19. rule 8 grading only the first unit, i.e. the flat rule left in place. MUT.append(("rule 8 grading only the FIRST unit", - _r_second != [] and "(inverter-b)" in _msg(_r_second), + _r_second != [] and " for inverter-b" in _msg(_r_second), "part 12e: 'a roster whose SECOND pack has a cut-out above " "peak_soc_floor is refused'. ⚠️ The offender is the SECOND entry " "for exactly this row")) @@ -5609,7 +5609,7 @@ MUT.append(("rule 8 grading only the FIRST unit", # 20. rule 8 naming a hardwired unit - CFG-04's rule 5/6 bug, which is why # `unit_bms_floors_indexed()` carries the roster index. MUT.append(("rule 8's refusal naming a hardwired inverter", - "(inverter-b)" in _msg(_r_second) and "(inverter-a)" in _msg(_r_first), + " for inverter-b" in _msg(_r_second) and " for inverter-a" in _msg(_r_first), "part 12e: the two orders. Either hardwired index passes one of " "them and fails the other")) diff --git a/goodwe_controller/test_price.py b/goodwe_controller/test_price.py index 0925e84..208b67c 100644 --- a/goodwe_controller/test_price.py +++ b/goodwe_controller/test_price.py @@ -2123,7 +2123,7 @@ check("...and so does a configured provider on its own", -5000, 5000) == []) check("an unknown provider id is refused rather than defaulted to 'off'", why(validate_startup_config(vbase(price_provider="nordpool"), -5000, 5000), - "not a shipped plugin")) + "which does not exist")) # ⚠️ TARIFF-07: A RETIRED ID IS REFUSED BY A DIFFERENT MESSAGE, AND EVERY CHECK # HERE GRADES THE REASON RATHER THAN THE VERDICT. The failure this section @@ -2144,26 +2144,21 @@ check(f"every retired id is refused at startup {sorted(_retired)}", len(_retired) == 3 and all(len(v) == 1 for v in _retired.values())) check("...and NOT by the unknown-id message, which would tell an operator they " "mistyped an id this add-on offered them and accepted for months", - all("not a shipped plugin" not in v[0] for v in _retired.values()) - and "WITHDRAWN" not in _unknown[0]) + all("which does not exist" not in v[0] for v in _retired.values()) + and "was withdrawn" not in _unknown[0]) check("...and each message NAMES ITS OWN ID, so the operator can tell it is " "about their configuration and not a generic notice", all(repr(pid) in v[0] for pid, v in _retired.items())) -check("...and (a) says the plugin never fetched a price, naming the endpoint " - "that does not exist", - all("NEVER FETCHED A PRICE" in v[0] for v in _retired.values()) - and "api.engie.be/dynamic/be" in _retired["engie_dynamic"][0] - and "api.totalenergies.be/prices/dynamic" - in _retired["totalenergies_dynamic"][0] - and "api.eneco.be/eddy/prices" in _retired["eneco_eddy"][0]) +# UX-08 2c: the endpoints that never existed are in DOCS.md under "Energy price +# providers"; the refusal keeps what the operator acts on. +check("...and (a) says the plugin never fetched a price", + all("never fetched a price" in v[0] for v in _retired.values())) check("...and (b) says what the site has ACTUALLY been running instead - the " "half §11.4 made invisible", - all("SILENT" in v[0] and "static_profile" in v[0] - for v in _retired.values())) -check("...and (c) says what to do, naming a live plugin and refusing to " - "pretend an alias could exist", + all("This site ran on" in v[0] for v in _retired.values())) +check("...and (c) says what to do, naming a live plugin", all("generic_dayahead" in v[0] and "manual_csv" in v[0] - and "NO alias" in v[0] for v in _retired.values())) + for v in _retired.values())) # ⚠️ AND THE SENTENCE CHANGES WITH THE SITE. "You have been on the static # profile" is FALSE where no profile was ever set, and that site is in a WORSE @@ -2177,11 +2172,12 @@ _with_profile = validate_startup_config( _without = _retired["eneco_eddy"][0] check("a retired id on a site WITH a static profile is told it has been " "running that profile", - "the static day/night tariff in static_profile" in _with_profile) + "ran on the “Fixed or day/night tariff” (static_profile)" + in _with_profile) check("...and a site WITHOUT one is told it has been running nothing at all, " "which is a different and worse state", - "NOTHING AT ALL" in _without - and "the static day/night tariff in static_profile" not in _without) + "ran on no tariff at all" in _without + and "(static_profile)" not in _without) check("...so the two renderings are not the same sentence", _with_profile != _without) @@ -2193,7 +2189,7 @@ _p = validate_startup_config( check("a provider AND the Home Assistant price entities is refused - two price " "sources on one site", len(_p) == 1) check("...and the message says which one actually wins", - why(_p, "HOME ASSISTANT ENTITIES WIN")) + why(_p, "are also set and would win")) # TARIFF-03 added a second source with the same silent-loser shape. _ps = validate_startup_config( vbase(static_profile='{"periods": [{"from":"00:00","to":"24:00",' @@ -2202,7 +2198,7 @@ _ps = validate_startup_config( -5000, 5000) check("a static_profile AND the Home Assistant price entities is refused too - " "main.py reads one of them for `cheap` and the loser is silent", - len(_ps) == 1 and why(_ps, "HOME ASSISTANT")) + len(_ps) == 1 and why(_ps, "Home Assistant price entities would count")) check("the Home Assistant entities alone still start, so nothing is taken away " "from a live install", validate_startup_config(vbase(price_now_entity="sensor.now", @@ -2945,10 +2941,10 @@ check("...and BOTH translations tell an operator which switch does which - " "the provider option says it is what starts the fetch, and the trading " "option says turning it off does not turn the feed off. One language " "updated and not the other is how this surface rots", - "STARTS THE PRICE FETCH" in _T10_TR["en"] - and "DOES NOT TURN THE PRICE FEED OFF" in _T10_TR["en"] - and "HET OPHALEN VAN PRIJZEN START" in _T10_TR["nl"] - and "ZET DE PRIJSFEED NIET UIT" in _T10_TR["nl"]) + "starts the price fetch" in _T10_TR["en"] + and "does not turn the price feed off" in _T10_TR["en"] + and "start het ophalen van prijzen" in _T10_TR["nl"] + and "zet de prijsfeed niet uit" in _T10_TR["nl"]) # --------------------------------------------------------------------------- # @@ -3431,8 +3427,8 @@ check(f"network charges folded into `offset` move the card's own price to " isinstance(_double_price, float) and abs(_double_price - 15.55) > 10) check(f"...and it is refused, by the CARD rule, naming the discrepancy and " f"the network-charge cause ({_double[:60]!r})", - "does not reproduce its own card" in _double and "OUT BY" in _double - and "folded into `offset`" in _double) + "does not match its own card" in _double and "the card says" in _double + and "network charges are not in the offset" in _double) _CORRUPTIONS = { "VAT left out (vat_pct 0)": spoilt(vat_pct=0), @@ -3451,7 +3447,7 @@ for _name, _blob in sorted(_CORRUPTIONS.items()): _why = refusal(_blob) check(f"{_name}: refused, and by the CARD rule rather than by another one " f"({_why[:48]!r})", - "does not reproduce its own card" in _why and "OUT BY" in _why) + "does not match its own card" in _why and "the card says" in _why) # ⚠️ THE TOLERANCE IS A REAL EDGE AND IT IS GRADED FROM BOTH SIDES, or # "within 0.01" and "within anything" would be the same check. @@ -3463,7 +3459,7 @@ _outside = refusal(spoilt(card_expect_incl_vat=round( + CARD_TOLERANCE * 2.0, 6))) check(f"half a tolerance out passes and twice a tolerance out does not, so " f"{CARD_TOLERANCE} is the number being enforced rather than a shape", - _inside == "" and "does not reproduce its own card" in _outside) + _inside == "" and "does not match its own card" in _outside) # A card that is absent is refused, and NOT by the generic unknown-field rule. check(f"a formula with NO card block is refused, and the message says why the " @@ -3569,32 +3565,31 @@ check("...and the hourly series' coverage is still DERIVED from the " print() print("15e. every refusal in the table, and the two that are WARNINGS") _TABLE = { - "units absent": (spoilt(units=""), "units", "is REQUIRED"), + "units absent": (spoilt(units=""), "units", "Choose one of"), "units not one of the enumerated ones": - (spoilt(units="cents"), "units", "must be one of"), + (spoilt(units="cents"), "units", "Choose one of"), "factor == 0 (every spread becomes 0, arbitrage never fires)": (spoilt(factor=0), "factor", "static_profile"), "factor < 0 (the dearest hour becomes the cheapest)": - (spoilt(factor=-0.102), "factor", "inverts the market"), + (spoilt(factor=-0.102), "factor", "turns the market upside down"), "vat_pct above 30 (the 6 / 1.06 / 106 confusion)": (spoilt(vat_pct=106), "vat_pct", "between 0 and 30"), "vat_pct below 0": (spoilt(vat_pct=-6), "vat_pct", "between 0 and 30"), "a non-numeric coefficient": (spoilt(factor="0.102"), "factor", "not a number"), "a coefficient that is an EXPRESSION rather than a number": - (spoilt(factor="0.1*x"), "factor", "evaluates nothing"), + (spoilt(factor="0.1*x"), "factor", "Write a plain number"), "a non-finite coefficient": (spoilt(offset=float("inf")), "offset", "not finite"), - "an unknown index": (spoilt(index="belpex_h"), "index", "cannot get it"), + "an unknown index": (spoilt(index="belpex_h"), "index", "can only fetch"), "an unknown resolution": (spoilt(resolution="daily"), "resolution", - "must be one of"), + "Choose one of"), "an unknown top-level field (which is how 'expr' is answered)": - (spoilt(expr="0.102*spot+1"), "expr", "NO field that takes an " - "expression"), + (spoilt(expr="0.102*spot+1"), "expr", "It takes only"), "an unknown field inside the card": ({**ENECO_CARD, "card": dict(ENECO_CARD["card"], vat="6")}, - "vat", "no field(s)"), + "vat", "unknown field(s)"), } for _name, (_blob, _names, _needle) in sorted(_TABLE.items()): _why = refusal(_blob) @@ -3649,7 +3644,7 @@ check("...and it is warned about, naming the month and saying why it is not " "refused", "2019-01" in (stale_card(parse_price_formula(json.dumps(_old_card))) or "") - and "Not refused" in (stale_card( + and "still starts" in (stale_card( parse_price_formula(json.dumps(_old_card))) or "")) check("...while a card from this month draws no warning, so the rule is the " "AGE and not the presence of the field", @@ -3850,13 +3845,13 @@ check("custom_formula with NO formula is refused, naming the option and " "showing the shape", why(validate_startup_config(vbase(price_provider="custom_formula"), -5000, 5000), - "price_formula is empty")) + "(price_formula) is empty")) check("a formula that does not reproduce its card is refused AT STARTUP, " "with the discrepancy named", why(validate_startup_config( vbase(price_provider="custom_formula", price_formula=json.dumps(spoilt(offset=13.0))), - -5000, 5000), "does not reproduce its own card")) + -5000, 5000), "does not match its own card")) check("...and a formula that is not JSON at all is refused with the shape it " "wanted, rather than with a traceback", why(validate_startup_config( @@ -5362,18 +5357,17 @@ check("...and none of those rows is vacuous: every one really did refuse on " _T16_DIFFER = [ ("factor 0 -> where a FLAT price of THIS leg lives", spoilt(factor=0.0), "static_profile", "export_price_eur_kwh"), - ("a negative factor -> which market it inverts", - spoilt(factor=-0.102), "No consumption tariff", - "No Belgian injection tariff"), - ("a card miss -> what a wrong `offset` costs on THIS leg", - spoilt(factor=0.120), "bills you for it twice", - "nothing is added to this leg"), + # UX-08 2c: a negative factor gets one sentence on both legs now ("put the + # minus sign on the offset"), so it left this table. + ("a card miss -> what else to check on THIS leg", + spoilt(factor=0.120), "network charges are not in the offset", + "vat_pct is 0 for injection"), ("invalid JSON -> WHEN this option is read at all, which is not the " "same answer on the two legs: `price_formula` decides nothing unless " "price_provider is 'custom_formula', and the injection leg is read " "whatever the consumption provider is", - "{not json", "unless price_provider is 'custom_formula'", - "read whatever price_provider is set to"), + "{not json", "(price_provider) is 'custom_formula'", + "used whatever the price source is"), ] for _what, _blob, _cons_mark, _inj_mark in _T16_DIFFER: _a, _b = ((_reason(lambda b=_blob: parse_price_formula(b)), @@ -5490,10 +5484,10 @@ check(f"a factor 100x out is refused BY THE PASS-THROUGH RUNG, naming the " f"share of the wholesale price it would pay ({_T16_PT_WHY[:60]!r})", "passes through" in _T16_PT_WHY and f"{PASSTHROUGH_LO}-{PASSTHROUGH_HI}x" in _T16_PT_WHY - and "|offset| above" not in _T16_PT_WHY) + and "larger than" not in _T16_PT_WHY) check(f"an offset 100x out is refused BY THE OFFSET RUNG, naming the EUR/kWh " f"it works out at ({_T16_OFF_WHY[:60]!r})", - "|offset| above" in _T16_OFF_WHY + "larger than" in _T16_OFF_WHY and "passes through" not in _T16_OFF_WHY) check(f"...and the WHOLE card 100x out - which trips both - is refused, with " f"the pass-through rung answering first ({_T16_BOTH_WHY[:44]!r})", @@ -5555,9 +5549,8 @@ check(f"a card block ON THIS LEG is graded by the same rung at the same " f"15.55) is refused, naming the option the operator typed " f"({_T16_SPOILT_CARD[:64]!r})", _T16_WITH_CARD == "" - and "does not reproduce its own card" in _T16_SPOILT_CARD - and _T16_SPOILT_CARD.startswith(EXPORT_FORMULA_OPTION) - and f"the tolerance is {CARD_TOLERANCE}" in _T16_SPOILT_CARD) + and "does not match its own card" in _T16_SPOILT_CARD + and _T16_SPOILT_CARD.startswith(EXPORT_FORMULA_OPTION)) check(f"...and half a tolerance out still passes, so {CARD_TOLERANCE} is " f"enforced on this leg too rather than 'something'", _reason(lambda: parse_export_formula(json.dumps(spoilt( diff --git a/goodwe_controller/test_selfconfig.py b/goodwe_controller/test_selfconfig.py index 336ea71..e73c5ad 100644 --- a/goodwe_controller/test_selfconfig.py +++ b/goodwe_controller/test_selfconfig.py @@ -236,7 +236,7 @@ check("the stored options are byte-identical to what they were", check("...and the refusal carries the validator's OWN sentence, unedited", refused.problems == validate_startup_config(bad, None, None)) check("...which is the sentence that names the key and says what it costs", - any("setpoint_entity is not set" in p for p in refused.problems)) + any("(setpoint_entity) is empty" in p for p in refused.problems)) _good = base() res = run(selfconfig.save(sup, _good, fp)) @@ -316,7 +316,7 @@ _probs, _ = run(selfconfig.problems_and_ranges(dict(_live, max_w=""), None)) check("⚠️ CLEARING max_w ON THE LIVE SHAPE IS REFUSED - rule 10 catches the " "rail collapsing to the 2000 default under an explicit 400 W slew, so " "the box cannot be emptied into a quietly halved rail", - any("site rail of 2000 W" in p for p in _probs)) + any("for a 2000 W site" in p for p in _probs)) # HALF TWO: the backstop cannot report "no problems" for a config it could not # compose. Returning [] there enables Save - a crash became a green. @@ -430,7 +430,7 @@ _probs = run(selfconfig.problems_for(base(max_w=4000), FakeHass(_ranges))) _by, _un = configui.problems_by_field(_probs, ALL_KEYS) check("the device-range rule is REACHED from the panel - the setpoint entity's " "own range is read, so rule 1 fires here exactly as it does at startup", - any("THE DEVICE WINS" in p for p in _probs)) + any("Lower the rating to" in p for p in _probs)) check("...and it lands on `max_w`, which is the field the operator has to " "change", "max_w" in _by) # ⚠️ THE COLLISION, CHECKED HERE AND NOT ONLY IN THE PROBE. `sign_disagree_w` @@ -467,7 +467,7 @@ _p2, _unread2 = run(selfconfig.problems_and_ranges(base(max_w=4000), FakeHass(_ranges))) check("...and with the same device answering, the same config IS refused - " "which is what makes the line above a skip rather than a pass", - any("THE DEVICE WINS" in p for p in _p2) and _unread2 == []) + any("Lower the rating to" in p for p in _p2) and _unread2 == []) check("the note is about the config UNDER TEST, not about the running roster: " "a newly typed entity that does not answer is the one named", run(selfconfig.problems_and_ranges( @@ -495,8 +495,9 @@ _leaked = sorted(k for k in ALL_KEYS _script)) check(f"the page's script names NOT ONE option key - so it cannot be rendering " f"a field list of its own. Leaked: {_leaked}", not _leaked) -_phrases = ["THE DEVICE WINS", "has no actuator", "two writers", - "setpoint_entity is not set", "would silently never happen"] +_phrases = ["Lower the rating to", "cannot control the inverter", + "point at the same inverter entity", "(setpoint_entity) is empty", + "accepts at most"] _copied = sorted(p for p in _phrases for f, text in _ui_files.items() if p in text) check(f"no phrase out of a validate.py refusal appears anywhere in the three " diff --git a/goodwe_controller/test_static_tariff.py b/goodwe_controller/test_static_tariff.py index 4078ae5..b2cda49 100644 --- a/goodwe_controller/test_static_tariff.py +++ b/goodwe_controller/test_static_tariff.py @@ -850,7 +850,7 @@ check("a good static_profile starts", check("a gapped one is REFUSED at startup, not at 22:00 on the day it bites", why(validate_startup_config(vbase(static_profile=json.dumps(_gap)), -5000, 5000), - "static_profile cannot be used")) + "“Fixed or day/night tariff” cannot be used")) check("...and the refusal names the uncovered range", why(validate_startup_config(vbase(static_profile=json.dumps(_gap)), -5000, 5000), "22:00-23:00")) @@ -859,7 +859,7 @@ check("static_profile alongside the Home Assistant price entities is refused - " why(validate_startup_config( vbase(static_profile=json.dumps(TWO_PERIOD), price_now_entity="sensor.now", price_avg_entity="sensor.avg"), - -5000, 5000), "HOME ASSISTANT")) + -5000, 5000), "Home Assistant price entities would count")) check("...and the Home Assistant pair ALONE still starts, so nothing is taken " "away from a live install", validate_startup_config(vbase(price_now_entity="sensor.now", diff --git a/goodwe_controller/test_tool_inputs.py b/goodwe_controller/test_tool_inputs.py index 9a8628d..602e7c6 100644 --- a/goodwe_controller/test_tool_inputs.py +++ b/goodwe_controller/test_tool_inputs.py @@ -86,7 +86,7 @@ check("baseline: the bare options object is CLEARED (exit 0)", code == 0 and "CLEARED for deploy" in out) code, out = gate(dump("bare-bad.json", dict(BARE, slew_w=5000))) check("baseline: the bare object with slew_w 5000 is REFUSED by the validator", - code == 1 and "slew_w is 5000 W" in out) + code == 1 and "(slew_w) is 5000 W" in out) for label, doc in (("wrapped", ha_apps_info(BARE)), ("wrapped, slew_w 5000", ha_apps_info(dict(BARE, slew_w=5000)))): diff --git a/goodwe_controller/test_translations.py b/goodwe_controller/test_translations.py index 822d21f..47e1db8 100644 --- a/goodwe_controller/test_translations.py +++ b/goodwe_controller/test_translations.py @@ -12,10 +12,11 @@ the sentence that says WHETHER TO TOUCH THE VALUE, because the tab presents a constant derived from 1890 closed-loop test runs and the operator's own inverter rating as the same kind of field. -⚠️ WHAT THIS FILE CANNOT SEE, SAID FIRST. It grades COVERAGE and PROVENANCE -CITATIONS - that every option has a name and a description in both languages, -that no translation names an option that does not exist, and that each derived -constant's English description cites the record it was derived from. It does NOT +⚠️ WHAT THIS FILE CANNOT SEE, SAID FIRST. It grades COVERAGE and PROVENANCE - +that every option has a name and a description in both languages, that no +translation names an option that does not exist, that each derived constant's +English description says to leave it, and that DOCS.md's "For installers" +entry for it names the record it came from (moved there by UX-08). It does NOT grade whether a sentence is true, whether the Dutch is good Dutch, or whether the result looks right on screen. The last of those is measured, not asserted, by `tools/supervisor_shape_probe.py` section F, which loads these files with @@ -107,83 +108,95 @@ check("...and no Dutch string was left as a copy of the English one, which is " == TR["nl"]["configuration"][k]["description"]]) print("\n3. ⭐ the description says WHETHER TO TOUCH IT") -# ⚠️ THE HIGHEST-VALUE ITEM IN THE CARD, AND THE ONE A COVERAGE COUNT CANNOT -# REACH. Sixty-odd descriptions that all say "the threshold, in watts" would -# pass part 2 completely. What makes this surface safe is that a DERIVED -# constant names the campaign it came from and says the value is not a knob, -# while a number that really is the operator's says so too. -# -# ⚠️ AND THIS IS A TEXT CHECK, WHICH IS WEAK ON PURPOSE AND IS SAID TO BE. It -# cannot know whether a citation is TRUE; it can only know that the citation is -# there and names the right record, so that deleting the provenance - or -# renaming the card it points at - goes red instead of shipping. The table is -# written out rather than derived because there is nothing in config.yaml that -# distinguishes a derived constant from an operator's number; that distinction -# is the whole of what this card had to add. +# The value of this surface is the sentence that says whether a number is a +# knob. Since UX-08 phase 2c the tab keeps that sentence short ("Measured value, +# leave it unchanged.") and the record it came from lives in DOCS.md under +# "For installers: where the numbers come from", where UX-01's citations moved. +# So each derived key is pinned twice: +# its English description tells the reader what to do, and its DOCS entry names +# the record. A text check, weak on purpose: it cannot know a citation is TRUE, +# only that deleting it, or the instruction, goes red. +DOCS = (HERE / "DOCS.md").read_text(encoding="utf-8") +_inst = DOCS.split("\n### For installers: where the numbers come from\n", 1) +INSTALLERS = _inst[-1].split("\n#", 1)[0] if len(_inst) == 2 else "" +check("DOCS.md has the 'For installers: where the numbers come from' section", + bool(INSTALLERS.strip())) + + +def docs_entry(key): + """The DOCS bullet that names `key` in backticks, lower-cased.""" + hits = [b for b in INSTALLERS.split("\n- ") if f"`{key}`" in b] + return hits[0].lower() if hits else "" + + +LEAVE_M, LEAVE_D = "Measured value, leave it unchanged", \ + "Derived value, leave it unchanged" +# key: (what the English description must say, what its DOCS entry must name) DERIVED = { - "sign_disagree_w": ("SAFETY-02", "MEASURED"), - "sign_disagree_s": ("SAFETY-02", "MEASURED"), - "unit_sign_disagree_w": ("SAFETY-30", "1890"), - "unit_sign_disagree_s": ("SAFETY-30", "1890"), - "site_sign_disagree_w": ("SAFETY-30", "CARRIED"), - "site_sign_disagree_s": ("SAFETY-30", "1890"), - "meter_freeze_s": ("SAFETY-18", "MEASURED"), - "circulation_w": ("SAFETY-31", "924"), - "circulation_hold_s": ("SAFETY-31", "DERIVED"), - # SAFETY-42. Two needles rather than one: the campaign it was derived from, - # and the word that says what it does NOT do. An operator who reads - # "not-delivering report" and assumes the add-on has handled it is the - # failure this alarm's whole wording is written against. - "delivery_hold_s": ("SAFETY-42", "DERIVED FROM", "REPORTS ONLY"), - "peak_soc_floor": ("SAFETY-24", "DERIVED"), - "bms_soc_floor": ("0x0560", "MEASURED"), - "integrator_max_w": ("MEASURED", "Do not raise it"), - "gain": ("MEASURED ON", "do not raise it"), - # SAFETY-39. `slew_w` joins the table because it stopped being an - # operator's convenience and became a DERIVED value the moment it was - # tied to the rating: 0 resolves to about a ninth of `max_w`, from an - # ~18 s measured step response. It is the one entry here whose value is - # a RATIO, so the description has to say what it follows as well as - # where the ratio came from - a citation alone would leave an operator - # reading "0" on the tab with no idea it is not "off". - "slew_w": ("SAFETY-39", "DERIVED", "0 MEANS FOLLOW"), - # TARIFF-18. `price_taxes_eur_kwh` joins the table for `slew_w`'s reason: - # it stopped being a figure somebody picked and became one SUMMED FROM - # NAMED CARD ROWS. Three needles, because three different things about it - # can go wrong on the Configuration tab and only the first is provenance: - # where the number came from, that the operator's own DSO gives a - # different one, and that changing it moves no trade - which is the claim - # an operator is most likely to assume the opposite of when a number - # doubles. - "price_taxes_eur_kwh": ("TARIFF-18", "YOUR OWN DSO", - "MOVES NO TRADING DECISION"), + "sign_disagree_w": (LEAVE_M, ("SAFETY-02", "measured")), + "sign_disagree_s": (LEAVE_M, ("SAFETY-02", "measured")), + "unit_sign_disagree_w": (LEAVE_D, ("SAFETY-30", "1890")), + "unit_sign_disagree_s": (LEAVE_D, ("SAFETY-30", "1890")), + "site_sign_disagree_w": (LEAVE_M, ("SAFETY-30", "carried")), + "site_sign_disagree_s": (LEAVE_D, ("SAFETY-30", "1890")), + "meter_freeze_s": (LEAVE_M, ("SAFETY-18", "measured")), + "circulation_w": (LEAVE_M, ("SAFETY-31", "924")), + "circulation_hold_s": (LEAVE_D, ("SAFETY-31", "derived")), + # SAFETY-42: the alarm changes nothing, and both surfaces say so. + "delivery_hold_s": (LEAVE_D, ("SAFETY-42", "derived from", + "reports only")), + "peak_soc_floor": (LEAVE_D, ("SAFETY-24", "derived")), + "bms_soc_floor": ("Read it off your battery", ("0x0560", "measured")), + "integrator_max_w": ("Do not raise it above", ("measured",)), + "gain": ("do not raise it", ("measured on",)), + # SAFETY-39: 0 is not "off", it follows the rating. + "slew_w": ("0 follows", ("SAFETY-39", "derived", "0 means follow")), + # TARIFF-18: where the figure came from, that your DSO differs, and that + # changing it moves no trade. + "price_taxes_eur_kwh": ("Check it against your own grid operator", + ("TARIFF-18", "your own dso", + "moves no trading decision")), } _uncited = [] -for key, needles in sorted(DERIVED.items()): - desc = TR["en"]["configuration"][key]["description"] +for key, (says, needles) in sorted(DERIVED.items()): + if says not in TR["en"]["configuration"][key]["description"]: + _uncited.append(f"{key} description does not say {says!r}") for needle in needles: - if needle not in desc: - _uncited.append(f"{key} does not cite {needle!r}") -print(f" {len(DERIVED)} derived constants must cite their campaign; " - f"{len(_uncited)} do not") -check(f"every derived constant's English description names WHERE THE NUMBER " - f"CAME FROM, so an operator reading the tab can tell it apart from their " - f"own inverter rating. Uncited: {_uncited}", not _uncited) -# The other direction, and it matters as much: a number that IS the operator's -# must not be dressed up as derived, or the labels stop meaning anything. + if needle.lower() not in docs_entry(key): + _uncited.append(f"{key}: DOCS does not name {needle!r}") +print(f" {len(DERIVED)} derived constants; {len(_uncited)} problem(s)") +check(f"every derived constant's description says what to do with it, and its " + f"DOCS entry names where the number came from. Problems: {_uncited}", + not _uncited) _theirs = ["max_w", "peak_cap_w"] -check("...and the numbers that really are the OPERATOR'S say so instead of " - "carrying a citation - `max_w` and `peak_cap_w` are the two the card " - "names, and both read 'THIS IS YOUR NUMBER'", - all("THIS IS YOUR NUMBER" in TR["en"]["configuration"][k]["description"] +check("...and the numbers that really are the OPERATOR'S say so instead - " + "`max_w` and `peak_cap_w` start 'Your own number', here and in DOCS", + all(TR["en"]["configuration"][k]["description"].startswith( + "Your own number") and "your own number" in docs_entry(k) for k in _theirs)) check("...and the one threshold that is NOT derived from a measurement admits " - "it rather than borrowing the others' authority - " - "`cycle_cost_threshold_eur` is an open product question (OPT-08)", - "NOT DERIVED FROM A MEASUREMENT" + "it - `cycle_cost_threshold_eur` is a product choice, and DOCS names the " + "open question (OPT-08)", + "product choice, not a measured one" in TR["en"]["configuration"]["cycle_cost_threshold_eur"]["description"] - and "OPT-08" - in TR["en"]["configuration"]["cycle_cost_threshold_eur"]["description"]) + and "opt-08" in docs_entry("cycle_cost_threshold_eur") + and "not derived from a measurement" + in docs_entry("cycle_cost_threshold_eur")) +# DOCS.md's "Settings at a glance" shows the tab's text. It must not drift. +_glance = DOCS.split("\n### Settings at a glance\n", 1)[-1].split("\n#", 1)[0] +_rows = {} +for line in _glance.splitlines(): + cells = [c.strip() for c in line.strip().strip("|").split("|")] + if len(cells) == 4 and cells[2].startswith("`"): + _rows[cells[2].strip("`")] = (cells[1], cells[3]) +_drift = [] +for key in ORDER: + conf = TR["en"]["configuration"][key] + want = (conf["name"].split(" · ")[-1], conf["description"]) + if _rows.get(key) != want: + _drift.append(key) +check(f"DOCS.md 'Settings at a glance' shows every option's English label and " + f"description exactly as the tab does. Drifted: {_drift}", not _drift) print("\n4. task ordering, and the labels that carry it") # ⚠️ ADD-ON OPTIONS ARE A FLAT LIST - no section headers, no per-option advanced diff --git a/goodwe_controller/test_validate.py b/goodwe_controller/test_validate.py index c38a704..b0bcb99 100644 --- a/goodwe_controller/test_validate.py +++ b/goodwe_controller/test_validate.py @@ -77,7 +77,7 @@ p = validate_startup_config(base(max_w=8000), -5000, 5000) check("max_w above the device maximum is refused", len(p) == 1) check("...and the message names the configured value", why(p, "8000")) check("...and the device's value", why(p, "5000")) -check("...and says which one wins", why(p, "THE DEVICE WINS")) +check("...and says what to lower it to", why(p, "Lower the rating to 5000 W")) check("max_w exactly at the device maximum is fine", validate_startup_config(base(max_w=5000), -5000, 5000) == []) check("max_w under it is fine", @@ -85,7 +85,7 @@ check("max_w under it is fine", # The charge side is a separate rail and an asymmetric device is legal. p = validate_startup_config(base(max_w=4000), -2500, 5000) check("a max_w the device cannot take on the CHARGE side is refused too", - len(p) == 1 and why(p, "charge side")) + len(p) == 1 and why(p, "when charging")) check("...naming the device's floor", why(p, "-2500")) # ⚠️ Not guessed at: the entity may simply not have booted yet. run_control() # re-runs this the moment the real rating arrives. @@ -122,7 +122,7 @@ check("...and rule 2 REFUSES that whole configuration at startup, which is why " len(validate_startup_config(base(max_w=_CEIL), -_DEV, _DEV)) == 1) check("...on the rating side specifically, not incidentally through some other " "rule", why(validate_startup_config(base(max_w=_CEIL), -_DEV, _DEV), - "THE DEVICE WINS")) + "Lower the rating to")) check("...and the case the refusal CANNOT reach - the rating unread because " "ESPHome was not up - still starts, which is precisely why SAFETY-20's " "answer had to be a runtime status row and not a startup gate", @@ -136,9 +136,9 @@ print("2. an actuator to write to") for blank in ("", " ", None): p = validate_startup_config(base(setpoint_entity=blank), None, None) check(f"setpoint_entity {blank!r} is refused", len(p) == 1) -check("...and the message says why it is dangerous rather than untidy", +check("...and the message says what it costs: nothing is controlled", why(validate_startup_config(base(setpoint_entity=""), None, None), - "heartbeat")) + "cannot control the inverter")) # --------------------------------------------------------------------------- # # specs §1.5: TWO WRITERS ON ONE ACTUATOR, AND WHAT ACTUALLY GRADES IT # --------------------------------------------------------------------------- # @@ -181,7 +181,7 @@ check("...and the replacement SEES it, because it counts writers per ACTUATOR " and len(_census["number.goodwe_setpoint"]) == 3) _hazard_problems = validate_startup_config(_PER_INVERTER_HAZARD, -5000, 5000) check("AC 3: and the config is REFUSED, where today it starts", - why(_hazard_problems, "one actuator")) + why(_hazard_problems, "point at the same inverter entity")) check("...and the refusal names the actuator and every writer aimed at it, so " "an operator can see WHICH declarations to remove rather than being told " "only that something is wrong", @@ -243,7 +243,8 @@ check("...and entity ids are folded to lower case, so a second writer cannot " "be smuggled past the census on Number.X versus number.x", why(validate_startup_config(base(inverters=[{"setpoint_entity": "NUMBER.GOODWE_SETPOINT"}]), - -5000, 5000), "one actuator")) + -5000, 5000), + "point at the same inverter entity")) # ⚠️ THIS CHECK CHANGED SHAPE IN CFG-04, AND THE REASON IS A DECISION RATHER # THAN AN ADJUSTMENT. It used to assert that a blank per-inverter entity left # the whole config ACCEPTED - "blank is how an operator leaves a slot @@ -265,7 +266,8 @@ check("...but the ENTRY is refused all the same, by rule 9 and not by the " why(validate_startup_config(base(inverters=[{"name": "inverter-b", "max_w": 2000, "setpoint_entity": " "}]), - -5000, 5000), "has no setpoint_entity")) + -5000, 5000), + "has no “Inverter setpoint entity” (setpoint_entity)")) # --- OPT-09: `capacity_kwh`, which is OPTIONAL but not PARTIAL --------------- # ⚠️ RULE 9 GAINED TWO CLAUSES AND BOTH REFUSE A CONFIG THAT WOULD OTHERWISE @@ -303,9 +305,9 @@ check("⚠️ AND A PARTIAL ROSTER IS REFUSED - stated on one entry and left emp "weighing a dimensionless 1.0 is not a comparison, so the key would " "silently change nothing at all", why(validate_startup_config(_with_cap(15.36, None), -5000, 5000), - "not PARTIAL") + "Set it on every inverter, or on none") and why(validate_startup_config(_with_cap(None, 20.48), -5000, 5000), - "not PARTIAL")) + "Set it on every inverter, or on none")) check("...and the refusal names WHICH entry is which, because an operator with " "three inverters told 'one of them is wrong' is sent to the wrong " "cupboard", @@ -339,7 +341,7 @@ check("a phase list disagreeing with meter_phases is refused", why(validate_startup_config(base(meter_source="ha_signed", p1_net_entity="sensor.n", meter_phases=3, p1_phase_net_entities=["a", "b"]), - -5000, 5000), "phase-count")) + -5000, 5000), "Make them match")) check("mqtt_p1 with no topic is refused", why(validate_startup_config(base(meter_source="mqtt_p1"), -5000, 5000), "meter_mqtt_topic")) @@ -349,7 +351,7 @@ check("ha_dsmr with only half its entities is refused", "p1_export_entity")) check("a misspelt meter_source is refused rather than silently ignored", why(validate_startup_config(base(meter_source="ha_signd"), -5000, 5000), - "is not one of")) + "Choose one of")) # --------------------------------------------------------------------------- # print("4. meter_max_age_s against the firmware's compile-time veto") @@ -361,7 +363,8 @@ p = validate_startup_config(base(**hw, meter_max_age_s=120), -5000, 5000) check("a meter_max_age_s above the firmware veto is refused", len(p) == 1) check("...naming the configured value", why(p, "120")) check("...naming the firmware's value", why(p, "30")) -check("...and saying which one wins", why(p, "THE FIRMWARE WINS")) +check("...and saying that the control board stops the inverter first", + why(p, "control board stops the inverter after 30 s")) check("the tested pair 30/30 is accepted", validate_startup_config(base(**hw, meter_max_age_s=30), -5000, 5000) == []) check("one second above it is refused", @@ -391,7 +394,7 @@ p = validate_startup_config(base(max_w=2000, maintenance_charge_w=2500), check("maintenance_charge_w above max_w is refused", len(p) == 1) check("...and the message names the charge rate", why(p, "2500")) check("...and the ceiling", why(p, "2000")) -check("...and says which one wins", why(p, "THE CEILING WINS")) +check("...and says what it blocks", why(p, "monthly recharge cannot run")) # ⚠️ Equality is REACHABLE, not a near miss: lo=-2000, hi=-2000 is the single # point -2000 W. Refusing it would be exactly the trivia that gets a validator # deleted, and it is the boundary the rule is written `>` for. @@ -407,7 +410,8 @@ check("below it starts", check("...and it is refused with maintenance_enabled off, as shipped", why(validate_startup_config( base(max_w=2000, maintenance_charge_w=2500, - maintenance_enabled=False), -5000, 5000), "THE CEILING WINS")) + maintenance_enabled=False), -5000, 5000), + "monthly recharge cannot run")) # ⚠️ MAINT-05: AND AT TWO PACKS IT IS THE WEAKEST CAP, NOT THE FIRST ENTRY'S. # The comment this replaces in validate.py said, in as many words, that it took @@ -448,11 +452,11 @@ check("⚠️ A CHARGE RATE THE SMALLEST PACK CANNOT TAKE IS REFUSED, even thoug "recalibrated, so its cap could not contradict anything; it is now, and " "its cheap-window charge would ask for hi=-3000 against lo=-2000 - the " "`lo > hi` contradiction, 0 W, on the pack nobody was watching", - len(_p_two) == 1 and why(_p_two, "max_w (inverter-b) is 2000 W")) + len(_p_two) == 1 and why(_p_two, "(max_w) for inverter-b is 2000 W")) check("...and the message names the pack the number came off, not the first " "entry - an operator told to lower a number on the wrong device is being " "sent to the wrong device by the message that exists to stop that", - not why(_p_two, "max_w (inverter-a)")) + not why(_p_two, "(max_w) for inverter-a")) check("...while the same rate against two packs that can both take it starts, " "so this is a comparison and not a blanket refusal of rosters", [p for p in validate_startup_config( @@ -463,7 +467,7 @@ check("...while the same rate against two packs that can both take it starts, " check("...and at a ROSTER OF ONE `min()` over one cap is that cap: the same " "message, the same boundary, the same refusal the flat config always got", why(validate_startup_config(base(max_w=2000, maintenance_charge_w=2500), - -5000, 5000), "THE CEILING WINS") + -5000, 5000), "monthly recharge cannot run") and validate_startup_config(base(max_w=2000, maintenance_charge_w=2000), -5000, 5000) == []) @@ -539,17 +543,15 @@ check("⭐ RESTORING THE 2026-09-05 PAIR - slew_w 1000 at max_w 5000 - IS REFUSE "It crosses the whole output range in 10 s against a plant measured at " "18 s, which is not a fast loop, it is a loop that commands its entire " "range before it can observe its answer to the first step", - len(_broken) == 1 and why(_broken, "slew_w is 1000 W")) -check("...and the refusal says WHICH RAIL it graded against and HOW LONG the " - "crossing takes, because 'slew_w is too high' sends an operator to lower " - "a number when raising max_w or setting 0 are both correct answers too", - why(_broken, "site rail of 5000 W") - and why(_broken, "crosses its whole output range in 5.0 cycles")) -check("...and it names the plant measurement it is graded against, so the " - "number is traceable to a step response rather than to a preference", - why(_broken, "goodwe/NOTES.md §5.10")) + len(_broken) == 1 and why(_broken, "(slew_w) is 1000 W")) +check("...and the refusal says WHICH RAIL it graded against, because 'slew_w " + "is too high' sends an operator to lower a number when raising max_w or " + "setting 0 are both correct answers too", + why(_broken, "for a 5000 W site")) +# UX-08 2c: the plant measurement the rule is graded against (the ~18 s step +# response) is in DOCS.md "For installers", beside slew_w, not in the refusal. check("...and it says what to DO, including the setting that cannot go stale", - why(_broken, "Set slew_w to 0") and why(_broken, "556 W")) + why(_broken, "Set it to 0") and why(_broken, "556 W")) # THE BOUNDARY. Equality is the DERIVED VALUE, not a violation - at exactly # `SLEW_RAIL_FRAC * rail` the loop takes precisely the plant's settling time to @@ -600,7 +602,7 @@ check("slew_w 0 - FOLLOW THE RAIL - is never refused at any rating, which it " check("a negative slew_w is refused as nonsense rather than treated as 0 - it " "is a magnitude, and 0 already has a meaning here", why(validate_startup_config(dict(_R5000, slew_w=-400), -5000, 5000), - "must not be negative")) + "cannot be negative")) # ⭐ THE ROSTER, WHICH IS THE WHOLE REASON THIS GRADES A SUM. `slew_w` is not a # per-unit quantity: main.py builds `Tuning(max_w=self.site_max_w)` and @@ -649,7 +651,7 @@ check("...so the same explicit slew_w that is REFUSED at a 5000 W rail is " check("...and a slew that outruns even the doubled rail is still refused there, " "so the roster path is not simply un-graded", why(validate_startup_config(_roster(slew_w=2000)), - "site rail of 9600 W")) + "for a 9600 W site")) # --------------------------------------------------------------------------- # print("the SHIPPED defaults must pass the rule they are governed by (AC3)") @@ -777,9 +779,10 @@ print("max_w must be a positive magnitude") # sim/inject.py's entry point and can be handed any dict at all. for bad in (0, -1, -2000): p = validate_startup_config(base(max_w=bad), -5000, 5000) - check(f"max_w {bad} is refused", len(p) == 1 and why(p, "must be positive")) -check("...and the message explains it would read as a trip, not a mistake", - why(validate_startup_config(base(max_w=0), -5000, 5000), "contradiction")) + check(f"max_w {bad} is refused", len(p) == 1 and why(p, "Set it above 0 W")) +check("...and the message names the setting by its label and its key", + why(validate_startup_config(base(max_w=0), -5000, 5000), + "“Inverter rating” (max_w) is 0 W")) # ⚠️ SAFETY-02 changed what this case has to say, and the change is real rather # than bookkeeping: with a 1 W ceiling the default 300 W sign-disagreement # threshold is unreachable, so rule 5 refuses - correctly, because the watchdog @@ -792,7 +795,7 @@ check("the smallest sane max_w still starts", unit_sign_disagree_w=0.5, maintenance_charge_w=1), -5000, 5000) == []) check("...but that same 1 W ceiling with the DEFAULT sign threshold is refused", - why(validate_startup_config(base(max_w=1), -5000, 5000), "never fire")) + why(validate_startup_config(base(max_w=1), -5000, 5000), "can never trip")) # ⚠️ SAFETY-30 ADDED A SECOND WAY TO DISARM A SIGN WATCHDOG BY CONFIGURATION, # and the fixture above now has to name BOTH thresholds - which is the check # doing its job rather than a bookkeeping edit. `unit_sign_disagree_w` bounds a @@ -1188,9 +1191,9 @@ def _roster_n(caps, **over): # The three rules that reduce over `unit_caps_indexed()`, each as # (option name, the token its refusal is recognised by). _CAP_RULES = ( - ("sign_disagree_w", "SAFETY-02 sign-disagreement"), - ("unit_sign_disagree_w", "SAFETY-30 per-inverter sign-disagreement"), - ("maintenance_charge_w", "maintenance charge in a cheap window"), + ("sign_disagree_w", "(sign_disagree_w) is"), + ("unit_sign_disagree_w", "(unit_sign_disagree_w) is"), + ("maintenance_charge_w", "monthly recharge cannot run"), ) _QUIET = {"sign_disagree_w": 300.0, "unit_sign_disagree_w": 300.0, "maintenance_charge_w": 1000.0, "maintenance_discharge_w": 1000.0} @@ -1220,7 +1223,7 @@ def _verdict(opts, token): ps = [p for p in validate_startup_config(opts, -5000, 5000) if token in p] if not ps: return (False, None, None) - m = re.search(r"max_w \(([^)]+)\) is (\d+) W", ps[0]) + m = re.search(r"\(max_w\) for (\S+) is (\d+) W", ps[0]) return (True, m.group(1) if m else None, float(m.group(2)) if m else None) @@ -1330,7 +1333,7 @@ check("...and at a ROSTER OF ONE every candidate that still has a member to " and {n for n, v in _at_one.items() if v is None} == {"min(caps[1:])", "min(caps[:-1])"} and _verdict(_roster_n([_SMALL], **dict(_QUIET, sign_disagree_w=_RATE)), - "SAFETY-02 sign-disagreement")[0]) + "(sign_disagree_w) is")[0]) # --- rule 5's SIBLING BRANCH, which was reading the FLAT max_w -------------- # ⚠️ FOUND BY READING THE THREE BRANCHES SIDE BY SIDE, NOT BY THE STRUCTURAL @@ -1342,7 +1345,7 @@ check("...and at a ROSTER OF ONE every candidate that still has a member to " _leftover = _roster_n([_SMALL, _SMALL], **dict(_QUIET, unit_sign_disagree_w=_RATE)) _leftover["max_w"] = _BIG # what a single-inverter install leaves behind -_lv = _verdict(_leftover, "SAFETY-30 per-inverter sign-disagreement") +_lv = _verdict(_leftover, "(unit_sign_disagree_w) is") print(f" leftover flat max_w {_BIG:.0f} beside a roster of two " f"{_SMALL:.0f} W units, unit_sign_disagree_w {_RATE:.0f} -> {_lv}") check("⚠️ A LEFTOVER FLAT `max_w` NO LONGER DISARMS SAFETY-30's PER-UNIT " @@ -1358,7 +1361,7 @@ check("...and the over-refusal in the OTHER direction is gone too: a roster of " "reach. It starts", _verdict(_roster_n([_BIG, _BIG], **dict(_QUIET, unit_sign_disagree_w=_RATE)), - "SAFETY-30 per-inverter sign-disagreement") + "(unit_sign_disagree_w) is") == (False, None, None)) check("...and the flat single-inverter config it always refused is refused " "IDENTICALLY - `unit_caps()` at a roster of one is `[max_w]`, so this is " @@ -1411,7 +1414,7 @@ print(f" {(_T17_P_GAP or [''])[0][:120]}") check("a table that leaves 00:00-07:00 unpriced is REFUSED, by the same tiling " "rule static_profile has - and the refusal names the KEY and the HOURS, " "not merely that something was wrong", - why(_T17_P_GAP, "price_taxes_profile cannot be used:") + why(_T17_P_GAP, "“Day/night levies and VAT” cannot be used.") and why(_T17_P_GAP, "leaves mon 00:00-07:00 with no period")) check("...and it is refused for THAT reason and not as a side effect of " "something else this fixture happens to break: exactly one problem", @@ -1427,9 +1430,9 @@ print(f" {(_T17_P_BOTH or [''])[0][:120]}") check("the table AND a non-default price_taxes_eur_kwh is refused, and the " "refusal says WHICH ONE WINS and what to do - not merely that the two " "are incompatible", - why(_T17_P_BOTH, "price_taxes_profile is set AND price_taxes_eur_kwh is " - "0.1198") - and why(_T17_P_BOTH, "THE TABLE WINS")) + why(_T17_P_BOTH, "(price_taxes_profile) is set, so") + and why(_T17_P_BOTH, "(price_taxes_eur_kwh) is not used, but it reads " + "0.1198")) check("...and the SHIPPED scalar beside the table is NOT refused, or every " "Walloon site would have to clear a key it never touched. The refusal is " "about a value the operator chose, and the shipped default is the one " @@ -1479,19 +1482,17 @@ check("...while a value that is NEITHER the shipped default NOR a superseded " "one is still REFUSED beside the table, naming it - the set of " "'untouched' figures widened by exactly the old defaults and by nothing " "else", - why(_T17_P_BOTH, "price_taxes_profile is set AND price_taxes_eur_kwh is " + why(_T17_P_BOTH, "(price_taxes_eur_kwh) is not used, but it reads " "0.1198") and 0.1198 not in _T18_SUPERSEDED and abs(0.1198 - _T18_SHIPPED_TAXES) > 1e-9) # ⚠️ AND THE REFUSAL SAYS SO, so an operator who HAS typed a number is told # both which figure to return to and that the old default is not the problem. -check("...and the refusal names the SHIPPED default to return to AND says the " - "superseded default is accepted, so the sentence is actionable on both " - "sides of the upgrade", +# UX-08 2c: that a superseded default is accepted is said in DOCS.md "For +# installers" now. The refusal keeps the one figure the operator acts on. +check("...and the refusal names the SHIPPED default to return to", bool(_T18_SUPERSEDED) - and why(_T17_P_BOTH, f"back to {_T18_SHIPPED_TAXES}") - and why(_T17_P_BOTH, "SUPERSEDED") - and all(why(_T17_P_BOTH, str(u)) for u in _T18_SUPERSEDED)) + and why(_T17_P_BOTH, f"back to {_T18_SHIPPED_TAXES}")) check("...and the same non-default scalar WITHOUT the table still starts, " "which is what makes the line above about the PAIR rather than about " "0.1198 being disliked", @@ -1531,18 +1532,18 @@ print(f" ORES : {(_T17_P_ORES or [''])[0][:110]}") print(f" Sibelga : {(_T17_P_SIB or [''])[0][:110]}") check("ORES's card typed in CENTS is refused by the PARSER's bound, and the " "sentence is the parser's - `beyond +-10.0`, naming the row", - why(_T17_P_ORES, "price_taxes_profile cannot be used:") + why(_T17_P_ORES, "“Day/night levies and VAT” cannot be used.") and why(_T17_P_ORES, "beyond +-10.0")) check("...and SIBELGA's whole card - 9,39 and 7,10, BOTH under that bound - is " "refused by THIS rung instead, naming both bands and the factor. Without " "it a Brussels site would price a 9.39 EUR/kWh levy and start", - why(_T17_P_SIB, "price_taxes_profile carries [7.1, 9.39] EUR/kWh") - and why(_T17_P_SIB, "factor of 100")) + why(_T17_P_SIB, "(price_taxes_profile) has [7.1, 9.39] EUR/kWh") + and why(_T17_P_SIB, "Divide the figures by 100")) check("...and the two refusals are DIFFERENT sentences, so the rungs cannot " "mask each other: deleting the units rung leaves the Sibelga line red " "while the ORES line goes on passing for the parser's reason", _T17_P_ORES != _T17_P_SIB - and not why(_T17_P_ORES, "factor of 100") + and not why(_T17_P_ORES, "Divide the figures by 100") and not why(_T17_P_SIB, "beyond +-10.0")) check("...and BOTH cards divided by 100 start, which is habit 7: the refusals " "above are about the units and not about Brussels or Wallonia", @@ -1639,13 +1640,13 @@ check("PRECONDITION: each of those two blobs differs from the accepted " == _T16_ENECO) check("a factor 100x out is REFUSED at startup, by the pass-through rung, " "naming the option the operator typed", - why(_T16_P_PT, "price_export_formula cannot be used:") + why(_T16_P_PT, "“Your own injection formula” cannot be used.") and why(_T16_P_PT, "passes through") - and not why(_T16_P_PT, "|offset| above")) + and not why(_T16_P_PT, "larger than")) check("...and an offset 100x out is refused by the OFFSET rung, so the two " "rungs are graded on their reasons and cannot mask each other", - why(_T16_P_OFF, "price_export_formula cannot be used:") - and why(_T16_P_OFF, "|offset| above") + why(_T16_P_OFF, "“Your own injection formula” cannot be used.") + and why(_T16_P_OFF, "larger than") and not why(_T16_P_OFF, "passes through")) check("...and a malformed blob is refused as a malformed blob, naming the " "field rather than 'invalid configuration'", @@ -1688,7 +1689,7 @@ check("...and a card ON THIS LEG that the coefficients do not reproduce is " "REFUSED at startup, so the optional block is optional and not inert", why(_t16_start(price_export_formula=_T16_CONS.replace( '"expect_incl_vat":15.55', '"expect_incl_vat":15.05'))[0], - "price_export_formula does not reproduce its own card")) + "price_export_formula does not match its own card")) # ⚠️ THE SENTENCE DOCS.md RESTS ON, AND IT IS THE ONE MOST LIKELY TO ROT. _T16_INFO = [m for lvl, m in _T16_OK_LOG if lvl == "INFO" @@ -1736,7 +1737,7 @@ for _v in _S10_BAD: _p = validate_startup_config(base(shadow_mode=_v), -5000, 5000) check(f"shadow_mode={_v!r} is REFUSED, and the refusal SPELLS the key so " "configui.problems_by_field() can file it under the right control", - why(_p, "shadow_mode is") and why(_p, "'auto'") + why(_p, "(shadow_mode) is") and why(_p, "'auto'") and why(_p, "'on'") and why(_p, "'off'")) for _v in ("auto", "on", "off", "AUTO", " on ", "Auto "): check(f"shadow_mode={_v!r} starts - the three values and the tolerant " diff --git a/goodwe_controller/test_version_gate.py b/goodwe_controller/test_version_gate.py index 13a0bf8..d32e1d4 100644 --- a/goodwe_controller/test_version_gate.py +++ b/goodwe_controller/test_version_gate.py @@ -138,7 +138,7 @@ r5 = run_gate(addon3, root3, "0.7.0", opts_file(bad)) check("refuses a config the validator rejects", r5.returncode == 1) check("...and warns it is exit 78", "78" in r5.stdout) check("...and warns the ingress panel goes too", "ingress panel" in r5.stdout) -check("...and prints the validator's own words", "slew_w is 1000 W" in r5.stdout) +check("...and prints the validator's own words", "(slew_w) is 1000 W" in r5.stdout) print() print("⭐ HISTORY WITH MORE THAN ONE BUMP - THE FIXTURE THE FIRST DRAFT LACKED") diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 9c71f42..eba1beb 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -154,7 +154,7 @@ p = validate_startup_config({**base, "max_w": 2000, "sign_disagree_w": 300}, check("300 W under a 2000 W ceiling is accepted", p == []) p = validate_startup_config({**base, "max_w": 2000, "sign_disagree_w": 2000}, -5000, 5000) -check("a threshold AT max_w is refused", len(p) == 1 and "never fire" in p[0]) +check("a threshold AT max_w is refused", len(p) == 1 and "can never trip" in p[0]) # ⚠️ maintenance_charge_w is named here only to keep this case about the SIGN # rule. MAINT-04 added a second rule against the same ceiling, and a 500 W # max_w is also below the 2000 W shipped maintenance charge - so without this @@ -162,7 +162,7 @@ check("a threshold AT max_w is refused", len(p) == 1 and "never fire" in p[0]) # `len(p) == 1` below would be measuring the interaction rather than this rule. p = validate_startup_config({**base, "max_w": 500, "sign_disagree_w": 3000, "maintenance_charge_w": 500}, -5000, 5000) -check("a threshold above max_w is refused", len(p) == 1 and "never fire" in p[0]) +check("a threshold above max_w is refused", len(p) == 1 and "can never trip" in p[0]) p = validate_startup_config({**base, "max_w": 2000, "sign_disagree_w": 1999}, -5000, 5000) check("one watt under the ceiling is reachable, so accepted", p == []) diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index e31e42c..ef97ea2 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -34,269 +34,267 @@ # is approximated by ORDER plus the `Group · ` prefix in each label. Do not # promise the operator visual sections; there are none. # -# ⚠️ EVERY DERIVED CONSTANT SAYS WHERE IT CAME FROM. The Configuration tab -# presents a number read off 1890 closed-loop test runs and the operator's own -# inverter rating as the same kind of field. The descriptions are the only place -# that difference can be stated, so a derived value names its campaign and says -# "do not change without re-deriving", and a value that is genuinely the -# operator's says so too. +# Names and descriptions follow STYLE.md (UX-08): a short label with its unit, +# and one or two plain sentences. A measured or derived value says "leave it +# unchanged", and where it came from is in DOCS.md under "For installers: +# where the numbers come from". configuration: setpoint_entity: name: "Hardware · Inverter setpoint entity" - description: "The ESPHome number entity this add-on writes the power setpoint to, normally number.*_goodwe_setpoint_w. This is the only thing the add-on commands. Leave it empty if you fill in the inverter list below: a site with a roster must not also name one loose actuator, and the add-on refuses to start when both are set." + description: "The ESPHome number entity the add-on writes the inverter's power to. Leave it empty when you fill in the inverter list." soc_entity: name: "Hardware · Battery level entity (%)" - description: "The sensor that reports the pack's state of charge in percent. Use the ESP32's own reading, not a figure computed somewhere else. The maintenance cycle and every charge-level floor read this." + description: "The sensor with the battery level in percent. Use the control board's own reading." batt_entity: name: "Hardware · Battery power entity (W)" - description: "The sensor that reports this inverter's own battery power, positive while discharging. On this installation that is holding register 0x0518, read by the ESP32. The sign watchdog and the circulating-power alarm both grade the inverter against this reading." + description: "The sensor with this inverter's battery power. Positive must mean the battery is giving power." batt_invert: name: "Hardware · Battery power sign is reversed" - description: "Only switch this on if your battery power sensor reports discharging as a negative number. The add-on expects positive to mean discharging." + description: "Switch this on only if your battery power sensor shows giving power as a negative number." inverters: - name: "Hardware · Inverter list (leave empty if you have one inverter)" - description: "Leave this empty unless the site really has more than one inverter. EMPTY DOES NOT MEAN 'not configured yet': it means the four entity settings above, together with the inverter rating and the battery cut-out under Limits, describe the one inverter you have. That is what every existing installation reads, and nobody has to touch anything. Filling this in REPLACES those settings instead of extending them, and nothing is inherited: each entry has to name its own actuator, its own rating and its own battery cut-out, so that no inverter is ever judged against another unit's numbers. The flat setpoint entity above must then be left empty." + name: "Hardware · Inverter list" + description: "Leave it empty if you have one inverter. With two or more, add one entry per inverter, which replaces the inverter settings above." fields: name: name: "Name" - description: "A short identifier for this inverter, for example inverter-a. It gives this unit its own namespace for its safety latch, heartbeat and write bookkeeping in the add-on's state file, so two units may not share one." + description: "A short, unique name for this inverter, for example inverter-a." setpoint_entity: name: "Setpoint entity" - description: "This inverter's own ESPHome number.*_goodwe_setpoint_w. Two entries may not name the same one - two writers on one actuator is refused at startup." + description: "This inverter's own ESPHome setpoint entity. Two entries may not use the same one." max_w: name: "Inverter rating (W)" - description: "The supervised ceiling on what may be written to THIS inverter; the site's ceiling is the sum over the list. Required of every entry: an entry without one would have to borrow a rating, and judging one inverter against another unit's numbers is exactly the fault this per-entry list exists to remove." + description: "The most power the add-on may ask of this inverter. The site total is the sum of the list." bms_soc_floor: name: "Battery cut-out level (%)" - description: "The percent at which THIS pack's own battery management system cuts out. Read it off the pack that is actually installed (register 0x0560) before that pack is ever commanded; do not copy another unit's figure. Required of every entry, deliberately: an optional one would be a defaulted one, and one default for two batteries of different models protects the shallower pack with the deeper pack's number." + description: "The level at which this battery's own management system stops giving power. Read it off the battery that is installed." soc_entity: name: "Battery level entity (%) (optional)" - description: "This pack's own state of charge. Leave it empty if this unit reports none - that is what it means, and it never falls back to another unit's sensor." + description: "This battery's own level sensor. Leave it empty if this inverter has none." batt_entity: name: "Battery power entity (W) (optional)" - description: "This unit's own battery power, positive while discharging. Leave it empty if this unit reports none; nothing is inherited from another entry." + description: "This inverter's own battery power sensor. Leave it empty if it has none." batt_invert: name: "Battery power sign is reversed (optional)" - description: "Only for this entry: switch it on if this unit's battery power sensor reports discharging as a negative number." + description: "Switch this on if this inverter's sensor shows giving power as a negative number." capacity_kwh: name: "Usable battery capacity (kWh) (optional)" - description: "THIS pack's usable capacity in kilowatt-hours, from its datasheet or its label. It is read for one purpose: dividing the site's target between the inverters by how much ENERGY each pack has left rather than by how many watts it is rated for. The two packs at the reference site are 5000 W with 15.36 kWh and 4600 W with 20.48 kWh, so those two ways of dividing the work hand it to different batteries, and the energy one is the question worth asking. Optional: leave it empty and the add-on has no opinion, dividing the target evenly exactly as it did before. State it on EVERY inverter or on none of them - a pack measured in kWh next to one that is not is not a comparison, and the add-on refuses to start rather than ignore half of what you filled in." + description: "This battery's usable capacity from its datasheet. Fill it in on every inverter or on none, and the work is then shared by energy left." estop_fitted: name: "Hardware · RS485 emergency stop is fitted" - description: "Whether the RS485 emergency stop is physically installed. It only drives the warning banner on the status page; it changes no control behaviour." + description: "Switch this on if the emergency stop is installed. It only changes a warning on the status page." pv_entity: name: "Hardware · Solar production entity (W)" - description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Point it at your solar inverter's own power sensor (any brand Home Assistant reads; it does not have to be on the RS485 bus) and the add-on records production beside the grid and battery figures, so a day of unstored surplus can be told apart from a day with no sun. POSITIVE MUST MEAN PRODUCING - if yours reads negative while producing, list it under 'sign is reversed' below. The unit is read from the entity itself - W, kW and the rest of Home Assistant's power units - so a sensor with no unit is refused rather than guessed at, and the status page says so. Leave it empty and nothing is read, nothing is published and nothing is shown." + description: "Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control." pv_entities: name: "Hardware · Solar production entities, per inverter (W)" - description: "Optional, and MEASUREMENT ONLY - it changes no control behaviour whatsoever. Use this instead of the single entity above when your roof has SEVERAL solar inverters: add one row per inverter, pointing at each one's own power sensor, and the add-on records the SITE total. Each entity's own unit is read, so a kW inverter beside a W one adds up correctly. ⚠️ SETTING THIS IGNORES THE SINGLE ENTITY ABOVE - clear that one when you fill this in, or you will see a caution on the status page saying so. ⚠️ AND IF ANY ONE OF THESE STOPS REPORTING THERE IS NO SITE TOTAL: the sensor goes to 'unknown' and the history records a gap, rather than publishing the sum of the ones that did answer. Two inverters out of three add up to a smaller number that looks exactly like a real one, and a week later that reads as 'there was less sun than there was' - which is the one conclusion this recording exists to test. The status page says which one is missing, by its place in this list. Leave it empty and nothing is read, nothing is published and nothing is shown." + description: "Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded." pv_invert_entities: name: "Hardware · Reversed-sign solar entities" - description: "Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a power clamp in the PV circuit - read NEGATIVE while producing and a few watts POSITIVE at night. Add each such entity here, spelled exactly as it is above, and its sign is flipped before it is added up; leave the others out. The status page marks every flipped entity. History recorded before you set this keeps the old sign." + description: "Optional. Add each solar entity above that reads negative while producing, spelled the same way. Its sign is flipped before adding up." meter_source: name: "Meter · Where the meter reading comes from" - description: "'off' keeps the single Home Assistant entity below, which is what an existing installation runs on until you choose otherwise. ha_dsmr subscribes to the DSMR integration; mqtt_p1 reads an MQTT topic; ha_signed reads one signed entity, which is what a HomeWizard P1 publishes; homewizard_local polls the meter's own local API and skips Home Assistant entirely. ⚠️ Only homewizard_local can tell 'the meter has not answered' apart from 'the value has not changed', so it is the only source on which the frozen-meter alarm means anything." + description: "How the add-on reads your meter. 'off' uses “Grid power entity” below, and only homewizard_local can spot a stuck meter." meter_entity: name: "Meter · Grid power entity (W)" - description: "The net grid power sensor, used when the meter source is 'off'. POSITIVE MUST MEAN DRAWING FROM THE GRID. Get this the wrong way round and the loop drives the battery in the wrong direction; use the sign switch below rather than a template sensor." + description: "Used when the meter source is 'off'. Positive must mean drawing from the grid." meter_invert: name: "Meter · Grid power sign is reversed" - description: "Switch this on if your grid sensor reports drawing from the grid as a negative number." + description: "Switch this on if your grid sensor shows drawing from the grid as a negative number." meter_phases: name: "Meter · Number of phases (1 or 3)" - description: "Must match your connection. A telegram whose phase count disagrees is rejected as it arrives and logged, so a wrong value shows up straight away as 'no telegrams accepted' rather than as a quietly wrong number. The range accepts 2, but that is not a real Belgian connection." + description: "Must match your grid connection. Meter readings with a different number of phases are rejected." p1_host: name: "Meter · HomeWizard P1 address" - description: "For meter source homewizard_local only: the meter's own address on your network, as host or host:port, for example 192.168.2.250." + description: "For homewizard_local only. The meter's address on your network, as host or host:port." meter_poll_s: - name: "Meter · Seconds between meter polls" - description: "For meter source homewizard_local only. 5 s is the meter's own update rate, so there is nothing to gain below it. It must stay well under the staleness limit below - the reading is never fresher than this interval - and the add-on refuses to start if it is at or above that limit." + name: "Meter · Time between meter reads (s)" + description: "For homewizard_local only. The meter updates every 5 s, so lower gains nothing. Keep it well below “Reading too old after”." meter_max_age_s: - name: "Meter · A reading counts as stale after (s)" - description: "Beyond this the grid figure counts as missing. On its own it does not command 0 W: the 'inputs missing' timer under Advanced starts only after this one has expired, and the two stack. 30 s is six polls of headroom at the default poll interval." + name: "Meter · Reading too old after (s)" + description: "After this a meter reading counts as missing. The “Missing inputs time limit” starts only after this one runs out." meter_mqtt_topic: name: "Meter · MQTT topic" - description: "For meter source mqtt_p1 only: the topic the P1 readings are published on." + description: "For mqtt_p1 only. The topic your meter readings are published on." p1_import_entity: - name: "Meter · Import register entity (W)" - description: "The UNSIGNED consumption register. Do not point this at a signed template sensor: the add-on works out net power itself as import minus export, so the sign convention lives in tested code rather than in unreviewed YAML." + name: "Meter · Grid import entity (W)" + description: "The sensor for power drawn from the grid, never negative. The add-on works out the net value itself." p1_export_entity: - name: "Meter · Export register entity (W)" - description: "The UNSIGNED injection register, the counterpart of the import register above. Same rule: no signed template sensor." + name: "Meter · Grid export entity (W)" + description: "The sensor for power fed into the grid, never negative. It pairs with “Grid import entity”." p1_net_entity: name: "Meter · Signed net power entity (W)" - description: "For meter source ha_signed only. ONE signed sensor: positive is drawn from the grid, negative is fed back into it. Do not split it into two template sensors - the add-on does that split itself, so that it is tested." + description: "For ha_signed only. One sensor that is positive when drawing from the grid and negative when feeding in." p1_phase_import_entities: - name: "Meter · Per-phase import entities (L1, L2, L3)" - description: "Optional, in L1..L3 order. Needed for the capacity-tariff quarter-hour peak on a three-phase connection. The number of entries must equal the number of phases above." + name: "Meter · Import entities per phase (L1-L3)" + description: "Optional, in L1, L2, L3 order. Needed for the peak limit on a three-phase connection, one entry per phase." p1_phase_export_entities: - name: "Meter · Per-phase export entities (L1, L2, L3)" - description: "Optional, in L1..L3 order, alongside the per-phase import entities above. The number of entries must equal the number of phases." + name: "Meter · Export entities per phase (L1-L3)" + description: "Optional, in L1, L2, L3 order, next to the import entities per phase. One entry per phase." p1_phase_net_entities: - name: "Meter · Per-phase signed net entities (L1, L2, L3)" - description: "For meter source ha_signed only. Optional, in L1..L3 order, each signed the same way as the net entity above. Same job as the per-phase import and export entities: the capacity-tariff quarter-hour peak on a three-phase connection. The number of entries must equal the number of phases." + name: "Meter · Net entities per phase (L1-L3)" + description: "For ha_signed only. Optional, in L1, L2, L3 order, signed like “Signed net power entity”, one entry per phase." max_w: name: "Limits · Inverter rating (W)" - description: "THIS IS YOUR NUMBER, not a derived one: the hard ceiling on what may ever be commanded, in watts. Set it to what your inverter is actually rated for, start low and raise it once the site has been commissioned. It is not read at all when the inverter list is filled in - each entry then carries its own, and the site ceiling is their sum. Several safety thresholds must stay below it, and the add-on refuses to start if one does not." + description: "Your own number: the most power the add-on may ever ask of the inverter. Start low and raise it after commissioning." bms_soc_floor: name: "Limits · Battery cut-out level (%)" - description: "MEASURED, not chosen: the percent at which the pack's OWN battery management system stops discharging, whatever this add-on is set to. Register 0x0560 reads 10 on the reference GW5000S-BP. Read it off the pack you actually have rather than copying this figure. It is here so the add-on can refuse a capacity-guard floor at or below it: such a floor could never bind, the BMS would win first, and the status page would report an energy backstop that does not exist. Not read when the inverter list is filled in - each entry then states its own pack's cut-out." + description: "The level where the battery's own management system stops giving power. Read it off your battery rather than copying a figure." peak_cap_w: - name: "Limits · Capacity-tariff target (W)" - description: "THIS IS YOUR NUMBER: the quarter-hour average demand the peak guard tries to stay under. Take it from your grid contract - in Belgium it is the capacity-tariff peak your distribution charge is billed on." + name: "Limits · Peak limit (W)" + description: "Your own number: the 15-minute average power the add-on keeps the grid under. Take it from your grid contract." peak_forecast_entity: - name: "Limits · Quarter-hour demand forecast entity (W)" - description: "Optional. A forecast of the current billing quarter's average demand. Leave it empty and there is no capacity cap at all." + name: "Limits · 15-minute demand forecast entity (W)" + description: "Optional. A forecast of this 15-minute period's average power. Leave it empty and there is no peak limit." peak_soc_floor: name: "Limits · Peak reserve (%)" - description: "DERIVED, not picked (SAFETY-24): the reference pack holds 13.8 kWh usable and the worst modelled peak-shaving day asks for 878 Wh, which is 6.4 %, so 20 % sits ten points above the pack's own cut-out and still leaves the guard about 1.6 of its worst observed days of room. ⚠️ IT BOUNDS THE PEAK GUARD ONLY. It is not a reserve for the whole pack: ordinary self-consumption discharges straight past it and goes on down to the battery cut-out, and raising this number does not change that by a tenth of a percent. It must stay strictly above the battery cut-out or the add-on refuses to start. Do not change it without re-deriving it." + description: "Peak limiting will not draw the battery below this level, but ordinary use can. Derived value, leave it unchanged." price_provider: name: "Tariff · Dynamic price source" - description: "Where day-ahead or real-time prices come from. 'off' is what ships, and means this site runs on the static tariff below with no trading. ⚠️ SWITCHING THIS ON IS WHAT STARTS THE PRICE FETCH - not the trading switch further down. With a source selected the add-on fetches the feed every half hour, checks it, records the day and shows what it holds on the Price history row, whether or not price trading is armed. On its own it still moves no energy: trading is the separate switch, and the cheap window the monthly maintenance cycle uses comes from the fixed or day/night tariff below. It may not be combined with the two legacy Home Assistant price entities further down: two price sources on one site, one of which silently wins, is refused at startup rather than left looking armed. ⚠️ THREE IDS IN THIS LIST ARE WITHDRAWN AND WILL NOT START: engie_dynamic, totalenergies_dynamic and eneco_eddy. Their endpoints do not exist and never did, so those plugins never once fetched a price - a site set to one of them has silently been running on the fixed or day/night tariff below, or on nothing, since the day it was set. They are still offered here only so that such a site gets that explanation at startup instead of an unreadable schema error. Choose generic_dayahead for the wholesale curve with a flat markup, custom_formula to enter your own contract's B x index + A coefficients off your tariff card, manual_csv for a file you write yourself, or off." + description: "Where prices come from. Choosing a source starts the price fetch, even with trading off." price_markup_eur_kwh: name: "Tariff · Supplier markup (EUR/kWh)" - description: "Your supplier's margin. The add-on adds it ONLY when the chosen price source does not already include it - under manual_csv, whose figures are all-in, it is ignored, and logged as ignored, never applied twice." + description: "Your supplier's margin. It is added only when the price source does not already include it." price_taxes_eur_kwh: name: "Tariff · Distribution, levies and VAT (EUR/kWh)" - description: "Everything on your bill that is not the energy itself - distribution, levies, excise and VAT - per kWh, added under the same rule as the supplier markup: only when the chosen price source does not already carry them. ⚠️ THIS NUMBER IS NOT A PREFERENCE AND IT IS NOT YOUR INVERTER'S. It ships at 0.11736, DERIVED in TARIFF-18 from the Eneco residential card for Flanders of September 2026 including 6% VAT: Fluvius distribution for Antwerpen 5,35 plus bijzondere accijns 4,876 plus bijdrage groene stroom en WKK 1,51 c/kWh. The energiebijdrage is 0 since 1 August 2026 - it was merged into the excise, so a figure copied from an older guide would count it twice. ⚠️ CHECK IT AGAINST YOUR OWN DSO. Only the distribution row moves: across the eight Fluvius DSOs it runs from 5,28 c/kWh in Midden-Vlaanderen to 6,70 in West-Vlaanderen, so the Flemish total runs from about 0.117 to 0.131. In Wallonia or Brussels the distribution tariff has a separate day and night rate and does not belong in this field at all - use the levies-by-time-of-day option below instead. ⚠️ CHANGING IT MOVES NO TRADING DECISION: the same amount is added to every hour, so it cancels out of both the cheapest hour and the spread. What it does move is every price you are shown, and the rule that refuses to discharge into an hour whose all-in price is below zero." + description: "Grid costs, levies and VAT per kWh, preset for Flanders. Check it against your own grid operator's rates." export_price_eur_kwh: name: "Tariff · Injection price (EUR/kWh)" - description: "What you are paid for feeding a kWh back into the grid, all in. One number rather than a series: no supplier here publishes a dynamic injection curve. In Belgium it is often close to zero, which on its own strongly favours using your own production over exporting it. It may be negative - at midday in summer you can be paying to export." + description: "What you are paid per kWh fed into the grid, all in. It may be negative." static_profile: - name: "Tariff · Fixed or day/night tariff (one line of JSON)" - description: "Your fixed or day/night contract, written as a single line of JSON. RECOMMENDED EVEN ON A DYNAMIC CONTRACT: this is what the add-on falls back to when the price feed dies, and with it empty a dead feed leaves the site with no tariff at all. The periods must cover every day type exactly once, with no gap and no overlap - a gap is refused at startup rather than filled in, because an invented price is one a strategy would trade on. A fully fixed tariff is one period covering 00:00-24:00 on all days. Prices are ALL IN; the markup and levies above are not added to them. Note that a window written 22:00-07:00 for mon-fri does NOT cover Saturday morning, so a weekend row is required rather than decorative." + name: "Tariff · Fixed or day/night tariff (JSON)" + description: "Your fixed or day/night contract as one line of JSON, prices all in. Fill it in even on a dynamic contract, as the fallback when the price feed fails." price_taxes_profile: - name: "Tariff · Levies and VAT by time of day (one line of JSON)" - description: "Leave this empty unless your network tariff really does charge a different day and night rate - in Flanders it does not, Fluvius distribution is one rate, and the flat figure above is correct. In Wallonia and Brussels it does: ORES charges 13,27 c/kWh by day against 7,39 at night, AIESH 15,17 against 8,21, Sibelga 9,39 against 7,10. Written as a single line of JSON in exactly the same shape as the fixed or day/night tariff above, with the same rule that the periods must cover every day type once with no gap and no overlap. ⚠️ THE NUMBERS HERE ARE THE LEVIES ALONE, NOT A FULL PRICE - the add-on adds them to whatever your price source publishes, exactly as it adds the flat figure. Why it matters: a flat figure is the same in every hour, so it moves every hour equally and cannot change which hour is cheapest - and a night network rate is cheap in the same hours the market is cheap, so flattening it makes the add-on think the day is flatter than it is and turn down battery cycles that would have paid for themselves. Set this or the flat figure above, not both: the add-on refuses to start if the two disagree." + name: "Tariff · Day/night levies and VAT (JSON)" + description: "Leave it empty unless your grid operator charges a different day and night rate, as in Wallonia and Brussels. Set this or the flat figure above, not both." price_formula: - name: "Tariff · Your own tariff formula (one line of JSON)" - description: "For price source custom_formula only: your own contract's two coefficients, written as a single line of JSON. Your supplier's tariff card prints the formula as B x index + A - those two numbers exist only on your card, there is no public index of them anywhere, and you are the only person who can read them. Type what the card prints, IN THE UNITS THE CARD PRINTS: every unit conversion and the VAT step are the add-on's job, because those are the two places a human silently loses a factor of 10, 100 or 1.06. Example: {\"index\":\"epex_be\",\"resolution\":\"hourly\",\"factor\":0.102,\"offset\":1.00,\"units\":\"c_eur_per_kwh\",\"vat_pct\":6,\"card\":{\"month\":\"2026-09\",\"index_eur_per_mwh\":133.9905,\"expect_incl_vat\":15.55}}. ⚠️ THE card BLOCK IS REQUIRED AND IT IS WHAT MAKES THIS SAFE: your card also prints the reference index it assumed and the price that comes out, so the add-on recomputes that price from your numbers and REFUSES TO START if it does not come out, telling you by how much. That catches a wrong unit, VAT left out or counted twice, a transposed digit, and the expensive one - network charges folded into the offset, which the add-on would then bill you for a second time. ⚠️ AND ITS LIMIT, IN THE SAME BREATH: it checks your coefficients against your card, not your card against reality, so two numbers copied off the wrong product agree with each other and pass. Fixed numbers only - no expression of any kind is evaluated, and an unrecognised field is refused rather than ignored." + name: "Tariff · Your own tariff formula (JSON)" + description: "For custom_formula only. Type the numbers from your supplier's tariff card as one line of JSON, and the add-on checks them against the card." price_export_formula: - name: "Tariff · Your own INJECTION formula (one line of JSON)" - description: "Optional, and only if your supplier pays you a price that moves with the market. Your tariff card has a SECOND formula for what you are paid for the electricity you export, and it is not the first one with a minus in front: Eneco prints `0,1 x BELPEX-H - 1,188` c/kWh for injection against `0,102 x ...` for consumption, and Aspiravi `0,07 x Belpex - 2`. Written in exactly the same shape as your own tariff formula above. ⚠️ INJECTION IS EXEMPT FROM VAT in Belgium while consumption is at 6%, so vat_pct here is normally 0 - that is the one field people copy across from the other formula and get wrong. ⚠️ THE PRICE THIS GIVES CAN BE NEGATIVE, and that is not an error: Eneco pays below zero whenever BELPEX-H is under 11,88 EUR/MWh, which is the middle of a sunny day - you can be charged to export. The add-on accepts that rather than hiding it. The card block is OPTIONAL here and required above, because Eneco prints the injection formula with NO example price beside it and there would be nothing to check your numbers against; if your card does print one, fill it in and the add-on will refuse to start unless your numbers reproduce it. ⚠️ WHAT THIS DOES NOT DO: no part of the add-on trades on an injection price today - it charges cheap to avoid buying dear, and both sides of that comparison are consumption prices. This is what you are shown, and what a future export strategy would read. Leave it empty and the flat injection price above is used, which is what every installation does now." + name: "Tariff · Your own injection formula (JSON)" + description: "Optional. The injection formula from your tariff card, in the same shape as your own tariff formula. Leave it empty to use the flat injection price." price_csv_path: name: "Tariff · Price CSV file" - description: "For price source manual_csv only: where in /share the add-on reads your own price file from." + description: "For manual_csv only. Where in /share the add-on reads your price file." price_feed_url: name: "Tariff · Price feed URL override" - description: "Leave empty to use the chosen source's own feed. Only a host that source itself declares is accepted, so this cannot be pointed anywhere. WHAT YOU TYPE IS SENT EXACTLY AS WRITTEN: the add-on adds nothing to it, not even the date range it normally asks its own feed for, so an override gets whatever horizon that URL returns - often a single day, with the rest of the plan carried over from yesterday and excluded from price arbitrage. A warning in the log says so on every price refresh. Clear this option to get the full horizon back." + description: "Leave it empty to use the source's own feed. An override is sent exactly as typed and often returns only one day." price_horizon_h: - name: "Tariff · How far ahead to fetch prices (hours)" + name: "Tariff · Price look-ahead (hours)" description: "How many hours of prices to ask the source for." price_timeout_s: name: "Tariff · Price request timeout (s)" - description: "How long a single request to the price source may take before it is given up on." + description: "How long one request to the price source may take before it is given up." price_now_entity: - name: "Tariff · Current price entity (older price path)" - description: "The older way of getting a price, kept because retiring it would take the maintenance cycle's only price signal away from a live installation. The add-on reads this and the average below and derives exactly one thing from them - whether now is cheaper than average - which only the maintenance cycle's cheap-window charging uses. It may not be combined with a dynamic price source." + name: "Tariff · Current price entity (older)" + description: "The older way to get a price, used only to charge in a cheap window during maintenance. Do not combine it with a dynamic price source." price_avg_entity: - name: "Tariff · Average price entity (older price path)" - description: "The average the current price is compared against. Only meaningful together with the current-price entity above, and like it, may not be combined with a dynamic price source." + name: "Tariff · Average price entity (older)" + description: "The average the current price is compared with. Use it only with the current price entity, not with a dynamic price source." arbitrage_enabled: name: "Tariff · Trade on the price spread" - description: "Charge in the cheapest published hour and discharge in the dearest, but only when the spread covers what the round trip costs. OFF in the shipped configuration, deliberately: this is the first strategy in the add-on that moves energy against the meter on purpose, so it is armed on purpose or not at all. ⚠️ LEAVING IT OFF DOES NOT TURN THE PRICE FEED OFF. A price source selected above is fetched, checked and recorded either way; this switch decides only whether the add-on ACTS on those prices. It needs both a price source and a P1 meter, and the add-on refuses the combinations that cannot work rather than letting them look armed." + description: "Charge in the cheapest hour and draw the battery down in the dearest, when the spread covers the cost. Turning it off does not turn the price feed off." cycle_cost_threshold_eur: - name: "Tariff · Cost of one full charge/discharge cycle (EUR/kWh)" - description: "What one full round trip costs per kWh: wear on the pack plus conversion losses. A price spread smaller than this loses money and battery life, so it is not traded. ⚠️ THIS ONE IS NOT DERIVED FROM A MEASUREMENT. 0.10 is a product decision and it is still an open question with the owner (OPT-08). At this value a fixed day/night site does not trade at all - the realistic Belgian day/night spread is about 0.08 EUR/kWh - and that is the correct verdict at this number, not a fault." + name: "Tariff · Battery cycle cost (EUR/kWh)" + description: "What one full battery cycle costs per kWh. A smaller price spread is not traded, and the value is a product choice, not a measured one." arbitrage_soc_floor: - name: "Tariff · Trading may not discharge below (%)" - description: "The reserve price trading may not spend. Deliberately not the same key as the maintenance floor: pointing a trading strategy at the monthly balancing cycle's numbers would couple two unrelated policies through one setting." + name: "Tariff · Trading keeps at least (%)" + description: "Price trading will not draw the battery below this level. It is separate from the maintenance settings." arbitrage_soc_ceiling: - name: "Tariff · Trading may not charge above (%)" - description: "The headroom price trading may not fill. The counterpart of the trading floor above, and kept separate from the maintenance target for the same reason." + name: "Tariff · Trading charges at most (%)" + description: "Price trading will not charge the battery above this level." maintenance_enabled: name: "Maintenance · Run the monthly battery cycle" - description: "A deliberate deep discharge followed by a full recharge and a hold, so the battery management system can recalibrate its charge estimate and balance the cells. Off by default." + description: "Once a month, empty the battery deeply, charge it full and hold it there, so its level reading stays accurate. Off by default." maintenance_interval_days: name: "Maintenance · Minimum days between cycles" description: "The shortest gap between two maintenance cycles." maintenance_start_hour: - name: "Maintenance · Hour of day a due cycle starts" - description: "Local hour, 0 to 23, at which a cycle that has become due begins." + name: "Maintenance · Start hour" + description: "The local hour, 0 to 23, at which a due cycle starts." maintenance_discharge_w: - name: "Maintenance · Discharge rate (W)" - description: "How fast the cycle drains the pack; the surplus is exported. Above the inverter rating it is CLAMPED to the rating rather than refused - the cycle still completes, just more slowly, and the status page says so. It ships at 2000 to match the shipped rating; raise the rating first, then this." + name: "Maintenance · Draw-down rate (W)" + description: "How fast the cycle empties the battery. Above “Inverter rating” it is cut back to the rating, and the cycle just takes longer." maintenance_charge_w: name: "Maintenance · Recharge rate (W)" - description: "⚠️ MUST STAY AT OR BELOW the inverter rating, and the add-on refuses to start otherwise. Above it, the cheap-window charge shaping asks for more than the supervised limit allows, the arbiter resolves that contradiction to 0 W, and maintenance would silently never charge in a cheap window on a default installation. It is also capped again by whatever headroom the peak guard leaves." + description: "How fast the cycle recharges the battery. It must be at or below “Inverter rating”, or the add-on will not start." maintenance_soc_floor: - name: "Maintenance · Discharge down to (%)" - description: "The depth the monthly recalibration deliberately goes to, once a month, on purpose. ⚠️ THIS IS NOT THE PEAK GUARD'S FLOOR: that one is the depth a money-saving discharge may never reach on any day. The right values genuinely differ - 11 here against 20 there - which is why they are two separate settings and must not be merged." + name: "Maintenance · Draw down to (%)" + description: "The level the monthly cycle empties the battery to. It is not the “Peak reserve”, and the two differ on purpose." maintenance_soc_target: name: "Maintenance · Recharge up to (%)" - description: "The level the recharge phase aims for before the hold begins." + description: "The level the recharge aims for before the hold starts." maintenance_hold_min: name: "Maintenance · Hold at full for (minutes)" - description: "How long to sit at the target so the battery management system can finish balancing the cells." + description: "How long the battery stays full so its cells can balance." sign_disagree_w: - name: "Safety · Sign watchdog threshold (W) — measured, do not change" - description: "MEASURED, NOT CHOSEN (SAFETY-02). Both the setpoint being emitted and the grid reading must exceed this before their opposite signs count as a disagreement at all. On the captured healthy day (2026-08-23) sign agreement over the gated samples is 93.4 %; on the captured fault day (2026-08-20) the clusters run 0.0-10.5 % with opposed runs up to 1752 s. There is no reason to move this without a new capture that says so. It must stay below the inverter rating or the watchdog can never fire, and the add-on refuses that configuration." + name: "Safety · Wrong-direction threshold (W)" + description: "A wrong direction counts only when the command and the meter reading both exceed this. Measured value, leave it unchanged." sign_disagree_s: - name: "Safety · Sign watchdog hold (s) — measured, do not change" - description: "MEASURED, NOT CHOSEN (SAFETY-02). How long the setpoint and the meter must stay opposed, continuously, before the add-on commands 0 W and latches until an operator starts control again. 180 s sits in the middle of a very wide measured gap: the longest legitimate opposed run on the healthy day is 30 s, while the fault day still trips 13 times at 300 s. Do not change it without a new capture." + name: "Safety · Wrong-direction time (s)" + description: "How long a wrong direction may last before a safety stop sets every inverter to 0 W. Measured value, leave it unchanged." unit_sign_disagree_w: - name: "Safety · Per-inverter sign threshold (W) — derived, do not change" - description: "TWO OR MORE INVERTERS ONLY; with one inverter this setting does nothing at all. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS on the two-master rig (SAFETY-30), in which nothing was faulty, swept across the whole range this add-on accepts for loop gain and slew rate. 250 W is exactly half the saturation threshold, so the smallest divergence this can see is precisely the gap at which the control law itself already says the inverter is not following. Do not change it without re-deriving it. It must stay below the inverter rating or it can never fire." + name: "Safety · Per-inverter wrong-direction threshold (W)" + description: "For two or more inverters: the wrong-direction threshold for each inverter. Derived value, leave it unchanged." unit_sign_disagree_s: - name: "Safety · Per-inverter sign hold (s) — derived, do not change" - description: "TWO OR MORE INVERTERS ONLY. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS (SAFETY-30): 85 s is 8.5 times the worst legitimate opposition those runs produce (10.0 s), 2.8 times the firmware's own 30 s link veto, and under half the 180 s the site-wide check takes. Do not change it without re-deriving it." + name: "Safety · Per-inverter wrong-direction time (s)" + description: "For two or more inverters: how long one inverter may push the wrong way before it is set to 0 W. Derived value, leave it unchanged." site_sign_disagree_w: - name: "Safety · Site-wide sign threshold (W) — measured, do not change" - description: "TWO OR MORE INVERTERS ONLY. The same 300 W as the single-inverter threshold, CARRIED ACROSS DELIBERATELY (SAFETY-30): the argument behind it does not depend on how many inverters there are - near zero the sign is noise, the deadband is 15 W, and there is one meter whatever is behind it. Do not change it without a capture that says so." + name: "Safety · Site wrong-direction threshold (W)" + description: "For two or more inverters: the wrong-direction threshold for the whole site. Measured value, leave it unchanged." site_sign_disagree_s: - name: "Safety · Site-wide sign hold (s) — derived, do not change" - description: "TWO OR MORE INVERTERS ONLY. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS (SAFETY-30), and deliberately NOT carried across from the single-inverter 180 s. On those runs the worst legitimate opposition at 300 W is 110 s with one inverter and 215 s with two, because the command has to travel the whole site rail at a slew rate that is not the site's - so carrying 180 s across would have shipped a false trip reachable at the lowest gain and slew with an ordinary 2.2 kW load reversal. 325 s is 1.51 times that, still inside the 900 s billing quarter, and still inside every episode of the captured fault day. Do not change it without re-deriving it." + name: "Safety · Site wrong-direction time (s)" + description: "For two or more inverters: how long the whole site may push the wrong way before a safety stop. Derived value, leave it unchanged." meter_freeze_s: - name: "Safety · Frozen-meter alarm after (s) — measured, do not change" - description: "MEASURED, NOT CHOSEN (SAFETY-18). How long the meter may keep answering with an UNCHANGED reading, while the command stands at the rail, before the add-on raises an alarm. Over 2399 s of this house at its settled operating point - 1194 polls, 735 of them repeating the previous reading - the longest run without a distinct reading is 15.4 s; 300 s is 19.5 times that and still inside the 900 s billing quarter. ALARM ONLY: it does not command 0 W and does not latch. ⚠️ Only the homewizard_local meter source can see this at all; on every other source the status page says NOT COVERED rather than armed. Do not change it without re-deriving it." + name: "Safety · Stuck meter alarm after (s)" + description: "An alarm when the meter repeats one reading this long while the command is at full power, with homewizard_local only. Measured value, leave it unchanged." circulation_w: - name: "Safety · Circulating-power threshold (W) — measured, do not change" - description: "TWO OR MORE INVERTERS ONLY; with one inverter the quantity is identically zero. Two inverters pushing against each other net out to zero at the meter and are invisible to every other guard in this add-on. MEASURED ON 924 CLOSED-LOOP TEST RUNS in which nothing was faulty (SAFETY-31): the worst legitimate opposition collapses from 505 s at a 100 W threshold to 5 s at 400 W, and 400 W is the sharp knee this add-on will not let you go below - under it, ordinary operation holds the sensor over the threshold for minutes and nothing shorter than the billing quarter could tell that from a fault. 700 W is 1.75 times the knee, and the extra margin is there because the second inverter's ramp and lag are still copied from the first one rather than measured. Do not change it without re-deriving it." + name: "Safety · Opposing inverters threshold (W)" + description: "For two or more inverters: how much power one may push against another before it counts. Measured value, leave it unchanged." circulation_hold_s: - name: "Safety · Circulating-power hold (s) — derived, do not change" - description: "TWO OR MORE INVERTERS ONLY. DERIVED (SAFETY-31): 75 s is fifteen control cycles - 15 times the worst legitimate episode the rig can produce, 2.5 times the firmware's own 30 s link veto, and twelve times inside the 900 s billing quarter. It is deliberately not a round 60 or 120, which would be a guess wearing a measurement's clothes. Do not change it without re-deriving it." + name: "Safety · Opposing inverters time (s)" + description: "For two or more inverters: how long they may push against each other before a safety stop. Derived value, leave it unchanged." delivery_hold_s: - name: "Safety · Not-delivering report after (s) — derived, do not change" - description: "TWO OR MORE INVERTERS ONLY; with one inverter this check cannot fire at all, and that is deliberate rather than a limitation. How long ONE inverter may stand at a discharge share it is not producing - short by more than the saturation threshold, with nothing this add-on can read to explain it - while at least one sibling is NOT in that state, before it is named. REPORTS ONLY (SAFETY-42): nothing is commanded differently, the loop is untouched, and the site goes on running short by that unit's share until you look. DERIVED FROM 2640 CLOSED-LOOP TEST RUNS in which nothing was faulty (SAFETY-42, plus a one-inverter arm as the control, which reports nothing at any threshold): the worst legitimate episode those runs produce is 35.0 s, and the ceiling is the 900 s quarter that bills the capacity tariff. 185 s is 5.29 times that. ⚠️ The schema lets you set this as low as 30 s, which is BELOW that measured 35.0 s - at 30 s you should expect reports on legitimate saturation. The second inverter in those tests is a COPY OF THE FIRST, because the second inverter does not exist yet: what a unit four times slower would produce (75.0 s) is a sensitivity study on that idea, not a measurement of any real second inverter. Do not change it without re-deriving it - and it can be re-derived now: admin/goodwe sim/delivery_window.py --campaign --blag (TEST-21). A pack at or below its own bms_soc_floor is never reported: an empty pack and a wedged one are identical watt for watt, and that setting is the only thing that tells them apart - so if this fires on a pack you believe is empty, that setting does not describe your battery." + name: "Safety · Not delivering alarm after (s)" + description: "For two or more inverters: how long one may fall short of its share before an alarm, which changes nothing. Derived value, leave it unchanged." shadow_mode: - name: "Safety · Shadow mode — run every decision, command nothing" - description: "Runs the whole decision path — strategies, arbiter, clamps and guards — and sends NOTHING to the inverter. Every inverter is held at 0 W, refreshed on the ordinary heartbeat, and the status page says plainly that the battery is not being controlled; the decision it WOULD have commanded, and why, is on the status page and in the action log. This is how you watch a site for a day before letting it trade. 'auto' (the shipped value) means shadow mode while control is stopped and ordinary control once you press Start — so a NEW install observes before it ever commands anything, and an install that is already controlling is not changed by one watt. 'on' means shadow mode always, whatever the Start / stop button says: that is the setting to pick when you want the loop and the strategies running on a live site with nothing reaching the battery. 'off' is ordinary control. ⚠️ While this is on the battery is NOT being regulated — the grid is not held at zero, no arbitrage trade is executed and no capacity peak is shaved. ⚠️ A failsafe latch that was already up stays up: shadow mode does not clear it, and the banner names it." + name: "Safety · Shadow mode" + description: "The add-on makes every decision but keeps every inverter at 0 W. 'auto' does this while control is stopped, 'on' always, 'off' never." auto_start: - name: "Advanced · Start controlling automatically on boot" - description: "Off by default. Leave it off until the site has been commissioned: with it off, somebody has to press Start after every restart of the add-on, which is what you want while you are still checking signs and entities." + name: "Advanced · Start control on boot" + description: "Off by default. Leave it off until the site is commissioned, so someone presses Start after each restart." gain: - name: "Advanced · Loop gain" - description: "How much of the remaining error the loop corrects each cycle. MEASURED ON REAL HARDWARE and already at the limit - do not raise it. Lower is slower and safer." + name: "Advanced · Control gain" + description: "How much of the remaining error control corrects each cycle. Measured on real hardware, do not raise it." slew_w: name: "Advanced · Largest change per cycle (W)" - description: "How far the setpoint may move in one control cycle. ⚠️ 0 MEANS FOLLOW THE INVERTER RATING and is the recommended setting: the limit becomes about a ninth of the rating, so the loop takes the plant's own MEASURED settling time to cross its whole output range and the number cannot be left behind when the rating changes. DERIVED (SAFETY-39) from an ~18 s measured step response against a 2 s meter tick. A fixed number is accepted and is never silently reduced, but a number faster than the rating allows is refused at startup - at 1000 W against a 5000 W rating this loop drove the meter from 3.4 kW of export to 2.8 kW of import on 2026-09-05. Lower is always accepted." + description: "How far the command may move in one cycle. 0 follows “Inverter rating” and is recommended." deadband_w: - name: "Advanced · Deadband (W)" - description: "Errors smaller than this are ignored. ⚠️ The deadband is a one-way ratchet: any resting point inside it holds forever, and the meter's import register counts every positive watt with no export to cancel it - which is exactly why the resting point below is slightly negative." + name: "Advanced · Ignore errors below (W)" + description: "Errors smaller than this are ignored. Keep it small, since any resting point inside it holds." target_grid_w: - name: "Advanced · Resting point at the meter (W)" - description: "What the meter should sit at when nothing is happening; negative means a slight export. -10 W is deliberate: resting at 0 W leaks about half the deadband in billed import all day - roughly 0.2 to 0.35 kWh at a 15 W deadband - and biasing the rest point below zero moves that leak into the export register, which is not billed. It costs about this many watts of given-away export, so keep it small." + name: "Advanced · Meter resting point (W)" + description: "What the meter should show when nothing happens. A slight export avoids paying for tiny imports all day." step_w: - name: "Advanced · Setpoint quantisation (W)" - description: "The setpoint is rounded to a multiple of this before it is written, so the inverter is not handed a new number for every watt of noise." + name: "Advanced · Command rounding (W)" + description: "The command is rounded to a multiple of this, so noise does not change it every cycle." saturation_w: - name: "Advanced · Saturation threshold (W)" - description: "The gap between what was commanded and what the inverter delivers that counts as 'this inverter is at a limit'. ⚠️ The per-inverter sign threshold under Safety is derived as exactly half of this, so moving this moves that measurement's argument with it." + name: "Advanced · Inverter at limit gap (W)" + description: "When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this." saturation_cycles: - name: "Advanced · Saturated cycles before freezing (count)" - description: "How many consecutive saturated cycles before the loop stops winding up. ⚠️ Do not set this to 1: a single noisy cycle would then freeze the loop." + name: "Advanced · Cycles at limit before freezing" + description: "How many cycles in a row at the limit before control stops building up error. Do not set it to 1." integrator_max_w: - name: "Advanced · Integrator bound (W, 0 means the same as the rating)" - description: "Caps how much stale error can be waiting to unwind when the sign flips. MEASURED on the closed-loop simulator with a 4000 W load dropped to zero: at a bound equal to the rating the command is 1000 W two cycles later, at 1.5 times the rating it is 1800 W. ⚠️ Do not raise it above the inverter rating - the output clamp already bounds what reaches the wire, so extra headroom buys nothing but wrong-direction watts after every saturation event. Lowering it below the rating is the useful direction, and the only reason this is a separate setting." + name: "Advanced · Error build-up limit (W)" + description: "Limits how much old error control can carry, and 0 means “Inverter rating”. Do not raise it above the rating." heartbeat_s: - name: "Advanced · Setpoint refresh interval (s)" - description: "How often the setpoint is rewritten even when it has not changed. It must stay well under the firmware's own watchdog, which vetoes a link that has been quiet for 30 s." + name: "Advanced · Command refresh interval (s)" + description: "How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit." stale_input_s: - name: "Advanced · Command 0 W after inputs missing for (s)" - description: "How long the inputs may be missing before the add-on commands 0 W. With a P1 meter this clock starts only AFTER the meter staleness limit has already expired, so the two stack: the total is longer than this number on its own." + name: "Advanced · Missing inputs time limit (s)" + description: "How long inputs may be missing before every inverter is set to 0 W. With a P1 meter it starts after “Reading too old after”." cycle_floor_s: - name: "Advanced · Longest gap between control cycles (s)" - description: "A deadline on the gap between cycles, reset by every cycle. On a healthy meter it never elapses and changes nothing. Raise it only if your meter is slower than about 10 s, and keep it under the meter staleness limit - past that there is no reading left to evaluate anyway." + name: "Advanced · Longest time between cycles (s)" + description: "A deadline between control cycles that a healthy meter never reaches. Raise it only for a meter slower than about 10 s." log_level: name: "Advanced · Log level" - description: "How much detail the add-on writes to its log. 'info' is the shipped setting; 'debug' and 'trace' are for diagnosing a problem and are noisy." + description: "How much detail the add-on writes to its log. 'debug' and 'trace' are for finding a problem." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index 2818589..41deae8 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -16,267 +16,266 @@ # volgorde van het `schema:`-blok van config.yaml; de volgorde hieronder is # alleen een spiegel daarvan, zodat beide bestanden gelijk lezen. # -# ⚠️ AFGELEIDE CONSTANTEN VERMELDEN WAAR ZE VANDAAN KOMEN. Het tabblad toont een -# getal dat uit 1890 gesloten-lustests komt en het omvormervermogen van de -# eigenaar als hetzelfde soort veld. De beschrijving is de enige plek waar dat -# verschil gezegd kan worden. +# Namen en beschrijvingen volgen STYLE.md (UX-08): een kort label met de +# eenheid, en een of twee eenvoudige zinnen. Waar een gemeten of afgeleide +# waarde vandaan komt, staat in DOCS.md onder "For installers". configuration: setpoint_entity: name: "Hardware · Setpoint-entiteit van de omvormer" - description: "De ESPHome number-entiteit waar deze add-on het vermogen naartoe schrijft, meestal number.*_goodwe_setpoint_w. Dit is het enige wat de add-on aanstuurt. Laat leeg als u hieronder de lijst met omvormers invult: een installatie met een lijst mag niet óók één losse aansturing hebben, en de add-on start dan niet op." + description: "De ESPHome-entiteit waar de add-on het vermogen van de omvormer naartoe schrijft. Laat dit leeg als u de lijst met omvormers invult." soc_entity: - name: "Hardware · Entiteit met het laadniveau van de batterij (%)" - description: "De sensor die de laadtoestand van de batterij in procent doorgeeft. Gebruik de meting van de ESP32 zelf, geen waarde die elders berekend wordt. De onderhoudscyclus en alle ondergrenzen voor het laadniveau lezen deze sensor." + name: "Hardware · Entiteit laadniveau (%)" + description: "De sensor met het laadniveau van de batterij in procent. Gebruik de meting van de stuurprint zelf." batt_entity: - name: "Hardware · Entiteit met het batterijvermogen (W)" - description: "De sensor die het batterijvermogen van deze omvormer doorgeeft, positief bij ontladen. Op deze installatie is dat holding register 0x0518, uitgelezen door de ESP32. Zowel de tekenbewaking als het alarm voor rondpompend vermogen beoordelen de omvormer aan de hand van deze meting." + name: "Hardware · Entiteit batterijvermogen (W)" + description: "De sensor met het batterijvermogen van deze omvormer. Positief moet betekenen dat de batterij stroom levert." batt_invert: - name: "Hardware · Teken van het batterijvermogen omkeren" - description: "Zet dit alleen aan als uw sensor ontladen als een negatief getal doorgeeft. De add-on gaat ervan uit dat positief ontladen betekent." + name: "Hardware · Teken batterijvermogen omkeren" + description: "Zet dit alleen aan als uw sensor het leveren van stroom als een negatief getal toont." inverters: - name: "Hardware · Lijst met omvormers (leeg laten bij één omvormer)" - description: "Laat dit leeg tenzij er echt meer dan één omvormer staat. LEEG BETEKENT NIET 'nog niet ingesteld': het betekent dat de vier entiteiten hierboven, samen met het omvormervermogen en de uitschakelgrens van de batterij onder Grenzen, de ene omvormer beschrijven die u hebt. Dat is wat elke bestaande installatie leest, zonder dat iemand iets hoeft aan te passen. Vult u de lijst wel in, dan VERVANGT die de instellingen hierboven in plaats van ze aan te vullen, en wordt er niets overgenomen: elk item moet zijn eigen aansturing, zijn eigen vermogen en zijn eigen uitschakelgrens vermelden, zodat geen enkele omvormer ooit beoordeeld wordt op de cijfers van een andere. De losse setpoint-entiteit hierboven moet dan leeg blijven." + name: "Hardware · Lijst met omvormers" + description: "Laat dit leeg als u één omvormer hebt. Hebt u er meer, voeg dan per omvormer een item toe. De lijst vervangt dan de instellingen hierboven." fields: name: name: "Naam" - description: "Een korte aanduiding voor deze omvormer, bijvoorbeeld inverter-a. Ze geeft deze omvormer een eigen naamruimte voor haar veiligheidsvergrendeling, hartslag en schrijfadministratie in het statusbestand van de add-on, dus twee omvormers mogen er niet één delen." + description: "Een korte, unieke naam voor deze omvormer, bijvoorbeeld inverter-a." setpoint_entity: name: "Setpoint-entiteit" - description: "De eigen ESPHome-entiteit number.*_goodwe_setpoint_w van deze omvormer. Twee items mogen niet dezelfde entiteit noemen - twee schrijvers op één aansturing wordt bij het opstarten geweigerd." + description: "De eigen ESPHome-setpoint-entiteit van deze omvormer. Twee items mogen niet dezelfde gebruiken." max_w: name: "Vermogen van deze omvormer (W)" - description: "De bewaakte bovengrens van wat er naar DEZE omvormer geschreven mag worden; het plafond van de installatie is de som over de lijst. Verplicht bij elk item: een item zonder deze waarde zou een vermogen moeten lenen, en een omvormer beoordelen op de cijfers van een andere is precies de fout die deze lijst per omvormer moet wegnemen." + description: "Het hoogste vermogen dat de add-on aan deze omvormer mag vragen. Het totaal van de installatie is de som van de lijst." bms_soc_floor: name: "Uitschakelniveau van de batterij (%)" - description: "Het percentage waarbij het batterijmanagementsysteem van DEZE batterij uitschakelt. Lees dit af van de batterij die er werkelijk staat (register 0x0560) voordat die batterij ooit aangestuurd wordt; neem geen waarde van een andere omvormer over. Bewust verplicht bij elk item: optioneel maken zou neerkomen op een standaardwaarde, en één standaardwaarde voor twee verschillende batterijen beschermt de kleinste batterij met het getal van de grootste." + description: "Het niveau waarop het beheersysteem van deze batterij stopt met leveren. Lees het af van de batterij die er staat." soc_entity: - name: "Entiteit met het laadniveau (%) (optioneel)" - description: "Het laadniveau van deze batterij zelf. Laat leeg als deze omvormer dat niet doorgeeft - dat is wat het betekent, en er wordt nooit teruggevallen op de sensor van een andere omvormer." + name: "Entiteit laadniveau (%) (optioneel)" + description: "De eigen sensor voor het laadniveau van deze batterij. Laat leeg als deze omvormer er geen heeft." batt_entity: - name: "Entiteit met het batterijvermogen (W) (optioneel)" - description: "Het batterijvermogen van deze omvormer zelf, positief bij ontladen. Laat leeg als deze omvormer dat niet doorgeeft; er wordt niets van een ander item overgenomen." + name: "Entiteit batterijvermogen (W) (optioneel)" + description: "De eigen sensor voor het batterijvermogen van deze omvormer. Laat leeg als die er niet is." batt_invert: - name: "Teken van het batterijvermogen omkeren (optioneel)" - description: "Alleen voor dit item: zet dit aan als de sensor van deze omvormer ontladen als een negatief getal doorgeeft." + name: "Teken batterijvermogen omkeren (optioneel)" + description: "Zet dit aan als de sensor van deze omvormer leveren als een negatief getal toont." capacity_kwh: - name: "Bruikbare capaciteit van de batterij (kWh) (optioneel)" - description: "De bruikbare capaciteit van DEZE batterij in kilowattuur, van het datablad of het typeplaatje. Ze wordt voor één ding gelezen: het verdelen van de doelwaarde van de installatie over de omvormers volgens hoeveel ENERGIE elke batterij nog heeft, in plaats van volgens het vermogen waarvoor ze gebouwd is. De twee batterijen op de referentiesite zijn 5000 W met 15,36 kWh en 4600 W met 20,48 kWh, dus die twee manieren van verdelen wijzen het werk aan verschillende batterijen toe, en de energieverdeling is de juiste vraag. Optioneel: laat leeg en de add-on heeft geen voorkeur en verdeelt gelijk, precies zoals voordien. Vul ze in bij ELKE omvormer of bij geen enkele - een batterij in kWh naast een batterij zonder waarde is geen vergelijking, en de add-on start liever niet op dan de helft van wat u invulde te negeren." + name: "Bruikbare capaciteit (kWh) (optioneel)" + description: "De bruikbare capaciteit van deze batterij, van het datablad. Vul ze bij elke omvormer in of bij geen enkele. Het werk wordt dan verdeeld volgens de energie die over is." estop_fitted: name: "Hardware · RS485-noodstop is geplaatst" - description: "Of de RS485-noodstop fysiek geïnstalleerd is. Dit stuurt alleen de waarschuwingsbalk op de statuspagina aan en verandert niets aan de regeling." + description: "Zet dit aan als de noodstop geïnstalleerd is. Het verandert alleen een waarschuwing op de statuspagina." pv_entity: - name: "Hardware · Zonneproductie-entiteit (W)" - description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Verwijs naar de vermogenssensor van je omvormer (elk merk dat Home Assistant kan lezen; hij hoeft niet op de RS485-bus te zitten) en de add-on registreert de productie naast de meter- en batterijwaarden, zodat een dag met niet-opgeslagen overschot te onderscheiden is van een dag zonder zon. POSITIEF MOET PRODUCEREN BETEKENEN - leest de uwe negatief tijdens productie, zet hem dan ook bij 'teken omgekeerd' hieronder. De eenheid wordt van de entiteit zelf gelezen - W, kW en de overige vermogenseenheden van Home Assistant - dus een sensor zonder eenheid wordt geweigerd in plaats van geraden, en de statuspagina zegt waarom. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." + name: "Hardware · Entiteit zonneproductie (W)" + description: "Optioneel. De vermogenssensor van uw zonne-omvormer, positief tijdens productie. De add-on houdt ze bij en regelt er niet mee." pv_entities: - name: "Hardware · Zonneproductie-entiteiten, één per omvormer (W)" - description: "Optioneel, en UITSLUITEND EEN METING - het verandert niets aan de regeling. Gebruik dit in plaats van de losse entiteit hierboven wanneer uw dak MEERDERE zonne-omvormers heeft: voeg één rij per omvormer toe, elk verwijzend naar haar eigen vermogenssensor, en de add-on registreert het totaal van de installatie. De eenheid van elke entiteit wordt afzonderlijk gelezen, dus een omvormer in kW naast een in W telt correct op. ⚠️ ALS U DIT INVULT WORDT DE LOSSE ENTITEIT HIERBOVEN GENEGEERD - maak die leeg, anders verschijnt er een waarschuwing op de statuspagina die dat meldt. ⚠️ EN ALS ÉÉN VAN DEZE ENTITEITEN NIETS MEER DOORGEEFT, IS ER GEEN TOTAAL: de sensor gaat naar 'unknown' en de geschiedenis bewaart een gat, in plaats van de som van de entiteiten die wél antwoordden te publiceren. Twee omvormers van de drie tellen op tot een kleiner getal dat precies op een echt getal lijkt, en een week later leest dat als 'er was minder zon dan er was' - net de conclusie die deze registratie moet kunnen testen. De statuspagina zegt welke ontbreekt, met zijn plaats in deze lijst. Laat leeg en er wordt niets gelezen, niets gepubliceerd en niets getoond." + name: "Hardware · Entiteiten zonneproductie, per omvormer (W)" + description: "Optioneel. Eén rij per zonne-omvormer, in plaats van de losse entiteit hierboven, als u er meerdere hebt. Valt er één weg, dan wordt er geen totaal bijgehouden." pv_invert_entities: - name: "Hardware · Zonneproductie-entiteiten met omgekeerd teken" - description: "Optioneel, UITSLUITEND EEN METING. Sommige sensoren - meestal een kWh-meter of een stroomtang in het PV-circuit - lezen NEGATIEF tijdens productie en 's nachts enkele watt POSITIEF. Zet elke zulke entiteit hier, exact gespeld zoals hierboven, en haar teken wordt omgedraaid vóór het optellen; laat de andere weg. De statuspagina markeert elke omgedraaide entiteit. Geschiedenis van vóór deze instelling behoudt het oude teken." + name: "Hardware · Zonne-entiteiten met omgekeerd teken" + description: "Optioneel. Zet hier elke zonne-entiteit van hierboven die negatief leest tijdens productie, precies zo gespeld. Het teken wordt omgedraaid voor het optellen." meter_source: name: "Meter · Waar de meterstand vandaan komt" - description: "'off' houdt de losse Home Assistant-entiteit hieronder aan, waar een bestaande installatie op draait tot u iets anders kiest. ha_dsmr luistert mee met de DSMR-integratie; mqtt_p1 leest een MQTT-topic; ha_signed leest één entiteit met teken, wat een HomeWizard P1 publiceert; homewizard_local bevraagt de lokale API van de meter zelf en slaat Home Assistant helemaal over. ⚠️ Alleen homewizard_local kan 'de meter heeft niet geantwoord' onderscheiden van 'de waarde is niet veranderd', en is dus de enige bron waarop het alarm voor een vastgelopen meter iets betekent." + description: "Hoe de add-on uw meter uitleest. Met 'off' gebruikt ze de entiteit netvermogen hieronder. Alleen homewizard_local merkt een vastgelopen meter op." meter_entity: - name: "Meter · Entiteit met het netvermogen (W)" - description: "De sensor met het netto netvermogen, gebruikt wanneer de meterbron 'off' is. POSITIEF MOET AFNAME VAN HET NET BETEKENEN. Staat dit omgekeerd, dan stuurt de regeling de batterij de verkeerde kant op; gebruik daarvoor de tekenschakelaar hieronder en geen template-sensor." + name: "Meter · Entiteit netvermogen (W)" + description: "Gebruikt als de meterbron 'off' is. Positief moet afname van het net betekenen." meter_invert: - name: "Meter · Teken van het netvermogen omkeren" - description: "Zet dit aan als uw netsensor afname van het net als een negatief getal doorgeeft." + name: "Meter · Teken netvermogen omkeren" + description: "Zet dit aan als uw netsensor afname als een negatief getal toont." meter_phases: name: "Meter · Aantal fasen (1 of 3)" - description: "Moet overeenkomen met uw aansluiting. Een telegram met een ander aantal fasen wordt bij binnenkomst geweigerd en gelogd, zodat een verkeerde waarde meteen zichtbaar wordt als 'geen telegrammen aanvaard' in plaats van als een stil verkeerd getal. Het bereik aanvaardt 2, maar dat is geen echte Belgische aansluiting." + description: "Moet overeenkomen met uw aansluiting. Meterstanden met een ander aantal fasen worden geweigerd." p1_host: name: "Meter · Adres van de HomeWizard P1" - description: "Alleen voor meterbron homewizard_local: het adres van de meter zelf op uw netwerk, als host of host:poort, bijvoorbeeld 192.168.2.250." + description: "Alleen voor homewizard_local. Het adres van de meter op uw netwerk, als host of host:poort." meter_poll_s: - name: "Meter · Seconden tussen twee uitlezingen" - description: "Alleen voor meterbron homewizard_local. 5 s is het tempo waarin de meter zelf ververst, dus lager instellen levert niets op. Deze waarde moet ruim onder de verouderingsgrens hieronder blijven - de meting is nooit verser dan dit interval - en de add-on start niet op als ze eraan gelijk is of erboven ligt." + name: "Meter · Tijd tussen twee uitlezingen (s)" + description: "Alleen voor homewizard_local. De meter ververst elke 5 s, lager levert niets op. Houd dit ruim onder de grens voor een te oude meting." meter_max_age_s: - name: "Meter · Een meting is verouderd na (s)" - description: "Daarna geldt de netwaarde als ontbrekend. Op zichzelf stuurt dit nog geen 0 W aan: de teller 'invoer ontbreekt' onder Geavanceerd begint pas te lopen nadat deze verstreken is, en de twee stapelen. 30 s is zes uitlezingen speling bij het standaard uitleesinterval." + name: "Meter · Meting te oud na (s)" + description: "Daarna telt een meterstand als ontbrekend. De tijdslimiet voor ontbrekende invoer begint pas daarna te lopen." meter_mqtt_topic: name: "Meter · MQTT-topic" - description: "Alleen voor meterbron mqtt_p1: het topic waarop de P1-metingen gepubliceerd worden." + description: "Alleen voor mqtt_p1. Het topic waarop uw meterstanden verschijnen." p1_import_entity: - name: "Meter · Entiteit van het afnameregister (W)" - description: "Het afnameregister ZONDER teken. Wijs dit niet aan een template-sensor mét teken toe: de add-on berekent het nettovermogen zelf als afname min injectie, zodat de tekenafspraak in geteste code zit en niet in ongecontroleerde YAML." + name: "Meter · Entiteit afname (W)" + description: "De sensor voor afname van het net, nooit negatief. De add-on berekent het nettovermogen zelf." p1_export_entity: - name: "Meter · Entiteit van het injectieregister (W)" - description: "Het injectieregister ZONDER teken, de tegenhanger van het afnameregister hierboven. Zelfde regel: geen template-sensor mét teken." + name: "Meter · Entiteit injectie (W)" + description: "De sensor voor injectie in het net, nooit negatief. Hoort bij de entiteit afname hierboven." p1_net_entity: - name: "Meter · Entiteit met het nettovermogen mét teken (W)" - description: "Alleen voor meterbron ha_signed. ÉÉN sensor mét teken: positief is afname van het net, negatief is injectie. Splits die niet in twee template-sensoren op - de add-on doet die splitsing zelf, juist zodat ze getest is." + name: "Meter · Entiteit nettovermogen met teken (W)" + description: "Alleen voor ha_signed. Eén sensor die positief is bij afname en negatief bij injectie." p1_phase_import_entities: - name: "Meter · Afname-entiteiten per fase (L1, L2, L3)" - description: "Optioneel, in de volgorde L1..L3. Nodig voor de kwartierpiek van het capaciteitstarief op een driefasige aansluiting. Het aantal items moet gelijk zijn aan het aantal fasen hierboven." + name: "Meter · Afname-entiteiten per fase (L1-L3)" + description: "Optioneel, in de volgorde L1, L2, L3. Nodig voor de piekgrens bij een driefasige aansluiting, één item per fase." p1_phase_export_entities: - name: "Meter · Injectie-entiteiten per fase (L1, L2, L3)" - description: "Optioneel, in de volgorde L1..L3, naast de afname-entiteiten per fase hierboven. Het aantal items moet gelijk zijn aan het aantal fasen." + name: "Meter · Injectie-entiteiten per fase (L1-L3)" + description: "Optioneel, in de volgorde L1, L2, L3, naast de afname-entiteiten per fase. Eén item per fase." p1_phase_net_entities: - name: "Meter · Netto-entiteiten per fase mét teken (L1, L2, L3)" - description: "Alleen voor meterbron ha_signed. Optioneel, in de volgorde L1..L3, elk met hetzelfde teken als de netto-entiteit hierboven. Zelfde rol als de afname- en injectie-entiteiten per fase: de kwartierpiek van het capaciteitstarief op een driefasige aansluiting. Het aantal items moet gelijk zijn aan het aantal fasen." + name: "Meter · Netto-entiteiten per fase (L1-L3)" + description: "Alleen voor ha_signed. Optioneel, in de volgorde L1, L2, L3, met hetzelfde teken als de netto-entiteit. Eén item per fase." max_w: name: "Grenzen · Vermogen van de omvormer (W)" - description: "DIT IS UW GETAL, geen afgeleide waarde: de harde bovengrens van wat er ooit gestuurd mag worden, in watt. Zet het op wat uw omvormer werkelijk aankan, begin laag en verhoog het pas na de indienstname. Het wordt helemaal niet gelezen zodra de lijst met omvormers is ingevuld - elk item draagt dan zijn eigen waarde en het plafond van de installatie is hun som. Verschillende veiligheidsdrempels moeten eronder blijven; de add-on start niet op als er één niet aan voldoet." + description: "Uw eigen getal: het hoogste vermogen dat de add-on ooit aan de omvormer mag vragen. Begin laag en verhoog het na de indienstname." bms_soc_floor: name: "Grenzen · Uitschakelniveau van de batterij (%)" - description: "GEMETEN, niet gekozen: het percentage waarbij het batterijmanagementsysteem van de batterij ZELF stopt met ontladen, wat u hier ook instelt. Register 0x0560 leest 10 op de referentie-GW5000S-BP. Lees deze waarde af van de batterij die er werkelijk staat in plaats van dit getal over te nemen. Ze staat hier zodat de add-on een ondergrens voor de piekbewaking op of onder deze waarde kan weigeren: zo'n ondergrens kan nooit werken, het BMS wint altijd eerst, en de statuspagina zou een reserve tonen die niet bestaat. Wordt niet gelezen zodra de lijst met omvormers is ingevuld - elk item vermeldt dan de uitschakelgrens van zijn eigen batterij." + description: "Het niveau waarop het beheersysteem van de batterij zelf stopt met leveren. Lees het af van uw batterij in plaats van een getal over te nemen." peak_cap_w: - name: "Grenzen · Streefwaarde capaciteitstarief (W)" - description: "DIT IS UW GETAL: het gemiddelde kwartiervermogen waar de piekbewaking onder probeert te blijven. Neem het over uit uw netcontract - in België is dit de kwartierpiek waarop het capaciteitstarief van uw distributiefactuur berekend wordt." + name: "Grenzen · Piekgrens (W)" + description: "Uw eigen getal: het gemiddelde vermogen per kwartier waaronder de add-on de afname houdt. Neem het over uit uw netcontract." peak_forecast_entity: - name: "Grenzen · Entiteit met de kwartierprognose (W)" - description: "Optioneel. Een prognose van het gemiddelde vermogen in het lopende factuurkwartier. Laat u dit leeg, dan is er helemaal geen piekbegrenzing." + name: "Grenzen · Entiteit kwartierprognose (W)" + description: "Optioneel. Een prognose van het gemiddelde vermogen in het lopende kwartier. Laat u dit leeg, dan is er geen piekgrens." peak_soc_floor: name: "Grenzen · Piekreserve (%)" - description: "AFGELEID, niet gekozen (SAFETY-24): de referentiebatterij heeft 13,8 kWh bruikbaar en de zwaarste doorgerekende afvlakdag vraagt 878 Wh, oftewel 6,4 %, dus 20 % ligt tien punten boven de uitschakelgrens van de batterij zelf en laat de bewaking nog ongeveer 1,6 van haar zwaarste waargenomen dagen speling. ⚠️ DIT BEGRENST ALLEEN DE PIEKBEWAKING. Het is geen reserve voor de hele batterij: gewoon eigenverbruik ontlaadt er dwars doorheen en gaat door tot aan de uitschakelgrens van de batterij, en dit getal verhogen verandert daar geen tiende procent aan. Het moet strikt boven de uitschakelgrens van de batterij blijven, anders start de add-on niet op. Verander het niet zonder de afleiding opnieuw te maken." + description: "Het afvlakken van de piek laat de batterij niet onder dit niveau zakken, gewoon verbruik wel. Afgeleide waarde, laat ze ongewijzigd." price_provider: name: "Tarief · Bron van dynamische prijzen" - description: "Waar day-ahead- of realtimeprijzen vandaan komen. 'off' is de standaardinstelling en betekent dat deze installatie op het vaste tarief hieronder draait, zonder handel. ⚠️ DIT AANZETTEN IS WAT HET OPHALEN VAN PRIJZEN START - niet de handelsschakelaar verderop. Met een bron ingesteld haalt de add-on de feed elk half uur op, controleert die, bewaart de dag en toont op de rij Prijsgeschiedenis wat er bewaard is, of prijshandel nu aan staat of niet. Op zichzelf verplaatst dat nog geen energie: handelen is de aparte schakelaar, en het goedkope venster dat de maandelijkse onderhoudscyclus gebruikt komt uit het vaste of dag/nacht-tarief hieronder. Het mag niet gecombineerd worden met de twee oude Home Assistant-prijsentiteiten verderop: twee prijsbronnen op één installatie, waarvan er stilzwijgend één wint, wordt bij het opstarten geweigerd in plaats van schijnbaar actief gelaten. ⚠️ DRIE IDS IN DEZE LIJST ZIJN INGETROKKEN EN STARTEN NIET MEER: engie_dynamic, totalenergies_dynamic en eneco_eddy. Hun endpoints bestaan niet en hebben nooit bestaan, dus die plugins hebben nooit één prijs opgehaald - een installatie die op zo'n bron stond, draait sindsdien stilzwijgend op het vaste of dag/nacht-tarief hieronder, of op niets. Ze staan hier alleen nog zodat zo'n installatie bij het opstarten die uitleg krijgt in plaats van een onleesbare schemafout. Kies generic_dayahead voor de groothandelscurve met een vaste marge, custom_formula om de coëfficiënten B x index + A van uw eigen contract van uw tariefkaart over te typen, manual_csv voor een bestand dat u zelf schrijft, of off." + description: "Waar de prijzen vandaan komen. Een bron kiezen start het ophalen van prijzen, ook als handelen uit staat." price_markup_eur_kwh: name: "Tarief · Marge van de leverancier (EUR/kWh)" - description: "De marge van uw energieleverancier. De add-on telt die ALLEEN op wanneer de gekozen prijsbron ze niet al bevat - bij manual_csv, waarvan de bedragen alles inbegrepen zijn, wordt ze genegeerd, en dat wordt ook gelogd, zodat ze nooit dubbel wordt aangerekend." + description: "De marge van uw leverancier. Ze wordt alleen opgeteld als de prijsbron ze nog niet bevat." price_taxes_eur_kwh: name: "Tarief · Distributie, heffingen en btw (EUR/kWh)" - description: "Alles op uw factuur dat niet de energie zelf is - distributie, heffingen, accijns en btw - per kWh, opgeteld volgens dezelfde regel als de marge: alleen wanneer de gekozen prijsbron ze nog niet bevat. ⚠️ DIT GETAL IS GEEN VOORKEUR EN HET IS NIET DAT VAN UW OMVORMER. Het staat standaard op 0.11736, AFGELEID in TARIFF-18 van de Eneco-kaart voor residentiele klanten in Vlaanderen van september 2026, inclusief 6% btw: Fluvius-distributie voor Antwerpen 5,35 plus bijzondere accijns 4,876 plus bijdrage groene stroom en WKK 1,51 c/kWh. De energiebijdrage is sinds 1 augustus 2026 nul - ze is opgegaan in de accijns, dus een bedrag uit een oudere gids telt ze dubbel. ⚠️ CONTROLEER HET BIJ UW EIGEN DISTRIBUTIENETBEHEERDER. Alleen de distributieregel verschilt: over de acht Fluvius-netgebieden loopt die van 5,28 c/kWh in Midden-Vlaanderen tot 6,70 in West-Vlaanderen, zodat het Vlaamse totaal ongeveer van 0.117 tot 0.131 loopt. In Wallonie en Brussel heeft het distributietarief een apart dag- en nachttarief en hoort het hier helemaal niet thuis - gebruik dan de optie voor heffingen per tijdstip hieronder. ⚠️ DIT WIJZIGEN VERANDERT GEEN ENKELE HANDELSBESLISSING: hetzelfde bedrag komt bij elk uur, dus het valt weg uit zowel het goedkoopste uur als het prijsverschil. Wat het wel verandert is elke prijs die u te zien krijgt, en de regel die weigert te ontladen in een uur waarvan de totaalprijs onder nul ligt." + description: "Netkosten, heffingen en btw per kWh, ingesteld voor Vlaanderen. Controleer het bij uw eigen netbeheerder." export_price_eur_kwh: name: "Tarief · Injectievergoeding (EUR/kWh)" - description: "Wat u krijgt voor een kWh die u op het net zet, alles inbegrepen. Eén getal en geen reeks: geen enkele leverancier hier publiceert een dynamische injectiecurve. In België ligt dit vaak dicht bij nul, wat op zich al sterk pleit voor eigenverbruik in plaats van injectie. De waarde mag negatief zijn - op een zomerse middag betaalt u soms om te injecteren." + description: "Wat u krijgt per kWh die u op het net zet, alles inbegrepen. Dit mag negatief zijn." static_profile: - name: "Tarief · Vast of dag/nacht-tarief (één regel JSON)" - description: "Uw vaste of dag/nacht-contract, geschreven als één regel JSON. AANBEVOLEN ZELFS BIJ EEN DYNAMISCH CONTRACT: hierop valt de add-on terug wanneer de prijsfeed uitvalt, en staat dit leeg dan blijft de installatie bij een dode feed helemaal zonder tarief achter. De periodes moeten elk dagtype precies één keer bedekken, zonder gat en zonder overlap - een gat wordt bij het opstarten geweigerd in plaats van opgevuld, want een verzonnen prijs is er één waarop een strategie zou handelen. Een volledig vast tarief is één periode van 00:00 tot 24:00 op alle dagen. De prijzen zijn ALLES INBEGREPEN; de marge en heffingen hierboven worden er niet bij opgeteld. Let op: een venster van 22:00 tot 07:00 voor ma-vr dekt zaterdagochtend NIET, dus een regel voor het weekend is noodzakelijk en niet decoratief." + name: "Tarief · Vast of dag/nacht-tarief (JSON)" + description: "Uw vaste of dag/nacht-contract als één regel JSON, prijzen alles inbegrepen. Vul dit ook in bij een dynamisch contract. Het is de reserve als de prijsfeed uitvalt." price_taxes_profile: - name: "Tarief · Heffingen en btw per dagdeel (één regel JSON)" - description: "Laat dit leeg tenzij uw netbeheerder werkelijk een ander dag- en nachttarief aanrekent - in Vlaanderen is dat niet zo, de Fluvius-distributie is één tarief, en het vaste bedrag hierboven klopt. In Wallonië en Brussel is dat wél zo: ORES rekent 13,27 c/kWh overdag tegen 7,39 's nachts, AIESH 15,17 tegen 8,21, Sibelga 9,39 tegen 7,10. Geschreven als één regel JSON in precies dezelfde vorm als het vaste of dag/nacht-tarief hierboven, met dezelfde regel dat de periodes elk dagtype één keer moeten bedekken zonder gat en zonder overlap. ⚠️ DE BEDRAGEN HIER ZIJN ALLEEN DE HEFFINGEN, GEEN VOLLEDIGE PRIJS - de add-on telt ze op bij wat uw prijsbron publiceert, net zoals bij het vaste bedrag. Waarom het uitmaakt: een vast bedrag is in elk uur hetzelfde, verschuift dus elk uur evenveel en kan niet veranderen welk uur het goedkoopste is - en een nachttarief van het net is goedkoop in dezelfde uren waarin de markt goedkoop is, dus door het plat te slaan lijkt de dag vlakker dan hij is en weigert de add-on batterijcycli die zichzelf zouden terugverdienen. Vul dit in óf het vaste bedrag hierboven, niet allebei: de add-on weigert te starten als de twee elkaar tegenspreken." + name: "Tarief · Heffingen en btw dag/nacht (JSON)" + description: "Laat dit leeg, tenzij uw netbeheerder een ander dag- en nachttarief rekent, zoals in Wallonië en Brussel. Vul dit of het vaste bedrag hierboven in, niet allebei." price_formula: - name: "Tarief · Uw eigen tariefformule (één regel JSON)" - description: "Alleen voor prijsbron custom_formula: de twee coëfficiënten van uw eigen contract, als één regel JSON. De tariefkaart van uw leverancier drukt de formule af als B x index + A - die twee getallen staan alleen op uw kaart, er bestaat nergens een publieke lijst van, en u bent de enige die ze kan lezen. Typ wat de kaart afdrukt, IN DE EENHEID DIE DE KAART GEBRUIKT: elke eenheidsomrekening en de btw-stap zijn het werk van de add-on, want dat zijn precies de twee plaatsen waar een mens stilzwijgend een factor 10, 100 of 1,06 verliest. Voorbeeld: {\"index\":\"epex_be\",\"resolution\":\"hourly\",\"factor\":0.102,\"offset\":1.00,\"units\":\"c_eur_per_kwh\",\"vat_pct\":6,\"card\":{\"month\":\"2026-09\",\"index_eur_per_mwh\":133.9905,\"expect_incl_vat\":15.55}}. ⚠️ HET BLOK card IS VERPLICHT EN MAAKT DIT VEILIG: uw kaart vermeldt ook de referentie-index die ze veronderstelt en de prijs die eruit volgt, dus de add-on berekent die prijs opnieuw uit uw getallen en START NIET als het resultaat niet klopt - met vermelding van het verschil. Dat vangt een verkeerde eenheid, btw die ontbreekt of dubbel geteld is, een omgewisseld cijfer, en de dure fout: nettarieven die in de offset verwerkt zitten en die de add-on er dan nog een tweede keer bovenop zou rekenen. ⚠️ EN DE GRENS DAARVAN, IN DEZELFDE ZIN: ze toetst uw coëfficiënten aan uw kaart, niet uw kaart aan de werkelijkheid - twee getallen van het verkeerde product kloppen onderling en komen er dus door. Alleen vaste getallen: er wordt geen enkele expressie geëvalueerd, en een onbekend veld wordt geweigerd in plaats van genegeerd." + name: "Tarief · Uw eigen tariefformule (JSON)" + description: "Alleen voor custom_formula. Typ de getallen van de tariefkaart van uw leverancier als één regel JSON. De add-on controleert ze met de kaart." price_export_formula: - name: "Tarief · Uw eigen INJECTIEformule (één regel JSON)" - description: "Optioneel, en alleen als uw leverancier u een prijs betaalt die met de markt meebeweegt. Op uw tariefkaart staat een TWEEDE formule voor wat u krijgt voor de stroom die u injecteert, en dat is niet de eerste met een minteken ervoor: Eneco drukt `0,1 x BELPEX-H - 1,188` c/kWh af voor injectie tegenover `0,102 x ...` voor afname, en Aspiravi `0,07 x Belpex - 2`. Geschreven in precies dezelfde vorm als uw eigen tariefformule hierboven. ⚠️ INJECTIE IS IN BELGIË VRIJGESTELD VAN BTW terwijl afname op 6% staat, dus vat_pct is hier normaal 0 - dat is het ene veld dat men van de andere formule overneemt en verkeerd invult. ⚠️ DE PRIJS DIE HIERUIT VOLGT KAN NEGATIEF ZIJN, en dat is geen fout: Eneco betaalt onder nul zodra BELPEX-H lager is dan 11,88 EUR/MWh, en dat is het midden van een zonnige dag - u kunt moeten betalen om te injecteren. De add-on aanvaardt dat in plaats van het te verbergen. Het blok card is hier OPTIONEEL en hierboven verplicht, omdat Eneco de injectieformule afdrukt ZONDER voorbeeldprijs ernaast en er dan niets is om uw getallen aan te toetsen; drukt uw kaart er wél een af, vul ze dan in en de add-on start niet als uw getallen die prijs niet reproduceren. ⚠️ WAT DIT NIET DOET: geen enkel onderdeel van de add-on handelt vandaag op een injectieprijs - hij laadt goedkoop op om duur te vermijden, en beide zijden van die vergelijking zijn afnameprijzen. Dit is wat u te zien krijgt, en wat een toekomstige exportstrategie zou lezen. Laat het leeg en de vaste injectieprijs hierboven wordt gebruikt, zoals elke installatie nu doet." + name: "Tarief · Uw eigen injectieformule (JSON)" + description: "Optioneel. De injectieformule van uw tariefkaart, in dezelfde vorm als uw eigen tariefformule. Laat leeg om de vaste injectievergoeding te gebruiken." price_csv_path: name: "Tarief · CSV-bestand met prijzen" - description: "Alleen voor prijsbron manual_csv: waar in /share de add-on uw eigen prijsbestand leest." + description: "Alleen voor manual_csv. Waar in /share de add-on uw prijsbestand leest." price_feed_url: name: "Tarief · Afwijkende URL voor de prijsfeed" - description: "Laat leeg om de eigen feed van de gekozen bron te gebruiken. Alleen een host die die bron zelf opgeeft, wordt aanvaard, zodat dit niet zomaar ergens naar kan verwijzen. WAT U HIER TYPT WORDT LETTERLIJK VERSTUURD: de add-on voegt er niets aan toe, ook niet het datumbereik dat ze normaal aan haar eigen feed vraagt. Een afwijkende URL levert dus de horizon op die die URL zelf teruggeeft - vaak één dag, waarna de rest van het plan uit de prijzen van gisteren wordt overgenomen en buiten de prijsarbitrage valt. Bij elke prijsvernieuwing verschijnt daarover een waarschuwing in het logboek. Maak dit veld leeg om de volledige horizon terug te krijgen." + description: "Laat leeg om de eigen feed van de bron te gebruiken. Een afwijkende URL wordt letterlijk verstuurd en geeft vaak maar één dag terug." price_horizon_h: - name: "Tarief · Hoe ver vooruit prijzen ophalen (uren)" - description: "Hoeveel uur aan prijzen er bij de bron opgevraagd wordt." + name: "Tarief · Prijzen vooruit (uren)" + description: "Hoeveel uur aan prijzen de add-on bij de bron opvraagt." price_timeout_s: - name: "Tarief · Time-out voor een prijsaanvraag (s)" - description: "Hoe lang één aanvraag bij de prijsbron mag duren voordat ze wordt opgegeven." + name: "Tarief · Time-out prijsaanvraag (s)" + description: "Hoe lang één aanvraag bij de prijsbron mag duren voor ze wordt opgegeven." price_now_entity: - name: "Tarief · Entiteit met de huidige prijs (oudere prijsweg)" - description: "De oudere manier om aan een prijs te komen, behouden omdat ze weghalen de onderhoudscyclus op een draaiende installatie zijn enige prijssignaal zou afnemen. De add-on leest deze entiteit en het gemiddelde hieronder en leidt er precies één ding uit af - of het nu goedkoper is dan gemiddeld - wat alleen gebruikt wordt om tijdens de onderhoudscyclus in een goedkoop venster te laden. Mag niet gecombineerd worden met een dynamische prijsbron." + name: "Tarief · Entiteit huidige prijs (oud)" + description: "De oudere manier om een prijs te krijgen, alleen gebruikt om tijdens onderhoud goedkoop te laden. Niet combineren met een dynamische prijsbron." price_avg_entity: - name: "Tarief · Entiteit met de gemiddelde prijs (oudere prijsweg)" - description: "Het gemiddelde waarmee de huidige prijs vergeleken wordt. Alleen zinvol samen met de entiteit hierboven en, net als die, niet te combineren met een dynamische prijsbron." + name: "Tarief · Entiteit gemiddelde prijs (oud)" + description: "Het gemiddelde waarmee de huidige prijs vergeleken wordt. Alleen samen met de entiteit huidige prijs, niet met een dynamische prijsbron." arbitrage_enabled: name: "Tarief · Handelen op het prijsverschil" - description: "Laden in het goedkoopste gepubliceerde uur en ontladen in het duurste, maar alleen wanneer het verschil de kosten van de volledige cyclus dekt. STAAT UIT in de standaardinstelling, met opzet: dit is de eerste strategie in de add-on die bewust energie tegen de meter in verplaatst, dus ze wordt bewust aangezet of helemaal niet. ⚠️ DIT UIT LATEN STAAN ZET DE PRIJSFEED NIET UIT. Een prijsbron die hierboven gekozen is, wordt hoe dan ook opgehaald, gecontroleerd en bewaard; deze schakelaar bepaalt alleen of de add-on op die prijzen HANDELT. Ze heeft zowel een prijsbron als een P1-meter nodig, en de add-on weigert combinaties die niet kunnen werken in plaats van ze schijnbaar actief te laten." + description: "Laden in het goedkoopste uur en de batterij laten leveren in het duurste, als het verschil de kosten dekt. Dit uitzetten zet de prijsfeed niet uit." cycle_cost_threshold_eur: - name: "Tarief · Kostprijs van één volledige laad/ontlaadcyclus (EUR/kWh)" - description: "Wat één volledige cyclus per kWh kost: slijtage van de batterij plus omzettingsverliezen. Een prijsverschil dat hier onder ligt, kost geld en levensduur en wordt dus niet verhandeld. ⚠️ DIT GETAL IS NIET AFGELEID UIT EEN METING. 0,10 is een productbeslissing en staat nog open bij de eigenaar (OPT-08). Bij deze waarde handelt een installatie met een vast dag/nachttarief helemaal niet - het realistische Belgische dag/nachtverschil is ongeveer 0,08 EUR/kWh - en dat is bij dit getal het juiste antwoord, geen fout." + name: "Tarief · Kosten van een batterijcyclus (EUR/kWh)" + description: "Wat één volledige batterijcyclus per kWh kost. Een kleiner prijsverschil wordt niet verhandeld. De waarde is een productkeuze, geen meting." arbitrage_soc_floor: - name: "Tarief · Handel ontlaadt niet onder (%)" - description: "De reserve die de prijshandel niet mag aanspreken. Bewust een andere instelling dan de ondergrens van het onderhoud: een handelsstrategie op de cijfers van de maandelijkse balanceercyclus richten, zou twee ongerelateerde keuzes aan één getal koppelen." + name: "Tarief · Handel houdt minstens (%)" + description: "Prijshandel laat de batterij niet onder dit niveau zakken. Dit staat los van de onderhoudsinstellingen." arbitrage_soc_ceiling: - name: "Tarief · Handel laadt niet boven (%)" - description: "De ruimte die de prijshandel niet mag volmaken. De tegenhanger van de ondergrens hierboven, en om dezelfde reden losgehouden van het onderhoudsdoel." + name: "Tarief · Handel laadt hoogstens (%)" + description: "Prijshandel laadt de batterij niet boven dit niveau." maintenance_enabled: - name: "Onderhoud · Maandelijkse batterijcyclus uitvoeren" - description: "Een bewuste diepe ontlading, gevolgd door volledig opladen en een rustperiode op vol, zodat het batterijmanagementsysteem zijn schatting van het laadniveau kan herijken en de cellen kan balanceren. Staat standaard uit." + name: "Onderhoud · Maandelijkse batterijcyclus" + description: "Eén keer per maand de batterij diep leegmaken, volladen en vol houden, zodat het laadniveau juist blijft. Staat standaard uit." maintenance_interval_days: - name: "Onderhoud · Minimum aantal dagen tussen cycli" + name: "Onderhoud · Minimum dagen tussen cycli" description: "De kortste tijd tussen twee onderhoudscycli." maintenance_start_hour: - name: "Onderhoud · Uur waarop een geplande cyclus start" - description: "Lokaal uur, 0 tot 23, waarop een cyclus die aan de beurt is begint." + name: "Onderhoud · Startuur" + description: "Het lokale uur, 0 tot 23, waarop een geplande cyclus begint." maintenance_discharge_w: name: "Onderhoud · Ontlaadvermogen (W)" - description: "Hoe snel de cyclus de batterij leegtrekt; het overschot gaat naar het net. Boven het vermogen van de omvormer wordt dit BEGRENSD tot dat vermogen en niet geweigerd - de cyclus loopt gewoon door, alleen trager, en de statuspagina meldt dat. Standaard 2000, afgestemd op het standaardvermogen; verhoog eerst het omvormervermogen en dan pas dit." + description: "Hoe snel de cyclus de batterij leegmaakt. Boven het vermogen van de omvormer wordt het daartoe beperkt, en duurt de cyclus gewoon langer." maintenance_charge_w: name: "Onderhoud · Laadvermogen (W)" - description: "⚠️ MOET GELIJK AAN OF LAGER ZIJN dan het vermogen van de omvormer; anders start de add-on niet op. Erboven vraagt het laden in een goedkoop venster meer dan de bewaakte grens toelaat, lost de arbiter die tegenstrijdigheid op naar 0 W, en zou het onderhoud op een standaardinstallatie stilzwijgend nooit laden in een goedkoop venster. Daarnaast wordt dit nog eens begrensd door de ruimte die de piekbewaking overlaat." + description: "Hoe snel de cyclus de batterij weer vollaadt. Het moet gelijk aan of lager zijn dan het vermogen van de omvormer, anders start de add-on niet." maintenance_soc_floor: name: "Onderhoud · Ontladen tot (%)" - description: "De diepte waar de maandelijkse herijking bewust naartoe gaat, één keer per maand, met opzet. ⚠️ DIT IS NIET DE ONDERGRENS VAN DE PIEKBEWAKING: die geeft aan hoe diep een besparende ontlading op geen enkele dag mag komen. De juiste waarden verschillen echt - 11 hier tegenover 20 daar - en daarom zijn het twee aparte instellingen die niet samengevoegd mogen worden." + description: "Het niveau tot waar de maandelijkse cyclus de batterij leegmaakt. Dit is niet de piekreserve, en de twee verschillen bewust." maintenance_soc_target: name: "Onderhoud · Opladen tot (%)" - description: "Het niveau waar de laadfase naartoe werkt voordat de rustperiode begint." + description: "Het niveau waartoe de cyclus oplaadt voor het vasthouden begint." maintenance_hold_min: - name: "Onderhoud · Op vol houden gedurende (minuten)" - description: "Hoe lang er op het streefniveau gebleven wordt zodat het batterijmanagementsysteem het balanceren van de cellen kan afmaken." + name: "Onderhoud · Vol houden gedurende (minuten)" + description: "Hoe lang de batterij vol blijft zodat de cellen in evenwicht komen." sign_disagree_w: - name: "Veiligheid · Drempel tekenbewaking (W) — gemeten, niet wijzigen" - description: "GEMETEN, NIET GEKOZEN (SAFETY-02). Zowel het uitgestuurde setpoint als de netmeting moet boven deze waarde liggen voordat hun tegengestelde tekens überhaupt als onenigheid tellen. Op de vastgelegde gezonde dag (23-08-2026) komt het teken in 93,4 % van de beoordeelde metingen overeen; op de vastgelegde foutdag (20-08-2026) ligt dat tussen 0,0 en 10,5 %, met tegengestelde periodes tot 1752 s. Er is geen reden om hieraan te sleutelen zonder een nieuwe meetcampagne die dat onderbouwt. De waarde moet onder het omvormervermogen blijven, anders kan de bewaking nooit aanslaan, en de add-on weigert die instelling." + name: "Veiligheid · Drempel verkeerde richting (W)" + description: "Een verkeerde richting telt pas als het commando en de meterstand allebei boven deze waarde liggen. Gemeten waarde, laat ze ongewijzigd." sign_disagree_s: - name: "Veiligheid · Wachttijd tekenbewaking (s) — gemeten, niet wijzigen" - description: "GEMETEN, NIET GEKOZEN (SAFETY-02). Hoe lang het setpoint en de meter onafgebroken tegengesteld moeten blijven voordat de add-on 0 W stuurt en vergrendelt tot iemand de regeling opnieuw start. 180 s ligt midden in een zeer brede gemeten marge: de langste terechte tegengestelde periode op de gezonde dag duurt 30 s, terwijl de foutdag bij 300 s nog altijd 13 keer aanslaat. Verander dit niet zonder nieuwe metingen." + name: "Veiligheid · Tijd verkeerde richting (s)" + description: "Hoe lang een verkeerde richting mag duren voor een veiligheidsstop elke omvormer op 0 W zet. Gemeten waarde, laat ze ongewijzigd." unit_sign_disagree_w: - name: "Veiligheid · Tekendrempel per omvormer (W) — afgeleid, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS; bij één omvormer doet deze instelling niets. AFGELEID UIT 1890 GESLOTEN-LUSTESTS op de testopstelling met twee omvormers (SAFETY-30), waarbij niets defect was, over het volledige bereik dat deze add-on toelaat voor versterking en volgsnelheid. 250 W is precies de helft van de verzadigingsdrempel, zodat het kleinste verschil dat hier zichtbaar is, exact de afwijking is waarbij de regeling zelf al zegt dat de omvormer niet volgt. Verander dit niet zonder de afleiding opnieuw te maken. De waarde moet onder het omvormervermogen blijven, anders kan ze nooit aanslaan." + name: "Veiligheid · Drempel verkeerde richting per omvormer (W)" + description: "Bij twee of meer omvormers: de drempel voor verkeerde richting per omvormer. Afgeleide waarde, laat ze ongewijzigd." unit_sign_disagree_s: - name: "Veiligheid · Wachttijd per omvormer (s) — afgeleid, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS. AFGELEID UIT 1890 GESLOTEN-LUSTESTS (SAFETY-30): 85 s is 8,5 keer de langste terechte tegengestelde periode die die tests opleveren (10,0 s), 2,8 keer het eigen veto van 30 s in de firmware, en minder dan de helft van de 180 s die de installatiebrede controle neemt. Verander dit niet zonder de afleiding opnieuw te maken." + name: "Veiligheid · Tijd verkeerde richting per omvormer (s)" + description: "Bij twee of meer omvormers: hoe lang één omvormer de verkeerde kant op mag duwen voor ze op 0 W gaat. Afgeleide waarde, laat ze ongewijzigd." site_sign_disagree_w: - name: "Veiligheid · Tekendrempel voor de hele installatie (W) — gemeten, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS. Dezelfde 300 W als de drempel voor één omvormer, BEWUST OVERGENOMEN (SAFETY-30): de onderbouwing hangt niet af van het aantal omvormers - rond nul is het teken ruis, de dode zone is 15 W, en er is één meter, wat er ook achter hangt. Verander dit niet zonder metingen die dat onderbouwen." + name: "Veiligheid · Drempel verkeerde richting installatie (W)" + description: "Bij twee of meer omvormers: de drempel voor verkeerde richting van de hele installatie. Gemeten waarde, laat ze ongewijzigd." site_sign_disagree_s: - name: "Veiligheid · Wachttijd voor de hele installatie (s) — afgeleid, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS. AFGELEID UIT 1890 GESLOTEN-LUSTESTS (SAFETY-30), en bewust NIET overgenomen van de 180 s voor één omvormer. In die tests duurt de langste terechte tegengestelde periode bij 300 W 110 s met één omvormer en 215 s met twee, omdat het commando de volledige installatiegrens moet doorlopen aan een volgsnelheid die niet die van de installatie is. 180 s overnemen zou dus een vals alarm hebben opgeleverd bij de laagste versterking en volgsnelheid en een gewone belastingomkering van 2,2 kW. 325 s is 1,51 keer die waarde, blijft binnen het factuurkwartier van 900 s en binnen elke episode van de vastgelegde foutdag. Verander dit niet zonder de afleiding opnieuw te maken." + name: "Veiligheid · Tijd verkeerde richting installatie (s)" + description: "Bij twee of meer omvormers: hoe lang de hele installatie de verkeerde kant op mag duwen voor een veiligheidsstop. Afgeleide waarde, laat ze ongewijzigd." meter_freeze_s: - name: "Veiligheid · Alarm vastgelopen meter na (s) — gemeten, niet wijzigen" - description: "GEMETEN, NIET GEKOZEN (SAFETY-18). Hoe lang de meter mag blijven antwoorden met een ONVERANDERDE waarde, terwijl het commando op de grens staat, voordat de add-on alarm slaat. Over 2399 s van deze woning op haar ingeregelde werkpunt - 1194 uitlezingen, waarvan 735 een herhaling van de vorige waarde - duurt de langste periode zonder een nieuwe waarde 15,4 s; 300 s is 19,5 keer zoveel en blijft binnen het factuurkwartier van 900 s. ALLEEN EEN ALARM: er wordt geen 0 W gestuurd en er wordt niets vergrendeld. ⚠️ Alleen de meterbron homewizard_local kan dit überhaupt zien; bij elke andere bron meldt de statuspagina NIET GEDEKT in plaats van actief. Verander dit niet zonder de afleiding opnieuw te maken." + name: "Veiligheid · Alarm vastgelopen meter na (s)" + description: "Een alarm als de meter zo lang dezelfde waarde herhaalt terwijl het commando op vol vermogen staat, alleen met homewizard_local. Gemeten waarde, laat ze ongewijzigd." circulation_w: - name: "Veiligheid · Drempel rondpompend vermogen (W) — gemeten, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS; bij één omvormer is deze grootheid altijd nul. Twee omvormers die tegen elkaar in duwen, heffen elkaar aan de meter op en zijn onzichtbaar voor elke andere bewaking in deze add-on. GEMETEN OVER 924 GESLOTEN-LUSTESTS waarbij niets defect was (SAFETY-31): de langste terechte tegenwerking valt terug van 505 s bij een drempel van 100 W naar 5 s bij 400 W, en 400 W is de scherpe knik waaronder deze add-on u niet laat gaan - daaronder houdt gewone werking de sensor minutenlang boven de drempel en kan niets korter dan het factuurkwartier dat van een storing onderscheiden. 700 W is 1,75 keer de knik; die extra marge is er omdat het aanloopgedrag van de tweede omvormer nog gekopieerd is van de eerste en niet gemeten. Verander dit niet zonder de afleiding opnieuw te maken." + name: "Veiligheid · Drempel tegenwerkende omvormers (W)" + description: "Bij twee of meer omvormers: hoeveel vermogen de ene tegen de andere in mag duwen voor het telt. Gemeten waarde, laat ze ongewijzigd." circulation_hold_s: - name: "Veiligheid · Wachttijd rondpompend vermogen (s) — afgeleid, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS. AFGELEID (SAFETY-31): 75 s zijn vijftien regelcycli - 15 keer de langste terechte episode die de testopstelling kan produceren, 2,5 keer het eigen veto van 30 s in de firmware, en twaalf keer binnen het factuurkwartier van 900 s. Het is bewust geen ronde 60 of 120, want dat zou een gok zijn in het jasje van een meting. Verander dit niet zonder de afleiding opnieuw te maken." + name: "Veiligheid · Tijd tegenwerkende omvormers (s)" + description: "Bij twee of meer omvormers: hoe lang ze tegen elkaar in mogen duwen voor een veiligheidsstop. Afgeleide waarde, laat ze ongewijzigd." delivery_hold_s: - name: "Veiligheid · Melding niet-leverende omvormer na (s) — afgeleid, niet wijzigen" - description: "ALLEEN BIJ TWEE OF MEER OMVORMERS; bij één omvormer kan deze controle helemaal niet aanslaan, en dat is een bewuste keuze en geen tekortkoming. Hoe lang één omvormer mag blijven staan op een ontlaadaandeel dat hij niet levert - meer dan de verzadigingsdrempel te weinig, zonder dat deze add-on er een verklaring voor kan uitlezen - terwijl minstens één andere omvormer dat NIET doet, voordat hij bij naam wordt gemeld. ALLEEN MELDEN (SAFETY-42): er wordt niets anders gestuurd, de regeling blijft ongemoeid, en de installatie blijft draaien met het aandeel van die omvormer te weinig tot u gaat kijken. AFGELEID UIT 2640 GESLOTEN-LUSTESTS waarbij niets defect was (SAFETY-42, plus een arm met één omvormer als controlegroep, die bij geen enkele drempel iets meldt): de langste terechte episode in die tests duurt 35,0 s, en de bovengrens is het factuurkwartier van 900 s. 185 s is 5,29 keer zoveel. ⚠️ Het schema laat u zo laag als 30 s instellen, en dat is ONDER die gemeten 35,0 s - op 30 s moet u meldingen bij terechte verzadiging verwachten. De tweede omvormer in die tests is een KOPIE VAN DE EERSTE, want de tweede omvormer bestaat nog niet: wat een vier keer tragere eenheid zou opleveren (75,0 s) is een gevoeligheidsstudie op dat idee en geen meting aan een echte tweede omvormer. Verander dit niet zonder de afleiding opnieuw te maken - en dat kan nu: admin/goodwe sim/delivery_window.py --campaign --blag (TEST-21). Een accu op of onder zijn eigen bms_soc_floor wordt nooit gemeld: een lege accu en een vastgelopen omvormer zijn watt voor watt identiek, en die instelling is het enige wat ze uit elkaar houdt - slaat dit toch aan bij een accu die volgens u leeg is, dan beschrijft die instelling uw batterij niet." + name: "Veiligheid · Alarm niet-leverende omvormer na (s)" + description: "Bij twee of meer omvormers: hoe lang één omvormer te weinig mag leveren voor een alarm. Het alarm verandert niets. Afgeleide waarde, laat ze ongewijzigd." shadow_mode: - name: "Veiligheid · Schaduwmodus — alles beslissen, niets sturen" - description: "Doorloopt het volledige beslispad — strategieën, arbiter, begrenzers en bewakingen — en stuurt NIETS naar de omvormer. Elke omvormer wordt op 0 W gehouden, ververst op de gewone hartslag, en de statuspagina zegt onomwonden dat de batterij niet wordt aangestuurd; wat er gestuurd ZOU zijn, en waarom, staat op de statuspagina en in het actielogboek. Zo bekijkt u een installatie een dag lang voordat u hem laat handelen. 'auto' (de meegeleverde waarde) betekent schaduwmodus zolang de regeling gestopt is en gewone regeling zodra u op Start drukt — een NIEUWE installatie kijkt dus eerst toe voordat ze ooit iets stuurt, en een installatie die al regelt verandert geen watt. 'on' betekent altijd schaduwmodus, wat de Start/stop-knop ook zegt: die stand kiest u als u de lus en de strategieën wilt laten draaien op een werkende installatie zonder dat er iets bij de batterij aankomt. 'off' is gewone regeling. ⚠️ Zolang dit aanstaat wordt de batterij NIET geregeld — het net wordt niet op nul gehouden, er wordt geen prijshandel uitgevoerd en er wordt geen capaciteitspiek afgevlakt. ⚠️ Een vergrendeling die al aanstond blijft aanstaan: schaduwmodus heft die niet op, en de banner noemt hem." + name: "Veiligheid · Schaduwmodus" + description: "De add-on neemt elke beslissing maar houdt elke omvormer op 0 W. 'auto' doet dit zolang de regeling gestopt is, 'on' altijd, 'off' nooit." auto_start: - name: "Geavanceerd · Automatisch beginnen te regelen bij opstarten" - description: "Staat standaard uit. Laat het uit tot de installatie in dienst is genomen: zolang het uit staat, moet iemand na elke herstart van de add-on op Start drukken, en dat is precies wat u wilt terwijl u tekens en entiteiten nog aan het nakijken bent." + name: "Geavanceerd · Regeling starten bij opstarten" + description: "Staat standaard uit. Laat het uit tot de installatie in dienst is, zodat iemand na elke herstart op Start drukt." gain: - name: "Geavanceerd · Versterking van de regellus" - description: "Welk deel van de resterende afwijking de regeling per cyclus wegregelt. GEMETEN OP ECHTE HARDWARE en al aan de bovengrens - niet verhogen. Lager is trager en veiliger." + name: "Geavanceerd · Versterking van de regeling" + description: "Welk deel van de resterende afwijking de regeling per cyclus wegwerkt. Gemeten op echte hardware, verhoog dit niet." slew_w: - name: "Geavanceerd · Grootste verandering per cyclus (W)" - description: "Hoeveel het setpoint in één regelcyclus mag verspringen. ⚠️ 0 BETEKENT VOLG HET OMVORMERVERMOGEN en is de aanbevolen instelling: de grens wordt ongeveer een negende van dat vermogen, zodat de regeling er de GEMETEN insteltijd van de installatie over doet om haar volledige bereik te doorlopen en het getal niet achterblijft wanneer het vermogen verandert. AFGELEID (SAFETY-39) uit een gemeten stapresponsie van ~18 s bij een meterinterval van 2 s. Een vast getal wordt aanvaard en wordt nooit stilzwijgend verlaagd, maar een getal sneller dan het vermogen toelaat wordt bij het starten geweigerd - bij 1000 W tegen 5000 W dreef deze regeling de meter op 2026-09-05 van 3,4 kW injectie naar 2,8 kW afname. Lager wordt altijd aanvaard." + name: "Geavanceerd · Grootste stap per cyclus (W)" + description: "Hoe ver het commando in één cyclus mag verschuiven. 0 volgt het vermogen van de omvormer en is aanbevolen." deadband_w: - name: "Geavanceerd · Dode zone (W)" - description: "Afwijkingen kleiner dan deze waarde worden genegeerd. ⚠️ De dode zone werkt maar één kant op: elk rustpunt erbinnen blijft eeuwig staan, en het afnameregister van de meter telt elke positieve watt mee zonder injectie die dat compenseert - en precies daarom staat het rustpunt hieronder licht negatief." + name: "Geavanceerd · Negeer afwijkingen onder (W)" + description: "Kleinere afwijkingen worden genegeerd. Houd dit klein, want elk rustpunt daarbinnen blijft staan." target_grid_w: name: "Geavanceerd · Rustpunt aan de meter (W)" - description: "Waar de meter moet staan wanneer er niets gebeurt; negatief betekent een lichte injectie. -10 W is bewust gekozen: rusten op 0 W lekt de hele dag door ongeveer de helft van de dode zone aan gefactureerde afname - grofweg 0,2 tot 0,35 kWh bij een dode zone van 15 W - en het rustpunt onder nul leggen verplaatst dat lek naar het injectieregister, dat niet gefactureerd wordt. Het kost ongeveer evenveel watt weggegeven injectie, dus houd het klein." + description: "Waar de meter moet staan als er niets gebeurt. Een kleine injectie voorkomt dat u de hele dag kleine afname betaalt." step_w: - name: "Geavanceerd · Afronding van het setpoint (W)" - description: "Het setpoint wordt op een veelvoud hiervan afgerond voordat het geschreven wordt, zodat de omvormer niet voor elke watt ruis een nieuw getal krijgt." + name: "Geavanceerd · Afronding van het commando (W)" + description: "Het commando wordt afgerond op een veelvoud hiervan, zodat ruis het niet elke cyclus verandert." saturation_w: - name: "Geavanceerd · Verzadigingsdrempel (W)" - description: "Het verschil tussen wat gevraagd werd en wat de omvormer levert dat geldt als 'deze omvormer zit aan een grens'. ⚠️ De tekendrempel per omvormer onder Veiligheid is afgeleid als precies de helft hiervan, dus deze waarde verschuiven, verschuift ook de onderbouwing daarvan." + name: "Geavanceerd · Verschil omvormer aan grens (W)" + description: "Levert een omvormer zoveel minder dan gevraagd, dan zit ze aan haar grens. De drempel verkeerde richting per omvormer is de helft hiervan." saturation_cycles: - name: "Geavanceerd · Verzadigde cycli voor bevriezen (aantal)" - description: "Hoeveel opeenvolgende verzadigde cycli er nodig zijn voordat de regeling stopt met verder oplopen. ⚠️ Zet dit niet op 1: één ruiscyclus zou de regeling dan al bevriezen." + name: "Geavanceerd · Cycli aan grens voor bevriezen" + description: "Hoeveel cycli na elkaar aan de grens voor de regeling stopt met afwijking opbouwen. Zet dit niet op 1." integrator_max_w: - name: "Geavanceerd · Begrenzing van de integrator (W, 0 betekent gelijk aan het vermogen)" - description: "Begrenst hoeveel oude afwijking er kan klaarstaan om af te bouwen wanneer het teken omslaat. GEMETEN op de gesloten-lussimulator met een belasting van 4000 W die naar nul valt: bij een grens gelijk aan het omvormervermogen staat het commando twee cycli later op 1000 W, bij anderhalf keer dat vermogen op 1800 W. ⚠️ Zet dit niet hoger dan het omvormervermogen - de uitgangsbegrenzing bepaalt toch al wat er naar de omvormer gaat, dus extra ruimte levert alleen watts in de verkeerde richting op na elke verzadiging. Lager zetten dan het omvormervermogen is de nuttige richting, en de enige reden dat dit een aparte instelling is." + name: "Geavanceerd · Grens opgebouwde afwijking (W)" + description: "Beperkt hoeveel oude afwijking de regeling meedraagt, en 0 betekent het vermogen van de omvormer. Zet dit niet hoger dan dat vermogen." heartbeat_s: - name: "Geavanceerd · Verversingsinterval van het setpoint (s)" - description: "Hoe vaak het setpoint opnieuw geschreven wordt, ook als het niet veranderd is. Dit moet ruim onder de eigen bewaking van de firmware blijven, die een verbinding die 30 s stil is geweest, blokkeert." + name: "Geavanceerd · Commando opnieuw sturen na (s)" + description: "Hoe vaak het commando opnieuw gestuurd wordt, ook als het gelijk bleef. Houd dit ruim onder de eigen grens van 30 s van de stuurprint." stale_input_s: - name: "Geavanceerd · 0 W sturen nadat invoer ontbreekt gedurende (s)" - description: "Hoe lang de invoer mag ontbreken voordat de add-on 0 W stuurt. Bij een P1-meter begint deze teller pas te lopen NADAT de verouderingsgrens van de meter al verstreken is, dus de twee stapelen: het totaal is langer dan dit getal op zich." + name: "Geavanceerd · Tijdslimiet ontbrekende invoer (s)" + description: "Hoe lang invoer mag ontbreken voor elke omvormer op 0 W gaat. Bij een P1-meter begint dit pas na de grens voor een te oude meting." cycle_floor_s: - name: "Geavanceerd · Langste tijd tussen twee regelcycli (s)" - description: "Een uiterste termijn voor de tijd tussen twee cycli, die door elke cyclus opnieuw begint. Bij een gezonde meter verstrijkt hij nooit en verandert hij niets. Verhoog hem alleen als uw meter trager is dan ongeveer 10 s, en houd hem onder de verouderingsgrens van de meter - daarna is er toch geen meting meer om te beoordelen." + name: "Geavanceerd · Langste tijd tussen cycli (s)" + description: "Een uiterste termijn tussen twee regelcycli die een gezonde meter nooit haalt. Verhoog dit alleen voor een meter trager dan ongeveer 10 s." log_level: name: "Geavanceerd · Logniveau" - description: "Hoeveel detail de add-on naar zijn logboek schrijft. 'info' is de standaardinstelling; 'debug' en 'trace' dienen om een probleem te onderzoeken en leveren veel tekst op." + description: "Hoeveel detail de add-on in zijn logboek schrijft. 'debug' en 'trace' zijn om een probleem te zoeken." diff --git a/goodwe_controller/ux08_allowlist.txt b/goodwe_controller/ux08_allowlist.txt index 5de744e..cc820da 100644 --- a/goodwe_controller/ux08_allowlist.txt +++ b/goodwe_controller/ux08_allowlist.txt @@ -1,7 +1,7 @@ # UX-08 ratchet (test_messages.py part 3). Each line is a user-facing string that # does not follow STYLE.md yet: "<kind> <sha1-12 of its text> # where :: start". -# These are waiting for phase 2c (refusal, option-name, option-desc) and 2d -# (log); phase 2b emptied the row and banner kinds. Delete the line when you +# These are waiting for phase 2d (log); phase 2b emptied the row and banner +# kinds and phase 2c the refusal and option kinds. Delete the line when you # rewrite the string, because a stale line fails the test. Never add a line for a new string: write the new # string to STYLE.md instead. @@ -48,127 +48,3 @@ log 1688a7478ceb # validate.py over 25 words (36) :: 'price_formula is filled i log f37f9fce4433 # validate.py over 25 words (96) :: '%s has no "card" block, so its coefficients are UNGRADED: nothing reco' log 396fbdd009c2 # validate.py over 25 words (52); banned: §1 :: "price_provider is %r but static_profile is empty. §11.4's degradation " log 37bba6ed37e3 # validate.py capitals: REFUSING TO START :: 'REFUSING TO START: the add-on configuration is not usable.' -option-desc b927826d01f0 # en.yaml over 30 words (112); capitals: LEAVING IT OFF DOES NOT TURN THE PRICE FEED OFF :: 'Charge in the cheapest published hour and discharge in the dearest, bu' -option-desc b98c42e34df7 # en.yaml over 30 words (34) :: 'The reserve price trading may not spend. Deliberately not the same key' -option-desc 84e054da385b # en.yaml over 30 words (39) :: 'Off by default. Leave it off until the site has been commissioned: wit' -option-desc 0f55d3b37afa # en.yaml over 30 words (38); banned: 0x0518, register, watchdog :: "The sensor that reports this inverter's own battery power, positive wh" -option-desc 307afdd74f84 # en.yaml over 30 words (98); banned: 0x0560, Register; capitals: GW5000S-BP :: "MEASURED, not chosen: the percent at which the pack's OWN battery mana" -option-desc 4da37ff6250d # en.yaml over 30 words (66); banned: SAFETY-31; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. DERIVED (SAFETY-31): 75 s is fifteen contr' -option-desc db464169ed66 # en.yaml over 30 words (144); banned: SAFETY-31; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY; with one inverter the quantity is identica' -option-desc df9735452fa1 # en.yaml over 30 words (88); banned: OPT-08; capitals: THIS ONE IS NOT DERIVED FROM :: 'What one full round trip costs per kWh: wear on the pack plus conversi' -option-desc 8147a82a437e # en.yaml over 30 words (51) :: 'A deadline on the gap between cycles, reset by every cycle. On a healt' -option-desc cb66f230ef63 # en.yaml over 30 words (45); banned: register :: 'Errors smaller than this are ignored. ⚠️ The deadband is a one-way rat' -option-desc 4167af90cfc2 # en.yaml over 30 words (288); banned: SAFETY-42, delivery_window.py, saturation; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY; with one inverter this check cannot fire a' -option-desc 3c0898cc1149 # en.yaml over 30 words (63) :: 'What you are paid for feeding a kWh back into the grid, all in. One nu' -option-desc 05560996cb2e # en.yaml capitals: MEASURED ON REAL HARDWARE :: 'How much of the remaining error the loop corrects each cycle. MEASURED' -option-desc f225d7a8f3a5 # en.yaml over 30 words (32); banned: watchdog :: 'How often the setpoint is rewritten even when it has not changed. It m' -option-desc ef70d16a93bd # en.yaml over 30 words (98); banned: clamp, saturation :: 'Caps how much stale error can be waiting to unwind when the sign flips' -option-desc bde7357af38d # en.yaml over 30 words (107); capitals: EMPTY DOES NOT MEAN :: 'Leave this empty unless the site really has more than one inverter. EM' -option-desc 217c5ae9599c # en.yaml over 30 words (66); banned: 0x0560, register :: "The percent at which THIS pack's own battery management system cuts ou" -option-desc 746a0f9ae506 # en.yaml over 30 words (143) :: "THIS pack's usable capacity in kilowatt-hours, from its datasheet or i" -option-desc cb6ad204f59d # en.yaml over 30 words (52) :: 'The supervised ceiling on what may be written to THIS inverter; the si' -option-desc 46142bcc1ab1 # en.yaml over 30 words (36); banned: heartbeat, latch :: 'A short identifier for this inverter, for example inverter-a. It gives' -option-desc d787e9f2454d # en.yaml over 30 words (63); banned: arbiter; capitals: MUST STAY AT OR BELOW :: '⚠️ MUST STAY AT OR BELOW the inverter rating, and the add-on refuses t' -option-desc a90fced63631 # en.yaml over 30 words (52); banned: CLAMPED :: 'How fast the cycle drains the pack; the surplus is exported. Above the' -option-desc ab58c8fae4fb # en.yaml over 30 words (57); capitals: THIS IS NOT THE PEAK GUARD :: 'The depth the monthly recalibration deliberately goes to, once a month' -option-desc 73f51bdd3d6e # en.yaml over 30 words (83); capitals: THIS IS YOUR NUMBER :: 'THIS IS YOUR NUMBER, not a derived one: the hard ceiling on what may e' -option-desc dd9023e6c812 # en.yaml over 30 words (45); capitals: POSITIVE MUST MEAN DRAWING FROM THE GRID :: "The net grid power sensor, used when the meter source is 'off'. POSITI" -option-desc aa5b929f3c22 # en.yaml over 30 words (114); banned: SAFETY-18, latch; capitals: NOT CHOSEN :: 'MEASURED, NOT CHOSEN (SAFETY-18). How long the meter may keep answerin' -option-desc 1b3038c5c9e5 # en.yaml over 30 words (46) :: 'Beyond this the grid figure counts as missing. On its own it does not ' -option-desc bbf26329f056 # en.yaml over 30 words (48); banned: telegram, telegrams :: 'Must match your connection. A telegram whose phase count disagrees is ' -option-desc 92da72e54e77 # en.yaml over 30 words (52) :: "For meter source homewizard_local only. 5 s is the meter's own update " -option-desc 24f329136309 # en.yaml over 30 words (84) :: "'off' keeps the single Home Assistant entity below, which is what an e" -option-desc 47e5fa0dba52 # en.yaml banned: register :: 'The UNSIGNED injection register, the counterpart of the import registe' -option-desc 9b8f5ea6c656 # en.yaml banned: 192.168.2.250 :: "For meter source homewizard_local only: the meter's own address on you" -option-desc d5d3e30ac4d2 # en.yaml over 30 words (37); banned: register :: 'The UNSIGNED consumption register. Do not point this at a signed templ' -option-desc 0b05d89400ba # en.yaml over 30 words (39) :: 'For meter source ha_signed only. ONE signed sensor: positive is drawn ' -option-desc e74a5db257e1 # en.yaml over 30 words (46) :: 'For meter source ha_signed only. Optional, in L1..L3 order, each signe' -option-desc 3f07a88a61fd # en.yaml over 30 words (34); capitals: THIS IS YOUR NUMBER :: 'THIS IS YOUR NUMBER: the quarter-hour average demand the peak guard tr' -option-desc 6ec195081ef9 # en.yaml over 30 words (112); banned: SAFETY-24; capitals: IT BOUNDS THE PEAK GUARD ONLY :: 'DERIVED, not picked (SAFETY-24): the reference pack holds 13.8 kWh usa' -option-desc 228fdc168458 # en.yaml over 30 words (270); capitals: INJECTION IS EXEMPT FROM VAT :: 'Optional, and only if your supplier pays you a price that moves with t' -option-desc 98987808a7f0 # en.yaml over 30 words (98); capitals: WHAT YOU TYPE IS SENT EXACTLY AS WRITTEN :: "Leave empty to use the chosen source's own feed. Only a host that sour" -option-desc 26f17751b2f7 # en.yaml over 30 words (234); capitals: IN THE UNITS THE CARD PRINTS :: "For price source custom_formula only: your own contract's two coeffici" -option-desc 011841a82d7d # en.yaml over 30 words (34) :: "Your supplier's margin. The add-on adds it ONLY when the chosen price " -option-desc d34ef16ba99a # en.yaml over 30 words (63) :: 'The older way of getting a price, kept because retiring it would take ' -option-desc c70929091e71 # en.yaml over 30 words (252); capitals: SWITCHING THIS ON IS WHAT STARTS THE PRICE FETCH :: "Where day-ahead or real-time prices come from. 'off' is what ships, an" -option-desc a62e17ccf445 # en.yaml over 30 words (230); banned: TARIFF-18; capitals: THIS NUMBER IS NOT :: 'Everything on your bill that is not the energy itself - distribution, ' -option-desc 56d56f58c43e # en.yaml over 30 words (206); capitals: THE NUMBERS HERE ARE THE LEVIES ALONE :: 'Leave this empty unless your network tariff really does charge a diffe' -option-desc 0b7ea32cf8d0 # en.yaml over 30 words (193); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' -option-desc 4172d9920d65 # en.yaml over 30 words (128); capitals: MEASUREMENT ONLY :: 'Optional, and MEASUREMENT ONLY - it changes no control behaviour whats' -option-desc 09ceba2c6afb # en.yaml over 30 words (70); banned: clamp; capitals: MEASUREMENT ONLY :: 'Optional, MEASUREMENT ONLY. Some sensors - typically a kWh meter or a ' -option-desc 42a7eaac6ff1 # en.yaml banned: saturated :: 'How many consecutive saturated cycles before the loop stops winding up' -option-desc 12b0dffec9dd # en.yaml over 30 words (42) :: 'The gap between what was commanded and what the inverter delivers that' -option-desc 91fd58c08a59 # en.yaml over 30 words (54) :: 'The ESPHome number entity this add-on writes the power setpoint to, no' -option-desc 01e1af709cd5 # en.yaml over 30 words (201); banned: arbiter, clamps, heartbeat, latch :: 'Runs the whole decision path — strategies, arbiter, clamps and guards ' -option-desc 96b077d4e2e9 # en.yaml over 30 words (72); banned: SAFETY-02; capitals: NOT CHOSEN :: 'MEASURED, NOT CHOSEN (SAFETY-02). How long the setpoint and the meter ' -option-desc addf5c495ae8 # en.yaml over 30 words (90); banned: SAFETY-02, watchdog; capitals: NOT CHOSEN :: 'MEASURED, NOT CHOSEN (SAFETY-02). Both the setpoint being emitted and ' -option-desc 0a66ac772b27 # en.yaml over 30 words (117); banned: SAFETY-30; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS (S' -option-desc c0deabb69ab6 # en.yaml over 30 words (60); banned: SAFETY-30; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. The same 300 W as the single-inverter thre' -option-desc 7d7272743277 # en.yaml over 30 words (123); banned: SAFETY-39; capitals: MEANS FOLLOW THE INVERTER RATING :: 'How far the setpoint may move in one control cycle. ⚠️ 0 MEANS FOLLOW ' -option-desc 436efca21a7d # en.yaml over 30 words (31) :: "The sensor that reports the pack's state of charge in percent. Use the" -option-desc 9ac8a3b21a1e # en.yaml over 30 words (43) :: 'How long the inputs may be missing before the add-on commands 0 W. Wit' -option-desc 86cbfd6a5693 # en.yaml over 30 words (130); capitals: RECOMMENDED EVEN ON :: 'Your fixed or day/night contract, written as a single line of JSON. RE' -option-desc 996dffbf563d # en.yaml over 30 words (74); banned: register :: 'What the meter should sit at when nothing is happening; negative means' -option-desc faf346256008 # en.yaml over 30 words (52); banned: SAFETY-30; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY. DERIVED FROM 1890 CLOSED-LOOP TEST RUNS (S' -option-desc 5323134f3131 # en.yaml over 30 words (95); banned: SAFETY-30, saturation; capitals: TWO OR MORE INVERTERS ONLY :: 'TWO OR MORE INVERTERS ONLY; with one inverter this setting does nothin' -option-name ca3a62bb8260 # en.yaml over 6 words (7) :: 'Circulating-power hold (s) — derived, do not change' -option-name edee163fdc2b # en.yaml over 6 words (7) :: 'Circulating-power threshold (W) — measured, do not change' -option-name 99b3beeab621 # en.yaml over 6 words (7) :: 'Cost of one full charge/discharge cycle (EUR/kWh)' -option-name cccd8a42f51a # en.yaml over 6 words (8) :: 'Not-delivering report after (s) — derived, do not change' -option-name 989891e2ce23 # en.yaml over 6 words (10); banned: Integrator :: 'Integrator bound (W, 0 means the same as the rating)' -option-name 42c6b595320c # en.yaml over 6 words (9) :: 'Inverter list (leave empty if you have one inverter)' -option-name 230e6dc9d872 # en.yaml over 6 words (7) :: 'Hour of day a due cycle starts' -option-name 18e1de907c54 # en.yaml over 6 words (8) :: 'Frozen-meter alarm after (s) — measured, do not change' -option-name 9071c4cfa460 # en.yaml over 6 words (7) :: 'A reading counts as stale after (s)' -option-name e3d06ed93e2e # en.yaml banned: register :: 'Export register entity (W)' -option-name a0f59ea5de36 # en.yaml banned: register :: 'Import register entity (W)' -option-name ed757924f40f # en.yaml over 6 words (7) :: 'Per-phase signed net entities (L1, L2, L3)' -option-name 52d03808da01 # en.yaml over 6 words (8) :: 'Your own INJECTION formula (one line of JSON)' -option-name bf22f2121af4 # en.yaml over 6 words (8) :: 'Your own tariff formula (one line of JSON)' -option-name 5593992fcf5b # en.yaml over 6 words (7) :: 'How far ahead to fetch prices (hours)' -option-name d9fee5514a4b # en.yaml over 6 words (11) :: 'Levies and VAT by time of day (one line of JSON)' -option-name eac7ee084aaa # en.yaml banned: Saturated :: 'Saturated cycles before freezing (count)' -option-name 5c6bbc5cab40 # en.yaml banned: Saturation :: 'Saturation threshold (W)' -option-name 99a1ec154d36 # en.yaml over 6 words (7) :: 'Shadow mode — run every decision, command nothing' -option-name 82fcd0faa687 # en.yaml over 6 words (8); banned: watchdog :: 'Sign watchdog hold (s) — measured, do not change' -option-name 8fc34172dc01 # en.yaml over 6 words (8); banned: watchdog :: 'Sign watchdog threshold (W) — measured, do not change' -option-name 8516934704f5 # en.yaml over 6 words (8) :: 'Site-wide sign hold (s) — derived, do not change' -option-name 2b8278ab2b16 # en.yaml over 6 words (8) :: 'Site-wide sign threshold (W) — measured, do not change' -option-name bd52e795ea97 # en.yaml over 6 words (8) :: 'Command 0 W after inputs missing for (s)' -option-name 9e33febf4481 # en.yaml over 6 words (8) :: 'Fixed or day/night tariff (one line of JSON)' -option-name 40e1e3ba3841 # en.yaml over 6 words (8) :: 'Per-inverter sign hold (s) — derived, do not change' -option-name 4ba7087578dc # en.yaml over 6 words (8) :: 'Per-inverter sign threshold (W) — derived, do not change' -refusal 87620efa0704 # p1.py:1176 banned: telegram :: 'p1_phase_net_entities has {len(phase_net)} entities but meter_phases i' -refusal 5d1b8147792b # p1.py:1186 banned: 192.168.2.250 :: "meter_source {SOURCE_HOMEWIZARD} needs p1_host (the meter's own addres" -refusal 701db346696d # validate.py over 30 words (85); banned: SAFETY-30, watchdog :: 'unit_sign_disagree_w is {unit_sign_w} W but max_w{unit_where} is {weak' -refusal 710b4d89a9d7 # validate.py over 30 words (88); banned: ARBITER, arbiter; capitals: THE CEILING WINS :: 'maintenance_charge_w is {charge_w} W but max_w{maint_where} is {maint_' -refusal 16d40434116b # validate.py over 30 words (193); banned: NOTES.md, §5; capitals: THE PLANT WINS :: 'slew_w is {slew_w} W against a site rail of {rail} W, so the loop cros' -refusal 613375fb6b5f # validate.py over 30 words (107); banned: SAFETY-07; capitals: THE BMS WINS :: "peak_soc_floor is {soc_floor} % but the pack's own cut-out (bms_soc_fl" -refusal ba21c5ba8c0d # validate.py over 30 words (224); banned: TARIFF-07, §1; capitals: IT HAS NEVER FETCHED :: 'price_provider is {pid}, which WAS a shipped plugin and has been WITHD' -refusal de8df32186b6 # validate.py over 30 words (46); banned: §1 :: 'price_provider is {pid}, which is not a shipped plugin. The ids that e' -refusal 0ee7c15eafef # validate.py over 30 words (103); banned: arbitrage.py, main.py, static_tariff.py; capitals: THE HOME ASSISTANT ENTITIES WIN :: "price_provider is {pid} AND {' and '.join(ha_price)} {'is' if len(ha_p" -refusal c4149a762c39 # validate.py over 30 words (62); banned: main.py; capitals: THE HOME ASSISTANT ENTITIES WIN :: "static_profile is set AND {' and '.join(ha_price)} {'is' if len(ha_pri" -refusal 6af34466bbc2 # validate.py over 30 words (83); capitals: THE TABLE WINS :: '{TAXES_PROFILE_OPTION} is set AND price_taxes_eur_kwh is {scalar} rath' -refusal 8f69bdbbf3fc # validate.py over 30 words (55) :: '{TAXES_PROFILE_OPTION} carries {steep} EUR/kWh. Belgian levies and dis' -refusal 96a090d2ad97 # validate.py over 30 words (72); banned: DOCS.md, §1 :: "price_provider is 'custom_formula' but price_formula is empty, so the " -refusal db9d0d53c4f1 # validate.py over 30 words (45); banned: §1 :: "cycle_cost_threshold_eur is {opts.get('cycle_cost_threshold_eur')} and" -refusal 58ccb3bbd560 # validate.py over 30 words (63); banned: §1; capitals: NO PRICES AT ALL :: "arbitrage_enabled is on but price_provider is 'off' and static_profile" -refusal 780592c897fb # validate.py over 30 words (85); banned: arbitrage.py, telegram, §9 :: "arbitrage_enabled is on but meter_source is 'off', so there is no P1 t" -refusal 4f80c091ca95 # validate.py over 30 words (69) :: 'arbitrage_soc_floor is {floor} % and arbitrage_soc_ceiling is {ceiling' -refusal 0c089bb2f200 # validate.py over 30 words (57); banned: §1 :: "price_provider is 'manual_csv' but price_csv_path is empty, so the off" -refusal 152dfec79224 # validate.py over 30 words (48); banned: SAFETY-02, heartbeat, latch :: '{where} has no name. Every inverter needs one: the Store namespaces th' -refusal eb14af760f5c # validate.py over 30 words (51); banned: SAFETY-02, heartbeat, latch :: '{where} and {seen[name]} are both called {name}. The Store keys every ' -refusal 36f53c989b4a # validate.py over 30 words (55) :: '{who} has no setpoint_entity, so this add-on cannot command it. It wou' -refusal c98c6ab66e9f # validate.py over 30 words (56) :: "{who} has no usable max_w (got {entry.get('max_w')}). It is the superv" -refusal 5ca16a4d0a1e # validate.py over 30 words (71) :: '{who} has capacity_kwh {raw}, which is not a usable number of kilowatt' -refusal 63a864d2e0a3 # validate.py over 30 words (73) :: "capacity_kwh is stated on {', '.join(stated)} and left empty on {', '." -refusal 8d82500ecb1d # validate.py over 30 words (64) :: 'setpoint_entity is set to {flat_sp} AND an inverters list of {len(entr' -refusal 3d778e0ab5e1 # validate.py over 30 words (36); capitals: THE DEVICE WINS :: '{name}: max_w is {cap} W but {entity} accepts at most {float(dev_max)}' -refusal ecd0883f5649 # validate.py over 30 words (36); capitals: THE DEVICE WINS :: '{name}: max_w is {cap} W, so this controller may command {-cap} W, but' -refusal eff7efac51f8 # validate.py over 30 words (56); banned: heartbeat :: 'setpoint_entity is not set, so this add-on has no actuator: every writ' -refusal b126f1a88b77 # validate.py over 30 words (76); banned: §1 :: '{len(who)} configured writers can reach the one actuator {actuator}: {' -refusal 07a88756c864 # validate.py over 30 words (48); banned: arbiter :: 'max_w is {max_w} W and must be positive - it is a magnitude, not a sig' -refusal c4a1d0371e31 # validate.py over 30 words (42); capitals: THE DEVICE WINS :: "max_w is {max_w} W but {opts.get('setpoint_entity') or 'the setpoint d" -refusal a15624d1aa10 # validate.py over 30 words (33); capitals: THE DEVICE WINS :: 'max_w is {max_w} W, so this controller may command {-max_w} W, but {op' -refusal 26d0602c32d7 # validate.py over 30 words (79); capitals: THE FIRMWARE WINS :: 'meter_max_age_s is {max_age_s} s but the ESP32 firmware vetoes any P1 ' -refusal 2ade09aaa579 # validate.py over 30 words (73); banned: SAFETY-02, arbiter, watchdog :: 'sign_disagree_w is {sign_w} W but max_w{where} is {weakest} W, so the ' -- 2.54.0 From c84d5fd14f62c1a15e92ae5cb8ff63ebef7e6deb Mon Sep 17 00:00:00 2001 From: goodwe-review <noreply@anthropic.com> Date: Sun, 27 Sep 2026 06:51:57 +0200 Subject: [PATCH 035/105] UX-08 2c review: unit settings anchor to inverters, plainer texts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - messages.setting() for one inverter in the list reads “Inverter rating” for inverter-b (inverters.max_w), so the config panel files per-unit reasons under `inverters`, where the value is changed. - The tariff card and plausibility reasons name “Distribution, levies and VAT” (price_taxes_eur_kwh) again. - The wrong-direction reasons say "safety stop", the sign_disagree_w option says what it protects, and the roster, price-entity, integrator_max_w and capacity_kwh texts read more plainly. - NL: stuurprint -> stuurmodule, "De piekbeperking". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 2 +- goodwe_controller/DOCS.md | 6 +++--- goodwe_controller/app/custom_formula.py | 15 +++++++-------- goodwe_controller/app/messages.py | 8 ++++++-- goodwe_controller/app/validate.py | 17 ++++++++--------- goodwe_controller/test_inverter.py | 16 ++++++++-------- goodwe_controller/test_messages.py | 2 +- goodwe_controller/test_price.py | 6 +++--- goodwe_controller/test_static_tariff.py | 2 +- goodwe_controller/test_validate.py | 6 +++--- goodwe_controller/translations/en.yaml | 6 +++--- goodwe_controller/translations/nl.yaml | 12 ++++++------ 13 files changed, 51 insertions(+), 49 deletions(-) diff --git a/STYLE.md b/STYLE.md index 0a470e9..5b8588b 100644 --- a/STYLE.md +++ b/STYLE.md @@ -6,7 +6,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Title**: at most 5 everyday words. It says what is wrong ("Meter reading may be stuck"). No "GoodWe:" prefix, no full stop. - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. -- **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w). **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. +- **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. - **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index 5e56830..839b5f8 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -40,7 +40,7 @@ Every row of the Commissioning list and every banner is now in `app/messages.py` Validator refusals, the parse errors they carry, and every option name and description are now short. No rule, key, schema, default or exit code changed. Over 36 spoiled configurations the old and new validators refuse the same number of times. The allowlist went from 167 entries to 43, and only log lines (phase 2d) remain on it. -1. **A refusal names the setting by its label and then its key**, as `messages.setting()` writes it: “Inverter rating” (max_w). The key has to stay, because `configui.problems_by_field()` shows a reason beside every key its text names. A test checks each label against en.yaml. A few reasons no longer mention keys they only named in passing, such as `price_markup_eur_kwh` in the withdrawn-provider reason, so the panel shows those reasons beside fewer settings. +1. **A refusal names the setting by its label and then its key**, as `messages.setting()` writes it: “Inverter rating” (max_w). The key has to stay, because `configui.problems_by_field()` shows a reason beside every key its text names. A test checks each label against en.yaml. A few reasons no longer mention keys they only named in passing, such as `price_markup_eur_kwh` in the withdrawn-provider reason, so the panel shows those reasons beside fewer settings. Each reason still names the setting that fixes it. A setting of one inverter in the list is written “Inverter rating” for inverter-b (inverters.max_w), so the panel shows it beside `inverters`, where that value is changed, and not only beside the flat `max_w` that a list does not read. 2. **Citations moved to DOCS.** Option descriptions say "Measured value, leave it unchanged" or similar, and the record behind the value is under "For installers: where the numbers come from". The UX-01 citation check in `test_translations.py` now checks the tab for that instruction and DOCS for the record. 3. **What left the refusals:** the shipped default in the peak-reserve reason, the superseded-default note in the levy-table reason (DOCS already covers it), the endpoints of the withdrawn providers (DOCS "Energy price providers"), the plant measurement behind `slew_w` (DOCS, beside the setting), and the leg-specific paragraphs of the tariff-formula errors. Each reason keeps the rejected value, the limit and what to change. 4. **Not rewritten:** errors that only a code defect can raise, such as plugin-contract and argument-type checks in `price.py`, `price_forecast.py`, `static_tariff.py`, `arbitrage.py` and `main.py`, which a home owner never reads. INFO lines such as the tariff-formula preview were also left. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index c4b1cb2..a3a2015 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -151,7 +151,7 @@ The label and description each setting shows on the Configuration tab, in tab or | Hardware · Inverter list | Battery level entity (%) (optional) | `inverters.soc_entity` | This battery's own level sensor. Leave it empty if this inverter has none. | | Hardware · Inverter list | Battery power entity (W) (optional) | `inverters.batt_entity` | This inverter's own battery power sensor. Leave it empty if it has none. | | Hardware · Inverter list | Battery power sign is reversed (optional) | `inverters.batt_invert` | Switch this on if this inverter's sensor shows giving power as a negative number. | -| Hardware · Inverter list | Usable battery capacity (kWh) (optional) | `inverters.capacity_kwh` | This battery's usable capacity from its datasheet. Fill it in on every inverter or on none, and the work is then shared by energy left. | +| Hardware · Inverter list | Usable battery capacity (kWh) (optional) | `inverters.capacity_kwh` | This battery's usable capacity from its datasheet. Fill it in on every inverter or on none. The add-on then shares the work by the energy each battery has left. | | Hardware | RS485 emergency stop is fitted | `estop_fitted` | Switch this on if the emergency stop is installed. It only changes a warning on the status page. | | Hardware | Solar production entity (W) | `pv_entity` | Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control. | | Hardware | Solar production entities, per inverter (W) | `pv_entities` | Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded. | @@ -201,7 +201,7 @@ The label and description each setting shows on the Configuration tab, in tab or | Maintenance | Draw down to (%) | `maintenance_soc_floor` | The level the monthly cycle empties the battery to. It is not the “Peak reserve”, and the two differ on purpose. | | Maintenance | Recharge up to (%) | `maintenance_soc_target` | The level the recharge aims for before the hold starts. | | Maintenance | Hold at full for (minutes) | `maintenance_hold_min` | How long the battery stays full so its cells can balance. | -| Safety | Wrong-direction threshold (W) | `sign_disagree_w` | A wrong direction counts only when the command and the meter reading both exceed this. Measured value, leave it unchanged. | +| Safety | Wrong-direction threshold (W) | `sign_disagree_w` | Part of the safety stop for an inverter pushing the wrong way. It counts only when command and meter reading both exceed this. Measured value, leave it unchanged. | | Safety | Wrong-direction time (s) | `sign_disagree_s` | How long a wrong direction may last before a safety stop sets every inverter to 0 W. Measured value, leave it unchanged. | | Safety | Per-inverter wrong-direction threshold (W) | `unit_sign_disagree_w` | For two or more inverters: the wrong-direction threshold for each inverter. Derived value, leave it unchanged. | | Safety | Per-inverter wrong-direction time (s) | `unit_sign_disagree_s` | For two or more inverters: how long one inverter may push the wrong way before it is set to 0 W. Derived value, leave it unchanged. | @@ -220,7 +220,7 @@ The label and description each setting shows on the Configuration tab, in tab or | Advanced | Command rounding (W) | `step_w` | The command is rounded to a multiple of this, so noise does not change it every cycle. | | Advanced | Inverter at limit gap (W) | `saturation_w` | When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this. | | Advanced | Cycles at limit before freezing | `saturation_cycles` | How many cycles in a row at the limit before control stops building up error. Do not set it to 1. | -| Advanced | Error build-up limit (W) | `integrator_max_w` | Limits how much old error control can carry, and 0 means “Inverter rating”. Do not raise it above the rating. | +| Advanced | Error build-up limit (W) | `integrator_max_w` | Caps the error that control saves up from past cycles. 0 means “Inverter rating”. Do not raise it above the rating. | | Advanced | Command refresh interval (s) | `heartbeat_s` | How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit. | | Advanced | Missing inputs time limit (s) | `stale_input_s` | How long inputs may be missing before every inverter is set to 0 W. With a P1 meter it starts after “Reading too old after”. | | Advanced | Longest time between cycles (s) | `cycle_floor_s` | A deadline between control cycles that a healthy meter never reaches. Raise it only for a meter slower than about 10 s. | diff --git a/goodwe_controller/app/custom_formula.py b/goodwe_controller/app/custom_formula.py index fcd2285..e7297b7 100644 --- a/goodwe_controller/app/custom_formula.py +++ b/goodwe_controller/app/custom_formula.py @@ -292,7 +292,8 @@ _LEGS = { neg_factor="Put the minus sign on the offset, not on the factor", card_required=True, card_note="The add-on needs it to check your two numbers", - card_causes="that network charges are not in the offset", + card_causes=("that network charges are in “Distribution, levies and VAT” " + "(price_taxes_eur_kwh), not in the offset"), ), EXPORT_FORMULA_OPTION: _Leg( option=EXPORT_FORMULA_OPTION, @@ -678,10 +679,8 @@ def parse_export_formula(value): def card_refusal(spec: FormulaSpec, delta: float) -> str: """The sentence an operator reads when their formula misses its own card. - ⚠️ IT NAMES THE DISCREPANCY AND THE SIX WAYS IT HAPPENS. "Invalid - configuration" would be true and useless: every one of these errors looks - exactly like a working tariff from the status page, which is why the check - exists at all. + It names both numbers and what to check. The usual causes are in DOCS.md, + because each of these errors looks like a working tariff on the status page. """ got = in_card_units(spec, spec.card_index_eur_per_mwh) leg = _LEGS[spec.option] @@ -744,9 +743,9 @@ def implausible_all_in(spec: FormulaSpec, taxes_eur_kwh: float): return None return ( f"{spec.option} gives {energy:.5f} EUR/kWh for energy and " - f"{all_in:.5f} EUR/kWh in total on its own card, outside the " - f"plausible band of {PLAUSIBLE_LO_EUR_KWH}-{PLAUSIBLE_HI_EUR_KWH} " - f"EUR/kWh. Check \"units\" against the unit beside your formula.") + f"{all_in:.5f} EUR/kWh with “Distribution, levies and VAT” " + f"(price_taxes_eur_kwh), outside the plausible band of " + f"{PLAUSIBLE_LO_EUR_KWH}-{PLAUSIBLE_HI_EUR_KWH} EUR/kWh. Check \"units\" against the unit beside your formula.") def implausible_injection(spec: FormulaSpec): diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 462bc7c..8974068 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -844,5 +844,9 @@ LABELS = { def setting(key: str, unit: str = "") -> str: - """`max_w` -> `“Inverter rating” (max_w)`, plus ` for inverter-b` in a list.""" - return f"“{LABELS[key]}” ({key})" + (f" for {unit}" if unit else "") + """`max_w` -> `“Inverter rating” (max_w)`. For one inverter in a list it is + `“Inverter rating” for inverter-b (inverters.max_w)`, so the config panel + also shows the reason beside `inverters`, where that value is changed.""" + if unit: + return f"“{LABELS[key]}” for {unit} (inverters.{key})" + return f"“{LABELS[key]}” ({key})" diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index da3ad67..53707c6 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -703,8 +703,8 @@ def _roster_problems(opts: dict) -> list[str]: if entries and flat_sp: problems.append( f"{S('setpoint_entity')} is set to {flat_sp}, but the " - f"{S('inverters')} has {len(entries)} entries. Move that inverter " - "into the list and clear this setting.") + f"{S('inverters')} is also filled in. Move that inverter into the " + "list and clear this setting.") return problems @@ -924,8 +924,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] where = _unit_label(opts, min(caps_ix, key=lambda p: p[1])[0]) problems.append( f"{S('sign_disagree_w')} is {sign_w:.0f} W, but the " - f"{S('max_w', where)} is {weakest:.0f} W, so this check can never " - f"trip. Lower it below {weakest:.0f} W, or raise the rating.") + f"{S('max_w', where)} is {weakest:.0f} W, so this safety stop can " + f"never trip. Lower it below {weakest:.0f} W, or raise the rating.") # ⚠️ AND THE SAME RULE FOR SAFETY-30's PER-UNIT THRESHOLD, WHICH IS A # SEPARATE COMPARISON AND THEREFORE A SEPARATE WAY TO DISARM. It grades a @@ -978,8 +978,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] elif weakest is not None and weakest > 0 and unit_sign_w >= weakest: problems.append( f"{S('unit_sign_disagree_w')} is {unit_sign_w:.0f} W, but the " - f"{S('max_w', unit_where)} is {weakest:.0f} W, so this check can " - f"never trip. Lower it below {weakest:.0f} W, or raise the " + f"{S('max_w', unit_where)} is {weakest:.0f} W, so this safety stop " + f"can never trip. Lower it below {weakest:.0f} W, or raise the " "rating.") # --- 6. a maintenance charge the ceiling can actually accommodate -------- @@ -1301,9 +1301,8 @@ def _price_problems(opts: dict) -> list[str]: # day/night tariff has no way to see that it lost. if ha_price and str(opts.get("static_profile", "") or "").strip(): problems.append( - f"{S('static_profile')} and {_labels(ha_price)} are both set, and " - "only the Home Assistant price entities would count. Clear one of " - "the two.") + f"{S('static_profile')} is set, but {_labels(ha_price)} would win " + "over it. Clear the one you do not use.") # ⚠️ THE PROFILE ITSELF, PARSED AT STARTUP RATHER THAN AT 02:00. A profile # that does not tile the day has hours with no price, and the only ways to diff --git a/goodwe_controller/test_inverter.py b/goodwe_controller/test_inverter.py index 8fdc26a..1a14bce 100644 --- a/goodwe_controller/test_inverter.py +++ b/goodwe_controller/test_inverter.py @@ -1653,7 +1653,7 @@ check("a flat setpoint_entity left set BESIDE a declared roster is refused. It " "names an actuator the roster does not, so nothing would ever write it - " "a site running quietly smaller than its own configuration, which is the " "'silently a different config' outcome this card ranks below a refusal", - _why(_p_flat, "but the “Inverter list” (inverters) has")) + _why(_p_flat, "but the “Inverter list” (inverters) is also filled in")) _p_dup = validate_startup_config(_opts(setpoint_entity="", inverters=[ dict(name="twin", setpoint_entity="number.sp_a", max_w=A_RATING), dict(name="twin", setpoint_entity="number.sp_b", @@ -1739,8 +1739,8 @@ check("the fixture actually desynchronises the two lists, or the two checks " check("⚠️ RULE 5 NAMES THE UNIT THE NUMBER CAME OFF. The weakest cap is " "inverter-c's 1000 W; it sits at caps index 1, and `_unit_label(opts, 1)` " "is inverter-B. The refusal says inverter-c", - _why(_p_skew, "(max_w) for inverter-c is 1000 W") - and not _why(_p_skew, "(max_w) for inverter-b is 1000 W")) + _why(_p_skew, "for inverter-c (inverters.max_w) is 1000 W") + and not _why(_p_skew, "for inverter-b (inverters.max_w) is 1000 W")) # ⚠️ MAINT-05 MOVED RULE 6's SUBJECT, AND THIS CHECK MOVED WITH IT. It used to # assert the refusal named inverter-b, because rule 6 graded the FIRST entry # with a usable cap - `Controller.maint_unit` was `inverters[0]` and the shaping @@ -1754,15 +1754,15 @@ check("⚠️ RULE 6 TOO, AND SINCE MAINT-05 IT IS THE WEAKEST PACK IT NAMES. " "inverter-c's 1000 W sits at caps index 1, and `_unit_label(opts, 1)` is " "inverter-B - so a caps index leaking into a roster index would say " "inverter-b here. The refusal says inverter-c, with inverter-c's number", - _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for " - "inverter-c is 1000 W") - and not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for " + _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” for " + "inverter-c (inverters.max_w) is 1000 W") + and not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” for " "inverter-b")) check("...and it is no longer graded against the FIRST usable cap at all, which " "is the behaviour change MAINT-05 makes here: inverter-b's 2000 W was the " "pre-card answer and appears nowhere in the maintenance refusal now", - not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” (max_w) for " - "inverter-b is 2000 W")) + not _why(_p_skew, "(maintenance_charge_w) is 3000 W, but the “Inverter rating” for " + "inverter-b (inverters.max_w) is 2000 W")) check("...and the counterfactual, so this is not a check that would pass on a " "validator that named nothing: the OLD expressions still evaluate, on " "this same config, to the wrong names", diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 66eb2a6..96119ca 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -554,7 +554,7 @@ check(f"every label a refusal quotes is the setting's name in en.yaml " check("...and a refusal quotes the label and then the key, so the config " "panel still files it under that setting", messages.setting("max_w", "inverter-b") - == "“Inverter rating” (max_w) for inverter-b") + == "“Inverter rating” for inverter-b (inverters.max_w)") print(f"CI: UX-08 allowlist {len(allow)} entries " + ", ".join(f"{k} {sum(1 for x in allow if x.startswith(k + ' '))}" for k in LIMITS)) diff --git a/goodwe_controller/test_price.py b/goodwe_controller/test_price.py index 208b67c..041f89e 100644 --- a/goodwe_controller/test_price.py +++ b/goodwe_controller/test_price.py @@ -2198,7 +2198,7 @@ _ps = validate_startup_config( -5000, 5000) check("a static_profile AND the Home Assistant price entities is refused too - " "main.py reads one of them for `cheap` and the loser is silent", - len(_ps) == 1 and why(_ps, "Home Assistant price entities would count")) + len(_ps) == 1 and why(_ps, "(price_now_entity) and “Average price entity” (price_avg_entity) would win")) check("the Home Assistant entities alone still start, so nothing is taken away " "from a live install", validate_startup_config(vbase(price_now_entity="sensor.now", @@ -3428,7 +3428,7 @@ check(f"network charges folded into `offset` move the card's own price to " check(f"...and it is refused, by the CARD rule, naming the discrepancy and " f"the network-charge cause ({_double[:60]!r})", "does not match its own card" in _double and "the card says" in _double - and "network charges are not in the offset" in _double) + and "(price_taxes_eur_kwh), not in the offset" in _double) _CORRUPTIONS = { "VAT left out (vat_pct 0)": spoilt(vat_pct=0), @@ -5360,7 +5360,7 @@ _T16_DIFFER = [ # UX-08 2c: a negative factor gets one sentence on both legs now ("put the # minus sign on the offset"), so it left this table. ("a card miss -> what else to check on THIS leg", - spoilt(factor=0.120), "network charges are not in the offset", + spoilt(factor=0.120), "(price_taxes_eur_kwh), not in the offset", "vat_pct is 0 for injection"), ("invalid JSON -> WHEN this option is read at all, which is not the " "same answer on the two legs: `price_formula` decides nothing unless " diff --git a/goodwe_controller/test_static_tariff.py b/goodwe_controller/test_static_tariff.py index b2cda49..0abe17b 100644 --- a/goodwe_controller/test_static_tariff.py +++ b/goodwe_controller/test_static_tariff.py @@ -859,7 +859,7 @@ check("static_profile alongside the Home Assistant price entities is refused - " why(validate_startup_config( vbase(static_profile=json.dumps(TWO_PERIOD), price_now_entity="sensor.now", price_avg_entity="sensor.avg"), - -5000, 5000), "Home Assistant price entities would count")) + -5000, 5000), "(price_avg_entity) would win over it")) check("...and the Home Assistant pair ALONE still starts, so nothing is taken " "away from a live install", validate_startup_config(vbase(price_now_entity="sensor.now", diff --git a/goodwe_controller/test_validate.py b/goodwe_controller/test_validate.py index b0bcb99..85fe40b 100644 --- a/goodwe_controller/test_validate.py +++ b/goodwe_controller/test_validate.py @@ -452,11 +452,11 @@ check("⚠️ A CHARGE RATE THE SMALLEST PACK CANNOT TAKE IS REFUSED, even thoug "recalibrated, so its cap could not contradict anything; it is now, and " "its cheap-window charge would ask for hi=-3000 against lo=-2000 - the " "`lo > hi` contradiction, 0 W, on the pack nobody was watching", - len(_p_two) == 1 and why(_p_two, "(max_w) for inverter-b is 2000 W")) + len(_p_two) == 1 and why(_p_two, "for inverter-b (inverters.max_w) is 2000 W")) check("...and the message names the pack the number came off, not the first " "entry - an operator told to lower a number on the wrong device is being " "sent to the wrong device by the message that exists to stop that", - not why(_p_two, "(max_w) for inverter-a")) + not why(_p_two, "for inverter-a (inverters.max_w)")) check("...while the same rate against two packs that can both take it starts, " "so this is a comparison and not a blanket refusal of rosters", [p for p in validate_startup_config( @@ -1223,7 +1223,7 @@ def _verdict(opts, token): ps = [p for p in validate_startup_config(opts, -5000, 5000) if token in p] if not ps: return (False, None, None) - m = re.search(r"\(max_w\) for (\S+) is (\d+) W", ps[0]) + m = re.search(r"for (\S+) \(inverters\.max_w\) is (\d+) W", ps[0]) return (True, m.group(1) if m else None, float(m.group(2)) if m else None) diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index ef97ea2..53e766e 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -78,7 +78,7 @@ configuration: description: "Switch this on if this inverter's sensor shows giving power as a negative number." capacity_kwh: name: "Usable battery capacity (kWh) (optional)" - description: "This battery's usable capacity from its datasheet. Fill it in on every inverter or on none, and the work is then shared by energy left." + description: "This battery's usable capacity from its datasheet. Fill it in on every inverter or on none. The add-on then shares the work by the energy each battery has left." estop_fitted: name: "Hardware · RS485 emergency stop is fitted" description: "Switch this on if the emergency stop is installed. It only changes a warning on the status page." @@ -228,7 +228,7 @@ configuration: description: "How long the battery stays full so its cells can balance." sign_disagree_w: name: "Safety · Wrong-direction threshold (W)" - description: "A wrong direction counts only when the command and the meter reading both exceed this. Measured value, leave it unchanged." + description: "Part of the safety stop for an inverter pushing the wrong way. It counts only when command and meter reading both exceed this. Measured value, leave it unchanged." sign_disagree_s: name: "Safety · Wrong-direction time (s)" description: "How long a wrong direction may last before a safety stop sets every inverter to 0 W. Measured value, leave it unchanged." @@ -285,7 +285,7 @@ configuration: description: "How many cycles in a row at the limit before control stops building up error. Do not set it to 1." integrator_max_w: name: "Advanced · Error build-up limit (W)" - description: "Limits how much old error control can carry, and 0 means “Inverter rating”. Do not raise it above the rating." + description: "Caps the error that control saves up from past cycles. 0 means “Inverter rating”. Do not raise it above the rating." heartbeat_s: name: "Advanced · Command refresh interval (s)" description: "How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index 41deae8..daa0d76 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -25,7 +25,7 @@ configuration: description: "De ESPHome-entiteit waar de add-on het vermogen van de omvormer naartoe schrijft. Laat dit leeg als u de lijst met omvormers invult." soc_entity: name: "Hardware · Entiteit laadniveau (%)" - description: "De sensor met het laadniveau van de batterij in procent. Gebruik de meting van de stuurprint zelf." + description: "De sensor met het laadniveau van de batterij in procent. Gebruik de meting van de stuurmodule zelf." batt_entity: name: "Hardware · Entiteit batterijvermogen (W)" description: "De sensor met het batterijvermogen van deze omvormer. Positief moet betekenen dat de batterij stroom levert." @@ -59,7 +59,7 @@ configuration: description: "Zet dit aan als de sensor van deze omvormer leveren als een negatief getal toont." capacity_kwh: name: "Bruikbare capaciteit (kWh) (optioneel)" - description: "De bruikbare capaciteit van deze batterij, van het datablad. Vul ze bij elke omvormer in of bij geen enkele. Het werk wordt dan verdeeld volgens de energie die over is." + description: "De bruikbare capaciteit van deze batterij, van het datablad. Vul ze bij elke omvormer in of bij geen enkele. De add-on verdeelt het werk dan volgens de energie die elke batterij nog heeft." estop_fitted: name: "Hardware · RS485-noodstop is geplaatst" description: "Zet dit aan als de noodstop geïnstalleerd is. Het verandert alleen een waarschuwing op de statuspagina." @@ -128,7 +128,7 @@ configuration: description: "Optioneel. Een prognose van het gemiddelde vermogen in het lopende kwartier. Laat u dit leeg, dan is er geen piekgrens." peak_soc_floor: name: "Grenzen · Piekreserve (%)" - description: "Het afvlakken van de piek laat de batterij niet onder dit niveau zakken, gewoon verbruik wel. Afgeleide waarde, laat ze ongewijzigd." + description: "De piekbeperking laat de batterij niet onder dit niveau zakken, gewoon verbruik wel. Afgeleide waarde, laat ze ongewijzigd." price_provider: name: "Tarief · Bron van dynamische prijzen" description: "Waar de prijzen vandaan komen. Een bron kiezen start het ophalen van prijzen, ook als handelen uit staat." @@ -209,7 +209,7 @@ configuration: description: "Hoe lang de batterij vol blijft zodat de cellen in evenwicht komen." sign_disagree_w: name: "Veiligheid · Drempel verkeerde richting (W)" - description: "Een verkeerde richting telt pas als het commando en de meterstand allebei boven deze waarde liggen. Gemeten waarde, laat ze ongewijzigd." + description: "Deel van de veiligheidsstop voor een omvormer die de verkeerde kant op duwt. Het telt pas als commando en meterstand allebei boven deze waarde liggen. Gemeten waarde, laat ze ongewijzigd." sign_disagree_s: name: "Veiligheid · Tijd verkeerde richting (s)" description: "Hoe lang een verkeerde richting mag duren voor een veiligheidsstop elke omvormer op 0 W zet. Gemeten waarde, laat ze ongewijzigd." @@ -266,10 +266,10 @@ configuration: description: "Hoeveel cycli na elkaar aan de grens voor de regeling stopt met afwijking opbouwen. Zet dit niet op 1." integrator_max_w: name: "Geavanceerd · Grens opgebouwde afwijking (W)" - description: "Beperkt hoeveel oude afwijking de regeling meedraagt, en 0 betekent het vermogen van de omvormer. Zet dit niet hoger dan dat vermogen." + description: "Begrenst de afwijking die de regeling uit vorige cycli opspaart. 0 betekent het vermogen van de omvormer. Zet dit niet hoger dan dat vermogen." heartbeat_s: name: "Geavanceerd · Commando opnieuw sturen na (s)" - description: "Hoe vaak het commando opnieuw gestuurd wordt, ook als het gelijk bleef. Houd dit ruim onder de eigen grens van 30 s van de stuurprint." + description: "Hoe vaak het commando opnieuw gestuurd wordt, ook als het gelijk bleef. Houd dit ruim onder de eigen grens van 30 s van de stuurmodule." stale_input_s: name: "Geavanceerd · Tijdslimiet ontbrekende invoer (s)" description: "Hoe lang invoer mag ontbreken voor elke omvormer op 0 W gaat. Bij een P1-meter begint dit pas na de grens voor een te oude meting." -- 2.54.0 From 6a95447248c8cb15d58194188b7d036b4e034f7d Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 08:01:16 +0200 Subject: [PATCH 036/105] UX-08 2d: plain log lines, the rest of the status page, and DOCS Every WARNING and ERROR line is one plain line of at most 25 words, with no card ids, capitals or semicolons; the reasoning of the ten longest is on a DEBUG line. The ux08 allowlist is empty and its cap is 0 (43 -> 0). The status page: the month-peak and peak-guard rows, the stale-reading row, the top table (Why, Tariff, Arbitrage, Shadow mode, labels), the Stopped banner and the line under the buttons, which now shows the plain hint of each event instead of the raw action log. The Supervisor question at start logs one line with a real reason. Refusals are counted as shown (labels expanded, long cases driven), seven were shortened, the card and parse errors lost their internals, a blank value reads "empty", and the panel no longer files inverters.max_w under the flat max_w. Option names lose "(JSON)", the NL texts are checked too. DOCS gets a glossary (control board, isolator, Developer Tools) and card ids move from headings to a "For installers" line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 12 +- .../DECISIONS/UX-08-short-notifications.md | 17 + goodwe_controller/DOCS.md | 252 ++++++--- goodwe_controller/app/config_page.py | 7 +- goodwe_controller/app/configui.py | 5 +- goodwe_controller/app/custom_formula.py | 26 +- goodwe_controller/app/inverter.py | 3 +- goodwe_controller/app/main.py | 514 ++++++++++-------- goodwe_controller/app/messages.py | 263 ++++++++- goodwe_controller/app/p1.py | 13 +- goodwe_controller/app/peakguard.py | 21 +- goodwe_controller/app/price.py | 44 +- goodwe_controller/app/price_history.py | 14 +- goodwe_controller/app/selfconfig.py | 8 +- goodwe_controller/app/shadow.py | 41 +- goodwe_controller/app/static_tariff.py | 63 ++- goodwe_controller/app/store.py | 4 +- goodwe_controller/app/validate.py | 129 ++--- goodwe_controller/app/web.py | 15 +- goodwe_controller/test_arbitrage.py | 13 +- goodwe_controller/test_clamp.py | 29 +- goodwe_controller/test_control_task.py | 8 +- goodwe_controller/test_freshness.py | 30 +- goodwe_controller/test_inverter.py | 2 +- goodwe_controller/test_maintenance.py | 6 +- goodwe_controller/test_messages.py | 203 ++++++- goodwe_controller/test_peakguard.py | 13 +- goodwe_controller/test_price.py | 67 +-- goodwe_controller/test_price_history.py | 12 +- goodwe_controller/test_pv.py | 18 +- goodwe_controller/test_selfconfig.py | 4 +- goodwe_controller/test_static_tariff.py | 2 +- goodwe_controller/test_tariff.py | 67 ++- goodwe_controller/test_validate.py | 16 +- goodwe_controller/test_watchdog.py | 2 +- goodwe_controller/translations/en.yaml | 18 +- goodwe_controller/translations/nl.yaml | 20 +- goodwe_controller/ux08_allowlist.txt | 55 +- 38 files changed, 1294 insertions(+), 742 deletions(-) diff --git a/STYLE.md b/STYLE.md index 5b8588b..dd5a0a3 100644 --- a/STYLE.md +++ b/STYLE.md @@ -1,13 +1,15 @@ # STYLE.md - how user-facing text is written (UX-08) -This applies to everything a home owner or installer reads: notifications, phone pushes, the add-on page, refusals, add-on log lines at WARNING and above, and the names and descriptions of options. It is enforced by `goodwe_controller/test_messages.py`. Kinds that have not been rewritten yet are on its allowlist, and that allowlist only shrinks. +This applies to everything a home owner or installer reads: notifications, phone pushes, the add-on page, refusals, add-on log lines at WARNING and above, and the names and descriptions of options. It is enforced by `goodwe_controller/test_messages.py`. Its allowlist is empty since phase 2d and its cap is 0: a new string that breaks the rule fails the test. ## 1. Shape - **Title**: at most 5 everyday words. It says what is wrong ("Meter reading may be stuck"). No "GoodWe:" prefix, no full stop. - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. - **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. -- **Log line** (WARNING/ERROR): one line, at most 25 words. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. +- **Log line** (WARNING/ERROR): one line, at most 25 words, with the numbers that matter. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. A reason text a line quotes (`%s`) keeps its own codes, because that is the evidence an installer searches for. +- **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3). +- **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. ## 2. Numbers @@ -48,8 +50,14 @@ A setting is named by its label in `translations/en.yaml`, in quotes when it sit | safety stop (a stop that only starting control clears) | failsafe latch | | software fault | BUG SIGNAL | | control board | master, ESP32 | +| power request, what the add-on asks | command, setpoint (on the page) | +| the power went the wrong way | sign disagreement, command and meter point opposite ways | +| check for inverters working against each other | circulating power check | +| month peak, 15-minute periods measured | billed quarter, banked, soft limit, open block | | shadow mode | a mode that makes every decision but commands 0 W. The name is kept. In shadow mode a text says what the add-on **would** send, never that it sent it. | **Banned in titles and bodies** (the test fails on them): SAFETY-/TARIFF-/TEL-/CFG-/FW-/HW-nn and other card ids, integrator, anti-windup, windup, clamp, clamped, saturated, BUG SIGNAL, latch, latched, arbiter, allocator, register, `0x…`, layer 1/2/3, heartbeat, watchdog, telegram, ACK, CRC, OTA, Modbus, planner, `§n`, file names, IP addresses, option keys in snake_case, **HA entity ids**, and runs of 2 or more CAPITALISED words. HA entity ids are allowed only in refusals and validator messages, where the installer has to find that entity. They are never allowed in alarms or status rows. + +**Glossary.** DOCS.md "Words used on this page" explains, once, the words a home owner meets without context: control board, isolator, Developer Tools, shadow mode, safety stop, peak limit, peak guard, peak reserve and cut-out level. A home-owner text may use them without explaining them again. Card ids stay out of DOCS.md headings: they go on a *For installers* line under the heading. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index 839b5f8..9750f74 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -44,3 +44,20 @@ Validator refusals, the parse errors they carry, and every option name and descr 2. **Citations moved to DOCS.** Option descriptions say "Measured value, leave it unchanged" or similar, and the record behind the value is under "For installers: where the numbers come from". The UX-01 citation check in `test_translations.py` now checks the tab for that instruction and DOCS for the record. 3. **What left the refusals:** the shipped default in the peak-reserve reason, the superseded-default note in the levy-table reason (DOCS already covers it), the endpoints of the withdrawn providers (DOCS "Energy price providers"), the plant measurement behind `slew_w` (DOCS, beside the setting), and the leg-specific paragraphs of the tariff-formula errors. Each reason keeps the rejected value, the limit and what to change. 4. **Not rewritten:** errors that only a code defect can raise, such as plugin-contract and argument-type checks in `price.py`, `price_forecast.py`, `static_tariff.py`, `arbitrage.py` and `main.py`, which a home owner never reads. INFO lines such as the tariff-formula preview were also left. + +# UX-08 phase 2d: log lines, the rest of the status page, and DOCS + +The allowlist is empty and its cap is 0 (43 → 0). Every WARNING and ERROR line is one plain line of at most 25 words, with no card ids, capitals or semicolons (the semicolon rule now covers log lines too). **Unchanged:** every log level, every trigger and cadence, every notification id, every row's colour and when it shows, the banner cascade, and every refusal count. + +1. **No code prefixes on log lines.** Nothing outside the repositories greps them, except `/home/homelab/clampwatch.sh`, a one-off site watch from 2026-09-05 that greps `OUTPUT_CLAMP` and `Engagements so far`. `OUTPUT_CLAMP` is still in the reason the line quotes; "Engagements so far" is now "Cut back N times so far". The tests that found a line by its card id (`SAFETY-37`, `SAFETY-44`, `CONTROL LOOP DIED`, `UNGRADED`) now find it by its words. +2. **Reason texts keep their codes.** A line quotes a watchdog's reason (`%s`), such as `STALE_READING: …` or `OUTPUT_CLAMP: …`. Those are the evidence an installer searches for and many tests pin them, so they were not rewritten. The line around them is plain. +3. **Reasoning moved to DEBUG, not deleted,** for the 10 lines marked DROP-to-DEBUG (for example the 14 768 W history behind the over-rating alarm, why SAFETY-42 reports and does not act, and the Eneco card advice). The 25-word line keeps the action and the numbers. SAFETY-57's promise stays on the ERROR line, as an ordered pair: "until it changes, or 17 s after the command drops below 250 W". +4. **The line under the buttons** showed the newest raw action-log entry (`OUTPUT_CLAMP …`, `FAILSAFE …: SIGN_DISAGREEMENT`, `ALLOCATOR …`). Each `log_event()` call now also names a plain hint from `messages.HINTS`, and the page shows that. The action log itself is unchanged, because tests and later analysis read it, and the page no longer shows it. +5. **The top table.** *Why* is `messages.why()`: the arbiter's winner and limit in words ("Keeping the grid near zero: 440 W, held back by the peak limit"). `self.reason` keeps `Resolution.explain()` for the log and the checks. *Tariff*, *Price history*, *Arbitrage* and *Shadow mode* keep every figure TARIFF-11 and SAFETY-47 put there, each in its own slot, in words. Labels: *Battery level*, *Solar production*, *Power request*. +6. **The month-peak row became two rows**, because one sentence of 15 words cannot hold the peak, its time, its share of the limit and TARIFF-13's coverage figure. The store's state at start (`restore_state`) left the row: it is the INFO line at start. +7. **The peak guard rows** name the projection first and the limit second, as before (SAFETY-38). The blind row says what it means for the owner: the battery does not charge until the period can be measured again. +8. **Wording that changed meaning-carrying words**: "command and meter point opposite ways" is now "the power went the wrong way" (banner) and "…went against what the add-on asked" (row). The N=1 banner still names the meter, the N≥2 texts still say "own power". The inverter range reads "up to 5 000 W each way" instead of "-5 000 W to 5 000 W". +9. **Refusals are counted as shown.** Setting placeholders are expanded to label and key, and the long cases the 2c test found are driven through the validator. Seven refusals were shortened. The card refusals no longer show `c_eur_per_kwh`, `vat_pct` or "its own card", and a text that does not parse says "not valid near character N" instead of the parser's words. A missing value shows as *empty*, not `None`. +10. **The panel's key match** no longer files `inverters.max_w` under the flat `max_w`. +11. **The Supervisor question at start** is one INFO line with a real reason (a timeout's own text is empty, so the error type is named). +12. **DOCS**: a glossary ("Words used on this page") explains control board, isolator and Developer Tools once. Card ids left the headings and sit on a *For installers* line under each. The links to the renamed headings were updated. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index a3a2015..82477d5 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -7,45 +7,73 @@ balance cells and recalibrate its coulomb counter. Installers: the printed field guide (`docs/GoodWe-RS485-Field-Guide.pdf`) is v0.1.0 and outdated; where it disagrees with this page, this page wins. +## Words used on this page + +- **Control board**: the small computer wired to the inverter's RS485 meter + bus (a T-CAN485 board with an ESP32 chip). It passes the add-on's power + request to the inverter. If the add-on goes quiet for about 30 seconds, it + sets the inverter to 0 W by itself. +- **Isolator**: the switch that cuts an inverter off from the mains. Switching + it off stops the inverter, whatever the add-on or the control board asks. +- **Developer Tools**: the Home Assistant page that lists every entity and its + current value, on its *States* tab. Use it to check that a sensor the add-on + reads is really there and updating. +- **Shadow mode**: the add-on makes every decision but sends nothing, so every + inverter stays at 0 W. Pages and notifications say what it *would* have done. +- **Safety stop**: the add-on has set one inverter, or all of them, to 0 W and + keeps it there until you start control on the add-on page. +- **Peak limit**: the 15-minute average grid use you want to stay under this + month, because your capacity tariff bills the highest one. +- **Peak guard**: the part of the add-on that uses the battery to keep each + 15-minute period under the peak limit. +- **Peak reserve** and **battery cut-out level**: the charge the peak guard + keeps back, and the level where the battery switches itself off. + ## Before you start You need: - A GoodWe **ES / BP family** inverter (AA55 / RS485 meter-bus generation) - The vendor's meter-emulating controller **disconnected** from the bus -- A T-CAN485 (ESP32) flashed with `firmware/goodwe-master.yaml` +- A control board: a T-CAN485 (ESP32) flashed with + `firmware/goodwe-master.yaml` - A grid-power sensor already working in Home Assistant, updating every ~5–10 s -After installing, turn on **Watchdog** on the add-on's Info tab. A crashed -control loop stops the add-on at 0 W, and the Supervisor restarts it only when -Watchdog is on (it is off by default). See -`DECISIONS/SAFETY-61-control-task-death.md`. +After installing, turn on **Watchdog** on the add-on's Info tab. If control +stops by accident, the add-on sets the inverters to 0 W and exits, and Home +Assistant starts it again only when Watchdog is on. It is off by default. ## The safety model, in short -The inverter **holds its last command forever** — it has no meter-timeout. So: +The inverter **keeps its last power request forever**. It has no timeout of its +own. So: -- The ESP32 commands 0 W if this add-on stops refreshing for ~30 s, and keeps - commanding it. -- This add-on commands 0 W when its inputs go missing, when you stop control, - and when it shuts down. -- This add-on commands 0 W **and latches there** if what it is commanding and - what the meter reads point opposite ways for three minutes — see "The +- The control board sets the inverter to 0 W if this add-on stops sending for + about 30 seconds, and keeps it there. +- This add-on sets the inverters to 0 W when a reading goes missing, when you + stop control, and when it shuts down. +- This add-on sets the inverters to 0 W **and keeps them there** if the power + goes the opposite way to what it asks for three minutes. See "The sign-disagreement failsafe" below. -- The **optional RS485 e-stop** is the only thing that covers this machine - dying. Without it, a failed host leaves the battery latched at its last - command until someone intervenes. -- This add-on **raises an alarm — and nothing more —** when the meter keeps - answering with a reading that never changes while the command sits at the - rail. See "The frozen-meter alarm" and, before you rely on it, "Capacity-tariff - exposure of the grid-following loop". +- The **optional emergency stop** is the only thing that covers this computer + failing. Without it, the battery keeps its last power request until someone + steps in. +- This add-on **raises an alarm, and does nothing more,** when the meter keeps + answering with a value that never changes while the battery is asked for + full power. See "The frozen-meter alarm" and, before you rely on it, + "Capacity-tariff exposure of the grid-following loop". -**If anything looks wrong: stop the add-on.** That commands 0 W and the -hardware holds it there. +**If anything looks wrong: stop the add-on.** That sets the inverters to 0 W, +and the control board keeps them there. + +*For installers: a crashed control task is SAFETY-61, see +`DECISIONS/SAFETY-61-control-task-death.md`.* ## Configuration -### ⚠️ There are TWO places to configure this add-on (UX-02) +### ⚠️ There are TWO places to configure this add-on + +*For installers: card UX-02.* Since **UX-02** the ingress panel has a **Configuration** page of its own, beside Home Assistant's *Configuration* tab. Both edit the **same** settings — @@ -108,7 +136,9 @@ One column, big targets, sections collapsed until you open them, and the refusals pinned where you cannot scroll past them. It is the screen for standing in front of the inverter. -### What the Configuration tab actually shows you (UX-01) +### What the Configuration tab actually shows you + +*For installers: card UX-01.* Since **UX-01** the add-on ships `translations/en.yaml` and `translations/nl.yaml`, so Home Assistant's *Configuration* tab renders human labels and a description @@ -179,10 +209,10 @@ The label and description each setting shows on the Configuration tab, in tab or | Tariff | Supplier markup (EUR/kWh) | `price_markup_eur_kwh` | Your supplier's margin. It is added only when the price source does not already include it. | | Tariff | Distribution, levies and VAT (EUR/kWh) | `price_taxes_eur_kwh` | Grid costs, levies and VAT per kWh, preset for Flanders. Check it against your own grid operator's rates. | | Tariff | Injection price (EUR/kWh) | `export_price_eur_kwh` | What you are paid per kWh fed into the grid, all in. It may be negative. | -| Tariff | Fixed or day/night tariff (JSON) | `static_profile` | Your fixed or day/night contract as one line of JSON, prices all in. Fill it in even on a dynamic contract, as the fallback when the price feed fails. | -| Tariff | Day/night levies and VAT (JSON) | `price_taxes_profile` | Leave it empty unless your grid operator charges a different day and night rate, as in Wallonia and Brussels. Set this or the flat figure above, not both. | -| Tariff | Your own tariff formula (JSON) | `price_formula` | For custom_formula only. Type the numbers from your supplier's tariff card as one line of JSON, and the add-on checks them against the card. | -| Tariff | Your own injection formula (JSON) | `price_export_formula` | Optional. The injection formula from your tariff card, in the same shape as your own tariff formula. Leave it empty to use the flat injection price. | +| Tariff | Fixed or day/night tariff | `static_profile` | Your fixed or day/night contract on one line, prices all in, as the documentation shows. Fill it in even on a dynamic contract, as the fallback. | +| Tariff | Day/night levies and VAT | `price_taxes_profile` | Leave it empty unless your grid operator charges a different day and night rate, as in Wallonia and Brussels. Set this or the flat figure above, not both. | +| Tariff | Your own tariff formula | `price_formula` | For custom_formula only. Type the numbers from your supplier's tariff card on one line, as the documentation shows. The add-on checks them against the card. | +| Tariff | Your own injection formula | `price_export_formula` | Optional. The injection formula from your tariff card, in the same shape as your own tariff formula. Leave it empty to use the flat injection price. | | Tariff | Price CSV file | `price_csv_path` | For manual_csv only. Where in /share the add-on reads your price file. | | Tariff | Price feed URL override | `price_feed_url` | Leave it empty to use the source's own feed. An override is sent exactly as typed and often returns only one day. | | Tariff | Price look-ahead (hours) | `price_horizon_h` | How many hours of prices to ask the source for. | @@ -218,9 +248,9 @@ The label and description each setting shows on the Configuration tab, in tab or | Advanced | Ignore errors below (W) | `deadband_w` | Errors smaller than this are ignored. Keep it small, since any resting point inside it holds. | | Advanced | Meter resting point (W) | `target_grid_w` | What the meter should show when nothing happens. A slight export avoids paying for tiny imports all day. | | Advanced | Command rounding (W) | `step_w` | The command is rounded to a multiple of this, so noise does not change it every cycle. | -| Advanced | Inverter at limit gap (W) | `saturation_w` | When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this. | +| Advanced | At-limit shortfall (W) | `saturation_w` | When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this. | | Advanced | Cycles at limit before freezing | `saturation_cycles` | How many cycles in a row at the limit before control stops building up error. Do not set it to 1. | -| Advanced | Error build-up limit (W) | `integrator_max_w` | Caps the error that control saves up from past cycles. 0 means “Inverter rating”. Do not raise it above the rating. | +| Advanced | Catch-up limit (W) | `integrator_max_w` | Limits how hard control keeps pushing while the battery falls behind. 0 means “Inverter rating”. Do not raise it above the rating. | | Advanced | Command refresh interval (s) | `heartbeat_s` | How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit. | | Advanced | Missing inputs time limit (s) | `stale_input_s` | How long inputs may be missing before every inverter is set to 0 W. With a P1 meter it starts after “Reading too old after”. | | Advanced | Longest time between cycles (s) | `cycle_floor_s` | A deadline between control cycles that a healthy meter never reaches. Raise it only for a meter slower than about 10 s. | @@ -246,7 +276,7 @@ When the add-on refuses to start, each reason names the setting by its label and - **Peak reserve** (`peak_soc_floor`): derived, not picked (SAFETY-24). The reference battery holds 13.8 kWh usable and the worst modelled peak day asks for 878 Wh, or 6.4 %. 20 % sits ten points above the cut-out level and leaves about 1.6 worst days of room. It bounds peak limiting only: ordinary use goes on down to the cut-out level. It must stay above “Battery cut-out level”. - **Dynamic price source** (`price_provider`): selecting a provider is what starts the fetch, every half hour, whether or not trading is on. It may not be combined with the two older price entities. engie_dynamic, totalenergies_dynamic and eneco_eddy are withdrawn and refuse to start: their endpoints never existed. They stay in the list only so such a site gets that explanation. - **Supplier markup** (`price_markup_eur_kwh`): under manual_csv, whose prices are all in, it is ignored and logged as ignored. -- **Distribution, levies and VAT** (`price_taxes_eur_kwh`): 0.11736 EUR/kWh, derived in TARIFF-18 from the Eneco residential card for Flanders of September 2026 with 6 % VAT: Fluvius distribution for Antwerpen 5,35 plus excise 4,876 plus green power and CHP levy 1,51 c/kWh. Check it against your own DSO: across the eight Fluvius areas distribution runs from 5,28 to 6,70 c/kWh, so the Flemish total runs from about 0.117 to 0.131. Changing it moves no trading decision, because the same amount lands on every hour. It does move every price shown, and the rule that refuses to draw the battery down into an hour priced below zero. See [What `price_taxes_eur_kwh` is made of](#what-price_taxes_eur_kwh-is-made-of-and-why-yours-is-different-tariff-18). +- **Distribution, levies and VAT** (`price_taxes_eur_kwh`): 0.11736 EUR/kWh, derived in TARIFF-18 from the Eneco residential card for Flanders of September 2026 with 6 % VAT: Fluvius distribution for Antwerpen 5,35 plus excise 4,876 plus green power and CHP levy 1,51 c/kWh. Check it against your own DSO: across the eight Fluvius areas distribution runs from 5,28 to 6,70 c/kWh, so the Flemish total runs from about 0.117 to 0.131. Changing it moves no trading decision, because the same amount lands on every hour. It does move every price shown, and the rule that refuses to draw the battery down into an hour priced below zero. See [What `price_taxes_eur_kwh` is made of](#what-price_taxes_eur_kwh-is-made-of-and-why-yours-is-different). - **Day/night levies and VAT** (`price_taxes_profile`): for Wallonia and Brussels, where distribution has a day and a night rate (ORES 13,27 against 7,39 c/kWh, AIESH 15,17 against 8,21, Sibelga 9,39 against 7,10). The figures are levies alone, added to the market price. The add-on refuses to start if it and the flat figure disagree. See [Levies and VAT by time of day](#levies-and-vat-by-time-of-day-price_taxes_profile). - **Injection price** (`export_price_eur_kwh`): one number because no supplier here publishes a dynamic injection curve. In Belgium it is often near zero, and at a sunny midday it can be negative. - **Fixed or day/night tariff** (`static_profile`): the periods must cover every day type exactly once with no gap and no overlap, and a gap is refused rather than filled. A window 22:00-07:00 on mon-fri does not cover Saturday morning, so a weekend row is required. See [Static day/night and fully-fixed tariffs](#static-daynight-and-fully-fixed-tariffs-static_profile). @@ -259,19 +289,19 @@ When the add-on refuses to start, each reason names the setting by its label and - **Draw-down and recharge rate** (`maintenance_discharge_w`, `maintenance_charge_w`): the draw-down rate above the rating is cut back, not refused. A recharge rate above the rating would ask for more than the limit allows and resolve to 0 W, so maintenance would never charge. That is why the add-on refuses it. - **Draw down to** (`maintenance_soc_floor`): the monthly cycle goes this deep on purpose, while “Peak reserve” is a depth peak limiting never reaches. 11 % against 20 % is why they are two settings. - **Wrong-direction threshold and time** (`sign_disagree_w`, `sign_disagree_s`): measured, not chosen (SAFETY-02). On the captured healthy day (2026-08-23) signs agree on 93.4 % of gated samples, on the fault day (2026-08-20) 0.0-10.5 %, with opposed runs up to 1752 s. The longest legitimate opposed run is 30 s, and the fault day still trips 13 times at 300 s, so 180 s sits in a wide gap. The threshold must stay below “Inverter rating”. -- **Per-inverter wrong-direction threshold and time** (`unit_sign_disagree_w`, `unit_sign_disagree_s`): two or more inverters only. Derived from 1890 closed-loop test runs (SAFETY-30) with nothing faulty. 250 W is half the at-limit gap. 85 s is 8.5 times the worst legitimate opposition (10.0 s) and 2.8 times the control board's 30 s link limit. +- **Per-inverter wrong-direction threshold and time** (`unit_sign_disagree_w`, `unit_sign_disagree_s`): two or more inverters only. Derived from 1890 closed-loop test runs (SAFETY-30) with nothing faulty. 250 W is half the at-limit shortfall. 85 s is 8.5 times the worst legitimate opposition (10.0 s) and 2.8 times the control board's 30 s link limit. - **Site wrong-direction threshold** (`site_sign_disagree_w`): the single-inverter 300 W carried across deliberately (SAFETY-30), because near zero the sign is noise whatever is behind the one meter. - **Site wrong-direction time** (`site_sign_disagree_s`): derived from the same 1890 runs (SAFETY-30). The worst legitimate opposition at 300 W is 110 s with one inverter and 215 s with two, so 180 s would false-trip. 325 s is 1.51 times that and inside the 900 s billing period. - **Stuck meter alarm after** (`meter_freeze_s`): measured, not chosen (SAFETY-18). Over 2399 s of this house at its operating point, the longest run without a new reading is 15.4 s, and 300 s is 19.5 times that. It raises an alarm only and does not set 0 W. - **Opposing inverters threshold** (`circulation_w`): measured on 924 closed-loop test runs (SAFETY-31). The worst legitimate opposition drops from 505 s at 100 W to 5 s at 400 W, the lowest value accepted. 700 W is 1.75 times that knee, with margin because the second inverter is still a copy of the first. - **Opposing inverters time** (`circulation_hold_s`): derived (SAFETY-31). 75 s is fifteen control cycles, 15 times the worst legitimate episode, and 2.5 times the control board's 30 s link limit. - **Not delivering alarm after** (`delivery_hold_s`): two or more inverters only. It reports only (SAFETY-42): nothing is commanded differently. Derived from 2640 closed-loop test runs with nothing faulty. The worst legitimate episode is 35.0 s and 185 s is 5.29 times that. The schema allows 30 s, below that, so expect false reports there. A battery at or below its own cut-out level is never reported. Re-derive with admin/goodwe `sim/delivery_window.py --campaign --blag`. -- **Shadow mode** (`shadow_mode`): the whole decision path runs and nothing reaches the inverter. The status page and action log show what would have been sent. A safety stop that is already up stays up. See [Shadow mode](#shadow-mode-shadow_mode-safety-10). +- **Shadow mode** (`shadow_mode`): the whole decision path runs and nothing reaches the inverter. The status page and action log show what would have been sent. A safety stop that is already up stays up. See [Shadow mode](#shadow-mode-shadow_mode). - **Control gain** (`gain`): measured on real hardware and already at the limit. - **Largest change per cycle** (`slew_w`): 0 means follow the rating: about a ninth of it, derived (SAFETY-39) from a measured ~18 s step response against a 2 s meter tick. A fixed value faster than the rating allows is refused. At 1000 W against a 5000 W rating control swung the meter from 3.4 kW export to 2.8 kW import on 2026-09-05. - **Ignore errors below, Meter resting point** (`deadband_w`, `target_grid_w`): the meter's import counter bills every positive watt, so a resting point at 0 W leaks about half the deadband as billed import, roughly 0.2-0.35 kWh a day at 15 W. -10 W moves that leak to export. -- **Inverter at limit gap** (`saturation_w`): the per-inverter wrong-direction threshold is derived as half of it, so moving this moves that argument too. -- **Error build-up limit** (`integrator_max_w`): measured on the closed-loop simulator with a 4000 W load dropped to zero: at a limit equal to the rating the command is 1000 W two cycles later, at 1.5 times the rating 1800 W. Lowering it is the useful direction. +- **At-limit shortfall** (`saturation_w`): the per-inverter wrong-direction threshold is derived as half of it, so moving this moves that argument too. +- **Catch-up limit** (`integrator_max_w`): measured on the closed-loop simulator with a 4000 W load dropped to zero: at a limit equal to the rating the command is 1000 W two cycles later, at 1.5 times the rating 1800 W. Lowering it is the useful direction. - **Command refresh interval** (`heartbeat_s`): the control board refuses a link that has been quiet for 30 s. - **Longest time between cycles** (`cycle_floor_s`): keep it under “Reading too old after”, since past that there is no reading left to act on. @@ -286,9 +316,9 @@ When the add-on refuses to start, each reason names the setting by its label and | `batt_invert` | | Flip if needed | | `capacity_kwh` | | This pack's usable capacity. Read only to divide the site target between packs by **energy** headroom — see below | | `setpoint_entity` | yes | The ESPHome `number.*_goodwe_setpoint_w` | -| `pv_entity` | | Optional. **One** solar inverter's power sensor, `+` = producing. Measurement only — it changes no control behaviour. See [PV production](#pv-production-pv_entity-tel-11) | -| `pv_entities` | | Optional. **Several** solar inverters, one row each — use this instead of `pv_entity` when your roof has more than one. Setting it **ignores** `pv_entity`. See [Several PV inverters](#several-pv-inverters-pv_entities-tel-12) | -| `pv_invert_entities` | | Optional. The PV entities above that read **negative** while producing; each one's sign is flipped. See [The sign](#the-sign-and-pv_invert_entities-tel-14) | +| `pv_entity` | | Optional. **One** solar inverter's power sensor, `+` = producing. Measurement only — it changes no control behaviour. See [PV production](#pv-production-pv_entity) | +| `pv_entities` | | Optional. **Several** solar inverters, one row each — use this instead of `pv_entity` when your roof has more than one. Setting it **ignores** `pv_entity`. See [Several PV inverters](#several-pv-inverters-pv_entities) | +| `pv_invert_entities` | | Optional. The PV entities above that read **negative** while producing; each one's sign is flipped. See [The sign](#the-sign-and-pv_invert_entities) | Use the ESP32's readings rather than the inverter's cloud or dongle sensors: those serve cached values, and a stale reading here ends the maintenance charge @@ -344,7 +374,7 @@ inverter's own **AC** power. If it is DC the AC-side ceiling is nearer 4324 W. | `soc_entity` | | This pack's state of charge | | `batt_entity` | | This unit's battery power, `+` = discharging | | `batt_invert` | | Flip if needed | -| `capacity_kwh` | | This pack's usable capacity. State it on every entry or on none — see [OPT-09](#how-the-site-target-is-divided-between-the-packs-opt-09) | +| `capacity_kwh` | | This pack's usable capacity. State it on every entry or on none — see [OPT-09](#how-the-site-target-is-divided-between-the-packs) | ⚠️ **Nothing is inherited.** An entry that leaves out `soc_entity` has **no SoC sensor** — it does *not* fall back to the flat one. That is deliberate: every @@ -387,7 +417,9 @@ in the log rather than silent, but it is an outage until someone puts the single-inverter entity back in that field. **Before downgrading, write down the `setpoint_entity` of the unit you want to keep running.** -#### How the site target is divided between the packs (OPT-09) +#### How the site target is divided between the packs + +*For installers: card OPT-09.* Two packs do not get half each **from 0.8.0 onwards**. ⚠️ **On 0.7.0 and every version before it the split is a fixed 50/50 regardless of what either pack can @@ -508,8 +540,9 @@ accumulator is doing: | `not-running` | control is stopped **and** shadow mode is off, so the loop did not run | ⚠️ **`Loop reason` is not the `Why` row on the status page, and the two will -often disagree.** `Why` is the *arbiter's* sentence — `loop -> -1200 W` — which -names the strategy that won and the watts it won with. It has never carried the +often disagree.** `Why` is the *arbiter's* answer in words — *Keeping the grid +near zero: -1 200 W* — which names the strategy that won and the watts it won +with. The log keeps the arbiter's own `loop -> -1200 W`. It has never carried the strategy's own reason, so a loop that is slew-limited or frozen says so **only** here. @@ -567,10 +600,12 @@ and `Inverter B` — are two names to the validator and one id once slugged. The add-on gives the second one a `_2` suffix so nothing collides, but the ids you get then depend on roster order. Give your inverters plainly different names. -### PV production (`pv_entity`, TEL-11) +### PV production (`pv_entity`) + +*For installers: card TEL-11.* > **More than one solar inverter?** Use `pv_entities` instead — see -> [Several PV inverters](#several-pv-inverters-pv_entities-tel-12) below. The +> [Several PV inverters](#several-pv-inverters-pv_entities) below. The > rest of this section applies to both. @@ -604,7 +639,9 @@ Only the third is a software defect, and **none of them can be told apart without a record of production.** This entity is that record. The attribution itself is OPT-10's, with a week of history behind it. -#### The sign, and `pv_invert_entities` (TEL-14) +#### The sign, and `pv_invert_entities` + +*For installers: card TEL-14.* **Positive must mean producing.** Some sensors — typically a kWh meter or an ESPHome power clamp in the PV circuit — read negative while producing and a few @@ -642,7 +679,9 @@ pictures, which is exactly the distinction the whole card exists to preserve. A failed read also **clears** the previous good one: the value never outlives its own sensor. -### Several PV inverters (`pv_entities`, TEL-12) +### Several PV inverters (`pv_entities`) + +*For installers: card TEL-12.* A multi-string or multi-orientation roof routinely carries **two or three PV inverters**, each publishing its own power sensor into Home Assistant. List them @@ -1025,7 +1064,9 @@ behind it would trip the firmware watchdog on a system that is working fine. | `delivery_hold_s` | 185 | **Two or more inverters only.** How long one inverter may stand at a discharge share it is not producing - short by more than `saturation_w`, with no reason this add-on can read - while at least one sibling is **not** in that state, before it is named. **It reports; it does not act.** Nothing is commanded differently and the site goes on running short by that unit's share | | `shadow_mode` | `auto` | **Run every decision and command nothing.** `auto` = shadow mode while control is stopped, ordinary control once you press Start; `on` = shadow mode always; `off` = ordinary control. See *Shadow mode* below | -#### Shadow mode (`shadow_mode`, SAFETY-10) +#### Shadow mode (`shadow_mode`) + +*For installers: card SAFETY-10.* Shadow mode runs the **whole** decision path — the price strategy, the capacity guard, the maintenance shaping, the grid-following loop, the arbiter that ranks @@ -1192,11 +1233,13 @@ If the setpoint this add-on is emitting and the grid figure it is regulating on point **opposite ways** — charging the battery while the house imports, or discharging it while the house exports — with both over `sign_disagree_w`, for `sign_disagree_s` **continuously**, the add-on commands **0 W** and holds it -there. The banner reads *Command and meter point opposite ways*, the add-on +there. The banner reads *The meter saw power go the wrong way*, the add-on log says which two numbers disagreed and for how long, and the `Controller status` entity reports `failsafe`. -#### ⚠️ At two or more inverters this is TWO checks, not one (SAFETY-30) +#### ⚠️ At two or more inverters this is TWO checks, not one + +*For installers: card SAFETY-30.* The paragraph above describes what a **one-inverter** install does, and it is unchanged: there is one meter, one actuator, and comparing the command against @@ -1285,7 +1328,9 @@ agreement is 93.4 %; on the four captured fault clusters it is 0.3 %, 0.9 %, says so. -#### ⚠️ A unit that stops DELIVERING is a third fault again (SAFETY-42) +#### ⚠️ A unit that stops DELIVERING is a third fault again + +*For installers: card SAFETY-42.* The two checks above both key on **direction**. A unit sitting at **0 W against a non-zero share** has no direction: it is not pushing the wrong way, it is @@ -1393,7 +1438,9 @@ correct toward that wrong value instead of holding a stale command. It is bounde happened to a lying meter whose value merely jittered — bit-exact repetition was never a safety property. -#### When the freeze lets go, and when it deliberately never does (SAFETY-13) +#### When the freeze lets go, and when it deliberately never does + +*For installers: card SAFETY-13.* While the loop is frozen the command's **magnitude may fall but never rise**. That is the anti-windup rule, and at `prev_w == 0` it reads as a refusal to *start*: with @@ -1668,8 +1715,9 @@ exactly like the SoC drift the monthly maintenance cycle exists to correct. capacity-peak guard will not spend the pack for money below 20 %"*, and **nothing more**. See below for what that costs on a real evening. - **When it binds you are told**, once per episode, with notification - `goodwe_peak_soc_floor` and a status-page row reading `PEAK GUARD - FLOOR-LIMITED`: the quarter **will** go over the ceiling, so shedding load is + `goodwe_peak_soc_floor` and a red status-page row reading *Battery at its + peak reserve* (`PEAK GUARD FLOOR-LIMITED` in the log): the quarter **will** + go over the ceiling, so shedding load is the only thing left that changes the bill. Failing to shave is never silent — the euro figure is the whole point of the guard. - **An unreadable SoC is treated as floor-limited, not as a full battery.** A @@ -1685,7 +1733,9 @@ Why 20 %: the reference pack is 13.8 kWh usable, so 10 points of margin over the BMS cut-out is about 1.6× the guard's worst measured day. If your pack is smaller, or your quarters are worse, raise it. -#### ⚠️ What `peak_soc_floor` does **not** protect (SAFETY-25) +#### ⚠️ What `peak_soc_floor` does **not** protect + +*For installers: card SAFETY-25.* **On a sustained-load evening this add-on will take your battery to the BMS cut-out, whatever `peak_soc_floor` says.** That is measured, not argued. Replayed @@ -1878,7 +1928,9 @@ unchanged is 12 W, which is inside the 15 W deadband — so the command there is parked at 0 W and the two halves of the rule cannot both be true. At the schema floor of 60 s that figure is 60 W and only the margin is left. -### The circulating-power alarm (SAFETY-31) +### The circulating-power alarm + +*For installers: card SAFETY-31.* > **Only at two or more inverters.** At the shipped roster of one this quantity > is identically zero for every reading, no claim is ever filed, and the status @@ -2345,7 +2397,9 @@ distinct state from "prices, all of them zero": the plan is marked provisional and arbitrage is disabled, per the degradation matrix. It never falls back to a price of zero, which would read as free electricity. -#### The hours the feed has not published yet (FCST-04) +#### The hours the feed has not published yet + +*For installers: card FCST-04.* A day-ahead auction publishes tomorrow's prices once a day, at **14–16 h CET**. Before that, the feed is serving today and nothing else — so a `price_horizon_h` @@ -2388,29 +2442,28 @@ firm/provisional split whenever that split is what refused a trade. And since TARIFF-11 that row carries the provider plan itself: ``` -Tariff: no static profile (recomputed this tick); provider plan fetched 412 s - ago for a 48 h horizon: dynamic_dayahead from generic_dayahead, - 60 points over 33 h, 36 firm / 24 carried, 900+3600 s spacing, - provisional +Tariff: No fixed tariff set. Price plan from 412 s ago, for 48 hours ahead: + day-ahead prices from the price feed, 60 prices over 33 hours, + 36 published and 24 estimated, 900+3600 s apart, not final yet ``` ⚠️ **The two halves of that row are not computed at the same moment, and the -row says so.** Everything before the semicolon is the static-profile or Home +row says so.** Everything before "Price plan" is the static-profile or Home Assistant price-entity sentence, regenerated on the **30 s tick** from options alone — no network. Everything after it is the **background refresh's** resolution, which runs every 1800 s and is served for up to 5400 s before it is -retired; `fetched N s ago` is the age of the fetch that produced it and is the +retired; `Price plan from N s ago` is the age of the fetch that produced it and is the only figure in the row that tells you whether the feed is still answering. On a site with a provider configured and no usable plan the row says that too, rather than falling silently back to the static half. Read the plan half as five separate facts: which *product* the feed publishes -and which *plugin* read it, how many **points** it carries and how many **whole -hours** those points cover, how many of the points are **firm** (published for -their own interval) against **carried** (filled from yesterday under §8.3), the -**spacing** of the points in seconds — `900+3600` is the normal mixed steady -state, quarter-hourly firm points beside hourly carried ones — and `provisional` -whenever any point is carried. +and whether it came from the feed or from your fixed tariff, how many +**prices** it carries and how many **whole hours** they cover, how many are +**published** (firm, for their own interval) against **estimated** (carried +from yesterday under §8.3), how far **apart** they are in seconds — `900+3600` +is the normal mixed steady state, quarter-hourly firm points beside hourly +carried ones — and `not final yet` (provisional) whenever any is estimated. ⚠️ **Points and hours are two different numbers and this row used to print one of them under the other's name.** `words` was `f"… {len(points)} h"`, so a @@ -2585,7 +2638,9 @@ uses the result as a cheap-window hint for the maintenance charge. They are — configure two of them and the add-on refuses to start, naming the conflict, because the add-on reads exactly one and the loser is silent. Use one. -### The three buckets — which price components can move a decision (TARIFF-17) +### The three buckets — which price components can move a decision + +*For installers: card TARIFF-17.* **Read this before adding a price component of any kind.** The optimiser reads exactly two quantities off a price series, and nothing else: @@ -2641,7 +2696,9 @@ Three consequences worth having in mind: is the only ORDER component the add-on has. Anything added next belongs in one of the three, and saying which is part of adding it. -### What `price_taxes_eur_kwh` is made of, and why yours is different (TARIFF-18) +### What `price_taxes_eur_kwh` is made of, and why yours is different + +*For installers: card TARIFF-18.* **It ships at `0.11736` EUR/kWh.** That is the all-in non-energy part of a Flemish residential bill — everything on your invoice that is *not* the energy @@ -3095,8 +3152,8 @@ does not protect*. P1 meter, so every other guard, which reads that net figure, stays quiet. This has happened on this hardware once for 6 h 25 min. The alarm is latched, survives restarts, and is raised again every 5 min until control is started. -The watts and the time window are in the log; the *Circulating power check* -row shows the live watts. See *The circulating-power alarm*. +The watts and the time window are in the log. The *Check for inverters working +against each other* row shows the live watts. See *The circulating-power alarm*. **An inverter is not delivering.** SAFETY-42. The unit stood well short of its share of the site target for longer than `delivery_hold_s`. A unit at 0 W is @@ -3114,16 +3171,19 @@ and command figures are in the log. See *The frozen-meter alarm*. ## The Web UI -The ingress panel shows live values, why the controller is commanding what it -is, and a **Commissioning** checklist that names any problem in words. It also -carries the three buttons: start/stop control, force a maintenance cycle, and -abort one. +The add-on page shows live values, why the battery does what it does, and a +**Commissioning** checklist that names any problem in words. It also has three +buttons: start or stop control, force a maintenance cycle, and abort one. +Under the buttons is the last thing that happened, in a few words. -Since **UX-02** it has a second page, **Configuration** — see *There are TWO -places to configure this add-on*, above. ⚠️ **It adds nothing you can do to the -inverter.** The configuration page reads and writes the add-on's own settings -and can restart the add-on; the set of commands that reach the hardware is -exactly the three buttons it always had. +It has a second page, **Configuration**. See *There are TWO places to configure +this add-on*, above. **It adds nothing you can do to the inverter.** It reads +and writes the add-on's own settings and can restart the add-on. Only the three +buttons reach the inverter. + +*For installers: the Configuration page is UX-02. The line under the buttons is +`messages.hint()`, the plain form of the newest entry of the add-on's own +action log (`Controller.events`), which the page no longer shows.* ## Status page @@ -3144,14 +3204,16 @@ ends. That row says how to clear it. | Meter | The grid reading, its age, how many readings were refused, and how long its value has not changed. | | Stuck-meter check | Whether the add-on can warn you about a stuck meter. | | Meter reading may be stuck | See *Meter reading may be stuck* under Notifications. | -| *month*: peak … | This month's peak, and how close it is to your peak limit. | -| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. | +| Month peak | This month's highest 15-minute average, when it happened, and how close it is to your peak limit. Amber from 80 %. | +| 15-minute periods measured this month | How many 15-minute periods the add-on has measured and saved this month. | +| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. *Idle, heading for …* is where this 15-minute period is heading. *Waiting for meter readings* after a restart means the battery does not charge until the add-on can measure the period again. | | Battery level, Battery power, Grid power | The reading of that entity. *No usable reading* means the entity is missing, or its reading is too old. Check it in Developer Tools before replacing it. | -| Inverter control | Whether the inverter can be controlled, and the power range it accepts. | +| Inverter control | Whether the inverter can be controlled, and how much it can charge and give. | +| *name*: battery power reading stopped changing | The reading did not change while the add-on asked for a change. It may be stuck, or the battery may be refusing. The add-on sets the inverters to 0 W until it changes. | | *name*: … cannot be controlled, commands refused, “Setpoint entity” is not set | Whether each inverter still takes commands. | | Power request too high, Battery is not keeping up | See those titles under Notifications. Each shows how often it happened since the add-on started, and *fine now* once it has cleared. In shadow mode the row says what *would* have been sent. | -| Direction check, Site direction check | Whether each inverter's power goes the way it is told. *Opposite for 12 of 60 seconds* counts toward a stop. When it stops, the inverter, or every inverter, is set to 0 W until you start control. | -| Circulating power check, Inverters worked against each other | Only with several inverters. See *Inverters working against each other*. | +| Direction check, Site direction check | Whether each inverter's power goes the way the add-on asks. *Opposite for 12 of 60 seconds* counts toward a stop. When it stops, the inverter, or every inverter, is set to 0 W until you start control. | +| Check for inverters working against each other, Inverters worked against each other | Only with several inverters. See *Inverters working against each other*. | | Delivery check, *name* is not delivering | Only with several inverters. See *An inverter is not delivering*. | | Solar production | Your solar production. Sources are numbered in the order of “Solar production entities, per inverter”. A strongly negative reading by day means that entity reads the wrong way round: add it to “Reversed-sign solar entities”. | @@ -3176,7 +3238,17 @@ ERROR or WARNING line in the add-on log. ***name*: “Setpoint entity” is not set** (amber): a roster entry nobody can write, so the site refuses to run at part strength and holds 0 W. - **Direction check, Site direction check** are the sign checks (SAFETY-02/30). - **Circulating power check** is SAFETY-31, **Delivery check** SAFETY-42. + **Check for inverters working against each other** is SAFETY-31, **Delivery + check** SAFETY-42. +- **Month peak** and **15-minute periods measured** are TARIFF-01 and + TARIFF-13. The store's state at start is the INFO line `capacity-tariff peak + store: …`, and the peak guard's full reason is on its log line. +- ***name*: battery power reading stopped changing** is SAFETY-37/56/57. The + ERROR line carries the full `STALE_READING` reason and when it clears. +- The table at the top: **Why** is `messages.why()`, the arbiter's answer in + words (`Resolution.explain()` stays on the log). **Tariff**, **Price + history**, **Arbitrage** and **Shadow mode** keep every figure they had + (TARIFF-11), in words. - **Solar production** reads `pv_entity` or `pv_entities` (TEL-11/12). The *Reversed-sign solar entities* setting is `pv_invert_entities` (TEL-14). - **Shadow mode** (SAFETY-10): the banner turns red when a latch is up @@ -3190,7 +3262,9 @@ battery power, circulating power, state of charge, maintenance phase and controller status by MQTT discovery. This is observability only — the controller works fine without a broker, and MQTT problems can never affect control. -## Before you commission inverter B: `tools/rehearse_roster.py` (ARCH-02) +## Before you commission inverter B + +*For installers: card ARCH-02. The tool is `tools/rehearse_roster.py`.* The day the `inverters:` roster is declared, two things change that are **one-way on a live box and invisible until after the restart that applies @@ -3371,7 +3445,9 @@ maintenance bookkeeping — and if a cycle ran during it, correct `unit/<first>/last_completed` by hand before advancing again.** This is a stated decision, not a discovery made at the inverter. -## Before you deploy: `tools/predeploy_check.py` (PKG-09) +## Before you deploy + +*For installers: card PKG-09. The tool is `tools/predeploy_check.py`.* Two ways a deploy has gone wrong on this system, both of which the Supervisor reports as success: diff --git a/goodwe_controller/app/config_page.py b/goodwe_controller/app/config_page.py index f596886..953c3f8 100644 --- a/goodwe_controller/app/config_page.py +++ b/goodwe_controller/app/config_page.py @@ -413,10 +413,9 @@ function showProblems(payload){ save.disabled = total > 0; if(total){ note(banner, 'bad', 'This configuration would not start.', - 'The add-on refuses to run on it and would stop with exit 78. ' - + 'Saving is blocked until these are fixed; nothing has been written. ' - + 'Each message below is the add-on\\u2019s own words, from the same ' - + 'check that runs at startup.'); + 'The add-on would refuse to start on it. Saving is blocked until these ' + + 'are fixed, and nothing has been written. Each message below comes ' + + 'from the same check that runs at start.'); banner.insertBefore(banner.lastChild, banner.firstChild); msg(total + (total === 1 ? ' problem' : ' problems') + ' - saving is blocked', 'bad'); diff --git a/goodwe_controller/app/configui.py b/goodwe_controller/app/configui.py index df6fa1d..5437bd0 100644 --- a/goodwe_controller/app/configui.py +++ b/goodwe_controller/app/configui.py @@ -289,7 +289,10 @@ def problems_by_field(problems, keys): cross-field rule is about all of its fields, and hiding it from one of them would be this card's own defect in miniature. """ - patterns = [(key, re.compile(r"(?<![A-Za-z0-9_])" + re.escape(key) + # ⚠️ `.` BEFORE THE KEY DOES NOT COUNT (UX-08 2d): `inverters.max_w` + # names a setting of one inverter in the list, which is changed under + # `inverters`, and it must not also land beside the flat `max_w`. + patterns = [(key, re.compile(r"(?<![A-Za-z0-9_.])" + re.escape(key) + r"(?![A-Za-z0-9_])")) for key in keys] by_key, unanchored = {}, [] for problem in problems: diff --git a/goodwe_controller/app/custom_formula.py b/goodwe_controller/app/custom_formula.py index e7297b7..b233295 100644 --- a/goodwe_controller/app/custom_formula.py +++ b/goodwe_controller/app/custom_formula.py @@ -175,6 +175,8 @@ import math from dataclasses import dataclass from datetime import date, datetime, timezone +from . import messages + class FormulaInvalid(Exception): """`price_formula` cannot be used. Raised by the parser, refused by @@ -285,30 +287,28 @@ _LEGS = { '"offset":1.00,"units":"c_eur_per_kwh","vat_pct":6,' '"card":{"month":"2026-09","index_eur_per_mwh":133.9905,' '"expect_incl_vat":15.55}}'), - when=("Leave it empty unless “Dynamic price source” (price_provider) " - "is 'custom_formula'."), + when="Leave it empty unless “Dynamic price source” is 'custom_formula'.", zero_factor=" and trading never finds a price difference", flat="use “Fixed or day/night tariff” (static_profile) instead", neg_factor="Put the minus sign on the offset, not on the factor", card_required=True, card_note="The add-on needs it to check your two numbers", - card_causes=("that network charges are in “Distribution, levies and VAT” " - "(price_taxes_eur_kwh), not in the offset"), + card_causes=("the units, the VAT, and that network charges are not " + "in the offset"), ), EXPORT_FORMULA_OPTION: _Leg( option=EXPORT_FORMULA_OPTION, what="injection", example=('{"index":"epex_be","resolution":"hourly","factor":0.1,' '"offset":-1.188,"units":"c_eur_per_kwh","vat_pct":0}'), - when=("Fill it in only if your injection price follows the market. It " - "is used whatever the price source is."), + when="Fill it in only if your injection price follows the market.", zero_factor="", flat="use “Injection price” (export_price_eur_kwh) instead", neg_factor="Put the minus sign on the offset, not on the factor", card_required=False, card_note=("It is optional here. Without it the add-on only checks " "the size of your two numbers"), - card_causes="that vat_pct is 0 for injection", + card_causes="the units, and that the VAT is 0 for injection", ), } @@ -527,10 +527,8 @@ def parse_price_formula(value, *, option: str = "price_formula"): value = json.loads(text) except ValueError as e: raise FormulaInvalid( - f"{option} is not valid JSON ({e}). Write it on one line, for " - f"example\n" - f" {leg.example}\n" - f"{leg.when}") + f"{messages.not_valid(option, e)}. Copy the example from the " + f"documentation. {leg.when}") if not isinstance(value, dict): raise FormulaInvalid( f"{option} is {type(value).__name__}, not a JSON object with " @@ -685,9 +683,9 @@ def card_refusal(spec: FormulaSpec, delta: float) -> str: got = in_card_units(spec, spec.card_index_eur_per_mwh) leg = _LEGS[spec.option] return ( - f"{spec.option} does not match its own card: it gives {got:.4f} " - f"{spec.units} and the card says {spec.card_expect_incl_vat:g}. Check " - f"the units, the VAT and {leg.card_causes}.") + f"{spec.option} gives {got:.4f} " + f"{messages.UNIT_WORDS.get(spec.units, spec.units)}, the card says " + f"{spec.card_expect_incl_vat:g}. Check {leg.card_causes}.") # --------------------------------------------------------------------------- # diff --git a/goodwe_controller/app/inverter.py b/goodwe_controller/app/inverter.py index d62f236..3e5923b 100644 --- a/goodwe_controller/app/inverter.py +++ b/goodwe_controller/app/inverter.py @@ -408,7 +408,8 @@ class Inverter: stop the site (`inputs_ok`). Folding one into the other is how a measurement fault ends up handing a sibling extra power. """ - return self.batt_fresh.note(self.name) + return (messages.row_battery_stuck(self.name) if self.batt_fresh.stale + else "") def link_note(self, now: datetime) -> str: """One line for the status page. Empty when there is nothing to say. diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 7ff0cfe..7b6dfda 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -73,7 +73,7 @@ from . import packshare from . import pv as pv_read from . import shadow from .p1 import P1Ingest, build_source, is_enabled -from .price import Uncertainty, price_option, provider_configured +from .price import Uncertainty, brussels, price_option, provider_configured from .price_history import PriceHistory from .static_tariff import resolve_tariff, static_status from .tariff import PeakStore, PeakTracker @@ -267,14 +267,15 @@ def tariff_plan_row(plan, tick_words: str, *, age_s, horizon_h: float, past `max_age_s`, is the exact state the soak measured; rendering it as the bare static sentence is how it stayed invisible for 802 samples. """ + # UX-08: plain words, every figure kept. The tick's sentence is "now"; + # the plan carries its own age. if plan is None: if not provider: return tick_words - return (f"{tick_words} (recomputed this tick); NO provider plan - " - f"none has been resolved yet, or the last one is older than " - f"{max_age_s:.0f} s") - return (f"{tick_words} (recomputed this tick); provider plan fetched " - f"{age_s:.0f} s ago for a {horizon_h:.0f} h horizon: {plan.words}") + return (f"{tick_words}. No price plan: none yet, or the last one is " + f"over {max_age_s:.0f} s old") + return (f"{tick_words}. Price plan from {age_s:.0f} s ago, for " + f"{horizon_h:.0f} hours ahead: {plan.words}") def arbitrage_row(*, on: bool, decision, decided_at, cycle_at, now, @@ -312,21 +313,21 @@ def arbitrage_row(*, on: bool, decision, decided_at, cycle_at, now, render, from one that never reports it - and the bound TARIFF-10's comment claimed did not exist is ~15 s of it. """ + # UX-08: plain words; the setting is named by its label. if not on: - return "off - `arbitrage_enabled` is false, so nothing trades" + return (f"Off, “{messages.LABELS['arbitrage_enabled']}” is not " + f"switched on") if decided_at is None: - return (f"ON (`arbitrage_enabled`), but NO DECISION has been reached " - f"yet - no cycle has run as far as the arbitrage step. The " - f"loop's own reason: {why or 'none recorded'}") + return (f"On, but no decision yet, because control has not got that " + f"far. Control says: {why or 'no reason recorded'}") age = (now - decided_at).total_seconds() stale = cycle_at is not None and decided_at < cycle_at - head = (f"no decision this cycle ({why or 'no reason recorded'}); the " - f"last one was taken {age:.0f} s ago: " if stale else - f"decided {age:.0f} s ago: ") + head = (f"On, no decision this cycle ({why or 'no reason recorded'}), " + f"the last one {age:.0f} s ago: " if stale else + f"On, decided {age:.0f} s ago: ") if decision is None: - return (f"ON (`arbitrage_enabled`), no decision this cycle " - f"({why or 'no reason recorded'}), and none stands from an " - f"earlier one") + return (f"On, no decision this cycle ({why or 'no reason recorded'}) " + f"and none before") return head + decision.explain() @@ -354,6 +355,8 @@ class Controller: # their behalf, and a guard that raises AttributeError on the way to # saying so is a guard that stops the add-on booting. self.events: list[str] = [] + # UX-08: the last event in plain words, for the page. See log_event(). + self.hint = "" # --- DEV-02: THE ROSTER, BUILT BEFORE ANYTHING THAT READS A RATING --- # ⚠️ EVERY PER-DEVICE VALUE IN THIS CONTROLLER LIVES ON ONE OF THESE @@ -467,7 +470,8 @@ class Controller: "soc_entity / batt_entity / batt_invert / max_w keys are NOT " "read in this shape; each entry carries its own." % (len(self.inverters), - ", ".join(f"{i.name} {i.max_w:.0f} W" for i in self.inverters))) + ", ".join(f"{i.name} {i.max_w:.0f} W" for i in self.inverters)), + hint=messages.hint("roster", n=len(self.inverters))) self.tuning = Tuning( gain=float(opts.get("gain", 0.6)), @@ -541,7 +545,8 @@ class Controller: # recalibrated on schedule and one that silently is not, which is # §12's opening sentence, so it is said where an operator looks. self.log_event("maintenance history did NOT migrate cleanly: " - + self.maint_migration.explain()) + + self.maint_migration.explain(), + hint=messages.hint("maint_history")) # ⚠️ ONE CONFIG, N MACHINES. The `maintenance_*` options describe the # PROCEDURE - how hard to drain, how full to charge, how long to hold - # and the procedure is the same on every pack in the roster; what is per @@ -590,11 +595,9 @@ class Controller: self._grade_store_migration(store) for inv in self.inverters: if inv.sign_wd.tripped: - _LOG.error("SAFETY-02 was TRIPPED on %s before this restart and " - "stays tripped: %s. That inverter is held at 0 W. " - "Restarting the add-on does not clear this - start " - "control from the UI once you know why the command " - "opposed the meter.", inv.name, + _LOG.error("%s stays at 0 W after the restart because its " + "power went the wrong way: %s. Start control once " + "you know why.", inv.name, inv.sign_wd.reason or "(reason not recorded)") # --- SAFETY-42 + SAFETY-34 ------------------------------------------- @@ -616,11 +619,9 @@ class Controller: for inv in self.inverters: if inv.delivery_wd.tripped: _LOG.error( - "SAFETY-42 was TRIPPED on %s before this restart and stays " - "tripped: %s. NOTHING IS BEING COMMANDED DIFFERENTLY - this " - "guard reports and does not act - so if that inverter is " - "still not delivering, the site is still short by its " - "share. Restarting does not clear this.", + "%s is still marked as not delivering after the restart: " + "%s. Control keeps running, and only stopping and starting " + "control clears this.", inv.name, inv.delivery_wd.reason or "(reason not recorded)") # --- SAFETY-30: THE SITE HALF OF THE SIGN CHECK ---------------------- @@ -650,10 +651,9 @@ class Controller: reason=str(store.data.get("site_sign_reason", "") or "")) if self.site_sign_wd.tripped: _LOG.error( - "SAFETY-30 (site) was TRIPPED before this restart and stays " - "tripped: %s. Every inverter is held at 0 W. Restarting does " - "not clear this - start control from the UI once you know why " - "the site's total command opposed the meter.", + "Every inverter stays at 0 W after the restart because the " + "total power went the wrong way: %s. Start control once you " + "know why.", self.site_sign_wd.reason or "(reason not recorded)") # And the per-unit detectors are told which question they are asking, # here as well as in `cycle()`. `checks()` and the status page read @@ -704,10 +704,9 @@ class Controller: self._announced_mono = {} if self.circ_wd.tripped: _LOG.error( - "SAFETY-31 was TRIPPED before this restart and stays tripped: " - "%s. Every inverter is held at 0 W. Restarting does not clear " - "this - start control from the UI once you know why two " - "inverters were pushing against each other.", + "Every inverter stays at 0 W after the restart because the " + "inverters worked against each other: %s. Start control once " + "you know why.", self.circ_wd.reason or "(reason not recorded)") # SAFETY-03. The output clamp's alarm - see clamp.py for why the clamp @@ -913,6 +912,7 @@ class Controller: # than re-derived a cycle later. Starts False: nothing is on the wire. self.following = False self.reason = "starting" + self.why_words = "Starting" # ALLOC-01. The allocation record from the last resolution, or None # before the first cycle. ⚠️ IT IS KEPT SO THAT SOMETHING CAN GATE ON # IT: SAFETY-28 puts the write path behind this record, and DEV-02 reads @@ -959,7 +959,7 @@ class Controller: # TARIFF-03. One line of prose for the status page saying WHICH tariff # window we are in and why it is or is not cheap - so "Cheap window: # no" is an evidenced answer rather than a bare no. - self.tariff_words = "no static profile" + self.tariff_words = "No fixed tariff set" # OPT-04. The tariff plan the BACKGROUND task last resolved, and when. # cycle() reads these two attributes and never awaits a fetch - see @@ -1005,10 +1005,15 @@ class Controller: self.loop_pass_mono = None # -- helpers ------------------------------------------------------------- - def log_event(self, msg: str) -> None: + def log_event(self, msg: str, hint: str | None = None) -> None: + """`msg` goes on the action log, the add-on's own technical record. + `hint` is `messages.hint()`'s plain words for the same event, and is + what the page shows under the buttons (UX-08).""" stamp = datetime.now(timezone.utc).strftime("%H:%M:%S") self.events.insert(0, f"{stamp} {msg}") del self.events[40:] + if hint is not None: + self.hint = f"{datetime.now().astimezone():%H:%M} {hint}" def _grade_store_migration(self, store) -> None: """DEV-02. Did SAFETY-02's latch actually survive the key rename? @@ -1066,9 +1071,9 @@ class Controller: """ rep = self.store_migration if rep.ran and not rep.ok: - _LOG.error("SAFETY-02: the per-inverter store migration did not " - "verify (%s). The latch is being re-derived from the " - "legacy keys.", rep.explain()) + _LOG.error("The saved safety stops did not copy over cleanly " + "(%s), so they are read again from the older saved " + "state.", rep.explain()) data = getattr(store, "data", {}) legacy_tripped = bool(data.get("sign_tripped", False)) if not legacy_tripped or not self.inverters: @@ -1194,10 +1199,8 @@ class Controller: return if stranded: _LOG.error( - "SAFETY-44: this store carries a LATCHED sign-disagreement " - "failsafe under %s, and that unit is NOT on today's roster " - "%s - so no machine reads it and the site came up DRIVING on " - "a state file that says it is latched. Re-arming below.", + "A saved safety stop belongs to %s, which is not in the " + "inverter list %s, so it is set again on the first inverter.", ", ".join(sorted(stranded)), sorted(on_roster)) first = self.inverters[0] # The one state this method exists for. @@ -1209,17 +1212,18 @@ class Controller: first.store_set("sign_reason", first.sign_wd.reason) first.store_set("sign_tripped", True) _LOG.error( - "SAFETY-02 LATCH GUARD: this store carries a LATCHED " - "sign-disagreement failsafe under the pre-DEV-02 flat key and NO " - "inverter came up latched. Either the per-inverter migration lost " - "it, or it was written by an older add-on while this install was " - "rolled back. Both are a disarmed safety guard on an install whose " - "state file says it is protected, so the latch has been re-armed " - "on %s from the legacy value: %s. %s is held at 0 W until control " - "is started from the UI.", - first.name, first.sign_wd.reason, first.name) + "%s is set to 0 W again, because an older saved safety stop was " + "found: %s. Start control once you know why.", + first.name, first.sign_wd.reason) + _LOG.debug( + "SAFETY-02 latch guard: the pre-DEV-02 flat key says the " + "sign-disagreement failsafe is latched and no inverter came up " + "latched. Either the per-inverter migration lost it, or an older " + "add-on wrote it during a rollback. Both would be a disarmed " + "guard, so the latch is re-armed on %s.", first.name) self.log_event("FAILSAFE re-armed from the pre-DEV-02 store keys - " - + first.sign_wd.reason) + + first.sign_wd.reason, + hint=messages.hint("stop_restored", unit=first.name)) # -- the roster, and the N=1 views of it --------------------------------- @property @@ -1805,7 +1809,7 @@ class Controller: now_p = await self.hass.number(now_e) avg_p = await self.hass.number(avg_e) self.cheap = (now_p is not None and avg_p is not None and now_p <= avg_p) - self.tariff_words = "Home Assistant price entities" + self.tariff_words = "Prices from Home Assistant entities" else: # TARIFF-03. §9.2 makes a static day/night tariff a first-class # product, and its required EMS handling is TIME-WINDOW SHIFTING. @@ -1851,7 +1855,8 @@ class Controller: if self.inputs_ok: if self.inputs_bad_since is not None: - self.log_event("inputs recovered") + self.log_event("inputs recovered", + hint=messages.hint("inputs_back")) self.inputs_bad_since = None elif self.inputs_bad_since is None: self.inputs_bad_since = datetime.now(timezone.utc) @@ -1886,7 +1891,8 @@ class Controller: # §11.1 rule 1 and is already what a missing reading does here. inv.batt = inv.batt_fresh.reading() if inv.batt_fresh.stale and not was_stale: - self.log_event(f"STALE {inv.name}: " + inv.batt_fresh.reason) + self.log_event(f"STALE {inv.name}: " + inv.batt_fresh.reason, + hint=messages.hint("battery_stuck", unit=inv.name)) # ⚠️ SAFETY-57 REWROTE THE LAST SENTENCE OF THIS LINE AND NOTHING # ELSE IN IT. The escape clause used to read "It clears itself the # moment the register reports a different value", full stop - and @@ -1913,26 +1919,31 @@ class Controller: # this line already interpolates, is where the pair is spelled out. # Saying it in both halves of one sentence is how an operator # learns to skim it. - _LOG.error("SAFETY-37: %s battery-power reading did not move under " - "a command that did, WHICH IS NOT BY ITSELF A VERDICT " - "ON THE REGISTER - %s. Treating it as MISSING, which " - "commands 0 W. It clears itself the moment the register " - "reports a different value, and failing that %.0f s " - "after the standing command falls below %.0f W " - "(SAFETY-57: a verdict whose own consequence is a 0 W " - "command cannot be tested again from inside it).", - inv.name, inv.batt_fresh.reason, - inv.batt_fresh.bound.release_s, - inv.batt_fresh.bound.move_w) + # UX-08 2d: plain, with SAFETY-57's escape clause kept as an + # ordered pair (time, then power), and the reason still in `%s`. + _LOG.error("%s: battery power reading stopped changing. Inverters " + "go to 0 W until it changes, or %.0f s after the " + "command drops below %.0f W: %s", + inv.name, inv.batt_fresh.bound.release_s, + inv.batt_fresh.bound.move_w, inv.batt_fresh.reason) elif inv.batt_fresh.releases > was_releases: # ⚠️ SAFETY-57. REPORTED, NEVER SILENT. A latch that lets go on a # timer and says nothing is a latch no operator can audit - and this # one is withdrawing a SITE STOP. `release_note()` is written to say # that nothing has been learned about the register, because nothing # has. - self.log_event(f"STALE WITHDRAWN {inv.name}") - _LOG.warning("SAFETY-57: %s", - inv.batt_fresh.release_note(inv.name)) + self.log_event(f"STALE WITHDRAWN {inv.name}", + hint=messages.hint("battery_back", unit=inv.name)) + # Not "recovered": nothing is known about the reading yet, so the + # line gives the value it still holds and the window it is + # rechecked over (SAFETY-57). + _LOG.warning("%s: the command stayed below %.0f W for %.0f s, so " + "battery power reading %+.0f W is used again and " + "rechecked over %.0f s.", inv.name, + inv.batt_fresh.bound.move_w, + inv.batt_fresh.bound.release_s, inv.batt_fresh.held, + inv.batt_fresh.bound.unchanged_s) + _LOG.debug("SAFETY-57: %s", inv.batt_fresh.release_note(inv.name)) @property def shadow(self) -> bool: @@ -2066,14 +2077,15 @@ class Controller: self.log_event( f"refusing to broadcast {float(value):+.0f} W to " f"{len(targets)} inverters - that is the ARCH-01 fault; " - f"commanding 0 W") - _LOG.error("write_setpoint() was asked to put %+.0f W on every " - "one of %d inverters. A site target handed to each " - "unit is supplied by EACH of them: the gain at the " - "meter becomes N times the per-unit gain. Only 0 W " - "may be written site-wide; shares come from the " - "allocator. Commanding 0 W.", float(value), - len(targets)) + f"commanding 0 W", hint=messages.hint("all_blocked")) + _LOG.error("Refused to send %+.0f W to all %d inverters at " + "once, so every inverter is set to 0 W. This is a " + "software fault.", float(value), len(targets)) + _LOG.debug("ARCH-01: a site target handed to each unit is " + "supplied by each of them, so the gain at the meter " + "becomes N times the per-unit gain. Only 0 W may be " + "written site-wide, and shares come from the " + "allocator.") value = 0.0 else: targets = [unit] @@ -2101,7 +2113,8 @@ class Controller: # must not be counted as a clamp engagement, or a transport bug lands in # the winding-loop counter. if not is_commandable(value): - self.log_event(f"non-finite setpoint {value!r} - commanding 0 W") + self.log_event(f"non-finite setpoint {value!r} - commanding 0 W", + hint=messages.hint("bad_value")) _LOG.error("refusing to write a non-finite setpoint %r - commanding " "0 W and continuing to command. This is a bug upstream, " "not a limit.", value) @@ -2139,11 +2152,11 @@ class Controller: refusal = self.write_refusal(value, inv) if refusal is not None: self.log_event( - f"{inv.name}: WRITE REFUSED {value:+.0f} W - commanding 0 W") - _LOG.error("SAFETY-28 REFUSED a write of %+.0f W to %s: %s. " - "Commanding 0 W instead. Every setpoint must be one the " - "allocator placed on THIS tick, for THIS unit - see " - "Controller.write_refusal().", value, inv.name, refusal) + f"{inv.name}: WRITE REFUSED {value:+.0f} W - commanding 0 W", + hint=messages.hint("write_blocked", unit=inv.name)) + _LOG.error("Refused to send %+.0f W to %s (%s), so it is set to " + "0 W instead. This is a software fault.", + value, inv.name, refusal) value = 0.0 # ⚠️ THIS UNIT'S OWN THREE NUMBERS. `inv.max_w` is the supervised cap on @@ -2158,7 +2171,8 @@ class Controller: # (§15), and it is a different surface from the notification, which # IS deduplicated. The count is what says how hard the loop pushed; # the notification only says that it did. - self.log_event(f"{inv.name}: {result.describe()}") + self.log_event(f"{inv.name}: {result.describe()}", + hint=messages.hint("write_cut", unit=inv.name)) value = result.applied_w # --- SAFETY-10: AND THIS IS THE LAST THING BEFORE THE WIRE ----------- @@ -2209,12 +2223,12 @@ class Controller: timeout=WRITE_BUDGET_S) except (asyncio.TimeoutError, TimeoutError): ok = False - _LOG.error("the write of %+.0f W to %s (%s) did not complete in " - "%.0f s and was abandoned. It will be re-issued on the " - "next tick; no other inverter waited for it.", + _LOG.error("Sending %+.0f W to %s (%s) took over %.0f s and was " + "dropped, so it is sent again next cycle.", value, inv.name, entity, WRITE_BUDGET_S) self.log_event(f"{inv.name}: write timed out after " - f"{WRITE_BUDGET_S:.0f} s - re-issuing next tick") + f"{WRITE_BUDGET_S:.0f} s - re-issuing next tick", + hint=messages.hint("write_slow", unit=inv.name)) now = datetime.now(timezone.utc) inv.note_write(bool(ok), now) if ok: @@ -2339,7 +2353,8 @@ class Controller: for inv, machine, blocked in zip(self.inverters, self.maints, maint_plan): res = machine.tick(now, inv.soc, blocked_by=blocked) for msg in res.events: - self.log_event(msg) + self.log_event(msg, hint=messages.hint("maintenance", + phase=machine.phase)) maint_results.append(res) # ⚠️ CARRIED TO THE STATUS PAGE, NOT LEFT IN THE 40-LINE ACTION LOG. The # deferral is edge-logged (it lasts as long as the other pack's cycle), @@ -2432,11 +2447,10 @@ class Controller: # operator press that clears the namespaced ones. self.store.set("sign_reason", inv.sign_wd.reason) self.store.set("sign_tripped", True) - self.log_event(f"FAILSAFE {inv.name}: " + inv.sign_wd.reason) - _LOG.error("SAFETY-02 TRIPPED on %s - %s. Commanding 0 W on " - "that inverter and holding it until control is " - "started again. This survives an add-on restart; " - "restarting will not clear it.", + self.log_event(f"FAILSAFE {inv.name}: " + inv.sign_wd.reason, + hint=messages.hint("direction", unit=inv.name)) + _LOG.error("%s is set to 0 W because its power went the wrong " + "way: %s. Only starting control clears this.", inv.name, inv.sign_wd.reason) # ⚠️ THE SITE'S OWN STANDING COMMAND, WHICH IS THE SUM OF THE UNITS'. # SAFETY-07 and SAFETY-18 both grade a SITE quantity - the quarter-hour @@ -2481,14 +2495,11 @@ class Controller: # the same reason `circ_*` is. self.store.set("site_sign_reason", self.site_sign_wd.reason) self.store.set("site_sign_tripped", True) - self.log_event("FAILSAFE site: " + self.site_sign_wd.reason) - _LOG.error("SAFETY-30 TRIPPED at the SITE - %s. That is the " - "SUM of every standing command opposing the meter, " - "which no single inverter is answerable for. " - "Commanding 0 W on every inverter and holding it " - "until control is started again. This survives an " - "add-on restart; restarting will not clear it.", - self.site_sign_wd.reason) + self.log_event("FAILSAFE site: " + self.site_sign_wd.reason, + hint=messages.hint("site_direction")) + _LOG.error("Every inverter is set to 0 W because the total " + "power went the wrong way: %s. Only starting " + "control clears this.", self.site_sign_wd.reason) # --- SAFETY-31, AND IT RUNS BESIDE SAFETY-02 FOR THE SAME REASON ----- # Evaluated EVERY cycle, unconditionally, above the "inputs missing but @@ -2516,12 +2527,12 @@ class Controller: self.store.set("circ_reason", self.circ_wd.reason) self.store.set("circ_tripped", True) self._circ_announced = False - self.log_event("CIRCULATING POWER - " + self.circ_wd.reason) + self.log_event("CIRCULATING POWER - " + self.circ_wd.reason, + hint=messages.hint("circulating")) _LOG.error( - "SAFETY-31 TRIPPED - %s. Commanding 0 W on every inverter and " - "holding it until control is started again. This survives an " - "add-on restart AND a Home Assistant restart; restarting will " - "not clear it.", self.circ_wd.reason) + "Every inverter is set to 0 W because the inverters worked " + "against each other: %s. Only starting control clears this.", + self.circ_wd.reason) # --- SAFETY-42, AND IT RUNS HERE FOR SAFETY-02's AND SAFETY-31's REASON # Evaluated EVERY cycle, unconditionally, ABOVE the "inputs missing but @@ -2623,16 +2634,18 @@ class Controller: inv.store_set("delivery_tripped", True) self._delivery_announced.discard(inv.name) self.log_event(f"NOT DELIVERING {inv.name}: " - + inv.delivery_wd.reason) + + inv.delivery_wd.reason, + hint=messages.hint("not_delivering", + unit=inv.name)) _LOG.error( - "SAFETY-42 TRIPPED on %s - %s. NOTHING IS COMMANDED " - "DIFFERENTLY: this guard reports and does not act, because " - "commanding a unit that is not listening achieves nothing " - "(HW-01) and the only re-allocation this add-on can express " - "would throw away a partially-delivering unit's remaining " - "output. The site is short by that unit's share until " - "somebody looks at it. This survives an add-on AND a Home " - "Assistant restart.", inv.name, inv.delivery_wd.reason) + "%s is not delivering: %s. Nothing was changed and control " + "keeps running, and only stopping and starting control " + "clears this.", inv.name, inv.delivery_wd.reason) + _LOG.debug( + "SAFETY-42 reports and does not act: commanding a unit " + "that is not listening achieves nothing (HW-01), and the " + "only re-allocation the add-on can express would throw " + "away a partly delivering unit's output.") stale_after = float(self.o.get("stale_input_s", 15)) # ⚠️ `any`, NOT the sole unit's. The hold exists so a single missed poll @@ -2653,6 +2666,7 @@ class Controller: # A single missed poll is not a fault. Hold, keep the heartbeat # going, and give it a few seconds to come back. self.reason = f"inputs missing {bad_for:.0f}s" + self.why_words = messages.why_waiting(bad_for) return claims = [] @@ -2828,7 +2842,8 @@ class Controller: actuator=self.actuator_of("safety"))) elif not self.inputs_ok: if self.target != 0.0: - self.log_event("inputs missing - commanding 0 W") + self.log_event("inputs missing - commanding 0 W", + hint=messages.hint("inputs_missing")) claims.append(Claim.set("safety", P_SAFETY, 0.0, "inputs missing", actuator=self.actuator_of("safety"))) @@ -2949,7 +2964,12 @@ class Controller: if engaged_now != self._peak_engaged: self._peak_engaged = engaged_now if self.peak_guard is not None: - self.log_event(self.peak_guard.explain()) + _pg = self.peak_guard + self.log_event(_pg.explain(), hint=messages.hint( + "peak_off" if not _pg.engaged else + "peak_blind" if _pg.blind else + "peak_reserve" if _pg.floor_limited else + "peak_saturated" if _pg.saturated else "peak_on")) # --- OPT-04: price arbitrage (§10.1 priority 3) ---------------------- # ONE `set` claim at P_ARBITRAGE, and app/arbitrage.py carries the whole @@ -3061,7 +3081,10 @@ class Controller: # operator needs - "it started buying at 03:00", not 240 copies. if self.arb.action != self._arb_action: self._arb_action = self.arb.action - self.log_event(self.arb.explain()) + self.log_event(self.arb.explain(), hint=messages.hint( + "trade_charge" if self.arb.action == arbitrage.CHARGE else + "trade_give" if self.arb.action == arbitrage.DISCHARGE + else "trade_off")) # --- maintenance ----------------------------------------------------- # ⚠️ ONE PASS PER PACK, AND `arbitrate()` IS WHY THE LIST STAYS SHORT. @@ -3145,7 +3168,8 @@ class Controller: self._maint_shape_suspended = True self.log_event("peak at risk - maintenance charge shaping " "suspended so the peak claim is not " - "contradicted") + "contradicted", + hint=messages.hint("maint_paused")) else: self._maint_shape_suspended = False hi = 0.0 @@ -3229,7 +3253,8 @@ class Controller: ) if decision.frozen and self.sat_count < self.tuning.saturation_cycles: self.log_event(f"saturation freeze ({self.target:.0f} W vs " - f"{site_batt:.0f} W)") + f"{site_batt:.0f} W)", + hint=messages.hint("not_keeping_up")) self.sat_count = decision.sat_count self.i_w = decision.i_w self.loop_w = decision.target_w @@ -3358,7 +3383,8 @@ class Controller: # made by commanding one pack to charge while another discharges. # `allocator.plan()` carries the argument for each. if not resolution.allocated: - self.log_event("ARBITER: " + resolution.allocation.explain()) + self.log_event("ARBITER: " + resolution.allocation.explain(), + hint=messages.hint("split")) resolution = Resolution(0.0, "failsafe", None, False, resolution.considered, unit_bounds=resolution.unit_bounds, @@ -3394,7 +3420,7 @@ class Controller: f"ARBITER: the site target was allocated across " f"{len(resolution.shares)} inverters and this controller has no " f"setpoint entity for {undeliverable} - refusing to command a " - f"partial site") + f"partial site", hint=messages.hint("no_setpoint")) # ⚠️ `shares={}`, NOT THE SHARES IT REFUSED TO DELIVER, AND SINCE # DEV-02 THAT IS LOAD-BEARING RATHER THAN TIDY. The write loop below # commands each inverter `shares.get(name, 0.0)`, so carrying the @@ -3422,9 +3448,11 @@ class Controller: for _u, _why in (self.allocation.dropped if self.allocation else ()): self.log_event(f"ALLOCATOR: {_u} dropped from the split " f"({_why}) - the remaining inverter(s) now carry " - f"its share of the site target") + f"its share of the site target", + hint=messages.hint("unit_dropped", unit=_u)) if self._dropped_last and not _dropped: - self.log_event("ALLOCATOR: every inverter is back in the split") + self.log_event("ALLOCATOR: every inverter is back in the split", + hint=messages.hint("units_back")) self._dropped_last = _dropped # 3b. OPT-09 / IF-04: WATTS NOBODY COULD TAKE ARE NEVER SILENT EITHER. # `unmet_w` is the site target the envelopes could not absorb. It is @@ -3441,9 +3469,11 @@ class Controller: if _unmet: self.log_event( f"ALLOCATOR: {_unmet:+d} W of the site target could not be " - f"placed on any inverter - {self.allocation.explain()}") + f"placed on any inverter - {self.allocation.explain()}", + hint=messages.hint("unmet", w=_unmet)) else: - self.log_event("ALLOCATOR: the whole site target fits again") + self.log_event("ALLOCATOR: the whole site target fits again", + hint=messages.hint("unmet_gone")) self._unmet_last = _unmet if resolution.scope_errors: # A claim reached the arbiter on an actuator its source's scope does @@ -3452,9 +3482,11 @@ class Controller: # card removes, and a site constraint on one unit is a bound the # other unit never gets. Loud, every cycle, and it does not change # the resolution - the arbiter already routed by `actuator`. - _LOG.error("ARBITER SCOPE: %s", "; ".join(resolution.scope_errors)) + _LOG.error("A limit was filed on the wrong inverter, which is a " + "software fault: %s", " / ".join(resolution.scope_errors)) if resolution.contradiction: - self.log_event("ARBITER CONTRADICTION - commanding 0 W, see the log") + self.log_event("ARBITER CONTRADICTION - commanding 0 W, see the log", + hint=messages.hint("clash")) # --- SAFETY-02's arming gate ------------------------------------------ # Was the number about to go on the wire chosen by the grid-following # loop, or by a strategy that commands against the meter on purpose? @@ -3471,6 +3503,17 @@ class Controller: self.following = loop_is_following(resolution, self.loop_w) self.target = resolution.target_w self.reason = resolution.explain() + # UX-08: the same answer in plain words, for the page's "Why" line. + # `reason` stays the technical record the log and the checks read. + _why = resolution.winner + if _why in ("safety", "failsafe"): + _why = next((c.reason for c in claims + if c.source == _why and c.kind == "set"), + "no claim was made" if not any( + c.kind == "set" for c in claims) else "unsplit") + self.why_words = messages.why(_why, resolution.target_w, + resolution.bound_by, + contradiction=resolution.contradiction) # --- DEV-02: EACH INVERTER IS TOLD ITS OWN SHARE --------------------- # ⚠️ ITS OWN SHARE, NEVER THE SITE TARGET. `resolution.shares` is the # allocator's answer and `sum(shares) + unmet_w == round(target_w)` is @@ -3647,20 +3690,20 @@ class Controller: self.log_event( "SHADOW MODE ON - " + shadow.why( self.o, control_started=self.auto) - + f"; inverter held at {shadow.WIRE_W:.0f} W") + + f"; inverter held at {shadow.WIRE_W:.0f} W", + hint=messages.hint("shadow_on")) _LOG.warning( - "SAFETY-10 SHADOW MODE IS ON. The full decision path runs " - "and NOTHING is commanded: every inverter is held at " - "%+.0f W on the ordinary heartbeat. %s", shadow.WIRE_W, + "Shadow mode is on, so every inverter stays at %.0f W and " + "nothing the add-on decides is sent. %s.", shadow.WIRE_W, shadow.why(self.o, control_started=self.auto)) elif not first: self.log_event( "SHADOW MODE OFF - the battery is being controlled again, " - f"resuming from {shadow.WIRE_W:.0f} W") + f"resuming from {shadow.WIRE_W:.0f} W", + hint=messages.hint("shadow_off")) _LOG.warning( - "SAFETY-10 shadow mode is OFF. This controller is " - "commanding the battery again, starting from the " - "%+.0f W that was standing on the wire.", shadow.WIRE_W) + "Shadow mode is off, so the add-on controls the battery " + "again, starting from %.0f W.", shadow.WIRE_W) if not engaged: self.shadow_would_w = None self.shadow_sized_from_meter = False @@ -3693,7 +3736,9 @@ class Controller: self._shadow_winner = edge self.log_event(shadow.log_line( would_w=resolution.target_w, reason=resolution.explain(), - sized_from_meter=self.shadow_sized_from_meter)) + sized_from_meter=self.shadow_sized_from_meter), + hint=messages.hint("shadow_decision", + sw=resolution.target_w)) self.target = shadow.WIRE_W for inv in self.inverters: inv.target = shadow.WIRE_W @@ -3771,25 +3816,29 @@ class Controller: stamp = self.events[0].split(" ", 1)[0] self.events[0] = f"{stamp} {row}" else: - self.log_event(row) + self.log_event(row, hint=messages.hint( + "power_too_high" if bug else "not_keeping_up")) if not fired: return if not self.clamp_wd.bug: # SAFETY-40: the integrator bound is anti-windup, not a bug - a # WARNING and a plainly titled notice, same cadence. Its OWN id, so # it can never replace a BUG SIGNAL notice still on screen. - _LOG.warning("SAFETY-03 - %s Engagements so far: %d.", - self.clamp_wd.reason, self.clamp_wd.engagements) + _LOG.warning("The battery gives less than asked: %s Held back %d " + "times so far.", self.clamp_wd.reason, + self.clamp_wd.engagements) await self.hass.call("persistent_notification", "create", messages.loop_bound().data()) return _LOG.error( - "SAFETY-03 - %s Silently clipping this is how a winding integrator " - "reached 14 768 W on this project before: the clamp makes every " - "dashboard read a legal number while the thing producing it goes on " - "climbing. The command IS clamped and the loop is STILL RUNNING - " - "this is an alarm, not a trip. Engagements so far: %d.", + "Power request too high, which is a software fault: %s Control is " + "still running. Cut back %d times so far.", self.clamp_wd.reason, self.clamp_wd.engagements) + _LOG.debug( + "SAFETY-03: silently clipping this is how a winding integrator " + "reached 14 768 W on this project before. The clamp makes every " + "dashboard read a legal number while the thing producing it goes " + "on climbing. This is an alarm, not a trip.") # A fixed notification_id, for the reason check_meter_frozen() gives - # and a DIFFERENT one from every other alarm this add-on raises, because # a clamp is not a frozen meter and neither is a saturation freeze. @@ -3829,13 +3878,12 @@ class Controller: was, self._peak_saturated = self._peak_saturated, saturated if not saturated or was: return - self.log_event("PEAK GUARD SATURATED - " + g.reason) + self.log_event("PEAK GUARD SATURATED - " + g.reason, + hint=messages.hint("peak_saturated")) _LOG.error( - "SAFETY-07 - %s. The guard is asking for everything the inverter " - "has and the quarter is still projected over the ceiling: this " - "quarter will set or raise the month's billed capacity peak. The " - "controller is STILL RUNNING and still shaving; there is nothing " - "further it can do. Shed load.", g.reason) + "The battery is asked for all it can give, but this 15-minute " + "period still goes over the peak limit: %s. Switch off large " + "loads.", g.reason) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A saturated peak guard # is not a frozen meter and is not an out-of-range setpoint. @@ -3889,12 +3937,10 @@ class Controller: # a second copy is the kind of stutter that makes a 40-line action log # read like boilerplate. The saturated path needs its prefix because its # reason carries the word in the middle of a sentence, not at the front. - self.log_event(g.reason) + self.log_event(g.reason, hint=messages.hint("peak_reserve")) _LOG.error( - "SAFETY-24 - %s. The controller is STILL RUNNING and charging is " - "still blocked, but it is not discharging to hold this quarter, so " - "the quarter will set or raise the month's billed capacity peak. " - "Shed load, or lower peak_soc_floor if this pack can afford it.", + "The peak guard may not draw the battery lower, so this 15-minute " + "period will go over the peak limit: %s. Switch off large loads.", g.reason) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A battery at its @@ -4051,15 +4097,17 @@ class Controller: dev_max=self.site_dev_bound("dev_max")) if not fired: return - self.log_event("METER FROZEN? " + self.freeze_wd.reason) + self.log_event("METER FROZEN? " + self.freeze_wd.reason, + hint=messages.hint("meter_frozen")) _LOG.error( - "SAFETY-18 - %s. The grid-following loop is regulating against a " - "number that has stopped moving, and nothing in this stack stops " - "it: the meter is still answering, so the age is fresh, the " - "firmware watchdog is fed and the arbiter only bounds the " - "magnitude. CHECK THE METER. Sustained for a quarter of an hour " - "this sets the month's billed capacity-tariff peak. This is an " - "ALARM ONLY - the loop is still running.", self.freeze_wd.reason) + "The meter shows the same value while the battery is asked for " + "full power: %s. Control still follows it, so check the meter.", + self.freeze_wd.reason) + _LOG.debug( + "SAFETY-18: nothing else stops this. The meter still answers, so " + "its age is fresh, the firmware watchdog is fed and the arbiter " + "only bounds the magnitude. Kept up for a quarter of an hour, it " + "sets the month's billed capacity peak.") # ⚠️ A fixed notification_id, so a second episode REPLACES the first # rather than stacking. An operator who has to dismiss eleven identical # notifications learns to dismiss the twelfth without reading it. @@ -4168,12 +4216,9 @@ class Controller: and standing is not None and standing.from_feed) if keep: _LOG.warning( - "tariff refresh degraded (%s); KEEPING the plan " - "resolved at %s, %.0f s ago. tariff_at is NOT moved, " - "so it retires %.0f s after that fetch; arbitrage, " - "where it is armed, stops with it. A kept plan is " - "never presented as a current one.", plan.words, - self.tariff_at, + "The price update was incomplete (%s), so the plan " + "from %s, %.0f s ago, is kept until it is %.0f s old.", + plan.words, self.tariff_at, (now - self.tariff_at).total_seconds(), TARIFF_MAX_AGE_S) else: @@ -4185,9 +4230,9 @@ class Controller: # here is something nobody expected, and the plan is kept for # the same reason and on the same terms. _LOG.warning( - "tariff refresh raised (%s); keeping the plan resolved at " - "%s. It retires on its own after %.0f s and arbitrage " - "stops with it.", err, self.tariff_at, TARIFF_MAX_AGE_S) + "The price update failed (%s), so the plan from %s is kept " + "until it is %.0f s old, and trading stops then.", + err, self.tariff_at, TARIFF_MAX_AGE_S) with contextlib.suppress(asyncio.TimeoutError): await asyncio.wait_for(self.stop_event.wait(), timeout=TARIFF_REFRESH_S) @@ -4239,7 +4284,8 @@ class Controller: if problems: refuse(problems) self.refused = problems - self.log_event("REFUSED: " + problems[0]) + self.log_event("REFUSED: " + problems[0], + hint=messages.hint("refused")) # Signal, then return WITHOUT entering the loop. amain() wakes # on this, runs the normal wind-down (which commands 0 W) and # re-raises ConfigRefused afterwards, so the exit code is 78 and @@ -4646,21 +4692,28 @@ class Controller: # a normal state on the 1st; "unreadable" is a broken instrument, and # a status page that spelled them the same way would let a 0 W read # look like a quiet month right up until SAFETY-07 shaved nothing. + # UX-08: in plain words. The store's state at start is on the INFO + # line `capacity-tariff peak store: ...` and `_pk.explain()` on the + # log; the coverage figure (TARIFF-13) is a row of its own. _pk = self.peak.peak(when) if _pk.is_unreadable: - out.append({"ok": False, "warn": True, - "text": "capacity-tariff peak: " + _pk.explain()}) + out.append({"ok": False, "warn": True, "id": "month_peak", + "text": messages.row_month_peak_unreadable()}) else: # §9.1's "warning entity at 80 %", as a status row rather than # a second entity - see the constructor on not doubling up. _frac = self.peak.warning_frac(when) or 0.0 _ok = _frac < 0.8 - out.append({"ok": _ok, "warn": not _ok, - "text": _pk.explain() - + f" - {_frac * 100:.0f} % of the " - f"{self.peak.cap_w:.0f} W soft limit" - + f", {self.peak.recorded} quarter(s) banked" - + f", on start: {self.peak.restore_state}"}) + out.append({"ok": _ok, "warn": not _ok, "id": "month_peak", + "text": (messages.row_month_peak_none() + if not _pk.is_observed else + messages.row_month_peak( + _pk.peak_w, + brussels(_pk.quarter_start), + _frac))}) + out.append({"ok": True, "warn": False, "id": "periods_measured", + "text": messages.row_periods_measured( + self.peak.recorded)}) # SAFETY-07. Three rows, not one, because "idle" and "cannot see" # are opposite states and a page that spelled them the same way @@ -4715,10 +4768,16 @@ class Controller: else ()))}) elif _pg.blind: out.append({"ok": False, "warn": True, "id": "peak_guard", - "text": _pg.explain()}) + "text": messages.row_peak_guard_blind( + peakguard.blind_kind(_pg.blind))}) + elif _pg.engaged: + out.append({"ok": False, "warn": True, "id": "peak_guard", + "text": messages.row_peak_guard_on( + _pg.floor_w or 0.0, _pg.ceiling_w, + shadow=self.shadow)}) else: - out.append({"ok": not _pg.engaged, "warn": _pg.engaged, - "id": "peak_guard", "text": _pg.explain()}) + out.append({"ok": True, "warn": False, "id": "peak_guard", + "text": _pg.explain()}) else: # ⚠️ OUTSIDE the `p1_enabled` block, and that placement is the point. # SAFETY-07 is NOT COVERED on the legacy single-entity path - the @@ -4913,7 +4972,7 @@ class Controller: # watching something that cannot happen. Say what is true instead. out.append({"ok": True, "warn": False, "id": "circulating", "text": messages.row_one_inverter( - "Circulating power check")}) + messages.CHECK_CIRCULATING)}) else: held = self.circ_wd.held_s(datetime.now(timezone.utc)) out.append({"ok": True, "warn": False, "id": "circulating", @@ -5079,7 +5138,7 @@ class Controller: # the row's first sentence, so it stays a headline. level, banner = "bad", messages.banner_not_ready(bad[0]) elif not self.auto: - level, banner = "warn", "Stopped — inverter commanded to 0 W" + level, banner = "warn", messages.banner_stopped() elif any(i.delivery_wd.tripped for i in self.inverters): # ⚠️ SAFETY-42, AND IT IS A `warn` BANNER RATHER THAN A `bad` ONE, # WHICH IS THE WHOLE "reports, does not act" DECISION IN ONE LINE. @@ -5137,10 +5196,11 @@ class Controller: # question it answers is the one those two cannot: at "Grid 0 W, # Battery 0 W" the site is either becalmed or throwing away every # watt it makes, and only this row separates them. - *(() if not self.pv_roster else ((("PV", w(self.pv_w)),))), - ("State of charge", "—" if self.pack_floor_soc is None + *(() if not self.pv_roster else ((("Solar production", + w(self.pv_w)),))), + ("Battery level", "—" if self.pack_floor_soc is None else f"{self.pack_floor_soc:g} %"), - ("Commanded", w(self.target)), + ("Power request", w(self.target)), # SAFETY-10, and it sits BETWEEN the two rows it reconciles. # "Commanded 0 W" above and a "Why" below that explains a trade is # the exact pair an operator would otherwise have to guess at; this @@ -5155,8 +5215,8 @@ class Controller: # - the page runs on its own task and `self.peak_guard` has # moved on. See `Controller.__init__`. sized_from_meter=self.shadow_sized_from_meter, - reason=self.reason)), - ("Why", self.reason), + reason=self.why_words)), + ("Why", self.why_words), ("Maintenance phase", self.maint.phase if len(self.inverters) <= 1 else f"{self.maint.phase} ({self.maint_unit.name})"), # ⚠️ ONLY WHEN A PACK IS ACTUALLY WAITING, so a one-inverter status @@ -5195,11 +5255,11 @@ class Controller: ("Arbitrage", arbitrage_row( on=arbitrage.enabled(self.o), decision=self.arb, decided_at=self.arb_at, cycle_at=self.cycle_at, - now=datetime.now(timezone.utc), why=self.reason)), + now=datetime.now(timezone.utc), why=self.why_words)), ] return { "banner": banner, "level": level, "rows": rows, "checks": checks, - "hint": self.events[0] if self.events else "", + "hint": self.hint, } async def handle_action(self, what: str): @@ -5207,7 +5267,9 @@ class Controller: if what == "auto_toggle": self.auto = not self.auto self.store.set("auto", self.auto) - self.log_event("control started" if self.auto else "control stopped") + self.log_event("control started" if self.auto else "control stopped", + hint=messages.hint("control_started" if self.auto + else "control_stopped")) if self.auto: # ⚠️ THE ONLY WAY OUT OF A SIGN-DISAGREEMENT TRIP, on purpose. # It clears on a deliberate human start, not on the condition @@ -5230,7 +5292,9 @@ class Controller: inv.store_set("sign_tripped", False) inv.store_set("sign_reason", "") self.log_event(f"sign-disagreement failsafe cleared by " - f"operator on {inv.name}") + f"operator on {inv.name}", + hint=messages.hint("stop_cleared", + unit=inv.name)) # ⚠️ AND THE PRE-DEV-02 FLAT KEYS GO WITH THEM, UNCONDITIONALLY. # This is what makes `flat True + namespaced False` MEAN # something, and it is the reason `_grade_store_migration()` can @@ -5271,7 +5335,8 @@ class Controller: # moment a second inverter was configured again. if self.site_sign_wd.tripped: self.log_event("site sign-disagreement failsafe cleared " - "by operator") + "by operator", + hint=messages.hint("site_stop_cleared")) self.site_sign_wd.reset() self.store.set("site_sign_tripped", False) self.store.set("site_sign_reason", "") @@ -5289,7 +5354,8 @@ class Controller: self.circ_wd.reset() self.store.set("circ_tripped", False) self.store.set("circ_reason", "") - self.log_event("circulating-power trip cleared by operator") + self.log_event("circulating-power trip cleared by operator", + hint=messages.hint("site_stop_cleared")) self._circ_announced = False # SAFETY-42, cleared by the SAME press, and for a reason that is # NOT the one above. The other three latches are cleared here @@ -5307,7 +5373,10 @@ class Controller: for inv in self.inverters: if inv.delivery_wd.tripped: self.log_event(f"not-delivering report on {inv.name} " - f"cleared by operator") + f"cleared by operator", + hint=messages.hint( + "not_delivering_cleared", + unit=inv.name)) inv.delivery_wd.reset() inv.store_set("delivery_tripped", False) inv.store_set("delivery_reason", "") @@ -5333,14 +5402,18 @@ class Controller: # bare `maint_start` with no unit, and inventing a unit parameter # here would ship half a surface: the page would still have one # button and the API would have two meanings. - for msg in self._maint_button(now).force_start(now): - self.log_event(msg) + _m = self._maint_button(now) + for msg in _m.force_start(now): + self.log_event(msg, hint=messages.hint("maintenance", + phase=_m.phase)) return {"phase": self.maint.phase} if what == "maint_abort": # Aborts the pack that is actually cycling - `_maint_button()` again # - and then zeroes the SITE, which is what it always did. - for msg in self._maint_button(now).abort(now, "operator"): - self.log_event(msg) + _m = self._maint_button(now) + for msg in _m.abort(now, "operator"): + self.log_event(msg, hint=messages.hint("maintenance", + phase=_m.phase)) await self.command_site_zero() return {"phase": self.maint.phase} return None @@ -5362,8 +5435,9 @@ def control_task_done(task: asyncio.Task, *, controller, stop: asyncio.Event, if stop.is_set() or controller.stopping: return # the normal wind-down, or run_control()'s refusal path exc = None if task.cancelled() else task.exception() - _LOG.critical("CONTROL LOOP DIED (%s) - commanding 0 W and exiting with " - "status %d", "cancelled" if task.cancelled() else + _LOG.critical("Control stopped unexpectedly (%s), so every inverter is " + "set to 0 W and the add-on exits with code %d.", + "cancelled" if task.cancelled() else (repr(exc) if exc else "returned"), EXIT_CONTROL_DIED, exc_info=exc) died.append(exc) @@ -5381,21 +5455,33 @@ async def docs_link_facts(session, token: str) -> dict: Asked together with a 3 s budget: a link may never hold up control start. """ async def ask(url, field): + """`(value, why)`: the field, or None and a short reason (UX-09).""" try: async with session.get(url, timeout=DOCS_LINK_TIMEOUT_S, headers={ "Authorization": f"Bearer {token}"}) as r: body = await r.json(content_type=None) data = body.get("data", body) if isinstance(body, dict) else {} - return data.get(field) if isinstance(data, dict) else None + value = data.get(field) if isinstance(data, dict) else None + return value, (None if value else f"no {field} in its answer") except Exception as err: # noqa: BLE001 - a link, never a stop - _LOG.info("docs link: %s unreadable (%s)", url, err) - return None + # A timeout's own text is empty, so the type is always named. + text = str(err).strip() + return None, (f"{type(err).__name__}: {text}" if text + else type(err).__name__) - slug, ha = await asyncio.gather( + (slug, why_slug), (ha, why_ha) = await asyncio.gather( ask("http://supervisor/addons/self/info", "slug"), ask("http://supervisor/info", "homeassistant")) out = {"slug": slug, "ha_version": ha} - _LOG.info("docs link: slug %s, Home Assistant %s", slug, ha) + # ONE line, whatever happened: the link is a convenience, not a fault. + if slug and ha: + _LOG.info("Documentation link: add-on %s, Home Assistant %s", slug, ha) + else: + missed = [f"{what} ({why})" for what, why in + (("add-on name", why_slug), ("Home Assistant version", why_ha)) + if why] + _LOG.info("Documentation link: the Supervisor gave no %s, so the " + "link is guessed or left out.", " and no ".join(missed)) return out diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 8974068..aa69875 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -10,6 +10,7 @@ per title; the body ends with a link to it. import os import re from dataclasses import dataclass +from datetime import datetime # Severity (STYLE.md section 3). An ALARM may use up to three sentences so # that no action a person must take is lost; everything else gets one. @@ -335,13 +336,13 @@ def banner_circulating() -> str: def banner_site_direction() -> str: - return "Total command and meter point opposite ways. All inverters at 0 W." + return "Total power went the wrong way. All inverters at 0 W." def banner_direction(several: bool) -> str: if several: - return "An inverter's own power opposes its command. It is at 0 W." - return "Command and meter point opposite ways. Inverter set to 0 W." + return "An inverter's own power went the wrong way. Set to 0 W." + return "The meter saw power go the wrong way. Inverter at 0 W." def banner_not_delivering(units) -> str: @@ -350,6 +351,10 @@ def banner_not_delivering(units) -> str: return f"{names(units)} {verb} not delivering. Control keeps running." +def banner_stopped() -> str: + return "Stopped — the inverters are set to 0 W" + + def banner_shadow(latched: bool) -> str: """SAFETY-10: first in the cascade, never displaced by another banner. @@ -502,9 +507,15 @@ def row_commands_refused(name, held_s, limit_s) -> str: def row_control(lo_w, hi_w, unit=None) -> str: - def w(v): - return "?" if v is None else signed_watts(v) - return f"Inverter control{for_unit(unit)}: ready, from {w(lo_w)} to {w(hi_w)}" + """The inverter's own range: charging below 0 W, giving power above it.""" + head = f"Inverter control{for_unit(unit)}: ready" + if lo_w is None or hi_w is None or lo_w > 0 or hi_w < 0: + def w(v): + return "?" if v is None else signed_watts(v) + return f"{head}, from {w(lo_w)} to {w(hi_w)}" + if abs(float(lo_w)) == float(hi_w): + return f"{head}, up to {watts(hi_w)} each way" + return f"{head}, {watts(lo_w)} charging, {watts(hi_w)} giving" # Rows: the two loop alarms. The names are the notification titles, so the @@ -541,9 +552,9 @@ def row_write_refused(unit=None) -> str: # Rows: the direction checks (SAFETY-02/30). def row_direction_trip(unit=None) -> str: """Per inverter. `unit` only at several inverters, graded on its own power.""" - what = (f"{unit}: command and its own power point opposite ways, so it is" - if unit else "Command and meter point opposite ways, so the " - "inverter is") + what = (f"{unit}'s own power went against what the add-on asked, so it is" + if unit else + "Grid power went against what the add-on asked, so the inverter is") return (f"{what} set to 0 W. Find out why, then start control. A restart " f"does not clear this.") @@ -557,9 +568,9 @@ def row_direction_check(held_s, hold_s, unit=None) -> str: def row_site_direction_trip() -> str: - return ("Total command and meter point opposite ways, so every inverter is " - "set to 0 W. The cause is the total, not one inverter. Only starting " - "control clears this.") + return ("Grid power went against the add-on's total request, so every " + "inverter is set to 0 W. The cause is the total, not one inverter. " + "Only starting control clears this.") def row_site_direction_check(held_s, hold_s) -> str: @@ -575,10 +586,15 @@ def row_circulating_trip() -> str: "0 W. The meter cannot see this. Only starting control clears this.") +CHECK_CIRCULATING = "Check for inverters working against each other" + + def row_circulating_check(now_w, held_s, hold_s) -> str: - return ("Circulating power check: on" - + (f", now {watts(now_w)}" if now_w else "") - + (f", for {held_s:.0f} of {seconds(hold_s)}" if held_s else "")) + if held_s: + return (f"{CHECK_CIRCULATING}: {watts(now_w or 0)} for {held_s:.0f} of " + f"{seconds(hold_s)}") + return (f"{CHECK_CIRCULATING}: on" + + (f", now {watts(now_w)}" if now_w else "")) def row_one_inverter(check: str) -> str: @@ -676,6 +692,184 @@ def row_pv_stray(n) -> str: f"entity in use") +# Rows: this month's peak and the peak guard (UX-08 phase 2d). The detail +# (the projection's reason, the store's state at start) is in the add-on log. +def row_month_peak(peak_w, at, frac) -> str: + """`at` is the local start of the 15-minute period that set the peak.""" + return (f"Month peak: {watts(peak_w)} on {at.day} {at:%b} at {at:%H:%M}, " + f"{frac * 100:.0f} % of the peak limit") + + +def row_month_peak_none() -> str: + return "Month peak: none recorded yet this month" + + +def row_month_peak_unreadable() -> str: + """The store did not answer. This is not a zero peak (TARIFF-01).""" + return "Month peak: cannot be read, so only the peak limit is used" + + +def row_periods_measured(n) -> str: + """TARIFF-13's coverage figure. `n` is an int, or a text when unreadable.""" + shown = n if isinstance(n, int) else "cannot be read" + return f"15-minute periods measured this month: {shown}" + + +def row_peak_guard_idle(projected_w, limit_w, month_peak: bool) -> str: + """The projection first and the limit second (SAFETY-38's ordered pair).""" + limit = (f"this month's {watts(limit_w)} peak" if month_peak + else f"the {watts(limit_w)} peak limit") + return f"Peak guard: idle, heading for {watts(projected_w)}, under {limit}" + + +def row_peak_guard_quiet() -> str: + return "Peak guard: idle" + + +BLIND_WORDS = { + "no_block": "waiting for meter readings", + "gap": "meter readings have a gap", + "frozen": "meter reading is stuck", +} + + +def row_peak_guard_blind(why: str) -> str: + """`why` is a key of BLIND_WORDS. The battery may give power, not charge.""" + return (f"Peak guard: {BLIND_WORDS[why]}, so the battery does not charge " + f"meanwhile") + + +def row_peak_guard_on(floor_w, limit_w, *, shadow: bool = False) -> str: + if shadow: + return (f"Peak guard: would ask for {watts(floor_w)} to stay under " + f"{watts(limit_w)}") + return (f"Peak guard: asks the battery for {watts(floor_w)} to stay under " + f"{watts(limit_w)}") + + +def row_battery_stuck(unit) -> str: + """SAFETY-37/56. A fact, not a verdict: the reading may be stuck, or the + battery may be refusing, and the add-on cannot tell which.""" + return (f"{unit}: battery power reading stopped changing, so it is not used " + f"for now") + + +# The top of the page: why the battery does what it does (the "Why" line). +WHY_WINNER = { + "loop": "Keeping the grid near zero", + "peak": "Keeping under the peak limit", + "arbitrage": "Trading on the price", + "maintenance": "Battery maintenance", + "failsafe": "Safety stop, power went the wrong way", + "sign_site": "Safety stop, total power went the wrong way", + "circulation": "Safety stop, inverters worked against each other", + "stopped": "Control is stopped", + "inputs missing": "A reading is missing", + "no claim was made": "Nothing asked for power", +} +WHY_LIMIT = { + "peak(quarter peak)": "the peak limit", + "peak(blind)": "no charging while the meter is unclear", + "peak(SoC floor)": "the peak reserve", + "supervised": RATING, + "device": "the inverter's own limit", + "pack": "the battery level", + "reserve": "the battery reserve", + "maintenance": "battery maintenance", +} + + +def why(winner, target_w, bound_by=None, *, contradiction=False) -> str: + """`winner` is the arbiter's winning source, or its reason for the two + that share a source ("stopped", "inputs missing", "no claim was made"). + `bound_by` is `Resolution.bound_by`, e.g. "peak(quarter peak)".""" + if contradiction: + return "Two limits clash, so every inverter is set to 0 W" + out = f"{WHY_WINNER.get(winner, 'Other')}: {signed_watts(target_w)}" + if bound_by: + limit = WHY_LIMIT.get(bound_by) or WHY_LIMIT.get( + str(bound_by).split("(")[0], "another limit") + out += f", held back by {limit}" + return out + + +def why_waiting(missing_s) -> str: + """A reading went missing a moment ago: control holds and waits.""" + return f"A reading is missing for {seconds(missing_s)}, control waits" + + +# The last thing that happened, shown under the buttons. The add-on keeps its +# own technical record of each event (`Controller.events`); the page shows +# these words instead. Every `log_event()` call names one (test_messages.py). +HINTS = { + "control_started": "Control started", + "control_stopped": "Control stopped", + "settings_saved": "Settings saved, they apply after a restart", + "restart_requested": "Restart requested from the settings page", + "roster": "Inverter list read: {n} inverters", + "maint_history": "Maintenance history did not move over cleanly", + "stop_restored": "{unit}: an earlier safety stop is back, it stays at 0 W", + "battery_stuck": "{unit}: battery power reading stopped changing", + "battery_back": "{unit}: battery power reading is used again", + "bad_value": "The add-on made an invalid power value, inverters set to 0 W", + "write_blocked": "{unit}: a power request was blocked, it is set to 0 W", + "all_blocked": "A power request was blocked, inverters set to 0 W", + "write_cut": "{unit}: " + T_OUTPUT_CLAMP.lower(), + "write_slow": "{unit}: the inverter answered too slowly, trying again", + "direction": "{unit}: power went the wrong way, it is set to 0 W", + "site_direction": "Total power went the wrong way, inverters set to 0 W", + "circulating": T_CIRCULATING + ", all set to 0 W", + "not_delivering": T_NOT_DELIVERING, + "peak_on": "Peak guard started", + "peak_off": "Peak guard idle", + "peak_blind": "Peak guard cannot read the meter well", + "peak_saturated": T_PEAK_SATURATED, + "peak_reserve": T_PEAK_RESERVE, + "meter_frozen": T_METER_FROZEN, + "power_too_high": T_OUTPUT_CLAMP, + "not_keeping_up": T_LOOP_BOUND, + "trade_charge": "Trading: charging while the price is low", + "trade_give": "Trading: giving power while the price is high", + "trade_off": "Trading: waiting for a better price", + "split": "The power split between inverters changed", + "clash": "Two limits clash, inverters set to 0 W", + "no_setpoint": "An inverter has no “Setpoint entity”, inverters stay at 0 W", + "unit_dropped": "{unit} left out of control, the others take its share", + "units_back": "Every inverter is back in control", + "unmet": "The inverters cannot give {w} of the power asked", + "unmet_gone": "The inverters can give all the power asked again", + "shadow_on": "Shadow mode on, inverters stay at 0 W", + "shadow_off": "Shadow mode off, the add-on controls the battery", + "shadow_decision": "Shadow mode: would ask the battery for {sw}", + "refused": "Settings refused, the add-on log shows why", + "inputs_missing": "A reading is missing, inverters set to 0 W", + "inputs_back": "All readings are back", + "stop_cleared": "{unit}: safety stop cleared by starting control", + "site_stop_cleared": "Safety stop cleared by starting control", + "not_delivering_cleared": "{unit}: not-delivering alarm cleared", + "maintenance": "Battery maintenance: {phase}", + "maint_paused": "Maintenance charging paused to stay under the peak limit", +} + + +def hint(key: str, **kw) -> str: + """The plain words for one event. `w` is formatted as watts, `sw` as + watts with their sign (positive gives power, negative charges).""" + if "w" in kw: + kw["w"] = watts(kw["w"]) + if "sw" in kw: + kw["sw"] = signed_watts(kw["sw"]) + return HINTS[key].format(**kw) + + +def hint_samples() -> list: + """`(key, text)` for every hint, rendered, for the test.""" + kw = {"n": 2, "unit": "inverter-b", "w": 1200, "sw": -1200, + "phase": "drain"} + return [(k, hint(k, **{f: kw[f] for f in kw if "{" + f + "}" in v})) + for k, v in HINTS.items()] + + RED, AMBER, GREEN = "bad", "warn", "ok" @@ -769,6 +963,24 @@ def status_samples() -> list: ("row_pv_negative", AMBER, row_pv_negative(2, 3, -1500, False)), ("row_pv_negative", AMBER, row_pv_negative(1, 1, -1500, True)), ("row_pv_stray", AMBER, row_pv_stray(2)), + ("banner_stopped", None, banner_stopped()), + ("row_control", GREEN, row_control(-4000, 5000, "inverter-b")), + ("row_month_peak", GREEN, row_month_peak( + 4998, datetime(2026, 8, 12, 19, 15), 0.83)), + ("row_month_peak_none", GREEN, row_month_peak_none()), + ("row_month_peak_unreadable", AMBER, row_month_peak_unreadable()), + ("row_periods_measured", GREEN, row_periods_measured(120)), + ("row_periods_measured", GREEN, row_periods_measured("unreadable")), + ("row_peak_guard_idle", GREEN, row_peak_guard_idle(1300, 2500, True)), + ("row_peak_guard_idle", GREEN, row_peak_guard_idle(1300, 2500, False)), + ("row_peak_guard_quiet", GREEN, row_peak_guard_quiet()), + *(("row_peak_guard_blind", AMBER, row_peak_guard_blind(k)) + for k in BLIND_WORDS), + ("row_peak_guard_on", AMBER, row_peak_guard_on(1200, 2500)), + ("row_peak_guard_on", AMBER, row_peak_guard_on(1200, 2500, + shadow=True)), + ("row_battery_stuck", AMBER, row_battery_stuck("inverter-b")), + ("row_circulating_check", GREEN, row_circulating_check(0, 0, 60)), ] @@ -843,6 +1055,27 @@ LABELS = { } +def shown(value) -> str: + """A setting's value inside a refusal: `'abc'`, `5`, or `empty` for a value + that is missing or blank, never Python's `None` (UX-08 2d).""" + if value is None or (isinstance(value, str) and not value.strip()): + return "empty" + return repr(value) + + +def not_valid(option: str, err) -> str: + """A setting whose text does not parse, without the parser's own words: + `static_profile is not valid near character 6` (UX-08 2d).""" + pos = getattr(err, "pos", None) + if isinstance(pos, int): + return f"{option} is not valid near character {pos + 1}" + return f"{option} is not valid" + + +# The units a formula's "units" field may name, as a reader writes them. +UNIT_WORDS = {"c_eur_per_kwh": "c/kWh", "eur_per_kwh": "EUR/kWh"} + + def setting(key: str, unit: str = "") -> str: """`max_w` -> `“Inverter rating” (max_w)`. For one inverter in a list it is `“Inverter rating” for inverter-b (inverters.max_w)`, so the config panel diff --git a/goodwe_controller/app/p1.py b/goodwe_controller/app/p1.py index 181eec7..0f19017 100644 --- a/goodwe_controller/app/p1.py +++ b/goodwe_controller/app/p1.py @@ -472,7 +472,7 @@ class P1Ingest: """ self.parse_errors += 1 self.last_error = str(err) - _LOG.warning("P1 telegram rejected: %s", err) + _LOG.warning("Meter reading refused: %s", err) # -- what consumers read ------------------------------------------------- def age_s(self) -> float | None: @@ -1167,7 +1167,7 @@ def validate_meter_options(opts: dict, phases: int, max_age_s: float) -> list[st problems.append( f"{_S('meter_source')} is {SOURCE_HA!r}, so it needs " f"{_S('p1_import_entity')} and {_S('p1_export_entity')}. They " - f"are {imp or '<blank>'!r} and {exp or '<blank>'!r}.") + f"are {messages.shown(imp)} and {messages.shown(exp)}.") elif source == SOURCE_HA_SIGNED: net = str(opts.get("p1_net_entity", "") or "").strip() phase_net = [str(e).strip() for e in @@ -1194,7 +1194,7 @@ def validate_meter_options(opts: dict, phases: int, max_age_s: float) -> list[st try: int(port_s) except ValueError: - problems.append(f"{_S('p1_host')} is {opts.get('p1_host')!r}, and " + problems.append(f"{_S('p1_host')} is {messages.shown(opts.get('p1_host'))}, and " "its port is not a number.") try: # ⚠️ Not `or 5`: that turns an explicit 0 into the default, and a @@ -1204,7 +1204,7 @@ def validate_meter_options(opts: dict, phases: int, max_age_s: float) -> list[st poll_s = float(5 if raw is None or raw == "" else raw) except (TypeError, ValueError): problems.append(f"{_S('meter_poll_s')} is " - f"{opts.get('meter_poll_s')!r}, which is not a " + f"{messages.shown(opts.get('meter_poll_s'))}, which is not a " "number.") else: if poll_s <= 0: @@ -1269,9 +1269,8 @@ def build_source(opts: dict, ingest: P1Ingest, session, broker: dict | None): # 0 W cycle, which is fail-safe. The refusal above is for cadences that # can NEVER be fresh. if poll_s > ingest.max_age_s / 2: - _LOG.warning("meter_poll_s %.1f leaves no room under meter_max_age_s " - "%.1f: one missed poll makes the reading stale. The meter " - "updates every ~5 s; 5 s against 30 s is the tested pair.", + _LOG.warning("“Time between meter reads” (%.1f s) is too close to " + "“Reading too old after” (%.1f s). Use 5 s and 30 s.", poll_s, ingest.max_age_s) return HomeWizardLocalSource(session, ingest, host, port=port, poll_s=poll_s) if source == SOURCE_MQTT: diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index 2fed3f8..2d0fe88 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -395,6 +395,7 @@ not need re-testing. Nothing here indexes a phase. from dataclasses import dataclass +from . import messages from .arbiter import ACTUATOR_SITE, P_PEAK, Claim from .control import peak_at_risk from .tariff import QUARTER_S @@ -485,17 +486,29 @@ class PeakDecision: reason: str = "" def explain(self) -> str: + """Idle: the status row's plain words (UX-08). Engaged: `reason`, the + technical record with every figure, for the log and the action log.""" if self.floor_limited: return self.reason if not self.engaged: if self.projected_w is None: - return f"peak guard idle - {self.reason}" - return (f"peak guard idle - quarter projects " - f"{self.projected_w:.0f} W under a {self.ceiling_w:.0f} W " - f"ceiling ({self.ceiling_from})") + return messages.row_peak_guard_quiet() + return messages.row_peak_guard_idle( + self.projected_w, self.ceiling_w, + month_peak=self.ceiling_from == CEILING_MONTH_PEAK) return self.reason +def blind_kind(blind: str) -> str: + """Which of the three kinds of blindness, as a key of + `messages.BLIND_WORDS`, for the status row.""" + if blind == BLIND_FROZEN: + return "frozen" + if blind == BLIND_NO_BLOCK: + return "no_block" + return "gap" + + def quarter_ceiling_w(cap_w, reading) -> tuple[float, str]: """The average this quarter may not exceed, and where the number came from. diff --git a/goodwe_controller/app/price.py b/goodwe_controller/app/price.py index 864dfe0..adeafb3 100644 --- a/goodwe_controller/app/price.py +++ b/goodwe_controller/app/price.py @@ -1314,8 +1314,8 @@ def code_leaks(cls) -> list: src = dedent(inspect.getsource(cls)) tree = ast.parse(src) except (OSError, TypeError, IndentationError, SyntaxError) as e: - _LOG.warning("could not read %s's source for the framework-key scan " - "(%s); the double-counting guard is NOT enforced for it", + _LOG.warning("Could not read the code of price source %s (%s), so its " + "double-counting check is skipped.", getattr(cls, "id", cls), e) return [] for node in ast.walk(tree): @@ -1718,9 +1718,8 @@ def _points_from_columnar_json(body, expect_unit, scale, # Not a refusal: today's prices are still prices. But §11.4 makes a # dead feed look exactly like a quiet one, so the warning that the # source is going away has to be emitted while it still works. - _LOG.warning("the price feed reports deprecated=%r; it still answers, " - "but this endpoint is scheduled to stop", - doc.get("deprecated")) + _LOG.warning("The price feed says it will stop (deprecated=%r), " + "though it still answers for now.", doc.get("deprecated")) out = [] dropped = [] for i, (t, v) in enumerate(zip(times, prices)): @@ -1739,9 +1738,8 @@ def _points_from_columnar_json(body, expect_unit, scale, out.append(RawPoint(start=start, eur_per_kwh=float(v) * scale, provisional=bool(provisional_default))) if dropped: - _LOG.warning("the feed published no price for %d of %d instants " - "(index %s); those instants are left OUT of the series, " - "never zero-filled - a missing hour is not a free hour", + _LOG.warning("The price feed gave no price for %d of %d times (index " + "%s). Those times are left out, not counted as free.", len(dropped), len(times), ", ".join(str(i) for i in dropped[:5]) + (", ..." if len(dropped) > 5 else "")) @@ -1790,16 +1788,16 @@ def dayahead_feed_url(plugin_id, opts, since, until, base, bzn) -> str: override = str(opts.get("price_feed_url") or "").strip() if override: _LOG.warning( - "price_feed_url is set, so %s is requesting %s exactly as " - "given and is adding NO date range to it. The public feed " - "answers a single Brussels day to a request that names no " - "range, and every hour past that day is then carried forward " - "from yesterday's profile and flagged provisional - §8.3 " - "drops provisional hours from the trade set, so arbitrage " - "would never see tomorrow as firm. Clear price_feed_url to " - "let this plugin ask for the %s..%s it was given.", + "price_feed_url is set, so %s asks for %s as given, and " + "tomorrow's prices may stay provisional. Clear it to ask for %s " + "to %s.", plugin_id, override, *(d.isoformat() for d in brussels_date_range(since, until))) + _LOG.debug( + "The public feed answers one Brussels day to a request that names " + "no range. Every later hour is then copied from yesterday and " + "marked provisional, and §8.3 leaves provisional hours out of " + "trading.") return override first, last = brussels_date_range(since, until) return dated_feed_url(base, bzn=bzn, start=first.isoformat(), @@ -2083,8 +2081,8 @@ def _emit_startup_preview(plugin, pid: str, points) -> None: try: lines = list(plugin.startup_preview(points)) except Exception as e: # noqa: BLE001 - _LOG.warning("%s's startup preview raised (%s: %s); prices are " - "unaffected - this is a log line, not a decision", + _LOG.warning("%s could not show its start-up preview (%s: %s). Prices " + "are not affected.", pid, type(e).__name__, e) return for line in lines: @@ -2131,12 +2129,12 @@ async def load_prices(opts: dict, since: datetime, until: datetime, # Not silent, and not a traceback into the 30 s tick. validate.py # should have refused this at startup; if the add-on is running with it # anyway, the operator is told which key and what is wrong with it. - _LOG.error("price_taxes_profile cannot be used (%s: %s), so this fetch " - "has NO tax component to add - it is not falling back to " - "price_taxes_eur_kwh, because a silently different tax " - "basis is the defect this option exists to remove. Fix the " - "table or clear it; validate.py refuses it at startup", + _LOG.error("price_taxes_profile cannot be used (%s: %s), so no taxes " + "are added to this price update. Fix the table or clear it.", type(e).__name__, e) + _LOG.debug("price_taxes_eur_kwh is not used instead, because a " + "silently different tax basis is the fault this setting " + "exists to remove.") return PriceRead.no_data( f"price_taxes_profile cannot be used: {e}") if table is not None: diff --git a/goodwe_controller/app/price_history.py b/goodwe_controller/app/price_history.py index 433c803..673d521 100644 --- a/goodwe_controller/app/price_history.py +++ b/goodwe_controller/app/price_history.py @@ -345,8 +345,8 @@ def _row_of(day: str, points: int, hours: int) -> str: whole day to carry, and that is the HOUR figure; the point count says how finely it is priced. Neither answers for the other. """ - return (f"{day} ({points} point{'' if points == 1 else 's'} " - f"over {hours} h)") + return (f"{day} ({points} price{'' if points == 1 else 's'} " + f"over {hours} hour{'' if hours == 1 else 's'})") def _bad_rows(rec) -> int: @@ -437,9 +437,9 @@ class PriceHistory: # exactly what this handler says, and a third `ValueError` subclass # nobody has thought of is how this defect arrived the first time. self.last_error = f"unreadable ({err})" - _LOG.warning("price history at %s is %s - starting from empty. " - "§8.3 carry-forward has nothing to carry until the " - "next refresh has written a full day", + _LOG.warning("Price history at %s is %s, so it starts empty. " + "Missing hours cannot be filled in until a full day " + "is saved.", self.path, self.last_error) return found = blob.get("version") if isinstance(blob, dict) else None @@ -775,8 +775,8 @@ class PriceHistory: f"which is not a PriceProduct. The optimiser switches on that " f"enum, so a record that cannot name one cannot be a series") if bad: - _LOG.warning("price history: %s in the %s record were dropped; " - "%d point(s) carried forward", bad, want, len(points)) + _LOG.warning("Price history: %s in the %s record were dropped, " + "and %d points were kept.", bad, want, len(points)) return PriceRead.series(points, product, str(rec.get("provider") or "price_history"), stamp) diff --git a/goodwe_controller/app/selfconfig.py b/goodwe_controller/app/selfconfig.py index da5ad38..b2c94d3 100644 --- a/goodwe_controller/app/selfconfig.py +++ b/goodwe_controller/app/selfconfig.py @@ -381,8 +381,8 @@ async def save(selfcfg: SelfConfig, proposed: dict, expect: str, *, """ problems = await problems_for(proposed, hass) if problems: - _LOG.warning("panel REFUSED to save: %d configuration problem(s); " - "nothing written. First: %s", len(problems), problems[0]) + _LOG.warning("The settings page did not save, because of %d " + "problems. The first: %s", len(problems), problems[0]) raise SaveRefused("invalid", problems=problems) info = await selfcfg.info() @@ -390,8 +390,8 @@ async def save(selfcfg: SelfConfig, proposed: dict, expect: str, *, actual = fingerprint(stored) if actual != expect: changed = changed_keys(stored, proposed) - _LOG.warning("panel REFUSED to save: the stored options changed " - "underneath this page (keys: %s); nothing written", + _LOG.warning("The settings page did not save, because the settings " + "changed while it was open (keys: %s).", ", ".join(changed) or "none this page also edited") raise SaveRefused("stale", changed=changed, stored=stored) diff --git a/goodwe_controller/app/shadow.py b/goodwe_controller/app/shadow.py index 9e36c94..ada7c30 100644 --- a/goodwe_controller/app/shadow.py +++ b/goodwe_controller/app/shadow.py @@ -318,11 +318,8 @@ WIRE_W = 0.0 #: a cap that does not bind - and a number invented for the row would be a #: second helping of the defect this constant exists to disclose. SIZED_FROM_METER = ( - "⚠️ AND ITS SIZE CAME FROM THE BILLED-QUARTER METER, WHICH HAS ONLY THE " - "HOUSE IN IT WHILE THE BATTERY IS HELD AT 0 W. A live run sizes the same " - "trade against a meter the battery is moving, so this is an UPPER BOUND " - "and not a prediction; how far under it a live run lands is a closed-loop " - "question and a shadow run cannot answer it") + "This is an upper limit, not a forecast, because the meter did not see " + "the battery move.") def mode(opts: dict) -> str: @@ -373,18 +370,18 @@ def why(opts: dict, *, control_started: bool) -> str: # discount. What is true in every live state is that what this add-on # decides reaches the inverter; whether control is RUNNING is the # `Stopped` banner's question and it is answered there. + # UX-08: the same four rungs, in plain words. The setting is named by its + # value, "automatic" for `auto`, so each rung still reads differently. m = mode(opts) + live = "what the add-on decides reaches the inverters" + inert = "the add-on decides but sends nothing" if m == "off": - return ("off (shadow_mode: off) - NOT in shadow mode: what this " - "add-on decides DOES reach the inverter") + return f"Off, {live}" if m == "on": - return ("on (shadow_mode: on) - decisions are recorded and nothing " - "is commanded") + return f"On, {inert}" if control_started: - return ("off (shadow_mode: auto, control is started) - NOT in shadow " - "mode: what this add-on decides DOES reach the inverter") - return ("on (shadow_mode: auto, control is stopped) - decisions are " - "recorded and nothing is commanded") + return f"Off (automatic, control is started), {live}" + return f"On (automatic, control is stopped), {inert}" def words(opts: dict, *, control_started: bool, would_w: float | None, @@ -411,10 +408,10 @@ def words(opts: dict, *, control_started: bool, would_w: float | None, that decided it did not apply, which is the shape of defect this card is about. TEST-14's rule with a new name on it. - ⚠️ AND THE PHRASE IS "ON THIS CYCLE", UNCONDITIONALLY, NOT ONLY WHEN THE + ⚠️ AND THE PHRASE IS "THIS CYCLE", UNCONDITIONALLY, NOT ONLY WHEN THE CAVEAT FIRES. Every number a shadow run records was reached from a plant - that did not respond; "WOULD HAVE COMMANDED -2 000 W" reads as a forecast - of a live run and no number here is one. The ⚠️ below is the STRONGER, + that did not respond; "would ask for -2 000 W" alone reads as a forecast + of a live run and no number here is one. UX-08 2d put it in plain words. The ⚠️ below is the STRONGER, conditional statement about the cycles where the answer can be multiples out - see this module's header for the measured table. @@ -431,19 +428,19 @@ def words(opts: dict, *, control_started: bool, would_w: float | None, if not engaged(opts, control_started=control_started): return head if would_w is None: - return (f"{head}; no decision has been reached yet - the inverter is " - f"held at {WIRE_W:.0f} W") + return (f"{head}. No decision yet, the inverters stay at " + f"{WIRE_W:.0f} W.") # ⚠️ THE THOUSANDS SEPARATOR IS SWAPPED ON THE NUMBER ALONE. Applied to # the whole sentence it ate the comma out of `head` - and `head` is the # half that says WHICH RUNG decided, which is the claim MUTATION.md's # masking rule says must survive. num = f"{float(would_w):+,.0f}".replace(",", " ") - out = (f"{head}; ON THIS CYCLE WOULD HAVE COMMANDED {num} W, inverter " - f"held at {WIRE_W:.0f} W") + out = (f"{head}. This cycle it would ask for {num} W, the inverters stay " + f"at {WIRE_W:.0f} W.") if sized_from_meter: out += f" {SIZED_FROM_METER}" if reason: - out += f" - {reason}" + out += f" Why: {reason}." return out @@ -504,6 +501,6 @@ def problems(opts: dict) -> list: text = str("" if raw is None else raw).strip().lower() if text in MODES: return [] - return [f"{messages.setting('shadow_mode')} is {raw!r}. Choose " + return [f"{messages.setting('shadow_mode')} is {messages.shown(raw)}. Choose " + ", ".join(f"'{m}'" for m in MODES[:-1]) + f" or '{MODES[-1]}'."] diff --git a/goodwe_controller/app/static_tariff.py b/goodwe_controller/app/static_tariff.py index 93b96c2..58dcae3 100644 --- a/goodwe_controller/app/static_tariff.py +++ b/goodwe_controller/app/static_tariff.py @@ -204,6 +204,7 @@ import math from dataclasses import dataclass from datetime import datetime, timedelta, timezone +from . import messages from .price import ( MAX_PLAUSIBLE_EUR_KWH, Absence, PricePoint, PriceProduct, PriceRead, Uncertainty, _Outcome, brussels, load_prices, price_option, @@ -597,11 +598,9 @@ def parse_static_profile(value, *, option: str = "static_profile", value = json.loads(text) except ValueError as e: raise ProfileInvalid( - f"{option} is not valid JSON ({e}). Write it on one line with " - f"a \"periods\" list, for example\n" - f' {{"periods": [{{"name":"day","from":"07:00","to":"22:00",' - f'"days":"mon-fri","eur_per_kwh":0.34}}, ...]}}\n' - f"Leave it empty if you have no fixed tariff.") + f"{messages.not_valid(option, e)}. Copy the example from the " + f"documentation, or leave it empty if you have no fixed " + f"tariff.") if isinstance(value, dict): tz = str(value.get("timezone", "") or "").strip().lower() @@ -1120,18 +1119,24 @@ class TariffPlan: for 76 % of a 40-hour soak and mixed 900/3600 s for 70 %, and no HTTP surface said either. """ + # UX-08: plain words, every figure in its own slot as before. if not self.has_prices: - return f"no tariff - {self.read.reason}" - tag = {"provider": self.read.provider, "static": "static_profile", - "fallback": "static_profile (feed down)"}.get(self.origin, - self.origin) + return f"no prices, {self.read.reason}" + tag = {"provider": "the price feed", "static": "your fixed tariff", + "fallback": "your fixed tariff, because the feed is down"}.get( + self.origin, self.origin) + what = {PriceProduct.DAY_AHEAD: "day-ahead prices", + PriceProduct.REALTIME: "real-time prices", + PriceProduct.STATIC: "day/night prices", + PriceProduct.FIXED: "a fixed price"}.get(self.product, + str(self.product)) gaps = self.spacings_s - return (f"{self.product.value} from {tag}, " - f"{self.n_points} points over {self.hours} h, " - f"{self.n_firm} firm / {self.n_carried} carried" - + (f", {'+'.join(str(g) for g in gaps)} s spacing" + return (f"{what} from {tag}, " + f"{self.n_points} prices over {self.hours} hours, " + f"{self.n_firm} published and {self.n_carried} estimated" + + (f", {'+'.join(str(g) for g in gaps)} s apart" if gaps else "") - + (", provisional" if self.provisional else "")) + + (", not final yet" if self.provisional else "")) def _whole_hours(points) -> int: @@ -1225,21 +1230,22 @@ def static_status(opts: dict, now: datetime): plan = static_plan(opts, now, now + timedelta(days=MEAN_WINDOW_DAYS), now=now) except ProfileInvalid as e: - _LOG.warning("static_profile is unusable (%s); no cheap window. This " - "should have been refused at startup - see validate.py", e) - return False, f"static_profile unusable: {e}" + _LOG.warning("static_profile cannot be used (%s), so there is no " + "cheap window. The start-up check should have refused " + "it.", e) + return False, f"Fixed tariff cannot be used: {e}" if not plan.has_prices: - return False, "no static profile" + return False, "No fixed tariff set" cheap = plan.cheap_now(now) window = plan.window_at(now) price = plan.price_at(now) when = plan.profile.next_change(now) until = "" if when is None else f" until {brussels(when):%H:%M}" - kind = ("fixed" if plan.product is PriceProduct.FIXED else "day/night") - return cheap, (f"{kind}: {window}{until} at {price:.4f} EUR/kWh, " - f"mean {plan.mean_eur_kwh():.4f} over " - f"{MEAN_WINDOW_DAYS} d - " - f"{'CHEAP window' if cheap else 'not a cheap window'}") + kind = ("Fixed" if plan.product is PriceProduct.FIXED else "Day/night") + return cheap, (f"{kind} tariff, {window}{until}: {price:.4f} EUR/kWh, " + f"{'cheap' if cheap else 'not cheap'} against the " + f"{MEAN_WINDOW_DAYS}-day average of " + f"{plan.mean_eur_kwh():.4f}") async def resolve_tariff(opts: dict, since: datetime, until: datetime, @@ -1336,13 +1342,12 @@ def _degrade(opts, read, since, until, stamp) -> TariffPlan: "(%s), so there is no tariff at all", e) profile = None if profile is None: - _LOG.warning("§11.4: %s, and no static_profile is configured to fall " - "back to. The plan is provisional and arbitrage is off; " - "self-consumption, peak shaving and reserve management " - "continue (§6, §10.1).", read.reason) + _LOG.warning("%s, and no static_profile is set to fall back to, so " + "prices are provisional and trading is off. Peak " + "limiting and home use go on.", read.reason) return TariffPlan(read, None, "none") - _LOG.warning("§11.4: %s - falling back to the static profile, plan marked " - "PROVISIONAL, arbitrage off.", read.reason) + _LOG.warning("%s, so the static_profile tariff is used instead, marked " + "provisional, and trading is off.", read.reason) points = profile.series(since, until, provisional=True) return TariffPlan( PriceRead.series(points, profile.product, "static_profile", stamp), diff --git a/goodwe_controller/app/store.py b/goodwe_controller/app/store.py index 90ecbd4..6ff0cc1 100644 --- a/goodwe_controller/app/store.py +++ b/goodwe_controller/app/store.py @@ -328,8 +328,8 @@ def migrate_unit_keys(store, unit: str, roster=None) -> MigrationReport: # ⚠️ NOT MARKED DONE. A migration that lost state must run again on the # next start rather than be recorded as finished - the one thing worse # than a failed migration is a failed migration a later version skips. - _LOG.error("per-inverter store migration LOST STATE and has not been " - "marked done: %s", rep.explain()) + _LOG.error("Moving the saved state to one part per inverter lost " + "data, so it is not marked done: %s", rep.explain()) return rep diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 53707c6..2ab7a0b 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -647,7 +647,7 @@ def _roster_problems(opts: dict) -> list[str]: where = f"inverters[{i}]" if not isinstance(entry, dict): problems.append( - f"{where} in the “Inverter list” is {entry!r}. Each entry needs " + f"{where} in the “Inverter list” is {messages.shown(entry)}. Each entry needs " "a name, a setpoint entity and an inverter rating.") continue name = str(entry.get("name") or "").strip() @@ -670,7 +670,7 @@ def _roster_problems(opts: dict) -> list[str]: if _number(entry, "max_w", None) is None or (_number(entry, "max_w", None) or 0) <= 0: problems.append( f"{who} has no usable {S('max_w')}: it is " - f"{entry.get('max_w')!r}. Set this inverter's own rating in " + f"{messages.shown(entry.get('max_w'))}. Set this inverter's own rating in " "watts.") # --- (f) and (g): OPT-09's capacity, which is optional but not partial --- @@ -690,7 +690,7 @@ def _roster_problems(opts: dict) -> list[str]: val = None if val is None or not (val > 0.0): problems.append( - f"{who} has {S('capacity_kwh')} {raw!r}, which is not a usable " + f"{who} has {S('capacity_kwh')} {messages.shown(raw)}, which is not a usable " "number. Set it in kWh, or leave it empty on every inverter.") else: stated.append(who) @@ -831,7 +831,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] # has answered; it is not called from here because at startup no device has. max_w = _number(opts, "max_w", 2000.0) if max_w is None: - problems.append(f"{S('max_w')} is {opts.get('max_w')!r}, which is not " + problems.append(f"{S('max_w')} is {messages.shown(opts.get('max_w'))}, which is not " "a number. Set it in watts.") # ⚠️ config.yaml's int(100,5000) already blocks this on a real install, so # the check is not for the Supervisor path - it is because @@ -866,8 +866,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] if phases is None or max_age_s is None: problems.append(f"{S('meter_phases')} and {S('meter_max_age_s')} must " f"both be numbers. They are " - f"{opts.get('meter_phases')!r} and " - f"{opts.get('meter_max_age_s')!r}.") + f"{messages.shown(opts.get('meter_phases'))} and " + f"{messages.shown(opts.get('meter_max_age_s'))}.") else: problems.extend(validate_meter_options(opts, int(phases), max_age_s)) @@ -918,14 +918,14 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] weakest = min(caps) if caps else None if sign_w is None: problems.append(f"{S('sign_disagree_w')} is " - f"{opts.get('sign_disagree_w')!r}, which is not a " + f"{messages.shown(opts.get('sign_disagree_w'))}, which is not a " "number. Set it back to 300 W.") elif weakest is not None and weakest > 0 and sign_w >= weakest: where = _unit_label(opts, min(caps_ix, key=lambda p: p[1])[0]) problems.append( - f"{S('sign_disagree_w')} is {sign_w:.0f} W, but the " - f"{S('max_w', where)} is {weakest:.0f} W, so this safety stop can " - f"never trip. Lower it below {weakest:.0f} W, or raise the rating.") + f"{S('sign_disagree_w')} is {sign_w:.0f} W, not below " + f"{S('max_w', where)} at {weakest:.0f} W, so this safety stop can " + f"never trip. Lower it or raise the rating.") # ⚠️ AND THE SAME RULE FOR SAFETY-30's PER-UNIT THRESHOLD, WHICH IS A # SEPARATE COMPARISON AND THEREFORE A SEPARATE WAY TO DISARM. It grades a @@ -972,15 +972,14 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] if caps_ix else "") if unit_sign_w is None: problems.append(f"{S('unit_sign_disagree_w')} is " - f"{opts.get('unit_sign_disagree_w')!r}, which is not a " + f"{messages.shown(opts.get('unit_sign_disagree_w'))}, which is not a " "number. Set it back to " f"{SIGN_OPTION_DEFAULTS['unit_sign_disagree_w']:.0f} W.") elif weakest is not None and weakest > 0 and unit_sign_w >= weakest: problems.append( - f"{S('unit_sign_disagree_w')} is {unit_sign_w:.0f} W, but the " - f"{S('max_w', unit_where)} is {weakest:.0f} W, so this safety stop " - f"can never trip. Lower it below {weakest:.0f} W, or raise the " - "rating.") + f"{S('unit_sign_disagree_w')} is {unit_sign_w:.0f} W, not below " + f"{S('max_w', unit_where)} at {weakest:.0f} W, so this safety stop " + f"can never trip. Lower it or raise the rating.") # --- 6. a maintenance charge the ceiling can actually accommodate -------- # ⚠️ Strictly `>`, matching the arbiter exactly. The shaping is @@ -1054,7 +1053,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] if charge_w is None: problems.append( f"{S('maintenance_charge_w')} is " - f"{opts.get('maintenance_charge_w')!r}, which is not a number. Set " + f"{messages.shown(opts.get('maintenance_charge_w'))}, which is not a number. Set " "it in watts.") elif maint_cap is not None and maint_cap > 0 and charge_w > maint_cap: problems.append( @@ -1089,7 +1088,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] slew_w = _number(opts, "slew_w", 0.0) rail = site_rail_w(opts) if slew_w is None: - problems.append(f"{S('slew_w')} is {opts.get('slew_w')!r}, which is " + problems.append(f"{S('slew_w')} is {messages.shown(opts.get('slew_w'))}, which is " "not a number. Set it to 0 to follow the inverter " "rating.") elif slew_w < 0: @@ -1133,8 +1132,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] if soc_floor is None or bms_floor is None: problems.append( f"{S('peak_soc_floor')} and {S('bms_soc_floor', where)} must " - f"both be numbers. They are {opts.get('peak_soc_floor')!r} and " - f"{_raw!r}.") + f"both be numbers. They are {messages.shown(opts.get('peak_soc_floor'))} and " + f"{messages.shown(_raw)}.") elif soc_floor <= bms_floor: problems.append( f"{S('peak_soc_floor')} is {soc_floor:.0f} %, not above the " @@ -1147,10 +1146,8 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] integ_w = None if not integ else _number(opts, "integrator_max_w", None) if integ_w is not None and max_w is not None and integ_w > max_w: _LOG.warning( - "integrator_max_w %.0f W is above max_w %.0f W. Not refused - the " - "arbiter still bounds the wire to +-max_w - but the only thing the " - "extra headroom buys is more wrong-direction power to unwind after " - "saturation. 0 (follow max_w) is the recommended value.", + "integrator_max_w %.0f W is above max_w %.0f W. This is allowed, " + "but it only adds overshoot, so 0 is recommended.", integ_w, max_w) # ⚠️ THE SIBLING OF RULE 6, AND NOT THE SAME CASE - see the docstring. The @@ -1173,15 +1170,13 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] if (disch_w is not None and maint_cap is not None and maint_cap > 0 and disch_w > maint_cap): _LOG.warning( - "maintenance_discharge_w %.0f W is above max_w%s %.0f W. Not " - "refused - the drain phase SETS the setpoint and the arbiter clamps " - "it to %.0f W and names the clamp ('limited by supervised(max_w)'), " - "so nothing is silent and the cycle still completes. But it drains " - "at %.0f W, not the %.0f W you configured, and the drain phase has " - "a 720 min timeout. Lower it to %.0f W or raise max_w to remove the " - "surprise.", - disch_w, maint_where, maint_cap, maint_cap, maint_cap, disch_w, - maint_cap) + "maintenance_discharge_w %.0f W is above max_w%s %.0f W, so " + "draining runs at %.0f W. Lower it to %.0f W or raise max_w.", + disch_w, maint_where, maint_cap, maint_cap, maint_cap) + _LOG.debug( + "Not refused: the drain phase sets the setpoint, the arbiter " + "clamps it to %.0f W and names the clamp, and the drain phase has " + "a 720 min timeout.", maint_cap) return problems @@ -1289,10 +1284,9 @@ def _price_problems(opts: dict) -> list[str]: if str(opts.get(k, "") or "").strip()] if pid != "off" and ha_price: problems.append( - f"{S('price_provider')} is {pid!r}, but {_labels(ha_price)} " - f"{'is' if len(ha_price) == 1 else 'are'} also set and would win. " - f"Clear {'it' if len(ha_price) == 1 else 'them'}, or set the price " - "source to 'off'.") + f"{S('price_provider')} is {pid!r}, but {_labels(ha_price)} would " + f"win over it. Clear {'it' if len(ha_price) == 1 else 'them'}, or " + "set the source to 'off'.") # ⚠️ THE SAME RULE FOR THE SOURCE TARIFF-03 ADDED, AND THIS ONE IS A LIVE # CONFLICT RATHER THAN A LATENT ONE. main.py's read_inputs() takes `cheap` @@ -1302,7 +1296,8 @@ def _price_problems(opts: dict) -> list[str]: if ha_price and str(opts.get("static_profile", "") or "").strip(): problems.append( f"{S('static_profile')} is set, but {_labels(ha_price)} would win " - "over it. Clear the one you do not use.") + f"over it. Clear the fixed tariff or " + f"{'the entity' if len(ha_price) == 1 else 'the two entities'}.") # ⚠️ THE PROFILE ITSELF, PARSED AT STARTUP RATHER THAN AT 02:00. A profile # that does not tile the day has hours with no price, and the only ways to @@ -1374,9 +1369,8 @@ def _price_problems(opts: dict) -> list[str]: and not any(abs(scalar - u) <= 1e-12 for u in untouched): problems.append( f"{S(TAXES_PROFILE_OPTION)} is set, so " - f"{S('price_taxes_eur_kwh')} is not used, but it reads {scalar} " - f"instead of {shipped}. Set it back to {shipped}, or clear the " - "table.") + f"{S('price_taxes_eur_kwh')} is not used. Set it back to " + f"{shipped} from {scalar}, or clear the table.") # ⚠️ THE UNITS RUNG, AND IT IS A SECOND QUANTITY RATHER THAN A # RESTATEMENT. Every Belgian DSO prints these bands in c EUR/kWh @@ -1403,10 +1397,9 @@ def _price_problems(opts: dict) -> list[str]: # observe. §14's warning box governs CONTRADICTIONS, and this is # not one. _LOG.warning( - "%s carries negative levies %s EUR/kWh. That is accepted, but " - "a tax component below zero is usually a sign error: the " - "add-on will SUBTRACT it from the published price in those " - "hours.", TAXES_PROFILE_OPTION, negative) + "%s has negative levies %s EUR/kWh, which are subtracted from " + "the price. This is allowed, but it is usually a sign error.", + TAXES_PROFILE_OPTION, negative) # ⚠️ TARIFF-15: THE FORMULA, GRADED AGAINST THE OPERATOR'S OWN CARD, AT # STARTUP RATHER THAN AT 03:00. @@ -1459,11 +1452,9 @@ def _price_problems(opts: dict) -> list[str]: # silent loser this module's case (a) is about, so it is said out # loud rather than left to be discovered from a bill. _LOG.warning( - "price_formula is filled in but price_provider is %r, so the " - "coefficients decide NOTHING - only 'custom_formula' reads " - "them. Set price_provider to 'custom_formula' to use them, or " - "clear price_formula so the configuration says what the " - "add-on is doing.", pid) + "price_formula is filled in, but price_provider is %r, so the " + "formula is not used. Set price_provider to 'custom_formula' " + "or clear price_formula.", pid) if spec is not None and pid == "custom_formula": taxes = _number(opts, "price_taxes_eur_kwh", PRICE_OPTION_DEFAULTS["price_taxes_eur_kwh"]) @@ -1552,20 +1543,18 @@ def _price_problems(opts: dict) -> list[str]: # bounds in `implausible_injection()` are applied, and the # operator is told which of the two checks did NOT run. _LOG.warning( - "%s has no \"card\" block, so its coefficients are " - "UNGRADED: nothing recomputed a printed price from them. " - "That is accepted because it is the real market - Eneco " - "prints its injection formula with no price beside it, so " - "there is nothing to grade against on that card - and " - "refusing would make the published line inexpressible. " - "What IS checked is the shape of the coefficients: the " - "pass-through (%.4g x the wholesale price) and the offset " - "(%+.5f EUR/kWh). If YOUR card prints an injection " - "estimate, add {\"month\": ..., \"index_eur_per_mwh\": " - "..., \"expect_incl_vat\": ...} and the add-on will " - "refuse to start unless your numbers reproduce it.", + "%s has no \"card\" block, so its numbers are not checked " + "against a printed price, only their shape (pass-through " + "%.4g, offset %+.5f EUR/kWh).", EXPORT_FORMULA_OPTION, xspec.passthrough, xspec.offset_eur_kwh) + _LOG.debug( + "Accepted because some suppliers (Eneco) print the " + "injection formula with no price beside it. If your card " + "prints an injection estimate, add {\"month\": ..., " + "\"index_eur_per_mwh\": ..., \"expect_incl_vat\": ...} " + "and the add-on refuses to start unless your numbers " + "reproduce it.") else: xaged = stale_card(xspec) if xaged: @@ -1578,11 +1567,9 @@ def _price_problems(opts: dict) -> list[str]: # every install TARIFF-02 shipped, none of which could have had one. if pid != "off" and not str(opts.get("static_profile", "") or "").strip(): _LOG.warning( - "price_provider is %r but static_profile is empty. §11.4's " - "degradation row is 'no price data -> fall back to the static " - "profile'; with none configured, a feed outage leaves this site " - "with no tariff at all rather than with a coarse one. Not refused, " - "but filling it in is what makes that row work.", pid) + "price_provider is %r but static_profile is empty, so a price " + "feed outage leaves no tariff at all. Fill in static_profile as a " + "fallback.", pid) # ⚠️ OPT-04. THE THREE WAYS `arbitrage_enabled: true` CAN BE A LIE, refused # rather than logged, because a strategy that is armed in the UI and cannot @@ -1598,7 +1585,7 @@ def _price_problems(opts: dict) -> list[str]: if thresh is None or thresh < 0: problems.append( f"{S('cycle_cost_threshold_eur')} is " - f"{opts.get('cycle_cost_threshold_eur')!r}. Set it to 0 or more, " + f"{messages.shown(opts.get('cycle_cost_threshold_eur'))}. Set it to 0 or more, " "in EUR/kWh.") if arbitrage_on(opts): @@ -1655,11 +1642,9 @@ def refuse(problems: list[str]) -> None: at all and even the exit status distinguishes the two. """ _LOG.error("=" * 72) - _LOG.error("REFUSING TO START: the add-on configuration is not usable.") - _LOG.error("This is a CONFIGURATION problem, not a crash. Nothing is broken;") - _LOG.error("the add-on will start as soon as the settings below are fixed.") - _LOG.error("Fix them in Settings > Add-ons > GoodWe RS485 Controller >") - _LOG.error("Configuration, then start the add-on again.") + _LOG.error("The add-on did not start, because its settings have problems.") + _LOG.error("Nothing is broken. Fix the settings below, then start it again.") + _LOG.error("They are on the add-on's Configuration tab.") _LOG.error("-" * 72) for i, problem in enumerate(problems, 1): _LOG.error(" %d. %s", i, problem) diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index a21b736..62b516b 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -31,7 +31,7 @@ import logging from aiohttp import web -from . import selfconfig +from . import messages, selfconfig from .config_page import CONFIG_PAGE from .configui import changed_keys, field_model, problems_by_field @@ -125,11 +125,8 @@ refresh(); setInterval(refresh, 3000); # them too, and says so, because a green page that is green for a reason the # operator cannot see is the exact failure this add-on keeps refusing to ship. DEVICE_NOTE = ( - "%s did not report a range, so the two checks that compare a configured " - "ceiling against what the device itself accepts were skipped - here and at " - "startup, identically. Everything else was checked. If the device answers " - "later and disagrees, the add-on refuses to start then, with the same " - "message you would have seen here.") + "%s did not report its power range, so two checks were skipped, here and " + "at start. If they fail later, the add-on will not start then.") def build_app(controller, selfcfg=None) -> web.Application: @@ -264,7 +261,8 @@ def build_app(controller, selfcfg=None) -> web.Application: _LOG.error("saving options failed: %s", err) return web.json_response({"error": str(err)}, status=502) controller.log_event("configuration saved from the panel - " - "not applied until the add-on restarts") + "not applied until the add-on restarts", + hint=messages.hint("settings_saved")) return web.json_response({"ok": True, **result}) async def config_restart(request): @@ -288,7 +286,8 @@ def build_app(controller, selfcfg=None) -> web.Application: except selfconfig.SupervisorUnavailable as err: _LOG.error("restart request failed: %s", err) return web.json_response({"error": str(err)}, status=502) - controller.log_event("restart requested from the configuration panel") + controller.log_event("restart requested from the configuration panel", + hint=messages.hint("restart_requested")) return web.json_response({"ok": True}) app = web.Application() diff --git a/goodwe_controller/test_arbitrage.py b/goodwe_controller/test_arbitrage.py index 714839c..9a40478 100644 --- a/goodwe_controller/test_arbitrage.py +++ b/goodwe_controller/test_arbitrage.py @@ -1487,13 +1487,14 @@ s47check("the shipped row carries the caveat at the worst cycle: the operator is s47check("...and it still carries the watts, in their own slot, and the standing " "0 W beside them - the caveat NARROWS the claim rather than deleting " "the record a shadow run exists to produce", - "WOULD HAVE COMMANDED" in _s47_row and "inverter held at 0 W" in _s47_row + "it would ask for" in _s47_row + and "the inverters stay at 0 W" in _s47_row and f"{round(_s47_chg['would_w']):+d}".replace("+", "") != "") -s47check("...and the watts are introduced as what it would have commanded ON " - "THIS CYCLE, in every shadow state and not only the caveated ones - no " - "number a shadow run records is a forecast of a live run", - "ON THIS CYCLE WOULD HAVE COMMANDED" in _s47_row - and "ON THIS CYCLE WOULD HAVE COMMANDED" in _s47_first_row) +s47check("...and the watts are introduced as what it would ask for THIS CYCLE, " + "in every shadow state and not only the caveated ones - no number a " + "shadow run records is a forecast of a live run (UX-08: in plain words)", + "This cycle it would ask for" in _s47_row + and "This cycle it would ask for" in _s47_first_row) # --- 3d-7b. THE ACTION LOG, WHICH IS THE RECORD READ AFTERWARDS ----------- # ⚠️ THE TWO SURFACES ARE GRADED SEPARATELY BECAUSE THEY FAILED SEPARATELY. diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index 51da777..c3f355c 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -77,6 +77,7 @@ Read MUTATION.md before you report a survivor. import asyncio import io import math +import os import re import sys from datetime import datetime, timedelta, timezone @@ -1874,8 +1875,8 @@ check("...and it is FIRST in the cascade: the same controller has other " "conditions to report and none of them displaces this sentence", _live_pay["banner"] != _shad_pay["banner"] and "Shadow mode" not in _live_pay["banner"]) -_slot = re.search(r"WOULD HAVE COMMANDED ([-+][\d ]+) W, inverter held at " - r"([-\d]+) W", _shad_rows[_ROW]) +_slot = re.search(r"This cycle it would ask for ([-+][\d ]+) W, the inverters " + r"stay at ([-\d]+) W", _shad_rows[_ROW]) check("the row answers 'what would it have done' with a NUMBER in its own " "named slot, and says where the inverter actually is in a second one - " "two slots in one sentence, so a transposition moves them", @@ -1889,15 +1890,16 @@ if _slot is not None: check("...and the second slot is the STANDING command, so the two cannot " "be read as one number", float(_slot.group(2)) == 0.0) -check("the row answers 'and why' by carrying the arbiter's own sentence, " - "rather than a re-derivation of it", - _shad_c.reason in _shad_rows[_ROW]) +check("the row answers 'and why' by carrying the page's own Why line, the " + "arbiter's answer in plain words (UX-08), rather than a re-derivation", + _shad_c.why_words in _shad_rows[_ROW] + and dict(_shad_pay["rows"])["Why"] == _shad_c.why_words) check("with shadow mode off the row says so, and says what follows from it - " "which is the arrangement that makes the one above a claim about this " "controller and not about the string", - "NOT in shadow mode" in _live_rows[_ROW] - and "DOES reach the inverter" in _live_rows[_ROW] - and "WOULD HAVE COMMANDED" not in _live_rows[_ROW]) + _live_rows[_ROW].startswith("Off") + and "reaches the inverters" in _live_rows[_ROW] + and "would ask for" not in _live_rows[_ROW]) # ⚠️ A STANDING LATCH IS SHOWN RATHER THAN HIDDEN. The shadow banner sits above # the three `bad` branches, so it has to say what they would have said - a @@ -2074,9 +2076,14 @@ check("defect 2: it quotes the requested COMMAND of that tick, not i_w", over and all(f"computed {_f(d, 'requested_w'):+.0f} W" in r for d, t, r in over)) check("defect 3: 'clamped to' is the clamp's own result, not self.target", over and all(f"clamped to {_f(d, 'clamped_w'):+.0f} W" in r for d, t, r in over)) -check("...and the 14 768 W rationale is still in its ERROR", - any(x.levelno == logging.ERROR and "14 768 W" in x.getMessage() - for x in log_o)) +check("...and its ERROR says it is a software fault and that control keeps " + "running (UX-08 2d moved the 14 768 W rationale to a DEBUG line beside " + "it, which is still in main.py)", + any(x.levelno == logging.ERROR and "software fault" in x.getMessage() + and "Control is still running" in x.getMessage() for x in log_o) + and "reached 14 768 W on this project" in + open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "app", + "main.py"), encoding="utf-8").read()) check("...under the over-rating title, quoting a tick's own asked and sent " "numbers in that order, with a red status row", clamp_notes(hass_o) diff --git a/goodwe_controller/test_control_task.py b/goodwe_controller/test_control_task.py index ed1f8b0..b37afa2 100644 --- a/goodwe_controller/test_control_task.py +++ b/goodwe_controller/test_control_task.py @@ -189,13 +189,13 @@ check(f"the wind-down ran: 0 W written AFTER the fault (writes after = {after})" check("the web runner was cleaned up, i.e. the ordinary shutdown path ran", ["cleanup"] in ev[(fault_at or 0):]) died_line = next((i for i, ln in enumerate(err.splitlines()) - if "CONTROL LOOP DIED (RuntimeError('" + FAULT + "'))" in ln), None) + if "Control stopped unexpectedly (RuntimeError('" + FAULT + "'))" in ln), None) wind_line = next((i for i, ln in enumerate(err.splitlines()) if "shutting down - commanding 0 W" in ln), None) check("a CRITICAL line names the exception and the exit status", died_line is not None and "CRITICAL" in err.splitlines()[died_line] - and "commanding 0 W and exiting with status 70" in err.splitlines()[died_line]) + and "set to 0 W and the add-on exits with code 70" in err.splitlines()[died_line]) check("the traceback is logged, down to the frame that raised", "Traceback (most recent call last)" in err and f"RuntimeError: {FAULT}" in err and "in cycle" in err) @@ -211,7 +211,7 @@ print("2. the same entry point stopped by SIGTERM - the callback must stay quiet rc2, out2, err2, ev2 = run_child("clean") print(f" exit status {rc2}; events {ev2}") check("an ordinary stop still exits 0", rc2 == 0) -check("an ordinary stop logs no CONTROL LOOP DIED", "CONTROL LOOP DIED" not in err2) +check("an ordinary stop logs no unexpected stop", "Control stopped unexpectedly" not in err2) check("an ordinary stop still winds down to 0 W, from a non-zero command", any(e[0] == "w" and e[1] != 0.0 for e in ev2) and [e for e in ev2 if e[0] == "w"][-1:] == [["w", 0.0]]) @@ -222,7 +222,7 @@ rc3, out3, err3, ev3 = run_child("refuse") print(f" exit status {rc3}") check("a late-arriving device rating refusal exits 78 (EX_CONFIG), not 70", rc3 == 78) -check("and is not reported as a death", "CONTROL LOOP DIED" not in err3) +check("and is not reported as a death", "Control stopped unexpectedly" not in err3) if rc3 != 78: print(tail(err3)) diff --git a/goodwe_controller/test_freshness.py b/goodwe_controller/test_freshness.py index dcc36d2..65dd36b 100644 --- a/goodwe_controller/test_freshness.py +++ b/goodwe_controller/test_freshness.py @@ -360,7 +360,7 @@ check("...and `inputs_ok` goes False, so the site stops rather than regulating " _cs.inputs_ok is False and _cf.inputs_ok is True) check("...and the operator gets a line saying which unit and why, on the same " "status list the liveness notes use", - any("STALE_READING" in n and "inverter-a" in n + any("stopped changing" in n and "inverter-a" in n for n in _cs.liveness_notes()) and _cf.liveness_notes() == []) check("...and the raw number is still recorded for diagnostics, so the " @@ -1581,7 +1581,7 @@ check("...and the site stops holding inputs bad, which is what ends the " _c57.inputs_bad_since is None and _c57.inputs_ok is True) _ev57 = [e for e in _c57.events if "STALE" in e] _msgs57 = [r.getMessage() for r in _LOGREC] -_rel57 = [m for m in _msgs57 if "STALE_WITHDRAWN" in m] +_rel57 = [m for m in _msgs57 if "is used again and rechecked" in m] print(f" events: {[e.split(' ', 1)[1][:44] for e in _ev57]}") check("⚠️ A LATCH THAT LETS GO ON A TIMER AND SAYS NOTHING IS ONE NO OPERATOR " "CAN AUDIT - and this one is withdrawing a SITE STOP. Both edges reach " @@ -1592,8 +1592,9 @@ check("⚠️ A LATCH THAT LETS GO ON A TIMER AND SAYS NOTHING IS ONE NO OPERATO check("⚠️ AND THE RELEASE LINE REFUSES TO CLAIM A RECOVERY, because none has " "happened: it says in its own words that nothing has been learned about " "the register, and it prints the value the register is STILL holding", - "NOTHING HAS BEEN LEARNED ABOUT THE REGISTER" in nth(_rel57, 0) - and f"still holding {A_FROZEN_W:+.0f}" in nth(_rel57, 0)) + "used again" in nth(_rel57, 0) and "recovered" not in nth(_rel57, 0) + and f"reading {A_FROZEN_W:+.0f} W is used again and rechecked" + in nth(_rel57, 0)) # --- 10h. the two sentences, as ORDERED PAIRS (habit 14) --------------------- @@ -1602,7 +1603,8 @@ check("⚠️ AND THE RELEASE LINE REFUSES TO CLAIM A RECOVERY, because none has # could be transposed at zero bytes - 17.0 s and 250 W in the stale line's new # escape clause, and 250 W and 17.0 s again in the release note - so each is # asserted with its value embedded in its own literal position. -_stale57 = [m for m in _msgs57 if "SAFETY-37" in m] +_stale57 = [m for m in _msgs57 + if "battery power reading stopped changing" in m] print(f" escape clause: ...{nth(_stale57, 0)[-150:]}") check("⚠️ THE STALE LINE'S PROMISE IS NOW TRUE, AND IT IS PINNED AS AN ORDERED " "PAIR. It used to end 'It clears itself the moment the register reports " @@ -1610,17 +1612,16 @@ check("⚠️ THE STALE LINE'S PROMISE IS NOW TRUE, AND IT IS PINNED AS AN ORDER "before it is what stops the register being asked. The new clause names " "17 s in the TIME slot and 250 W in the POWER slot; swapped, this goes " "red", - f"failing that {BOUNDS['batt'].release_s:.0f} s after the standing " - f"command falls below {BOUNDS['batt'].move_w:.0f} W" in nth(_stale57, 0)) + f"or {BOUNDS['batt'].release_s:.0f} s after the command drops below " + f"{BOUNDS['batt'].move_w:.0f} W" in nth(_stale57, 0)) check("...and the release note names 250 W in the POWER slot and 17 s in the " "TIME slot, in that order, which is the reverse arrangement of the same " "two numbers", - f"sat below {BOUNDS['batt'].move_w:.0f} W for " + f"stayed below {BOUNDS['batt'].move_w:.0f} W for " f"{BOUNDS['batt'].release_s:.0f} s" in nth(_rel57, 0)) check("...and the 35.0 s the register is re-graded over is named in the note " "too, because it is what the operator is being told to wait out", - f"re-graded over a fresh {BOUNDS['batt'].unchanged_s:.0f} s window" - in nth(_rel57, 0)) + f"rechecked over {BOUNDS['batt'].unchanged_s:.0f} s" in nth(_rel57, 0)) check("⚠️ AND THE DIAGNOSIS HALF IS SAFETY-56'S AND HAS NOW BEEN REWRITTEN, " "WHICH IS WHAT THIS CHECK WAS FOR. It used to require 'battery-power " "register is not following its own command' to still be present, so " @@ -1632,7 +1633,7 @@ check("⚠️ AND THE DIAGNOSIS HALF IS SAFETY-56'S AND HAS NOW BEEN REWRITTEN, present(nth(_stale57, 0)) and "battery-power register is not following its own command" not in _stale57[0] - and "did not move under a command that did" in _stale57[0]) + and "stopped changing" in _stale57[0]) check("...and a re-trip's reason names the TWO durations separately, each " "beside its own value, because after a release the verdict's window and " "the register's own unchanged time are different facts", @@ -1811,7 +1812,8 @@ _S56_ACCUSATIONS = [ ("app/main.py _read_unit()", "register is not following its own command"), ("app/main.py checks()", f"{_BATT_ENT} is missing or not numeric"), ] -_log56 = [r.getMessage() for r in _LOGREC[_S56_LOG0:] if "SAFETY-37" in r.getMessage()] +_log56 = [r.getMessage() for r in _LOGREC[_S56_LOG0:] + if "battery power reading stopped changing" in r.getMessage()] def _s56_row(c): @@ -1952,8 +1954,8 @@ check("⚠️ AND THE DISCRIMINATOR IT POINTS AT EXISTS AND IS SELECTIVE, which "row below?' answers the question this one declines to answer. A row " "that pointed at a surface present in both states would be worse than " "the accusation it replaced", - any("STALE_READING" in r["text"] for r in _c56_ref.checks()) - and not any("STALE_READING" in r["text"] for r in _c56_abs.checks())) + any("stopped changing" in r["text"] for r in _c56_ref.checks()) + and not any("stopped changing" in r["text"] for r in _c56_abs.checks())) check("...and the row's wording is NOT shared with the log line's, which is a " "design choice rather than an omission: the two sentences have no clause " "in common longer than the word 'entity', because one explains a " diff --git a/goodwe_controller/test_inverter.py b/goodwe_controller/test_inverter.py index 1a14bce..4b7281e 100644 --- a/goodwe_controller/test_inverter.py +++ b/goodwe_controller/test_inverter.py @@ -832,7 +832,7 @@ check("...and the per-inverter rows now say WHAT the unit was compared " "look at P1 for a fault that is visible only on one inverter's own power " "sensor", len([r for r in _c3r.checks() if r.get("id") == "direction"]) == 2 - and all("its own power" in r["text"] for r in _c3r.checks() + and all("own power" in r["text"] for r in _c3r.checks() if r.get("id") == "direction")) # The operator's clear, which is one button and has to reach every latch. diff --git a/goodwe_controller/test_maintenance.py b/goodwe_controller/test_maintenance.py index 8b513aa..9d35cf9 100644 --- a/goodwe_controller/test_maintenance.py +++ b/goodwe_controller/test_maintenance.py @@ -1581,9 +1581,11 @@ try: _logged, _ = controller(NAMED_OPTS, store=_log_store) finally: logging.getLogger("goodwe").removeHandler(_h) -_s44_lines = [m for m in _records if "SAFETY-44" in m] +# UX-08 2d: the line is plain now, so it is found by its words, not a card id. +_s44_lines = [m for m in _records + if "which is not in the inverter list" in m] print(f" SAFETY-44 operator lines logged: {len(_s44_lines)}") -check("⭐ the repair SAYS SO, at ERROR, naming SAFETY-44 - deleting this line " +check("⭐ the repair SAYS SO, at ERROR, in one plain line - deleting this line " "left the whole suite green, and it is how an operator learns their " "latch was re-armed rather than never lost", len(_s44_lines) == 1) diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 96119ca..7459936 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -289,20 +289,66 @@ print("\n2. no notification is worded outside app/messages.py") APP = HERE / "app" -def render(node): - """A string expression as text, placeholders as {expr}; None otherwise.""" +# UX-08 2d: a refusal is counted as it is SHOWN. A placeholder that names a +# setting is expanded to the label and key `messages.setting()` prints, so +# `{S('max_w')}` counts as “Inverter rating” (max_w), three words, not one. +SETTING_CALLS = ("S", "_S", "setting", "messages.setting") +CONSTANTS = {} # module-level NAME = "text", per file, for keys + + +def _key(node): + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value + if isinstance(node, ast.Name): + return CONSTANTS.get(node.id) + return None + + +def expand_setting(node): + """The shown text of a placeholder that names a setting, else None.""" + if isinstance(node, ast.Call) and node.args: + name = ast.unparse(node.func) + if name in SETTING_CALLS: + key = _key(node.args[0]) + if key not in messages.LABELS: + return None + unit = node.args[1] if len(node.args) > 1 else None + plain = unit is None or (isinstance(unit, ast.Constant) + and not unit.value) + return messages.setting(key, "" if plain else "inverter-b") + if name == "_labels" and isinstance(node.args[0], (ast.List, ast.Tuple)): + keys = [_key(e) for e in node.args[0].elts] + if all(k in messages.LABELS for k in keys): + return " and ".join(messages.setting(k) for k in keys) + if (isinstance(node, ast.Subscript) + and ast.unparse(node.value) == "messages.LABELS"): + key = _key(node.slice) + return messages.LABELS.get(key) if key else None + return None + + +def render(node, expand=False): + """A string expression as text, placeholders as {expr}; None otherwise. + `expand` shows setting placeholders as the page shows them.""" if isinstance(node, ast.Constant) and isinstance(node.value, str): return node.value if isinstance(node, ast.JoinedStr): - return "".join(v.value if isinstance(v, ast.Constant) - else "{" + ast.unparse(v.value) + "}" for v in node.values) + out = [] + for v in node.values: + if isinstance(v, ast.Constant): + out.append(v.value) + continue + shown = expand_setting(v.value) if expand else None + out.append(shown if shown is not None + else "{" + ast.unparse(v.value) + "}") + return "".join(out) if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add): - a, b = render(node.left), render(node.right) + a, b = render(node.left, expand), render(node.right, expand) if a is None and b is None: return None return (a if a is not None else "{…}") + (b if b is not None else "{…}") if isinstance(node, ast.IfExp): - a, b = render(node.body), render(node.orelse) + a, b = render(node.body, expand), render(node.orelse, expand) if a is None and b is None: return None return (a or "") + " / " + (b or "") @@ -346,14 +392,14 @@ LIMITS = { # kind: (words, keys ok, entity ids ok) LOG_CALL = re.compile(r"(?:^|\.)(?:_LOG|log|logger|LOG)\.(warning|error|critical|exception)$") -def strings_in(node): +def strings_in(node, expand=False): """Top-level string expressions inside `node` (not their parts).""" - t = render(node) + t = render(node, expand) if t is not None: yield node, t return for child in ast.iter_child_nodes(node): - yield from strings_in(child) + yield from strings_in(child, expand) def collect(): @@ -363,6 +409,12 @@ def collect(): if f.name == "messages.py": continue tree = ast.parse(f.read_text(encoding="utf-8")) + CONSTANTS.clear() + CONSTANTS.update({t.id: n.value.value for n in tree.body + if isinstance(n, ast.Assign) + and isinstance(n.value, ast.Constant) + and isinstance(n.value.value, str) + for t in n.targets if isinstance(t, ast.Name)}) for node in ast.walk(tree): if isinstance(node, ast.Dict): for k, v in zip(node.keys, node.values): @@ -387,24 +439,26 @@ def collect(): out.append(("log", f"{f.name}:{n.lineno}", t)) elif re.search(r"problems\.(append|extend)$", name): for a in node.args: - for n, t in strings_in(a): + for n, t in strings_in(a, expand=True): if len(words(t)) > 1: out.append(("refusal", f"{f.name}:{n.lineno}", t)) - tr = TL.parse_translation_file(HERE / "translations" / "en.yaml") + # UX-08 2d: the Dutch option texts are held to the same length. + for lang in ("en", "nl"): + tr = TL.parse_translation_file(HERE / "translations" / f"{lang}.yaml") - def walk(conf, path): - for key, v in (conf or {}).items(): - if not isinstance(v, dict): - continue - if isinstance(v.get("name"), str): - out.append(("option-name", f"en.yaml:{path}{key}", - v["name"].split("·")[-1].strip())) - if isinstance(v.get("description"), str): - out.append(("option-desc", f"en.yaml:{path}{key}", - v["description"])) - if isinstance(v.get("fields"), dict): - walk(v["fields"], f"{path}{key}.") - walk(tr.get("configuration"), "") + def walk(conf, path): + for key, v in (conf or {}).items(): + if not isinstance(v, dict): + continue + if isinstance(v.get("name"), str): + out.append(("option-name", f"{lang}.yaml:{path}{key}", + v["name"].split("·")[-1].strip())) + if isinstance(v.get("description"), str): + out.append(("option-desc", f"{lang}.yaml:{path}{key}", + v["description"])) + if isinstance(v.get("fields"), dict): + walk(v["fields"], f"{path}{key}.") + walk(tr.get("configuration"), "") return out @@ -413,7 +467,7 @@ def problems_of(kind, text): p = [] if len(words(text)) > lim: p.append(f"over {lim} words ({len(words(text))})") - if kind != "log" and ";" in text: # logs are phase 2d + if ";" in text: p.append("semicolon") return p + text_problems(text, keys=keys, entities=ents) @@ -426,7 +480,7 @@ ALLOW_FILE = HERE / "ux08_allowlist.txt" # The allowlist may never grow. The test demands the list be exactly this long, # so deleting lines means lowering this number in the same change, and adding # one means raising it where a reviewer sees it. -ALLOWLIST_MAX = 43 +ALLOWLIST_MAX = 0 def read_allowlist(path): @@ -491,6 +545,30 @@ _own_banner = {"row_direction_trip", "row_site_direction_trip", "row_circulating_trip", "row_peak_reserve", "row_power_too_high"} _long = [t for fn, c, t in STATUS if c == messages.RED and fn not in _own_banner and len(words(messages.banner_not_ready({"text": t}))) > 12] +# The hint under the buttons (UX-08 2d): the last event in plain words, one +# per key of messages.HINTS, held to the rule for a green row. +for key, text in messages.hint_samples(): + p = row_problems(messages.GREEN, text) + check(f"hint {text!r}{' - ' + '; '.join(p) if p else ''}", not p) +_calls, _bare = 0, [] +for f in sorted(APP.glob("*.py")): + for node in ast.walk(ast.parse(f.read_text(encoding="utf-8"))): + if (isinstance(node, ast.Call) + and ast.unparse(node.func).endswith("log_event")): + _calls += 1 + h = next((k.value for k in node.keywords if k.arg == "hint"), None) + if not (isinstance(h, ast.Call) + and ast.unparse(h.func) in ("messages.hint", "hint")): + _bare.append(f"{f.name}:{node.lineno}") +check(f"every event the add-on records gives the page its plain words, from " + f"messages.hint() ({_calls} calls, without: {_bare})", + _calls >= 40 and not _bare) +_raw = ("OUTPUT_CLAMP", "BUG SIGNAL", "FAILSAFE", "SIGN_DISAGREEMENT", + "ALLOCATOR", "UNMET", "ARBITER", "PEAK GUARD") +check("no hint carries the raw event codes the page used to show", + not [t for _k, t in messages.hint_samples() + if any(r in t for r in _raw)]) + check(f"every other red row makes a 'Not ready' banner of at most 12 words " f"(too long: {_long})", not _long) @@ -555,6 +633,79 @@ check("...and a refusal quotes the label and then the key, so the config " "panel still files it under that setting", messages.setting("max_w", "inverter-b") == "“Inverter rating” for inverter-b (inverters.max_w)") +# UX-08 2d: the refusals as the validator SHOWS them. The scan above expands +# setting labels in a template, but a reason that carries a parser's error +# (`{e}`) is only as long as that error, so the long ones found by the 2c test +# are driven for real here and held to the same 30 words. +from app import custom_formula as _cf # noqa: E402 +from app.validate import validate_startup_config # noqa: E402 + +_BASE = {"setpoint_entity": "number.goodwe_setpoint", "max_w": 2000, + "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", + "meter_source": "off", "maintenance_charge_w": 2000, + "maintenance_discharge_w": 2000} +_CARD = _cf._LEGS["price_formula"].example.replace("15.55", "15.05") +_TABLE = ('{"periods":[{"name":"day","from":"07:00","to":"22:00","days":' + '"mon-fri","eur_per_kwh":0.1},{"name":"night","from":"22:00","to":' + '"07:00","days":"mon-fri","eur_per_kwh":0.08},{"name":"night",' + '"from":"00:00","to":"24:00","days":"sat,sun","eur_per_kwh":0.08}]}') +_ROSTER = {k: v for k, v in _BASE.items() + if k not in ("setpoint_entity", "soc_entity", "batt_entity", + "max_w")} +_ROSTER["inverters"] = [ + dict(name=n, setpoint_entity=f"number.sp_{n[-1]}", max_w=w, + soc_entity=f"sensor.soc_{n[-1]}", batt_entity=f"sensor.batt_{n[-1]}", + bms_soc_floor=10) + for n, w in (("inverter-a", 2000), ("inverter-b", 200))] +_DRIVEN = { + "formula card": dict(_BASE, price_provider="custom_formula", + price_formula=_CARD), + "formula not valid": dict(_BASE, price_provider="custom_formula", + price_formula='{"index": "epex_be"} x'), + "injection card": dict(_BASE, price_export_formula=_CARD), + "roster thresholds": dict(_ROSTER, maintenance_charge_w=100, + maintenance_discharge_w=100), + "levies table and flat": dict(_BASE, price_taxes_profile=_TABLE, + price_taxes_eur_kwh=0.1198), + "feed and entities": dict(_BASE, price_provider="generic_dayahead", + price_now_entity="sensor.now", + price_avg_entity="sensor.avg"), + "fixed tariff and entities": dict(_BASE, static_profile=_TABLE, + price_now_entity="sensor.now", + price_avg_entity="sensor.avg"), + "fixed tariff not valid": dict(_BASE, static_profile='{"periods": []} x'), +} +_LEAKS = ("c_eur_per_kwh", "vat_pct", "its own card", "line 1 column", + "None", "JSON", "one you do not use") +_shown, _long, _leaky = [], [], [] +for _name, _o in _DRIVEN.items(): + _ps = validate_startup_config(_o, -5000, 5000) + _shown.append((_name, len(_ps))) + _long += [f"{_name}: {len(words(t))} words: {t}" for t in _ps + if len(words(t)) > 30] + _leaky += [f"{_name}: {t}" for t in _ps if any(x in t for x in _LEAKS)] +check(f"every driven case is refused ({_shown})", + all(n >= 1 for _n, n in _shown) + and dict(_shown)["roster thresholds"] >= 2) +check(f"...and every refusal, as SHOWN, is at most 30 words (too long: " + f"{_long})", not _long) +check(f"...and shows no parser text, file units or Python's None (found: " + f"{_leaky})", not _leaky) + +# The config panel files a reason beside every setting whose key it names, but +# `inverters.max_w` names a setting of one inverter in the list, not the flat +# `max_w` (UX-08 2d, from the 2c test). +from app.configui import problems_by_field # noqa: E402 +_by, _un = problems_by_field( + ["“Inverter rating” for inverter-b (inverters.max_w) is 200 W.", + "“Inverter rating” (max_w) is 0."], ["max_w", "inverters"]) +check("a roster refusal shows beside `inverters` only, and a flat one beside " + f"`max_w` ({ {k: len(v) for k, v in _by.items()} })", + _by.get("inverters") == [ + "“Inverter rating” for inverter-b (inverters.max_w) is 200 W."] + and _by.get("max_w") == ["“Inverter rating” (max_w) is 0."] + and not _un) + print(f"CI: UX-08 allowlist {len(allow)} entries " + ", ".join(f"{k} {sum(1 for x in allow if x.startswith(k + ' '))}" for k in LIMITS)) diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 08e5bc5..187e5ad 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -5932,10 +5932,12 @@ _S38_CEIL_W, _S38_CEIL_FROM = quarter_ceiling_w(CAP_W, obs_hi) _S38_IDLE = decide(_S38_PROJ, batt_w=0.0, cap_w=CAP_W, reading=obs_hi, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) -_S38_LITERAL = (f"quarter projects {_S38_PROJ.projected_w:.0f} W under a " - f"{_S38_CEIL_W:.0f} W ceiling") -_S38_SWAPPED = (f"quarter projects {_S38_CEIL_W:.0f} W under a " - f"{_S38_PROJ.projected_w:.0f} W ceiling") +# UX-08 2d: the row is in plain words now, and the pair is still ordered. +from app import messages as _msg38 # noqa: E402 +_S38_LITERAL = (f"heading for {_msg38.watts(_S38_PROJ.projected_w)}, under " + f"this month's {_msg38.watts(_S38_CEIL_W)} peak") +_S38_SWAPPED = (f"heading for {_msg38.watts(_S38_CEIL_W)}, under " + f"this month's {_msg38.watts(_S38_PROJ.projected_w)} peak") print(f" projection {_S38_PROJ.projected_w:.0f} W against a " f"{_S38_CEIL_W:.0f} W ceiling ({_S38_CEIL_FROM})") print(f" {_S38_IDLE.explain()!r}") @@ -5958,7 +5960,8 @@ check("...and the TRANSPOSED sentence is NOT what it says, so the check above " _S38_SWAPPED not in _S38_IDLE.explain()) check("...and the row still names WHERE the ceiling came from, which is the " "difference between a cap an operator set and a peak the month already " - "banked", f"ceiling ({CEILING_MONTH_PEAK})" in _S38_IDLE.explain()) + "banked", "under this month's" in _S38_IDLE.explain() + and "peak limit" not in _S38_IDLE.explain()) # THE SHIPPED CONSUMER. `explain()` is not read by anybody until main.py prints # it, and round 3's lesson is that the pin belongs on the CALL SITE: the status diff --git a/goodwe_controller/test_price.py b/goodwe_controller/test_price.py index 041f89e..5485d06 100644 --- a/goodwe_controller/test_price.py +++ b/goodwe_controller/test_price.py @@ -2189,7 +2189,7 @@ _p = validate_startup_config( check("a provider AND the Home Assistant price entities is refused - two price " "sources on one site", len(_p) == 1) check("...and the message says which one actually wins", - why(_p, "are also set and would win")) + why(_p, "would win over it")) # TARIFF-03 added a second source with the same silent-loser shape. _ps = validate_startup_config( vbase(static_profile='{"periods": [{"from":"00:00","to":"24:00",' @@ -3427,8 +3427,8 @@ check(f"network charges folded into `offset` move the card's own price to " isinstance(_double_price, float) and abs(_double_price - 15.55) > 10) check(f"...and it is refused, by the CARD rule, naming the discrepancy and " f"the network-charge cause ({_double[:60]!r})", - "does not match its own card" in _double and "the card says" in _double - and "(price_taxes_eur_kwh), not in the offset" in _double) + "the card says" in _double + and "network charges are not in the offset" in _double) _CORRUPTIONS = { "VAT left out (vat_pct 0)": spoilt(vat_pct=0), @@ -3447,7 +3447,7 @@ for _name, _blob in sorted(_CORRUPTIONS.items()): _why = refusal(_blob) check(f"{_name}: refused, and by the CARD rule rather than by another one " f"({_why[:48]!r})", - "does not match its own card" in _why and "the card says" in _why) + "the card says" in _why) # ⚠️ THE TOLERANCE IS A REAL EDGE AND IT IS GRADED FROM BOTH SIDES, or # "within 0.01" and "within anything" would be the same check. @@ -3459,7 +3459,7 @@ _outside = refusal(spoilt(card_expect_incl_vat=round( + CARD_TOLERANCE * 2.0, 6))) check(f"half a tolerance out passes and twice a tolerance out does not, so " f"{CARD_TOLERANCE} is the number being enforced rather than a shape", - _inside == "" and "does not match its own card" in _outside) + _inside == "" and "the card says" in _outside) # A card that is absent is refused, and NOT by the generic unknown-field rule. check(f"a formula with NO card block is refused, and the message says why the " @@ -3851,12 +3851,12 @@ check("a formula that does not reproduce its card is refused AT STARTUP, " why(validate_startup_config( vbase(price_provider="custom_formula", price_formula=json.dumps(spoilt(offset=13.0))), - -5000, 5000), "does not match its own card")) + -5000, 5000), "the card says")) check("...and a formula that is not JSON at all is refused with the shape it " "wanted, rather than with a traceback", why(validate_startup_config( vbase(price_provider="custom_formula", price_formula="0.102*spot+1"), - -5000, 5000), "not valid JSON")) + -5000, 5000), "price_formula is not valid near character")) check(f"...and a card outside the plausible band is refused too, WITH THE " f"SHIPPED taxes in place - the flat " f"{PRICE_OPTION_DEFAULTS['price_taxes_eur_kwh']} must not be able to " @@ -4100,13 +4100,14 @@ def _t11_render(over=None, *, plan=None, plan_age_s=0.0, soc=55.0, cycles=1, # row that is WRONG IN EXACTLY THE WAY THE DEFECT WAS, and both answers are # asserted. _T11_SLOTS = { - "points": r"(\d+) points over \d+ h", - "hours": r"\d+ points over (\d+) h", - "firm": r"(\d+) firm / \d+ carried", - "carried": r"\d+ firm / (\d+) carried", - "horizon": r"for a (\d+) h horizon", - "age_s": r"fetched (\d+) s ago", - "spacings": r"([\d+]+) s spacing", + # UX-08 2d: the row is in plain words; every figure keeps its own slot. + "points": r"(\d+) prices over \d+ hours", + "hours": r"\d+ prices over (\d+) hours", + "firm": r"(\d+) published and \d+ estimated", + "carried": r"\d+ published and (\d+) estimated", + "horizon": r"for (\d+) hours ahead", + "age_s": r"Price plan from (\d+) s ago", + "spacings": r"([\d+]+) s apart", # ⚠️ THE *Arbitrage* ROW'S OWN AGE SLOT, and it is deliberately the same # pattern for "decided N s ago" and "the last one was taken N s ago" - # WHICH of the two sentences was rendered is graded by inequality below, @@ -4144,13 +4145,13 @@ def _slot(row, name): return derived(_get) -_T11_GOOD = ("x (recomputed this tick); provider plan fetched 7 s ago for a " - "48 h horizon: dynamic_dayahead from generic_dayahead, " - "132 points over 33 h, 36 firm / 96 carried, 900+3600 s spacing") -_T11_SHIPPED_DEFECT = ("x (recomputed this tick); provider plan fetched 7 s " - "ago for a 48 h horizon: dynamic_dayahead from " - "generic_dayahead, 132 points over 132 h, " - "96 firm / 36 carried, 900+3600 s spacing") +_T11_GOOD = ("x. Price plan from 7 s ago, for 48 hours ahead: day-ahead " + "prices from the price feed, 132 prices over 33 hours, " + "36 published and 96 estimated, 900+3600 s apart") +_T11_SHIPPED_DEFECT = ("x. Price plan from 7 s ago, for 48 hours ahead: " + "day-ahead prices from the price feed, 132 prices over " + "132 hours, 96 published and 36 estimated, 900+3600 s " + "apart") # The slots divide into the ones a *Tariff*/​*Arbitrage* ROW carries and the # ones a REFUSAL sentence carries; each group is calibrated against its own # well-formed example, because a slot asked of the wrong kind of sentence is @@ -4399,11 +4400,11 @@ check(f"AC, AND THE WHOLE OF DEFECT 4: 'trading is off' and 'trading is on " f"in the options blob", _T11_OFF[0]["Arbitrage"] != _T11_ON_HELD[0]["Arbitrage"]) check(f"...and the armed-but-held row carries the CONTROL LOOP'S OWN REASON " - f"({_T11_ON_HELD[1].reason!r}), so the operator is told which input is " + f"({_T11_ON_HELD[1].why_words!r}), so the operator is told which input is " f"missing rather than being sent to look at a switch that is already on. " f"The reason comes from main.py, not from this file", - _T11_ON_HELD[1].reason - and _T11_ON_HELD[1].reason in _T11_ON_HELD[0]["Arbitrage"]) + _T11_ON_HELD[1].why_words + and _T11_ON_HELD[1].why_words in _T11_ON_HELD[0]["Arbitrage"]) check(f"...and a cycle that DID reach the step renders the strategy's own " f"sentence - {_T11_ON_OK[1].arb.explain()[:50]!r} - rather than a " f"re-derivation of it, which is the guarantee OPT-04 put on this row and " @@ -4449,10 +4450,10 @@ check(f"DRIVEN, no clock touched: a decision stands " and _T11_DROP_STALE is True and _T11_ON_DROPPED[0]["Arbitrage"] != _T11_ON_OK[0]["Arbitrage"]) check(f"...and it names the reason the cycle stopped " - f"({_T11_ON_DROPPED[1].reason!r}) beside the age of the decision it is " + f"({_T11_ON_DROPPED[1].why_words!r}) beside the age of the decision it is " f"still showing, so 'the strategy decided this' and 'the strategy last " f"decided this' are not one sentence", - _T11_ON_DROPPED[1].reason in _T11_ON_DROPPED[0]["Arbitrage"] + _T11_ON_DROPPED[1].why_words in _T11_ON_DROPPED[0]["Arbitrage"] and isinstance(_slot(_T11_ON_DROPPED[0]["Arbitrage"], "arb_age_s"), int)) check("...and `main.py`'s 'if and only if' is graded as BEHAVIOUR rather than " @@ -4585,8 +4586,8 @@ check(f"...and the row an operator reads names the SPACING that makes those " check("...and this is the same wording FCST-04's *Price history* row already " "used, so the two rows describing the same feed can be compared rather " "than being two conventions on one page", - "points over" in _T11_E2E_ROW - and "points over" in ("" if isinstance(_T11_E2E, _Raised) + "prices over" in _T11_E2E_ROW + and "prices over" in ("" if isinstance(_T11_E2E, _Raised) else _T11_E2E["Price history"])) @@ -5360,14 +5361,14 @@ _T16_DIFFER = [ # UX-08 2c: a negative factor gets one sentence on both legs now ("put the # minus sign on the offset"), so it left this table. ("a card miss -> what else to check on THIS leg", - spoilt(factor=0.120), "(price_taxes_eur_kwh), not in the offset", - "vat_pct is 0 for injection"), + spoilt(factor=0.120), "network charges are not in the offset", + "the VAT is 0 for injection"), ("invalid JSON -> WHEN this option is read at all, which is not the " "same answer on the two legs: `price_formula` decides nothing unless " "price_provider is 'custom_formula', and the injection leg is read " "whatever the consumption provider is", - "{not json", "(price_provider) is 'custom_formula'", - "used whatever the price source is"), + "{not json", "unless “Dynamic price source” is 'custom_formula'", + "only if your injection price follows the market"), ] for _what, _blob, _cons_mark, _inj_mark in _T16_DIFFER: _a, _b = ((_reason(lambda b=_blob: parse_price_formula(b)), @@ -5549,7 +5550,7 @@ check(f"a card block ON THIS LEG is graded by the same rung at the same " f"15.55) is refused, naming the option the operator typed " f"({_T16_SPOILT_CARD[:64]!r})", _T16_WITH_CARD == "" - and "does not match its own card" in _T16_SPOILT_CARD + and "the card says" in _T16_SPOILT_CARD and _T16_SPOILT_CARD.startswith(EXPORT_FORMULA_OPTION)) check(f"...and half a tolerance out still passes, so {CARD_TOLERANCE} is " f"enforced on this leg too rather than 'something'", diff --git a/goodwe_controller/test_price_history.py b/goodwe_controller/test_price_history.py index 488731d..d1e74c4 100644 --- a/goodwe_controller/test_price_history.py +++ b/goodwe_controller/test_price_history.py @@ -1328,7 +1328,7 @@ check(f"...and a store holding a day names the DATE, the POINT COUNT and the " f"HOUR COUNT {words_of(_h_words)!r} - 'a cache exists' and 'the cache " f"holds yesterday, all 24 hours of it' are different facts, and only " f"the second says the horizon will be full tomorrow morning", - words_of(_h_words) == f"{YDAY_D} (24 points over 24 h)") + words_of(_h_words) == f"{YDAY_D} (24 prices over 24 hours)") # ⚠️ AND THE TWO NUMBERS ARE NOT THE SAME NUMBER - FCST-05's LOW. The row # shipped as `f"{d} ({_n_points(rec)} h)"`, which counts POINTS and prints them @@ -1362,11 +1362,11 @@ check(f"...and the row reports BOTH, each under its own unit: {_qw!r}. " f"A day of 96 quarter-hourly prints is 96 points over 24 h, and the " f"figure that says whether tomorrow's fill has a whole day to carry is " f"the HOUR one", - _qw == f"{YDAY_D} (96 points over 24 h)") + _qw == f"{YDAY_D} (96 prices over 24 hours)") check(f"...and specifically the row does NOT say '96 h' {_qw!r} - a point " f"count wearing the hour's name is H1's defect, and this row is where " f"an operator would have read it", - isinstance(_qw, str) and "(96 h)" not in _qw and " (96 points " in _qw) + isinstance(_qw, str) and "(96 h)" not in _qw and " (96 prices " in _qw) check(f"a file that only PARTLY loaded says so in the row {_w14!r}, or the " f"days it dropped read as days that were simply never written", isinstance(_w14, str) and (_h14.last_error or "") in _w14 @@ -1546,7 +1546,7 @@ for _shape, _bad in _BAD_STARTS: f"{_wload!r}: ONE point held, and the row that is not a point named " f"rather than counted", isinstance(_wload, str) - and _wload.startswith(f"{TODAY_D} (1 point over 1 h) [") + and _wload.startswith(f"{TODAY_D} (1 price over 1 hour) [") and "1 malformed point row(s) in" in _wload) # ⚠️ AND THE TWO NOTES ARE GRADED APART, BECAUSE THEY MASK EACH OTHER # OTHERWISE (MUTATION.md TEST-16). `_usable_days()` records what it FOUND @@ -1577,7 +1577,7 @@ for _shape, _bad in _BAD_STARTS: check(f"...and the store reopened from that file is CLEAN: the whole day " f"held and nothing to report {words_of(_hM2)!r}, so the note clears " f"itself rather than becoming permanent furniture", - words_of(_hM2) == f"{TODAY_D} ({_want} points over {_want} h)" + words_of(_hM2) == f"{TODAY_D} ({_want} prices over {_want} hours)" and _hM2.last_error is None) # ...and the shipped path, end to end, through the caller that catches @@ -1641,7 +1641,7 @@ print("5d. FCST-06 - the OTHER way to be a store that cannot persist") # read-only and again on a full tmpfs: # # last_error = 'could not write ([Errno 30] Read-only file system)' -# words = '2026-01-14 (24 points over 24 h); 2026-01-15 (24 points +# words = '2026-01-14 (24 prices over 24 hours); 2026-01-15 (24 points # over 24 h) [could not write (...)]' # yesterday()= series, 24 points # ON DISK = {} <- and gone on the next restart diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 20f282c..6f73277 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -516,7 +516,7 @@ check("⚠️ AN UNSET OPTION ADDS NO STATUS ROW AND NO PAGE ROW - not a caution "input; this is instrumentation and a permanent caution on every install " "that never asked for it is the warning spam the card forbids", not pv_rows(c_off) - and not [r for r in page_rows(c_off) if r[0] == "PV"]) + and not [r for r in page_rows(c_off) if r[0] == "Solar production"]) check("...and the whole row list is otherwise the same length, so nothing else " "moved either", len(_on_rows) == len(_off_rows) + 1) _pv_row = [r["text"] for r in pv_rows(c_on)] @@ -527,7 +527,7 @@ check("a good read says the watts, as a green row, and names no entity id", _pv_row == [f"Solar production: {messages.signed_watts(3210)}"] and "sensor." not in _pv_row[0] and pv_rows(c_on)[0]["ok"] is True - and ("PV", "3 210 W") in page_rows(c_on)) + and ("Solar production", "3 210 W") in page_rows(c_on)) c_bad, _, _ = run(cycles=1, states=[state("1234", "%")], **PV_ON) _bad_row = pv_rows(c_bad) @@ -552,7 +552,7 @@ check("⭐ ...and it is a CAUTION, never a `bad` row: `status_payload()` builds and c_bad.status_payload()["banner"] == c_off.status_payload()["banner"]) check("...and the page row renders an absence as an em dash, not as 0 W", - ("PV", "—") in page_rows(c_bad)) + ("Solar production", "—") in page_rows(c_bad)) # ============================================================================== @@ -936,7 +936,7 @@ print(f" {_many_row}") check("a healthy roster says the SITE total and how many sources it came from", _many_row == [f"Solar production: {messages.signed_watts(3750)} from 3 " f"sources"] - and ("PV", "3 750 W") in page_rows(_c_many)) + and ("Solar production", "3 750 W") in page_rows(_c_many)) _c_gap, _, _ = run(cycles=1, by_entity=HOLES[E2][0], **PV_MANY) _gap_row = pv_rows(_c_gap) @@ -960,8 +960,8 @@ check("⭐ ...and it is a CAUTION, never a `bad` row, at a roster exactly as at == c_off.status_payload()["banner"]) check("...and the page row is an em dash, not a smaller number: the one row an " "operator glances at cannot show a partial total either", - ("PV", "—") in page_rows(_c_gap) - and ("PV", "3 300 W") not in page_rows(_c_gap)) + ("Solar production", "—") in page_rows(_c_gap) + and ("Solar production", "3 300 W") not in page_rows(_c_gap)) # ⚠️ THE ACCEPTANCE CRITERION THE REST OF THIS FILE CANNOT STATE: at a roster of # ONE the surfaces are 0.11.0's, character for character. `c_on` above is the @@ -978,7 +978,7 @@ check("⭐ ONE ENTITY IS ONE PATH, however it was declared: the status " == [r["text"] for r in pv_rows(c_on)] == [f"Solar production: {messages.signed_watts(3210)}"] and page_rows(_c_one_new)[[r[0] for r in page_rows(_c_one_new)] - .index("PV")] == ("PV", "3 210 W")) + .index("Solar production")] == ("Solar production", "3 210 W")) check("...and a refused read at a roster of one is the one-sensor refusal " "too, not the roster one - `no reading, <reason>`", [r["text"] for r in pv_rows(run(cycles=1, pv_entities=[E1], @@ -1007,7 +1007,7 @@ check("...and that caution appears ONLY when both are set - not on the 0.11.0 " check("...and an install with NO PV roster still adds no row of any kind - the " "whole of TEL-12 is invisible at the shipped default", not pv_rows(c_off) - and not [r for r in page_rows(c_off) if r[0] == "PV"] + and not [r for r in page_rows(c_off) if r[0] == "Solar production"] and len(rows_of(_c_many)) == len(rows_of(c_off)) + 1 and run(cycles=1)[1].state_calls == [] and run(cycles=1, pv_entities=[])[1].state_calls == [] @@ -1106,7 +1106,7 @@ check("the status row prints the total AFTER the sign", _mix_row == [f"Solar production: {messages.signed_watts(MIX_TOTAL)} " f"from 3 sources"]) check("...and the page's PV row is the corrected total", - ("PV", "3 270 W") in page_rows(_c_mix)) + ("Solar production", "3 270 W") in page_rows(_c_mix)) _c_hole_f, _, _ = run(cycles=1, by_entity=dict(MIX, **{E1: [None]}), **PV_FLIP) check("a holed roster with a flipped member names the missing source, not " "the flipped one", diff --git a/goodwe_controller/test_selfconfig.py b/goodwe_controller/test_selfconfig.py index e73c5ad..10d6608 100644 --- a/goodwe_controller/test_selfconfig.py +++ b/goodwe_controller/test_selfconfig.py @@ -172,7 +172,7 @@ class FakeController: self.inverters = [] self.events = [] - def log_event(self, text): + def log_event(self, text, hint=None): self.events.append(text) def status_payload(self): @@ -552,7 +552,7 @@ class H: async def limits(self, e): return (None, None, None) class C: o = json.loads(os.environ["OPTS"]); hass = H(); inverters = [] - def log_event(self, t): pass + def log_event(self, t, hint=None): pass def status_payload(self): return {} async def handle_action(self, w): raise AssertionError("no") diff --git a/goodwe_controller/test_static_tariff.py b/goodwe_controller/test_static_tariff.py index 0abe17b..cc9f2d1 100644 --- a/goodwe_controller/test_static_tariff.py +++ b/goodwe_controller/test_static_tariff.py @@ -527,7 +527,7 @@ check("...and arbitrage is refused, per §11.4", _none.arbitrage(peak_guard_active=False, min_spread_eur_kwh=0.0, uncertainty=frozenset()).kind == "refused" and arbitrage_allowed(_none.read) is False) check("...and static_status() says so in words rather than reporting a price", - static_status(opts(None), THU) == (False, "no static profile")) + static_status(opts(None), THU) == (False, "No fixed tariff set")) # ⚠️ THE TILING REFUSAL. An uncovered hour has no price and the only ways to # serve it are to invent one or to fail when the clock reaches it. diff --git a/goodwe_controller/test_tariff.py b/goodwe_controller/test_tariff.py index 981412f..854a85a 100644 --- a/goodwe_controller/test_tariff.py +++ b/goodwe_controller/test_tariff.py @@ -116,6 +116,7 @@ from pathlib import Path from named_absence import given, nth, present +from app import messages from app.main import Controller from app.p1 import P1Ingest, QuarterAverager, QUARTER_S, make_sample, split_signed from app.tariff import ( @@ -977,16 +978,22 @@ check("...and the peak is unchanged by the repeat", # quarter in August, so every check below passed in August and failed from # 2026-09-01 - on a commit nobody had touched. The suite must grade the month # it created, not the month the machine happens to be running in. -rows = [r for r in c.checks(when=B) if "capacity-tariff" in r["text"] or "peak" in r["text"]] -peak_rows = [r for r in rows if "peak" in r["text"] and "quarter(s) banked" in r["text"]] +# UX-08 2d: the rows are in plain words and are found by their `id`. The peak +# and the coverage figure (TARIFF-13) are two rows now, one sentence each. +rows = c.checks(when=B) +peak_rows = [r for r in rows if r.get("id") == "month_peak"] +cov_rows = [r for r in rows if r.get("id") == "periods_measured"] print(" status row: " + (peak_rows[0]["text"] if peak_rows else "(none)")) -check("the status page carries exactly one capacity-tariff peak row", - len(peak_rows) == 1) -check("...naming the peak, the soft limit and a coverage figure, all derived " - "from the controller that was actually built", - bool(peak_rows) and "4998 W" in peak_rows[0]["text"] - and f"{given(SHIPPED_CAP_W):.0f} W soft limit" in peak_rows[0]["text"] - and "quarter(s) banked" in peak_rows[0]["text"]) +print(" status row: " + (cov_rows[0]["text"] if cov_rows else "(none)")) +check("the status page carries exactly one capacity-tariff peak row, and one " + "coverage row beside it", + len(peak_rows) == 1 and len(cov_rows) == 1) +check("...naming the peak and its share of the peak limit, and the coverage " + "figure, all derived from the controller that was actually built", + bool(peak_rows) and "Month peak: 4 998 W on " in peak_rows[0]["text"] + and f"{4998 / given(SHIPPED_CAP_W) * 100:.0f} % of the peak limit" + in peak_rows[0]["text"] + and bool(cov_rows) and "periods measured" in cov_rows[0]["text"]) # ⚠️ AND THE COVERAGE FIGURE IN THAT ROW IS SCOPED TO THE LIVE BILLING MONTH, # NOT TO `when` - TARIFF-13, and it is a KNOWN GAP stated rather than rounded @@ -1007,22 +1014,23 @@ print(f" the row read at {month_key(B)} carries the tally for " check("the row's coverage figure is the LIVE month's tally - graded against a " "row count taken straight from quarter_blocks, so this pins the gap " "rather than restating the property that produces it", - bool(peak_rows) - and f", {_live_rows} quarter(s) banked" in peak_rows[0]["text"]) + bool(cov_rows) + and cov_rows[0]["text"].endswith(f"this month: {_live_rows}")) check("...and it is FLAGGED, because 4998 W is over §9.1's 80 % warning point " f"on a {given(SHIPPED_CAP_W):.0f} W limit", bool(peak_rows) and not peak_rows[0]["ok"] and peak_rows[0]["warn"]) # The half that matters: the same page with a store that cannot answer. c2 = built(TMP / "no-such-dir" / "nope.db") -u_rows = [r for r in c2.checks(when=B) if "capacity-tariff peak" in r["text"]] +u_rows = [r for r in c2.checks(when=B) if r.get("id") == "month_peak"] print(" status row (unreadable store): " + (u_rows[0]["text"] if u_rows else "(none)")) -check("an unreadable store gets its OWN row, saying UNREADABLE", len(u_rows) == 1) +check("an unreadable store gets its OWN row, saying it cannot be read", + len(u_rows) == 1) check("...and it does NOT read as a quiet month at 0 W - without this, a broken " "instrument looks exactly like a month with no peak", - bool(u_rows) and "UNREADABLE" in u_rows[0]["text"] - and "0 %" not in u_rows[0]["text"] and u_rows[0]["warn"]) + bool(u_rows) and "cannot be read" in u_rows[0]["text"] + and "%" not in u_rows[0]["text"] and u_rows[0]["warn"]) check("...and the healthy row and the unreadable row are different text", bool(u_rows) and bool(peak_rows) and u_rows[0]["text"] != peak_rows[0]["text"]) @@ -1040,7 +1048,7 @@ check("...and the healthy row and the unreadable row are different text", # (That asymmetry in the row's own text is worth a look on its own; it is what # made the original filter brittle. Not changed here - it is product text with # other suites reading it.) -_peak_rows = lambda rows: [r for r in rows if "quarter(s) banked" in r["text"]] +_peak_rows = lambda rows: [r for r in rows if r.get("id") == "month_peak"] _later = B + timedelta(days=45) # same fixture, a later billing month _other_peak = _peak_rows(c.checks(when=_later)) @@ -1048,12 +1056,12 @@ print(f" the SAME controller read at {_later.date()}: " + (_other_peak[0]["text"] if _other_peak else "(no peak row)")) check("asked for a LATER month, the same controller reports that month's " "absence of a quarter, not August's 4998 W - the row follows `when`", - bool(_other_peak) and "4998 W" not in _other_peak[0]["text"] - and "no completed quarter recorded yet" in _other_peak[0]["text"]) + bool(_other_peak) and "4 998 W" not in _other_peak[0]["text"] + and "none recorded yet" in _other_peak[0]["text"]) check("...and that is NO_RECORD, distinguishable from BOTH an observed peak and " "an unreadable store - a month with no quarter is not a broken instrument", bool(_other_peak) and bool(peak_rows) - and "UNREADABLE" not in _other_peak[0]["text"] + and "cannot be read" not in _other_peak[0]["text"] and _other_peak[0]["text"] != peak_rows[0]["text"]) check("...and it is not FLAGGED, because an empty month is not an exceedance", bool(_other_peak) and _other_peak[0]["ok"] and not _other_peak[0]["warn"]) @@ -1076,7 +1084,7 @@ check("calling checks() with NO argument still reads the month being billed " bool(_now_peak) and (bool(peak_rows) and _now_peak[0]["text"] == peak_rows[0]["text"] if _today_is_fixture_month - else "no completed quarter recorded yet" + else "none recorded yet" in _now_peak[0]["text"])) # THE MEASUREMENT IS OF DELIVERED POWER (SAFETY-20). Graded on the parsed @@ -1253,21 +1261,25 @@ for _q in range(_N13): # Ground truth from the OTHER tier, which the tracker did not supply - the count # under test must be graded against something that is not itself (habit 2). _truth_before = len(c13.peak.store.blocks_in(_mon13)) +_cov_row = lambda c: [r for r in c.checks() + if r.get("id") == "periods_measured"][0]["text"] _row_before = _peak_rows(c13.checks())[0]["text"] -print(" before restart: " + _row_before) +_cov_before = _cov_row(c13) +print(" before restart: " + _row_before + " / " + _cov_before) check(f"precondition: the fixture banked {_N13} quarters in {_mon13}, so a " f"count of 0 and a count of the truth are different numbers", _truth_before == _N13 and _N13 > 1) check(f"...and the row says so before the restart", - f"{_N13} quarter(s) banked" in _row_before) + _cov_before.endswith(f"this month: {_N13}")) c13.peak.store.close() # THE RESTART. c13b = built(_T13) _row_after = _peak_rows(c13b.checks())[0]["text"] +_cov_after = _cov_row(c13b) _truth_after = len(c13b.peak.store.blocks_in(_mon13)) -print(" after restart: " + _row_after) +print(" after restart: " + _row_after + " / " + _cov_after) print(f" rows in quarter_blocks: {_truth_before} before, " f"{_truth_after} after; the restarted tracker has banked " f"{len(c13b.peak._seen)} block(s) of its own through sync()") @@ -1279,16 +1291,17 @@ check("precondition: the second Controller is a REAL restart - it shares no " check("the peak and its attributed quarter survive the restart - the durable " "half, asserted so that the coverage claim below is not graded against a " "reading that had already collapsed", - _row_before.split(" - ")[0] == _row_after.split(" - ")[0] - and f"{_W13:.0f} W" in _row_after) + _row_before == _row_after + and f"Month peak: {messages.watts(_W13)} on" in _row_after) check("...and the COUNT BESIDE IT DOES NOT COLLAPSE TO ZERO, which is the " "defect: a coverage figure that resets while the value beside it " "persists actively misinforms", - "; 0 quarter(s) banked" not in _row_after) + not _cov_after.endswith("this month: 0")) check(f"...and it is the store's own tally, {_truth_after}, not a " f"process-lifetime counter - graded against a COUNT OF ROWS in the " f"other tier rather than against the property under test", - f"{_truth_after} quarter(s) banked" in _row_after and _truth_after >= _N13) + _cov_after.endswith(f"this month: {_truth_after}") + and _truth_after >= _N13) # ⚠️ The restarted run banks one MORE than it drove, and that is correct: the # checkpointed open block was stale, so `restore()` closed and banked it. The diff --git a/goodwe_controller/test_validate.py b/goodwe_controller/test_validate.py index 85fe40b..1678bcf 100644 --- a/goodwe_controller/test_validate.py +++ b/goodwe_controller/test_validate.py @@ -1223,7 +1223,8 @@ def _verdict(opts, token): ps = [p for p in validate_startup_config(opts, -5000, 5000) if token in p] if not ps: return (False, None, None) - m = re.search(r"for (\S+) \(inverters\.max_w\) is (\d+) W", ps[0]) + m = re.search(r"for (\S+) \(inverters\.max_w\),? (?:is|at) (\d+) W", + ps[0]) return (True, m.group(1) if m else None, float(m.group(2)) if m else None) @@ -1431,8 +1432,8 @@ check("the table AND a non-default price_taxes_eur_kwh is refused, and the " "refusal says WHICH ONE WINS and what to do - not merely that the two " "are incompatible", why(_T17_P_BOTH, "(price_taxes_profile) is set, so") - and why(_T17_P_BOTH, "(price_taxes_eur_kwh) is not used, but it reads " - "0.1198")) + and why(_T17_P_BOTH, "(price_taxes_eur_kwh) is not used. Set it " + "back to")) check("...and the SHIPPED scalar beside the table is NOT refused, or every " "Walloon site would have to clear a key it never touched. The refusal is " "about a value the operator chose, and the shipped default is the one " @@ -1482,8 +1483,7 @@ check("...while a value that is NEITHER the shipped default NOR a superseded " "one is still REFUSED beside the table, naming it - the set of " "'untouched' figures widened by exactly the old defaults and by nothing " "else", - why(_T17_P_BOTH, "(price_taxes_eur_kwh) is not used, but it reads " - "0.1198") + why(_T17_P_BOTH, "from 0.1198, or clear") and 0.1198 not in _T18_SUPERSEDED and abs(0.1198 - _T18_SHIPPED_TAXES) > 1e-9) # ⚠️ AND THE REFUSAL SAYS SO, so an operator who HAS typed a number is told @@ -1660,7 +1660,7 @@ check("...and a malformed blob is refused as a malformed blob, naming the " # coefficients against arithmetic done with the same coefficients. So the leg # starts, and the operator is told WHICH check did not run. _T16_UNGRADED = [m for lvl, m in _T16_OK_LOG - if lvl == "WARNING" and "UNGRADED" in m] + if lvl == "WARNING" and "not checked against a printed price" in m] print(f" {(_T16_UNGRADED or [''])[0][:118]}") check("a leg with no card block starts, and says at startup that its " "coefficients are UNGRADED - naming what was checked instead, so the " @@ -1683,13 +1683,13 @@ check("...and a leg that DOES carry a card does NOT print it, or the sentence " "would be noise an operator learns to ignore rather than a report of " "which check ran", _T16_WITH_CARD == [] - and not [m for lvl, m in _T16_CARD_LOG if "UNGRADED" in m]) + and not [m for lvl, m in _T16_CARD_LOG if "not checked against a printed price" in m]) # ⚠️ AND A CARD ON THIS LEG IS STILL GRADED, at startup, by the same rung. check("...and a card ON THIS LEG that the coefficients do not reproduce is " "REFUSED at startup, so the optional block is optional and not inert", why(_t16_start(price_export_formula=_T16_CONS.replace( '"expect_incl_vat":15.55', '"expect_incl_vat":15.05'))[0], - "price_export_formula does not match its own card")) + "price_export_formula gives")) # ⚠️ THE SENTENCE DOCS.md RESTS ON, AND IT IS THE ONE MOST LIKELY TO ROT. _T16_INFO = [m for lvl, m in _T16_OK_LOG if lvl == "INFO" diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index eba1beb..1012389 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -1930,7 +1930,7 @@ check("the status page carries a SITE row of its own, and the banner says the " any(ck.get("id") == "site_direction" and not ck["ok"] and not ck["warn"] and "every inverter" in ck["text"] for ck in _c31.checks()) - and "Total command" in _c31.status_payload()["banner"] + and "Total power" in _c31.status_payload()["banner"] and "inverter-" not in _c31.status_payload()["banner"]) _c31_mode = _c31.o.get("shadow_mode") _c31.o["shadow_mode"] = "on" diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index 53e766e..4598deb 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -161,16 +161,16 @@ configuration: name: "Tariff · Injection price (EUR/kWh)" description: "What you are paid per kWh fed into the grid, all in. It may be negative." static_profile: - name: "Tariff · Fixed or day/night tariff (JSON)" - description: "Your fixed or day/night contract as one line of JSON, prices all in. Fill it in even on a dynamic contract, as the fallback when the price feed fails." + name: "Tariff · Fixed or day/night tariff" + description: "Your fixed or day/night contract on one line, prices all in, as the documentation shows. Fill it in even on a dynamic contract, as the fallback." price_taxes_profile: - name: "Tariff · Day/night levies and VAT (JSON)" + name: "Tariff · Day/night levies and VAT" description: "Leave it empty unless your grid operator charges a different day and night rate, as in Wallonia and Brussels. Set this or the flat figure above, not both." price_formula: - name: "Tariff · Your own tariff formula (JSON)" - description: "For custom_formula only. Type the numbers from your supplier's tariff card as one line of JSON, and the add-on checks them against the card." + name: "Tariff · Your own tariff formula" + description: "For custom_formula only. Type the numbers from your supplier's tariff card on one line, as the documentation shows. The add-on checks them against the card." price_export_formula: - name: "Tariff · Your own injection formula (JSON)" + name: "Tariff · Your own injection formula" description: "Optional. The injection formula from your tariff card, in the same shape as your own tariff formula. Leave it empty to use the flat injection price." price_csv_path: name: "Tariff · Price CSV file" @@ -278,14 +278,14 @@ configuration: name: "Advanced · Command rounding (W)" description: "The command is rounded to a multiple of this, so noise does not change it every cycle." saturation_w: - name: "Advanced · Inverter at limit gap (W)" + name: "Advanced · At-limit shortfall (W)" description: "When an inverter delivers this much less than asked, it counts as at its limit. The per-inverter wrong-direction threshold is half of this." saturation_cycles: name: "Advanced · Cycles at limit before freezing" description: "How many cycles in a row at the limit before control stops building up error. Do not set it to 1." integrator_max_w: - name: "Advanced · Error build-up limit (W)" - description: "Caps the error that control saves up from past cycles. 0 means “Inverter rating”. Do not raise it above the rating." + name: "Advanced · Catch-up limit (W)" + description: "Limits how hard control keeps pushing while the battery falls behind. 0 means “Inverter rating”. Do not raise it above the rating." heartbeat_s: name: "Advanced · Command refresh interval (s)" description: "How often the command is sent again even when unchanged. Keep it well under the control board's own 30 s limit." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index daa0d76..49476cd 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -59,7 +59,7 @@ configuration: description: "Zet dit aan als de sensor van deze omvormer leveren als een negatief getal toont." capacity_kwh: name: "Bruikbare capaciteit (kWh) (optioneel)" - description: "De bruikbare capaciteit van deze batterij, van het datablad. Vul ze bij elke omvormer in of bij geen enkele. De add-on verdeelt het werk dan volgens de energie die elke batterij nog heeft." + description: "De bruikbare capaciteit van deze batterij, van het datablad. Vul ze bij elke omvormer in of bij geen. Dan verdeelt de add-on het werk volgens de energie in elke batterij." estop_fitted: name: "Hardware · RS485-noodstop is geplaatst" description: "Zet dit aan als de noodstop geïnstalleerd is. Het verandert alleen een waarschuwing op de statuspagina." @@ -142,16 +142,16 @@ configuration: name: "Tarief · Injectievergoeding (EUR/kWh)" description: "Wat u krijgt per kWh die u op het net zet, alles inbegrepen. Dit mag negatief zijn." static_profile: - name: "Tarief · Vast of dag/nacht-tarief (JSON)" - description: "Uw vaste of dag/nacht-contract als één regel JSON, prijzen alles inbegrepen. Vul dit ook in bij een dynamisch contract. Het is de reserve als de prijsfeed uitvalt." + name: "Tarief · Vast of dag/nacht-tarief" + description: "Uw vaste of dag/nacht-contract op één regel, prijzen alles inbegrepen, zoals de documentatie toont. Vul dit ook in bij een dynamisch contract. Het is de reserve als de prijsfeed uitvalt." price_taxes_profile: - name: "Tarief · Heffingen en btw dag/nacht (JSON)" + name: "Tarief · Heffingen en btw dag/nacht" description: "Laat dit leeg, tenzij uw netbeheerder een ander dag- en nachttarief rekent, zoals in Wallonië en Brussel. Vul dit of het vaste bedrag hierboven in, niet allebei." price_formula: - name: "Tarief · Uw eigen tariefformule (JSON)" - description: "Alleen voor custom_formula. Typ de getallen van de tariefkaart van uw leverancier als één regel JSON. De add-on controleert ze met de kaart." + name: "Tarief · Uw eigen tariefformule" + description: "Alleen voor custom_formula. Typ de getallen van de tariefkaart van uw leverancier op één regel, zoals de documentatie toont. De add-on controleert ze met de kaart." price_export_formula: - name: "Tarief · Uw eigen injectieformule (JSON)" + name: "Tarief · Uw eigen injectieformule" description: "Optioneel. De injectieformule van uw tariefkaart, in dezelfde vorm als uw eigen tariefformule. Laat leeg om de vaste injectievergoeding te gebruiken." price_csv_path: name: "Tarief · CSV-bestand met prijzen" @@ -259,14 +259,14 @@ configuration: name: "Geavanceerd · Afronding van het commando (W)" description: "Het commando wordt afgerond op een veelvoud hiervan, zodat ruis het niet elke cyclus verandert." saturation_w: - name: "Geavanceerd · Verschil omvormer aan grens (W)" + name: "Geavanceerd · Tekort aan de grens (W)" description: "Levert een omvormer zoveel minder dan gevraagd, dan zit ze aan haar grens. De drempel verkeerde richting per omvormer is de helft hiervan." saturation_cycles: name: "Geavanceerd · Cycli aan grens voor bevriezen" description: "Hoeveel cycli na elkaar aan de grens voor de regeling stopt met afwijking opbouwen. Zet dit niet op 1." integrator_max_w: - name: "Geavanceerd · Grens opgebouwde afwijking (W)" - description: "Begrenst de afwijking die de regeling uit vorige cycli opspaart. 0 betekent het vermogen van de omvormer. Zet dit niet hoger dan dat vermogen." + name: "Geavanceerd · Inhaalgrens (W)" + description: "Begrenst hoe hard de regeling blijft duwen als de batterij achterloopt. 0 betekent het vermogen van de omvormer. Zet dit niet hoger dan dat vermogen." heartbeat_s: name: "Geavanceerd · Commando opnieuw sturen na (s)" description: "Hoe vaak het commando opnieuw gestuurd wordt, ook als het gelijk bleef. Houd dit ruim onder de eigen grens van 30 s van de stuurmodule." diff --git a/goodwe_controller/ux08_allowlist.txt b/goodwe_controller/ux08_allowlist.txt index cc820da..605e7db 100644 --- a/goodwe_controller/ux08_allowlist.txt +++ b/goodwe_controller/ux08_allowlist.txt @@ -1,50 +1,5 @@ -# UX-08 ratchet (test_messages.py part 3). Each line is a user-facing string that -# does not follow STYLE.md yet: "<kind> <sha1-12 of its text> # where :: start". -# These are waiting for phase 2d (log); phase 2b emptied the row and banner -# kinds and phase 2c the refusal and option kinds. Delete the line when you -# rewrite the string, because a stale line fails the test. Never add a line for a new string: write the new -# string to STYLE.md instead. - -log a5e99679fd80 # main.py banned: SAFETY-02, latch :: 'SAFETY-02: the per-inverter store migration did not verify (%s). The l' -log 128b18b32d86 # main.py over 25 words (41); banned: LATCHED, SAFETY-44, latched :: 'SAFETY-44: this store carries a LATCHED sign-disagreement failsafe und' -log f60446541ae5 # main.py over 25 words (83); banned: LATCH, LATCHED, SAFETY-02, latch; capitals: LATCH GUARD :: 'SAFETY-02 LATCH GUARD: this store carries a LATCHED sign-disagreement ' -log 04d06bf223c8 # main.py over 25 words (73); banned: REGISTER, SAFETY-37, SAFETY-57, register; capitals: WHICH IS NOT BY ITSELF :: 'SAFETY-37: %s battery-power reading did not move under a command that ' -log aec01642bd07 # main.py banned: SAFETY-57 :: 'SAFETY-57: %s' -log aebbca17acb3 # main.py over 25 words (52); banned: allocator :: 'write_setpoint() was asked to put %+.0f W on every one of %d inverters' -log b74c3018461e # main.py over 25 words (30); banned: SAFETY-28, allocator :: 'SAFETY-28 REFUSED a write of %+.0f W to %s: %s. Commanding 0 W instead' -log cefffafa8b27 # main.py over 25 words (31) :: 'the write of %+.0f W to %s (%s) did not complete in %.0f s and was aba' -log 1001c6250b85 # main.py over 25 words (29); banned: SAFETY-02 :: 'SAFETY-02 TRIPPED on %s - %s. Commanding 0 W on that inverter and hold' -log 8252ef5eefad # main.py over 25 words (48); banned: SAFETY-30 :: 'SAFETY-30 TRIPPED at the SITE - %s. That is the SUM of every standing ' -log 8a65cf945e00 # main.py over 25 words (32); banned: SAFETY-31 :: 'SAFETY-31 TRIPPED - %s. Commanding 0 W on every inverter and holding i' -log 5d2beed2f1a2 # main.py over 25 words (65); banned: HW-01, SAFETY-42; capitals: NOTHING IS COMMANDED DIFFERENTLY :: 'SAFETY-42 TRIPPED on %s - %s. NOTHING IS COMMANDED DIFFERENTLY: this g' -log d50b775b9cd4 # main.py banned: ARBITER; capitals: ARBITER SCOPE :: 'ARBITER SCOPE: %s' -log 749c2c6fe81d # main.py over 25 words (26); banned: SAFETY-10, heartbeat; capitals: SHADOW MODE IS ON :: 'SAFETY-10 SHADOW MODE IS ON. The full decision path runs and NOTHING i' -log 4d271dfc6f1c # main.py banned: SAFETY-10 :: 'SAFETY-10 shadow mode is OFF. This controller is commanding the batter' -log 730387e0da2b # main.py banned: SAFETY-03 :: 'SAFETY-03 - %s Engagements so far: %d.' -log 3bf899e99297 # main.py over 25 words (56); banned: SAFETY-03, clamp, clamped, integrator; capitals: STILL RUNNING :: 'SAFETY-03 - %s Silently clipping this is how a winding integrator reac' -log 78cb6bd09633 # main.py over 25 words (48); banned: SAFETY-07; capitals: STILL RUNNING :: 'SAFETY-07 - %s. The guard is asking for everything the inverter has an' -log cc735997adc7 # main.py over 25 words (44); banned: SAFETY-24; capitals: STILL RUNNING :: 'SAFETY-24 - %s. The controller is STILL RUNNING and charging is still ' -log ebcb428a70d0 # main.py over 25 words (70); banned: SAFETY-18, arbiter, watchdog; capitals: CHECK THE METER :: 'SAFETY-18 - %s. The grid-following loop is regulating against a number' -log 38018b887495 # main.py over 25 words (43) :: 'tariff refresh degraded (%s); KEEPING the plan resolved at %s, %.0f s ' -log 0eab1ec96fe8 # main.py capitals: CONTROL LOOP DIED :: 'CONTROL LOOP DIED (%s) - commanding 0 W and exiting with status %d' -log db529f2c419d # main.py over 25 words (40); banned: SAFETY-02 :: 'SAFETY-02 was TRIPPED on %s before this restart and stays tripped: %s.' -log c5aadd5c8bf9 # main.py over 25 words (45); banned: SAFETY-42; capitals: NOTHING IS BEING COMMANDED DIFFERENTLY :: 'SAFETY-42 was TRIPPED on %s before this restart and stays tripped: %s.' -log d72bbdb7e595 # main.py over 25 words (39); banned: SAFETY-30 :: 'SAFETY-30 (site) was TRIPPED before this restart and stays tripped: %s' -log 8b880e65a7c3 # main.py over 25 words (38); banned: SAFETY-31 :: 'SAFETY-31 was TRIPPED before this restart and stays tripped: %s. Every' -log 23f58b7f305c # p1.py:1264 over 25 words (30) :: 'meter_poll_s %.1f leaves no room under meter_max_age_s %.1f: one misse' -log 88a7251e842b # p1.py:470 banned: telegram :: 'P1 telegram rejected: %s' -log 0dd83d6dfaf4 # price.py over 25 words (30) :: 'the feed published no price for %d of %d instants (index %s); those in' -log bcfd7062e28e # price.py over 25 words (79); banned: §8 :: 'price_feed_url is set, so %s is requesting %s exactly as given and is ' -log b57bc6de4a6b # price.py over 25 words (47); banned: validate.py :: 'price_taxes_profile cannot be used (%s: %s), so this fetch has NO tax ' -log d5595aaaacc4 # price_history.py banned: §8 :: 'price history at %s is %s - starting from empty. §8.3 carry-forward ha' -log dbed0b8e35ea # static_tariff.py banned: validate.py :: 'static_profile is unusable (%s); no cheap window. This should have bee' -log 8fbe9f5407ea # static_tariff.py over 25 words (28); banned: §1, §6 :: '§11.4: %s, and no static_profile is configured to fall back to. The pl' -log 4ce29e043d89 # static_tariff.py banned: §1 :: '§11.4: %s - falling back to the static profile, plan marked PROVISIONA' -log a3c7c9719ed2 # store.py capitals: LOST STATE :: 'per-inverter store migration LOST STATE and has not been marked done: ' -log 5b537a77052b # validate.py over 25 words (41); banned: arbiter, saturation :: 'integrator_max_w %.0f W is above max_w %.0f W. Not refused - the arbit' -log 12ae40f9d289 # validate.py over 25 words (73); banned: arbiter, clamp, clamps :: 'maintenance_discharge_w %.0f W is above max_w%s %.0f W. Not refused - ' -log c6dc799502cf # validate.py over 25 words (32) :: '%s carries negative levies %s EUR/kWh. That is accepted, but a tax com' -log 1688a7478ceb # validate.py over 25 words (36) :: 'price_formula is filled in but price_provider is %r, so the coefficien' -log f37f9fce4433 # validate.py over 25 words (96) :: '%s has no "card" block, so its coefficients are UNGRADED: nothing reco' -log 396fbdd009c2 # validate.py over 25 words (52); banned: §1 :: "price_provider is %r but static_profile is empty. §11.4's degradation " -log 37bba6ed37e3 # validate.py capitals: REFUSING TO START :: 'REFUSING TO START: the add-on configuration is not usable.' +# UX-08 ratchet (test_messages.py part 3). Each line would be a user-facing +# string that does not follow STYLE.md yet: "<kind> <sha1-12 of its text> # +# where :: start". Phase 2d emptied it: every row, banner, refusal, option text +# and WARNING+ log line now follows STYLE.md, and ALLOWLIST_MAX is 0. Never add +# a line for a new string: write the new string to STYLE.md instead. -- 2.54.0 From 569f16aa9159a89e79a0e9fbf01f6fc2610fad6f Mon Sep 17 00:00:00 2001 From: Claude review <noreply@anthropic.com> Date: Sun, 27 Sep 2026 08:29:14 +0200 Subject: [PATCH 037/105] UX-08 2d review: action log reachable in status JSON, engaged peak row pinned, imported keys expanded - status_payload() also returns the action log as `events`. The page does not render it. Some entries (a dropped inverter's reason, the peak guard's projection, unplaced watts) are written nowhere else, and DOCS still points installers at the action log. - test_peakguard pins the engaged row's ordered pair (the battery's share, then the limit). - test_messages expands setting keys named by constants imported from another app module, so the shown-text 30-word scan counts them. - p1.py: 'A meter message could not be read'. DOCS glossary: control board in plain words, with the hardware in an installer note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 2 +- goodwe_controller/DOCS.md | 13 ++++++---- goodwe_controller/app/main.py | 5 ++++ goodwe_controller/app/p1.py | 2 +- goodwe_controller/test_messages.py | 26 +++++++++++++++---- goodwe_controller/test_peakguard.py | 13 ++++++++++ goodwe_controller/test_watchdog.py | 7 +++++ 8 files changed, 57 insertions(+), 13 deletions(-) diff --git a/STYLE.md b/STYLE.md index dd5a0a3..7e645ae 100644 --- a/STYLE.md +++ b/STYLE.md @@ -9,7 +9,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. - **Log line** (WARNING/ERROR): one line, at most 25 words, with the numbers that matter. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. A reason text a line quotes (`%s`) keeps its own codes, because that is the evidence an installer searches for. - **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3). -- **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown. +- **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown on the page. Installers read it as `events` in the `status` JSON. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. ## 2. Numbers diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index 9750f74..d5a7ae1 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -52,7 +52,7 @@ The allowlist is empty and its cap is 0 (43 → 0). Every WARNING and ERROR line 1. **No code prefixes on log lines.** Nothing outside the repositories greps them, except `/home/homelab/clampwatch.sh`, a one-off site watch from 2026-09-05 that greps `OUTPUT_CLAMP` and `Engagements so far`. `OUTPUT_CLAMP` is still in the reason the line quotes; "Engagements so far" is now "Cut back N times so far". The tests that found a line by its card id (`SAFETY-37`, `SAFETY-44`, `CONTROL LOOP DIED`, `UNGRADED`) now find it by its words. 2. **Reason texts keep their codes.** A line quotes a watchdog's reason (`%s`), such as `STALE_READING: …` or `OUTPUT_CLAMP: …`. Those are the evidence an installer searches for and many tests pin them, so they were not rewritten. The line around them is plain. 3. **Reasoning moved to DEBUG, not deleted,** for the 10 lines marked DROP-to-DEBUG (for example the 14 768 W history behind the over-rating alarm, why SAFETY-42 reports and does not act, and the Eneco card advice). The 25-word line keeps the action and the numbers. SAFETY-57's promise stays on the ERROR line, as an ordered pair: "until it changes, or 17 s after the command drops below 250 W". -4. **The line under the buttons** showed the newest raw action-log entry (`OUTPUT_CLAMP …`, `FAILSAFE …: SIGN_DISAGREEMENT`, `ALLOCATOR …`). Each `log_event()` call now also names a plain hint from `messages.HINTS`, and the page shows that. The action log itself is unchanged, because tests and later analysis read it, and the page no longer shows it. +4. **The line under the buttons** showed the newest raw action-log entry (`OUTPUT_CLAMP …`, `FAILSAFE …: SIGN_DISAGREEMENT`, `ALLOCATOR …`). Each `log_event()` call now also names a plain hint from `messages.HINTS`, and the page shows that. The action log itself is unchanged, because tests and later analysis read it, and the page no longer shows it. It stays reachable as `events` in the `status` JSON (review of #136), because some entries are written nowhere else: a dropped inverter's reason, the unplaced watts, the peak guard's projection and the shadow decision. 5. **The top table.** *Why* is `messages.why()`: the arbiter's winner and limit in words ("Keeping the grid near zero: 440 W, held back by the peak limit"). `self.reason` keeps `Resolution.explain()` for the log and the checks. *Tariff*, *Price history*, *Arbitrage* and *Shadow mode* keep every figure TARIFF-11 and SAFETY-47 put there, each in its own slot, in words. Labels: *Battery level*, *Solar production*, *Power request*. 6. **The month-peak row became two rows**, because one sentence of 15 words cannot hold the peak, its time, its share of the limit and TARIFF-13's coverage figure. The store's state at start (`restore_state`) left the row: it is the INFO line at start. 7. **The peak guard rows** name the projection first and the limit second, as before (SAFETY-38). The blind row says what it means for the owner: the battery does not charge until the period can be measured again. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 82477d5..d20c55f 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -9,10 +9,10 @@ v0.1.0 and outdated; where it disagrees with this page, this page wins. ## Words used on this page -- **Control board**: the small computer wired to the inverter's RS485 meter - bus (a T-CAN485 board with an ESP32 chip). It passes the add-on's power - request to the inverter. If the add-on goes quiet for about 30 seconds, it - sets the inverter to 0 W by itself. +- **Control board**: the small computer on the inverter's meter cable. It + passes the add-on's power request to the inverter. If the add-on goes quiet + for about 30 seconds, it sets the inverter to 0 W by itself. (For + installers: a T-CAN485 board with an ESP32 chip on the RS485 bus.) - **Isolator**: the switch that cuts an inverter off from the mains. Switching it off stops the inverter, whatever the add-on or the control board asks. - **Developer Tools**: the Home Assistant page that lists every entity and its @@ -3183,7 +3183,10 @@ buttons reach the inverter. *For installers: the Configuration page is UX-02. The line under the buttons is `messages.hint()`, the plain form of the newest entry of the add-on's own -action log (`Controller.events`), which the page no longer shows.* +action log (`Controller.events`). The page no longer shows that log, but the +`status` JSON still carries its last 40 entries as `events`: open the add-on +page and add `status` to its address. The action-log tables in this document +refer to it.* ## Status page diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 7b6dfda..7cd312e 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -5260,6 +5260,11 @@ class Controller: return { "banner": banner, "level": level, "rows": rows, "checks": checks, "hint": self.hint, + # The action log itself, newest first. The page does not show it + # (UX-08 2d), but an installer can still read it in the `status` + # JSON, because several events (a dropped inverter's reason, the + # peak guard's projection) are written nowhere else. + "events": list(self.events), } async def handle_action(self, what: str): diff --git a/goodwe_controller/app/p1.py b/goodwe_controller/app/p1.py index 0f19017..6c0f5c8 100644 --- a/goodwe_controller/app/p1.py +++ b/goodwe_controller/app/p1.py @@ -472,7 +472,7 @@ class P1Ingest: """ self.parse_errors += 1 self.last_error = str(err) - _LOG.warning("Meter reading refused: %s", err) + _LOG.warning("A meter message could not be read: %s", err) # -- what consumers read ------------------------------------------------- def age_s(self) -> float | None: diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 7459936..d9cf7c8 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -402,6 +402,18 @@ def strings_in(node, expand=False): yield from strings_in(child, expand) +def _module_constants(tree): + """Module-level `NAME = "text"` assignments.""" + return {t.id: n.value.value for n in tree.body + if isinstance(n, ast.Assign) and isinstance(n.value, ast.Constant) + and isinstance(n.value.value, str) + for t in n.targets if isinstance(t, ast.Name)} + + +_MODCONST = {f.stem: _module_constants(ast.parse(f.read_text(encoding="utf-8"))) + for f in sorted(APP.glob("*.py"))} + + def collect(): """(kind, where, text) for every user-facing literal of a ratcheted kind.""" out = [] @@ -409,12 +421,16 @@ def collect(): if f.name == "messages.py": continue tree = ast.parse(f.read_text(encoding="utf-8")) + # The file's own constants, and those it imports from another app + # module (`from .validate import TAXES_PROFILE_OPTION`), so a key + # named by a constant from elsewhere is expanded too. CONSTANTS.clear() - CONSTANTS.update({t.id: n.value.value for n in tree.body - if isinstance(n, ast.Assign) - and isinstance(n.value, ast.Constant) - and isinstance(n.value.value, str) - for t in n.targets if isinstance(t, ast.Name)}) + CONSTANTS.update(_module_constants(tree)) + for n in tree.body: + if isinstance(n, ast.ImportFrom) and n.level == 1 and n.module: + theirs = _MODCONST.get(n.module, {}) + CONSTANTS.update({a.asname or a.name: theirs[a.name] + for a in n.names if a.name in theirs}) for node in ast.walk(tree): if isinstance(node, ast.Dict): for k, v in zip(node.keys, node.values): diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 187e5ad..06c23ea 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1221,6 +1221,19 @@ rows = [r for r in c.checks() if r.get("id") == "peak_guard"] print(" status row: " + (rows[0]["text"] if rows else "(none)")) check("the status page carries exactly one peak-guard row, flagged", len(rows) == 1 and rows[0]["warn"]) +# UX-08 2d: the engaged row names what the battery is asked for FIRST and the +# limit SECOND. Both are watts, so only the ordered pair tells them apart. +from app import messages as _msg_on # noqa: E402 +_on = (f"asks the battery for {_msg_on.watts(c.peak_guard.floor_w)} to stay " + f"under {_msg_on.watts(c.peak_guard.ceiling_w)}") +_on_swapped = (f"asks the battery for {_msg_on.watts(c.peak_guard.ceiling_w)} " + f"to stay under {_msg_on.watts(c.peak_guard.floor_w)}") +check("...and it names the battery's share first and the limit second, and " + "the two render differently so the swap is visible", + len(rows) == 1 and _on in rows[0]["text"] + and _on_swapped not in rows[0]["text"] + and _msg_on.watts(c.peak_guard.floor_w) + != _msg_on.watts(c.peak_guard.ceiling_w)) check("an engagement that is not saturated raises NO notification - §10.3's " "'clamp AND alarm' is SAFETY-03's rule about a BUG SIGNAL, and a house " "load bigger than the inverter is not a bug", diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 1012389..39940ea 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -375,6 +375,13 @@ check("the status page says so in words: a red row, at 0 W, cleared by start", for c in ctrl.checks())) check("the banner leads with it", ctrl.status_payload()["banner"] == messages.banner_direction(False)) +check("...the line under the buttons says it in plain words, and the action " + "log with the raw reason is still reachable in the status JSON", + ctrl.status_payload()["hint"].endswith( + messages.hint("direction", unit=ctrl.inverters[0].name)) + and ctrl.status_payload()["events"] == ctrl.events + and any(e.split(" ", 1)[1].startswith("FAILSAFE ") + for e in ctrl.status_payload()["events"])) check("it stays at 0 W on later cycles too", hass.writes[-1] == 0.0 and hass.writes.count(0.0) >= 1) -- 2.54.0 From b878663b2d2be1c771f8c13a4820f0ef4353a3c0 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 08:42:01 +0200 Subject: [PATCH 038/105] CI: bump infra pin to ecd3864 (admin/goodwe#60, UX-08) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index de4eb22..c2040ec 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -7081df4276ad3cf788355b97a3b3f40ea28d72bd +ecd3864d9376a990c267dfb399eb2dae4e56c76b -- 2.54.0 From 23a3a3f5b536e8e502b241c6aabc7e0b3d439f74 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 10:58:43 +0200 Subject: [PATCH 039/105] UX-10: the last plain-language leftovers: log lines, two table rows, 'Why: Other', red at 0 s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - test_messages.py part 6: every dynamic part of a WARNING+ line is classified as data or as a built text, and every built text is produced by the real code and checked. This is the gap the 2d scan had: it counted `%s` as one word, so reasons built by loop_clamp_note() and friends were never seen. - Quoted reasons rewritten to STYLE.md (red-alarm shape, codes kept): OUTPUT_CLAMP, METER_FROZEN, CIRCULATING_POWER, STALE_READING, the peak guard (codes now PEAK_GUARD*), the migration report, price feed, price history and gate reasons. Plurals via messages.times()/count(). - Top table: Price history "96 prices over 24 hours for 26 Sep", Tariff "one every 15 minutes or every hour", "not final yet" dropped. - Levels and noise: per-cycle shadow line DEBUG, shadow on/off INFO, aiohttp access log only at log level debug, settings warnings once per start, one plain line per Home Assistant outage (hass.Outage). - INFO jargon and error texts: no "§8.3", ISO times, "banked", "keys ARE", "NOT_OBSERVED", "did NOT land", "AND". - Display bugs: WHY_WINNER covers every winner and safety reason (main.why_key(), part 7 finds them in the code); the meter row is amber "waiting for the first reading" inside its limit after a start; the missing-reading age is counted when the page asks. - STYLE.md and DECISIONS/UX-08-short-notifications.md (UX-10 section). No change to safety behaviour, alarm levels, notification ids, triggers, cadence or the banner cascade. One row colour changes (meter at start), justified in DECISIONS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 15 + goodwe_controller/DOCS.md | 37 +- goodwe_controller/app/allocator.py | 2 +- goodwe_controller/app/circulation.py | 8 +- goodwe_controller/app/clamp.py | 41 +- goodwe_controller/app/freeze.py | 14 +- goodwe_controller/app/freshness.py | 41 +- goodwe_controller/app/hass.py | 49 ++ goodwe_controller/app/main.py | 132 ++-- goodwe_controller/app/maintenance.py | 9 +- goodwe_controller/app/messages.py | 21 + goodwe_controller/app/p1.py | 24 +- goodwe_controller/app/peakguard.py | 66 +- goodwe_controller/app/price.py | 15 +- goodwe_controller/app/price_forecast.py | 51 +- goodwe_controller/app/price_history.py | 91 ++- goodwe_controller/app/selfconfig.py | 6 +- goodwe_controller/app/static_tariff.py | 43 +- goodwe_controller/app/store.py | 54 +- goodwe_controller/app/tariff.py | 35 +- goodwe_controller/app/validate.py | 41 +- goodwe_controller/app/web.py | 10 +- goodwe_controller/test_clamp.py | 35 +- goodwe_controller/test_freshness.py | 11 +- goodwe_controller/test_maintenance.py | 10 +- goodwe_controller/test_messages.py | 652 +++++++++++++++++- goodwe_controller/test_peakguard.py | 12 +- goodwe_controller/test_price.py | 25 +- goodwe_controller/test_price_forecast.py | 17 +- goodwe_controller/test_price_history.py | 38 +- goodwe_controller/test_tariff.py | 4 +- goodwe_controller/test_validate.py | 4 +- 33 files changed, 1268 insertions(+), 347 deletions(-) diff --git a/STYLE.md b/STYLE.md index 7e645ae..09b06be 100644 --- a/STYLE.md +++ b/STYLE.md @@ -7,7 +7,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. - **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. -- **Log line** (WARNING/ERROR): one line, at most 25 words, with the numbers that matter. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. A reason text a line quotes (`%s`) keeps its own codes, because that is the evidence an installer searches for. +- **Log line** (WARNING/ERROR): one line, at most 25 words, with the numbers that matter. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. A reason text a line quotes (`%s`) keeps its reason code (`OUTPUT_CLAMP`, `STALE_READING`), because that is the evidence an installer searches for. The reason itself has the shape of a red alarm: at most 3 sentences of at most 30 words. The line as logged has no semicolon, banned word, capitals, "1 times" or "(s)". `test_messages.py` part 6 builds every such reason with the real code and checks it. A line that repeats every cycle is DEBUG. INFO lines carry no section numbers, ISO timestamps or capitals. - **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3). - **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown on the page. Installers read it as `events` in the `status` JSON. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index d5a7ae1..7eacf7d 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -61,3 +61,18 @@ The allowlist is empty and its cap is 0 (43 → 0). Every WARNING and ERROR line 10. **The panel's key match** no longer files `inverters.max_w` under the flat `max_w`. 11. **The Supervisor question at start** is one INFO line with a real reason (a timeout's own text is empty, so the error type is named). 12. **DOCS**: a glossary ("Words used on this page") explains control board, isolator and Developer Tools once. Card ids left the headings and sit on a *For installers* line under each. The links to the renamed headings were updated. + +# UX-10: the last plain-language leftovers (after the 2d test) + +**Unchanged:** every safety behaviour, every alarm's log level (WARNING and ERROR stay), every notification id, trigger and cadence, the banner cascade, and every row colour except the meter row right after a start (item 6). + +1. **Why the 2d scan missed the clamp lines.** Part 3 reads a log call's own literal and counts `%s` as one word. The clamp lines are `"…software fault: %s …"`, and the text in `%s` was built elsewhere, by `loop_clamp_note()` and `ClampResult.describe()`. So the scan passed a line whose logged text had a semicolon, "BUG SIGNAL", "clamped" and "1 times". The same was true of every quoted reason. Part 6 closes the gap. It lists every dynamic part of every WARNING+ line as data (a number, a name, a path, a library's own error text) or as a built text, and a new part in neither list fails. Each built text is produced by the real code (the watchdogs, `decide()`, `loop_clamp_note()`, `MigrationReport.explain()`) or, for a family of builders, by every template of it (`PriceRead.no_data`, `Gate.block`). The text and the line as logged are then checked. A mutation shows the 2d clamp text is caught on both clamp lines. +2. **A quoted reason gets the red-alarm shape**, 3 sentences of at most 30 words, and not the 25-word line limit. It is the evidence behind an alarm, and it keeps its code and its limits, which the owner asked to keep. The alarm shape is STYLE.md's existing rule for the texts behind a safety stop, so no new limit was made up. Rewritten: `OUTPUT_CLAMP` (both kinds), `METER_FROZEN`, `CIRCULATING_POWER`, `STALE_READING` (SAFETY-56's two explanations and "cannot tell which" kept, in order), the peak guard's reasons, the state-migration report, the price feed and price history reasons, and the maintenance and trading gate reasons. "Software fault" left the clamp reason, because the ERROR line around it already says it. +3. **Codes are one token.** `PEAK GUARD`, `PEAK GUARD FLOOR-LIMITED` and `PEAK GUARD BLIND` read as capitals, so they are now `PEAK_GUARD`, `PEAK_GUARD_FLOOR_LIMITED` and `PEAK_GUARD_BLIND`, like `OUTPUT_CLAMP`. Nothing in admin/goodwe or in the scripts under `/home/homelab` greps them (checked). `/home/homelab/clampwatch.sh` greps `OUTPUT_CLAMP`, which stays. +4. **Top table.** *Price history* writes "96 prices over 24 hours for 26 Sep", joined by commas. *Tariff* writes the spacing as "one every 15 minutes or every hour". "Not final yet" was dropped, because a plan is provisional exactly when it holds an estimated price (`n_carried` counts the provisional points), so the estimated count already says it. +5. **Levels and noise.** The shadow line of every cycle is DEBUG, and "Shadow mode is on/off" is INFO: it follows a setting or a button, and the banner, hint and event are unchanged. aiohttp's access log is on only at log level debug. A settings warning is logged once per start (a filter on `goodwe.config`, WARNING only, so refusals are untouched), because the validator runs twice at start. When Home Assistant restarts, `hass.Outage` says so in one WARNING line for the REST API and the meter websocket together, puts the library's text on DEBUG, and says at INFO when both answer again. INFO lines lost "§8.3", ISO timestamps, "banked" and "keys ARE", and error texts lost "NOT_OBSERVED", "did NOT land" and "AND". +6. **Display bugs.** + - "Why: Other" during a latched per-inverter stop: `main.py` turns a safety winner into its claim's reason, and "sign disagreement" (and "unsplit", main.py's own refusal to split) had no entry in `WHY_WINNER`. The mapping is now `main.why_key()`, and part 7 finds every `Claim.set()` in the code and checks that every key it can produce has words. + - Red "Meter: no reading for 0 seconds" after a restart: until the first reading arrives, `P1Ingest.stale` is true, and the age is the time since start. The row now reads amber "waiting for the first reading" while that age is inside the limit. **Colour change, justified:** red at 0 s contradicted the limit the same row prints, and once readings exist the row is red only past that limit. Amber, not green, because control waits for the reading. Past the limit it is red as before. `stale` itself, which gates control, is unchanged. + - "A reading is missing for 0 seconds" stuck at 0: with the meter reading gone, the grid value stops changing, so the loop runs a cycle only every `cycle_floor_s`, and the line was computed once per cycle. The age is now counted when the page asks. The hold and its 15 s escalation are unchanged. +7. **Witness** (admin/goodwe): the resolved push says "after no answers from … to …", as the resolved card does. The YAML with every title and message stripped is identical. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index d20c55f..b3d31a0 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1639,7 +1639,7 @@ is the design rather than an accident: it is 1.0 at the top of the quarter and grows, so the guard is gentlest when its projection rests on the least evidence and becomes aggressive only once the quarter is nearly measured. -**The ceiling** is `peak_cap_w`, raised to the month's banked peak when that +**The ceiling** is `peak_cap_w`, raised to this month's recorded peak when that already stands higher — once a month's bill is set at 5013 W, holding later quarters to 3500 W buys nothing and costs real charging. **That relaxation is granted only by an OBSERVED reading:** a peak store that cannot be read leaves the @@ -1716,7 +1716,7 @@ exactly like the SoC drift the monthly maintenance cycle exists to correct. **nothing more**. See below for what that costs on a real evening. - **When it binds you are told**, once per episode, with notification `goodwe_peak_soc_floor` and a red status-page row reading *Battery at its - peak reserve* (`PEAK GUARD FLOOR-LIMITED` in the log): the quarter **will** + peak reserve* (`PEAK_GUARD_FLOOR_LIMITED` in the log): the quarter **will** go over the ceiling, so shedding load is the only thing left that changes the bill. Failing to shave is never silent — the euro figure is the whole point of the guard. @@ -1758,7 +1758,7 @@ because the guard it bounds is not the thing doing the discharging. **And the two can happen in the same cycle.** On the high-load block of the same day (15:00–17:00 UTC) with the pack below the floor, the guard reports -`PEAK GUARD FLOOR-LIMITED` — *"commanding no forced discharge"* — on 49 cycles, +`PEAK_GUARD_FLOOR_LIMITED` — *"there is no forced discharge"* — on 49 cycles, and on **all 49 of them** the loop is simultaneously being granted a discharge of up to 2000 W by the arbiter. The status page is telling you the truth about the guard while the battery empties. @@ -1848,14 +1848,14 @@ Both are watched. A guard that watched only the emitted value would be silent on every standard configuration. **The integrator bound is not a bug, and it is reported as what it is.** It -reads *"the loop's integrator reached its +5000 W anti-windup bound; the loop's -command this cycle was +2000 W"*, titled *"the control loop is at its integrator -bound"*, logged as a `WARNING`, with an amber (not red) status row and its own -notification (`goodwe_integrator_bound`), so it never replaces a BUG SIGNAL -notice still on screen. Brief -engagements after a large load or solar step are normal. If it stays engaged, -check that the battery is following its commands. Only a command over the rating -carries the BUG SIGNAL text, and it has its own notification budget. +reads *"the correction the add-on builds up reached its +5000 W limit. The +command this cycle was +2000 W"*, titled *"Battery is not keeping up"*, logged +as a `WARNING`, with an amber (not red) status row and its own notification +(`goodwe_integrator_bound`), so it never replaces a software-fault notice still +on screen. Brief engagements after a large load or solar step are normal. If it +stays engaged, check that the battery is following its commands. Only a command +over the rating is logged as a software fault, at `ERROR`, and it has its own +notification budget. Why: [`DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md`](DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md). ### The frozen-meter alarm @@ -2444,7 +2444,7 @@ since TARIFF-11 that row carries the provider plan itself: ``` Tariff: No fixed tariff set. Price plan from 412 s ago, for 48 hours ahead: day-ahead prices from the price feed, 60 prices over 33 hours, - 36 published and 24 estimated, 900+3600 s apart, not final yet + 36 published and 24 estimated, one every 15 minutes or every hour ``` ⚠️ **The two halves of that row are not computed at the same moment, and the @@ -2461,9 +2461,10 @@ Read the plan half as five separate facts: which *product* the feed publishes and whether it came from the feed or from your fixed tariff, how many **prices** it carries and how many **whole hours** they cover, how many are **published** (firm, for their own interval) against **estimated** (carried -from yesterday under §8.3), how far **apart** they are in seconds — `900+3600` -is the normal mixed steady state, quarter-hourly firm points beside hourly -carried ones — and `not final yet` (provisional) whenever any is estimated. +from yesterday under §8.3), and how far **apart** they are — "one every 15 +minutes or every hour" is the normal mixed steady state, quarter-hourly firm +points beside hourly carried ones. The plan is provisional exactly when some +prices are estimated, so the estimated count says it. ⚠️ **Points and hours are two different numbers and this row used to print one of them under the other's name.** `words` was `f"… {len(points)} h"`, so a @@ -3204,7 +3205,7 @@ ends. That row says how to clear it. | Row starts with | What it tells you | |---|---| | Control | When control last ran. Red when it has stopped running: the control board then sets the inverter to 0 W. | -| Meter | The grid reading, its age, how many readings were refused, and how long its value has not changed. | +| Meter | The grid reading, its age, how many readings were refused, and how long its value has not changed. Just after a start it is amber and *waiting for the first reading*. Red means no reading for longer than the limit. | | Stuck-meter check | Whether the add-on can warn you about a stuck meter. | | Meter reading may be stuck | See *Meter reading may be stuck* under Notifications. | | Month peak | This month's highest 15-minute average, when it happened, and how close it is to your peak limit. Amber from 80 %. | @@ -3244,8 +3245,8 @@ ERROR or WARNING line in the add-on log. **Check for inverters working against each other** is SAFETY-31, **Delivery check** SAFETY-42. - **Month peak** and **15-minute periods measured** are TARIFF-01 and - TARIFF-13. The store's state at start is the INFO line `capacity-tariff peak - store: …`, and the peak guard's full reason is on its log line. + TARIFF-13. The store's state at start is the INFO line `Month peak store: + …`, and the peak guard's full reason is on its log line. - ***name*: battery power reading stopped changing** is SAFETY-37/56/57. The ERROR line carries the full `STALE_READING` reason and when it clears. - The table at the top: **Why** is `messages.why()`, the arbiter's answer in diff --git a/goodwe_controller/app/allocator.py b/goodwe_controller/app/allocator.py index 2bc9b22..e63a8d5 100644 --- a/goodwe_controller/app/allocator.py +++ b/goodwe_controller/app/allocator.py @@ -250,7 +250,7 @@ class Allocation: f"{self.tick!r} and this is tick {tick!r} - a record whose " f"envelopes have moved cannot authorise a write") if not self.ok: - return f"the allocator refused this tick ({self.explain()})" + return f"no power split was possible this tick ({self.explain()})" if unit not in self.shares: return (f"{unit} has no share in this tick's allocation " f"({self.explain()})") diff --git a/goodwe_controller/app/circulation.py b/goodwe_controller/app/circulation.py index 41df103..26fd5a9 100644 --- a/goodwe_controller/app/circulation.py +++ b/goodwe_controller/app/circulation.py @@ -325,12 +325,12 @@ class CirculationWatchdog: return False self.tripped = True + # UX-10: plain sentences, every figure kept (test_messages.py part 6). self.reason = ( f"CIRCULATING_POWER: {circ_w:.0f} W measured going round between " - f"the inverters (peak {self.peak_w:.0f} W) for {held:.0f} s " - f"continuously - the meter cannot see it, because it nets to zero " - f"there (limits: over {self.cfg.min_w:.0f} W, held over " - f"{self.cfg.hold_s:.0f} s)") + f"the inverters for {held:.0f} s, peaking at {self.peak_w:.0f} W. " + f"The meter cannot see it, because it nets to zero there. Limits: " + f"over {self.cfg.min_w:.0f} W, held over {self.cfg.hold_s:.0f} s") return True def held_s(self, now: datetime) -> float: diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index f321e93..59ce685 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -142,6 +142,8 @@ import math from dataclasses import dataclass from datetime import datetime +from . import messages + # The reason code, distinct from any saturation-freeze code by construction: # nothing else in this add-on uses it. See "DISTINCT FROM SATURATION". REASON_CODE = "OUTPUT_CLAMP" @@ -234,31 +236,38 @@ CLEAR_CYCLES = 3 SUSTAINED_CYCLES = 3 -BUG_SIGNAL = ("This is a BUG SIGNAL, not a limit being used: something " - "upstream computed a setpoint the actuator cannot deliver.") +# UX-10: the reasons below are quoted by a WARNING or ERROR line, so they +# follow STYLE.md's rule for a quoted reason (test_messages.py part 6): no +# final full stop, the line adds it. The line around them says "software +# fault" for an over-rating, so the reason does not. + def loop_clamp_note(d) -> str: """The loop-side alarm text for one `control.Decision`, or "". SAFETY-40: the integrator bound is anti-windup doing its job and says so; - only a command over the rating is a BUG SIGNAL. Every number is the + only a command over the rating is a software fault. Every number is the decision's own, i.e. from the tick that clamped. """ if d.clamped: - return (f"{REASON_CODE}: the loop computed {d.requested_w:+.0f} W, over " - f"the {abs(d.clamped_w):.0f} W rating, and it was clamped to " - f"{d.clamped_w:+.0f} W; the loop's command this cycle was " - f"{d.target_w:+.0f} W. {BUG_SIGNAL}") + return (f"{REASON_CODE}: the add-on computed {d.requested_w:+.0f} W, " + f"over the {abs(d.clamped_w):.0f} W rating, and cut it back to " + f"{d.clamped_w:+.0f} W. The command this cycle was " + f"{d.target_w:+.0f} W") if d.i_clamped: - return (f"{REASON_CODE}: the loop's integrator reached its " - f"{d.i_bound_w:+.0f} W anti-windup bound; the loop's command " - f"this cycle was {d.target_w:+.0f} W. Brief " - f"engagements after a large load or solar step are normal. If it " - f"persists, check that the battery is following its commands.") + return (f"{REASON_CODE}: the correction the add-on builds up reached " + f"its {d.i_bound_w:+.0f} W limit. The command this cycle was " + f"{d.target_w:+.0f} W") return "" +def write_clamp_note(named) -> str: + """The write-side alarm text: `named` is `[(inverter name, ClampResult)]` + for every inverter whose write was cut back this cycle.""" + return ". ".join(f"{name}: {r.describe()}" for name, r in named) + + @dataclass(frozen=True) class ClampResult: """What the guard did, with the RAW value preserved. @@ -275,10 +284,10 @@ class ClampResult: bound: str = "" # "" | "max_w" | "device" - which stage bit def describe(self) -> str: - return (f"{REASON_CODE}: the computed setpoint {self.requested_w:+.0f} W " - f"was clamped to {self.applied_w:+.0f} W by the {self.bound} " - f"bound (rating {self.limit_w:.0f} W) - something upstream is " - f"winding") + return (f"{REASON_CODE}: asked {self.requested_w:+.0f} W and sent " + f"{self.applied_w:+.0f} W, cut back by " + f"{messages.LIMIT_WORDS.get(self.bound, self.bound)}, with a " + f"{self.limit_w:.0f} W rating") def is_commandable(value) -> bool: diff --git a/goodwe_controller/app/freeze.py b/goodwe_controller/app/freeze.py index 3e1c46d..b07199a 100644 --- a/goodwe_controller/app/freeze.py +++ b/goodwe_controller/app/freeze.py @@ -424,15 +424,17 @@ class FreezeWatchdog: # page was telling, printed into the log and the HA notification where # it would outlive the page. ceiling = rail_ceiling_w(max_w, dev_min=dev_min, dev_max=dev_max) + # UX-10: plain sentences, every figure kept (test_messages.py part 6). capped = ("" if ceiling >= abs(float(max_w)) else f", capped from max_w {float(max_w):.0f} W by the " - f"setpoint device's own rating") + f"inverter's own rating") self.reason = ( - f"METER_FROZEN: the meter has answered {float(unchanged_s):.0f} s " - f"without its measurement changing while the command stands at " - f"{float(commanded_w):+.0f} W, at the {ceiling:.0f} W rail{capped} " - f"(limits: unchanged over {self.cfg.hold_s:.0f} s, command over " - f"{rail_w(max_w, dev_min=dev_min, dev_max=dev_max):.0f} W)") + f"METER_FROZEN: the meter has not changed for " + f"{float(unchanged_s):.0f} s while the command is " + f"{float(commanded_w):+.0f} W, at the {ceiling:.0f} W limit" + f"{capped}. Limits: unchanged over {self.cfg.hold_s:.0f} s, " + f"command over " + f"{rail_w(max_w, dev_min=dev_min, dev_max=dev_max):.0f} W") if self.active: return False self.active = True diff --git a/goodwe_controller/app/freshness.py b/goodwe_controller/app/freshness.py index 4527243..ab81d62 100644 --- a/goodwe_controller/app/freshness.py +++ b/goodwe_controller/app/freshness.py @@ -594,31 +594,28 @@ class Freshness: # ("what did the register do" against "can I trust this entity"). One # helper serving both would have to drop whichever half the other does # not need, and the half it dropped would be the operator's next step. + # UX-10: three plain sentences (test_messages.py part 6). SAFETY-56's + # two explanations stay, in this order, and so does the admission + # that this check cannot tell them apart. The reading is treated as + # missing either way, which the log line around this says. + # ⚠️ SAFETY-57, AND THE THREE DURATIONS ARE THREE DIFFERENT FACTS, each + # in its own slot: the register's unchanged time, the WINDOW this + # verdict actually rests on after a release (`regraded`), and how many + # times this unit has been round the loop. Without the second one the + # sentence reads as though 92 s of unchanged register were what was + # compared against the 35 s limit, and it was not. + regraded = (f", checked {self.releases + 1} times over a {held_s:.0f} s " + f"window since the last stop was withdrawn" + if self.releases else "") self.reason = ( - f"STALE_READING: {self.held:+.0f} unchanged for {shown_s:.0f} s " - f"while the standing command moved {moved_w:.0f} W to " - f"{standing_w:+.0f} W. TWO THINGS LOOK LIKE THIS AND THIS GATE " - f"CANNOT TELL THEM APART: the register may have stopped reporting " - f"reality, or the source may be unable to comply with the command " - f"- a pack the BMS is refusing holds still under any setpoint, and " - f"an honest register then reads exactly like a frozen one. Either " - f"way the number cannot be read as this command's effect, so it is " - f"reported as MISSING rather than as a measurement (limits: " + f"STALE_READING: {self.held:+.0f} W unchanged for {shown_s:.0f} s " + f"while the command moved {moved_w:.0f} W to {standing_w:+.0f} W" + f"{regraded}. The reading may have stopped, or the battery may be " + f"unable to follow the command, and this check cannot tell which. " + f"Limits: " f"unchanged over {self.bound.unchanged_s:.0f} s, command over " f"{self.bound.move_w:.0f} W and moved by over " - f"{self.bound.move_w:.0f} W)") - # ⚠️ SAFETY-57, AND THE THREE DURATIONS ARE THREE DIFFERENT FACTS, each - # in its own slot: the register's unchanged time is in the sentence - # above, the WINDOW this verdict actually rests on is here, and so is - # how many times this unit has been round the loop. Without the second - # one the sentence reads as though 92 s of unchanged register were what - # was compared against the 35 s limit, and it was not. - if self.releases: - self.reason += ( - f" [re-graded: the {held_s:.0f} s window this verdict rests on " - f"opened when the previous one was withdrawn, not when the " - f"register last moved - this unit has now been graded " - f"{self.releases + 1} times]") + f"{self.bound.move_w:.0f} W") def unchanged_s(self, now_mono) -> float | None: """Seconds since an arrival carried a different number. Status page. diff --git a/goodwe_controller/app/hass.py b/goodwe_controller/app/hass.py index c4925db..55945a6 100644 --- a/goodwe_controller/app/hass.py +++ b/goodwe_controller/app/hass.py @@ -16,6 +16,38 @@ _LOG = logging.getLogger("goodwe.hass") CORE_API = "http://supervisor/core/api" SUPERVISOR_API = "http://supervisor" BAD_STATES = ("unknown", "unavailable", "none", "") +# What the Supervisor's proxy answers while Home Assistant restarts. +UNAVAILABLE = (502, 503, 504) + + +class Outage: + """UX-10: Home Assistant not answering, said in one plain line per outage. + + A restart takes the REST API and the meter websocket down together, and + each used to log the library's own text for every entity and service + ("502, message='Bad Gateway', url=URL(...)", "Received message 8:1000 is + not str"). Now the first channel to fail says it once at WARNING, the raw + text goes to DEBUG, and the last channel to recover says so at INFO. + """ + + def __init__(self): + self.down_on = set() + + def down(self, channel: str, what: str, detail) -> None: + if not self.down_on: + _LOG.warning("Home Assistant is not answering (%s), perhaps it is " + "restarting. The add-on keeps trying.", what) + self.down_on.add(channel) + _LOG.debug("Home Assistant not answering on %s: %s", channel, detail) + + def up(self, channel: str) -> None: + if channel in self.down_on: + self.down_on.discard(channel) + if not self.down_on: + _LOG.info("Home Assistant answers again.") + + +OUTAGE = Outage() class HomeAssistant: @@ -58,10 +90,18 @@ class HomeAssistant: async with self.session.get( f"{CORE_API}/states/{entity_id}", headers=self._headers, timeout=10 ) as resp: + if resp.status in UNAVAILABLE: + OUTAGE.down("api", f"error {resp.status}", + f"read {entity_id}: {resp.status}") + return None + OUTAGE.up("api") if resp.status == 404: return None resp.raise_for_status() obj = await resp.json() + except aiohttp.ClientConnectionError as err: + OUTAGE.down("api", "no connection", f"read {entity_id}: {err}") + return None # SAFETY-61: an undecodable body is an absence like any other failed # read, never an exception into the control loop. except (aiohttp.ClientError, TimeoutError, ValueError) as err: @@ -113,6 +153,11 @@ class HomeAssistant: f"{CORE_API}/services/{domain}/{service}", headers=self._headers, json=data, timeout=10, ) as resp: + if resp.status in UNAVAILABLE: + OUTAGE.down("api", f"error {resp.status}", + f"service {domain}.{service}: {resp.status}") + return False + OUTAGE.up("api") if resp.status >= 400: body = await resp.text() # 400 here usually means out-of-range for the entity - the @@ -124,6 +169,10 @@ class HomeAssistant: domain, service, resp.status, body[:200]) return False return True + except aiohttp.ClientConnectionError as err: + OUTAGE.down("api", "no connection", + f"service {domain}.{service}: {err}") + return False # ValueError: an undecodable error body (SAFETY-61) is a failed write. except (aiohttp.ClientError, TimeoutError, ValueError) as err: self._moan(f"svcerr:{domain}.{service}", "service %s.%s failed: %s", diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 7cd312e..340e30c 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -49,8 +49,8 @@ from .circulation import ( circulating_w, opposing, ) from .clamp import ( - BUG_SIGNAL as CLAMP_BUG_SIGNAL, REASON_CODE as CLAMP_REASON, ClampWatchdog, - clamp_to_rating, is_commandable, loop_clamp_note, + REASON_CODE as CLAMP_REASON, ClampWatchdog, + clamp_to_rating, is_commandable, loop_clamp_note, write_clamp_note, ) from . import freshness from . import messages @@ -230,6 +230,22 @@ def pack_energy_of(inv): inv.capacity_kwh, inv.max_w) +def why_key(winner: str, claims) -> str: + """The key of `messages.WHY_WINNER` for a resolution's winner. + + "safety" and "failsafe" each stand for several causes, so for those the + winning claim's own reason is the key ("stopped", "inputs missing", "sign + disagreement"). A failsafe with no claim of its own is the arbiter's "no + claim was made", or main.py's refusal to split the power ("unsplit"). + """ + if winner in ("safety", "failsafe"): + return next((c.reason for c in claims + if c.source == winner and c.kind == "set"), + "no claim was made" if not any( + c.kind == "set" for c in claims) else "unsplit") + return winner + + def tariff_plan_row(plan, tick_words: str, *, age_s, horizon_h: float, provider: bool, max_age_s: float) -> str: """The *Tariff* status row: the 30 s tick's sentence AND the provider plan. @@ -544,7 +560,7 @@ class Controller: # re-arm anything. It is still the difference between a pack that is # recalibrated on schedule and one that silently is not, which is # §12's opening sentence, so it is said where an operator looks. - self.log_event("maintenance history did NOT migrate cleanly: " + self.log_event("maintenance history did not move over cleanly: " + self.maint_migration.explain(), hint=messages.hint("maint_history")) # ⚠️ ONE CONFIG, N MACHINES. The `maintenance_*` options describe the @@ -750,7 +766,7 @@ class Controller: self.peak = PeakTracker(self.peak_store, cap_w=float(opts.get("peak_cap_w", 3500))) self.peak.restore(self.p1.averager) - _LOG.info("capacity-tariff peak store: %s", self.peak.restore_state) + _LOG.info("Month peak store: %s", self.peak.restore_state) # FCST-04. The §8.3 carry-forward store: the published prices of the # last few Brussels days, so the hours a day-ahead feed has not printed @@ -786,7 +802,7 @@ class Controller: # `.words` read below are unguarded, and a cache that raises here is an # add-on that does not start. self.price_history = PriceHistory(price_history_path) - _LOG.info("§8.3 price history: %s", self.price_history.words) + _LOG.info("Price history: %s", self.price_history.words) # SAFETY-07. The guard TARIFF-01 was built for. It is stateless by # design (peakguard.py holds no history between calls), so the only @@ -1071,9 +1087,9 @@ class Controller: """ rep = self.store_migration if rep.ran and not rep.ok: - _LOG.error("The saved safety stops did not copy over cleanly " - "(%s), so they are read again from the older saved " - "state.", rep.explain()) + _LOG.error("The saved safety stops did not copy over cleanly, so " + "they are read again from the older saved state: %s.", + rep.explain()) data = getattr(store, "data", {}) legacy_tripped = bool(data.get("sign_tripped", False)) if not legacy_tripped or not self.inverters: @@ -1678,6 +1694,22 @@ class Controller: """ return packshare.weights(self.pack_energy, target_w) + @property + def why_words(self) -> str: + """The page's "Why" line. While control waits for a missing reading + the age is counted when the page asks (UX-10), not frozen at the age + the last cycle saw.""" + if self._why_waiting_since is not None: + return messages.why_waiting(max(0.0, ( + datetime.now(timezone.utc) + - self._why_waiting_since).total_seconds())) + return self._why_words + + @why_words.setter + def why_words(self, text: str) -> None: + self._why_words = text + self._why_waiting_since = None + @property def inputs_ok(self) -> bool: """The site meter, and EVERY pack's own two readings. @@ -1923,7 +1955,7 @@ class Controller: # ordered pair (time, then power), and the reason still in `%s`. _LOG.error("%s: battery power reading stopped changing. Inverters " "go to 0 W until it changes, or %.0f s after the " - "command drops below %.0f W: %s", + "command drops below %.0f W: %s.", inv.name, inv.batt_fresh.bound.release_s, inv.batt_fresh.bound.move_w, inv.batt_fresh.reason) elif inv.batt_fresh.releases > was_releases: @@ -2078,9 +2110,10 @@ class Controller: f"refusing to broadcast {float(value):+.0f} W to " f"{len(targets)} inverters - that is the ARCH-01 fault; " f"commanding 0 W", hint=messages.hint("all_blocked")) - _LOG.error("Refused to send %+.0f W to all %d inverters at " - "once, so every inverter is set to 0 W. This is a " - "software fault.", float(value), len(targets)) + _LOG.error("Refused to send %+.0f W to all %s at once, so " + "every inverter is set to 0 W. This is a software " + "fault.", float(value), + messages.count(len(targets), "inverter")) _LOG.debug("ARCH-01: a site target handed to each unit is " "supplied by each of them, so the gain at the meter " "becomes N times the per-unit gain. Only 0 W may be " @@ -2203,10 +2236,11 @@ class Controller: # one writer, and this is that writer emitting the value it emits for # every other refusal. if self.shadow and value != shadow.WIRE_W: - _LOG.info("SHADOW MODE: not commanding %+.0f W to %s - holding " - "%+.0f W. The decision was reached and recorded; " - "nothing was sent to the inverter.", - value, inv.name, shadow.WIRE_W) + # UX-10: DEBUG, because it repeats every cycle in shadow mode. The + # INFO line when shadow mode comes on says the same once. + _LOG.debug("Shadow mode: would send %+.0f W to %s, and holds " + "%+.0f W. Nothing was sent to the inverter.", + value, inv.name, shadow.WIRE_W) value = shadow.WIRE_W changed = (inv.last_write is None or value != inv.last_write) @@ -2666,7 +2700,12 @@ class Controller: # A single missed poll is not a fault. Hold, keep the heartbeat # going, and give it a few seconds to come back. self.reason = f"inputs missing {bad_for:.0f}s" + # UX-10: the age is rendered when the page asks, not frozen at + # this cycle's. With the meter reading gone the grid value + # stops changing, so the next cycle is up to cycle_floor_s + # away and the line used to read "0 seconds" all that time. self.why_words = messages.why_waiting(bad_for) + self._why_waiting_since = now - timedelta(seconds=bad_for) return claims = [] @@ -3505,12 +3544,9 @@ class Controller: self.reason = resolution.explain() # UX-08: the same answer in plain words, for the page's "Why" line. # `reason` stays the technical record the log and the checks read. - _why = resolution.winner - if _why in ("safety", "failsafe"): - _why = next((c.reason for c in claims - if c.source == _why and c.kind == "set"), - "no claim was made" if not any( - c.kind == "set" for c in claims) else "unsplit") + # UX-10: `why_key()` maps a safety winner to its claim's reason, and + # every key it can return has words in messages.WHY_WINNER. + _why = why_key(resolution.winner, claims) self.why_words = messages.why(_why, resolution.target_w, resolution.bound_by, contradiction=resolution.contradiction) @@ -3692,7 +3728,9 @@ class Controller: self.o, control_started=self.auto) + f"; inverter held at {shadow.WIRE_W:.0f} W", hint=messages.hint("shadow_on")) - _LOG.warning( + # UX-10: INFO. It follows a setting or a button press, and + # no person has to act on it. + _LOG.info( "Shadow mode is on, so every inverter stays at %.0f W and " "nothing the add-on decides is sent. %s.", shadow.WIRE_W, shadow.why(self.o, control_started=self.auto)) @@ -3701,7 +3739,7 @@ class Controller: "SHADOW MODE OFF - the battery is being controlled again, " f"resuming from {shadow.WIRE_W:.0f} W", hint=messages.hint("shadow_off")) - _LOG.warning( + _LOG.info( "Shadow mode is off, so the add-on controls the battery " "again, starting from %.0f W.", shadow.WIRE_W) if not engaged: @@ -3776,8 +3814,8 @@ class Controller: # SAFETY-40: only an over-rating is a bug; the integrator bound is not. bug = engaged_write or loop_bug if engaged_write: - reason = (", ".join(f"{inv.name}: {inv.clamp_last.describe()}" - for inv in clamped_units) + ". " + CLAMP_BUG_SIGNAL) + reason = write_clamp_note([(inv.name, inv.clamp_last) + for inv in clamped_units]) _named = len(self.inverters) > 1 facts = [messages.Clamp(inv.name if _named else None, inv.clamp_last.requested_w, @@ -3824,16 +3862,19 @@ class Controller: # SAFETY-40: the integrator bound is anti-windup, not a bug - a # WARNING and a plainly titled notice, same cadence. Its OWN id, so # it can never replace a BUG SIGNAL notice still on screen. - _LOG.warning("The battery gives less than asked: %s Held back %d " - "times so far.", self.clamp_wd.reason, - self.clamp_wd.engagements) + _LOG.warning("The battery gives less than asked: %s. Held back %s " + "so far.", self.clamp_wd.reason, + messages.times(self.clamp_wd.engagements)) + _LOG.debug("A short hold after a large load or solar step is " + "normal. If it lasts, check that the battery follows " + "its commands.") await self.hass.call("persistent_notification", "create", messages.loop_bound().data()) return _LOG.error( - "Power request too high, which is a software fault: %s Control is " - "still running. Cut back %d times so far.", - self.clamp_wd.reason, self.clamp_wd.engagements) + "Power request too high, which is a software fault: %s. Control is " + "still running. Cut back %s so far.", + self.clamp_wd.reason, messages.times(self.clamp_wd.engagements)) _LOG.debug( "SAFETY-03: silently clipping this is how a winding integrator " "reached 14 768 W on this project before. The clamp makes every " @@ -3878,7 +3919,7 @@ class Controller: was, self._peak_saturated = self._peak_saturated, saturated if not saturated or was: return - self.log_event("PEAK GUARD SATURATED - " + g.reason, + self.log_event("PEAK_GUARD_SATURATED - " + g.reason, hint=messages.hint("peak_saturated")) _LOG.error( "The battery is asked for all it can give, but this 15-minute " @@ -3933,7 +3974,7 @@ class Controller: was, self._peak_floor_limited = self._peak_floor_limited, limited if not limited or was: return - # No prefix: `reason` already opens with PEAK GUARD FLOOR-LIMITED, and + # No prefix: `reason` already opens with PEAK_GUARD_FLOOR_LIMITED, and # a second copy is the kind of stutter that makes a 40-line action log # read like boilerplate. The saturated path needs its prefix because its # reason carries the word in the middle of a sentence, not at the front. @@ -4217,10 +4258,9 @@ class Controller: if keep: _LOG.warning( "The price update was incomplete (%s), so the plan " - "from %s, %.0f s ago, is kept until it is %.0f s old.", - plan.words, self.tariff_at, - (now - self.tariff_at).total_seconds(), - TARIFF_MAX_AGE_S) + "from %s is kept until it is %s old.", + plan.words, messages.when(brussels(self.tariff_at)), + messages.duration(TARIFF_MAX_AGE_S)) else: self.tariff_plan, self.tariff_at = plan, now _LOG.info("tariff refreshed: %s", plan.words) @@ -4231,8 +4271,9 @@ class Controller: # the same reason and on the same terms. _LOG.warning( "The price update failed (%s), so the plan from %s is kept " - "until it is %.0f s old, and trading stops then.", - err, self.tariff_at, TARIFF_MAX_AGE_S) + "until it is %s old, and trading stops then.", + err, messages.when(brussels(self.tariff_at)), + messages.duration(TARIFF_MAX_AGE_S)) with contextlib.suppress(asyncio.TimeoutError): await asyncio.wait_for(self.stop_event.wait(), timeout=TARIFF_REFRESH_S) @@ -4612,7 +4653,16 @@ class Controller: "text": messages.row_controller_ran(_pass_age)}) if self.p1_enabled: age = self.p1.published_age_s - if self.p1.stale: + if (self.p1.stale and self.p1.age_s() is None + and age <= self.p1.max_age_s): + # UX-10: no reading yet since the start, still inside the + # limit. Amber, not red: it is not a fault yet, but control + # waits for it. Red at 0 s contradicted the limit the row + # prints. Past the limit it is the red row below, as before. + out.append({"ok": False, "warn": True, "id": "meter", + "text": messages.row_meter_waiting( + self.p1.max_age_s)}) + elif self.p1.stale: # The last error is on the add-on log's WARNING line (p1.py). out.append({"ok": False, "warn": False, "id": "meter", "text": messages.row_meter_stale( diff --git a/goodwe_controller/app/maintenance.py b/goodwe_controller/app/maintenance.py index 44848e2..32fe91f 100644 --- a/goodwe_controller/app/maintenance.py +++ b/goodwe_controller/app/maintenance.py @@ -351,7 +351,7 @@ class Maintenance: the action log rather than watching nothing happen. """ if blocked_by: - msg = (f"maintenance: forced start REFUSED on {self.name} - " + msg = (f"maintenance: {self.name} cannot start now, because " f"{blocked_by}") _LOG.warning("%s", msg) return [msg] @@ -378,10 +378,9 @@ class Maintenance: """ if self._deferred != why: self._deferred = why - msg = (f"maintenance: {self.name} is due and is WAITING its turn - " - f"{why}. It is idle under the control loop and will " - f"recalibrate at the next start hour once the slot is free; " - f"this is not a stalled phase.") + msg = (f"maintenance: {self.name} is due and waits its turn, " + f"because {why}. It starts at the next start hour once the " + f"other battery is done. This is not a stalled phase.") _LOG.info("%s", msg) events.append(msg) return events diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index aa69875..e2e4297 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -315,6 +315,17 @@ def times(n) -> str: return "1 time" if int(n) == 1 else f"{int(n)} times" +def count(n, noun, plural=None) -> str: + """`count(1, "price")` -> `1 price`, `count(3, "price")` -> `3 prices`.""" + return f"{int(n)} {noun if int(n) == 1 else plural or noun + 's'}" + + +def when(at) -> str: + """`27 Sep at 09:15`, as the page writes a moment. `at` is already in the + time zone the reader wants (the caller passes `price.brussels(t)`).""" + return f"{at.day} {at:%b} at {at:%H:%M}" + + def for_unit(unit) -> str: """` for inverter-b` on a site with several inverters, else nothing.""" return f" for {unit}" if unit else "" @@ -383,6 +394,11 @@ def row_controller_stalled(age_s, veto_s) -> str: f"sets the inverter to 0 W after {seconds(veto_s)}.") +def row_meter_waiting(limit_s) -> str: + """UX-10: no reading yet since the start, and still inside the limit.""" + return f"Meter: waiting for the first reading, limit {seconds(limit_s)}" + + def row_meter_stale(age_s, limit_s) -> str: return (f"Meter: no reading for {seconds(age_s)}, limit " f"{seconds(limit_s)}. The add-on log shows why.") @@ -766,6 +782,10 @@ WHY_WINNER = { "stopped": "Control is stopped", "inputs missing": "A reading is missing", "no claim was made": "Nothing asked for power", + # UX-10: the claim reasons main.why_key() can return for a safety or + # failsafe winner. test_messages.py part 7 finds every one in the code. + "sign disagreement": "Safety stop, power went the wrong way", + "unsplit": "The power could not be split, all at 0 W", } WHY_LIMIT = { "peak(quarter peak)": "the peak limit", @@ -898,6 +918,7 @@ def status_samples() -> list: ("row_controller_ran", GREEN, row_controller_ran(2)), ("row_controller_stalled", RED, row_controller_stalled(45, 30)), ("row_meter_stale", RED, row_meter_stale(40, 10)), + ("row_meter_waiting", AMBER, row_meter_waiting(30)), ("row_meter", GREEN, row_meter(-350, 2, 3, 340)), ("row_meter_frozen", RED, row_meter_frozen()), *(("row_freeze_off", AMBER, row_freeze_off(k)) for k in FREEZE_OFF), diff --git a/goodwe_controller/app/p1.py b/goodwe_controller/app/p1.py index 6c0f5c8..5632aca 100644 --- a/goodwe_controller/app/p1.py +++ b/goodwe_controller/app/p1.py @@ -48,6 +48,7 @@ from datetime import datetime, timezone import aiohttp from . import messages +from .hass import OUTAGE _S = messages.setting # a refusal names the setting by its label (UX-08) @@ -524,6 +525,16 @@ WS_URL = "ws://supervisor/core/websocket" BAD_STATES = ("unknown", "unavailable", "none", "") +async def _receive_json(ws): + """The next JSON message. A socket Home Assistant closed (a restart) is a + ConnectionResetError, not aiohttp's "Received message 8:1000 is not str".""" + msg = await ws.receive() + if msg.type is not aiohttp.WSMsgType.TEXT: + raise ConnectionResetError( + f"Home Assistant closed the connection ({msg.type.name})") + return json.loads(msg.data) + + class HaDsmrSource: """Subscribes to state_changed for the configured DSMR entities. @@ -574,8 +585,12 @@ class HaDsmrSource: backoff = 1.0 except asyncio.CancelledError: raise + except (aiohttp.ClientError, ConnectionError) as err: + # UX-10: Home Assistant restarting, said once (hass.Outage). + OUTAGE.down("websocket", "the meter connection closed", err) except Exception as err: # noqa: BLE001 - any transport fault retries - _LOG.warning("P1 HA websocket: %s - reconnecting in %.0fs", err, backoff) + _LOG.warning("The meter connection to Home Assistant failed " + "(%s), trying again in %.0f s.", err, backoff) finally: self.connected = False await asyncio.sleep(backoff) @@ -583,16 +598,17 @@ class HaDsmrSource: async def _session_once(self) -> None: async with self.session.ws_connect(WS_URL, heartbeat=30) as ws: - hello = await ws.receive_json() + hello = await _receive_json(ws) if hello.get("type") == "auth_required": await ws.send_json({"type": "auth", "access_token": self.token}) - reply = await ws.receive_json() + reply = await _receive_json(ws) if reply.get("type") != "auth_ok": raise RuntimeError(f"auth rejected: {reply.get('message', reply)}") await ws.send_json({"id": 1, "type": "subscribe_events", "event_type": "state_changed"}) await ws.send_json({"id": 2, "type": "get_states"}) self.connected = True + OUTAGE.up("websocket") _LOG.info("P1 ingest: subscribed to %s", ", ".join(sorted(self.ids))) async for msg in ws: @@ -618,7 +634,7 @@ class HaDsmrSource: new = data.get("new_state") or {} self._absorb(data.get("entity_id"), new.get("state")) self._schedule() - raise RuntimeError("websocket closed") + raise ConnectionResetError("Home Assistant closed the connection") def _absorb(self, entity_id: str | None, state) -> None: if not entity_id or entity_id not in self.ids: diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index 2d0fe88..a6a5084 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -402,27 +402,27 @@ from .tariff import QUARTER_S # Why the projection may not be graded. Reasons, not booleans: the status page # and the action log both have to say WHICH, and "blind" alone is unactionable. -BLIND_NO_BLOCK = "no open quarter - the meter has produced no sample yet" +BLIND_NO_BLOCK = "no open 15-minute period, the meter has given no reading yet" BLIND_COVERAGE = "meter gap" -BLIND_FROZEN = "SAFETY-18: the meter is answering without changing" +BLIND_FROZEN = "the meter is answering without changing" # Where the ceiling came from. Only the second is a relaxation, and only an # OBSERVED reading may produce it. CEILING_CAP = "peak_cap_w" -CEILING_MONTH_PEAK = "the month's banked peak" +CEILING_MONTH_PEAK = "this month's peak" # SAFETY-24. Why the forced discharge may not be sized. Reasons, not booleans, # for BLIND_*'s reason: the status page, the action log and the operator # notification all have to say WHICH, and "floor-limited" alone is unactionable. -FLOOR_SOC_UNREADABLE = ("the battery state of charge was not measured this " - "cycle, and an unreadable SoC is not a full battery") -# ⚠️ SAFETY-25. "the peak guard's SoC floor", not "the SoC floor", and the -# possessive is load-bearing: this string is what the status page, the action log -# and the operator notification all print, and `peak_soc_floor` bounds THIS GUARD -# ONLY. Widening it to "the SoC floor" would make the one sentence an operator -# reads at the moment the battery stops shaving into a claim about the pack that -# the grid-following loop is at that instant disproving. -FLOOR_AT_SOC_FLOOR = "state of charge is at or below the peak guard's SoC floor" +FLOOR_SOC_UNREADABLE = ("the battery level was not read this cycle, and an " + "unread level is not a full battery") +# ⚠️ SAFETY-25. "the peak reserve", not "the SoC floor", and the name is +# load-bearing: this string is what the action log and the add-on log print, +# and `peak_soc_floor` (“Peak reserve”) bounds THIS GUARD ONLY. Widening it to +# "the SoC floor" would make the one sentence an operator reads at the moment +# the battery stops shaving into a claim about the pack that the +# grid-following loop is at that instant disproving. +FLOOR_AT_SOC_FLOOR = "the battery level is at or below the peak reserve" SOURCE = "peak" @@ -566,8 +566,9 @@ def blindness(projection, max_hold_s, frozen: bool) -> str | None: return BLIND_NO_BLOCK gap = uncovered_s(projection) if max_hold_s is not None and gap > float(max_hold_s): - return (f"{BLIND_COVERAGE}: {gap:.0f} s of this quarter uncovered, past " - f"the {float(max_hold_s):.0f} s the averager will hold a sample") + return (f"{BLIND_COVERAGE}, {gap:.0f} s of this 15-minute period not " + f"covered, past the {float(max_hold_s):.0f} s a reading is " + f"held") return None @@ -743,9 +744,9 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, return PeakDecision( engaged=True, floor_w=0.0, ceiling_w=ceiling, ceiling_from=from_where, blind=blind, projected_w=None, - reason=(f"PEAK GUARD BLIND ({blind}) - the battery may not import " - f"while the billed quarter cannot be measured; commanding no " - f"charging (floor 0 W)")) + reason=(f"PEAK_GUARD_BLIND: {blind}. The battery may not charge " + f"while this 15-minute period cannot be measured, so it " + f"is asked for no charging, floor 0 W")) projected = float(projection.projected_w) if batt_w is None: @@ -807,17 +808,18 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, ceiling_from=from_where, projected_w=projected, excess_w=ex, wanted_w=wanted, floor_limited=True, soc=soc, soc_floor=soc_floor, soc_floor_reason=denied, + # UX-10: plain sentences, every figure kept (test_messages.py + # part 6). The code is one token, so it is not read as shouting. reason=( - f"PEAK GUARD FLOOR-LIMITED: the quarter projects " - f"{projected:.0f} W against a {ceiling:.0f} W ceiling " - f"({from_where}) and {wanted:+.0f} W of discharge would hold " - f"it, but {denied}" - + ("" if soc is None else f" ({float(soc):.0f} %") + f"PEAK_GUARD_FLOOR_LIMITED: this 15-minute period heads for " + f"{projected:.0f} W against a {ceiling:.0f} W limit " + f"({from_where}), and {wanted:+.0f} W from the battery would " + f"hold it. But {denied}" + + ("" if soc is None else f", at {float(soc):.0f} %") + ("" if soc is None or soc_floor is None - else f" vs {float(soc_floor):.0f} %") - + ("" if soc is None else ")") - + " - commanding no forced discharge, so THIS QUARTER WILL GO " - "OVER THE CEILING. Charging stays blocked (floor 0 W)")) + else f" against {float(soc_floor):.0f} %") + + ". So there is no forced discharge and no charging, floor " + "0 W, and this period will go over the limit")) floor = min(wanted, ceil_top) saturated = floor < wanted @@ -826,13 +828,13 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, blind=None, projected_w=projected, excess_w=ex, wanted_w=wanted, saturated=saturated, soc=soc, soc_floor=soc_floor, reason=( - f"PEAK GUARD: quarter projects {projected:.0f} W against a " - f"{ceiling:.0f} W ceiling ({from_where}) with " + f"PEAK_GUARD: this 15-minute period heads for {projected:.0f} W " + f"against a {ceiling:.0f} W limit ({from_where}), with " f"{QUARTER_S - projection.elapsed_s:.0f} s left, so {ex:.0f} W must " - f"come off the meter; battery measured {float(batt_w):+.0f} W, " - f"floor {floor:+.0f} W" - + (f" - SATURATED, {wanted:+.0f} W was needed and the inverter can " - f"only give {ceil_top:.0f} W" if saturated else ""))) + f"come off the meter. The battery measured {float(batt_w):+.0f} W " + f"and is asked for {floor:+.0f} W" + + (f". {wanted:+.0f} W was needed, but the inverters give at most " + f"{ceil_top:.0f} W" if saturated else ""))) def charge_headroom_w(decision) -> float | None: diff --git a/goodwe_controller/app/price.py b/goodwe_controller/app/price.py index adeafb3..b1c1ca6 100644 --- a/goodwe_controller/app/price.py +++ b/goodwe_controller/app/price.py @@ -150,6 +150,7 @@ from enum import Enum from textwrap import dedent from urllib.parse import urlencode +from . import messages from .custom_formula import ( EXPORT_FORMULA_OPTION, FormulaInvalid, PREVIEW_HOURS, parse_export_formula, parse_price_formula, preview_lines, price_eur_kwh, to_resolution) @@ -1738,11 +1739,11 @@ def _points_from_columnar_json(body, expect_unit, scale, out.append(RawPoint(start=start, eur_per_kwh=float(v) * scale, provisional=bool(provisional_default))) if dropped: - _LOG.warning("The price feed gave no price for %d of %d times (index " - "%s). Those times are left out, not counted as free.", - len(dropped), len(times), + _LOG.warning("The price feed gave no price for %d of %s, at index " + "%s. Those are left out, not counted as free.", + len(dropped), messages.count(len(times), "time"), ", ".join(str(i) for i in dropped[:5]) - + (", ..." if len(dropped) > 5 else "")) + + (" and more" if len(dropped) > 5 else "")) if not out: raise SourceUnavailable( f"the feed carried {len(times)} instants and a price for none of " @@ -2106,12 +2107,12 @@ async def load_prices(opts: dict, since: datetime, until: datetime, pid = provider_id(opts) if not provider_configured(opts): return PriceRead.no_data( - "no price provider configured (price_provider is 'off'); " - "§11.4: static profile, plan provisional, no arbitrage") + "no price feed is set (price_provider is 'off'), so the fixed " + "tariff is used, the plan is estimated and there is no trading") cls = PROVIDERS.get(pid) if cls is None: return PriceRead.no_data( - f"unknown price provider {pid!r}; shipped: " + f"unknown price provider {pid!r}. The known ones are " f"{', '.join(sorted(PROVIDERS))}") caps = cls.capabilities() diff --git a/goodwe_controller/app/price_forecast.py b/goodwe_controller/app/price_forecast.py index 97fc265..830576f 100644 --- a/goodwe_controller/app/price_forecast.py +++ b/goodwe_controller/app/price_forecast.py @@ -164,6 +164,7 @@ from dataclasses import dataclass from datetime import datetime, timedelta, timezone from enum import Enum +from . import messages from .maintenance import CHARGE_TIMEOUT_MIN, DRAIN_TIMEOUT_MIN from .price import PricePoint, PriceRead, _Outcome, brussels @@ -411,13 +412,14 @@ def fill_from_yesterday(read: PriceRead, *, yesterday: PriceRead, if not out: reason = read.match( - series=lambda r: (f"the {len(r.points)} published hours all fall " - f"outside {since.isoformat()}..{until.isoformat()}"), + series=lambda r: (f"all {messages.count(len(r.points), 'published price')} " + f"fall outside {messages.when(brussels(since))} to " + f"{messages.when(brussels(until))}"), no_data=lambda r: r.reason) return PriceRead.no_data( - f"§8.3 carry-forward produced no hours: {reason}, and yesterday's " - f"profile has nothing to fill them with either. §11.4 applies: " - f"static profile, plan provisional, no arbitrage") + f"no hours could be filled from yesterday's prices: {reason}. So " + f"the fixed tariff is used, the plan is estimated and there is no " + f"trading") _audit(out, published) carried = sum(1 for p in out if _utc_hour(p.start) not in published) @@ -431,10 +433,11 @@ def fill_from_yesterday(read: PriceRead, *, yesterday: PriceRead, # hours" about a 48-hour horizon. The fill's unit is the HOUR and the # feed's is the POINT; nothing derived from one answers for the other. total_h = len({_utc_hour(p.start) for p in out}) - _LOG.info("§8.3: %d of %d hours carried forward from yesterday's " - "profile and flagged provisional; the feed published %d " - "points over the other %d hours", - carried, total_h, len(out) - carried, total_h - carried) + _LOG.info("%s of %d use yesterday's prices, marked as estimated. " + "The feed published %s over the other %s.", + messages.count(carried, "hour"), total_h, + messages.count(len(out) - carried, "price"), + messages.count(total_h - carried, "hour")) product = read.match(series=lambda r: r.product, no_data=lambda _r: yesterday.product) @@ -525,8 +528,8 @@ class _Permitted(Gate): "one rule this type has.") self.action = action self.hours = pts - self.words = (f"{action.name} permitted on {len(pts)} firm hours " - f"({pts[0].start.isoformat()} ..)") + self.words = (f"allowed on {messages.count(len(pts), 'published price')} " + f"from {messages.when(brussels(pts[0].start))}") class _Blocked(Gate): @@ -570,8 +573,8 @@ def price_permits(read: PriceRead, now: datetime, return read.match( series=lambda r: _walk(r, hours, action), no_data=lambda r: Gate.block( - f"{action.name} is gated on a price and there is no price data: " - f"{r.reason}. §11.4 - and a missing price is not a cheap one")) + f"{action.name} needs a price and there is none: {r.reason}. A " + f"missing price is not a cheap one")) def _walk(series, hours, action) -> Gate: @@ -579,19 +582,18 @@ def _walk(series, hours, action) -> Gate: for u in hours: if not series.covers(u): return Gate.block( - f"{action.name} commits {action.commits_h:g} h from " - f"{hours[0].isoformat()} and no price covers " - f"{u.isoformat()}. An hour outside the series is an hour with " - f"no price (§11.4 for that hour), not a free one") + f"{action.name} needs prices for {action.commits_h:g} hours " + f"from {messages.when(brussels(hours[0]))}, and no price " + f"covers {messages.when(brussels(u))}. An hour with no price " + f"is not a free one") p = series.at(u) if p.provisional: return Gate.block( - f"{action.name} commits {action.commits_h:g} h from " - f"{hours[0].isoformat()} and {u.isoformat()} is PROVISIONAL - " - f"carried from yesterday's profile or standing in for a dead " - f"feed. §8.3: no irreversible action may be taken on a " - f"provisional price. It becomes available when the day-ahead " - f"print lands (~14-16 h CET, §5.4)") + f"{action.name} needs prices for {action.commits_h:g} hours " + f"from {messages.when(brussels(hours[0]))}, and the price for " + f"{messages.when(brussels(u))} is only estimated, from " + f"yesterday or from the fixed tariff. It can start once the " + f"day-ahead prices are published, around 14:00 to 16:00") pts.append(p) return Gate.permit(action, pts) @@ -622,5 +624,6 @@ def _go(maint, now, gate) -> Gate: def _no(gate) -> Gate: - _LOG.warning("irreversible action refused - %s", gate.reason) + _LOG.warning("An action that cannot be undone does not start: %s.", + gate.reason) return gate diff --git a/goodwe_controller/app/price_history.py b/goodwe_controller/app/price_history.py index 673d521..e6576db 100644 --- a/goodwe_controller/app/price_history.py +++ b/goodwe_controller/app/price_history.py @@ -186,8 +186,9 @@ import json import logging import os import tempfile -from datetime import datetime, timedelta, timezone +from datetime import date, datetime, timedelta, timezone +from . import messages from .price import PricePoint, PriceProduct, PriceRead, brussels from .price_forecast import fill_from_yesterday @@ -345,8 +346,19 @@ def _row_of(day: str, points: int, hours: int) -> str: whole day to carry, and that is the HOUR figure; the point count says how finely it is priced. Neither answers for the other. """ - return (f"{day} ({points} price{'' if points == 1 else 's'} " - f"over {hours} hour{'' if hours == 1 else 's'})") + # UX-10: the day as the page writes dates ("26 Sep"), not ISO. + return (f"{points} price{'' if points == 1 else 's'} over {hours} " + f"hour{'' if hours == 1 else 's'} for {day_words(day)}") + + +def day_words(day) -> str: + """`'2026-09-26'` -> `'26 Sep'`, as the page writes a date. A key that is + not a date is shown as it is, because this feeds a status row.""" + try: + d = date.fromisoformat(str(day)) + except ValueError: + return str(day) + return f"{d.day} {d:%b}" def _bad_rows(rec) -> int: @@ -393,9 +405,8 @@ class PriceHistory: self.last_error = f"no durable volume at {parent}" # INFO, not ERROR: on a dev host or in a test container there is no # /data and nothing is wrong. - _LOG.info("no price history: %s - §8.3 carry-forward has nothing " - "to carry and the horizon stays as short as the feed", - self.last_error) + _LOG.info("No price history is kept (%s), so missing hours are " + "not filled from yesterday's prices.", self.last_error) return self.ok = True self._load() @@ -449,15 +460,15 @@ class PriceHistory: # would not notice a writer this build has never met. if not isinstance(blob, dict) or isinstance(found, bool) \ or not isinstance(found, int) or found != SCHEMA: - self.last_error = f"schema {found!r}, not {SCHEMA}" - _LOG.warning("price history at %s has %s - discarding it rather " - "than guessing what its points mean", + self.last_error = f"version {found!r}, not {SCHEMA}" + _LOG.warning("Price history at %s has %s, so it is not used.", self.path, self.last_error) return days = blob.get("days") if not isinstance(days, dict): - self.last_error = "no `days` object" - _LOG.warning("price history at %s has %s", self.path, self.last_error) + self.last_error = "no days in it" + _LOG.warning("Price history at %s has %s, so it is not used.", + self.path, self.last_error) return self._days = self._usable_days(days) @@ -504,20 +515,22 @@ class PriceHistory: kept[key] = rec notes = [] if dropped: - notes.append(f"{len(dropped)} unusable day record(s) dropped " - f"({', '.join(sorted(dropped))})") + notes.append(f"{messages.count(len(dropped), 'unusable day')} " + f"dropped, " + ", ".join(day_words(d) + for d in sorted(dropped))) if malformed: notes.append( - f"{sum(malformed.values())} malformed point row(s) in " - + ", ".join(f"{d} ({n})" for d, n in sorted(malformed.items()))) + f"{messages.count(sum(malformed.values()), 'bad price')} in " + + ", ".join(f"{day_words(d)} ({n})" + for d, n in sorted(malformed.items()))) if notes: # Recorded, not silent: `yesterday()` and `words` both report # `last_error`, and a cache that quietly discards half a file reads # to an operator exactly like a normal first day. - self.last_error = "; ".join(notes) - _LOG.warning("price history at %s: %s - the controller starts " - "anyway and the horizon is as short as the feed makes " - "it", self.path, self.last_error) + self.last_error = " and ".join(notes) + _LOG.warning("Price history at %s: %s. The add-on starts anyway, " + "and fills in only what the rest holds.", + self.path, self.last_error) return kept def _save(self) -> bool: @@ -680,10 +693,11 @@ class PriceHistory: # undone with the rest of the merge, so those rows are still in the # file and the next write that completes drops them again. self.last_error = ( - f"{sum(junked.values())} malformed point row(s) dropped from " - + ", ".join(f"{d} ({n})" for d, n in sorted(junked.items()))) - _LOG.warning("price history at %s: %s - the record is rewritten " - "without them and the refresh continues", + f"{messages.count(sum(junked.values()), 'bad price')} dropped " + f"from " + ", ".join(f"{day_words(d)} ({n})" + for d, n in sorted(junked.items()))) + _LOG.warning("Price history at %s: %s. The file is saved without " + "them and the price update goes on.", self.path, self.last_error) self._prune(stamp) if not self._save(): @@ -752,21 +766,23 @@ class PriceHistory: if self.last_error and not self._days: return PriceRead.no_data( f"the price history at {self.path} is {self.last_error}, so " - f"§8.3 has no profile to carry forward for {want}; the plan " - f"covers only the hours the feed published") + f"there are no prices from yesterday to fill in for " + f"{day_words(want)}. The plan covers only the hours the feed " + f"published") rec = self._days.get(want) if rec is None: - have = ", ".join(sorted(self._days)) or "no days at all" + have = (", ".join(day_words(d) for d in sorted(self._days)) + or "no days at all") return PriceRead.no_data( - f"no published prices recorded for {want} (held: {have}), so " - f"§8.3 has no profile to carry forward. A record for another " - f"day is not a yesterday") + f"no published prices are kept for {day_words(want)}, only for " + f"{have}, so there are no prices from yesterday to fill in. A " + f"record for another day is not a yesterday") points, bad = _parse_points(rec.get("points")) if not points: why = bad or "it is empty" return PriceRead.no_data( - f"the {want} record holds no usable point ({why}), and an " - f"empty series is not a free day") + f"the {day_words(want)} record holds no usable price, {why}, " + f"and an empty series is not a free day") try: product = PriceProduct(rec.get("product")) except ValueError: @@ -775,8 +791,9 @@ class PriceHistory: f"which is not a PriceProduct. The optimiser switches on that " f"enum, so a record that cannot name one cannot be a series") if bad: - _LOG.warning("Price history: %s in the %s record were dropped, " - "and %d points were kept.", bad, want, len(points)) + _LOG.warning("Price history: %s dropped from the %s record, and " + "%s kept.", bad, day_words(want), + messages.count(len(points), "price")) return PriceRead.series(points, product, str(rec.get("provider") or "price_history"), stamp) @@ -805,7 +822,7 @@ class PriceHistory: if not self._days: why = f" - {self.last_error}" if self.last_error else "" return f"empty{why} - nothing to carry forward yet" - held = "; ".join(_row_of(d, *_held(self._days[d])) + held = ", ".join(_row_of(d, *_held(self._days[d])) for d in sorted(self._days, key=str)) # A file that PARTLY loaded says so, or the dropped days read as days # that were simply never written. @@ -833,7 +850,7 @@ def _parse_points(raw) -> tuple: continue out.append(pt) out.sort(key=lambda p: p.start.astimezone(timezone.utc)) - return tuple(out), (f"{dropped} malformed point(s)" if dropped else "") + return tuple(out), (messages.count(dropped, "bad price") if dropped else "") class NoHistory: @@ -861,5 +878,5 @@ class NoHistory: def yesterday(self, stamp: datetime) -> PriceRead: return PriceRead.no_data( - "this caller keeps no price history (NoHistory), so §8.3 has no " - "profile to carry forward") + "this caller keeps no price history, so there are no prices from " + "yesterday to fill in") diff --git a/goodwe_controller/app/selfconfig.py b/goodwe_controller/app/selfconfig.py index b2c94d3..5f3b852 100644 --- a/goodwe_controller/app/selfconfig.py +++ b/goodwe_controller/app/selfconfig.py @@ -82,6 +82,7 @@ import os import aiohttp +from . import messages from .configui import changed_keys from .inverter import build_roster from .validate import validate_startup_config, validate_unit_ranges @@ -381,8 +382,9 @@ async def save(selfcfg: SelfConfig, proposed: dict, expect: str, *, """ problems = await problems_for(proposed, hass) if problems: - _LOG.warning("The settings page did not save, because of %d " - "problems. The first: %s", len(problems), problems[0]) + _LOG.warning("The settings page did not save, because of %s. The " + "first: %s", messages.count(len(problems), "problem"), + problems[0]) raise SaveRefused("invalid", problems=problems) info = await selfcfg.info() diff --git a/goodwe_controller/app/static_tariff.py b/goodwe_controller/app/static_tariff.py index 58dcae3..8b30275 100644 --- a/goodwe_controller/app/static_tariff.py +++ b/goodwe_controller/app/static_tariff.py @@ -1130,13 +1130,28 @@ class TariffPlan: PriceProduct.STATIC: "day/night prices", PriceProduct.FIXED: "a fixed price"}.get(self.product, str(self.product)) + # UX-10: the spacing in words, and no "not final yet": a plan is + # provisional exactly when it holds an estimated price, which the + # count already says. gaps = self.spacings_s return (f"{what} from {tag}, " f"{self.n_points} prices over {self.hours} hours, " f"{self.n_firm} published and {self.n_carried} estimated" - + (f", {'+'.join(str(g) for g in gaps)} s apart" - if gaps else "") - + (", not final yet" if self.provisional else "")) + + (f", {spacing_words(gaps)}" if gaps else "")) + + +def spacing_words(gaps) -> str: + """`(900, 3600)` -> `one every 15 minutes or every hour`.""" + def one(s): + s = int(s) + if s == 3600: + return "every hour" + if s % 3600 == 0: + return f"every {s // 3600} hours" + if s % 60 == 0: + return f"every {s // 60} minutes" + return f"every {s} seconds" + return "one " + " or ".join(one(g) for g in gaps) def _whole_hours(points) -> int: @@ -1206,9 +1221,9 @@ def static_plan(opts: dict, since: datetime, until: datetime, *, if profile is None: return TariffPlan( PriceRead.no_data( - "no static_profile configured; §11.4: plan provisional, no " - "arbitrage. Self-consumption, peak shaving and reserve " - "management are unaffected"), + "no fixed tariff is set, so the plan is estimated and there " + "is no trading. Self-consumption, peak limiting and the " + "reserve are not affected"), None, "none") points = profile.series(since, until, provisional=provisional) return TariffPlan( @@ -1338,16 +1353,18 @@ def _degrade(opts, read, since, until, stamp) -> TariffPlan: try: profile = parse_static_profile(price_option(opts, "static_profile")) except ProfileInvalid as e: - _LOG.warning("the price feed is down AND static_profile is unusable " - "(%s), so there is no tariff at all", e) + _LOG.warning("The price feed is down and the fixed tariff " + "(static_profile) cannot be used either (%s), so there is " + "no tariff at all.", e) profile = None if profile is None: - _LOG.warning("%s, and no static_profile is set to fall back to, so " - "prices are provisional and trading is off. Peak " - "limiting and home use go on.", read.reason) + _LOG.warning("The price feed failed: %s. No fixed tariff is set to " + "fall back to, so trading is off. Peak limiting and home " + "use go on.", read.reason) return TariffPlan(read, None, "none") - _LOG.warning("%s, so the static_profile tariff is used instead, marked " - "provisional, and trading is off.", read.reason) + _LOG.warning("The price feed failed: %s. The fixed tariff is used " + "instead, marked as estimated, and trading is off.", + read.reason) points = profile.series(since, until, provisional=True) return TariffPlan( PriceRead.series(points, profile.product, "static_profile", stamp), diff --git a/goodwe_controller/app/store.py b/goodwe_controller/app/store.py index 6ff0cc1..ddc4f05 100644 --- a/goodwe_controller/app/store.py +++ b/goodwe_controller/app/store.py @@ -222,6 +222,8 @@ class MigrationReport: self.misdirected = [] # Why nothing ran, when nothing ran. Empty means "already at schema". self.skipped = "" + # The inverter list the moves were graded against, for `explain()`. + self.roster = [] @property def ok(self) -> bool: @@ -237,19 +239,27 @@ class MigrationReport: # the flat keys ARE its namespace - and an operator reading the # startup log needs to be told which, because only one of them # changes when a second inverter is declared. - return self.skipped or (f"store already at schema " - f"{self.from_version}; no " - f"per-inverter migration needed") - out = (f"migrated {len(self.moved)} flat key(s) to inverter " - f"namespaces: " + ", ".join(sorted(self.moved))) + return self.skipped or (f"the saved state is already at version " + f"{self.from_version}, so nothing moves") + # UX-10: plain sentences (test_messages.py part 6). Each problem is + # named by its key and what went wrong, and `problems`, `lost` and + # `misdirected` keep their full notes for the checks that read them. + n = len(self.moved) + out = (f"moved {n} saved {'value' if n == 1 else 'values'} to one part " + f"per inverter: " + ", ".join(sorted(self.moved)) if n + else "moved nothing") if self.kept: - out += " (left alone, already namespaced: " + ", ".join(sorted(self.kept)) + ")" - if self.problems: - out += " - PROBLEMS: " + "; ".join(self.problems) - if self.lost: - out += " - STATE LOST: " + "; ".join(self.lost) - if self.misdirected: - out += " - WRONG NAMESPACE: " + "; ".join(self.misdirected) + out += ". Already in place: " + ", ".join(sorted(self.kept)) + def keys(notes): + return ", ".join(note.split(" ", 1)[0] for note in notes) + other = [n for n in self.problems + if n not in self.lost and n not in self.misdirected] + parts = ([f"lost {keys(self.lost)}"] if self.lost else []) + ( + [f"moved under an inverter not in the list {self.roster!r}: " + f"{keys(self.misdirected)}"] if self.misdirected else []) + ( + [f"read back differently {keys(other)}"] if other else []) + if parts: + out += ". Problems: " + ", and ".join(parts) return out @@ -436,6 +446,7 @@ def _verify_moves(store, rep: MigrationReport, roster=None) -> None: if roster is None: return names = [str(n) for n in roster] + rep.roster = names # `unit_key()` builds `unit/<unit>/<key>`, so the unit is field 1. Split # through the same spelling the writer used rather than re-deriving it. # @@ -469,8 +480,8 @@ def _verify_moves(store, rep: MigrationReport, roster=None) -> None: if unit in names: continue rep.verified = False - note = (f"{target} was migrated into namespace {unit!r}, which is NOT " - f"on the roster {names!r} - nothing reads that key") + note = (f"{target} was moved under {unit!r}, which is not in the " + f"inverter list {names!r}, so nothing reads it") rep.problems.append(note) rep.misdirected.append(note) @@ -536,14 +547,13 @@ def migrate_maint_keys(store, unit: str, roster) -> MigrationReport: names = [str(n) for n in roster] rep.from_version = int(data.get(MAINT_SCHEMA_KEY, 0) or 0) if len(names) <= 1: - rep.skipped = ("one inverter: the flat maintenance keys ARE that pack's " - "history and are read in place, so there is nothing to " - "move and the store layout does not change") + rep.skipped = ("one inverter, so its maintenance history is read " + "where it is and nothing moves") return rep if rep.from_version >= MAINT_SCHEMA_VERSION: - rep.skipped = (f"maintenance history already at schema " - f"{rep.from_version}; written by a multi-inverter " - f"version and not touched") + rep.skipped = (f"maintenance history already at version " + f"{rep.from_version}, written for several inverters, so " + f"it is left as it is") return rep rep.ran = True @@ -567,8 +577,8 @@ def migrate_maint_keys(store, unit: str, roster) -> MigrationReport: # the re-run a no-op where the keys did land, so refusing the marker # costs one repeated pass and buys the difference between a migration # that can still be fixed and one the store says already happened. - _LOG.error("per-pack maintenance-history migration did NOT land and " - "has not been marked done: %s", rep.explain()) + _LOG.error("Moving the maintenance history to one part per inverter " + "did not work, so it is not marked done: %s", rep.explain()) return rep diff --git a/goodwe_controller/app/tariff.py b/goodwe_controller/app/tariff.py index ee7283f..f0463e0 100644 --- a/goodwe_controller/app/tariff.py +++ b/goodwe_controller/app/tariff.py @@ -114,6 +114,8 @@ import sqlite3 from dataclasses import dataclass from datetime import datetime, timedelta, timezone, tzinfo +from . import messages + _LOG = logging.getLogger("goodwe.tariff") QUARTER_S = 900 @@ -339,8 +341,8 @@ class PeakStore: # INFO, not ERROR: on a dev host or in a test container there is no # /data and nothing is wrong. A store that OPENED and then broke is # the error case, and it is logged as one below. - _LOG.info("no peak store: %s - the monthly peak will read " - "NOT_OBSERVED", self.last_error) + _LOG.info("No peak store (%s), so the month peak cannot be read " + "and only the peak limit is used.", self.last_error) return try: self._db = sqlite3.connect(self.path, timeout=5.0, @@ -360,8 +362,9 @@ class PeakStore: # fault must not stop a controller that is regulating a battery. The # cost of continuing is a peak that reads NOT_OBSERVED, and every # reader is built to treat that as "do not use me", not as 0 W. - _LOG.error("peak store unusable at %s (%s) - the monthly peak will " - "read NOT_OBSERVED, which is not a zero peak", self.path, err) + _LOG.error("The peak store at %s cannot be used (%s), so only the " + "peak limit is used. The month peak is unknown, not " + "zero.", self.path, err) def close(self) -> None: if self._db is not None: @@ -672,12 +675,12 @@ class PeakTracker: now = now or datetime.now(timezone.utc) snap = self.store.load_partial() if not snap: - self.restore_state = ("fresh: no checkpoint" if self.store.ok - else "fresh: store unreadable") + self.restore_state = ("fresh start, nothing saved" if self.store.ok + else "fresh start, the store cannot be read") return self.restore_state block = snap.get("block") if block is None: - self.restore_state = "fresh: checkpoint had no open block" + self.restore_state = "fresh start, no open 15-minute period saved" return self.restore_state current = int(now.timestamp() // QUARTER_S) * QUARTER_S @@ -686,11 +689,13 @@ class PeakTracker: # A reshaped accumulator (meter_phases changed) is a different # measurement, not a resumable one. Say so; do not half-resume. self.store.clear_partial() - self.restore_state = "fresh: checkpoint does not fit this averager" + self.restore_state = ("fresh start, the saved period does not " + "fit the number of phases") return self.restore_state self.restore_state = ( - f"resumed the open block at {snap.get('elapsed', 0.0):.0f} s " - f"of {QUARTER_S} s ({snap.get('acc', 0.0) / QUARTER_S:.0f} W banked)") + f"resumed the open 15-minute period at " + f"{snap.get('elapsed', 0.0):.0f} s of {QUARTER_S} s, with " + f"{snap.get('acc', 0.0) / QUARTER_S:.0f} W counted so far") return self.restore_state # The block ended while the add-on was down. Its measured part really @@ -704,10 +709,14 @@ class PeakTracker: if snap.get("pp_acc") and snap.get("last_pp") else None)) banked = self.store.record_block(closed, self.policy) self.store.clear_partial() + # UX-10: plain words and the local time, not ISO and "banked". self.restore_state = ( - f"closed a stale block from {closed.start.isoformat()} at " - f"{closed.offtake_avg_w:.0f} W (partial coverage), " - + ("banked" if banked else "NOT banked - store unwritable")) + f"closed the 15-minute period from " + f"{messages.when(closed.start.astimezone(BILLING_TZ))} at " + f"{closed.offtake_avg_w:.0f} W, partly measured, " + + ("and saved it" if banked + else "but could not save it, because the store cannot be " + "written")) return self.restore_state # -- steady state ------------------------------------------------------- diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 2ab7a0b..f006133 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -343,6 +343,30 @@ from .watchdog import SIGN_OPTION_DEFAULTS _LOG = logging.getLogger("goodwe.config") + +class _WarnOnce(logging.Filter): + """UX-10: a settings warning is said once per start. The validator runs + twice at start (before the first cycle and again once the inverter's range + is known), and a warning about options that have not changed is the same + news both times. Refusals are ERROR and pass untouched.""" + + def __init__(self): + super().__init__() + self.seen = set() + + def filter(self, record): + if record.levelno != logging.WARNING: + return True + text = record.getMessage() + if text in self.seen: + return False + self.seen.add(text) + return True + + +WARN_ONCE = _WarnOnce() +_LOG.addFilter(WARN_ONCE) + # ⚠️ A MIRROR OF A FIRMWARE CONSTANT, AND IT CANNOT BE IMPORTED. The firmware # threshold is a compile-time YAML substitution baked into the ESP32 image # (`max_age_s: "30"`, master/goodwe-master-stage4-failsafe.yaml), so nothing at @@ -1314,12 +1338,11 @@ def _price_problems(opts: dict) -> list[str]: if profile is not None and profile.product is not None \ and len(set(profile.prices)) == 1: _LOG.info( - "static_profile carries one distinct price (%.4f EUR/kWh " - "all-in), so this site is priced as FULLY FIXED. Arbitrage is " - "off by arithmetic - a flat series has no spread - and the " - "add-on runs self-consumption only, which is §9.2's handling " - "for this product. Peak shaving, reserve management and the " - "maintenance cycle are unaffected.", profile.prices[0]) + "static_profile has one price (%.4f EUR/kWh all-in), so this " + "site has a fully fixed price. A flat price has no spread to " + "trade on, so the add-on uses the battery for self-consumption " + "only. Peak limiting, the reserve and battery maintenance are " + "not affected.", profile.prices[0]) # ⚠️ TARIFF-17: THE TAXES PERIOD TABLE, PARSED AT STARTUP RATHER THAN AT # 03:00, FOR `static_profile`'s REASON ONE OPTION OVER. This table is read @@ -1505,9 +1528,9 @@ def _price_problems(opts: dict) -> list[str]: _LOG.info( "%s is set: injection priced as (%g x index %+g) x " "(1 + %g/100) %s, i.e. %.4g x the wholesale price with a " - "%+.5f EUR/kWh offset. ⚠️ NO STRATEGY IN THIS ADD-ON READS " - "IT: arbitrage.py prices the sell side as displaced IMPORT " - "and compares two all-in CONSUMPTION prices, so this option " + "%+.5f EUR/kWh offset. No part of the add-on reads it yet: " + "trading prices the sell side as displaced import and " + "compares two all-in consumption prices, so this setting " "changes no decision the add-on takes today. It is what you " "are shown, and the shape a future export-aware strategy " "would read.", diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index 62b516b..a774fa3 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -304,8 +304,16 @@ def build_app(controller, selfcfg=None) -> web.Application: return app +def access_log(): + """UX-10: the page polls /status every few seconds, and aiohttp logs each + request at INFO. That access log is kept for a DEBUG log level only.""" + return (logging.getLogger("aiohttp.access") + if _LOG.isEnabledFor(logging.DEBUG) else None) + + async def start(controller, port: int = 8099, selfcfg=None): - runner = web.AppRunner(build_app(controller, selfcfg)) + runner = web.AppRunner(build_app(controller, selfcfg), + access_log=access_log()) await runner.setup() site = web.TCPSite(runner, "0.0.0.0", port) await site.start() diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index c3f355c..a738c51 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -1037,7 +1037,8 @@ check("...and the operator is told WHICH bound bit, so a device-rating clamp " and messages.LIMIT_WORDS["device"] in notes_w[0]["message"] and messages.LIMIT_WORDS["max_w"] not in notes_w[0]["message"]) check("...and the action log carries the row, written by write_setpoint()", - any(REASON_CODE in e and "device bound" in e for e in ctl_w.events)) + any(REASON_CODE in e and messages.LIMIT_WORDS["device"] in e + for e in ctl_w.events)) # The same stimulus, the same clamp, the two calls swapped. This is the ticket # in one pair of runs. @@ -1125,8 +1126,8 @@ check("⚠️ THE ORDERED PAIR IN THE §15 ACTION-LOG ROW (main.py:1366). The " "the loop asked for +2000 W and the guard clamped it UP to +9999 W - " "past the 2000 W rating printed four words later - which is the alarm " "reading backwards on the one line an operator is woken by", - any(f"the computed setpoint {_asked_x:+.0f} W was clamped to " - f"{_sent_x:+.0f} W" in e for e in _rows_x)) + any(f"asked {_asked_x:+.0f} W and sent {_sent_x:+.0f} W" in e + for e in _rows_x)) # UX-08: the notification is a SECOND surface off the same numbers, in its own # words (messages.output_clamp): asked first, sent second. def _asked_then_sent(msg, asked, sent): @@ -1142,8 +1143,8 @@ check("⚠️ ...AND IN THE ClampWatchdog NOTIFICATION, which is a SECOND surfac bool(notes_x) and _asked_then_sent(notes_x[0]["message"], _asked_x, _sent_x)) check("...and the TRANSPOSED sentence appears on NEITHER surface, so the two " "checks above discriminate rather than decorate", - not any(f"the computed setpoint {_sent_x:+.0f} W was clamped to " - f"{_asked_x:+.0f} W" in e for e in _rows_x) + not any(f"asked {_sent_x:+.0f} W and sent {_asked_x:+.0f} W" in e + for e in _rows_x) and not _asked_then_sent(nth(notes_x, 0)["message"], _sent_x, _asked_x) and present(nth(notes_x, 0))) # The DEVICE bound, off part 6c's controller: same sentence, other stage. The @@ -1154,8 +1155,8 @@ check("...and the same ordered pair holds on the DEVICE-bound row, where the " "loop asked for +3000 W and the device took +2500 W. PRECONDITION: those " "two also render differently", f"{_asked_w:+.0f}" != f"{_sent_w:+.0f}" - and any(f"the computed setpoint {_asked_w:+.0f} W was clamped to " - f"{_sent_w:+.0f} W" in e for e in ctl_w.events) + and any(f"asked {_asked_w:+.0f} W and sent {_sent_w:+.0f} W" in e + for e in ctl_w.events) and _asked_then_sent(nth(notes_w, 0)["message"], _asked_w, _sent_w)) @@ -2028,10 +2029,11 @@ check("PRECONDITION: the integrator bound engaged, and on a tick where the " "carried integrator AND the emitted command both differ from the bound", any(d.i_w != _f(d, 'i_bound_w') and d.target_w != _f(d, 'i_bound_w') for d, t, r in wind)) -check("defect 1: the integrator bound is NOT reported as a BUG SIGNAL", - wind and all("BUG SIGNAL" not in r for d, t, r in wind)) -check("defect 1: ...it names the anti-windup bound, from the same tick", - wind and all(f"its {_f(d, 'i_bound_w'):+.0f} W anti-windup bound" in r +check("defect 1: the integrator bound is NOT reported as an over-rating", + wind and all(" rating" not in r and "fault" not in r + for d, t, r in wind)) +check("defect 1: ...it names the integrator's bound, from the same tick", + wind and all(f"reached its {_f(d, 'i_bound_w'):+.0f} W limit" in r for d, t, r in wind)) check("defect 2: the integrator accumulator is not printed as a request", wind and all(f"{d.i_w:+.0f} W" not in r and "asked for" not in r @@ -2050,7 +2052,7 @@ check("...under its OWN notification_id, so it cannot replace a BUG SIGNAL " "notice still on screen", notes_i and all(n["notification_id"] == BOUND_ID for n in notes_i)) check("...logged as a WARNING, not an ERROR", - any(x.levelno == logging.WARNING and "anti-windup" in x.getMessage() + any(x.levelno == logging.WARNING and "reached its" in x.getMessage() for x in log_i) and not any(x.levelno >= logging.ERROR and "OUTPUT_CLAMP" in x.getMessage() for x in log_i)) @@ -2070,12 +2072,13 @@ for d, t, r in over[:2]: check("PRECONDITION: the output clamp engaged on a tick where the slew limit " "rewrote the command AND the integrator differs from the request", any(t != _f(d, 'clamped_w') and d.i_w != _f(d, 'requested_w') for d, t, r in over)) -check("the over-rating KEEPS the BUG SIGNAL", - over and all("BUG SIGNAL" in r for d, t, r in over)) +check("the over-rating says it went over the rating", + over and all(" rating, and cut it back to " in r for d, t, r in over)) check("defect 2: it quotes the requested COMMAND of that tick, not i_w", over and all(f"computed {_f(d, 'requested_w'):+.0f} W" in r for d, t, r in over)) -check("defect 3: 'clamped to' is the clamp's own result, not self.target", - over and all(f"clamped to {_f(d, 'clamped_w'):+.0f} W" in r for d, t, r in over)) +check("defect 3: 'cut it back to' is the clamp's own result, not self.target", + over and all(f"cut it back to {_f(d, 'clamped_w'):+.0f} W" in r + for d, t, r in over)) check("...and its ERROR says it is a software fault and that control keeps " "running (UX-08 2d moved the 14 768 W rationale to a DEBUG line beside " "it, which is still in main.py)", diff --git a/goodwe_controller/test_freshness.py b/goodwe_controller/test_freshness.py index 65dd36b..f09515c 100644 --- a/goodwe_controller/test_freshness.py +++ b/goodwe_controller/test_freshness.py @@ -1644,9 +1644,8 @@ check("...and a re-trip's reason names the TWO durations separately, each " [f.submit(A_FROZEN_W, 1300.0, float(t)) for t in range(80, 130)], f.stale and f.releases == 1 and "unchanged for 92 s" in f.reason - and "the 35 s window this verdict rests on opened when the previous " - "one was withdrawn" in f.reason - and "graded 2 times" in f.reason)[-1])( + and "checked 2 times over a 35 s window since the last stop was " + "withdrawn" in f.reason)[-1])( Freshness(BOUNDS["batt"]))) @@ -1799,8 +1798,8 @@ check("...and the two runs were driven at 50 % and 11 % SoC and the sentence " # bytes, and "the register may be unable to comply / the source may have # stopped reporting reality" is a different and wrong claim. _S56_EXPLANATIONS = [ - ("DEAD", "the register may have stopped reporting reality"), - ("REFUSED", "the source may be unable to comply with the command"), + ("DEAD", "reading may have stopped"), + ("REFUSED", "battery may be unable to follow the command"), ] # ⚠️ WHAT THE THREE SENTENCES USED TO ASSERT. Each is a claim about the # REGISTER or about the ENTITY, and 11a measured the register to be alive on @@ -1868,7 +1867,7 @@ check(f"11c. BOTH EXPLANATIONS ARE NAMED, AND IN THAT ORDER: " check("...and the sentence says in its own words that it CANNOT choose, rather " "than leaving two explanations side by side for a reader to rank - an " "operator who reads a list picks the first item", - "CANNOT TELL THEM APART" in _r56_ref) + "this check cannot tell which" in _r56_ref) # ⚠️ THE POSITIVE CONTROL FOR THE `not any(...)` BELOW, AND IT IS NOT OPTIONAL: # a quantifier over an empty list is True, and so is one over three literals # with a typo in each. These are the three sentences as 0.10.1 SHIPPED them, diff --git a/goodwe_controller/test_maintenance.py b/goodwe_controller/test_maintenance.py index 9d35cf9..2f492b6 100644 --- a/goodwe_controller/test_maintenance.py +++ b/goodwe_controller/test_maintenance.py @@ -497,7 +497,7 @@ check("a FORCED start is refused while another pack holds the slot, and the " "phase machine does not move. The calendar is a preference an operator " "may overrule; one pack at a time is a property of the grid connection " "and a button does not add a second one", - _b8.phase == IDLE and len(_ev) == 1 and "REFUSED" in _ev[0] + _b8.phase == IDLE and len(_ev) == 1 and "cannot start now" in _ev[0] and "inverter-a" in _ev[0]) check("...and an unblocked forced start still works, so the refusal is a " "condition and not a disabled feature", @@ -534,7 +534,7 @@ check("...and the deferred pack's PHASE does not move either, so " _b9.phase == IDLE and _b9.store.get_time("phase_started") is None) check("...and the words say WAITING, name the pack it waits for, and say it " "will run next - none of which any failure path in this module says", - "WAITING" in _r9[1].events[0] + "waits its turn" in _r9[1].events[0] and "inverter-a" in _r9[1].events[0] and "not a stalled phase" in _r9[1].events[0] and "ABORT" not in _r9[1].events[0] and "stuck" not in _r9[1].events[0]) @@ -687,7 +687,7 @@ print(f" a store already written by a multi-inverter version: {_rep3.explain( check("a store already at the per-pack schema is NOT TOUCHED - not one key " "written - and says so", not _rep3.ran and _m3.data == _before3 and _m3.writes == [] - and "not touched" in _rep3.explain()) + and "left as it is" in _rep3.explain()) # ⚠️ AND BREAK IT. The read-back postcondition is the whole difference between # this and a two-line copy, and it is inherited from `migrate_unit_keys()` @@ -766,7 +766,7 @@ check("...and the refusal NAMES the namespace it used AND the roster it was " "graded against, rather than merely saying something went wrong - the " "operator's next question is 'which name, and which one should it have " "been', and a bare `not ok` answers neither", - "WRONG NAMESPACE" in _rep5.explain() + "moved under an inverter not in the list" in _rep5.explain() and unit_key(UNIT_A, "last_completed") in _rep5.explain() and repr(ROSTER) in _rep5.explain()) check("⚠️ AND THE MARKER IS NOT STAMPED, WHICH IS THE WHOLE REMEDY. A stamped " @@ -893,7 +893,7 @@ check("...and the counterfactual: the SAME two calls with the roster's own " "`already at schema` early return, not a refusal. So 9c is about the " "NAME surviving into the second start, not about second calls", _rep7ok_a.ok and _m7ok.data[MAINT_SCHEMA_KEY] == MAINT_SCHEMA_VERSION - and _rep7ok_b.ran is False and "already at schema" in _rep7ok_b.explain()) + and _rep7ok_b.ran is False and "already at version" in _rep7ok_b.explain()) # --------------------------------------------------------------------------- # diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index d9cf7c8..541b189 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -580,7 +580,7 @@ check(f"every event the add-on records gives the page its plain words, from " f"messages.hint() ({_calls} calls, without: {_bare})", _calls >= 40 and not _bare) _raw = ("OUTPUT_CLAMP", "BUG SIGNAL", "FAILSAFE", "SIGN_DISAGREEMENT", - "ALLOCATOR", "UNMET", "ARBITER", "PEAK GUARD") + "ALLOCATOR", "UNMET", "ARBITER", "PEAK GUARD", "PEAK_GUARD") check("no hint carries the raw event codes the page used to show", not [t for _k, t in messages.hint_samples() if any(r in t for r in _raw)]) @@ -796,6 +796,656 @@ _bad = ast.parse("await self.hass.call('persistent_notification', 'create', " check("a hand-written notification payload is seen by part 2", any(not (isinstance(c.args[2], ast.Call)) for c in notification_calls(_bad))) + +# ============================================================================== # +print("\n6. log lines as they are built at run time (UX-10)") +# Part 3 reads a WARNING+ line's own literal and counts each placeholder as one +# word. So a reason text built elsewhere and passed in as `%s` was never seen: +# the 2d test found "…clamped to +2000 W; … This is a BUG SIGNAL … Cut back 1 +# times" in the log while part 3 was green, because `loop_clamp_note()` built +# it. This part closes that gap in two steps. +# a. Every dynamic part of every WARNING+ line in `app/` is classified here, +# as data (a number, a name, a path, an exception's own text) or as a text +# the add-on builds. A new dynamic part that is in neither list fails, so a +# new builder cannot slip past. +# b. Every built text is produced by the real code and checked. It is the +# evidence behind an alarm, so it gets the red-alarm shape: at most 3 +# sentences of at most 30 words, 70 in all. It keeps its reason code. The +# whole line, as logged, may carry no semicolon, banned term, capitals, +# "1 times", "(s)" or a doubled full stop. +from datetime import datetime as _dt, timedelta as _td, timezone as _tz # noqa: E402 + +from app import clamp as _clamp, freshness as _fresh, peakguard as _pg # noqa: E402 +from app import store as _store # noqa: E402 +from app.circulation import CirculationConfig, CirculationWatchdog # noqa: E402 +from app.control import Tuning, compute # noqa: E402 +from app.delivery import (DeliveryConfig, DeliveryWatchdog, UnitDelivery, # noqa: E402 + delinquent) +from app.freeze import FreezeWatchdog, FreezeWatchdogConfig # noqa: E402 +from app.price import PricePoint, PriceProduct, PriceRead # noqa: E402 +from app.static_tariff import TariffPlan # noqa: E402 +from app.tariff import Projection # noqa: E402 +from app.watchdog import (AGAINST_METER, AGAINST_OWN_POWER, SignWatchdog, # noqa: E402 + SignWatchdogConfig) + +_T0 = _dt(2026, 9, 27, 9, 0, tzinfo=_tz.utc) +PLURAL = re.compile(r"\b1 [a-z]{2,}s\b(?<!\b1 [a-z]ss)|\w\(s\)") +COUNT_PLURAL = re.compile(r"%d [a-z]{2,}s\b") + + +def dynamic_parts(tree, fname): + """(key, call) for every dynamic part of a WARNING+ log call in `tree`.""" + for node in ast.walk(tree): + if not isinstance(node, ast.Call): + continue + name = ast.unparse(node.func) + moan = name.endswith("._moan") + if not (LOG_CALL.search(name) or moan): + continue + i = 1 if moan else 0 + if len(node.args) <= i: + continue + fmt = node.args[i] + parts = [ast.unparse(a) for a in node.args[i + 1:]] + if isinstance(fmt, ast.JoinedStr): + parts += [ast.unparse(v.value) for v in fmt.values + if isinstance(v, ast.FormattedValue)] + elif not (isinstance(fmt, ast.Constant) and isinstance(fmt.value, str)): + parts.append(ast.unparse(fmt)) + for part in parts: + yield f"{fname}:{part}", node + + +# a. DATA: shown as it is, never worded by the add-on. An exception's text is +# the library's (hass.py words the Home Assistant ones, UX-10 item 3). +DATA = { + # hass.py: the _moan() wrapper and what its callers pass + "hass.py:msg", "hass.py:*args", "hass.py:entity_id", "hass.py:err", + "hass.py:obj", "hass.py:raw", "hass.py:domain", "hass.py:service", + "hass.py:resp.status", "hass.py:body[:200]", "hass.py:what", + # main.py + "main.py:'cancelled' if task.cancelled() else repr(exc) if exc else 'returned'", + "main.py:EXIT_CONTROL_DIED", "main.py:first.name", "main.py:OPTIONS_PATH", + "main.py:err", "main.py:', '.join(sorted(stranded))", + "main.py:sorted(on_roster)", "main.py:inv.name", + "main.py:inv.batt_fresh.bound.release_s", "main.py:inv.batt_fresh.bound.move_w", + "main.py:inv.batt_fresh.bound.unchanged_s", "main.py:inv.batt_fresh.held", + "main.py:value", "main.py:float(value)", + "main.py:entity", "main.py:WRITE_BUDGET_S", + "main.py:_e", + "main.py:messages.times(self.clamp_wd.engagements)", + "main.py:messages.when(brussels(self.tariff_at))", + "main.py:messages.duration(TARIFF_MAX_AGE_S)", + "main.py:messages.count(len(targets), 'inverter')", + # maintenance.py, mqtt.py, p1.py + "maintenance.py:phase", "mqtt.py:err", "p1.py:err", "p1.py:self.host", + "p1.py:self.topic", "p1.py:poll_s", "p1.py:ingest.max_age_s", + "p1.py:backoff", "p1.py:self.url", "p1.py:str(err) or type(err).__name__", + "p1.py:self.poll_s", + # price.py + "price.py:doc.get('deprecated')", "price.py:len(dropped)", + "price.py:messages.count(len(times), 'time')", "price.py:plugin_id", + "price.py:override", + "price.py:', '.join((str(i) for i in dropped[:5])) + (' and more' if len(dropped) > 5 else '')", + "price.py:*(d.isoformat() for d in brussels_date_range(since, until))", + "price.py:pid", + "price.py:'/'.join(sorted((c.value for c in caps.sources - {Component.ENERGY})))", + "price.py:' and '.join(ignored) + (' is' if len(ignored) == 1 else ' are')", + "price.py:getattr(cls, 'id', cls)", "price.py:e", "price.py:type(e).__name__", + # price_history.py, selfconfig.py, static_tariff.py, store.py, tariff.py + "price_history.py:self.path", "price_history.py:day_words(want)", + "price_history.py:messages.count(len(points), 'price')", + "price_history.py:err", + "selfconfig.py:messages.count(len(problems), 'problem')", + "selfconfig.py:', '.join(changed) or 'none this page also edited'", + "static_tariff.py:e", "store.py:err", "store.py:key", "store.py:raw", + "tariff.py:self.path", "tariff.py:err", "tariff.py:start", "tariff.py:month", + # validate.py: option values and keys (the refusals are part 3's) + "validate.py:integ_w", "validate.py:max_w", "validate.py:disch_w", + "validate.py:maint_where", "validate.py:maint_cap", "validate.py:pid", + "validate.py:i", "validate.py:TAXES_PROFILE_OPTION", "validate.py:negative", + "validate.py:EXPORT_FORMULA_OPTION", "validate.py:xspec.passthrough", + "validate.py:xspec.offset_eur_kwh", "validate.py:'=' * 72", + "validate.py:'-' * 72", + "web.py:err", +} + + +# b. BUILT TEXT: each producer, run for real. A reason that is only ever +# stored and restored (a saved safety stop) is produced by the same builder. +def _sign(against, cmd=1500.0, got=-1400.0): + wd = SignWatchdog(SignWatchdogConfig(min_w=250.0, hold_s=60.0), + against=against) + for s in (0, 61): + wd.evaluate(cmd, got, True, _T0 + _td(seconds=s)) + return wd.reason + + +def _sign_texts(): + return [_sign(AGAINST_METER), _sign(AGAINST_OWN_POWER, -1100.0, 2000.0)] + + +def _circ_texts(): + wd = CirculationWatchdog(CirculationConfig(min_w=250.0, hold_s=60.0)) + for s, w in ((0, 5200.0), (30, 6000.0), (61, 5800.0)): + wd.evaluate(w, _T0 + _td(seconds=s)) + return [wd.reason] + + +def _delivery_texts(): + units = [UnitDelivery("inverter-a", 1000.0, 990.0), + UnitDelivery("inverter-b", 2000.0, 0.0)] + sentence = delinquent(units, 200.0)["inverter-b"] + wd = DeliveryWatchdog(DeliveryConfig(hold_s=120.0)) + for s in (0, 121): + wd.evaluate(sentence, _T0 + _td(seconds=s)) + return [wd.reason] + + +def _freeze_texts(): + out = [] + for dev in (None, 4700.0): + wd = FreezeWatchdog(FreezeWatchdogConfig(hold_s=600.0)) + wd.evaluate(3600.0, 4480.0 if dev else 5000.0, 5000.0, _T0, + dev_min=-dev if dev else None, dev_max=dev) + out.append(wd.reason) + return out + + +def _stale_texts(): + one = _fresh.Freshness(_fresh.BOUNDS["batt"]) + for t in range(0, 40): + one.submit(-1200.0, -1200.0 if t < 1 else 1300.0, float(t)) + two = _fresh.Freshness(_fresh.BOUNDS["batt"]) + for t in range(0, 40): + two.submit(-1200.0, -1200.0 if t < 1 else 1300.0, float(t)) + for t in range(40, 80): + two.submit(-1200.0, 0.0, float(t)) + for t in range(80, 130): + two.submit(-1200.0, 1300.0, float(t)) + return [one.reason, two.reason] + + +def _clamp_texts(): + over = compute(prev_w=1000.0, grid_w=9000.0, actual_w=1000.0, + tuning=Tuning(max_w=5000.0, slew_w=1000.0, gain=0.6, + integrator_max_w=9000.0), i_w=8000.0) + at = compute(prev_w=1000.0, grid_w=9000.0, actual_w=1000.0, + tuning=Tuning(max_w=5000.0, slew_w=1000.0, gain=0.6), + i_w=4500.0) + write = [(n, _clamp.clamp_to_rating(w, 5000.0, -2500.0, 2500.0)) + for n, w in (("inverter-a", 3000.0), ("inverter-b", -7412.0))] + return [_clamp.loop_clamp_note(over), _clamp.loop_clamp_note(at), + _clamp.write_clamp_note(write[:1]), _clamp.write_clamp_note(write)] + + +def _peak_texts(): + proj = Projection(projected_w=4338.0, elapsed_w=4338.0, elapsed_s=799.0, + covered_frac=1.0, complete=False, block_start=_T0, + held_w=0.0) + kw = dict(cap_w=3500.0, reading=None, soc_floor=30.0, max_hold_s=30.0) + sat = _pg.decide(proj, batt_w=1500.0, achievable_w=5000.0, soc=80.0, **kw) + low = _pg.decide(proj, batt_w=1500.0, achievable_w=5000.0, soc=20.0, **kw) + unread = _pg.decide(proj, batt_w=1500.0, achievable_w=5000.0, soc=None, **kw) + return [sat.reason, low.reason, unread.reason] + + +def _migration_texts(): + out = [] + for moved, kept, lost, wrong in ( + (2, 0, 0, 0), (2, 1, 1, 0), (2, 0, 0, 1), (0, 2, 0, 0), + (0, 2, 1, 0)): + rep = _store.MigrationReport() + rep.ran = moved > 0 or lost > 0 + rep.from_version = 1 + rep.roster = ["inverter-a"] + rep.moved = {f"unit/inverter-a/k{i}": True for i in range(moved)} + rep.kept = [f"unit/inverter-a/old{i}" for i in range(kept)] + for i in range(lost): + note = f"unit/inverter-a/k{i} was written as True and reads back as None" + rep.problems.append(note) + rep.lost.append(note) + for i in range(wrong): + note = (f"unit/garage/k{i} was migrated into namespace 'garage', " + f"which is not in the inverter list") + rep.problems.append(note) + rep.misdirected.append(note) + out.append(rep.explain()) + return out + + +def _tariff_texts(): + hours = [_T0 + _td(minutes=15 * i) for i in range(8)] + pts = [PricePoint(h, 0.2, i >= 4) for i, h in enumerate(hours)] + read = PriceRead.series(pts, PriceProduct.DAY_AHEAD, "x", _T0) + return [TariffPlan(read, None, "provider").words, + TariffPlan(PriceRead.no_data("the price feed timed out"), None, + "none").words] + + +def _static(spec): + """Templates for a family of builders that is not one function: the first + argument of every call to `spec`, or every value assigned to `spec`, in + the named file (placeholders count as one word, as in part 3).""" + fname, kind, name = spec + out = [] + for f in ([APP / fname] if fname != "*" else sorted(APP.glob("*.py"))): + tree = ast.parse(f.read_text(encoding="utf-8")) + for node in ast.walk(tree): + if kind == "call" and isinstance(node, ast.Call) and node.args \ + and ast.unparse(node.func).split(".")[-1] == name: + out += [t for _n, t in strings_in(node.args[0])] + elif kind == "assign" and isinstance(node, ast.Assign) \ + and ast.unparse(node.targets[0]) == name: + out += [t for _n, t in strings_in(node.value)] + elif kind == "return" and isinstance(node, ast.FunctionDef) \ + and node.name == name: + out += [t for r in ast.walk(node) if isinstance(r, ast.Return) + and r.value is not None for _n, t in strings_in(r.value)] + return [t for t in out if len(words(t)) > 1] + + +TEXT = { + "main.py:first.sign_wd.reason": _sign_texts, + "main.py:inv.sign_wd.reason": _sign_texts, + "main.py:inv.sign_wd.reason or '(reason not recorded)'": _sign_texts, + "main.py:self.site_sign_wd.reason": _sign_texts, + "main.py:self.site_sign_wd.reason or '(reason not recorded)'": _sign_texts, + "main.py:self.circ_wd.reason": _circ_texts, + "main.py:self.circ_wd.reason or '(reason not recorded)'": _circ_texts, + "main.py:inv.delivery_wd.reason": _delivery_texts, + "main.py:inv.delivery_wd.reason or '(reason not recorded)'": _delivery_texts, + "main.py:self.clamp_wd.reason": _clamp_texts, + "main.py:g.reason": _peak_texts, + "main.py:self.freeze_wd.reason": _freeze_texts, + "main.py:inv.batt_fresh.reason": _stale_texts, + "main.py:rep.explain()": _migration_texts, + "store.py:rep.explain()": _migration_texts, + "main.py:plan.words": _tariff_texts, + # Families: every builder of the text, as a template. + "main.py:refusal": lambda: (_static(("main.py", "return", "write_refusal")) + + _static(("allocator.py", "return", "authorises"))), + "main.py:' / '.join(resolution.scope_errors)": + lambda: _static(("arbiter.py", "return", "scope_violations")) + + _static(("arbiter.py", "call", "append")), + "price_forecast.py:gate.reason": lambda: _static(("*", "call", "block")), + "static_tariff.py:read.reason": lambda: _static(("*", "call", "no_data")), + "price_history.py:self.last_error": + lambda: _static(("price_history.py", "assign", "self.last_error")), + "price_history.py:bad": lambda: _static(("price_history.py", "return", + "_parse_points")), + "maintenance.py:msg": lambda: _static(("maintenance.py", "assign", "msg")), + "validate.py:aged": lambda: _static(("*", "return", "stale_card")), + "validate.py:xaged": lambda: _static(("*", "return", "stale_card")), + # Refusals: part 3 holds them to the refusal rule already. + "selfconfig.py:problems[0]": None, + "validate.py:problem": None, + "p1.py:problem": None, +} + + +def reason_problems(text): + """STYLE.md's red-alarm shape, for a text a log line quotes.""" + out = [] + n_s, n_w = sentences(text), len(words(text)) + if n_s > 3: + out.append(f"over 3 sentences ({n_s})") + if n_w > 70: + out.append(f"over 70 words ({n_w})") + long = [x for x in re.split(r"(?<=[.!?])\s+", text) if len(words(x)) > 30] + if long: + out.append(f"a sentence over 30 words ({len(words(long[0]))})") + return out + line_problems(text) + + +def line_problems(text): + """What no WARNING+ line may carry, whatever its length.""" + out = [] + if ";" in text: + out.append("semicolon") + if re.search(r"(?<!\.)\.\.(?!\.)|\.{4,}|\.:|:\s*\.", text): + out.append("a doubled full stop") + if PLURAL.search(text): + out.append("plural: " + PLURAL.search(text).group(0)) + return out + text_problems(text, keys=True, entities=True) + + +def _fill(template, fmt_node, key_part, sample): + """The line as logged: `sample` in the text slot, `X` in the others.""" + if isinstance(fmt_node, ast.JoinedStr): + return template.replace("{" + key_part + "}", sample) + return template # %-style: filled by the caller + + +def scan_log_lines(files, text=None, data=None): + """-> (unclassified keys, stale keys, [(key, sample, problems)]).""" + text = TEXT if text is None else text + data = DATA if data is None else data + seen, bad = set(), [] + for fname, tree in files: + for key, call in dynamic_parts(tree, fname): + seen.add(key) + if key in data or key not in text: + continue + maker = text[key] + if maker is None: + continue + i = 1 if ast.unparse(call.func).endswith("._moan") else 0 + fmt = call.args[i] + template = render(fmt) or "" + args = [ast.unparse(a) for a in call.args[i + 1:]] + part = key.split(":", 1)[1] + for sample in maker(): + p = reason_problems(sample) + if isinstance(fmt, ast.JoinedStr): + line = template.replace("{" + part + "}", sample) + else: + slots = iter(["%s" if a != part else "\0" for a in args]) + line = re.sub(r"%[-+ #0-9.]*[sdrfgx]", + lambda m: next(slots, m.group(0)), template) + line = PLACEHOLDER.sub("X", line).replace("\0", sample) + p += [f"as logged: {x}" for x in line_problems(line) + if x not in p] + if p: + bad.append((key, sample, p)) + unknown = sorted(seen - set(data) - set(text)) + stale = sorted((set(data) | set(text)) - seen) + return unknown, stale, bad + + +_FILES = [(f.name, ast.parse(f.read_text(encoding="utf-8"))) + for f in sorted(APP.glob("*.py"))] +_unknown, _stale, _bad = scan_log_lines(_FILES) +for k, sample, p in _bad: + print(f" BAD {k}: {'; '.join(p)} :: {sample[:110]!r}") +check(f"every dynamic part of a WARNING+ line is classified as data or as a " + f"built text (unclassified: {_unknown})", not _unknown) +check(f"...and no classification is left over from a line that is gone " + f"(stale: {_stale})", not _stale) +_n_texts = sum(len(m()) for m in TEXT.values() if m is not None) +check(f"every built text, run for real, obeys the rule, and so does the line " + f"that quotes it ({_n_texts} texts, {len(_bad)} bad)", not _bad) +_counts = [f"{f}:{n.lineno}" for f, t in _FILES for n in ast.walk(t) + if isinstance(n, ast.Call) and (LOG_CALL.search(ast.unparse(n.func)) + or ast.unparse(n.func).endswith("._moan")) + for a in n.args[:2] if isinstance(a, ast.Constant) + and isinstance(a.value, str) and COUNT_PLURAL.search(a.value)] +check(f"no WARNING+ line puts a plural noun after a bare count, which reads " + f"'1 times' (use messages.times() and friends; found: {_counts})", + not _counts) + +# Mutations: the scan catches what the 2d scan missed. +_OLD_CLAMP = ("OUTPUT_CLAMP: the loop computed +2148 W, over the 2000 W rating, " + "and it was clamped to +2000 W; the loop's command this cycle was " + "+440 W. This is a BUG SIGNAL, not a limit being used: something " + "upstream computed a setpoint the actuator cannot deliver.") +_mut_text = dict(TEXT, **{"main.py:self.clamp_wd.reason": lambda: [_OLD_CLAMP]}) +_u, _s, _b = scan_log_lines([f for f in _FILES if f[0] == "main.py"], + text=_mut_text) +check("an injected bad reason (the 2d clamp text) is caught, on both clamp " + f"lines ({sorted({k for k, _t, _p in _b if 'clamp' in k})})", + [k for k, _t, _p in _b].count("main.py:self.clamp_wd.reason") == 2) +_new_site = ast.parse("_LOG.warning('Something broke: %s', self.new_wd.reason)") +_u, _s, _b = scan_log_lines([("main.py", _new_site)]) +check(f"...and a new line quoting a text nobody classified is caught ({_u})", + _u == ["main.py:self.new_wd.reason"]) +check("...and '1 times', '(s)', a semicolon and a doubled full stop in a " + "logged line are caught", + all(line_problems(t) for t in ("Cut back 1 times so far.", + "2 malformed point row(s) dropped.", + "It failed; retrying.", + "Cut back to +2000 W.. Only this.", + "index 0, 1, .... Those are left out.", + "moved to one part: . Problems"))) +check("...while '1 s' and '1 time' are fine", + not line_problems("Held for 1 s, cut back 1 time so far.")) +# INFO lines are not held to the length rule, but the 2d test found "§8.3", +# ISO timestamps and "keys ARE" in them. Their literals may carry none. +INFO_JARGON = re.compile(r"§\s?\d|isoformat|\b(?:ARE|NOT|AND)\b") +_info_bad = [f"{f}:{n.lineno}" for f, t in _FILES for n in ast.walk(t) + if isinstance(n, ast.Call) and n.args + and re.search(r"(?:^|\.)(?:_LOG|log|logger|LOG)\.info$", + ast.unparse(n.func)) + for _n, s in strings_in(n.args[0]) + if INFO_JARGON.search(ast.unparse(n.args[0])) or SHOUT.search(s)] +check(f"no INFO line carries a section number, an ISO timestamp or capitals " + f"(found: {_info_bad})", not _info_bad) +check("...and one that did is caught", + bool(INFO_JARGON.search('"§8.3 price history: %s"')) + and bool(SHOUT.search("the flat keys ARE NOT that pack's history"))) + + +# ============================================================================== # +print("\n7. log levels, log noise and the display bugs (UX-10)") +import logging # noqa: E402 + +from app import hass as _hass, p1 as _p1, validate as _validate, web as _web # noqa: E402 +from app.arbiter import Claim # noqa: E402 +from app.main import Controller, why_key # noqa: E402 + + +class _Rec(logging.Handler): + def __init__(self): + super().__init__(logging.DEBUG) + self.records = [] + + def emit(self, record): + self.records.append(record) + + +def _captured(logger_name, fn): + rec, lg = _Rec(), logging.getLogger(logger_name) + old = lg.level + lg.addHandler(rec) + lg.setLevel(logging.DEBUG) + try: + fn() + finally: + lg.removeHandler(rec) + lg.setLevel(old) + return rec.records + + +def _level_of(fname, words_in_line): + """The level of the log call in `fname` whose literal holds the words.""" + tree = ast.parse((APP / fname).read_text(encoding="utf-8")) + for node in ast.walk(tree): + if isinstance(node, ast.Call) and node.args \ + and re.search(r"_LOG\.\w+$", ast.unparse(node.func)): + text = render(node.args[0]) or "" + if words_in_line in text: + return ast.unparse(node.func).rsplit(".", 1)[-1] + return None + + +check("the shadow line of every cycle is DEBUG, not INFO in capitals " + f"({_level_of('main.py', 'Shadow mode: would send')})", + _level_of("main.py", "Shadow mode: would send") == "debug" + and _level_of("main.py", "SHADOW MODE: not commanding") is None) +check("'Shadow mode is on' and 'is off', which follow a setting or a button, " + f"are INFO ({_level_of('main.py', 'Shadow mode is on')}, " + f"{_level_of('main.py', 'Shadow mode is off')})", + _level_of("main.py", "Shadow mode is on") == "info" + and _level_of("main.py", "Shadow mode is off") == "info") +_access = {} +for _lvl in (logging.INFO, logging.DEBUG): + logging.getLogger("goodwe.web").setLevel(_lvl) + _access[logging.getLevelName(_lvl)] = _web.access_log() +logging.getLogger("goodwe.web").setLevel(logging.NOTSET) +_start_src = " ".join( + ast.unparse(n) for n in ast.walk(ast.parse( + (APP / "web.py").read_text(encoding="utf-8"))) + if isinstance(n, ast.AsyncFunctionDef) and n.name == "start") +check(f"the page's own polls are not logged at INFO: aiohttp's access log is " + f"off unless the log level is debug ({_access})", + _access["INFO"] is None + and isinstance(_access["DEBUG"], logging.Logger) + and "access_log=access_log()" in _start_src) +_validate.WARN_ONCE.seen.clear() # part 3 ran the validator already +_twice = _captured("goodwe.config", lambda: [ + _validate.validate_startup_config( + dict(_BASE, price_provider="generic_dayahead", static_profile=""), + -5000, 5000) for _ in range(2)]) +_sp = [r for r in _twice if "static_profile is empty" in r.getMessage()] +check(f"a settings warning is logged once per start, though the check runs " + f"twice ({len(_sp)} line(s))", len(_sp) == 1 + and _sp[0].levelno == logging.WARNING) + + +def _outage(): + o = _hass.Outage() + o.down("api", "error 502", "read sensor.x: 502, message='Bad Gateway'") + o.down("api", "error 502", "read sensor.y: 502") + o.down("websocket", "the meter connection closed", + "Received message 8:1000 is not str") + o.up("api") + o.up("websocket") + o.down("api", "no connection", "Cannot connect to host supervisor:80") + + +_out = _captured("goodwe.hass", _outage) +_warn = [r.getMessage() for r in _out if r.levelno == logging.WARNING] +_info = [r.getMessage() for r in _out if r.levelno == logging.INFO] +check(f"a Home Assistant restart is one plain WARNING line, and one INFO line " + f"when both connections are back ({_warn}, {_info})", + _warn[:1] == ["Home Assistant is not answering (error 502), perhaps it " + "is restarting. The add-on keeps trying."] + and _info == ["Home Assistant answers again."] and len(_warn) == 2) +check("...and the library's own text is kept, at DEBUG", + any("Received message 8:1000" in r.getMessage() for r in _out + if r.levelno == logging.DEBUG) + and not any("8:1000" in m or "Bad Gateway" in m for m in _warn + _info)) + + +class _WS: + def __init__(self, kind): + self.kind = kind + + async def receive(self): + return type("M", (), {"type": self.kind, "data": "{}"})() + + +def _closed_ws(): + try: + asyncio.run(_p1._receive_json(_WS(_p1.aiohttp.WSMsgType.CLOSE))) + except ConnectionResetError as e: + return str(e) + return None + + +check(f"a socket Home Assistant closed is a plain ConnectionResetError, which " + f"the reconnect loop reports through that one line ({_closed_ws()!r})", + (_closed_ws() or "").startswith("Home Assistant closed the connection")) + +# "Why: Other". Every winner and every safety reason the code can produce has +# words. The keys are found in the code: each `Claim.set(source, ..., reason)` +# through main.why_key(), plus main.py's own refusal to split ("unsplit"). +_SOURCES = {} +for _f in sorted(APP.glob("*.py")): + _tree = ast.parse(_f.read_text(encoding="utf-8")) + _consts = _module_constants(_tree) + for _n in ast.walk(_tree): + if isinstance(_n, ast.Call) and ast.unparse(_n.func) == "Claim.set" \ + and _n.args: + _src = _n.args[0] + _src = (_src.value if isinstance(_src, ast.Constant) + else _consts.get(getattr(_src, "id", ""), None)) + _rsn = next((k.value for k in _n.keywords if k.arg == "reason"), + _n.args[3] if len(_n.args) > 3 else None) + _rsn = _rsn.value if isinstance(_rsn, ast.Constant) else "" + _SOURCES.setdefault((_src, _rsn), f"{_f.name}:{_n.lineno}") +_keys = {why_key(s, [Claim.set(s, 0, 0.0, r)]) for s, r in _SOURCES} +_keys |= {why_key("failsafe", []), + why_key("failsafe", [Claim.set("loop", 0, 1.0, "tracking")])} +check(f"the scan found the claims ({len(_SOURCES)}), including the latched " + f"per-inverter stop the 2d test saw as 'Other'", + ("failsafe", "sign disagreement") in _SOURCES and len(_SOURCES) >= 8) +_missing_why = sorted(k for k in _keys if k not in messages.WHY_WINNER) +check(f"every winner and safety reason has words in messages.WHY_WINNER " + f"(missing: {_missing_why}, keys: {sorted(_keys)})", not _missing_why) +check("...so the latched stop reads as a safety stop, not 'Other' " + f"({messages.why(why_key('failsafe', [Claim.set('failsafe', 0, 0.0, 'sign disagreement')]), 0)!r})", + messages.why(why_key("failsafe", [Claim.set("failsafe", 0, 0.0, + "sign disagreement")]), 0) + == "Safety stop, power went the wrong way: 0 W") +_without = {k: v for k, v in messages.WHY_WINNER.items() + if k != "sign disagreement"} +check("...and a table that lost that entry is caught", + any(k not in _without for k in _keys)) + + +class _H: + async def number(self, *a, **k): + return None + + async def limits(self, *a): + return (-2000.0, 2000.0, 1.0) + + async def call(self, *a, **k): + return True + + +class _S: + data = {} + + def set(self, *a): + pass + + def get_time(self, *a): + return None + + +class _P: + enabled = False + + def publish(self, *a, **k): + pass + + +_c = Controller({"setpoint_entity": "number.sp", "meter_source": "off", + "max_w": 2000, "stale_input_s": 15}, _H(), _S(), _P(), + stop=asyncio.Event()) +_c.p1_enabled = True +_c.p1 = _p1.P1Ingest(max_age_s=30.0) + + +def _meter_row(): + """The meter row, or a named absence that fails every check below.""" + rows = [r for r in _c.checks() if r.get("id") == "meter"] + return rows[0] if len(rows) == 1 else { + "ok": None, "warn": None, "text": f"<{len(rows)} meter rows>"} + + +_r0 = _meter_row() +_c.p1.started_mono -= 31.0 +_r1 = _meter_row() +_c.p1.submit(_p1.make_sample(_p1.SOURCE_HA, 500.0, 0.0, phases=1)) +_r2 = _meter_row() +check(f"right after a start, before the first meter reading and inside its " + f"limit, the meter row is amber and waits, not red at 0 s ({_r0})", + _r0["warn"] and not _r0["ok"] + and _r0["text"] == "Meter: waiting for the first reading, limit 30 " + "seconds") +check(f"...past the limit with still no reading it is red, as before ({_r1})", + not _r1["ok"] and not _r1["warn"] + and _r1["text"].startswith("Meter: no reading for 31 seconds")) +check(f"...and a reading makes it green ({_r2['text']!r})", + _r2["ok"] and _r2["text"].startswith("Meter: 500 W")) + +_c.auto = True +_c.p1_enabled = False +asyncio.run(_c.cycle()) +_w0 = _c.why_words +_c._why_waiting_since -= _td(seconds=7) +_w7 = _c.why_words +check(f"'A reading is missing for N seconds' counts while control waits, " + f"instead of the age the last cycle saw ({_w0!r} -> {_w7!r})", + _w0 == "A reading is missing for 0 seconds, control waits" + and _w7 == "A reading is missing for 7 seconds, control waits") +_c.why_words = "Keeping the grid near zero: 0 W" +check("...and once a cycle decides again, the line is that decision", + _c.why_words == "Keeping the grid near zero: 0 W") + print() if fails: print(f"{len(fails)} FAILED") diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 06c23ea..e217fc2 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1240,13 +1240,13 @@ check("an engagement that is not saturated raises NO notification - §10.3's " "goodwe_peak_saturated" not in hass.notifications) check("...but it does reach the action log, which is where a control action " "that moves energy belongs", - any("PEAK GUARD" in e for e in c.events)) -n_events = sum(1 for e in c.events if "PEAK GUARD" in e) + any("PEAK_GUARD" in e for e in c.events)) +n_events = sum(1 for e in c.events if "PEAK_GUARD" in e) asyncio.get_event_loop_policy().new_event_loop().run_until_complete(c.cycle()) check("...and it is edge-logged, not level-logged: a second engaged cycle adds " "no second line, so a quarter of engagement cannot push the cause of the " "event off a 40-line log", - sum(1 for e in c.events if "PEAK GUARD" in e) == n_events) + sum(1 for e in c.events if "PEAK_GUARD" in e) == n_events) # The saturated case, through the same real cycle. # A floor of 1.5x what the inverter can give: it saturates wherever in the @@ -1661,8 +1661,8 @@ check("...and it still says what it WOULD have taken, so the under-shave is a " near(d_lim.wanted_w, WANTED, 1e-6) and d_lim.wanted_w > d_lim.floor_w) check("...and its one-line explanation tells the operator the consequence in " "the words that matter - the quarter is going over the ceiling", - "FLOOR-LIMITED" in d_lim.explain() - and "WILL GO OVER THE CEILING" in d_lim.explain() + "FLOOR_LIMITED" in d_lim.explain() + and "will go over the limit" in d_lim.explain() and f"{CEIL:.0f} W" in d_lim.explain()) check("an unreadable SoC lands in the same branch, with the OTHER reason - so " "an operator reading one line can tell a flat battery from a dead sensor", @@ -1944,7 +1944,7 @@ check("the status page carries exactly one peak-guard row and it is NOT ok - " "the money is going to be spent and a human is the only actuator left", len(rows24) == 1 and not rows24[0]["ok"] and not rows24[0]["warn"] and "peak limit will be passed" in rows24[0]["text"]) -check("...and it reaches the action log too", any("FLOOR-LIMITED" in e +check("...and it reaches the action log too", any("FLOOR_LIMITED" in e for e in c24.events)) # A missing SoC sensor, through the same real cycle. `inputs_ok` stops the loop # at 0 W in that state, so the guard's own answer is what is graded here. diff --git a/goodwe_controller/test_price.py b/goodwe_controller/test_price.py index 5485d06..5fe1c81 100644 --- a/goodwe_controller/test_price.py +++ b/goodwe_controller/test_price.py @@ -4107,7 +4107,8 @@ _T11_SLOTS = { "carried": r"\d+ published and (\d+) estimated", "horizon": r"for (\d+) hours ahead", "age_s": r"Price plan from (\d+) s ago", - "spacings": r"([\d+]+) s apart", + # UX-10: the spacing is in words ("one every 15 minutes or every hour"). + "spacings": r"one (every [a-z0-9 ]+?)(?:,|\.|$)", # ⚠️ THE *Arbitrage* ROW'S OWN AGE SLOT, and it is deliberately the same # pattern for "decided N s ago" and "the last one was taken N s ago" - # WHICH of the two sentences was rendered is graded by inequality below, @@ -4125,6 +4126,18 @@ _T11_SLOTS = { } +def _spacing_s(raw): + """`every 15 minutes or every hour` -> `[900, 3600]`; raises otherwise.""" + unit = {"second": 1, "minute": 60, "hour": 3600} + out = [] + for part in raw.split(" or "): + m = re.fullmatch(r"every (?:(\d+) )?(second|minute|hour)s?", part.strip()) + if m is None: + raise ValueError(f"no spacing in {part!r}") + out.append(int(m.group(1) or 1) * unit[m.group(2)]) + return out + + def _slot(row, name): """The number in ONE NAMED SLOT of a rendered row, or `_Raised`. @@ -4140,18 +4153,18 @@ def _slot(row, name): if m is None: raise ValueError(f"no {name!r} slot in {row[:90]!r}") raw = m.group(1) - return ([int(x) for x in raw.split("+")] if name == "spacings" - else int(raw)) + return (_spacing_s(raw) if name == "spacings" else int(raw)) return derived(_get) _T11_GOOD = ("x. Price plan from 7 s ago, for 48 hours ahead: day-ahead " "prices from the price feed, 132 prices over 33 hours, " - "36 published and 96 estimated, 900+3600 s apart") + "36 published and 96 estimated, one every 15 minutes or every " + "hour") _T11_SHIPPED_DEFECT = ("x. Price plan from 7 s ago, for 48 hours ahead: " "day-ahead prices from the price feed, 132 prices over " - "132 hours, 96 published and 36 estimated, 900+3600 s " - "apart") + "132 hours, 96 published and 36 estimated, one every " + "15 minutes or every hour") # The slots divide into the ones a *Tariff*/​*Arbitrage* ROW carries and the # ones a REFUSAL sentence carries; each group is calibrated against its own # well-formed example, because a slot asked of the wrong kind of sentence is diff --git a/goodwe_controller/test_price_forecast.py b/goodwe_controller/test_price_forecast.py index 9ec5298..59761eb 100644 --- a/goodwe_controller/test_price_forecast.py +++ b/goodwe_controller/test_price_forecast.py @@ -66,6 +66,7 @@ import sys from named_absence import first, nth from datetime import datetime, timedelta, timezone +from app import messages as _msg_fc from app import price as _price from app import price_forecast as _fc from app import static_tariff as _st @@ -668,8 +669,10 @@ check("with neither a published hour nor a yesterday, the result is no_data - " check("...so it has no .points to iterate and no .get() to default out of", raises(lambda: _nothing.points, Absence) and raises(lambda: _nothing.get("points", []), Absence)) -check("...and its reason names §11.4 for an operator", - "§11.4" in _nothing.reason) +check("...and its reason says the fixed tariff is used and there is no " + "trading (§11.4), in words an operator reads", + "fixed tariff is used" in _nothing.reason + and "no trading" in _nothing.reason) check("a naive `since` is refused rather than silently interpreted as UTC", raises(lambda: fill_from_yesterday(TODAY_PART, yesterday=YESTERDAY, since=datetime(2026, 1, 15), @@ -745,9 +748,10 @@ check("...and the phase machine did not move: it is still idle, so the " _m.phase == IDLE) check("...and the reason names §8.3, the offending hour, and when the real " "price is expected", - "§8.3" in _gate_bad.reason - and bool(_first_prov) and _first_prov.isoformat() in _gate_bad.reason - and "14-16" in _gate_bad.reason) + "is only estimated" in _gate_bad.reason + and bool(_first_prov) + and _msg_fc.when(brussels(_first_prov)) in _gate_bad.reason + and "14:00 to 16:00" in _gate_bad.reason) # The positive arm, so the block above is discriminating rather than universal. _firm_long = series_of(hours_between(START, @@ -772,7 +776,8 @@ _gate_none = begin_phase(_m3, START, PriceRead.no_data("the feed timed out"), MAINTENANCE_DRAIN) check("no price data at all BLOCKS an irreversible action too - a missing " "price is not a cheap one (§11.4)", - _gate_none.kind == "blocked" and "§11.4" in _gate_none.reason + _gate_none.kind == "blocked" + and "missing price is not a cheap one" in _gate_none.reason and _m3.phase == IDLE) _short = series_of(DAY[:4], lambda u: t_price(brussels(u).hour), PriceProduct.DAY_AHEAD, "generic_dayahead", diff --git a/goodwe_controller/test_price_history.py b/goodwe_controller/test_price_history.py index d1e74c4..8e4a743 100644 --- a/goodwe_controller/test_price_history.py +++ b/goodwe_controller/test_price_history.py @@ -1020,7 +1020,7 @@ check("a store holding only the day before LAST answers no_data, not those " _y3.kind == "no_data") check(f"...and the reason names BOTH the date wanted and the dates held, so an " f"operator can see which it is: {why(_y3)!r}", - "2026-01-14" in why(_y3) and "2026-01-12" in why(_y3)) + "14 Jan" in why(_y3) and "12 Jan" in why(_y3)) _h4 = store() _ph.PriceHistory._remember( @@ -1217,7 +1217,7 @@ json.dump({"version": SCHEMA + 99, "days": {}}, open(_p7, "w", encoding="utf-8") _h7 = PriceHistory(_p7) check("a file from a schema this build does not know is discarded rather than " "guessed at - its points might mean something else", - "schema" in (_h7.last_error or "") + "version" in (_h7.last_error or "") and _h7.yesterday(NOW).kind == "no_data") # A record whose points are malformed. THE DEFECT IS A DEFAULTED PRICE. @@ -1270,7 +1270,7 @@ json.dump({"version": SCHEMA, "days": { _h14 = PriceHistory(_p14) check("a day record that is not a dict is DROPPED and REPORTED, and the rest " "of the file still loads - one bad record is not a bad file", - _h14.ok and "unusable day record" in (_h14.last_error or "") + _h14.ok and "unusable day" in (_h14.last_error or "") and sorted(_h14._days) == ["2026-01-13"]) _w14 = derived(lambda: _h14.words) _y14 = derived(lambda: _h14.yesterday(NOW).kind) @@ -1291,7 +1291,7 @@ for _shape in ("oops", [1, 2, 3], 7, None, {"points": "not a list"}): check(f"...and the same holds for a day record of {type(_shape).__name__} " f"{_shape!r}: dropped, reported, and every accessor answers " f"({_wX!r}, {_yX!r})", - _hX._days == {} and "unusable day record" in (_hX.last_error or "") + _hX._days == {} and "unusable day" in (_hX.last_error or "") and isinstance(_wX, str) and _yX == "no_data") _pF = os.path.join(tmpdir(), "price_history.json") @@ -1300,7 +1300,7 @@ json.dump({"version": float(SCHEMA), "days": {}}, check(f"a `version` of {float(SCHEMA)!r} is refused although it EQUALS " f"{SCHEMA} - a schema check that cannot tell 1 from 1.0 is one that " f"would not notice a writer this build has never met", - "schema" in (PriceHistory(_pF).last_error or "")) + "version" in (PriceHistory(_pF).last_error or "")) # --------------------------------------------------------------------------- # @@ -1328,7 +1328,7 @@ check(f"...and a store holding a day names the DATE, the POINT COUNT and the " f"HOUR COUNT {words_of(_h_words)!r} - 'a cache exists' and 'the cache " f"holds yesterday, all 24 hours of it' are different facts, and only " f"the second says the horizon will be full tomorrow morning", - words_of(_h_words) == f"{YDAY_D} (24 prices over 24 hours)") + words_of(_h_words) == "24 prices over 24 hours for 14 Jan") # ⚠️ AND THE TWO NUMBERS ARE NOT THE SAME NUMBER - FCST-05's LOW. The row # shipped as `f"{d} ({_n_points(rec)} h)"`, which counts POINTS and prints them @@ -1362,15 +1362,15 @@ check(f"...and the row reports BOTH, each under its own unit: {_qw!r}. " f"A day of 96 quarter-hourly prints is 96 points over 24 h, and the " f"figure that says whether tomorrow's fill has a whole day to carry is " f"the HOUR one", - _qw == f"{YDAY_D} (96 prices over 24 hours)") + _qw == "96 prices over 24 hours for 14 Jan") check(f"...and specifically the row does NOT say '96 h' {_qw!r} - a point " f"count wearing the hour's name is H1's defect, and this row is where " f"an operator would have read it", - isinstance(_qw, str) and "(96 h)" not in _qw and " (96 prices " in _qw) + isinstance(_qw, str) and "(96 h)" not in _qw and _qw.startswith("96 prices ")) check(f"a file that only PARTLY loaded says so in the row {_w14!r}, or the " f"days it dropped read as days that were simply never written", isinstance(_w14, str) and (_h14.last_error or "") in _w14 - and "2026-01-13" in _w14) + and "13 Jan" in _w14) check("NoHistory() has a sentence of its own rather than an empty cell", NoHistory().words == "not kept") check("...and `words` never raises, whatever the file holds. It is read once " @@ -1546,8 +1546,8 @@ for _shape, _bad in _BAD_STARTS: f"{_wload!r}: ONE point held, and the row that is not a point named " f"rather than counted", isinstance(_wload, str) - and _wload.startswith(f"{TODAY_D} (1 price over 1 hour) [") - and "1 malformed point row(s) in" in _wload) + and _wload.startswith("1 price over 1 hour for 15 Jan [") + and "1 bad price in" in _wload) # ⚠️ AND THE TWO NOTES ARE GRADED APART, BECAUSE THEY MASK EACH OTHER # OTHERWISE (MUTATION.md TEST-16). `_usable_days()` records what it FOUND # at open and `_remember()` records what it DROPPED on the refresh; both @@ -1562,22 +1562,22 @@ for _shape, _bad in _BAD_STARTS: f"'{TODAY_D} (1 h)' - the status row reporting a full cache while " f"every tariff refresh was dying on it", isinstance(_wafter, str) - and "malformed point row(s) dropped from" in _wafter - and TODAY_D in _wafter) + and "bad price dropped from" in _wafter + and "15 Jan" in _wafter) check(f"...and the row MOVED from what was found to what was dropped " f"{_wload.split('[')[-1]!r} -> {_wafter.split('[')[-1]!r}, so the " f"two notes are not one note read twice", isinstance(_wload, str) and isinstance(_wafter, str) - and "malformed point row(s) in" in _wload - and "malformed point row(s) in" not in _wafter - and "malformed point row(s) dropped from" not in _wload) + and "bad price in" in _wload + and "bad price in" not in _wafter + and "bad price dropped from" not in _wload) # ...and a SECOND refresh over the same store is clean, which is the state # a restarted add-on comes up in. _hM2 = PriceHistory(_pM) check(f"...and the store reopened from that file is CLEAN: the whole day " f"held and nothing to report {words_of(_hM2)!r}, so the note clears " f"itself rather than becoming permanent furniture", - words_of(_hM2) == f"{TODAY_D} ({_want} prices over {_want} hours)" + words_of(_hM2) == f"{_want} prices over {_want} hours for 15 Jan" and _hM2.last_error is None) # ...and the shipped path, end to end, through the caller that catches @@ -1641,7 +1641,7 @@ print("5d. FCST-06 - the OTHER way to be a store that cannot persist") # read-only and again on a full tmpfs: # # last_error = 'could not write ([Errno 30] Read-only file system)' -# words = '2026-01-14 (24 prices over 24 hours); 2026-01-15 (24 points +# words = '2026-01-14 (24 points over 24 h); 2026-01-15 (24 points # over 24 h) [could not write (...)]' # yesterday()= series, 24 points # ON DISK = {} <- and gone on the next restart @@ -1701,7 +1701,7 @@ check(f"...and `words` and `yesterday()` AGREE about that store " f"{_h16.words[:44]!r}: neither names a day the file does not hold, and " f"both name the write failure. They disagreed - `words` printed two " f"full days BESIDE the error while `yesterday()` answered 24 points", - YDAY_D not in _h16.words and TODAY_D not in _h16.words + "14 Jan" not in _h16.words and "15 Jan" not in _h16.words and "could not write" in _h16.words and _y16.kind == "no_data" and "could not write" in why(_y16)) check(f"...and it DEGRADES rather than raising: the carry still returned a " diff --git a/goodwe_controller/test_tariff.py b/goodwe_controller/test_tariff.py index 854a85a..d1a6069 100644 --- a/goodwe_controller/test_tariff.py +++ b/goodwe_controller/test_tariff.py @@ -448,7 +448,7 @@ print(f" restore() across the boundary said: {said}") aug7, sep7 = st7.peak(month="2026-08"), st7.peak(month="2026-09") check("a restart that straddles the month boundary BANKS the dead August " "quarter rather than dropping measured energy", - said.startswith("closed a stale block") and aug7.is_observed) + said.startswith("closed the 15-minute period") and aug7.is_observed) check(f"...at its partial-coverage figure ({aug7.peak_w:.2f} W = " f"{RUN_W * 399 / QUARTER_S:.2f} W, the seconds it actually covered)", near(aug7.peak_w, RUN_W * 399 / QUARTER_S, 1e-6)) @@ -1325,7 +1325,7 @@ print(f" quarters banked in {month_key(_sb)}: {_before_stale} -> " check("a block closed by restore() rather than by sync() is counted too - the " "old counter incremented only in sync() and missed it entirely", _before_stale == 0 and _tr13.recorded_in(_sb) == 1 - and "banked" in _state) + and "and saved it" in _state) # --- the count is scoped to the MONTH it is printed beside -------------------- # ⚠️ TWO MONTHS AT DIFFERENT COUNTS. Equal counts would be satisfied by a diff --git a/goodwe_controller/test_validate.py b/goodwe_controller/test_validate.py index 1678bcf..853bff5 100644 --- a/goodwe_controller/test_validate.py +++ b/goodwe_controller/test_validate.py @@ -1693,11 +1693,11 @@ check("...and a card ON THIS LEG that the coefficients do not reproduce is " # ⚠️ THE SENTENCE DOCS.md RESTS ON, AND IT IS THE ONE MOST LIKELY TO ROT. _T16_INFO = [m for lvl, m in _T16_OK_LOG if lvl == "INFO" - and "NO STRATEGY IN THIS ADD-ON READS IT" in m] + and "No part of the add-on reads it yet" in m] check("the startup line says, in so many words, that NO STRATEGY IN THIS " "ADD-ON READS IT - the operator is told what the option does not do in " "the same breath as it being accepted", - len(_T16_INFO) == 1 and "displaced IMPORT" in _T16_INFO[0]) + len(_T16_INFO) == 1 and "displaced import" in _T16_INFO[0]) # ⚠️ THE ASYMMETRY IS ASSERTED AS AN ORDERED PAIR, NOT AS TWO NUMBERS IN ONE # SENTENCE (MUTATION.md habit 14). "6 and 0 appear somewhere" is satisfied by # the two legs TRANSPOSED - which is the sentence telling an operator that the -- 2.54.0 From f1a660881c04d2a66136a51f4e86be0ae9ffaddd Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 11:03:30 +0200 Subject: [PATCH 040/105] UX-10: two INFO lines read better on TEST-23 (hours count, maintenance history) "11 of 48 hours use yesterday's prices", and the maintenance-history line no longer says "maintenance history" twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/app/price_forecast.py | 4 ++-- goodwe_controller/app/store.py | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/goodwe_controller/app/price_forecast.py b/goodwe_controller/app/price_forecast.py index 830576f..1fc65f9 100644 --- a/goodwe_controller/app/price_forecast.py +++ b/goodwe_controller/app/price_forecast.py @@ -433,9 +433,9 @@ def fill_from_yesterday(read: PriceRead, *, yesterday: PriceRead, # hours" about a 48-hour horizon. The fill's unit is the HOUR and the # feed's is the POINT; nothing derived from one answers for the other. total_h = len({_utc_hour(p.start) for p in out}) - _LOG.info("%s of %d use yesterday's prices, marked as estimated. " + _LOG.info("%d of %s use yesterday's prices, marked as estimated. " "The feed published %s over the other %s.", - messages.count(carried, "hour"), total_h, + carried, messages.count(total_h, "hour"), messages.count(len(out) - carried, "price"), messages.count(total_h - carried, "hour")) diff --git a/goodwe_controller/app/store.py b/goodwe_controller/app/store.py index ddc4f05..22cfd7b 100644 --- a/goodwe_controller/app/store.py +++ b/goodwe_controller/app/store.py @@ -547,13 +547,12 @@ def migrate_maint_keys(store, unit: str, roster) -> MigrationReport: names = [str(n) for n in roster] rep.from_version = int(data.get(MAINT_SCHEMA_KEY, 0) or 0) if len(names) <= 1: - rep.skipped = ("one inverter, so its maintenance history is read " - "where it is and nothing moves") + rep.skipped = ("one inverter, so it is read where it is and nothing " + "moves") return rep if rep.from_version >= MAINT_SCHEMA_VERSION: - rep.skipped = (f"maintenance history already at version " - f"{rep.from_version}, written for several inverters, so " - f"it is left as it is") + rep.skipped = (f"already at version {rep.from_version}, written for " + f"several inverters, so it is left as it is") return rep rep.ran = True -- 2.54.0 From e0b578756fc2808bfe01fb0d65d465a0bc1b1155 Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 12:08:38 +0200 Subject: [PATCH 041/105] UX-10 review: the line as logged gets the red-alarm shape, clamp lines at 30 words, plain HA 400 Part 6 checked the quoted reason alone, so title + reason + tails logged as 4+ sentences. It now also checks the whole line (at most 3 sentences, none over 30 words); 25 lines failed and are rewritten (one-sentence wrappers, two-sentence circulation and peak reasons, STALE_READING's fixed limits on a DEBUG line). The clamp lines for one inverter are pinned at 30 words with OUTPUT_CLAMP and the numbers kept. Home Assistant's bare '400: Bad Request' while it loads becomes one plain line; still WARNING, throttled, a failed write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/UX-08-short-notifications.md | 4 +- goodwe_controller/DOCS.md | 4 +- goodwe_controller/app/allocator.py | 6 +- goodwe_controller/app/circulation.py | 7 +- goodwe_controller/app/clamp.py | 36 +++--- goodwe_controller/app/freshness.py | 12 +- goodwe_controller/app/hass.py | 15 ++- goodwe_controller/app/main.py | 96 ++++++++-------- goodwe_controller/app/peakguard.py | 14 ++- goodwe_controller/app/price_forecast.py | 6 +- goodwe_controller/app/static_tariff.py | 10 +- goodwe_controller/test_clamp.py | 12 +- goodwe_controller/test_messages.py | 107 +++++++++++++++++- 13 files changed, 231 insertions(+), 98 deletions(-) diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index 7eacf7d..ee2cc44 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -75,4 +75,6 @@ The allowlist is empty and its cap is 0 (43 → 0). Every WARNING and ERROR line - "Why: Other" during a latched per-inverter stop: `main.py` turns a safety winner into its claim's reason, and "sign disagreement" (and "unsplit", main.py's own refusal to split) had no entry in `WHY_WINNER`. The mapping is now `main.why_key()`, and part 7 finds every `Claim.set()` in the code and checks that every key it can produce has words. - Red "Meter: no reading for 0 seconds" after a restart: until the first reading arrives, `P1Ingest.stale` is true, and the age is the time since start. The row now reads amber "waiting for the first reading" while that age is inside the limit. **Colour change, justified:** red at 0 s contradicted the limit the same row prints, and once readings exist the row is red only past that limit. Amber, not green, because control waits for the reading. Past the limit it is red as before. `stale` itself, which gates control, is unchanged. - "A reading is missing for 0 seconds" stuck at 0: with the meter reading gone, the grid value stops changing, so the loop runs a cycle only every `cycle_floor_s`, and the line was computed once per cycle. The age is now counted when the page asks. The hold and its 15 s escalation are unchanged. -7. **Witness** (admin/goodwe): the resolved push says "after no answers from … to …", as the resolved card does. The YAML with every title and message stripped is identical. +7. **Review: the line as logged gets the shape too.** Part 6 first checked the quoted reason alone, so a title, a 2-sentence reason and two tails still logged as 4 sentences ("Power request too high …: OUTPUT_CLAMP: … +5000 W. The command this cycle was +1000 W. Control is still running. Cut back 1 time so far."). Part 6 now also checks the whole line: at most 3 sentences, none over 30 words. The wrappers became one sentence each, the circulation and peak guard reasons two, and `STALE_READING`'s fixed limits moved from the reason to a DEBUG line beside the ERROR (its release clause stays, pinned by test_freshness). The clamp lines for one inverter are pinned at 30 words at most: `OUTPUT_CLAMP: computed +9000 W, cut to the +5000 W rating, command now +2000 W`. Several clamped inverters read as one sentence of asked/sent pairs; which limit bound each is on its own action-log row and in the notification. Totals above 30 words remain on the direction, delivery, frozen-meter and stale lines (up to 74 words). Shortening them is a follow-up: the direction and delivery reasons are also persisted in state.json, and the direction one is pinned byte-for-byte in test_watchdog. +8. **Home Assistant 400 while it loads** now reads "Home Assistant refused number.set_value for number.x (error 400, no details). The entity may still be loading, or the value is out of range." A body with more than "400: Bad Request" is still quoted. Still WARNING, still once a minute, still a failed write. +9. **Witness** (admin/goodwe): the resolved push says "after no answers from … to …", as the resolved card does. The YAML with every title and message stripped is identical. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index b3d31a0..1c4018b 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1848,8 +1848,8 @@ Both are watched. A guard that watched only the emitted value would be silent on every standard configuration. **The integrator bound is not a bug, and it is reported as what it is.** It -reads *"the correction the add-on builds up reached its +5000 W limit. The -command this cycle was +2000 W"*, titled *"Battery is not keeping up"*, logged +reads *"the correction the add-on builds up reached its +5000 W limit, +command now +2000 W"*, titled *"Battery is not keeping up"*, logged as a `WARNING`, with an amber (not red) status row and its own notification (`goodwe_integrator_bound`), so it never replaces a software-fault notice still on screen. Brief engagements after a large load or solar step are normal. If it diff --git a/goodwe_controller/app/allocator.py b/goodwe_controller/app/allocator.py index e63a8d5..38872a2 100644 --- a/goodwe_controller/app/allocator.py +++ b/goodwe_controller/app/allocator.py @@ -246,9 +246,9 @@ class Allocation: block the failsafe is worse than the hole it closes. """ if tick is None or self.tick is None or self.tick != tick: - return (f"the allocation record on hand was made on tick " - f"{self.tick!r} and this is tick {tick!r} - a record whose " - f"envelopes have moved cannot authorise a write") + return (f"the power split on hand is from tick {self.tick!r}, " + f"not this tick {tick!r}, and an old split cannot allow a " + f"write") if not self.ok: return f"no power split was possible this tick ({self.explain()})" if unit not in self.shares: diff --git a/goodwe_controller/app/circulation.py b/goodwe_controller/app/circulation.py index 26fd5a9..8990376 100644 --- a/goodwe_controller/app/circulation.py +++ b/goodwe_controller/app/circulation.py @@ -328,9 +328,10 @@ class CirculationWatchdog: # UX-10: plain sentences, every figure kept (test_messages.py part 6). self.reason = ( f"CIRCULATING_POWER: {circ_w:.0f} W measured going round between " - f"the inverters for {held:.0f} s, peaking at {self.peak_w:.0f} W. " - f"The meter cannot see it, because it nets to zero there. Limits: " - f"over {self.cfg.min_w:.0f} W, held over {self.cfg.hold_s:.0f} s") + f"the inverters for {held:.0f} s, peaking at {self.peak_w:.0f} W, " + f"over the limits of {self.cfg.min_w:.0f} W and " + f"{self.cfg.hold_s:.0f} s. The meter cannot see it, because it " + f"nets to zero there") return True def held_s(self, now: datetime) -> float: diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index 59ce685..31aeb80 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -239,8 +239,8 @@ SUSTAINED_CYCLES = 3 # UX-10: the reasons below are quoted by a WARNING or ERROR line, so they # follow STYLE.md's rule for a quoted reason (test_messages.py part 6): no # final full stop, the line adds it. The line around them says "software -# fault" for an over-rating, so the reason does not. - +# fault" for an over-rating, so the reason does not. Each is one sentence, so +# the logged line stays within 3 sentences and about 30 words. def loop_clamp_note(d) -> str: @@ -251,21 +251,29 @@ def loop_clamp_note(d) -> str: decision's own, i.e. from the tick that clamped. """ if d.clamped: - return (f"{REASON_CODE}: the add-on computed {d.requested_w:+.0f} W, " - f"over the {abs(d.clamped_w):.0f} W rating, and cut it back to " - f"{d.clamped_w:+.0f} W. The command this cycle was " - f"{d.target_w:+.0f} W") + return (f"{REASON_CODE}: computed {d.requested_w:+.0f} W, cut to the " + f"{d.clamped_w:+.0f} W rating, command now {d.target_w:+.0f} W") if d.i_clamped: return (f"{REASON_CODE}: the correction the add-on builds up reached " - f"its {d.i_bound_w:+.0f} W limit. The command this cycle was " + f"its {d.i_bound_w:+.0f} W limit, command now " f"{d.target_w:+.0f} W") return "" def write_clamp_note(named) -> str: - """The write-side alarm text: `named` is `[(inverter name, ClampResult)]` - for every inverter whose write was cut back this cycle.""" - return ". ".join(f"{name}: {r.describe()}" for name, r in named) + """The write-side alarm text: `named` is `[(inverter name or None, + ClampResult)]` for every inverter whose write was cut back this cycle. + + One inverter reads as `describe()`. Several read as one sentence of + asked/sent pairs, so the line stays one sentence however many inverters + there are. Which limit cut each one back is on its own action-log row + (`describe()`) and in the notification.""" + if len(named) == 1: + name, r = named[0] + return f"{name}: {r.describe()}" if name else r.describe() + return f"{REASON_CODE}: " + ", ".join( + f"{name} asked {r.requested_w:+.0f} W and sent {r.applied_w:+.0f} W" + for name, r in named) @dataclass(frozen=True) @@ -284,10 +292,12 @@ class ClampResult: bound: str = "" # "" | "max_w" | "device" - which stage bit def describe(self) -> str: + # The sent value IS the limit that bound, so the rating is not + # repeated: on "max_w" it equals the rating, and on "device" the + # rating was not what cut it back. return (f"{REASON_CODE}: asked {self.requested_w:+.0f} W and sent " - f"{self.applied_w:+.0f} W, cut back by " - f"{messages.LIMIT_WORDS.get(self.bound, self.bound)}, with a " - f"{self.limit_w:.0f} W rating") + f"{self.applied_w:+.0f} W, " + f"{messages.LIMIT_WORDS.get(self.bound, self.bound)}") def is_commandable(value) -> bool: diff --git a/goodwe_controller/app/freshness.py b/goodwe_controller/app/freshness.py index ab81d62..7281d7a 100644 --- a/goodwe_controller/app/freshness.py +++ b/goodwe_controller/app/freshness.py @@ -594,10 +594,12 @@ class Freshness: # ("what did the register do" against "can I trust this entity"). One # helper serving both would have to drop whichever half the other does # not need, and the half it dropped would be the operator's next step. - # UX-10: three plain sentences (test_messages.py part 6). SAFETY-56's + # UX-10: two plain sentences (test_messages.py part 6). SAFETY-56's # two explanations stay, in this order, and so does the admission # that this check cannot tell them apart. The reading is treated as - # missing either way, which the log line around this says. + # missing either way, which the log line around this says. The + # limits (`self.bound`) are on main.py's DEBUG line beside it, so the + # logged line stays within 3 sentences. # ⚠️ SAFETY-57, AND THE THREE DURATIONS ARE THREE DIFFERENT FACTS, each # in its own slot: the register's unchanged time, the WINDOW this # verdict actually rests on after a release (`regraded`), and how many @@ -611,11 +613,7 @@ class Freshness: f"STALE_READING: {self.held:+.0f} W unchanged for {shown_s:.0f} s " f"while the command moved {moved_w:.0f} W to {standing_w:+.0f} W" f"{regraded}. The reading may have stopped, or the battery may be " - f"unable to follow the command, and this check cannot tell which. " - f"Limits: " - f"unchanged over {self.bound.unchanged_s:.0f} s, command over " - f"{self.bound.move_w:.0f} W and moved by over " - f"{self.bound.move_w:.0f} W") + f"unable to follow the command, and this check cannot tell which") def unchanged_s(self, now_mono) -> float | None: """Seconds since an arrival carried a different number. Status page. diff --git a/goodwe_controller/app/hass.py b/goodwe_controller/app/hass.py index 55945a6..da1dd33 100644 --- a/goodwe_controller/app/hass.py +++ b/goodwe_controller/app/hass.py @@ -164,9 +164,20 @@ class HomeAssistant: # value is rejected outright, not clamped. Always log it: # silently dropped commands are how a controller ends up # believing something the hardware never did. + # UX-10: plain words. While Home Assistant loads its + # entities it answers 400 with only "400: Bad Request", + # which says nothing, so only a body with more is quoted. + said = body.strip()[:200] + if said.lower() in (f"{resp.status}: {resp.reason}".lower(), + ""): + said = "no details" + entity = (data.get("entity_id", "no entity") + if isinstance(data, dict) else "no entity") self._moan(f"svc:{domain}.{service}", - "service %s.%s rejected (%s): %s", - domain, service, resp.status, body[:200]) + "Home Assistant refused %s.%s for %s (error %s, " + "%s). The entity may still be loading, or the " + "value is out of range.", domain, service, + entity, resp.status, said) return False return True except aiohttp.ClientConnectionError as err: diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 340e30c..54598a1 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -612,8 +612,8 @@ class Controller: for inv in self.inverters: if inv.sign_wd.tripped: _LOG.error("%s stays at 0 W after the restart because its " - "power went the wrong way: %s. Start control once " - "you know why.", inv.name, + "power went the wrong way, so find out why before " + "you start control. %s.", inv.name, inv.sign_wd.reason or "(reason not recorded)") # --- SAFETY-42 + SAFETY-34 ------------------------------------------- @@ -635,9 +635,9 @@ class Controller: for inv in self.inverters: if inv.delivery_wd.tripped: _LOG.error( - "%s is still marked as not delivering after the restart: " - "%s. Control keeps running, and only stopping and starting " - "control clears this.", + "%s is still marked as not delivering after the restart " + "while control keeps running, and only stopping and " + "starting control clears this. %s.", inv.name, inv.delivery_wd.reason or "(reason not recorded)") # --- SAFETY-30: THE SITE HALF OF THE SIGN CHECK ---------------------- @@ -667,9 +667,9 @@ class Controller: reason=str(store.data.get("site_sign_reason", "") or "")) if self.site_sign_wd.tripped: _LOG.error( - "Every inverter stays at 0 W after the restart because the " - "total power went the wrong way: %s. Start control once you " - "know why.", + "After the restart every inverter stays at 0 W, as the total " + "power went the wrong way, so find out why before starting " + "control. %s.", self.site_sign_wd.reason or "(reason not recorded)") # And the per-unit detectors are told which question they are asking, # here as well as in `cycle()`. `checks()` and the status page read @@ -720,9 +720,9 @@ class Controller: self._announced_mono = {} if self.circ_wd.tripped: _LOG.error( - "Every inverter stays at 0 W after the restart because the " - "inverters worked against each other: %s. Start control once " - "you know why.", + "After the restart every inverter stays at 0 W, as the " + "inverters worked against each other, so find out why before " + "starting control. %s.", self.circ_wd.reason or "(reason not recorded)") # SAFETY-03. The output clamp's alarm - see clamp.py for why the clamp @@ -1228,8 +1228,8 @@ class Controller: first.store_set("sign_reason", first.sign_wd.reason) first.store_set("sign_tripped", True) _LOG.error( - "%s is set to 0 W again, because an older saved safety stop was " - "found: %s. Start control once you know why.", + "%s is set to 0 W again because an older saved safety stop was " + "found, so find out why before you start control. %s.", first.name, first.sign_wd.reason) _LOG.debug( "SAFETY-02 latch guard: the pre-DEV-02 flat key says the " @@ -1953,11 +1953,18 @@ class Controller: # learns to skim it. # UX-08 2d: plain, with SAFETY-57's escape clause kept as an # ordered pair (time, then power), and the reason still in `%s`. - _LOG.error("%s: battery power reading stopped changing. Inverters " - "go to 0 W until it changes, or %.0f s after the " - "command drops below %.0f W: %s.", + # UX-10: one sentence, then the reason's two. Its limits are on + # the DEBUG line below, to keep the line within 3 sentences. + _LOG.error("%s: battery power reading stopped changing, set to " + "0 W until it changes, or %.0f s after the command " + "drops below %.0f W. %s.", inv.name, inv.batt_fresh.bound.release_s, inv.batt_fresh.bound.move_w, inv.batt_fresh.reason) + _LOG.debug("%s: the limits are unchanged over %.0f s, a command " + "over %.0f W and a move by over %.0f W.", inv.name, + inv.batt_fresh.bound.unchanged_s, + inv.batt_fresh.bound.move_w, + inv.batt_fresh.bound.move_w) elif inv.batt_fresh.releases > was_releases: # ⚠️ SAFETY-57. REPORTED, NEVER SILENT. A latch that lets go on a # timer and says nothing is a latch no operator can audit - and this @@ -2187,8 +2194,8 @@ class Controller: self.log_event( f"{inv.name}: WRITE REFUSED {value:+.0f} W - commanding 0 W", hint=messages.hint("write_blocked", unit=inv.name)) - _LOG.error("Refused to send %+.0f W to %s (%s), so it is set to " - "0 W instead. This is a software fault.", + _LOG.error("Refused to send %+.0f W to %s, so it is set to 0 W " + "instead, which is a software fault. The reason: %s.", value, inv.name, refusal) value = 0.0 @@ -2483,8 +2490,8 @@ class Controller: self.store.set("sign_tripped", True) self.log_event(f"FAILSAFE {inv.name}: " + inv.sign_wd.reason, hint=messages.hint("direction", unit=inv.name)) - _LOG.error("%s is set to 0 W because its power went the wrong " - "way: %s. Only starting control clears this.", + _LOG.error("%s is set to 0 W until control is started, " + "because its power went the wrong way. %s.", inv.name, inv.sign_wd.reason) # ⚠️ THE SITE'S OWN STANDING COMMAND, WHICH IS THE SUM OF THE UNITS'. # SAFETY-07 and SAFETY-18 both grade a SITE quantity - the quarter-hour @@ -2531,9 +2538,9 @@ class Controller: self.store.set("site_sign_tripped", True) self.log_event("FAILSAFE site: " + self.site_sign_wd.reason, hint=messages.hint("site_direction")) - _LOG.error("Every inverter is set to 0 W because the total " - "power went the wrong way: %s. Only starting " - "control clears this.", self.site_sign_wd.reason) + _LOG.error("Every inverter is set to 0 W until control is " + "started, because the total power went the wrong " + "way. %s.", self.site_sign_wd.reason) # --- SAFETY-31, AND IT RUNS BESIDE SAFETY-02 FOR THE SAME REASON ----- # Evaluated EVERY cycle, unconditionally, above the "inputs missing but @@ -2564,8 +2571,8 @@ class Controller: self.log_event("CIRCULATING POWER - " + self.circ_wd.reason, hint=messages.hint("circulating")) _LOG.error( - "Every inverter is set to 0 W because the inverters worked " - "against each other: %s. Only starting control clears this.", + "Every inverter is set to 0 W until control is started, " + "because the inverters worked against each other. %s.", self.circ_wd.reason) # --- SAFETY-42, AND IT RUNS HERE FOR SAFETY-02's AND SAFETY-31's REASON @@ -2672,9 +2679,9 @@ class Controller: hint=messages.hint("not_delivering", unit=inv.name)) _LOG.error( - "%s is not delivering: %s. Nothing was changed and control " - "keeps running, and only stopping and starting control " - "clears this.", inv.name, inv.delivery_wd.reason) + "%s is not delivering while control keeps running, and " + "only stopping and starting control clears this. %s.", + inv.name, inv.delivery_wd.reason) _LOG.debug( "SAFETY-42 reports and does not act: commanding a unit " "that is not listening achieves nothing (HW-01), and the " @@ -3522,7 +3529,7 @@ class Controller: # other unit never gets. Loud, every cycle, and it does not change # the resolution - the arbiter already routed by `actuator`. _LOG.error("A limit was filed on the wrong inverter, which is a " - "software fault: %s", " / ".join(resolution.scope_errors)) + "software fault. %s.", " / ".join(resolution.scope_errors)) if resolution.contradiction: self.log_event("ARBITER CONTRADICTION - commanding 0 W, see the log", hint=messages.hint("clash")) @@ -3814,9 +3821,10 @@ class Controller: # SAFETY-40: only an over-rating is a bug; the integrator bound is not. bug = engaged_write or loop_bug if engaged_write: - reason = write_clamp_note([(inv.name, inv.clamp_last) - for inv in clamped_units]) _named = len(self.inverters) > 1 + reason = write_clamp_note([(inv.name if _named else None, + inv.clamp_last) + for inv in clamped_units]) facts = [messages.Clamp(inv.name if _named else None, inv.clamp_last.requested_w, inv.clamp_last.applied_w, @@ -3872,8 +3880,8 @@ class Controller: messages.loop_bound().data()) return _LOG.error( - "Power request too high, which is a software fault: %s. Control is " - "still running. Cut back %s so far.", + "Power request too high, a software fault: %s. Cut back %s so " + "far, control runs on.", self.clamp_wd.reason, messages.times(self.clamp_wd.engagements)) _LOG.debug( "SAFETY-03: silently clipping this is how a winding integrator " @@ -3922,9 +3930,8 @@ class Controller: self.log_event("PEAK_GUARD_SATURATED - " + g.reason, hint=messages.hint("peak_saturated")) _LOG.error( - "The battery is asked for all it can give, but this 15-minute " - "period still goes over the peak limit: %s. Switch off large " - "loads.", g.reason) + "Switch off large loads, the battery alone cannot keep this " + "15-minute period under the peak limit. %s.", g.reason) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A saturated peak guard # is not a frozen meter and is not an out-of-range setpoint. @@ -3980,9 +3987,8 @@ class Controller: # reason carries the word in the middle of a sentence, not at the front. self.log_event(g.reason, hint=messages.hint("peak_reserve")) _LOG.error( - "The peak guard may not draw the battery lower, so this 15-minute " - "period will go over the peak limit: %s. Switch off large loads.", - g.reason) + "Switch off large loads, the peak guard may not draw the battery " + "lower. %s.", g.reason) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A battery at its # energy floor is not a saturated inverter and is not a frozen meter, @@ -4142,8 +4148,8 @@ class Controller: hint=messages.hint("meter_frozen")) _LOG.error( "The meter shows the same value while the battery is asked for " - "full power: %s. Control still follows it, so check the meter.", - self.freeze_wd.reason) + "full power, and control still follows it, so check the meter. " + "%s.", self.freeze_wd.reason) _LOG.debug( "SAFETY-18: nothing else stops this. The meter still answers, so " "its age is fresh, the firmware watchdog is fed and the arbiter " @@ -4257,10 +4263,10 @@ class Controller: and standing is not None and standing.from_feed) if keep: _LOG.warning( - "The price update was incomplete (%s), so the plan " - "from %s is kept until it is %s old.", - plan.words, messages.when(brussels(self.tariff_at)), - messages.duration(TARIFF_MAX_AGE_S)) + "The price update was incomplete, so the plan from %s " + "is kept until it is %s old. The update held %s.", + messages.when(brussels(self.tariff_at)), + messages.duration(TARIFF_MAX_AGE_S), plan.words) else: self.tariff_plan, self.tariff_at = plan, now _LOG.info("tariff refreshed: %s", plan.words) diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index a6a5084..0276899 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -414,8 +414,8 @@ CEILING_MONTH_PEAK = "this month's peak" # SAFETY-24. Why the forced discharge may not be sized. Reasons, not booleans, # for BLIND_*'s reason: the status page, the action log and the operator # notification all have to say WHICH, and "floor-limited" alone is unactionable. -FLOOR_SOC_UNREADABLE = ("the battery level was not read this cycle, and an " - "unread level is not a full battery") +FLOOR_SOC_UNREADABLE = ("the battery level was not read this cycle, and " + "unread is not full") # ⚠️ SAFETY-25. "the peak reserve", not "the SoC floor", and the name is # load-bearing: this string is what the action log and the add-on log print, # and `peak_soc_floor` (“Peak reserve”) bounds THIS GUARD ONLY. Widening it to @@ -818,8 +818,8 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, + ("" if soc is None else f", at {float(soc):.0f} %") + ("" if soc is None or soc_floor is None else f" against {float(soc_floor):.0f} %") - + ". So there is no forced discharge and no charging, floor " - "0 W, and this period will go over the limit")) + + ", so no forced discharge and no charging, and this period " + "will go over the limit")) floor = min(wanted, ceil_top) saturated = floor < wanted @@ -833,8 +833,10 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, f"{QUARTER_S - projection.elapsed_s:.0f} s left, so {ex:.0f} W must " f"come off the meter. The battery measured {float(batt_w):+.0f} W " f"and is asked for {floor:+.0f} W" - + (f". {wanted:+.0f} W was needed, but the inverters give at most " - f"{ceil_top:.0f} W" if saturated else ""))) + # Saturated means floor == ceil_top: the ask IS the most the + # inverters give, so one clause says both. + + (f", the most the inverters give, but {wanted:+.0f} W was needed" + if saturated else ""))) def charge_headroom_w(decision) -> float | None: diff --git a/goodwe_controller/app/price_forecast.py b/goodwe_controller/app/price_forecast.py index 1fc65f9..916a8fc 100644 --- a/goodwe_controller/app/price_forecast.py +++ b/goodwe_controller/app/price_forecast.py @@ -591,9 +591,9 @@ def _walk(series, hours, action) -> Gate: return Gate.block( f"{action.name} needs prices for {action.commits_h:g} hours " f"from {messages.when(brussels(hours[0]))}, and the price for " - f"{messages.when(brussels(u))} is only estimated, from " - f"yesterday or from the fixed tariff. It can start once the " - f"day-ahead prices are published, around 14:00 to 16:00") + f"{messages.when(brussels(u))} is only estimated. It can start " + f"once the day-ahead prices are published, around 14:00 to " + f"16:00") pts.append(p) return Gate.permit(action, pts) diff --git a/goodwe_controller/app/static_tariff.py b/goodwe_controller/app/static_tariff.py index 8b30275..fc6659b 100644 --- a/goodwe_controller/app/static_tariff.py +++ b/goodwe_controller/app/static_tariff.py @@ -1358,12 +1358,12 @@ def _degrade(opts, read, since, until, stamp) -> TariffPlan: "no tariff at all.", e) profile = None if profile is None: - _LOG.warning("The price feed failed: %s. No fixed tariff is set to " - "fall back to, so trading is off. Peak limiting and home " - "use go on.", read.reason) + _LOG.warning("The price feed failed and no fixed tariff is set, so " + "trading is off, while peak limiting and home use go on. " + "%s.", read.reason) return TariffPlan(read, None, "none") - _LOG.warning("The price feed failed: %s. The fixed tariff is used " - "instead, marked as estimated, and trading is off.", + _LOG.warning("The price feed failed, so the fixed tariff is used " + "instead, marked as estimated, and trading is off. %s.", read.reason) points = profile.series(since, until, provisional=True) return TariffPlan( diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index a738c51..3c900f0 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -2039,7 +2039,7 @@ check("defect 2: the integrator accumulator is not printed as a request", wind and all(f"{d.i_w:+.0f} W" not in r and "asked for" not in r for d, t, r in wind)) check("the command quoted is that tick's Decision, not a later read", - wind and all(f"command this cycle was {d.target_w:+.0f} W" in r + wind and all(f"command now {d.target_w:+.0f} W" in r for d, t, r in wind)) check("at the bound nothing is described as 'above' or 'over' the rating", wind and all(" above " not in r and " over " not in r @@ -2072,18 +2072,18 @@ for d, t, r in over[:2]: check("PRECONDITION: the output clamp engaged on a tick where the slew limit " "rewrote the command AND the integrator differs from the request", any(t != _f(d, 'clamped_w') and d.i_w != _f(d, 'requested_w') for d, t, r in over)) -check("the over-rating says it went over the rating", - over and all(" rating, and cut it back to " in r for d, t, r in over)) +check("the over-rating says it was cut to the rating", + over and all(" W rating, command now " in r for d, t, r in over)) check("defect 2: it quotes the requested COMMAND of that tick, not i_w", over and all(f"computed {_f(d, 'requested_w'):+.0f} W" in r for d, t, r in over)) -check("defect 3: 'cut it back to' is the clamp's own result, not self.target", - over and all(f"cut it back to {_f(d, 'clamped_w'):+.0f} W" in r +check("defect 3: 'cut to' is the clamp's own result, not self.target", + over and all(f"cut to the {_f(d, 'clamped_w'):+.0f} W rating" in r for d, t, r in over)) check("...and its ERROR says it is a software fault and that control keeps " "running (UX-08 2d moved the 14 768 W rationale to a DEBUG line beside " "it, which is still in main.py)", any(x.levelno == logging.ERROR and "software fault" in x.getMessage() - and "Control is still running" in x.getMessage() for x in log_o) + and "control runs on" in x.getMessage() for x in log_o) and "reached 14 768 W on this project" in open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "app", "main.py"), encoding="utf-8").read()) diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 541b189..9943508 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -862,7 +862,7 @@ DATA = { # hass.py: the _moan() wrapper and what its callers pass "hass.py:msg", "hass.py:*args", "hass.py:entity_id", "hass.py:err", "hass.py:obj", "hass.py:raw", "hass.py:domain", "hass.py:service", - "hass.py:resp.status", "hass.py:body[:200]", "hass.py:what", + "hass.py:resp.status", "hass.py:said", "hass.py:entity", "hass.py:what", # main.py "main.py:'cancelled' if task.cancelled() else repr(exc) if exc else 'returned'", "main.py:EXIT_CONTROL_DIED", "main.py:first.name", "main.py:OPTIONS_PATH", @@ -975,7 +975,9 @@ def _clamp_texts(): i_w=4500.0) write = [(n, _clamp.clamp_to_rating(w, 5000.0, -2500.0, 2500.0)) for n, w in (("inverter-a", 3000.0), ("inverter-b", -7412.0))] + # One inverter is not named (main.py passes None), several are. return [_clamp.loop_clamp_note(over), _clamp.loop_clamp_note(at), + _clamp.write_clamp_note([(None, write[0][1])]), _clamp.write_clamp_note(write[:1]), _clamp.write_clamp_note(write)] @@ -1098,6 +1100,20 @@ def reason_problems(text): return out + line_problems(text) +def logged_shape(line): + """UX-10 review: the line as logged, wrapper and reason together, has the + red-alarm shape too. The reason alone passing is not enough: the 2d-style + "title: reason. tail. tail." line read as 4 sentences with a 3-sentence + reason inside it.""" + out = [] + if sentences(line) > 3: + out.append(f"over 3 sentences ({sentences(line)})") + long = [x for x in re.split(r"(?<=[.!?])\s+", line) if len(words(x)) > 30] + if long: + out.append(f"a sentence over 30 words ({len(words(long[0]))})") + return out + + def line_problems(text): """What no WARNING+ line may carry, whatever its length.""" out = [] @@ -1145,7 +1161,7 @@ def scan_log_lines(files, text=None, data=None): lambda m: next(slots, m.group(0)), template) line = PLACEHOLDER.sub("X", line).replace("\0", sample) p += [f"as logged: {x}" for x in line_problems(line) - if x not in p] + + logged_shape(line) if x not in p] if p: bad.append((key, sample, p)) unknown = sorted(seen - set(data) - set(text)) @@ -1174,6 +1190,36 @@ check(f"no WARNING+ line puts a plural noun after a bare count, which reads " f"'1 times' (use messages.times() and friends; found: {_counts})", not _counts) +# UX-10 review: the two clamp lines the owner quoted, as logged for one +# inverter, fit the red shape the tight way: at most 3 sentences and 30 words +# in all, code and numbers kept. The real literals from main.py, filled with +# the real notes. +def _clamp_line(opening): + for n in ast.walk(dict(_FILES)["main.py"]): + if isinstance(n, ast.Call) and LOG_CALL.search(ast.unparse(n.func)) \ + and n.args and (render(n.args[0]) or "").startswith(opening): + return n.args[0].value + return None + + +_over, _at, _w1, _w1n, _w2 = _clamp_texts() +_clamp_lines = { + "error, loop": (_clamp_line("Power request too high"), _over), + "error, write": (_clamp_line("Power request too high"), _w1), + "warning, loop": (_clamp_line("The battery gives less than asked"), _at), +} +_clamp_shown = {k: (f % (r, messages.times(1)) if f else None) + for k, (f, r) in _clamp_lines.items()} +for k, v in _clamp_shown.items(): + print(f" {k}: {v!r} ({len(words(v or ''))} words)") +check("the clamp lines for one inverter are at most 3 sentences and 30 words, " + "and keep OUTPUT_CLAMP and the numbers", + all(v and sentences(v) <= 3 and len(words(v)) <= 30 + and "OUTPUT_CLAMP" in v and "1 time so far" in v + for v in _clamp_shown.values()) + and all(x in _clamp_shown["error, loop"] + for x in ("+9000 W", "+5000 W", "+2000 W", "software fault"))) + # Mutations: the scan catches what the 2d scan missed. _OLD_CLAMP = ("OUTPUT_CLAMP: the loop computed +2148 W, over the 2000 W rating, " "and it was clamped to +2000 W; the loop's command this cycle was " @@ -1197,6 +1243,13 @@ check("...and '1 times', '(s)', a semicolon and a doubled full stop in a " "Cut back to +2000 W.. Only this.", "index 0, 1, .... Those are left out.", "moved to one part: . Problems"))) +check("...and so is the 2d-style line, a 2-sentence reason inside a title and " + "two tails, which reads as 4 sentences although the reason passes", + logged_shape("Power request too high: OUTPUT_CLAMP: cut to +5000 W. The " + "command was +1000 W. Control is still running. Cut back " + "1 time so far.") + and not reason_problems("OUTPUT_CLAMP: cut to +5000 W. The command was " + "+1000 W")) check("...while '1 s' and '1 time' are fine", not line_problems("Held for 1 s, cut back 1 time so far.")) # INFO lines are not held to the length rule, but the 2d test found "§8.3", @@ -1317,6 +1370,56 @@ check("...and the library's own text is kept, at DEBUG", and not any("8:1000" in m or "Bad Gateway" in m for m in _warn + _info)) +class _Resp400: + def __init__(self, body): + self.status, self.reason, self._body = 400, "Bad Request", body + + async def __aenter__(self): + return self + + async def __aexit__(self, *a): + return False + + async def text(self): + return self._body + + +class _Session400: + def __init__(self, body): + self.body = body + + def post(self, *a, **k): + return _Resp400(self.body) + + +def _refused(body): + ha = _hass.HomeAssistant(_Session400(body), token="t") + ok = [] + recs = _captured("goodwe.hass", lambda: ok.append(asyncio.run( + ha.call("number", "set_value", {"entity_id": "number.sp", "value": 1})))) + return (ok[0] if ok else None), [r.getMessage() for r in recs + if r.levelno == logging.WARNING] + + +def _one(res): + """(write result, the one WARNING line) or a named absence that fails.""" + ok, lines = res + return ok, (lines[0] if len(lines) == 1 else f"<{len(lines)} lines>") + + +_bare_ok, _bare = _one(_refused("400: Bad Request")) +_full_ok, _full = _one(_refused( + '{"message": "Value 6000 for number.sp is outside valid range"}')) +check(f"a write Home Assistant refuses while it loads is one plain WARNING, " + f"still a failed write, without the empty '400: Bad Request' ({_bare!r})", + _bare_ok is False + and _bare.startswith("Home Assistant refused number.set_value for " + "number.sp (error 400, no details).") + and "Bad Request" not in _bare) +check(f"...while a body that says more is still quoted ({_full!r})", + _full_ok is False and "outside valid range" in _full) + + class _WS: def __init__(self, kind): self.kind = kind -- 2.54.0 From 2f1627e28738ec0b6d68ed8dcf515b18dd3a1e9c Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 12:19:51 +0200 Subject: [PATCH 042/105] CI: bump infra pin to d637d0b (admin/goodwe#61, UX-10) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .gitea/infra-pin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/infra-pin b/.gitea/infra-pin index c2040ec..2434e5a 100644 --- a/.gitea/infra-pin +++ b/.gitea/infra-pin @@ -1,2 +1,2 @@ # The admin/goodwe commit CI tests against. Bump: set to the full SHA of admin/goodwe release/1.0 HEAD (README.md, "CI and the infra pin"). -ecd3864d9376a990c267dfb399eb2dae4e56c76b +d637d0b1b13f1b863dc47e445e2ca4cf4a82fe10 -- 2.54.0 From 29837dfaa74dd22f897bea9b7ed31d5546a6457c Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 13:34:30 +0200 Subject: [PATCH 043/105] UX-11: safety log lines give one plain sentence and the code, the figures go to DEBUG - Every WARNING/ERROR line that reported a safety reason (direction, delivery, stuck meter, stale reading, peak guard, circulation, over-rating) now ends in the reason's code (messages.reason_code()). The reason itself, figures and limits included, is on a DEBUG line right after it and in the action log. - The reasons and state.json are unchanged, so an old state file loads and shows the same way: every saved reason opens with its code. - test_messages part 6 checks every WARNING+ line at 25 words as logged; nine non-safety families are listed with a reason and capped. The byte pin in test_watchdog now pins the meaning, in order. - The meter logs one WARNING per quiet episode, and INFO when back, so the red row's "the add-on log shows why" holds. The Why line past the hold names the missing reading. Action log: "25 engagements", "Shadow mode off: ...". No trigger, latch, threshold, log level, notification id, cadence, row colour or banner order changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 2 +- .../DECISIONS/UX-08-short-notifications.md | 11 + goodwe_controller/DOCS.md | 18 +- goodwe_controller/app/main.py | 130 ++++++--- goodwe_controller/app/messages.py | 21 ++ goodwe_controller/app/watchdog.py | 9 +- goodwe_controller/test_clamp.py | 13 +- goodwe_controller/test_freshness.py | 7 +- goodwe_controller/test_messages.py | 274 ++++++++++++++++-- goodwe_controller/test_watchdog.py | 24 +- 10 files changed, 425 insertions(+), 84 deletions(-) diff --git a/STYLE.md b/STYLE.md index 09b06be..e3b3c8f 100644 --- a/STYLE.md +++ b/STYLE.md @@ -7,7 +7,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. - **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. -- **Log line** (WARNING/ERROR): one line, at most 25 words, with the numbers that matter. The reasoning goes on a DEBUG line. Log lines stay in English and are not translated. A reason text a line quotes (`%s`) keeps its reason code (`OUTPUT_CLAMP`, `STALE_READING`), because that is the evidence an installer searches for. The reason itself has the shape of a red alarm: at most 3 sentences of at most 30 words. The line as logged has no semicolon, banned word, capitals, "1 times" or "(s)". `test_messages.py` part 6 builds every such reason with the real code and checks it. A line that repeats every cycle is DEBUG. INFO lines carry no section numbers, ISO timestamps or capitals. +- **Log line** (WARNING/ERROR): one line of at most 25 words **as logged**, with any built text filled in. Log lines stay in English and are not translated. A line that reports a safety reason gives one plain sentence and the reason's code (`STALE_READING`, `OUTPUT_CLAMP`), the evidence an installer searches for. The reason itself, with its figures and limits, goes on a DEBUG line right after it and into the action log, never onto the WARNING/ERROR line. It keeps the shape of a red alarm: at most 3 sentences of at most 30 words. The line as logged has no semicolon, banned word, capitals, "1 times" or "(s)". `test_messages.py` part 6 builds every such text with the real code and checks it, and lists the few non-safety families still over 25 words. A line that repeats every cycle is DEBUG. INFO lines carry no section numbers, ISO timestamps or capitals. - **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3). - **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown on the page. Installers read it as `events` in the `status` JSON. - **Sentences**: one idea each, active voice, present tense, with nothing nested in brackets and no semicolons (a semicolon is a second sentence in disguise). These translate well into Dutch and French. diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index ee2cc44..e4b2832 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -78,3 +78,14 @@ The allowlist is empty and its cap is 0 (43 → 0). Every WARNING and ERROR line 7. **Review: the line as logged gets the shape too.** Part 6 first checked the quoted reason alone, so a title, a 2-sentence reason and two tails still logged as 4 sentences ("Power request too high …: OUTPUT_CLAMP: … +5000 W. The command this cycle was +1000 W. Control is still running. Cut back 1 time so far."). Part 6 now also checks the whole line: at most 3 sentences, none over 30 words. The wrappers became one sentence each, the circulation and peak guard reasons two, and `STALE_READING`'s fixed limits moved from the reason to a DEBUG line beside the ERROR (its release clause stays, pinned by test_freshness). The clamp lines for one inverter are pinned at 30 words at most: `OUTPUT_CLAMP: computed +9000 W, cut to the +5000 W rating, command now +2000 W`. Several clamped inverters read as one sentence of asked/sent pairs; which limit bound each is on its own action-log row and in the notification. Totals above 30 words remain on the direction, delivery, frozen-meter and stale lines (up to 74 words). Shortening them is a follow-up: the direction and delivery reasons are also persisted in state.json, and the direction one is pinned byte-for-byte in test_watchdog. 8. **Home Assistant 400 while it loads** now reads "Home Assistant refused number.set_value for number.x (error 400, no details). The entity may still be loading, or the value is out of range." A body with more than "400: Bad Request" is still quoted. Still WARNING, still once a minute, still a failed write. 9. **Witness** (admin/goodwe): the resolved push says "after no answers from … to …", as the resolved card does. The YAML with every title and message stripped is identical. + +# UX-11: safety log lines give the code, the figures go to DEBUG + +**Unchanged:** every trigger, latch, threshold and alarm log level (the WARNING and ERROR lines stay), every notification id and cadence, every row colour and the banner cascade. No notification is added. + +1. **One plain sentence and the code.** A WARNING/ERROR line that reports a safety reason (direction, delivery, stuck meter, stale reading, peak guard, circulation, over-rating) now ends in the reason's code, taken by `messages.reason_code()`. The reason itself, figures and limits included, is on a DEBUG line logged right after it ("Evidence for inverter-a: …"), and the action log entry carries it as before. Part 6 checks that pairing in the code. Circulation and the clamp lines were not among the five named, but they break the same 25-word rule, so they follow the same pattern. The clamp numbers stay in the notification (phase 2a item 3). +2. **The reasons and `state.json` are unchanged.** `reason` stays the evidence text, so what is saved has the same format as before. An old state file therefore loads and displays like a new one: every saved reason has opened with its code since it was first written (checked in the git history), and that code is all the ERROR line reads. The saved text goes on the DEBUG line. A stop saved without a reason shows `REASON_NOT_SAVED`. `test_messages.py` part 7 restarts from a state file holding the old long texts. The byte pin in `test_watchdog.py` now pins the meaning: the code first, then command, reading, time and both limits, in that order. +3. **The 25-word rule is checked as logged.** Part 6 fails any WARNING+ line over 25 words with its built text filled in. Nine non-safety families still run long (tariff plan words, price feed reasons, the state migration report, write refusals and claim scope errors that only a software fault raises, maintenance, trading gate and price history reasons). They are listed with a reason in `LONG_LINE_OK`, capped at 9, and a listed family that gets shorter fails until it is removed. Shortening them is a follow-up. +4. **The meter row's "the add-on log shows why" is now true.** When the meter goes quiet past its limit, the add-on logs one WARNING per episode, not one per cycle, and an INFO line when readings return. This is a new log line, not a new alarm: it has no notification and changes no decision. +5. **The Why line past the 15 s hold** names the missing reading ("No usable meter reading for over 15 seconds: 0 W", or the battery power or level of an inverter), instead of "A reading is missing: 0 W". +6. **Action log:** "25 engagement(s)" is "25 engagements", and "SHADOW MODE OFF - …" is "Shadow mode off: …". "SHADOW MODE ON" was not named in the card and is left as it is. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 1c4018b..a51a92c 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3095,8 +3095,9 @@ stop control on the add-on page. This part is for installers. The texts live in `app/messages.py` and follow `STYLE.md`. Every notification keeps a fixed `notification_id`, so a repeat -replaces the card. The full figures and reason codes are on the ERROR or -WARNING line of the add-on log. +replaces the card. The ERROR or WARNING line of the add-on log names the +reason code. The full figures are on the DEBUG line logged right after it +(log level `debug`) and in `events` in the `status` JSON. | Title | Severity | id | Card | |---|---|---|---| @@ -3223,8 +3224,9 @@ ends. That row says how to clear it. ### For installers: status page -The texts are in `app/messages.py`. The full figures of any alarm are on its -ERROR or WARNING line in the add-on log. +The texts are in `app/messages.py`. An alarm's ERROR or WARNING line names its +reason code, and its full figures are on the DEBUG line right after it and in +`events` in the `status` JSON. - **Stuck-meter check: off** needs `meter_source: homewizard_local` (label “Where the meter reading comes from”), a `max_w` (“Inverter rating”) and a @@ -3246,9 +3248,13 @@ ERROR or WARNING line in the add-on log. check** SAFETY-42. - **Month peak** and **15-minute periods measured** are TARIFF-01 and TARIFF-13. The store's state at start is the INFO line `Month peak store: - …`, and the peak guard's full reason is on its log line. + …`, and the peak guard's full reason is on the DEBUG line after its ERROR. - ***name*: battery power reading stopped changing** is SAFETY-37/56/57. The - ERROR line carries the full `STALE_READING` reason and when it clears. + ERROR line says when it clears and names `STALE_READING`. The full reason, + with both possible causes, is on the DEBUG line after it. +- **Meter: no reading for …** (red): the add-on logs one WARNING when the + meter goes quiet, "No meter reading for …", and an INFO line when readings + return. Past `stale_input_s` the **Why** line names the missing reading. - The table at the top: **Why** is `messages.why()`, the arbiter's answer in words (`Resolution.explain()` stays on the log). **Tariff**, **Price history**, **Arbitrage** and **Shadow mode** keep every figure they had diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 54598a1..a5df597 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -611,9 +611,13 @@ class Controller: self._grade_store_migration(store) for inv in self.inverters: if inv.sign_wd.tripped: + # UX-11: the plain sentence and the code. The saved reason, + # with its figures, is on the DEBUG line beside it. _LOG.error("%s stays at 0 W after the restart because its " "power went the wrong way, so find out why before " - "you start control. %s.", inv.name, + "you start control: %s.", inv.name, + messages.reason_code(inv.sign_wd.reason)) + _LOG.debug("Evidence for %s: %s.", inv.name, inv.sign_wd.reason or "(reason not recorded)") # --- SAFETY-42 + SAFETY-34 ------------------------------------------- @@ -637,8 +641,10 @@ class Controller: _LOG.error( "%s is still marked as not delivering after the restart " "while control keeps running, and only stopping and " - "starting control clears this. %s.", - inv.name, inv.delivery_wd.reason or "(reason not recorded)") + "starting control clears this: %s.", + inv.name, messages.reason_code(inv.delivery_wd.reason)) + _LOG.debug("Evidence for %s: %s.", inv.name, + inv.delivery_wd.reason or "(reason not recorded)") # --- SAFETY-30: THE SITE HALF OF THE SIGN CHECK ---------------------- # ⚠️ ONE PER SITE, BESIDE THE ONE PER INVERTER, AND ARMED ONLY AT N>=2. @@ -669,8 +675,9 @@ class Controller: _LOG.error( "After the restart every inverter stays at 0 W, as the total " "power went the wrong way, so find out why before starting " - "control. %s.", - self.site_sign_wd.reason or "(reason not recorded)") + "control: %s.", messages.reason_code(self.site_sign_wd.reason)) + _LOG.debug("Evidence for the site: %s.", + self.site_sign_wd.reason or "(reason not recorded)") # And the per-unit detectors are told which question they are asking, # here as well as in `cycle()`. `checks()` and the status page read # `inv.sign_wd.cfg` and can be called before the first cycle has run, so @@ -722,8 +729,10 @@ class Controller: _LOG.error( "After the restart every inverter stays at 0 W, as the " "inverters worked against each other, so find out why before " - "starting control. %s.", - self.circ_wd.reason or "(reason not recorded)") + "starting control: %s.", + messages.reason_code(self.circ_wd.reason)) + _LOG.debug("Evidence for the site: %s.", + self.circ_wd.reason or "(reason not recorded)") # SAFETY-03. The output clamp's alarm - see clamp.py for why the clamp # itself is the cheap half. @@ -929,6 +938,8 @@ class Controller: self.following = False self.reason = "starting" self.why_words = "Starting" + # UX-11: has this meter episode's WARNING been logged? See read_inputs. + self._meter_quiet_logged = False # ALLOC-01. The allocation record from the last resolution, or None # before the first cycle. ⚠️ IT IS KEPT SO THAT SOMETHING CAN GATE ON # IT: SAFETY-28 puts the write path behind this record, and DEV-02 reads @@ -1229,8 +1240,9 @@ class Controller: first.store_set("sign_tripped", True) _LOG.error( "%s is set to 0 W again because an older saved safety stop was " - "found, so find out why before you start control. %s.", - first.name, first.sign_wd.reason) + "found, so find out why before you start control: %s.", + first.name, messages.reason_code(first.sign_wd.reason)) + _LOG.debug("Evidence for %s: %s.", first.name, first.sign_wd.reason) _LOG.debug( "SAFETY-02 latch guard: the pre-DEV-02 flat key says the " "sign-disagreement failsafe is latched and no inverter came up " @@ -1726,6 +1738,18 @@ class Controller: return all(inv.soc is not None and inv.batt is not None for inv in self.inverters) + def missing_reading(self) -> str: + """UX-11: the first reading `inputs_ok` finds missing, in words.""" + if self.grid is None or not self.inverters: + return "meter" + for inv in self.inverters: + of = "" if len(self.inverters) == 1 else f" from {inv.name}" + if inv.batt is None: + return f"battery power{of}" + if inv.soc is None: + return f"battery level{of}" + return "input" + # -- io ------------------------------------------------------------------ @property def pv_roster(self) -> tuple: @@ -1885,6 +1909,21 @@ class Controller: horizon_h=float(price_option(o, "price_horizon_h")), provider=provider_configured(o), max_age_s=TARIFF_MAX_AGE_S) + # UX-11: the red meter row says "the add-on log shows why", so a meter + # that goes quiet gets one WARNING per episode, not one per cycle. It + # is a log line only: no notification, and nothing it decides. + if self.p1_enabled: + if (self.p1.stale and not self._meter_quiet_logged + and self.p1.published_age_s > self.p1.max_age_s): + self._meter_quiet_logged = True + _LOG.warning("No meter reading for %s, over the limit of %s, " + "so control waits and then sets the battery to " + "0 W.", messages.seconds(self.p1.published_age_s), + messages.seconds(self.p1.max_age_s)) + elif not self.p1.stale and self._meter_quiet_logged: + self._meter_quiet_logged = False + _LOG.info("Meter readings are back.") + if self.inputs_ok: if self.inputs_bad_since is not None: self.log_event("inputs recovered", @@ -1953,13 +1992,16 @@ class Controller: # learns to skim it. # UX-08 2d: plain, with SAFETY-57's escape clause kept as an # ordered pair (time, then power), and the reason still in `%s`. - # UX-10: one sentence, then the reason's two. Its limits are on - # the DEBUG line below, to keep the line within 3 sentences. + # UX-11: one sentence and the code. The reason, with SAFETY-56's + # two explanations and its figures, and the limits are on the + # DEBUG lines below and in the action log. _LOG.error("%s: battery power reading stopped changing, set to " "0 W until it changes, or %.0f s after the command " - "drops below %.0f W. %s.", + "drops below %.0f W: %s.", inv.name, inv.batt_fresh.bound.release_s, - inv.batt_fresh.bound.move_w, inv.batt_fresh.reason) + inv.batt_fresh.bound.move_w, + messages.reason_code(inv.batt_fresh.reason)) + _LOG.debug("Evidence for %s: %s.", inv.name, inv.batt_fresh.reason) _LOG.debug("%s: the limits are unchanged over %.0f s, a command " "over %.0f W and a move by over %.0f W.", inv.name, inv.batt_fresh.bound.unchanged_s, @@ -2491,8 +2533,10 @@ class Controller: self.log_event(f"FAILSAFE {inv.name}: " + inv.sign_wd.reason, hint=messages.hint("direction", unit=inv.name)) _LOG.error("%s is set to 0 W until control is started, " - "because its power went the wrong way. %s.", - inv.name, inv.sign_wd.reason) + "because its power went the wrong way: %s.", + inv.name, messages.reason_code(inv.sign_wd.reason)) + _LOG.debug("Evidence for %s: %s.", inv.name, + inv.sign_wd.reason) # ⚠️ THE SITE'S OWN STANDING COMMAND, WHICH IS THE SUM OF THE UNITS'. # SAFETY-07 and SAFETY-18 both grade a SITE quantity - the quarter-hour # average at the grid connection, and a meter that has stopped moving @@ -2540,7 +2584,10 @@ class Controller: hint=messages.hint("site_direction")) _LOG.error("Every inverter is set to 0 W until control is " "started, because the total power went the wrong " - "way. %s.", self.site_sign_wd.reason) + "way: %s.", + messages.reason_code(self.site_sign_wd.reason)) + _LOG.debug("Evidence for the site: %s.", + self.site_sign_wd.reason) # --- SAFETY-31, AND IT RUNS BESIDE SAFETY-02 FOR THE SAME REASON ----- # Evaluated EVERY cycle, unconditionally, above the "inputs missing but @@ -2572,8 +2619,9 @@ class Controller: hint=messages.hint("circulating")) _LOG.error( "Every inverter is set to 0 W until control is started, " - "because the inverters worked against each other. %s.", - self.circ_wd.reason) + "because the inverters worked against each other: %s.", + messages.reason_code(self.circ_wd.reason)) + _LOG.debug("Evidence for the site: %s.", self.circ_wd.reason) # --- SAFETY-42, AND IT RUNS HERE FOR SAFETY-02's AND SAFETY-31's REASON # Evaluated EVERY cycle, unconditionally, ABOVE the "inputs missing but @@ -2680,8 +2728,10 @@ class Controller: unit=inv.name)) _LOG.error( "%s is not delivering while control keeps running, and " - "only stopping and starting control clears this. %s.", - inv.name, inv.delivery_wd.reason) + "only stopping and starting control clears this: %s.", + inv.name, messages.reason_code(inv.delivery_wd.reason)) + _LOG.debug("Evidence for %s: %s.", inv.name, + inv.delivery_wd.reason) _LOG.debug( "SAFETY-42 reports and does not act: commanding a unit " "that is not listening achieves nothing (HW-01), and the " @@ -3554,9 +3604,14 @@ class Controller: # UX-10: `why_key()` maps a safety winner to its claim's reason, and # every key it can return has words in messages.WHY_WINNER. _why = why_key(resolution.winner, claims) - self.why_words = messages.why(_why, resolution.target_w, - resolution.bound_by, - contradiction=resolution.contradiction) + if _why == "inputs missing" and not resolution.contradiction: + # UX-11: past the hold, say which reading is missing. + self.why_words = messages.why_missing(self.missing_reading(), + stale_after) + else: + self.why_words = messages.why( + _why, resolution.target_w, resolution.bound_by, + contradiction=resolution.contradiction) # --- DEV-02: EACH INVERTER IS TOLD ITS OWN SHARE --------------------- # ⚠️ ITS OWN SHARE, NEVER THE SITE TARGET. `resolution.shares` is the # allocator's answer and `sum(shares) + unmet_w == round(target_w)` is @@ -3743,8 +3798,8 @@ class Controller: shadow.why(self.o, control_started=self.auto)) elif not first: self.log_event( - "SHADOW MODE OFF - the battery is being controlled again, " - f"resuming from {shadow.WIRE_W:.0f} W", + "Shadow mode off: the add-on controls the battery again, " + f"starting from {shadow.WIRE_W:.0f} W", hint=messages.hint("shadow_off")) _LOG.info( "Shadow mode is off, so the add-on controls the battery " @@ -3856,8 +3911,9 @@ class Controller: # write-path engagements and 2 loop-side ones. if engaged and not engaged_write: tag = f"{CLAMP_REASON} episode {self.clamp_wd.episodes}" - row = (f"{tag}: {self.clamp_wd.engagements} engagement(s) - " - f"{reason}") + row = (f"{tag}: " + f"{messages.count(self.clamp_wd.engagements, 'engagement')}" + f" - {reason}") if self.events and tag in self.events[0]: stamp = self.events[0].split(" ", 1)[0] self.events[0] = f"{stamp} {row}" @@ -3871,8 +3927,9 @@ class Controller: # WARNING and a plainly titled notice, same cadence. Its OWN id, so # it can never replace a BUG SIGNAL notice still on screen. _LOG.warning("The battery gives less than asked: %s. Held back %s " - "so far.", self.clamp_wd.reason, + "so far.", messages.reason_code(self.clamp_wd.reason), messages.times(self.clamp_wd.engagements)) + _LOG.debug("Evidence: %s.", self.clamp_wd.reason) _LOG.debug("A short hold after a large load or solar step is " "normal. If it lasts, check that the battery follows " "its commands.") @@ -3881,8 +3938,9 @@ class Controller: return _LOG.error( "Power request too high, a software fault: %s. Cut back %s so " - "far, control runs on.", - self.clamp_wd.reason, messages.times(self.clamp_wd.engagements)) + "far, control runs on.", messages.reason_code(self.clamp_wd.reason), + messages.times(self.clamp_wd.engagements)) + _LOG.debug("Evidence: %s.", self.clamp_wd.reason) _LOG.debug( "SAFETY-03: silently clipping this is how a winding integrator " "reached 14 768 W on this project before. The clamp makes every " @@ -3931,7 +3989,9 @@ class Controller: hint=messages.hint("peak_saturated")) _LOG.error( "Switch off large loads, the battery alone cannot keep this " - "15-minute period under the peak limit. %s.", g.reason) + "15-minute period under the peak limit: %s.", + messages.reason_code(g.reason)) + _LOG.debug("Evidence: %s.", g.reason) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A saturated peak guard # is not a frozen meter and is not an out-of-range setpoint. @@ -3988,7 +4048,8 @@ class Controller: self.log_event(g.reason, hint=messages.hint("peak_reserve")) _LOG.error( "Switch off large loads, the peak guard may not draw the battery " - "lower. %s.", g.reason) + "lower: %s.", messages.reason_code(g.reason)) + _LOG.debug("Evidence: %s.", g.reason) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A battery at its # energy floor is not a saturated inverter and is not a frozen meter, @@ -4148,8 +4209,9 @@ class Controller: hint=messages.hint("meter_frozen")) _LOG.error( "The meter shows the same value while the battery is asked for " - "full power, and control still follows it, so check the meter. " - "%s.", self.freeze_wd.reason) + "full power, and control still follows it, so check the meter: " + "%s.", messages.reason_code(self.freeze_wd.reason)) + _LOG.debug("Evidence: %s.", self.freeze_wd.reason) _LOG.debug( "SAFETY-18: nothing else stops this. The meter still answers, so " "its age is fresh, the firmware watchdog is fed and the arbiter " diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index e2e4297..0e072de 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -311,6 +311,22 @@ def seconds(value) -> str: return f"{n} second" if n == "1" else f"{n} seconds" +# One token each, like a code, so the line keeps its length and stays greppable. +NO_REASON_SAVED, NO_REASON_CODE = "REASON_NOT_SAVED", "REASON_WITHOUT_CODE" +_REASON_CODE = re.compile(r"\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+\b") + + +def reason_code(reason) -> str: + """UX-11: the code in a safety reason (`STALE_READING`), for the one plain + WARNING or ERROR line that reports it. The reason with its figures goes on + a DEBUG line beside it and into the action log. Saved reasons have always + opened with their code, so an old state file reads the same way.""" + if not reason: + return NO_REASON_SAVED + m = _REASON_CODE.search(str(reason)) + return m.group(0) if m else NO_REASON_CODE + + def times(n) -> str: return "1 time" if int(n) == 1 else f"{int(n)} times" @@ -813,6 +829,11 @@ def why(winner, target_w, bound_by=None, *, contradiction=False) -> str: return out +def why_missing(what, limit_s) -> str: + """UX-11: past the hold, which reading is missing and what it does.""" + return f"No usable {what} reading for over {seconds(limit_s)}: 0 W" + + def why_waiting(missing_s) -> str: """A reading went missing a moment ago: control holds and waits.""" return f"A reading is missing for {seconds(missing_s)}, control waits" diff --git a/goodwe_controller/app/watchdog.py b/goodwe_controller/app/watchdog.py index bbe857b..8bb97b6 100644 --- a/goodwe_controller/app/watchdog.py +++ b/goodwe_controller/app/watchdog.py @@ -670,11 +670,10 @@ class SignWatchdog: # ⚠️ `self.against` IS THE ONLY THING SAFETY-30 CHANGED IN THIS STRING, # and it defaults to the wording that shipped - "a meter reading" - so a # one-inverter install's `reason` is byte-identical to what an operator - # (and test_watchdog.py) has always read. A per-unit instance names what - # it actually compared instead, because "commanded +1500 W against a - # meter reading -1500 W" would be a false statement about which - # instrument produced the evidence, on the one line somebody woken by - # this alarm reads first. + # has always read (test_watchdog.py pins its meaning). A per-unit + # instance names what it actually compared instead, because "commanded + # +1500 W against a meter reading -1500 W" would be a false statement + # about which instrument produced the evidence. self.reason = ( f"SIGN_DISAGREEMENT: commanded {commanded_w:+.0f} W against " f"{self.against} {against_w:+.0f} W for {held:.0f} s continuously " diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index 3c900f0..9d5ca16 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -521,7 +521,8 @@ check(f"the action log records every engagement, coalesced into one row per " f"episode ({len(rows_r)} row(s), {ctl_r.clamp_wd.engagements} " f"engagement(s))", len(rows_r) == ctl_r.clamp_wd.episodes - and f"{ctl_r.clamp_wd.engagements} engagement(s)" in rows_r[0]) + and messages.count(ctl_r.clamp_wd.engagements, "engagement") + in rows_r[0]) # ⚠️ REGRESSION, AND IT WAS A REAL BUG BEFORE IT WAS A CHECK. `log_event()` keeps # 40 rows. A row per engagement flushes that ring inside 40 cycles of a winding @@ -538,7 +539,8 @@ check(f"a long winding episode does NOT flood the 40-row event log " f"({len(rows_l)} rows for {ctl_l.clamp_wd.engagements} engagements)", ctl_l.clamp_wd.engagements > 40 and len(rows_l) <= ctl_l.clamp_wd.episodes) check("...and the count in the row is the counter's, so nothing is lost", - f"{ctl_l.clamp_wd.engagements} engagement(s)" in nth(rows_l, -1)) + messages.count(ctl_l.clamp_wd.engagements, "engagement") + in nth(rows_l, -1)) # The RED row exists only while engaged, and the episode above is short, so it # is captured mid-run rather than asserted after the hysteresis has cleared it. check("the status page flags it WHILE it is engaged - amber, since it is the " @@ -2051,9 +2053,12 @@ check("it still NOTIFIES (not suppressed), under a title that claims no bug", check("...under its OWN notification_id, so it cannot replace a BUG SIGNAL " "notice still on screen", notes_i and all(n["notification_id"] == BOUND_ID for n in notes_i)) +# UX-11: the WARNING quotes the code. The reason is on the DEBUG line beside +# it (test_messages.py part 6). check("...logged as a WARNING, not an ERROR", - any(x.levelno == logging.WARNING and "reached its" in x.getMessage() - for x in log_i) + any(x.levelno == logging.WARNING + and x.getMessage().startswith("The battery gives less than asked: " + "OUTPUT_CLAMP.") for x in log_i) and not any(x.levelno >= logging.ERROR and "OUTPUT_CLAMP" in x.getMessage() for x in log_i)) check("...and the status row is amber, not red", diff --git a/goodwe_controller/test_freshness.py b/goodwe_controller/test_freshness.py index f09515c..80a8e3c 100644 --- a/goodwe_controller/test_freshness.py +++ b/goodwe_controller/test_freshness.py @@ -1813,6 +1813,11 @@ _S56_ACCUSATIONS = [ ] _log56 = [r.getMessage() for r in _LOGREC[_S56_LOG0:] if "battery power reading stopped changing" in r.getMessage()] +# UX-11: the ERROR line quotes the code, and the reason itself is on the DEBUG +# line logged beside it. +_dbg56 = [r.getMessage() for r in _LOGREC[_S56_LOG0:] + if r.levelno == logging.DEBUG + and r.getMessage().startswith("Evidence for ")] or [""] def _s56_row(c): @@ -1855,7 +1860,7 @@ check("PRECONDITION: all four operator-facing surfaces were really produced by " "two are the same string, which is 11b again on the log surface", len(_log56) == 2 and _log56[0] == _log56[1] and all(len(s) > 30 for s in _S56_SURFACES.values()) - and _r56_ref in _log56[-1]) + and _log56[-1].endswith(": STALE_READING.") and _r56_ref in _dbg56[-1]) _idx56 = [_r56_ref.find(t) for _w, t in _S56_EXPLANATIONS] check(f"11c. BOTH EXPLANATIONS ARE NAMED, AND IN THAT ORDER: " f"{_S56_EXPLANATIONS[0][1]!r} at {_idx56[0]} then " diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 9943508..6bb209e 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -877,6 +877,8 @@ DATA = { "main.py:messages.when(brussels(self.tariff_at))", "main.py:messages.duration(TARIFF_MAX_AGE_S)", "main.py:messages.count(len(targets), 'inverter')", + "main.py:messages.seconds(self.p1.published_age_s)", + "main.py:messages.seconds(self.p1.max_age_s)", # maintenance.py, mqtt.py, p1.py "maintenance.py:phase", "mqtt.py:err", "p1.py:err", "p1.py:self.host", "p1.py:self.topic", "p1.py:poll_s", "p1.py:ingest.max_age_s", @@ -1047,20 +1049,35 @@ def _static(spec): return [t for t in out if len(words(t)) > 1] +# UX-11: a WARNING+ line quotes a safety reason by its code only. The reason, +# with its figures, is on a DEBUG line beside it and in the action log. +SAFETY_REASONS = { + "sign": _sign_texts, "circulation": _circ_texts, + "delivery": _delivery_texts, "clamp": _clamp_texts, "peak": _peak_texts, + "freeze": _freeze_texts, "stale": _stale_texts, +} + + +def _coded(maker): + """The codes a WARNING+ line shows for the reasons `maker` builds, plus + the fallback for a restored stop with no reason saved.""" + return lambda: ([messages.reason_code(t) for t in maker()] + + [messages.reason_code("")]) + + TEXT = { - "main.py:first.sign_wd.reason": _sign_texts, - "main.py:inv.sign_wd.reason": _sign_texts, - "main.py:inv.sign_wd.reason or '(reason not recorded)'": _sign_texts, - "main.py:self.site_sign_wd.reason": _sign_texts, - "main.py:self.site_sign_wd.reason or '(reason not recorded)'": _sign_texts, - "main.py:self.circ_wd.reason": _circ_texts, - "main.py:self.circ_wd.reason or '(reason not recorded)'": _circ_texts, - "main.py:inv.delivery_wd.reason": _delivery_texts, - "main.py:inv.delivery_wd.reason or '(reason not recorded)'": _delivery_texts, - "main.py:self.clamp_wd.reason": _clamp_texts, - "main.py:g.reason": _peak_texts, - "main.py:self.freeze_wd.reason": _freeze_texts, - "main.py:inv.batt_fresh.reason": _stale_texts, + "main.py:messages.reason_code(first.sign_wd.reason)": _coded(_sign_texts), + "main.py:messages.reason_code(inv.sign_wd.reason)": _coded(_sign_texts), + "main.py:messages.reason_code(self.site_sign_wd.reason)": + _coded(_sign_texts), + "main.py:messages.reason_code(self.circ_wd.reason)": _coded(_circ_texts), + "main.py:messages.reason_code(inv.delivery_wd.reason)": + _coded(_delivery_texts), + "main.py:messages.reason_code(self.clamp_wd.reason)": _coded(_clamp_texts), + "main.py:messages.reason_code(g.reason)": _coded(_peak_texts), + "main.py:messages.reason_code(self.freeze_wd.reason)": + _coded(_freeze_texts), + "main.py:messages.reason_code(inv.batt_fresh.reason)": _coded(_stale_texts), "main.py:rep.explain()": _migration_texts, "store.py:rep.explain()": _migration_texts, "main.py:plan.words": _tariff_texts, @@ -1086,6 +1103,26 @@ TEXT = { } +# UX-11: a WARNING+ line, as logged with its built text filled in, is at most +# 25 words (STYLE.md). These families are not safety reasons and were not +# rewritten by UX-11. Each is listed with why, the list may only shrink +# (LONG_LINE_CAP), and a listed key that no longer runs long fails. +LONG_LINE_OK = { + "main.py:plan.words": "tariff plan words, TARIFF-11 pins them, follow-up", + "static_tariff.py:read.reason": "price feed reasons, follow-up", + "main.py:rep.explain()": "state migration report, names saved keys", + "store.py:rep.explain()": "state migration report, names saved keys", + "main.py:refusal": "write refusals, a software fault only", + "main.py:' / '.join(resolution.scope_errors)": + "claim scope errors, a software fault only", + "maintenance.py:msg": "maintenance gate reasons, follow-up", + "price_forecast.py:gate.reason": "trading gate reasons, follow-up", + "price_history.py:self.last_error": "price history errors, follow-up", +} +LONG_LINE_CAP = 9 +LINE_WORDS = 25 + + def reason_problems(text): """STYLE.md's red-alarm shape, for a text a log line quotes.""" out = [] @@ -1133,10 +1170,12 @@ def _fill(template, fmt_node, key_part, sample): return template # %-style: filled by the caller -def scan_log_lines(files, text=None, data=None): +def scan_log_lines(files, text=None, data=None, long_ok=None, long_seen=None): """-> (unclassified keys, stale keys, [(key, sample, problems)]).""" text = TEXT if text is None else text data = DATA if data is None else data + long_ok = LONG_LINE_OK if long_ok is None else long_ok + long_seen = set() if long_seen is None else long_seen seen, bad = set(), [] for fname, tree in files: for key, call in dynamic_parts(tree, fname): @@ -1162,6 +1201,11 @@ def scan_log_lines(files, text=None, data=None): line = PLACEHOLDER.sub("X", line).replace("\0", sample) p += [f"as logged: {x}" for x in line_problems(line) + logged_shape(line) if x not in p] + if len(words(line)) > LINE_WORDS: + long_seen.add(key) + if key not in long_ok: + p.append(f"as logged: over {LINE_WORDS} words " + f"({len(words(line))})") if p: bad.append((key, sample, p)) unknown = sorted(seen - set(data) - set(text)) @@ -1171,14 +1215,79 @@ def scan_log_lines(files, text=None, data=None): _FILES = [(f.name, ast.parse(f.read_text(encoding="utf-8"))) for f in sorted(APP.glob("*.py"))] -_unknown, _stale, _bad = scan_log_lines(_FILES) +_long_seen = set() +_unknown, _stale, _bad = scan_log_lines(_FILES, long_seen=_long_seen) for k, sample, p in _bad: - print(f" BAD {k}: {'; '.join(p)} :: {sample[:110]!r}") + print(f" BAD {k}: {'; '.join(p)} :: {sample!r}") check(f"every dynamic part of a WARNING+ line is classified as data or as a " f"built text (unclassified: {_unknown})", not _unknown) check(f"...and no classification is left over from a line that is gone " f"(stale: {_stale})", not _stale) _n_texts = sum(len(m()) for m in TEXT.values() if m is not None) +check(f"UX-11: no WARNING+ line runs over {LINE_WORDS} words as logged, except " + f"the {len(LONG_LINE_OK)} listed families, and none of them is a safety " + f"reason (cap {LONG_LINE_CAP})", + len(LONG_LINE_OK) <= LONG_LINE_CAP + and not any("reason_code" in k for k in LONG_LINE_OK)) +check(f"...and every listed family still runs long, so the list only shrinks " + f"(no longer long: {sorted(set(LONG_LINE_OK) - _long_seen)})", + set(LONG_LINE_OK) <= _long_seen) + + +def _code_lines_without_evidence(files): + """WARNING+ calls quoting `messages.reason_code(X)` whose next statement + is not a DEBUG call that logs X itself (UX-11: nothing is lost).""" + out, n = [], 0 + for fname, tree in files: + for node in ast.walk(tree): + for body in (getattr(node, f, None) for f in ("body", "orelse")): + if not isinstance(body, list): + continue + for i, st in enumerate(body): + call = st.value if isinstance(st, ast.Expr) else None + if not (isinstance(call, ast.Call) + and LOG_CALL.search(ast.unparse(call.func))): + continue + coded = [a.args[0] for a in call.args + if isinstance(a, ast.Call) and a.args + and ast.unparse(a.func) == "messages.reason_code"] + if not coded: + continue + n += 1 + nxt = body[i + 1] if i + 1 < len(body) else None + dbg = (nxt.value if isinstance(nxt, ast.Expr) + and isinstance(nxt.value, ast.Call) + and ast.unparse(nxt.value.func).endswith(".debug") + else None) + want = ast.unparse(coded[0]) + if dbg is None or not any( + ast.unparse(a) == want + or ast.unparse(a).startswith(want + " or ") + for a in dbg.args): + out.append(f"{fname}:{call.lineno}") + return n, out + + +_n_coded, _no_evidence = _code_lines_without_evidence(_FILES) +check(f"every WARNING+ line that quotes a reason code ({_n_coded}) has the " + f"reason itself on a DEBUG line right after it (missing: {_no_evidence})", + _n_coded >= 14 and not _no_evidence) +_n_m, _m_bad = _code_lines_without_evidence([("x.py", ast.parse( + "_LOG.error('Stop: %s.', messages.reason_code(wd.reason))\n" + "_LOG.debug('Something else.')\n"))]) +check("...and a line whose DEBUG evidence was dropped is caught", + _n_m == 1 and _m_bad == ["x.py:1"]) +_evidence_bad = [(n, t, reason_problems(t)) for n, m in SAFETY_REASONS.items() + for t in m() if reason_problems(t)] +check(f"the safety reasons behind those lines, on the DEBUG line and in the " + f"action log, keep the red-alarm shape ({_evidence_bad})", + not _evidence_bad) +_codes = {n: [messages.reason_code(t) for t in m()] + for n, m in SAFETY_REASONS.items()} +check(f"...and every one carries a code the line can quote ({_codes})", + all(re.fullmatch(r"[A-Z]+(?:_[A-Z]+)+", c) + and c not in (messages.NO_REASON_SAVED, messages.NO_REASON_CODE) + for cs in _codes.values() for c in cs)) check(f"every built text, run for real, obeys the rule, and so does the line " f"that quotes it ({_n_texts} texts, {len(_bad)} bad)", not _bad) _counts = [f"{f}:{n.lineno}" for f, t in _FILES for n in ast.walk(t) @@ -1208,29 +1317,43 @@ _clamp_lines = { "error, write": (_clamp_line("Power request too high"), _w1), "warning, loop": (_clamp_line("The battery gives less than asked"), _at), } -_clamp_shown = {k: (f % (r, messages.times(1)) if f else None) +_clamp_shown = {k: (f % (messages.reason_code(r), messages.times(1)) + if f else None) for k, (f, r) in _clamp_lines.items()} for k, v in _clamp_shown.items(): print(f" {k}: {v!r} ({len(words(v or ''))} words)") -check("the clamp lines for one inverter are at most 3 sentences and 30 words, " - "and keep OUTPUT_CLAMP and the numbers", - all(v and sentences(v) <= 3 and len(words(v)) <= 30 +check("UX-11: the clamp lines are at most 25 words and keep OUTPUT_CLAMP and " + "the count, and the numbers are in the reason the DEBUG line beside " + "them logs", + all(v and len(words(v)) <= LINE_WORDS and "OUTPUT_CLAMP" in v and "1 time so far" in v - for v in _clamp_shown.values()) - and all(x in _clamp_shown["error, loop"] - for x in ("+9000 W", "+5000 W", "+2000 W", "software fault"))) + and "+9000" not in v for v in _clamp_shown.values()) + and "software fault" in _clamp_shown["error, loop"] + and all(x in _over for x in ("+9000 W", "+5000 W", "+2000 W"))) # Mutations: the scan catches what the 2d scan missed. _OLD_CLAMP = ("OUTPUT_CLAMP: the loop computed +2148 W, over the 2000 W rating, " "and it was clamped to +2000 W; the loop's command this cycle was " "+440 W. This is a BUG SIGNAL, not a limit being used: something " "upstream computed a setpoint the actuator cannot deliver.") -_mut_text = dict(TEXT, **{"main.py:self.clamp_wd.reason": lambda: [_OLD_CLAMP]}) +_mut_text = dict(TEXT, **{"main.py:messages.reason_code(self.clamp_wd.reason)": + lambda: [_OLD_CLAMP]}) _u, _s, _b = scan_log_lines([f for f in _FILES if f[0] == "main.py"], text=_mut_text) check("an injected bad reason (the 2d clamp text) is caught, on both clamp " f"lines ({sorted({k for k, _t, _p in _b if 'clamp' in k})})", - [k for k, _t, _p in _b].count("main.py:self.clamp_wd.reason") == 2) + [k for k, _t, _p in _b].count( + "main.py:messages.reason_code(self.clamp_wd.reason)") == 2) +# UX-11: the line that quoted the whole STALE_READING reason (60 words on +# TEST-23) is caught by the length rule alone. +_old_stale = dict(TEXT, **{"main.py:messages.reason_code(inv.batt_fresh.reason)": + _stale_texts}) +_u, _s, _b = scan_log_lines([f for f in _FILES if f[0] == "main.py"], + text=_old_stale) +check("...and the UX-10 stale line, which quoted the whole reason, is caught " + f"for its length ({[p for k, _t, p in _b if 'batt_fresh' in k][:1]})", + any("batt_fresh" in k and any(f"over {LINE_WORDS} words" in x for x in p) + for k, _t, p in _b)) _new_site = ast.parse("_LOG.warning('Something broke: %s', self.new_wd.reason)") _u, _s, _b = scan_log_lines([("main.py", _new_site)]) check(f"...and a new line quoting a text nobody classified is caught ({_u})", @@ -1487,6 +1610,9 @@ class _H: async def call(self, *a, **k): return True + async def set_number(self, *a, **k): + return True + class _S: data = {} @@ -1549,6 +1675,104 @@ _c.why_words = "Keeping the grid near zero: 0 W" check("...and once a cycle decides again, the line is that decision", _c.why_words == "Keeping the grid near zero: 0 W") +# UX-11 item 3: past the hold, the Why line says which reading is missing, +# not "A reading is missing: 0 W". Driven through cycle() for real. +_c.inputs_bad_since = _dt.now(_tz.utc) - _td(seconds=20) +asyncio.run(_c.cycle()) +check(f"past the hold, the Why line names the missing reading " + f"({_c.why_words!r})", + _c.why_words == "No usable meter reading for over 15 seconds: 0 W") + +# UX-11 item 2: the red meter row says the log shows why. A meter that goes +# quiet logs one WARNING per episode, not one per cycle, and INFO when back. +_c.p1_enabled = True +_c.p1 = _p1.P1Ingest(max_age_s=30.0) + + +def _meter_at(age_s): + import time as _time + _c.p1.submit(_p1.make_sample(_p1.SOURCE_HA, 500.0, 0.0, phases=1, + ingest_mono=_time.monotonic() - age_s)) + + +def _quiet_episodes(): + for age in (1, 40, 45, 50, 1, 2, 60, 65): + _meter_at(age) + asyncio.run(_c.read_inputs()) + + +_mq = [r for r in _captured("goodwe", _quiet_episodes) + if "meter" in r.getMessage().lower()] +_mq_warn = [r.getMessage() for r in _mq if r.levelno == logging.WARNING] +_mq_info = [r.getMessage() for r in _mq if r.levelno == logging.INFO] +check(f"a meter that goes quiet logs one WARNING per episode, not per cycle, " + f"and one INFO when readings return ({_mq_warn}, {_mq_info})", + len(_mq_warn) == 2 and _mq_info == ["Meter readings are back."] + and _mq_warn[0].startswith("No meter reading for 40 seconds, over the " + "limit of 30 seconds") + and len(words(_mq_warn[0])) <= LINE_WORDS) + +# UX-11 item 1: a state file saved before UX-11 holds the long reasons, and +# they load unchanged. The ERROR line at start shows the code, and the saved +# text goes on the DEBUG line beside it. Old and new files look the same, +# because the saved reason's format did not change and it opens with its code. +_OLD = { + "sign": "SIGN_DISAGREEMENT: commanded -1000 W against a meter reading " + "+1500 W for 180 s continuously (limits: both over 300 W, held " + "over 180 s)", + "delivery": "UNIT_NOT_DELIVERING: inverter-a is standing at +2000 W and " + "delivering +0 W - 2000 W of its share (100 % of it) is not " + "arriving - while inverter-b is not in that state. Nothing " + "this add-on reads explains it - held for 121 s continuously " + "(limit: over 120 s)", + "circ": "CIRCULATING_POWER: 5800 W measured going round between the " + "inverters for 61 s, peaking at 6000 W, over the limits of 250 W " + "and 60 s. The meter cannot see it, because it nets to zero there", +} + + +class _OldStore(_S): + data = {"unit/inverter-a/sign_tripped": True, + "unit/inverter-a/sign_reason": _OLD["sign"], + "unit/inverter-a/delivery_tripped": True, + "unit/inverter-a/delivery_reason": _OLD["delivery"], + "circ_tripped": True, "circ_reason": _OLD["circ"], + "site_sign_tripped": True, "site_sign_reason": ""} + + +_restart = [] +_rs = _captured("goodwe", lambda: _restart.append(Controller( + {"setpoint_entity": "number.sp", "meter_source": "off", "max_w": 2000}, + _H(), _OldStore(), _P(), stop=asyncio.Event()))) +_rs_err = [r.getMessage() for r in _rs if r.levelno == logging.ERROR] +_rs_dbg = [r.getMessage() for r in _rs if r.levelno == logging.DEBUG] +for _m in _rs_err: + print(f" {_m!r} ({len(words(_m))} words)") +check("an old state file's long reasons load unchanged, so the stops stay on", + _restart and _restart[0].inverters[0].sign_wd.tripped + and _restart[0].inverters[0].sign_wd.reason == _OLD["sign"] + and _restart[0].inverters[0].delivery_wd.reason == _OLD["delivery"] + and _restart[0].circ_wd.reason == _OLD["circ"]) +check("...each ERROR line at start is one plain sentence with the code, at " + f"most {LINE_WORDS} words, and a stop saved without a reason says so", + len(_rs_err) == 4 + and all(len(words(m)) <= LINE_WORDS and "(limits" not in m + for m in _rs_err) + and any(m.endswith(": SIGN_DISAGREEMENT.") for m in _rs_err) + and any(m.endswith(": UNIT_NOT_DELIVERING.") for m in _rs_err) + and any(m.endswith(": CIRCULATING_POWER.") for m in _rs_err) + and any(m.endswith(f": {messages.NO_REASON_SAVED}.") for m in _rs_err)) +check("...and the saved text, figures and all, is on a DEBUG line beside it", + all(any(t in m for m in _rs_dbg) for t in _OLD.values())) + +# UX-11 item 4: the action log's clamp count and the shadow-off entry. +_main_src = (APP / "main.py").read_text(encoding="utf-8") +check("the action log counts 'engagements' with a real plural and the " + "shadow-off entry is plain, not 'engagement(s)' or 'SHADOW MODE OFF -'", + "engagement(s)" not in _main_src and "SHADOW MODE OFF" not in _main_src + and messages.count(25, "engagement") == "25 engagements" + and messages.count(1, "engagement") == "1 engagement") + print() if fails: print(f"{len(fails)} FAILED") diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index 39940ea..cb8d5db 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -1422,14 +1422,22 @@ for _t in range(0, 400, 5): _wd_unit.evaluate(-1000.0, 1500.0, True, T0 + timedelta(seconds=_t)) print(f" site: {_wd_site.reason!r}") print(f" unit: {_wd_unit.reason!r}") -check("⚠️ THE SITE INSTANCE'S SENTENCE IS BYTE-IDENTICAL TO THE ONE THAT " - "SHIPPED. It is what an operator reads on the status page, what goes in " - "the action log and what is persisted to /data/state.json, so it is " - "asserted against the literal rather than against a format string", - _wd_site.reason == ( - "SIGN_DISAGREEMENT: commanded -1000 W against a meter reading " - "+1500 W for 180 s continuously (limits: both over 300 W, held over " - "180 s)")) +# UX-11: this was a byte pin. The reason is now the evidence: the action +# log, the DEBUG line and /data/state.json carry it, and the ERROR line quotes +# only its code (`messages.reason_code()`). So what is pinned is what it says: +# the code in front, where every saved reason has had it and where the ERROR +# line finds it, then the command and the reading in that order (habit 14), +# the time held and both limits. +_sr = _wd_site.reason +_order = [_sr.find(t) for t in ("commanded -1000 W", "meter reading +1500 W", + "for 180 s", "both over 300 W", + "held over 180 s")] +check("⚠️ THE SITE INSTANCE'S REASON SAYS WHAT SHIPPED, IN THE SAME ORDER: " + "the code first, then what was commanded, what the meter read, how " + f"long, and the two limits ({_order})", + _sr.startswith("SIGN_DISAGREEMENT: ") + and messages.reason_code(_sr) == "SIGN_DISAGREEMENT" + and all(i > 0 for i in _order) and _order == sorted(_order)) check("...and the per-unit instance names what it ACTUALLY compared instead. " "'against a meter reading' there would be a false statement about which " "instrument produced the evidence, on the one line somebody woken by " -- 2.54.0 From c628099e692fe052ff0614bec71fb4f549f009f1 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 13:49:17 +0200 Subject: [PATCH 044/105] UX-11: the meter WARNING names the limit only, as 'over 30 seconds' TEST-23 showed 'No meter reading for 30 seconds, over the limit of 30 seconds': the age is 30.4 s, which rounds to the limit. The limit alone is always true at the moment the line is logged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- goodwe_controller/app/main.py | 5 ++--- goodwe_controller/test_messages.py | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index a5df597..ff4abd0 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -1916,9 +1916,8 @@ class Controller: if (self.p1.stale and not self._meter_quiet_logged and self.p1.published_age_s > self.p1.max_age_s): self._meter_quiet_logged = True - _LOG.warning("No meter reading for %s, over the limit of %s, " - "so control waits and then sets the battery to " - "0 W.", messages.seconds(self.p1.published_age_s), + _LOG.warning("No meter reading for over %s, so control " + "waits and then sets the battery to 0 W.", messages.seconds(self.p1.max_age_s)) elif not self.p1.stale and self._meter_quiet_logged: self._meter_quiet_logged = False diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 6bb209e..7513364 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -877,7 +877,6 @@ DATA = { "main.py:messages.when(brussels(self.tariff_at))", "main.py:messages.duration(TARIFF_MAX_AGE_S)", "main.py:messages.count(len(targets), 'inverter')", - "main.py:messages.seconds(self.p1.published_age_s)", "main.py:messages.seconds(self.p1.max_age_s)", # maintenance.py, mqtt.py, p1.py "maintenance.py:phase", "mqtt.py:err", "p1.py:err", "p1.py:self.host", @@ -1708,8 +1707,8 @@ _mq_info = [r.getMessage() for r in _mq if r.levelno == logging.INFO] check(f"a meter that goes quiet logs one WARNING per episode, not per cycle, " f"and one INFO when readings return ({_mq_warn}, {_mq_info})", len(_mq_warn) == 2 and _mq_info == ["Meter readings are back."] - and _mq_warn[0].startswith("No meter reading for 40 seconds, over the " - "limit of 30 seconds") + and _mq_warn[0] == "No meter reading for over 30 seconds, so control " + "waits and then sets the battery to 0 W." and len(words(_mq_warn[0])) <= LINE_WORDS) # UX-11 item 1: a state file saved before UX-11 holds the long reasons, and -- 2.54.0 From 3c298af3d89c252e46d4ccc11e7bd85c228a07b2 Mon Sep 17 00:00:00 2001 From: goodwe-reviewer <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 14:21:05 +0200 Subject: [PATCH 045/105] UX-11 review: restored stops log their figures to events, the quiet-meter WARNING is rate-limited - After a restart, each restored stop (direction per inverter and site, delivery, circulation) also writes its saved reason to the action log. log_level defaults to info and events starts empty, so the DEBUG evidence alone left the figures only in state.json. - A flapping meter (ha_signed under a flat load, 42-97 s between changes) logs at most one WARNING/INFO pair per 10 minutes, with the episodes in between at DEBUG. - LONG_LINE_OK refuses any key whose text is a safety reason. - test_watchdog keeps the byte pin beside the meaning pin, since the text did not change. - DOCS says the DEBUG line needs log_level debug. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/UX-08-short-notifications.md | 5 +- goodwe_controller/DOCS.md | 9 ++-- goodwe_controller/app/main.py | 48 +++++++++++++++++-- goodwe_controller/test_messages.py | 27 +++++++++-- goodwe_controller/test_watchdog.py | 6 +++ 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/goodwe_controller/DECISIONS/UX-08-short-notifications.md b/goodwe_controller/DECISIONS/UX-08-short-notifications.md index e4b2832..3d88ff4 100644 --- a/goodwe_controller/DECISIONS/UX-08-short-notifications.md +++ b/goodwe_controller/DECISIONS/UX-08-short-notifications.md @@ -84,8 +84,9 @@ The allowlist is empty and its cap is 0 (43 → 0). Every WARNING and ERROR line **Unchanged:** every trigger, latch, threshold and alarm log level (the WARNING and ERROR lines stay), every notification id and cadence, every row colour and the banner cascade. No notification is added. 1. **One plain sentence and the code.** A WARNING/ERROR line that reports a safety reason (direction, delivery, stuck meter, stale reading, peak guard, circulation, over-rating) now ends in the reason's code, taken by `messages.reason_code()`. The reason itself, figures and limits included, is on a DEBUG line logged right after it ("Evidence for inverter-a: …"), and the action log entry carries it as before. Part 6 checks that pairing in the code. Circulation and the clamp lines were not among the five named, but they break the same 25-word rule, so they follow the same pattern. The clamp numbers stay in the notification (phase 2a item 3). -2. **The reasons and `state.json` are unchanged.** `reason` stays the evidence text, so what is saved has the same format as before. An old state file therefore loads and displays like a new one: every saved reason has opened with its code since it was first written (checked in the git history), and that code is all the ERROR line reads. The saved text goes on the DEBUG line. A stop saved without a reason shows `REASON_NOT_SAVED`. `test_messages.py` part 7 restarts from a state file holding the old long texts. The byte pin in `test_watchdog.py` now pins the meaning: the code first, then command, reading, time and both limits, in that order. +2. **The reasons and `state.json` are unchanged.** `reason` stays the evidence text, so what is saved has the same format as before. An old state file therefore loads and displays like a new one: every saved reason has opened with its code since it was first written (checked in the git history), and that code is all the ERROR line reads. The saved text goes on the DEBUG line. A stop saved without a reason shows `REASON_NOT_SAVED`. `test_messages.py` part 7 restarts from a state file holding the old long texts. `test_watchdog.py` pins the meaning (the code first, then command, reading, time and both limits, in that order) and, since the text did not change, still the bytes. 3. **The 25-word rule is checked as logged.** Part 6 fails any WARNING+ line over 25 words with its built text filled in. Nine non-safety families still run long (tariff plan words, price feed reasons, the state migration report, write refusals and claim scope errors that only a software fault raises, maintenance, trading gate and price history reasons). They are listed with a reason in `LONG_LINE_OK`, capped at 9, and a listed family that gets shorter fails until it is removed. Shortening them is a follow-up. -4. **The meter row's "the add-on log shows why" is now true.** When the meter goes quiet past its limit, the add-on logs one WARNING per episode, not one per cycle, and an INFO line when readings return. This is a new log line, not a new alarm: it has no notification and changes no decision. +4. **The meter row's "the add-on log shows why" is now true.** When the meter goes quiet past its limit, the add-on logs one WARNING per episode, not one per cycle, and an INFO line when readings return. A meter that flaps (on `ha_signed` a healthy meter under a flat load can go 42–97 s between changes) logs at most one such pair per 10 minutes, and the episodes in between go to DEBUG. This is a new log line, not a new alarm: it has no notification and changes no decision. 5. **The Why line past the 15 s hold** names the missing reading ("No usable meter reading for over 15 seconds: 0 W", or the battery power or level of an inverter), instead of "A reading is missing: 0 W". 6. **Action log:** "25 engagement(s)" is "25 engagements", and "SHADOW MODE OFF - …" is "Shadow mode off: …". "SHADOW MODE ON" was not named in the card and is left as it is. +7. **Review: after a restart the figures go on the action log too.** `log_level` defaults to `info`, so the DEBUG evidence line is not seen by default, and `events` starts empty. Each restored stop (direction per inverter and site, delivery, circulation) now also writes its saved reason to the action log ("FAILSAFE inverter-a, saved before the restart: …"), and the page's event line gets the same plain words the live stop gives. `LONG_LINE_OK` also refuses a key whose text is a safety reason, not only a `reason_code` key. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index a51a92c..938c3c0 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3096,8 +3096,10 @@ stop control on the add-on page. This part is for installers. The texts live in `app/messages.py` and follow `STYLE.md`. Every notification keeps a fixed `notification_id`, so a repeat replaces the card. The ERROR or WARNING line of the add-on log names the -reason code. The full figures are on the DEBUG line logged right after it -(log level `debug`) and in `events` in the `status` JSON. +reason code. The full figures are in `events` in the `status` JSON, also for a +stop restored after a restart, and on the DEBUG line logged right after it. +That DEBUG line only shows with “Log level” (log_level) set to `debug`; the +default `info` hides it. | Title | Severity | id | Card | |---|---|---|---| @@ -3254,7 +3256,8 @@ reason code, and its full figures are on the DEBUG line right after it and in with both possible causes, is on the DEBUG line after it. - **Meter: no reading for …** (red): the add-on logs one WARNING when the meter goes quiet, "No meter reading for …", and an INFO line when readings - return. Past `stale_input_s` the **Why** line names the missing reading. + return, at most once every 10 minutes. Past `stale_input_s` the **Why** + line names the missing reading. - The table at the top: **Why** is `messages.why()`, the arbiter's answer in words (`Resolution.explain()` stays on the log). **Tariff**, **Price history**, **Arbitrage** and **Shadow mode** keep every figure they had diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ff4abd0..97dd201 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -119,6 +119,9 @@ WRITE_BUDGET_S = 4.0 # restart this add-on (measured on TEST-23), so a latched alarm is re-asserted # this often. Why: goodwe docs/DECISIONS.md, SAFETY-34. REANNOUNCE_S = 300.0 +# UX-11 review: a quiet meter logs at most one WARNING this often, because on +# `ha_signed` a healthy meter under a flat load can go 42-97 s between changes. +METER_QUIET_REPEAT_S = 600.0 _mono = time.monotonic # patched by the checks; asyncio keeps the real one # --------------------------------------------------------------------------- # @@ -619,6 +622,13 @@ class Controller: messages.reason_code(inv.sign_wd.reason)) _LOG.debug("Evidence for %s: %s.", inv.name, inv.sign_wd.reason or "(reason not recorded)") + # UX-11 review: `events` starts empty and DEBUG is off by + # default, so the saved figures go on the action log too. + saved = inv.sign_wd.reason or messages.NO_REASON_SAVED + self.log_event(f"FAILSAFE {inv.name}, saved before the " + f"restart: {saved}", + hint=messages.hint("stop_restored", + unit=inv.name)) # --- SAFETY-42 + SAFETY-34 ------------------------------------------- # ⚠️ A LATCH THAT DOES NOT ACT, WHICH IS THE ONE ASYMMETRY WITH EVERY @@ -645,6 +655,11 @@ class Controller: inv.name, messages.reason_code(inv.delivery_wd.reason)) _LOG.debug("Evidence for %s: %s.", inv.name, inv.delivery_wd.reason or "(reason not recorded)") + saved = inv.delivery_wd.reason or messages.NO_REASON_SAVED + self.log_event(f"NOT DELIVERING {inv.name}, saved before the " + f"restart: {saved}", + hint=messages.hint("not_delivering", + unit=inv.name)) # --- SAFETY-30: THE SITE HALF OF THE SIGN CHECK ---------------------- # ⚠️ ONE PER SITE, BESIDE THE ONE PER INVERTER, AND ARMED ONLY AT N>=2. @@ -678,6 +693,10 @@ class Controller: "control: %s.", messages.reason_code(self.site_sign_wd.reason)) _LOG.debug("Evidence for the site: %s.", self.site_sign_wd.reason or "(reason not recorded)") + self.log_event("FAILSAFE site, saved before the restart: " + + (self.site_sign_wd.reason + or messages.NO_REASON_SAVED), + hint=messages.hint("site_direction")) # And the per-unit detectors are told which question they are asking, # here as well as in `cycle()`. `checks()` and the status page read # `inv.sign_wd.cfg` and can be called before the first cycle has run, so @@ -733,6 +752,10 @@ class Controller: messages.reason_code(self.circ_wd.reason)) _LOG.debug("Evidence for the site: %s.", self.circ_wd.reason or "(reason not recorded)") + self.log_event("CIRCULATING POWER, saved before the restart: " + + (self.circ_wd.reason + or messages.NO_REASON_SAVED), + hint=messages.hint("circulating")) # SAFETY-03. The output clamp's alarm - see clamp.py for why the clamp # itself is the cheap half. @@ -940,6 +963,9 @@ class Controller: self.why_words = "Starting" # UX-11: has this meter episode's WARNING been logged? See read_inputs. self._meter_quiet_logged = False + # ...when the last WARNING was, and whether this episode logged one. + self._meter_quiet_warned = None + self._meter_quiet_loud = False # ALLOC-01. The allocation record from the last resolution, or None # before the first cycle. ⚠️ IT IS KEPT SO THAT SOMETHING CAN GATE ON # IT: SAFETY-28 puts the write path behind this record, and DEV-02 reads @@ -1912,16 +1938,30 @@ class Controller: # UX-11: the red meter row says "the add-on log shows why", so a meter # that goes quiet gets one WARNING per episode, not one per cycle. It # is a log line only: no notification, and nothing it decides. + # A flapping meter logs at most one WARNING per METER_QUIET_REPEAT_S, + # and the episodes in between go to DEBUG. if self.p1_enabled: if (self.p1.stale and not self._meter_quiet_logged and self.p1.published_age_s > self.p1.max_age_s): self._meter_quiet_logged = True - _LOG.warning("No meter reading for over %s, so control " - "waits and then sets the battery to 0 W.", - messages.seconds(self.p1.max_age_s)) + now = _mono() + self._meter_quiet_loud = ( + self._meter_quiet_warned is None + or now - self._meter_quiet_warned >= METER_QUIET_REPEAT_S) + if self._meter_quiet_loud: + self._meter_quiet_warned = now + _LOG.warning("No meter reading for over %s, so control " + "waits and then sets the battery to 0 W.", + messages.seconds(self.p1.max_age_s)) + else: + _LOG.debug("No meter reading for over %s again.", + messages.seconds(self.p1.max_age_s)) elif not self.p1.stale and self._meter_quiet_logged: self._meter_quiet_logged = False - _LOG.info("Meter readings are back.") + if self._meter_quiet_loud: + _LOG.info("Meter readings are back.") + else: + _LOG.debug("Meter readings are back.") if self.inputs_ok: if self.inputs_bad_since is not None: diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 7513364..6a45287 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -1227,7 +1227,9 @@ check(f"UX-11: no WARNING+ line runs over {LINE_WORDS} words as logged, except " f"the {len(LONG_LINE_OK)} listed families, and none of them is a safety " f"reason (cap {LONG_LINE_CAP})", len(LONG_LINE_OK) <= LONG_LINE_CAP - and not any("reason_code" in k for k in LONG_LINE_OK)) + and not any("reason_code" in k + or TEXT.get(k) in SAFETY_REASONS.values() + for k in LONG_LINE_OK)) check(f"...and every listed family still runs long, so the list only shrinks " f"(no longer long: {sorted(set(LONG_LINE_OK) - _long_seen)})", set(LONG_LINE_OK) <= _long_seen) @@ -1397,6 +1399,7 @@ import logging # noqa: E402 from app import hass as _hass, p1 as _p1, validate as _validate, web as _web # noqa: E402 from app.arbiter import Claim # noqa: E402 from app.main import Controller, why_key # noqa: E402 +from app import main as _main # noqa: E402 class _Rec(logging.Handler): @@ -1695,7 +1698,12 @@ def _meter_at(age_s): def _quiet_episodes(): - for age in (1, 40, 45, 50, 1, 2, 60, 65): + # Two quiet episodes close together, then a third 10 minutes on. + for age in (1, 40, 45, 50, 1, 2, 60, 65, 1): + _meter_at(age) + asyncio.run(_c.read_inputs()) + _c._meter_quiet_warned -= _main.METER_QUIET_REPEAT_S + for age in (40, 45, 1): _meter_at(age) asyncio.run(_c.read_inputs()) @@ -1704,9 +1712,13 @@ _mq = [r for r in _captured("goodwe", _quiet_episodes) if "meter" in r.getMessage().lower()] _mq_warn = [r.getMessage() for r in _mq if r.levelno == logging.WARNING] _mq_info = [r.getMessage() for r in _mq if r.levelno == logging.INFO] +_mq_dbg = [r.getMessage() for r in _mq if r.levelno == logging.DEBUG] check(f"a meter that goes quiet logs one WARNING per episode, not per cycle, " - f"and one INFO when readings return ({_mq_warn}, {_mq_info})", - len(_mq_warn) == 2 and _mq_info == ["Meter readings are back."] + f"and one INFO when readings return, and a flapping meter at most one " + f"pair per {_main.METER_QUIET_REPEAT_S:.0f} s ({_mq_warn}, {_mq_info}, " + f"{_mq_dbg})", + len(_mq_warn) == 2 and _mq_info == ["Meter readings are back."] * 2 + and len(_mq_dbg) == 2 and _mq_warn[0] == "No meter reading for over 30 seconds, so control " "waits and then sets the battery to 0 W." and len(words(_mq_warn[0])) <= LINE_WORDS) @@ -1763,6 +1775,13 @@ check("...each ERROR line at start is one plain sentence with the code, at " and any(m.endswith(f": {messages.NO_REASON_SAVED}.") for m in _rs_err)) check("...and the saved text, figures and all, is on a DEBUG line beside it", all(any(t in m for m in _rs_dbg) for t in _OLD.values())) +# UX-11 review: `log_level` defaults to info and `events` starts empty, so the +# saved figures also go on the action log, where `status` shows them. +_rs_ev = _restart[0].events if _restart else [] +check(f"...and in the action log, which an installer reads at the default " + f"log level ({len(_rs_ev)} events)", + all(any(t in e for e in _rs_ev) for t in _OLD.values()) + and any(e.endswith(messages.NO_REASON_SAVED) for e in _rs_ev)) # UX-11 item 4: the action log's clamp count and the shadow-off entry. _main_src = (APP / "main.py").read_text(encoding="utf-8") diff --git a/goodwe_controller/test_watchdog.py b/goodwe_controller/test_watchdog.py index cb8d5db..7188da8 100644 --- a/goodwe_controller/test_watchdog.py +++ b/goodwe_controller/test_watchdog.py @@ -1438,6 +1438,12 @@ check("⚠️ THE SITE INSTANCE'S REASON SAYS WHAT SHIPPED, IN THE SAME ORDER: " _sr.startswith("SIGN_DISAGREEMENT: ") and messages.reason_code(_sr) == "SIGN_DISAGREEMENT" and all(i > 0 for i in _order) and _order == sorted(_order)) +# UX-11 review: the text itself did not change, and it is what state.json +# holds, so the byte pin stays beside the meaning pin. +check("...and it is still byte-identical to the one that shipped", + _sr == ("SIGN_DISAGREEMENT: commanded -1000 W against a meter reading " + "+1500 W for 180 s continuously (limits: both over 300 W, held " + "over 180 s)")) check("...and the per-unit instance names what it ACTUALLY compared instead. " "'against a meter reading' there would be a false statement about which " "instrument produced the evidence, on the one line somebody woken by " -- 2.54.0 From 1f97c7652f481092e5a7300e899b90b92ed5c375 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 16:43:27 +0200 Subject: [PATCH 046/105] SAFETY-52: a battery that refuses is asked for 0 W, with a 200 W probe every 15 min At the BMS cut-out the saturation freeze held the last request for hours (+5000 W for 11.87 h on 09-06, +1940 W for 3 h 55 m on 09-19) until the grid error changed sign. compute() now carries a refused direction: after SETTLE_CYCLES of a ~0 W reading against a larger ask it holds that direction at 0 W, probes 200 W (below the gate's 250 W) every 15 minutes, and lets go on charge, an answered probe, stop/start or another writer. A stale-reading trip on a frozen ~0 W reading seeds the same hold, which ends SAFETY-59's ~70 s cycle. One inverter only; no SoC in the loop (SAFETY-25 Option A). test_refusal.py drives the real Controller and gate; tools/replay_refusal.py replays the 16-day capture. test_clamp.py and test_delivery.py re-baselined where they asserted the old hold. DECISIONS/SAFETY-52 has the record and what SAFETY-58/59 must take into account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../SAFETY-52-a-battery-that-refuses.md | 84 ++++ goodwe_controller/DOCS.md | 17 +- goodwe_controller/app/control.py | 54 ++- goodwe_controller/app/main.py | 93 +++++ goodwe_controller/app/messages.py | 5 + goodwe_controller/test_clamp.py | 15 +- goodwe_controller/test_delivery.py | 5 +- goodwe_controller/test_messages.py | 6 + goodwe_controller/test_refusal.py | 386 ++++++++++++++++++ goodwe_controller/tools/replay_refusal.py | 97 +++++ 10 files changed, 756 insertions(+), 6 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md create mode 100644 goodwe_controller/test_refusal.py create mode 100644 goodwe_controller/tools/replay_refusal.py diff --git a/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md b/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md new file mode 100644 index 0000000..0bb06af --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md @@ -0,0 +1,84 @@ +# SAFETY-52 - a battery that refuses is asked for 0 W + +**Decided 2026-09-27 by the owner, on the phase A plan (option D3). All four +questions answered yes.** + +## The defect + +At the BMS cut-out the battery gives ~0 W whatever it is asked. The saturation +freeze (`control.py`, `frozen`) then holds the request where it stood, and its +SAFETY-13 exit cannot fire, because a reading of ~0 against a large ask lies +inside the interval a limit can produce. The request stood at +5000 W for +11.87 h on 2026-09-06 and at +1940 W for 3 h 55 m on the bus on 2026-09-19. It +moved again only when the grid error changed sign. SAFETY-48's lead cap only +changes where `i_w` parks (one slew step ahead instead of at the rail). When +the request moved after the reading went flat, the stale-reading gate won +instead and ran SAFETY-59's ~70 s trip cycle. + +## What was decided + +1. **A refused direction is held at 0 W**, reason `battery refuses`. It engages + in `compute()` when the freeze has held `SETTLE_CYCLES` and the reading is + within `saturation_w` of 0 against an ask beyond it. The drop to 0 skips + the slew limit (it only removes an ask nobody meets). The direction is + carried like `sat_count` (`refused=`, `Decision.refused`). +2. **A 200 W probe every 15 minutes, 34 s long** (`PROBE_W`, `PROBE_EVERY_S`, + `PROBE_S`; twice `BATT_OBLIGED_S`). An answer of at least 100 W ends the + refusal. 200 W is below `freshness.MOVE_W` (250 W), so a probe cannot arm + the gate. The clock is main.py's `now_mono`; `compute()` stays clockless. +3. **A gate trip while the loop is frozen on a ~0 W reading is a refusal** for + control (`Controller._refusal_from_stale`). This is what stops the ~70 s + cycle. The log keeps SAFETY-56's two-explanation wording. +4. **No SoC in the loop.** SAFETY-25 Option A stands. Nothing reads SoC. + +Other exits: the loop wants the other direction (charge is accepted at the +floor), control stopped or started, another writer on the wire (the arbiter +reseed). A gap in the readings keeps the refusal, because the gate's own stop is +what seeds it. + +**One inverter only.** At N>1, OPT-09's `pack` limit already closes an empty +battery's discharge end and moves its share. There, a one-unit gate trip must +not refuse the site. `compute()` is passed `refused=None` there, and that path +is release/1.0's law unchanged (the `i_w=None` equivalence sweep in +`test_control.py` still holds). + +## Evidence + +`test_refusal.py` drives the real Controller and gate (the 09-06 and 09-19 +shapes, recovery with no sign change, the probe cadence, every exit). +`tools/replay_refusal.py` replays the 16-day capture, same model as +`replay_recorded_loop.py`, and should be read for deltas: + +| plant | law | gate trips | request >1 kW above delivery | longest held | import / export kWh | worst 15-min | +|---|---|---|---|---|---|---| +| fitted | old | 85 | 113.3 h | 16.57 h | 112.0 / 35.2 | 3434 W | +| fitted | new | 130 | 11.4 h | 0.21 h | 112.3 / 35.4 | 3456 W | +| offset 0 W | old | 1010 | 102.2 h | 16.58 h | 112.0 / 35.2 | 3434 W | +| offset 0 W | new | 85 | 6.1 h | 0.33 h | 111.9 / 35.1 | 3434 W | + +The +22 W worst quarter and the +45 trips on the fitted plant follow the fit's +-22 W offset, which slowly charges the modelled pack above its floor while the +hold stands. With the offset at 0 both vanish. That is inferred from these two +rows and was not traced further. Rejected alternatives and their figures are in +the phase A plan: bounding the integrator by demand made the worst quarter ++541 W worse or cycled the gate 3368 times, and an SoC envelope needs the +configured floor to be right and needs SoC. + +## Not covered + +A battery that gives a steady part of the ask (e.g. a 500 W keep-alive) is a +genuine limit (SAFETY-13 case a) and still holds its request. + +## What SAFETY-58 and SAFETY-59 must take into account + +- **SAFETY-58** (the first read after a rest trips at once): a probe never arms + the gate (200 < 250 W), but the refusal seeding reads the trip. If 58 delays + the first verdict, the seed arrives later. The 09-19 shape then needs the + compute-side engagement (12 cycles) to win, which it does only while the + request stands still. Keep `test_refusal.py` part 4 green. +- **SAFETY-59** (DOCS says a ~70 s pattern proves a failed register): with this + change a refusing battery no longer produces the pattern at one inverter. The + DOCS text should say so, and that the `battery refuses` reason is the + discriminator the add-on now has. At N>1 the old pattern can still occur. +- If either changes `MOVE_W`, `PROBE_W` must stay below it. + `test_refusal.py` part 2 checks the inequality. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 938c3c0..735f1a9 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -526,7 +526,7 @@ accumulator is doing: | `Loop integrator lead` | W | that value minus **the command it was computed against**, i.e. the command the previous cycle left standing | | `Loop reason` | — | the law's own word for this cycle | -`Loop reason` takes one of eight values: +`Loop reason` takes one of ten values: | value | what happened | |---|---| @@ -538,6 +538,21 @@ accumulator is doing: | `saturated-freeze` | the inverter is not following, so the command's magnitude may fall but not rise | | `freeze-released` | the freeze had run out of plant-shaped explanations and the command was let move again | | `not-running` | control is stopped **and** shadow mode is off, so the loop did not run | +| `battery refuses` | the battery gave nothing for a minute while asked for more than 500 W, so the add-on asks 0 W in that direction (see below) | +| `battery probe` | the add-on asks 200 W to test whether a refusing battery gives power again | + +**When the battery refuses.** At its cut-out level the battery gives nothing, +whatever it is asked. The add-on then asks 0 W instead of repeating its last +request, and the `Why` row reads *The battery refuses to give power: 0 W*. Every +15 minutes it asks 200 W for about half a minute; if the battery answers, +control resumes. It also resumes when the grid needs charging instead, and when +control is stopped or started. 200 W is below the 250 W the stale-reading check +needs, so a test never trips it. One inverter only: with several, the battery +level limit already moves an empty battery's share to the others. + +*For installers:* SAFETY-52. The event log reads `BATTERY REFUSES …` and +`BATTERY REFUSES ENDED: …`, and the INFO line ends in `BATTERY_REFUSES`. +`DECISIONS/SAFETY-52-a-battery-that-refuses.md` has the replay figures. ⚠️ **`Loop reason` is not the `Why` row on the status page, and the two will often disagree.** `Why` is the *arbiter's* answer in words — *Keeping the grid diff --git a/goodwe_controller/app/control.py b/goodwe_controller/app/control.py index 9a6cfda..fbd0d1c 100644 --- a/goodwe_controller/app/control.py +++ b/goodwe_controller/app/control.py @@ -265,6 +265,30 @@ _SAT_COUNT_CAP = SETTLE_CYCLES + 1 # 13 # `slew_limit_w()` and therefore with the rail. SLEW_LEAD_STEPS = 1 +# --------------------------------------------------------------------------- +# SAFETY-52. A BATTERY THAT REFUSES IS ASKED FOR 0 W, NOT HELD AT ITS LAST ASK. +# +# At the BMS cut-out the pack delivers ~0 W whatever it is asked, so the +# saturation freeze below holds the command where it stood (the recorded +# 09-06 case: +5000 W for 11.87 h) until the grid error changes sign. The +# freeze's own exit cannot help: a reading of ~0 against a large ask is inside +# the interval a limit can produce. So a refused DIRECTION is held at 0 W, +# carried between cycles like `sat_count`, and left again when the loop wants +# the other direction, when a small probe is answered, or when the caller +# resets it (stop, start, another writer). The record is DECISIONS/SAFETY-52. +# +# PROBE_W is below freshness.MOVE_W (250 W) on purpose: a probe that small can +# never arm the stale-reading gate, so it cannot start the gate's ~70 s cycle. +# test_refusal.py pins the inequality. The cadence and length are the owner's +# 2026-09-27 answer (every 15 minutes) and freshness.BATT_OBLIGED_S twice over +# (17 s is how long a healthy reading needs to show a command). +REFUSED = "battery refuses" +PROBING = "battery probe" +PROBE_W = 200.0 +PROBE_ANSWER_W = PROBE_W / 2 +PROBE_EVERY_S = 900.0 +PROBE_S = 34.0 + @dataclass(frozen=True) class Tuning: @@ -346,6 +370,9 @@ class Decision: i_bound_w: float = 0.0 requested_w: float = 0.0 clamped_w: float = 0.0 + # SAFETY-52. The refused direction to carry back in (+1 discharge, -1 + # charge, 0 none), or None when the caller does not carry it. + refused: int | None = None def slew_limit_w(tuning: Tuning) -> float: @@ -442,6 +469,8 @@ def compute( tuning: Tuning, sat_count: int = 0, i_w: float | None = None, + refused: int | None = None, + probe: bool = False, ) -> Decision: """One control cycle. A cycle is one meter update (~5 s on a HomeWizard P1). @@ -449,6 +478,9 @@ def compute( `grid_w` net grid power, + = importing `actual_w` what the inverter reports it is doing, + = discharging `i_w` the carried integrator, or None to seed it from `prev_w` + `refused` SAFETY-52's carried refused direction, or None to leave it out + (the `i_w=None` equivalence path does) + `probe` the caller's clock says a refused direction may try PROBE_W now """ reason = "tracking" @@ -739,6 +771,26 @@ def compute( target = min(target, prev_w) if prev_w > 0 else max(target, prev_w) reason = "saturated-freeze" + # --- SAFETY-52: a refused direction is held at 0 W ---------------------- + # Engages only where the freeze has held for SETTLE_CYCLES and the unit + # delivers ~nothing: a reading within `saturation_w` of 0 against an ask + # beyond it is a refusal, not a slow plant. The drop to 0 skips the slew + # limit because it only removes an ask the battery is not meeting. + if refused is not None: + if (refused == 0 and frozen and sat_count >= SETTLE_CYCLES + and abs(prev_w) > tuning.saturation_w + and abs(actual_w) < tuning.saturation_w): + refused = 1 if prev_w > 0 else -1 + if refused and refused * i_w < 0: + refused = 0 # the loop wants the other way + elif refused and probe and refused * actual_w >= PROBE_ANSWER_W: + refused = 0 # the probe was answered + elif refused: + wants = refused * i_w > 0 + i_w = 0.0 + target = refused * PROBE_W if probe and wants else 0.0 + reason = PROBING if probe and wants else REFUSED + # --- quantise ---------------------------------------------------------- # 10 W. The register is 1 W and the inverter reports at 1 W, but its # response lands on a coarser ladder (~17.6 W measured at ~900 W, consistent @@ -749,7 +801,7 @@ def compute( return Decision(float(target), sat_count, frozen, reason, float(i_w), i_clamped, clamped, float(i_bound_w), float(want), - float(clamped_w)) + float(clamped_w), refused) def maintenance_charge_floor( diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 97dd201..2d0847d 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -39,6 +39,7 @@ from .arbiter import ( P_LOOP, P_MAINT_SHAPE, P_MAINTENANCE, P_PEAK, P_SAFETY, Claim, Resolution, actuator_for, resolve, ) +from . import control as _ctl from .control import Tuning, compute, maintenance_charge_floor, peak_at_risk from .delivery import ( DELIVERY_OPTION_DEFAULTS, DeliveryConfig, UnitDelivery, @@ -241,6 +242,10 @@ def why_key(winner: str, claims) -> str: disagreement"). A failsafe with no claim of its own is the arbiter's "no claim was made", or main.py's refusal to split the power ("unsplit"). """ + if winner == "loop": + # SAFETY-52: a loop holding a refused direction says so. + return next((c.reason for c in claims if c.source == "loop" + and c.reason in (_ctl.REFUSED, _ctl.PROBING)), winner) if winner in ("safety", "failsafe"): return next((c.reason for c in claims if c.source == winner and c.kind == "set"), @@ -925,6 +930,12 @@ class Controller: self.target = 0.0 self.sat_count = 0 self.i_w = 0.0 # the loop's integrator, carried between cycles + # SAFETY-52. The direction the battery refuses (+1 / -1 / 0), carried + # like `i_w`, and when the refusal (or its last probe) started. + self.batt_refused = 0 + self.batt_refused_at = None + self._now_mono = None + self._refusal_auto = False # TEL-10. What the last cycle's loop did, kept for publication. Seeded # to the SAME values the "stopped or blind" branch of `cycle()` writes, # because before the first cycle the loop has not run - which is the @@ -1058,6 +1069,68 @@ class Controller: self.loop_pass_mono = None # -- helpers ------------------------------------------------------------- + # --- SAFETY-52: a battery that refuses is asked for 0 W ------------------ + def _refusal_probe(self) -> bool: + """True while a refused direction may try `PROBE_W` (every 15 min).""" + if (not self.batt_refused or self.batt_refused_at is None + or self._now_mono is None): + return False + held = self._now_mono - self.batt_refused_at + if held >= _ctl.PROBE_EVERY_S + _ctl.PROBE_S: + self.batt_refused_at = self._now_mono + return False + return held >= _ctl.PROBE_EVERY_S + + def _refusal_start(self, sign: int, evidence: str) -> None: + self.batt_refused = sign + self.batt_refused_at = self._now_mono + self.log_event(f"BATTERY REFUSES {evidence}", + hint=messages.hint("battery_refuses")) + _LOG.info("The battery refuses to give power, so the add-on asks 0 W " + "and tries %.0f W every %.0f minutes: BATTERY_REFUSES.", + _ctl.PROBE_W, _ctl.PROBE_EVERY_S / 60) + _LOG.debug("Evidence: BATTERY_REFUSES: %s.", evidence) + + def _refusal_end(self, why: str) -> None: + if not self.batt_refused: + return + self.batt_refused, self.batt_refused_at = 0, None + self.log_event(f"BATTERY REFUSES ENDED: {why}", + hint=messages.hint("battery_gives")) + _LOG.info("The battery refusal ends, control asks for power again: %s.", + why) + + def _refusal_update(self, decision, asked_w, batt_w, probe) -> None: + """Follow `compute()`'s carried refused direction, and say so.""" + now = decision.refused or 0 + if now and not self.batt_refused: + self._refusal_start(now, f"asked {asked_w:+.0f} W, the battery " + f"gave {batt_w:+.0f} W for " + f"{decision.sat_count} cycles") + elif self.batt_refused and not now: + answered = probe and self.batt_refused * batt_w >= _ctl.PROBE_ANSWER_W + self._refusal_end("the probe was answered" if answered + else "the grid now asks the other direction") + + def _refusal_from_stale(self, inv, now_mono) -> None: + """A stale-reading stop while the loop is frozen on ~0 W is a refusal. + + Only at one inverter: with several, one empty battery must not stop the + site (OPT-09's pack limit moves its share to the others). + """ + t = self.tuning + standing = inv.standing_w() + if (len(self.inverters) == 1 and (self.auto or self.shadow) + and not self.batt_refused + and self.sat_count >= t.saturation_cycles + and inv.batt_fresh.held is not None + and abs(inv.batt_fresh.held) < t.saturation_w + and abs(standing) > t.saturation_w): + self._now_mono = now_mono + self._refusal_start(1 if standing > 0 else -1, + f"stale reading {inv.batt_fresh.held:+.0f} W " + f"while asked {standing:+.0f} W") + def log_event(self, msg: str, hint: str | None = None) -> None: """`msg` goes on the action log, the add-on's own technical record. `hint` is `messages.hint()`'s plain words for the same event, and is @@ -1840,6 +1913,7 @@ class Controller: """ o = self.o now_mono = freshness.monotonic() if now_mono is None else float(now_mono) + self._now_mono = now_mono if self.p1_enabled: # ⚠️ P1 is the only authoritative measurement of what the utility # sees (§5.1). When it is stale this is None, which falls into the @@ -2003,6 +2077,7 @@ class Controller: if inv.batt_fresh.stale and not was_stale: self.log_event(f"STALE {inv.name}: " + inv.batt_fresh.reason, hint=messages.hint("battery_stuck", unit=inv.name)) + self._refusal_from_stale(inv, now_mono) # ⚠️ SAFETY-57 REWROTE THE LAST SENTENCE OF THIS LINE AND NOTHING # ELSE IN IT. The escape clause used to read "It clears itself the # moment the register reports a different value", full stop - and @@ -3340,6 +3415,12 @@ class Controller: # loop should be. It is safe because the loop's `prev_w` is # `self.target`, which the end of this method re-seeds to what is # actually standing on the wire. + # SAFETY-52: a refusal learned while control ran does not survive a + # stop or a start (shadow mode keeps the loop running when stopped). + if bool(self.auto) != self._refusal_auto: + self._refusal_auto = bool(self.auto) + self._refusal_end("control started" if self.auto + else "control stopped") if (self.auto or self.shadow) and self.inputs_ok: # ⚠️ prev is the ARBITER's last output, not the loop's own last # wish. If something outranked the loop, that is what the hardware @@ -3357,6 +3438,13 @@ class Controller: # stale period as power. if self.loop_w is None or self.target != self.loop_w: self.i_w = self.target + # SAFETY-52: another writer overrode the loop, so a refusal learned + # against the loop's own ask no longer describes the wire. A gap + # (`loop_w` None: blind or stopped) keeps it: the stale-reading stop + # is what seeds it, and dropping it there restarts the ~70 s cycle. + if self.loop_w is not None and self.target != self.loop_w: + self._refusal_end("another writer") + probe = self._refusal_probe() # ⚠️ `actual_w` IS THE SITE SUM AND THAT IS DEV-02's OTHER HALF. # The anti-windup test inside compute() is # `abs(prev_w - actual_w) > saturation_w`, and `prev_w` is the SITE @@ -3385,6 +3473,10 @@ class Controller: tuning=self.tuning, sat_count=self.sat_count, i_w=self.i_w, + # SAFETY-52 at one inverter only: with several, OPT-09's pack + # limit already closes an empty battery's discharge end. + refused=self.batt_refused if len(self.inverters) == 1 else None, + probe=probe, ) if decision.frozen and self.sat_count < self.tuning.saturation_cycles: self.log_event(f"saturation freeze ({self.target:.0f} W vs " @@ -3393,6 +3485,7 @@ class Controller: self.sat_count = decision.sat_count self.i_w = decision.i_w self.loop_w = decision.target_w + self._refusal_update(decision, loop_prev, site_batt, probe) # --- TEL-10 ------------------------------------------------------ # ⚠️ THE INTEGRATOR HAS NEVER LEFT THIS PROCESS, AND THAT IS WHAT # THE CARD IS. `self.i_w` is carried between cycles and published diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 0e072de..4c8bcdb 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -802,6 +802,9 @@ WHY_WINNER = { # failsafe winner. test_messages.py part 7 finds every one in the code. "sign disagreement": "Safety stop, power went the wrong way", "unsplit": "The power could not be split, all at 0 W", + # SAFETY-52: the loop's two words for a battery that gives nothing. + "battery refuses": "The battery refuses to give power", + "battery probe": "Testing if the battery gives power again", } WHY_LIMIT = { "peak(quarter peak)": "the peak limit", @@ -852,6 +855,8 @@ HINTS = { "stop_restored": "{unit}: an earlier safety stop is back, it stays at 0 W", "battery_stuck": "{unit}: battery power reading stopped changing", "battery_back": "{unit}: battery power reading is used again", + "battery_refuses": "The battery refuses to give power, the add-on asks 0 W", + "battery_gives": "The battery refusal ended, control asks for power again", "bad_value": "The add-on made an invalid power value, inverters set to 0 W", "write_blocked": "{unit}: a power request was blocked, it is set to 0 W", "all_blocked": "A power request was blocked, inverters set to 0 W", diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index 9d5ca16..98e9a52 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -497,8 +497,13 @@ check(f"AC 1: NOT ONE of the {len(emitted)} values that reached the device " # largest emitted value is what it is and not 5000 W. The clamp is what makes it # bounded; the freeze is what makes it small. A check that read # `max(emitted) == max_w` would have been asserting the freeze, not the clamp. +# SAFETY-52 re-baseline: an inverter reporting 0 W for SETTLE_CYCLES is a +# battery that refuses, so the command then drops to 0 W. The freeze still +# engaged first, and the event log says so. check(f"...and the saturation freeze is what pins it at {max(emitted):,.0f} W " - f"rather than the rail", ctl_r.sat_count >= ctl_r.tuning.saturation_cycles) + f"rather than the rail", + any("saturation freeze" in e for e in ctl_r.events) + and max(emitted) < LIVE_MAX_W) notes_r = clamp_notes(hass_r) print(f" the loop clamped on {ctl_r.clamp_wd.engagements} of {60} cycles, " @@ -580,8 +585,12 @@ check("UX-07 item 1: during a bound episode an earlier over-rating count is " # ⚠️ NOT A TRIP. 11.2's action is "clamp and alarm"; the loop keeps running and # keeps writing the clamped value. If a later cut changes that it must come here. -check(f"it is NOT a trip - the command stands at {ctl_r.target:+.0f} W, not 0 W", - ctl_r.target != 0.0 and ctl_r.target == hass_r.writes[-1]) +# SAFETY-52: the loop itself now asks 0 W of an inverter that gives nothing, +# with its own reason. That is the loop's decision, not a stop. +check(f"it is NOT a trip - the command stands at {ctl_r.target:+.0f} W because " + f"the loop says '{ctl_r.loop_reason}', not because of a stop", + ctl_r.loop_reason == "battery refuses" + and ctl_r.target == hass_r.writes[-1]) check("...and the controller still reports itself running, not failsafe", ctl_r.auto and not ctl_r.sign_wd.tripped) diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index da20040..a266a38 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -1158,7 +1158,10 @@ async def _one(): c.inverters[0].dev_min, c.inverters[0].dev_max = -2000.0, 2000.0 c.auto = True hass.ctrl = c - await _drive(c, n=20, dt=0.1) + # SAFETY-52: from SETTLE_CYCLES of delivering nothing the loop asks 0 W + # (the battery refuses), so the run stops just before that. 11 cycles is + # still 1.1 s against the 1 s hold. + await _drive(c, n=11, dt=0.1) return c, hass, store diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 6a45287..1bf14d9 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -1399,6 +1399,7 @@ import logging # noqa: E402 from app import hass as _hass, p1 as _p1, validate as _validate, web as _web # noqa: E402 from app.arbiter import Claim # noqa: E402 from app.main import Controller, why_key # noqa: E402 +from app import control as _control # noqa: E402 from app import main as _main # noqa: E402 @@ -1585,6 +1586,11 @@ for _f in sorted(APP.glob("*.py")): _keys = {why_key(s, [Claim.set(s, 0, 0.0, r)]) for s, r in _SOURCES} _keys |= {why_key("failsafe", []), why_key("failsafe", [Claim.set("loop", 0, 1.0, "tracking")])} +# SAFETY-52: the loop's claim reason is computed, so the scan cannot see it. +_keys |= {why_key("loop", [Claim.set("loop", 0, 0.0, _r)]) + for _r in (_control.REFUSED, _control.PROBING)} +check("...including the loop's two battery-refuses reasons, which get words of " + "their own", {_control.REFUSED, _control.PROBING} <= _keys) check(f"the scan found the claims ({len(_SOURCES)}), including the latched " f"per-inverter stop the 2d test saw as 'Other'", ("failsafe", "sign disagreement") in _SOURCES and len(_SOURCES) >= 8) diff --git a/goodwe_controller/test_refusal.py b/goodwe_controller/test_refusal.py new file mode 100644 index 0000000..e2bf87b --- /dev/null +++ b/goodwe_controller/test_refusal.py @@ -0,0 +1,386 @@ +"""Runnable check for SAFETY-52. `python3 test_refusal.py` + +A battery that refuses to give power (the BMS cut-out) used to leave the +command standing at its last ask for hours: +5000 W for 11.87 h on 2026-09-06, ++1940 W for 3 h 55 m on the bus on 2026-09-19. Now a refused direction is held +at 0 W, a 200 W probe asks every 15 minutes, and the refusal ends on charge, on +an answered probe, on stop/start and when another writer takes the wire. +DECISIONS/SAFETY-52 has the record and the replay figures. + +Mutating the modules this file grades? Purge `__pycache__` first, or run +`tools/mutation_run.sh`, which does - see MUTATION.md. + +Parts 1-5 drive the REAL `Controller` (read_inputs + cycle, the real +SAFETY-37/57 gate) against a scripted battery whose reading stands at exactly +-4 W for any request >= -4 W at the cut-out, and follows otherwise. Time is the +`now_mono` handed to `read_inputs()`, so 12 hours run in seconds. `OLD` runs the +same fixture with `refused=None` forced into `compute()` - release/1.0's law - +so every "new" figure is shown beside the one it replaces. Part 4 also runs +`compute()` alone, as the bus saw 09-19 before the gate existed. + +Mutations, each on a copy of this tree purged of `__pycache__`, graded with +`python3 -B` over test_refusal, test_control, test_clamp, test_telemetry and +test_messages (MUTATION.md). Reds are failing checks, on this tree: + + # mutation reds + -- ------------------------------------------------------- --------------- + R1 control.py: the engage `if` -> `if False and ...` 8 here + 1 clamp + (release/1.0's behaviour) + R2 control.py: the exit on the other direction removed 1 + R3 control.py: the exit on an answered probe removed 2 + R4 control.py: `PROBE_W = 300.0`, above the gate's 250 W 4 + R5 control.py: the hold keeps the old target, not 0 W 4 + R6 main.py: `_refusal_from_stale()` returns at once 1 + R7 main.py: another writer no longer ends the refusal 1 + R8 main.py: stop/start no longer ends the refusal 1 + R9 main.py: the probe window never opens 4 +""" + +import asyncio +import sys +from datetime import datetime, timedelta, timezone + +from app import control, freshness +from app.control import PROBE_EVERY_S, PROBE_S, PROBE_W, REFUSED, PROBING +from app.main import Controller, why_key +from app.arbiter import Claim +from app import messages + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +LIVE = {"max_w": 5000.0, "gain": 0.6, "slew_w": 400.0, "target_grid_w": -10.0, + "deadband_w": 15, "step_w": 10} +TICK = 5.0 # the meter's measured median tick (replay_recorded_loop) +CUT_W = -4.0 # what the register reads at the cut-out, 2026-09-06 +H = 3600.0 +BASE = datetime(2026, 9, 6, 19, 30, tzinfo=timezone.utc) + + +class _Store: + def __init__(self): + self.data = {} + + def set(self, *a): + pass + + def get_time(self, *a): + return None + + +class _Pub: + enabled = False + + def publish(self, values): + pass + + def close(self): + pass + + +class _Hass: + """House load, and a battery that follows unless `cut(t)` says it refuses. + + At the cut-out the reading is exactly CUT_W for any request >= CUT_W (a flat + register, which is what arms or does not arm the stale-reading gate). A + charge request is followed: the pack accepts charge at the floor. + `cap(t)` limits discharge while not cut (the 09-06 pack gave 4570 W at 10 %). + """ + + def __init__(self, load, cut, cap=lambda t: 1e9): + self.load, self.cut, self.cap = load, cut, cap + self.t = 0.0 + self.cmd = 0.0 + self.writes = [] + + def batt(self): + if self.cut(self.t) and self.cmd >= CUT_W: + return CUT_W + return float(round(min(self.cmd, self.cap(self.t)))) + + async def limits(self, entity): + return (-LIVE["max_w"], LIVE["max_w"], 1.0) + + async def number(self, entity, invert=False): + b = self.batt() + return {"sensor.grid": self.load(self.t) - b, "sensor.soc": 9.0, + "sensor.batt": b}.get(entity) + + async def set_number(self, entity, value): + self.writes.append((self.t, float(value))) + self.cmd = float(value) + return True + + async def call(self, *a): + return True + + +def run(load, cut, dur, cap=lambda t: 1e9, old=False, events=None): + """Real cycles every TICK seconds of `now_mono`. `events[t] = fn(c)` pokes + the controller (stop, start, another writer) at that instant. + + Returns [(t, grid, batt, setpoint, i_w, loop_reason, batt_refused)], the + number of gate trips, and the controller.""" + async def go(): + hass = _Hass(load, cut, cap) + c = Controller(dict( + {"setpoint_entity": "number.sp", "meter_entity": "sensor.grid", + "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", + "meter_source": "off", "heartbeat_s": 10, "stale_input_s": 15}, + **LIVE), hass, _Store(), _Pub(), stop=asyncio.Event()) + c.auto = True + c.dev_min, c.dev_max = -LIVE["max_w"], LIVE["max_w"] + import app.main as m + real, real_dt = m.compute, m.datetime + clock = [0.0] + + class _DT(real_dt): + """`cycle()`'s wall clock follows `now_mono`, so the 15 s input hold + and the gate's release run in simulated seconds too.""" + @classmethod + def now(cls, tz=None): + return BASE + timedelta(seconds=clock[0]) + + m.datetime = _DT + if old: + m.compute = lambda *a, **k: real(*a, **dict(k, refused=None)) + rows, trips, was = [], 0, False + try: + t = 0.0 + while t < dur: + hass.t = clock[0] = t + for et, fn in list((events or {}).items()): + if et <= t: + fn(c) + del events[et] + await c.read_inputs(now_mono=t) + stale = c.inverters[0].batt_fresh.stale + trips += stale and not was + was = stale + await c.cycle() + rows.append((t, hass.load(t) - hass.batt(), hass.batt(), + hass.cmd, c.i_w, c.loop_reason, c.batt_refused)) + t += TICK + finally: + m.compute, m.datetime = real, real_dt + return rows, trips, c + return asyncio.run(go()) + + +def at(rows, t): + return min(rows, key=lambda r: abs(r[0] - t)) + + +def longest_hold_h(rows, floor_w=250.0, until=None): + """Longest run of one identical request at or above `floor_w`, in hours.""" + best = cur = 0.0 + last = None + for r in rows: + if until is not None and r[0] >= until: + break + cur = cur + TICK if (r[3] == last and abs(r[3]) >= floor_w) else 0.0 + last = r[3] + best = max(best, cur) + return best / H + + +# ============================================================================== +print("1. the 09-06 shape: a load step takes the request to 5000 W, the battery " + "cuts out, the load ends") +# ============================================================================== +def load906(t): + return 1020 if t < 60 else 4800 if t < 162 else 940 if t < 11.9 * H else -600 + + +def cut906(t): + return t >= 132 + + +def cap906(t): + return 4570.0 + + +old906, otrips906, _ = run(load906, cut906, 12.2 * H, cap906, old=True) +new906, ntrips906, c906 = run(load906, cut906, 12.2 * H, cap906) +for name, rows, tr in (("old", old906, otrips906), ("new", new906, ntrips906)): + print(f" {name}: request at 2 min {at(rows, 120)[3]:+.0f} W, at 6 h " + f"{at(rows, 6 * H)[3]:+.0f} W (i_w {at(rows, 6 * H)[4]:+.0f}), longest " + f"hold {longest_hold_h(rows):.2f} h, gate trips {tr}") +check("PRECONDITION: the old law holds +5000 W for the whole night on this " + "fixture, as it did on 2026-09-06 - the fixture reproduces the card", + at(old906, 6 * H)[3] == 5000.0 and longest_hold_h(old906) > 11.5) +check("the request reaches the rail before the cut, so the new law starts from " + "the same place", at(new906, 120)[3] == 5000.0) +t0 = next((r[0] for r in new906 if r[5] == REFUSED), None) +check(f"after the cut the battery-refuses hold takes the request to 0 W within " + f"about a minute (at t={t0})", t0 is not None and 132 < t0 <= 132 + 90 + and at(new906, t0)[3] == 0.0) +check("...and it stays refused overnight, with the integrator at 0, and no " + "request of 250 W or more stands for longer than one probe interval", + at(new906, 6 * H)[6] == 1 and at(new906, 6 * H)[4] == 0.0 + and longest_hold_h(new906, until=11.9 * H) < PROBE_EVERY_S / H) +check(f"...and the stale-reading gate does not cycle: {ntrips906} trips in " + f"12 hours (the old law's latch also kept it quiet: {otrips906})", + ntrips906 == 0) +morning = [r for r in new906 if r[0] >= 11.9 * H + 60] +check("when solar makes the grid export, the refusal ends and the battery " + "charges - the exit on the other direction", + morning and morning[-1][6] == 0 and morning[-1][3] < -400) + +# ============================================================================== +print("2. the probe: 200 W every 15 minutes, below the gate's 250 W") +# ============================================================================== +probes = [] +for r in new906: + if r[3] == PROBE_W and (not probes or r[0] - probes[-1][1] > TICK): + probes.append([r[0], r[0]]) + elif r[3] == PROBE_W: + probes[-1][1] = r[0] +starts = [p[0] for p in probes] +gaps = [b - a for a, b in zip(starts, starts[1:])] +print(f" {len(probes)} probes, first at {starts[0] / 60 if starts else 0:.1f} " + f"min, gaps {sorted(set(round(g) for g in gaps))} s, lengths " + f"{sorted(set(round(p[1] - p[0] + TICK) for p in probes))} s") +check("the probe asks exactly PROBE_W, which is below the stale-reading gate's " + "threshold, so a probe can never arm it", + PROBE_W < freshness.MOVE_W and all(r[3] in (0.0, PROBE_W) + for r in new906 if r[6] == 1)) +check("there is a probe every 15 minutes through the night (at least 40 in " + "11.8 hours), each about 34 s long", + len(probes) >= 40 and all(PROBE_EVERY_S <= g <= PROBE_EVERY_S + PROBE_S + + 2 * TICK for g in gaps) + and all(PROBE_S - TICK <= p[1] - p[0] + TICK <= PROBE_S + TICK + for p in probes)) +check("...and a probe reads as a probe on the loop's own reason row", + any(r[5] == PROBING for r in new906)) + +# ============================================================================== +print("3. recovery with no sign change: the battery gives power again at 2 h") +# ============================================================================== +def cut_rec(t): + return 132 <= t < 2 * H + + +oldr, _, _ = run(load906, cut_rec, 2.6 * H, cap906, old=True) +newr, _, crec = run(load906, cut_rec, 2.6 * H, cap906) +after_o = [r for r in oldr if 2 * H <= r[0] < 2 * H + 600] +after_n = [r for r in newr if 2 * H <= r[0] < 2.6 * H] +exp_o = sum(max(0.0, -r[1]) * TICK for r in after_o) / 3600 +exp_n = sum(max(0.0, -r[1]) * TICK for r in after_n) / 3600 +print(f" old: worst grid {min(r[1] for r in after_o):+.0f} W, export " + f"{exp_o:.0f} Wh; new: worst grid {min(r[1] for r in after_n):+.0f} W, " + f"export {exp_n:.0f} Wh") +check("PRECONDITION: the old law answers a recovering battery with its " + "standing +5000 W and exports kilowatts into a 940 W house", + min(r[1] for r in after_o) < -3000) +check("the new law never exports more than the probe while it waits, and the " + "answered probe ends the refusal so control resumes", + min(r[1] for r in after_n) > -PROBE_W - 50 + and after_n[-1][6] == 0 and abs(after_n[-1][1] - (-10)) < 100) +check("...and the event log says the probe was answered", + any("BATTERY REFUSES ENDED: the probe was answered" in e + for e in crec.events)) + +# ============================================================================== +print("4. the 09-19 shape: a stale-reading stop on a frozen ~0 W reading " + "is a refusal") +# ============================================================================== +# The request steps +1540 -> +1940 and more as the battery cuts out mid-ramp: +# the request moves after the reading went flat, so the gate trips before the +# hold's 12 cycles - the ~70 s cycle SAFETY-59 measured. The trip seeds the hold. +def load919(t): + return 1530 if t < 60 else 2400 if t < 1800 else 900 if t < 4 * H else -600 + + +def cut919(t): + return t >= 65 + + +def run919(old): + return run(load919, cut919, 4.2 * H, old=old) + + +old919, otr919, _ = run919(True) +new919, ntr919, c919 = run919(False) +print(f" old: gate trips {otr919}, longest hold {longest_hold_h(old919):.2f} h;" + f" new: gate trips {ntr919}, longest hold {longest_hold_h(new919):.2f} h") +check("PRECONDITION: on the old law the gate trips over and over all night " + "(the SAFETY-59 cycle) or the request stands for hours", + otr919 > 20 or longest_hold_h(old919) > 1.0) +check("the new law stops after at most two trips and holds 0 W, and the event " + "log says the battery refuses", + ntr919 <= 2 and at(new919, 2 * H)[3] in (0.0, PROBE_W) + and any("BATTERY REFUSES" in e for e in c919.events)) + +# The same shape through `compute()` alone, as the bus saw it on 2026-09-19 +# before the gate existed: +1540 -> +1940, then a battery giving nothing. +T = control.Tuning(**LIVE) +res = {} +for name, carry in (("old", None), ("new", 0)): + # sat_count 2: the +1540 and +1940 cycles were already short (the plan) + prev, i_w, sat, ref, cmds = 1940.0, 2340.0, 2, carry, [] + for _ in range(2000): # ~2.8 h at 5 s + d = control.compute(prev, 1950.0, CUT_W, T, sat, i_w, refused=ref) + prev, i_w, sat, ref = d.target_w, d.i_w, d.sat_count, d.refused + cmds.append(prev) + res[name] = cmds +print(f" compute() alone: old stands at {res['old'][-1]:+.0f} W " + f"({sum(v == 1940.0 for v in res['old'])} of 2000 cycles at +1940 W), " + f"new at {res['new'][-1]:+.0f} W from cycle " + f"{res['new'].index(0.0) if 0.0 in res['new'] else None}") +check("PRECONDITION: without the gate the old law parks at +1940 W, the 7 065 " + "identical writes the bus recorded", set(res["old"]) == {1940.0}) +check("...and the new law holds 0 W within SETTLE_CYCLES cycles", + res["new"].index(0.0) < control.SETTLE_CYCLES + and set(res["new"][control.SETTLE_CYCLES:]) == {0.0}) + +# ============================================================================== +print("5. the other exits: stop, start, another writer") +# ============================================================================== +def stop(c): + c.auto = False + + +def start(c): + c.auto = True + + +rows, _, c = run(load906, cut906, 1200, cap906, events={600.0: stop, + 700.0: start}) +check("stopping control ends the refusal, and starting again begins from " + "nothing refused", at(rows, 590)[6] == 1 and at(rows, 650)[6] == 0 + and at(rows, 705)[6] == 0) + + +def other_writer(c): + c.loop_w = 1234.0 # the arbiter gave the wire something the loop did not ask + + +rows, _, c = run(load906, cut906, 900, cap906, events={600.0: other_writer}) +check("another writer on the wire ends the refusal (the arbiter reseed)", + at(rows, 590)[6] == 1 and at(rows, 605)[6] == 0) + +# ============================================================================== +print("6. words") +# ============================================================================== +w = messages.why(why_key("loop", [Claim.set("loop", 0, 0.0, REFUSED)]), 0.0) +wp = messages.why(why_key("loop", [Claim.set("loop", 0, PROBE_W, PROBING)]), + PROBE_W) +print(f" {w!r} / {wp!r}") +check("the page's Why line says the battery refuses, not 'Keeping the grid " + "near zero: 0 W'", w == "The battery refuses to give power: 0 W") +check("...and a probe says what it is", wp.startswith("Testing if the battery")) +check("...and an ordinary loop cycle still reads as the loop", + why_key("loop", [Claim.set("loop", 0, 10.0, "tracking")]) == "loop") + +print() +if fails: + print(f"{len(fails)} FAILED: " + ", ".join(fails)) + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/tools/replay_refusal.py b/goodwe_controller/tools/replay_refusal.py new file mode 100644 index 0000000..b739f1f --- /dev/null +++ b/goodwe_controller/tools/replay_refusal.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +"""SAFETY-52's evidence: the 16-day capture replayed with and without the +battery-refuses hold. `python3 tools/replay_refusal.py` + +Same disturbance, fitted plant and pack floor as `replay_recorded_loop.py`, +plus main.py's reseed, 15 s input hold and 0 W rules and the REAL SAFETY-37/57 +gate on a register published every 10 s. `old` is `compute()` with +`refused=None`, which is release/1.0's law unchanged; `new` carries the refusal, +runs the probe on main.py's clock and seeds a refusal from a gate trip. +Modelled watt-hours: read the deltas, not the absolutes (see that tool). +""" +import math +import pathlib +import sys + +ADDON = pathlib.Path(__file__).resolve().parent.parent +sys.path.insert(0, str(ADDON)) +sys.path.insert(0, str(ADDON / "tools")) +import replay_recorded_loop as R # noqa: E402 +from app import freshness, control as NEW # noqa: E402 + +def go(which, rows, fit, publish_s=10.0, stale_input_s=15.0): + law = NEW + tun = law.Tuning(**R.LIVE) + t0, g0, b0, sp0, soc0 = rows[0] + pl = R.Plant(*fit[:4], soc0); pl.seed(t0, b0, sp0) + st = dict(target=sp0, i_w=sp0, sat=0, loop_w=sp0, ref=0, anchor=None) + fr = freshness.Freshness(freshness.BOUNDS["batt"]); reg, reg_t = None, -1e18 + bad, trips, was = None, 0, False + M = dict(und=0.0, imp=0.0, exp=0.0, q={}, run=0.0, mx=0.0, last=None, refh=0.0, probes=0) + for i in range(1, len(rows)): + t, gr, ba, sp, soc = rows[i] + dt = t - rows[i - 1][0] + if dt > R.TICK_CAP_S: + pl = R.Plant(*fit[:4], soc); pl.seed(t, ba, sp) + st.update(target=sp, i_w=sp, sat=0, loop_w=sp, ref=0, anchor=None) + fr = freshness.Freshness(freshness.BOUNDS["batt"]); reg_t = -1e18; bad = None + continue + b = pl.step(t, dt, st["target"]); grid = gr + ba - b + if t - reg_t >= publish_s: + reg, reg_t = float(round(b)), t + fr.submit(reg, st["target"], t); batt = fr.reading() + if fr.stale and not was: + trips += 1 + if (which == "new" and not st["ref"] and st["sat"] >= tun.saturation_cycles + and abs(reg) < tun.saturation_w and abs(st["target"]) > tun.saturation_w): + st["ref"], st["anchor"] = (1 if st["target"] > 0 else -1), t + was = fr.stale + if batt is None: + bad = t if bad is None else bad + if t - bad >= stale_input_s: + st.update(target=0.0, i_w=0.0, loop_w=None) + else: + bad = None + if st["loop_w"] is None or st["target"] != st["loop_w"]: + st["i_w"] = st["target"] + if which == "old": + d = law.compute(st["target"], grid, batt, tun, st["sat"], st["i_w"], + refused=None) + else: + probe = False + if st["ref"] and st["anchor"] is not None: + h = t - st["anchor"] + if h >= NEW.PROBE_EVERY_S + NEW.PROBE_S: st["anchor"] = t + else: probe = h >= NEW.PROBE_EVERY_S + d = law.compute(st["target"], grid, batt, tun, st["sat"], st["i_w"], refused=st["ref"], probe=probe) + if d.refused and not st["ref"]: st["anchor"] = t + if not d.refused: st["anchor"] = None + if probe and d.target_w == NEW.PROBE_W and M["last"] != NEW.PROBE_W: M["probes"] += 1 + st["ref"] = d.refused + st.update(sat=d.sat_count, i_w=d.i_w, loop_w=d.target_w, target=d.target_w) + tg = st["target"] + if tg - b > 1000: M["und"] += dt / 3600 + if st["ref"]: M["refh"] += dt / 3600 + M["imp"] += max(0, grid) * dt / 3.6e6; M["exp"] += max(0, -grid) * dt / 3.6e6 + k = math.floor(t / 900); a = M["q"].setdefault(k, [0.0, 0.0]); a[0] += grid * dt; a[1] += dt + M["run"] = M["run"] + dt if (M["last"] == tg and abs(tg) >= 250) else 0.0 + M["mx"] = max(M["mx"], M["run"]); M["last"] = tg + worst = max(max(0.0, s / d) for s, d in M["q"].values() if d > 600) + return trips, M, worst + +def main(): + rows = R.stream() + fit = R.fit_plant(rows, stride=7) + print(f"fit {[round(x, 2) for x in fit]}, {len(rows)} meter instants") + for label, f in (("fitted plant", fit), + ("plant offset 0 W", (fit[0], fit[1], fit[2], 0.0, fit[4]))): + for which in ("old", "new"): + tr, M, w = go(which, rows, f) + print(f"{label:17s} {which}: gate trips {tr:4d} | request >1 kW above " + f"delivery {M['und']:6.1f} h | longest held >=250 W " + f"{M['mx'] / 3600:5.2f} h | import {M['imp']:6.1f} kWh export " + f"{M['exp']:5.1f} kWh | worst 15-min {w:5.0f} W | refused " + f"{M['refh']:5.1f} h, probes {M['probes']}", flush=True) + +if __name__ == "__main__": + main() -- 2.54.0 From 1d33265aac94b24d64a26fb6b0b7f2ddc0f63cb2 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 17:04:55 +0200 Subject: [PATCH 047/105] test_price: grade the Why row of the same render, not a second read of why_words Since UX-10 the waiting sentence counts its seconds when it is read, so the second read could cross a second boundary on a loaded runner ("1 second" in the row, "2 seconds" in the check). CI run 953 on this PR failed that way; test_price.py passes locally on the same tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_price.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/goodwe_controller/test_price.py b/goodwe_controller/test_price.py index 5fe1c81..7a53af1 100644 --- a/goodwe_controller/test_price.py +++ b/goodwe_controller/test_price.py @@ -4412,12 +4412,16 @@ check(f"AC, AND THE WHOLE OF DEFECT 4: 'trading is off' and 'trading is on " f"`off (arbitrage_enabled)` for both - naming an option that is `true` " f"in the options blob", _T11_OFF[0]["Arbitrage"] != _T11_ON_HELD[0]["Arbitrage"]) +# ⚠️ THE "Why" ROW OF THE SAME RENDER, NOT A SECOND READ OF `why_words`. Since +# UX-10 the waiting sentence counts its seconds when it is read, so reading the +# property again here, after the other renders above, could cross a second +# ("1 second" in the row, "2 seconds" now) - CI run 953 on PR #141 did. check(f"...and the armed-but-held row carries the CONTROL LOOP'S OWN REASON " - f"({_T11_ON_HELD[1].why_words!r}), so the operator is told which input is " + f"({_T11_ON_HELD[0]['Why']!r}), so the operator is told which input is " f"missing rather than being sent to look at a switch that is already on. " f"The reason comes from main.py, not from this file", - _T11_ON_HELD[1].why_words - and _T11_ON_HELD[1].why_words in _T11_ON_HELD[0]["Arbitrage"]) + _T11_ON_HELD[0]["Why"].startswith("A reading is missing") + and _T11_ON_HELD[0]["Why"] in _T11_ON_HELD[0]["Arbitrage"]) check(f"...and a cycle that DID reach the step renders the strategy's own " f"sentence - {_T11_ON_OK[1].arb.explain()[:50]!r} - rather than a " f"re-derivation of it, which is the guarantee OPT-04 put on this row and " -- 2.54.0 From 3c0f2b966947a74d148fd4269453a374977a0bbb Mon Sep 17 00:00:00 2001 From: goodwe-review <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 18:11:42 +0200 Subject: [PATCH 048/105] SAFETY-52 review: a refusal is under 100 W, and any delivery ends it - Engage (and seed from a stale stop) below REFUSED_BELOW_W, the probe's own 100 W answer, not below saturation_w: a battery derated to 100-499 W was held at 0 W ~93 % of the time. - A reading of 100 W or more in the held direction ends the refusal, probe or not: at a 1 s meter SETTLE_CYCLES is 12 s, shorter than a healthy reading's lag, and that held a healthy step at 0 W until the next probe. - test_refusal part 5b and a seed test; DOCS states the N>1 limit; the DECISIONS record carries the traced cause of the replay's extra trips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../SAFETY-52-a-battery-that-refuses.md | 42 +++++++-- goodwe_controller/DOCS.md | 16 ++-- goodwe_controller/app/control.py | 15 ++-- goodwe_controller/app/main.py | 7 +- goodwe_controller/test_delivery.py | 6 +- goodwe_controller/test_refusal.py | 89 +++++++++++++++++++ goodwe_controller/tools/replay_refusal.py | 2 +- 7 files changed, 153 insertions(+), 24 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md b/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md index 0bb06af..07c4a58 100644 --- a/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md +++ b/goodwe_controller/DECISIONS/SAFETY-52-a-battery-that-refuses.md @@ -19,12 +19,13 @@ instead and ran SAFETY-59's ~70 s trip cycle. 1. **A refused direction is held at 0 W**, reason `battery refuses`. It engages in `compute()` when the freeze has held `SETTLE_CYCLES` and the reading is - within `saturation_w` of 0 against an ask beyond it. The drop to 0 skips + below `REFUSED_BELOW_W` (100 W, the probe's own answer) against an ask beyond + `saturation_w`. The drop to 0 skips the slew limit (it only removes an ask nobody meets). The direction is carried like `sat_count` (`refused=`, `Decision.refused`). 2. **A 200 W probe every 15 minutes, 34 s long** (`PROBE_W`, `PROBE_EVERY_S`, - `PROBE_S`; twice `BATT_OBLIGED_S`). An answer of at least 100 W ends the - refusal. 200 W is below `freshness.MOVE_W` (250 W), so a probe cannot arm + `PROBE_S`; twice `BATT_OBLIGED_S`). A reading of at least 100 W in the held + direction ends the refusal, during a probe or not. 200 W is below `freshness.MOVE_W` (250 W), so a probe cannot arm the gate. The clock is main.py's `now_mono`; `compute()` stays clockless. 3. **A gate trip while the loop is frozen on a ~0 W reading is a refusal** for control (`Controller._refusal_from_stale`). This is what stops the ~70 s @@ -52,18 +53,43 @@ shapes, recovery with no sign change, the probe cadence, every exit). | plant | law | gate trips | request >1 kW above delivery | longest held | import / export kWh | worst 15-min | |---|---|---|---|---|---|---| | fitted | old | 85 | 113.3 h | 16.57 h | 112.0 / 35.2 | 3434 W | -| fitted | new | 130 | 11.4 h | 0.21 h | 112.3 / 35.4 | 3456 W | +| fitted | new | 130 (133 after review) | 11.4 h | 0.21 h | 112.3 / 35.4 | 3456 W | | offset 0 W | old | 1010 | 102.2 h | 16.58 h | 112.0 / 35.2 | 3434 W | | offset 0 W | new | 85 | 6.1 h | 0.33 h | 111.9 / 35.1 | 3434 W | -The +22 W worst quarter and the +45 trips on the fitted plant follow the fit's --22 W offset, which slowly charges the modelled pack above its floor while the -hold stands. With the offset at 0 both vanish. That is inferred from these two -rows and was not traced further. Rejected alternatives and their figures are in +**Traced in review (#141).** The +22 W worst quarter is the old law's worst +quarter too. There the old law stands at +2060 W on a pack giving 0 W, and the +new law asks 0 W, which the fitted plant answers with its -22 W offset: 22 W +charged from the grid. The fit above the floor reads `batt = cmd - 28 W`, so a +real inverter asked 0 W may do the same. Of the 71 new-law trips with no +old-law trip within 2 min, 59 come 85-97 s after an answered probe. The offset has lifted the modelled pack +just above its floor, the probe is answered, control ramps, the pack empties +again mid-ramp, and the gate trips, which re-seeds the hold. The other 12 +follow an other-direction exit the same way. On a site this is one +`STALE_READING` ERROR line per answered probe at most, and only on a battery +that answers a probe and then cuts out again. Catching the re-cut before the +gate needs a faster engage than `SETTLE_CYCLES`, which accuses a healthy slow +battery, so it is left to SAFETY-58/59. After the review changes below the +fitted-plant row reads 133 trips (the delivery exit now also catches answers +that arrive after the probe window); the other figures are unchanged. Rejected alternatives and their figures are in the phase A plan: bounding the integrator by demand made the worst quarter +541 W worse or cycled the gate 3368 times, and an SoC envelope needs the configured floor to be right and needs SoC. +## Review changes (#141) + +- **"Gives nothing" is below 100 W, not below 500 W.** At `saturation_w` a + battery derated to 100-499 W (cold, a tapering battery) was held at 0 W for + ~93 % of the time: 300 W derated gave 86 Wh in 4 h against 1 200 Wh on the + old law. The capture has 0.11 h in that band, so the replay does not move. +- **Any delivery ends the hold, not only an answered probe.** With + `meter_poll_s: 1` the 12 cycles last 12 s, less than a healthy battery's + reading lag (up to `BATT_OBLIGED_S`, 17 s). That engaged on a healthy step and + held it for 15 min. Now the late reading ends it within seconds (2 s held in + `test_refusal.py` part 5b). +- **N>1 is stated as a limit in DOCS.** The pack limit there covers an empty + battery only when its cut-out level is configured right. + ## Not covered A battery that gives a steady part of the ask (e.g. a 500 W keep-alive) is a diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 735f1a9..192f9af 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -538,17 +538,23 @@ accumulator is doing: | `saturated-freeze` | the inverter is not following, so the command's magnitude may fall but not rise | | `freeze-released` | the freeze had run out of plant-shaped explanations and the command was let move again | | `not-running` | control is stopped **and** shadow mode is off, so the loop did not run | -| `battery refuses` | the battery gave nothing for a minute while asked for more than 500 W, so the add-on asks 0 W in that direction (see below) | +| `battery refuses` | the battery gave less than 100 W for 12 cycles (a minute at a 5-second meter) while asked for more than 500 W, so the add-on asks 0 W in that direction (see below) | | `battery probe` | the add-on asks 200 W to test whether a refusing battery gives power again | **When the battery refuses.** At its cut-out level the battery gives nothing, whatever it is asked. The add-on then asks 0 W instead of repeating its last request, and the `Why` row reads *The battery refuses to give power: 0 W*. Every -15 minutes it asks 200 W for about half a minute; if the battery answers, -control resumes. It also resumes when the grid needs charging instead, and when +15 minutes it asks 200 W for about half a minute. Control resumes as soon as +the battery gives 100 W or more, when the grid needs charging instead, and when control is stopped or started. 200 W is below the 250 W the stale-reading check -needs, so a test never trips it. One inverter only: with several, the battery -level limit already moves an empty battery's share to the others. +needs, so a test never trips it. A battery that gives some power, even 100 W, +is not refusing and keeps its request. + +⚠️ **One inverter only.** With several inverters this hold is off. There, the +battery level limit moves an empty battery's share to the others, but only if +its “Battery cut-out level” matches where the battery really stops. A battery +that refuses at another level, or for another reason (cold, a battery fault), +can still hold its last request until the grid starts to export. *For installers:* SAFETY-52. The event log reads `BATTERY REFUSES …` and `BATTERY REFUSES ENDED: …`, and the INFO line ends in `BATTERY_REFUSES`. diff --git a/goodwe_controller/app/control.py b/goodwe_controller/app/control.py index fbd0d1c..89d4ee5 100644 --- a/goodwe_controller/app/control.py +++ b/goodwe_controller/app/control.py @@ -286,6 +286,10 @@ REFUSED = "battery refuses" PROBING = "battery probe" PROBE_W = 200.0 PROBE_ANSWER_W = PROBE_W / 2 +# "Gives nothing" is below the probe's own answer, not below `saturation_w`: a +# pack derated to 100-499 W is a limit, and at 500 W it kept ~7 % of its power +# (review of #141). The capture's refusals read -4 W. +REFUSED_BELOW_W = PROBE_ANSWER_W PROBE_EVERY_S = 900.0 PROBE_S = 34.0 @@ -773,18 +777,19 @@ def compute( # --- SAFETY-52: a refused direction is held at 0 W ---------------------- # Engages only where the freeze has held for SETTLE_CYCLES and the unit - # delivers ~nothing: a reading within `saturation_w` of 0 against an ask - # beyond it is a refusal, not a slow plant. The drop to 0 skips the slew + # delivers ~nothing: a reading below REFUSED_BELOW_W against an ask beyond + # `saturation_w` is a refusal, not a slow plant. The drop to 0 skips the slew # limit because it only removes an ask the battery is not meeting. if refused is not None: if (refused == 0 and frozen and sat_count >= SETTLE_CYCLES and abs(prev_w) > tuning.saturation_w - and abs(actual_w) < tuning.saturation_w): + and abs(actual_w) < REFUSED_BELOW_W): refused = 1 if prev_w > 0 else -1 if refused and refused * i_w < 0: refused = 0 # the loop wants the other way - elif refused and probe and refused * actual_w >= PROBE_ANSWER_W: - refused = 0 # the probe was answered + elif refused and refused * actual_w >= PROBE_ANSWER_W: + refused = 0 # it delivers: a probe answered, + # or a slow reading arriving elif refused: wants = refused * i_w > 0 i_w = 0.0 diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 2d0847d..03a008f 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -1108,8 +1108,9 @@ class Controller: f"gave {batt_w:+.0f} W for " f"{decision.sat_count} cycles") elif self.batt_refused and not now: - answered = probe and self.batt_refused * batt_w >= _ctl.PROBE_ANSWER_W - self._refusal_end("the probe was answered" if answered + gave = self.batt_refused * batt_w >= _ctl.PROBE_ANSWER_W + self._refusal_end("the probe was answered" if gave and probe + else "the battery gives power" if gave else "the grid now asks the other direction") def _refusal_from_stale(self, inv, now_mono) -> None: @@ -1124,7 +1125,7 @@ class Controller: and not self.batt_refused and self.sat_count >= t.saturation_cycles and inv.batt_fresh.held is not None - and abs(inv.batt_fresh.held) < t.saturation_w + and abs(inv.batt_fresh.held) < _ctl.REFUSED_BELOW_W and abs(standing) > t.saturation_w): self._now_mono = now_mono self._refusal_start(1 if standing > 0 else -1, diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index a266a38..f356a2f 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -1147,8 +1147,10 @@ async def _one(): "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", "meter_source": "off", "max_w": 2000, "gain": 0.6, # ⚠️ THE SAME 1 s AS THE TWO-INVERTER FIXTURE, AND THAT IS WHAT - # MAKES THIS SECTION NON-VACUOUS. The run below is 2 s of wall clock - # against a 1 s window, so a hold is not what stops this firing - + # MAKES THIS SECTION NON-VACUOUS. The run below is 1.1 s of wall + # clock against a 1 s window (SAFETY-52 shortened it from 2 s, and + # "the window was never even opened" below is what still makes it + # non-vacuous), so a hold is not what stops this firing - # the reduction is. With a shipped-length hold "nothing was # reported" would be true of a fixture that simply ran out of time. "bms_soc_floor": _FLOOR_PCT, "delivery_hold_s": 1, diff --git a/goodwe_controller/test_refusal.py b/goodwe_controller/test_refusal.py index e2bf87b..a396727 100644 --- a/goodwe_controller/test_refusal.py +++ b/goodwe_controller/test_refusal.py @@ -34,6 +34,12 @@ test_messages (MUTATION.md). Reds are failing checks, on this tree: R7 main.py: another writer no longer ends the refusal 1 R8 main.py: stop/start no longer ends the refusal 1 R9 main.py: the probe window never opens 4 + R10 main.py: seed from a stale stop below `saturation_w` again, 1 + not below REFUSED_BELOW_W (review of #141). The same mutation + in control.py's engage clause SURVIVES, and that is expected: + the delivery exit (R11) ends such a refusal in the same cycle. + R11 control.py: only an answered PROBE ends the refusal 2 + (`and probe` back in the delivery exit; review of #141) """ import asyncio @@ -366,6 +372,89 @@ rows, _, c = run(load906, cut906, 900, cap906, events={600.0: other_writer}) check("another writer on the wire ends the refusal (the arbiter reseed)", at(rows, 590)[6] == 1 and at(rows, 605)[6] == 0) +# ============================================================================== +print("5b. review of #141: a pack that gives SOME power, and a reading that is " + "only late, are not a refusal") +# ============================================================================== +# A pack derated to 100-499 W (cold, BMS taper) gives what it can against a +# larger ask. Engaging below `saturation_w` (500 W) held it at 0 W for ~93 % of +# the time; "gives nothing" is below the probe's own answer. +# `compute()` alone: through the Controller the stale-reading gate trips on the +# flat 300 W first, and that fixture then passes whatever this threshold is. +def derated(carry, cap_w=300.0, n=1800): + prev, i_w, sat, ref, gave, held = 0.0, 0.0, 0, carry, 0.0, 0 + b = 0.0 + for _ in range(n): # 2.5 h at 5 s + d = control.compute(prev, 2000.0 - b, b, T, sat, i_w, refused=ref) + prev, i_w, sat, ref = d.target_w, d.i_w, d.sat_count, d.refused + held += bool(ref) + b = max(0.0, min(prev, cap_w)) # one tick late + gave += b + return gave / n, held + + +T = control.Tuning(**LIVE) +gave_old, _ = derated(None) +gave_new, held_new = derated(0) +print(f" pack derated to 300 W: old law {gave_old:.0f} W average, new " + f"{gave_new:.0f} W, held as refusing on {held_new} cycles") +check("a pack that gives a steady 300 W against a 2000 W ask is never held at " + "0 W as refusing, and keeps giving what the old law got from it", + held_new == 0 and gave_new == gave_old and gave_old > 290.0) + + +def lagging(tick, dead_s=6.0, publish_s=10.0, phase_s=5.0, dur=600.0): + """`compute()` on a HEALTHY pack whose reading lags: it follows the command + of `dead_s` ago, published every `publish_s`. A 1 s meter (`meter_poll_s` + 1) makes SETTLE_CYCLES only 12 s, shorter than that lag.""" + prev, i_w, sat, ref, hist, reg, pub = 0.0, 0.0, 0, 0, [], 0.0, -phase_s + held = engaged = 0 + t = 0.0 + while t < dur: + then = [c for tc, c in hist if tc <= t - dead_s] + b = then[-1] if then else 0.0 + if t - pub >= publish_s: + reg, pub = b, t + d = control.compute(prev, (3000.0 if t >= 10 else 0.0) - b, reg, T, + sat, i_w, refused=ref) + engaged += bool(d.refused) and not ref + prev, i_w, sat, ref = d.target_w, d.i_w, d.sat_count, d.refused + hist.append((t, prev)) + held += tick * bool(ref) + t += tick + return engaged, held + + +lag1 = lagging(1.0) +print(f" 1 s meter, healthy pack with a late reading: engaged {lag1[0]} " + f"time(s), held {lag1[1]:.0f} s") +check("a healthy pack whose reading is merely late is let go as soon as the " + "reading shows it delivering - not held until the next probe", + lag1[1] <= 10.0) + + +async def _seed(held_w): + """`_refusal_from_stale()` on a unit standing at +2000 W, frozen.""" + c = Controller(dict( + {"setpoint_entity": "number.sp", "meter_entity": "sensor.grid", + "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", + "meter_source": "off"}, **LIVE), + _Hass(lambda t: 0.0, lambda t: False), _Store(), _Pub(), + stop=asyncio.Event()) + c.auto, c.sat_count = True, c.tuning.saturation_cycles + inv = c.inverters[0] + inv.last_write, inv.batt_fresh.held = 2000.0, held_w + c._refusal_from_stale(inv, 100.0) + return c.batt_refused + + +check("a stale-reading stop on a register standing at 300 W is not a refusal " + "(it gives something), and one at -4 W is", + asyncio.run(_seed(300.0)) == 0 and asyncio.run(_seed(CUT_W)) == 1) +d = control.compute(0.0, 1500.0, 1400.0, T, 0, 0.0, refused=1, probe=False) +check("...i.e. a held direction that reads 100 W or more ends the refusal " + "without waiting for a probe", d.refused == 0) + # ============================================================================== print("6. words") # ============================================================================== diff --git a/goodwe_controller/tools/replay_refusal.py b/goodwe_controller/tools/replay_refusal.py index b739f1f..6b53173 100644 --- a/goodwe_controller/tools/replay_refusal.py +++ b/goodwe_controller/tools/replay_refusal.py @@ -43,7 +43,7 @@ def go(which, rows, fit, publish_s=10.0, stale_input_s=15.0): if fr.stale and not was: trips += 1 if (which == "new" and not st["ref"] and st["sat"] >= tun.saturation_cycles - and abs(reg) < tun.saturation_w and abs(st["target"]) > tun.saturation_w): + and abs(reg) < NEW.REFUSED_BELOW_W and abs(st["target"]) > tun.saturation_w): st["ref"], st["anchor"] = (1 if st["target"] > 0 else -1), t was = fr.stale if batt is None: -- 2.54.0 From 15627c38a6dc4091dac0528108cc00b59c1dc54b Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Sun, 27 Sep 2026 23:11:31 +0200 Subject: [PATCH 049/105] UX-13 P0: layout table, page<->options derivation, warning tier, entity list The foundation for the new settings page. No visible UI change. - app/uilayout.py: screen -> group -> part -> field for every option in config.yaml (67 fields, 11 derived, 0 hidden), with control, unit, display scale, step, entity kind, show conditions, Simple/wizard placement and "applies after a restart". Ranges stay in the schema, words in translations and the new app/ui_text/en.json. - app/uimodel.py: options_to_ui()/ui_to_options() for the derived keys (one inverter vs the list, solar rows, static_profile from simple prices, a year-stamped region preset for the levies figure, and an OPT-11 hook for arbitrage_enabled that changes nothing yet). Unchanged derivations write the stored values back, so the round trip is exact. - validate.py: validate.Note, a warn/info tier. Each logged warning is also a note when a list is passed; config_notes() adds checks that need live data (missing entity, a kW sensor read as W, a limit below this month's peak). /config/validate returns them as "notes". No refusal changed: 261 recorded validator calls, 0 differ (tools/ux13_validator_calls.py). - GET ha/entities: Home Assistant's entity list for the picker, read through hass.states(), cached 30 s, 10 s timeout. When HA is down it answers 200 with the old list marked old, or an empty list that says why. - DECISIONS/UX-13-one-layout-table.md amends UX-02's "no option key in UI code": keys may appear in uilayout.py and uimodel.py only, both tested. - Tests: test_uilayout, test_uimodel (round trip over the recorded calls, the TEST-23 option files and config.yaml defaults), test_haentities, a warning-tier part in test_validate; test_messages scans notes and ui_text; test_pv and test_selfconfig part 7 widened on purpose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- .../DECISIONS/UX-13-one-layout-table.md | 69 ++++ goodwe_controller/app/haentities.py | 87 +++++ goodwe_controller/app/hass.py | 27 ++ goodwe_controller/app/messages.py | 12 + goodwe_controller/app/selfconfig.py | 9 +- goodwe_controller/app/ui_text/en.json | 38 ++ goodwe_controller/app/uilayout.py | 295 ++++++++++++++++ goodwe_controller/app/uimodel.py | 326 ++++++++++++++++++ goodwe_controller/app/validate.py | 135 +++++++- goodwe_controller/app/web.py | 22 +- .../scenarios/ux13/test23/options.arb.json | 73 ++++ .../ux13/test23/options.baseline.json | 73 ++++ .../ux13/test23/options.doc1-roster.json | 98 ++++++ .../scenarios/ux13/test23/options.json | 73 ++++ .../scenarios/ux13/test23/options.s3.json | 73 ++++ .../ux13/validator-calls-652097a.jsonl.gz | Bin 0 -> 4871 bytes goodwe_controller/test_haentities.py | 209 +++++++++++ goodwe_controller/test_messages.py | 20 ++ goodwe_controller/test_pv.py | 22 +- goodwe_controller/test_selfconfig.py | 25 +- goodwe_controller/test_uilayout.py | 202 +++++++++++ goodwe_controller/test_uimodel.py | 212 ++++++++++++ goodwe_controller/test_validate.py | 41 +++ .../tools/ux13_validator_calls.py | 106 ++++++ 24 files changed, 2224 insertions(+), 23 deletions(-) create mode 100644 goodwe_controller/DECISIONS/UX-13-one-layout-table.md create mode 100644 goodwe_controller/app/haentities.py create mode 100644 goodwe_controller/app/ui_text/en.json create mode 100644 goodwe_controller/app/uilayout.py create mode 100644 goodwe_controller/app/uimodel.py create mode 100644 goodwe_controller/scenarios/ux13/test23/options.arb.json create mode 100644 goodwe_controller/scenarios/ux13/test23/options.baseline.json create mode 100644 goodwe_controller/scenarios/ux13/test23/options.doc1-roster.json create mode 100644 goodwe_controller/scenarios/ux13/test23/options.json create mode 100644 goodwe_controller/scenarios/ux13/test23/options.s3.json create mode 100644 goodwe_controller/scenarios/ux13/validator-calls-652097a.jsonl.gz create mode 100644 goodwe_controller/test_haentities.py create mode 100644 goodwe_controller/test_uilayout.py create mode 100644 goodwe_controller/test_uimodel.py create mode 100644 goodwe_controller/tools/ux13_validator_calls.py diff --git a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md new file mode 100644 index 0000000..b23019f --- /dev/null +++ b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md @@ -0,0 +1,69 @@ +# UX-13 — one layout table, and why UI code may now name an option key + +**Status: DECIDED 2026-09-27 (owner approved the UX-13 design and mockup).** +Card 6ab979852f3eca02fb40f69e. Amends [[UX-02]] §3.1. Design note and +mockup: `goodwe-session/UX-13-design.md`, `UX-13-mockup.html`. + +## 1. What UX-02 said, and why it no longer fits + +UX-02 built the configuration panel from the Supervisor's schema, so +`app/configui.py` contains "no option key, no label and no rule", and +test_selfconfig.py part 5 checks that the page script names no key. That kept +a second copy of the option surface from drifting, and it is why the panel is +a flat list of fields in schema order. + +UX-13 needs things a schema cannot say: groups and sub-groups, a slider in kW +for a value stored in W, a picker for an entity, a field shown only for one +meter source, locked measured values, a Simple view and a setup wizard. It +also needs page fields that are not options at all: one inverter card that is +stored as six flat keys, solar rows that become `pv_entity` or `pv_entities`, +a contract and two prices that become `static_profile` JSON, and a region +that becomes the levies figure. None of that can be read off the schema, so +some code has to name option keys. + +## 2. The decision + +Option keys may appear in UI code in exactly two files: + +- **`app/uilayout.py`**, the layout table: screen → group → part → field, with + control, unit, display scale, step, entity kind, when it is shown, whether it + is on the Simple view or a wizard step, and whether it applies now or after a + restart. Every option in `config.yaml` is a field, `DERIVED` or `HIDDEN`, + exactly once. +- **`app/uimodel.py`**, the derivations the table names: `options_to_ui()` and + `ui_to_options()`. It may name only the keys it writes. + +What UX-02 made authoritative stays authoritative: + +- **Ranges** come from the schema (`uilayout.range_of()`); the table writes + none. A unit holds no digit. +- **Labels and help** come from `translations/*.yaml` by key. Page-only fields, + group titles and choices are in `app/ui_text/*.json`, held to STYLE by + test_messages.py. +- **Rules** stay in `validate.py`. It gains a warning tier (`validate.Note`, + "warn" or "info") for the page. A note never blocks a save, and passing the + notes list does not change the refusals returned. +- **The stored blob** is still the one truth. The page model carries the stored + values of every derived key (`keep`). A derivation whose page fields are + unchanged writes those values back untouched, so a blob the page cannot + express survives a save of another field. + +## 3. How it is held + +- test_uilayout.py fails when `config.yaml` gains an option, or an inverter + field, that the table does not place. It also checks that uimodel.py names + only the keys it writes and that web.py and haentities.py name none. +- test_uimodel.py round-trips options → page model → JSON → options for every + validator call the suite made at 652097a (`scenarios/ux13/`), the TEST-23 + option files and config.yaml's defaults. All must be identical. +- `tools/ux13_validator_calls.py compare` runs those calls through the old and + new validator. At P0: 261 calls, 158 refused, no refusal changed. +- test_selfconfig.py part 5 still checks the old page script; P1 moves the page + into `app/static/` and the same check applies there. + +## 4. What this costs + +The table is a second place that knows the option surface, which UX-02 set +out to avoid. The cost is bounded by the coverage test: an option added to +config.yaml and not placed here fails CI, rather than silently missing from +the page. Changing a key's type or range needs no change here. diff --git a/goodwe_controller/app/haentities.py b/goodwe_controller/app/haentities.py new file mode 100644 index 0000000..d6f0784 --- /dev/null +++ b/goodwe_controller/app/haentities.py @@ -0,0 +1,87 @@ +"""UX-13: Home Assistant's entities, for the settings page's entity picker. + +A read of `GET /api/states` through the add-on's own session (hass.states()), +cached for 30 s and trimmed to what a picker shows. Nothing here writes, so +UX-02 §6 holds. When Home Assistant does not answer, the last good list is +served with its age, or an empty one that says why: the route never fails. +""" + +import asyncio +import time + +CACHE_S = 30.0 +DOWN_TEXT = "Home Assistant is not answering, so the entity list is empty." +STALE_TEXT = "Home Assistant is not answering, so this list may be old." +_POWER_UNITS = ("mW", "W", "kW", "MW", "GW", "TW") +_ENERGY_UNITS = ("Wh", "kWh", "MWh", "GWh") + + +def row(state: dict) -> dict | None: + """One state object -> {entity_id, name, state, unit, device_class}.""" + if not isinstance(state, dict) or not isinstance(state.get("entity_id"), str): + return None + attrs = state.get("attributes") if isinstance(state.get("attributes"), dict) else {} + return {"entity_id": state["entity_id"], + "name": str(attrs.get("friendly_name") or state["entity_id"]), + "state": state.get("state"), + "unit": attrs.get("unit_of_measurement"), + "device_class": attrs.get("device_class")} + + +def matches(r: dict, kind: str) -> bool: + """Is `r` what a picker of this kind offers first? `kind` is one of + uilayout.ENTITY_KINDS; "" or "any" offers everything.""" + unit, cls = r.get("unit"), r.get("device_class") + if kind in ("power", "power_w"): + return cls == "power" or unit in _POWER_UNITS + if kind == "energy": + return cls == "energy" or unit in _ENERGY_UNITS + if kind == "pct": + return unit == "%" + if kind == "number": + return r["entity_id"].startswith(("number.", "input_number.")) + return True + + +class EntityCache: + """The last entity list read from Home Assistant, at most CACHE_S old.""" + + def __init__(self, hass, clock=time.monotonic): + self.hass = hass + self.clock = clock + self.rows: dict | None = None + self.read_at: float | None = None + self._lock = asyncio.Lock() + + async def get(self) -> tuple[dict | None, float | None]: + """(rows by entity id, age in s), or (None, None) if never read.""" + async with self._lock: # one HA read however many pickers ask + now = self.clock() + if self.read_at is None or now - self.read_at >= CACHE_S: + states = await self.hass.states() + if states is not None: + rows = (row(s) for s in states) + self.rows = {r["entity_id"]: r for r in rows if r} + self.read_at = now + if self.read_at is None: + return None, None + return self.rows, now - self.read_at + + def peek(self) -> dict | None: + """The cached rows if they are fresh, without asking Home Assistant.""" + if self.read_at is None or self.clock() - self.read_at >= CACHE_S: + return None + return self.rows + + async def payload(self, kind: str = "") -> dict: + """The route's JSON: matching entities first, then the rest.""" + rows, age = await self.get() + if rows is None: + return {"available": False, "text": DOWN_TEXT, "entities": []} + ordered = sorted(rows.values(), key=lambda r: r["entity_id"]) + first = [dict(r, match=True) for r in ordered if matches(r, kind)] + rest = [dict(r, match=False) for r in ordered if not matches(r, kind)] + out = {"available": True, "age_s": round(age, 1), "entities": first + rest} + if age >= CACHE_S: + out["text"] = STALE_TEXT + return out diff --git a/goodwe_controller/app/hass.py b/goodwe_controller/app/hass.py index da1dd33..3835e1d 100644 --- a/goodwe_controller/app/hass.py +++ b/goodwe_controller/app/hass.py @@ -18,6 +18,7 @@ SUPERVISOR_API = "http://supervisor" BAD_STATES = ("unknown", "unavailable", "none", "") # What the Supervisor's proxy answers while Home Assistant restarts. UNAVAILABLE = (502, 503, 504) +STATES_TIMEOUT_S = 10 # UX-13's entity list, like every other read here class Outage: @@ -113,6 +114,32 @@ class HomeAssistant: return None return obj + async def states(self) -> list | None: + """Every entity's state object (`GET /api/states`), or None when Home + Assistant does not answer. A read only (UX-13 entity picker).""" + try: + async with self.session.get( + f"{CORE_API}/states", headers=self._headers, + timeout=STATES_TIMEOUT_S + ) as resp: + if resp.status in UNAVAILABLE: + OUTAGE.down("api", f"error {resp.status}", + f"read all states: {resp.status}") + return None + OUTAGE.up("api") + resp.raise_for_status() + obj = await resp.json() + except aiohttp.ClientConnectionError as err: + OUTAGE.down("api", "no connection", f"read all states: {err}") + return None + except (aiohttp.ClientError, TimeoutError, ValueError) as err: + self._moan("read:*", "Reading the entity list failed: %s", err) + return None + if not isinstance(obj, list): + self._moan("shape:*", "The entity list is not a list: %.80r", obj) + return None + return obj + async def number(self, entity_id: str, invert: bool = False) -> float | None: """Numeric state, or None. Never substitutes a default.""" obj = await self.state(entity_id) diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 4c8bcdb..df26ea7 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -1099,6 +1099,18 @@ LABELS = { "unit_sign_disagree_w": "Per-inverter wrong-direction threshold", "slew_w": "Largest change per cycle", "shadow_mode": "Shadow mode", + # UX-13: named by the settings page's warnings (validate.Note). + "integrator_max_w": "Catch-up limit", + "maintenance_discharge_w": "Draw-down rate", + "peak_cap_w": "Peak limit", + "peak_forecast_entity": "15-minute demand forecast entity", + "meter_entity": "Grid power entity", + "soc_entity": "Battery level entity", + "batt_entity": "Battery power entity", + "pv_entity": "Solar production entity", + "pv_entities": "Solar production entities, per inverter", + "p1_phase_import_entities": "Import entities per phase", + "p1_phase_export_entities": "Export entities per phase", } diff --git a/goodwe_controller/app/selfconfig.py b/goodwe_controller/app/selfconfig.py index 5f3b852..7c56b78 100644 --- a/goodwe_controller/app/selfconfig.py +++ b/goodwe_controller/app/selfconfig.py @@ -288,7 +288,7 @@ async def problems_for(opts: dict, hass=None) -> list: return problems -async def problems_and_ranges(opts: dict, hass=None): +async def problems_and_ranges(opts: dict, hass=None, notes=None): """`problems_for()`, plus WHICH setpoint entities did not report a range. ⚠️ THE SECOND HALF EXISTS SO THE PAGE CANNOT LOOK GREEN FOR A REASON THE @@ -303,6 +303,8 @@ async def problems_and_ranges(opts: dict, hass=None): has just typed a new `setpoint_entity` must be told about THAT entity, and a route that asked the running controller instead would report on the old one. That was the first shape of this and it disagreed with itself. + + UX-13: a list passed as `notes` collects the validator's warnings too. """ flat = str(opts.get("setpoint_entity", "") or "").strip() @@ -329,7 +331,7 @@ async def problems_and_ranges(opts: dict, hass=None): # disagreement is itself the finding - so it is reported rather than # swallowed. Returning `[]` here would turn a crash into a silent # acceptance, which is worse than the 500 this replaced. - found = list(validate_startup_config(opts)) + found = list(validate_startup_config(opts, notes=notes)) if not found: found = [f"the configuration could not be composed ({type(exc).__name__}: " f"{exc}), and the validator did not name a reason. This is a " @@ -347,7 +349,8 @@ async def problems_and_ranges(opts: dict, hass=None): if flat and unit.setpoint_entity.strip().lower() == flat.lower(): dev_min, dev_max = unit.dev_min, unit.dev_max break - problems = list(validate_startup_config(opts, dev_min, dev_max)) + problems = list(validate_startup_config(opts, dev_min, dev_max, + notes=notes)) problems += validate_unit_ranges(units, skip_entity=flat) unread = [unit.setpoint_entity for unit in units if unit.setpoint_entity and unit.dev_min is None diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json new file mode 100644 index 0000000..d3244fb --- /dev/null +++ b/goodwe_controller/app/ui_text/en.json @@ -0,0 +1,38 @@ +{ + "groups": { + "meter": {"name": "Meter", "description": "Where the grid reading comes from."}, + "inverters": {"name": "Inverters and batteries", "description": "The inverters the add-on controls, and your solar."}, + "tariff": {"name": "Tariff and prices", "description": "What you pay and are paid per kWh."}, + "safety": {"name": "Safety limits", "description": "The peak limit, starting and stopping, and the safety stops."}, + "maintenance": {"name": "Maintenance", "description": "The monthly battery cycle and the log."}, + "tuning": {"name": "Control tuning", "description": "For support only, because these were measured on real hardware."} + }, + "parts": { + "meter.timing": {"name": "Timing"}, + "inverters.solar": {"name": "Solar"}, + "tariff.selling": {"name": "Charging and selling on price"}, + "tariff.feed": {"name": "Price feed details"}, + "safety.peak": {"name": "Peak limit"}, + "safety.start": {"name": "Starting and stopping"}, + "safety.stops": {"name": "Safety stops", "description": "Measured on real hardware, so leave them unchanged."}, + "maintenance.support": {"name": "Support"} + }, + "fields": { + "solar": {"name": "Solar inverters", "description": "Each solar inverter's power sensor, which the add-on records but does not use for control."}, + "contract": {"name": "Your contract", "description": "How your supplier prices each kWh you take from the grid."}, + "region": {"name": "Region", "description": "Fills in the grid costs, levies and VAT for the year shown, so check them on your bill."}, + "fallback": {"name": "Price when the feed is down", "description": "Used when the price source does not answer."}, + "fixed_price": {"name": "Price per kWh, all in", "description": "Energy, supplier costs, grid costs, levies and VAT together."}, + "day_price": {"name": "Day price, weekdays 07:00 to 22:00", "description": "All in, as on your bill."}, + "night_price": {"name": "Night and weekend price", "description": "All in, as on your bill."} + }, + "choices": { + "contract": {"none": "No prices", "fixed": "Fixed price", "daynight": "Day and night", "dynamic": "Dynamic, hourly", "custom": "Other time windows"}, + "fallback": {"none": "None", "fixed": "One price", "daynight": "Day and night", "custom": "Other time windows"}, + "region": {"flanders": "Flanders", "own": "I enter my own figure"} + }, + "applies": { + "restart": {"name": "Applies after a restart"}, + "now": {"name": "Applies right away"} + } +} diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py new file mode 100644 index 0000000..23fec4d --- /dev/null +++ b/goodwe_controller/app/uilayout.py @@ -0,0 +1,295 @@ +"""UX-13: the new page's layout, written once - screen, group, field. + +UI code names option keys only here and in uimodel.py, which holds the +derivations this table lists (DECISIONS/UX-13-one-layout-table.md, amending +UX-02 §3). Everything else stays where UX-02 put it: ranges in config.yaml's +schema, rules in validate.py. test_uilayout.py fails CI when an option in +config.yaml has no place here. + +A field's `key` is an option key, `inverters.<field>` for one inverter in the +list, or `ui.<name>` for a page-only control that uimodel.py turns into options. +The key is also its text key: label and help are translations/*.yaml's entry +for an option, and app/ui_text's `fields.<name>` for a `ui.` field. +""" + +from dataclasses import dataclass + +RESTART = "restart" # stored options apply after a restart (UX-02 §5) +NOW = "now" # runtime state (OPT-11's battery switches), none yet + +# Controls are names, not string literals, so a key is never followed by a +# constant (test_defaults_pin.py reads `f("key", <constant>)` as a fallback). +CHOICE, ENTITY, ENTITY_LIST, TOGGLE, SEGMENTED, SLIDER = ( + "choice", "entity", "entity_list", "toggle", "segmented", "slider") +NUMBER, TEXT, SELECT, LOCKED, INVERTER_LIST, SOLAR_LIST = ( + "number", "text", "select", "locked", "inverter_list", "solar_list") +CONTROLS = (CHOICE, ENTITY, ENTITY_LIST, TOGGLE, SEGMENTED, SLIDER, NUMBER, + TEXT, SELECT, LOCKED, INVERTER_LIST, SOLAR_LIST) +# What an entity picker offers first. `power_w` is a power sensor the add-on +# reads as watts with no unit conversion, so validate.py warns on a kW sensor. +ENTITY_KINDS = ("power_w", "power", "energy", "pct", "number", "any") +SHOW_OPS = ("==", "!=", "in", ">", "<") + + +@dataclass(frozen=True) +class Field: + key: str + control: str + unit: str = "" + scale: int = 1 # shown = stored / scale (the peak limit in kW) + step: float = 0 # slider or number step, stored units; 0 = 1 + kind: str = "" # entity picker filter, one of ENTITY_KINDS + show: tuple = () # ((name, op, value), ...), all must hold + applies: str = RESTART + simple: bool = False # also on Settings, Simple + wizard: int = 0 # setup wizard step 1-6, 0 = not in the wizard + + @property + def text(self) -> str: + """Where the label and help live: `translations` or `ui_text`.""" + return "ui_text" if self.key.startswith("ui.") else "translations" + + +@dataclass(frozen=True) +class Part: + id: str # "" is the group's main part + fields: tuple + collapsed: bool = False + + +@dataclass(frozen=True) +class Group: + id: str + parts: tuple + support_only: bool = False # collapsed, with a "for support" warning + + +def _src(*values): + return (("meter_source", "in", values),) + + +_DYNAMIC = (("ui.contract", "==", "dynamic"),) +_MAINT = (("maintenance_enabled", "==", True),) +_ONE = (("inverter_count", "==", 1),) +_SEVERAL = (("inverter_count", ">", 1),) +_PHASES = (("meter_phases", ">", 1),) + +# The per-inverter card. Its keys are `inverters.<field>` in config.yaml. +ROSTER_FIELDS = ( + Field("inverters.name", TEXT, wizard=2), + Field("inverters.setpoint_entity", ENTITY, kind="number", wizard=2), + Field("inverters.max_w", SLIDER, "W", step=100, wizard=2), + Field("inverters.bms_soc_floor", SLIDER, "%", wizard=2), + Field("inverters.soc_entity", ENTITY, kind="pct", wizard=2), + Field("inverters.batt_entity", ENTITY, kind="power_w", wizard=2), + Field("inverters.batt_invert", TOGGLE, wizard=2), + Field("inverters.capacity_kwh", NUMBER, "kWh", step=0.1, wizard=2), +) + +GROUPS = ( + Group("meter", ( + Part("", ( + Field("meter_source", CHOICE, wizard=1), + Field("meter_entity", ENTITY, kind="power_w", show=_src("off"), + wizard=1), + Field("meter_invert", TOGGLE, show=_src("off"), wizard=1), + Field("p1_net_entity", ENTITY, kind="power_w", + show=_src("ha_signed"), wizard=1), + Field("p1_import_entity", ENTITY, kind="power_w", + show=_src("ha_dsmr"), wizard=1), + Field("p1_export_entity", ENTITY, kind="power_w", + show=_src("ha_dsmr"), wizard=1), + Field("p1_host", TEXT, show=_src("homewizard_local"), wizard=1), + Field("meter_mqtt_topic", TEXT, show=_src("mqtt_p1"), wizard=1), + Field("meter_phases", SEGMENTED, wizard=1), + Field("p1_phase_net_entities", ENTITY_LIST, kind="power_w", + show=_src("ha_signed") + _PHASES, wizard=1), + Field("p1_phase_import_entities", ENTITY_LIST, kind="power_w", + show=_src("ha_dsmr") + _PHASES, wizard=1), + Field("p1_phase_export_entities", ENTITY_LIST, kind="power_w", + show=_src("ha_dsmr") + _PHASES, wizard=1), + )), + Part("timing", ( + Field("meter_max_age_s", SLIDER, "s", step=5), + Field("meter_poll_s", SLIDER, "s", + show=_src("homewizard_local")), + ), collapsed=True), + )), + Group("inverters", ( + Part("", (Field("inverters", INVERTER_LIST, wizard=2),)), + # pv.py reads each entity's own unit, so a kW sensor is fine here. + Part("solar", (Field("ui.solar", SOLAR_LIST, kind="power", + wizard=3),)), + )), + Group("tariff", ( + Part("", ( + Field("ui.contract", SEGMENTED, wizard=4), + Field("price_provider", SELECT, show=_DYNAMIC, wizard=4), + Field("price_formula", TEXT, + show=_DYNAMIC + (("price_provider", "==", "custom_formula"),), + wizard=4), + Field("price_csv_path", TEXT, + show=_DYNAMIC + (("price_provider", "==", "manual_csv"),), + wizard=4), + Field("ui.region", SELECT, wizard=4), + Field("price_taxes_eur_kwh", NUMBER, "€/kWh", step=0.00001, + wizard=4), + Field("price_markup_eur_kwh", NUMBER, "€/kWh", step=0.001, + show=_DYNAMIC, wizard=4), + Field("export_price_eur_kwh", NUMBER, "€/kWh", step=0.001, + wizard=4), + Field("price_export_formula", TEXT), + Field("ui.fallback", SEGMENTED, show=_DYNAMIC, wizard=4), + Field("ui.fixed_price", NUMBER, "€/kWh", step=0.01, + show=(("ui.fallback", "==", "fixed"),), wizard=4), + Field("ui.day_price", NUMBER, "€/kWh", step=0.01, + show=(("ui.fallback", "==", "daynight"),), wizard=4), + Field("ui.night_price", NUMBER, "€/kWh", step=0.01, + show=(("ui.fallback", "==", "daynight"),), wizard=4), + )), + Part("selling", ( + # OPT-11: derived from the batteries' selling switches once battery + # modes exist (uimodel.arbitrage_from_batteries). A toggle until then. + Field("arbitrage_enabled", TOGGLE), + Field("cycle_cost_threshold_eur", NUMBER, "€/kWh", step=0.01), + Field("arbitrage_soc_floor", SLIDER, "%"), + Field("arbitrage_soc_ceiling", SLIDER, "%"), + )), + Part("feed", ( + Field("price_feed_url", TEXT, show=_DYNAMIC), + Field("price_horizon_h", SLIDER, "h", show=_DYNAMIC), + Field("price_timeout_s", SLIDER, "s", show=_DYNAMIC), + Field("price_now_entity", ENTITY, kind="any"), + Field("price_avg_entity", ENTITY, kind="any"), + ), collapsed=True), + )), + Group("safety", ( + Part("peak", ( + Field("peak_cap_w", SLIDER, "kW", scale=1000, step=100, + simple=True, wizard=5), + Field("peak_forecast_entity", ENTITY, kind="power_w", wizard=5), + Field("peak_soc_floor", LOCKED, "%"), + )), + Part("start", ( + Field("shadow_mode", SEGMENTED, simple=True, wizard=6), + Field("auto_start", TOGGLE), + Field("estop_fitted", TOGGLE), + Field("stale_input_s", SLIDER, "s"), + Field("meter_freeze_s", SLIDER, "s", step=30, + show=_src("homewizard_local")), + )), + Part("stops", ( + Field("sign_disagree_w", LOCKED, "W", step=10, show=_ONE), + Field("sign_disagree_s", LOCKED, "s", step=5, show=_ONE), + Field("unit_sign_disagree_w", LOCKED, "W", step=10, + show=_SEVERAL), + Field("unit_sign_disagree_s", LOCKED, "s", step=5, + show=_SEVERAL), + Field("site_sign_disagree_w", LOCKED, "W", step=10, + show=_SEVERAL), + Field("site_sign_disagree_s", LOCKED, "s", step=5, + show=_SEVERAL), + Field("circulation_w", LOCKED, "W", step=10, show=_SEVERAL), + Field("circulation_hold_s", LOCKED, "s", step=5, show=_SEVERAL), + Field("delivery_hold_s", LOCKED, "s", step=5, show=_SEVERAL), + ), collapsed=True), + )), + Group("maintenance", ( + Part("", ( + Field("maintenance_enabled", TOGGLE), + Field("maintenance_interval_days", SLIDER, "days", show=_MAINT), + Field("maintenance_start_hour", SELECT, show=_MAINT), + Field("maintenance_discharge_w", SLIDER, "W", step=100, + show=_MAINT), + Field("maintenance_charge_w", SLIDER, "W", step=100, + show=_MAINT), + Field("maintenance_soc_floor", SLIDER, "%", show=_MAINT), + Field("maintenance_soc_target", SLIDER, "%", show=_MAINT), + Field("maintenance_hold_min", SLIDER, "min", step=5, + show=_MAINT), + )), + Part("support", (Field("log_level", SELECT),)), + )), + Group("tuning", ( + Part("", ( + Field("gain", LOCKED, step=0.05), + Field("slew_w", LOCKED, "W", step=50), + Field("deadband_w", LOCKED, "W"), + Field("target_grid_w", LOCKED, "W"), + Field("step_w", LOCKED, "W"), + Field("saturation_w", LOCKED, "W", step=10), + Field("saturation_cycles", LOCKED), + Field("integrator_max_w", LOCKED, "W", step=100), + Field("heartbeat_s", LOCKED, "s"), + Field("cycle_floor_s", LOCKED, "s"), + )), + ), support_only=True), +) + +# Option keys the page never shows. uimodel.py writes each from page fields. +DERIVED = { + "setpoint_entity": "inverters", # one inverter, stored flat + "soc_entity": "inverters", + "batt_entity": "inverters", + "batt_invert": "inverters", + "max_w": "inverters", + "bms_soc_floor": "inverters", + "pv_entity": "ui.solar", # one solar row, stored flat + "pv_entities": "ui.solar", + "pv_invert_entities": "ui.solar", # the rows' "reads negative" toggles + "static_profile": "ui.fallback", # built from the price fields + "price_taxes_profile": "ui.region", # a preset writes it, "own" keeps it +} +# Option keys the page never shows and never writes: passed through as stored. +HIDDEN: dict = {} + + +def fields(): + """Every field once, in page order, roster fields after `inverters`.""" + for group in GROUPS: + for part in group.parts: + for field in part.fields: + yield group, part, field + if field.control == INVERTER_LIST: + for sub in ROSTER_FIELDS: + yield group, part, sub + + +def field(key: str) -> Field | None: + return next((f for _g, _p, f in fields() if f.key == key), None) + + +def visible(fld: Field, model: dict) -> bool: + """Whether `fld` is shown for this page model (uimodel.options_to_ui).""" + for name, op, value in fld.show: + have = model.get(name) + if op == "==" and have != value: + return False + if op == "!=" and have == value: + return False + if op == "in" and have not in value: + return False + try: + if op == ">" and not float(have) > value: + return False + if op == "<" and not float(have) < value: + return False + except (TypeError, ValueError): + return False + return True + + +def range_of(key: str, schema_ui: list): + """(min, max) from the Supervisor's schema (`info["schema"]`), or None. + + Never typed here: config.yaml is the one place a range is written. A range + arrives as lengthMin/lengthMax (tools/supervisor_selfapi_probe.py).""" + path = key.split(".") + nodes = schema_ui or [] + for step in path[:-1]: + parent = next((n for n in nodes if n.get("name") == step), None) + nodes = (parent or {}).get("schema") or [] + node = next((n for n in nodes if n.get("name") == path[-1]), None) + if not node or "lengthMin" not in node or "lengthMax" not in node: + return None + return node["lengthMin"], node["lengthMax"] diff --git a/goodwe_controller/app/uimodel.py b/goodwe_controller/app/uimodel.py new file mode 100644 index 0000000..f5f9c5a --- /dev/null +++ b/goodwe_controller/app/uimodel.py @@ -0,0 +1,326 @@ +"""UX-13: stored options <-> the page model, for the keys the page derives. + +`options_to_ui()` turns the stored blob into what the page edits: always a list +of inverter cards, solar rows with a "reads negative" toggle, a contract and +simple prices instead of `static_profile` JSON, and a region preset instead of +the levies figure. `ui_to_options()` turns it back, so the validator and the +Supervisor always see the real blob. + +The rule that makes the round trip exact: the model carries the stored values +of the derived keys (`keep`). A derivation whose page fields still read what +`keep` decodes to writes `keep` back untouched, and only an edited one is +re-encoded. So a blob the page cannot express (a `static_profile` with odd +windows, a malformed roster) survives a save of some other field unchanged. +See DECISIONS/UX-13-one-layout-table.md. +""" + +import copy +import json + +from .price import FLEMISH_TAXES_COMPONENTS_EUR_KWH +from .static_tariff import ProfileInvalid, parse_static_profile + +__all__ = ["options_to_ui", "ui_to_options", "REGION_PRESETS", + "arbitrage_from_batteries", "DeriveError"] + + +class DeriveError(ValueError): + """The page model asks for something no options blob can say.""" + + +# --------------------------------------------------------------------------- # +# Region presets for "Grid costs, levies and VAT". Year-stamped, updated each +# January (owner, 2026-09-27). Only presets with a sourced figure are listed: +# Flanders is app/price.py's Fluvius Antwerpen sum (TARIFF-18). Wallonia and +# Brussels have a day and a night band (config.yaml) and join with sourced +# figures; until then those sites choose "own". +# --------------------------------------------------------------------------- # +REGION_PRESETS = { + "flanders": { + "year": 2026, + "taxes_eur_kwh": round(sum(v for _n, v in + FLEMISH_TAXES_COMPONENTS_EUR_KWH), 5), + "taxes_profile": "", + }, +} +OWN = "own" + +_ROSTER_FLAT = ("setpoint_entity", "soc_entity", "batt_entity", "batt_invert", + "max_w", "bms_soc_floor") +_TOL = 1e-9 + + +def _blank(v) -> bool: + return v is None or (isinstance(v, str) and not v.strip()) + + +def _num(v): + try: + return None if _blank(v) or isinstance(v, bool) else float(v) + except (TypeError, ValueError): + return None + + +# --- 1. one inverter (flat keys) or the `inverters` list -------------------- # +def _roster_decode(o): + entries = o.get("inverters") + if entries is None or entries == "" or entries == []: + card = {k: o.get(k) for k in _ROSTER_FLAT} + card.update(name="", capacity_kwh=None) + return {"inverter_shape": "flat", "inverters": [card]} + if isinstance(entries, list) and all(isinstance(e, dict) for e in entries): + return {"inverter_shape": "list", + "inverters": [dict(e) for e in entries]} + # Not something a card can show: edited in the Configuration tab only. + return {"inverter_shape": "raw", "inverters": None} + + +def _roster_encode(m, keep): + out = {} + shape, cards = m.get("inverter_shape"), m.get("inverters") + if shape == "raw": + raise DeriveError("the inverter list is edited in the Configuration tab") + if not cards: + raise DeriveError("at least one inverter is needed") + if shape == "flat" and len(cards) == 1: + card = cards[0] + if not _blank(card.get("name")) or not _blank(card.get("capacity_kwh")): + raise DeriveError("one inverter stored flat has no name or capacity") + for k in _ROSTER_FLAT: + if card.get(k) is not None or k in keep: + out[k] = card.get(k) + out["inverters"] = [] + return out + out["inverters"] = [{k: v for k, v in c.items() if v is not None} + for c in cards] + if shape == "flat": + # CFG-04 rule 9e: a flat power request entity beside a list is refused. + # The other flat keys stay as stored and are not read. + out["setpoint_entity"] = "" + return out + + +# --- 2. solar rows: pv_entity / pv_entities / pv_invert_entities ------------ # +def _strs(v): + return [str(x).strip() for x in (v if isinstance(v, list) else []) + if not _blank(x)] + + +def _solar_rows(o): + listed = _strs(o.get("pv_entities")) + if listed: + return listed, True + one = "" if _blank(o.get("pv_entity")) else str(o.get("pv_entity")).strip() + return ([one] if one else []), False + + +def _solar_decode(o): + rows, _listed = _solar_rows(o) + flipped = set(_strs(o.get("pv_invert_entities"))) + return {"ui.solar": [{"entity": e, "reversed": e in flipped} + for e in rows]} + + +def _solar_encode(m, keep): + out = {} + rows = [r for r in (m.get("ui.solar") or []) + if not _blank(r.get("entity"))] + entities = [str(r["entity"]).strip() for r in rows] + old_rows, was_list = _solar_rows(keep) + if len(entities) <= 1 and not was_list: + out["pv_entity"] = entities[0] if entities else "" + if "pv_entities" in keep: + out["pv_entities"] = [] + else: + out["pv_entities"] = entities + if "pv_entity" in keep: + out["pv_entity"] = "" # TEL-12: the list replaces it + # Flips of entities that were never a row stay as stored (pv.stray_inverts + # reports them). Flips of removed rows go with the row. + extras = [x for x in _strs(keep.get("pv_invert_entities")) + if x not in old_rows and x not in entities] + flips = [e for e, r in zip(entities, rows) if r.get("reversed")] + extras + if flips or "pv_invert_entities" in keep: + out["pv_invert_entities"] = flips + return out + + +# --- 3. contract and static_profile ----------------------------------------- # +def _fixed_json(price) -> str: + return json.dumps({"periods": [ + {"name": "all", "from": "00:00", "to": "24:00", "days": "mon-sun", + "eur_per_kwh": price}]}) + + +def _daynight_json(day, night) -> str: + return json.dumps({"periods": [ + {"name": "day", "from": "07:00", "to": "22:00", "days": "mon-fri", + "eur_per_kwh": day}, + {"name": "night", "from": "22:00", "to": "07:00", "days": "mon-fri", + "eur_per_kwh": night}, + {"name": "night", "from": "00:00", "to": "24:00", "days": "sat,sun", + "eur_per_kwh": night}]}) + + +def _shape(text): + """The periods of a profile without their names, for comparing, or None.""" + try: + prof = parse_static_profile(text) + except ProfileInvalid: + return None + if prof is None: + return () + return tuple(sorted((p.start_min, p.end_min, tuple(sorted(p.days)), + p.eur_per_kwh) for p in prof.periods)) + + +def _profile_decode(raw): + """("none"|"fixed"|"daynight"|"custom", fixed, day, night).""" + if isinstance(raw, str) and _blank(raw): + return "none", None, None, None + if not isinstance(raw, str): + return "custom", None, None, None + got = _shape(raw) + if not got: + return ("none" if got == () else "custom"), None, None, None + if len(got) == 1 and got == _shape(_fixed_json(got[0][3])): + return "fixed", got[0][3], None, None + day = next((p[3] for p in got if p[:2] == (420, 1320)), None) + night = next((p[3] for p in got if p[:2] == (1320, 420)), None) + if (day is not None and night is not None + and got == _shape(_daynight_json(day, night))): + return "daynight", None, day, night + return "custom", None, None, None + + +def _tariff_decode(o): + kind, fixed, day, night = _profile_decode(o.get("static_profile", "")) + provider = o.get("price_provider") + dynamic = not _blank(provider) and provider != "off" + return {"ui.contract": "dynamic" if dynamic else kind, + "price_provider": provider, "ui.fallback": kind, + "ui.fixed_price": fixed, "ui.day_price": day, + "ui.night_price": night} + + +def _tariff_encode(m, keep): + out = {} + contract = m.get("ui.contract") + if contract == "dynamic": + if _blank(m.get("price_provider")) or m.get("price_provider") == "off": + raise DeriveError("a dynamic contract needs a price source") + out["price_provider"] = m["price_provider"] + kind = m.get("ui.fallback") + else: + out["price_provider"] = "off" + kind = contract + if kind == "none": + out["static_profile"] = "" + elif kind == "fixed": + out["static_profile"] = _fixed_json(_price_of(m, "ui.fixed_price")) + elif kind == "daynight": + out["static_profile"] = _daynight_json(_price_of(m, "ui.day_price"), + _price_of(m, "ui.night_price")) + elif kind == "custom": + if "static_profile" not in keep: + raise DeriveError("odd tariff windows are edited in the " + "Configuration tab") + out["static_profile"] = keep["static_profile"] + else: + raise DeriveError(f"unknown contract {kind!r}") + return out + + +def _price_of(m, name): + value = _num(m.get(name)) + if value is None: + raise DeriveError(f"{name} needs a price") + return value + + +# --- 4. region preset -> price_taxes_eur_kwh / price_taxes_profile ---------- # +def _region_decode(o): + taxes, profile = o.get("price_taxes_eur_kwh"), o.get("price_taxes_profile", "") + region = OWN + for rid, p in REGION_PRESETS.items(): + same = _num(taxes) is not None and abs(_num(taxes) - p["taxes_eur_kwh"]) < _TOL + if same and str(profile or "").strip() == p["taxes_profile"]: + region = rid + return {"ui.region": region, "price_taxes_eur_kwh": taxes} + + +def _region_encode(m, keep): + region = m.get("ui.region") + if region == OWN: + return {"price_taxes_eur_kwh": m.get("price_taxes_eur_kwh")} + if region not in REGION_PRESETS: + raise DeriveError(f"unknown region {region!r}") + p = REGION_PRESETS[region] + out = {"price_taxes_eur_kwh": p["taxes_eur_kwh"]} + if p["taxes_profile"] or "price_taxes_profile" in keep: + out["price_taxes_profile"] = p["taxes_profile"] + return out + + +# --- 5. arbitrage_enabled: the OPT-11 hook ---------------------------------- # +def arbitrage_from_batteries(m): + """OPT-11 hook. With battery modes on, `arbitrage_enabled` is true when any + battery may sell. Battery modes are not built yet, so this returns None and + the toggle is stored as the page has it: no behaviour change.""" + return None + + +def _arbitrage_decode(o): + return {"arbitrage_enabled": o.get("arbitrage_enabled")} + + +def _arbitrage_encode(m, keep): + derived = arbitrage_from_batteries(m) + value = m.get("arbitrage_enabled") if derived is None else derived + return {} if value is None and "arbitrage_enabled" not in keep \ + else {"arbitrage_enabled": value} + + +# (option keys it writes, decode, encode). Each is independent of the others. +DERIVATIONS = ( + (("inverters",) + _ROSTER_FLAT, _roster_decode, _roster_encode), + (("pv_entity", "pv_entities", "pv_invert_entities"), _solar_decode, + _solar_encode), + (("price_provider", "static_profile"), _tariff_decode, _tariff_encode), + (("price_taxes_eur_kwh", "price_taxes_profile"), _region_decode, + _region_encode), + (("arbitrage_enabled",), _arbitrage_decode, _arbitrage_encode), +) +_OWNED = {k for keys, _d, _e in DERIVATIONS for k in keys} +_MODEL_ONLY = ("keep", "inverter_shape", "inverter_count", "region_year") + + +def options_to_ui(options: dict) -> dict: + """The page model for a stored blob. Pure: reads nothing else.""" + model = {k: copy.deepcopy(v) for k, v in options.items() + if k not in _OWNED} + for _keys, decode, _encode in DERIVATIONS: + model.update(decode(options)) + model["keep"] = {k: copy.deepcopy(options[k]) for k in _OWNED + if k in options} + cards = model.get("inverters") + model["inverter_count"] = len(cards) if isinstance(cards, list) else None + preset = REGION_PRESETS.get(model["ui.region"]) + model["region_year"] = preset["year"] if preset else None + return model + + +def ui_to_options(model: dict) -> dict: + """The options blob for a page model. Raises DeriveError on a model no blob + can express, so the page says so instead of saving something else.""" + keep = model.get("keep") or {} + out = {k: copy.deepcopy(v) for k, v in model.items() + if k not in _MODEL_ONLY and k not in _OWNED + and not k.startswith("ui.")} + for keys, decode, encode in DERIVATIONS: + was = decode(keep) + if all(model.get(name) == value for name, value in was.items()): + out.update({k: copy.deepcopy(keep[k]) for k in keys if k in keep}) + else: + out.update(encode(model, keep)) + return out diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index f006133..5177739 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -321,8 +321,9 @@ WHAT IS DELIBERATELY *NOT* REFUSED, because it is untidy rather than unsafe: """ import logging +from typing import NamedTuple -from . import messages +from . import messages, pv from .arbitrage import enabled as arbitrage_on from .control import SLEW_RAIL_FRAC, LOOP_TICK_S, PLANT_SETTLE_S from .custom_formula import ( @@ -330,7 +331,8 @@ from .custom_formula import ( parse_export_formula, parse_price_formula, stale_card) from .inverter import roster_entries from .maintenance import MAINT_OPTION_DEFAULTS -from .p1 import is_enabled, validate_meter_options +from .p1 import ( + SOURCE_HA, SOURCE_HA_SIGNED, is_enabled, validate_meter_options) from .peakguard import PEAK_OPTION_DEFAULTS from .price import ( PRICE_OPTION_DEFAULTS, PROVIDERS, RETIRED_PROVIDERS, @@ -367,6 +369,22 @@ class _WarnOnce(logging.Filter): WARN_ONCE = _WarnOnce() _LOG.addFilter(WARN_ONCE) + +class Note(NamedTuple): + """UX-13: a warning or info for the settings page. Never a refusal: the + add-on starts. `keys` are the options it is about, so the page can show it + beside them.""" + tier: str # "warn" or "info" + keys: tuple + text: str + + +def _advise(notes, tier: str, keys, text: str) -> None: + """Add a Note when the caller collects them (the settings page).""" + if notes is not None: + notes.append(Note(tier, tuple(keys), text)) + + # ⚠️ A MIRROR OF A FIRMWARE CONSTANT, AND IT CANNOT BE IMPORTED. The firmware # threshold is a compile-time YAML substitution baked into the ESP32 image # (`max_age_s: "30"`, master/goodwe-master-stage4-failsafe.yaml), so nothing at @@ -789,7 +807,8 @@ class ConfigRefused(Exception): super().__init__(problems[0] if problems else "configuration refused") -def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str]: +def validate_startup_config(opts: dict, dev_min=None, dev_max=None, + notes: list | None = None) -> list[str]: """Return the list of reasons this configuration must not be started. Empty list means go. `dev_min`/`dev_max` are the setpoint device's own @@ -799,6 +818,9 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] Pure and side-effect free apart from two warnings, so it can be called from a test or from sim/inject.py without a Home Assistant anywhere near it. + + UX-13: pass a list as `notes` to also get each logged warning as a `Note` + for the settings page. The refusals returned do not depend on it. """ problems: list[str] = [] @@ -1127,7 +1149,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] f"site. Set it to 0 or to at most {bound:.0f} W.") # --- 7. two price sources on one site ------------------------------------ - problems.extend(_price_problems(opts)) + problems.extend(_price_problems(opts, notes)) # --- 8. an EMS energy floor the BMS does not already enforce ------------- # ⚠️ THE FALLBACKS ARE peakguard.PEAK_OPTION_DEFAULTS, NOT LITERALS, and @@ -1173,6 +1195,9 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] "integrator_max_w %.0f W is above max_w %.0f W. This is allowed, " "but it only adds overshoot, so 0 is recommended.", integ_w, max_w) + _advise(notes, "warn", ("integrator_max_w",), + f"{S('integrator_max_w')} is above {S('max_w')}, which only " + "adds overshoot, so set it to 0.") # ⚠️ THE SIBLING OF RULE 6, AND NOT THE SAME CASE - see the docstring. The # drain phase OWNS the actuator (`Claim.set` at P_MAINTENANCE), and a SET is @@ -1197,6 +1222,10 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] "maintenance_discharge_w %.0f W is above max_w%s %.0f W, so " "draining runs at %.0f W. Lower it to %.0f W or raise max_w.", disch_w, maint_where, maint_cap, maint_cap, maint_cap) + _advise(notes, "warn", ("maintenance_discharge_w",), + f"{S('maintenance_discharge_w')} is above " + f"{S('max_w', maint_where)}, so the battery empties at " + f"{messages.watts(maint_cap)} and the cycle takes longer.") _LOG.debug( "Not refused: the drain phase sets the setpoint, the arbiter " "clamps it to %.0f W and names the clamp, and the drain phase has " @@ -1205,7 +1234,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None) -> list[str] return problems -def _price_problems(opts: dict) -> list[str]: +def _price_problems(opts: dict, notes: list | None = None) -> list[str]: """Rule 7 (TARIFF-02): the price configuration, refused where it is untrue. ⚠️ NOTE WHAT IS *NOT* HERE. `price_provider: "off"` is not refused and never @@ -1423,6 +1452,9 @@ def _price_problems(opts: dict) -> list[str]: "%s has negative levies %s EUR/kWh, which are subtracted from " "the price. This is allowed, but it is usually a sign error.", TAXES_PROFILE_OPTION, negative) + _advise(notes, "warn", (TAXES_PROFILE_OPTION,), + f"{S(TAXES_PROFILE_OPTION)} has negative figures, which " + "lower the price, and that is usually a sign error.") # ⚠️ TARIFF-15: THE FORMULA, GRADED AGAINST THE OPERATOR'S OWN CARD, AT # STARTUP RATHER THAN AT 03:00. @@ -1478,6 +1510,10 @@ def _price_problems(opts: dict) -> list[str]: "price_formula is filled in, but price_provider is %r, so the " "formula is not used. Set price_provider to 'custom_formula' " "or clear price_formula.", pid) + _advise(notes, "warn", ("price_formula", "price_provider"), + f"{S('price_formula')} is not used, because " + f"{S('price_provider')} is not 'custom_formula', so clear " + "it or choose that source.") if spec is not None and pid == "custom_formula": taxes = _number(opts, "price_taxes_eur_kwh", PRICE_OPTION_DEFAULTS["price_taxes_eur_kwh"]) @@ -1491,6 +1527,8 @@ def _price_problems(opts: dict) -> list[str]: # exactly right and a site refused over one is a site that # cannot start. _LOG.warning("%s", aged) + _advise(notes, "warn", ("price_formula",), + _card_note("price_formula", spec)) # ⚠️ TARIFF-16: THE INJECTION LEG, REFUSED AT STARTUP ON THE SAME RULE. # @@ -1571,6 +1609,9 @@ def _price_problems(opts: dict) -> list[str]: "%.4g, offset %+.5f EUR/kWh).", EXPORT_FORMULA_OPTION, xspec.passthrough, xspec.offset_eur_kwh) + _advise(notes, "info", (EXPORT_FORMULA_OPTION,), + f"{S(EXPORT_FORMULA_OPTION)} has no card block, so " + "only the shape of its numbers is checked.") _LOG.debug( "Accepted because some suppliers (Eneco) print the " "injection formula with no price beside it. If your card " @@ -1582,6 +1623,8 @@ def _price_problems(opts: dict) -> list[str]: xaged = stale_card(xspec) if xaged: _LOG.warning("%s", xaged) + _advise(notes, "warn", (EXPORT_FORMULA_OPTION,), + _card_note(EXPORT_FORMULA_OPTION, xspec)) # ⚠️ A WARNING, NOT A REFUSAL, AND THE ASYMMETRY IS DELIBERATE. §11.4 says a # site with no price data falls back to the static profile; a dynamic site @@ -1593,6 +1636,9 @@ def _price_problems(opts: dict) -> list[str]: "price_provider is %r but static_profile is empty, so a price " "feed outage leaves no tariff at all. Fill in static_profile as a " "fallback.", pid) + _advise(notes, "warn", ("static_profile",), + f"{S('static_profile')} is empty, so the site has no tariff " + "at all while the price feed is down.") # ⚠️ OPT-04. THE THREE WAYS `arbitrage_enabled: true` CAN BE A LIE, refused # rather than logged, because a strategy that is armed in the UI and cannot @@ -1644,6 +1690,85 @@ def _price_problems(opts: dict) -> list[str]: return problems +def _card_note(option: str, spec) -> str: + return (f"{S(option)} uses a tariff card dated {spec.card_month}, so copy " + "the new figures if your contract changed.") + + +# UX-13: entity options whose number the add-on takes as watts, with no unit +# conversion. pv.py converts each solar entity's own unit, so those are not here. +WATT_ENTITY_KEYS = ( + "meter_entity", "p1_net_entity", "p1_import_entity", "p1_export_entity", + "p1_phase_net_entities", "p1_phase_import_entities", + "p1_phase_export_entities", "batt_entity", "peak_forecast_entity") + + +def _entities_read(opts: dict) -> list[tuple[str, str, str]]: + """(key, inverter name or "", entity id) for each entity the add-on reads + with these options. Keys the chosen meter source or roster shape ignores + are left out, so a stale default is not reported.""" + out = [] + + def add(key, value, where=""): + for e in (value if isinstance(value, list) else [value]): + if isinstance(e, str) and e.strip(): + out.append((key, where, e.strip())) + + source = str(opts.get("meter_source") or "off").strip() + by_source = {"off": ("meter_entity",), + SOURCE_HA_SIGNED: ("p1_net_entity", "p1_phase_net_entities"), + SOURCE_HA: ("p1_import_entity", "p1_export_entity", + "p1_phase_import_entities", + "p1_phase_export_entities")} + for key in by_source.get(source, ()): + add(key, opts.get(key)) + entries = roster_entries(opts) + if not entries: + for key in ("setpoint_entity", "soc_entity", "batt_entity"): + add(key, opts.get(key)) + for i, entry in enumerate(entries): + if isinstance(entry, dict): + where = _unit_label(opts, i).strip().strip("()") + for key in ("setpoint_entity", "soc_entity", "batt_entity"): + add(key, entry.get(key), where) + solar = [e for e in (opts.get("pv_entities") or []) if str(e or "").strip()] + add("pv_entities" if solar else "pv_entity", list(pv.entities(opts))) + for key in ("peak_forecast_entity", "price_now_entity", "price_avg_entity"): + add(key, opts.get(key)) + return out + + +def config_notes(opts: dict, *, entities: dict | None = None, + month_peak_w=None) -> list[Note]: + """UX-13: warnings that need live data, for the settings page. Never a + refusal, and nothing here changes what `validate_startup_config()` says. + + `entities` is Home Assistant's entity list by id (app/haentities.py), or + None when it could not be read, in which case those checks are skipped. + `month_peak_w` is this month's peak so far, or None. + """ + notes: list[Note] = [] + if entities is not None: + for key, where, entity in _entities_read(opts): + row = entities.get(entity) + if row is None: + _advise(notes, "warn", (key,), + f"Home Assistant has no entity {entity}, which " + f"{S(key, where)} names.") + continue + unit = str(row.get("unit") or "") + if key in WATT_ENTITY_KEYS and unit in pv.WATTS_PER and unit != "W": + _advise(notes, "warn", (key,), + f"{entity} reads in {unit}, but {S(key, where)} is " + "taken as watts, so pick a sensor in W.") + cap = _number(opts, "peak_cap_w", None) + if month_peak_w is not None and cap is not None and cap < month_peak_w: + _advise(notes, "warn", ("peak_cap_w",), + f"This month's peak is already {messages.watts(month_peak_w)}, " + f"so a lower {S('peak_cap_w')} saves nothing until next month.") + return notes + + def _number(opts: dict, key, default): raw = opts.get(key, default) if raw is None or raw == "": diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index a774fa3..aa117a9 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -24,7 +24,8 @@ routes below read `GET /addons/self/info`, run the SHIPPED validator, write mode or reaches `controller.handle_action()`. The set of things an operator can do to the inverter through this panel is exactly what `/action` offered before this card - test_selfconfig.py part 7 asserts that by listing the routes and the -actions and comparing them with the shipped set. +actions and comparing them with the shipped set. UX-13's `ha/entities` is a GET +of Home Assistant's entity list (app/haentities.py) and writes nothing. """ import logging @@ -32,6 +33,8 @@ import logging from aiohttp import web from . import messages, selfconfig +from .haentities import EntityCache +from .validate import config_notes from .config_page import CONFIG_PAGE from .configui import changed_keys, field_model, problems_by_field @@ -140,6 +143,7 @@ def build_app(controller, selfcfg=None) -> web.Application: if selfcfg is None: selfcfg = selfconfig.SelfConfig(controller.hass.session, controller.hass.token) + entities = EntityCache(controller.hass) async def index(_request): return web.Response(text=PAGE, content_type="text/html") @@ -216,11 +220,16 @@ def build_app(controller, selfcfg=None) -> web.Application: be a second opinion about a rule it does not own. """ _body, options = await _proposed(request) + notes = [] problems, unread = await selfconfig.problems_and_ranges( - options, controller.hass) + options, controller.hass, notes=notes) by_key, unanchored = problems_by_field(problems, _keys_of(options)) + # UX-13: warnings and info beside the refusals. Never block a save. + # The entity checks use the picker's cached list and never wait on HA. + notes += config_notes(options, entities=entities.peek()) payload = {"problems": problems, "by_key": by_key, - "unanchored": unanchored} + "unanchored": unanchored, + "notes": [n._asdict() for n in notes]} if unread: payload["device_note"] = DEVICE_NOTE % ", ".join(sorted(set(unread))) return web.json_response(payload) @@ -290,6 +299,12 @@ def build_app(controller, selfcfg=None) -> web.Application: hint=messages.hint("restart_requested")) return web.json_response({"ok": True}) + async def ha_entities(request): + """UX-13: Home Assistant's entities for the picker. A read only, and + never an error: when Home Assistant is down the list says so.""" + kind = str(request.query.get("kind", "") or "")[:16] + return web.json_response(await entities.payload(kind)) + app = web.Application() app.add_routes([ web.get("/", index), @@ -300,6 +315,7 @@ def build_app(controller, selfcfg=None) -> web.Application: web.post("/config/validate", config_validate), web.post("/config/save", config_save), web.post("/config/restart", config_restart), + web.get("/ha/entities", ha_entities), ]) return app diff --git a/goodwe_controller/scenarios/ux13/test23/options.arb.json b/goodwe_controller/scenarios/ux13/test23/options.arb.json new file mode 100644 index 0000000..e0a3ec6 --- /dev/null +++ b/goodwe_controller/scenarios/ux13/test23/options.arb.json @@ -0,0 +1,73 @@ +{ + "arbitrage_enabled": true, + "arbitrage_soc_ceiling": 95, + "arbitrage_soc_floor": 20, + "auto_start": false, + "batt_entity": "sensor.test23_battery_power", + "batt_invert": false, + "bms_soc_floor": 10, + "circulation_hold_s": 75, + "circulation_w": 700, + "cycle_cost_threshold_eur": 0.1, + "cycle_floor_s": 15, + "deadband_w": 15, + "delivery_hold_s": 185, + "estop_fitted": false, + "export_price_eur_kwh": 0.04, + "gain": 0.6, + "heartbeat_s": 10, + "integrator_max_w": 0, + "inverters": [], + "log_level": "info", + "maintenance_charge_w": 2000, + "maintenance_discharge_w": 2000, + "maintenance_enabled": false, + "maintenance_hold_min": 120, + "maintenance_interval_days": 28, + "maintenance_soc_floor": 11, + "maintenance_soc_target": 99, + "maintenance_start_hour": 10, + "max_w": 2000, + "meter_entity": "sensor.p1_meter_active_power", + "meter_freeze_s": 300, + "meter_invert": false, + "meter_max_age_s": 30, + "meter_mqtt_topic": "", + "meter_phases": 1, + "meter_poll_s": 5, + "meter_source": "ha_signed", + "p1_export_entity": "", + "p1_host": "", + "p1_import_entity": "", + "p1_net_entity": "sensor.test23_p1_meter_active_power", + "p1_phase_export_entities": [], + "p1_phase_import_entities": [], + "p1_phase_net_entities": [], + "peak_cap_w": 3500, + "peak_forecast_entity": "", + "peak_soc_floor": 20, + "price_avg_entity": "", + "price_csv_path": "/share/goodwe_prices.csv", + "price_feed_url": "https://api.energy-charts.info/price?bzn=BE", + "price_horizon_h": 48, + "price_markup_eur_kwh": 0.03, + "price_now_entity": "", + "price_provider": "generic_dayahead", + "price_taxes_eur_kwh": 0.06, + "price_timeout_s": 10, + "saturation_cycles": 3, + "saturation_w": 500, + "setpoint_entity": "number.test23_setpoint_w", + "sign_disagree_s": 180, + "sign_disagree_w": 300, + "site_sign_disagree_s": 325, + "site_sign_disagree_w": 300, + "slew_w": 0, + "soc_entity": "sensor.test23_soc", + "stale_input_s": 15, + "static_profile": "", + "step_w": 10, + "target_grid_w": -10, + "unit_sign_disagree_s": 85, + "unit_sign_disagree_w": 250 +} \ No newline at end of file diff --git a/goodwe_controller/scenarios/ux13/test23/options.baseline.json b/goodwe_controller/scenarios/ux13/test23/options.baseline.json new file mode 100644 index 0000000..768a884 --- /dev/null +++ b/goodwe_controller/scenarios/ux13/test23/options.baseline.json @@ -0,0 +1,73 @@ +{ + "arbitrage_enabled": false, + "arbitrage_soc_ceiling": 95, + "arbitrage_soc_floor": 20, + "auto_start": false, + "batt_entity": "", + "batt_invert": false, + "bms_soc_floor": 10, + "circulation_hold_s": 75, + "circulation_w": 700, + "cycle_cost_threshold_eur": 0.1, + "cycle_floor_s": 15, + "deadband_w": 15, + "delivery_hold_s": 185, + "estop_fitted": false, + "export_price_eur_kwh": 0.04, + "gain": 0.6, + "heartbeat_s": 10, + "integrator_max_w": 0, + "inverters": [], + "log_level": "info", + "maintenance_charge_w": 2000, + "maintenance_discharge_w": 2000, + "maintenance_enabled": false, + "maintenance_hold_min": 120, + "maintenance_interval_days": 28, + "maintenance_soc_floor": 11, + "maintenance_soc_target": 99, + "maintenance_start_hour": 10, + "max_w": 2000, + "meter_entity": "sensor.p1_meter_active_power", + "meter_freeze_s": 300, + "meter_invert": false, + "meter_max_age_s": 30, + "meter_mqtt_topic": "", + "meter_phases": 1, + "meter_poll_s": 5, + "meter_source": "off", + "p1_export_entity": "", + "p1_host": "", + "p1_import_entity": "", + "p1_net_entity": "", + "p1_phase_export_entities": [], + "p1_phase_import_entities": [], + "p1_phase_net_entities": [], + "peak_cap_w": 3500, + "peak_forecast_entity": "", + "peak_soc_floor": 20, + "price_avg_entity": "", + "price_csv_path": "/share/goodwe_prices.csv", + "price_feed_url": "", + "price_horizon_h": 48, + "price_markup_eur_kwh": 0.03, + "price_now_entity": "", + "price_provider": "off", + "price_taxes_eur_kwh": 0.06, + "price_timeout_s": 10, + "saturation_cycles": 3, + "saturation_w": 500, + "setpoint_entity": "", + "sign_disagree_s": 180, + "sign_disagree_w": 300, + "site_sign_disagree_s": 325, + "site_sign_disagree_w": 300, + "slew_w": 0, + "soc_entity": "", + "stale_input_s": 15, + "static_profile": "", + "step_w": 10, + "target_grid_w": -10, + "unit_sign_disagree_s": 85, + "unit_sign_disagree_w": 250 +} \ No newline at end of file diff --git a/goodwe_controller/scenarios/ux13/test23/options.doc1-roster.json b/goodwe_controller/scenarios/ux13/test23/options.doc1-roster.json new file mode 100644 index 0000000..551b715 --- /dev/null +++ b/goodwe_controller/scenarios/ux13/test23/options.doc1-roster.json @@ -0,0 +1,98 @@ +{ + "arbitrage_enabled": false, + "arbitrage_soc_ceiling": 95, + "arbitrage_soc_floor": 20, + "auto_start": false, + "batt_entity": "sensor.test23_battery_power", + "batt_invert": false, + "bms_soc_floor": 10, + "circulation_hold_s": 75, + "circulation_w": 700, + "cycle_cost_threshold_eur": 0.1, + "cycle_floor_s": 15, + "deadband_w": 15, + "delivery_hold_s": 185, + "estop_fitted": false, + "export_price_eur_kwh": 0.04, + "gain": 0.6, + "heartbeat_s": 10, + "integrator_max_w": 0, + "inverters": [ + { + "batt_entity": "sensor.goodwe_a_battery_power", + "bms_soc_floor": 10, + "capacity_kwh": 15.36, + "max_w": 5000, + "name": "inverter-a", + "setpoint_entity": "number.goodwe_a_setpoint_w", + "soc_entity": "sensor.goodwe_a_soc" + }, + { + "batt_entity": "sensor.goodwe_b_battery_power", + "bms_soc_floor": 10, + "capacity_kwh": 20.48, + "max_w": 4600, + "name": "inverter-b", + "setpoint_entity": "number.goodwe_b_setpoint_w", + "soc_entity": "sensor.goodwe_b_soc" + } + ], + "log_level": "info", + "maintenance_charge_w": 2000, + "maintenance_discharge_w": 2000, + "maintenance_enabled": false, + "maintenance_hold_min": 120, + "maintenance_interval_days": 28, + "maintenance_soc_floor": 11, + "maintenance_soc_target": 99, + "maintenance_start_hour": 10, + "max_w": 2000, + "meter_entity": "sensor.p1_meter_active_power", + "meter_freeze_s": 300, + "meter_invert": false, + "meter_max_age_s": 30, + "meter_mqtt_topic": "", + "meter_phases": 1, + "meter_poll_s": 5, + "meter_source": "ha_signed", + "p1_export_entity": "", + "p1_host": "", + "p1_import_entity": "", + "p1_net_entity": "sensor.test23_p1_meter_active_power", + "p1_phase_export_entities": [], + "p1_phase_import_entities": [], + "p1_phase_net_entities": [], + "peak_cap_w": 3500, + "peak_forecast_entity": "", + "peak_soc_floor": 20, + "price_avg_entity": "", + "price_csv_path": "/share/goodwe_prices.csv", + "price_export_formula": "", + "price_feed_url": "https://api.energy-charts.info/price?bzn=BE", + "price_formula": "", + "price_horizon_h": 48, + "price_markup_eur_kwh": 0.03, + "price_now_entity": "", + "price_provider": "generic_dayahead", + "price_taxes_eur_kwh": 0.06, + "price_taxes_profile": "", + "price_timeout_s": 10, + "pv_entities": [], + "pv_entity": "", + "saturation_cycles": 3, + "saturation_w": 500, + "setpoint_entity": "", + "shadow_mode": "auto", + "sign_disagree_s": 180, + "sign_disagree_w": 300, + "site_sign_disagree_s": 325, + "site_sign_disagree_w": 300, + "slew_w": 0, + "soc_entity": "sensor.test23_soc", + "stale_input_s": 15, + "static_profile": "", + "step_w": 10, + "target_grid_w": -10, + "unit_sign_disagree_s": 85, + "unit_sign_disagree_w": 250 +} \ No newline at end of file diff --git a/goodwe_controller/scenarios/ux13/test23/options.json b/goodwe_controller/scenarios/ux13/test23/options.json new file mode 100644 index 0000000..5a388aa --- /dev/null +++ b/goodwe_controller/scenarios/ux13/test23/options.json @@ -0,0 +1,73 @@ +{ + "arbitrage_enabled": false, + "arbitrage_soc_ceiling": 95, + "arbitrage_soc_floor": 20, + "auto_start": false, + "batt_entity": "sensor.test23_battery_power", + "batt_invert": false, + "bms_soc_floor": 10, + "circulation_hold_s": 75, + "circulation_w": 700, + "cycle_cost_threshold_eur": 0.1, + "cycle_floor_s": 15, + "deadband_w": 15, + "delivery_hold_s": 185, + "estop_fitted": false, + "export_price_eur_kwh": 0.04, + "gain": 0.6, + "heartbeat_s": 10, + "integrator_max_w": 0, + "inverters": [], + "log_level": "info", + "maintenance_charge_w": 2000, + "maintenance_discharge_w": 2000, + "maintenance_enabled": false, + "maintenance_hold_min": 120, + "maintenance_interval_days": 28, + "maintenance_soc_floor": 11, + "maintenance_soc_target": 99, + "maintenance_start_hour": 10, + "max_w": 2000, + "meter_entity": "sensor.p1_meter_active_power", + "meter_freeze_s": 300, + "meter_invert": false, + "meter_max_age_s": 30, + "meter_mqtt_topic": "", + "meter_phases": 1, + "meter_poll_s": 5, + "meter_source": "ha_signed", + "p1_export_entity": "", + "p1_host": "", + "p1_import_entity": "", + "p1_net_entity": "sensor.test23_p1_meter_active_power", + "p1_phase_export_entities": [], + "p1_phase_import_entities": [], + "p1_phase_net_entities": [], + "peak_cap_w": 3500, + "peak_forecast_entity": "", + "peak_soc_floor": 20, + "price_avg_entity": "", + "price_csv_path": "/share/goodwe_prices.csv", + "price_feed_url": "https://api.energy-charts.info/price?bzn=BE", + "price_horizon_h": 48, + "price_markup_eur_kwh": 0.03, + "price_now_entity": "", + "price_provider": "generic_dayahead", + "price_taxes_eur_kwh": 0.06, + "price_timeout_s": 10, + "saturation_cycles": 3, + "saturation_w": 500, + "setpoint_entity": "number.test23_setpoint_w", + "sign_disagree_s": 180, + "sign_disagree_w": 300, + "site_sign_disagree_s": 325, + "site_sign_disagree_w": 300, + "slew_w": 0, + "soc_entity": "sensor.test23_soc", + "stale_input_s": 15, + "static_profile": "", + "step_w": 10, + "target_grid_w": -10, + "unit_sign_disagree_s": 85, + "unit_sign_disagree_w": 250 +} \ No newline at end of file diff --git a/goodwe_controller/scenarios/ux13/test23/options.s3.json b/goodwe_controller/scenarios/ux13/test23/options.s3.json new file mode 100644 index 0000000..18354a9 --- /dev/null +++ b/goodwe_controller/scenarios/ux13/test23/options.s3.json @@ -0,0 +1,73 @@ +{ + "arbitrage_enabled": true, + "arbitrage_soc_ceiling": 95, + "arbitrage_soc_floor": 20, + "auto_start": true, + "batt_entity": "sensor.test23_battery_power", + "batt_invert": false, + "bms_soc_floor": 10, + "circulation_hold_s": 75, + "circulation_w": 700, + "cycle_cost_threshold_eur": 0.1, + "cycle_floor_s": 15, + "deadband_w": 15, + "delivery_hold_s": 185, + "estop_fitted": false, + "export_price_eur_kwh": 0.04, + "gain": 0.6, + "heartbeat_s": 10, + "integrator_max_w": 0, + "inverters": [], + "log_level": "info", + "maintenance_charge_w": 2000, + "maintenance_discharge_w": 2000, + "maintenance_enabled": false, + "maintenance_hold_min": 120, + "maintenance_interval_days": 28, + "maintenance_soc_floor": 11, + "maintenance_soc_target": 99, + "maintenance_start_hour": 10, + "max_w": 2000, + "meter_entity": "sensor.p1_meter_active_power", + "meter_freeze_s": 300, + "meter_invert": false, + "meter_max_age_s": 30, + "meter_mqtt_topic": "", + "meter_phases": 1, + "meter_poll_s": 5, + "meter_source": "ha_signed", + "p1_export_entity": "", + "p1_host": "", + "p1_import_entity": "", + "p1_net_entity": "sensor.test23_p1_meter_active_power", + "p1_phase_export_entities": [], + "p1_phase_import_entities": [], + "p1_phase_net_entities": [], + "peak_cap_w": 15000, + "peak_forecast_entity": "", + "peak_soc_floor": 20, + "price_avg_entity": "", + "price_csv_path": "/share/goodwe_prices.csv", + "price_feed_url": "", + "price_horizon_h": 48, + "price_markup_eur_kwh": 0.03, + "price_now_entity": "", + "price_provider": "manual_csv", + "price_taxes_eur_kwh": 0.06, + "price_timeout_s": 10, + "saturation_cycles": 3, + "saturation_w": 500, + "setpoint_entity": "number.test23_setpoint_w", + "sign_disagree_s": 180, + "sign_disagree_w": 300, + "site_sign_disagree_s": 325, + "site_sign_disagree_w": 300, + "slew_w": 0, + "soc_entity": "sensor.test23_soc", + "stale_input_s": 15, + "static_profile": "", + "step_w": 10, + "target_grid_w": -10, + "unit_sign_disagree_s": 85, + "unit_sign_disagree_w": 250 +} \ No newline at end of file diff --git a/goodwe_controller/scenarios/ux13/validator-calls-652097a.jsonl.gz b/goodwe_controller/scenarios/ux13/validator-calls-652097a.jsonl.gz new file mode 100644 index 0000000000000000000000000000000000000000..a019bc5603bf004b5d74f136e65a1e12390846b8 GIT binary patch literal 4871 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 literal 0 HcmV?d00001 diff --git a/goodwe_controller/test_haentities.py b/goodwe_controller/test_haentities.py new file mode 100644 index 0000000..a562b97 --- /dev/null +++ b/goodwe_controller/test_haentities.py @@ -0,0 +1,209 @@ +"""UX-13 P0: the entity list for the picker. `python3 test_haentities.py` + +`GET ha/entities` reads Home Assistant's states through the add-on's own +session (hass.states()) and must never fail the page: part 1 drives the real +HomeAssistant client against a local server that answers 502, garbage, the +wrong shape, nothing at all, or too slowly. Part 2 checks the 30 s cache and +what is served while Home Assistant is down. Part 3 serves the real route. +Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). +""" + +import asyncio +import json +import sys +import time + +from aiohttp import ClientSession, web as aioweb + +from app import hass as H, haentities as E, web + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +STATES = [ + {"entity_id": "sensor.grid", "state": "812", + "attributes": {"friendly_name": "Grid power", "unit_of_measurement": "W", + "device_class": "power"}}, + {"entity_id": "sensor.soc", "state": "54", + "attributes": {"friendly_name": "Battery level", "unit_of_measurement": "%", + "device_class": "battery"}}, + {"entity_id": "number.setpoint", "state": "0", "attributes": {}}, + {"entity_id": "sensor.pv_kw", "state": "1.2", + "attributes": {"unit_of_measurement": "kW"}}, + {"no_entity_id": True}, +] + + +async def serve(handler): + app = aioweb.Application() + app.router.add_get("/api/states", handler) + runner = aioweb.AppRunner(app) + await runner.setup() + site = aioweb.TCPSite(runner, "127.0.0.1", 0) + await site.start() + return runner, site._server.sockets[0].getsockname()[1] + + +async def read_with(handler, timeout_s=10): + runner, port = await serve(handler) + H.CORE_API, H.STATES_TIMEOUT_S = f"http://127.0.0.1:{port}/api", timeout_s + try: + async with ClientSession() as session: + t0 = time.monotonic() + got = await H.HomeAssistant(session, "token").states() + read_with.took = time.monotonic() - t0 + return got + finally: + await runner.cleanup() + + +async def ok(_r): + return aioweb.json_response(STATES) + + +async def bad_gateway(_r): + return aioweb.Response(status=502) + + +async def garbage(_r): + return aioweb.Response(text="<html>", content_type="application/json") + + +async def not_a_list(_r): + return aioweb.json_response({"message": "hi"}) + + +async def slow(_r): + await asyncio.sleep(2) + return aioweb.json_response(STATES) + + +async def closed_port(): + H.CORE_API = "http://127.0.0.1:9/api" + async with ClientSession() as session: + return await H.HomeAssistant(session, "token").states() + + +print("1. hass.states() answers None, never an exception") +check("a normal answer is the state list", asyncio.run(read_with(ok)) == STATES) +for name, handler in (("502 while HA restarts", bad_gateway), + ("a body that is not JSON", garbage), + ("JSON that is not a list", not_a_list)): + check(f"{name} -> None", asyncio.run(read_with(handler)) is None) +check("an answer slower than the timeout -> None, at the timeout", + asyncio.run(read_with(slow, timeout_s=0.3)) is None + and read_with.took < 1.0) +check("no server at all -> None", asyncio.run(closed_port()) is None) +check("the timeout for the list is the same 10 s as every other read", + "STATES_TIMEOUT_S = 10 " in open(H.__file__, encoding="utf-8").read()) + + +class FakeHass: + def __init__(self): + self.answer, self.reads = STATES, 0 + + async def states(self): + self.reads += 1 + await asyncio.sleep(0.01) + return self.answer + + +class Clock: + def __init__(self): + self.t = 1000.0 + + def __call__(self): + return self.t + + +print("\n2. the cache, and Home Assistant being down") +_h, _c = FakeHass(), Clock() +_cache = E.EntityCache(_h, clock=_c) + + +async def burst(): + return await asyncio.gather(*(_cache.payload("power") for _ in range(5))) + + +_p = asyncio.run(burst()) +check("five pickers opening at once cost one read of Home Assistant", + _h.reads == 1 and all(x == _p[0] for x in _p)) +_ids = [r["entity_id"] for r in _p[0]["entities"]] +check("power entities come first, then the rest, and a broken state is left " + f"out ({_ids})", _ids == ["sensor.grid", "sensor.pv_kw", + "number.setpoint", "sensor.soc"] + and [r["match"] for r in _p[0]["entities"]] == [True, True, False, False]) +check("each row carries id, name, state, unit and device class", + _p[0]["entities"][0] == {"entity_id": "sensor.grid", "name": "Grid power", + "state": "812", "unit": "W", + "device_class": "power", "match": True}) +check("the kinds filter as the pickers need", + [r["entity_id"] for r in _p[0]["entities"] + if E.matches(r, "pct")] == ["sensor.soc"] + and [r["entity_id"] for r in _p[0]["entities"] + if E.matches(r, "number")] == ["number.setpoint"]) +_c.t += 10 +asyncio.run(_cache.payload()) +check("within 30 s the cached list is served", _h.reads == 1) +check("peek() hands the validator the fresh list without a read", + set(_cache.peek()) == set(_ids) and _h.reads == 1) +_h.answer = None +_c.t += 30 +_down = asyncio.run(_cache.payload()) +check("Home Assistant down after a good read: the old list, marked old", + _h.reads == 2 and _down["available"] and _down["text"] == E.STALE_TEXT + and len(_down["entities"]) == 4 and _down["age_s"] >= 30) +check("...and peek() then gives nothing, so no warning rests on an old list", + _cache.peek() is None) +_h2 = FakeHass() +_h2.answer = None +_empty = asyncio.run(E.EntityCache(_h2).payload("power")) +check("Home Assistant down from the start: an empty list that says why", + _empty == {"available": False, "text": E.DOWN_TEXT, "entities": []}) + + +print("\n3. the route") + + +class FakeController: + def __init__(self, hass): + self.hass, self.o = hass, {} + + +async def route(hass, query=""): + app = web.build_app(FakeController(hass), selfcfg=object()) + runner = aioweb.AppRunner(app) + await runner.setup() + site = aioweb.TCPSite(runner, "127.0.0.1", 0) + await site.start() + port = site._server.sockets[0].getsockname()[1] + try: + async with ClientSession() as s: + async with s.get(f"http://127.0.0.1:{port}/ha/entities{query}") as r: + return r.status, await r.json() + finally: + await runner.cleanup() + + +_st, _body = asyncio.run(route(FakeHass(), "?kind=pct")) +check("GET ha/entities?kind=pct answers 200 with the matching entity first", + _st == 200 and _body["entities"][0]["entity_id"] == "sensor.soc") +_st, _body = asyncio.run(route(_h2)) +check("with Home Assistant down it still answers 200, with the reason", + _st == 200 and _body["available"] is False and _body["entities"] == []) +check("the words shown are short and plain (STYLE: one sentence)", + all(len(t.split()) <= 12 and t.count(".") == 1 + for t in (E.DOWN_TEXT, E.STALE_TEXT))) +print(json.dumps(_body)) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 1bf14d9..e82176c 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -26,6 +26,7 @@ Run `python3 -B test_messages.py --violations` to print what part 3 sees. import ast import hashlib +import json import os import re import sys @@ -388,6 +389,9 @@ LIMITS = { # kind: (words, keys ok, entity ids ok) "log": (25, True, True), "option-name": (6, False, False), "option-desc": (30, True, True), + "note": (25, True, True), # UX-13: a settings-page warning + "ui-name": (6, False, False), # UX-13: app/ui_text, a name or choice + "ui-desc": (25, False, False), # UX-13: app/ui_text, one-line help } LOG_CALL = re.compile(r"(?:^|\.)(?:_LOG|log|logger|LOG)\.(warning|error|critical|exception)$") @@ -453,6 +457,10 @@ def collect(): if arg is not None: for n, t in strings_in(arg): out.append(("log", f"{f.name}:{n.lineno}", t)) + elif name.endswith("_advise") and node.args: + for n, t in strings_in(node.args[-1], expand=True): + if len(words(t)) > 1: + out.append(("note", f"{f.name}:{n.lineno}", t)) elif re.search(r"problems\.(append|extend)$", name): for a in node.args: for n, t in strings_in(a, expand=True): @@ -475,6 +483,16 @@ def collect(): if isinstance(v.get("fields"), dict): walk(v["fields"], f"{path}{key}.") walk(tr.get("configuration"), "") + # UX-13: the new page's own words, held to the option texts' rule. + for f in sorted((APP / "ui_text").glob("*.json")): + def walk_ui(node, path): + for key, v in node.items(): + if isinstance(v, dict): + walk_ui(v, f"{path}{key}.") + elif isinstance(v, str): + out.append(("ui-desc" if key == "description" else + "ui-name", f"{f.name}:{path}{key}", v)) + walk_ui(json.loads(f.read_text(encoding="utf-8")), "") return out @@ -485,6 +503,8 @@ def problems_of(kind, text): p.append(f"over {lim} words ({len(words(text))})") if ";" in text: p.append("semicolon") + if kind in ("note", "ui-desc") and sentences(text) > 1: + p.append(f"over 1 sentence ({sentences(text)})") return p + text_problems(text, keys=keys, entities=ents) diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 6f73277..1768e4b 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -697,13 +697,21 @@ print(f" {len(APP)} modules under app/; TEL-11 material is in: {_touch}") check(f"PRECONDITION: the scan found the whole package, not a subset - " f"{len(APP)} modules", len(APP) >= 25 and "control.py" in [f.name for f in APP]) -check("⭐ EXACTLY THREE MODULES CAN SEE THE MATERIAL: `pv.py` (the reader), " - "`main.py` (the read and the two operator surfaces) and `mqtt.py` (the " - "publication). `control.py`, `arbiter.py`, `allocator.py`, `peakguard.py`, " - "`arbitrage.py`, `maintenance.py`, `clamp.py`, `freeze.py`, " - "`watchdog.py`, `delivery.py` and `circulation.py` do not mention it in " - "any spelling, comments included", - _touch == ["main.py", "mqtt.py", "pv.py"]) +# UX-13 adds the settings surface: labels (messages.py), a settings warning +# (validate.py) and the page's layout and derivation (uilayout.py, uimodel.py). +# None of them decides anything, so the decision modules stay excluded. +_DECIDERS = ("control.py", "arbiter.py", "allocator.py", "peakguard.py", + "arbitrage.py", "maintenance.py", "clamp.py", "freeze.py", + "watchdog.py", "delivery.py", "circulation.py") +check("⭐ ONLY THE READER, THE PUBLISHER AND THE SETTINGS SURFACE SEE THE " + "MATERIAL: `pv.py` (the reader), `main.py` (the read and the two operator " + "surfaces), `mqtt.py` (the publication), and `messages.py`, " + "`validate.py`, `uilayout.py` and `uimodel.py` (settings). " + f"{', '.join(_DECIDERS)} do not mention it in any spelling, comments " + "included", + _touch == ["main.py", "messages.py", "mqtt.py", "pv.py", "uilayout.py", + "uimodel.py", "validate.py"] + and not set(_DECIDERS) & set(_touch)) # habit 4 in the instrument: a scanner that cannot go red is not a scanner. check("...and the scan CAN go red - a module body with the material in it is " "caught, so the green above is the tree speaking and not the scanner " diff --git a/goodwe_controller/test_selfconfig.py b/goodwe_controller/test_selfconfig.py index 10d6608..81bd773 100644 --- a/goodwe_controller/test_selfconfig.py +++ b/goodwe_controller/test_selfconfig.py @@ -636,12 +636,18 @@ _app = web.build_app(FakeController(), FakeSupervisor()) _routes = sorted({(r.method, r.get_info().get("path")) for r in _app.router.routes() if r.method != "HEAD"}) print(" " + " ".join(f"{m} {p}" for m, p in _routes)) -check("the configuration surface adds five routes and touches none of the " - "three that were there", +check("the configuration surface adds five routes and UX-13 one GET, and " + "none touches the three that were there", _routes == [("GET", "/"), ("GET", "/config"), ("GET", "/config/model"), - ("GET", "/status"), ("POST", "/action"), - ("POST", "/config/restart"), ("POST", "/config/save"), - ("POST", "/config/validate")]) + ("GET", "/ha/entities"), ("GET", "/status"), + ("POST", "/action"), ("POST", "/config/restart"), + ("POST", "/config/save"), ("POST", "/config/validate")]) +_ents_src = io.open(os.path.join(HERE, "app", "haentities.py"), + encoding="utf-8").read() +check("UX-13's entity list only reads: haentities.py calls hass.states() and " + "no service, setter or action", + "hass.states()" in _ents_src + and not re.search(r"\.(call|set_number|handle_action|post)\(", _ents_src)) _selfconfig_src = io.open(os.path.join(HERE, "app", "selfconfig.py"), encoding="utf-8").read() for forbidden in ("set_number", "write_setpoint", "handle_action", @@ -692,6 +698,10 @@ async def _e2e(): async with s.post(f"{root}/config/validate", json={"options": base(setpoint_entity="")}) as r: out["invalid"] = await r.json() + async with s.post(f"{root}/config/validate", + json={"options": base(integrator_max_w=3000)} + ) as r: + out["warned"] = await r.json() # ⚠️ THE COUNTS ARE SNAPSHOTTED AT EACH STAGE. Asserting # `sup.writes == []` after the whole sequence would be asserting # about the LAST request, not this one - the first draft did, and @@ -749,6 +759,11 @@ check("...and it honours the browser's language per key, falling back to " check("POST config/validate returns the validator's sentences, anchored", E["invalid"]["problems"] and "setpoint_entity" in E["invalid"]["by_key"]) +check("UX-13: POST config/validate also returns the validator's warnings, " + "beside no refusal", + E["warned"]["problems"] == [] and [n["keys"] for n in + E["warned"]["notes"]] + == [["integrator_max_w"]] and E["warned"]["notes"][0]["tier"] == "warn") check("a save of an invalid blob answers 422 and the Supervisor got nothing", E["save_invalid"][0] == 422 and E["save_invalid"][1]["kind"] == "invalid" diff --git a/goodwe_controller/test_uilayout.py b/goodwe_controller/test_uilayout.py new file mode 100644 index 0000000..5d04ec5 --- /dev/null +++ b/goodwe_controller/test_uilayout.py @@ -0,0 +1,202 @@ +"""UX-13 P0: the layout table places every option once. `python3 test_uilayout.py` + +app/uilayout.py is the one place UI code names an option key +(DECISIONS/UX-13-one-layout-table.md). This file fails CI when config.yaml +gains an option the table does not place, and checks each row against the +sources UX-02 keeps authoritative: config.yaml for ranges, translations and +app/ui_text for words, validate.py for which entities are read as watts. +Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). +""" + +import io +import json +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) + +import translations_lint as TL # noqa: E402 +from app import uilayout as L, uimodel, validate # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +CONFIG = io.open(os.path.join(HERE, "config.yaml"), encoding="utf-8").read() +ORDER, NESTED = TL.config_surface(CONFIG) +TYPES = dict(re.findall(r"^ ([a-z_0-9]+): *(\S.*?) *$", + CONFIG[CONFIG.index("\nschema:"):], re.M)) +EN = TL.parse_translation_file(os.path.join(HERE, "translations", "en.yaml")) +UI_TEXT = json.load(io.open(os.path.join(HERE, "app", "ui_text", "en.json"), + encoding="utf-8")) +ROWS = list(L.fields()) +KEYS = [f.key for _g, _p, f in ROWS] + + +def coverage_problems(order, nested): + """Every way the table and config.yaml's schema disagree.""" + out = [] + placed = [k for k in KEYS if not k.startswith(("ui.", "inverters."))] + for k in order: + n = placed.count(k) + (k in L.DERIVED) + (k in L.HIDDEN) + if n != 1: + out.append(f"{k} is placed {n} times") + out += [f"{k} is not in config.yaml" for k in + set(placed) | set(L.DERIVED) | set(L.HIDDEN) if k not in order] + sub = [k.split(".", 1)[1] for k in KEYS if k.startswith("inverters.")] + out += [f"inverters.{k} has no card field" for k in nested.get("inverters", []) + if sub.count(k) != 1] + out += [f"inverters.{k} is not in config.yaml" for k in sub + if k not in nested.get("inverters", [])] + return out + + +print("1. every option has exactly one place") +_p = coverage_problems(ORDER, NESTED) +_fields = sum(1 for k in ORDER if k in KEYS) +print(f" {len(ORDER)} options: {_fields} fields, {len(L.DERIVED)} derived, " + f"{len(L.HIDDEN)} hidden. Problems: {_p}") +check(f"config.yaml's {len(ORDER)} options are each a field, derived or hidden, " + "once", not _p and len(ORDER) >= 78) +check("a new option without a place fails this check", + coverage_problems(ORDER + ["new_option_w"], NESTED) + == ["new_option_w is placed 0 times"]) +check("...and so does a new inverter field", + coverage_problems(ORDER, {"inverters": NESTED["inverters"] + ["mode"]}) + == ["inverters.mode has no card field"]) +check("no key is both a field and derived", + not set(KEYS) & (set(L.DERIVED) | set(L.HIDDEN))) +check("each derived key names the page field that writes it", + all(any(f.key == how for _g, _p2, f in ROWS) + for how in L.DERIVED.values())) + +print("\n2. each row is well formed") +check("every control, entity kind and show operator is a known one", + all(f.control in L.CONTROLS and (not f.kind or f.kind in L.ENTITY_KINDS) + and all(op in L.SHOW_OPS for _n, op, _v in f.show) + for _g, _p2, f in ROWS)) +_names = set(ORDER) | set(KEYS) | {"inverter_count"} +check("every show condition reads an option, a page field or inverter_count", + all(n in _names for _g, _p2, f in ROWS for n, _o, _v in f.show)) +check("every entity control has a kind, and no other control has one", + all((f.control in (L.ENTITY, L.ENTITY_LIST, L.SOLAR_LIST)) == bool(f.kind) + for _g, _p2, f in ROWS)) +check("everything applies after a restart: options are read at start, and " + "OPT-11's runtime switches are not built yet", + all(f.applies == L.RESTART for _g, _p2, f in ROWS)) +check("no unit states a number, so no range is written here", + all(not re.search(r"\d", f.unit) for _g, _p2, f in ROWS)) + + +_SCHEMA = CONFIG[CONFIG.index("\nschema:"):] +_ROSTER = re.search(r"^ inverters:\n((?: {4,}.*\n)+)", _SCHEMA, re.M).group(1) +ROSTER_TYPES = dict(re.findall(r"^ {4,}(?:- )?([a-z_0-9]+): *(\S+)", _ROSTER, + re.M)) + + +def _type(key): + if key.startswith("inverters."): + return ROSTER_TYPES.get(key.split(".", 1)[1], "") + return TYPES.get(key, "") + + +_ranged = [f.key for _g, _p2, f in ROWS + if f.control in (L.SLIDER, L.NUMBER, L.LOCKED) + and not f.key.startswith("ui.")] +_unranged = [k for k in _ranged if not re.match(r"(int|float)\(", _type(k))] +check(f"every slider, number and locked value has a range in config.yaml " + f"({len(_ranged)} of them, without: {_unranged})", not _unranged) +_SUFFIX = (("_eur_kwh", "€/kWh"), ("_eur", "€/kWh"), ("_kwh", "kWh"), + ("_w", "W"), ("_s", "s"), ("_h", "h"), ("_min", "min"), + ("_days", "days"), ("_floor", "%"), ("_ceiling", "%"), + ("_target", "%")) + + +def _unit_problem(f): + want = next((u for suf, u in _SUFFIX if f.key.endswith(suf)), None) + if want is None or f.control not in (L.SLIDER, L.NUMBER, L.LOCKED): + return False + return f.unit != want and not (want == "W" and f.unit == "kW" + and f.scale == 1000) + + +_mism = [(f.key, f.unit) for _g, _p2, f in ROWS if _unit_problem(f)] +check(f"each unit matches its key's suffix (mismatched: {_mism})", not _mism) +check("the peak limit is shown in kW and stored in W", + L.field("peak_cap_w").unit == "kW" and L.field("peak_cap_w").scale == 1000) +_watt = sorted({f.key.split(".")[-1] for _g, _p2, f in ROWS + if f.kind == "power_w"}) +check(f"the pickers that expect watts are exactly the entities validate.py " + f"reads as watts ({_watt})", + _watt == sorted(validate.WATT_ENTITY_KEYS)) +check("range_of() reads a Supervisor-shaped schema, nested ones too", + L.range_of("max_w", [{"name": "max_w", "lengthMin": 100, + "lengthMax": 5000}]) == (100, 5000) + and L.range_of("inverters.max_w", [{"name": "inverters", "schema": [ + {"name": "max_w", "lengthMin": 100, "lengthMax": 5000}]}]) + == (100, 5000) + and L.range_of("p1_host", [{"name": "p1_host"}]) is None) + +print("\n3. the words come from translations and app/ui_text") +_conf = EN["configuration"] +_no_tr = [k for k in KEYS if not k.startswith("ui.") and not ( + k in _conf if "." not in k + else k.split(".")[1] in _conf["inverters"]["fields"])] +check(f"every option field has an en.yaml name (missing: {_no_tr})", not _no_tr) +_no_ui = [k for k in KEYS if k.startswith("ui.") + and k[3:] not in UI_TEXT["fields"]] +check(f"every page-only field has words in ui_text (missing: {_no_ui})", + not _no_ui) +_titles = [g.id for g in L.GROUPS if g.id not in UI_TEXT["groups"]] + [ + f"{g.id}.{p.id}" for g in L.GROUPS for p in g.parts + if p.id and f"{g.id}.{p.id}" not in UI_TEXT["parts"]] +check(f"every group and part has a title (missing: {_titles})", not _titles) +_contract = {"none", "fixed", "daynight", "dynamic", "custom"} +check("every contract, fallback and region the model can hold has words", + set(UI_TEXT["choices"]["contract"]) == _contract + and set(UI_TEXT["choices"]["fallback"]) == _contract - {"dynamic"} + and set(UI_TEXT["choices"]["region"]) + == set(uimodel.REGION_PRESETS) | {uimodel.OWN}) +check("both 'applies' labels have words", + set(UI_TEXT["applies"]) == {L.RESTART, L.NOW}) + +print("\n4. visibility follows the page model") +_m = uimodel.options_to_ui({"meter_source": "ha_signed", "meter_phases": 3, + "inverters": [], "maintenance_enabled": False}) +check("a signed meter shows its net entity, and three phases its net list", + L.visible(L.field("p1_net_entity"), _m) + and L.visible(L.field("p1_phase_net_entities"), _m) + and not L.visible(L.field("meter_entity"), _m) + and not L.visible(L.field("p1_phase_import_entities"), _m)) +check("one inverter shows the one-inverter stops, not the per-inverter ones", + L.visible(L.field("sign_disagree_w"), _m) + and not L.visible(L.field("unit_sign_disagree_w"), _m)) +check("maintenance details hide while maintenance is off", + not L.visible(L.field("maintenance_charge_w"), _m)) + +print("\n5. UI code names option keys in two files only") +_KEY = re.compile(r"""["']([a-z0-9]+(?:_[a-z0-9]+)+)["']""") +_src = io.open(os.path.join(HERE, "app", "uimodel.py"), encoding="utf-8").read() +_owned = set(L.DERIVED) | {"inverters", "price_provider", + "price_taxes_eur_kwh", "arbitrage_enabled"} +_extra = sorted({k for k in _KEY.findall(_src) if k in ORDER} - _owned) +check(f"uimodel.py names only the keys its derivations write (others: " + f"{_extra})", not _extra) +_leak = sorted({f"{name}:{k}" for name in ("haentities.py", "web.py") + for k in _KEY.findall(io.open(os.path.join(HERE, "app", name), + encoding="utf-8").read()) + if k in ORDER}) +check(f"haentities.py and web.py name no option key ({_leak})", not _leak) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_uimodel.py b/goodwe_controller/test_uimodel.py new file mode 100644 index 0000000..1267d62 --- /dev/null +++ b/goodwe_controller/test_uimodel.py @@ -0,0 +1,212 @@ +"""UX-13 P0: stored options <-> page model, exactly. `python3 test_uimodel.py` + +app/uimodel.py derives the keys the page does not show (the flat inverter, +the solar keys, static_profile, the levies figure, arbitrage_enabled). Part 1 +round-trips every options blob the test suite hands the validator +(scenarios/ux13/, recorded by tools/ux13_validator_calls.py at 652097a), the +TEST-23 option files and config.yaml's defaults: options -> model -> JSON -> +options must be identical. Parts 2-6 edit one page field and check the blob. +Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). +""" + +import glob +import gzip +import io +import json +import logging +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +logging.disable(logging.WARNING) # the validator's own log lines + +from app import uimodel as U # noqa: E402 +from app.price import (FLEMISH_TAXES_COMPONENTS_EUR_KWH, # noqa: E402 + PRICE_OPTION_DEFAULTS) +from app.static_tariff import parse_static_profile # noqa: E402 +from app.validate import validate_startup_config # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def trip(options): + return U.ui_to_options(json.loads(json.dumps(U.options_to_ui(options)))) + + +def edit(options, **fields): + model = json.loads(json.dumps(U.options_to_ui(options))) + for k, v in fields.items(): + model[k.replace("__", ".")] = v + return U.ui_to_options(model) + + +def raises(fn): + try: + fn() + except U.DeriveError: + return True + return False + + +def defaults(): + """config.yaml's `options:` block, read without PyYAML (not in CI).""" + text = io.open(os.path.join(HERE, "config.yaml"), encoding="utf-8").read() + block = text[text.index("\noptions:"):text.index("\nschema:")] + out = {} + for key, raw in re.findall(r"^ ([a-z_0-9]+):(.*)$", block, re.M): + raw = raw.split(" #")[0].strip() + try: + out[key] = json.loads(raw) + except ValueError: + out[key] = raw + return out + + +DEFAULTS = defaults() +SITE = dict(DEFAULTS, setpoint_entity="number.goodwe_setpoint", + soc_entity="sensor.soc", batt_entity="sensor.batt") + +print("1. every known blob survives the round trip unchanged") +_calls = [json.loads(line) for line in gzip.open(os.path.join( + HERE, "scenarios", "ux13", "validator-calls-652097a.jsonl.gz"), "rt")] +_test23 = sorted(glob.glob(os.path.join(HERE, "scenarios", "ux13", "test23", + "*.json"))) +_blobs = ([("config.yaml", DEFAULTS)] + + [(c["source"], c["opts"]) for c in _calls + if isinstance(c["opts"], dict)] + + [(os.path.basename(f), json.load(open(f))) for f in _test23]) +_bad = [] +for _src, _o in _blobs: + try: + _back = trip(_o) + except Exception as e: # noqa: BLE001 + _bad.append(f"{_src}: {type(e).__name__} {e}") + continue + if json.dumps(_back, sort_keys=True) != json.dumps(_o, sort_keys=True): + _bad.append(f"{_src}: {sorted(set(_back) ^ set(_o)) or 'values'}") +print(f" {len(_calls)} validator calls, {len(_test23)} TEST-23 files, " + f"config.yaml defaults") +check(f"all {len(_blobs)} are identical after options -> model -> JSON -> " + f"options (not: {_bad[:3]})", not _bad and len(_calls) >= 200 + and len(_test23) >= 5 and len(DEFAULTS) >= 78) +check("config.yaml was read whole: the defaults hold every option", + "inverters" in DEFAULTS and DEFAULTS["inverters"] == [] + and DEFAULTS["price_taxes_eur_kwh"] == 0.11736) +_m = U.options_to_ui(DEFAULTS) +check("the page model never shows a derived key: it keeps them aside", + not {"setpoint_entity", "pv_entity", "pv_entities", "static_profile", + "price_taxes_profile"} & set(_m) + and set(_m["keep"]) >= {"static_profile", "pv_entity", "max_w"}) +check("a blob that lacks keys gains none", trip({"max_w": 900}) == {"max_w": 900}) + +print("\n2. one inverter or a list") +_one = edit(SITE, inverters=[dict(U.options_to_ui(SITE)["inverters"][0], + max_w=1500)]) +check("editing the one inverter writes the flat keys and keeps the list empty", + _one["max_w"] == 1500 and _one["inverters"] == [] + and _one["setpoint_entity"] == "number.goodwe_setpoint") +_card = U.options_to_ui(SITE)["inverters"][0] +_two = edit(SITE, inverters=[ + dict(_card, name="inverter-a", capacity_kwh=None), + dict(_card, name="inverter-b", setpoint_entity="number.goodwe_b", + soc_entity="sensor.soc_b", batt_entity="sensor.batt_b")]) +check("a second inverter writes the list and clears the flat power request " + "entity, which the validator refuses beside a list", + len(_two["inverters"]) == 2 and _two["setpoint_entity"] == "" + and "capacity_kwh" not in _two["inverters"][0] + and not validate_startup_config(_two)) +_listed = dict(SITE, setpoint_entity="", inverters=[ + {"name": "garage", "setpoint_entity": "number.g", "max_w": 2000, + "bms_soc_floor": 10}]) +_l1 = edit(_listed, inverters=[dict(_listed["inverters"][0], max_w=1800)]) +check("a list of one stays a list, so the inverter keeps its name and stored " + "state", _l1["inverters"] == [dict(_listed["inverters"][0], max_w=1800)]) +check("a name on the flat inverter is refused rather than dropped", + raises(lambda: edit(SITE, inverters=[dict(_card, name="garage")]))) +_raw = dict(SITE, inverters="garage") +check("a roster no card can show is kept when another field is saved, and " + "cannot be edited here", + edit(_raw, gain=0.5)["inverters"] == "garage" + and raises(lambda: edit(_raw, inverters=[_card]))) + +print("\n3. solar rows") +check("one row writes pv_entity", + edit(DEFAULTS, ui__solar=[{"entity": "sensor.pv", "reversed": False}]) + ["pv_entity"] == "sensor.pv") +_pv2 = edit(dict(DEFAULTS, pv_entity="sensor.a"), ui__solar=[ + {"entity": "sensor.a", "reversed": False}, + {"entity": "sensor.b", "reversed": True}]) +check("two rows write pv_entities, clear pv_entity and flip the reversed one", + _pv2["pv_entities"] == ["sensor.a", "sensor.b"] and _pv2["pv_entity"] == "" + and _pv2["pv_invert_entities"] == ["sensor.b"]) +_stray = dict(DEFAULTS, pv_entities=["sensor.a", "sensor.b"], + pv_invert_entities=["sensor.b", "sensor.old"]) +_pv1 = edit(_stray, ui__solar=[{"entity": "sensor.a", "reversed": False}]) +check("removing a reversed row drops its flip, and a flip that was never a row " + "stays as stored", _pv1["pv_entities"] == ["sensor.a"] + and _pv1["pv_invert_entities"] == ["sensor.old"]) + +print("\n4. contract and prices") +_fixed = edit(DEFAULTS, ui__contract="fixed", ui__fixed_price=0.31) +check("a fixed price writes a profile the tariff parser reads as one price", + _fixed["price_provider"] == "off" + and [p.eur_per_kwh for p in parse_static_profile( + _fixed["static_profile"]).periods] == [0.31] + and U.options_to_ui(_fixed)["ui.contract"] == "fixed") +_dn = edit(SITE, ui__contract="daynight", ui__day_price=0.34, + ui__night_price=0.26) +check("day and night write a profile that starts and reads back the same", + not validate_startup_config(_dn) + and U.options_to_ui(_dn)["ui.day_price"] == 0.34 + and U.options_to_ui(_dn)["ui.night_price"] == 0.26) +_dyn = edit(_dn, ui__contract="dynamic", price_provider="generic_dayahead") +check("a dynamic contract keeps the day and night profile as its fallback", + _dyn["price_provider"] == "generic_dayahead" + and _dyn["static_profile"] == _dn["static_profile"]) +check("a dynamic contract without a price source is refused here", + raises(lambda: edit(DEFAULTS, ui__contract="dynamic"))) +_odd = json.dumps({"periods": [ + {"from": "00:00", "to": "12:00", "days": "mon-sun", "eur_per_kwh": 0.2}, + {"from": "12:00", "to": "24:00", "days": "mon-sun", "eur_per_kwh": 0.3}]}) +_om = U.options_to_ui(dict(DEFAULTS, static_profile=_odd)) +check("odd windows show as 'custom' and survive saving another field", + _om["ui.contract"] == "custom" + and edit(dict(DEFAULTS, static_profile=_odd), gain=0.5) + ["static_profile"] == _odd) + +print("\n5. region presets") +_fl = U.REGION_PRESETS["flanders"] +check("the Flanders preset is the sum of app/price.py's components, and is the " + "shipped default", _fl["taxes_eur_kwh"] == round(sum( + v for _n, v in FLEMISH_TAXES_COMPONENTS_EUR_KWH), 5) + == PRICE_OPTION_DEFAULTS["price_taxes_eur_kwh"] == DEFAULTS[ + "price_taxes_eur_kwh"]) +check("every preset carries its year", all( + isinstance(p["year"], int) and p["year"] >= 2026 + for p in U.REGION_PRESETS.values())) +_own = dict(DEFAULTS, price_taxes_eur_kwh=0.06) +check("a figure that is no preset reads as 'own', and choosing Flanders " + "writes the preset", U.options_to_ui(_own)["ui.region"] == U.OWN + and edit(_own, ui__region="flanders")["price_taxes_eur_kwh"] == 0.11736) +check("'own' stores the typed figure", + edit(DEFAULTS, ui__region=U.OWN, price_taxes_eur_kwh=0.13) + ["price_taxes_eur_kwh"] == 0.13) + +print("\n6. arbitrage_enabled: the OPT-11 hook changes nothing yet") +check("the hook answers None while battery modes do not exist", + U.arbitrage_from_batteries(U.options_to_ui(DEFAULTS)) is None) +check("so the toggle is stored as the page has it", + edit(DEFAULTS, arbitrage_enabled=True)["arbitrage_enabled"] is True) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_validate.py b/goodwe_controller/test_validate.py index 853bff5..ea9c5df 100644 --- a/goodwe_controller/test_validate.py +++ b/goodwe_controller/test_validate.py @@ -1808,6 +1808,47 @@ check("an UNREADABLE shadow_mode resolves to SHADOW, not to live - the " and shadow.engaged({"shadow_mode": ""}, control_started=True) is True and shadow.mode({"shadow_mode": "garbage"}) == "on") +# --------------------------------------------------------------------------- # +print("\nUX-13 - the warning tier: notes for the settings page, never refusals") +from app.validate import Note, WATT_ENTITY_KEYS, config_notes # noqa: E402 + +_warned = base(integrator_max_w=3000, maintenance_discharge_w=2500, + price_provider="generic_dayahead", static_profile="") +_notes = [] +_with = validate_startup_config(_warned, -5000, 5000, notes=_notes) +check("a config with three logged warnings starts, and gives three notes, " + "each filed under the setting it names", + _with == [] and validate_startup_config(_warned, -5000, 5000) == [] + and sorted(n.keys for n in _notes) == [ + ("integrator_max_w",), ("maintenance_discharge_w",), + ("static_profile",)] + and all(n.tier == "warn" and f"({n.keys[0]})" in n.text for n in _notes)) +_refused = base(setpoint_entity="", integrator_max_w=3000) +_n2 = [] +check("collecting notes changes no refusal", + validate_startup_config(_refused, notes=_n2) + == validate_startup_config(_refused) != [] and len(_n2) == 1) +_rows = {"number.goodwe_setpoint": {"unit": None}, + "sensor.soc": {"unit": "%"}, "sensor.batt": {"unit": "kW"}} +_cn = config_notes(base(), entities=_rows) +check("a battery power sensor in kW is warned about: the add-on takes it as " + "watts", [n.keys for n in _cn] == [("batt_entity",)] + and "kW" in _cn[0].text) +_cn = config_notes(base(meter_entity="sensor.grid"), entities={}) +check("an entity Home Assistant does not have is named, and only the ones " + "this meter source and roster shape read", + sorted(n.keys[0] for n in _cn) == ["batt_entity", "meter_entity", + "setpoint_entity", "soc_entity"]) +check("with no entity list (Home Assistant down) those checks are skipped", + config_notes(base(), entities=None) == []) +check("a peak limit below this month's peak is warned about", + [n.keys for n in config_notes(base(peak_cap_w=2500), + month_peak_w=2900)] == [("peak_cap_w",)] + and config_notes(base(peak_cap_w=3500), month_peak_w=2900) == []) +check("pv.py converts solar units itself, so no solar key is read as watts", + not [k for k in WATT_ENTITY_KEYS if k.startswith("pv_")] + and isinstance(_cn[0], Note)) + # --------------------------------------------------------------------------- # print() if fails: diff --git a/goodwe_controller/tools/ux13_validator_calls.py b/goodwe_controller/tools/ux13_validator_calls.py new file mode 100644 index 0000000..bcd75d1 --- /dev/null +++ b/goodwe_controller/tools/ux13_validator_calls.py @@ -0,0 +1,106 @@ +"""UX-13: record every `validate_startup_config()` call the test suite makes, +and compare two validators over those calls. + + python3 tools/ux13_validator_calls.py record OUT.jsonl.gz + python3 tools/ux13_validator_calls.py compare OLD_APP_PARENT OUT.jsonl.gz + +`record` runs each test_*.py with the validator wrapped (in this directory, so +run it where the suite runs: the CI image). `compare` runs the recorded calls +through the validator under OLD_APP_PARENT (a directory holding an `app/`, +e.g. from `git archive <base> goodwe_controller/app`) and through this tree's, +and prints every call whose refusals differ. P0 of UX-13 used it to show that +adding the warning tier changed no refusal. scenarios/ux13/ holds the record +test_uimodel.py round-trips. +""" + +import gzip +import json +import os +import subprocess +import sys + +HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +_WRAP = r""" +import json, runpy, sys +sys.path.insert(0, ".") +from app import validate +real = validate.validate_startup_config +out = open(sys.argv[1], "a") +def rec(opts, dev_min=None, dev_max=None, *a, **kw): + try: + out.write(json.dumps({"opts": opts, "dev_min": dev_min, + "dev_max": dev_max}) + "\n") + except (TypeError, ValueError): + pass + return real(opts, dev_min, dev_max, *a, **kw) +validate.validate_startup_config = rec +sys.argv = sys.argv[2:] +try: + runpy.run_path(sys.argv[0], run_name="__main__") +except SystemExit: + pass +""" + + +def record(out_path): + tmp = out_path + ".part" + open(tmp, "w").close() + rows, seen = [], set() + for name in sorted(f for f in os.listdir(HERE) + if f.startswith("test_") and f.endswith(".py")): + before = sum(1 for _ in open(tmp)) + subprocess.run([sys.executable, "-B", "-c", _WRAP, tmp, name], + cwd=HERE, stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + with open(tmp) as fh: + for line in list(fh)[before:]: + call = json.loads(line) + key = json.dumps(call, sort_keys=True) + if key not in seen: + seen.add(key) + rows.append(dict(call, source=name)) + os.remove(tmp) + with gzip.open(out_path, "wt") as fh: + for row in rows: + fh.write(json.dumps(row, sort_keys=True) + "\n") + print(f"{len(rows)} distinct validator calls -> {out_path}") + + +def _run(app_parent, path): + code = r""" +import gzip, json, logging, sys +logging.disable(logging.CRITICAL) +sys.path.insert(0, sys.argv[1]) +from app.validate import validate_startup_config as v +out = [] +for line in gzip.open(sys.argv[2], "rt"): + c = json.loads(line) + try: + out.append(v(c["opts"], c["dev_min"], c["dev_max"])) + except Exception as e: + out.append("raised " + type(e).__name__) +print(json.dumps(out)) +""" + got = subprocess.run([sys.executable, "-B", "-c", code, app_parent, path], + capture_output=True, text=True, check=True) + return json.loads(got.stdout) + + +def compare(old_parent, path): + old, new = _run(old_parent, path), _run(HERE, path) + differ = [i for i, (a, b) in enumerate(zip(old, new)) if a != b] + print(f"{len(old)} calls, {sum(1 for r in old if r)} refused by the old " + f"validator, {len(differ)} with different refusals") + for i in differ: + print(f" call {i}:\n old {old[i]}\n new {new[i]}") + return 1 if differ else 0 + + +if __name__ == "__main__": + if len(sys.argv) == 3 and sys.argv[1] == "record": + record(sys.argv[2]) + elif len(sys.argv) == 4 and sys.argv[1] == "compare": + sys.exit(compare(sys.argv[2], sys.argv[3])) + else: + sys.exit(__doc__) -- 2.54.0 From badea3cb2d7a396a5bf7e1ea8eab90b600d77bb6 Mon Sep 17 00:00:00 2001 From: goodwe-review <gschrooyen@gmail.com> Date: Sun, 27 Sep 2026 23:39:43 +0200 Subject: [PATCH 050/105] UX-13 P0 review: keep unread keys, back off a failed entity read - uimodel: editing a listed inverter keeps the stored flat keys, and a region of "own" keeps a stored price_taxes_profile (both were dropped). - haentities: a failed read also waits CACHE_S, so polls while Home Assistant is down do not queue one 10 s read each. - ui_text: the Flanders preset names its DSO, and the help says Wallonia and Brussels have no figures yet. REGION_PRESETS cites the card. - tests: decode of a reversed solar row, both kept keys, the backoff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/app/haentities.py | 6 +++++- goodwe_controller/app/ui_text/en.json | 4 ++-- goodwe_controller/app/uimodel.py | 11 ++++++++--- goodwe_controller/test_haentities.py | 18 ++++++++++++++++++ goodwe_controller/test_uimodel.py | 12 ++++++++++++ 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/goodwe_controller/app/haentities.py b/goodwe_controller/app/haentities.py index d6f0784..695ef6f 100644 --- a/goodwe_controller/app/haentities.py +++ b/goodwe_controller/app/haentities.py @@ -51,13 +51,17 @@ class EntityCache: self.clock = clock self.rows: dict | None = None self.read_at: float | None = None + self.tried_at: float | None = None self._lock = asyncio.Lock() async def get(self) -> tuple[dict | None, float | None]: """(rows by entity id, age in s), or (None, None) if never read.""" async with self._lock: # one HA read however many pickers ask now = self.clock() - if self.read_at is None or now - self.read_at >= CACHE_S: + # A failed read also waits CACHE_S, so polls while HA is down do + # not queue one 10 s read each behind this lock. + if self.tried_at is None or now - self.tried_at >= CACHE_S: + self.tried_at = now states = await self.hass.states() if states is not None: rows = (row(s) for s in states) diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index d3244fb..dd39981 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -20,7 +20,7 @@ "fields": { "solar": {"name": "Solar inverters", "description": "Each solar inverter's power sensor, which the add-on records but does not use for control."}, "contract": {"name": "Your contract", "description": "How your supplier prices each kWh you take from the grid."}, - "region": {"name": "Region", "description": "Fills in the grid costs, levies and VAT for the year shown, so check them on your bill."}, + "region": {"name": "Region", "description": "Fills in grid costs, levies and VAT for the year shown, but not yet for Wallonia or Brussels, so check your bill."}, "fallback": {"name": "Price when the feed is down", "description": "Used when the price source does not answer."}, "fixed_price": {"name": "Price per kWh, all in", "description": "Energy, supplier costs, grid costs, levies and VAT together."}, "day_price": {"name": "Day price, weekdays 07:00 to 22:00", "description": "All in, as on your bill."}, @@ -29,7 +29,7 @@ "choices": { "contract": {"none": "No prices", "fixed": "Fixed price", "daynight": "Day and night", "dynamic": "Dynamic, hourly", "custom": "Other time windows"}, "fallback": {"none": "None", "fixed": "One price", "daynight": "Day and night", "custom": "Other time windows"}, - "region": {"flanders": "Flanders", "own": "I enter my own figure"} + "region": {"flanders": "Flanders, Fluvius Antwerpen", "own": "I enter my own figure"} }, "applies": { "restart": {"name": "Applies after a restart"}, diff --git a/goodwe_controller/app/uimodel.py b/goodwe_controller/app/uimodel.py index f5f9c5a..fddf36e 100644 --- a/goodwe_controller/app/uimodel.py +++ b/goodwe_controller/app/uimodel.py @@ -31,7 +31,8 @@ class DeriveError(ValueError): # --------------------------------------------------------------------------- # # Region presets for "Grid costs, levies and VAT". Year-stamped, updated each # January (owner, 2026-09-27). Only presets with a sourced figure are listed: -# Flanders is app/price.py's Fluvius Antwerpen sum (TARIFF-18). Wallonia and +# Flanders is app/price.py's Fluvius Antwerpen sum (TARIFF-18: Eneco +# residential card, Flanders, September 2026, VAT included). Wallonia and # Brussels have a day and a night band (config.yaml) and join with sourced # figures; until then those sites choose "own". # --------------------------------------------------------------------------- # @@ -93,9 +94,10 @@ def _roster_encode(m, keep): return out out["inverters"] = [{k: v for k, v in c.items() if v is not None} for c in cards] + # The flat keys beside a list are not read: they stay as stored. + out.update({k: copy.deepcopy(keep[k]) for k in _ROSTER_FLAT if k in keep}) if shape == "flat": # CFG-04 rule 9e: a flat power request entity beside a list is refused. - # The other flat keys stay as stored and are not read. out["setpoint_entity"] = "" return out @@ -252,7 +254,10 @@ def _region_decode(o): def _region_encode(m, keep): region = m.get("ui.region") if region == OWN: - return {"price_taxes_eur_kwh": m.get("price_taxes_eur_kwh")} + out = {"price_taxes_eur_kwh": m.get("price_taxes_eur_kwh")} + if "price_taxes_profile" in keep: # "own" keeps the stored table + out["price_taxes_profile"] = keep["price_taxes_profile"] + return out if region not in REGION_PRESETS: raise DeriveError(f"unknown region {region!r}") p = REGION_PRESETS[region] diff --git a/goodwe_controller/test_haentities.py b/goodwe_controller/test_haentities.py index a562b97..30ffb81 100644 --- a/goodwe_controller/test_haentities.py +++ b/goodwe_controller/test_haentities.py @@ -161,6 +161,24 @@ check("Home Assistant down after a good read: the old list, marked old", and len(_down["entities"]) == 4 and _down["age_s"] >= 30) check("...and peek() then gives nothing, so no warning rests on an old list", _cache.peek() is None) + + +async def down_windows(): + """One loop throughout: a contended asyncio.Lock binds to its loop.""" + hass, clock = FakeHass(), Clock() + hass.answer = None + cache = E.EntityCache(hass, clock=clock) + counts = [] + for step in (0, 1, 30): + clock.t += step + await asyncio.gather(*(cache.payload() for _ in range(5))) + counts.append(hass.reads) + return counts + + +check("five polls while Home Assistant is down cost one read, the polls just " + "after wait for the next window, and that window tries once", + asyncio.run(down_windows()) == [1, 1, 2]) _h2 = FakeHass() _h2.answer = None _empty = asyncio.run(E.EntityCache(_h2).payload("power")) diff --git a/goodwe_controller/test_uimodel.py b/goodwe_controller/test_uimodel.py index 1267d62..62702d0 100644 --- a/goodwe_controller/test_uimodel.py +++ b/goodwe_controller/test_uimodel.py @@ -128,6 +128,9 @@ _listed = dict(SITE, setpoint_entity="", inverters=[ _l1 = edit(_listed, inverters=[dict(_listed["inverters"][0], max_w=1800)]) check("a list of one stays a list, so the inverter keeps its name and stored " "state", _l1["inverters"] == [dict(_listed["inverters"][0], max_w=1800)]) +check("editing a listed inverter keeps the unread flat keys as stored", + all(_l1[k] == _listed[k] for k in ("setpoint_entity", "soc_entity", + "batt_entity", "max_w"))) check("a name on the flat inverter is refused rather than dropped", raises(lambda: edit(SITE, inverters=[dict(_card, name="garage")]))) _raw = dict(SITE, inverters="garage") @@ -137,6 +140,10 @@ check("a roster no card can show is kept when another field is saved, and " and raises(lambda: edit(_raw, inverters=[_card]))) print("\n3. solar rows") +check("a stored flip reads as a reversed row", + U.options_to_ui(dict(DEFAULTS, pv_entity="sensor.pv", + pv_invert_entities=["sensor.pv"]))["ui.solar"] + == [{"entity": "sensor.pv", "reversed": True}]) check("one row writes pv_entity", edit(DEFAULTS, ui__solar=[{"entity": "sensor.pv", "reversed": False}]) ["pv_entity"] == "sensor.pv") @@ -195,6 +202,11 @@ _own = dict(DEFAULTS, price_taxes_eur_kwh=0.06) check("a figure that is no preset reads as 'own', and choosing Flanders " "writes the preset", U.options_to_ui(_own)["ui.region"] == U.OWN and edit(_own, ui__region="flanders")["price_taxes_eur_kwh"] == 0.11736) +_prof = dict(DEFAULTS, price_taxes_eur_kwh=0.12, + price_taxes_profile='{"day": 0.14, "night": 0.1}') +check("'own' keeps a stored levies table when the figure is edited", + edit(_prof, price_taxes_eur_kwh=0.13)["price_taxes_profile"] + == _prof["price_taxes_profile"]) check("'own' stores the typed figure", edit(DEFAULTS, ui__region=U.OWN, price_taxes_eur_kwh=0.13) ["price_taxes_eur_kwh"] == 0.13) -- 2.54.0 From 016ed5a5a3e26ced9bc7405001c8fd1adadc2a81 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Mon, 28 Sep 2026 00:13:26 +0200 Subject: [PATCH 051/105] SAFETY-73: a battery that refuses, per inverter, with two or more SAFETY-52's hold applied per unit at N>1 (owner, 2026-09-27, option R). A unit that gives < 100 W for 12 cycles in one direction while asked > 200 W, or trips its stale-reading gate on a ~0 W reading, gets a P_SAFETY `refused` unit limit closing that direction, so the allocator hands its share to the others within their own limits. Probe: a +-200 W pin every 15 min, one unit at a time, only while the site asks 200 W that way. All units refusing: the site law holds 0 W. Exits reseed the site target from the wire. INFO plus one WARNING (REFUSES_ABOVE_CUT_OUT) above the configured cut-out; SAFETY-42/43 no longer report a refusing unit. N=1 unchanged. test_refusal_units.py: cases a/b/c on flat and jitter registers against the old behaviour, probes, recovery, exits; mutations U1-U13 all red. TEST-19 no-fault campaign: 0 engagements in 5280 runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../SAFETY-73-refusal-per-inverter.md | 89 ++++ goodwe_controller/DOCS.md | 26 +- goodwe_controller/app/arbiter.py | 6 + goodwe_controller/app/inverter.py | 17 + goodwe_controller/app/main.py | 198 +++++++- goodwe_controller/app/messages.py | 19 + goodwe_controller/test_arbiter.py | 12 +- goodwe_controller/test_delivery.py | 32 +- goodwe_controller/test_peakguard.py | 28 +- goodwe_controller/test_refusal_units.py | 480 ++++++++++++++++++ 10 files changed, 867 insertions(+), 40 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md create mode 100644 goodwe_controller/test_refusal_units.py diff --git a/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md b/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md new file mode 100644 index 0000000..c30a334 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md @@ -0,0 +1,89 @@ +# SAFETY-73 - a battery that refuses, with two or more inverters + +**Decided 2026-09-27 by the owner, on the phase A plan (option R). All four +new questions answered yes. SAFETY-52's four decisions carry over.** + +## The defect + +SAFETY-52 held a refusing battery at 0 W at one inverter only. At N>1 +(`main.py` passed `refused=None`) nothing closed a unit that gives ~0 W while +its state of charge reads above its configured cut-out, so the allocator kept +handing it its weighted half. Measured on the real `Controller`, two units, +house 3000 W, A cut out: + +| register | law | B gives | grid | A's gate trips / h | +|---|---|---|---|---| +| flat -4 W | old | 533 W | +2471 W | 46 (each stops the whole site) | +| flat -4 W | new | 2000 W (its rating) | +1004 W | 1 | +| jitter | old | 1910 W | +1094 W | 0 | +| jitter | new | 2000 W | +1004 W | 0 | + +House 1200 W, which B alone carries: old +671 W (flat) and +284 W (jitter) +standing import, new -16 W. Both cut out: old keeps asking two empty batteries +(+1910 W each on the jitter shape), new holds the site at 0 W. + +## What was decided + +1. **A refusing unit is closed in that direction** by its own P_SAFETY unit + claim, source `refused`. It engages when the unit gives under + `REFUSED_BELOW_W` (100 W) for `SETTLE_CYCLES` (12) cycles in one direction + while asked more than `PROBE_W` (200 W), or when its stale-reading gate + trips on a held reading under 100 W. The allocator then hands its share to + the others within their own limits (owner decision 1). It is a hard unit + limit that always intersects, so OPT-11's P_MODE layer fits inside it. +2. **It binds every strategy's ask on that unit** (decision 2): peak guard, + arbitrage and maintenance are placed around it like the loop. +3. **A refusal above the configured cut-out** logs INFO plus one WARNING ending + in `REFUSES_ABOVE_CUT_OUT` (decision 3). SAFETY-42/43 no longer report such a + unit: its share is 0 W, and `account()` treats it as parked. +4. **All units refusing the same way** pass that sign to `compute()`, so the + site holds 0 W with SAFETY-52's law (decision 4). Probes go one unit at a + time. +5. **Probe:** every 15 min for 34 s the claim becomes a pin at +-200 W and the + others carry the rest. The pin stands only while the resolved site target + asks at least 200 W its way; otherwise it would make a sibling take the + opposite direction, so it falls back to the closed limit for that cycle. +6. **Exits:** a reading of 100 W or more in the held direction (probe or not); + 100 W or more taken the other way for 12 cycles (charge at the floor; one + cycle of the loop overshooting through zero is not enough); stop or start. + On every exit the site target and integrator restart from the watts on the + wire, or the reopened unit is handed a parked remainder at once. + +**Why 200 W and not `saturation_w`.** A unit's share is often small: a 400 W +night load split two ways asks 200 W of each. With 500 W the empty battery +kept a phantom share that SAFETY-43's relative arm then reported as not +delivering, the ERROR decision 3 replaces. Shares of 200 W or less that give +under 100 W are "too small to call" in `account()`: the sibling covers the +meter and nothing is asked of the empty battery that matters. + +**Why one direction throughout.** On TEST-19's flapping family a command that +swaps sign each cycle reads ~0 through the plant's lag: 42 engagements in 21 +no-fault runs without the rule, 0 with it. + +**N=1 is unchanged.** Every SAFETY-73 path is gated on `len(inverters) > 1`. +`test_refusal_units.py` part 6 runs SAFETY-52's whole suite with every +SAFETY-73 method made to raise. + +## Evidence + +- `test_refusal_units.py`: cases a, b and c on both register shapes against + the old behaviour, probes and their spacing, one-at-a-time probing, the + recovery reseed, each exit, the small-ask and small-site-target cases, the + WARNING, the status row and shadow mode. Mutations U1-U13 in its docstring. +- **No false engagements.** TEST-19's no-fault campaign (admin/goodwe + `sim/delivery_window.py` families, 2640 runs at N=2 and 2640 at N=1, every + unit executing its share) graded with the engage clause: 0 engagements, the + longest qualifying streak 5 cycles against 12. The grader is + `goodwe-session/scratch_s73/s73_nofault.py`. +- **Recovery.** Case a, A recovering into a house that fell below the parked + target: worst grid +0 W with the reseed. Phase A measured -1059 W without the + reseed and the site hold. + +## Not covered + +- A unit that gives a steady part of its ask (100 W or more) is a limit, as at + N=1. SAFETY-42/43 still report it. +- `pack_permissions` stays SoC-based, so the peak guard may size a shave with a + refusing battery counted. The shortfall shows as `unmet_w`. +- A wedged unit (HW-01) reading ~0 W is now shown as a refusal, not reported as + not delivering. Its share still moves, which is the gain SAFETY-42 measured. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 192f9af..28a58f7 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -295,7 +295,7 @@ When the add-on refuses to start, each reason names the setting by its label and - **Stuck meter alarm after** (`meter_freeze_s`): measured, not chosen (SAFETY-18). Over 2399 s of this house at its operating point, the longest run without a new reading is 15.4 s, and 300 s is 19.5 times that. It raises an alarm only and does not set 0 W. - **Opposing inverters threshold** (`circulation_w`): measured on 924 closed-loop test runs (SAFETY-31). The worst legitimate opposition drops from 505 s at 100 W to 5 s at 400 W, the lowest value accepted. 700 W is 1.75 times that knee, with margin because the second inverter is still a copy of the first. - **Opposing inverters time** (`circulation_hold_s`): derived (SAFETY-31). 75 s is fifteen control cycles, 15 times the worst legitimate episode, and 2.5 times the control board's 30 s link limit. -- **Not delivering alarm after** (`delivery_hold_s`): two or more inverters only. It reports only (SAFETY-42): nothing is commanded differently. Derived from 2640 closed-loop test runs with nothing faulty. The worst legitimate episode is 35.0 s and 185 s is 5.29 times that. The schema allows 30 s, below that, so expect false reports there. A battery at or below its own cut-out level is never reported. Re-derive with admin/goodwe `sim/delivery_window.py --campaign --blag`. +- **Not delivering alarm after** (`delivery_hold_s`): two or more inverters only. It reports only (SAFETY-42): nothing is commanded differently. Derived from 2640 closed-loop test runs with nothing faulty. The worst legitimate episode is 35.0 s and 185 s is 5.29 times that. The schema allows 30 s, below that, so expect false reports there. A battery at or below its own cut-out level is never reported, and neither is one that gives under 100 W (SAFETY-73: it is a battery that refuses). Re-derive with admin/goodwe `sim/delivery_window.py --campaign --blag`. - **Shadow mode** (`shadow_mode`): the whole decision path runs and nothing reaches the inverter. The status page and action log show what would have been sent. A safety stop that is already up stays up. See [Shadow mode](#shadow-mode-shadow_mode). - **Control gain** (`gain`): measured on real hardware and already at the limit. - **Largest change per cycle** (`slew_w`): 0 means follow the rating: about a ninth of it, derived (SAFETY-39) from a measured ~18 s step response against a 2 s meter tick. A fixed value faster than the rating allows is refused. At 1000 W against a 5000 W rating control swung the meter from 3.4 kW export to 2.8 kW import on 2026-09-05. @@ -550,15 +550,23 @@ control is stopped or started. 200 W is below the 250 W the stale-reading check needs, so a test never trips it. A battery that gives some power, even 100 W, is not refusing and keeps its request. -⚠️ **One inverter only.** With several inverters this hold is off. There, the -battery level limit moves an empty battery's share to the others, but only if -its “Battery cut-out level” matches where the battery really stops. A battery -that refuses at another level, or for another reason (cold, a battery fault), -can still hold its last request until the grid starts to export. +**With two or more inverters** the same rule works per inverter. An inverter +whose battery gives less than 100 W for 12 cycles while asked for more than +200 W is asked 0 W, and the other inverters take over its share, each up to +its own limits. The status page names it: *inverter-a: the battery refuses to +give power, the others take over*. It is tested at 200 W every 15 minutes, one +inverter at a time, and only while the site asks at least 200 W that way. +It still accepts charge, and a minute of charging ends the refusal. When every +inverter refuses the same way, the whole site asks 0 W as with one inverter. +If the battery refuses while its level reads above its “Battery cut-out level”, +the log adds one warning ending in `REFUSES_ABOVE_CUT_OUT`: check that setting. +A battery that refuses is not reported as *not delivering*. -*For installers:* SAFETY-52. The event log reads `BATTERY REFUSES …` and -`BATTERY REFUSES ENDED: …`, and the INFO line ends in `BATTERY_REFUSES`. -`DECISIONS/SAFETY-52-a-battery-that-refuses.md` has the replay figures. +*For installers:* SAFETY-52 and SAFETY-73. The event log reads +`BATTERY REFUSES …` and `BATTERY REFUSES ENDED …` (with the inverter's name at +N>1), and the INFO line ends in `BATTERY_REFUSES`. +`DECISIONS/SAFETY-52-a-battery-that-refuses.md` has the replay figures and +`DECISIONS/SAFETY-73-refusal-per-inverter.md` the two-inverter ones. ⚠️ **`Loop reason` is not the `Why` row on the status page, and the two will often disagree.** `Why` is the *arbiter's* answer in words — *Keeping the grid diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 2ecfc36..ab5b36d 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -226,6 +226,12 @@ CLAIM_SCOPE = { # reaches the allocator, so a unit-scoped claim is the shape that sentence # asks for rather than an evasion of it. "pack": SCOPE_UNIT, + # main.py: `Claim.limit("refused", P_SAFETY, ...)` and, during a probe, + # `Claim.set("refused", P_SAFETY, +-PROBE_W)`. SAFETY-73: THIS battery gives + # nothing in one direction, measured on THIS unit's own reading. A hard unit + # limit that always intersects, so the share goes to the siblings. Filed at + # N>1 only; at N=1 SAFETY-52's law in compute() does the same job. + "refused": SCOPE_UNIT, # main.py: `Claim.set("maintenance", P_MAINTENANCE, ...)` when the cycle owns # the setpoint, and `Claim.limit("maintenance", P_MAINT_SHAPE, hi=...)` when # it only shapes. §12's monthly recalibration is a PACK procedure - drain diff --git a/goodwe_controller/app/inverter.py b/goodwe_controller/app/inverter.py index 3e5923b..c5370ef 100644 --- a/goodwe_controller/app/inverter.py +++ b/goodwe_controller/app/inverter.py @@ -317,6 +317,16 @@ class Inverter: tripped=bool(data.get(self.key("delivery_tripped"), False)), reason=str(data.get(self.key("delivery_reason"), "") or "")) + # SAFETY-73. The direction this unit's battery refuses (+1 give, -1 + # take, 0 none), when that refusal or its last probe started, the + # current probe's start, and the cycles of evidence so far. Memory + # only, like SAFETY-52's: stop and start end it. Used at N>1 only. + self.refused = 0 + self.refused_at = None + self.probe_from = None + self.ref_count = 0 + self.ref_sign = 0 + # -- store --------------------------------------------------------------- def key(self, name: str) -> str: """This unit's namespaced Store key for `name`. See store.unit_key().""" @@ -411,6 +421,13 @@ class Inverter: return (messages.row_battery_stuck(self.name) if self.batt_fresh.stale else "") + def refusal_note(self) -> str: + """SAFETY-73's status row while this unit's battery refuses.""" + if not self.refused: + return "" + return messages.row_battery_refuses(self.name, self.refused, + self.probe_from is not None) + def link_note(self, now: datetime) -> str: """One line for the status page. Empty when there is nothing to say. diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 03a008f..40845d1 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -28,6 +28,7 @@ import contextlib import functools import json import logging +import math import signal import time from datetime import datetime, timedelta, timezone @@ -234,6 +235,11 @@ def pack_energy_of(inv): inv.capacity_kwh, inv.max_w) +def _refused_interval(sign: int) -> tuple: + """SAFETY-73: the (lo, hi) a refusing unit may be asked: 0 W that way.""" + return (-math.inf, 0.0) if sign > 0 else (0.0, math.inf) + + def why_key(winner: str, claims) -> str: """The key of `messages.WHY_WINNER` for a resolution's winner. @@ -1121,6 +1127,19 @@ class Controller: """ t = self.tuning standing = inv.standing_w() + if len(self.inverters) > 1: + # SAFETY-73: at N>1 the same trip refuses THIS unit only. + if ((self.auto or self.shadow) and not inv.refused + and inv.ref_count >= t.saturation_cycles + and inv.batt_fresh.held is not None + and abs(inv.batt_fresh.held) < _ctl.REFUSED_BELOW_W + and abs(standing) > _ctl.PROBE_W): + self._now_mono = now_mono + self._unit_refusal_start( + inv, 1 if standing > 0 else -1, + f"stale reading {inv.batt_fresh.held:+.0f} W while asked " + f"{standing:+.0f} W") + return if (len(self.inverters) == 1 and (self.auto or self.shadow) and not self.batt_refused and self.sat_count >= t.saturation_cycles @@ -1132,6 +1151,111 @@ class Controller: f"stale reading {inv.batt_fresh.held:+.0f} W " f"while asked {standing:+.0f} W") + # --- SAFETY-73: the same refusal, per inverter, at N>1 ------------------- + # SAFETY-52's decisions applied to one unit of several: a unit that gives + # < REFUSED_BELOW_W for SETTLE_CYCLES while asked > PROBE_W is closed in + # that direction by a P_SAFETY unit limit, so the allocator hands its share + # to the others; it is probed at PROBE_W every PROBE_EVERY_S, one unit at a + # time. The ask is PROBE_W, not `saturation_w`: a unit's share is often + # small (a 400 W night load split two ways) and SAFETY-43 would otherwise + # name the empty battery as not delivering. DECISIONS/SAFETY-73. + def _unit_refusal_start(self, inv, sign: int, evidence: str) -> None: + inv.refused, inv.refused_at = sign, self._now_mono + inv.probe_from, inv.ref_count = None, 0 + self.log_event(f"BATTERY REFUSES {inv.name}: {evidence}", + hint=messages.hint("unit_refuses", unit=inv.name)) + _LOG.info("%s: the battery refuses power, so it is asked 0 W and the " + "other inverters take over: BATTERY_REFUSES.", inv.name) + _LOG.debug("Evidence for %s: BATTERY_REFUSES: %s.", inv.name, evidence) + if (inv.soc is not None and inv.bms_soc_floor is not None + and float(inv.soc) > float(inv.bms_soc_floor)): + # Owner decision 3: a refusal above the configured cut-out level + # may mean that level is set wrong. One line, no safety stop. + _LOG.warning("%s refuses power above its battery cut-out level, " + "check its cut-out level: REFUSES_ABOVE_CUT_OUT.", + inv.name) + _LOG.debug("Evidence for %s: REFUSES_ABOVE_CUT_OUT: battery level " + "%.0f %%, cut-out level %.0f %%.", inv.name, + float(inv.soc), float(inv.bms_soc_floor)) + + def _unit_refusal_end(self, inv, why: str) -> None: + if not inv.refused: + return + inv.refused, inv.refused_at, inv.probe_from = 0, None, None + inv.ref_count = 0 + self.log_event(f"BATTERY REFUSES ENDED {inv.name}: {why}", + hint=messages.hint("unit_gives", unit=inv.name)) + _LOG.info("%s: the battery refusal ends, it is asked for power again: " + "%s.", inv.name, why) + # The site target may stand above what was placed (the refused share + # was unmet). Restart it from the watts on the wire, or the reopened + # unit is handed the parked remainder at once (phase A: -1059 W). + placed = float(sum(i.standing_w() for i in self.inverters)) + self.target = self.i_w = placed + self.sat_count = 0 + + def _unit_probe(self, inv) -> bool: + """True while `inv` may try PROBE_W. One unit probes at a time.""" + now = self._now_mono + if not inv.refused or inv.refused_at is None or now is None: + return False + if inv.probe_from is not None: + if now - inv.probe_from < _ctl.PROBE_S: + return True + inv.probe_from, inv.refused_at = None, now + return False + if now - inv.refused_at < _ctl.PROBE_EVERY_S or any( + i.probe_from is not None for i in self.inverters): + return False + inv.probe_from = now + return True + + def _unit_refusals(self) -> None: + """Engage and end each unit's refusal from its own reading.""" + for inv in self.inverters: + b = inv.batt + if inv.refused: + if b is not None and inv.refused * b >= _ctl.PROBE_ANSWER_W: + self._unit_refusal_end( + inv, "the probe was answered" + if inv.probe_from is not None + else "the battery gives power") + continue + # The other direction: the battery takes PROBE_ANSWER_W or more + # the other way (charge at the floor) for SETTLE_CYCLES. Counted + # on its own reading, so one cycle of the loop overshooting + # through zero does not hand it its share back. + inv.ref_count = (inv.ref_count + 1 if b is not None and + -inv.refused * b >= _ctl.PROBE_ANSWER_W else 0) + if inv.ref_count >= _ctl.SETTLE_CYCLES: + self._unit_refusal_end( + inv, "the battery takes power the other way") + continue + if b is None: + continue # a gap keeps the count: the gate's trip seeds + standing = inv.standing_w() + sign = 1 if standing > 0 else -1 + # One direction throughout: a command that swaps sign every cycle + # (a flapping load) reads ~0 through the plant's own lag, and that + # is a battery following, not refusing (TEST-19 flapping family). + if abs(standing) > _ctl.PROBE_W and abs(b) < _ctl.REFUSED_BELOW_W: + inv.ref_count = (min(inv.ref_count + 1, _ctl.SETTLE_CYCLES) + if sign == inv.ref_sign else 1) + else: + inv.ref_count = 0 + inv.ref_sign = sign + if inv.ref_count >= _ctl.SETTLE_CYCLES: + self._unit_refusal_start( + inv, sign, + f"asked {standing:+.0f} W, the battery gave {b:+.0f} W " + f"for {_ctl.SETTLE_CYCLES} cycles") + + def _site_refused(self): + """Owner decision 4: every unit refuses the same way, so the site law + holds 0 W (SAFETY-52's, in compute()). Otherwise None, the old law.""" + signs = {inv.refused for inv in self.inverters} + return signs.pop() if len(signs) == 1 and 0 not in signs else None + def log_event(self, msg: str, hint: str | None = None) -> None: """`msg` goes on the action log, the add-on's own technical record. `hint` is `messages.hint()`'s plain words for the same event, and is @@ -2516,7 +2640,8 @@ class Controller: now = datetime.now(timezone.utc) return [n for n in [x for inv in self.inverters - for x in (inv.link_note(now), inv.stale_note())] + for x in (inv.link_note(now), inv.stale_note(), + inv.refusal_note())] if n] async def cycle(self) -> None: @@ -2810,7 +2935,13 @@ class Controller: # what part 6 grades instead is that WIDENING the window # changes the answer. live=inv.is_live(now)[0], - parked=inv.sign_wd.tripped, + # SAFETY-73: a refusing unit is asked 0 W on purpose, and + # one asked under PROBE_W that gives under 100 W is a + # refusal too small to call (its sibling covers the meter). + parked=inv.sign_wd.tripped or bool(inv.refused) or ( + n_units > 1 and inv.batt is not None + and abs(float(standing[inv.name])) <= _ctl.PROBE_W + and abs(float(inv.batt)) < _ctl.REFUSED_BELOW_W), # ⚠️ THIS UNIT'S OWN CUT-OUT. Not the shipped 10 %, and not # the site's `peak_soc_floor` either - that one bounds a # money-saving discharge only, and grading a pack against it @@ -3422,6 +3553,16 @@ class Controller: self._refusal_auto = bool(self.auto) self._refusal_end("control started" if self.auto else "control stopped") + for inv in (self.inverters if len(self.inverters) > 1 else ()): + self._unit_refusal_end(inv, "control started" if self.auto + else "control stopped") + # SAFETY-73: each unit's own refusal, engaged and ended on its own + # reading, before the loop reads `self.target` (an end reseeds it). + _probing = {} + if len(self.inverters) > 1 and self.inputs_ok: + self._unit_refusals() + _probing = {inv.name: self._unit_probe(inv) + for inv in self.inverters if inv.refused} if (self.auto or self.shadow) and self.inputs_ok: # ⚠️ prev is the ARBITER's last output, not the loop's own last # wish. If something outranked the loop, that is what the hardware @@ -3446,6 +3587,8 @@ class Controller: if self.loop_w is not None and self.target != self.loop_w: self._refusal_end("another writer") probe = self._refusal_probe() + if len(self.inverters) > 1: + probe = any(_probing.values()) # ⚠️ `actual_w` IS THE SITE SUM AND THAT IS DEV-02's OTHER HALF. # The anti-windup test inside compute() is # `abs(prev_w - actual_w) > saturation_w`, and `prev_w` is the SITE @@ -3476,7 +3619,10 @@ class Controller: i_w=self.i_w, # SAFETY-52 at one inverter only: with several, OPT-09's pack # limit already closes an empty battery's discharge end. - refused=self.batt_refused if len(self.inverters) == 1 else None, + # SAFETY-73: at N>1 the site law holds 0 W only while every + # unit refuses the same way. Otherwise None, the old law. + refused=self.batt_refused if len(self.inverters) == 1 + else self._site_refused(), probe=probe, ) if decision.frozen and self.sat_count < self.tuning.saturation_cycles: @@ -3486,7 +3632,8 @@ class Controller: self.sat_count = decision.sat_count self.i_w = decision.i_w self.loop_w = decision.target_w - self._refusal_update(decision, loop_prev, site_batt, probe) + if len(self.inverters) == 1: + self._refusal_update(decision, loop_prev, site_batt, probe) # --- TEL-10 ------------------------------------------------------ # ⚠️ THE INTEGRATOR HAS NEVER LEFT THIS PROCESS, AND THAT IS WHAT # THE CARD IS. `self.i_w` is carried between cycles and published @@ -3585,8 +3732,44 @@ class Controller: # ability to DELIVER rests on this argument - a weight cannot stop a # unit being commanded and cannot move a failing unit's load to its # sibling. The `pack` claim filed above is the half that constrains. - resolution = resolve(claims, units=self.units, live=self.live_units(), - weights=self.pack_weights, tick=self.alloc_tick) + # --- SAFETY-73: each refusing unit's own P_SAFETY claim --------------- + # A hard unit limit that always intersects (OPT-11's P_MODE layer sits + # inside it): closed in the refused direction, so the allocator hands + # the share to the others within their own limits. During its probe it + # is a pin at PROBE_W and the others carry the rest. + for inv in self.inverters: + if not inv.refused: + continue + if _probing.get(inv.name): + claims.append(Claim.set("refused", P_SAFETY, + inv.refused * _ctl.PROBE_W, + _ctl.PROBING, + actuator=self.actuator_of("refused", + inv))) + else: + claims.append(Claim.limit("refused", P_SAFETY, + *_refused_interval(inv.refused), + _ctl.REFUSED, + actuator=self.actuator_of("refused", + inv))) + _live = self.live_units() + while True: + resolution = resolve(claims, units=self.units, live=_live, + weights=self.pack_weights, tick=self.alloc_tick) + # SAFETY-73: a probe pin stands only while the resolved site target + # asks at least PROBE_W its way. Below that a sibling would carry + # the opposite direction (circulation), so the pin goes back to the + # closed limit and the split is resolved once more. + _void = [k for k, c in enumerate(claims) + if c.source == "refused" and c.kind == "set" + and c.value * resolution.target_w < _ctl.PROBE_W ** 2] + if not _void: + break + for k in _void: + claims[k] = Claim.limit( + "refused", P_SAFETY, + *_refused_interval(1 if claims[k].value > 0 else -1), + _ctl.REFUSED, actuator=claims[k].actuator) self.allocation = resolution.allocation # --- THE TWO REFUSALS, AND THEY ARE NOT THE SAME REFUSAL -------------- # Both do the same thing - REPLACE the resolution with a 0 W failsafe @@ -5114,7 +5297,8 @@ class Controller: _now = datetime.now(timezone.utc) for inv in self.inverters: for note, red in ((inv.link_note(_now), not inv.is_live(_now)[0]), - (inv.stale_note(), False)): + (inv.stale_note(), False), + (inv.refusal_note(), False)): if note: out.append({"ok": False, "warn": not red, "text": note}) diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 4c8bcdb..b74548f 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -786,6 +786,14 @@ def row_battery_stuck(unit) -> str: f"for now") +def row_battery_refuses(unit, sign, probing) -> str: + """SAFETY-73. One inverter's battery refuses, the others take its share.""" + way = "give" if sign > 0 else "take" + if probing: + return f"{unit}: testing if the battery will {way} power again" + return f"{unit}: the battery refuses to {way} power, the others take over" + + # The top of the page: why the battery does what it does (the "Why" line). WHY_WINNER = { "loop": "Keeping the grid near zero", @@ -805,6 +813,8 @@ WHY_WINNER = { # SAFETY-52: the loop's two words for a battery that gives nothing. "battery refuses": "The battery refuses to give power", "battery probe": "Testing if the battery gives power again", + # SAFETY-73: a refusing inverter's own claim, closed or probing. + "refused": "A battery refuses power, the others take over", } WHY_LIMIT = { "peak(quarter peak)": "the peak limit", @@ -815,6 +825,7 @@ WHY_LIMIT = { "pack": "the battery level", "reserve": "the battery reserve", "maintenance": "battery maintenance", + "refused": "a battery that refuses power", } @@ -857,6 +868,8 @@ HINTS = { "battery_back": "{unit}: battery power reading is used again", "battery_refuses": "The battery refuses to give power, the add-on asks 0 W", "battery_gives": "The battery refusal ended, control asks for power again", + "unit_refuses": "{unit}: the battery refuses power, the others take over", + "unit_gives": "{unit}: the battery refusal ended, it is asked for power again", "bad_value": "The add-on made an invalid power value, inverters set to 0 W", "write_blocked": "{unit}: a power request was blocked, it is set to 0 W", "all_blocked": "A power request was blocked, inverters set to 0 W", @@ -1027,6 +1040,12 @@ def status_samples() -> list: ("row_peak_guard_on", AMBER, row_peak_guard_on(1200, 2500, shadow=True)), ("row_battery_stuck", AMBER, row_battery_stuck("inverter-b")), + ("row_battery_refuses", AMBER, row_battery_refuses("inverter-b", 1, + False)), + ("row_battery_refuses", AMBER, row_battery_refuses("inverter-b", -1, + False)), + ("row_battery_refuses", AMBER, row_battery_refuses("inverter-b", 1, + True)), ("row_circulating_check", GREEN, row_circulating_check(0, 0, 60)), ] diff --git a/goodwe_controller/test_arbiter.py b/goodwe_controller/test_arbiter.py index 76327d2..57fa525 100644 --- a/goodwe_controller/test_arbiter.py +++ b/goodwe_controller/test_arbiter.py @@ -149,7 +149,7 @@ check("...and `source` is still the first positional argument, which is what " Claim.limit("device", P_SAFETY, -1, 1).source == "device") print() -print("ARB-03 2. the split: eleven sources, each classified where it is BUILT") +print("ARB-03 2. the split: twelve sources, each classified where it is BUILT") # The classification is graded against what each claim is ABOUT, restated here # so that the table in arbiter.py and the expectation in a test are not the same # sentence read twice. test_peakguard.py part 10f pins this set against main.py's @@ -189,16 +189,20 @@ UNIT_SOURCES = { "is added, `peak_soc_floor` is not consulted, the SITE target " "is untouched, and main.py does not file it at all at a " "roster of one", + # SAFETY-73. + "refused": "THIS battery's own reading gave nothing against THIS unit's " + "own standing command, so that direction is closed on THIS " + "unit and its share goes to the others. Filed at N>1 only", } for _src, _why in sorted(SITE_SOURCES.items()): print(f" site {_src:<11} {_why}") for _src, _why in sorted(UNIT_SOURCES.items()): print(f" unit {_src:<11} {_why}") -check("all ELEVEN claim sources are classified, and only those eleven", +check("all TWELVE claim sources are classified, and only those twelve", set(CLAIM_SCOPE) == set(SITE_SOURCES) | set(UNIT_SOURCES)) check("the six that are about the GRID CONNECTION are site claims", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == set(SITE_SOURCES)) -check("the five that are about a PACK, a DEVICE or one write are per-inverter", +check("the six that are about a PACK, a DEVICE or one write are per-inverter", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == set(UNIT_SOURCES)) check("a source nobody classified cannot be routed at all - actuator_for() " "raises rather than defaulting to the site, because defaulting to the " @@ -216,7 +220,7 @@ check("with one inverter every source routes to the site, per-inverter ones " all(actuator_for(s, "inverter-a", ONE) == ACTUATOR_SITE for s in CLAIM_SCOPE)) check("...and with none configured at all, likewise", all(actuator_for(s, "inverter-a", ()) == ACTUATOR_SITE for s in CLAIM_SCOPE)) -check("with TWO the identity breaks and the split becomes real: the five " +check("with TWO the identity breaks and the split becomes real: the six " "per-inverter sources route to the unit this controller drives, the six " "site sources stay on the grid connection", {s: actuator_for(s, "inverter-a", TWO) for s in CLAIM_SCOPE} diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index f356a2f..9d07d5a 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -33,7 +33,7 @@ from datetime import datetime, timedelta, timezone from named_absence import given, present -from app import messages +from app import control, messages from app.control import Tuning from app.delivery import ( DELIVERY_OPTION_DEFAULTS, DELIVERY_SHARE_FRACTION, REASON_CODE, @@ -592,7 +592,21 @@ check("...and the SHARES now differ, which is OPT-09 and not a weakening of the "cards meet here from opposite sides: OPT-09 stops the ASK, this file " "grades the ALARM, and neither can do the other's half", _pw != _pf - and _sf[-1]["shares"][1] == 0.0 and _sw[-1]["shares"][1] == 2000.0) + and _sf[-1]["shares"][1] == 0.0 + and max(r["shares"][1] for r in _sw) == 2000.0) +# SAFETY-73. A unit that gives < 100 W for 12 cycles while asked > 500 W is a +# battery that refuses (owner, 2026-09-27): it is closed, its share moves, and +# SAFETY-42 is left with units that deliver something but not enough. This +# fixture compresses `delivery_hold_s` to 1 s at 0.2 s cycles, so the report +# still comes first here. On a site 185 s against 60 s puts the refusal first. +_ref_at = next((i for i, r in enumerate(_sw) if r["shares"][1] == 0.0), None) +check("SAFETY-73: the wedged arm's B, giving 0 W against 2000 W, is refused " + "after 12 cycles of that evidence and asked 0 W from then, the report " + "having come first only because this fixture's hold is 1 s", + _ref_at is not None and _ref_at >= control.SETTLE_CYCLES + and all(r["shares"][1] > 0 for r in _sw[:_ref_at]) + and all(r["shares"][1] == 0.0 for r in _sw[_ref_at:]) + and _cw.inverters[1].refused == 1) check("...and the state of charge is still what tells them apart", [r["soc"] for r in _sw] != [r["soc"] for r in _sf]) print(f" both arms, last cycle: grid {_sw[-1]['grid']:.0f} W, shares " @@ -640,10 +654,10 @@ check("...and `account()` STILL turns this pack away if the ask does arrive - " account(live=True, parked=False, soc=_cold_b.soc, bms_floor=_cold_b.bms_soc_floor) is not None) check("...and the WEDGED arm's B differs from it in exactly that one place - " - "which is why it is still asked for its share, and still named", + "which is why it was asked for its share until the refusal, and named", account(live=True, parked=False, soc=_cw.inverters[1].soc, bms_floor=_cw.inverters[1].bms_soc_floor) is None - and float(_cw.inverters[1].standing_w()) > 0) + and _sw[0]["shares"][1] > 0 and _sw[-1]["named"] == ("inverter-b",)) # ⚠️ WHICH FLOOR, AND THIS IS A WIRING CHECK THAT THE PURE ONES ABOVE CANNOT # MAKE. `peakguard.pack_floor_pct()` conjoins a pack's own cut-out with the @@ -916,9 +930,13 @@ check("...and EVERY WATT IS THE SAME. Grid, site target, both shares and both " "reported or not - which is what 'it does not act' means, stated as a " "measurement instead of as an intention", _power_domain(_sw) == _power_domain(_sn)) -check("...the wedged unit is still being commanded its share after the trip, " - "not parked: this is NOT SAFETY-02's remedy and must not become it", - abs(float(_cw.inverters[1].target)) > 0) +_trip_at = next((i for i, r in enumerate(_sw) if r["named"]), None) +check("...the wedged unit is still commanded its share after the trip, not " + "parked by this guard: this is NOT SAFETY-02's remedy. What later takes " + "the share is SAFETY-73's refusal, which runs the same in the arm where " + "this guard never trips (the line above)", + _trip_at is not None and _ref_at is not None and _trip_at < _ref_at + and all(r["shares"][1] > 0 for r in _sw[_trip_at:_ref_at])) check("...and nothing named `delivery` reaches the arbiter - the resolution's " "own sentence is unchanged by the trip", "deliver" not in _cw.reason.lower() and _cw.reason == _cn.reason) diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index e217fc2..59c1076 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2655,7 +2655,7 @@ check("...and so does the persistent notification, which outlives the page and " # wants from you, not an edit. CLAIM_SOURCES = {"device", "supervised", "failsafe", "safety", "peak", "arbitrage", "maintenance", "loop", "circulation", - "sign_site", "pack"} + "sign_site", "pack", "refused"} # The two appends that file a claim BUILT ELSEWHERE in the method. Named here so # that a THIRD such indirection reads as an unrecognised append rather than as a # silent gap in the scan. @@ -2697,7 +2697,7 @@ check("every `claims.append(...)` in main.py's cycle is one this scan can READ " "- a claim filed through a shape it cannot parse has to fail here rather " "than be counted as nothing, which is how a scan like this goes quietly " "vacuous", len(_appends) >= 10 and None not in _filed) -check("...and the sources that cycle can file are EXACTLY these ELEVEN. THIS " +check("...and the sources that cycle can file are EXACTLY these TWELVE. THIS " "is what makes part 10 a tripwire: replay_loop() hand-builds the claim " "list, so it cannot see a claim main.py adds - and a loop-side SoC " "reserve is a new source. Filing one takes this line red on the line it " @@ -2848,7 +2848,8 @@ check("...and the split is the one ARB-03 argued, with SAFETY-31's and " {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == {"loop", "peak", "arbitrage", "safety", "circulation", "sign_site"} and {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} - == {"device", "supervised", "failsafe", "maintenance", "pack"}) + == {"device", "supervised", "failsafe", "maintenance", "pack", + "refused"}) # The shipped roster is ONE inverter, so §6.2's identity holds and every claim a # real cycle files is a site claim. Observed on the claims main.py's own resolve @@ -2945,7 +2946,7 @@ check("⚠️ AND THIS IS THE BREAKING HALF. Give the same Controller a second " "rest of the roster goes on pushing the same way - and this line goes red", _routed == {"device": "inverter-a", "supervised": "inverter-a", "failsafe": "inverter-a", "maintenance": "inverter-a", - "pack": "inverter-a", + "pack": "inverter-a", "refused": "inverter-a", "loop": ACTUATOR_SITE, "peak": ACTUATOR_SITE, "arbitrage": ACTUATOR_SITE, "safety": ACTUATOR_SITE, "circulation": ACTUATOR_SITE, "sign_site": ACTUATOR_SITE}) @@ -3027,13 +3028,13 @@ _unit_sources_unrouted = [ if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT and "," not in r[1]] print(f" {len(_direct)} direct appends, each read at its own line: " + ", ".join(f"main.py:{ln} {s} -> {a}" for s, a, ln in _routing)) -check("all ELEVEN of `Controller.cycle()`'s DIRECT appends route through " +check("all THIRTEEN of `Controller.cycle()`'s DIRECT appends route through " "`self.actuator_of(<string literal>)`, so this scan can read the routing " "of EVERY one of them. An append that computed its actuator, or omitted " "the argument, or hand-wrote a string, fails HERE rather than being " "silently skipped - which is how a scan like this goes quietly vacuous, " "and 10f is in this file because that already happened once", - len(_direct) == 11 + len(_direct) == 13 and all(a is not None and a.startswith("self.actuator_of('") for _s, a, _ln in _routing)) check("⚠️ AND AT EVERY ONE OF THE ELEVEN THE LITERAL IT ROUTES THROUGH IS THE " @@ -3050,15 +3051,15 @@ check("⚠️ AND EVERY PER-INVERTER APPEND NAMES THE INVERTER IT IS ABOUT. " "site-scoped sources and is the whole defect for a per-inverter one: a " "`device` limit built inside the roster loop and routed without `inv` " "files inverter B's rating on inverter A, where it binds the wrong " - "share. Six of the eleven appends are SCOPE_UNIT - `device`, " - "`supervised`, `failsafe`, maintenance's two and OPT-09's `pack` - and " - "all six pass one. " + "share. Eight of the thirteen appends are SCOPE_UNIT - `device`, " + "`supervised`, `failsafe`, maintenance's two, OPT-09's `pack` and " + "SAFETY-73's two `refused` - and all eight pass one. " "SAFETY-30's `sign_site` is deliberately NOT one of them: it is filed on " "the site, beside `circulation`, because the number that tripped it is " "the site target", _unit_sources_unrouted == [] and len([r for r in _routing - if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT]) == 6) + if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT]) == 8) check("...and the only appends this pin does NOT reach are the two that file a " "claim BUILT ELSEWHERE - `peak_claim` and `arb_claim` - which have no " "`actuator=` at the call site to mis-type. Their routing is pinned where " @@ -3067,7 +3068,7 @@ check("...and the only appends this pin does NOT reach are the two that file a " "arbitrage.claim() by test_arbitrage.py", sorted(_indirect) == sorted(CLAIM_BUILDERS) and len(_direct) + len(_indirect) == len(_appends)) -check("...and between them the twelve appends account for exactly the eleven " +check("...and between them the fifteen appends account for exactly the twelve " "sources 10f pins, so the routing pin and the source set are one scan " "and neither can drift from the other", {s for s, _a, _ln in _routing} | set(CLAIM_BUILDERS.values()) @@ -3119,7 +3120,7 @@ check("⚠️ AND THE RATING LIMITS ARE FILED ONCE PER INVERTER, ON ITS OWN " ("supervised", "inverter-a"), ("supervised", "inverter-b")]) check("...and naming those three is not an accident of this fixture but the " - "reason the static pin exists - SEVEN of the eleven sources need a state " + "reason the static pin exists - EIGHT of the twelve sources need a state " "no check in this file reaches. SAFETY-31's `circulation` is one of the " "seven: it is filed only while the site is MEASURED to be circulating, " "which no fixture here is. SAFETY-30's `sign_site` is another, and it " @@ -3127,7 +3128,8 @@ check("...and naming those three is not an accident of this fixture but the " "standing opposed to the meter for its whole window", {c.source for c in _cl2} == CLAIM_SOURCES - {"failsafe", "safety", "maintenance", "peak", - "arbitrage", "circulation", "sign_site"}) + "arbitrage", "circulation", "sign_site", + "refused"}) # ⚠️ AND NOW THE HALF THAT WAS EVIDENCE-SHAPED AND OBSERVED NOTHING. The three # checks above grade WHICH ACTUATOR each claim lands on. They say nothing about # WHOSE NUMBERS the bound is built from - and those are two different defects diff --git a/goodwe_controller/test_refusal_units.py b/goodwe_controller/test_refusal_units.py new file mode 100644 index 0000000..525a4b9 --- /dev/null +++ b/goodwe_controller/test_refusal_units.py @@ -0,0 +1,480 @@ +"""Runnable check for SAFETY-73. `python3 test_refusal_units.py` + +SAFETY-52 per inverter. With two or more inverters, a battery that refuses +(gives < 100 W for 12 cycles while asked > 500 W, or trips the stale-reading +gate on a ~0 W reading) is closed in that direction by its own P_SAFETY limit, +so the allocator hands its share to the others. It is probed at 200 W every +15 minutes, one inverter at a time. When every inverter refuses the same way +the site holds 0 W. When a refusal ends the site target restarts from the watts +on the wire. DECISIONS/SAFETY-73 has the record. + +Drives the REAL `Controller` (read_inputs + cycle, the real freshness gate, +allocator, OPT-09 pack claim and SAFETY-42 detector) with two inverters in +simulated time. At the cut-out a battery reads -4 W for any request >= -4 W +and accepts charge. Two register shapes: FLAT at -4 W (the 09-06 capture) and +JITTER +-3 W (the gate cannot arm). `OLD` runs the same fixture with the +per-unit refusal switched off, which is 652097a's behaviour at N>1. + +Mutations (MUTATION.md, `python3 -B`, copies purged of `__pycache__`), graded +over this file / test_delivery / test_refusal. Every one is red here: + + # mutation reds + --- --------------------------------------------------------- ------- + U1 main.py: the per-unit engage clause never fires 7/2/0 + U2 main.py: the N>1 stale-reading seed returns at once 14/0/0 + U3 main.py: no `refused` claim is filed 13/2/0 + U4 main.py: a probe never pins (always the closed limit) 7/0/0 + U5 main.py: a probe pin stands whatever the site target 1/0/0 + U6 main.py: no reseed of the site target when a refusal ends 1/0/0 + U7 main.py: no site hold when every inverter refuses 2/0/0 + U8 main.py: the other-direction exit removed (charge counter) 1/0/0 + U9 main.py: the delivery exit removed 3/0/0 + U10 main.py: probes are no longer one at a time 1/0/0 + U11 main.py: the above-cut-out WARNING condition inverted 1/0/0 + U12 main.py: SAFETY-42's account no longer sees a small ask 1/0/0 + U13 main.py: a unit engages above `saturation_w`, not PROBE_W 1/0/0 + +On 652097a itself this file stops at the first sample (`Inverter` has no +`refused`); its OLD arms reproduce that tree's N>1 behaviour instead, and +every PRECONDITION line is graded against them. +""" + +import asyncio +import logging +import sys +from datetime import datetime, timedelta, timezone + +from app import control +from app.control import PROBE_EVERY_S, PROBE_S, PROBE_W +from app.main import Controller +from app.arbiter import P_LOOP, P_PEAK, P_SAFETY, Claim, resolve +import app.main as m + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +TICK = 5.0 +CUT_W = -4.0 +H = 3600.0 +BASE = datetime(2026, 9, 6, 19, 30, tzinfo=timezone.utc) +UNITS = ("a", "b") + + +class _Store: + def __init__(self): + from app.store import DEFAULTS + self.data = dict(DEFAULTS) + + def set(self, k, v): + self.data[k] = v + + def get_time(self, *a): + return None + + +class _Pub: + enabled = False + + def publish(self, *a, **k): + pass + + def close(self): + pass + + +class _Hass: + """A house, one meter, and two batteries that follow unless cut out.""" + + def __init__(self, load, cut, soc, jitter): + self.load, self.cut, self.soc, self.jitter = load, cut, soc, jitter + self.cmd = {u: 0.0 for u in UNITS} + self.t = 0.0 + + def batt(self, u): + c = self.cmd[u] + if self.cut[u](self.t) and c >= CUT_W: + if self.jitter: + return CUT_W + ((int(self.t / TICK) % 3) - 1) * 3.0 + return CUT_W + return float(round(c)) + + def grid(self): + return self.load(self.t) - sum(self.batt(u) for u in UNITS) + + async def limits(self, e): + return (-2000.0, 2000.0, 1.0) + + async def call(self, *a): + return True + + async def number(self, e, invert=False): + if e == "sensor.grid": + return self.grid() + u = e[-1] + if e.startswith("sensor.soc"): + v = self.soc[u] + return v(self.t) if callable(v) else v + if e.startswith("sensor.batt"): + return self.batt(u) + return None + + async def set_number(self, e, v): + self.cmd[e[-1]] = float(v) + return True + + +def _off(c): + """652097a's N>1 behaviour: nothing refuses per unit.""" + c._unit_refusals = lambda: None + c._unit_refusal_start = lambda *a, **k: None + + +def run(load, cut, dur, *, soc=None, jitter=False, old=False, events=None, + extra=None): + """Real cycles every TICK of simulated time. Rows are dicts per cycle.""" + async def go(): + hass = _Hass(load, cut, soc or {"a": 50.0, "b": 50.0}, jitter) + inv = [{"name": f"inverter-{u}", "setpoint_entity": f"number.sp_{u}", + "soc_entity": f"sensor.soc_{u}", + "batt_entity": f"sensor.batt_{u}", + "max_w": 2000, "bms_soc_floor": 10} for u in UNITS] + o = {"meter_entity": "sensor.grid", "meter_source": "off", + "inverters": inv, "gain": 0.6, "slew_w": 400, + "target_grid_w": -10, "deadband_w": 15, "step_w": 10, + "heartbeat_s": 10, "stale_input_s": 15, "auto_start": True} + o.update(extra or {}) + c = Controller(o, hass, _Store(), _Pub(), stop=asyncio.Event()) + for i in c.inverters: + i.dev_min, i.dev_max = -2000.0, 2000.0 + c.auto = True + if old: + _off(c) + real_dt = m.datetime + clock = [0.0] + + class _DT(real_dt): + @classmethod + def now(cls, tz=None): + return BASE + timedelta(seconds=clock[0]) + + m.datetime = _DT + rows = [] + trips = {u: 0 for u in UNITS} + was = {u: False for u in UNITS} + pending = dict(events or {}) + try: + t = 0.0 + while t < dur: + hass.t = clock[0] = t + for et in sorted(pending): + if et <= t: + pending.pop(et)(c) + await c.read_inputs(now_mono=t) + for u, i in zip(UNITS, c.inverters): + s = i.batt_fresh.stale + trips[u] += s and not was[u] + was[u] = s + await c.cycle() + rows.append(dict( + t=t, grid=hass.grid(), site=c.target, reason=c.loop_reason, + a=hass.cmd["a"], b=hass.cmd["b"], + ra=c.inverters[0].refused, rb=c.inverters[1].refused, + da=c.inverters[0].delivery_wd.tripped, + db=c.inverters[1].delivery_wd.tripped)) + t += TICK + finally: + m.datetime = real_dt + return rows, trips, c + return asyncio.run(go()) + + +def after(rows, t0, t1=None): + return [r for r in rows if r["t"] >= t0 and (t1 is None or r["t"] < t1)] + + +def mean(rows, k): + return sum(r[k] for r in rows) / len(rows) if rows else float("nan") + + +def never(t): + return False + + +def cut_at(t0, t1=None): + return lambda t: t >= t0 and (t1 is None or t < t1) + + +def probes(rows, k): + """Start times of runs where refused unit `k` is asked exactly PROBE_W.""" + out, prev = [], False + for r in rows: + on = abs(r[k]) == PROBE_W and r["r" + k] != 0 + if on and not prev: + out.append(r["t"]) + prev = on + return out + + +SHAPES = (("flat", False), ("jitter", True)) + +# ============================================================================== +print("1. case a: house 3000 W, both give power, A cuts out at 120 s") +# ============================================================================== +for shape, jit in SHAPES: + new, ntr, cn = run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, H, + jitter=jit) + old, otr, _ = run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, H, + jitter=jit, old=True) + tail_n, tail_o = after(new, 300), after(old, 300) + held = [r for r in tail_n if abs(r["a"]) != PROBE_W] + print(f" {shape}: old B {mean(tail_o, 'b'):.0f} W grid " + f"{mean(tail_o, 'grid'):+.0f} W trips A {otr['a']}; new B " + f"{mean(tail_n, 'b'):.0f} W grid {mean(tail_n, 'grid'):+.0f} W " + f"trips A {ntr['a']}") + check(f"{shape}: PRECONDITION: on the old law B never takes over (mean " + f"under 1950 W) while A gives nothing", + mean(tail_o, "b") < 1950 and mean(tail_o, "grid") > 1050) + check(f"{shape}: A is refused and asked 0 W outside its probes, B carries " + f"its rating, and the grid imports only what B cannot give", + cn.inverters[0].refused == 1 and all(r["a"] == 0.0 for r in held) + and min(r["b"] for r in tail_n) == 2000.0 + and abs(mean(tail_n, "grid") - 1004) < 20) + check(f"{shape}: A's stale-reading gate trips at most once, the site is " + f"never stopped after the first 5 minutes, and SAFETY-42 does not " + f"report A as not delivering", + ntr["a"] <= 1 + and all(r["reason"] != "not-running" for r in tail_n) + and not any(r["da"] for r in new)) + +# ============================================================================== +print("2. case b: house 1200 W, which B alone can carry, A cuts out") +# ============================================================================== +for shape, jit in SHAPES: + new, ntr, cn = run(lambda t: 1200.0, {"a": cut_at(120), "b": never}, H, + jitter=jit) + old, _, _ = run(lambda t: 1200.0, {"a": cut_at(120), "b": never}, H, + jitter=jit, old=True) + tail_n, tail_o = after(new, 300), after(old, 300) + imp = sum(max(0.0, r["grid"]) for r in tail_n) * TICK / H + print(f" {shape}: old grid {mean(tail_o, 'grid'):+.0f} W, new grid " + f"{mean(tail_n, 'grid'):+.0f} W, new import {imp:.0f} Wh") + check(f"{shape}: PRECONDITION: the old law leaves a standing import", + mean(tail_o, "grid") > 250) + check(f"{shape}: B takes over the whole house and the grid sits near its " + f"target", abs(mean(tail_n, "grid") + 10) < 25 and imp < 10) + pa = probes(new, "a") + in_probe = [r for r in new + if any(p <= r["t"] < p + PROBE_S for p in pa)] + check(f"{shape}: A is probed at 200 W every 15 minutes while B carries " + f"the rest, and the two never pull opposite ways", + len(pa) >= 3 + and all(abs(q - p - PROBE_EVERY_S - PROBE_S) <= 2 * TICK + for p, q in zip(pa, pa[1:])) + and all(r["b"] > 0 for r in in_probe) + and all(r["a"] * r["b"] >= 0 for r in new)) + +# ============================================================================== +print("3. case c: both cut out; the site holds 0 W, probes one at a time") +# ============================================================================== +for shape, jit in SHAPES: + new, ntr, cn = run(lambda t: 3000.0, {"a": cut_at(120), "b": cut_at(150)}, + 1.5 * H, jitter=jit) + old, _, _ = run(lambda t: 3000.0, {"a": cut_at(120), "b": cut_at(150)}, + 1.5 * H, jitter=jit, old=True) + tail_n, tail_o = after(new, 600), after(old, 600) + pa, pb = probes(new, "a"), probes(new, "b") + print(f" {shape}: old mean asks A/B {mean(tail_o, 'a'):.0f}/" + f"{mean(tail_o, 'b'):.0f} W; new {mean(tail_n, 'a'):.0f}/" + f"{mean(tail_n, 'b'):.0f} W, probes A {len(pa)} B {len(pb)}") + check(f"{shape}: PRECONDITION: the old law keeps asking two empty " + f"batteries", mean(tail_o, "a") > 150 and mean(tail_o, "b") > 150) + check(f"{shape}: the site holds 0 W: the loop says `battery refuses` or " + f"`battery probe` and each battery is asked 0 W or its probe", + all(r["reason"] in (control.REFUSED, control.PROBING) + for r in tail_n) + and all(r["a"] in (0.0, PROBE_W) and r["b"] in (0.0, PROBE_W) + for r in tail_n)) + check(f"{shape}: both batteries are probed, never at the same time", + len(pa) >= 3 and len(pb) >= 3 + and not any(r["a"] and r["b"] for r in new if r["t"] > 300)) + +# ============================================================================== +print("4. recovery: the reseed stops the parked site target reaching the grid") +# ============================================================================== +# Both cut, the house drops to 940 W at 1 h, A recovers at 1.5 h with no sign +# change. Phase A, with the envelope but no reseed and no site hold: -1059 W. +ld = (lambda t: 3000.0 if t < H else 940.0) +for shape, jit in SHAPES: + rows, _, c = run(ld, {"a": cut_at(120, 1.5 * H), "b": cut_at(150)}, + 2 * H, jitter=jit) + win = after(rows, 1.5 * H, 1.5 * H + 900) + worst = min(r["grid"] for r in win) + print(f" {shape}: worst grid after A recovers {worst:+.0f} W; A " + f"refused {c.inverters[0].refused}") + check(f"{shape}: A's recovery is found (at its next probe at the latest) " + f"and never exports more than 250 W", + c.inverters[0].refused == 0 and worst > -250 + and any("BATTERY REFUSES ENDED inverter-a" in e for e in c.events)) + +# Case a: B at its rating, the site target parked at 3600 W while the house +# still imports; the house falls to 2500 W and A recovers. Without the reseed A +# is handed the parked 1600 W at once, 1100 W more than the house needs. +ld2 = (lambda t: 3000.0 if t < 0.5 * H else 2500.0) +rows, _, c = run(ld2, {"a": cut_at(120, 0.75 * H), "b": never}, 1.5 * H) +win = after(rows, 0.75 * H, 0.75 * H + 900) +print(f" a: worst grid when A recovers {min(r['grid'] for r in win):+.0f} W") +check("case a: a recovery hands A no parked site target (worst export under " + "250 W)", min(r["grid"] for r in win) > -250 + and any("BATTERY REFUSES ENDED inverter-a" in e for e in c.events)) + +# ============================================================================== +print("5. exits, words and the circulation guard") +# ============================================================================== +# Solar: the house exports from 30 min, so the loop wants to charge. +rows, _, c = run(lambda t: 3000.0 if t < 0.5 * H else -2500.0, + {"a": cut_at(120), "b": never}, H) +check("the grid asking the other direction lets A charge at once (its limit " + "closes only the refused direction) and a minute of charge ends the " + "refusal", + c.inverters[0].refused == 0 and min(r["a"] for r in after(rows, 0.6 * H)) + < -500 and any("the other way" in e for e in c.events)) + + +def _stop(c): + c.auto = False + + +rows, _, c = run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, 0.5 * H, + events={1200.0: _stop}) +check("stopping control ends the refusal", + c.inverters[0].refused == 0 + and any("control stopped" in e for e in c.events)) + +# A small house: the site asks under 200 W, so a probe may not pin A (B would +# have to charge while A gives power). The probe waits instead. +rows, _, c = run(lambda t: 3000.0 if t < 600 else 120.0, + {"a": cut_at(120), "b": never}, 1.2 * H) +check("with the site asking under 200 W no probe is sent and no inverter is " + "ever asked the opposite way to the other", + c.inverters[0].refused == 1 + and probes(after(rows, 700), "a") == [] + and all(r["a"] * r["b"] >= 0 for r in rows) + and not any("ARBITER" in e for e in c.events)) + +# The hold binds every strategy's ask: a peak-guard SET at P_PEAK on the site +# is still placed around a refusing unit's closed limit. +_res = resolve([Claim.set("peak", P_PEAK, 3000.0, "quarter peak"), + Claim.set("loop", P_LOOP, 500.0, "tracking"), + Claim.limit("supervised", P_SAFETY, -2000.0, 2000.0, + actuator="inverter-a"), + Claim.limit("supervised", P_SAFETY, -2000.0, 2000.0, + actuator="inverter-b"), + Claim.limit("refused", P_SAFETY, hi=0.0, + reason=control.REFUSED, actuator="inverter-a")], + units=("inverter-a", "inverter-b"), + live=("inverter-a", "inverter-b")) +check("a P_SAFETY refusal limit binds a higher-priority strategy too: the " + "peak guard's 3000 W goes to B, A gets 0 W", + _res.shares.get("inverter-a") == 0 and _res.shares.get("inverter-b") + == 2000) + + +class _Grab(logging.Handler): + def __init__(self): + super().__init__() + self.lines = [] + + def emit(self, record): + self.lines.append((record.levelno, record.getMessage())) + + +_g = _Grab() +_lg = logging.getLogger("goodwe") +_lv = _lg.level +_lg.setLevel(logging.INFO) +_lg.addHandler(_g) +run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, 600) +run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, 600, + soc={"a": 10.0, "b": 50.0}) +_lg.removeHandler(_g) +_lg.setLevel(_lv) +warns = [x for lv, x in _g.lines if lv == logging.WARNING + and "REFUSES_ABOVE_CUT_OUT" in x] +infos = [x for lv, x in _g.lines if lv == logging.INFO + and "BATTERY_REFUSES" in x] +print(f" {warns} / {infos}") +check("a refusal above the configured cut-out level logs INFO and one WARNING " + "naming the inverter, and a battery at its cut-out logs neither " + "(OPT-09's limit closes it first)", + len(warns) == 1 and warns[0].startswith("inverter-a ") + and len(infos) == 1 and infos[0].startswith("inverter-a:") + and len(warns[0].split()) <= 25) + +# A night load of 400 W: each unit is asked about 400 W once the loop has +# made up A's missing half, under `saturation_w`. Engaging at PROBE_W is what +# refuses A here; at 500 W it would keep a phantom share that SAFETY-43 names. +rows, _, c = run(lambda t: 400.0, {"a": cut_at(0), "b": never}, 1200) +check("a 400 W night load: A is refused at a share under 500 W, B carries the " + "house and nothing reports A as not delivering", + c.inverters[0].refused == 1 and not any(r["da"] for r in rows) + and abs(mean(after(rows, 300), "grid") + 10) < 25 + and mean(after(rows, 300), "b") > 380) + +# A night load of 150 W: A's share never passes PROBE_W, so it is never +# refused, and SAFETY-43 must not name it as not delivering either: a battery +# asked under 200 W that gives under 100 W is a refusal too small to call. +rows, _, c = run(lambda t: 150.0, {"a": cut_at(0), "b": never}, 1200) +check("a small share on an empty battery is neither refused nor reported as " + "not delivering, and the grid stays near its target", + c.inverters[0].refused == 0 and not any(r["da"] for r in rows) + and abs(mean(after(rows, 300), "grid") + 10) < 25) + +rows, _, c = run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, 600) +notes = c.liveness_notes() +check("the status page names the refusing inverter", + any(n.startswith("inverter-a: the battery refuses to give power") + for n in notes)) + +# Shadow mode writes nothing, so nothing is asked and nothing can refuse. +rows, _, c = run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, 1200, + extra={"shadow_mode": True}) +check("shadow mode: no inverter is refused and both stay at 0 W", + c.inverters[0].refused == 0 and c.inverters[1].refused == 0 + and all(r["a"] == 0.0 and r["b"] == 0.0 for r in rows)) + +# ============================================================================== +print("6. one inverter is untouched") +# ============================================================================== + + +def _boom(*a, **k): + raise AssertionError("SAFETY-73 code ran at N=1") + + +_saved = {k: getattr(Controller, k) for k in ( + "_unit_refusals", "_unit_refusal_start", "_unit_refusal_end", + "_unit_probe", "_site_refused")} +for k in _saved: + setattr(Controller, k, _boom) +try: + import test_refusal as _t1 + _one_ok = not _t1.fails +except (AssertionError, SystemExit) as e: + _one_ok = isinstance(e, SystemExit) and not e.code +finally: + for k, v in _saved.items(): + setattr(Controller, k, v) +check("SAFETY-52's whole single-inverter suite passes with every SAFETY-73 " + "method made to raise, so none of it runs at N=1", _one_ok) + +print() +if fails: + print(f"{len(fails)} FAILED: " + ", ".join(fails)) + sys.exit(1) +print("all checks passed") -- 2.54.0 From f8d63cc6147c1fed2d7601184c5b4e84501f0748 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Mon, 28 Sep 2026 00:45:01 +0200 Subject: [PATCH 052/105] UX-13 P1: page shell and Home screen on a structured /status - app/static/{index.html,app.css,app.js}: tabs (Home, Batteries, Settings, Setup), hash routes, phone bottom tabs, light/dark. Served inlined at "/"; the route list is unchanged, and every URL is relative. - app/homeview.py: /status gains state, now, batteries, plan, attention, month_peak and control beside the old fields. The plan is what the add-on does today: the arbitrage verdict (the same plan.arbitrage() call as the cycle), the monthly cycle, the peak limit, "follows the house". - The Home plan chart has hover, tap and keyboard-focus tooltips: price bar = hour and price; block = what, when, why, kWh and EUR. - Region preset and year: in config/model (for P2) and on the Home price line. - test_home.py; test_messages part 8 scans every Home sentence; STYLE plan line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- STYLE.md | 1 + goodwe_controller/app/homeview.py | 932 ++++++++++++++++++++++++ goodwe_controller/app/main.py | 21 +- goodwe_controller/app/static/app.css | 137 ++++ goodwe_controller/app/static/app.js | 368 ++++++++++ goodwe_controller/app/static/index.html | 135 ++++ goodwe_controller/app/ui_text/en.json | 42 ++ goodwe_controller/app/web.py | 110 +-- goodwe_controller/test_home.py | 518 +++++++++++++ goodwe_controller/test_messages.py | 63 ++ goodwe_controller/test_pv.py | 11 +- goodwe_controller/tools/ux13_demo.py | 131 ++++ 12 files changed, 2388 insertions(+), 81 deletions(-) create mode 100644 goodwe_controller/app/homeview.py create mode 100644 goodwe_controller/app/static/app.css create mode 100644 goodwe_controller/app/static/app.js create mode 100644 goodwe_controller/app/static/index.html create mode 100644 goodwe_controller/test_home.py create mode 100644 goodwe_controller/tools/ux13_demo.py diff --git a/STYLE.md b/STYLE.md index e3b3c8f..1014aae 100644 --- a/STYLE.md +++ b/STYLE.md @@ -7,6 +7,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "<title>" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. - **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. +- **Plan line** (UX-13 Home screen: the plan, tooltips, a battery's "now" line): at most 2 sentences, each at most 12 words. Words from `app/homeview.py`, checked by `test_messages.py` part 8. - **Log line** (WARNING/ERROR): one line of at most 25 words **as logged**, with any built text filled in. Log lines stay in English and are not translated. A line that reports a safety reason gives one plain sentence and the reason's code (`STALE_READING`, `OUTPUT_CLAMP`), the evidence an installer searches for. The reason itself, with its figures and limits, goes on a DEBUG line right after it and into the action log, never onto the WARNING/ERROR line. It keeps the shape of a red alarm: at most 3 sentences of at most 30 words. The line as logged has no semicolon, banned word, capitals, "1 times" or "(s)". `test_messages.py` part 6 builds every such text with the real code and checks it, and lists the few non-safety families still over 25 words. A line that repeats every cycle is DEBUG. INFO lines carry no section numbers, ISO timestamps or capitals. - **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3). - **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown on the page. Installers read it as `events` in the `status` JSON. diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py new file mode 100644 index 0000000..c4e56b7 --- /dev/null +++ b/goodwe_controller/app/homeview.py @@ -0,0 +1,932 @@ +"""UX-13 P1: the Home screen's part of `/status`, built from what the add-on +already knows and already plans. Reads only; commands nothing. + +`build(controller)` returns `now`, `batteries`, `plan`, `attention`, +`month_peak`, `control` and `state`. The old fields (`banner`, `rows`, +`checks`, ...) stay beside them for the installer details and for anything +that reads the JSON. See DECISIONS/UX-13-one-layout-table.md and the design +note, section 3.3. + +The plan shows only what the add-on does today: trading on price (the +arbitrage verdict, the same call the control cycle makes), the monthly battery +cycle, the peak limit and "follows the house". Battery modes (OPT-11) are not +built, so nothing here invents a mode plan. Every sentence is in the words +section at the bottom and is held to STYLE.md by test_messages.py. +""" + +from datetime import datetime, timedelta, timezone + +from . import arbitrage, messages, peakguard +from .maintenance import CHARGE as M_CHARGE, DRAIN as M_DRAIN, HOLD as M_HOLD +from .maintenance import IDLE as M_IDLE +from .price import Absence, Uncertainty, brussels +from .static_tariff import static_plan +from .tariff import BILLING_TZ +from .uimodel import REGION_PRESETS, options_to_ui + +# A battery at or under this many watts is resting, not charging or giving. +IDLE_W = 50.0 +# Display only: the lowest third of today's price range is "cheap", the top +# third "expensive". A price range under this is flat, and nothing is marked. +FLAT_EUR_KWH = 0.01 + +# Severity words the page shows; the same four as STYLE.md section 3. +ALARM, WARNING, INFO = messages.ALARM, messages.WARNING, messages.INFO + + +# --------------------------------------------------------------------------- # +# Time: today's local day, on the billing calendar +# --------------------------------------------------------------------------- # +def local_day(now: datetime): + """`(midnight_utc, next_midnight_utc)` of the local day holding `now`.""" + here = now.astimezone(BILLING_TZ) + start = datetime(here.year, here.month, here.day, tzinfo=BILLING_TZ) + nxt = start.date() + timedelta(days=1) + end = datetime(nxt.year, nxt.month, nxt.day, tzinfo=BILLING_TZ) + return start.astimezone(timezone.utc), end.astimezone(timezone.utc) + + +def _hours(t: datetime, day0: datetime) -> float: + return (t - day0).total_seconds() / 3600.0 + + +def hhmm(t: datetime) -> str: + return f"{brussels(t):%H:%M}" + + +def _kw(w) -> str: + return f"{abs(float(w)) / 1000:.1f} kW" + + +def _eur(v) -> str: + return f"€{float(v):.2f}" + + +def _kwh(v) -> str: + return f"{float(v):.1f} kWh" + + +# --------------------------------------------------------------------------- # +# Now +# --------------------------------------------------------------------------- # +def flow(w, *, shadow=False): + """`charging` / `giving` / `resting` / None for one battery power.""" + if w is None: + return None + if shadow: + return "resting" + if w > IDLE_W: + return "giving" + if w < -IDLE_W: + return "charging" + return "resting" + + +def now_block(*, grid_w, pv_w, batt_w, has_solar, shadow): + """The four tiles. `house_w` needs all three readings, so without a solar + reading it is None rather than a number that leaves the sun out.""" + house = None + if has_solar and None not in (grid_w, pv_w, batt_w): + house = float(grid_w) + float(pv_w) + float(batt_w) + return { + "solar_w": None if pv_w is None else float(pv_w), + "house_w": house, + "grid_w": None if grid_w is None else float(grid_w), + "batt_w": None if batt_w is None else float(batt_w), + "has_solar": bool(has_solar), + "lines": { + "solar": tile_solar(pv_w, has_solar), + "house": tile_house(house, has_solar), + "grid": tile_grid(grid_w), + "batt": tile_batt(batt_w, shadow), + }, + } + + +# --------------------------------------------------------------------------- # +# Prices for today's chart +# --------------------------------------------------------------------------- # +def _points(plan): + if plan is None: + return () + return plan.read.match(series=lambda r: tuple(r.points), + no_data=lambda _r: ()) + + +def _spans(points): + """`[(point, end)]`: each point runs until the next one starts, and the + last one for the series' own spacing (15 minutes or an hour).""" + pts = sorted(points, key=lambda p: p.start) + gaps = [b.start - a.start for a, b in zip(pts, pts[1:])] + step = min([g for g in gaps if g > timedelta(0)] or [timedelta(hours=1)]) + step = min(step, timedelta(hours=1)) + out = [] + for i, p in enumerate(pts): + nxt = pts[i + 1].start if i + 1 < len(pts) else None + end = nxt if nxt is not None and nxt - p.start <= timedelta(hours=1) \ + else p.start + step + out.append((p, end)) + return out + + +def _day_prices(c): + cache = getattr(c, "home_prices", None) + if cache is None: + cache = c.home_prices = DayPrices() + return cache + + +class DayPrices: + """Today's prices as seen so far. The refresh keeps only the hours ahead, + so the hours already past are remembered here for the chart. Display only: + nothing reads this back into a decision.""" + + def __init__(self): + self.day = None + self.points = {} + + def see(self, points, day0, day1): + if self.day != day0: + self.day, self.points = day0, {} + for p in points: + if day0 <= p.start < day1: + self.points[p.start] = p + return sorted(self.points.values(), key=lambda p: p.start) + + +def hour_bars(points, day0, day1): + """One bar per local hour: the mean of its prices, or None when unknown. + `kind` is cheap / dear / mid by thirds of today's range (display only).""" + n = int(round(_hours(day1, day0))) + bars = [] + for k in range(n): + a, b = day0 + timedelta(hours=k), day0 + timedelta(hours=k + 1) + inside = [p for p in points if a <= p.start < b] + price = (sum(p.eur_per_kwh for p in inside) / len(inside) + if inside else None) + bars.append({"h": k, "start": a.isoformat(), "label": hhmm(a), + "end_label": hhmm(b), + "eur_kwh": None if price is None else round(price, 4), + "estimate": bool(inside) and any(p.provisional + for p in inside), + "kind": None}) + known = [b["eur_kwh"] for b in bars if b["eur_kwh"] is not None] + if known and max(known) - min(known) >= FLAT_EUR_KWH: + lo, hi = min(known), max(known) + third = (hi - lo) / 3.0 + for b in bars: + p = b["eur_kwh"] + if p is None: + continue + b["kind"] = ("cheap" if p <= lo + third else + "dear" if p >= hi - third else "mid") + elif known: + for b in bars: + if b["eur_kwh"] is not None: + b["kind"] = "mid" + return bars + + +# --------------------------------------------------------------------------- # +# The plan, per battery +# --------------------------------------------------------------------------- # +def _run(i, kind, start, end, day0, day1, what, why, amount, *, kwh=None, + eur=None, price=None): + a = max(0.0, _hours(start, day0)) + z = min(_hours(day1, day0), _hours(end, day0)) + return {"battery": i, "kind": kind, "start": start.isoformat(), + "end": end.isoformat(), "from": hhmm(start), + "to": "24:00" if end == day1 else hhmm(end), + "start_h": round(a, 3), "end_h": round(z, 3), + "what": what, "why": why, "amount": amount, + "kwh": None if kwh is None else round(kwh, 2), + "eur": None if eur is None else round(eur, 2), + "eur_kwh": None if price is None else round(price, 4)} + + +def trade_verdict(c, plan): + """The arbitrage verdict the control cycle would reach on this plan, or a + reason there is none. The SAME call and inputs as `Controller.cycle()`: + `plan.arbitrage()` with the peak guard's state, the cycle cost and the + no-weather uncertainty. Returns `(verdict_or_None, why_key)`.""" + if not arbitrage.enabled(c.o): + return None, "off" + guard = arbitrage.guard_state(c.peak_guard) + if guard is None: + return None, "not_covered" + if plan is None: + return None, "no_prices" + verdict = plan.arbitrage(peak_guard_active=guard, + min_spread_eur_kwh=arbitrage.threshold_eur_kwh(c.o), + uncertainty=frozenset({Uncertainty.NO_WEATHER})) + return verdict.match( + allowed=lambda v: (v, "allowed"), + refused=lambda _v: (None, "peak" if guard else "not_worth")) + + +def _point_end(plan, point): + for p, end in _spans(_points(plan)): + if p.start == point.start: + return end + return point.start + timedelta(hours=1) + + +def trade_runs(c, plan, verdict, day0, day1, now, shadow): + """A charge block and a give block on each battery, where the verdict put + them. The site trades as one; each battery's share is capped by its own + rating and by the room its level leaves (arbitrage's own floor/ceiling).""" + floor, ceiling = arbitrage.soc_bounds(c.o) + runs, later = [], [] + for kind, pt in (("grid", verdict.cheapest), ("give", verdict.dearest)): + end = _point_end(plan, pt) + if end <= now: + continue + if not (day0 <= pt.start < day1): + later.append((kind, pt)) + continue + hrs = (end - pt.start).total_seconds() / 3600.0 + for i, inv in enumerate(c.inverters): + kwh = inv.max_w / 1000.0 * hrs + if inv.capacity_kwh and inv.soc is not None: + room = (ceiling - inv.soc if kind == "grid" + else inv.soc - floor) + kwh = min(kwh, max(0.0, room) / 100.0 * inv.capacity_kwh) + eur = kwh * pt.eur_per_kwh + if kind == "grid": + what, why, amount = (run_grid_what(kwh, shadow), + run_grid_why(pt.eur_per_kwh), + run_grid_amount(eur)) + else: + what, why, amount = (run_give_what(kwh, shadow), + run_give_why(pt.eur_per_kwh), + run_give_amount(eur)) + runs.append(_run(i, kind, pt.start, end, day0, day1, what, why, + amount, kwh=kwh, eur=eur, price=pt.eur_per_kwh)) + return runs, later + + +def maintenance_runs(c, day0, day1, now, shadow): + """The monthly battery cycle: under way now, or starting later today. + The cycle starts in the hour `maintenance_start_hour` names, read as the + control cycle reads it (UTC hour of `now`), shown in local time.""" + runs, lines = [], [] + waiting = [] + for i, (inv, m) in enumerate(zip(c.inverters, c.maints)): + cfg = m.cfg + if not cfg.enabled: + continue + cap = inv.capacity_kwh + if m.phase != M_IDLE: + hours = _cycle_hours(m.phase, inv.soc, cap, cfg) + end = now + timedelta(hours=hours or 1.0) + runs.append(_run(i, "cycle", now, end, day0, day1, + run_cycle_what(m.phase, shadow), + run_cycle_why(shadow), + run_cycle_amount(hours))) + continue + if not m.due(now) and (m.next_due(now) is None + or m.next_due(now) >= day1): + continue + start = now.replace(hour=cfg.start_hour, minute=0, second=0, + microsecond=0) + if start + timedelta(hours=1) <= now: + start += timedelta(days=1) + due_at = m.next_due(now) + if due_at is not None and due_at > start: + continue + if not (day0 <= start < day1): + continue + waiting.append((m.waited_days(now), i, start)) + # One battery cycles at a time (maintenance.arbitrate); the one waiting + # longest goes first, and none starts while another is under way. + busy = any(m.phase != M_IDLE for m in c.maints) + waiting.sort(key=lambda t: (-t[0], t[1])) + for n, (_w, i, start) in enumerate(waiting): + inv, m = c.inverters[i], c.maints[i] + hours = _cycle_hours(M_DRAIN, inv.soc, inv.capacity_kwh, m.cfg) + if n == 0 and not busy: + end = start + timedelta(hours=hours or 1.0) + runs.append(_run(i, "cycle", start, end, day0, day1, + run_cycle_what(M_IDLE, shadow), + run_cycle_why(shadow), + run_cycle_amount(hours))) + else: + lines.append(line_cycle_waits(inv.name)) + return runs, lines + + +def _cycle_hours(phase, soc, cap_kwh, cfg): + """Hours left in a cycle, or None when the capacity or level is unknown.""" + if phase == M_HOLD: + return cfg.hold_min / 60.0 + if not cap_kwh or soc is None: + return None + hours = cfg.hold_min / 60.0 + fill_from = soc if phase == M_CHARGE else cfg.soc_floor + hours += (max(0.0, cfg.soc_target - fill_from) / 100.0 * cap_kwh + / max(cfg.charge_w / 1000.0, 0.1)) + if phase not in (M_CHARGE,): + hours += (max(0.0, soc - cfg.soc_floor) / 100.0 * cap_kwh + / max(cfg.discharge_w / 1000.0, 0.1)) + return hours + + +def peak_run(c, day0, day1, now, shadow, limit_w): + """While the batteries hold the grid under the peak limit, one block for + the current 15-minute period on every battery.""" + pg = c.peak_guard + if pg is None or not pg.engaged: + return [] + start = now - timedelta(minutes=now.minute % 15, seconds=now.second, + microseconds=now.microsecond) + end = start + timedelta(minutes=15) + return [_run(i, "peak", start, end, day0, day1, + run_peak_what(pg.ceiling_w or limit_w, shadow), + run_peak_why(), None) + for i in range(len(c.inverters))] + + +def house_runs(n, day0, day1, now, shadow): + """"Follows the house" for the rest of the day, drawn under the others.""" + return [_run(i, "house", max(now, day0), day1, day0, day1, + run_house_what(shadow), run_house_why(shadow), + run_house_amount()) + for i in range(n)] + + +def region_of(opts): + """The levies preset and its year, as the page model has it (UX-13 P0).""" + try: + ui = options_to_ui(opts) + except Exception: # noqa: BLE001 + return {"id": None, "year": None} + rid = ui.get("ui.region") + return {"id": rid, "year": ui.get("region_year") + if rid in REGION_PRESETS else None} + + +def build_plan(c, now, shadow, running, held=False): + day0, day1 = local_day(now) + fresh = c.fresh_tariff_plan(now) + plan = fresh + if plan is None or plan.origin == "static": + # A static profile is pure arithmetic: price the whole day from it. + try: + static = static_plan(c.o, day0, day1, now=now) + if static.has_prices: + plan = static + except Exception: # noqa: BLE001 + pass + seen = _day_prices(c).see(_points(plan), day0, day1) + bars = hour_bars(seen, day0, day1) + + limit_w = c.peak.cap_w # the limit the controller parsed at start + runs, lines = [], [] + # The control cycle trades on the fresh plan only, so this does too. + verdict, trade_why = trade_verdict(c, fresh) + if running: + runs += house_runs(len(c.inverters), day0, day1, now, shadow) + if verdict is not None: + trade, later = trade_runs(c, fresh, verdict, day0, day1, now, + shadow) + runs += trade + for kind, pt in later: + lines.append(line_trade_tomorrow(kind, hhmm(pt.start), + pt.eur_per_kwh, shadow)) + else: + lines.append(line_no_trade(trade_why)) + cyc, waits = maintenance_runs(c, day0, day1, now, shadow) + runs += cyc + lines += waits + runs += peak_run(c, day0, day1, now, shadow, limit_w) + if c.p1_enabled: + lines.append(line_peak_limit(limit_w, shadow)) + lines = [x for x in lines if x] + + kinds = {r["kind"] for r in runs} + if held: + verdict_key = "held" + elif not running: + verdict_key = "stopped" + elif "cycle" in kinds: + verdict_key = "cycle" + elif "grid" in kinds or "give" in kinds: + verdict_key = "trade" + else: + verdict_key = "house" + + known = [b for b in bars if b["eur_kwh"] is not None] + price_now = None + try: + if plan is not None: + price_now = plan.price_at(now) + except Absence: + price_now = None + feed = fresh is not None and fresh.from_feed + tomorrow = any(not p.provisional and p.start >= day1 + for p in _points(fresh)) + region = region_of(c.o) + return { + "day": brussels(now).date().isoformat(), + "now_h": round(_hours(now, day0), 3), + "hours": int(round(_hours(day1, day0))), + "verdict": VERDICT[verdict_key], + "verdict_key": verdict_key, + "head": plan_head(verdict_key, shadow), + "prices": bars, + "runs": runs, + "lines": lines, + "why": c.why_words, + "price_line": line_prices( + price_now, + min(known, key=lambda b: b["eur_kwh"]) if known else None, + max(known, key=lambda b: b["eur_kwh"]) if known else None), + "tomorrow_line": line_tomorrow(tomorrow) if feed else "", + "region": region, + "region_line": (line_region(region["id"], region["year"]) + if feed else ""), + "has_prices": bool(known), + } + + +# --------------------------------------------------------------------------- # +# Batteries, attention, month peak, control +# --------------------------------------------------------------------------- # +def battery_rows(c, shadow, running, held=False): + shares = {} + alloc = getattr(c, "allocation", None) + if shadow and alloc is not None and getattr(alloc, "shares", None): + shares = dict(alloc.shares) + rows = [] + for i, inv in enumerate(c.inverters): + m = c.maints[i] if i < len(c.maints) else None + phase = m.phase if m is not None else M_IDLE + cap = inv.capacity_kwh + rows.append({ + "name": inv.name, + "level_pct": None if inv.soc is None else float(inv.soc), + "power_w": None if inv.batt is None else float(inv.batt), + "capacity_kwh": cap, + "stored_kwh": (None if cap is None or inv.soc is None + else round(cap * float(inv.soc) / 100.0, 2)), + "state": flow(inv.batt, shadow=shadow), + "mode": MODE_HOUSE, + "maintenance": phase, + "now": battery_now(inv.soc, inv.batt, phase=phase, shadow=shadow, + running=running, held=held, + would_w=shares.get(inv.name)), + # Per-battery reasons arrive with battery modes (OPT-11). + "why": None, + }) + return rows + + +# Row id -> the title on Home. The row's own sentence is the body. +ATTN_TITLES = { + "controller": "Control is not running", + "meter": "Meter reading", + "meter_frozen": messages.T_METER_FROZEN, + "freeze_check": "Stuck meter check", + "month_peak": "This month's peak", + "peak_guard": "Peak limit", + "peak_forecast": "Peak limit forecast", + "sensor": "Battery readings", + "control": "Inverter control", + "power_too_high": messages.T_OUTPUT_CLAMP, + "not_keeping_up": messages.T_LOOP_BOUND, + "write": "Power request not accepted", + "direction": "Power went the wrong way", + "site_direction": "Power went the wrong way", + "circulating": messages.T_CIRCULATING, + "delivery": messages.S_NOT_DELIVERING, + "estop": "Emergency stop", + "pv": "Solar reading", + None: "Inverter connection", +} +# Row id -> the DOCS.md heading under Notifications, where one exists. +ATTN_DOCS = { + "meter_frozen": messages.T_METER_FROZEN, + "power_too_high": messages.T_OUTPUT_CLAMP, + "not_keeping_up": messages.T_LOOP_BOUND, + "circulating": messages.T_CIRCULATING, + "delivery": messages.S_NOT_DELIVERING, +} + + +def attention(checks): + """Every row that is not plain green: red rows as alarms, amber rows as + warnings, and green-but-amber rows (a state still settling) as info. + Most urgent first; within a level, the page's own row order.""" + rank = {ALARM: 0, WARNING: 1, INFO: 2} + out = [] + for row in checks: + ok, warn = bool(row.get("ok")), bool(row.get("warn")) + if ok and not warn: + continue + sev = INFO if ok else (WARNING if warn else ALARM) + rid = row.get("id") + out.append({"severity": sev, "id": rid, + "title": ATTN_TITLES.get(rid, ATTN_TITLES[None]), + "body": row.get("text", ""), + "docs": ATTN_DOCS.get(rid)}) + out.sort(key=lambda a: rank[a["severity"]]) + return out + + +def month_peak(c, now): + """This month's peak against the limit, and the 15-minute period so far.""" + limit_w = c.peak.cap_w # the limit the controller parsed at start + local = brussels(now) + out = {"month": f"{local:%B}", "limit_w": limit_w, "peak_w": None, + "pct": None, "period_w": None, "state": "not_covered", + "line": ""} + if not c.p1_enabled: + out["line"] = line_peak_not_covered() + return out + reading = c.peak.peak(now) + if reading.is_unreadable: + out["state"] = "unreadable" + elif reading.is_observed: + out["state"] = "observed" + out["peak_w"] = float(reading.peak_w) + out["pct"] = round(100.0 * float(reading.peak_w) / limit_w, 1) \ + if limit_w > 0 else None + else: + out["state"] = "none" + pg = c.peak_guard + ceiling = limit_w + if pg is not None: + out["period_w"] = pg.projected_w + ceiling = pg.ceiling_w or limit_w + out["line"] = line_period(out["period_w"], ceiling, c.shadow) + return out + + +def state_of(c, level, shadow): + """One word for the pill and the banner's colour: running, shadow, + stopped, alarm or warning.""" + if shadow: + return "shadow" + if level == "bad": + return "alarm" + if not c.auto: + return "stopped" + if level == "warn": + return "warning" + return "running" + + +def build(c, *, level: str, checks: list, now: datetime | None = None) -> dict: + """The structured half of `/status`. Pure reads of the controller.""" + now = now or datetime.now(timezone.utc) + shadow = bool(c.shadow) + kind = state_of(c, level, shadow) + # A red banner means every inverter is at 0 W (the status cascade), so + # nothing is planned until it clears. Shadow mode still plans: it is + # what the add-on would do. + held = level == "bad" and not shadow + running = (bool(c.auto) or shadow) and not held + ctl = next((r for r in checks if r.get("id") == "controller"), None) + return { + "state": {"kind": kind, "pill": pill(kind), + "ran": ctl.get("text", "") if ctl else "", + "sub": banner_sub(kind)}, + "now": now_block(grid_w=c.grid, pv_w=c.pv_w, batt_w=c.site_batt_w, + has_solar=bool(c.pv_roster), shadow=shadow), + "batteries": battery_rows(c, shadow, running, held), + "plan": build_plan(c, now, shadow, running, held=held), + "attention": ([{"severity": INFO, "id": "shadow", + "title": ATTN_SHADOW, "body": attn_shadow_body(), + "docs": None}] if shadow else []) + attention(checks), + "month_peak": month_peak(c, now), + "control": {"running": bool(c.auto), "shadow": shadow, + "text": control_text(bool(c.auto), shadow), + "maintenance": c.maint.phase, + "docs_url": _docs_url()}, + } + + +def _docs_url(): + slug = messages.addon_slug() + return None if slug is None else messages.docs_url(slug, + messages._site["ha"]) + + +# =========================================================================== # +# The words. STYLE.md: plain, short, present tense. A plan line is at most +# two sentences of at most 12 words each (UX-13 design, section 4); a title at +# most 5 words; everything else one sentence of at most 25 words. In shadow +# mode a text says what the add-on WOULD do. test_messages.py renders every +# function below through `text_samples()` and checks it. +# =========================================================================== # +MODE_HOUSE = "Follows the house" +ATTN_SHADOW = "Shadow mode is on" + + +def attn_shadow_body() -> str: + return "The add-on decides everything, but every inverter stays at 0 W." + +VERDICT = { + "held": "Held at 0 W", + "stopped": "Stopped", + "cycle": "Monthly cycle today", + "trade": "Trading on price", + "house": "Follows the house", +} + + +def _w(shadow, live, would): + return would if shadow else live + + +def pill(kind) -> str: + return {"running": "Running", "shadow": "Shadow mode", + "stopped": "Stopped", "alarm": "Needs you now", + "warning": "Running, with a warning"}[kind] + + +def banner_sub(kind) -> str: + return { + "running": "The batteries follow the plan below.", + "shadow": "The plans below say what the add-on would do.", + "stopped": "Start control below when you are ready.", + "alarm": "See Needs attention below for what to do.", + "warning": "See Needs attention below.", + }[kind] + + +def tile_solar(pv_w, has_solar) -> str: + if not has_solar: + return "Not set up" + if pv_w is None: + return "No reading" + return "Producing" if pv_w > IDLE_W else "Not producing" + + +def tile_house(house_w, has_solar) -> str: + if not has_solar: + return "Needs a solar reading" + return "No reading" if house_w is None else "Using" + + +def tile_grid(grid_w) -> str: + if grid_w is None: + return "No reading" + if grid_w > IDLE_W: + return "Taking from the grid" + if grid_w < -IDLE_W: + return "Feeding in" + return "Balanced" + + +def tile_batt(batt_w, shadow) -> str: + if shadow: + return "Held at 0 W" + return {"giving": "Giving power", "charging": "Charging", + "resting": "Resting", None: "No reading"}[flow(batt_w)] + + +def battery_now(soc, batt_w, *, phase, shadow, running, held=False, + would_w=None) -> str: + if soc is None or batt_w is None: + return "No reading from this battery." + if shadow: + if would_w is None or abs(would_w) <= IDLE_W: + return "Held at 0 W. Would rest now." + verb = "give" if would_w > 0 else "charge" + return f"Held at 0 W. Would {verb} {_kw(would_w)} now." + if held: + return "Held at 0 W until the alarm clears." + if not running: + return "Held at 0 W while control is stopped." + if phase != M_IDLE: + return {M_DRAIN: "Monthly cycle: emptying.", + M_CHARGE: "Monthly cycle: refilling.", + M_HOLD: "Monthly cycle: holding full."}.get( + phase, "Monthly cycle under way.") + st = flow(batt_w) + if st == "giving": + return f"Giving {_kw(batt_w)} now." + if st == "charging": + return f"Charging {_kw(batt_w)} now." + return "Resting now." + + +def plan_head(key, shadow) -> str: + if key == "held": + return "Every inverter is at 0 W until the alarm clears." + if key == "stopped": + return "Control is stopped, so nothing is planned." + if not shadow: + return { + "cycle": "A battery runs its monthly cycle today.", + "trade": "Charges in the cheapest hour, gives power in the dearest.", + "house": "Charges from spare solar and covers the house.", + }[key] + return "Shadow mode: this is what the add-on would do. " + { + "cycle": "A battery would run its monthly cycle today.", + "trade": "Would charge when cheapest and give power when dearest.", + "house": "Would charge from spare solar and cover the house.", + }[key] + + +def run_grid_what(kwh, shadow) -> str: + return _w(shadow, "Charges", "Would charge") + \ + f" up to {_kwh(kwh)} from the grid." + + +def run_grid_why(price) -> str: + return f"Cheapest price in the list, {_eur(price)} per kWh." + + +def run_grid_amount(eur) -> str: + return f"Costs up to {_eur(eur)}." + + +def run_give_what(kwh, shadow) -> str: + return _w(shadow, "Gives", "Would give") + \ + f" up to {_kwh(kwh)}, to the house first." + + +def run_give_why(price) -> str: + return f"Dearest price in the list, {_eur(price)} per kWh." + + +def run_give_amount(eur) -> str: + return f"Worth up to {_eur(eur)} at that price." + + +def run_cycle_what(phase, shadow) -> str: + if phase == M_IDLE: + return _w(shadow, "Starts", "Would start") + \ + " the monthly battery cycle." + return _w(shadow, "Runs", "Would run") + " the monthly battery cycle now." + + +def run_cycle_why(shadow=False) -> str: + return _w(shadow, "Empties, refills and holds full", + "Would empty, refill and hold full") + \ + ", so the level reads right." + + +def run_cycle_amount(hours) -> str: + if hours is None: + return "How long depends on the battery." + return f"Takes about {max(1, round(hours))} hours." + + +def run_peak_what(limit_w, shadow) -> str: + return _w(shadow, "Gives", "Would give") + \ + f" power to stay under {_kw(limit_w)}." + + +def run_peak_why() -> str: + return "The peak limit comes before everything else." + + +def run_house_what(shadow) -> str: + return _w(shadow, "Follows", "Would follow") + " the house." + + +def run_house_why(shadow=False) -> str: + return _w(shadow, "Charges from spare solar, gives power", + "Would charge from spare solar, give power") + \ + " when the house needs it." + + +def run_house_amount() -> str: + return "Amounts depend on the sun and the house." + + +def line_no_trade(key) -> str: + return { + "off": "", + "not_covered": "No trading on price: nothing measures the 15-minute " + "peak.", + "no_prices": "No trading on price yet: no prices have arrived.", + "peak": "No trading on price now: the peak limit comes first.", + "not_worth": "No trading on price today. The price gap is too small.", + }[key] + + +def line_trade_tomorrow(kind, at, price, shadow) -> str: + verb = {"grid": _w(shadow, "Charges", "Would charge"), + "give": _w(shadow, "Gives power", "Would give power")}[kind] + return f"Tomorrow: {verb.lower()} at {at}, {_eur(price)} per kWh." + + +def line_cycle_waits(name) -> str: + return f"{name} waits its turn for the monthly cycle." + + +def line_peak_limit(limit_w, shadow) -> str: + return _w(shadow, "The batteries step in", "The batteries would step in") \ + + f" above {_kw(limit_w)}." + + +def line_prices(now_eur, lo, hi) -> str: + parts = [] + if now_eur is not None: + parts.append(f"Price now {_eur(now_eur)} per kWh, all in.") + if lo is not None and hi is not None: + parts.append(f"Today: cheapest {_eur(lo['eur_kwh'])} at " + f"{lo['label']}, dearest {_eur(hi['eur_kwh'])} at " + f"{hi['label']}.") + return " ".join(parts) or "No prices for today." + + +def line_tomorrow(known) -> str: + return ("Tomorrow's prices are in." if known else + "Tomorrow's prices usually arrive after 13:00.") + + +def line_region(rid, year) -> str: + if rid in REGION_PRESETS and year: + return f"Levies and VAT: {REGION_WORDS.get(rid, rid)}, {year} figures." + return "Levies and VAT: your own figure." + + +REGION_WORDS = {"flanders": "Flanders, Fluvius Antwerpen"} + + +def line_peak_not_covered() -> str: + return "No peak limit: this meter does not measure 15-minute periods." + + +def line_period(period_w, limit_w, shadow) -> str: + step = _w(shadow, "The batteries step in", "The batteries would step in") + if period_w is None: + return f"{step} above {_kw(limit_w)}." + return (f"This 15-minute period is heading for {_kw(period_w)}. " + f"{step} above {_kw(limit_w)}.") + + +def control_text(running, shadow) -> str: + if shadow: + return "Shadow mode: every inverter stays at 0 W." + if running: + return "Control is running." + return "Control is stopped. Every inverter is at 0 W." + + +def text_samples() -> list: + """`(kind, text)` for every sentence above, rendered with real values, so + test_messages.py can hold each to its STYLE limit. Kinds: title, plan + (2 sentences of 12 words), line (1 sentence of 25 words).""" + out = [("title", t) for t in VERDICT.values()] + out += [("title", t) for t in ATTN_TITLES.values()] + out += [("title", MODE_HOUSE), ("title", ATTN_SHADOW), + ("line", attn_shadow_body())] + for k in ("running", "shadow", "stopped", "alarm", "warning"): + out += [("title", pill(k)), ("line", banner_sub(k))] + for sh in (False, True): + out += [("title", tile_solar(v, s)) for v, s in + ((None, False), (None, True), (3900, True), (0, True))] + out += [("title", tile_house(v, s)) for v, s in + ((None, False), (None, True), (1100, True))] + out += [("title", tile_grid(v)) for v in (None, 1200, -800, 5)] + out += [("title", tile_batt(v, sh)) for v in (None, 2500, -2500, 0)] + for phase in (M_IDLE, M_DRAIN, M_CHARGE, M_HOLD): + for w in (2500, -2500, 0): + out.append(("plan", battery_now(62, w, phase=phase, + shadow=sh, running=True, + would_w=-2400))) + out.append(("plan", battery_now(62, 0, phase=M_IDLE, shadow=sh, + running=False))) + out.append(("plan", battery_now(62, 0, phase=M_IDLE, shadow=False, + running=False, held=True))) + out.append(("plan", battery_now(None, None, phase=M_IDLE, shadow=sh, + running=True))) + for k in VERDICT: + out.append(("plan", plan_head(k, sh))) + out += [("plan", run_grid_what(12.34, sh)), + ("plan", run_give_what(9.6, sh)), + ("plan", run_cycle_what(M_IDLE, sh)), + ("plan", run_cycle_what(M_DRAIN, sh)), + ("plan", run_peak_what(3500, sh)), + ("plan", run_house_what(sh)), + ("plan", line_trade_tomorrow("grid", "02:00", 0.1234, sh)), + ("plan", line_trade_tomorrow("give", "19:00", 0.3612, sh)), + ("plan", line_peak_limit(3500, sh)), + ("plan", line_period(1240, 3500, sh)), + ("plan", line_period(None, 3500, sh)), + ("plan", control_text(True, sh)), + ("plan", control_text(False, sh))] + out += [("plan", run_grid_why(0.1412)), ("plan", run_grid_amount(1.23)), + ("plan", run_give_why(0.3612)), ("plan", run_give_amount(3.47)), + ("plan", run_cycle_why()), ("plan", run_cycle_why(True)), + ("plan", run_cycle_amount(None)), + ("plan", run_cycle_amount(5.4)), ("plan", run_peak_why()), + ("plan", run_house_why()), ("plan", run_house_why(True)), + ("plan", run_house_amount()), + ("plan", line_cycle_waits("Battery B")), + ("plan", line_prices(0.16, {"eur_kwh": 0.14, "label": "13:00"}, + {"eur_kwh": 0.36, "label": "19:00"})), + ("plan", line_prices(None, None, None)), + ("plan", line_tomorrow(True)), ("plan", line_tomorrow(False)), + ("plan", line_region("flanders", 2026)), + ("plan", line_region("own", None)), + ("plan", line_peak_not_covered())] + out += [("plan", line_no_trade(k)) for k in + ("not_covered", "no_prices", "peak", "not_worth")] + return out diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 03a008f..b35d5c8 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -54,6 +54,7 @@ from .clamp import ( clamp_to_rating, is_commandable, loop_clamp_note, write_clamp_note, ) from . import freshness +from . import homeview from . import messages from .freeze import ( FreezeWatchdog, FreezeWatchdogConfig, looks_frozen, rail_unreachable, rail_w, @@ -1047,6 +1048,9 @@ class Controller: # because `self.peak_guard` is a different cycle's decision by the time # the status page renders. self.arb_headroom_w = None + # UX-13 P1: today's prices as the Home chart has seen them. Display + # only; nothing reads it back into a decision. + self.home_prices = homeview.DayPrices() # TARIFF-11. When the most recent cycle() STARTED. `arb_at < cycle_at` # is the exact, derived statement of "the latest cycle did not get as # far as the arbitrage step", which is the fact the *Arbitrage* row @@ -5508,7 +5512,7 @@ class Controller: decided_at=self.arb_at, cycle_at=self.cycle_at, now=datetime.now(timezone.utc), why=self.why_words)), ] - return { + out = { "banner": banner, "level": level, "rows": rows, "checks": checks, "hint": self.hint, # The action log itself, newest first. The page does not show it @@ -5517,6 +5521,21 @@ class Controller: # peak guard's projection) are written nowhere else. "events": list(self.events), } + # UX-13 P1: the Home screen's structured half. Read-only, and it may + # never cost the page its rows: a fault here is logged and the old + # fields are served alone (the page then shows the installer details). + try: + out.update(homeview.build(self, level=level, checks=checks)) + except Exception: # noqa: BLE001 + # Once per process at ERROR: the page polls every 3 s. + if not getattr(self, "_home_failed", False): + self._home_failed = True + _LOG.exception("Home view could not be built, so the page " + "shows the plain status rows only") + else: + _LOG.debug("Home view failed again", exc_info=True) + out["home_error"] = True + return out async def handle_action(self, what: str): now = datetime.now(timezone.utc) diff --git a/goodwe_controller/app/static/app.css b/goodwe_controller/app/static/app.css new file mode 100644 index 0000000..826b35d --- /dev/null +++ b/goodwe_controller/app/static/app.css @@ -0,0 +1,137 @@ +/* UX-13 page styles. Colours follow the approved mockup (UX-13-mockup.html, + version 2) and prefers-color-scheme. No web fonts, no external files. */ +:root{ + --bg:#f3f4f6;--card:#ffffff;--ink:#1b1d21;--muted:#5b626c;--faint:#8a919b;--line:#e2e5e9; + --accent:#1c64d9;--accent-soft:#e6efff;--on-accent:#ffffff; + --ok:#17773a;--ok-bg:#e6f4eb;--warn:#955300;--warn-bg:#fcefd9;--bad:#c02626;--bad-bg:#fce8e8;--info:#5b626c;--info-bg:#eceef1; + --solar:#c98a00;--house:#6c47c2;--grid:#56657a;--batt:#17773a; + --cheap:#8fcca4;--dear:#f0ad72;--mid:#cfd5dc;--track:#dde1e6;--shadow:0 1px 2px rgba(0,0,0,.05); +} +@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){ + --bg:#111317;--card:#1a1d23;--ink:#e7e9ec;--muted:#a2a9b3;--faint:#7c848f;--line:#2b3038; + --accent:#6ea2ff;--accent-soft:#1d2a44;--on-accent:#0b1220; + --ok:#7ccf98;--ok-bg:#15291d;--warn:#f3c16b;--warn-bg:#2e2412;--bad:#f28b82;--bad-bg:#3a1a19;--info:#a2a9b3;--info-bg:#22262d; + --solar:#f0c04a;--house:#b39cf0;--grid:#9fb0c6;--batt:#7ccf98; + --cheap:#3f7d56;--dear:#9a5a26;--mid:#3a414b;--track:#343a44;--shadow:none; +}} +:root[data-theme="dark"]{ + --bg:#111317;--card:#1a1d23;--ink:#e7e9ec;--muted:#a2a9b3;--faint:#7c848f;--line:#2b3038; + --accent:#6ea2ff;--accent-soft:#1d2a44;--on-accent:#0b1220; + --ok:#7ccf98;--ok-bg:#15291d;--warn:#f3c16b;--warn-bg:#2e2412;--bad:#f28b82;--bad-bg:#3a1a19;--info:#a2a9b3;--info-bg:#22262d; + --solar:#f0c04a;--house:#b39cf0;--grid:#9fb0c6;--batt:#7ccf98; + --cheap:#3f7d56;--dear:#9a5a26;--mid:#3a414b;--track:#343a44;--shadow:none; +} +*{box-sizing:border-box} +[hidden]{display:none!important} +html{-webkit-text-size-adjust:100%} +body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;overflow-x:hidden} +button,input,select{font:inherit;color:inherit} +a{color:var(--accent)} +:focus-visible{outline:2px solid var(--accent);outline-offset:2px} +.top{display:flex;align-items:center;gap:12px;padding:12px 16px 8px;max-width:820px;margin:0 auto} +.logo{width:36px;height:36px;border-radius:10px;background:var(--accent-soft);display:grid;place-items:center;color:var(--accent);flex:none} +.app{font-weight:700;font-size:17px;line-height:1.2} +.pill{display:flex;flex-wrap:wrap;align-items:center;gap:0 6px;font-size:13px;color:var(--muted)} +.dot{width:8px;height:8px;border-radius:50%;background:var(--ok);flex:none} +.dot.warn{background:var(--warn)}.dot.bad{background:var(--bad)} +.tabs{display:flex;gap:4px;max-width:820px;margin:0 auto;padding:0 16px;border-bottom:1px solid var(--line)} +.tab{border:0;background:none;padding:10px 12px;border-bottom:2px solid transparent;color:var(--muted);cursor:pointer;display:flex;align-items:center;gap:6px;min-height:44px;position:relative} +.tab[aria-selected="true"]{color:var(--accent);border-bottom-color:var(--accent);font-weight:600} +.tab svg{width:20px;height:20px} +.badge{font-size:11px;font-weight:700;background:var(--warn);color:var(--card);border-radius:9px;padding:0 6px;line-height:18px} +.badge.bad{background:var(--bad)} +@media (max-width:640px){ + .tabs{position:fixed;bottom:0;left:0;right:0;z-index:20;background:var(--card);border-top:1px solid var(--line);border-bottom:0;padding:0 4px env(safe-area-inset-bottom);justify-content:space-around;gap:0} + .tab{flex-direction:column;gap:0;font-size:11px;padding:6px 4px;border-bottom:0;border-top:2px solid transparent;flex:1;min-width:0} + .tab[aria-selected="true"]{border-top-color:var(--accent)} + .tab .badge{position:absolute;top:2px;left:calc(50% + 6px)} + .wrap{padding-bottom:96px!important} +} +.wrap{max-width:820px;margin:0 auto;padding:16px 16px 40px} +h2{font-size:15px;margin:0 0 10px;font-weight:650} +.card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px;margin-bottom:12px;box-shadow:var(--shadow)} +.muted{color:var(--muted)} .small{font-size:13px} .tiny{font-size:12px} +.row{display:flex;align-items:center;gap:10px;flex-wrap:wrap} +.spread{justify-content:space-between} +.grow{flex:1 1 auto;min-width:0} +.banner{border-radius:12px;padding:12px 14px;margin-bottom:12px;display:flex;gap:10px;align-items:flex-start;font-weight:600} +.banner .ic{flex:none;margin-top:2px} +.b-ok{background:var(--ok-bg);color:var(--ok)} .b-warn{background:var(--warn-bg);color:var(--warn)} .b-bad{background:var(--bad-bg);color:var(--bad)} +.banner small{display:block;font-weight:400;color:var(--ink);margin-top:2px} +.tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px} +@media (max-width:640px){.tiles{grid-template-columns:repeat(2,minmax(0,1fr))}} +.tile{border:1px solid var(--line);border-radius:10px;padding:10px;min-width:0} +.tile .lab{font-size:13px;color:var(--muted);display:flex;align-items:center;gap:6px} +.tile .val{font-size:22px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1.25;margin-top:2px} +.tile .val small{font-size:13px;font-weight:500;color:var(--muted)} +.tile .sub{font-size:12px;color:var(--muted)} +.sw-solar{color:var(--solar)} .sw-house{color:var(--house)} .sw-grid{color:var(--grid)} .sw-batt{color:var(--batt)} +.brow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 10px;padding:10px 0;border-top:1px solid var(--line)} +.brow:first-child{border-top:0} +.lvl{height:10px;background:var(--track);border-radius:6px;overflow:hidden;grid-column:1/-1;margin:4px 0 2px} +.lvl>i{display:block;height:100%;background:var(--batt);border-radius:6px} +.lvl.none>i{background:var(--faint)} +/* the plan chart */ +.chart{position:relative;margin:18px 0 4px} +.bars{display:flex;align-items:flex-end;gap:2px;height:72px} +.bars i{flex:1;border-radius:3px 3px 0 0;background:var(--mid);min-width:0} +.bars i.cheap{background:var(--cheap)} +/* not by colour alone: expensive hours are striped, estimates are faded */ +.bars i.dear{background:repeating-linear-gradient(135deg,var(--dear) 0 4px,color-mix(in srgb,var(--dear) 60%,var(--card)) 4px 7px)} +.bars i.est{opacity:.55} +.bars i.none{background:none;border-bottom:2px dotted var(--faint);height:2px!important} +.lane{position:relative;height:18px;margin-top:4px;background:var(--bg);border-radius:4px} +.lane b{position:absolute;top:2px;bottom:2px;border-radius:3px;min-width:3px} +.lane .house{background:repeating-linear-gradient(90deg,var(--mid) 0 6px,transparent 6px 9px);top:6px;bottom:6px} +.lane .grid{background:var(--accent)} +.lane .give{background:repeating-linear-gradient(135deg,var(--house) 0 4px,color-mix(in srgb,var(--house) 55%,var(--card)) 4px 7px)} +.lane .cycle{background:repeating-linear-gradient(90deg,var(--warn) 0 3px,var(--warn-bg) 3px 6px)} +.lane .peak{background:var(--bad)} +.lanelab{font-size:12px;color:var(--muted);margin-top:6px} +.nowline{position:absolute;top:-4px;bottom:0;width:2px;background:var(--ink);opacity:.7;pointer-events:none} +.nowline span{position:absolute;top:-15px;left:-10px;font-size:10px} +.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--faint);margin-top:4px} +.legend{display:flex;flex-wrap:wrap;gap:4px 12px;font-size:12px;color:var(--muted);margin-top:8px} +.legend span{display:inline-flex;align-items:center;gap:5px} +.legend i{width:14px;height:10px;border-radius:2px;display:inline-block} +.legend i.house{background:repeating-linear-gradient(90deg,var(--mid) 0 4px,transparent 4px 6px)} +ul.plain{list-style:none;margin:8px 0 0;padding:0} +ul.plain li{padding:6px 0;border-top:1px solid var(--line)} +ul.plain li:first-child{border-top:0} +.meter{height:12px;background:var(--track);border-radius:6px;overflow:hidden;margin:8px 0 4px} +.meter i{display:block;height:100%;background:var(--accent)} +.meter i.warn{background:var(--warn)} .meter i.bad{background:var(--bad)} +.alert{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)} +.alert:first-child{border-top:0} +.sev{flex:none;width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-size:13px;font-weight:800} +.sev.warning{background:var(--warn-bg);color:var(--warn)} .sev.alarm{background:var(--bad-bg);color:var(--bad)} .sev.info{background:var(--info-bg);color:var(--info)} .sev.ok{background:var(--ok-bg);color:var(--ok)} +.alert .t{font-weight:600} +.btn{border:1px solid var(--line);background:var(--card);padding:9px 14px;border-radius:10px;cursor:pointer;min-height:44px} +.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent);font-weight:600} +.btn.danger{color:var(--bad);border-color:var(--bad)} +.btn:disabled{opacity:.5;cursor:not-allowed} +a.btn{display:inline-flex;align-items:center;text-decoration:none;color:var(--ink)} +details.more{margin-top:12px;border-top:1px solid var(--line)} +details.more>summary{cursor:pointer;padding:10px 0;color:var(--accent);font-size:14px;min-height:44px;display:flex;align-items:center} +table.rows{width:100%;border-collapse:collapse;font-size:13px} +table.rows td{padding:6px 0;border-bottom:1px solid var(--line);vertical-align:top} +table.rows td:last-child{text-align:right;font-variant-numeric:tabular-nums;font-weight:600;padding-left:12px;overflow-wrap:anywhere} +table.rows tr:last-child td{border-bottom:0} +ul.checks{margin:6px 0 0;padding-left:0;list-style:none;font-size:13px} +ul.checks li{margin:3px 0} +.c-ok{color:var(--ok)} .c-warn{color:var(--warn)} .c-bad{color:var(--bad)} +.kv{display:grid;grid-template-columns:auto minmax(0,1fr);gap:4px 12px;font-size:14px;margin-top:10px} +.kv dt{color:var(--muted)} .kv dd{margin:0} +#toast{position:fixed;left:50%;transform:translateX(-50%);bottom:24px;z-index:30;background:var(--ink);color:var(--bg);padding:10px 14px;border-radius:10px;font-size:14px;max-width:calc(100% - 32px);opacity:0;pointer-events:none;transition:opacity .2s} +#toast.show{opacity:1} +@media (max-width:640px){#toast{bottom:84px}} +dialog{border:1px solid var(--line);border-radius:14px;background:var(--card);color:var(--ink);max-width:min(420px,calc(100% - 32px));padding:18px} +dialog::backdrop{background:rgba(0,0,0,.45)} +@media (prefers-reduced-motion:reduce){*{transition:none!important}} +.tip{position:fixed;z-index:40;background:var(--ink);color:var(--bg);font-size:12px;line-height:1.35;padding:6px 8px;border-radius:8px;pointer-events:none;max-width:240px;opacity:0;transition:opacity .1s;box-shadow:0 2px 8px rgba(0,0,0,.25);left:0;top:0} +.tip.show{opacity:1} +.tip b{display:block;font-weight:700} +.tip span{display:block} +.chart [data-tip]{cursor:default} +.chart [data-tip]:hover,.chart [data-tip]:focus,.chart .hot{outline:2px solid var(--ink);outline-offset:-1px} +.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap} diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js new file mode 100644 index 0000000..01f9d0a --- /dev/null +++ b/goodwe_controller/app/static/app.js @@ -0,0 +1,368 @@ +"use strict"; +/* UX-13 P1: the page shell and the Home screen. Plain JS, no framework, no + external files. Every URL is relative, because ingress serves the add-on + under a generated path prefix. Every word comes from app/ui_text (fixed + labels) or from /status (sentences built by app/homeview.py), so STYLE.md + is checked in Python. Data is always set as text, never as HTML. */ +(function () { + const T = JSON.parse(document.getElementById("ui-text").textContent).home; + const $ = (s) => document.querySelector(s); + const t = (path) => path.split(".").reduce((o, k) => (o == null ? o : o[k]), T); + function h(tag, attrs, ...kids) { + const e = document.createElement(tag); + for (const k in attrs || {}) { + const v = attrs[k]; + if (v === false || v == null) continue; + if (k === "class") e.className = v; + else if (k === "style") e.style.cssText = v; + else if (k.startsWith("on")) e.addEventListener(k.slice(2), v); + else e.setAttribute(k, v === true ? "" : v); + } + for (const c of kids.flat()) { + if (c == null || c === false) continue; + e.append(c.nodeType ? c : document.createTextNode(String(c))); + } + return e; + } + const kw = (w) => (Math.abs(Number(w)) / 1000).toFixed(1); + const eur = (v) => "€" + Number(v).toFixed(2); + + // Fixed labels from ui_text. + document.querySelectorAll("[data-t]").forEach((e) => { e.textContent = t(e.dataset.t) || ""; }); + document.querySelectorAll("[data-t-label]").forEach((e) => { e.setAttribute("aria-label", t(e.dataset.tLabel) || ""); }); + + let S = null; // the last /status + let busy = false; + + /* ---------------- toast and confirm dialog ---------------- */ + function toast(text) { + const e = $("#toast"); e.textContent = text; e.classList.add("show"); + clearTimeout(toast.timer); toast.timer = setTimeout(() => e.classList.remove("show"), 2600); + } + let onYes = null; + function ask(key, fn) { + $("#dlg-t").textContent = t("dialog." + key + ".name"); + $("#dlg-b").textContent = t("dialog." + key + ".description"); + $("#dlg-yes").textContent = t("dialog." + key + ".yes"); + onYes = fn; + const d = $("#dlg"); + if (typeof d.showModal === "function") d.showModal(); else if (window.confirm($("#dlg-t").textContent)) fn(); + } + $("#dlg-no").addEventListener("click", () => $("#dlg").close()); + $("#dlg-yes").addEventListener("click", () => { $("#dlg").close(); if (onYes) onYes(); }); + + /* ---------------- data ---------------- */ + async function getStatus() { + const r = await fetch("status", { cache: "no-store" }); + if (!r.ok) throw new Error("status " + r.status); + return r.json(); + } + async function act(what) { + const r = await fetch("action", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ action: what }) }); + if (!r.ok) throw new Error("action " + r.status); + return r.json(); + } + async function refresh() { + if (busy) return; + busy = true; + try { S = await getStatus(); render(); } + catch (e) { offline(); } + finally { busy = false; } + } + + /* ---------------- shell ---------------- */ + function banner(el, level, title, sub, role) { + el.replaceChildren(h("div", { class: "banner " + ({ ok: "b-ok", bad: "b-bad" }[level] || "b-warn"), role: role || null }, + h("span", { class: "ic", "aria-hidden": "true" }, { ok: "✓", bad: "×" }[level] || "!"), + h("span", {}, title, sub ? h("small", {}, sub) : null))); + } + function offline() { + banner($("#home-banner"), "bad", t("offline.name"), t("offline.description"), "alert"); + $("#pill").replaceChildren(h("span", { class: "dot bad" }), h("span", {}, t("offline.name"))); + } + function renderPill() { + const st = S.state || null; + const dot = st ? ({ running: "", shadow: " warn", stopped: " warn", warning: " warn", alarm: " bad" }[st.kind] ?? " warn") + : (S.level === "ok" ? "" : S.level === "bad" ? " bad" : " warn"); + const words = st ? [st.pill, st.ran].filter(Boolean).join(". ") : S.banner; + $("#pill").replaceChildren(h("span", { class: "dot" + dot, "aria-hidden": "true" }), h("span", {}, words)); + } + + function render() { + renderPill(); + const structured = S.now && S.plan && !S.home_error; + banner($("#home-banner"), S.level, S.banner, structured ? S.state.sub : "", S.level === "bad" ? "alert" : null); + ["#c-now", "#c-plan", "#c-peak", "#c-attn"].forEach((id) => { $(id).hidden = !structured; }); + if (structured) { renderNow(); renderPlan(); renderPeak(); renderAttention(); } + renderControl(structured); + renderDetails(!structured); + renderBatteries(); + renderSettings(); + } + + /* ---------------- Home: now ---------------- */ + function val(id, w, show) { + const e = $(id); + if (w == null || !show) { e.textContent = "–"; return; } + e.replaceChildren(kw(w) + " ", h("small", {}, "kW")); + } + function levelBar(pct, label) { + const known = pct != null; + return h("div", { class: "lvl" + (known ? "" : " none"), role: "img", + "aria-label": label + " " + (known ? Math.round(pct) + " %" : "–") }, + h("i", { style: "width:" + (known ? Math.max(0, Math.min(100, pct)) : 0) + "%" })); + } + function renderNow() { + const n = S.now; + val("#v-solar", n.solar_w, n.has_solar); $("#sub-solar").textContent = n.lines.solar; + val("#v-house", n.house_w, true); $("#sub-house").textContent = n.lines.house; + val("#v-grid", n.grid_w, true); $("#sub-grid").textContent = n.lines.grid; + val("#v-batt", n.batt_w, true); $("#sub-batt").textContent = n.lines.batt; + $("#home-batts").replaceChildren(...S.batteries.map((b) => h("div", { class: "brow" }, + h("div", {}, h("strong", {}, b.name), h("span", { class: "muted small" }, " · " + b.mode)), + h("div", { class: "small", style: "font-variant-numeric:tabular-nums" }, b.level_pct == null ? "–" : Math.round(b.level_pct) + " %"), + levelBar(b.level_pct, b.name), + h("div", { class: "small muted", style: "grid-column:1/-1" }, b.now)))); + } + + /* ---------------- Home: today's plan ---------------- */ + const LEGEND = [["cheap", "background:var(--cheap)"], ["dear", "background:repeating-linear-gradient(135deg,var(--dear) 0 3px,transparent 3px 5px)"], + ["grid", "background:var(--accent)"], ["give", "background:repeating-linear-gradient(135deg,var(--house) 0 3px,transparent 3px 5px)"], + ["cycle", "background:repeating-linear-gradient(90deg,var(--warn) 0 2px,transparent 2px 4px)"], + ["peak", "background:var(--bad)"], ["house", null]]; + function tipText(lines) { return lines.filter(Boolean).join(" "); } + function chartItem(tag, cls, style, title, lines) { + return h(tag, { class: cls, style: style, tabindex: "-1", role: "img", "aria-label": tipText([title + "."].concat(lines)), + "data-tip": JSON.stringify([title].concat(lines.filter(Boolean))) }); + } + function roving(group) { + const items = [...group.querySelectorAll("[data-tip]")]; + items.forEach((el, i) => { + el.tabIndex = i === 0 ? 0 : -1; + el.addEventListener("keydown", (e) => { + const d = { ArrowRight: 1, ArrowLeft: -1, Home: -1e9, End: 1e9 }[e.key]; + if (d === undefined) return; + e.preventDefault(); + const j = Math.max(0, Math.min(items.length - 1, i + d)); + items[i].tabIndex = -1; items[j].tabIndex = 0; items[j].focus(); + }); + }); + } + function renderPlan() { + const p = S.plan; + $("#verdict").textContent = p.verdict; + $("#plan-head").textContent = p.head; + const hours = p.hours || 24; + const bars = $("#bars"); + const known = p.prices.filter((b) => b.eur_kwh != null); + const mx = Math.max(0.01, ...known.map((b) => Math.abs(b.eur_kwh))); + bars.setAttribute("aria-label", t("plan.name")); + bars.replaceChildren(...p.prices.map((b) => { + const title = b.label + " " + t("plan.time_to") + " " + b.end_label; + if (b.eur_kwh == null) return chartItem("i", "none", "", title, [t("plan.none_tip") + "."]); + const kind = b.kind === "cheap" ? ", " + t("plan.cheap_tip") : b.kind === "dear" ? ", " + t("plan.dear_tip") : ""; + const est = b.estimate ? ", " + t("plan.estimate_tip") : ""; + return chartItem("i", (b.kind || "mid") + (b.estimate ? " est" : ""), + "height:" + Math.max(4, Math.round(Math.abs(b.eur_kwh) / mx * 100)) + "%", + title, [eur(b.eur_kwh) + " " + t("plan.per_kwh") + kind + est + "."]); + })); + roving(bars); + $("#no-prices").hidden = known.length > 0; + const lanes = $("#lanes"); + lanes.replaceChildren(); + S.batteries.forEach((b, i) => { + const lane = h("div", { class: "lane", role: "group", "aria-label": b.name }); + const runs = p.runs.filter((r) => r.battery === i).sort((a, z) => (a.kind === "house" ? -1 : 0) - (z.kind === "house" ? -1 : 0)); + for (const r of runs) { + if (r.end_h <= r.start_h) continue; + lane.append(chartItem("b", r.kind, "left:" + (r.start_h / hours * 100) + "%;width:" + ((r.end_h - r.start_h) / hours * 100) + "%", + b.name + ", " + r.from + " " + t("plan.time_to") + " " + r.to, [r.what, r.why, r.amount])); + } + lanes.append(h("div", { class: "lanelab", "aria-hidden": "true" }, b.name), lane); + roving(lane); + }); + const nl = $("#nowline"); + nl.style.left = Math.max(0, Math.min(100, p.now_h / hours * 100)) + "%"; + const used = new Set(p.runs.map((r) => r.kind)); + known.forEach((b) => used.add(b.kind)); + $("#legend").replaceChildren(...LEGEND.filter(([k]) => used.has(k)).map(([k, css]) => + h("span", {}, h("i", { class: k === "house" ? "house" : null, style: css, "aria-hidden": "true" }), t("plan." + k)))); + const list = []; + S.batteries.forEach((b, i) => { + for (const r of p.runs.filter((x) => x.battery === i && x.kind !== "house")) { + list.push(h("li", {}, h("strong", {}, b.name + ", " + r.from + " " + t("plan.time_to") + " " + r.to + ": "), tipText([r.what, r.why, r.amount]))); + } + const house = p.runs.find((x) => x.battery === i && x.kind === "house"); + if (house) list.push(h("li", {}, h("strong", {}, b.name + ": "), tipText([house.what, house.why]))); + }); + for (const line of p.lines) list.push(h("li", {}, line)); + $("#plan-list").replaceChildren(...list); + $("#price-line").textContent = [p.price_line, p.tomorrow_line, p.region_line].filter(Boolean).join(" "); + } + + /* ---------------- tooltips: hover, tap and keyboard focus ---------------- */ + (function () { + const tip = $("#tip"); let hot = null; + const hide = () => { tip.classList.remove("show"); if (hot) hot.classList.remove("hot"); hot = null; }; + function show(el, x, y) { + if (hot && hot !== el) hot.classList.remove("hot"); + hot = el; el.classList.add("hot"); + const lines = JSON.parse(el.dataset.tip); + tip.replaceChildren(h("b", {}, lines[0]), ...lines.slice(1).map((l) => h("span", {}, l))); + tip.classList.add("show"); + const r = tip.getBoundingClientRect(); + let L = x + 12, T2 = y - r.height - 12; + if (L + r.width > innerWidth - 8) L = x - r.width - 12; + if (L < 8) L = 8; + if (T2 < 8) T2 = y + 16; + tip.style.left = L + "px"; tip.style.top = T2 + "px"; + } + const target = (e) => e.target.closest && e.target.closest(".chart [data-tip]"); + document.addEventListener("pointermove", (e) => { + if (e.pointerType === "touch") return; + const el = target(e); + if (el) show(el, e.clientX, e.clientY); else if (hot && document.activeElement !== hot) hide(); + }); + document.addEventListener("pointerdown", (e) => { + const el = target(e); + if (el && e.pointerType === "touch") { if (hot === el) hide(); else show(el, e.clientX, e.clientY); } + else if (!el) hide(); + }); + document.addEventListener("focusin", (e) => { + const el = target(e); + if (el) { const r = el.getBoundingClientRect(); show(el, r.left + r.width / 2, r.top); } + }); + document.addEventListener("focusout", (e) => { if (target(e)) hide(); }); + document.addEventListener("keydown", (e) => { if (e.key === "Escape") hide(); }); + addEventListener("scroll", hide, { passive: true }); + })(); + + /* ---------------- Home: peak, attention, control, details ---------------- */ + function renderPeak() { + const m = S.month_peak; + $("#peak-month").textContent = m.month; + const covered = m.state !== "not_covered"; + $("#peak-figures").hidden = !covered; $("#peak-meter").hidden = !covered; + $("#peak-now").textContent = m.peak_w != null ? kw(m.peak_w) + " kW" + : m.state === "unreadable" ? t("peak.unreadable") : t("peak.none"); + $("#peak-limit").textContent = kw(m.limit_w) + " kW"; + const pct = m.pct == null ? 0 : Math.max(0, Math.min(100, m.pct)); + const bar = $("#peak-meter i"); + bar.style.width = pct + "%"; + bar.className = pct >= 100 ? "bad" : pct >= 80 ? "warn" : ""; + $("#peak-meter").setAttribute("aria-label", t("peak.this_month") + " " + (m.pct == null ? "–" : Math.round(m.pct) + " %")); + $("#peak-line").textContent = m.line; + } + function renderAttention() { + const list = S.attention; + const icon = { alarm: "×", warning: "!", info: "i" }; + $("#alerts").replaceChildren(...list.map((a) => h("div", { class: "alert" }, + h("span", { class: "sev " + a.severity, "aria-hidden": "true" }, icon[a.severity] || "i"), + h("div", {}, h("div", { class: "t" }, h("span", { class: "sr" }, t("attention." + a.severity) + ": "), a.title), + h("div", { class: "small" }, a.body), + a.docs && S.control.docs_url ? h("a", { class: "tiny", href: S.control.docs_url, target: "_top", rel: "noopener" }, t("attention.details")) : null)))); + const n = list.filter((a) => a.severity !== "info").length; + $("#attn-count").textContent = n ? n + " " + t("attention.to_look") : t("attention.nothing"); + if (!list.length) $("#alerts").replaceChildren(h("div", { class: "small muted" }, t("attention.nothing"))); + const badge = $("#attn-badge"); + badge.textContent = n; badge.hidden = !n; + badge.classList.toggle("bad", list.some((a) => a.severity === "alarm")); + } + function renderControl(structured) { + const running = structured ? S.control.running : null; + const btn = $("#btn-ctl"); + btn.textContent = running === false ? t("control.start") : t("control.stop"); + btn.className = "btn" + (running === false ? " primary" : ""); + $("#ctl-text").textContent = structured ? S.control.text : ""; + $("#hint").textContent = S.hint || ""; + const docs = $("#docs-link"); + if (structured && S.control.docs_url) { docs.href = S.control.docs_url; docs.hidden = false; } else docs.hidden = true; + } + function renderDetails(open) { + $("#rows").replaceChildren(...(S.rows || []).map(([k, v]) => h("tr", {}, h("td", { class: "muted" }, k), h("td", {}, v)))); + $("#checks").replaceChildren(...(S.checks || []).map((c) => { + const cls = c.ok ? (c.warn ? "c-warn" : "c-ok") : (c.warn ? "c-warn" : "c-bad"); + const mark = c.ok ? (c.warn ? "!" : "✓") : (c.warn ? "!" : "✗"); + return h("li", { class: cls }, mark + " " + c.text); + })); + if (open) $("#c-details").open = true; + } + + /* ---------------- Batteries and Settings (placeholders until P2/P3) ---------------- */ + function renderBatteries() { + if (!S.batteries) { $("#bcards").replaceChildren(); return; } + $("#bcards").replaceChildren(...S.batteries.map((b) => h("div", { class: "card" }, + h("div", { class: "row spread" }, h("strong", {}, b.name), h("span", { class: "small muted" }, b.capacity_kwh ? b.capacity_kwh + " kWh" : "")), + levelBar(b.level_pct, b.name), + h("dl", { class: "kv" }, + h("dt", {}, t("batteries.level")), h("dd", {}, b.level_pct == null ? "–" : Math.round(b.level_pct) + " %"), + b.stored_kwh != null ? [h("dt", {}, t("batteries.stored")), h("dd", {}, b.stored_kwh.toFixed(1) + " kWh")] : null, + h("dt", {}, t("batteries.now")), h("dd", {}, b.now), + h("dt", {}, t("batteries.mode")), h("dd", {}, b.mode))))); + } + function renderSettings() { + const line = S.plan && S.plan.region_line; + $("#set-region").textContent = line || ""; $("#set-region").hidden = !line; + } + + /* ---------------- control buttons ---------------- */ + // The action is a toggle, so the page reads the live state first and sends + // nothing when control is already where the person asked it to be. + async function setControl(want) { + try { + const now = await getStatus(); + if (!now.control || now.control.running !== want) await act("auto_toggle"); + toast(want ? t("toast.started") : t("toast.stopped")); + } catch (e) { toast(t("toast.failed")); } + refresh(); + } + $("#btn-ctl").addEventListener("click", () => { + const running = S && S.control ? S.control.running : true; + if (running) ask("stop", () => setControl(false)); else ask("start", () => setControl(true)); + }); + async function simple(what) { + try { await act(what); toast(t("toast.done")); } catch (e) { toast(t("toast.failed")); } + refresh(); + } + $("#btn-maint").addEventListener("click", () => ask("maint_start", () => simple("maint_start"))); + $("#btn-abort").addEventListener("click", () => ask("maint_abort", () => simple("maint_abort"))); + + /* ---------------- tabs: hash routes, arrow keys ---------------- */ + const TABS = [...document.querySelectorAll(".tab")]; + function select(tab, focus) { + TABS.forEach((x) => { + const on = x === tab; + x.setAttribute("aria-selected", String(on)); x.tabIndex = on ? 0 : -1; + document.getElementById(x.getAttribute("aria-controls")).hidden = !on; + }); + if (focus) tab.focus(); + if (location.hash !== "#" + tab.dataset.hash) history.replaceState(null, "", "#" + tab.dataset.hash); + schedule(); + } + TABS.forEach((x, i) => { + x.addEventListener("click", () => select(x, false)); + x.addEventListener("keydown", (e) => { + const j = { ArrowRight: i + 1, ArrowLeft: i - 1 + TABS.length, Home: 0, End: TABS.length - 1 }[e.key]; + if (j === undefined) return; + e.preventDefault(); select(TABS[j % TABS.length], true); + }); + }); + function fromHash() { + const want = (location.hash || "#home").slice(1); + select(TABS.find((x) => x.dataset.hash === want) || TABS[0], false); + } + addEventListener("hashchange", fromHash); + + /* ---------------- polling: every 3 s while Home or Batteries shows ---------------- */ + let timer = null; + function schedule() { + const live = !document.hidden && ($("#t-home").getAttribute("aria-selected") === "true" || + $("#t-batt").getAttribute("aria-selected") === "true"); + if (live && !timer) { refresh(); timer = setInterval(refresh, 3000); } + if (!live && timer) { clearInterval(timer); timer = null; } + } + document.addEventListener("visibilitychange", schedule); + fromHash(); + refresh(); +})(); diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html new file mode 100644 index 0000000..cecb7a2 --- /dev/null +++ b/goodwe_controller/app/static/index.html @@ -0,0 +1,135 @@ +<!doctype html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width,initial-scale=1"> +<title>Battery add-on + + + +
+ +
+
+
…
+
+
+ + + +
+ +
+
+ +
+

+
+
–
+
–
+
–
+
–
+
+
+
+ +
+

+
+
+
+
+ + +
+ +
+

+

+
    +

    +
    + +
    +

    +
    :
    + +
    +
    + +
    +

    +
    +
    + +
    +

    +
    +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + +
    SettingValueReason
    gain0.6Inverter needs 3–6 s to settle (1.4 s dead time, 94 % by 3.3 s) against a ~5 s cycle. At the limit — do not raise
    slew_w1000Most of a correction in the first cycle without running far ahead of the hardware
    slew_w00 follows the rail (max_w / 9). A faster fixed value is refused at startup (SAFETY-39) — see DOCS.md
    deadband_w15Measured residual: mean 15.4 W, max 27 W. At 10 W the command never rests
    saturation_w / cycles500 / 3Divergence = inverter at a limit → magnitude may fall, never rise. The 3-cycle term is essential: tested instantly it fires on every large correction
    step_w10Register is 1 W but response lands on a ~17.6 W ladder. Finer is meaningless
    +

    + + + + + + + + + + + + +

    +

    +
    + + +
    +
    +
    + + + + + + diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index dd39981..75d3b0c 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -34,5 +34,47 @@ "applies": { "restart": {"name": "Applies after a restart"}, "now": {"name": "Applies right away"} + }, + "home": { + "app": {"name": "Battery add-on"}, + "tabs": {"home": "Home", "batteries": "Batteries", "settings": "Settings", "setup": "Setup", "label": "Screens"}, + "now": {"name": "Now", "description": "Updated every 3 seconds.", "solar": "Solar", "house": "House", "grid": "Grid", "batteries": "Batteries"}, + "plan": { + "name": "Today's plan", + "description": "Point at a bar or a block for details, or tap it on a phone.", + "cheap": "Cheap hour", + "dear": "Expensive hour", + "estimate": "Estimate", + "grid": "Charges from the grid", + "give": "Gives power", + "cycle": "Monthly battery cycle", + "peak": "Peak limit", + "house": "Follows the house", + "now": "now", + "time_to": "to", + "per_kwh": "per kWh", + "cheap_tip": "a cheap hour", + "dear_tip": "an expensive hour", + "estimate_tip": "estimate from yesterday", + "none_tip": "No price known", + "no_prices": {"description": "No prices for today, so the chart shows only the plan."}, + "list": "The plan in words" + }, + "peak": {"name": "Peak limit", "this_month": "This month's peak", "limit": "Limit", "none": "None recorded yet", "unreadable": "Cannot be read now"}, + "attention": {"name": "Needs attention", "nothing": "Nothing to look at", "to_look": "to look at", "details": "Details", "alarm": "Alarm", "warning": "Warning", "info": "Info"}, + "control": {"name": "Control", "stop": "Stop control", "start": "Start control", "maint_start": "Start a battery cycle now", "maint_abort": "Stop the battery cycle", "docs": "Add-on documentation", "more": "More actions"}, + "details": {"name": "Details for installers", "rows": "Status rows", "checks": "Checks", "event": "Last event"}, + "dialog": { + "cancel": "Cancel", + "stop": {"name": "Stop control?", "description": "Every inverter is set to 0 W until you start control again.", "yes": "Stop control"}, + "start": {"name": "Start control?", "description": "The add-on controls the batteries again and clears any safety stop.", "yes": "Start control"}, + "maint_start": {"name": "Start a battery cycle?", "description": "The battery empties, refills and holds full, which takes a few hours.", "yes": "Start the cycle"}, + "maint_abort": {"name": "Stop the battery cycle?", "description": "Every inverter is set to 0 W for a moment, then control carries on.", "yes": "Stop the cycle"} + }, + "toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."}, + "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, + "batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"}, + "settings": {"name": "Settings", "description": "The new settings screens arrive in a later update, so use the settings page for now.", "open": "Open the settings page"}, + "setup": {"name": "Setup", "description": "The setup steps arrive in a later update, so use the settings page for now."} } } diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index aa117a9..648b7ca 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -10,7 +10,9 @@ a cellar, by someone who did not write it. Numbers alone are not enough - it says what is wrong in words. ⚠️ SINCE UX-02 THERE ARE TWO PAGES HERE, AND ONLY ONE OF THEM IS THIS FILE'S. -`/` is the status and control surface and is unchanged. `/config` is the +`/` is the status and control surface; since UX-13 P1 its files are in +app/static/ and its Home screen reads the structured half of `/status` +(app/homeview.py). `/config` is the configuration surface: its markup lives in app/config_page.py, its field model in app/configui.py and its Supervisor conversation in app/selfconfig.py. What stays HERE is the routing, so that the question a reviewer has to answer - does @@ -28,96 +30,48 @@ actions and comparing them with the shipped set. UX-13's `ha/entities` is a GET of Home Assistant's entity list (app/haentities.py) and writes nothing. """ +import io +import json import logging +import os from aiohttp import web from . import messages, selfconfig from .haentities import EntityCache +from .homeview import region_of from .validate import config_notes from .config_page import CONFIG_PAGE from .configui import changed_keys, field_model, problems_by_field _LOG = logging.getLogger("goodwe.web") -PAGE = """ - -GoodWe RS485 Controller - -

    GoodWe RS485 Controller

    -

    Configuration →

    - +# UX-13 P1: the page lives in app/static/ as three files - index.html, +# app.css, app.js - plus the page words from app/ui_text/en.json. They are +# joined into ONE response here, once, so the page needs no second request +# and no route of its own: the route list below is unchanged, and every URL +# the page uses stays relative (ingress). No build step, no external file. +STATIC = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static") +UI_TEXT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text", + "en.json") -
    -
    -
    -
    -
    Commissioning
    -
      -
      +def _read(path): + with io.open(path, encoding="utf-8") as f: + return f.read() -
      - - - -
      -
      - -""" +def page() -> str: + """The assembled index page. ` web.Application: selfcfg = selfconfig.SelfConfig(controller.hass.session, controller.hass.token) entities = EntityCache(controller.hass) + index_page = page() async def index(_request): - return web.Response(text=PAGE, content_type="text/html") + return web.Response(text=index_page, content_type="text/html") async def status(_request): return web.json_response(controller.status_payload()) @@ -203,6 +158,9 @@ def build_app(controller, selfcfg=None) -> web.Application: "running": controller.o, "running_differs": changed_keys(controller.o, options), "lang": lang, + # UX-13 P1: the levies preset and its year, for the P2 Settings + # screens, which show the year beside the region choice. + "region": region_of(options), }) return web.json_response(model) diff --git a/goodwe_controller/test_home.py b/goodwe_controller/test_home.py new file mode 100644 index 0000000..395e316 --- /dev/null +++ b/goodwe_controller/test_home.py @@ -0,0 +1,518 @@ +"""UX-13 P1: the Home screen's `/status` and the page shell. `python3 -B test_home.py` + +1. `/status` keeps every old field (`banner`, `level`, `rows`, `checks`, + `hint`, `events`) AND carries the structured half the Home screen reads: + `state`, `now`, `batteries`, `plan`, `attention`, `month_peak`, `control`. + Both are pinned here, by name and shape. +2. The plan shows only what the add-on does today. Trading on price is the + verdict the control cycle would reach (the same `plan.arbitrage()` call), + drawn where the cheapest and dearest prices are, with kWh and € per block. + The monthly cycle, the peak limit and "follows the house" are the rest. +3. Shadow mode says "would", a stopped site plans nothing, and a red row is an + alarm under "Needs attention". +4. A fault in the Home view never costs the page its old rows. +5. The page: served at `/` from app/static, no external file, relative URLs + only, every label resolves in app/ui_text, and the region year reaches + `config/model` for the P2 Settings screens. + +The STYLE scan of every Home sentence is test_messages.py part 8. +Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). +""" + +import asyncio +import io +import json +import os +import re +import sys +from datetime import datetime, timedelta, timezone + +from aiohttp import ClientSession, web as aioweb + +from app import homeview, web +from app.main import Controller +from app.peakguard import PeakDecision +from app.price import PricePoint, PriceProduct, PriceRead +from app.static_tariff import TariffPlan +from app.uimodel import REGION_PRESETS +from named_absence import field, nth, present + +FLANDERS = REGION_PRESETS["flanders"]["taxes_eur_kwh"] + +HERE = os.path.dirname(os.path.abspath(__file__)) +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +# --------------------------------------------------------------------------- # +# Fixtures: a real Controller, with its readings set directly. +# --------------------------------------------------------------------------- # +class _Store: + def __init__(self): + self.data = {} + + def set(self, k, v): + self.data[k] = v + + def get(self, k, d=None): + return self.data.get(k, d) + + def set_time(self, k, v): + self.data[k] = v.isoformat() + + def get_time(self, k): + v = self.data.get(k) + return None if v is None else datetime.fromisoformat(v) + + +class _Pub: + enabled = False + + def publish(self, _v): + pass + + def close(self): + pass + + +class _Hass: + session = None + token = "" + + async def limits(self, _e): + return (-5000.0, 5000.0, 1.0) + + async def number(self, _e, invert=False): + return None + + async def state(self, _e): + return None + + async def set_number(self, _e, _v): + return True + + async def call(self, *_a): + return True + + async def states(self): + return [] + + +ONE = {"setpoint_entity": "number.sp", "meter_entity": "sensor.grid", + "soc_entity": "sensor.soc", "batt_entity": "sensor.batt", + "meter_source": "off", "max_w": 5000, "shadow_mode": "off", + "maintenance_enabled": False} +TWO = dict(ONE, inverters=[ + {"name": "Battery A", "setpoint_entity": "number.a", "soc_entity": + "sensor.soc_a", "batt_entity": "sensor.batt_a", "max_w": 2500, + "capacity_kwh": 9.6}, + {"name": "Battery B", "setpoint_entity": "number.b", "soc_entity": + "sensor.soc_b", "batt_entity": "sensor.batt_b", "max_w": 2500, + "capacity_kwh": 5.4}]) + +# Sunday 27 September 2026, 11:40 in Brussels (09:40 UTC): the mockup's day. +NOW = datetime(2026, 9, 27, 9, 40, tzinfo=timezone.utc) +DAY0 = datetime(2026, 9, 26, 22, 0, tzinfo=timezone.utc) +MOCK = [.24, .22, .21, .20, .21, .22, .24, .27, .26, .22, .18, .16, .15, .14, + .16, .19, .23, .28, .33, .36, .34, .29, .26, .24] + + +def make(opts, *, soc=(62.0, 35.0), batt=(-2500.0, -300.0), grid=10.0, + auto=True): + c = Controller(dict(opts), _Hass(), _Store(), _Pub(), stop=asyncio.Event()) + c.auto = auto + for i, inv in enumerate(c.inverters): + inv.soc, inv.batt = soc[i], batt[i] + inv.dev_min, inv.dev_max = -5000.0, 5000.0 + c.grid = grid + return c + + +def provider_plan(prices=MOCK, day0=DAY0, days=2, provisional_from=None): + pts = [] + for d in range(days): + for k, p in enumerate(prices): + start = day0 + timedelta(days=d, hours=k) + pts.append(PricePoint(start, p, provisional_from is not None + and start >= provisional_from)) + return TariffPlan(PriceRead.series(tuple(pts), PriceProduct.DAY_AHEAD, + "generic_dayahead", NOW), None, + "provider") + + +def quiet_guard(projected_w=1240.0): + return PeakDecision(engaged=False, floor_w=None, ceiling_w=3500.0, + ceiling_from="cap", projected_w=projected_w) + + +def status(c, now=NOW): + s = c.status_payload() + # The status route builds at wall-clock time; rebuild the structured half + # at the fixture's instant so the day and the hours are the mockup's. + s.update(homeview.build(c, level=s["level"], checks=s["checks"], now=now)) + return s + + +# --------------------------------------------------------------------------- # +print("1. /status: the old fields stay, the structured half is added") +# --------------------------------------------------------------------------- # +c1 = make(ONE, soc=(62.0,), batt=(960.0,), grid=800.0) +s1 = c1.status_payload() +OLD = {"banner", "level", "rows", "checks", "hint", "events"} +NEW = {"state", "now", "batteries", "plan", "attention", "month_peak", + "control"} +check(f"every old field is still there, with its old type ({sorted(OLD)})", + OLD <= set(s1) and isinstance(s1["rows"], list) + and all(len(r) == 2 for r in s1["rows"]) + and all({"ok", "warn", "text"} <= set(r) for r in s1["checks"]) + and isinstance(s1["banner"], str) and s1["level"] in ("ok", "warn", "bad") + and isinstance(s1["events"], list)) +check(f"...and the structured half is added beside them ({sorted(NEW)})", + NEW <= set(s1) and "home_error" not in s1) +check("...and it is JSON, as the route serves it", json.loads(json.dumps(s1)) + == json.loads(json.dumps(s1))) +check("`state` names the kind, the pill word, the control row and a sub-line", + set(s1["state"]) == {"kind", "pill", "ran", "sub"} + and s1["state"]["kind"] == "running") +check("`now` carries the four tiles in W and a plain line for each", + {"solar_w", "house_w", "grid_w", "batt_w", "has_solar", "lines"} + <= set(s1["now"]) + and set(s1["now"]["lines"]) == {"solar", "house", "grid", "batt"} + and s1["now"]["grid_w"] == 800.0 and s1["now"]["batt_w"] == 960.0) +check("...and with no solar reading the house figure is NOT invented: it is " + "None and the tile says why", + s1["now"]["house_w"] is None and s1["now"]["has_solar"] is False + and s1["now"]["lines"]["house"] == homeview.tile_house(None, False)) +_b = s1["batteries"][0] +check("`batteries[]` has level, power, state, mode, the now line and why", + {"name", "level_pct", "power_w", "state", "mode", "now", "why", + "capacity_kwh", "stored_kwh", "maintenance"} <= set(_b) + and _b["level_pct"] == 62.0 and _b["state"] == "giving" + and _b["now"] == "Giving 1.0 kW now.") +_p = s1["plan"] +check("`plan` carries the verdict, the prices, the runs, the lines and " + "the region", + {"verdict", "head", "prices", "runs", "lines", "now_h", "hours", + "price_line", "tomorrow_line", "region", "region_line"} <= set(_p) + and len(_p["prices"]) in (23, 24, 25)) +check("`attention[]` has severity, title, body and docs; `month_peak` and " + "`control` are there", + all({"severity", "title", "body", "docs"} <= set(a) + for a in s1["attention"]) + and {"month", "limit_w", "peak_w", "pct", "period_w", "state", "line"} + <= set(s1["month_peak"]) + and {"running", "shadow", "text", "maintenance", "docs_url"} + <= set(s1["control"])) + +# --------------------------------------------------------------------------- # +print("\n2. the plan is what the add-on actually does") +# --------------------------------------------------------------------------- # +s_house = status(make(TWO)) +check("with trading off and no cycle due, each battery follows the house " + "from now to the end of the day, and nothing else is drawn", + [r["kind"] for r in s_house["plan"]["runs"]] == ["house", "house"] + and s_house["plan"]["verdict_key"] == "house" + and all(r["end_h"] == 24.0 and abs(r["start_h"] - 11 - 40 / 60) < 0.01 + for r in s_house["plan"]["runs"]) + and s_house["plan"]["runs"][0]["to"] == "24:00") + +ARB = dict(TWO, arbitrage_enabled=True, cycle_cost_threshold_eur=0.05) +c_arb = make(ARB) +c_arb.tariff_plan, c_arb.tariff_at = provider_plan(), NOW +c_arb.peak_guard = quiet_guard() +s_arb = status(c_arb) +_runs = s_arb["plan"]["runs"] +_grid = [r for r in _runs if r["kind"] == "grid"] +_give = [r for r in _runs if r["kind"] == "give"] +check("trading on price: a charge block at the cheapest hour (13:00) and a " + "give block at the dearest (19:00), on each battery", + [(r["battery"], r["from"], r["to"]) for r in _grid] + == [(0, "13:00", "14:00"), (1, "13:00", "14:00")] + and [(r["battery"], r["from"], r["to"]) for r in _give] + == [(0, "19:00", "20:00"), (1, "19:00", "20:00")] + and s_arb["plan"]["verdict_key"] == "trade") +check("...placed where the control cycle's own verdict puts them: the same " + "plan.arbitrage() call on the same plan", + c_arb.fresh_tariff_plan(NOW).arbitrage( + peak_guard_active=False, min_spread_eur_kwh=0.05, + uncertainty=frozenset({__import__("app.price", fromlist=["x"]) + .Uncertainty.NO_WEATHER})) + .match(allowed=lambda v: (v.cheapest.start, v.dearest.start), + refused=lambda v: None) + == (DAY0 + timedelta(hours=13), DAY0 + timedelta(hours=19))) +# Battery A: 2.5 kW for 1 h = 2.5 kWh; room to the 95 % ceiling is 33 % of +# 9.6 kWh = 3.17 kWh, so 2.5. Battery B: 60 % of 5.4 = 3.24, so 2.5. +check("each block carries kWh and €: charging is capped by the battery's own " + "rating and the room its level leaves, € = kWh x that hour's price", + [r["kwh"] for r in _grid] == [2.5, 2.5] + and [r["eur"] for r in _grid] == [0.35, 0.35] + and [r["eur_kwh"] for r in _grid] == [0.14, 0.14] + and "2.5 kWh" in _grid[0]["what"] and "€0.14" in _grid[0]["why"] + and "€0.35" in _grid[0]["amount"]) +# Giving: A holds 62 - 20 = 42 % of 9.6 = 4.03 -> 2.5. B holds 35 - 20 = 15 % +# of 5.4 = 0.81 kWh, which is what it can give above arbitrage's floor. +check("...and giving is capped by what each battery holds above arbitrage's " + "floor (Battery B: 15 % of 5.4 kWh)", + [r["kwh"] for r in _give] == [2.5, 0.81] + and [r["eur"] for r in _give] == [0.9, 0.29]) +check("the price bars are today's 24 hours, from the real series, with the " + "cheap and expensive thirds marked", + [b["eur_kwh"] for b in s_arb["plan"]["prices"]] == MOCK + and s_arb["plan"]["prices"][13]["kind"] == "cheap" + and s_arb["plan"]["prices"][19]["kind"] == "dear" + and s_arb["plan"]["prices"][0]["kind"] == "mid" + and s_arb["plan"]["prices"][13]["label"] == "13:00") +check("the price line names the price now, today's cheapest and dearest, and " + "that tomorrow's prices are in", + s_arb["plan"]["price_line"] == ("Price now €0.16 per kWh, all in. " + "Today: cheapest €0.14 at 13:00, " + "dearest €0.36 at 19:00.") + and s_arb["plan"]["tomorrow_line"] == "Tomorrow's prices are in.") + +c_late = make(ARB) +c_late.tariff_plan, c_late.tariff_at = provider_plan(), NOW +c_late.peak_guard = quiet_guard() +s_late = status(c_late, now=NOW + timedelta(hours=9)) # 20:40 local +check("a block whose hour is over is not drawn: at 20:40 no trade is left " + "today", + not [r for r in s_late["plan"]["runs"] if r["kind"] in ("grid", "give")]) + +c_peak = make(ARB) +c_peak.tariff_plan, c_peak.tariff_at = provider_plan(), NOW +c_peak.peak_guard = PeakDecision(engaged=True, floor_w=800.0, + ceiling_w=3500.0, ceiling_from="cap", + projected_w=3900.0) +s_peak = status(c_peak) +check("while the peak limit holds, the verdict refuses as the cycle does: no " + "trade block, a plain line, and a peak block for this 15-minute period", + not [r for r in s_peak["plan"]["runs"] if r["kind"] in ("grid", "give")] + and homeview.line_no_trade("peak") in s_peak["plan"]["lines"] + and [(r["from"], r["to"]) for r in s_peak["plan"]["runs"] + if r["kind"] == "peak"] == [("11:30", "11:45"), ("11:30", "11:45")]) + +c_blind = make(ARB) +c_blind.tariff_plan, c_blind.tariff_at = provider_plan(), NOW +s_blind = status(c_blind) # meter_source off: the guard never runs +check("with nothing measuring the 15-minute peak, trading is NOT drawn, as " + "the cycle refuses it (guard state None)", + not [r for r in s_blind["plan"]["runs"] if r["kind"] in ("grid", "give")] + and homeview.line_no_trade("not_covered") in s_blind["plan"]["lines"]) + +c_flat = make(ARB) +c_flat.tariff_plan, c_flat.tariff_at = provider_plan(prices=[.2] * 24), NOW +c_flat.peak_guard = quiet_guard() +s_flat = status(c_flat) +check("a flat day: no trade, no cheap or expensive hour marked", + not [r for r in s_flat["plan"]["runs"] if r["kind"] in ("grid", "give")] + and {b["kind"] for b in s_flat["plan"]["prices"]} == {"mid"} + and homeview.line_no_trade("not_worth") in s_flat["plan"]["lines"]) + +c_old = make(ARB) +c_old.tariff_plan = provider_plan() +c_old.tariff_at = NOW - timedelta(hours=3) # past its max age +c_old.peak_guard = quiet_guard() +s_old = status(c_old) +check("a stale plan is not traded on by the cycle, so it is not drawn", + not [r for r in s_old["plan"]["runs"] if r["kind"] in ("grid", "give")]) + +MAINT = dict(TWO, maintenance_enabled=True, maintenance_start_hour=12) +c_m = make(MAINT) +s_m = status(c_m) +_cyc = [r for r in s_m["plan"]["runs"] if r["kind"] == "cycle"] +check("a monthly cycle due today is drawn on ONE battery, at the start hour " + "the cycle uses (12 UTC is 14:00 here), and the other one waits", + len(_cyc) == 1 and field(nth(_cyc), "from") == "14:00" + and s_m["plan"]["verdict_key"] == "cycle" + and any("waits its turn" in x for x in s_m["plan"]["lines"])) +check("...with its duration from the battery's capacity and the cycle's rates " + "and hold time", + present(nth(_cyc)) and _cyc[0]["amount"].startswith("Takes about ") + and _cyc[0]["end_h"] > _cyc[0]["start_h"] + 2) +c_m.maints[0].store.set("phase", "drain") +s_md = status(c_m) +check("a cycle under way is drawn from now, and the battery's now line says " + "so", + [r["from"] for r in s_md["plan"]["runs"] if r["kind"] == "cycle"] + == ["11:40"] + and s_md["batteries"][0]["now"] == "Monthly cycle: emptying." + and any("Battery B waits its turn" in x for x in s_md["plan"]["lines"])) + +# --------------------------------------------------------------------------- # +print("\n3. shadow mode, a stopped site, an alarm") +# --------------------------------------------------------------------------- # +c_sh = make(dict(ARB, shadow_mode="on")) +c_sh.tariff_plan, c_sh.tariff_at = provider_plan(), NOW +c_sh.peak_guard = quiet_guard() +s_sh = status(c_sh) +_texts = [r["what"] for r in s_sh["plan"]["runs"]] + [s_sh["plan"]["head"]] +check("shadow: the state is shadow, the battery tile is held at 0 W, and " + "every block and the head say 'would'", + s_sh["state"]["kind"] == "shadow" + and s_sh["now"]["lines"]["batt"] == "Held at 0 W" + and all("ould" in x for x in _texts) + and s_sh["plan"]["head"].startswith("Shadow mode:")) +check("...and 'Shadow mode is on' is the first item under Needs attention", + s_sh["attention"][0]["title"] == homeview.ATTN_SHADOW + and s_sh["attention"][0]["severity"] == "info") +check("...and each battery's now line says it is held at 0 W", + all(b["now"].startswith("Held at 0 W.") for b in s_sh["batteries"])) + +s_stop = status(make(TWO, auto=False)) +check("stopped: nothing is planned and the head says so", + s_stop["plan"]["runs"] == [] and s_stop["state"]["kind"] == "stopped" + and s_stop["plan"]["verdict_key"] == "stopped" + and s_stop["control"]["running"] is False + and all(b["now"] == "Held at 0 W while control is stopped." + for b in s_stop["batteries"])) + +c_al = make(ONE, soc=(62.0,), batt=(0.0,)) +c_al.inverters[0].sign_wd.tripped = True +s_al = c_al.status_payload() +_red = [a for a in s_al["attention"] if a["severity"] == "alarm"] +check("an alarm: level bad, state alarm, and the red row is the first item " + "under Needs attention", + s_al["level"] == "bad" and s_al["state"]["kind"] == "alarm" + and _red and s_al["attention"][0] is _red[0] + and _red[0]["title"] == homeview.ATTN_TITLES["direction"]) +check("...and nothing is planned while every inverter is held at 0 W", + s_al["plan"]["runs"] == [] and s_al["plan"]["verdict_key"] == "held") +_rows = [r for r in s_al["checks"] if not r["ok"] and not r["warn"]] +check("...and every red, amber and settling row reaches Needs attention with " + "its own sentence as the body, and no green row does", + [a["body"] for a in homeview.attention(s_al["checks"])] + == [r["text"] for r in s_al["checks"] if not r["ok"] and not r["warn"]] + + [r["text"] for r in s_al["checks"] if not r["ok"] and r["warn"]] + + [r["text"] for r in s_al["checks"] if r["ok"] and r["warn"]]) + +# --------------------------------------------------------------------------- # +print("\n4. a fault in the Home view never costs the page its rows") +# --------------------------------------------------------------------------- # +_real = homeview.build +try: + homeview.build = lambda *a, **k: 1 / 0 + s_err = make(ONE, soc=(50.0,), batt=(0.0,)).status_payload() +finally: + homeview.build = _real +check("the old fields are served and `home_error` says the rest is missing", + OLD <= set(s_err) and s_err.get("home_error") is True + and not (NEW & set(s_err))) + +# --------------------------------------------------------------------------- # +print("\n5. the page") +# --------------------------------------------------------------------------- # +PAGE = web.page() +JS = io.open(os.path.join(HERE, "app", "static", "app.js"), + encoding="utf-8").read() +UI = json.load(io.open(os.path.join(HERE, "app", "ui_text", "en.json"), + encoding="utf-8"))["home"] + + +def resolve(path): + node = UI + for k in path.split("."): + if not isinstance(node, dict) or k not in node: + return None + node = node[k] + return node + + +check("the page is assembled: no placeholder is left and the words parse", + "/*APP_CSS*/" not in PAGE and "/*APP_JS*/" not in PAGE + and "/*UI_TEXT*/" not in PAGE + and json.loads(PAGE.split('id="ui-text">', 1)[1] + .split("", 1)[0].replace("<\\/", " 30 and not _missing) +check("data is set as text, never as HTML, so no status sentence can inject " + "markup", "innerHTML" not in JS and "insertAdjacentHTML" not in JS) +check("every function of the old page is still on it: start/stop, the " + "maintenance start and abort, the status rows, the checks and the " + "event line", + "auto_toggle" in JS and '"maint_start"' in JS and '"maint_abort"' in JS + and 'id="rows"' in PAGE and 'id="checks"' in PAGE + and 'id="hint"' in PAGE and 'href="config"' in PAGE) +check("stopping, starting and both maintenance actions ask first", + all(f'ask("{k}"' in JS for k in ("stop", "start", "maint_start", + "maint_abort"))) +check("tooltips open on hover, on a tap and on keyboard focus", + "pointermove" in JS and "pointerdown" in JS and "focusin" in JS) +check("the chart is not colour alone: expensive hours and blocks are " + "patterned, and every item has a text label", + "repeating-linear-gradient" in PAGE and '"aria-label": tipText' in JS) +check("the phone layout puts the tabs at the bottom under 640 px, and dark " + "mode follows the system", + "@media (max-width:640px)" in PAGE and "position:fixed;bottom:0" in PAGE + and "prefers-color-scheme:dark" in PAGE) + + +async def _serve(): + class _Sup: + async def info(self): + return {"options": {"price_taxes_eur_kwh": FLANDERS, + "price_taxes_profile": ""}, + "schema": [], "translations": {}} + c = make(ONE, soc=(50.0,), batt=(0.0,)) + runner = aioweb.AppRunner(web.build_app(c, _Sup())) + await runner.setup() + site = aioweb.TCPSite(runner, "127.0.0.1", 0) + await site.start() + port = site._server.sockets[0].getsockname()[1] + out = {} + try: + async with ClientSession() as s: + async with s.get(f"http://127.0.0.1:{port}/") as r: + out["page"] = (r.status, r.content_type, await r.text()) + async with s.get(f"http://127.0.0.1:{port}/status") as r: + out["status"] = await r.json() + async with s.get(f"http://127.0.0.1:{port}/config/model") as r: + out["model"] = await r.json() + finally: + await runner.cleanup() + return out + + +E = asyncio.run(_serve()) +check("GET / serves the assembled page as HTML", E["page"][0] == 200 + and E["page"][1] == "text/html" and E["page"][2] == PAGE) +check("GET status over HTTP carries both halves", + OLD <= set(E["status"]) and NEW <= set(E["status"])) +check("the levies preset and its year reach config/model for the P2 " + "Settings screens (P0 review follow-up)", + E["model"].get("region") == {"id": "flanders", "year": 2026}) +c_reg = make(dict(ARB, price_taxes_eur_kwh=FLANDERS)) +c_reg.tariff_plan, c_reg.tariff_at = provider_plan(), NOW +s_reg = status(c_reg) +check("...and Home names the preset with its year wherever prices come from " + "a feed, and says 'your own figure' otherwise", + s_reg["plan"]["region"] == {"id": "flanders", "year": 2026} + and s_reg["plan"]["region_line"] + == "Levies and VAT: Flanders, Fluvius Antwerpen, 2026 figures." + and s_arb["plan"]["region_line"] == "Levies and VAT: your own figure." + and s_house["plan"]["region_line"] == "") + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index e82176c..33d3e72 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -1817,6 +1817,69 @@ check("the action log counts 'engagements' with a real plural and the " and messages.count(25, "engagement") == "25 engagements" and messages.count(1, "engagement") == "1 engagement") +# ============================================================================== # +print("\n8. the Home screen's sentences (UX-13 P1)") +# app/homeview.py builds every sentence the Home screen shows. Each is rendered +# with real values by `text_samples()` and held to STYLE.md: a title at most 5 +# words, a plan line at most 2 sentences of at most 12 words each (the design +# note's new row type), any other line 1 sentence of at most 25 words. +from app import homeview # noqa: E402 + +PLAN_SENTENCE_WORDS, PLAN_SENTENCES = 12, 2 + + +def home_problems(kind, text): + if kind == "title": + return title_problems(text) + out = text_problems(text, keys=False, entities=False) + if ";" in text: + out.append("semicolon") + if kind == "line": + if sentences(text) > 1: + out.append(f"over 1 sentence ({sentences(text)})") + if len(words(text)) > 25: + out.append(f"over 25 words ({len(words(text))})") + return out + if sentences(text) > PLAN_SENTENCES: + out.append(f"plan line over {PLAN_SENTENCES} sentences") + long = [x for x in re.split(r"(?<=[.!?])\s+", text) + if len(words(x)) > PLAN_SENTENCE_WORDS] + if long: + out.append(f"plan sentence over {PLAN_SENTENCE_WORDS} words " + f"({len(words(long[0]))}): {long[0]!r}") + return out + + +_home = homeview.text_samples() +_home_bad = [(k, t, p) for k, t in _home for p in [home_problems(k, t)] if p] +for k, t, p in _home_bad: + print(f" {k}: {t!r}: {p}") +check(f"every Home sentence obeys its STYLE limit ({len(_home)} rendered, " + f"{len(_home_bad)} over)", len(_home) > 80 and not _home_bad) +_shadowed = [t for k, t in homeview.text_samples() if "ould" in t] +check("in shadow mode the Home plan says what the add-on WOULD do: every " + "shadow variant of a plan text carries 'would'", + all("ould" in f(True) for f in ( + lambda sh: homeview.run_grid_what(2.5, sh), + lambda sh: homeview.run_give_what(2.5, sh), + lambda sh: homeview.run_cycle_what("idle", sh), + lambda sh: homeview.run_cycle_why(sh), + lambda sh: homeview.run_peak_what(3500, sh), + lambda sh: homeview.run_house_what(sh), + lambda sh: homeview.run_house_why(sh), + lambda sh: homeview.plan_head("house", sh), + lambda sh: homeview.plan_head("trade", sh), + lambda sh: homeview.line_peak_limit(3500, sh))) + and not any("ould" in f(False) for f in ( + lambda sh: homeview.run_grid_what(2.5, sh), + lambda sh: homeview.run_house_what(sh), + lambda sh: homeview.plan_head("house", sh))) + and len(_shadowed) > 10) +check("mutation: a 13-word plan sentence and a 6-word title are caught", + home_problems("plan", "One two three four five six seven eight nine " + "ten eleven twelve thirteen.") + and home_problems("title", "One two three four five six")) + print() if fails: print(f"{len(fails)} FAILED") diff --git a/goodwe_controller/test_pv.py b/goodwe_controller/test_pv.py index 1768e4b..ad71ba7 100644 --- a/goodwe_controller/test_pv.py +++ b/goodwe_controller/test_pv.py @@ -700,17 +700,20 @@ check(f"PRECONDITION: the scan found the whole package, not a subset - " # UX-13 adds the settings surface: labels (messages.py), a settings warning # (validate.py) and the page's layout and derivation (uilayout.py, uimodel.py). # None of them decides anything, so the decision modules stay excluded. +# UX-13 P1 adds homeview.py, the Home screen's read-only view: its House tile +# is grid + solar + battery, and it shows nothing without a solar reading. _DECIDERS = ("control.py", "arbiter.py", "allocator.py", "peakguard.py", "arbitrage.py", "maintenance.py", "clamp.py", "freeze.py", "watchdog.py", "delivery.py", "circulation.py") check("⭐ ONLY THE READER, THE PUBLISHER AND THE SETTINGS SURFACE SEE THE " "MATERIAL: `pv.py` (the reader), `main.py` (the read and the two operator " - "surfaces), `mqtt.py` (the publication), and `messages.py`, " - "`validate.py`, `uilayout.py` and `uimodel.py` (settings). " + "surfaces), `homeview.py` (the Home screen's view), `mqtt.py` (the " + "publication), and `messages.py`, `validate.py`, `uilayout.py` and " + "`uimodel.py` (settings). " f"{', '.join(_DECIDERS)} do not mention it in any spelling, comments " "included", - _touch == ["main.py", "messages.py", "mqtt.py", "pv.py", "uilayout.py", - "uimodel.py", "validate.py"] + _touch == ["homeview.py", "main.py", "messages.py", "mqtt.py", "pv.py", + "uilayout.py", "uimodel.py", "validate.py"] and not set(_DECIDERS) & set(_touch)) # habit 4 in the instrument: a scanner that cannot go red is not a scanner. check("...and the scan CAN go red - a module body with the material in it is " diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py new file mode 100644 index 0000000..5b9067b --- /dev/null +++ b/goodwe_controller/tools/ux13_demo.py @@ -0,0 +1,131 @@ +"""UX-13 P1: serve the real page and routes over a fixture controller, for a +headless browser check. `python3 tools/ux13_demo.py STATE PORT` + +STATE is running, shadow or alarm. The controller is the shipped `Controller` +with its readings set by hand (two batteries, solar, today's prices in the +mockup's shape, trading on). Nothing here talks to Home Assistant or to an +inverter: `/action` changes only this fixture. Used for the P1 render check +(no JS errors, tooltips, phone width, dark mode) described in the PR. +""" + +import asyncio +import os +import sys +from datetime import datetime, timedelta, timezone + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from aiohttp import web as aioweb # noqa: E402 + +from app import homeview, web # noqa: E402 +from app.main import Controller # noqa: E402 +from app.peakguard import PeakDecision # noqa: E402 +from app.price import PricePoint, PriceProduct, PriceRead # noqa: E402 +from app.static_tariff import TariffPlan # noqa: E402 + +PRICES = [.24, .22, .21, .20, .21, .22, .24, .27, .26, .22, .18, .16, .15, + .14, .16, .19, .23, .28, .33, .36, .34, .29, .26, .24] + + +class Store(dict): + def set(self, k, v): + self[k] = v + + def set_time(self, k, v): + self[k] = v.isoformat() + + def get_time(self, k): + v = self.get(k) + return None if v is None else datetime.fromisoformat(v) + + @property + def data(self): + return self + + +class Pub: + enabled = False + + def publish(self, _v): + pass + + def close(self): + pass + + +class Hass: + session = None + token = "" + + async def limits(self, _e): + return (-5000.0, 5000.0, 1.0) + + async def number(self, _e, invert=False): + return None + + async def state(self, _e): + return None + + async def set_number(self, _e, _v): + return True + + async def call(self, *_a): + return True + + async def states(self): + return [] + + +class Supervisor: + async def info(self): + return {"options": {}, "schema": [], "translations": {}} + + +OPTS = {"meter_entity": "sensor.grid", "meter_source": "off", + "pv_entity": "sensor.pv", "maintenance_enabled": True, + "maintenance_start_hour": 18, "arbitrage_enabled": True, + "cycle_cost_threshold_eur": 0.05, + "inverters": [ + {"name": "Battery A", "setpoint_entity": "number.a", + "soc_entity": "sensor.soc_a", "batt_entity": "sensor.batt_a", + "max_w": 2500, "capacity_kwh": 9.6}, + {"name": "Battery B", "setpoint_entity": "number.b", + "soc_entity": "sensor.soc_b", "batt_entity": "sensor.batt_b", + "max_w": 2500, "capacity_kwh": 5.4}]} + + +def controller(state): + opts = dict(OPTS, shadow_mode="on" if state == "shadow" else "off") + c = Controller(opts, Hass(), Store(), Pub(), stop=asyncio.Event()) + c.auto = True + now = datetime.now(timezone.utc) + day0, _day1 = homeview.local_day(now) + pts = tuple(PricePoint(day0 + timedelta(days=d, hours=k), p, False) + for d in range(2) for k, p in enumerate(PRICES)) + c.tariff_plan = TariffPlan(PriceRead.series( + pts, PriceProduct.DAY_AHEAD, "generic_dayahead", now), None, + "provider") + c.tariff_at = now + c.peak_guard = PeakDecision(engaged=False, floor_w=None, + ceiling_w=3500.0, ceiling_from="cap", + projected_w=1240.0) + for inv, soc, batt in zip(c.inverters, (62.0, 35.0), (-2500.0, -300.0)): + inv.soc, inv.batt = soc, (0.0 if state == "shadow" else batt) + inv.dev_min, inv.dev_max = -5000.0, 5000.0 + c.grid = -10.0 if state != "shadow" else -2810.0 + c.pv_w = 3900.0 + if state == "alarm": + c.inverters[0].sign_wd.tripped = True + return c + + +async def main(state, port): + runner = aioweb.AppRunner(web.build_app(controller(state), Supervisor())) + await runner.setup() + await aioweb.TCPSite(runner, "127.0.0.1", port).start() + print(f"serving {state} on http://127.0.0.1:{port}/", flush=True) + await asyncio.Event().wait() + + +if __name__ == "__main__": + asyncio.run(main(sys.argv[1], int(sys.argv[2]))) -- 2.54.0 From fad73d4012a76c86d1c60a39461702805eb1f4c2 Mon Sep 17 00:00:00 2001 From: goodwe-review Date: Mon, 28 Sep 2026 01:18:33 +0200 Subject: [PATCH 053/105] UX-13 P1 review: Home draws only what the cycle would do - Trade blocks: none on a battery with no room, no sale at a negative price or while the emptiest battery is at arbitrage's floor, nothing when a level is unknown. A give after a charge may use what the charge put in. - The refusal line names the real reason: prices not published vs gap. - The plan's peak line uses the guard's ceiling (this month's peak once above the cap), as the peak card does. - House below zero: 0 W inside the idle band, no figure beyond it. - Price bars are "Low price" / "High price": the add-on trades in one hour. - Control toggle: one request in flight at a time. - test_home: the new cases; the house-sign mutation now goes red. Co-Authored-By: Claude Opus 5.5 --- goodwe_controller/app/homeview.py | 85 ++++++++++++++++++++++----- goodwe_controller/app/static/app.js | 6 ++ goodwe_controller/app/ui_text/en.json | 8 +-- goodwe_controller/test_home.py | 75 +++++++++++++++++++++-- 4 files changed, 149 insertions(+), 25 deletions(-) diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index c4e56b7..4e58505 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -85,9 +85,16 @@ def flow(w, *, shadow=False): def now_block(*, grid_w, pv_w, batt_w, has_solar, shadow): """The four tiles. `house_w` needs all three readings, so without a solar reading it is None rather than a number that leaves the sun out.""" - house = None + house, disagree = None, False if has_solar and None not in (grid_w, pv_w, batt_w): house = float(grid_w) + float(pv_w) + float(batt_w) + # The three are read at slightly different moments, so the sum can dip + # under zero. Inside the idle band that is 0 W; beyond it the readings + # disagree and no house figure is shown. + if house < -IDLE_W: + house, disagree = None, True + elif house < 0.0: + house = 0.0 return { "solar_w": None if pv_w is None else float(pv_w), "house_w": house, @@ -96,7 +103,7 @@ def now_block(*, grid_w, pv_w, batt_w, has_solar, shadow): "has_solar": bool(has_solar), "lines": { "solar": tile_solar(pv_w, has_solar), - "house": tile_house(house, has_solar), + "house": tile_house(house, has_solar, disagree), "grid": tile_grid(grid_w), "batt": tile_batt(batt_w, shadow), }, @@ -156,7 +163,9 @@ class DayPrices: def hour_bars(points, day0, day1): """One bar per local hour: the mean of its prices, or None when unknown. - `kind` is cheap / dear / mid by thirds of today's range (display only).""" + `kind` is cheap / dear / mid by thirds of today's range (display only). + The page calls these "low price" and "high price", not cheap hours: the + add-on trades in the one cheapest and one dearest hour, not in a third.""" n = int(round(_hours(day1, day0))) bars = [] for k in range(n): @@ -221,7 +230,19 @@ def trade_verdict(c, plan): uncertainty=frozenset({Uncertainty.NO_WEATHER})) return verdict.match( allowed=lambda v: (v, "allowed"), - refused=lambda _v: (None, "peak" if guard else "not_worth")) + refused=lambda _v: (None, refusal_key(plan, guard))) + + +def refusal_key(plan, guard): + """Which of `TariffPlan.arbitrage()`'s refusals fired, in its own order: + the peak guard, no prices, under two published points, then the gap.""" + if guard: + return "peak" + if not plan.has_prices: + return "no_prices" + if sum(1 for p in _points(plan) if not p.provisional) < 2: + return "not_firm" + return "not_worth" def _point_end(plan, point): @@ -231,26 +252,47 @@ def _point_end(plan, point): return point.start + timedelta(hours=1) +# Under this many kWh a block is not drawn: the cycle would not move it. +MIN_KWH = 0.05 + + def trade_runs(c, plan, verdict, day0, day1, now, shadow): """A charge block and a give block on each battery, where the verdict put them. The site trades as one; each battery's share is capped by its own - rating and by the room its level leaves (arbitrage's own floor/ceiling).""" + rating and by the room its level leaves (arbitrage's own floor/ceiling). + Only what `arbitrage.decide()` would still do is drawn: no block on a + battery with no room, no sale at a negative price, and no sale while the + emptiest battery is at the floor (the cycle's `soc` is the emptiest). + With a level unknown the cycle does not trade, so nothing is drawn.""" floor, ceiling = arbitrage.soc_bounds(c.o) + if any(inv.soc is None for inv in c.inverters): + return [], [], "no_level" + level = [float(inv.soc) for inv in c.inverters] + legs = sorted((("grid", verdict.cheapest), ("give", verdict.dearest)), + key=lambda kp: kp[1].start) runs, later = [], [] - for kind, pt in (("grid", verdict.cheapest), ("give", verdict.dearest)): + for kind, pt in legs: end = _point_end(plan, pt) if end <= now: continue if not (day0 <= pt.start < day1): later.append((kind, pt)) continue + if kind == "give" and (pt.eur_per_kwh < 0 or min(level) <= floor): + continue hrs = (end - pt.start).total_seconds() / 3600.0 for i, inv in enumerate(c.inverters): kwh = inv.max_w / 1000.0 * hrs - if inv.capacity_kwh and inv.soc is not None: - room = (ceiling - inv.soc if kind == "grid" - else inv.soc - floor) - kwh = min(kwh, max(0.0, room) / 100.0 * inv.capacity_kwh) + cap = inv.capacity_kwh + if cap: + room = (ceiling - level[i] if kind == "grid" + else level[i] - floor) + kwh = min(kwh, max(0.0, room) / 100.0 * cap) + # A later give may use what this charge put in: an upper + # bound, like every amount here ("up to"). + level[i] += (kwh if kind == "grid" else -kwh) / cap * 100.0 + if kwh < MIN_KWH: + continue eur = kwh * pt.eur_per_kwh if kind == "grid": what, why, amount = (run_grid_what(kwh, shadow), @@ -262,7 +304,7 @@ def trade_runs(c, plan, verdict, day0, day1, now, shadow): run_give_amount(eur)) runs.append(_run(i, kind, pt.start, end, day0, day1, what, why, amount, kwh=kwh, eur=eur, price=pt.eur_per_kwh)) - return runs, later + return runs, later, None def maintenance_runs(c, day0, day1, now, shadow): @@ -387,9 +429,11 @@ def build_plan(c, now, shadow, running, held=False): if running: runs += house_runs(len(c.inverters), day0, day1, now, shadow) if verdict is not None: - trade, later = trade_runs(c, fresh, verdict, day0, day1, now, - shadow) + trade, later, no_trade = trade_runs(c, fresh, verdict, day0, day1, + now, shadow) runs += trade + if no_trade: + lines.append(line_no_trade(no_trade)) for kind, pt in later: lines.append(line_trade_tomorrow(kind, hhmm(pt.start), pt.eur_per_kwh, shadow)) @@ -400,7 +444,10 @@ def build_plan(c, now, shadow, running, held=False): lines += waits runs += peak_run(c, day0, day1, now, shadow, limit_w) if c.p1_enabled: - lines.append(line_peak_limit(limit_w, shadow)) + # The guard's ceiling: the cap, or this month's peak once above it. + pg = c.peak_guard + lines.append(line_peak_limit( + (pg.ceiling_w if pg is not None else None) or limit_w, shadow)) lines = [x for x in lines if x] kinds = {r["kind"] for r in runs} @@ -663,9 +710,11 @@ def tile_solar(pv_w, has_solar) -> str: return "Producing" if pv_w > IDLE_W else "Not producing" -def tile_house(house_w, has_solar) -> str: +def tile_house(house_w, has_solar, disagree=False) -> str: if not has_solar: return "Needs a solar reading" + if disagree: + return "Readings do not add up" return "No reading" if house_w is None else "Using" @@ -805,7 +854,9 @@ def line_no_trade(key) -> str: "peak.", "no_prices": "No trading on price yet: no prices have arrived.", "peak": "No trading on price now: the peak limit comes first.", + "not_firm": "No trading on price yet: the prices are not published.", "not_worth": "No trading on price today. The price gap is too small.", + "no_level": "No trading on price now: a battery level is unknown.", }[key] @@ -884,6 +935,7 @@ def text_samples() -> list: ((None, False), (None, True), (3900, True), (0, True))] out += [("title", tile_house(v, s)) for v, s in ((None, False), (None, True), (1100, True))] + out.append(("title", tile_house(None, True, True))) out += [("title", tile_grid(v)) for v in (None, 1200, -800, 5)] out += [("title", tile_batt(v, sh)) for v in (None, 2500, -2500, 0)] for phase in (M_IDLE, M_DRAIN, M_CHARGE, M_HOLD): @@ -928,5 +980,6 @@ def text_samples() -> list: ("plan", line_region("own", None)), ("plan", line_peak_not_covered())] out += [("plan", line_no_trade(k)) for k in - ("not_covered", "no_prices", "peak", "not_worth")] + ("not_covered", "no_prices", "peak", "not_firm", "not_worth", + "no_level")] return out diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 01f9d0a..fb9810a 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -309,12 +309,18 @@ /* ---------------- control buttons ---------------- */ // The action is a toggle, so the page reads the live state first and sends // nothing when control is already where the person asked it to be. + // One request at a time: a second confirm while the first is in flight + // would read the same state and toggle it back. + let toggling = false; async function setControl(want) { + if (toggling) return; + toggling = true; try { const now = await getStatus(); if (!now.control || now.control.running !== want) await act("auto_toggle"); toast(want ? t("toast.started") : t("toast.stopped")); } catch (e) { toast(t("toast.failed")); } + finally { toggling = false; } refresh(); } $("#btn-ctl").addEventListener("click", () => { diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 75d3b0c..6170326 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -42,8 +42,8 @@ "plan": { "name": "Today's plan", "description": "Point at a bar or a block for details, or tap it on a phone.", - "cheap": "Cheap hour", - "dear": "Expensive hour", + "cheap": "Low price", + "dear": "High price", "estimate": "Estimate", "grid": "Charges from the grid", "give": "Gives power", @@ -53,8 +53,8 @@ "now": "now", "time_to": "to", "per_kwh": "per kWh", - "cheap_tip": "a cheap hour", - "dear_tip": "an expensive hour", + "cheap_tip": "low for today", + "dear_tip": "high for today", "estimate_tip": "estimate from yesterday", "none_tip": "No price known", "no_prices": {"description": "No prices for today, so the chart shows only the plan."}, diff --git a/goodwe_controller/test_home.py b/goodwe_controller/test_home.py index 395e316..40e21c2 100644 --- a/goodwe_controller/test_home.py +++ b/goodwe_controller/test_home.py @@ -184,6 +184,19 @@ check("`now` carries the four tiles in W and a plain line for each", <= set(s1["now"]) and set(s1["now"]["lines"]) == {"solar", "house", "grid", "batt"} and s1["now"]["grid_w"] == 800.0 and s1["now"]["batt_w"] == 960.0) +_nh = homeview.now_block(grid_w=-3000.0, pv_w=1000.0, batt_w=1500.0, + has_solar=True, shadow=False) +_nz = homeview.now_block(grid_w=-1030.0, pv_w=1000.0, batt_w=0.0, + has_solar=True, shadow=False) +_np = homeview.now_block(grid_w=800.0, pv_w=1000.0, batt_w=-300.0, + has_solar=True, shadow=False) +check("House = grid (+ import) + solar + battery (+ giving): 800 + 1000 - 300 " + "= 1500 W", + _np["house_w"] == 1500.0 and _np["lines"]["house"] == "Using") +check("...a sum below zero is not shown as a positive figure: 0 W inside " + "the idle band, and no figure beyond it", + _nz["house_w"] == 0.0 and _nh["house_w"] is None + and _nh["lines"]["house"] == homeview.tile_house(None, True, True)) check("...and with no solar reading the house figure is NOT invented: it is " "None and the tile says why", s1["now"]["house_w"] is None and s1["now"]["has_solar"] is False @@ -254,12 +267,53 @@ check("each block carries kWh and €: charging is capped by the battery's own " and [r["eur_kwh"] for r in _grid] == [0.14, 0.14] and "2.5 kWh" in _grid[0]["what"] and "€0.14" in _grid[0]["why"] and "€0.35" in _grid[0]["amount"]) -# Giving: A holds 62 - 20 = 42 % of 9.6 = 4.03 -> 2.5. B holds 35 - 20 = 15 % -# of 5.4 = 0.81 kWh, which is what it can give above arbitrage's floor. +# Giving at 19:00 comes after the 13:00 charge, so each battery may give what +# it will hold then: B is at 35 % + 2.5 kWh of 5.4 = 81 %, and 81 - 20 = 61 % +# of 5.4 = 3.3 kWh, so 2.5 (an upper bound, like every amount here). check("...and giving is capped by what each battery holds above arbitrage's " - "floor (Battery B: 15 % of 5.4 kWh)", - [r["kwh"] for r in _give] == [2.5, 0.81] - and [r["eur"] for r in _give] == [0.9, 0.29]) + "floor after the charge before it", + [r["kwh"] for r in _give] == [2.5, 2.5] + and [r["eur"] for r in _give] == [0.9, 0.9]) + + +def trade(soc, prices=MOCK, provisional_from=None, now=NOW, opts=ARB): + c = make(opts, soc=soc) + c.tariff_plan = provider_plan(prices, provisional_from=provisional_from) + c.tariff_at, c.peak_guard = now, quiet_guard() + s = status(c, now=now) + return ([(r["kind"], r["battery"], r["kwh"]) for r in s["plan"]["runs"] + if r["kind"] in ("grid", "give")], s["plan"]["lines"]) + + +# Review of #144: only what arbitrage.decide() would still do is drawn. +_t, _l = trade((96.0, 35.0)) +check("a battery at arbitrage's ceiling gets no charge block, not " + "'Charges up to 0.0 kWh'", ("grid", 0, 0.0) not in _t + and [k for k in _t if k[0] == "grid"] == [("grid", 1, 2.5)]) +# 20:00 local: the dearest (19:00) is over; tomorrow's charge is a line. Put +# the dearest later today instead, with the emptiest pack at the floor. +_late = MOCK[:22] + [.40, .24] +_t, _l = trade((62.0, 20.0), prices=_late, now=NOW + timedelta(hours=8)) +_t2, _l2 = trade((62.0, 35.0), prices=_late, now=NOW + timedelta(hours=8)) +check("no give block while the emptiest battery is at arbitrage's floor: " + "the cycle's sale is graded on the emptiest pack (at 35 % both give)", + not [k for k in _t if k[0] == "give"] + and [k[:2] for k in _t2] == [("give", 0), ("give", 1)]) +_t, _l = trade((62.0, 35.0), prices=[x - 0.5 for x in MOCK]) +check("no give block at a negative price (the cycle refuses that sale)", + not [k for k in _t if k[0] == "give"] + and [k for k in _t if k[0] == "grid"]) +# Running, a missing level is a red row and the site is held. In shadow mode +# the plan is still drawn, so this is where the level gate shows. +_t, _l = trade((None, 35.0), opts=dict(ARB, shadow_mode="on")) +check("with a battery level unknown the cycle does not trade, so nothing is " + "drawn and a line says why (shadow mode, which still plans)", + _t == [] and homeview.line_no_trade("no_level") in _l) +_t, _l = trade((62.0, 35.0), provisional_from=DAY0) +check("a plan with no published prices yet says so, not 'the price gap is " + "too small'", + _t == [] and homeview.line_no_trade("not_firm") in _l + and homeview.line_no_trade("not_worth") not in _l) check("the price bars are today's 24 hours, from the real series, with the " "cheap and expensive thirds marked", [b["eur_kwh"] for b in s_arb["plan"]["prices"]] == MOCK @@ -295,6 +349,17 @@ check("while the peak limit holds, the verdict refuses as the cycle does: no " and [(r["from"], r["to"]) for r in s_peak["plan"]["runs"] if r["kind"] == "peak"] == [("11:30", "11:45"), ("11:30", "11:45")]) +c_pk = make(ARB) +c_pk.p1_enabled = True # the peak line is shown where P1 runs +c_pk.tariff_plan, c_pk.tariff_at = provider_plan(), NOW +c_pk.peak_guard = PeakDecision(engaged=False, floor_w=None, ceiling_w=4200.0, + ceiling_from="month_peak", projected_w=1240.0) +s_pk = status(c_pk) +check("the plan's peak line names the guard's ceiling, which is this month's " + "peak once it is above the limit", + homeview.line_peak_limit(4200.0, False) in s_pk["plan"]["lines"] + and s_pk["month_peak"]["line"].endswith("above 4.2 kW.")) + c_blind = make(ARB) c_blind.tariff_plan, c_blind.tariff_at = provider_plan(), NOW s_blind = status(c_blind) # meter_source off: the guard never runs -- 2.54.0 From 06aa09e28c9310f504ec3551a8d68e771cf14c6c Mon Sep 17 00:00:00 2001 From: glenn schrooyen Date: Mon, 28 Sep 2026 02:16:24 +0200 Subject: [PATCH 054/105] SAFETY-73 review: a refusal needs 22 s of evidence, and the cut-out warning is for giving only - REFUSED_SPAN_S: the 12 cycles of evidence must also span (SETTLE_CYCLES-1) * LOOP_TICK_S = 22 s. At a 1 s meter, lagged healthy readings refused both units 10-16 times an hour after load steps (site held 0 W). 2 s and slower ticks are unchanged. - REFUSES_ABOVE_CUT_OUT only for a refusal to give power: a full battery that stops taking charge is always above its cut-out level. - test_delivery: its wedged fixture (0.2 s cycles) no longer reaches a refusal; the release/1.0 checks are restored and a span check added. - test_refusal_units: lagged-reading and full-battery plants, two new checks, U14/U15 in the mutation table. Stale "> 500 W" wording fixed. DOCS/DECISIONS. Co-Authored-By: Claude Opus 5.5 --- .../SAFETY-73-refusal-per-inverter.md | 21 ++++- goodwe_controller/DOCS.md | 10 +-- goodwe_controller/app/inverter.py | 6 +- goodwe_controller/app/main.py | 22 +++++- goodwe_controller/test_delivery.py | 39 ++++----- goodwe_controller/test_refusal_units.py | 79 ++++++++++++++++--- 6 files changed, 128 insertions(+), 49 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md b/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md index c30a334..bddc1a9 100644 --- a/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md +++ b/goodwe_controller/DECISIONS/SAFETY-73-refusal-per-inverter.md @@ -26,14 +26,15 @@ standing import, new -16 W. Both cut out: old keeps asking two empty batteries 1. **A refusing unit is closed in that direction** by its own P_SAFETY unit claim, source `refused`. It engages when the unit gives under - `REFUSED_BELOW_W` (100 W) for `SETTLE_CYCLES` (12) cycles in one direction - while asked more than `PROBE_W` (200 W), or when its stale-reading gate + `REFUSED_BELOW_W` (100 W) for `SETTLE_CYCLES` (12) cycles, spanning at least + `REFUSED_SPAN_S` (22 s), in one direction while asked more than `PROBE_W` + (200 W), or when its stale-reading gate trips on a held reading under 100 W. The allocator then hands its share to the others within their own limits (owner decision 1). It is a hard unit limit that always intersects, so OPT-11's P_MODE layer fits inside it. 2. **It binds every strategy's ask on that unit** (decision 2): peak guard, arbitrage and maintenance are placed around it like the loop. -3. **A refusal above the configured cut-out** logs INFO plus one WARNING ending +3. **A refusal to give power above the configured cut-out** logs INFO plus one WARNING ending in `REFUSES_ABOVE_CUT_OUT` (decision 3). SAFETY-42/43 no longer report such a unit: its share is 0 W, and `account()` treats it as parked. 4. **All units refusing the same way** pass that sign to `compute()`, so the @@ -79,6 +80,20 @@ SAFETY-73 method made to raise. target: worst grid +0 W with the reseed. Phase A measured -1059 W without the reseed and the site hold. +## Review changes + +- **The evidence must span 22 s, not only 12 cycles.** At a 1 s meter the 12 + cycles were 11 s, shorter than a healthy reading's lag (dead time plus a + 10-17 s publish). The reviewer's harness (real `Controller`, both units with + 6 s dead time and a 13-17 s publish, load steps 300/3000 W every 2 min) then + refused both healthy units 10-16 times an hour, and each time the site held + 0 W: +50-85 Wh import an hour and a +4.6 kW grid peak against +3.7 kW without + the refusal. At a 2 s tick there were none. `REFUSED_SPAN_S` is + `(SETTLE_CYCLES - 1) * LOOP_TICK_S`, so 2 s and slower ticks are unchanged. +- **The cut-out WARNING is for a refusal to give power only.** A full battery + that stops taking charge is always above its cut-out level, and the WARNING + told the installer to check a setting that has nothing to do with it. + ## Not covered - A unit that gives a steady part of its ask (100 W or more) is a limit, as at diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 28a58f7..4ba090b 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -551,15 +551,15 @@ needs, so a test never trips it. A battery that gives some power, even 100 W, is not refusing and keeps its request. **With two or more inverters** the same rule works per inverter. An inverter -whose battery gives less than 100 W for 12 cycles while asked for more than -200 W is asked 0 W, and the other inverters take over its share, each up to +whose battery gives less than 100 W for 12 cycles, and at least 22 s, while +asked for more than 200 W is asked 0 W, and the other inverters take over its share, each up to its own limits. The status page names it: *inverter-a: the battery refuses to give power, the others take over*. It is tested at 200 W every 15 minutes, one inverter at a time, and only while the site asks at least 200 W that way. -It still accepts charge, and a minute of charging ends the refusal. When every +It still accepts charge, and 12 cycles of charging end the refusal. When every inverter refuses the same way, the whole site asks 0 W as with one inverter. -If the battery refuses while its level reads above its “Battery cut-out level”, -the log adds one warning ending in `REFUSES_ABOVE_CUT_OUT`: check that setting. +If the battery refuses to give power while its level reads above its “Battery +cut-out level”, the log adds one warning ending in `REFUSES_ABOVE_CUT_OUT`: check that setting. A battery that refuses is not reported as *not delivering*. *For installers:* SAFETY-52 and SAFETY-73. The event log reads diff --git a/goodwe_controller/app/inverter.py b/goodwe_controller/app/inverter.py index c5370ef..328c9fa 100644 --- a/goodwe_controller/app/inverter.py +++ b/goodwe_controller/app/inverter.py @@ -319,12 +319,14 @@ class Inverter: # SAFETY-73. The direction this unit's battery refuses (+1 give, -1 # take, 0 none), when that refusal or its last probe started, the - # current probe's start, and the cycles of evidence so far. Memory - # only, like SAFETY-52's: stop and start end it. Used at N>1 only. + # current probe's start, and the cycles of evidence so far and when + # they began. Memory only, like SAFETY-52's: stop and start end it. + # Used at N>1 only. self.refused = 0 self.refused_at = None self.probe_from = None self.ref_count = 0 + self.ref_since = None self.ref_sign = 0 # -- store --------------------------------------------------------------- diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 9921d2e..30df409 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -236,6 +236,15 @@ def pack_energy_of(inv): inv.capacity_kwh, inv.max_w) +# SAFETY-73 review: the evidence must also span this long, not only +# SETTLE_CYCLES cycles. SETTLE_CYCLES was derived at the 2 s meter tick (22 s +# from its first to its twelfth cycle). A 1 s meter makes 12 cycles only 11 s, +# shorter than a healthy battery reading's lag (BATT_OBLIGED_S, 17 s, plus the +# plant's dead time), and both inverters of a site were then refused after +# ordinary load steps. At 2 s and slower this changes nothing. +REFUSED_SPAN_S = (_ctl.SETTLE_CYCLES - 1) * _ctl.LOOP_TICK_S + + def _refused_interval(sign: int) -> tuple: """SAFETY-73: the (lo, hi) a refusing unit may be asked: 0 W that way.""" return (-math.inf, 0.0) if sign > 0 else (0.0, math.inf) @@ -1171,7 +1180,9 @@ class Controller: _LOG.info("%s: the battery refuses power, so it is asked 0 W and the " "other inverters take over: BATTERY_REFUSES.", inv.name) _LOG.debug("Evidence for %s: BATTERY_REFUSES: %s.", inv.name, evidence) - if (inv.soc is not None and inv.bms_soc_floor is not None + # Only a refusal to GIVE: a full battery that stops taking charge is + # above its cut-out level by definition and says nothing about it. + if (sign > 0 and inv.soc is not None and inv.bms_soc_floor is not None and float(inv.soc) > float(inv.bms_soc_floor)): # Owner decision 3: a refusal above the configured cut-out level # may mean that level is set wrong. One line, no safety stop. @@ -1243,12 +1254,15 @@ class Controller: # (a flapping load) reads ~0 through the plant's own lag, and that # is a battery following, not refusing (TEST-19 flapping family). if abs(standing) > _ctl.PROBE_W and abs(b) < _ctl.REFUSED_BELOW_W: - inv.ref_count = (min(inv.ref_count + 1, _ctl.SETTLE_CYCLES) - if sign == inv.ref_sign else 1) + if sign != inv.ref_sign or not inv.ref_count: + inv.ref_count, inv.ref_since = 0, self._now_mono + inv.ref_count = min(inv.ref_count + 1, _ctl.SETTLE_CYCLES) else: inv.ref_count = 0 inv.ref_sign = sign - if inv.ref_count >= _ctl.SETTLE_CYCLES: + if inv.ref_count >= _ctl.SETTLE_CYCLES and ( + inv.ref_since is None or self._now_mono is None + or self._now_mono - inv.ref_since >= REFUSED_SPAN_S): self._unit_refusal_start( inv, sign, f"asked {standing:+.0f} W, the battery gave {b:+.0f} W " diff --git a/goodwe_controller/test_delivery.py b/goodwe_controller/test_delivery.py index 9d07d5a..2688c84 100644 --- a/goodwe_controller/test_delivery.py +++ b/goodwe_controller/test_delivery.py @@ -592,21 +592,16 @@ check("...and the SHARES now differ, which is OPT-09 and not a weakening of the "cards meet here from opposite sides: OPT-09 stops the ASK, this file " "grades the ALARM, and neither can do the other's half", _pw != _pf - and _sf[-1]["shares"][1] == 0.0 - and max(r["shares"][1] for r in _sw) == 2000.0) -# SAFETY-73. A unit that gives < 100 W for 12 cycles while asked > 500 W is a -# battery that refuses (owner, 2026-09-27): it is closed, its share moves, and -# SAFETY-42 is left with units that deliver something but not enough. This -# fixture compresses `delivery_hold_s` to 1 s at 0.2 s cycles, so the report -# still comes first here. On a site 185 s against 60 s puts the refusal first. -_ref_at = next((i for i, r in enumerate(_sw) if r["shares"][1] == 0.0), None) -check("SAFETY-73: the wedged arm's B, giving 0 W against 2000 W, is refused " - "after 12 cycles of that evidence and asked 0 W from then, the report " - "having come first only because this fixture's hold is 1 s", - _ref_at is not None and _ref_at >= control.SETTLE_CYCLES - and all(r["shares"][1] > 0 for r in _sw[:_ref_at]) - and all(r["shares"][1] == 0.0 for r in _sw[_ref_at:]) - and _cw.inverters[1].refused == 1) + and _sf[-1]["shares"][1] == 0.0 and _sw[-1]["shares"][1] == 2000.0) +# SAFETY-73. A unit that gives < 100 W while asked > 200 W is refused after +# SETTLE_CYCLES cycles that also span REFUSED_SPAN_S (22 s). This fixture's 14 +# cycles are 0.2 s apart, so the wedged B meets the count and not the span, and +# SAFETY-42's report stands alone here. test_refusal_units.py grades the +# refusal. On a site the 185 s hold puts the refusal first. +check("SAFETY-73: the wedged arm's B is not refused in this fixture: 12 cycles " + "of evidence in under 3 s are not the 22 s a refusal needs", + _cw.inverters[1].refused == 0 + and _cw.inverters[1].ref_count >= control.SETTLE_CYCLES) check("...and the state of charge is still what tells them apart", [r["soc"] for r in _sw] != [r["soc"] for r in _sf]) print(f" both arms, last cycle: grid {_sw[-1]['grid']:.0f} W, shares " @@ -654,10 +649,10 @@ check("...and `account()` STILL turns this pack away if the ask does arrive - " account(live=True, parked=False, soc=_cold_b.soc, bms_floor=_cold_b.bms_soc_floor) is not None) check("...and the WEDGED arm's B differs from it in exactly that one place - " - "which is why it was asked for its share until the refusal, and named", + "which is why it is still asked for its share, and still named", account(live=True, parked=False, soc=_cw.inverters[1].soc, bms_floor=_cw.inverters[1].bms_soc_floor) is None - and _sw[0]["shares"][1] > 0 and _sw[-1]["named"] == ("inverter-b",)) + and float(_cw.inverters[1].standing_w()) > 0) # ⚠️ WHICH FLOOR, AND THIS IS A WIRING CHECK THAT THE PURE ONES ABOVE CANNOT # MAKE. `peakguard.pack_floor_pct()` conjoins a pack's own cut-out with the @@ -930,13 +925,9 @@ check("...and EVERY WATT IS THE SAME. Grid, site target, both shares and both " "reported or not - which is what 'it does not act' means, stated as a " "measurement instead of as an intention", _power_domain(_sw) == _power_domain(_sn)) -_trip_at = next((i for i, r in enumerate(_sw) if r["named"]), None) -check("...the wedged unit is still commanded its share after the trip, not " - "parked by this guard: this is NOT SAFETY-02's remedy. What later takes " - "the share is SAFETY-73's refusal, which runs the same in the arm where " - "this guard never trips (the line above)", - _trip_at is not None and _ref_at is not None and _trip_at < _ref_at - and all(r["shares"][1] > 0 for r in _sw[_trip_at:_ref_at])) +check("...the wedged unit is still being commanded its share after the trip, " + "not parked: this is NOT SAFETY-02's remedy and must not become it", + abs(float(_cw.inverters[1].target)) > 0) check("...and nothing named `delivery` reaches the arbiter - the resolution's " "own sentence is unchanged by the trip", "deliver" not in _cw.reason.lower() and _cw.reason == _cn.reason) diff --git a/goodwe_controller/test_refusal_units.py b/goodwe_controller/test_refusal_units.py index 525a4b9..4366a7a 100644 --- a/goodwe_controller/test_refusal_units.py +++ b/goodwe_controller/test_refusal_units.py @@ -1,7 +1,7 @@ """Runnable check for SAFETY-73. `python3 test_refusal_units.py` SAFETY-52 per inverter. With two or more inverters, a battery that refuses -(gives < 100 W for 12 cycles while asked > 500 W, or trips the stale-reading +(gives < 100 W for 12 cycles and 22 s while asked > 200 W, or trips the stale-reading gate on a ~0 W reading) is closed in that direction by its own P_SAFETY limit, so the allocator hands its share to the others. It is probed at 200 W every 15 minutes, one inverter at a time. When every inverter refuses the same way @@ -33,6 +33,8 @@ over this file / test_delivery / test_refusal. Every one is red here: U11 main.py: the above-cut-out WARNING condition inverted 1/0/0 U12 main.py: SAFETY-42's account no longer sees a small ask 1/0/0 U13 main.py: a unit engages above `saturation_w`, not PROBE_W 1/0/0 + U14 main.py: the evidence need not span REFUSED_SPAN_S (review) 1/0/0 + U15 main.py: the WARNING also for a refusal to take (review) 1/0/0 On 652097a itself this file stops at the first sample (`Inverter` has no `refused`); its OLD arms reproduce that tree's N>1 behaviour instead, and @@ -61,6 +63,7 @@ def check(name, cond): TICK = 5.0 CUT_W = -4.0 +FULL_W = 40.0 H = 3600.0 BASE = datetime(2026, 9, 6, 19, 30, tzinfo=timezone.utc) UNITS = ("a", "b") @@ -89,23 +92,39 @@ class _Pub: class _Hass: - """A house, one meter, and two batteries that follow unless cut out.""" + """A house, one meter, and two batteries that follow unless cut out. - def __init__(self, load, cut, soc, jitter): + `lag` (review): (dead s, publish s). Each battery reading then shows the + power of `dead` s before its last publish; the power itself and the meter + follow at once. `full[u](t)`: that battery takes at most FULL_W of charge. + """ + + def __init__(self, load, cut, soc, jitter, lag=None, full=None): self.load, self.cut, self.soc, self.jitter = load, cut, soc, jitter + self.lag, self.full = lag, full or {} self.cmd = {u: 0.0 for u in UNITS} + self.hist = {u: [(-1e18, 0.0)] for u in UNITS} self.t = 0.0 - def batt(self, u): - c = self.cmd[u] - if self.cut[u](self.t) and c >= CUT_W: + def power(self, u, t=None): + t = self.t if t is None else t + c = next((v for tt, v in reversed(self.hist[u]) if tt <= t), 0.0) + if self.cut[u](t) and c >= CUT_W: if self.jitter: - return CUT_W + ((int(self.t / TICK) % 3) - 1) * 3.0 + return CUT_W + ((int(t / TICK) % 3) - 1) * 3.0 return CUT_W + if u in self.full and self.full[u](t) and c < -FULL_W: + return -FULL_W return float(round(c)) + def batt(self, u): + if self.lag is None: + return self.power(u) + dead, pub = self.lag + return self.power(u, (self.t // pub) * pub - dead) + def grid(self): - return self.load(self.t) - sum(self.batt(u) for u in UNITS) + return self.load(self.t) - sum(self.power(u) for u in UNITS) async def limits(self, e): return (-2000.0, 2000.0, 1.0) @@ -126,6 +145,7 @@ class _Hass: async def set_number(self, e, v): self.cmd[e[-1]] = float(v) + self.hist[e[-1]].append((self.t, float(v))) return True @@ -136,10 +156,12 @@ def _off(c): def run(load, cut, dur, *, soc=None, jitter=False, old=False, events=None, - extra=None): + extra=None, tick=None, lag=None, full=None): """Real cycles every TICK of simulated time. Rows are dicts per cycle.""" async def go(): - hass = _Hass(load, cut, soc or {"a": 50.0, "b": 50.0}, jitter) + hass = _Hass(load, cut, soc or {"a": 50.0, "b": 50.0}, jitter, lag, + full) + dt = tick or TICK inv = [{"name": f"inverter-{u}", "setpoint_entity": f"number.sp_{u}", "soc_entity": f"sensor.soc_{u}", "batt_entity": f"sensor.batt_{u}", @@ -187,7 +209,7 @@ def run(load, cut, dur, *, soc=None, jitter=False, old=False, events=None, ra=c.inverters[0].refused, rb=c.inverters[1].refused, da=c.inverters[0].delivery_wd.tripped, db=c.inverters[1].delivery_wd.tripped)) - t += TICK + t += dt finally: m.datetime = real_dt return rows, trips, c @@ -448,6 +470,41 @@ check("shadow mode: no inverter is refused and both stay at 0 W", c.inverters[0].refused == 0 and c.inverters[1].refused == 0 and all(r["a"] == 0.0 and r["b"] == 0.0 for r in rows)) +# Review. A 1 s meter makes 12 cycles 11 s, shorter than a healthy battery +# reading's lag (6 s dead time plus a 13 s publish). Ordinary load steps then +# refused both inverters and dropped the site to 0 W (16 times an hour). The +# evidence must also span REFUSED_SPAN_S. +_steps = (lambda t: 300.0 if int(t // 120) % 2 == 0 else 3000.0) +rows, _, c = run(_steps, {"a": never, "b": never}, H, tick=1.0, + lag=(6.0, 13.0)) +check("a 1 s meter and slow battery readings: load steps for an hour refuse " + "neither healthy inverter", + not any(r["ra"] or r["rb"] for r in rows)) +rows, _, c = run(lambda t: 3000.0, {"a": cut_at(120), "b": never}, 600, + tick=1.0, lag=(6.0, 13.0)) +_eng = next((r["t"] for r in rows if r["ra"]), None) +check("...and the same slow readings still refuse a battery that is cut " + "out, after the span and well inside the 185 s report", + _eng is not None and 120 + m.REFUSED_SPAN_S <= _eng < 185 + and not any(r["da"] for r in rows)) + +# Review. A full battery that stops taking charge is refused (charge), and +# it is always above its cut-out level: that says nothing about the setting, +# so it gets the INFO line and no REFUSES_ABOVE_CUT_OUT warning. +_g2 = _Grab() +_lg.setLevel(logging.INFO) +_lg.addHandler(_g2) +rows, _, c = run(lambda t: -3000.0, {"a": never, "b": never}, 600, + soc={"a": 99.0, "b": 60.0}, full={"a": lambda t: t >= 120}) +_lg.removeHandler(_g2) +_lg.setLevel(_lv) +check("a full battery that stops taking charge is refused that way only, " + "with the INFO line and no warning about its cut-out level", + c.inverters[0].refused == -1 + and any(lv == logging.INFO and "BATTERY_REFUSES" in x + for lv, x in _g2.lines) + and not any("REFUSES_ABOVE_CUT_OUT" in x for _lv2, x in _g2.lines)) + # ============================================================================== print("6. one inverter is untouched") # ============================================================================== -- 2.54.0 From c9ab48d6fcc150c4e958d23d9e5a9d43481571ad Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 28 Sep 2026 02:49:58 +0200 Subject: [PATCH 055/105] UX-13 P2: the Installer settings view - Settings tab: the Installer view (app/static/settings.js), drawn from app/uilayout.py through the new app/uipage.py: search, six collapsible groups with "n to fix / n to check / n changed" badges and an "applies after a restart" chip, radio cards, segmented choices, sliders with units (the peak limit in kW), entity pickers with search and the live reading, inverter cards, solar rows, locked measured values behind "Change", and the add-on's refusals, warnings and info beside the field they name. - Save path: the page posts its model to the existing config/validate and config/save; uimodel turns it into options before the shipped validator, so nothing it refuses is saved. No route added. A value equal to the stored one is written as stored, so a save that changed nothing writes an identical blob. Save bar, then the restart dialog that names 0 W. - The region choice shows its preset year; Wallonia and Brussels are listed as having no preset yet (TARIFF-22). "Classic settings" keeps /config. - P1 test findings: (a) "Going to 0 W" until the last accepted power request is 0 W; (b) the trade blocks and the price line name the feed's own points ("Lowest published price"), the hour bars say "hour average"; (c) the entity list's WARNING gives a reason on a timeout. - test_settings.py; test_home, test_haentities, test_uilayout extended. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- .../DECISIONS/UX-13-one-layout-table.md | 6 + goodwe_controller/app/hass.py | 11 +- goodwe_controller/app/homeview.py | 98 +++- goodwe_controller/app/static/app.css | 81 +++ goodwe_controller/app/static/app.js | 21 +- goodwe_controller/app/static/index.html | 25 +- goodwe_controller/app/static/settings.js | 555 ++++++++++++++++++ goodwe_controller/app/ui_text/en.json | 88 ++- goodwe_controller/app/uilayout.py | 16 +- goodwe_controller/app/uimodel.py | 43 +- goodwe_controller/app/uipage.py | 275 +++++++++ goodwe_controller/app/web.py | 73 ++- goodwe_controller/test_haentities.py | 21 + goodwe_controller/test_home.py | 59 +- goodwe_controller/test_messages.py | 2 + goodwe_controller/test_settings.py | 437 ++++++++++++++ goodwe_controller/test_uilayout.py | 11 +- goodwe_controller/tools/ux13_demo.py | 144 ++++- 18 files changed, 1871 insertions(+), 95 deletions(-) create mode 100644 goodwe_controller/app/static/settings.js create mode 100644 goodwe_controller/app/uipage.py create mode 100644 goodwe_controller/test_settings.py diff --git a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md index b23019f..540cbb0 100644 --- a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md +++ b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md @@ -60,6 +60,12 @@ What UX-02 made authoritative stays authoritative: new validator. At P0: 261 calls, 158 refused, no refusal changed. - test_selfconfig.py part 5 still checks the old page script; P1 moves the page into `app/static/` and the same check applies there. +- P2: the Installer view (`app/static/settings.js`) draws from + `app/uipage.py`, which serialises the table and names no key itself + (test_uilayout part 5, test_settings part 2). The view posts its page model + to the existing `/config/validate` and `/config/save`, which turn it into + options with `ui_to_options()` before the shipped validator runs. No route + was added. ## 4. What this costs diff --git a/goodwe_controller/app/hass.py b/goodwe_controller/app/hass.py index 3835e1d..a2546c1 100644 --- a/goodwe_controller/app/hass.py +++ b/goodwe_controller/app/hass.py @@ -132,8 +132,15 @@ class HomeAssistant: except aiohttp.ClientConnectionError as err: OUTAGE.down("api", "no connection", f"read all states: {err}") return None - except (aiohttp.ClientError, TimeoutError, ValueError) as err: - self._moan("read:*", "Reading the entity list failed: %s", err) + # A timeout's own text is empty, so the line names the wait instead + # (UX-13 P1 test, c). + except TimeoutError: + self._moan("read:*", "Reading the entity list failed: no answer " + "within %s seconds.", STATES_TIMEOUT_S) + return None + except (aiohttp.ClientError, ValueError) as err: + self._moan("read:*", "Reading the entity list failed: %s", + str(err) or type(err).__name__) return None if not isinstance(obj, list): self._moan("shape:*", "The entity list is not a list: %.80r", obj) diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 4e58505..250720d 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -82,7 +82,7 @@ def flow(w, *, shadow=False): return "resting" -def now_block(*, grid_w, pv_w, batt_w, has_solar, shadow): +def now_block(*, grid_w, pv_w, batt_w, has_solar, shadow, settled=True): """The four tiles. `house_w` needs all three readings, so without a solar reading it is None rather than a number that leaves the sun out.""" house, disagree = None, False @@ -105,7 +105,7 @@ def now_block(*, grid_w, pv_w, batt_w, has_solar, shadow): "solar": tile_solar(pv_w, has_solar), "house": tile_house(house, has_solar, disagree), "grid": tile_grid(grid_w), - "batt": tile_batt(batt_w, shadow), + "batt": tile_batt(batt_w, shadow, settled), }, } @@ -174,7 +174,7 @@ def hour_bars(points, day0, day1): price = (sum(p.eur_per_kwh for p in inside) / len(inside) if inside else None) bars.append({"h": k, "start": a.isoformat(), "label": hhmm(a), - "end_label": hhmm(b), + "end_label": hhmm(b), "points": len(inside), "eur_kwh": None if price is None else round(price, 4), "estimate": bool(inside) and any(p.provisional for p in inside), @@ -196,6 +196,19 @@ def hour_bars(points, day0, day1): return bars +def day_range(points): + """(lowest, highest) of today's published points, as {eur_kwh, label}, + or (None, None). The feed's own points, like the trade legs, not the + chart's hour averages.""" + firm = [p for p in points if not p.provisional] + if not firm: + return None, None + lo = min(firm, key=lambda p: p.eur_per_kwh) + hi = max(firm, key=lambda p: p.eur_per_kwh) + return ({"eur_kwh": round(lo.eur_per_kwh, 4), "label": hhmm(lo.start)}, + {"eur_kwh": round(hi.eur_per_kwh, 4), "label": hhmm(hi.start)}) + + # --------------------------------------------------------------------------- # # The plan, per battery # --------------------------------------------------------------------------- # @@ -407,7 +420,7 @@ def region_of(opts): if rid in REGION_PRESETS else None} -def build_plan(c, now, shadow, running, held=False): +def build_plan(c, now, shadow, running, held=False, settled=True): day0, day1 = local_day(now) fresh = c.fresh_tariff_plan(now) plan = fresh @@ -477,17 +490,15 @@ def build_plan(c, now, shadow, running, held=False): "day": brussels(now).date().isoformat(), "now_h": round(_hours(now, day0), 3), "hours": int(round(_hours(day1, day0))), - "verdict": VERDICT[verdict_key], + "verdict": (VERDICT[verdict_key] if settled or verdict_key != "held" + else ZERO_GOING), "verdict_key": verdict_key, - "head": plan_head(verdict_key, shadow), + "head": plan_head(verdict_key, shadow, settled), "prices": bars, "runs": runs, "lines": lines, "why": c.why_words, - "price_line": line_prices( - price_now, - min(known, key=lambda b: b["eur_kwh"]) if known else None, - max(known, key=lambda b: b["eur_kwh"]) if known else None), + "price_line": line_prices(price_now, *day_range(seen)), "tomorrow_line": line_tomorrow(tomorrow) if feed else "", "region": region, "region_line": (line_region(region["id"], region["year"]) @@ -499,6 +510,13 @@ def build_plan(c, now, shadow, running, held=False): # --------------------------------------------------------------------------- # # Batteries, attention, month peak, control # --------------------------------------------------------------------------- # +def at_zero(inv) -> bool: + """Has this inverter's last accepted power request reached 0 W? A stop or + an alarm asks for 0 W at once, but the inverter gets it with the next + write, so until then the page says "Going to 0 W" (UX-13 P1 test, a).""" + return abs(inv.standing_w()) < 1.0 + + def battery_rows(c, shadow, running, held=False): shares = {} alloc = getattr(c, "allocation", None) @@ -521,7 +539,8 @@ def battery_rows(c, shadow, running, held=False): "maintenance": phase, "now": battery_now(inv.soc, inv.batt, phase=phase, shadow=shadow, running=running, held=held, - would_w=shares.get(inv.name)), + would_w=shares.get(inv.name), + settled=at_zero(inv)), # Per-battery reasons arrive with battery modes (OPT-11). "why": None, }) @@ -633,15 +652,18 @@ def build(c, *, level: str, checks: list, now: datetime | None = None) -> dict: # what the add-on would do. held = level == "bad" and not shadow running = (bool(c.auto) or shadow) and not held + settled = all(at_zero(inv) for inv in c.inverters) ctl = next((r for r in checks if r.get("id") == "controller"), None) return { "state": {"kind": kind, "pill": pill(kind), "ran": ctl.get("text", "") if ctl else "", "sub": banner_sub(kind)}, "now": now_block(grid_w=c.grid, pv_w=c.pv_w, batt_w=c.site_batt_w, - has_solar=bool(c.pv_roster), shadow=shadow), + has_solar=bool(c.pv_roster), shadow=shadow, + settled=settled), "batteries": battery_rows(c, shadow, running, held), - "plan": build_plan(c, now, shadow, running, held=held), + "plan": build_plan(c, now, shadow, running, held=held, + settled=settled), "attention": ([{"severity": INFO, "id": "shadow", "title": ATTN_SHADOW, "body": attn_shadow_body(), "docs": None}] if shadow else []) + attention(checks), @@ -673,8 +695,9 @@ ATTN_SHADOW = "Shadow mode is on" def attn_shadow_body() -> str: return "The add-on decides everything, but every inverter stays at 0 W." +ZERO_HELD, ZERO_GOING = "Held at 0 W", "Going to 0 W" VERDICT = { - "held": "Held at 0 W", + "held": ZERO_HELD, "stopped": "Stopped", "cycle": "Monthly cycle today", "trade": "Trading on price", @@ -728,26 +751,31 @@ def tile_grid(grid_w) -> str: return "Balanced" -def tile_batt(batt_w, shadow) -> str: +def _zero(settled) -> str: + return ZERO_HELD if settled else ZERO_GOING + + +def tile_batt(batt_w, shadow, settled=True) -> str: if shadow: - return "Held at 0 W" + return _zero(settled) return {"giving": "Giving power", "charging": "Charging", "resting": "Resting", None: "No reading"}[flow(batt_w)] def battery_now(soc, batt_w, *, phase, shadow, running, held=False, - would_w=None) -> str: + would_w=None, settled=True) -> str: if soc is None or batt_w is None: return "No reading from this battery." + zero = _zero(settled) if shadow: if would_w is None or abs(would_w) <= IDLE_W: - return "Held at 0 W. Would rest now." + return f"{zero}. Would rest now." verb = "give" if would_w > 0 else "charge" - return f"Held at 0 W. Would {verb} {_kw(would_w)} now." + return f"{zero}. Would {verb} {_kw(would_w)} now." if held: - return "Held at 0 W until the alarm clears." + return f"{zero} until the alarm clears." if not running: - return "Held at 0 W while control is stopped." + return f"{zero} while control is stopped." if phase != M_IDLE: return {M_DRAIN: "Monthly cycle: emptying.", M_CHARGE: "Monthly cycle: refilling.", @@ -761,9 +789,10 @@ def battery_now(soc, batt_w, *, phase, shadow, running, held=False, return "Resting now." -def plan_head(key, shadow) -> str: +def plan_head(key, shadow, settled=True) -> str: if key == "held": - return "Every inverter is at 0 W until the alarm clears." + return ("Every inverter is at 0 W until the alarm clears." if settled + else "Every inverter goes to 0 W until the alarm clears.") if key == "stopped": return "Control is stopped, so nothing is planned." if not shadow: @@ -784,8 +813,10 @@ def run_grid_what(kwh, shadow) -> str: f" up to {_kwh(kwh)} from the grid." +# The trade legs and the price line use the feed's own points (a 15-minute +# period on a quarter-hourly feed), so both name the same price and time. def run_grid_why(price) -> str: - return f"Cheapest price in the list, {_eur(price)} per kWh." + return f"Lowest published price, {_eur(price)} per kWh." def run_grid_amount(eur) -> str: @@ -798,7 +829,7 @@ def run_give_what(kwh, shadow) -> str: def run_give_why(price) -> str: - return f"Dearest price in the list, {_eur(price)} per kWh." + return f"Highest published price, {_eur(price)} per kWh." def run_give_amount(eur) -> str: @@ -880,8 +911,8 @@ def line_prices(now_eur, lo, hi) -> str: if now_eur is not None: parts.append(f"Price now {_eur(now_eur)} per kWh, all in.") if lo is not None and hi is not None: - parts.append(f"Today: cheapest {_eur(lo['eur_kwh'])} at " - f"{lo['label']}, dearest {_eur(hi['eur_kwh'])} at " + parts.append(f"Today: lowest {_eur(lo['eur_kwh'])} at " + f"{lo['label']}, highest {_eur(hi['eur_kwh'])} at " f"{hi['label']}.") return " ".join(parts) or "No prices for today." @@ -924,7 +955,7 @@ def text_samples() -> list: """`(kind, text)` for every sentence above, rendered with real values, so test_messages.py can hold each to its STYLE limit. Kinds: title, plan (2 sentences of 12 words), line (1 sentence of 25 words).""" - out = [("title", t) for t in VERDICT.values()] + out = [("title", t) for t in VERDICT.values()] + [("title", ZERO_GOING)] out += [("title", t) for t in ATTN_TITLES.values()] out += [("title", MODE_HOUSE), ("title", ATTN_SHADOW), ("line", attn_shadow_body())] @@ -938,6 +969,7 @@ def text_samples() -> list: out.append(("title", tile_house(None, True, True))) out += [("title", tile_grid(v)) for v in (None, 1200, -800, 5)] out += [("title", tile_batt(v, sh)) for v in (None, 2500, -2500, 0)] + out.append(("title", tile_batt(0, sh, settled=False))) for phase in (M_IDLE, M_DRAIN, M_CHARGE, M_HOLD): for w in (2500, -2500, 0): out.append(("plan", battery_now(62, w, phase=phase, @@ -945,8 +977,14 @@ def text_samples() -> list: would_w=-2400))) out.append(("plan", battery_now(62, 0, phase=M_IDLE, shadow=sh, running=False))) - out.append(("plan", battery_now(62, 0, phase=M_IDLE, shadow=False, - running=False, held=True))) + for settled in (True, False): + out.append(("plan", battery_now(62, 0, phase=M_IDLE, shadow=False, + running=False, held=True, + settled=settled))) + out.append(("plan", battery_now(62, 0, phase=M_IDLE, shadow=sh, + running=False, would_w=-2400, + settled=settled))) + out.append(("plan", plan_head("held", sh, settled=False))) out.append(("plan", battery_now(None, None, phase=M_IDLE, shadow=sh, running=True))) for k in VERDICT: diff --git a/goodwe_controller/app/static/app.css b/goodwe_controller/app/static/app.css index 826b35d..ad582d7 100644 --- a/goodwe_controller/app/static/app.css +++ b/goodwe_controller/app/static/app.css @@ -135,3 +135,84 @@ dialog::backdrop{background:rgba(0,0,0,.45)} .chart [data-tip]{cursor:default} .chart [data-tip]:hover,.chart [data-tip]:focus,.chart .hot{outline:2px solid var(--ink);outline-offset:-1px} .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap} +/* UX-13 P2: Settings, the Installer view (mockup version 2) */ +.btn.link{border:0;background:none;color:var(--accent);padding:6px 0;min-height:0} +.search{width:100%;border:1px solid var(--line);background:var(--card);border-radius:10px;padding:10px 12px;min-height:44px;margin-bottom:10px} +.key{font:11px/1.3 ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--faint);overflow-wrap:anywhere} +.chip{display:inline-flex;align-items:center;gap:4px;font-size:12px;border-radius:999px;padding:1px 8px;background:var(--info-bg);color:var(--muted);white-space:nowrap} +.chip.now{background:var(--ok-bg);color:var(--ok)} .chip.rs{background:var(--warn-bg);color:var(--warn)} +.chip.bad{background:var(--bad-bg);color:var(--bad)} .chip.changed{background:var(--accent-soft);color:var(--accent)} +details.grp{background:var(--card);border:1px solid var(--line);border-radius:12px;margin-bottom:10px;box-shadow:var(--shadow)} +details.grp>summary{list-style:none;cursor:pointer;padding:14px;display:flex;gap:10px;align-items:center;min-height:56px;flex-wrap:wrap} +details.grp>summary::-webkit-details-marker{display:none} +details.grp>summary .grow{flex:1 1 200px} +details.grp>summary .gdesc{display:block} +details.grp>summary .chev{transition:transform .15s;flex:none;font-size:22px;line-height:1;width:18px;text-align:center;color:var(--muted)} +details.grp[open]>summary .chev{transform:rotate(90deg)} +.gchips,.gbadge{display:inline-flex;flex-wrap:wrap;gap:4px} +details.grp .body{padding:0 14px 8px} +details.sub{border-top:1px solid var(--line);margin-top:4px} +details.sub>summary{cursor:pointer;padding:10px 0;color:var(--accent);font-size:14px;min-height:44px;display:flex;align-items:center} +.subhead{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--faint);margin:14px 0 0;font-weight:700} +.f{padding:12px 0;border-top:1px solid var(--line);min-width:0} +.part>.f:first-child,.subhead+.f{border-top:0} +.f .lbl{font-weight:600;font-size:14px} +.f .help{font-size:13px;color:var(--muted);margin-top:4px} +.f .ctl{margin-top:8px;min-width:0} +.f.inline{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:4px 12px;align-items:start} +.f.inline .ctl{margin-top:0;grid-row:1;grid-column:2} +.f.inline .help,.f.inline .msgs{grid-column:1/-1} +.f.changed>.head .lbl::after{content:" •";color:var(--accent)} +.msg{font-size:13px;margin-top:6px;display:flex;gap:6px;align-items:flex-start;border-radius:8px;padding:6px 8px;overflow-wrap:anywhere} +.msg .mi{font-weight:800;flex:none} +.msg.bad{background:var(--bad-bg);color:var(--bad)} .msg.warn{background:var(--warn-bg);color:var(--warn)} .msg.info{background:var(--info-bg);color:var(--info)} +.f.has-bad .ctl select,.f.has-bad .ctl input,.f.has-bad .ent-btn{border-color:var(--bad)} +.switch{position:relative;width:52px;height:44px;border:0;background:none;cursor:pointer;flex:none;padding:0} +.switch::before{content:"";position:absolute;left:2px;top:8px;width:48px;height:28px;border-radius:14px;background:var(--track);transition:background .15s} +.switch::after{content:"";position:absolute;top:11px;left:5px;width:22px;height:22px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.3);transition:left .15s} +.switch[aria-checked="true"]::before{background:var(--accent)} +.switch[aria-checked="true"]::after{left:25px} +.swrap{display:inline-flex;align-items:center;gap:8px;min-height:44px} +.swtext{font-size:13px;color:var(--muted)} +select.sel,input.txt,input.num{border:1px solid var(--line);background:var(--card);border-radius:10px;padding:9px 10px;min-height:44px;max-width:100%} +select.sel{width:100%} +.row>select.sel{width:auto;flex:1 1 200px} +input.num{width:110px;text-align:right;font-variant-numeric:tabular-nums} +input.txt{width:100%} +input:disabled{opacity:.6} +.seg{display:inline-flex;border:1px solid var(--line);border-radius:10px;overflow:hidden;max-width:100%;flex-wrap:wrap} +.seg button{border:0;background:var(--card);padding:8px 12px;min-height:44px;cursor:pointer;border-left:1px solid var(--line)} +.seg button:first-child{border-left:0} +.seg button[aria-checked="true"]{background:var(--accent-soft);color:var(--accent);font-weight:600} +.choice{display:flex;gap:10px;align-items:flex-start;border:1px solid var(--line);border-radius:10px;padding:10px 12px;margin-top:8px;cursor:pointer;width:100%;text-align:left;background:var(--card);min-height:44px} +.choice[aria-checked="true"]{border-color:var(--accent);background:var(--accent-soft)} +.choice .rad{flex:none;width:18px;height:18px;border-radius:50%;border:2px solid var(--faint);margin-top:2px} +.choice[aria-checked="true"] .rad{border:5px solid var(--accent)} +.slider{display:flex;align-items:center;gap:10px;width:100%} +.slider input[type=range]{flex:1;min-width:0;accent-color:var(--accent);height:28px} +.unit{color:var(--muted);font-size:13px;white-space:nowrap} +.ent-btn{width:100%;text-align:left;border:1px solid var(--line);background:var(--card);border-radius:10px;padding:8px 10px;min-height:44px;cursor:pointer;display:flex;gap:8px;align-items:center} +.ent-btn .grow{min-width:0} +.ent-btn .grow>div{overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.ent-pop{border:1px solid var(--line);border-radius:10px;margin-top:6px;background:var(--card);overflow:hidden} +.ent-pop input[type=search]{border:0;border-bottom:1px solid var(--line);width:100%;padding:10px;background:var(--card);min-height:44px} +.ent-note{padding:6px 10px} +.ent-list{max-height:240px;overflow:auto} +.ent-opt{display:flex;gap:8px;align-items:center;width:100%;border:0;border-bottom:1px solid var(--line);background:none;text-align:left;padding:8px 10px;cursor:pointer;min-height:44px} +.ent-opt:hover,.ent-opt:focus{background:var(--accent-soft)} +.ent-opt .grow{min-width:0} +.ent-opt .grow>div{overflow-wrap:anywhere} +.ent-opt .v{font-variant-numeric:tabular-nums;font-size:13px;color:var(--muted);white-space:nowrap} +.ent-all{display:flex;gap:6px;padding:6px 10px;align-items:center;min-height:44px} +.elist .erow{padding:6px 0;border-bottom:1px dashed var(--line)} +.elist>.btn{margin-top:8px} +.inv{border:1px solid var(--line);border-radius:10px;padding:0 12px;margin:10px 0} +.inv>.hd{display:flex;align-items:center;gap:8px;padding:10px 0;border-bottom:1px solid var(--line);font-weight:600;flex-wrap:wrap} +.inv>.f:nth-child(2){border-top:0} +.invs>.btn{margin:4px 0 8px} +#savebar{position:fixed;left:0;right:0;bottom:0;z-index:15} +#savebar .in{max-width:820px;margin:0 auto 10px;padding:10px 12px;background:var(--ink);color:var(--bg);border-radius:12px;display:flex;flex-wrap:wrap;gap:8px;align-items:center;box-shadow:0 4px 16px rgba(0,0,0,.25);width:calc(100% - 32px)} +#savebar .btn{min-height:44px;padding:6px 12px;background:transparent;color:var(--bg);border-color:rgba(127,127,127,.6)} +#savebar .btn.primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent)} +@media (max-width:640px){#savebar{bottom:62px}} +#s-set{padding-bottom:80px} diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index fb9810a..0153c55 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -40,10 +40,12 @@ clearTimeout(toast.timer); toast.timer = setTimeout(() => e.classList.remove("show"), 2600); } let onYes = null; + // `key` names Home's words in ui_text, or is {name, description, yes}. function ask(key, fn) { - $("#dlg-t").textContent = t("dialog." + key + ".name"); - $("#dlg-b").textContent = t("dialog." + key + ".description"); - $("#dlg-yes").textContent = t("dialog." + key + ".yes"); + const w = typeof key === "string" ? t("dialog." + key) : key; + $("#dlg-t").textContent = w.name; + $("#dlg-b").textContent = w.description; + $("#dlg-yes").textContent = w.yes; onYes = fn; const d = $("#dlg"); if (typeof d.showModal === "function") d.showModal(); else if (window.confirm($("#dlg-t").textContent)) fn(); @@ -98,7 +100,6 @@ renderControl(structured); renderDetails(!structured); renderBatteries(); - renderSettings(); } /* ---------------- Home: now ---------------- */ @@ -162,7 +163,7 @@ const title = b.label + " " + t("plan.time_to") + " " + b.end_label; if (b.eur_kwh == null) return chartItem("i", "none", "", title, [t("plan.none_tip") + "."]); const kind = b.kind === "cheap" ? ", " + t("plan.cheap_tip") : b.kind === "dear" ? ", " + t("plan.dear_tip") : ""; - const est = b.estimate ? ", " + t("plan.estimate_tip") : ""; + const est = (b.points > 1 ? ", " + t("plan.average_tip") : "") + (b.estimate ? ", " + t("plan.estimate_tip") : ""); return chartItem("i", (b.kind || "mid") + (b.estimate ? " est" : ""), "height:" + Math.max(4, Math.round(Math.abs(b.eur_kwh) / mx * 100)) + "%", title, [eur(b.eur_kwh) + " " + t("plan.per_kwh") + kind + est + "."]); @@ -289,7 +290,7 @@ if (open) $("#c-details").open = true; } - /* ---------------- Batteries and Settings (placeholders until P2/P3) ---------------- */ + /* ---------------- Batteries (placeholder until P3) ---------------- */ function renderBatteries() { if (!S.batteries) { $("#bcards").replaceChildren(); return; } $("#bcards").replaceChildren(...S.batteries.map((b) => h("div", { class: "card" }, @@ -301,10 +302,6 @@ h("dt", {}, t("batteries.now")), h("dd", {}, b.now), h("dt", {}, t("batteries.mode")), h("dd", {}, b.mode))))); } - function renderSettings() { - const line = S.plan && S.plan.region_line; - $("#set-region").textContent = line || ""; $("#set-region").hidden = !line; - } /* ---------------- control buttons ---------------- */ // The action is a toggle, so the page reads the live state first and sends @@ -334,6 +331,9 @@ $("#btn-maint").addEventListener("click", () => ask("maint_start", () => simple("maint_start"))); $("#btn-abort").addEventListener("click", () => ask("maint_abort", () => simple("maint_abort"))); + // Shared with settings.js, which loads after this file. + window.UX13 = { h, ask, toast, t, maint: (what) => ask(what, () => simple(what)) }; + /* ---------------- tabs: hash routes, arrow keys ---------------- */ const TABS = [...document.querySelectorAll(".tab")]; function select(tab, focus) { @@ -345,6 +345,7 @@ if (focus) tab.focus(); if (location.hash !== "#" + tab.dataset.hash) history.replaceState(null, "", "#" + tab.dataset.hash); schedule(); + document.dispatchEvent(new CustomEvent("ux13:tab", { detail: tab.dataset.hash })); } TABS.forEach((x, i) => { x.addEventListener("click", () => select(x, false)); diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html index cecb7a2..ad2b649 100644 --- a/goodwe_controller/app/static/index.html +++ b/goodwe_controller/app/static/index.html @@ -96,16 +96,23 @@

      - +
      @@ -126,10 +133,16 @@ +
      + diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js new file mode 100644 index 0000000..074ad3e --- /dev/null +++ b/goodwe_controller/app/static/settings.js @@ -0,0 +1,555 @@ +"use strict"; +/* UX-13 P2: Settings, the Installer view. It draws from /config/model's + `layout` (app/uilayout.py through app/uipage.py) and `ui` (the page model + from app/uimodel.py), so this file names no option key: keys, labels, + ranges and choices all arrive as data. It posts the page model back; the + add-on turns it into options and runs its own start checks, and nothing + they refuse is saved. Every word is from app/ui_text or the add-on, and + data is set as text, never as HTML. */ +(function () { + const ROOT = JSON.parse(document.getElementById("ui-text").textContent); + const W = ROOT.settings; + const { h, ask, toast, maint } = window.UX13; + const $ = (s) => document.querySelector(s); + const ws = (path) => path.split(".").reduce((o, k) => (o == null ? o : o[k]), W); + const clone = (x) => (x === undefined ? undefined : JSON.parse(JSON.stringify(x))); + const same = (a, b) => JSON.stringify(a ?? null) === JSON.stringify(b ?? null); + + document.querySelectorAll("[data-s]").forEach((e) => { e.textContent = ws(e.dataset.s) || ""; }); + document.querySelectorAll("[data-s-ph]").forEach((e) => { e.placeholder = ws(e.dataset.sPh) || ""; }); + document.querySelectorAll("[data-s-label]").forEach((e) => { e.setAttribute("aria-label", ws(e.dataset.sLabel) || ""); }); + $("#savebar").setAttribute("aria-label", W.savebar.label); + + let M = null; // the last /config/model + let V = null; // the page model being edited + let ORIG = null; // the page model as stored + let FP = ""; // the stored blob's fingerprint (compare-and-swap) + let MSG = []; // [{field, card, tier, text}] from the add-on + let DEVICE = ""; + let LIST = null; // the inverter list field + let FILLED = {}; // field key -> the preset field that fills it + let active = false; + let uid = 0; + const ROWS = []; + const OPEN = new Set(); + const UNLOCKED = new Set(); + + /* ---------------- the page model ---------------- */ + const sub = (f) => f.key.slice(LIST.key.length + 1); + function valueIn(model, f, card) { + if (card == null) return model[f.key]; + const c = (model[LIST.key] || [])[card]; + return c ? c[sub(f)] : undefined; + } + const get = (f, card) => valueIn(V, f, card); + function visible(f) { + return (f.show || []).every(([name, op, want]) => { + const have = V[name]; + if (op === "==") return same(have, want); + if (op === "!=") return !same(have, want); + if (op === "in") return want.some((x) => same(x, have)); + if (have == null || have === "" || isNaN(+have)) return false; + return op === ">" ? +have > want : +have < want; + }); + } + function put(f, card, v, redraw) { + if (card == null) V[f.key] = v; + else V[LIST.key][card][sub(f)] = v; + if (f.mirror) { + const m = findField(f.mirror); + if (m && (m.choices || []).some((c) => same(c[0], v))) V[f.mirror] = v; + } + if (f.fills && f.presets && f.presets[v]) V[f.fills] = f.presets[v].value; + if (redraw || f.fills) render(); else paint(); + queueValidate(); + } + function findField(key) { + for (const g of M.layout.groups) for (const p of g.parts) for (const f of p.fields) { + if (f.key === key) return f; + for (const s of f.fields || []) if (s.key === key) return s; + } + return null; + } + + /* ---------------- numbers: stored units <-> shown units ---------------- */ + const decimals = (x) => { const s = String(x); return s.includes(".") ? s.split(".")[1].length : 0; }; + function shown(f, v) { + if (v == null || v === "") return ""; + return String(+(Number(v) / (f.scale || 1)).toFixed(6)); + } + function stored(f, x) { + const st = f.step || (f.type === "integer" ? 1 : 0); + let v = x * (f.scale || 1); + if (st) v = Math.round(v / st) * st; + if (f.min != null) v = Math.max(f.min, v); + if (f.max != null) v = Math.min(f.max, v); + return f.type === "integer" ? Math.round(v) : +v.toFixed(Math.min(10, decimals(st) + 2)); + } + + /* ---------------- controls ---------------- */ + function choicesOf(f, cur) { + const out = (f.choices || []).filter((c) => !c[2] || same(c[0], cur)); + if (cur != null && cur !== "" && !out.some((c) => same(c[0], cur))) out.push([cur, String(cur)]); + return out; + } + function toggle(f, card, lid) { + const on = !!get(f, card); + const b = h("button", { type: "button", class: "switch", role: "switch", "aria-checked": String(on), "aria-labelledby": lid }); + const txt = h("span", { class: "swtext", "aria-hidden": "true" }, on ? W.on : W.off); + b.addEventListener("click", () => { + const n = b.getAttribute("aria-checked") !== "true"; + b.setAttribute("aria-checked", String(n)); txt.textContent = n ? W.on : W.off; + put(f, card, n); + }); + return h("span", { class: "swrap" }, b, txt); + } + function radios(f, card, lid, cards) { + const cur = get(f, card); + const g = h("div", { class: cards ? "choices" : "seg", role: "radiogroup", "aria-labelledby": lid }); + const items = choicesOf(f, cur); + const buttons = items.map(([v, label], i) => { + const on = same(v, cur); + const hint = cards && f.hints ? f.hints[v] : ""; + const b = h("button", { type: "button", role: "radio", class: cards ? "choice" : null, "aria-checked": String(on), + tabindex: on || (!items.some((c) => same(c[0], cur)) && i === 0) ? "0" : "-1" }, + cards ? [h("span", { class: "rad", "aria-hidden": "true" }), h("span", {}, h("div", {}, label), hint ? h("div", { class: "tiny muted" }, hint) : null)] : label); + b.addEventListener("click", () => put(f, card, v, true)); + b.addEventListener("keydown", (e) => { + const d = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[e.key]; + if (!d) return; + e.preventDefault(); + const j = (i + d + items.length) % items.length; + put(f, card, items[j][0], true); + const again = document.querySelector(`[data-rk="${CSS.escape(g.dataset.rk)}"] [role=radio]:nth-child(${j + 1})`); + if (again) again.focus(); + }); + return b; + }); + g.dataset.rk = f.key + "|" + card; + g.append(...buttons); + return g; + } + function select(f, card, lid) { + const cur = get(f, card); + const s = h("select", { class: "sel", "aria-labelledby": lid }); + for (const [v, label] of choicesOf(f, cur)) s.append(h("option", { value: JSON.stringify(v), selected: same(v, cur) }, label)); + for (const [v, label] of f.later || []) s.append(h("option", { value: JSON.stringify(v), disabled: true }, label)); + s.addEventListener("change", () => put(f, card, JSON.parse(s.value), true)); + const preset = f.presets && f.presets[cur]; + return preset ? h("div", { class: "row" }, s, h("span", { class: "chip" }, W.region_year.replace("{year}", preset.year))) : s; + } + function slider(f, card, lid) { + if (f.min == null || f.max == null) return number(f, card, lid); + const sc = f.scale || 1; + const st = f.step || (f.type === "integer" ? 1 : 0.01); + const v = get(f, card); + const r = h("input", { type: "range", min: f.min, max: f.max, step: st, value: v == null ? f.min : v, "aria-labelledby": lid }); + const n = h("input", { class: "num", type: "number", inputmode: "decimal", min: f.min / sc, max: f.max / sc, step: st / sc, value: shown(f, v), "aria-labelledby": lid }); + r.addEventListener("input", () => { const x = stored(f, +r.value / sc); n.value = shown(f, x); put(f, card, x); }); + n.addEventListener("change", () => { + if (n.value === "" || isNaN(+n.value)) { n.value = shown(f, get(f, card)); return; } + const x = stored(f, +n.value); r.value = x; n.value = shown(f, x); put(f, card, x); + }); + return h("div", { class: "slider" }, r, n, f.unit ? h("span", { class: "unit" }, f.unit) : null); + } + function number(f, card, lid) { + const sc = f.scale || 1; + const by = FILLED[f.key]; + const preset = by && by.presets[V[by.key]]; + const n = h("input", { class: "num", type: "number", inputmode: "decimal", step: f.step ? f.step / sc : "any", + min: f.min == null ? null : f.min / sc, max: f.max == null ? null : f.max / sc, + value: shown(f, get(f, card)), disabled: !!preset, "aria-labelledby": lid }); + n.addEventListener("input", () => { + if (n.value === "") { if (f.optional) put(f, card, null); return; } + if (!isNaN(+n.value)) put(f, card, stored(f, +n.value)); + }); + n.addEventListener("change", () => { n.value = shown(f, get(f, card)); }); + return h("div", {}, h("div", { class: "row" }, n, f.unit ? h("span", { class: "unit" }, f.unit) : null), + preset ? h("div", { class: "tiny muted" }, W.preset.description) : null); + } + function text(f, card, lid) { + const v = get(f, card); + const t = h("input", { class: "txt", type: "text", value: v == null ? "" : v, autocapitalize: "none", spellcheck: "false", "aria-labelledby": lid }); + t.addEventListener("input", () => put(f, card, t.value)); + return t; + } + function locked(f, card, lid) { + const box = h("div", {}); + const id = f.key + "#" + card; + const open = () => { UNLOCKED.add(id); box.replaceChildren(slider(f, card, lid)); }; + if (UNLOCKED.has(id)) { open(); return box; } + const v = get(f, card); + box.append(h("div", { class: "row" }, + h("strong", {}, v == null ? W.not_set : shown(f, v) + (f.unit ? " " + f.unit : "")), + h("span", { class: "chip" }, W.locked), + h("button", { type: "button", class: "btn link", "aria-label": W.change + ": " + f.label, onclick: open }, W.change))); + return box; + } + + /* entity picker: search, the matching kind first, the live reading */ + const ENT = {}; + function entities(kind) { + const now = Date.now(); + const e = ENT[kind]; + if (e && now - e.at < 30000) return e.p; + const p = fetch("ha/entities?kind=" + encodeURIComponent(kind || ""), { cache: "no-store" }) + .then((r) => (r.ok ? r.json() : { available: false, entities: [] })) + .catch(() => ({ available: false, entities: [] })); + ENT[kind] = { at: now, p }; + return p; + } + const reading = (e) => (e && e.state != null && e.state !== "" ? String(e.state) + (e.unit ? " " + e.unit : "") : "–"); + function picker(f, lid, value, pick) { + let data = null, all = false; + const btn = h("button", { type: "button", class: "ent-btn", "aria-expanded": "false", "aria-haspopup": "listbox", "aria-labelledby": lid }); + const pop = h("div", { class: "ent-pop", hidden: true }); + const q = h("input", { type: "search", placeholder: W.picker.search.description, "aria-label": W.picker.search.description, autocomplete: "off", spellcheck: "false" }); + const note = h("div", { class: "tiny muted ent-note" }); + const list = h("div", { class: "ent-list", role: "listbox", "aria-labelledby": lid }); + const allBox = h("label", { class: "tiny muted ent-all" }, + h("input", { type: "checkbox", onchange: (e) => { all = e.target.checked; fill(); } }), W.picker.all); + function drawBtn() { + const id = value(); + const e = data && data.entities.find((x) => x.entity_id === id); + btn.replaceChildren(); + if (id) btn.append(h("span", { class: "grow" }, h("div", {}, e ? e.name : id), h("div", { class: "key" }, id)), + data && data.available ? h("span", { class: "chip " + (e ? "now" : "rs") }, e ? reading(e) : W.picker.missing) : null); + else btn.append(h("span", { class: "grow muted" }, W.picker.choose)); + btn.append(h("span", { class: "muted", "aria-hidden": "true" }, "▾")); + } + function opt(id, name, val) { + return h("button", { type: "button", class: "ent-opt", role: "option", "aria-selected": String(id === value()), + onclick: () => { pick(id); close(); drawBtn(); btn.focus(); } }, + h("span", { class: "grow" }, h("div", {}, name), h("div", { class: "key" }, id)), val ? h("span", { class: "v" }, val) : null); + } + function fill() { + const typed = q.value.trim(); + const t = typed.toLowerCase(); + const rows = (data ? data.entities : []).filter((e) => (all || e.match) && (e.entity_id + " " + e.name).toLowerCase().includes(t)).slice(0, 200); + list.replaceChildren(...rows.map((e) => opt(e.entity_id, e.name, reading(e)))); + if (typed.includes(".") && !rows.some((e) => e.entity_id === typed)) list.append(opt(typed, W.picker.use, "")); + if (!list.children.length) list.append(h("div", { class: "small muted", style: "padding:10px" }, W.picker.none.description)); + note.textContent = data && data.text ? data.text : ""; + note.hidden = !note.textContent; + } + function close() { pop.hidden = true; btn.setAttribute("aria-expanded", "false"); } + btn.addEventListener("click", () => { + if (!pop.hidden) { close(); return; } + pop.hidden = false; btn.setAttribute("aria-expanded", "true"); q.value = ""; fill(); + setTimeout(() => q.focus(), 0); + }); + q.addEventListener("input", fill); + pop.addEventListener("keydown", (e) => { + if (e.key === "Escape") { e.preventDefault(); close(); btn.focus(); return; } + if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return; + e.preventDefault(); + const opts = [...list.querySelectorAll(".ent-opt")]; + const i = opts.indexOf(document.activeElement); + const j = e.key === "ArrowDown" ? Math.min(opts.length - 1, i + 1) : i - 1; + if (j < 0) q.focus(); else if (opts[j]) opts[j].focus(); + }); + pop.append(q, note, list, allBox); + drawBtn(); + entities(f.kind).then((d) => { data = d; drawBtn(); if (!pop.hidden) fill(); }); + return h("div", { class: "ent" }, btn, pop, + f.optional ? h("button", { type: "button", class: "btn link tiny", onclick: () => { pick(""); drawBtn(); } }, W.picker.clear) : null); + } + function entity(f, card, lid) { + return picker(f, lid, () => get(f, card) || "", (v) => put(f, card, v)); + } + function entityList(f, card, lid) { + const arr = () => (Array.isArray(get(f, card)) ? get(f, card) : []); + const box = h("div", { class: "elist" }); + arr().forEach((_id, i) => { + box.append(h("div", { class: "erow" }, + h("div", { class: "tiny muted" }, W.phase + " " + (i + 1)), + picker(f, lid, () => arr()[i] || "", (v) => { const a = arr().slice(); a[i] = v; put(f, card, a); }), + h("button", { type: "button", class: "btn link tiny", onclick: () => { const a = arr().slice(); a.splice(i, 1); put(f, card, a, true); } }, W.remove))); + }); + box.append(h("button", { type: "button", class: "btn", onclick: () => put(f, card, arr().concat([""]), true) }, "+ " + W.add_row)); + return box; + } + function solarList(f, card, lid) { + const arr = () => (Array.isArray(get(f, card)) ? get(f, card) : []); + const box = h("div", { class: "elist" }); + arr().forEach((row, i) => { + const flip = h("button", { type: "button", class: "switch", role: "switch", "aria-checked": String(!!row.reversed), "aria-label": W.reversed }); + flip.addEventListener("click", () => { const a = clone(arr()); a[i].reversed = !a[i].reversed; put(f, card, a, true); }); + box.append(h("div", { class: "erow" }, + picker(f, lid, () => arr()[i].entity || "", (v) => { const a = clone(arr()); a[i].entity = v; put(f, card, a); }), + h("div", { class: "row" }, h("span", { class: "swrap" }, flip, h("span", { class: "swtext" }, W.reversed)), + h("button", { type: "button", class: "btn link tiny", onclick: () => { const a = clone(arr()); a.splice(i, 1); put(f, card, a, true); } }, W.remove)))); + }); + box.append(h("button", { type: "button", class: "btn", onclick: () => put(f, card, arr().concat([{ entity: "", reversed: false }]), true) }, "+ " + W.add_solar)); + return box; + } + const CONTROLS = { toggle, segmented: (f, c, l) => radios(f, c, l, false), choice: (f, c, l) => radios(f, c, l, true), + select, slider, number, text, locked, entity, entity_list: entityList, solar_list: solarList }; + + /* ---------------- rows, cards and groups ---------------- */ + function keyText(f, card) { + if (card != null) return V[LIST.shape] === "flat" && f.flat ? f.flat : LIST.key + "[" + card + "]." + sub(f); + return f.key.startsWith("ui.") ? (f.writes || []).join(", ") : f.key; + } + function fieldRow(f, card, gid) { + if (f.control === "inverter_list") return cardList(f, gid); + const lid = "sf" + (++uid); + const keys = keyText(f, card); + const msg = h("div", { class: "msgs" }); + const make = CONTROLS[f.control] || text; + const row = h("div", { class: "f" + (f.control === "toggle" ? " inline" : ""), "data-key": f.key, "data-card": card }, + h("div", { class: "head" }, h("div", { class: "lbl", id: lid }, f.label, f.unit && f.control !== "slider" && f.control !== "number" && f.control !== "locked" ? " (" + f.unit + ")" : ""), + keys ? h("div", { class: "key" }, keys) : null), + h("div", { class: "ctl" }, make(f, card, lid)), + f.help ? h("div", { class: "help" }, f.help) : null, msg); + ROWS.push({ f, card, el: row, msg, gid, search: (f.label + " " + keys + " " + f.key + " " + (f.help || "")).toLowerCase() }); + return row; + } + function blankCard(f, first) { + const out = {}; + for (const s of f.fields) { + const k = sub(s); + out[k] = s.control === "slider" && first && first[k] != null ? first[k] : s.type === "boolean" ? false : s.control === "number" ? null : ""; + } + return out; + } + function cardList(f, gid) { + const wrap = h("div", { class: "invs", "data-key": f.key }); + const msg = h("div", { class: "msgs" }); + const cards = V[f.key]; + if (!Array.isArray(cards)) { + wrap.append(h("div", { class: "msg info" }, W.raw_roster.description), msg); + } else { + cards.forEach((c, i) => { + const box = h("div", { class: "inv" }, h("div", { class: "hd" }, + h("span", { class: "grow" }, c.name || W.inverter + " " + (i + 1)), h("span", { class: "key" }, f.key + "[" + i + "]"), + cards.length > 1 ? h("button", { type: "button", class: "btn link tiny", onclick: () => { + V[f.key].splice(i, 1); V[f.count] = V[f.key].length; put(f, null, V[f.key], true); + } }, W.remove) : null)); + for (const s of f.fields) box.append(fieldRow(s, i, gid)); + wrap.append(box); + }); + wrap.append(msg, h("button", { type: "button", class: "btn", onclick: () => { + V[f.key].push(blankCard(f, V[f.key][0])); Object.assign(V, f.grow); V[f.count] = V[f.key].length; + put(f, null, V[f.key], true); + } }, "+ " + W.add_inverter)); + } + ROWS.push({ f, card: null, el: wrap, msg, gid, list: true, search: (f.label + " " + f.key + " " + (f.help || "")).toLowerCase() }); + return wrap; + } + const chev = () => h("span", { class: "chev", "aria-hidden": "true" }, "›"); + function render() { + const host = $("#groups"); + const y = window.scrollY; + host.replaceChildren(); + ROWS.length = 0; + for (const g of M.layout.groups) { + const d = h("details", { class: "grp", "data-g": g.id }, + h("summary", {}, h("span", { class: "grow" }, h("strong", {}, g.name), h("span", { class: "small muted gdesc" }, g.description)), + h("span", { class: "gchips" }, h("span", { class: "gbadge" }), ...g.applies.map((a) => h("span", { class: "chip applies" }, a))), chev())); + d.open = OPEN.has(g.id); + d.addEventListener("toggle", () => { if (!$("#set-search").value) (d.open ? OPEN.add(g.id) : OPEN.delete(g.id)); }); + const body = h("div", { class: "body" }); + if (g.support_only) body.append(h("div", { class: "msg warn", role: "note" }, W.support.description)); + for (const p of g.parts) { + const pid = g.id + "." + p.id; + let box; + if (p.collapsed) { + box = h("details", { class: "sub part" }, h("summary", {}, p.name)); + box.open = OPEN.has(pid); + box.addEventListener("toggle", () => { if (!$("#set-search").value) (box.open ? OPEN.add(pid) : OPEN.delete(pid)); }); + } else { + box = h("div", { class: "part" }, p.name ? h("div", { class: "subhead" }, p.name) : null); + } + if (p.description) box.append(h("p", { class: "small muted", style: "margin:4px 0" }, p.description)); + for (const f of p.fields) box.append(fieldRow(f, null, g.id)); + body.append(box); + } + if (g.id === "maintenance") { + body.append(h("div", { class: "part" }, h("div", { class: "subhead" }, W.cycle.name), + h("p", { class: "small muted", style: "margin:4px 0" }, W.cycle.description), + h("div", { class: "row" }, + h("button", { type: "button", class: "btn", onclick: () => maint("maint_start") }, ROOT.home.control.maint_start), + h("button", { type: "button", class: "btn danger", onclick: () => maint("maint_abort") }, ROOT.home.control.maint_abort)))); + } + d.append(body); + host.append(d); + } + paint(); + window.scrollTo(0, y); + } + + /* ---------------- messages, visibility, search, badges ---------------- */ + const ICON = { bad: "×", warn: "!", info: "i" }; + const RANK = { bad: 0, warn: 1, info: 2 }; + function mine(r, m) { + if (m.field !== r.f.key) return false; + if (r.list || r.card == null) return true; + return m.card == null ? r.card === 0 : m.card === r.card; + } + function paint() { + const q = $("#set-search").value.trim().toLowerCase(); + const placed = new Set(); + for (const r of ROWS) { + r.visible = visible(r.f); + const msgs = MSG.filter((m, i) => { const hit = mine(r, m); if (hit && r.visible) placed.add(i); return hit; }) + .sort((a, z) => RANK[a.tier] - RANK[z.tier]); + r.tiers = new Set(msgs.map((m) => m.tier)); + r.msg.replaceChildren(...msgs.map((m) => h("div", { class: "msg " + m.tier }, + h("span", { class: "mi", "aria-hidden": "true" }, ICON[m.tier] || "i"), + h("span", {}, h("span", { class: "sr" }, W.tier[m.tier] + ": "), m.text)))); + r.el.classList.toggle("has-bad", r.tiers.has("bad")); + // A card list counts as one change when cards were added or removed; + // an edit inside a card counts on its own row. + r.changed = r.list ? !same((get(r.f) || []).length, (valueIn(ORIG, r.f) || []).length) + : !same(get(r.f, r.card), valueIn(ORIG, r.f, r.card)); + r.el.classList.toggle("changed", r.changed && !r.list); + } + // Search: a row shows when it is visible and matches. A card list shows + // while any of its rows does. + for (const r of ROWS) if (!r.list) r.el.hidden = !(r.visible && (!q || r.search.includes(q))); + for (const r of ROWS) if (r.list) r.el.hidden = !!q && !r.search.includes(q) && !ROWS.some((s) => !s.list && s.card != null && !s.el.hidden); + let any = false; + document.querySelectorAll("#groups details.grp").forEach((d) => { + const rows = ROWS.filter((r) => r.gid === d.dataset.g); + d.querySelectorAll(".part").forEach((p) => { + const inside = rows.filter((r) => p.contains(r.el)); + if (inside.length) p.hidden = inside.every((r) => r.el.hidden); + }); + const hit = rows.some((r) => !r.el.hidden); + any = any || hit; + d.hidden = !!q && !hit; + if (q && hit) { d.open = true; d.querySelectorAll("details.sub").forEach((s) => { s.open = true; }); } + const shownRows = rows.filter((r) => r.visible && !r.list); + const bad = shownRows.filter((r) => r.tiers.has("bad")).length + rows.filter((r) => r.list && r.tiers.has("bad")).length; + const warn = shownRows.filter((r) => !r.tiers.has("bad") && r.tiers.has("warn")).length; + const changed = rows.filter((r) => r.changed).length; + d.querySelector(".gbadge").replaceChildren(...[ + bad ? h("span", { class: "chip bad" }, bad + " " + W.to_fix) : null, + warn ? h("span", { class: "chip rs" }, warn + " " + W.to_check) : null, + changed ? h("span", { class: "chip changed" }, changed + " " + W.changed) : null].filter(Boolean)); + }); + $("#set-nomatch").hidden = !q || any; + // A sentence shown beside any field is not repeated here. + const shownText = new Set(MSG.filter((m, i) => placed.has(i)).map((m) => m.text)); + const other = MSG.filter((m, i) => !shownText.has(m.text) && MSG.findIndex((x) => x.text === m.text) === i); + if (DEVICE) other.push({ tier: "info", text: DEVICE }); + $("#set-other").hidden = !other.length; + $("#set-other-list").replaceChildren(...other.map((m) => h("li", { class: "c-" + ({ bad: "bad", warn: "warn" }[m.tier] || "info") }, + h("span", { class: "sr" }, W.tier[m.tier] + ": "), (ICON[m.tier] || "i") + " " + m.text))); + savebar(); + } + function dirtyCount() { + const seen = new Set(); + for (const r of ROWS) if (r.changed) seen.add(r.f.key + "#" + r.card); + return seen.size; + } + function savebar() { + const n = V ? dirtyCount() : 0; + $("#savebar").hidden = !(active && n); + $("#sb-text").textContent = n + " " + (n === 1 ? W.savebar.one : W.savebar.many); + } + $("#set-search").addEventListener("input", () => { if (V) paint(); }); + + /* ---------------- talking to the add-on ---------------- */ + let vtimer = null, vseq = 0; + function queueValidate() { clearTimeout(vtimer); vtimer = setTimeout(validate, 400); } + async function validate() { + const seq = ++vseq; + try { + const r = await fetch("config/validate", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ model: V }) }); + const b = await r.json(); + if (seq !== vseq) return; + MSG = b.messages || []; + DEVICE = b.device_note || ""; + paint(); + } catch (e) { /* the next change tries again */ } + } + function banner(level, title, sub, button, onClick) { + const host = $("#set-banner"); + if (!title) { host.replaceChildren(); return; } + host.replaceChildren(h("div", { class: "banner " + ({ ok: "b-ok", bad: "b-bad" }[level] || "b-warn") }, + h("span", { class: "ic", "aria-hidden": "true" }, { ok: "✓", bad: "×" }[level] || "!"), + h("span", {}, title, h("small", {}, sub, button ? [" ", h("button", { type: "button", class: "btn link", onclick: onClick }, button)] : null)))); + } + function restart() { + ask(W.dialog, async () => { + try { + await fetch("config/restart", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ confirm: "restart" }) }); + } catch (e) { /* the add-on stops answering while it restarts */ } + toast(W.toast.restarting.description); + }); + } + async function load(after) { + let m; + try { + const r = await fetch("config/model?lang=en", { cache: "no-store" }); + if (!r.ok) throw new Error("model " + r.status); + m = await r.json(); + if (!m.layout || !m.ui) throw new Error("no layout"); + } catch (e) { + $("#groups").replaceChildren(); + $("#set-search").hidden = true; + banner("bad", W.load_failed.name, W.load_failed.description); + return; + } + M = m; V = clone(m.ui); ORIG = clone(m.ui); FP = m.fingerprint; MSG = []; DEVICE = ""; + $("#set-search").hidden = false; + FILLED = {}; + LIST = null; + for (const g of M.layout.groups) for (const p of g.parts) for (const f of p.fields) { + if (f.fills) FILLED[f.fills] = f; + if (f.control === "inverter_list") LIST = f; + } + if (!OPEN.size && M.layout.groups.length) OPEN.add(M.layout.groups[0].id); + if (after === "saved") banner("ok", W.saved.name, W.saved.description, W.restart, restart); + else if ((m.running_differs || []).length) banner("warn", W.differs.name, W.differs.description, W.restart, restart); + else banner(); + render(); + validate(); + } + function firstBad() { + const r = ROWS.find((x) => x.tiers && x.tiers.has("bad") && x.visible); + if (!r) { if (!$("#set-other").hidden) $("#set-other").scrollIntoView({ block: "center" }); return; } + for (let p = r.el.parentElement; p; p = p.parentElement) if (p.tagName === "DETAILS") p.open = true; + r.el.scrollIntoView({ block: "center" }); + const input = r.el.querySelector("input,select,button"); + if (input) input.focus({ preventScroll: true }); + } + async function save() { + const btn = $("#sb-save"); + btn.disabled = true; btn.textContent = W.savebar.saving; + try { + clearTimeout(vtimer); + await validate(); + if (MSG.some((m) => m.tier === "bad")) { toast(W.toast.blocked.description); firstBad(); return; } + const r = await fetch("config/save", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ model: V, fingerprint: FP }) }); + const b = await r.json().catch(() => ({})); + if (r.ok) { toast(W.toast.saved); await load("saved"); return; } + if (r.status === 409 && b.kind === "stale") { + FP = b.fingerprint || FP; + const names = (b.changed_fields || []).map((k) => { const f = findField(k); return f ? f.label : k; }); + banner("bad", W.stale.name, W.stale.description + (names.length ? " " + names.join(", ") + "." : "")); + return; + } + if (r.status === 422) { MSG = b.messages || []; paint(); toast(W.toast.blocked.description); firstBad(); return; } + toast(W.toast.failed); + } catch (e) { toast(W.toast.failed); } + finally { btn.disabled = false; btn.textContent = W.savebar.save; } + } + $("#sb-save").addEventListener("click", save); + $("#sb-discard").addEventListener("click", () => { + V = clone(ORIG); UNLOCKED.clear(); render(); validate(); toast(W.toast.discarded); + if ($("#set-banner .b-bad")) banner(); + }); + addEventListener("beforeunload", (e) => { if (V && dirtyCount()) { e.preventDefault(); e.returnValue = ""; } }); + document.addEventListener("ux13:tab", (e) => { + active = e.detail === "settings"; + if (active && !M) load(); else savebar(); + }); + // app.js chose the first tab before this file ran. + if ($("#t-set").getAttribute("aria-selected") === "true") { active = true; load(); } +})(); diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 6170326..dbb87a0 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -29,7 +29,12 @@ "choices": { "contract": {"none": "No prices", "fixed": "Fixed price", "daynight": "Day and night", "dynamic": "Dynamic, hourly", "custom": "Other time windows"}, "fallback": {"none": "None", "fixed": "One price", "daynight": "Day and night", "custom": "Other time windows"}, - "region": {"flanders": "Flanders, Fluvius Antwerpen", "own": "I enter my own figure"} + "region": {"flanders": "Flanders, Fluvius Antwerpen", "own": "I enter my own figure"}, + "meter_source": {"off": "One grid power entity", "ha_dsmr": "Import and export entities", "mqtt_p1": "Meter over MQTT", "ha_signed": "One net power entity", "homewizard_local": "HomeWizard meter on the network"}, + "meter_phases": {"1": "1 phase", "3": "3 phases"}, + "shadow_mode": {"auto": "Automatic", "on": "Always on", "off": "Off"}, + "price_provider": {"generic_dayahead": "Day-ahead market price", "custom_formula": "Your own price formula", "manual_csv": "A price file"}, + "log_level": {"trace": "Everything, for support", "debug": "Detailed, to find a problem", "info": "Normal", "warning": "Warnings and errors", "error": "Errors only"} }, "applies": { "restart": {"name": "Applies after a restart"}, @@ -58,7 +63,8 @@ "estimate_tip": "estimate from yesterday", "none_tip": "No price known", "no_prices": {"description": "No prices for today, so the chart shows only the plan."}, - "list": "The plan in words" + "list": "The plan in words", + "average_tip": "hour average" }, "peak": {"name": "Peak limit", "this_month": "This month's peak", "limit": "Limit", "none": "None recorded yet", "unreadable": "Cannot be read now"}, "attention": {"name": "Needs attention", "nothing": "Nothing to look at", "to_look": "to look at", "details": "Details", "alarm": "Alarm", "warning": "Warning", "info": "Info"}, @@ -74,7 +80,83 @@ "toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."}, "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, "batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"}, - "settings": {"name": "Settings", "description": "The new settings screens arrive in a later update, so use the settings page for now.", "open": "Open the settings page"}, + "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"}, "setup": {"name": "Setup", "description": "The setup steps arrive in a later update, so use the settings page for now."} + }, + "choices_later": { + "region": {"wallonia": "Wallonia, no preset yet", "brussels": "Brussels, no preset yet"} + }, + "choice_help": { + "meter_source": { + "off": {"description": "A Home Assistant entity that reads grid power in W, positive when you take from the grid."}, + "ha_dsmr": {"description": "Two Home Assistant entities from the DSMR integration, one for import and one for export."}, + "mqtt_p1": {"description": "The meter's readings arrive over MQTT on a topic you name."}, + "ha_signed": {"description": "One Home Assistant entity that reads net grid power, positive for import."}, + "homewizard_local": {"description": "The add-on reads a HomeWizard meter on your network, and can spot a stuck meter."} + } + }, + "settings": { + "name": "Settings", + "description": "Every setting, grouped by task, and the simple view follows in a later update.", + "classic": "Classic settings", + "search": {"name": "Find a setting", "description": "Find a setting, for example peak or meter."}, + "no_match": {"description": "No setting matches your search."}, + "loading": "Loading the settings", + "load_failed": {"name": "Cannot read the settings", "description": "The add-on could not read its stored settings, so use Classic settings or the Configuration tab."}, + "footer": {"description": "Every change is checked by the add-on's own start checks before it is saved."}, + "to_fix": "to fix", + "to_check": "to check", + "changed": "changed", + "on": "On", + "off": "Off", + "not_set": "Not set", + "locked": "Locked", + "change": "Change", + "support": {"description": "These were measured on real hardware, so change them only when support asks."}, + "picker": { + "choose": "Choose an entity", + "search": {"description": "Search by name or entity id."}, + "all": "Show every entity", + "use": "Use this entity id", + "clear": "Clear", + "missing": "Not in Home Assistant", + "none": {"description": "Nothing matches, so check the entity in Developer Tools."} + }, + "add_inverter": "Add an inverter", + "inverter": "Inverter", + "remove": "Remove", + "add_row": "Add a row", + "add_solar": "Add a solar inverter", + "reversed": "Reads negative", + "phase": "Phase", + "raw_roster": {"description": "This inverter list can only be changed in the Configuration tab."}, + "region_year": "{year} figures", + "hour": "{hour}:00 UTC", + "preset": {"description": "Filled in by the region above, so choose your own figure to change it."}, + "cycle": {"name": "Run a cycle by hand", "description": "The same actions as on Home, each asking first."}, + "savebar": {"label": "Unsaved changes", "one": "change not saved", "many": "changes not saved", "discard": "Discard", "save": "Save", "saving": "Saving"}, + "saved": {"name": "Saved, not running yet", "description": "The add-on runs the settings it started with until you restart it."}, + "differs": {"name": "Stored settings are not running", "description": "Some stored settings differ from what runs now, so restart the add-on to apply them."}, + "stale": {"name": "Changed somewhere else", "description": "These settings changed elsewhere while you edited, so save again to keep yours or discard to load theirs."}, + "other": "Other messages", + "restart": "Restart now", + "dialog": {"name": "Restart the add-on?", "description": "Every inverter is set to 0 W while the add-on restarts, and then the new settings apply.", "yes": "Restart now"}, + "toast": { + "saved": "Saved. Restart to apply.", + "discarded": "Changes discarded.", + "failed": "That did not work. Try again.", + "blocked": {"description": "Fix the settings marked in red, then save again."}, + "restarting": {"description": "Restart requested, so this page stops answering for a moment."} + }, + "tier": {"bad": "Must fix", "warn": "Check this", "info": "Note"}, + "derive": { + "raw_roster": {"description": "This inverter list can only be changed in the Configuration tab."}, + "no_inverter": {"description": "Add at least one inverter."}, + "flat_named": {"description": "Add a second inverter before naming this one."}, + "no_source": {"description": "Choose where the dynamic prices come from."}, + "custom_profile": {"description": "Other time windows can only be changed in the Configuration tab."}, + "no_price": {"description": "Enter a price per kWh."}, + "unknown": {"description": "The page cannot store this choice, so reload the page."} + } } } diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index 23fec4d..b0288e4 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -43,6 +43,8 @@ class Field: applies: str = RESTART simple: bool = False # also on Settings, Simple wizard: int = 0 # setup wizard step 1-6, 0 = not in the wizard + mirror: str = "" # a choice also copied to this field, if offered + fills: str = "" # a preset choice fills this field (uimodel) @property def text(self) -> str: @@ -73,17 +75,20 @@ _MAINT = (("maintenance_enabled", "==", True),) _ONE = (("inverter_count", "==", 1),) _SEVERAL = (("inverter_count", ">", 1),) _PHASES = (("meter_phases", ">", 1),) +# One inverter stored flat has no name or capacity (uimodel._roster_encode). +_LISTED = (("inverter_shape", "!=", "flat"),) # The per-inverter card. Its keys are `inverters.` in config.yaml. ROSTER_FIELDS = ( - Field("inverters.name", TEXT, wizard=2), + Field("inverters.name", TEXT, show=_LISTED, wizard=2), Field("inverters.setpoint_entity", ENTITY, kind="number", wizard=2), Field("inverters.max_w", SLIDER, "W", step=100, wizard=2), Field("inverters.bms_soc_floor", SLIDER, "%", wizard=2), Field("inverters.soc_entity", ENTITY, kind="pct", wizard=2), Field("inverters.batt_entity", ENTITY, kind="power_w", wizard=2), Field("inverters.batt_invert", TOGGLE, wizard=2), - Field("inverters.capacity_kwh", NUMBER, "kWh", step=0.1, wizard=2), + Field("inverters.capacity_kwh", NUMBER, "kWh", step=0.1, show=_LISTED, + wizard=2), ) GROUPS = ( @@ -123,7 +128,9 @@ GROUPS = ( )), Group("tariff", ( Part("", ( - Field("ui.contract", SEGMENTED, wizard=4), + # A contract without a feed is also the price used when a feed + # is down, so the fallback follows it (uimodel._tariff_encode). + Field("ui.contract", SEGMENTED, wizard=4, mirror="ui.fallback"), Field("price_provider", SELECT, show=_DYNAMIC, wizard=4), Field("price_formula", TEXT, show=_DYNAMIC + (("price_provider", "==", "custom_formula"),), @@ -131,7 +138,8 @@ GROUPS = ( Field("price_csv_path", TEXT, show=_DYNAMIC + (("price_provider", "==", "manual_csv"),), wizard=4), - Field("ui.region", SELECT, wizard=4), + Field("ui.region", SELECT, wizard=4, + fills="price_taxes_eur_kwh"), Field("price_taxes_eur_kwh", NUMBER, "€/kWh", step=0.00001, wizard=4), Field("price_markup_eur_kwh", NUMBER, "€/kWh", step=0.001, diff --git a/goodwe_controller/app/uimodel.py b/goodwe_controller/app/uimodel.py index fddf36e..08523ed 100644 --- a/goodwe_controller/app/uimodel.py +++ b/goodwe_controller/app/uimodel.py @@ -21,11 +21,23 @@ from .price import FLEMISH_TAXES_COMPONENTS_EUR_KWH from .static_tariff import ProfileInvalid, parse_static_profile __all__ = ["options_to_ui", "ui_to_options", "REGION_PRESETS", - "arbitrage_from_batteries", "DeriveError"] + "arbitrage_from_batteries", "DeriveError", "COUNT", "GROWN"] class DeriveError(ValueError): - """The page model asks for something no options blob can say.""" + """The page model asks for something no options blob can say. `code` names + the sentence the page shows (app/ui_text `derive.`), and `field` the + page field it is shown beside.""" + + def __init__(self, text, code="", field=""): + super().__init__(text) + self.code, self.field = code, field + + +# The page model's inverter count, which show conditions read, and what adding +# a card sets: a second inverter turns the one flat inverter into a list. +COUNT = "inverter_count" +GROWN = {"inverter_shape": "list"} # --------------------------------------------------------------------------- # @@ -80,13 +92,16 @@ def _roster_encode(m, keep): out = {} shape, cards = m.get("inverter_shape"), m.get("inverters") if shape == "raw": - raise DeriveError("the inverter list is edited in the Configuration tab") + raise DeriveError("the inverter list is edited in the Configuration tab", + "raw_roster", "inverters") if not cards: - raise DeriveError("at least one inverter is needed") + raise DeriveError("at least one inverter is needed", "no_inverter", + "inverters") if shape == "flat" and len(cards) == 1: card = cards[0] if not _blank(card.get("name")) or not _blank(card.get("capacity_kwh")): - raise DeriveError("one inverter stored flat has no name or capacity") + raise DeriveError("one inverter stored flat has no name or " + "capacity", "flat_named", "inverters") for k in _ROSTER_FLAT: if card.get(k) is not None or k in keep: out[k] = card.get(k) @@ -96,8 +111,9 @@ def _roster_encode(m, keep): for c in cards] # The flat keys beside a list are not read: they stay as stored. out.update({k: copy.deepcopy(keep[k]) for k in _ROSTER_FLAT if k in keep}) - if shape == "flat": - # CFG-04 rule 9e: a flat power request entity beside a list is refused. + if shape == "flat" or _roster_decode(keep)["inverter_shape"] == "flat": + # CFG-04 rule 9e: a flat power request entity beside a list is refused, + # so a list that replaces the flat inverter clears it. out["setpoint_entity"] = "" return out @@ -210,7 +226,8 @@ def _tariff_encode(m, keep): contract = m.get("ui.contract") if contract == "dynamic": if _blank(m.get("price_provider")) or m.get("price_provider") == "off": - raise DeriveError("a dynamic contract needs a price source") + raise DeriveError("a dynamic contract needs a price source", + "no_source", "price_provider") out["price_provider"] = m["price_provider"] kind = m.get("ui.fallback") else: @@ -226,17 +243,19 @@ def _tariff_encode(m, keep): elif kind == "custom": if "static_profile" not in keep: raise DeriveError("odd tariff windows are edited in the " - "Configuration tab") + "Configuration tab", "custom_profile", + "ui.contract") out["static_profile"] = keep["static_profile"] else: - raise DeriveError(f"unknown contract {kind!r}") + raise DeriveError(f"unknown contract {kind!r}", "unknown", + "ui.contract") return out def _price_of(m, name): value = _num(m.get(name)) if value is None: - raise DeriveError(f"{name} needs a price") + raise DeriveError(f"{name} needs a price", "no_price", name) return value @@ -259,7 +278,7 @@ def _region_encode(m, keep): out["price_taxes_profile"] = keep["price_taxes_profile"] return out if region not in REGION_PRESETS: - raise DeriveError(f"unknown region {region!r}") + raise DeriveError(f"unknown region {region!r}", "unknown", "ui.region") p = REGION_PRESETS[region] out = {"price_taxes_eur_kwh": p["taxes_eur_kwh"]} if p["taxes_profile"] or "price_taxes_profile" in keep: diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py new file mode 100644 index 0000000..9a84e4b --- /dev/null +++ b/goodwe_controller/app/uipage.py @@ -0,0 +1,275 @@ +"""UX-13 P2: the settings view's server half. It names no option key. + +It turns app/uilayout.py's table into the JSON the page draws from (labels +from the Supervisor's translations, ranges and choices from its schema, page +words from app/ui_text), turns a posted page model into options through +app/uimodel.py, and says beside which page field each validator sentence +goes. The rules stay in validate.py and the sentences are passed on as they +are (DECISIONS/UX-13-one-layout-table.md). +""" + +import copy +import io +import json +import os +import re + +from . import uilayout as L +from . import uimodel as U +from .configui import help_of, label_of, problems_by_field, split_group + +UI_TEXT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text", + "en.json") +# A choice the page cannot make, only keep: odd tariff windows (P5 editor). +ONLY_IF_HELD = ("custom",) +_TIERS = ("bad", "warn", "info") + + +def ui_text() -> dict: + with io.open(UI_TEXT, encoding="utf-8") as f: + return json.load(f) + + +def _roster(): + """The inverter list field's key, read off the table.""" + return next(f.key for _g, _p, f in L.fields() + if f.control == L.INVERTER_LIST) + + +def _node(schema_ui, key): + """The Supervisor's schema entry for `key` (`list.sub` too), or {}.""" + nodes, path = schema_ui or [], key.split(".") + for step in path[:-1]: + parent = next((n for n in nodes if n.get("name") == step), None) + nodes = (parent or {}).get("schema") or [] + return next((n for n in nodes if n.get("name") == path[-1]), None) or {} + + +def _words(translations, lang, key, T): + """(label, help) for a field: ui_text for `ui.` fields, else the + translation without its `Group · ` prefix, and the raw key last.""" + if key.startswith("ui."): + entry = T["fields"].get(key[3:], {}) + return entry.get("name", key), entry.get("description", "") + path = tuple(key.split(".")[:-1]) + name = key.split(".")[-1] + label, _lang = label_of(translations, lang, name, path) + text, _lang = help_of(translations, lang, name, path) + return split_group(label)[1], text + + +def _choices(fld, node, T, value_type): + """[[value, label, only_if_held], ...] for a choice control, or None.""" + if fld.control not in (L.SEGMENTED, L.SELECT, L.CHOICE): + return None + name = fld.key[3:] if fld.key.startswith("ui.") else fld.key + words = T["choices"].get(name) or {} + if fld.key.startswith("ui."): + values = list(words) + elif node.get("options"): + values = [v for v in node["options"] if not words or v in words] + elif value_type == "integer" and node.get("lengthMax") is not None: + values = list(range(int(node["lengthMin"]), int(node["lengthMax"]) + 1)) + if words: + values = [v for v in values if str(v) in words] + else: + return [] + out = [] + for v in values: + label = words.get(str(v)) + if label is None: + label = (T["settings"]["hour"].replace("{hour}", f"{v:02d}") + if isinstance(v, int) else str(v)) + preset = U.REGION_PRESETS.get(v) if fld.fills else None + if preset: + label = f"{label}, " + T["settings"]["region_year"].replace( + "{year}", str(preset["year"])) + out.append([v, label, v in ONLY_IF_HELD]) + return out + + +def _field(fld, schema_ui, translations, lang, T): + node = _node(schema_ui, fld.key) + label, text = _words(translations, lang, fld.key, T) + value_type = ("float" if fld.control == L.NUMBER and fld.key.startswith("ui.") + else node.get("type") or "") + out = {"key": fld.key, "control": fld.control, "label": label, + "help": text, "unit": fld.unit, "scale": fld.scale, + "step": fld.step, "kind": fld.kind, + "show": [list(c) for c in fld.show], "applies": fld.applies, + "type": value_type, "optional": not node.get("required", False), + "writes": sorted(k for k, how in L.DERIVED.items() + if how == fld.key)} + if node.get("lengthMin") is not None: + out["min"] = node["lengthMin"] + if node.get("lengthMax") is not None: + out["max"] = node["lengthMax"] + choices = _choices(fld, node, T, value_type) + if choices is not None: + out["choices"] = choices + name = fld.key[3:] if fld.key.startswith("ui.") else fld.key + later = T.get("choices_later", {}).get(name) + if later: + out["later"] = [[v, words] for v, words in later.items()] + hints = T.get("choice_help", {}).get(name) + if hints: + out["hints"] = {v: e.get("description", "") + for v, e in hints.items()} + if fld.mirror: + out["mirror"] = fld.mirror + if fld.fills: + out["fills"] = fld.fills + out["presets"] = {rid: {"year": p["year"], "value": p["taxes_eur_kwh"]} + for rid, p in U.REGION_PRESETS.items()} + roster = _roster() + if fld.key.startswith(roster + "."): + sub = fld.key[len(roster) + 1:] + if L.DERIVED.get(sub) == roster: + out["flat"] = sub # how the one flat inverter stores it + if fld.control == L.INVERTER_LIST: + out["fields"] = [_field(sub, schema_ui, translations, lang, T) + for sub in L.ROSTER_FIELDS] + out["count"] = U.COUNT + out["grow"] = dict(U.GROWN) + out["shape"] = next(iter(U.GROWN)) + return out + + +def layout(schema_ui, translations, lang="en") -> dict: + """Every group, part and field of the Installer view, as the page draws + it. Built from the table only: a field the table places is on the page.""" + T = ui_text() + groups = [] + for g in L.GROUPS: + parts = [] + for p in g.parts: + words = T["parts"].get(f"{g.id}.{p.id}", {}) if p.id else {} + parts.append({"id": p.id, "name": words.get("name", ""), + "description": words.get("description", ""), + "collapsed": p.collapsed, + "fields": [_field(f, schema_ui, translations, lang, T) + for f in p.fields]}) + words = T["groups"].get(g.id, {}) + applies = sorted({f.applies for p in g.parts for f in p.fields}) + groups.append({"id": g.id, "name": words.get("name", g.id), + "description": words.get("description", ""), + "support_only": g.support_only, + "applies": [T["applies"][a]["name"] for a in applies], + "parts": parts}) + return {"groups": groups} + + +# --------------------------------------------------------------------------- # +# The page model -> options, for the validator and the save +# --------------------------------------------------------------------------- # +def _same(a, b) -> bool: + """Equal as the Supervisor stores it: 3 and 3.0 alike, True and 1 not.""" + if isinstance(a, bool) or isinstance(b, bool): + return type(a) is type(b) and a == b + if isinstance(a, (int, float)) and isinstance(b, (int, float)): + return a == b + if isinstance(a, list) and isinstance(b, list): + return len(a) == len(b) and all(_same(x, y) for x, y in zip(a, b)) + if isinstance(a, dict) and isinstance(b, dict): + return a.keys() == b.keys() and all(_same(a[k], b[k]) for k in a) + return type(a) is type(b) and a == b + + +def to_options(model: dict, stored: dict | None = None) -> dict: + """The options blob for a posted page model. A value equal to the stored + one is written as stored, in the stored key order, so a save that changed + nothing writes an identical blob (the browser reads 3.0 as 3).""" + out = U.ui_to_options(model) + stored = stored or {} + for k, v in out.items(): + if k in stored and _same(v, stored[k]): + out[k] = copy.deepcopy(stored[k]) + return ({k: out[k] for k in stored if k in out} + | {k: v for k, v in out.items() if k not in stored}) + + +def derive_message(err: U.DeriveError) -> dict: + words = ui_text()["settings"]["derive"] + text = words.get(err.code, words["unknown"])["description"] + return {"field": err.field or None, "card": None, "tier": "bad", + "text": text} + + +# --------------------------------------------------------------------------- # +# Where a sentence goes on the page +# --------------------------------------------------------------------------- # +# `inverters.max_w`, or `inverters[1].setpoint_entity` for one card. +_SUB = re.compile(r"(? list: + """[(page field, card)] for a sentence that names option `key`. `card` is + the inverter card's index, or None.""" + roster = _roster() + cards = model.get(roster) if isinstance(model.get(roster), list) else [] + names = [c.get("name") for c in cards if isinstance(c, dict)] + # messages.setting(): “Inverter rating” for inverter-b (inverters.max_w), + # or a roster rule's own `inverters[1] (inverter-b)`. + card = next((i for i, n in enumerate(names) + if n and f"for {n} ({roster}." in text), None) + index = re.search(re.escape(roster) + r"\[(\d+)\]", text) + if card is None and index and int(index.group(1)) < len(cards): + card = int(index.group(1)) + if key == roster: + subs = [(f"{roster}.{s}", int(i) if i and int(i) < len(cards) else card) + for r, i, s in _SUB.findall(text) if r == roster] + subs = [x for x in dict.fromkeys(subs) if L.field(x[0])] + return subs or [(roster, card)] + if key in L.DERIVED: + how = L.DERIVED[key] + if how == roster: + return [(f"{roster}.{key}", 0 if card is None else card)] + fld = L.field(how) + if fld is not None and not L.visible(fld, model) and _mirror_of(how): + return [(_mirror_of(how), None)] + return [(how, None)] + if L.field(key) is not None: + return [(key, None)] + return [(None, None)] + + +def anchors(problems, notes, model, keys) -> list: + """[{field, card, tier, text}] for the refusals and notes. `field` is + None for a sentence that names no setting on the page.""" + out, seen = [], set() + + def add(field, card, tier, text): + if (field, card, text) not in seen: + seen.add((field, card, text)) + out.append({"field": field, "card": card, "tier": tier, + "text": text}) + + by_key, unanchored = problems_by_field(problems, keys) + for key, texts in by_key.items(): + for text in texts: + for field, card in targets(key, text, model): + add(field, card, "bad", text) + for text in unanchored: + add(None, None, "bad", text) + for note in notes: + tier = note.tier if note.tier in _TIERS else "info" + for key in note.keys or (None,): + for field, card in (targets(key, note.text, model) if key + else [(None, None)]): + add(field, card, tier, note.text) + # A sentence placed on one inverter's field is not also put on the list. + roster = _roster() + placed = {m["text"] for m in out + if (m["field"] or "").startswith(roster + ".")} + return [m for m in out if not (m["field"] == roster + and m["text"] in placed)] + + +def fields_of(keys, model) -> list: + """The page fields that show these option keys (a stale save's list).""" + return list(dict.fromkeys(f for k in keys for f, _c in targets(k, "", model) + if f)) diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index 648b7ca..e599ce0 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -37,12 +37,13 @@ import os from aiohttp import web -from . import messages, selfconfig +from . import messages, selfconfig, uipage from .haentities import EntityCache from .homeview import region_of from .validate import config_notes from .config_page import CONFIG_PAGE from .configui import changed_keys, field_model, problems_by_field +from .uimodel import DeriveError, options_to_ui _LOG = logging.getLogger("goodwe.web") @@ -65,13 +66,16 @@ def page() -> str: """The assembled index page. ` web.Application: async def config_index(_request): return web.Response(text=CONFIG_PAGE, content_type="text/html") - async def _proposed(request): + async def _proposed(request, stored=None): + """(body, options, model). UX-13's settings view posts its page + `model`, which app/uimodel.py turns into the options blob here, so the + validator and the Supervisor only ever see a real blob. The classic + page posts `options`. Raises DeriveError for a model no blob can say.""" try: body = await request.json() except ValueError: raise web.HTTPBadRequest(text="expected JSON") + model = body.get("model") + if isinstance(model, dict): + return body, uipage.to_options(model, stored), model options = body.get("options") if not isinstance(options, dict): raise web.HTTPBadRequest(text="expected an options object") - return body, options + return body, options, None async def config_model(request): """Everything the page needs to draw itself, from ONE Supervisor call. @@ -161,6 +172,10 @@ def build_app(controller, selfcfg=None) -> web.Application: # UX-13 P1: the levies preset and its year, for the P2 Settings # screens, which show the year beside the region choice. "region": region_of(options), + # UX-13 P2: the Installer view draws from these two. + "layout": uipage.layout(info.get("schema") or [], + info.get("translations") or {}, lang), + "ui": options_to_ui(options), }) return web.json_response(model) @@ -177,7 +192,12 @@ def build_app(controller, selfcfg=None) -> web.Application: product this card is delivering; anything this layer did to them would be a second opinion about a rule it does not own. """ - _body, options = await _proposed(request) + try: + _body, options, model = await _proposed(request) + except DeriveError as err: + return web.json_response({"problems": [], "by_key": {}, + "unanchored": [], "notes": [], + "messages": [uipage.derive_message(err)]}) notes = [] problems, unread = await selfconfig.problems_and_ranges( options, controller.hass, notes=notes) @@ -190,6 +210,9 @@ def build_app(controller, selfcfg=None) -> web.Application: "notes": [n._asdict() for n in notes]} if unread: payload["device_note"] = DEVICE_NOTE % ", ".join(sorted(set(unread))) + if model is not None: + payload["messages"] = uipage.anchors(problems, notes, model, + _keys_of(options)) return web.json_response(payload) def _keys_of(options): @@ -202,7 +225,27 @@ def build_app(controller, selfcfg=None) -> web.Application: async def config_save(request): """Validate, compare-and-swap, write. Or refuse and write NOTHING.""" - body, options = await _proposed(request) + # The page model carries no stored values of the keys it shows, so the + # blob is settled against what is stored: an unchanged value is written + # exactly as stored (uipage.to_options). + try: + posted = await request.json() + except ValueError: + raise web.HTTPBadRequest(text="expected JSON") + stored_now = None + if isinstance(posted, dict) and isinstance(posted.get("model"), dict): + try: + stored_now = (await selfcfg.info()).get("options") or {} + except selfconfig.SupervisorUnavailable as err: + _LOG.error("saving options failed: %s", err) + return web.json_response({"error": str(err)}, status=502) + try: + body, options, model = await _proposed(request, stored_now) + except DeriveError as err: + return web.json_response( + {"kind": "invalid", "problems": [], "by_key": {}, + "unanchored": [], "messages": [uipage.derive_message(err)]}, + status=422) expect = str(body.get("fingerprint") or "") try: result = await selfconfig.save(selfcfg, options, expect, @@ -212,6 +255,9 @@ def build_app(controller, selfcfg=None) -> web.Application: stored = refused.stored or {} return web.json_response( {"kind": "stale", "changed": refused.changed, + "changed_fields": (uipage.fields_of(refused.changed, + model) + if model is not None else []), "stored": stored, # The page needs the CURRENT token to be able to save # again after the operator has read the difference. That @@ -221,9 +267,12 @@ def build_app(controller, selfcfg=None) -> web.Application: status=409) by_key, unanchored = problems_by_field(refused.problems, _keys_of(options)) - return web.json_response( - {"kind": "invalid", "problems": refused.problems, - "by_key": by_key, "unanchored": unanchored}, status=422) + payload = {"kind": "invalid", "problems": refused.problems, + "by_key": by_key, "unanchored": unanchored} + if model is not None: + payload["messages"] = uipage.anchors(refused.problems, [], + model, _keys_of(options)) + return web.json_response(payload, status=422) except selfconfig.SupervisorUnavailable as err: _LOG.error("saving options failed: %s", err) return web.json_response({"error": str(err)}, status=502) diff --git a/goodwe_controller/test_haentities.py b/goodwe_controller/test_haentities.py index 30ffb81..6db27e8 100644 --- a/goodwe_controller/test_haentities.py +++ b/goodwe_controller/test_haentities.py @@ -10,6 +10,7 @@ Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). import asyncio import json +import logging import sys import time @@ -96,9 +97,29 @@ for name, handler in (("502 while HA restarts", bad_gateway), ("a body that is not JSON", garbage), ("JSON that is not a list", not_a_list)): check(f"{name} -> None", asyncio.run(read_with(handler)) is None) +class _Lines(logging.Handler): + def __init__(self): + super().__init__() + self.lines = [] + + def emit(self, record): + if record.levelno >= logging.WARNING: + self.lines.append(record.getMessage()) + + +_lines = _Lines() +logging.getLogger().addHandler(_lines) check("an answer slower than the timeout -> None, at the timeout", asyncio.run(read_with(slow, timeout_s=0.3)) is None and read_with.took < 1.0) +# UX-13 P1 test finding (c): a timeout's own text is empty, which left +# "Reading the entity list failed: " with no reason. +check("...and its WARNING line gives the reason, not an empty one " + f"({_lines.lines})", any( + x == "Reading the entity list failed: no answer within 0.3 seconds." + for x in _lines.lines) + and not any(x.rstrip().endswith("failed:") for x in _lines.lines)) +logging.getLogger().removeHandler(_lines) check("no server at all -> None", asyncio.run(closed_port()) is None) check("the timeout for the list is the same 10 s as every other read", "STATES_TIMEOUT_S = 10 " in open(H.__file__, encoding="utf-8").read()) diff --git a/goodwe_controller/test_home.py b/goodwe_controller/test_home.py index 40e21c2..1adf98f 100644 --- a/goodwe_controller/test_home.py +++ b/goodwe_controller/test_home.py @@ -321,11 +321,11 @@ check("the price bars are today's 24 hours, from the real series, with the " and s_arb["plan"]["prices"][19]["kind"] == "dear" and s_arb["plan"]["prices"][0]["kind"] == "mid" and s_arb["plan"]["prices"][13]["label"] == "13:00") -check("the price line names the price now, today's cheapest and dearest, and " +check("the price line names the price now, today's lowest and highest, and " "that tomorrow's prices are in", s_arb["plan"]["price_line"] == ("Price now €0.16 per kWh, all in. " - "Today: cheapest €0.14 at 13:00, " - "dearest €0.36 at 19:00.") + "Today: lowest €0.14 at 13:00, " + "highest €0.36 at 19:00.") and s_arb["plan"]["tomorrow_line"] == "Tomorrow's prices are in.") c_late = make(ARB) @@ -454,6 +454,59 @@ check("...and every red, amber and settling row reaches Needs attention with " + [r["text"] for r in s_al["checks"] if not r["ok"] and r["warn"]] + [r["text"] for r in s_al["checks"] if r["ok"] and r["warn"]]) +# UX-13 P1 test finding (a): the page said "Held at 0 W" about 15 s before +# the inverter's power request reached 0 W. Until the last accepted request +# is 0 W it says "Going to 0 W". +c_al.inverters[0].last_write = 20.0 +s_go = homeview.build(c_al, level="bad", checks=s_al["checks"], now=NOW) +c_al.inverters[0].last_write = 0.0 +s_at = homeview.build(c_al, level="bad", checks=s_al["checks"], now=NOW) +check("an alarm while the last power request is still 20 W says 'Going to " + "0 W', and 'Held at 0 W' once 0 W was accepted", + s_go["plan"]["verdict"] == "Going to 0 W" + and s_go["batteries"][0]["now"] == "Going to 0 W until the alarm clears." + and s_go["plan"]["head"].startswith("Every inverter goes to 0 W") + and s_at["plan"]["verdict"] == "Held at 0 W" + and s_at["batteries"][0]["now"] == "Held at 0 W until the alarm clears.") +c_sp = make(TWO, auto=False) +c_sp.inverters[1].last_write = -1500.0 +s_sp = status(c_sp) +check("...and a stop does the same, per battery", + [b["now"] for b in s_sp["batteries"]] + == ["Held at 0 W while control is stopped.", + "Going to 0 W while control is stopped."]) + +# Finding (b): a quarter-hourly feed. The block's price and the price line +# name the same 15-minute point, and nothing says "the list". +_q = [] +for _k, _p in enumerate(MOCK): + for _m in range(4): + _q.append(PricePoint(DAY0 + timedelta(hours=_k, minutes=15 * _m), + round(_p + (0.0 if _m != 3 else -0.01), 4), False)) +_q += [PricePoint(p.start + timedelta(days=1), p.eur_per_kwh, False) + for p in list(_q)] +c_q = make(ARB) +c_q.tariff_plan = TariffPlan(PriceRead.series(tuple(_q), PriceProduct.DAY_AHEAD, + "generic_dayahead", NOW), None, + "provider") +c_q.tariff_at = NOW +c_q.peak_guard = quiet_guard() +s_q = status(c_q) +_grid = [r for r in s_q["plan"]["runs"] if r["kind"] == "grid"] +_lo = min(_q[:96], key=lambda p: p.eur_per_kwh) +check("quarter-hour prices: the charge block, its price and the price line's " + "lowest are the same 15-minute period", + _grid and _grid[0]["from"] == homeview.hhmm(_lo.start) + and _grid[0]["why"] == f"Lowest published price, €{_lo.eur_per_kwh:.2f} " + "per kWh." + and f"Today: lowest €{_lo.eur_per_kwh:.2f} at " + f"{homeview.hhmm(_lo.start)}," in s_q["plan"]["price_line"] + and "the list" not in json.dumps(s_q["plan"])) +check("...and the hour bar says it is an hour average", + s_q["plan"]["prices"][13]["points"] == 4 + and '"plan.average_tip"' in io.open(os.path.join( + HERE, "app", "static", "app.js"), encoding="utf-8").read()) + # --------------------------------------------------------------------------- # print("\n4. a fault in the Home view never costs the page its rows") # --------------------------------------------------------------------------- # diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 33d3e72..f75653d 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -883,6 +883,8 @@ DATA = { "hass.py:msg", "hass.py:*args", "hass.py:entity_id", "hass.py:err", "hass.py:obj", "hass.py:raw", "hass.py:domain", "hass.py:service", "hass.py:resp.status", "hass.py:said", "hass.py:entity", "hass.py:what", + # UX-13 P2: the entity list's wait, and an error's text or else its name + "hass.py:STATES_TIMEOUT_S", "hass.py:str(err) or type(err).__name__", # main.py "main.py:'cancelled' if task.cancelled() else repr(exc) if exc else 'returned'", "main.py:EXIT_CONTROL_DIED", "main.py:first.name", "main.py:OPTIONS_PATH", diff --git a/goodwe_controller/test_settings.py b/goodwe_controller/test_settings.py new file mode 100644 index 0000000..c312adf --- /dev/null +++ b/goodwe_controller/test_settings.py @@ -0,0 +1,437 @@ +"""UX-13 P2: the Installer settings view. `python3 test_settings.py` + +The view is drawn from app/uilayout.py through app/uipage.py and saves the +page model through app/uimodel.py and the shipped validator. Part 1 checks +that every group and every mapped field reaches the page with its words, +range and choices. Part 2 checks the page script names no option key. Parts +3-5 drive the real routes over HTTP against a fake Supervisor: the save round +trip, where a refusal lands, and a stale save. Part 6 holds the view's words +to STYLE. The headless-browser click-through is in the PR, not in CI (the CI +image has no browser). +Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). +""" + +import asyncio +import copy +import glob +import io +import json +import logging +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) # the validator's own log lines + +from aiohttp import ClientSession, web as aioweb # noqa: E402 + +import translations_lint as TL # noqa: E402 +import ux13_demo as D # noqa: E402 +from app import selfconfig, uilayout as L, uimodel as U, uipage, web # noqa: E402 +from app.validate import validate_startup_config # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +SCHEMA = D.schema_ui(D.CONFIG) +TRANSLATIONS = {"en": TL.parse_translation_file( + os.path.join(HERE, "translations", "en.yaml"))} +DEFAULTS = D.defaults(D.CONFIG) +SITE = dict(DEFAULTS, setpoint_entity="number.goodwe_setpoint", + soc_entity="sensor.soc", batt_entity="sensor.batt") +TWO = dict(SITE, setpoint_entity="", inverters=[ + {"name": "inverter-a", "setpoint_entity": "number.a", "max_w": 2500, + "bms_soc_floor": 10}, + {"name": "inverter-b", "setpoint_entity": "number.b", "max_w": 2500, + "bms_soc_floor": 10}]) +UI_TEXT = uipage.ui_text() +W = UI_TEXT["settings"] + + +def browser(value): + """What JSON.parse then JSON.stringify does to a value: 3.0 becomes 3.""" + if isinstance(value, float) and value.is_integer(): + return int(value) + if isinstance(value, list): + return [browser(v) for v in value] + if isinstance(value, dict): + return {k: browser(v) for k, v in value.items()} + return value + + +# --------------------------------------------------------------------------- # +print("1. every group and every mapped field reaches the page") +# --------------------------------------------------------------------------- # +LAYOUT = uipage.layout(SCHEMA, TRANSLATIONS) +_flat = [] +for _g in LAYOUT["groups"]: + for _p in _g["parts"]: + for _f in _p["fields"]: + _flat.append((_g["id"], _f)) + _flat += [(_g["id"], _s) for _s in _f.get("fields", [])] +_keys = [f["key"] for _g, f in _flat] +check("the six groups, in the design's order", + [g["id"] for g in LAYOUT["groups"]] + == ["meter", "inverters", "tariff", "safety", "maintenance", "tuning"] + and [g["name"] for g in LAYOUT["groups"]] + == ["Meter", "Inverters and batteries", "Tariff and prices", + "Safety limits", "Maintenance", "Control tuning"]) +check(f"every field of the table is on the page once ({len(_keys)} fields)", + sorted(_keys) == sorted(f.key for _g, _p, f in L.fields()) + and len(_keys) == len(set(_keys))) +_counts = {g["id"]: sum(1 for gid, _f in _flat if gid == g["id"]) + for g in LAYOUT["groups"]} +print(f" fields per group: {_counts}") +check("every field has a label, and every option field's label is its " + "translation without the group prefix", + all(f["label"] and " · " not in f["label"] for _g, f in _flat) + and next(f for _g, f in _flat if f["key"] == "meter_source")["label"] + == "Where the meter reading comes from") +_ranged = [(f["key"], f.get("min"), f.get("max")) for _g, f in _flat + if f["control"] in (L.SLIDER, L.LOCKED)] +check(f"every slider and locked value has its range from the schema " + f"({len(_ranged)})", all(lo is not None and hi is not None + for _k, lo, hi in _ranged) + and ("peak_cap_w", 500.0, 15000.0) in _ranged) +check("the peak limit is a kW slider over a value stored in W", + next(f for _g, f in _flat if f["key"] == "peak_cap_w")["scale"] == 1000) +_choice = [f for _g, f in _flat + if f["control"] in (L.SEGMENTED, L.SELECT, L.CHOICE)] +check("every choice control has choices with words", + all(f["choices"] and all(c[1] for c in f["choices"]) for f in _choice)) +_ms = next(f for _g, f in _flat if f["key"] == "meter_source") +check("the meter source is radio cards with a line of help on each", + _ms["control"] == L.CHOICE and set(_ms["hints"]) == {c[0] for c in + _ms["choices"]}) +_reg = next(f for _g, f in _flat if f["key"] == "ui.region") +check("the region shows its preset year beside the choice (P0 review)", + ["flanders", "Flanders, Fluvius Antwerpen, 2026 figures", False] + in _reg["choices"] and _reg["presets"]["flanders"]["year"] == 2026) +check("...and says plainly that Wallonia and Brussels have no preset yet " + "(TARIFF-22)", _reg["later"] == [["wallonia", "Wallonia, no preset yet"], + ["brussels", "Brussels, no preset yet"]] + and "Wallonia or Brussels" in _reg["help"]) +_locked = sorted(f["key"] for _g, f in _flat if f["control"] == L.LOCKED) +check(f"measured and derived values are locked behind 'Change' " + f"({len(_locked)}): every control tuning value, every safety stop and " + "the peak reserve", + {f.key for p in L.GROUPS[-1].parts for f in p.fields} <= set(_locked) + and "sign_disagree_w" in _locked and "peak_soc_floor" in _locked + and LAYOUT["groups"][-1]["support_only"]) +check("each group says when its settings apply", + all(g["applies"] == [UI_TEXT["applies"]["restart"]["name"]] + for g in LAYOUT["groups"])) +_inv = next(f for _g, f in _flat if f["key"] == "inverters") +check("the inverter cards carry their count, and adding one makes a list", + _inv["count"] == U.COUNT and _inv["grow"] == U.GROWN + and [s["key"] for s in _inv["fields"]] + == [f.key for f in L.ROSTER_FIELDS]) +check("a page-only field names the option keys it writes, for the grey key " + "line", _reg["writes"] == ["price_taxes_profile"] + and next(f for _g, f in _flat if f["key"] == "ui.solar")["writes"] + == ["pv_entities", "pv_entity", "pv_invert_entities"]) +check("without a Supervisor schema the page still draws, with no ranges", + len(uipage.layout([], {})["groups"]) == 6) + +# --------------------------------------------------------------------------- # +print("\n2. the page script names no option key") +# --------------------------------------------------------------------------- # +JS = io.open(os.path.join(HERE, "app", "static", "settings.js"), + encoding="utf-8").read() +ORDER, _nested = TL.config_surface(D.CONFIG) +_leak = sorted(k for k in ORDER if re.search( + r"[^A-Za-z0-9_]" + re.escape(k) + r"[^A-Za-z0-9_]", JS)) +check(f"settings.js names no option key ({_leak})", not _leak) +check("data is set as text, never as HTML", + "innerHTML" not in JS and "insertAdjacentHTML" not in JS) +_fetch = sorted(set(re.findall(r'fetch\("([^"?]+)', JS))) +check(f"every request is relative, to the add-on's own routes ({_fetch})", + _fetch == ["config/model", "config/restart", "config/save", + "config/validate", "ha/entities"]) + + +def _resolve(path, node=W): + for k in path.split("."): + if not isinstance(node, dict) or k not in node: + return None + node = node[k] + return node + + +_used = {re.sub(r"\.(replace|join|length)$", "", k) for k in + re.findall(r'\bW\.([a-z_]+(?:\.[a-z_]+)*)', JS)} +_used |= set(re.findall(r'data-s(?:-ph|-label)?="([\w.]+)"', io.open( + os.path.join(HERE, "app", "static", "index.html"), encoding="utf-8").read())) +_miss = sorted(k for k in _used if _resolve(k) is None) +check(f"every word the view asks for is in app/ui_text ({len(_used)} keys, " + f"missing: {_miss})", len(_used) > 25 and not _miss) +check("search matches a field's label, its key and its help", + "(f.label + \" \" + keys + \" \" + f.key + \" \" + (f.help || \"\"))" + in JS) +check("a locked value shows no input until 'Change' is pressed", + re.search(r"function locked\(.*?\n }\n", JS, re.S) + and "UNLOCKED.has(id)) { open(); return box; }" in JS) +check("nothing is saved while the add-on's own checks refuse the model", + "if (MSG.some((m) => m.tier === \"bad\")) { toast(" in JS) +check("the old settings page stays reachable (until P5)", + 'href="config" id="set-classic"' in web.page()) + + +# --------------------------------------------------------------------------- # +# The real routes, over HTTP, against a fake Supervisor +# --------------------------------------------------------------------------- # +class Supervisor: + def __init__(self, options): + self.options = copy.deepcopy(options) + self.writes = [] + + async def info(self): + return {"options": copy.deepcopy(self.options), "schema": SCHEMA, + "translations": TRANSLATIONS} + + async def write_options(self, options): + self.writes.append(copy.deepcopy(options)) + self.options = copy.deepcopy(options) + + async def restart(self, confirm): + raise AssertionError("no restart here") + + +class Hass: + session = None + token = "" + + async def limits(self, _e): + return (-5000.0, 5000.0, 1.0) + + async def states(self): + return [] + + +class Controller: + def __init__(self, opts): + self.o, self.hass, self.inverters = dict(opts), Hass(), [] + + def log_event(self, text, hint=None): + pass + + def status_payload(self): + return {"banner": "", "level": "ok", "rows": [], "checks": []} + + async def handle_action(self, what): + raise AssertionError(f"the settings view reached {what!r}") + + +async def session(stored, steps): + """Run `steps(s, root)` against the app over a fake Supervisor.""" + sup = Supervisor(stored) + runner = aioweb.AppRunner(web.build_app(Controller(stored), sup)) + await runner.setup() + site = aioweb.TCPSite(runner, "127.0.0.1", 0) + await site.start() + root = f"http://127.0.0.1:{site._server.sockets[0].getsockname()[1]}/" + try: + async with ClientSession() as s: + out = await steps(s, root, sup) + finally: + await runner.cleanup() + return out, sup + + +async def _get(s, url): + async with s.get(url) as r: + return await r.json() + + +async def _post(s, url, body): + async with s.post(url, json=body) as r: + return r.status, await r.json() + + +# --------------------------------------------------------------------------- # +print("\n3. the save round trip") +# --------------------------------------------------------------------------- # +check("the fixture site starts (so a refusal below is the edit's)", + not validate_startup_config(TWO) and not validate_startup_config(SITE)) + + +async def _round(s, root, sup): + out = {} + m = await _get(s, root + "config/model?lang=en") + out["model"] = m + model = browser(m["ui"]) + out["same"] = await _post(s, root + "config/save", + {"model": model, "fingerprint": m["fingerprint"]}) + out["after_same"] = copy.deepcopy(sup.options) + m = await _get(s, root + "config/model?lang=en") + model = browser(m["ui"]) + model["peak_cap_w"] = 4200 + model["inverters"][1]["max_w"] = 2200 + out["edit"] = await _post(s, root + "config/save", + {"model": model, "fingerprint": m["fingerprint"]}) + return out + + +_stored = dict(TWO, gain=0.5, target_grid_w=-10.0, peak_cap_w=3500) +_r, _sup = asyncio.run(session(_stored, _round)) +check("config/model carries the layout and the page model", + _r["model"]["layout"] == json.loads(json.dumps(uipage.layout( + SCHEMA, TRANSLATIONS))) and _r["model"]["ui"]["inverter_count"] == 2) +check("a save that changed nothing writes an identical blob: same values, " + "types and key order, although the browser turned -10.0 into -10", + _r["same"][0] == 200 and json.dumps(_r["after_same"]) + == json.dumps(_stored) and isinstance(_r["after_same"]["target_grid_w"], + float)) +_written = _sup.writes[-1] +print(f" the edit: {_r['edit']}, changed " + f"{sorted(k for k in _stored if _written[k] != _stored[k])}") +check("an edit writes exactly the fields edited, the peak limit in W", + _r["edit"][0] == 200 + and sorted(k for k in _stored if _written[k] != _stored[k]) + == ["inverters", "peak_cap_w"] and _written["peak_cap_w"] == 4200 + and _written["inverters"][1]["max_w"] == 2200 + and _written["inverters"][0] == _stored["inverters"][0]) +_blobs = [("config.yaml", DEFAULTS), ("site", SITE), ("two", TWO)] + [ + (os.path.basename(f), json.load(open(f))) for f in sorted(glob.glob( + os.path.join(HERE, "scenarios", "ux13", "test23", "*.json")))] +_bad = [n for n, o in _blobs if json.dumps(uipage.to_options(browser( + json.loads(json.dumps(U.options_to_ui(o)))), o)) != json.dumps(o)] +check(f"every known blob comes back byte for byte through the browser " + f"({len(_blobs)} blobs, not: {_bad})", not _bad and len(_blobs) >= 8) +_grown = U.options_to_ui(SITE) +_grown["inverters"].append(dict(_grown["inverters"][0], name="b", + setpoint_entity="number.b")) +_grown["inverters"][0]["name"] = "a" +_grown.update(U.GROWN) +_g = U.ui_to_options(_grown) +check("'Add an inverter' on a flat site writes a list and clears the flat " + "power request entity, which the validator refuses beside a list", + [e["name"] for e in _g["inverters"]] == ["a", "b"] + and _g["setpoint_entity"] == "" and not validate_startup_config(_g)) + +# --------------------------------------------------------------------------- # +print("\n4. a refusal lands beside the field it is about") +# --------------------------------------------------------------------------- # + + +async def _refuse(s, root, sup): + out = {} + m = await _get(s, root + "config/model?lang=en") + base = m["ui"] + + async def validate(**edits): + model = copy.deepcopy(base) + for k, v in edits.items(): + if k == "card": + model["inverters"][v[0]][v[1]] = v[2] + else: + model[k.replace("__", ".")] = v + return (await _post(s, root + "config/validate", {"model": model}))[1] + + out["card"] = await validate(card=(1, "setpoint_entity", "")) + out["same"] = await validate(card=(1, "setpoint_entity", "number.a")) + out["floor"] = await validate(peak_soc_floor=5) + out["derive"] = await validate(ui__contract="dynamic", price_provider="") + model = copy.deepcopy(base) + model["inverters"][1]["setpoint_entity"] = "" + out["save"] = await _post(s, root + "config/save", + {"model": model, "fingerprint": m["fingerprint"]}) + return out + + +_r, _sup = asyncio.run(session(TWO, _refuse)) + + +def _at(payload, tier="bad"): + return {(m["field"], m["card"]) for m in payload["messages"] + if m["tier"] == tier} + + +print(f" blank power request entity on card 2: {_r['card']['messages']}") +check("a blank power request entity on the second card is refused beside " + "that card's field, and not beside the list as well", + ("inverters.setpoint_entity", 1) in _at(_r["card"]) + and ("inverters", None) not in _at(_r["card"])) +print(f" two cards on one entity: {_r['same']['messages']}") +check("two cards on one entity are refused beside that field on both cards", + {("inverters.setpoint_entity", 0), ("inverters.setpoint_entity", 1)} + == _at(_r["same"])) +check("a peak reserve under the cut-out level lands on the peak reserve and " + "on each card's cut-out level", + {("peak_soc_floor", None), ("inverters.bms_soc_floor", 0), + ("inverters.bms_soc_floor", 1)} <= _at(_r["floor"])) +check("a model no blob can say is refused beside its field, in plain words", + _r["derive"]["messages"] == [{ + "field": "price_provider", "card": None, "tier": "bad", + "text": W["derive"]["no_source"]["description"]}]) +check("a refused save answers 422 with the same placement and writes nothing", + _r["save"][0] == 422 and ("inverters.setpoint_entity", 1) + in _at(_r["save"][1]) and _sup.writes == []) +_fixed = U.options_to_ui(dict(TWO, static_profile="not json")) +check("a sentence about a key the page derives goes to the field that writes " + "it, or to the visible choice that sets it", + uipage.targets("static_profile", "", _fixed) == [("ui.contract", None)] + and uipage.targets("max_w", "", U.options_to_ui(SITE)) + == [("inverters.max_w", 0)] + and uipage.targets("pv_entity", "", _fixed) == [("ui.solar", None)]) +check("a sentence naming no setting on the page is kept, with no field", + uipage.anchors(["Something odd."], [], _fixed, ["gain"]) + == [{"field": None, "card": None, "tier": "bad", + "text": "Something odd."}]) + +# --------------------------------------------------------------------------- # +print("\n5. a stale save names the fields that changed elsewhere") +# --------------------------------------------------------------------------- # + + +async def _stale(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + sup.options["peak_cap_w"] = 5000 # the Configuration tab saves + model = copy.deepcopy(m["ui"]) + model["gain"] = 0.4 + return await _post(s, root + "config/save", + {"model": model, "fingerprint": m["fingerprint"]}) + + +_r, _sup = asyncio.run(session(TWO, _stale)) +check("409 with the page fields to look at, and nothing written", + _r[0] == 409 and _r[1]["kind"] == "stale" + and "peak_cap_w" in _r[1]["changed_fields"] and _sup.writes == [] + and _r[1]["fingerprint"] == selfconfig.fingerprint(_sup.options)) + +# --------------------------------------------------------------------------- # +print("\n6. the view's words keep to STYLE") +# --------------------------------------------------------------------------- # + + +def _texts(node, path=""): + for k, v in node.items(): + if isinstance(v, dict): + yield from _texts(v, f"{path}{k}.") + elif isinstance(v, str): + yield f"{path}{k}", v + + +_long = [(p, t) for p, t in _texts(W) + if len(t.split()) > (25 if p.endswith("description") else 6) + or (p.endswith("description") and len(re.findall(r"[.!?](?:\s|$)", t)) > 1) + or ";" in t] +check(f"every settings string is one sentence of at most 25 words, or a " + f"name of at most 6 ({_long})", not _long) +_labels = [c[1] for _g, f in _flat for c in f.get("choices", [])] +check("every choice, including the region with its year, is at most 6 words", + all(len(x.split()) <= 6 for x in _labels)) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_uilayout.py b/goodwe_controller/test_uilayout.py index 5d04ec5..70c4bdb 100644 --- a/goodwe_controller/test_uilayout.py +++ b/goodwe_controller/test_uilayout.py @@ -82,8 +82,9 @@ check("every control, entity kind and show operator is a known one", all(f.control in L.CONTROLS and (not f.kind or f.kind in L.ENTITY_KINDS) and all(op in L.SHOW_OPS for _n, op, _v in f.show) for _g, _p2, f in ROWS)) -_names = set(ORDER) | set(KEYS) | {"inverter_count"} -check("every show condition reads an option, a page field or inverter_count", +_names = set(ORDER) | set(KEYS) | {uimodel.COUNT} | set(uimodel.GROWN) +check("every show condition reads an option, a page field, or the inverter " + "count or shape", all(n in _names for _g, _p2, f in ROWS for n, _o, _v in f.show)) check("every entity control has a kind, and no other control has one", all((f.control in (L.ENTITY, L.ENTITY_LIST, L.SOLAR_LIST)) == bool(f.kind) @@ -189,11 +190,13 @@ _owned = set(L.DERIVED) | {"inverters", "price_provider", _extra = sorted({k for k in _KEY.findall(_src) if k in ORDER} - _owned) check(f"uimodel.py names only the keys its derivations write (others: " f"{_extra})", not _extra) -_leak = sorted({f"{name}:{k}" for name in ("haentities.py", "web.py") +_leak = sorted({f"{name}:{k}" for name in ("haentities.py", "web.py", + "uipage.py") for k in _KEY.findall(io.open(os.path.join(HERE, "app", name), encoding="utf-8").read()) if k in ORDER}) -check(f"haentities.py and web.py name no option key ({_leak})", not _leak) +check(f"haentities.py, web.py and uipage.py name no option key ({_leak})", + not _leak) print() if fails: diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py index 5b9067b..028f4c3 100644 --- a/goodwe_controller/tools/ux13_demo.py +++ b/goodwe_controller/tools/ux13_demo.py @@ -1,19 +1,29 @@ -"""UX-13 P1: serve the real page and routes over a fixture controller, for a -headless browser check. `python3 tools/ux13_demo.py STATE PORT` +"""UX-13: serve the real page and routes over a fixture controller, for a +headless browser check. `python3 tools/ux13_demo.py STATE PORT [HOST]` STATE is running, shadow or alarm. The controller is the shipped `Controller` with its readings set by hand (two batteries, solar, today's prices in the mockup's shape, trading on). Nothing here talks to Home Assistant or to an inverter: `/action` changes only this fixture. Used for the P1 render check (no JS errors, tooltips, phone width, dark mode) described in the PR. + +P2: the fixture Supervisor serves config.yaml's defaults with this site's +options, a schema read off config.yaml the way the Supervisor renders it +(`schema_ui()`) and translations/en.yaml, and keeps what the settings view +saves in memory, so the Installer view can be clicked through end to end. """ import asyncio +import io +import json import os +import re import sys from datetime import datetime, timedelta, timezone -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) from aiohttp import web as aioweb # noqa: E402 @@ -22,6 +32,7 @@ from app.main import Controller # noqa: E402 from app.peakguard import PeakDecision # noqa: E402 from app.price import PricePoint, PriceProduct, PriceRead # noqa: E402 from app.static_tariff import TariffPlan # noqa: E402 +import translations_lint as TL # noqa: E402 PRICES = [.24, .22, .21, .20, .21, .22, .24, .27, .26, .22, .18, .16, .15, .14, .16, .19, .23, .28, .33, .36, .34, .29, .26, .24] @@ -73,12 +84,119 @@ class Hass: return True async def states(self): - return [] + return STATES + + +def _state(eid, name, state, unit=None, cls=None): + return {"entity_id": eid, "state": state, + "attributes": {"friendly_name": name, "unit_of_measurement": unit, + "device_class": cls}} + + +STATES = [ + _state("sensor.grid", "Grid power", "-10", "W", "power"), + _state("sensor.grid_kw", "Grid power in kW", "-0.01", "kW", "power"), + _state("sensor.pv", "Solar power", "3900", "W", "power"), + _state("sensor.soc_a", "Battery A level", "62", "%", "battery"), + _state("sensor.soc_b", "Battery B level", "35", "%", "battery"), + _state("sensor.batt_a", "Battery A power", "-2500", "W", "power"), + _state("sensor.batt_b", "Battery B power", "-300", "W", "power"), + _state("number.a", "Battery A power request", "0", "W"), + _state("number.b", "Battery B power request", "0", "W"), + _state("sensor.peak_forecast", "Quarter-hour peak forecast", "1240", "W", + "power"), +] + + +# --- config.yaml as the Supervisor renders it (App.schema_ui) --------------- # +def _node(name, spec): + spec = spec.strip() + optional = spec.endswith("?") + spec = spec.rstrip("?") + out = {"name": name, "required": not optional, "optional": optional} + m = re.match(r"(int|float)\(([^,]*),([^)]*)\)$", spec) + if m: + out.update(type="integer" if m.group(1) == "int" else "float", + lengthMin=float(m.group(2)), lengthMax=float(m.group(3))) + elif spec.startswith("list("): + out.update(type="select", options=spec[5:-1].split("|")) + elif spec in ("bool",): + out["type"] = "boolean" + elif spec in ("int", "float"): + out["type"] = "integer" if spec == "int" else "float" + else: + out["type"] = "string" + return out + + +def schema_ui(text): + """config.yaml's `schema:` block in the Supervisor's schema_ui shape: the + fixture for tests and this demo, which cannot run the Supervisor.""" + block = text[text.index("\nschema:"):].splitlines()[1:] + out, i = [], 0 + while i < len(block): + line = block[i] + m = re.match(r"^ ([a-z_0-9]+):\s*(\S.*?)?\s*$", line) + i += 1 + if not m: + continue + name, spec = m.group(1), m.group(2) + if spec: + out.append(_node(name, spec)) + continue + items = [] + while i < len(block) and (block[i].startswith(" ") or not block[i].strip()): + if block[i].strip() and not block[i].strip().startswith("#"): + items.append(block[i].strip()) + i += 1 + if items and items[0].startswith("- ") and ":" in items[0]: + fields = [items[0][2:]] + items[1:] + out.append({"name": name, "type": "schema", "optional": True, + "multiple": True, + "schema": [_node(*f.split(":", 1)) for f in fields]}) + else: + node = _node(name, items[0][2:] if items else "str") + node.update(multiple=True, required=False, optional=True) + out.append(node) + return out + + +def defaults(text): + """config.yaml's `options:` block (as test_uimodel.py reads it).""" + block = text[text.index("\noptions:"):text.index("\nschema:")] + out = {} + for key, raw in re.findall(r"^ ([a-z_0-9]+):(.*)$", block, re.M): + raw = raw.split(" #")[0].strip() + try: + out[key] = json.loads(raw) + except ValueError: + out[key] = raw + return out + + +CONFIG = io.open(os.path.join(HERE, "config.yaml"), encoding="utf-8").read() class Supervisor: + """The stored options, kept in memory: a save here writes nothing else.""" + + def __init__(self, options): + self.options = options + self.writes = 0 + async def info(self): - return {"options": {}, "schema": [], "translations": {}} + return {"options": json.loads(json.dumps(self.options)), + "schema": schema_ui(CONFIG), + "translations": {"en": TL.parse_translation_file( + os.path.join(HERE, "translations", "en.yaml"))}} + + async def write_options(self, options): + self.options = json.loads(json.dumps(options)) + self.writes += 1 + print(f"options saved ({self.writes})", flush=True) + + async def restart(self, confirm): + print(f"restart asked ({confirm!r})", flush=True) OPTS = {"meter_entity": "sensor.grid", "meter_source": "off", @@ -119,13 +237,21 @@ def controller(state): return c -async def main(state, port): - runner = aioweb.AppRunner(web.build_app(controller(state), Supervisor())) +async def main(state, port, host="127.0.0.1"): + c = controller(state) + stored = dict(defaults(CONFIG), **OPTS) + stored.update(setpoint_entity="", meter_source="ha_signed", + p1_net_entity="sensor.grid", price_provider="generic_dayahead", + peak_forecast_entity="sensor.peak_forecast", + shadow_mode=c.o.get("shadow_mode", "off"), + inverters=[dict(i, bms_soc_floor=10) + for i in OPTS["inverters"]]) + runner = aioweb.AppRunner(web.build_app(c, Supervisor(stored))) await runner.setup() - await aioweb.TCPSite(runner, "127.0.0.1", port).start() + await aioweb.TCPSite(runner, host, port).start() print(f"serving {state} on http://127.0.0.1:{port}/", flush=True) await asyncio.Event().wait() if __name__ == "__main__": - asyncio.run(main(sys.argv[1], int(sys.argv[2]))) + asyncio.run(main(sys.argv[1], int(sys.argv[2]), *sys.argv[3:4])) -- 2.54.0 From 1752adf6e6c720e59f0b65acb42c0496882dbd24 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 28 Sep 2026 03:02:43 +0200 Subject: [PATCH 056/105] UX-13 P2: test_settings reads fields through named_absence Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- goodwe_controller/test_settings.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/goodwe_controller/test_settings.py b/goodwe_controller/test_settings.py index c312adf..89455cb 100644 --- a/goodwe_controller/test_settings.py +++ b/goodwe_controller/test_settings.py @@ -31,6 +31,7 @@ import translations_lint as TL # noqa: E402 import ux13_demo as D # noqa: E402 from app import selfconfig, uilayout as L, uimodel as U, uipage, web # noqa: E402 from app.validate import validate_startup_config # noqa: E402 +from named_absence import field # noqa: E402 fails = [] @@ -78,6 +79,7 @@ for _g in LAYOUT["groups"]: _flat.append((_g["id"], _f)) _flat += [(_g["id"], _s) for _s in _f.get("fields", [])] _keys = [f["key"] for _g, f in _flat] +FIELD = {f["key"]: f for _g, f in _flat} check("the six groups, in the design's order", [g["id"] for g in LAYOUT["groups"]] == ["meter", "inverters", "tariff", "safety", "maintenance", "tuning"] @@ -93,7 +95,7 @@ print(f" fields per group: {_counts}") check("every field has a label, and every option field's label is its " "translation without the group prefix", all(f["label"] and " · " not in f["label"] for _g, f in _flat) - and next(f for _g, f in _flat if f["key"] == "meter_source")["label"] + and field(FIELD, "meter_source")["label"] == "Where the meter reading comes from") _ranged = [(f["key"], f.get("min"), f.get("max")) for _g, f in _flat if f["control"] in (L.SLIDER, L.LOCKED)] @@ -102,16 +104,16 @@ check(f"every slider and locked value has its range from the schema " for _k, lo, hi in _ranged) and ("peak_cap_w", 500.0, 15000.0) in _ranged) check("the peak limit is a kW slider over a value stored in W", - next(f for _g, f in _flat if f["key"] == "peak_cap_w")["scale"] == 1000) + field(FIELD, "peak_cap_w")["scale"] == 1000) _choice = [f for _g, f in _flat if f["control"] in (L.SEGMENTED, L.SELECT, L.CHOICE)] check("every choice control has choices with words", all(f["choices"] and all(c[1] for c in f["choices"]) for f in _choice)) -_ms = next(f for _g, f in _flat if f["key"] == "meter_source") +_ms = field(FIELD, "meter_source") check("the meter source is radio cards with a line of help on each", _ms["control"] == L.CHOICE and set(_ms["hints"]) == {c[0] for c in _ms["choices"]}) -_reg = next(f for _g, f in _flat if f["key"] == "ui.region") +_reg = field(FIELD, "ui.region") check("the region shows its preset year beside the choice (P0 review)", ["flanders", "Flanders, Fluvius Antwerpen, 2026 figures", False] in _reg["choices"] and _reg["presets"]["flanders"]["year"] == 2026) @@ -129,14 +131,14 @@ check(f"measured and derived values are locked behind 'Change' " check("each group says when its settings apply", all(g["applies"] == [UI_TEXT["applies"]["restart"]["name"]] for g in LAYOUT["groups"])) -_inv = next(f for _g, f in _flat if f["key"] == "inverters") +_inv = field(FIELD, "inverters") check("the inverter cards carry their count, and adding one makes a list", _inv["count"] == U.COUNT and _inv["grow"] == U.GROWN and [s["key"] for s in _inv["fields"]] == [f.key for f in L.ROSTER_FIELDS]) check("a page-only field names the option keys it writes, for the grey key " "line", _reg["writes"] == ["price_taxes_profile"] - and next(f for _g, f in _flat if f["key"] == "ui.solar")["writes"] + and field(FIELD, "ui.solar")["writes"] == ["pv_entities", "pv_entity", "pv_invert_entities"]) check("without a Supervisor schema the page still draws, with no ranges", len(uipage.layout([], {})["groups"]) == 6) -- 2.54.0 From 7be09197d401e941431a4a44db1d2469d65eb5b9 Mon Sep 17 00:00:00 2001 From: UX-13 P2 review Date: Mon, 28 Sep 2026 03:43:47 +0200 Subject: [PATCH 057/105] UX-13 P2 review fixes (PR #145, comment 1880) 1. Discard reloads /config/model: after a stale save the page kept the new fingerprint with the old values, so Discard + Save overwrote the other surface's change without a 409. 2. Removing cards back to one restores the stored inverter shape, so a flat site stays flat after add + remove. 3. A choice the page can only keep ("Other time windows") stays offered while it is the stored value. 4. A load locks every locked value again. 5. at_zero() needs an accepted 0 W write; before the first one Home says "Going to 0 W" (the heartbeat writes every heartbeat_s, so it clears). 6. A field with a unit drops the translation's "(W)" from its label: the peak limit read "Peak limit (W)" beside a kW value. 7. A mirrored choice lists the mirrored field's keys, so a search for static_profile finds the contract on a fixed-price site. 8. test_settings: a save refused by ui_to_options writes nothing. Co-Authored-By: Claude Opus 5.5 --- goodwe_controller/app/homeview.py | 10 +++++--- goodwe_controller/app/static/settings.js | 22 +++++++++++------ goodwe_controller/app/uipage.py | 7 +++++- goodwe_controller/test_home.py | 9 ++++++- goodwe_controller/test_settings.py | 31 +++++++++++++++++++++--- goodwe_controller/tools/ux13_demo.py | 2 ++ 6 files changed, 64 insertions(+), 17 deletions(-) diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 250720d..c6c62c6 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -511,10 +511,12 @@ def build_plan(c, now, shadow, running, held=False, settled=True): # Batteries, attention, month peak, control # --------------------------------------------------------------------------- # def at_zero(inv) -> bool: - """Has this inverter's last accepted power request reached 0 W? A stop or - an alarm asks for 0 W at once, but the inverter gets it with the next - write, so until then the page says "Going to 0 W" (UX-13 P1 test, a).""" - return abs(inv.standing_w()) < 1.0 + """Has this inverter accepted a 0 W power request? A stop or an alarm asks + for 0 W at once, but the inverter gets it with the next write, so until + then the page says "Going to 0 W" (UX-13 P1 test, a). Before the first + accepted write nothing is known to be held; the heartbeat writes every + `heartbeat_s`, stopped or not, so this does not stick.""" + return inv.last_write is not None and abs(inv.last_write) < 1.0 def battery_rows(c, shadow, running, held=False): diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index 074ad3e..18273be 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -87,8 +87,10 @@ } /* ---------------- controls ---------------- */ - function choicesOf(f, cur) { - const out = (f.choices || []).filter((c) => !c[2] || same(c[0], cur)); + // A choice the page can only keep stays offered while it is the stored value. + function choicesOf(f, card) { + const cur = get(f, card), was = valueIn(ORIG, f, card); + const out = (f.choices || []).filter((c) => !c[2] || same(c[0], cur) || same(c[0], was)); if (cur != null && cur !== "" && !out.some((c) => same(c[0], cur))) out.push([cur, String(cur)]); return out; } @@ -106,7 +108,7 @@ function radios(f, card, lid, cards) { const cur = get(f, card); const g = h("div", { class: cards ? "choices" : "seg", role: "radiogroup", "aria-labelledby": lid }); - const items = choicesOf(f, cur); + const items = choicesOf(f, card); const buttons = items.map(([v, label], i) => { const on = same(v, cur); const hint = cards && f.hints ? f.hints[v] : ""; @@ -132,7 +134,7 @@ function select(f, card, lid) { const cur = get(f, card); const s = h("select", { class: "sel", "aria-labelledby": lid }); - for (const [v, label] of choicesOf(f, cur)) s.append(h("option", { value: JSON.stringify(v), selected: same(v, cur) }, label)); + for (const [v, label] of choicesOf(f, card)) s.append(h("option", { value: JSON.stringify(v), selected: same(v, cur) }, label)); for (const [v, label] of f.later || []) s.append(h("option", { value: JSON.stringify(v), disabled: true }, label)); s.addEventListener("change", () => put(f, card, JSON.parse(s.value), true)); const preset = f.presets && f.presets[cur]; @@ -324,7 +326,10 @@ const box = h("div", { class: "inv" }, h("div", { class: "hd" }, h("span", { class: "grow" }, c.name || W.inverter + " " + (i + 1)), h("span", { class: "key" }, f.key + "[" + i + "]"), cards.length > 1 ? h("button", { type: "button", class: "btn link tiny", onclick: () => { - V[f.key].splice(i, 1); V[f.count] = V[f.key].length; put(f, null, V[f.key], true); + V[f.key].splice(i, 1); V[f.count] = V[f.key].length; + // Back to one card, the stored shape returns: a flat inverter stays flat. + if (V[f.key].length === 1) for (const k in f.grow) V[k] = clone(ORIG[k]); + put(f, null, V[f.key], true); } }, W.remove) : null)); for (const s of f.fields) box.append(fieldRow(s, i, gid)); wrap.append(box); @@ -496,6 +501,7 @@ return; } M = m; V = clone(m.ui); ORIG = clone(m.ui); FP = m.fingerprint; MSG = []; DEVICE = ""; + UNLOCKED.clear(); $("#set-search").hidden = false; FILLED = {}; LIST = null; @@ -541,9 +547,9 @@ finally { btn.disabled = false; btn.textContent = W.savebar.save; } } $("#sb-save").addEventListener("click", save); - $("#sb-discard").addEventListener("click", () => { - V = clone(ORIG); UNLOCKED.clear(); render(); validate(); toast(W.toast.discarded); - if ($("#set-banner .b-bad")) banner(); + // Discard reloads what is stored: after a stale save ORIG is no longer it. + $("#sb-discard").addEventListener("click", async () => { + await load(); toast(W.toast.discarded); }); addEventListener("beforeunload", (e) => { if (V && dirtyCount()) { e.preventDefault(); e.returnValue = ""; } }); document.addEventListener("ux13:tab", (e) => { diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py index 9a84e4b..d82c4fa 100644 --- a/goodwe_controller/app/uipage.py +++ b/goodwe_controller/app/uipage.py @@ -91,6 +91,10 @@ def _choices(fld, node, T, value_type): def _field(fld, schema_ui, translations, lang, T): node = _node(schema_ui, fld.key) label, text = _words(translations, lang, fld.key, T) + if fld.unit: + # The page shows the unit beside the control, in its own scale (kW), + # so the translation's "(W)" goes; "(optional)" stays. + label = re.sub(r"\s*\([^()\s]{1,6}\)", "", label) value_type = ("float" if fld.control == L.NUMBER and fld.key.startswith("ui.") else node.get("type") or "") out = {"key": fld.key, "control": fld.control, "label": label, @@ -98,8 +102,9 @@ def _field(fld, schema_ui, translations, lang, T): "step": fld.step, "kind": fld.kind, "show": [list(c) for c in fld.show], "applies": fld.applies, "type": value_type, "optional": not node.get("required", False), + # A choice mirrored into a field also shows (and finds) its keys. "writes": sorted(k for k, how in L.DERIVED.items() - if how == fld.key)} + if how in (fld.key, fld.mirror))} if node.get("lengthMin") is not None: out["min"] = node["lengthMin"] if node.get("lengthMax") is not None: diff --git a/goodwe_controller/test_home.py b/goodwe_controller/test_home.py index 1adf98f..2a69591 100644 --- a/goodwe_controller/test_home.py +++ b/goodwe_controller/test_home.py @@ -123,11 +123,13 @@ MOCK = [.24, .22, .21, .20, .21, .22, .24, .27, .26, .22, .18, .16, .15, .14, def make(opts, *, soc=(62.0, 35.0), batt=(-2500.0, -300.0), grid=10.0, - auto=True): + auto=True, wrote=0.0): + """`wrote` is each inverter's last accepted power request (None: none yet).""" c = Controller(dict(opts), _Hass(), _Store(), _Pub(), stop=asyncio.Event()) c.auto = auto for i, inv in enumerate(c.inverters): inv.soc, inv.batt = soc[i], batt[i] + inv.last_write = wrote inv.dev_min, inv.dev_max = -5000.0, 5000.0 c.grid = grid return c @@ -471,6 +473,11 @@ check("an alarm while the last power request is still 20 W says 'Going to " c_sp = make(TWO, auto=False) c_sp.inverters[1].last_write = -1500.0 s_sp = status(c_sp) +s_new = status(make(TWO, auto=False, wrote=None)) +check("...and before any power request was accepted (just started, or every " + "write refused) it says 'Going to 0 W', not 'Held'", + [b["now"] for b in s_new["batteries"]] + == ["Going to 0 W while control is stopped."] * 2) check("...and a stop does the same, per battery", [b["now"] for b in s_sp["batteries"]] == ["Held at 0 W while control is stopped.", diff --git a/goodwe_controller/test_settings.py b/goodwe_controller/test_settings.py index 89455cb..5df6a2f 100644 --- a/goodwe_controller/test_settings.py +++ b/goodwe_controller/test_settings.py @@ -103,8 +103,12 @@ check(f"every slider and locked value has its range from the schema " f"({len(_ranged)})", all(lo is not None and hi is not None for _k, lo, hi in _ranged) and ("peak_cap_w", 500.0, 15000.0) in _ranged) -check("the peak limit is a kW slider over a value stored in W", - field(FIELD, "peak_cap_w")["scale"] == 1000) +check("the peak limit is a kW slider over a value stored in W, and its label " + "does not say W (the unit is shown beside the control)", + field(FIELD, "peak_cap_w")["scale"] == 1000 + and field(FIELD, "peak_cap_w")["label"] == "Peak limit" + and not [f["key"] for _g, f in _flat + if f["unit"] and re.search(r"\([^()\s]{1,6}\)", f["label"])]) _choice = [f for _g, f in _flat if f["control"] in (L.SEGMENTED, L.SELECT, L.CHOICE)] check("every choice control has choices with words", @@ -139,7 +143,8 @@ check("the inverter cards carry their count, and adding one makes a list", check("a page-only field names the option keys it writes, for the grey key " "line", _reg["writes"] == ["price_taxes_profile"] and field(FIELD, "ui.solar")["writes"] - == ["pv_entities", "pv_entity", "pv_invert_entities"]) + == ["pv_entities", "pv_entity", "pv_invert_entities"] + and "static_profile" in field(FIELD, "ui.contract")["writes"]) check("without a Supervisor schema the page still draws, with no ranges", len(uipage.layout([], {})["groups"]) == 6) @@ -183,6 +188,18 @@ check("a locked value shows no input until 'Change' is pressed", and "UNLOCKED.has(id)) { open(); return box; }" in JS) check("nothing is saved while the add-on's own checks refuse the model", "if (MSG.some((m) => m.tier === \"bad\")) { toast(" in JS) +check("Discard reloads the stored settings (after a stale save the page's " + "copy is no longer what is stored)", + re.search(r'"#sb-discard"\)\.addEventListener\("click", async \(\) => ' + r'\{\s*await load\(\);', JS) is not None) +check("a load locks every locked value again, and a choice the page can only " + "keep stays offered while it is the stored value", + "UNLOCKED.clear();" in JS.split("async function load")[1].split("render();")[0] + and "same(c[0], was)" in JS) +check("removing cards back to one restores the stored shape (a flat inverter " + "is not turned into a list of one)", + "if (V[f.key].length === 1) for (const k in f.grow) V[k] = clone(ORIG[k]);" + in JS) check("the old settings page stays reachable (until P5)", 'href="config" id="set-classic"' in web.page()) @@ -343,6 +360,11 @@ async def _refuse(s, root, sup): out["floor"] = await validate(peak_soc_floor=5) out["derive"] = await validate(ui__contract="dynamic", price_provider="") model = copy.deepcopy(base) + model.update({"ui.contract": "dynamic", "price_provider": ""}) + out["derive_save"] = await _post(s, root + "config/save", { + "model": model, "fingerprint": m["fingerprint"]}) + out["derive_writes"] = len(sup.writes) + model = copy.deepcopy(base) model["inverters"][1]["setpoint_entity"] = "" out["save"] = await _post(s, root + "config/save", {"model": model, "fingerprint": m["fingerprint"]}) @@ -374,6 +396,9 @@ check("a model no blob can say is refused beside its field, in plain words", _r["derive"]["messages"] == [{ "field": "price_provider", "card": None, "tier": "bad", "text": W["derive"]["no_source"]["description"]}]) +check("a save no blob can say answers 422 with its sentence and writes nothing", + _r["derive_save"][0] == 422 and _r["derive_writes"] == 0 + and _r["derive_save"][1]["messages"] == _r["derive"]["messages"]) check("a refused save answers 422 with the same placement and writes nothing", _r["save"][0] == 422 and ("inverters.setpoint_entity", 1) in _at(_r["save"][1]) and _sup.writes == []) diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py index 028f4c3..a00ffca 100644 --- a/goodwe_controller/tools/ux13_demo.py +++ b/goodwe_controller/tools/ux13_demo.py @@ -230,6 +230,8 @@ def controller(state): for inv, soc, batt in zip(c.inverters, (62.0, 35.0), (-2500.0, -300.0)): inv.soc, inv.batt = soc, (0.0 if state == "shadow" else batt) inv.dev_min, inv.dev_max = -5000.0, 5000.0 + if state != "running": # 0 W accepted: Home says "Held" + inv.last_write = 0.0 c.grid = -10.0 if state != "shadow" else -2810.0 c.pv_w = 3900.0 if state == "alarm": -- 2.54.0 From be57b87c34a3723d6495415a590b88165fc8e86f Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 28 Sep 2026 05:31:18 +0200 Subject: [PATCH 058/105] UX-13 P4: the setup wizard for installers The Setup tab draws the Installer view's page model one step at a time, from each field's `wizard` step in app/uilayout.py: meter (with the kettle test), inverters and batteries, solar (optional), prices, peak limit (battery modes: "comes in a later update", OPT-11), check and start. It reuses P2's controls and saves through /config/validate and /config/save. No route was added. - First run: /config/model says `setup_needed` when the stored options name no power request entity, or on a new install (no `setup_done` and no `auto` in the Store, control not started). The page opens #setup only when opened with no route. The wizard's save writes `setup_done`. - Kettle test: GET ha/entities?entity= reads one entity now, in W. The change decides: up keeps meter_invert off, down turns it on; a net or import/export meter that goes down blocks the step with what to check. - Last step: validate.setup_checks() beside the refusals: the meter reads, each power request entity exists in HA (bad if not, SAFETY-77), battery levels and power with direction, solar sign, prices. Saves with shadow_mode on by default, then a confirmed restart naming the 0 W. - P2 test finding (a): a stale save lists only the keys the other surface moved (the blob handed out on open, by fingerprint, against stored now). - test_setup.py; tools/ux13_wizard_blobs.py makes the 88 blobs the wizard can save; all accepted by Supervisor 2026.08.0 AppOptions (offline). - DECISIONS/UX-13-setup-wizard.md; DOCS "Setup, for a new install". Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LyR88rXETvwhTgx6yHE39p --- .../DECISIONS/UX-13-one-layout-table.md | 4 + .../DECISIONS/UX-13-setup-wizard.md | 93 +++ goodwe_controller/DOCS.md | 26 + goodwe_controller/app/haentities.py | 30 +- goodwe_controller/app/selfconfig.py | 23 +- goodwe_controller/app/static/app.css | 8 + goodwe_controller/app/static/app.js | 4 +- goodwe_controller/app/static/index.html | 15 +- goodwe_controller/app/static/settings.js | 282 ++++++- goodwe_controller/app/ui_text/en.json | 58 +- goodwe_controller/app/uilayout.py | 28 + goodwe_controller/app/uipage.py | 77 ++ goodwe_controller/app/validate.py | 240 +++++- goodwe_controller/app/web.py | 72 +- goodwe_controller/test_messages.py | 2 +- goodwe_controller/test_settings.py | 6 +- goodwe_controller/test_setup.py | 694 ++++++++++++++++++ goodwe_controller/tools/ux13_demo.py | 28 +- goodwe_controller/tools/ux13_wizard_blobs.py | 254 +++++++ 19 files changed, 1885 insertions(+), 59 deletions(-) create mode 100644 goodwe_controller/DECISIONS/UX-13-setup-wizard.md create mode 100644 goodwe_controller/test_setup.py create mode 100644 goodwe_controller/tools/ux13_wizard_blobs.py diff --git a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md index 540cbb0..310e5b6 100644 --- a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md +++ b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md @@ -66,6 +66,10 @@ What UX-02 made authoritative stays authoritative: to the existing `/config/validate` and `/config/save`, which turn it into options with `ui_to_options()` before the shipped validator runs. No route was added. +- P4: the setup wizard draws the same model by each field's `wizard` step. + Its tables (`KETTLE`, `SHADOW`) are in `uilayout.py`, and its live checks + are rules, so they are in `validate.py` (`setup_checks`). settings.js still + names no key. See [[UX-13-setup-wizard]]. ## 4. What this costs diff --git a/goodwe_controller/DECISIONS/UX-13-setup-wizard.md b/goodwe_controller/DECISIONS/UX-13-setup-wizard.md new file mode 100644 index 0000000..d3fa8a6 --- /dev/null +++ b/goodwe_controller/DECISIONS/UX-13-setup-wizard.md @@ -0,0 +1,93 @@ +# UX-13 P4 — the setup wizard, and when it opens by itself + +**Status: DECIDED 2026-09-28 (P4 dev; the design and mockup were approved +2026-09-27).** Card 6ab979852f3eca02fb40f69e. Builds on +[[UX-13-one-layout-table]]. Design note: `goodwe-session/UX-13-design.md` §1, §3.6. + +## 1. What the wizard is + +The Setup tab draws the Installer view's page model one step at a time: a +field is on step *n* when its `uilayout.Field` says `wizard=n`. It uses P2's +controls, `/config/validate` and `/config/save`. No route was added. +`uilayout.py` holds what a field cannot say: the kettle table (`KETTLE`), the +optional step and the shadow switch (`SHADOW`). Step 5 has no battery modes +yet (OPT-11); it says they come later. + +A step moves on when no refusal is anchored to one of its shown fields +(`uipage.step_problems`). A refusal on a hidden field, a field on no step or +no field at all blocks the last step, which lists every refusal. + +## 2. When it opens by itself (`uipage.setup_needed`) + +The page opens `#setup` only when it is opened with no route, and only when +`/config/model` gives a reason: + +- **`no_power_request`**: the stored options name no inverter to control. +- **`first_start`**: the Store has no `setup_done` and no `auto` key, and + control is not started. `auto` is the key Start/Stop writes, and + config.yaml ships `auto_start` off (the same "fresh install" reading as + app/shadow.py's `auto` default), so this is a site that has never run or + been stopped by hand and never finished the wizard. + +A site that runs control, or ever started or stopped it, is never sent to the +wizard. Without a Store the answer is no. The wizard's save writes +`setup_done` (an ISO time) to the Store. A save from the Installer view does +not. + +**Not decided here, for the owner:** the add-on exits 78 before it serves the +page when the stored options name no power request entity, which is what a +brand-new install ships (config.yaml's `setpoint_entity: ""`). So on a truly +new install the installer fills in "Inverter setpoint entity" on the +Configuration tab first, and the wizard opens on the next page visit. +Serving a setup-only page from a refused configuration would change the CFG-01 +startup gate and UX-02 §4 ("the panel is not available when it is most +needed"), so it is left as an open question. + +## 3. The kettle test and the sign checks + +Step 1 reads the meter's entities now (`GET ha/entities?entity=`, one +`hass.state()` read, in W) before and after a kettle is switched on. The +change, not the sign, decides: a rise of at least 500 W keeps `meter_invert` +off, a fall turns it on. For a net entity or import and export, a fall cannot +be fixed by an option, so the step is not passed and the page says what to +check. A meter the add-on reads itself (HomeWizard, MQTT) cannot be read by +the page, so the test is skipped and Home shows the direction after the +restart. The installer may skip the test; the last step then warns. + +The battery and solar signs cannot be forced from the page, which never +commands an inverter. The last step reports each battery's reading with its +direction ("reads 800 W charging now, so check the inverter shows the same") +and warns when a solar entity reads below zero without its "reads negative" +switch. + +## 4. The last step + +`validate.setup_checks()` sits beside the rules because it names option keys. +It reads nothing itself: `web.py` passes a Home Assistant entity list at most +5 s old, the running options, the running meter reading and today's price +count. Tiers are ok, info, warn and bad. A power request entity missing from +Home Assistant is **bad**, because a write to it is answered 200 (SAFETY-77) +and only the entity list can tell. The wizard does not save while anything is +bad. It then saves through P2's path (`setup: "done"`) and asks for the +restart as the second, confirmed request, with a dialog that names the 0 W. +The shadow switch is on by default and writes `shadow_mode: on`, which holds +every inverter at 0 W after a restart even if control is started. Off keeps the +stored value, or `auto` if that was `on`. + +## 5. The stale save lists only what moved (P2 test, finding a) + +`/config/model` remembers the last 16 blobs it handed out, by fingerprint. On a +stale save the add-on compares that blob with what is stored now, so the banner +lists only the other surface's changes. `changed` (stored against the posted +blob) is unchanged for the classic page's "theirs → mine" list. When the +fingerprint was not handed out by this process, it falls back to `changed`. + +## 6. How it is held + +- test_setup.py: the steps and tables, the kettle logic (and the page's copy of + it), step blocking, the first-run rule on new and TEST-23 sites, the live + checks, the save through the P2 path, the stale fix, and the words. +- tools/ux13_wizard_blobs.py produces every blob the wizard can save from a new + install and three TEST-23 sites (88 accepted by the shipped validator). At P4 + all 88 were accepted by Supervisor 2026.08.0's `AppOptions`, offline, 78 + keys each. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 4ba090b..3d6c8e2 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3221,6 +3221,32 @@ action log (`Controller.events`). The page no longer shows that log, but the page and add `status` to its address. The action-log tables in this document refer to it.* +### Setup, for a new install + +The **Setup** tab walks an installer through six steps: the meter, the +inverters and batteries, solar (optional), prices, the peak limit, and a last +check. Each step shows the same fields as Settings, and nothing is saved until +the last step. + +- **The kettle test** on the meter step reads the meter, then reads it again + after you switch on a kettle. If the reading goes down, the add-on flips its + sign for you; with a net or import/export meter it tells you what to change. +- **The last step** runs the add-on's own start checks and reads Home + Assistant: the meter reading, that each power request entity exists, the + battery levels, and whether prices are known. A missing power request entity + is red, so it cannot be saved. +- **Save and restart** saves, then restarts the add-on. Every inverter is set + to 0 W while it restarts, and with "Start in shadow mode" on (the default) it + stays at 0 W until you turn shadow mode off under Settings. + +Setup opens by itself when the page is opened on a new install: control was +never started or stopped and Setup never finished, or the stored settings name +no inverter to control. A running site is never sent there. The add-on does +not start with no power request entity at all, so on a brand-new install fill +in "Inverter setpoint entity" on the Configuration tab first. + +*For installers: card UX-13, and `DECISIONS/UX-13-setup-wizard.md`.* + ## Status page The add-on page shows a banner at the top and a **Commissioning** list below diff --git a/goodwe_controller/app/haentities.py b/goodwe_controller/app/haentities.py index 695ef6f..4aa47d8 100644 --- a/goodwe_controller/app/haentities.py +++ b/goodwe_controller/app/haentities.py @@ -13,6 +13,7 @@ CACHE_S = 30.0 DOWN_TEXT = "Home Assistant is not answering, so the entity list is empty." STALE_TEXT = "Home Assistant is not answering, so this list may be old." _POWER_UNITS = ("mW", "W", "kW", "MW", "GW", "TW") +_TO_W = {"mW": 0.001, "W": 1.0, "kW": 1000.0, "MW": 1e6} _ENERGY_UNITS = ("Wh", "kWh", "MWh", "GWh") @@ -28,6 +29,18 @@ def row(state: dict) -> dict | None: "device_class": attrs.get("device_class")} +def watts(r: dict | None): + """A power entity's reading in W, or None when it is not a number in a + power unit (the setup wizard's kettle test).""" + if not r or r.get("unit") not in _TO_W: + return None + try: + value = float(r.get("state")) + except (TypeError, ValueError): + return None + return value * _TO_W[r["unit"]] if value == value else None + + def matches(r: dict, kind: str) -> bool: """Is `r` what a picker of this kind offers first? `kind` is one of uilayout.ENTITY_KINDS; "" or "any" offers everything.""" @@ -54,13 +67,16 @@ class EntityCache: self.tried_at: float | None = None self._lock = asyncio.Lock() - async def get(self) -> tuple[dict | None, float | None]: - """(rows by entity id, age in s), or (None, None) if never read.""" + async def get(self, max_age: float = CACHE_S + ) -> tuple[dict | None, float | None]: + """(rows by entity id, age in s), or (None, None) if never read. + `max_age` is how old a try may be before HA is asked again: the setup + wizard's last step asks for a list at most a few seconds old.""" async with self._lock: # one HA read however many pickers ask now = self.clock() # A failed read also waits CACHE_S, so polls while HA is down do # not queue one 10 s read each behind this lock. - if self.tried_at is None or now - self.tried_at >= CACHE_S: + if self.tried_at is None or now - self.tried_at >= max_age: self.tried_at = now states = await self.hass.states() if states is not None: @@ -71,6 +87,14 @@ class EntityCache: return None, None return self.rows, now - self.read_at + async def reading(self, entity_id: str) -> dict: + """One entity read now, not from the list: the kettle test compares + two readings seconds apart, which a 30 s list cannot. A read only.""" + r = row(await self.hass.state(entity_id)) if entity_id else None + return {"entity_id": entity_id, "found": r is not None, + "state": r and r["state"], "unit": r and r["unit"], + "watts": watts(r)} + def peek(self) -> dict | None: """The cached rows if they are fresh, without asking Home Assistant.""" if self.read_at is None or self.clock() - self.read_at >= CACHE_S: diff --git a/goodwe_controller/app/selfconfig.py b/goodwe_controller/app/selfconfig.py index 7c56b78..5458253 100644 --- a/goodwe_controller/app/selfconfig.py +++ b/goodwe_controller/app/selfconfig.py @@ -131,11 +131,16 @@ class SaveRefused(Exception): own sentences, byte for byte; `changed` names the keys that moved. """ - def __init__(self, kind, problems=(), changed=(), stored=None): + def __init__(self, kind, problems=(), changed=(), stored=None, + moved=None): self.kind = kind self.problems = list(problems) self.changed = list(changed) self.stored = stored + # UX-13 P4: the keys the OTHER surface changed - stored-on-open + # against stored-now - when the caller knows what it opened. None + # when it does not. `changed` also holds the operator's own edits. + self.moved = None if moved is None else list(moved) super().__init__(f"save refused ({kind})") @@ -359,7 +364,7 @@ async def problems_and_ranges(opts: dict, hass=None, notes=None): async def save(selfcfg: SelfConfig, proposed: dict, expect: str, *, - hass=None) -> dict: + hass=None, base=None) -> dict: """Validate, compare-and-swap, then write. Refuse rather than half-do. Returns `{"fingerprint": }` on success. Raises `SaveRefused` @@ -382,6 +387,11 @@ async def save(selfcfg: SelfConfig, proposed: dict, expect: str, *, genuinely wants what the other surface wrote replaced, the page reloads, shows them what changed, and they save again from THAT - which is a decision made in front of the difference rather than through it. + + `base`, when given, is the blob the page opened (the one `expect` is the + fingerprint of). A stale refusal then also names the keys that moved + underneath it, so the page does not list the operator's own edits among + the settings "changed elsewhere" (UX-13 P2 test, finding a). """ problems = await problems_for(proposed, hass) if problems: @@ -395,10 +405,15 @@ async def save(selfcfg: SelfConfig, proposed: dict, expect: str, *, actual = fingerprint(stored) if actual != expect: changed = changed_keys(stored, proposed) + moved = (changed_keys(base, stored) + if isinstance(base, dict) and fingerprint(base) == expect + else None) + keys = changed if moved is None else moved _LOG.warning("The settings page did not save, because the settings " "changed while it was open (keys: %s).", - ", ".join(changed) or "none this page also edited") - raise SaveRefused("stale", changed=changed, stored=stored) + ", ".join(keys) or "none this page also edited") + raise SaveRefused("stale", changed=changed, stored=stored, + moved=moved) await selfcfg.write_options(proposed) _LOG.info("options saved from the ingress panel; a restart is needed " diff --git a/goodwe_controller/app/static/app.css b/goodwe_controller/app/static/app.css index ad582d7..d766298 100644 --- a/goodwe_controller/app/static/app.css +++ b/goodwe_controller/app/static/app.css @@ -216,3 +216,11 @@ input:disabled{opacity:.6} #savebar .btn.primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent)} @media (max-width:640px){#savebar{bottom:62px}} #s-set{padding-bottom:80px} +/* UX-13 P4: the setup wizard */ +.steps{display:flex;gap:4px;margin:4px 0 12px} +.steps i{flex:1;height:6px;border-radius:3px;background:var(--track)} +.steps i.done{background:var(--accent)} .steps i.cur{background:var(--accent);opacity:.55} +.msg.ok{background:var(--ok-bg);color:var(--ok)} +.sev.bad{background:var(--bad-bg);color:var(--bad)} .sev.warn{background:var(--warn-bg);color:var(--warn)} +.checklist li{display:flex;gap:8px;align-items:flex-start;overflow-wrap:anywhere} +.kettle .row{margin-top:8px} diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 0153c55..8c9530c 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -332,7 +332,9 @@ $("#btn-abort").addEventListener("click", () => ask("maint_abort", () => simple("maint_abort"))); // Shared with settings.js, which loads after this file. - window.UX13 = { h, ask, toast, t, maint: (what) => ask(what, () => simple(what)) }; + // `first`: the page opened with no route, so settings.js may open the setup + // wizard on a new install (UX-13 P4). + window.UX13 = { h, ask, toast, t, maint: (what) => ask(what, () => simple(what)), first: !location.hash }; /* ---------------- tabs: hash routes, arrow keys ---------------- */ const TABS = [...document.querySelectorAll(".tab")]; diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html index ad2b649..3831627 100644 --- a/goodwe_controller/app/static/index.html +++ b/goodwe_controller/app/static/index.html @@ -117,11 +117,18 @@ diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index 18273be..75d5c00 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -5,7 +5,9 @@ ranges and choices all arrive as data. It posts the page model back; the add-on turns it into options and runs its own start checks, and nothing they refuse is saved. Every word is from app/ui_text or the add-on, and - data is set as text, never as HTML. */ + data is set as text, never as HTML. + P4: the Setup tab's wizard is the same page model, drawn one step at a + time from each field's `wizard` step, and saved through the same routes. */ (function () { const ROOT = JSON.parse(document.getElementById("ui-text").textContent); const W = ROOT.settings; @@ -28,7 +30,8 @@ let DEVICE = ""; let LIST = null; // the inverter list field let FILLED = {}; // field key -> the preset field that fills it - let active = false; + let view = null; // "settings" or "setup": the tab drawing V + let STEPS = {}; // wizard step -> refusals that block it let uid = 0; const ROWS = []; const OPEN = new Set(); @@ -60,7 +63,7 @@ if (m && (m.choices || []).some((c) => same(c[0], v))) V[f.mirror] = v; } if (f.fills && f.presets && f.presets[v]) V[f.fills] = f.presets[v].value; - if (redraw || f.fills) render(); else paint(); + if (redraw || f.fills) redrawView(); else paint(); queueValidate(); } function findField(key) { @@ -290,6 +293,7 @@ /* ---------------- rows, cards and groups ---------------- */ function keyText(f, card) { + if (view === "setup") return ""; // the wizard shows no keys if (card != null) return V[LIST.shape] === "flat" && f.flat ? f.flat : LIST.key + "[" + card + "]." + sub(f); return f.key.startsWith("ui.") ? (f.writes || []).join(", ") : f.key; } @@ -324,7 +328,7 @@ } else { cards.forEach((c, i) => { const box = h("div", { class: "inv" }, h("div", { class: "hd" }, - h("span", { class: "grow" }, c.name || W.inverter + " " + (i + 1)), h("span", { class: "key" }, f.key + "[" + i + "]"), + h("span", { class: "grow" }, c.name || W.inverter + " " + (i + 1)), view === "setup" ? null : h("span", { class: "key" }, f.key + "[" + i + "]"), cards.length > 1 ? h("button", { type: "button", class: "btn link tiny", onclick: () => { V[f.key].splice(i, 1); V[f.count] = V[f.key].length; // Back to one card, the stored shape returns: a flat inverter stays flat. @@ -393,7 +397,7 @@ return m.card == null ? r.card === 0 : m.card === r.card; } function paint() { - const q = $("#set-search").value.trim().toLowerCase(); + const q = view === "setup" ? "" : $("#set-search").value.trim().toLowerCase(); const placed = new Set(); for (const r of ROWS) { r.visible = visible(r.f); @@ -451,7 +455,7 @@ } function savebar() { const n = V ? dirtyCount() : 0; - $("#savebar").hidden = !(active && n); + $("#savebar").hidden = !(view === "settings" && n); $("#sb-text").textContent = n + " " + (n === 1 ? W.savebar.one : W.savebar.many); } $("#set-search").addEventListener("input", () => { if (V) paint(); }); @@ -459,17 +463,21 @@ /* ---------------- talking to the add-on ---------------- */ let vtimer = null, vseq = 0; function queueValidate() { clearTimeout(vtimer); vtimer = setTimeout(validate, 400); } - async function validate() { + // `extra` asks for more, e.g. the wizard's live checks. Returns the answer, + // or null when it failed or a newer check overtook it. + async function validate(extra) { const seq = ++vseq; try { const r = await fetch("config/validate", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ model: V }) }); + body: JSON.stringify(Object.assign({ model: V }, extra || {})) }); const b = await r.json(); - if (seq !== vseq) return; + if (seq !== vseq) return null; MSG = b.messages || []; DEVICE = b.device_note || ""; + STEPS = b.steps || {}; paint(); - } catch (e) { /* the next change tries again */ } + return b; + } catch (e) { return null; /* the next change tries again */ } } function banner(level, title, sub, button, onClick) { const host = $("#set-banner"); @@ -513,7 +521,7 @@ if (after === "saved") banner("ok", W.saved.name, W.saved.description, W.restart, restart); else if ((m.running_differs || []).length) banner("warn", W.differs.name, W.differs.description, W.restart, restart); else banner(); - render(); + if (view === "setup") drawStep(); else render(); validate(); } function firstBad() { @@ -524,6 +532,20 @@ const input = r.el.querySelector("input,select,button"); if (input) input.focus({ preventScroll: true }); } + // The one save path, for the Installer view and the wizard. After a stale + // refusal the page holds the new token, so a second press saves. + async function postSave(extra) { + const r = await fetch("config/save", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify(Object.assign({ model: V, fingerprint: FP }, extra || {})) }); + const b = await r.json().catch(() => ({})); + if (r.status === 409 && b.kind === "stale") FP = b.fingerprint || FP; + return { r, b }; + } + // The settings another surface changed (not this page's own edits). + function staleText(b) { + const names = (b.changed_fields || []).map((k) => { const f = findField(k); return f ? f.label : k; }); + return W.stale.description + (names.length ? " " + names.join(", ") + "." : ""); + } async function save() { const btn = $("#sb-save"); btn.disabled = true; btn.textContent = W.savebar.saving; @@ -531,14 +553,10 @@ clearTimeout(vtimer); await validate(); if (MSG.some((m) => m.tier === "bad")) { toast(W.toast.blocked.description); firstBad(); return; } - const r = await fetch("config/save", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ model: V, fingerprint: FP }) }); - const b = await r.json().catch(() => ({})); + const { r, b } = await postSave(); if (r.ok) { toast(W.toast.saved); await load("saved"); return; } if (r.status === 409 && b.kind === "stale") { - FP = b.fingerprint || FP; - const names = (b.changed_fields || []).map((k) => { const f = findField(k); return f ? f.label : k; }); - banner("bad", W.stale.name, W.stale.description + (names.length ? " " + names.join(", ") + "." : "")); + banner("bad", W.stale.name, staleText(b)); return; } if (r.status === 422) { MSG = b.messages || []; paint(); toast(W.toast.blocked.description); firstBad(); return; } @@ -552,10 +570,234 @@ await load(); toast(W.toast.discarded); }); addEventListener("beforeunload", (e) => { if (V && dirtyCount()) { e.preventDefault(); e.returnValue = ""; } }); + + /* ---------------- the setup wizard (P4) ---------------- */ + const WS = W.setup; + const WZ = { step: 1, kettle: null, shadowOn: true, done: "", checked: null }; + function redrawView() { if (view === "setup") drawStep(); else render(); } + function allFields() { + const out = []; + for (const g of M.layout.groups) for (const p of g.parts) for (const f of p.fields) out.push(f); + return out; + } + const say = (text, vars) => Object.keys(vars || {}).reduce((t, k) => t.replace("{" + k + "}", vars[k]), text); + function watts(w, signed) { + const n = String(Math.round(Math.abs(w))).replace(/\B(?=(\d{3})+(?!\d))/g, " "); + return (signed && w < 0 ? "-" : "") + n + " W"; + } + function line(tier, text) { + const icon = { ok: "✓", bad: "×", warn: "!", info: "i" }[tier] || "i"; + return h("li", {}, h("span", { class: "sev " + tier, "aria-hidden": "true" }, icon), + h("span", {}, h("span", { class: "sr" }, (W.tier[tier] || "") + ": "), text)); + } + + // Step 1's kettle test. The table is app/uilayout.py's KETTLE; this is + // uipage.kettle() (test_setup.py grades that one) on the page. + function kettleSource() { const K = M.setup.kettle; return K.sources[V[K.source]] || null; } + function kettleSig(src) { return JSON.stringify([V[M.setup.kettle.source], src.read.map(([k]) => V[k] || "")]); } + function kettleOutcome(src, before, after) { + const d = after - before; + if (Math.abs(d) < M.setup.kettle.min_w) return { say: "none", sets: null, d }; + const o = src[d > 0 ? "up" : "down"]; + return { say: o.say, sets: o.sets, d }; + } + function kettleOk() { + const src = kettleSource(); + return !src || !!(WZ.kettle && WZ.kettle.sig === kettleSig(src) && WZ.kettle.ok); + } + async function readMeter(src) { + let total = 0; + for (const [key, sign] of src.read) { + if (!V[key]) return null; + const r = await fetch("ha/entities?entity=" + encodeURIComponent(V[key]), { cache: "no-store" }) + .then((x) => (x.ok ? x.json() : null)).catch(() => null); + if (!r || r.watts == null) return null; + total += sign * r.watts; + } + return total; + } + function kettleBox() { + const src = kettleSource(); + const box = h("div", { class: "f kettle" }, h("div", { class: "lbl" }, WS.kettle.name)); + if (!src) { box.append(h("div", { class: "help" }, WS.kettle.self.description)); return box; } + const sig = kettleSig(src); + if (WZ.kettle && WZ.kettle.sig !== sig) WZ.kettle = null; // another meter: test again + const k = WZ.kettle || { sig }; + box.append(h("div", { class: "help" }, WS.kettle.description)); + const tone = { ok: "ok", flip: "info", none: "warn", unread: "bad", skipped: "warn" }[k.say] || "bad"; + const words = k.say ? WS.kettle[k.say] : k.before != null ? WS.kettle.before : null; + if (words) box.append(h("div", { class: "msg " + (k.say ? tone : "info"), role: "status" }, + say(words.description, { w: k.before != null ? watts(k.before, true) : "", d: k.d != null ? watts(k.d) : "" }))); + const busy = (b) => { b.disabled = true; }; + const read = h("button", { type: "button", class: "btn" }, k.before != null && !k.ok ? WS.kettle.again : WS.kettle.read); + read.addEventListener("click", async () => { + busy(read); + const sig = kettleSig(src); // the entity may have changed since drawing + if (k.sig !== sig) { k.before = null; k.ok = false; k.sig = sig; } + const w = await readMeter(src); + if (w == null) WZ.kettle = Object.assign({}, k, { sig, say: "unread" }); + else if (k.before == null || k.ok) WZ.kettle = { sig, before: w }; + else { + const o = kettleOutcome(src, k.before, w); + WZ.kettle = { sig, before: o.say === "none" ? k.before : null, say: o.say, d: o.d, ok: o.sets != null }; + if (o.sets) { Object.assign(V, o.sets); queueValidate(); } + } + drawStep(); + }); + const row = h("div", { class: "row" }, read); + if (!k.ok) row.append(h("button", { type: "button", class: "btn link", onclick: () => { + WZ.kettle = { sig: kettleSig(src), say: "skipped", ok: true, skipped: true }; drawStep(); + } }, WS.kettle.skip)); + box.append(row); + return box; + } + + // Step 6: the shadow switch, the checks, and Save and restart. + function applyShadow() { + const s = M.setup.shadow; + V[s.field] = WZ.shadowOn ? s.on : (ORIG[s.field] !== s.on ? ORIG[s.field] : s.off); + } + function shadowRow() { + const lid = "wzs"; + const b = h("button", { type: "button", class: "switch", role: "switch", "aria-checked": String(WZ.shadowOn), "aria-labelledby": lid }); + b.addEventListener("click", () => { WZ.shadowOn = !WZ.shadowOn; applyShadow(); queueValidate(); drawStep(); }); + return h("div", { class: "f inline" }, + h("div", {}, h("div", { class: "lbl", id: lid }, WS.shadow.name), h("div", { class: "help" }, WS.shadow.description)), + h("div", { class: "ctl" }, b)); + } + async function runChecks() { + const list = $("#wz-checks"); + if (list) list.replaceChildren(line("info", WS.check.running.description)); + clearTimeout(vtimer); + const b = await validate({ setup: true }); + WZ.checked = b; + if (!list || !list.isConnected) return b; + if (!b) { list.replaceChildren(line("bad", WS.check.failed.description)); return b; } + const items = [], seen = new Set(); + const add = (tier, text) => { if (!seen.has(text)) { seen.add(text); items.push([tier, text]); } }; + const bad = (b.messages || []).filter((m) => m.tier === "bad"); + if (!bad.length) add("ok", WS.check.pass.description); + for (const m of bad) add("bad", m.text); + for (const m of b.setup || []) add(m.tier, m.text); + if (b.device_note) add("info", b.device_note); + const src = kettleSource(); + if (!src) add("info", WS.kettle.self.description); + else if (WZ.kettle && WZ.kettle.skipped) add("warn", WS.kettle.skipped.description); + else if (kettleOk()) add("ok", WS.kettle.tested.description); + const rank = { bad: 0, warn: 1, ok: 2, info: 3 }; + items.sort((a, z) => rank[a[0]] - rank[z[0]]); + list.replaceChildren(...items.map(([t, x]) => line(t, x))); + WZ.blocked = items.some(([t]) => t === "bad"); + return b; + } + function finalBox() { + const again = h("button", { type: "button", class: "btn", onclick: runChecks }, WS.check.again); + setTimeout(runChecks, 0); + return [h("div", { class: "subhead" }, WS.check.name), + h("ul", { class: "plain checklist small", id: "wz-checks", "aria-live": "polite" }), h("div", { class: "row" }, again), + shadowRow()]; + } + function wzBanner(level, title, sub, button, onClick) { + const host = $("#wz-banner"); + if (!title) { host.replaceChildren(); return; } + host.replaceChildren(h("div", { class: "banner " + ({ ok: "b-ok", bad: "b-bad" }[level] || "b-warn") }, + h("span", { class: "ic", "aria-hidden": "true" }, { ok: "✓", bad: "×" }[level] || "!"), + h("span", {}, title, h("small", {}, sub, button ? [" ", h("button", { type: "button", class: "btn link", onclick: onClick }, button)] : null)))); + } + async function finish() { + const b = await runChecks(); + if (!b) { toast(WS.check.failed.description); return; } + if (WZ.blocked) { toast(WS.check.blocked.description); return; } + const shadow = V[M.setup.shadow.field] === M.setup.shadow.on; + ask(shadow ? WS.dialog : WS.dialog_live, async () => { + wzBanner(); + let res; + try { res = await postSave({ setup: "done" }); } catch (e) { toast(W.toast.failed); return; } + const { r, b: body } = res; + if (r.status === 409 && body.kind === "stale") { wzBanner("bad", W.stale.name, staleText(body)); return; } + if (r.status === 422) { + MSG = body.messages || []; STEPS = body.steps || {}; + const first = Object.keys(STEPS).map(Number).sort((a, z) => a - z).find((n) => STEPS[n] > 0); + if (first) WZ.step = first; + drawStep(); toast(W.toast.blocked.description); firstBad(); + return; + } + if (!r.ok) { toast(W.toast.failed); return; } + let restarted = true; + try { + const rr = await fetch("config/restart", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ confirm: "restart" }) }); + restarted = rr.ok; + } catch (e) { /* the add-on stops answering while it restarts */ } + WZ.done = restarted ? (shadow ? "done" : "done_live") : "restart_failed"; + drawStep(); + if (!restarted) await load("saved"); // still running: read what is stored + }); + } + function drawDone() { + const w = WS[WZ.done]; + $("#wz-count").textContent = ""; + $("#wz-steps").replaceChildren(); + $("#wz-desc").textContent = ""; + $("#wz-nav").hidden = true; + ROWS.length = 0; + if (WZ.done === "restart_failed") wzBanner("warn", w.name, w.description, W.restart, restart); + else wzBanner("ok", w.name, w.description); + $("#wz-body").replaceChildren(h("a", { class: "btn primary", href: "#home" }, WS.home)); + } + function drawStep() { + if (!M) return; + if (WZ.done) { drawDone(); return; } + const S = M.setup, n = WZ.step, words = WS.steps[n]; + $("#wz-nav").hidden = false; + $("#wz-title").textContent = words.name; + $("#wz-count").textContent = say(WS.step, { n, total: S.steps }); + $("#wz-steps").replaceChildren(...Array.from({ length: S.steps }, (_x, i) => + h("i", { class: i + 1 < n ? "done" : i + 1 === n ? "cur" : null }))); + $("#wz-desc").textContent = words.description; + ROWS.length = 0; + const body = []; + if (n === 1 && !M.setup_needed) body.push(h("div", { class: "msg info" }, WS.done_before.description)); + if (n === S.final) applyShadow(); + for (const f of allFields()) if (f.wizard === n && f.key !== S.shadow.field) body.push(fieldRow(f, null, "wz")); + if (n === 1) body.push(kettleBox()); + if (n === 5) body.push(h("p", { class: "small muted" }, WS.modes_later.description)); + if (n === S.final) body.push(...finalBox()); + $("#wz-body").replaceChildren(...body); + $("#wz-back").textContent = n === 1 ? WS.not_now : WS.back; + $("#wz-next").textContent = n === S.final ? WS.finish : S.optional.includes(n) ? WS.skip : WS.next; + paint(); + } + $("#wz-back").addEventListener("click", () => { + if (WZ.step === 1) { location.hash = "#home"; return; } + WZ.step -= 1; drawStep(); window.scrollTo(0, 0); + }); + $("#wz-next").addEventListener("click", async () => { + if (!M) return; + const btn = $("#wz-next"); + btn.disabled = true; + try { + const n = WZ.step; + if (n === M.setup.final) { await finish(); return; } + clearTimeout(vtimer); + const b = await validate(); + if (!b) { toast(W.toast.failed); return; } + if (n === 1 && !kettleOk()) { toast(WS.kettle.needed.description); return; } + if ((STEPS[n] || 0) > 0) { toast(W.toast.blocked.description); firstBad(); return; } + WZ.step = n + 1; drawStep(); window.scrollTo(0, 0); + } finally { btn.disabled = false; } + }); + document.addEventListener("ux13:tab", (e) => { - active = e.detail === "settings"; - if (active && !M) load(); else savebar(); + view = e.detail === "settings" || e.detail === "setup" ? e.detail : null; + if (view && !M) load(); else if (view) { redrawView(); validate(); } else savebar(); }); // app.js chose the first tab before this file ran. - if ($("#t-set").getAttribute("aria-selected") === "true") { active = true; load(); } + const sel = document.querySelector(".tab[aria-selected=true]"); + if (sel && (sel.dataset.hash === "settings" || sel.dataset.hash === "setup")) { view = sel.dataset.hash; load(); } + // First run: opened with no route, on a site the add-on says is new + // (uipage.setup_needed), the page goes to Setup by itself. + else if (window.UX13.first) { + load().then(() => { if (M && M.setup_needed && location.hash === "#home") location.hash = "#setup"; }); + } })(); diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index dbb87a0..f4f594a 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -80,8 +80,7 @@ "toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."}, "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, "batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"}, - "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"}, - "setup": {"name": "Setup", "description": "The setup steps arrive in a later update, so use the settings page for now."} + "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, "choices_later": { "region": {"wallonia": "Wallonia, no preset yet", "brussels": "Brussels, no preset yet"} @@ -148,7 +147,7 @@ "blocked": {"description": "Fix the settings marked in red, then save again."}, "restarting": {"description": "Restart requested, so this page stops answering for a moment."} }, - "tier": {"bad": "Must fix", "warn": "Check this", "info": "Note"}, + "tier": {"bad": "Must fix", "warn": "Check this", "info": "Note", "ok": "Passed"}, "derive": { "raw_roster": {"description": "This inverter list can only be changed in the Configuration tab."}, "no_inverter": {"description": "Add at least one inverter."}, @@ -157,6 +156,59 @@ "custom_profile": {"description": "Other time windows can only be changed in the Configuration tab."}, "no_price": {"description": "Enter a price per kWh."}, "unknown": {"description": "The page cannot store this choice, so reload the page."} + }, + "setup": { + "name": "Setup", + "description": "For installers: six steps to a working site, and each can be changed later under Settings.", + "done_before": {"description": "This site is set up already, so a change here replaces its stored settings."}, + "step": "Step {n} of {total}", + "back": "Back", + "next": "Next", + "skip": "Next, or skip", + "finish": "Save and restart", + "not_now": "Not now", + "steps": { + "1": {"name": "Your meter", "description": "The add-on steers the grid reading to zero, so it needs your meter first."}, + "2": {"name": "Inverters and batteries", "description": "One card for each inverter with a battery, with its entities in Home Assistant."}, + "3": {"name": "Solar", "description": "Optional, so skip this step if the add-on should not record solar production."}, + "4": {"name": "Prices", "description": "What you pay per kWh, so the batteries can charge when power is cheap."}, + "5": {"name": "Peak limit", "description": "The grid stays under this limit, averaged over each 15-minute period."}, + "6": {"name": "Check and start", "description": "The add-on checks everything with its own start checks, then restarts."} + }, + "modes_later": {"description": "Choosing a mode for each battery comes in a later update."}, + "kettle": { + "name": "Check the direction", + "description": "Read the meter, switch on a kettle, then read the meter again.", + "read": "Read the meter", + "again": "Read again", + "skip": "Skip this test", + "before": {"description": "The meter reads {w} now, so switch on a kettle and press Read again."}, + "unread": {"description": "The meter cannot be read now, so check the entity and try again."}, + "none": {"description": "The reading moved only {d}, so switch the kettle on and read again."}, + "ok": {"description": "Good, the reading went up by {d} when the kettle came on."}, + "flip": {"description": "The reading went down by {d}, so the add-on flips its sign for you."}, + "wrong_signed": {"description": "The reading went down by {d}, so choose “One grid power entity” above, which can flip it."}, + "wrong_dsmr": {"description": "The reading went down by {d}, so check that import and export are not swapped."}, + "self": {"description": "The add-on reads this meter itself, so Home shows its direction after the restart."}, + "skipped": {"description": "The meter direction is not tested, so check it on Home after the restart."}, + "tested": {"description": "The meter direction was tested with a kettle."}, + "needed": {"description": "Do the kettle test first, or skip it."} + }, + "check": { + "name": "What the add-on checked", + "running": {"description": "Checking with the add-on's own start checks."}, + "pass": {"description": "The add-on's start checks pass."}, + "failed": {"description": "The check did not run, so try again."}, + "again": "Check again", + "blocked": {"description": "Fix the items marked in red, then check again."} + }, + "shadow": {"name": "Start in shadow mode", "description": "Recommended, because every inverter then stays at 0 W until you turn shadow mode off under Settings."}, + "dialog": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and shadow mode keeps them at 0 W after that.", "yes": "Save and restart"}, + "dialog_live": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and then the new settings apply.", "yes": "Save and restart"}, + "done": {"name": "Setup is done", "description": "The add-on restarts in shadow mode now, so open Home in a minute to see what it would do."}, + "done_live": {"name": "Setup is done", "description": "The add-on restarts now, so open Home in a minute to start control."}, + "restart_failed": {"name": "Saved, not running yet", "description": "The restart did not go through, so press Restart now to apply the settings."}, + "home": "Open Home" } } } diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index b0288e4..4eafd2e 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -234,6 +234,34 @@ GROUPS = ( ), support_only=True), ) +# --------------------------------------------------------------------------- # +# UX-13 P4: the setup wizard. Its fields are the ones with `wizard=` above; this +# is what the table cannot say per field (DECISIONS/UX-13-setup-wizard.md). +# --------------------------------------------------------------------------- # +WIZARD_STEPS = 6 +FINAL_STEP = WIZARD_STEPS # a refusal on no wizard field is shown here +OPTIONAL_STEPS = (3,) # solar: "Next, or skip" + +# Step 1's kettle test. Per meter source Home Assistant reads: the page fields +# read before and after a kettle is switched on, each with the sign it adds to +# the grid reading, and what each direction means as (outcome, fields it +# sets). Sets None: the options cannot fix it, so the step is not passed. A +# source not listed is read by the add-on itself, so the page cannot test it. +KETTLE_SOURCE = "meter_source" +KETTLE_MIN_W = 500.0 # a kettle is 2 000 W, a house wobbles less +KETTLE = { + "off": ((("meter_entity", 1),), + {"up": ("ok", {"meter_invert": False}), + "down": ("flip", {"meter_invert": True})}), + "ha_signed": ((("p1_net_entity", 1),), + {"up": ("ok", {}), "down": ("wrong_signed", None)}), + "ha_dsmr": ((("p1_import_entity", 1), ("p1_export_entity", -1)), + {"up": ("ok", {}), "down": ("wrong_dsmr", None)}), +} +# Step 6 starts the site in shadow mode unless the installer switches it off: +# (field, value when on, value when off). +SHADOW = ("shadow_mode", "on", "auto") + # Option keys the page never shows. uimodel.py writes each from page fields. DERIVED = { "setpoint_entity": "inverters", # one inverter, stored flat diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py index d82c4fa..ce2b269 100644 --- a/goodwe_controller/app/uipage.py +++ b/goodwe_controller/app/uipage.py @@ -17,6 +17,7 @@ import re from . import uilayout as L from . import uimodel as U from .configui import help_of, label_of, problems_by_field, split_group +from .validate import power_request_entities UI_TEXT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text", "en.json") @@ -101,6 +102,7 @@ def _field(fld, schema_ui, translations, lang, T): "help": text, "unit": fld.unit, "scale": fld.scale, "step": fld.step, "kind": fld.kind, "show": [list(c) for c in fld.show], "applies": fld.applies, + "wizard": fld.wizard, "type": value_type, "optional": not node.get("required", False), # A choice mirrored into a field also shows (and finds) its keys. "writes": sorted(k for k, how in L.DERIVED.items() @@ -278,3 +280,78 @@ def fields_of(keys, model) -> list: """The page fields that show these option keys (a stale save's list).""" return list(dict.fromkeys(f for k in keys for f, _c in targets(k, "", model) if f)) + + +# --------------------------------------------------------------------------- # +# UX-13 P4: the setup wizard (DECISIONS/UX-13-setup-wizard.md) +# --------------------------------------------------------------------------- # +# Store keys (app/store.py), not options. SETUP_DONE is written when the +# wizard saves. STARTED is the one control's Start and Stop write. +SETUP_DONE = "setup_done" +STARTED = "auto" + + +def setup_needed(stored: dict, store_data, started) -> str | None: + """Why the page opens the wizard by itself, or None. + + "no_power_request": the stored options name no inverter to control, so + the add-on cannot start on them. "first_start": this /data has never been + through the wizard and control was never started or stopped, which is a + new install: config.yaml ships `auto_start` off, so it comes up stopped. + A site that runs, or ever ran, control is never sent to the wizard. + `store_data` is the Store's dict (None: unknown, so no), `started` is + whether control is started now.""" + if not power_request_entities(stored or {}): + return "no_power_request" + if store_data is None: + return None + if store_data.get(SETUP_DONE) or STARTED in store_data or started: + return None + return "first_start" + + +def setup_spec() -> dict: + """What the wizard needs beyond each field's step: read off the table.""" + kettle = {} + for source, (read, outcomes) in L.KETTLE.items(): + kettle[source] = {"read": [[f, sign] for f, sign in read]} + for way, (say, sets) in outcomes.items(): + kettle[source][way] = {"say": say, "sets": sets} + field, on, off = L.SHADOW + return {"steps": L.WIZARD_STEPS, "final": L.FINAL_STEP, + "optional": list(L.OPTIONAL_STEPS), + "kettle": {"source": L.KETTLE_SOURCE, "min_w": L.KETTLE_MIN_W, + "sources": kettle}, + "shadow": {"field": field, "on": on, "off": off}} + + +def kettle(source, before_w, after_w): + """The kettle test's verdict, as the page reaches it (settings.js + `kettleOutcome`): (outcome, fields it sets or None, change in W), or None + for a source the page cannot read.""" + spec = L.KETTLE.get(source) + if spec is None: + return None + change = float(after_w) - float(before_w) + if abs(change) < L.KETTLE_MIN_W: + return "none", None, change + say, sets = spec[1]["up" if change > 0 else "down"] + return say, (dict(sets) if sets is not None else None), change + + +def step_of(field_key, model) -> int: + """The wizard step a sentence on this page field blocks: the field's own + step while it is shown, else the last step, which lists everything.""" + fld = L.field(field_key) if field_key else None + if fld is None or not fld.wizard or not L.visible(fld, model): + return L.FINAL_STEP + return fld.wizard + + +def step_problems(messages, model) -> dict: + """{"1": n, ...}: how many refusals block each wizard step.""" + out = {str(n): 0 for n in range(1, L.WIZARD_STEPS + 1)} + for m in messages: + if m.get("tier") == "bad": + out[str(step_of(m.get("field"), model))] += 1 + return out diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 5177739..d1ad560 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -374,7 +374,8 @@ class Note(NamedTuple): """UX-13: a warning or info for the settings page. Never a refusal: the add-on starts. `keys` are the options it is about, so the page can show it beside them.""" - tier: str # "warn" or "info" + tier: str # "warn" or "info"; the wizard's checks + # also "ok" and "bad" (setup_checks) keys: tuple text: str @@ -1749,18 +1750,7 @@ def config_notes(opts: dict, *, entities: dict | None = None, """ notes: list[Note] = [] if entities is not None: - for key, where, entity in _entities_read(opts): - row = entities.get(entity) - if row is None: - _advise(notes, "warn", (key,), - f"Home Assistant has no entity {entity}, which " - f"{S(key, where)} names.") - continue - unit = str(row.get("unit") or "") - if key in WATT_ENTITY_KEYS and unit in pv.WATTS_PER and unit != "W": - _advise(notes, "warn", (key,), - f"{entity} reads in {unit}, but {S(key, where)} is " - "taken as watts, so pick a sensor in W.") + _entity_notes(notes, opts, entities) cap = _number(opts, "peak_cap_w", None) if month_peak_w is not None and cap is not None and cap < month_peak_w: _advise(notes, "warn", ("peak_cap_w",), @@ -1769,6 +1759,230 @@ def config_notes(opts: dict, *, entities: dict | None = None, return notes +def _entity_notes(notes, opts: dict, entities: dict, bad=()) -> None: + """A note for each entity these options read that Home Assistant does not + have, or that reads in kW where watts are taken. A missing entity whose + key is in `bad` is a "bad" note, which blocks the setup wizard.""" + for key, where, entity in _entities_read(opts): + row = entities.get(entity) + if row is None: + _advise(notes, "bad" if key in bad else "warn", (key,), + f"Home Assistant has no entity {entity}, which " + f"{S(key, where)} names.") + continue + unit = str(row.get("unit") or "") + if key in WATT_ENTITY_KEYS and unit in pv.WATTS_PER and unit != "W": + _advise(notes, "warn", (key,), + f"{entity} reads in {unit}, but {S(key, where)} is " + "taken as watts, so pick a sensor in W.") + + +# --------------------------------------------------------------------------- # +# UX-13 P4: the setup wizard's last step +# --------------------------------------------------------------------------- # +# Below this a battery or solar reading counts as idle for a sign check. +IDLE_W = 50.0 +# The keys that pick the meter. A meter the add-on reads itself (HomeWizard, +# MQTT) is only known live when the running options read the same one. +_METER_KEYS = ("meter_source", "p1_host", "meter_mqtt_topic") + + +def power_request_entities(opts: dict) -> list: + """The power request entity of each inverter these options name: the flat + one, or each entry's. Blank ones are left out.""" + entries = roster_entries(opts) + if not entries: + values = [opts.get("setpoint_entity")] + else: + values = [e.get("setpoint_entity") for e in entries + if isinstance(e, dict)] + return [str(v).strip() for v in values + if isinstance(v, str) and v.strip()] + + +def _reading(entities, entity, convert=False): + """(number, unit) of an entity's state, or (None, state text). The number + is as the add-on reads it: raw for the meter and battery power, which it + takes as watts, and in W for solar (`convert`), which pv.py converts.""" + row = (entities or {}).get(entity) or {} + unit = str(row.get("unit") or "") + try: + value = float(row.get("state")) + except (TypeError, ValueError): + return None, str(row.get("state") or "nothing") + if value != value or value in (float("inf"), float("-inf")): + return None, str(row.get("state")) + return value * (pv.WATTS_PER.get(unit, 1.0) if convert else 1.0), unit + + +def _signed(w) -> str: + return ("-" if w < 0 else "") + messages.watts(w) + + +def _cards(opts: dict) -> list: + """(who, entry) per inverter: who is " for " in a list, else "".""" + entries = roster_entries(opts) + if not entries: + return [("", {k: opts.get(k) for k in ( + "setpoint_entity", "soc_entity", "batt_entity", "batt_invert")})] + out = [] + for i, entry in enumerate(entries): + if isinstance(entry, dict): + name = _unit_label(opts, i).strip().strip("()") + out.append((f" for {name}" if name else "", entry)) + return out + + +def setup_checks(opts: dict, *, entities: dict | None, running=None, + meter_now_w=None, prices_known=None) -> list[Note]: + """UX-13 P4: what the setup wizard's last step shows, beside the refusals. + + Live checks on the proposed options: the meter reads, each power request + entity exists in Home Assistant (a write to a missing one is answered 200, + SAFETY-77, so only the entity list can tell), the battery levels read, and + prices are known. Tier "ok", "info", "warn", or "bad" for a missing power + request entity, which the wizard will not save. Reads nothing itself: + `entities` is Home Assistant's list by id (None when it did not answer), + `running` the options this process started with, `meter_now_w` its meter + reading and `prices_known` how many of today's hours have a price. + """ + notes: list[Note] = [] + if entities is None: + _advise(notes, "warn", (), "Home Assistant is not answering, so " + "no entity was checked yet.") + else: + _entity_notes(notes, opts, entities, bad=("setpoint_entity",)) + _meter_check(notes, opts, entities, running, meter_now_w) + for who, entry in _cards(opts): + _card_checks(notes, who, entry, entities) + if entities is not None: + flipped = pv.inverted(opts) + for entity in pv.entities(opts): + w, _unit = _reading(entities, entity, convert=True) + if entity not in entities or w is None: + continue + if w < -IDLE_W and entity not in flipped: + _advise(notes, "warn", ("pv_invert_entities",), + f"{entity} reads below zero now, so its solar " + "production sign looks reversed.") + else: + w = -w if entity in flipped else w + _advise(notes, "ok", ("pv_entity",), + f"{entity} reads {_signed(w)} of solar production " + "now.") + _price_check(notes, opts, running, prices_known) + return notes + + +def _meter_check(notes, opts, entities, running, meter_now_w) -> None: + source = str(opts.get("meter_source") or "off").strip() + if source == "off": + parts = [(opts.get("meter_entity"), 1.0)] + elif source == SOURCE_HA_SIGNED: + parts = [(opts.get("p1_net_entity"), 1.0)] + elif source == SOURCE_HA: + parts = [(opts.get("p1_import_entity"), 1.0), + (opts.get("p1_export_entity"), -1.0)] + else: + same = isinstance(running, dict) and all( + running.get(k) == opts.get(k) for k in _METER_KEYS) + if same and meter_now_w is not None: + _meter_line(notes, float(meter_now_w)) + else: + _advise(notes, "info", ("meter_source",), "The add-on reads " + "this meter itself, so Home shows its reading after " + "the restart.") + return + if entities is None: + return + total = 0.0 + for entity, sign in parts: + entity = str(entity or "").strip() + if not entity or entity not in entities: + return # a refusal or a missing-entity note says so + w, text = _reading(entities, entity) + if w is None: + _advise(notes, "warn", ("meter_source",), + f"{entity} reads {text} now, so the meter has no " + "reading yet.") + return + total += sign * w + if source == "off" and opts.get("meter_invert"): + total = -total + _meter_line(notes, total) + + +def _meter_line(notes, w) -> None: + if abs(w) < 1.0: + text = "The meter reads 0 W now." + elif w > 0: + text = f"The meter reads {messages.watts(w)} taken from the grid now." + else: + text = f"The meter reads {messages.watts(w)} fed into the grid now." + _advise(notes, "ok", ("meter_source",), text) + + +def _card_checks(notes, who, entry, entities) -> None: + if entities is None: + return + setpoint = str(entry.get("setpoint_entity") or "").strip() + if setpoint and setpoint in entities: + _advise(notes, "ok", ("setpoint_entity",), + f"Home Assistant has {setpoint}, the power request " + f"entity{who}.") + soc = str(entry.get("soc_entity") or "").strip() + if not soc: + _advise(notes, "warn", ("soc_entity",), f"There is no battery " + f"level entity{who}, so the add-on holds 0 W.") + elif soc in entities: + level, _unit = _reading(entities, soc) + if level is None or not 0.0 <= level <= 100.0: + _advise(notes, "warn", ("soc_entity",), f"The battery " + f"level{who} reads nothing now, so check {soc}.") + else: + _advise(notes, "ok", ("soc_entity",), + f"The battery level{who} reads {level:.0f} %.") + batt = str(entry.get("batt_entity") or "").strip() + if batt and batt in entities: + w, _unit = _reading(entities, batt) + if w is None: + _advise(notes, "warn", ("batt_entity",), f"The battery " + f"power{who} reads nothing now, so check {batt}.") + return + w = -w if entry.get("batt_invert") else w + if abs(w) < IDLE_W: + _advise(notes, "info", ("batt_entity",), f"The battery{who} is " + "idle now, so check its direction on Home later.") + else: + doing = "giving power" if w > 0 else "charging" + _advise(notes, "info", ("batt_invert",), + f"The battery{who} reads {messages.watts(w)} {doing} " + "now, so check the inverter shows the same.") + + +def _price_check(notes, opts, running, prices_known) -> None: + provider = str(opts.get("price_provider") or "off").strip() + profile = str(opts.get("static_profile") or "").strip() + if provider in ("", "off"): + if profile: + _advise(notes, "ok", ("static_profile",), + "Your prices come from your contract, so they are " + "always known.") + else: + _advise(notes, "info", ("price_provider",), + "No prices are set, so the batteries do not charge " + "on price.") + return + same = (isinstance(running, dict) + and str(running.get("price_provider") or "") == provider) + if same and prices_known: + _advise(notes, "ok", ("price_provider",), + f"Prices for today are in, for {prices_known} of 24 hours.") + else: + _advise(notes, "info", ("price_provider",), + "Prices are fetched after the restart, and Home shows them.") + + def _number(opts: dict, key, default): raw = opts.get(key, default) if raw is None or raw == "": diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index e599ce0..f294a99 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -28,19 +28,23 @@ do to the inverter through this panel is exactly what `/action` offered before this card - test_selfconfig.py part 7 asserts that by listing the routes and the actions and comparing them with the shipped set. UX-13's `ha/entities` is a GET of Home Assistant's entity list (app/haentities.py) and writes nothing. +UX-13 P4's setup wizard uses the same routes. The one thing it adds that is +not options is a Store key, `setup_done`, written when the wizard's save +succeeds, so the page stops opening the wizard by itself (uipage.setup_needed). """ import io import json import logging import os +from datetime import datetime, timezone from aiohttp import web from . import messages, selfconfig, uipage from .haentities import EntityCache from .homeview import region_of -from .validate import config_notes +from .validate import config_notes, setup_checks from .config_page import CONFIG_PAGE from .configui import changed_keys, field_model, problems_by_field from .uimodel import DeriveError, options_to_ui @@ -103,6 +107,22 @@ def build_app(controller, selfcfg=None) -> web.Application: controller.hass.token) entities = EntityCache(controller.hass) index_page = page() + # UX-13 P4: the blobs /config/model handed out, by fingerprint, so a stale + # save can name only the keys that moved underneath the page (finding a). + handed: dict = {} + + def hand_out(options): + fp = selfconfig.fingerprint(options) + handed.pop(fp, None) + handed[fp] = options + while len(handed) > 16: + handed.pop(next(iter(handed))) + return fp + + def store_data(): + store = getattr(controller, "store", None) + data = getattr(store, "data", None) + return data if isinstance(data, dict) else None async def index(_request): return web.Response(text=index_page, content_type="text/html") @@ -165,7 +185,7 @@ def build_app(controller, selfcfg=None) -> web.Application: info.get("translations") or {}, lang) model.update({ "options": options, - "fingerprint": selfconfig.fingerprint(options), + "fingerprint": hand_out(options), "running": controller.o, "running_differs": changed_keys(controller.o, options), "lang": lang, @@ -176,6 +196,10 @@ def build_app(controller, selfcfg=None) -> web.Application: "layout": uipage.layout(info.get("schema") or [], info.get("translations") or {}, lang), "ui": options_to_ui(options), + # UX-13 P4: the setup wizard, and why it opens by itself. + "setup": uipage.setup_spec(), + "setup_needed": uipage.setup_needed( + options, store_data(), bool(getattr(controller, "auto", False))), }) return web.json_response(model) @@ -213,8 +237,27 @@ def build_app(controller, selfcfg=None) -> web.Application: if model is not None: payload["messages"] = uipage.anchors(problems, notes, model, _keys_of(options)) + payload["steps"] = uipage.step_problems(payload["messages"], model) + if _body.get("setup"): + payload["setup"] = [n._asdict() for n in await _setup_checks(options)] return web.json_response(payload) + async def _setup_checks(options): + """The wizard's live checks: a list at most a few seconds old, and + what the running add-on already knows (its meter, today's prices).""" + rows, age = await entities.get(max_age=5.0) + if age is not None and age >= 30.0: + rows = None # Home Assistant is not answering + try: + prices = (controller.status_payload().get("plan") or {}).get( + "prices") or [] + known = sum(1 for p in prices if p.get("eur_kwh") is not None) + except Exception: # noqa: BLE001 - a display figure, never a failure + known = None + return setup_checks(options, entities=rows, running=controller.o, + meter_now_w=getattr(controller, "grid", None), + prices_known=known) + def _keys_of(options): # ⚠️ THE ANCHOR LIST IS THE KEYS OF THE BLOB UNDER TEST, and that is # sound only because the page posts the WHOLE blob it read - which is @@ -249,21 +292,26 @@ def build_app(controller, selfcfg=None) -> web.Application: expect = str(body.get("fingerprint") or "") try: result = await selfconfig.save(selfcfg, options, expect, - hass=controller.hass) + hass=controller.hass, + base=handed.get(expect)) except selfconfig.SaveRefused as refused: if refused.kind == "stale": stored = refused.stored or {} + # The fields to look at are the ones the OTHER surface moved, + # not this page's own edits (UX-13 P2 test, finding a). + moved = (refused.changed if refused.moved is None + else refused.moved) return web.json_response( {"kind": "stale", "changed": refused.changed, - "changed_fields": (uipage.fields_of(refused.changed, - model) + "moved": refused.moved, + "changed_fields": (uipage.fields_of(moved, model) if model is not None else []), "stored": stored, # The page needs the CURRENT token to be able to save # again after the operator has read the difference. That # is not a force door: it takes a second, deliberate press # made in front of what changed. - "fingerprint": selfconfig.fingerprint(stored)}, + "fingerprint": hand_out(stored)}, status=409) by_key, unanchored = problems_by_field(refused.problems, _keys_of(options)) @@ -272,6 +320,8 @@ def build_app(controller, selfcfg=None) -> web.Application: if model is not None: payload["messages"] = uipage.anchors(refused.problems, [], model, _keys_of(options)) + payload["steps"] = uipage.step_problems(payload["messages"], + model) return web.json_response(payload, status=422) except selfconfig.SupervisorUnavailable as err: _LOG.error("saving options failed: %s", err) @@ -279,6 +329,12 @@ def build_app(controller, selfcfg=None) -> web.Application: controller.log_event("configuration saved from the panel - " "not applied until the add-on restarts", hint=messages.hint("settings_saved")) + # `handed` keeps `expect`: another page may have opened the same blob. + store = getattr(controller, "store", None) + if (model is not None and body.get("setup") == "done" + and store is not None): + store.set(uipage.SETUP_DONE, + datetime.now(timezone.utc).isoformat(timespec="seconds")) return web.json_response({"ok": True, **result}) async def config_restart(request): @@ -310,6 +366,10 @@ def build_app(controller, selfcfg=None) -> web.Application: """UX-13: Home Assistant's entities for the picker. A read only, and never an error: when Home Assistant is down the list says so.""" kind = str(request.query.get("kind", "") or "")[:16] + one = str(request.query.get("entity", "") or "")[:255] + if one: + # UX-13 P4's kettle test: one entity, read now. + return web.json_response(await entities.reading(one)) return web.json_response(await entities.payload(kind)) app = web.Application() diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index f75653d..fe882ca 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -920,7 +920,7 @@ DATA = { "price_history.py:messages.count(len(points), 'price')", "price_history.py:err", "selfconfig.py:messages.count(len(problems), 'problem')", - "selfconfig.py:', '.join(changed) or 'none this page also edited'", + "selfconfig.py:', '.join(keys) or 'none this page also edited'", "static_tariff.py:e", "store.py:err", "store.py:key", "store.py:raw", "tariff.py:self.path", "tariff.py:err", "tariff.py:start", "tariff.py:month", # validate.py: option values and keys (the refusals are part 3's) diff --git a/goodwe_controller/test_settings.py b/goodwe_controller/test_settings.py index 5df6a2f..0df8da0 100644 --- a/goodwe_controller/test_settings.py +++ b/goodwe_controller/test_settings.py @@ -429,9 +429,11 @@ async def _stale(s, root, sup): _r, _sup = asyncio.run(session(TWO, _stale)) -check("409 with the page fields to look at, and nothing written", +check("409 with the page fields to look at, and nothing written. Only the " + "field the other surface changed, not the page's own edit (P4, P2 " + "test finding a)", _r[0] == 409 and _r[1]["kind"] == "stale" - and "peak_cap_w" in _r[1]["changed_fields"] and _sup.writes == [] + and _r[1]["changed_fields"] == ["peak_cap_w"] and _sup.writes == [] and _r[1]["fingerprint"] == selfconfig.fingerprint(_sup.options)) # --------------------------------------------------------------------------- # diff --git a/goodwe_controller/test_setup.py b/goodwe_controller/test_setup.py new file mode 100644 index 0000000..9c08004 --- /dev/null +++ b/goodwe_controller/test_setup.py @@ -0,0 +1,694 @@ +"""UX-13 P4: the setup wizard. `python3 test_setup.py` + +The wizard is the Installer view's page model drawn one step at a time from +each field's `wizard` step (app/uilayout.py), saved through the same routes. +Part 1 checks the steps and the tables the page reads. Part 2 the kettle +test's sign logic. Part 3 which refusals block which step. Part 4 the +first-run rule on new and existing sites. Part 5 the last step's live checks. +Part 6 the save through the P2 path, and every blob the wizard can produce +(tools/ux13_wizard_blobs.py; the Supervisor's own validator runs over the same +set in the PR, not in CI, which has no Supervisor image). Part 7 the stale +save names only what changed elsewhere (P2 test, finding a). Part 8 the +words. The headless-browser click-through is in the PR. +Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). +""" + +import asyncio +import copy +import io +import json +import logging +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) # the validator's own log lines + +from aiohttp import ClientSession, web as aioweb # noqa: E402 + +import translations_lint as TL # noqa: E402 +import ux13_demo as D # noqa: E402 +import ux13_wizard_blobs as B # noqa: E402 +from app import uilayout as L, uimodel as U, uipage, web # noqa: E402 +from app.validate import setup_checks, validate_startup_config # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +SCHEMA = D.schema_ui(D.CONFIG) +TRANSLATIONS = {"en": TL.parse_translation_file( + os.path.join(HERE, "translations", "en.yaml"))} +DEFAULTS = D.defaults(D.CONFIG) +NEW = dict(DEFAULTS, setpoint_entity="number.inv1_power") +UI_TEXT = uipage.ui_text() +WS = UI_TEXT["settings"]["setup"] +JS = io.open(os.path.join(HERE, "app", "static", "settings.js"), + encoding="utf-8").read() + +# --------------------------------------------------------------------------- # +print("1. six steps, drawn from the layout table") +# --------------------------------------------------------------------------- # +LAYOUT = uipage.layout(SCHEMA, TRANSLATIONS) +TOP = [f for g in LAYOUT["groups"] for p in g["parts"] for f in p["fields"]] +BY_STEP = {n: [f["key"] for f in TOP if f["wizard"] == n] + for n in range(1, L.WIZARD_STEPS + 1)} +print(f" {BY_STEP}") +check("every field reaches the page with its wizard step", + all("wizard" in f for f in TOP) + and all(s["wizard"] == 2 for f in TOP for s in f.get("fields", []))) +check("the mockup's six steps: meter, inverters, solar, prices, peak limit, " + "check and start", + BY_STEP[1][0] == "meter_source" and BY_STEP[2] == ["inverters"] + and BY_STEP[3] == ["ui.solar"] and BY_STEP[4][0] == "ui.contract" + and BY_STEP[5] == ["peak_cap_w", "peak_forecast_entity"] + and BY_STEP[6] == [L.SHADOW[0]] + and [WS["steps"][str(n)]["name"] for n in range(1, 7)] + == ["Your meter", "Inverters and batteries", "Solar", "Prices", + "Peak limit", "Check and start"]) +check("battery modes are not a step yet (OPT-11): step 5 says they come later", + "later update" in WS["modes_later"]["description"] + and not any("mode" in k for k in BY_STEP[5])) +SPEC = uipage.setup_spec() +check("the spec the page reads is the table's", + SPEC["steps"] == 6 and SPEC["final"] == 6 and SPEC["optional"] == [3] + and SPEC["kettle"]["min_w"] == L.KETTLE_MIN_W + and set(SPEC["kettle"]["sources"]) == set(L.KETTLE) + and SPEC["shadow"] == {"field": "shadow_mode", "on": "on", + "off": "auto"}) +_src = L.field(L.KETTLE_SOURCE) +_choices = {c[0] for f in TOP if f["key"] == L.KETTLE_SOURCE + for c in f["choices"]} +_bad = [] +for source, (read, outcomes) in L.KETTLE.items(): + model = {L.KETTLE_SOURCE: source} + for key, _sign in read: + fld = L.field(key) + if not (fld and fld.wizard == 1 and fld.control == L.ENTITY + and L.visible(fld, model)): + _bad.append(key) + for _say, sets in outcomes.values(): + for key in (sets or {}): + fld = L.field(key) + if not (fld and fld.wizard == 1 and L.visible(fld, model)): + _bad.append(key) +check(f"each kettle source is a meter choice, and reads and sets only step-1 " + f"fields shown for it ({_bad})", + set(L.KETTLE) <= _choices and not _bad and _src.wizard == 1) +_shadow = next((f for f in TOP if f["key"] == L.SHADOW[0]), {}) +check("the shadow switch writes two of shadow mode's own choices", + {L.SHADOW[1], L.SHADOW[2]} <= {c[0] for c in _shadow.get("choices", [])}) + +# --------------------------------------------------------------------------- # +print("\n2. the kettle test's sign logic") +# --------------------------------------------------------------------------- # +K = uipage.kettle +check("one grid entity: up keeps the sign, down flips it", + K("off", -10, 1990) == ("ok", {"meter_invert": False}, 2000) + and K("off", 400, -1600) == ("flip", {"meter_invert": True}, -2000)) +check("the direction is the change, not the sign: exporting 3 kW, a kettle " + "still moves the reading up", + K("off", -3000, -1000)[0] == "ok" and K("off", 3000, 1000)[0] == "flip") +check(f"a change under {L.KETTLE_MIN_W:.0f} W sets nothing and is not passed", + K("off", 0, 499)[:2] == ("none", None) + and K("off", 0, -499)[:2] == ("none", None) + and K("off", 0, 500)[0] == "ok") +check("a net entity that goes down cannot be fixed by an option, so the step " + "is not passed", + K("ha_signed", 0, 2000) == ("ok", {}, 2000) + and K("ha_signed", 0, -2000)[:2] == ("wrong_signed", None)) +check("import and export are read as their difference", + L.KETTLE["ha_dsmr"][0] == (("p1_import_entity", 1), + ("p1_export_entity", -1)) + and K("ha_dsmr", -3000, -1000)[0] == "ok" + and K("ha_dsmr", 0, -2000)[0] == "wrong_dsmr") +check("a meter the add-on reads itself has no kettle test on the page", + K("homewizard_local", 0, 2000) is None and K("mqtt_p1", 0, 2000) is None) +_js = re.search(r"function kettleOutcome\(src, before, after\) \{(.*?)\n \}", + JS, re.S) +check("the page reaches the same verdict: settings.js kettleOutcome() is " + "uipage.kettle() line for line", + _js and "const d = after - before;" in _js.group(1) + and "Math.abs(d) < M.setup.kettle.min_w" in _js.group(1) + and 'src[d > 0 ? "up" : "down"]' in _js.group(1)) +check("...and it applies what the verdict sets, and passes the step only on " + "a verdict that sets something", + "if (o.sets) { Object.assign(V, o.sets); queueValidate(); }" in JS + and "ok: o.sets != null" in JS) +check("a changed meter or entity forgets the result, so the test runs again", + "if (WZ.kettle && WZ.kettle.sig !== sig) WZ.kettle = null;" in JS) +check("each verdict has words", all(say in WS["kettle"] for _r, o in + L.KETTLE.values() + for say, _s in o.values()) + and {"none", "unread", "skipped", "self"} <= set(WS["kettle"])) + +# --------------------------------------------------------------------------- # +print("\n3. which refusals block which step") +# --------------------------------------------------------------------------- # +_m = U.options_to_ui(dict(NEW, meter_source="ha_signed")) +_msgs = [{"field": "p1_net_entity", "card": None, "tier": "bad", "text": "a"}, + {"field": "meter_entity", "card": None, "tier": "bad", "text": "b"}, + {"field": "inverters.setpoint_entity", "card": 0, "tier": "bad", + "text": "c"}, + {"field": "maintenance_charge_w", "card": None, "tier": "bad", + "text": "d"}, + {"field": None, "card": None, "tier": "bad", "text": "e"}, + {"field": "peak_cap_w", "card": None, "tier": "warn", "text": "f"}] +check("a refusal blocks the step of its field, a hidden or non-wizard field's " + "and an unplaced one the last step, and a warning blocks nothing", + uipage.step_problems(_msgs, _m) + == {"1": 1, "2": 1, "3": 0, "4": 0, "5": 0, "6": 3}) + + +class Store: + """app/store.py's shape: a dict under .data, and set().""" + + def __init__(self, data=None): + self.data = dict(data or {}) + + def set(self, key, value): + self.data[key] = value + + +def state(eid, value, unit="W", cls=None): + return {"entity_id": eid, "state": value, + "attributes": {"friendly_name": eid, "unit_of_measurement": unit, + "device_class": cls}} + + +class Hass: + session = None + token = "" + + def __init__(self, states): + self.states_now = states + self.reads = [] + + async def limits(self, _e): + return (-5000.0, 5000.0, 1.0) + + async def states(self): + return copy.deepcopy(self.states_now) + + async def state(self, entity): + self.reads.append(entity) + return next((copy.deepcopy(s) for s in self.states_now + if s["entity_id"] == entity), None) + + +class Supervisor: + def __init__(self, options): + self.options = copy.deepcopy(options) + self.writes = [] + self.restarts = 0 + + async def info(self): + return {"options": copy.deepcopy(self.options), "schema": SCHEMA, + "translations": TRANSLATIONS} + + async def write_options(self, options): + self.writes.append(copy.deepcopy(options)) + self.options = copy.deepcopy(options) + + async def restart(self, confirm): + self.restarts += 1 + + +class Controller: + def __init__(self, opts, states, store=None, auto=False, grid=None): + self.o, self.hass, self.inverters = dict(opts), Hass(states), [] + self.store, self.auto, self.grid = store, auto, grid + + def log_event(self, text, hint=None): + pass + + def status_payload(self): + return {"banner": "", "level": "ok", "rows": [], "checks": [], + "plan": {"prices": [{"eur_kwh": 0.2}] * 20 + + [{"eur_kwh": None}] * 4}} + + async def handle_action(self, what): + raise AssertionError(f"the wizard reached {what!r}") + + +async def session(ctl, stored, steps): + sup = Supervisor(stored) + runner = aioweb.AppRunner(web.build_app(ctl, sup)) + await runner.setup() + site = aioweb.TCPSite(runner, "127.0.0.1", 0) + await site.start() + root = f"http://127.0.0.1:{site._server.sockets[0].getsockname()[1]}/" + try: + async with ClientSession() as s: + out = await steps(s, root, sup) + finally: + await runner.cleanup() + return out, sup + + +async def _get(s, url): + async with s.get(url) as r: + return await r.json() + + +async def _post(s, url, body): + async with s.post(url, json=body) as r: + return r.status, await r.json() + + +STATES = [state("sensor.grid", "402"), state("number.inv1_power", "0"), + state("sensor.inv1_level", "62", "%", "battery"), + state("sensor.inv1_battery", "-800"), + state("sensor.pv", "-1200", "W", "power"), + state("sensor.net", "-3.1", "kW", "power")] + + +async def _steps(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + model = copy.deepcopy(m["ui"]) + model["inverters"][0]["setpoint_entity"] = "" + return (await _post(s, root + "config/validate", {"model": model}))[1] + + +_r, _sup = asyncio.run(session(Controller(NEW, STATES), NEW, _steps)) +print(f" blank power request entity: steps {_r['steps']}") +check("over HTTP, a blank power request entity blocks step 2 and no other", + _r["steps"]["2"] >= 1 + and all(v == 0 for k, v in _r["steps"].items() if k != "2")) +check("the page moves on only when the step's count is 0, the kettle test is " + "done on step 1, and the last step saves only with nothing red", + "if ((STEPS[n] || 0) > 0) { toast(W.toast.blocked.description); " + "firstBad(); return; }" in JS + and "if (n === 1 && !kettleOk())" in JS + and "if (WZ.blocked) { toast(WS.check.blocked.description); return; }" + in JS) + +# --------------------------------------------------------------------------- # +print("\n4. first run: a new install opens the wizard, a working site not") +# --------------------------------------------------------------------------- # +S = uipage.setup_needed +check("a new install: never set up, control never started or stopped", + S(NEW, {}, False) == "first_start" + and S(NEW, {"phase": "idle", "sign_tripped": False}, False) + == "first_start") +check("a site that runs control, or ever ran or stopped it, is not sent to " + "the wizard", S(NEW, {}, True) is None + and S(NEW, {"auto": True}, False) is None + and S(NEW, {"auto": False}, False) is None) +check("a site the wizard saved is not sent again", + S(NEW, {uipage.SETUP_DONE: "2026-09-28T10:00:00+00:00"}, False) is None) +check("stored options with no inverter to control always open it, whatever " + "the Store says", + S(DEFAULTS, {uipage.SETUP_DONE: "x", "auto": True}, True) + == "no_power_request" + and S(dict(DEFAULTS, inverters=[{"name": "a", "setpoint_entity": " "}]), + None, True) == "no_power_request") +check("a list roster with a power request entity is set up", + S(dict(DEFAULTS, inverters=[{"name": "a", "setpoint_entity": "number.a"}]), + {"auto": True}, True) is None) +check("without a Store the answer is no (never nag on a guess)", + S(NEW, None, False) is None) +_sites = [(n, dict(DEFAULTS, **json.load(open(os.path.join( + HERE, "scenarios", "ux13", "test23", n))))) for n in sorted(os.listdir( + os.path.join(HERE, "scenarios", "ux13", "test23")))] +_starting = [(n, o) for n, o in _sites if not validate_startup_config(o)] +check(f"the TEST-23 sites that start, and run control, are not sent to the " + f"wizard ({[n for n, _o in _starting]})", len(_starting) >= 3 + and all(S(o, {"auto": True, "phase": "idle"}, True) is None + for _n, o in _starting)) +check("...and the one that cannot start (no power request entity) is", + [S(o, {"auto": True}, True) for n, o in _sites + if (n, o) not in _starting] == ["no_power_request"]) + + +async def _first(s, root, sup): + out = {"model": await _get(s, root + "config/model?lang=en")} + m = out["model"] + model = copy.deepcopy(m["ui"]) + model["peak_cap_w"] = 4000 + out["plain"] = await _post(s, root + "config/save", { + "model": model, "fingerprint": m["fingerprint"]}) + out["store_plain"] = dict(_store.data) + out["after_plain"] = await _get(s, root + "config/model?lang=en") + m = out["after_plain"] + model = copy.deepcopy(m["ui"]) + out["wizard"] = await _post(s, root + "config/save", { + "model": model, "fingerprint": m["fingerprint"], "setup": "done"}) + out["after"] = await _get(s, root + "config/model?lang=en") + return out + + +_store = Store({"phase": "idle"}) +_r, _sup = asyncio.run(session(Controller(NEW, STATES, _store), NEW, _first)) +check("over HTTP, /config/model says a new install needs setup, with the spec", + _r["model"]["setup_needed"] == "first_start" + and _r["model"]["setup"] == json.loads(json.dumps(SPEC))) +check("a save from the Installer view does not count as setup", + _r["plain"][0] == 200 and _r["after_plain"]["setup_needed"] + == "first_start" and uipage.SETUP_DONE not in _r["store_plain"]) +check("the wizard's save writes the Store marker, and the wizard stops " + "opening by itself", + _r["wizard"][0] == 200 and _store.data.get(uipage.SETUP_DONE) + and _r["after"]["setup_needed"] is None) +_r, _sup = asyncio.run(session(Controller(NEW, STATES, Store({"auto": True}), + auto=True), NEW, _first)) +check("a working site's /config/model says no", _r["model"]["setup_needed"] + is None) +check("the page goes to Setup by itself only when opened with no route and " + "only while still on Home", + "first: !location.hash" in io.open(os.path.join( + HERE, "app", "static", "app.js"), encoding="utf-8").read() + and 'if (M && M.setup_needed && location.hash === "#home") ' + 'location.hash = "#setup";' in JS) + +# --------------------------------------------------------------------------- # +print("\n5. the last step's live checks") +# --------------------------------------------------------------------------- # +ROWS = {s["entity_id"]: {"entity_id": s["entity_id"], "state": s["state"], + "unit": s["attributes"]["unit_of_measurement"]} + for s in STATES} +SITE = dict(NEW, meter_entity="sensor.grid", soc_entity="sensor.inv1_level", + batt_entity="sensor.inv1_battery", pv_entity="sensor.pv") + + +def tiers(notes): + return [(n.tier, n.text) for n in notes] + + +_c = tiers(setup_checks(SITE, entities=ROWS)) +for t in _c: + print(f" {t}") +check("the meter reads, as the add-on will see it", + ("ok", "The meter reads 402 W taken from the grid now.") in _c) +check("with the sign flipped, the same reading is fed in", + ("ok", "The meter reads 402 W fed into the grid now.") in tiers( + setup_checks(dict(SITE, meter_invert=True), entities=ROWS))) +check("the power request entity exists in Home Assistant (a write cannot " + "tell: SAFETY-77)", + ("ok", "Home Assistant has number.inv1_power, the power request " + "entity.") in _c) +check("the battery level reads, and the battery power with its direction", + ("ok", "The battery level reads 62 %.") in _c + and ("info", "The battery reads 800 W charging now, so check the " + "inverter shows the same.") in _c) +check("a solar entity below zero, not flipped, looks reversed", + ("warn", "sensor.pv reads below zero now, so its solar production " + "sign looks reversed.") in _c + and ("ok", "sensor.pv reads 1 200 W of solar production now.") + in tiers(setup_checks(dict(SITE, pv_invert_entities=["sensor.pv"]), + entities=ROWS))) +_miss = tiers(setup_checks(dict(SITE, setpoint_entity="number.typo"), + entities=ROWS)) +check("a power request entity Home Assistant does not have is red, so the " + "wizard does not save", + ("bad", "Home Assistant has no entity number.typo, which “Inverter " + "setpoint entity” (setpoint_entity) names.") in _miss) +check("a missing battery level entity is a warning, not red (the add-on " + "holds 0 W and says so)", + [t for t, x in tiers(setup_checks(dict(SITE, soc_entity="sensor.x"), + entities=ROWS)) + if "sensor.x" in x] == ["warn"]) +_two = dict(DEFAULTS, meter_source="ha_signed", p1_net_entity="sensor.net", + inverters=[{"name": "a", "setpoint_entity": "number.inv1_power", + "soc_entity": "sensor.inv1_level", "max_w": 2000, + "bms_soc_floor": 10}, + {"name": "b", "setpoint_entity": "number.b", + "max_w": 2000, "bms_soc_floor": 10}]) +_c2 = tiers(setup_checks(_two, entities=ROWS)) +check("with two inverters each is named, and a kW meter is shown as the " + "add-on reads it, beside the warning to pick a sensor in W", + ("ok", "The meter reads 3 W fed into the grid now.") in _c2 + and [t for t, x in _c2 if "reads in kW" in x] == ["warn"] + and ("bad", "Home Assistant has no entity number.b, which “Inverter " + "setpoint entity” for b (inverters.setpoint_entity) names.") + in _c2 + and ("ok", "The battery level for a reads 62 %.") in _c2 + and ("warn", "There is no battery level entity for b, so the add-on " + "holds 0 W.") in _c2) +_dsmr = dict(SITE, meter_source="ha_dsmr", p1_import_entity="sensor.grid", + p1_export_entity="sensor.inv1_level") +check("import and export are read as their difference", + ("ok", "The meter reads 340 W taken from the grid now.") + in tiers(setup_checks(dict(_dsmr), entities=dict( + ROWS, **{"sensor.inv1_level": {"state": "62", "unit": "W"}})))) +_hw = dict(SITE, meter_source="homewizard_local", p1_host="192.0.2.5") +check("a meter the add-on reads itself: its live reading when it already " + "runs on it, else a note that Home shows it after the restart", + ("ok", "The meter reads 250 W taken from the grid now.") in tiers( + setup_checks(_hw, entities=ROWS, running=_hw, meter_now_w=250)) + and [t for t, x in tiers(setup_checks(_hw, entities=ROWS, running=SITE, + meter_now_w=250)) + if "meter" in x] == ["info"]) +check("an unreadable meter is a warning", + ("warn", "sensor.grid reads unavailable now, so the meter has no " + "reading yet.") in tiers(setup_checks(SITE, entities=dict( + ROWS, **{"sensor.grid": {"state": "unavailable", + "unit": "W"}})))) +_down = tiers(setup_checks(SITE, entities=None)) +check("Home Assistant down: one warning, nothing claimed ok about an entity", + _down[0] == ("warn", "Home Assistant is not answering, so no entity " + "was checked yet.") + and not [x for t, x in _down if t in ("ok", "bad") and "entity" in x]) +_fixed = U.ui_to_options(dict(U.options_to_ui(SITE), **{ + "ui.contract": "fixed", "ui.fallback": "fixed", "ui.fixed_price": 0.3})) +_dyn = dict(SITE, price_provider="generic_dayahead") +check("prices: known from a contract; for a feed, today's count when it " + "already runs, else after the restart; none when none is set", + ("ok", "Your prices come from your contract, so they are always known.") + in tiers(setup_checks(_fixed, entities=ROWS)) + and ("ok", "Prices for today are in, for 20 of 24 hours.") + in tiers(setup_checks(_dyn, entities=ROWS, running=_dyn, + prices_known=20)) + and ("info", "Prices are fetched after the restart, and Home shows " + "them.") in tiers(setup_checks(_dyn, entities=ROWS, + running=SITE, + prices_known=20)) + and ("info", "No prices are set, so the batteries do not charge on " + "price.") in _c) + + +async def _final(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + model = copy.deepcopy(m["ui"]) + model["inverters"][0]["setpoint_entity"] = "number.typo" + out = {"ok": (await _post(s, root + "config/validate", + {"model": m["ui"], "setup": True}))[1], + "typo": (await _post(s, root + "config/validate", + {"model": model, "setup": True}))[1], + "plain": (await _post(s, root + "config/validate", + {"model": m["ui"]}))[1]} + return out + + +_r, _sup = asyncio.run(session(Controller(SITE, STATES, Store(), grid=402.0), + SITE, _final)) +check("over HTTP, the last step gets the checks beside the refusals, read " + "from a fresh entity list", + [x["tier"] for x in _r["ok"]["setup"] if "number.inv1_power" in x["text"]] + == ["ok"] and not [m for m in _r["ok"]["messages"] if m["tier"] == "bad"] + and "setup" not in _r["plain"]) +check("...and a typed power request entity HA does not have is red there", + ["bad"] == [x["tier"] for x in _r["typo"]["setup"] + if "number.typo" in x["text"]]) + + +async def _kettle(s, root, sup): + return (await _get(s, root + "ha/entities?entity=sensor.net"), + await _get(s, root + "ha/entities?entity=sensor.gone")) + + +(_k, _gone), _sup = asyncio.run(session(Controller(SITE, STATES), SITE, + _kettle)) +check("the kettle test reads one entity now, in W, and says when it is not " + "there", _k == {"entity_id": "sensor.net", "found": True, + "state": "-3.1", "unit": "kW", "watts": -3100.0} + and _gone["found"] is False and _gone["watts"] is None) + +# --------------------------------------------------------------------------- # +print("\n6. the save goes through the P2 path and writes a valid blob") +# --------------------------------------------------------------------------- # +_plan = {"meter": "signed", "roster": "two", "solar": "two", + "prices": "daynight", "region": "flanders", "peak": "forecast", + "shadow": "on"} + + +async def _wizard(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + model = B.browser(B.apply(m["ui"], _plan)) + v = (await _post(s, root + "config/validate", {"model": model, + "setup": True}))[1] + saved = await _post(s, root + "config/save", { + "model": model, "fingerprint": m["fingerprint"], "setup": "done"}) + return v, saved + + +_store = Store() +(_v, _saved), _sup = asyncio.run(session(Controller(NEW, STATES, _store), + NEW, _wizard)) +_blob = _sup.writes[-1] if _sup.writes else {} +check("the wizard's model validates clean and saves with 200", + not [m for m in _v["messages"] if m["tier"] == "bad"] + and _saved[0] == 200 and len(_sup.writes) == 1) +check("the blob written starts: the shipped validator accepts it", + not validate_startup_config(_blob)) +check("it has what the six steps set: the net meter, two named inverters, " + "two solar rows with one flipped, day and night prices, the Flanders " + "levies, the peak limit, and shadow mode on", + _blob["meter_source"] == "ha_signed" + and [i["name"] for i in _blob["inverters"]] == ["inverter-1", + "inverter-2"] + and _blob["setpoint_entity"] == "" + and _blob["pv_entities"] == ["sensor.pv_a", "sensor.pv_b"] + and _blob["pv_invert_entities"] == ["sensor.pv_b"] + and json.loads(_blob["static_profile"])["periods"][0]["eur_per_kwh"] + == 0.34 and _blob["price_taxes_eur_kwh"] + == U.REGION_PRESETS["flanders"]["taxes_eur_kwh"] + and _blob["peak_cap_w"] == 4200 and _blob["shadow_mode"] == "on") +check("every key config.yaml declares is written, in the stored order", + list(_blob)[:len(NEW)] == list(NEW) and set(_blob) == set(NEW)) +check("the wizard saved without a restart of its own: the restart is a " + "second, confirmed request", _sup.restarts == 0 + and 'JSON.stringify({ confirm: "restart" })' in JS.split( + "async function finish")[1]) +_all = B.blobs() +_new = [(n, r) for n, _b, r in _all if n.startswith("new-")] +_ok = [n for n, _b, r in _all if not r] +print(f" {len(_all)} blobs from {len(B.starts())} starts; " + f"{len(_ok)} accepted") +check(f"every plan from a new install is accepted by the shipped validator " + f"({len(_new)} plans)", len(_new) >= 25 and not [n for n, r in _new + if r]) +check("every plan from the TEST-23 sites is accepted, except where the site " + "trades on price with a plan that has no meter or no prices, which the " + "last step then lists", + all(not r or ("options.arb" in n and "arbitrage_enabled" in r[0]) + for n, _b, r in _all) and len(_ok) >= 80) +check("every accepted blob keeps every option key (the Supervisor count, 78)", + all(set(b) == set(DEFAULTS) for _n, b, r in _all if not r)) + +# --------------------------------------------------------------------------- # +print("\n7. a stale save names only what changed elsewhere (P2 finding a)") +# --------------------------------------------------------------------------- # + + +async def _stale(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + sup.options["peak_cap_w"] = 5000 # the Configuration tab + model = copy.deepcopy(m["ui"]) + model["price_timeout_s"] = 12 # the operator's own edit + first = await _post(s, root + "config/save", + {"model": model, "fingerprint": m["fingerprint"]}) + again = await _post(s, root + "config/save", + {"model": model, "fingerprint": first[1]["fingerprint"]}) + return first, again + + +(_first_r, _again), _sup = asyncio.run(session(Controller(SITE, STATES), SITE, + _stale)) +print(f" changed_fields {_first_r[1]['changed_fields']}, moved " + f"{_first_r[1]['moved']}, changed {_first_r[1]['changed']}") +check("the banner's list is the other surface's key only, not the operator's " + "own edit", _first_r[0] == 409 + and _first_r[1]["changed_fields"] == ["peak_cap_w"] + and _first_r[1]["moved"] == ["peak_cap_w"]) +check("`changed` (stored against mine, which the classic page shows as " + "theirs -> mine) is unchanged", + _first_r[1]["changed"] == ["peak_cap_w", "price_timeout_s"]) +check("saving again with the new token is the deliberate second press: it " + "stores the page as shown (Discard loads theirs instead)", + _again[0] == 200 and _sup.options["peak_cap_w"] == 3500 + and _sup.options["price_timeout_s"] == 12) + + +async def _two_pages(s, root, sup): + """The classic page and this one open the same blob; the classic one + saves first (the browser run found the token was dropped then).""" + m = await _get(s, root + "config/model?lang=en") + classic = await _get(s, root + "config/model?lang=en") + theirs = dict(classic["options"], peak_cap_w=5000) + await _post(s, root + "config/save", {"options": theirs, + "fingerprint": classic["fingerprint"]}) + model = copy.deepcopy(m["ui"]) + model["price_timeout_s"] = 12 + return await _post(s, root + "config/save", + {"model": model, "fingerprint": m["fingerprint"]}) + + +_r, _sup = asyncio.run(session(Controller(SITE, STATES), SITE, _two_pages)) +check("two pages on one blob: after the other page saved, this one's banner " + "still names only the other page's change", + _r[0] == 409 and _r[1]["changed_fields"] == ["peak_cap_w"]) + + +async def _unknown(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + sup.options["peak_cap_w"] = 5000 + model = copy.deepcopy(m["ui"]) + model["price_timeout_s"] = 12 + return await _post(s, root + "config/save", + {"model": model, "fingerprint": "not-handed-out"}) + + +_r, _sup = asyncio.run(session(Controller(SITE, STATES), SITE, _unknown)) +check("a token the add-on did not hand out (it restarted) falls back to " + "every key that differs, as before", + _r[0] == 409 and _r[1]["moved"] is None + and _r[1]["changed_fields"] == ["peak_cap_w", "price_timeout_s"]) + +# --------------------------------------------------------------------------- # +print("\n8. the wizard's words keep to STYLE") +# --------------------------------------------------------------------------- # + + +def _texts(node, path=""): + for k, v in node.items(): + if isinstance(v, dict): + yield from _texts(v, f"{path}{k}.") + elif isinstance(v, str): + yield f"{path}{k}", v + + +def _sentences(t): + return len(re.findall(r"[.!?](?:\s|$)", t)) + + +_long = [(p, t) for p, t in _texts(WS) + if len(t.split()) > (25 if p.endswith("description") else 6) + or (p.endswith("description") and _sentences(t) > 1) or ";" in t] +check(f"every wizard string is one sentence of at most 25 words, or a name " + f"of at most 6 ({_long})", not _long and len(list(_texts(WS))) > 50) +_rendered = [x for notes in ( + setup_checks(SITE, entities=ROWS), _c2 and setup_checks(_two, entities=ROWS), + setup_checks(SITE, entities=None), setup_checks(_hw, entities=ROWS), + setup_checks(_fixed, entities=ROWS), setup_checks(dict( + SITE, soc_entity="sensor.gone", batt_entity="sensor.grid_x"), + entities=dict(ROWS, **{"sensor.grid": {"state": "x", "unit": "W"}}))) + for x in (n.text for n in notes)] +_over = [t for t in _rendered if len(t.split()) > 25 or _sentences(t) > 1 + or ";" in t] +check(f"every live check, rendered with real values, is one sentence of at " + f"most 25 words ({len(_rendered)} rendered, over: {_over})", + len(_rendered) > 20 and not _over) +_dialogs = [WS["dialog"]["description"], WS["dialog_live"]["description"]] +check("both restart dialogs name the 0 W, and the shadow one says it stays", + all("0 W" in d for d in _dialogs) and "shadow mode keeps them at 0 W" + in _dialogs[0]) +check("the wizard defaults to shadow mode: the switch starts on", + "shadowOn: true" in JS) +_leak = sorted(k for k in TL.config_surface(D.CONFIG)[0] if re.search( + r"[^A-Za-z0-9_]" + re.escape(k) + r"[^A-Za-z0-9_]", JS)) +check(f"settings.js, wizard included, names no option key ({_leak})", + not _leak) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py index a00ffca..6a2d3ed 100644 --- a/goodwe_controller/tools/ux13_demo.py +++ b/goodwe_controller/tools/ux13_demo.py @@ -11,6 +11,12 @@ P2: the fixture Supervisor serves config.yaml's defaults with this site's options, a schema read off config.yaml the way the Supervisor renders it (`schema_ui()`) and translations/en.yaml, and keeps what the settings view saves in memory, so the Installer view can be clicked through end to end. + +P4: STATE `new` is a new install (config.yaml's defaults with one power +request entity, an empty Store, control never started), so the page opens +the setup wizard by itself. A one-entity read of sensor.grid steps through +KETTLE_READS, so the kettle test sees the kettle go on (up) and then a +reversed meter (down). """ import asyncio @@ -74,8 +80,12 @@ class Hass: async def number(self, _e, invert=False): return None - async def state(self, _e): - return None + async def state(self, e): + s = next((dict(x) for x in STATES if x["entity_id"] == e), None) + if s and e == "sensor.grid": + n = KETTLE_COUNT[0] = KETTLE_COUNT[0] + 1 + s["state"] = str(KETTLE_READS[(n - 1) % len(KETTLE_READS)]) + return s async def set_number(self, _e, _v): return True @@ -87,6 +97,10 @@ class Hass: return STATES +KETTLE_READS = (-10, 1990, 1990, -10) +KETTLE_COUNT = [0] + + def _state(eid, name, state, unit=None, cls=None): return {"entity_id": eid, "state": state, "attributes": {"friendly_name": name, "unit_of_measurement": unit, @@ -240,6 +254,16 @@ def controller(state): async def main(state, port, host="127.0.0.1"): + if state == "new": + stored = dict(defaults(CONFIG), setpoint_entity="number.a") + c = Controller(dict(stored), Hass(), Store(), Pub(), + stop=asyncio.Event()) + c.auto = False + runner = aioweb.AppRunner(web.build_app(c, Supervisor(stored))) + await runner.setup() + await aioweb.TCPSite(runner, host, port).start() + print(f"serving new on http://127.0.0.1:{port}/", flush=True) + await asyncio.Event().wait() c = controller(state) stored = dict(defaults(CONFIG), **OPTS) stored.update(setpoint_entity="", meter_source="ha_signed", diff --git a/goodwe_controller/tools/ux13_wizard_blobs.py b/goodwe_controller/tools/ux13_wizard_blobs.py new file mode 100644 index 0000000..8b74ee7 --- /dev/null +++ b/goodwe_controller/tools/ux13_wizard_blobs.py @@ -0,0 +1,254 @@ +"""UX-13 P4: every options blob the setup wizard can save, and the Supervisor's +own validator run over them. + + python3 tools/ux13_wizard_blobs.py --dump DIR # write the blobs + docker run --rm --network none -v "$PWD:/w:ro" -v DIR:/blobs:ro \ + --entrypoint python3 \ + ghcr.io/home-assistant/amd64-hassio-supervisor:2026.08.0 \ + /w/tools/ux13_wizard_blobs.py --supervisor /blobs + +The wizard edits the page model one step at a time and saves it through +uipage.to_options(), like the Installer view. `blobs()` walks each step's +choices (meter source and sign, one to three inverters, solar rows, every +contract and price source, region, peak limit, shadow mode) from a new +install and from the TEST-23 sites, and keeps what the shipped validator +accepts, because the wizard saves nothing it refuses. test_setup.py checks +the set; `--supervisor` runs it through Supervisor 2026.08.0's `AppOptions` +offline, as the P2 test did. It touches nothing: no network, no Supervisor. +""" + +import copy +import glob +import json +import os +import sys + +HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +def browser(value): + """What JSON.parse then JSON.stringify does to a value: 3.0 becomes 3.""" + if isinstance(value, float) and value.is_integer(): + return int(value) + if isinstance(value, list): + return [browser(v) for v in value] + if isinstance(value, dict): + return {k: browser(v) for k, v in value.items()} + return value + + +# --- the wizard's steps, as edits to the page model ------------------------ # +METERS = { + "entity": {"meter_source": "off", "meter_entity": "sensor.grid"}, + "entity_flipped": {"meter_source": "off", "meter_entity": "sensor.grid", + "meter_invert": True}, + "signed": {"meter_source": "ha_signed", "p1_net_entity": "sensor.net"}, + "signed_3": {"meter_source": "ha_signed", "p1_net_entity": "sensor.net", + "meter_phases": 3, "p1_phase_net_entities": [ + "sensor.l1", "sensor.l2", "sensor.l3"]}, + "dsmr": {"meter_source": "ha_dsmr", "p1_import_entity": "sensor.imp", + "p1_export_entity": "sensor.exp"}, + "homewizard": {"meter_source": "homewizard_local", + "p1_host": "192.0.2.50"}, + "mqtt": {"meter_source": "mqtt_p1", "meter_mqtt_topic": "p1/power"}, +} + + +def _card(i, flat=False, **more): + card = {"setpoint_entity": f"number.inv{i}_power", + "soc_entity": f"sensor.inv{i}_level", + "batt_entity": f"sensor.inv{i}_battery", "batt_invert": False, + "max_w": 2500, "bms_soc_floor": 10} + if flat: + card.update(name="", capacity_kwh=None) + else: + card.update(name=f"inverter-{i}", capacity_kwh=5.0) + card.update(more) + return card + + +ROSTERS = { + "one": ("flat", [_card(1, flat=True)]), + "one_flipped": ("flat", [_card(1, flat=True, batt_invert=True, + max_w=3000)]), + "two": ("list", [_card(1), _card(2, max_w=4600, bms_soc_floor=15)]), + "three": ("list", [_card(1), _card(2), _card(3, capacity_kwh=9.6)]), +} +SOLAR = { + "none": [], + "one": [{"entity": "sensor.pv", "reversed": False}], + "one_reversed": [{"entity": "sensor.pv", "reversed": True}], + "two": [{"entity": "sensor.pv_a", "reversed": False}, + {"entity": "sensor.pv_b", "reversed": True}], +} +PRICES = { + "none": {"ui.contract": "none", "ui.fallback": "none"}, + "fixed": {"ui.contract": "fixed", "ui.fallback": "fixed", + "ui.fixed_price": 0.31}, + "daynight": {"ui.contract": "daynight", "ui.fallback": "daynight", + "ui.day_price": 0.34, "ui.night_price": 0.25}, + "dynamic": {"ui.contract": "dynamic", "price_provider": "generic_dayahead", + "ui.fallback": "none"}, + "dynamic_fixed": {"ui.contract": "dynamic", + "price_provider": "generic_dayahead", + "ui.fallback": "fixed", "ui.fixed_price": 0.3}, + "dynamic_daynight": {"ui.contract": "dynamic", + "price_provider": "generic_dayahead", + "ui.fallback": "daynight", "ui.day_price": 0.3, + "ui.night_price": 0.2}, + "formula": {"ui.contract": "dynamic", "price_provider": "custom_formula", + "price_formula": "", + "ui.fallback": "fixed", + "ui.fixed_price": 0.3}, + "csv": {"ui.contract": "dynamic", "price_provider": "manual_csv", + "price_csv_path": "/share/prices.csv", "ui.fallback": "fixed", + "ui.fixed_price": 0.3}, +} +REGIONS = {"flanders": {"ui.region": "flanders"}, + "own": {"ui.region": "own", "price_taxes_eur_kwh": 0.15}} +PEAKS = {"low": {"peak_cap_w": 2500, "peak_forecast_entity": ""}, + "forecast": {"peak_cap_w": 4200, + "peak_forecast_entity": "sensor.peak_forecast"}, + "high": {"peak_cap_w": 10000, "peak_forecast_entity": ""}} +SHADOWS = ("on", "auto") # the switch on, or off (uilayout.SHADOW) +BASE = {"meter": "entity", "roster": "one", "solar": "none", + "prices": "none", "region": "own", "peak": "low", "shadow": "on"} + + +def plans(): + """Each step's choices once, with the other steps at BASE, then a few + whole sites that combine them.""" + axes = {"meter": METERS, "roster": ROSTERS, "solar": SOLAR, + "prices": PRICES, "region": REGIONS, "peak": PEAKS, + "shadow": dict.fromkeys(SHADOWS)} + seen = [] + for axis, choices in axes.items(): + for choice in choices: + plan = dict(BASE, **{axis: choice}) + if plan not in seen: + seen.append(plan) + for plan in ( + {"meter": "dsmr", "roster": "two", "solar": "two", + "prices": "dynamic_daynight", "region": "flanders", + "peak": "forecast", "shadow": "on"}, + {"meter": "signed_3", "roster": "three", "solar": "one_reversed", + "prices": "daynight", "region": "flanders", "peak": "high", + "shadow": "auto"}, + {"meter": "homewizard", "roster": "one_flipped", "solar": "one", + "prices": "fixed", "region": "own", "peak": "forecast", + "shadow": "on"}, + {"meter": "mqtt", "roster": "two", "solar": "none", + "prices": "formula", "region": "flanders", "peak": "low", + "shadow": "on"}): + seen.append(plan) + return seen + + +def apply(model, plan): + """The page model after the wizard's six steps, as the page leaves it.""" + from app import uilayout as L, uimodel as U + m = copy.deepcopy(model) + m.update(copy.deepcopy(METERS[plan["meter"]])) + shape, cards = ROSTERS[plan["roster"]] + cards = copy.deepcopy(cards) + if m.get("inverter_shape") == "list": + # A site stored as a list stays one: one card keeps a name. + for i, card in enumerate(cards, 1): + card.update(name=card["name"] or f"inverter-{i}", + capacity_kwh=card["capacity_kwh"] or 5.0) + m["inverters"] = cards + m[U.COUNT] = len(cards) + if shape == "list": + m.update(U.GROWN) + m["ui.solar"] = copy.deepcopy(SOLAR[plan["solar"]]) + m.update(copy.deepcopy(PRICES[plan["prices"]])) + if plan["prices"] == "formula": + from app.custom_formula import _LEGS + m["price_formula"] = _LEGS["price_formula"].example + m.update(copy.deepcopy(REGIONS[plan["region"]])) + if plan["region"] != "own": + m["price_taxes_eur_kwh"] = U.REGION_PRESETS[plan["region"]][ + "taxes_eur_kwh"] + m.update(PEAKS[plan["peak"]]) + field, on, off = L.SHADOW + m[field] = on if plan["shadow"] == "on" else ( + m.get(field) if m.get(field) != on else off) + return m + + +def starts(): + """(name, stored options) the wizard opens on: a new install (config.yaml's + defaults and one power request entity, typed in the Configuration tab so + the add-on starts) and the TEST-23 sites.""" + sys.path.insert(0, os.path.join(HERE, "tools")) + import ux13_demo as D + new = dict(D.defaults(D.CONFIG), setpoint_entity="number.inv1_power") + out = [("new", new)] + for f in sorted(glob.glob(os.path.join(HERE, "scenarios", "ux13", "test23", + "*.json")))[:3]: + out.append((os.path.basename(f)[:-5], dict(D.defaults(D.CONFIG), + **json.load(open(f))))) + return out + + +def blobs(): + """[(name, blob, refusals)] for every plan from every start.""" + sys.path.insert(0, HERE) + from app import uimodel as U, uipage + from app.validate import validate_startup_config + out = [] + for start, stored in starts(): + model = json.loads(json.dumps(U.options_to_ui(stored))) + for plan in plans(): + name = start + "-" + "-".join(f"{k}.{v}" for k, v in plan.items()) + posted = browser(json.loads(json.dumps(apply(model, plan)))) + blob = uipage.to_options(posted, stored) + out.append((name, blob, validate_startup_config(blob))) + return out + + +# --- run inside the Supervisor image --------------------------------------- # +def supervisor(folder): + sys.path.insert(0, "/usr/src/supervisor") + import voluptuous as vol + from pathlib import Path + from supervisor.apps.options import AppOptions + from supervisor.apps.validate import SCHEMA_APP_CONFIG + from supervisor.utils.yaml import read_yaml_file + cfg = SCHEMA_APP_CONFIG(read_yaml_file(Path(HERE) / "config.yaml")) + check = vol.Schema(vol.All(dict, AppOptions( + None, cfg["schema"], cfg["name"], "local_goodwe_controller"))) + bad = 0 + files = sorted(glob.glob(os.path.join(folder, "*.json"))) + for f in files: + blob = json.load(open(f)) + try: + got = check(copy.deepcopy(blob)) + dropped = sorted(set(blob) - set(got)) + ok = not dropped + why = f"dropped {dropped}" if dropped else f"{len(got)} keys" + except vol.Invalid as err: + ok, why = False, str(err) + bad += not ok + print(f" {'PASS' if ok else 'FAIL'} {os.path.basename(f)}: {why}") + print(f"{len(files) - bad} of {len(files)} accepted by AppOptions " + f"({cfg['version']})") + return 1 if bad or not files else 0 + + +if __name__ == "__main__": + if sys.argv[1:2] == ["--supervisor"]: + sys.exit(supervisor(sys.argv[2])) + if sys.argv[1:2] == ["--dump"]: + os.makedirs(sys.argv[2], exist_ok=True) + n = 0 + for name, blob, refused in blobs(): + if refused: + print("refused, not written:", name, refused[0]) + continue + with open(os.path.join(sys.argv[2], name + ".json"), "w") as f: + json.dump(blob, f, indent=1) + n += 1 + print(f"{n} blobs written to {sys.argv[2]}") + sys.exit(0) + print(__doc__) -- 2.54.0 From 3198f346fdbf402f5038a7d07ae87f0b2aa2246f Mon Sep 17 00:00:00 2001 From: review-agent Date: Mon, 28 Sep 2026 06:12:09 +0200 Subject: [PATCH 059/105] UX-13 P4 review fixes (PR #146, comment 1887) R1: first_start also needs a Store created at this boot (Store.fresh), so old never-started sites (both TEST-23 add-ons, one in shadow) stay on Home. R2: a kettle skip after a fall says on the last step that the reading went down. R3: the shadow switch goes only on the model the wizard posts, never into V. R4: Home Assistant not answering is red on the last step. R5: meter + solar + battery below -300 W flags a reversed battery sensor. R6: the live checks say what to change and where. Co-Authored-By: Claude Opus 5.5 --- .../DECISIONS/UX-13-setup-wizard.md | 30 +++-- goodwe_controller/DOCS.md | 6 +- goodwe_controller/app/static/settings.js | 27 +++-- goodwe_controller/app/store.py | 4 + goodwe_controller/app/ui_text/en.json | 1 + goodwe_controller/app/uipage.py | 12 +- goodwe_controller/app/validate.py | 70 ++++++++---- goodwe_controller/app/web.py | 4 +- goodwe_controller/test_setup.py | 108 +++++++++++++++--- goodwe_controller/tools/ux13_demo.py | 8 +- 10 files changed, 195 insertions(+), 75 deletions(-) diff --git a/goodwe_controller/DECISIONS/UX-13-setup-wizard.md b/goodwe_controller/DECISIONS/UX-13-setup-wizard.md index d3fa8a6..5d7387e 100644 --- a/goodwe_controller/DECISIONS/UX-13-setup-wizard.md +++ b/goodwe_controller/DECISIONS/UX-13-setup-wizard.md @@ -23,14 +23,17 @@ The page opens `#setup` only when it is opened with no route, and only when `/config/model` gives a reason: - **`no_power_request`**: the stored options name no inverter to control. -- **`first_start`**: the Store has no `setup_done` and no `auto` key, and - control is not started. `auto` is the key Start/Stop writes, and - config.yaml ships `auto_start` off (the same "fresh install" reading as - app/shadow.py's `auto` default), so this is a site that has never run or - been stopped by hand and never finished the wizard. +- **`first_start`**: this boot found no `/data/state.json` (`Store.fresh`), the + Store has no `setup_done` and no `auto` key, and control is not started. + `auto` is the key Start/Stop writes. The startup gate exits 78 before the + controller writes the Store, so a new install's first good boot is fresh. -A site that runs control, or ever started or stopped it, is never sent to the -wizard. Without a Store the answer is no. The wizard's save writes +"Never started" alone is not enough: both TEST-23 add-ons have `auto_start` +off and no `auto` key, and one has run in shadow for weeks (review of PR #146, +R1). So a Store read from a file is an old site, and it is never sent to the +wizard. A new install that restarts before the page is opened is not sent +either, and its Setup tab still works. A site that runs control, or ever +started or stopped it, is never sent. Without a Store the answer is no. The wizard's save writes `setup_done` (an ISO time) to the Store. A save from the Installer view does not. @@ -52,13 +55,16 @@ off, a fall turns it on. For a net entity or import and export, a fall cannot be fixed by an option, so the step is not passed and the page says what to check. A meter the add-on reads itself (HomeWizard, MQTT) cannot be read by the page, so the test is skipped and Home shows the direction after the -restart. The installer may skip the test; the last step then warns. +restart. The installer may skip the test, because a cloud can fake a fall; +the last step then warns, and after a fall it says the reading went down. The battery and solar signs cannot be forced from the page, which never commands an inverter. The last step reports each battery's reading with its direction ("reads 800 W charging now, so check the inverter shows the same") and warns when a solar entity reads below zero without its "reads negative" -switch. +switch. It also warns when meter + solar + battery, all known, add up to a +house using less than -300 W: a battery sensor reversed while giving power. +An idle or charging battery cannot be judged that way. ## 4. The last step @@ -67,12 +73,14 @@ It reads nothing itself: `web.py` passes a Home Assistant entity list at most 5 s old, the running options, the running meter reading and today's price count. Tiers are ok, info, warn and bad. A power request entity missing from Home Assistant is **bad**, because a write to it is answered 200 (SAFETY-77) -and only the entity list can tell. The wizard does not save while anything is +and only the entity list can tell. So is Home Assistant not answering, since +the list is then unknown. The wizard does not save while anything is bad. It then saves through P2's path (`setup: "done"`) and asks for the restart as the second, confirmed request, with a dialog that names the 0 W. The shadow switch is on by default and writes `shadow_mode: on`, which holds every inverter at 0 W after a restart even if control is started. Off keeps the -stored value, or `auto` if that was `on`. +stored value, or `auto` if that was `on`. The switch goes only on the model the +wizard posts, never into the page model the Installer view also saves. ## 5. The stale save lists only what moved (P2 test, finding a) diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 3d6c8e2..d5367cc 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3239,9 +3239,9 @@ the last step. to 0 W while it restarts, and with "Start in shadow mode" on (the default) it stays at 0 W until you turn shadow mode off under Settings. -Setup opens by itself when the page is opened on a new install: control was -never started or stopped and Setup never finished, or the stored settings name -no inverter to control. A running site is never sent there. The add-on does +Setup opens by itself on a new install's first start, until Setup finishes or +control is started, and whenever the stored settings name no inverter to +control. A site that already ran before is never sent there. The add-on does not start with no power request entity at all, so on a brand-new install fill in "Inverter setpoint entity" on the Configuration tab first. diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index 75d5c00..603dfcb 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -636,31 +636,37 @@ if (k.sig !== sig) { k.before = null; k.ok = false; k.sig = sig; } const w = await readMeter(src); if (w == null) WZ.kettle = Object.assign({}, k, { sig, say: "unread" }); - else if (k.before == null || k.ok) WZ.kettle = { sig, before: w }; + else if (k.before == null || k.ok) WZ.kettle = { sig, before: w, wrong: !k.ok && !!k.wrong }; else { const o = kettleOutcome(src, k.before, w); - WZ.kettle = { sig, before: o.say === "none" ? k.before : null, say: o.say, d: o.d, ok: o.sets != null }; + // `wrong`: the reading went the way no option can fix. A skip after + // that keeps saying so on the last step (review R2). + const wrong = o.say === "none" ? !!k.wrong : o.sets == null; + WZ.kettle = { sig, before: o.say === "none" ? k.before : null, say: o.say, d: o.d, ok: o.sets != null, wrong }; if (o.sets) { Object.assign(V, o.sets); queueValidate(); } } drawStep(); }); const row = h("div", { class: "row" }, read); if (!k.ok) row.append(h("button", { type: "button", class: "btn link", onclick: () => { - WZ.kettle = { sig: kettleSig(src), say: "skipped", ok: true, skipped: true }; drawStep(); + WZ.kettle = { sig: kettleSig(src), say: "skipped", ok: true, skipped: true, wrong: !!k.wrong }; drawStep(); } }, WS.kettle.skip)); box.append(row); return box; } // Step 6: the shadow switch, the checks, and Save and restart. - function applyShadow() { + // The shadow switch goes only on the model the wizard posts, never into V, + // which the Installer view saves too (review R3). + function shadowValue() { const s = M.setup.shadow; - V[s.field] = WZ.shadowOn ? s.on : (ORIG[s.field] !== s.on ? ORIG[s.field] : s.off); + return WZ.shadowOn ? s.on : (ORIG[s.field] !== s.on ? ORIG[s.field] : s.off); } + function posted() { return Object.assign({}, V, { [M.setup.shadow.field]: shadowValue() }); } function shadowRow() { const lid = "wzs"; const b = h("button", { type: "button", class: "switch", role: "switch", "aria-checked": String(WZ.shadowOn), "aria-labelledby": lid }); - b.addEventListener("click", () => { WZ.shadowOn = !WZ.shadowOn; applyShadow(); queueValidate(); drawStep(); }); + b.addEventListener("click", () => { WZ.shadowOn = !WZ.shadowOn; drawStep(); }); return h("div", { class: "f inline" }, h("div", {}, h("div", { class: "lbl", id: lid }, WS.shadow.name), h("div", { class: "help" }, WS.shadow.description)), h("div", { class: "ctl" }, b)); @@ -669,7 +675,7 @@ const list = $("#wz-checks"); if (list) list.replaceChildren(line("info", WS.check.running.description)); clearTimeout(vtimer); - const b = await validate({ setup: true }); + const b = await validate({ setup: true, model: posted() }); WZ.checked = b; if (!list || !list.isConnected) return b; if (!b) { list.replaceChildren(line("bad", WS.check.failed.description)); return b; } @@ -682,7 +688,7 @@ if (b.device_note) add("info", b.device_note); const src = kettleSource(); if (!src) add("info", WS.kettle.self.description); - else if (WZ.kettle && WZ.kettle.skipped) add("warn", WS.kettle.skipped.description); + else if (WZ.kettle && WZ.kettle.skipped) add("warn", (WZ.kettle.wrong ? WS.kettle.skipped_wrong : WS.kettle.skipped).description); else if (kettleOk()) add("ok", WS.kettle.tested.description); const rank = { bad: 0, warn: 1, ok: 2, info: 3 }; items.sort((a, z) => rank[a[0]] - rank[z[0]]); @@ -708,11 +714,11 @@ const b = await runChecks(); if (!b) { toast(WS.check.failed.description); return; } if (WZ.blocked) { toast(WS.check.blocked.description); return; } - const shadow = V[M.setup.shadow.field] === M.setup.shadow.on; + const shadow = shadowValue() === M.setup.shadow.on; ask(shadow ? WS.dialog : WS.dialog_live, async () => { wzBanner(); let res; - try { res = await postSave({ setup: "done" }); } catch (e) { toast(W.toast.failed); return; } + try { res = await postSave({ setup: "done", model: posted() }); } catch (e) { toast(W.toast.failed); return; } const { r, b: body } = res; if (r.status === 409 && body.kind === "stale") { wzBanner("bad", W.stale.name, staleText(body)); return; } if (r.status === 422) { @@ -758,7 +764,6 @@ ROWS.length = 0; const body = []; if (n === 1 && !M.setup_needed) body.push(h("div", { class: "msg info" }, WS.done_before.description)); - if (n === S.final) applyShadow(); for (const f of allFields()) if (f.wizard === n && f.key !== S.shadow.field) body.push(fieldRow(f, null, "wz")); if (n === 1) body.push(kettleBox()); if (n === 5) body.push(h("p", { class: "small muted" }, WS.modes_later.description)); diff --git a/goodwe_controller/app/store.py b/goodwe_controller/app/store.py index 22cfd7b..b3fea7a 100644 --- a/goodwe_controller/app/store.py +++ b/goodwe_controller/app/store.py @@ -585,6 +585,9 @@ class Store: def __init__(self, path: str = "/data/state.json"): self.path = path self.data = dict(DEFAULTS) + # UX-13 P4: True when this boot found no state file, i.e. a new /data. + # Only the setup wizard's first-run rule reads it (uipage.setup_needed). + self.fresh = False self.load() def load(self) -> None: @@ -598,6 +601,7 @@ class Store: self.data.get("phase"), self.data.get("last_completed"), self.data.get("sign_tripped")) except FileNotFoundError: + self.fresh = True _LOG.info("no saved state, starting fresh") except (json.JSONDecodeError, OSError) as err: # A corrupt state file must not stop the controller: losing the diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index f4f594a..bd5cb3c 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -191,6 +191,7 @@ "wrong_dsmr": {"description": "The reading went down by {d}, so check that import and export are not swapped."}, "self": {"description": "The add-on reads this meter itself, so Home shows its direction after the restart."}, "skipped": {"description": "The meter direction is not tested, so check it on Home after the restart."}, + "skipped_wrong": {"description": "The kettle test saw the meter reading go down, so check its direction in step 1 before you start control."}, "tested": {"description": "The meter direction was tested with a kettle."}, "needed": {"description": "Do the kettle test first, or skip it."} }, diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py index ce2b269..42dfd52 100644 --- a/goodwe_controller/app/uipage.py +++ b/goodwe_controller/app/uipage.py @@ -291,19 +291,19 @@ SETUP_DONE = "setup_done" STARTED = "auto" -def setup_needed(stored: dict, store_data, started) -> str | None: +def setup_needed(stored: dict, store_data, started, fresh=False) -> str | None: """Why the page opens the wizard by itself, or None. "no_power_request": the stored options name no inverter to control, so - the add-on cannot start on them. "first_start": this /data has never been - through the wizard and control was never started or stopped, which is a - new install: config.yaml ships `auto_start` off, so it comes up stopped. - A site that runs, or ever ran, control is never sent to the wizard. + the add-on cannot start on them. "first_start": a new install. This boot + found no Store file (`fresh`), the wizard never saved and control was never + started or stopped. `fresh` is what tells a new install from an old site + that was never started, e.g. one left in shadow for weeks (TEST-23). `store_data` is the Store's dict (None: unknown, so no), `started` is whether control is started now.""" if not power_request_entities(stored or {}): return "no_power_request" - if store_data is None: + if store_data is None or not fresh: return None if store_data.get(SETUP_DONE) or STARTED in store_data or started: return None diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index d1ad560..2a27f6d 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -1782,6 +1782,9 @@ def _entity_notes(notes, opts: dict, entities: dict, bad=()) -> None: # --------------------------------------------------------------------------- # # Below this a battery or solar reading counts as idle for a sign check. IDLE_W = 50.0 +# Meter + solar + battery is the house's use, never below zero. Below minus +# this, read seconds apart, a direction is reversed (a battery giving power). +BALANCE_W = 300.0 # The keys that pick the meter. A meter the add-on reads itself (HomeWizard, # MQTT) is only known live when the running options read the same one. _METER_KEYS = ("meter_source", "p1_host", "meter_mqtt_topic") @@ -1848,33 +1851,50 @@ def setup_checks(opts: dict, *, entities: dict | None, running=None, """ notes: list[Note] = [] if entities is None: - _advise(notes, "warn", (), "Home Assistant is not answering, so " - "no entity was checked yet.") + # Red: only the list can tell a missing power request entity (SAFETY-77). + _advise(notes, "bad", ("setpoint_entity",), "Home Assistant is not " + "answering, so press Check again once it is back.") else: _entity_notes(notes, opts, entities, bad=("setpoint_entity",)) - _meter_check(notes, opts, entities, running, meter_now_w) - for who, entry in _cards(opts): - _card_checks(notes, who, entry, entities) + meter = _meter_check(notes, opts, entities, running, meter_now_w) + batts = [_card_checks(notes, who, entry, entities) + for who, entry in _cards(opts)] + solar = [] if entities is not None: flipped = pv.inverted(opts) for entity in pv.entities(opts): w, _unit = _reading(entities, entity, convert=True) if entity not in entities or w is None: + solar.append(None) continue if w < -IDLE_W and entity not in flipped: + solar.append(None) _advise(notes, "warn", ("pv_invert_entities",), - f"{entity} reads below zero now, so its solar " - "production sign looks reversed.") + f"{entity} reads below zero now, so turn on its " + "“Reads negative” switch in the Solar step.") else: w = -w if entity in flipped else w + solar.append(w) _advise(notes, "ok", ("pv_entity",), f"{entity} reads {_signed(w)} of solar production " "now.") + # A battery sensor that reads the wrong way while giving power makes the + # house use less than nothing. Only with every term known: a missing + # solar reading could be the difference. + known = [meter] + batts + solar + if solar and batts and all(w is not None for w in known) \ + and sum(known) < -BALANCE_W: + _advise(notes, "warn", ("batt_invert",), + f"The readings add up to {_signed(sum(known))} of house " + "use, so check each " + "battery's “Battery power sign is reversed” switch in step 2.") _price_check(notes, opts, running, prices_known) return notes -def _meter_check(notes, opts, entities, running, meter_now_w) -> None: +def _meter_check(notes, opts, entities, running, meter_now_w): + """The meter line. Returns the grid reading in W (positive: taken from + the grid) as the add-on will read it, or None when it is not known.""" source = str(opts.get("meter_source") or "off").strip() if source == "off": parts = [(opts.get("meter_entity"), 1.0)] @@ -1888,28 +1908,29 @@ def _meter_check(notes, opts, entities, running, meter_now_w) -> None: running.get(k) == opts.get(k) for k in _METER_KEYS) if same and meter_now_w is not None: _meter_line(notes, float(meter_now_w)) - else: - _advise(notes, "info", ("meter_source",), "The add-on reads " - "this meter itself, so Home shows its reading after " - "the restart.") - return + return float(meter_now_w) + _advise(notes, "info", ("meter_source",), "The add-on reads " + "this meter itself, so Home shows its reading after " + "the restart.") + return None if entities is None: - return + return None total = 0.0 for entity, sign in parts: entity = str(entity or "").strip() if not entity or entity not in entities: - return # a refusal or a missing-entity note says so + return None # a refusal or a missing-entity note says so w, text = _reading(entities, entity) if w is None: _advise(notes, "warn", ("meter_source",), - f"{entity} reads {text} now, so the meter has no " - "reading yet.") - return + f"{entity} reads {text} now, so check it in Home " + "Assistant before you start.") + return None total += sign * w if source == "off" and opts.get("meter_invert"): total = -total _meter_line(notes, total) + return total def _meter_line(notes, w) -> None: @@ -1922,9 +1943,11 @@ def _meter_line(notes, w) -> None: _advise(notes, "ok", ("meter_source",), text) -def _card_checks(notes, who, entry, entities) -> None: +def _card_checks(notes, who, entry, entities): + """The checks for one inverter's card. Returns its battery power in W, + positive while giving power, or None when it is not known.""" if entities is None: - return + return None setpoint = str(entry.get("setpoint_entity") or "").strip() if setpoint and setpoint in entities: _advise(notes, "ok", ("setpoint_entity",), @@ -1933,7 +1956,8 @@ def _card_checks(notes, who, entry, entities) -> None: soc = str(entry.get("soc_entity") or "").strip() if not soc: _advise(notes, "warn", ("soc_entity",), f"There is no battery " - f"level entity{who}, so the add-on holds 0 W.") + f"level entity{who}, so pick one in step 2 or the add-on " + "holds 0 W.") elif soc in entities: level, _unit = _reading(entities, soc) if level is None or not 0.0 <= level <= 100.0: @@ -1948,7 +1972,7 @@ def _card_checks(notes, who, entry, entities) -> None: if w is None: _advise(notes, "warn", ("batt_entity",), f"The battery " f"power{who} reads nothing now, so check {batt}.") - return + return None w = -w if entry.get("batt_invert") else w if abs(w) < IDLE_W: _advise(notes, "info", ("batt_entity",), f"The battery{who} is " @@ -1958,6 +1982,8 @@ def _card_checks(notes, who, entry, entities) -> None: _advise(notes, "info", ("batt_invert",), f"The battery{who} reads {messages.watts(w)} {doing} " "now, so check the inverter shows the same.") + return w + return None def _price_check(notes, opts, running, prices_known) -> None: diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index f294a99..730073a 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -199,7 +199,9 @@ def build_app(controller, selfcfg=None) -> web.Application: # UX-13 P4: the setup wizard, and why it opens by itself. "setup": uipage.setup_spec(), "setup_needed": uipage.setup_needed( - options, store_data(), bool(getattr(controller, "auto", False))), + options, store_data(), bool(getattr(controller, "auto", False)), + fresh=getattr(getattr(controller, "store", None), "fresh", + False) is True), }) return web.json_response(model) diff --git a/goodwe_controller/test_setup.py b/goodwe_controller/test_setup.py index 9c08004..be86f82 100644 --- a/goodwe_controller/test_setup.py +++ b/goodwe_controller/test_setup.py @@ -21,6 +21,7 @@ import logging import os import re import sys +import tempfile HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(HERE, "tools")) @@ -170,8 +171,9 @@ check("a refusal blocks the step of its field, a hidden or non-wizard field's " class Store: """app/store.py's shape: a dict under .data, and set().""" - def __init__(self, data=None): + def __init__(self, data=None, fresh=False): self.data = dict(data or {}) + self.fresh = fresh def set(self, key, value): self.data[key] = value @@ -294,16 +296,38 @@ check("the page moves on only when the step's count is 0, the kettle test is " print("\n4. first run: a new install opens the wizard, a working site not") # --------------------------------------------------------------------------- # S = uipage.setup_needed -check("a new install: never set up, control never started or stopped", - S(NEW, {}, False) == "first_start" - and S(NEW, {"phase": "idle", "sign_tripped": False}, False) +check("a new install: no Store file at this boot, never set up, control " + "never started or stopped", + S(NEW, {}, False, fresh=True) == "first_start" + and S(NEW, {"phase": "idle", "sign_tripped": False}, False, fresh=True) == "first_start") check("a site that runs control, or ever ran or stopped it, is not sent to " - "the wizard", S(NEW, {}, True) is None - and S(NEW, {"auto": True}, False) is None - and S(NEW, {"auto": False}, False) is None) + "the wizard", S(NEW, {}, True, fresh=True) is None + and S(NEW, {"auto": True}, False, fresh=True) is None + and S(NEW, {"auto": False}, False, fresh=True) is None) check("a site the wizard saved is not sent again", - S(NEW, {uipage.SETUP_DONE: "2026-09-28T10:00:00+00:00"}, False) is None) + S(NEW, {uipage.SETUP_DONE: "2026-09-28T10:00:00+00:00"}, False, + fresh=True) is None) +# Review R1: the Stores the two TEST-23 add-ons really have (2026-09-28): no +# `auto` (Start/Stop never pressed, auto_start off), no setup_done, stopped, +# one of them in shadow for weeks. A Store read from a file is an old site. +_T23_ADDON = dict.fromkeys(( + "circ_reason", "circ_tripped", "last_completed", "last_start_attempt", + "maint_schema_version", "phase", "phase_started", "schema_version", + "sign_reason", "sign_tripped", "site_sign_reason", "site_sign_tripped", + "unit/inverter-a/last_completed", "unit/inverter-a/last_start_attempt", + "unit/inverter-a/phase", "unit/inverter-a/phase_started", + "unit/inverter-a/sign_reason", "unit/inverter-a/sign_tripped")) +_T23_ARB = dict.fromkeys(( + "circ_reason", "circ_tripped", "last_completed", "last_start_attempt", + "phase", "phase_started", "schema_version", "sign_reason", "sign_tripped", + "site_sign_reason", "site_sign_tripped", "unit/inverter-a/sign_reason", + "unit/inverter-a/sign_tripped")) +check("an old site never started (the real TEST-23 Stores, one in shadow) is " + "not sent to the wizard: its Store came from a file (review R1)", + S(NEW, _T23_ADDON, False) is None and S(NEW, _T23_ARB, False) is None + and S(dict(NEW, shadow_mode="on"), _T23_ARB, False) is None + and S(NEW, {}, False) is None) check("stored options with no inverter to control always open it, whatever " "the Store says", S(DEFAULTS, {uipage.SETUP_DONE: "x", "auto": True}, True) @@ -345,7 +369,7 @@ async def _first(s, root, sup): return out -_store = Store({"phase": "idle"}) +_store = Store({"phase": "idle"}, fresh=True) _r, _sup = asyncio.run(session(Controller(NEW, STATES, _store), NEW, _first)) check("over HTTP, /config/model says a new install needs setup, with the spec", _r["model"]["setup_needed"] == "first_start" @@ -357,6 +381,22 @@ check("the wizard's save writes the Store marker, and the wizard stops " "opening by itself", _r["wizard"][0] == 200 and _store.data.get(uipage.SETUP_DONE) and _r["after"]["setup_needed"] is None) +_r, _sup = asyncio.run(session(Controller(NEW, STATES, Store(_T23_ARB)), NEW, + _first)) +check("over HTTP, an old site never started (a Store read from a file) is not " + "sent to the wizard (review R1)", _r["model"]["setup_needed"] is None) +with tempfile.TemporaryDirectory() as _d: + from app.store import Store as _RealStore + _path = os.path.join(_d, "state.json") + _new = _RealStore(_path) + _new.set("phase", "idle") + _old = _RealStore(_path) + with open(_path, "w") as _fh: + _fh.write("{not json") + _bad = _RealStore(_path) +check("app/store.py: fresh only when this boot found no state file (a new " + "/data), not after a save and not for an unreadable file", + _new.fresh is True and _old.fresh is False and _bad.fresh is False) _r, _sup = asyncio.run(session(Controller(NEW, STATES, Store({"auto": True}), auto=True), NEW, _first)) check("a working site's /config/model says no", _r["model"]["setup_needed"] @@ -399,8 +439,8 @@ check("the battery level reads, and the battery power with its direction", and ("info", "The battery reads 800 W charging now, so check the " "inverter shows the same.") in _c) check("a solar entity below zero, not flipped, looks reversed", - ("warn", "sensor.pv reads below zero now, so its solar production " - "sign looks reversed.") in _c + ("warn", "sensor.pv reads below zero now, so turn on its “Reads " + "negative” switch in the Solar step.") in _c and ("ok", "sensor.pv reads 1 200 W of solar production now.") in tiers(setup_checks(dict(SITE, pv_invert_entities=["sensor.pv"]), entities=ROWS))) @@ -430,8 +470,8 @@ check("with two inverters each is named, and a kW meter is shown as the " "setpoint entity” for b (inverters.setpoint_entity) names.") in _c2 and ("ok", "The battery level for a reads 62 %.") in _c2 - and ("warn", "There is no battery level entity for b, so the add-on " - "holds 0 W.") in _c2) + and ("warn", "There is no battery level entity for b, so pick one in " + "step 2 or the add-on holds 0 W.") in _c2) _dsmr = dict(SITE, meter_source="ha_dsmr", p1_import_entity="sensor.grid", p1_export_entity="sensor.inv1_level") check("import and export are read as their difference", @@ -447,15 +487,36 @@ check("a meter the add-on reads itself: its live reading when it already " meter_now_w=250)) if "meter" in x] == ["info"]) check("an unreadable meter is a warning", - ("warn", "sensor.grid reads unavailable now, so the meter has no " - "reading yet.") in tiers(setup_checks(SITE, entities=dict( + ("warn", "sensor.grid reads unavailable now, so check it in Home " + "Assistant before you start.") in tiers(setup_checks(SITE, entities=dict( ROWS, **{"sensor.grid": {"state": "unavailable", "unit": "W"}})))) _down = tiers(setup_checks(SITE, entities=None)) -check("Home Assistant down: one warning, nothing claimed ok about an entity", - _down[0] == ("warn", "Home Assistant is not answering, so no entity " - "was checked yet.") +check("Home Assistant down: red, because the power request entity cannot be " + "checked (review R4), and nothing claimed ok about an entity", + _down[0] == ("bad", "Home Assistant is not answering, so press Check " + "again once it is back.") and not [x for t, x in _down if t in ("ok", "bad") and "entity" in x]) +# Review R5: meter + solar + battery is the house's use, never below zero. A +# battery giving 1 500 W whose sensor reads it the wrong way (-1 500 W). +_rev = dict(ROWS, **{"sensor.pv": {"state": "0", "unit": "W"}, + "sensor.inv1_battery": {"state": "-1500", "unit": "W"}}) +_bal = ("warn", "The readings add up to -1 098 W of house use, so check each " + "battery's “Battery power sign is reversed” switch in step 2.") +check("a battery sensor reading the wrong way while giving power is flagged " + "(review R5); not once its switch is on, not without solar, not with " + "the battery reading unknown, and not on the normal site", + _bal in tiers(setup_checks(SITE, entities=_rev)) + and not [x for t, x in tiers(setup_checks(dict(SITE, batt_invert=True), + entities=_rev)) + if "add up" in x] + and not [x for t, x in tiers(setup_checks(dict(SITE, pv_entity=""), + entities=_rev)) + if "add up" in x] + and not [x for t, x in tiers(setup_checks(dict(SITE, batt_entity=""), + entities=_rev)) + if "add up" in x] + and not [x for x in (t[1] for t in _c) if "add up" in x]) _fixed = U.ui_to_options(dict(U.options_to_ui(SITE), **{ "ui.contract": "fixed", "ui.fallback": "fixed", "ui.fixed_price": 0.3})) _dyn = dict(SITE, price_provider="generic_dayahead") @@ -667,7 +728,8 @@ check(f"every wizard string is one sentence of at most 25 words, or a name " _rendered = [x for notes in ( setup_checks(SITE, entities=ROWS), _c2 and setup_checks(_two, entities=ROWS), setup_checks(SITE, entities=None), setup_checks(_hw, entities=ROWS), - setup_checks(_fixed, entities=ROWS), setup_checks(dict( + setup_checks(_fixed, entities=ROWS), setup_checks(SITE, entities=_rev), + setup_checks(dict( SITE, soc_entity="sensor.gone", batt_entity="sensor.grid_x"), entities=dict(ROWS, **{"sensor.grid": {"state": "x", "unit": "W"}}))) for x in (n.text for n in notes)] @@ -682,6 +744,14 @@ check("both restart dialogs name the 0 W, and the shadow one says it stays", in _dialogs[0]) check("the wizard defaults to shadow mode: the switch starts on", "shadowOn: true" in JS) +check("the shadow switch never writes into V, which the Installer view saves " + "too: it goes only on the model the wizard posts (review R3)", + "V[M.setup.shadow.field]" not in JS and "V[s.field]" not in JS + and JS.count("model: posted()") == 2) +check("a skip after a fall keeps saying the reading went down (review R2)", + "wrong: !!k.wrong }; drawStep();" in JS + and "WZ.kettle.wrong ? WS.kettle.skipped_wrong : WS.kettle.skipped" in JS + and 'const wrong = o.say === "none" ? !!k.wrong : o.sets == null;' in JS) _leak = sorted(k for k in TL.config_surface(D.CONFIG)[0] if re.search( r"[^A-Za-z0-9_]" + re.escape(k) + r"[^A-Za-z0-9_]", JS)) check(f"settings.js, wizard included, names no option key ({_leak})", diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py index 6a2d3ed..d430ec9 100644 --- a/goodwe_controller/tools/ux13_demo.py +++ b/goodwe_controller/tools/ux13_demo.py @@ -13,7 +13,7 @@ options, a schema read off config.yaml the way the Supervisor renders it saves in memory, so the Installer view can be clicked through end to end. P4: STATE `new` is a new install (config.yaml's defaults with one power -request entity, an empty Store, control never started), so the page opens +request entity, an empty Store made at this boot, control never started), so the page opens the setup wizard by itself. A one-entity read of sensor.grid steps through KETTLE_READS, so the kettle test sees the kettle go on (up) and then a reversed meter (down). @@ -45,6 +45,8 @@ PRICES = [.24, .22, .21, .20, .21, .22, .24, .27, .26, .22, .18, .16, .15, class Store(dict): + fresh = False # app/store.py: no state file at this boot + def set(self, k, v): self[k] = v @@ -256,7 +258,9 @@ def controller(state): async def main(state, port, host="127.0.0.1"): if state == "new": stored = dict(defaults(CONFIG), setpoint_entity="number.a") - c = Controller(dict(stored), Hass(), Store(), Pub(), + store = Store() + store.fresh = True # a new /data: the wizard opens by itself + c = Controller(dict(stored), Hass(), store, Pub(), stop=asyncio.Event()) c.auto = False runner = aioweb.AppRunner(web.build_app(c, Supervisor(stored))) -- 2.54.0 From 159d7461d8c3b5b6ada8ee28307bef8ba74ebce6 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 28 Sep 2026 08:48:21 +0200 Subject: [PATCH 060/105] UX-15: setup-only mode, and the wizard fixes F1, F2, meter, step 1 A new install names no inverter. When that is the startup gate's only refusal, the add-on now serves the setup wizard in setup-only mode instead of exiting 78. It builds no controller, MQTT client or meter task, its HomeAssistant is read-only (every service call refuses before sending), Controller refuses a read-only HomeAssistant, and /action answers 409. Any other refusal still exits 78. DECISIONS/UX-15-setup-only-mode.md. Wizard fixes from the UX-13 P4 test: - F1: /config/validate converts what it can, so a conversion error blocks its own step and the live checks still run; save 422 carries steps. - F2: saves send the model the page opened (base); only keys this page changed are written onto the blob stored now. - A meter entity missing from Home Assistant is red on the last step. - Step 1 says the reading went down after a skip that followed a fall. Co-Authored-By: Claude Opus 5.5 --- .../DECISIONS/UX-02-two-config-surfaces.md | 5 + .../DECISIONS/UX-13-setup-wizard.md | 22 +- .../DECISIONS/UX-15-setup-only-mode.md | 110 ++++ goodwe_controller/DOCS.md | 32 +- goodwe_controller/app/hass.py | 20 +- goodwe_controller/app/main.py | 18 +- goodwe_controller/app/messages.py | 13 + goodwe_controller/app/setuponly.py | 90 ++++ goodwe_controller/app/static/app.js | 15 +- goodwe_controller/app/static/index.html | 1 + goodwe_controller/app/static/settings.js | 16 +- goodwe_controller/app/store.py | 7 +- goodwe_controller/app/ui_text/en.json | 4 + goodwe_controller/app/uimodel.py | 25 +- goodwe_controller/app/uipage.py | 42 +- goodwe_controller/app/validate.py | 35 +- goodwe_controller/app/web.py | 53 +- goodwe_controller/test_setup.py | 139 ++++- goodwe_controller/test_setup_only.py | 488 ++++++++++++++++++ goodwe_controller/tools/ux13_wizard_blobs.py | 11 +- 20 files changed, 1075 insertions(+), 71 deletions(-) create mode 100644 goodwe_controller/DECISIONS/UX-15-setup-only-mode.md create mode 100644 goodwe_controller/app/setuponly.py create mode 100644 goodwe_controller/test_setup_only.py diff --git a/goodwe_controller/DECISIONS/UX-02-two-config-surfaces.md b/goodwe_controller/DECISIONS/UX-02-two-config-surfaces.md index 76a57dc..81b9ee1 100644 --- a/goodwe_controller/DECISIONS/UX-02-two-config-surfaces.md +++ b/goodwe_controller/DECISIONS/UX-02-two-config-surfaces.md @@ -148,6 +148,11 @@ exits 78 and the panel goes with it. Recovery is the Configuration tab. That is the reason it stays, and the reason the panel refuses to write a blob the validator rejected: this surface must never be the thing that removes itself. +*Amended by [[UX-15-setup-only-mode]] (2026-09-28):* one refused configuration +keeps the panel: options that name no inverter at all and have no other +refusal, which is what a new install ships. The add-on then serves the page in +setup-only mode and commands nothing. Every other refusal still exits 78. + **The panel shows fewer refusals than the startup gate can, never more.** Two of `validate.py`'s rules compare a configured ceiling against the setpoint device's *own* reported range, which is only knowable by asking Home Assistant. diff --git a/goodwe_controller/DECISIONS/UX-13-setup-wizard.md b/goodwe_controller/DECISIONS/UX-13-setup-wizard.md index 5d7387e..2fa8570 100644 --- a/goodwe_controller/DECISIONS/UX-13-setup-wizard.md +++ b/goodwe_controller/DECISIONS/UX-13-setup-wizard.md @@ -25,8 +25,9 @@ The page opens `#setup` only when it is opened with no route, and only when - **`no_power_request`**: the stored options name no inverter to control. - **`first_start`**: this boot found no `/data/state.json` (`Store.fresh`), the Store has no `setup_done` and no `auto` key, and control is not started. - `auto` is the key Start/Stop writes. The startup gate exits 78 before the - controller writes the Store, so a new install's first good boot is fresh. + `auto` is the key Start/Stop writes. Neither the startup gate's exit 78 nor + setup-only mode (UX-15) writes the Store, so a new install's first good boot + is fresh. "Never started" alone is not enough: both TEST-23 add-ons have `auto_start` off and no `auto` key, and one has run in shadow for weeks (review of PR #146, @@ -37,14 +38,12 @@ started or stopped it, is never sent. Without a Store the answer is no. The wiza `setup_done` (an ISO time) to the Store. A save from the Installer view does not. -**Not decided here, for the owner:** the add-on exits 78 before it serves the -page when the stored options name no power request entity, which is what a -brand-new install ships (config.yaml's `setpoint_entity: ""`). So on a truly -new install the installer fills in "Inverter setpoint entity" on the -Configuration tab first, and the wizard opens on the next page visit. -Serving a setup-only page from a refused configuration would change the CFG-01 -startup gate and UX-02 §4 ("the panel is not available when it is most -needed"), so it is left as an open question. +**Decided since, in [[UX-15-setup-only-mode]] (owner, 2026-09-28):** a +brand-new install ships `setpoint_entity: ""`, and it no longer exits 78. When +naming no inverter is the gate's only refusal, the add-on serves the page in +setup-only mode, which commands nothing, and the wizard opens with +`no_power_request`. Setup-only mode writes no Store file, so the first-run +rule above still holds for an install set up on the Configuration tab. ## 3. The kettle test and the sign checks @@ -96,6 +95,7 @@ fingerprint was not handed out by this process, it falls back to `changed`. it), step blocking, the first-run rule on new and TEST-23 sites, the live checks, the save through the P2 path, the stale fix, and the words. - tools/ux13_wizard_blobs.py produces every blob the wizard can save from a new - install and three TEST-23 sites (88 accepted by the shipped validator). At P4 + install and three TEST-23 sites (88 accepted by the shipped validator). + UX-15 added the shipped defaults as a start (setup-only mode). At P4 all 88 were accepted by Supervisor 2026.08.0's `AppOptions`, offline, 78 keys each. diff --git a/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md b/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md new file mode 100644 index 0000000..7265a50 --- /dev/null +++ b/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md @@ -0,0 +1,110 @@ +# UX-15 — setup-only mode: a new install serves the wizard + +**Status: DECIDED 2026-09-28 (owner decision; UX-15 dev).** Card +6aba0053d27a32cb3f210dcc. Changes the CFG-01 startup gate and closes the open +question in [[UX-13-setup-wizard]] §2. Amends [[UX-02-two-config-surfaces]] §4. + +## 1. The rule + +`config.yaml` ships `setpoint_entity: ""`, so a new install's options are +refused by rule 1 of `validate_startup_config()`: no inverter to control. +Until now that was exit 78 before any page was served, and the installer had +to fill in the entity on the Configuration tab before the wizard could open. + +The add-on now starts in **setup-only mode** when, and only when +(`setuponly.applies()`): + +- the options name no inverter at all: no flat `setpoint_entity` and no + `inverters` entry, and +- rule 1's refusal (`no_power_request_problem()`) is the gate's **only** + refusal. + +In setup-only mode it serves the page, says it is in setup (banner, `/status` +`setup_only: true`, a WARNING log line) and opens the wizard when the page is +opened with no route (`setup_needed` is `no_power_request`). After the +wizard's save and restart the normal gate applies to the saved options. + +## 2. What still exits 78, and why + +Everything else the gate refuses, including: + +- a complete configuration that is refused, e.g. `maintenance_charge_w` above + `max_w`; +- no power request entity **and** any other refusal; +- an `inverters` list whose entry has a blank power request entity. + +These are configurations somebody edited. The Configuration tab stored them, +the log's refusal banner names each problem, and the tab is where they are +fixed (UX-02 §4). Serving the wizard there would put a six-step setup in +front of someone who needs to change one field. A narrow rule also keeps the +setup-only decision to one comparison against one known sentence, so a new +validator rule cannot widen it by accident: any other refusal fails the +equality and exits 78. + +The cost: an installer who first sets, say, a DSMR meter with no entities on +the Configuration tab and leaves the power request entity empty gets exit 78, +not the wizard. The log then names both fields. + +## 3. Why it cannot command + +Setup-only mode builds nothing that commands. `amain()` branches to +`setuponly.serve()` before the MQTT broker, the controller, the meter task and +the tariff task are built, and it returns from there when the Supervisor +stops it. What serves the page is `SetupOnly`, which holds no inverter. + +Three checks make it structural rather than a convention: + +1. **The HomeAssistant is read-only** (`HomeAssistant(read_only=True)`). + `call()` refuses before it sends anything, and every service call goes + through it: `number.set_value` (`set_number()`), notifications, all of + them. The flag is fixed at construction, and there is no setter. +2. **`SetupOnly` refuses a HomeAssistant that can write, and `Controller` + refuses one that cannot.** So neither can be built on the wrong one. +3. **`/action` answers 409** in setup-only mode, before + `handle_action()`. Start, Stop and the battery cycle do nothing. + +No MQTT client is created, so nothing is published. The page's other routes +already read only, or write the add-on's own options (UX-02 §6). + +Setup-only mode writes no Store file. The wizard's save writes `setup_done`, +as in any mode. So a new install that is set up on the Configuration tab +instead still has a fresh Store on its first normal boot, and the first-run +rule (UX-13 §2) sends it to the wizard as before. + +## 4. How it is held + +- `test_setup_only.py` part 1: when it applies, including the three exit-78 + cases above. Part 2: the read-only write path refuses with nothing sent, + and the two constructors refuse. Part 3 boots the real `main()` on the + shipped defaults against a fake Supervisor and Home Assistant over HTTP and + logs every request: the page is served, `/status` says setup-only, Start + and the cycle get 409, and there are 0 service calls and no MQTT request, + also with `auto_start` on and a Store that says control was started. The + wizard's save is then booted: it passes the normal gate, does not open the + wizard again, and every write is 0 W (shadow). Part 4: the refused + configurations exit 78 and serve nothing. +- Mutations, each red: `applies()` always false or always true, the + read-only refusal removed, the Controller's check removed, `amain()` giving + setup-only mode a writable HomeAssistant, `/action`'s 409 removed, and the + `return` after `serve()` removed. +- TEST-23: a real container on the shipped defaults, with the Supervisor + stand-in logging every service call (the PR has the evidence). + +## 5. The wizard fixes in the same card + +- **F1.** `/config/validate` converts what it can of a page model + (`uimodel.ui_to_options_partial()`), so a conversion error blocks its own + step beside its field and the live checks still run on the rest. A refusal + about a key the failed conversion writes is left out, because it would + judge the stored value. The save still refuses such a model (422, with + `steps`). +- **F2.** A save from the page model sends `base`, the model it opened. The + add-on writes only the keys whose value differs from `base`, onto the blob + stored now (`uipage.only_edits()`). So "save again to keep yours" after a + 409 keeps the other surface's changes. A key both surfaces changed takes + this page's value, which is what the second press after the banner means. +- **Meter entity.** On the last step a meter entity Home Assistant does not + have is red, like a missing power request entity, so a skipped kettle test + cannot let it through. In the Installer view it stays a warning. +- **Step 1 after a skip.** When the kettle test saw the reading fall and was + then skipped, step 1 says the reading went down. The skip stays (UX-13 §3). diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index d5367cc..7493bdc 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3233,19 +3233,35 @@ the last step. sign for you; with a net or import/export meter it tells you what to change. - **The last step** runs the add-on's own start checks and reads Home Assistant: the meter reading, that each power request entity exists, the - battery levels, and whether prices are known. A missing power request entity - is red, so it cannot be saved. + battery levels, and whether prices are known. A missing power request or + meter entity is red, so it cannot be saved. - **Save and restart** saves, then restarts the add-on. Every inverter is set to 0 W while it restarts, and with "Start in shadow mode" on (the default) it stays at 0 W until you turn shadow mode off under Settings. Setup opens by itself on a new install's first start, until Setup finishes or control is started, and whenever the stored settings name no inverter to -control. A site that already ran before is never sent there. The add-on does -not start with no power request entity at all, so on a brand-new install fill -in "Inverter setpoint entity" on the Configuration tab first. +control. A site that already ran before is never sent there. -*For installers: card UX-13, and `DECISIONS/UX-13-setup-wizard.md`.* +A new install names no inverter yet, so the add-on starts **in setup**: it +serves the page and sends nothing to any inverter. Home says "Setup: the +add-on controls nothing until setup is done", and there is no Start button. The +installer's steps: + +1. Install the add-on, turn on **Watchdog** on its Info tab, and start it. + Leave the Configuration tab as it is. +2. Open the add-on's page. Setup opens by itself. +3. Go through the six steps and press **Save and restart**. With "Start in + shadow mode" on, every inverter stays at 0 W after the restart. +4. On Home, check the meter direction and what the add-on would do. Turn + shadow mode off under Settings when it looks right. + +Any other problem in the stored settings still stops the add-on (exit code 78), +and the log names each one. Fix those on the Configuration tab. + +*For installers: cards UX-13 and UX-15, `DECISIONS/UX-13-setup-wizard.md` and +`DECISIONS/UX-15-setup-only-mode.md`. In setup the `status` JSON has +`setup_only: true`, and no MQTT entity is published.* ## Status page @@ -3260,6 +3276,10 @@ inverter stays at 0 W. If the banner is red and says a safety stop stays on, one of the red rows below is a stop that will still be there when shadow mode ends. That row says how to clear it. +In **setup** (a new install that names no inverter yet) the banner says the +add-on controls nothing until setup is done, and the one row says to finish +Setup. See *Setup, for a new install*. + | Row starts with | What it tells you | |---|---| | Control | When control last ran. Red when it has stopped running: the control board then sets the inverter to 0 W. | diff --git a/goodwe_controller/app/hass.py b/goodwe_controller/app/hass.py index a2546c1..2f75fa7 100644 --- a/goodwe_controller/app/hass.py +++ b/goodwe_controller/app/hass.py @@ -51,10 +51,18 @@ class Outage: OUTAGE = Outage() +class ReadOnly(RuntimeError): + """A service call on a read-only HomeAssistant (UX-15 setup-only mode).""" + + class HomeAssistant: - def __init__(self, session: aiohttp.ClientSession, token: str | None = None): + def __init__(self, session: aiohttp.ClientSession, token: str | None = None, + *, read_only: bool = False): self.session = session self.token = token or os.environ.get("SUPERVISOR_TOKEN", "") + # UX-15: setup-only mode reads Home Assistant and calls no service. + # Fixed at construction; `call()` refuses before it sends anything. + self._read_only = bool(read_only) self._last_moan: dict[str, float] = {} if not self.token: _LOG.error("SUPERVISOR_TOKEN missing - is this running as an add-on?") @@ -181,7 +189,17 @@ class HomeAssistant: return None return (_f("min"), _f("max"), _f("step")) + @property + def read_only(self) -> bool: + return self._read_only + async def call(self, domain: str, service: str, data: dict) -> bool: + if self._read_only: + # Every service call, `number.set_value` included, goes through + # here, so setup-only mode has no way to command (DECISIONS UX-15). + _LOG.error("Setup-only mode called no service, because it may not " + "command anything.") + raise ReadOnly(f"{domain}.{service} refused: setup-only mode") try: async with self.session.post( f"{CORE_API}/services/{domain}/{service}", diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 30df409..bdce450 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -87,9 +87,11 @@ from .watchdog import ( AGAINST_METER, AGAINST_OWN_POWER, SIGN_OPTION_DEFAULTS, SignWatchdog, SignWatchdogConfig, loop_is_following, ) +from . import setuponly from . import web OPTIONS_PATH = "/data/options.json" +INGRESS_PORT = 8099 _LOG = logging.getLogger("goodwe") # ⚠️ `UNIT_A` NOW LIVES IN app/inverter.py AND IS RE-EXPORTED HERE, because the @@ -375,6 +377,11 @@ class Controller: def __init__(self, opts: dict, hass: HomeAssistant, store, mqtt_pub, *, stop, peak_db_path: str = "/data/tariff.db", price_history_path: str = "/data/price_history.json"): + # UX-15: a read-only HomeAssistant belongs to setup-only mode, which + # builds no controller. Refused here so no controller can hold one. + if getattr(hass, "read_only", False) is True: + raise ValueError("a controller cannot run on a read-only " + "HomeAssistant (setup-only mode)") self.o = opts self.hass = hass self.store = store @@ -6011,6 +6018,15 @@ async def amain() -> None: _dev_min, _dev_max, _ = await hass.limits(_sp) _LOG.info("setpoint device %s reports range %s…%s W", _sp, _dev_min, _dev_max) _problems = validate_startup_config(opts, _dev_min, _dev_max) + # UX-15: a new install names no inverter. When that is the ONLY + # refusal it serves the setup wizard in setup-only mode, which builds + # nothing that commands and returns when stopped. Any other refusal + # still exits 78 (DECISIONS/UX-15-setup-only-mode.md). + if _problems and setuponly.applies(opts, _problems): + await setuponly.serve( + opts, HomeAssistant(session, read_only=True), store, + port=INGRESS_PORT) + return if _problems: refuse(_problems) raise ConfigRefused(_problems) @@ -6054,7 +6070,7 @@ async def amain() -> None: stop = asyncio.Event() controller = Controller(opts, hass, store, pub, stop=stop) - runner = await web.start(controller, port=8099) + runner = await web.start(controller, port=INGRESS_PORT) loop = asyncio.get_running_loop() for sig in (signal.SIGTERM, signal.SIGINT): diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 7fbeada..4750030 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -382,6 +382,16 @@ def banner_stopped() -> str: return "Stopped — the inverters are set to 0 W" +def banner_setup_only() -> str: + """UX-15: setup-only mode, where the add-on serves the page and commands + nothing (app/setuponly.py).""" + return "Setup: the add-on controls nothing until setup is done" + + +def row_setup_only() -> str: + return "No inverter is named yet, so finish Setup and restart the add-on." + + def banner_shadow(latched: bool) -> str: """SAFETY-10: first in the cascade, never displaced by another banner. @@ -861,6 +871,7 @@ HINTS = { "control_stopped": "Control stopped", "settings_saved": "Settings saved, they apply after a restart", "restart_requested": "Restart requested from the settings page", + "setup_only": "In setup, nothing is sent to any inverter", "roster": "Inverter list read: {n} inverters", "maint_history": "Maintenance history did not move over cleanly", "stop_restored": "{unit}: an earlier safety stop is back, it stays at 0 W", @@ -952,6 +963,8 @@ def status_samples() -> list: ("banner_peak_reserve", None, banner_peak_reserve()), ("banner_power_too_high", None, banner_power_too_high()), ("banner_shadow", None, banner_shadow(False)), + ("banner_setup_only", None, banner_setup_only()), + ("row_setup_only", AMBER, row_setup_only()), ("banner_shadow", None, banner_shadow(True)), ("row_controller_starting", GREEN, row_controller_starting()), ("row_controller_ran", GREEN, row_controller_ran(2)), diff --git a/goodwe_controller/app/setuponly.py b/goodwe_controller/app/setuponly.py new file mode 100644 index 0000000..0e0a6b2 --- /dev/null +++ b/goodwe_controller/app/setuponly.py @@ -0,0 +1,90 @@ +"""UX-15: setup-only mode. A new install serves the setup wizard and commands +nothing. The rule and the argument are in DECISIONS/UX-15-setup-only-mode.md. + +`applies()` says when: the startup gate's only refusal is that no inverter is +named. `serve()` then runs the ingress page on a `SetupOnly` stand-in for the +controller. Nothing that can command is built: no Controller, no inverter, no +MQTT, no meter task. Its HomeAssistant is read-only, so a service call refuses +before anything is sent (hass.py), and `/action` refuses too (web.py). +""" + +import asyncio +import contextlib +import logging +import signal +from datetime import datetime, timezone + +from . import messages, web +from .inverter import roster_entries +from .validate import actuator_writers, no_power_request_problem + +_LOG = logging.getLogger("goodwe.setup") + + +def applies(opts: dict, problems) -> bool: + """True when the options name no inverter at all and that is the gate's + only refusal. Anything else refused keeps the exit 78 (CFG-01).""" + return (not actuator_writers(opts) and not roster_entries(opts) + and list(problems) == [no_power_request_problem()]) + + +class SetupOnly: + """What web.build_app() needs from a controller, and nothing that writes. + + It holds no inverter and no publisher. `hass` must be read-only.""" + + setup_only = True + auto = False # control is never started here + grid = None # no meter is read here + inverters = () + + def __init__(self, opts: dict, hass, store): + if getattr(hass, "read_only", False) is not True: + raise ValueError("setup-only mode needs a read-only HomeAssistant") + self.o, self.hass, self.store = opts, hass, store + self.events: list[str] = [] + self.hint = "" + + def log_event(self, msg: str, hint: str | None = None) -> None: + stamp = datetime.now(timezone.utc).strftime("%H:%M:%S") + self.events.insert(0, f"{stamp} {msg}") + del self.events[40:] + if hint is not None: + self.hint = f"{datetime.now().astimezone():%H:%M} {hint}" + + def status_payload(self) -> dict: + return {"setup_only": True, "mode": "setup_only", + "banner": messages.banner_setup_only(), "level": "warn", + "rows": [["Control", "not started, in setup"]], + "checks": [{"ok": False, "warn": True, + "text": messages.row_setup_only()}], + "hint": self.hint, "events": list(self.events)} + + async def handle_action(self, what): + # web.py answers 409 before it gets here. Nothing is done either way. + _LOG.warning("The page asked for an action in setup, so nothing " + "was done.") + return None + + async def shutdown(self) -> None: + """Nothing to wind down: nothing was ever commanded.""" + + +async def serve(opts: dict, hass, store, *, port: int) -> None: + """Serve the page in setup-only mode until the Supervisor stops us.""" + controller = SetupOnly(opts, hass, store) + _LOG.warning("No inverter is named yet, so the add-on is in setup and " + "controls nothing. Open its page to finish setup.") + controller.log_event("setup-only mode: no inverter named, nothing is " + "commanded", hint=messages.hint("setup_only")) + runner = await web.start(controller, port=port) + stop = asyncio.Event() + loop = asyncio.get_running_loop() + for sig in (signal.SIGTERM, signal.SIGINT): + with contextlib.suppress(NotImplementedError): + loop.add_signal_handler(sig, stop.set) + try: + await stop.wait() + finally: + await runner.cleanup() + _LOG.info("stopped") diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 8c9530c..2aed6b4 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -94,11 +94,13 @@ function render() { renderPill(); const structured = S.now && S.plan && !S.home_error; - banner($("#home-banner"), S.level, S.banner, structured ? S.state.sub : "", S.level === "bad" ? "alert" : null); + // UX-15: setup-only mode commands nothing and has no control to offer. + const setup = S.setup_only === true; + banner($("#home-banner"), S.level, S.banner, structured ? S.state.sub : setup ? t("setup_only.description") : "", S.level === "bad" ? "alert" : null); ["#c-now", "#c-plan", "#c-peak", "#c-attn"].forEach((id) => { $(id).hidden = !structured; }); if (structured) { renderNow(); renderPlan(); renderPeak(); renderAttention(); } - renderControl(structured); - renderDetails(!structured); + renderControl(structured, setup); + renderDetails(!structured && !setup); renderBatteries(); } @@ -270,12 +272,15 @@ badge.textContent = n; badge.hidden = !n; badge.classList.toggle("bad", list.some((a) => a.severity === "alarm")); } - function renderControl(structured) { + function renderControl(structured, setup) { const running = structured ? S.control.running : null; const btn = $("#btn-ctl"); btn.textContent = running === false ? t("control.start") : t("control.stop"); btn.className = "btn" + (running === false ? " primary" : ""); - $("#ctl-text").textContent = structured ? S.control.text : ""; + btn.hidden = !!setup; + $("#btn-setup").hidden = !setup; + $("#c-ctl .more").hidden = !!setup; + $("#ctl-text").textContent = structured ? S.control.text : setup ? t("setup_only.control") : ""; $("#hint").textContent = S.hint || ""; const docs = $("#docs-link"); if (structured && S.control.docs_url) { docs.href = S.control.docs_url; docs.hidden = false; } else docs.hidden = true; diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html index 3831627..14577db 100644 --- a/goodwe_controller/app/static/index.html +++ b/goodwe_controller/app/static/index.html @@ -72,6 +72,7 @@
      +
      diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index 603dfcb..aa3e9ff 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -533,10 +533,12 @@ if (input) input.focus({ preventScroll: true }); } // The one save path, for the Installer view and the wizard. After a stale - // refusal the page holds the new token, so a second press saves. + // refusal the page holds the new token, so a second press saves. `base` is + // the model the page opened: only what changed since then is written, onto + // what is stored now (UX-15 F2). async function postSave(extra) { const r = await fetch("config/save", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify(Object.assign({ model: V, fingerprint: FP }, extra || {})) }); + body: JSON.stringify(Object.assign({ model: V, base: ORIG, fingerprint: FP }, extra || {})) }); const b = await r.json().catch(() => ({})); if (r.status === 409 && b.kind === "stale") FP = b.fingerprint || FP; return { r, b }; @@ -624,8 +626,10 @@ if (WZ.kettle && WZ.kettle.sig !== sig) WZ.kettle = null; // another meter: test again const k = WZ.kettle || { sig }; box.append(h("div", { class: "help" }, WS.kettle.description)); - const tone = { ok: "ok", flip: "info", none: "warn", unread: "bad", skipped: "warn" }[k.say] || "bad"; - const words = k.say ? WS.kettle[k.say] : k.before != null ? WS.kettle.before : null; + // A skip after the reading went down still says it went down (UX-15). + const said = k.say === "skipped" && k.wrong ? "skipped_down" : k.say; + const tone = { ok: "ok", flip: "info", none: "warn", unread: "bad", skipped: "warn", skipped_down: "warn" }[said] || "bad"; + const words = said ? WS.kettle[said] : k.before != null ? WS.kettle.before : null; if (words) box.append(h("div", { class: "msg " + (k.say ? tone : "info"), role: "status" }, say(words.description, { w: k.before != null ? watts(k.before, true) : "", d: k.d != null ? watts(k.d) : "" }))); const busy = (b) => { b.disabled = true; }; @@ -715,7 +719,9 @@ if (!b) { toast(WS.check.failed.description); return; } if (WZ.blocked) { toast(WS.check.blocked.description); return; } const shadow = shadowValue() === M.setup.shadow.on; - ask(shadow ? WS.dialog : WS.dialog_live, async () => { + // In setup-only mode nothing runs yet, so no inverter is set to 0 W first. + const dlg = M.setup_only ? (shadow ? WS.dialog_setup : WS.dialog_setup_live) : (shadow ? WS.dialog : WS.dialog_live); + ask(dlg, async () => { wzBanner(); let res; try { res = await postSave({ setup: "done", model: posted() }); } catch (e) { toast(W.toast.failed); return; } diff --git a/goodwe_controller/app/store.py b/goodwe_controller/app/store.py index b3fea7a..c716fd6 100644 --- a/goodwe_controller/app/store.py +++ b/goodwe_controller/app/store.py @@ -581,9 +581,12 @@ def migrate_maint_keys(store, unit: str, roster) -> MigrationReport: return rep +STATE_PATH = "/data/state.json" + + class Store: - def __init__(self, path: str = "/data/state.json"): - self.path = path + def __init__(self, path: str | None = None): + self.path = path or STATE_PATH self.data = dict(DEFAULTS) # UX-13 P4: True when this boot found no state file, i.e. a new /data. # Only the setup wizard's first-run rule reads it (uipage.setup_needed). diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index bd5cb3c..833286e 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -79,6 +79,7 @@ }, "toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."}, "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, + "setup_only": {"description": "Nothing is sent to any inverter until setup is saved and the add-on restarts.", "control": "Control starts after setup.", "open": "Open Setup"}, "batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"}, "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, @@ -192,6 +193,7 @@ "self": {"description": "The add-on reads this meter itself, so Home shows its direction after the restart."}, "skipped": {"description": "The meter direction is not tested, so check it on Home after the restart."}, "skipped_wrong": {"description": "The kettle test saw the meter reading go down, so check its direction in step 1 before you start control."}, + "skipped_down": {"description": "The reading went down when the kettle came on, so check the meter's direction before you start control."}, "tested": {"description": "The meter direction was tested with a kettle."}, "needed": {"description": "Do the kettle test first, or skip it."} }, @@ -206,6 +208,8 @@ "shadow": {"name": "Start in shadow mode", "description": "Recommended, because every inverter then stays at 0 W until you turn shadow mode off under Settings."}, "dialog": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and shadow mode keeps them at 0 W after that.", "yes": "Save and restart"}, "dialog_live": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and then the new settings apply.", "yes": "Save and restart"}, + "dialog_setup": {"name": "Save and restart?", "description": "The add-on restarts with these settings, and shadow mode keeps every inverter at 0 W.", "yes": "Save and restart"}, + "dialog_setup_live": {"name": "Save and restart?", "description": "The add-on restarts with these settings, and then they apply.", "yes": "Save and restart"}, "done": {"name": "Setup is done", "description": "The add-on restarts in shadow mode now, so open Home in a minute to see what it would do."}, "done_live": {"name": "Setup is done", "description": "The add-on restarts now, so open Home in a minute to start control."}, "restart_failed": {"name": "Saved, not running yet", "description": "The restart did not go through, so press Restart now to apply the settings."}, diff --git a/goodwe_controller/app/uimodel.py b/goodwe_controller/app/uimodel.py index 08523ed..ad72b97 100644 --- a/goodwe_controller/app/uimodel.py +++ b/goodwe_controller/app/uimodel.py @@ -20,7 +20,8 @@ import json from .price import FLEMISH_TAXES_COMPONENTS_EUR_KWH from .static_tariff import ProfileInvalid, parse_static_profile -__all__ = ["options_to_ui", "ui_to_options", "REGION_PRESETS", +__all__ = ["options_to_ui", "ui_to_options", "ui_to_options_partial", + "REGION_PRESETS", "arbitrage_from_batteries", "DeriveError", "COUNT", "GROWN"] @@ -32,6 +33,7 @@ class DeriveError(ValueError): def __init__(self, text, code="", field=""): super().__init__(text) self.code, self.field = code, field + self.keys = () # the option keys the failed derivation writes # The page model's inverter count, which show conditions read, and what adding @@ -337,14 +339,31 @@ def options_to_ui(options: dict) -> dict: def ui_to_options(model: dict) -> dict: """The options blob for a page model. Raises DeriveError on a model no blob can express, so the page says so instead of saving something else.""" + out, errors = ui_to_options_partial(model) + if errors: + raise errors[0] + return out + + +def ui_to_options_partial(model: dict): + """(blob, [DeriveError]): every derivation that can be made, and the + stored values (`keep`) for each one that cannot. For the checks only, so a + step can be blocked by its own field and the rest still checked (UX-15 + F1). Never saved: `ui_to_options()` raises instead.""" keep = model.get("keep") or {} out = {k: copy.deepcopy(v) for k, v in model.items() if k not in _MODEL_ONLY and k not in _OWNED and not k.startswith("ui.")} + errors = [] for keys, decode, encode in DERIVATIONS: was = decode(keep) if all(model.get(name) == value for name, value in was.items()): out.update({k: copy.deepcopy(keep[k]) for k in keys if k in keep}) - else: + continue + try: out.update(encode(model, keep)) - return out + except DeriveError as err: + err.keys = keys + errors.append(err) + out.update({k: copy.deepcopy(keep[k]) for k in keys if k in keep}) + return out, errors diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py index 42dfd52..e4564b2 100644 --- a/goodwe_controller/app/uipage.py +++ b/goodwe_controller/app/uipage.py @@ -186,7 +186,32 @@ def to_options(model: dict, stored: dict | None = None) -> dict: """The options blob for a posted page model. A value equal to the stored one is written as stored, in the stored key order, so a save that changed nothing writes an identical blob (the browser reads 3.0 as 3).""" - out = U.ui_to_options(model) + return _settle(U.ui_to_options(model), stored) + + +def to_options_partial(model: dict, stored: dict | None = None): + """(blob, [DeriveError]) for the checks: `uimodel.ui_to_options_partial`, + settled like `to_options`. Never saved (UX-15 F1).""" + out, errors = U.ui_to_options_partial(model) + return _settle(out, stored), errors + + +def only_edits(mine: dict, base: dict, stored: dict) -> dict: + """The blob to save: `stored`, with the keys whose value in `mine` (this + page's model) differs from `base` (the model it opened) set to `mine`'s. + A key this page never edited keeps what is stored now, even when another + surface changed it meanwhile (UX-13 P4 test, F2).""" + edits = {k: v for k, v in mine.items() + if k not in base or not _same(v, base[k])} + gone = {k for k in base if k not in mine} + out = {k: copy.deepcopy(edits.get(k, v)) for k, v in stored.items() + if k not in gone} + out.update({k: copy.deepcopy(v) for k, v in edits.items() + if k not in out}) + return out + + +def _settle(out: dict, stored: dict | None) -> dict: stored = stored or {} for k, v in out.items(): if k in stored and _same(v, stored[k]): @@ -202,6 +227,21 @@ def derive_message(err: U.DeriveError) -> dict: "text": text} +def derive_messages(errors, problems, notes, model, keys): + """The page's messages when part of the model could not become options: + each conversion's own sentence beside its field, then the checks of the + rest. A refusal or note about a key the failed conversion writes is left + out, because it judges the stored value, not what the page shows.""" + failed = {k for err in errors for k in err.keys} + by_key, unanchored = problems_by_field(problems, keys) + kept = [t for k, texts in by_key.items() if k not in failed + for t in texts] + list(unanchored) + kept = [p for p in problems if p in kept] + notes = [n for n in notes if not set(n.keys or ()) & failed] + return ([derive_message(err) for err in errors] + + anchors(kept, notes, model, keys)) + + # --------------------------------------------------------------------------- # # Where a sentence goes on the page # --------------------------------------------------------------------------- # diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 2a27f6d..525e94b 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -808,6 +808,14 @@ class ConfigRefused(Exception): super().__init__(problems[0] if problems else "configuration refused") +def no_power_request_problem() -> str: + """Rule 1's refusal: no inverter to control. UX-15's setup-only mode + starts when this is the only refusal (app/setuponly.py).""" + return (f"{S('setpoint_entity')} is empty, so the add-on cannot control " + "the inverter. Set it to the ESPHome number entity for the " + "setpoint.") + + def validate_startup_config(opts: dict, dev_min=None, dev_max=None, notes: list | None = None) -> list[str]: """Return the list of reasons this configuration must not be started. @@ -828,9 +836,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None, # --- 1. an actuator to write to, and AT MOST ONE WRITER PER ACTUATOR ----- writers = actuator_writers(opts) if not writers: - problems.append( - f"{S('setpoint_entity')} is empty, so the add-on cannot control the " - "inverter. Set it to the ESPHome number entity for the setpoint.") + problems.append(no_power_request_problem()) # SAFETY-28. The §1.5 non-goal, graded on the writers rather than on the # count of option keys. Read `actuator_writers()` for why the old check went # green on the very config this one is here to refuse. @@ -1704,6 +1710,14 @@ WATT_ENTITY_KEYS = ( "p1_phase_export_entities", "batt_entity", "peak_forecast_entity") +# The meter entities each `meter_source` reads through Home Assistant. +METER_ENTITY_KEYS = { + "off": ("meter_entity",), + SOURCE_HA_SIGNED: ("p1_net_entity", "p1_phase_net_entities"), + SOURCE_HA: ("p1_import_entity", "p1_export_entity", + "p1_phase_import_entities", "p1_phase_export_entities")} + + def _entities_read(opts: dict) -> list[tuple[str, str, str]]: """(key, inverter name or "", entity id) for each entity the add-on reads with these options. Keys the chosen meter source or roster shape ignores @@ -1716,12 +1730,7 @@ def _entities_read(opts: dict) -> list[tuple[str, str, str]]: out.append((key, where, e.strip())) source = str(opts.get("meter_source") or "off").strip() - by_source = {"off": ("meter_entity",), - SOURCE_HA_SIGNED: ("p1_net_entity", "p1_phase_net_entities"), - SOURCE_HA: ("p1_import_entity", "p1_export_entity", - "p1_phase_import_entities", - "p1_phase_export_entities")} - for key in by_source.get(source, ()): + for key in METER_ENTITY_KEYS.get(source, ()): add(key, opts.get(key)) entries = roster_entries(opts) if not entries: @@ -1844,7 +1853,7 @@ def setup_checks(opts: dict, *, entities: dict | None, running=None, entity exists in Home Assistant (a write to a missing one is answered 200, SAFETY-77, so only the entity list can tell), the battery levels read, and prices are known. Tier "ok", "info", "warn", or "bad" for a missing power - request entity, which the wizard will not save. Reads nothing itself: + request or meter entity, which the wizard will not save. Reads nothing itself: `entities` is Home Assistant's list by id (None when it did not answer), `running` the options this process started with, `meter_now_w` its meter reading and `prices_known` how many of today's hours have a price. @@ -1855,7 +1864,11 @@ def setup_checks(opts: dict, *, entities: dict | None, running=None, _advise(notes, "bad", ("setpoint_entity",), "Home Assistant is not " "answering, so press Check again once it is back.") else: - _entity_notes(notes, opts, entities, bad=("setpoint_entity",)) + # A missing meter entity is red too (UX-15): with the kettle test + # skipped, nothing else on the way to the save would catch it. + meter_keys = {k for keys in METER_ENTITY_KEYS.values() for k in keys} + _entity_notes(notes, opts, entities, + bad=("setpoint_entity",) + tuple(sorted(meter_keys))) meter = _meter_check(notes, opts, entities, running, meter_now_w) batts = [_card_checks(notes, who, entry, entities) for who, entry in _cards(opts)] diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index 730073a..e21029c 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -31,6 +31,8 @@ of Home Assistant's entity list (app/haentities.py) and writes nothing. UX-13 P4's setup wizard uses the same routes. The one thing it adds that is not options is a Store key, `setup_done`, written when the wizard's save succeeds, so the page stops opening the wizard by itself (uipage.setup_needed). +UX-15's setup-only mode serves these routes from `setuponly.SetupOnly`, which +commands nothing; there `/action` answers 409. """ import io @@ -136,6 +138,10 @@ def build_app(controller, selfcfg=None) -> web.Application: except ValueError: raise web.HTTPBadRequest(text="expected JSON") what = body.get("action") + if getattr(controller, "setup_only", False): + # UX-15: nothing to start or stop until setup is saved. + return web.json_response( + {"ok": False, "error": messages.row_setup_only()}, status=409) result = await controller.handle_action(what) if result is None: raise web.HTTPBadRequest(text=f"unknown action {what!r}") @@ -149,14 +155,23 @@ def build_app(controller, selfcfg=None) -> web.Application: """(body, options, model). UX-13's settings view posts its page `model`, which app/uimodel.py turns into the options blob here, so the validator and the Supervisor only ever see a real blob. The classic - page posts `options`. Raises DeriveError for a model no blob can say.""" + page posts `options`. Raises DeriveError for a model no blob can say. + + With `stored` (a save) and the `base` model the page opened, only the + keys this page changed are written onto what is stored now, so a save + after a stale refusal keeps the other surface's changes (UX-15 F2).""" try: body = await request.json() except ValueError: raise web.HTTPBadRequest(text="expected JSON") model = body.get("model") if isinstance(model, dict): - return body, uipage.to_options(model, stored), model + mine = uipage.to_options(model, stored) + base = body.get("base") + if stored is not None and isinstance(base, dict): + was, _errors = uipage.to_options_partial(base, stored) + mine = uipage.only_edits(mine, was, stored) + return body, mine, model options = body.get("options") if not isinstance(options, dict): raise web.HTTPBadRequest(text="expected an options object") @@ -202,6 +217,8 @@ def build_app(controller, selfcfg=None) -> web.Application: options, store_data(), bool(getattr(controller, "auto", False)), fresh=getattr(getattr(controller, "store", None), "fresh", False) is True), + # UX-15: this process serves setup only and commands nothing. + "setup_only": getattr(controller, "setup_only", False) is True, }) return web.json_response(model) @@ -219,11 +236,19 @@ def build_app(controller, selfcfg=None) -> web.Application: be a second opinion about a rule it does not own. """ try: - _body, options, model = await _proposed(request) - except DeriveError as err: - return web.json_response({"problems": [], "by_key": {}, - "unanchored": [], "notes": [], - "messages": [uipage.derive_message(err)]}) + _body = await request.json() + except ValueError: + raise web.HTTPBadRequest(text="expected JSON") + model = _body.get("model") + errors = [] + if isinstance(model, dict): + # UX-15 F1: a part the page cannot turn into options blocks its + # own step, and everything else is still checked. + options, errors = uipage.to_options_partial(model) + else: + model, options = None, _body.get("options") + if not isinstance(options, dict): + raise web.HTTPBadRequest(text="expected an options object") notes = [] problems, unread = await selfconfig.problems_and_ranges( options, controller.hass, notes=notes) @@ -237,8 +262,10 @@ def build_app(controller, selfcfg=None) -> web.Application: if unread: payload["device_note"] = DEVICE_NOTE % ", ".join(sorted(set(unread))) if model is not None: - payload["messages"] = uipage.anchors(problems, notes, model, - _keys_of(options)) + payload["messages"] = ( + uipage.derive_messages(errors, problems, notes, model, + _keys_of(options)) if errors + else uipage.anchors(problems, notes, model, _keys_of(options))) payload["steps"] = uipage.step_problems(payload["messages"], model) if _body.get("setup"): payload["setup"] = [n._asdict() for n in await _setup_checks(options)] @@ -286,10 +313,14 @@ def build_app(controller, selfcfg=None) -> web.Application: return web.json_response({"error": str(err)}, status=502) try: body, options, model = await _proposed(request, stored_now) - except DeriveError as err: + except DeriveError: + model = posted["model"] + _opts, errors = uipage.to_options_partial(model, stored_now) + messages_ = [uipage.derive_message(e) for e in errors] return web.json_response( {"kind": "invalid", "problems": [], "by_key": {}, - "unanchored": [], "messages": [uipage.derive_message(err)]}, + "unanchored": [], "messages": messages_, + "steps": uipage.step_problems(messages_, model)}, status=422) expect = str(body.get("fingerprint") or "") try: diff --git a/goodwe_controller/test_setup.py b/goodwe_controller/test_setup.py index be86f82..ebcd97c 100644 --- a/goodwe_controller/test_setup.py +++ b/goodwe_controller/test_setup.py @@ -9,7 +9,8 @@ Part 6 the save through the P2 path, and every blob the wizard can produce (tools/ux13_wizard_blobs.py; the Supervisor's own validator runs over the same set in the PR, not in CI, which has no Supervisor image). Part 7 the stale save names only what changed elsewhere (P2 test, finding a). Part 8 the -words. The headless-browser click-through is in the PR. +words. Part 9 UX-15's fixes: F1, F2 with two tabs, a missing meter entity and +step 1 after a skip. The headless-browser click-through is in the PR. Mutating a module this file grades? Read MUTATION.md first (purge __pycache__). """ @@ -51,6 +52,7 @@ DEFAULTS = D.defaults(D.CONFIG) NEW = dict(DEFAULTS, setpoint_entity="number.inv1_power") UI_TEXT = uipage.ui_text() WS = UI_TEXT["settings"]["setup"] +WS_D = UI_TEXT["settings"]["derive"] JS = io.open(os.path.join(HERE, "app", "static", "settings.js"), encoding="utf-8").read() @@ -626,11 +628,15 @@ print(f" {len(_all)} blobs from {len(B.starts())} starts; " check(f"every plan from a new install is accepted by the shipped validator " f"({len(_new)} plans)", len(_new) >= 25 and not [n for n, r in _new if r]) +_empty = [(n, r) for n, _b, r in _all if n.startswith("empty-")] +check(f"every plan from a new install as shipped (no power request entity, " + f"setup-only mode) is accepted ({len(_empty)} plans)", + len(_empty) == len(_new) and not [n for n, r in _empty if r]) check("every plan from the TEST-23 sites is accepted, except where the site " "trades on price with a plan that has no meter or no prices, which the " "last step then lists", all(not r or ("options.arb" in n and "arbitrage_enabled" in r[0]) - for n, _b, r in _all) and len(_ok) >= 80) + for n, _b, r in _all) and len(_ok) >= 100) check("every accepted blob keeps every option key (the Supervisor count, 78)", all(set(b) == set(DEFAULTS) for _n, b, r in _all if not r)) @@ -645,9 +651,11 @@ async def _stale(s, root, sup): model = copy.deepcopy(m["ui"]) model["price_timeout_s"] = 12 # the operator's own edit first = await _post(s, root + "config/save", - {"model": model, "fingerprint": m["fingerprint"]}) + {"model": model, "base": m["ui"], + "fingerprint": m["fingerprint"]}) again = await _post(s, root + "config/save", - {"model": model, "fingerprint": first[1]["fingerprint"]}) + {"model": model, "base": m["ui"], + "fingerprint": first[1]["fingerprint"]}) return first, again @@ -659,12 +667,13 @@ check("the banner's list is the other surface's key only, not the operator's " "own edit", _first_r[0] == 409 and _first_r[1]["changed_fields"] == ["peak_cap_w"] and _first_r[1]["moved"] == ["peak_cap_w"]) -check("`changed` (stored against mine, which the classic page shows as " - "theirs -> mine) is unchanged", - _first_r[1]["changed"] == ["peak_cap_w", "price_timeout_s"]) +check("`changed` (stored against what this page would write) is only the " + "page's own edit, since a save writes only that (UX-15 F2)", + _first_r[1]["changed"] == ["price_timeout_s"]) check("saving again with the new token is the deliberate second press: it " - "stores the page as shown (Discard loads theirs instead)", - _again[0] == 200 and _sup.options["peak_cap_w"] == 3500 + "stores this page's own edit and keeps the other surface's change " + "(UX-15 F2)", + _again[0] == 200 and _sup.options["peak_cap_w"] == 5000 and _sup.options["price_timeout_s"] == 12) @@ -757,6 +766,118 @@ _leak = sorted(k for k in TL.config_surface(D.CONFIG)[0] if re.search( check(f"settings.js, wizard included, names no option key ({_leak})", not _leak) +# --------------------------------------------------------------------------- # +print("\n9. UX-15: F1, F2, a missing meter entity, and step 1 after a skip") +# --------------------------------------------------------------------------- # + + +async def _f1(s, root, sup): + m = await _get(s, root + "config/model?lang=en") + price = copy.deepcopy(m["ui"]) + price.update({"ui.contract": "daynight", "ui.fallback": "daynight", + "ui.day_price": None, "ui.night_price": 0.25}) + none = copy.deepcopy(m["ui"]) + none["inverters"] = [] + none[U.COUNT] = 0 + return {"price": (await _post(s, root + "config/validate", + {"model": price, "setup": True}))[1], + "none": (await _post(s, root + "config/validate", + {"model": none}))[1], + "save": await _post(s, root + "config/save", { + "model": price, "base": m["ui"], "setup": "done", + "fingerprint": m["fingerprint"]})} + + +_r, _sup = asyncio.run(session(Controller(SITE, STATES, Store(), grid=402.0), + SITE, _f1)) +print(f" empty day price: steps {_r['price']['steps']}") +check("F1: a price the page cannot turn into options blocks step 4, beside " + "its own field", + _r["price"]["steps"]["4"] >= 1 + and {"field": "ui.day_price", "card": None, "tier": "bad", + "text": WS_D["no_price"]["description"]} in _r["price"]["messages"]) +check("F1: ...and the last step's live checks still run on the rest", + [x["tier"] for x in _r["price"].get("setup", []) + if "number.inv1_power" in x["text"]] == ["ok"] + and any("402 W" in x["text"] for x in _r["price"]["setup"])) +check("F1: no inverter card blocks step 2, not the last step alone", + _r["none"]["steps"]["2"] >= 1) +check("F1: the save refuses it (422) and says which step to go back to", + _r["save"][0] == 422 and _r["save"][1]["steps"]["4"] >= 1 + and _sup.writes == []) + + +async def _tabs(s, root, sup): + """Two tabs open one blob. A saves a peak limit; B edited only the + timeout, gets the 409, and presses Save again.""" + a = await _get(s, root + "config/model?lang=en") + b = await _get(s, root + "config/model?lang=en") + va = copy.deepcopy(a["ui"]) + va["peak_cap_w"] = 4000 + ra = await _post(s, root + "config/save", { + "model": va, "base": a["ui"], "fingerprint": a["fingerprint"]}) + after_a = copy.deepcopy(sup.options) + vb = copy.deepcopy(b["ui"]) + vb["price_timeout_s"] = 12 + first = await _post(s, root + "config/save", { + "model": vb, "base": b["ui"], "fingerprint": b["fingerprint"]}) + again = await _post(s, root + "config/save", { + "model": vb, "base": b["ui"], "fingerprint": first[1]["fingerprint"]}) + return ra, after_a, first, again + + +(_ra, _after_a, _first_b, _again_b), _sup = asyncio.run( + session(Controller(SITE, STATES), dict(SITE, peak_cap_w=3600), _tabs)) +_moved = sorted(k for k in _sup.options + if _sup.options[k] != _after_a.get(k)) +print(f" A: {_ra[0]}, B: {_first_b[0]} then {_again_b[0]}; B's re-save " + f"moved {_moved}") +check("F2: two tabs. A saves peak 4.0; B, which edited only the timeout, " + "gets the 409 naming the peak limit", + _ra[0] == 200 and _first_b[0] == 409 + and _first_b[1]["changed_fields"] == ["peak_cap_w"]) +check("F2: B's second press keeps A's peak 4.0 and writes only B's own key", + _again_b[0] == 200 and _sup.options["peak_cap_w"] == 4000 + and _sup.options["price_timeout_s"] == 12 + and _moved == ["price_timeout_s"]) +_both = uipage.only_edits({"a": 2, "b": 1, "c": 5}, {"a": 1, "b": 1, "c": 3}, + {"a": 1, "b": 9, "c": 4, "d": 0}) +check("F2: only_edits() keeps every stored key the page did not edit, and a " + "key both edited takes this page's value (the deliberate press)", + _both == {"a": 2, "b": 9, "c": 5, "d": 0} + and list(_both) == ["a", "b", "c", "d"]) + +_gone = tiers(setup_checks(dict(SITE, meter_entity="sensor.gone"), + entities=ROWS)) +check("a meter entity Home Assistant does not have is red on the last step, " + "so the wizard does not save it with the kettle test skipped", + ("bad", "Home Assistant has no entity sensor.gone, which “Grid power " + "entity” (meter_entity) names.") in _gone) +_net_gone = tiers(setup_checks(dict(SITE, meter_source="ha_signed", + p1_net_entity="sensor.gone"), + entities=ROWS)) +check("...for a net or import and export meter too", + [t for t, x in _net_gone if "sensor.gone" in x] == ["bad"]) +from app.validate import config_notes # noqa: E402 +check("...while the Installer view keeps it a warning, which never blocks " + "a save there", + [n.tier for n in config_notes(dict(SITE, meter_entity="sensor.gone"), + entities=ROWS) + if "sensor.gone" in n.text] == ["warn"]) + +check("step 1 after a skip that followed a fall says plainly that the " + "reading went down", + 'k.say === "skipped" && k.wrong ? "skipped_down" : k.say' in JS + and "went down" in WS["kettle"]["skipped_down"]["description"] + and "not tested" not in WS["kettle"]["skipped_down"]["description"]) +check("in setup-only mode the wizard's restart dialog does not claim a 0 W " + "wind-down that nothing runs, and the shadow one says 0 W", + "M.setup_only ? (shadow ? WS.dialog_setup : WS.dialog_setup_live)" in JS + and "0 W" in WS["dialog_setup"]["description"] + and "0 W" not in WS["dialog_setup_live"]["description"]) +check("the page posts the model it opened with every save (F2)", + "model: V, base: ORIG, fingerprint: FP" in JS) + print() if fails: print(f"{len(fails)} FAILED") diff --git a/goodwe_controller/test_setup_only.py b/goodwe_controller/test_setup_only.py new file mode 100644 index 0000000..e880155 --- /dev/null +++ b/goodwe_controller/test_setup_only.py @@ -0,0 +1,488 @@ +"""UX-15: setup-only mode. `python3 test_setup_only.py` + +A new install names no inverter, and instead of exiting 78 it serves the setup +wizard and commands nothing (DECISIONS/UX-15-setup-only-mode.md). +Part 1 checks when it applies. Part 2 the write path refuses in that mode. +Part 3 boots the REAL `app.main.main()` in a child process (this file with +`--driver`) against a fake Supervisor and Home Assistant over HTTP, and logs +every request they get: the shipped defaults serve the wizard with no service +call, also with `auto_start` on, a Store that says control was started and a +Start pressed on the page; the wizard saves; the next boot passes the normal +gate and runs in shadow. Part 4: a refused but complete configuration still +exits 78 and serves nothing. +Takes ~25 s. Mutating a module this file grades? Read MUTATION.md first. +""" + +import asyncio +import copy +import json +import os +import shutil +import signal +import socket +import subprocess +import sys +import tempfile +import time + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) +DEADLINE_S = 60 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def defaults(): + import ux13_demo as D + return D.defaults(D.CONFIG) + + +def state(eid, value, unit="W", cls=None, **attrs): + return {"entity_id": eid, "state": value, + "attributes": dict({"friendly_name": eid, + "unit_of_measurement": unit, + "device_class": cls}, **attrs)} + + +STATES = [state("sensor.grid", "402"), + state("number.inv1_power", "0", min=-2500, max=2500, step=1), + state("sensor.inv1_level", "62", "%", "battery"), + state("sensor.inv1_battery", "0")] + + +# --------------------------------------------------------------------------- # +# The child: the real main(), with only the outside world faked over HTTP. +# --------------------------------------------------------------------------- # +def driver(scenario, work): + """`work` holds options.json, state.json and the files the parent reads. + Every request the fakes get is streamed as `EV [...]` lines.""" + import aiohttp + from aiohttp import web as aioweb + from aiohttp.abc import AbstractResolver + import app.main as M + import app.store + import app.web + import ux13_demo as D + import ux13_wizard_blobs as B + import translations_lint as TL + + def event(*e): + print("EV " + json.dumps(list(e)), flush=True) + + opts = json.load(open(os.path.join(work, "options.json"))) + stored = {"options": copy.deepcopy(opts)} + schema = D.schema_ui(D.CONFIG) + translations = {"en": TL.parse_translation_file( + os.path.join(HERE, "translations", "en.yaml"))} + + # --- the fake Supervisor and Home Assistant --------------------------- + async def h_probe(_r): + event("GET", "/core/api/") + return aioweb.Response(text="API running.") + + async def h_states(_r): + event("GET", "/core/api/states") + return aioweb.json_response(STATES) + + async def h_state(r): + eid = r.match_info["eid"] + event("GET", "/core/api/states/" + eid) + found = next((s for s in STATES if s["entity_id"] == eid), None) + return (aioweb.json_response(found) if found + else aioweb.json_response({"message": "not found"}, status=404)) + + async def h_service(r): + body = await r.json() + event("SERVICE", r.match_info["domain"], r.match_info["service"], body) + return aioweb.json_response([]) + + async def h_mqtt(_r): + event("GET", "/services/mqtt") + return aioweb.json_response({"result": "error"}, status=400) + + async def h_info(_r): + return aioweb.json_response({"data": {"slug": "local_goodwe", + "homeassistant": "2026.9.1"}}) + + async def h_self_info(_r): + return aioweb.json_response({"data": { + "slug": "local_goodwe", "options": stored["options"], + "schema": schema, "translations": translations}}) + + async def h_options(r): + body = await r.json() + stored["options"] = body["options"] + event("OPTIONS") + with open(os.path.join(work, "saved.json"), "w") as f: + json.dump(body["options"], f) + return aioweb.json_response({"result": "ok", "data": {}}) + + async def h_restart(_r): + event("RESTART") + return aioweb.json_response({"result": "ok", "data": {}}) + + async def h_other(r): + event("OTHER", r.method, r.path) + return aioweb.json_response({}, status=404) + + fake = aioweb.Application() + fake.add_routes([ + aioweb.get("/core/api/", h_probe), + aioweb.get("/core/api/states", h_states), + aioweb.get("/core/api/states/{eid}", h_state), + aioweb.post("/core/api/services/{domain}/{service}", h_service), + aioweb.get("/services/mqtt", h_mqtt), + aioweb.get("/info", h_info), + aioweb.get("/addons/self/info", h_self_info), + aioweb.post("/addons/self/options", h_options), + aioweb.post("/addons/self/restart", h_restart), + aioweb.route("*", "/{tail:.*}", h_other)]) + + fake_port = free_port() + + class ToFake(AbstractResolver): + """`http://supervisor` is the fake, on its port.""" + async def resolve(self, host, port=0, family=socket.AF_INET): + return [{"hostname": host, "host": "127.0.0.1", "port": fake_port, + "family": socket.AF_INET, "proto": 0, "flags": 0}] + + async def close(self): + pass + + Real = aiohttp.ClientSession + + def session(*a, **k): + k.setdefault("connector", aiohttp.TCPConnector(resolver=ToFake())) + return Real(*a, **k) + + aiohttp.ClientSession = session + os.environ["SUPERVISOR_TOKEN"] = "test-token" + M.OPTIONS_PATH = os.path.join(work, "options.json") + app.store.STATE_PATH = os.path.join(work, "state.json") + M.INGRESS_PORT = free_port() + kw = M.Controller.__init__.__kwdefaults__ + kw["peak_db_path"] = os.path.join(work, "tariff.db") + kw["price_history_path"] = os.path.join(work, "price_history.json") + + served = [] + real_start = app.web.start + + async def start(controller, port=8099, selfcfg=None): + runner = await real_start(controller, port, selfcfg) + served.append(type(controller).__name__) # listening now + event("SERVED", type(controller).__name__, + getattr(controller.hass, "read_only", None)) + return runner + + app.web.start = start + real_amain = M.amain + root = f"http://127.0.0.1:{M.INGRESS_PORT}/" + + async def ask(s, method, path, body=None): + async with s.request(method, root + path, json=body) as r: + try: + out = await r.json(content_type=None) + except ValueError: + out = None + event("PAGE", method, path, r.status, out) + return r.status, out + + async def scenario_steps(): + async with Real() as s: + await ask(s, "GET", "status") + _st, model = await ask(s, "GET", "config/model?lang=en") + event("STATE_FILE", os.path.exists(app.store.STATE_PATH)) + await ask(s, "POST", "action", {"action": "auto_toggle"}) + if scenario.startswith("setup"): + await ask(s, "POST", "action", {"action": "maint_start"}) + wiz = B.apply(model["ui"], B.BASE) + wiz = B.browser(json.loads(json.dumps(wiz))) + await ask(s, "POST", "config/validate", + {"model": wiz, "setup": True}) + event("STATE_FILE", os.path.exists(app.store.STATE_PATH)) + await ask(s, "POST", "config/save", + {"model": wiz, "base": model["ui"], + "fingerprint": model["fingerprint"], + "setup": "done"}) + await ask(s, "POST", "config/restart", {"confirm": "restart"}) + await asyncio.sleep(3.0) # room for any stray task to write + await ask(s, "GET", "status") + + async def wrapped(): + runner = aioweb.AppRunner(fake) + await runner.setup() + await aioweb.TCPSite(runner, "127.0.0.1", fake_port).start() + task = asyncio.create_task(real_amain()) + try: + t0 = time.monotonic() + while not served and not task.done() \ + and time.monotonic() - t0 < 20: + await asyncio.sleep(0.05) + if task.done(): + event("ENDED_BEFORE_SERVING") + await task + return + await scenario_steps() + os.kill(os.getpid(), signal.SIGTERM) # the Supervisor's stop + await asyncio.wait_for(task, 20) + finally: + await runner.cleanup() + + M.amain = wrapped + M.main() + + +def free_port(): + with socket.socket() as s: + s.bind(("127.0.0.1", 0)) + return s.getsockname()[1] + + +def run_child(scenario, options, state=None): + work = tempfile.mkdtemp(prefix="ux15-") + with open(os.path.join(work, "options.json"), "w") as f: + json.dump(options, f) + if state is not None: + with open(os.path.join(work, "state.json"), "w") as f: + json.dump(state, f) + env = dict(os.environ, PYTHONDONTWRITEBYTECODE="1") + try: + p = subprocess.run([sys.executable, "-B", __file__, "--driver", + scenario, work], cwd=HERE, env=env, + capture_output=True, text=True, timeout=DEADLINE_S) + rc, out, err = p.returncode, p.stdout, p.stderr + except subprocess.TimeoutExpired as e: + rc, out, err = None, e.stdout or "", e.stderr or "" + out = out.decode() if isinstance(out, bytes) else out + err = err.decode() if isinstance(err, bytes) else err + ev = [json.loads(ln[3:]) for ln in out.splitlines() if ln.startswith("EV ")] + files = {} + for name in ("saved.json", "state.json"): + path = os.path.join(work, name) + if os.path.exists(path): + files[name] = json.load(open(path)) + shutil.rmtree(work, ignore_errors=True) + return rc, ev, err, files + + +def page(ev, method, path): + """(status, body) of each page request, in order.""" + return [(e[3], e[4]) for e in ev + if e[0] == "PAGE" and e[1] == method and e[2].startswith(path)] + + +def tail(text, n=12): + return "\n".join(" | " + ln for ln in text.splitlines()[-n:]) + + +if len(sys.argv) == 4 and sys.argv[1] == "--driver": + driver(sys.argv[2], sys.argv[3]) + sys.exit(0) + + +# --------------------------------------------------------------------------- # +print("1. when setup-only mode applies") +# --------------------------------------------------------------------------- # +from app import setuponly # noqa: E402 +from app.validate import validate_startup_config # noqa: E402 + +SHIPPED = defaults() +V = validate_startup_config +check("the shipped defaults are refused only for the missing power request " + "entity, and that is setup-only mode", + setuponly.applies(SHIPPED, V(SHIPPED)) and len(V(SHIPPED)) == 1) +_blank_bad = dict(SHIPPED, maintenance_charge_w=2500) +check("no power request entity AND another refusal: not setup-only, exit 78", + len(V(_blank_bad)) >= 2 and not setuponly.applies(_blank_bad, + V(_blank_bad))) +_complete_bad = dict(SHIPPED, setpoint_entity="number.inv1_power", + maintenance_charge_w=2500) +check("a complete configuration that is refused: not setup-only, exit 78", + V(_complete_bad) and not setuponly.applies(_complete_bad, + V(_complete_bad))) +_list_blank = dict(SHIPPED, inverters=[{ + "name": "inverter-a", "setpoint_entity": "", "soc_entity": "sensor.s", + "batt_entity": "sensor.b", "max_w": 2000, "bms_soc_floor": 10}]) +check("an inverter list whose entry has no power request entity: not " + "setup-only (someone edited it), exit 78", + V(_list_blank) and not setuponly.applies(_list_blank, V(_list_blank))) +_ok = dict(SHIPPED, setpoint_entity="number.inv1_power") +check("a startable configuration: nothing refused, the normal start", + V(_ok) == [] and not setuponly.applies(_ok, V(_ok))) + +# --------------------------------------------------------------------------- # +print("\n2. in setup-only mode the write path refuses") +# --------------------------------------------------------------------------- # +from app import hass as H # noqa: E402 +import app.main as M # noqa: E402 + + +class Session: + """Records every request a HomeAssistant would send.""" + + def __init__(self): + self.sent = [] + + def post(self, url, **k): + self.sent.append(("POST", url)) + raise AssertionError("a request was sent") + + def get(self, url, **k): + self.sent.append(("GET", url)) + raise AssertionError("a request was sent") + + +def _refused(coro): + try: + asyncio.run(coro) + except H.ReadOnly: + return True + return False + + +_s = Session() +_ro = H.HomeAssistant(_s, "t", read_only=True) +check("a read-only HomeAssistant refuses number.set_value before it sends " + "anything", _refused(_ro.set_number("number.inv1_power", 0.0)) + and _s.sent == []) +check("...and any other service call, e.g. a notification", + _refused(_ro.call("persistent_notification", "create", + {"message": "x"})) and _s.sent == []) +try: + _ro.read_only = False + _flipped = True +except AttributeError: + _flipped = False +check("...and read-only cannot be switched off afterwards", + not _flipped and _ro.read_only is True) +_rw = H.HomeAssistant(Session(), "t") +try: + asyncio.run(_rw.set_number("number.inv1_power", 0.0)) + _sent = False +except AssertionError: + _sent = True +check("control: a normal HomeAssistant does send the write", _sent + and _rw.read_only is False) +try: + M.Controller(dict(_ok), _ro, None, None, stop=asyncio.Event()) + _built = True +except ValueError: + _built = False +check("no controller can be built on a read-only HomeAssistant", not _built) +try: + setuponly.SetupOnly(SHIPPED, _rw, None) + _took = True +except ValueError: + _took = False +check("setup-only mode refuses a HomeAssistant that can write", not _took) +_so = setuponly.SetupOnly(SHIPPED, _ro, None) +check("setup-only mode holds no inverter and never says control is started", + list(_so.inverters) == [] and _so.auto is False + and _so.status_payload()["setup_only"] is True) + +# --------------------------------------------------------------------------- # +print("\n3. the real main(): the shipped defaults serve the wizard, 0 writes") +# --------------------------------------------------------------------------- # +_runs = { + "setup": (dict(SHIPPED), None), + # A started-control attempt three ways: auto_start on, a Store that says + # control was started, and the page's own Start (the driver presses it). + "setup_started": (dict(SHIPPED, auto_start=True), {"auto": True}), +} +SAVED = None +for name, (options, st) in _runs.items(): + rc, ev, err, files = run_child(name, options, st) + services = [e for e in ev if e[0] == "SERVICE"] + print(f" {name}: exit {rc}, {len(ev)} requests logged, " + f"{len(services)} service calls") + check(f"{name}: the process served the page in setup-only mode on a " + "read-only HomeAssistant, and exited 0 when stopped", + rc == 0 and ["SERVED", "SetupOnly", True] in ev) + if rc != 0: + print(tail(err)) + check(f"{name}: 0 service calls to Home Assistant (no set_value, no " + "notification), and MQTT was never asked for", + services == [] and ["GET", "/services/mqtt"] not in ev) + _status = page(ev, "GET", "status") + check(f"{name}: /status says setup_only, with the setup banner", + _status and all(b and b.get("setup_only") is True + and b.get("mode") == "setup_only" + and b.get("banner", "").startswith("Setup") + for _c, b in _status)) + _model = page(ev, "GET", "config/model") + check(f"{name}: the page model opens the wizard (no power request) and " + "says setup-only", + _model and _model[0][1]["setup_needed"] == "no_power_request" + and _model[0][1]["setup_only"] is True) + _acts = page(ev, "POST", "action") + check(f"{name}: Start and the battery cycle are refused with 409", + len(_acts) == 2 and all(c == 409 for c, _b in _acts)) + check(f"{name}: setup-only mode writes no Store file before the wizard " + "saves, so the first-run rule still sees a new install", + [e for e in ev if e[0] == "STATE_FILE"][:2] + == [["STATE_FILE", st is not None]] * 2) + _val = page(ev, "POST", "config/validate") + check(f"{name}: the wizard's live checks run and find nothing red", + _val and _val[0][0] == 200 + and not [m for m in _val[0][1]["messages"] if m["tier"] == "bad"] + and not [m for m in _val[0][1]["setup"] if m["tier"] == "bad"]) + _save = page(ev, "POST", "config/save") + check(f"{name}: the wizard saves (200) and asks for the restart", + _save and _save[0][0] == 200 and ["RESTART"] in ev + and "saved.json" in files) + check(f"{name}: the Store gets setup_done from the save", + bool(files.get("state.json", {}).get("setup_done"))) + if name == "setup": + SAVED, SAVED_STATE = files.get("saved.json"), files.get("state.json") + +check("the saved blob passes the normal gate: no refusal, not setup-only", + SAVED is not None and V(SAVED) == [] + and not setuponly.applies(SAVED, V(SAVED)) + and SAVED.get("shadow_mode") == "on") + +print("\n after the restart, on the saved settings:") +rc, ev, err, files = run_child("after", SAVED or {}, SAVED_STATE) +services = [e for e in ev if e[0] == "SERVICE"] +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 " + f"values {sorted(set(writes))}") +check("the next boot passes the normal gate: a Controller serves the page, " + "and it exits 0 when stopped", rc == 0 and ["SERVED", "Controller", + False] in ev) +if rc != 0: + print(tail(err)) +check("...where Start is accepted (200), unlike in setup-only mode", + [c for c, _b in page(ev, "POST", "action")] == [200]) +_status = page(ev, "GET", "status") +check("...its /status is not setup-only", _status and all( + b and "setup_only" not in b for _c, b in _status)) +_model = page(ev, "GET", "config/model") +check("...and the wizard does not open again: setup_done is in the Store", + _model and _model[0][1]["setup_needed"] is None + and _model[0][1]["setup_only"] is False) +check("...and it runs in shadow, even after Start: every service call is " + "number.set_value 0 W", writes and len(writes) == len(services) + and all(w == 0.0 for w in writes)) + +# --------------------------------------------------------------------------- # +print("\n4. a refused configuration that is not only missing setup: exit 78") +# --------------------------------------------------------------------------- # +for name, options in (("refused", _complete_bad), ("refused_blank", _blank_bad)): + rc, ev, err, _files = run_child(name, options) + print(f" {name}: exit {rc}") + check(f"{name}: exit 78 and nothing served, no service call", + rc == 78 and not [e for e in ev if e[0] in ("SERVED", "SERVICE")] + and ["ENDED_BEFORE_SERVING"] in ev) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/tools/ux13_wizard_blobs.py b/goodwe_controller/tools/ux13_wizard_blobs.py index 8b74ee7..d3f7d71 100644 --- a/goodwe_controller/tools/ux13_wizard_blobs.py +++ b/goodwe_controller/tools/ux13_wizard_blobs.py @@ -11,7 +11,7 @@ The wizard edits the page model one step at a time and saves it through uipage.to_options(), like the Installer view. `blobs()` walks each step's choices (meter source and sign, one to three inverters, solar rows, every contract and price source, region, peak limit, shadow mode) from a new -install and from the TEST-23 sites, and keeps what the shipped validator +install as shipped, one with a power request entity, and the TEST-23 sites, and keeps what the shipped validator accepts, because the wizard saves nothing it refuses. test_setup.py checks the set; `--supervisor` runs it through Supervisor 2026.08.0's `AppOptions` offline, as the P2 test did. It touches nothing: no network, no Supervisor. @@ -177,13 +177,14 @@ def apply(model, plan): def starts(): - """(name, stored options) the wizard opens on: a new install (config.yaml's - defaults and one power request entity, typed in the Configuration tab so - the add-on starts) and the TEST-23 sites.""" + """(name, stored options) the wizard opens on: a new install as shipped + (config.yaml's defaults, served in setup-only mode since UX-15), one with a + power request entity typed in the Configuration tab, and the TEST-23 + sites.""" sys.path.insert(0, os.path.join(HERE, "tools")) import ux13_demo as D new = dict(D.defaults(D.CONFIG), setpoint_entity="number.inv1_power") - out = [("new", new)] + out = [("empty", D.defaults(D.CONFIG)), ("new", new)] for f in sorted(glob.glob(os.path.join(HERE, "scenarios", "ux13", "test23", "*.json")))[:3]: out.append((os.path.basename(f)[:-5], dict(D.defaults(D.CONFIG), -- 2.54.0 From 63e7e8a1331629b3e2f45abf0a1f6d42d42ebba5 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 28 Sep 2026 08:54:26 +0200 Subject: [PATCH 061/105] UX-15: mutations fail named checks, not crashes Co-Authored-By: Claude Opus 5.5 --- goodwe_controller/test_setup.py | 15 +++++++++------ goodwe_controller/test_setup_only.py | 10 ++++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/goodwe_controller/test_setup.py b/goodwe_controller/test_setup.py index ebcd97c..4de85cf 100644 --- a/goodwe_controller/test_setup.py +++ b/goodwe_controller/test_setup.py @@ -28,7 +28,7 @@ HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(HERE, "tools")) logging.disable(logging.WARNING) # the validator's own log lines -from aiohttp import ClientSession, web as aioweb # noqa: E402 +from aiohttp import ClientSession, ContentTypeError, web as aioweb # noqa: E402 import translations_lint as TL # noqa: E402 import ux13_demo as D # noqa: E402 @@ -264,7 +264,10 @@ async def _get(s, url): async def _post(s, url, body): async with s.post(url, json=body) as r: - return r.status, await r.json() + try: + return r.status, await r.json() + except (ValueError, ContentTypeError): # e.g. a plain-text 500 + return r.status, {} STATES = [state("sensor.grid", "402"), state("number.inv1_power", "0"), @@ -790,18 +793,18 @@ async def _f1(s, root, sup): _r, _sup = asyncio.run(session(Controller(SITE, STATES, Store(), grid=402.0), SITE, _f1)) -print(f" empty day price: steps {_r['price']['steps']}") +print(f" empty day price: steps {_r['price'].get('steps')}") check("F1: a price the page cannot turn into options blocks step 4, beside " "its own field", - _r["price"]["steps"]["4"] >= 1 + _r["price"].get("steps", {}).get("4", 0) >= 1 and {"field": "ui.day_price", "card": None, "tier": "bad", - "text": WS_D["no_price"]["description"]} in _r["price"]["messages"]) + "text": WS_D["no_price"]["description"]} in _r["price"].get("messages", [])) check("F1: ...and the last step's live checks still run on the rest", [x["tier"] for x in _r["price"].get("setup", []) if "number.inv1_power" in x["text"]] == ["ok"] and any("402 W" in x["text"] for x in _r["price"]["setup"])) check("F1: no inverter card blocks step 2, not the last step alone", - _r["none"]["steps"]["2"] >= 1) + _r["none"].get("steps", {}).get("2", 0) >= 1) check("F1: the save refuses it (422) and says which step to go back to", _r["save"][0] == 422 and _r["save"][1]["steps"]["4"] >= 1 and _sup.writes == []) diff --git a/goodwe_controller/test_setup_only.py b/goodwe_controller/test_setup_only.py index e880155..3da2d5e 100644 --- a/goodwe_controller/test_setup_only.py +++ b/goodwe_controller/test_setup_only.py @@ -339,10 +339,14 @@ class Session: def _refused(coro): + """True only for the read-only refusal; a request that reached the + session (AssertionError there) or no refusal at all is False.""" try: asyncio.run(coro) except H.ReadOnly: return True + except Exception: # noqa: BLE001 + return False return False @@ -372,8 +376,10 @@ check("control: a normal HomeAssistant does send the write", _sent try: M.Controller(dict(_ok), _ro, None, None, stop=asyncio.Event()) _built = True -except ValueError: - _built = False +except ValueError as err: + _built = "read-only" not in str(err) +except Exception: # noqa: BLE001 + _built = True # it got past the check and failed on something else check("no controller can be built on a read-only HomeAssistant", not _built) try: setuponly.SetupOnly(SHIPPED, _rw, None) -- 2.54.0 From 30cba1e58d21a64e29716c254b9ba11fd59ae80a Mon Sep 17 00:00:00 2001 From: Claude review agent Date: Mon, 28 Sep 2026 15:06:12 +0200 Subject: [PATCH 062/105] UX-15 review: shorter setup banner (PR #147) The Home banner title was ten words; UX-08 asks for about six. Co-Authored-By: Claude Opus 5.5 --- goodwe_controller/DOCS.md | 11 +++++------ goodwe_controller/app/messages.py | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 7493bdc..8a8712b 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3244,9 +3244,8 @@ control is started, and whenever the stored settings name no inverter to control. A site that already ran before is never sent there. A new install names no inverter yet, so the add-on starts **in setup**: it -serves the page and sends nothing to any inverter. Home says "Setup: the -add-on controls nothing until setup is done", and there is no Start button. The -installer's steps: +serves the page and sends nothing to any inverter. Home says "Setup: nothing +is controlled yet", and there is no Start button. The installer's steps: 1. Install the add-on, turn on **Watchdog** on its Info tab, and start it. Leave the Configuration tab as it is. @@ -3276,9 +3275,9 @@ inverter stays at 0 W. If the banner is red and says a safety stop stays on, one of the red rows below is a stop that will still be there when shadow mode ends. That row says how to clear it. -In **setup** (a new install that names no inverter yet) the banner says the -add-on controls nothing until setup is done, and the one row says to finish -Setup. See *Setup, for a new install*. +In **setup** (a new install that names no inverter yet) the banner says +nothing is controlled yet, and the one row says to finish Setup. See *Setup, +for a new install*. | Row starts with | What it tells you | |---|---| diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 4750030..32bb31d 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -385,7 +385,7 @@ def banner_stopped() -> str: def banner_setup_only() -> str: """UX-15: setup-only mode, where the add-on serves the page and commands nothing (app/setuponly.py).""" - return "Setup: the add-on controls nothing until setup is done" + return "Setup: nothing is controlled yet" def row_setup_only() -> str: -- 2.54.0 From 39e6c260fe14f2b7af7559683f3ca0b987b97f42 Mon Sep 17 00:00:00 2001 From: Claude review agent Date: Mon, 28 Sep 2026 15:15:51 +0200 Subject: [PATCH 063/105] UX-15 review: DECISIONS states the TEST-23 run that happened (PR #147) It said the PR had TEST-23 evidence, but the PR says TEST-23 was not run. Co-Authored-By: Claude Opus 5.5 --- goodwe_controller/DECISIONS/UX-15-setup-only-mode.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md b/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md index 7265a50..d733a4c 100644 --- a/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md +++ b/goodwe_controller/DECISIONS/UX-15-setup-only-mode.md @@ -87,8 +87,12 @@ rule (UX-13 §2) sends it to the wizard as before. read-only refusal removed, the Controller's check removed, `amain()` giving setup-only mode a writable HomeAssistant, `/action`'s 409 removed, and the `return` after `serve()` removed. -- TEST-23: a real container on the shipped defaults, with the Supervisor - stand-in logging every service call (the PR has the evidence). +- TEST-23 (PR #147 review, 2026-09-28): the add-on image on the shipped + defaults and an empty `/data` made 0 service calls and no MQTT request in + 3.5 minutes of setup-only mode, counted in both the stand-in and the rig + shim logs. The wizard save then passed Supervisor 2026.08.0's `AppOptions`, + and after the restart it ran in shadow: 11 of 11 writes were + `set_value 0.0`. ## 5. The wizard fixes in the same card -- 2.54.0 From 667b8e9145d7f9442ccdbc50a85f5d7ca04b0fa6 Mon Sep 17 00:00:00 2001 From: Claude dev agent Date: Mon, 28 Sep 2026 16:33:32 +0200 Subject: [PATCH 064/105] UX-13 P5: Dutch text, STYLE check, DOCS screenshots, period editor - app/ui_text/nl.json and app/uitext.py: every page word in Dutch, English fallback per key; the page picks by browser language. Home's sentences move into ui_text `home_words`, so /status?lang=nl builds them in Dutch. - test_ui_text.py: EN/NL key and placeholder parity, STYLE limits, jargon lists for both languages, no inline details, untranslated Dutch caught. Shared rules moved unchanged to tools/style_rules.py. - tools/ux13_screenshots.sh/.py: DOCS screenshots from the demo fixtures in headless Chromium; docs/img/ux13/. Battery modes (P3): no screenshot. - "Other time windows": a list editor (ui.periods) that builds static_profile and names bad times, empty prices, overlaps and gaps. Co-Authored-By: Claude Opus 5.5 --- STYLE.md | 2 +- docs/img/ux13/README.md | 9 + docs/img/ux13/home-phone.png | Bin 0 -> 166193 bytes docs/img/ux13/home-running-nl.png | Bin 0 -> 181100 bytes docs/img/ux13/home-running.png | Bin 0 -> 174349 bytes docs/img/ux13/home-setup-only.png | Bin 0 -> 34120 bytes docs/img/ux13/home-shadow.png | Bin 0 -> 194670 bytes docs/img/ux13/settings-installer-nl.png | Bin 0 -> 182800 bytes docs/img/ux13/settings-installer.png | Bin 0 -> 179464 bytes .../ux13/settings-time-windows-overlap.png | Bin 0 -> 227915 bytes docs/img/ux13/settings-time-windows.png | Bin 0 -> 219089 bytes docs/img/ux13/setup-step-1-nl.png | Bin 0 -> 138566 bytes docs/img/ux13/setup-step-1.png | Bin 0 -> 141516 bytes .../DECISIONS/UX-13-one-layout-table.md | 17 + goodwe_controller/DOCS.md | 18 + goodwe_controller/app/homeview.py | 357 +++++++++--------- goodwe_controller/app/main.py | 5 +- goodwe_controller/app/setuponly.py | 2 +- goodwe_controller/app/static/app.css | 4 + goodwe_controller/app/static/app.js | 29 +- goodwe_controller/app/static/settings.js | 51 ++- goodwe_controller/app/ui_text/en.json | 171 ++++++++- goodwe_controller/app/ui_text/nl.json | 307 +++++++++++++++ goodwe_controller/app/uilayout.py | 5 +- goodwe_controller/app/uimodel.py | 139 ++++++- goodwe_controller/app/uipage.py | 36 +- goodwe_controller/app/uitext.py | 51 +++ goodwe_controller/app/web.py | 25 +- goodwe_controller/test_home.py | 21 +- goodwe_controller/test_messages.py | 75 +--- goodwe_controller/test_setup.py | 6 + goodwe_controller/test_ui_text.py | 252 +++++++++++++ goodwe_controller/test_uimodel.py | 103 +++++ goodwe_controller/tools/style_rules.py | 58 +++ goodwe_controller/tools/ux13_demo.py | 22 +- goodwe_controller/tools/ux13_screenshots.py | 96 +++++ goodwe_controller/tools/ux13_screenshots.sh | 43 +++ goodwe_controller/tools/ux13_wizard_blobs.py | 29 +- 38 files changed, 1633 insertions(+), 300 deletions(-) create mode 100644 docs/img/ux13/README.md create mode 100644 docs/img/ux13/home-phone.png create mode 100644 docs/img/ux13/home-running-nl.png create mode 100644 docs/img/ux13/home-running.png create mode 100644 docs/img/ux13/home-setup-only.png create mode 100644 docs/img/ux13/home-shadow.png create mode 100644 docs/img/ux13/settings-installer-nl.png create mode 100644 docs/img/ux13/settings-installer.png create mode 100644 docs/img/ux13/settings-time-windows-overlap.png create mode 100644 docs/img/ux13/settings-time-windows.png create mode 100644 docs/img/ux13/setup-step-1-nl.png create mode 100644 docs/img/ux13/setup-step-1.png create mode 100644 goodwe_controller/app/ui_text/nl.json create mode 100644 goodwe_controller/app/uitext.py create mode 100644 goodwe_controller/test_ui_text.py create mode 100644 goodwe_controller/tools/style_rules.py create mode 100644 goodwe_controller/tools/ux13_screenshots.py create mode 100755 goodwe_controller/tools/ux13_screenshots.sh diff --git a/STYLE.md b/STYLE.md index 1014aae..d86db9a 100644 --- a/STYLE.md +++ b/STYLE.md @@ -7,7 +7,7 @@ This applies to everything a home owner or installer reads: notifications, phone - **Body**: **one sentence** of at most 25 words, saying what happened and what to do. A **red alarm** may use up to **3 sentences** (70 words, each sentence at most 30 words), so that no action a person must take is lost. - **Details**: the last line links to the add-on documentation and names the section with the rest: `Details: add-on documentation, section "" under Notifications.` Background, figures, reason codes and history go there or into the log, never into the body. - **Status row**: one sentence of at most 15 words. A **red** row may use up to 3 sentences (30 words), like a red alarm. It shows the live numbers the reader acts on and never an HA entity id. **Banner**: at most 12 words. **Refusal**: at most 30 words, naming the setting by its label and then its key, as `messages.setting()` writes it: “Inverter rating” (max_w), or “Inverter rating” for inverter-b (inverters.max_w) for one inverter in the list. **Option name**: at most 6 words, not counting the group prefix. **Option description**: at most 30 words. Where a value comes from belongs in DOCS.md. -- **Plan line** (UX-13 Home screen: the plan, tooltips, a battery's "now" line): at most 2 sentences, each at most 12 words. Words from `app/homeview.py`, checked by `test_messages.py` part 8. +- **Plan line** (UX-13 Home screen: the plan, tooltips, a battery's "now" line): at most 2 sentences, each at most 12 words. Words in `app/ui_text/<lang>.json` under `home_words`, built by `app/homeview.py`, checked by `test_messages.py` part 8. The page's own words, English and Dutch, are checked by `test_ui_text.py`. - **Log line** (WARNING/ERROR): one line of at most 25 words **as logged**, with any built text filled in. Log lines stay in English and are not translated. A line that reports a safety reason gives one plain sentence and the reason's code (`STALE_READING`, `OUTPUT_CLAMP`), the evidence an installer searches for. The reason itself, with its figures and limits, goes on a DEBUG line right after it and into the action log, never onto the WARNING/ERROR line. It keeps the shape of a red alarm: at most 3 sentences of at most 30 words. The line as logged has no semicolon, banned word, capitals, "1 times" or "(s)". `test_messages.py` part 6 builds every such text with the real code and checks it, and lists the few non-safety families still over 25 words. A line that repeats every cycle is DEBUG. INFO lines carry no section numbers, ISO timestamps or capitals. - **Refusal length is counted as shown**: a setting placeholder counts as its label and key, and the long cases are driven through the validator (`test_messages.py` part 3). - **Event line** under the buttons: the plain words of `messages.hint()`, like a green row. The add-on's own action log stays technical and is not shown on the page. Installers read it as `events` in the `status` JSON. diff --git a/docs/img/ux13/README.md b/docs/img/ux13/README.md new file mode 100644 index 0000000..ad3fbd8 --- /dev/null +++ b/docs/img/ux13/README.md @@ -0,0 +1,9 @@ +# UX-13 screenshots + +Made from the real page by `goodwe_controller/tools/ux13_screenshots.sh`. Do not +edit them by hand: run the script again. + +- `home-*.png`: Home, running, in Dutch, in shadow mode, at phone width, and in setup. +- `settings-*.png`: Settings (Installer view), and the time-window editor with an overlap. +- `setup-step-1*.png`: Setup, step 1. +- Battery modes (the Batteries screen and the Simple view): not built yet (UX-13 P3), so no screenshot. diff --git a/docs/img/ux13/home-phone.png b/docs/img/ux13/home-phone.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3788f4374959070fa2347bb3db9457d2d026e9 GIT binary patch literal 166193 zcmbrlWl$v1*XD`4ySvkP<L(qrA&oWGNaKyWJ2X~}ySux)ySp{+(6}@8e>dLPh}qcL z*_irJA2PF&<lLM0ob%k@6QQasi;6^q1OWko3XqcmLO?)<LO>u?AV7hS^efGAKtNzX z0Hnk<+%wKIVa13Qu!qszz#m3j`AzWWeeplvo13VoESHy;G%#I&s>x(J%AY$qw_Y92 z_V&|PAG}=c&CFSU(p4xB0#%_Mpu{nPIdf<z5hN&8K^QQ(7z_aLafAdK7;y#|d8|MR z94J~uaSWsYP%s5Th!{WuBUs}9<#H)hIiN!XLl6dYz&3CenCBRdQD{O{n3qRu0wby4 z5G;nVzg?sY(f~36d*T=vajDDX87YDKOcLx;#wt<@1e_+$YVl)ZL=OAMwU1Y#ah8~v znCjR++;|^dFV-WYmhFjuEtYXNHSxT^KJI0@{M$X4nTab@NX9^ztHGcxL+X_J(yiSl z;5h(WfutqJTzZE@O`R_xAwksI-kaT?Zf%TddvbH2kjzp&Qm5B!YuMxs>vc1mKiuj0 zNLwN<W+Y~#PqMAUQOf}-E)Em;m9Oll?2N(yG9i|f5;PnTQxX`QqY#ew%}QJocac$@ zuAW}6(T2nJ<+rh9*vk4kvH`n@h=Kn3Cp{$#3kw%@kQhcmOi3h7K)2QiMxF``Gd{Ml zMsLuMA4VnU-2eb%0TnGheYTK?00p}$P(nghrC8}~iKU~Xub+CU;ye5$`jcn=@Net+ zqWjm!tNi>QoSa-nKou4Hi!{v|8%xWR#<OM7XYWv{e3{Gd?XK~Oi6P!_K^%5(11{Fz zKHvVGUA}u2718mpwlZsd`Ek|%a!<V0WWB!9A7s7#bcw>x%*J*#k;*0N<HNnM2#-!Q z(2CPaY`@+0Cn4^9CbzREpZ@LbjZDZJhYZv1hwXgn4|rr`WX{itRi{-Q9TwdtK95}- zoAI$VtKHy#`+q4Aq)Qt1v~=Zh*e|FtCBoSyH3~H~3o<e?e#oknl$Eu%31EM@AmDUf zxjmXD_G*bG6P{ZbaNZpl-N~`EvQkX@+PgtQrj0D;&izOtX#VwWY?QHQ-ygD@noqr0 zMbziih8q3Rd@^mT!^dm4V03krA4Y*%#QW*`aB@8)3U73DOh-rCpv9eogCky_Ntos0 z=79OZ)m8shYiX+Ii$JD`_dto)BYBhU{Lt*I!$lh^;y=W5*yXD4-L~t>#MWo77i(K> zKCgr0$!4S<<H>BV55#ft@vFt(>@68fbNfU6-k#z!aIs0>FV-JJknxELiBU;bKF5=* zxh$sWFoNYZ)>arPrL5U~H4e4p2aP06q@>Swc6axB8Umzz4K8D|yYKFtAFtN)^YSEW zDzM!9EEKcNZER5fD5ZUUzB`$Z!e<k3J%^y108i&$2WneF1`HAsDn`mF9@{Fz?!WJ| zN2B@hWmZ<~t6e_rRhym}LM}*4GI)Gmmv0Bm_$(}6#B+J<S3Qp|JOAwsNqj`>HLo{X z)6>%rH)cb*9*!lJ|NZ;7*>01a^J}n96>C*yyEAPv5)zt#+sE7CB(azC71|#by{7Zk zdi?EMRUoj=@!(X8MKADK=5YVuXgafb=eeF92n4Y|KWw&Vt~a}#ZeY&o>gxKuJg6wj z&n?YSVFVLttjPza`Q~YrEQFexnvPsIS==6GWlhcj=VQnOwZ=FboSmJU?AMX7An@dE zY&Mdo4NVKofa>#1b!)u#+i9t3p}`>@uTMSM)!EsFA+R(nux&0EP@YmXRxfSNCyrNJ zKAfLZ7lN6BZinA<{WJeP-<3)uvjJlvu(5wYL;G;PpUmUq;x5{K_hZHhkBTZs-X@KS ziGhnC6x#n(HauIZoSy@V`g}+!_q_mwsZu}%fEo>u7{-{YC3A!tP!9w{Ty|a5(zhNT zAFt{F*PHC?le%c(cC{(!aibw7mQz+1nVRb1?VS<Rq%5sPjEjrPy3!jI#?R%_(6DMr zO-=3ErhcSMubhQ~f&!yX%TL=V9d+ovtg|#VFgUcz|8{U(TC2!K!Na4aq@<~F_gO5d zsmU!scli29{yCYgayXI6Rjghd<KXZQX8i5>lZ=R{$KIsRo?KP-Te7f%MsRCiU?3Ef zID@1n2`@OvQ=vU54z8}g_ov))bIaA+hm+}|ejgp3UXO8PV?)vDVwg;IWB>r7p4a-j z*JF~Vn8fbqVvKSOT9J9tBe_t){4s{cVaA|L&y;^|azes@PD@QqxMEL5a4^i2P6O59 z7iQ-1_gCMm^ddSZTgRIl81>EF%E}7g<bv59{NG<3u`2k%52IK}?p0z(Z548AQ&LmI z&ch=E01(b$Y-p;hlXH1~6*Pfr>tSVNWK1=@{)|7TDWpM;jFkTjUdqhOc=LUBSi_vo z>hwo&&{@A&Dje?*L%-VYM#pvXMn+g6q_-$OE+KFQTo+47O8Q-e)?;hL(SBflsp%8( zc~Pt>7~4gcmyeA5VQUK;VZZ(9=fC6CS6x_08$fX%pv&nItYoYPNqG5ueBpDuWLu&E zg<qui&HO98RU;=CSD<9zC}`d7d}4B%nem;JZ+Uq>DD8fvgyF$d%lxqOwOdjGdni_2 zODk2_!p=w)Lt|f@c5T6Oer|r;re&c~Z~6F`V1}EQ_gfb%%=tu40JQr2TnvdYTqHIT zmVm{jUk#Tj$F%umMkWcb{T5UoOw2xb`9-pn_FhKUw8?QBjv<AoWnyIwz0VNvfU`nh zHD-j#<wKPMi6O|ukf8eI%S5l%7()xS4abrOynIPnY*RX8%@lk*o+bVea5*WXU=#H| zR&A=dyWG?Rs5z|EU|y`b`4<Wa38j6tLy3gbRAV#j42*1=FIJJ*F`wz_jTTDNZ}aw8 zo+7nfZ(_CPrEs^gwqCE)Ypz2AN4kV|qs8|k0=wAef&>nobSdA9w<Mi984DkOyUoQ~ zPOc=qT{cR~Hj;2KU*`80Yiw+KWdct3>pM%XbJC2q`(sOMi`(rE517COY$+x|2sgCv zGCdo^+fFeefGEWxM236@>a`_+v9gL1<3C4zF4zd7sE#6VZla@GTUiN@aA-DSV9E<v z&C9Q>tg2G3AtHf=g&iFoJv%$ArDg*!^*TB_2Wv#Cv4<y%H*cx)7#d}3Q~nV!dc3^6 zN5qjx$f)xRa~i6u6l3`{B@BFgD<d=E&c_%9U8;XT32|y0){-p+DdCj?4gL&P`U1j? z_3m13(UdG22muQ@G>F6q?{W&`Bm&-id<;(`@scos6q<Q--N=Z)nS)!d{d^iczXHE7 znGb~*(mpY$+ld3x4{`%)L!_X0H=dEh&`5cBI7FPUAp$7mG)qUdfesw?dGcByM#*Bs z0`zUd#Ej9SGaV1YLz$D`Wqy4!;^xz7gakW}*B`>Jda^L$W&Wyt>lg|G&tFgz06JY0 zDk_|ggn!Tmyitc;JrM%m$aB4Cx-aFiGJA1~4x=QD9JLh^2{*qYz=+4)lz0Fl<%%LA zu&RnUM|B2kEuAG%BM?a!J)%lSqHGDO6u<@EFK`TKrpgwUfk}LPsn6dR<1Qv1!ph;! ze!;d<c1(Wx5^2aofzYR<Bo8XA!g;f6&2qj{PYOq%q*OjG2b{O2_i29N$wceM699q( zGqSx<Kyy+muXtYaaI81g9R3Mk+3U8)R0JO2HG?kMAGF|Va^K#n<=%A?xTi#GF`*}s z&p``RR8-VcsFz)iQATT$YE1q5<0I_=`Rl@BxD_@Qk?-Ea`^po{cT!unX}T;WB2BA* z;Id(+h5_H=H4+Cc_P2=J-?cjF#53(WU^)XMqsQx3vGgt7zA0)JLqYBwMre{Z-rL`q z*Qi{^iJ8RK(Afd=pfz0{mh$U4*!sJBX9WcX9}z#nU;F!!gHA3D<?F?}6Qz5JIOCso zLA^#oKL3UWMrP&$Kac1l0HcBrWOnOy&jSwBoSgNs*#g;_nVYSWdU<`p(o)@?uU&zj zYTQhX5mZDMbB%g7fU=#4v5^VS+pTsFY;;XcGpOfb484vP#~%T+@>ae^pt?9LX1@#& zeZUpncZ00BOrVBhkf_|oy_a#mnR(Gv@#t>Q@U(EcCj%2xczF2n*@^e(NpWduRaxHK z-6}Kk?KY>w)n9dLXdh3G_k%OH-@70#{HiB-xU-Yfk<n2+9K0LzKB}$kuC!F5paa-Q zYDPwff2T?#;9_ub!AOf+MrLrM?e+S8J+}J|3JD46!lq*X;NXdDys*4^CxTSiB(5PL zp$?Q6nAg!fjlW`?0-N6M^EeBCrDEjfUm$^Y?rq@P`^Ta>OT;fTIosaK=C1c>yfaJ% z^he$A1vVv>z~X2h9GJqQLc?yC>CHucT5i;(>)pln{R9nUE^I#N>;2Cg)SoAV30IF> z*?B*9QBdz%ToE6hmo{a=PrZM55R~F*3xx(_diSsXn@U!9O!#jeo;h$j`mG{I)9iJ* z+laoEJ<r7n9VoHWaD4Lf4}GLe@vU%lc9(DW;|`+@a^#7nb!r+xFA(M?R_&w+)TpJR z)r%V7qtUC#+U5J1n2=y&^HWtr%IoC@RggUE7g01^>La<x?Z=zT#<6kCLz5R83AHx) z@r^lDY<6eCeCo%}S@Tu(cH4Hob@7&PTLzyGBR?%Fj_Gn2b!h0z4;d6JeC%&P;KI_< z7whC6L+ky^i7aO~hcwZ!)zM}{v6<DVZ+gu(Tg~4d1s}=#v5`|necn~FT8~f9Ap~y^ z*3mJLG16pMl~1k8HU*l&H<D9S^u0fPKXW5b=dnvj%<Ob{HE<u1MJGql<M;YUv|QvP z;`2J9%R-;~H=g%O=zOj8BAgOhOp8p&bEpw<CX=NdjZbh@C6yg0BV+#g_fHLuS9{hZ zk(<r7jG`hAQhMzR5xok|_B;V0sn_4RXe|S!*T)kzZB<jF9NANxn`$-7VI{?af)=f| z?NC(B0&Q(wXIL(Pa%MZ!)s_uArK1zLHiU7Ao~W?tqD791e0ex$VrJgEJazs%hN|sv zUlbT9bObb*O#5lgu^y6^MkF&h5FQyB9vRVO_ZN|$r6bLt(;<w3c!g1iP$XA?T~TaL zQ7OgMu=t^}ci`tn_$oOzfqsF*(dju39@*?dzmkdyFU=RIx>4A@U2NV81E{=TdsEQ( zvVxAKUBc~^y4{6-*_RpVDcrVDSFU?|*ilg@H;#2is7i#QkrVqH!3hQXef;wyE2@vI z7prp<TdXUI*N(<lvHniP`1tmAb|#j_a88^0Bv4S2HkGyOt$y+H3Lpjs=}I|JiJWv8 zeJKu$5OH~VdB7Ru>C8m`cQF8=rKP+1NJC2sfsiy77FI{9KB%DRqumP{;1H45N5!p) z3qXvpVB7X=;qUf%oLw4{@4-7THKTAJNY745$;-cAZwegw=BWE}Wn22bl@#2<R~bIl zPJsjW-Cs&VA}_I!KeaTsN*4%BGYG)^3T};thKB7|J;daJV;dVSX17Hc&PQJ$w#Y|R zfBlr=$gHZUfWZ`~b29kUar*h+TEK(rc;MsLGy-CS?%SSaQB?)?y)*P}-_CZ-5m7+l zptObtgS^@SYHBH=7W*F<J0EvTNeF34$@dG{Lv3m*DNBccS2?&s8ed<orn01-xDRm{ zt3!&9w>Rtj_rQ4?>0f-%u(ARG;Ci;8+*5aGUi2Z}dk!e^S?|m~S&)+puUFzn7+@It z#1qGicVs1R7o`Irj#gBVJh1jwgG`>I*?SO(ICG}gaFOX%2oP(Zosz4ZaG#EEVXY8D z(J$f64i&RUE-6x)$r)JPRjAc33k!O9g*+~Sx8`I^elR%C%Owpo5!fhd631mQ>HgqZ zO0!U{$^Iv*sj_pc!z`w?q@)Bv{NOl6Tdv#tw#&TVEMipb)L%r{T#*nyme(r*69Ewx zF3b`4a;C^kRh2+0ffDuaemU=zfFS4a7l)eW5I&CQp6<`<(ZSW+ipkPaCJVEp>q9|- zHQ&!?X13VX9cZhA$%)?wpD_z!?ysBh<W+?|o9&L7CzcY|BZH#>I7CxQ1qFqID{Cp~ zL_w{0m;Ll=WVw*ma=N-qyu8T_=zLb(nv0asuM?RfrHS9Tpq{^#HtfO4_&4yebZg6} z#9sneq+rA5e%fDn{M<>4<b^VtFNj~iUw@=@M8Qn$>TJ6Z^aj7*YeRDqoicipCFP|7 z4$gZIK1Bd(CSCaiH1Y*Q1@-sY`DFIwaXkN##}Q*_m8^CYSBw$(g+>n^vnGYWmg&Dg zEVQb((X1gHPPSSnAX{=dt7>X~-G^Qn{bX>`X!dGpW#1Fja|@C<KCx0E5zep{N3iFT zmmgUZ=3x;^7aQ<ge6igz6))T>;Gk~dnJtp8NB(AKx6vf4C4&bgmcyuuIMQe?XkE^o z?%H=1p8FnASNoN>^YM7~d7L+;S(A~#A(A=_6@n{T?1O`8Qv(#NMP)F6p#@u+K=2*d z@OJu{79x{RPe)6*<lOw+d?gyX*6!QsHw@bDdPGA(BIWfg@t5u)ij0U_UR=V$|2zwU zT+~Clx!KQYgo5ZsDZ9PDcW%L>PmyfGmFUpXEX0cTF|x?n!hljy<wgWex?$J+h(tny zVmkj}ve)BvK-_9k@A3%Aj+F})lOg1L8kkzju_^}nTwIbz1L>T^v}hx0V?+pun4^(m z-mhCk?)toIce-*IeyHr3k&{#OeEg?=WtW*ra)GdKU!~uTI=5WmK+O)y+uQB*>6*wA z!DNC**eB0F1xeL}>N1<kvC9vJr->;BQ?kfdyOYA~@9zf(O9zsP3nzr6I!FuLe)2{{ zsf7QI9G#q;pP#Q~=VDnVlOm#71kqq&(8-iCAYi{~xeCdt<!LB3zziUiy$wncX)HG* z1Zo5jJq;;o6liF`Kq;UOuS;MQRQ*KA-lRg9Gx}eub^kxbz5nCOO9%l>wDM7iG8}3X z{xoX3@;j<)2y@q%lu|n?2^g641A~Yha@dPSZ6KIaN$TTkSqcPjP9Liil}CX3f|Zg$ zL$gzz)~CS&fT}Nv%gI#&%aIU8h?xvYbOk*oRArG2YMPM<o{(z6p5QaY7{O3^ad4*^ znq>@toRGy;ra%hR6sn?DjX@)2O_~UCb|m9`gg^>22uf1U9u1u`DgeQR3`T)|nK^@| zE@<S%7hK6oQBdF%N+GHNm{<TMvfxn1?drzSAlP7oe~6pYa^t9W;tHTmOcsU_|4<@G zOpcOQz~Yet4?v)XIO}!2-v2^D)##-6*BxRLSrFWXe}+GS@|^TDO-@Sw$3K@`B6t&t z<W1$LWrfLyJIa63@r+sOfLU5AbwQ?~v!2Hl`L}GA;E5CqDB{8b7;KfswN_~S+Z&MR z_CVt4gZZ(vxqa1Yxzj{HtRQb)7oXtv6ibM|jNu~d?D@7|&&<>~G6WBA2>*J0nElx5 zbGWCJ=ZaodVS9jcs4UPfR8A3A!v1QQ^@?{POYuqOa@v9$n%&;@n!K48t*nd7xHVb3 zxS-WP@>LtYKW4IVk>ku}8&pEs#@7(o9hn?EDW~mqWn{nnKx&(gtszYSuc?(fW~Tu0 z=wqm7m5MRaExQQ-It;bTw%bR!Z5w~16yEJqUf$6D&c;KHIOpcqHKR7?%vDEik?HPM zS*fHhsrh|`SB>|H<o?VhJhrQD>bgjHlKXcKM2D}sBWD3^;k3tg(jU;t$wE_MA^g5< z(O@Ua4cTG^daH8Rcv4c**6TeM3bq>NZ1DNQ;h~+YfVosOl*mb;%A@z5<eDz8F|wVV z@yES=Y`4toY5DQpFRT7X2Uv@XipR->jJp_DgY$_r0fsKK9`*LeTigyN<&N&E(wsxH zzf)Uy38Gg{N0Lvx-_0r^FEhslRthp2g4m{I3x}EIMs+RIV{ErXS*a~A-rr04PmCCP ziDFO;ndz8@Jop}cJ9qT^_md=zk|oshSf4hO#wUN;oGy&F2K^4knRp>2Mlh(%Ekipu zuupy<8;aTf0d@J|3CV14{C9S<G&-1I2*@b=o!_n@hpoM7D0Sj^PODkoP1?lO3aFJ9 zLU$YCx%2v>*C6V(v>My|g9~fa``VfcXd?6VgoR4tw@?>FIR*Yr_b?2ZmmBU~Nwoqz zKJ<F)Hy+>LPs;4?MZvdQZX<~ajbGfOn!7~5&v^9J6m<d}=YB8ViBX5A<tH$F_wd4h zdvH5*zFrJr&L+pG(4JVCj}lka)#IH7YLGiw&DQ%r>LUjpaNezuC@B4r&ZPH=e0%1( zLryhRhaYTK)U`VdQE_V)<%jg#w>%tct&B!T6Tb1{D&9;fqMI7Gzu5JwDJ;ZRW}5{r ztStG>*4e2CVfEv0uE3S2t(e3GHt56avB~*w{9?_c$=|Wt7yA%?x)=CD3y0JrXuc2u zdtsBtaw0%W$z}GjsPr4_aQH99Sq=I+8Tli-1LrckH_^54#tAJb59|B6p19{t>p@?* z9Mxih-4<49fNXO2xb>z*R<Sp2(hJr>^VNaQ;VwU6cAmGeB8jdJH(rMvD+~Fhi~D3C zDGb|nPQfpCO$lFj`MV3tFz1A?6z|+?=s1-T5l*e+0w;Pw?~dLJGTi*QPiIC)_e?9r zot5-zPCe>tYi*YFNvY7vGd|tl-Zure-|sn@SS}A2pw}W#<ItzqL*c{3viQiCp{rSW zcpQjUN{|b_xn^@5Uw_Fnp)a6<*VIsCE=M7tgDVs0PrnOxwlT-j5n*EaxJiajraS+- z$nGzSi5b6|ynK79Xv|?7C%gP%_kBReb!H$bXgE`sij4&so{E;ztjZDru}WIQ6n9k7 zJs)Q-D#<Mq?qu=tA^MSMWnlq!&S@={(AgA^0rNzn&zFp-X>BmhQrzCpk;FjaRxmoO zAvr{^S@@5gpPx(?N3g&`0L{UGfu8%e-lo%_)ZQ2Z7X07R+OoPxL3mb{W>banA)9(b z16`47_H4!V<CJ($7zX+ABfLXRQyoSJ0Ip79@PsM6u)+w6QVdL3ymcvZ_T_*X4K^;c z5YaF8R!%+bmUu)L{zNEUN}4`UzCP-OoG?@ds*S6#AS^4QAUuNdZ-VpLXkp9BA7gG& znt}|FW<7yt2Xk5F-oJpsNr6P`?G3ZsN9|lY2KTNfPYa*lrF3oF<rRUhR*;<-&honY zAPfYYt=qSW%ii$>Gu%34M{4ywiZJi*kPRj;M+}BQP($JZK$s~9m&UZv*~#kNYaYaj zr#l3Rm<uDpVI>Q4bV8!VEl7RTQQqx8NM<V_oZL7vXVPp<#K2&o>R+Fngp$qFhj1g% z)8aG!b$3j|#`wBiA<FGsr~gdrErPb+etwSjBWYvfgY}%*Jtn@Cqkb)BSJ&!S{-qQ* zM1NSPeO_L7G(|}{7WR9$cmY$f6gzoG_lw9h>jY&dE|vqwKM<D4Vm$ai?==(iX+a87 zWand&q?LM({T82^&9yrqgeg(b+Ug~kG}(B)h6fi!`Be3V)p(-2iIB>_pf^1!8Mb>W zw5iR{4(|G7VLxHCp{;`{b!5b1=`kYm%}+&RA1A8jJJdZ!7Y#1GaEFMWbl&?ACRaLc zw~pIKkHrC|Y`f=)){k*zxTR}2k=K7qex$>_;O-Jeig!dOM_uPRvBahd=X!$N&&$jt zs+SW4tgIyB<#1wr^f915X0(2fL^e@*84UAZ&8yCv)PXZm#CS1N87iVbVY0@+%>hsQ zRp@0PP+@X%gqg{I4LT5adROn<XC--IW5S|dC2$hz&laZWO1+dcLKg_>+}Aa7Dkn$^ z^v4Ju5D6HOm#^>aXqljK@xZMrT)@?!NFmK6vl!-F?GcB=E=`vthRP-AL${AokdMG@ zsAz`I&NOiFeWd=!Q~r9_2%;-P<YVOR7G*KfK_ayg-VXDd9vL5FoX~Tzs4lDEq$Jrn zAWtKKjcsc!itk9!cXVZHVF|ttXrnBl@;-hHHPTgV9o{wwg24W^(cG*MM!cO>uwRs% zkd)!>cj5Kh5B8fud{EhW056ZjlKQO3-3wH~9@ihro55y+filW0L+y#Lnw&TFY~F3d zS!Q{5$E43eZkQ#UL1~SX?}zo=m>r^g#Igp4^3&tNfN;IXEzv>2!1h7L5iP^znBuK% z2y`^MY9Ak%ywQg}j8j$QnDj`mJu)=$V!!8YM7;WJUK5+MG}Yfz4=k=i!jOLfEu`z~ zJbrjj4n2QULk6Xh1(iB>oWd~B?yy2@+sGCeBz-V?>qZ=-ZXVEePI4@y5wL4OP3YPU z`$MiJ(}8Y+3;$HCg@2c$XgCI0{T322RMgl|lq6?*$`z=fVy+$$Pt=qtL(xM#j~5O~ zQfjY3!lB`zw)AK&MXs{_%d#{v(O8%$yA3^mm%vRK+)%h3_)UBZ!ykUVEKxeY@e%!L zI4tJh`7oh%_xm0ppIs2zwE2;@uA`6g>#X(F#Z{9<UMSQ&U)sE}A~Leu*5u?FJKmJ> zXMcT<=9dC|JMx+oE`l&snD~s1H+hyg$$iX3y2so6LiO&MmwTPZ>_#N;VDdxeBQg~u z<~p2T;AV$shlPH22izpd%3{^2H$NImEg(T68tX<{l{uP43Z!uHOM6flONEq<h-*Ig zP)^yF88fgl{XAC(?tJ+g-Fnk&7ub?mSQMY~GbB`bviKnAEpfdEOIb}{t1hG{-hEIj zN&_2Kq6&CmP2a(CwdHUjtO9WHpp-Fq3T?B_Fm&iudD|9;^>!6kmUG0>w#Yo!!)Odq z@|fhrHQWCiTk@48toy&U02*BWk}^_vX<egwR+4OM`1|*3Sq*{`ypoZ_GS|pB-F(-I z0ywCSFgGD#m!n}P_TdE6{pdy1jJry@W+GidaXU)2_#mq|_?QK>#75A6kN`}o1?LS6 z7;&cm?G_;Xh2!U3p;L0~rRdOea(1%Yzlp+)j1Bq9qpix<f3^RDXToD5yId}K)HDO3 z0?k#joOWjryPQ^^&2UTB@C-%$BsJ0po?!Tzr4s$kuC`kA;z5R@K0%^TmNN_JfV#$J z7gx8b(W#G*dqJ8V6@7`_vDR@9k3?(vkK@byr>Ee^1d@#(2*=3wx+OLS?JhId0pGpc z_5>dX{{GRAD2q=6t=0Rmagt&Y++5!4<*m^S(Tj9FhL>Q~oWBdAGXrmim#@I>2Wr~O z-xhwp)qZ=apYAfAMeSk4g55Pa$6J$LtsWk>f(>fRMy_Agbah|;Z4TGOv2!8U7fq($ zR3RY=`CNZxVX4%KGKUL=Gc{Lqo(O9u2XA(!d2)x``xAoV<9#ps8qEzR-+bOzPlmFh zJ(jbxlC<Is8K|gk?&p`2Z1q-GbUs&`1DDyh`fjfd|5};dw&$a36XVR!%-va?Ffu=W zhCYNyOLvKS_XkQ24h$*~OiWSE1LqAyJQ!IiFIVUO2z~8(^1enyLuqPgy8C$wsfU6d z1@TN5E2pC)Egt{uQ@YJ2Dj2ri-%LYG_g%n?pO+r~%j83*pPMT2G5Ou<>z|NB={@uA zS56gqdEeJJRGZF-Z|W>8N>$hh?PcZFUaxDmN-UE+q`KoHAB*a=naYp8N2G+9h_ag{ z0P3ZXC{;D}f4*0lNoi;YjV=uy=rjVHFBj!*YXZ8J>&>Bmbe0fJ`(1qdB>OZMH4-#6 z2~gnlN%<&M=_pynWn_pr5eq(4?Pb~z#(Ov6Bcr0`)#vf2btG!ClKB4|b@)6l&5VEt z;?>)y<P5*s%*-4YceW@tJw9{r-0$YDmg}|YYI$}xKJgDJud~nui?x&Y^5^R7+3Ma= z5{tH)swxH^NuAreNT6B7ZxVK*EI;=lSDO_~EE1?x^ed5#Mvvr}DrHBLn|(EP@z53P zBHXzyzYhZqZJ2HVB0#kJJwx<IKv|oWtLs!l?L5~!*VE<nZmWWb&zq^yPxqUV6XasH z$jFGv4EA)HAFkHTKJO3kZmC%~HZP|k)>5nfk>Gfbt}K|&mnl)u#zCKD@cR}uR47_9 zLek?E1k?)&-Hzi|taO^i2E_O7y~euPeOTXN@_9*mp(`lLHPkhBdF^fe?F^&5U8tQ` zIAj^07=c+#;fb04Yg%Zb&*y?UwHU&M&z8}q`kxqk`EGT1JKgWPq#QiX+aCs}{wk#C z^g6rT(0`+;&r<8|U$0zizFaAU77D&dcky4Q>*$P%BK%}|M>prT+FdGE->wpF50CnE z`E7LWeARzWCdfzeG!?xrDT~U@!F@T~PW;U3^K#8dK$=e<<Li9|*zWZ~jYjF^G$}R| z_8M&WmGirKcHZqnWCwtQNP5EO^ky?$MH&`s?Aib)?`C>6JK4_L>GM2QZ+6Q=y5^5N zQ)i28S^DWFQdLsGZa22_M^?F)O)-X;$M?8|(ufUX;+xOzWO=iU62YL$`PFtuY-G4@ zw=HSGMdta7%gMHdQTEWJkcgL`>+P>Fi~INTN9a%#e?w(!H3dEEk&)hMGGS`oyR+Bn zjf#zf;^bb|5E!^_&kwj5d<~c0n`hR`2}n__-MwnVF2tx`b^@$)cFVb$p+liHhgqba zv6-AP!cj8$(<!{29?XYvf8@vH1$oaYZYL*{;LwN>BGBzcd_Q0EHQTi^m|<M9y5B@s z;D2E6{iCKsBjEABLNra@?zBZ;ezu%#8+_3u-pSdy)?8fl_4zcjwa83Jsjx3mp}3EH zVF5Hf@LV%9g5i@wNIDt!pL~37>O+duM~9|IGz0WCom^O?@7vUYEiL?hW{ly5(X`rx zIX}T<j&ZNCjaw*w*I8I_XAtQLRc!=Hl$^5S^LamsVr5AQ0}CxK7If%CHm~hR>JN(x z5}OwkQ!D*cVkE?Rr?(3$!gRuqm&0*AI?gY1A1Z|0F5C_d5l<<6(@B$C-M(yebW3%% z<M^@JK>^TXjV@O_c{UXnl>k|Qf-Ex+9ol(RTu$73JDQvvyC7MBaI;Izfv%LY0oq-- zqW==i8xoi-p|G(0S@!BZV$f;oVqoX%>FFu{VUIi>>Qa~zH8N^uX696>svw)b0k4j% z&Imw^)9s>H?RkbAost`ea5{NSCjUVn9grWYB-qM_Dd&^#tAG`bnMz^*6T#}M-InR9 zu6Ph5E*=gD(E)%6l*OCWUGV$)IklNeUB{Z){JY`#xzFt#vMa!3cejH!EQW0E;!3PB zKWZ;%`4Q?Jx>r=U(|K}fGd)8m34yJSv+mkIKpNUoAR6rh&7RPbkTAR=-g3nPE~u(3 z_ptE5<>$09fUy+qyFgF8NXM(TqQ-9p*4DU$1PbhZ{$N8w{#8w4t<%%9q(+3yhtFQM zn_J|4oDXsw=<0`wTCO9z3|O7ur>Q#F@lkJ%fW0w1T)YoIzk-5&T->KDF&^(}bOL$w zE8(Q1c)P<zoCiu#w(asp{D1}CQ@1Y>QRXaZ5+uPWaN_JHeb*5kW+ENW!pi6U>*y3u zNXpyQ<Xu@TDKT(TlHI;9!g3W=xptoNMBmz|&glPHExwHg(eD!wtB!YBtQ*LE$?k^Q zWyG)~<FfpnUk_bf+XELkhJMLD+zMOi@#`q}8?necFOStJnjQX=YMk%KQ)^>pB?y$) z5!jIx@G;CwUTIs|V<OP;h*1$~Esm?1XhJlQGfu)*;?k~#e)Ul$5+n@omRJrUwQFb4 zDqRzJ7V!_TL{e+9o!zw~1Xe&_X5WXU1|ix}ltp@xe)Lj`iDh0P(!gYqU*oBe@}JB$ zV1_qFww=B<lV@zE^oK}@ot}o2dk|=p(SI!|0_`A88n9cxJQ3a?Au%zH%^xZrFhQtL zr!Zj<Mx(@@FI1|p$JkOjT`X}s6-~v1KuryGKc_iaDeAqd?U?ba;hwddZCNaIuU}T3 zFBZ84n1})oc8ZUWE&t3WDQ^l&#KdH=Mr##RRc!?uhER-FJages8GJRzaMI6--;;6F z;;e%Vb3S}a<r<pyXGjUi{YaZEAMsYHE)s|Ag(*LP5vo<{O#8)x;5l2V(oESI=6bTF zBl$-Kz1|6b(m=rPIbl}aY~S?v@94CfaH0|!dB?Gy%b*^8-EJQi#X5_7@;SfZp-k`s zs0CEJTq<WCI1EQ(x4D}E=NFhKc=>RJip{zthCLW05z#3-<*%L&`E+Cxe`Y!egHLH_ zQs5{S4s3NhSL;LQTT)>pJcx{{LDwI#u}bWmj9ftVxNP*c{Jf&Eseol)Pph<;EHn!a z_jY-Cxwt{T`Gcx#C1qDTUth8l!x~;3A`&Vls<D_#1PG>^Tu)_v{TXX$sD7hf#9wt| z;4``kdeA75bx7d8t)OCL6&L_h#+S?aH)Q&@pulv-tm#UBRrrWjgeU7v%w5IkzBzD# zb7hu=N`D0;MIi_Kf63HF+v^B{3qSs62sJnaff6`M%e1WlY`9qmBcz6fJT#@^+)pwX zQtsi4fiw}ACSWu{4i=-@`)A1<h$aRMs>%(P1j4H04x?%!ipM!Z=3-RB4x`3V(ICQz zV+6=y1Emg1!C+=CO>`Of+EstD2#r$LuE<3Ttl(gpGBES{2H_A_VwFBz#+#TxMKgdf zE0I@{z(5Nwg0*d_dqc3QLu)k3<1vG)O%VxyyHX=aycuGY-7Cqth%y9(x1mr@QV>*h zW5LavFo~BVihsaLrTFDhK;;Fe@KNegN8?!^67#O$+DJrD$ldo&+hP8nQMZ$FK#m{) zVt#@e5b9(O_;!saP9#D_MYU_<4_@$7b9yYAb3~-28$ffw6)=j0i1?qy5phKtN<1zU zjezQ_Cr73MO1JdawvwN<2?aFAIBKX;j*hnxWl*7NzQ(x?2?dcLr~rzQZY3ElGy;Y? z&N-tT49&t*g+MVd9T-HAOGb$R<&VR_%xHSBAHWAb6{&><^V>)q`n%G9@gOGHAl!Y^ zay;F#$V3ew5U4FTuc}T54yL>6H%(T53?~4hng>{8pK#}ihKsjBpu_|V>_Yy0V&Cx* zq;Z+HnZc*VKCqznz#2S)n6wULa2}F);TQnxCs}6;!Pyfg3?n`UlBYwV9-|f*o}{6z zndA+mIOxGaG8VL>aNlVH{0CSDl2PDL;DdV_CVEyyfJuU!yc`Dj??6E^m!?pf0;sgh zf@{Ih^O&@vVg(Yn-ErXmCK8R|iA-&1C~8kmK9w;sF_A6m_g{~X@ExR8t+U*`ol~rm zUF+2K`PAzCEdL+c8a`J66do>D97C#ArK?ap|6h}GVW^lAj5TX&X^D966I@k*K%n*J ztEp68zsnBTYJ+Y{E|m-+QY<X_qHJNmfA7QSoTNlVu2&z>{~1LETR9K{Wu51Jq_Ec` zJuR)%q;9>d@Y|}ko|h-j_j>d9q{?;5+vMu2!trk-Q0=Z4{Jw8Esa@U&RwgD`U~;Kn z`WU1!_I6#husGQIBkbX9$$mcrmzdaX|JXsb988qnooreUKd`jBUcsuDd|&5L(XK5{ zNLYA#gR03I={g}3_MPkcuJ>P$a^W-I?LHegtdjNe<ZW^U0}Id0z~Fqj5TD`vt0p-y z5f;1Dr98=@*1_2LZ?!?E-F8=HbTk-oCJzh@92^)xK}AK_&!z-J7yPt|!i2b_dQ$m` z?HcZ;&c?==YQi88n6%>x*M-??_k|Syi>ao0Cf!|B@(z8J_do+sP;fd;04O9^`g1AA zgr&yEGcvs__oNUJoqi=!l94HD{RXCw4Lf{qo4~t&Je7JPJ`W`O6`JEoFgI-f?grD7 z?L}(n*$g@}v$Aw9fyL9`|Ke~ecX_`)AD<}XL3Oy_PaWO5<u#2=Oz76wYz7UpiTJ&? zdiKW{`UXgms*S@>DO5gqe>HyN`!&F--y)?<L~snQXo}xjy|A#b_jY$#CMGF2o0QHh z*bD+4_Af8Did@dZVzb0D+HKRdU;=B5*yX`sf}_*z3cqS0@`IX#1BV4iO_@YL6*3Ys zWhN-?kemPu1BVEQWXJ&KuupiD72P;=<XC%(gtaH!9}21sGEm3-Qkw6-wE)cc*&3EA zZ|z71;?JD8En$J_bbd>*>`Um^`;K1+boPXN+ADffY1Uoqfukua?o+~w3gbItkbx3? zVET#g+o0D@hh7D&RpWhALc;#;ATpg|#_s7U)E}~FB7S}WiMO8@X^Fp91YOS^9l$86 zYoN|fHH&UXgY7y`O?Yc-YD0sDk&)^jx@g4xY<e~}@^b`KRBl|eLUgaLH(sZ@#6q24 zKc6DzlPMq#WR>k$b#CSw*Jn8#;9lCm0kYnlQ&*Q1=3wNf=S9zwVK{j|Szk<lJhx#9 z3heWAKATzSN6qSC5kwbzzWY6qN0ruIj(y}RzS(psgwUMV(V;J4G6zOM>^6*-KG80> zk$vqqy=d6zEzFFYj&>XroaXlvzM{G;I^>7?ce?IQ(EdU`9vsX;er>7_dV+SBsZro6 z{{5r6L+6K^tAH@Iq=I_pS;@41%fmQZ&(_k*bwquQ?uwL+KGbqk&PtageJ^CNEkI6g zB1H%;*y}2H54_CfaOaF8o2y{r<7e|&0H}E_erZYcQ@6X?tXD(`ZbKh!QmHX7Jiya_ z7jU!M+Taq+<_FK3V(j7A-=w^`U<Hq(w$|Ld==I^8MizT{Y0lBX6{<Q~zf9>&D*^z} zBo@N9bRVFlQ6><am>3wDS~?wARUrPxCgSmMlk*{*Nn%s)<Y@8HoMEIRmV@~@nWk71 zsH$pnu-oeJ4-CHpgxg&G>F*YvnbViPXvHOm!8>m4E=KETR&Dzl*_xqYLDTimEvC2f zc-~G)V*lu;gie8iiDl;Vx7GEmT5X6*p!wyR#G2CT@#>r6?Aj2NG04mt8Z6Dg$mDOy zV|~hpPw(Y^-tGHnyMK81wkTL_?!8rQ&2s^B03m6=+NYympVjH@^>dnz5dgqg?V~a; zIA1A6)?bGzgx<{H@`2j7*>>WiWBoX5HUzJPe}>TLwXN=N?!#PdJH%=fm40`mdH4%A zI&G`P(R9I2wGXa|AA_8q=RB%1qK>9(=D{G6o82}TL<-gA|3OVXWfC{7T&>-eAQmTD zQpONOCf+x>YJAm;ZNwWe!?(6B7Lx}qW~+F5&!Y_bX2c$!PNGtERx!v&CSR>{o>x|a z`}+Dwy<+12gh)3eEI7MA^mtKevndcWBUeRB?C=XyGk^U8HK()6PbUK>-0l)Q8Sq(> zmxn@^{=30hN&|&q`NAs}QOg~n0OLVkNfY)C!ExuW-)k>C&B-v^CzxxxCR;8shQ7H) z606zC!JEpI3DpOzH9qJzcn5{FBBrn?S5O~p;>n>fAnRn|6e)bOuWy{*nBZgQ!=XW( zi`I6H1Lc{}jl1pr*ZWG!@Ncy;KAtiFoI;a(b=<V1m_a7dwG(7Ds=uZ5Q5<`C<Ny2# zQRK{!N`siEi-EgfFlXnn+3asMufgew)$97nV_^=k1Q={x?cjV<j7;o5-fk}sYe%*) zzb%RuGsD5z7q{yffUrk6=XB(i>v8y#@FwgnL;cMnZsbbzy$6x16OzYhgK=b>@c2Z6 zC}Rx3h3B7a@iS+bmEA^_T$Q5)6y*L{k8iK_C9A)krDn6|f@*#zFkpA)Wbj-rE`{M% zl#}J3g;XpEG*^d~VI9SsJV9#(d%i-R%lgtLV5DklaU>?d!3g`2kcfkr6pu9+iRbtJ zfs7-oE00tW6r0^8fi?iz-NmMa%*8`>;l8#`NWjS!`FuBq2o4x&3>bxI!X<QsgSPto zt4_gSgy!z|A@f!hi+;F9$op;Bja>B43H`KTe-UC4jfeO1$JwxopBp|sJBN{z{T7!f zXILYtum_oQfD>wtQk61VSWKqv-_eW40F$hC=gb6XEveMfl=Ie_tUpJr<0EpC2^Pma zTOQBP-pvO_7Vmq><f-)@!@k$RUKwPBk9W#}^v5kcb2=DNck~RmC>UnNkHbt}O4AxA ztl&2P6UgdgOQ+=1vy*~i3q=C1-(OjK9H1csjgZ`l{tQR^X8?YLf=R`r3omkZ7`dat zr6H`Wbxq=?sHg}xtL@WGS@R%1J!WL>)0tYXOu>eL(@M$V>A;NMTb>$wbcT&`y<yvS zba8#SCKEfWfkv+H0u2Cp`2f|Z0+>IoTyzped3k}gxgszHa_R_qJYX>P-}4)4ARBAU zLru2+BxV|qYgBk74-dGjYc~CuP`6-HN$n&M5@#PSQXzwOaDLFgMxq@Uq}(Yi$%#wM z6m}Q02dA0txS4QiW*&djpmJClJgJJm1m7yRvl2j7*0zvc1lzY0UOV2+1bBq7*0(n} zb}WD7l<j;66@tRej}D2Ct*{V)%st5DRtY&+ld6WX-sin-0mXKYOWZqYrRAk{(5w?y z=OqLfY)#*w_|-TZ1lH0p^3AF-pn4)AMz34?0#zaM`f9M;Q&wSnIsySYI)q)X(D9}F z`x@ajzu-Ju{Cn{7gT+0K^}Rn{paZqQF*|Ihc*-)$>Y=>OL|!6U3H21v9UGH}YJxSV z$lzdyUgbC94@6cZN`cxD{?(;dfy41{H1eh{u`ERbAaP1)1E4y^RjqdWds>;2!dIg7 z=g9)jLK^I#JH;X+L^YRdU6Pl~LjwJ$>@1~KjIK3r_5Q!RAB+Xa|83u$tpd<M95Qn% zXFkgEZnupz0<sh#FE0;-wTo3D%1>ySSGMC)ZMd-DQVrEe5BNo0RAkZX&^J3aJ}L$! zSXC&30v9xN4p)&PlYex8UslfGfXbxK>b`kKz1V%JS(HRmS`!ZUSlCtuYDl07SRfY@ zG2Mw>bW<@lR`Ui%wv{;!vQZg4ddhQGd%2XL0s>z->3IzeWrM^{x#s48F9K<dmJ?Z6 z%#LomF7^Z(4{hJDbKRU3)-H&w#$e_s{1sBul5~I%V&*jNo5TdT9hZx;#~`V-3z#{7 zRdr2yg=s8(xN5Kde5&Qn7ldyhaHCIY66+8Q2Nz5*FgSRFj5N;VzuYMfymYC?3}yyk z)Z$|gimMV){L;ylDXM4%-;^n^+AEsE84%b^8}OBHr)~~b9?RenE@J1*fEwYk3sO9B zK(C$>Dp|8<9jn?)Qu_Kock<d6Yea5}vX1L9!<|7O{_o@0nxX%b50XJkU5_Mn*QZvj z<u4bEcnLBrO(`E2n+PZy2^Vhweoi$D+_VNlfoND+(%d)>Zxx8RY%6Bn<51?)6(`<0 z*tu17J8Zz31f@g&QYUh9wPB47Da{-gC#;R>`9653A(6m}Bo_h9|6*Hw*_j{|z3)Cw z;e)cwQKd|xVfn$Kz{?L}I9$mzk?8xCn^n{VF)HMI_q#Q9w69fNT1slm=c&PbZ>sVv zIV!?9|F0)(WeO`Jt2o7oJp<NOQqtU4R)kf8yGtW2`Mh8mdfKDJm#L}1MOr30yNPh| z9ND-Bo3)ahoSGE1FLZQ>5wEe}oiOR2mR5HsvpQ;O0Zyg6ySwOHhQ4n%#j__$M6Ep5 zyJ)Fkl-kkFrOoLxqA<i#9i11dl+>|)n=JC-+w7^JqGYA~cK`bgviJML4{>8k{jtMI zA&R5h=4|;$B=BMwhlYkYJvr{=;_80~F0sAep}{z9Zc2V9YVT>``RaJ{FZz+Okp}Av zGc!vW3LJkX9%;3aik|eSI$$0JK&3VDr9ge<QLI;~uHwr?(-r^QVWu0nx>Rhk-lL@* z?WpFpTi4Up=JVJ<0GFa*STX5iGqW#(D_NqCN(Svrw8k)&nfJ1f6ft$$uv5_Oq%Exs z$%C1?5t8L|`~c^lK~m5Lvf-A(G;2G>&#-DgjMrGTK8jnv7dR4Om#!b}T9WV&t)91J z+GBCg7q8VbHF9-gzqFs4$-ClOTprcjr52uMC0`#-p?D$Wa80uW++dg39nOF8;tvbM z#}*e_U?9Mj=rJ>L?Zr6B8R6t|s7t<3y;ti1TD#z>yU7)m7(q3@M$4VpR|?L(8I0FS zUf27BxqB9kUl(8RFX7;(*t-4S0wr2xbH%3ZNOK`JT)~!$^TL<M6IK>lS{9Z<3N~~$ z#cqEi$EuK2OE86vP>{rM*NvHcVYje`!dhW)dlycxG9cLeE#cr>f=oV`>(3S*{TMoZ zxp)nFx&O+`73v&YMcT6f`y=&g2rQ$DFXQYVfHSe1jV>ZThPL<fVShj-@&3MPx_b*; zXmFSB(Pq0BJyfansTL?fvrX31IZVoAEHR34!0>x*IJ3*#Ro8sOc?h`k6KJqS^m~Sd z1@~W~?svbFLOm62I;vvu+J84CnVSGPi)jiAiZa{Xg{iraFQ?8k^u6?$IkyK^{Kc%I z?=mm|(GM~EQ8F6ksagM`8w&KLu{}i0%uEZC+0rJng0Fc}!(&zE=4a{VJ=@m6s;!x= zEw~XnV%tpN_X}xDi)<|PxVp^DwS&?B0B6P8alRF1ECkpbxi0{{*`h@4eOfp{N!J{M zdM&6vWW<P343?W4n~5*X)bow%>(!#ZuwkJJ^77_p@7stu^Cx5Sel9dkpVy3f#N*FS zMLode>TR&0iT3tidWEix7Vz#<%@!b$cT-CPHt4xG5)d6@egQ)VC`6IrVl8oBz<vd4 z>@=d&`l9GCDQzj7jyStbFBmwm&u<QvOS%>tH&Q&}OfAEktFk6JS61bQ3|H;Eblxmi zYGSlupY!a#vGHpUBeWi=RG1Mr0>tac!pg|ttO%<J2d6;NgrcH+ZDXww8>~a&Lc^V1 z=2`%mxZ>T}qah5?-oc^H@BNaRklFkGP!im*$gSw=!Gr{hoBR3(Oc&dmjxG|r#VxN* z3?NvsgO^^^JC|M)s(uv|nbFWnFA<+-aq#Piqy;ort8Hv+Z=~Un>*wM;7?<_nt+NC< z7<f}fs~*0-1b^EoaG(Y|47@LveB6cc@bFO2*P$<YQn-yLYA)K*0}Sb?siFVTg%dik za@+16`-FivAmx6RlsDQg3Ni5g7CQ|rn08n;0euk2(^?XOF4nOVO;&cg+8;>2x7Y}4 z3skY9`FOboOwdJd<jA;yyPAoHFg;gSG@6&YV<<=)QWm8mB^rr|Z0-=FA*$j_{$Fo{ zXOAa@sTj&s;2j+SSsMCgEK~$anUu_Q`<!x}-WzaM$7P!+NKpqd!4L>CGFlegPt|7A zjxsU|tm%5=V+!GyQb4iV6;^w3`|srB1qLo`XP!z3=_yG|YiWgMLO0tvE0R39;T_Ut zOzBFPfWS*iFbq$08AD=Qi>kJoK@(67Gt$R(+@{l3KNS`M>^NWr`%?ob)gU9O-C2R% z5Z1}O^I|H=%<x%A*gqt<K<@OasON|f|DUe>-Vfx+|JDNjABKK$7Jxhe5FH)$CqABM zW;yxKpYo?b4-b#{c(pioZf>v(mJ$P|G+VXMA{4A?xm+xb4^HNL#cqMEhD~)21iZdr zTbE5MvbmWVn|=e#nA`aV>c^Lg^CHD`OiV%m#eLZMc?OyA>oIX!-79V>A7ntlR23OC z92#XD93*W;LH!Y{e+Ae!U#ZtVHn0+`TudtLd-FGcc)QEb@8hl(1Wfg@#>K-$CFQw! zjU~^TOmjV+F_4vgoiCntyV|;1>RgWRhfn9Wm7qv~zx%mz9dFp}L(hbMJi9|l4O9nj zR8Jrlh^szoVWmh|FI9ni&a;<A1!`Fo``J8?^(Nb?ERoqxuVwId3)o+dtnK>#5}hN9 zjQ{3#vfEnwL&oJ~!*cMZFqthoIVs7Y#>fHJpjD2=Y45Od>U-*YWLk<w)v}X2@x@ks zvs*UgH4jxBoYbZQkR#vy1SFl#TbZ2r?l(PdVq!uaiXIf)?PsKeoRpBD-|D$JIq9;t zFq-j9H#GD^CKhV@qBlquM#2~ljYz;}$cEV3+C86vi9y4=_xLzv$#%_ttIh|kX`L-s zg5xH&DQK5NaXp-#J$5RubEI-K))5>Uda%F0vbJ_T<>+AS%Kr4QDahW45M1W{`44+b z2AlpjwQN@zUqnQNGtv88NIlq)&G*VJLj-|i3xh#S-0bp-W@dKq@%{=1a>N5xzngk{ zLtRyz+Z@`S9^s2o;2a)CGaFH1CJxVxT#xR(GBGj1%<bf;8Xk-Ker&W_qrZulwEGOR zo?4wIvt`vcGTtUF8vi>OU;d49iP<uhC5+x(YH5b1<8V25Z_Rt<a9FY4@e1~OnF>&H zSndbwm{xC@{sk8m*m6qh+~7$sTy3qX6novKPL2eat2Xr2YrgOoE%Aqr{nAbG`5cuT zh@UEIuWW99IP*6j_<@q5t|68FxGe!-1Z#iDU~xOIPg^e)9xmi#3%gqkF6iI<V{<$% z7M}6{;OwlUst(sLFAdTlBHbX3bVwuJAV?$K-Q6J4-5?;{-7Q_xUDDkh^Lp>^&bl*e z;?Df%TFP3-!#UsgdH4S8{aAj(;zq`7Iac-;iea_bU7OoIJ<;*BT5YK_ynuy&Yq3<b z)&Khs<lDW~_LD)ZAxKC_-d1&FT;>+B^0tUkD<H+VJD&^>jQ*aTEbey#kpzUukgEF1 z*GSKv=J#+xbMs$f>M8vdVv^$Y^a65P*jT}T0do*p?`K)r@%}!u%Xr7dj;t`9=~Ix* zCNZYr2dl$fs>tK9WL_l+1qD^H9WWH2UFH5ZLHPC!7WRJ2>KHtdtXCf1;o&5uCU0(G z_fU}w8hvpwD7Q*qOGnr{?SD@O)jHU#gC6QXn_eY<gU2Bw6HXb<OUUQ;2sF;^5nh-$ zRt^q-{?RnK%(f2ep#*w(-<F5dJrEKpP8cN%E~%(tx<Z9#prM(VoQ8GhW1*#`rzd+) zK0L7$CxDCQvRo)lpds<=*RR-o*^`wV4lV&=Y%~Qwo$B_jAjE>yKO-$JdsT&n5`8Fs zu&@`1@Ym0e;i5S#q28!f=H`|-?=bcch@cT%co!Dcy`QhiSXm*hlpsytuQ}#(I?_pi zp%L6oR@+|YnonNMme}twwz<DRm@PTfcyq|Oot;mYExSi%a{gjqF~43?DP6p~zqe&@ zxtKW;i_8qe<q|rb8&sR0kL`;*J+}a3BouSs=mMB#(d2C^^k<+u83VAo$a3h1Pc79F zPqlCMeP+`)rdt2heSJy+N{&owz0i|-;%NHtu=LXtlt9=@i)(Rye!b;^k<)-`xi%56 zQ&&%q!SHUh!DxvZOPj~jigm{tdUtT0*)%gd<@Hr+J+TD6Ix7)tMf=(jyZIpl8U1pt z{vsEms?+hfy3FTa!&40)iA+N|lY}(|#4#TCv!==)ZMozTJYO!L;ewaEPosE~)6$UI zn{N*F+r?o~cJp&`gio7~ZHgZs@7zxvY#P=$82G$)%6JVTl9J{wO_c^07_^;3m2P6l zsi>T9$GsYMMl*QY&92m$l|FxV9PfZY#2)rHsrNAq4-d1_Y-V*{fpiHx=C=va{gjm_ zo6P#s-iU>-i)qy?d!(V$VrRbJqoAjk4aRLCR2s-D2@_bU8X{f{db$THM@5Z~mo7Tl z7+S4XeowbrpH7P-*A~c)AmATJ#>B!J(N3+Ysd*(q+Ib+WR>1bkSx^vkr$hxcHMMzd z(eUW@0U<v=?#&gA%2}i`Q7BSJ_!RTY%&R44X6CYzu}K<4e3sS7WpK3U=!${-%KvB8 z41u$3jE?*o_>g(~cK!$q{1mU5(myg38S$-HcO9HO1-s{Bm!f9A-~!sPdpO|d*Ok=Z z(nf)UBr2c_@B7FyRZ0G<mlCLqyZ5CJiRH^`HG17Z#-*)htu~%0_D1C-dDXDD>Uk>y zMjBbhl?F>jcW^^Hn<04q<MS5lx7Ero5}_B8{T18EDR~{BnRV`ewY&C<2aZG@rRb)C zqGVA<1bd4@j^4(b&CRK)XMR~(JISIXle<jp{M<a>v!CVpWTd2e#`-Ychia$q;+Q0n zE*%FXT=2S8Hn$AMw3<jrNcb!_OdtypB_$<EbM%1j28vpA6;)J>ez%w&HYO*l6`JBu z_6F(c4cAjI;Ykb>0v_zyw-dx$7ppDluM@OZf5_8GXliOIDe=<tV&;-C@SQD2>d4?V zgMjMhS|tmR)7GPZqd3h#-81z?u6o}pYkRe&rCDfe^Ua@hUh@Vo)|nk|>LTvFB$Q}z z8q@4z&uJ2~UT)|iAbi7#?eln8f4E=nOIGR?{0igB<)VQ7+a&b$xxN_6=<uL+wQX== zCAxT0Xeh?Mf)+%=;Y>PQDg8)iPH-{1=Y&avG|P(yxXA>;Me6t{AnoUr<hopM)PB0i z13^QpmC8)f{9+o~2N>9s#Ws|y0toq=80Z8p9F_k5VMvOqI_8JRs~xdS#^QuwC^d+S zwm@S{G)lBY*YC3e-0XZLAE;fgs$O)XtFg<e@=uBQ&;R6?XK~u+$q|3?`-N5Xo|-<L z*?0aE$<i@e|Lx;daCOepX{YBp7O(rdB)o!eqX=>B=nauq__9_I(joGmsx_Yvq3vjR zSj2pd5%rwdLuA_d73$RV@6pi#t$IC(;RW~8o<wW@Wvz7h+zjv~1wmfqN^*1sbYag{ z$06+Z{Vc)LP8Ibe%QY3J1*WmRXeETvVMtf&qQirOL5-VLbu(`bB@{&rSetpA6_Y?G z%Dnxu7XCm0Xp1pYNr=fN4M-Na>Ntc9#K8KMXt}($zwt^1WXVgC3oEO0(sOg6!$pn9 z9PKK|p4ccp1%`#uNg+<w)Ht}rb{d$uar;s#`uhk~lFR0jQw%^iXtCmk>(0~J@c1!- ze6-)J=xCq|X7a1=1ki!fle?@lbg*+e1}IB)#N25Ia8%LhMof~27Ib6UO?777C`=J~ zVMNrlWWvN<(AkdA#o54DOVPc`q#tP7K;vGjG&MAEIJ_Zh(_QSUUBkCl@%vL0AD7TS zG|;JGws<VeJTU>@)a5h+_}pjVD<_HTIu!^(5|H}$eLBBtwk|(Tcc`sJ$>c;7G&eOZ z1bXs-UK6)^C&_x*C<?zP6f;XT!VD)S#|huzax12Y0LjKHj(VTc7MG_skgI$zO<W7v zB2>dVt<(B6SLjKb<nc6$XJH`z(d`~X8P)*Af{8qimRdeS(0&Vzpr@ypVaSvtMusnv zn#ir}c0S}e-@H5M>DhetY{J?7K--_f=A=_)My5O{FqcX<llOBcCO)<8<y=Wssg_CK zX%ofBTim248w;<h%0BJT5@g#udKt}W!I=MmlKHrW7nKkVQNF=mn&P}S9wZPjkc95f zVX<ug@|#7xd)k*49s!T`yVgTwS3HFzLPhG*^X;q$!~-`yujf?|L6+uesGlKKI9>$$ z@jXgy5Y+qcK=c9jS;g2qR~92$DCNPomqQH+7lXLQ!Vfz#$?55_X)#7tMszMu#WU7K z{BG}))O8gD13n3qH~@hZnlx%3748)`WFFd7maVp!5t+~K7n_0gY0@t`3|h^lMcGSj z$oA5IZUb^#gJnAqk*31ID{g1Q7f?H0F*Ylr(d613=g>?>YYpPh{)pSi)rpMUMwr$d z7gwV~pMoB83Nf2{6Z0)JGzAw=#lRMoW5?1Rg^HZA+f87(Lttidnlj1_#p_RRu2f&$ zNGhAGjLZ<@`ze#MqMwC=#BqH+b2f`XTc8wco~sd!l0(0?;?q9Qdx>@h<)~nO$U;?t z5jr<BWTbz)!w5C-LI@PZEc>CGigy?We%F}MY&k~8>YQyAMLS-gpy)C6_Rb4nMOv$p zl#Dag`{QU`0N-}Z=4V48AtaO*QEwy+%}^{dUr(uh6BPOn9Z)Og9R&p#Zh;9){_pyr zYRslV?%uC3noHg9^2vT(*?O?TDxys#kU&@@-_pLp72G9Q2BPUtBLj4CC{i|FDXq^E zHaOtbM22eK?2|c2U|?Y>sD74}7$T2?6_ivD%1g0p)TswzsIKy9lWOL|I}`zRNku_z zc6PqTSM+!HNSb^zs&RIpZwZS!a<=uW{QQBoj9FnJ`BHilH?HZPTHq(v4+;wK-a=6& zimPyBj*$MHK5jY%#=bU=wjYFb#Bvl*BwCKI;>^J8Bkx{X|LKzm>r~vu>(}d?_7|_$ ze55KAgU*3F<`?1<CoUmb@IHPuA2O2-h{VClFHNe+3(r~5`+D$)pRQM-%6Sw8Pw_bZ z4_U^4Z-c9)mvDuFap3lsW$dN2zk+m%<+_b6?xk7-YBDyP<8raUkp#w4Na3EEO`1*3 zxgGQESHV`Fr>_v<qGLmh%Bl(&SfxwBF#n_WEP8E0tVOGHOu`1!AB^-UA%$MjY5FHt zaq4qCtrz-P)2vdF>vFNMr8ve?B3I+xJvXPe{*$P>x}=U+?4flosWTP$B?}sY>p8mH z4tef!*^fMFVr0mMxI)upil0CIzOVn+uY%}@l;Y8)NbnS;S&^ja-qz*2Z?moI3egAJ zo<LZ3g$YEf?Bf)If)Ya7*wDL!2{gp&I9MU3zG<3;?}{f6nfv~2Mzk+poE{1&$>Ns( zCOl(Y7s!dH6T9THgO5eL`nw-;4L36MVd3AV5d8Y8e;usI7Y5pf1^&m9^FM6@Wz&x_ zILDqBo<fA=ZOe-<#2+L7@=*b=RWNubZ_e(YPI5wjdK)0)lSX6UB)pG^{FfG>FHqj0 zhnm^qa{lOOWK{PvP_2IS2t4B(U*F!t5%76AfhR^<@&I*VF~{LtvnPS?6tC$C(cuDS z#wdQKhET0zbMmCj^dJql(K$YDxT_BM3@yy7J6g<!-h@`)oek;e$cX`;bK*ng8JJ1H zkSPMw;PE7DW_BNkK!yNX@$4nC`#hU!Ura0QSuovFB0lxxXsss){4{U;?n}7rd26v5 z^*kC;S7^F-P<M#KZx#~kPj8HaN#<{gDTWDe_+v5#vqh(8vx;&Pi^at6d$~^I__#o1 z=ljNowSkD%VAP`(I?CSF;dY0k>w+Ip;u3CW_pN?@9xxOjey^l>8`YE@K|#&fyQ31d zcbklYkvZx)#<9!X6nOMAHvfERzBrq7A)E&_U-sRWi8WL#P<fu*9Y=--gD!!NYeRMq z18r<*>};~g%*@?8(e>v13DOVP*;EXaGr-yRoiY{(YI3l!-|Af+9;Rbsi(gu50b~g@ zZ1CW~ASgiVTAFfMPFMy{JE~D_yQ+G6qc;y8cPQVXg98|oSOP&Ojr-kOi}z|c$xfxM zC3GXYf&X1kM_8gM8XN>7sqR-nFKNw3V54Hj#>j*r!(Hw%kait*A3n&n&z`jGIW+mF zvn}aDD^5<?(n*YV*bg$P>d*5}Vocz|zQz#Y8WHY%6Re{cDX#9uW;x%2&{;Ltc@29q z+&u!^?2Ef%=O`Qk%zE>e%9UlFf5>y-DLm!_%j<SM*f|P&SpbHMt$RydXqimb-tJ}B zgHb3~*SppxM=+jR%(qatc%^WdBas@KTh8a0!+p7)YNQ3HH)RCD@%Bc;&e~bcB~pJt z>gLkVgHuW<DVq1>NLD2M(39>Xz3E^g025@;!%kPcMidS{F3L6bk~n4`l7B@<X>%le zZeC#`n-#UG>A79IA<}SmR0X_v!F$?T>q$rq-Phsx3q%;eDKWrl*im<3|1drq$hwr` zj+#Ln<<<{ma*`;KoXPcg7Eg>x3b-M|<FIeKl)|{m+v~B3HY}Vx3lb6%$+&oaiEwvC zG=o`c>?+$?D!Ot6bB%(svUT5r&2`1!&+%k2%J+5+*C;)xq%AhR>^7=a_v-S380l?v z^-lS_xq6-!#7;iNsKnUB#8iMX_`*XJiN`?8$r|0x%BfM(Ybm?9H~2g-lU<a1Y3TjI z=*Xs|80eSJEcQ^eGm8~vFu=8vhb+wWu@ovonrk0YvCiOkf30b5GvQ3cnUSfJm7N`z zl%y&D#b_4C7U3K5*F`5Hy&WJ|#~^?jyyLF3Z-u6&0Q}h`ZyBqyw@c-?c=g?MI*4FG z@$c2)NZmD>fl$$3{!`4Zi0$K!d2tAX@Y>3I26$JSGp`ECc7-wz_a$F!Vt@p4z%6Al z$X=hqeYQsXMZR<HrA0wa9X-hWI~kAW?Xj4@IQ^>=tdNsiI6%<YpC4|0AcL(vwV-2Q zKyfUDOo)k2fR#{h(#?A>*GJuQ6BbqzXRH*-$IETM6-mg4=B1=KX|?L^@p$=b>$?%A zc(_oytYwd5I?tuji{t)Rk+_pT7wE8Lea<zsIjTa2h7?Rie=99cM3VwK*p)jFzOad; zue4lHnkydjx`+~AC6nSJckzN*5-m+uLPAMd*<^A8^AbM$x59@?0~|-T&vgW#Tr6ck z(*I{pS>8FQ=<wr$6#FmTT46@z<B}Gii#LN&Ylp7Al&U4^7c5r*Aq58nHK_w3{DbXd zO~dvNMR1+!EPEJF4xJtCn~T8PE}|kSIBZbxk4)p__|t9(H2Y7VKK*roTz9^z1+FI` zM~0}^=(QFUd^sUZ_qxBwgvW{+-($Tslm8Gt&+siuSy>)U)8lL~+yF8xU3;0^uToP{ z5pw!kO2slJA;E9WAy%{ujmZxZO_tkZ<1i<m5qmh@%v#^^sJFGhAc+LZ9Xv1`$9(_j z%KIO{t&^)72Upd>{5Z?qj592*4+#nF7!<1v%c(0(@n5aio#!rC9vT@+Wpn)KJH<*0 zPD(6BWXFQ}#yi-i6f8O-%uLO*uFqKoA#brWU$K8w6QoV5sX<aJcqm=AJ;!B&WGJgB z=fT#c^WTHM!b?kD(?F-QhxH=qfIbr;gW^5slMt7NWRV1&HcM>&hR7Q~ORru8Rk9*b zRbZ}cjVMK5wp*18zas`>Z5h%|E6F@P_sU30f)daIzrY`(NdmZ}r+L2oWzvda;>4i_ z!wP$XGvlA3Lxk-1(L0&PiGyh|3kCnroeKXxhx~hqts`Hvp`yI}>Cr=ET%2<DIVh)m zyuD*#L>0p*@P705ZC5QK0s=i9P0?ny2v8P5mm+CS_O8QWRvn1|7A-X=r@_i&;A)#E zBRzefgoZ|Hp%UfQ;qO+`p_N8^>&fj>8>N`oQuVr|msL$MF*wK{ANlw)XUY~&|Licr z`U`F&;g1tBWG1L^=_qtI8$Sh&L}q@J5f>-6&;6N8DT~i<xo?1jg9BMuFE11Wq?2GI zJOyPDjfORTJiLR3hFccnF`0CB79Jks+X@oD#8%IT<ICjgQaXBet1tOErC1oab;c)c zzW%{loZbub1K$MR58ojszNObLDlf0syHnKH&*|tOj!KeBEcdv)_If<cNK4aHL!_jn zxH{l?4@9Qk%fjU*Cto(7f=<7OYof>7-#d?ulVJFSR^<O7BKL}b$NBrWZ;kE`d4+o? zU&*s`^cQN5hyj~*{tJ`9@~G;qw4~&<#mdCO!u|PA`>Lw;=C)SXgX@~T>NI?Ula)q= zXhO)SB88ERR~@|83&TTG!<RsZrlDzX4*|`P5YeE6bfcj%N44yW%1l-MSejOg0ar^$ z2j#}_YNh>6-4PEe!P0E4lrbbaO4l($*0H_>qjuZ*#YHBUKCVXOD`8=O(8cR(>vg;Y z12L4r>H0bw)qJ+h-~fHR*cf%pNQQ*{?0DH7@&}DBe0Qw|lQ$vwAq9os^VP;e8$eNp zOt`u>a_ZjR-|vcFEwjYC4G#~eh;ox!mYVp}C%0BFWqdrVzRK6SezWof2bth`dHbz0 z8ok_qCSQ*6w)N!|TvQf=KOC~pO%z^aNx}PKpT*DWiZr@vpJ!fKo~(MW4Z^jfdbPH+ zz~`<g-o(6l_ok$vKv%b8IhY?B9(ZU!-cr)jhoAV#cSG7A9UZwCC%?n%KG|W^0TTZ1 z?(QRpbwm~O%`Vc(N_%jD-uJhD28K&>A9OVYH%$g6uncN@K~4#iQWm0bq<3LqrZ+`k zpWcyC0s_L<t;wzBZp|B%v<i@tkVK#Oc|8w5n@vwoyBa4ae+Z5Z@Oh&EyThQ>?sP$D zJlZtUJTKfrK~5Q-#`ImQ5GnA4-%FObwrePHxOhCTHcJ67JPb)L{Ua>;nNt23>y6oR zn{eW&mb*_mhu7mAi!pR~NZ@SxJy6vI!&o>t>Pz0S7SbgrCwuJlim(X7dL(|<hcIU- zJ9QzSQQ7tt{9$mPs6z~W4s7$NSdy>kGYQ+!q#oMsUWn5+Pxn`*%T4iXF$r(CTivh7 zCxLSWO^ZT7Mo-^|{<#DmNYkPOQZZFk7|Nla`c5OoLccLXT@@7-dF&Kbh#GwV7XF7v zRZ|n`E%a>U`^fqe&n~j;L(39KfA7_lXI~O0_JqyS0o^!q%AZN^aL_`c8r_b1LlpFz zoKKoO4~$l9!#NR9BTZH-hn}H=DZ_}IkM@6MuJWJE)xl`qF1uel?oP3Bat0K<0<S{? zypDi?fVzaYNh}^vqJ<^Wpo+F_$gCO{uBWf>Vl?}=2`Fmr6%7(`1ro*ch&z!!8I(Os zY|EqHZ2);c5@O`xbSY*F3kd-s&aY!pLUat>;WF)NubIO}D7eeTI>T69-oddkA}%*g zQPJ(fSg}M#jitG6s1;s-inls#ZA?+e0*@(wjLzGFt>rlGC-`z$9haRBnZF0h&h7nu zV{>!-^t;)fo-ayDWHdA>&I#TEua>rCQrStM!5Nq@CZ{u+`~e~Z;=>08DMY0gpS6&F z6J9OLiXE2fs)-3^KmyZ^$RLQAkW=Mf5^-+!3@Dk;mMqoSw(9bdemQ~yDT6$jbR@l= zWYqIY-RF-5^QRXVa^li&Dqw-vl6Oo|s4>fM>V9{QRrUzTYk@bW;~me2^zdiaU)Vwa zbnl3UX7%w(D{4Ei$tVVU8Hwi}E;w+*N8dj`QTvzH8tRG{0K|fP?YXYL_WAKh%)|tG zDG!<ypU?YwqS5@OzrX)G_9!p}vPr-D$jC4ScWmgZ`1c5G;#ncVxZYL0?K_aQ-Pev; zs5dt@G<4lQbRA6y2R9Opx+5Pn$MOu`xn%GxS*UeCIm67K;{q=tHa=df(ah4#jhhEk z`^V0xjs@V;Gcq!Kj*JYA<p}w^hN{o57TZ(#=G8R17BL`Sqc{z#8{7s~2)P*41md*O z2X_7F7Q07&S5o@Z^W~VHAvPGZ?BIBNkhQpcwE<=ZO;w^mA4pvqLvOXu4W%&tq3N$S zfVuN{zSVv$>xX`y94@;9(^AT?^Y#`kI2f=;(-RV&Uv@nKEYIh57ywYVq~Bx%`1bbI zSLUi?DJ<n0kt^N7$bsrf<*RL(yw05q3uZglmVWh%C6zqN;|@o2PNQA%0A^EB`uu@~ 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�SCc-LqWHn4b4@~qDSAls(jB9J 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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/home-running-nl.png b/docs/img/ux13/home-running-nl.png new file mode 100644 index 0000000000000000000000000000000000000000..21f5a47ecd19b49261e7345ba30af952c3289120 GIT binary patch literal 181100 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℞el?54j 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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/home-running.png b/docs/img/ux13/home-running.png new file mode 100644 index 0000000000000000000000000000000000000000..51d972db1d5d13adf7dcecaf28c8a3c64e0f723e GIT binary patch literal 174349 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"v3chqoAK0Oz6jw;gF0@u29eNIl!<}Yep&2i}l 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%0DTa)XxrbMvK3<C1kQM47T zhGu(bQE!#glok{8mITI*M$_uB%qXs4XhwBeozHf{CiUcS7$#cZawHIXJY002s``?@ z^LW^hydJSV-yDA9Gq8vqVZO@bRcSvuV!7sc@F|SPYO|3^roiU`E0)Oy2kUuG4Zd?? z)=CgRX7G|UD(RoYbCec3QUl*Eg#i%9X)~2ru>yCo8}50S&%nK*5mDXXxf17?3rFsu zDkQQ=;c<C~{QVb$hTAKizL!Vzvj)Y@Ul*SnbZg?fSq2uG1fy0~|A0Jf%5NgBoCnpf zp(#-~NEge+d2EK8)g23saW{Sy>!T25W7hwHvaSrz;3$~Gb+qg&@!=T`qaG$UaXPhX z!FGkN21_y}4$5-3f-e+xj_8}{&=1RbzC1%^<50)m7^2ACbWhaWRP7pvc4Qs5{t-1I zyS=`LY*}TLMUW7(I>o5ND()3#BC+_n1;c&_FM&QuxB?HAyjg0GAW__Ap=YA^z5W!? z4>sSPZAoQC?v0nqdIv=r*Uj23`Vo17w7(g<-)uz&sICdpo9^wal<~NQ<IfFGU}<pU zc5aHDyMLFTVNq%Ka;nyAqWLgsHIUbtyu%{<!h*Nh85>j<^#;XaEh!r;s@ZKdcIWTZ zFkTH}F{q%urRaG%mf4PyMNYr1CTD#<E=9)}R$?y$B`Lx#YSCii$mI?iHQsS@Xd}U! zMxQ*C5i~rhbSX9tB`bN)95X=HRySa~n_t46&$RZ_>9Xh02*%UKIk8<bkT2N!^9=kn z9{+37bOr-sp!}B&;kDZ!+l14-W9(50j!JI)cq{PgGud!ti)1Ejt_4^olxGPT#MR2i zINzqW6q!{^8LKawoqh*Go3iCfWLx$e>&@Ir-N*rH&|gQh8LZdf_$_4T;cDsL_>a%_ za)9=9Nhq)&DQ5CG?Ih6^(bG2(si;y4cd%OZcm+w3EXf}bYI9tiD7)0JDRJ1$7E$<E z59Q6TOQVEGMI;E*P5h3xDQ;{`q)9ZX8byD61*n+#8-a4NLF{a5CQY)@71WGB9T{v^ zoQ=)(Y!MN*%dKuoD@XNl>pcM<%XGH67OsiXgl#D7qWVrFGkB^$>|&fP*#uJ7C$Sxb z$~(^Qy+ttU+I5Cc=&He-@Jp;%7JGg$HID?pNGj|ejrGExgldQ=UP{j~J43*EdF<Ce zi46KP#ah@=&(&#}KHJr)?qW>H>n>aV*|7IJi!mY+^eM2;Kbw%}d|5x*0=+@FM%dK% z1Q7(k=>iG9T8#7>GUvpCHyKJ2AYekVW8%LiA`qr07eBw4FWE#g?-S<8qBKM&?wYB0 zjK*7h$*)wS<mZfAzE)<zVqg;c$g5I7k^$-qC(fV7>+R8$zymVG?Po_8&;xi`G{s1~ zDQSh#Ed0aq{Pe8!I{js&ZH4xK;O&68cx7iIJK-Ctnvf%K{dYW?k1x{k+=rr)2z!$E zshp+%{^<~(E>trGk~tmWXYH0H--zfp7(xW<=l^g8#}q9h`qM0qZYdCkc=m)eW?D2b zO1{ILv}_;0poACqqjc!qs{Dd&!{uf<*=%}B;m=qg{Y7VJHSGGcv|>iCVcaLcSW;8a zpW;xnY`&2jnl%<gv|0AO`P9NUJ&kNhi>q9+73IhWwtJ<U(8f!co(Kowo^E!t2Zv?} z!*ID!R|+L5M_E_ANgp55E)&tKcWG9pmX>Mbc=(Q+YH9GrLZ@6|N@oxGHcyiBZ4+9U z+-+x5!M*qUKi70aHv?$#>r72maG4BZ$kyjFEzp=<J}eN~lj{q6LfCUmFKTBh(qi74 zY}SwC(8tcsj*=2<Z}(iryBYQ#1?*^>OeQh=Nf<x`Lh16|+I$|((<z%SFnU9?bi3ss z?#j6cVxRfVw*0}dfZX8$;|BSBQ@X@K-{A^<%#grcSAt`Qsi^d6#}CJS;SYzFDBy%v zRC3elRs6F=;6>OB8#376lVYN6&I^#0M&NPu%-?oZ#<aFB=hBQ4OqGSf5oy5sJ6-ro zDW(Nk0pIlod@$->6a<w%duofaUQH7NY0>wlMpm2wRgtBXsC{zjK86)jM`A^MF@K-? z`0C&{Ng~zS`AgJH`r~Rbop9a>9JVAf=G<Yut?~8k&2+i2bwZhIvTJf-p<=JFY_z;i zue*nY0XW^{!n)B1t*^@NGanYCkBss2xg>~*{KX~%zXx@Q&V?%oJCW{4gvsZuXM4G% zL@3|xFb)l46I^Y*-Dlt)Idf1I;yQixuAI#CH%SYND3@A-U@G-qjA}6kSkx_l%XH_) zJS_mK*>P^Z`>waYnH-4_0^~hWNeCy}3J3hZybBlGwbHuw_ZR!(9lc`#%u@xeFJ2IX zK{>ko-8=pTUe(?(w-jSZq<&O2BdQ}ErOJR0G7R>1(hm)-r@&*S+31v8FCt+&RXA#} zaa^pV{!vG45QFyq3L}M;&ba5FBL)p%R-p&!#n|NVe6K*;7Eb0fCTg3rjeg(6SJ|mv zKvbQZOGtk&7u6@SBBCLE`3rx7seZfG?i7lpcbM|tTD{`p`mr}wOx*oHSb$6#rB2pK zUhO9f$w{SBhxY9X{dG+T`Hamfh1gAXHU}1F^%iT%AR6!Wpil90TZi{!K4JWkXfOH0 zmgDN`SfX<@<HQs*T1D!^rs8hUCFs_O;TyPbJC#2Z{)$^KY$dycN0ADL_Y2J;=GP(Q zJW3Mj^EZDtmU0$WU0W-qB2h{&=@Xd)Zs6ma{<e4NEum?o6xHB>N`A;~v?p+Z21ezj zJY`~0b@wUT?$Kkxss!VLm+mu3b91000TeS~abJQ-86CRR>fENa?g3BwV@`*Kv@3Kj zjVvNO)>!(8D1ct(c4P1>5_R!vGBx>on|J}276<75RC#{mi}(l`8NNJ?PO(l$Rf&J1 z?rG@@d19kdf-6O|hgetLhXWO;m~Dw7rr1O@ON}(~69EaJkd&I-U%0REHVQ`R5~fWn zDV4l}<)P0pe3r+5$zh(`5uKTm=5Pz5E@P?b->u7dCs_oCCoDSA64<kywAscLUS8}Z zMA94jN7^GSuw=kO9*fyp_j{irr4&{#ZEPn0`7HIV5$T0WY|v7r8BkcoU4MR%_4-yP z+u10uVJq?{NNnT_HAlIU$$B8oQQqG@x*|FZJdOSb4bq}Bnf;b&%3hjCu7u+xuNMWI z;ReNMYt$_JyX~jQ-ZDr6q@$vl%7X=uSTYoF>KIGp8y;xr(ImeOd=ed=+5K+C?RVm| zq>d>0w55~H)SYB>cEsK%MY(>odCm+@(XjQ1irDl9#<VYYS>qU#=RY$rD3^wQO3v!Y zZKAb&+hFxw<;UWxN#U6KO1-NF1W5*f@C>BsTgGZae2ZVO2(H{(j}r(j+>_b03~AwZ zc^C7PJ_~1jbq}=>Hj<&Y!Ev!tgF6C`m|}KZZ&0uYbvb6DfEbb}@@*r{c<Yf~gAf1w zcBl^=Fx|;{^yp=b3%A_{aw4SQEvk3_U|L*`RnoW>b)RtXN;@Ej&667AjBvhi!GyfT zQxfvs<x6?xl4!r&y1o1Oju$nAUp2tv%{3`sv>%5f%5$t&JqZu!Yn16%r|VE>!{uWy zbOzc|*uyO_B?DqI7-ff=i(zNd<UpN>zP7Hmy}*7E(qz<<0_8bL(sb-l;(8VGlcbJR z;+?;-WAUdGkoDVJN@s#f^oY5hZ5*mzuLJ=Yfp$MTbEsh~u7rz!mVqwGu9u_O`Q$3n zw{lTDy|#DA8`;v4spXHTrhUGIik&P@w5mctTlz!g0Soi-@g?)eBf-FC<$avDu`0jo zZBg%->*M;q#3{zby}!Z84lkn;;JkpY42Ud=R8@Z1{etH<5+|s$jZ)^oFKYeL4P{E? zK)A{c(Lg4N-Hyll^~7OFbcTdQuJ^wA-cOL>A%}lvk)6HDvCV{yK@#T?6K7)@xnUFU z1Oz{POy&izjb$l{4uxHa?hq!vk{9&@mqk^f9L8O2(WtRD@wIDw+YR;LpIEfO^*xdn zY*X1cj$+c+qzPkFU9i{V-3&97cZ|nsjYBc^dJ%*2Z@6B+{`oed=Zx2BXR+0+#5{_% zD^P7QNPf0Jks#l0UsG{5y6k04if)q!HeFtm$NJBksaCT6M<I_pU2T%_)Ft8lgn<YG zZw@u`T{^Ew1losBeZvdBnF5|heV;QdLysVj@L>v|97igK1PhK@Y1I*%(%=4QQ3QxU z3(4GF74puEZ=nl({zow!U&f3F_wa@MjR1tzPqv885au<-P<uNdpVRfU&u>G-b;*+I zefF8vi%(i!2dd*$i4;Wz?rh*AsWYYLvWDi3eM6+HA7o4yCbqa5U$^MvLj|A&g#VGA zg>9F0`pusK$hdZo&4TuKn-quI<tFIPO!|H2%j-Dv?*e>NBFNoEXFFH~9}}Xg{SnRN zjWp?)g<3_I2-eaHS@f})lc3!U8VZy#!OT%keB#tWQV>W0&A2dE_))Ruu!C4PtgwWn zFSLv%VP#!TWl4USHzzaDfc@t1k6j>aSW-cEl<h(}OkXpF-Ui)0GE3w?6x9hkF{Rn= z-nZ+8#pO%Q0YkK}(JDyq&s`h?O>Uh`N{4w&;1U$Slm7^jzZ+HEhSj=nHR~0+B~=8l zg+RFln`o$`dkyaGIkkYV|HHt``7-q3u_1SP0N?OuDQeIyg(?fw+^<y_tiJY>K?>sz zIuvq;sHBN_sx@mGT|nZL(R{fvvsb~s@Z!?J5?<(cjiuAcPNwlH7IV_^(CuK5S?;Q3 zOr`x?dGOWg?s=lGUOk2I%Ud|F@9I(X^{14vlFO1Z&+^vFm+HUn7!S}eD>C;6(tI`( z_Mt&`_Po7OXFLuxM0d~CsAyv`_~C`0R$67&3RR19k%}khkI2Q$Wcze>kRQ$H7;1=g z$n%cW4mDpMYr*%1=L=^&au&KY8cW|%eCp4`_UEBU%IY%W#s{q*qv(y9G3!P}-n6|> z>>$XWxCqO|8A*=hXM=nwb-vhHe3wmHR28Za`Qxj0darwg`qMEla*mZNh>*(eVb1+j zdhv<L%-ZPMJ@+pqb-J1BhjYdJ8U38s=j`6-=(k&*RBia(-5qTmj5Ne+d!NPfWth0y z>bz?2I|6>Jm-*%PS_LkSumfus4G|h~gkQbWFFx1Xr~j@+6Gx1s%Z3!`!c6$(%i}E6 zLM!Jqx_A?O4gYz6Y9l7Kq8clB93fM56=VM?Vq0=kGO7}xP(@(wBs3H(MMll?KDqWS z%|Eslqj}LW$-K!%rj*>VvIgC@7O4YuEt^;i5<BUe=A2`%<N&;*PmEdItjXyM`?mB( z6P-B<AfnmN6eqsaAI0u>8$M5|4Ukr(g+iu(NAa^JX%!i^jvVTcmxrs}IT{81RC90A zUN#%aXp0mTcIipswpGegg2av~-6j+@cTve&|H95P*;?H#bH`73i&+roB0Y*G?tg}A zSuDUe++B3LBLUEy7uW*{qP%}{aC~XECb$2&7>esggUVsCM8Y<o73LL48MS&*#)Pk~ z?gmk_Mdf`Wna{#37j=<@)zX_@oT08b8bAJwf4zb}p<GY7x1V|Qa61?{9uUWfFIWl% zKpC3ly7^*xf^$wA#YB-06Qi)n(HGQAA<9qKlk)YiXTd0GgCR>9iMlnApt@-h*G$S$ z3hmh3N8`zv?=B;zv)I++1Y$~l#ms6vI@pW#A0}%L!wXkA$YNWr;Fy-#<|R1-<GZG_ zE`_`|_p|#4riFBLX0#=$cnv^?H0;n>)9M_wI!4XZ%hcWxQGZxnG`w5v?!o8CaZm6G zlz_>bKieL5J{>@o_$p&XHmF}JBPu%6g-ai+ajv)vS{%bALLaWbqT#Dms2H6^f+FM% zv8>PcZfa_0zR#AHCXp;8?)(e*20+pEN}a{F<lt<!SCv^cX9BehtMBBM;5DgWSa>A; zu^K%E`|3B<V*kmJmXLe{&CYa%r9@T7@VIF0Mkg5S=X_K!_aAY$O>Q;kZ~mbWjuee} zY=N{iGV0Z$yWxJwS3AwwdB`GJ`(Ru@Gd6~HeTH5&gkzUO`19bS@BVa!g~jG@ex6ji zfb%nAnm|YquW@*bK?O6S@JNw@8M@I9X)a<t4LK;>Ep~eR+Jmyty8r7JI_B`OLfk?R zb(rQ$H=e}qk}mtm%e~*vrm@{@+OA2_W@Hq}Db3S)mR=y-i`}08v`;_zhYzmZfu#$( z@W{yR#SS^F*R8*x=zLB+t0}0y!QJd8m@c_o?JVr)z{Mk=!h2Jb3E(pf6B)78)MRfY z#Jw@D)p1joNpAa<CZF?>;7e;+O1Lkrf_$sAQjwWPU)XZPirG-!dLX%)9E3irPh)er z;{7vtBI?~`v5<G3bCx6JDmktF!@OD<P8^m~W}87EPp!e2H{QrWW+$=2phTniX3b1& zS=nq;*<Jr^>tk2Z?|3bw@%Me1+}By8?=`+3(kqJQxGE?qE_LUKc2HM)P<p5yulRnL ztU~ybOW!7%?Ib(Y^};_#BnHVBkKw&fU$$u&#ro?}QRuVo(AU&oC#tOx|Dq=e+-1Xh zaIW^ZDQ^*k)A3_U%d$JZ4ueezVS-xL_7}AUi|*CMg)#|?*oul=#RU-IHCSO_{4QSu zf3LkM2r26Le?NVenDOBGn`3x&!^8JG!p%04Cn4Tb3|riKCp3J?#~lwfE`{Ls_AJWl zNEgM`S}mQ+0-bNUzA3D>QT=iN5L3OH_(#FUFy-&g_DCL4{!2XmO6EmS;QWFquFvxg z7>7sGQENIu_-Nifoj=x7PMXLLO_D!lQ&-p&=r7K^A0HCdKX(aX?;o!3?-*7ro{9|g zk{1$VnAFP-k{YV1)ii}z94(?q3EvjR$H9xnXDxoFP%SShEV*SnQY-XYbJ!L?Pf<P6 zfX41f;*kqG_{o^<k9c>&UClT#;O$6~&=$6&a|s`BZbQkrnAIWVM0xbWFJZxvL5Cm& zn?wKitfG5=iE;`ZF8a+KjX+h}4vV3j%`Z_a_<Ho%<m42J{>K=_pb*Ng#L>Yu{e>U4 z&P={R#3sbFosG5M5vq(0YJC{&e(cG?y}UVH-}Z8MeuQq5iFZ0^+m@B(iAXe@Q6ZFT z#eZ%j)l&yd)N2BUgf_hh9+)4s9nxRa+#U4MWUMqbZ?WL%N=#%MH6>`D!8-4?3Zyqv zQ}YzAjgrwrjT0JwswH!|;h(Ndbc|u<h-}{Fo?(1VghQ@(n#_wn8@HmB5{=0Hs{ZB6 zK7(vLp?f6d>K3&@iSlS%m^7|N>Z7dGk~}YITg+BLPydYuoy^~6A?rU71IpzOd6{oz zJVCQ}`;PmatsL4R`F#Xq%9XI7tQE}abE%f@c2e8s%M1NxCviY-#*K>i5VzC=$nNyD zwD#SmE!`s(G({@o-~J;ZxTA}EkqK%(zSrX$X!%HetKK&!2=i|?&d&RMekO-P)*)}A z1fEiwIF2NsaA7`1(G%#D;+<38)}f&j{9I>L#{Z)lqyNzF*EL(ao0#bMRz`N_hK8}z z>=A#nX7XNu<HO#>bSelFV$dlt?P!Zg?oazSImIf>&oiabefwDSu~BFHrdK!%4T}i0 z6KsQ`ShEuDD10H2&bGR>-NzBO!gR9x*{x1W3ZjXP70uUA!7eM$V6JPby@p?-qE<{3 z{?sT_J97S&_(6+lf4Usf+h46wu|lWIx&o-RLPa7o3!4_x&EVf}zQ@z5<B{TXSY6%3 z1sJaz*Bvd!;0X!|0Xje^;#=8ZY<u6-R2TFy<dpKIiS|=COO7u;h)fx%^lK?AtwP>g zXz@uWm>2?R+ek7O=n+IY)ZuRWv>Dtu+WP6Tz^=@CT?&QoYCBmsnpYb6aJIr?8&DUZ zbBggv5kFpq|7-I<Sb*<897k<Q$;rC_XZX?`;RSh+>@@zS#hys7jD<;J-_q*!xU~hr znOyPrcjlc#db-dTq`!VW;yTm6_d50iZa*IIgsv1wVh#c75wz`LuSA7MW6-=pM(zqr zN}A(hB1m+mr~doCzQ9RfZ~*=c^121`j=Xc4IsgNq)vKEOYQX{n6M*#%D6np#7JMW8 z?w=-~u--2~vk)vTvGH+;?(Yk<VSyK*6A}WEcZZ8X3~Ouapdsjky$wf};;i;GgJOyh zbbNAKi>Vqs$?~g|Ad~3sWOZ^Q8R-==MkK*+RE|;o`h(qF4(|!tzu7;K{D0S`Z$PM& z70c?GdLZT`=nX-{zs`p7Fy^D8a=G@)MY;Nkyf+gW6?J}cF_5~Tyi_3wDsb;^PMuqu z8*ZFq!4-+uzq#?|<bE>)Vm@fKk{qE4XWN4<X1%RZI&M0eNxg$#j+oL3jaxG^%ALyf z^j{-6KOp?Ql9}z1K+7Vq&Ro7Rxy@qG2G`Twi#wEwOWyRilgqv<64Z#TLn5+|wkijL zh5vqN8NvTSkl7#mq`XiN%LJ?}f1dyXa?`ao;jbWYO;tisgPWdD>glech(crE-DP)B zL<i+!{yrw0|K_H3k(o}!q0=_pfDaeu8iW6o^phh2gz_BLisa^tUr`ej!E3w@{`&wa zQy80=Twc21Hx+`EXRPtr-dM?p#9w58KkL*D23};WtfHb~78ZcUymr|4_Vx&N_DyzZ zDA?uxegtaxuN0KIXzb(;AT5*{C~jmrCfTzny&xEW?Hh4l6rcHdG>VCVfE__I@Z-Mg zye2=t?ADB!73r;|r<fut_^9PuUrzQh@yae2&w*17GZn;IG$@F#>h%Sz2_Zg#`H1Q3 zzh00!Z-iIT;o)LVss;w6yC2z1bK=JkP!KR_yMZXi*v!~?y=&Xz6(}Hib#ZFogBk!{ z9fE`gFDcn8A>I3@ElEmS)j&~0F<9C2yJ3%@Yv{D{)!@+&HUtcc+sYI8u2W<74De5O zR*;QieZ)e`16XCG(O&sb{l>2?#DP01mhy5!f=UugdP_E!mtc<i{!V;)1O6^w!uL?= z<`G}|H?E*G?k%6NjG%nM0{Ct_ZQ_WN_*GCqB&d?wfVdf;^Wys-{Q3W9<!?{7;FD<S zdI}dam5iB7h>ICz^7QodZ|YlHI%o)LCE3~A3&-?$o=*=xJ_4Huh|bXU5}+@Qivu;h zt=WFhzE}Kvr-pQysktb)xV(Z8;$xSU5So};hFa=pspb65kF*x~BFIQV5fEo&j>PeF zXY8~c?$;SoaYk{Ni-@UaP5p9GAl@;C3kfDSwfGx+1q&a}u9f7Cgd&+lrDP2*Hg*@8 zHR|68%D+p2aLYN=(%g7RdRa9Z|2jTAA|fI*bih1W_TQUItJ)MXCQ_`AN@)P-zv2Sz zbEPCf@Qo=eI~I8NP#J^{DoPlbK!u0mmM3o$1%mKB9?eO^$ESw^ncae2yss-{Nfl7G zXW6rO#F(81o>br`a#&&oJ9v<LF1n5^4oRi!SI9RyH%}KaOa?v~ueR_N2p<$rWaDBU z`L~Zx+4#TjYnRssVt+^oEi4Vmo<4t^R9}5>*MFY8fnJNnr#l%Vzp${k=t+e3zc=+g zz0LnrVW!9rP^7x!MeM?;SID5k$-><HHPs*xU}tOo$RYTK@amO|+coV|don1qlai9e zq1RLz8v%iaWmOi{KYpM;U80@qU%mpghZ2&~b+)sPBSeY7-8-6Imj#Rkz&{cd8jAMi zXkv44(tK#5c__D6G58fB`8&|`YCE2j?>_^a>%MCnbPBL9U&as#0+F5C-(Acg9RIq8 z3nT@~VKW$Z^ls}V+6jKE(0pTeV7W?@%Hb*X<(shYQ4J61h;sV#E89x-^}jogJZKFw z16pD}*MmxvUS>82)Q2nE&fvG@<@R#%w9AdI@}N$js~dzuRef9v{`JdVeZE?wRI}B) z=_leo*pxt*w>+@Efym$zJ00L8fk#2Gn#*c!YlDI~M<g7^O6y@hll90J4;P?%#FP4m zM8He4QLWg=+cQG(_+Y^|3zV>BWaxwb!LC6e?|b00v%IUJdwNdLA1S=lwlok?Q3um_ zzmi4#PUWiuaf*Y0WC3e$lk5I1urUr@UtZcyf7b&^4nOUd$LbU-hEwYf=NjaFkip{y z;_h6%&!xntP(WrCAMkT2+}yVr)ETXVUfUF2ZaTF}kwWIB?FPo1yEl~}>TY|)08ilJ zKKBiX+y!Z4k|5jA<6<W~5q<~6F#fwyR&;`lIZse24<RHbegtNIU?dt&5<+H4WYh{~ zZFH+3Ndf_gFV2nzzg1vm+G|yPGI~m=Q3m-eAmkH7TIbp%j!gV6P)J9|$8Rw2M-;Wu z*Iy=_t&oHxo&@1b7gtyFz`#{tVqy&1@)+ClqN1Weiqh+}v^1bV`J0A$=L#0<CxcaT zvM-b^`NjD*xk7IjNE(atkgjANadUQ-{uG6vqod>P9ROT!p3UA2sk>(M*W#QJiH!VS z8#}S>Fs`m&S)GhcO*M<gt}_$+)A=>p{a@tmg1Zx_6B(Z#q;Y#P5a-o9`iyIaSK)1B z5T{@J1BiqGA-W7>$02^6+Fx7K=vn^AivU{%sI+5f?F!8H^NT$hWQ|#H+fm7pI0Xt~ z*PXE=5KIpOCovO6JM<Mb+^)+Hmm074=CbvG<pcH*B>IK9yZj3D`yjrC^gu%b1qQ1e z114r>yUSo({pI6uEc%nR1e^S`cT8!7*3i@Z5-ya3h2cKd{{H&<`cGaTAH#2-Kl%WH zJ`QLWTwgQJ|13mCCZZ_3It7yFx{4Kc_4w<;&e2QdN!hr$b*eqgK*d$b`?9B-8Fb1c z3j0MfCX$kp(tvNQOmKE`apenj9A7LJ>p)fR8qR1d)f^XdcjiZ|dTH0v>}^|G78%7M zHwZMHbexQfY=y)<tC?*s-iLcv58XD>FYg(v>?eZ)gIj!|<K%^hP|S}AZN#|YaUX$j zPcu8U$zoX`dZMYX$<yQ3bR>=L>tb~ksgMs!OsGR;T>|^(KTt@3**C`EV7TXxULfWI z33LtPv07S!ydPk3-rL$*u6A1iMmCUzOOOciN|bk;X><ce4Rq@rl(&0T*+MVTYfX$d zLXCipad)|;<U*XYm=>hr0CfT=0G$VsqE8#d#2E0YpyTLlS58b$rgJ&w@tgyUA|yKf z|0KFG2Vm#wDuQAY+{+LUe5Xjnu`#{RJ<i5fp}Q2fCH|-Nc#IS{N47>bD~(F_D@9vu z%bXei${I#~*^7el_PZMW^`CK79m4(E)Q<{89Gp7p@*m75uUZ=U_`qxIO_%G}sn_-u z6-f@xnDrT&T3h?;5ePf67W68l=mFg1GS%&M456K+CHdHB@2|%?rKXQ%AZ^-ZZ(?a? zre_7}ojSwx68RwJR?yR>$>UOc=`Jdg!@Q=pmiUcz7pQu}5=x~}Ji-}HWzwqh0-aSI ziep(mOXQtW2fwS`{00|6i^bE^baxx8TcNpZ)xn7?{gR(UbrMXwU_$3)6!5yw2spQR z+eNf7D6N>L_0t6bM6Z$Xncw_FwM8?U=6eiTS05%cX!NKKat?^ZXBY5>>}{5CbG(j` zN_l{E()>&6uh!85)m|#M?VrPSe%mXGL@i9P6->^~dR}a3Eon~!|H$5KdB)^2j{9BQ zdI5-FTb&EzXdrU_2<U0j#fIyX`SZloH^ngmf_$$cw%=mXmVs@TA3rj3+1<0qvrZgz z`z+M>JpQf)=@cLgW=%m}9t55dOQ9@Jup<?)6-r%N->`g3fQq^$kn?|Qc7F`#VR|G~ z1dU7{w+}yRhVEQT@^^KkqbH7@YKT*g+3nx8`FQ_ZE&SJ1#<0X!Yqipte9dprwKk}3 zPas&@7ME=Vsy`<Z2)n^G%oXy6_#@D0-9&eJ{pfg++2*15Qvtz>+KwdSnL+D_lUDF9 zFq^R$z;xfvo2_5<RakJ2gccD`_6@&;_394%;V30>m;?%7xHvd&Pfjs0&J9|9oSl6m zlK-BJsHo1s1PN$xawP)eKM+FEW@d<7u7IB2(!=dJLK~K`$G<oA;H+I}>fzysv(5e> zVc1P@@T<`M!T9_L=s9T_i3l+n-r><dauWHw23{`l*S&ASCl=K>qG9M-DH4%jZVUDE z^HEUvkctyE$eW;Y<HFwhAV=5k`}t{h*r^Nn<Z)O)3<TY*#Q69@UG69)AKcG*fS2Cg zqYcw^g<G%M$kWS9tmtv$R{m7=npA*Jzm)a0LSz&S45rY&+V`9FLKbkZu|4)Y9s;}` zbBPn@>f)?D@Ls24tkS`B6I5RKtY59HH33bR_sLGNNZWI8Y6t(drGw&ysd8nr)9_1= z#zvqsFV$QwR({k5Aa`!ar9qpS1{`JXSY_qMvb1i}Pd|pfxUW{#g0me!Kg%sw1AVje zff|Tm)|O87`zOE+0dYl=klPQ(p2#?5W$~963ND~9J-*)ixczGBrHQdgZwx_X6xVl+ z{mu}@uNKU#oHDG|mco8MFaE99rUnk4e=QJyM^k6AHai<zYA8o^UlpZW2EYVvRAUxC z5<B!+X_PtL+KaZY5ye$N?}w5Z(JD;%=;?nib#l1by*wnfyS?E3Cp8wjDV+xu_IXHS zv1h(bmR<WdEc=d`lp6cLzCTNETDUNZUp=qy@**M!I`W|Op`pzqbR`T7KD27ARtCwK zzPKt+=f2xa*TS0Kza7oA#H#n*s&}(S|Bn!k|4*r_|J%tyL}Pf)`oB8`vuZF%NudYb z`(SOHAmVl#t*_@<Ej+#SCB?#GESgWAEk8>7^&ISXfn7Ik&=cN25wQ|;uv}Ea(u2eK zf~bneV6gU^>MV9~J&)DT*~<}<_XSUvm`c`JNQg9i+cTzpQyI&ox|pXU!^Qs70^#U* zij-KU)#Mn$Y4P|?5B#}16wkMdoktBCzI!q7@tFfKGwI~?vdIz1G?M@Y(c<$JZD+;z zX5-*?kl<Uqfgu3f=VBk4wC$LSpSOAe{=6>sIsZq}hnwB%*kF~`Q7bxndXMhk!zDAe z30tr)LP~Y(Hv32myV`&-96|PUwwuA=IZUmA4^X-b?;4L+y#r;BBzzxLz_|K%f*~d* zCI{|T;7>y(5q$5%&B(a8UZw#S%YjkQ^w{Ec`I?GKEhXS$TSxI&F%xD3SKRb#Y+s~| z7)7;A_H*Ke+E{(#mw7c56s}egQG`?FKqJg`y*8biSh3Xgp@lsGsrmd8dU9HQwiR2| zP0m2%FYrN->`zJT*l=ji>U!IRPEt=?&KN5(4hdu}A5==(_1#NJz3%!*kMvR?0i#3{ z)#(rsL`N{Im5)ImrAw8JWJEFWZje1gF|T91uTHv_zb{(6=zA8C*<FdiMFquCY16Fs z0$q?|Jw>549AV$eU~ji7{8nHugI@DbpsJcP_gUG~2xI04R`a@cz@JtCY>6IJ6;q)c zOb*ZRh1B5Dr`8kF3rcG>Gz$8j-VM$k|7aZ$i?wubfv=*^c0e$+_g=p3&s4wI=@O6q zBj&jdQ5Q%6YlKzsC>RIJi5D2PTYm!GRbwOc_|2o^T4_nD^tYj8fF`E1ddR2`GEV4Z zXBz=hdidKgyYuS^9fso=e6B1JAZnV3Js1M0d9UKL`6~0>r54I>Kv2YEZ0E_Js&|hv zTdLpSk$^ZMXSd?*a6Yoq`SSAHO3}{hx`l@QA_-UJ^==#U?QI(_hFFf0px~1|l2(g5 zOE#AeejYe0zA%;Kx1=B5qml-Qi=mqvaf8OwKf9YxNRgFoCQR!9%V*vjLp7J0HfRVa zg938_vn`6%2$%}60bDa4<LB2N3lVe~tG+erA3$y(b_NiU*o9WU3a^Xn2iwwFAiH!N z8Y5DlKU(w*U9^bnxHV||=w_$F;+wGu9||BvWe?s%TXZuzER^RJW&GDBkD)z1QAAX> zFU(q9dwmYJw?DJAlaud_1UXst_VkP-HGy6eykm+E5<#!e4avnd+VNCX)j%_z%sAx8 zT!}$R+1aaTKqP#LJ2J9P!_w$xXJcW))HVvNUyLJUaznp=%Z1{id4S4C7*dI!{GMEc zBznJ%{D5Rwq$`s@u`{@=yc6zH>LB9F;*agvw<rv0x(B?*mP8d|^As3MRVJCA3hb6z zVqC9|r_F|g4}bpT9nou^DY5ZX<JcsizCF8K_$;Is6~&?7=p>#J2FWfC`>{_Lqfu_h z6Nu4`IGEWkp|}Qkko(Jn4;D6ppEmNU%;a(k{hnLtwsGwtAcBP6tSj3TBkI(;<KaZ^ z*+Ru<{|<G-!@~~N@kr#wvk_hiBDGliR2`4+_v`TR@v{~Ea|yYPvszn)<iObbYMa2O z$JOucAC=#3CovQG;j4Q^fY26V1|xJn0)T^u`J}JFAuW^7^M`CF-x^Wg5wk&4EpR+^ zghpuC9SDB<AOp<+K9!ML`-%~FCtfT%UBmtIM`jKhij>{40^S_oW`4&;q?tcSlORUj zbm-)nKciMeH(EVq<OI44iJ-gB?%wbZN;rDyLqxI8jt~@?ITvX5dL?A<Jp)BYCo{PN zE-tMaSw%%=TPE}+Q1P8q0ZbQh-aF{UKjeCc1n+^BsK)Zv;}&iEzw~d(BVf&vl<ozm zk-iGVY!#rxL+g8&+R|q>BLRw9L8&%)SM@TvphHiTk<2&aLsM9E)8m*H<=X6pqDv{X zfj^m2*8=1<?38GUkeoRpVX{_KfXU|eZPvQq4jQ_Jl0#o5o9c8r(&hw?yvhMg)~DQf zl2vfnNEWuK%E&lMiCV~P`SiX<rX3*N!^vDI>6xgm!lO=FjZUW@ZoMJfyO7UsOfccS z&<UROpnmsb<6qJ1g#n&A{t(%p`vZ7NgytKz$8MAZ;$9t1{S3+tXd#P8&|9hZ^k`9~ z)e(&<9MxwsV1+rQy(35LO=3}Gw)#O4bcR&bRSmpSeakISc)jT7w`XLu!k;d>B4u;Y zcCDQ;91kYgL;KME0rrj}SPme2atDp&Q84u8qSQIq#j=4);GmPy=L!!VaTORl3Lsy@ z@h&Ypo4k=TNx#KsVY8%;-R!4`w98gJTT->n3i=P&@|9*#*yCA>oB(a_ECi=~Wo;u6 zik|nwt;>47V5nHR?8^;C|1P+D!sg|uaAO`E<yHe^*eDR&C6d2%tCuZ=yZq5%$u#lJ z0E|D2=#>l{g=?S|c)nxbOZsEZ55$gD1~MUblyKYG+1VrE4#kkE$h`Uzw^Elx{e&r- zVJ5fwyuT-7=OY&b@g~fEP|)BL3_WjnPQ@69eRbxZNK;2?Ocqo`TxBsxzd$`0*@KUM z61Mr749tvBFbV>Bdw7JTgp~K)LyY|}JuXW4EW5lp`2Ava7uFM;f;g7CTG_te-vw|7 z7)rGpn*Fld0Y<KLAc=%4;-q1;Esw=Ofy48>3mnI8Z(DlVd2oh)3}n1{&2{w{qUcZ1 zhaEu-lXu>Y@s1XpW=~~PKeHGBl`W<z>YK39C@lI|)cfFavUh?WZ-H7-uI2;vPHLEz zX~G-1G1|o3$Ej1w53D?7@bB{F$;et=w?#q0;hMbT=ybY7(EG3i*Z={)z07ZMMU1fS zzjayYOJJYheFxf~NifP9Q$3SbR!|qua%lH5{u5o@W_7Rs;kgL`bp$TX(~%JoumfZ! zJ+EZyC{r0)Bg3NOoN|B%&6tdug^No)Ew-h&u%wU>7dK>sZz6eu-T3E|BE5m=038<? z&s5Tm4-ffm*JNPdNA1lH<Y5`mi+DhwlU0APo!5e}`eVrhYPj5g&hUO4$voP9JbF_8 zU;^b&*-Z?*tWl<muNT*9I~+L)f_7klDotdpft&{-(Q3WZD%r9Meshi?`gE9lxMB@M zCQ<@JAl-VfFY-gM%YAk(4f;u~{gMJi52m5ZS=Wo`N(&O^-nA(s03ziPzxO33aHcy@ ztYLn{U~>dch|R>6hHEq_674$6FP-!YJ+_`>daBF|3OHL6C=&gGD)v+iIIg`#_)-EV zG%Z7Z^}5n%>o<}3kq~#8a2jQ!_i%74qwjQen?K-_zrN~SmZB5tF0Vq{uySrGD#aK_ zuz=ogVF-OYX}=k(WVLEqljwFb8%Utrz3YL2LHTOIs9EdsPD+cK1`J2@H=9!ixqxaq zBFQlJL4Q^fQkZ!2wu@obo>KmM<w+f>u*TELx@!|00%N6GKAxA8AvFNMQ$XH2zk%<@ z8@82>jt788Kv$FwtwY1p2&Wf(Hx$X=B&DRt2(yJb%y&-ebUr6Y6ZFN$e+!Ic!>L@f zDzv^bmPJ{_d1Bx|+EtNkY-j{FA6i%r)vxwdEAtY%MY=rnvjNl~!`JhE8HRjy{DGy_ z2VwO3?^XALoLw5=mXn3)S8L}35-u<}*lO7#trlQO8)0mZ8}stSS{T~DEe?4T=pi?| zNT(JI<2pP}51g-?y}TH{xm8uy_Vjg@%-Z>Xuj<|chzL9qsx&C9xDwpV8LJxG04}J- zc1oHqt29Sa1Ly>G_>;BDH|!(&o6en()FzrMSUpOtTAs<SIUZJ489nm8$t@4%2EDY$ z#B#f}i`rB-)~(OHikWR#b(cH+NT+4Bgl-a2lGyY~70&nSz{N*tb_@b1wo7n2Ux0y% zu00YsmXwO+LuQQi1>BfJ_}+Yfms$-!FGK||jk;e^$r=nnH?Ui7#U&*iYhu{C06R4p za^0Xlc<A_A-#;lce*Qo)!)vmP;Vt+G=W4TfW8t8luhNj~n{j#$C3`KQn&aT-HTM-D z99*Ru`@p+~Xz=d6rbwp;B6eRLU_3cERPzjwk&)345q`6=b4s9>tyCdB!>`Id)aG6P zHLfG_q0#cTQEoFm9!YxXSm5e--s~tRVb*?G(hgg+IcrOowgN3x=;PYK^nTrsZTJZ3 zS4X+-nd5E*LiMBI%pPll`hde(Y40XF(;0WAwHdH9;KaN2zmzf*AF<kEl?u(Lfj4x~ z_X4)~;_O|1<<|kT2(c3NhKC&lj?*gb1jK<CIbM-x$G{M=3eXNbZV?4wjZhidoh^|E zivH0DSF59r1cYKs;%v8T6j`}B8ztbqfsuX}nZi2xOQg-E-*{~ZOb=zcbuW4+zH3o# zip3TVU*=TF8LA;(TK6nclL~n=>#~v};=D()u$Xv-i&c;wRa>vwk0IIfHY30pmk2|< z*2(=sh1D(qHJX@>)p@{!5&Zd5c40#T5#kx~;!vN8wPYW7?QH`?q`mHlVkei?jfAQi zFbjrtepuox4_hZoLU<8j*M2zu0PfW_c~i_duiB9~V&#+*4svY|D1`Fk``c%DOt@%( zsqf<L5X$3v!&3a}WyA*tL<vMTwwEpNp8SNT_i>0pxkiFFSQFC|lLY=L&e_c!sHDQa zDDZt?LkSM)+g$w=hXAZ`G~O#BMwzu(*w|64DT@und6-eZ&>x@O>L(9Wb&Kxq?PzP8 ztJj$`A-yH>;Aw@B5@GPq_J3|CQZv6TRPuVnY^DGFNl)oLJjG!Jt}E+<|72W$hi*zh zHb#8m4fYFkYo2#RjrwQ8mg0anIXk_#w6iXK0EcA2!#~;j%cHSE;U(hn^jQF~zyWy4 zCuzdOYX`9AP~5oz5>d>nCmpQzp|r&R6P61ySPc3Eb15J1_rO&Lv2$VtYEWrmhz&re zLqXn*noHz=2-1m3Gr$A^rVaM7$MWB!a+qje9wnuc(<%P-2IfA=zsG$boeDRf$`Bi> zry-@!1h1j+>R;Ye0+cH6?eDUGR0IPiT~0*|dBhEipXgtjp!k%U6_5PuQvnR!FYt}V z%%-NN-;B-njwwo*#{c~Ya%it5rKHGB#r^==SMD!uRcIz6ee*!A^e?HE`TY5%OHg2F zn6l?zR_j>S4F*QsTM+0thMJxjBUv<pCtA!jE5tBt_bPt90&HW}<e)E#GzJO|BwXyA zLuvgAPcL?7e~*DjgpD1vQ2++!i9_Q)3A*f`wQ!&RqYL;;+l7Prj_!f3uAZ>bQ9Obj zLcE>zwg(cpC)NX(3@to7IxIT6-Ipz@rl2*WJmXdFl^Wo)_s~jm4-%J5OfaY<&Wu*k zL)W`a1;9TUZzJp=dkjR=dubFKO@{X%Qv>K^CUCi<ZZ>cr5q#ly;h*$0XfmKREKhIX z77FG14vG1c4pp<>0~B3~i%+b_H-$RzJ;!}RunIU#q4?l$C^Vx6z7B<)>#M&ETIm1F zny>#W#;us;HJ7OF2d@vhL<Q^Xe>=W_3<CfH-hyM()7Uf@uyXIg$Hz3j=<6%0zxkx5 zNeMVb7;kYH7&U{xB<BiB*kI94(#{Uv12;Rpwgz`k-x%6>vq-T74G)z<*3@SzPfZC4 zILgi;9P_`VtM9_BeY=b$fyL10zygtCzs)4RvF=wW$l`q?MNc<9JQ|i+73)0?Q8=qC zAWb7Z=|e@QNHEOpzv}(v*L*#;q2ohcNiofZL>xzS*tod3=;#T<>|g)A!K%#ru}JWP zVr8@9!9Yuaup$)|&d$ybaP9wtv$Kw>vhCKrjX_8#5`uJtfOIKcf^>sODcv0wAl+R` zcXx_(OE*Y&cdj$>{l2|V>~Y39`!C0M7c6)e&-2`KUh|sQ@1I#a##b@nJ9q9z9m_dg z-F8A4u7`|Lf2=mH?i^g*Ze5Q+FSM$^h&6#cMow~%x<gTTC6w~3WH00Sk%{crR|ekS zH*s*c%eMcHGlL#7F&awaK>CI!y^gVZ?DhZf7yRoQUzV)>`jdyX`}fb6e=l*rK#Ksc zf8T{+0X=``pk(6G(g8AHg!uamAQngZul`t9zvBOOJo?8hFfGHNCmsUbm0YFXzWozI zA?=Rk12b-iHCuW4&}}>?h-OSkNcj6viM9OXdEFJulBTc*=`dP>i`<Uqx<I$!_r8sU z1OrjV=i4!XOv*j2y*d!8(i8!h_(&du_(1jhgoMoc=UyRcSE@9zI1KAQh>M7%0SpVq zfWn{EkLldMeg)(wB{{hwB*P9K4CQd~TT(fn15wE3Z2zi`{YJS0&I?te{?x(tFe6su z32w-sTd-qLFF#&tlXI+eJXjmdQOfgQJb~dM;M%HPFH+;;Ow#<HCc87b9mTsqw2POw zH??Z<_Qy-uK|~HMJ2-9&0ou+pF*AsNYw}(gFEct@N}#w3^C~;t-_R;ICjwd)@RUG} zg5X05AQKdPtmNT1Y}w(iu!4_l>sONmD#r$3e}WjarfxsLrg3(jzPu>}DRzq4>Ce`P z*7?kr0WxH@SZoIA!}T|AKi|9XL>uu0&<?FyEz=9yV)2D`7=rvowZU9{tRLN4zdLrQ zKyG*_M^#ltFT%|T@-5Gf2$hQ*$x>n3X}@+-sx{4vyVw)UvIIlaJ&na$mowYW@_T)b zkLguEU#o<qGT?sLZB4S7|NiZVH$=Vek(XzdrMSUrs;&flFSLNN1`%K3P^~mux~CeD z^1XGqHa_0oE-tNwCUA>FI*x!-HxRN|J$POf`=LTqki*&jro-mB`{SIksdC#2$ez4U z$Y;K7KF)gM2CM~JFOQJ%YA*LCt(BR*G8wZ~uQuncybiPg<tkGi+gc$j15BL|oFb4J zZ=(>h3jTf0_UOPySm1*I>{*EjYA@@9*a~`@aE73%-J_!fHnYouBu@xU{1RcG1+iM) z-LH3W!u9~04RQXKmlG?H`!|P1WLZWqoxopVwWP_sv~_P6#+WXb_}?uJ!f7>?i-c_? zuLANks#u3}Czr=kn1{Y_07n5rUn3zl`_YYMn6$qi5rFadHWNFk{b4o^j9*$K5;&|5 z7qXO=F<RZ!rwHB7PsR?q!aA0ku0%~KK<7%usYYHN@AUhAkVD_s;rt`<bF{AeuV?8B zYZt|?t$q+~11xunE{ENH6>G^(0BY<|bThKD*4iDJB_Rt_1Hc7`lYJg5;rS<GAs^AK zOwF46!JA5X8a)wg(vZ%H$71}w`etcq>FMbmBs79U`?I00uE~y$j)6|e-=dQQoLp@6 z)?j)^FY(!fV0!+~Us$r+54vKg6{x*rxI(Ek44XSgVJ?ZKHFU9a3#QB}qUPV=-rd*w z>^uZ!Hkfs>bB+LS39<GK27MsH`S~K3s66>Hqd8Rz&E)-kytxQDHxvlz|8nOrfm=^i zT|G8({&IKW!R(~vLc6$I3|kI^Qf+qS30Pgq^HUz-E+gvDSgl+C?779!Yh(_<1qCT~ zqXQLs_V(q!P~i#jgvV1r#2*(I*LL}LE@WCVGBQRVsZ7Ry+lr2kZe_s7!%ovy7;)gy z;8{sYNg=z$dla>;7LN0?bs4edHCRk=<@1XI_X3Cv92dhWkP;BZVYbr0l!x`W9I@R7 zGqw_y!BPz*-V7WYrN>xUg{~d+L{z8<3m`Swed>D%RzAsT-WrHkEw|fp-AVcK<tFhQ z<QN*X1q;RQ0T60^v@j#aOvhwzGY*2$(!Ip^8`l>W=yGsytVKjT3v`5Mw;&5GuIjMd zX=@Ae<=f3J{?wC5>4|TRRlIhlx(KiK&o+P=0gt+{2;XK)aV1Z$x$iDvgn@y<(e{ka z3R$WDd`(S_#-Fm6Z~!jz!7PCdM&gROfq~dgCu1f{Qvyxiz7bPG&n`g&2i@SQ)fn&} zw&xA`Qzu%6o5$MOb%ar}6e^To{u~CN1O$~ZdPb)I2@I4@xPfmurtLe~e>Mp%7>s9? zf7HbJz5MVQ=Sb_0fD$H!KbOm*@h_{b&u<DKwnI<6Cz_c-Sbuak%rAx&g4wgiP9AkE zb;TGgWU_o-k4Xh?99CW>P&K7AD#6zRH|q@sx+2xpwY8<51ZnNHt9`XLb`?#S-(h3B za$f{Dv{M@mWrKMHOKY(w0RfqVFzEW7?}_U#b2+yQxpJF`%ZoO-G{%b!wcle0c#hUv z(ZRhhul}Z<&;>Q7KLszPVHi)=c@+rCwIKR;48LR?yns$Kf-Ea<x{~X|sk3C3TH5Zr zC%-jo_515}C{PJ_80~t+Ph_s*m~>AyrtMqvh?uAiVd?=xj>@AyJFvBnUgC6C{owxn zLzvVoEit@N)lT21VKE%}E*{oC`{LIokQGl)P9mt(3JecaA@y>++%*R-zseIxWmaP~ zVYfMzgcyhz7Be2_<2NLunB*`rL^|5qIXt9StF@dX?}~Y0!fVz|yYj(OtcPIoS3|?v zklDaM#qC6dOp@@|ug-4K)nJ~5Sl0K`1wLhEXuE5oU)c=TC(5Q@+BhZ7TwCCy=bP^C zwrx0NVK(S8=`R)dkY))-2LZ=BSbY@~WP&K381~79089fXTN4Jpx;LMyQ^c{lV#a$b zEO>79XR#TtO=n3QNtwXpui9eGl<`se%Y}CoQV9Y-KLWmUzf0HD^<*{YYeG#w`ont2 z0jgElYd+aq2-mu2xfe#wj<Pyjqd~J2JxBxU$#>O-`=Z4<`XFuG5~um!;E%RM3Xm<# zLCz}7F`&qX0D?N~R`d=lIj>T&v%^ej$-#0-@wiv)Uf+hP>1KGiO6ZrZviSH@$J1{W zw?`Rfo{^cEnK4{;`+D%mh@H&sZY%oZD@G@|!Bv33CDf|R|Gf?B@-5dhkN0YqGU0m> zxhE%X%VPxxFg~)0u>;vwEOy#$<oE-ou<Ft=;<ejqw!4dyEm-jsHI0uhNfc<p7_>^U z7C{y{@f#mUHHjuU*j#?Q1Y>)>^Sf5ea_$<OZadMQX-C69%@S_j03T|9no|p`m%n>H zl_78O>TGWJs^g-)h`vqsD8T};0a3mzVtXls;WBUa^;6Hee0QyFY{CeCpf6Zjho<%_ zV}+fy;i5Pt2Jf~kJff0Sh8rc3@bhPZPRZBnCYbTK41s*opldr%oh%fWDQGgO9?oa( zW0cuIb`u>olvhEQ=yp7lUlH1~b7?)xXt!J+a5}H+2GDQJD_QOxPE+(~K4JP!!FdOS ziTU=e<V&zqc|Z-cY{zKUE1ulY^k%$k5)<9_&~32;f;~Tf#&EUbi1^|HM#P^HUm0R} z91bx!PK;F)eBWlNXWRGkGiXdU-iAfD5Ri|FW}Hk%LCsW$IWOd*d38ukIXcXdz<B2V z&fVEML}ZDVm&MyZY=0k}R|RC9kC=|9$+XSeKi|9-^-~!c3q&mqTHlh^y_~sm!ulU8 zA}E9t1}p6-qKPE0c|oBFqj~ZC`5Vn_n0T+1tw%H3wRuV>fUc_q>I8#UEg~P!qh0NV zN%_&Ag8B<bQJM_(g4m8(g?geN;33G-Oqqq~;7IUb1)-?fR@EJ>4i^={bFBxG=%gM0 z_PUpI5L;8{j8a@wqIhDeD?b2blGWHaajU<N&)%+UME{hOv~<4?7B%)6{x+~z`9d-o zeo(=O@4B?MwfvR=@sr0E1JM=C5%T>h@7!PPa=>5nZqOmLP!9>ii2fF<|GmQc|D_B6 zKL*eL_#@H(+d=O~T6Dbhyqu&n46L%>e8eJ?jJ_usr0cx(=6fZgbX9l}gA0SEsij%y zR-=e(!vNo6i%`=X1E=6aYinOxYi8y9oR0t4_sYOp$TFKGFvov^o@}H^&CB$hl}U7% zRD}QVugq}Sa7^0F@KMkSFthJu&JfrE4-R|+?*0S$<?{uLnNPrdabc|Z?KiLG1OGM; z2nAqCy>4px+T>n?9ekS*I{o2ZHYweL^73)JP49kT4-W_u1!x6k@Ir%Uz?*Dk8I%qP zFs-a|0=6w~KLLRmNfI&S<x{?20$c=m8AnG({^3VIxq{|8>wd2+dzVP;tTnZ3RYO6# zHW!?}ybKe|?x?xKcMGc(dyhkDHEjR<`2meIf1gIBv%{FLN_2$7{&8ENHc8_OAeiV> zi{*chMKaDw$8x)S{rU4JD5(XW`}eQzg5*2QoA$)_-2SZve4yl2JXB-M6!LK8Dk!fK zTf~pU)|9Eb;mpme7(*Bp_2Ppwq$EF|ncK^iC?n`l%Eo20E#404isB&=>qy|U0}%1O zdmQF}eiu`P{PhOPLWJX3@57QWL0&??-2A%S8x<3E-V?p=nwrX$YeD6*UB|e2^wVq_ z61(SDPg4cGW^>faio1gZ)FF7A!f4p!F7mnle{?cg`SIZ2_lqeV$W>t0s;yovwYfO; zgPOquW%carEP>Ch;BEbltf6dX*6tCAHwN~o_N_lam`;%hTOBSdJKpcEy+HEDqKDOh z5|cBj>h=CIx0zq=5Wq?N*Q<-cOC4f6`@*$Ke){<r`pcddMS-8g(y<5#!a1zSUp+2i zvoVb#lL&9}c|0<rY_~SF*PqrCxwW=7o~cj;z9-|!>K|qanlWr<;{{d`=eUrA2}R=C z>7t)U`cu=1YMaA6tH|vmw>r~?=CG`x7gnaS5Mg~)mRPB59~ixbimoTF?z#Q)k%$p0 zJ~xQwK2Y8qEcZTQK>uB4I(X$(ASPCT{8a(Qpy=tIx4~4sKY4n?zG>DvyCZ}}MED$b ztxvoam{X-2I^g#t^4*-wLP}LDG5%D2R=7aZw50Z5wh~3frBreTg2KYNDuw*Nqaz}Y zAl54ARm(n*%4=#|u86TKBaxA=H}7;Xe9+NJg4DWu6ciK>9#~z8AK&CbVhEpQsWZ_v z4zH&z_{mcc_6^{!`udj_ExM086Fi?k#e_;#aP?_@CHr(&*V7pma){bJI6y%q;9lQ3 z%rQ=l$e2LurPVB4-wsL=xPvw@`1;qeZ%~l-5B_O4O>#g(-hS{nFcr+0utAXj@$bE- zssrvTMy7(7eLMvz*0<<HwWPwZx5>Uc1MsIk?2*>HU!XOJ9_vN6Y;ajq$t2pl?=Em! zzlZ8IiAE{UtK*q=URqX_)9@kWu-mNvrk6_<wA<nm5FlX;h|h1~<h)ae;>GawYqzK3 zB-+)-9t=92K&2zUy06EPpCpss^A2Lt%3vS?TKoF=gxxs(`0*Og#n=1h+kep0m{ROE zCdj+N{_4^=F=5=b8a7&}m!nwH4#XmIUqYJmTbzaJuFlorh)~)q!ORW4E;icMdY|dN zJsUYSF*WUS$PzPAP}q}uZG&k_0X$Aed@j-X_t@BupkW2R6nZ}tt&qUk)I`?U1&Tzu z`Ap(IdgJN0F-Atq#(cQzPwJ!>>j+X*P-(KVRf;t0T;={=J1lStfKS*LcgoMlYsYQx zh$1iT^J3VO$h&QD1^>&?Sfj181b|;4xZ3^xc^NrfBvQ7$y<K^L$6{kz06D;aYeC9O zOFdxBsJ$>N)ort!S$hAbZWA6kV|MGa8yh75+)e+xORJRdn~yijuKba{vwHUQTGgp= zvtorrx|aKQgLsMGEDvR`Rb8Bx7=5~Na<G4i7(nUUXsuUM)h{S6#&Qk%r}#QNw7q(o zU*Mhm-NOkFcu6S+Nv>MKH|-i*h_+^Rg0=o|-bt+_XTAC|8BP$l+>g^Gqx)F8a~FDk zr6-b{vBL`>Yr_78TBS#2vm$>Xsq-7px*Jyy#C^i1pFBA$PolxVv}-kAiBmZH<)70- ziSf(XgJu1E-(hC&2QCbE$IdM)a&x_G#9bw?s+ez=w_zKI#Tr@ifEFJUrKR8_tIyTX z>8%4Txem0aT(6vmm;{8Fj|nl+39%0@rWLNv3Kpz==H*qq2e@vh|C~WwU>!C*#j)AG zasZ>FfB5y+LH0jO;M*M;f@6-r-O0<#tE%#>tE+pt?=w+#bObc`t%(}E<Bb@&KM-Wd z69|)uiHQx%#m9)u!Sov4m0fsvlIHx-TeG#>n!@ZGT4tO(+TeReDr0YNUq(=a$7;*# zJfH5_G7eX1vEk$;$OioFw{G2v<+6L_aJkMwPfkv5wbaGN!m`m<(z3~O)_8Jvd2f*c z9|wo5Hn#3<Z|MeC>g$9GhYnVvlD4gJXpzni2uYLgL4+_GA<tvi+rSQn<${LBF14~O z#VoR9X?7#M4kf@JX9d1<IYV>a-j+EcaEa%0qUR%2I=#G!<eng1%aoqI1n%|5M|7ke zbAWGS`;fcv3%avyH-u(~`$Eh&d1HE*3By6+M#RiqWH&`{tXA=E1qjoya6opBU+$2n zULt&KV>(@7WE{J*-!_+{TFP#|{RU7^XoO=*khf2yN5JD)ZPcT=a6<6yH&4yP#N-YF z<QJ!<ZVih|znC(3^5jmJ6V(d7S&&cl-L^^}FH6|?7hT0Q0}#znt1HKlxjA&nm+DWR zJ{@P<8Z8kJEr{o-93N3W0_+MREFnOg{lo5ynI(y0raz92oA*@NEoKMcH2ylTn*ZLb zE}^tRYxlJvH7holsJwd05iwzun$=p<Q+Fps{GVLm!Vy1z08=SCD#pfmy1R{vsL&TS zoQ59P^N{1Ry#Eb;>XQJHPh}SU;lRW-=#Ev1#=*ueb8Sck)#V+}<>l5@c7GJ;h{hA? z+F-(FbU8ov0*w7Uw80DQb{kV_Wl|fE=^g=eYOv|5m72PpAB&}kKT0_u8Ff4Bj{6~S zhX(&asgL<g-vUi4d1@S|4W&Y1BM3$tqg8zD>`zvBNJx_QmKYw>tBZmbsy0l&djA%e z6~O6Q(_5*-XzVrzUd1}h{AvnG>-p;LF_<A&1xWFhOZHmR3t@cKGk*<$T7-4<%ADHA z4COHC75;PsMTlCFvQB5o)Pk4zc&x;T=tQXsRvaRqu(7eN-&<^HX-V1+dPS>Pyu7U~ zkZ;x=(-7OCl)Kof?H=ZQiT~View)o~;&6R@Yh^_R5bl4`+?REBIr(O@l32$H6jJX{ zfMU=UO!i>$z4Fa!`;*nZv>r49-bOLwzH*t4@Gfiyl|x`hgLuhmGWO&FrBav!{R4CA zgM$Ou-p+UEcQo<mAB$xb@kH&NA!&i5cwu>&-TsYRLG5Ivi@|j5P3XQM-~3zF{eZhI z-SFYALbJ&`wRNNR7CvI{R{LY5cp|W_u*hjDD?hPpSU!16lO&AF%*y&0gHxmI4H=BU z|AjVxCgEq$5&wvSjg&oEdMh3k71c^(k%XM!cO3&gCGGaXno_k-?I!`Lvrjiq)l~Gb zm1+$SDkJhVIXT()S4SJVyA{VaLC{nyGXb0fPIqWR9--p$!h$<)l^LR5fhIzmTf3ul zBT_C?w+-F_GJwe(Kbvb4PjK69I_IiaB<DPPz^k_kLlDscl&{I<1YyJ3Z=L}fQ9b{O z$XJa5124VnEsH~llm$=>r4~-;+6inT@$(Dpf$-@V+|&nAR&r(&6Gp?Cy(JO`1=nO0 z3CwubjZJ!y2)OOPf4`-K$(gR7s=s_~zAXfg;{8%CkF3GluCW82O1ma=%v_e_^DL!2 zR>y(6Cjp*czZy@L&dnr=P;S)UJX2FuogI*PEhs6O&DwPvmPNkd9Jy7%W6tYC1u%=u z8DjsFDAN)FfVVH@4r8HWNy5ll#ky3F19`v2?6k`0>}Z{&KYeHjWK+knfwn6n`_f*n zzTavjXtMFZLYTerZF{P`B17$Ds^)B|qO+{D`%|ma`Pa5jpQax(s6sfUqO<t<@$?ZP ztx6^T$;)tB4cFEE(Kbwq;`f^qIZh0X_#i8kmK6!S`8IF2B1?uYxzrI+R!&<id(UfI z$R`{bcVzls9Pb;=opNbCozcu_JEI@3yTAkQ8)eb|46gYO8ed!9^%;rWuMZ7?>;utJ z63;GweylR?LIWa_kLLB%1YRf2;`cI)1VR&Dkva>zDQP{iLLSl!i?>wl-i;Q9O-+IJ zmovAtG@Po@(*B61GoIrq`W3!q-tMKtbUd$<2l}=79}Ryw()IXVMjwHYL4+Yh$*lcL zIr)=CIDp4L-?f}uqyu!gyoy3Jixs_Gr8SgaztIL3Dd*WDmU~Z5Pk~GH!*p`YXgK=? z<VzD?I$Vs|{QOD8uJSD(ct&Ko_h+81qLHg>)kX1IDOy{1rlPDp{Mr@CBBIe1%4XQf z9*d1EprRZZ@RSYR%DftrTxzo~Wv<*JNv8gxvd*Hr4>rsY1l>x2ezD#VoYHZ+zsdo8 z0nM6IB7DK$6BQC@*#;}Kx65AuL(m`fCNInT*5?u(v{{O@St?1wS*#oA%M#-(?Qg$Q zdj|jr&+pAR;J=AhHfzov2Dt&|#-U><MLblQ-E9i4zBH+rjIMk9=DrAOYg3EY@CX?G z{rj5D&4@4UEFC~2ZolnQI9B3>mizS8P?B1qu><r43p8Ka9sOzetMP$V!DP5Ua(b|u z=pD~(bB9N|6Q9jhR#bEw2m+wsU_Zr_gK-83L5P`)6=t`tI38vo$-)|5lPwrwfagg` zmk+B#P>y|qi(XA_&YDIS|GP*J@3Q#J2rP13VdT5faq%;}0ux}u)c5GlCW2o^CP<Wj z?h0;v_cJ;h$x@k1OYRB1RZx)0K>n+SJ1G7H7dIvRpYZCgN6LKTGoNl+KI~GnOAeEa z;v@l+RVx#9_Qc>|iOpKLDCMke424-dg>-zzIEoETi$)!6n6=u)14HuF9panw=;;05 zwuspe_stcQ6@Yy+yWaFbBVR)hxpkC~(;4fe8rEF0v$Ls*&NOQAEoVgc=EAd0-SU@O zMc%nF>9rT@58h{VDl?t*pbDWNcJtC*1zJu}3Z%(3eZ0Q8rkvyDHRe|I7)ONGd}(tM z#&vJ27TUvw!iT4)2~}iQl=GEZBj1s|#$|IRcfwb3u)11oi@)l+1rtOck-&DKa{k*X zpmw8|h~g<svCa85KaqN+J)6w!6m3rbBJY*1;k(btw6-^w$jDjmjH*C2(H=%k%qyp& za37oc8!ASn*xi>U9QPLr`^>F5Ea%y6=N~HSy?_5r3jO{=l_?h_)KatIJGXsWCGS66 z0749o=f|67{i$TU#H5PM7KVWbTjOciyq_<xVN69<yc>+R&=HBCmAP?I@apENj$5O< zj8F$ay&D*=px)kCRKDDfQl7D*PFj`LD$_6B0AP_WdiOi}8{S}^4ZnDg_;`9L@e)IY z&5265O+WO5{mQ&HaNE|>vOSKANW@?2!LJDz%006Rz@1&6xTVc`s5^amAxdY&`|2~U z@^^I=il<LCj32nCns#9Tl(6t^0h)mQY2d%L01-XuA|Rb$A6AIY@b8Ab(&LHnjF%iO zl!~IIy&@gGDMhrd9WD2w+#X4hph(_GVek}vXn+W)srqO(yE(`1DrPAE{>KfLiOIN` zO?td>bA!()cwhWxHaT^Fnm2zeKzWMVFqu*u`p!oB?0jq-#7I@eyUtS#%WJzm4)k3| zu17rwYm7<rch`ZJflt&jcdqFzq4{1Vy_yrCoxbDrX>6C*uNMv$ZtSu~tnv2|V;dsZ z5znI1Tzf0OOua{+C7aUM8q`o^&_SMX#F<lSH;r%$+WE3NIG@%+(gP4Zd!EDY_%1Q= zMZ=^>F0)SqD}+3|lI%T}dL81orE*`Naqm<(9htTTi-l(gM^}vb&4Z9YpGzM+HYnUS zE#8-$Pbc)MgvLK`pF~J-;ZcckuX>-tnSWdkZ4RlGH559Dh_EcBr7o><>(To*vG!z# z^9q^rI|D0qH*VfoXnd7hF`Rt@WJe^@Xy;>Tidc2vQ{Pl68gptoY<z8K5sW(c2{a@} zdwccjeY@q*H@mwjc_DJaMqylb^fo{1r+B$pzo+S=($mwgeq2|$XSkZL%R(h9&cog- zK$eSDMjSt1*4^8yed0~%pTJI~U?>)Qnx6js`%h0a0#?I;H&0&^>;H17tUyd+3lW!- zGLxl{>~+Ug!Bzd7g(Xb8?RS6LYsGhl<7~SNU0MFm(jtyFClLmS^GUl2^3BV(P%3uP z`JoN2_yBI;4ZnNxiYXCU)WR-4v?YR;Mm1T~4=q!IR3TU~|K)X#sGv_VWu{`?ig=Tg zll!NX2kc^tw`FB1dO0NgMxTFHzb;xnjyYLiGFEIjmFP!$C0aGF1tp5x$F}G#vyd_) zd&g-*Qy<Qt#W9=pLsl_Q`A2m{g-W%UdaMSrAB-1jowiH?of;-z<*-&dqo?prYxE3_ zKrt`(+E1>Je=bp(n3<IrQt?EuOK0`xXcRGN@(nW}q2;Kiv=^rMB&$<AI)xR)%ne!O zkmxlE4JUkddrHlSn<5k~6ui=PxQt^HoyM!7UWU8jBe>|7b}GYxbZ|jn(S}7bCA)jJ zkWl4h)QH2dBxIC0<ATralHbtGa635YDgJtx5~<Md0<9KjyPp1jtG2#{q`J$+G#jJj zQ(nVH^O6=sR`BNpteA_7^OQw8v@E48+wDI@RP9neDDL9Mtln&5vOdf#7iV#ldGfGy znS3KNS?ZTi^(sDwRQ&P}3?*;1AbF?6wNjI_o)}g$fV-uH^1)1b51Tf#u~yl`$&}pD zm~>)WFhKIAm>*!mJv>|d69UzZK18jo^rwNO^5$LMDtptRqIA6R=U9ha%@ShGD)qa; zZkFHT*)1$v^U-B@+2$9&4h-a)rUvxL*(jH4Ox|Cx5w++Zcbf__FQf6=P_7sYq%rU> zSsUtTv;EaU<t4SdWiW@(es8d}UblIYGySnAdELamsPPfjIl|{A5fPE)B6*!QvgfDs zzPqTXvccqa^z(Ww+{h2mB0>aiUz@sT9p=E$Dx`g~Jh>wwiLH4O7%q6(LU;z=u9V=( znzJ;F>;)#r3A|^SS`+xZ*4y(`{R8yXcht&E%_cLOKzLNlQP(W^H616npn9@W*WLQD zacB>lp1MF|J|wzAJ4{_eos_e6yJT%R;3-#b=~b-<6wk8ywm2H4`Wq)~CR3S>w#8vK z=~{L1!Npg^@M?xBSl}do9S<+CXK3Z+s;qOoguJgZ<H^Tnw<@q69)01XA`{0#Lq@K4 zUdU9H32)!Oyg(uiRc^Fx5S35#@yXKua=OcufwKU3I6Ad5A2xpPweVT|;E3fPiH+;U z2nM#M9QzcTki9a1c!yJIi2sV}R7~?ZNs+H{RLIy8j|`uYpHg7%CFy^8e;aT~Y-Urz zGlNF1vCMY0$c={;W7I8~7*1(eDm7RUvQ@UPD>@T3eI3^~G}1H$wkV|MlZ#akRHfsO zTfOvv!)&=|t`v}qHJBsk1TLA2^K(7r(i+3CcH7cYaa9!+6)|^B9swzfZm-S5<QGOm z`&C=yr5`56U6!LO*+gZB5XIWt5eW>c>}I{69lE_Vq=F;}0h_7tj*DHR<5klHel zUeEsIfY=Ylhriz!d$8<?<&#@B&B3fxDX(c_NhY^=qQWI@maoR~+RqUg3pXv;;NLIm zK{6XDSK)mS!)BzKrHFF!Q?vU0WyBXxF-9iOs&P+3TTYu(tunKS_IIduN3d64YBoLe zTe-qAMaU;2mdou`+MtKK`(U<;!2NXapRA2$^@P)n8#9f+Fdca5l~Yf_XN99Z^SR>U z6m6{B!Y3?DFH4bb!1kac<K7l^k#5_sc%HL%;>57!AQDfdTzSSQzsVYd9v^H5u406e z{>JZGlP%s0JT{XcU`$ih(nn(NJsJTi3>l9#@%6a>^-tH~NrcNmytvqZ`vKP7ZM64& z#d<CN8&%E&92qI1lf{4@lr2%9@i#Ti-Q<|)2&IbKcO<JVFOOz5p|$B6GT{`B>uVo# zoM6+L^?PVHS*YI?Y>rOVO(b*=?a_y9^^CsIjD8q0?GA4LpfVMb#n50IZJ29z1GuIL zKn#Wba2MO+T6(6nG^->ca)ER%YmkV?{(bt>7bLk@heVOonX7unYZ|`6g~B1K7&iys zsgK>Var^pBz6b&Sw86nVEee(hs`+ebRAY|7c^fp)-i`l!Tra4puCzHTc5NWHypN6b zL^(sYNnW$z!&q`btVHqqLGmI$KS?gTZb>p1!{N-qWR;F+7DHz~ZRcGpDeE!{mT^V8 zm;i+BXUDT=3)4tnc2_eMaw^SdW(SRi+O?l4t)3pNVQv-1pYsM8S-ZNr0@yYF#SWK| zk<kZy#&^nqtDNtm;ovo!;$Dp`F&ucptvdo~35vPOhR2$pii-BYw*vP}44oS5i61G2 z<xZ_O+O=j0%!iR<QX$_&@`lfl?o?GJJ3Cx#SZq!40E@IdPCO-Zb!G<rsMfOW?t=#m zYPEekNuJ66xs98jK>2E2N>rCrdS@1|Q7E`mKHMc2ThTcKx3fpU4Ax|=i-@q|R#qf3 zRcX^c%hm*=X4QZq8M~tc54}uvWb_?*VAh2oYnz!7+BGFtE9Jkve$TmmE!^B<M>J)0 zd|YiZ>t2ffWN?CjAt|@~e0$p$PXfRt%OAOUtL=!dk+T>hiFn#$)693i@-HsWla~$V zV?uGhIIrfe88B06)F`fT8Ip`*qRJpg>VrWE1b$#2y$QXrnrnXTBN^q5<yxZlrNah~ z14*>_F!qk+MSItv!Xz41H%ISe{O<-&0s#-y>2mG3A7oSYfsSB{ihkiRHq?bTa4%(h zI#(bKvjw#U?=}6tMxARzSJ&%Yq9?cutrbp7rqvNW{mhH2p0RJ5Vj5^J^lt`gb5}bv zsi~3o<6*Xul&8fp-Z|Pg8m)|zuLjQg_HN47sMS*P>S6yW;dH6ppJ)~%E|A`}bWN*E zd}mu<aKbTQwL~{kVN|9bC;D0`5lgIlb0kAzy0*q@v2*66buXai4AcUi*(~k*ACGR< z^TgfV{BY!Y$8K~L=$>(WZuJ8L^3*;+C7a*yEW0kU=mvw$*?lboc(zF^_en8x;ILaQ zt}oCifr~TQxqF)a_7u&nBWvRFw8=A^iR;&{^?Ce>mvZKKbnV);=QnQI!9PFmKD>J2 z8p%s@B>2boTK&`i{}+4M2{d`{!<$t#O*V<W@_1HmfRAbf?~{!4-+8<L^%pr}qvNFJ zB!0e_z$*#f<PW{khSvJHaz-a<?~CDQUVCZo7Ls@%^P?xJ;aqoFYeQzHcb9?qjm!&N zE43W=n#5iz_#*o{^oeQT<!|59zqerYg%Hwkb}A7r=9RP)$hp9e`|0Ex|HSMg)>zVK zZaMJ{1R)P~D-Gv<#f@v%J{~=(=SdRsJWC^TZ?Vq2cccVww_Tf<CF$YqkL-W{P_a*t ze8BMa3-WL(e}{uH8$d*s)3FW>HThu6!I!=*zPpJ-&DqJ8kw)AgkTAiK)*DrhMVZh! zpK)(9Bu%o)0a(Pb94K^P=x`zY41#0T%^No%3FbR|bF~$GGo>n_Q(k1F`|XpB*vkxs z@O8r1JfZW*y1VaP3{9E(^R>T#vxy3an3fiVY({$e?k{!c>JCZ%_&m{VObeKJ@IE?% z<~{6f$+p_2dU$*NOhv(ck}vd2#iL_6Z8)D(wzjkwob}YrcZC?h=tHJghFQP!(BZTg zNY#WcBVtLtt?wOcT)P5{q+{6^R#(Ro9r`iIyd~y}40>Fr3W^ju79rE5BOK27+=N(e zo7G`0H>dNF@y<>l5mqbaM6b$%Hw)2`JIR@o3r^94wP6LkGDNjNxII`-K>?rdoSCXo z8wM*96{A+Q->KeGE(EE-p<H4#45YhYaMkev5jriwIa_KO;$G^%cyijlN94sld|G2W zDNP|2i;RZGpqMQRqr}&*U-NAY?X`zxk&{;f$1&jCFf!W~{IDK=G13W_G$N=+Lpf?! zi9m7AUC||BG)iNIHscE&N|_2-yV^@qLqikAa6wdW99tSTdx;;8r;zJERy{F`6B28Y z3_co;Dq=S1=G|YKiJz?Eb-S$YXi1QYe!(IgKLO~=_!kcCzl0<PdQT7W>^CRew<vt` zG_sn%1?iA(!pF7L0~G_0MW4Lb1`BU`t=(4bs{|C&{>s5}3oVfLV7dxOXmMe++II_3 z-`&|?8;2+zkf!N03+3aM80ywf^(XA?HYZj_lVXIkOa@bH60|x!fD5UXc>n=0CVk~I z--42k&JU|Xk{TlOT6mn7e@K;E%;`%@=h@>i*^D7`lmvE8)@sC9Eivq`@looRobA&> zy|L1lGXIrSq#GZGFL9i9qoo^5aJ=aD#Mfw?b=M(kmEz7@Y}Pzc2_Y_Lv_R*q?viud z?az|s<=<;`GQHg3du#rDLRo&H1Y>y`JLX_tO2<M1CvDi)LdWB*2F(CMv(f5ThVx{Q zW~5QdKVF&xPFtc4$QcT?w6CkJvD+MT*_=4xL)(A?L2fWp;SSoRb7MN=+2shy9JlMa zviPv9QN)alPP6USq1Tw%<s3a>TSI|XKsY+NRBW}&xc<G_K3;=EU*aZl7PF~N4kufO zCl8-&PnOMDb80{`($V_K#@N9c#4Ko*zuy_43Q>h9Arj=L=k9{5Fh*C(QdDT4(Q+oh z46UQh|F;&<0#)(p+$!O$$z)qd8qEAs!)Nr!5_o(nB&3_}KO#*vC@jtff-Lt$wZj^W zOHiLqWYKHTllbCr<%063YSP(e2u@HDzjN_Bt1!I(AzL!-ibw){>D8lB&G%1yP-2MN z*hF9RFY=T>@qLo=zzV)tZs=Y$52v;DI7}4s7B!5xE&`D#TwD(6r4o}D>!W*2=8Nkb zG)7rX65$yeP#INQ%w2UUIH)KO;BxmHi|27FZ3#fs@^t&fu+h;mxBYCAh#(;*Iocd& zKn$eO($PsLoJuGPd#nv*kYs3>l$DgAAm6p0U%`3&m|jf7BwH@6^xQ|~ME~_-XB<QQ z#mElk;h_o~Q0QiBh6Cy3LPvaPgl!27d7&eCY=)6<ktm^f2@bA~9&?W+^~FO>ViFRT zq*%8F8&<iyyT|Is@;LebLA`cu%JSAx*|&<Y9IQz>T#2M)et?7z{IcRsO-)541PSZd zQ#SM#q}^iBsy4T^&3!Y2uq*xW`+KdQ-+@mAgD$&Msj=bQ_Kz=FZg0+J1kjL>&Ysq- zM|0{WzNod|;m2^8_@JjOb#Fl1$SAAaC^5i$_b6b6E+jujJV_WuBml>0cOZjKtrYYM zNwK%Te_jW*Y^u=aY^uh|O}WBx<`)^4>lAUs-C6&+wY9ANON3fA;FEWmxoNp)CJIMJ z-90J#;QwJ;k*M6@SzC}yP#d?Ish)v$h=P~}IU)sA3=Mb^Jv>bz-kh7mWWe+xlZaq5 z9{CQJ0s0JjgC|N`G>d)-e27$|HE-%~tO{I}WfUSU$>9sL>%@F8Qn}LWaLNH_wdJ<{ zl<D{Zmzo+?Po7%YD+1TJks1rr>Dmw)rEYD3x==R}fBcK(x!g1<gu>jHRoom!ugf#< zuQ4&>6;{~DA+4P$=Ubbbsl3jo>rvV_7l;Mi?=N7%IaY?JCDp}_8z;onBkbYnfpo@K z<EA2}O}^Ofmf=#x3XM{>#!(3J+3Cr_=D6F>?}Dbg_UDaa_v*oKookxg6VHQo?_N+d zXoK*iUmU-ONutvg%~K{;1QJE9q@fA~WWA1IjR!UReRi8%>h0S|S<);f#J3MjEHB?0 z;UQSLWS=7PJJP15V~Imr1)PwaFfl`J+}`al|8#x=Hl0W4=tK=UY9-F=8#P8pc}x%r zP-ngqoSWd9ZEKDlQ)YZ{g!X&wph&;x9`fDy6X`*4IB(mMK&jy;mZ}@?=k4q4yq1@S zMo-n&(>Ne5<__sPRST^;$4b?@Dr7e5>gtMls<rQT`YI1_UEU-~>Ep$yFsC))iSRqX zNFN@nJO-Q2Cr6{$UwpzS=~T3mdb8CF20GR(z+;;=obCc=Rf-RGri*+qlgsM-cK$Z? zprL%aJe}I1@t3+|Ns~OKx?HSQwbJ+T<`~d(0AUggr}@rJnE=2w9?M>6yf>Z6GfcM3 zXTSX&+6u6WT3A_W6x!Dxo7I^O*UCj%KJtD{wYz|g;Jdl<yLMw6on&pms2q&*(7qU? zH{OI(spQ4=Pxbfv1XoKgKh<y2OJ&48qgLN?<IA8(O4`?ClZuK|)9;XDigH+HT2d@d zZFk!Olz6ZU9p;&nFyyKoABUJy_+Na`J2+Blgkg?{3(M}h7R4a=`FMQ>L~v`LL=!{j zENRV&goGr}0q1)(tC`LAPt6B=q<PO_D6U@VOlB6(Jz98yAcHQV&UMZaBFj)PH7hJx zoDPjGdI)h}7>?DMB`kKuXjZvSPImdll;6A-$oNm;jBBd+NlA$C2sxRhKT=s(gxobX zxp!6lfs&N#9bCCJU$G7T4d*Mf*D^>`xoUMkAXo`pn;?yA7TLPQPgJ0guyb-!=Kb1^ zQzARW%UxnnS1+`7Sdw}gEVl8hxtV+h+Z-Yk#KS4k%TnI=5{q^HF#o|1Puq_{P?A#S zq=ZZ%UQwH^M1B+|SDLz^Cmw;zXSxn2cC#NsN_^M-0XDVrGdF};t)eDU#t@?1Hg2Hz z>}W0PoQ-#NBI9NK`PEy={K%3VtFcsyQtq9(l&PO;&+1pzACA;hggVO?Q$w%Miy=+_ z#l30V2WLug;zlzs4WXW}Pv})xMER{cBC^(*^f`HxAS}AKM6o-gItm%SZAw9YVj9^m zqokWv$=gC*ShVXs{8#%W5DBbakgL)tkui~Sg5RI%1t<0SR$W#mOYi$GEX)TvUMa!r zInz+TZ(lwuulqnA^<r20s+tcL_%Ew@bEPP|H#@<4T-N8mx3|lt5l@)*X%={F_ZD-Y zBA{G(h=H*yHca3b{bIV%CPvMln}8r-w(Ahwd~W9j3}IH|#UDDBv{1$Lzxu~jwX&~n z@8c9@%4h9Ne)X~t`Bt@DFzu^V`%bT#qcfW4D95EY0H5P@gp1DY3+-lB;PPFMi=iX~ zLJklJb(IUS88lmCL>+{%={1c(GoTjnufptebIwF1INeL4PoT!3=`9oR_Qs-FSz5|V zj@HbZ&bJ78XDsWScJpTzad};g=IQC?M1`6|2RK-0)h-({<kG@?OFry{&$UQXu9!nS zqeO>f-R4+ts!bMb&v0;ZG{<a!+uc>YOw-|YvoEepQZo|MLwtN%3663^KyQ+8<5Qw0 zy5NKL{;ITH#b_pzW}Up2_AH+>YEsV6+I4!{-YHfpD}21u-vy^p^EBSSUrz7Ud34Qw zYem=}KjqnL(CQj~kr<myRmNm9s8(AK`F_yy!{4)r2#}PthUZI-(~;)Ism(%0Qj0%4 zP0hwj6Aolf`ENfUkF}kyz1Vw98;TB58ZZN)rIQs!y^9<eTcFobx;|PI6&>x5%WQkr z!!<EE38@IFjm<j;d?v9V;A5Sy7wOwrSOhf_4(DD;KOoxOxOo%!Kl)wqMWz?hNNATh z4<Ej%aV()#DV(UZQF~l$co6M$v<c{T&7@xSI*Yl9iU(<k)3r0PkQ7IyT6Go7kjPwh zjA8xG=!*`9Dq1F$`R+K0%#KY{Q$@w_-B9`C>Y4<0gB}7qOx<|!J)G|KkT6O4<8NY8 zydJGEIvO+@1|!^1qC*j^AHa4(PfXn#Md2HsoEwXD<1bXZAg|GOYjkdYet!Kt4@Z2% zwku#w6D$bF1$H~LO|BOQkXRuu9mm@6T#W+*iV(N6!#Dvq0(!Ml$;Vt(U#n!AgBGAm z`m?)06CNHeYhp6;{c^4)K!>$ulFn+;?LuV&BDBWG#@c5e)2ch44Q=G-Kd+*-1>?YK z(N5{|pLzkNlNk~iLTQjQSc9`u*8mbW*GBi2Dl8Wy%LQg@W-U#hAzh_h(gP#>OkHzY zFdzgA?PiphyL*!oi3qHdQ9<PoF<h@+y`phdR>+;0PB9t{f7j$~yVZNP8%6_#?f$N# zdW!f07Fs-nhf$nTi+1>H+0ttkO1cV*2w_tOPUla9)<x|n<ny>Kg3Zi3#%z0sViK7~ zvC=vNT$1uRst&T9xtD{ZO)5N6V6UjqU9lYPvs&uLrcxgnJJs5{fN|vdxZN`Y)T1qm z*BsW%=2P4b@Rr0Ipm`Sx6=s49!J>VUw2Ef4a6Z!O%#gfJAXlS`JVp!j85=LlZP+nt z&%XgVY3xpi>T5%c3JB<I+8=#9KiMVYY!Ji?al|IAyXiKyBT-%U#n>HR9!@Nc(s%C0 zN!9mvP|X<K>Jtejt6)S;F~PCw(dwQG7huRysPT9F!2~zPV-Sy^LJ6aiBX1!3;eB-W zN_9Rz2nRla{d0GpCZ9)PWijVtqlGqA!*eY<wFKCE1R3($<A(_g)Zy!HQFT&jRgN2A ziyKan@s}OtDD>3x38&XEO=M<V-_U81rqw7_A5zSH-YP@4#pDokc5=p`b=j~>sCfI< zF@%8fi_OO6UOV=5dl?AnL5dPH?0zE_TdDUSwMWn^Sl0g%vcL-<;9-3?zf7;eiAKn) z3(Hnu%k^a&+|)X9=F)x#iy)_m8zuHTvL|mMnqAJ0q+?%{2%MFI;<hzz_QyA>$Pro* z5G5z8j>6GIakPIOh0IqX=EX2qhcbA!ix>t_udNN6MY4Y=bUuur)Xd%!Nx-5}G(H_@ z)7RI>xC=7R#=^p2uE0_z?7OjD;=z!Z)g@fga<4hZtl13@9lgT1EwNSfqTGx^bZ#(f z*aH=h@w?VE11}*dl{oJMv#Dwr(JR`xFLlO6ut<cL$2|M73QLTbbqL!(A6;SMB5Wz? z^SG-coJy|5Fl?&EvGs1@OqJV($$l$3czO`?{hKh`3TfULcLNadXTci%*D=;xy=(g` zb+g@a7?H8mqN-sv)SncXJY&5Z<8tOTqMm~z6?Vz&EFlP)t$pcY$b?V&*i=2F*^l%* z!z%nCtI4V4Rj0}DHTfaOI9NnOf1Bx<kagJPm$7l<nfWwI^O<zUu=PxgGP_Og#eBW< zfx~Gtmh_jPooKZl3IV6O>!<EG=Kdkpz5E%H5KbvsZe-oE&Uj{N!x@YPF6&id95zZy z<zFG%uO492-Me>hWjHUOsL1Nf)+C12BzCr*q{Un|?{l>##{Cw59F}9Bp0ut=D!5+C z<^zz(?(HZ_D%u>ZmT0-KWb1d~-n`>Vz68NMmr3**dRkqvyh7dFNT{dkxN}{NXI@8n zPOgZ{svYR6SJ>VL3ckcibMfp}DIDpF=E!;V<y52UV1I8fpeoxwPk)z7P|9M#SxleC zZ;9cXkC&-WwUMy@Wu^LPp;*`R-e$q++f<uBznUR^Sm)bjb~?-6TkOnKDAJFyeVU>f zzwAg}X$9*Ke5cF(;E?D};8Oc+2CJuf4QKl+diwg*TY2Ra)Z*{z2$N+NNeocsD5N_V z=Lc3A0`#aXzqLcGFt<s&AV<~muv=j4oowaO#+DY5ZcW|bwc$L8nx9isu8rTcA3UbJ zwA_Bq(H6^QHv}%W`Hg2JtyOOqJ4Yw0Y~mPQR-=jx7F>w@&d~62xpkGloF3@+MAsS} z5pV=31lz-byT)(sh9uS|;_8pX!++lr*8DvVIrbhS6S5}Dw*^;NEv!zL^+Xd6H^-Rw zCX(q02hgggziGoD^FTe>^$g1zv^^2cRsO*b<D&=I^rVRSBpxNuyet<3rC*<X*C;t{ zX$z^1U`q4-ovtlF)sLIH+RH<}EINp2=zdDJX1zJFGg2_O8;bP~7JKE&OrI(#4a0M# zJvv>5)JG$np3o*-dd+r2H49z)Aeyks^|V0O<z6a=U3{H=Z?#H4XvQ>*L@RA@ROt%M zn*M^mn1qBlWu1Bh>F|QS<R=&z#l}K9DLzTBPGbnBO2^GFE>aUEX$l4%asOKjnB<hz zlczB5&rG3Bm)cN`<Fr+-S=4eOhyI(xvRtgKNPI!ua`Ojkb6k$G(2vizb$>8@4hvIA ztdc3TNtohEG1P=CUQod@nS%zM_P298iF${7+u9103y2lN6`9loDtM+62g4y@_Jv8G z^5e;3F%p(4(jtLbUK%n4ta2Z$j%pk_AY5HKyShR+q=Gq+=T)c-U3v6Fzdjnh$|jag zm$FWp|NJpKO_Ij_91D%01S57iYrARbrYFi%TBI=iCzhq=>&I<^*b(Q86eaJ(ji-@E z@5x>>9ZifXD?5UL4=O(U`*()KCkl^GPYiA@6wf<<rk@N(*Q01%+}|9OLtTNos(lAO zQfCzbsz)8Ykd%ckHf|B|=x9*V!ZVa!qtg7x=emo>{Vr~MizZz$EMnzEmULMndAvT4 zyF-+SdU42$LceZ(mf!qo-!kuq$7aKsV?2jMD9`0^p0DmLW}PW$*R5m55wKm_W=!G- z+v2C%C$bfeSKc5$VH$>-*zLwRfnU>T!9^E0Z_Jm3V9{@t|M~uw#lgwJ!T;DWvRdKn zXv1Z7f2Cf_mEK4pP0FMp<6B8s*!gZySx&ZeGOw(^u8Qd(by!b47ef!IfKHdy9EF(k z=cQT+QxsC?F4b*OVsOWUHxHBzb9&oO!ReK2+m%;UbGWmh&DyD#yjaY|-iqtRDN4!S z$G{%2N^G{o%(o9_fgxDE(%Aj<jd#oHN1u*q!tmV>)T63TOFOST1A_Ns|9UYlJ))f7 z)I@WBw?z*^Q#GPlV=)?nxbXK49)5(*Z!~btrYqKFW-NC4^lT)>o-=5jwttMN${HiS zC(CQ0_pCHTnx~{d&u3A5{ezdh6@z*;CH6wfizjB7wddzW&~gu^D-2IgYVfX~9c<7M zB0LQAOrw~`pYZ29Pj&Fhcn-Q&@>81_`f+z*O!~oEIZYs6!Wgl|b4_jbxB+@bVk1ST zJh!7hDOb;l3M)2H84Qn}#7VKajOmiC%#lVlynM>KE>O{F$@T~@a<)DMIY1;{R{Owl zJ&q@)AGA#r%;pfdv;=me<klA<YgV@_SV8tUXWWjP(7|?nLg?u$+t0Te?d2-it0H6Y zq&DtP*VwU<0|K6BxrhOfIC@A>hS5BG{w%{iRp0Z4*_1I<18YNBMTnoDz)i5VOi4B` zlT;Tzyg%A+U^x}Gj2xmO{>$#wnC*A@swJ@*$2O+6S<qFdQaU`v{G!a4T1Wp3YX#u) zoW}h8{<7lzGi)+L@{1bxuXTj;+@t3E)CEY}7f5Ie+0vSV99&?ZU_Z-t)2j1!+Q;q2 zU~b{5rlU)-&pV%NyEGcL85$bG^=mdqc_n^r_2YT_eOWiXi-;}jYtVIdBx@=_cX}ci zDve9FC_vfYpC&y>A0z8z+rEfp=FG)aB}3wY$4Qpv5t>oVIXT8cLw4BYB;Fn(zP|Bn z!m8Y4@^UX%>qxZVO?%}k)P1E-e%F~*i(%M0h6D&`X=&LU_a;SVA?=F6HicCN`X-;b z`Pw4NPP3hzUC4t8Ci9)y6es|LmY+4rG!(&xglLc^e<ZF#Lqo$;{L9O`0e1u5AbtKK zfMMI_Lguw8tWqp!$PweMVk-D`SCy<^<@w1|47(%hf*Sjj^r%^j;LvZ|<~}3QHM&o| zURe&b5hx}E%UYY8zp37l<F*gpS@`oqAxj>Dn1e!v47%cJmMp#e!>|7AS%YNiYGOTE zN;#tXncvyRpI~4F^ElZuFy#Gc5SC2fR6$j(c=NXP!b`jhH3;)hflf<~R^2P{fmLn% zVHgO4HimrfUYLdLc{NKf&Q!GnO-2f-Gj_5GQu_k!35D5<3`sN`R${Z-YD;x8e7cOd ztG;Sp3xxgL$-2YMe#Asnh!`E^%odVEQd_Ul6Czq}^;~Ys71k@&n@_#WwnW#$AqMox zxUt;9W<=32VukDJwJXb1$k@noke1kr(gru?IJ0gRXEpSYU$vrw*A_kSHXtO!pl?2d ziarsdohvLCN5G!Jw%pp<DqVT_%}%KiRux4RBo%cQyi;`Q2y*mqs}xHnrdGn<Te0yZ zeZ~oRM-P5}5@7nXwsa&myotucty?a%r_Xm;PVZUeG=WN*DMjc?`$_Z8JZH(wT25{* z{i;F5z%z*Ws{3FiiR~cv2s|Eap=-K5q7$L{2XkXKmM-dIw;PPzC1Pg;?R5Nb3A3m3 zWxO_IiMg~~fc4pe!8vDZAf8h0Bc++h)%abv4FkLr!SkUbnn+fQ-Ab|+v7~yiB#!Z0 z&kCkD%%x5NHS*sF{a^gcwh(sYrEvmnOLA*v+p9rvo~$ap4T+-e?c%e${Jehnm1h8j zCOjQ1>G7Nw5z(lGPENxa!@tkkLhR>S2fe_lPhF6=et^dY1Mk_L<)GMxVzX(*&ns{U zGiX$XnyYvyF|%+rb`O=pU<i|3QqsOctd$k!F+fZYhCN^|yA3I8k2YGenW|?ea}-lk za%KEdiJ1y{2lHM5u}boJnsf%Jc15=+p1^V8?<gnX;3RIsReCcrC01V<TpUE)Gb<`^ zNXY)Fv%P4BRy1tnfw-ONbVj70QnAwR_74%yLzBU+?o0gf2p%f0+WzZ*Y<|pM`or#f zn|D~&z)TSM;-4Hl%%##<t7<^Ij`6r!#1EIzc;p+a30M2=HK-Q+@Pjh(KIQ$Vd*hcl zB#IafW}+XdWQ?>eEN1i@wC8(CQ3M(N`nqFzat0o{oN?<w$FQ)HgL1QGQkFewz7u6( zqp|F;v<QQM&B=jE4QPE~0Yg{iUJD`ncP+&AFMy!T3sNz9(Gk(?%u{BWA}*IIRp)%t zt^|fWmBM_3o?5k1V;{vtcu;Fr$O_r;gZBtJ$3QVq5ht<?(8wOmc9&YO$X>s^4hrP@ zNP!DfBT}lBwrf;rl)>J~(e|f#k!F_}utDZ0yJnSvZP(it5VefT82IzW&e_&j=@#iQ zV=?Z=uiI8(^7s^D4iF&X7i~l4*Tz3s+f5>jyw;l)Fknjd3$#9wr#Xs#xL-VxLqZvr zEZYdV#ez^&{^et-XZa5wi}flS0@f2DDkeB>*3VeE0H;91V>W15^fC4Aw-v<b51$;5 z{=9DJ>yu>=U}`D;XKBf9Z)igdvo2&=CD(XV>gjmd`$0wTX}$JPs9S_y8Y9J&a}jN3 zMMXa)HcNm7H$_p_0MyIfJun!)FdTUXB}d6s$uS?0P(EuaRA!n0X5wV?8U9zFK7~;$ zNUjpYEh5s5x8Pf;xN*8m5W)OOY+Cva!yHU&vOw5oF&a2_{bk>Pk8yGFTxTp4+|~N9 z8$n*wl^NCn<{9FcjO3o>UXo_Ng#3#ot@U+dzV(5fo(7R%T;^Uo&TG~5(I0=lz5O9^ zc<timmq`uT@t{9+L}UWc1hiSp!zO-|v+#IJg`b$=M3r4nQ`6w@`r((}<-6BeokynK z+;#g?=|lnu6IgVjF~(6E#>cs!YHsUMIoyM3Q*4nz$8HabZnES^x!4|E44Y^@%gnKC zRtQERZL#&b-_(F`MhCC`vP}7#S0%&0H^%KqMKT-sshxQot!Xr~)3IJXcuX01IxgQ7 zmy?|)9|4$<@2;O%dM7D6x`0ISi~jzHhh{#(LCdIK5}9F|@tQl8VQKcUjUhDBpVo%y z#rT<eqgqF!e`shfRM~Ad$5c25)tgra57dWnb0Bkbb6YNT$DO~w$EHPp;CwcDH0_Td zpK0Auq$T3m3mr4RJU<B@+mLMqjJronOpN?D6u-;M>py<{kV5P~lP>?KuhN}s?vhm{ zfN2QXAV!>ab#wC6Z7Kr3I~Ha99%d8eAA+btVymdz#I2W(kN*d2Zyiu&*X@hin4l;k zAfQsxQX(w~(jYA@(%rcT6#)T}?oztD7a<}Ni%#iYba$Vz^!xVS=ia^Vx%)fYf8JMD zJu#m-$NbgcuChOkLq@9(Gd|V?;JLMzZ4}81s{uuC!>`Psa9$|XsjH_#`VXYAMwvjZ z5SdNyXb<uPp5@Q1W%_w8hdYqNQwsi)l9EU$!;o52Dc@dHXUQSMf)q3RkIGCBzZB?- zH5^6@&VPFu7B#;&#PiA>sdC>1Ma<*WQd?VV;bunm=&aMRG||q{&LP@wQFEI{(#HY+ zOyilq5)9&6p3pcxH&=8^IY?ZmQNU;nbmgj`{AZ6muIcHasl(PayyctK)nb;HmhL3= zuHUAjRean&*0U$wq$-+$lD#9nr6R|<&TuB+?B$htLC6>Xzy<P$g<Hej067C2a^~eb z4AXYz-dW5GXWm@6yaNAuck2N_@c-=>2^#89!hj_^l$If%Q8(Vau=}}A>jr!sE7`yD zb^rT;oTLZ|3khHNb=2)eEfdH@uOjEyCZTOae|pDH5rbb}UNM&~;-%Sgw26qnew@ie z!>w{6bb-d_rM6jSah?(@=S6taD*K1S=v&0M?%-{`7I50o7V_F(s5>fF9MH~Kg_j-t zJ8w_j2oONX2k48XAD<=)Uvw1m;{7AvAOYH_XwKr4HEAtEif!TqqaztrvI%W^)frd| zn7&w4<42Wj?_WQeJvtK-q++;}v7w(P9>8|Le!Uch{g|^L%-2B#4gLMQ07dGe!U89d z_NyKqUU&@hBBHT?rt4T+*;rbNTDHKF2sPWQz9c<A91IV)i;K5=9gi3t-6Iz`@hz_Z z3u1&jJIT<>9s1br5OYdLJTYt=-UpUUHbY_`+{YfCo;0~D-)r5q8(gA~o&o1^e{TSP zVQmACHdPWPpuvuBn#;q*s+Z24J6C<5neOr9$DN%kBgp<D$4n$(JOKGRUL&t5fm1xa zMe~1>ldu@|C@Ih=1)at57gpz;=R~wsPSklmKFz-}=7&gL-#uB+<h*(B9;gb?pgN)A zjEW)Z0Y!Jqyj*DMiw)yzKt+%ONgAUgi+oaA;J0rWsVr(pNywr~(F@o$@6xd0_5x|| z_{!pJsZLV?n8ritloL#c`q~BxGZWRz94sdiD5|Sn2V!DqlyZLOzc_T*>|ERy56@1M zLn>ls4VAt?GGS22K)})(w4Ve}9iK+tV)TPhSXg9*{c#bv>8&n~FO^#Zy8}jWuR+9Y z>J1{_yVO?D*ag<d#=5ww1IU!xi-xAQZJU5joc>1c!j=Mv#pAC|#ehBYIZc<F!Mwz7 z4oqi?`cNM>cE>H#*?(dI*kUHRkU1D1!vW1!Dk{~7o`%vYglrrwu<`M_9Atr}ba}8i zKQHgq+rwMO1=jt5gl1=DCFMhb(`0@E&48d2kM-)P%k0vCO0kK|H-UXk*MZQML3o0X z?B{5LEfa!{?b5v?Jrqw=^<}!4f(1Q3UeIrPoBA_lN3T^?zctDhx-)^!C*HYB(ki<M z;p9|e*p1=J_~<mdGWB<7P!w4w_w2EuW1%KCiQQ&jHr$P8PD?;Eo<2P9Pl{kvDX>|o zyhtC#POp|W?xoHf`^>Nz6<%HCw6mwZT7B02WJRSA9F?%5!W94+jsMKI3kM~pDh<)8 zF>lJAA$5vN!#kFiV$@|3?k^=FC~F9MR4MOcg2j;b(l3z?>ytUq06yYLx>&N<#f{m+ z#ax!`Av*&=>h~<Qd8#TeVIK%caqAQju;}~WXT!iKz{uZcvf7FpbCuSE<|EDnX`(Cx zd(wRKK|n8SxE#du9xMGFUt`}U<K9223vwI%(acak9yci=-=Cu%9uMLbAeEwc^hcq_ zYOW(-(G&f=(pi;xy%co33oEj}6c0;VB6y1xTM3z86&VC#6Au#eI&XoNgaG{%y=bYW zrFBiOMMhTAs8<}HF(j(!`s(le#fcaGAYwt~@iG_KkDaw_fQP!%fR*`Gjv9yR&>sH% z<`9PM*?2Ga7aw}#_+EJVHHNbEL&>BY1U-Uy9oF8Uv&yaY+5=MUR!_E5xB1|jDtdCc z?5*p&UxLk^kY^1cZxMKhaTkf$jPfixC)4F9i_LnO^%Q|rwj6P~vMXwO0t${~-L14+ zoU!1`!&&G_pNSb67#^mJEQWb-Z}sLdi>%FtbhPT=>)%OthUKEXjTZZspGKZmN4A7C z-KI!EeUD_BP1<76Qa7z}IsEd|n83o;mW_#N1o%8KF1{rqece!gs}<P15|fdq7SH*z zckpuBMZVLk?X3=>z?X=8_3eY_L`MfSIk6z%ceIt=1_0U{v;?pxeQG+IfIZt7`9g9T zmT=hbAYBeiw8Uq!rl!-o>&5Q`&t!<I_oU0Io=_C-gYL5+zez1oZ$vg(4C;>>vk^{1 zRehKi`#+4I++`{)2u(nUX&Z*fKXK+@1A;dW`kZ|O5%Izcf+s9&3U8~A9lvR(GC<Bl zntZ-MsuXcsESK9{d)>k_*}Q(kVq-V8?WWWbF8hTy`r(rc$E~12yP2!|oz;$i;XDO; znoJ>;^h%ZUzHH|4slD~`a-pY}S7se392UNB&N3alHHXqKPA<ItEsKRfxSd95yp)ky zKV4Cfjb5Fec9<I<1znoSK!NGW2O+4&p)gY!DzWj070dimEzfz;$<IC#Xh&;Wu4~a* zVm>UQnIH@i5}Lp9{sbsg&ftjiZ@N>m!Mn9@*(z47{-Z)Gs3p=AvLY7e=GOSPjR4jr zSnqu@!}rxYdj_1uN2xj^Bf~wJ7cxNGJdMJy8LBEQECf|ea%i%aI2d<qY;5G+58;>q zH_Z5HhW@J^@lATlM@~KsRHq*iTZkLfCg(4?RG*~!;SS6FSq5@%{TE6QF_rD5QQMJ& z8{uz}pg3_!RfygJWH3~Vi%T_KH8Xh*vz85&jy>_#aS>f+UYo&>r`OEi$hRjvb&}rz zViG+*ZUMgMI}JzEQw&2T<~0a*^tE&l?yH=3OUJu*QH(wd8bsP2>%i<|rS}NO?eN$? zs(68f&r;xN666tf>$hF?V{>dS`a1rGV!m~(%+MOlMKA#*w8`Z>1<UqsXy4s4XU5qQ zCgUtwDI<f*$#mp(rl(Zh1};{=3X1nm4-HZTsUXR2YXlC`8M<+90IP^B$p#jmY#G=3 z^k~zf>XIKli>{TeEiw0=@A{b3Cy;qnI>JoMr2T6No<5q>_aF(oaYTn6N|2*;i6`?y z$R>hJe0Q_`lFRRz+v#65%dK=<<^mVO#isU+_By_P9baHG65m!&G^pN38*fYJNX2uO zE3LXJWb}Ue+|v(0;~IWEwW#??gF0`QQ4tSfw>ZDVb#jwcbF@-CoX#N`^B6n${X^UF z5B2u5WV;V(7FDOmNpYXQbRkBb>Ap3Kq?c~eL4QNVsCGut%s<F<fdUz<>~l7!tF~m@ zdg--8L;A&~rAng#h~3rbISE*CW$&|qMtHDz5rEC&q9O^sA_&9rA|b)J$@*80r@g(U zQb*5dgdU;AJJrQDKwJFzaC^8Xm;TI|SB?(*Iwd8aqo1#dVT8!dwd&{IjwjAF7Oh%< zR-vz12nPNW0jO>h{1KjADxAq1B~QFNe@a0O`fm4DEswTgYf;!h2&;GGt2%pJOo=52 zRb&biDl6Y%#&ufd8dl^h_=@j`K37+Wz82^C_eDaDMk{8taxte@g(G!Vj~P?PVZE|+ zV_{9{;~Y|>{$)w<kS!5DG#)Elf85#`VUVpB+88j`I6l|dF_*ShbDERUCz!}4CqY+4 z8RjEOi76BTq;ve&q!BgjFcu+ih@9mI5Pb_h#=lcc8;tvNX$e*u0~7tLszQsp7NOCb znd~T`8OMf$1Gm`10MrdIC-FNXmj{oH!95Y$|4n<A0XQm|E}H$=$V;Nc^jJ8@`!eCu zp+!zrjG0F&dxmu{XYlIPz5WU)l7sStPI;^+ChJpLRnqIyot6EG`DBjW2b+g>NwD61 zyu7lS5?)=+Wxt|0$_(C&l?|C$`e-*AwX}esi4=+G_1}y6L5i@MN_^?BFiJ?oo@H%g zC9yCd8C`mx&sD&&U-W}K%W#AYnNiQ)1GeDC!?%ki%j<-}W08hyq{Q^*btof2FGU*7 zK2RXG#IdP69*$0(3Am}QJIYV!heocCT|Zhvfj~4WI=bFvVJ?3PAS#@zS3w=f?~87o zlym^?h1~66;OwidW{e8;Bq2R8r(|`g)U7`k@xlGWVqbQ5N$XfI9ktx@z-Dx6suBoL z54M-Hdrub0*Jg=prki4+gm~+DH@#(f1X&{z_@lrn-g#JvMvGQ4$7yYxe_oa;c+sX} zsC2dQg|+o&{8N)CV75@<j7qu6v`uutiMzTS>Y&i%ERI`^*84cLJS0x?8S?oMsoI50 zLc-vos;p07Fr25=o#L0w^z50#=#fx=jwULUMSs^!ePmdT?<8qxd8jn``Qvr7#&O2U zoCSc2!x&F%yHVo2H87iKYiT|7!w8dhyFCwgSApU^D&#+}GxE#%Sn~Dj2zk4i;Y87? zm!iwg%C`sVv?jEAGZaDFDV093%$KF6UadA@$f7r(-^%Iy`=)X*hxM#(d)zUqozL3F zCg7H{iwnE?fZf5CChSJ}j`HMyN=sT_8n6c7Bka9GX1{#KYfD&zCT>jt+OGx#uXk`t zBQNA}a)ADSL)RCQJ0Musd9EY=X{0Hq{Ss6w1A?hyM*5VTDN9<8{E(g#0CPDIC3=R2 zkv*1gZ$i+9<7Qvg;m**&z|K-94^(7EhhK=f+y=^NLD{A0%=;K1vM#ID(JIh+Ya;E` z^?1L!#e=5gC(l!KOI*G~6Z3%cKum*w6_9kdH=RbR>DxIuIGQ=3Rvarf-UT86M6ml9 z)K-}zY}x@LICG*i7omQ~x;}?*K60IlrPIB3{J@Wh1Y%R%)}0#|xqR_yDQUC5++2NA zZ9Qvd^yRLjt#ceN#=xDx7*IJ0+6hob=mN1*k{~fJyROk!Rv6ST5;i$L{&l5Y0H(Od z0eqeKQrJK6__Dx#^EQ+w^hPjM#W}tlb<JF}SP*H3Q_D5yUAfZFuhBPPjTVhnwQHP> zzY$_@?<4%f?EpbJfg-$la}Cut0vcGQ92GLgfcrV%0?gN4ECC_p_WVe9PY)|O>+}Lx z0sH#Wo&C>$Clahb9+8KtzAIUb;dR+#v#HL+hL@l3k0guFPSkl}<l4OBQ<4;&Ytfct z&B96`nx|9UsRPM$vL*1&)v-_V0sR6%LZ#9nU2Re6ZC!0kWFf`v_6XkXmVrX%(z49~ zsM{cRhCH#sG-Nx!xVSZ*PtzNh0;IovAZG8P5SNPOUO(6-()1^0BpU{n3e?;EIj8Ah zX18iR0LFXfg%f&<I%o*WaBdnJ8dkb2mxeZ5quv-0)MhP!aYZ-7a*9giDgl>X&p0D* z{8Mc-?7EWkPrtWMTRV-$C>I;`nRMqQ-su7()6~+^aJ9NB+h@X$9v*I6ov9Gu9Lr~4 zlGI*(j3t&B9<GGMj?GleA)n>LB~6u#pIM5jl8)B^VIQao!Y_yRnDHT2j*1Lf$k!wf zPLLqp0reCs8&dsT*w5<qF=zUTV*9a^#lB-!$H`p<S|ySvbJmWEPb>cuMn2r`ijLMd zE#^GE)(QyXaaphb`VHI=N4^hnNS%rdIx9^gnQ?oZb{8I!N$j}>Erm4&Q}%!(a9m$A z?briXDzv9f!ltG6g%>K51<YL>;rE_8>&P~UR<;h?kAI(T8bc{=EwjJUxMNspv%j&- zWuG)kfQx%DvKyRK-`!mZ>1yCKR4#jChHiOkq#0G#;5pqkf^;K3+%|AzBX#5k-rw`{ z8i=ZN?i2iW8}Ar@SV!2COSL&%jPMs^HN1b)oA&+tJA&?%JB{&tkC+Q&>#wf&NsdH% zlU%nPskB^-ULSiYD9E5%@R(VaZ)NC8SH#*Isn$*_&@}`m)-WiQn8-4A>@4%4P%^N= z`77xV$KG>bG*;Un<UyRM5r@5@Ph}FVve5Lqw+#K(Tn6t5V_^}<#gcd8y#@o+Ptjmq z)#+H{*ROuq?#-wAIc}mOxe#cOLj;Q(rE}n(bdRxI(d_&F{kw;6SmPzBXy)~WVq-8D zR=Azk`sj)~J3IHFzzxA2=qEXYxPNAp?!zIMh|!x3>z27&vbRI;=@`VbfNIS~Jd`ey zODX5X<uGgC()5QRz>m+s_q0*VZ8H}x+aD4JxgehjcnUzjDLY5ZIW10&Bd$GCQ9Roo z9n7MS-DG-vu*GXRnWTlip-dZ^Ep!bnc8g~vCV7h@S&{mJ7<PcHQ#U0r{pLmxSem)j z?Ri7?a)>24h4{HN^-T2p^H`D+l9#aOsM6J&9r*ccWrst{D7ROQdNahP^y6<}e7U04 zd(Pu|-`tahx?Vso&lh5U<zOOqvjrPVdOE<<Zk`bp<d;{WrOm|QO|#qB)1vkjQw;XP zb-#*7ch5eX1R*ZA9wwj-4R#N9=C|uMBGTwPUoDi$?pWK}#xm<BEIp2V0pV<{gr=d* zq0<*0r1Jo6F6m8Hz-(t{cMaVd=%hhok3gYYt*0%*ujceTK-!<m(=-%#K~s;HvdHPF zdS5gurHQaFU0s}}HYj^aay0z~R%H3o`whHi(K`&XWdSkg%aG+w`_V~93Yl&(-17)( zJ$AF6JefMrp_1d6Ik2I$eAMQ3J=%kWnkpx|a2r~EYS{&;g=gO4Uwj~)VQ65mc@dsB z2)dy33yY+yIeL`xW~{_?5f%QnkDr0fWUNA2@2#HR)30ut)KOw_Ul1mZQelBJG(MFn zj+--84(nEx7n=rDp!C$?hrP%%`;|&uRqEBj?b`!64C=fgviY2KA8~o^O*Xv^7i!Kg z_yNF4m~C*_N36n1ohDLxE1uMU$OmX?nkt{0suV9B%r|T#*f0F%55wKnRgk3`y+##o z=6Y=Fe?iW1NGu(xHo(j*#Z3EvKt0E}ysYe=UW5fPjbhe=Xh!p#6iGt$YG)zQ`oOP8 z;WhfWGcz;PzQLu|r`1)`vApzD%o|^F!2NJ=HN(WjM0OKOEq31==2g1=kf0BJKSkwc zZmXCETD_^Rbla5<Xx{+xpDIRdIr^d49Y!=%(z)?t|DJtNJkrFJ(r#d)-;taAi@HC2 zX0l9$N8#<^M-fSJ1|Db_`Eyb4W`C<{>2$XYv7Nnr_hMq@TSPqSqHFop+@D*{WmEf& zayiPGQzBs-IG4*1yK&ARGwE?3Ovhh$;NFN~HT3D%UR@f9Nt)Y(onzPI;&#VtcSRor zM5ux%0JlF#C0LEa8nl#YoryJ9u3rt=NbQ+2?%NyRiA9o-kl-^O$6lsbsd1h+*40f< z5@a|)ak#79%_}Gh(&;Xj^K#zbNYN`rmi@eNallSltdEXqL`Y{<XkmNe)~&l}G$vbq zYaqPZ^@Mp4h`n>?&QD6NETA)>3EU0rt6vU7DqnJDD_-6Aylab3!KskI#WE2A0@zmY z7^kPF7m1ie@tPJ~CwGdu_tDD>B@a16vZP|K!{hN8)tQT){T@R7YJQhAIz#LF%yly9 zzI;&pmW&KP|9i0*?H3vtnPH~P)cJTSUPwBEzQP|j%*{@-vSVZ})SD^&dtw6E@T=Z> zY^)#n6OcPS`59k+c&eYXQY46@w|!AE<c`x!6&cqWz<xm)!H(~*9~b)K(MIK&#S*S- zlwskJR+LqUTvjA1)J3I`BR-PLwLEPMrA_4wV9TsJV30Zyd8OO3N^ss$I=!lVn%&z) z5mDU9ESEAKaP#7s&sS@Y)hQL~qKX&AJzsIfK|2|zgDpeQ$?H60rE8%s>4zK0pN4$_ ztKlQAF)b}Mi9aEe+VYOk6QHWE*e&+uw8ha6<xf#zMCqpCbOp}ykEqA#Uzg2gPP_<K zVcO5yUU$sE7Jm7XCZAwtr3zuhEEi7uO=~*?&oZ^bW_|-?`#oB2r|*RQNt&Jk0H{(d z7OE?bFIsETw^R;$=@9+oAgWUccT5sw*ZF-p9YvU+AV6xrFLKhfZL>{DHQN>wl3Z#u zAkbW8DJ++Jg<QJCc&VRh%q;jCu{fx$j<?zQvQ>klM&hpj8@pewi$depT&H5OG%OZ9 zSymson=Msp*V_Eiqv@j@MFq?4FVv9=M$m@G>P+K`<kmB$fDm&Kx5<ezsd_Izo<yVX za?S4HAD5g~YIma{P%1Zsmc`0sn(?)~Df@jQt2FL)$AjKaooGEhxl{?(pB*|Sr~!^c zSe6#q$63nJEc839WYkx1F0rlEM>-ziNo~E6(z}I2;?xq!!a`1Nv-H~%3_ejU*Y2#J zvTKW=TOxxaQ!8u9PLA7-^-WKUY3W+%xw%Qw!!1L87gAFUkO}5EQB#YSy$IsNl_%Il zTskw#0|^b`q9TMm8?@AK(_{4^LaGp>z<gZ*hOX_~QX37URk)nG_nTs6%|eREmD(XF zA%&OAx-UjFIJNmZ_>hSQOIt})^A9;ni1IUpeD$n4D^*LSF#=oWU5zZ&)SWn<noO5s zT{H+RN(zhpxCE95*`#An7D4~v%F7(jxlJghyyA|NLCj<Kh@4z7x8HyNAbRZdH|-*| z?%v7>U+7or+5>;S9qRls!7Rn9zF;a|+`ACp6vpC(R5mgF-P>CaohBTN6Gr2tA618J zz0KWI75fy(Q#chKYm~*|yeER{Th@7ALTjx@^dfAe+}i#JR|CP0zuHO~<Udpl_blz` zIB+{nPfm7KyQqpT!}g~d2xg;{AU_vEWd229tV3D6Oupa}(elj?z8Dd|g1Pe)LS}Am zr?3)JGZ72@4R63a`62~b%89>D&U@+XLGf&Lp!GJ$0S8Mo3<@ZExrz{pM=U+_lc!$> zD{K*qiu5Uxkwr!`8$Nh6kJIx`Qg1*}=iK?j(f4kPbz2-ydM7L*vf%f}vaU>|$k~`_ z#uz-M#G!v5SPNrYu918BO{;K>&s=@c`+GHrP@~TQ)&z@#To$n<g3kR5Jn7eUlyevu ztZp{{Ga{q1`Bs9M5%KkZ3;?tO#b(CY@2Ves4!Lra3n^hAD(eLSg}iUZXCa!m!_XF7 zt=>v9ilH>h1-gqnFiC=s7K-k`u>UMAA#5#C*#928>yMpyw?JI9S1jj=<DSTHWaBhO zkonXUy+xi89ppp4Q~W1tKoa75(QT0g<`=G1`{K8T2c?E&0tLcH^z1or<%}kjMT_hv zgv59XDH70f-bth+xU>2`w}jDmj^PpBqrC3)?o<q09X|(9MIZ;(#Y>7A@-p;Oy%{pv zYXMrcO4-WgZ__6>DnfiHF85`qkF}0SPBtd3QZ+WSn-1>%L%r}J`LB8*jjaDKJC6Ij zCjN=*ZX6GzM&(jRwfb;xSir+YI>hURL|Ju>C+1R6zc2%!I+U(`2+V+(f^12JuJ7Hm zXU|egDU{15Q_H0S&M&kO2pvO?mo{qwMuA$y@~@O4aE{!2rA4qIMDEi+(i_;>m9k$V zEo#*$yr;->%zu3`9IWguF&#>t=5|}jatJkX#|S}x7(wrAQ&Uqw(<7+tN%-7O-Aq+x z#C-2Ea)5qCD)Yv*YnjT0FMW_jD!myXM%Ad&%dY$?8@U2v;)BpW2N*~pA>_7C8hBK2 zV_&sVIPDUHDAhel<3ahWSLH@G9M%8ID_X+&r>e7bwGnBVPCIjbg-Y>YFC5S*F&s|g zm(8Rp48qUUJmrUaF|a#GF<T{VIh|WT-m?E;=Pg-o+>p-)Ji(W!tBuaA=^36o=Z=@; z-Q)5{A)t{xTSr8tYXS-ZBYzJEberk}ylVdQhhw0~(>!sultXo=wv%uD9vW&O*1Y;1 zDl3J<i6s6vZ@zxq(4qM%8xSl6C@JI0Bb{Ti?Lg2gu@;F$c0iULEWehip;7CgyQF8< zl|}x@?8#kdR_3p~xc~3m`Ras+r-vf~(V!lHtD0(KZ5tX@6ynz&%XO+X`{hc%vOrCE z{}gV$ujs_n6(g$RA-TFSz6Y$VJ@X1HYz&C!kE|vHF7{TzvW$tGNUE?WB8TUHW^s0Q zW*#q>$R?q|`@P8ronhFSi)|?dQ6N#Zoe#Clu>UQNVw&RB+c9_O<P*?^s0^ph2~L%g zjN�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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/home-setup-only.png b/docs/img/ux13/home-setup-only.png new file mode 100644 index 0000000000000000000000000000000000000000..be38b56f2f4f30b614973f8370ffc5cc6ea7a66c GIT binary patch literal 34120 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 Z)r6X{$Z1F}eGA}_<~^OeC3hZ&{Wr0E0m1+P literal 0 HcmV?d00001 diff --git a/docs/img/ux13/home-shadow.png b/docs/img/ux13/home-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..a16bfa7baeaf40339527c24d526900089cf2bdf2 GIT binary patch literal 194670 zcmce-bx>SE_bp0<5J3`L0wlN-Ja`f;*Z?y~aCdhYEJ1?@*TG?6u;32C-5myZcO3@a z@O|~WRqu~ib#K+JM^SZ7b@l1#vwQdIwb$M!SP>wF^_uiG8X6jw^mlO}8rrjMG&GEY zmrqeGry<SeXlQTIq{Y7~yQS_gpnKxEl3^SdHZ(N6Az<iSSXi*0(fb#ONzAKPi{t9* z3Pqoz3aC~@-MOcq|5#)pka?s1tmWu*hb^H(E294>4Y4G_%`BMk1T{9=&p`Ru|K7a7 zX(fMb`GWSL_SxgjOSI>%k5{xOKbNr|uOHCf!vE9vIhwEFW5Z9hFLoG@H*e8i9zI^t zo}&Hl4AN4*3S7aJ%!$2^f0e+YEBTud?;R5!Asd0djCg=7$>TsjeLmFs@Z=hQbEh@P zHKvlYj^p^&Y5Ywt_>&h~TP`h-N}}zXF6n)e7XnAf=ic{#5Eqw|m(yw=UTX-&&dTyd zs<Z1hkIl_ljAZ;G&=v5ywX(AtS?z4$dK`R-UH?UMU=}b6ZqQqw<08V%n5?J2L!|IY zNQjDoAz#|i6wK}7(#OuA)#$XdN-Jy0c^DX;63>G4L!1vm8oUr#dZdAo_mtU&225Uz zOai-xU(g;+cC0PdiDYJAA{b<UXV}ckR8187`wfSLL0hLTcUF1yX{9-+PGP><T-b1P zm|6<6rmCvgyJKeNhf>soEiNM?<BqvG=HvXhQRZ}3(V&afJ;hR^me&%`&mpunsXae; z-m(4m4L4;T4-XHAQsj1YNmolwPFAYWtHGsMv+6Y#mS)}V@bdD9j~_Gb*XXNlmkw{v zwxXhx%y-Psm8GOiC;K+IZPe9g144<KgmjgpV(7v>&bQfES>=(kGBR|4<kKw}!O_x< zR*QT4%nSoF7a~$L-Y!A^VwZ<pz{PBLwXMb~jtvt51OSH047(Q*x3B^jHkm-ID~k&U z91id7>=1N4R6b}hy}P@!S!l*1CA2U$pRAHK<>KP1ekfa`=j7tls4@4t9(k9X5Rls$ z+Z!`e^Juyew9EoINNgO3d#Xmm+cPZt<e`K~-WpS5WAYiF@9OHEy}iE}6=vF{!aT2! z^+5?;YhB?SyqsyA#=8(f*U8CA?_2Zo0>(}au3fXq@=pJgwe8Zdu=m2`Lf4@F(;Y5T z3So!FVA-|J!4&OguydaRh>NQt@stL++8Js(3@2pKVxVR<)Hm_oJ>R*$c5^A3h>fi< z9iE+=IcC*Vc_YS7KtK>qDty^BI8Q!TgZk6G*h;RQ`F!}hP_=lm);=^Y*SI@^yhN+% zcKc)vws^nR9f^VYJ~cjmvBg$Y`c?2dYN;mAn`o4~aGoA$9-+S>Bq1inB;nk?*yF1( zLAL#8-Ieoer==OG?+E6r)c6xP-z7)A1dSsGIy$-(lTrm79LtxQu0}^k7poi_qN8y^ zIxBha@6HBD0s{ljCr~!%@828EmeQ_w%5%6*;xd(x5TC98jP;h7n1+q6k2OZO(XDqa zcdJRTCRRmx+Z+lY_c-78y6$<GOe*;A1do0=P0-rL1i<gTaEmovvXsbe|Ma58X~P2b zUdBd7*YOp}0sO9qo@Qp-am)#r=NCJ)^ioip1&_am=+9rIes*_QsIO}BxX6N9&sFY> zLv3^SGAk>cX3Ghz=PNToPpr~Y;qbb%O;Jxfg>T<d)9ULQY-cMAENj>%iZe4ueg0)! z`#+b*!g_%+MaIh4&L)6N->x~j_h?v7PR>jyNVC#vHcR3xc0Cq}fgKx1bWl}U$!iV& z@-+#zFgnUns@oJF9V-I>6!aRU*VQEvlVJq-ySahK+NXzy;R9g;wa?D?M<GB#kT+k- z;X=bwt$oaa&%th$%|g9OsvggqwVjR0dS_<dDm-dxF=1it>iPb?s_1BkVTyDIAqhJv z`feGb&zzjmzSn<O9&Am<OSBteV~tAHboN2XA}Mnu06R6)zDQbP)bxM8ctvm}z{pr! zx(wigofKWO0kCjzj^=Iup>`ey_A;Dm^ER9;2#50KdQ?|ky|<%-o0nHo7F0+V6aM?R zoV@gGlLx!40xOohP0g=gPih)0Yf6H!DKD?CpyjRxK!?34R%VEa${Rd9azn$b(mWof z4P$Rya`NJ=EEbl#hsn&MqW2^O8wbe4=_PMN!~lc~YB|lu!BHmX&WL=F%`cVmSz8mS zsvjMj+H9s_=}6Mk(V_UyHvI4r<$>m2kn;Tgu>72Z<>lk`UeN19+r>r*-%-tycS?<6 zw@bBr&s>#{l1)jkQ%7fKk#(`_!Hm)*nt{PXOBI0HL(mX!Ev3eWh=9=fU@Ym1w#0%k z5I{;pLvxIsny&lLWklBA-oBBYfY45-{O_lws<ZL(f<nhUI%?*AyND+StgI{|Sn5B% z`xNL6i{x@WdxXTFKfi#I1Q=Nhq3dc1BpX{>Qc_Zk3=F`l{seXvW##TjvTo~M`JE)e zoZ4D98=b?4beZ2<1o*K?NBttPY)Nks??#>-3>=CkuRZNaPY;(PZ^Y$63ZL!e_Gr`C z6PS9UBz8Czbylqy9Ua{Z3=AI)%pggAe*Tk(4lr!n!@bF%?^)BVC_esrL1b<&x^v^j z{R5fj=BA|2;NakY&a1C}%lG7c>^+7lnJwqXwVoThzUZL_1_mCN%axpbyqo|9g*TY5 zje_8n?y@d60P|UBzmBuB6AClisi|rexW>k9;dc|tUZ*+1At5p?14(<7Z~w%_IbZJA z?Qogo<f*!6Ur`8qh)YT;-MYHCz?^<s5SncN`Pj?Ih`6N8(4u&cFJyXHTKQ>Tk2RUk z)y$~HW&s>>RKUnss8-s`&XVtR8;y(Wq-?kR?`z*)XJ;ojggPh^i$dtnycPw@z+Zl% z&f6dcwn!4L2nxgQ2;B-3EOfXZ#${c7{g~{*T+QBMvF6bta(lGO1BYLIR*72DuHCi8 z8;QTZAr<j{p$ue7+K(Ex${f^(L}Flq@79CML;6OugW}@ig0M-ZIyx@~W-ByntPV#q zwN*m(GfHi(trt)b3wx1oqVMEXIbEXTygl;HlB_|WTJrL6a(r<yja*h)*{MAc>+9Fn zp>S=D8f#rGppeUXBFu!txNm)>J#aAfq@q|mJFN-vWBvzH!1g~*{Nbm6dATD=esK|1 zfrU=f9;E6)N5;)SpQpV?_LZv{4IebJ-hbPaw7n<Tt7?xfCMITWZLPSdNL>8-$XH!b z@jI;@tGv95ib~$yi-RXmo^W!O*VhZc30IPm)JaH4(u*|{Vq+`KCO6m1vb*TIsx*n2 zYR2L6^772qRFt^yvr01A=;^yX0p4G~>gi?tYJM{B|A=W{-ahUvo>pPD;@YERMf-Oj zErok6N`8e&v&wvDPg{_+cC)0-)6nIp^|1^N4vvlndR!i2VZMad*y8+$kU0l7^m#Jh zbKDpk50oN#z<g2c44YajjEt(%-or!8)-BvKq5|nR5hy6O7*1;nlnnH6c^E|fGTOiC zpS*`lGWHx>CM;vCseirCm3H%4-v#e<5@5u{t$IF}pfw(FT~C;;xD&lyXm<BQypef) zPEqRR;gXh{!O98-W9$-vu>_2ij<sPO+LFEKzdG&n*d@ckjOlC;>CTp!?~k{n$%dH) zrJiR%!a?Exp^DeIs1a0u7-atbv}VK-m#Fj}0?a9;<E;y|=xmKOl9&n`GkF{a4fb>S zzW8_i(xQ@>lGT;6@Gfz4@L8c`e~|f!c2+W^`=;rm(hB$%UG=f^TSe5UA$8Tyk=i~S zD}ic(f8J8l^=-p`TeqZj@cnSIc!%T}kJfwaiUtcr4ZO_|D!-HEuw^|p|Mx-HffNGl z;7e?bwG-5wU6dzyglx2*uoaBN-JDxp0J6UM7UxrECw(fv4-Xe}VNsFXR~_$xo>rNV z*C_HNt5!1KXoG$hK*)x4oI3AKCVkj&uEB^*<>cVC8i&mig{vt3aJ$(pb`|lyK}WBi zibo>O74O<8e_SA!ON(<0igJF${IXs0N{o-<uu>G=l=U2CF)&y=ee+sA3^N~bdNE(X zXuj5sX^5KDmwziRf0k16Yxr!7ckRG1Ug3PdG*zDUs5R3{?#Tp}>y1bW#}ppt#oCJ_ zl*ep#JFZTkw?y8z2c17S&VC~x*x=c#F)=dn9>r(VZGa>v4|&S!a=)qBO1ppZ)ynnF zG@Z6!O=0hkkNWSXZ5EADznGEv4U}{wGqGnGS&g+KBL5nEV%Go9MKpcX@ld7rABTOc zYJmUe=}unj)!1}3MXl2v`mAs5)RaPC4Ipr=KuojRE(HQvyB}lzOe3cu1C!s|><UcP zRh5we)Lk7*gTa!8geCCa&5eyEpF0*7mT&SZxu!J{4h{~k6hbzmm1RXmR+5rk7!MgH z@?_(B_rF@l#(=k|{r7GOj9_Bu5e2WtC!{as8fx<JOr8;y5)cx&9Ke4;$RQ+dn};ii zmFygU8rEkGdfdmzAcc17ES3TJx|l3lpWXYhBe9>cIYue*gL3lWiA*#!bRNy#f<A|G z)X#=^I+_|>FE7q;UWMB^{4KneG}Eye7REe3w^^)XXJ?<T(4=?fnUtTuqM@Zt7jW(E z>dW#;Ka5PP7o3@2th?&z==d8P(~j}*kBD7&gJ@k)kk`T4eiOojegYlVt+v|Cf@KZN zi;A`^cO4)`Im#?7m>`0cxoS5iN?Ka`7jr3#+WPiNhTW2E;pFBlhn_J&V3y&kxVZn0 z_MMRRH%YLGjW>nLUegkyx3{+$d?0VCv2Rr@P-)#+GN$QDG14v1%)~?8lw0`b5h}0< zm=2wRwpYFdD`B3tRz>;>1{PN5SIyMyLORB#rsLzh#VOLiLqSsdN~77`HqQ_j<rQUf zuE#&r>n=21`uh6h-V6HT9t;U%I662mirCDQhthF^ua|%RTOKH~aw(s8IbiM?rsT8u zo#lHMXx(5A@9EjDIr7}etvNytY1INX`U>`znh}b?Ro#U3=CcbypBsxpLV3pJLlL+A z(<)7fKqbXU&Gb-H5QEq_T0+Spcn#@&{8OYv9^$eu@;3d?cj3s?&$4g0yw5+Oqx0KR z>bd|?cDz64&>Q&O8oqCRNiLF>tZG~=ARrL$z@IY5zo-6v`)bK#)T8J;93LNlu@U)i zZ89ZzO>%Bt!}bAzhBehBi;?W?I8BGL@HQj4Mrw<bytMS_%*ekZ!+$5^Tk}=s(nr1_ zvlKeEZl?0G63m$f<X*$SvdbMfW9Y-OE*_@yAm{-Bo)w?nFM(!m9V1`8ZZCFSF1pB< zaPAw=tmk0?QJKvFN#@gl)NdYkX2cSnyKYB_mE*GU^C`0x-4?H_wlkiKM#OTjrEPkq z-)*(oVRUk|q@&S)H=SK6-n&e&g(k3_#JB@};xB!sgVk1qHKmYCN{w0PSe%c0(}{`O zls?1%XaNXN9r#O28VZz3*upEyE4V7k8HNB5?&<(byjQR6L)rv1H1OXqAw2&iBtRY5 z(Qmz*JpRTZaPFVf-Js*&7Kkhq%LcXietTVd=`tnaO}V4OWRgNm0xTBhV`pcjj_I59 z3^g(^GO{rln<<Ej$jd8<sQ%TQ7FZ91l>?QXtn~Fq{kn&{!YO13%q(T!XfpS2u{UiC z{fs>7)>#nj@A=MWy>FC1%s2pwaP?W?aamVn`ZS*No^*Ds^%W@Kd;pV?u{Q+C>_t5x z+LEF7C7q(2bBx;<OoW2i_|3f4RooZg`pSR%wOx{dPF-Il)OWfLJdj{lKHjnE3B_z; z<aL4I5sREWrmL-{sg211-`>pibA5e%reB~iorf)4f#lT`iS#t>7w0?Drk^Ugd6Mft zV>}N$9-1EN0!n}VH3jTs1hp;>Oe7L6_GT)5HzPLHDLZj`>i;57-7LQ_NJ5+wwJ;-! zk8$ZsP#Rldq#xyqt)2e|Dyp#(=Qm(QG-r=P_v;xF9s+`pl-Qx!LM{n$1`(MAd`A=c z9lNDWJa>2ZkdV_?!M(A%plDDP56^v4?BCQP%=S7K&a|srWoMqMjvOOcM!Jw=6jL{f zTtEb?ysj1_PfG|C`U%;LHx!6;Wn`rP;?b<GuHK;EoIH{O+}Ee+Y-G80;+<WzbWlac zWT4=DjP`!5zqmliOx4jR*Yc@&2bJRIB<4FsK0^e@u=8+5n>-;_R^(2Ik<z<&8aPgF z|M*INEkZ9vPfnyYNO!IH0`@y%mGfS7g%LZg4f!E((nj`+idj(L(#!Y7L1r#Mc6yA9 zlVE)V#j03X<!&}LQNb{6wV0f8<=>x<e$)bPZmXBk5pOv;Iq_m*wppJ17lM2}ATQq} za9#i%w+8ZG;8(Ile-mQ9Ec$HZ`3?BP?fE=h3w1g;2Js#tMg08(Kz2lgtD^YQ((;1N zhhx7#BF){Dltxi#q@=)MUsidJd5AiZY0uTP<b;^HLZPNnzNtd;=@wgRB@4V9yp<Kz z0<I^d1gDz359ON^+#7JXkO0}2ZnE>rzqLPf0IFJY+`_^YMMYu7R~6RhxiqxfJMeU$ ztojR6dP{v9nIkGXwg>?AU$5!|fsq2SJ(;DK&MzmIq2>Pl34eZ%t{NMa8=tmiQMs$D z=e^kWd@8&R@y2{9;INun9sh!$&mH5l(|K%N-A-5mo>`|(vv-R1PKV$U?4`=J(N3zg zq{-B1%wss-9YNeC{2V3f{e1CK-gs9$mhs*FWiQ0!D;KQyPqpyo)L&>|{Vvy40_t2L zBCuyFwLf`PR(A3N42}cv($cB`03|AK)MO4~?NQQG0W>^U!p!Y?c#j?FkCuVqEp9RB zoVAvxfsqrY;Glm8{u@VtU$~^plma|WQ!@#~ud6N3^MRqGZ6NjrSNTCz4di|a_hYmj zSlhYi>TLx`X@<gvhT;6e*;$59eZ>m=z%T~pa;!d-GE}oagP2MgzZCw&aNZX#=ozB| zR5n{2*chlQ?CeY(d1zZx(eiApE09*P%>g=P{bZUVK+Ml-j6dJ0^{r2DId)*N6&Q|7 zP6m_--Yglr$*jCdxR>t6b@DW@v@XcYqM@Ve6MU0QN-pJWvlIyQ(DA<aNXLm|i3|Z^ z*@m69ovDm>VXsMIA&obU9J%lw$u#LFW%!=|Zew&-KwT&9(y72CXL5kzAYJJeyl`Rv zteKD3q{D75mU;V!lEt*+zK;EOm~<ow|M|d8|FrD_it@Aeuy4;-q!a|}=N?GP$%koh zTb^#!7vn~+b_Ko|iU@abJmuz@#JD<YvYz%vv3^-cJYj8scGBs__KM%bqDSIsWlqk- z@OW2$d_ofB{XV-+ow@p=P~d5PY-~=?R$n`Te2S3wR+=9><7=*gpWec(gZ$3hjChhq z{C4LzvI_REUJ=n_xb!4}=nqAm;0FPwU~pgs2o*hB?vmi+g0~j4MTF~*<y|_Ky&JA5 zlUj@j$d&V%3gt*eWyHm6$M~Ytl-x<HE2@RSyZh}>8&QRno_Qa|2OSTb_nKv3yvh56 zgJKWoy$%GEhdrz+fd5F_*o^I9u2QScBqlyy(%bu2T>*!O?E6J^x%XVF%cC)<XcgAi zSFBn80wd^zH8QSl=Yq^NJImn3`9ZI8s7O=;4h0GnN0a<lvkY#{!1o>>Q4Bw0<sZ%` zFZ6)iEOc6fftrsWfi!Gd1D;&URk^+bS8aV3>zkV>hIWGd{4N}TREdpq^8i8w8Tr-E z(l-}$)vUA{<MRUF4rj`lo11?#h@KL~I;>m8!!>VZSf0{@$+-Y*001_~@8tvaGrl&$ zp&Oh19xrKtYJ9}&MAGakQan6%wvSyN4RVX>o-VCsucdn#!2)yNR4C6zd*gL|bj!du zR7{Ip8-@10AuZl%yur4#DCha|?AP+WGk%=u73Zd9RtN1zEe1NRY)MYEs=wd`RTS%R z<XS^%Rewh8n8qG%`_GfL$WTwAUEs7L3mIAQ`q<wwGa^<AKg8j_V~WCO#4o8K>ukpf zhV5srL}lu~%gUlsUO>hCUo24KxY^&g@D|RHBU<A&{G}asXP?p9Ho2tVc8n4(`X6r* z&iz-9Lw}gDv)@&tV^K!^Q*~u{y?Jc(l>a|c)&H+Z^Z!={$t)SmMrJK7$zxy0U|$Z% zhsLRnsq#20ak-3^9p&U(wxfNidg}LW-N?AAk{cC#{j_*xY`n#JOj&o!B=uV#%oDHw z93-vZe6=Ae3ZDb2Y5-4EPytHHq2v2oRzgAo!(~CBs_N$26~{-$*{(4yP1%@V0&aKv zH#?3ARovWxScjH2CXb4$G8VzrgQWedv#rjF@k9OzByW+Ok`JxYJITK}lFdH#mQE&G zdMeKpldqbZMW(iN&R#XdV!bE6*4gKG8$dwVowf85Q52Hf#j4|rwUQmQ1+{CRv}Qgo zi=wbH{Nb5&5-k@FUCSGGC(ihcRa*2b$-ve5?m}4aG(#gooRI1Jo4vyOhm1W#xy+oz zzfoW$c_6{YmX_`qH#0{i-Lw7zvMcp7$sfw8@1C!`Q*yt#v8q9doq@@)%1ZpRZ~`JC zl!i&NyC*Fz&56}@p?USx_uDl%9-k;EP>PgvyUKEWbvxJ*#SX~ls`qD$$4#N}snIgd zU=k8@GTAq`{S#k3Jq?uXqtZ&SsjtmEG#l(2>I!<d-}x!4#1>LsGna^=$fP(*bgtpk z58%3_hi=5mnXzBVDoE^B+<<R?1*v=8%gk^nP4;e|?YL~*R1(HVSJX4xA*^bX^>gUz z-7;`Nx{d5Ch58os-0Sn9%n*!Hqvj+v+ePgbugFs^o_5817ne#(p^V5xGv^d!fnx$E zS4C_bKQk9QyC^SPv($7%Q@v}6N$l^Q{Dd^yK+Jv6&UkXqQ13#$<C3kT2{G9&*VD|R zu$F9#+}zws)g?E?=b3pze0)@Bo@)tpfy~tuco#8GAI<zoPDv(Ja<$P}EZ|BA#5rK6 z?dAVlhj<J)H;2dRK0Rforfy%0bKSzW-hOL#RqdQk-b}dn$2Ru~+CNvc)+U_;pFeds z;K110k+fb|ak1#6{nmx56GvR4BaQJywZATy5n#pM&21I@m0ffZkx~jxjBV7eA*pvc z;9B)<Dz)kPjkD=Bd9-Pw9dt;#IhbhsftKgsUsOyM6&3!eKXE1#hOD&L=3!=L$zqvy z;V%8mL}#7taEVpTykq1Vl%3mht~S}iOioM4);RgdT%LicXPTyIk_(otrXizSp|9y? zbe@?FEohKBI!xD2FI{Z*xVmpImpEHrH`*~*b{d!q7j&wuDq<ZhB<bI~&=e+Ttriq5 z{kIo>g^E;Wq1iz=2F=e^3T&4=xWU(YSk5YW`k&noPaCehoot{Ak!(C9|1W!_trNx$ z3dY~{@GWV{hB57dnI1IG@K@Q9dD3y$;cDYc{+qVMxlF7dl^aOn;yL(qwuF#>*l9Y> z?c#0DhF4mL=1CUb=hiF?^z^asZ8GqTs9a`A4H1;Sx27HKg{;>NTKTSqMhFke3^AD7 zd~NUf9->xGeDCVYVVvtJ+`wLod$lqP3HK|W3*W2hJLoZ5C?8vWXwgz7y;~pQdwr;+ z#9?e~EQWFAXz$W9%)aa;4FrCZ+aJ#@Qx<tJz8~w!H`|m&xr(Blf<k}BGQjcV7>v>+ z3d0ydAk{oi1p*WWDQP)F{z;1}^X@On3x`BUN4uw2+w92Top>Kz?N-(N`ST~+4-(@? zF1Ue;uq!QQ_itp`nRX*ddAH|^8_4IYqvJNT3gpnQ1zjn-y6A~XcWdmdvx;(hB32Qt zOM7vyk|wCLO(Owt5Q|Tc2yS)d*-cFny}@`vPe-3ZOiD_!>*aEOe9XY(Ou%c8E36Ia zU6WGEP4dz>8SLt$x0`a8+>A?cr4+KaoNU}#gC26PqvCOAr%Fjok}rE7TQV}r46{+Z zSfP{;6~C$3z!_N>Dl0!_lky7A!r_gk>_Wc2-!_bl&3xra1$+A)371<mf*SKZ+34DC zh@|F!7KJ$lRTqm0_9c{vMXK3S2)h`%sm{F_o@SDf*)-|eXQ(+6adN0sQv-zuhrfyZ z4OCKU_ITj1_O7fRlnY0R-e!ONNv<!mKp}|INa%#f-=zK7I#SO9h=lM??vs*oZepzW zF&b?Xed$DFQ#wO`M+j_9KGtmlZv!n!tR9-KD()K-Z3@{Jp~2kFC^+$+Wi~ZpuDi=B z&rHEPeZ!AMp%a9UxfDG!s{@{WyD?L_svZQAkzr1fkTfRBsV7g}a5pjk>H@o}3dbMM zCE#HSBlzb@*12(28HJya@g2E$#Oy{n5hO@F@7Y*;{YKRa6-_`qA_?%<FU~&?7BE)n zHoI7&=u(SZx`DNI+19_&o^9d;x(NKkjg9sE&+@HNM~valTdixdYPL>CbD5e6mnc2R zcERf(;O>6S6u%k>1f}p<15s}GHDr|tMA4>NI#0z+FNjhsWb`y$4+ndeJ%1m0iM|&C z%gD>;iZ#T?=1g19ML{5g6QRNwkq2`giP%c2MYH0$y02cHpm;iDu8Nm;44NG^9ART% zL`+ENzIN#);9`In*&YL?iuK7X6=nH8EfyxtD9aXhPUNR}e*QmNKr(R^JNvHd;Y^7{ zMc%{;<=gdx!8(C>U&KO?0>g%;W@1DA=OvHhb(FR^kv_FGrH$Ym<LVA4wJ<e|OHBPn z84{bb?o*3h$51ui`&uJ>Lf$em0%^fHh4KxM;eDKB5cAiM54MXg4^f&1Ku%{xcnf0r zq?4J?41L$kd<+B0@!|KA|7N{zmx)yHqqOccDLd^CV3seaKQdKX<l_>wFsdLV33nOP z+~wB~8<NhK4-9j<7&}MbwMp0P4;m`h3plW8aZTcrH8N(}8k&Px0h4vPxik%EI;{a) zI_pB31*~jL>lSP)<)1di<f3AtuA?i=MV;fJt!Bg;bN73AHqE^SZZ&<WvA;t?V{uP( zq`PI5x`9h&mcZ?l)CuC|C$PE)Ij_EfKCNc(TE@L_F)J&Kw5$EhS<%i+-P~MUIn2NI zIyD`tsGNImVF5Fg!kT1np(_uL@eA5YiKKj1U_nNJ$IQlNqe3zM>S%mo;=FMB=<c@P z>9RUFrYka$>mf2vK6RD~>|_Nm+KI`}{`>d0psN6H#;*n^E7=8Q;qdVA28XpnRQQnZ zCRbrHU!q8ytI-@bP}3B};9<|SG?`Bi(DgjsM?cadG@+Z+P2Jr$N>504y<AmE&d3X_ zPm8Fw1kt-7)h<lT4}wEOl_HGPvj4t?cIcTHD4&E3q^4?V5I8ybt$5bXE*|m!68ZF* z`y+>WD?BMSte`}0<v!a-uYXg1&xiapbHaPMr+3<RNsxbLod3PdfGL|6gu_^<X?9nt zs8hfwC0wO`?0V#6m@;&;AXax;Nek$3c{eHQo!*aP&+UH8I+QZ~?91c8qEUIn%DB&d zaVj2zl%1A~p&<G@NQcYw4npbRH)REonVrz_)}OXcAIabc7oyrX7Wr%zS&T9Tkot`r z|H<`$ic=X*2ibPqkZ-G@)r)t^IqVE<XP9h7#P9$K##vKkEhc_vv1d>lnffV-x}>(O z)!fbif-YQ4IPW1!L`A8YM>Ae_y}tah-g04>Sy_e@LN2o3<>bD9&jaS7u=gV7b>#1y zB1!XTtXOe5x!8!;$-FDi<r7X@JioP5ndw+<BzAPt(?ac-vIz<EaMJ6GwJOx5G(l== z4Z#&+@~{Qn!33>vjduYiu(t^BmoFp3z<URKH@64pjB5-6sD)_xosEP}NsWy~TWK=V zN(7)F7naxG+q<#3f#NH&-(@~MTnMb^xkzEm2O9=ekV)z(zJ$c=sQAsFdNw%c=YJT^ za|s-ODTSCDY(TNU+8hG3j3?jhN^z{XmnHotilUeO4Vv}kc*Ns2#F?<~B*q+NZ@NIS z1Z+&Vv6UU-qD_+Rzk^?%uu%k*#j*g%aOn;0$u|@<140Y@L$qiy$og(C%bKs4E+aiX zLMbLj5s?T&Ye^r^zv;Ftc~AZ%#H90CYG7eZO^#Ab=+29Nx^Bg*SzHhV8HxJrBtweh zqJHU63#J4`F32!h%XUyRGfM%1ZN6Lg@CkVWP<6^vP^VIPh2wx+cx|>K#yrK`)SSaX zNM~AUQ<F~933$y5Ikj-(Xu54?&as4fwK~DxL|O%m%}n93mW$L`5U_>UBc>o2_yUFC z3LbhYsy5A%JZ?E3bF3P(&2obSLJW_+<z+h+6#@;90iQB#cOt8!R>Q?3<o-bseFTZL z!o#8~4F}^ad?E+M1bI?>)U<+(<u+1EideSb+V)BuesFBGk>d}w(-_UTxl(qmsnm>~ z?N%g(bDdvdtN(PxbtSlKGFTWZ{F`V!J;BmI$>3nsaGQ*h;*NsW{_ijOxE{{K$sxd^ zJVj|cHO^(6LuKQm=H=a+8~N7`W5h$he%XC>vFI#Iv=viMtoU;ifX=E_;D1|M_dR}E zUEOL;PbrH1K9^Zvf29#FwCi>{(Bv^40bku76inAB97nJ+BOkW95X#zOahrvO#hpz> zpF}>EjWrJC=H-1Wh?qa7V`i4kzr!joE)%S@md1e<*eo`0ZS+q+yS*@KZjvdL931Ms z@ZJ(5#}3~&Dzpjv+Ra-yWplV#EQSYF5N)GnW;Qf6B_O2eRYsa5of=M$`P}ooeB~Iy z)o-D-4~@HP70s|6X2Z8g!FEPvu8bo69}1m&Qs$sxl-jCY(g)s@&lswPQ+YFQ5iy)q z+CiSo^2%~F)Mp?>Jqr6$Qy(6DrBq$8YXm=h_#F{Yo5GB$TVi;5c=0vA9LiPS$H%cD zZZy2?3#s9PkzR*#^G1D|#+`RzcHDTIn}uuAAC76M&4JNQitZ|HpQ+Dk<hsyn^ya{| z>1>l+c9B=7su;@$<S`zfEwVVPq;dCvsL7G=dFdd?19lac^!$V#K)fWCNkQZ;^^TB$ z&r&$>hS$ltYUgODB0<Nk8Mf*2r?)rNkCxn8KCg@6VZrB|g-IaKmL1TKii~#Jd=(CS z;JR*kd3j|A3+BnMq@~SwNcLG}+|o6YQ+9WDQ|s)E;raUKV^x~2l)^5W7u}vr5LKRW zz`^{!sApC{VQA(r9V@N72w@Be=`7a%^xk&CS)IE(o+J*mcP#q1>~BkR%TE`+O{8%( zI1>L<e5`ZBzAvCCns&KfwI{*Rca(tRUeSe0XfU#|*`xAkj~VDK1xwo=v>~rU)NVMB zj?cT5diZc@s=mW2D=X`DjN@d!-!t*WN$!1sHafcdrT5(qNs`lF@mZv(dJufV#?bg{ z0p!+G$->m40sBTZxgr}`MdrFQBJo3feY>}!obw@aGax|1i8mPA#O%C#IBnXF_8Hn2 zq}U_Y^oDBQ8a$Y0eUyBcBrwCv<XIX&38UpuA-IxPNof?U8?N`it~7YYGg`bh>2K-D zaIC4@DLRzntU&_R(J@P3QYbL6pnpBL=_0(<)Nn^{t1vt+yR9@COMc55KV3Asz-94O zMWW92YADUN(a*0PMiTZdOpJP-a4`8(x+CIH4E$+h@Dt{_Q=UA9Y*c6(_V)DNkyntP zuNcD}zraibw|(EhI*pnzxwVAE4a%6joFnNc<8IB+iadFg<b7Nk8Xp=Q41*QOC4Gh^ zPYlH_{d7=V($RE10L7~H^z>QH%@jzf0m6OY`I$s)x+qa7J389nn*k6+WGc}5&r>$; z-hqi(SlAEf0d*;sm64?svG+hs)yVHL9bHKGMq|4T>DIffUz32DsF}y1Qfj>9su!p& z6)L5W)`U+&FkWRSXiD$lp}E)IJuGDJ!C}(zcGD467;$=bX1iFY>wTHcEy58zbz@rr zoqP~jmp=f}+ec_$y%)NbD1fLmIQKM+kqQbldTlir3~pwvQpwy!_8tB01uCiLXb<IC zd-#6)X1+&00u@9F>sZl>sxEBLmS&1;>Kr3->})SjB@`^_sR|OKTQb4c*aHr)`%s*m zrLwSaJOQ5ot}`h@d&dfT*7pKiI9_;-_t#r92?+^~vJ;JD(tR(J+U+mQR7{fc5=l*d z7)zkMy97>Inf_W=qX(APo~R?XUSO`R?V;Y(5+y;H{qT>CrD^K$G(_p5IqR_z2O3IP zi58V&7#FDQm-_`M+ZmTA{R{a%mW!Lpg-Jz)BXE4I7P*EOoqt)B2W#^jnt~w0!m->- zueC0w<4xotvx0fkTLO*Wx2P$E%BrgG%va4&Sq#_f+ABd_S;vYUP?v*`e#WLn8Oo(K zEG)qKO7D&&CUtBZOBZS@40`Vx8}D*r@n0WafJae<ou02yny{al`=}sIW)D|wMx&pj zG1Jw26q0hOkc!Ir_Ap075Twb8`)v~HLPbTlBH)4;B(Uz25p~pb>f0Nn-@g?B3bxnL zhY???*}9EF&GSn&CqY>m$Ht=PVkfe?3N;2k0<RQpTOvV|?9k}-*oj=`X%x1EG3qK` zjt%dQ3KS6YsjD=ptE-b-5*7SNZwkU8BCl%pI5IW1F)^_ElN?X+7GKU?P5WScIB#l8 zKu&r?>jJfJ7pXPDHQao~+Nj-I^|*V>9pZu_oM_s4kxx;q`b}$-$Y)YVhvSI(B+MA~ z6P0Rt%%#F1Ngj*DdrBaO18EuiBw~!IB_)L^{0M)lxM9#`zeV{+B`*m&DW?j-Mx5-H z&-oTSWvOp0)q|_`g~9codsB9;*}u+2An!d2d8~_HNbub34-OQ&zoG~TlDhT6T%MTo zAyqpg<h=NziCWkGO;i=u%ctCN1@z{#w5=zdjR#Y8S3c_vf;n%uf?~wujL`GMAruEh zXZJe5d{c+NrZyTymC@C(f>4+}o;G4Aq@EY^ACA>h=341evuQ)W<-wYTnk7mf)qAWd zZidv>`WKygDB@C!dF8mEq2<5%U$w`)|0k8j{|EBrbnxUp!;5BEq~`g5>Ob=TSLyQ0 z|A>*1m0>K8nFch{7qsa7FYbT+PZ9Kp@_(BDf2foG|9+dLFX{!~)hUGi`$GKtWw!Yr zGj7L7JSGBMRy<tRchOlG)HDPC)B=|8d0uhQX3-{P<?_GWd+fBvh{wik&=(?}C=?>m z*~ZyPb!r^;@|o@{UxXU9Rx-U(bl<1k$CA5$ktK4K+?ti#HHzYO;y*%ul|F%fYQ`QN zlM9YEdR!wkG>Y6++Fk=%5=>95mxsE)zMErLe@8X{lu_~m`H%l0-hJKLRN~)%+R4xQ znB+#)3gO2yaB?W}p~{<SHIn~Rn)IdWZPG4wYZJgf5jSc~=s%`~Nkj$v;yrWzxvWD^ zmHT<;@$D3;Ujm%{Q4MXzwPUCZ8d`?r+tl5cs0YPmLjSvfPo6^s+HgKizVrS_@Yo>` z)!}(-Q^a57qai2W`hp<;8>Q_w7_)W+>qgH#;KyE0RLr!2^A!y2f}3lydDSwZp#~z& z46JNMq=}`qdd^xBJNB98_L*|eV&1MoAh`W^dYrgaKttb|!w$Rj)Jp&4NX_<P4&HxU z>|6oAN;5yu3m@MYA88_1pXw&W<Ey>@Aj%wmpLBMa8Og)W9EXVIbvUF)mD&@0tmRXD zVnY=1Fh_Sj2&vr8DD(*jdzvXp>p!_rPzb9na~A?>qPwe4^F<5}158O1?J8T`{znTC zVEgg6`vNCYp=<#)LlK;a<`$3RP)T=ZcV=3G>V{8zd##J^PRIW|RU)y6a87GmJ-Hg0 zkI7cFWqHm|W@l^oTq_n1=~cxWJ(SPvEwA|(=XhzSmi%sbclC=;3p!;=>UL|anYgvI z`F1;Jt7Z%AhZTw&tG$&w_W>l3`y{A1x+hpi)x{cV))LfR_pGtLT=;yF6}7Oa5-%Me zVAiwG5*vN5l{_7|qA4kLCcG|x4S{N^NUN-t%ll7SZ5QF!DZiM+5p~ec=Ufj_841&; z<<YZ;ZH@bS!<M<Zv;%59=fi>#3-laIa>7Ml7OT$v@*f6IQ%crR(;5y<@t5e3Eb@Rm zbd250vW;ZcZUuyUwlkQgeD5vjc;P7klzHi)tM!L$0}&?p#j{6~^^6YX?aEKA;d?l= zM~bDIpvxN{m!6Klu2crNq+KripjYNM)oWAVdkgI_7}y4`yxfF1_M4&%>A9wLtcFpG ztfp3NOyeIa-CMAu$$y#1L`65`o>{byL}rgt!q;P+t>z+^0XapL+%sq3bp-U=w=nZ@ zo!d+6eAAf}k2b2T7vXbCd<0!%27dA>mwKP&)n6|y2=C8$aUMBzy#Nzz7;ogzqqj7| zGR!AxuLjD?IdAWW2IY92%xvdvo{Pn7;_sFhIFS-<=Vp}HE@rialyr*9D&F`;9oOLa zHrc#<^NNh$8Rb|5mpR1Zcx4BlHDmxuuFHEVT~JAkm#^MH#SsnII$y|DinCyOT1qo} z4Nr#IN1tj|zt71ryxnnp<)uJrpl_2Go0S|9Q0P3LX<qhmID&Ps_j`^E^az<9UyM<) zAqHE6ZEK8uC2}4w@L9s>My;(=af)U&DGd`_Z|t;zdH6<7myer6h-!0fPFSX)lna|O z2P@maWQBESgAgS}x++hl65qNNF20l5d1@F9Eh}D737&B*_cdW!wf~1m%NLgijU`sB zeZ!Mg=A-#%wH6{y%>?;2M%{uuF0se1IGwacW;Z-??`Q7Sdq<T4fZ$gX+|Jcj{E8Z1 z<Fv0E!^D;B3$Csre@plMsNT07$roPI*uB^r?f8_Qdj1?8OYA5G!J>&ZQRa{<Hl9JG z<}ik5K3`$BsPIEMtU%){;C5aU0W^F%8BWfkiTOum$_N4N4rp$1O<WXd81;^lNl1nD zFV<XX){u8;_fn>(jdMGyj&a`acWY=VCsGi#)u=Kr+$}D`4Hry)w;*yWxBpeIO&igO zk7&rqzKl^B<F*}DXej^C&-Mf8Us@ac-mAItp1H*6qkdEf!aq98*VPr9dzVv5OCugK zQD`X$sh8i>Tp{3d7N9xyvWvaBsvbNGHo9)m-u~>4*Fa%5#fJ2D|7)8j`=IMD(diyE zQSA_pbzHgkIl10YL}a?m=H1zf`&S#fgN@UQG0vDQZuwLcgyuhGI=qkqN=7|>l44v4 zg_*L_(A;e=Q}sz&QObj)UPqxSMb@N(2uB{Q=CD1yth=F(Cr)GT?Pes##Y5w+l_V9M zjHheJCdZkT1whfulloDsk*C7*@sT)e%R`;W2^f*-6l_~_cc#+K+oY;H0BeFvR4}~x zdiKdv_;AbThQNb}b1%u!5L^B=KOJ}NIns@@j^?xL#(~&9vhK#uHL6PeiRJj6S9}}c z?@>@(QbP9be6>6ZL~l+z$n1j!mD57{HZ?eothIr+D8}D6JSZ>zFkqh-oqC`R2)-Lo zZtk?(J&6fPi>r@nay%k=y$e<;$$~)#f^hZ!Y&nNS!d_HY{<Hs@T8*L3$e}icRbwGs zJ7465txd1=<-E>ESyIW*gz00k9y~|T*(`;xdhc`mi@YZck(?X$$ES0dT|*GfNR2cI zu7~T@u<-_Z{~xuQZL_WR3NF>+7hJit!vGd&uJIPYTr<B-5_j1}gdZMx_O;RDPVY#| z-T4_J!Z2}ctlu&a2wx#fTur_z_QGE~x6;tyK0+K`dY8&-!fr;GOTOsnB=Cv~Hp@x( zPvl5n(Mx&bcsZvqDjaOZUjRbiRGBS`vQyuz!k+AGVD<GYU>)S`TP}b<p~D3QO@S<H znzEJF<C*5aw+6SMYI{E#nD!C_nwuS+7Z_yRHcOhsbeEdS%!SBZIaD$xyuICh7}Ynh z@%VZeEf;3E<HxuzpaZTa!@roo@x_w&@75kTPmy?=vdZ=A2Eg*nQrq#5?*%bCH@2V; zs4q-Pd%JhF^ov!iZj^ikuzLX!9JaIRB7<klxA7dtm*kSn<|&H{9KvkdDxJAa&E{Ib z97?2E_S*Z~BE}9it=_mpypG(B?QN>{NqHB6*i6Ga_%+ZYH>Ey4iEF8PFf?MRuTKVx zT+j|N0tkccD1)}hfb&_5HP*m^?gSTdNtr&zGD=m?V@n<}vUm2c{&W6>cpx*6l=}{O zNPwymh25!sI9Cr~hp!m?1mworZ@e0&rmO?KUn7lkyCNX+TJ<1kf#uP1!gM~>4=rWA zd2bqL#irC-zC+=)-CHHht<z?^mTr0swgwscf}O8be+31h92>3uN29?2P&F~%PL~}( zKSf7_X9QlwKIxTCq5Z8lQYK8v+r}We{ME-rWh1OBZ#})G>eVdZLgmA%BYxdP_(9~L zwfUka+I*H@w7S*L1W;tbFZR+LdVehB8Ji|yuIHMI1NtCsjDwW%n|KKBmb*D<2^~5s zz{k4Mnx2wacbPY;{bC?js?&I++U}K83k}`JV#CR>Ga>%GF%{*(*c-YZT7Rb9cX_K* z+B)_M=RJmm<rb{FOH76(@=0cXRFUFew1&S9;sz;kypl=Zhx7E~1Xc}@$@VZPc8?o| zGUo5hRp!`Cx1O;VZ4>Rg`<cin_%+#J>v%(6Ff+2afj!j+x`_m)2F(Yd-7oeuYV=@l z$<}i%%=X}+6(#vPHj^eV1*t`1ZHnhGjTLy-jdT55>U0N#hFYGwkJwK)Gz4ixs!IoP zoKNH~y}z9ZBXhl|Zw#*<C_$AD@S2b1Xi6G<CbxCE4R-8FASB|n+FUAUnv=W9B;Npl zbv-SE{aZXn9EaYqI-2f!+i$Xm^s@#c0SjOkYXIv$@v`@5-omlW^v|u%L2ihoHoanv zMCiR!?1r<uWeP`Oex)3qX?K>wZrf?|01?cocQE+^3+x^cfjX(TQyRG6$ei)q{75<t zWQJF1AU6|mH<s2Co=vn${?H&$uAH)+h#%7GWwJbDrMLd%#8fcs3rfyQU9F7BWrk>G zzZO`M$@5E>xq4Np@?5w@t}d0aB|Z?)sH{a0XS17(Y5LH<Q0<O7B!gx9#yA}jBiQ2K zf5ZYrj<KX=HNQ*UC_M>DmON);=-!*J&hzupU=nZ{<8(Gbv0Mw3<`&d^Kw}(d@%fV% zEsnM`^Vk-NSB*rok2tM@jJ7<+eP455wcUrYQ<y}6`@~n%{DK~-$&vGGMFI0P2%*#l z+pRD3%ZKcoUTa8}iCMo(jyT3|neP=(BJ#=Rf`3boB)OiUGTY%~_6FeWOM}%haCLE8 z(~+fOdJRr8cA}a+f5E@rwATr$irHtcEM81m`P`}kUb@SYn{#~C*kps-$sP5t-QA|1 zcfbf)IPSd6rKPXu5$Ae{5zWvy=SCo<K@}|tp7iqMUk49M86~uWLL18Z`brO`Tjp5M zE_72`Ng%Mm<z1pLTyCgI-oUR8{U|!?Da^jyF~_<8#Rn!1QURxzZr(`-RFL<dET<Zh z$2kQE<-HEc`CE$k$cGBHHB)$ZhIp}HJu^EXSxkHLo3=)lyj>i~JYjy;!20%BG}U2F zeomjNO8>m##VQ+pT>djSTloSE^(vRNxWIH1?Wojp-jun}Q^yLB;Xtxa->gCOSRXiE zdZk%~6}MCH*0n=Bw~|KL(zLIl)H+BB-l}{*i*H#nM$2bAm9QE2exnp-O0w@BgRN(A zU3OaFeYR%f54%-ejplUfC^0dEW*OQn&zyk#_$Vq{%~BfRa89N6j;MQdCHzgxADs~I zT*UJV6E7Xzr8o#F`$tx(hp`kK?G8QzR$ga;Zk0a?5<%|pRblJ+%JtN?hZaUN;=hCN zGtQW8tTBLJgwM9n3($S9fD<B+$N{C2V7!IzMdpP0`dfuF9kRUcumV_&U2O$ncxSgk zLBl(8?g%A744F%!kBpYGe$)Au-fQ5ki*^178Lz{mB>5<2QTptn%JYYD{G0P&A|vQo zRd>cGWuP~oWXS%zBg)ZU@a?zU!|ou$?fIHGm9b?@^&!5m*thZbK0R*@=DpX)!^H0& zHsqIP<=jUKELu-1fQ+?fn!Fp$;tL_kT>}aEP6U&leT_;#fT~JA{Lk`mzb$DmeF}6S zn0#qHhbjN^GUC*uOPQJ7&oL<@ua1lM<Kg>Ro-aoD6Ln(1x|93GI%TR0*M=|jny{q2 zH0`}8va~?A#g|}ro}M*<xFiItfUJaSbF10finYT(9mOAmK{|15S^zgzX4bVmg?X|g zjV!)SNW@Hwn2x%%c`hiATDY28G-!NcOBWQQ!o~=5C@>4niu{S-2Vx+e5UiWTo@ntg zQc+#zCcIRuUw0ZPuwJCO?j+zh9`qln(S{xw*$!*OL|*8IY9DOUXJ4DMm`hx&SW=*n z3I#|j2M}aw$$=Tyr9yxFojeGP1jm-!{zTBu=`Aksf2nIhc3gP2D_1Efj(o}y8~<s# zl@rIkV<g+z9;RWnTj`TgOvB6*F`pHQZM*&XD?p`Y^<Sl7@SF2Kd4-W`r(CF$K-3W1 znA{F=bj0I#)%m2p9>}OaO0h-icF<b^P?sJ1Ll&`&v&d!nC`>Z=+&wuZNyx&FjDUp% zur{i|CmRnM>l^&e($}ANhB)V@=2!*!@Cd)Ys3VcK^3FOXb7nSoWGYogdU;u6s9-?A z02RLK;X%1f+|p(*!93M<73Ur1Bt$IWgJPVTjyyZp$E-2*Y~`<U0493JNWA>|UMzPN zTtX&h=3?(Z$qGrY!{IitHDLH3fxC1Fh_4*_?|diR|Gwpfjo#_r@on1+MHl^iPuV9L za^C{yMf?FN-_;2B88no_V?<o%zA@$5=~#ujFtLvNF%3>nMZWU1pS?&2aZDC&ij`WR z_rc6KQWfY^g=wRSH}UQ_OZtD-mBZ?j9z2a`7~xV%{W-UFXC<^coUbjE^9Fz8n6fwJ zI;(kaLKRfTGtGWz00*>l-IEyGs8S8N1b)R(P<D~CP&3K^BvNij<+MFonyVpGY5Lih zPM?*}BI8_(r|izM&v0&L3+UwQNBu;K8hnOtuh%hk?VxKh=e3_?no^fFRX3g8_fp6j zG$VDSX<ZiMv?fJ<CDxuFd$?&yO1GDc&xFWoPv#9ZSf7n@TgnBoebnJg1<M&D{M{CF zT%j7X?l|QAdBej+gMe`38chKQMZU^hFOo3gi2u<7BC-PCHSj%t+_bzpaohgtkdw!P z$#Ai8soQi*M|T!L`{R}>^3w6@bIUKlteTMd5G`Z&chf@I5dJIh@G#)a%P#Do)Nnyg zN9E|E3L<yIV`|f#z_o#;Qt&&!$PjR$k=ICGF`YZ8tT+B?6aLBHm)a|a&cAVz+urCi z`n8L`?V*EankVBKA(A0uyyi1XZhUp5>0v#G1%0kK={xG~qvAy-;0#y^qtHpH*80Ko zbMal%`ATmRO7B=k@-wj+Tc6E*U<XrAvPkoQHe-kn@osOiLHEzTq!tp)W9s+G9w{rE z4CB&BT%Rn0QaLTpMGJnn{qe7S>SZM7u8BVH(ypt!)O+87BY$?jTEan@rj|-go|449 zLwbD|Z9YC+`4a5lbkej?F`G`6)j>_ic){pC{l%FQOu+o7oCxB4(pZ_qD*<j4YDwe$ zzH2+}ZS;2w>yjt}nEkBa+_HOIE*IEn8B7$Qw>KrWw8Z}pkR-AJAD}riLBf(FytYnI zq4bz(haIT_y6&yxTaP%XN@44HDIK41lnC{s4&?XXBj`9+f4HC6H4!hpR#Hd8SXz4c z$#I1nqx7b`uR+za_U5Jm(r`L$SDpJOzZM_apo*%4@&p<94zcZZ))~bEEMC1DeHWSv z!}bs)`mYBu+9t)Q+=HZ?7=ZR=g>w_`HP#}^ATv?>1%zPG%$tB6kei32!uXRjredBE zb!q_D)%KSVgcT+E9-)$m0*^as?eq!tGqh`+%vBwqe7k;+=>Q8eV!mA==lTA#y=`%R z&^=OKx3XB0t<VHtcwRLyTp(3_48jD*|0^KBKzNA!`$<$vQl@&ZsHvt}F6@oBJo+53 zp{mmUTG$7g2^44ItC16E32Sa!!{@;iP*@nUF40>a`AE&^iyY(mYb(11xB6X*E}*t( zd<zgDICOk?8Gsf;x1fD%Z{sQ^F=auxKQv@6Wx|IS_a_HFV?2j_shT+3J8J*6H011z zX(+%VT}Q2YY@W|~M}K>w;8daj+~-+8bd5l%RcS<g#x#-|RitM7@Br|fD=E>&+5SMZ zO_o8lvZM3PRsR`Rp=fc5<Uu<5gI`;`;Z<)}c*7WDXb{GxkDDiKu$HI9Z<B~Z6YQWb zRn011@$t<CSyi#qj$F#+?e%%8L@3iU=0fCki;m8Wor$?CzwyDjzg_62*P!L%Z3~KW zxT5p!@TIusVB<|M&2b!Dms;nK6xvQ#OSkCeL!%tG!g6|0vF`W&Lg2lnz_Hq;Mwi8L z32k#iGLH7O-ja|8lg76>aD&{u`u{`QTSrCtwg3Jof<dX2fPkp9fOMCXbj$$K(%l^c zf+EsNH%NDPN_Te--9y9BobBiNKHqcJI_p{IyVh_0{?c{NaNjfcy=U)zUDx}1y$=I) z880QqJi1y)NIJV|%-1t1<2d(s#=eFhfINmw@Z<V&HyZrKt<RZ?S+-DXBMC|Wv#ijt z90prcZV|t;a>Uk*XRS%~cXE2TdO`QP@uY6~&z}bfQb;?c;iieO;%M>Cp!@lE#qqLT z?v2IXGOyu7J}mLOzPcOMz9tT_4Mq^2W#=*!q~sbdeIOA6Lce??$i{qSO@ZF0S`LQU z5Dl2u{#=;PT=}>6#J%;dYm*O0hhLGFj}l>8<xiHGpPsE-F&uZy>29C@x`*OX^skOx zhMd&wIGmSf>)KKdLMscbW&%=9QWn}ObQ|{-ei4)E8D_PC6*qTN4eH@<RFH0{WXl7E zW|qMn$dWHQXexT?OjTs)lo?(`?ny~Y<vzCY0L@X5)N5r21_5{8nmC!*4`y}|O+l&X z?(RokZc&--=%X6h=Zx8@v5CYI_QuxvzsShN_djYQMho!4ZjU8A?amAJs^?o1Z1HMS zbda0<a#)3Knd(~uZgg0lXPk1*iAa$rno@A`0`dOLXTq-&VPR3s$N-=1!vacy@+~7u ziBWFvI19wdz2PW`trFX>mbpHucoi>45J=D$juTr=;Wg&$%5I3{)}F`E3Mxm&zR0jL z807e_dswjAg9NH*LKSQiW)Eg}ow$J9>9LDSM1V=S!URXb5+eqRr;w|j8|D}RXteQA zwDIz=0cng=$vW5z6takKVQ;Rr6Rz@ZzMb-@6k`72gs3aM+}VG&?8wS5P!3`fOcbF8 zQ2fPsfaJMIUBp(%d0M3587fc2>sWfD$!hzBhYo~uHjAp4vu3L-XFd8TU);VgY7>IY zz0W^|5CwbiUvHxyAhV8w@;}4A{O5AUzfK|)<Bh&9@_A~4pW2liC)wrv!f(#&IxMFw zX6hTpB-wi%99afBszxf2y(zCa)1NFXWk9jh<3agQUUQ(QN4GH-cf%?()9~P|n~7%5 z`Q-j6O1%d{1g9}ceom+17$e&(;(OTvxReiCb3?NtM8(0j^mk|TO0+`-dv@!P(1yOy zW~*_MOk#T*rB=h~j|;cLIgb~l@e1J-&U=EbY#(FQraK2T^SXadTJgu0xrnsiO5e`8 zu8&w&UTx->PjlDwsXDGNBgV>Q76j1Hd>@8r=@EZXwZ7SGo;=<P<ZLAWkV~Ag^o|cK z$Df5EvFH-A%Kl_y6jW3*T^(~{pF(Tl^;aLgV1np^$dgJAPOIrYe^M?+iVN@&Q}t3U z)!8OS6xI^uK!4mU^45(f&X^HCtfY#VDDeeq@qH9f)*Vc0dW;=fTES+yFy?*vz*jUk zmxd2^OGQiB;ND3vqrScS6MBU6B(U^7yUA>+WII|W(R}qW8#85rRvy)Nw;2n09<hU# zorbsoy$z@S^z^qE;<jEF6HKq#I$F|w^Ypc~JwKa>z9GTbCMUzs%TIa5#3VAm(0C8K zlAvB+@!8}`WN2osncoB>3(JUwyi~9??E2KPVy4mr$RuCBAnqpJY0ybYtcd;j^QogM zD<M85+CW^8eC^FaO?`sJ;6MT8+cvsF^1;bQXEH&Y&>tE0uOOXRc!Y$;8+KbAs5*Cx zZL4D=N=8#(3KLw{2sNwS1nH@(+&iPT&3bm}+%B&jg>0&Qb0}a+_>;PB;_GiXi^@;( z2^g^njK0rRtdhT6C<&%_E^cXQ(Lm1Uq{1teDajv5O3Bq7|4FR$J1fwfQfoT9{cLLF zvVNpRE7>hDKXYJ(nyhtPPmaqk`%$L5yPuU~EMu=N9m*r1TUT@6r)8dRfoDcdr50du zJcNaZZ#tQl!<FLd*h*PAL2wSD^XzI2OsR1{Ic;Y4kvrHp_LGRQjT%2>jA>v-dPYxA z3{g`-=F1LV4@t@HU9lY%>ly3xBG~EKiZTiEuu)2~WOi|j`Ov>oC3B;2Znl2s#p(6c z&@|EUos{e#R9WT4#pvrw*N$anUaL80R@RX^TO?3p(=$#T+H;PKu;v8unDwLv^;v9} z?fjXp(7@g{%kvX&yKXe&g&(l47ug~YKsV*I>%p$~N;GIT?v&Gz$_dd{Z*)Rt#3w}Y zk)w))Ce{q_POOpOs9I0SXT93|WH{A^c7c|#)H$emw&?Gdk)!BhunTm4TMEV_`D<IT zYA1jWv^P`WH#H`gn=GxZy_6h}G&j$kuSYsuErcr<BoogRAAeM|wY9UG3DTK-zm@~L z4iY32IA!A)YOp!ISH&@S+OjiWy(OK~Ix=Rn7Zz;A#6`Y$)O0K0e!)lzSR>AK0<^K0 zU|ir3Uzr=oB!s12=VD#a4MekCMsU+BD@SfZ7Ck-62yQD3`Wbn+BtJ^Up6!?|EamA? zdywOvy6)~dZnoh&Y4Tt%IhAcLS~eds@ThNxCb<ga+Bjv8_-4tQ4NcW-#ZKq;1e6gJ zrmY$O`%wn<_3dKOuPZ#idHTX_|FBo3Kau8T(KXBsLd~05e|YJCTtyYK-N`Fu;Bfs* zi#{0BVV2F=Y8o~-2>EWWlPa~5I*mJ1Whylv5b%V45@B?u5wjUevf#JG2Ju9kP83OB ztyhuP?$6ft4G;LNe?*%Pz?di$3m1m*LOLJb4V6XjWA4t|PI|KzktK#jJO#Ss_QjH> zOOHpXJ)FD;`kX~W#havF4Cz)6d3&82s6$?kl||-_+7CMS$8i}L7z(<rvm2T0OAKmP zSl$-(oU~?XBh>30cBaB6gf`ClO_rh0z$vE}8?`o-)hqe^2JN-YCU>_BI@A14YMnMr zk=P8?X%O%FxSBR<s=M1>Q3hFdO0<iNJm-OU?#$)O3&R;2I&MKbWL$e0v1Ah&>4MAE zta?1=)?_4Nv;r2mFh8U8%E^TF+r*2+r!<VTYK=C;4Wf=~91T>Mo8yYmle@bU&=sWe zE^eSO)f>h$Y{tpSUhi_V6v!))Beam|s-NW~vYDZQoWsX6FqT{HOU&J3-6&eSdNpAo z@ZQwnu5fLihl=BH%y)K_+D?3TY$9@k#If3mOe|JgSo^GOCw(N;KWCznpIY@+ptXHE zieT}^?^UBJz1Dey-vFmmIT>>{uVdh&Knu9@_Q62p-#R$-UbEKcsTmKmQ(@nwu52z4 zp!&dz5kF$Mva}?W>~b4|x#2XRbva^&o3xaLfC^o}Q~1e|-L5q8Hk}pO!f}*U&%l7J zr0n2Lmb$gEeg|oE?!cI^tykB%>vnFB>`P1PP|`n^f~^^OY0Xa6T+=S~hmOS+DQ?H- zv0laet!erK55C!a1r6m9U+1$j-<jn~LEnT1g_uvqg)P&AhTeers{Oj*oUhbY+79J^ zc%zwH-DKk$d`4W~XdM6g>ZU;XNk%5<R!J=RgRz^qikuZF&B_fHT5=$`deD(tJA{XF zzjJHA*w`}3Q8e4AC$w~|jM5pu%z5mtG4N2h<P$`TvMJ@&`?s%Y-s+vN`tIft#i|Y4 z`p<EQwe?MX-XFI2lhc$N>;uFS>!ocW>ZdY6CsRfY&!6jcp!1A9dxmRld6>iOADeUU z1}pG~fP;^{nq_EV!R9%`E3SlDnXa}^$Y7*IW&A8eScM97os-PvsZl$is2u9&t}~2I zym(1wX>Qmez|KChLXxuF624fRZI!5QLwK$)MDte{pe$lT_~QB6y~N@IL7KMSkJ6Tx z_DM-0M#^b;1o(D!_D4sCh8Z>T<N}9N_UCg2WxQgdqW8bPF=A5hJR`(khrgwHfU`Zn zRe^j+cZ~CrcmFhP6pC0UeZ^Gt1@RP@Ffuy)cXduip_|=)oD`v?loSi)=_r;G4FdFL z<>k;iLY?Q!k6%!ZX=}}{gB7Xq;?pP57)$H^wcXE%)5ULtor}gy+K{A$I@g@Wr1dtn z-lF7%fx>&yA+5bVFI0_r17ZgG>+$goTyg2PrfQFB6l@6Z?rQOKJ#WUoeVb~^q++0) zuB|z)U2B4}Uw0%*l-k>I-dxZ-k_+1NzvYusQsQGjy{r1Ai$n6Zz5UIoK*mPBrW`pI zd*tu6g6#^n#e{bZ|IP(KH<>JPK#_X)*+*U7U%3IVdEYmn?WLO}va)}oj`Wl{aS8|s zoJ!hSvrMhtq@<Pfk0{4H`}~!v9Z5#d$X92iq$H^2pz#UX#?b?GJ702Bg6mLrzy!1w zpKSH4%&FJAE>!yfOF==wVf%iTSjAOu6|=2>WmM)|^upzNm7Sx(oB45#(7ZS?CA%4> zzzIl@`E;M@aDpV>z|qms`FGdl+W<th!;NlWCN}gFKEbmim)07w&ytdlmE%@$!)s6> z+!y^<p}&R`ct0-G?i(5F7t%0MQ&XoEW!<zPDheV^>r`Yp?qKE1_z7i%h0?OU>C1<G zlC6ovYFWlcXnvwf2F8#put2l2a4Cj8H@Hh8U4OUmK1JeTBkh<0<9HD{KY#yfgcLEx z)|T1ZjC56Y+PLVtPK~n@F+HViFv}ic9Sm^(4C9B~y3V_uC-9h%f>y*b%f_!CUT?9X zIhI?jZyxseS=QVh#1h_QM97GYh)DjjhcPrH_HvT3tSMd{1xt|5*0Ll+#(8p1^zCdb zk1w9ePzV4f$i$5?K7763-3nw_iU#@N#|`SXOOkm;a?WJc8_`+Uy_4il7PCRLO?E4b z{=NUqN?!u%P_9<0Xa$+B&8O1QSVqFAzSml6a2;d4qNWf388MP`7t!LAnz%!tB(>7W z=4P@Vxr4+`JRmV_6mH<vZo0}JQOnMui+!=<xXCLiqQ%Zm3A_H`X(7I<q^RUzX28A{ z9SNo08*R`+$`xd9cw6>@yY<ml2k7vG2C?I|@0#X=e<z*o+f#+yZaEtoqKWVq6y$m7 zUsah8PYov9qc)3ktV8jvAWID=h+(TgG2FF0alUB2X1P6<ahwDMMqpRSXVa(Y7N0o7 zo^~x2X=+I6OQxl+Q|;L#+bi|q!gxdJ=CY)W1vF~!3c3vh`HRd}IW1w!*pmzD=hXQj zGnJ3&<a$2p7<U&z#BWaO5)$$Q!dkAUSI*Htu{pQQ^gj$uswpf?9m|v60aOyOJFdE8 z_gWYUR*&0$zP!9EtM#rws3Uln*Jf8!7K`27USIO@<HoIbNxY`pMP6ql-0`(pAtZD8 zl5aB6>9qd-K*q`(S+f{Xvqrpy@3cvApDVd!m08@%>t`{!p7fPfSEsAt@;25$YY$M} zoUflg9dU1a$D=w_n$vpn_-js9r+G4cRZ<Z7@L%xe7cbnNp4%Q|!tL*m_+rd=6`NBJ zfXZwS@vJ7BWqZi&$Nn*f?c;7bsiV1B!lNgl0psIJ8x0DjN@{A{x5B#HW_0Lo>XFz# z<E0HJ?gK8<LK2jYgJW#TGOIaKM<FI6L0$GuvXr9mrM^OT@z1B$=AOB_($bP$J-2r; zs|E6Z5Lbf)w=BPM$^v%$Sav#7Y%p+PjmXIG@c5W8aiWG?NkDiIYkzw%FZhcva(r6D z>nP;;)0euYMqPC%M6uJ4{b|?l*l>%wStivp$RSXf`tpdkaO3_{idPXn0`Opo8agc( z9)Aits@(IzaY7(FgZ1K$>ZeqK(nC7M17xnvSKi~+l#_a}E4>QU*_*AD(Lwfx{N<mf zkO9Fy8VG6GRu^wk>E6BbxY<kl<&AB<@)Epi!UfK7ABevGMIto=!ZAi0TRQN{{|O_l z4s|De%>4JD!kdptjy~h6)P^5EdH+4Yt`x8c<@^M5RHA!3@b`caR>Wg}W`&0!ngxfN z|Lf2bNpPr|t3po7_w7G?w`}j{P`(}Xzf?c`=ORvE0z^5_f3BOuLJ<+P14L$p0it-e z)_>m$nwjzaY5pa06B9#zu=poLR!%F1cKmq%SNf(S>|ZSN>&N}Ss}~AB9tOR_C%u$` zp^?oU8iFV${kAq~rJM(Ye_urLv+@36m-F6=>e%sLqQuBY%#;!HzS774T!~yGr`X{4 z4;J+<53%fOFWGWaf*;xbkMJKwuVF;vGt2z4QG1*PvcD*Qkn-6wAJc=L(LW<#(tj)U z&Gxvn2($TSC#}EyTXWRk`;MZ6`~MB<`u~dVQNZQs8JB1nXz6JgGWLLu36$hf7Tu`< z7?AG6H(%dr>}TkWbPte4{w!|7!n&qvM3%*18=<F{x~!*He({&af&%BI(*(0FAwK>n z+^6NW?vmbPTU)7POb^NrYST49hX^$o>>rGdc&e)OQ~&QDcv_eesX>P#qQcUBs8DrK zCsrnf{bJO(Yw)Ij&HVkyk9=Q?q16QCzYLHBe-7><T6@Gynf+<`_&?A6ylS&rl$*$u z&9#UZsEa{gHk)9Rf~*)wT7gIX1R9Bd{NxGke`y+9YKSX}6+V2BQTmYZuh(g)B!BoT z8nhIg{UcT6s)D^U94h?F*-asq3b4bA9hzzgc{&HW?T7;d0&S}#{+@L(wF?Rjf>-6> zejDKVZ7HvbiER02z+uW6d@w5_d4QZr6X^&WQDXi_B>QFXcb8~008Z8lZRYdK*)Y-K z6XO2!<x|w5woHt|fGh;EJimi+EdRmx3P_8JKFIld+5h(=`;SCm_n(vWIy!<l^70D; zTU%TE@T>RWqobgVgXSewdX-ylkkP$DlG|LlG`TmqZ2j}BQBu@Fty=2i$87WHf!?Sh zIyySNfBwh}v$>%Wi<nJFQPFn45fxvDj)9@U?esFiwW&Xm^R9c;*kVw`FBBaOt!y5L zOyI~98G^vZ#;&nFCiv$^B#8b1c}dmwsNmCK=NW0;^XJbmwAE|O*!lC{F=&*VRNAd= zpOSDW%9HEBS&auvP%Y+bZx);1SRkkEH&#|~|51;gGlO|2kEJDoo14dBYi?_B+}u?s zAS7hE>h6`{r6g`Aa(~kKIP+Aa3XxLk)`^YSkF4^Smy#Oj?@yBg(fecm279D-RtV{T zpY4v5fFZ#Pxd4-wXR=EE@<)i9yT(eZu2>$iYXO?Wa^@BaE#qT0V}AY|qLxo`+8%4} z={dSMCcJmg`}OPBmzQo}o&SULhJu-vnKt%{?KMknO7TINzVCO5^$o)Jj^RIJ62js- z#@^(PUcfLPVFl7KFc{wQp5Ar*CVsSchlPc8x;5&lUcZWSIZ5;Ottf0{WW?9k*Tqi} z0%3UfE+Q<<Y&v(X)h{$jz}|d1)%D8Ba!=6Z<L@TRc#gkU4qd%XGY(B|SQOxgfrd!4 zOXE%+x8;}Ca~r3Zh$~(sIV=0YrhnZAy>(_|dX{mY&e28z*a0@cn)LdO$OXOD1(gP^ zU*`HP-X_QLnd(_tE#yFqr?TAKc!-E%CGU3CmX}xb_4ELWEvHW8$_a;zKl6h-p!&{M znLA$%G(5y1cQk=Vfg$?Ej*>Ei{N^j@G^>UM1O#MHXlrWr@xD;r{3_CNd~}=xa3X78 zy@oo!06y8%J(?3b7_Yq_6FogfXwW*M)$hp&8%h?X1^#A6@xjM9LLD#Sz?>PsFDaf4 zb^Y<Dql>o<06Sp6J+~InIuxIgvDP53m2sS!r8rztFC7yW)-mb#;DK*?hVg-1?lMUc zmqfPl`P$fB(6?{rfJRF#AG^M~`cYmhj?L7-y2)`iM43K%SkS*ez6zkpxVYF-qj?;+ zi*1INu}Nn}X)-gZ0K)0^_FiG3ESO)ukZS|H$$0ws7!>q~Yg>5T?BwSVtW$Y6|Mm+> z`W*sV4Dxp^oVr*E3&q9TH@D2l1!2Fn;t96Rat|N-t4(u9sF{AmDXQ9Ff)|%?;5>S? zHD6}WN@xt|YgN~>ty!5Fgm`!yPG)VqIy~r8#fF?P+TNZX(DL{$hIM6xePDj!JJz<e zSJ7Pc8~Qi;x<;iiq_90?r7azgU3m>OEJ6@>LnW*Zr48BDF(bzVvR(l{ex#>o4!`b? z<M_pUxGqa#Uk4c-VH;DvSU4?#5PDn-%&2SZ@jE0?NtgWy@n4B2#HzF(Tms)YE;=S= zY7o*ny3`NarYPUOrTH~F+<UE)33#UiF~{z>#(rRcE)E@#Y4NZ*TWW6oz18U3q&`<( zIqp@33>uYP{r!eL)`y;(i;a(Qsgb+mOmsXmZEY?aXACVZ36R%u#Ka-k!RnPJ10my$ zTC)HqeChnp65ra^)-Ip)ex$AIPshyi&>^e2>N_5f>s`P_Af8q;HZmN%bfkr7%Vxd3 z+1bsJab0mC2BhH{<`UZy+s6&=4w*0AS66GAR2aj;BQvIWtcL@r<boNs8w^c#rGyiD z1_M>|SK_zU%&USiPyKM#+Z>)$fP}FXJhQ#0sj{?r{x}l3d{H)GIU^=dx@(y|m}+SL z^+OBj56bQnbiWks6tBb!0bmObTdR`;fA_rg$gvfb+X~+!_C&T%rJp(A(l}&wi0Rwt zZ`E9+0jq>I>IdXpb^+Gf4tzoqg!V>qnF8^Z`@sSJu;U2{P0j19$7wM~GI!@&fguPD z#e7Z<7L)NgU$bKkr@gF2?SJlTwilR)w|8U1Jz#Rld>sfC(D3SXsw66EKm;)|`TU3X z#p#CAU5Nwp-|6*EK}9KjOpbH_+lkkSJe8QQ-PT=$e)|m*bzWM5Bq`KxVscc#<;1~F z+(=y9$VrZIA1^g+1@t~~TEja9`k82Cq~tQb%@jFvX4Y358R~X$jt&+77%LB2{P})+ zpsSCCWoT!#45NQ9&Fg1a*z3qUK<8?Gok|1OX|Ro^wXT$Vh*=J$>ye6>$-xmbs3J_l zn}c6?yco)IZ$|>E+~QmUU%=@}CP80fvo>Dm_Eh0`ONKe<NzHz+kbRw~l0b-N+XLS{ zu<#JHzokPyY94DF5_})y!|TXNTa-iJ)tePv6_s-m3@XE8f)9}BoqvRq|IRv3M8(8h z_i-Q!p8!t%Z%>&o;!VqQ{NDmKHLf7NJr-`cJ`fddEJGymxUM?gp#M9f9+H_`RvWiH z;@fm^_KtzRzx!g$B&n#t!!<cf_{Oc8&1n@eU8;uLvutNqir15)sim$i#qR0E{K;Rk zdwE&U!WozPA<xeP&wXPnv%Vz#jZ|DTyHXYaG#aziwK^IdJO*U0(^H3P)S#C$$)%0( z&M%#V+I%i2yMO^oHxM|0iihV>yCY|&&a-xunyP1o;rL8<z{`S@blk(OH)HJngOq>g z0t}TKY#X^5uV9R*r`Uv9e~DzDhsGyTmmQ3Z2pl`9-wul?3MbJrxkyCl>|Aur`q|Z_ ze|w-Dr{mV}TcDdZ2lS7PJtM`<%FJE<Y@L?!%Ij_^E15bvGEz57e9bs_w2UxFiP>{< z;SFA0PWkTPHpB7OK#;cw#>%e2{_PR|ENp)X62}ho2#iGyu!V-Zp{bH*k$I+0gGufz zYm;t!f*xTbtowL0&AjZTv-XQFI|SDVgU#yYw%9-m6UHX82z$+DSY)RCd7B!b2zJN? zi(_s@hsSGd)$dxogI}DNz$Ppg@Nr2bPH#iKlRZOjrtNW9ao=RJ;KN<oxmnf-YXt0( zpHs+wFJprd?&IAv1>H+zb}lIlQ86={Sv`C+{h^{X>~;GIs)QW#hYt|ykW2x=VDbvL zRwsZ?1)78Sz)t|FR;$%$6rTOVWKzy@UdPT;s(q#<sAI-{@l(|RVx#}kbg+2^?~*nW zn`kH=eQ&m`x5Lt%fI&mro|&CvQ6pwAaTaWT8MI5}G=uc_1|iv5_4NtA8w(Ti-)X4a znYLv2^Pagjy2a}#ESgwL_jWt$_kf<c*4MAGu+F_=)&T92l-tt@<Wg4G406f^?YCXP zHe@dk)I9Z4Q;!J>K!0~{SKmvHY8|kiNhsJ%wFpiOdCR`hpr@PK*)kh-2P6c@2c^=A z47E<D0y?chaC0*3F&~Gf<W!h>*BOqHgEj_DbTeOU5!V0S5oZ%Z`Q&7zx_bsDCdYMK znU#BJ<E>_kS!lV%l*M9apC;IgwEmz8IG=NRHAW3O3#B1iA2btqn|)eZ&d)`kRIt6q zdW!d49QSuuFX<Pl(-Ww=dhW=Y<Y1SKj0^`W`?BSi0csA$-|6MwERii6<MGa*uVS93 zD$k*9ZjO)65!7o>lzCW%Hi#U`+3@i3b7Kh;l~UNnv+$~6oA175XVbWsrV{`2MXp~f zmiQl)j#M{`7Xb1y+28Qyj~58(iM+!S6YaOJBeSz(C^3xeaTpriLHGxni@-l%I4GC{ zju&*~)?)3--Dgo-!er&|AUPm^&(Q{3UF`iI^bq||BB{G*yQ3q(`UX21jKBcU<V$qU z{0IXhFwj3BQqUm%ZR||T*)i&+I*GiMwtywal#3_Z)P+z1tRVOyh$U{Cgxzab$1pEB zh3=jk7^Y{V3f^6<(9qIeM8rM`w6i-_j>H2oRinw1DNoN&I>sxKy?BHf!4i*121C(# z$+IhJt@#d=Usc~d1lVEI&aB-0SF{uZe?t8lH_|sLXocr5F3?IIOM(IjJN!lQ&2?At zp^(<+D{u9@6;Ox^{HF)C;)6tT>~xLW%(f020pi>wF)xRP1?BFelw@>xWMMbi(^;H@ z<_=UxZ^T2hf^`y{qU<SAS2fdw>>PGo^zCQvVb6F47DeJk?WEjH)znVE>Rx#V{P$&+ zz-0)1+#B@dSy)i;vuWtl(~Y2ln3d$&cpPNe7#4yG=Iqlhi#s6R5af2f08ygJQ}oC% zP!z$(@9ys{GD87x!MEU3Ae{0{nGmQu{G;jz+K<597W-Dx@>{Ch737CiPwBu3(f@tI zad1z@my-2ve#6M|8D4y$8(LR{BAltgd!GE??-5b5-MvaND|dxLs{Wjzj{o`hSG^2= z*vNAY$rl8>{OY@B(61b!W}aWc-GHK!;EbVxvsG+!lAUk==K!oaPX<-xWzwoG4^FfP z7<*ufa{mfRNWvx2R#O=q3_N8L{qgXNH7)-bSZAwWZo9baPZkWl1OYYiQ?^Lc&!UvR z_Hq&pcH^dVDw<;o1v$E|@beQ@^D;c69q5g1ds{m>zpcO<Rsh75Q54qg`Sz<vDnJ>F zPj`FHl0>Da>m%!d$ffxxqq|0)RpM-kJm}dZe}Ttiyl#N*X(G1O=&ZW$MyB}gf>FQA zrX>A<rXiI$$mwb!%^fE>Gs_r=2v2q=hC6x^tWn@N_uO&FvS8TOgKg=n_~sn@Qzz7@ z@X&~js!A(R&rgwKUUMQf?q^fUaj4GY+)HY32}VpzjM!Kh@K$?SKl{}~?+?hR_k@4T zCXg_%A*)<ZPF(#e8DiszxOLYvE4;Gva#&E{K*sQ0T&c&R(n*gC(s#Us$EtUU;V{OY z$1PZDe8&vIO+&NK!g&0+rs+Vv#;N!FxOCnOP7AUiyBI3-lAPb;SL%x*`no+rUN%lT zsbLn3x-xb)upV6QnncVL!9Cv_oxcJ!3a}j)oU~46b8>mZYrdcxgn42lL)7`lxhVTR z^T3KC)ae3O?V`NJ?7O2~v3?*L*geKO??y&M>`vyHXNaJG{|1_cBe3=WMHqCB7rEN# zymv-dE`9N3|B;V7>Ra01RxyO-9DiWW;!5=~>Z)jdhPBw(;}1)IWXBw)`6-!Y?SYQ@ z)wMOkXuQB5KOmj`bvPgbVjCO3MD9^BF?I5)*xDXqgih{z2!OF&!(nT-HxuKw06R!8 zfuxyp?#IRxaoXD&3H^-7<in}6DH?JsRs;9pdZ)0ud39|A-f)*LKghTXaLn_23pEYj zzPWgO7y-~ZC8bf!6UVF5Jt_)DxgzoQHUXDag5;kj2HAquUQAA3zkO$-?m3qFa+t2> zq^C_?Z+}`FYHkTzKln8_Xz>9kA<Fq>lKG<K7Kb1VvcbYI_jF?eCFHDgBiPgd%ET7i zX8>hud6Q=1_2K450G-cemyzyu%bq1l_VV7YN%GH_Hi3*|R={NrgN%TE9ZgSN!$Gan zF=OK3?_*Z}I>%bK6*;i-IXZ6-#Wg0;?b)Pm?b_>w#bj@$QSX%*%RIrvX6Ib9aABMH z+G%xSNX<YwUZO>hVUN2Vo2+AVxLp8XVKei?-LKh|@zGP7Mbru@=pMx(yj*p~l^!?} zP-;mwPO`VnHeDuj7QbhmE{E;2I)~<4$W^52U#VF9RIjs@@btVL^G}P!!v`Dp3_zK6 z&KKz%c;Ndjn26h?>(9alqgGZT@u|mo+YQ*koMf0A>9u_k>b`z)%q3;IsmVV~_^c=` zch+DtFQoC+v;^?@sq$*a`rbH8(_{az+7;-G8^FY+QUsr9o7O!$kqmqOJicl_BRYFg zD$C8HfPpHAh=2$m#IX42555Iy2b#V~#H=aUXnQ+;vf36isHu#LPb%#-JvLxAnyVHc zRX8Th8(v0OL`g+i$HkkTnK7#E>o%fN;y8IvN?!#1B=i0~RKa?HlYau=U+^-4*P`)f zjJ9tuYNuiH>-S9kN%;wit^k#xAOz@OTkxzpZ*RGMvcxSJ7RUJb7pk?b{=tDwcL%hF zClhP46!?TD#$u!ratZGHSGGOh6disRgD^9fOJR_K7unt0I}j%@T=EM+?q!wEPl7tM z_<MQ5COu2b{?SqB=P{!k$)sE7(UET!@cE^My72HPZSSn7Pqyi_byqL!GlvVeCmJN& zvB@SCR7t0bs1ds$1YKWW3w<$?jGhueizVdFxKK9r^%9vnMoCLcK}|nfT7wbUIi=b! z6IAD9)(f5jmVX`cL;c!ELs#353hTqPvS;MzB%kP2J#FMP?#I`DRCoKHRLJ27t!>`i z*@C|0r;OarRbv?$fx7Kq4L;tBcP6VeTZoXGR6veN>U&-wLMc$)mL3u|=}XemmfmU7 ziBLM_-dA`?dgN#ZkK@VC7cgpjwfzVi%h>Pt`9iHPeO-y-{n?VMr>KH-J!?=d;~t!I zN5}HbHd04OZe=A)mh6vO(@wji-8H}r-`v_de~1nd%1VMV8NZ+a!lUkEd}l71i^J7Q ztUMQu0FaCj@H|`IXD~M~NY~Ozxc=&sT<bn`&%nW=z9F$9B0c?ULw_M)1fmFkSzNH8 zp*wxzytM1I96pdJr^n)=gR8umJ8K?jJN^d3mwG&W($(MVezJP8chku>1~t7CGp49% zH8IPEBt~*p18`CT7wnf^e5#L!kqSp0=UegbZkUf^mZ5i=tz_cFyNZdWdZQfNd$+zu z{gmx=Byk-0je(HZBc}QQ5}Ax<Er^KaREogEkOW}0mBPx}AIAgfrlaBz;HIQ}#}`KW z{fNjCy6gP@Q9yu(wA&_05oQ`kh!p+~nuB`i8Cg9H0P^eMS0&Af!Fu)2pNDJ3bCu4I zYx3g=-UpE2JpkSx(8>%O{hM>BsRvd70IH|NE&1`|j{$@-tFM$Z*Vym0f_7(^Dqt?k zTCP;`&j~nH9-TP%oIe9IU}o8m^60Xv3h|mJ5AK8MIi1#eT;=Vx%;PG*lc$O6mhE|D z-cI(-6uJfKY=%7;&-rVeT#g5*-*Z7VHTlx&8)yRuUL0v<mYMHAqqDx|FeVNb+o&ij zoeB(i0hL4xFOGRJI2p-xoIyAL`CCts@8_$C$Vhww7*G6M1%%fP%<_UrmkP^C@20B4 z$gl{L;l2#7eJjjI`L8p%&c=P$WROb^2iggQ4m&6PLK)uriFEUEL0G4O0ReB)^k|Sn zzexD^_&vaQu|FFRsC#B>Te5mY^(27^e`T-o;Bg|kcA4!%#{?dCf4Mb=B*DOt9S^|= zFS%_C<4SU8mY{P7*_m?9iB$COu8V|#XhAIWZw7~ulv`mbS)<{;N%2reLo=;heL@&q z6`p~karr!KKW!Z5{b_6|qU|JC{P)oYm}&vLP?zLb(a~Ef3ow;K&JtdmxEQd_vI<ai z&-4WG68OI7k(e$smykjL^p$lz?8SMBa&0pWO&7!ih`&;k@On+c4SHt9@-NNlVM_o& z!r^TBj)FoC{sSQVbzJK8Ah*29IDyf3?Ozt3jXQ1fDU5G)A&MWt>!@2#I%Kx>Anj_n zVq(53{qbZ1wj7+Cp-Gv>1`CbI>^RBUS#^F80rqBdTJe8I>5;!)sJ|K-oBCOc8xEPN zH0wwT{tL$@6_OR>zDf4EFJ{xTvzwvG4qsAW)>anlzVRi5EaZBEpkKQPJ}l~)RP~mf zA<;)5@rR14@-tj9THFUH9HZZ<8d9c|DoQfASfK@CE+ae9r2`@vT*+a&auyyGX`f8z z1I-=_%D#lHwoPNGTG4g&u5A!vf?%=1uNB0goR+g`*{_%=DcQXS*tpfy7D~W&qso3? z*Or-?T{#llQUm?L_xG=g14`|+$(}q3yVx*Q7q(^1V2VXaOHGAtp|k3JY{Hs7`zS35 zvT~))qLpPO=?~6&uMKnEO&o6ioeQArA&QL!b|Yzebd=}c+R`cMCompk49D)3q=B>l z5M8ry3yz`mS~7?@ZTlt1qc@JlYr9(v^OL*2-g!Rr{>hUkAo%vWm_g*CgPfO`$)~m! zK@||lob1e>Htat{Z=}{!*YZomp<!H|>r8wW9UY!$^ob5XIN^ObVnRXn1`%yK#_TpF zlv@gEiHeNenktNh`=M-0ZrE@3E%;>Q%~n_~0Jjf-*YWkruc#`C<MR~lcjh|Ykb&PK zg?UItCFjS1JzTS#sAx=P<>ziQx^l=?Pftrw!#Ji8Ds@C;Vy{qvLJc!3ud2L8!}nH+ zcB%=F&mnpXi`s9>kwDV1WF8@d_Ps6rE!dq%N#xurXB&@Oyw$0{8B@uKf1oU>zp{*l zb?bO2qV6W{;gK2__oUr<fnqD~*T8*dg{Irq;H;FC_f#AMT?$Q9oG8FlB0O`{Ln#cC z?Jbt>#<8grpy<q~*Uu`Mn$jkoq!n=tAEmm88n7XN!yxpglvGaB<31w4t?kz9y_8Oz zqGHMN^X2dOjNM=2u2LDkp+`kWiU-cA1Fdd@HQC%!=cr91ukhmM74KRQbW{LMZu0+M zKoaD4dRkg;9x8DuDJ6MTRdMmm^*3OB`Q|5~;8#-eD<T3973F{uB>GVAqh@5JpPrn) zrF`3HGIw%vGBotw5Z{p0(vq2(8Qqi5+gljWT2IhUGDw6ZCH<4(4?#H|SgcV{P@tpG zJvB;Ma=lx~k{E0Z8DMO1L+(uF#QR3hw@C_uw|P0W1qJn?VR&UN0i~KG4l72yDXS+o z29EJ!r~TFuKI)q?ED}yuoga<18%&?l^Q?E**9ZRKbc~MXIVazi<NVfAsKZW_?ayBy zh)@3c^L+YQj`qRTvS1vWrLOt@Sl#}YsDc?awb>$gF)b5Qs5g1XHoMm_`cR{OG<IU` z%oO)PERuw@YurF|#*<1u)=1ZMw!t`gonf|`&9cOHGzz%WprhOZ&@}qSxjzK2(bCfL zR<mNRYbZNA+vcvhwQ7G3wu87ixCPv<i(K(OCYl$_c0tHGXW-MdGgkvx?3vM%c{`KV zXS?Ih@P+yQ_!^dj)|4@Ut7unfqh90F45yiExdgucKcO3|Ijk6j3=`wy7y4UzA|j|> zcVFs|d&%7Hdl`P6^Rt|}-1~&dKi}Id4#iAOB^%4_Pp9$9F3r1>6WeYS&NJz_CGpup zf%l&GJ~4tP>bB&1XekZYC+@<lnBKJ2!>+6b7hnqu`-R$#ujuJD`l|uSNWW9|=;SDl zOZO$rD<jKzNOb{xbsv!rpwTYz9tzo`JuHmKan(Zg`Ao+=nEPE+RFsi>rRA(q$6#5J zR-NtY=5Vs{K(^W3c;2Lvna=yWNutrLQdq6?4v*VOm-pB21IbOB!>x6xspr*AUeK3X zRh}ys7=(4s`%<%ggu&8TZYno59fGflmGhzolWLd`-hdyhcCACKukS@Hq!R>J+47)r z<rT-`pUOwtrHJsDCYR17M()kKFFku!&r3d;$#^m}Iht0xb@LF%&0)Xek8^M;N5+|A znt1+&J>{$)_LAMPT_`DUiS6-(VAQpCe|0>E_36RMT!Xp9VAA}w0PON)dm#-6(R_Kf zHJ@Qm4W71lCJUCdt>ob{oUri9oSm}*_t~>w!)fA5oqjmC%E2GA@CFl`Hg|X1Zk7#* zh=@bTIXT|(T~8G7VtVZF!M%oRE&YH&9yzzim&Sue6U`@|9Kv`g*-vL81EZn{Ft0y{ zkO~SLBi8RYLS+%}06<X3Gggcghn&CAND~K#>2havwQI6T-|y^%ljrid|5|A1rop|a zwDhPn<Bq5H%5jgWoST%_jgObNF83J(0@;G%jBnNCB>wRCXVB<~9rH%@dx5g(y|_@U zFhIs`R~-_9t#h}UZg82Gk)byJqq&*Fp>lX;CU;pHymB(xPl||a@*=-M?dzAZhSyJ2 z%9^iZ04F_ulOYtI9LvusgMUJer-qu#Jd>6*DLm+D=_Eh?h>na>W-Tmbq23V${;WlJ z^X|wkYv7gn;=HiEy|c;nxY9l=#KSU`rpI}E%p3a=IiCk~yjng<0MIkHCNeN|?g;wh zhZ{F90;Ab%|K9RNMwHYveGZG6{OoKllc7Jk-+zU#l)nlJ4$eDQGBTpNIX%AW`hzS4 zwdH8Wq&%&o+Z!ZWJZIru>J?!#QdC-cXVTT)M6h)desgi`<I^%xkcR=sr4Gt!*&fiU z^U}GNaCxv1r6M5E7@j3FTW=U2nUPTuNr?()_qs#5)G%H9k*j!u1a6(m!6Z+ge)O`m z$Tw$Z{DT7!MBZ-5+ncC@*{zb#OZ$nn4ywwE{GhPI4);=DGkF*t71e<pIb5OMvbK}5 zQ(j5pvOjED^J4#gYd>FEhm%x14_rR<sRkM8=$5fPj`u{+iQlraj;iZ)3*8I6umjY- zG^*Ra*-pXtE;GBnb6K-sUj@5;;=GvbnKbxC$n`p=jNSxZD9heDRI>c5^&ut}R>({K ziBjb{xx_l>onhdJ)frAD%jJ|`n~6Pj;X!^Mm3v7;R=HwXT3r1538#R-?;hK)K3prg zIm#a0Q&ZV-wk5~j<hWqdySB1YrMqI}_EOLmG-=XvGF4r2WUf}Z+K-HmN(2$dN1V{6 zK@u$%iZI$J+kh3~+s0L+z9@ps+k4H)QEh`w>FKKt`&m9Pg^w{AHMFP-Xso!vSfM_q zTHd%y&;v77_6Gv{(G%d`VjyJ02itZ!8jJNt1q!ms%1es=ewnLNM5_}(mw7A$$-Yup z7z<zY&e#Jd0UsJVy6?9tZX1rcxcZsbd$-CVBt%*QR+LO7%?;l<BMgec=SKyfpWUvl zc(Y4kpEF67N#|3Om8_!f@J!Rh{;XGVoFY0Faq(^_CAr{bl?m8A9w;_kVHZ2wgam{v zlvqlu7)4q6Ivq#ax$hAX6X=>73TI$c4nDklMM7_XR#%pu&IY!zT|%MvvS0DPIiBfv zZ)y1eu-W7Sc62t1%q2i%25Kar;*XhCPGF{M)biyEm)FwBX32{C>2`@}E05IDI3^J> zu{brl^G$;>uze&PNcP;nF+1)!t*qpjt=!+8tC0Bo`6&c->f#Zjm>Ak6iSo2^*Xx$o zGOqf_+zw@><??}mAkdPgId$<T6t%fQ7^1A~XlM75!=bAiR{{vQREsX?Sy}VqmZ;@k zIPVYib2s%V{fwTR7~!e*8U&Lk1_s8;^2+IngCK96gnY7~`<|&uim{oVsAJ$1*TCbR zpF;<Y{B@;{fkOw6Q29x(Q%Iqr@DMM{8A%OnOEMJ#Bl6zB%tp_9XO${Onc{yp@K6~v z36O&dh|Dv-V{z_U^d_0SQ-+xh_V<&rTIs2)U;b*nie^+B8*BFsBN%_in83>qBi@K! zF&emBE3<DKkVr8#v$INgN~qc`rqWGId!nkUnssTbudh$v7!ejH<#j5ET=PxDxmI{O zhxWC$HqIOpotm18+=r_Qrsw2z%R{IT(?Ev-=T$E^k%QIOYmdS?lI!|^TwxRe#lql) zD+^3A@W-Pv$3UP30CZ3u*Tke>zrw-@p5p0&nj6Zs2JoIq-l;m>9BJ<HIUYCBH{B!u zLt6@nc*P}^#buQSftgFchPgE64=Aaqu!vc}3i>8bh4IQ9vAqoe*0Nb$#l^*7iBmGz zK*-aY-C7?9VPf4}3qZZ}pYD1*Aa$o6lA_-e5CHZf^{!>P9ftev1f-;p!wjT=0LbbD zlkl=Cw+=k?WCIK9BjuV*x#a0Q=cdw9slEEB$o8Cy_!t%E(xMR<99S9ypmgpX7DiL3 zH(AjF0RcfIp4Vl8toh6h8XABVr(j>+udJx_I6c#{v5Cn*3n2Jo-5YY_pu)4197sQv zY6_f!KAL>XDbWSV%w(Kfhjn!c>2N(FRIDjr8CrL`iBCr6c{x^6qAxyafOkePPrK%; zEP&UBg?R!b)T_C-OESA2ji?hUQAS3YgUL<#=cEoR9SjT%1x}WE_0=`Tp?fE^I`s~* zjrUxyj13F~T#w3)i^%Zz9ojH>$<K#B^I8dk5^K9?`+{53Y{{{8V>H<1Aa1YG5HBm( z1m}BhhF7S8+J?(z^O5rlo}&3mEeW7FT6o5!Q{%R=$A5Xhu+bvwS1h;V$fgQIoOZoi zAVS0ugU$`WQcKI0<}AM5D$T!U;~VLFAjae!ot!LBg2ON1asGt!amI>_Dq)tSz677^ z*=t^2zolz~nBt6@?$cSMY!KEa{j^ZBedg8P4K-BKFy-ECnKS%Pb1NG=o3(aRi>kmz zd)2Y6lU-^PA(Phc9v=8lV6a^TueThnRc3E;2~8YC>Ryf|13$y{+sh)}D$N=<M8C%V z<CRXkSuW+di|m{nY*Ln(B&*rRaOb(E2}>Fp8Uui2rUO4?oa`v)kgwJT{o9e{I%%W? zi7<fk&GYwXMhwuD3c9anrlpnHw({)#ga%A`ErJUVpWEtB36vS%U0()s!uCVR*i$WM zIffO7<&$d^ZLH^O*M=y*<|bPoX9k0+`j*8?0$Ojaqg7UFzNj(&F~*bEsi|1KMd<d$ zRotGJsi5{)UHt+TYrI6CdP?QD%*CnC$>h%X4ueKj8SLcr^b)xvP3r3Ey2ELaiVZgR zXA`|+#)Attb6fT9ou<DW504^M@8*PSTv=5Kqp2bXA{t3&E7sY1{?_DUF;uC8h&pWc zu=JcRW(p`!1#aB(8VbfC&Y|3_)T~1a3_2xd@Y}CI1On`%dF;>l;CWz56&y@xb~;9Q zWRKO_wX+a6NLM9^pyO;WG~|Ks1L7I@he5;H#N2#1Z@iC?H+jGHkM~V-lZWfs?u92R zIu0?Hkeb>SSbEDTf{EGndRG1Cn(6jDx{eH`Jv?BXmJ7sWWWzO(PGG}JQe`FRac*)| z*)O+-Wt!^)CYdi!=ST>ESgFC?X*hZr7-Vk+{zT+}k_nnW+VMt?ic_>EqX_C(X~KcN zM9yS7-MZU_)`+U0WC27L+%r)+D>s%nWxu^JaVAl~+3+%=1X}f;l{xI^&(HLfX1OP@ zToWU+HX&4}>s8vu+^o7Qd$;0wQl4_-ukK<embGBnZA>zD9hpt_J<fZwr&)do!tF3% zte2CQqcnWdvPQz8La;0CG!X?T=xM=rA_RDCHR+)&xH?PWVjHM6%?+ux`V!8FnG4{# zU1bI5ci-cyD$xO6-jx>WIxxsX0w)2ucks@g()+MA-~jv-MN(84stWlV+(b{(XI>*? zHqFg@Rwa{3e_<02Ch#!tPhNl#pZO4`%Wl5zwtC=wmR$Fkme5JyVC88~&wybHu=tc> z`KM59&gB8M(CdF_)KfMlafiaLtgJQ9R2O}p;ggV1ijPmdT))-5$5;~VB;C<gf(L1) zuSn#boH!Dx-!alMv#_jkAijRzH@6f7KdfP9W`|5)Gs!-}qtnygzMj&`(){jbGPajG z<-S9IKy{ZrpZWt3zjA6i)Ye><eN+DJg%f#u!iMsv3h=Y9ro&keNJl3p(;h<T!Lo{p z0>x<lkDA7R13v$AUGD$#V|v6o^m%oC?E*}<eqNt#JU#Cn`+^n?kb^VhvN1AJ0bxEW z{1-^70HeP>$fXCy6AXG%7DfRIZpz4e=Mn%ETX(!9kd1Tf`~10SnN(WH;?INndXIGs z5ZHK};OGgV93nh6<7xQ$(?%#v>z+Kq%z1yA#gH`t4EgA9#8<8|F&;fx(&|#T$UwQ{ z2I`f!JUmvwr;V^^j?aB*1{C~v=j_j=JB&VjXdTpPRBZK5)6<*RabZ3nt-0HrUNL5> zmX}X%ii?ZW-uekvaMz|kC{ohB6IOG!OGj8Ucf~jX!+nHqCv8B)#OXK(JAcd0e<Lly zL_<^Waf6L||A+O42wW66_^I$1C@LNTUx^DhyQ+k3t!lfn<&eOT2iPyUE8K24)V~W( zS_TG7FT&W_8DOJl4M3D4ov&F(Nx3%qtR>pB^*-BE6S~o2P|ai1I>&GXy?u8qUTT0i zT=MJQ6&nSu8d#g0l%6Rv+p)0F(MipfWRFq2es?tO50cOd6gsLB(jPx|b@cd<%|+`i zFH1{HojO!ZXPqR<+W(6DC1ATA78A1>M7#3hsloI#_u*qn^h+L~EIuihn8dCx8gZtu zbOEx7UC7MG&1yMWG1skJEH;Da5KB;#f0rbvA-bwF{*umjeQkqeb8ATMD*^(A;yoiu zE6AW=U}!(nb(Y%BrJF0slqGIOWG>~PSes;1Q_^;yb@%ni$;dD=(k_(R-xZZ*#YOBd zKa#asswWx`dgSwiBlO@04HyILNethvp2MSBsp)xnX=&SqbW}w}-}14{2)_FC>ElOr zsemhGv3hOy(Z{K>=65Nw5lUB=3|`inWzbLOqed1cDH4W`0sEkYD?onVWNva{pV!$$ zgx~Z9Ev<$6D;F?}(I_e^Iy#O=j5*8{wYPON!8S(oO;<P=w4BMgGV==XiOEcj^|?VY zkJt`qcDQS5fWQgtUCW)*1fZWchbj%h7GeAL6se4{E|V1@KaLi#BG%rHH}9FmbBo}G zXYDZ=%f^31?d|SSz)w#pR?wDnYKhTx7_eQN=?AG_ypzZXyq_~@z$N^DO9VZZr<T?; zJE#XV)0q@6&*GRjkW>TMpk&_sdx^i+!DMgdJk4vU5C-HIzxP{`=6OcmV_yF>@hjHt zwF1??08J1zVXXJ1SONVbRHowplt1!NrDux@2b4aG>?7f2PqmHC*Az6o{y0;JO~zl4 z@~S8`-(mASR&A78X=@4C8OqP|0ox?Njn}R;VH|%}Z4X?D<4$)*K<eE;C?JRHHR^pD z9xAJ=y|3kik}^_?5arAp9At)6)l0^i>)Qoqs0<XUtbDP5BatOfL`a067#oX^kDHZ~ zGe9y22hOmQwcPHXB|F2*Ye2sClUkhZ!{YMyzzZ5)>$~F@ngELnO%_B<WUK3%>2;wz zdId_^zGpgkG1+ez_`e?2X83mJaqjE5HEQ2p@jZb%Fvgz=;K6Bq1~tmVYSZ+$=-F-C z!*om|fQQskCClpR$PO0b;YMFVUqq){Zq`wwy1EL7B}>)^ad;fm&*gMI@oNJjTNicH z9T|<*3+AevlYuXP+zzHJ2hW<`wzbpZtPx)C%sl4#nFir0h^reCCXN)OtsecOFM$oL zyg~!z)2%fhAjx}jn<|U%W$Wx0l3#xf`YU|g>y044ny<O5hWJfL$R%Bwue}CIYbh<D zL^4?(+gu*kzzg~-Hys~sr=K{KegE#Y-A%IerpG{9)*!inQ&vMy!$Wz_d~K;t6sS1t zybX48;2p^*+5U{kWNI$ST}dnfk-4AIA$K-ryVylL!|@VmDcy%lD}*U@fm7`6`*CY- zT3XX`UOQW-6f16SHJl<&P|Nh(KOU~gvDcSyU!WKrWpxp0$_;o9Yd%DGrpI8-l^B|& z9Nz^-IBqv*H(_BTDU0v72mkd9DBrLiFGt3IX!!ulr@a^x<#m3JjSfr%SiZo0PRzWL zbvPy*>3BJlM)yHnoT{NGL|QCA*T?;n%Ui_jX)BIKYU;bY8PPpY1#N9c{x>4R+6$m& zKuV(Uxary>^(m@PzJ8qwu%KdQWlv3YPxGoID5P40yPo_mBMcvQHV{&vK||(NQl5t# zazxg6?s%H1i`#sB(K^j!NJO+LCegXJv0=T?7)tu8DdjyacVq}UD9?+_(;lkId;rLH zK$ZBb-#b&4xj<hhe<33o;!FrtY=8FK+kAS?m;Z5JM6};jNb!&C-bt%}RF?8nAb&Nt zsC^S9QgMt!j*2AX6K2m}jli>K4bNStfBRNOM|mzwFIBJQ!=2flp}D2)-7q9qcF0uR z)|PoD4E3uBs>lc4a`W#08o#q0iG<@))7ZJ8ATD89JGH*_%sAIpSC0z6GEG(n@@=Of z&!6tPYPyQL7t)l_UgN7FS4k<;`cXpsn>!<+j7KE&$1BE+?{vyypCCr5f`3JY=?Og@ z+URm;P4#KH|M>Ah6sw)d-91?C6$}$N|FwUW7>v3Rh<1KgIS!&Q*Vi|Wrn~3B@cN#2 z^9d#AF?D&^rR}hszCsgOIls--ISezu`YYXEiDvhOafDu@|Bu66jZI84h&C0M<JnQ< zjx#3K3Hs?yH}v=Nk5@L?5pv1%VE*noNGJo^c|G1-xLs0{ha+&y1#z^wX|8+Y5qAEi zo*TawqD?f3WJa`8A;-u1OMd=K9tt5HOHArcjmG0cpuJX6Q8GYz@N|#v&BtuJ1LiOG zb!>F+>krS^*_q3$Dvl1Xx;ohRk>pd&*(%Ro;7O4J11X@WQSwW~GFEMm*q5CAN7ks? zuemwrFsst9`Ys7M%QQL#NqF_tp`v2p!lSFNFLm$y+gmq<im;GT>|`!_N=ixNa0$$< zPX4~Up5R#|kgQgD9M%&F29J)6eO{DU``?<(QO*T{^48z{@-7$sr(kYyM(}^Q!VM4x z@g>WeYB{9zZr8vRS!%as?e#8>71Xi!)(Q@^QlCGEedTlC>yGd`1^yUeP7-sfd2qXy z*RQu``==C=Y15wGZK0bupeP(Nh8JkCIl3=(FH9Xa>vMwkWqVfrMqP{iervdwg}J`u zeDH35&bMZUYt%<Cp>t^6^0?xb3pJsQqM%RX;pu)(R%?w=mg{Io6O)cKbqZ}&$=3?& z(PgBem+RGePA*M+?2G@!+gC?r*>-!{7zhT^At2HqEsY@E-61J0-5@H`AT82JcXvt( z0@B^xoewb^-|szV=6v6*b<WJ0`OCF@g8RASy7vCnmL?c+x^>f&`c&tB%#N9^adK{| zY=^iN%q+9r;9Q$U(2-F4uV}1~maI*bb6&r%VKvyi=fSA6p{<UW-PczHL)h-#y9XHN zZ_k(J-FF>W%fa*i<|9I$`{85ak9;j%Lc$`zBm*3VLNFF_xWTtI8}GJ%=Z-L_z#n7G zensq}0om$M=sIGxRR)?_ysMY$&tT=rSaoJIh!h@H85t7uzn>BJJeg(WI7_28yC{na z3?2tsvZVe3)4S}=$DJejUAz6Grys5fI;oyyl|MOLDUC+&P=l&0C@d!ATlheVULorI z&)AyQ1ALB$kI?C0bKCe*REa~McUZv9(j(AhmiPptq3y>n?x&xs8zW12PE_f}uHU}< z4?X9~jlX1jOt@SW%=rt~6^ZF#1cbQ9A-ZAck7d7Sn;j)k%JVf4!-1BwSm?C5`4G{O z&lg7Y&}vp2_LM!8D@ipUj{lN}SBYvmniuTuDBU3-6SAJ_7vd>XP*AvU1D;a9(YTfG zu&S`BVEbH*?dHo^|8P7w)njMQ(QfN{%WdPdyjy<}ffa)J;D*hZJw;e-P~_LIVo1AV zoOdc!;}fr#PXz>ce@~6ejz=6F%Ql@Yrbpki0S|~obhU1LYA>+lx3J%v=bz<i&pr|n z5gihF9A{J#4YOAr`+xHU9;*6fL!jBv_goIPkYArI)7<`U7}mtM;?bonFgRek2?&s! zT_E>jScRR|!GYEBMO<%Vd3OM(C#Z;*C*@^iL`DZXupT_vyPuknBZ69UUI4i!h|U%8 zEMQ|TWsg?*)=*(}GIdC+v(4ntb2IYaba31{NHG017Fw(F(@C+#NGfu7s=F6~5+fz` zg_gTjY(o<kC+EpDWVwFPeiK&f*p^nQxLgDIMS~?u)O0-82e&usa-AYjsH0fKB_u$| zsA!y?m5|e1hpN;0>t}lUvNcL-URs*d;sF@wkn0qQ2x)5G><1^!^%WKE^%NAiyEyHf zO+1F!0@Qju3PM^^QB>gH<Rs;#rDx96HQwiXb<P?ZrFDOVac#7o|J3n}U<?qz4E2po zqN{SRqmWFW$yfWVBW1XQ=JeVqYM;tJ4yv<_(%`<Jnpja@+SjXT*G%z?g5>^%j1m;L z1ax%WM1M&nz2vJA4gaK(1lJays;#ggAj2M@Hrh6-WzRq3k^eUhsOzkIE;u~TTZM$t zpG3@o>*)$iA;&<A2n9-8f$7TstjmlWx1Y)cl2kE6<nB*HEM%UWKhv=?+V1wFeq2YQ z@c8=&h%@6KRe*;yEHCd%MuE1B2;22KVsa93b$)5^rJdC0o$>Gw*~inszuEoo;P1om zjT&JQulAoJf-TP%ri+L};|%<K#6u&(g1$V+{kb*d`aW|2N7D5b;dO3~HRt$&8f*BJ z5E&(Vgu4nkh|_;{_V+3n)Tn{PRmA9XTAG(vUf$QQX=Ru;-Y>Rv;;G?smZhbYB^4FH z42(_&SHq@jqg|-0tEL=@L_c`{mi_j-%)SXDbu~0$zNCDeZ0>AiMOU3B?zr9B3rs*8 zT)TJyYTxD2fV0lbb|y~H{PJiT&%*6P+t|E2Ti=Ofv~Fz5aVc_UKRS)jecKzMeZ>d~ zt|+$4rijk0`^b+@q^a5uQ<%8b^M7Ljm!jt@Pp|wJy5avOW%M6U-|Z{^HUZ?H?$UoD zuikHKX<?yck6I583!-CW42_7;!A4f$0D@Un73b1uS|bY{#Vn0V8lauk#IhvgCLT8j zCdUFT4QQ6*&YZG^aDG6*!CpEyD?9skz!Pk2X4B>_#vy=|_g6<fPfW&&_|?Tt`_djF z_hH;Pblh**2^01fW~*T9iwTR|-#9}Y*LFm)>ZmY%KRR|Pvp#MEa!}!9kFu?+i{Pa_ zrp-~66EzJ@Cmc$h9VsCpFryYY1KI0+>3oKUhJ$9+kkT<)Vpwf6ilV7mD~iztR;y?Z z2gf0=ZrV6*c^G#bV87F6=(DyyTD&?|%zpE5%j-7F;UY#?+?#m(I}B2_w~&|YPUh$w z$I4tC+EebkWsg1pWVvJOs=GU_hP~YW9;M^yTzaOl?27%#o^nUaH^#HUpvU@_1ki$I zS?AeA*@4-heRSKVJ7*F0<`RU*;_7`>I|j`(TOBaO+zyYaJl_~g*IDeuTgGMA+xsqv zk~ewo{_0hG1Z{E~-hL8MMM_GuCn|x1pqOOW3l^4$h=|@x<`q#epBYZ2@%k|wXu{07 z=F0B`yfgp6z`_3h1h?yox$4|@8`o@>R#&^zDS@tC9Wbx5+k9m$_6yi);9Q?zVKpJF zm%h|9o_s_?g~>nUL{vS%!=Bi+N;n+Gy6}0T)Yxwq<mTqq)SNfonbp<P8;&U19O4)J z1ueewJu5`#c<gxP&!24*6)vSZEhu9C*=jqPK?z*DaTH`!9F9BAASk|c`=))Xb*oz& z=GLsVogLZ7fqe1rf`I@?CZ1Q?n#`gA$&2;m$@<b#9lLg+zId)?ZDee0PFk9f;cIpA z{^iN*Je)l5F1par&^AWhzR*|r`!jJS_es#X0IR>CpJKN$5yhc5vMk#I6ws@d0v5B0 z6Nd$Bb-Wk>|22oW9wj6cd@ienwVasIbf=CHn>W*MWS>hWZg4ss>gnr)=ToZe!nB@< zn!1DVBa*ZmSZ`Ta4t@Nspj;u~az1Sdo&;UDD<JOUnwiV*qtc(SZP_0+jw7n$LX&h; zQL;htn1S8X(shwO+Fo_)JosFKI;!%Mhv4&P&nqk5sq~fC?iDby$V)3ErjOSgmZ>h< z0!}h$J}xRO&hUG1eXug>hNMnx+R_ksVgR1XQYwsGXg#oYo8BLr4GT{EF?F?ie*PsA zHLzc(_~lKc&wAc8gSnD|`jH$iB^~+kLX77fZ{d{Y&y1QtX}6|<^|fpv$A7sWhS)+6 zug+eaZ06W5InD`ESJ;06!)TD$>K{GCk2PQ71Tk}8iaY~6$y40m>p`qVMg=8ISJ)WG zayYO#H!c;XN`8%svOtR8>@DAQ#bL4a^YcUA^tyg>_`T|Ur9ac-o@)%3)xkk_R3JWk z4!{G-9_}X}Qt0>Be|U(>(Gt*GfAWuM@D52u#Tz0eA>ltur>Oy?-I!7o=EmZWS4x+U zkDrwTCG72;?^h(YtDl3meH`1|)Re8fJDB3XDlRU*lyAD4(r-Kf^mZY`$<k)6^-m&z z!Ou<(%B_zn>^9`ubIauR%!dXBRD^}o!SV_SOV`*~<OrM9dB$R9DNJZK>HncOzMu}s zMi|P$#Nq5YF)0iWW!DzE*o`ok(hd&_;<8=gK&$|c0__Js-mCgIgbCB3pB4XuGI%~F z)W=5#B)R;rKOqj6&CImLTtHy`U1wJRoUtY^Z)r%llQBeAMlokx+t`%u&94_C6QGt% zFB5vwBGT2WR$+7<&q*xiC0oJi)_Zbp3H#;!&v+i4I0fR?*FN%fsg;f7Dh`s*3ZA&$ zF0(vC*>_$(UT9qQ1ugd4Xy$5v)Zs+Ut{yy4=d!`U!EzPY9QN^vA9&*?s+;}sT-J`j zq{Pa~%3yG&ZD=U`Fma|VhRx>4VFCH>lZMa86J-vf+S)zY>~=J2RgF9@U|%;k!8v3| zl~k*>H3XT#EU83iYirUum_5<Z<}Q^R&P^F~I;2%jn<3x6shlNEAdVm+VA5^tUHicL zUi?XQQBhIEBISYn$>34?cS%|hn#BVpS?#ijkM~3_x-WawuF`trH6BnlKt0sBAW$Z+ zfaSPFQnR(aJ@@5CO#^9qpLigk6H;^4Hk;ib^X-$9Uo*+VT{FSwc9LHHp;_f<wN%HI z^87RKzG#)3T=u-A<8RG*msvT8+J>YqfLLPuI*4PA<P;Su=kxngJ^bj=4B7__@GP>E z8<LY#ic&neElrd9K+**;n9s;d)a2x^_&4&rgjV?EcR|1iCf?Wg1bh#dyxHZ^j?mL* zl)z$|BI4kyFAiGK&!`)V2R}lL7Q<@rM0TyMLFWv^IvETW=D0X3rMdt=3INBT#6ziK zS5TvuZgO7w?$2ch6cnl=qF3G;V_fWdV4|UMX#M`Z(D5x>r93O6o0y0wy@JL0==bm6 zc@9=?$LoXTgE^DB@ip=3zucO8erVU9YNlto&MoDG&?vRF#(ueAW4w}$v0!s3;Vhv+ z(AU>DGwvFR)6JVVGt#XPQl<IZsVU?uD=Q|R3GT0En>!af)qnT>e%qahg@?Z-?n$(k zJz6Rm$BF=L)(}@lMuuCCO8uxxN>R}>2Fgl5^2{>KkY<#{5{uL!Y7+8<qb{l<Fq0)x z)b24eGrt0OczvLIKuky^1%(tzwQcnWFK@PLg+`Sn10_4cztp@|V>~H28Sp2*o14&C zWw@~zudEHVhNpi^X-+-Nc}gqjiHp4WOUv0(L<B&bQB6t3sEL5!MBaTJ{+7mJrN~0g z{(d>Y#?ve{mvL2@?Gkv;cbKA<KfU+x5N;{SwzetK)}EzNuXLF`_$V17|CXop{011j zdw*f|>i>%FPq6_mz8CI9NFX@dX{TCoJ8tX8V?UoLaNygw^Ux^Ko)4bHkl}ss5dG(O zM-A7S@RVEE_ixspaX+Ub3Jwbc1$_X1DzT#3>h3!G#W~~qymyAm%NL%D4n|s9Jj3HX zKcbzMaAAsVPKtsBi0BUD8?FNvyFJ@1=iJ|MRvr_B7lWh~_nd@;oyqKECt1)Jy`vn4 z$9juL$^9&IhP%$na(7AS{rxi!e*U}iV`*Trr=sTM(+upDiCfuQ)AGl|!Q-})eyvny z<;k3o@Nm#<A|m8F8+$6b^q|E0(yL0ZMf}{7b+)a;fnquATq8P)63x^GZ|GaWp3*Fr zJ)^W|+tbT1ywM}mX{0D4m-N0fdjJCs-O>}6#pt%pGm=!bYKuc?mP9emi9qvev~&e5 z8nEEUzkympwbpfgOmh(f9bG`M<&;rR23Fucx8`5Nd!@#Q8e@cqYZE{1!p|qFkuoSU zBqRd*s<qCmSa)3!Thp_X^B5zq&Uj=aFOWUflHI7>b{Bvojb0@ORJ#1Wbf;z+8s3u* z+o-501Olm%^qHLV$gkq`!ouD*?m@JO(E=N%Kn<7WrSh4olf4ZrboBG>?{1(uqpWd+ z$^wPs4BY!sEan27k+iAF={X5GCtG(?y*VJI4nu>+pR#r?T4X_TTr)h(LgWYrM!uc- zh4pLf*UR*(JsM)-^(8I4#dBgL_D+inaKvPukBB^mXa<vw5hc*+p=jBsK8Gl-?r6lU z!jp1FTj%L*A5QP>&c%kAc{e(yskyg{`_1g6q!ASaoGuc+@YtK`y%89$j(`7nn1Jit znywCb*TA@ivAeS3@*WeuUSx}9$@$;UW(~TIFRS7sbEbmQTF2vSPX;+PIHKrWC`K9B z=tDQ9^G!`tCGZAvRl)FT)Nk4Eqj$J5R#Z}=4bT6K#w4@Jm>BBHm(VZqIs-a_sQDi2 z9`_a{zrGx9XkZ{FhN{Wz`mH@tF%j*T)JDHRVN!XxG(I%!uo<iFEQv}mcGz1K*(v@_ zT6yI6?{|~2weoUu6rF&f7u#fp3kV22*}Nv)eGGEBJ=CwIpd(NRrnW@;n4q|fd$meg zcF_D75m|}EzcbBuGOVO5$2QdZ=6cD-SS@IOeWpSKk@l85LkFwY*R$k9S=alhJH#8C z8i$|L*)oSS)@v@%%F0WF?Hrd|AM?rD@$<Ll#?@Pa#Rtp^wk6?D3<NE>VQBVGpM3y+ z<uV9VHSjL7Am>1kzlBC4KL7=D&${@M>);FvLmMqN+#a2g_j}NrEsMzWB3l_wFm3lA zJ%A_-(wL{Moj)TvW30^Mx*L$zC)});+xD#~f;y@FaM|8NIsF!sikj+cMLMHp9Sg}n zG|E?B{?RDM9E+rR;b3CEH8T1!Ver|vpcn+RoSd8`4s0-?v&sULhxy?t`tq_Vz?%^4 zLE$&ttGfS`?YV@Y>TY2<H&}5sBmyXw#O_0CMPmzTMtZuGbFTG!uhzGY@+XtVfr>C* z!$_qf<ump!$mnFhYo%X<Fag!}JTR>!!Cf*(H$f#N{i51DMq3Xuw;&wB4F4(zh) z5DG#=!7QzzP%%&%4Vfz=h?V*?RWcfy6pC~Is8T*&KH!NjJDe-0g3x2%7T2q>Y9b*? z?TV%(BO59(<owgwUAy<>aOAO<57=?9@LYHIal-q{h5g^xYp$y5ikt=;t4=mKdv%HE zL(Mq)<w-<$kYZe)wUX6!P;k~zydfl%rjyp=XEhYQb898&FGDND)CNb!WTs|o>`LcU zyKo$@&HR;9w9<sRc=d4<GWx@2$*k+nE<Se)+U{C15deM$r$goSjSGBZ;jiu|k0N5} zmw#;vtzWsazq}OXYp(5rb>-+*4@1H3&OOXDT8LdRXlc-ae3d?0iil`ur?9K<&51b~ zJfRq6-q>HX$U}m2v`_PbBpP1093c-c{N4ZlmP<J=Vlr)m(^k!(NT&-w>j4IaPJ9g{ z*TgNG3Qm>4BfSs9&)<I1(S+Z4pZ})vt(AK)@}XNnVU%?W6<%KHe!2L{-)0>Xjw%#Q zH~Cp3RvInjWv%zmaBVzer#&oM>|mH+ahbV>S=V&>=x;0lRtjdudAX>iAykVcy{xR3 zD|Lz_6huU@5tGppKR?h@6ot?Ku}~M^+qk>~xSvDj&=2*?D)7pc8(02C%l_w;|4ef9 zC#*EV+0;(p;-<OA^K1?wW(Gz|ulQGbN=DDGMt%+D(COS1yRWOS?@;ZkxGW03OHsuf z%_{A2U`c@=m~-0y5f(LSi#Np;!)83~G#O}e={|(ejBM*~Q0Rg7GQiu{Aa26#$YeMU zr#zQNxtxoL{#$y!$Rq;DDZ4eUM(6weS(gE1??2zEKdXF#`N;O7yVvIoiX5oDnV~?J z7j=tzp+7Y7u?3zUd!)R4`a@J?{mSn;a0eAaUd0h($CMOgtB4rDq;oOaW0%`naVN(} zpZ-eonUCZmB>c&v8DaP$LxuJ7%-l!+*2ajI3vQJy=a7iF$;Nc)D20wAjeP{>)>M9F znwJm&*I@x02*SFCRdGv^Z;|QJwHoT<8usdy4lJCUR!!eJLYn=5_sA`x95=2fS5#zp zl;5$Tq$Ia}JGyh4jMJOyH;<yFuN@r{B`EJ;N`3zu?YzAvx7$H-{8S!T&0fgo6)^6i zA}^06+_yox@fj0m#R+i)uF}LZb8VAW6qs0j(YH=gExs}dmO4Z;AalRO{L<K8kTJ58 zw*0IQVDBg>DDadVOYg}|Pe{o~l(9(J3-&2^6vNUAt1nxgWO8OVqIwbpKmgjZ<A|zM z8FX=Gs<5v8sM@l}dyKO<)LH_A-NR^XmF#tSwF@$RA6L(v_q6wng@(JM?;ljRKrVpJ z<+-Z43ejAu@7})jFgXZ{iD@|ar+$RY4+8A4o)m(^(PtJ|!5YMraFbz0?G~HeHnu<4 z|7>bxw6ak6%hi~e$gx=m?4m8R!dR-@?ZdNFvCf&k&JI8F0*2`8pX(q%h$J})Zae80 z{$4)Jbo6O6F?7t~3+Go~tzBDPUKtuyu65dMc{gK!Tl@>#1j2R9ZSGQ3kUrsdzH=Yu zw;T_QlD>Qv9mA_7L^kP^dWcvnZ)wbLh+;Bz-tGM8!;oBf71Bdt8@08tO|xd|dD8&9 zx#7Av7I*N(GH_HG%B)2%+&0-)dWPOC^xdJYo{(zHwa(YmO$v-*>k6=3>+@Ko)ufvj zWP&ac)*KMUxKC+J;&a$m+Rr~nc!>(>I%!lp*v<Vu4^0sFzwe2>=7N~0#jcV4S#EPr zkyG9D$&=&>PBz8p6qqNzh7|%{V=^fj{j&!TUiTYva^g7}8JiM<(1HD(fI#@CPcIMC zGcqg{Y?(bQC*EXHrP<<(ai$lUywTTwqrbAhpl<&<)IB!m%NHqm^NzkoFOhv{bU{0! zqWW!kROL97;L-1dYyC;-vorlsa%e0}bV)=k)j=Ytyhj|4Csi;$+~@9&b)D4q>l?lj zul=y-T8CQWd-^fK+FESOs*I(q90^LY!{y=RZ()28?9<!R)+WSay7t-=H;ksF;#)>i zk}mkqvLCbMZ=I|=VgFk7Fa213|8h^-GL26cbNOD8TN8^iTK#6#tc3VE^F~kcD2tg} z1{oz;>vq5o!?5ngpmpHyvR-!lNKE|8PzW@MR2~g5f*ArqjMUUIh@!MKB?*Oa+JI3N z<uSLTP#JbS>ffSJS#Y_YGd}Y;GD;CkcBIgE+d@6rqWj`Aj8=T_?%hOfZ9ZP&q44ee z{5xza-`48bMqnuY&tHpD<T2sy$BWf1O(b%-pGO^QdisapVT-w{RHI**^a&u}f3zMM zk>9^%(2qivyo!{RQolAk>yV5F2KpnT@t&}N`lYGGzdE4HY_j*}ms(*++QDYBzB0N| zMRe&6>|-pcOe-s!xsuwc(boD)g~JV<UlqLj;MAU`py#o@bYs6*^h^G3|?e!A`X zly_xu7%QhuUSYZQKKhfA(IQK|49G(|=;j7Q%}0ivbbC~3y!zrbA72<fCqe+S$cJXp z*(xqc5Uz)hD9#tf^IsinZmNq>kudoi%|#z-$Q@tx_VT(tD!ptJ`T&FApL&8Ha^gZ> z7mRYrzT-pr-P;Tp{GU7kBYKRDZLz-K!U`FEhUAwe?bIk#`nMAPDsqQ6AUX@5+a>5w z9<mG!Ht<dG&YH7DMjS|=rxuy^`%yQ8>bd?vPF7l?t2OK8yLNpVG!MvPdNCj2I#G4@ zzB)P-LzUgmY2%Htsjy^mF=Ns*63uECbF&lj$J{n<$8*EJK95WD84n$2O+md8zO`;b z1%BIit9t?dCWfy|lu`UA8i(E4Kwon018<svnOSV=plZ#Xkr5>@(F@>}J2*&=YtZ*+ zSTk9&lb!YA^1tSXr#dXdI=`dCF9hb>fD$JF#TJ_V#D=I9#Y;?{M?HRK;;A1#*W1JM z@37HzwRfeqZL}s_x7RfN7yi5RZqNHk6qSg3wD5qy$oBk0-K1r}3}}@qD%4jO)Y(er zQK-nt=?)jkolrpNzW|_&GC)T-!^(<k&oW|Ur^mM96v&tr7UZH9nFH+Hwjl(uNc;Ql zPG!q&W#w=AlH@!1kVl0xCWwNQXR~;IQ*_DyHaqLc{iWU*#|mZ(*XeD?iNq(-W*CdV zeo;-_3BY63U2nz%-=@5jQeV1DW?j70!aYSD0AX3oMj70G#>t^}T^7$SGE9`IGGR2# zc#*J_W|C1_41|??mwkO%J^c5X_>+n$1r#^QUySB2#o*Z3SKT1G$mvm(mFa<&KPl;1 zCN?L<a|K0J-_l~XrWVj#-AzwS48u(zdG=g-BWo|&oZ_#N`S6-@iu1I5XlRC!(IdRa zg7R)EtYY`&)cobBB!$EzB!rph=%;e(Rum=fW8lD*F#4++{x;hDqz3JS)4I$4pHgiL z4|phI#xSVzFYBj&5)J;pqDeH|615*+;@IyuePc`5uJ1!o>bX|o<wNlv{DYSflK(#s z=ki|tQ`4`81qPbKt}sdsA#-ovl0j6(>7a<HsHUU6Wn4x^+7ix^sEE*Ie&p8p_Kst* z&frEtPft}<6?j2Vu{gXO&#Rp_<1z;=Jz-=(6*Q}xN(l*Xdi77$6ci46LxllhP2j>| zF_l)7#bGkKafzB#Yn<gf>&a*b2jrmG80hI&J6*Vf7GJ;ft3n5vt1AJGdQHL6p+^|k z8O2>+pIfL{6Ri^(Ij3YqkV(nPIzM&JNv*<Y07o>%KC`e;<J=UNDv2j6Eq&+Sz14BM z`111d?|k30vewkuOZGR$3o{-{#<GbARl8K$##Gv-PT}J}oL)FTojGPe?jr`4lUa+W zcDPW#V0^JlGn&%?-}J0vUb;r+-<g>c@G4yz|K@KVdHAB!DizHQhakn_QBrYO{%qT? za#=X%Xvz;VZ6YKUi>Wki5W&J)2EL})wEtIfKJl(R@B=q*ctC*M>v38R&C1#>uokA$ ze*580oXW`9=V-g$3O~g;6&Dvf=B4W=8Fm{SEUe+-;n%QhBOQu4+&nfC0Lmubi<Xu) zH8)kz=1{L)ky^P*2+Z>Cj-RIfow7-tlDN2)qfzO)F?Mt1_u$}aZ)z!cFl<&?CMpl1 z1Jwr`jSFJW$IoxZh0VHE3;V48qvxR67}`Vh<(_ic#m+chknSTsqu@Dj&**7tYPz_b zc|UIc+16G-YdV?l8}PNMu`xr10tkYEY*qC#`^a=Ga^asY?1Ky!#dTlu5P`7;e+0Y~ zB&q@Hu18B2y07IHC8D>!#DqM?#4K~WsP8LcB;jv*(th!Rj&1=jU%4=4Fn3Z+Qc_V) zE{QQQCuL=BsgCE2_x}e`BVKYd$}^QThB&jvLP9`b0Rk|WUc67wuBtkXvLm?V`N=RX zbANL@JHz(W+G}UayYkS9+vhxnt%#X{ZpV3FfuDc4vGu)1wez~|q=tGrF*z#<2hq1j ztoM)m#=obfwRSca02Wsj;&?Cy4y4NE<w(i_lUT+LSsiwY3dj#gPD*=W&tvYu+9^Rn z@%*5kxb*1LYhu2$`ZFha8B#KxPW38$Z2UKG<6H3R{sS*06{l!E3E_C%*JSOqq{!CS zqH)*K5Ch|aH3X-6Ny&yUE+YVCWn^}y@<+jh-y<UfQvZS%EN|dOJ2w^$r>S(>d?hCK z3-tKIDjEv<1A-Uti9J!hyu82<;V<$@5`P?=uL}Y6@owC0tGOE0DrHlH;At_RtT+af zl!%W=s66z`Kal%!?_tn%bAKk}6C4_1jehBH^4r}7`t-iIl^GnCtiqB4NC8{#uEq%) z9UqTVRaWWQ&iOwlXsqkcPpzn_mEv5lo37(A(9<(#X}0$bjQF#I%{f&9S3JRCUQ?AU zUXg7ma#xW&JrJKOPySv6Jc~_Dq|gaW)*!qzeEdaUx*ZD$Dc!Jvq#7uvkdaY1t)`8j zJxlc?SVj;|we7Q4g#g)RxG<BIlhRWwX~)ms8CkQ{y0kP@7Rl{TOGU+IyTh?BEFr93 zZtI&}-1LdAf#|z782V%^g77(Q2D`gY9Y#JWnoo4Uy1DNF!73L)A+VL>(Is(HKf*(n z>MEV!swbRYBXcKAFrPe@L86v<t8@d88F^{+3?e<zmeLo49xuMVEBoBf(zXZ=TT8?U z8%p6VP1SPk$QEA%)Qxczl)J-~n^*RSYt7e)d*=Se0uC4aSILWI?SRe!ZxcSJ>kk$M zzzSVsSwHeN<q>`aUK7;T)~lT{_b_Pbq%;8u8hwBD41y+Y7xuhY2Wjr(u-TtB{*;?e z`OkAWoOoDH4mH}E$!<1rY$tn(6zn%oz_l@Ix6v*ADj9P94{sJ}MbJcZIxQrnq%7=3 z79QOa5*OvRTXt-E2u7E*&JM1PF}JnZLpm1PIBl9IBZ$2<UQ%?jas^!9oxN<Qz!VAW z?<pDD20HUv2D?YYz9}>T=937S->GC`dNv|mjB_~V1QE>v5DP134Ebh3VPTOBR`lYL zc1Da3p%ucyGKBP&+ElJbGuqH#hKGi}g{&Q=*U$FL9TwkY0)z-kWOu`wz}PZb)@bu| zst$3(2j8xB&{0J*3^Zl3c%rQ77-^>^r%zN0E`lrcg?zlFtA#KfHDQdw(CHw(6~k<F zw3?%=^%cH-S8y*icls~+UA??wlird-Kvd~eQd9jxy1%k1?P^e-m-k|#URPHyEm+B7 z&&#XTz-*(z6BROnqgW0jz?|Z=ej*Og(6_cz1ArmXe_e#NtpLA(06yAh%{PK(6%00f z#E1aA5dt=65T=x!kV_RPN=e0kV=G0q!NI}FAOBZOP9$$}L@b2Zu~?ZJ>6nU>-r(Ti zjH)Pmr<s@*6B8qAfhK&%JNcg5G*`95qI*gBt;6(`&yLQ#+8{5l$=9BJ4AnK-g)$~K z2?Pg9C@6@^5<ewt1dQOQo3C_jY%tx$SOpc$`I3C0KL+x}&=wv2Io@bVPk%QwV7q$k zkf{nCSvoXtkRjvYKl@rzk)44us`HK<6S^v1puhO<?jBtyAiSPGBT-~(fpsv3!^&{L z+$}AGtoteta717p@c8rzlzI(#&7CC`VW@C|v(L^EGFDcFAn^FU5gi@fA{kpz!JM2s z67;==T5U_U3x7OvhrR3Q#Pw~#MET58yF!-Q4uY5B7Yvg5ef3I=Rw}L8B@Tyh6NCGK zlG2wA{J9c>Ib#Ehqju+KhF9K9_Z0M8pmy!{)z!T(s7&@K2h<Uq=@I??eH5L^ie32D z_VLNdOs->?DYxFDKYH|NSb4aLlZmOX*&lmn*rKVaY1ryE6-5Xo1(_VK7_S-!DNCTy z#F}#Xk3=Gmos=zTMj$UGg@Q}I4E9&ENtZb-^9GczPEJTp1{@70B`k2Nq@`&iY}h3J z5jE5APeLU(z3!EqY_POykwX^Ghha--xH8s2!IoTS3qFm`*!uFir_ZQnfcRB38-t}x z%s1cuoa&?xy3F^tw7^Ma9bTi8YF1!b0NeQ);_%F{?b%5Qo9o(E7xzVh-K4v7M$5fB z>yw8pEb8yZD-U_(`TKu*TWOYoyQ(Ada1^8@7c{lMQC5(48r?qg9`taBU;4&PqXzcm zgoT4p)P^JeSMKJwceamYI^)LLTG37yQ`7v?<QrgadV44g`Nvc3Bu`q7|6*=3H8bD@ zQxr+Yofm>m;3J>u#_t)3*eqV(66)NM{mJ?#p(blaE3}=dPkz{T4s8-VGv$m6YS9xz z-RIkdiwX-V^C1Q0yHj*dRzLsIVv?Ib>1`Z-^;+(e`3ED4wq*_^<i9DK`(u#FMx}9% zAsbTK+j@|W5G{#34>6#9JJ9#W)KDPx=HH#6ZR-<bmfG!u1eC|b*FhS~)*!_1l2KFG zF_XShtKVRoJGgmyb}s@z?FYs%^YN+*%VUDvYK_zUIlGcRJ>9qV`)y74R|hsm%Fi~| zas1cTDFa5+Wj*&-2lB?VRf^S$wTG+OS+cXUVRua{8!UzFjNXsr=5KggvRVT0wcQrq zPX9Q5{9NK-YwK5Q>r(gk%eDJaNHC^^FSZpY=lBMvBa5x=M5O`7WN!n~;TfZ8idBd{ zgkXIB{26g@+A$Fs7MPJ?w5mYu@8_3Mes6AyuwfVle4gRd-!xy^RrCnEg!}mP{Kt5k zayK*fCWDEr%i!v>U*jKnx3>t-OaMb7?Jv>O(_J&6#*(OXs{}PjA&dF)?~-|lQeB`u zmK9K8V<$B@*b{b^{r+&d)u6toe_e$ocaMv?Lmh|o*>h^;{Mfb?NH5Yces}QR50_bM zwe##=cvebAdC2$i_gv9dUOD2?%SCln{FE=pX*we#qphBwIoZLE7$5$bEwzTG@sv5r zYDf1xdU^DM>u70tx39=r5rgz#fdNXL3+lG(wzj9-6})#Q#>V{8^GD`yq}}^lX5098 zQz|1Rh57G%4n-w&AP|x=w6N?fDJ&yn`M>ZvuLb+pma`psZtAmbr3qJ-E`5E8XWH@Y z^uzUP-%pKmbD?q+hN8m43b^q_MT{IoK98J}2Yd7G-t#5nGd4=2(<J)S%Sr%ySZW|A z1~X9};n7<lem@885?|qq%Y;?@#~5+(8Hs8g(x4MP4Xm!b;zeXSdxgvT<27_GBwIT> zyT#!cyOqerm<a>B*zxfg13Mi`tt;0=$i}zNhP$h6e3KP0E^501ar7s=V;l??A`K>7 z65`w=0^^F4%ZEh5W!&AJR+62jVjs@T%zSC$w%FNQWr2K?5t;`NA3k&;MIP(*64#?I zFFQIKcRJt~6r@$&JG&?&hZi3vV>4`|r#{BAgADvcf*TAQhK+vgmoEgNXiY)H&+FGo z*D=dLiuLf}@|9Z~m;dpa?Y;Yd<t;g;vF-%tFH81<4tG%#u3qbw{Mj?~qniy;M=_qU zNKO0TVNg!@U@rqBeNl(Do|zHR7xZP1&-}MTDYmz_3Ew;{$15=AYR~tKxV0Yh?dw;v z2SHEwa(=(zN$$LLaymK)$3yPxpPcO<wlH7qd<xLdePsJ#NfH<Lq9zuycT=(Cek0yV zC0s9$>K4;^Ucas&CwoanPoeVE^vzTbCnb%^V=tjwu{w5K929UQop<lv!4Og%YF2lm zDW635T2jq%-@HLY)T2yCmw(Oh-u259MMQ*GmqI@xTPpR$-K$2vktPnlm#uwhNa(LG zZCE|f+QfQY05_dus4?Z`*S2Zvkbfz8@oo?wY1D+0{gnJcx1tNBb;gpM$WtPs@zDO} zo?neh@Nw>q^avl<F+wVO?ZcQ5Cp8JKZ5NUUXQ7rV!-|$v<H;tO*GkH7!T~XTzI97K z<+*YewV$8NfvNDpY^(tCm@KW$pNrGo<?Zf-ov(=XkHf8tfnLB%2<gQ;;6vckSCPj6 z{`2y(zVdIs=zsf`_cc5!edbH%u^JOSniy2-E-P#N@*aV)FDo5dG|Gcq&#w}@MiISz z`s~@>#+jf9>G6?k^ugh2I>SPT=1vz3hq9DK#bqrw>A$s{%O@!5c)I8D@^q`am%n|G zLS5h4nRoM*PL&I{SM9me^ok|}hDhr9_MtOs*WrieP}c+4?Xr}rg@sU!Y*FAY><)w< zmNI{GvR;dkOBN95>l?-7rW{DKe!;SScwSwZJzjS9J+9Wo{ZW%om9-6q=cE(j^JfoE z$DPx5`teCLayg#m6=dW+y5-?r#hKhLjT*<@P6i4Jl`oBZkWI1JG5hTFh1@zWoTNko z^r*H|G6;5aMs$8`O-mD*Z|_T&7dKmhFvm{K3bVIbQq@NM$%Wi5=PL)}NLStC?qRe| z=E(O#`X@fS12Z_yo7bAIBMw@_7%GeAAhN!|pwx~==0QV=av@`ys?|lpV_4LK(8<*D zc<f(4E7(CPx74cknvLUfBA2kVavLp{#d+nS&3~`f+GV`#6&`Y}rHlGgP5cPbt_%f= zz<0G;?#|kgq+J>s<+k?-9?u#p<Wjl5!!geMadTH^sDE8t$=?3BAUUZW(w?i{9kbD& zv0CXCmKMsYkv|_E)^Bq9IQ8XA4&Er)xIax`oO-z{J2P{MoOj|-6=cJvjj+x%k5#!$ zj<%GlMFxxG^vhNZn@>8p?%hjMDd%{uUTahOHi&oVmdVPpRm3-@9Ma3>M(>LLSaHW$ z2m6iTncBR(cNTNm?5MVDTtfxQ4JFy%@Hrh&>eJS!;9e3{H060Yk<7PRxJXM$vwPA} zi9o?`SR=l5Xkp`2ZE(?@$bVNMQ;pDxx$?mDo54?QYSp3j{ZSbbA7M9sqSNI;#&R-p zJB_j{ytahP?)Am$tNQ2e?u3L1x5YTCCNO@*DK?Ql7D1!l*$Im(t1pki6^)=cU)p9M zB*%60zo|X7-HWkWx@OXoN3(N=K#i-@*O}vsAl=BF^cH>Rawf1*IJ>J+ZQ;Zdx6z*= z$KkM0H6yakthHIM12=paWvF}w&h}8=Vx9C_b^V#+Ob9-!t3XF*ee-Fdnen`jo*>G) z+v>*kPe&pwqd$H)kLH}sPyr`eX0aOk)FH#+Y#|2LjMt%bm}SPJ$D)HM_^jmTyJt(J z0U(ey>B?Du$cI7kC0Dd%AhpY-cMFevafB&j!PYXbuzjS0U#Ce=flSfymzO(hfdL<n z_t*VnN*3Kzt3}(!ToPaQsK{?^=rFN`iH<J(+{oM<2OIr!yjqDEoxxn^INhUky~Q6l zp<Ap#Om(xP=2n%*z(OVGQp9_6msoxiF+B@DWgiS`wF=#Q(qO@B928GU{oOwbN)nN4 zq-k+IE8l(<%Jr$W+<snQb-}-INNLvn)i(d9+q6WEhf8u#-87ObyH~4GE!P#o(IH={ z)*rVoMei{aJ5pOHML>3O(TiM}d=7lpP&3;DlY^9$lueFFow%u{A7`F{(rX*nBMOp5 zZ(nXRSRcjpitam1a+KpWP2Ut%^u0d8RpS{D!)0+IDlpvKEMgm;q<|IH=6(4zk<l<b zXSRj23V?~2xcCF5md3`r8HCTyPFaOcj7?0UK})LkQlsGOZY@U6Q=^vNYtO?dl=prX zMv!?w)#wNg$`GVS9E-we54E6Q0%>@7c<b})yC?phL-Z3Zi{Eu}qP5=$dPYMk)2F$o zVF9KOYFuqKCj))-lCl@WHk!ZnQ_kM6+Z*;37Z;0;xyPKP+WwOco(cWJ(kDnDjRh^J zoT=?`0m;MM)z#(x9OWlnTJ}c{Q#(cKnflk@v5{`pnmXru!N9QEU;J@sLoFyjU%D=} zYv!E^{)$!J-&lZJw6?pt6Y5RRPZBXNuoKpM7jsM2hDg&s7q^!9zv8XnIp?s{yNllH zId**9KIn@<`9ZTioWf#hiTqi~YF`FLntWgRmT!a^JjH}Yl0HYGXzYm1d0f`DhrPZ8 zb5>G$M`IsS@8KB#-1Uyt7#l<-xz#r5Y)kyTPBJctSn^~ozl}f$85z0pDqP~mp)&Ja z8q6)!+Z>KFYt7k}sp2Q{QsR=5=S-nJ9XU!lzYaK&?(gm6u%zuS__ySTT&O53gJ}59 z-`Cdl_LKIo8teVfFRK>oy4NdF+a##f3x@hvOPe@Oyk&tkLfpJDkS#AR)(oaeRouvq zPG+)~uk+t^7==B&%l*!QNT}w-VQ0@_do`(`aqPGlr&JW3)<+Z1avtig>ccIIAYM)F z8OlL(bqL<Km?rT-FGtiROVvAT->rp3PBCXPd||mgjNBWmNuTv=wTwprCYeUj7G>!m zCf37;4vQOn<u}8rr1wsnj4{2u{HiS1!{fty#>wz__5zu(F|pHzSw+al*N8ms9f`_p zqN6X&w}rFqZt`<Xq)oD3{z}7oKLqM@#6}E63A3$l9tTNFx2{25_R7}ijE!lcYX9rr zB9)8FN89WuF4q$^*8?-WAiY}G-JIlP{szb5MlP)U=+@RW?_T}>O!aEvhKimaFwsUw z@V-Xj8w8AXdHm>+YUx|G6gi6~ao!DF?_Fn2)r3$og&XA#hO<YjESr~eUzph<_VB+e zX1#s0t@x=5r(`Yo)&?ktl`1UH8o9S#?X^cx_9uv2`DLl3|L7P!Y!QzQVpJ>V1$)lg zH2`hs4W@n4dlv;-8ksXR+xyr3zx)^<iZ|=<Xde(e(s{l!{bqVv=QFBYp;f3%#jrg+ zxq3!fjOjp<i+oaieh?j3)=3N>oQhC%$AmWzuO*8(J39+0y*Be)<7K-8QI>DtnwlnC z8);1$SXnVJFv!XmIyoR-vd#sYW(RC-$9Q6VkmKVck$g*VcKXncA|^E9^!l~z>@3~d zr<6j>6EwyO^5WtXP6(paz!>7UJQgfO%IDp*PoHkd)}J~gvrC<IcE2lxLPy9-gUfXw ze4&RqCsgLLN*e!D_9Tk=T~<ly$nXUIH&(p=7j-j_W<2BX-d^9pK#V^H8}%o#+tD{f zuHV`))Q-<3c#QLBlMPb29f`b$RhD|^`XOVzl@8Tkzh>^KZcoSqvf`m;&i%%UmOq8O zbU~tyHdb-!L#XpT+YI14Fk1dpdSqBoUVpxI;y2#=!QJT_CiYAi|4eH91NY0nD|dv3 z=JVxeT^&z6qt;ZcqrGn5;2;Y<V`FAq+7jlUx1c>0gLz%AT0hl!V;vU3o1P12>+wk5 zK0<qTSqB7NyQq75-Gz``Te~lo8CsAz(Vp?v)}h~Z?Ja>0f2wHmPXe1RXJUTH52)zI zV{O;upJz+m+h(And&vFq1E08`f1!T<qsyalHH-Ve3&X3vj4?7YzOGP5jwGYr<82_i zAyW7WV$;3Lj&9_i`Q-;C1O*Yg?l@t>{kF%z^Aznd4h9a6XB?)0O7Cx;NuCeVP8C|s zoGxDd(mjPv&T7F)LZCakYf<&p@3JUv8+&jI>$%60<L!@oH|m#+6Jw;E9N$dEnl*;2 z9(l9*ocP$QYtja}jYM1?68_Aj0MjXU?yh8V3hk|pW#LWA<q(qI^~=A#`x}9svMPK# zGzYURm3u($vf>u8`!7`7|B0gf%JsuN42-yEgj{r7gjXA29`K)SL_ZY-gm15$oSe+O zcjsC5ad&d$^~1-*gYjivca62Rb#-;$n&^I7fu;m%HCrLI=Emlx=H_VwYq6{v*J$s2 zx<m)}9&ZhZ0^wP{DtzFTMkf1sHj7!|^4q(+)~()=J^BXj8lks$L-ET9dXezyz_|LL zfWheU6kfZ*uWXX_fv@4=^E;vVUo9k&EWAb<h%DK4|J=<>s&KutsD2I4ajwIQnQ-x7 zCWwixGBj93L^4|DQ6%(iw+KUc3>)e=#e-}7u^+=#*EQ0n`s<GRB>Y@J;CAFtzXmql zJIRnFGlIuAN{lc6une&=I^`!ZleIrR5UQkqzJ<lwdJtSFGUeNm+OtQ8rahlt8GMW1 zz{1I=b%swQ>OS)j^Bd{?488L-tW$*bUVj=VY0C%ngzvPQIjJ$NQ#53z@Z+>hbpN`e zRa(nhni$?mK8A<!Lt6{;pKkak{fie`eV2dsKiyCLtE)R0>q!$xL`*y{fNn#hZET$R zbIp9RMqCW-E?O&X(x=kWLnrf1iZIH1h6i&$d)I~w7h8kWp>rf6%GQB476R<Hwzr$= z#w+c17u(I_I`A86{jucB3k2K|5FiS;fWf(W#g|6_I&0=z_V1<!equxzpIop(NP4lT z0X)z`5s*|e9gdAb5EyqF!t)IlAqGaq7mP3JBz1@d0w?d=RUc5PypY6AlPf=&dUYMf ztUZOR5`+$W45;deG%(0Ww(K9n^X7&rux6(BCMCD47WV@0#k&i_D!0vQt3iB4#lgEz zAb)abVq!uA_u^oE)IX}k`E+S8k)L6Bhk(mft;A$Ls?^*xE87=?mRWZz9#UigFhgCM z90bIRst}AP;Kd53R!y;9?&-mTz*E<~Aq(z{_aAQFMaCVXH3-19RDFbnRc?0n`Cxs7 zTBCr9k+DcPL;!E3RCa7iFp%J)(9u*%>RrIvaHf1FQOfk@c;zO+11)|162o3}69G?@ z^_9WQ%V*;Z6VfkX_Rmcb9F7BL6qLdu2$N!dBvg4+w0A~mWZsk21S0g2QuEbKg5N3X zf{m+~oAdiMdaJhlzUXJGUFnbkRsL=|SP5UUn$zjvXBg$;ihTRU;o%-|(x=R}RbgTM z)5L<3(Htb<<t~dT+SZ`srcV~Vzc#6e>#)2N_VBxFM+m9pBv<XTXV0xy`qp<ByDV`& z*11e4CeOOYDHZ5?gS!G!bnl>EvDB-ou4cDh0-Ii{IL-hH_K;h{=ML3U)0QKc>zAWa zj4kanm=m*oqsOgoYL&(8E-X^qm-=LZ^<~fx(NnMqJYCmrK0~NhnDEzB9iJ-~t4T`c zIuxeh<Kz2AP-&J}KWrXMm#q{$%pqfNTA0ipEy8FQ6cju>Pc|quQ%AlZf->3quz}5H zIl$f4bQG7(8Eu>KGb--Oz7%m|WF;jf#<x<M(c7Idm3nQV_;k)>pI7^G`m;q1fZAwU z_YMpc)SXPSAV$WZkjryvp&75V$uBGnp)Pzoed=hlsulm*dq%y&x&mfY(pEdp3@*}Y zs8u`H*VkWdINTsjm#+Q>z0{sM+=)+rp^>S32)@R`!7AwRW2Sp|ajrH#rc!F=o~C~K zq<qB%fqFamDdyFRA|>x&lE$mDvb_>9?6F)f2OXm<8yn_Oo$&JUeNX&8T4c!NR!=mE zN??+e4K^7Ty`5*}PvkRI^uQ`etxD*-sa9p5zt9nt!8Y6$Moo!=MybFEe$%G;AjT6U zI5qGs;B2aL0223%DVC8cJ1dF7N19zpRT&76%L_26`nD`s&B@-r(aD@ZuthB#9la;W ze8TbTS4?)cxkoY^`%!i`cNW7YemBYA@ci_0u8lk?&RSC+vaDg~_X-!iZI*wS2hYe4 z&!o*wxH(QvZuMxwtV<p3;0exYD&EgLY!j_p?Xn6|@7_Ts3}lI+V`C2#8P2+%ooMMg ztEtsgIZ!HOy|+I(+74kdk}J&54_B4WR$<zlsOe6&YAH3J6p!1kb==3PEHA%j6d4(* ztgJkp&SRU@{$0>!g=x%f>q~w<-J=WfZ;S%(XeA1cMt*3Z(H5Rv{x*IYB>J`*|C50R ztB%jq7qPWec#n^kdwu$GBw|@<->&`aU5v<`c;LxmHcam7B5V7^pi>>KC+u_kDK1)( zRoAOm*YRUD$WK}e<knT&o+6Lc){aR?;N!>kXvT3kD5OadBE$LEU+7R>wvSevsS9gY z<aRx^KV3>74<ThXA7B&>r|O~4Rw;qlzA1M;&ry+)pREs7iw;-%XY0<#2XoYlN=vz| zkGy)scMcCRknk%wc-bbqyI<L^)VLr~Dv;G03?68<_+@D3=D54NU*28ceS8)1m5G=% z`pR2l5U9zVyc2*~D|Hj~gt9h6&FXxP`;1-D#Dq%2PLQAfPB72pI?Qrm+5BQ0fxdON z)y+K>^5qfip|P=>v$OI7bxJ{jn@Gu=irVT!Lgm6i(m`fsw}~cdENueAi(V_9C||pF zeZJXibaQbr*MT<DVjFp^*wY<xIEaYQ@I)a%*RfVqELE?xJ6s;W*Pza3H<E9KA%Q<P zKA1iFZgs#k-+3TQ`5ha-Xu(u#oB3!BUqu>owklE7`Am~&@_4z}@oZPnch|F{Zqx>_ zb3yCkarcQ_g)pdk>M6dAXqLURkcNTaB%*B+9l=evHg7bRUhRtI<c4VBzs`kx%%hV0 zlD04g(t?GV+(3LzO6f6WT!E~r)3|*W^Kp=kFK){k&^3>?*lic|tJ<!)?Cl*V&SyTH zbUndc+a!2D3JX2{jGAX)4B%2D2Qf~$YKUB?TU2fxC)6`r{-bt!q*q<lYYkhVC0U?R z33%^xJ`;9(rb&1=BCB!Sw*7!pFffkQb!BY9v{KK&FTh**yz4W7i&}R?6|%g84I2rb zV4ZdLQc|!rukS~F9a3uQx~6Kk#`$jPC|}kf*L55}4wWE0cjDdtNj7wd)Jg?++ZD$! z2}vp=dhkZe+}!+eSa2B}<zT{Up<ep|Y`EMh66m#u!|Ad}iY%oNRgR5~{St$m-n#Xv z8s3W<{SIvLC}zW<H06mZhwa8%?WW+_7D)gem6ep9dTUfFbetaV;$V?4Cm5cO4eu_{ znhcdG$Bvb2mRH!W_mqpTDu}S83(pF;oS@jB&Uq)ePk-Jwp0iv5u~m)bywUgP5cm5F z*E}-+_up6m9$rhpnN9N~1AxJa1i?j|pxtYWD7QI$wJbyOMX)Pm5Cra;V$7SvZe^BD zJMxr@JVee5V<cge3UxxX=9@n`n}<e+3D0XRR?QI1)L&2#ON*0fukb7k15nD1<TBR? z9+cV6mW(jfT6ak$+IIu)K$LA}X6AY^J$qhj9g@RIMs@_FA4A*-bWBY4Ha*%=)nY?w zRqxVX-I=qnv~f~T<KY6J@__^DTGU=lsZCS~aY=Zm)4`-KU~!`*Mn2OY1%rPaHs4?M z3HdUcDVy00U{rVq_Uxd%@nNe=I4Z%m%2Tbir8i$4ms)?mmlV#u&E<w-Hd;U)PM)*6 zu8LajFMZPgav!c3#`VL^sf`#MOPyONOP*Bh^z%aQvsvK*ar6!|urKieJM+vS=yvWF zI`!AZ)m5BFk5<;yZs=5TX!wS_%f53D)qFC?zh|GQAntsyC|&k>c^OARK?yH~x>SP6 zF#Ub(J}1aY4L66UJAfnaqWxn{Ow2e$KaY)Tjt&p|RCn}c%i?e&-N$|J*5mOjvg2*6 zmsbt<zCTx61f|u~lK1bttth)q#dM`}tKShR#Q69V)lSd(hgvmQ*%mBqth(Z8QG0d| zf^p)C!@@E%gEzgyXq0ie!Fk?P!bsFunJf}s24g59dq~8@#dOX0xCpqkr<;ROx^V_1 zea=7f@h(!U1qgnCplZf6&D9Oghz~b+y*-+?&U#a6RhO3M@z8LIN=o?8X%0)*RrJVR z!@*;k*y+)f?s0D(wJZd!43I_wR8$OFP1HO05l7oPN|C`&C__WWF$w4YI=KWlE$5O& zBV=&RO-()Ad}ghLh1{BUH`Yh(AVb#F$VjEenf2AW4~2XN*)ya?+jJQcdGRKuG@+m$ z&^C0VcKxn<s-Ud!Qu^8}tDoBZxszr7x62F$1MD_9AEY)nwKO$1-d@nhWQO2)mfsi{ zBr%+?lpBq-wLio;euy1A@_EvR&uPI%PhVi^VZPD5ZDFAui1r~VncXaxc|ZXWZMU60 zen`6H>x^y<YI)t_bMs4VX+c47Bufo{$Su8gvOD;5WUe5XZ}e)V<y;q%UGNNuz8&cG zcB1GFvs0xy0_BePhp}cd^)kZRl@xxH*;wJmrk2f#LI4u9ekLCCVt<W{^v6MDdU%w> z@)t^uiT(WXx?GOZ`P#9lkWc%;oKn)eS9U)KyB<ga6+odmF($IeRQdw--u=hHvS~au zU#5No=O0QXEoSTNe(jjsd5^D#prJ)FrqTgX^JVW*{NBWM!7s5bc~(KZv>G*!o&{oM zg6nQ;`@8i-aI(+1(~%NxjpNxsuK}%Ygo)vsfTD_wt`F7-N=24@<<s2=GwuAtnwt6c z@Xjy>!Ku`EP~dqJ>#+!=>)O#K6YGyL+^KR@tue{}qJMj=#Sfnx>RUbZpDCYw*)Zst zn9}9)v(|)kCs|B}-QN#Qa>qLqer{y}^9e<#Y8lTtCjw=2sJhl{9otC3UGM{-v(3#- z*qF|b7gWAR*_cf_9&@kmJqmd=ogKwe-+Fgmgn+{`G58saX5!b~O1oGq3>wt?_b3<C zhPnv{7vr@oCQgctZyh0ZY8Lbi{l0yHGgLarB3kmIwBwu2`seH?ZDG=<RKdle%6Yml zKAS%Wm$gyZNFlSp>0+9+OS7@LQQP=CN$xdW76Eb~8iZ*Xsd(e%>PIub<av#u48vMT zbmD%~<5N>h>Vl;2Q>D_v4j87Lk%D|p?MCD6biKz1J_iJB3dNQ;N%g3^A?X^Zg2j&Y zX9v{oH%@Cl3Z9(xsH;3>WTbkrWmV%WQgB{RnBeXnx3k#(z3d=~=INvpI}~E)={8MW zJIXs4I%_7T$vV)t@$vq!oNGOp%y_~qfF8?Nprm>idv|BMu!PY-uqVB_j&uJHi@JQ{ z^}5%%$7bXBSx2@L>I0&So@%QCkH8p?-L>OPuIh?~U)yKb{d8GwNmq`s-+&LLKD>U| zr*lcgCQ%X*eJB2&=&^bAY6C2lfQyIO4p5P9^`@2$*$+n_+9kQ_Q2l~v1V4{Zz+(hV zW-o!L$hh)I@0uD7aD&9#c*)*FZ%uvkX81GZWK4!XxPOge%(bIWt!^g+hym~3ljU(7 z8ft~E;Dg&512rhlsHi*k`<a(gk$?Pwja<=%DpXaK!MEGk)ZEhCG_A>d?c%-EPTnNE zcf0F%E6npf<922F(+@8#e)!#6_j<DN6E&w$%l`@Y_^*29%ZC47F_`hRU(l;v&r&37 z-KkYdOeYHN-{NxJYiN~>;|imYeI-<`QoLI0awu_>)9fEt=G3J@=#isdxq+De_;M^s zx!s^Ew*AS{NcA9;fH&^HoF|`}-`5bjo{SS8nwdGu7a_RPa&bK92My`H<@-)LzszSD zv5u=b98b&iGHrck`v+xkD~*_p?xh#lZMx!u0Ed7~LZ#B|Y_Hb9sNl=d(Getz2)l)4 zM^28vcZao#laz(t#z3tg$v{m@YpUF8@#g<v?JWbM{Q7=h{{|u@NQp?7G=hM%ba%&q zw6t`C($Xm<AyNYZ(hR9|BSQ=f-O}B)7kJ-$KWCrwob&9x&pTc)*IaX5Ypq{?Kfj{5 zEq8T9%REib{fEJ*M0YAp+h@vO(I;o6?Te<Ri^W@j`f<Swog9nWkDt57!3v~8@J5?d zmMM?cwzfw?8Sdx=r)MVx^gA8#(#~t|@CG)g$~kn8to<}LCVXdsvz!u@hvB?6vu`Ss zsDWXlO3lDv**z?j(?qMw!NIsnv@*Z<?z|u3H@e!Ieyz_J93mA8Dllt<-z0qpPE-{Y zAGZ|gR%1k=CZcRfY1twxXjoVpeXkoq*85jdW@hH)L#(L=&w=*#TA)V`QNAx7<gk$2 zCnfK^jufvQ1DtmG)M`N|`>s^(?GQuJjg5`y0~;_$0XV9cm-mVxP1D6T#CUbi=aH3_ z&bvn9IUJOp@yvCXqc(iaA}u#|ecZe+IZVmyPqgs-8fePGPSCG+8izMOnIN|Xb<UG^ zd0kQg54{Et&ebd<W8>qEDc{pQd`7FnEl8c(_oR4^I>(hQ06mb5curA=>$5sFFf~Pz zY;hlLq5Uf5K-%9w?~-S#qodli2k6x++MjZ}y5i!-0nZQc*S~AQ&f0niPxqELXG%)q z;=WC?c<;;_p6)HN?ew=8w*<*g3kuSN5|Rm8hd`mw3XCVtp2u6nuYdTeoCdQ1i<Q8j z-pb};7uSxNVEYC%>H_o$ivcY3<Fb6J(ZvSOK3n_m-`MoinCl2B!s6G0FJIcPmf^q7 z1g0N&q1kRVfcXA?et0!xCnN}y*l8n^n!|fxxo9YFz|HeKo>9{UfI2|VPpg00`<zv; zCZ5$mpRR+IOm9_6TjudNn3YkW0WEVFSxXvA(if;j<SRp52wEFq4$DlCTD+iZ?FIr# zvU?yc1HQ(3IA2&LVWPgRrRAI6cs3>n8=KqdT0-4~)dnu!{{Fs@<Fa*$zJLi~e#PhR zTKDxMF#84c9_dtDp7!a@6iX>#Rvxs4CHh`pA}TC~=oC{jD|)MJ_<#f;md-ByQBxEL z=gVJ7Ai5+4m?n<po<zIW9g5d{S4l^jPEN1(`Wif3X3EVotozh-a;mq-M)D2)E7!Sz zXo1rTS>XjMdkO$?AjBcD4@T`8;RZt$avtW3@0%SR9X%EFIB*-x>K6~i`|N|AWB!F{ zRU?7bfFNUdv|mAwsUK^2^Xzaf>&$TR6E5A<qycxn!EvI#z|v>(bbHW6tJh$bR<iwY zBYM32sy~C3jB5i~NerT+O=Q*QLaq-z3OS+p1WY<c=2l^8;pKMYd-yz#%NI7if2_x2 z1;gfZ9%YzrH{Jt_K=*VYWn;W7;;G;(yJ`M1M1YUCCwg~rFy-)w^>`Wm)TZC!##qz! zY|{#>NtY4F`!~MvlOTLsi+z0vLUHv%4KO>cV+n`i_1e#|8HokWamDOqegUt={K<Zp z&%!cj@!$QF!f6Euj0@qzReH_cgF{R_ZaMxlF|oCm3&rX+`<SG+lM*t7eA`P<ty)jm z+1VYyBg3V;(yz8n!=aL-lXBXE3s{XZfr{BXc((nF&pjMW@(?ft!!vMiX{GmU25j}5 z?Sq&2|7=~r${kGxri(gQla9OM=;j$ACN$ScTmpiE`q8Z>1P-oHbV9R%<Qb4NsIt+0 zOv2?bI8Sr${5bWsq1W}5zkP@JNAa-4bbe>EwMFR~o8zq^vTCyMFRv{um6Ucsqe9vE z1eF;+A*bW$^ZJc+K6A4cltanLEA`1L&tozsoq9Q2It*eiYRzK3G(P9}X?xA$vpg`2 zM>SXO3!8m6nB>H^JXVTZGDD4tLB@mZ?{{e{qd8m~-TVz@Z03aJP&|!@6#0Wc1lAO2 z-z?T^#B-eoycBR~#SH|>rwRx(u+^LPRB>7%&|`mlZ6cjDG(ar&_AER(B<|`0NL39w zn6xUMk`>9Pj*jh1OTPboXFQNGQc_Ci$J>ufvV<AD-YBm2;XLkZ2QwVz3xn_e{1&zv z{Vw{7{+J%SkXgSTPmwl^pug$*4xbH_{8Kv?DKGoJ?+^~0f)-bnfrMUmm13gGW@Yje z-RIJI_@uNc;?(&|4P!PKgj502i5T_n`ve`k0IL5~(BZ&sHt$WVgw2F2lV&c4C88&> zB=?f%UYwo*EREk==L=$H#(?D^wBWN$gU3>6cTg~6fILV85=t^aVxHwsAFd;clpByM znVETt8T14-@8^uNqF?(?Tl)%KH_>2H?7V=NI&$-eUX)wHDl75(TlHWLSVZidV`J}z zJLf_kELrBl85*n*>En*eMiO7FdOnxnA)IGtDOx+=>V+kC1z1XN-e$h$>!%MGEXxpI zC8Cq9RS&Ue)vLb%QHA{lu%U@G37AwJk>?E{)|E|U;<w*>Wuye72{C`3wWGnTyEu^X znD4$a=ln1T@5!Y|c#Ot|Eqv!*zOiKqICL9L*+o=*;c>(u<@H+WpK>%GC{Qj!hA11i z-VII6-Pu9i_-Ndr_*NDGsD`Sq-w4m8WV#8&7vmsk)axLV>HCDN{b_vY2)W^xxVQ_O zd@l3j($OXa1kBo@bit(ybhA*<EYtQ{&g}sMU)|Zhn(c~SlaDcc5!&G4oWW-JTo6aW zP`GUss<r#WvJDeAB;?i4pO8WT?GSL=d1DeQlUOwNLz!b$;OXv*J#`+(#dj0ABcQ1k zTWW5!%<QlmYjXl5(Kz!B9&4Ml#&p6>2hvH7tC+OQ$nS^}^@g2GO1*nw){)~2=D2j? z8_M~g9kS}x20#;8AjLX4><*h>zkbzXkJWWZ4Y*S%v()WhO+WbWTtHtcC$q-)7gq@{ zl%K<FsOiDR|LFGAbt`axg?u35Cmy{(HpVXL>@akw#(8dfs6ago#8l|9cvO^4Fh{d- zB+^K^Q;d|?>Hb2DipO!gx^2W5DK$xHR#t!id{S{5AJtSChDIRTQgnPQb2$0H&o^XC zR)}Kv^JVpM{#vG)$EbyZ<Q$<>fdRX@nCpvZudIL1@>9ZE#i*AdQ<K<4<Smd=BXM=& zo%N)crYN#7O#;+k_IS3F^%30oAqozBJnF@I(k@-03x#UX$ue<AYsVgfzSbm%!?j9Z zxir1+@09C1o(gSoFOn~Dml$3qFn%`dFfPF&W`DX{OzwW?=Re}4SQDc#N6FG`c#Mk7 z<K)*+-9(m?4=1k^7&N{14xk%)@~N*RC~^57#>gzRW0rnndtxEWk2+_AA&5SW_0{ET z<mPnw!&7l#=A25k(XEE_T9?&;aCRfk)gc8LO{b&DCR9-{{)Lz;Kd+)v?yKK}7)^=5 z*8QZKS0;XduM#Et0T%s7{Hdk2wF*oHOxn9#8!0d{HnGYrU|^O~NdD*Yd>(p!w8{4| z_8oDT+IW3QW^E&s=S{&2fd#xzx=XXOnU*|m2jcTWVG;8CX7Z#mA`;?}k&&H;R85g2 zevsYn5l$8^tfnk8eSTjJuS%LcoApumy~Qi%-hAM-f_Xd-?Yfkbw`c02-s!I9Ji4ih zhLdq?l+nn?H2+*u*!sH<u$<NVY-j3CC-QMxN=@ob-Vi*uQ+vM$-uu%yg$%*47_Db! zWUqb*k#6t)c}MB~m@4OrKVgCg^w&2_d}dZf$s5`EDq3YTLy`Yl0H2Zc38n)vZDS%8 zr3`43dzS#FM}W@!oyUd;jh7E4qli-JTx}&KA5O-W%RaLte)bG$Rw<5!ax<Tgg!8OA za~AtyupUS!eKq{rIr-Yx`(tFRl#$`jkv@`_p-%WAz0>Y)^FiG9dw7%A7Z;Z}#1yFL zU>vLVx1f1i!@2o8S<~OO%R*b0&CGCOVmg~Bg{Zwh>Sn(2$rcgd7a*Y~W{T{Mp?c^; zsR=6HQSqrxrIl7Ac&|PS`3l<qobDH-<&toD;^54vQ6$m-B#On^5)o?^OA#0xVKI~| zmv*M9<)+n!hX0<g<lF|={XQ-+mo)>VAp0ctvU|h|7@|VW>c|4j9gl4R^L~D^na7>q zDe+UXqWr5D=RXt`rA1|rZ<VhMXnwyipE`?}cgtR1G>fUINDrENXJPS4x8}rXu5Y4R z9F6b^I(Z0=f$)pSN#G9rBYmIEeSRAyC@3^o?zzhavKw{qp2&;w%7xSWh6fFv$E^DG zuZ-I>S|r24m>Mf<ISeC>`)R1Etwu0MzP1j!6KVuD00N1Ye(v5o*s&h{zM2>n&5`#y z(@8wA$w!5!Q-8q}=V*V*^H@~01-oY9k#MnGddWaO@B&+@0`d|G{hC2+Gga?QTt{f= z;iYoKEyv;%r=pqzig7_1s8iT3RI6bjJa*~)s060wn(8z0>8gG@G6S#0=QW@dHfBLl z&#!DAC@odL{I=4stCXkTG6{2Bc=T{!&W-IeBbEM}_nAO4W53zVmR<}7VHq14C+Meq zNlUYT{R6i(=0$jfuzVaO7ry>gs?S!k=;wMF$e4PMpBP9kn1i~UPW39=W)%JT<LA%0 zk2LW*<LDk2w<MXoef#76FTL?YTF><E=8thcKt2Op%SR0T+Wd748vL-^W4h%h#B;jQ z6T~-C*0zz{%OI&L=zG;HN=SHr>+Ec=&)wV0tNmKgV(tQFGf^dxJyPk(D(n!qe|T9k z_fMJYiG`Wj+V(ap2@wfy9CNC`=O|)g{n`0L77^gZaif3qBn-S?<e}y8c9w3Ev+ex( zR@l*zOD=7$zW#QM0xk#i>8A`(+&M!*;j6OIm|@YzZ_ECUR~CB`Z1d)c$K-Y#8Ue!# z%<V<;hEQL(xX9zDZbV>wrOo(gVUpEJh;oPG7qIMWzs3xLF+tI8sl29H1(+u`8z;|3 z3KuXR9WBP@^t9#5L$6+ksO8F~kaNXqSYG*wyYY{~j2Uf@r1}&xc7=q?u5s#lWpujR zy&@oZk}ex#jrI!?Pv5Ww@aDR8HrgiC#*;eu&?%;2MTNXM!~Qr0LIz+(8KnxoWXvQY zX?)12Kp=^#ZDibNttb}Yg$kU12E3CemtlvJBcb>4i}heSWnzy?%MzHh?+)akc4G5) zef|_b&K3}a1$&M~##3u|{n193JCRWrrSQduo`{mXd;-_2Gly~Ose-micl4QteY^?o z9u@T&z}Cz^xHD%VKf<E!(M}(0i%)?6&02Yl@q>z+pH8XQBNS30A9kyLetw}SA_0~C zaj=SBjX!By|H`CZM^ZODHipXjqBRe_p2Nw(p&2j~>fK#7CIeS8RB~iM-u3Z=?DAQ? zxQ29UuwvM`xm)raU05ik7~GGZk3Ya)`3?`It2Vrg6Js`}CgJ%$r#)<#gwJ(B07||J zq(A$FAwuy4M;_Otb`85__{w#FVHQUx-4_|dF8NH~I-mhW{`L0lclLgRG@b{G#q3Av zk|_htn2K?!?o*pdwQ@7e$#%5G0pCL;Cya}<O9Uf$n0^`qH8v>e;bT&X4<W<fzxm(W z5`B6)ztls_ZEJLg${v^3g9(~Iw<Xtbj)ko|HUo2X1))c%Y<qcVMlT5jKcI)xYUCVL za;g_~DlM1$;wH47Y`v&;I+YpF_x=&nsU@2NO<MOQwlm}&EmAdKDHZ?`22`W6d))DQ zp6Ja>?-w$1a$;r`zSn}FSEHpRhvcVW`DKDlRl%+b@GHb4m7eR@n~Z;f?JuFZd3el~ zGUQPwdn{U=FM#HO?O3M^I(H$*H+@n88%AiVs}#7eJ}@nh+Dw4&V3P7X0dDn3LVe^r zFnC;lDQs$Ij%qkxACsqFCV^4VcbAf#{RtHa)LE-v0K=;RijUEzc=tRk5Xmx{0dq@? z8dJ62lD3Zk(W=Fh`hLvG@p_W-;X0jwb7um~Wi#k$6(w0zhbFZ>&J~yCFgE@BfGVxP zkHYYg$3%J?ysQ4n6=nqm@Ur(zN+-jsLzu*z(W%)5jZoe<>IG`;6ZeFl*w*rUFx9;P zq2jaGm%DrSonKQ^tJzmm_Xy{*yRPr{1coKDDb+gBZ-_271;#5mTd2siSovjoR4@E6 z$}p&LBWls22ZPgtqzONQo4?xjE$6FHJj=C6X3tTkfIy}KvPZQia{89UyVCQ@_$1-I ztK>)J<g1zm7IE!<p+l+`ZE+K9VB*^Qvd!F(kR*Eqsb1wue;Vh)b}~8vOY`~G&W{~w z+>S(61BI#wd1}BU)jDrZf_4LwE2UhURIVD_*|xLr)uFQkl4wpVg2k^rQnmm5szZpQ zFJnG?h1XM2R)qw>!_n{3%=*~ay(gX;BMj<n;p7-`;c8+Hmfs=g13y2Cf;xTt3u=XQ z{(mS?C9cXXPk+pPJK7TXa8d)Q<1*@sARdh%<sdM89t$nft^BUZO22{I^o0RYh%sEK zYQ9l3!)-TS<-WknY1Q#?6;YzNkjos3&-jd#An2)-Iy;61N9&uzHEx&g%>cgjFWMaP z_$hCO3w0lA+uXPG%TDt?TvJysB9ycQL)e-kE=gc3{IE2SgFh}STafS)jmow9Q}hf$ zZ!Y`h6Et@D2-6Nm$ZR})oX@qlN^m4Zv_%ATx$?Th#b9?;^Au79jhE-BI?7B+R|kvM z6ABS*djl4#=SRe2Ro-*~oo>nRkEaFHsZ8kwOu9to*>tO{IjPe=zm+V4R10r(-%}J0 zaX?nAzqK(9{Px3Z+(;OXlBtVe0bMG?L%1kM+jIyceGBG<5zuBqr<h)8JwEyq%%ci1 zB&0EDSE{8Hep2%-{6vf*G%BjeX?5>=^0l{TrFsuRDwmD$%kfGKBKCX)>!s0xk&y3M zy}K$LA?kU!5vfT;!slFBT52)+-QwfL13ys_Ya5$&L?I$eUANUsEB7`LVmcRKIasgl z<WvDIJK`!>ONHNi_5Mv080h<!x_<~jL_1j?Rw}O&<;eh2a`dX*@N4L<>-s2j^emxD zGfXPxcl2)p<_VWgBvBpSHfAUu%lBYvSo(C3bD?U*i=0H-RZn~#xIojNiDkyn;f<rF ztBY@@>)BNcpbF2J$ci%qtF)SUrU@wxd&;lWmwwn3nN|movTN(B#vR@L=^O40b&j-( zDQrfINub;4=^x@(wv%sLcfQ`NarL&iDYn-h8)9C1U*IfxAtBkIb?=qshEyo_n}7iE zMVHQWI8jWi_w}@{S4RP<gBci}G~Q&x@nPKG-+!qwFep1SF;VmC;xrIrcI&G4?XSCK z1{uxfzQ_Hd#rA&WtB1Y6ehs#^z8*LA@bpBF-S(u>eUfoJ!l<dr!7(1mlprFvb2K#p z+6OEfv+{Uy>hOsDlQOlG&0(x@&}XbYGeUQEqf)l0b}Vz0zWO=H{_G#f5X#W=$IPKx zLhB?cs{s01bWHS~!%Bf#R6CJq4vmdW)ohUZ5_uI)_{>c-b|X{;Q`#G$S=`^>UxxoA zFWsBV6PENi*_uvLvNVhWmI7^*i6Y_tXO3{%>JfeR!5sl7_kfk>Im{huY4!z~EEIa5 zxo8w|zN3Hg)yu?Qp2uGJh-UZ>=3uIdz*g9ojax?C=d2?kl(T*hQd?tg_89u+5yV1< z+v#a=cHv*Y1g8ZH8u2rMr#{8wm(2?>6WtAUsvaJ|`Dw$XIwNvBJ<--p$=mV}xqI)p zLdqFb5^A@a+hjpt>b){&zxdn7<xv(VJ#y1+`X@1Qz3&?rJ?rj0{}V&*a4GcvQGPfW z5}_r9j)VTK{iAR4H~$U+d+D;?-N7oh4UtRc(h^ef0rb*>zC3}yGO-k6P=dH{U;sT2 z|FzcI-#0yiFYcY3o_cz?OZ!HIgzW6>0K6V{NQg?{jX*8SiGY;!rQOwCSy|asCNAJ% zH65(k&&}rm+lfRX&(6=UkJkSLhJ6kvJ0_+)2kG_*A^||HOdJ~<>rP+<jpqd~Z%QKZ zS75#^cFf~vzh}-bJuf`2F518_>4WtN;?na4Iz@1J9qldk<PD?;-hT*sIRt$6Donbb z0G~jo_eKeqBLv!esHmtgsHL8DB_*eRY63~jV~~n9?TN4T+1C(rbMp_vOc(S7%~K%2 z0U|tT+f6I3GRp6vIINW9WN}FeAR#s!LmZ3tKj+z7?pt4)voNyO$(38hrBfj2%upn! zl)>V-DaR1Wf<7$Al}O#{tvB$gpKqGfps`O^Xa9hLqoFK1I%r=4Ud<yh_ft>EzjFa% zU4!VDVc0L!=NA@4oBw<7<qMv_9ndH!D0g$vZZH0yEBP$cw;L~a9Rb$<E{?Ly|5x3n zg6<{5tG(4yHz7nozS4!|my&|Tl3rRgKmFc`RENNbea*I$)>bhAfk3E-pYn9UnMCf{ zC{OrvnRTLMG_mBgMo?50%Vv&=ifZ+kzJ5|k#UlB;n9H(5?f#KW?s8%1?k9WY-3)#z zvMs_8pS!p3Am*sm+lwBHdI^b>NJoq2;UTl&(3iJHl>A6c=%3s5mo4zAG^RPx+5>La zy|7mTbHU6D?V;{IxGlrQXn1!e7TQsK6GRjnO}FO%&d=*G7HX6W$BJVrNU3=)_sQK; z)=<1l9{<T<xZEML<I^RkTyskrY;U{2MK$C%!#WpXi#nIeeY9AVgO};YS7At+9%bCb z!gL*VJy|1bwMBmct?zFR?!9flk=|W>t49!Wo^G4uJxh72wZhg-A+M9CSm%;MOm;rk zme>rp_AoN)<r{&y^ySJ-Ea7?^-2To%Upx<Q<%v<fIH>(#%&}?QsD*Ayx5oApd*x=| zaVKfwB-a9mP5Pv6u7d;rzk<zcW%zp77>oFJs!>XXs-oP5UBN5DV#CwxKaV6FboZPu zs&y$LYMk~w(x(pUo5%;1%5^5Pcq=q#TVrZLH+M=kwBA!~(}#P_xNnfbmU7(0(iJGm zaAtK~#sbsxoaf&6x&63h`KsTU%ck`CEXg;QGo0I<B{p-yh47JWQxkR{E_Rs?*F_{M z8#rwG)#}xCL;Y&`1qL7g)s9|D=5oT2J`k1ZCy>orID8Fa#usM+W64j_;XKvY78Clb zHKk^RT~ud>*Ipsi%{o+d^!*#Bm#S5r2clw`HPhr3tK|6ykN@`JQp-9QL%yVd|5Q~K zY+F~EaS%v`TJ9g*{r5L^$*ho$n(Acbt;1ivi-?PCfTbp^Q|F)de1}3B(@UX^3D$JS zVrxHcwE&lNm!4YJyqw;Nxyr-o#SJj@?rV0dl+PIliQ3!ytmUz}N%o)$38w+mm#4|@ ziMCMA&o2ZXynXlft*OOUQcM5u-{h;V4R)SB!{3`+1O!YkOI9vv`D`_czr7Z2*@N#I zc=*KkRIWqc{iGzy@Txku^4%=$&JESge_ayW)XR|FvUi%OEiHOmM0M&qfBX;NB8r^- zy7zNsRw*F%^os-aWqSJ+GDlVYu<7QHkweDo95084*8KGnh_~X-%$2DI1^(qPMu^}w zJEH|?Z5|w8@h*4WgYr?z*a1<k2#S)Pbx@_)KoZvh++YZ_(q_s@ux3bMg3TjTchEQ8 zmA4i0q5-s2q7uEaExles9u6O`$Ie47v{KHl%v%i#X)>%7)e8^odQgcfyeMzV+m{>c zl%8}Dvmowvnk<Y=3$is2`Ym69h0#N2z4=7aarJ6GMOs3Z{L3C_SG@H4-YHuAuyF}H z_`dMYY3amIPJ&N%R`Dy*4LHug&JiP8XljZ8ZxpFMP?+FMvu`uFcwJo3&9!bom{D~# zJHjgDU6Ne?)=UsQr5E=sie9qd<d6wSKZQ0*x{Ua0s!!F^GiU5ML$BBKy5!V%UDau< zPHVj?P2u$y7~T(LlJBH;V=JS;6^!*LWi(f3iZ9oP4<ISA(A5!xx_PxtCLvLSk1Dhv z#p^jXmZ%cU85~l<Saew_+tG8}ln&qPKC@D6#B7i|HPQXdxLpF#R@|94P*B$su{`rf zxSg(sxyH$T_*i#j;x<qhFI~Ef9mAEQ>${0|S&~;#zXo1e)z`!b<VYox=9Gb_gTSvI zYq<jON$b<q$bWtEM=5I#mK9b^zj6i=<B>e?xn6qHsI}n?Pf0RZzP|Dd=3+BDXsLbE zllVKfv5#)V#au@@!-jnnaGvDl0jg|OStl63w@eS1jhmr)q<Pp-l-H<U+q(w;3aR_- z>9{gQjSKn&+<)vNwgZb$ny9wC&R&{EHVVVx26agHA()*T%&w7k#@NI1+z62^hfGw= zMyd1f<sUm;KW;AW{?`Zm{(j)heW=>*<a+sX&uVWIsfr-1qcw#$f|ZeEKfura>K864 zvGeBTy(sLNkeU}10!hRv%a#4=L(uxb7-;k^-1U5kEB)_HWQ9jZZXzqIidnz0=T5<T z4HWR%T~5U;UoND(o4oT|DMK_6W=!X54r6KI5rnj%>BKZnuvYI{bDogcui)nJNeAiL z^c)T=jI`IXXHK0Wj+k|{1#gUZoWykC30TjyW8wXO%v+Dle+yDjo=w9i4eGkV!J#9V z?6TQir7CaoUD<c7O!tM?kQt=x;MFmr*yj|K*51=aw6=DjfzNB1fGH}TsH>84p&fLz zuUM5-JCimCGQCB_4jOVQn_Nb2Ua}YaCKA7z!<4y4{V=ciJDr=o+}Q!5*yHw6d1N9I z<_DibOjgg1UD&mFtF02Rd!Rbjq8X75MTHkVP$HNYB@f2rYH;)*kvAo!Hqqs0#k?E? z-%U8Q8S&k*yF1TGHXdKW*lyjAoEpJu62zP#g>xeVN?@-LqCAT{`K;(@@uvjhqhIbo zLi3Fy%g!yZPob*%aQLXLSUR}^>~;DZL&=b1r_aSfW9m#Yvu7dIQnlQ**uS(QZ{gmD zpgAv0nI2W0`S+VtA0wg0iILfe3h^;B(2Yays_;-u@nEFc&#kC8TaUd;i60<nG^tCt zUQ#<$ZIgpV%N0Y!Z@&rC45%a2jC{oohTt_2&(OTwZMfRS((u8y4TP_UP9+LRF9wf) zMamD)_MfK1zc#rfYz~_yev@_|xvcE5TS1h5GCI|gKXX%_&Zw<zvQ8nrtlVeKQ(3!_ zZVeuPUH6TCEo#5wB^i?4rr)K0gecCdx;|uWh%LOj%5Ps9xq0k-aoru3Nt+s@86GO= zpT*kxPS_bXFDnZT1Y<mIY^^t0?bX9i9C)7Ir^W2q!H3sZ4wkjd^5es=j`NBg))JS{ ziR!#4D{uUV|M;(Pq(R-9J6JnyszcR6&Y&LR@>wyP6ugP7Ug>J~Gi(1VDrs=MGk|A$ z8ebx7sN8i}Rcvpt!Eo(hX?bpiFgX=-xVfmQLT$pJIo+{P<N-LteWv3-E3Ve!p%rf1 z2poEsTB*=(f(O;gn)d`p+44u+d4|}tGb>F_yR&1=k}<|G6tK6;SY711v%OEnWNwWy z^q0bxFAC96swY@o*T`itLkv&HJh|Xo)<Z0X&Cs6w)%kL@0n13mwKKji4=2si;e9F? z^C_=>bf3+2b-pDK6?LsNkBE)LG7rwO=J_yxOH2nh;s38IY?eTjCJfFKm2XaY{L4yT z?L?8Lz0iiTkQhJ#(bs!r<H~}-y+8~wW&<l20ZtE!n{^QKhnVPhvA`vQW<uqnDccpL z!s`0WR#>kw8V8KePE`Gu+500TbH!C~p(YHGbrRrY9(>T(WA&p#jAkNv`D)l0&vCQt z@_XL#-UCycgHLLPx2%e?*dAZm?tE}x7B2kC`+I&!u7fgxOh)TGB<autVdpAc?P7=- zdJ~Jjcim|`vw_m61h9BjH>R9Y+X8${+(mC_Z|&yB^z5fiJmeImeb;7=-ehcmBS@vz z3+DcS5|iyFgb*u(mqY5Td+g-9(djJ^>DI&^m>#->!<AN=Q)ZCep`2WZr$Y~2Y|E_% z@2@+7R1g6E#IAvYygfKwCdhwqyPn1Ty&5|l+T=2RHQbbzQgww)0LHwJ+W^12(Bd#X zKMPWql0JK_D*_ga=FAX(%(K59aQFe(-Bm))ZB1WNa<7p1X9<bh2{bRq_4S6qfkl_U z_2?><Gq<40<xrpx7y4HWNFSrHiA=a!8g>HZy93s|G6<ik#^1};Ups8BPCXI8lvN!v zkk2wY#RFHVh17x5SKiTg(-OQr(%Y!vAmZjgER(NabEe7t(c}Wtt9!Lj+z1>9Vc*R) zu&9yXKL5Q_a0Y#^&L{Grz&@&9uhVNKo&j@S!kBCqMmu3p7n`JCm2n6zm)^VgY1ruR zJA^ku&JmwyWD;q!!A0lmyDFFzwd-8QnJ;QD4y+NyV82+FM%(~MfJ^7H$*wx&Y9W)G zYwWw}psHGWfmZ|}hu^uqQ)<REutnh4XNkKOYb65XTn7x@d6`W|cGYaj)03)$26gTK z;T27R|NY~8*~4V9Q37#3_gr<r>tVd+DhRzAHmz1tLZo^!fZh83R4nw?_oGaJPZmS$ zrw?oqEMDh{s`%Y`jSx?EUmkTSt2&ouBz@rDe_Mh>X=?S-1#K>YySL^m;eJ|CVWmim zNMCl@?5$M&yH&+xvTMPM0#>86$ps(gB9ODB3cL{7O=RGr<0cd$`0tlqUvUVY{k5|& z_RWe3bO&q15}a)X<oWCC5T6M8trCd;(!bxfH`P64Wucbxvx!Q^D!hRYE}Jt~OKKET z6E|mP?DFmXWnG&nJzno_5=zO<p|_$>Uk2|-LA}Atc_I!DE|f#~jDSL^ptYkT_%>B@ zLzJ=j?mBaI0y7;#`S^!!VQInK#=`dPTXLm>ziavb92j%6zizK$rD$X{5BMSTKLTON zamHYN2bFLbC=7x!`ckJY0LOsLLh&HLwHO&MEHmltUgR)drClAvYr1@c0|E*d>fPFE z|0F%dxbJgT@3MeJ(FeN5uF~sFE<dN;$Qf}~$x*hDqcCsA3u4~c#GBSt0e21FtA^^5 z?ck`+ZsVt)PBn|S2GX0FYgV4RIQpJls5?2SJde5y^z&yA?{_mFrLA}#u6yron0_+q zx81S>8m?O@Bb?KkVSg$hC}_#W;pd0M>VeU;a}tMTK=5>R_T{jFm#`YZ+S=P1oV+90 zKqqKjXZ}0t)%`^mvHC`@!*<F*w3E|^03AT`JFhOo_h+t+Cjc}kO|Lf$bc=IfVqipP z176b4KZf^AG+mDyWr3DF`mhN!{x={;9#A$6x%d4$7jV-jNe`4GHUL9{+JWOo=*Tiz zFYO)v2;*Y%n`51qyQ8t&;9h01Z3$n6js0$S1W=-<B&YB$cCQ|tF~=Sx)w-P`ZPSpS znIU&u;;vKtcR|DTfI)2pkzgi3g6t<=?EhS{$U!q@(QDK%^uQla2<=-xzl3wXe!bZ5 zO?VrKi}413tgE8<8krFSi+V2PxZdv%XbDt)LVy|oSYCd9qV?Whg=!3WmebXw`alpO zVTkeY!2?gXMpj5!Qksp1*ydB!2Fo_UR3U%wd$8yp%++UVF181{)d(mW0|QS11cCBf z){fMT91$mG3vd*?@mP|Yyi=DM5!Mp3jW&p@A3t^gig~#=#%5|cO(bhiJDO8bO6sYQ z*$Y3rRVktCJH`vFkRde&1DA!-DL_KO2b36t>r^||$;RWK6y}jDtZ`=*zjR1z_@T;` zu{Y@ov08rvg-bz@V*yPXW_IRbhL2gdE!7!#d6xGcpB(HZ)M@=}p5%Y=;{H8=!T9w{ z`kse}hpB90jmJVH`J;J+-Sp|IWAp|)&aXsPRm;Ah%}Oh^7~QG3Jl3;=4JIGfDtmuk z*DcsB2qRk+R0gVu$_W?pfM$q;qkP7fBnaq3EQ@B!_8WT^z+^WD{2p;}Nn?{!ha4bk z(fX>liUp7<<<+`BoSY9C@PiMwE5TmiJ0{JNgTZNR%FTq^Aue-(YvQ&(N6(d*=-_$D z<vYzEa^7Z88k**b1@cow&-VV@aGzE&8h-yk{iyOld;f2bb>OS8kPr+sEc?y`QJ3uM z?cnd)*1dhb(FVRNa|sh&!Wfm_UPA43tt&20N_zbb52K>1>_%(S!BZ0|0PTqjE1%_w z?`LI%|K(TR$g7~uU)CT0nw-SAUX<Wn?xx2g*G?BQAYFBXo#^8c5Hwm{<FK-B3(-d6 zfc!+riy<J&me$hI0R){PE-M0XD%=Xv*-22gk|qC1{?321w@umq*A%%$AZs5L`APOR z-}uKIpDfXd5EVTNFT^Riv9a+}DaCb4EY~V}HnaWiZjACvz?1@ag8N3w|0l{^1W@6H z*B!OCw%))kgbIIWj;ZR-)Cr(HLJw^#Ih^2ITV180rJY|ny|=xDW+ixd)I^4sSZQ$- z7WZ{J@4PPWMDYALF;KJ3$O`3k*gbzl(|nQ>8OOT@UB5<cYbOm+N5_v9ejt`)Lx8hU zs2n%7o)mIUjfL2reSzxnNhB-t6^r8BaB$*1+<9CQx!k6@21Rn4LEI-8PnrX3#Dw3@ z7Sr554Jl%M0aS&vsC1<!h{_@}>L(9BIlc5(l&ei4JugYeom!U&*$&s;a2z&emhlN~ z-8IOIh7@P3IV*y1wb2%$YGNwJ@1z%*rTlj7%2y4(9hHnb&H24n=d#?+G}7;CHa_rw z0Ou7LrxGIyzxhav21Vj?T*Bj{%ixm}R{0m`OU~F2CqXYGnt7SDw9U|iN@j$q<0hIa zjdE7EyLa;Yyxz#ap95-SFxgM`+fhbvJ2N5>y*m%h59$6Ot2c5=80hFM)V-P&C%mT< zt5!kkPe7UrB9*enEOaPa=RyH<|HRI7>uFYOOqA$eiN#mQ6TTX#q~m5)&b@VnVl;^U zTxW9|ES>Hh8SE{2FgR?+LZQitFZK;@vUO60;SsU6jVLH*Lb@Es6~Ns&Rm+n5^!LVA z0r&SQ@sevd^tCh+Q<gT3dR3PeSa;uKq%h=~Lo68|<Q2d#=SoT;roNPHxk4TW;8lL= zXpZRp{@@Jjshs8GV@|L@E&LtbiS6GYxgZcSc6w`ses+C?YBKFz3rKw<6f7tJ82eUI zk`cW#bcmD{6Qi~q<gRY~sE<V#mXse*ae!b!6i=~-DbKNw_W9Ve52xmtzg^s4H27FS zsXRa~JU~7DTLY|t|0xxW_~E7J<)x+;ezO~^DMW+jRzR8mKIN3TrKR<|x0!~9tYkt~ zvX1v6dg7jQB@B|PS#hWuUuIMivH@GtEr$(H%AvN*t1wn2Dr%<6g%PcD;|wbH{bZx} zH?}aO#m33Ge~Y5HA*B7MJhA_kp8lKk%M)DOjE494!OXpVU!FS>5fMGo*&Q615t_wC z!8kZ{T<kPU<qW$$lzGJs$ZbAFM5LC#Z`)5SK5;#pkzJs@CVBFtpkQYne;uGO*sxDl z_W@uypyKp+e#Bo=!KfiBqalgMZv3i+?yvEt@2#=YT{$Xh{aD0z3|xXLa|G6W$##P` zCdPr|a%XW~UU2ILqvo;sfWcCy;q`LF3M2P%-hcr<OVUhh>r;z!S5kcdJ{sTHG$B0i z-}i3hSFjw_9fn2MtP#i)N1oWogwbO5_R8IeRVd*&K;4=OhW<?|U_IU0I}*m;j^+pk zM^52+szscS_h~mX7t2=8x>dmHmff_tggBLUI$iZQ-#4>+BgA2N46`d_Nqy5UfKmmp zRH;>)!r!Cz^tZh=SW+zBzWqRb3AkhukBKvl8oo*d1-YSsVhUK_t{_)*V^FA`OQP!c z!rt%G9=@anikGPV&Ap|*h&e!JtF3L=`d!u5#>kDVw6!#|T#IJRn^><lD)ZXitDNGk zWY(>{A4GS}`EUWq_0yZ2h&jC8z}RV4SWj0z_6*73ck9)7HE0|%IIK6gEcEwiZYd8A z&f(yIshdAVZ$zXw7WDsjzhG&(Efo7wQbOWuZw#(EXtXf4H3N$h?8eCd$t~b-_<wW@ z^8UI7`9SIAl%3)Gp>#K~*n%N}wGN0R6FUY%@fb20zS^3ZA@hA~;@waFSVR;g{9QCS z)~vhUz)v=)aq64yCukwnp9bdD$)R_NY-e?e(Y5qLAk1A!2^Hl#6SJRx918I0x<9kn zAGVVSKWQzQsox)3As;uT^kX&19ZtcVutMZ#nT>P~)zvn|oZB+qShUO8|2;Q=s#E{J z=mk(!*++f)<i2v+sJ<`J*^Pelma_T&l2-6d`u<f-f-_N4vcGuUN}-809y8rYR%TZE zlA8m!?nCe9;@fvg2boI?=YXdnSpCg^-eF6?Eug}?y!{Y7r8DKjtqC%rYHK7p_N7Vv zzgUeJ_hs<SCVf$tm(5P-xZy7~73|+ADzf@E^22u>b{k$WF?k`bsPy%xedV50-MmZX zTtEkj`%zKxPN_QAW|Rp`u)Fo<O?fdUIil{eYrEg<t8SCqO3(idTN$IVI_E1UM*kOr z^M55GRx$_*3i8sjP*4byQ)Xr0Z#_66A^>u^Rd#Q0Z(L*1D^404I0!dDvY+ak(bG!c z9x2m)h(`G+|7B4)z5?V$HbKe+GzN$GXnYke&8up3^~8HZfEQ-4UhO(OG$bo0*E+EO zaJmP7)N5_iR|t>AYG{Lyu8`>hH(=(UW@1qe+NsKb|Dv6*yV7|>US#a{P2QT}hOmU( zSrdK__dST+Tav!Ud2)Ea0Ucg*VMUi5(i7*=D<_B73Y~FDhkEI+Hh*I0yfu$f#95TF z&qQS@?SP80sVkR`_A<IF7u{ffuk|`qDwiSkcpdyN_pKYR6R74OXFWM_Og6vJRPpjf zJVN;S`{SJ$#xGs8G?ns%!&Q2Ta`*?0UAeM(Xt8qj1@1$p=seQ<(kN$V%gebu8)c~3 z%(r)%tv*;<3cM(I{^d$cJS#$V!U3{9p;re|JxY8fZ;<#I(bypBj3xjHS8zTSWU!fB z%ScZ+4OVX=8<z5XED$Wzz>?E;<g(waPZAkqF1pM_Wsl;>JN+!VsN3XJ5j)$7v|VHO z{?caCV$Y%4B9cZ`m4j7z`8FXFqmlfSs13Cgb;h@fi^BpWC-$M)5As`<bAkDdA#GBR zw)`LHQ7u6xewCZ$F#Y>$%g%m=uf`*xWNDHunoG&;rgXBVRZ)rUiFC4wuo-Uo?%WK` z!D2}9b@KQ_2DAeKEuAC_EqG7I01`g=^MkJiXTskaTg9(oy(h&MV+M6&!Qt&T^G!@& zUZ~!R{KSy6deaimqpRdK5y5h36P1LgweJC@%4V`s(!fB7VlHp<Za7$9F3e}kqujrH z=1g#K6QaGy*q>EfRreaH)r32j8+^HcMv6TRo;L{nI>yG>7#Jh~D&~w{+w|ocKSR?- zlEjoFlzt}PvtLb-rbyV0D!OWiLfR7p6Qfry;`FTyc&y2HM4sK}3cARJ66{h)7Xs*8 zZ=Y7vrw|`Yqr_(^uC2mi)PM6e|J&hyorbuC1f;?Jv5@TN_bf@Q)vxzX8IM<3ryR|y zSq-YPVad=*rcl)cmH_sLIS;w{Dfikp9}55a8VM`YEK$+7CCE8kIV(CRySTfz;>@5~ zTa%ui{wBGnJkd51=3r7<O5l6Av*&(sU}~+WS4#OHjE69uapQdO`bdC~Lv?7+R0e=B z@g>WGOl%!Esb5nc%zazQ@bl9aeZe9~${qih>|WW#ghqi9viYJ(h!$Ac6Zoe5=32s{ znX-=Pa4<`}{fQ=j<=X6SITlYjcfRUoe}m+f9Y5Q0THf(DI#%LgsI7V8;m<)1a3Yi~ zC4j;Zs_C=PhlGPqu>@>0m{W$uH+=T{MaTDKtWZU+Lpt+mF)h8Z(7=4BsyE3}US7?W zy2q>rO<~>Sk-Mj}u3Ph!p-VD=D@anUl1RsD(jzG*k<RN1GlHqqERgcJlm7GN=d)NS z{b=-0MPcBJFeeEqt}jyzq?`OZ7l1kK<|g2FAXmk2)j6=-`N?;;Tz$v`=3q7h+s=Qr z76O`<-XD&(bPOzYGZs;-i4t}z-7KG$o{2XGO(wgPz@s^|(iHGLrIncfRc$tcrd_T@ zh2v*Fn#VfH_C&F?WX6Lbt-y&Qp67)?%`qgM(orM-jlS9)F*8$HeB9yD=%l1EFynco zNWBf-T(1z(J)jQ@LuhwDfB&!&0Joz#Qk~@7-0m}=Z2cP5_?%B_Coql9&bfHiV%{IP z$7hJ*IRU5n0=@+NOc?l?+}rim<ztI3-KK!Tn*G*i_r2%2PyKc*-mmhY3pH%R1(A<m zYLk<pj&m2Zw6y<#_Vzdy{RRlk%VO8=49(IiB$LvKViQD00@H$I`%Csuf*nn&qr$_R z{h9iS^c34-UcdD65&{jFy9%n$qf@~TyK9QpZ6)>7+_UccdDNHbA2u`NVTkbXi2IeC zt*qp1o?N<AE!i6HgMv`pqE;8y>6FX{vxVg+=}kL8Izmy$X8PQ#ljhS{Hs}4*lM90h zy(RnZK(yw+zs9KlK@8q&&p9L*v;|4$FHtMT1MXUo@6JA<mZ%Rq$Q?wijbI1w1`s@d zZfTc_-=aU=IENGSz~tFX0hGe8Og9Qd3|w1CToPPkLtB>15jY%ReRPf<#3kee`p(i} zgfRC4tA(G(z(UQ%rND;!0$0i7z5PpP--W>}X#rJS<NAM^94=X6ch@YXoWdKgd>=1@ zo@GGMx@$@R3~T{y!+Y<|!|7_ry5(ksRR}p$4aH#HKOupJ;hvS$a;}zWR#p~J9s_P0 zAa*H{iL_AdD3rX5xqCwQBk1BgcI7so0~+f(c6Ud6`<3UaMB)*%33@)1LdH%2K$SVR zka2D8yswz_o=fC(Sj3IAqiADdgiy6mQI%`yO7|>O=FY3N1!`&QpvBXJ)de7kfoO}I z9Gt(FDn-Vhr0Wa9!8Qu9(I7UF$u^~IEK-Ztp6fe|GcOK7Mnp7yns|R8D$>$A2NXiY zjHA&R{a~0MLp=Q;3{svBLB=yeF2<nfWvbeuJ|e=uDC!<RFHvi(IFVlhgS;2qx2Id^ z0B~O%J1V0r;v1e-2>kY8gSaG=fc~U^Uw~BqB_J9XiWYC2oq3qb5Hzr!7GU44430`C zOsJnfKtDNHb%a~lwn1eGDV1_F4`x3ztM{I->q;rI8h|O-e#mFBoMD(o-u9mdgekyr zmd*N#URC65{r9fp%hJ-2-fZQ%ilEFZsU{nj<GDC6U;r#|>v`NKm>5m3^jMblIy+yi z%JYdhW;~X*AqA_23%H(=3KwD3HR5Q?xE=8<b9&{Lf&2<sC&7u#Cl;1QS-C-|-L~Mt zhuvb{pijui$es|yOi<J<m)GwfG&&<5Y$tdLojF?|n!CI2CS08)hoPLIkX>8=Xly>k z>c;kLY59vG(8rsjiVuF1+1G<vFgWv1S|azf;=H%%xrRLU7ibBER47RIb+secidN2Z zF)fz{)~S`u?05bocm8>Ie~Dn(jFz^2gdxGvcVV~ru(AQ7QToQklTQu90uzV&@S(7l zNNj7QP0GAQH0NU7`jG1#AKU2)eJQ(8&il>_W2@+>Z97&bCQg?~^-b$?^1GgU8|qEz zBoDy*m39+bEI8y-qRD=Iin*pXkUXWY^R}&alM3YskNRb8%CoG4(Qg!gBi+^NxAZxn z&rP4<?oEqXIQrx#pZ7P!bOQyN+xYDNg_OP11BG_nROCQ39|`It0JZRc1cCd{gzf(! zltz#u21vOZ$b2KQlvQa9KRI)Dz{Sg!6Ns-j+6s;O0}l@m1H%`u&eFb#Dgc}&g+Obg z>n9I;T8d#n`q?B5rSg9qnLrR7sdg|pU;x}~PcF}0O+{8aE5;rsZR=s{IYtBm2vdIQ ziFBX(oV)|LKs$5B?6`-T7mBurCnthWT6z=_03&DZp|10WR|Q&A^LpS|@Z{t(!7@=r z;7r(gM1!k~;(Fr-O^~Lu9IsZ(5nVUt_H*?L2Lw@If$Qhg<38QTax6*LP2~%KH(Nar zEb?G4IVA;^9_$h&YinzOW?R&l`xD*M+Nw38M|OD^0~2$@x*ScY3c#c{zJMrMq~LyF z!0DNHXym81_v7;qc88Wutyb0Sd&3avu(ENp(yDmyEqntY&Rs1z-FvOAqtlu2>rv#H zbt<Q986Q8hiif<C4h?XkUJwzZ#(p>X=JMtrJk{qy=5yVkT0r5S*6{vRRVg}JA&WB% zDLT-v{N;EiOp_JTK!53cJ%<a@1xihUvKqxv5fQj5OCZ|Sv@HodaCAt`qg6hixwl2% z?|HdA^|I;O{cN%g;B1Ta%86pcB&_F-9n1$R$TKw8dNS|$dA99>k+^A`cG_-k0ZzSu zoW9Jey|h9`{?2+g)OjB2wEc@pjROWvt=>L-jH<?Q-qwTIo^-^C1t6`P1V-!J`D3z- z)8p7oh;7LXDX)i&6tl%}v4oS;#>4A@(1q%)v1$<Gf(%FKHQ3DbpLu+DpB*)2{=!m( z-jh_28HkV9$Box`1mHoS9S|93J)E9p^r2!jILgP}f$!O~+}YRd9dtFd4H66rT$o@A z%Cn4UHtV-`t4{+YJ42WH7J&AKJn|8G)XB~-Ry$J3?Cw`OF#ub!Atf(W4Tgc?zy|XF z{8?dzD5eWGdCgt7?t%<TsXI^E1Y_Feq3&aJ$NeunS3UU@)t7@pnc_nz@Rz9ZF`F)( z2`#<DYP{_&L&V0teSP=)ybfg0SVkl_%cydq_a`d62M(YM&mEUqOXvo^%+xp^&t5f{ zR4a9@UEBp_fW2jxcv`}k_kg%%F!D>~`@OLYa2#q75V*K>t;FJM(n(D}8XHGGBc@a3 z_N$Nkglxi7C73ierIE#J@K{h7l5pO&l9OY?s<s)u=F(avn%g|5pb!-96%g{AJL?{~ z1kiW@0U*em_a`^c=;(Sm&YXx(%fq+V^@Zfoqet8P_0}<>Ri%+3;a-vWFxU+Z#)@Da zIJMXvD?M=&Fe#NR9Si3t>tEe|t1I)<ERo-h3=MU0=*>wo*6`>Ymg2G`6c=Y4pmo}w zES7`Lml?l;X<7IPw|pa<Zk}68g^hFPE%FTj#}EcE(uVa1HvaRR!k5!Z-=9ba_sTkS z_6|e-@e(>QY%w8B4V8U}6XSs~={yp%V6HbcL$2^<k=J5U>OLm-_9PikHkqxDF<qZl zr3ry8DWitn+HhmeK_9E_1&0}H|K~oeUu}I$#~o3mp;AU8Nan~$o&iV=@;b3N>~jgp zWC@+^1xSB2dLL74ad$#4IZc^tHKlAQ3FxDRwvqD1AkCvhW+;_oH;m<bAz(1s>>j2G zGP+2!uDy+%bx_4><68m%<Ck#6vGHL6K43&s@h!Akl%oM`J0O)RD%Y8fxD=)6*E`&+ zUICU=tx)A9FE4Lu1BuzMm8sGdC4l#hp}DkKBoA;Md)#@P_(Feiq!3Z0%T=ra^9xE% z3C$-dp00s3TGOv?6&d8wk}9-D1u?gN6+^={Y#_HlIGxRe-8(<h`e9NDg+3B_AJC8M zOZ;)prVfkW{V2<1H_M9KhU|BqXN<^$>>f>>huAws(?9yUC=jWx={YiZo0E+ri%rYn z&*9vf{m*q>x2mgqkoD5{Oe&8_`E#9|7xFG1^Iae#CRFLdUvgF9u&WfUB|Ih-ph4Nn z-vRp72B)Q-R3aEhGe{L3j(5ZF@@NLA0=E~8Lh=0X89ys4MhbdX(pRo?G6BsYMPR^z ztA&3A{m{z1(+hHoI1cCbdLq@1t}2y%phVmo;9z7#7Yi7oy$Vg*7@c|uc3w~F1U>mq zTuz`n;Ezqt)Q5%3coZ;23z7K^{{Hb^jd{beZH>ApIAp{Adq)&esQO!KBf)WACRdsM zFV%9k=-1lSoPvU+8Cb$=`Cl)yIp)h5N!f+#@E*&TnGWmy-Z^RToQc_6l9|KHhkOg& z(BC`oh<YB7SZ&w;WxVYtWGf|l<7Q<>rSl7U>@j^l`m?()D8RSyadCJ&?AI>}2w$b} zDW<LqK1+O)#E8t0Idj<$whqbt9WNo<UZvq`H3Qy|kYV7V$L)|_z(-QUmM=b~jtBN2 zTsQgnoqn<sS8obW9}Ety>^|D9siV>p{Xv7!#~tqwzVxJIV^*FdN}l53pfz3uHMPY4 z)W}!U!d-RF)ZU6;1ciK;$)sMB@VRe|raeR@GN^YFtq&QY$eOBhylyR}ik<3wC9w&{ zC<^b%JwMvLR4VndSfw_p5)o-JyW;t$r6$ohj^Q(_zv1HAv*Dso-xvLItQPOOcE(WY zf{tk%9r-gy7k^$(wq;QD1!KQOBZ*vHOEGL)S{@$$vZ<4(l&KLo-Ws>)>GyWLPPaC- z`1Jg!ri%k)8NYR%M+}Q^?(7=h*$WX-;R|^B+!W*KpLMEFjJIfXq4jDM6rXl3gF5Ft zkAzTAD+Qbi#p8aPm-xG9$-b<W7UTDY7gLrT0XsP+0dK)aJJk73My*RkfwQHC_#(IM z-po@L&D=#WOj(DkXLmX6A%Wk|OHil{SF7a>NCFC8bn|O^6aH2ZTi~3ax>dm(E(xZ8 zhJ37>C;FK5cwsl6%UTJpn=-hNXGjGq#vhYvAnUnqX?x2>9TNccbe-<!(df{({Ln4n z{F#p79e3}5w$9&#%qmJ-bu?Q2+4j<hzUN#1bp2nphl^?a+6;mp<CPcqOUnP5D3l$N zIQ${)cE1^*WXQ>8qKb51Nzm$-@;)+HHyr)W)zU849EU&OL|nZcLB#c@R-#Q+#TMP( z2|IRP88>jZW`1dtDoqo}&)CQM8-lSzjPE$-<~vg41WRayvb+NT!u4ZW1YlQ@b6(BP z;f^n5t_k|=WmzVm;rDpM^g1E9u~Wnj>UR|f84<SaIVgyqQ4x2q(#y5Z925!IFHd;p zs^?Bt_fE9s<ig>`X<3@z#KdHFd9&i)6N_Td<tE2$3lk7j2i!f~d&|Eknl@1>!W2gS z9h_1Q9F$*ae5y-C##K<=+qR=e!2FP-r8<NsnOO0>)x1U@@!ZN+<GkJC>uny{`(1qA z0XTl`u@OjhZ}CdN3^1Cck}|>>mj<&NKaOQ)z6GN_J}71cl(6Quv2}KL1FnaP{YNm2 zqD?Wo)nTdgN(GKqrPgIs#w?2c0SvsHFE_4H`sj7CvUWr}lZxE@cP;>ce|GnrjXnaF z_w@%wkOLrm1?+$E3I0fSHZ)t^7LW+A7>|xT$z~$1nV#g$hfrxXxgAP?%6kUC_pWSp zWC*{YH<n9cz{%LjMJxe1=K4s=D;q8bl-Mm00LAGB8j-kNwi^dfe-`2V*#Y_{Xy((? zJRei>_L`X={~91u!~v|paAMBI?n>Rz!ke0_>MT;Z+;Yj0u(-l@T1yHq+u(^hKUM24 z{0<iVQReJhSP5q$(-zaH<D!9SYX7$_!-q#}qyJ=7o9+iW5R+HA;ZPgYiM59RV`2zS z+0#{3rT6dN$;ny2dzS=f_Pw6g1Ph7%@Q27LyW5fqR79I!Q_Jg8zbtbj9u%@;rbPIc zC<O`7!{$6cm~{Cqu2+QyGkxpgO5pK1Gx*mMs<c$oZZaiYdp}4S2om?jKC+9&kGi%n zVGMH%`~Pg`Vpkf=MQ$8{ye6688DsH-?K=_S5j$)5N)CVA@AY$JU{1uMq*Q-evz}cu z_Ifq37$n<Te-L*uFJ@d^-g|hk#kJ{+{@-YO>!7ULuiaZEM3Iv2Ryw3xx<R@@x-Ys* zk?ux7Lg13_?rs4=y1ToZeRAKwXV0_W*)#8c-<f^?;mqxf3S8gsd9HP=V;!HBRrLON zYElkzh&M>@?qxC;i?z|ZBvTK2NdDDTB)#~N*f46e+tPs4Uy-n?z|>s-E2qhFIa`oT zzA|0pGi3rB8uR$#e9V%wid8I2D<h1wv$pUS`lv4+^f8|5FT7XUNZ1(|JlJo+TnST= z0aJkogs2|h6upE;rTyI0i?MS5#p>$}TLFVc*-)MB*A>xF5_AG=?8Q8t(0<H;zJ%@R zDn7DXQ$}6VP`8Jb@s?j<D)q$KPS1$Zxr7AYQsd!l84{GofNy`k`4QDk_KkLf+e?KH zANr-#-c#-My@~lgh9zK*B9qELIrsaGjc9gkTpF5W#|JJs0=+sosT9fHaoon0Ru7a$ zht`MTeX2!f>GsL>&kW>Q+3Ukvjrm}hB#SrEWw=~|{vd@Br=*#xTVF4IsS9ur(N^7( zfzZB$r;@4~wTJS?(!qguWJX<U;CI1Y6d2M7$6Dd4V6*bduaFX;jJsMSb9*g>bg@A7 z#1$x9WF?$!dR1N#e29|k!ZkHB`$BDZtS8nj(fsBM`Bje}bFBdh_>TU(YWzs0lBu50 zNGKv=QL2WU>bEzR;zDFVVt+kT<O_GA|17wkmIFe5`Ry~DhDx>s+HBuo5Jha@S`ou9 zve|6b1$zd?-q}szAPURc%cU}DH3*q?a3kR4DsFx87!@3JFX+w4B|JhyZN0adIaKl{ z9xt@xLu#?vJh`fiit9r@y||#Km^QSx9Ue;Ip<WDI=DE~nw^`HzOqNc`6%Vi~8l+-b zLy|FRq>~pq^StC-XMS<6Hg#<F%|zAVAG^92*Az*Ue7BKgv~(2fX3}~s=TJ+$wV!tC zXf@UgW!QPfyq4!%qYS)cLXcPB-r#D-E}4Us{B+g2PR(CM@+u`FjWe{-+}|Erh6|-k z^5`0Wr5V`y-eBVICWC5`wl25gHtx^3e}-Hqi;u;s(00HCp_N=1?G?<WM+VOVwws>F zZ_v=~Ocn*3(o+OPBlb|xN{22jF<J^9uv1WA!1Sr+0Ok)o9Nc34ZN}ZCsY3J$HFb?Y zsJFb%){;o_SX@JnE{@}eZs$>w-UYrB#jf<3unvz1rdF-A9WEw3V!|anmo;Q+%xmRW zu41O1$LAEZ^*nY*>4;2k{u9fqkabhn;{Bd~cJ)|2%5l=;;?9_2W_P?eLJ3ElYy9c` z1YY&Yw8D22$!9p<45WHc2>5jgTKTM|eOvG+iq1EG!<Chl^~#0g^TDnb71349&IUin z%4DDj#E8}Uj;-GoK;IDc36FaT8%kSV$#ghdFz~p+FoJ#-HM=`ghLqU~+*J>3mZYOU zYK{B7&t;Lk2CQD`OP0jPZX=(}X%~p0`^9~vp#^z<U^E-(AGm6l`Q2fe6vmyB2fKWm zWs_c5o2S-?u`2>9N*;KjRq0vubNTqo7x~!k@Q<HDy&6nbot4nhMOt;ZD<_UfNgHC5 z(&6U?A8cBi@^)$ahk}q&K6qnPFaH@)3c|q~D+mtDnrpXIE^<6rQQ2&lL}E|oD1JQ7 z5?B~nC43P^$cDr9nOwNTF4h!eRs-UU<L;as#JP)`Dch%{i*}MU;`*qqMCmrcAOg3H z-2QQj=#J&jq<FYuJvXU;IVb1)S;A~}nL#jlso<?i*k8%|_|O<)>ZiCq5U<(nPM#)K zs66&u0o49A``n+TPaG+7ETAWxA0?btokYO6P=RtsLiYs*&36H{p*@82qZ=VBy|T~S zJ3A^gD|HAS9)khaRE5pl%W4$gD2bO-;zIs;Ql{Q=T-La9eak8TKpDE;w@=lbEM$R_ z6dbJJ=y*an@ZIbWX5_m-F>`PhRF)e{$$aNVZ{T31Yg7%V(J1#k^)lNFsls>3*g-y+ zRI(EV4-gfLNoOl)ybbnUDM0#5WYpM?Ut0^`dV1uNzdFczcJ`-p3@@*m7Hc;cTUmvL zj+T(a|GF6!6v<BeU!^s{zb2vP*Dx|tVCHfC5_aVsy%{_%$=nRunIS{tUo{`{HbM*z z0SXN0{i_w|5g@mK*#83khM=j-$jr3#atmICI~DUWB4<dkWZ640Ib;90DTgJh%we%} zOGL><t@~Po!FPUXJC_}xhw{efLf}w9zth{lAZHFhi3k$ha}^=@cKK$?P(3drDNyZ2 zgpJo_&t!(S+Zg|m_o=R1|D@`}q%Ln$BU-ZARZl6Z;?*@A21DFq%K=FTd6cTl?|5N` zLItIlF%#bh<zx$B*b4ss5cBzB?l{t~6L<Igmyx-vnCtC3Hf`0#D&o;u;6fmxKSff| z=tWxnDN)T23-2u^k*Z>1lQq+Ldepza_Qj8x$mRG`ocO3h#?4NpaZhu7RerEuWfZxK z6b*#*<i`8q>k1+|7g*B<dr!o70-;TO`FAif2SDGUeflYy+ncerWa#@CEUrW=nqR7} zB-)PsC<31s=)pNtPS%`byfOgR4Sm?Wd=pW(5f&C6i$VS4Or#MF1EEM#+P}`Te26u* z#uEz$`t{c3J<<#;;U(~Mwy#^#s!>^5Sonr{d|b*I>9{Fqc?~MyGx@TI$`7)Hy`Nk^ zcwTK$>$aFp?VH!T9*^#yoNK*WeBgppX&%6Oiv}eGOcn#cOyS0^HGL;hw;azA6VWRf z>XnTO#a{C=G+ZUHUq`J(m_)yvJOmbntUhASTLvu&kvQik*%9C<{+WA{jS_&rXC+bT z|E{9A1srW4K}SBlrM)Gw_&`Bn#6qgR#Ty$Jm(ol}-4(>b)Ewym@0!75Z}=NT#7p-> za<g|-R8yB7;%vab5`!$Vlrt>U4>iUP4#Xrrir=+d?)jFAg?c4<<qZf5fN}KXIFWz@ zM%&Yero+s2OF%lSyKF6!^cm8vGpWdrF=f<#z`)3M90mNZ;X4n>KVLQ|p}H+@HIGNH zmK&rbB(xh1Qs*RUCT&m%`6$gcjw`U=4{Lv7V`E@|+!Tt|9P(eCaY;yUu{9vbzp&&u z_{37;st$h23B{U>MqxndYPOeNS89Vv%vov7%jMc`7a+0yd(re{8OQ_fqJnbMigfmE zwYwAn2bz=q(K`dcA~K4L4#o5#WG}4&;4i@7vI3B1NVJ0FD_0SAV1I3LT`y)e#s_II zaev1%jLg(=R0)ZROB~6|#4b7X63EXNX0dTKwy|EvAWY3(ej9Z=h6p-mkH&zfb1DEN z9|__XZte5PLzS4ffq{6Bc{=*4v7F~q_@oW*k016=h<e+$J70?1h{0B@{si!+?g=pH zII@T*j`yXy!aL0bPq^2w5hv9k2fgd$4s=*iv%}?qD*cz=i23EpwTk;9y6knE?R!il z7Ug<XU*$!5KiDj|89WXYWdfOvEnihp&mr!B!S6PtL0YP8BX{xp)fH@58xPht4pdzG zqA@C>EwBsgiBXV*0iw`}!60h7V)mu?>;9DYmmzHUvNAHLwj{5Uj&_-3ZdMPkzulgT zuvP$v3_iXk&uk%3HF5boKT1eU0V(mP{xU-Rk5G&_ouxDwalWQT2Och~MXwCqR6JLq zPnvI|=LB}E@o@2GW@jHNymyb<yud6jMn_Ir`7CpNcW=KOfU#a!(nT>w{&yF3PX&A$ zH)O7UbN_UCIqN+z+U!kL`#Ua(%clXq7S`<1zfwaYwaVQ}Jie6l0zlo}K`q@Jc;H~Y z!PN|uorbvwP|qherxB%D<8kEv1%{q&SHJiI4l4)yUjM0L00>K+t!bBNZ1`wPfRAlz zWW;J=CSa})T2qkCOvvFLR8<wvxv`v;({MqE{0b?B+2h!+tV2G%DM;QZg>3-X&%nK0 zSyQ1?<s6!2I0QPIi$^F(Tx1^=)%SE2@$>h01Hvz`zmf!t0~UgM_NV6pkF8c0)%%)k zvAp{th6+H2eeLeM;*EtuiyU4nW5r_ssQzwZclp|T?)y(57Wsa_J5ZM|xpZ9vzOlh1 z7M|AwD#6@r1(1bij=UIA@xXw9pUJXB0*cP`JQoDNO>7cp`xI0NdF=1P<__?VXXAiN zD>HMYqQ-1A!+kuYd>zv=BDk!~F@H3?jbEeI%BlDV*TI4dE{}!n0<T<%I03QLL1XLc zAAo8*ewQtBOje@X1eq_ltLn!D?w(8;;PX}`#SRUlgOB<tvIJ0bOUFu^Vd3GxeM~9w z;twcz*$efgH6MxsH}8^sNXCRSoR>$>b?3QVZ?DLRtmiY!_6(veD=SN%jM)KbFUXRw zEl<>;l+o29jw*FR8gH~TGyrtrBZIB@ANE5ZB`|LUj_m2O+a+T3p3ezHsk1;-!&kzl z*W0Brm$d`r;ccbv>1pHp!>q2(LQsKjq@$zWd0Al`UH$-Jt`G9&l7ca#4^CGf0ekEX z3K82+0JJjzfzq~f*@A?AE&9u7EwWbyKt36j1l+Xtk|05}<?xg{j(|lscl~hyHl%<M z`HJ!hq8v$l3A&y{gMljW#L+5!;3r+4*uNzYICJv2zxa=G)sD@eC;m~uUPAHD<J$HB z^z_#NWVk6XvP{e5j+v+fgtv?A=*-3ZH?#dIHC3*8mb?0|E4r_ICEfyvF|b_Ta#z-z z-u1lRSm@~FR9V*%T?+sgAUaNiNs~ZZq)u7-*Dss>W*H~A@L~+t;c&r6IZp_;ZXDBr zA-i&eYF@`xohC}arl@Pl5pb<hpGk@cD(}Rj=`w26=`z@=6>@=6JC>fLh8ai#;-C2K zCG=nq0Fw01<CsP_jEcxkaJg~oPxW;|>g~n@ACN8I=G}n$5cuZdQDDG<s<6@Sk)jG} zMFL)XMR`5O$k^52=IE%VBt-ctO(C3B0KM1CJOF<n7lCZx%N`nj{&$m6g&r$u14LOz z1%OWc6*975V?jQ}%1^*y1OnXG_kmwpTLECNAM@jP|6Cmc*TYp>3Q>E10H5_Z`3*-$ zK&lfjwa!!yG!Of-+Q{LT*|})i2Atx~x3yPSD8%>i39xHn|6LKFvoF>#8l6ShijA4@ z{bB?#JYC`fKHJ&g=oOP_w}hRL=rKqqF{0bimiR#va0nJXfQ$l}D#s^%H`+mSA)*Kq zIZ7G&^GyICy+*E*MU*HNBwLLk6A|fNVXW95XZm-w-WLT<E*s{QnZou>>Z1`PQf(Ao zdt=2QLm0>nvj7wq*hE{5>`bR&eezuj<ML?~$~<xV7XC7-G;UQSmSDiRkoq?i#29^L zpO_GQU1S_LL7?#j{?R#Md?}`>r4hV1tjfFMIzZ~83%E-7n3z?r*NG)!BBB8H<Jq41 z^d|oH2XA7q^_+1}XLmO#7Y#E0*86*T=lp1yiBDw;<#FE+37Bhb9vbV=rUrFOwN?7? zYYtL59lSvp2!iFooP(Xp6<JoLAiEH&u;g96^`y5EGf%Z;5{r1XQ;N&$nCkv=Yocb) zs9MhHUjRFE0~`-h((R311xK}`+4?#jJhOW5?<gnlG!A0%aB=&KDXCek^%*2y@WVQQ zefd%L^>qH1q`sYBQf^aP9<RI(e;R^ITsaI|)K1dlVE}$LR_dD*x*@rsx5wKK@@ClP z6;pt(?Gz)^vLc;+8-4gvVB5C*R%4FEM+WCxFVQyemdh=n6<hYOhjb}c8bXy-g0E^B zdnTtu=J!IB_ZfIegJ7nl?JKB?xXLj&y2r+p30gafI5S*3;rvfu7-I|rKV#<aK(Nj+ z6xHQ<Ty@z|zyS$e{I1+FI!Xrepdf1=HhM-z0|^ZJhKBct{sk6N&F4p*c!+BQ->7y# zlN&N{d3J);a^!M;v;X4y)S$Ivpg}V}L;{68^cpOJ<Rb}x33{fvXLt;Vvj`2H6lG)> zw_DhsS|G9*wU0+-D;%G)GBX$5T=kdEwIYv#B&OF%SngNiQ%KC^z<Le!f<hdP!r4fy zsV~L%?$a+dYxIJk36Bmx7%N_H7Vc5@qJMk4JjfGyb(J0HH!umoq>GaO^qexC*Msz8 z322sefH&K=&<qw&Y8TE^Tvn3W`bWvGc1<On1v;KU#%V2KR_<VR2!E^ymq9Wly~S}K z+-gGk&U8zHLccv}i{AQX4-ncdJ$&ndN@J?kqe9ulPv<G)tp-Po3^5{W4RFIcmCLr# z7U&B#8$@}xayu-V*??m`+u^(2<4`h3UW>`<#dZaj*BJ`HYuW;^<ya!)fwpT$f{rD- zmE}Zj^HdszxltJz0%gvyu94a2sY-?U-53c4^FF+BnqiGvGFG~~znjBA!}fS+SAkrg z?~F~A8xps>_<4cSqZ7w!^oE}2uz@!sI3iE6Ok3HJHKsWPKj8Q7cQhDmM!nFypsqlq zova;lfL5B!({S23tMh-oAufdXHBbBW09=A|^|#MbzA7IB?cWHW7G-<U^0?n=lR^7G z9c~>V;nDEm{eHH9>B~UB1kg03pQYv`s^e_mfmJQtT2Dg#vK5o1vTXf%O`jp{FC0X@ zs}cBoBIEEp*wpGxQe9wVqpqRB&9!!81L!mj4u_=95?~Fdi=AuA95JC-Y}x3tA_^mV zlgsn&cf4f{xH3E1JA4S4KSgyW2L%H{X;KIwV$j&rf%q~Fj8JG*UzJu2a{KfNxN?0e za5wJkl)}!e+%Riy$i}dY(0*PQ-qsPYBJ}jx2;8_{f7x$y0}wr57jmEsbel#71$BN0 zD@4EYk$`g{dg%YLBakhuH1nlZ9zh<EeJvF^x!=JHz9FM2Yb!&b7Ng)qdpS^@0qVA| z*ksvYeQY2iZWWBI_wPia9A5-QjQ~$DDHkYMiP8?iI@<>(i49{pP)~coc(Dn_`+OuJ zvw`9#ooPo84((Z1ycRsMRug#q2;EjcCnL`)B{O%;hkO(8>duKBaK63r4wDZOXQh5f z9<%!ys0Mlel0a7Wq9SUH*x=*G&!3ll;le0o9i!}A7_?C}Eb0uB57o<j+<7IaRD++G zL4&Kx4PuzQYq{q4jJdg7LQ>9&60(CMo`$f-;@W8ZCBVy`%hJaHQihtb|8;`Y9mYg& zJUKzQf#Ee1Sk>YfG-P^l3<|YNoSl|m9tm3mOsM(G|8#f%ZWpokwDN^d{gd$Wzgmg^ z?{;nfZ;3qrXI~5G{Y1N@;_UjBo;`*n(y>@|=4#a(=2Aa}U<2@3r#?VT0V<)N<H<u4 zN45TX{y1Jj`orb#w5A(`MTk~pT2q7L?(}YAv*}Qp5;t}?2V}I-@=`ZT>~UjvmzJ=_ z>{v0ZC+snWi-(_I*G_C2C9N<j3Ycics}HB3f?2=N-^pDZAEWiOxSduD_Z07QI})+F ze$T)Eu|tmm7SJ$h6z|S=IaW#<oDa80s{$Qq*tfd|5`DWTinRn*4>jz`n;I9?3KX<r zr|mu}sQ<y*O8}8i=DH8-1!}3>E*)s*qlN1r924w^t-t1V-6BiF8}(UUUbZ(bl|G!S zqrF#&y^kCRa6aunG9ff+dw{c0B>{yLv$nf^Wr2HXFqzg=WidHvge4nsp4AgMppr|+ z^GiADHRl#i>vfgQ;&Z5j*Uj0hF26A;b4q2uSY&LDy67u9dabIC*6@^?vAs<6_wpc# zU0Z^5aM(;^r-s4_faU^}%FT{Pr_#nPC;DW;(}%-v;P`i=$o+D=1t1ck(nl8;M0_Sz zHAF2Sq224C5f1E4tX%a(rY~g}E=*X@*Z^)+?=xI?YV~FV%mai`JzAAwKy*X0yBb}m zt(`Y3N1YCpgiqb3uGdvCX>Zk;ec*H1Y1&NbVYmeRbGFY*sM>bQ@jq%lN0$sIn%OTt zz;M_sydCY!`)k@C$KVB`j{6coqo2a+wi8dQW-Pvf$GRRVusNL41dwO~IkH`pvmG5u zknT-@F=V?xOy#LQSg0!!4s`w&7!ed6-gQ+pTixP%d@?oCF<T7*11ce-!dk_r&t6bC z0Fzq#YUzP55ar!`dtf+DcsesPGoSl;8mryiPZ$r=-&YQIhq0qBh@zn79M4yc=Es}^ z1ihhokJ{x|G5D_z$htzXFh5LzFmx0m?y#>-9?m8MX|jJ3a&vR3l^(}RZ2=kYlBgw& zfcXw!-YnHh+6Pg}8nly2|CBDYoVDkX-ka*{|MV`~Zhll!J|4Y{8%u7wy|~<&CVZLc z_V*VEBp)+Mz#y~~^^r+Z&WZ5Mr75a0kM2g2Rt;Y1Vw)4irJt{X9qtPPIfxc^yWR0B zw28!A?r+3Js-G1nb%kK^Ijw8~ZWl5!zx~Z`jXFxttE)2bse+iYGRq#-xVE|)g|}Hg zfOvVD*nEF;*4-G0d@$SO!8qhX`VD#r&9I2?2lO<o!1;MSa?a+vbL6X~wvN~91D54c z7&<bF;)n$q#OQ!^1%sX3?B)LQ<;&aKTf~@NlluVK-o-n9{kJE4IH%Hw-UkN<J`Ze$ zZS7qZo4<vfO)t}$?q9y?rszzZb=kw?G~2RS^=@%FY_9zn)`od{_&BKBWU>$9WwU7& zlaDwZHuefNSO80755VWVd7>Su)k~MQqREZKiTLd+m3jbK9vO#0IhUk({uG<8ohfDl zp*Jd^?Wi6JzrlIi%El&gnY+r;xB?LNwj_jv+LNnxZ_jsuFEs4fP%M($@hUebCvmUc zSfG}~&Hm#<*5VgIi7+^L_<rk!&EfR(v$O6nIjOJU#tg^fA^>UdJO;j=*C#3f;qiMQ ziCnxSZ9aisFR7cp^TQ=ECq>P3m3-xdciy%|CE9tJuE9O$O$Ppqlb5?3kO)E!{oX%l zwLBq)L+LFfvJ;tWAklLTD^!#;o(*!>`IHp=`Y6vX<Mx91s;9E$6KyBV*Y%}Mz+!>+ z{RHcrPP-fit%HMv9w_VBj2ZzbR5h&GqR>mLu|VrtXM`B-nGtX>q;m#y(D!!tQT9e# z9ZdRs0u+mb``jd7ipU_9C8p)i)XiDoeNai6C<3ec!OI}e|7>sMepwj1?gJ?)>BNMp zuSw}^E6j^;?`{RCI9+Gb{~kw$xfhru*<+&cyq=yT?GRg{qH5lY;h~H#7TtEE5w~N2 z?#`DxX?^_og)?l`_nuM0J`*72+VxZUSAARq-^q3HYXFjGx;M<Rpsiq(7GW{`<AcX? z8w@rb(+8T9>(FctA&Iz^$(q9j02`q5ZazKw*wp@0yVmR#nPHb<sv_jzfV0*&#GO{+ z!<_ngP_$uoy4rTmAJ2}s30>&9wx2$MxbkQ7A$5v*(GbhTgtiddAm&##D9xU_#yKfB zESlT!<VKzTFEmv4aHr|p%DPV!Ol=2Hd(0I7uI()}<!DU~fmb4lQaZujc;I*1IR}vl zROwisQMZ09$AwW_$F3mxgYnAa!~67>(u%72CI=6=K8*lN8?biPDOGDfE)b5-W;It! zy1~Z8G*xdbJf5$zw$bH}L2bJi&fF62adfVj@zDG$|G>BtnxS1+u1>Nb8ysr!C*xt< za<U7o4nw6RYcRWL)Ao*I8ouZ1vFXzHHy^8?595`+_)M`7@)^?=oz^RsE<O{V@@bE_ z1w~{Byf~e33?Tcvwsuv;5I}1Z=yd;NORhHG!^6J}1b_<ISZ;u}EjK=8x7J*xZV?OL z`Sud2wUNbiux(ub;71Y?{unXWjoPvCbg_;H;AN!Hstp04FDW6zyGR|PHp4oV)nAxz z@j}8p=IfoJOch#EY1QZm|Fo3MNzn0XZXkofBt>!8<RuIP*#bz*!Vxj4vY3cU5IotK zImaiCy&_E~jS#Wb&bIwYt5(v-pndUeRc#Lmmg;nKXegSGXQ8jZD^;VyM6~&(3&OEl zVWuK9q`SKtAWQM$2mVV7h%}niZB%DIh6-v{AN7u`_VV`azm97pm24oRqf*Fp1p&QX zn9C4~g;7+o)p*eo-TC)2I5ps&pG#vtY3~|{B=+HAKu~4yNr`qp?|0fNjqV6U!o8g} z%YKA|1K0g4L`0p+&qTUxV7WI~s{sIMwsOt<Fc7im(L$FKzU}fCU!~SNmM9eMJeu73 zbG!l}xY1h4yR<d2Ir5<$u3>Y{4vA41l2?V`v&vI4y}3NR-5A853o$YkWW)bp1bC!q zX>kC$7y7;2`Zi*{Kdw#R{rY6QQoyvg=tUn>V^Z{k`|8FZNO$au2h_iguVSqsmotM} z)ot{jK0QaFcnY8uuse&Le~jTfmG42`NAvvLBB}R_Hm1OpQys)(Cvm$eHdGgRTy6t= zvDS3EeNOgh6&0WSI@J)=v1zt?|IL*<ix}*;PdG3g;t|yq6*^^Bl1=qaJdQgd!jaE1 zO-q_V!yJk|)G>t1Wf3-a?Tb3t-TljUSqR|u#6%Y<&0l=AsBjx#=k-|i{cLCrs3pYO ziK+~G77z%(<CR36A$=|uU@RMw-oN)s4B~Cy<&Y$nHE$9PD|gzB2uAnmnGp{o2uD)A zp$6(Z>mn1hO3j=v5D}Z<-RodipRL2q$IBY)@rPN_*Ou6bylyvR_W(254st6VI4qI7 zsrcq&__E?5OwM@h_C3Y(`?EFikXJ<X+%EeI8M-=FNAnGrojoYB7Rhwl4nsfgv58>= zC1vOn>6J_dHjqYN#2i(|K%vkp+TwJgv@`@6V{G4==sE|U;11XHI@804gZcW;IBL(V zn2>KW+B)9JC7*CnO^tPmKwxZ1Q~3?w$xQ(U$Qdyc0<nn1L32QU!Ij{LEyXXU@qnig za($ap0}01rhmEWV3Q#~H7I4$dH<E;^@lLN&x-cuW>>M2hu~|MM&H<c}>YF(`$(~iq zz>EFTbWo-Go4%T^Q*_MAmI(k$r^}6^A-Oh>+3(K*naA)AM8Q(Er1Ki2yia6!^EG0M z5`+yz`TN5$d=yPh1@XekET$14KNgfjLNYDJyBBr;ATt1Fwo>EouU_;}X)%hgBn^O- z(iOs;&J{a$0I)a0phSq8{la28%w|1`10##a!JDXUiMw5;g*DM&eJi)t7d6{WtGve5 ziGh(>c9~{V8tuF0pO;jZ<cOthaCc{Cde-v-YRA6zJ4q>73Zu{4R;0<b`}@%?Cl5~p zfMARHiA((L3yG>q=I|j6c_qoQ@$A%QGGg{w@uB&2JAKN8&0@6%1Zq5x&~}b7G7jqK zvh^y9an!%Ot~B76C#J*2YV&siz2;@%Kq~-<l^FULd!d{yp>Gw#$`I$zqqNxEWLE<A z!+Y*;QBYMR-m_WE9gP>LNqpD8>I_!myaBk_?YTVRjsPSALc-0#lyD?e;++_O(+Xp0 z?C}CE)1A1!t53b;QtwII0{jxv()b}ZQ@usA&XrapjZV7>oHAFX4VQZgR%r}QMDp~B zC4lNJ3Gp<O*qZmaG=1Q^2c;q+_HV++^YPeBfnTy5EG&fFMo}4U4}pM50=OuzZ(D@? z?HP4*?<T%lbqNC-^<?|C!;c>XXsH|)Qy&kEL-(lj9O*5Flr-!eC>wM&5MF{6?y^DG zcsqbD0pY2DY=Dc08$rPQ#tEk6Cn{>K=WX$`a{*~Ad}aDNCWMzRzjLDj3k=Bn*GJ3W z;;S%=MW;Ga*b8HMCVVY8w_Hmo?{lu$;GySOiO6HPjaZhmzc5w98>>d;mv7rRMDc(9 zy6C4?Mm>DvvBE@}tEl3HImr;g!NKylKRFWgg~!?I@vKiNOu@aL(nG9Z=Cg9}x-|A= ziJF?`-ddj$R60IiqXOP}XlsN#%g}(e(7gQU1+0E<Q)+7di`tbwT>-SL)el>nC2Qw< zLpmPGRc1O_syYo6)i|sBs}AQoYy@7OcNXLM&WFdLSH2Q*fzH;q7uRr?4G^7%r57=K zUa~jdVyf^uub*w6r}DVi4zxDm*gzC|9{7BoSHv->yuGwkQRCe{j%oUy?KrLo@H2lO zzK>?QvFznqP47jfUu~oc=i9`^y#ihsYhf`#-Xt{6YV%3`zuiutOmFhqJjfksfrASK zSupkv4j@BWg^h=37wPQ$CCdGww89gR<7Ego<2&R^$o$TqWpa?uUTb^2k`CS}`sKZ8 zhv{-tt#U^$28T(TxlT4sD~3!i?Xh2v=RH@)=l~vZ%#F!m$Q($I$f$Vy97>OfwqiP* zKyR5)s7?qONBGbj78$Nk;jG5tGN%e{!J<=NN)0qE(v*@SQzm5h92=vKO=gAo=^a0) zRi{3K*Z>Gd98%9;OT_3D!7u(DE~gts(d2>4X?R#z5h)Ccs;(NO5-0Mbkze-JZZfqa zaso|3&~}&p93v*8a=yA<N5Ek0y9fcN8#>+6pdxn>2?%Mhe<S}Wz^?11GkeWc6E-w9 zHWEo^zHaq@INi+H!>bJF;d^FN&-~fiS|#_BpfazKMSOyzlS4<iEP<Fk6+eGlPmh|p z{+v{_TE{60<g<M&Jn~+o&k7T=)Fng*g@`xoQpmpRs5aC=Wab0K^gYV;Dac=IO680A zmGQihvL`2j=<)^J$tq`lx+vu76<~9Knl<$n7pYgd56+ysj+H1iU}fraTuv?=HbrBj zB9i>++}Hl|EFY;|>do3fipxwTwNlQ5KQ;*_t@6hYB@jZ{7Rg|7-+7)INgtKFi9CZQ z(MrJ2q@NHYkeV&5MsSGte$8v2ZPtNdS&|>)cCvx?(l)r&spIc}bXi#bd<;OZls)rZ z!s$CLz1`&q$<Zn|tsF(_KJTxSK-<HbHpnG)Yk@GO5gnu88b4hyBBSb)FxZK$^67Ze z4Bzd`r;MU4O(}JWFr~=`B79umeCIQL=<M?$Y4}R}zPb@)B!8a)K(w{|<Fk{?u$DEG zIB(J%5Zj!{pf|GC{O-LlBV299vfv9FIy?IIo;JhQDoYN7Ov58FwNG|k9i=PBF{7U2 z<=GyuP~O-mPwEeX2b+t@_7MW8o)IE+qvJr0U-e0^w0)QZkTZa-mp)XN($G}j!p8xl zM~%k*0ik3m0<)3K>2x2t9%->PmMFStdUOneuqg#kr=TB52dIEzusfZV5+zhiwwlh_ z_<7l&?7F-#B%Y?%+1{5{2S9V}!aH<cu6E@jU%$~-7Z3k5%>q+S{qVt@sB=+*mkNu= z<=}3w?sQ`?iIUwSP%55=<nUy1Mn`9WrqNtBksj8M#5FIZ^9=;Ewv*hn+N)>i1sr0K znk_}~5!#Q`P=uJtxoHQZo@XIlot}~&p^F(Y{ygcGq4?k#o(#h7$&pLPWjA0Ig2Ewg z^vePc%3yY%QuKVDO2s>xS2QvW)z)Hfh-q@aga@lsGnaiRKt@5VsjgP7g0(6=8+dB~ z^Qx<)Z)JQxvrGDz!K3GbzAmndLERS$g^NjCDRDhSD=syKm4u3F7P~Ay2Qd2XVyu|i zN8h#Zgeak0SAbYW6$!~fiSTV|O1;roo5<YYRbffYKd0dnLr^+G@wb_;=R3HRghRya zltNp#nlD$7ASGXYOuLWr?rte9Wh$GD3%s;J+!ir!8lOyD6v*cn4PlolyMTv>r77Bs z{?O5Tz_VuWx_K;T_f=}LSiLGP4bqo3BE^C8O0A3PPiLpdO~?ldiZg)i#G7E%0FF!^ z=RH?;50B$nL4fP)AkRGepj#&etvkh*81T8eLSti+Pn#=8Y}){io?sLm*Bu<D44aCL zA~?wgJflHq7XcvwQ$xnusZ^vW1%KhYOExZ`*|eUc2Nwa6N-Y+43!HzNm99x&e+uRx z@55oLHFDT2=7-FTmuTAaT-l%5rG^Dv9j2mK_ybBVo9Z?|R|RlL^|MYXZ`^*AyPT=o zRV&fy@c3AAd1xm`Ci*p(P=6)%y?p0~hzR7-nphmHVHt{U5avN%E!#s0lSuDZWREy( zV5kIY_9PZl@@pE7?YU{66gErW-Kwh+%fum5ig`F*5KT|e7=W}I)v+~Jhku}t<9)KW z-7TAPT(5L>QIOsd@MZyU^rlQ;`tS>D9C9LRg~IQxf8W7{3Q-2PR%||q&S)|JB)ebg zC2w}Umbz1&0C+y#hL+-!Dq~*+4*=DBw4SPTTLjtlxrBfi8O%|=lE{zdS)$jn4M>cm zwf<6oEFqz*vBIGK)4+{6ORvBroRG&^Qg28~lZT*_9U;bBqEk%j3ghx%zDHutT|SMQ zzUHHm3sdM79~X3yexb?(h28#KfL66c^Cu3hp~uSV3h3M?@>LXP#S77@L>rlxFr8;F zPOOz_REn?ex)96sVIaz*$2ip0xT4v<ai)1Olt!EFTAJDLT_%a3XA|%OXS%cDRco6t zTfUkwQXGAlpEl4_>{1pRJOcONS0f&Vcd86zSS&99nQk+b?N3k7%k(n+d-srZ9nan$ zOx}9{Z`0YnbJ?PpZ_!Y>vh4rGA-WwX4j2@RTOSYfn3<{hDC0-hcvZ43nt+tiOnY6w za0=$16pQcM(n>T6h<50O?*4;znd;5;zOQ#VSU`7(Y9{7qH5*el|D6qQpU&rT-j;v7 zGzREth=>k;O65J8pS;K@q`jKr6>q3nr<pWDs?=2Y#NVletq%X-Q_C}eYkZE%I!iCb zp}W1Eu!l=e;ZiS2THWluip4ML>3K)|_n{q5N<~)5N0OM&qO*FR=eS!X%5MoAf>g5~ zkZf>l6&baf74K#!7j~8!SrT~XNr&m#AG${fxUI5XjXQ>wa)yGuUWOAeTOBTV87L7; z?ls6C1DmIpz&VLC4?lu|r8cvoU32yT^jUC)@qijt1or7Akb1FTTpDl7tIN6FPAad~ ze;Adxw%63yoFCan^oahL@y*_jPFwI%m<F7QqY>K<Zu_%Z)}E5u5F>D4_c5&&TZ1wJ z{biIU4xmIeQgwEf0kOe)#z|!2`J{if^%E?xiQB0=;+8PyU?Y4tU!{oK=0T{j4!|n! z0Eu2K5;qiZ?ukTl&v(WZv=MbT_&pvP%iE_z5&1^xNA+eaA;D&^NUv6VBC#1XeJzWv z^sUrUBro^VU%&vYH@Y6&?<-3@_Hw(d08r<CTv-MrRDjq-J!M!?6R`8Lb9C(VckMni z?+Az-o%|aqAGBC$m+C5RwODMeZKZvhU~NZOIc(D6JV?_Oo_N0$iuD_x)yyn{fa|E+ z6LeU;<-G}=NV<ERP?@?%{%ylV4~gqSohJMCPU;Gi!SK*Xd}b>%`o7S~N-I)^RDhi& z<f)9E)m$^N&5QR=uY%0a)Cx<tAhWrR`k|5cu-Z&_e_YJ4TZK2EK^~R^ps9NNj*tJP z1z3%7QkO#J>)~Pw%MtfR>;A^RAJ(k43WY_9=<SkDT$@m@5DWKt(5P^lMfSSS7TGJ+ z7w+_nMc^m`D4dlAjXK3qenHuzqcf|;pNOxu)HUTEcTwt~>%XI6hIIf^rE?JS`O#ZG z&D(82uh6VaG&JE34P)(i$Z&tgr?7CX!81><L^o6wknZwWEH~aXdfNOghPhA&Ai+dN zEjqQgq%Vk+j^%F%3*S<Pq;okD9449$C4b|w1Sl$#2b=EfKA$n0DcEg}&Mb6q;!ymY zj2A@EleM8HpGQI7gZ#xuDe9vA_8LqSVz;H%pD&RKq%htBsLLnWpQdl7l@zx%S-Ipf zsdX5KrvHVk_yWiZLX4wfi?<gZhxJ!NA|fo+DhtfxHYWhC>3zA%CvT=c1w>L?TmQJ$ zystU_?&tVC>(1?leSmq><(Ix!#_zu8H;PWG5prHFv#l7?WecJ4emz^L0q`i({!|mX zpEQR9-{6kzCVH3Im8A=KEi{@pMa9f#O8onNn%UL|1BHIRRNu=pq|*;p8+f!%r7V;4 zr5K)+t(&UHjMikfUDOZN=6^NsoTJ7HlYAa+CVteP<EP-@uePn$=!u7}qSYEEan1vp za->p~M(BiziOJzY6Rl4D*=U!fq`S5n5MWuH?_hbGmbMW?Rl+#o`gRj7*mjl-R5D%5 z1YuOXLyVxuinfOj-@2p|B5$f^S<wviuoK0*LcPqTgHyjO;SghWxVkF&bfGsleMhj+ ze=n1KcKbz8xKzM$B3HNc^Yd+rY~GzQ>!2~Bi@KG0?b9cT&Hbl78lY0F%={-|@a)SP z?dXwxcx2Zc(}9uiT7w<{(SYtcblVSTw%nYY{na)JRRFdn&&bG&gOJ=NiZyB8l@Me> z^5{pW0QijKmo?#tKc+lYAx=R*q2X+ppn<0N3`+2m&0)suAAy1I4^V;nCFE|SAF>2* zVrojOdj^e)Yj;vrAr7kbSl%eQT3?!VIryE_umrkL1Gb|R_r*Nv8ZD0E*A~n07t0+l zDMpnsKNg0;?5wR(J%osi{cuA(B3cF98NfBvC^u5zo(xT7OeG-fB7uqYL8urrQe^x3 z#`25LGe~!G%cVRVTa`}r%BvWL1zY0yTW7zxIqJMP03F4I?usH~Mi=k#xL7?yj>=0) zVr@iiu0EvEu8m4AQXC#0e%x=UsZ0G~v^X?Cw5u#(-lPH!_&FxFDz)OYP+RBPW_u@R zXH}o?am6~+(43Tf7R^6bj<N0Mu-6E6>jUGJ%G#rtaImmAc(~NRVvR{hLb3TnT)rlj z=<4fHH}Nc;cYS$&f28{SmEk6ts8NCA&QRhZ*)(n1T$c#nSQ1CcVsEq0kXlCX0Ji)m zYp}%vCA`Yj5Y>dlX>R<J1)KI0`}%h{u(3jImeO=l16C+EwpmOs59guFl)_PGnr1dO zjO<;%h;fU@bQ;d_xE+~@Xc`wi(r+($byww*uNtC?J0)J|Cq&_vRa>Sz?-WUFTG)tL z9Yt#Qfu+LJL%zo!ovk|K4TP!PVD<{;wF{BBwX5qhv}zm_EQ+c4S;X2#Mr%N^00fpa zK<oR!ihF#ias1E&c-DZP@<M@oM5qaKTYLY0TCN66vCK{kmfyRaPV56Q7P``KF2E0e zVBXovckccBp9H(D9`HZmSL@18X#oG<V(pCD8HAkL|K<#HI~}N2x^4qHe2Fgk<NIiG zGO~b3ocT((f(5Ue!#U_(iM@7%bCdY+f=>PU-nldY2@gy57}nawZs;^z;<4Ru=;`SR zvJ@9XP;`j$h#xogSlF%R=*&o%n2zS^PKEmEHR?U*u7dx`!J_`$eb3{1^k+SB;oh70 zakjqdvC(Uj*{z>gE+T?ni#-tw=kYe%pev+Uy_tfazu6;F&&s-j-Fj5r`PFb5U;0T; zdV{l-ldY|-iw~b!Zz+Jlx}9#g0ZNYE-$#DuwTz~w`*rY`qY&DCUW5SY(1^nvj1hsh zOs`fQ7O*<*VCPopwOK3{j)y=!_S36jYs>7PfKCh?nKWL}3}s2ML>CcURaTCwXm%U} z#iUim;WGH1muC+AhSCXi5i-u8+33tW<mELPN^Y|6Qbb2b_wu?Y8}ffI_hYm~k9eB0 zP^;yq=e0c&-dIm*Q4xK$5dcjOrf{UPnd%PWvF%J2gdT%6?fc6`M6j_zDTR@k%JJ^q z##Y&?<wSAMaHn4<nds}`G?v4w;Mifk##-lnF)*IVrd;pVt9JxA+?$=MUCYTLpVJL% z5KsXoQlIv^2eqcs05jOlt*K`dR2@_0>$Jz5z@YXTv)?rS`qZ@svUq)Uyn4XrF=;d9 zXU(8FhD*+<)BF~b&}n5Y4-|C3;tB@~4_HBJbd6?xqlP_l-;)8RAsxjKz$hD?=iwVO zT(AB>UCRs-5~vqWf&KQ3(BCfr9NxzL0<Q}Q=j>)K{;ZEARXirAq>wK(x$Uxd$NiV` z3Iu^d@O1wpzLF`U$jf)Ol_LsrGNdH2v$6u5n%!tSas61nhA=mgIf${g>9uY>!(~yp z8W#8!cJK7tS2PqLKo)+<?t*C}z{7hTWjrsZ#Owi=Lk%Eq4J0z~JKg*S>8;EgTO+GL zHrrn;In4AwJrr;)1><ZfOxj9|X)>P&&nz+IVer=Ny#RkQ5c|c{2~b!;b#FdjpDiDL z<=q#vo|blq&tY-3v@Co_Bk}N#U6&^ehy84lIcwv0(&gDUOQYx3bOEE>c^Bg5GG%M8 zf*}ZP2BtO;zy%NEVvPvQC2!sUTdk4`2?<H-+?>o!0oYp|`oVR7cW*qvYBS+DdyyJR zBp`Nkca~J)axfPj64HJZNqqm?Xk##*HgPWOzbM30*rcvN9|jm=oksN$P`s}>+vjW7 z#aKyp9fLX?GM!oH?=K2S#HcccG93ZuYQ^da95zJw_`CYT@Qd|Mvm+yAxejRf_$ff0 z&di>hNli_CFMCIb0<+rl7*N>4Ir`_%QDj~$Xw<3ctDR;qn!UWKKamKq+fS8}eog1s zX>{%T(~DX{UAhj&qHj<lZ51Y{(t%r^s=@%@#oEEiiG_*Db!o--b0uJPhQI*@MDUKD z2Y#eZdj~K2?5yPhN5I=a#>y&vq3PygAN=?2*txp;dyV=?X1)n*$>l<?K5)_WCXssp zzYK5{!-WTjtNUeNa5?kyOD=kL!F0ss{RK|@Z)&h0U})v^8{TyJbSMna9q+&j@+aF; z5;qnSwY|ZVn$gt1)v}g%cc$l>hnEZBNO~)-si6fP&L@+&hyZ}b%&-F-oncP|$Q%}* zQ72g4+<ZJ)FPN!nf&CL-pq$L(^R<#UQwz2eP>U0^<epx({Sj<BZMq@dGDSGXlFQK# z#Slojxz&h`Vb5f)uGfA2IN-2LConwTT~}l<cZr#UQM1rli$l-E4=($;S~pA3OXleb z$;cFPf>6M(=?O7$jnUDbe5}mOuU@}?8@SkVi3KWeU8~)M@TX&OL_S#7xcM6ZeF3%m z^d>w72N?;8@bR`&Jd#*CXJa6xM*rIl0GfwIM)s6|Q{oUvHDzVY0f{B*PP-R`f}_aI zN}CXU{r}k#H#qJ4E`ulGaJu3!H87CGoZaDIuO$^A>UEq949H@pfs`OP1{h!r`;{Xj zBW-#=6~dE`71Ppmb+}zb#v+!<#Unz<36+PP4i<fynwrXREhnvWwQ{O|{yY)y0sWqK zqbn|qMBnAX?Bd^ng8#IA-&}z+2anYvL>%u8F|VWR<5%IQ?@qy_C+ybcPlg~E=R9iE zn)QK7FipT`1ia8-SkRC4o$YDLpR82lZHR7Y=vUfu&#g%i+3E%0g(?Ng40_Glt71r6 zHT$0}EN)i11}H<ZjfT_4D1J#qx3m0`$7lD9Yfkg_6uSErzH4PwXq*_fb`L_leeiF2 z6lZ`<{d{X=e`vk|N3Y0Y-0c(_pzEzx{Ejhc;t~@Q3Bfw5Oe(keO;}Q3B*8#T*Dvv! zVzpx34hc|S2nh>mRa(tfS#Ij`H4G#$YW<P{udl4E%-gr<&ihmEa{uI9GVb#@nosAa z)<j-@dAQG4D+r06I%yLQNJ&ZY5AY8s;u7-I{Fg7N4JLN~92GLMjKId7p)4rIOF>6g zBkW9S2>VaPV_a6IphCjVesLX&?f)7}`3^a^pa9?3RfPql4ZFFytq-T`Ia9nn`cJu; z%KMH-Hz6g(<EIduG2-XVrKHa3x}dA#kA5$Ki!MlkJg~+4{@15vA%sP^@lrpvVhGTY zdz0A;94Qpf)zy~U{l~0;X$<ZD`+rZngg?kj9Qo?8K@NWaT9fzS@f{fs1nfKjGclKc zy7~fcpI)mt#W!=39$=dBPfn~9=D%s`BHaHHwEoYSdjBH9{@0AY8Ialk^pBz$Gt?25 zBW7cQn76?3Wbpk2DTe=(^Zft+?|%Ba|94;E8Qf^50cAhuI`tPH&^Q30aja<8WelU) zdB6TJ5M`ybpkP)wQCx`I?QsErwiFD8jidwo{E!Lx%e{ISknq@2ne56zKsV<DIE@Io zovkN-o`MOYvRBB{gzbOhJ39nL)Z^ffr?ni;ti6}=sv;ttM`&3o>^9>K@{g$v7rnAw z_MJLKCa*vV*t#%P?v%2jMHLbnN~@fG1w^Y(Juve83$;YqR^F=wCeqh<S`Co<uolz4 z@Us(ly&^GdSrd5$Bybn;x*RmFxOz?jSueQby<8d|uTkyMeJ^A!-DhyB)UHDNIn+aD z2>3+6gHCJqZgr?OuHB@@YMeo|BHPBAfXNnNNUtvX_JR=Sbe5B}BYUfJa;{xeI)Abd z1Vs0ZuCI2>V;EV;(Ogu}NXe@V%9BC0GI!2;+!XSp!Vma-6zX%st{lsa<dLB7P0HiI z!BvhbnoA1iYM6=$HC#UkrQTB)!IZ0MLT!66gyE)r08CX;6UX!tjC|m3%%6gQeTGxr z53e`M2JT0pQp=;?W{dJ;PO&<E^f~>P7C?7$e*O0FVAf}8V^B+oo6G4&CTSEpoOa7G z9rG>V4XtABQQN%-GO<j3{~LT}JOSYKaX;JPGhew9et9wU{dn_g@jcjf=^wnhyAEyn z_1FZCaWF`5+WG@I`hx~aG@KT2KVmcL67jgZ&Q8dJ#JSoOnquXPZ|@N;8C46n^3cUO z3iTYWj-vmX4)x2WGU?j`m&6$?pGw7QpV7n*w<^oYvA?&9VzKlXxOjM~1)8EabM~hj z`#dg(%Ys5tA_@pULon%S%%npsf<gzf!0%H>M23VUe>j(4?#ZwqXOZhpwbMKj9`7EL z90@KV-Fr^ZFO5AUoBAP7_|{n%9tFd3F@M~$8Zuq#aI3oP@uyBn81dozhdjAd8=^AX z7OfWj*nC&+X<BQbKcK!}(tGsw3P8rCK%SkMc`X8H5KT)Avo-RENfjGcx3{YpNUvYd z_$>Va^K@{YdYo+q<lcaCeQtg}dboA{S>iL^D#L`^OJWk<t`d)ngBH*0koYQ<%VHfG z)xs}ukj1hBg${UdU-Tvn4vn;xsT5$XghU~?B{9}qu$T@FC9`G8&PI59KTKDcqAP<R zI!pUBbC$TlRDZw4Snsk*{<zSX_tBqaV5<t=9sHl3sycvDr+8JWpUPeB;^?Sdqi;CL zkP7Mwg<o>}np!oGCqGwD#QtQVPRr*9ZFF?QFk%*W<#-FWGUAi9K6;(Jy_dus7n7x> zrLrkC{El{gDIAAE`oepAdqy=!sewH}Hrg0U3f}L0NCN(zqh;_qn$yYg*&clY^_x^8 zgV*YYtX<e1R)`@e{P`SvmuS_BL3rcJq@N$GidK+(YE;xzSqBGhA&m;n>gZgShuWLP zMyCdQXh>p-w)I41-?x`2w5n8$33cA98*SeLJ32amzaLV_`?HB}X~YSnK76hL-y zt#?y>d1zOr^Wj2hPryWxCJi5}tAOqP3=*j3oUOH<D&UJBZslySaG*SNx;ewOu}QaI z??=YxR@c*e1WwB-d>}-$h3OtH-rjhBOfb7BY&qQ=c+Y?yTq*GD9+QwT{J6>88Cx8< z=<cSD(Z3&q0=IJ(+*wa<Mt~s?d_N3Ik<WeQ_!oCw1J546yhI^hai{`=aj)CzUY8Z> zV#B}-gVau<?(oMI=s*HiLhjCr9I8uiF#7xXIX#YCy-OgNqX4kF`yltWSmqn#KcmL9 zQ6h9I<rF*FXM(hxoJKuEI#*#UCBUIps99C6ew-cE-^KDJ9*VhA?F)zaIgEXn6ZWsi z<$h#vMB75^SFz^=6IRnP)t`QAC(tXogO2JkttE;wbg=dLJt8Iz6%UVG2M{$gj23w7 z0+9$~$i<xn{f#WMMpGl}$G}+FE^^rxn|?<d7znmMl+BhMV>4*?Co-1&ovaW`7)|{a zXIs5@F|`N0m|tOTme)Y9#^8(TM=~`|_2rvZh1j{MbOI>DY(75n1Ak%p?Gx&By4;vn zub55>9u{`4-YLg;U_(lvyi)ZgENsNR^&6VeV5J=Lc5*y+t1n9D(-oVph}gu~Ej#IK zvMKD{-G2Uo1N*wrg=R00r6qmd)>R=6gR7`QjS9e6=^r@tTFPn7>WRpLUvXq&W5Z<S zRDm;okEXbd&tY?XbVQ}bzJ12Z#1uteVv>}*5AF?6xl$)=ucn?oDBZ_XXxOX06%?h6 zR%{%j;$vP%_De>Jq76pu1;Vi1Au3ok&DCpRIN%R)lA+$#&}jCY?hePJ8S=lyt|s1u zgHPtLrkSAC{=os6IRX6?uvkc9`-?YY(yFz%UX$r9G~VByJK5j-IuREY2lZu*^S-8Z zA_Fm>dv;1gLvZjb$S+P-9+&-xt<AtDQwSuWW0@G0#8d0#CpF`eO3qu@aO!z)YKoJ| zqQxnwgZP*_6x-r=P>O=1j3eld-7mJ@ML`U@?{7cOm3sBaX=|WXtqM)oNne7W4V^|~ zhGcBF*DX@#xEttGzK_)@iT_Blo~bPU)XZC)4?JzCF$RNN2qLIOAPmT7ZA-5!aiGC@ zKZ(y2QmoBYpj`aq7w$T%9w2w6tFeIHCH?uc){6`?JS8eQytA(b_+ZWb9QSX+L0g1} zk57)NSzv->UbfN|LVAQ5)4qZNJYN?Hb8<xdj?whrvN=s2zju}ZU+jtmY!3(~thYZ; z-jgyG;PmcVXoYipn49J*H$9wK#onWxZm(4XeOuq?sA4@Oupb>9lrZld5`Sqp2g82j zfdL4qc9T1jq0u3&#lPmZt$}^ACvzMBa<gux$T29nLmF1vgcD!KeA>P_$B%s{zdv4Z z>-TCEi(WTmfJ00d0N**@+r2{QwY7}a*(gve77h$2;J50XS`;I{XQcZ0=XC2B-LHaN z{7nk?KI0y29iDF$oo*urM~W!o=AzHhvt3Mz#64hp^l)!J1n|y+1bU!H2EH%bn||=H z5?;ss*TU8v%KR4?-sbgMbnA`ujf}<~O$OU=h>6qXbm}K_RnL7`9)#2@J}<wmv-Y?? zp%h}})ssy=<2msK_O&K3@}^B-Z2Lyw>`!7I;CM2Ylo$J+^wZXSjsO{jU0@jDr3ctc zEiDG#baIOl<ucznF|s(p-%Xy|291nDRMa};WHvvfrj~svf<)-3E*&qIR|A!DhKFtz z!-V`_gWLVJaiv@L@=rKMf3Y|CA^2eGbqZ|l8#_DokFA1sJ3tn(0xrWN$A^`!ItNpI zL)$I1B`MRM)LP(utKDYM<wV(B1zr7`+*gcoF({AEY<24MuU}W*qN0<)M(eyI`w5KX zzwZ_u{jh@qG1T%MH-EI)>R<f0Mj)A~whouC1d`F$`&-!`OwB%zZLS#NU*ii@$!COL z^SVHC80OuVmqnZ(v)<T0UpYCx3U^f=7f+b5(3S>+!u!kL)2?zj+>U>qWb(h{H;lTC z-~FMY>;3V2`+G;cZW`snV<2SZV5&|lOAP5jqiSwuM#^e)>85|b1lI>7*B0qDa5FG? z-z>7gA<3x-PD}cUM}xsw0<98!VpSrep6sndfR)?%04p<Fo2j5zYpgoJmXGU6#z0*u z(Ug_nQiG!5ld}O05rPVShWZDP#FMA=C_({fDyx*ziCHtWMTSz6!&1C9RH>l7P2v=O zyff^d((9p9uf&04vR}#06BKL%j;H|>n@FXP+G9u2S^IldYIItPC6IaK)cXFkcvM2n zCbxm=YecMN_7KD|;OTy9@GGi3h8Mtdr_JfZ0Eq)d0pll<mW)p?F-j_vmFn-wcm<c; zL(``Wr5ML*k?GV+5mYRP3Li<6{IeLrNwHLH4ZNFe4$g}Y-x5mH$4hK%!rD|^!Q7)Z z5TLl&a`j3?j#oHY>`*{PXX|`TZiU0Kf#`8|+U)<J?Jc9SY`6Ab1*E&AyGxMn4rxTX zySrPu8>Cx7x}>{7knV1zyAk&3de-{C``!D~8e{J<_#!g!_P(#{yyl$8?>OcVT#B_A zj#j;G4zC&Zd(K}O?BFR)`+i|F!GRy3t$@1OiNJCZaH1+cUwi%&s_7>OC7s3XB|q|k z(_;B76S~|)tTF9ZMu(#JL{utH6VyJ%vaN$$?{z+y{kdm_Mq?(B=?m7{4d2~AZV?Aq z?<c+jyd0}gLR?(JpLLKL62-D{>j2wVWoc~EyRHC#`O_B8@sm2qY`}(K(O4?qx!bba zzYYeb-bPq5%>>3=Q-lU<%?_U>)25Y=_13t(1dR<k9ljV^x}~Z}Eblv=B2%}t>kYB$ zJFL^*OIf23^B6DP5Q;dup00$><7p@yvF)!Y&C;vQfs7}LA+Xuo>HJB<n`Qwo00Ier zR<Fqrw~*{RA&2o<xmH6TZanp)(ZN?}qyzHeh=o$n*Xl6pFidI=PJnemMtrK#EW4(= zpiy63UM8rN&KB^9U>THgIhlUl#L`-m%4x?T5Q9_ov*t&Y5MD7D`Fx*rICp@(tJ=n! zDcz{|=Vdv;M%Wt@et^IA-R_UO!QSg$L5mI6u(nR;v<heo-5Iu_m>iPYFlsc3G==pu znG3@r<Z;G<EK<l3kC3@JgG)f%1f|TnH!hz!N&U^sQPvx6EE)X%6xEO7--bo3-|$vp zyhdozss>+>7)QWyfZUtkf+hZO@^mBWgg<-pm2T2w+sp9j^X|y#$*8=*Wqa*mfusU_ z&492M62UmiC1)?v4~wI{G3J8q-+d;PH2FqGf(7Zhuljjn`)kQB?T2&y&WpgDO-n-@ zw;4W>WhCvxhasX#x7A_W==bn?&~YZeJ*x)PN>yiuic1HT7J`)<<O#(LCt?IK85mLu zO$*hB*3CskAn4xMKn6qZ_1q(*1Pv2IVn+S04%mTWSeqO<Mw~4%_`23SV>5b`X6{}k zEt|%Nmd&FsRQjp-YhH!FD#d0{{OjhY{lozWH1l_R6Xc|3fEq;AYgKn(vvv-(UEyJk z&M;Ejp>QGNA{$Qtr80AwfjyV^HtbZfAiVZ2d*t`x4GsOghU#jAd}hJ0SPE_q^!U7x z#A%j3dJ#?NUgi9B{hJU6JjqJkrjQd<;vACl=np~H(nv^h;bwBc2Y-<C;kVrHSe(~H z0-g}$i{E5Y^72?TyY2eDq^koye*D<$#BMS9d#J!`q>Btuc5!PU#=*I2Pjce>cN!BD z%EngvKe}z6eBO6GQ}mP2y^@;uXk&tY=A+AR#3Ql&l_L}1EA|+_Vig=^R4tp|jmCe* zU+RAr%qxHY1_|+1Y8sdS50~H5CUf#`h*}`V6`$AEaCy#MR1{KAZ!M@7%A&|fqw?!_ z@c$Kj*TQD89QH<E%kZ_=V+>%4z{IBSmsZ2>uPjQ(;8L~9WI7%AFNh=OC`1AQbiW*= z5#W)D*gcPqG+6a9`V^eKjI#yP)4!PJR=&&s0yf(U;rVJYK6x_B=<oI%=ce8ZGc)qb z^{@DN|M{8xXP`1VkB)}xtHYKbI_A_pCG}JEy0176d~)LG1y<?9^<i`-g5)koC@NCw zs-jOU5kC>DDQ0GZeZP^=Kx?~&QGFIZHv2PL+)HOC2@|zQfaqeK)o}MihiNQ}!xNYB zYQ2UGkQ`)R+1H7FhNnig&drQ0?8YW-Er)#wA4bB)-eq`YWs)wG`*;rncKmt5U%`AH zdAOjIH*QGI%Oge5p9#7!Hjvdk%LGFwvV?aEG$=_Z2$$LB?wO<teXK^dw*3&4(!V91 znlYMXQsi%tbx5ELhO+rA0tUlFphK*;FsRRlKxU2cSnr#et+T=MH*L`RF?&!UEY59n z+1a<Jf<bDp8E4l7JG;9xzjZ;yzW6;~Y%#Lw3BH_F*)v=(C~*C$PD=iwvQUoJ_Ca%F zn1qBGRh}Aqc5X`4!u|pa8UD-IrQokz^NH;wOl+p>+J#T0nw0Bv!y<6P@4IJ_(M(M( zBPfxm3ENdVyk2~_3K^gBKZpNk7I3oUR+H1c`c>QCWhEx7g^1rbAO=z=IW0LkDe0J! znd81FoC+b`JVqxuaXQ@F+b3^coq_;4Els2QSR>o&nW<MYp)+@VnFIYihSpD9N_KyJ z9F2a7XeDb@uQ80WG>U@?ZI=F978V{h@_?F{aZ<ak1y?#M9CdkKJn1K1nZlx?0f@6u z>!7J|8(!?2dO5t?<0Y+a33V|zJGw2X8(KM}Up|k>&cDZFY`z+t|NXE!8~pjmv;DA9 zcu739)z!HkX&rL=?*eDSlw)<(e;TgLl$yDD)JLQFky0$b;COm|GYA95zO<Nnj?8`g zimq}*d=$YCGElp+;*{SYA6+8>15q_n{YoO*;}W~m0@jKwYP{QG-8sb7*w?A7b;1s$ z^HO<Lf}tiS@F`Vyo6vUDR=L_(rC!}ZsSnKExe!xS726Qv;oT_U>FK5RGRt)R2)w(1 zpndfQQsuQ)!4It--!mnB0W<yJPFLv5>0&Jq39Is?kjk9*H}Zl?Aq!L$2=(uR{m%+u z+~Qx~U{En}XpLmDr}Sm=xp+R_=(wFO52_#w1G@}><lz$;ozYKL%ZiVmAz_A-7$LFx zOb}-C-JxWL;WIlgwKS`QaY4=Oi@0`lEo@L_x-QrasY2~5$=4?_XFXR`w3qRXiJrNx z>K4^~y|XXX_pDQwraUy3=$(3FYG3L1?TU`bBfUMSUzLdkkRx&0*+RkH{fJ8_R$ttk z6DVE$R%J*V(l-2QLFV5TV5m|9Cq~3#s3>2IMrA*I@W%-tZtC<T5F?WHWEd$_VNkNy zn}4xgZT7jiL;D&!MPM<1fB<a)Fw>0|(XgYH+QdW@+;Sz&4RVd<tJ$#H-2Qo9Qj3IE z`bl_d$;qin5}$dw`#vHRg15tJWytXG29?2spY3LtX-3jn<ocn_xw(CIkE*w*Z;n@V zK*t#s6?O3?S)<h*VWhfLnwOqxcc7|YK>jnkti65J)7*AEf5LXyofO0bLwTsQ=+o<+ zO4x8(UT5=I18y!ZC}phX+SpjTibb5m<Vnrl-Ve%n9OhLkKJ+82Bc3W^<*?A+cRTZe zXC^W1%+HFLXX^6VJO$QGHBXL_{=W2%hhPI3hVoWo(U^9lGp=qU7zb3j;~J^if)hG& zz#92h1kCnrSK0%0-`V75b8<c=tKW^SEW3?l^S*$X90D-WDu3?>J?{wQ1HfbWq$Y{< zbTiv^At52XPP+rPm@oZ<gUq`{*5auj)EUn6l;&5R5g&ek-(0&6^ao&hA&^=F`4zUu z>q_S~yn{xK{HiRq(Y!-;k_W7!Ajp=?9DK~%30qu=c^wtqt%EBC`N$w@0x_htey{jK zSV8ULYeNM>bQee<3Oa79$LVtfC=uMc9L!=(jeHH?BBjTGQtc_7tLR}K%V6}lg9**r z3QW0uL|MqG4pf<38|yexcwvByC^v}&zlgIsmcwwfiwvsI{b8Hs22bD_Od$N#@LrF6 z^hP$A+`?F|bfO*rqQr8Gm$C$M-VvoO<LAg1pnT7A)TNH)0on=xJez;YA@nXk-0ad% zzgqelRMgoF5q|~&!hJQi1ETRcdubK#GuP!L&v|c-R${Sy>nv5QmegypAl5`cR*|_| zQN;tq)C6E7`zrNmlGJf95sqx0j7g9$V(SNX>%DGIcwJBWcc2lRoQC0dVhP7qH==RT zT-jIg82zXyC#wrqfNrwRi!B(m{{p6ZnYlim9$vtOkW1o4V0k%P&YP+KYuRsoJ#Jhv zh*Scc;pUcx5K~m?a>`mu83AnO2kPRTOQSiftsa0E$Y$*$#>JY+SJ5hyZ{n+yun5*` zu+0L2+x7wMfuZyCEcNwr$Z+j3p+x@B433|&yW{&$_#c_qb6K;wy|O=$ZCniaptU>S zzkkAEFg@gOi_dZ-`(ZbSE#Zl++hQ9ye37i3{W;2Nro^N?on0}cF*hM$TI2md1sxiq z2Iyn{Jg{eD9Ie~U=eAeLkgClk@h8BNS6}r?qI-CLSCS`GevXJsMIYvFK|UUc$r;qW z8`Z*3bjOB=C#vcSgb}*#cI~MMOaco`%5413E({;Fn4vi=ml0XtVl#se;yo+7(jOOL zrg)HNtL=9)vftv?EJ`-4ZV?vsW3ssx7X5Nef40FwnW`%|z?RY>cUK1I@C?l8eqM_8 zuEA+6Bcy*R_iYu4(M4+TO{PmG<?*_)cl<q#Rk{s2cpe@u=9&4CS=Y(!;?z}U_~}YD zyS|?@c5Ce!0yaNK2~WT{9jNzQL9lGjwWjr(Zq>C`DDRB3^h}tj74t<y5jXvK=9luQ zsi~-dCR(9ei|qShqgN4egh8imS8(q9${maf;2O#^3gvR@ocAxHMiBRu$ng;fT#sfH zM!Im`GUG96GrLXyu8x3@NYhAbacySRqo8n<@Rac4m9$|jPxvO?Y_r6W?Xdx)S8Lf< zWk9~s9@OJAc0yQ1A4UNh{)x?ROkjMfs;ttNIpB&XCCU{#IVm+vx-D)h5pwqyoq3Oz zhUVfF02_-?i4|acE#TD8w#Txyw8TwAO9vRgfHa{h*MPT;Du+iv=eQx%-$ZZMcPp~B zTWzhab^7#CRU~@3*+*+TCXC>iuU_Q-0-jl!p61AY?3t*;9wCk2t3M!EMm~pItt?gk zG@D;c_vOtOEINu_YUe7aqlupIm(Pd=9<`=~JUk-O9M<Z3t@h&;`ZFiX-*`{T@`{`E zp9z>!8k=lzd7QVyF^bxq*33pTRXcQbENFvS)3!`_xfkDQ{}9`}r5|6f)_i=pE{(0s z8LsI|PfrJo{hQe>=&RGv&6>k`T0S!G!F6HTyzUrtYr_#gR^#VZZr7WIrK><u5zeLx zWi_=u1xeABdY37n>})iDkdh_f>`yBn7|m{p3!SB@K2s6^0~#TUX7xu`8!;x>KP>j+ zin34ks#k|gdkdF)WN_QG1mPeeXOY7uTpV+em7a6sB6On(4E&3Wi%00jOx_KzJl-A- zw|kSt1H1*Om<2L(L~!A7$z^n-nJihu7{Ae&)t!%LMI|MRbXw|77=C(3$EKwI>rVRq zQ9YiJ$E6F_$V6qrrDu^(Px(fQEUI@hkt<<)UNpERq}OXm4{h?Jp~+IILdW%?YHf~( zmC>fz2JS=#u*Sg)rWS`goUZcc2zZ4IGG^$os1WjdiinD~DO1D9>vs~dnF}4(6DkUS z2oDFaYVv^pt0h#P)1Na7SS4j&p|ZdvNW>!iKHhadA^4x$>Rsk54yshh7-B)V(x5vb zBr9YIbXkeT#YOvbo7F~ta(HTZxbUW%N;E{+le=DHjGoEm(^pg&sT<<;2&{+f%4zBb zM!KPpF$<FrkdR17(RaUE$O!m73F`UJ|FlnbP7*x0O?2OD+kWPp>J-vbQBje=lT{+a zf4y*=oA+x(_FER^(|T13sF*d?2R$(kr-~GQ($Ur2cJD?IIHl6-v&_selGb1l*6T7z ziRtF-bQwd|!oPG8ph4N;-HXV~lxYMu9ESZs)$Rb6Ub0i7v)t?MZc7Ud;noLz*Y_On zyH~hrg%Bjf#k*FzcCZ8mUusN-rG_*3(lB4khYTqf67oALZYrhb0tzrXIyzXU1r#3H z-Ae;=LVB@!uK6DtPWAmZ@6g)g;xRs%_eFd`&q=abpaar)3?&r`Is&mk1K>QQFZZ`F z0bz}cEw&I$9^;V)uS>j|8&6M9dx<~as5k64xox2y%l>fhKqsY;3TF}vnYljW5r!52 z4q@l@l}6dpy-6UVv73rTr*=Scs(+HsQB!l_QG5_-`4vSBg|<BZr>|C0V&HsbHL+bv z{ZUIHPxJe0RZ6X0-^DshTboY=CZpzu_J+XqNAVBx84p{;w7{p(8z>n&TdqOL=o3R; zF1DS9in|HPE`bjF5EeFQsZzRK-}fvbLT>njede;NBSt^YevG$6t?`A48J?KOd;21} z6s&njFi^vOt^3LSctO=VfJRKe(0Qd1*Hw~>^G@OJEk)C@0}u*;zp2cnJiXTJ*ZQ-b zLAOpiL%YY}&Hj{GU_jtlCeNshsQXJ$Td-I~?j-#y+vUb4*Q~>^4bctVn@bcffJ`L~ zVQ8`0^`mu&bo1x@eHDI1_Mwn?yKN;ZbbGFZ3aG(osfaoJeg>wNWH0ZpZxfb?_Rb&b zN=h`pY5Q*M3HBEZC>+4IOER6)lzpx0*3_EIFV3RT)@O4+-%QTw@N23uDKEF$UAw%@ z2@3K8DQwwp&+;4cs8GVFQ0H!c|IzW`;=g|YUrMkf|Na|c)Zka>C;!d2#bfRYT5qn7 z^!EmL0)a{=CLta^00aFd+LdUoP13IDq>aO7l`ea|yHBP^GHMq#fCPMnb-#kU6&Z_A zu_7ZU6DLbdNPtEnnk_ZEB@abuY_ahHMhn16a{udRVe`jDy4!@pBO{mEjouzDD;NFx zT%HvhI^*3-vq!6JcJ~NVl?ps7bI}<vNVxU-6AAP4>higL4Yp2u3Ja|!TGG<e9nXPJ zPfxqQ^cpR%H8=42eV=-J=Nk=rpkWVxn~$ZkxSVgApw~Lz9Np*jNQ|cOzFh8&F;KCw zA#(PW$NPigwAbCkD@V{To-jK6z7fQoK!IOpx7-+>$s3Csn<L!S)d)MP*=D)|gfOmu zUiD@Jc-8A5m)`MUwbcFG@Nl-ma;osUQ&_aaH(JvBlk@bqVYL({UG)m>G^J6asi`Tn z@PeVCA^MbeQ-DD>JN4z_q^0%9SQ6~^8CK<ly;UlZz`?=cayhg#o7271Ew-=#2lJBx zmPzvW-{v%q@eFMqkF#TIet;IDrCq~*=OR1;=2rx~Zsi(nJhsO>JN#~|B4Q8jkGiei zX;~NNTLXV!P)OH_Q9pP3i-z*Lxys7P9Zs1E9jY>d2a1}S+P~5~{&jr_KdDMJz9oo= zhyXDr2a`?86Zzuc;#F<>_-(GTHu?m0$7yebPAR|l%s@165lAx^AgbdoD9A#Y`taZ& z21kI6n--S^y;1`>=fGL{GnroH#}CXHyUE6QkYowqABXdlN<I$TRYPlQ3Wgor1MwMZ zc^sJH6~MwY*sYS8p0-1}5&~v$X=8S<6a2jXe#(s)v4DG1h2B!D#?;{VK``TCv|;31 z97OAJJ+|Nb_hq&Q4|fZ(Gc;vJc+AUQZ!^(mmg9E1MomFQGCAI<C?}Up`Q6wA3l(R5 z>rk!2TI0D49FtIQLhYM`m6b0$+gJX|g*pvg!0l`%n~|QGX=rW8kT3!!4R53m4hrEI zCVJ9p{xb{sBhcR7NEiv2tI?5>2-GE^F(Zw<fEve}&~UI3es?sB9fWKb{?d}me*fnt ztA*g7Tkl*eZ%i1Q01zn3g`?_ij!gvxZ6zg^vARAQ-XAXnsg9G9Faht`*w`3LEO-$Q zKJ{<X$)6MzrDSA`SgH!Bsi}wBbwK48OUygc4Jzr+D(zwE=~8%Huf+@_Flo^-F1KdE zmgqab;>mB|u%DWm)G&5*e4mqA>?+aG?sJxsnmQ<;dU?=?fphWi`)!j`82dJWoQ+{* ze0+SUnEq2sW#w81r=7aDzW#WN+bLRDRMgeQjqP-mzfEF4ace73b40#&_<iok@dItP z%$Mn4n`girhk=}-uz>E^X4d!bqtHIyM}fj~fx~KlZ*L5)zWkkLO_^PeuH$yR)k6OL z&am3T?jz7)*sT>iQe)(gc{ol5y*u+E;w58<-U=d6-3a)=d@U;KnY5eBYYPc!&QCz! z)Zw)CecGm#{O20o#;*a_C@7owy|}oY4@!#jluA|QBtc49&{6q&P|a#KtX?0^RSLBG zG7V!}!K?pMaRQ+A$B(+3qgAC=cZaW;EJg=$2IN2L>PS!Skr;nj+fd78H+zk>ukfxI zyfcf3WzcE0@0BtmB+S}-r;A81Ua7Ohabb*JvotU;m#6&JhLMrJG@=5(Mo_h&vS_YW z@^;qd7!$KGFAxUYo~qkr(AS4qd>+jjm$Us;{byK>3_9IqkEka`nUcUH9!mbtb$byi zB4YSnayxuvWaOXXqlt%JK;ZT6+2l7FI7w3z6M$y{-=&q6)p<Plbb%ci8ymZuw&PnN z^c~En5@SjNTq2@TlZ@5qUOSjtpAR}Z@k={WhK7bBhWY;O?e@mb&WP3r{rwV?qY>fv zI5?Q*hSrD!5dXZB=k$4KEQ{#}(hv=N@i0=2ds(e;ZvPzHFACs~7>jhG|Gee@^~2)7 zd$jzopVqYxlIXSn=gIWKD2piLB<3#!PS{*ixqpBDxc}?t|9R5=_s_Hc?w5$i&<K^$ zsc~{J26jlRl*Bp`J>Cr|<A$HE`Jv)s^>qWJypm7XsUsXLY}+;f*;X})*T<Y^on1W) z1UNYA6(ZlJr`c|t?juwHq_nf$55{$XcM>NP7413Tv?j~GTdc#cJLEW;DatvLX}h`l zaX247Ox*p3*Y3HSkk`$r>8l(sxFuJe{K5oPB+0ZJ-7W6ICba$I5)vl;*5h0Wj}$Wb z`u@zttJB^WNmjNG#AL0*vw|mCh2~27qZ}+sy~po~4o=oLv6(9bWm=~^9zUI-42_If z6rG@iF}Wx}gLyc|6dVlY?%DcXweBD;j~v8Uef_3gZ7F9gMu9-g>$?eZf0pew0S7Wu zs?y?l+<av0axm?C;bd{XzOe=F`4zvj&wsq{fA;i0tfhbFuv@8j8;c2ibRy-s964p2 z57<+fnXseg;V}(7EF2shBv3YNDy`7HnhdVh;n{OrxOst|{a%63NzQCGi>Rg56twsP z*B!`63hCU8))Pv$zH#pP(j^Lx(>KUA$@i=@^z<kM<9<UQQ^0|VhlA7G*9T%u4ge9s z!?W1tbsJOya*5({a)_-vQ}w`8*I=TT7KoqA)js&XMBJWFqggGQi<)ho&JEQ=*k+F? z1eP;3!5NP+AHO+ABS!PM9(CG6VO*>WLyDdF?);qjCi9ku%N0}w>dnryy?j0oN9T#u zMgv?3)TMfrC#ya%>Np2g;*q;mGIi#wh>=L!<sT{OnY0)LfThnFXcjH5HUvk!WV`** z8I;a0z!ns9Hk?wq+3srtrj%zU#QeUFcV|jiSXhrSu4K565A42kC;Xs$1yOC@V(w5U zG`>FJorXW0ZnM|d*VEZ8qwu)-SXlOdPZ)`YBJV;yu(OgExZ2<cDGl0aHcU@W8k#XW zX^?7Hh24WA`T+^wV7OBA+s``(BTP)pc?_LKXKrrVCX-=oofaw7NcaAxOKbo!E-uu$ zIaf)_s;XjtfdXv*#PqmWaLwd=t(zWz#-+b7gfkOW8Hx`B{2x4!?3RCA2hPDbvDS74 zLIbQ}<2M+iC|<;Am=;nMNW_d!(K8-*A+*P+(-I2$UI6;IFJd2&@O>lbWEhB0Tuz?e z`1rKJZ4G>(Q3}A|dM%&H_h%z8rKzdu@;6#v<lEcJOG$Q6`Va~@S{EGhB)x!LXUbC_ zw>I0!mJSZ^Y7m}&&R79M#s?{>&pUR%<Ai|#WAdwAwH%K|>zq1Rsp`{y0!@Bzkl0s{ zp`mq9Lol2XPacw&63(ZlXnz(%*wRf-MyFQ7<~bckCLR$K8VVBJq?JCPeVh2M)bsr3 z0W=+-viE*gL!U0Ug_do0f%v8QA~ywW+LpRKcV&5W^N6M8`hqVk+F}wC+%AU!QhI`d znb!|>)L(><@HzBdngPU#8Gn>1Lm#*7Ds)cQ?z6|FiM)7Lq)-iF6U-U{cX+udzWTJ( z!{+e1brsgv`L_$yG`p=m$G9$t5;PxF=y-u!5C(;4aIx0?St(mGHtW0gkmb}D8vv_2 z67f%tjC{Jw3xZi1N~E$+@chxMqy}|9LP14!ve<T;914S%efb@&xw(08r2P*}+RdAc z25Wq-T;iXKt;Z&6iIr<zJ(2+d0s1?*oU<BA=Wj(bQX1UMrPPo1=4<yxjao&D5*@zu zN`<dz8xC)W$Hd6XN_#$@tjyY+n9JL*FlaRob}wg=!{+CbL_X%cmiBq^4+QZqL6!p} z2h(k8=bL@A<vKF}#Rg77k&YNVc8Ji-W|zK^jdguHol@-Gxs9HXb?rf)u-Y9a8O?fg z0n=ru-3@-{--GW{cA%jjTn?wR+0BRwam74ap|i;vLeygwq&{0(EKXyS3q*Q9Z|<bm z;fsBo{jNk<t1l!(lEVMkj>qnZ)9)O#*6O47O&SaF5AcU%vH%6Yy{%9#qt*1-^EU?p zaFE0l?ZsvoKJ<Q~_Lc*PTYN#kzG*s}1A(btJZ}k>QXm|zT77keiGcy>`NO97!_^Ro zvrC^Tt<-KG86NgJX$@9?IhwEI1<P9`Z;uvWHUfk+HGw;Yw{p>6stZEa2;|Q==yYJq zhXc}zd>4RhkznYYi_7geUvG2L;O9fo530jv*L^;#*(-}Fv-?LF66mHj_x+zoX{<cl zi?_tgI0*=U;n*ik{9$>2{a|+y{i{@m=4MI`TlKjzizz^S2q^;><IO%VYH*e7HGEht zi_t(qu>D7xJDyD_`Z)XsTSmQh%wJfv@n&6wYY+F2m3j?4lsijc%$6y%?c#E<P@)nE z#w&Gob@RG-FP~rG93T_$EH~9|Ej6414soee?N)=eP*mM0%|9YhXWe8tiG_tDq+68N ze|<fJ-#MX|y3OHo_kBw8N>(#CZ^=u6djOxuef-Ko85$*|Q5Lh^(b7^gM*wo1^8Yj$ zQR`@Ap!Rp%pTv@?{`~nBnBVPqR1jF9YP!ypu+tc%e2XL&@PtANl3FO|AINb0INxM7 z2E4>TPL1xOU|=iLP}Y(s32<Pdvz<vNb|l6_o{2XarNox9<<0G-lW5Ut7-grRKvd~m zlh@Mn+Q_G5;PczazuaRYIXg&(Sz7&)kWk}x>c2l#WJu#g#EPtuoci+ht8o(bmn8Gd zU+D|T1bm;qh6TZBVUw>GP{uTOhnYdg<BU|lm#qGs%(PPLCio@I#`fe%L#w`dLoD3p z9q{L9-RdG8&S|yU3#eL^szx%6c(?i}QSI;JF0IrX)>R29Dx!}i;LuiQ$XKU!>&FSp z&D2--cMo-Udmp7vs3SOlhc5|u_~MN~ReeMx;6oHR6oz~xhn^a#FV9#H2wHg~A*rsN zTYorHUXYik)C8!{FJHhQPNZ0<Qm9O5>U5#SuW9(BI-5b5<y`$ShzFZb&JzypoK&tY zR1qHrC@Jag-MR9Opxh~6l}5eI6yEF9_KH8tjF99Sil1Ypq*L?prz>x__m$_{^zkc{ zTR3DH;^X71R)y8cyF#KfisZ7i3p`!awIyN+s_kC<GqbaKy|2_`Pgd;NN0M5#cWJ?1 zWnMa3+J*V~Bw8cVy=w#g+QaeH)m3C@#;<~a2^i62)cVoraETq|#B6eZ_h9G>7KyMh z(R=6Hch#geyBw~6r11bV^;{#=T9?wL%mvnRI@R8fW<R&Xt8&84azhi9foKu`!RjzQ z^)0A-4ZF44Cg1EjmBH(yhvda4LKG@cQi?BEe@K*2AX*9hbu?SP^pox<sI!GVIuByg zRz)8Uk>2P@>fdJj7-dPmotp5^BC6j2H3R9#w(k$Ua9bq2&928!H@~!ce;*#^2zU_e z6qc00vr^ae-mDdbRk3w9>8=U@lBH6sC?-7IAr$$Th|fLA$iJuA&eF21s3^3k-=rz$ z*XsDV;$kA%Yg_+OLlYG=zu(ICw!rHKfGy#>pEUKLZ=F}3Kr)D3tJ?}S{vao}Qss+u zbplWTQVsp4k@F_UGGVZiS{qw35{tgxV+-2UFIh*Kdo?K$;v^VPSh+XuW4*S9!dSyo zo@%+4r<YejAc^-zH)Ryo#Si{-h#?!8B-K9i5hv5J@0xY+e(%^28Rg1viCYyls&;yY z0tbQpt!f7bo2W6XJv+NVRC0O+xSqf52nq=J{@ngxUTqGo{+sOE83r6mJ%hwo$zdE9 zk6zZmWE@$5#8u};Z0HI__3|Xl-&Ab|ctH`t0S6=&{g*s`W~V6TzDTUorJ}byIzX<O zp!k|a$@0;VGiCmLUzf}JyXlDuVNS7$e_iN5R0?zbe}%}QOiZu<a_eYuKL+jyH0?$M za#4?XcIM{mhld$)sU*kF^Fv9PSfQ~`d*Yo`(fHM`mfpTTI_Ayh@hLPZ#Rh4i>6~s~ z2C*u1+f+-Oi(L+NSp2)#QLJ#6T1i0$-+_S74Z-aA!}S3j4Go*k;`T$dR+alTcB7(! z4!zpV00$gS2_$4-V<s#dvIVuhw-W>-8E<vwTqr~5Q&)HDJ}YbO`j+iN4Y&3f$YTXr zFwmQ)t1W)FCq5i&!=1|-Hgl!_nFTCIy^&5Dk48Q6@VR~d(=VsB+;D1qj{ZyLuLQ67 zvB6l=6YprPD*WPG1Qslj*dn1p^irb-y=;Pd)dGjba)X`SKm0=3i8_SrUg|UVKBhfk zmn}R##mgY-;a$gG2B%1HZU&Vij(R*m^biWQ&GEtlN35NU>f@JcMBYfTL0NvP+}*5! z2$2OZ8}PDYnQ4C}Gx**x0craiKkWl1LM{cVv$}fQzrcr$L!n<|S-e(Y02cls9Q4r4 z?HpJ~5TOU%(h0-$&z1%YpOM2}hJC@QJU-Dyguqcm)W$Z=US)nXQ_EXH+fwMrAZxL% zvA$eeXM>JG2#N1;eehz9+RcOOs+@XbV9@rm-qroa2`IMP^EbT+6b*!mnpj2}l-YjT zd!X`le`3<%DPOBXE0_i0Y?3iJ+41qnEdopXq3AS9tx&z+e<Xw=irf0}xx|y9URl$p zurV-<Xnejl$1PxrbvO0){&NSv1LcB;Nnm*IWJ40wTfetQjEaYMaKAesf^Zn|PH%Ib z(LG8oN?k}!4haDgiX!_z7bBQ?JX1+EzOY<fN%u700M8|%%`uoNmgzPTta_(T-DyaY zrQ_j6NK3=q9Gf~7F*CDQzlut^+-2l){tbI{OGii7Z2`*lV3I2Ac|!x$u3XURu%Aaq z@l}a;5n;cuXYbbn+<B$l2WGZXrS!{IQM2a+IAt_7RfTX&cP9gmtHxt2ECd-u?J**? zQERDQAjl|4s4>Fl-ong9h2IZ$ADQTt$?AV1Jm$N33XY7%<4{yp;&waf1_3u_W9dwf zF=Q=L++9h6R{d<@TAJUoRDPJp&(DvgHfd~Zv4COB4ise~lj?isp)HhfVnN^c9tVi? zVoH6e1zxvD+uH@74`EThm6V{reLKLxxg`OD05ZSk^Zwt_0GDYQkKvyT*>BSo@zXWa z)f-3z`8}Nn0s%eK$n0I4Qd>8etG6a_CnGCsOg!Xqy$MG)6)a6c%kn`>i+A8}rL5F_ zxjULoJ^u=_oX_jzsR!nEXw)x;Ga33p#Cc?3pVhRqxTHe68u8)d-S>imo~X21109Ll zt~fG<C5(4}t7Hq6vV5`)4dyUL7md8KuOJz<5+pS@+pVdHG(dggl3k35$T!OEeImDu zh=A9&MYR}tFQJpCEQVr0AQXHds5~|K*LeEdQxKk+o}QkYJ3P2=iO6<wXyWxMmi&n~ zNS@01Ul)XV=|~Rg<00`a@p6kFvG3D(6*JdER%WwEUC${PBmWyG*lUbs&VXEBVB=&p z@tR_hydmZid&<y0gXOfEbskDEIr_tBP@&VdTA_o_6~CYtdm;}aQ+J@=71`Ra&}1u& z{7#iwZTA|BGN@u*Y4sTH6e6zYdBU`Y;D)o~qQ2upSn>xH-!brHk-QfW*Z>71+1tNK zuk!v(8&K~?9pA^h`#69S*%#yiH`byFI9z<{fxcFPpcyHwuLli~zc60mZ-5<$Vz8Fe zBI;F5em2W|Ia*(I!Pov$x$Ou+<oYl1UT_F*)q)pvqldHQTwMa0f0cEJ>O)fZ+gH0i z644o5w-D^hjSl3j$`~qG$-BQYx&w%?u}4iF#|t!nSmI+5MxPBS7g5?a(XR9S<TzMb zTy1rseiRmPH^?e3W6<~oG%gUfhz_lm8SwtoM|46P+qEVuQ_E(M9`?t}t*d@ur>+y% zu^!ukgw^K(S;)u2(h|O2rkEc7(;`^vP6Xf13nl*M@~`*Y$-83rqh(yE9}{@Y01><d z9^1X<GG|M!3v?fw87$*ZJZ_Hab=@XFKn8sR8aLR1VJbm&F;#8k<>AOwE#$cL+DWAk zyc$G!_)RD(oB6zkrY82}XMO^Yi+5-nU8)2g5;_j+LXYb^(E<U?nV+70pMSfl_u%8< z)Yxd!5WERK@=Th)8GmIjNmYEh(sDZAgij6gKb0Ih%ahAC(26u}=Az*O?sVe%+HwK= zM~Kkr&I)2?fK$f|ROd$<+vCObM`WqrKrR+K)X9ozeLdjoSK7?hPO?s}4`;Nh9j`&X zU8s;z;}rVXc%B$Tz>n+|?jzY^`isK)<#R38v$^jf2TI{so+$LWAmPz5v#jV%b&9fh zJ6#Xlkw+t}wg1QuBWr78L(2f!ngUicSy0!uw`Bz;<bOPzWlR-^L4ZtM(5xGsef?Jx z_rm_)nmFDT-@)whQl>M7u3mSKtNH2H*5P<@Wc?TH-qOR6ItC)&dxh$1YXmAN=|Je~ z-Z3mD_3*bj>{k8L#jMTF$MJEgibExvBe>l2N4U1OS|P}U9-AP-VEHzUwMe*;1f5dQ zc^+1*J8-RC2VZ{u3g;j3HtzUqub32pX~=TD3r3kO%}r2muY*zM_4O61$IWu^NEG7v z*dnGk;jbLdfzkG<V&$U$BYmf+!}>g4X;#@g%-QlgJ3Fr@y)#nUweoJY58$b@nXPoo z;`Jl#rGYBd-JcxR`LbQ!$=#$C$%Z#w2@}0k283n|BO3ISZ!+^g2TJm1(%BDpd;8wN zyeZJE`|-okn<<PaoPBU=rI<d3tdv=;$F169D}>-**Bu8Zc)UN<RQ8@tSL)dvax|zB zRVHI%DJv`2>SbXzzn5+|l58oEjGZag(aO%0VE|`Yr?v`<rc31RuWD5BMlhLiafvRJ z`v&h8e!tiD`aLR<H6>M?*)&#HXQ%$J60Dw(=;^5`(UgI1xIcvFtfsPr@2#Oqh}y$| zP+|XZk*NP{JuYrkr@2Qb_aEFq9{GQsZIp%@c_Jd-A~3uIMEsfKT%^kmXuE9Wu$y|~ zq@*lq<QGs-Zr+A9;RY4_7wG=S7^d#=j8SK5jsXj>FACDq0rE8^=0ojDKy@-VH~(5# zNOx{28B2r$hh&n&@z~(+Bcs+36vl#I0V%8Y)cz5T`QD&C)FXWO@Vc+-0#dn7SpIRh z4~<qm-23Sc&MCX1f++<b$Yv}ok=oekC7yL9-2%48ol8qaQWN>fK{t0IgZYTVDetJs z)h;fV4q<JuG|LUeWo|;gA8Dm9s3e5zqk+W$z;>s<`uXpe5<f%p48p;K(O&*!mJBJZ zwKG=;*txm7Kn}%ElfDuoN#y(hL?omLEc*VTb8W;0_OOESk6_0KsNK+*j2G@xe3W6` z)ITsXFx;hrA?)GeH4%Sfk3eA%X(`AYR*c&<HO+K3-qx1z->!$;ZHjQBu=A00uSyO% zQc@$U8V3u-;ML%%=i#x|i90*8yHG8>ynljfe&L!jrni<tBErqdf>D`(jT)E;80ojU zU{QmZ|Cy`5=g3B@`K!nJR@%Sl2+0%vkM7J5ht`{8k~SPMURA}EMPP6j48i4aF%A5r zK`O(<q5IQ`1F`nOuWyfega23{4venoF9g$G4W~4M#G0-q=ezM|K83X4QX$xYI|T4A z{GHZkbtpFiyN2iEooe|<jk~}dp#BE96z*j-=n44MgHPB-hkoqKg&*8qS3qE3u%M#) z?@s3H#mnf>0V^<eY;?Aq{+^w4e<7$y0ww&U@pt}@e&VrriurGq*pHfG`4X-zQ~LjF zN#Kp7xftTV6^XTgXSocBz#y+K;a};01!UNOK~{=oxPJ@8s6yRY|9qDO{`LQ#-;N+q z`mC-}VQZ}k?U!8giFk+a<~*_JJ^EV53(0%Bh+rRYZ#|FJU0;}{pO9NxmX@4F*<f;w zAbGM{+W=^pJN#q5(WNEH&2TUlv0EwhS@Q);c{IMHr45lKCMG&a0|Uh)3XV7M0iV~# zT?|ebWiA8ZncQpeLx!vC;cQFc*RNG~Akuu}1Z;{R1Oz%r_puuxRRA90CirBqJbQjj zG&I)vbRt7=vB~NdMOQa-84;HU!UH>;51<hs;l+vXcB5b*I)iNwK5l+~-fGTvFh^kE zp!1ExcaU8c7>Y<NV0bmGMnncTj{Ix*6Kagd&5_4(Gtzy|7PTx;xCwI_zsRkO<p`>k z+x{Aow8bY{6LoTVo86j~?5Ai&^F!C?A+J_8`@K%K@^-Nm=j}0$!d(u?KdH3P2@Pgh z1jWDyzC*wQe79n%+^$E92<)d?-9KYMc+0rsc%TY``<JVoI8$V{k0!_l^)xP=E~YJ< zIb}*q7`5tv&e1+N@%gh5Vo6pr7ZSdJ^dg%-@;s0^eE+~0Kw+Qo{zdKW_SWZ{GTKD< zBx7^zJ2LnX-@xhz2-PO-J*1+6NzO<&*fNN-4V(+}V>|S!1}DSk@ZEt!9n(`zyt-&F zxIpJ-o2%4;M}RxKa#t$1RDoru5wxIHE7QclJr`Xg_>bNp^33-c0F198LwmiSXb76X zd={V6mXN3Mw)eaTM1^N@S<neqz!ibDNr%e|Q;#<%AC;8+-<zHTnYXH@#C^Yefe`!@ zFpB}?gpAtv@y2HM$RpDm$Q9QID|S(r=G(nChr1wl%P>Ur32+s=@6?^oI#)sM?6N;; zaVNERb#=9tEJ|czvI9EWi`qrtCjlu>$SY%TZ2VAdDt!^l9dJaJk1;w5IRd5H#gh*% zrA-jMJzLk$fuY;73<@p`8uiN~BS~0~PxnqCNccn2AEDW;X74U`5IXEV&(<eaavrw& zF5hy@Hf1n4&73vrd6|<MUe4NpzJaUJ&n{&&>u(6^7;RIDl|u{>w|a>)?FLT!isL<b z4(@P#z^UqFTu05e@z|=*u(m2d#E$!FB{8U?vILx5^%YV5*cchh!Mg?`HMqg1knZ41 zW(q?x)Fue*3a}<Xr`Ga*m7iCQL9f|89HEv87>|rV08yzLqoB`4>S2frNDK;#h}nHM z@jX>kERsK_7L){8%EU&-jW6r3AK?N6_|%4v^%G#=*RcU833n?93AF~iyC9<CL5U<R zPk<%5>w?W?F$#DH!u*kX#>P;vvs6mwn4C0Tw@d@Vz<^*A%4zi(GBgAkpBo&(pbD=- zAfo~*)x@TW7RVgqb@T6tM+}UUBBDr0N@BA=8)q3Uz+<<jA@F<ZwK$Z*_|Gh$*uf|Z z@Ly;r<Lz0+X+ug~lf<m&&~wqS#wI2<PD=vj<FDB3j@Y&aqWN7OtO0!sREYAW2AHeU z(%jt7h$HFjK7dZ?RtvE+7+*I4!UyxO&0;i2t(5?A8E7P2=tMy~%)R^don!sAztb*Q z(VOf2mBZxDkB99>W}xQ)RyVQv`VU(lDP^*GT&Qxm#h`l`6<iKyH?Co<Wn3(mmYcj# zHh@I4pgw2F8K7g_OJjyJ;@$vf`U_k+)n`CCJD={JdwTxED=+LNG-Kqv+v^U}1VERj zL<Q<rQQj`2LT?$57t*EX4zTiw4+2a%ut$H6&&{Ejgq3Kw*g{^AJJx}_;{sQ-9&~Nd zud=Ve`1VXHcLrPws@s@gA7vYM4ctuc?j!gJNm<DyKy<v9JYUabi71Yso*+57C?zFj z5U2#5Blal(K>AT=zp3R^@zW;&3#?)Y-*4d#f1!^|o}a5cC&<vVv8?X>tz6Z~9gF*} z$A)tC3>^bQX^X}flaQf>Y(LoR`;Qi(4`pjr4xPDqQXwa_=U}N`_}beQdjJPNCxHbB zEDh*%o}<h6QgB;jYx2g^?9$M~nruXD+@Cx_ajEX^?mF~%zeVkgQ{$gw-U%RDk;uO9 z-5*L0mjfjFAU2P`^pOkVjGr-7$^CSPzh|YYz6Q=o5=M5UNY_;6UP+mDt?;!h|B48@ zehkta*h|jt^{DpG4hafWEs`=L%p<7w)P`k3e=d^y(6=7GGd!bhTUd};uT?LZ?B^HO z%dxSuvxM9pE<FOq`bi0A>({SeHr6#*bUa3D0{onfw&+bF(Rec`M{5P8rIA%2wP~g# zSyZH^k01L-PYALp2SU^ksNxuON|FYf%*TK}E85gm3-}Y#V_JQNfvp0^3CXW@ZQ4k0 z9P~Oyvl?ExFbWjHK{_Fx(tHlEo5<((grR00$X!t_G4A_-cYgPf&g~R4sNX$A5Ntnt zfB9B}i)wcZOgm6vQBWj1xcoK@bJ`&lwOgsv;+Mh`?%oM^{~3Grt^K953v_TmpVim= ze*sb~%TfQ<h3aapPX8qgse)Yn5ET3XrxXU4E|QvMlMf(^Y9K13GxItWnNVZ5X1P<S z1MCZ}-5oL7m5rV2RL<s;k|`)GbUp802thiC?Cl{6Bn^Bi&M&)IyhMT+tKG{+f)z8v zP_DGi%9&FtS8OMcB}si}HCGW`9MGp$Qv()o`rEF*3zo!TF-$Ef`8m&0U^P?bFTC*o zRDH;}yI^_kPOP8zdL&~(#C-UxZLckf7X}V};f|Me0|BS74{wk);t|*3QQnNABDMpV z$a1-HLWgQu&qEy{h?i<BGNoc9o4X*fz~|+4;D)>SHhB94|4awqxcdBg3aW%Nu?Nm& zK>X{AxHzqmI!Yq`Y<sw>{P^wXLGp05E1gcWbJ}}s_f*jU9sVkALILljZ+yO+6pQG) zeYPuJ>}7g(=iT?IBdX=P)Q(*l4JYoN&*s#rpH7yWhT*iws^Sa2z#tuU_&hS*>eVVO z^*0yjzyPT86Nc#y5E(_{u8)_j7Jm%6>yB`eHN>eBc1IEMqf>P<YOOHov<IZs`L+Q# z{2TX&^}KPp61B>Zh4hB#yn|{AAs3JqA*1+QnQDNDvAWs@Q>c)$_@lV|GSy-85IaPw zM-<Wab)q0%HfYK~UJM4eQe&ueD?&-J!kYi!#^MY;$io*fJ#s(Sk{QXk^8t)tL(?Df zWhF5#G=T~MALv|=N3K&@Q6b=Xg+q{_GiND2t*AYS{v}CKlZLE*@CpU?^U6bKUQZS; zZ~jV!W}WHPcQhuMw*^vpIARCsiKE~|AAdW)meF8$e+L-zLSLEWd0PieT9BP)Ffae% zzTUk!@<-92N<T%tZuoH~Mk5JGd}VPPErWzXfz#sW>Z0jtPQF{wfVipy%~)fFUZjNA z)x1NmcB`|;M1lzbj`031?Y(h}Un%%zf>T#(n`I>>g=3jk$-q^q|Kdu-?$~`-&BR1c z;<saA(XD?4W;mG8`Bzbh)0j+QgFp)1+`nT}M}~7#M+~%9$AAtr-p`4_WFQ4Ly?6y} zf_jfe0}z`K;PMum4ourcSH(uf6FcqUIRk(o0fY_G1xkT8>A!#-LbXCO5Sgs{c*l|k zb=ge@M41@Gq;dFQ+hxCnu|hYdB_WB+60qE6R=u-ZZ5M^?Z=;BD_x4#>S_(&`s*xlm zwp)u#@heN$mo$?93Ra6mXEbOxJDZ%X`@equ+FI#X;=gb0w%jgvf69x_u7zR4sEM#H znkt(^DntX|ue6zH#m%f$T*7f?V`C$Mq6hQOnv(C8m1c(4QT}jS)7fp0DJ=|)O8H`d zPhYCD8P;MVJqbl5QU|LAN+Z6gRT!Tx^7%d``3xXmYzyNtbH7zm#)us#2Vp0F&bNxd z(rzjEve(SI<h~%&Mfml?<BE}hZ*LWH0lQyBd;2r>>w^RFdnwS+^dg-0OiWG&OlS&| zE_p*3`~VT`Kxbk>?yg|9IoJl9YC0ci7#ld5S=XAD+PpZKy!xYQ>72>6BUUH{xvwrg zQ1$``<rYw5HBd)2rZu<vkrq&2=#~mJ5wOWe&P&yraq#gC_JNxOVHK7d^84$?K7-gY z)$)==WwrPMB_*YwKc(Bet~;-0OVwgSQHbG)U7UZr-z<BWKDF3ypqq{Zn*v}wAuK>? z|HH7a#s_e8cFOT#-@ffc?JLKF(KJ;zFR3?dN{P9Ku%sl+Oi)O(!ItT?eDuK#<H#?` zSOR~oFl}i~7udk2dXLLOX6mu5mRA+A@#GYCh(eIRL2OYRY2Y{^S6=W`PiXAnOzF~h zr9dx;rPQK5{3If3dm3`PD!hDSMdwyIHK_QI&~R=6(%01a8+l9#i3!9{&6B7ndFZE( zhqE>&SSD;ZpQZpiLekFP%V4u<w&SjsJxEiwPymQJW?Qg%&U!A!nwGYuVj|_-`OE_J z8_W|UkUogl3#}T;K-C(Q+-?FP#u=QpLPUS>N#xOBoiBgFI|#_iS4!Th<Zu}f%o6Fe zxcWZsmV;Z-rr-F7E?QN-gbnaV<ksjjCEu8nxtX2YHyV8IUODFZ5f~ydGFxs7#IB&W zCeJ!cWh#Xrn5f}m$>Bj}iFNK;vrpxk!3y=D>IA7Pc@I_kod+zc?O&)M9^T4g0rr0q zUEf;mrLHHx?wsk3!8&!ZRtF1#B1c_0izeu>3_d_}egbcEm568^kMqG#Qy2pf$5{2T z`#tp7N07B~`IhN}7kuj2KrG?bZ~b?=eNBY$LMYVKK`gQwT60fl!UqUaG_L-Co`K2d zl>QTqUXiN}pPI2T#i?X6$7c0I_ewAfhWv?=6ck$%5RcicEP1_VWo7AU;GY$JsigC( zMD>zs&Gl)`Soyz3i54*dJB?9TXrSFuW4MFf7O=W``}km>V|>j*UP?{K-#m+dX&s&U z>OhXI|IDjzw{||g&kDMz&us>)%NmZm{=-Od9nA2q&cBUKEqRR3NW{e{!_+pQz&R2M z(QmHuRSFF|@k@4yhm4B2cyD4Pi%tmc*udOdNDPD?j>NPyEHpHYc5m+UB%HbR$oURC zPKl3C(~L?GoSQi^PfQ*3p*Y1XbNSE!2Ieyz`3}f?5ME>u)Q8$(vE@muCun2C=qvN8 zP%Bjw=xwlwWoMVTEVBiZ!Lf#^v(w{2ymerUqGSw#&E!{LU2$(<@d4tUtf)@U@^V>f zOiYfSkh%Hyy$oV(Me|=k-2r(?$wnN^c{M_HB`W#(1sf*)GZclrqRI4HUxM?fAs_?A z(6`kIbCur~ag=Mdx!=H+(xx&VAMqY9Z|K%axNNY+Ar}lpy)!aE-sv**WylN&P+T8} z2b+<EuX3LN)0t}-CnPDE!O!6Pg+^CoR2+dW#*geqQMijV8ec~4o$uR!>veG&5H!{_ z7X)Jo?s_u9c354@Bi1L&8ntF)3bN8c!e}8cpn|*5p8JC3i}@Bap`jrb_-@Sw$3;Ov z(mS;Z25RDQdek}w#J;JbwO1PjlZ)lS!Q2Q*(=&1y(=ok&Z-HK|${$Gp@({EInLs(1 z^kqL<3L>ka{(7ikb=}=>pZTMH{k0{#&yJehn&aYz*hy31j&y>Mg-xeEI6h|XdNzac zM_`YfoSdwt>Q!fPAAfburk(?f5(wa8=!b`HQ{-$A(XxdS%xZDL#)YBpAAnV0F?Ame z1^ozG8Q`J?QmV^t>cftQABPOzJBFX(;o;~x5T$ZbX6KK)1~luw7S@z3>rRuxM!pY6 z9)==hna%EJ0JYKXa6s5i1%XeFlahSr4~E+|m;vx+S}-i(xovq1Qkjp9%d$zme!zg> zhsfVHsa^^84aiDr;a4c&P!kXyZwT*7GKHI4n$ytH63#bdT$>r_SLnYUi3DQY=g_w| zUQxpr+oTQMgau;&H#r;dbv>Rnn*0ja4ae-7nwAFEXjWH41~Nd8SC1CVuup?0M;~?1 zQxFSUJ(C4zKuJvay+OLkyNNI8%B1$Z-5PLO!~TD~m|Lo(QvHGijr|?u<}I)BonZBK zy0)PN;Xd)A_XyR1GWNa6aBflrHX}OzBW@2{DXc8m<!5RKCth>)gV?Cyjy{zOp@#`E zVxcGu>HLf~BNZ=)&u6#$+wfThEN>%j7B4r*rbL4-0d&_h_K!5M4t}&iQhHeMeIgYt zD_MN{WO+IBXje}pTmpu*3?pNGALYQo=MDjKe#kEzH&b2hTOhs-#MP3LEuSB`9xru8 zk2lMOf`ypEx>dnbfMx^6#&8&68P#=6#phNhf>LRw+g$jdwLhQjH(Zj%dQSs3yEQ#e zv$L9bWHx=?U|oqC=hjhEzf^s@K3szFQ{+2ZVyM*R8>+7O)<uth)#%|=tLK4$f)a|H z!SD9G5%}1+=KsT$zCBiCQF)urXtP{RlXuT1k#_B)K2N+myG0*aw#SblzzkKdZ1B~1 z{rG|Cv_K>{!L12|SR#3BWCVo0Z7YlJ&M7XxlS~Y1`MhEM82xynO1-y?ACp`R6kF=q zwZooh?YXA!>Zlz9s?ieP5(sG5x8#ZdssM11NCObi1`N~p#{Ci!xM}F^esS4f`j?yB zbwx!*!xdhm)JCk!(K%c&W7;Pi$lx)j_h_NNuoIn-JXtS)pEzD}W0oz~tjkOk*bJYW z8+-hT7yMNYW?v*b;%hGjE)lv1mGq_{<X^1RxZ|7eOIO?DZMoG<z&T_O_EVAK@pue) z1qK#TQHb})P_VW81oeP=oT}ZcahuNb>sFw7W@k$kCxLy^_|Gf=B(OCb54|s3+8%=R z6*(Asu_*>I%3Y%HNUz&k>|VNhzfz=9a^<NBvY^YQbNTL+u){%=4uM6DEJ;S%A!${> zA$<0=w!usvZGWnz=%7-R6_XkfaU>|V7xeEYr#M+$9wi{Ul}us{JZr%yuIQ^bujk#X z%EhklXg#q6-2J*!LHoZKXAb38ns-@4(e>naphTa*iqCQzOP0t_Aomo7fUB3Ug!x5F zmB#Pr?t}c9>iJM&QCb}$(T!Qa+ej7+_pr85eXFJI@%SU3gTW<WAQy{)e)Fd1fWvF| z3Q+Q-RJ|$osQh4ON2|vnm{~HO*V<&vnlsDZue7+Wf#F{KmAX5h-!p^?E^*E)Wlmzh z;|G^P%wEyr&h%j`-jIzk4mc>S&+_jTc-}|xMl6#J9MI_IyW2~_VvuF(GxdV>K1N5v z?L4cw(X)=*!#Vs?c7c~rWa0{HbN^S-#5;OR60<496!oqfA!bWo&tcx#-5BQoV@}ZV z=hem8Afl7M+?6w^Hd4U+$5!moUQT-6u6~3IRKB*szrv|sCPpjVT+!((HoD);UA9Or z4Es)HhXfk`*o6a%SS?pdzLn^A(Q40SUd51P5G*mq_7=ra8+C^@=vo|S+AwU_thw^f zRoLK%t0lU-h5z*%lP3>q{Obmgk)3UH=+SC8u@AUq0Dv(8I^Lr8|3%$dh6UNJ+gd@o zLApyCLFtqbkOt}Q?rx+TL>iIq?(UZE25C?lq@>P7U3;y));YiS`LqA}eR|>L`@Zv; z&luw#;u0~;*;!wrz{~_fultxZbNzkcNym!)G`io$8F|QjTW&+?Ex)xEX@A>CSzaGt zI<6XR0BpkqZ+*-#VivKV0@NEoUMo>)NG@S)Zf?<Tbu(NP_AN65*MLNU<9<*}9aK~A z%6Kz)ga>~`D&}uCy~-`+adXJ~I<u?F6MRA;Aw6s7`fa;0h$QW@od`c)67!YM%0v<H zj`Wd#vb^sYAh-_#*))l!w~-i>C)&RBhfq?3N(U-W&So~>VH7G9Ao|Qz1;q&El`?U* zE3EFWwr3l>R$qJ<lc(p<#iQJ&#fumKwheyK?mNhrwi{F#?)pEwj~9xQO0G0l6a4#X zBNL}S#>4o()M~xGK1(>1ZX5cUnra>2SiD*(dO;FA3wA@gy}okKa8qAf3xG{IvzD=e z!QuR!zUT}0bNhW9V`-hs0Hm6hFIlzmN?+wEmuv5?5N{_a6JKg1vsstq7KXkHo_{TD zvQn%X6d5UHX_>&Ny8Bz&L}2uNI_21<79Fd?rgQDXe}BNsF;k|&6@@thTq~jxL`C`O ziAiw{=6T#Hao0m@z&E{iz4gs_s{<8<p{K8_0Dk%FiX_w@trPBM#`%ytm!-B7m&;&m zOqU!LF3RS{DO2rfrO|47#uy#WfUdmf#ccw+-WpxILyi0~Gln50r6iF={Ou_%`Yq(6 zsgjM^sOiHPPI?Hp^Y_yH{J-K}G~j5=LJPJj?pbKpws^wS!>aH!Ge>^;!X#(tIm+em zW~$NjUnM`Ik;H8tBM*0O7|ORfGbQT5i{gd~eG87I`N;H*viCxP5n}+x{ELc{#&os) zzWGc!1*}Ke%%&W6KXy<f#d-j%W{VsDK%0P{n`jha8I22-Bp$jt_oaE4`hSIIWJTSb zj;OVo>&5h1gG$kG)`UNFE&>G?agAw&lHx@q{zh?GUf-5KSi5)Mj3hE+20+HBX9Xgy zCXadz{W>p4wwP&VrNvvHHvEo0r4Z@(g&bH%$wu?Vmk<`hEIrXm%~jY*m-;xO(2rm% zzg8@tih01hzIx$-b}~a(@kM`r5?B-5`xw8z`-<}nB)>K`8L>jZ&Q$-$6s~6Dg_xLR zzJa3ccKCi&+2G;$#4Gyfr*}6Q2K!u2@KLbDuUt^~$kEl4t3^iI6*7y8xb3EJ!qHX8 zq?0+MU0UBrHCQgQSpF&oq@gaYLmo2&{f<=0E2MaOM;}E9B+RUn#`DrdDV7=*W&wx8 z{r=kfE}IVnJ>k&$Jn*hPr#b7MK^Suy7N2YVm*Fi#mep=)64B$N_<|t3V9`VRI-fKM z8YM=r%+2+8Px*UZKiTA1w-xmJy7_K{Gimjm`^D}`V+kQWzYq+{y7qo;p-GL=a3iO! zZHGWdqG)w>b@nn@-{V3p<KxG~Av9MAUv56;`R;O-OYRS7urF+)m-E+rkGz>-=qT)L z#HclfhKdpJLozbZZelYyzydIc(&)5oQP}{JT>ApLRf~6%AIcRO4$h}Zwl|O<ahQxe z3&bAZu7eRQ8+dQJXpcJv5%`qY6gp0QGBoDW8ToNWD6FD~ypin#($e^U#`nJ%2jVv% zchL^JhrI{>tRAG8ay#8$X>8|xZEJS>b0IKML?!A~p)qhX=-?i_&0lvG3TchfO(w~) zPt}c^Qmfw=-kYse>cJUuM4g4uju;Nz&Vyba|NTe2PN}^q7~kt*pO3cP-MQnIXx6WF z6ky`vnE^BQ0aqul0+|JZ()H;U#UV<3VE2uYJLxUtm9i?%aTG|RCgb3DnNy|6J82F= zy9QbX3KuEWz(2TBMmLT?HdxlJ%aD3MUM!=XMm}Ig1&6PTDu;+QH?i<}-TEuS+$fMm zRTB+=on3Z0?qA_+h5qH%>8sM5v!yGBO$ERwMn<@C$Z1gt3GCgO!C@raF)Mt#`{<f5 z+lI6*o-UA!F_oWQJ!7Z3qq#S-BRKJgi6QWzLk|eSgt&oI{xBG-*cVA4%#4SJ_nc0N zzE6GAIFnxNPdeG~Y6*7!ztYJh;Q;?^cRet@A&T;K3}bzN(K+4y(#kb8E(Br&IOv$r zI_jaaYSO%)G_QeM@8)IUJ!9ghRl^x?M6&}ZnT~38kqq;e2a&*sZIKcGrv3A;51f+q zX*^#3H=_do5<q@H>rDh7`N4((DtPjIQ1q>JeSMQar#`dLm>aBnRQE(5U9G;J+?V83 z^6B3{(|Y+}e1pmn>LL4ysMu5FgVj}?=!B~WeDJeBO2Z@HX#VQ7_tKBzu^VUH|6i&0 z=P2<lE&!X(4i^~rh);vq6yR4k^^b3EZjO&^EYu#&dAG0n1yMY7nQE=9)C(q*@-9?Y zsn@NrQc?!=9IaGgM_+YeHn(_kTpypDcy67jIo&p2BRKCb4SyA|u-FIaqWUF2m?R!U zuD?mcV6ekRIX;aO1u0FCI6uBxTOR(b0h+{|?{D9(J^Q~Ze9FOLVSCd}-*9%usUnG; z78|cY2J~Zd@Ha5_Mc~&V6E1~aT^uY*r-1c7t5hmI;UA&#v~RHYk7QTBG?`<c2NF+q ze=>0XIO2eAydKPR0@(Uf)eeLVNQ?;}thxfU{_wMW5M9C9-BT`*hl}3_cZ&T-Rq0dC zAe*H|S#EA_e!faa<?YY!RnSOyBpy&I9g4AW0Pf&tQ=!K-FhI+0wFLaqgP_GHS1QRs zPtO<FD+fW!ljPpq1K<_>N2Mery2N!qFFM^mxX)aI*w0IQRonZ{9xyX3wLOe=w34UE zQ`}!1aD%1F<srX~{Wl_1R27i^g@S^jaKGBE04WAA`M@I~b=m6@R(3eXq@@86`DJm5 zIp#~H@V3<rDw(XTtVg6TNXx{6x}*5u?!pcAA9V=WFLl4lRc0UN&8gVizm9hqZam)^ z(WI8I4hA=6y;hIw_3c(j<WS`@9$HmZQ?u>H&EGD8E5B|kih_c|H!C*6sp-6jP)ID7 zaYeI0WkYB|SW|D)TE?3$I+}0slR5s~)nIOJW>%Rdo8Li7I@STGm|K&p^tUJcAc&v< zQl-))1Hj{R?E=Erv#Hj<?vs6>5E6j-WAyXuJ<x9A7la&i=xkFCxcF036Z@MwFH_`s z?g8T&5OHx|x#;9EN(Tl)gLCc+ue%qhiz!lK1YqwuAkWVfYksQ=dhg=WU9-pD8wrju z1)4PkK9C&#F>MYSUWi%BA3(Z-Sf3A>kPGJ*-z%~S5Sbg#*vRUOBG1bFyujxAa1XhJ z?CxY4)Jn`bfII7hkO>y*pu$qC$*l)$S^L5Xy|2c+eq8^4jBX#^H0Gs;0GfP61Vcd) z9YY7mj89F6o$@OxDEvG>2TRo0`1{^rbx<C1u+oCxd9YZc*=lzVg3;?67_|)zeLXz_ z17X=|OkP8PEDKilTD2BQj9<8UJ$`0?Qhe*_$%~=C!R2U%koP>QOua5rGw1?*?Le5j z1%SzzK?4scee+97Du|4{09O>?PlbTf8n5&Pxgx(`=O5)a598zGfkbRMSKbjzgQ0tF z96c~F@Yl_rW^vSd2ihs=-uFTz5wMyG1At<k)v}V3T;OL2PGWv5NqPCoplqo>e^t~6 z#r}1zv8$^qkV|O!dHey#a=9_i#aEB3Co@amA1pE7O3v~yDZf<xQR)573b2iC30Uo1 z?Ck7BgQSgea{>2UUP0m4=~h@jO@{6o*xHkkW&J!C_YRG)oTx{mVz<CRpq3NF?sa+A z>UqOvexU*KGxe~mZ`x(%m8lgADG(mXa<p7rhkMHYx>DHhuuxI^u_LqESK17V)Lm3u zqO|yLVL<lq1P<;`IK2A-=`nx_OnyLZZdLgDi3z_dF)=YpOKU|c`4)8y5T>+R?J(1b zeqi~|O-%`Ja;d7S0%wW$)$R#cT_FBESEZ1goy?Q!AikNeQIC2T^CCEf!*(Jz5DCx1 z`CDO5PK{MdQGI2C&(%z9T+z&%J7S)4Wo;RhB-L`8iha85oSdpBSU6X0x$P8XnPdyd z(^FHcj5=!|%Nk!PPg&IB?)3L#^pG&7l*Hd&Uoir@96gSY(K<mj&HG$w?}P7OiCNiS zKSsQvXQcoj^{Qdm(mid3_fZjdTCTqa_L-Db_b?!6$-KLE`g#0RtHuvpiHDQ8iIeYd zE|2Qp>dAjPR&tR(7GwyY2Tb!1X26=Z&c9${U~nZjVMSni!b3`$0p2CS8gh^AAyq6> z>bqj|*|MOZAaZ=GL+<1SwhnP2y~^GQ{FO#Wn5T)Gf3IAB;ZkUS;ZpRbsC=$Jex6|D z{Q)=xKX4h?K0sERjC(XK#!s8iST1hg-`~N&z_>?SlQ3#lnw-cdfWQ{8E(>-_r!YnK z2-Qc~5-Ea@T<|IIYphy-UW~GC2aezG1370PlRlhOm!92LZ2OO0faOgj>J~0;lDm^N zb^~kpB|s}A1Jj7)Lhg%RkW=;ewU3){S8Lw#2*L*M%8Z-&o|=c-noG#&EBA|V@V!al zvoBR){<6aBzSQDO9R06cq5_bt@BD7AP<A*sUl5$EHgj1F$_H%aamL!TcNoE{{O|ND z3tlqRkQ5YRW;M+g6G6T8dgc*}8k^sC%kWZ7E)dUnv~@k0K1WB7;Utr3CnHKrw9r#Y zzHz?#`8}pGRGgWRkTIdVkILWQUqwwxR!%NDk%XL_oP}kovr~`*U5%fEVyZBc@}^%u z@}%?X*Ds)cDseo82cpxa&ow-biVFo5RTSatg>U@n8rOCok5U|Lpsb0tAw65xd&175 znWi_iwgwYoqH%v)z3!#|3`YR3$U!FaI2}FI+B_U}_}^3)#Qeb*+&_>2<C{qlqMVI` zor4bk<sXw+@RDHX7iy01h={*@j>q3l^%oN%_~dWE9oCon+5g~|AE^msfqz2$SJna# zp&mX0|7#-Zkk@A)L3>oGAf@-ilZ!J@LcZ+&b34lEaN*7`0h@~5>TnU%eA1%3f>Hhi zgDQ+ltHnsuPoy?1fj-8ifK*6SqrpvTfz>|DhO^Gp7<AI!ETs&4-rqKuIhr4$oVf1= zzf{r9o{on7Yw}Vi$<EIHNz9S03G)bkuzhf(P!hlIfCagYUQ8oKjb;{)Zj(djk4Z_c zo4d?dBkEE25lPqN{qw^DVD5@eyeX+d7eGA~>TF4G@H&uJ5&MwW7Y1|&J@LTfPw{p= zg{;wN(exhsS0UiGW8VhHd6r&WtO3|tTJ!vFKR3Tu?Eu<J%A1#h^lFO5{dWkfSS~Az z>}A8LtN>$!#<(NcmsXhN4H^6dfMvGch3qIQzjOnxEpWEk3R`h_->(DLI~s@ErVb!$ za0s>o@{7@MY9E^2@0j}Hi>0H~I9T700G4oO{9y%;BmLo14kI|<07oB;f?&Fv0-}JU zLp6ZuskW%q01Mmo^>s&R2<a<cUczmHlv7~u01mOWo#?E-qoszToRaAxQD^+m78_&0 zm84c<v9{fsr2r7+LRpc7+~xQkupnmn#P#&UcOJSu_gTg^>I{&g1A+8n=Q1K#ez)6f zY0J;t&PO%oi`#&<!8TKa3NWPsYd13o+{t*!{jS4!(`c?6y~F5@jr8HM!2H2xJrmou zeR=dPiiq0_n6JRNrB6;Ct<kaSc{~<96g~v3GBuWqjewfAKAX_*7ZfF(%JU^Qb_(Pj zU~VGorESE-fS7B$yVQUHG&E3lZ@brWb8&ezo4_wopF$;*`~hdv>983Jm~x$*4hRYN z(a0;>-?|)pZ!n)t4G$jz{Jcs@ARGM&E<fV6|0b6gTkl{*5s3$+J0Ot(f&(;-0|F12 z#NnfY^MTWCSB@N@PkgglTfM-}2sB`IuA42X7{7g6V7}ixJr0H-u4-%LN`rU)qp7^w z6`6(s@LOBO<kIE!f|IAmE|ykSe5UIhj*gB_Ghovr_Z+lB;qqIB`}#tVf%y;ggv0>} zJek!TWbFx1>~2OhL0%oyrF#8(&aHbpXKA$<tr%-*U=aJhj*%0KV`$Wb6r6^@y$R-f z;I%`LN@me&TX9^fX9iQnx=g5AzNLPP*)Z2KI%TfZmvFn4)kZmOZGhjh1*n(ju8hwK z)#S|7%)rj%=I7y8I4n5Yfq`JrFu^)KDYCvDkWluBWDTaR_kPF#Qxlcw4e;`b718M0 zHPcXqywq;BSgK|vVS1v7i-WVd&l8H_Fa*$mnKsF+Rp4M2k^~IcAIK$wP9r&(AkG9H z5IAJyQdM$p>yVIl;Kjk`a<I8*(Q-8~GMFm0^kaf<1Oi%S^dL?*u)6qI98X82s+XuK z`qx=F;&bZZK&-8;9esPSq0Bf><@SCW@S#=#AOfZ3znz?3AS1zr-4VD0t(!$U+n^=< z>EKC9!x@;PbtMi#PEe^cC7UQhZ>j0%NqoXTQ2|<0>q%%dSik^g&^tOy+=UR?+wIY8 zw?&&=(OugI*E@lbz(_?!S!XdXXkfGL6<H0MHh!L;S&uiH0=|tw3MCOu$>*>-NnMY- z+o`E3r~M^L9=gZa;d5}jzkXA2#BWpXSQIZilvwhm@sd`nd9JahXrbDa*Jf<2OnXB# z0?$VXY|HgLz&u}9s)zu&3m``}jM*1=Hz@H<^rm34Nwme7V~Y|Bilnz!wbDt~2B95Q z`)z?=BoiB~$FWo>SFYRp*MMXhoL!(?HzMRC1r;L&t`vCeRt}ekywXe<>IlMX$u)Z~ zwHjZ!ZzCd}+`%9sBO(fKg0Y*2*Lw;3j3C!|&0Nn73@AgNdJve{^*>=X=oiT6&?;6= zj7{ag&vOEZ7Z4fS0YxvbjYbX^>t?G>V{GBU;B0vi5Efsa1;lAC??XW+BQ4k9E2n_L zq#lcf<{VIU4*V5qzzDMFOIFby@b2Ba`KHVEpWokqW~*@oS!m2qu_^MYgMqEVpW+FJ z^G(E$tS%6mIWrarSnZygs(v)$V6ion2Hg^Jx*;OJ6&7~bTPXsK-(lDz0L^MX{lhWE z;Z#ZVZ*0Bv0~}5aGnF%;&%5`z0w@huDq%U>Q>L#~H`lsE2jdww8odqx7mEaz!zWU; z$>|PoHfD>puGhCDHvKVRV;%Q2gakW}r$FCFgUiW8b3>IJlx~LZaPq>o%0I&BY=Q`1 z2Zk0vnr1-JT=o<|5k6gI%aY1U0|I;x4e)pHxf~y#8cKlV?h%iY!ggl2Qi+;hP0Zj# z4+=5wLL);{WqC?!n+}@7a=OnQ_^fX+Qb!P^(e>eV_h`Gfs@6J;<Lt-*7D7;XywZD~ z-%(sOJ3YP5WJS7iMCsA~H-2lCi`O$#)&(YO`K<Ba0E)qJwHs>ahPVbZlm1RAYmu_3 z-{t9PDz`N$UT>sklaQcbRgumpAN?pQ;5ymc+s{r+eBup;D^q!F!vrX>XAlq&w(-EB zA<d*B5I}yseW1?o{QxkDK;Thto(hPWa0UT$X4vdJV+-d+c!t*1o&NTALeX#>kXe4^ zG_<S6Y7STs4nQ{sZoKjB*-|ZlJ30Y$fGR7-a2KQQumHpD^{v7E=QvUq#5@!w2b%xk zV)7;gF+(wK)6*&N1z5|)X4C@a<zhhP6A|CvMpw^eD)+mBc@{h*4&E)C$LzXfX89h- zt`9kG7!7#@cNjc+fjI7TJszz<L#48di5jddEa_dezpX&9!%r(9a(t68C+F-Ea+r47 zQ<h3C7vJZ3<y#_V3F#0Ns!kSWZpG2ff7S!(NyCT9pN!lnI-{irH<t%k?^Lry9Osfq zNI(MHpPtof={WMubHS%w$u|tFm|3?!;urzy2&Y4r!H+Xy5Dpef<%{lK0Os%`Dt{ah zl@tr)-wA1E3Ea6QtEt&(d3W^=Gv$JU=H<>MkDvW$;7Y^9%sewO1voQ%;H@ur)NHfG z_*$yj){#vbWy4vONF*)Yk5j5|sfmHn77nrFlSb$~J3DFbu#1C<302?|AnYLsL8fcc z*VQ=?fD^(Q74B;i;=7DigJQm3N;r?fwn=X>$`lSjP9-W8h*4cidgwG)T%qCN{vpnD zV;w4{Z_L_nd)IYu>h{KnwoGR;mO(lUb+Xd%ObVYJDBFS{V9I=ZvOz^piRk#}ZX6mF zB{N(4C7OM+8BmsijABoJ3_6>VlkxVxf6oZWFD&eA=JMLdne&W`jmzOJ$ZBaRD1Zx3 zXF>;Xj3<_exb7#n0l^o7M(LuYgCIilm^@!$*E2Qc)c>WRVLuQXBKcwaN`rGIy)H^d z#0@$;xxT*yUs?Bdq$2n6;DIXMg+|_w+VM5SzK|=%ycRO4U=r*)4LuG(NLZ+|rh5!_ zq9$g_onKrynH-y3fHp)Q?*hXxEOx7v&YrdRrzhtDc)jqGy}d8`1OSKZW1I3KTZyhi z-`jLnP`(v{K!(1Y#Go)0Rw$G5@!(j1&h2KKfvV-``Aa2&8Ha4Jy{Zbv=@EqRqJ@Hb zTTN}$gL*XncQp|Imbvq@|J(YYxeKe4Au)Qa5J!rN1Iy(fY{nOoMWL8$eqUa>k}Z+1 zQ?Z#ZJTDE`<KhBK4}pXPr$5+}W<&9z^5f!ev}bZ3z^&I8TI5A8T2_`m0hi-^%_O1U zcR;c3jr@#r$qJ(X?X$D&q|5>f-<cc%khasNzwb{qK)%s`Rs$FlQLG>*Kbd@8c?o)u znDs?E&Jj^KveAuNrSNBOu6~)Cn^zoQrAy)>sKos-%>dIXg1%Wd#ycroRO+2`G;P4J z!wMW{2O}m1ETKzK1>=v2oJlalWLSaTSx&od8|fGSOrR$}KB^yS8Ri(n*J(k_+8;tZ za1>=wUe+dfYqZ9P2?U_*cR=@;yO*APW<(7u;)9gs=c~V%|81`ijy(x4ZF6$=#Tc)+ ze3NFTrWD@3h0?9RS1wb#-%uSIR!J9zTZZj0hx9G!vbSvnYez6ac~w4BQsQ60C&INN zR$qL<JkAUpgwsXJF?sC)02<NDcHM8nu&Y#@4sMWg0`tb0G@qiAlHyafHg^jB29+u< zR#y0=dEIoEVL2xNs-7Ob-s0t0lsPE5`@34f(J|y#j%4Mqy{!lN4#1l;)zgER<}lkl zZco>lXN}X>70;@T7zWM=W63nT@283`o8TwE7Gh(Y$?pTS>9uG%&oS@c@B|;mpdW_O zDz8CkGvjGG<l$Tef@vb|&0)(8Aa3;ysHO^p!>D1MKhAVwI{^qgkI2g+<EWq2EVXDo z01`;)=gcTYGDf*g{8T@NSY4oeq+2jKCd4J`;`|H+rA)xZ;~%>KgrF8b%64&lI{WCV z?$_iMDikYndW-J=WCxh8zDMUr8|1lf`1EX)@`OGl8ojB(Wzb*B2gLcxeEe^Sg=ETD z=(~Yqe{y^#^_62U@CFkS9_R{e?m++3GlTE@ZW9$zkbW#fsOb^de}s6$`(BxITcDRN zJn=iQ_P|p;c}}_sv8_p60(>nx;&f`&Vix<xLuUJo$9@U)1z}G>t@2&@L<KfwK!<8# zOZYQ&+R1GEPpaZz`ViG@p-vfzkH<s}+^VeBxuGHQE*OM2q|D)Kac^-woAJCUMQ@}` zkKjlO-rtRrTNTWs4%s2NUh~e)%@Npx4c!W=z^Gl>+$658^YXk|eaXxm?U}ef9Y$4e zN+k*d8b>&<`_&0^c4{I?(AL-2uhN*ZUOAGrMz{l?M4FyH3eg;b>IVbRnPqfB%fDy_ z?q!+!e9~#m>Qai1TcL)ilBdt>nP>|OJyN$U7$!a>rvZ>WX3z1l4f`b_IM4Y#Y|>Wc z+nztS<1jw-m>-SPM-uF{bQoUgS^ItsUGm(?9406d<c+}-)YbmxvG^`4r4N%Xx9Z0Z zZCD<FvV+ZUr_987sUHt#f(i+BV`3sPQfkY7WOBe)r|PpgFoLm}&Am~5y9F*pHd8~X zth_8N^nC)7iQB`;TFnleG@Q6zOw}#G49$9TJreE`6BF-^YaJ2{urs!*^t2a;^E7Al z<Lcm(RovIzl-gYjvv*UBJ4w;1K<@A!DjFxm_+5DH+;ETj3m!zULG(tdR@@$aVh+l8 zQ4W{eP-bmRRB$x9jul?DJv`zZ@yN-$64TaEbYDEv^?1epI>7le#?Z4n7~}@0gTVeC zUAC_7T3}XT!x)T#x#e;FQQa-|{QSoZU=K9cNHJWL>i)Hhthjaan5kym0xJk-2SNb2 z30W;SVp5Gomw)VNA|y`xfUCUe%Tz|h^{J(Vjg)i^Q~<uRqdxex4ts%_VnF1rfpO^g zY;_Z~K(0T#c%4}Bn90WUKooekW``x33W41R!Ye3RD@XhWZTv7d)op3~1JAgI#@dg; z-|LYv39E4iyVPo5C-d#83s<5X)Q#j+hUrJ|rRaj&zodG`y++%r?osFMoX8(Dt{1mZ z5dBd>b782Jd$3L?S642?#M+GRuiNjDN<VYZfK8T@^AGrpkYn5qXbrTFX(L|<luB&o ztK3DGxg1Y5RyC~D!dPZX7gsAiC=-?`!qw``3Vzv-yFdC^XsQ{hX<10=gFtN96oiJW zoZCLvS&_?@s7)`h&D0x3UXPySg4R*MqGaXZ5T>{XYZgHL`qpT;F*A%0uE=jA1-Av& z$zKD%UM$rPIzl$E{QRNN6Nv(p-*mZvXSg8FSn|R`X2EQca-CO8qjH(%OZ8Ivp}K|= zy`NSruWMO}$-F>M@1!<+GaR|heNRUtl!P0{RyL){O7r(g<I%3p&W8O1OF0I$nt&po zLAa0}`KHKW5Vi+AI#jT1v5lA4TQvVx%J9(fo=+fBj7LH*yW5I!<yFpda9Z3Gas5H1 zy8iyoU#^S*j{GO%{-bXeUB@z+$5aroNMFBx{TD+oLTK_x;C$wTQJYk9kp1<&^U-{r zd!GB9+qqJ)#@)q1)Az~T{iQWNt6PfjD;!E77_pka&_%8SAo_3l)yqNauB*?E+zpKk zg1zgXbg@&s_{=IWnJc9;VPwq<!CuDzE?qpf>r>8$H$zF2b1=A|yatkHtkCgdFZD6m zF8aKc1W^JK2C2tCv;ZM~+jun1e&P|E@bAtDCU<;99foA~pa!(Hg&NDLY1WUfC-wn@ zs_Q*lG&X36h=?=AYRndMV!XV(F4Gy}YbT<&;kfUE5b-lgN|5jkKsh5Sq&h2wTGe(* zgj6^)LL<GVys#9~G&TYHM1zEL;v@?TEA~)Y7bC(NU$5(PZEPOb{4B89M<Qf{i0;<{ zdlF$r>ZVAN{&)t>rRf5yrJsPAug=yaP8S3!%IH<<H-9GCm!E@gzy>&f$l!j=meo0a zUZjhf6%P#sp|JTQh)ANOAc%yM>{Ccp#3&dwG+J23fMI<0au=5z0&eaMt;$woLauU| z)SXXCemwc2Dp_=~FUvkWhll50s@qO{Ah3pazXi3f<9oV4up+Ie%Gcr<7B3FDKd5)i zaGOoRuCen1LhwL5jo)@3U-hR)!WQgIib_9Vt!9?w82$#ktHq<U3zm|Eadw<m3iuJ< zh}bFi9B0STD#8~gXrdND;c6#*qIy6#{bRvVF_lcESli$kn*_UW!LtwcFG-ngmvD@0 zeLqEX>ve?ix;t1e&mb4=|E8yYZYdJgTLccef5!|=a&mrj`3I6NHu$*Mzgr@{v0bHI z3!MaZ{hQE#&$^o)IzQQ9kz6Hnf2TVGGJeqaX#lZHfNrKZ{z+94@;A)gzpe=0{^#z= z$1&Lp&n}4e(NW@8v4-I=E0Fz4rt0r)LIVOCQWi-89)V!4%fV4%Q&%+ChEqbw$w%VZ zOg8{NAs`^EiHZGq^6(_OrTIATj|l;xEj}m~I3M=kdtQs`;R-S<mnkVOFha~bKEFIS z7k2T#$~CYZLkDzZIxWwF0@InAJzh5(Q3<-H=yV}g>v`xff{T7vY8$@A(`u}c_E5xm zY~aBzF~hui!_lEf!^!Ci*kQ*hv2@zfE;7y4JL}P!e)C6yR|ajB0N9VTCK&(4d!GFZ zo98yzAq13UgSe=pYU_{96Y~Aov9WTH72@-9iHZpcPZ^~C2!PtbYPMOeET<YhoS*7i z&pHMN=lX+dL_*SC({DjcKcQ%bvO)zYXJb#U2!Etx*Y;gqonTN@ms%ZOc)ol5WVo;= z%)IJBONxUPB>J<q-%7cIvwh5@f1_LS#>TN(!)^1}`f-vKWI!k9d$rNN0J8&WQK8-1 z-QsZ$Khx9|bn&1F$u(IpnLBVEC4LY5=GS1|whZ*_&S;g`i`{wW&Hgo}uAra*?Iy1* zN!&2p$vivP98^qLaQcA)qcafvY(8^_zXU{ZYvON@#)fiyv~Fz(u5t5Gb|RuOAabsD zl*wiN`o@;r72zitYQaaN(eChA`(Agnl0d77PV~v+Ucd3d2Z9uK9pzt8?SG_$EAGdX z{qB~+pCJ1GOg;F+*!>R);@?FD9K-)bqJp2smH^RAiSrlWo`3+|*0ZI{AJ2-3T7D66 zJCW5H-}Tz*6l+zL3Xm`MNW^dbpkLz|{oG~)zy?ccLiLisrvXmz7BSyH>O#Z~Hdqdu z&Q@UjHe&qd|Ni&gzo49<fq|GrgWhy<f3O%9pVMtOpl>vM^S^cd7z8%=5jcF$pQ1#~ z-k=bDIxFU^GMZap`+A_-R!8s&#P2))tpCZCskUiHAK2RJB!BBeSLVOVg+S06q(*=` z4AAMKkDRdj`VA^+z+u%86$OEgR6xJo`$Lv3Zji0}{{1`HkaYgP(6SZ1P?y9UQy?V- zX3re)?|8U)j{9>y%dowx0Giq#1A}#aZhi~Mx&WRMehl*XNw~ORb59b!Ut_u~FCno9 zLi}JXfJ2GOSFP&JkM07=CSaJri1`GFLf~L<H!yfE`F${+v66|s&Hi!)cz6LL^)IS4 zy6NWEH8?YXMlZHm493mnwg*|z+5rNHAZF<=1LBl|^#q`^Kvht=&M4x?ysGCl?cv@m z7*khT?Ul8)kH8<7#@7Q@BuH?K8uhz-JKr*0C&A1PtBn-@-7hE-Y>TZ{DoZREXD|m6 zf*@KQZz6L8Ule}OjDI-|w$BbG-y*-b{2EeS<00P$BJUo%h5vPfSsX10LCeX?zM-ge zUYpq3%-)P=P<J>WGm8)GXa&?(_e(-CNihO01E2}b%O`AoYxR8GIhzr~frKxpsJ|KL zf(%L#jToDrmJ%1|a@!Z)5?A_MYe5IHu4lW^Mn<`0hQ1hb$o4x7!NI}RAX^GzI=9VF zpZdJQgZ6j{ERHe~QXs95Mj7(#g75$!qe6s+GNVpG?rifMpFIq75;!_-8te?c3uLw1 zfZp*83QCui!>af-9`x@gvfDb~#VkK$>@UzRre0?T*OL+#xAh;?Q{Je*>DGW-yFWW+ zTBoaWQVwkS8=x-(K25d7xW`aEoCWuAhLC7{13f#_7=R336my=D9HM<c!E+gif#E}^ z3nFZC0&sJ(X5-OTAUdG^SsezM@dLNWLd_lw3SPa@`2hAy?NZgI)WMm{vh;CK^5k5- zr=zRO=QL!}FCKiaSTqw(#M){2T`za!?V;D<5)?2kL|1*>ui3%RUjvDDqtP!YoQxi! zVw@n&**AICHz}a1N9p&(uJTWoF%<#sg;eT7u456{MrwmnU|;nsGoV|5Je0W5`z+}% z3zUwIC-m4aHIsPlp|KGEthS#sD&}tBlDUcu{kOGmx+j|b$;8%MiFko%;8wR-WV>AS zZHBYo*d8`yq-)}K1bP`Ur`ZtLl?Ngdv3M@Tf_=A8CHd3jrvwoHEKV??0Ogqdn+<2! z#~gq8oz0T%{|;9@cBYrhtPc-70cEQI_{I^1$Eka(f}MZ~Ov+~`C!8Qc%iY-Fs2{T4 zQ<2+fyEk*XB{41@ZA}0AYLc9ctkLmky4<U!2VuwiYPH7foGbFt))xE?36wJ7^%rEm z4Fd}gXlQ6lyWtu3aw)6DMnLz3Si>6rtXQf5mstp+`oIVS<nTfh(-2!CrDy-x1-Ph0 zhhe`&4uO+u1DoHdgwgc!#X57aWEgy(H`0C@!Gdbzd2=Ds{(Budn|}3Y9ok9DjnWAo zoOR&Uf&6ue1dn_VeqM3$0kDm-u&6vZ1Xi0e<ua@96Z2+{Q^9MX6K;JJaD+jOa1BVI zNIzybD%rJeR)6)|SLpSySuc^4un3QwUYz*A5o}+4qLf%^v{j_Ar7Q~d;Ix_Wxpp1d z-!FLy)^_Hg#P$pa7~Hp~=}>eLSW+{^<HYfP;MJekO(_)P67e^O-2e!5#{e=)7w9|* zkWf@h6<BU`+~=wmZ7&t#7F#)#Uaqxr{QTNI7eFh5yB&47t!d}5DG*CFK!>SxIS;^P z1UHJzO$|NA!#m~TBh_7)`WlSO?6C{p7GfS36H`-MVz3fEr2v^Sg}dT;dw%bGdaW0{ zDJg}DMaiC?d&y&CDsts6^rHqW;Xr@{c<?gGq<xX#xB8Ebt95|vfJ5{le|Hy9^U4o_ zArM7TRZ<k@!UY@@K(Jkx0lcy(pyeGikTiotX0KGT3=Ti2)(QA6^siq6i9g*ZC&lz+ zcNZr}TGQ#kA*k8!714k6gLa9R{O$)e;mduuAwvJ;h8baQ(V55bm*k)l1L*l<wLYZh zJZmQo;QCgfuMC20W*~14`YM*&+%LVVa%*9``r%uGc}&dA0KXD;QRD3g;fsq4+aKcy z131Z*%A<#5+;kMLKxrpEw8dxONoFp1zX*+hPR~@Y0f9CYl+mgBNI%3fH_Zc8oPtO~ zHC1V2Wxz{BKa^02I5hlU`#QLzm9}s7reQZ1U+7bDx8J_etojgNt8}8*qxu&YNuLjj zNAv1QTK#;5NR}$#1^HABqRHMK3sZ{6qBa!&iL5bzt=$U`F_Eq}aMf1Jp#k%!kDq## zT0pUH_I@DcK|F43_ZrpqSogQRdf0iHHZQ~f@Bz%uqwLo6GW3G29wGV&Jiq5EFYLcv zl)%t(|F49`rSWksMa3GxwSP4-F*PQuAkS59UH9qJr+!kyIO3Z5zgw<Igqs$NBC0eP z-8E#PQ<I$v5KgfG?G=@w0}b}rsXVS+?n)QV`XD2HM#FZo>eKSe%?(IFTEGNVO(&!@ z@|oM6s4pNWsHx#7@o(rU1t<b5)W=U;+**NMOz-pJ#mPpmm_&G-keV770?1F14=5_! zn@$59VG02thCdTAoNG|E708aKFBn9oDcW2T?Y^`Z(j84^j%e}v2=g%wyvDylg>zc= zu0*1}+jh7}kO-ga>p6aBq@I}*v4~yS|Dz33Sy52{uQt|Ky?t&jk)Lq5GA7FpoN#|^ zV-I-MeSoo`e*S0g1F+gkCMt=bBLYN_^PRM{+W<PToJB+=kePoPzf<z7V!rGOD5TtP zID-X&3gE~PzEuzHac}?%_hVQIM|^9@&xWURd}`)mHG>@ZKT81F9%PaLb7OE*?N42x z>;Y`rwc{WM({0kba;IhJge^KKPWIn1nV;u=$Esk+@RJlySF0(ku`G^@d;7L3T6VqB z(G0w*5P@q~SN>rMjP}><ol8rVg4aNms&f!(P2+J*X6N5YG=7ZFTy%eZPd|hma689l zdfPF0a|iR%Uw7x?@~n)`)A^&EbkbV%I1^A*UG`=OrH`%50d`zSuu2;outz`{7kH0> zaYa@xDOglbBjy*b>snBJJ33ME7)**$IVSNqTJZ!kr%Ll)@9_1*3iWT(6C$V+VPR0e zyW)V8+>W7=%9qcv1Nzx0ku+e`c3P<ZOS#B@s|negEvnPo`T>MPAgmhx$+`e-l;_o} ziPkL5fAs7<9NxK`x_9)Pk$g%A{A!gMpoO89D%VN-LG!cO17CuEM<-?8XbPQ@WS;XV z5%>yV^9@!C2KZn3BRfU%x^W161Fo$`!1SxFWgDt~Roj4&#tIe-;dfx-QvP76Dxe#5 zqZHlUxitpt81+y9_P3&81)7Uq*fSFUdm~*SW>|Q4r)zwo&P*{bIAwMxYD5L~1i{B1 zpaXa8{Cs>mfVc^K1qFF|c{wFD#+Q-6oz>SZrnJ*(_-P|9hcz6eDjW|dmP_^Xj)RX$ z{a`8%ZWN1@K#oNOU*B|l^s~P4x9?L0lO3cPpEYI+ii!}l**GYkDZgnkH8EpM<PQSw zxh&~%|3Bue(}+L)CvgALy=J7J*#5Q_Dk#X<TJ6I)-fuvi&Tl{++rI(og2ta`rrcnE zP)~ns6u>7-mt1Lk&@okgYUDoGNxDr&MpmR)l37qdv*Fum+_8GFvGMuSCwXu~J~?=k zqQXh?TDI<X<j7-vXGa^<o`*!eARnEWcx2cKDk&=`3}PJT1Bz8;UA!T={EJr~$C-|W zA9De|%9_`R)qiT!7)pqH!d`?ffGTqN_4nQqQW2q{V8Ocac%2YL|3iU8-*FZs`mek2 zm?DU<HT<~@C$3Y$GF~F-19K|?TGf;)zOH-V!hC!t#Q*{AA5C6F`1lA-rhtm+N=GAL z(_oDQGLuDxg^K9Egi#*<-%WsNyY}~YU%BQE;QswU|K=ch2)@ii|KsWtCjH?5=f42O z7DB8Z<A3`vzlkP?58aH7tvhNt+1c8-JWwxm@$Jvwm8nQ;X!9#BE-pXrU;W7RtUIdL zGop_aH&3+B0}&qi?*6XHCOgghV_lTDnHk=tdPvw!Xy%4Dc-g&x8QeS2KM=_5`fGEe z+OnN#ZQZ2q8mVHElJH1jsK~H>Fq=nl<ff+Ii+PW|(W1vIWdvL^Pi(G1&Gc1WLR-pa z)!Vgs&s&J@jS~)PE(b<N?_h0Wr0>fx*0G7*h*i&?3Xsx#YYov5O^pn<*cc#-ekCp3 zhxT2nEjlVq?+(IOev*O(k>^X>PxRGn2eWJxc(|^OP5x2zJzi2~x#ml_G_nc`dkg(1 zQVQA1Mg|5p-Y_N>+Uu<V!o|l&+9yc;L|DYs^$lG_=*W5fmm+3P{$P|5YBNdSPG%ng zQk)A_94R_xnxw%=;WxKwSuFP3^pX7-yZHsC-?`NA>~c{M;WZn)Bn%XWno#(5UTR;W zz!vJi7vktxzLEL#DMl(HqMl#MVJNSMagQu3%kvIGCap=MuQ3ql%-sHYD-D-SWX!ah zjc!F6xb_STQfv04fOTVcw|WpJaIyQ<o-!2s_1J8eYN@&tpUWu^-Rr$yCGKe(>$I_S zU3V{1TaR5%_Z3U<6z65$zU@&xOJFyX%`=H6yJ{FSv;-Ao3`0_Ad>;GZg@v@wCKoTY zrVCYU8(<urw|*To)|j6>UCRoRNnw7?I&)w1CL1m7W4-Z%-1Diey}B_RrjGPj`oV-a zTXChCOU^JQ2aDOzK{|8xMs?Nr*_oMjFLtUC4F!35`T}*q_3_(kYH6lAOS?tKt%U<8 zU?(D2@V@FknZzzsQJk7)7}<J8M0_Bu`i`b=PoI^;`9!>WEqgO|Bad<SNBkI_ru^0O z{QS3!dwkxJ?x(kyg=K1S;wf)r8P#h}hPhu(ZFf<Pnk$uM78g@6Q^}1pFJ2OuSuM(P z$oIlB8Lth@Fj&OJQfNy-ztnPVb-jF=LwiE~?D7ZFqLy28N3zpV$A;lx;$Hk!9?sE{ zd$sQ12)Mt1e>73mxAWcovR4|WU+|nYsyzsaP`RKn)ykw9Ft-RankMj~Tw31vGibFQ z=JYKlMx_CWXkaC+mZa#_^AJT68GQYv`m-l8ceh)6i_XL%!Xg>&Gqt5Y0)96LDs86j z(PU;=MlUq@+Tjo8!)6uFSbp7!=rk_auc~Z7J8trColdKp$W0e1t=kEe_HN#i@Nt0B zwPDrjiBd}m$#*F_pso3PGP0#QH8r&kvLLZQQ>RHvP)K??M%u^h+``V#fPP3og?~e% zS-81`i-Gz9)3~$xdbh=perRrVH!5u`=Q<W_SV(oz0-@a`Ju4GeKiYKX7h%V_*jj6Q zYiPURg+<&!NMu(;KNW$OwtDrt3X4&FGOI{vBhc~WY<v>C355Wk+YXic*M0zuB!s!f z_F6I%VzEY@;dy04C-3oQQW#rJA*X{$7hLf&PU@0|ayw6Mp0e3~euwX#F)}fCiRuP4 z;ERL)5mExKuS-*jZ6p>T)dn1WB7g|)@oK0wNmZ2$qn0TibHJ_jPG>QnNC^!N?j0(l zB&qI%-H#=-Nlq#z%0N+J-E}a`t!2kpaw8%$_?!ntvL#?-1zzlQ<-bJi*xr8OffV|I zuCn(-M~gf54Q(9#wa_|dLToG|0-2tF*^@nz&B#`*?;6u(HpqTLPz;48a`QCI(dnol zMkF3LwMAa>EFfZLs2kQf$aQ*fQASSSX~HXJw&$F@X$<f)laBaxvqk0y#3W{!7w0IF zqy6A%6;~Sx2!l0euqJMEK57{rmXuAaEPGg4tc&q%3OqL>zwKDG{+6+!NGF5Mh<f=2 zhKsw}e4?Dl%W9$aX8Q|_i9VII_SEc4UOgLaVKSqeL%*ybl+|p%PjJXc;8nmj3`@I( z{jjHBaK^xT-jXodGsv!?{BoNZhETu-&d0#yYcZAzqKANrbvYv>`Ih@j?O;3m_ZSZF zCx{k{4celjVTSddpRwp>tkf!8kj29>ireL+=&(iwbFxOIKUY2L)U1aR-=Er*YPulA z<w{R*95xH)x4##Eqa$Wm1W$Gu(0qTzj1>wmfo2*Zs@KxK`BZAM$eqex*GsE$!twj9 zX{VoGH*J4K#EHX?IV|rotu|ig6TH1t#E>sgZzJMRl){Uv66nlFcAl{Y|5U@nBinn& zL*L7OxRYpYkp7Y(hodKK?>Gy!kw`?DT*%Y(i?Rp3p>wf?VF>?yhFyx`+>>C(NSkli zBJ0%M{JGsv308l-e!+dlUm<<}{03?pbLL_b(JRvHAG-k2^)ZU@{zUpy2TrW4tH}_Q zeRLS(4*~fZKKFE^&TPJ|$DJEUN`(7dGHLGZE<WeF#y3u{UO>2tNlSN-%};fUapr9? zYt!(Y*6}hDI||=A0n$D0SRcTp;NEZ|FGHW6Oz*Lu?=1khuij4|O(gW&_UQM93`06i z$s9&F4$$-iOms@63LT4!-&RT;@3>|<mF-hG5R6E}%TaR)7phHUN1=UnHfp~xnPn>L zYo)R2PIYAEA)TMAv02~V#!*R%$Mhoig;ZhFYx7tqi>)vvx1+bSV70fj8sBXkd0qdq zta^box9f+7O8$aiO9^xE3@$xf(Mwzx6Vou<N-SI#%9|ejm7v7?s{S%Nr_1}Sd0Z(e zDKRnOwV{+((9uCrX|4|)Fy{DmntU4~C><1a^OjN3(f2i<FQG5@NEw%yDXo`Voloo0 z`cV*ZP!DBIE!9|CoHmd}@*TvQ!x3{o%AO7?Tl-plC|2chE=*1~2wT`NerdhbYHg$! zZmarU$g}^0R*EFkDKhaC4Cd3b)W}G-@PwudVqMOiO`+y>S-e@Rm6pp@I1$N}9eg~Z zr#IBJ&#Nk<w4e0e1q{w)O3rcFTy$b07|Wz`e#;S=9^h@{6l)&eV?P?zYKH&vbK&gn z1E2KPpsHkAl|xtITMmDWAfz9Dq(q~UX=Cq7)tx&N@y?iQ6~3ZVKg+L%l9<(54oHHt zy8OB!3Z@cWR!lr1xM2#$rL*}=KJRNTI}`q)nz}<C)K+@4v-Y)^$rllUZW!KgPRLGA zFWzDtpPmGD38>UdG<*3qvI)YqGL?km;+;ASTt)W=LZ|V0Td5ocwV?7M`=WOe<_yrC z2cDZBaoRYjxLKop?ex>rXwjv+mHQaC8)Xs!6PaQ_-X2=>d2(V>;yK;L$e{6LGG(!i z&2!KbGhR<P@y5Pbtq${rN-Pe`;m?o}*duNSh`}k^INHX8g_rpS^pZcyZ*|4cunz&d zNRD++iC%~QBzz31AM<nKT3n$@2EnAz$5|%LEN%zZAMI(374NgYWw;C`&_QN|Z?Eah zifrcgUtnFfly@Z1tLhD2w1BTn?2HS=3<43cd};tQM7yi+Kmhs|K4%*91N0)2KDHP5 z(IXJoHNDd%;SDtKsJ+-6m#dXbuUOhQz_X;JUG{uNLfv^^h}=g#*K8{k2YrpW-3=PI z{f$Cj?hF2H{c!YmAuH@g-EXSlt5-fX_EaQyHrQx#p%BBCA-}Hc`uSu>w<K9HgXA+y zaab=&iuy^#&zWW5ie)ZY@;r7~$|pS?dbKNTqHh9?6EPMZ&8+LlxYE<=6|qBXztBCt z4$0xo=s~lQJG5Nsg-bxf^qRa*C8ph-P5%_fG^>I`cA89Rvbm=Sd~A)CTob18VSavZ z{c6eHYmjetk{6>HzAl4JcqiwfgH4<g;KSv8`x6S|P$sp-!fG+NN2q%=jnj5NmeYh5 zJ%Qj>mV93~u|}t%pCoFF@-%Q9k<Q~ep&NmkQCM!ooa%cchEzUV2P36io19~14C|bU z1ua#CGoD$r6Kl}7_(u1}meZ#MmfZC1VCAT`Tc-ZYL{?l0Ey*GJ`AFU%5fuCnAp{sG zy*2lqjR%}A7T1|ciFmpjNj&zt2Wry+39}!`cZY1aGwDhft9jK$G#a4`x`(8hU{+dh zV4=&yl&#*>w_SL^U_c3@AQ~CzX(>BQAtaO)73QZmts4&-MKDvZ`g%anH(8n~?s#Xq z>wmyVg$StAP2qBHu=Q)al|h6_+{x7A(@RCwuAzECshi?EmDpm#nbIIjO5E&$J(L=b z2J?Qf)vpf}Zr6?hL`jWT55yWTBs{?<>No28>nW=|&vEnh3|$X;H3{5qI`E}0oSBlK zpXKD_oZQ$$_zA|pOorMcf#0FruF}R9<Qc=j5J55A#zoA6ym8vuBxm9<*!sk2^Fe2z z+4V-?TdL+Jk6iQmkC}pyYoqB2&V0{Zzgg>V_7E{1)_Ky~zCXIe4mS3pMC&h)X_BAr z4`9;8_89n?BIb!TBXnbIS5cnj>W&0kots7vs?9l|^}<GG5R)N7A+JR)u94xh9qrB! zSBTUMq`aBz>L0dnu|PgP_6YI~Seri^hM}fqdkYuyfYq~KQy<wM7nQ=X*qBqo5)|ly z=4iYB;m5AQHvnHXorO8Z*5wm1PI~Rh<0Y7wiMF1MIzY|XibM`tX@^sxX1K8mfQwj5 zfe_2q_B{b)E+3neptx3>qqWULDm_stqRVIktkM*I-Jzgn`Kgb1Z!Dt3kHYgsl2_7c zO^6L+gJ02t(r3#w+K}SHYi8JHx9V9LBSU5eDm7e$DX^+92-U)jb&h=WRn#_SV3mV1 z$^=zS#P1(F1Cf48oPm!5>J~cVsd-*6>N6j1<F!yT#bOcy{yxvQ&E<9Q=e`R;=>j-T z8u_@zSQKnTA?Lp9Z+qy#~L0DpX2k)pi{XWjWzR@!l;K3@5BwWl)A;r?f8unil zRaO1kb!NG!G|coNOY}{wJ|>InHkm(=(sami_}yS<_)Yw86H#nwKB2>DHM{B0O1~tb z#=#D9ar@N?8C_34LqsnD63>L7Mxc@6=QTJ<y3goe#ghfLk*C1XNAOgI_w6}5TAICj zfF9y4_k_Kn>S@A(_wgQLKWe5xUR{3{;LoVdf*)aAbwfmtUDDHwYPyOh9QcBT;W@Ga z9sOOorw&?=yxtn=y+dV~-0gRV>YBIEPJNM<-7v<wOf+e!uDEf7a88T*=RI&5ia8SB zGw<f6itn$!4@MqPT6k^-;jM{93#{-nU0t+@4n;lNnaI%3>kG%Bs7SvON2B58T-5UL z&`aG5zG5d?(@OV<h~jtM&h*XnEvOj()G#?G`MxGJt~?7qwZ7~G&Ilqwso~Z3)!7Ns zV^Cd9**Shy-E5&xCM{q`K~|lKLDwJzqq)VOG+cSeX4UQbiq(3-X0lfEBZ&&rREcKT z!P62NoKt@^uLQ&isX3;vva+(0=*{w7vT{mt3Lp15{2HL_wPvLs5_i>D%%_HGJI=7n zbUA`*-WcSuepY2>Q7BP3`I5k%3ibY!EWt6Qy%xTYSHftqzO`Ta+tHG9>>T*|Fnd)X z3ayjGs1OGD`)|+`D%GBPoDtb!<dQqVE5LvD(Q(J{B0yt$n!@9L@_I^C5JFNIl`O>r z2On3@M)b)is4fC3_H|6K1bvbPYfc;I?Iu@3KbY2HbG{z;x%^rnX}Uxc!>A3{K0!CY z=JH;@>4Je%U?bWoAvl;?g)S)v#%U&eXefU-iq%}9BU`I6oAKwj4XT#}T-AXd!j<i- zvL?bykr?@8iF3N#LGPhnq@5Zv$bNctL2uhu^A^r82Yb71Wtm$-f<#ML<Iu;Im6HZ4 zhU^*3wj7J}cE5;(AN^`ffzi?IP_1yL`G)FMz*B<?#JX3FObXl(3u<be+gwso=PE3B z^<`WOYUO+O{FW)jQ9}E<uq)jG8i7&^qx>HSiB!-N8L;-qSRk)tbR5bU?TM?7&9hXJ zLl-x|i^hK|gQG!t$bj~JYPYalMu_|sG1R_&LfHzs(~V9X1YPms2&8r;?@<M&T|>fb zsb*0P{xV6kY(J&=b5RsU<<S+}zB;E6#gBDty&vaPIXYTJrOQ)k3bkS_X9O1m7lhjR zN#;~ZGMMCbDU7YB+9e0+sJw=-WkRMAnzKHd<TyB15crnBgxZ|Wp>?VX!YsA!poVYZ zjF~CKl<%k;&<Bh%Syv$zkC)fO1O>)1=p*~kRTjxMhh-34_4$_wuRmdwJ}-<@Wf$=4 zvx|<wKglSNyW;}4k#3c{)$#Xh*dIGP$$HYHotQ)U33Dl;eR%14#64`Va#ffK>-BU} zyC?!6ZX0B_F@Jg0N)#Hv(VJ4hJA37$i5Pqo6%}gIn*|@0>eXzLr3;r$Yj@{E{t<gZ zv<GMqb$IR-)x>1h)_VQyHC!N$WYJJvz;`5Q#}F#`uBMHuXP;4Z@H)nZ^kSb^JwVz} zYqvQP3qi*Zq7d^Vz{6qGb?F+JEjG?aZy2v}=rf~I+w@Lf(VXZ?hlO1CL1Up~A(xQY zp@o0`yzEp|P!K`LnTSNEGTG%ksFCwRB(VP6uWxj*#_D3w&)A^yLt#5oPzBK>N-PGI zng%)>(bX>~`sCN=y9M^gL9arTz7}>KG@+b7!@{P<nS;uZCi$i6mUyQ6=Hl=e)0|yM zq|S8yxzjG(<o4i$58_(giGfG75Wz|4;K0D<`FoLHQ79Vw+ztdzS*2h0b>!{7d7_$Q zOHx4SZ{n*MywxI$wMp2Q5_<5UgS3R~?OdoaYd<R1Zd6E1)nxk8UhS6z$$)wtbS}La z;LkbPn`PL!<aIj*MbGBu;P}z0?At_Ux6d6t4UOSiWsSxKRspq3sV+0RmE8K<Sh{kP z@rfxNN;o-gy?vHqjH@rCCSO5J-dB@y-dwEO*hs0bIr7x_rRocc7lM%zi*AE(;b!#d z=~oiuQ&VH@JdJK$Z26;&Y&FH+t&YPJXAErQ<W=f<$enC<V|k)GjK~LTdcHJ=y(R8v z#!{c0oHg>a%SuOLjOxlQyCoW%P>8BDZ&Gy5_fED6LD+uyYSxLe;=R6Q;EV2~&LEjL zn;WFy-?GhSt2Z&)j|r96^YE$Aiv;}DtUh>nX*d>_pL*0TqBpgja1=@cD+@S6ddAl~ z<q&ySRU(z576RN|G&VxEzKoC!U3ekoKeqZjPGYGm@^=%dUTS6dk=Q(pzt@o8Y<VF@ zS5Hq;ql@~bMW?5?MnX76j7*;<AxhQg;Pg6QHEPyc*O7>|y6u?z4!sHIA#noQ#?}j$ zp>2>`O&mXYOg*jT*yZPDkIPPmM|O9f5JIe6IC`42fldMkN0@AxlT>|NWvjRKVj)eK z>)A??d=LCliw9~TA(8~1t$m=dF!VL{OWsNEmFI)+XNF`mhT2gkCcHiN-mSZ9G?=-& z7Ll)O`)a+q+H1FX1_}3iQcrKO<$;>Mj0qbGu5}Fxg@j(6)5`#<YcD7*Ew}OV7>+&* z_DxwDpK}4;rpooJ<C=p1!`oX&RkeljqNpGx(y2&EcXuk?-Jo<xcS{M<-HjlPbc2+n zba!`m?>AA;dt<!u?yEb-J^yfoz1fSk=KSUtzrdy?w)u|t!fk70lTK$9di8doDZrmU zZR*=c?K5K|LO<O%tHS;#)3>r8biZOrh2nex9UXo3%(?E&duKb6MrWMM>B&+CaRJlT zBQjgvK_>z=s8#u@g4iE70m9xM?C2v$Ytxb`_D3ct1oK?e_}mU*m@+v*>-4%U+Tu${ zUCw@u%gs!`y4Vl-w3=*0Ii6oUPZ@7CC6T&ADgV)6eGQdc>xP`RmLS!*(yNhRd<cc* zei!Cs2LjP#srj=qxQ591%kZ=FU5)H=Gfl{q5~?oA%1^G~@A_^pcose7P;g!nRWpQT z-!Slw73iFIf308``GEJ6@FnUXyiqUMlf+N#iFy%?#I6oBSu8p}B_{B#eseE0+K+nj zUoU_zomPVQ)L2HN&VbEG?+zDl3wdu;+W?=UERba^QoL@*W}0g9nWzj?=krAjGBK&U zZl2pfP0%JKlo-&hAAp}A0-?}kmg@F^BBBD@lV{_hojjQ>zqF_*#FpFjMC*}?Pr&dx z3!XlW+hJm?%$dT}Tyj@qoG?cHYUX#tk5G6Wa^BvPi3T@vGRh@Iq1#Ajn1pBM<9YRv zZun}I_o)b0I0A}yQ5M6<E6}$dnSL5~?(NCr!5uP4(|!d8$jK-Bv-=I<ONVI9rXQ@~ zO0<5>VI)CqJj0^QJ`Vg$y0~s$Ls-Y)*!ul@scKU3>nknsBA>=8#xETM#J3nP%06kL z*8h?Wufh3g7mIfPvRa1&ouLRkMxDD`Rn57}wnS6qGWYa1+8JQ&^3j1bEND@6Kz*b4 zeAfErBjd(YnFZ+od=(dO!;YNlbhc&v9Q@f|T|h2yj|DA&%nvY&dQs>EmytBUrf_8J z_2l}}(W>s}>QE&Aa%*hw9U}pMr=H<U>gTtGI>l%&j#iA1--U`b9ubCrK}Ep`iGgdU z&{0{k7b56T@I$Xup4Qi1n0a%|E`W8}f|`)cKte^G4msOC4e1$Rh?9E5t~Wbyk1~@G z(%@7!cuY;aKg%L|1FHM?UU$&Pz5S9~(aH0d8M19A(2xv&|NIWSkB#X}mL0w4nnbS| z_w>vHdJ_4Ayo=maZ?7d)+WkH|@G$*aaoXeaV}y&FbV#oDy19d4L%u6}2O0ne>towz z*VO3W2Lon&gR7+xHIGrB95lx6mh;C?*9ziqknR~QIzEhy?+6F$Ij{2z5d&*5(13S4 z9e9=}p1|_KuvDXtm>g#Xq(VIpF$)csd<=eYE$PsPpsBgA2h-OVTlHD)=Ur-C+$DX+ zEi6p7$Q3qA4v~&c_Z<MMs}wH=olq)Es49LS6ui6Oh1GR-&dtdkugbrsWp(Q{l^Zl# z%tXJ#o?wU;cjLrVeqlGJp~_wfO(Q0P^y=qIB%k6E!RHfS<fP(DkrxLIj@jHs*mF5X zRa9zs8TeUj%OyZaq*IGe@WXW5+nwsu&t4ynjs!hAtm4zL9F|XzXi^C8hiwzSdR#3v z6B8I?i0YxXo+Fn&-FTY-TF7Xn{N_8gytm<DNeqgblIYbI_Tnb^{nm7a?B(pgKnv;X zM$j}DF%@3<mqq^<zq#z15no)WVD_GGB{e<4mtpAl-?ABDYY6^~DFl!t-SE9woiOqD zfkYmi(N$LSJX|-cd;Zi)%H@eHj<sL{_(GpS$lTo2BQ*SQJEn;hx9<$!?WM(RS*iB! zMq}4!<Eftu&Oz{_*d`dX1)2F_qN~W67E-AUX!E!w6<~(d75=98qWbup81zEwvP><e z8s8NMQb8m2UlS+C;7yeJGD(R^-Q2AQTV&q=vcxPt>0>>lP!ht~Xl931+@X*uRL7L< z#ird{C0XS2dKQNq-!xVD`LwoCG`ET(XkO2A&9-t-9U~!pr9}Pu(kJU@5Te&nY><_0 zo_y0u<+S7vPXR_fF-o#(RcQm7CWp(+tK#)U!=Z}_tA(`t?f%0bGX+6=pW?vw`asvS z4>e%7{%b!YL(awvbt10O#SoN>EAP<bc^#GQX6ss<!gbk(#of84J1K6rad6N<O@kUi z&EekvTY9PpDO?dL6TiSZ|07Xv+<n_mf;ME<w&ONmcU;7ZIO$h|n&k+HR{fSm%Iq~3 z9Oe(USG^3c%AaWAxtP0kEPnnsJm&bef*vjXLedWM^apGPB!(`(&k9=f#U9pHsBQf? z(4JOHUb_zaXxU1|&qJ)B1-oXiVkBl#TbKCts_hvW0kfh$&MyXWME(yN8ueZRa*0ev zW{{KbF(2W)B~S<iK2oYGDa15|-qw)l*d$ytG$tW<oFjkH>4y8*1ryU-;t|jlibuSu zy|m?z-#yl$mNw`n{9eS^$PmG*%{%`@@zba4azkf+nhNKhMLz!?&ETj|XH@T_?mgN* zPR}RNEl=M_d|CQJI65-s7kL|Bp`bu`?7v^0VD84r*?W!Yc*Q06r8tQl=yf;S%+g7f zjYvF4#z8;LcjpZD;)6|$2{B`38d~)abYAVj+^V2>VoIPLH<6F}wN+xJ#ypcbqgYs` zM|oASNkFVej7A4W>tRN%gbVQ*DHJ35{`z)f&YECq`5<ACSDD0&8dVri#f#gT$|YAH z1Pm*Fw1xx*7>3Wm$kHPyUR=1H-95+lcfu#5Ew=twgvk78Wc14_p^h&ldE#nM*2s}9 z=plY09VX@lo6EX6gn$`*I?zHj2U+|OjRcwY^V#%`r*GW!ccSo~@jb^@VY%k#6~}lH zfq3M~ycx~|{oKFE(V<XZ``HDL+FV)CD|RymX<NUPyW_H$tN5$I7bpKv-tXE{uiQQl zlk)PCh_0f@Q+!6E=ei*&GXJq2kLg~WNEisQdtmnEfxmPYa+`x+X%Psc???5AV^tns zY%mWb3~YOebOP=BKQRx-W)W=7TvSkWsH{>_Qj*w-Tly<511IzncuG;!9Pl;T?CMzT z;!Q*7j2JD@{@JJbr9@cM%e~=q;R8Co&+c^}p7>w+btELn;wIwmvRR}vd43D=vLdB; z+Yg3J=y&F)U|O7r+1*km^(f2(9NCb-`#Hc41OjV~Jr=TH{KnVmNvEt(<A6BJj9oI< z1o@`Wc@m!1oWO4vRTkNbr&@z0{Ytr11OB^IVwLkv$8e&0A{dr<i$EUkZ$WxkIAK8x zs4I$!BurGUH}8%8{_5($t+a#@i(+5^(%0}PHLL5?XExg8lgLTSIc+AZnWYCn)^MnG z+4QcoTXegwHd`<NUCr-<+SLr~sVt6HASQ#fNw>~3`L8+-;R7;Z@GXIeq~vH{S1IUV z0Zvq0q*TrO<D~IILKGAn0C!a7hY0w!{32INNVNV7P3V9CcQ*(F8*3pxm+MXcHT8xO z8A#@cL<9win3<#Tr6pzcpC~J1VgXIGy@~vH_{m9sAyLrB5NO~5)nD9zJXzbn>A=ar zG6WhKdCJ)Zo3qF^Hpj%<#pcRxM^~Ka2cV<x4@4tKvh@_2J*f39dr|*>I7A){PsD+5 zx22h0rTzMsqQga?j>g2u^qR9$*KYPp#RmPQ^J&R9%deoUe=lRYSnpzg)-{c&npa@J zY`SOtUZ>86n}Wjrp-B9{iz4{v!}uOR4gMH0n$ndvx@^J(-%dsPqR2=|aao_mBz~0# z9V#%weCp%V7t0ubQPl<dF^r7qz3~+pgMxp+9P(;#p@G8_N~#J9KoL+7>ylsG|HRPo zfOoHX_cM@IbMhW;s_@|Mpr)h@nw{~d%*_tv|ASWrMu9EfGzTu^5G*H00673t1hn|` zd$&%6b;9Yt4?Yk=Y+y4;4%9N*Gxm3OW7`P+$snSP5G~96U4<zAK(zhuZGx7EBmBSq zc7|2L8X^pgKhPEZ_t_EfZ_)2>nIB;)&2kD#Qj&xJZJI;@CQ8aE>p_70JB67D-Tu$i z&-Q7QxFD418s^Munv>crN$_6)%loizxjE5hk5@U!ZQ>3nQMkDO`&$T^nHAN=BP-oJ zfie_*Ozd*`)dMG8+P{VP?TC}^NfZ#i_)2o}1kgo%Nwc%EvVzK)wD=blM*oRL3BBn4 z20S9g$l%D!Yd2v5vWD2L=7ro6pGVjqP!GWMF!KHSMM-Hp9rRVn?cwo*JaOg$y(Bgk zP+z(a{@$n7XQmifxY@Z`&}Hv8F7AMzLl3=){}lvi>>NXCOX1B53Oa*LfjG(IU4<;V zhe-lVx37(&x;pNLBUxhLUB(}+*K0ChVyq}2VuUrzpIwkul$8|%8Fj<?^R_#FD599S zw8*qHZwSeYirn(3tSBgj{T7(=TF4tUI}G<}US^WyPo(K7CrDgrxT}BFu^wgxo>Ll2 z+QW1c!h|Vao0^c1KQs_7Kg@pMt~v6ml&@6XauD`EJd?fsv)qm$&u(kvW4(49ZoVsc z(Z8MZB1hm~R*f^T{6mXbfxznIMjJptSMlLCGwz==<m2%1e-Xs!_K=)}Ik~9+5Dekr zydV#$f1mYLX?8|NMiDdyCZ@W;R}xR^#|t0Y0#qyY#g^>Wg8Y0S;rKXexc*Pp&f!BX zSd?P2gFhj_LmCs4c}z(;bAxk*{jcb5%QKwm=oSy^tXvH((cpg{0@>)BgvMbR561Eq zj3)7fRSIi?rC~&miXxg8uljofpaQe>xHNRpqX?rpR-8bQuqg0c$?egJ)%3qz8T+Ff zhZf0U<|NIldnHY`yu7^GLy|g2Gvwd0?VwQ4Qj;*ldy6i*hWxl5Z!N|u!O%aJ*sS1R zcp-Xj5S0{!@D|;}j6NM`rD0E}d-SiE=>FX@elLQsM|}*ke*Z;@wH7e)lK3`Xi2d2n zkt7jP+qh?kvulWGsn<^}WR?A!{bm3D=-G7Cza{SU!=S&vSK+@X5Q!ckg(3rXAo5$T zQ<-Y(!F~m0`Q?A7VB*h}v`FzbUfstFF>$Z#`fJ!pEE*FNBUbh3Df<5uKK=($<$w5X z9cy5)$Lo0#<3FyX4D41)b8<S@zXFW5T$LFnt|=gp1HVilI7;*y1tlRV&P=(Cn4F-L zM`t&d&d|i9`(M=ef;|g|#e8kLy)85EMytL8v`R-u45`h=3V3^6_5jGUcFu11V&4T3 zt4C(_c*YL!HfS34HxB@@!q%4Au=fnGzKJ6uA{c;&;J0sY|9iaIkF?oDR&&=!0X{e+ zq+Q_419Td`OQ-hV_tB^~5~^;O>Na#d1=bosgejffm`${KhbZX3Ucld|d-r%EF-l2= zxLxklIURbE&8;?jI@rw~tgdP{xmJ~EbHCc!tuQF%<pt_Y!NIo$s`d8wHx6$0PH1&9 zfDHox-hlE-t=pVZ=>{l3ghY&G+Ouq6emhyZSfn;=ySh;fT$5mtUjzEGvNM!Uv#WBU z(Qn{N^<$nJApeWC@)hLdj)1$=k=@o0)L1HYV9gxxZ+$+X0P;D&h(&2NIy1^-%y7>* z(aC3Z>?l(MPu`nLf-@jj(g8FYowi4s8Wd}^x#zwh;Wz4c0dngFqV6(4ildWDpC6yc zX3hYPM|g==(-#2)gE19$Cm_cL9IuP0GypgC1F*^k_AlVAw);0on`Qjf6R&w4SLSao zCni{7U+x8@qnv3s*l+w@gn|69fSi$pOwf1)IXknL9b^Z@BP|B6H=ZTx6)%}wyO+G- zoVMrS9WNbrwWlBAfKCsaxmmCP&}yo8I&?f-@C6j7Bh_SPCqXl_oekDk9Cbh}%Vx0} z2Fo5ui8Z01q1Ef(viUJHGkpoS$C5EMG06iKj-NwALji8!->G@W`Dif;Nb(aS566s& zn0@hrxg<v`ozw{nL=)<bKudd#^(k;00y4Z^VX43x2jl&7a|Dk-qw^#Oa+x&X%`G9% zh@FPc%BoCVNRS>+srV}k*d+7a?a$VLBkJwn6Z8r(5YR48DJO;mbQRyFQll*OUtXM- zg0Z^jod?JmO|Ie<{lDJ723jhqK%KQB9WJjR&w5(-i_3hr@#4;S;dr6ucjLi>QXLmy z4;h~0-KrxlfBf@-7w~ru#w*+aM}*^APFY#s(f;%2pe2z#*oRAe$e%rP{Jp2QcV?}c zo8xU!c`QKiq(67C;F_+9hMa+Mfhf{$X>O9azLv^_Q%ZwHyKUIjEjT7rKUi9(#m4p^ z-T<m5>H1y)r{mtYP>16CTgM9LK!*nm3yWf)u`C%&HT}&d8+gwdNu~GRBT~S9x?XHC z{(E9#5CSk|q&#C`+`xJ{|NF=)=j-|c<)YqL#!cu~mcH-WkdV$ErERyf_4&w1zb7Q) zwIf3ge8X$P7aJ}YKq^TJZ8b_tMk*@YnUIKgum7X(!BGp1XTQF_(?*aVl3{E3`#Sqa z11wAc7QIeU!jR7NR)XwfI-ZDgj3t1AiwT6${0a&XMDK1RtRd7mT+U0t!MDNwKnVmK zetwAHyDttVi<W@BvPIY2Y^r8w?9}FTXf;=xe`KfnqLL4canQ*_%tr?-e}4A73o!8{ z0XziY-U-+enW@@te?mv#(>0(n5zz@`$R#9#PK{&?BEgiO%kxHPT>@xW-|z2hOqS|5 zxj}|wV)o`s;Nialxm@P&AwYgjda(Nu0FsE@c7Jrte8_(lQ^sI7yUuKRhC=e}p0&i% zuwQz$`4=qoa{#m4%;|bX^3Iob_HrPFsai=~d(QAS?OhN8f)1Z&vE~%W@87c0T8!5h z1B)b6Gc!WTQF1O49>a;1=jWde_}!V@W}KCk@x!hziNLcR$`U?>Io&)v;Qra&%>Xz@ znv=leCRE@K=xYIM;K>4MxAQFF(2x)^>7*al!)TFqKnZNLXBg;uol~pQtUkcZRGYFI z&H3HKA{Se$o0*xl{atB?&sJUU>)Dt$>JpN1%}veNYAn<$Tw?(Qm=`vjR+j~x@khLD zTHO!F;vKDOL0(e;bYbWp)TzA#m__Z^+;jD}KcYQmvxI{{(tY0A=hV8_!w}u#yk2*> zbPUu@TZ92=0;s-Nh?!gg?1dKA?=b+6`#Ur)+^7a5GYgHWq$HeH8Gf6YJ2Ir*R6eii zwz<mqXcCz@r>&0I-5UJ8nV&M@z#YZ#lp`wxOj)fl<P{MS;UgR?AH7-U>s{S$A9Yg| z6!aqN>+6kW(mx~VsMbKY1)7@8LPJC~mXYfvWA?<Zj~?)`HXxzj0ejNZ`7%ki0*Gnx zefnrQV0;J&-0qEi<)rNa$jT}TY>bS5!yN_1&E>%az&whnaa3N_OV5&rzsk%lxB+pZ zs^oyCwPvgm<ohHaNFojy`c?l-SDh?&ckYDmp8DwVd#SILzg!Lp2^rK~QFAx-UVL+L zp0y*KIfMGef{*P2@hLbNz(0n@<bYOLVAwTW`yIds-`_n$y=LWWZKIiuh>wjOuU1wJ zqYwb6l(0Z)MJWqHHV_`q6mmHTe=0rr=Ml<(c0aoCwPa&tqtTss>V>i%p4Moh*1`sT z31FY^(Tt5AXIfL=mkB3`c45zKqTFA>$jEO+WA44elv`^PS5k^$W@2h^*pchX&F!9c zalVf2Mm|Gk`1893?;HeVt)`pV56pSmK$6Fhvb!5gr8>bwNy$m^HUz!Vs(#vH@bYk4 zVfJ($%x;6@(||X;kia`_UOKv4t>mO}ofa3!z9v;$^Mg0}pib}cgxG70*Fm7iXsuw2 zP;@d;Rlw_fmxABqczPfi&i?wCobX>g(xDq*=wD8o#HP{oF*zzrPsv^itW(hDRaH?* z<FV|hPQ4Az%O@ozcRJJ?<U7jJ%)07z&?L^*!(-1=%u%>#8B!=TQl2d4E;d)$T^VWy ztMpn@wGf*&DJhQ4aV_JumG*4?4S=d$zUGLFOyu;4Vz!)Vb~xSI3a`K}kyGw58kt%K z*CPk~FE#>sfPxb4U)|n+IjYlVkNIu^*(>I-ALZ?iItn$=w_~dZ_oBb0fHQc}Ei0dQ zCqo-aHpmdYbwoL6Y3KO~^Q3T@ui0zd?=XTj;k>R<Hz1%%0g!8Oq8mX&fjAb@4iDOV zz#z2qZ(_G{*g2<kwu&<J8?!eS^{XEqmdgIm?xpm@_kg6JrrbYIZMWAD(S|WPjP+2& zEr0Z%>Mlixn8$I<6)+|EU*qWhUzG@#_5aaCKBF5IrV|uyi_Mo|w|IkHKp4x=(9i~g z2Lz;!kKt2d`kimDNIpZi5`EN?c`qXD6?EUfjyCs{9W5;K)DcEjK(4#SD*rVRzETc= z3qsJPvG)@pr-*PXw$JdqBzoBo=miGY5))#8JJ7)6a_&e6<d4?K*mIBd`rlySal$z3 zcpxh+x%$95pxp@YccLqqXJ;Yj$u%S>cyErEhMDQe0Yd!z;y2a}K#uFwd1{JCEJK5y zQdg*7c&|&t9NO)5Fc|1-@lClcsr7fsYCVa9@L<0MT!vTGdsDRz*aQHLy;bk9*~5%I zy_o72UOQ)fzL7d;V{`Idw_*5RcZbHdS{(8@WA!_|^<(yay!ja5C@8D}u3uG2$$9%& z<j%y_7GQ6!0o$y@j+wcF&-oe%x*jt!cs+ma57rWO%8OpI*@$ae>@WSjDsfHqPAgu- z&l=THB~n}T1FC89CJIAmn=VfPWuU9*d__zO1?vqi{;Bw#Bg6Dcr0^R-oH<?)jpCd7 z#ky8kA$LT6$KNPe{Gt^V7QBv*FV21E*;!eE2@%a}l($A|oem$&u_+yo>m!_7yYq0g z<T`SGqGMlTa=!1pkJ|i9xTd0)Cj1#GAr-L(-tw(GT&}K`dMyiwAW=JYn=x5e`MP)0 zwd9<tjB6%*8jI^d8zzwIZi}QK9oqoWYHATQ!ANy<HAutoW)`~z(q+H=`c+O8=|n;O z2T9HEb)9)miuE)+<=!8i1wNAQ^W2v&!f>k8D)xJ*&O^iQ_s`UoAIt0a-hyr*O$Ew6 z#TqR+pf?s21Sv`yNNHJF#g@x*F1ys>V<roy%-8hc2gOsP_4JHFj(srpsLR@oUT-bX z0q+&cX`NEf)JjYUFUygL!(qz6R(Qi{gOxPfF=Y)|M*sck)eKufm+so}XgqQ{4*|bx z;E^;gfI2tbE*;m(zoXM`!bHXGG?dJG3uIUEE%sSjnSPddNQzy6@nRfRzPa8f3{3p! zhy>_F|4(}hUMv(Gk6o?1anN~0mHCX5k`R~n1{ZfeBTaf2tNL#L!-iIsr8#IRWq5+t z=&ul*yw9<}WhZLuV;R{)Z}E`Nr}G5yX&gdcAXR@_<hJWo^Jr24S&h$rg>4SP!otIa zV=;9M?K8oY6I#q1V>3PISW*QJ6dlmCY(3BXl`H-F_acm8v-u(F+Nt8+reDW<QwJiQ z86X#o7*{epB-bTRu?GONX6B|R@xtP5TtF1EDj|$*=P9s|RrI*uxStMImFF(yT}0km zHTYygm}30)!)DfVdA;Y)UFV!$j#Nk&=5nA;9E{}H!(Qx%K?BsW_X@Cz+^Fs|p4%cC zYNqIEf(?JQvzuufX=h@>Qz|ws^z~rQEn$2t8|;kVsJ^$B0HkH`&1-+7srBA9Bk^ku zMcSZlbJ*({S?#8+Vs7Lsu_9zv)-ezFXN~T6M{s~RfmYJ`n%ZU{E4Cf>oRN*mI*p^S z+5xGEMUD`_t_8RSpLpKmEoLV_qbt`R%sg4A;qwgno8STViqLo<wvgp*uywRRg@FZ{ ztrq}jgQQ6<dTBdX8Yc$~d=(@lWJI)Ad$+J_Vd_Vg^^F15IA~!Q%-U1_1e?Fo8jM5q z+Qkw%0F()2m3s6()Hiq>4&%kUM4+-C@^IMioh6|9`pJ6#c9>e?1E6s#)$+M2NMK)E zq8u}C1E<ja>Q?_XU9C@Dep&99UopodoZe+vJ%n>a*%%x!$b(LxC7#0dF{aiGn~0Lr zaIbq$GaQE-X|l#bivR&x-N)J(zKEvJU-Ug7pUgU$gr-|)uwj-R1iyufum>k=P}p^? z**)9GudBy5+S<uU{Ua`$3)yF9FF^lySyGUS)A17`5x3PbRlG3sxkS8zipt56`|LOQ zroXA7qNE}^**J)7mRc3xEDDV%puZ2`+pK`uV`SU#@PrQm)NUMTMZ+yVMMTbfM==1J z@-~Va5`~DzBSxe>6HpWjEM>H>1&K2Iuz#y4D9r6OZ|=L5QpHkR+Rio^EU?gcW@&n8 ztd&nVoa-&~Ks4ruYnd#cEF+q7w7O9E-A?sX5X~(%p86!|GPp67U#`S%{=uZ$eqpSw zQ6#rxMwiKm^>DxU^=W_K8yDS{T%)tAO7r<mC)fKm+`f336=duGdI42S(aO~YKjB{t zwrvV^^LZ?LlLi=Gm!qtA$)xHsn4`s%@WcihZ;lE?zVl(Xl!K)%0TbePwZWSe!TPY3 z%Q6=h!B~{UWhkDsKT{sp%ul_jROg2gRxnrvo(Kz-7MEaZAA~vCDrCQ$LK!&ib@i6o z`xZI<<<8_Y)px62*E>jmN?RBh_)8z(%cggQ(#aLyOrxLgk%x=|N*1FzX-F{npcV!v zDw#+g3UraV(mXg^`T?ml6ATFW+?J`xr=p(Zyi7DS(}OFddXe%&g^Y~UcrkLd5ok8w zJ*8GIf<o<ChYpG4KTykZzP2@l_SVyF7Ml+Y5r&ILuQFHef>c$qD0<GTLiv&wwY6q` z1dOP6&%Wk4%GE203&z<87hwA@>90dY;$dN3|I2@;|Kz`(F6JtY)^d&Yq(Q-XjtLrN zKYtSWeWYh+>aU)WC_+3&WV2LL6;?I`AbyGqz`pr7huP!)2r~12N9cKd!b(hxV0uIo zI83e0M8eEWbwff9GZi%52DRa?(l+g%o$=Fgro;20yxS0;d}^%YB2-O1PITc1#`|&o zaito^->>`PV9lA0gyW{NI1<$olKWHnT2Tg`gjM7#<NI6<N5=yh_VRR^%@Hd3HHD(c zpFQa09yKq*JA_a~(jJJ*#07@H6OH%pi)9TUe<CZdJR~FlFfEDJqWb`23|I46Hd~}h z;!ise0|QJ>pnws#cOCwO)&(;OuW!v)Dr!nbB2p<MBQiv|msFHgltzYzt+g-h$kM;4 zQ>O+XS28er(`i-r#&!aok-=n6)T{!J<c-dbvm7{vK?pilplXNv=7}(%{$CZs>l<XW zI9`JmHNztoi5y^&ysFX>#NWyW@elr9nEL4v;EiQ#eGmfQmJba7B34)YpEZ%nH)egv z+)<OL&em?Ed#i)epUCzAPS}Lm@br49*2(Nb-y?ZUqISE9OPV!x=Pn+5&KHBgGb81# zUtbWiv1-TVo|F(eh}&;dJOL-^h{t~40Ki9jJuU@lCOi77L6}eXX33;IH}lbpya*}x z?t12RC+o3g3lp||l_fmp>G5`00;4V_s5gA3r}u_VtliMyq2D5Di_Y<@KVb;Zy|7-i z*kH*$K}{bY?QO@Qcu&urhkAx5{w~)9tGoNNCF_L0XsjRvJkCGkxY?n;e6KGmzmtI$ zGUF{Vw7GyBgB$wsz<t+`sGzqGH>Y+E^t=lK@!;(7#XVnW|DGaXYXN|CB3(a@#HLtL zOCM>J8%<u8V_EP@ksh}bqB3c#p0I#Wc}Gr06#vXe$lz^6E2u0#4zsYcI_^zXmn-{s ze0wXy_W=Qj-WZi8ww3*uwm?P@lvG?TT;fh1@?Y^MIpz{mA1<E*1w-9l@pXDTN%`ev z@T7kSV)N~i$N4XOoZ)0v)1fTW>~G%;rd>peb8>TAWkP;{*%-o85|(u1>#}_H{qy9@ zy^2^hT7aH~_g)%0x^b`w34O8Ta&&UB`Zku<5*w%|aFW8HT|BHBuLu(vXTsYZtW@cf z4^}Xk@v!ietDI9!uof=Ucadg&TDm_vMHZ6z!6GDIA%^5|UR&#I`uB#fc*x%pxZkN= zEwqy#aT0F)Zb07Cd6RZHok@G(2Ac3iRB?x+*}?U$!%D5g0Fvb%*{&_{*blu1b1bjt zVmZyc4NMKr{|8WDf)57{l)gk!I3-?NeE@N>Tp9W9hRCR6sTuG+`8^(XG|kL@n<+;? zO}y8#Yb|H(mFTt5Wc4^I<S-x07|6GaCn3&G6lCF7DyIog`ScgA0S-VE7f$83-XXhS zOY63{G{nV`^_LbD6v(-yxaZ{;WCd35&mjvwH#fPYyKuHH!pe|VEnb|-C<%357P}o- z4HWbMOxPyK5#^^sl;f0`dXyGIOOKno*oI32lFf)t^pt?!0p<yr)zp9z2M6C`-UIWy zypPW~S`h*UD>_2wS3tCIEVttJ+BO5dlT7?+M0na{)`jNHB}8P|gpu8uvG-)1eOUez z-#*UwFk`J4M~j?yAilrD^$*vnbzkkImc2sC_=-)Z8Jqx2e5)-@-L7|vbEvf|q=yma zBA)Qt8UBbDjFrF)PvhY?{UwBnxvs%lP~NS<T3By6|J8VVWk{zH#V_)Ei`XZ$BZ*9H zTD5wzo7L|Un0?tFhAZW`E3j%a7($Vd)XMS3sb!O!pdI2P62@vjY8NRi)wF(9BoCoV zYr#Z(+%w%G{}lRoPL99!kbU7iJOx5|F;)O_1)3{gJKB@D^%u&K3bB?=#OKl4ZYc;m zm@Am1LtaeFs-b^$XC0zPiv4w;EI<oL!i0q@uRg3v{rr56{l%`EFM-YQI|eK=qB%8! zUwlGfD^**^R74X2r2+?2iEqV+k_{(wYlR)5JD*`jpl9_fj$Tvb7n$wHqsAZ5$w@e; zhpz(H)MbEC_HqemvxbzKz=;;Y`l%YC^<g3B<YnX)YHH2IuG6r5{Luy<9>Ug_UvdhS z!fDdq)*#nLQlX3aS!eSt=F@i%55!2dx^noP_LbK-wGwh^dzdiKH8`kVO42VQ&pfVO zPBc8!?Baa7X6l3pFbZ+myhLy^JreRGfg>i*YXPsg`~A;OPo@>_uTEUxBl7qZe&6Q* zuZhilU;ed_prAM8a{TWQ5YAM9>Hfm&Y!!k821-KW@{F{+zW>_!22XpweG~gPzENY( zjsEAI(+w|12J_@~q^e1{+rmeSaGHN(9L}huIGF<8^oUO0!;E7}N-86R|0?`$Z!iEh zBo!Vxxb}XW`>K5DTe;n=b^dQA+_qT@Ek*_kkFYBOH>W2ko%LUyI6H2OY>SAOA!_cu z?|6#X(16*{z}R|lz~e|wrY6P?M?6n6hy1I;X|S9IE~un=aNXG$lA5M|k!tmz-3!&) zbhZ^0*|**+COKN19@0<q918r0keLvZm?#|i)d!vGz|eb1hwQq^5H0{5>fQiz3H4b> zZx!uZt(2#pkQx0e=u4(+75n(e$k;f9;1I!i{Kr>>XURJ&g`|XF_>;!W_Pt!BQdF_W z8fkHHaXGUR(ko9X`UK;E`S@8&hZn3woYd68LCIh-DOnnmpvS<FbCQO7Gxh!cy^h(v zyk359Y+(4!(BRv)uKUYp;5`q|G5pHQ?aC|cwsi4w%X2F+R12UKZjrr%Zo^yC!eAEn z2Ksv9)7M5vm?^p{I-MUci2qe5;r3nNKqgMdN1Q}2#C@@SegvOe<o1iXEU)d?Ij6BF zT=CHX{QHRD)n3RKR@oAe<jG?&!=-_~B=~wt{}4;syAOVLbh*@J|NbKVN$Y)Adm;k( z4ix`uAMVGmpP>b;VITh|0t)Wn@hcP>RO{pIfD(90So?V8P-0NfPLE%q;6E?DeEdrI z1ZD2=o<hBa`agaN<k%MEaxN~7b6R)<eSP|mKYy@){ZdpT$huC;Q6R{h0HO6>G%F-6 zF)=ndUX;8jB?a^&D~m#2q&B|*FaDVxh7hkl%{e{Id1hs#!WN%QLQXAdn&wU57o8II z>u0!t@I__F3m4951T(5XZ&;+|V@yN<Gtm>JA%i8+pPqM&TWHLjtf9o*3V;5%Ou26* zxlsuz5{zHH37%kH5)cL`xJe{MHnaWt!yuS%FtfA11=1ZF1_ZgOuWxJs$pur>Jm$x1 zmkTr!K0oWH36gpdgXH6uxaNh&N-ZfPBcdY{_jf^2koEL*%New(?#H73dBMIuov-KP z{f5$0l2gs>_8T}b^jp$#wI5GNjrO&21Daq^6j;K!d#~?2l9>dzXwbPX4GfR8uO8ph z*&Qw=wr}YB`1+pizTdHef1V4)OJOnunY`L~7$M{Bbyz2z5^%%*T)m!rCvQLiSm$sD zhC<{7H-8=$2G9sY$Zrbyzj#3Z@1OD^A-yVS<a=#wQ%*%iL@e#!$5B@7?d^5Rrh$x- zv88O%s*#w41o!c>uRP%n*3FKi40&BInt=v+%X(=1<=i!5A``e*j<yHM5fR-nNWYDH zD{+BD;a>aYAwP|FwGSn2W)H9?bl5)mv!kGz34Gk@R;)SjXKFNSO(-$D6Bj{I+xr#$ zyREJBUb}2_vuqlVzJ#R7Nius$7!F^^pGR;Qz<01-tXlfU(sFi=*AW<x6&zInUw~%k z>mabdJQ}L^XR1&a)8gZ6AU|6JkO^Ml;hpWy2Jkag5%AgW0r6yYb@lOrX`q>>AR>}` zR1TcBYYwfy6E}rbJ7$X@xpH%BH#)m4KKP!E9ie7_`cyzcMYT|CL(M~+<)n+<RibU; zmo>2l{#>J2YW`Dq&)o}rbp1yiU`@4zQk@DJlN0?eS*5D7e4QpdMQeZSyN>+LL0z0z zuN)2!Oe_qALx<D(N4YA^ruA0IKmjwBE1mQLmnY)S=7PRF>H5e4wBxpBtpo<&%mcAJ znDiOog91ja)fNuf%b3)vurRQpuNk$ZZdXYAfM;rr+4>29L~Ju_U!SU1IP$`50rg1} zGn3bRuAlm+;NKj~`l|q~yDU*;W8`prq*qfw&`vsuCse^Rd7_v@Yk*mHFp}iU_STk| zxa2UcPoHXu3=aRq&`*K>B)OSfL?}tgQ!p-`t92>VME)*{eBih}qHb~m+`hQa^(bmb zkplQUv`<bFfYH-iGO}~qod(O_RP`^efdBUeKDX(511A@7O`z2%2ec5=k&fd(n^+gQ zwMk2!mM6TYP_Y3kwlJPnx6WnM^#LGQ<*8MQxSTFx>gsTLzkUByFm7wTB{UlNX|TWl zY^rK=Bec-SD0Vx5_~d8nqH89P+eKqxd(BgqXtK~2_pj)6OuLiCrqgX<&kIzlY#a~H zms+!*(A}HzjVYAs@Pc_O-qqD`z*BpGfa@&EOe>+|m68$HsW*rO`oZIUrP>V-!(9P% z@X+Mg_78WRvdx~C2MY$@*N>e~v1rUjb1{*+Iy&ey7}ACKk-9uW8y*Ic{+vT7b6&C2 zCCvL8)yHS<16IeLw{+a(n;XTmXYJKs_3&M~6Oq%CmusuYOmuW4?0*z0P$}$9k4@E9 zq^bv=tV1wdYBK-z0@~(^9QQR+xg04PpMpm<GQtD~%`aadoB-h#czD3H``AHchJ^om z&$L#0cOqtH+L4vDDrU`qvEt<X)O@CrF?mLOo~sI*R_BJ3?2E_L#o`+dpl3nZLkVvE z&qco-b-v~Ygp-q8G7&AyZT>JE91OjTQgU)~&8Wz2BWE!azq&-qXDy8G9Osk3TKo;S z(b${|qOG0XH1XwRsV?Q=%*@0lWN)Erv|8{!YX%(+ZOi|6dS=KOq_mYRguv-Ez0kpI z((|I<uC0So`*l5#n?fx9`HG&t-j>5*11R`>O6MB@1$<vm4{FPRa54OCQF(dPQa3n5 z7%Q@3<5wh(3Cv7PhFa7UuNMs|W!Kgo_zBW#uR+|o`-p~yW;~$jc%IHpuj59qQ?|VC zMv#fB(|pnFd1@(cRCPG?b&B|)9y=~3rrd6jXu~aq&ucwe7wXwM9Ok92QOD6o;CjmA zdd6`()Y0J=RaO;i*cpU59hZ?oXhB<?HFJJ`*4|E{pr{xdbAoOsCPv{kpd<*|&xwp4 z2=_ehS9y@nt)T5U#cD-XdlpSTI98~+In?U0_wK=|#}1)n@ARa()3APM@ZPC5j}^5d z)F&E|iG{`eekK?a5hv5>2ITtvI-tRtS)#vKj@D%l2$RO!nC#^9JmGgfQ#voGxEfSI zfh?_J1Lu*ksqS8;mQ6Fy93C1WU0G3iLBak{!eLn0*y(X;mL?fp6DYy4DN$&zUK#6s z61$x8eb?^6cWuY{Iw><UlkeI3Q}7pmvDE&Z#(TO`wR?TPfSW7d{@h`ALcRQxu#9(T z@*J0wO-Oh+eR-4oGhhr?Lpz(`Bb!90R-5244(1@|cDR-9ojV~RFI@97^NDC_Elf>` zD(xK{Sn-%^GU$MjW`HK-!gF|hczA5g{pyJEb_irfU7Lz$n}d22a{X)wGIV)v>|H>W z5d@VHYdyV@i_`;OSR{(Rd4b1F=iTb_^QkeJ=3iaACguoyx1@A@H+KD#SJ2gC`{x(! zfGR=2cbrmTjfsTKI@p#yjI=L3>zK;pv<+B5eUtU@3l1PCWJ$D?>SipxW~wM>vz&KW zI?CTHZ8Z9=E0fR5Li0E#q#>r_VG8m-@yR=*cG#K9G#w?|W9U5aaN_~~=sOcuWBn!L z%!8Y6xNFQ!Ofbgj0Ike8{ucNOyI$<fkC$zJ6GvY|a82m$?M>tHe9OX8>FG<Bx{tr# zz)_-B?YEemVg)cKK*+{o)@f&DD0BoemJdc3&F5r?L(TiZH_GkO0Uik{`-Tg%joZNy zhtXC_-kjLz84Nl0Cw3MV>%}^Y<EZtfl$)`9W6kkjM!jp|k0BC6t=#O9c`&G3&u1WD z)p|jtvQcHO!d&`kXQ&R}f4lhLRs_ibcWlsfV$9}^8*)XC01>fhgZ=q)nCE6GOrC!A z1v^0C>7?Z%tX<AWx5mX7xoaQ}D;CCBsOtI`(k|d2cGm^GlWZUxOlvV)_(p^|lV28T zq5ZrU@lR5#uzc(+PH8G~Gt-ZZ`RbN5AYPHf414_GbUV5(F|o4Jy7W6R=LQ1XKnj)S zEGODs$@20Nd1xq4jl&%rP?D13iW^1<&F}#dCjbbuciA7Pjvk31OBa|nGCq!){s2z9 z2eyx>k*4|EHHW+sVp88KX{Tb>f%r_Md^+seJ}$=Vdi~2*Wyy^n``Kgz8cSTlvX>C6 zo74CrT*hx+j*gDY!!HT=M~iHHpP!p6_MIm?-QW4%oY{UGX~_Tj(L}AIQ9W8&ImTaQ zdt)CKv?-6_zv`~6(9rgOLEdRF?9!>n)h%^I%3Yhq#LX@!>V~i(Ug>PDKFkh}jNFwt zK4AC3fwPG6jyJ@oR?Bjkj-^N<H}~%2jiJ2s6190p(N{5la%`ol0;I>Z3<6s5^71N7 zOx=g9mWHNmW^KS-NKBu^w@u#&`%G({|67fNscAl1SX^pqJA~vwVeSqxEFiUqUH=9Q zcey+cPCj58w<hv<-mILQYXW=tOvGn{*jDbxiDSCZ+J@j0pggguC+g)nQ$lARp0vjN zsDfzHE2^k~YzZ>3E<q-en5b@}d&>W5<NknTe65N_c&-(TQzO(&neXPNf`rHUuD`7a zEgHhfzMnL1k;HC#bl{83&8I6TMj@>*J(kdujRM*4D~gT50O1^$LNxDBUU^5i(VtKY z8T!f?ZCqGDvAK4X*G)@LPtM^J8rumb%}xh=Q)SwP;;Ub*tnI!NbH(;N64PzJ07+VZ z(cQ7;@d4fdELvR%=S6U6m2h(0?`F^Yi%v`X!bZ*bFj3jGSM0V7US!gE(?BJbl#}$_ z+`UnIRD^)<MnNA4hRt8TehG(w%lVBTgffpg$wTsU8<5U^Zqd@vxB)@p-80_EK_eqW zVbLx?{+8<=`28CR9*LceDJBYSGE`{I1W2e!NJ<t4-=JuGoSvRuMwJIgo)7+kDe3lN z5aw87lpw(+laMt%@1IKNbJRO)dJ_BCKWW(iY+dyKKJEU$DX#vXf61jT4Sje|@4!HB z@5Zq$d=;p<C@D+8YzUMK0qu{=28sdhphZqcM@PfeNW>^kjvL1L2E5^8g1rl;x-bmq z%ag~N=_km??k6*}(xRf`ROd`EcEOZ4CKl7s(E8is?|3lNdftnVITI}zF{93c7n+h5 z+4K1QpSmwvn;H#`4C9IY6(_#K|E&!)iE85u_g?Erm~kmmv3zutk%1Qlwc+W7XM^$K z1IWh>5$v-sug@rXczh^}LFW4NC*j8BX%qFuO{l7Y!Q00TMaYRV*QfktO2f@W&G~~| zAQ-hIpk3VnDH}eZr<jb3idts{X(f~1f5Y$6%UAWWeFJ#^Fy{!{%{CbmoZen9U?%f< zOaK!?oX6|z@eb#SBPj5}c2|{(97t(+4P@j@7DBQ_GJ5PzPii|odisA!TT1jwh`uC< zh>FSz04m}HJO)>No3b&nvA7i0r@xdR(>#GJ!rJ(BJ?{M3nF(=O`dkue6_x77l%gw} z#>T~JvuPjc{f_DUcz^+FY~=CsW7p9U4SPL0HfFoMC@L!(PFb5*YkfQdbk|LR<ZGU} zYQPtyPt%dUK0X(F^N?#hsm%d=n0T}|Z)|{li>~e>uzo$;nbuZRWai{d>|Mwfd1)N) zu(XspkjnL#A05rRT~aH_m8xfdS$aKJ{V5xDi;0AibGlivD~-1yozL!~Khf^Xm*?3c zp?L;oy<rzS<GXg7^c@`?)t^i!o079ZA%2A^DJEs_w79;zs|v(3lfI{wST1YZ1G~cl zHa6hsmAxDhG2{XJ@;MC5?)Hwo-JY4bX3No4U0q!~opzlYgfC#3gJWuz)#_KZ)pY%Q zX7K%j$1Rxm6e<^TIrdXvV*YKNkPE0L0=ATO`1Kud_{t4oCIT5^mYBzK8|j<yE{r?j z?_u~el9FBxVs01xqx1Ssz)B@HHuk3Og@m+pj)=s5;bc)VuiM0fM?*531(V)d0y2R| z9xn~e+(Kq@Rn>VLj9oh4X`=_oy3r-}f%Q0W-rQT5XJosOoV4Vn6j3zF5x6^ACcz`3 zq;wgWgPAN@{Lr=d!=|D#=16%3h>By;s;e|<j9Z2QU3q$~CL>;$OYdh|AdcZTocDHj zXV{cL?6O5m7nqpJwHq8Wm%V)h%J+qfadIx`Ue1GprPgxa3>e6IKMNSz!CVjq7*9{g z@-w84t}ds&Ie$8>=ScR9?Cb=LW_tknhY;Rkux)#juV*p;O*|Wb151InyTxL?MORGz zXjN5Jzzf{7o6yOlNd3pv`#Jp?=H*HIFB3-MtgI-s=spf~Ci9IKRFdJi?1C<FOr0xc z<Aq4LEJNMh5gu%0Y!@IMWf{uypT9YOwdm}^ZaUWu^o65Jq%qCSzEfRYpJEg6x=JBa zYR*ox9!}P<SCy(&cVwD7Ig*V5QcS%^@~eRM?Xj|VVq)E2LM@Zoi$NMQzt4RM>{LA< zt-e&sMOF*-!lNP}>~?f06`LtKE9cwu8XO7W9i6$`Ty+m`4!!~4Q8vrD9}?q91bpsA zir+5)+L}^fFnKqrrOoko@@y4woqYYfA`dg0wm{E<_0!e|yo2GUSL5^fSuLNov$8H? zFK3<34(B*a?0tPUz($bd)#lB#*`n&ypL~OSxo>~}4w<(9H@Bl>#!Ta%LNPdCI9p^0 zN}C+0x60Pg9KlwATeoB^U`@~OLVCAx!8G_DbSA2I`xgdefM<%^>95@-?{~%^7<leS zm4v<Ioo!TCbYuxCnBkhig-NwDn=H5<?%G^xZTE)J9b7r>nd~oOs`9$JvRV54aL1`y ztP+cVbbe}Qz11(92U2QImmL-)P}19u#N_wI(>6ODww~oHlF6h+rKNeU{*ta2L#ZoZ zMc^uokcgEkE-t318vOzI0N&o7wh{=^lKywVi88hZ69eN@!AzsurA&WNllyhO5R3!D z?%q2u$mfU%xm**a_p0*pRp!IFD#b~0aai^}M5=k@Bjmce^@%@o9Tl2fSwZ(4q-15S zO#lP_sUfL=N?T<Z|Al)TxEWBM&+TI)8A$0jR7$kIB8&jF%3AAX8q%eA0bxJ(0kq)G z=3DLJO{=28;ZRxM>UUY-oh<T#K*HfB#iuk)3M>cE<qW4kwem^^Zd(T}qi9H>LF($) zi_W896<1c;TOHP167YOlXaoTX$!f9AZS_}ioMV=6Lr777%WUWJV2X!W&MxpUL@0UN zkkRi0gIT2qbi-&sU170X!T&DcrB0n5r6LPJ3A;I24W#i#I}T4+aL-g7+V70vX4<T* zqSwwr_MCtQsiRxsUEd4R*6+@ZT7P=8<c|+pXt^|oc^Sj5+sDUuciigj73n&ga#4N; zuofmaDgd5n(#c#dw<<ND+re%+!jY4)$~`<eihk#L7BR%&__KRR?ne}`vvLF8t+^RN zi`CNRpdzB_|D9()Uv3x-Hm)n5*Km<K`o^uPscBDN4-Bl=ZID#ZiB;2LVsheFbw)+S z(K#(0&{~)#pq50mL$qTI&S-ofy^sXq&GB&N`ewbtaeoGY+l5SClaTm!biDP{y$01$ zV4xVHolOM{ct}^vC_)yrQvdY==K8`bV=xqr6cjpNmxBcKd}k7$)pZUO)45C3iq)Uy zAC|La<LOd6rIa&$TwPtCbGz@HO&|TRcAT2dpIjyp)z{O@Z`@xly9I5pPq#mx&>0V= z>StG!mM#wKcY&z%G2Lu><N%b1p|9ApmM4leb?RJ;Kej(dKtSlfjE;@PXZQ*B98e~4 z3`^(0y}!1rvDEG?nmWq#4S&u1P@S<^-{K`u^G1f-$u&^D<7@Qy6xT}+V2F&=*Vk8A zSO_{|@S*yeEuO#eSlKKVgxWzK_KNLOfp!D%>t%h+7e3qifp(s#h=|7BW$kACS}=9* zs8qsAk#2+Q!ksX$D_4aVb5&5)d8V(Mw6s)*)XEOmBT->6%>`i491rHoM8ho^%gV+U z3RRJH`CHyJxk^e(s;g^+y<zpC<xw<r9qE9-*LtoXe|LX-dAc!Rd2L1SSWs)nkzyo$ zD!J!cU(af$WHp_|si*;5S5vqwM7joEvd9J<9&p!`=^m<$1yxzjn+><QfM0@(vn47l ze7Q62v6mpPx5582hkw2UhtIY$sQhFzL5*tDt=0-1F955_DI9j6;FfN_t*!lcKb4ik zZ1?&~7B={6dolk{#T6+&KRYlN74C;yMvdg;<WWQ?VO&*`Q>6SD|4L$?FWvpc**PmK zt0YHrX=!O)o%-^Qvx0)Hf<jbgrnek-Y&yT^S*AGPLM5huRUzcznHw1q0!-(()FJ^J zqvX2O)ROsVi|ZL#ZYnBR<HMbAZR<TEyVkz8KtBa{KFd$|R~{9$#C;$ioEJIt<;d;A zl1x<8Xt|wj!bntXq>B7Q9qQvVS|S$&sqx$ay{d%7i4-mcWnAue4)A@bJ1`UIi^Yg9 zEK=${l16`sIL!HzK8u3}_`;fjA;#KzvlA6aGwZxsPF_F0<3Z?3B~kaYLTzQGl7xhY z_(Kd8IYjo3qPKTR?D4I4<8n3-R*JyF!hDR|`7kD!Y@({igb)gCnZAA9Rw)+K&enOF zlXIH05!6uYSe14;-)ct`6k;ax83rF;2Sr#5vBmhk4Xcaw=Y1<g|HFC45fHFV!YZD@ z!&Ak&d(`dr@ec;xc3pQSpy8IrVyGdG*Jn9%rrs5nPH}zpioI_5txzbx={yitqdWK& zs=3F2Ulf`B3nBFAs%O;bw<aUMP;3D!I(oDOQ!dzGyX-psrGzI_vHnYM9_BYxFy4ea z-F1jZ%ECN<e!ex`0J^EDBwain8<b~{S-}pwNt+i3aAtPcWiM~XO-yvyVf_GdPCcSp zi0Q#XGwK_>TDz_ZK=c@ey0<?Vi@d%)+gh*~>s}6d>kN*wp~!4Kkvuc~3e#1tTxcLu zJiS-VN<|e!SrPqRhTr8R<{H!Us*KtZ8PZmVNlHSZ5Aq=Y*^2UVkY(AYvfl4)ql30{ z0$)4p+qX*AegG}j+0_LL4P6dg6kKf~t?wMK)`R1LcO)oB1@tlt`xlAn>8(aLXmu7A zfNfGTiw#ded*&}dM$v6{rKM#pmQJ1kd}3-I%yC!HSABzuDsK9re=AapE`GyqWi21r zA18s)Fdoj4u}-bLoTVilOe?q3Atg2C<?iHn$Ks^1TF}1#f`s>JzM6!ZyDvv~5tNFE z(y>WN^}thwp8oJx=&R#b6%`fX=^PF~{2x;}wz(;Fcf1do7{q6LNpG~+{QT`PN_3Eg z0*iu_s3bE>OO>(uuXBzXIiL&yLQD>J_7shL{@Bv7s=)TvQA%T|WZo?R`IS)F_RrRK zr4j&X$76Pl0mL6=F5vAj+~`svojkWQR;*ZTHqHf3;<viZ?%+QEKD|E8%iCJ;&{m<* zZKK<2^Opo>ITPdKiNH(|^cP2&NBG^(GN~D7fPPC_iJ79|?nNq)`&#`K2B7{%2s>wx zJAkaEW+oyk13vaaK@w8KLhs&P?(>V){Qv>3SflzwO;X7L;08_$Yieqy^4Z00P}0)g zpR5<oH#k1*r5>H-e{b?2e;~f<3Ja4LMhfkVF9m4kO3QJ*&yrp<$O{V#O{u9<jIya* zqXo){n3%C`-#aqfMQ5u`_Ycar1LE)ZrXiQsq>74w<U-OF1`7*2nWy6cd_C+{Zf{|M zpJsPY4?ef2ZSbr}>wc3Hq&1Ow(`1p&V&t1w3*Y8|?o`?6J8Mg!(#UX-nG-MMNE$oZ za?u971brN|a<|Kcz;3bn=dZYpVj3G8hXmmf5V$}JC@o2TR9lv<r{B__+`<6Z-*GD= zEu~9Umx&ddCa)b|0k0sfo6AheDhG4bW6_N4iCXz~<Fr8#Q%B>H5|f);&yy@G^78YW zUGH;snz%sUOpHcp4uS<pR~hWKHPWw2bQ)v?<1_&CtlD52p;rwUiA~jwKDsXoMazAe z{qb>hh{$)cRP*#?yzu-L8zYR%R{!)Vu-wXG5X=w6S2V~bOuFa=b(3*}0^u7D6N*j@ zGal!o?gCbG5F;2oc4EY%zx#jr0x!+l=Rij~46YMUSQNqxUV(|m_0e*+GIcyK`!c)h z=#d9qQV!q~6Qm20YB{b%Mmx5uM%Vi!VpaKFGTT|o2p5-@92Pduxdh;Oq%eo7k=_=Z zd)08U=n40ju!1u+yleN6DM7`ky?z{%N(qPmBbs)lfsuiNicW>2M=+M-V;HQQ5~m<A zH#K!EJJiaL+V(rvrwmqHopn0Ad-gQ1BP}hh%>G&;m$3T{uWL$AOO$vvuXtiwn#J^p z<<ZbxISZ}*Mas3uE!Ut;YHU=Bp1z{L<5NWzkOt*Sr47}DpRQ4kQp%OXu1IRVzNOhW z2LAOW+W0^i^PRf;THwd^AE0}L4ujpw?^ts<mkiEQP{)}9`R6*3Om$63JK#)Z|D+wm z{%)$aCv=1UBqoEmT5p|-mv_EIdk^N)+Q7hoezRE`k5#MQnFwaRYWHN4hmav6Xe%K6 z&F;edaf|th(f-UiMwKd^?#)#XI@i0M$wF$5nzqtNU~k@^So4|A%H)Jyr-PfBxeyqJ z?9WtB?^J)KqXhLleWfHAg1K^?o6c6BUszZIy?GMR(46r%tY&^iMK5Umn;Mt13rCHl zA&cn0awTGKVQwWNiY@MqVYE$5QumYC&8L1|T%>aEg$Z}!gH8a5%CvYaKdKJr0PVb| z*-kV_WvpC3;I^@@qEJn9vPfS4rjinvouMRslTKFAtof9i1Ogmmwg{icO$cQz6b`E` zhqAHxSl+?fSTtB@Bm^)t5<I&TMJy~V88l)JLyF%A%Vp1P9CMRMwdKcZibcJZtqZ_D zEL1I(x6aH_yf4?8zmp)sd<i`0D$Uky3*I?_=C*#oOXI<`@Svcq1SY*JISJvIvOG&F z4uZ(XHO7B^vth6)SC`6mJy7hG*G3DzA8a{W@*50gr>@+tPn3bb-r-ywH7$wsaQaiy z`RR<j``nE09OHcC{~K*@9aVL|M*G?Uf+8T&Dk3EyEiE7*-5{-Wcc-F&v~+hYLb_W( zM7nd)-Q9T}eD^;4-m&i;=Z<^s{qG&>3k%k7{eI7P&d;2W*yD|%{=_Uk93^C#TY@OR zJWjaFfP7eyWM)uLccK9Q%|?pg9aFsB)#0--q%AKy1Gs(1MH$Nm21V$y{pZJfS)F8; zH*luBVkUa})zR{qWI>6?`M>=MwLg4!eZppK<U0LJKX7J9Hb2dwHZbui|4)mdyKZwf zPpOrQ($#C#>h?=q&yLXu1uM>Y!)bQ=xCc$GR)@GKD9Se}^Lu-WoAMIBtn_7&lzA=@ z`OD-ISw*|s)Gzl_p%bySc^IK=St+)TyG`!w?WGp57`s<g9G6f>FTG95xUnFA$drUY zC^U{N!;x9^9PM*q5ld3ilJv8v^;^(w4?eNRh6&X8^!4|1+RkIedc(oZ3dcR?F>Dhw zS{a-%D=Wf^N}T*7>x($SKlR*w*&b_Rb;qAi=**ml1p$5&v(Zq3e(&%5L|jRp<Kw1F zazA1E`o*gdS?ivWahF{(KS@AK%Y}FmdPt2xMS(MJNi6jN3gx0Ud%Slbg#QT8J&B|> zKS+L0b!TP2HkN_V<!6p#v!34_w%j$_|A8wFK#HK2qsDjGJ9>2Jq~VEnuXay0@lQ}# z6xdX-0oD1sv&+_dK|xQ7bYEffauUIdi<#*5XeP8fcNm$O!vX^nJ*B0k-NtTtD}4+^ za%uPclFJ$#DK^s7(t4Y(4^QooqQf1Gay@%i*34Sz;ZT~#L|hI<cHK^t%Yt78ch^_y z{rSwPDOe+K>4}PnpyDMI35L_i>ZHBb*Dw+d3^~e$Q}6IqF*Ls)ZlV<59zI_awRx|m z7DsQM9mNF4Q87|oOiav*zDUl>hyd%TsEC5=vOk<pcTXJh!;#{X45tV85?Av3+!#^} z2WjBYzOuGz1rR|6^Mi8X3FfXe;VInX+c!Mi-R&<N`9YKyb8@<d_Fhp*SOoQgE5*=P zBHk(1;XqDWHp%dDh1f?ElNYbu{tSNm!WRy*VW~bcYIziOzB7@*5{~wk3pAoaVu@}n zs;NbJhBU7+E12>fJJl)_d4gpgEX>WPrKR0bb=~g1yLn`J@8YA5d>FXM$Q{32IFwsS z;b0Mn4qmZx_|w|DW;MaD01Dx=5)6Q5?znheP?HnfDVDqzF~b(T_L8axHsIC%Y9wTJ z`m{}hz4?e*P1p|wWjo{q4Ta5TM^k%BAoEeF;b7P;a&75PkOUUC7GqY{)z*fn=4qvT zOi~yPEgA8nM{&{7tvRe>{1*TMo2RCr6ORgBjpd$)i87s|)Ae1Ju(j|xUm(>>3uJ~y z`@U&f{p@yV7R8EWam2-sKm3@2O*uJ*3(`*u6?@ZmvHS$=F9X7EGm?o)0`g%O-!t>F z<a1Hc(NpU!6W1P@r<|Ys*d$8+iujRKrHw=vHm!DKmnja#prWP@ttJred^bp42JLf& zg#{PR%wlatb0wI+j7%3gVs$zri61`1!@^Pll|o&eJ22~Q`f}&Dk*_BHsu_9I90lob zMZyJ8=NDYxGCq6emLo9Vp>DVOho=tXZH>TUO_SSAAAcgw@d`PS{TSlOo_H6yT!&22 z9L~0J$E2n@FKG-iiC8YX59(`5OqLcFFMnjx^Jl5o=1huVSCC0&O=6PpB6)3PApkCD z>$f=B6HAKTz-o1P=NOdicWhRnM~>hPein{f-SqH_R>)BzVdT}*izt+lU`EDryM8u? zO_MG~lZLp#!NC;9-}F=dbPRY<MMfzpD#dVEdr%zek%Wp2i_#K>>c9f<;d1BQEqmBD zgw!+8aGIJX#Y_9fV78fu&tlU5Ly?4n!s{9V6VYqCZxi-PZ7`7TbDiCS?dRdQ$UhC_ zDkzXQd#NzWbWwi}m)gUd{kIm-kQ`~X6f`lBESL2NEa<PEf?Z~^R#qz|gh|}4k46}k zQX__jvIcXcq{4`L{M;dfomR9yUMa!90{ab#+491L>y2ihk(t@V0`s^AV_?s9+tGZ} zt_l^025H-&zHkf8D8ANC=sHMtPBU}u{yI+#vR%f-$yq6py#^8yjP7Sw^rW($zcagU z3#&f`baJo5;=aY9>hK8dtxmLxO~b(wKO-I#oS5i8gLlT>=nWS%7HCr~3fzz}`*d7+ zFNq;ObNl94KUVog_3s4Kz7k_(Uxum=FLP{|wDeJJ*izb!YNvEFnj&Fz)m4&bB*U0Y z7s)>>_tDLk6ztmZhX%MER^K;xOw^nP4lKZAwRcf1&1tz$P+N%y@8AO%`_wGw%Q_;a zMv@^;8=@6WIZ&wTUirQ)cBMjZtH5%BHZu$MTlPkuNwZSEK_{Y*nHG0&V8h0MA6iN_ z`HAhpT7zc*Je`e*f>}U@7C`g4pw~yCLzb5N;j&Nt^6Cw-21UN5WMg=Z&b+4&_Qvw_ z^GkixAMWvgxbHnD;>fl~$H+KoQN|cL>GU=y`j0U&w@KTOIp$01m#<~#=ge#zS05;) z*8AuT7K-4UV3LWC40LXwi{CX}@XwZ&gPxgp;zE(HT?kUy5_827ltv5Ugs_Eu4z+?0 zZe=gXNNr1OSI6K}+=$X<Tac}8+WVsP2o<L{N;0UodqAz&0yp&YU=H$wp>q7$2yTsz zSoGVsZ`oK6QZ1O)dMa+l6FlZJ`U61I;$nJwCM?E?BP^6^@Bn2UX3Mi5k-fv+F3aMF zG_olhNY^VDRP_8gK~L&9S9@wr-|6Wc5Or964-E;$p^hQb;lXOrr(zqng>*@3B^$ED z=uy<=d!Apqv3uTddmr<f)rBXGymE<wuAbIAFW0$kZQf|nthcGhan%l&r>@nZM2plG zFCigpDtV*+0__DFf9lm$0C(GnBZc?Y*-JWNm~>$pVXcZW*A!qmDK-55q#~rHt<7L) z6S)=+=f1et_L=*&@s`zQTlBPKg0nb6SFils@V!I^-(*O((^HVPzf+G6)XL9SC$G~3 zTc61-KEAfRJW`TO3Di`08o9HPeKW$st84pF(Dmb2ax4J>0k6#6;@dZGF0J7IX+Eo6 z;pf%R(0ZHl$E2M<TY1VDQ9v%YPBAU>i^6~pg|^}qN>|au%a?6FBSRUzIyRP8ddC}s zU%GUpi;*oY5L6m9;$I$go!p$_I~q$vh{en0s>Oo#%%Iz@R$`U^hv*4UU0n#FJJ;SJ zxL)me{WsZ{VSxuMgpkWGp{&B@)+7rFJd}Gla;XG#cXy|~c+uDqR^sO7qNOG4x7?qu zMPp&&u1-QG9)p608qI7?UrYMp1vB~UKOkeOtE<ntE#7iZ3rmwsLpX|g+`0t-kb4sX zN#Wp7k^1^0h{1`_O(UnxPbYQt7x<pl+$3dutd-6S>#$7GjgPk@o^wxi@D;yezJ>LB zJG%fAf7ydHM*HKoVG_@MDsuACYTMdqO@;Z=-3HtGjW0B({zU99YscIOaRR0Xdn{-m z^ymPgc*#NDS(ikSeViuj3j0D`CUdD#e8x>D8ePwnQoWhl6*pVWTqNL!J$(UPE?h^) za<EQaE0O^47=RoF?yRSJ{xwJ?EiS*>eFVr>@L~Udgr@$l-P8Z(TU#aGYyIUcH+AWH z26Ylt!0#iD8MyqWk_P{Kr0jpaoHK>i*7jEM=8Gw9`f}DIY871nke7l2kuHzX!~cqC zZ_F-2x9!St&Fv$-7<c3MM}Ke}H;aFKj4mkdN0nP=mh#uzJgkJ12%i0LMtO!5R!?I< zXn5q$R?%t7rFn&k%P%uY>k;?3_6qihr3{I;$l3)lCkqojEs6i--+iim?B;0S+A2)R zkJ7mz8yx!U@+bW{fugG2BBv&<WTM0f4(`)%s`fznmpVnGqliw9;g76}iZJ4VsFEfN zD$`SN2{9SOd3kx?y!ilcvEJ)fugDpw3cZV&Wax7z?3VNlmsVE(foln5!PHgL;gyn@ z)6#zH<n(aqB!;4Y)=6=ASiHkIoLaej*mz|dJIk;?gBzM606dyM87p_RtxF=EZnB@5 z<8+zUvavgeb2c0_`5<g`ysH>aqn`K~I24Lr9r*OnU%q_F8}MDEh;k<@HQu(0id7Yv ze3!mCc5b+i&3ZkGBS0aDHZqbyR~}S){U=}`YEMpzMVGe4(D@xThf%BUs?JPQnTHa- z6B1%IpYC(BxBP2rlV5XlJi-Vb@rnsjI<NK46g6j<`jbgV3h3}qu4(-B+vxdqu*|J{ z%sD(aSG_%o$zgvr2a(n4KR>rt?d<8u%bWB+;nKV9o=r3Mt0TQI%%Gy~B!%t4(+uh^ zzybwzd92DFIWl6<T0#hGNBM5w&y-4L8@p<^cWfOyQY`5I`1k%etIg?KIsE9!$?wi5 z_j?+qNCbw5WEIOk5d9TA-4n7zkD9ShmZbF+?P<;sDxWDDMBfTaNMuR!#8SLl10ql1 z$9wa!k^bXj2YBILerLRE7#J9^j*^{yZ=@3G{A)9@(sqO0Z1ejh!8UM$qOnse3uG^f zg9QWPRW4voc+1bfVRm4KEXdCK;*4#W<wEmC{)Y-7ar`TdLzr<){h~Ls4coyCm~cIm zEHzmJG_;EkWf#;y-OG3A4c6s5B%XG-Fc;eAgSOt-@pW%2`TkjSZ0y?FnGHyaK96V; zJXZ!yQyz2v#~WlZvCupz{h?l(rj5#um#)<Rd$@e?%k6+$Wx$&mgIN$68HpS))e(OA z{CS_|f=y;Z@1{FyI3HgFcrQW?RWUJv$xV0tGjek~r_A&c)T$i}3^FfKt1I8!Ce`A$ ze{oYI(x2r@tC-Q6y!gSO+mVs(azY;oIbKOo#Ag_sWR_y<*^uiS#Ba8uZr!_gFC|r5 zJdT6#F_vuC<D{3H{ERCDrXc689-3>Gjc$~2lK@hg+ESVuo}p46R9uYh`kI6U0){>U zA1=RX!Y_bENi2j7WUXjTUZTrfJH3xU@jk&DO!%CgZS1`N6zxyTpI1i{_h$Ml14Q7G z!eh=`>uoyPTVXj^=l;-?=vIvt?s(XB{`rf?{@Tos9JSSDXA&x^rh)FA!H9-HiuVsr zJ~h`Kl6TMjz4vSamO+w(6&y`6Z_i3<Z6E3_n$JK%{nxW1;_hl{Y!nh&h`$1|R)#`p zN8*>0AsdvHQy~~kfIIH(=`kArv9wRPo>Qpviu)=eAuK*zp`M%cGK8?nQtv6#dS6gj zt*ww%5m!-PD8FtaLPO_SQ^>%-jG}$x^Jmc1Rk3F_Qr`Q;qrbl&&d?T?JC-{q2gD|0 z747j~3%F8k@FM8#r=g1~DM{pLF!@*S|0E0lUfKMYCLe+RO}ftc`PsKe)!)$UTffD7 z`973U%2qB_Dl${!4(B0cXWzA2?yXTp=4%Q_oqVsm-rL)YEZOL5OpHc`8OtEV#f31= z=Y<&xTgC_~bJT0Sj#$}>OxazgXF<N@<!ktRS0(?OK6sM><8ev|BZ>1`kofoLMiCU6 z<>o3CwOKL=eOCV17ABv#n<S}9UQ;cvwBKZ%Ed}R>hNgz}T{w<`#$vFEhldRdVI$O^ zlfQniBs>ECJlu3YaZA0|^35zr`f%;@23&Uz6NIA_#E7p8b0IFCmRcd@!pE1_<fj_| zCIO8^p`gOQ_RxjempsO;`S1PQ6dtNIWd$nyglV$dWV4gXpWvTgIhO_^-;X4#CGcY1 zWmd&rEb1>${;3w5vaI%sf*Og0FbxY+)JNg%_BoZDAT`Ar(ZAsG`IU5dd=TJjQ!w>v z%)IuK4C=o8a+3j`-Y2;Yf%BBOuUMDtS@rE%aqY_$C(d&y6`~qKwNvKGd%S&za$PPj ztxvVL-A-~}WdBSg{`)oG5d2qkWOGXPQxJHH-rv66xpT+Y+gsy`OCUh;07!7}>_X+S z7JN@rx5;zF*1`Q(j5%%RjHcZVXC7i4L>ra!UDb#}#DZm-lUOv@%Fq^On=RbVh+o^i z2dfU&>!RJeXE0X67Z6v?eSG*z8xse|7Ody`HIeXaS!rpd8jVo6*jhi;LEV`qlA<eG zc|=P`C;z@ewpyj>#pj!-IIu1};Hdk?;2NBaK@`+(asRh{^Wf2=@pK_eJiF6b{lfX| z$IWjAvjP8v`|gJpqhINC(6@lgXm@yGyKxh_6zT%@&in!<2kzUrg-g4LDvAP|)^wv| z-=CD=XsSUFBw$hk#Z84@_fM^_UXhG@FnaL@2D7Qe&$}}v_6^l1_rW8rKPA|mUn|kZ z-&uj13A7oS?QOdgjaA0Jwr@#wo#;jQ!-S~QGT)A$%O~jn$mD*?S0aLG;s<XobPbg+ zh8ZME&bnt1xVX6B+h`C=r)MgZ((G7b6`OD)n`IENkGbVkTF%&r*;qv(h|cvWQgNt+ zkp2GZg!63I)wDK`dqgR@xhw{=X2%M7vEuctmN>7t)$_@&R}<;)MLaCCT517pKB7md z+QwN{OUTsq?z#8j=UN)DHZhOOE}9Jn(&;RIy+T=+c_Go((ZS_1-B;~+ASWw#yl<1E zK+CNNSrV!KuzF53tL3h`@tWYtS=paEL&Z(Q8M^K$*oS_A7O{`nUMl<ZVBD<rW!+|4 z=Qhi;MEHYS#OMUXkf9+J%pZXa+*XHrNapM@PMg6DnJjnJ9ZtssM|*n~lhJS7u9W-S z&ih97hvsnVZ%r*TTUh7RCY^IRJMPPo+d1ZD@h9Mni-{4P<78zmk7hAN4#`fLy}o|C z46B$=PrD<AH9RtOxJW4Y{OmZ-?=oBBw5OzGpcKuV?YO^avwrGM$j+(P>u_MLnC~P6 zrpftiwZp!of<m%ue_tOSlablv<j0cOhfXU4+3AOa6>_aHF$Auzu1c5&ovp3Ou@cz7 zmisfsqF%=hWN%KV&w(FNQNhL-3^jOZ;*qlp3$C+6Ta%NMc>P%tF|Yhv&o26lyIABz zU;JAOsL1y#YM@oC5Vef>$6?CgZzK2v$5(ZY+DlUbJ;`}Ne5{f^N4a(jPPOpl-RMbW z@RK~0g^8YtP#F4Q;DNR_UR?NGxlUb0sKlS<n|M6y!B%nrcxGV94DGBn_v(U=@;xxn zd{LvbgOZaZR=!3&c7!XQ%iZ1MGW=k+^>9sj#0;Wxfx2l4MMaF6XuYBLskN6wyu7`= zMbG&MG1*7~rDwM>n&?kNm4QWjJp(CUqJv`SorWHOPdZ1XAoYTX)8IyRg5FnvN*uy+ z&_sRxe)|%oCMUOdIJFKC5<7E&9C(kAeyFSKQ|;)lUn$TnSnGV^?=P$M_IdlO=g+@( z3_;w+#2oqV0CRs8DM4Lq*bk;%N=S%o{_SsS5m+qH&Zd|lO?ob!j>2VnUJuDdHWu=r zo|XK~7<Zd@Q)6m&O+C&j4TAnXv#ZZT3OVDsYwcG`CYvP>IWA6*EQJj+0WpdtgPS>x zdd>6#aaV<$4`fP)3E!Piz9R4H`uQp6bCVx_0~T-Yi;6dLQu2wYSK#qt^$Dcs`r5}s zCC&?zJl7X(FsldBXH9hnouEC=Ef|rKvN~ovxfjh+RNCZ+o0^!&;~95B^^D9@AxIrq zf!e1aX_!q-O&KYg3~z_-s+Aec6)<Nj`^CSGtgfxn+oEr2N1bnvWV7!X*~8bnasG8z zheLb$-m$`~VodK5g&Y;tSFSlSxp7k;r>K>Oq-N^A2-f^+%qNko-`P2!HJFD^O7(n; z(6~4n(hbENOR#PRvsJTGGlXRFp+D`&;LM}loka`o!3sHQ@$AUr=;Vf<JbV<E5pp?3 zT6*sizk5$yQhcwBKYmn8exl^{)_t?sa1i2HkVi^|kVWDRQ9t-!l?#k+&J}hi3$BhX z@lX^(BaZ4SyF#WG+sD)Q#?;hxtddR{A;jha(GiaaGv$J}Z;zSLM(nK6B@1@RT}7*P zKB$4ZG$W$aQK85N<6h7!a%9{kW~U?ETD|=6$KZjDEH=i(#T{-fHw_j*3#U<g=Vh=~ z;pavrX*V`r<0xo*B^^EXAK%LWgZuXM%nYAUNRn^X%00^Ky;3>y*_5R30>&J{5PP{T zyEM|D2xW?5QH*ITKZA_iC#Su~D!zUD7ANjJQes@~932hafXJhTUNYcke)rZTeRZCk zd}<?)b$jVF@#=(x3n~t6b4SPUT+J8Wp(N5)Z#IUTVzFGo{-|Rf@JWchH2u2vD>~v< zrh9DX+w`s6r1H|hGdInBU+$5kKuAcaM>t?Q^xA3hyCMVPJ|SDs^b_~_bDA&uT=)ao zY2m*Q?*=creNMw;cS-UPXrzv2DKY9!0x%H^R+ohahbPN~ynyiyoqz4q&o|yF;F~4C zJ)djEX<Fwr9Q;wP(~m+NFR_F3lBW4;l9}iQit1>Op+R3dMnM6+l}T4C&uq+1uhBJk z+m~xue4YVahMp8<Ny@e6!G(pvlg&@IIS>jrPAtlt7smVa8AeJCMG%W~RD+8x!FakI zQNck$RW54=BB(yAF)={4x(`qvTkiH7Uc6MV7#gkGjxfj6D~Ad<_A$;w5~GPJFeABi z+Q>OMIoU>ev2WAc{V}TuNirVn9$4=+y+TNG?A~yJ{q%Jk9Qd(r9B@m@%fG-*T+)S5 z5tbVTi%dH_yZN%@X%OB<fLF2EESl}F+T&Snr))8#Nu-|gY*bp=o@@o{o<@SV{Emkw zF4LEn;b3oXZMcvf8*6E8pl!4bd7>(nCDqrqr0P1<RVTYq<*<k6eoy$8tYC_01D6P} ztz8Ow@}R(k6b@!93bm&Gdc$-A#+)=~=g^R(pdf-yt`>htnmVTCbT>?;@3<>UhBIhD zP*v3#8P;yJXVQdzU~j1_a~9;C(TfmEq>TOi`RdrKgahlS>>%kt*TOJLf5v*q-$6dI z%fcA22TD^}Su8oBBP6dOKekMim-B-E21*49jv9fh$<BO*e6E^b4_T;phObywzQdmP z7f*B<gDKjg%?b)i@}4!Ukw`1a@#=Q&N7D;GrRAlQl3r%tA`B-`LzmM9c`=I7<n58@ zY=(wRV-(HzMS8DmdO{^hn>7y$tpQnH=!i*D1aPy5A7kxJ<~9+#c|oZq?MQw|+u>Cy z$(ws9MR$v)svWEmLJ`v)qHK(^d&G23<YK&o*JU@;ezz-^w8zk8%eO~aaWdQNk}DD0 zXtD9*4~_K9D`aSham!_mND__>{fcNAw_P6%4GSdVHn|u34l98|vW8-DO-un#T3UsT zygi!5d4Klm*wsl|B{gw>e;n+p6%ZK8EnNI!Xq3q3FClBn11k@Jj%7p<OmGr@9U9h1 z{3PuTqnq)W0|9z?7(aV<I_nNx#m{VCW;YDGjlUesIpbSV=}+_idkN#bRiNKn8I)0w zS?S9^TXEY%RGd#jsrT)QvfbnY&WnbpP9cR0ozZ-{lYcN8mhRa<+jJCqK&YogPDp4- zMO9~0Q6(fSo|c_vj0k5P!%2EnA@!f@6nunWCX-RP6eBCx*mhlL8|VB9&MxlLGn)>C zoTH%zyf3$~){-sC@n;Tg8y1*`F|U6K0%s_lg=%9JvY(S3d+FjeuU)@xIPkJSORleN z*yQ=s#KhxU$B^?AXqgc0PR|qL=P98=Pu%6>e>>04YGa*XHP=^}8<g}=+rP#+hT^#P zV)J9`z#38Ie%{QT(4j`dp}fxvJ2;U4vzmHyFsfXn=dv?E=>6jCeC?|y)NrE9{z%7A z?7}QfZ<J!wx(%Q}Lw$YKgbQjcmM}1vMa4cUS^u%`KB)z<F0QN;UN2IhNY8Hw=}&(r zwD%zp;hmsS%KPmw8%~O&)w&zOh|Y9jF|Xk8=;)}Zhj<T1@-=S*UK`=Qps%-^O^d>B zCafcBuB-FrO+tQtJ}5nCG9GHBHrT=H$a5_do!|a%!ozuZ>MqvfO`V(MZX5)-@hUk~ z#Jj$EYxj1ehUOH5oTTRpwr#1T{iw5o96o;Kd^>p%J%3?AQHl>P9+0`oG40HFxVRvo zt=d1Ezd}b!V$mV1IUn%G_6o{|O(1&-U^VEfj*>xK*2lh*0a)@=J1P%q2OqS*D*oWH zx6+TSc8p*7u_P;R`axM;TwGr7p);qmOR`uf<!7GH0|WA+UPs4AJNKz%%(TAn@kTRg z!Wj(0^sY}76<POn*od(=%cP|}@2_JnFR*DZ@4oQE-`F1FnPbcBYHDgKT$8<*9JK<B z(fVjLS>N0n5#<$2(bboO<rW160Oo!OW@#K){b8!D>QX{(FfW^@wcYxC`{TzcStU)! zP^iTA8h(~}*3{^nI)aa1rKcq(hBnVGg<(~9dfK_p|MqQ}<7ync>r_6;?TlltChHf- znF~j$x&ZHXAul1>oixw(C}x<-iLkW?AARLbdxC#gOuBDcORJ{(;nF*6%T-})$uun# z+G)oHNjr;w-rA&eo4^&D{m~<U$%r}f0$So(Sy>;+%SF0<X}stV3tSMGLc_7w*_JW@ zQh1Wv>2#K2PKlrY(uD#DF>Nx(--gH3dP@&;v1JDgM&30ml5Z}HSkA}0!$r6`vfB#_ z^Yuf09VR-WqA%G+ksT&CcSx|<7r?c_8ej8GCls;87ZvlpPs}QegLF4Ve2bZ_?L@iw zs0Zu_Oay?!2eyo#;`k)=6<tgaypxbXP_Z1NHE^RXh6^YuQOYnLTl08^Uc6$U@}WV; zg+utYik4IC#k5z|dunA76Yk;TDHMSdknyIa4WJwb6glaGSZVjo+AD!)lk;s$GH_OG zwV9e@x13iwFi{=MQ7d<ySie;=!G`Fm-d><p>$%c6z@j!T%7b&1q|>2JdfnOC8=dhK z2y)168&x6}cG^wq)xXFz_w}{(0Q|-v$|I<(<Owt|J%6RulJL|<BQno?r$x>%!VR4a zxRpTavRjLN`3*}9y6yrA%2(Y?Px&*XlA$oT1<GZHyy@lAOebpi65rM&;CsA#hC`Ol zcVc4|G32{FS;q$j++PLAZN|J~zt}yKz<%M1ICCv;G-<TW##gN^Hb$n2uPI@5=#^ah zZXr=jhP->KD7}m-^``w;mv7-!fGU~?2Ln9r6L1s_8&jcS?Uu9gEl|pAicu6fG}5Gk z0SR<PH7+(b;aG*S=VE94Qc{tAVOTtOQ<uATp^liCuip@0Fvd!y6*g<}z&Yck8JqT$ z1y)4i$tVd63(F?z=6?5yE&Ma47DA)C3R#lwWJi|$M4o1~C;Y4qtA~9Q!Ek6O&_q7s zlq!{39B2ZW2!1o-aQI*{?unr3%eW^|tCqg?r+WtO`L!?T+y}m{+d1tX?M`W)A8_=< zhF!V%bn9Y&`6?96fx<z(zq%jsT7P*96R}v`mFVN#8fLTWQ4KsLg^aEwUC+>;JoQ?x zxXz26y){`yMrL|8>t)|y83`9nC<L%wwQ@cCE#lqU-qvQ+UGI;Q-r$Lb%cao=Of{Tr z0bS|D>YHrrj1d^BX*Y(*J(x03C$~C~O@-`md0o6&+EP|&3braE^|OFx$g$`EApgr~ zHPmnrc1PRV982g}+bpwM^bLvctAeMNaadt2axVB`q0Ky&uAx}4bG(_N8Ax{B%6ZqL zqR>=r3uy~o$0h*!0FI+Jppa!LF3y&aQ!beXr|W~3kt{-dEoo3>clyRK(l)6=2fRC3 zge+iUMP_kbcidLw^EKS-eaLOl8!4SKB{kv2DC8<0tdE_*$ca;l&5u!TQsfEo@sUCW zQ;3%P6SB+Z$g<K=c=?Y3w7IrMn3|IMI{@EuVSP+Pmu9<dmK#=CRB9acz?8iB%A8e& z?I7J8q88>eWZe``8$%5SbF76-WV+;tV~4Dsb(>54wK-!<cxZE<^4%(4>58P8l9rLi zV>XhkcYF<uRd?}Qi0#PA$?7SUw&O<>=>H!*!j~=`&ukr~3fJZr^X!`G_gB6|T*TdL zJ1`tcY2IIBhig_8adj*MpFt<2%b4@nnfGAvAtt8t*{MR#`^+CdME!Dd7(DzQ^V32X zFf<7a(<zS(i^Vc)Lf^y5zTGCbLIMI&>aw<sK_alSxY%X-yy83N@mJ0(pJu0@BSMOL zpWpd+GPZF-?ZWxSU&HW@4P|Pk!Ta|SlLswc(9|ne>e4_Kur5UyOEGjkd!z_)z+VyB zf#qaxb7}Q$MB}hqM)8@M-MKI>dw+g@m686W+FL_1pSm{Jeqx+=O;$N|@-Z&1T(Scb zGg=<tk&+%=U0n}U=qNX!yFz+Wv##O#{=c;Vm!f(fOy1D>#YH`v+(+_3)|lL$LF7)E zU9rL6yYeUp<X6vWZK!Gt$I?BrGg2w63f*!D7DX{Rr1>#ib+$>LzYq|3TM%FHK&8k7 zFs_?7(|#?!-QL+L&3lEzfvtbxbUaIyoA5zq?xY4UW*ynZ^y$xtB}La672oyiHr!b3 zx`CC|d0kz3`n|ewuU)=QJhP$?8HJfPG;1J^)jB5jJIY0M%n66{=^H)9itdG(o#w8t z@9R%D@t4}}-n)av=7fQ9WXrwiCai}(u@{YYrA6!?eKcY`;t7$P<C2hu87({9(bA{; z^FA9pIn`$k=4LG0tS%-_tYO=2PJYx~P~#@CY%mph)*<Q@92d7<qK$;)-{SgPp^Ast zJ{C3`Tr|LaGSboc-w7x)-;sw^04loeAE43a(?1^Lf$c5Z5d+$dQqys}=0ATVwex}H zu{)~UxS~7X`8_uF?6gq?8b0bt*QAquE}a1AX6F$R32s?9M5bPG#fD-bP;0Ae8UCW? zA?R+7xKj-ompbbI+g_djatr^foabO0^AT>t<+nIh^xZASCC32)_%?#+@=rqW{?pL& zzy3=9ZG&Fw%>U<_pZ;x&odTI{SG!126LA+*1rHL^)<CH=VvmNu;p8h|Wu$VbnFy$; z={!R_LvXTC1-KN*Joab^l$mKUd__R<kJxMiVN?M%8v_#qEO)Cd%{lECoAkkD!WBpT ze_zC*Pa@fG+Bfd|qkZ3|rB5ydJH`CkTED?)_1DLQOu=?RkZ@rA4tu{ADc$9tZk7T? zXAv4692WhkJp@JU&z!Jj3bqg7PJ>|l*RMC~9${<G!6Jme|Mp4#Wv2As_M;QJU3*~A zK<N)!o$a6-2Y|aBA0J0WL~JTU;^*9B(q*X!I_PJ)s$>7ARJh?yWo?<kc2e-wi_Gu} zA3&4NOhCG}S3lEz6TGk`yiLkL$X2BO$`oCO2G%?Q?t}mt)w<>Re7M8mVxXJG77p{} z3l6$dSAF_TXzi`I5cP#Rzg${bq?uNKgf!HK#05p+VPaaYpYj*Bgp&CZM@NTOx}2o} z)B~!|-o~J3!&H|Z=;4!z4HEGVc#j`jS?A?~JIDkbmUE}>B4Y%EHWeE^-QBqKc9ZY{ z1W*+GL|FUV(%f8ZH0-9@0xk)yTFo=KBTwWQSK1g4{f7Cf>tVb-SFQDlzgK=Yz|hn$ z+agczkI$=BSsm@KRl>s>wAggjta%U@;l%#s7WxM=-}BR>^)W{P%Fhcix3|%WS@(CB z3ZdD<px;O!0FMG(F1<gSaHxGJBI10y$ly3|PiYNmjscnBbUm+!?5m@#Ae^Oaw!hrI z&tlNGxf@vs)kCHuMdr0N&LN>&shpSZZDj-4N)kCk65+zFEtX5%b10&?I?u*^!gB$r zwAwiTGR1crY^(BnkBcnkq5yr|gJjNJW<S!ltT5S+h~a$CFn6x?QK^Cc0-GaIqqD*3 zLmXK4@)?_IP|~2(aC~*XT^aL*_*!>0tPj`$n@CPJWTh{MKY4Au(6oQKcm{+>PJ>@t zm}IsUj(Iy(c3a!^{36${UGun)Uq5A0xo0LU+BWeWxN)iC@zK#AmI!n}>C`IE14_c? ztB!m?n;N<+5%U@w1B0UIso_8lLIkyCRJ_`u%4LR0XZ7nTz{j9CWP)mzg!)hua|YU$ zpi2jmZxbcPhN`M#YU0ipM+-05j}l1)5uH};&CN?=$fZUf1rR)wR&HN@rX~+Oyy3!Z z#=5Ag3UYwp-%w;82Zv4XeRk2%4TuI5Gz3aXAtVS9c=mpHOa_C+Ab*^En`%fOYi*5g znbH&pfcLottk(63%G88}t`wn}3>mWWj!4^;-%NO9kRK5qlr=<5vF<zq5%&8U%Vp?^ z6ZWmp_~mIdW?Je>NIgL8w?_{kWwYicyZ9v(!iioWp3|xpyb~7Alxuwi8^$jdXJksn zFJrkmiq!><EP{9+kNcXjGT4hu2aEJEDLp0PLWr9r;vm@dQ!Nn`_EmcYPZ}fKIQi|? z@Ke(z{SSsBbgDd3`R2(UyPJI(4Dn89>tof;G_fWmZOVD+z*no7oHrUkqHLipj{kbL za&eLI&@QO_Y&Lp-LqVs%;iE4TcZit7lAD$DMqO`g|2jAMVWL)D-KGpemM)HPgcM$5 zOh`@5$jK4EKWvj(S?jRpaZ9bnAv@(qQLi%&l8Bi2Vky`Z&L?QPS~?J>{$f1X-|yvp zyubH4-pLtw2)&;tYn7mVMVFfN-aiRRN}9Ip#3`a@98I$}6kdZkW|WdJ6kEN8O>vJ% ztxNK)SLAntYqwR|Ol^?Db!S__2yhI=M19>$Iy!PFu*WvI?espH2$1fJ6S8BCT=mV3 zCk~w*?h{{p_OW|9HC|I=C~SnuuwV^5daKB-<$lAzw%cJl03iaiA${qKYNPK7(r#E; zSq;?}K7hv6i_UKiQ`{+2Rc<0~hq>x|ySqll7Z>fY)1VZJm(KAnLOmdHG4wmK7r|^e zPRYn9DkC#f-`EN#(uCg-+?0NX6BFjK6!eKuUS9s83Z|NgiL|tfX=MGFESt^hE8B55 z-MF~Rg0EFrPp1XuODwxJ#5_hp)j3#a&vULkao<5KJ^DQP`tIGk(xVry-U@ttU(VZG z+9)|nQI?k#6`ze<K6_lK;92&~Ld(QI0&LN~IXO!D#*SHCdM2i`&2CTP<BVrSn3yCX zUS5?=>*!D(rr%4+PUSf7tB*}JpIhSPbywRKJfi)lkTU5R=%F-FJa#zVH8nGPS8O1s z{}Xw##?4|P9?hnxD(2U+0}*|M=MKL!i+`=_r;Lnd-zAyF1u*MiNzT60d3}yO1A2Jt ztaByFM?Jm6<6<1whf%Dd7k<!O>6x!yv&r(^gnnpb;O{fa#q`k3;ArYyvyVM985Ic? zH3jn_p-h|TY(#u>hC)DRye8Z#1sd*pd67UOfraN+I0u*gu`h34NlD4)#JX@=bEuK& z8%qE91wg}>iY3nwKcSZ(w(|AwrY4+X2+E2%o`|n78?}+=8SIU~s<3^ElMY!)Zjr(J zpyQ|)^7U^4iV>FkUM#qa4^0dWVo;Ybc1cm5-EkWOJA1T8rLCo}w||Y(93>jrix<Wd zOI&tcS4zIHvqCUMTADtf30bCZ2^T3Ss(&AQ6ZpWrOueJ}X3xw*M%J>yZ}dl5;8avA zB;w)b=8&<TO5}x1wT^0<*6!XOc!<@S2*KzQLI`-v%SjEFea!B9jnzV>kYfc8({>Z( zC0#iB_8au2{Qv@Ee{JiVuWzPutrSD0d?!b|<LYR~z7$1E1yfc5eIXu8aiQ^$te}GK z@~oGUBhtn={mnWA5H_EKmrE8v42?S36A41Pj)EsN{#0SqA02aKy6)e-t3Q~y0{|}? z8rrC>iE@>eJuQOEdU;sBI6sp9=tAL1hd8HhMTf~)NdvG9RAIDp3e$hDIOUkx5XM`= z?#snOe@kyjW1q12gk!1n1>2Wb{gH_4vG8UKHS~`33^5?}plUdEs;O}aamMC9<4lHL zyj%AOws*IjNmES~Fj!2-qv#Cxvv4|xJOMwnuwy;F@9~K0ct=;Cf<jD8%%v3u$W_9M zv1&^hwVXff_nMoVO(&{ZvQ!iW7cM+u(P8UCa6o7%wrf2+K^K>o@2GJXZRl}>sCxVM zNdOm@fQQH7LztI7ZDYV5!prKK0+h?@8a4m20s{TUDuQkWVS=0xo=|~l-JgL{H1U1n zLmgz#=H})g&_~SbFbWkFP!SRze^J*UNTrbZi}-SuJt8{otfIdeZ{|ER2Z=B^uj<le z#HOdGW1U~giHR|S0PhWD=v1RHK$rWG{TGUY0%5hBGVhV9l<yB+QZ=6vM8zDT0n=-^ zm2?xH!L&+MA;Q~oneUYqm3&oS#~)#&E4eOiVq_+RM-+9$dVH{^sjpoJpLY=Wfpn<e zSf`YELQ6%#LLGJFqQbB0|AX>6{N<C#F1a+{&8fa^fvISc+^uRE^Esx#zc-3=okhwW zRI@pz?UY#ynT+)~<)H3zVF%Jv`oAymP$qHu+|W!bB(+b}$8Uy_S4iOU3x47zqFk>< z7mUi%`Z=4jFqbknr!_mL<9t$?siKdr5EdA=AWTKCQG5J%=sqWcp*5=Lny1TOGUST+ z|9#8ip?oB_B&_&~bv&5it~&4ZgEJAGE1kM}EnFiJ^dL+92U=ia%prL6h=vhaR#paB zc&M2PkT(!Ijf%hkTRG8uXbN(m%q9k<R>LTD7&maLKTJ)JIqu(W{|Kdl6Z;9=PKV@_ z6^yQ5L^sL55qz$l@IWKxM{w@M9#ZY^ttdEP&`mVAA}b54HSY>O8ojH{&8=v=F}ATm z|BXWZnL2u7L54g79i0~i-9M>RfgY?A;oDaZ)j+~bJN)`pBs}L;Z6pjNs+9*04qUn| zga3jDLh9h02WXlCt@<JiPF^#DMMcG5bx!8}24PBxB-R=yP++f|XZ#)(CLmJoc=8)c z9Nb8-D*21zE(=UtL@wnzZ(og?_(`b;tk+y?LwCGG%@yJGxjqe~^(2P+t;=NUJt&uv zFxX#Zy%!=3?KL{`B~dM=2c#?PHV#HAwKfB*_SaR8A?bbd#trDmg9*wb&SCekIZaF% z#;4BKIYnhf?701bY@~9DF#?00p265CQxX+BC|D+lLN|uXSzbW_GUqxSRW~8K2<xo+ z`nx}(Odob@l3g~bxWx-Jdc%33&u(#3ijXiC4W9+<TFBa&j20ciJ}}#jaS3s8lYt-l zz$~1ep6c_Q+$Xq)f@1PPIlf`)(CK*hxOi{}hc+x%g}=Y@cyC!)WWjbWsjS3hCJjQi ztyF)&02S`nCgI~FCFOVUrgZA=j^DGgzRB`=zTA4nAJnd%*S~)YP|4@iz<A~vKn&{9 zXn&%JiOD)(b&&fPr{eqkC3e4WsgU669W>T|YXLO6{h7rIIjX$_0|UJ$o%b?q95=fH zbJb^HA1a&&Z1$G-AV7TCH^QyVhRIxMymxTF%=Ur@z)i~ZESzyaMs(`Ic4H*)e=yKw zjEp2YSHeBuw4IJ#R_?4bzR~$~)(d*fsZEgkvF9%5fZQ!(_d!5?Sl7K|5zYjRM_)Vx zpp~=xv&qoUFq^da_=)hc*D^A}_3UpKzx5VhjeWJgURhN=(anXJq1xu4*k??Lgs@C! z6z5>;O18UuB!pjKF<)Hu$x8o;d_|gZhJ5yN*GH0xYS)dqIYM0A{xb7q4GAJZCj$jP zE77P_T~23b(c#g$`ucSfrht^E{LYj!ZfkGz9&@U>dfjtV;j&NhWS`imC#AdPRMlBd zLOp;}0*qilM|#7clM3>Fa8A6a+J~4hARCu$o`5F6Lb;zmEao6tC<*-LHDiqIWjL-B zTNmlu-lg&Bz^zNBaPf3HJq%=?XlV&jeHP0BcKCGe8?$$R;8$H~+nIY@>vZJ3eg#^- zePR;-{7zE4Ic+-$$iBN8dJ(pjwDHhliD4(vhyWW3FM?$l`d{)A`DW+lP&No`_!b3v z6B`5<nfUSF>F%X8%Y6C5#}QvEDJeM_|L|qv#Qi>A1X{ZpqOu8}b^}<Fo>o7XwHPi- z8hT0tKp~HE13gNh>H$&tzUV^#9Ktfts^xUL$meGj*3*&5DXKg>m9MNM993IN%x%A% zZ^)8OJ@zr7FiK5(mtI0tc%<5K1E3TLyBG}osKeS4*1a;RF4UZ10V{QBP?}P|5+3Ll z6lbef%EQHCdxx3JVRy)SUj-+;hCx?cx%Oi(fR|s>DlGO!g0!jNxJ2);`z@B8b5Sf7 z&vdM&T4N4R7ZK<0kDlD*t6uwYW;2mbr#*(tYVn=JmlTXJYIUK5GlguGfi&wZIDHio zUV-dS4J1V!Hgct^l_t)wL%&c7)Qo}{hH@j6O2OOLcXe*GR4Ca4a@Q#bt;H+MJ<n_6 zPan~!1;xe|wmJ)nqnmaIY4;sYH8d?Tr~q%lY2R~0SZY@dye!A%U0fS?mP+G{_la(k zFC^2qw_QNa4BDFc-4<K>-9mIQ2i<z5ProN+3miec8zY-k3b~!JYa{L5A14zMd3bpG z?AAw*_<h2q`c^b1>@Vvn;%gtokdeNskWDBOb_~5nrHx*Jg%LwNry7+fP1<{RrU^FL zc#Zn)y134-9%+l<SVN${o|s)1<)h)CF#rcxY!5<s7Y*PJ=fhhYRPc~mL5A<k#gDE> zftpR?5s`8>$f7A|?ZCoIpX*;447tO<{vc8Nk~DDnTwy$(ke0@#Ilr3J5v(C`eS|ui z*)&n<HNX7=7fpyc0H5R>TR25PB|A7AN6^8#mE9PJy`s_$+0|yg1v4qZ&;B^>^*49s zMPoViVIwCa=D7=|E7vRj2TF8G{Xh(NMlmJxqgH~v+p`DtO_!nM{eBPYtfdyq)2~8( z<cz_Ko!tt#XN68n8kRdPn!m*o?!23M&3ce6$>TiZQ4Gfod=4!;4UM45g0KE*hlIT0 zWmeU13sZkXbXR${q$^7Yj3#Irpf>P$hR<Jv;yw1+T^+seHE_?+Iit*MYBZe0AD~v9 zp+;lD$-f@c*7oE4>~^ssQYQ=f0;MLo$sd76{7<g8y5<J0>|?1~;`G3IJ_U3``RuNL z_yTHoaVfSly<qTicoc9ne~Txye&Vbgg}#)<W%n0bTU&_^pFKQ0vQ~VJ*=@ul*}l-w zmzEjt4pn=qp)+2qMga+e(dy6S-pW9g)1J2)PM_ULM>Qlt;7n`N``bD^S0#DnecCq# zwktmafNQ*+6m<WL-86>^d-mD0XNPOirAE=Lno1CVgb<lOA?GrvI=q<cLsML)>#LNo z_|&j3g3GvN-1+v9jf05E2Sa3rrYCeSEqRWQKo5$qnD3Hm@VMT;vcHs;J$DG%trF;| zT{A!O?R-I(J3HB16H`Q(PK-luK_Vjk!Af72AmD4jN&-Z{V_2^fh_Z|g{z0nkiduC= zA;#3tIzFi8O!y&D7cwnAI+zP7tj-wLrdiJvSQe(P&wqnuDmd3v+y*^VHRJ3uKKw`z zID#G`Z7vii*^9I%1t#sne0<kYaE*~gX_O@FA0aeSlrWI3w7<0GG&$+I?+fvp{QRe( z9QZ5-?*@sCk|&MyseWX?)K6q|gB`Pf#@-D(K%0du6Np+B;Jw(qC~^QalJRz6la#V@ zmJ$;_DL-ixb?qokkzPqE&voUKj##~JunP)?`P<MjoWg|9p%n&dqC@tNhUk(Z74R#D zOhf#-Lzs8e&O&=)9&e=-47w=&&se-o?sPfy6v_Uf-JktPRrf5QepYBkS2SLj3_JF* zRWbB=Fa-Kw)*eB_mrNJS7n^I?p9m{$y!`zk$Gj5DZkwu|LQ&hpOD0Aj5l(7~V!f2+ z`;PrHv+nG-DJx-a`)%Kji&*xO9z5xch>jd+QVS`$8BS`)=ri^dCY2lwW9u^qmxD7I zL<gJIl8PPQqS`<nMlu*)yn;Nl_ZnZOZe}HXWtUuxIo)km5cU>94prIr>PirGWj_v- z@fu~7>b4@p$WF@S^-C7?8>&QpSsx!7$ZeW3Tk7h)88AtJa^aE?6B`mE+T<_&x_Y`t zx_4+6o}5!`hPSF^oBWBEj!uujVbjZ2Dm7`W#gYP2M4fB5Aa$>KYOX6%wAHw$tUGJa zba9y3Sjl*-AkyZV>V!Wo)AmxY=>ooLWM8hjgsND!Ow)cY>Tj&0%dt`FvP<QqgAX3P z-4i*X%F~ne^_d;7HI6rn&NSrY@AZQI6K&pqiXAX~)%ncSG;G&IcsPnsURLs*hy>yq z0xO)|V)y;IC}izh(DPK^F8awU3LQZO7yQOKTu$Ha%(tg^b3b_nsjCwZlSGAI!Hz!0 z4|-ZZOC;S=Y*p~c7iW9JjICCee`2YGNiq$#BBM=OWb`HVFw;b%$_)0DD#MJS^lq`; z1rp7>`<<>~^J$rx_4n&`T_jGv66%~RJ<Kf1XWEv=EXTk8#SOYbhaY)=;dP&)*QosU z-5Z<f*#%NW`4s)`-_*2DWfP=CvXv{nDULZXEb;OhPMzPCDqa)G``j4Eq4CvSP|}@= zo>ECc@C51-TzQ{Pv#8%|(H*%NO+rnrn$OEGJmqqJ6=Mnm;LkjgF7bp<<cy&;aWydn z7d<(`A0$7xSnN4*eVh*Y`s?|~XBQV2Z~^(Li=MOps!MDgwp>6K89T#A;O34yJDc=f zsI@z?60QB^lDI+>$beNCQlIPA10au$X<~ix2~Ep1^sbec?NS-E)w6r%+*;_2XRuwb z59!0I(0{{1s)Th`?p|L@yvP>mx=(+T473t*)xB<>lq{LF$)EbNr#2VDo2zr`q?ssj z<KEt~Rk}6S1@RJ<;);rq4O5#NPbKeuB1}+M%vjC+5r26_KzJ!wsydTD%VyXA-3FuR zdGvQ)Bcqo{?O=mWs958jfpRD)nP}b!QF$nvHZ3ef$W<1g5#J>v8>fX*gI@n<XtS++ zCp=dzS>tJ_^>9W7s|_KGO;Oi#clPRT<VTpt*a?W@Tn|2tQvfuVE&zAmF$RP`s-LNr z);pH6zbemV&Y4ZpJmlhsn;QrA62;eiDJFmsWOk6sb~f_N>~KU;D-&6_#VE(u@5ahl zGN5!VA0BSIPnuSka7g&9%rVkUtxC4<<vs_6u#J3}6Hj|w0ea&TwiUhmg%VN}Y}C|p zdZ#do(m_IIJjHxQm54q4WrcY#zG|x%f!OK1PaW*@RZ|x3yuH7H!629UlQ|86SXo|% zK3wtmsS221*z}hKu5usv$OaMe;`~H?^pXvlsYBC;d*4gG(;EWByQh~yF9vm?^IJ?J z<cg$3C{8KK$Iw%dio1NYjG3Ym(NhLGCISm`Q{CPptZ*Xgl>k5hW>-Ofyc1{}OL`=G zcyPVCYjJfh;Co~!zb#P&y)sn9s}d7I>b&4}wJ4;{TS_d;>s|Mc5j8zmuXMq}Z-L_c z@<LsyrSLTlnJ$Led+bizeM|Mkkx3`>r?eyg;uO49zow?TXLxP7`y7oWK;rrqI?;>W z>~D2-Pi3)_`-e)KH0w^wjpP&fd!HL+I&MxTY96TZx7R8bz5oC$`SaIbzo10X!^6GX z48&efbV68=_i*)1{W7qBHy!X2PWny*O7R{q7H-VRekm#_dTmcx>%)=i4Y{1HR_h{N zauewxHpp*}5$g(n;#N+gef83UWn`F%+u`(vOjqhx8?F;0VCme&>()g{pO@)vy<LA$ z1FQpVLzD{AL~$TAvO%_lOma}P)STU>Na&r9sWr<;a16L5moV(lDCkeLU{-b-8bI;> zNJAnnsjH$}h{<a4$v#P*M%u&jBM7#2o6wH(#nx&(D>mq_-#J2MCWK1FQWNA;P<o)M zaQ)X`WPxO5XGx~_g<nH`!xG-_<_xl%mjyfELOfD?bfFif<(Zz90p^UxZ~?ZvDGSDk zfFV`ZNU?!|zP@UO6aT*+25(M}NQw@IvJ-sL)7q6>&I$Miu^|w|M8_ONZS}eCVY%fH zZE;FCS$_#C+b4=1ZI7U!huHO~>T%fTXK!wv2LLtUwEGdog#6~=ZAS7Wsu5d|&n#`0 zn_X=7op{vulfF5nUcYim4xq$Th1F7(?u3ht-9HAtb-@PZKMwws+d&L#4uekF{^D@7 z$$O-1e%zW;6798#LZs$&N=B1JOj6!-S7VK~2z#AwhK68i^xzNVn}!}~X{_=vYGu*V zT0UOB$^)}BhtQyc?Iiad@2I1M&)4-Bp(pLxGZI+;UO%vwsgSD!nc-GSj&n#+{q~Rk zp#QNhQPJ{sCFeGG95Vf5L%-nwpi3?TZA<IxNN91oB#1a(m;!L;hsXSZtgpA%xbK($ ziwx*kg0gqfyLUQD;Plrl)C`r~jt4dm%kh_zv^T#`S$Xkhe9QFeRG)R-4mdNTG{#bn zr(&(+_aT;<MW0IkS@bWSf$LUy!&ptbA4Q$LbVym*>&i#Q<bK_}!!;fM;s}bBz4I<P zf^Mb19Kjc9F8KI!+k5lk7yJt^sq6nYUJ@Vfv{PMOJ(xZ5PU5a#n|l7<O;wMtU35wA z(pMwa-#tg9h!Sx7`<c7Jk%>3_hL@LDjmtS~&rV%b%rzMUFS5dBMW}HDj_~X@Yf&m) zbpo)$hp0Vh^?}1t)x~C=e5Z;nWH=vO5qirbYeW>wrriUC47eb)79RZ6Fjib%N$<?4 zJnrH4<p9wm_e16%?xIhOBM=@7_)Fdu+HlLpLr{GVZ4J*aHCKX*v)o4$mAw+2w4H?~ z+XoHD#aV*BkF%4Llan$F0E0rortH$8*JiNISxIVa?TD>S&&e6cmDo7BPxOc>?a$u{ zxL!zHNHam!jzdivHnF$}u|GV0k*<}VC?zE-*grHxyGxY)bd%`?DFzl+O0Mb8jmcI) zeieu7(X2B_^{1@%+q=nR63jX3tyoqK-=K|)i4KEXccc@1pj|6#%F~mZ^s+Bj`-Z1> zGiGGXs5!X$m(#zBqGqdZ@|zlw^lS6+Hh>D5U+n=AG;+a$hOd-P4IXG2YT1<7JlQX) zMb4Sz+zM0oQkDxsLrG7r$_G{khAC$R=}*z1q&_L)*Z4O2)Gb{J7Z-z~FS}}J=j}Ir zZISo@Q;MfTB0|0Wc(t+q79ZXubhQmf-#cv$O%f;CT4cO~ikc;x5p>v%V#+nPtXN=m z6x4`{8t}46!@WC{tltBCR-chI**^zcM_PJ%@31voG^M32V8!l!E$1IpT9HLP?+GXi zi%II)F3Jdwe2B@)mw2flG{$i|xheBB#B&|BP?2{PQ;~%IiG}hMd@KSjEj{wXt8*X` zL*Sb?_ZXh%5f9_>Cw$PWp*b)=_w~Fd+~Ut)eGH__Z1J|U2223(3OzGgT}Zf$=XGCp z$r%`Ao?rb8ALbY?W8oEf>c}28v(2tyOB^V9qTXfkYH{;>N!_wp>i7w5-N<~G<zTT} z6GZLv151$yC|%%c)Y_cI%aHlIY^X+QOvzojG6$QRU@?sdEd2Ni5pT5`r#0dSA53)Q zAs4!lJ%<XhUQ#M51tZ*zO373eb(kzwV?XyeZ0{;wM;;$W<8fnGhoo1C@|y=9M77+> zy>^BC_Wul)UrNWMmpSo6Gs?^V{`CLVTBHAhCaO=NEAiFk_i%kg;%t1Y<tF$db^4HV zzj7tj<A1Be`@iuE*W#+ts@0HFVzn2+(ZLh-q2MT4XoW0!PMQ6cwXfVbP^Sn8kH!cO zk9@~>q2Jlwk{rK^<uPS8+gG-YcTdp!($e@;iw~*1!0_0pXgvO>s;BSmBkxwVJ<ka; zaoPJv*w$F|+Cr5~gg|&wS>O3ZHzdS&=%@clmHR+iw6y9+ige26sW_A3-<1ScPP0LY zSD6FBJdK|rl^4^Zyax;i4T08n=i|0u!m!}b;-Vr+DXEXbb2|%<FZ*ceW}ZKPe&fas zC>HhfxPJW$eIY%xV=<8K9Q%d)mxO_dlCN3gdNH*hTUqpidNt~APTZCB|L2^zHvu&{ z`JeGbWoT52kLTXOe^6U;`A%}*rCgsQ4^Y@trAyLId!eSp@-D;8<bvtIJLalbToYAu zcw1W}Ll)T3j1UZ5r#IV7Ygg9ki1>Y~1(k8fIa{XVWi99_DJe0p%?;|R%AW})8-962 z9cB8y)Z>Wro4WGl+Y*1{|B?WC$N;TagQcBNAw4u1_dQ~9y{2_=FjuD?kJHg+u(w}Z zaA$jeyrzNk=~F2|<w~jKTYz7Doo|@g;;>o!AH2PFRMqX<?Q3Cxf=VbMC`bz^Aq@%- zAl)FTNOyNBiYTel-7LC01*E&AySp0}=UVtYzqii2_c&+2WB=ul0c$P3eB-{aIp=5U zkESL9{7AaR;b24BLPVqia}@@@CS&Es#>NG}=>a2d?8j?;$<mQ)7a$&1DzQ35CUjHN zah(WqB&j~)W@e4B3R;{5ItbJqJyCrsX%+?SGB8Wc1rIPll##{scRpmlCMWN}$_PRf z;3SdAiW-H%FRYPSpFMj<K~cX(T;{mD(gg*FG##LGPyu|~zuw1Tcj*xWLkG?dS*hLP z*6OfrU_d}}4&WW9Sa}~mwi^HN5p3QLr5q5(g<hE|yUpB?f^!hAJ)CPNGoGhbDf#JK z!ARN6p8*;aq=^WGd~!@XPQrfyZ%bt+?!n-Um^&ge(qVOUmFL|-=V%#qI`Q2Ies%S+ zfD|SuqWzU%v$e44zkD_l^8tX357vlHR0^%ZNAu3OuS2`jGcav>8XKs`Hq&z%=Gc|i z8SLg;JI7cgOTRO??KUnry!ue7>$k?Yoq%!Enfug}fB+|KcgKplplE%7{pr(eu(c>3 zW{x@lF1<?+kc*)7sTCS&Pk+8eN7wqM+-|S}Vd=5AipQXQ`wl+4OO00PMobsveV85F zxhyU70PJ4e9_0uejd#y^d3Y){=jrn|KVB^j2@m(X&$0*T?x}t}IEN<YU)EI+&1!kN zs;diE3{0r6h`lD^J?g9ix-Rg=SdGVW^(HSl6uX=XdUn-*#!Q-o{HXM3Wb=U0SrAOD z@{KfvE<+-NjdR~&W1{OqF!H3NExd|~iOF*Ks7>svbjA=WKQH{h&(GJe5-s&+TAv|5 z=I<~U&UftKXC_f30WzoSF%%d<UC|&sR<@INcY0w;>-T_LE=ygF0OCDAf8Cf4W7Zd| z&C`*vHCuU^Q>odoH*CA2n&+UsZ{mBH7shc2KvSGGuOX-PqV;6$H6lf7>J&ViHsFh< zAku*7OsivjuG|tsWmW(s5(3${_JLDwj^<1nk?fWd0=vV(P3h_dZtpm5l{+1ViLB%N z9<*^iyWrW+{PykJhjet7TQiG4V`ALuZ)<;Gh*K(ZnFh0UgCAk-tV_cwK6<fys?)JU zDA<aWR8%%S;PM1tm)@1RW9h!}>R2YiNMR67B%(OlFbTu&=cRB{Qy)Uo5{X2f&?Tn% z0;MvoKUuIv+n+;!v=sOB%isx2^=N2PZRm!2Q{^Eg5eIzKL=|1sErH}x^(iYUB0*4K zf2w}!Df!Pcv(%X4Ec06g18_~~l61dM_rB?WwkVl3=Bx?>`7SU*LWdGKGD>XEE^=bx zt|S(Z)Oze;5i#e3ZVPSIitB`sLvSfix)|z)mV*^?;^lW&%>@UKgrs8@d6riKMiU^v z4rsvr!R8@7ebt#{MXB}ft(`-a)Rb80!WwU(VpTj?SH~?l92!!F4lH2nw}ago_BS~W zZKXcT{d+54*HE^)4MSk0kcmW;u)m86mX!%sOlid7^zR0*2H?UsFFUKMMg&+PZ<uY( zggRI+6LA##86&dWqyLhZ*B(}2rK4+`YYQ_OpIn34)Hb#my1}8necc(g5-4MP^cR;` zhxg~^YDU+<ssh3YZXnK~3IQ>3Y+_>F)qUV!81$twqJ<xJ_=NW)NzfahJY3ULl{NtK za)BnIdhrmeoq-$ZYvh0Kyd>92B<OgFsO<qDprx&qNM3ifO4Bp+E0L^ntp_HL#m>R7 zTjnqld2!T%Z56_bwM$C|az#3#UF+kn#n#KuUGFwS3`hTM^UT+>{S_}y`q?*rcO?~t zgk)u*A+4d#m)-0=YA|!@@;2|crR8PYoq?Q}m(@Pi$M*67A0H^13(cR1)z9Vyy@HIR zxST}@-<gi<kAC*SM^ng94-X5f$Ei33KCH#k=>90Y1J|O-M|bx@+YCB5&Ofm}dH%6t z911p$L_|<k-CLr5gTKl2UHY9!8d!<E@Y<K>85@7T;H9A{RqR;PZ19e=@hkxkf!=VX zf1H~ebag{B(LDww3g(PZrC9*4^=FOe>+GV>Q7)V}6&*(7sa05%<m5<8$HSab=WlX0 z+UXy1whpfxjTY>?Ai~$SqAa}|S!;$zAJKtq>a#Xf@VU>PWG-74L8J~t<|K)zM)*}= z9%0Eo0ub^vDq2_HuPm%g+h*f?YKG^`h|A_bWV`QE;S&1=2mH`U$WrURVUcGiTrI#I z8r<Rq@ezP=$d)99*uP3qcvs9QhTm!6dNgCGtxZk7d#27RXPQJ%4t`}Ydd%IsfsPpz z^y4`r;}e@!kgS0~+uGI!Q0zMIAi(4k;OQ7^llKyz9zxv%&N14?lg)5R0b80Th?~l8 zOqcvQJKnmV!?4jQZXeJCc4&XJI`Yyx5j%B>MO!wY@}wo48_8ZhM0tHl_ATn<d+8_p zYrfP_hy3AM1FLA(i?&6+S3`u{l@F80AO2<+HiE$yY)Ygg?|WjqPd49d*!}4oIC7F9 zReg#EYc+cri;|SCo3cOFFU?y7?lf;{pEGPWuDz%`?Vo6*5={xkBW%$B^uznyK<mmS zH{$xhmszpteUorUi*QQ|sx<Ow&sH8*Vwq3K=sE%wv=VUt7!_cZD5?B`pZEM7-?RPq z_#&sYR+416s@p4$H%Z|1tj}M}3yDTKAmQQo75~xGr^(jCnA{F~$c5?JfHK&03kV1? zCDu)E0u#RJ<oQh>S`T;kd%Nj>Qxn$z;V8I#0;C2YQrZH74kDG%1tRJGu^?oSIKE!& zugRIF3|W6%jER9qKL*7uvX#HiqBgho3fH@R9?(x}fY^+pE`*G)vtVA3y6<)zP0jOY zvOAHs)pYJxlPvw|aTJerI*K&3rjVsZf{R}lpdct%A5nr4GG713nc(TLH<Qu>HImv$ ztAK}tH(5=6(<0Tje~9sAc`@mB++gt>4^7<gZx0%u%ogcPk*}!*u8a-{IIZjZ1lKN5 z-Bi;?z97Pcu4H#`uL3*PCn6$!Le`I%mmRV|1_lNVzN=*%R(HZS7MUdR^%ouYNy=T% zVnu`7ebpWe?ENPiwo{spbm-Dh!SbCu-{A^_nEK=3<7ls++xO@dGUZYnb`4JOQd?07 zp!y{Aj4{CV%iS2xGj)CS>eZ_9p}(lG@Zm9_bbwj#C-Q!ugv1p{10p&U^@3pK1n+NB zC~yH+#>yC;FyAr2%=%{*kgidC6}1ouN>6`6Gt$k`^8$hSU}cq4T2onhC@6yy#9?NZ zXZRdi*|D+J??3RLoSvq<c(rMQN~)(3{EOi1a0YFFKyc<_IXXNfVYlI8V=ETiUBagH zj<*hHb=80pdU>10p?IJ*2&_6OV-MAaDus%NGcS&3NebH>gPH}v-ZGn0K_5?C-S!Yc z!`wk*uguJ~0AcKcd}e*1+kS#{EsrabPh7kJ0y&_9#ndZisRQ64{OTSF+d%fqj~T-@ zTH3lL(C7(XRcOQP;rSjE1QzJNH8sxv3Ik80wMdP#NostikJWS0dAq))x7X?qpFkjz z(h1N72#LrNNc)$T4sB@gx3#qm>;Vr^t=vjUQBij*;Rec10Of!&J-Y4SWaeigVYQJ1 z&&QPxAMm`c1K~4VGW-vxLI}CJwU5w+{uaFlGzNOAl}>dXyfM~kc&M>#o)vx9;qCi4 zkk7e|gTrMqazEC3dR^>0<>lxOgrr97BotwQl|imTnMGN{=1QzT`@@IXk99E~M1uVr zz))UXFRXs0DP#aiyAtBO#sUC?`h=M_k-l)hO9n*+Kh-xj)`oh%t)E@O#s7v!r@U8k z$pe!FB3}jIm4vy`CTr{lN2kVUzCA`?iN1#zASl#F>!NP(?(U0C)`mqyIBj<0g2)PX ziG<64A(nwf4O|G+;7yv$qouJiK{vtmU?Dy|UA3m4?ZQunPoBroO}`6WfVx>^JpO3l z0OkSxgO+NlM*z_<26({ERR(5Ufm(O3piY&3pz+wQ4lPgSgcD?)Be^}HSrkmx@8%`2 zO8Yx-K7G6eW@-xcDwDPr#VkD&w{6ty2c{2H@fgp$kAU>8^g5(JS$Y~gbiSjGzcZCA z+fs3Pc%tVRUW<`|6^NL_VrQdE6UZ0c+{+M~Ulex$T6Vy2y<|v0czF2t(8b;|)8!z# z-|6Zv(_rnZ5oXXer5(VB*BZ`by_Ha~%*y3-@Pz<~|F712{+-bL?fIXiIzpX$@M&{! zXlP&6S&WVGu#xrfUyGJI1Dm}N*ZCVkuz2J#H9cfa2pa<-AA(1;v`j!c@RSl*-BZjO zPgg68x-{NAD+;!YTyRSY+i;>i@pSgO*N)hL&ptpV<eQ<KQ!X4YI87lIr>kEZ8F8$T z98+mtJG8ete2bWo3rt%>)Zesqw7P!+(Lo_YiPL`T)1oXwER2henK>O=rAn=rq@)Ph z-`)4gHaZj;qJxmUVNYovR1pp$`P>mS2D+X^mP<RKR#qd=O=Aqd;xp;qvyQrMJeR>~ z3$+{)D$g8R?Kr4<5B5em&)#21wM|0kK2fXup$y9Pe*kD3y&<T!{Ae)`Yx{ex(V{|3 zTu;hTY_7?vx)x^4TR=25UCPH_9WF?;SFg12Athh|up=cox&7%-Ul1PNAUiv>(V}M% zmN5xL-E?!}1qfdGV@^(JU-XS28UuVna?VDR>W{oxSXcw7H%qa|MEcsoNXfPp8#oac z|5z=oYA_xsytML0u`OzG(ia(%k}tEiSex+iO_dg;6)>~ti`m@$PHVQaunBjIuEI{* z;HsFKWwVum8vyAr34g9yVH0VR5;!AvkW!_KPVyUq3agwW`j^2OusJ#1@Jy5P$~BLb z!CCMe*N$a^bP8Uw8*iq8(1GW6O!CFx?aq36Nv0fj;{9Ky<K^0fxK@S$d2Q;oT3L|3 zhV_7+D+8*mmecWf>babca8eCrT6`a@K@$n+z~b&>i#<tF_8|nr`T7OcEjrlPn$5<V zf<E9N!*|8pQ5Ox&crZMY{Dq!Pm&RE-B@q2Xz~$rslkpP&j~^?b+bg3xXSyNf_N!?r zk)$h~soGwgwre6Sulz_@Kg)0iZpz5^Bo~XC`z(!%hd+<4|BBt9tE1iZ*q_oT`k6CL zfs_Nv!Z%HMXt)LJssJ2CVc`_}?WB$<u9#dZZ5D@D&l-oCMa(kd;;0k<l8uG_QH`DC zJC3&VLdKq-<r)%mqhU=6h;2QgE}}mmY#&0F1dR7_d*xYK40U&u@vW_Qja8n@a%X)i z8||vD9vJvSQ!Mw9h{Ni(ysti1mDA=A8P3^hlvbY9MNnwc_k*T7Aj6$veR@TV3BfHj zUPvsU0U%eaTW^6l(r+5D^^f5}=igxG_t@p7IrBC`q@|_**8jWd)Dopq%96MLx*ds& zUGF2WC>uX5YD<g?(#6NQO$9U^q8&p=T9spX6{c0%<VdJ2Gq#e_pt+`yY*)Zm{zS=3 z&QQUmGAb*vw$?T<tKFdclKFe7KT8N>3B?TPHw|$U0b%;GewnK3k#tH(q=p8m<kd&G zy|hy7K?=o+S!?+wy)p+{N&FN@qu68iT0!rj9A}JC={uJ19jq*gxb!YO*nx4rKDC=i zAT@sMWe|=s)hh(61Jn!UmNEh0;X|f_Mit-VOy}(EjJ%1F#sBeYVgBLHRPOr7ChQHw zZnR&S(?v$zp=M-s!xLhd&xsd;b|Q&;j60ryQ^R$<q6A<ma(f?;b(Fy)+Yo0<O{13q zkdd+2K|GpkVd2ip(J$6#VfNyVcz3Mx4M;-*(2?;i<N#UgL8nsWxH42*XlOXQk59L7 zlOx(7!pb$b=`HYrB(dSCv+Z%e4YlVZL6veLz6XRQ&F@H}e&9j&5c@hb1AyY7}F z&y~ME33YNC+7LC%2sbr-`0#QEuf0&}eGCb~^?%Pnz<m(TYAE6(cRZ47d=2fAX9)<^ z(yFuu;$q@rbN^DQX<TKvE8W#B&))yc&VIUHG=BF{-RZ%>6|hexv03#*XW}muz6S;Z zc{nf-;4v<eJG{HQ{qd49Ctcz@_mef!{Cx|%^7IuWd-f98n^THK{P-5~SN!4OAvxkP zhPcUFy`Pv;1LC6M*iN3l-*JLP-JM)8%Dn!PAh*!PBW8N|uoIH(Fr8PXf-qK@=heTW zD4oE4#w?#GlC;8)zPyvQKU{QzCw}YJ&})L2-ZICIF-pnkE@6SgujdGan(GmSRw0-V zc;4yubIn<b!3Y8rypS`-6I<g&Ptt<7Ww0_Ta@^<XSL(@9KSq2oc8*1AI>A{r8A^Bx zCNT+Yd&azLa*t_tx(z*SCSWWVkXlFd(B*6eHo<tAD#4#RKVaOr)yLY2xZV1EX<^~% zyN=t>>Wp|~WwC8y-U-~=lYfE~dmGrXj?d#Do>Nh>!1@)oPleLbFCWoyM?y}T3ar13 zsRV_3eZGuWhBxJ;r5`<i{u``~pP3k$3NRdeFk)HxY+!K08$d-%Exl>yyDU~XOgj!3 zbLs)0n7>dInuiRF7aoK5Ftyjp-oQ(=axe$BhOt*b(cAt|NXTm&HcCnl>PD&$FJBrl zY6gqOPNHDrvK7w9Yw$#0F#`p}&W_E8>ED0}Xn9am3|7rWrPP@&NgJEzfeT4(W{IUw zc$IOVLlo(>^VDijR6@PVNl<isZXmF^!Yw{$|H`lURpqC=XFbMN@wKCxsA_t@2kftZ zjM4*We+GtB(6eA+WfgN!R~2&S*DT&)k*&VUA6^5kYRD6=z{W@=JF(_;xiYA3#eQ#- z)wuo1Po@%jBE$vijFMvFzr@CBR7bd*9z_CX0X7)duvX$ZnXF7+zlO2K;r!J|8i?oU zmb3@@2dd>cpz(h89Hjp@RKeO|I$d!qmB^(3hg(jUnC_`-e5cF{5%~1!v+-E@BW`ZZ zYBzy<?a^?v$UQrIC#EPbkIN+K@Im)%Kk#^c2&t>s*wO?$uDl}i5VtgH!4-Ty+lr7W zoUun!9aj_%PogefIM|L!YmN5i>mC`*Oa4-46Qw_#w42hSJD|}l2!R<|t|p&wR%)wm zwgAqQkyrX(*P@^=GRWDcw!V#4F(dXvXXjHeXqKYkmTjYreo;bo9){2Hf4<4#IvE$T zu5JX&i2}p3Z07>~IdKA38AVxaqS$}1<n#O6v4{C4!ylS0P&k*J1AV}3`!&G+U=ngS z-3~JNE(@J6ahR!J18~8M`rz@q9vwPfSKrv|fpjHVY)!I3x1nq(#uGD2?+nX+(;;*x zTEqd(_5_#uS7%fSK*tCTiO<2~_ilCCq@<>9<gFx%Dx$ku61kpruKL2NEW3rS$>bi{ z6E4t`#zAvWwE3gC2Wim^4Gg&XfJ*U{<ylgj2Ku{MU~mjn$b~dUQs2cb0fdp0^J&P5 zFR2H3qZ2QFpT9vu-hyX?sxyh7#3FHC*y2}Kw!*q55@bAFm;%-H;(Sa{H;a5=J=a>Y zHd>kq1C+DM(OX8wp?BH-Bga5(G)@q%VH{3N_+xhtk|qNQ>$ie}l~P<{qBWEmJiGQq zg0Q*3s;1|`X9~1v@>vpvM=${7aozkuT}<jAn@ovILf7)*O|%3b0c^y#4>qyq9NTXz zNH71S{BvQ4u9MFtU%YTa0To)c){EWt9hIjm8%F)1)Af=|TI2Gbw0)UshOwTEX@KeR z9gUosow3-q@FV7VMfYFH>DyIzUDj0l!PE+;_;-<z)1#frvx(RVF}<x={;N>vq@i}F zPh3O*=NL5U*wi?gM9+fZxm$c>QX8WsnzVsjDXNhXKN!tV*c`T#qQOX3u>3YUI9vtT z1kk@HT^Qd5u9=rCZ#Btkfy!sc<EkFZhvpz;+8@i*#?C^X2pd)-{H(;tQ6Nq2t@0L| z`dvHQ;|TPmzFuh5*WTIqZK|<(wnc9iVukLXKHIEMilK>;YtIT`%;%6584TuH-V;KP zK{YX2tPb^OZMI8PTu}_?yPCnYs*&m^V{H$BCi0QhchKKnBx#C(nZ1nskHVoG!+!7$ zzC#%FW=}4$ERR(<O71ptmvK`_ggKo20vIEe2mKzM3UGk`nrX*jr%>Zde_ff6kR<`< zBfUo%lxNERvM1G>bhF>X9EBu;5czzD386d9pc4!$WHbtNv&LX%@PN}MSvAGtolLju z^9<?Q2b`mCsy2U2Spe-_B|n?iCKzg!w2t>8uVE4=T^0#ke5NUwL!ysMx~28jQ?|G1 ziCy8Bh;NzXg1*H4IsC_Qn72o%^uYAsD=HsOL-u*z^}gIj_HVj{*mi<H#CM5kk&WGf ze`WzZX>qCDDVoP|3V}KT*9`ygDw0}$z`7xKm7I(JwcGMTi%;)5t|XPabOi9_2;I6c z(GTo{glAGTa{J;U!c5&~l~Gt#M1eUh%rv>&c%O=m2L*8}!PI>9%9Svc5R9ZCko0jJ zpvmS+1L9IP(DR0|5IA5$rwZ^&c`x(Q7f(Y&gTDB>@)?o3Z_3vjRqoB7;46VN@^>SG z4C?<#+u3T9N-ILvi>WX4UOs!4^RoIS1fSfZYg-yyy?uT0RBy{lA()w;#)L5k`n;)f z>B%x(uUQt0<z-|{72GwDE5=n_jk9qS2EUIk2;;6Dwmv<?F<(^chCD|d!LogHbXCB5 zeGa>XNdU^ny}iHSEM2AB;+l*XkMTA%HWuiLzT;&RoD`%pITG<No<rB8x9I90Q9Ot4 zvQCY=JFPvIv#ABT5)X9uFU#*ZvhUj;9lVsD_Ts|#B;V4Si>4zF{n&XiZs;sqgFjU< zO{C~+`V+cCZW-9RKP(MNQHpn%tfb}BL!e#r08ckw)une|l&<kS)8%77i#k*vx9+_# z;rM4R88o9g`|$1`z5d=uXZ}cbO@hmH>~<U3d6rr4E>oSD!G0LfD8(9=hYt=uDP{q! zcz>Xa|J~T-1%nJ*l3)Pvg@xRQvX+rz`!tJL5fsO_iuHMM5!K+Ez#mTzxG!(80tlWA zRRg%~#u>=2AAc}Da%qDwPPVt@cr~0=9Rv_7&O{(1)Ky+gKp-I700r|{%F1C@UK7D5 zlVj_<keYOM=7!$TIlqtNOcz|4{strPGMs}EPPqQBK-^KP(0`y8{H^9ghxL2#D%x?K zk5YfdHU3ro^#da?g|VsWS!p>v&VMe4ic#47&PWT0v|<aT&j_ngQh5v;PAD7NeJZ*g za|Z6c5q>Cuf-k-fRT_M?stsfL#jYmGy4kszhv&a0&c}vnVNvt%qb--<MG_Jhg9OI< zKRrHwSI-TWN1>$t0RcFdwE;fiVAa$(YoQI_^IK9-=TBjwyObC-9iTql4cz@)_;~&& zV~n3_LBje8?|R|Iqa5=aGO853&mI*7-*R&db)qeWxr~S?oF_4BnD8Axg}SJ?Xapq$ zJ!|eZuWEak22#^<U@VTq*zO3bCY2-<3f)T4Q9-y3+vBir5rKgMb>a{er76n$exup# zyh9;$c5ZG9eP+XA5XqFw*v-h;y~DtBeuP{vqw^^ZvJVcj?=akwRgzWqq?Nyra_RvC z>xQ?I4Q{43^RqK8l3V(V_yN;{@3>GODB9=UH!GLF=A~{<J@sy_a<@s?BSEV^_0VuM z>8i5w?LHK-k8EkGjot&{7huB2Mbe39ZOaF;DZH@5_WN~s@2vUmtPQ-<f#ZfI2kCLg z`w8SU-0<Nm?@2Jv|3nvFT>5kL|Bu@N&g|IBol44qW<h^zes=a89pTD>=|M&(P^?PN z`LOOMmiq*fOj@v`wY9meB_3NrLINC}$_j#?CElDz@+F1bThdn|R#u3PSea<UTiU++ z2PQIi{KPtUK}`t7kUA<0elCwNLSy+;kG+l;9U_J%E`VlFqsO>G_LdiU-|A~<M3~_B z2Pvpi?Y$HgEU|>eBoae@{q%e9d5raqKZX0e;^N%tafa^aDJ?DYSMYu=e_chog{37E zV{Sfk@3~uq>aV;w2L~NI0g9{5SK)-*;`Ip&B&Vb#W1wt-*M<`c$A3mki;8hFZLb;V z6k=Odd(VPjR-umfg=dfolhWeTJqMg{mm0LTH&qvLqgohnyhvqjFp-twp%1NsZbUlf zG9J)7!Pnovn-QW&*vo~+Q0`KQRn9g4eN}jnVxv)lvEx!~-p<xXP6kCdV1F*T<f*7y zxb<Me-6GZ>%XtL#RZntqa`#?T0|fl%|2IbE3=OqXoZc3el!Q>hRRRJ6F?RGDH`<z; zbF-hKq*o|%oAA39m<FzJ!07KUvQA7)lEDf%MR)k1E51Q2<uN6tWax7;7M9(zBo1JN z11tIbsD5Jxy~hA?oH=Z}7Qtb^f*e(`H92F_+K2(jynvt}<2VC3`RuQ+ve4;ze&r)C zEzroiBy&_6AGgDklEvt)D3-RC7Q~+RHoD@k0ojamH!cWf-O-$`k0>Y#wMEO;Mv3&V z7$o2U4&*;0IvCW;%T3Q-I@lb1k$(PM9*;i679!R_=>u0D6!TVUoGNQ;lN<bphIZ7i z`~EQ;XkOTh2SBB_?NpHzbCt{PT~4RdXu^0wzjy*Cz%_uT?ToCcgD?z4hN<HzA3uhB zJQm6G8Gt;3GRo~>26nL_BKrAI#60Ao0571oMcbc=PjDYtNIfj?-P}%oB(_i&``v#g z#vecRgS>@%xG0jx`23c0;VuT)Up|5Dw+e{Iq|s`nMzb*==z(q7ZH565zg1<}h-AJQ zAKQ7#PHw;WLjYC{(0*BLvw9>%LXtXY$wuUm`Ul;=LPW1#>a^NS?r@)&crwS(&*OLx zM&+_)?j`mB1_wh)Sa|p!@=IuEL&b^IVFXhA)hntKIVeh&lDgeDH0S|H^5^o#u*_@V zfjtdNqK(aKadA3wcBPpUScz%!pFp`b1R<Xn_ya|TnuezG)Yb%b93OrKpoAYRU1U2o z1hY5WM;+x}o*nJd-V!xWJXi&Fohc90b@&rh3)_{Hkj`htXS8AdYM?YLA*x0IDLD@r zNr-x#SES%x(9}^FtWRnNG3=1;#@DaYlwwGNeR+s}sY}qav3)WIWVGY*Y5RznY6l)> zu*%b<FSo(v{w*W~hw#|l`9AK02Y2r1Yxu64pdNJJ-l9&-)ulj?+J;Mwh4}btpbAu{ z)vTZ}7Xpwu>FF!)FVYj2*&q-ICNvnZ{oU!@D)P6G&41_3Wz+vvWAlY?ui-6H1$~yT z?X8wT&0+z8b;R*bmRyrnf2OG`rhfZMC`^Qx1_oobmu<j2RI)yjgh-=xF@c@u1733r z;5Wkd*=-eMwRK`F1_lOj051(b-^02-vQ+rJr7j0`!F+rBcOt)GnmjQ9f6<U>+%FDf zn$px%PbtUqK|wJX(DSXnR&G%K1K5|E$$RuD)?SQwxQG~DW1=73%UfDrVa9d#suKgO zY-mNzP{-(C7(5GiDjUviaQ|Zu4%8F%|M=<i-@Qoj&4Bp#?}5Mk8Px)%H6C~sx>sUR zP!5GGrQk!Cwy+{}bW9zW6o{NZ;B;|2JcUv|i>(>`xrWW%UB}aUufvxvD<htF&*AuV z-zC++hETQ_smCB5!bVO*BeI|b{)FVnv+PRaX&^)A)x!Bh!fnHa`arXo)fK93A?(8= z>060jx>>3m<D)rgmeDT2fV_EfWqYm|jQ6@O5&skopTE=ApF}uDk?X;R`D7fq5GDzm z&CFXr;!)VQ1V={FvGLVjEre=QO^?&l%W-k>>!Yqed7O5atVcPlQ3^JdE!;6P%gf7y zo~ZwX#*TsNY91E4K$4M)@(Q5UMf=wha#)#x@RUOS=+Pu3p&@iBB`dqypCt*fg5+mU zo;Y=kIpZW8?byt9JSQjDUa!2IHC_&8HGEc`fX|=np=hGic3C-=4=9xkK+9i(`H`UG zQLC)HJiuaET={4k4D=0&+3eWJ*|iU{A2A<7q6AjKfH<nAr)OmiCY_5c+Ybl~(0?$1 zD=IENnrB-T91Pt9J_mVmGtl*%0?k@!$*DW5tEyS*NbW0=9rKdW+~H4MB062Z`1v8+ zWts+m4d}HlNON!u<s)HV85$PSnFlVrd{z$IrG@{(fuEK6a`VQG@BaRrHYZxELj^>o z1JL!_{n%(XOpQAzx{B8)DI=rc|D`s$M}d}xrt^YNP;hXO;lBFNUQJrS_fY$jgRgUK z;l@KV6qF2S0FL|@7T%wt+<JL$Hmx7BV?+7+qj^HCNijGXX=&Rlq4U5g0lDe!h`O=| zcme*@D96lZzAia}<8xA?t*za~FH+CknZkb!cqMX}{oUQEs8PxBY)ddgk~`(QARB1s zItn^H6yitw%d!V64kt5<poc?2tA2+!KKE8lohStTp=L%_$+>QeJWx#hP}5;$tY>&o zSeD7Pe~`u0X5wdTo^A&x`|gb23(J@XckkbqE3qIK*~m~Sa@g3obBu$wzu1F7S$3t? zq|6x<afSqa2^{xE>_r52zSR`LV)zzpVo2D`?0%=?(<u-55b{1Ndhc&Jj*i>Q3h{<Y z=dx=4&j3l0&bC|{4PJ_*4Q7C>0e+pWP2r9asODkvv{v~A$2){CdMcfdgI3AR!82&T zeQ(o_ivWC@YQoaeX3o$Y@V^K<m)?)L1MWYo*`?i*JT+=_Od@7xDylC8FgSz<m1>bq zK~NF}xrB{EOHh{6!A4hVV9QXx2@9$PX;i)3slcUHCpPj0ZO^#&)5MKi%L+Y-b-)ML za|c9~--F}dvva+RO!+zAzkde+-*f$5GcYlLO%Us?(93^j0qJT*-=om4-%Pl>H5uPf zYHJG|m&9j-!Z7_h4@1k)tCx$B_56FKF(8Rj664mbcv^o@OLOC;X`J`hDjMaRTN_7; z&L&_Oycol_yChu3eYW9qUr<)9#KE{J7Z+zAZYnvJh-(5i1_^H~%;Qz`^z6zCjj!~7 z>dp(^SMhA0Ztw|(r4QOTGzwptF9g1QDZ27g)Arsb|KFM8FUr2#Aa#l|R%W2^L;RJP z)9z8*P{DG8FTQ{Wa?_uZSu(c5VX`I>^y6C(80}6=Ss31QnT*R-sgKg{MbgSMMm}{( zFANHrXoOp){_p%7XE1K~jdiwqqc+aVv)+fGJ5arv-a$n1BLtYt&CT;w%Ev3y)H4YF zb^lx48hB<gW0soUpDdpxKJ0taD=KXP%pu@B`>K`wB_ssxw1Ipx?GIF-Y#|9yTG0A{ zihiypZ)Id;h}S8?zE~ud8B_dtp=&x}Mk_1=eHDlp2!f{t(9*rMH(Iu{0?H1w{3Kop zf@%s&Xa>hqCKvez!$eN&l^2UXE+Bfw<`(6A-Gs|7Wk&3x`Dj=mh=2i%(Bds_dtrg+ zXJ1-B6-Kx7dwMmF{<QFMLpO^(<Yf<q3{~}<cLHJZ4VVv--9%UA_HSYC;3`l3on)<( z`74Uq+{wUT2zL4TlX8!ej#z!nz)>L)$sr{@o}!4As!MqPe!6<a6r_}mY%$R{K{m|? z6nFEg+=rwf;J<?F4sVRPlBd00&h$A`n(BDr*s$&TP@&;AT!a(fZrdnfs&RO!k~=_1 z*Pp`MwzXrhASKKMk`K^UIAptG7R_pFgKKD5%J9s22&Yu-C;gYLHBeRi(#|ORUAA`H zn%ZM6I5Q?ARnB_B3u5AMz1{e4(z`$pLH8ZklNlv2)+Sp>z6@=`TAK&dguDp2QGED4 zTwu~?72{r*^LGuiK&LrAlfh%P{w|li!rX*enJbDiGIxm%!Lg1efQIDf=B@}CcpZ!1 zU25;((0wNs+ixwpQ_N(nRGhO421_enQ7ed9@C7vodV7nVxi~L)yxVD#)rAqEfsvNh z+Zag=Q5DWA3X!I)ckZ4>e9m)+PQa|c@l_c5w*I6zp>0bc2yZ1_Pb@X7=Y3XmRY@qm z>m3{<6z@@A0}_Tu<~6Es(n`UkiX*|rN#bER>f~YUoH22!GA~b6x|Giq8}6r1U&+h6 zuS&h7QOul~-ll%cELZi`eNYhMkV!GO=~3Wu?jYV_uvg+0V4s{^Caoa@u*@VwFg=&@ z01F~=`tYRWN8FE;l&_^>VXiOUzJ7hb&vvkD!IPAS=fhQ)Q|S-u$CytGT20rq3?GBP zQBGOMQwOD!H3B5w-KRW)$VZagfaWbU+v{z{9fJKEBkS(1&XAz9HM5uNyiNnT)@2Qu z+$;Pp+-06GSRYqX`%`2pSNzV@CWIcW;iKJ!cc1C&uL%8nHE<7LAw$*yd5ert;$Wqu z4eh~>AL)sCoVOB>>GEBvWcF95jZpQy*c`tt=h_jMW7E@HC(RZf$ufhbh`OxD{o3)j zwVCUIGdIYsOYg@I-(e<b%ZAKhesmsV9w@jC@W=a^1)~=iH@A-|zAZMaiqg_3U?My> z-c;H1S4Xx4-X&mXWVATC*$=)(b`B1y5iO>~@^U9RIc8U))Gs|%P|}-oX|}r+juD-B z7_T-@VbvAwDRR+ZSu<O_g<q<7nRQdOdgQMN7$iL$gSOs3YR&xIT&}jFL4s>wV89=# z3DgD}n?mMXAMwD;$NSd{Y}e=P7Q1nq(~Zy(U3zbP2sxGYn4cG5i}>eTCg;2UNw|6` zkp{QiF))XeGl!#z4?$lz3j}qZSOhLSck@n9Z^V}wbVLbrBvlU~u*5(`MpjE_a>#87 zDmML_5(mUFJ<Sq^@6$gDThHiy4g*-B=Zq%9%_FsM+3h1gxY;z&F;CqNq50>gT6vdt z{U7y=ip`(JuwQn8*W%#9XpucUvE%AQL*x3=-UMTkp2cQGM|Y}S;^XxAJ#+9?7FdH? zTUo!tGRCu&M3hq%{nk(}#1r)5Sv42Xbpa`Ce$bfH+Io^rc>6X;&J70gX`V#v|3$Hp zAq#8;)H8PX##d|vKmtPCu<p5_D9`a&oE<2{Gunfvus$gOxiv{VT*|q~B2fftwza^e zrV6z@G#fpU7n3IP5YQP7!FxLS7%1nJjA}khs)Ljiii~j40DNziAS&IOpP9Ky#O1xJ zvA%fdlsAkQJ6L!g?DX2$xK7~f=?ly-ekht_7JGKuJxd!<GhEQJPBs?n%o+B`QDfr| zbsIhFk^2z8hi|7E2GaP$T?0Vi1lK}f)-sqr@>lwghozNMZyut0hMOl>p0;Vtrn0;X z>O+iQ7@|sgh~8t3<2YFzt)i|@JUVzEEE0)(y}feCB2=msQAVzqrDoVuSTG?2&2vKq z#$+mH)Z|pm%--~^Rv0GlBTya1z4u=0z6AFOgykO(D}51JXGNAQ_KF_F`Toum_OFL@ zmgYy!QB!Go=@N@s<w%Z#!8`2{+_p<QN~j%IGX|tzJZQjXM)#&%YjDVV+1koVMpi~m zR~&JF2PzY4$ol_HEqNAFZ@x0b!p<IA(=#QoeeD*pLaZBydukX<Dihj+fc`8s?svcR z!VsRR%}D1mS{x@af4;pb@)pA9dM|2Wz11bl=-#cKGcsC)1!x+;huVvctqd{|vb07I z?-`o_kb}*9D*wlicSR;@gU|NQ@!d4IdJt=YMQ@Rje#6P}q+G0NVC+H(#4NwZ*Mr~T zpZsJvpp$e0X$cANb4dmun}KteV5q`_sjuZvfvuw5ZnA{fbk9`C`d<xk|5Wj2z3HWq zu2VDnA$W^0Q$24Dp2ZMOh-PZAuD{t&%<V{tczm9D<q&Pn1^P9U&BzsC5MdhM@PGiU zN9TxMmuyn|H-CSo=aA#c@|)kD7kinN3Xu*S9i8TurY?T;*?fn{m9o^-REo!sjfP22 zzK@q!ssU#k`lJM`tqWY79mZWZzELkI1VjXk436d4no<TMoe#-+-0>n`S=}xnqGt#$ zvh}-GweJ70^iqQ3Ung0QAPsOsjdbhyP_@`DG}yn^B_1^b4!A5~AwqCDv1S?!Hr;>+ zuCgpW$&yW&$_xzD&e5be*F>^M$I&Py#l#XE%HNXpl|bnOjeP2_lPh3=N99>fbF{h& zuU+$yith~hqnB7%<kq$O)3jMpR@c<1niaZhYv~9I3FW=PR=RI&jessT;EY<Z$m-N( z-d#QXn>~FURl)0N2o=1Xx}|R>mzRU1qSVW5=v+)mt4qFeImsg0R^}EucgC|^WBcN1 zLmL~D!HYsoOY5b2JEIDaA)VikHYUj;jdJ5kPdk;ruKdD+!8H@a@seq1gAz39zMx8G z6EW8|_=(u;7FJ3y0M!%4*${Y`2mZ7DkrIsRM~~(^qVBqCz*6qvOPJfhkaGus#Tl&X z>bbcV&*Lf^1-iR@FlgrcGgPis4Z++%5{mi$ub0odCid>^tQe`=*hnbYNSK(=Uq&ld z%}n>s7pwOB;dZ_ezW^vY^tv5}H`vrsGOy$nWMVE-Q&V3>2T`N+M^jZ)Q?rD4OJ{ma z{j3FQ2Yns^Wcc<yR3JqyFD|S+;>l(AP8RP=r;ROLW<WoinSb5pxip{%-?|YDgF(}P zA%EHKo4fh<sV>^vv-5MW4itYn(a=Ig6c4=2@u`H2u<+?_SzoQZwwl9Wext<R9(7xX z!dRFO<Zx@<KX4(y?VGBkI5)Ao(!y-ZKP>7I8JQ1~I5GYq10}S?2SruGk6btjgg*rM zIec;MahC7st!rz~|A|+U&opkqQ<!G$W&qx5h0!0RsmddvAd*zP7SiJ2i>usns0r~z zmOGJ>3yiuq6@!}H_K1;{Pf#yg@ZZz<{>vzN!g0ja5G=qDnc80&J%bk3*48I;ewIKM z-r2D_pW1qUoIoBQ9qk&f^PD0i!tw9iDKR~(rVw8x=CyC;*+rguB(^9#t?~z49uc=q z#G%CL5!MM2b}i~xd|?hSh5Z6^|L`BV-QR1k4VbzjUUS(sZUlEkQ_<48ZtXg6&ERiy z+N1c;aipk?#sywzQe1CoIW|rUqC0TSYXVdwjJ(RrPe6<|87amkzSC8f<)ztA58*%f z-BTu<_mR$+wdQ8oz%%xaoPiuARIgQ6SKp&oPnE8480V?*@$o@tpyJ}10&bm)3lg5p zE2|@-IS*a$v2=jZi_<D+yv&r>=S_xkA2eoy#C?;1F~a21ztGLz1T3lR1B+c{MLnTR z^G?prz|jx-@xubf8&KfbiEg#Nre~~Ohx+tC_g^T6jw^yU8P=XIP}N85Cxlg^3N=Wp ziHV8Ob1{;sM)=^tD$Kv1oAiE(QqHwvKb6ZVGyyOhjEVcx)jHZI$10A~6tXJpxA!2I z1_LJOd-MDH6<4{rKkE(Wpe^7jXM59hb#&%ps%s&VRo7~{T=+mXNuvMvZ(>HR&Sh40 zXmX3K?~4Bn!}J2k{^yI-Q`Gn7_Ken!I^R>fYqdTX5*ay)$Z8qPn;$MThM~rAOUgR$ z*$8w{!g=KwGle`3W3l|~?cEBMRROxxidhN;%DV>qS8p*hGA29~cQ+;%NQ5mTBigQo zpPD1rNRezh!UJz^4!TFJELRLnOa!s0ch(0g-KSh&Qvz%6!u5fYw@B6MM7Tx0RuMH^ zUsHpdDNg$OSlQVYu;sC_pKa$C7NV-~ZUK<2U>&Ry!Tmpf2U(QBnNcQ^4yzSMTgT3y zDYCjyl091HC<~xvwM2UiyaN3mPkMp##0M4rW5oD9^2NbSruFd(7SlB&V10eOhB?S- z<%K*^(#w~utc0heQ4IxDD#^;pIUTQ|2VaT!XBIG8<k6QZZJ_I6ocg*7`VRHBCcb?G zKX7O6fJcKLu>lN^59|vKhd)1%l9f-yi3$s&G1v{w#8ex&_=dMCNt`e*C9*d|mXnn9 zQnc`SgcE`^Rb?nH_wuk~+Y;_Q`Ur7JNnWdkFP+zc+@ne_lr11C%0w&r%T@?H&QVI8 zw*;juWGn!3Xxk>Mq$IpSO)P0=5mZ<Rtd?)z9@Yg;6~Tj~vr5Tzsz?PTLZKAps+5?C z35Q)m5M8!ZlGWAA6vW}INs6g*G#M)@h8@{|9+aE3^PFtWVz^?$?2+kd=RM_bm6hsx zdiT#Jp?(FV00x&RQuAU}3I@p;Ss;MHJmACwZV@RiFm!K3ogy#30%19cCN%7K+8f*6 z1#{E#@&%1ouNHzbhG8$X2t|wB`T6-fn}@$_!gDg-RO$E-pa^V}5KV&d1bA@3$RD=i z1h<eQz?KmdTOYUk5Ej9*27@kHw_~lyWL&4}5fbh#P=pCUV9#j8D{xCoM%#Bcx<@aK zwSA8}1H_AdNanS|bt@9^l5(8u&QA9}A;$ZG&OrC%iNlW7bLPyE1SPNSc?M#R;{M)W zpQ3VMyX%R1PLm1xLffU|zMY-D{h;llLPuea>x&76BA=7jM&l*ZK>B<Dg9tXgWG_+P zhD=O8(b)HuCaVTvl5nK~*}lki-Q?D-TbtWBDG-Hz^ytwlht*iNd0r<RuB&UDMRe-9 z<-xMi9J@woLjz)=TwhUw-uw0H|G<E#w7JoM<>gI%*yt1*s>BoRbaQ7H;>2jf+gn@U zaMsd-KJVs2DR~~hCQW~C!|IwkcJ^`r<w3iV6kdOSzpm$4kYuF`uxRy|tM_WQpV-J} zq^Hkd9BtzW(x#`S)$W-yM0T(8!&@Ib=sYe?%_TiE?fto5)Bh5=HZ!A@LZx0DdDjMr z&}b@R=#?+j9$&tES@4O&jX}8_`Vo4aD0kd~R3`|@o<EkPXi(-z;F{W(l$__OUhzOB zof6!o&#$}#vj1Lu-r$B+b<6A)_zpz8;5lW44Ic@fQy-iC(!H$|Y%nh;3OM@hJwo08 zHxwZ+1`d|)L2ydEaFo1yu5BX~KyUHjqr@6dRlmxmPEUi<L^t|T-ztK>HOO8LbBL>z zZyW@5F#Qn85C0I)QP0;v9kc?5&966|s$j*yLYw+W%ZA6YMcu3gGi_=^J^9lO?swBu z1uVVnM40EFpa_*%+p@@|Y4)7_{%mo9N%m5Ha1E)ZTwov^HI()Vt?@id`xsI-{rx?j z$6+DgL&@uAn;T!XG{1s?(le>|4b$*6*V3KefG3oN-Dd~o<O0-7KP)~YP{kAy<>zMM z{y3#CV!$!mtLik_S_QJYT2tq)cSO3_--<Y@PlApd&0g>W>eRVFh4(+)XMq~wT=)j7 zDb&9g?!Iq%QR4OW^ltRG*TvjVxER@(Rc9W<S?O}|B}~NKe83AJWk%H|KJ$2;_o(}N zD+BCAMZ)<n3kx?r5-{qOR5CG8)_eWev+0C{qia`mb#?E#(9j%h2N!3ZFOSx*RacZt zM@3bb%@VHf^Q{Kl>o*xP-}yCI<9}kgJmy^@O2V_JT4X;T6zNF)OE%sw>ue?zBXhje zcIIHvUi7!r6i%2yTm33@`nLL+9i0S9x?CJ*xuK>LQDGK%wT6_Ggxj9pBBD5JbIlQx ziC6B$+l>^<U@vG>)hb-)$Tr%Y^N{4e_e7;3Gd4!ibj*1@2yb@QaDAC|{d}Fqd%d(d zAkANw-g#rQppcp2q&Mnv0})5jw$r9yGF(E5X{^Bv7O>b%@K_!lF&!xxFL7R0JNES^ z;r>;VewRhP%zS=hGp~ojm&Tw(PA!QbFD2!>Te*|;w3F}QkErh&@3cU^Iq<RK{`Mnm zZM!MDWs-`9>OTGw6Po<$!oq!Q&CBqcAw%Sp=4a;=q!h8kjQeO5c4{#pt02uj^5RXf z4y+oHlkw}6yl1u~JY5QnO-<<Hue^RIzm`@|5S*E+A&W~$C@$p~Iw?rx#F9~^7EIUe zctcK!c=CqXD+%f^LYXyRW)R5Jh7xQGEsVq#OdQ}$6%;UInBu&VE+d^29l1ur%VCpL zFQ^ctBUb(B`VF7X{vK&Lxd}hv<qh^duMbg~6HywdbLFq^Vcd>z$^Hli_(otxQk>kD za19yhwO!jSmt$#B+4vt{?^K=cRS3~EH{<Z1Uj7)yV)BA6ib1_2qNqI0`5GG9;gPlB zX5O?{zxwARhX58sg(4tdy(Rp}U*j($1NSoR$TF+QE$5y2kXtHT<>SuYlCQYTkKDv@ zTVf_USBZ}yl_WMT6~=3^1x#*v#f)JQMI4RE@4=a)Mz5<f;kmQJE-Ks8?HkFFm6^HM z#QM-rLryNh`{qu{>`0wq6Lm@h22k(f%G;b>wRUv<oP}t@36>WP@<b7{GIx!os@e^+ zY$@AS^<G!CPwO%~FD`-Wxc$wM$ECEO&-K_H!H+cVh=_RRv%6JCRxJqLT8gT&Qqwb+ zt3eE7=H!@vsE(!VP&XJFP*4`}{5^R{%P{`_=ZWD>`e2Hg^%wN}XZ?=?Y77<9_{su4 z>*tI1n-rL8A`+4tNhUWoneyj!0>vA|L$Qx%X^k(f-Yy;L>P=_U`C&M$&;}+cd#<SE z6I^5E=kfA128zk4$zYf!ryy@>YL+o`-8(55_N~AV#n)|rlen5VYB!J6EWKmCu|WNK z^6_Je8*BK=9B>!fpcE0209STw(c7ycXt?_peU;)~H9i5uYut9ZZ})JribxK8ek<VR zCHcm83RBJI`2;APo_wS_>dE#k#2XIz{@s3i?IW_n5vQOt=36IA%bc`MVz%A!T0F9% z%yiru!u0C=@in!GC?CS!_#NS{k}Q8RAE%9lMY!B-3QQ$&r*?L{t!eS3G+(?htG#Ny z+?TnzSJ5FvQYB!C=u)n5T6NxNq*fLtm|W$I7Eik;Ec}($j@N00UF(Hus+p|XS>JL| z{tl+G$`RTXcI$OgW(wCX(tARNV;w2s`qkQ4qplmf7%?rBBEw$u;)o#rhW6}8<RPb& zS-X|}&nmv+vxSsQUp&`w^elb}iCGbfHiF@Lm#@Rc){4`gcNZ$F{dE~s23hP6=Ztp^ z<QD`#9H^OZ`#Nd$>Xv%(?c?o{u$LG#8I?YVJALGHNApt-7X4O46vMr?P{Cu3-Ot8u zj_0PH+hFhNw;Z?Bdt0T>rx-0)nW3XeKEP*hwOu%hEr^wP(qP)!+B%e77uh_|M~1=3 z+==LwxV&VLy3TVT)tQj(GG9GStj1a4yl?&@Ix3*Is-6<=tX*t!k9ADZX6EK>^oIHL z6p$aPAvYPEKGKL|wS7Pk{j+cw0B<}6{yO3WD?_fm=|8?g^eltm`MdfV2IZNl)YnR? z#U~ws%SDTBl%$NQFHeWMx}F6j4C))F(*Z`q?izaB@rB^bG1UnUfmVa;O=WR;me>jZ zUvfiLM;*rKYktv{X8ERPL&wfHYz6G><REN(l@)7G1H5~ETl(*Rhsqq=uA-ii2jQ?p zgmk~_&gL$H<Jm1lQc@k|V|w)*jiZ?^zR0d|*OUDDpE+H%SHr?Xw+O3#Ija@v>kj{J zqZap6`sBTH=Etc0?x@JV=QClE-D@Se!koecjL(p+&oYTLUhcySlaf#<9%m=-b+9(b zB|kg!rLM(6d^c7bE-gSdj753~$&X<W@#g7{zq%CqEt`Q9?amXbZiVK$GzAlL>fZ)x z7*x0d8NU_Mx(&K$6cnUmJW1WGsWUS$=-*olNnN~i{nLu0PLq-D9FpSlGp)MT>y;a) zTwL1`p%I~$79qTq^O3d^l|wnpAN^QI9p)=Ah>O!c29kxFSX%mJ9U;6`qFE1h8P$=E z@sb9Q4iow4i^}w|3fjvzwhT#J$``S!!b3wsI;#!Ddw$RE&hGu1<R?+z`%B4QK-xUT zd*Ah-N!P=UN^3)1A_8gEl0Jvk?CQ`nY3!`UaX<sBem0$F4GY(gt2Z0y-f$_VN+8wD zkY~G#k(3zS#=DsF^KVSB+-sT+mJF8_GVGCltZKvMLq)Cy+gbZ<!DcJPL&LqCRfs+V zrPGcAM$ad<LQ!l+wXVFLCkq9v<A++ZErSGii@!_HOOt(eE}RwhYe-{JXPp~VP}E-h zIVGfE=Uh2`6{~o`%@X_WR0XlAh0Hss`@JTqZ)xd>?j=FYovLf%>#brsj4a?{G+HpX zKw>Ky_spI4_=J)Cr1-ImL44EzaPygmE%R7IMR!6ucwINQWCi_tF(;+KtNgp4Q|l$N ze<t9GMXV&ErD9>SL3u@fnJgX_Lisgcjwh#WSV#6J_>~VFsAoBC@0FKLp1!<%EY5B# z6HaS7T&X!WHS5QHG7-d38L)Z4Q?Z@MM#f9v+<hIN@vNl+OGnpQ<+OFE@gsMsu4KiD z;?N^P&bfsC-xZvCFAm%&btQ=2C@7dOuQ+A|WfSU180Ku<sP%QVJ8X`G%vsq<T$4X? z-?waC@{3>a?+E+8*`Y_A8V8%K;|_`nI;<W&EG8=p`Sn@D&1&ov2ybHR<`C(OXwoX{ z<u-9P<B{%$s1v&$o#=j6hu-Uc{j?s^>XUx9?ZOfgOZpvMm^|+(dRTi#`nis$Jfe-3 z`Vsr1uHhv1TFv(Uq}L{;8tvN&O*5i*hf`KpRV-mM{(5g9mAr+RS99usFe|cB>k!-g zdAJkf!?WqOtl^%q?{LKQswd1!S**ThF7Ha%Mscff()9lB3l3JqTo^|PC<y*FXQrEg zXv*lAA1_IZF&$UWnD4d{yHxa6GWMpx{M^nLE>g{otyk)jWrHJY>{`ohP1N63GPn_r z+kL62hHlkw9p5}Z^|f-Mn%SqLqw6p&uSq&dVtg7sNJnOIQzdI~3bu=8JJe6;C51&6 zb{x(1uqMZ>g_KacH7CUNeX3{js3DWog-O)Rmg@bvHwov(`DPCN;kgYG?KWzO`u@^& z)Clgy#ZR2@Pt1iHlyT|*%a0vT%Dz_3gabmPwzV=yfQeCax-n@C^s@K#WdC{}rDzIx z`9JKy|AF`X-+t7m25jCzCx|(ut2`S2HSU9I-_KRtZ%XuwgpP?{Z&>VRGFHLidB2Wd zbDFJ;6l|+eOdT6oF+ff@pQWmv80;pwkzub{)I43Pj}*7%Jt>X-ooEQh<sj<O2o~+f zB=P%EJH1DxNkSrqmyS~}eY7zCtdrKqwkv64PjssqPcqA92@MySG@Ef;{=leZ73yS` zg8I!JFdZJ)Z%W$Qb5(9+yGmP6<X!S(y{(>?&3Mx6*Vf9NW2)NIj5dp;b1biXkzD8H zn%~p&?kx{acO}i9v-HAlp)%_B-=*n$Jh_)flBmYv`X-QnJ;>-sS=#UZNL!0$*XQhH z1%#aihCxBEzGJl&Rcw9T?lQD!xF!6p;aIIe6B)=}ltELrw$e&Wi4ap$RUMDnUo{z3 zoe14tCXPR<D;V&+va{piDYWyoMeG@GMb26~Ms5ebKdE1bs>0F9@$Oc!))ATF{948i z@1aR#3%1jQdn&c2>^38vrs<&bnKpO*P48gb%-64tI-d5Ieat<X%BUzsgw5o+31lfy z*5S{77xAD^ql?mE#b+sTY$}htXk%#OX<z$%KTdzIx<moRyvyM)CNVh-4T?Q9PwVej za~AwO66ikf63sA4e7JZLoK{J{Td_Momiy%L_T2@N(SC+5o$H_Z?v9WkGorg<P7fD7 zrKomR+75HeGa6a#+sF3T7Q=(gIz1>&o!3fTWaehNnsS}?l4n}*aD<Dq2Bpr9bla`- z9QT(soR2Z~*NJJJEuqzMFo^aZ9yhe;c%7C{cF8Pm4OX=V%^C&=s+Z-@q!2n7_{bX0 zsg9hU$jWdbJN1iJgDyJa$G$moXiIk4+*j{bQ}{NnU8`^pb@|;^5esC$l;EJq(jGKe z+-BU7J(J*Sd9*X9(?2`iL)vmLB8)~KIX7q4bM500`E-xB&$j+=WAg{W_b5Bms`}KF zNM8A}W}bETy~Ac|Z)BVP_4upNVCQmpB;!wp$O@P6<J?Vsnbq8ylm_yX*_xHTJt+kj zQ^(p_>~1n!gt%C+xt0ALB?(dHW@HOrL|rFYo2u%AsHgr>S`Nl}mTN;BN)5lTe`K<4 z`~^q<7dqLRhkWwpcnKw<U0rPxE}TBXCGbKe9-_O;yL_EUDmzpPYCbxBgS#47;Cizx zd5EFpWX#5PCR5AG<a1)(XLaO&eOvck$5MN{=wfxH$!HO;;J&MZJA=F_^;*3W_z^J$ znx@lYM<&<y5)^IhdT@Ole{>n`dkcQ7G8a5<%`2TvP*JE*IsS<uf9m)e5fR35YBdBm zrH4V+_sJf1>99Hf)t$>~@Z7|Dd^hdm=Zc=Y;&pu=8gq$zo0l)yD;>v=*i9^_Eq+Zh z=f8{a9({9C)_hWtr}FuDg=Mx1DLk|)o10%h5w$N<@TBpAz5Xil-u?k!meW)S7e(D$ zJxwe!YjwF<l93)frEkOKVxn5HEQ73r(T(&?gN<#pA`B0rDfqVt;7Gmul)@-ff2b*| zE#)+_`Bm8b+UdPl>pc4|6)l9s^)3tJeH8JN3CK;lD9%L>YQ{p4glOhk_}0<(?-f?Q zk7vD2(96~`l4V%Lt%PSUCAc3w___#T&g?wPSzyR()mRgws^UZYdY)&YnJJVyiAjhe z!-<kBy5ZjS(QVb)1CqxSLqoSVF-QiAHUbS?r_~!Vho4;a|84-|hcD!UBYxf_Si+4G zECnHyWc1v0#)>KHu4`1^wEbVIu&3!7@U{4-jh}LD*Oa(VpXGBtYu97Euh80R%;QY{ zuDxzlm!3|kqB65PcKjK+<Eeseq$mmN<H@b)B+2r;hehV^PRFwvy9f}eZ`kPNiHQao zT>hWtt~{E}b=|kMx6snm){?YD&1IX%VjEg>6&<LdVs3;Osx3h@x>0RWilU|zsi73D zd92dXhMI{Y2`NDvf*4|UzwEQtUHATT?>Xn5v)27DYrXm2>G?g+@Ao`;^SuMZ*@bp5 zFb=&1s~eW}ExE<oO8Eh#<R2Rw5oi1cY<A?WpYt{`=zxnuhg<gq#{^Q?;TNKEKHHxc zo=*>J8OrhMBf6KBuN;jxWcn`h-h6a%9CxX;PvkT*fc0Ho#kaL;SW~T)7FXXQ>P>%7 z24}*n@SoCC-K{KqLzB;bTvgee)alL_j@*u!nmy9jzgthN0I2Yay%R3^xvPqD^Qdt& zX7oOq?T@$DL`nEhHtb;f&(q%jN<se<$>L+qL3lXfqwE`1@0lf=x0@TD<YE=Sh&Oqu zp9@fFu3_?JDRC<7RJ*S19m>2kn@6?937*JTd8IF=DM3jrm^hofbC}z^Hkjv-z$NX_ z)r|N~gTHuwKDwNaNJ$D#<OF)Ca?q>fvK=L|=?iHZRA!h=@Ko`Bd<0Mnce;>jr{xh< z;cL??+iF02wOGc?`nE)dL^dRl{c!5CFVwAHwiLylXZ5wKwkQ=Js(b!8-mu>E)<JGl zhr4>#(YS6X8UP(q%)7ec6$zniE~iX_>6Xj#%ZCbf`JFqNJTb2QsK>|B+JXr5lHfN| zbNpqWbW|3i${}V#oDhwK2wBy|6#p7^q2;Op*krcPULFzGAy*d;2J9zvOd>jb|G}il zvzrcSZkAO9q>oX}=U>Db@AyJ>G@Qra;OK`I6!KJ3LLyHm`}<^xsIOEbO*2lYTF)KV z+#H`oU=I;us&z9rD0n6|)miiO#a(X~00aw<cl~Tu|8$<SF6b1X!YpDqGJEBq>~rp) z6ACX&kF_3)#w@H@0Y5eveC7MUDJ9moWAknobYFp@Dus?d1a|rXKBvu9DJyya887!j z?bAtM_`!MS3Ps3K!Wkl>%3cmp+94L;0?^?UQko-OFXF=z_)FR7oaSi`jZ#}5XT$iv zHqHLoh2Xl+{9aXsMN(}0ey+{be#C>6`t+IbpfJXM>U?KRw!5~Izj<&85I_ygP8JkM zjcPe1o1b?7laB@AGON)chi>??Sr;^6cMX^Q;=^;+yz+NgnXA(L%4TI_fj7{ElvEWj zYon)l4xSJO@JJ27Z-;ASN%kT}fX4n<&*UEWB+u{HFjvJ$_}|_ycwF&t2AsnHG&qzj znek!)CfVLXpLsJN!gagG6j-{IxylyD?)|Ld6FFCtSh$h)nq@Y+`K+W$bhQB=CCK1m zJdSKp`k>cL#r!-l9p3yZdONioR3;F|4jab_k1+<)B>csCQ)5c_*FeBz^Un#M04|OG z4f^&Ub#&Ipp94WPr-BYUm{mhT-~9Bo_1X{`$br|zqaydK5X7+zM9M~2QSWfbv`iHL zaoQ6sylHMM)*21Gr&IYyEccJ`x)p*#U;0Bz95%b8V_fhdrH>U>6mOYCGj%T2n*KC{ zBZs5|xhm3x_t8LC9jb0&y({t~|MPKJ(8pfQx_WJF*9WLhaO#$heH)E;pH&*;dQPId zB4Rc?!Za!vxxap4&q72;;lO*_Ti<N(eL-^OhqM;h;?42u2~|Mv3Rj5FarEui=~eE2 zYaG9Ci)F(jzFq{&|43S$*XCfaqr{=xVsw%$t%W^+4l`6*JA5C<E9;z&e0eG)@&c6N ze;X5Jxa!Buoj8-+#H}%H(4;P-u=|GMkmlvzg=!I%*%Fr2YlZ!M>EU<RDWV(J7b;zZ zQ)g!RD4t_=n}BGJWuOX0Oe)UvlEv<<nl)}@_sMsB4lZ8e`XnQ*&@}wdXEq@|k+1D) zJCOacB^*q82uI%fO>#@6TxbSW-2!#QC4GCQ12pa@kV1Sn3o7a%quv>_eU6)omFPK- zpXjQi6Mc)D+%Il#xKEB)#O|!W-R2O58o8Vwai$N7gyeM<0q1^AdW!c~3|FgK&#hTS z6o(kStp9p)b?6M8(R_9%TUiFs94Qg4sJ@RJS*>^63J#J(jX4&G3ny1&{20bV3sHB= zdhF`AsmZL`CdqkCf3)JJrIi5~{_gEJoLe~>L~Br_jF)0c%sH8J<z+$?9Y#T7PFx`^ z`x#_(ZLLU?*nRv>gYweTo^n7rcgsZoQ978H2!*tUWRg9HiGY&zHXe(1d&2v^A9rUm z7KOpS#Zw7rx)UyU_u6&f&ary^Rp-6t^pZ|q^Lt^D0TEQkP<WqcXsrg=h8~rYI(UcW z6HJ${{dQ0L7a$g%JWEQHfO@12rpl($0PDVL_sUKZ?M`fkqdVI3YwBjYuWSRDnmy=* zK?zv;-O=?F73oB)G+LFZq)TnC8E$a)cg6cH2%FYTjN%W4?t`%z(%X>{F_NHVPs6@Q z!L`1sUWODpBG4sofw16$=w{Y*U#fsRGKYC}Z#i@>n65pY+#J;t-WA9S#{73#?Y7Rp z)7cYR%LLDPTKSV&epR%KXq*slB1=!)p|$51_JN!y7aX<4(FRr_p9S7u+nchmwJ4mJ zAQ@$WiaHoMdKl|C`F-RU(Vlf6PFy)c#YPuMXUYCt^C^0ND-k{ZDIUNM)72#T#}FKM zx(J86*T2RmWB0^^n^tB_xu3c(`$z#jfgO_=8V951%GIs6-I$;FwKLik6q%Hb7+|@4 z4LW}AjYe;q>*Yp)SI0>Q(Kmm1KQVb7?C`h>680)1u5|A=2B1fc56S~WBJV`5OsJ}k zhkyU>tyROA>h$y9l5oQ$)fLP3&-yG1XA3l;&)o!UazzlB>8Tr=AlmrR-#@yvksA9@ z+DZ)`vkuU(x3n(Bh=pc^_Y+<6AI;WI6>pXy;TWpk>KlKpA8EErM7`yUwg)hxOi`hg zehZo2xlqOx&@%C7O0@GBRdhLa`!*D9t%?pKXT>AD1WoX5B3w&@hIV6iZ%W}n@>^z| z2Bx1vug-i8EbDCbs(Ag(nlpj!odO1_MYYkvwOiZ5LfNzbWu6kJY(bR$cJ;-zc(Wbn zwdv|Fnu>;^eqI@hs*=08c@7$V&e!+pFJF=MBrQ-pPq^p!4juY+iG7a%Jyg-Qj@4xn zrE$ym(oBAAspjxxbN<@kinodwWwtA+Owe`<#HuzHn9)!ix<(&-8l!;ytSaAjE>u`% zA?wETUieKde>3c=V2V)0Oiku3)rBPRFSvsb?`ryo+88x@=Uvi$de9X;@;*QiGd=dc z1?@Sk`HRcmu+|TTu2;fkn5vSq>{c`-@OR>f5w`IsxiQP`xp5k3Zag?`TdbR6fV?to z6VzHx-tcq)RYXuZb^wSig29<6>Gi}q2cE(W#VRqr@Yye~QkRCkpQcAP%r$ha=$l=x z4%(}fv$DRu`6eeRLtf>wUcPmBv;3}AN}qs_Q=2wAr1}r0L)!<^^6QJ{mac6Uwu>!} zAW+eeJP_E0)FFZTB>&L-%lm}Lc#)SnQncB-m12pC4P96w97EYDX`^v(EV;oo#5I|l z9s1@?)PcdnT13gA#k&d&y}RCopX))X$M+Is#s*&pDUjWL@NWezYr1d5z**~4PAG4` zsSOuTbojfDhIE>fcEDux#IYH}2YmOZ$9IzFMK8swmcP%NvrJ6y3Hdgu|Jl)5@I}O} z1mbz_{r14u{7Z6>zX^U+@7K*SmyI<-EvI4LnFw6y&UM;ii!0_oSHW|<=%!)%e53Qy zy}7Zf8c5P%W{xDKTH<<Qb(B>xP&&cto@`id=suHtcr$OS*08~<A)X$fu*}nwh{AGj z9A9|N1&(6%Rw9+fiVi<ar7o3dv?}c;{N{2aR;$t?bv^8<MWT~^p$FhKhGSwtbw=;p zU*#~R4DFpEc_avsxXNI*j=)2xFv-F$00M{pwY9ImR~taojR3tj-^ebLv9<kgR;Tj~ z>P<U5)wXvJv-wpx*;56|%_=^@xSF(TqR-A!`l04hhT^>N4k1=~Tr&&uH<>d!S2T|Q z^cavyS$&>roJZJII|J!^aLugvYK$5?hv;D@85cL!Is<ChK&J#H3}g~1f29}YDc4Q# z14!j88eSxEw1_>GQv`{MQE7q%73h)uaI{x9SJVv$cqzLvHMYbt<?1m({t*~k_w9hl z@&ct}Hug@v_3T0U&GGjoX&Q0n?oX&2^MSS*NJ7&Uf5W_IBqCAE_XaA=u@Vq#w|z^? zgEqtUpd_`d9u*SIT*~MpyKZVE58?Uw^hlVJN<^oR@=ZBJ0}TTlcbKw2D>}0Z+TDLZ z>Z;^HWm=kC7cbG30@9JEUnbtIbTPut$~iF^oQe0sJ(YmJVNT6UK|PO4H(pTrlIxwu z!LewAd2@oH%%9O9S;vH>vP#z)2Tpvq-Z^sUfrsf#06r7ErX3-xUdzR@R}t#JhalVr zmU2E=?UpuSAAXkPk%(qr_TZlI?<<%7y^#6W6ledxjJA9LZ0o^+aEIhH@PU&Z`Z*3= Z-%?Rb@&5^2<Z<Ybxv`Z|`9;^r{{Z)3U&;Ug literal 0 HcmV?d00001 diff --git a/docs/img/ux13/settings-installer-nl.png b/docs/img/ux13/settings-installer-nl.png new file mode 100644 index 0000000000000000000000000000000000000000..74dd7c9dcdddc7aaa8d6670f219859b23ec95d68 GIT binary patch literal 182800 zcmb??Wmr^Q|E`aSD5+A?D$*t0pdcMXBQ4#Gbc29^lG0rgLr8abcgN5jLk|oC44ln# z&U-$b59j)y__X)MHG8r4T5I3GweI+(q$q`hNs9UC(IXrg>CY;U9--|%dW3=Y>@n~c zS)8!7M~_}SlKK2e%`FwSgzklJPK9wIr{d}g&a%j|uy=J0I{4bw^Ml{`@p(A=;?mL* zgGv?w0|DdIQge9o{pOctW{q5G=&_ur7i+>`zheU2_1@EAnt_?o5NQ6<qt)TO&VO&( z$ne@J9_~J3y{SWcxUu->iR;7l5zF^g+=pu>`isSX9&V~0`3pW=zY~4@hVgJS_W0S+ z!}XE&qyI`H2Z<lM2swmaqS&@WlJ?g=7*R?MZH2gnDFrhb{oBl)|Ej+EXCuV|CC&HS z?A$bFe2>|KUpiQ}ev=Rrr_2~Eu)8wnv0Zl98PRh|>|Aqm_o%X5%5%-o7ZA8;C}q>F ztGjP&A5P&pacd&<En#M4)@{0y%Oe^X7+6lKT}2^?Yfh~7FCY*9>yEn)dkVefr{=p4 z`3hE=A1nWmX#6Y`?yRf3%FoZQvDKagrOXr$3@{O~X;oYm(Wtv0f?L_{t@>vxf(crJ zBVTtnk^B%_TWWO0!aOUwAOM<dYkkUi<oum&f&qV@!#O<Ua7#=Ww{vz2v+zQUNv_EK zd^t)Owp@JR@4Ax0WiM7~Hq6!ffrdsR7;!KDPEb&gjW?kn$_I5lfhTx-*MWHb(9L{` zCy0etzxYi%X6M4V94V!~1c-2Ql-RMteLXyAQ=pt295vt-Br}H!NON|4zT7;LQm@hJ zSGae*(>!8)T$vo#{5nia*z>Z^aYs>1%*alkRoKbJMZX5F<5B#DS;PTuA^nXWr^*&; zHkRopDJdCNwJmIYnR=Yyjo4k=m^2@4x;eTH3ma<oL=@{Z2Bj~R8D@WclPKz&e%3JV z#j4lf1-m+}sBmDClLLVw3sfPA$;lO?6PU22S~d}p<-tMgvrU;ZwyBfY$5GNwhYR6t zZEb&He`kudaY#7&78ZhfhzST-z3u}_iG1DnCUQMLwO_i_1O#IrEf(NEtj7~cG0i0H zm!U~2GR0|~O_I?i=j+MammM7)EGe~GT3WSM)6r41u;=)6dd(iy-i<ty5YWXLJehMR z4U3p{VSauj?WQIYgeHcjC*YdQZ!CZU+t|qB^+r$(kJ#Qd9v>~1H`+GxPzbv4`J8R0 z)*ma~n&u#Hj+Pp0?a+NLkvlz-J$bZwT1i@2S%`Vf=CIJvU*YQY9!{hu%N>Yt?C_p& z3Qn`3e4Sc5g>;T^Z$?%TA9y0WJ==z4#A`z^`2NWMKH-pCC>MrUN$|bv-q|K1>I}w- z^d=EB-4Cm(;*wE)c2zZUFbmF{5;23*3;gq?Y_-|*(<khQB}Mj}5TX5&eNg~5TjIiC zM9K2ASM5TCv!9_~jTYh;z5XXSk`h=t#d?(k6BE%<@le$5?Xst<UvMynF!r-&&z?W8 zcRAE<_3?(*TDz{ceWFOm#TirOY7Zq=_Gl=jjLw#dL|?*caav1_tL7GlO+pZv?c%k^ zbDtcI>E@cvkK4s>$apOJ)RHpAPLBMM6-KwwGzQ_M!aS_35%Db!TZ~c|km(}L3WFkU zt`Bavo6iN4f*=H+r6j=f4TsryqKU#f6K{k)T_E^q4K-zE7mO~CL(V)Au$jrp>@~WV zFLy>W@GMr+AK=C9{7v0#h>|WSf!X4dkfM4(V^)?Sl&9G8;~RqH#N=hX=2rK?cy*@x z&2M}W5fOvF_u*0T%c`oA6O$9zIM|gH6-69S9Y4QieSKwic5IY1x6RladcH3_?W>>A zisBafuWEbB(cF<p%YuS>cXzJTxHyS+)X~x##>+vwpve+%!TBOCq1-pOhJ3acKc0ij z@ht14B9B_{u5~Oe83fHbbim~WX>;=nc{#ZpKz|>B-#-E7CS;$fZqmQ7i9V1GqVkXD z)lX%q2uccJS%=WXN%Ik#m6nb9N@*r0IWRaQHr7N6qqlH~M?~Z;ouDV`I{b{9;*i3m z^XTX(d1nj)7In!4XNXYwHvN3+;OO9Ub-L3Ab;ZQOBIQ2gW{-l~?VKZ#Nc8%8{+St# zirEF}!Q0QBs)8;@3(cOqf=$*txEL70Ih$&7a!kg?#`9fvB_&}wy}k|gNhCOY{3u^& zy{?_549Wlas=k#HDtmj&Wb$DB*>@g{X8|wP$+QbI!`lByWO$wR{{g0ze-1iXDT;z~ z23{2oNr6DMGL^K}nxz`NekFD^wKH0c+tbzxxmihGcirnle}|k8X1FXDe=@G9x#B(B z?UQCDef=TYE$ywRt^0hDbn#lj+kmGouorE(s#cJD1^F;XhYBoA%;6z@@3m@wgHQK5 zT3T4>UZktvPPy@b@g2jJW~qMns&%F`cV^fh0P*PPSHr_B7FWy7o-;E%oOvK~RlzKJ zwv^~Ujxv`0_f-1_aq$VE_t!=?gG4OvD5d%Yl72I3mI%AO7*W#-Xf2Z?#tf`|j3yOM zK3@??1vQ|7-J#7VU)7$0<mG=i^U(9<OhEqrEjA7P+Iv-N@iyr&;KO`ZEqKM=)iGwv z?P1Do{Z{YT)HL)-3CQI|5&r%W8GOijbA$JE5Nt}W@9Ae}@PWZW@0S<;X%0v#rV!Z> ziFM899lg{vG&FE;ckdwO_Rdxszh}Jn)g?@eh$x=Q>q>d^d?zq45Ce}gx%KNOMMWGi zT+vNPAB`%5?j>k2hvxk1#}5FUK17r8$tn_>4JX=P!uSW~AN#%G<1<-mz^Q<KwsMpG zbih;G=(2Y<%)6qDHO7FER+}o|?6G|7`fnAn4JhHb7kmEvmnuZjJa~9`_%`{*cBz8l z&Bux09H~)CGz{$50#2VhpW-k*A<UKxOBAwSKN9ww|0Nan+J1LzO(rJq_3PaXKA*pO zjV}KjLRF7e8k}!Dk6Ct?i=iWFP~W?)gwu^>MkY4!LREhT)7|cL5r!&OhR^jWU53w0 z!8tk=m`zU@W#Egngw>t$*Ym^GO7(>yib)*4caOE>i;4!R27L`qW^Jh+fU<VQ#~ZPP z@VGb<?|l07>2Y)8*SWE*2R!^<vqnG^_d!WD&`TU=R3Dpd(ThQlHCwEc%PeS7pG97j z+ze8xDr5dybx9>J!o<`xH#e8tZZXkn850zjps6IhJl@{kBYCD7(q(jdzB3vguAr-% z%Acxf{Y6PBF(U)?t3D+3=4t~J9){D3+9rz|Jwx6mCcf6uA-g<&$B=0xr1y`-=7CNz zBz9|Si-v{<$z}01vvl-fZCJbo;9&g4qN*c$r*GKwhJA7!>9;BKvrTdzkMvd4+Zy}^ zZ4T0D!*8WjVp$(JIXPS3+^4w`4Y>ow+1{Asp^1D3r#N@LcQJ!qM%x=vm*UXmIIQ<8 zCtPFdQ7fUc62b|erD#!D$70fir$@pb;~!UAyszO$-4Bm`WO-B9%KF%ElPq4+Bf6~R zTzjPZq=UOs55`PDw%Da~hWgr~G<19Lnv6_JB=qaUBbltLB^;%Cx{}?OO!KiTEb?yq zdHpP}M)VS16BU`J{ku`jT+Up-Tk!U!Ph*SiLX2ccjd#i{F|Ux>3_i5*NDagP=HP-O z+rQUT+nvO06Dzs`X;;$#MyT2!6UgB&N5-W6y8s_?zgRRNrr0~AIAn2}ZQYPX!;hD{ zD;%!{^D}x$ROhRm^+r0?UBHRIJXC^@a&Lim!AX0Mz`DP%xK8@*g&RCRZK(U#Su<@! zEs>ca7<AA3t!udZ-yh>YLCki~%epFx9$?{NQZ?P)YbwT6ATeW-NE|%5I7t?kQy+f! zND0sPdw~Ym{nk{&g}~h-RSlPsb+9ifN9JheKi*Rcs$agmroca5sUX1-^`xwJ9Brp+ zy-``}!t2O@3A;@#FT0F)xK1hH6H<7>Hs^C<)##*xS<@a1pjVj|iu-so5|Sm9nXg2Z zirjxMh_GT2d;bc3`T5ZT|95XbL^CL!6*)E2ll;(;eAPON&DP;KV%J_fgSq|LHMlq$ zT&c4Q(MhS|f$Mv#*2%@rhHv*|*)VuXH`QD*E#Gk6F`=Z17n~O~l^&md+PfdVoK6{Q z*BeP<zcx|rNL>11`faO7sZ2GIvc9tYYTxtu&cJi?l$0d(>%zsR+Zc1U?afX0hcQs^ zyjc%rBgrqojAB(afV=z4Lh1?JJ&)RH3ec0b{4uYy{3c({l0rQ_p>+kRcPFQl;BX4} zyY=Z23MkoY>FfD~xVVf)r^Ali1GbG<UQNQ{9hB+(z6{jV2g+TXvQTo|9SNr}NTZ2e ze?fuyh+d0_@CR<;Y-RC`=;(<`;?f_YA!F0i1*=%(utPQ0)3!DISZfG~1e{q4HncOd zGJ8ef)v6lo0-u`fBc=lx)R7U0aoZ4^_Y1pN*mcw7CX_7Jd0m*<%lt|RzFAtmIXh5Q z`ttgmBfW%-T-ZKOp(s8{Yo06En%B<U#EkpoGN(G%>-MU@(oRocZ1Lzx;QRNqjr9Ud ze<wD6n$sy7Jj1LvP}3Dl$t!z?k8dn6U+1>flUu}FpdhrU2ZzH|R3_)Pj^=$g?UXDO z?I`s^$0jG8U7Vg_K0m)a%U?Y&U1?$=_~~*e_!+td+qAH;`8<gE919|uZ8~l;f_tf- zegtQH3JiKCrjmVWoJS+EJRxz_+Q=Pa#CvxndakLdKBZj?ju*XD1$FJwf>du8l#`Z( zgv@rOIb$8Hb5F!GqY;1sXXoY3CHFdTd7%)W7ISlxaX@y%lgQ_z=HReDj&JVl?CeeE zrmAsydg)N6>Y06=6FUVQUIr*@PQj=B!B`e=*5}WcZtxJhGwxF-Zy_W4CbK)^F%YQh zA$Yn1`FAhoNYqU_O54zTVuHhNvBB~DvKjXfx=l=QTjj+qv9=e}JFen#Ec&Nxcl9?0 z;%-4cX?Lz}12TfQzhXV`qnw~+RIlz&*)!Rl*1P%=(@?YX<#a0xi#nGL7mqlb`ZR%> z<5>t@WN+@TW?`Y-f>6zpbL8#WSxDth>65^q@#GtB>k6wSA`eE^x0Wk@#!HP(uQ?qo zv@Gk3ia1lYA3m4D$L-A;Zsadj*$V426JbAq(KB3&)V`K!u)n$C_PpACj<dPB+1=H1 zaSV+qJPx=)%uJ8x-tNO-CMG7*Buis$A1}2T{V=L*73||_6M5XdR@2^KmU7`F3}&q! ztY$VWD&|YtndGmB{-d@@$?lYy07(gGw!Ie-&et7|0LyY-oN}=9SWQ<*$iw8eE@TvC zQaFueL$?)5mg^3WXRExS8hLqn*+DpYg*<8TeQfI}bg(acSvPPiFDK{u6R%`Z^_iXF zbe>EDwm^w5TH0QhYmWt*$H&J>ILbg?MjTrX^A6BzyZJId;<PX0T^brhXO65)Y*gGf zFNW(Ciil_)C*-sKhYQHf4Gfg%?`IGZNyi~`gD!ljy#(JebA<ehD;$gJc^Y-GknRin zvrcau^Ji;#)I-Dakr^TeYH9>z2_Fd$Vyn2U<>V+M>9pP@2s$o2aV}L*80_mG{sodZ zq7vZeCm<r!Nz`1fh0gVrWoCYK_tMtR+c0RhCZ~XLRyfWXT3gGxeAJYJ{7Egn6-!PW zA$eaEo4gGj3#PENHl}&?%hACxX`l)`%g8{pHA{E^zkqvt2{kw$t#0nV5&cI`JoDXk z=x)Mek(G`PU1lNxOa|FBDKJs7ck_l6l#vcikYMPz>Q1^)cvWpBj^~vL{Ac?^+5Z^# zwr&<Pfyrn;cbip9iO@}_F_2DFm9jv{RM}p}Od~!aK@cY;F;OXrpZT^tG=_RQ$aGT3 zlTsqkM19Z@8ymh*ZOQ!w)od|!dV1+`eJhcmSbEg{3V`yX^=icS@YM8l{~+7f#v08N zq!}$O><PId&5i`j^6B{G^x!C)NwCB_8ONlQBmh+`ed=4%mw%K~lkDNRj2JXD?6i$X zu4K@Owl}Zdv}fThdz;7CLIj6h+Jg<~nKdaQCa9(-rl+~5W<_1sFw=sakLF6o4IuxP zdv(7Oj_N<1&+1D>>nGn?d{R$xQ0zTbCnvc(v6pK#>%>5q`vUdF`^DW4*$x0N`WXti z+T#vt6*C$?qs?d#A<+Xd*}&5iZ10(M-~9G6h?ngXy*-1Ry;DqUevN#mZD_KRzLYK+ z=}!KZzcDi=xU&~j3%8c-98Te`CnJ!(upw=6<n3xTb(F-3I}pFUP5vS3p{vVW-)y;> z_7x1qi)lr?X~idSxUnniD2hlEaNXTyAk9=Iz9$-<=VNXCIRs1HRv^7`lW9rxys>+x z$q=Dxy43bDqeS~dTvl;SO-1qtyG^O%k;CO&>W4#z5=A~RjlrF-chzE_!3}m0YTZ@O z6sOHrAj%M&jd;7dN>KsMbjs_w234!$>9T;c*tN)a*O&XOo^vg>2S6D+L;C+Rmb$y# z5x{bEWDOQ{y(I7mDO@!*HC;i~rG|7-9+ie54i~P>&CF0&2aJVG2V}e9RDxpeFNs+V zAoqm(1Gu;@s&wJdmYp}#Qw%1q`(q`l82#Rhy<y}P_JbwIK3_(*92orZlnn+G45+Z` z$=GVF4>MAuFE_wU3{rxE{6k41T5EyrZ}EP-d+CWmmQ<4Vc*bt=?hvn)jD&<JA$BM& ztFB+T(Phzf_X^Zn%E7^9b-0om?P~vP9p@s2=S=VV9P`?Dpo=}s1IN2*M7OR2vC7`x z{w@#eu^G^@+-T8%2MYZPP2M?EEJu~qOON+ra_97-E^g&n1+Ma2Av(I=;b{pT$@i~l zfNI7kxW9XQC|~-=KO-dp3^wmn!&jfdk5Nq}hY^}3#-$ls8T~0Wkcn5X70Icp3S%V& z5a`3SRuXn$(ayF<T|Fr&X}<20;>4taf*>7UT3Q+%9i4*P<>DbQ)9g4pMyr{^T(FKS z3@CVC!RpT+=8)kDqM<#(%#~d=A%CD`w0LYwqaX&m35iP~EJOE<0$Q8v?<wXWt8{|G zTTU~!HSGr;dZhM`zh~M@fW{Kj%S!B>LZ_6nXe(NsfrhVV>A#2M^mNk^5fTDC2G7Z5 zA$;M10sW5c?@5t;#Y*7F&@y??rCU7fK*Ao$^rvrRYwX@xr{!P%@i2%DGQ-Xau!zr` zN#NiI6#U-s<Nq^j`OxbBGxhmjXrz#ijp5zic=zAA-+y<%dRS~sj?5ILRRYT}ArJe} zR06Rwdmb%qM8qY4h_~k7FhgZuUj;u2{J~D1=bfSv#`8iWHjwK6Zm*uuC`xIK0XJdR zX*HNdig|l~m*a$uhKO@EBfiJ<nE)@3#p-to6sW=HVB}7`m*Vhng;cP~5Dg6MRqn`? z?C;H=1^z*kideyJlIkokKQ)%Z**L8mB4ego8y~J##Z)oK_lo~>8#CFOC)6@!zpc%L zh{wJqV_A%M-cx44xpnZ@5}Ee+-ue>l{sra{+}FzE`h52bz$t&f$5mUr{|AYVPR4T_ z7A|*kdHJ<VUfw1(AsCvfr8+b`RLF->{)If@Hvu8V!KTGAv`t47aS<<yH0_48S{Wq1 z)Y*&8bJ6eg!QR;4WnXwh&B-K4mp}p3`*Hwmsy>+Ow^mhQw|qa|U)TNeB{4O5Cf^Wk zTcKjx%SXwnzC*g@BRQq!+D;yCK~aCgjRQ8EPqi^=<hZn;Ud16W3E4qJS$g`_Emg_T ze58_hXN%~$G3S%wX1L}1V!CjricR)=ef!g2qNtX_tVl%cFJqg(#Zw9zD%!GCYyjtM zrcb7g@94;R8Gg>UPEs7*;-ikJgN3&N)oVI)U4P||@x}~zK}$_{s#ddhP5kLtBCw0n zYjQB&i)7j!NnhXCQr;uS#0s6UUC>w4oybw{++q7udnoe3djCgHOY{kG#&0(^KAXi| zLwV;X!6Ni53<opS0S(VPBE3}OrdYLV!{#ug5^5+LW8H1VIw{jde1G|DSts`N^_5k( zQt9<(@|74?r1-glS8(hd95M}~l%#jWrg9w36~?{ZIjzG3^TJ85uiQ8$zE&N#l|SE* zA_dqRb(hoq@TMkzphkv;h0He?uQZ7InpOR{x(`T|r4#XNy>gT8-y5Y!+!v(KP*G!~ zT<QOEZZe3w6JZ19D2X}kyb1y1ZtLIA{F3ykq4RX|+|X(+@*w>yadv(lAlA8;-PyV1 zj2bXtOcN2NwjK_$ZAF!Jb#?tH$Yb<Lgo!%+6~C!jYLFHYw$NH(z3W;Y$qPA;ZGH)y zDf3C6AUvGc&YVN`)S|RMxJp*ihR;P&2jlz+T}r7vMxsWYJA-j|XNwxQlT!H{+uPc{ zj^CWu>B<}@lkpyxER`K594EXcB~?ORx~pNUDuAdBb`J_zqD?<9dAeApbx32ZC@S2H zuyfUVl6bvaUtdWN=er4(8}z%xnNEK?^^~x$7B*MZxuI;goj)2eKhIxlhcOSGzc?C~ zILBtF_PxCma!JHIF<`slrhos}vG<Zx|CPhNUr{Bspst2C<tri)pP_Gg0(tVUJ8`RQ zr=xumd9kO*cZx_ww-H>0-+U_sgM&n2<^Ze1aK5nki<xsG8)dB<Fq?iqQLa4+u2XwK zq*HDffpgvi_1wMclzIv54?3S-80%Lidnc+{r&sU-D600--&2@@t#q!!@i@B|ltw|Z z;_g}4F>Q-^8Y+tVy3|9_tC*TA2jzswkA17>7kT?D51`cc7HHb$rldij<G%7qybPh? z!O?r??uAQRZRbOBC4J>j)wg{+%4%*kwUvjnjlpqo=+rFbs_M+VrK@JE!VPK))7GpB zF|pAC9$ha$u9|_}68gG>KPAqLb#JeolIqW{ulc+A`_V-B^UN)-SAXc9f|x^E$`85G z5nWv-<zIw+U_V`ob>ibt#e%_pel34h^tH7w+aYqVUd1HtmsM7mS5^)KyEUrq?X3&} zM|NS($-c3%?s?0vt?63x{EY~ztmnX6x!}Mi%25|7wIniG_C=MI8(sF<uVuJonmtf1 zpFVw}UI|JQtT7(_X{6t?v$F-ApVzH(YF6#7dF)sAx2Y-I7fV3h?ZsW4K?Wu4RVS6i zk7c}_Z+v%v=3q6SO5x6X)so#z(VZss5@cIkd;{N?4Su1@M$i)8VC;ulA~t=l_1G7L zB08Erc;xslXKqlRm#^X0<8wh#^$0vY4>qe~`O*_ijNVLN^x}hp-o^GM_v98k=d7s+ zXbpgmKD9f#PUhQ1_>XsHh+?tip?Pg{X)<HdY(p&!J7Qk@Y1^Z`gmgL~LXC;+U+oz? zXL5tx6y7*_2sh`7Qx5TOLOEAjMuC;wk@4Ks(4sRhHB#T%;f}vvhEfKd<Nx$LjgG;n zW-=K4{4R<WboR^psDlvSI9q?IQSD%h6gP(sL@h4Xd5(oi0khq+sH*x<dL8^r7EYUs zzY0Z&b%o8%3>11d&Nzk3x~Es^UWT{XQ8YvJn|{{BE0*4Vdh+PeX84`hX6sY*mSbOJ zfQn$8gXqnbUYxgz<$K}ja&f`rFxvQwW{vH=HBvX;L?5<^QUMQX{z#wmQ@2GITa?Z< zH#a9Yg-|Al+Hy1rEm-mW`}c}ze0Iyw$?&i+pIh5pC3<(6-GJavZ}A=<KT)nApQ=qL z3XN%OWNIFm>Ctw#N6H#V4~IP$uCDUkuS`MTV~?7x)oI|;@aT8kzIY)GwlL0wfRa`> z*ji)mv)C*8ch>_<jQq;>9rN;E-kr#3Xt=2E#l7&j>Mgv8kKaBXN*1uZ?aSGW9TvRQ zPE1i{QjP#`97~~zET;?S5~5m~J)QR7Fic2EwcZ{^I>*-2MNp;1#57tS*tt+Ohsiy2 zf8le|$FLH#JQ9H$>(kMh@nM4Wewxe=hN)ZUfST*)M7u$dj+L6PrmX^8PT2;7@}Z~` zGYd;Ic=V{M)E8xJYi}>?&1Sk*^VdD4!iPVK7Y?a%#FGt!^EW4xsa)FbW%U*`L55aR z>kTSk-|TDzd_C|uJq~qzb9UmSwYL$f?w(*mXFHRR3`j#=q(6%mmxCQuWzR^%@Y2N& zg43}w{_`|4rLx07gP9CG-CVGydE+1!+psz)_(~1V6$L`uLv{>nVz!9HLc3?bei7VY z(ZsqJN&#)eRG{PE51rVLp-e-n>tB{;eqMwGz721sQWY_jkTej@2KQ*?ZekMIjmEd= zO_g|g|3R~aj-cQpra55ufp&TB0>R&u!tM>uJ0dzd2l~PSlZN+$XVVfA66*IKlz)k& z?M|#GMv03gib7=YS8#M(Xy4N?jjCQsz5ys6UnGYiz(Dv6lN~R3?n<b|T?2f<?JQ7h zsb0N`=HRH53V*!_k<!G8QD(3n(8;EN*+i!E;ZtQ;*qRnNRIpPA?VdQ*94>&S4T$M5 zcr_E2g&S42U7YO|<rT9g1feTwT(+=-{e2sAre7PKPZ8N?-;7i$f~#Vk@7p_RGJH*J znCsd5n#VqP*K0D+k3?v`R@G0H6Fn-%Akz`Jc1dwC-|5A~&u>J^3p3F(UtI>T0H=(_ zoT$<UOBI!g{5vVMf`UB&wVe*rSuWI1kV_3t`@liTvo_-s+BLI5eZ&YxejFU`#Nbsq z+`T28Zo7Kee}L<5@gFXrX0rq>_y%z(GpyJds~wMOdbjE0c2g4#^%n8Cg#{qNmBJfw zTbr9{Lf&f|c-w;fvK~K1)7eiuL9KQxHPvysIr&=J`XcTfuN!(M{<!0ZXjLUx|ArPu zpd1Q2YL#0>5-X2gqHawNz2V%x{OX?!>#rK^HKtO9Q%H2Zb+3i$|9GRJg{+EelZ7AB z@A)YZp8gf<uh-C_LK(LUQ41>u2SwwTaT?M@;xn>(Z%Lcurg^zzVQ6_dzk!6H49`L( zHUyH#-dXTLl-!Wzn<acw{vj##`xVrC?+rV1{bR}fLaRqKF&qmvLFO;H(iu_Iz6zpb z8uI8q&P=0I#IlDvF0khNRpp|1AEzMS(}4>#DMi*q&H&tQt6`}vKLSF+gY9*B!(>{E z<tlc<j&OkLmzOWRGyF3&Gh?=}d1^NSPOGt<=Ah?;%~uku4QeJr<WEo-_NOu{zUL%* zmN~8mW$hgRb>@wjhCFP!Df~UXU&yphnVZ@v$Niee8Z#<ic<$uv+#5l<P_5clNvy0k zkh?FK+X+y>O2`QMVjZLez(HKD8d_;fy4aO`d_zyqY?5I$F_$o$9Jju&^s!%)@^~>P zB`JUxq-n6yr7|s774SFG)6mfH1QmRPM*$gH+t~VK&Y>qz1DQ;jf`?VX;fss6A($d4 zi=VPIG`V|wNd=aBy`T*9-V=2H9c6Z#Z;)pttks;+I*#v^_^^E8KYZrc8yW<Z$ID^X zsAQg~i!ctZ5A;kd#`|*BE#ZY)qj^s&bkdVa9kAqR&W{%7zFi=1+jdO#F9q%>uhFy% z`Dm%S;>ividGwG)SgPe8L{xt(zp3IZn(#Khz9L~{o@&?KvHC<Z9ct<QXX1UeyST8T z&#zrm0a4oUQH?E``j6z~dhJhL<CqLYO$wG;O)Iq~Y0G;1L-SuZeCGU|TvMdD<+pio z;CNxSIze^+&BfuHy}cE*fktZjf&hn#cA!akiDAZ|o-#2#Dk?oaE;|0`E4aw8+sJ4g zV0A|H8U{piqD9pO&d#uyhwcMcK0JMtkMjg^-S$$>=jDJ884(eYa+7Le&v^Ut)YNBp zBWH4Q*e*nBR#DCF-V~V(phzS+kCI`sbBgQd-liPJ<dhV-k2f<=SE?7k^wDw88Sf>l z9M0w39c0{Z)AXXn8XYGomv-!a);lV#(F~Eb4NcjMcetyk&P`2KX(C3nwB~`y(19-t zN_5kR-nWEYicR)}YuCoY+n1WWBb6qUrEI^MJ7Nd=9JDrwA$d-CIK7>D@i;jZ47Qk= znRz~pA>ta}^5O{2LCZVgvA10|h?H5WOF*$e@f7}QUlG_YCp$fQROxpY)axHwD#Re{ z1aaHg@~5WaS2ES}8AvsXYDO<j8@(sXGQgt7M=?5|Pfo7A-gVd{V&uP*LVtZ+ug-Ti zTg9_{z0)ZNapA1y+3L=dd*#K%CTw1$nGsU;nY7e!>)@ZmgK!<!K+%vB>t&OfDH-^; zr929fBrSllxVgWW{#mH%{)XFnVi$5ugt3B$_Z$c7IhLsR(K>{RMd^+*FbEIdlwcl@ zN^rVK%ecX3`j7i$(JUG_yy&e&clS1t*;%iz^*zyagDU=`Hs2=?pOxd?CE1a?)6ll9 zCqbUO=XH+8ozDP1leFCE?Zs%d0ka2aCMu{zs<EC=*)Kk-%e&;NbR`ea!ttmiyx_}= zPet^@;Lvg!t7}PBKZT)uz5Lupqi@IjzB>8?p=HLR6>O|*{hB_{&pmd((R?cW`=?3u zk^0m78Umz}3L^{6{z;)X9oQ<QLPh3&?<XXRpvzaQ<_9YNq;g03Z1U%w6)UdhE6nbR z1M2vAA|cArwziKm_-~j5dl&!88qSU^2hGfP_m9I%Gcy2nCNhCc-G_|3^otWRYV+g% zp}C2nE|jhRGvrJd=0uEBotdE%W$MUl64VvzY;7bBk+1l&YgdGy)M4H@{9!`O%_Cju z?V{#jU@%S9#`Yz9ZUyQH0TViWe@sCqM<I*sxz?TckFG$k*}mT#Ufoi?NhMM3GLo@^ zRPg3ry6y~5c@<3-W}oq(K<35pn4~yVZy^riXo-s3=-aS}{1;xkCCa(hT9|*^JXUE- z*;`SNyHgSq1C9D+&)PXs&93wswffJaJHZ!=2WUE<HQo5!K4t_>toV;+8;_<o=GYmb zJ9W=PJHvf^L9YcT1}DR<zyRsFyM8exv$3buFqf8|lmrk_mWCw|2#CMpukI^x1}#c{ zdu`A#n;4zcji9S|px9fG`ozVa5OO|n`d#~dEAG|mCK!!~!g9e?(Ne!bsjs!=&K9{> zFW`aGplGU(*ANT3KNfX^*?r3of__q2OO2{|s%q*)@}3^vUY$~Vb9tnQM}zv=75(Vb zURHkoRWkgDommQ_(L72SR{SA9Ej$c6L$bwUw#UE#RI0Os3+PgpwyP2sH)R-+HLyiq z^KBD==VH|J$PN-IVI9GUNKF($vUs@dFLqncq9u5v7>0w9J7p`9aa1u{Z^%!rJ!-1x zu0tx(dqvA@*^Aw)ieLPMln%pICQh>75<T@G*HJCOjodhR&o4{Hw@+EGIYi9SAY>+w z5z|~7vTH6zj4xn&Wns>P@->MPR#nYnH`VCT#o7ZYC(+kRTUd5v6S@_}^e<qc+hn1P z-1h$HX)&44If1SEZt+bDnk|hDWDmKvopW3&99Pz&Cnl0qX~)`aY)n39yoykat|^`m zejd85s;u9RyV63I8WS^k>6(xMxrGB&q}Ba^wRv#&)jK`dp9V>Lnf`<fW)r{+c>Ld| zJHc7UoJwE;TIpNV^ilg%#Z5z;3PGYu3j;JTM4a_}(Wpxe&+$k~_uV+Yra2uJR;8)v z{o3A9&DWzacIx22D@~J~!!)g#-{2?h{rv^Gri=|zs#yo{c{$)1T<u&$M4jV{FPmPk z+PNJ-EG%@_Y$I=H)U_NKK2@wg_%d{uTz^)R&h~F{5H5_2oQRSFrP66akf&2)F;gI} zlgGhcZtu8q^Mk_WTNxR<)7OmjXto!s+JD+m7kI7n+FBYX=-|=B+uhSiz>e17wbEp{ z(TouZkfey?rEF&=(PW#OBQ)N}$G}-4g4Aoar8Be@HNU9)3NZP+){UDQkuJKz+8Neu zw7lsx@RB12+1M2C3?<)!a$Vwl`Qzf!*>a{tnu7~I(l0w#{+wV5w9L!P?`ZbSTEde$ zYhaeKuh{H1J87jf-uwENAAfgF$#-l1wp}z2_k`EO_ct=HzJ|(Xbiuvy14Q~Wh=tO0 zc<S-=6=;P`&+*fQWlNJ7K^kqQ(_Jsu0Vqhv%ll33=!BY}Wfp4kWjt8S%GbPRlgq7h zCasjZItI|>sQ7)Z8>xICa*}%_Nr%wtydo`m1yT7g*^<~=wU(Z0PS|O$t^lrownqKa zr>rv})5*z;PW0oU#U@)sHJM+aL^u4G+EQycV6UTUXJ9Ub=nSF~0!7@UxpU?xX_ZHc zj>MhwU#BLfTG^T!+FjP-5~|^ag5+zeYm8bwwN+GP)!kiri6eUS&tZ$YspRTDNR>V| z(bm7_E{kY+92!R~7~YPdov4J{YGi6^Q}o0uVspB{Q?-E6{^8tHm?mmsg41271ZI{T zdt6yj8E23STibw0fznZzgAx_&0I-WiB{nAwiAp$r1N9NeAJ`2L|3o|?VxhF<FLxXc zXq5j{K>x11V^Duqzr<R${^PAs(#n{O=8OzVf^lVDwzrNb&E#3yVGWAea)TVovs`+u zF>d-}c_o+fdaNX?YR*8HRdHauGVtDa01#1G_3Ov~%4FA9=6&N^RDik$i+WAu8wMa9 z^DOTwTeu~O7mW;h$Vf^1sA{=yJ{XQm$vVg;X9qNkMG^<PGfFFFjdC#swp=}W^d=z0 z(|gtaz5RP`VN@Wz^l4t6=?4b`QPZ0qdZED$^$E{JA74-RI)+HdN`V?-jBw6Er4->^ z?5~FUW^G?R)OX9G5uaHF<_RZrr-1_s^Agl-j*Fy6Fcp)eL=X=<dmh!ic%Yz}5-gvq znvRwRVs56_;?UVSE#cEt@6K&kc9ooeGguH-1$DhYR;@KiPy_8fJDjPrYZ0+9ySh)` z;<y$dZ*9F#f&@i4|JIsEEG@UaV=NNX+JA3y8u>I~j1OZ_lPbu`=wvj{Me>^1f6rI; z(8;VXewmCL?(SWX7Ui{iGIw`yW_4-U@kd>qzq~_;kWX-Wl8PAZ(U{7!ql<PZH0=)9 z2}BQ=&$qB+j(T{ye*nL-9@W6--TFbLLuBt#@8AU~TQ+ICxuZ__=6vVZN?#Cu<+awF zc~ir~lP!g9R22;D`vbcbT{Gm4f|lE7$L3{k6esG)&AOcqRunf8I`OhQlvNVI4z<X9 zeyktuJc!?QPg_@4tgCV-TKi^k&lxHXFxgcv8wRFg{`^^=s&XpVopqi^Q4t>D$`CSm z$hKtONcPKxNc%W3aPsgm2_#Z3Tvb(`S{<y<&UWN7pgnRnoUB<wPzf0Y=T=|tm6px` zHfZf9fWvupI6665{|kKoc*?`0?rk-o)nNU{_?$WU{y`}Czx77{Zv=vSpYRosN#?S! z&e{O*AEqe&<Iiq;uye1n)guERMAAo1B+SDKBv)Af)1<BWugduU-^cyG>FYy3{%dCN z|D};t4kf`+1EI*!P-A^a8?;tVPR{bp+qdkr0zpq185#Zk142VW{`C@Ffj@pLEmkj@ zfkA6C3ZekhVQ`>uzEg!(<?=}1P>x@AZ-nh~L)=q<VumQD-JNk~e0b<pTMAk`D#K}i zC~0v~H}BfU)|NU$f(tzJH)Jv)LDTDWOS4F$)DZaLN5xUFs@R{w`L%p5pSFa4HqIwp zi~BJ-O|M?63i_rG-<!BbG?<r4#VYEhwX3OaAn@@ko=ki67xz_E31tO6-?r&%c&*PU z`oU7YXU(&&?7rs{6{4Zaek1Q6w5PyXla7|Q#y+N}(tMbUn>+WkySrP^1s3LZJvG(! z{>_`OS0{$$<!lM8HzF+Dwin6OjR@FMlO<YY@8IAl;P;Ypa^j*nGwclJfA^Xv;6Gfz z9JEO1_s2JxrV5EC@qvNp)3D0QN*rvQOW3ltjg64g+;2O*#)_E0pdkGQCw>-TJ&+~{ zWY8*?zzVxMm@Um{{T4O2b+JERsaZ;ytVs!M30gCAbeq09&a5lPr@J`EM@Uw2maK** z2~<0$7pL);YO^6X)b7^D<8g_m-KKXsS!{}GVkZr0y!;YtV*O_E+M8Kz7n-&-zJ9H> zTM}@BmDxfg5JWy@wg+aUqUJ|JSXk$4ok6F_Tjv8_rH@p?R-23UVBgd31k}xi?cPfC z;MPRn=>}cX#mv=l0!yRM#`PlqvCVSRcu$Yymj4s6wE^`a3|vy_cGOyS@XlyjZB-R1 zx7B-7I6Brcw8~Qa<IUx4iJndaELfdMb8c<{FsctNEEJkziFzE4=ru-C@;BTfRxGX% zqIW+*KU3Jf8-n5hN%4y9$_eB`21d0PhY|Gb5IqM_@kdW=64@!O6VIvRY<84AiGT4d zmWtz#a6S0;1vlr|##kR2NG=j1Ar|X%8Yzh)%tp+Z<2*3X^c|Iyo}~7O=!-7|2@Dq7 zd5GnYj;uRixq2!cMSKK;cO5G!z%|rPgoTrHHSE}AVnN5i(3`S}8G(omTXfI<km+{^ z>;VbIPJfK#rIC@0^{qRcHeey6`n`C`(ny3A^!_^MmG*}XZu+{?*UI4sL_ST?6!6t> zA~i4wHa72RJgb{ph;`-p%SWp>25@?tCA2mvf1AIYaOka?42O=s7&<WTiCA<lx-!(Q zFTy!aYuUcsZu-M9zUJAjpa-8ZU@T+b8aFwrkxsAnFX3?hYZwqzX*QCXj374fA|)qh zCJG%K7%Vsww%#5R@%F$Y=lgmPub^hn%g%1OQj*r<=NB1?hx3gumAhz`%VzHDer*5t zwpnKo?%_oB;6n95QQcVI&M4rnW=g)_l)>M-Kf#FhITv(2OcHW8n#@x;JcKQiir!s^ zr*Ltwu-GDx2Ys&$lM-r)QMYI3pw|04jBam$2?9RYTMSr>mJ?EWZ}$;?;ORSdPD9h6 zTy_M4fyet6du2H>N%I{e@xu;%cWLotbdRU!Iu%`~;<ZeA$<>BayC7<)g$nG9aG&py zL!XG+@*5qnctfMf=WZ(bQ9J<LtEF71@52c4VF1N2#*_D%a>DVX9PLDzP^T<|>BBgp zi&43Y-KOVp9UPW~zTmIprF7@SxD{6xW!;cQ$Msy4Ig#CP1;<u#qTNz+LAwqU#{grO z<4v+kppVn{(^ZWi^(4`QAyo97Q$IF<Dc&`LjbN<o708ziPbIH+If;@!Exfh)YPSa_ zMM1b8URiYj>6Y~~sfISD_vJm${J=ya;;x3-sv#QlH2EAI(h;&(T_xhkV*<b_-*JJl zuxHD@yOEg{Edgd|XedLr>;9Deh~T+)wUtbNop)mmg@BWikD=R@IAcbsUSoteU=K}6 z{N1G%o{^D}olPxhV`ZiCg?=yA3=B?4zhsP(l8_=Jm0d1*`4WVD-0sY{XVBU%VrpVS z;366}LO)e31eC;+V~N1ypE)5YKMCMPi$yY8w<vUw<^`-RW_jTW%{eB^MfGbXDISsQ z14}kel~{q>K|<8tBdH>0j@Qz8VY0=U+JX{ZfO~X5DTH{a)`02t@=RTA#-{5j2*3E6 zSs}M=SVSW33gE(PhHERiH^#Nvvl_eo22)wW>d<b(JB$V+F^DHa3UrX=6bf?@!guK& zFMkmp@d&6fKn5Cq{Zng=->D-<6Pm4No6~E%Ubu6Rqq&5vv<R}zp(8};kP81~qMDiE z6DT$sW+q#hkkM1{5l)ga=crAO-#g(uze$-i!NN#3@YW>-)MTS!CRXBc_rQ85d$o&E z27(E9bTsb3RsG(u@cWrwIr><yQq%Lia3DJZN*8d3?~db;@kEev@86iNFf@Ij<Ao@s z@DxL<%%~>5mqf6ta))3M$`D-x@t<o1RbpbSiLI^k(PCikinkoKqod={(2%K|A@Szg zT9)A!P(kmy^Ie+HZ0<^25535pZ@dy5Zrru#4A79z#r`mfEJmq*VXUfM?KXQBGSE%w zB0z;#sq65ewn}$uLe)33)ew;vBo2Ko3R(kcCmCk;+U^wdmSjJNiU$$Kuu6}-6p|_Y zN_8!8uuUW<yF`NCL387%YvZ&l|NY(7pwmBTjAb-l8s-KH><Q8Af|;eA3=9dkGj~4z z)7PQsI;8|$4l~CSb6-_vTM1VS1%2Zy<3<eR*5ajGd!YlWz6aBPK*32Fcx-@rAte_n zvjf@2q$~Eg(9=<+w)^z!clmY_={JVzO6m)z*H*$zUVbG+fQ49)QLneRyVe#O<O3ME z8=Ma`i}lZ^*V(YKvFpf7q~VO@jrH}RpF1uO7s~M*D=O;+suu*Iwa2?aP76V~bVYcJ zN5ooHRq-dP#Lg~uiR}8S3{M7dfEOpH!vQ3@N5^`a$m<*j*EJYhxkbbv(?srkzk&J* zeH`h{_xJ|0Y{M^{_$s~%)E7NR5yXd#h|(j!dh$${g<tR+gxBOiq8)#vlx+Gs^0^`! zT`G`cmB8>0ADFYYE<&(l;+b^Wha0N=k(WwG<&lTsIDERe=Dl8m`qS4OOir<MPBWiG zz1}(^B=!<K9h)hf1h{VRx7A$l_T!Df1&(`${hrXuVQhX;P({4mo7q_zSLki4UTNm! ztF2iv+sw!tYhns~VUxLUjJ2v(fL7^p=|TzEgctT0sHl!JGvByW6sXct2zb4J_s&1a z*w~0pKE1*g>XJv~FD{m*muhQko0ghZQRz4*x;9l}tK)kg-+Fu5_|fWc!P&Sse6(ns zh2devQ6$T$3X%|hRZ(ITBGhK~WaQWRYCJ%;)c!-oQ;qaKsmf$zxhJZlyx^_tM<!}- zVce}%Li00U{<nMeM>gFDON-Ko<6qTax$H^9T*AjPEAW(2S*iQ<o(KdGQv90rr@EK{ zA^$~2TuM)hX}RDgn()Q5q@)85Hep87LgrfOxs8-qxK|cy<le&E@BLE`p?<3|A<lCe z^gHblgYA>%^+2>?&CxO~!NK@uErm$4ptaL2nfYkDQ%m=byA?>Db<;mIQ`n40rD<UC zm0}&<`|{h!Er9$_Oav4IAVwA9U1*)aD%WyHyS_J>#AyaUS~>_F6;0#zEQyH`*VgVi zSra!OP41r}2z0>1LtyQ&33<R1DTxR+rKF^Mk=?|`y%AcCW)~P#tosYakf^AC;*gqm z^&JBX59aTy(d=8)+KbRF$l22xk7?JcxP-f1+@5S7IbQbFs*^FQU9j$#cSk^-a{Fe# zlFKkMBcO%ek!xIx?Zj^^m^=iH<%UDJIF0S}qb#<<T2Xcsiv#rRF`{PfPq*BYr=!O; zFhhNO%aDya71y;~3tYXI*%b4!VGLIQ3$Z^w^}B!rfYn&LyeeFrRHsnc?nAQON&~mU z@vhZS@A*c%J==6+ofPEYldE08VNgd`_LC=gL~<L>o{b#K4FDuU><j*?T_kD<#^R=C zZ=R`W|KLK(CuU$^kdf&hPT@6fr5gYeFu>;BdMxvwNIHH)Ld-yAW#x)s?#q+$4SvU! zdWSv#ztHPy>)GA+Ycs=|D>B0a1FxP1lG+hIWPbj7?WLK(hVCwll2k0cg1%QY#%vXx z8nNSNFh~#Mb2(0D8#SGI4P32P>1Ih09^q4^j6nDg4yJOlWt5Y4B?{Y=A}wKm>By2& zsr$#AxHB)$@qV%1Z+$*$$D`nz(4;eYPFpPBicI6Aw*9Apb-e9ULI5R4DF)-wMX!vk zVNPHy?CsWtWH>2%H7!x-xq~Afg$Rd3*E3<^C18c1Vc_+*{E)R7D+Lm>chCyVK)n`O z!%Ttn;&09s6aB2O4qNp$?TTWesq5f%HoxJIC4j?05g*1=D@;O!Z?Rq@!e+iAZU70y zEL&P|yuG~4Mw7R;gIuwI7oU=qslU1#JTw1A$Ya(-%i0jWDSLCG{q{eZT&Fl-`TQRz zZvTDe|1Gu)#AHVxp$Q}2$N2N3$4s-6ed-4_KZM;rqXkE%2{>OGRhwPG+^2TrT1sc+ zKEE3uZu2Ci{TVLz<$8k(cG4jMY&+yEz5{VBrWAKH0wN-jXTBY3li75j`I!=`Dpi09 zB4K&yMrUzeBh2;f7LF_yykvhvb1$hBpBhbi&Y|yqTgo(};>mF#cS-U`Wq6sxS<WS_ zKy5Gh6)<RzfWYlnK!Fiirj)0!ceGFEcQ&flSNS&u@v9^at?;7oe<UFUl9cG1ybj|b zjXIrA^@k2#o^z~8u2S5`55La0PJ6s?hV%-IA^>HGc#4>OHQ3HLr~Mnyk^E%&IY7Hy zUOH(eeueeD-QM0FO4%It9h`!R17=7r@o%L-3hWq=YuxJ^0SBXAz0ZxQu77y=R_2{I zGs|84bH=ONu1ymGe0mn9?Bw{yqJw#?gyA8147^=qb8B(@9CH)E0w&DMJKEiCsdT># z2uPlnR9S8c&h1Bff)DZ}KljCUu_vIt*x9iHhF}2K8E5Hec}Ad<0Z-`@c&&E5FFOeR zK8_X3_2z|pTbk&4tpn1{85SlEHsHR7Yjauuv1@#1@cH1xEiyxrmNu`-cCtdeaRzpE zBJ~o8oW#c^RKu+Sf>lsbo4U55>ZjLBAXCBTu=~-aqOl#prrV<N+d%q26j{uUds$<- zN8)-E2ry3z^V)cnV^F}VMXSoMLMyOss{iQ|**(#|hD!bLG<T^`!#n%E2kY1^kdfgU zl3i10gc`V;s5r=)nc;FvNPnqoEIJ=+M_JP8H#j)<wTbAmYA%#1dw5&}p$Nc>wb)E7 z%QC;vD)GI_y}(vML1FGE2?f5UuF8W_UH%2gLyQ3#j;YTY8XB;H%^kwn*f;@xfw9UR zR^6=V$}GQ6iaz=~kNPRIXqKD2+1B?QN#~0lF{r3ONSyj_TON>0+x&v_^YaWzNoR|d zprs{A$si{Wt?prY8Nd%eG&8=YY(1L9FX2wHn~zmbrFfw9c6E}{X0|88s^8<f0cI~< z<b8T};p6RLVdt`-;4_@O0F}A?3Pg$quby~Nj~z97UC^SA_tqqj32M}}28!)>cl*nN zBi)7U<ZW&}&&>u#g=kpBH8p2D7Q<{W$8OdD9T%`=A5Axhc9dw&r!z_wdQBGOEQ$<( zlVn${lST2>C>0r3W*H;dB|Xwk?gFIv`Q7!?qx168^egdbw8RC)|HB0UAc3uCy8k>k z-m~4%u4Kds-5psNuFGmZQ&mg<%66e4)Q5Ng1gJEiR#MB%rlxfmlIc^HVPziZ%zEYr zYucoAVS34z=Jr+z&Vi3lJv<J056h~mc7YfNI&Mh%G9~3ae|_tHeM>nw;Max}4IPA1 z*j{6aQTf{3x||p7c+5l`<ARFaX|*N|gWhah_O9Lx9~F|uZrX$k>RntMYHwFu^7`|~ z7(pSxx_S;ofxVCe!&nI=<9%ag!2qP}LmQ#reVT!Vr^xOvsdB|<e=U?|S!Fe@dwKSB zIUVo^&3(}szfMU>QQ5z~7<FdR;YvYVs)>ttR+H6oPSEEGsnEV<x17DB#%U6oD$W|< z(VTBOqyK=aF)EHs*ol2^oYDG|m7ZCJmkFs^VB;G{9iuvdOU}<q@SJ!k=`BIXC6$1k ziN$Mj(o4Q~(P`5KoW$YbVeis~SDNp?McSoF;ZQm3!@4tne~=^{r0=MR>F(+lj`+=W z%pDT^HY;YCbULs4eyfOg&OF=LK&4X76%l^3771jvmJ5s<Q(=qS3S^UgsNhJ|a`*kN za+cd<yM-1(I^JV2PReiiYF3VDPk_`*HQ`)a$l5t^De3NkrZ?y01jjD+Z;fKW4aqob zc-(GWZhyMbi%rIE($>#O48$e=zEB&p?<hg*?!D^TluZ%l7Ctvy)pOxHu><sU8J|z> zpg~Pf_Xbdg5Gw<XGvbc=Y?7%|=EkL%VdaMBWN!r$+!6KS6{(_5JI~Ff-i=PRjbiT* z3ImVfBa?hVg|K>rn$IM=6@6`FhfdxELOVC(IU^oj+_80B?`w(}I#9+jv<Ny>09NK- zo$GhxzEc9chr@uT)Yc;2n_u=>6wuR^`2Rr}HF|7Z3W7no$t&5tAa@~3y#&bZr#MK( z8D`;0L5ic6I})JX<-@`ks;rb%w6(u{iH(tyIC)1cPVMd8?1%DXOBGF-NUy@j3ie^s z*3we?#hz(vJx~Yt^aczaP8}be+42Ch#8aiE5kT-C9Apt;kE%dV=sg^-#xFLRWu>66 zvGS>}%<cp{MJZfo6e3mk-PXL8LrA&Vp0L;J`|I-P8-O!cx0$j}Q3k4L`HNMsPhaj} z4+i@zp{wo7D5H{eQi(@AR^;U5lz%Co6+XhM7GYwb7}vy2R@=&HT^KZiy}zJa?@p+1 zYGx*hu85Dn@lqV4oV!ETHDlmXvsN`MJj~POKz^1>z}1GBNkLI<8n^!b`_ueBJ^gmb ztFxr@1bV3Q+ZdM@rUM7OU|>w!1lv&_2rgdEb0^nBdX~lkIT@Mkq)ALJt6gKTxfHjh zY;EmvkbDYPdSUU@<0=o=0I@BD_1UK9(;AkmGN0e;rDkC(6o1BeqnDgNV>ZDs0LaDp zKZ}}h;jprHlq3$B{Gm)RRqoCXo6#*Q83Hk%h@<g{4;ik)Vzj-Cu+<3`aqG)N0zxS; zB{Ii+zO8wO&>9Yaw?twDE<&uCNwot?-hN3=nS4F0*OAY)-1gsSd&{UeyQXU}1_=-# z2^KsF!7aGEyL1D=0|a;1h5!L>JV@hijRXkp5FkM4MjQ9wH15*aT)CflzV-f@H8X4G z`^V~aamhJ#PSvT}dskm%OsY1k{;yx{i2;h{zBX2$L-;bAX_@|OI)kDFueJUf&PRYk z1=QCR<wB~eMt}OZ8A<nz_y2Y33{pC&f`^kSFUio2pm_xVjFrPk_>5E}l<nQ-+PVhZ zGMk5+n}Ly4<3bM&#By0PCe3y#5()A1zfB&aINiKunv%nO(<fPP?iRyod01)a`RGMC z!XaC0Yw91t1K{4--gwH9u~Alb=7##}@v(_E7m*)^J4p==OSXA;f})6lU9CPMw7Zdk z^u40y7!u%U_#IWIW!OCeN}hu?d49^tkBp={3N*7rLIh;0fLde35S+$(B`7FJ<T^&3 zjDdxv;CX>Vmd)(EVv{$cVZV_~@>wRu?u<z(Wm?+nvh0a_VApXM>Y1HgnLxU`F~e!~ z$2oHLrj!CoivKL(c#qUW3pUjN;#K}_8G@2<fwS6m+>X{T`L~CM%cn5b!9ir9j47$0 zwBwV-e58xNzl5wd9i?yyigbL|md`#}Wvn2s<VMMArR`}<k`9=VknntO49Jo`6Kt@a zAAvQeE0n3=7Q0Xulx6y^O_#LZJaXj%rM1UZ#%5))g$Osl=4=db6tvFZ_9uj1@$j|8 z#?tReFumGA?SO&`K4qq*Z7>^Znf{mU#Z!w3;+dSRTx4t(6eL;?xIX>@KOZ0YjqNDt zt^{_V4#8rARF=%M6K_BRI%KXO<;Sn{@f#Md@nDvpw|92NdbJrKu)JPoAhgB)d%lM! z;%p4%a83g&0YJ;;Ierp%|Bk<u34%_!G&1=Foo_FO_$w+QieEQb@9Y}~T<YEFK7QQh zVXrqzWOEgVZTKe9`F?R7{Qi}$zP?5rC(F&t+pMCSf~)mMon>fJs3a-sDl{;6dHSUk z5n7oG$&|C93&>wkQ=tDWcv^V-Hjmk`Tpr@M)6mXA6Zm}5?@N^rguLvIU<YOCFgP#l zeL=Oix!akW>&Y=ueHC&6R(-1#lc>IpQko*3pEvBH7HPWwvwR~kMq8F!CRMim4%dV* zd|-O$mLf*|%_n0?#`_8EooyhD9JPLqdvfoi9a=#((vz0yi@$y7R-{59*P|izSYZIY z)z);J*|Dy%FupK&_N(M%(THj=om<rH6l|jL(vYHf-vaK@d@MNf+g|8`$8M|UPiAT@ zz{(sZAyTODb+cOXxoD@Ma$o~a8CGYd#}&CUPeVjMj7-61*+c+~|4V7hHWj)`NlzW? zPYLBI!N!x@(^7=)rDnvJR>U=F?QE7;L)Ns=Mj+qI{$jz5|E$<)pj3*DjU(pgSWy^q z1z=;Y@w3$px)pVR$t%S)G&gFgFTX{R7-eTINOpHIiZ@s-u9+K1Ce=D9;wQ7*>WWfo zN3=bCXJ}QFXEw*ndUkro@IpSQI#BeQyiH4~<J%9Xz*Eod1XvtEVxtE^tV!S7?*7g_ z0Ky`ZU3uLNe$Qq2*zZlINv0J>`<Fyr!^X|Cz;**KV@>C4gRrMS&ZkRU6R)^ghGyYG znuJ0bshLuwqkV|rm7%?sw+7br+5+)j>ea3udEAZ`He@V&Ca(bIa96bC)2*~R?=jhS zz^MXJ7`JjVCA@%=l_?VnKd+or#j+aPMoy&r`1tIK1f=oVy6`b1F603?mK%M=cB(&f zKbZx2V`P&O6GKDVnyo*XEn)8BUMeao9W3H#rR**I83Azfs@cMK!JbPF(?8RD`Go{D z5jB|`A(EpJ6Xei?5At)qG>57Qy|`y*XT|Zi!c4slfojowAa6=5f@)Wn>+@aNlG@tu zyQ8bH-Naf#!QX0`ZG<De*(I}7yCdzmnTNvO#0nEWK3khp?{7xU&WB)uo<VJGBFbyX zrsK31%(jS|phrbT;Cf3fGTq1Sdo=e+C8urLD1QxaevZ;bAf&7s$jDHAxHnyivvggy z6rd%V_?JMatIH?+;K8@B2w%#}z2UlQ6ZGEMs;4oNnv~AHug8JQ?ys5DF}hX}GvsXa z+}W9%5(1&Mm?Rxc7fpt&?Cn{)1LPMJ>TbeUWk)ket>Fg$Wxl1R>WbYpN5K2hm_Dn0 zF`r6@duP*vW~&k`X)$EkbO!#RkEI5Do9h+295_3qack}htnP0dpB$9AyLp`o-F06q z=5nmc;?A}E-m7(#7udTwyHIes6o>X`To!%2S%^iHq|MdX_Cdm8?oY3oXr%Hd?*_}u zzegx30&6w9`|$1Uq~qdDZwE$C3lL%9QBLdJ)f0i=fE`?!%(%z|_@_rp5b(Nm05J-b zy#YM%zmZ~{?P}%x9T1j}6}cmT@GX{7APOR{W6kR@bGCqwu$EJQP5F*hAD~^6`rI#1 zA^dZf0gWSMocQC_zNn8)9t4GXE}|X2$#@(b&c`+O<0G3ZP=G^EU`_eNPXges6hBfV z;ox<gqx9nAXJ_vKz%u@WL<f}8aXVY#HPHnS)h$}L=HHXfw)Lq%2sk+&uJ5^Ds96yW z)tVZ5I64|1vs!x%_-Jo>{={Qbtu#QVMh~C|k0}F(!1v5!vtk0YdwomVn*If4vaUsH z6>chIe5V4C4O3Io<KpFDNUKQdHfSab%3F;&j>j}7cgG4s`IaMZ^8nB@xUEu)%4}5@ zuaL>t$?COX<JN4G)Y=Kd`8w2}!LZRUGj1OTsJNGgf<A(~#M|<XzcQ9stH$8*w6Kze z3`IpL+uAbQGAqse{#EdqObRL>>(iF57{9x4Wb<cjCX#4<9Vq*oP-8A)Mfg#P*rI;{ zAb3E2W&hKCgV2Eb3_!;4`~A}&@NcSk=eyxgn8n1hSBgqXtP7P0!=<sp``LzK1O?+0 z6iQEkt<hh5Tb3!OluG8N-!WR-ztqBB)m)WH3f|zVWdT6xY->PPb1EvzTXu^6pIvN9 z3!6f|r;A2vM|pgc?0YVneSeg^bbGi*vb!u%emmhQ*1_k<+rkN)dTRp-aZ_zdCoOC~ zK4p@zv@mC+(1F|hc&em?u)^2V)dM@LSOF3^b~=`@+4)L!bKl9vI8y5pqb3O9A}6$c zib>>#5RV@B--x+wzF)$5YJB-`u=Am~@gB4_MQ$i%X#?+?SH3DU1R!X@T4U8uH~!|p zHUt|oc#a1V@8|(^jvSY8NIAS7(4e3Qt>g*@5WwGLi29DsF3)|D<5WhvZViqBAHEYT zlADTQ$}ZJSA0rAtm+XHB*9X{pM8NGmJ-}6XiMCKVO{3bHDuI9_Js=a(LrV+bsw|4= z>Uk?SbgfObVS4E$CX`;n4qB7Bn7-fGUXG|uOnp7COP{|kwg5XQMU$s$jEQ3Zdn|=g z`TzGEkOEJh`tKJ73%WH4GttFpw&Vvx9y{XWLWP+yK}Tv=l_Z_yA?F%)29mo7FG@-( za}c|lr~8t^t!HI-dOe*ZOKauB2aDqWOH|I#{BO?de<S&_GVtRsf@CDV+`wi;$Z5*o zblK&_>OcH~rZF+!%;d$Mhato>C7mjjC}fLiSVmqF(R>FATt5S1Q<yinOhscE3qQX9 zLx$sJVH(;ePATD3$z`BX(*7aLMEWlx<7YtTM>%i-4O7V<U96^1KyS{VtC(Cc?-9g= zSo5!v-WQ6vtPe^$DZ}E10H)!wum(qrJn-`aXmNXgg4_GhS>VyE6^+Vj$iI*lfX|ix zLpm-za29wFE2YLu;8h+xAbZO>K^5d%?)3Vt8u%|hWKTWv;(z4=zQ_`$GVpV#<2>81 z>mpdr`<r7GhrZ#Tc=h*RdM=AF{^t*e(tiIwr}RN*Nz&od6dSC7w?x1NIT0^1Y%n_8 zlALb-4iP{r1C{?jPz!W;dPT>?3|H~@NWN7FZ%xjoVkd5s2(bQM`$kBFu627XdCjs= z7~jGO_EnDW(wvrC+#Z@h(GybuWr3@jEIz2_$t_ay_lPa2^Rd!&mkz=fWMNihx~iF| zExb@GkA5!9Qv7pi7I>jz@@M;wc~L20uz+lj`!yRhmPpn1p=b96Wb^{JKj%Fy=hp0` zTA3*1xJGDGd&tD*{pn?P3H!c|;7k+L5qOJ{pEdeVsWS|RfoDfy3wF0Y{A??!;<*t^ zs$8yBsKB*Kv%h<vRf2QuoBN$17H_Dv_TwPCK(ifK^H+J-z<UW905$aBf%`)s@1o{` zJgM%Y=nJ)PYGvZN9#Oma@%W~C#Y`*;SF}EF^SkkD*6}x=7;ZoCymCKCgxb;+$@T^W z<Zct-ToLir2bh?yk2{QqDH|q~hkLdJo_3GxX{B+~U&&;GFH$=WFlcaE1k$r@v)UQx z%UcURb*bs_8&LiG@F$&ZcV9DgNyuFshKl5i(%f*P822|}eO359@0M4YTR`s)QfC|0 zeQHkZj5IVa54(u(C0yN4pIZg>C3~W4$v<0JsB~lDSCXgb&3IoCZ5D-PeN^BY<>9V# zx7`)nqRgtGQps_+39cbeb0a75zW(TdjNIq)|IWbZ<K$tez2fT2F6Qd1Hq*>l8Fh@_ zENqLy=|EQBvyin1*p#bXcgC_iAXK8O+#P3a4uwT%KxD)0tk_~50$g|DS-B-jW2(`D zu|q21O?9>k&i<HC-)w_Lfwk4l#7AY-{Hd_1i#adux)Uqai529{b4rnJxnxguGu~}s zWSfkdM_S@$Cr77cq|2BU5G9-~=$(G*>l0~wMd=cXSoW#k-kE7;7dq})ARvx0Dv9en z!mmu7X-1!=o2<`^o8*S8ITXs=-oFYAuLG@Cn3>zgXH(rDchU~3yj5FBL+~-u^lxdX zRqQhL54%|-t2B~1++NQM-7worIvb(;v+2=Ko);RHeAtYdmU9!=P9%J-H!XOL$&C`t zqBKr{5;{YSRTUFm^YK)gV+x;D{2=*d%3=7-X3?@VFuV{h)A788@ZwLk{QH7PnQ;Ri zQOm!xiLu253V0sH%HYdEfd^7aJU5jb@~++O5f$#RG4k0Bb{K2-yx38dSxF>$OL+P2 zaqN4UC&(Hws<q}mZ2G!VvGpyzwu_grEQ{#b9HAL=U;BxUXL>U?*YeDIG_tw6`RMt{ zVb|o-O<p2%TE1Q3_?6@E>?J1FfjwUHlB`_a-$z8%?jR%5^)q()*Z@E8r$Q9|{$mq^ zkx?vrw`f(RSX{9V8#bZ4(_>UB*2`$YXcxy(nwxn#?4w@d^YSpZ5kAff8=-HQ{1gsE zB=jf3hfdlCPjCxl!a_22)n=08i=~1mNhVv<Z%*-O6gHD9?QTXI5XBV<9Yo+nq(E?R ztXRvQgq**<h*j48&n9F$ANdTa?9<HVwoM`U3@dv0Q)9-eSPV1!kj}^A)beyt{`sld z-YmmS7xCK;1Ai54P68%-Z13$!gLVbRdFp%XR-K*pS|XVlMv|!xxoZUM_QkMvTeNa{ z2`Yo!Q$5Ar#N#;Jm~Mo$=SxVs-g)-z7Scm-CjY1~L?En#GK=)O*m;wqcEj>6Md4|A zm(dHHki<(w#PK-mY*!}&-jj@2*Pt1B@Sjykbb*#ag_){Pz+ifS;b_i)jn4LjOLYOL z&U>M({wUv@$=GCf+^AyC1&6h#e4Z>+_qP}kXJE|p!-LGr%cPKedZ=0Yd5ZWtGCoMT zbOW0So_3ZoUU02%$DYY6MUru&#mV=u!(iP@+rxA%2fuzqe676OT&Bs84kBf4t(Yn! zz=##=X!VhFaL#;hWzOc?`+~HOLLlXWgr{#i-mR|Zn`G~~9$L$+W|Cu!1f51HGdOD! zWt7g^oqnHL`IuP0<l{*>(P7Qc%EZmXG~T4pCr8r2v%>?$Ugoa$j_v333>foXiO<^| z|6_&-3#ea0&V=<|q}G`3_}Z7)*_p13<1@n}ww{OC+=H)*;ypZ8xL~pmk8wB~JYm#i z{4K}!eVF#sZQ5r=>Y|mPrj28Q`T4q(Ar6BykD}!-RoPTm4$^Liq<SWLe3THW_3@!? z(Y>dhsC5iMVKPtBgiG!p-Up0e5DbUsvDmca-a-GVf}bCa5Q=nA*Pk71K1zE<YLHdY zECbAj_#mJtNewY`t@o55s)Ed4nbRi5OR3#l{n@3v53Cu>?{+(j?iy|@eV9zNxen`t zu9<t)Zh4y{`oIxI;d9ZKhucYNTOsV-Y|Xqok_o6SQto|DUfxqbBRx9@MP&_#(wtW5 zj~W#Y!fI;SaUKO0$??#`@qWH9dy-Oi^Xb){h70i5y3^LvY{N+qBc6Y9Nok0+5{W^w zo;K6_yAitQi+73UjEyyA<vA9S*S4AIKW35*9b~NE;;PrR@NZ7&_}74pwzic7$;^L= zyuu0rN5QDi8Ep#3NjmLp)rAmf`yKK$?ZnddCU{MH7&4zK>i$kRKMr103{OLhU?jDI zXFW&X_8A#s<|=x_Pd*J&f|biNn+zxgsq=5M637fw;&LqC=sNgYJTioT+p`jcB0nUg zv62D%kIi$yo4kIVzLO5lUm42VuJ)XJC`{RgAQwB_;i{`;=$l4%mT36SJTWT2Mv<j7 za_>l2F|Mw!u336Es~B!f=eT#}?|?lWC#5v&+1ZDL&Tl`KZZz{8Y)ll1MK`rBL*l-% zGq7n1WcA4hwHz4-HnzSuW+CoRl247LRBzyf+Kn#NFcQt9?%z@$D0@?#-kewc{z-$+ zZkKyF<vLl3%?{YA5$oweLU>60AlB=%qjvUd!q2p1X*0hTJ4Wo`oMgJ%DfyP4SUL#F z>YWaKc&NKO2IUI2c{71cz!UFg#CEcBcj`HJIkfcO(MsH~9KFZG)dvwLmzU>S(;`%2 zAztW)5?+VsOusq4Jzh}}L1B&+;^;~S#t)@-nYK*;5A#7W2f#JUceFE6zx{KEEvGqD zAaC!mnUzV%xbyYRnhxP+A*c~%GPPkSrB<Hzj{*^>fmp<7UL=l+d@-O?(1&UHXfQtL zdw&N;HHc2E1<`J>;Dte#gr|V4nD`#_{fUQoHyj-K@%?}j1U1eej@*-G!4tT%oK8J6 zgs~KA@`WJ^-3%Hc6LMGDT8#1W?-$=a6#FzlA6ldxUpVcnt~Cd2O%VCw3cJq^`aRwe zGI>fnBtGbiq8ZLgYNAzuU(<~4t+rqsP~_xH&Tv*h=X04tD<fLne-DktswPc`kygbT z4GzK?#Y7}{XWD|rd>hC=?~E${yUc*EKNS3fC^?gRH6L9zsufBL1V*?b0lo*CPqVd~ zF?*w1Vp#hT5smf9ag(FN<!Qdw3z8m+7sMj3s27|Z-YIBMvHH*ox9|TMOB<}i>?Jm3 z+QfcuoXElqhq#!NT)%Q(CF0)tAk4=@x4i65rt0src~q!l96A1jb0R*I!u>G)?eGDG znUFU~cVWCYwM{A}B;ONh3?p!_<4;W_>9nY?a5D)cmOC>$SK}Ap!~WrH>tlI;@h<m^ zzhq1~f3+PUk1Ek7sfUe<vyp7F!qSJcAiWaZSgZ@RN=DY-MPY6WpYB)gc1b>#XOJUN z>dp?$$7NejG#QFtDAjmb_(|V%+wNY<X3Eivv<+r;(26!+Z5^u;Fw1Qm_~tT20#Wpr zsfU0oFmpKAUtTKP9&=1N+m4~=O*(fNY-ylAdr8CUiiiG$C_Fn5Yi|vHlmNs(ne=`= zsv9%a7w)0m{-BXx@IaSz{S${>P{m-gdZO6jgg6&DiG+-9wx@P)h;casvo@bmuGBwJ z*Wmpz|Hk%JB{Lk~haI)6m+br5dimbwr9HiMqkr%lG$DLjhmJm&y|s@XFV6iGU0=-G zEMG9T>=ikpzO2_tzjLqVCk}C8s_6Tgf%pd^kB?A1J{eoF8cPGbkW$kRi^Z4=p{*_Q zl)2`M^oH3Va7y{SAT^TBB74J;2#D3ep4iRF?Z6J<hmElaL#1>7#q_<|ag+H?2i9gT zq+@&9$60E$MRA)B;vo*-?~Y%U!>7Oc8u0vh#O0>Gc$l`lq@EWzd>q|ya=gR4ca3Aa zF-C;h+{N{&Q_!P({o;{fezDu=zt;Az<V`W7l)vc&y+5f3qY%nFJr^gX`CGzi(DtwR zYb9-64G$Y{g}}NpN1{IF7g(1~B~?uHWu5S1a7w1Zw>Ya!6#de}(9#7Nff7O~^Cj%^ zgr35_ui3gBuE*?rpDh`k@!5=*?$&F?f~Ui1uTtOTerrorHVhB&f~u<avWXzZdHi*q zCA8z~y7owVOqq(uv@ihg5`rq3&q{x#(qwRzA<gp2g1#-MhVe>&p5Y)wkr)>^Jt>w{ zF#ih*WS+p@pK9<|U7w!Wq2@Zol#ldxT7ezy$py?e?tILOF;Z0oAC8J$n#<6%^Z#ze z)D4frux6(=nzvd0Ghwzd3>+$d1^_2Fd%&+L)&&W*T2mR#pC8_AAcI)4D%uP4V*z8( z4&JQtG^un&RpB3G8<~Bwngr%T>%a?eh==UKe~f^$QeDu$8cFKzz@LHau)lgs{~KlB z|L;I3Ul2dZQRi(>vjZ+RqdYrw(R01K8NwT9IfWzmAeu7XJ@Y#aU%br0{=rJO>RG#d z#fyEhBI>I^L1XE*Ca=ByF%otnSt@>yJ99}+TnYhqS^-)^|36}7-&;+`hG>*k`qOIl z^2`W^jhcJL|AC8K$CeEeYYAqPH%L*-3R{XReQ*3V?{jn?rjyM%tjQcO(IlrVjs5u0 zIP}jQ9d`TuTBgj>+(+G3o@!$glcVC2NPujdf<E4rvC|~doQ-h5cXASQI`va^Sm0BV zwNTxB2;xzGfqoO@zxK3L{{5@bELH{vi^bQ;l}o-<L}mLk37ZwPFbg=oRfs>$=Hwe% zTWuqwD)T9hqRDo&KW@k+lPU#yw%gIRVUaBN!Az-;`+jd&WI)-<FKE4=eSI<VYQB~H ze9iiKz82GMZOQl!|LjiRWcmOsEG7O}2j5ZHG7A>L44DXdwxMgd^@$(gO#G*hz>|wr zlNHYku=~m|9*6JtpC1^-<gM)Om+^sVNTRkRVaUq7yN=~GyJ*_p9%>dQ7nU(E>?=gB zPp;&%?G2tks+o!haSG3809jab^L2L9SDZDj7t}(PFxaM*qm(%eN9TZlW-cX-Z0yto zKO42PV?X06%-%7A=%(E;M`m?fT15qC;))>FU04TH29;HwJnAgmxu}?b7NMqm3ppF= z#T8jF%mj)%L&oipoyEs#i$lGNCbT*Z(?VzEZ^L4ZBcl9KD{G%}D&=T;OpgYIF4&D) zKwyKFWxCYvF%pj5>Xla@00r9aR((i6JQGLgH*C-hg=TJUuZgEinO*wbMgJU8;@j5% zySO{&07)+e3bsvWX|RD`b$TStM7_0EIV<asA@=T6Spu}MsY{Y*5>y|p!GUGKCe?B9 z_#i}RTDN9Ts$%h3v)8SWh6V?ZwT<3JeOuo_m{{2#oLxIWvST2T{4M`3*6mV-7T3&| z4Ve-1z?x)0q(rP>qs?hgRh(SRl`CQV^gDrNg(&2uEkLfbF_lhOzz?u-uxY&>N&Q{S z?}%?{XlOV?HzN2|EXK{F){I)SNh1s<wL|cd)b)5i`qvt_CyAV)VP-@`geAKX8R_<c zkWafV%>kgW3L<eBbvZkA+p{y?6V>a^hp}5)tRp*rE;|*|qU4p7hTGk4E8^k;%j;<8 zO!4Y@x$jpkE0B`{LNooCTe=}3$d~dsL|8I&7nubK%4y|(t1$D=qg6I$_MM_Yn%(7x z)?&}L2W}+ZE4=`{via7V-3&h)OR}p|@9%{njL`+F+rOG@HAatWk9&JV%lHmD$d7;I zwFcqwdg{o{C?mP5QFWtLSbakV`DPP~LurN;A6Ym#IX~+|hrUmnklG-}NE|{#W%vbV zsf7KVClljzXPR^c0FgtP<cbA*<Zpd%{b!jL*)6ZU_}1d$av!$r*(GGP`9+cm({MEu zH`aO+P|M=#{Tc=7Xd<}^ZJ{F_p7icJi~(Cr1JdhRT8oghSW>}ZVV@0bh}CC{&AQ{0 z^&>BM`uU$DS09)<Go`TeQRk}sdXi3)40p~Av3kzUa*m7WX`KAi2Q(IWrUYBKJ5#lR zU4B~xt2fX&w;UuateHka!d=Y5eCtcV4R-`K^=@orf=C;JaMpmg>KLZtEpXpOgs#Qn z;vPxf<HW@+bgH$zd#^07n4h0$;lFP2Bda3DuA694f;%*ZVLcYFInDWa{%mdhISIWG z*)RiSR;S9|++*IPx7OT2hQp9tk;*9cGX?8weA}V?_x%qTSGlT9Qcu)g^V!nT#tPi0 za7<d-sTfBGWc;GQF?&@_>S-G~+bH=aMt=D<inHZ_!=FvrS-|z3K{bmAW$$8C6A6Oi z`Npr$oTL~lyj0I)5&f*h+1|gfqD-UCe(@Gjq?vpa2ACunUT<`(ev&Bby#?Up4$E*2 zBW+y_!zV8yr88I?Qd%{8`(gqWvAi~(j}tNhX*f)yic|eSf94u|u?(@o@JbTg-RS_A z9<)f7LkzHU>s?+AbJOwA*!JVwdQkFDe2*KBr`Eo2HQhP;`2zhU`(`NlR7v%CmOVhf z;p|&-3s;Xp={c)$Lyc}e=F%-tEp$TZqSvLxxDWS+$vt+();Ct1b_bxjk6S$VrqdK9 zr0CfSmg0tD>bXUr%g`y;b+pJSg6=(w>8MTz7jpQB6sNu2hie+Ku>QNB8LYc@)Ht@m zn(OpN_m|pEY-U@RJTtllFQX`s^uS+Aw>~b`(m)bkdlgA)y+ZoI!{0?uwx(A!Ow|Bw zw#P=+WIr4}C=^pM{X^&dtAOhhLAYAQ5MCMIo)Tg}vq?P!nrOe;Z2y$R5ACXI6c`P? zDrhqPv0z8ct`FI8`Se(Aii^Zi<C>who+(-#^=>ik3Kc9Dch0L#xFqIf$;oq^nR8fj zLQGCZ8qqTlq~@Pvpqem>ce~wJH<`47N}V|oy_4|2JGDLD!%spA5M3X(4g0Sg@!K{~ z+*tQ$qiM;=vv1a`wUCp{dgpV!`0Y2WZ#nAng2deKbg&dks48NV0%n{fn|)xzOE>6E z_bi9_;N@iK+;kJAh&%MSwypeZt;tw32gV^*KK+WcusJ#8SQ7Qj?>^Gl->|OD`SEZ! zJ$vPhpSV9dqqU3iz)#`&pHS-!?o_zp_v(euR#|V6%;eWG2A9q~#2&DK^FeG%%FMGl zyxUgO^vHZlj2I1&*tnC)HhS-yS`v$xFDj`r_S$mk&YSP_Wy^d^XY4c<?>;{Zxy9(r zZi+QE{d*WvqJ6hPWmi7UV)eYcwx8DAoT(usX#Dg_$tou<wolIZmdcAy*)@SFhmgkw z9_D7J{>iY$T1-fD-N#1Mja19G9<wh>7@B@QGZk=C<-ynXu&fRs3_m(f6r%tSZ4QK_ zXG2<ohO8?Wu#2eI3)wGE`{pE;-3BUWe4G#t{X7Ivxu8}uzXAA2Iv+nvkUy`T*iHBG zAk&;dW@}Iv$CxObnIX@%97pUv<lIn;OtA>5*40hV=3iyEezN5SXlz-ZB&$n&m1XJ( z-dfeW`j7*<p!T0r-hAsud^Gue80a<wW~)HfYklY-aYesPct7=(@oFIK`rc+B=pO&x zUP>}`B-!+-t3{WO;$l1pGkau**kGexgc)aw8lF<`T9Q+{z!1wcO$;LO>m?R>>Lp8W zcc`vQlz@-1b7(_;N;o-fcx&9_lSR>?Gx`2aB35*=>wrw5QYjpf=kD*xw;5KWOhdmR z{^DfQ9P>|IS2Acx8f+e`rg&|K${x@xiVhgt&zy~-WJ7VCj78Y<soLkhlCN}l=oXU5 zq&YcB%x=2k>39<dCwIF_QDpSxyOVd#`Ru{IcJ$}Y5JOVp-iT7a!A^3bsESLpJ-|IX zH}|2I3Y#&0o*SF~JIEiZd30HRFe?O`UGMmMK!JvLmtWXT{6b(%cC4mXHk5gCZ|1O1 z2YW}rzRM{h7vl58jhZukn*&8E@F@3iZg_JPL^)Tt#rt`q_-$LuliEDEN?1MX2~K3i z0(PpP|5lxT?t)N#uBJKg8dfb<D{PedqXz<T1+Wu(<u+BMr4ANHOuV5KpgYXAWo~+$ zg)62WRb<@l$-Z0QV%892uXpykPo6mvj#DTPt2TkOEflG}?v-!uUWBnsS6cR+=r}r} zPsr~#+H3I$9f~n5RLK++td=vdxMz?{yxOzR(nyx)eg?A>vgo&diMugn<M%*ghX|u( z+D{Qzd-^=ExPC^IFJ5*!kN4Nl9iI5FM_RaWpPXi97^_Q%cza}lQ4|7=z&9p~rSM&8 z{KBDDYrqx_*h_kxJ9R$lf3Q?GHf>D}%8Y$S1{K41yf61oz+}%`wFYXvuWd{mCQD_^ zM65Fp8hC{6FPF_`r>P8Qhwd-snC6l4rH|NrbX=<LewQF5a^uZp7m74G^}TcH=w#Vf zLFe}9R6HesQ8JP$W}C4~t3u|Zr<<~X>pxuuQBr&meC?st5DE2+wxernu5WRt|1LF0 zd_gTc!Xewaax}I@Jm^P?V%(ozhM-DuaI@RJPOLxg2I;N>5C&1}`A=$v@7$cNXLP8C zbFmpFV%d#b=5nK{^GBPM8U_bd7Bg7|URmud-k#EX++=<`Ty44I=He<s=N;Flq`eNf z=<%Dy;1>4zNIjc0M5$NBPQg*E^U>>b4c+3Z?5R$}2&+(RH07w{_&1{{?tYoR_r>X& z%OhG@;wHl$*j5?~X1%|ptD~nJ!hSeDbx*gjwCrJHI8;q>L6ptEb9a201jm00J;~ki zSL!ersc`3-&688hC)E40;=YS0m=Ft4?FMis+Z=9_1suVo(Q=Z5q88@tj-%tr{?)F> zc$6JK%=S3popAdh-ZvVTwO8xI_VzdF$`oARLcI+ZOI5DxD|Jhoa@S(dBd7MY(F#@$ z7H~FZzK$=dX6?o|6~{uqduKJT@>jP9zfl>^jlu|c^p>(Htz5xuF(n%<%En<=es5|n zU)Mk|LGIwqJG*c1EvcWsTngWCJ2Rg&Tot|y<rrCiZqxbPxL;Vg;N!4&`~XE-U#*k* zJCH!C%)s{wQzbK1eSF#2z7#S}Yws22VSehf<bg1%JASkl55!K8fC7P9l&^l{%XPGg z#L(Ds-0xD}{n^i`UBv==tZK^UYSmtlq_%#3)shm@M*3yyY3D7jO!g3{58wY4sqb<` zfu?FQKVu2M!1Ql61N3F1jBJm4wS&S0U4424v@rGBm}JK~C5TgK!01<jW<_u&Poc;8 zOi)LbxdtOG|E|Ik6=m^?>P%*wQMjrSBF}ausvy`=AjD!F>XyJ3Q$g8aJ+n5NKynq* zqrq`Ruy~gN;qA!zz{ry?H^n>kSjyc?IPK~R5eVjJe)(E55I|Zd`_HIjMND$V8tH24 zeFQ5fYd;R|B4O1v0)r(xZWQmB*fr3w`;zmGJrvyI)yULTA>tXgc!xTaWP5qLpjs>a z-kmhlM%B*!yiI_hcktt9OS6f|j+wbJSpk8&Jx%~zBXRQ1j%5%BJF?`X)#p!6N3$aE zd~iu#*<wfed@gg_d`2pCb*lF5b$k-?gW`Zn6pF8mrIDcddG()FYR1OwCNEd{`-;)3 zaKFG$y)DKy!@ab$Vh}2+w^2-!b}Uv~tBcJt2}y>1JPv<G>p(jKW4$Bm{-t?!c67SL znONVA+b=7L{3k4f@d~PsU2xNjTyppH_%7T$P4SgbbR<lzHftk`^uxxmKmPlQf0DG8 z^ionw=X>BSvPGV;U#t)O>OP%&DL#H^e-m^d)<lAC)Ti&awj?liEVa@k*Ng|wu6zZ? ze7HM+<o&}ziRx!GQl++>&~P<X^GdfkOws-7quO+ay0I_t?z+I_>)y<;`aOXx9rcWi zj7i2ES`g)t0;8MWnN6;d16feZhE%e~Yz+^;1))W;!&vi^ORkBTcewvubm1{dHj~ro zl&Dpd;ys8eT1}pZgZJk1vfJ!h(x7o0%+8(#=zFlm`qN7Il@Z<hsa-Se#k|TSkVdfR zcge0ShK44VM&^I~Q~7h$=sl+A5bHB1(~9JZMp~j+<UEI;p6YR1dnur4AFg}8Xw!n? z2bVbFrrzFpx?xV_>2@oaVU8|pH1QV+9&n;U_=nU3ET$-B_0~2%XpME9O?;`rfGPi! zHvb^`l52f}mV-_-EL?sAXe`t9k4cReja*Tk(CR&IA3}S+?WLu^S`R5&@Ploo6Ys+3 zW5tvLilUm~GAL@JjK2_Wj^PD*XcRviUh*)(82+GD`)>^!wCUi68jpB~2OZmzQ`5OH zktQT6U*EAITKB7;61ryW2V!Nal4IS;k%uB%Qdd8ZA}dtS0qk62SoCvTOEpRvcOKcc z_;^iT*_~~aI!_Gy3r(W?WJj@Y*}dBwazG~LKe>R}F2AcZ!^E1f(*q+tZU38HceYri zCVEyH+sQ6RwFBezZI&z6>57Xd=+_-SG*;c`Qk!@cxt|rzIxadcLo%_}{n1N5#o6gM z?=u;uGd_Q|%4t=1cWaDzdXwlZ)%$!;N~f^IMa*Y5?|SOa!x{*0bG%=IYYHZ=-TJA8 z4KwlVZ;LZzeFGyd5FN(992$kQ+_-e@E?$u`t!nJ%oVEJVSd9ji04WBFJ-g}Z?B|&} zTiZ7smcm3+B<yJr_S4a2g5(m~hVr`@Vikel7-reo<+I9@3LW-QC$Aq?#?0)AK{0qb zdp2D0oUX%J-2lx>7y#EK5|?|BxK8*J3rx?9C?eyeWG;Gfg)8Tu=XreEL7xyq#MaB- z(qIl2EnkS<>UyJ&y%cx)*Ik&OJn~R(*ZloqWK8KdWJ08*cJ1Df@UxaObnf^%jS^6L zLv-AygnCl*QxYWq28RW<w||GJE1=4r<+zAI@eO%(;S9UF&=$25jvCj6i(`VaIc|57 z#&P?&(1r&}>tVt0tJh>(mYW+j*^;M6lJ^(elkEisQGL+UM}>ki=f>HuYx_#<9BrAe z2G&Z%Oi`@HHL<#>3r~j=Pp-J=aV^Jdn*?R!>mcrM#pLm=wOnMVrk8hN_E#dJ%9y+r zq^6m*r#JNA&3gBjikVP@nUhQ1)AE)Jl(PFOwGx<(jp6jA+A1tiQAv)|)zhh2UR430 zrP91;hYxzwmX5V98i$d$P)E6uk`rwFY3)!+FcPO`ybox!cy+S(AryY{R5InNrRRF{ z&c0qO^Cd}=v$k5|b4UCFx4Ug!%B&Tn78^5f!ZMsSQsk}410(WN=KunYv!GHHbL5hg z8!CzI;TVP-HM@>2vum?>zkEQI#(GhC0H`SDrpjRxh6B65>ZTV9I1$xX*<C2VEy3ZN zUL*uEY1ay~4Iew}^xvL}O^`V*`HlejmeQ~VJfELQN{lZ?+)c<n@bGxJx;MY{>d-Z# zPWwVUUJfEBQ^Vjw+yA<g%)8p$R9g8R+!qIKGdtPocby_4mRldjZvV1}CM8M`U*{%M zZyI6BTN<JEJ7T`|fHB`0`|+nsiUW<{csR4!b0W{Q?4ArV42yUZ-=dy!@l}32-rsGQ zHokHjy}2}|{Kq<LSG0V5D;LsX+@7j91dc5z`g6=LVG^INfgK`Q>O1=Ot=Lhykck_e zg}pgPvEx+8f${)?xj=gl*?B(@qQ9%B;%(_n6i^NaH>*Rp;6g-)qE{QSxwkD`&^=T4 z;;p;BX2Z<6>jv9}UG$#1k`m6WEfEosN$fjckGNB?f}%o)=lxrus<JXE3kwG=i@A2K znjc~D-QlWY`$|vOfQB5@gy<C9NS(s4=0|`XANJ$a6X*fyiunm4Y<6e&s^I~DcTb&W zw;aDng;}}H%0&y$!885b?McvjF2V{NY!({FTlAg0VME1iytWn2iUjf{SO2C<&c%Eg zzs30nUdPn#h)tweD?thi&70|7oNtk4<|7ZA5P^VL`sZOip5paBy8*;6E%J-ID!Z50 zs+F~a>tgoJZdUFRXj(loQGc|}!9HaQlb`nQ*;c0Puj9|$gva*hAX~~|^@CdN!C)%P zgMd3FRfmU$wmzQcU$t4&)V<rcsarjRx*GNchKl8gj_`0(5|+6cJZg&mAQYhOGI$tV zTB8H0L%-fH@zH|us9Ta0uCH$sD#gqu4b1J7NlW+HxBJ!<9Cy|o2K!n3&K|zb`i&Zu z=QLpZHt(QGTCQcG0ZqbC$5#i;7(h_+a|wAOGuVqA2-Cj_@0FY6hbjsVmf!9nFtTqN zfs}4(VY%@g6i6n*aq1>yI&kJ{?V4RyjUW&R8X|?C4B^O5y5tn~9v_bdNG}E%yNl^u z8p~R@KJH$rDV*+$rtlYHY`VXVO76E;1rj#>t!->f?XB-n*JCq`zHT-IFBzLu^dpOK zQB!Pl{kf3zjRm1PQjs$nrilyGXrO<$1_lIvnX44A!0*37pG3T27J4oUIdW{UDe77* z%@#APUGtQCDg+T}Q$^yOx{YeDOO^%MST7n?w1o}>;@<uJL+KpOPgs+CV@W3)?o+&J zFfa5z*tTxS784qJu(Ow4+MnUcYHlXX`)wpUF5aUP1P&l~C;ByFT)doz=T4}_5_c^N zKzMLC`+mOJs*_Mw?_{p}I31tlUUf8@O(B+SJ`#>R7V(~~w^8g!ms7s`LYK4i$C%Y8 zUH0yH@Tseqp6tt-#)8wZ9vmjtDrR6wmd-~wINdu$b{H>ICKr%@*)aT$N6F-imt`{c z5oDY_c^6G;O<fKZg9x51RG#6UrgNXh8z32>U#Vsx)Q~fM#74CC?M>>&3?6D}@7LAN z<Gvx-@$wg=Ork9N@t>~fg5`V|WbKoq(g`f0vg-*`!+K<_#ocM&Wad-VIbD4`)YMsL zzWi14NUo?^XFQM_KqRx~J!`)>oS6a1_N#qx9>{qbn~hI(&sMG(Y0++HrER3<9#(<L zBV>`rcb@y$Yb_BU)t2KuHeUBX7tNBNpy%vOC2&$De)cs{nrJdi@+O&jD2?+%iJ93I zUq_Bf`Gb~vdhCq*9G-LIJpNsC;6{ZzB5}^Z-$!sK;l4Ka<ZCVgi6*qo^*ZUqGN!yX zH>IQDuM;T0Aydol_^L`N^t3iZ#5)o0sXolMmxv#{9PAU7hR%(wk&^KaDUa3yPPkj| zY>33Xg7?Klo%egA!n;Y&L@D1i1>odHT=zXriL-sbumtm1c_PaN&5Nzt<LWusTYkO6 zC5s*?<~4naquOlX*z&;9;@Z$+ggU-u<TK$1WBdfa{i`NUbHAZKL<3!-E0tj`Nm(nq zjVjAV!oRXz#Z;YN-llVbc*7qXe<-7KNlYdx<MD)t1YoI}Xkb0&G5=k;=zeIEE9v+d zZ19*}=St|YW@${c(($>Q`8J-Gw6^_hgX78Yt`w7VW}91N+Z!Wwbpr#<m90-@`*kSN z8SNyCV_W%&{9kKsA#;yPrJ6c_t1tapb8G-dDk(cV*MdB6GdJ#q1=}?q<6mKw)~RE- zsnBq47iN~%-H7ZK$5HOtPggzx&psmqyb<5+eWy^ublB2;I}r4n-^llS5|sQhw|20x zv->sv$k6-n*eU72jE0?-helK&+MgETnG9nlI(@~~u%R=@&0fpIeXwGadu(Fi5fhov zcJq6@R$0*y%<~;iK_wP_eC7;$k$*gM6ZB5-H#z*wStrLuzc{YMqs+xeFa@9hp}r<q z_^ypZy^(%JZ$veaO8O?Z&?#Uy)-Tzn;yO(|VPP7Ynu~^nhXOlt!~Zlcwd_7kHl0Q& zOj*|(17oE0lsB&ABvyCOp6%XRivGP|vmmw(CO2QAU%Kt(dxLfhdc*q+9`E-me>RTq zC)Ka;G)13VRa<IQ8Q{saXG82oy?A~zn^)uXEP70ou?VXr`0*veHiB6NlEa5B()hWE z11RahGCpZcO$pDh<4LTQrOx`~HB$NWzpa|<7n(~HD!T7*cHc|^B}}+2?*3UQ8!d<@ zM9}~&mphAGCzo(kqnydL$HBCTu22C|s%VMZW)Hg^5~6e<>%Tm_)LN<T9(-T)BW!r< z24pz@q*&k1NvE;v@nI~0parCV^{zahc*^QwJokPf0ky;Dqi<H!M{s`lo!@2hJD6U9 zk#vyE+tX?)kGIePD0<q5{ihy!T#5B>BkQvVoo&2_>)^iy(f^OSX*VzX^j7{=9#g0N zE1|SeM#S+H_Ze_sb=r4NV6ze@6A}O9_x*j4IMF`>&Ckal0g&8(_|gArxq$=!G5amf z3IHtX-mSd;&uuUy!NRsr|MmlRc8gp1TUBMET_cMSU?82s25Q1b-o%X!fB*T5EQRQB z{C`lwOwBrf!~seE2kNn1@hQt3>O#-<-Nk?NY@7`ID-Ngr?oS%%qiN3M$XKz%vqlS3 zSsk?$DO#_8VZiSj*M*s1lJF&zkY{w|y~5mn7WPupV>1H&SBLG(J@3n@oFK~(Do*!j zL>JA{VHN_zNqvl)5r{@p(eA@0)7;P8z;!=6sO1Kh!$}R_>ZlED;WRZ~nNb3~d0)2_ zY*LC6;DQJ0$^Sp~7yrL5G`oLq4PpoA0+R1uh4=ginvIp*y?oSYK&2Ljm>3%~&)EkI zlC<ih0a&xN5@wkLD=V`th5-#ej{ftpub7Mgfl<G9pcyeSQ8F1hsS`g1=Jq4lkK(U^ zdilYCn;P$hcZnOv{`(T4jLgi#1O0p)yyFuRRgHMSy&vYPgF83p^z{Fo%tO!AnI?3z zj{#LOFi|*@Ngr9*SlDE3{<bwz@1LCI>?r;ib#OO9225;~$mf5B@6@|{;jN7YQUA^? zGy=OFAnc+4Y7joK`ec<;Sq78p3=h-;mH|<q{8#;dEeos|)<+N_{eRllS4j~=Kc&C$ zuAEndsb3}EKCb&RqRad!_u0Q9hB=!5#foRvy(5ks)%t4$e}8l`OVyM7f6?*%x^XHD zIQKKqVqjn>p8+jc&CSg@?!R7MUINm48+EyRdF5td1Ox;C0pB|3$Bz$mbfG06K=i+s z6}}3n1MekQbM{kz9vT=>R#mkyiv9Za$t+vZq@tptQM+G>aMr@N(j{gc|L%$01qq>$ z5=OmW<v{c8#n#m1<i8&+9u184(}=9(HJ}Bq4WJ|jsFNt488*4B13kS5#7yq*Zt<yv zKb6M5S_T>kBM=B4HIIWuky$~H%jqgJKmnrgA$B5gL-TDgptWZod3?FDVmixCN=nMD z{4&9V;KYZ5-|0(zWC@Sp?R1T0?6H@P)9i~`iXxjeJ_E{G%34rLTAm8t^XCN#6M_O} zaRLE%t#A+tuwnve-Jm7-_JyDE0R<xq3yaBO4I0@pKQs!a9IYPn93P*W!}JLVQeIFh z3i0qbkE4+T{M%BV3{Fv+73}61!M=M~tdXB`|NII!KxOM)_g5@}`Gtj4K^e<<RaI5M ztbYbP2Gq3ki(itHU-#2z|G@7t<%kZCiYhP(2)OT!CPx%0D=Fo_qt$|R%$xo<7r;Qy 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�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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/settings-installer.png b/docs/img/ux13/settings-installer.png new file mode 100644 index 0000000000000000000000000000000000000000..57258b8ccd7024c9177bebb6fb1c039b166594a4 GIT binary patch literal 179464 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%0Aj)6*4b^~nnG$+U)Z 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 &P#aC3u7#4J!=m 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 QICDl>UR|zO_Ic3102qLQ?*IS* literal 0 HcmV?d00001 diff --git a/docs/img/ux13/settings-time-windows-overlap.png b/docs/img/ux13/settings-time-windows-overlap.png new file mode 100644 index 0000000000000000000000000000000000000000..9dc9ca92802dad6d422d15ac1cde98108d80b001 GIT binary patch literal 227915 zcmdqIRa_iF_br-);K71>aCi6M7A&|2cXto&u7kU~JHb7;yE}u!pl8VU|IT?m_ujYL zPxG6u>gwKAwQKLS*9w)F6-R)>f&1{`1A?T4$j=WSAkaR1fPI1a1pY^0d8g;Y2jmZu zB7#b;>8ERuTDS+e&=>xn{dmxli6P;fT<(9m0I5$@fUVXit(A?fZQx4*LMjjk&BX<Y z^x}<dVLwYq2)3Y+Z{zZaKDq6FJ%06R^;(C1wft185Y1OUUqX$Rmb%B*&W=eKhA05} z%BCnkzi;n%Z7nm;A1XeCrap^4Nl$M<1v@6=?Mo#krRGv<YDzzFOCcCglkin>w!FL= z<)5x+KOrNdk8;ZBD2X?$Qquqm(lq<)>p9ob$JXU9@2!V?G&RI9;-qkn%_XQM#a?}2 za#U1g>3hh-(%;7w`XCsaS?MgMg4jbkJmdnP_()uIszu{~8U!AQD8Q4Fn_fXv(Z2&y zD#4AKntEh{fsuXI;9pM(DlsT`x93j*Kd@9V)`)cE|Ll|$Un*h0_e1^(*F%~a1}8-R zS#~5>{3{xhV;1WBa1z)zxAiE@M7G-)aG!5TKfO1Oi541CqD0PJiBeGBVt)TZqWmAZ zF_N=Zs!I7n-T(Rx4Sq8e+U!Gz3s+KB!urn;<c67_dx)*UCS1D~c^~vj0S^({7u9JI z<-GyrZ$FBE4I$+({@u>~0GIjRObG4!e;yk0iPDw$eLRH^kaGXVg_Easb-!C>U|^`~ zlQ=M!g@S_G1MqQiagnmt>-j^SjxJPfthRa$uB}xlk75J{1_nptf!~SS>G+qi`G`_n zLPEk&@!@iVIWxN7ZH2zRrM30ne})X9!r(m<uw`UtM}&wb6lkn#U}0wOxwt8b$7Q8d zy|}r^St#EydFs0BwN+D7<A~Pb^KdUNDIs!we2M1jl*@EHTIJ%RYWeC<!C;d$SGKU$ z><uW10kHU-Y;;XD*BJcABuxE&MancuH4wMBtk?q9Kf1iV&;V(d7l%Ot&JQgc;VKmx z<vK0tUZCBhnYl6*B~H;BfD-5NyA6iAlnd6bckj3R_vu!qXIM&8Qdq55Z8v|vMl`R` zFfmOH47jh{WxPDzF|k$H?+jGb7>EJa>wu4uxDw12>TT;IBh1v)+?<@dvn4ap1a2>^ zdY*1lceh?~3F+mPm7N~<I&^du{9f)2W@}*?{5(7!Gy7H_Z6M6&%6)HA#+Gy2<b{Pv zczK^!LGWy=YtTqIrdC#gmzeZgwRLro(a{2q50ri_(#Z^}E>5C@#Oq;EQCyA>67ur4 zI|GqWh=;*TOg|~nh;a}0_6+p&rh4-<BXQ0xLEx!daXEDdT_rX)s?-(AJl&m*zfZ`n zZjQZQQA$b*zZaC{MrVOSFH}yBo?_9<PkDJp&&5eh1|43vD_Za?2aCH<hzBQE=>V5I zpt}{vQ`vO7ycLy{R<i}Y@U5&^Sn9U7^<6kPG&R%glb&yu>aGtMaImnx;4KQ!)4v8Y z?I4|Q%+yO7h_FCFAyz2#T21-6saERf)|fZIsSZpKY;>G}w)bd+At2BKIW0Fgb4+A2 z7@3$l9rwZt0!7u-9)7>R%+Ae4;R`Hv5&CaZv9UEsHxXD{SLTUDz#zh6bD58IdbQ2D zw!;d@2z|Jp$OXN=emrzbe_F6CM;RgH--h<`;_Len2pMRxU?U+dH>kn#zSKdl${PD- zb0d2dnhky5Z;vY>pl;e+fFHNNwzoSTUB&i7AJ3K1@Y!W7H}LWS_xAVL%~mCtYsF+- z4$S99bgyuI-aK4vYFr$i_)!Ee9FJ!Ky9o(h2e17*B~dtByzK0EcV}(PG!cvzqx%S2 z^i7I`h=ScjX-$?HPYYRCKCeCfG|BXb$Hx+K?KW?Ms0KT0JTBRbcV{c>EhnJ9dsv}d zlZi}^^^VYo60;d{7ULf;UU%tf3st+<pml!!gTLwJibd@ER<p%9)N+aMn|i2AXz#P! zVg0tfaulHeHV#G*Vsl6c44swL9i0X4$=6s#qeQJX6}sX3&6v)Su`&HV6y=%1NH?HA zdY|T%9|dVEGFMG+CH-F{0)G8q%?5LIVtc=fkPvn&4aqP*_lFO!8BM=p3zPQet#}q= zC8|5TaKXzb;EPH)#&}TlbB^~*D-1NsH+GBp1h7k!QXV_N#Kd3@4DA2(QBkSSQ)OgC zikkXMa=1^TD{r9j9wsxSP@()EG&n%6{{BjSd0(+D7CL?2h@LBT*tn)VB{EFFryS(B zT+BeCL_tZ((9u0xF1+Wm(yMVkl@fdEo7D-M&1}8H2;qa}Y(a>a=#~?=Xs^+}z5vi? zqlEI30y4e=dCzl+i6P1)?of%IyxN@b$cclxUS&gNP8yccp~>pLq54@RN6y+8$MPtA z9#e~Ob0^z39h<DdBH0Xn_tS?*gf#HJ>e2^&1)l}f5V-}pV?P39#xNC?0@NY}n}hVw z(T(u&3+&UiA%)2KRMA+xo{;A*A#(-3qZJf&+j8xtloeCbP#`g(3RC0uO!f$Ue8o~w z{5v(Tq^hD~+=-ot%8M`HU8=Lj4SfgH)9rM<j4L4xOR_XJcYf=J7#<xOqI6Rvr=XAy zB6M@pR7<#Jq;POxIm%6<)n2c#z|_=S;duQRmnqKQ^^J)MMcefd`3pR}czv+I>1)FY zd%0GF@s?lL-0UpaHG)|C-P}ag)yGuFY|$_<3JR$$ENDu~l9`mPKgI(_J)_;QL_CJo zBch=46!sA?J-zjutqFwr1p<o9u$MGak9n0L>-@50_WJDH-CH3cAw{<nCQcS?tk>K7 zmA;BfpU=&ZeA_(BXv@SBlUx0(-L@wKx`@Su>-#gV*;J+5bu`tXiQNxg+fVxynkkUI znVI)f$|lCf%U!xz0Resf!BLFc5epBn0&?lR=)Jyzf>tXo+)j^Qh$%=3WMs;eD$K=W zQHgeELWwDM(>vWa<n5SB71Aj<9KY`-TzZMg($3=D4r&a=PcUQ;9l?+O9qu(Y=|o73 zcf;W`4=6h5xWjKVEiThkQyWWRvU>Fs{b3|uZzwJv3_dExpKo1u!>+Eb_Wyz$)*d67 zi%#bot}jt3OeO#)Cr^fp)kJ(At_cd3<2Y<8m1^wP&vMG8DHqou4;LUS+Wq#~N}I!W zz8Tna$o!BppR4U(?J_pV53jr45`IdiRc~}1w!hgnGBN_Lw?u-sh1_*z(|MZj2xVDu z!g-f41BSiq+b1=6<*0~P9<7Ok-F=qb@Lpq8<t=ac7Z<5mCRmmIEJw|+@X(63wjnt= zzIr7d{+*t~;DZ<Jt>;R)hSPqXZ(PShY1P~6{P^)DPI&M6BgV~O2f`P7yUHN-{6T0a zD0K~uYB}$?pdOOET#LE#935l(G-M%uIKXLcJ!{K77doa%r+3B9{(xudb2F#6WqF~$ zu&imZ_1Q9EmY}Gpx~}eHLP)-vRO9MX`qe{!_oXK;sxtm<bdyiF9i$jH9^bhAs^`t{ za~_C&pcIF<;OmYuXG9Lh^%hmu@X$!COBO2qGD)6(I^LNyE2@#Sl&r#*{nSicN=l#d z7S7=bOCl*XcaX09ru<wKsA<!lt93bbOcfnHP0efzmspU3Vo)kNom!<fEKCYJHlEe6 zZscvo2@i2_uD|6*{L>r_K37d3hxKd>F@?}jk>XdFT~S$4PwzjgEj9<^@gVEtm#3N{ zS*E=hRJ`ZMWZh{`PdFCl+&dt{1Z{C#vHs7`qV^<3J4iFo<uGkmtk(;COg;o*qdPwN znl^)xyQ(O<l-+gPKZJgiM$i+Lhi~>WFo$)jQM@5uLPvYDTdm;ZV02S%cME4>R*5vl zw!5QdAGRC09=<#rUb5umpqL#U1xF>FU_F#OpK^srRPrk7bUL$;(rWE%8ri%t?Blk& zyhxib)rzLg(}4p=kSyA0X!;c~ab`4rxK`|#3&_q6dm_t(*CXk2yT8pI4zBk3C2(n} zfI_y#XQN$LU<DR+wxVK9r9z)tspgaK>G0QS$S3Qf^DJYYy5!*`Se0kL?RcFdvT$nS zPX-_=bwbuiS8U|oWbXk%Z$T!%()4E}ztrl0PllzW3@A6>0B9LMA5PZQKAWEoMXVB! z4Pica(S9+g{UoTarxnWf6=u}D<wd8XM0@586s|f=;$Ux&0w*zuAVlP@B*fI&cWR}< zR;5}r-=<7S`voa_B)+xg%L`*{>=ac=$yHKjM!Y|40MO!LcPV^J_>seAo{<tJgGtW@ z!XLEl5fsxeQYCR@pR2Dgos5l{_1iP0U7XR-$jHRdFsZ1~SCFV!L|$IP-92b*xwg7| z@?vN+#&(vAonB{OXmlNta0sT=?MT$JBwAK*HT-&EBcBC*5WsG*uR8JD%gx!jQTa{O z><9Ri)UmUsCy7Bx*$oQ9X|gCfJ56`p3ln{NC0iedg%y-gN=Y42P+cfdAQ>N}aov+@ z|FY7our?yKHvN;?XtvYq(qv-4-7EY#-uvZ|zr#Zl5eKc_P|{j0#d<uIs7w{Ju*iao zd!!gpTN^ivsc-*4rpQL?q`WtOt}(z3w2o<g;%+lXS2hWMn@CBbOK)W%C#tZ$uTYAL zi>oVGj>J?S2J~EaV#8!wKNvNXQMnIo6pjuL66Blgp`Wz^a?A6T#{D=P<W6_8wKigS zfq(EeVpjJnHA0%i$|FPMXxcZ^a!LxHC*&3Gdj_P3+pO~qci}j6WGhXoa;o~>P%@+4 z>g)qe+F6iSay*5tu<t+S)d^}JTe!UEG5is<FeI70K2rq-Ph|@>P1aQI?HdkV$p`e> z*IviTF)@yhs|8{R$HYTwHSX~~zvMME9=A}7%9fY04o@K45mZ!F>uMUg9nOF1|73>B z<nw7c*i`WT_%<@Pa*T7lU#P6Vv!hzE76(Xt*-m^5Pqs0ivyDH85;SbQ|1;HO<Ihr8 zE1TKz%f!OrY78VF@GVELh0BeSg`8eTSa@w@nwX8vsy8WvYpI1_E;BGFs7={LQdV-w z<Ki&B$lF)2`}X9us|rJU)nU_AO3K{Oajbxb<9M#3fA6^q-f5%T09H~mI66xVz{F%n zSaD{sQAD(bqLHd`n9;{dW?oj7*I~Mpy1Lqaom}|~Yl&Ix<~y+r8kt2jW#YYs%aR~P zBajPN^|PX}qx*@={!?X@hTDT+rq>G8Jo*Xh-?0(UJ^`;NIB~1j=X$|!bvoYMcwSUn z0?wBP&MN5`=I_N2iGn~jn6$+W2EnNSY~~*f<TB>ASNXfn1Z7*jkl5HmT!6bng`3wF z7i9`LZ+83quuKA}>MZsOUiA0{lR*XJu?-GgqDx5cEjJbqZ`-!BI}56c)dncG1#x|| zu>pzbpjIqEEQJ<_7}}PTCRW&?l(3Ats(;-hG<<|$l=;$8!1=A{1S>r?eWt(=8U#VO zP~COddFP1relFX1FP5MzkSs@n6H??r0Cs$hYgj{F60NC%JGq(bB7Eb&Sb%pqnQ_)) ze{pCXxzwE+-pG)Ge&pv*zU@?5ppH`Q-tl>{8|jjv5;e_m^C-u^r@Dp3C1v<LZg<mj zY1-V4k#axqc&no$8w&E`UoI67yq}EhL+!7wu91KKYELR8uT>0Bsw_R)f83Y(CKQuN zkiq1e++?Gd^Ie(xw}jkiv1S_-`L8}EXurm(UT6l*2EB*PkIFwHzJ87GCCP1dI{)qB za?ZawRiWsFIR$k4<yRddVMRBdy;(g)0@c>SEv-sIN0(>PBpVVb;$d>{TU`xvU`{A9 z5#s&&x|8hJ<0mS;;91|8!PDq*c(zjFMZ?C%77#~fZegTHPl>jBaQ*gd1tlgXBC=4a zofni=Hg={pKu<Y5)Zjt0Vw5~Vr;&7Z-N%0$k)oEBSJvb{Xh+BGT&edAJHeN|8Hz0Q zifT_n>?$S}lFnFetmk{)*j`L2B5gF*Gc{TLbVTvi^;+ul%&Evv=oR*<b=rG{u+6a8 zEtIDlLjT%>{VU`T^HM43!j7km8H`FGK~O{r6-yP&5ivB&`gA<3q<YV+rJ(V7TXUi4 ztxG(%sY86-=f~yrQMqfdS1$`#=llGlD(@<G=FzV1(9SE+Z@Vu-=mtWJ6oa*t{Mc2n zMp;H_v_;IQd~;OQ28X>ke4Pm%zV3iQr>;BRK$%BG7OVLD*mG-}?aSfO@p8z9y^GU& z+na<=2?c*&KiL)NIin4!mH`AANL6xVJ(tmRwu*_08SJL5U0ULu;$HHzpOcdFW^zh# z$h)AhNV%aQQC0G@!$Rdor=8->3N8Qukig+mb(mb3p+n*F6;^J;Z8~4?eEI;J9}p05 zno8Cc^*eFTmeVdaQBl+Jy1{%sg$i0Ub2evZ+NH-b@@!O=U#*TZrzLH3xc5TKDfr{e zfOFHrFaD43pvD!x{I-2KJpU09hiG7+=+Ao!Dm%_xT`f?`4TaofcknB}VLlcYdc1c@ zkK28^HGly6fSwD$Xp;>{lNlD@ASxWDab2JuD1aTi5$!j>T3<^UB_GmPg!fs)tTV0V z;=cXdvz^t{;o)3EegAe3#6V|qI%Atpm&R+N`bxCWE@-@bJn~7<j)vn5(D9meB6Okj zjrQ*d!!)`NuuA^bN{*WF?lk+PR9<DD1Xn#-%Q1#*OHNMp02H1~u*MyBa!ua@MwM*) zjU)$b`x3aw+M;6AnOGT9nC-MeFMVDv;f1m|Y}U^gy?!lbztaDGn}EofIh$X5A_+!d zWnvdu#lWC{s&trgVGj=*h{mRWA)|0yDH-DaDx1|2qI^7El2H>&)OsK#&=~$QmmpPM zVGiQnX~qlWUSY*+jmW65`?d6%d{01}YEQ^!WvY217nYv#c8ahAwrhq$$uB|(Rn4|< zWRMWcva&)q;iTmHoNI&7moRC8)WS(!KH!ivG7>ir5$_i~$h2Q+x5+{rSX9-OQt#HT zd^7}$!)eZYfw?x2nL>osM)h+avs7pYp7usLwb>NM+(DK%&Z7(HmK8yOaO*5rt8?uy zs)(sz4O>zY{E@3=8+hLlF|=Vv0(n&IeuvZaEFutwlSK|A6N8(Q^d+;oc15NOv+87_ zDzK92`4%{nm!18MT*WcZT|!MHhtv4h<91*whnl3-fSgCe)8ejd;q|a`yCms{`_iHs zIN7ghvH=I<XFRT71Si%!ko<*v8NCMYDl+g&_jkQ)>)ezazkHRLSHXa>%jCVLQOHgz z6jMnul}SuUh=IPk^!ghDQ9?2(D{Z|&PsdGPDO-VKT&Nr)2?q<C%%KjlD9b6#j0L<* zE&H_waX)!9Fb}UlUYRY{<FI*n&fr*A6#gZ+J&HvY27vK95Pb-<T<yRh9$%_EPzPoC zcy=}!l|nya2iTRTD$DE(4$}oklcDK!EZ3{DMsr19>rC<>`}^kh$Mi<X(SpjgLe-US zZbUeu8MHOLmY4zHl}_c}pRBMb{Fa_*f~s9HOS<7@p{eNcU6F72^A0!8ODl!(?Bh`N z=hqtoWy9BcEk0-jB?2lk^r-3I#*eC*!`_C)ZIO@Z!ZkWJ4qvC?m7Ar!a83}+E8m1Y zdYN#E>u0&#AVp8<b{!tmWLF8CjwH#GlvTYcWJ800k4Ss)`dpUk0^caWD2n4C7CejM zXXL}Iu*gUbHa6_pE{<v0!$yz&`>VrHmJp*L#8cH)$^gY3F{EBCtnXUW9n#R{4gMW# z=U&0AY-}jD#l@wqsxGma1=edCX-#KhS2TPi5FKWMf`qF*1tleV*;Ucr^{ovSi1>>p zgPFqK3_6$aaHVZZGcz+XNvIec7ONLSp)3p=511He^QBwlKq`p6s*1F<>vah6)ite= zO1f`7Jf1g7B1$(gAHAd)6uQSyrTg2v|LEc}CKgN+#7TmYv}+Wn=KMnDy)I=HDFttD z9mo2@j*jAcY05D~#DVIsP0aL}QzwR|lrIeoj==?n!>>KsZUGcw8m24E!0&JoJ1bZv zr6nU?aC?i93UyD);5c`zEaX`LaX=@9P71V(iP050;?kfLKNdc{K5%jNL)lGhseouu zFJJqL2yg^gy6Uu5?E!~r3_2hr!f632F31dBtoXFFHpjgnHwSMSNg1|>3s7#sd_5;E z@$`2j$0epiyYQ$`R2WES_W1%65pNoL{_c@!A!7g~0*JtYMX}Pgi-MFCHau{@u<!=} zoE$T=)RieQ8S@vWH$=)wfYCS=RYiuj#y^F9qy>_jAu}^m`kkf4iz4s%^6ry7?W?HH zz9w;4x)h||Dbk6zXfW?gjGVcejH0NzV_HH(=y8fOy60~e;-YE%*pT#Tmby`vHd5EP zh}h3^UrLZgWJ9u2s>0sUYfvWI!9IqO*W4eGu-eAPxS-SZN<98}kg^Xu2c0HXvPw#Z zu3=%7zL8S*O26YQwoK+}(-jEv=Gs{|voI(XM=lYxjP~l5Bsw~;jq1}Ciz49U*w<VV z2<&RJyErV7Ua;o7a;w!pOS(b}3|JrMxd-^<tz;r`ST2ow@(s#nY}8xXgvMr-s4N00 zCbSX=6hon5iSj>xrWxVpjv($zyK_6v$uBRXVX)U1*@!c6WJ{@1llG#EDofOW5RVKK zm0kSfj$=<k@f|fPD4j?b?k*&$@UaODw4uRgrk8PjZbvW<*6l<@h6|LCsAcdM>PgSQ z8_`AU%Ko*HgZc&ZMT5=ebgBX3I#Fp`PzZ)fMp7F;!wCKLN}Ehx0p)hS#EaB%Qr;-S z5o->3p($BhS91p~hn@_J(9&7i2zM|2Y<=m2$6gCAaJXerzlu^iYqhl~wYfbJ@H~@$ zD{c)(UG4|(j%)}{exl*O1Jp!Jp(roR+dIMQosaIVFHf$Ars3A7LQvc1d{rUESTocE z9UhLdaucg9_l&7?;0&<IW+m6ozts}J#nrN4?RIy(9_j^}99@{}msAyhnqPyS&}|1V zmEOLnyWA}07SA*1ogk-MN2kSpbxn0Ob?=L(P7?+#Cl?1U?_<wI>VY+Ga9M!$&(P^< zI?p`;<Yy=gbJJ|f;L=9S%2m_(Vtx;4oK)xM(Ike;<8e*kpj^D-G#>t`JQEoi*@g*& ze1Z77oWA~!`GVugY$qE@rz&Ei=l(q$jVb8?M}#zH;1L4CjqVe)v7s^I=?Vmy#}n`P z=tPxnk@4uy3AkQEEqdq`B3|NF$vpS*G}ahZOAQS%Yn{x3z$I}DvZ}FZHYx>W0FCQg zPIQZUA{-%UK#cv*ZCg$#s0evAE%`sMp_$e<>Qpo|C8f1KKU%s@`jm~oG+^n)9uCVv zZVPOgR2m1`C1A0R!=zoPzB2R}lpUH{z=el>4(t)~{oo@i3dj2=HsRxnO5kWep=w~S z!s|XkS-#rE?k}6<_%ux1<lpSfq^!?HH6-9vB;Yb<3x!<;cn&~{ju69RIU1a5yTf1d zIqaL*5ho`r8q;ilOr{dJJDa<`X`!K6uzqoRl#_@oU#rh^iKaJJe)SnlEG&e2yqa9) z=28+hb=n^5PeeE&;IpHrCAJ?M>b`^x9aXVOeLG+PA6?d~cYTJI7XjAajH2vAH;;Pu zaDBUT=u+9Fq@{JM4aa+0y3EbYUtcCh&b7I-t*h2Qm#fve?QORxOx3^?xrg<#ISNGL zuzznwX1zG{eKcEz8Ef+%rJptY)kQFo*>&TC%WHjuEFDfyGjBaVJ1a8gJ1ierA`lJs zU7Brn!SN4z1cY=Wz`eBH1f@PU%I?vFqpA3V!dG4>!mja^`=dkCh1Uza%8xew$TPnx z+8iyt4i5o0HxcLB%cHb+R`L?&8r;TjrWJ-sRCVOj%8724*_y~Ke^Xx-?U)pO{R6<o zvanu33^<>$rpP?n5g{{Anisl6BpIIIqOlz>VK<bk7AlN!qGt#D^2Y%IMq1wKo>eq_ z)+20eDk?M63Ni$iuNDxGuEiynF*V;O{h5Z;zHJMpLZcXFWoq{j=ORmo5we%=?rV%s z%ImtLjN>faw*vz|Rt?Ho%oXdXQ8s(N+y&H-Oj@?7x|Hnc;Md5ym8MP{L}N`OaaGXc zujGQnzrv5-MGWs~vRm}+ln|rn8=3hkDb9%90{L#bZ$j9a>uSqVJTC%&{9t$5R*Mi( z3jT01zVgl4Q^rNrQNYa1oV8q)f{`)+B^Z%FoBLZzT~nPI)yc=}tFUc*&SDc~o-~K# zN(B7Hm4W52xaQw=qiGgwlIi<KdOQ#R@Gl~!Y;Mn`8KI3n{xe|}d0c4{{b#1tIb4@Q zIf9~yc!@y7ukS@Aj~rVU*4&`q*}ohQe|^{rNh_-ZvUF{3GT!*rpr&+AkmlHgdwqo> z7bbvNO6}<pg7D(IA=}%#R#q}(XjQ%@cfg<(hJso1gm`lA8=xpIyIlN&`VHXQDNyKn z<G8^`_(@w-B7kvQr_?FUWp97~=;UNzkV2mhXRazfJ`EQS=k+SFEB{_TH@n&veB9ez zhMMk+Mkms^y6n`|#D3)Y-LQErDn};yLn<l1vpULdyFamr@(wfVL&oo-3EdXgz5TX| zqB3pwNK%rsvgK@eW*&;B;$jKon)2v*DPzEuIdO?O>|*I6m0G?0H^V;6WOPo6_xdd` zu%}zm$)xCn1GvAtdkb7cU|1{T5%9Uh$<U3u1IED>5V|_O<xD_S4b~ODotoMN4|wlB zm>DJ5X!K)A7M5`UbL)^K5d$C(A%rjq#8*e7kUx*pwc!l|sq40+%|7LPPgKyO`0fqg zA?tyNhs)>rE4&aP79y?7l}&Sn9N~m$VekHUynU%FfpY7jW(FIe?(;X*Z)j&Ot;qw4 zz^5yUjKvvTK0m}U$nsSImseYv!SmkU<?&rx+iUR;|6KYhHs~|Zr}~?K?#*XiC$<KB z55y7L#`K0b^}_a4+uhZ}m{<Up!*YPe_e8D#VgWP@z;tdGY$}>UA@G?9P6#^WAINE+ zN*fPR!b8Fu8)|x_Z_0DV=fO$c&i(V(xHyXiTj6Ac)E|zmR5al@vI-;>1EV8Jm+4G~ zzoRlagI{^RqybWun3!6f?mv>a(*uy#gb|MC^!s#=t}uNHXn2X?e3+9xK+9H!Eyw|& z2Y%rurJq0H9)ZjCmSICw)Z`dte`JFo*E)bkmZp@$Hj<>|MfK+ESaz^M;7ww@>ri&? zdEIz84Bz7BX4#aND>_%Ey%TjP4lf#&$?LK?R5Crod+QN8*DaON=8EtVboh;?ZSmi{ z@0EnIiexROY4bGRUb*?HMV3qo_JjbrgujNr7v4Ip;7l?nn~8n<b}kopKi1-yw&3HR zj-(VAv?WP^o*Qff3xmY+9vdRRAb{~wr}_r-=9X7}7s<$DdT?MHo7w3$6J%O9<ulm% zY%~(EXTiSVv8g@A=ns8Udj1oEgs-(8Gt%?0BBxTPsIhHq&)CpV764M!a2H#UwbCx- z`gRn^X>iwGaJbb&9m0KTFCw5E@{FO913twHq_Oym8SJ@27VGO-R~oEeAICM_PB`rk zf0NO0JagGlb!At3rS1C`c$XaHi6RiL+Kfhd`Ov9Ft<zi3gy%pQJ!i`)Yo4^gtA2YB zF26n~FCnD6%WH_!Hs&(_iSsE>_DqwI%lq!&l7z-K<_~C;<HE)Xlj5B@0SfYJp@<;q z$SKQHB)&&R!M3urEWX@o5(R@b95x$I_ovv?BzXqgv|}>Tj`yDf1GtnL5|^M^Eys2< z(o~31{DM~d7A2VZIXI$q<+B-X9k_(_rpmeC4<-O5L<iC|5{l}nX^BNeu!*c3Wx2F( z(ust0)O>spbti{I&0Dac*!d2Rcc&Prn9)M{O@>STNeX4mBeZ$s?{!ii6(!5<WDjp_ zj{_N4vU9=xYxv1@4*@s!X5Ff<iW(XziJ2XJEC4CtD&0^f9Gv5a`1W@Dm%A77=vauE zm^UX~8hD37PeYZTIk{4AF#52(nbh{8aOh7{8pE{Ld2H`X;x(<aVxtiiF7VaHzbpl7 zIHDfyYWa=sNx7<)0v-|epw!lC&olZo&2JXpoj{uR#}+Pa{JYgK^9Z5d-w{UP59V1T z$@?!5=0EfZhDhWi8t?ymUdR7G9`d_ZNHL4g<@E+oH*L`F<yooS)(y51QNS|?B?d15 zkSd$T&%((W-~~ud<}f<`A}tNSpSE?sExJ=kmm;S~75LtGS68xTvqaGUF@wkD+29WE zZm;zgcctF??D)8+b8KS52h4vVBC1I*0AHeFVu=KV7zD2a0^cdoq@p82LOfp{WdsEU zLqoIpy@HOGwiXu`Rjbx7K+nO^?YVgdq%#5HBKanUjN7J2HaT%%{>5})HJeFMtm;4N z4UBE!cuGlGh59SD`9f(6xI9QhBaL1;qU&&Av(c$8BZIKhWV6AwldQhPwN&?(PJ;}C z!*2OIRyw(&+3m!+EGd^3aXYaT@$b%Hq=K@tldXM)%DCBBGvWC7`0Cm!X&?nT`7I%% z;mkhWtIe~^>FQj8Gz9_zf(WB<P?YQW{q}NXn#F?E;d(_{Vc|ZwV%zm{N#XuQE`zJh zWTI2GO2_4Na((9dwetm<(M!oOqOwxfS>>*L!x%a^fL61!)@)~hs>G}}I9gUlM%eXc zw5kh`n#!$O78IzT^wB@)5!A8R;DL0Ul$1)Y9a0t!|Bu{7oCHYByFl2%z`ziAyV(&4 zPv+uWl*?dNkW<AZ@$w{K&~16_Jg`DV-Ki0XIA5L1liU%zJ)TQcm9Vp$0$pPgu6LD{ zKMNjP?3K<PADinS0nIEds=x*AmmnFRiHz$NU>z9gd0R*qVC){#^?5VeFZc3r(OX=& zAFeHUyE&g@$(jI8){KTHSGBqT&8-Y>cLGAi5zkC4ZrK@&RVq?lY{Jh+mRqf!5{6Nk z5Q1U_aCw}CkfP5eq{h>_Y|m1a*IJ#2$HvT8>$%92=-;;`k%)$9r`7$=LydS8L3DUH zF1sTP50qQ>`C2QneUI&2sk7B`eXH%|Pweh^c{NtUq3o}*sJxzs4UR_wU<8=geKw@| z;qzxP7e3%io#{uO?!zgPWtYRa)YLFN5)xrB;wry$IW{)7y|aT|XdL=!=BFZs%rgL= zK){+->e}Oy_`*v5hoz;KC$A3w-KD5u&=4%@;h`xZe{<I04%5Fkv{xc^{i&*Iv)Y`~ z*~uT=t2dY(A0C;mrjnEdBRfLhw>(mNGgN(HYd}KctfouL$(i5Wy!hvP7QUH*RisaR zyy8Vwj&F{k7#UeXk6+I;WU6M$wQK3=#hk^0PbO#o@^Y#1IF2RPv!}PGke^|wd|nXG ze`Y&NpCe*4uc!zY6O+LWn=tE-H>8}54Bh=p#ZqV};i`lV_t|G>XJ=Sg*i*)y!og^- z+uK`4JXF-tC_{r<=FW|x@_bqwDtJsfLH3jR$g(n3dO~hPWS;4<S*2PLPKP@!aOcqX zU5_k8N=+e!#hLw9cQDc0)58d+A6-i))4Lo_67=G8*LytPa6O^7obfo<H6<nI$N@7o zo6d&D$NMiz*(`KB-K|V1kJEVUPdNv&(-X@U9FJ&Q!?ko^qhzBbC5Hh3^@5F&i3t~b z$G-1+dRxzsZ`C9#jaK-0U;V7bzd*Npwf))>C^p3Yk5dt-wD+S>RZZUT&fqd!l!(ss z3W~<+FuD%nZm`g653h5mGnQFyJeh4bTKSv7o!wP+YELfrs4gd0r5-+Swd};o!iLNL z!%=Q7t{;A*(`%(bGaBrc4)*seG+N3dzRtR~>-7dXp3NH^*JG2dYg|qEwOsEbVX@XL zCZBhB+_N$>gE>7S6Pu4t7KJizkR(MiSuGw1&h*KeV(*560Yxi@MMzdNbLde+Fmr<` zQnGXDv;6G`-1PjN)!CEa*-YOfB`3Gz92w%0jE)EkqX%CmL_|b6L1ICt93KmaiqLUz zg5;}2iu4o|6n@Fevr$lhmqs+k`%J{Vl@~AejePkJzwmVpnRf~a0`>jQ{}UGCpC)A9 zJt*z2hu;hKrtt9$YPf=8Lo=Fk#6Lk_^7NJp6%BY~u-S$~FIsNCvC>D{ollkdlfC?6 zeE&e|10sN5pGgy;?TL%a0u9gOaP&3T+eo#r$5YkYs-$4p{ZboM1GiJn0_8*kHbUFa zf1Jn|INk%v^lCSPj9AS-2Uzn~8@ZWG6nlGT*GMEkxu`s{%FH!pkJblNP*Dccpbt8B z9<&hUddqdfAFT)4pE<j(Rds?7N;5<5cT6=Kk5>Pr4#LDeGi-RHr=^ZNopEn#cZ$b+ zy?RJ;aV(7Ko#7~3sg4S-DK8d9n^}e1F@tBGVR<-?l3A&@o8G_LvCi-s;lw!z5Th`L zL%?x9J}(^~552y<xeT8`wVkUlXS3e1?h$#)xW9>({%g$4aPB#@1(-iwU)Eu%aFj8$ z{#{;upo8?O?(>&CGxa(dR1e`}5GmL+uhM9iAW+FfRv$JiaCtN$9u*&F0F(L4#AJtA z_(S=Dn3elnl3`|m=RmbylNkL#y2wUZvJN?Sea%mnvZWlo?W4)kj@B1}>pnK;qxB7@ zyY7CA9v6epfSk;AZ09qNITmAPAp#F5at&Nfvyo!BV3hqmQ&ybC@i5ev!;m7~av2tj zs8&RZy__!V18agcr^VI_lB|dJ?Ky1Dk+5WJdr*&oz)TbZoyFaWfghuEozq~@0I*D} zl$?35@4<~?$q@+59~C9sNYrFND40)ucfW7maE(uRPN-+?CzuT6%ZqJu_KxgH3kUry zj4IJr_pLYSBw*)x4HvMd<M)k@-rr<iNmq$U`)Oe9Y;OTFv4#n)U-{8EXzZj9&$j_l zJTlK5%wjCM_U`!X7AgrD)X*1ima=%niy$>(5YYgD`)VjcF(4+A#d%8M9veRnGY$Ik zk1;#s6XJKquews;pnKhXSUovOq57=b(g0M}RB1vN_<P+-I8(2Pi945IqB_yXqKl}i ztf;8$U4(l*%n2n+2i?e|_>W6`rJG+qIr~MRUw|=`sj*_NUgkcCoa=I^?E`c-oIule z=EUDwiA1xE3#y`p<g~<mx^XVs%tC^h*<&z4Wj2MQ(c$B0A;2nk$5%n6sC25pp7y?! z2+yElIq9)qjxwxdM5yAWoKC0)b6+kEe^^VYRR$&2a4UWUs`!>!m<^EzQ-rCc5k5^1 za->fDi;%iRrmT6Ct#4i+G9k@z@G^rWI|`Gw+hSdz*xjEs7hHl$uNQf`*~X5Sz@<fx zzpA~H<0Yk)_cIm@2yJaAW;p7{`F#BLi@Nbe2lK5?d@sB{a&o{FEpJ&dat8~W`chx% z(es9~M$?q@Bez>+Yx*pU>HG{pVSB5s5?4vpUp$WlhE2eNh2GzIfZDeDg4O2pBydcU zP=U{a&7LKxVZ@JCoehOzu33Y80B>WoD9=&E$=Xz*$Vj;=81wJ?$k_gg(%EEar=K|3 z0X;V<jpV`c)9hyH2!swjexu($=2~EtZnxuT&{;raN9+9e#qcG6^58moD=WRm*$ZrN zG4m<@L&VlyZpw1|$B_o9cw)X6WWdhO2IjwX>HjZb^`9arIW9N1z(6n%A}E-XU0fXU z?#MdX!E`ZY^vbXYIYsSAqWquAyskpU3F)ah1B(4wjY&}A>Hv^UNSI7MVSQ{c``?3a zk5nHJmP>Wxza=A{0;8*oB^>p1<x^7Ptn;hN%FFwZe@aqg@$Oy2BXa>#vA`_Ke+k;a zW?UvoXZr#&i~(v~#Frb!G31}v)N%Aey9vpIO{^@1L*SbA5J%MLo?0p(dr4@gAABDT zF>_KgIW8%us%RXIhZpO=SirjpH(*&chpCQ4`}@BTW&PONl$_NxvHbJz4!R<0Z^G=C zpcuJAwTp!K<f_Vn9eEr4cjN@&5jg8w+TsQRcM=1K<<;`pg<>45;6w*RPvlBXiN+Y< ziPPU{6}%a0{gvXq?6_^q6^O<g`~Ika-`bL)1c`#+n7%E)JYNJradiX+)(^3_-|c8I z8xt!h-evW^2$278xbOdaGP7u0-EWVbWUXa;p%6$7re|hINb<~QZB3|^O--@7egn5p z$2>i%QNXBM{-9b)8hl`nT-7^o9gHS6l;SHAO=LbPGcmDqaF}!wFxU{@!S|Z;X6EJj zH{LD0l^p$Vl6;cG<L>Tm%%uF0e|tc4b8~&YqpB+AzVz@2%~iDb{S4~zae8TCDet+e zE91&&h^GO5Wl3jGQF8ioF2@w;7N0d`<nE6^k*qR;(>mrd&g;jI>+AgN?Cc1*vkQ|k z9o$*K3rb4L3$LsCptiK6B#i3<N_Q27n;o$s4$&<_DEcB0JjU%2&&5DwS{&2Fi_SA> zVdIC<N{hur7<w7N<|}(oRo82$^^4f>hJSE0bwQ8E-MKi|57F^-&`Mx<a!Qr?VRh{F zK0_b7dZWH_S|h&4&GFM_xA1<M5N|M@;_DG1{|ye8xg|ELR;%Z2R=>1#^u)+W>g#9~ zI4$~N1TRCG(oE-mGPjGrpqP{;dC1CO_*j{;I4iV2`uHTV+F$~R*v^fEr?3h)=Jz*i z(~o2B>dQl!VPO_~VQlmYrU!@KS*&gvGy4^O{=%fdO6{iZg?m^YTHr--3Opt~KEM5q zHvTlrBNA4`P$tL^jjxRI(T-#{?W%=YPD)BDgWLJRW4$MdPP4eUm@#WSH}E>eMr|UK zpld8;z|+85t82^?qEIevx<=T;87p#Rw`2zBu?}WAnRKEO5UgFOy0;e{yvS%a(yO=2 zuSYB`Ee%Fxr0^Wb?O&_i`WIBT9=1|O>pqXJrxX-@osX(9?97g@qfSA6!AxO0iQe3l z2a4a*($dBl>$I4UXA|{S>2?$s6$QJ<WpSOHYDI#+oC~;Szw-AR>FeX+gG5Ov_S3k^ zkgtq92Rt$#Z%^vHUkbrQ+1KZpXtH%7AB4*Ib60n2CMi>IjYd-)_q#uTvN0KS!R$}V zmCoMDKh-{6{I@3y27SX@eSIRhxE2YkRW^h<-(wOp)>;(B+XJOR!oksx54;0MW}Cmg zIo)bR!AxJ^iqAJHsur{Of#Sr}R2(r3OiV&v$G*`~Tq<i0js;kOsJC*#%)XZ=q(!(a zE)PWM)8zsdlJm{$d!+AcSeJ<>jaEF>k8Bq6hbv7@fD$SmlGbDAv-Px?n8gMQ6SqL% zhEKKKju?ephL|r{T7b>$ik#LoIN$hB^Dua)-eKNfFq&M}*4o<EwpBqPmzhgmQesy8 zv&mX}(cX4?!)G%)IT@)@4=LI@aeYZ+8Jxh?7&)J=@|kVRxngI<R9mkNOja{$<Ky30 zJac+$34SCTZe$XOh`SLf->5zsyflzLW$VIZV7FNcq5)EqlSkrm;BjUPXfA{EPB19Y zV0`9&L(XBb?08d*a(WYDz;3mUalxLgGLGZiSexc)N%&N%+~GyA(e4Ds&X0qq@+K!j zF7>vyIILH3c#K(t!1{=&EY8qO9ARPqKYune`C4&tv1{t`T#Vm*dxwW5{h^V{mFvjO z{rZRoqVexZRL+1c4k;5*9ZKOrDYsg9Vczw-v>#i`HCj4W+$V&uui(PxloJ?rWJEz1 zFRU_|_DzqibXsgnuwQ2&S1OA{$k9zps8s9ZahK*l@cq6t`!unz6ot{A!SR!EVG`r9 za^8HUvY<U|$e~VwaBBIxCSHApd%~9GutURFugREuZV)9OX-;-$hgg-EJI>xA=O_au z{~hCtlcA0U$C<3t`t1P*I?Ir8&b^Fe=#iRcQORhV`+0NhbVVioiYS=U$m=d(r6o>c zL}olup+tM$vl9{H`l<`D?iI2=aFrFbi)dcSpg#EY%GH5;!koAp>GP*wIystvYbeu` z6Yp=raC{U2kN0yQ6`pt9!B}Kuq-KNr**V`6;`v7J-=EtTzr;s)VG}rS*{o;fYgc3Q z20Oi9f=2f?S+53dy0)8_tL?6bP<oMTGPu14hNmuPkLtj%N`+<<BEK$!ZfB24K=0lc zeBNU9x<Vsbh2`55juz_G`3j9N_MMeK*_)fz+M-49=>jgmB_8k9MH2Do8WZ&V`M9`v zJM?<6g2z+i>E<ZV$pk+3-mdo{Z%~%k`_#h9YOc*i4$NnW$>=}8C$znDj6~&>O$-VO z!s>KbP}J3}GLFPSL5cOaJ41qp=U}OrE;EUSLO5m#@TAHrTR}v|8qX5Iq{CZ&`f5X` z_JH)Nm7bBtZq@#)TVPbRoSKh^KOLNQ>b6>n0yFtC((%NjvERV#`hhOj%kAy{(Qphp zv+3g4_&f;io=Tmzzkiv{Zx+Ej`5Rzsdz%-m8mhO#3YD`5c0$BJr3u(r|FER}dKB`7 zkpN!Q^EV8H9`;`;ffrr?h?o?;v8D#VYlI_|>&fpkonQtg%|<++&9CJ(`TBN`ppTA? zkBdcMMW!I_<mKkJx!u@1JHL9IXGyqhv^t3!Z$TsCXL6mm_<m=!{pF*(Q6wOjI<l_n zcr=n&cknllQ1APjHyFGbjLPzS*^ew{Mk2`V`Z9xrv-q}riyQu`-jl?#RU|o)2?FCG z-e5Yk&zk|_w!;4P^~It0>ocSn-U1>%_w?A9<7nY6Jm#3k^?=V~1Ymi28AgASxdzqa z>EYWVH40aMU*F9U%ZHO@kAp@#1E0kf)S`I^tgM)rYPV4pR_(<#&h$z9Z(;g<OxwSG zg=eOJV$!7)RaDgJC!U@w1@H{z1O)_qll}Qq<$SKlM=YpV4({MwyX~GamvD?8kIVf_ zQmyAw99Tz|+m>&&GM}27JI}{Owl~4$!^6GYWV2wscrj(FbuwSU2aXro*}PX%I=$Rk zvH+RnMLF^NZW|HLez|)^sA1t7ksI!G*a~Ce7wu~tiYQ#S=Ea&bDqi#JSinD8V)gJT zu$p<Lhjz)4jBj~WM=L4MT+llrn#{u0K<ncu3#ttB6HdS-`B{jL2R{{wIA?vqN59ey zq`um~ERS>)<Z+X}sj<m9lq!;I57tRKWDL1wf<#?4E$6_?yJv&TV!<r1nyrc=%QK-n zO4p6t?iNHU4&MMJn_Bjltg<U%ENa7r2faZ*xTaZ~Lvd+iozs=VY2z%Rxn4*lAg(8} zzNKt}Othf=WRUkH-WN7y<Qi=A0GVcq_=v4br8EwU$Dz?ODfIZ^cyD&bN%1k?k48pQ zEloFD-9rNJyH}FIr6<~8ZLJJUrGzKbTv3A$=s~AZEh;DqpTAs%!~>O<QX34u{<dxq zFn$Z{>;da@zCB=Zx?)vkjHu<-&(_a^C4jZP&9Z9MwoE*pz*qkwxh#Y4_9||Vr%Q!0 zn#f#Rv;nqfVDXvVw85^=>cu5CtLx&?jLAxqjfJ`Sa@E_W#e((bb(HCsEITnzBj%@x z7S+m5o{1`*x~S2u!h!;)^JV-&SbY&_=wLg6*NDY%qFrf_7J#DOr~k*hCJcEbTT-X# z?rlrK(Qyo{FKM({87mCO!^h)xx&7nh@9*ywDwLaRV6D?Nw(c8(gtc8UiaDY8FkLVz zj!0OnT2*<|2UB6Y-|DtQT{(s|6}nG0P1ij3xHHieGiSP74=eV{Zc!*c!O!`TXl?K8 zr5UWkV`uSo0i$v$6CWa3S7ae7(;KaqDBa4OD^l~sBh#6#o4~Tm2AhQ>?F{9z`DRX4 zVQ<J@FZcVNz;DLl3#9H1lOMSaFTO|UwwwBjBeg_YS7@-Ayb-m=XIrJsBjB(JXAf8( zTw~Jfv^WZ?s*1aB-{Nv0;WL|F3gjY^ySUsVX0*ztKGYp_cuZvS-M4$7E<`Od{~ui% zV-_H?fvwU6<!npCx$h#!9|~d9UUZPcS-<O}Khtmj-5Y>INF<}@)$S1iAFmW<t@)n) z-FCCP)51rH$F;WmUk}wet^ly;(&k)ut<9z1R>~X>w=0v|394dY!{JQ`p2K|i0*tk< zGyzA-HC3E3dN@hH+9G)EjVQnU{w;>^=9BecutBk?ND+lE79IlO{dAXsMCiVCg>M7- zxqYq41hZ9vF{13OOtnfTjT`XdbOsLb6BqHbLJM->nB`{pe!OyJZlWfvOiDsvCr<`^ z`to^TH<;{7F0ypQ*g7+K4-~kk$J<ry`d#s5J@U30PXX3|2P<*|Z#XH)O*Nw4wsBMM z;rM#&FyT|99GDNn`}AEaRFniMzp7uIXFjgO=Ec{ComnTcG|@?bQx;Dm+NqdKiqoky z&tcEZIBTF)LKojB<#j^7&Y4Ygr%XiwzlFZm0zU&B{u`m8V~y$x-1)ys30uip@!Z1m zW2171U-=ynnpoo5^eYhr0F!{I>tA7tK3T7cAr^ws^P#-WpU4oWngvKms+cBj6d%R@ zmLTD<oBrN}SaY@<ZYGHL#xx^Me`JgS#DZq}hA|n^1$P6IldH5u`Oz<Bu%#3JaG4J< z)W!6%Rs8I~UVm45YB_9^I`8aP%vWe86;J$+{;|k<gMt`_a?fk^Zzf;#kNGtojzvdI z{c<jcg9eKQDAo2R>kX@gO1i%i%><ox*W|Ll?Jh4Ry0&J#7On}%Umfm%4@!;ZOP`Wy zj0=sw5b2JX_$YM~c1@TswPrXTZ(IHPR!O~xk%7{%WQ~J^!=T$ijnAu|k|y2R<}1QV zpR(v-X=kSVc!PqCt-e;ljmyQf%^8ZKTl>uh1rLul^w)zY|6k19&Yq<47|$N{KU3WV zs+QW^F8cfsH+@9ie-U?b>-ySQ3gylgTUHXwRBhIp2cq1rcCneK<CdYIgTHljhscSA zP>{0d%k0tB+&zs6$j&V0!%!~CL`Fy)6><|3`<*#`YCn0AaO8Ktx&i!;Jo2)+M>vU~ z8`>l6%@aBMn}*P{Z|eQY#{Ed5MUGxhcXtlwFmZ77UAB1i`Jxf0M=k?Wa!%dbLx%{g zX+g7A;?AI4ZkJs95pjKfXWv4nFpu+xU|nYwc9QkdA+K$vzfptO>N*#*l~$VRc}sfQ z+H0psT_T}65H~!(gmW}MDvSClYVWLNXo7Xbq$}e?i<BH3$)Iif2T>eeBR2E`3~P<# zOhaOJ?!CnImZ&Js0E0;~3XldK_gd|hsGB;QG8tG)z@cj>N{SIceuX*>c_?KNF9uUo z3b<Z8s)$s=-#}WyD#L&Y1NrG60q=<hXNqYTr~iuujEPD!8xKy*@0Bnb>p{m*j?f_Q z#rkbO6o19#`pErRq0r}t_fj|Ne9g@eVuO?OnuORz0OwD+a04SHK*lZ13kaN;{vNAr zOt<M6=H=bZ_>9F>)ERB>;nVu7D=YkOgA2o%rQK>0*jBp*w%xYZ`)6Q<>Q=;Bt>`r_ zhc)qLZ$sbM&nBmBKY9COv6R4TMv}K33@o&OgzEgfYU_+;aK8FO;)mr->+S3jOUxTs zn7uxRJyY}}Ei*aU<>fI_WxI^TQR|!6T&*&X7CkY6XapG*AckSH4q8q^<qe!{`TPYu zt=M$cVy>E*9gU0-uHOH$v<xs5UfSEN8xIjC6m#Usmpp=HW?>1Jeo=9j3Zn#RRat90 zgu7%J-h|_Z^8BTcOI>V`PL417yV`7LaG&Xw#$m(ba%WhuQ4#SVXP>B!^9ho5I5t*c zYHI54P8r+oXFgFS@rKK~!FT0Vmc-0V`WNX<YOPB7hf6}Jg@u`T%SGy1b`5uTv7<<E z<;~pKnA{8EW8Cxda@Gsagak&d?ur<N5Rm`HuKwHjOo<}2*mFN#&i7vy2L4G9H7J!{ zb{O>d@cj4JxSXbH;4I8GNqid)#Bz6)fD#-BMlKAcoKN%wr^_bDTMehDrxU!Xo^A8M z=`I2xd%kp2W(JSbche|DbuG9$o1??$t~fj+#A~*8n29Qi*DIgFWo{pWh?kCRxYoJ( zXs=|uDW#`uV5W9m#A@!;3Gw9Z`mAVKMH{6dz>86q($Jsc&VknNW8%Fp3QyxhuWZXH zZ;o%0zD1;i|86Jc-o3K0R|0>#s+4NDqFO0*b@8D;lNdL%GbM2~n9ZCSw6E=&PQ=ps z2v)i7$0{g16jRf@`IHf3)HEjHvyJ?p^(2&q&-2@>58YtBiyi}5&74G8VYR{zF1>cs z(xq}(%oNU5)xG|)v(~frZ7%IgNF{^{KRpm#A4H(wIEseyFi`y1^&#tWb(J?A!!|U$ z-DXED(t54a;pK5$PdGS)BakUhxe4ryzq*4f&!b6IT6N}-Y3F3S@DE>+hVeL@$ENZI zkqEu-*)(Wq!XqMn+?0?Q_ehg|)z{aba#M95=*uS^zQ_|_H+_}zks=!#A0r{oi@7pl z`E07M>{fax+^vO^iW3I|l@T;BkSooXK4ocT1ui_{`y8qha(gCB80Z3;Dt-75BkJlJ z`U5x1H(ojIo?!+SmzOcnVaXa~Bqg^(<e2u2jlnX~IP99j0uN|4$^S*#TL#tDu3frO zEF^evcemgg+zG*g2M_LU!QGueaCdhI?(XjH?r<LR?){xpXLnciuKt&*z*@}3<e9gO zYmA;FQ-$TTcVYa7!zt?MC?#bTP;PGi{^NrMN^Z;Sa5na9xOlm*dq4law{nC2FqH+o zAMOlV?O_3>4&bomy)!>GGN)q9e5dLnr>g^DW766+mD!WEYye?dEk6|2upY!Tep$ac z;<3kb@F$DO4J#=r;jrV<e`LV!$@V_0pUjn25zQ@_ON(x&HnKSBYFm=t!c4@(>Uv6- zMuBCqnUs@JP<EvFEbXbSp*OfG!)t3<wcLvZdD$W&GD?T?RZxSN{pN`UrLZw<JT)dH zkXU-ea`-H+i&kn78Dqzfd!gHlSRZO%LU7}lRZJB9o7Z;LYPH3E=*P_b)cJ1Fv-Y<0 zyT=(uM|n*O`K}MxdQWVq53&&ooMdEZl8+%Kzh+{g@&W?5%a%5h-t>~N=L7`C!;o(w z&Q+R}TW;*~xi4=)uZ^6<MnzTFExCh3iGG9dXid++;ATHQS%;Ims@qseNl8m3wb&f& zt+%mw6>@F%6t<V!lpN<KCF5X~a-yQ-&e4|P(Chspvsd2$=Z_mL?zQ)8h^&WC*V-R% zr)KgKAujgTJbi225te!?950m56DA@qaw_H%6Tt+AVU-tBlH^YJlf&>)$oZd6$zP?& zZ*&4<X=IW3DFZ`sr6A)rcPsY_m8+fBH@uzu!!!w>lp3gj=u6-;KOw&=1pZZ@^XKh% z9M;#}qr`!a35=L(kNb?uosV?8!z<~af7WU@TF94v0{yhMJ!t13;jo34&<7hpO?G~I z8l$)mer|X_JU`WPTWrVJI_pDKA#8~E7&Y2kMP6P4#uYYu%n%JO`MJ3>%^J8tZ1y6^ z{VQ4)_g={sT3Xzg)*S?#7@Rt+qj!YD0f!kvF$fo$<v}$R3t+~hvkC@ot*xyO53h-q zmcp~Lvje&Mn56()Uh8nCFcbI>flj@OBjil@1OW7Sm=ierz@m5xlFn`aKjP=C$gwj) z_*OtWW&QNH<x(X7HS4%{tN=7jm9|rs<p>=gv2?Q}B@Y6n88{{$MLGqAJw2J0-?c+~ zVy%=y?nro_=M?W@N40gT!#!Aq%!}uzQ5r^1B}ylh@w;!aO;pL+(aA43N?L1vA=6>j z5G~Scu|h4D%g30V`mK*2i54zrf9|U6Ajbc~u8sDcZW)|)j(|u-C@zcMVZ#lu_~3&q z0+U2h*{n*FF$^|L+gFJ?H~~k$X*?Sud1n%_u)|Y2(4%Ek*<!c1w|^oxg$`+};?S+u zrwk@?k&2eNMm2=09I10zbm}#~^VkE@=;~k$wnWK=m4XnTbpLCJ`zjL^jXLK{nRK6h zris!u(pxyJ``rm6p+v>Wu`w&_3Vo=XuT8^4<;$xnU@~GH%1zU2cQpIh7H6?gcNKtW zr)Z+uEX3YN?Y@_)m1RGDEOT|p!)tx9M?2Q{?Tzxo0!MWyHqXkn{}?*p7&Wbb(AITr zR4Xw8xf?LN@U-?uOh3O`aw|=~ToZ;H&?w1qZOfWePyp^HG56&;=hap`xNlgR`xBYA zhIoS7HGVu<U7CT3z-+EIWTMX20~e$__UV&_#R)K9(ZfCe`G=m4EJwQ8U6m#~A#%(M zw=4RQ9oC5Vsj1xc>Gg`By?y&>W}wAOMIk2h2tHc=eCC7q?_t64qRRNAV8!O<=H2CC zBCEmd;eu26ecNUNFbdgZyw>cuxBUaQ;I561-(cp-efTqFvqKJM?S!6C)8^h|PWmOJ z?HliF8Piy!r~H!Gv?7Klb8=iXS}G0nsjCAn7eVM_C4qf8FEBj+<tk9XL8G(vkEuY= zYEW>HdAG@Q#oI1sb`p4)bObKj^)Kk<*1OX<1H110zOmFdkoiM$d6#Z)8CSpbsA^>D zzg{@O4kj{7P2VlB6Pmiky|Hv%GfbdXtGuO!tET(1g8Gpf$8_a}or6?kMNY}asFLR{ z{;`gw^UJS3RODhT1I-j_G3>WpXG=mGvCUXSr;{O-33Y^y$9aBU6?~N16Paz)(}Pbd zg|M4g0ej`2sESj5Oppc2>=E)PD^uE0FIr>{+E5%oza7<kI>B^=)9+98&VQxKa(OU@ zsU{U+H&<bJv1jJiV1EOHtLZ@8%>f<t-XVR1Qo(k6d?MYc8XBpSF@Wp|ajx136&=0j zvIZZ;`k_-&^)|+e{FK`?ZEM7M;giX2KbO-bm&;{=U9tLDwxmmQP1Uso6Dp7N%dIU8 zrg@cWN7Q^!WymRsqLVtCP#1c&6G1xN9n3M)gW=gf{s<cf!l40@R8Q@=C<qAt)7_Ju zLYwt9@Jfx23&DG_<>lqT_CPH$KY9U$!2KLLjb;Z^^@Rmy+M6vyVq9t8{5IfhGpAS> zFd0Ig+`9n9fM3C<o~O)2+9TOZl@SGsIE$ii7VWOV1=rul>Au1&Pd{H!iuYMQvc6`P za(3q1!F7U$g>5Zcf2i@2h_10%U0p3{nuZ!B3?JE<sb89BE1xl18V$2;%`8t%ed)9% z;IOQPt(HdoF(XWdC#X=ip83v;B1SlLar^W4=512xZ}zOQZPXlfx|;cxOceV0i!Mnn z_nNmpr5lcVdd>-W9Maq0i_B?Nphe!{D_b(GiE_7SLcb-&&3qb_U5O45qY)76pRLi^ z#zO958Qt8CJ$lTGqFO0oTFG|J&&&F{s9}V#PGS3fjqrXmxEV|-b{<WMWVN-|#N6t{ zWAV<2zCfIptg)9UR~ixzx^5Jgr->K*WZ*XK{`f0Ff&7Uy)_Wc4bfBg##^Ei^7%Ho8 zq#Mf!Tl|e9(NYj4Ccz6u)VHqCMb=(#{9fpUOifPGtoa-kza^!OZ??}&PY>qF!a}}1 z;55dH=ZU=XzM~hXLyBw=XpXC{9_kQR3`>he1^t_o7;+(V#J6Nb@bCHzaKeuO^B`4k z!cG389?Yi~DwuO+TV>^yx=ncJhJaQst`EDuN;!2+S2?HVd=O(5#Di2gXoK1Z4|4<) zShS9wJIlm$rP@~S3geZ&?)!&oStsUUO1E{nm)B6`aH-Ui(m~|H&;gJ8*obQTj8GI= zul~7W<KpVH`E|F8xUiuuBM50-D{FH!W@9>j;N*3Tmu;xQxO(IKhHnK-pl_TX6Xg5i z&HC?~pOj0EaYKKnIh~q|E-x=1U(K^oD}T~%B6g?0(Qg<Nu3)~$;;GNiiEnHgv~d&5 zT5fOqq=GboJ4+d}i01`wpiw?|$RUWC3R_{p?JKrlMTnCAqZ<1rX2c-CIjwm9pH=4R zLh3V5{J&I$0u^NR(`O8@{_JM)!(agGP!1nC`5N2@O%m`8>vLWtu<z0NyR&7e?7zya ze1!3O_DDO$=0nPQt~PXFAf<2aU;W(=f7sYU{j%xr%--QaDrv*y`Z@Jy#Ir|O6U&cA z7?^iV;}d9n+`+9^1L!+@ourv`&u?i*%uPSh%^Qoq9!ZYH2}l@p^zBT2y=T9rZaV^M zuCewn(xN+zk9ePMj&izLn1M~(bzq2O#v{k`{+RWXyiBS8cH!EyhZ+U{+oNCn$2z8Z zi4h4cvhqOdC<A;$wtLW@e+Kl{w6y1?`Dgs*l;P3-I7_JvL~_ASBIn*C@vZfZwQXeV z6z^A#Z;+pt_3mY5WqB~DsF&BVhw!A)@BI6vA3C#0K8V>oUnu@Mj|Yw&SRwzHJL3Nk z<C5L~qDUu|0Me=O2GvsAz73=5_@|$``7A)H-u9<dc8kSiu1~H?(QHxb5%fnU-Tl2d zcW3<!Bw$60#jIC$9{2Ola&p!qjYF+#UlAecpcu)c#c4rkjFJ)<Bmy+7H*R@(L>6FZ zI>^YFv2<%!4nV4ngMdCD_q)HppiBCGdPSI9`q*8IV(z{p-^_`diXO4+IC$>r*&8h& zy+5)Q&}2bBe&!n6GAkf;g=#gagj~v7S)OUFu2T0)oSX)`g}Hwo{nNxnch5{V-IPat zmWlUecyiLRqFS3`qOcxrw#sxdlOHqd>sueMg_;AUW>d*52F~+S6sWh<3Cs~VY{p-3 zxwa}oi~l_f;8Fu0u?TT)|MJep-ix6-b%&dq;N2;M$&An6>~;9GEYl%ujwb;YF(~!H z2jaG)qeHQ1X=gsQQm5#hqUk3ixn!=|a_HBeoQMNjMF8PtZBsGx5j_1ragb(9QD5o1 z7Ju0^dioR8FHw~g!^^!t@#}@;`}h6oZ3EueV>Oy;Tx!@dE;w9ORb?e*pPHSH!V7~Z zIw)BJ0|MA9jCR()pd9sLk%z~`g#U`wH_+^y?48>p-&Jas8i*Od)DCK((1eZcb9h{} zu@|t86uL+VRHVQt71D};iFLX=^aK_r-oip`YymORQHdUzq$I@k>>M_G^B=Um_*MW) z_@Lf2@<q{Xs?LFl)G4TcXe*iBj*Wq$F2J9jgprwns#F+QotP~);U<Uu&^KCWwzIpm zqhDJ^I$S&p@C%?X)S9ms);FQ1u5z^F#0ApXsvnb3m@!FQte@^rD^>X1ON_Q`b=wJc z(BrRg?9*T6++#lRzLEY`6rU^l!(K;9stE91mx@fnccC#i<iZ{qVXuXyZaEzWSIE{1 zmB!q(+R3^82cdJcIg(rL`h3K5PS2A6bz+c&lH;zok|XE0f2k&I=pe+cBk}HK{}FLW zd|yz6lZ}3l`Y(11V|De%OrvTK{?-yyM<?sak&(_7_t&t|4VG&m0OEId;W`9#l5$NQ z>&5<Lc-x9dK*u$3*T~G)Ct&+zI}UG4wCS>akYAiV*Bt5_QWewiK<1v1%<hC<KhZsm z$BhpiEo>f|o~aPLOFF2!Jy)(`ZQKwL00Yym*I>P&2S9F{SVM4rg#~=AnF~RvcKZ=F z-Mqh#WxF1z_{edIvpZch5%#iCI<eLd;zi-+V;kwT-4!mkzmXQ~o43B+UOwWnK2kA& zGc0Y}miTNWQ%BZtv47LI9A?J|;p0Uh)bhdu+Byxt`^T5+80&bzDZYOn$ZIs7tslE^ z7n+9MA)>mJ9_W?y;(>6a)FP<nV%F)nrZAXzH4iMk(~d+JMf|Hj<A0-pXmI|G!)Xcg znSbaoX;7_B-8TBwBE$ikIqZmNY)IkA&!lGSB!r7M9ZNME{<a_R#R02ki5XNAX|%XH zQE5~siN=8yC{*Ado&(3+ca7^aQK<HsOACmw(Q5V9Y_YKm$$3Is+O1Fv*HMv0XzAIA zZCWCjOp7L5(dePL3VlNZ*+<}GQjZ;Nj0WR4KUhrnR;ti5a1wwu@arGecNaUZ+tUVb zxY7)fKdLvnLe{_VE}pAElA$Gh*P5Q0&&)nOmnvwNySe?OP*DiJAn+$jOYhhgExHAf z*YHicu4`{N-bjHcKVUSW*tzO#zqh-018a}cP?8W_bTnkk^LDl!|M2wICZUudGKY~e z8(;&6<c8&6Aiq<`HlrwrXKG-&`Q41Naq4(7A{z7b?2I%BJ!D&_Wt1t7o|feakcK&& zLTRC96SpRQ#;!?^0MNMghpT^=l(dh@k`riN2yjM6$Fve|P6iC&%?w=OHM(iHZ7*;y zne>G`Kux*g@QjYOVi{!b(nzuP7cDe6U0=s5GtGaY;&#ko%$lz|<F%DK99k37$~a== zc|NYZfo__w++ug1_>z_eKOEa(cb=F?dAI^^<EQPrEmI_ILSPK?3F61E{8?olhs#%y zT&}lRsO_VfOeS);@6jOOxpee&*G?O)Wpw3y`c{Gf#TWm2C%opXFlAa{rvIn{?ZYq0 zt?sb~gEqkS5s(?oR3KpHc4I2F){0L7<lRKu#DCK9UksiMaY-2+E_+F+lMSkbGr(T$ z<by+!PRG!8=KZJENUJ7em=@H+k#^_ufAQk+{`AOsMNPj7t#b;0YtMb$8P!cjMoF2U zpQ{;Zs{8;aEidnA5nHrqxR{~Y$j%fVo<L{&W|T-o1D}%lX-MOXCQWQ$Hv<&`%zJ7? zBJ9~JfmaZs>A;4f6rY3yhcg8gkq$~2Xr34ryOKu3dcIXSt4)Of1j%13eRojG4*^{U zXV1iD%J8sg5DE{?g7=T@T(sIIDGoH1F?&>~c4#5uC0+zS8B8jt);!DVZYjK?TBC*j z?YhOZ57cQG{O(veWfj|3jvHt0H0K>H3n&9aLjw68y#^wugAJpn`3C29TM^ca?aA;V z+V6^Nfb_q^P-%)4CT$P-_HG|rE=!;^?oV&;D;s`euLnPRPWkAUE}Y}z_98kyf&#sB zp`+e-)2%eT100oRC?9ENQ-fH=4yW=l5fhC|f9_$uNpNwp?N}|zJvcCaws1xH8g5#D zlJ1-K<bfSCzl4GL>(Ao;tB;#m(4swPIkJ84=_AV`5Q|0-3{u@zcFq(V>+E7^-Y4O) z)z)_FH9BvE=9@bR_IOTbo{Lnt`G)-deY&Sg$nUbwSt5WVEw2u3ER2IUf8unJ6%<a~ z-rkwS?e_M;XkT1S?SLVVh|AqY9<xHH`=y`aFszHjXr$)FNNVQ?LgYUh-_6NR*}L6E zvn=e8<jwB4@pE3Bew)T-npYjMb^X?O4O}ScEHI#lj|mA{9P!CL?%@-@y+Kd=B+AXh z%`Fo_s(pt<Ph1t(R0H{bV(iNludvDvlXAHxWGhC`2fjygQWiL_aQsvRzaii=JDlvz z`_U;<t*fl>zMb$h$$A}dG4rCp$7*4YnlJD%6|+`d&CL0bm-Z-2bT(|)*%X+FW%yO7 zG@{Xm4CZsTPJ;mol64XOXYa~3#2H{V$24tcK`leT@eM=lJLK>lDe^~p%ggkpaW0AO zfK)|<(uCL{q&ErMscnw<AKRlwiPQ5Dph*X=qDQjpQ-HNn8pXkHQhE94igQ@zoYq>* zY**Ove6_PbBeGb!x<t%;{DgxVb*Y8Hi*PnO=pz{`b+czps9I4D<!<4M$XWa!e3ITy zT}8}f9^r-auD-m1fc5ecOwm8s@5qPB{^He-_~z)BId^hsZ!~?`8ylMo&DVD&)wrUO zO2j)1XJ<EQGacmaqe%HVc^RboWo@;!4%;u=qo&24QA;fU^C%Im6*vc|^JLQnn?Iwi zu+TwIiqgST6&9Y0IJjPU;1SJp?8s?!JJg+$Qfvt5&ott^9G$HO;EvGgfgs4nshb(9 zLyTaL|K5jeYl;We)_Cr#xH!_uo7>dkFhX_#?-{()+2Hz!evKJj*VS;mu@&v?@TJx) z{tUlDuSIEFXCb}KegmX1Sx%cnhEZQABY4C9-)!;ZxIOB!^6~@S-BCfpB6-<&qMt?m z@8Z$e?qo2^{6)5lW=gQ#N2Ild8;Ui1B!j;(Q&Yco3Rd&d!303BjGSQIfli*<*ua@P zs#A9Nf>Y>jAS3z@rpWf0SBaBGQ<lw+Yqr!^yO~=ilQoYEcj}!!KE_SLdNM_WA!eR@ zbciQjLu>lFih7R`6Z;Fym$u9~uj_K?_EiVm8wnv7{H`M<oUa}U1sH$$6fd0?9IncB zb|dai6j^L7)|>sr<#IUu18hqb0vvX)5L2NQR^~g5x_zTf7r$+noWVi0rXkGlPdiO- z^;lKxiKLd=-Q!`F+IQT7QaG&h*L@$>xp^vn7Zr(+55+tj-wMQqA<yZh?wm+-tl48? zHS%kb#qpw*O;80=lhwV7jut#1`^w!7rS+nx1mKZGL@|^to`}lTKRoWm>L&+EZ})*A za>x~~qqcr2tx-*Fif?%1N-ihGh6o)4gNXFdcVDDPSx{m3FFv>&rB>@;2pB+#j?8%* zzqgdKF{%grRJl8$`rx$-4l|YPhv~R(Snohwb$BFHQ2(v(u6C2PP7mX$QQT8VZn{R< zZat>EHr7cebGmk}pFm}-M|-A2sYEvx(-1Hyk9zvUb)1Z$KG*dd3I_4nsh+n53pH!i zY)^O`U$d*6l5y0~Ebf%s7NWUQ2}x7)(gHS1&KtHd_|GOYWEvR)4CR^+36Dsd@98x@ z&8L`V6{wgKfdWpcSvOV*1xY4P$p6MBZ(BtXM{Sl?qa2-@%<=1&0v#<X<@2A!#4>xW zi@H>1I?!#9S94|BOB(NDwl=m1IXqmEvLxh93b$xf-9<jUe@ZUT>iq?atv)R#vh|$- z_G)_;fiRp>x!GaLWXSi&c=%DSY#(;1VwY`UNpzSw-&@r@wwP{rO(zl}l7aYURZ%5q z{K0O`*K}n7qXpFSozV(R#uy;IO>}<5MMlnLYGX=V-f0BNj*W3t8hM|iu=~VW0^5g+ z^?0i~JA+U!4FF_E>eGld^=};R1~n?I?gi+Yr1i2Q&a37nak?O!oGia=^nu$AG)7vL zBI<-+Z*)CVa1_(2`f@|qHT1~ox*nD6%G*T-yu~q*x}^Qh=6bY$<nWlD56kaW5zu@l zv79_luBfc|dTk(4yVBj$*Y|W#>;~_@yZs~fH!t`dZtm`T&F@zJvWsqKs|8O{v8Fk) z_eW9>4*dzi9PmD;<MvRvGbb<ITefJ`j=+Nmz*8B{Q3TqE1^tq7Vjf0z*d_-IrgRa| zGf_%b9|w~eku)V|1O+?VF?RQ2x342*v*^A$%Lb-<CRv*)ei1<<Kos5TZp}2Rw>1oW zgEGg}9umv;6^DrJOH;p|GzK4xP8mRAeeS(7Yta)9%Cft5waZ0JUA0OzgoSB;>A))A z=Hz^n|D9Kuh*?<j7TzqH4AOgVcUxrYrBYG%_Ba05T$ep>HN<tXp{J?3lV=*1?BdYo z8ulN${Wu5!$qOIkYTY|JAtfQkz*yKS2gS_I$Ax8}S~MSs9)E`rmcePif9}D?IK!SE zX}8Fe&s_AF9i-bqOeA(l1UT2U9Domrxr*rR2)}n3kKU_3;&D`M8<4MSj8cq>_GXji z-tGrO9~v(8&9eab+o%v%oe(O?)Gj!JS2+~<3Yk5s52FK&x4(NIY48a$MyXAAS`nUl z-ZeMHiE$#9C}k*SC;Gl$4Mk*8ibX2>i4u~CcG5}vu+WdFb0{n{FYG@*2l`}*{5ZT` z=hJ;bU{Vs#5Gx2gXT6-$#0EL#dCf&w6}|5&l}%Mo2xC3DlR`u81%6DMk7#tX$KhK# zFA%QWb!?%g?7fGiUbQ#o!kqmH#wu+1XXh85{~!ZLf*W>ofAQV>dYR+@V>|Z$k);2} zxZ%I^bPouS)Oj9p@I9)5yQ`O{RI4SDPw+3Gb$|Dz8c6Zs`TiGf@c*}O4}G!f{_k19 z^Q;Btzj(nE^JDAf<(2hy9oQc~ayVF7Kbeerb;;^BK~bTKCtshvp{cgiYNA%Dw%eax z9Gr}Kz62<8TwS5hzHqoM54Z0j%F3-SaapHxM9b@cU&YZ9u&@mE&1D13B9}-ynOhtj z*?&KhUP*EWl9t~2jC)4F*I7-Mw7iBq*Vizeu5lRp?P6!DF*Q0G!6I&ME@EnG3XH<B zJ_s`~(9w|*Gfm9*_s`CXiHeFca1#-Mp~PIFqm4u&U^pF&#?2LFWhvE+U0s{p{-|(p zsBo#NIRt(P_4}hUIFT2P_B22AtP36OLxJ%&TfE-e+fz|i772xgvJb>CG&1T_5l~fC z<<m-YnaCR*`!3}6^g@zaQUw!pC$l>;CMG62I{2+7D-|avEp2l`WcvALYe0^9EtnGg z4LxZ34gQ>@51uf1O#4&Ygr$D7CxwN@#r$rvA9)o-MMGn{P}SChBy2R9$6`0Q-+1>S z=Txp1Yp~_@T~Kf^T}#8;z~4MqM$;+W5#K;P3#^WL*H=c$r2{ty)En&mMe=Ln;;*g} zn;(Ch8EBp?Z;8%To8-#Ye{7BFlvMHYg-G*qxr6K1I1Y`B)D{xz3|;GbkI7ym(6P(% zgF&mEj%s#r65?bm<UmDIB52BN+N-2<Zi{}C-R)8iIPAwz-(&+g8<?E)JaN9oPpAs1 z@@#xan4pBOQEjrc>FAx1#9-k=lLPX#@oWJ*{A3L}-Q9D*RMdglOY_q)kaXAE?0KAA z9WFer4b_4#cE0Y$6klpI;t*2-B3e-46}m%PT3Y7S)-+$Z<>uz@EU(vDw9VGK4J9); zq$Mc-l1cCK5%waq6=1cw9(LvDZ%av8?vc$-R{*}tV1;WmRRC~Ht>>HPG@5MQM9~9y z6Q>Kk_w?Wcc(LQ<KHI0`ATme$<-<*%?iX!9#c_4C&}6fgS6<GjMJ43C_tjeNJe(iW z^%s-XQ`16S9lQRJ+IR85z`&(yyQ$K2-+=g44Yxb(tHFc4$)eqb{H?{tyG+!8PyG!y z?+{j1>&!1tJI=&oXtd4RC_ro0xtB^RW@Td&&+Y=jaoRni%_EH#icai+?Im08`YZT$ zsnP278d78gPzV2xisA&`xUsY<W#1o{NJDUYdV16w_0;@Nj~41tF)#v7O9?n^jcZ-D zXwo`?E}@;>O7E%3x`$_~SUt!;c%ea81s$`bre^#8CJ^pu3Hy`zpI-U=iHV5@oJ9`D z_3vFF*zmiW9`WU_M>FYnw>J6J#*06fja#K7{{}QTb0uSNx;OpiW+0#$98^$H03MKk z(B6o0an_X{h2U^SV3$-@ii(K*d4Wg@?kOoLsXD7EtG>yD?KHlqHmR{Xd2yMfsA!`} zbG!V*fEpNDqsapI#K?0*+`H>Zuqsedlt~a47QQ=fdEmq;w(bCwM4ymIqvOT#c|&MB zoX^4jegcyb1(y;ar-5#>K#399jZDYTD0yY_TwY9!jtcbdt`O4R&rDB)l#6VE8%IY+ z{M6JlRI1Yx2i1;t9gs;7hmGw4q-X#yZhIr5i%)F3vPvw(om%pvJM8l}U05FHZ6=pn zxvD!e01Q0bUGYEm04Bw8Z`v?L@gzLf&e4(mnUW4G&OmIc@)_<L8F~2{XQ3W=5u}1d zjUSteg{lf<@N}!g0ZFhYpFg{k(R%yojKi({=5z>HEK+7N^6T_#!{A-qP^+v_UAVGi zz^^5Shslfu66fz!6E^bcKK1<pCvr<J?}z)xVW0H$bXGMe`y#5}cXV~_?d;|?!ZjP4 z7#|;H_9@C}3JC6t2ndQiMa7k>H`Z<YaawP8|NP7^DIqbu<@bk@f?{^~4==;}SG^e- zL|GD(3Nib<-|TC28qYh_o1DE@s?A;#JCteYNg%n_F#Y{=Aa*f4M#jW+TI(DD%VzBw zyJDPth2qb2BbDN$pDvA$<z~I##e)0@tE)>JMn)M4#;xLJ^tbWx35)f18mFiIGgb$) zRpc&Rj(Q3oIpERJ{fWZD!|@42R>WfT^n894q@?i5V;OVV9}l;V@@YtiruWCQZ>Zra zISN6rPm4`ufEbHw{-rcGUf$+MPlWF~J3B(n(i!xtAtFXbVBPI4CMl^aOhQ5;hDwl& zSf(X1SQ`Gr+#G6DYM%syH3ioxpSA8S0Lg)2!rvGdXJVA2Dt<-m)~rPrNb9TZ$&$~n zg|NKGi{y=Z$~L$h?W5=kn^XRvL4ULec$@TPi&j+&dA!PGZ#fM9{8p27`C#ttyQlCQ zn})(U+x3kNe2Up}JGZMtHE~}_D&S3Fy$*syUZz5WBkUno33QYPbJgNfqM!9~2|p+e zvs7=j-4%TYbQAE!k4Q=i))a<>Y**REz%ZGs5JIy%NXWTkASQlmvkj0NpONsZ^BpTW zh&B-S5u>yMtf{qb=jT;ni<QeSH}a=)Fslw)_=RVnL5{{rSF+n*i+~$PiU@~W-A%J= ze(9K`B$Fd>6i6f!IJ~15`)X-<pv=@4hmGF~q}H=G+XeaQ+S=NTD_x~v>k>pToLuR; zkl-JgC71j4?ZkAWRegV#o`RL7@o)}0`w=Yc`PIRknvnb6WB~@V*0^^ds?01<*{P}} z(p#QoU1)bn=cv^yNLWi8Eph>0gWPsi;Ab&YV;~N$HeaE#Z?M;Np^jJqi+F#&$p*Mv zRGTcF?BARL+z9uqjZ9*Hb$`A<DYEK-J@wsjviI4bM$NZ6j7ZW4PTk!gJ!<8>ot;Y4 z3B&6We6(842SWhkyEr?SSy^K3AAketFO;~xCv(jvtvgp{!x2FV^@^Ka_xpEvzBfon z+F5A<0RgW(J@VMtdYr?)K0rub?k{SZntsH_UfbOzc<3i`@bK^$=^%OdV@*`F2mt}? zFGv_=+7Y4N3?<*8V`9!te-jUNJL_DU2OKVA&g$ygyLT`%TWmd%!1I2EO#Es9<>N<y zhiF>K=YBPC3V5!JP~e{p?^_~ctKnLsGW!%%o9r)D?BNkGIpvEFd!N6;OD;mpUL;EZ z6d~5u=c%uqn!|-z)5ZoSCw=~wKDlzy|6UN%D#ZVbRDF8&zm5FiCBCOCQN3?h@eN51 zU1nS&0s_C+^~DXnR2L9DhqI-Di=uxwf%q9wL-7u)@fGOvp*IQ^!3#bimVcpTKIGKz z$5H6^_XRwPzk0fR*Q_KGs?2uv`jLokl4_C;zeGcSkmz4F8b6pU{Y@W<aJ}4MrYe*$ zT&J>h$jmv?;4xpa1$TIx{f;e<JxfaRS6!U8wNzs9)|jG!vrNv$Voq><Y5}Rk86g*~ zy7a_kkEHZ~F03ksjlqx19u%F1S{L@#_F&X23X-Iu@}2qgQYKQ${<%HVA21q!Mk;e> zn!F?NdG7DYd6I0^R1!2LZ#1iE7IiV;jMFi<9PUg791TM>eOr>|t=lX6V4H0^D9L=& z^V0{8-|kzroJGDeb7&Il7d$whPxzFlpX=T*URW-TF1(gFyxlI5`ngSNL9H_P=&xzd z(U*pWEqyCYM_8M$(ie@6i!8H6<&7lLfw4PVvEw=VPcc46ePcF;Y!!xeN8T#_M_YaV z_RcJF)sjz_lMVAC8pVnTF(guX{zJ(=@yr;rGhvi4VuwzcHiibBl$9bMVi7jicWn>H z7QJv?4_alH^7Np5>=W|tp`J>7OdzW0HTjDY!?NwxY&g!%%mzi>Tvu+X-6GWw^-MoX z<Gvx@_!XbK(SFlqwXcksPp?}45lk5Qr8J--3giop#=ebZ@l=!`3eEFas-2HD1mSH= zc;Z$1s0k|*@H*S9UTU`$Q6JdvvL{CQKGr4GJ6KPp<~%Q-Z-!(VZnn^8;{z<I*|Q)L zhofNK8%ccIHVkHJ=g?y0<M0T%ljv<25WIyjCNF0FTp^{xa4?e*qiv0jC`XWQ;@^@O zybTIkhGu1tQGnp|>7)NN1@EJ~L9aIpD;%9|pfJ=UAnAzEDFu=Cs-mBo>35g@$-+gy zDpkDGiodh=Lfo*x`@6%=GDGrievF>50VnjCID-s7q0KB|V$#k<Zd4LSnXt(8=s3!f zHH&f9JQ5ljTV%H92JA^R8tJ7uD+UAx?$d@Edf-+LN7eT1f~aRMJdJeH)#n0YDz4y! z(ni89Q(o&lhwpVovMy?DMpRA}K1yR!2Zrb(jpTna@)8pAklFvfo@9XATu3rbOcZ6E zFd4agj!BNnBA!RSQC=4jaaKT+ldoyL$`o*AP<;mQqx{;jgrdA1FaFR{$u8Q>d&Qsl zr?K4Zl-6RsHo16;y=x(WErlA<@z|gK(NyG(Bh5M6B1(99Gqx4)Xv%DPD7~78xoys{ z%6J<7LOd{}4+T;a!$$!_N%O?v)d{xDA{^h>M~(Ubfq>_3=ms^1w>rtNsd?+=k?PB# z63utwlJR5f0t<DItW^1Uq|_>5&NNc|V8gQ)!+fEV<-k>A&P-bUliqS~l_o&D--yZ9 z>H7S>G@C8n0qd7g<EQlr-!^STfT8_r)Bj|$Tk$D|D}KB1x~qCn9a(;?M(-Udv)t<L ztlY%8YnXCnQglt-jfLx$nXeAa8N(=y))3B>pkuBJW4$Ajq$wA>rC)k(abeGzAESh$ zsiaXB_c7-wCktsTz1egYjbh?o?7rJA&VvUw5u7r7UMkg>H0=HQEz-^#m}qw^k*W4E zQu1p@OB<gsr^mh6`~FrSC@xMsu>Fh{MuuN^SHwN0?f+TwtE7D2{41JR=h>g@`^QMj zdG0^r&;E=4^nWtcxS8yGd-^D;faDkk2Ij4xpx{5jbJfD2SCIG4CwLr_Q`F}E+~G;; zCDxORo&#x^o|zl+@`G>N-*esB$%_vkkt@ww`m?5#X;XMpQCS(HEItbCZ{TF>mly<V z4RjL!ddc_XI5zjWCv=I)L!pu)3=G5h-_T^km!ZRD6>N(#<NuYV*C->qrj!s*l$jCe zgA$q?h5oj*(WcYK@t+s5d)FdiDds3+L7$H2?MYfy9rE}2aWjaHv7MEnM+ftj>iL2c zWmZOAr2e^$z9_C))Fy%rjQ1w^PYNnz^C%Q4g}>tr=U?#C$jC6r34$xj(D8rG-+;r` zOLxgskCsTSaCkmO`F|ck%y@9!|DFY$nz{eUS}uo>1|QZrk;L=U?cNBlMCP3ID_QXW z@o?n2LAt?t4fhzpkdMyJI9(lGjLEW6QiFuFW?5z65u5f10Oo%E$mHZuK{Chur)&`^ zsmsd~&FA|ht!4<5lUl7xtCP05NTu0gBEhE3C)jYbU;{W`#SMWVHm%`hO$pt;-rilF z@8*tmtvt@Mu27Vvejcr@mQtY<l203oZvrI*xj?;dIsWbMT^4Y+zhIlhZj;EN&kU%v z#RuHZ$8Y6&!3j);bQx(N$1N0_gWhg1Swhgk-ntF<xetKva2av>oxozoY`PEE7hB9; z;s!@}STx(DJq3_^dro!WB(>HV#LUPz*Ql=nnoIzP&L{!hr|<W^!AXU>#A`1vAglH9 z@!r|puBod7j5F5JgBePC{{!TQM*EX8{ySTMQ$_b%o^2MMq0(AJv0-ym91W)?>8y^T z{J92twZ^;4rRJyM(NV4L<<AUL#56RAoxv)DgA>fgvuUZRk8L^OOolatU6&x+4VW1L z)vAz+N_~)^@l2h|@}EbLmIV}WSUiuOM8maKs1-I9D%FPmD=8`8*LNc#B7T9~v|<fh zklF@v;SOi&am|7O<vjTSDCdl=fxf=ECT)FCcPbPs`M#0w3OTqtKkV?k+Zp^_Kb)W4 z1+vES<Z?&rY{cbU_v1!_u3NG}k=<ak7m}4l@=>N<L9#06JSfOy&h`xigytP6I_LVw zLH^jYPHC>{XnQ8z*WbTXM?y<$bjE6HMyN!q>Ad*<5+J2pMf#u>^Vy=k-U1YG9}uG2 z^a+6(4X730zIxgERseIq9Voj%$1NEYoGH$$!)U!N!pJyA{cDm|mF{Q&^J#}sPi!&a zV$S&9Y&hj5FjZr9UMJ%KFU+;gn|M9u1&UP;5F<8eGB<O=K#7Obyxr<8-u!fF1Y-E~ z25;3i1KK+}%x0=wfEpY$z_qN3m<-12tHgZ(vFHlMwtDCs0D9`^MyT<ZsiM}PR95H8 z4CHdXCkin6(v0Kd;*xxR$dLka<<7PSg8hS&J~<?OAu9lfWR6VR3C(Ib08e9cP&~4u z^Curq_smR9C!Uq++FPdM@N1E>UoZD(s)7BSfE2aLr%*q?d0^Yd(U&)2^c2U{)zZ>r z6f4#Ibg~6(vCu5m$N&Ef@Qc4^MiZq7Zwmh5Lbe+p9{~r%YkU9g)#X$|2|<?~vpK+r zFsx$s{Q6`%o+iksh>8j#$AaP+90-&h!7wW$P$=kLv!$U{#0$^EV5ET!B13%n?1s<> zPSC!6BY=Vj@cR!CuzE{;#_k1Qr)ZMs=hKDl)|DaNWBo)PS?v%XO5}FGez7)HsJ5}I z(ASpE@s*r`@@D~DS~cbr?cAJVM{-2OsGp2BP!jQl9jLGnKD7Cb3Zeod58K0OiaZ}) zI@eYKTa5TXb33~>aexpma0qIu0{JD!322SO(Ah2S>FRsk?r%`_3;>Vm<MxYbEL}f2 z5S2E){=Ix_9H0kxc6XzSP?%eD!rQ{Xx6vt}uS_j}evM|42RnhrW%$M?JuQ94{~bWS z&1UMHXAqfvez9rK0<kYbQK51r1j0%ju8<~?rD8V^=mK3wS{<H`=hKJn@zS-d0hKmF zg4=U!^WAm&pq3Zvv$N9`0PW1pp~dFZ)ze$mptdmoDRkT7=?kJ1-+%bvAL36=MkXRE zDX1<Wta5j{k-tsBZgGlSchk_|@>N!rzA-S6@%CugW}?__iBhr1+s7N=ZJhufaf4x_ zsB*5Veg`IhmR45u$EzFp0A=VLPysmQ=<u-p{#qcJfZp4%wbIg3+aiVFq?$Sv8;3oQ zCO$cTY@t}Jx?`d?Alf^7N9W!zSQ3d3O{z8vrWxVP`LfwnzkmO>=hwy0{fLDXl;fTB zLMFX>Xzg@9Uk(Hj+P;|JPush(;&~_jP7bQkk~m8s`irz&gv(5o3Ff`#a!;iG?X6>k zVEU;a@^d%7UhlD3H%1zIalixhQZ`gQO^A+y0;BLA3^Fr0PLVG%J+rr5X^)H3(_cS6 zIIKqbhT`B0uO4nrmg|QCUW9KD!XTR4#W9K7s!FpBqUCdoU#2afd_R5+*|D*)hUZKb zhK6R5n9Q=tmr4>S<W8eZt)YdjC3_>Z@4?!8<oXBAJ+`RG)Dz-@*ya!2Dy9PpZ!AFs zON76CjU`KX9!03+tCtWUs5b73_E?(!F|r)WmI4V0X=ilvvGE0mJ$RbH;X2?`$3_tB zlH@B^7u9;#X3Prt_yiFEKmE$eO5*TLgJ=q3lJD9xqtc?_SJ`qIYy1f|M{F|Wxs-E_ zi;u_VaeUUj1OITu@G*aF-+VcGP41T155Ixo#YB^f%BNl6Tc<yiBwX`F!`V$*U0q$Q zw;t?$uS`YCOr~pc>xEf9_%fRALpJLDwmTvwBD%ii<iocI)_wcLv(wXfu9iicI^Vzl z34wn1j**@@M)9Q;<JtChTw)?t)zQ8z1C4Hhwn4rEl_2e0hA0nsdamy8AWhG7mm2&q z#0%3R<t+^AsCFYK4?L8kq@jsuo+n~XalM>}Ghhq6T2VCkrX+M91<7LJanKPM3nqWp zx}BduieVZ-s?G>GIXM;$mvr>AQnY7&{(js)9f#}Iyar1^YM-T=y92dOv!SHq7#!7+ zB+_RmuJ?V`BLm~WPr#59TqZZ+pfhl%{L0Utlmw7sMW?$wz^3fXq&w}T4JXN|s`jJm z%Z3rpx-Ea72{fJ0(Ojsr`ADTq1<$W2H+9H0Hafa4pJK7*1En>6SD>w>wfP7vw$#7M zq3?ZDUU0NIIZAPV4S%azV-FoZwk<>W<^3BPG`EY{3x&ctu2V$801-R@J}fjpeNmUG zw>|10;R`U`=$+Vh6Brd=jM|>xpDgU_oiIA>fUn;0yJPSA|L`;}wvD&vz(3)yb)s`J zJY8!32mJADVX1!9ZcdY>CM36@nk3+N$ZdCt?BrV+6Ek^#;}(j;SOn&ECnqOvk0-y} z{>&BZ8`~BwHah<1v{Bw%O93;^*<9H!+XD{5Os`AVHXkOym_+n{!{AHis;_#w9?JmM zf`qo8rF8Em2Ygl^Y2#6NkLHT7=Y&FV*7ok+kjH0=KcR!^xrBFAV+e!h&RDk8=eUVl z*{&tMf&QKzlf|<4mlgj&9hHVN9!UkVU6+wrex`@&RqMEyrq%}A#8@DgH87U87VB^j zTP3`aQrn+0mKK}kF`HyS8Rku^?ZIq+9J4pV(*36+;H2ymEHFtyL(`<Ov<MtR37;z? z=V~#QSd=Ve^vLhJ>Wjad!A9d$S``P_G9n-#h%k{;x`n+~IUhoFad}8435sRWR#nB? z1ZJrI<Sf={&|V&hLzEGUFQM%3CR-MN-}NlW>r$n0f)ftl07NV$;$Ggqgv>x09EIcm zp%<fam+Rt!`O_!+vrgPOVR`vVPH}%}k!4F(ksqR=$Y4XW1d$e2)<*mH7|Qx$@9E!c zc`TQ(6o}f?B+X*7XnEEt4~hpLGCo93m)=+?@biZ~Aq#qDn;p_Da{&D&&*egiE482$ zN=i}DV_%Q~@Y4BPjdO>Z(fljCnb_s(-~M9g|KTqd;NqYT+KJn2@#mrum|H;^BfG?e zY02j2nZJX1`%h)x{OT2^7Yocl+PCA3v{veje`MlMAEAupxb2RKs3^4le)A)WS8LkP zFNaY%MM`8SAZ__qUqC~fObZVKl-<Y);wu^|jH6SMQhopI$eOG`<01qB^OWY_+7ek- z77^~Q{#ESnBpd#8K}<}Pk$znE>sKx04D;hRhMe*y)WO@+?VP*K&mP9zR}e2H<c!lo zVn{->d&!DC;Cck^|50`WDc3R?WqyviynGGT2jAyQgSxqd@^1Cu`wW7=zR3~6Ls1U| zQHEJ*$=^e-^@@psHipgNCP&y-3Wq{YK%@Qd8?cBfDWUu0WH{O9QGnp@e$wmlWc?A) zb&dZW<Ayy!-I_dW%)Q|Mn=I`AXa;#pm#S1Mj2FO8e`clT+6!SV3vArVXyI_UY<6Y~ zf%;mZV4>CdJ-=IAR9sZQvo8+M$(_OO(Yu%eP3~+EYBi8h{^Q(hM_kba1{OwFcrdXM zWC=v%$}Js*<izD{Pp5>HSV|?v$9pfR4f<z_FV<cidsDK+_1f-_-$>3~GN8y`rmD!v zS)UEMIGpL}>4rWykerzSANUKPsR;78<4fh|!-%QW>@(eryb6?Xc5PWj+0%ch-9B_F zp04piZyvfcYB}}m{^0|k#@fLkJve~{w5WDJ<`COxH6X#qj#_*VR!;7*tV*!Bzy+D! z|3=L97d`OljlKDh)M#%5Bo8J9)bT?Qq#F;yQXyEg&7y6NuCyAoYLynZ>n9UxiE%?I zi5#yWhk*PYc<9&3S$%KPpRSsnRSvnd-H2zUBiipY83HDyG5T8GVnuNZ1DL4D$bT;k zI1NqPZ41mP48$FQLAwh`ErKlPyIUQzQ@y!*C)Gf!-n27Tz9*dReDD<0wMMPRirEGk zl4v+r=MekB1Pur`|Lv{3m>V5Ut6n=&Da!$y-0aM+A<aU{Qfw>9l3D^4E5;9b84?oQ zCa(yHGLRy1|JnnLg{PM&LjwG{Tn<lx_&|GgbwrPnoLsQ0Jr!S6Op49&UIHl9#ij8Y zRV6OxkC<SVoR0049et95nPU6MWm<tZIEaR_WW@>sK_;&lbmB&PN+}3Uv(4t4>~`mM zk<;?ifo$bx_|46|b~ep-8}rN33c9iJVY1S)%s!wT;j!D9y%C=RN@}1fU6b$%2O`aN z^I8?#{VwwUk(LjYvrTu)dp~(0IWU3tG=7gpNkB^KF#esQb8^!cz;PgdBsdo!IZC~X zBpp((sbwd0v${X`&SyC!A|hhrVEf*A+`WD5M>Yhxs86Gc0`&%La(wAKHZXg!bdAIV z8Eof!ZB&5I{Lyp~O4Tp#TJ%XWHnxt1fsI>gX;l5Lcd^CVcgQHHbKm@7S`O=Nu38LE zK<1|Aj}%(7jDC~uL#Tqmi(htcThl;p0Kp(o+YgT-W9y}ABCyJZh1qXjQIOIWXZ@l~ zK;Ox0ay+}d&#cBFSO51c0OSZSwC$D~scEUfTPCr&bsTkI8b1MW^K{pzCny+pVqD;E zyCuDg46+`_3Aic2p>+2Ru`qw)bV6`Ca}@c(`VsUCG(^tHjl68X;TlQ^jZF%~%z6;T zdCb={s*lb<9z7~h+%gr>mOp-zwXN1F=DKwGh@0$1FBNh*tDFELYC0hrp1MgnI3O)D z&OOAUf|N>L0`Y#!V1WO_le?U)H^_|1%FNa_(rB<OzkYa(9*6WrZ=DC!0i!IE?dn?g zAkVpDL0+Drp7LAmva<3awHn*Q)yh99@W@3)MI=YVOh8k=%Gw2~`LL-5gxk}2d7Sc; z@6Hf$$-ES%Oy_NEEcixm!()p9Ay&V(POgUTd|qL3{=+|n5;^1@8&&3c7c~O~2_0+y zlgV&PdUkr6cAln&_=6W4L$TRwe)IEy5TxQRRv&P3mlhVOHhXSEMt7k(@Aj3`t{<@O z05xQrCzqpiQX?`3PK)eDW>zLkjv}T?=mISRWvJ4idX3}bsSVaKNYw=CK$Hm0F^>Y* zfLZb7qU0cDBSryE!d=o93KHUd*9EC;_)iM)N^Ai(bNFa{6<$%aJ|pYr`;*WI1U@IF zT@LYFo+<9aQO|KSHI}n(+iyCT*8<v`ei>Eb3c<G4E+3ziqoHG>x~;{KO6`ICm<Tra ziuI^ZiMfrqJbR<1?_-+u)<O`8mx-lxSVc8c&ps9lak6OcAOHOGJ@MtqM?RXwZ(UDx zu%cxbDgva|L8|2z^&ugXQORB3S8D?mR^@0K1>!fTlxp#Lc-&g!R{Stfsnk3fk%d+{ z?QeDqL2M)j+BUvW3p&g@5MiiZZs6Ns6Z=I*#=_=fl7ofRCze8wG5T4XM0w2d!sy@O zH&d-Btd*J;;UlHn<bTdt331tNF+Tqpe%WXNvshze2Vzrlk-Ab0oNs0|7S%!Sw50UV z4+_&+C6UkXafSo2g~*2U1S2&)Zx3gk&<@^rVsTk~$evyCykj<-{XVlRxt$!%@^zD0 z$L`H)-q=<Vr~NvkK`We%VO@H07{b*Wm3nE*;N)$#1tEOFcgD1l=pu?Vtcs-t_Ud1( zu0*pUR2A)YDFeLMOt#};++6khi*8W|Zc$1sME1kNorB(sI#`ityn!BB7$(rn`&kE0 z(a}*^_vfBjS)DQ1cgIDsLt~!8Qkpwl^>*xbJM0OKp)`$3kv<>fO-hk~l0Qt*t;f`4 zEKPI`!bURaz0=ipT6Q)P8diW&kop2gFfJFe2?b27x`KZMx(xT4ySMkwda~=W%dRg9 zxwQA|e+Y;Abn&jq*rNG%dO|f^EIl9zJw_x%h%%eANr@HSa&@U&Lwol=w0)3|rLnAR zv>jKNKtQS5fYj+vAE&iA?v{_wZ4R4ndQh}YSuw@gYww)B-3tzWi1W^C#En?Iat3+} zXsFvIvqayS)$Ww@uJ^H4cOS5Y3+SwN->7bCdWysbH3C5hw5|QqN+evPGd(;qmd_a` z#4+Ml{OSHX2M#Gmqdrbfc*#YlZ7#j_<xY^Kf~E5=d>=JFx@&7;?h2i|<9eNhG+S#g zdRjG;2Vqk$OGwD)x;<5E@WZ7aC`<;h_D#^ig9l)DD{_9~oh*;;HLB%wEP}M^jzU6W zVi?@JBFrUY$8z!z=O=$q-1;_y+Xw`%##HMZ^V#YGcgF=tzPC;zR3CBwsr`wNjGA@- zDNBml&H+gTjFVH6+S&<y&Yh6p{r1Fn5Q!okxLmc2Oq9kJP*5{moNV|VA!57j4!QWC z($Whjay};k#Dl=flRRB}Ejl`SVq)BIBB#mVf`?OHey1av269ByRGnMuoSl7^tIlQ} z*ujRCA`#N$YH5u(S3?$|*4r5RGRiHmGqtv+o4e9FO~}d1o2Lm!E_-|w!4g_7L!|Tz zgM!Y!wJ}W7p)xgpQWufJQ}Tcg8{m5djhZl!@ChEu`$v#PYLJmekBLNPW`L*QCq#xN zld-bg#-#T}7Nx^}em_20#uhIL$;)V7?b1}v=WFlvVBL(E#0_nwZz?BXOz#7=QM}R& zlu9@ee>H8DVLkIe_%4|Yx<ECsbrKYUtQ6!u-Zc5*4_&hKmhYt{bDZAAXtTwq-uz#j z0A(9-BnR%7jl&Hqyaxv(=&3Ij`8;0E$QrABa(#X4i05=NlDURQKRg9mTP+UUjfv!i zLi;HI447$VYp1Vl3x4w)4daOCHo*Eov7;MJh8~vlC)Eo*JpTKU+}#iFmpyT*ukXJ1 zefJ1Fn$zpiB#Gbe4d$4pWrYIpoRjsQSIybZS#0-O8V?jlzT45^^e-rKqOn-k=Np+7 zEo@u|jab5mH}4!W03q88p<Nrq7XnU1w*k&pJW?tCqa=nSmus(&YE2m;ByJgxsR;6l ztf$LDogh*M7(aG??9>k!*wL~h;PDC%P3G>xFC1<n)7I*ljB&8X+dtbL{Vc5riOZkJ zC|>Ne)4SGfFj9dqiGb_84&}+u^Nlb*87gBk4-GR_YZ`l+HX$KFA!akmmLQ`Q`LPO{ zM)eigXNQ$fC5Z^!ai6{W@WE)Q>Me&mQ19EmfJRiM(0mbpupWinLk@wfT#=5(`-G52 z?|`(u=VHDDOT#iErTs$5Mu4KU6uR3=R4nX|JqU{1ryJC|ZoA;x^-m1b!LVb&zUOc~ z4;$MmUbe*I5(BgXpfKcZ*=oq5q$0mFtsx<fpnZ=!fE17%7Vfd-OWpWW$?&S_v>@S= z=q<KI-1={#bqcVRw~!Ck1VU6>A}tb=Lc51TLr$CoBnREH2aKJa_-WJ3CEa@C7i>fV z5Tz&3yM~;Jy))t8HlVy<%Y<C5G1ClM2DN<UYgCC2%$d7lK2JVJ<cOe8np=^}pl1*O zv;i44*)QvrQ{lM@?hjTtY%Z>isoI(Vq1Ti7PFpoz0`WGHU4sha)!qWgml(qHE}m<< zAo>P<!~)HCqD7aBBeSUJQaE<-Qp~O5k>Lo2?>cZF>Xd#ODEMZojV2NgI3t8_BRlk@ zd6YGG!Y}1b!hU_m_^Ri!x`q^vq3QdJ#o&*hY{a)-0B_EOvo6BFWVGz&9Gu~nRoH<; zCiyd|&GYVh|3{7y)LTA>jkUEebqw7#cr?)VnEkSAspeigr&3HpLJ<3C0zLO%lcU%x z=iwRg-}_@R*9{HxT%X@i?yCwljozifMif$?9rJ#LxzHiyHAf;H+!Lo%yD^ly6sZN2 z$xDpnxNigy5myGpUUCH9p4ouxnKD}(=;_&8s>f6ZX`8N(t4u{+=AVb8zTA?aID-Md z>Ce48#5J~~BhD}u_fMB!qrGYHRqH@Lmu1GG+V|Z57noqBPlXnaeoSQY4sIkem-OLL zjZ5p&*#jV2wYj8%5L;ee9y)q_1auf9*^tS|h7yxO1QTDFySXp65SEYI#l?ART!1s< z2YnqcNzikY+ugS9SjCnm4{NqZ&1!t3anvhSnod}@4&D5`DYB_O_eHdJJ^Uxi=X)<I zj9cX4?@^0XzM)A%w=X%~*$BmNn^Duhq}jGO2yqW9fja*N+8dO3h<KZ}Q{pbzQLhNZ z>7HR@ZJHhtD)FfIUlnngOW>4AghEEeg<0i)-^Ox(nUUl&oPHtX+&owtI0a@cr&C8` zXg6YJL!k<B2rlM}f<)KjbgO;}dM?9s`djNIZ8>m+gBDu21J76nWPBIfFG?3h*Ic+L zclV~UuMUh$rxarqG7pgIp(iw_yg~P&Dm#%86^@lgIINBVAeGMF$44l!*_vNPMHca@ zPtNiG;q9%%vi#aNUlpWNx=TO->28pe?gr_Q?nXMLkp}4o=?3ZU?(UM5W)@%HcV>PQ zdml5iXaDE%s602%v+i|Y>$=YK{OH6AR8$)h5(2UpOzZFZ&z;5?I0IBlE|4O-)1qwD zw=G`yJjFutYRh?XDDuJR2Q~UaGi5bmwn9R}l}>r2_1`LA&=N&;$FspRE<`kW%zZ~7 zxbYg+DBOh%yGEj<2|`_I^)dQUm|8t(NP@9RgyPrz=IA24InX1GyN3hI#RnR+p)xIf zGP|g!`8?MHLkId=2gRi%dTw4<CSc<fTGt!KD>Me+m44~yS~>g{92y}bX6s;Mz?;im zM4^y6f4s}pi@F0FIV*}B^*zOt%~X|4uAMjsgn9w{!WegDebH<kr2PtWp^k<Tte6nV zxSrL<uN$m|5`kuQMp1A-e-HSgmwgZbf>ghBj|Aa;@~ezYNEt75(P#dE-STI&(H{0Z zzE}hq32L;*+rp>&qY=m>X8ZWC0>!l6=<-`76aT_)3uv--d+1#oBdtCQeKYw6%%Bx$ z_<wCDL|U9=(g@jk#<7);-2qU0Cm*f*NJp)w%QQkeKH!Xs#nViPQX|MbXp>?Ku3#d) zFc|n`U`B3@;b#v|*7DJ^uOAUMxDOaVvSNY|vqu|7fbrw1x+w|V(x~|)No_Xmy|?^* z)Ku@@9?lk=lOKCUtKe*g5b|Ai_zUoyVqsHX*>sdjzTwk^kP|ynKL!{V5fznSQ{D!; zex~xlj*gOs^Pz=IXwJ>;Etlm#di`zZ-cEoAND)Tx*fS`;-ZF;VdneROH*{c`$g|`Z zIgUQey|#Jq?iPt4qM5MWg=puMXkf+d@R(>!WCFACqpfBsi4Kpvdv(bu<Y!B>5QY8Y z2hnJSaZoTqoLw=-`-`B?9qK%32F1_?xY=VYi82B!6X4wm!uX(Bg0u1dq-~G7z4^@k zvk67b=RiN+ES#KnMIzo;v#W0Gqe{s_$N;bA=}6LJObrMkX8<?%920ACVD7`n&A{Z8 z@XVruC$2(TJqlqeyB(^HZ$^e^uvupp<voKFY`dnnY|t<N2hKRjR>{Pl?nB#d$W3GJ zpu{d}kYI5k8(0p=A+hr%+vz>6WOqj4z+mdq7e$J?*#7lfz{7?ke1fL|_nCgCj!!Fb za5QH4@LkJDNm9r={>}NpWcudRP?m(-Sa0AmyCO>P_jk}XBfD!5s0g4Sc+{VNE5~bk zz3K^0;-GV4Ta3g>8i;hLkd^~ZN?b0tr0YyHw^^5><t{Eatq+$n2bh5IVivHx2@D$~ z1K!0Wlj%L*6I2@v)RNCPFaio|rtPpwf8DN&J=#qxii89E=jywMhqA7My*-dAs>c*` z{Ualw*WibHG1tQWz}pjcQRCwiJ0K!DX0*JBd_$D~MrSONKhlrA%xa``90x1K*gzRd zP7ni4AI-*zUSTW(4^t7iejZBGD`T1qL(KLxe)9cm!RT*}z6?@E-2njPg<4bX?xD~( zyQ8hvTOwj6kjj-mWxrC-zUgBHb%F~a_nEK|^|>RpU=a7;h!u*#oj@edPTKJghBuV_ zaBHLG6X!-FL17^RRk=BrQO4A(a2VpbZ-hx)e>EMJw9%yaXJtO;l-1Z0Dk?PKH%Ur< zq9Qws+{-$kMaEUvjQIY5aeUT+;bJeDGHCUw;6nP}y@1vDfcGDsk#IP%grF{bhv-d^ zK0?I!gYE9k8qIt}Fkd(ogPNjbaZY_=Qz@pV<OcmO3gKSb)W&Ev-E4+Y#Q|zKweOpo zv2XAoIUvxB$nx?&ZjYCvMixf7uT>r1W@QLghNuQ2n$VL8YG+qu6G0NoWf~;*=l||w z!iu6iUZ}*g&B>R?+0(7j182SfDA#e7*ZCx@H0v7`ZY`>e5$B+Frmz3;%1m?{x)KsU z=b6UHWNW=w+pm@g=e5|coaP~y77X@eRXV#$svNuWoQyA4?UO4rC91zH<qxa(T8Hi| zx;w`YsL#;^U~cR|-h~dW^DVmh@2bzkwU69-@~j}`z*=~@S;9?fthw0+l=rx!J-!~j zR5$putKx4;Jh8M}u4bmj%4;e<2jPn;)Yo%nbs)h?7!;y}jy&kQy1b$j6wA4`^vPRX zY`XRn+OtxQIZ-q+Qs$Qhp@&Voa#-P4oc7cQJARVLjA(~hLVc}JSEkk`&a&3n@dE<O zlVi)_q?Cd!*(Vgvf3X*s#Ln{90XEOw)5s^r|EZkt#edhb{y(v-{O8td$ZHw!A^oep z9U50JenY7YvP<$!{<$76qW!;=Jh}f%Z~wpWI{-F@<H=lnRFwBifFo9zp!$Z#0+7{u z==N*v<UBk}Mng$|ks>P?z@q{J@{keW+WA2bGD}pOfYX7;?bw}TXJ~Nn?CP|QU)I{% zK#}<$fyh~Nfmp3p9ufgJ5XpCdJS`2N*9UB}!-1xzrqxvxEG%Q%KTqUjgJ*w`ffF%_ z(*qnl_ooK1a-~vfv_1m`yQ;HamTxmKja)dR$0a9gG&fKK8ra`C!pn5mk(luCa5xoz zf@cf?fO~<7{pQvYllg8Wi7&L?CQtydS}tmqX={ZsvoU?#^oweJ;9Y2M*BkFlhkVr* zrekyi4M{A>>Gin2%)<rb9w{R`T<i^lsZ4Gla~yQKXantj|KioxC;O|!`cfqJ8y)}6 z+3zS7n`e&H@1*Jj%6oPsvXjM2ZkPRw9C+i)i;GCF{l%#cfG87>=~l=cX7{>^1!fXY zPtR}am!xD_*(Xtg>r`*wUd+dZVq4DFokpNhxbijR(F`*Q3yZF_I^jXY<VlM50lo0R zUy+ps25efXX8r#8EEa^e_OjPdB9H4N48lsi-OOD5JO~zY#HAGN(WpJCo3S40>tkSI z>cR%SR`5NV?wO9aO{8+Abp#^n2HssAHGdw{gVY6lx9)+lEYXS$3k!=kZ{GZ4aEP?x z7xu{u=6mW~KKB!nGcb6|#YjQHO3BsJv%_#VJ~h?V)}{@pcO+wFtq)_(8Z&Nxj*ANO zm7N^oXyGdHuy-Z2Nu@uDOX~(+UM_!AQC6mX_wKK8tL0_7{m8^9iEnpUGX24f4j3Ab zY2=lau{rd=y(+1zWA}jYb?4<HUbWch{`LyO_weY*cqr+;2N}mM-fmBKS9ynE1_};^ z1hvG!1aUdPv*5A;m;s%~hEh7Eo!(Xgi%ttr{R}%J-ePmO9!}(qR8&@EW@dso%=sSz z51bBW@Ng0okpakfuE&f1&)V{n+4|6dwdoRte+_PwJ@#vlM8dIa?Ea(yT3MCJnE7Nc zYHH)v&+2ku3>4%n1kuFqp57Xl`yk+ctuP-Q*1v3}$#g!uucjpVZ6%o#K#Wb-7eNPb z;17ev<X~SFRrYsg)gu0{N0B7C_@__d5fNqDOG;{Lu@mzZ4sQJXzkokz&guLdM8I0u z?5^@+85{4_M;3&HhdVl!b`J|bFZMGF;DRgOT&ZDVWsUYEj>+<Uc!Yokk}O?aQ&cRx zovovo^bs~TCOQVJ3aQdk+P|9)+sXMOy)_8n2cvx=URMxjuauoi^MQsojW4UH=wAxH zbgKG==P5l<z7?M}9{qD`Judyv)rILy&g+!RoGxs61)@%Pgy%YMdtqE$55$G2(sh|> z7VOQ;^Ma%51!m}YSF7>o+x?a<I8b@x3H`cr7>0RV9e&<hS-yLIH@CB9_XX+5>%%Ju z%ZKA**A=N!$;fq&E6YzM(prZs{Y-`;9i@Nwuod>MR*U%mEw#2&BBg-k>^Zd4!-PM+ z5`jWqu9Vgw11IJ1%=ums^IKzQisNtdb$Eq+s)fY=BXk<s3OD-+LC=n@Gp^C4`lJ)n zwgIGTny2Y(hK7`#bjXQ+qwbZ3E6HqhIgE|;u8X~h<;!$^)mo2G*KY2_&`Vx7>ae^I zy^<rVMO>^F6W!v;0}+i5SMN7WQqXWy6W%kM%oa2j)i|T_dIAw_X@gQpx5c7Vf=TOn z+M`Y1oaA;_Dl!N6MADMR!k63|ot6hGR+i+0d56xs!I<JLBY&Pht|$rQpRuI|k}Q&D z@#J@?o)^oIY?Ipd|D&oq+DLn*U~9B+uLaAJyd|BEa{Y8kc8T?2LF3$(%%fRbST%{g zfP&Wx*J$3v#Q39)tnJD|zJf&MxDCS0|0{WI+`(*;dA<LG)lxvpOqsJ~vnD+QU(E$6 z0%ICqFq6r0bvzCwB`0$jU2J6`zDPoR)|km>HfrgMEV4Aua@L_@j{jP+t$WZO;l6$z zqGAk&t=dMtTksJNl3c7+#dBp5u<bNM(*$_9tz{ME5`P}U%aLid(Y{xE+v(jm#h5qz zaT?#sj5z5pi4TzfBK2GYlu4e7BpRC-7k-<wmqcXGc#reSO$sS+V4}jV_C1pTX>X8> zv1F>GP)1aMLo@4irp;dY>3ccT+N+i~Qc>w@pQDw3CB#)8gcyG=Cfqu4*y9jQNbK6d z2!eQn*h6s%g!SxnKlc{%3TgMrdSl9A^#5DN+d@hAT7L2@c8I0YI2)6JHsv-<u>-pq zz7iT17FX(@FVwvfl2r7?<Y|%}ozgp|vhsxb#Y2jb#AKWdtfaS{x_o1yDdy(nydT?u zy%*)IBtJzYv15#Wbd^42!*-HD!~W>_qP)@P(?*Yr_8<Ku$9=u5q_e~QMCU#{!GOHd zzMEcBP0l|o5ur%%h#t0GPjMP|+SM3)I2(m#W`+GH_WHayJ--UJez6)ohZBKOJx707 z=JlSgczqBmV~o82d_cn%B4=GguB)Vc=5CQOLc@`z7X08F>nW))B?ZzqcGz;5`%@6D zKP6o<prHrWb}+@X;jh(j1QG2#lnl(;NypFU!s!L3sb%<DH11k1*=4wW-^e8l3jbEP zhls(}Ur?7?u(vXaMoS-#uT;#Sr(>WXBYIy{)rlZ7BcxDKGd`ARf{L@=m#`T7QxlO| z-y!#v-w9i64oM7t+PgwDzN?%FE9Ug)EAM5?dbQ+Oc=MPB-DLNgyCdKO4U3_444T8i z?Z(eypOh+dfwOvcM2kSo5{>yutHkZg)%H33PJR(ftwmuEukC8wMjm(9$JvRLLGEy= zEN$Gg{SKy|V;d_CEli53c@}fIb`W0>D_vPLoJP{lr|9kN3JVV&F6Jeg0|qB{!X%t1 zKWgPlF9m7THX*vPvP4zG{5MEC+iAgAIfbq47EZfExt6cS+GYN`NKQCo1S1WW5IcdM z#?rSz`)Wl|$>qh>C<ZrfuC6_sXLgK?i5hNMN{E{3j>b&dnjg^g!%wy*<Tza|OElQ3 z@+T?^XFA}GtqhIM9SR+Hg>>4UB?c`daJ+@YOuw)FVQMXpwCoc`eA2J`+32r26yZn4 za|$MmAKDX%$u=)zf{KyXNlVl0q$)e{oD>cmj(!t)NMk&Io}X^7Jh2mu*QX~tzumOg zHC(YQ%*Nw>5R>`)gy;R;%>DM+Q9`nLaCgP{9JU8i@mT-AsJOq%Ag0-#ox#Ba1FH{^ zR>;YrKG&9!W&c5<-fJv-x(b^iZ)*m1g>n`1J(m-T9Utjm|L`3;X)4JlGj#Or&27BB z11f52hHQBydguNfEMi+AL|57<_@}(RVI_{r2<KxV3;@ECa#(Q@DA!3<mC_JMnV^)4 z3OgX?`0K1I0?9nzjVQ$5?`7(Sq*FyOW)aua4$sO){9Sp-QjUK$>L00q;sk9$qvxLw zh6@axlR+S0<R_qUc_ztaw&zR|f&X$wAop*LdVnHSmrq{1;7d`pHG_XX_!e5`mDm2S zz+V8pyFuDtE2_$<JC^)!MRD{{Ka{G%zc^5Lt5J7_?ShJTn6MZa7-KQ?0Bj$5f|O)+ zOA^^HX!;g>A^$}}GB-Lwi2|CjB#$2+httt>va>t4Y=Mg9@uAZ#^6#@>Ok7Y`4k%UH zDYjQ$wdrJBt31(%p?s21NbM+Cg@D|xhj{*yZ(gM9B%~!iScRl~`c<g=`sTI2r2k)k zf8^7^4wk{rHpA0Pu@YTFoGy=L%SJ$HHa0R8k0_^S>uCiN_waC}!Myi0H13CY+1g8- zg@x${!8>B7JZERL4C7N>9Kgoe*_r(b15E@K#C_ktY6-1mQosRJyOnEbAQ|7?drbEF zK*_{(u>5d$dJ21aFjXSgp>_LA+v5G>rfXs{nr)*G;LNte7+6G4t8H0TRaGL0cy*19 zeHzDLd=G-pePI_18w30TSj|VjKA#g`Tug6mJ_ZsBg~uta*<u{EZb&9GD5z*urYIO2 zZN+-&C9s?B7bqCtLoB=AaT`4`GcyzNoHf{dD0=#LFTi8RGB2DUK_(_DYAjc)2el*6 z)Qn1&+#je^fIPMt5kZLTgPQ;TRM7}9ng`@^&MWzU(kQnbs{X>}>TGXJ)lqZAl`DNG zEGqhJCpVNyjElRxJLDKjV!d&f+cvgcYX^DAJ$l5XjCyVDUVyW_Q2k|~#o_+C4`g~4 zo;shx!h)p#gX3*Wef@{AdO#b8LL>|r{RG>n-?jhs*RQLid8+sC<5VpH_pfJosVG5t z?Va7Y{Dd{O%)QGiaM!HVN3gDo;TRb1^xeVgb}EfAF!=ijGH=O~`HwN!0BU^vod74r zdk%6I7Aa8;jaz&mfC&l@>H3<Kq`r4{es(6<K`I+MJL?Pq;jt}&3gZV7t;Q|9xo5-D z9|BI(cz8S$8KhhXE4HW;Px^^kALfhI6t-hNsIx~Da06BFpWnMcWOo@+a{!ds{|3`F z`ZUc?nleeJajRE~AU3%l@32{q{sekK1YCAv5|YzeJ|nBSrVNc4TIV9EBITG|$wtR5 zQd@7s!MOBvJ`mSS9*X5~I7(<GmCjqO)hG>(Oi0LTE(Sm+%9c}wUHfqZbMdpoIYm2r zE?yJgOC&Jqs;bMuQ4=^q)}os3QhYvkToG{}@2bY7kH`%4V)Nz`$v;NPF*N=msHrZe zLWe;>yl{1~Hxwcu!vPU~lR$txGXWnObU0n#tl@wa*6Mz=Z7~APvZM(}I75Sl7bg=R z8{ED5e;Pfoa&aA~vn*LIx9qIS#@)#O>{qqPPVWZ{EimF5hdP+HKtP0_m>Ls6o&<pe zB(7b(z>rX5x@0yqf5}n*ye<fUXq$`2=RX=E#)X%fTn_HLB*ZX&m>!O15OBQ_hXHX8 zn}kRNybZ2XaGP5-C$pDlThta7AJ73`$ZC7y`j$61ECd+$DeunKa|U*Wn3x%xJRi2R zgZawI%4Jy17w;$hP64Y?ZEg<06FT8YZAcS;opgnM{aOog`=`TNNN6+7;|>^+ha`(G z_UAroE5GODq#!4EINFZ`R^nguHBcIf*_#F+r3#>P%uG!$_a@*MP&8~umLHs*4(o`@ z{qO#q1TL5AeuUPSw6r`12c4b>yn*j7AW?%hl?xXe8}h$q`#s!V>XspYG8bQ=l(F7I zB_#AbzW2vHKK6x1tO6~Jfhdl<#LAt+B4y#_<L#0K)@fzFFv80*&xO?=pAU&yp?rWZ zJ(HiW6${4q>X>VFbF))KdbC6XYjf?HeaBuAR*yu;=`*a%YWwQ2AQWr(`?1?nv+)Wb z3`NI8+gw+hEK9ENKLOW?eovTDXS25|+!fg^90Y`~+tse6xxw3WY`{e7tK9Jn4i4@O zv{-1V)LG#L{gv2y!_~(J=-IGf@xECh{hn~v5_$jUEqaZ4wo(*%&kg$xTFh`7*GO7R zzqt0MU-zHh(+RRb<SMkC>l0^QcDu*3*|82JBA%&&j|Tyl2YQ>!5TZoRH_R53s~{)w zc}!Vl;UC3NZgaqTq*}2$GFx}em4^IuZ5Wc4W+^8(212+P85tcM9NvZo1wFfTaAwP} z0#Z})=b}vb_4PJbm?wu*S~J_X!mv4IwTCJzD&%P30P`^{IJiu{3#NqR4zpWSw8zZM z6dM;iwtOA#wT#YrfX!i8#z)bl#6-)vD$g|^7myDklg@w!rlfBGr;yWaco8&{E{^By z&c9ojbkC}7)2aF?-#cadB(Wv}0-LxTm(!72gLzkHI)&u5&ElATPp##`aCocz793J4 zfZCBU%c-c~@vaAgCrOr#1wf$~Nml7&otvidx;b7gzU~_Ulq9~hGgd}sP0$mXFdmtU z+RbeOFgs!4t+ozPl`<`373-r0#OQjE1K@GCX^N2j7n!wSxEZ92goL!=d4F>XAQS^# zpB#?HaZUqMOO62N?`_;%l_@-Fo;SqZOo_%0;B%FCHaL8Vz-7Td2`6I9wMt)BPfD_T zyycQ`C!6mGjKHMP#K*uG3TnJkF4in5D~pi*;k5E{S26V;klkT+--O@#h<xw|mp`SH ztn8T~YaIdWwz{jU8P~Cl>o26Y4};bo(`xD8zJ(;xCpX;E_PE{9?}&xHAv6fi?tz4Q zy|A#LzuFawmCEHYdK6lR!XPzg2cD=b=CXVg6i{Ej(ehn1_aAPGB=s*2F8&%tiK0f5 z_NxRMZ{5y6v)}M}pzbVhD#(GI0|6G%VxfkmA<U2v!knB=yQ#@!ESdtu@N;nXE-<pQ zQb?y6Sy=D@hE?Wzrso6H8a)u!3Zd4~cW{(Ar9X-dR_fD#jelmTI_TdFME%)t+8xJz z>VRqd<0NX$p~>RFVvry|F>x?eFce;_k+&U_=ZU>LU+)o``)xJ~pkQz#0_W0in$1;P zky?L%aGJMlbXL8;TE?R$ir8L?%A~;}AZaz~0&dpuVg1u*0}-R?^{p?KE6ovM@xX0J zO6jLpG-IJ_>~ePB<xNH@bl~}W7N}gmm&{>fpxuE~RFGrL>v?6q)J>4^;-tH~XXMFv z3&fyGr_~3&O>7cX!hl1+(_S+k;U+nb^5Zo*seNXXg^uh*VDs7oca*v4dq#%8ejW+# ze+XZpZ@#`ScyB(4N{H%hz0-X;06;fjnK0;0VuwY9hH5l9?<G!9;^PZhY&KLEX)c)o z%N!dMOV_|(MA=KO_vs^lu1-0ewhahQ(<~?RGpNcm|GYrN=ayvTJ~?Ui#OA3u-1`<5 zHd>d)=anISq;CGY!Reqswj(sY?Dt7}rPq!%dx?4t|AM)Z8HL>^^GH6=bbs$sEiRpA z$B)rGt{W#n#PPxIRO?0z>18y&IiDrS5t${M0^P!r1t(Bq{AqF`Vt{5O2R%kmLUI<; zZxMMtvKXETy_KflvZ^$4y*TuR`Fd0vZ7%MpW^y-X6W|f}mG~Vy<mvHZ>m!Z+Rq-K> zU#}|5X2)}1k_crqKjW2?E}2PqSeW@jE=$112AaLSefCQA&!5h>7ix2MB*J-ld2G(R zFp%!mU#5g;W{XC?0zZtNm-vWJ^Y)$#9UEP(xc*q+lf`EguE+9|7(jqU>p`NXrY7^K z_P84kL~ibv*4A#Yzv*3rxZDpe?Sn$Zp|u;hzUCIG>%MBPF&}du{rcGOv~TqSMUXd8 znt;o4z6qnmAiV`bI+Z(s0sEJP243>jiPbGl1jxV9C;R9~%$M%<6y-!0LA#fj2qK)L zi)0Zf-v*Utj@6PS9`s)>AnpgxFHTO{YdTvk)Xz-i;L0nw-Zp^jxOmC!?ftO((Mn@F z5d=Kd-;bv+0p82T!RB}=i+VY!)!8uop6*492j2Z3qE>WtVAp8auGOI+lZuRqX*AiR zvPW%kK~pUX(2$83P8b|mz#7XaEc~?hCi3-X^wT+CN_&|fBR&MQHcwa$A8s#C+_w6w zM}Lm4u8z*ms&4Y3tp7Zz@mjgeEh$M&jr;cU!Xg8$vtFIW(f#tzpD$$F{8k6wl52nW zgbPHB>l5kJ42j@()ck?*)TlCHb>Bn=AYEY+6Wjq8$_WthPd-pl`C$f;7P$CG#(d~u z8t>b?B$&JswbSZ>U9-B{LA}OIrAS$dk`j0_=FbfLonT&p#wu=z+XZKpRUofGXOekg zjbn+r`6eXi{QRyFfPPk3vRN&Q{I<Wl0=|;8N{0hSNSR$@^OcqlxuTDB?Ch#<PR@i; zcQ)Q=L~k8$Q`GaI^srTE8jdUjDp(&f87Xh?aKBzZB7uh2<0VKOSpcaT9TEm6z+0F@ ziJ~?4jyj$P>sE4%#pUV(R%kh_uF`67mWa)A-X|gAJ+ytck+Ct^2Llt6AP9^(G6%%V z3ghycawD=l#u|i%^GJxJ>1He+_09^d277tsT<9PaL3Ce=)r&rT5d0+gYceZ7e@M9O zmHJ=|W%&1N#xu(Gb9l#Np4mFxW;1D|HB>nlm!~J~v=BI~8<M@?5v?Y9S=HH`n0ywj z6%|6RFWm;Lj%wwu8_8e!RgCi(zvq<XY~5{g7y*XIz{m*Q#^mfz0j(-Jo2X#+>f=R^ z-&#uWa0>DhONCrujnPri4tLMLu}L264MuhFXMnpoY>V-)=Wu(iqYh$XqC<Kei802+ z7vVRyj>ynOy@HBH@jvCF!wI(<CIGTl?0&eC%ZhDYZf+*S_ZA+Q4s$nHCCNuGg@LvQ zw=q57?#0z|J76;haWPLJTM`KoHa0fjYvIVn3TNu=^3+;~M9f5G-{mVbItDL_zzPeW zY`2qm{u%zJQEQonh5YRnl<PCa>T;a5HaBN++1Uovcy4{zoyLb2x=HHlM3bV^R{S+z zW{j?b#(?J}Nh5)*mBr##(!eRoMg4xHJvP=rQWn6(n!2RJJ_KuvIjXu!eE(5a7WlE| zaIU(FnNOW9G179e+4!V|hl?DUfS#qq2S(mCsqPw50zR~2N08#pL$vv3rywCrA4#tJ z;o%`@=a1)T$XsBrzpE%OZ=0s(NxUF2JM#>UD>nqT<g3{`k_uVl;WQxe*gV51io}1o zfOY{na$g1q2g8YYCi7PKuZ$3cq<dqjZ^Z~`0~Ox!LB}M0ukqONHX6cZwRpSFM$f`9 zJlxkU9??u69v<A$mzeryF6$vMyr8f!9G5ld=pkReYj#vt=S`!kYQm1kp`5&QxROkI zYn9Oks}#s#^}Q=9T64X8(&f*XJWrfmQAZ83RA)<Iw9yQ<eZ1Yky4Y=YId|+ihUkF0 zbh2@btzQo#ZP`ZL_|G0Uy_0>{>)xWny`iDOF@x>R&7UI_K|w(VJy|#(?>9Av`c@yB zKkMr1QgoB+TbQ5z{Aq2Ev4-5720Xp0p#Eup?KN=UZoqNs+|=3WL@+4E_`1pCi?Q)Q z5E{vDA(zvmk1R3Gl5t=?iV#_#cMU!rpcKuXy12N!e_sG#gY7z?0PpNmKqlf)=5%hb zy}TVGgB~O5X-Rq5Sp<ca_;CT<H>o~!tX6pCQGNdoClGN4P9wT^&`)WtFL*?OU=ur{ zBqO7M1QxTr?b|m)o$9xgloA0%E-o7}Un4AUjOmcg{R$>L+gLfkm~8Ei7y+P{!frRT zt_~`$e`z*4KIEl)(zwxf?k3k-c9h1u6Jgv9D=yY*5VGeVFJ210LFKYsyD#0nHyns^ zLJ*_YANc9Sj)=z!>BYX4p>leWSlK$9(gp$oeMZl%_dDex2tC*}kw__1T(Do;)c4yS zyXpxFb|4dRapZde9CpniHYit|*k+PzPaI5U;Eratir5;Rj(UHt)GT=XuuN4i(Rgfi z%d;#=0`v2|*-}JT#pq}SAD@q$P9`0(dr`GkSx}dpHu3l3|Lz4;TYbRM&o4^{(R%Ue zJqlYqp4)k4f7+ywSXq_pU0i}<ifIPNdYsNKZop!3S@tr})!mkzLL%E(->^Hg#o?eH zez*R`5rtUG`+FGOao$H|(<g6VLz$I2n~%`YZU$lW_-JTMe@<@95B$R;K#m-ZYLzN+ zKw4DklH2!|16F_=vbdAZlTO!7mVxZ;l`fB(05)w;Y^F3heAgkLSH7cUzP$*+q<%ut zwXRpY;e_JMwZH;P!=S=KnP)bY0!|<ix)<?aBabBTI=l`Br?FPo%OupD<%^38e1ap1 z!BD~m09hV)f_K<kM75!GYps#YRVpODBv*r*CYWk*-=f0vtTvy!2eE6wu5FAJLX4on zPEHQ|b81tC4vnJP6~5{;7r-5f%|8wIWo@iES+G)q7%@OB|H2uPdWqW=2NxHg$CjTH z%EuexcB*)-MK^1=Mxc|L%kfx5bG%ljtYT+>sgZL1P^oAJ6ElQ!GM(4MadVdey(=~X z<QL*=DM^MEsW^2F_;m_hb$2j^zYJ!q89d~$qm)YPUfu|XECjRxw*x{DQ}p5$h5ZzX zUm^cyXRpk!)xjFib0h@KI(v(w0E=rb`wMh!q}_>gi_gFJ9W=HdDl>IE8Z1jQ^Y~8| zo!+tVJai4r9L8R6V4)MAPi9yYDScrBQa_uihM}bf$H|Gi-iOqhnrUs`mV}2B;Q=gK zEr)?~-u7y6c%xCTaBW*xLOQvNf9qUWxY4QeqLb!;)v^fW%pRrsHZMi#=P8%1_<S<j z*{lyGN|JrVh;PhDD9Z!LE3mDb&$KWlF&`!X){|zP^?PbAjpYj}Dyl|Db36{$u(Few z-@k+YWs3}B$DOVGau>lTRjAQg9uUw_QgU=vk}ScT5_TP)*%5d}r&eKp8odQvPiks& zjZT*OD{#(u*Xv#IA~x)t#=!V!Fbk8-A34kag2bf=Ot_P9aWC;ECjc;q0gLK>=WxaN z>1O5;B5+iDIO%er#RHn&6X0?CKlOv)EPhcdLA_`YiFjp^{AtkbbbPDELftOgkqOf; z7B5=HaI*3rGo~b$_3rNq@+Vad4FDC}KCFkY?)p;+2-QfJrXX62>$yS&J0UnvLKWq9 z0u|C99Y(Ia9~v{myGDWw5li01;v<BFa6`1-#F7#kMHkoA2W(JKP;1B<;*8@RSqr&{ z2X&gq+foNlNnBp5tGc}u0L6{Z`7_=Fa#wVFzV7(M1zwhC^B#rAYN4XQ^TAc}1{)8@ z(7?bPP_UAV>hgC%m3p?;6OK={fgMR<H9(`&fK8&(h?H7VQjCI`MO|M(nDq(f#wwbd zJ@=KOVjaHW)_ASbDxCGunSV~6D6Z+ajDEC&d=)b@>fBE<W6AFi7j5&^i(jVm!<Tu0 zF^74Ve7R(8JA@D62eQFf6Cb_x@qHYuz6j}ldz_i7(B|@k=t7mr^gz~^P@`{S%A`;2 z!|d+8PgdNuRrKi`N5+!oUoU*w*+1s>617Tq2)-8dPW@IrNU5tAr=*AuANV(@cVK}M z7X)`b1`oWarKM$Jf=^618}Ug)g~TK$G=c+e>{(7DqJtoTX(|BzP#(gK4&?Xq^CRT8 z-z?+sqQ~&@B+afin<_3C)f7u4zVUvn81F%emH{Ww=T|%30z29}>hVkC;tX9Vx^aa? zgvF1C=nzf$y!q=)*0{|j@k65<CkHqhs{rqvRPL?IeYBwUrh&0>oa(J;`BK(lM|r>1 zB(na&Wa$SNPAun(-EY!Leod0~5ieadp!$C9j68t2j)D3ykUadVe<BD_xWfkVxACkG zj(JunJ*QIe+3~kxW0^tkH{$9-DXcU+S1^&%yu0i^Qc@(PNshVkU70rnD=SbR3QD>T zdiw@?;`4<UyvxQ%|CaK?8}&}9cpUv<E&l9hW%Y-rPSq^insxG;?99py*Y<${x1%ID zUVCj(Q9Q3O9~5S4TmXDJ(bH`8gz!l1oh4cSb9UvjK?ESB11%cE`uxk^1zu=9;$s76 zFfR-lGs|R)e|qhgi3*p81_#h~Jv%$co1Tg1rp~a{HN-fo)Nk=0M7tqeYVd&8Qn6U@ z{2uz%O2NQj(#QV^#E8bBdVK>@j0}&)nva19dZ0ncCHE-8ov!n{?8)Wx#j2@U{`n?% z(+`B%u)pK;Cs;U^_2*{3Wg35*sFfF8oo0AVu4~uvw;PIve+K?%C2Q8P4%ICF!oog+ zz`OdjHIwu;5&6wGIb~(}HQUo3rM7;L@ef^pf1VI4Bo2NWV?>_y%5*E<zqM1czoU}+ z`^Q^(pLs-)C$GTZVQ;WMbJkH&37Gt-t_C{(nHTJjx)&A7Iw@?){>3=`m*GW`?DIqe zDeV(qb?QIkBle7+L5wnS!sV;t3R)$y!~jF{jAMeik>1=oe=V5NeV3k2mM*sD))RK& z5HrE}cQ!&9t-u6whj8Sde^zW<To}SdwEXzr!Oc1NlO)0=2wcUM7pFQa5oSp%tobft zZ>~ppx$+zdv_i!^0W@2j>Peu-{gF!M^$Eep|B>Cd%PT(N`5NQI-l1cn1E$pLOdVy^ zXS?tF9mPE=&yD7a=;-ncZE0=ZD_Jl^aa2O}K#h35_Cjz;QN#T5zIlb2Wko}gBdZFn z)%gXb-TD9gZX{2r7roH`VOEp*;(ud|#=o{wg9i{z8GMq__XOOoW{>MrwLC=YC7>Dd z57Y_hzOV4PmD9%Go_lgCQZT%)@9YI4=-^Np1FDFX0XE?E3-jr36;SPwPF<<8pgT9z z4Q8`ki6N}CpUSPoD*dF5iG?MT!pp_Q73fiKbC5>lnM8sDL!S~IP2r*V(+gN(#&f#5 z$p^1JmO;$AsE`O#NaXT1lQA6ve1t)ZxK5pArtdy~Js>b-W+powGo`PhNd$$2Bf`PP z+)PKI8B-2l+pT1vN!F)wyO}QKrbfr3<=#K8$MJF951vdFUM_47U3d85aB$R*Lu{!8 z8&jEH2bB|j*VU)cN3A{P{oE1+XYSo!VRy0ya7<vkdT6xXQ{RS<zIpF<x&1*M)A3pX ziRw(NNNn4*EhW*hW;#0Fg#O~fJ`oOwH9sQr9L~ReV8(JmrP`rjo0#XZ76<Lpo?7+W z8JFwXVlT-9BH~5jNP*IM_v_dGgEQ0lo=0D5xq+3Yx5XU~T~F7tFej%kNJHVNR$yLT zJ;;22x>VOB-|O>^tBAXiqMRHKZ=KcN_$Ymq#Zr?*AZwUU%OL9$)^p{+X}VB|qac^A z`l=lXwB<$J8sBVyaU_5+lxgv%4=Ak)DK2&GZQs4)<D{Ua=E8&4MP$QjLO?)ru+8sx zhr(c2h?@ZDATB49p&+_9%2u<Mrn*;&%HE2YTzEyn8=?%GttD?7jxzN(#<cebI4X%p zT`np36+ULE#XudxN^dtMAnbI4Y*TbN$fJd-cRYqBs-2e_X#mv(0xJr+r+_)bW;sko z66_0BD<1R?>#BV&Xg7JGDwesqIRjiXl;nAzUrB-h`N<MHE|C-kfr-cat}p1zEf(-s zG!aa91$OZu#-JzxTc1&%tV4KU24s00@mg2qCLjFr<XK0Hrqyf-&kp)lZ3y5^+*7s> zMh=RSheHd0Knof5>($8;4;|mr`c|@stD~GUrr}GSyVk8!XF+dzHag@yxv*1@t9C%b zqA1eIGXj>ifl8$)MAyv+$enc%ekF2wz-+1*k(zUXDN+u+eF(6j`N#4l_P{e))coZM z)tt7NOWXB^y9@iOB)$ydXEh?ig@=1OnX?`*)J)RIy|%iBnx;|gs3HhN)oE~~W`B#Y zP*W>vOh8}(8QN<xSt$3=nFtSHEKE!+y2do+LktvLlvpIVtZo|tmr2hinGMsy(95ZR zqqXkdgj!DL^Ddl~-yk3ABx+z_#V$vrQ{-iHaL!)tFN1JySd|8tdF?xBBLgF(!-bCx zs)>z1?3X?fsrL?pAm7=AxmB&h@U$f^hIM@aMw%~iWx*eGtYI}C)|sA~+MCFNuaTL< zyXwE>Qaz=j5b?eHBd??c<~waWK1&;>dpO|Tbn~)4%?gQ`|9JHcZ!&H$G#KqoOt~4m z`k{Hr?d9<>VaK%zu>4VzF!W^<en2`*m~~DhU**Ircc8O*Sj&hnD+&dwc%xtso7G<N zbjlG9{H<R<MggNMnuY*NtJfYA17kxWAZxOJyy?RD_xw=f<^CkM*Iq-6zEYnp!BG(y z$&*BxS}MOz$0}Yent6GsA<(9Kf)st20t^kWA))l4Gnk8m21_W<ed*3)NI4Yx?yWtl zBonFS1*M!+G`>ir;Qa23P9q!unnI(2HrB!6zP34;ZB*6USpO&(+A_^XG<;l3J@cSu z(;sD&&9aG=y}og0?yFj=s=L}t^&c0$ABv^Gai6%YW%-qiNxBclzk6DrN^T=r%T)@4 zzBrXt*a)s2dz$4!u6q~G8b*h2jsD(;m>6apvWwP7uWQ*2XjCW|7|b$*_nJks##G-( zWp*#SVPOc%p|;VAp=FabW3@snpEPQ|L}C#+zxUd;asrVkj*k6ICtQt`=5sA<R20)= zZG;{_u9K_#rQVPS2RfgQ8<LTAczd{oJY*mYZpn7o$f?1oV<y$J!+p-K^CZKU5zS!C zN>;KY12=&ZwiNoYU`CuSEvg+QQiKTclP<I4!h2t7CK3kmEfRJQV%OXjcEa`5kyh4> zts<^JyQg0fH5@bVL{@6eyKpb|&c;6PTstn)$>No@p1q<d*li!RTJOwye7Re|<#Zu{ zzl&XEW^b{(j@QW9%4ztDbGrBt-=A79^6`G*b&0yObTTKb2eta^S8Ntb-vXfB#3@%C zt$8UZ$jPkNqA@5a9E@5{8A-ivFWs3FNFZ)O6p;PiEFmKD%<XoMu(pNzu&aJyi(&(R zb0vRT)rFgmXYFXE_(r@ob|`C;?f`8VgSP<ID0MJu&GD>CPcO{FtNB9N0+nft#c*lF zkB7kNLH~UwTM-o|?svOiRF){he1(2lLTvvV&^oNfK3Q=#WIU$6mQN7mgo3(FlUig@ z3~Fp6(OpLFLJQ~sr;n;H3uoh7MJzW0CTzx(7iZw+p&bsNeXx9_1A>zY?KD5po2@_a zV-lI%44;VuKP0=6GF6~$4QL{?<xf}J1qSPj-j};}EcN$Sx-Ma|TWWilk{T?oZ+X4D zR$5~c#G+X-FU|UQFTfJ?_(nSG!u#bBx!rUJu6STl9``qY2Z<@dW{hLMz@oZcakNnH z&nq}aeYYc3Z)Rw$PtQfGc*{_Gya>G&ax`H~$KUxmd#?QM^XlBWm9$%dL#Wa3Js2f< zHH+gc3S%RqlF|$K4I^J#zaUZ6py`)ct3Mu_e`p0D9tY<AkY)TbZRJhnYCK(4QDHmA z<1M!nQ?{*}-#t-}mi}TcoAxz=sTffVW`=z0x;A|`HD72rK@)?eZl;gWW?8rmQYBJY zE<5C9aRs8FfAK;U!L8D=nSaXXMZp71Dhj+cY*fHAsjRe<4b|IN&-he+I>&add*FIr z{XReQ9FtaIM@G&?F7AWyv_gTo=2ULMnaJjQDyq`ST@L4CxKlcRZSQN8EI=hx8iRf3 zq-K(=^Yl|pL*vWsml!!>Yo|=>&9Wl*kRMRoCbM5N;>N1=l1Ml&PK$wBV5L!1Wp+gN z<!BK4uzG`Db<Owb!5JMv3$+&8Z`jV<#31<k0H>_gk5>3XvCupkIvgJvw)t#+AZGOF z7X@W{ZNh9_ToG$s<D*5AqO59_#g3=V-R54UY+`?$n(UN_Ur6_L?U)eZmU2Mi4d3=> z@+WmOvNYvlb!2a!)|E$96$eRGwNC?|7;w6(jN1OBD}9)HXt4Kd&hY-mvi*<{+e;*f zRs3PBTNBzdlh8ADbbwook5_m5fG+f$9+jC@a*koNy^-0d6U9cFOlH(SG+|jcIxt%V zf#5~?YYu;9PK$l`1P7Kc`(qVq3O2=EnrIW~l0>>lY7MJ+lKl)s{%XB_<s>xk_Wq30 z+Y!TL%kwZhvm^TBe&vwOLt0KySXZwjHR8Z_7}Xp}fyboMVC00695Xm|I^pBi9i$Iq z!1f$fBjUDgqR0vHBw~8INDPN&C!l8YK9=5SXBS+?UWDh+OwT}lRF-W(bF;btC9Kz< zxr`^_!0<8D7;Y1_i)=v$;usMTk)O0b$Qo^rL_7sZTs069f5Ym{qRbTkx@EN8eSvK* zyZwCE+^=a}>wWF~#?E3J^zB<uUC@sIFlu3Mp4JyJPRZ~sx^Eg>4%<z#b6bWxo0+4E z->EF2nWXWBO;^3OTQNw|O39*{=smL)ax%mM8bp6Yvc)M4G-^@58xCPaXbi#O?nch2 zSPoHcZqFp;ZsZgRsEcp9clUSDhnrOe2FFS~OZW9U)Vz_jo?<Nyq{;fg#v)=9fr^h% z@A3WRdwQW?Pn6g}+xYR?UqI$Qwj4G8wvR-68!D1b>mLq;^A0FfNlGwD;+~$~XO;YR zzSSN56=^={1PwSje%rnVQQ~nHviVg^x{@Wvy0l)UqWUU>?y>>&I=Z=&vr}7wV%SiM z&~98MpNvMFt0hE<-iG&>S<Ucog-|;n>f~3@$<NdkN-1o8gNYM)f045?tZ{!H9hd6S z+(n@*?2a18B3nNo*c>hPwj=ODG(dMl;K;{DnwMZp0g~lMWfuapiV)I@=Q+k$a;wK5 zPgMg3GC>;w{0;3*8F87BU)+#u`Jd_OJNzgD8XN0>V08-1?Q|LXP$h3h>A$3J$^7sm zFc4<AzyJHvU6XJtDKcERVrOtrSbu2>eLAmQi*H1{t)cRqhyhzZeNxb5c3jjGakb5Y zR4TW$=a2%%kNVP;D*f%o^y$j{P$(w*&pP(T`=lD`yg#u)YQG*FtrrXrj5<rPkgRY5 zes9xTL~{#z#JC7p72H9*bylQ|ZfZ?(5)!psAiLP0+m>$fZkZgs@UDhnEt#!roOO2S zzXsVX?M42&jrGQ8365J60;Iqr*R2TkfC?$#cEXy_06X;(Sxnuv!CZ}@6H-L<;>>RO z>D3bLATk`qLnCZ(FGNb%dTBvHxva0eKU^C#5~k@Q`gqUk+k7hBgaX}3Z)Fq+B~I;T z_1aDzQURBA0zY(D1Dk!=8|O8>{ECC0aHHZGk%o=amnEx({CUC5a>P?<wCB6J-C?H? zP=pBI&#@k;LPrNDgm`%&;S^yOF;z;JQ9@M=3)<l;ZKqskkH^Ny1m==J3TMBI>>n8P zv+t3y#hTUhVHsQ^IC>&nhU3_h4{LZnL84k+WF0|zCMLw)foLzUIJP)xAUq*$ASj;o zB%qlg@Ns|2jh<EiGc{GAiT!UK{+}V<))&7@pzI17NSeOnArX1qbcCXbrgLL}4dsVf zx<98PW^5gzSEjAIOhorjv>yZ+?W-X}+)HcRK1=nd9~B^(hcXSl_y?y-z9hxQX4?KL zTF+Fv5Z=dCIkJTOEd8$3<yE=|579W}Wk$#~Db<%Bw(<UX!HJZeiO!fpRP#RWoJxOe z&-mZBt0GnMARK+e1NFr`tS7U59!iuRq-1II(__E1yCA6<(mYEI$=I^9Lj`s?1)b$D z#rN~UamjDhAwzIK2qSn8lrgHy8!1np6tSvKResG;o?aB9diyy?-M<oBkDyS(&`{aQ zw?8YmH>;NMO!LfuPw6Wz&27Y5GJiznmlcvK7l)|oxMCs3&+grlNQFdK*7orUok44Q zm9fxBrr6j9jq8n{&vy6sjB<Gr+J0F1i$Vo_Yr21>`n7YCJ}6Th9>cd3`Vj?bpufzk zSXd@wR8Ei6rxnOeXTN<$*10-&Lgv2R7wFkvXi24cV#H-JgMo+4J+U)txvIT}f<o&- zP*LqvuqdE?uy8;_u60`RB=8__lIB1z!Ga?X^Clr9gP(93<IU4lj>8!hjfdNU^!HQy zfelnVimacWLypFgQGet-p1%K)mq(c_^h(mWEAElXjn)vI){hX4glH)BJuR*R4$*`r zwpe?q_S1a_hfk9H(oYv?$zU;Pqc_|(b?KefTbva6UXXAuzUwM#)julN5d05CPLQWw z(GhMxAlnvcP3WOh4JlSwVE?9<)vasaBJ|65YU`EtH0!l9+V;&O<1{!(N-W?aP=H|` z{MaL{m*R^9TT!=foPp%<nmqr#mocSiC!ZtZPw}nMAQC$;v-*kZxTm;g*Y*My>+Swq z1dg9!{n;Of=+uREvP*5Ijz!Ran@zl-l0}z!iYUt=|B~$7zaG$!o4;tdcW{u^asN9N zXTMa{f{xPbi)^1@j{9Qs$#0@Bte$6&8oO2*WWq)C+jtep9@ZgMnal=_b$$tTw&W_7 z(Yx`ZB)>Rmr6oQqcYc76n=Zzg&=y<@s60y^Sym8(t~>zMtu7p*Tjh^j#*eQG&B^u& zBW<ZABt28CtYeI0dwy;gz_nakzC7%n{YnQBVEAphAPV}N1Dlc}oB%`>;+gzXvLC|U z)6K++PyY1*(J%|;B~l|E8`&t-=y&DP<rnGbQ1pWzgos#iF&3}rpTGfTIN_YZ9$Ot< zx=l#5mhs$#W0%G+kZy>Sck{J6je1=I^{oEtclmf8Y^&ikc+AH3pVTvaxA$%gP5O6^ zAob;=Li~`LFfiYGu21@6WdqiBv*U(iMuWU?o^P8ze>&mrBEuS{ej#Kt6)okm^I@uU zV%DdZL}k;xc)5m*fv?6>&f2l<r>}i+DzfV!9nmwotIUpraSSB4py7XKk4~_hT9=Tv z6c0`<y{1@M*9!&3UmYK<rlMxk>yz=m34!mJn0lv$G*huv7p1B5p#!EesT`Dw;)v8W z{e|QMUjvgR3{9DN><@*ej0Ttl+NfI5tsg|{Ot9LrU*&RPqppp#&k`e*KT;CX418_z zGZT%&G~+)|9-{U03kmfLhfZl*(uL9yhNIuMm~X%%r^)xi{Ap!a=;h;c>mv^xpyb51 zGhsaJ!fJy>g~;8j`#WdAk`^P&%FK*&k=Z(9z5Z7h8Xne@DlOII51T1cDO7t=6W@I2 z{<3)%8z<qr_8f*eF0Zv{?0iiKB}X+2brxSXOk2@>&3pR0hmozF@B6MCahFol^2G5Z zXKy(%<RLCuiRr~OMIFv2)yi7w5QS1{-o5*pjY&1FNwm`PrL|!JtTEX&sYN^;gyt}m z3k;p7I<dpg8Oa$_pAXqs7*JKXdVTNthu4d1N;F{1s4Dwe<zM%g6z^ZZi;O|`sNUq* z?o&?#*8W=O8zR=r5~}^?@4t_WXZ+Q@IiL?e;?*7sh6>96@xN1`j8MTrTYASl{pURX zb9P{x^4yNkd<4|hv8YZ)o4%X%6Wqu{O5%j4X5FFUD#yjk4H0Av9iD@wtOGY9FW&-e zSMe$~8)ZoNHY=}Ee`=4bK^4@elKOOAlfaiQ{qXt>upj*%0w2KiGN>=5|4_h)JTKex zzAGZZtxb}p-j)J-^-`nR^1QP=#OhiGm(BL3pC#S>hV1Mstv-mKn)*%^VscwVM|)#| zfgrKF9hs=HRv3q<H|)Bx<u9R}Ss-zlLqC!qHeDkHzgS_809tolAM}5tIE@{-R$I6n zx05@uVPzPps!n<s_WPw{KES>A#o1Y`)d{353X#d~?Z+QiGxV#sYAtu3BihAhK)9~@ zQqpAhQUo=hbS~O1E{D_f5Jokbem-OSVt0B^Jr2I!OuJl3`GaOvcob@i)U4%H1<w80 z{xoXnueZVP>&_OkAa1X&!I?70(2$)96Unkt14~EIYO~Nvrge9g9h}lJPP}fl&T|RN zBys2zVGCc1G)A;szpQ)}l#y80s_6ii>fX#S-{wVmT<DJZyTW3j9Jw1JmVcv_?yRKY zN8zvL@-M*jz0m;`-W_fpstm`hw7ZJT_e3a#@EZQItkluebu5XQR%$}C)|Bh9(*oP* zmdazGqo)Y*FxHOuI#aJv3(rO>!WOY}sPM4DsO9kuenCP435s!Ft3{w=-Wht_C1RtP z@o|q%heCRCJlnxHxW*a3@(wTUiZ}0x@noqOH>zOX5*&Jsy42;@e81ALl2%fI0VN!G z-g{i!Am@!}i%Cd`mQ&AOiXs!$t;S<G*PYp!+KWa?(Hn&}m-qJ<mwwCtSRbb(wL14% zOm~i}Y12jcV0g*EO@n$Z*n1DlfS0DBl=d4l%l5!*gPjhLh+dC%bZUXka3Qxf_euiK z#Cw-^>cb=o)rXM;oB_HaOez((Ulw#Hz5JXuHn6VpJfa+^6w(`=POiGB!0A|CRTZfP ze|7$Rq}9Bn5-|O2B3I{%@p(EtlPQWRSVg0-t}%9UvapiG#}SFT%6zSzPh`mM-F@@m zR8&H2SRS!PY@u~YJ(1UCSI<c=bNY`$MgRWld~iZ%u@Nv+ERQStF7kPsfDrY)8;2&L z!3!5l6Ju(xjeM=%G(nrTpWY!<I<J&o#8`L=c(>P9E9OR~MAw*i?T_%Ld?3odrx}e! znP_VfnDYM}^qL&`klDI_vZSpik-6DKs_<C92^E#wFtowJ@L&y+g+<md-anZ148lK~ zk*_~5zsO1q8X2{QEuoQE)L_jdjiS4If4Xvedusz<G_dfyb?`ejac+T4{Hfe+?NIX8 z(*4;C0tC|vl)F}+t$+6d;^Nc{@#F&gl|>#0I?1!SZB8##zX}jC&3He!wi~#zk(_oG zRAvPt7xwM=Ke}8U^7**KZR$YWzfNds$ICpMNF9NsmjXoT@@ef8N=SU71;=A9r_=Ge zsE^>32D|C9wxYID_}X(2?5&hJ*`5!3i#_i&VCA+GQDt6q?<b>1IiW?<r`tI>DAQx3 zWQH$9F>p3;h8Jolkwv_sIA*h4Dz#E73z%>cOndj!$;fDn+0mh}I@C83_lzd^FBdWo zsdIwKD1rQWCgai|`xi`M@}le6n<f|p^?&t+uSV<dX-R~M|9S70pS9J6E(SxLF(Tss za3Q(9MlD32{Vtg=(f@jpaQRRFvKjt=e&I*CvwEZDM|E{vRs=*ufJJoYvXA_9+4&Ke zr`ed8j%LSHMp51d8RWGxNQsIXclGl@Ast$2wYK~qISYn~@I7F&1jsS{&fgg<d|UD+ zvn3j}-C=~}+=#>Jt&vfQbB!u8YGPnezpnE=9G7EpdRiIN`7ogsBn>CCmXvF0YBt%= zmGSZ}^DZC#bUU9e@r6dFe!Ea+Ma0IY;{OXM-s~?f<Mt)u>7Jz4M#I=vdItvX9wL+! zbkg*I0URog1JCb?tLhIx?X{6G$dX2}Gn>!mNEj<9pyf0c<eN6TUe(#{NSmpvukbb- zt}&FCLnGlQUCmRkTguy>r7gMTNqdMdN{NZF+nh}%jFDk|&_3Izro+R=?#-)z`X#{E zYI!SPzz@EvNlXiYkF4gi_DAy$=9}Bw57myTGJ)Zg5YoYcq?RB|8cV0Eo={3dsHgK? z;LZ*fWGa`Aws!at-=k(+N(#+n*oty-%H<XQmJlHbtzTZO{!%NFN4%rA#*N`a7l6-U zE6EGFzd4v#3D63$$oKonCl{BOT}LsLG9Mld`^IwyFrs~ao$+}J%0fWGG1H>U$mxy& zfC5NaMkfWAL;9a+d+VsE!}f1bMd?zcOF(Ln?v_TnkuK?y?(PN^k?xl6?vU>8X6TTP zz47@yyMOGSv+p^(@4s`H;e2QAxUTC{Agodc>xEtrf1QwvV0JZ#-B7$FYD!ncR0xiY zTxv8d%r<O_mW%_!3Q{llzN0<sX30;VFrDu2W!)b(rvdkWjqZn{i3wG~^I`=#xwPot zN)WBOQ#7Baz4Ow{AZvH2DRH3owEvr7g>j49+Eomf1GJIVJn+L12;u|I|Dlo+Ny$mN z3GLA?*L}*!KY<zwh^?d(oP$SouWLQH-!$M)KazWe4E+9p97J?@sQd-w*a2LvGdDN8 zqhJ+q*E<3)PD57I*{v2>3Jf-OR?@Pw$&u(kK<e$OCpwxKyLAOHqE`kJYrbNFurvpo zoAbkfmI7IMD%{xJ)`T~hm=Of^^&ERps7kU6{Ok9576fm0ms^ff3#S@6?;UI|fr{j+ z#dMrv?GVHS7!5g}<-Xzv14&Zp%kGF1)fk_w_aVZ@Qv>YEIoJK)HcMJA3M`z)vJfH& z2wzG6x;d3pQTe%cu|cgk{rh^a!Mf#VROy%966?l?ggd|QdPZiUcW_Buw0N)le23IN zfBx7O=5V^!6@9_CRNkANoeiFolauw0Q^T!;M!Eg9|A_$zGJHCPkRxbi5nGuvC@1Hu zJ>aUB-5!NFLP}o~d(~J!3LGbb91zRnk=51J*MI&{&(K03>SxpS2iy>35)2BNr8;w` z%M_1C^%^3sKcj!7e{Pi-^cW8%04}x8JsfgKL=&0PFN_zZv|$V;y<dNcf>a78=(#D? z`z&|%)na#2kS=lvokj{Q`$XS(-o6p{P9Od19_@_pajmfV9@g{nKFV_5;d7O1gq#5? z0nbFC>|;bCTMLIFG>F(El!TMvSSn0KTfa|t_H=pcu@b!|@K(VowC|gIGgheKSQd5^ z0cXA0BovjfL6A%(=DOuUo!$1lcG2yknalDfU`2Ox;^yxGk|{a!!Tw^6*NXSU8rzS( zlXXh%_?tKW(``aQ0eF7>e|J_Xc_^g9BOL7QH-&T^L&HOThh<18K1eYeHKY7Rpj@xB z+wN+u5ZKoC-0f1#ebKcTMna;kZP|6OvJ#EPfAdm=-LoADL_6#2iY=o8b-`<}nWN`U z^ZNaCu}@A;B7=i}pmmNc<v8q>wA>KP_uNILq9D5JjS2q>SgF1>eL!QP={nU>wU}*O zs`vDW9~OD(cMs)PMT`yo0;MS-<g3)#%wF~|u8xnV{?gW-x}~T3Q(Q&mB3#Yd>+ygc z{1#LnKJ4>@9K`sCZWe;4@R>-<M7^L^a`Z^e{7Orz=!Arep@yRpwR^EW71}cHy`otp zEV=~dTUsqb!WsU0hXdc%`&+aR+KmkFHxw{)8=1E)H^0eO;}G(D+Rl#YBqb-8-tSq{ z{G`3L93AG*AK<aV4K-U{(u%-uXp?8vpZJVqhZHceat&R`Uk72Q3C>EtPA(4kOD{^4 z*U}YpVVdTv{E*P5%Kd^OC%)!mN$JZ(5L8t?(l<>1Rx>v<gIEnapP^g}LA^WMsO7Aw z%6Q!_E$2#A9(MYcRhzEb-v@}nXrZRxO+)$7BO#ZAHT>|gz#~mH?r`z`C*3WkAP|o= zq@|6trKeLVTQAjL-#abC$4U@N;Nc<77t_%lf66$22?zyQDm(?72otP@iQm7I5x+?7 zT_qFK(`oyNBo<QdQvlQ}5bVGxd~Wpx95#FS${63uf}bO$3_?OeRFoD%xKc?Bs9RVk z(WyGBqkiLgF=RX;ePIqtFT!M!xkN|wj?vbJ+uGV5uMm(|JA%-<TIrRFpF`+d&>nRs zbKzNO;#0AQN`PW#r0(o%O+e6cWQ&`s)|Q@{PY*^Pf=~2^(?f{M&E*m0oVu?ceR~50 zqa+BG@Nls~-@zr7uSqtEBZMUY@9T9RrqgA2d*;dQkyi%#3Y~w>LWQ|ogQIr25QBm? zBFe#ZNtF9t%T#eHyH{H|d6+Pz(d`9asSJ>}rf_1sBzdJ}^2G$l{e%=zTJxH2Z1Kp) z1v&dI@uMzlN?~GuSG3&IX`D|Rwc1tL;B-`9U*8+l$akP@ZoWsWQT=edewQPi7*4>b znRHGwk|qEXi!jAlOlI|2O-(R!V;dVj0r=Ti>siswSJl+WN_&*ney$!9sf>J!9XIj5 zt-%QcT}Sf>IXe5vna1FFMSx5+@&TX#PWubICUTDnNebV;U0*a1>wY&MZG5`DZS>{! zV(JHSbF%-G<a}$I%X#MC3rFlpU`zehDEHz1Ce){NoPf)nWzBH|h)O|aED(fBjLY}? zMiq&S)M~oWn3_1FaqCkdQ;^}NVLAHM+{Uu6X8jjNB04(g=HjZ1W>T)P;%xe6OOf~N zC%)4Fq&Ci3P7KQM<!X=I&zeR#IkXy;-m^#hv+qu-8bG9FyB%B=<ZSl2`5xSurmQR) zoq^4K-xw1kiNI48X4an>N{OQdf^aX^!oF|7FxCV4jFRSXgTs8J(~^gEyT1*%=>h$5 zIWyle9vs<W`0?@auCDdR?O9nl;J#m`1BpwdRwkzTrAcjZloeC(n1_v7fhhQhQ6IIK znM10Dt6jM;E(&fh%bxoMB_}6?h##<Ti#5xBQ{?8+;Le7eoH)gO&}w#_JSvq$h}H3` zO+TkdK*q;6zvfmp7WbRj0Z|qyylydbTZ4ODt<1(lY-biXH+v-^4bg8w?sid#v!EG( zlM1;|!(*a7s9f;P%^BbG-fLGFNn>URkVFu(W2t0&dJxaV>pBX$cwRkdUYo$)z=mPd z_6`o>b2#H{<XmaN9Q7H>>gmM+&V0b4455eW!%1#&<RREGUnmRC|8y^fR9KtPgLOty zm3?8wT?>7e7#M-W`*q~mk>kMzTGR1bf6GI4MpjmP@pz6jjgSz`r)=sB)9)0cql}X| zjb@Vx`}>IeD+w)A5jcFvLKgFEMQ65Whbo8xReNl``mVL?ks%?<9E9aCL)7BW)Aa{r z9{<+FGTDVmSS?3tUY)Hq*g}MTz}JwKoeTFe2@66?rQ?46w_p-Yd(RKqHx@pJ2_HW( zAt|Hy%a>r-H>z=nlG^$TV`G~wh|t}sDoH)Pm>u*+J4#TJ!9evdj;5^#b<9bszffe{ z!=a%Nv6KqA5uaG!T`~4VUQc)0O%Kh}P_R`)ITZ4>gHR7tOCAbqYjLL1zCX_e&P*Hg z>3+5YpD-vtcK^W|Dp7BOB|+4Io?1-3_5A#~02U4JnQ<!4OnTF0WO9Rgr3oD*YbcpJ z&|lN{wdA5k5R<;XJ^>-&zr(G1LX>CFWt+DlP)3?Z!}Da4y(17c`Le?a@wKNm$K%c4 z#G?6|a3b#2fIsverzb&c3bADdVjWXVMhn6wcn%@#XXgZ5_Fsb{wOlU=pRtdFz}J92 z!`-7n5968OC-v7*Z?DN{V;v4|WYOvA>2sJM!I)kJ1_p*JkFF9OuiM4o7=yX%EB#L8 zU6voOaWPq~AAC20mQfU7b0Q5Tv1L6R@NAdrB%R#2xn~m}K}dUxJ+;!sgL>7|(#0Jb zlBrluVKwPJUM1^peCQ6ZF&^v%A=7b;3%ePq+a2UV+#be<xAgffgM6{(i8p*K#~+6Y z`P_vcBI+EqwH@}RcwGl{@=$r+!B>IC;*TJg!-bGX^u0hh>DQBCq_nam%>}K6gn>uX zRls^Z*jI8kB?(zkzB30Qw6@v&FBh(C3?{Vji0WxIYPys?B?o$X@CC=WSDENfDpE%> z1sz_(ru^NTQ~tNn!={oO{#;b6v|~KWp}ulTU^!uMyMp|byMC29_DvynJ&)(uZZV=| z?{MieX-w}6Bt%4DdbKg#6Aak=i?dy7*A=7FCCjCjx-?!64pMIGgXCde#W$>sn)fQs zwIF@DoL)*LtX@&+XE+af9B5?LkentJ)YTE)QrgQaDEqK=JYh!9<_Z-HBM^FMI;}EA zBmD86-KLh6ok%KDAju;CXw-?~%atK2ycT*74yKI|NpTn7wOzGUP!In{)$m4q(EB|e zx96CTM}miEliAAR-fY8TjL>aL9w<Ib94?udgzYFm`>25QF6F)Tpl8p-jQACrfm%t* zohqz&)yHLkCxY%x`D(LP41}0h0~Yq$<zOlSh)V}qz_IMcZ@~V>i%I@2*8i^=7MJ$f z++}p%{!fZy3(QlC{3VHw{lBw-|HpQjCy*FcMN&TW@rKq-KkTK#C%yeY%JaoJaZ~T+ zhM<{Gbj6MQ<M*_(3N$S?WC1-wrhVD#K3v)`iSeT<qEA&=Zg8N&dv5psVtlS{K@}N+ zn9jbM+>+evN)}d&y%Q;H%2h{a36&VV#OF=(>WFHqK5o7k6-<42s5p!x>8JC{+1I1# zK9ts9ettTa`n~Ax!E5n4DGrAK-Ig^oPtc6@?8MwC9f}l^y{j5|#EIc1`>mNvX*f?{ z&&M-T6uyzDc3V?FCQ{hUWW2f}E;su<4UcXQW|%gN`i#Vw-(^a;;{`rqS@znSY_%AY zhx8M*>n@QuVQjqIHB~<f8W-CqzCL;vQeSgS4pjKbYH$nv3SiSN$Kz`4P@?2t>unox z^%T;GM}SDA75LJI^S7KyS%net-K2~8(l#J_<iVej-q$RY?oCUfhmO-9E)vD5y!-41 zO7x6$rKe@w+wyYofJ3B?YsrtI7Iy)Ouac6ZSzgDO%#_g75gb0l(ehd!h;odfQ-;2Z zM#tKZKZ3S5yR<oQ4WaA>#zLkK$t!7vWsWLVuGHxyqf>ksH|jfY$#0IhJc_kb>Dc-t z1bQ;!t+%rX<nwtN1=V77S9x1|IuyRWaW{F4eT&WSrpQjbJmdGUE!9LmT`a*H<oeE5 z-uIMzphA$IBEbpDKOy=Jn;26|Dd$E;a=ZjqbjR&7)dJ4P*<tSl3G2RLChvo=GI?5L zdH6Bew(TM?m14ji+mi@mLX?pFdzg(SPAgqjq&Phw7fjzrQvqemi~9s&a%Y^%Pfsj+ z>bIl4;1a?p^F_$a4U&xXE$Koeh9M4Y-^A01@L28g6xe?lksBgTS*c)-^_J>sv;<=6 z#Up&$wZVNTEK%vC8lbE0qr$Q<Gck%u(7@|lgr6gZQ1=f}f5TFRyc3#6)gGOXI;3{k z;a>Rj_L`bj&IUmehGyND?Dis?gTt-b-l2v?$s^!yptkad|9V3vjbrH9DKu*%uHdb# zV1z`PZ~5KKcd=8FUUij(obZ7?cqhBV#fTF$ahA)&8LG^QiMEeo(c;p-_xGUiTsapG z<hw40*_t!5;JNP1oq7Dqh4oFWJ}0I&j>O=AJPZDjLAiD2us1M~{s_$;H=H}!I$V{^ zpB&SqqVaG(71a5QEx)b~IT@9g$3|PKh0fZU(6E;GjC9w?M*ZA+<o}Fw`{<XQ?K@zk z-0_Br7BW^dB?%uPUTXflBs;P!zLJWZuDrFcgMyxof>EQVbLJyev68`yry<xwgvmp- zmb{U@8Q+(Wj?gA11Elc;)KjjUDI-C%zNS#8qm}A2eu5Om0s~#c{5Yb-Z<I=((~DsP zMT`sGdVUK^z1_s_zmN>GE$>6N+=I4dVG<^)Q5F0eODcS>Cz8S|RvD{_94ww+I+Ir~ zEPoSmtkgDEmR+*^(YmlPOKOt-C7${W{+2K$<`0zx%YnMq-ca_H_ixfUC`*2~d&GZ} ze`gY0S*#J1qScta`p^~<fce0uI9~oEIGn3kCUR@G?DaLQil~zGzwMHsUVCtkX#Mgx zZ=4RK>iEzi_l7dyZ0#;eGkA!4sK1w1dOq32WPhwq0~@Y{4p+d(&1q8rX7X%*`gi-K z@qBsHc6>B%qR?qM(tA`sA(Y8YF|$Kml?|_rODdTBvSgiQM-&vxIWFPkg(~iuk@oSy zKj)ggt29PSg5r5Aj3a~XN+ydGQ_GJ@UFbSA%5fv(A^c5jX`h$nNLee*_6oP?><4%} zG!~GMXK)fy<LGBxZ>xML2gfoE7t=cCtM?K={}TV}ul|nlY=42v>S*>^178y!P9jp> zXds&k#n!ia!O!x9ia5PYPvrzyMWe?-J{27``w@Q$M#ejYok`zjYoegaUNw-2n{BV| z8J)aGVFCx&G+p=B-5@mEU~8$nN$+6)qwF>vct84S=k?`1L+M1{_;jD*RnRD-gVpNx z2OhSRA+4v{ZzJ`i(0{H55EAT_y7`}rVHxHBhuLXsW@v84+8O})?qYw&F1C2-yh9rW z(%G12mUrKwyNKY&gm<CKYjTFr(+>~Qc=L^nO?{Jah<JYkL@+O0;QQcw%LP?_{=~$L zn_y%anVNd@?|H%%B~O$T6c9I+dU`*q#zpc^ew2U;NUJ0yNk~Wlb0jDZZh0;E%V^`| zx$sRnnE;V4hr#ey3e5Hn4toi^03}tmQsjTSw1ye*xaWkelWhovd`#dGY1!#pl4v^q zy%jg2>-$a-hIkP$1MTgnLI3xk2QuQFArQKl9q}FK0#?`h`ZpntHlITN9b(29gPn?M zYVp-rI=F7{fwzx@WdEzDACM=}1d`I{@cxYt&kL%LCjUA+l3|Jj&J~INz7>Zzy=2}m zK4ky1iA_;s!H~T?THcOhAb$P!9e<b1)B6Eioc(DF|F6ukc|1<u;^Tv8nCaf$-q}BY zI<pdp@qr!X_-M=o7}!z-9d>rbzI{B<SW;J4mywC+JOCvm_)|bl$)TXIvMTQNb|09p zAp;&61GEELNy&fz{{8n9(GvetedGm}At8n#pJ%tPlW}l-nM`Q0cd!ScyiNy8<E>Lu z?d^hE8~E&257lc<c?4o&K?wwN6;3+N!ov1a;aAvrc#iisC_2lig4ts?mR)@fCr%N2 zILnQgo;xG2-Q2j(BvzGGRH|M2tC<CiL1e7;A|n6SWAyXyU~GAOHIj#usekz4&af-t zuSV1j98gcxH`L{Y)vXOX^twx!-5eFN+aK<bAuU&%^AG*KFrz(`Nxb$Hx`q8)^r6gy zdLJ4{`{b?4bANya_xFhWY5iwOl-r%A<ZL4Nn)VDOV{}JYE;Zsh(z7?0+l+6iF)u5r zKtPKq7D?duhKapI<4g#nJL<dT_VzZtdgGV#yqLAalqR=DO)WU&9ZDt7Mzj0C2yUmt zl>3Vh`zhRBfNx=Np-}-=UfG`4U8j!u^kDq`h2phH%kjKC|A)_9`r?mHM$(c}GHTb` zuKli9gzj^Yp2oNs7j}}}%|Gjc^g4<h6B8W=Gbf5`j(3ZlNec@Avrlw$4c=|2<3M=Y zLivocXJK*1!zmR7*5nXMZxlPbvoLI-9|ni~Ul|ywZJ_=1K({z`7tI6ga;+!JMKVPr z*A7e5g<LQ8>8v{9rYlXq?<ZNLkHx`JPZgPC%X9h+C36iWG2WZrW1W_*=W^fPobS#S z$q<sMZi_1F5O}RksKqim9dR#=msCtGd$}B|2!9y~KnE)G#yemC&M*F&4K_&XP-s=6 zzJKui=wSr$uW~D~t`FJ|aKANQ$Bh2FktU8=x)j~r8;!?vPD!fSrsPK%`xt>kDD!65 zpTIy^Ji>1PdVBlYv%$@YUo9AP=t?)OHn8)P+0i4Yd<Ov%1~?W<z!{`HwbqdkSs}4l zt3kW!gPZNg&ekG|Sg2N$CsGC+2_VoCH=gC#4m392;n$G5&sD{sg@;6F)S3A;6jlgl z9Be_~=X^a7y&4hl_z!1P*ETF7%*je=b>{;eHK+YXCqN$6tBy4*&z(GBp433{J>zd> zf#ndamrj_aN{y9_W3{c620p$+h?0$X_bjt9xBc<xsC*?6u(sW-iEVjo+`(34W*$Y4 zjfpWeGIBj$S=Crw1rv?Z@^arl(24x<_VH)ms9MrmD`ESKE(p0`_kP?BqjoP!|Ek%U zu32_}RpX}>)m_ZqVJ-AVq-Vi&AG+`#7T-jyUsJNlZ(t&a&+eM%qE!J%vK4l=;0XM8 zbL6d=hEj%aGMx1W?FcU4EuNh3fN*tfWCY8_oT^ij)C<1m0|2O;$cRf_0iXrgEeD7M z)YZ9&bcul0;pE(6Zn0z@={p6`*>T*O28RIkJ5}Pm{OGiGAWb7Om8`tY$@PllG3fD_ zD#|@|s@e)tM5ctup}V73-GlH{ly2M_S+fJ<_kC4~HKZBuvO3{QttX3qsLAOD!Uh^< z-|gyy?I+ACtH=|dkkC3tM*J-{R;#8s{`fPe*Ms2wjSA#|9Tnvuk?rr!Ncw#i!a5n~ z^ljF2@<U8NnTFKV)O?6c)`H>XHMO<<b{xfAsv~PcxZyrg>Jy1_fc`BeKD&|VF4*hi z^bq03pv>+rt|CPQF1J}PI6At}jVXJ;QZ=B2Np!B&t1+y|IbK_g40p7?`^aNzesY=e z<XDGy!V)AUD?5x|V+CyNLK=<<v|2nn78kXge+w@}R+{V55Pyq_DYKg<nsxB;@p&Gu z9T*tM#x{kuwY9rz3I>6iZ9GQ$`VbxzKzerKd3P+ad1F<3{IlpY1}-KU@pGeGKw;s% z=jw+Ogs@gxuRs^z+xG_QbkoODHV(JkZw5GrDKNXt%@v7J$5$ld7B!Rpox~>XVEt)Z z&d;!$d|eavmb*@v-)&`fRcK->(g+a)lU#iCuM*B*09-Wi@E|XJRYYnfwm<LnF(>uz zUKViPIk~u2MvnD_qKN*=N*0dDj@W@wxhYsu1*e7Lk35zdtf_yyCxFVu{eC^8X8E?! zr|56AkH-dC5|6`Fp|oUvN=o1O6RvN%XZ3@&dJ(@t;%`>QE6Kb&PoLx>)<%bayPHMe zKX`s2UUzd`yrtCz2R}B#b-CMcbNE2`d8IuPQdpURC@wz#Rqs{9k;h2AVLzjRsGi%> z-7D(+e8g=T9R6Y#=3xkG$o!Gl)k*K`4)q$d?5~R+w--8fu7epVT}|h1BccYPQNEsU zqLzTUSZ|EMrl5<OsoL4rAeR#~FZYr|q<bCGU0!}F+j4Vq&uNW^%bR@p{OPBC#Ir%5 zmQ~{kc?&F2Ffsco`}svpO-&UPzJarTzv9(tR#uk!=U<ZV->ll4)rOupx5iIYp38T@ z{;OH8#k`$wRPPu{eSG*H{Jp^7hY)Db9K=$878Y;Sa&X>Mn$tdAEgQreIwUFL2c<O? znE&dBVZr}b=r?UvjH#-!vXh?fo4VhN3D<>|<tO+!+6x(A%8|kfDxxRn;%UzuQd(;= z|MQt?@y_4GD<%8;UY^3IJtO~zGWRlv1+IM(vu(L+{z&9=dV2dNIrsXz@4tfUEen2E zc71*J<|f$jFY+<F$jL!~2bJj4#F=E6{$jG@zq0@eyu^=C9K4M!O!zF7v>i}a!T<XN zqtVY`mzYm7G7bD0#10PJ*x16w$30bk$_Cwt&tVI*2KU{0wkvM@Y}fhnB=XydrU45N z>N|(KQmm(f)IzbpjDWOtVuFLdBrPioxtfX)VFdPti#RZQP*ZcEepqbL(N@u(p7_P~ z1n+Nfrd<T0Thh|5a|MdX$!2eYf=&+M^5{&Y@ew9pDW96Wp6d-SjK_Z-;8he<q`=uG zyd?79Sb`rWZsqC0{QvK4007+YKHT3<Tlx0~&9ImL8R&B~F^Nk|jEjjkv^Gvm`c_a_ zXs$i|8=3_YJnZe?V{JJYk{B8q0^=2;!{UUL&q9ZWUw;1hF;P?gHU$TGr`2A%Vr{jr zzk_T=7CCr$c;p{jlhg5~7ss0dWTM^c7hv}TI=CXnde7AkG1BAAc)nggxqtLF>>wYV zoVMp<!*z?re4X`e@%@^Pg{J$;EE31t*SJjvm(MK-xIMWz-v6G<icCf3AtrzjD<~;7 z+8w2<Cw*o`@>G*o(hNu0fbN_qwtok9?$DxOae#muE&lv5!Lq6|aItuMvJmjd&;v6B z$i5FM&Kv6<=S*WqhIbb|T<I!z2C`yPw#4K$;I~1RPo!t|U~!tFJZd3-V7;^ekr{Fh zjC#9ugt*^RA0Jcgd=4Oh8SNg7EF|Q2xh)lUU}R*px&Vs&SnBPqO)=3P{XQBcg#9ly z?bbRCo=8TNj9F==$Bs%;Ha4Fy<CUIWyk~5-9oSFO^j|;*c8dd-(Wws}^|v?9f0j*M zT?5?}#KCwBenVh0;N59-Lc9FuIbFf%N931G=$M2W>gtd@IOA35q$kgd3qei!haN;_ zBaH_Wz(kzE+k`1Y+LN5*{7qG#_v_C05nIc}g>x+{C;O3>-{l(dI{(Ec%cKwYn;%wL zq4P@3(e=5GTbjrCB{D=jX*GA5s(F}#C`>u0E~`_;nJ>f^nqBX)UWVcX^UzGdT_+a& z8JAZZJfxr?QJb~W(|hfYJ+~6hNleV;nh`36h^A58x9~==*DhqEX!htA-t<Iil&9Tx ziXVtcot*MKZt9WLQ)RbaK3JdRqUPL`S<tdBnNlrY6gGzLZ#W;eXLt2Ke)s@cXx{UV ziAnc>(LkPDzN@9;y<Y;XNb3AuP#+Z!MSKYnN|W-s&3x|RM!?~IHxh%fO&>@)*aR0@ zd1-~jpZo!@ersc5;(M;|Vdt`l5tnn#Vyy!^-Qvt7u2|dyh>x8^<a^6_n&0|v1_l7F zgM))B%Hd(MJW%53*yIY+`9nHFkLcgF6q`qv$!INo{lm+(AO-x0Ev{riF1XHoIh}Q{ zdTV>z8kj?Vzg)7lFsZQ`cih0eM3p`sr*Bzohy%*I6QG=u=EWlmD)j*X2+ZtEqoorD z8au{1*Xgw2PgG*=kp6=?J8@uvm7mPvfR%uj`!X2~p}`%+FwCUkf{4p`gTp-&zk1(d zyns`*){sWUX>Z|q5CduPa(Sl6S<dpX4$xt8bhkIbMcp`8fkNvb>E67fnwI-Qm#Pb; z{RB}q&$fDVT?pf@RF@j|Xz>=++|-nlla0rT<Yf)US1$MtJD_agE3ggjLwDS~IWlK6 zGBhq(t{m^4>#J`zTv+s%ZAplWjm2=^wf)+=>1e4zD)0pcjfIlk`n$sQyF$b$991Q8 zjL9wiUc=#>!{D=9C<-u70g|qkyPNI!G@u-`cC=WQ`I&HP>3KZsB)y;&u{WVs;kmcy zFRY49Idk`*+3=^nSs7FIU^|-zz@#2zcWe`wp@Qz`eN}6@T`lS8(L!aSRi?AZF5e9Y zz>VuLOvBB6xqls2X5%EkjK|3)e6_aOvRqFXaO&Sx=;wrgJv=sbyi29Z`~__mi1J?0 zVncHs`i<m5O>#$MfqzT@)jn_ogM7k_m9VHw=63GiR)I`nfRokbJvU_u8&Y@6jc58* z*?zj;O<tIv=??U-M)Tt-46^u$6yOWC7dnI;G@#Y8JK}QN!VAxc>D<Y6k?S9JdOU85 zy$QJ(!z>)FFhKsvuP!G?HJ3MKwa|Pt!nk~)P4l414yrQyHB$ftAf>Ge-5C55;6pk8 ztG68-S$B3HM-1KFrMq@e7N3d58cd)vR`676O$#<3e7sPMt+Ctq+}dc(H#!|B=yH{c zoWx?~zb}lul<eV=Hmr-Ec-9s-BdTk^pG@5HFw<8~RKDRw`gLt)^%T3n;LG{YZ_}B; zlV=@lLtWJo4)-9}Q-3{kxFrY^g)=DQX176B{-Kt1;?KFNj%KwjN}v={SbeVFkdTC+ zm+lT8yIHVYKBq35x0bLW2{E_L&2-nY<lpl&NyM;FB_j=jQ<0To%lUed7Hv-)3I4|| z$`-n2!GIzv>%)0#U4xtbC<ad<X6lXOSZa))ch%56*=_Zy3h~4Ei%lmatl>up%YK5> zyh_I4=|+A9IeGR-ElvghqY0`EFzY+j*{f-0zkM_k4-gAyx;t$MKr}6A?Ac={Gio}q zEyPMW_35h#fd?5AxFa>5N>U#rGIfp)M-JE2lzFNEcNBT@Z#T{N^rf`Ku2zUyKwr4P zV4j<{a}H2v`tcF5TBOP4OMqMuZ8uZWYIz^omq`b!)1NYP4bte9)du^Hmc8y{u_1>$ z$+B{*@{AO+I02$@zkZYh`fyXdQ~sxHg<e`PkmvyjSDPiA8ktqcX%>@=ySu)g-l}gG zP3K~J#@a-s8_v%_R49#-r^kGzjdH)F28%gF`vqH8c=(5a%!tLLE|h^p#@+}5u4ffr zaF{bPj-0Ek)I`ctr16BjbTefLGaDP-W8*tNQiY*Sf6LQS>SkdphMAV?-;y35JEYd6 zVuCo{m@Af&#E3Hl3qID>am=!ocHxA71a2k%y*<;Dla?mdw>=3FU(3H38g{sm2fDF1 zzGlapn@>OQ>+4Sdt#jYxWcKKV)@>O|oBiEHJcyFjs&h3Mn|X~hb7<JQu2welimh4{ z^}-BMXlJx&{5I7+%$_H)w&wU;F5c4R<RwfX$9o}bkF!}f{WPg*JXI`emS{m#j5pt) z3GsrP@3NYeo5sq^vo<ECiV_AjYI)e`h;s1Wz9T{;__}+^^ezM)<$*6gQ5g{Auf={d zNylEo+a>tgD!3$q;#;T1#rW3I5@ch1Q&3oSKtyO_GVV4nl~g{NP*M;nl8a|FxxwS3 z-}xp(*w|%>Z7ilKqRlh8vD<2qQ=U-efiu|I$-zv6RP&XF6mh%n=fWh<cW|xitbFn) zNXx2xD>U?Uu@isxYymVf*@a@)Kas^r*Ko$v1hihY=!kxmSBedU^KQwAJZPD1;imM; zF~9c*S#9i9<3GJ(c$*&<LSo#pm0SwP!8Ie)`iEHXZf#8;C^zzO(yJK7X_l0(m#q*Z zvj8o-J=|XpL1AUyC9LbX+;%ouB}w~->PxZ+9MXpiBsMOmbG57f(C%Ux>4n9W9%@=z ze9lU*hUy}J=r0B%ocGgJ_%*sTT#k1W#>7J^@s_x~zbt5xm_C?c|2ikyD$M}=VhK#! zV3y5PR$F-Md_&&CSIb^lc9eW9`;Z0E5?PPuHo6=>Z9-aBo5UxJo$ohUZ0^U(;e5(j zEi+V9K3=owsrZZ^EObet^UiR1Tr_@d(Wj1z)}B;U46!Zx_@@_Z8#C@L&6nR>!-ZKH z7Q_qKwnenp^S)gPJcJIDQcH8{Dk_l!t=R4~cWiH5&Z@9k``&|5Ew-})|7KV`qfz~u z>u0I2;L61-=K9Pr^h)OqWZ6>XYQslVcZk+1iO;RAE(V5;%kdZ$9@+Q4JI_}5M^Env z12c2OR{U=l;5OTQx3MV8?|d6@LPi6t&Z)arZ$t9}pM&Q8IYb7#;QfOYDJ&#>At#4I z?Edjl;vJ8g;O4wk9G#Axqpi0*oF}=>>w8c*FwDcpZn1}VCRQIF&ZO(B$tF$>!ua`i zjYnO<wfg!-&`etq@Hr|xgfblbR<D_D{Yd=H@NOsF<@$Qks3E^$KD%GF%TA9}q3)*+ zXAn+qjMwK_blYnvO89E6;;)`#^q4aem|K>=U;UgA63F)Z9Dc?5OJMY0^s%#V#&~r? z#w~QsJ-C@*hsnv9kwWF<qWb3j2~94WJB~Nn*UAlhmbPMZYSq&;X)G+EL1MxoYRbi- zkkmNj&*9}nbkD?oTJik8&K*knu0u~XvA>&FXoR@W?fmuy65YgZNfUgJO;x;7{Cubs zY)VH3n9pw1t$$KW(JhT<KC9As{9H&MtFKGM>yEzF46=?>T6U(<_-;{iUSLzgrB`1$ zR|VFQf>iE~kIUMgg4stoDFJnPL~p%=OioVu8A$PHJdQ;TDFPA}Bjr{l%#R17!ocAe z<kZpZb5NQ8{mY4to9UV_ISs?Wd-CjX0=8#jtM(WZ<DDHSaX^cnYX6?=>swe@W%v7Z zZC<<Z=H<uAx4Rw0aC`7C-0Tm|cc;&EeY~4qs=blD{CmP>d-tO@rCx`=Wn*Ik$N&Un zYkX&!wMAB{_EuGkm-i=|!uCVIy0zsnZTr!Ks;#2Dq9+osfNB0TUbt5_Ox68#veCaY zE5smB@;&57jUpLb00AjlMUJdi=@mPVy>pnhmtncwYNY+W%dSLiknYOp_;|;-00J7} z#CC=C7Cs&h2&EtX#U?^x`0q3l2Z@N6L!OUFIAj_%78H46o0e-odUrlw*_}|1PN_Iv zOuiIn-&B8YJr|VfLF~GTcUqF>{E~H85|#<3j`?VN^Xt&X-a!!F)ipamd2SAn#so|& z^BGB}ME05GAXB{eDqeh9sI0FLT30t)D=$<ql-0M8VM$tZ)clvrECI~Yhq2Y24k_m6 z)e&T2!^ulYbqAs!jVN+jW|SEwO%N%ja83>XtO<hQDVy<DAz})}YiE}cKLaH!v!p*} z2HJIw7;LaM;lqQ28Z|CKeja|{?*G#hq+1Ro0Ch42(mZU3#SvApJ5)aaC?1A>?G%TI zh`8$2_D)O0Ecz`qwJFdYe0fL+i=(6YBAZv4(X|v}t*f{!W#wPUH4mCR!A%KA0p31N z{|+Q<GZSk{{E62uB#9cWM=+QM5uG%?D20Fj?k7kBUqDo5n;^IuCn6unN^KXBB7-8Y zN+YMG7j0)_tCTy0nG(l?siPbmQ2~Yn$>yfJm!*JOn!%K8mKs@aMgb%HWolvAGhfp? zs^>K*TFY;Xb`=YUvg)6jj59G!!M^X9vX96;GD*!}87JlotFF2q_+fsN9eLcLAU`|y z)@_AvA$;W)SUa+z1Ha&9RV)LE-DGZ4bm^>GnJvJCdb{96I`s4@uL2MKCO3N@+)n_B zR`_E_nsR!Eq^qIe7|dhJFhp!`_}^JTYgW!;e{ZjURQKYbNOq<_4_3+)S@El3fg<ny z1}A#vdu>sGgct}lJYEeS0j%Q1aLE58-x+&5uhst>NTQ>p{pYpOXQBUi`~RO_@SeLn zo@yiOF>ZOhmK-<odK@1!XK#-s(`@oI?@o%sd;z>nb6W1xkFTic>G>VkD$_WDKfZRA zmEGXF*U5qJ`g3D{FRZt^U?sZ4OSnxh36(DbyZ1~UFh2is(sFH6R!fME!?K#qzWKOx zeN3}jrl6_Gbh3$iN&-f)Eqr?(vxmT3!D69a66?AO*A7fxbDK{hkB`zq`#>6KIQ0Hc z96umgVVg<W4-f`0wY+u2w0sY^+j+E-UK$?fSJbOEia_~hbUzh;<bK+hctodF#syAF zpQtN)zK7EuFn28Eu6Ma5S_nIax2!fZ8x>q%!yqNi4A@4E^(aXz;J=20Z?FZlFi{k; z<&cIjl{2b??5Q}4EG!cX7hl^sx8oV4b<t{zrT4V=OVj*xDO@g^VMfv$>nygVsSnVw zb_`Jhn0luJDjq!`IJ7b{g78?nH>wj}py7aqxYmt^wA`nt>MFBH9;7%1!ba2YxQ2%# z12kX-ZFNKn7+jdm7t|eZ*f==$72aJh!Lm)wG<lM>FYq`F1h>ViH6844P~9cwWt@WY zeSfJ)5!B1RfjB#RC7(|-k4v^MmGMb44RWOL*0-RQm#w2wEmy0BvfF0n{B6VxhjaP7 zFDt=wV+n4b#_j>BxvEPg7VTU8{+Ze#<`cznC>0G2_tz^9^`Bw}*lH{M<Cjy>(({h8 zMErg2jm5`NXK(4HAIMB7Qb6Ff(>~`FD2oAVqC4GP{{TFbm@CT5B3#(aAjtAyln;vA zkUET@V%*hfs|7AcQaLfw-IZ|_!vu~^;nsLS1{@;vP_MBFjP~_y2Rb%uG12Loassxz zl8_L_7vH}D`aOs5AAcdC2GBs|WM$ohzPBDtip$OMXrWmPKLB2Vw<%#k9>@u|hl0Ss z(Y4BIG+XiZ7xxLsY$zWh<h4jt8C=Ks_79(oU$gziZXjb|qC1kQk=t!Gq|ainr&_Yi z!o;#alb-yU>9m!@9sn>@_`)Amw2}yH>eeY?@Hx5m7wo`9?F&d*tyN4P<ES}WDRaY( zhls_24)*?Jx_hG19>7a8C|tz8=qDrBD{`P|dG53AE7blKTM)(jbzyvN&(8xl=yVOi zNUj(!lHE%HloIi{uQ@7($7a9k8)+=Y?dDmq1!Xv}0O8i}eTHw2*+LS5_!V-z;N8r7 z+*z^=ALJa`km&tOp3zB|5u51s<jh|IHIfsUp!<G_{+r7K`M)FCNkRbw6Zr;t(Ha8z zDZ!J^t~nj=>=kS!$a(@Z15v_T67%F-zF;r99q(k9(x4pR6QEb#TtEXU%O9h?Y$YHm zcnW^)t#zNM^Xs{|oPEJHhiL{zx4W};*z$HjnE=*rnB{Ze=@B$P#0w`WA?bGGfMt#f z?SAm<0jn+1mE~u0arqh{pJTb@9+uk$u|U~6Rza~plN_J%&?~QpQG#tz)EPp?EU%qS z^VOQng+)yz;B5f$`KTnQr1Vw>!-<{8>H1txL-6Na{SDr9J{i(LZ*Lzxm3NVnR+(RC z)&`iq=&v8DgYS{8mR?58ed2j9#e##YsA!E0;Y4iK?|=->!~`6&_C^0r6<VI#^L+}6 zVmS_Tb}Mc#MkUfw(ZQr!;5f^Zgx37>_12ccs7<;`CKH**Cf753gaRLD)0u-It=frP z<7o&aP!Mrv`P~TI#a@UImCKJ`pRXuolmD8{zX<?E)kd4tZm`$0a=5Z$%1NPAYOmc- z>tcO3O9i(W0@AV?4JmE4kuiewmw%(ezI|7G)NIHPF#gU+2DfgyRxCdoZ7Gay9_LQj zJzi<88+Q0&H6TD_-if#t13M}_-8Y0c1zDQDsQg;V13|Drq+*xCV)06+nb#oiaICDo z*QWqsohQM(fsOXa@JmKAeC*Ge)VK#ed)?I04!HDWDoPv-{L6V_^HDr8RN~qvW78V= zyZ_7PX6d;92s>j^K;7ePowS6F*0_mLSqJh|&VV-E@8(kQlHKAfKk&%ega<44;d6}* zxB3u(C>)RYU)&oTnfb;u!ZM_nhaAp$Jfl66lKU#C|3*-yWFC~R5vn=~@FK5jewbj1 z>i8X6K*QF9&~`7kbrMGi`*mK#Kkg@9|5|Upp8El|&5%Ydvg?Zj;EC+#V?5l#2@Y4< zgf?PIrAR~^rFTr)$xP2fnQ6GiNNWDa(1#(oVdN9=^BE5S80C_so?d(Oy9wl91l0!% zaBXJF!)yIVSQ&Q0ln;N=!YZq(a$4AMakT-kShjJp!e%i$TV9tNA0J}NRhxX|rM|Yd z0J@z1%(B9rhC0^+EJ#S9WM=dTjbQfdM*<>-6+$js{kt7KoSDvZ*1mLiBPl6p-awHp ztGCD7TsJn;yD=mKc@lPu*=#wN4f;?m`?ml13E`yjU7HcPx+ryVpCI5|1t8{XkI93i zp{`__LJt&yu8$;*40`X8eLz;Th=IV$==$^8xR?&u3@@E(eQ8?>ycb^g9+p<xd|Q-M z2P=|#Yr7B{qJ)`x>3K#20o1}`|I=1%Q$sabC7EZk2VnA%F<9Wv1u1+v*R{P&_c6&- zky5V{%=r92*bv-rPAgyOXmcXOswgbjVs@dj2C~don=-m})8MRbJ>Jp0U_4GmYG!e1 z&nr&m&dOfwz?^*AKiY^*zTbp}g!&Qd(QTmvE&|F(2QzK>LLYt*pOU3U__k+Qa$knc zQ_7|SqjN<yxDgam8%A{_qn|s$N~(-M6utSp@3q|*sG7iR5Gi)hYuJaZ)+x415H_W^ z=FGE=VCAo>_Q)tmxG^<X)Oi>yZ?2hp5SE)9N34S4N=Zk=y43;ms5Dfk-5G7Ac+gq} zvL&-v2?MVwP?91R{gw-o$24wy`1Y#|birvp!|v;bJm<14DQJG#?$xYKm3>=^f63wV zu>f7f%+)oyFWyJa)XZ1Coj6B8AAUfRKAd>>yi^AZG7ozvcHvm9-;$pM!lEd3a|CaL z>hzDj`DSN1!Q{A?o=O-k(iB}&snj8TDR)^2`-h*rG-T3m#Kro;{+tOw6gzi}RHQaf zn`EZx@z|fSLpS52Y-lqMFJ33c*2kSNoAdTAxq;A;tgc>@@4uGQG8q|**T;)lxm-WH z`b!jwnyOK=U>PwWH9txvo&9OutuSsx^au%0-<_LhMORe^$QcNac^eRt1zbZx^^?x5 z8z5*NL}@h;Oj5qrw|+1w@k8vCkNe9rAb0YZcLR`oVPMlUChwqtS+AC*Mfr(Z!!I96 zV_KPgJ9Se808;={t*e#IcE?+Wa89o;FB)Eng2LtA%?X<jPI?hU5{05e1|y_Fu<leR z;V^1L>2`<}x772V2%=C^8qt#dB!XB%S4_?y!vhhCulwqh)le9Ak6xP2*1w{N8_#L> zp5+{nKaCZ8$Z&QC9zl6!JA-J1ywBa<OJJ(@bZ~(oKwbf(<B<Ek;iyDGv>vkR8u3sp zzkeAz^}E8nZ3fR?6~r5dU3d(_7bGm1`uciV!WF)(@au&oQE_%;Vgepr7!a-O=!a4i zB`t)_KfMF~L8_Z1o4J|g5-+uCcV<RVQ(Rw0;&46ltNaiUTgbk%yPL70oKrGlw27v7 zb+?wuX%dM3GMZzw%m(M3{Ll{X@q})OPYk|M6huM+mI*dH@@Ie;5l|TCnWgvgTVaqY zEUl6&;W%lC3X2-5s`LYKt<&*|f-0O+M!9~TRJtM3a9CXXI|1ED-&y#kg;;a;MNOj5 z#+YUS?q)bwRpfI!%<?aI@3{V0>0FOZUQj~Z)YDaXVN!nE(g)>I#7f9dm97hZCFZat zC_<C1P*aThIhc?k5jGn=sh8d!d(v8pqDcC|ednvLwmPtXGGrGVq%SJIR&oRPfhcng zq1mt6MkUw}-KCxFjp3Gg=mA&1*sh&<OCy6}y<UC$rqHQI|4|Yh5?F6AqEHV1<Y!|k z5X9lQp(`~vV#Qccb!kN=Bea>Jra~w{UV6}h6oOD(8}<qL;b^8=>!U6@^5U^oYx>1w zZ^)+|?=AWpWvsD*iuN~tOJDAD2$`4fD^o<Y&gTI5BEtN$1(B;(r2nCJm_AQq`t2o+ zW3x$RIV19g<G|yJESM1?x9t;1YjJjH7ip{!joMIM?fdt!)~$trA#0!#x|w(UuAd=k z1i?OVBh>2<n-2HUK^87~sjM2G^HN{X5E02sE#!fY^KaV*&IRDVyr@Md&D3W^hweh# zslC&YI-W5F!c)c9$AXcixrr|PWpvsn)J<l;(A*@A@UXtg6)QmnbyrvWY<Y|odvRre z8p;vYzI4^I!Cwjmz%7HmUV~3jgfll{>(t*rx7PVmh*8LFGL?jRcAA7x0pyxW_mvMH z)!K*<wvmhmMA5b>_0{qVoiV%COz5qYG!P6Y7@7K1GSy;JBl`qp#KlGJFoe<s35ct2 z4jL{J6B9#3vZ!kXaCmg9{fz|0o-02mLtmf~i%M<B5UwN7&I*nsav-PfC{L-YO)o5j z5lE9?RYJ~=UFV`hF@5zarx-O)*sx13{zZ7_$oVh%S|u4sd$Fb;g7lOj^#tPe#5<-D zgbwXj$}bha4<Mwu@0#6W?9j&Y7ReQ+2pG~+l95o)e$)vSqc~ivKOW|*?d;(CFkGnE zooO8ShzHFD9!t(5n4}YTW6%WIs<?MqW`G_yatcP~#~x|z>G|tuMwGK|ba^9)CyXf4 zZdZLmAq&XLfgp6)VttLRzN=61yc~ip&&yGmC2a8rjKDjH6Bt=g_PhH%A7n_VH{mBy zqk$PW@XU#$)q2zR!+cUFk%3J3h|F3<s3%nPYIGqUQPO<$PpBjTC>=+Oj^>=;ldJZr zxcY#dx@<g4PDKg3(PTL)0J9|Pe(T!C9sDeS&^aHD45cUOVtz;9zB>AXbdgLz_%$zZ z4Po4dS3osSvkz9%ySbU~CKGM>dY;?<S55v~M8WJRSZ2<*(+$KPlMQazQeR(>FAlmK zwPg;;pi<GuOM%2>1ta*;sj-2v{Ai(cTO4$>{DGph0=%^83(IAznY8B9(SlOq-d3vE z`0F%CyB&#A9&SZv=a)@a?WbmQv9se~u|}t-6($}??q~wd9~X(d+n9hC&?}lbgifxs z;xz<Y+G3~#6<WEE8LWu;@=DtbOo`1S-{NS-zm*gC;*g8~zq0^qUgiUVGTlz!+@;ZU z{kuZN9`v(Y>uuV=bivsVs;mrWFJZNQ-Cp3!iBm!Ul&F}<g;z1WZ!d}pJe&Iwl98jN z`i-gb$6>}+0L(jyl^K!wpiNmhMYxgY?Glu*efX}*D#)?aGZQs8o74Py6Q*0c&;5AW zR-S=NHVa2uBX&~l=ZkQ52A#H7fnsEZlaSk|iq?U*D9vR!tvK#G{Y$ArITL-p)pu+~ znmWKNh~;zcanKb*_Tx>DdIKyQBBX9BPG#D?py?%va^|cqK(7(edJ7y9M@<o958Z3) z3xcCUM)O<k*236sQ3(_yM}FtKiSH-_CHQ8?b2Lfi!Y#}k-(P(-os6a*>8Cn7Fq^|m znjdj738BxM@F^lQx-i#CHBSYz(d0RO<?0rmPnkN*cHA9x=EL<_k5?~(LLVE#O<3#9 z5bLuj$j4NVHlPVJtc?yKAlSrtPpA3&^S9G3C#23;-k}JBv^OK(o5K>)(m}iPC1LdK zjQU;OU4`_86bu~8MVj@`ohSpnVn;#GbHr_rj3GU04A&J>tOvSp9JFJ&Z3B}T*4TE* zc$lClgCtSJo#4@^O4G@G$1mYjdW@q<_Yd2r$t6s+Ry9L}X>!0Y*nbQI2GDs@`0R>5 z1vrT|QlsJg>3Ss#ZS74z{Ob@v&_}Eg55E6r6!jI`zFkahcMkwk!-g~{scp&wMe9GC zog*28K<^-$Gd1&<R?oHWy!m(;mV_!pszk{14CIj45@Kh#Po`-+(x8wO9taHyGAF1r zm4gu)Wa4BFrhm^vu;3FY_e+Q(w3N5R3`vCYJB&m1Fkv|F?8^-uL7U$72>jM&YaQb1 zCoQ0%gx!)X?(Eo<N)Q~+N}61(JkDl5%UtQ?^EPg4m77}@sy}8(x!SyE11<QYA`B${ z?;3Diag)8%a!}K1(^7>iem;h@7L*h-z1nE22ytuO4Xs+msi4<tMr_IAa{I-@u-eMU zVzYl-SF!ADv$g|Siuqm5FF!jT8pLvdJMq`H^m|AO;!N(I#v}#}TLLA7nI{Ws8wq7J z80x8gX^#m>ROUs}BCPs;XZF-8<u$x?N2Mgb!9d8zi{Mv2KHVsL0!Y`BqZm_ZAQ0bv zcR&|_l4i<?iS#r-?y}F#eFNhJ&1P3E62X=wPhzi=bpS-U(KA=bMipmVc>TxACRG0A z&vf8jgDS?&g5`Q$v*j5`5fhutyBSax%^_$Ack+<C%xVo~G#oRDeZ9iw3nQbq5bKk_ zbQ){UcYP{m-}%c$7Kd3A`O@-;70hm}o538I&!{^r?%sz8y$Dql+s2jGLaqhS6IzwZ zGswo@EG7S~zoTX_cQ}}M=m3anZ|iToF|oxUDcwHN)T{eDaygM5g;<X?(&O33i*0qa zX&4$M{5my0Iz6SH9fcWI(9iipTN~}RxKq=@d{zZC?-<Yi#_2A1v%G%gd)xj|<NI)N z>zLmS13-?ILUInRfSbtoChDo*wgC-SH{ZB?>HL8SLcTkRI7!fHeA}G{XU(xRl`2dg z)y!-8LEVE6#a}!&mA`y{pEfcXHui<LdBaV21IYRrbs(KH5V;~%z3|ojKi!0S*$&TD zoU`hGRV+EXtbU8#Y0JJ*h<_z-*!5k^kldfqVEBQIEC^LDn8$E!=T*yZ=k)_Lc|4WB z&_U;Wa))k_*nn_;D&$}IjLq$PEVW+N*NVCU?P|S{x#m6=Wh}QNA}wA1tBpbz(ZIm3 z=hGFXtrem)-k2D4x;z{>jT&s$h(eMmlI3&lC+8-OmOagYA!L&o)TjLl6M{kl+;TdC z34{B%yx;6hbzzfxPuyIbhebvdu0f$@udU#el{CeIVaF<sjL=vZ^Ofpt`stJ~7lu4m zA13}3m|IufBS=Z~@fJCYkEaM|(FeH+8$0amAc!|{GUwjce#K3o{KDF&`CzE<Dmr3` zx4!xEguN7Y)i$~Sap<{=nXT#OmLFot=^GzoKSuJrRiyq6{>cB4+a;s~s$o<7jv&A{ z%dcVR7ndDo=u{g0sIw`rGzFSUtSzHc>mA+D=x+(3v%lO2LbK66QUCmjwFVV@Ej9Am zcSBj!JEU1F@h9Rgl{W%aJ<0bVqYbl9QWBy!Upe|VtC5-Iab`5N@bZ(8+U4NRJQwlY zLt$xgBXk~MQ_(SWQciBiu78PT5DP?oK<Wv`@nV1NAt9ZzZ}8l1`8c>&d$9qYwLhH) zVpmw6va*}D_k(uobxa8lwDkvXOWMjPKMttK3t!TbGIEOCY5wHt!#q0LRaHd5^e)0q zP)`2{%I9dH*(aRbus58*<Q`)IK3mF28~v4PNAwAo**GYMrx$LiE$nVw#h=f<{YWqW zIx?jTbu6_`lbejYt1mDJay(rw25qNYa<m1Cj*XXQmC4?a$J!6&g@AXpj`vgN(-WRE z`Jkn&V=!N2&fDJ<c8mS}BU%tfV=v*Hw%0{d(>FzFSbmU2VO)}ioj8I{AeaZR6|3IL z4kP|@30qbqK@8T);*jIjLM7rH&D0PhB=5g#p$yu{e+Eb6uJLtdb89m|Ot?+rd>77| ze>BRay}{{b;5zHaL<xWLZIm<-3+dIEA<n=^E-o&v{tY7b_Rgx`9M4qAO8Mez1=`^j zXHsab<GKolQ;pX)Jjv<NFo{b>>zq9|gksIHGBWbz(nk)%lswxvkO+);HO>gF<dpLO zqJaJVr2jbi=(gK9ITY9ZX$&lV`n><T-aI?WI`Or6V&X+VGX3|(|Gic?2_d<){%`-$ z0ynPPm!=A~VpuU`@yMnB5hw2iY6$;VWflKh4TL^gc8*^Va?8S{)H%^-rZ+8yeWzqK zn-F)F0$wo#Go3R%4O;5zb8`;(IZxI++q=CDSsNR?ZWq!XE}_R)@D1*2Vj1Ir#E(G< zBPi6df#y<WxxP2QI;?CyS99rTz3>@1JS+?ik&E4S<EzEGoQet-8_=ixF50WPJTaXa z(Y}6DV=eaN?E@kvTRy0<>D_&1W@esE2Ob~|b#+x%lL`xqb>=mSnWBS<>|j|~E{_%% z_IGx6W~}MASZQsJgAg<12KQ{qZJB@E-<JX!Bhi5PemySB&u(i^z;5(^u=kcxS#E#Z z?oyCOx<o)ix<QbZMv(3n>FzFR5Rgzxy1Tm@k?s!Z?#}z2;9CFZdG-@~?D6hB-Y<K7 zTuax``@Xp5oWFUV#{u-W=f3Y57HTm7;^Q`qsM(4b7ys(&8UMyWOiT=-bkOSRD!}Kw z=H|6xI2gEV85npz3wS#OoNhuK1KV#r{T9E3?{#(lw45zHfdr6HKL=$Z$nJCsFp(b2 zG>UTg2?xiBon=m`l-W6p7-Ze1nobs3PL;f`x;dL%EL<#+t-2YXTzr9tmx#>ic&ztX z;D^jd&)ZUJ3JTGO2BsJttu&Xz?)72&#r64C=$=-i3+{^-068>Tvb32u*wft&$U4T; zWzSBd-QI>U0c~M*k+wE5Zy)so>1LLWhNj;61p8@dXeibve}6w9;(d9J>v!1Qoio>< zF_<O!8vR$J>&3@NuP9+{ZEb8~Zf=sh1s>2DAfxegv9@L+LHv=vPbhr8JHG*H=()K; zHM2FPvjuUM2tS6hl^J5cckJo+da9RL4gcncS|b$_6&18R1484qEx=P+gfL3abs=NN ze1FMz^p1l6ej-;_qq!-H*2e8t6A{rC3JS{F@pLmnBIb_sVxHsS8#+!F)$NrBR5d`6 z(XT&fVsYJ#1td^q1;`UYy(J%iBtC~eB7A^dxoZ#OJKG&cA+6R9Ti6&##-WBiAmq6j zaNcO-uw971UG6PkNRkJkOi!%Ku$PH*9eYr)D6K<Ji${ayvpg<`vp@B9Hq&Z?u7BwY zh5O+W1p*AUh6~7eCwm@^$7p-7n4De$cU$9a59`|}?p*fBwV2dhSGT>z8%+@60$L*X z+pWV0U7_+G-=J?xecKD=2iiLmy%d4?Tl0?Z43wfpE^_`#`0Va-fk}u#PEKCOS%=^y z5q*CRI@wrudS<(c1Df^PwKiB5tvNZH-@hwBw>iAAZmR*pKK1IhQhc|gv>0W4CSHUS z07>$Bi_hwG31BpxEenk<fHI-^&!fR&_#v5TXYaD!(Y;|75AOxAPj-R?(YCx4EDRx! z%TV8#-OblT)OR=oiTocweCX?CXnuR}^Wfu_7YXnOUxlz|(<I0Li~SN%qhdIrUan*9 zY&bA0utt*P%;z>)nqGXY8Wi;Y?K94g9XX{3O&6{H_MWY)P?9A8@gqh-M@Pp?@3C@S zDVIw~(tJ5GrdfXhBJ$X?y`Gw-`X??bZ6AT7nbVeS^V?w4RGmKQaq%!u8zMOoF)M3< zDvR_qy#iuKat$556MEi?gB}^PZF2)R_cGf+A|PZPi+=kiPp{o{yMnUV155szqP_Tf zZ&EujrVH}qNw!D`t^+xx(J>-M#P6VQ6gp6d@bKmv<4WB6i}z5V2f)bA&gXgmRET0% zg)yVm1$KjgRz1wx9sl7u3rQ<oGydIj&u=Jo<zVDV#cH-7ji_S;P)DNU*)2aQsKWq) z1Pc>WtHB9=mb0!dT{N`AKPicD1PShK;qe?|YpeY>E*3Vn0Q>L1p)N<LFg8&=@OC>h znac|mmFldP>(doMo3y6GX&gvuQ#s1T3ttwaL5jaE61vitcD~V7Ia<+~h-4p4d~+p? zx1_WRo3&XK50%MZ#Gjc#W$&%i;ZRy9Fs!S>q`x4e4f${^8Uv~N1Ugf{;uC?CnnKF0 zRP@54OwN0O$ML@H?&iYBM{uUXVm?<_v~-HW-?!rA7=6X5(j0Nk7g>5R%gXUf{+L&O zd~loOL;f5hX>vlZ4!SIsQl6SQDiev2rJu<jXJ^%<{wRfj${JDg<PE6J0p&H&mWe1U zE3=IV7V8-p<Z@r^&qF6XqY11DmiI^UC>i>>P~=rd^8%M!Wi}%{UH5wElP^tlbd(O1 z+-_%#R;?3LhGhH%u-X;FQBk9>uo@jgSX1$NuU5-Z7Caqq&J)2833{H;72#T#h_9%M zs#;G#j>d_vZEsJnUcC$lCwh>X<28P9uxXN3Jlh>$TO3og?b_|nU7;){(-2*r?>a6d zy*ard+Gwq$#>}I@`DYfeU3JdOtL=V5r{N^YJtxcTF<<9)IZR=-`kI1*i-U)e>X#C4 zkfSemV14x2Ho$&9Gzhvq3Hv)n6S=Gpi`_5wCYOs+Q<pAFb<Yp@RFss!=+XAXMxRN3 z6=r5`4t9xyg98*okY7xFs(;1ToRI<TokcQT^Oi{_uFk*!-8|@np<Wy6vDI7UTKanO z-T8XROyv$m7*Q#(aPI$1b|dG?D5Pt)X;{s^;%lR-)$ctA0I8W9CsUU&=2yQznI1}| zInUPt#aP+A>()iVDz-Ji%%VN7tUVZrh%5W(@PgeTq|J~(%X3dLuyClPx4H0=Ae!3u z^13SQ>(}W<L(72Yyi=Wf^>4Wt)bH~x10Y<;Q85d_zwv-)P~hPOa(`l!#rJ}(LRvxs zvOasTG~{(!Yejtd)0yw;%05br%zU<Dptm364palp!}(0_{3X+x&CY&QGPVRRVtbcv z#JukPI0YJ-Q)Tw9i%pG+TBU}AgvMZa><Ayxe0jX1m=8fG3<WE(1g_lncsrZIa8l!q zqKM#2YmP~E%l^yr*@M#5EuNmwh_rlsDA)|C;+%Fy&GxenDuu5^inW`MM%$9PDlCg% zB3ryQ-MKEqnga~K`}?0!p`KcM)X_|h9PTrKtOm^FI<sIwQ_PR1d>5P2@ivk3>i%r9 zuF6~;aU2Z;V`p=d@}Xw|ab{&(xIMgM2XH&1g)(!}jV@r@Gx<3A@jeWz4WvLX)|*(& zI$}MbU<6UXLaE_^FeeDNJ5u;F5?qfDLbNK_#)0yFAx$dru3^UBXf$gabbl1J2Eg6+ z^hl??b|Ra>T*rWB-R$gi5MjHh&SeSlVZqtvxZ}`oot;U`g!7rPgxx&ePh<1N@l`@) z?mwj@4`g9N^cEKOq+k*v{oY+qy|IhD>yK3}g(f^tHR$J_b*XeTTIGD!m8q;PyMdB; z+t#s2<l(<PsF+V7neYmN1>-C;z$o4y-~4Xw%wppi{A=~P=L9fVJ7-p{-#AlnY;A4g zo!K55KH(7VzoSdWc2b~EbUR;<hZiTw&E0`Bp$Do)LLws0J)vdc&*;=xiP#-Z3l9&w zEG*Kpx6b#vQ`<!~;p@T0sJfcm_VTjE8CC?Xlq1-@B?{#{15`LLrvh9$&^l>%Rrr0l zl#b74etmL*HJ*j?1_KLkZE2}!z=s^APl{ADbh^>>Mwb>(-{bO#LU)A|;o#!&Rm8uH zE@x8yQA1Sp=Wy#2&z^u3d~U^Q3e<%%zb{xU)EK!}TVdYu@%b_|tc{`(U=LJqdl$C4 z`u+MWKO*m14uF3M1^QL0J=(*GeUfu*yp?#JHiriG)E`@EV*|$-XpDy~M#S{}(N9+T zqiB?8D^Jjq5ET~Enb|Gpfdewq@tlVfJmt7=Q<`_%*QC8WI)qdZxa_z8esDfIyDTsN zsh`)TMq50ziNGgH``?}wWO}vV=AsEx-S1TI2GOA>QTvrrD4W;+(4xMjp^}7~t7K!$ zte7!+GHZ$&`tWE<Cr}tWN2*<g;!`~~g1AMED3i)SvA!-<msW2L6Z3t6o9nfUnz)2~ zdlliJoi(~eK(-zhUKQR@ePL!e7GVv=TPB+Hf~C)BPy`uR8`0~c0We7o5vt_FETs-7 zXJ;kCR$8B|-gS?Mq#@*v_x&u6^ZQcFv);M8h!ahRX&Ck6O<p`v4EfpaaR01Gqz8}H zU~LBpLD1MxmboFrst~34=^_?MjoP|!XSQBUoa+VNREJ9R2c6riL_-_()6Lyfj7nY0 zhMSLkDCr{wJED$4wa*DY#$c5kbo1zbyX|wm@~#b#=CgDqjnbF@fkE&B6E_KpG(18R zvHAG`HYX$E-bswz%N5g9`3SF*NGSmBz!ZJSform95P^o5sP?M#1aEqDI43WXPO{d{ z4x(AVVD2~iB+eYx(TohsXLN9nQ*$acn}&_0?ZS*VE?m=KX`QRY=g012&k8>M3QpsD z{tAzgcYJH(Z$Ve@75p<m@tBA(2=L3iM#3BKT-I^Pvd|=ds}FN<ChhE`rM2t#O*YFT z-G%M@`Xc=Ex)-K~YgsYqFVM~RSW=5AxulZwC$ob?6|R2h3wukl^IiNVWv9ElRtta@ z(yuIKqC=-`fW3555ts8u*=vqmUN$UdU}B8ONUqhHacoKPB1b7BsjKT@ZVOB3wLh4c zZr2d)R%-GV5~b|zW#8j!$X1l?TWTb3m15I01Hq1k`4ZdQ=TM@xaoekcgjd?7xHEZQ z^FEERFk_-y3aOoKT}39Q%DmCnzi9KhJ(xM&-ZGYdVMyJvffa>~tv^pwsQbGAJr#=` z(}-Y31Idb(50{$0_PooXjc>N3gl*nqk&P<l>Mz<#BR%tw(GLavuVuGXGY3S_gT7Ws zr5ilQR(!4WBkDVqO1-M07-_q|`P~a8Uwv}2%%A#~#Z78x>5TPL)afcRuals2Q=@{C zUcF(=HGS0|^F2B$3PH|R!lwqG|3>h&{xpa1$a2{iCv^9qq^JN<(r?ZBnY4W8s}XMQ z2lsSz`Q2$99Rmv*)SF_oX2`v1wg}Mpx>$~A$&sk|&Gv#Sol;u#7O7$~R7ubTxk4s; z!y|Q^YtZ_!FRJ*IjHVZ}+b}7Z*d}Sjf7K|vtgUvER3|M6q;`x|q=}JbO|Vh&5MUtE z80$^QYl%I8e{LO}xhD{VI)>(CNQ}OI?P#gAg?L$vQ-=fu^&YE#$F(B+aJV-*$j@*$ zlA8Fw4D&1`<P>v1uOdfmQH_C^m87-EZ*Q?u)i^GN7~Qs-Uia2)buKtl^%y?-p08L= z5X!jnnTC>5EQ7I8Ea8hEo7=F430{6ds5nI5D69`zKhzS?P%+yvMj|+4<xXVzg6b#g zvD5Iad3{>n=9pWc@9vnZeiwGu8%6DZKqv^`;O89f1KMrH?U4#-&qj3Rk9`qn#>QJp zHg|tCNh_&+|E6eQq^^uI@|u&a{Lu1+n5>@IPM!Vcbf@}@eWC;v73-JVd4Cl#QO4|M zBm{`OG|N`dXr^Q#*8XH+_9~|VkqeQSjy!WYA<dU&!)Jx2$_^<a`E~?BUE#XX4S6kA zXmBi7crb}q={=5=$htCa%eHv=Ck%<b1kIOZj%jkx7`mj70}Tka$x_uQO#@oVxrRsX zSX+I0;<hyp!vLh)Z!=-JA!Kf(Vm`>fi$1a5-uiGm5)HG)QCZ8QRA#VTyBuLL*}V5W z$xz_j?D?-=`tY}xNN);Cu~{mNcTnwZCig!IB1*GUjM@?h6ssVe%2>un#5y}z5L927 zeb!9Ydagt_NAmRfeiPLjHg?}|^tG=-)ENnLl{Cd-j5bE|!l6D7;3aw~e#7(q<G}$s zX6x<o?6z?I{Z(Vv+qSMVViEg(GA!&GX30V!PV%psZY$N$F!Lq5b3=0}l=a;cGh+&$ z(vxE-D_MUplY`gx>Y|T7A5sEAlfGra#^)qL@-~cA$~6-!r?y3$Q?Wg6w|Uy6lFyWq za8sIBT?ymuh--_rm<}u}mIh=57$AZ~AZhw7YNVjs6i3(g-auuP$<}gZA>6Y6;k7mR z9MVJt6RqZat>%mXfkDErGFg;y(%6jUtUk2GejF1Oq^JJPMB(de9z1?THy<DP|5>Pn zpeU0bew6_0=l_j=L8!>RhJ^`W7E#~7gJXO&n24+rgR-6rIL}6TiojeyPF0c+O&F41 zMUCw1^Ao*$4X$-t{Dnx+x&?cBdR|e|=;>R(*YeP5tjhwr<UhaO+Jq_zG?r2mw&UWr zCC;GJ5X9a?-EK*g0^!{E@C3ENxsXm_@TceA0ev2Rj<wbG*=ZGo41>)bi9NFdxltCH zs@!Do-@^^@01z2qQZoJG-myaaMMo#8dO(`~P*1S`;iQx>vP(9{JR&t#<Ahm`zAMY* z<mU_ilrLl&irL;2J4QtK2ZutQ1VAmXXI|jv2Xa%kEJw=yY3`E02&Pa;dTcREJbtX< zhS>ezQ9qEoU`mI<AcRLhzC)*lSzaq>X$>&w@RCrz^Z4?BWN>y!#e3X1{14y9Zw^dp z9B^Lq*Q_dGJQ!+fjEb5e`rX^t!|8D=q-LU)uLQ`NW~u2XkTj4NMnU4XJ)5xy8)BfI zXJ%)|dHj~Cofn#%z!{>dRZuj62OraF+fKQe5S)<}MS6RB2>I^)ikt4)h?$Op8JY?C ztZj_9d<J2KgoQ75=PieqUjsoXU@;zSPwtovaXkK=Ga@&7j=v`)9528U(QBXge!jm0 zoUqEBc$P&@H!E#$ZbV?(fK<E_Ri-!`gLiko1FiliKK=vo&A%IK4}K3BCVNh2+HOem z-v2cVxG|pY*C7Ce+X2}mUZO(7vNb%L>33Yl2th)2xwd~Oxz@#kE2qgcRSZqdd3V?_ z(DTirb(<}^b37m)02dn8j-ZYU?$5^NMxkb7+KLEK-kuz<T9+^0xOGMnJ$`)(KW+7$ z)fx>7L3SV~q2=?FyO%F!ET`)viC^?d?MzrY>CTwSNC~V3#H{yum;xYUaBy(x4Y+*n zkK>UD$<53h&vq<cUDX4BJ`b+#cp@B-^eA^)h+$cDy80l)c(2g)2Y&Jk^d8p)C3)s7 z{1>sSR}RQQ8r5I3mR@49zw;rhE+7`_T+}hT)*EwkzV(`DBqQi2zyo8Y&DYuI7ZfzO zURXfF)|ZkJ6EUzI@Mf#3ssNkelM^`So$qmJ$Fjb65(ky)y7FS_<fQrSF(w;(3)ZvF zBMPZRMLb*3P$`k%-}?o-@Fftb4t05Z_j`<Xc(@Ajlj8ZBXLR;wGm=aK9eYL>UG&T6 zdpWV-a!du3nF70w9=}u*r=kvdIk_@`tZ@_bfkFPhClUyD@8po&)9bUH_St8}$+UW4 z0`xN^ekxzua~7rw5ErSqkzalKt@KU&tVpZ**{}~Pj^R&~1!s8<11+ulP<1rky_s&< zu8yukjmp;faaEFG2U~k|`5FgOx6PEM+^sFtU@P&iu1+p?8&ql!r|ebG4PFsNF&%HS z9UfV<7JK-_0;!W|jub%gi<DHJS4f+Bd}Kliiw;WZwQ3;ve7wAxqR%1yY~RQw6PU03 zaL6TV9QLlk&=wmT8v*h*T<8kqJv?K4sHYt_aSP;8-<O5g)We?)&C50aGYi1JyFQOE z28fAIlj)^2+>YTw!%U7Z>N(jR>}yfcVeHpFT2j2o2k)z{P(l+>tk;D-*iA?P4#&rj zEzhY4J49W5GAyhafHh*jn@y&8$+4Om`E_&v_Uc|IYOKzoq2UE2wosi%g?p@8I+;z2 zS2XMz1$RjL(h%5!KbO@KU?IO5Ei$LEAO7+sco0_m`o1?zk2p?MwYhlaqv9Y54cBZ} z-KWxqY|#~9m6VYJ`8u)kxa=E{j*<`;C(h`Q|G1c^PF0@Lf`p6&GRuE+RBFq(&vs@n zVj)Mjw{F(e6&0s|jyYd{LnUN7n^hTFdA8twqfdN;^76A!F*qg-X@S9|s+LyLZg_5- zv0q7!Df#UR((WXN8f<hnfJkt%RS1fS7$|{+F~acIOIW+TIsS#+?@3AEmNvFD-M>J! zSrN(F!3GQx-vY@|PyoJzI-4m1!@^!Sc;-+#zEw?}oDU;Btc~zT8pv?~f?+n?FwGzl zjTl8#r*U<Y42D}^z=Rdn#C=w&?WyjCOhAz6hq!)MwR|x)#<~kK>h!8*w~e*7s6~Z^ z_S>gh;Ju}km5fcN_EdAcC^6=c6_>4M@#u34P1H{PQky!6eu83)8+2^q0Q9qq(;ZqO zxZJU!Ca-*3Qn+H44eEsfp9&jCTVD6|1VaqR-I<v&_Mu6XCcEkWPSwXpkDOcCf-5H( z@JBt5w{Ud3BtyP_wYIZUX?CbgN=kA%{hiugHo58M&eeCbG^=XaPftl35?FJ$&s84q z9FJC^$)wuzpopRQx+`07LnQR2uI@oi-CIiyNK8>t(IKnRY~ED?dzQsQli|gE`{8n> z<)lG(3-2+SR1)XTcvj}=5)U<_%Vi6=z&$)NDJ(49TbO#oNiJ3K5k6{>;hi^Q-Xln9 z7`l+l@!Otxp$RS*J#prGL^27;TGrNb$Ow#gHCUfy<p&4fT9yZbm3pqmdbG1sHLIGC zG%Oz%y!`p@wtrr1G#KlhUb4J@SS<7z1NoBqkjy@P3Tgh)acbqLjQ3n#9<WJ#J=vdl z@%P8SNwpz)m=C>Al0G^mYVG_r4BUf{KM9am;I5DH++qCY^`9MU>i=zRW@s021?(8~ z^>4?^MV~&)DePYqc-WUDDFWKZnVmgI#y@+&gUE*b*&9fLBvoA<C!mFZl~pF@ar5H* z!1aiV0-Fys(5=XR-1Rs+41eIp!`lSA5-^5^&rkyO1;BE{d$EZK{_k+kY{O1#Hel0X zjHe1vBE}bGV6X9q>-G;MgoRx~au74nKO@UfMKu--MIJwDXM@~+u9Isy9>DZCf~R`+ zhzU{95cu+*fHYS@`r(=BF8@HMOfSecJ)@Gf*h@`I9c^R^nE#tw+hPwawTyy-f|`tq zjEstchK7oYzJadDf6+pU-HlC+Rn=m_u1bIi;7i_7em@cB<^YjvVoG9~OqV))$<RNW z5ghJqt`o4s^7eYz&Y&I>c@e#Q_*UTlw<=0QyVZO5D&<GP2iV;XAOb(&cJVDO?bDL> zFHlt4SX<Lw3AV&}iSkzdoBV#qeB$9q{IaUF-w#8@q)ZwmAZA6u2SgUo?Na(`b#`5d zXUmIC2;05D&<iPe|FK`X`0pN5xs1ApcB2l6i2>#aJufi{^K~f&&EWc;YxI4Un$tP| zyu=4_v?Lht4CB!Ik24;FrRsw3O3CTN*lN)mkoOqW5jUARt>!Cu|3P&lrRd_7FJ*e1 z(~CE5sH?(an^@M4AWPW}b9Qq9ncC|pZ3l4$>f7K}M%uh&(LNJEe*z?>sCImgDQV9$ zVJ~i8#&w-Bv?MZ3u1cb@<`}@8Iqcp{{|V*mNdxgOdOyLDv%>>N++(y}m9MM!R_|jn zsQ6Z!Ea4I0JF+twUz=hT?gJXjJq45?gEq_1<iT`fIe5K56TWq8XmrE}<!&?Bq{boe z(rHZGThgVNt+FUJgrKo2XP<+mQI4LLcBbj3C9&r6S}7Xnmr4o@Wo1;HE;oO*Lb(K^ zIqY&w6~_?y&J;BU{BU*wvg2$I_ueP&E@S14KV_r5n1Sv4PyGg*rgcoP9M<Ymz4*f{ z5?|DFtmL>wgNW5Ed&wJSaC6;32O4Ih-9shdroW$uXLYoXfwDz1?guUrw@X`R?r<!c zk5nQDkrii7P{1tEpLZ^bNqrFKb*6?})6-nEnfl$-Wxw5#-Yq9*Z*K>1E(up%z1?hj z7|h?2B8Cg)VXq2cwCh4T29xTY*oo0H=d%r~w+W^E=%C3_=SZ{4oe+*YgDsfWrCwT~ z&N_Vn6&|pe{_)2C0Q5v{IESD&=zTLX4QuLHUvQR$MMp<px-s}^c7~3Xm!PKSB0+aw z)t(SLxq+;!-PTysm)K(sP?*dNC_jXgnfb)IE&hsgT}nW%41}6%5c5$8>vky}>g`VX zje$Rdcv`Ay0j|M;^tM&Ek>OvyXb(W#S}uM=vr)T!tX*$Cdlj4tu!v4VW5BRg>|A#I zN`jLUo%?I-)a7$tb1ub&H{!qA8t9+v>l;=BH=K#VWQ$0M8_92^B(;sNyoKs)f?`q@ z`>pL1AHS58Rp4^w6gz9O_?;^98riSWR;kWOS!fZC#0++UkJ;4PUWNCZfE#AT?xKi5 z-|N{kzZ;aB#jhbEEJTmxtkSxS$j5e8qz6NLYAV6gOc&4i)Ld6i1jhjKT0_WEU!Pe; zU@pVg>e8x6X`x!@p69=+M^#6&^ZIlwEEa;~4K4i_MIfKo*Oymwj*DdRxvrf6hz=pj zmh6@R`^*PXae86c$|?wyMbo!|6kWamo+P$|<XaBg)IfJ1r{j`ba*`&^&aXmUil+bo zc@!=N@FHLw4#f1VHfEIh3CtY>tu61gH4pgVWJOqdF+O|qfAfb{J)6wJp$Nf-0v>C3 z-pi2;Yf{dusvDhFxl?ht4qp^DTc)<@6C7ZnFZJTLo6p+Yj9GI<EwTEA0ImRsFgD-v z-nsD3u&iQUtE&3m!G;l|;=7`}^oxK=tWo3vM-%lx4@u3G5I`S;4|+eP(rD4Umd_4s z(VsvK4Tk{&rCBZzJyh5S4g^QEl<_&6DyOxee|K|IEQzbUI!fEk&><W#QxQV}s<9B` zBg>i{V4370CABrpM5cN}cXwimQ(->(={!XFRoG*VBO(-RwkUb@uo8D`e@lF$2-%*g z6;zwynX7SA0<vXQu)C<QqFYQjmje(%Bq#xUplb6=eM)*=(t0<SkhqGH%Kp>*6X~tP zSeAJ`anM8Wh6Mfs^aC)7St(C<PL(M@dwls9Le%x~Sez|`G~whz{ocLc&yHAXD4&6V zg4r5^Y(c$)1y5+*lDgRA6x=_i=E<Y<fYj6QfINwojwz?{nf}eqQczbXXQme6eIrIQ zEN@FpW_ET>w|t;@u;AGJPMcamCFChSYe|><^XKpwy+Zm)`Sg$nF|`Vtwc|Hcf0Nh( zZgxxI-}EVBz*q0TjePa>9i^+&4kJvp>FBYN5Sato-^C{;v#^)ER(I<JvP_Ov^8con z4h`L*RlDX=%XC|&CaS2j5y9hqOT#SQm+i)8VtqC;A{WvM@;27?NE@msH(m$p5IGf< zKys+sL*NCsj_%2jAqUi;?tIB!Rm%_KG2%G1_mZib5B;@zTSr@exX;V{!2mK4A<eIU z@|}25N^u?4?Y!S@7xbMl^>i27^bgPS8%#eKzxv#vH!K>5I~ma|Gro7%60yQ~(tLhQ zc2HG_eOo55`<HMyZCcQ5ELq?_8)Y7-c6|-tb-8@S%6Vj@cFkiK1W+E$r)?@iQziN_ z0y<w31+f}oiG?1Jst-93rglc^mO4^3<}bk#L*3bu?oX8b3?zBf*i5N+XcfR|%NI>} z`mOJGof>a6*DY^LO!6Pcpli~|=s|Yf;n7&HyZ&WCR5Ru2=6pDl-P~p~fI5ma2RYZ; zMC*;pf0zXRYk(BhiEj9PGuROyMZrR23M7IxJ0MK?Q7Q<YvkX}k+q(Xf2mG7!PElLN zj_u9OcOI=W0mS?{yJtX#$DDOAwYj_FGaBzwGp#b&eCPP=FE!To&E2P_$&RxVLrenp zACV5N9I>G3?7nXzD0a09M<CBB0K}JN^VOHW5(=oRp9=WZW(vmo4IVTCId-zhK)oX( z1bT(ch+leI=5J8aU0T#W;}h|G8Up?0@y_ptH~V*#Jb>ka$?IYT&MHOFR*uMK1x&L= zVz*;>aq!|otO;;YSvVl-sv`NZxi%)kFJ9mk`tI*}>^Fs)vr6Hr+sCvDs`mhV_|c=J ztYBk!N*E~@yn9>vf~b9!eBf>fd&FarW#STFaCE1&*1?ZP6iT|!o&A2|&PdT3i?FkP zNPMTm;6?Z3OuN8dkq^9T3(!@;BWEwf_~wn*5tK3!%cnr2?V3MM?eEBHl*jT43P`o- z%(<toaWaG@n=K<D;+G4%TRqeA9-KXn0bTl*i+{brqk9@Aa&KqfFW>Z6r$ZidKutP8 z8~Ax)a0q=Xtv3Bk_-;)z-R6rp+>6&-6v_p@)Ur+Kq(7hfqwEKu>Os{3vZZ<sy3s2; zD#pWLaWSMh&+cZ7JcAu<O61d#lFXp;=g&+=Tu}w|#@5Zb?66CYu6ZgX+P%Cv8aI=m zHuZGii<eJDzMl7Z6-(iv{Cv5-c(@OUW+XpS#zEKq`V|%Ijc>;)_0u)4*M#%ax5AL* zPi!Zwxg-*sl#`Y-OegcwJE~*C*=#@~?KiFopq1BAT}Y=~_Jl6i55_KdlA>p$W1;HR z!&JH{oeGsHC2&g*Lg~hKm;`@Nq3~{nSGvgfj`>XfWl6!sJMHc5ZSEq)t3&;d=Rq9o z<fnfO#qSqz{sOymr6M(y>}M9p)qm;JDsYkxkp`n#F$6_*<};&8!E%e@j(1qe%j?=R zt-Ti$>uRC3U@xhZl9I%z&Zm5WB#Zlvk*r08S%2B+N|17dZ^EoYzU3oJing>9NMGxU zp@ykVdcOL)^cqbvjQWJuNag;Gv=X6eO8Gaaxp%cumelVosf57!*Xx<s9Co8C*Tu^Y z#g7}PP_j@b$B^@ApB~u4q69^fUJ<&Y=h^Xzdp<6HGxR^yUx^NJz}dWp5k-IL-1A;1 zjahTb#^Rq@0BG_!MWiSU(f_`~*(*Dy<Rb{(m(m1p9n<W?uelAXfye(=$q|Ou)-f@u zJJtkY@5|U1fW?z;q8-~t(E9b+32v6+r&l5GFNu!xzhD9mAJ~Wm%`%H_&--RnoZ86_ zK~)Hm$xZeFkUsa*%3FmeS*FWngn!veXn8y_VEF_mqAibMEjA=@gR{~d#sj?Xt*iK+ zV$k&dfDjV=bzxva&4IJ7YB>^;{g+R8QVI<@O*~mH(sx*S>C;%?I)=xHX(NtO_11jC zhHEAy^0RHE3MihtsZzTVcx`zZH{0f_7vCMA^g>pZ7v*ZOSIO5WtpZaRwd0v(tA@n= zqocbVT1{HpT}tIlQnVKu4;Y2I9`QRm?dt@wr|I8^u9j6>hJ)VmXljNK#nygOXX97K zGy3?E(Ynvdnkfz`iV1?vFO7qMUZ<MFs>fTvrx^7PmZ;c1-l65qT$w6{-_L+0<nze> z+4GuOPOzP-1-9P6Yzs|JZZUav31X@!XKYql$PWq{Y2z&@{C7HQ-E?ZA-%ZntiYzR& zl4?R>DHKfXLcEEZSOhhDz>2eNGm)2-II+B4gNj6FQ?06omqTI6#V^_73%k!7_5N&Y z8rd^k2^6K<<*Rl#4myIqAc2Nk5q7SS=7~a+dlWmOHm*hy0IhEA?u4Gxh|@$lhVsHX zB!3>|2OW0L`=tcxvJ5NHNQ4UF+)fVsgzU|T)lZ1bP?3F!0Z18&2#zwxhjE__c4nLA zOZeTN33RWlFd+>xMow1eQ52oLbA8V3`UKm+te)MWwL>b$?EEsH#19aW!3jyE*=ONt zm1({UHt2;jeonW<lIC6}k{MR#UTs-g376me3C2O*t9c|cgr}cNh=X>x!5peNvASm4 zF}C^A!s}9tI6*QNAw3wA^$CV{$ea~^>V<E;jJmOv-{{a}_5<~W*J-0)+{gJWC6Jo@ zZVPXl<m0KZc5cb4L=xZ*2!4RW8r47q>Gs#0UsmkI)m$c}_BxGsa#>L3ek4iGhY=L3 zC_I7S_<K=5oqhBx<N2B9hESpGB7kYYa$VfF>;V^^3R?yKL~-rDEOS>zMoJ>{(K0+c zMO$ewjh;}7p0x09CrzUVUusdb%UK@_OL<<P%r`y3wxX1-<*roAkMo$41U)S-Xy|H7 zfxgDu04LefGL)rQ4uqO%-@O<U9||AsRVnNI`LrA4`$g3xBxrD?Jy+t=o9WsFUAi@; z`$|RY{DXfXD_EbcCzW`2%mv|4_qUWt0d2El9A-n2wmXD{6GNp&=TnEELee2+`td$3 zT_200bA6t960^cOstEa8qPx1wH1*G(d~Ebu^O`<i_Zp>=o|jdWgvV`|K4qThXgum1 z>YWlvb-!C7xe_=u+C}J1qjb2FhW_G}bC?aVArs5)u!OPPOQO84^ePHAjH4c>R~Oqw zIYX`~jM7TA;O7*=9JWCkXKNsJW4**&p?<0kbj0S{vP&d*W5tHTzvFC6peroK3%-m3 z@ZQ!RM=_KSM#17HPRG^t<*?ue-Szm;yT$UL`r87;lSx3|@K!YdT_^ouDFqnn&q3?U z`kvr)?z2A#CNf8j#P&$|W0rsmWVWrYc&e%f?%K3)SW_Lt=wstOj>ox41qG)@c2rd; z-FWi=c3{Crlr;U5P6Z_umHBjoab>w+pCce9z$&VBra_<n{x|b)v0H`f<X0<=fxAo7 zRfKh4uxC>YWPEfDzhc@MW7-DjvC5w6BMNEUP+5$53t8*;(#=xKGtN<7-?~CInr!+h zwC@8q;P6|(mg->_(KfZj$DkU7@HtIH5s$YfSqADiw3m;{T6x#!Qk`D<?~GNlC4l2W z9U6>cp{kga-#MCoR7G&}YF~EAG_l~DZaW|!20XzPyce}K%&k}Y&!rPY8&IHFl5K1A zJ(X3)T5y!VN>Pk14^xgW-=H73`W^gb&%s=e!I`^fd?_jZt-~d-NvB{hQ3VpdQ<zcC z`fzDHTs(xz*xT=ZW6$b#OGWW40EhD%sH`XrwsF&NxdKzPjyzhP;M#oZD)Fa<o7H%W zM6Q%?5yC}P&OM*66$Xecp4fs54hZ2n<5Uq?30CZ)95s)=<8%DRyqa7z>HZJ?;RnLW zaTPn+RAKM|DAxHE<v!?_d)||GXeik2-Xy0%lL^9})w)$Kn?q@^0~VAt>K&3??5!hF z_0!`<QD7#XT2-KzBl9(yuZ=geG=0teeEEQ!t)x=P2?bl835P<|?_E@i?!zYb+crl} z;Z+MQH8In#;U$P^BzY6}%0=c0)3Xj%&8!>+m^@M@D!fGI1T?UB+z;L&IR3pol0$B* zt<R|Q<_(kV{`FFMEZfeV@JW+z874KK^u?cwL7lz3#8O01BZj51F>zJ_QkO9<N=o}j z+4epy{g)rI_RP#NlU^h-_`~|y$l$?!LlXFKzt1j<Cr|i2DyY=DpAX;vm%F(5Ol*XY z-%qa|Ze?T>TJaGe8pay0|DspDH>a$kzzRSfQ`9muiaSta;s2C3##Ut06qwdz;-1)} zsOfX81gVb|B1T=+6wxb0qmcQv<r6ak&Pi5J^sz#OLZ@0w2IiQaA7-A&)qc3Mkwy-s z{z_@xdTvP1%Qhw0n7FoU;<frNy1~24d<I?*QO$1!Pcy=HICFX$WQ@Ov5WVK?&~IT5 z-N+fL7!D$~k*tf!b43w=3k0sDgypSd{;~H6cZoeMo*X3|Eom?T1V~VfT`8WBQ=e*6 zis5_Hj!ue~JRaN2nZ1-uei18p0+`a^;sc}mq!;Y1bvV5}tww6lo&q}9?>J0pfOj!j z-p^v3R>ZqxfW=szm1RP!PPexsV=QdFlwMO1{H^9q+>tBWZs_8HR1UlS4(p)k+s5a= zjl|-XGUx(Hnn~~fP@In|K0CQ^BX&K^Xa(*`|3B>r{7YpFfHok;^>{B4zJchfp8rF1 z;sdwwch-kLME42oyu-uvlKB6WWcXi&j>u|*W?d6Ag%gYk%PDZ_GzW~D_Gn54x9v4j z1c-=;sa3QPdp}{GV36Vj%wjsay=tuHYV%nUb#?U|Ixzl>XR`zddNmb=Qy`)RJ%L_G zrRj$K%6j1)?DGn<VF8DpXu8=C;2%lJqQ#n8i#r%5gQ>M%5MKQH{J9#Cbj1K0=fhnH z!0<OYF_G;aV=3d{OsB?9O(Em6yH=W$?t`Q=C<(wbb<X?x`U2PGiW;yonGdJc3Y3An zoC-^$;&j2Y4`42A^v*#lsjKdZ+EP!HsiF`ZGO|Roqx2B8SipHxqJBLwaSSs{xi7^B z5057bh+|=ga1S}ufyB3Fm{`~#Hu#E0f@v0*fNyt-&yI;_9d<*4!*EavwN7GiW22%@ zu5h$Nao?~393!z`;j9B$cE&peKaD!O%|o;+L2z-X?RlapE}mDjbKtpr!q6=B;RB|l zbOJZlix)3&aH<{dVAc{OGDo6lAdixgG~%$<!@q!UslkF&RMgt>7Xx1}k)OSgvS>EH z56rO_m|wv?#0s^wiC`i@_8tcdE0F_#Y-nL&ps3ZdnLaA)CB7>KJ3HWL3QJ2%^WK7N z;_dB&ZxW2%?VWvS^R=6syb}v*YH&B$jF(HT@3hO_;W~YMZ8Fw9+&89xts*1yIhK%c zpPG&pRV&z2wa$1&O|?7YJ%-+z3<hl<ok72w{9F>#3UaXn!K*NTWCD_488x*!kM=G; zPwmuWJ3XvwBCGAwz$L*_d`!FNFwH>F2Sn3;nkso9x7$l%Xt=S8v)cP5tzNtOwM2|G zF5kp1y!s{hn!-0iW?T!T5|D6NES71&l~${0atJQRdOx0JR8$mkgX7|paQ>;lz?%7L zNXpd-j>pw_^$JD9U+i&C%L$GPro%lu@s>>oBZY?DnM1)i4B*M(;G%H_H}|0WAnIG> z!84fL{5kaUvK|T+`3{760r6KI`U^Ss+wR>LoP{b!H>)_>NoVH?z^R*+l|{9R{3Tm- zu&HJ!f#V=(I7I-JS7&)OvEIS)VEUrien%(O+Rg@JrTEIU(C}n}$m8@q<cSYN?WRSB z6_V`-9IaDT?ms{C3r-d;=4d<x%F=x8#h$r24X2lzVr1mxT_7ED>;-Bo$LAIS`IJKb ze#TvW)dxU?yfVK(S9|j5_jHOaL-Xl!uDsXserGr;LvhveIcO1iB(M{q>;w>P^rCNV z&gx9=^E}=Ou`Wf>O1HM+cwXM)tBAicayi>~yy_WOqJuQoY$Vnmpx|*Ijw@$<a&7OD z9M$r)?OjJ6A_)k4$+P5HBbzSb<z>iwdAQ<pbHQp?;%Po(=gbw}?Ro$(N^57oeiA8U zobTV*F2vOvoIy!raBF8v6a0i>g&uL+8wa%iu8xj|+vDI9kK5-CS@%%>w3=0JUGczs z_)JlqtvKL`$ohgeG7^1xGR{3~iYH&J;mnQ0_H6d#xanlX?tNqZ$5^jBc<PeWM$K#~ zf;9%OxBL5{Yl0KNYI{9o^=74?Jx^0oQAXtzLVrR+g8R+$kLkKUpO>W%iO?wB-%tKf zL@;cfvj>*yW+liI?WC}<3--nP&n@`umUXptb_e^_z+5g<Iz2rNCd|*DBQI42fBovk zgCat%GCAXPb-FiN4=NT3%iGH~eTxvk_ZWW?v9Y4)(r4SMfxP7Ixno^j<WyAeQ3(UH z0YXiT23J7HTBh1Ub4vJkA(!j<+;<%9&o%<DVD1Nb?^HCGQS}brxr18l^8R-!hSS~g zgM~&{e-V+W`fr_9z^McB6KkXPcJ`uSFM^QY-oQNHB?8U|OzH6F2wDw@8$QItDG4RW zvxA^Q@;-9}gF;FGR})ymLjY)P+w<1f+o{gx%p`uI&`<Og9UZ|rn_0@{Z@0NdTYLm@ z2Tba6=aY2=0}9-(^?q&C7dBeT)omi<O^woacC2PLh6B*4-0@B|_;@d1v>Tibv|vKy zmZ=Uy9k%A)&skYpd+ocuN}AK~Scn$;S4SZB;@jixnxqrik)F;yM0xw;Gb$?jh`qKI ze+V%A#L$WTV5x5_hD{}PJwXi6gKA(tvOZ#LjE(0*#dr?1t5GKDI+;#+rsuC-P9%P+ z-Rb#U72a42Q%R=oRa9~<p5ykuzf6l~+5+6J9zy2p;hk%p(=Je1jhB~}mkX?x%`acO zUPPnFYMuD*g8NOXgq)L-54(H2LaypgPSA6S`uY&<#;>jc5xd#Wi@nKCO9EC>4g($V zE1>BHuS2as?`krgCft%cYB&fZ>AHvIYqv9jmBfV`r^n0n5SdR4-`*nD|Mv>oKyvO} z_Hkjv9w3?*F7<wbKR^oBJX2HCxKuc(+og6<SmYNeg_(uaeqa3hP?<vUl?y(Ii{%`a zwce49g?QiIMn<9!bK6qT7x6=>Gij)+AF2PvHZhScl^DIZKUY~V>d5D`6aHk{#NzUD zo4U~4J3z|KvIwDX=Lf~>*Pv0?tKnpvYkU^Pd-{8QeS5qLIUydDm~enq+q(i?(vBJF z6d9XAEj&J+-RiI;g47?hlU@zg+f2)=Os!26s_RtCi!Mfa-sa|~bD6Bd9nr205(Rer zn=e)f!=(9RgGq`_!)&E`wa2%bdgtB=6y9rSd_jMtnJRZt4Gq8bsS4-bdni~x1W1Ib ziHVwn!&f&18MQ-ri@65j95+6Tdv8CG7hwYZBpsLz6bAl^R<9cUo%1Gl*Zkn=M%U`u zhzJTPn2$H>h3eWKXUKEvKvlX}4QXlYv7~>c`z`weGJI`@)u(y~bKOs$^7{OS3RLAm z%;AlvVnaksTvVmmm1TGc_-T#O1w|=~y*lLOHiyGm%VufNniP0BXdo&36a?yhV3ASp z+*1Ty4+yv%TazfhJa}D6@`r*^^#r0`omja%-ewQ`Qe1|1Xk#<rvg&nQoov{i9BU*b z#xUGG^J*fPX@2W0m+S$xySHa<R^WMiubyi2Ypf$^<pu?JE=w}s5AhztIR)-W&W>q{ z&+r*>KOq`Ky$;5ixZP%SZ|xY*E!UQllPg}}(aFvwSzi`L%x>nufFa%t1MA_FS}6GA z<yD;PbE4hNA;#Bl?Dy+!IV&z?-<E1}6<_dO&i<g&kn*_jg`mB?@wl<yN^o5FI6X47 zl0V;?H{F>Cr7j;X)=rk@gDn4UZHIz6<+5eV(c(e0){hkbow_qp2-Z^anc3N^ODC`q zxZ=L0eqv?-);*DFgmE-nr-@=y<;O_Ej}-e2i?YVTsKd*{o#C69PCoV{tDkHy4MB+z zcK}O?2L}_A>@@`qEy|aWkg^;@Vo2QUh?<^GY2-K7jPp$d9CnvEG&(rCpL7AZIVy&R z3TjXdIKgz;*_|nHc6EldB;(m+FBUYw$Jl(gPIKjmG>%4q0i=-y{zQroepJ|lMs+_Y z7dsmpn_HJt4*O%=KC{PV%R~ggP**CrTX&$PWu&BvTvuQhrAGh+{MJgH5Og2c!rpUo zapiu%?!ro~ddoRBM)%Blb)lwIASF|u=T^~r;wO=N39t(N2+aQB$&De!&coA4k(bai zkXTO<LL{;F5co9e(RG-`!^c0EZ(Nb}pxZAUO7Yq|povD5CUhcR$yaA7qMGL5I2dqN zcWN7BDq=C{qkR0-UL0Tky&oT>37a;55V@cp&k6pw5*X>L${Novw}GVUO3yOBBS6^1 zF`haWA{VgfX2Sow8iQx%8WqF-VT8(L5&=FQd>FjoWD=?7<DwHTDlC7b@Pp8!m5-IF zULpL))Rlw9e0Rp%8HiZQkV{T-<EhqVk`G$dyo;0ideZC~5#1a5{((MfW~;Na6I+%E zs{SBe96M&}#vFxD+e2xFhU|z0ssDwf^#%F$0V13P_1CE+BeFLqyAy?lnO}QCa%zNR z(;!8tt>erL)V#0j`{wEgTgbZvwnL$Q7L(8QjvJ3a{05Xbmw!dz+zxgc#=Ot4H=l8; zJ}>!>;2hNYgjkv73pBsUpYp`^py)EafX~x*+mF!9Wu{A$t<wUq2C44%kzaM)=%`t& zv_^70apIQ)Nnr(%=V_Tq(&Z7!9C%4xIhClMNyyU^%zI82IjS$&y)&3?CBT2LU+r91 zA}CGSJQ8xq6E97!7o%Ep^?diErBE2n!#Be^WCl&&|CQ4=vqm4HQzVk9IvI8V7s7n7 zGtphGd0JFXQH-c0t1Q7&S5X>)koinNl|LzUF!srL<YhTNR2%wBPPLAJgb&PnZ}PGW z$yn?T&>;9qg7I-%Vmo5x?QL@I{vq3+j$SdGC)QVraYXL()JQ}{Qv@Bqej$$Zfo#jr zBKDks(J19tyL$O4?%SR>#8!(-WspVTmf8Xlo`9-K%rX)NXy0tsii#ct<e;kaxFKcC zciDsEJENT<d2Ztk^*S4J1TbH1SjN3*4pSgl!KsDYIXy{95vk!$q$7FKgE6~#H%u#K zWv)y7_m1W+XQvfZp)6R-Ctt)7gUj}#CQ2jMGrr^1;cgMjX+>BUw-OYV6<hE)akPzQ zWpa!^_=Arzhh(_*$;in%$;}qgWlH74Gvz7r#TcVz>^AkP?I&de!<hOB#a;z<wDh#5 z3EYlVmZBDAu3~MG=_5p2tYdj+d@W4WF_M!)>-Z-0^lmIC&c|<E{M{CMCbA^iH98Ls zN|*>ar{bb;^jKH5h44%HjdQ3(wC~QOR6O+Uo@e7<;QXdLmGC;f5x`T9_3t|iQncs_ zUnuxRsUy@}D=LblIN<e#b9HWX{i5&O&8+!@N^7-b#k(3uXeb!4YtK%x5ng9yVc|u@ zs?DmrfA&~fAbZRb6H7mnd=o4LR{X^hY$b$^D0ohg58@P1RouwqrHsJ+fiLd+)9-6i zM1&Td88at3)a1Y&Y@K4hJ=wa2X4mC(H^-TH`RenSXap2X5m6JPSA}de`ucuXk^cT$ zsi{Fl9#&m=DzR|ZM@-J>u+r_{XG<eV1Yt?vV$sOCyJbGSZNg{Lre_^E?ae<(tQ_bm zG@M1@xSp+^owj``todwvq2Y3R#1h1b_d`wvue_k()tUu%6(WmV8MHhNX>M+%U-*y6 zP<aVkjOE}D__6QDHDO3n3u;OVe)Lgl3W)CCZttg2GNm%ps74rGKzFTe;i{-^Xa3Au zg~w9L$@kJ3o~B+j8)d32M;-YjM~%cM46i%@`%~F$3l||%_zLUSTIOPJG5sQf*y)Ev zwbR`#-6*>yJw4uY$^UClVdZC)Mbg74A}qv!?F9iwz`(-RlP5P8>o|Jw2Ij6c+cE2N zaB#nDwl@uRvvfx|uYXVf)tl7#q9rMVqSn!VW4+ujQ*O2@aVdPn+GzgumN%rxT?}?T zf54(^yQolCZ@imvw|kw=5b4ZJ&0%Z2<AeT(H3_&L?`#s+CmZ|gIBWX)i1+y`XMH?% zNM>te(_AdCeh-b`-jWdHKj$$EvFeZB;~Dhboqib^qxs7E5YHrs(@_Lj&Cwcxv)nPp z)4?JlNWPdC3t?#P*Xa4BU+9it$o7x-)CETRKh%QkKD?~I?6QPMs?(XSO|9jZb%-de z%+2i(;bV|BF>dMn<EagxIB9RmjBBmGJ*eDU?B%ECre=JuS&tik!mgPCG_7sqYn#7* z+QCPy{-?%5y8hUlF#d(Vo9Wkwn4N<Yxd*Pw&#_v+<Z?MHV}mb;LQG~;dG3Ns)~V}% zEUyJedbHAyv!6lILEpbC3);~CFKJvGyuBkM%OWF3mLo@wk8QlTg}|IfT3NLEcn}05 z9^-np{Ck}k8FDj?w3|>lzTk&uDqM^VNWD~5@u2nn3TWwn^)eJFPb#RZOFaI17Ad+; zc^z2*<m9oHch60Fr|^Wz_%ok7RTXf<p-0N^#Ko8Xqj3$Spv+E~bK}C7@ESt`h`hv5 zMH3f;PPVhhcM@$nol)RsVR;23MxcMn(8vf&@4@0@V*j`=t<(v<(H>+IvDdS<F3KJU zXWZprigt{EU~g~#;BkeymLni|@4=t?r_u1>aee<jS4dq~7b^nxnTm!S^}}PlIxVDo z1l{}X9pMwqkMNHlEBL?1p?m)l3R~V9e)nYLu^Yl&Z<OWR)7yLXx=$4PS+{g42Kc>$ z^sJ;0b(8->LiVr0-aq5R7F)_BdLU^;t~b-sSx9wvrJ<>8)=G$rvcJ6ysu-(KDpaci z)nZXmVOd`dgz<?9@TT&6JYLEDIytXB1T6++Le6CX$M`ItU4MNB2b%QEKv!{odBorb zis$e_LE3ItXO}_WBqXq!8||2Xk9EuHt~Xsg{`FCh!#BjaUsGf^T(k!C#@v<JbRH+K z-yOC)E;ezT&_PrGOn{6&CD2T4k*DCjTTLgJt=2O%90b)^UI8hof$U`Wqml18Kw#&a zEw0d)2rd*ZmQ5|CJ#X4IT~QR#Y&(;824J=8FdfeF4?Lq$fTtCbmf76vklpVFIUdJf zW+Q=ATvqQU%;j1(kUo6u88F<+%f_G&ZDC;nb$x;12t2DBLqi_D6XpoRA05;{9Tk66 zYjkoFhq_sf!|+_)^j=L}LxVQ>VXOvbL*M{43#jgh(qTZj3c@itjgIl1CruBbJ40{p zqip8&#*n^x`1e}oYScs~+e;2Cw^cO+p6pCu1O|*2s@E3uf1oBNeYUTY03>0qTAJZ1 zoLrI{oD+&s_rPgMUw>`B-toqh73Bgza7s#gm-mk_DALo?wSO?HI?eo#Jp-VBq?!6< zAuI%=3HQKJ?`04Z`ykQ{qLC??MOyV#B7rpoAgnAr*F=C-4m3OfHi?FY_h=UsLLQ8A z0@*({CZ-4!<DnFO8=Ep4Rse3fT8zsDGdhrr-u&&;zJG_p`vbD#C_S$Oiw0HwLm|%* zWSRmAeQVxwc^nSJ_b{CtA6w3SIW(RW;bkOevslYR-Y*(J52}jK{}$U;iN6GHNhBqu z15|uv>DcHOY9oAPj`ICp2YgMy<#SO1N}|If9!=Lr+=JzMExPpDMK238^P1pkrW~EQ zx#BRhxE+@M*+01eadEweY7-31wb~4p$<~TAA1FfGrHh36W+RiydhmN~Ev}`AKUz>R zg(7Lm_AS~PgqxednZUpxYw8SK7Y-7T$=dZLb^#xnrY60wFTW<o)NIg;(t-lBxy{sd z`+lHR85sEWt7ic1VZWXB1w7EI|7ER!Ockz=@v^+!^fyrRekG^}S2@`C4Y;1**!fU* zCuKYgISj+VN&ZXUmW%rOy5EYFl=Powfw!YHc4S=C*-aj@(iv@8S$QX_bXXU=g~&UO z>Dg(LeuJca<)ZlpEVO6DuSGt)=UZg<c|T=gWu&E{1LCc}|5*P|N(G?5V%h&A^*CM{ z!VPtE<~!lFX8doiQ!JOO9|9Gm_fIsr9K+eUGP4ao#IYLe<`A1sSYin#B)&X3M*NzH zWVXEIKMz2zZNZLQ%rlKgP)8YsXASNZ-Vck60JpN>Iv7|0rp9@1<k}QHa25PlT>_)@ z|GG-BzcOzz(Z{ausabDVq+CqM2IBm1(mpyqHv}kf4RW<j`1B3>G!sH1o!z3Jr?&u? zTe^AR*ehHdP~K}e*}V@rZHt!oxW#B3**5^q)|t)vXAy`gLAl@k2m7h*nV<Fl+$3P6 z4Vpz2Jn^`604*Ct1VmC2i{_hw-BdvsL<sLpl?m@oXfCj#O*cXq8=UrLEAg01!rXix zF5oMTsob5y5JCufty&pqzzri9*?_P?=+__&Iu!vBvI~FppZ%s^CB$-_SF^<&9HcBP zz7`gmS29`7HEeA!AEVrC5h^o*M6u`fc-X<9^JsUs%;Vbk4c6!K<f^>|OmQ#s-+w@H zbX<yi{faTixtv@<>fs`X@7D=c(mm;akcs*(Z{c+<6uC45)ex!xA;W)LjDK{9R#x`* zT(%R0K_keh$0whVgWvN1mjV7yl>wUWb%sG^y>k!v0dTb96y@Yd_KRjK+#x!U@(qT8 z8)s+9Na{b9l0%Kd&T7Q3unDqo8rQSi=|836!{Wo5Z;!ePXUpb+W|P~mKIr}OzAQvO z*_}t5*Jd~Ia#7iG%Jt9)%NV$9J-IB8=E9nIojJvFo=0800sayoLK#a$$4N#7E5{hp zRrmOMgF{Z=9<WzZkY~cZI3B5(c6Pox#vj+pQ8Q>d3Azk?LtQPpbdwyNgwjODZH{^E zI}=3+%G^+3-!z9`Kj-$=M!VJl96oj*)@*tgXGiv!9~6K`2xKNoOSK<?hL0|u9V-du zVHF7;t=y^Z0Nhhc;m$d#g4<Su&AioBg#dqtadMlzF1lQW>pNv4hpkQ0u`d?}((Ej6 z6df^pj<?%iDg}!~<iniV9(bi6tI20<&+&>79tnh%Qr^GLaU~%^aBt%~j|B>8c~;w5 zXBSr9^Pz34I|Ctk6!ySuw!$B}2~y%x=Bpo*6C%F|dKoe#aNuZ6_Suac@{@Pj`-=ZB z;@&bUj;~$wPC^0!0)*fm0>NE_2M;cd1P|^K+=(E8AR$0-_XdJH4Z+>rgEwxC+id>N zbI#11H6Pw}X4ZN?LDSuISM933tM2={t{>-kH$)T=6^piYFiGZkIXOwBo*=SHrV%>} zwLbMcMhS8C6o7;RRP;4oG;}q=L5canrFY$bhI%KTAx^NT$7``M$^O%vaOenTv8mbV z9&>J9UJ&+L4j3_@M!w8MK-;;z{G!h~-LdLl*bGKF^c~=2wEIuM2O6)}(U_Jr$`x>A z8j8&oNE2A#J_gGD6d^ZkbG+DS0IS;jJBt7L5LKqGuC8YBOG^t7bxTTh@|;){mOW6< z33gN-KxOi_)v2B;zxxK3?LzNWQM5N(ljD=E^CxERCdGSt&)pdXN4iT5;W5@-I_JA| z0Dz5Bx{t0?wI3D|+&(UiK|*(j)6T~CckALw0GJ$!riyb@e*bnfgTh#K<r)YC3C2Q_ zy)b`8|2jo%&&`b*?{?S%_^8+_h#I`tbEK=fq9kF8C3Kl|V(zYvs)QGEY&6HRqzX`c z!EMm4hL7aK#LO}>i~)Jf#LP6a1uk;}h${G4qq?%t-{Av?QJ(?IBW4Xh5JT`g;FiqS zyW&E{Yo*k^WbxWncWW6!mMMXWCB2M{-}6;d+JlI~#+bFbu-SA$WGp!Ix-4G-+g}&N zAqQu{(5nn?IU8w?AM8(KvsQ5{YJkb(+h_II@}5Lht@xPKZ^~bVMVVkXLE)8l)1)6A zWUaI>ck>8I0l36r=iG9&D$-ay;1YCw?;a#*rRXLBD-HoQHI1<V2ZLGHCt<>;rD3K0 z&5fU@0@~+-Bb45GA6L>pXY^Aapc-EDx!wIzWvktna)?$pb|G?SWvJq&e5X%H2ms(4 z>pRqPi(OsMg;@C&(#r@I>YON|M{|nm+5adJ^JYZZ*Hhp#Nv3|!l#W0#G2i%R-mLkJ zv1j8Lcw$n0I2WgCFw2I2+xB{($BO=HZhb0QX4pIMt6!+UPacph9<7~i$>C7m;<MgS z-RK9l^r!GUk$)s5+esS%;plkc*pKe6t#LY12xvk{f$I1dnHT%Jr!lWs(?>p@Ztq)z za`vLTDaQy_BW{lFCx%hAcpSK-yBKrdHp4T=GLq|iP{U%4Vlqf$1!wWg1Awpfsz(ME zwtH@C{StQMbA6-hm4}}(h~E#o-(>&&!Is688eJ6T0`tTt3{9-57uC<}ldn9hJo|$^ z{Q3LFmlx!GHh+OECAR2&RMO9h(yzS8_SE6D;ZNUruWg+GAQhR2Ct(V!f3Y_|TBQ2A zAl&<DMGJt;1U}m-_qvM&EZsH8r<`lo1y(|cf#2E_K;WK>1=k9K$-rrlr=85GU~OcV z{*_%3SWkUjdLB<Ll#y%D#^e>Mh`Fe#FpZ}a=;Cs)1nTS8TP7M1ECQ4w0gF~G0N?@= zai-uBJ1ZTXTD-dZ1IpaCQJ|BdRkU24hMlpcoTINuU!*>L_6+Jy2M(#aMAhFS45{xF zE+3a702;V=u8pl-lprU2@d}VT|E+=_yTH(K1*W&7!Hjr!sKbj|e!V7aax$mf&j6P0 z4!o%VO<&EXST9JJ3!G`0L0BV`u|`m0GA|TL<p&1dTqslz>jnTjRkE|g@JAp_;(5go zQpRX>lSJpK{=*nXdk~2GN7kQx52*A3<=}(XV8*|~`g=M)F?<S56k1V#lb)q2<h=X? zciDzS@3bo&iQmOSQ(q(8IR_?)n)ywsegfWx^k|SiceH!59^gdZrGGCTY^I`p{w3XL zE-(ED6VRd?a@V?2>EaX3^CQP$i(iUAy1aDf<8@Sv=MCUuFUju>E-1$d{0;cmJ;8;# zFi|BXw|CjWifR=@(Xqwz7R!5RNPl8v4I&z-@JPrSW{nmWflF6V;38{>7$kicn(I$K z8_dYdd(X$o-M~uZtH(d{UMJlfgutr54<(+V{K(krNgl??QSNhg%T9$1(zae<BFjy` z;KvT=VsL8ox?4gu4s0e1CVqnIb<p+k0+&tOTCTz{sFiaI@J&xYrI7<+f0@Pcb5vBA zk(Je>SwkS#H<o&qKjWGHTWXv%z$l-m(NU#qWqmmm-{0J1@y|r_0_Mo$DxwN(c|A2V zJS@x>GTN5DU&&GE#xY`F8h2qIq@ecdSgwoW(v0M?<7<USIcgeaF-lqMK4Ke~3vjfw zr=>o7E!n3Fwr3PaL00~H_-Ef!9!^NeSAZJC1<LTbt$=)hz0_RbYYGy0j!<GvEAGcD zS1zVqqsQBq8q3I`QVtuaF-Q?LLl2MNg`&Vw(9ym-yQmw~S?6L>_+7LDty^oBh*?{j zf0hZ7Pd+>ahoO%ekaY>H9$dozQ(MhNPyd7npP?;P0<qT|_Eop}l<NCp->3v1_OuHy z1NiF|v2lp{8uF(^#s`QK`VS5FzG`KE-1-bRutsN6{=^X@fUBTOhDzEihTdkea&d0% z*|Ggcf{=;%ej<IfZ`yq`$s~NZczDgl*hF}YkcuNL$>|OnaZ@uZcLNS4X67~w_Xq9c znn%>s)W(H))#*)91v=P;Nyqi5!2+kG{`I?}HTk99-WCe^DdcMOYS{7$94J~yIwZK! z-tun}fWEEGmQ<CegD$O1YCH-0T@tb-6ioo`9m|qdI?x%NvXj)^-yI(vFCBx1cAzY4 z37i1QA)<whMon{o!Cuz%M&&}nYJv98VJ=nVT!V`alvR>un~-Qh;hn6UQf&Xjp^V`d z1x3HWxk(7Dugx;ft5e+#4PSso`$M%B<P5CzY(;K9a34rYbE>ctdH5#~wEYkZ*XBIR zz^5Pt(T<8pH>Rb8ykvb5rTRgmx$i|Ciu89mS+;K>lb>fL1)rS02#|Qmq){|42#nnW zjSF!zEdo@5y@5*aIerXAtPhM${O&o`(AGXZcp)hjh__|9X<q<(>o5R-I^echXr!g3 z)x;-Sk(QFe4}4hq*krnZzn{VJ)j}Buh($DVyxVPPFG>EEgL~HT8{BzHbhe4|QF6z@ zF)4(!ntX+(Z>%gQEmXes^!?#fjk@}ou9uC9g3S4DFz^(k1fz4WH8&rBEs2DXP@a@i z*CQ<9DFflw;AZ*8(pGy3zm2j1yKXI8Bu<>6Nxk}FY#p(>Q^j4r3m-#yh&hTehE3hj zcB<bS>5Iaa3>44bc{T5GUx69%TZ=+|p@>C8kCH^DFi_x2OiWI8GOOuJZp}6(?{vQq z+kLTG_#d@^E|CZ`JAuDDtKWQi03w%DZKtK&6%;2BRfHj9$&a?h3hq_NX~qHS2KA0_ zBt*U|veEKt@_~5rd+N>|=BxwSpO}{{uA;1@?x$kFLKe_-cH8FWYGkx>ko!XnSPFuJ zOAQDNo{^U{zpO^X9tt+zV_~WJ?D0%&wM7z7&O<Rp`1=J{+cfswgE!nSU$Svvz(<jK zP|H0m2m-ha)nAkod(qx{uJLDCjTRazu5OOQ7;h;A9J@M->LuKead!iLD4(}T_#jE5 zyU7@9nv067ndJnYsXsZ{iU)ql;MpQ=cjU*&!PCMXTZNj5ztkl(WM(z`m6ALU48H-* zI7pMwyQPzlVM~%H74Y8M;r-B5C`QVAX7kAJ*Le)eoStYilH5pq+K06W3pJfgtA`8+ zVC63OrfjQ{C!wb?oc3>J^|bIB9|b9c-P?&j;tcnPzKWKgnlN_Qr9a@-feJ~0UM;f7 zOV>yki0zjwB>~iP=~O>fso5&0)CLlepOQjKtdsJg?~jQJLrlmD*LrkGU40!FbU7Nt zf`4GR?$$j1U~zZ|_*E^hSXn6=kwf+Wr-+%AqA9AFm*4t)zis|s!Q#_^oj_<0s5}gf z2i$oEgCT!7H`0u?tF3YzB;{l4U9IkxHWs(H<sxU%QUgYg^!q#sSg%&x{}9Dd04LWk z0}LvpY90`w|3#xck1fxSb?)e%(tR|`Kp5|^0<H@i@W|=Ehi3jeuzl#U1N*n~)qe&k z`m?(vxdVP+cTe?J1w(A8+JnzWfX-g|T#11b(s~7b1S&K@efPDaeI=32^?XoH<39A9 zP~z|}FdS)0n#ANQ5c4`-^l+zoUr-?!ncm}cJc|{vGS$M0aa#GM*Tuu~(V#}e<;Xo| z^Usq|?3=3#IS?K4B_zgYloBrX&dx5S<;smaUnRkj^ZGR9Mp_D!ERE%hx60VHCA61e zrzX#9`6?al&)H<l=*ri@#;<w2>^!~z)|6i7s1f9NL(j~p?)!@P1T{{0yt=FcYX0zy z!u2D1H+??H{--MZS<~5#BmI5&lr-<0nvgsj)O?i){~cK1Pm49@kV8WQ;&tEO&$}-_ zts+H1Mt&8&znKmyUqb@<DfhzV1JoABzrf0Bmv8Uu`?(J#J-jW;q)S9k56`R|Ff3~Q zQuiGEgY9Uh)!DKYWfUq)e;0Fzp1*t%1u^OMw2Ctu=eyWY8IT`8Q)edpbok!1*d&AF z!;fFGCsr@CUbA(7pyp9Iy0o3I#X|c4$YjebQis-)_6mNx?F<}&hC06LzJ1B(2j5Uq zeU;N_xVH{fqcW6(9W_+!H+-+h2`HK}hvq=LtIL&Dd`Ww&r`Bq9TM6%eLH)vUa3Pl3 z{mTj)6h`jb{UT?_Ol(nfC=A{$*aJ*c3xj$M01lEd-u(M>*wH3~!Ah*5g~cb4blEY> zmqdg-xPa)l0DXf_rBI0`&exx?x|%8hE;MS389qsOsO)JK6h7N}RnR6M_T{rE<^*xg zLMVd<K5ffuF5qcQ@3CG|5?);|niZ<czukc-SdFb@(@3Vj2q+{Mbi77PqnB)}QObV! z+?pzurd1T3;eC_896Xk#q>MsM5Q9UxYI!)Qm0~3Zbg958W|&><>2PEIss3@f`P$Oz z;x8JNmjVJCW)iEw&lFN@S;KE_#qGgTOGcELSpX3rJB1&BT%#1)4<46p!T%srfB13U z<;~tVg(z3~{%=C3{u{wnATt64(f^~m=sFI76{+`AS<|F&$tL{sZ7#n4E3)zb3hMg* z0u1}WHp~d5f}3{^=p9i4<)(=DdEUXk*+ns9hOyBYS$|)jE(oOl^5s!_6)5vk1^`>_ z(lAI-_ZUHkbc80x#m3SKvICt7KJ%^QeYNgg(U830^n0DAlT!f@lpa$5oRrhNzpC8& z<#jzOYHf6UeD<D&sG;Fd?eXi^2{NgR8ih$Gr=%YRM4BGZM}si0h>pVQ^)~_n{qDyY z`DzT{pF24bFzGV=)8EhlHI<pl<E`21GZYG6raczzhPGmzYS3V4n{R1pkxMu1?xyFK zXQrZB0gB=^hqy04Fgx7SJF>E}kWmaIkk!a<b|<qzQ|QMoK0aRZ4Taa)!-=-}&WG18 z4fpB2dOMhx7edh8D(!6NwTm*X$chSzioDb%xAVOAg;bQ4Rn$!A!EZ<nB5x9TP1m32 zx11dx9O&+`@ZQ$0HeTGYcH<~%qkBcYSUSw~V`OA3<pn}EAD=~4kDO}_7~;@Sb7^Cr zf}A`)I&SswT*lKgFfx*oSriDc-#ER0|Av`bM5L)tjIKjn11Xam86~LjePe~54y|xg zmOy3MX;yoq&vqv!h{PD>QQrIxlhJuE8CE1#`tf6hf3@%JlP6D}J$UdyEl9`xRj;q^ z&du^`mj#uZ&8fpEk!!Y8vi+^PV(CF)0KME>7>yUh6L6g0-v;LHUQCE)^yf&TSxQqw zOD~`q7rxP*6B3jlP!uvy>$$XAg^T-9*iEzy&#$nDUE9u6SWn#c3>@@VLx8Tj9TS2@ zkbD&MjHJ}|YTzMKP@!&RPK<H=#vrWM-YM2j2-c9|JC&kteTg7@+nW`SMJgyk6%`d_ z**e8ntk*Q$Te}F_KeUPo4bIa_Eh#lm&<S{L7cOHBCS3MrqFnDrvKg@`gpQ7nbA`e} z!b1Q;mc86$BQ!LW_%FwKtifcF{uN_UtSVVp!`+`S{*@g0<inLRyw<>oq?`FO++m68 z1E3$op;63<G>9OVu7_xOg%b%ZT?c%h_d30}>KYbs+f%iczcd3e5wZNvTdr$cl^{G` z*mdV|Kc`>wD_37DQY&-UxOF!ot_u0yp^=WTMEC6p5ZsPgwLKIdMu`OWxcahpb4_F8 zZ6DF7@5PB5I{I;~lUY7AZ|GeJji1dFqH8y$s%m1@o<@Zs<46WXr!nfh`}h%i4J$$# zi~99l%);$l<;Km`-^9t{A&09fz~o6?yEr$D*qaAI+f_E3fF0rPDHQYbC-LF91DavF zp<xxz1Q%`c6~$Z=Gb5GLD*SL);BKyIurg#<#A~mmmXj6~IxHn`ke?BY*cCdciis_^ zQ2Zk0KiB-e-XHf<vEl;w1@vk@EX0>@*e%rg-0dkqAP_e<EQSWXCQli4^?;1o^{{PA zMKq<B04Dvi3YYB(#$R{uS}Q8R_zXX?j6*YSD!wx9`YWn-wl!YAUodGe@!gP2z%}jE zX10-2y##7Es8_G2lq?7x&BG2z4~m#8)^B|4=Ipu$`_P;r6GhV(C(O;w+@CIk?ip%9 z5x+H8fA)7Uc{acJN1)sO$D89pA%Igi0XsL%F^N&hWM-@z*OQJtl#DZhOgtv$;my@> zd`jSE(tMFlY_H~TjZ*)XmW<)dCYGoq*<VhJwsTWhy`(%gPy64>*-e*8I?8gm_^V_Q z4mA}|j^>WpOPb$=lkt~0g%fkDRv}(d;uvR6O})vHt+2I$0uOh3N^?cUodNm@VwzJ@ z^2rucrXABICl61f*S>I=-}RK!NZVm_lEqYae*d5dbFs}5ZYX(;P!ij%_{&5tOF`z( z3_4te`T3&V!N?X6&^I?WHZGU~n49tlCwp1N9kyN8*R;eI6NU6AjTp|GO0Br&Knj_e znMuTMGu<Exa*u*@CvTC09w9ACN=dSVouHhZ;H~~SDM@#>%64pQ%w3RNAn+18#VOP~ z^yei%f6i6_ArWyj1ra$p=ws3}SQ;56MaNN7QVzp(cx5SZpVqnTCZwbscFnJx&ez{u zA`HzlnGI2>sb8ZX71TONtE<P5eaO@ShK$rZL)MIp3`^?SX3a7#)L>C0l%cn}y1Jt| z3R964y^6M^j5_Wn5+)x%mO2oGhK0uc99(`q?1$lkv1C)R3au^=InC-xb!aF|A{BV4 z?im*CFqw6(`o+%;U1NQ6(KlCBW0VFnTG_JT$nlsEY*?P^uJ<6$iD7%&byKw18pSD< zI|%KwnGc|^&ABol5RPRPz~*+Tg!|R~K|@EUuOy5%E8Lr}2OI%G5FB__yO?dB1rbS3 zoNYCj{B33xlK^E<`pN4yU~@`y;-_-=3Ih&@5B(~k%4cyoUbiKPy?yZl&$dZh#ykDF znW?%XDsG~C9z9s-2w51cm2$G?soM;~!Q^sKcXjUX&jF#&*qy4~{`=WyzTPD}F_zWf z<hYev34HJIJeg`e4=QQzljXJEA3vTGpZXpiZH-&QJWsNgKp3>USCff|^Lm||h-p4F zmeX!04mc#t&CN#-7JU2;J+6N-YY#c(hLfcTd;KmfWCCs$^GitX0GH*6#9nHhobBdx zxwMh$&%{}(oK<MyvU<TJ`J4BSPe#&2S<DAgzJL3cwS+^fqz7|NMz$#|0vwYbCQ<Rs zEc-q8&DXmXlOXPTZ?-eODt;-i>~s~XIY_RQ;?DlsAm@kAZA&%><oHN-OFoR53GOFv zvjeCPME66XxT}_8V{40lSK@$}LQP0WXl|ygznvS<cd|9Molh69-xEs8&)tgUW(3eL z)f2~#(A$K)h1^th$c(6zB=#xEV>-V#e0)_F3rY05NmkQP)7SyB_?euHjO&d7+o)Vc z`-KKAHIp$Ah;25QAi6SJZ7uMz<;_Op4F(1VI7@EdYaR`YY;Az>>n)KF2cI7L=piEr zSXQeICcOnrwE;hY-lo!G*t@f;{}~|A(rQMpg2`*Xz|CN5NSAH@%2vQNL=p585=HEP z_ok(<o0&<rOCGQLRy&SsBZCcuQe%_jndjy9j|GCunXR+Zin8dNGdDq1^~{$|e?YUb zZ!Ig=9HfqG>*%OYRcdY<tt@*AoSk_bE~(}MC&Z^eZ><>%I9xc0m7Ee1;=Y9=PJFEG z3|Vyc1emF0S$$vl#WJdCc{$=ee?Ijt7yGKV>j=QmRUxBOSaS~_Ja{|)Dr3c(Q_$z5 z<M9!IVysX+f64qhECLRekhhg|f=fZ4iMFswMC?fK*OZrm$a)@+z%PFv$IyZw59|b$ z#w-4#7Vtdf{!ee-y8rWv2TQ2n(WkFUL@7th`zanj#urRK9ZLHE!kzRFvfHCzoe!$| zlvJ6cMsJmz@NzUzRSgzA4+I(b<oYeI-;&_1>VS6-cIOIm_FA}+a3@_DJzX}KbK0mT z|C^@mlKFI`RS*e1kq@g%^Ny>iQ`2_B{KLwbn-a_neCl7P)<Z-px%<`^3WH#o-mdNy zOVBG`(3g|?@z?269~wY(%)%zjtkh_Fw@_3OSMl~tZqR5%6)o%%>q^<<g-K9@v)|uX z?XD<|iBg-z1*r%r^L9a}W8bKsnlCCzlj`^^)ULPP*35gq`#D^w)QJxY|C06Cr%3i3 zaNe5~6*z7FI7sRezq5)Ul`61IO*y?QZ0V)tk^U3QX){rk__c~Dip+WYQqDszEc%QR zl}`{UcS#7t(O|KD75i789RInhwrErPCp#K6Je#1Gw<oZIL8BKOXi>#U$Ez~d0?vEl zhH^>j6~^Schcf0zqmQ9ER@2zQ9H&BcRl_|Vu1j`~iN3IBvWbTpR*9dJ6&STY+O;HF zS1+_}9G-K?=Ge}-acGK(qJjM+(tLxP6x(gT!qK71axonyH~327Dvq&>t|#m2ocayM zCA7Rlq!&`UBiO-oGQC!RcsIw&xU>27LyVol3D?hVOuy4rg}BdE+0NH;`_IX8*?qXq zJ=on?1&_v@_X>3yBUoAMzD!rlx|IpKZFiFptvns19#tHO=5xFVsGSbT5z<30Fl}t` z?G+mOQ1Vq5;Z)4a!7Qc76)ofEw|fMkNM5k5$iiEVCu};K84zk>KR+mdp<(U{w3{`I z?eNri;Kk53R*4U?^W)-k&S30(Kp4s$x3p_XYFHSOXU<k8o|Nm{YR_N7-Rqy^R*wBN zYlFmfa@wv4{?S!`esNwCWYAEWNj`$};K3ii&sRk6rCQZ;vv$%8GY8NWWpUyd5AsMe zEVe!rs*JZhwk*vL4bOI!`TK*{YP>(sMAypMMpdF`{;R$0dY8iBq++*uPY|uBVnF#} zWud^VL`vPYM0S{y64I%@pq43;5Vvrv=GbVYU;Gcs=WK_l7sUNsvQWOGnVg;lQB<|) zpDVowCeAhqn_Zj~N<XOf7)(|xW3q{e_)NL^;%!pWN|axo%9@OEowF{^Ju^G^kkRrW z_6Vq%pa7%Tq#|Jcfm}&nFQwC=bEBJkZ_NHvws)9$R7~tj3D%twqc@QUU%XPJ2voaW zL_y6A7O=Lbt>OA(Hj}r94Ebct%&1{`e~lBII0qDwCN({B7&2WfwKn{ewaPN$JA+>i z)t%Mi{m)kgiF54g>v@qlAA9rJGH+&;oHONQp`CQh(^A7Su9drOY9kk3-+V$6h?5dN zdD_d8T*<~OM3a)E%1y_kBPthc;JH|lS26c<oF>4em&B@Dy(~a*CZ@q=uhzenfkB(T zn2oX6BwGvh&@#Z3*3SY{RMAr^{Y!WTQxpLOX_UtMF7OTi_+=r_yN=ZQ+64)fKj9#@ z<tL(3d!wY$Hm{>3&T&+(%JC$az<4!=iQi?{X0Fbu2j{Gppo}ifV&=?+Zu4r?dSYUs z^=d?BzYsy1QabwK0<Bs)=gV~2t2sfOidh7kdhD>RvBTyPj!30q&X_GNgmBe$Maz}k zpg$+kw0m4mikYlP$a^65Fk>x`*QsoBSyOd6QiWHezuwE*pd=~ur)afsxYV+5^Ow-6 z0=ghp>G@>QL3=WH`r`Bs$aDII?z~NCmY~q>842E3e55*J9j;M~!v@Dc5dFdCk?2F; zzo+`J0=~v}u&HT#AFmDnBK|;PTX(L`DpbsbgB#9y2Onh~-*PK<{K<i32fpE><lSjL zBp^n*oV6YkgLYy1Ev=*;6%%6_OsAQ0;z;0wNfdee_{#7Dk?qy#%xT}o+l4$29jg1K z=dZyVjen+W;*!DQqsRBd?;-xbP2NcU|IG53|HqmAzdU(9br2mB1yNRhul%x$^*QJ$ z++QO;NTraGk+Gz2RNGAblEie3ZAG3!$MBjaci44kf{vkU_(4Rc@%`(BMFIi>)Zp~= zXR8DzrW;n!{CBdlY}~4?2hoYKO5HLLJxL9z1h8T~IB!r1mJYu)F|~NZ%gf5oA_~!~ zG-J=9SqlCMkut0L{2Tv%sXEAxjEP|%8drQL%S^PMl1fb!KDEHljG_L|mVcKtq+zG8 z%&Uo8`sU<r<h6Z&+4qSxDX>mf)seUryZU}x7+<${x+sDtl(D+Hdk!udc9L`z&zA91 z(9j+W$_%tK+`nfK=SkxAqldZm4wy=69!B6#54N75@jM}I#i^#27?vmgXBpf=N8`Cj z<r2ih!&^#Z16z@{koKYVgjQ8q>VI7<|I04@-&fNAKcA$o?PsRfdjHQE_+Shj*M@Gv zp$@&eHaq+L;>n}?U7Dt!_CfqGa8$1*fR>)#_hAc|R3D5H;M!yfySRho&wuTi0B}R3 zq~oFbBZ~Ps?)v)rKZl4xP12m8s9}0T5>u|%M|33#h{9|3*J1yRbqhFDETIK#q#rSr zfT1p73yLa}e_v4eL%>K$FR3H0E++Qnehgogag4}@97PTv^1++H0q}_x<4N2%xVx$3 z6CxtZz<Od|8Jaa(A-$rk)rz?W@02W%>SUlDGPrX1&(IGl85$b;eojk!tNdP#`Z+E! z+-f{+y$yQ78!9LJ&cZU!Y;ASK)x>OV2pMnbt2_7t2U<U)qqD@YV!TYUvd7e-<01}9 zMFulo()M=!vsD<6eP=Pj>puNA#_iLw{VW~<0fo@Vz4|A;xjxkvfGZ1n%<6sekW}F_ z!=S|mj5IHHid{Vi_)okh4IXZKdec7M^4{xga}yTbIvQ%Oq$P{-;>5jL4>cZ_5rjw5 zFZvl`+Clw{31i`w!%+gWegjuH+;V;N+-Fp=*qpU3o|BdJZt`RnpIPVX?=a5#G0o+3 zH95q$Y_I;fdXp3T#NKC<ue3GgZ3L-0I@F2)i*4XWdWVhdBFdb_q>;{Gna2;)%G*Y| zv#s9%D2}&8T3V<W1*$|+HAz%-zzw$h8Vy9#KNm?+L5~wVa#(a<9Ga|v=+=*w(D|^~ zY#dv>XjX$mu7-F?{>D)?$;C(Gjb=)Ca^1o8T7k@pR6-)rB5c2Lt6D+i?u~(pN_tB? z(qhnD<HkgtDTJ7Zn<t6e<<)Vpr9~duLUkCuk3@D>R!10dhqr&J0hYSDdcMt83m>rC zRuGj2S4qW&+a4dI$0hXi_j|$jYS$vvy>I;t1P~|aKO!Tws?F$+r*V9qLSK8f>DM?K z4>!bjNFkdBZik*Lr8Zo9dkSqWWFsMA$b?1g)?>}pyX{U@Yw{Ai3OQ6<m)>Z>X0C(& zy`9k`(b2dhiHRCQvwkNgcjx%eh4P?^e_V!UxLdD$Z^iIlKVjb(=<Azlw7zTD&zaHI z=>Z&a9qk71wZtFMHs;1_+XQhx6J+Vndrkz@k~w(B{NPJ2d&}cfQ~m_P_Dm#+oG<!x z?%q0a;%F;+i!J9n#oEs`QV_(xMUVXP<7vb<G;e}sg6GbwZMEOJ=zwU+cXRMrXIqC} zt?NclSpEK2ar)oGvQZFKg9h)>OzTc4Z;VFI%3%WkR2jhixRjULd0)&F&7P6t$JmiW zE=fK+AMdnVv-)_eN5^n+kM%P7FQn3U^@5V3UcE<zhR;D)KFCaCV4&j~naIeG5K2vq zCsvUtaNu)x(5-Pi9vRoESgVMLfHg?!P%$$LF$?Kcb9n_X5;HNlB{w+>@zV(NvMR}_ zs7Oj)R2JWDI>pY<r4Er`XO8G)Rs!^rySuR8?Q#rA;k9`0pIE<f(aZbz(dWqYW_Inx z%GsZSGE`rG##`=JaB-WMnp#ZV971Lu%%GpqDk<c}Bb=vQ)5vOF&M0je>H}KB($Bt+ zRT0H&1<Q1s<#e2p*A(REtLib+@=m^0iq(%DjNw6t!7cI%hOag4=avpH>Q8TPwoYaN zXe3gF{r6SG`6Y^W95D!u4&f1oB@VMpLw`mhXhO-|T)4-N(7jKW)iqps1V{;SN%67s z3r62LpMgy3=_kMVUdG_!_3X#O$t=${zl~dF`P?3zm@gD(Wu2?xdK`@<k`1uZ4UO7T z&uR0o?~8bQuV3S(^4hzQSdOwomWJi7<cgnw#LrHpWH(0}neFVVjO3rOQJLy)Hj`5M zKhN%S(sxF4w~W6ol-Pl^PoSQf;kG2Qv}Nv3tfrWnc~8#w@$@jtoS1maM%>iIOuxZ9 zO27Qk*M(8Lp6>2nT4X}SN-3~wcqxI<+VqA^K+r=NRbO|vkn7g<SLq1LZbay;+h4*; z&Z1ayrjIE`2(ENIy;|Qyaw8-kJ<qz~i?kNo9Ohb&&fVqlMB(B^XnsDxtvOr-g1GgR zCQOKE!X8j0(+(`e_~|mtnl5pM6Q}x=l}P7g2N3PPvF*z);9Z1aadWa~oMAcl8Nhsl zv;&iO=d!oCQc`|aOd~Qr{yjj|{sLdo@kOmL@l;6Ll~GX0tTGjU2CFdJSRKL~`KVa@ z8}SU}f>oWLSyo<`>YbFD+ne{3D^_%LrVPRjGp-tsP8j`c{4|PrOx=Y~G$87wWn2Vg zMA&!=tk{$G^WQ^)E6Ynw_VshPE&K)z>I{uf43`k65h*jy62sq7=VM*NT!X4|`?jV= zKM#^LaVRkJD_y)+yCU^CIAFI$KG|>=_GxY`Bop@SIG*kWFk{W)o2=|}t!cg;$V+bK z`KvW+aU>X)*X2H~0Jp&fBp6;bEQdlSw=)kUp5%hwMuv8((~$;}kZ8Usc)VN?uMp!V zf*9}Sj;GiN)f5vtRrA<$kIULf^L98F#}2RPhC+6*Yk9&}TImBnxAwP&vI>i>zgIk; zkgt)xV3G>U^p91$X?i|Mzp1X`vfrLk)sZvq`qK!7_BbD9Mm>gjJ}!J;p2Bg0u<s0z zmVyL-qZh)&BomVCM6}e70uzsg3fIq+4MxBDF{tV2#iBxbd2b+deSE~*2n|4c@9-7c zDgN3C_mDKEdj^x-T7>*ZEx>by_aw0tC`hNP3RdZuoCqRl2Q%b0vR37!?+z%Dq%bMY zbGOrL&LwgX>Mv;ps>{}PoQ3G<DcQ|Cc+t>~>QBiTMu{Ja?r&PGj1h|=9%pK*d!D2} zm7}%PJ^|@mUT1I)&$b_<8^uH0*!|+@x#b*We&NiC!%+wDZYKm9w^`eBPhHoY1tog( zy+ZrVfb+^?ih8$}y~$4fL8?q+5T$}H=yIxhCoE*9ko?v>6DOB7L~(p{e0XduEtYMD zkX|^I+=zc;7?OPYZ9U6Evb`yMmn@%2sn|eXCd9{mw?hxA3oR(Ho2pCvLQt9bwdiC$ z*{hdJnEO#XwriYNaM@3z0CexeBkp9csp&_HD5Fk=eS7Ex@7F2w9GWEdyU0s%!!0M_ zYoCnJ+C`U2QWU9%i(szX<gnigSFXAs#Fy9BE&H)DIOBsxckAsC<e3l@TK-C9=}+p$ z$N5nmL%nX=F+zV^a+StAk=6C}E>D&ZsVym(`}-}PB|o*Ft5fQfI?g%OaofxMA-&O1 z*<=sEG;!Rvk6`tt(jhF=2YLs=oCGLX4mlW^lN@MtF=WVU{=(kN^3?;o^ryB9rLlYC zgS7%h);GWOoLfG$xrf*;EI|tk-<YpgS9pjN&A;8%SmKES?2@-S0$wxJof`cU_P0@w z9{0<boAUGIvD2GF%yHUttj>P7bY{2c;j3z>X1M0?<Qno%!5_;bHQ7$3Bqqu!>45To z@vOXc`b+ndb-g7R-1LWQkp2t%1&_DI<oyX#qbjs@Q%7=XQE0Q`hhwuFe}^GEN<{_@ zj^c_Mf#FV`Yw13zLN_F`2hNXh^wi>w>t~FW+}{j~ihcfsY17+bhDSb|I$oeq31=oH zLq4t2SPZ>OD0_4grFQ;p)Gx#umw3u6S=cQ=@lL6sA%avyu7I5D&&Be%&JJTR-Kn#3 zPQIjho&)N*urxe9D;G#nL}z)JH(w8n9OwnP+QO;jFcb&ZlI9vXH;T)8bI&F1GyDq} zk4=gX)Lw<?^TWFggXojXZ+!5`FVuM@FYs$N)_)flAJ2!{r+8eIbgGZb(K#ujcE<W4 z3M_W-NUIMdihZCAcQX(9pP(5a=r6*F_{N$C%-Yyu8F}}HX3@pPeL^su>3V~4@#qMu z?S?CSW+%q1G8>8IKgX)lhUK=#rbLaUf%JA`r66Za{YsmMWKwF=B>Z{y@7_O#y<q2- z3@Wb8XNQ$$(t^$&HSBz(Ha?t_pHYCXDlHcurUO0NBZD_y*72*cqGDp;gcm#T$;i+n zrbZ(b>N(r8v64TDG;;gHvwyjYN=YT)OJa3Sf7g`8Bzd<_X>n{3hLG(aka`jfGMPt{ zxa3brw28@z$!7S_(9ky>vSP73zrW2U&f#~SNffZ=z?-#L*^EEndHK$n0XA>1c8MRt z6Iisx%fp+QnL5B5O`D@ct|XusB*BRyVE7^<**2@_V*ELQC*#~=Ey}K9FTR497*$Ww z>Wo08+2C`8n9@G_xSBen&W8XAw^Vg-n%Ok<%&BN=hpgvDm4;<Mf&D=ZlI&Gnogk}D zN4jEQ=&H6@e{22*%B10n7?GPwB3c}=!L5S(cnjoejBN`!PNgv{7{;o!mx^LBs=p_a z`cf68uM<BqGnj|{b@O3{<|-oenP=6A=jQJIkmwCuXi-xfc_^_d&F!wP?n~7Vo|uKz z;lTbxA=3|c3-W70pR)t_iXy|kJugW}h~p9nH@QYKaxgInw(0SS0N{*X1`7qYKUcd+ zQ1w*JH!=U?x*u<)6FB2{EajeIAf_3`z}{-kSgEz&-$Ojh7}crt(p*|mU1GVrV<EOe zwB@!uz*zKxi%Qe1eFAr>{7*(?E!P_wyk+rXg!G+{$c1bCI$gsvl&;ZY-%3C6N=QHE z$E%)7fH=w$>ulxl^TP;ojSCeD@DWF^>Owd=T`N0N4#K13!9`adv7z;RO^fkWxo2hm z#5jo?eP)H#a5S;MK4ac<#ZJ|LB2m<l)?*?FF%{j)h^U<UA9kvsA+ymWXSB>2^?-uB zotPxGDu0F)s-0)RX_$@_cM5az%H6KsOC%&3YF5gohlUM*ml?YHz+)$TbYQhHrd?CV zp>*1#_*%W-psTo!zNh*D*{`uJuAM0;pBI_Ke?4b}Z9K=#77tKWp5yN|g!BYGm2pvF zcwlzxrAWzdI)W2SmLs91rY3JsVDTPuEH0CpA*HWRjxoeY11m?MyGuu~kjXncW)lvK zMem7B(hdvgiKc%FQL6Bky=);O-6=q;($*&4`BV|D_PfhWt%lT7KvD>|VdNH<pSLfG zKfSCyWRW-~I6OR4)7AC8ff6kXWh5Cs%t2IKFNQ2_BeCR&o{=glQPan3#A^eF5)SY` zqtgke6*F>`@(QvH6~m<;5w2S9HbcE1-%H>M^qtNRk<fS^DcgPu+>Dm7FGELr9IfWx z`>~`v#}|#kwb6G)y0}T5sYGmCKT2)dcl@sr4U}>iRrM_OY?~^ujxC$a1CJaw#w&WI zh@@7?L${mzK}Wo{g1(LNwp27Pa$J^mEKR+ux0?VBZSzN_o2VMX$UIH_%ZwI+#d#pp zZ5Lsd9R8e<@t9nXUsd9FVJ(*&6><6k`x46#k}NkKxa5P-hUM%rGmI#sDC2nPY^3Nh z%$em>oLK=Sp{e<Xa;lz<O~XN38uVxhDgiNWg~z?|<TW^1P(O!)qxJj3cMcXw4}L~S zjOoY}wsXb{1;Vjv5)y*JQ^OePVx*Se_>}yXF$Ry4CGPm0lLpps8?VlGWndqiC$dJ7 z1tKQyDBOetm~$LsV2)@JFygB@ecPTiyUeyM>ZJ|$yy;CJ0+>a#JqFq``me%_HAv@k zSVQyzZy=^5^hfC#UdljCA#C}z+99c7PynknE`8pjfph%peMZ?uI@NvZcKVQkm?BsU z1ht(zM;6T4x`|)H7qFZd7)!_361dl;g)dz~b=)&D<ZQejd7YpNbe!3K=suCpew<zW zQGV0qnfzv^{*sui7h-hUu!==NGT`7K?`Xe)-U9N`1>8ldg=F#3%HO11JT?8LlqhZd zi#b7jNh+ycPD7P2&w)?PGdtXBNr52<&ER40^CoTv@y}oROQs3z_-E8^^S>NPumt3X zKTf`#PCsJp=~PU~tiG-Iibxv`R}QG%GA-TCzRAE(tM=JZ@YKkobMj&bkK8!zB2tD5 zx_h$G;aTqwAH8N+IJa_ZD!W-8vAZ)MNREPIASIt{npuF=p>H_8xFu7w#@q8RJfB+k zn*%HK^=)Z$G-<UdmOaC>AsN%nmVJhLbRk!q&hQViax?_Rb6KMoA+Hymgq{%|rWmP7 zWC1g&Wqkb|zdY-lGj;5u89#<{C(+5NtJPxQ7D|ha1U&2q7vyK{=5X%W;`p9kKrsW} zUKtz)C%cQp*~sh7kN?Un^krmZB--8|vRNokq$sv3n#Jkt+Z>cx+R~u9^n%WIX!CeA zUJj8l(-3^Kv|>&#=(0N(o-8dUHa7>EW;DkL-*rs9@qo=li|!ZCRJ&vuHNm@r_EOe# zzV@i(<VcP6O9*M9ugf#m7AMV3MT+<8iniPCa_fCL7?ar#$RnuiQ$yPuyL-1^IrBX_ zxu@Vj?WmZKny_j+o*p)$>t1{$Ej&pU`Ge^yM6EpMyi2+%{G%6vSp8T-@O=0@%G5jf z$xeGYfv}IKi)pUsRYMNSCw*=>dm2AE%mfsXazh&4mS}Uixo_S4Ec!6-bevZA(bO_w zVPc5!X-x6v>$r?+lUnJn{+sTv3|Ds0x5Xuhz)!p7tV~RoE;m&PKICOBYsy6&w6sAB zx+CwP?^9sPBbGOjMJn;@3cLAaQ^KrPVH2-3FTQop^n6+P#hz{MbIHibEzF)T*I8ww z>kD6^U+2glkoIx1x#JZw&iBc??Q<AQx7|jGNU^ZA7!oM&!GAZ80j|3(&+=)OPAU?V z1ilMD=AJD^8$PtOwmrFCV<gT|y`B-NQq|2ng=dSQp9q!4E)M&a61-*0j@9t)>x`f; z8=|MC;w&#C(&lkX8xZz{a%7Vo9>*5q_B*V$#ea96F_Yasc7Ahs{(7UGm`k%#iG8MP zAD=0=vOINnXkzRKboE#l6;)=8NK|M)I_XtLM(e9r0a3t-D;*)ciwPrD!7OmyXYkf# zm@`!g$tFXg9nj5i;+)TVtsMDv*EL=GhoVgtPgp+AuSd_Xp4GWb7Ok47*Mfzwl{t}5 zS;E@LUR+dHTBmnX<j3U}A^SJ-*>Q3&?$gwUnIS6o+mRDc8MGo$oR<Rii_)b~EB{`N z-^L8~VVJgL#d9^{o1dAlE36h)Z(Fep<f#P78Pt{-`Ep-JAO0OShQ3jb&T0)TB3E&V zzr>l&A6p0LXvC3Nz#xYku1}e!7ei^OmAoX-ae^FieKP^ch-)jitTO!buAIDs;bK?4 zJG=o3p=5T`mectwbJq7#_CMhPJGrlq$8Im!n&N|pm8>U5-+5XAM0{+=5D6~-YbO0e zIS^9qAA1Pl`>fhtrrrd>h|<^3$7(EdIoTVIU$FZPZtq%ZAlvH+#Kflj81ob&ncwDX zjdgOQ;IOVLk-LnQ(3GSxN@h>`Khi8gU#MVm`X{qA{FrcC#928l=batKl25yRSWoDM zCmbl30b3+MaSCxw#9zYN8Y#D!;%9Rkg{k2wZ;5J}6Mp4M2t!JPymSdUgU>|Xcz=3> z-xsf6_TEj&Go6gvs3bWIuN51Ho{OBttFO*9l<(3DZpsO+YoI1mrKaNsf}rL&=HA4> z^>IhDSL0Su??G^|OnHuCR+&?!H0#Ms=#3}54nx2K362MuIux}J$p3c2P9c)>zG^jh zF=1*tlvKFnTFo;iiF1WyOCfU<*~J&*<0c~$b-Bejm&@=`WyRVUtB9Lf_pna+I`oo0 zCo6BNUYda4IsdPOju`76LL=r<tA{nHW3*svBxXC$FyHs@SY1E~d%iEH`4SpK5W;EC z&RG3OrW*S1+ZvXy{BC)<ae7Z;YI5X>%Rg@0@$Zi$?noY+4K)s(4^tr*FV^YkD^4s- zBtRo#c;&O@(ndvMh^9C#%4u9d2!|2Ai$uh()%{YYq;H$I=YDyOC#y$%hwwv97W4|f zoig0|oN(GdRdepYR&bl9{gjLWN7kAFuL{{EwbFL<=x=0{antRA3(txa#$x5!P{_F7 zkfC@OpV{hAkL%K+!u;AD3G3;Lo;2}_RqJYM*#-L=#I~gIj&0#UQoY#HPkneHaU#Sf zV<ro(jv>}UdlfB{Ss)xUq+RD~ch_3RU6COyR38vcGZ~V)Grs#SV1q-2+d2e|;-*LY zN`&?w<wECDZ^(NPorU<VSRr!Kcfp989E7n|+3UggAGH9b{fuV_=Kw6u022O37I(eg z(oeZjnEh`an~lR2vO>xn13DFoz6FPkjw#3fT(0s)`!>44GF|0cc@Vx98x<d;kgGbZ zWa;Z|trn;)qa_o(%L65Xeo<~NEMuYctXINf%*CX_KWW?E-W>ZIE^k?DG<?Ke@QXET zavDnTE-^Pfr^8njW@SqLg?L}nLk%_8mh<-PtIqDQ94iY#mF1Gi7b^7_83y1>oX6Op zYF$~uB{5s{jQ^9RHGQR8%{~`5OA6+Ki4(+lIO1}$uomhYqJl0VAtBfME>X>`k_e9= zKXP26(bIOPdU1EQ_Ot$X_-=^B`+U#+xDfK#9#^ez(65Jw!5JRW;e+S?kLUgT_I^T- zhS^KkMBw`AXtB!1rs2CvXFV6wjWZ>1%CwT-qwnOLv*L<GPsn=$ddBsPm8ThN&*h$L zm)oJQ`SNc~-6}8Xj~;))e77>fJ~k^ptbE=tVERpXx<DvKxmS5D1vHd9)m&FKVN~iB zpW@{5<S(QRl3d11zroLm19Ok24!Atqp65JF^Q^pzGMAM_E6-Ih`a7Dor^v9XTzW&* zw2AocbTe^7t|!2Cz)FpaLy{sqFTjWoOK<YoUpgiz_PzX=0@p(MyHdIoe7Vk$v~_cI zLWNa4b?#p&!VHZ$b5~}x;uKW*o$KD^n^m=tiJKIYY-~MGD1DrJyyrt_5Mr-dZLo@A zfN#+B;B+=PPAT~EODk1ozkC=pZ}s8Wvt)%l7M<y0XXSAoZst~KX?z@o&6hfr#D7|8 zX$zSL{=e^=Ll6Ex^(Ft^MEi7nW*2s0=ISkG6cDxWBuFu(_Q%qzR~-CspQi#1TayZB zbAoY7>#NgpfSqwK@p~ZrXoI!e`<Um?NK0YMqIg$#HwH$8iQgNDd{B6bhN>#5;Gg(F zaj{m=UXbvsfx4=!_YShM4NaQfzu78_#^5K>IZIp%1fZ~BD0?|H9UH8A5ET`2{t|mC z+oDIGUs7|0Vki;C$4}ZX<Z4G({p$D-E4+i1NJ~uvYN|nEp+%LZpgx63A+mCE{W^k{ zh!D5IVj;8({+^zmo<|UNdgA7V@Sj*7tCI|J4d+@1x8e*vvS8Jcmh9xRx7wd8w~og+ zK0#kS_5dLefq{}$PFCZk2z^%Xh5N!bU~eGS6?V#<9H$N>jQ8q2z|EfX*59_<5w8G} z`wp8j@`hb~@1&i|dRKqHfZJi+m2vU(Xp`menBja!viv6N+xfbyAM`gEtN*jQg!c<L zq&0PQ<<(PTn(Q*>IDL-Z-2HI_b=Cc$-(dmqs88r)ePM8Yp!|~TY#aGg!0YRUMZP<q z*$c-OS4?eMzCEW817)+5)Zam*I^3Duz;<&p)LPINc!Ba5IJJLP71{5DV2Z_B=M(%e zgvZS<&uzNjd{s91&k-qh9NA5;D>jN-qkjZqkvSkhUii=f8gJbFu|k)--ozc37|Xj= z&>Vtxq!`W&@;*j6IRc^@3>w!D-9bPKL{;tDs_Q`lCtR;9DtAyJ^ciS`jC6tQ3-rg2 z>SUgfgCaVIkdHa5J{g})T0m{^?{J<qXrdc=$;xKq#4r4c4xS=yFp;n}$pl_{8cSii zl#~;(_pSAW3GBQRj^Oo0IB-IYmux2O7r|Upo?=JkqnG^oCYk<Ny{7qohri|HzN<)1 z0_fZ8phd#i<zpu&r+}zenMMGBrg2jj45MeImEL6F=U2>)#1{xO!nskeGD(Os!VoAd z&c!(!JlWJv*rL#&Z6ECIW%ZNB!+Y)eXRhxJCnqB(V`5-fZxJ02PYRmK4%=+K8@SFn zBIyGk`XCx|d_YY}uQE-orKJT*)7j`vIAk&~<NV;w9S2ueOqc9<LJ|#kH%rU>=rJxT zaUbHG0b#r~tjKp_843LHZ<V_+m5X0Ni1*<lG0{DJG_POB#K*K_f}>cys`>r{*2WuV zf1@!c3N(08^sK*t!ut%$IQU-2@Xudgf6X&eQ&X!r`^#Ru!D<Q3$?*g+qw)2;;P73) z^@nZ2n_D}J?($!#_s(u`7e(*6ANDA0{ara^SP(!Fu-=cgxA-Ir0kuSOg4Fj*$fInw z$hHsu>HbG39leg%P9SzN^DZ~swj;9K1dI_%7N7BPwap0CVXWQ><(g79PGFJe?YFcy zc3Gc`87ldvLWPXJFTB2;uH(9+*Kkb$Si|`JWPzAFjO(8L@}a)k<tc+3qYU82O=sH1 z$IDHpaVz3AqpyOZg3I1;`@%$s)UU-4#GAM0M3S%pvRRJ%&Ch=0HweK4GY+|shh6*f z{&ZsW2Qa435H7E&Zx@@T$CF!HUM;mN`M02r`-WniNSYgOsA;JFjEppEb6UTSnQLe; z{CX+f-bM`H)HqjA6T=N|p~~bQQwNQt04m105BDFEp5Q$QF;z@~tzL}PD-GJUu;Yq? zx=~M`lw>}K@v4a_V}pCcb<%QLiR4MHm3d}@#zl-q%|FAFVZ|&sJ^h})%0^?F`>#tH zs53)p|0Uf}We%ieTo+L<m&LpP5Zct$FCW3rPnT%_()Rr~I@|wN1^%Dk`ANq;<XgD; z{by|vhzr>sny=%hykRB=kJD~NtI6)4KzVwvbbUbjQt<w?cKCE~uUq-^FS)`0`zQCW zF3{DZaodsv7#XcMQtMOQJ%<-b7ON#CC4oIcki59h2Iz0YA|iM>IE;ip1NEznoQ$=F z1zYOd_wUcM<zf?gY+D>Om6c0;TXS{=ZnHG3CMxJ5RP5~R!0})?+@KYISnpbIWnq<< z59J_D7II4=r?ItVzE@NTYkNxlqRtfn%}j`JS65dSKppmF_xceFt`>kacaHKWFfRgf z>~3#j^MRzyHO@-&i0y^iWBig<Y;5eH2y$bq)uWgKV5LZ8^R)q)+VKg%s37F<SNY;_ zVSyDWKneF)bQ`Wuizx2Tn93}gdDlf>PEk$GSY$dnE?{>6K2ngZV@ewk7?2Nz`ih(h z3||06zGXvYObj5mI#7p2E+3zqoWv)fJ$qJG!WJ8S?RU$_#DqA*V&mXYQ&oMD%*o5T z4?GM!6B^Jp243IW+oh#QnP3_6h*XfXf!djyYi_b(vdv{h&F?fmyR&`eIyKZh0P|88 z@&id^^=|t>fqrp)$J_Y!<<qB6$3{m@8A{F16qnet)n{ygmIh#3hUW=l;^GKXe^{7K z*YvqF6sc?hoxPa0b^<n*t*xtTRdTZJ#S7!$oiE>PWW*K7!L|;ud5>``MN9Ve$wx)~ z1Xd8c`KnAA925qa&1~6bwQ(msdtVCo*LAHDheHq;J@cjt6FuVGX@h6$2O65^+5DUb z{`&gZU`%9Wsp&DYf`Y<uJ0|(%c;6<(3jtR&%+o^eWQ-kvkY}_Fl{%f#lG|~KJ396N zuLCXtL6hf6kINv7@ygHJW?-ySRxboj8W9m-%PEKvVa;_e+dDg{t*t$ysG(<Mgw$wN zIUo8Tu1HL}Y>vc$F*P+c8$P|OFrpVYI*2rW`0$}{vA&zd;$Bd|v88<Ftl-(z#U8m5 z9hs-#>0HHOL|<qh+QwqZ$K$ZXY746TMW>y(;Y{hUtjIA>x!9XApq@TI_YXlrYjxh7 zI6hnS{pf6SbFh@zF2b@s3?m6(vl{XFT@RF8y?yew<V1L;)*x4-qRn5z)x^YP3_(<m zKp;j&Mq6832UCR<d_2^-PHw!aiFIafE4(+G#e=d<vn~V|B3pwhDkRS8;PYSMr9tKS z9eJj?9*#M60k~i+l=sI41yzJL+qxlR{bRqAN3YJB0Zgesf!oJnpGSe;bLWk~;D0fM zL{P-CH2I#4v`ES!W011B^q3?pO&#Kln)eC292p3i0$DuFZ82;BKBgIyoa}NnFfW7C zDdM{<qap>wLS{7|SJs=6uIS8xDa2`)wMj*thLSRJc`W^_U#TX#O7wJv$9Bt;<G7#S zeOZzOoPLUt+nO{z{Mr#g(#zs6IsHyueXS_<4meRZ*E6N}C@Ir{ncY~*Pa(g+)H+vq z07eF?#`Ej_i9EogqDDxB(od-G>)Ycn_EMA8AZ<uyI9Ex8fJ*!;CfN+ck(k%6Z;CzB zVtsMqMpUwlA>k(CgoJ=u_wVvZDn0CZPv?gE)#<K;d5!yFS$z<S&~r5%Sw+RYp?pSx z6du4I_?H1@OamRCC1V|0l~47GibAMC8fmdVUYbP2c5C&nIRE8cqZiMtK;qv-S1Pgg zmS-nG)0cNwqj%h9HJ=0f9H~{0nLIy7ep6|W<+bZ7>v*)I#o60;ab8NB97@kOToMII zO!fO8w7q3eoZZ*%Nj!l74*^1e07>x1lEz&UTpD)?4vo7*AOV60cb9J5-4ZmoTVo-( zyW4D@|GcMarcRxCXQob7J~hyt8}56rz1O;~-=&@s5pl3JWrt2UDlOs#hr{jja$Zxp z76aSET%(F@i=*3_$=`4LPCGN%3)9uR_BX5Q8AV$4CHO=d8i{+~pAtD=Y{h3}+;1mw zEbZv%aN3<UHr^R8!~m9)J8KJRenkbm=yk>hPW?Ngl9H0Nqc{C*L3!pkm#1W^8X9u4 znc+;@7piQQQpDn=VHbZMW83QP(ruv?K7UlqTXY#p$}NbIMWaB)i32M}03^At+w$nx z7=RDN4~O<VvBb_zj7~Nl&f2el2P%)T9fKr`$$PlCi#0VhUWMX;i0p%b{nk~pF7fwZ zCBzhvhQMIFvr}d%pVrqmyM9MC2K&iWx4??zW^CY#XBWrBL|9Ls;+?=4;%<452?OSO zI#3C9OEd;N&VL-&25(Y$FJ%V^@P%J8#trljBE#9Z-;gs%+YJkVolaI3#j#iEVlG_B zm&{SsIT_c@MHV<*6evlOMOudO>fJZ?@*ER|mDu<#D2}nw*&`xSeSKZPZ3_a+eOmmn zdC;Fg$}Kim$VJ1pfj_b<tOuYZKX}c}KwaoQd>HEQS9VrtviA<h39lgE*nn?=BO<mC z6&01z^e8-!Y)7b2rD#2??nutYHS*xoo1unsb*tHghoGu|VUj8I7*Oz4Vcc9>d)kAq z__EIB&@t#`pQ-cG_k}IPQTvq~%d&%cZh>S&1S~arX<t!EvCd($>~LUKL`0;!n~d=R z!M2lrZf@QIg^S&4uaQ-byh|>NV!+3f)!6d?>IDc19n7=$Flb6kCs`CZdIs9S;dw0~ z!2tns3MvELz4SCRX}W;kjjf?giI2ZbID!}^%Ps}pH&mU4X#8GQem*YP);4r0qf8p5 zOxr5T%CfxI)?Qt}8Y88arKQ^;Ib0AUb;M0u>>IG3Zapx~fAsZnZ4##&W5$sghD;KV z!!gQ%OSjs_p2zm+A$Mz+0>VqPD&va8&3@N$Z}4r^A=0hd(oOReWFh1R;va8Kfz+pf zI-L07k}~))>cNv+qc(kg3y|BQ-2Pn8(ysCldu@KVd(3Q9ts}}a!Kx*z3)EH`MLDKv zu>Qpl_g8*ZvUF5dR?Z){$ejqIEnJdQf&s#LFVDxv*mX9CY}p@(n(R(fn!V642h~lk z_9GE-!`Pb^lNGgAWX3KoE`DwbV3lOCPCX&+$fbe)4`)j5yMxX;9n+-~i$u-Gm;nFS z-P>LEo_+p!_2j_G-WE<yNjaN-<dYIgGA;T3g;t%Sg9yU4H<i0uI)$sz<<LkjTn=#l z^_XT}K5_5_mGqeGz4Om6O<VXv%K_zmWBv2F3jP7O9jEK;gKd*Ed~bD!urW}T4jKE+ z1zN|)$kKrn7h?k>`nc2U4c2DGD%FiqZrigr_(@HdJ8nT8F9V(h5VIA~F~cIMuqt+S zLSAR)<Oy9nF+R8`UG%zi04~j(<8A&QW%OgWj^@+7p{uCTyC*N{le1z{dJ5Yi?efx6 zTSt3*Lfq3%Sy3fx>!%L-&x*D43h^I3d>nHwMEl|VqKUQoeQb1iuKDAlY0astXU_sk zOH1+0y6x>BKYXaJ8mDri^vLj&s3<^hu$qlmlogwGgNhG>8Q0$z7LL-s0yXSTP>$w= zGqmr3^REzk;|V(KO!xEMtN*Ru!rAK<1;@ccx*ce8r~PnIYavcn<7v|+4?Sm??h<Al zXEm!5^0Q=FOG8oJlg_O7;}4#kLVxIjcTfA3AHD1Hq7B5d^jq=%6s+7hiX>iiSPu~? zPFaEUdP)CSa#;|RXI^buIr!TfKb}MOA3g0Kw-gBsHYW0svcp4XA_g}{cy_y_tH*AH zs4A3c{g0&SqiY~4kEfCS>%8gN#Y`185E(vUF_v4|7$apFJdnNFls+|#(D!hbcszT- zLDco$=V7zi>D(u3;{%J!kXzYZ9EwIS*9m55;}7c0oar)Y4C2B-c}ek{TH<$^6k;&x zo=CHqCJlB;N>A<HS&TU;{lbDjzt4_@j@kMjm`9(feHZ}ZT0J{p5NI{BsOL0c4(E%V zxzc;V9DhW2$>R*=l73>(sv<_)Oo`7XAo9D1ddHjazMtHC6I5Yx?PFIyu&F0{5o&zX zuoOF>KgxYVT+q`K_#CT?&fpaxrvFK@9<w&wk$6T^)dkY4&w@H~DjWLS&R=hH?9d?0 z{!tASG*nwE1{?9r?Jcl|#PoeBCK9dJsZ~4E4SvHr*~i>hvHC|@T?%!Hu=L&+QTGE5 z8}u;R-mVBIqN({G1i%xL2&=GpLY|TYW$J2$Wy8E;?{#lgE&1}Fx{{CREq(eJe{?#* z$bUSvKHHJDzL$=|E61xlvCKRkpo*Q2KsOXVccyxUebz1S3-fTF*limBXUYux!I8Hd zDW@*BC<)H$BFzAHwrZ>KN%j0PJ|;p3hT5mi)G9g$=p)Pr1_v1J+F##LQb~(cH>!8} z<;GQ$eAYg%8tiyw7PSOn)xzvx=ac-L)f>4iZZ<s`2e~cR@ku)S<{n~{UEXDu2yuHt zx%6IL0t9Oezgx^~eFq~uq^%8)?s_VJ`07r~|K;(wMVHiKgAwC6Z7BmW>%GHGPpd6A zEK6;<Y9;O9X$G>KMmrt-^(+GR{!XZaKT~1a8!Z<E@!^p3MohA(<H+(=Pb;_{Stc>t zgv2h%0}QFp6;cV6yKHG8j>`07T2I4TB(xoytQiHhMby(9QW98{;6g3(cD@eOd<rzb zaTMb}pTX-OE+2;0eTFylNp)<)e&-qVx3nakAuBZfx}*bO`id3!-@*f^%Q)^_CKba| zaa&nG%w0Y*aOOPb+q$pQF7Q?Sc?i?gcEj3)_Q1P;Et@7{HICEbhvZ}=jy<u_t6jg% zs^M0$uB;Kkb*1pRS&d7dWrIn&U&{^}girWutoP#^{2H_40}-cv6GRVQE8??YMk%C_ z@~<G?WWwhw&FCs$^Ru%LAh#L{D(qKweu<enB=$c@NOXWlZmc*iN;?8WNWB)emTz~J zFLj@!r`^rcqNaDScD{@&6#r$6L9jZPy4zV2|DsY^a$nL`B?M&%+=v?T>WYhWaI^gs zEpCEz&9Xj=BMo~tx4$;$Ewe|xJci}k{bx@}?+TYZosQC;xZHKusf%hyvn`I!SY58= z)%KIF!i!_5h&y;nzHrHZEruZ7-0=@{X1jIR7{x;Vb8tqj>ilcbJJWQ>`PZcPW#H+* zi^u<;(=i!wN|~)KI#BYUKRkcrlacZ6F)-Otf<`1mdo1Ky;YTFsdcw0-76LNl^=uOg zf?2L<X}b?8DB}lUpX_-&Yq3N20-~-O!g+{JB;V2g5)*rg{}Lnc0Hdr-fptug!W0h; zO_cRHtk&f`D#^ZL?3@Q2)b=Q8AVz`c>lP_2*InIsBAt{bdHKWB{EyMT1SNc<mXP7( zba`B-{v7RREUn7VNV!p&f!;LTC2F)k-|TdVkH;yqvvPAGpp~Hm6@1$&MoUSR{Su#m z84XQu@pX!X>t@9$A=vil=;CCiWras2b)cbr57BV$?(T|?j9ysaqDDh9*<!dvxUU06 z&0{nHo|zT}L2m)&mjqAH1RCYr#8wHO0`I`Sb^Yh07F<5<Cuqk~r4NhmIvi~s3_L@L z%+H>=GoYi5(g_Q{@C9v)H*A&*&*tA^p&i3MXwRU1!MLjWZ?rU$yi$avtme*KU0nh~ zf!x*Oc!TxO1t^c}9IrbT$U8x-)WB$ATU#5HLHQI4h4PT{>)x*6^!D@^^F4U`_AT(s z{vEjen+>v`?D3h;o;(Cz(hm-deA3n{HYnEJqpaYT?v<`?2G<M5#B&yH|K*OH(e)<> z9~TcFWFEGqHmCjANAK<@_!GN=_NV+Lw`C-6%*-E)*yZwsWFan=uQ;agEdD%L&Ky2c zwb*dZ|C-OXLb5ugXVcM)mnTIkjwAjY_UKXLCA<v@B*@^Tt-qYdTKIZeCYkM!zl$&f z>-Ck}yv~!hRIi1W_Sj<0LOnm}#Hti-uk<Tto%!lJs)PG|U*X=W{DA9;hr7**6^rV6 zsY<)WZU_v-oO8HfdLT)t7=2tLbwn=ZO}Gm&V;hFmjXTfEN|1dH7KzJ`vPHPh*`e_Y zUOx&qJ|@Hp6L@w|h>fbqA3v;jW;a)(&A6O)C@3l0-A|B%P?zo_${?>e=s7X!a~@Af z;(Kuw6{n7)T&ZMhn{}91uklZCddJ5%Bm(1rcs7r57(Y-MII$lt*LZBI`!3!BX2QAM zZevkBq+Va(^Pk1elwNA<E#2<$%Px&3RueNy7(3aS5hK^D!a~Sci&Utk>tmxXaj%H# z54(DYDM6#9{q#`7jq%}ykXLA5Tvu_m4_VyL1}&x?cWh?a?K&!;k%57M0AcPr-zV)8 zp4K*4t03xlbwc7*_k6AS_NO4kdvbbuhy;i|C&j^GtkHfMSkEWwRR)0l`+cQFXKFpF z+KPHc5#S)KsHC&*_g2qKMa9Gv>9v~lrZ;0#Q&3b{O~g2=DJxg?M$r1y?98$o?ER5W ztd?(9-JRq0$0F>FIsqmhXP3P<v4B>=1|LP5P4rh=%_m=NQ&f2{YBkxO?sx#|hq}?B zk#xJJ%63F#<aC+KM}L`FBzbUEdQHt42>JvuSn2o3$y>c2XeFUInvM@o4-OLEd%kvy zovf(=hrZy~`_XH*kOuM)ey@d$+W2_H#0a<3E+H|Y{8x5M^IvnmbsIM*ulJ0MO*+kd z(H7c<*xdlx0Zx42_$?WOOXRvU^9VvqNJMmYehy3G&~`qJ<>M0#Bb^u>CE{K&ljv%` zEnOHd<PMjUBNq)JVX+p7*E)MO`pn@>@ZhXy!`${=@;2VI8r|!<)R`73uNbqX`Z%7H zhq!o=?8aYS79SB`*&PPKT(d6xR_!ZQY%TW}#4-=Y#80D)1*htW<UQ1BrU^ZrkFaN? zNw>0G&rMO6lMVRf_TM&V9Vxx#iH`AQrU(TOu^r_(FFE>90v+SB<J=t7%+)lsS^^&5 zJJg3G-AwTan7NB7sSMG%P!P{Cndoa0@9uFLynm8Up%liS+?0s=`|0?WQ=m<WT-*Uw z&BnNtx5$QqnHExMNk`q??X0=J=rCTfX8{A{Y(J7mwLXd$Q9y_D!uTcjpZAU{En}M% zQ)xQOefa1Ab!w(Zy{gl9BYs5WvMWuMN<CC+f2L(WcUf}<-egjQZ$-JxapUyr(z8s* zpeW<@KxyfffGGZBw6rRZJirY4WipnRT4gaWj`#_UR4zXEy#WA#>1wNb*JCEHg8AQ} z^QCqZ4d)n@m6g=e2?EqxT?)n}i@6g<0QO?s7suy;iUPgU?YYJ7(JEtD>IkiZy;OBk za%4or+{L+4sqR1uFB#PQ;n<{d;T0`}%k{)*p5SFnW0G&nh+l}t%d3(&nLXY*r|Eht z{>o<|FewQx>pz3V&DQ{S@mC*oVs$RDOPr=^Onbs4V->z^PE5FflQYO1rCq6mC+FqC zCm55#M~JrKeWB64I$Qkv^~s6D+Ms9mC}C7mMI}pYu_~Zg{Ob2QSXxIS%O;4GoJEPe z)`#))q?^2MQ{H8M%Ub%Au9KY|Z4VLt^y$Qj5FiV#4`Dqi&aQIb3#_LhZn82dT#J_{ z44AV1i+c+?>{TU`H4E7I_|aetr_IaXW(k8a1s>zIfwP!MSn`kPXx7gH{OHReM5bQs zZbtQ07V%*DQvH!6H;KqDTl;;&7C0~;JNk|0qw0oSTKHuZ!p~cztJso2q4=~*wHxo_ zbY9(@1m4LS!z9@;7roPz3Kxk5-b6}pHd<RKB4Iq;P5cAxqic;@IvUwOYv#pS>Aw+_ z)o{&-X;2w5LwShO+R86oGwQv@*ZSdIgg%7z<W-t7?@cLq)1tfk&7NKEQmHhGymcY$ zk|y}eY%Ae9)!<Wx6oo=_zxbK<rfde}p*J7|)$p7q<FRKYwQX2LB%^N~sE=uwC$#>n z7cimAd3frzhIO;3dDRz7Xm?>&St_sU@=l~?4|8>qT}#5GfN9etw`5<B=h$udcSWxd z%GS{j12)2@bFqgy;CRzRU14yDoCtd{{bd}2S7H+4zk>iBoXTwlr4(d`Y%g9ln3wj$ z%)HJmHe*6s#O)>QW-ntmQ}{1APID6NEjLF74ENH!qwv?LlA*M3hrXnwSX!;#RDgWh zNgXdOr<)m5$H(eXg&xcVvG+hGy%a-NUtdT-$k@mTE{W;q&jPoZnfeK=7U~OrauZ8o zJ<7f3mM^0VOs+rxoYrH^M%!ie^Eq}2PF(8X%$&~>X6jMiA|AXxejw})`GPsO;`Ixh z^96}mA0Honr|p}?(|Nz=q@UOc`fqRchV-N2+cZ@QnORtlJokMb1N;YD!R_pLM}ptw z@wVMU3nc*Kbn`~}_b2h5UeD~BT!BtCHW^CC=o$W8cw>Bce5ui~1Zmhrp;_$agw@&k zrGgy1XMB5fn%i|$EMZ}yGGFU4R<8Lp#9j8A0xXqty22D!LYPIWT#h1JbmXT%s$~Z? z#p|0(G{Axxb^*DXOdi^DAHpOQ&=1hJQCuG?AzZZ-u(iC~{6lq>kknY6qy!}~UZ>d9 zgWT!<QkMBPidaRxx=FedxU#&gjb*y~EVqY=Ml>-KbWUU?MaP_qntZ53-cy~duo9u? zJ8SJd<T6b~9Hqu&2qj{oX86Te8+>N}>t;7N>->eIpRI>Vvy*8yw5Y;li8y?dB#Ae- z-gV5(fDkT5XeP;j(34e%*G@pxv>o{&J@KNoIzH-K_wDl>-=f~O;mX0CuqiwdH==M= z>kFHWaF>ppkgWBvow7XvmT40NkGvOQW{+}VFOfKGl4!2@QM+KfPJdfF0=+`%9Cp7P z-++>Kj`LMd9S{$c$n`SN<ZL@7n~siVWr>Xs3wb;KxQB+cNWIEO_tY#y+D(vZYr}l? z@85rr>*gyh^Q}&0X?a<v*`?KpT-QQCSS=p<B>JItqo=}~e`cEOVs9qJS#A}IjVt4b zCsQlCd#)!seIEKm41k?Aq>R1CN>xs7f4bTeWQR^S7!q^SGBJg5r9);)R{9c3AF#2F zS1iRcc^qLL0s1rYw6Hg6)DFPPV5R|$AbpYjLJ~IckC#>@@aHMW38vc<B*@pCU+$9s z$|mzV#D2=c&YrmsIx=#%RKC<<oiG-b(U6dkZu;~x?g-M^dIeiO|6Go!_;A4oirWAH z61=zLc;Xmsp>h61ct5o>Xl;!pBSn@7mY-I{8>nn+OU9ML<*@Y=Ymj1F1Xat)*-PE3 zeU+plOHXe5jvy*jDPmE{nV|dL)|Z?Y{M5|`<0|Q#2g4Chb}36270NMa9VxO1;Iy&y z-enlA;n_vciRoFQT@Iixlpm9+`?>CG$HrLaX=nb<fyi2?WA5z@sJ|CW4CKX2*=g>| zx>E7X*4pL^R*YDdv&~>++bGC-HL9xOM`D$EtIKQx&TtPClb$-T%5R<vFQ1s@nj2GG z{;@Ek))4OYwP3*Cy);4*chxm^C5@>_DogmZtR*$#V0GA5^eVqRuqea>J2BKrS1a!E z*WRQL7E=eQFPUz<3(*0+O+w;kb2}|2#>n%=AJ(qG9=MhT49+0hm8+18tLkNFmM(KS zs^KVlIIgNn+4<AAwckI}-dtFjn`@r?MJK7KSDNP{im7MbOJj!QO;A!(i%x~>;kqdx z<fiE0BO{V^Mcr3Yrt<Q7nBz)xDg0hTRTjiVX-DPe?E@Z{T<m73Zx>{zWE^cPJ$xQX z>-)z?2V8b5n(;+2WkV-}?rQkDHX<h{aHk0`6;`OVP!;VZ`^gH6m}_ZpUR3ijmV>>y z!}-A&=&{1DM)d4IJu_YuS5Ep24@!Y|mD59V1*QZ<IG`+56fAp?4K@Vzlk9lx*4tiz zDPaxY`If6&)+|dbi9jeBl^Mj&^WCAaV?s)t{Ov>TfML&8_yo=9l+1d4BhGHdAyMuD z?O`DgDRC;5^XoX_WRGQ)yuIBLvBv)OsiQc8AoDT*KCvD~h(e9L+!8)sRPR)m%+M@T zkY5r#zKQd4fGWDRdY(KykP_q8F5&I5zqV(Lj7O9|S(fa&<=8}}a>iq{&tvVe1~Tzi z+X1+MU&Q@u4&2NzNlBQPSXS>R_S|NA2qb|EsF%6h3A$n9$}t-oWJSW5&z=p959`74 z$KGRId&F@~eDnR$=ys~06kIn3sSg6sDlp}2@M$Q?^mnDGgiMuu`}VNgSZclcA43C! zwarbXDplUu2=VlE-IHwmSP<?!-{9aj-n;&{IR7Q@{*mkYV!2V@0E_$H;KHNB=2YIz z)@<Qv$Ez+ZWFAuX-ul`QZbdR(3=>21kM12+LS8McAtpz3j4&V}GOnrjT+GS(wiHaL zu(-GgOW}dT_2iF1q-=z6d*$t07YtrP^p~AvIR#g%^fHZ-2vUUnOI<5@37Vpvpb+HO z;EO-sNUU9a{(fWePLg8vkdJDGH}LBfh1d1c?3*{IOm@h7m!)N9U+u2`Ej%)aT5hXL zDGNvE|IqkDLU#0?C_5kr#lL$@B+u#6&LUo3F^C@v5tG7=+lb17<#BE|#?#P1Qbx7D z=E-)&`z%`0l1MPUMeMzPnF@PEeUV8u>p{L>%-zM0W${Uv9_$fM+*>d@d<_h;ysm79 zDmU2!C1E(Bg&OP@!v>%vNv$9Af-$+NjEDNIds;z5m5c?LX_UHd7yHPMT8&x#OpA(A zZ^E)iRnU&EGwZK7*`q>3L+8L|uF`Bm<+>pwuwFJHp2g;>YMVPULPA28-EwYYxUzGR z8U{%^FTQ?ada5uo%w|4mU}3oY*-B?hk5=JiciyQrr>{19{JM#cjyrLr4leBO-jXe; zV$^?O3HAhAN;+UN!O2;>H41WUghj4yH@{z;Zn~{(aiTkJIlYdOYbT*&`J2BW8cLdp znRXGGzu80$gP$GW1N%r76%_>~C6J)i+xt7qM|tdU#Qf&w9v~u0SzLO4Ibq$kpU@ER zBJ{N)w~ZwUpk=I8ylPFnXGcP~`(w)oQhY-;D#FUCW!;@=K!AiWdwGpUG-u{(71tI$ z_YF83O>qB^6K9sSBx>5x%G6V8Bkpc$RVdczyj_6bt|@6I`N+c|x3O9>bR!P$*RC-? zi>I9eCkDy-EW0Fn(J0hQ8&)wKo1Ugzroc6<Xqu_rPSruFb2K<4vOkyDdy-9(ysLlM zH1|rvklHmn9dkrEd{`k?$oBphbrn(mf#K>fJAbV0@^VQ&?N1&LFK=x@hC1!_ljot| zgF!u+F10AnGRXcAy28H~yIDb4u2E%4$HZi;r}ww+5*C8mDTRJu<GVWbuAOIE8_njP z&9eNJDT-BTIh(iP#-LsCo{p|wf7MdaH{vse=Z%YSY=1H&sobeJ1((Y6a^u*HFRa;W z*HYIbUx@fdmECY7*pY+_<DoCFt9|0_^=p~U3o%D5%2;DS9Endz2)=M#O4>ClU5uqy z`xKUdK&Sx8Mzg1f9~Q~$)V+mEY`2pQL9NuUkLwg`enNIs(-&I(<x|%O7s$`uQ=+q% zk4zPiGF{f-KkvS>bzV5_2n6om8$C8xXX+<n`iLQksd<ThevdsaYh_Q@Qf9g1Q6q%` ze*<y25}DfT=jg?s;oZMUFwM%_TX<z%@nhbB+@_7}EpH;k;TrK;$uE@1Yt!ICAd})R zi7t9`ecEPg*<+pbyQ)<;Ct`u_@IGSt2(x-4`OIv~1mS$CBoaAnFfyfWb1d#x_#oh8 zVCSG;-xTpVl)~SYEf&kF;>fz|$qvnhdAvD?lhqP3MAwG)k)QhTX2&{)+ofqpxcDRU z0sSW$?f#zeTPTKOgDPpZNmowY%dv-#OuGuMGNdD)-_<#)|Io-7R%XCd<nMrHVM)oJ zUe4rFYEWRFu(2%gMveGy!ApKAj(|Bdj`k2e7P{{O4vr!$&l+;f$!0p<eHoAN^W#cx zE-awW&dzREg?Bko?Yr;*nZ*8tQo6eP=)u7O$n<5P?*%iSPo30MRN%PeemiHOMo1{* zR3PN)D&p$Ob-7SOL_<$sVKw}B(A%Tsp;RYq`XsqXlM99|Xn2~j@p(N~h)`Koi0&&< z4AVfN?!547F5UiEbhn7{241GPB27eeUXIiOBUNf1?E&<!vI6q)B3U#7@izONN-LCk zf^}R<Rw^a8>Ur~wTj2M$`>03c43;_-lEMYQv)tW2a&nfkYy8kkWU@q)4U29#W4=v3 zAnVB^atj$n<R}M@Xd&0$$t0x1aWDHq^dMdgwP%|bpO8<gdKqO|+}97`VVg~II$=n9 zP9^6~I8bs7ktrx_A#jnGFffl&QK9DH@!@)z`!g4T&^T_~qPw-8?<^n8uL&?Xd*LXe z=dqmYTcp~h@jc;Jhk)PtQ_Trg<`(RkXdo?#oTnaCS{wnAojub($IFqK>ODT^^K>-7 znU8Uz?Xbu=;g&{hb{+OBc0!z{14SgwMVDXmq(>i#YnTj8y5BbOwiNq40pp1H+p_5* zEO#5?E7~+1zHlP@>0ibevyNzQa&Bw>#g_aD`ue|;R{dn)QQGJI1A418;?Ejt?x8)I z(PjcZ_Y8g~Y{1LeqX=AU2LzXYu&ehdDBA%J2x#Gs#ck5@Kr8xth@EqHUk_+kZ{T$O zbyrM56L6ntiS$V_*Y@;AYrpHe8k~cKock`ErJfr9pnX{&O8K6XAYm@_0$ld;;$d9x zk%6=W=spOTC$&aqWqr%3gTq~^z!!b#`e75}ve7?&d`3fSQ;vkKc6W=7=or}ZT<oI# z!JzD+!!zj2r|ItgEe86)nxlI};^;8fI(6|bQ|Pe#@UXnRygO+V<s&pctB4oRVP#?& zs&C{p0nh0D;FwU~Gc>rsJ03{CEG#iMw;*Z8=f0p|7e+Xm&b>!ysm%X!j`$j<GH+{y zUZcUO-f`XN^C#yEFbUZHtL}W@UCef;S^M+9)WH4Ezxd}W5fYg*fD!in#hhljWl#Md z*_@mvjS?OzHtpW{QxYD>^9zd{Hb4sG@z_z=48lKNu|V4<Ib2>mdNo!A*qPj?WOtgr z)X2vdU+ukjKU&V)>GM$ngPxiKHFOW>;NTFOgtrfThr0~CaGDY19|6(_NQDWhsJu8` zPtVR3Bxi;)7tc2U!=?p8$S+2Z(J@6+0{|U~-gJskkgs=Im-XaSe7G_5OI%#;11sxx zWwBT1iG@j4u}+$gk9*gW-pc4y&#!b{st!LLOv0Zx$ki7<HU9tA3n(Wj=4ouOv$fNx zHbDV<ieqqK*|7e=s@%|rzC;xF=@z6e(4SO0wrEaDT3Y9LGY4?gRjMYxBiFc3N!vTx z6BAxN6Gb1Q+COiIEq4Fd`fi%Da$~YTT%>8wB@^U>L;{_Xo5SvFB2wL{$>8MkrbJOe zK|utT3_}8^;y5%zZ}A1APJMJ#lAgJN0P}A#$#Q8Y05+>Rdx*h|O9bW|;z~b%BVVD= z5)vX3R?d%n?LZ(X6&s&m;6U@~Pmi5~E>=}H-!M5K&KXN|0uYOIf9LO#WQK;>-7l3E zIxvRVI@_t`afcol!1XxXe}6$gWrT3W1o{Bz)zSOot-0JneaRu;wzdvl=Q9fWcM^#3 z@gLqEYhQBBOOIaF*18Sva8Ig@e0}kPNTwXnEYrkyU@7Vv>VqGZH8tIVR-do2E(Ww< zukPo0vYP2RU0f{#(dg#J=#~GQduVB%$ja`K6_O%=E3q^3l+;~DR1zbN1UwkcyyhXa zv>(h+4?zRGko$CqR^rV+gSCTsrRSsK`tH~FK@e*<y??)jxj#z5D)p-<tdyV4eZL!% zQ;m@5|Ket!@%SU7pW^I7#_1XJ7nOFepP+ay<4lMgpk=NRn{NRhzzBA`(xqS}A(@e1 zQpJK`{*X-K|9mSyFHdtp4;PRXZ>y%}#y1l8bw<?ACv!0jt48?Wto>Yww3pbKuHPKn zbYj$M6ejo3Zsv6Xp&V$PF?}>HB|+$zL6e6Qx?H%}WL$p$`{7sm0)AEST8n9E^Hpi3 zLywW2u}n;K_*8`jc8HX;q)w@khrZp&`g|xxSa8l~L2~kUnWj&s+~j5qxN8A&)oR`$ zQ&&O~{4ou~hOCIIR##SrQNUOZ0-B^w^Q`6YEgNW1D<4H+au9V6Cs$ov99Df_H$-~+ z%5X7YT!>>wX4l5Ay?F5=Qu(GXSE(oGusQJ^6Lqz2&rbJC;xooGV1WDjgkz*hR&>L+ zhn>dv)?@1<>*lV$F;5ClrgxgtTR`QZn@$F@^4HuBO=`GqCnop6)V656MZv(H9$yG( zdDnR_`lXu(6Fqlhi(Po;fc+c^5r|HlY2e`!9ufn?iM%Kp2qgG58&ZnXU)J;+rhwx6 zl8X14dE$;TGQjbz#2ptgqd!yxz>q=u`73zkCcW+X?47}{h48T;D#5Q-Y_G?89XX{* z%uS7iAD#b4)lQ)GNU8lf=J7g(#MF0iOY7x691a($G?8G2rShamaM&v|mgoKt-Fy16 zcCC#+N!RLrM;NK45u840`(pc2aSxDfvWoMWOPcLKnfGNNuUpD8=zc+nesBPV4&$K{ z45SK^1B4MQyYj?BL!rxfROKrf?@5N924$FtctjlYq6WN|sGzZ>bFH#i$5CbnxCTtN zA6%aH_w;xjcNDh>E7j~9(m-gAc7}wNm2=Dxj=OXI$~8_E+Qge3&&dU`aUanR)hiU5 zjFmk)`hIwRmHzd@@0+k}TdsBKC>9G?y1Y*e=eB4omQm^nfccxg5ROL&l;0`M&h1eY z$FcS^%Hz<eF_1L@YZv~{UnbP9I{Bdj+fE7fL~f)=YQ23j{Jn_Zh4hxiR6qGfO*+wI zZepdUz-^HGu@kU`NInWbGNf#WN@li<>G+2#EI=3-8olOI>@717d6W63a=AkI>=R^* zUo#{<M(T%-OL|C=b>!2OJ^<SOtuIk{sr^S%(GYcWb3OSN#980dy|rCMsFXB6?NVyS z*2dcy87UhnvtcR()0OW{PC7$AmA0Di&Yeq6^i=mYSBq|LE<DJ+5L&f@bW~W3L?rm4 zM*2G<lD)f)goWD`N%bM=#R$nhjq*yBvsZHH=?|$;dZX#$BreMY!o1PT>`lEZrZ=}k z;UFA2(;NL%M&V;)OJnB8orB70&wINxujB@Z#{6w<4<VZ7z>=cKkp;yc`&m%X>t?@h zl2$yO5zkAa67k}NVm!Co0>oj=rP-a?S%56>z0xE!3b}>`YBrh#0KFYmrRaUzGjbJq z+&GK42l+Wj7Hy2QGdR`pU&j;P-Cd6=w_k9|a0&~8rQOgkNN>D_l)H23%T28SXK+kN zUm|-czxx%vFQO=Ux>SLZqDO=s9OO#L{ngbHVhNev{z^wG|I#xw1oq(9e}@r)ZqFW) z!R2bRjV-I_1*uWc@}U48X1XAf9HPex!+!V`QiT1y^+1P)i#=dG>UFdlGmngmO-SgM zF?3@FO9L(8Q%Suj4qqn%OA*X*Mg|6@n-38&F*zJ`uf=nPm4tokE+LwV=OM8S+Ya~; z9h(B{-8c!JgFRcX1AE{K$Llv)d8W`@tXF#Ht3JK{8=V-{qe6e)q;#0$4@+7Wmynlc z<lxvE9-EesP^68_FEIo+=F}^IZ~gh#UAd&XylHi%|0H6j>GX%~gRy68jh9XsF(ZVr z{ZpelIfc1z+gGd2cLcPkx1J@=4G!p(MHr=JC=Oo!K*p&Oxtw})C+qYSXBaa3PoK^t zOis%-hlN(f6nnin{;5>OTbRIJdpr1*gwJN>oiBsPb9JJP+;?(mJR8k!Tj#-jn1J!b zs8L&V#WTlOY`Tlw5;Qj4ILqI{+x%=S?Tbm2HarT}P*C}lC!rZm>7hNWn^m$9Fc8e% zVTM21cwsR#<Lw$-Cb6jj+*in-ACn{4ltXCwOS3EMPiM^xxAFNz@C<T^L>skOq#}`A zhGru*|32bU4v-n{K;|gD^)(2you<$`3+&?!dG)&6y;6hPEjkJw3gqS8+Rx)Do|EMZ zhML1@4zp}lE7prAjYe3G_T{LUw~9Ml4m(gFuETt_+C9?tf&6CjYW1jA68R@8F_GKt zf`ZE%G+|G6h79))bij*|iIT?lRd_4_P()m{ljC&DV*6cE=Oj~AznQeovK8wN$(}<y z-_;)VI94CQSdz>E@HKMcY3`h&CNszdKr~V>y}(v~bo>fXU7~Ov^ohrR-VfBNbA+ob zJhvZ5yqh{u@{*Mc%%j4U$R{w2i+^=pVZ@s{fViqKADZbN9|L1%^?pG6qeA3xovyVw z3W8s%P?R%iottO#n(;<8$iqryxiQOoTxm8Ec+nqIc#$mh3}0-e_bg^5i`#K~=EmR9 z49Q*z>>+P;ambn-H&W<sUjbyEG>92q9G}gDbSrLy;NZu+Yey=ca-)4Jo{RAtiZxDB zrV$zkBUaK|=D_31kW}jw*8c=6RkPHHcPuDLoqb|-@Uw!7%WS=UTAxORJ42s1ehq;A zGiN`_qr$2p+Mt|}Q`1P0loT%~3BoJs-j#``ynNDBZ+|?#_v;!kzD<x6Et!9xA9HwJ zZ~?Cp-`jAR{ESk+es&z3p<(DS)w}TTKEeiy&wU|7jQ9zW{o>JDL-G%Db4?ZJKJ)W1 zQEluz!wgEp6JAG@xf~o~AWzap#PYAQ0Fq~EWf_xrG`0KvW7j&R)d%V-&IT2Jb&zb# zh2Q8JB8nh362K~AV*E@#0`FdbmoDr|s3Kf(UALJuqiS4xL0?f-6)*Ki+8w^lz&9w* zdNE&VVb0fAbl4WjU)|fQ_)cC<xri-(Xhp7(;REf|%xGK$p+YiT1GqPc%KkN5Qh#n8 z0X6ClF=_H1(6p<!;YeVxIjJ+cdqwu26gaYs@6INKod54IR{y^PLI1o=0if?YqWYJM zc3GIlReY^4wM@{R&jjf;XaSCd|NBfd|5No5I6#u{963oy<gLBJbT}^67u`i|qw1Yt z3b?o{xRO#*Jnl=A1@R;2?xj^%TeXMEF)_f*(Q9l3+5n3kp>lF^MjUnS=XrT~5}+Y< zcVTBtV$d1TnJt<x0Vi%rj*jU|VK|)Va2;?-c=nF~!2N~Y4F&;IGl(m3_pCCXO-V`V zw<b8+(Q^Jo0oDPuTbzJBBnR*v$(#lR1egLX;VCoB!lDq}*!h-^gPCq*u0OPM5wz)> z-A<c;Uqnq!ZQ(g5Cnw8rM~8aveR=%9i?}VVt=rq%pJHK;^3J|}qU-61Y)VEoTcv{D zQrTi_OAE+$CuXnu5fk&$c!9<4^B}heZ=*;E#4_XW-@nEKDI;FMV8g&5JtSW7b!uu# z@hC&&pU~%6Sm8_J39pDXR8e#Fb|Zs>X;)AMc@Ur>l*noZp*=4)Atrj6BcZ7HNi-)X zXV}>cG#q9Tlx^*uBVsa_5s5LWKld<|;1P&Bb>(+(W1?zTa)C&v`Sv6zQ{OCB@FTaw z)*c87=*Dbs@9j>FEk1LJ_HJsr?42rdbF2hIRHM27m`Ls<z(m8qu^<{oL|cb+J0&wm zRV@GYEoW)ybSU-`_|tLRJhBJmC=ePNj?<l~Dv#B{KLSL|29w{5w73+QQmSH%#7riC zUAt*inF}t01fAFa+DdS7aKht${AOf>Lg5#|YOb!Xrt9l?RsE^F4Aj)q4ZfMDc1(tb zl&LDkIWmdoZHsUF#C1(}buOK@XPVr?HurH6uE$$~)1S=^YT(N-!;^#)o2?pgKsk(w z2_d+xDbSj(GE=@yN{lrgnp{CFOJb99(KC?ut?q}u=KE9&dHdF;rOm3ZuMeo~L8?no z5FJg52fJ~KxA(8ENQ4QS1plU|#&pNfP|xQ2xCJ+jhjy*2#dM5xGYL1~dGWiAKX-(| zlKDnDN*z?4+knbi?hwFj`xAKCfy8BWbZKmp-Aws<CPUaRp*+EZmZrvrLodhwO<1_K z?f5*mqPFjypf7Oj=F#GZ52gNCH^RJTtxXpf{_Xsv+y~Wxfd?oZPj2TuE3W!^uRo3} zTebPIOtP518!(THT9C0}zcnf7e0s8tl1b#FV`NN0r?9jPyMO;ai22ENwmY4>?jxRv zRhuZ(sQ$lavmF0z@7W<G#on3CLA}6l1X(lP{k6_r!{db-#i}>tm`qo?T|T}+CgjtV zW^T7P4?tE$MFtpyZ2T#&tW3vu*c_&0V7Q)`zu9yBD>KH5ilyXd%ydlzqmwmMD*vhF zNX{`f#_Gskff_Taa+gK-O7-iop8O|+rA+_RxM7}8m)yXk(x*`s&#<{^`d__(_;}0N zvT$0=@13Ek$dY5y+WPq>kK}Gi<ALN<4$}h#7&Z~%Kd(Od(x7OG`0fls)C?ye-0O6A zE-NFpzP=M^Jan2}1IC36OY}u=bMllve;x!~U9#F}a}n0dh!}^1N0ij^S4*a-Y0?9W z@H^!<MDEgqMG+ICR+MD`vOrE8tF~B&q!ZcFaoI3sRZFX?TsK#D_s_b5V)<f1h!s?E z8o7OeZLDsl-Ya#3>sdfRlo1HckoiEv%P{-<cS&!ZNC=TQ2wIT}4$;$JH2FEQY1-W6 zF{#Z75+%5&BP82%iH?45zojHT(T=1FK|~KjO@*CyV+&>r4K~iEopzv<-di$Zq_ao@ zDH)m24I_4|IYyd)3NE)}p<My8D<Dk5Qg*O@lijkeZYMG}5)nATpC9)V3mD-#+oLVx z5EBBiH(O$Pa^hlQij%G$Np9sNcA(L{w6p{esy==S5s}6N32H|DongGx(yw7%0e;Cz zsH>}ygNPN6KO%jSl)Ugc09C>_Gz{wu%bzEprL{Q6{t7*CH*~ox84!ibg@C%&$$NaM z#RmhAxIo*?r$vb9dthLHcW*`!%}H1p&h!LTp4&tb-hEPj&*5~B%R8q~y;G_LeKNNb zq?wVGmDN!|NWSb%^B3Ail(^dYEtzhlifq~~u&yYE$*J7FFE0(3TTc@2@4o}1i3(E% z(&}K6Nd!Q6c!Wem{N!VUgOA4O2#{aRZ(4+bK#hohArXvZp=Q|6FtfYI_i!@%lQ@C% zQox0ViD|dhFV|C*!1wpnFlMGD2c;pUBL#zI4$EOQb;GNm9b_>gHbMPhN`%*gw@xyi zlQz=S#H6HEG2RZoDE44ffsh23+<Z>A)o*QML$R3&Vmp8IgRaptgnveDOeXN|;q4wh zKIM_KN=``FnBgp+N>mJ$S5RSMhE-c?#oSgz_{i;Q^X7&gjD4458y^St>!tqwb3<RG zS2sTeL*WwhmkN;_mTFK?h6U{H#W8z-3g~ES&kYWK-mD@a;jTi6D+Y1d9=$3|ZY<6X zc;;|8M3$Xjx=2mRWA8k7YWHcP(r(p~SE~`X6T3XNQK#N9GZ1rRVj?Iw7$VI<Ng%nr zvZBnPVPr(b4FJbDsXqixGqii4Dxu{-6FQmjGCf;PDd2)^3_QTqX6)u`pB;JHx!Guy ztC=ER@;+~LyK_a!7S`REjD5MeF4Ali`QYm}GQvzHm9Vvaozcsqc$QAuj6uLC&nk?N zBR8ZpEJnacNHl`Vuik!rGF#)4xc#o-|1`PC`ucT{@w){29UdOCo1<o`!<Z?l>!unt zCLTP&F4IXI&2&3$yu8_vM{SE~jO9u?vH8mlWX8wS9=k`Y5sbwnRYIj@>Q8I@eEn5Q zbzA*0c|j=FB_#+!w<Nf>PC{mO%9Iep&P6mN^Tl!fyI*pc{OAGp!FLkPReylTP^DN4 zaWD4XwM;UXma6*F;o&J6x8u8ZQJa%T;2PT$C!&EckxMG+eG{zNo2o-ZQBCcr)yL5y zxqD!|(u`o^ryi~d_>=m~HD-qL+r+?3^-l^2|6^~_Gd7mg^&z>PE;egQh89}gdPlLT zSC};EPXp)#_?gq4>G>R%c!%BbWiZAB!Q0uo3C8PTL875V)J#l>EadOS!`SPZn%+9# z9b|T#p@{YVh@7zc^Yh+lYg~%*x(d5=0>@nEYP8+_z0rDh&l%M`Hzf`Yppr8s&t3h% z$G7m)a{_Ww=TTn;^hS2z(*_5BY*=^|Tt<t?i(6f_S>1)5T}ShX&owpHk4Y%iGl5Hf zlLMUNBb}0BV!<IH+13iW{-d3l{l!N|_Po4}(8aq18Hm?{3;tZwG49ic(Mn%TB2rVE zeSK@=DqnBZf+?q*qGEydhLhb2s|Ctnbb=fxUkd3N+SQC?WMs@Wlh&N-N3e!1<-J3y z0vF2eK2f$1Y(Q?Qcm#bX_m2AbQ%Awp>&t+2p@%rtXrLN10>BXOHpF{`ADu6PRn^(< zcFKPa{r*?Oi2uzd@c-%l_5aOhMkK9}a$Eil&+MF90I^IMlG6aqc(PJAKS9Rf{Cjaf z5`fMF%8}o{{{|!M50wl3$@MQoEba~sXL|Vf%wbn$Q_buPE<gos9HilFYj3{2zTS>i z@5Te<XdX*D{c}JfR;JVw<5*Rt!DjV&L&C;pzo{9^e6m7V_CKK+1avyGSH~T{rDG%3 ztg6hUE-8NremL(n4$yFhZ;r0)<H8){<P}eMW=VM=&tUhx|IF4qRaLQZ)^b{1UzrAb z3H&V7a0*T3;Dq<q=y+Ww>%DYis=G|8J-pk&y?6o9q*qE;F4E>+pQfFz+NGzbmy(op za+vLu$&flZT4#1VJBqg>BqYq3E;l_KPfG)c(rPe&0mB^b!>@0zXEiLK1<BnTk<Yfo zAQFvOJwZ}0qT<gjKBc5pI17EC<0ulam$xtb$q#9+sTsyss*<v?#()8ju(Y`NGb}7! z3BA4`AY<XNb`xtYo<BoPPfJQjbhNjF=r^B^hmRj#H^3bPy+7}!Xx$flYe)`u5C3p@ zbZo^l=k%qruMW=pPZ<J>Bo-00z-1%{JTPPP{GZ!l`HG5Br`!Dhkdg{2V3S_Cou)Lh z`~Ww<aacakVXU1<#b5PVH5WxkN8b@&(nvpyMnNEbeBMLnjh<M%e`79M(<g<!I)`30 z|89^=e5dj{i2vk$;c1@i#qDKnTWV-K12+*&fmTL(7QgXE=r7qSZf=zDqe7j2iea+) zNs@_(u$t^>9V+UX7TnYUtBLWhk)EE3)52^+{m$`1ARz?*8X9#f;8PjBz3@D^erIq* zY%Cd{JBXLl4^8D^wQaMm%PcC|8Ks>sD<`?Q6ub5G(9*mBbOQPd-CsZ~4cbVq_Pd^| zJG>jw7?>Cs&(Q$`eBb#hODSL3P&plmytBs%cnAjg->hr}T`$|W6f_aB812v7Ncx*z zvsDcZ?P9tM**1QayeRX@IP@Y)Z*+~S%B^Avu}Mx}<x;ryQQ?wCIgqPqtJ^MqO7>tr zu26EOo*5B!P~<$NNY=VpHYR*P5)IMJIpgp`^>^ilOpF-E6ULAFQiG7VY)J&z2sJwI z+a9eI_w<^6Mh;*B3W9;L;fR2<s>||CSgD35nyEGMq<HzzrBoD=DD?sdJ)XmcTM? z_4o69h6^*%?#W(w;&diBeB9k{vh$BVElb-eJC#LcE~uo}CNfc5G{;D_+L+$o$TKr# z%+K#%jUM+pVm({o8fJMzNBNfaZ8$ZJ=Lw&&GdI2?XJ6k^%0q*&?ShQ-Hn$gXBVxYu zV$sDkbZVaQ480sjdN$ZFi`PJr6_pahw|mKHU#{<ub-K&%d^v7)ec@oZlBL}M)kk`T zbSrMXcW8Yk+R^E?Hj4LDqK>q(q7p2?Kzy<Tm<=ST>P1O$tvdVmkrA`0;r6@n;iwMA z6Vu^a<(IbnWMQdu8X;Ue4~5&GtiD2a-|{QURwuXdw<>m~_Z|(r|9GgtuciIVKWt;) z<;9WcgOAgYRF9;hqBi0gk=hnR+m>@nP)ZDpjGFd6%=Go8*}>`0`g8{fkVw=B<Kes0 zrTUjZ^s=(DJhTUvkrMJdbL{m+UqwZPD+&}-ut~_z%Xr7YFq>_+3JR`ldXR)B2n=8Y ze$2>7{kw;uX%k*7a65ZlPK)hemEpW&BQBOUSiZJfGZ_VE+~3hd2nbU-o<)fgMdzA) zfsP!<#ye>n9|Kt3SHqZJwFhmhhhYEE)6-MxOZnh|$4BzkmkbF(cJnwom|oYYYOh;C z9zH8jc~5ud5#iUD$C%Hb6LB~r%OYMpDzngFFJ)Gs)&fCwK0@M$a<%zd+=v5=E0<;X z?H2(-!F$mKBB4Z*`XZsP_)O9;?hgJsW#Y4AH+7MyIdxBPqtbeb=y;}tM{A5`=4ONv z@l)pK?NTSqC|KNhPrluJC$xAtt=1E^ULZlv8tsB50v&Y`ZFI9Qzk(7n{-={w5zqCB z7qm7c42zC);L0LKIXnCWLU*&@r;R~<O!RsMM_KJj{1CM_eX)b`D`S75YCvsqEBJ5r z&Y6&$bBopV-FN@*rknhC3L7vzfmlT_#9e#EO)UBB*|VH`lH$@qfuZ;$`f0`BKImmJ z2lTgJZx>j8t{zGSKQ}Zq?C$*smzbK8GCMcDA6$mJT#YXxBjfKpo4J*_CFHr(c+85s z=T}A@Uq4~ZI@f$;&D!jxtRx0A5%Xj_;Q}obYP482i<cNT>~5-S1hw0EI7A32O>#;~ zBH%X!jOx<117*T?E<EBxAMSg<VSFp6qv9{2po=3XfsRf@1kYgp<||6H1`rk*dU}+U z6b=p*@fR5`3T_tw&=tqxF$b8X7@aEPc$ofGF;vrU?48}4*H-`hcn|PQE2){;sdi2a zNx;Ff5I*Eu7Xk)uzWOaKnI^#v4R;}Udz|N!8AH76*c%nD3x{<UiOR{`9NVbVYVQ<F zYm=I<$;W^M{Y~@}38#&+N;Qr`@7ej2<DIGY)nkorLX<kuU6+5O_*+{RRQeaoXT`+P z@o^~$nQRtX9(ACMsbFDs1!L-ej&6Pj*sbJr4Cpi@u)75Yl%}ta5FiG0O3N#sKXu+6 zZdTFgi~;MyPvcCg1=GH|KJ#jlW7yCwwf2Atqn5xi{>ISe=v=@%MP1zmA2OAZ_tGJO z0id~?la;m9Vc~|<-@H_dq~-Cb{;YP51-rx|r5nNH3aN;DOa)?K`liuVQhQno3VTys znqQDIMCDCQAq$OU;z569u*qW6jD0tRjQI+%*f*7Lky*&N`1r~{ol1ooEEa#XTJNH9 z&L=Io^LRKXr%QMhcE7e7Nhf}Kz(X3=?`t)8p`jjUip-U_%?M8bDHK-86%}~oZw0TR z;1DUrtJFkGv|{@G?|=0IK0AZ9Hox0K-nXo8;odhW{2-d=Lt+a<Eg7wE7<j)XeD`DM zm0DwZPXn@`oJQDG9Q|e*uD-P`U5pN3fCsxy-T5OEIYS>7-qVNY=jXvbJPI#}C}`OS zzpNSWe`|da{K@8nLYUGd9%jg10<~OArmvE!>L<C}nwq#!%nKMR1YU=}`xIPJ{0{>_ zX)KJ^5%>oa0D0V+-Su@XTUZoL&_8r_cfTTzQCu;Z+??up;1846kjwP-6CIB0E!awS z!+JTfn}!MgD+#EEC<7F`KKr(Hqr(IP8=L3Zj~g&BUBHo(`l{GO`wH2%wI0c4Io-Od zBO@iHUH189bPm90R$UgimO-IvQ&WKN40wD%1M_7d<X@w_wuQE=khi#`<j1r4L%-+J zZ>jPa8nK^^jE~AHE58VR=1P{4n_g6u(|z|4vfTwe^8ZUs8dbqd*?VRUUj2Wtx%08{ zwCmKztZyc+@20M=s{Dxi?OvM2!isNUj#pTSzr9_VoE#sfz@PBQLY^I7oqP}Nk3#;r z3jR|lvxjlNVnunRyb^=UY;|e)_=S&G69fNSZ<!5yIFp!o7y8qZ>C&&%)ScEUssH)$ zeDLFGSff{NDe|QJIU{cyyYnk8dPcds!bpeaIBV+ixVUWV^m#2`R*26cZMYwx3CtoF zPI-pb-yi(>g*7)P#hX2s{!x@HbwU9FZEw%BKz(;9zL=#qiL8?=cLb)<y0+SbPg?I` zTn_Lzh*p2;go?w1zXAJ~5KM&HAeF<%tAD@gQ#7@>A9)pqpXn<Tn5kELeE9+k1}e+) z`#f07WIMr9c4jt#XJJ9y-%htd!VLi&{h0=}V{^>Bf8V6{-#6)G;4!?okjTybfcZ>E zDf*;t!-Yt_JWYDTk7FA=wGLtW&IhL|6;(z=FDSX|gW+F=9+=%-*FT86U&4;fWrbEw zYHCIZ=E#r1n_+DgUf9R~%hxerj{*WPw>L3Oz4EWQw*1ELuJWzSzrU2$|4#APBm0IJ zt*CH2-JzzUV6&PlP%F=Izwx(l-XEq0I&^y(pk_j_;onwW9j?v+>jxMURhvyKYiLOJ zil+kZPcVQHwRdz>T8@>0PWX`c(9n=2HkqN35vxs!lfAjt)C-8&WF9rEfgUMDSXg*x zht$e_eq)VgV<tDVuFmz`r9r0wG+Rvo4GXNP$0V!sRhMF>rt6@wtW$n6u@)Bx(q-?k zE^q!RiFDkxnXR+%-?Q3}$OdhOBI~!{lupRuJh|8jqmc*fqSn6caE?emW5D9t9&emz zbi+>J_1b}&&}`RR53evx1GW3{i6;&j8UKD_S9$YgO8@e5tgLXW@`v2FxQDXf46!~{ z&qVTrkT4#wO}2*%Cl;ww3|CzKoLHZ!kP|RycV8iVKDK(PmwW!La4BD5XtX{T!MCg1 z;r|PG&lsufX5$t(Bwi~mV?aam%t|J;d}%BZTZcuM*=nYWnwQ+}px5^~uyrd>;D5&? zX5Y^~+ri!i7T%XHUjp%C17L%-2T5p$f^Ifr5(6u1C5%6oA(1UgM@Uoi>MvRB&V`*D z*u1YBRWoWC4V>Ss9Mb_`n97HM^Wetg!_>>`D`sOE7K`C;mQ6?dgy+YTIns&lytWUc zLCgxD>p`0wGqXYh%b=maF5fkPYH^vQNyhss4wWcL!Asis6+N|U>+BFR|7K~ox3@DJ zc~sj^1=d&Jl1W3MP|pjOG4@C*`KS6f+}^uBUh@@plWCq9t1@8$LG$&u$e0`v5Sg&N zDkUQhve2&`TadBE-JTw`$sx<hZrD=`zmajly;7+YR*9e*^i)^8*9ZH<P&%06eNNk> z$=>ymHF_C#AY%bCMzV`bYfn$lcutkV^E+c!3nOHMCH=mXtt}LjjK_X*csPQ0HT>rK z^8cXit>dcNyS>rvHc6FGX%!GDk#11BI|Kxz8$`MdLQp_jT0m;i-Jo=LcXxMl$6`PG zoOhpl?zzwBeed<-AG%=8HP?*a9AkV7p8zk0!zF1ME=9YS8=e>h)lVq+)Oo?JY;Vg! zux5XM-=HH(HwZf?FRvgsS3-=+=q7?!Hu80eqi<@iR-MJp4Z&0XIf(G3`OX_g6nd!y zhQYa%wP#3LzaJjAn5L$GJnqg!iPeT|^1c+n|9~Dbv9LySS?->B`BO*j07}nYW)tsn zmk1A@)lKpn_4E3W@zX_5&bhd9|Aor3Zx$~ne`nbp6KXWuLx^cBRChBQU&r6&ali71 zq5U!w*Y#`HaPHlcof2TH@2}_J=Kh3%%6ER{iurBg_Gm^mHct+*lvjaKQG7L78Wqbk zqvF=CYH9@1(pd-!m-g4Mk1zIDRJ-UuyxeGQYcqNwBs2_B!E7<Zk7${F$AnR(d!MkH zk7^@KU(t`0$KAb<>FVhT3JWvvLPJGukKyKZ9c7#91@z{cm%B5g(Vsi9@pt&gjIHy_ z9SB~;dDXxA9(h{)*7k@!FE{t>&yP`rYCeAGK(un2{BEOTMJ(N&n}b(&O|$A3@Bp!( z7dDK0{ovkRBXeVknH@A#^U+dX2<JgslKXE|`F;gt&6{Jb@Qbf6%!?AIz1~VB2>HUO zHs!XUbs=QdOMZVY1=MUdPapDKir1f^EnPf4K0XE`9YoCT^%CbJV|#o11M>@i&f6qB z!&?jH__xr|PE00<Iih=>$9DLm-_|!siPxgk@$Q+&z!>27I9Ak|nNFRbo$b{>FK1sB zS<Y75p2^h_#tccF?&bCofO?hcVmtv=9XLt|d7MCZ9WWUOkJ1XDl^_sQ);;xz9Jk3b z@W1tR_f%tMDKa*N?3sqv+Qz}o_hXXFM@TR02ml^!&CZWc>{T5-5n_8Q*Z)Y7Ue4cE zP<S027|3TaaRH(AqU`J{C`}i!P7I8|lVTShd!_h{Owsyl`q!`SKXv<pDslXYOX$?L zcFwC_d#Kyg4i7u-w=UIqV&cK=+L(P8Irq29qQX~-VzGE%OiVRX?;8y$%Auu>v&)1Z z9xFX7Ynafp3!}M|EaC4F5eydvpBoLuST;WLk00Lz3{HVXO~bWvAn$%}83kcbL}=m0 zFM2ac-~3%`+piVAA+c_E$SL@*a;qkNs@OBpym<fP4XWHKy26AUwXaI>ui3d-wCl)) z>#BTm2n96TjwATk*wm{&@x)h-8J~CFZ?~FVq!(|g=kUc>to$Yv5FiT_I_(+s-MzG! zUBS0wClDBa^ET0-@_ZU<em>KZKT*=WYL%8wmIk)~@|0P<dzWUmbK~<$TsJi9wm<yy ztXle|KujK@{EgRcy&9azSS*HwW?VEX#3Uqsf?iv-&|<<bRqg8WzVqr{6qPiRO6n&n zDv5^XZ`xlgWnHLdH&$wGOrdHE?bng{F)I#Y|H5TDELNOn6sXaGA<<R~AIdU($;V9R z-`K5BGxPWll+1WFl2dMxR}ftJ;}B<g*Ct!B<sQgA!Hodduf%Z;-zIEuXc)DD%W<}= z_IIU^$L?CsLi?B#0JN);A6~rOna==lLy>!lQFw$4L<yj`)F^$c#Ka!W<#61a>ZV?o z9v7FXwC?1IFnnb>Tz&;>M<(ulf$32P4E(F<sSs4;iT9Zm9UP7}7F-XGoOO`Y&yA9j zs%I6Ik)@mG*4(>1Yzo#l#6-Y0cW<>{)S66?oRt5pem)7OoQo@#K5>uCM0`h>IA*`F z-&$U}C?G0*6$rI7w5@=PKUGYg@@{8}WX+hEDWwCaJM;Pmiq*j!ldbsc@diH@zdty8 zcm4egg_Iv5GYb{sr^54hwVO$jgoPV}b-@};;H2k@xPnf=QH)$|zkU05{_GPaZZw<g zD}H`{YdJpcX`fi-iruZd?V^2tzdwmpCcj@6?R}zF6yjXPkBdPq70LQSk%VeODyGoM zpIW}Vj&f_WD}mX>4R<~nW{RC#ON)cUslGFSns~UWbJ%r*vhqVI9cPXzvjv0Q{A`c` zUB;QtN_idi-k$XhjJNlqr;whoYAiu_OM+#3KgV5_imGgM_4r<(sDo#OhfR9bHZa;Z z@k0!zpb$V+VxsQCb$H9(C(I(Z)6+R_UVBcmu)oH6a+|QZsSN|%9BZnNU~+~PZES2_ zpmkOXfQ7f;>nbg5o6n<FPA&1fYjn8iN~if$3{+HPWWBYu_7L=LJ+8fwt}W-QST;a1 zL}Rr;%jN>Yi-2d(&g{%5nuA>>YnBVD^ub=LshK>POd4cq`KdwS-P+#X;pEJ{{j>x_ zWyq&*kpqVFGE3@JMMA0@Li*L7iG%r$ZFFGR$;!-(f`(>cswFiuWU?;^Jc)xY9SZZ; zWv#u4VdHv`7{>OW=IH)5y?z}D$MNt9Sf9GxiFpP7n!dC&JW1yPF);z*;j-sUN_#)? z4+%f=nZADQs9Kt+H)Fhz9<Rk)+2*nQ(q7x!Aq7mI!5~52_P(px%Q5Kj$`|GXzI`Vv ze+=|8<FC~{ZvA%Pch=@i2<ZFq495~$Vo!=J?)|PWh|A5akkH@8rKC({P~LJ=p=p(X zCk22-G6b7fbN<+ijeEJKpatyJzXltV*Zy1A*vWnJaJh(xBNP+~e!dfG#W7Yv=6wB^ zk-Zp}!*Ka76Blj%G}H-NT4-P*!?T#6QaliUf{}4qYe)T6YtwV7s2LoeFk*<#j}-az z-SD{azm~%@4`No=(B$O4d;WaLtk^VO`Cm(MHT!N`+ji7jBCflijUEINb2Xx1_OA}* zEf3)<T$b$L|0>x>EJgyVqX=(PB>VC3NL-!Nx0v`nq9#{*JP~BU*7lJlm0%h<)b34$ z)LHWoit3;stG6~T+<K_;6BQ9$B~2f$YR6RIiy$|7BN@5p9QEv6cNK+&Yb+`q27iif z*LX>|2yj2yt(-7iR_Ig8sI5{y`>WegK^FGv)1zh-3g07FIIWVLXX@pssKjh-eOOq! zRaIN>Q}aH0G_y9+T4aGHCvWu;axhj?hEC3pdoSA`waahtzH|-JmtUc<TIe4i>mMHL zA0Oe8Jz>zKp_G&)S5p&IQzO55vyGVh`#(FnAcV&y_|o}S=Kq7i)Gv0fqvPw~YylkU zde37YA5`RY^96r3JJ(sEmRCt?&d;B^+H$#tq4SVQXvCji^YZUmfME(!!te(Mzhvp! zy|!3N3TpAI_cKQa3s<sY!`clR7UmX&1q4=BR<h+=67Z@?<9GM0;Sq+!QQp&a3ajrh zWovE-6Kh=gu#rL2CLL8G^1HF~#m43qBft^L3g4<uez{DIE-{U8v-*Gh_~-Hrr|UA` zmw8N}5JQ4ZlJY@2a#w$a2?ZXpK_V=q*pd&4y!;Rk9^qFh{D>?&+A196!M`+4MP-P| z-)kXnUn+xAUlO17UG-vC==o;!$8s)ccK+DBemp2W0+?)5Q<IpeC?4MOna!fTv8to0 zs-wPAA$)&GHzRShFEk(e>bQl2Gs{_Mkp~vpkU(G}{zYHX6v=i%ej~*gq?YQ_M@b2E zY^)%bjY09gBvBpV))*ddEgvIeuR=fKn2wDy2W!&-PxC?>(~`M^kaq6US_-mfYDZ2| z=FcwoCNb5)-p9v#EZ;?12TdM4$wB8pE9t8*xe5S?#e_>^`x`T(n23n|*;KnP`k2-` z(gXYsM@KCEzCanLqN587i)?@$`or1CxZA7<n2;~EwBEh*`Bc$1nB~>=Kn*!H^aeNh z*_}fuq>FhS#7K?40`D9qY+M?m0w(>v=3Ti3!8r^Jc`0bpii$`w%pZr{B9{xd5hF=P zaWNYxB9w*IgrG=-$P0OOjzVS@hBp>+bCgUpe6q41d=&pWGoZPt?01dvSeAHl;Z8Qa zK(hPm4Dw_HavDXN6_tG3{yK2|$;W1#kPQeZj((ER<>kk{om!3U-;kFp5P$-oz8ooy z`<Edg`9BlTA><s#ZA~>P%Oa`DEh$#>rS{{?V|WzM-K&tFBb#5SlwUMpYpc)0*H*P4 z`Yn73Zr1qd=wO6#Q_|p|h>6kVB^(=j>VA!CSEeNSAvrnq!(ZkNm@!d=HR|vl%DF8a zF{ym*f<m*)z3m_fvF}~VlBd9za@}pLX=?i2r`XpOFqL_kcRu_36H$4^Uti1D(F>Ev z#aTl-x*6wwTA@+R+uD*5KgX3A>t**@q)WDD>Az+kP0c=T_rU>4m+e22&j|(bQCZN1 zVcL6IVB%9)SloVj9Iov75#iF%V4084TGN?NQT7Zdi%DK4bEn)tL?Cc1*v35m9%aBM zK=e6`Gtm8}yhoDP7|u>{%uFxuKF1FqG3p4U?4}?)9SeI)@;m&hjD<}0)G;>Yp&2Lg zo&U4nB9EE9<KD83zLFA{3SH_3s~lz`V*<LMY*cwx^+Y}nDwApL`qtLqRDS4T{bTJz z@r+D#GN7C<508z#SS_)`zUc%ccLpoyk?A`Jzy}DK@-Qi0b5yj(rcyY)kR|k$!)g8F zVk4-&AJqtT9)2HuHJ?Dlc6b0F$a9iMq@+6IA4v?;YOBPxv>usVL=;qkofZG#eJuPZ z9MZrvY}?^sD?S~Aal!J`7PNWDdo($N3phB|%e_;hB|BifjN@1CxaZgsN=wY+EFd4= z@j_pJ9w=sRs+C`-78~k#trt5hb5n<hRRg9jGXZ+(VhgtgZj_>L?mFTV6F(xfTCeta zdG+S!_L;Ra?K)}dWXV{Y>Dg3RuWV=Y3_7yZt1K@*j2xm&v_>&6tXG^=AEl<5ANj;4 zOGH~vO_O)c9hN&Xo7JZWB-FQub6y;J2T2$y8tsId;rP4nfFrVeG3q<;npVlHO8(F! zpLACK&IWgc)K9%k9YoaNxbzlgFn@k{uLMk&W~q3haAv3VQ3o`Q^4(O&$cf`40JKHe z_)T9Ea)OWDAH~BnrK~(WFRjtXtjA97@7(2au<!2bTIwzd+T4{^w*l$ApI?Rt<7lyi z$>L^!oLo1wgFmLWu&V&sPTU%&(^wrXF}XPZL@Mkm7=o~<j9y;f`d$yK{68#q#wwg* z)uj{^dOPDtg`Am@GDrC*Zh00HANbu!AgP1HZE89sZD7y=Bxc0i@4_HRKC?ovWgeTt zFX2O~d?gW!wFvS{j)C#(>JR}Q9<%P|!<Sl9#~6`vVl_Q|CIbs}hf^y7nvzh;g=UP* zOi!l`>O&mF9JLba%oD{r5ZEE_!O73<h%}`O2Hi#FYDPMY&Ni4P5VAW)rKU;~$23m< zzS<GPsR`j2HOTQ5)7yufF+_R#YZln`{_2&cq9hCBoP}m6sLpots}8oFMXs(@=eZH} z(h+Qx(y`+mvAoFvI6UB0CUEv1_>ona>KRG<7bf|v=7$L;VeRkUy#szMsSvu`VP}Qz z+NT>}p%xH5)f#Sf^=9d3a{}6*dSB+5IuVN0PEKWrqGWWc`*;t+bKI&|GEYy>lxZ$x znTP^4T~!XoR>Rjuit-9_#!DS^pozjANl#4`t@vQj9;0KxW^+svxeQ<RJ@&$Q1qS*q ze@(R~Cc#Uj?Egxsk+$h*p0Hg~63-g5bY0@{{#u^tku=N&ZPt6YcEj^dUfZD=fN@$J zPw|JVthua|{DZ?ol@2?e6+`7JjHs-u*|~voj*d6vBU0-92}oamR5zM_1d{;gN*s^8 z$#386;7RP^K}ki~Wl#0+EXS2pv0NcIBx|C$V7Gx>(e!QKh<v?tOBm{axv_RDrVOiI z_)rR|KXLN2Xim4myL#kSR(Xh`A-xw>Am(-kJNy4IJwYx~lOk$rE2H5-K)j5Qs)e>y zPwXUXG2L-~7bT*$S3zANMpsW4X#udmdIU_}G(-xMx#^>*;HW5x3x`0isRzxd@KjvQ zuCC&p)qJH;8|>^uTaaS?p1khj+l9vQq4oOk%<hmCq}yq_amU+jXuw@mFJEffhakTm z+!B@rjjfWPV97RZhQ3pCc217@K)?4{PhX#&u(63rSh#P+YHCV~44bFs7|X%Z3?T`L zbo5sRDrzei<j#Ngm+DNGB4lP_`Y~AhB)NyepV|0lo3lH|abWB3Pd9yIH!=J>2$&3i zEZWo3()uXDjfaW3FJY9pyqCrbO#iz0U2B_9pZMKbYpO}1eGd=B{GA8QHrwgJ72DG^ z<t&dKbTB%ejH^mLN;%0o{ga%GTwGaQA#W`;v@kRjV(!iIQjMCzWasAQgoPWjgQ!OI zeZGSu7q8=PZJSz=GL0q@gm@t-OV>ZtLjm*HL_)qM(N`NOIi)FFcavHC6sqH<v28@W z{gQoJiY;}3E|qZ3Q0f3n8yLbNYMMW1d6KX@el4X<J)d1J-Du*~RDw_fAR~3$ON3d- zc!`y=eb|R*XZ(D8XQ!uSHfwUOA7CtDWNggiI4g_X&+_uq&PSi@PF1>9!lR=r-b_87 zqBukh>LdE1*`551RTaaKyZA#D=X*+;-{al}3W}t5DrqQFVI1Qyv!ZrxQV@1tY<T{W z<apOA&f#h9>QIHevT(AGAO;B!)AOf>u!1@BbToIrJI<$sl7}e<A!cq4E(7b-bQH-z z6Lvd4NK?wv+u);K>&>}}>ngx&K+#-c*D+*O$?Lp3xKVXhZR1p%<Jc!XArZ4YYWIiD zlrPxe$qNzKI^&Lv<|*G6Q~z}C;(&Z!_I?crcqA|W7v5aEcI5O%uaEuV`=e{!J&cb@ zNoi>b(6VkKY|nwn1ps<ifI_tcAp9Z4OiWAy4e}c!KOVs}yE0#J>E;R*4i<j%!d9wu zzCNsho13?6Yzi2v`sIdL{!^R3EOhy>44T5R02qlkjN}G*TIUuNOfm7Eh2SCOv6jNt zUtc`j+}$mGw^y2;Zi?IFO?gxt)zo0>&qmc+K34=p`J=>+G;nJN53E0%puCv0+9`2Q zmKKnCWq(?mT3%k>MsV?_@=h<B!(pSW6=NRob1q3j;i(H#-c+n3h349oPnDEH-PXox z;1K*WNR9ELfPcIn{;NUxj}(y6N-}vdc}75+kfmhG{ilN>AtzYP2un0+=$FD>T`z0C zif>!{8G#wJ$z^ZRrThEC&(Ht$^3i_AbTWqY{{D4J%D-Nc`4)lDwdh!S1~T=+JS(La zFSZkekw5x%|Jl;-Pf?R^+G4ob$G-fdMZElZSZmvO<)@;epZWQRcHW=;7L*(wbFs7E zR2~?RPeSr4|IkcV4x(UXfBPN`mq7a_(AU+q8EHYxVib4^LFw=dn}TuU90+zi$!Nqd z0=GsTql!$vKr+%+L!*+>;7M7TcxuYip&`oQe^i(5UyCdlCn{-0B->Ch=ZDoOe0G?n z^#G{~2QY66@VrYf5Bd4dt^nwTn4005nS~G%GCA$OF{VOF*K4rhhc9YgPN7u&JMxgC zO`N+#9hli9oi&o9wSWIjXJxH(&!R$p&K>1zl?dcN-edo>rvBd-wfv9o{5H#UFldSG zPsrVl>E-VJ>ecZ4+*}^(z**(_uiyNTKw`bxD;XsSc75Pm=zYWnRU=qJ#%W%>tT@?? z-CYY_=(sGb5C8n%q2M(`nJ`hl#cj7g+t+fx)OP)JZ_yI^J>*5<Y_xs7PSfJ+s5Pbc zxqexFz9tqSPEdz)C}4|VenZT=rRzm0XtOcC)|C*rNp|NJSiBmTm;?ny?(}!W)`NxX zXsOKtRBj3NUr+XmCMflD4&uu?!a3c3SJy!vMRlDVuJPP*fda>Hp^Jf*mX@k&Y1#^p zEtXy`pj$aL$sJKGjg5E4Vt)Pj5kjpjA}+pTUk(DCl|?4UlYalp!nG%y1bt~^+&D;U zO+hJE;*GGJ?6S=(4c)*Wt*sWM+t+}XgOm4h233GUkOJ*AVH+e9>auz*I5&$nd(%~V z0NR_Jypu%MU;drmrTJ=+7t`snZ&pP`1vIy>UytVKP#8+QdC}RCrgR_Y*8chs`5hcN zmiT}xS3W?BM-02p@Tr3p(vwMDAFN|wt%_hZJ8oDjnjZOk7Er2rc6Jr!a$<sl4io2B zr>5>Q?M?o!vfCIEzY0LV(|$4N+P%#?+Sk-1B_#%@va{c!YJoCT2af+Fnn4PsqC$kr zp9wooXM~Qmw0mCsIbY8G66jq691>UrGuiIBt!k-mD8}tx99Vht5`9s#Wr|6Xi;5_v zc0BW_<!z^sqx^!ZS`{Vwlh-zfGn1UeQk=R<LaNw<f+uz&Gb1QDEG%n74JPAYbJPH; zewZ6NRe|VOFg(0Zp|9Q#kDQK<*ZJ^H#D{u9UI$}HSg;mWS095~RL_8O_W&@i<I>{Y zfzHlXKtG1rEKm;i7RS$E=nR)>oR*e?#(z@vLd+iYrOneFYC--6I5b~gVc}1=IwzuB za;l=FzV|7As;4>UG+%n2F;UOLaa{31S|ro%t*EAwjP<!RX}+?5H%nh=5`8A)?rVc( z%}udn(K2(g7IAU&sFXa5q?kg~4R@#G6hEqkn4ftqRi`vMKN93TT5w1fq(|7<3$`4O zX&6a^N;k>K$V#o3tWVl2?$c@b5ue$Fvtyv|4P60Hbv4}-|JH4^jh=>ZqSS<h8cZ3M z_!sq<1o-#>fe8vX>@IehO;nyq60WKRD+P`c^SrZi>MamoKxOr=?uVF{^o$IsPy;Tn z%-1gz#+eLkD8$+EU2!AIj^1_en~)DMH6)^>q-7?Sq-S!(Dyv>}4NOL^i1fTq4+i20 z@JJ7bPNJsP6b9#*Sc9CfzHt}k`FLV&h`x~`#f37mGCp1RNU!jD5U$%!u@_V$Fdr6^ z7LPqRBP<=t;r9YV+H#kbBG<E01}ix_jc|Ivs1%aGACEwaje+N!KRM}zO!r<&Vuqfn zDU(&d9Uup5os~qIV$0o$)G;v{EuqhzRdK(3xdG^{YwMz{PIDqFT!@FcG=x7zFVs{T z&z!kj9W9ubi?MNVNuqRqP+eTeyd1N|x<HpF@?z-WtwC>-KC^bXPQrs|SP<<b!9X`l zbKbWsEyc2UOE8BT)`YT9#%whGEj;|F{vgBGmw9ZpH>YN-?7-T_2Fg}Mg+&8oOvbWD zMurL3oSbv~@>}hy7};B4?dcX<HiFXL1g=_yk57KSHFz%h1McqejLLGX+-797`ZY4I z;?EAvVkBpFuj;}RIZTkTur8o0xz#Yn8@VlW@Wf|<IL!STDmUCjUnEoKu{NIBqAKWW zdr3R|lnwW}@sv^BE!<(jMrmW-hxwI0UKF*oGtWd<P61G=)Lt<>?__0SFzt#jVLKq& z>f0R1a)AS0JF}zT5n;J;?t(v5r8)8I*N+dMyr`%tWgm_d+F)}s+H{jYA<r3j{x`ud zirER~@9Uf|*z^xFiI5pE$Xi{UCADl=(@t(gt;HfLg>kN9v897C_uUsqCdFRanPgpD zCCi2;?!I}F&qTS;9y9S&MHifYZ$~i6$%ikzA>)s>>n#&zZJ`UA;``h9g}>J-83|sd zJmm;Ps6c#U>BZ|?NcF(O-DfOS*`IT|gYH?Kr|5oQ(&Q5lSN_tXD=5%#ar1KaJ&7jx zZ$3`{9cteHaS|Gks9`y&bo~&ovua91PDb|q1`RngEft57_16!TnFt?-o@~8^SpbQ9 z{)p{hq-O{Y387@<moSZj^*zax1FDlvL73@)CAHf~c12D}>htFy_1!tbD0Rlgzh}9$ zoDn|_tqwmeZL4AHoBIat$&HQQeMfBNO|`{#5<SA3T2rwF3^rYlgcKF=kVmMJjk$@t z<zCy|7MWnft!p2P-346KiKrw!1O+H5pBfsbc(>oVM{M*XOZWgrmLb94di%Qcm%jki zyhO)a^`?8*fjZQgj!;uYo{10~985oTPHmmV$A03kZk6y2ck>H%Z6EWnx`%_~E-bXN z#1a@3g6oHZ<{wWFS-h}t{#uyT`67hWqW3I&bgUGbsoJbh=9^4RfPff`MKEpq0dKrR zeAi~SRz-bGNP>Q5fuy(0;6AV$C=Covj3fv-Kc-fJ`A0L;^`7^#W^!t3jFjvl-9I-C zn_60Wx_cM<Dy&{~o{&<shezV`x@{SQ*8~{i#7JvK@wnBs_cJ`4tPsD@Fe6e!Y9L~L zBixgjS6K4KY<qbHFJkSvHA}3o^eLwZXURKJ_{e~H44Ug}$r>hRswd`PB>)3Wf}*uJ zzl;q7$)wHQv5$ItoLp<1_URJxi%i|x_}`%gVzs#X-R&7#ULk|q{F#`2z6?U&AfYgV zUGHN~z{``ujI6P8R@c@|aC*s5J4*<R*VfnX2LfS%c~|}iJB+JPb<gRPt)*<wzOks; zm#Dan8Odyhg|TVR#c{vVVa38oD=98XtjSx**f=Gx!Ui0bzPexAYY`C@rQcIHN-}&u zMM=wjw(60F6^JEt<Jd%*CjPkqsfRGy7tBxjyXeM`@e7|b##R0LF*!OqDhatRc<*+$ zVYs~_&kN!a=OyDQjEb-MOq?<g@60YNFrscth#G$TIr`#id~6*yCPdxT)k$zGX~{D& zRYQCeivK+&uxJrXoSxR^U|HntOG#M*PjO`Lz!#Xxy<e#0dgUb(m@TiJZTotZp!CSZ zQPz@CQ|p+%k_%7J$}*t4O~@l^Cg^()pIB6fAurc%o&DA8s!uGJ)9xL)K%<GTWBE0E z{pv-7gNIZ6#{|nO9>N0j7;;BRZ+>9qB})$%o869eW2dKgX!@w45TW|qV0gU>v!%IF zSI@xz!E*PnDiOHucv!KfWGy`%3mjgeTz^7Ki!o);PQbwA@jaz*mxoM3O`cyxMU?Hy zqRZzb&(hKeD&&nf^!c-2*4ZU8BclnFVTxbKW{2&6tcm}d@%2t!;C~%mOPv{Ba_q*C zAeD5+yr$yA#@5|vcKNP$DKW)@S(}M^A=MSM^P@tTVsoVSq*nZMitS>2`Sy%Uj7w%` z!$Hj9^t+VTE>%{4A+7ud8Ly*&)57F3VtKJ~$#1V13FRf!Um{cqo)bF)$u*6iZgSc? zG42Kbmx(s%e8sXI5<e4ayMzX@7MihbeseALrhbURBw;b?Zg2TQQNNMK6m^LoZjHcD zZW&84h78Yd@Y#bTtsmTpXSfFKo;{arIaeg8Ml^FTW;#n<KEJ?>?S58@-D=7kt$?>X z`h9uKDVH0ezuX9bkiknU)QL&;Ok~cAio+|21tY`1Fu!~x=Ev<f)ij~mH5_3i61=*~ zfWSb-NdI3U%C#O_Xgi_#L}HxcPU?GH|Aa7Uxd4e{$<Jc_d6u!il1=cxas_YyJN?&h zH|&`4@-3Is+Pr{5+kwnzNC2pfB3p(q0?23pH`I{=v$Tv1^7)?~Djt#1AQXMDo7oyw z4^B15$8%xdB0|9_=d9Mf7Q|<emK5Bv@P!e$aThYF)7jQ`2lg{7CZ?vNaW0%d<^#xi znX|ph>;ML~a`nEkyEEN$!2bg^>T-Y0QKG+eK~OWB&2sCn-!-89oZjD*4KwE+9VPZ= zT(VLc(yy|g%Ci~4?5es;D(qy>MOo#ZpTFCc(2%8aVqz`Pis&;D_K$ve=N2Nm_ZuM8 z3YM?r7-3WmF#zO9b@VyUD5%N@vL>EiL_@xBY=3$zo7s4}gE-ymO4+)o%oBfm?u1V( zZ4owV0u8YxZ*5lEU8*B{7HAyy=4<XtcD2G1DcaE(#bpKEb!T>;&GqR9J?cf@lMiQ3 z<mBXGwCW58C)azDI=1b1-<vDZi&~?Aoa&3)>(Z5uHP9L)MgqYkoO|IUav+Pz_@{au z**v3CojweXqtD%~&Pz<BEoHm1wfLLqbZhD*ohd6%YEGbBgthui9pd1#jke-F6s0eT zcL+8bXix9m#dA1lmsG*Si?9N7gP>$7x3?R9U%xWRFZ?-i{i4!nA^YXoz4mBg?E6)A z7qS4&*-B+JcZ5d;;^PvXthvk5X@;B~zvCom0V}lJngCgPC`!PXg(as*D-0IodT8T` zlw+VZ2*e7ScV_+4#?M8(F=9ahv2F19SETo*T*DhG*Hiny(d^_{`@vNlNLcLHR(bq< z{09&RQD~C~`tLC?)Qx8;dAElzuc{W0eFQYVr^NJ$8AWf-4;0XvIy$nnv3lNn56vqQ zhT`zEnvOD<%v-at2N=myfHZrFS5#`Yy+Sy8n3Mfr6_JwCIXG&)UE6g)!jt*7{fn~s z{%XHBw~zauAIEtemd6H1X{b3VIFe>X7ydnJ9dK8Hsn-iEwYRN+$3j{m2M33uMEq2P zG*{|BNp&FYW`P1-QTjN_yJQHMI}zL_Nt@k-|6<U^PrZNt9{3i(?>TovVd-C5!sFq| zLVT}fdZS(Ffa|5_?98>dSYT-?Ip)@*-x_f?b}*1RCZnjRcaDamoucOZZX~kk3XY@U zSC5h=e>8)zSVn5<5xR$sO*x5+jgUB8annzQm1SXzjFuoWM|^V+jc~P_;t{2{Unm$t zWPcU`%ojgaQ|9eV|5+EQC&YR~suYtqPzc{F9|K_>hH5u4&&Lvkix@0Ewn)coi|X2E zdw8&8G}PCF3C5T9^sKCodnt(Ta0(6bfSU!q75?7dt*Hk*vC?L_HZ4N7DAvPCrJvs# z11E2>RytZ<Q9>I(JA#NR-b+tF;Ads!xW&qO@xkQp7hzX?2_myJcD}$YVZQ1`z*9~N z;kgMXg*a-~br~BUzQDH<0t&mw8D$G?G4TilAFEk9J{Y|uh`@Z&yl-$6ky9scK_aGH z?|EZ2C_v0SK?q$*S$?fEQ_@jLNY(KM+>O6Z4M0~8GN_n@xVTE&J+Uo{0H`2?gB7~y zdo3Qz4yVc0{p<*5i*&&yCx7+#EMRei6z)r{vT-UEKGZ#Wlm;2rps1*H_n!i|LEmqr z-|!L(uVEl%WTdC}=4*k00J#63oA0Mr?XRgEoE#q>UQ22h6cCcnb+}Ks-OnrY@?~7^ z5Evp>#8mtk=briwG-;Qcenuw7KNFMlbXLvMA-4J{J0AXG7X#61hUUrf&1=`?ziAu% zI1W`cYK_14gpNY<=~I}O;(xz*@=8Du#>4c@jh$~neh6^AwiK8aG5LJ`ibaHtO<*8% z+;v9v#HAfEwhG0WPJ^`V`e^Dl`JxQ>!zWLa*gQ*B7dw8vsPYk&xLUs_L+SQvd3kYm zejdqDW%K{^siOSjpL;<JHs&uTVuEc_ws-r!U3nsOgXsx5bH?f3WYK!5%~G#a{wmb# z3`V1kSylMfi;G6KUrWM8m2BIiZ>|@zgj(l?e<IqOu5cpJHrso|B`W5;z99rPNx{XW z&1M&=9oU03_!1%0ECkDf5HV!EMbfbl#iD0mkjHxc&);p4MWuEdKs4%5DTq8<?n{Fx zBA|~^sqv+S(k{MsJ!)2*`kpqBDa#uioneMNBVT*s<fgQYfLCN{ii3|&6-7%*`pL(6 zRngJLqVZSd!RV-Fn8t*py1iQ|u_Fl~701<(XmH0{8Cui48x<cI5a+66C6B5B+=lPn zj)4V<N2Ir<ozzT9Q<FzTq?GoDz9@&@n}@0@7}2w-@cMPR-panmm(bOT1rF=RH}n(% ze{tPH$Ip5;8}HUo3Ykvie4(r`blj*s+eY1nX@90;_d@z`o1dR|Kwu!1l~R%;RzXw0 z*+_WzN-T?oYE^@cCLiD9v7a#spfCm7;`f?}TsT2WHj!?e4#Vr*nGzvh<TgfU=Oc7r zY>h$LCXG`CE&#az)7`s}Z8YpFZvvo6I;J9j-#=sLURLiw4<6Gm6>HC%w@Hf3ha`kb zr*B{Nd%!VSyY!_Ohso5e?-fMVWxSzJoX~vpBY8*D#pli+lZ<4SUcD6S0}r{gbC*x= zR$y62EDff9WIZUdP!9@#WW>ONkUju0fkSC~u}-_+DscT1E^mg<S07Xq6lQw*aj<Jn zN_xWSh8tv@K3s9$sIP?>S&epE=W$qOTB}@CUo<t-)@KJWbU(uK-N}CR*-gy3+4&m~ z=cF}tnxk_*k)TlbGa~g9%TX`F(CR8FW1&_WoAy%n&ktn>>lTCAB`L*EA>8=Ig{yqB zGc|}kdSm_{_-oG5p2@=@m$bFG<m3h;IgDNvnUs*W{hb5g!O3cArTU1z?)$V^iwI$H zyWsg=y2&F*pH&#K6%#4Ur`-*bD;TD4T0Z4+`R&5m+$^@+U<2n+iDjgIxb#L4e!8lW zmDNtiSy~auh5k=SY8Sty?asUm-4YQeNh$x3T|glTbO#_keD@@qSyM|~c5V6@$9$<A z=|L(-4%j>?Ojab^+>#zOIiD!y4FBl-bt!zQH8KE@!ilgZsKVu?7;4WqoS#WlLnHr< z=3}_MUFFIZ(8JJU@OOW@$^QFy1h<nCx7w%6g8NS1zqBJ}oO0iTW~OF)yBfTV{uo__ z4$w(lO!>lT`yWCV<h(v(TfqL^JIu_?tYitT<+8t!h!?GS%2$n$HT-1nrRIgriz0q` z(eSX1^>!qaDCm|_{Zks;#}5cDA&HQ~1H{B-EzE3!{3ha2Woz!JR#u<@3bq)11ryq) zcBw9C8N|OFY0puR>6W`h9_^dGG&Yucn?2@7#0>dg|BwL56sfn>U{g=cw@GMDpleP@ z@K$}S6`215dcss)lQct<wAslYLkTx`ESH5ZyMeVrsKK4(3jVUt!pDRV&wqzh@;^Fm z!FSfIdOxiVk<rzI&|t}4Vo8P~Y+lI|EUV91nE~{akPz$d?~XcOW5d8;hN}3FA6hA* zMPu<tjB~nrMw8Vc1S7U*dpq4ntB2*Mr=LF?y0{S88apuY+Y1C&#`u*-A@zhvI#`NH z%#Hn(v&I_ghnp24iAUay_bI{GXOW1<HOXXQ-v@Quj-;3_iZfcjY++s&JWX7j8>H0@ zyGEzRPCBL5Ms}CS!;#$|u%;MD8U`C5K4vH-BcOaLqkzwDI$4`Tx?WPkYGDj6R!r2? zk@H)d&i&)5%ysFaGeS}i&icAZD&@b0!MTG0%nOneqq5Oaz^GIJ)+6PwsKO+YmK29D zg^t!{_|B$7@k{)-JNjuOW$9wT*cUv0_lddm&5cdXjJndjY5)F4&GH%=u5V<ry}h;I z{+uUrN*!i0TKx>*FTDi4<XUHcSIy3m3#-51+HhxEp&xD0X=QhbaM+=Htsb>oM^hV8 zQ~yUL6Z36pS^AvF!VM!+EksrtHXd$5Vk&%2G?*f-mE9h~OQ&s<m+y(;+B5HJ{a}8+ z<oJ}1ccQ*@>w5q{VA0#}F4H03(@6qnu-|O((Nh{Q)UnJi!aLb}j;~{)L;2`Y&h~(> zGx0=;!TkdYX(KXUOVhscA3xqVP<tD;MGVub7KSo_g!i7!6yVK&A$Iux@(G(yz`cLp zOHg2G*|0@K98H**>m5S8p%A!%tC9#VP`82&t4t2k9|q2hfI!2*a7Ug@bkl6?Hvy<2 zh>LkCsi+w4;fa<sBXZa;4_w``LY0}p(4YiRVOo1XBj1@K%%f;Oy=AWy`ji3w|H5Sl zsA}-~iwgJu^u+jeF<6GS_%xFR{TH^~{m)u=1MiHEjS-2((c(OnQ~eQK7#v#KCHJFq zdL8~;`~0V+o!!wy+pqJHwkNuLKdy`~%+9us6IC#B9z<@mw`1KE-7Nnt-x@$_q@iI{ zS!u+>Q(|fP=iR$^W#<y~jEolN^%s|o7pJtw61+AEn=hi0%k!DCDCN;tdb=2yLo$3K zBMU=9UI+*XC>%kI@8hmd*3#zM+NH6Y(d6PxySvwxkngFbR=&fo^;@4-4HbS<AcR1U zYaXO^m^CPXADDN=ulwL8wMC$Ghfvt_&EgcAt4EF$U4Q)ealEpx13Xr_xi_Svp5ok# zV6k{6LRK<@Sz)6*QlK-7+*Vd8+TL<OsjE7_a?xtgj}a;LZz8K1*q`B#hUG1zJA=2d zMA2fj{Rru;?G{|5;2pd8&n-s!e>G9=A6kma!w<X5%OSqu8uIf7J|?A7RuhN@iJ-?g zyI`oRU+%@gN7-nORIE=FMiYhNJ6rVDR)1|D?Uw1CaghiC)y-gn`wbLYSYTsla`l66 zZ>-3a#Rwe3yQ04)y<ty8{=6ZL+*z#W_V6i>1K<A!7qq(p*XUU6p`dbAb#$z`vA4Io zi_=2FwJ9blY1W(lAv0JrNS5;X^XzPy6vecpO)T7d_rQxxGPQH8t*^IN;hcejVgbCc z_LdzVKxO6YFwg_8b?q>Qdw6-^W+w`RW?Qo6F$m84*SSw{(0Y1$Zerm1Z8xSoohr#t zFVgB;E~vH=k(7+yYD#{UmMaYm3;(@~bFbKYv>J~uz#~G5kb;sDZ-xu=)>EFN)sFes zmClNn8}Izm#+90y3ZWeO9WfON<M@y0xSS6SL9+7fb@69A53z@|v}RC5Xm*^*eOvs} z!DH5wWFxwvs;1`QaqSlJ95_1Ugi|a|WNko32$<W=kvr|L5p-5%O|yX{<Y;-tg6BJv z&B#7cNlA(J6x5x5gxt3Kqeph*M34m`46tU1zkg<FiDp~mbIa|@vzs^zGY%W$H-nP> z>`iusNjgSL&B|ng6_2f^wB3cbE$>|vC{*5JgQU3L+sQg_PTg<MyX>e_uE^iJpizTB z&~nGN(hi<j&`o&>f|}jiLW@7i^>C|!k*CCJAaB=Ze}7B8%)G+cJ!R1_CkoE!Pt{6o zJqd|)Z4`~nS0$?Um~>qB2-N~(ul=>zHr~=@2>L=A_K{2tZef4&^6TvGUZ1F<^PF(7 zc&(&#ui0XvB+q(@*Q7t4fL{9ngW}A1to_n9Zm^f9=iU-)XJ4Pq_<*KHh3(nyQr@(4 zbxqC9+rT0m>|{<0m43i$-iLt0X3E6CFkEJF5mzHzYniED<+?Qu4sEnY-2}iB8+X!q z{@k+q1hU7e^jw;?hqiHnc!Z9IMgsAN8m{N36ZgsPU6=OqCyYL7N+uOXk9>Z9=JDm+ z$Ip*aFFGTGX2EsOmupl&i3U8l;G949?nJnrjQM}MaXYA}{K2mli^?<Cp7{(uhl<Tf zlpC0<RZbn_)zy6H8z47%adEC)@@o6+HgDBQ`(lZv>v*2<0r{8vJiBiBCI=dp*DOe4 zV_i=%=X55Vk_|f6AuE*c(MSLNwUIcI&i?-WWRglo#*+)~VYkzBwFb;JxHFb}Ey3?( z(E}|^SDd8Ntz-Ob`c|3k+R{W->~yKt6JG-6+804jB)PbjgDZK&zCFv$QW8H6ny{Oj zSvlz&rNc?!hqI}f<ieI{v!b+ap84hcloUox!8V2Y`2rS`nPX11cWqZkX@zXy>Le5O zUmpW+$B!RB-Mo$G=Z<~;{CyZRLV062F;7N=Za*fu`f-Kh-s!t_U<<xBoyc5kS1(h} zc=d$j5hEkE%iFV)i$|3L=u;XEXTZpsZt=vxe^`9i%h&fSOwl~zKQBkqTeK|5BtM<L z!pX@gDM@?H;L3*&{>0pvn3ya~41DZZB2{e{SMlhub!NbHqxEQdM^34DcTaYEZ<KvI zaUfk*o$v)~Vz=R9V~y)_XXRNC20hC=>vY9qj)RpEr><%89^M#R=*A%W6S_1M<W~wP zDCmn(AMrvb@b)ae`1PAl_5xS657_Wiv~lGcLi3_PZ<5~70L>_5#)qbQd*|f^oo2xN z=X5}3;9J;3rN;KAyIvUQXXF>B5QeZ%Tln*1{FQ*v`Jls%%w&TTKXu#n@q~;F?sv1B zFhYR`avWio9ys3J{XxiOUu?4y`UKKvvX&V8g}oyqO`u_{<s~2>$ms+EtP#^zVKNjL z4&L*5{Urt+#Psy^i@E{`iKX-BaOqKTGIau7()Mk(aC7H0?%%V3K{6pJ&LWFcxjN+S zxAZ6+2&MK5W0v?4_*ZZ2D$^9@=JFZh;^4e4%Jh;6PAzrYxKer~79Nt}EBWHZk5j$3 zA}JNo(GOSP@%hs-!Iz-lXAWGE!u)%Rq&I9<SbrRMo+&$f8ZR#ketGtE;+QL_AS49L zJo`)ZC5LKKa`UWU*XoMIR1Ms}gP3W&++hTacB&#cg^^3-HXmL8di2Qg9?4g>YXL!A z6SC%Xq&wGWBUt%SZ#Gd_i%^D=&M@e=F5*%v$5o-z6`4)k#U)aA%w~YQTr#rg#|YL@ zGA^}}y3294n7lj;ISA<~;h?%K_Zl6M!3+ci9esOi3)p4+TX;$ta&_I^+hFiGrxt6_ zJupDRWjGmFr57E7hldy28bNz;Lz8ml>+3PN%)j+eaVrYJ7181T9!1^eR$L74J1h;= zd59Y}Yn*&}yS&_oSIMdUex8Brwh`QB&oTKz=UPIC6*5$t(;-i1^<r~sGLDpqnc29k zSmO8%pQ$NfbATd;+d1FBdd2SE?&|8QemfM(cD$d1-o&j97rvYp-g2__0so=nDd8SS zY}#Jw;1yGk%{^Qn$!hS89ZXQxw1yB|o^(NDtDN#+oAu!gwD`;`7nK#!u+last1{n= z`<UY4F3dR?TClM3dTn^^?9}}}AQ8+oG_7@YDz3bpj1AJFqB%uH@-zad3ov08u~d2W z>S<`gf!VJgahe^`Jt>P{Y^bi^xNc-@7%!dg3@bm-XXfYi#en|S&CyU-2kY+UYIxA1 z5Dt9kqDKJExVuoTLMX`%78aIwc6LEbJm<lveSLj**Pn($(4Tsl?OEp(2;55(1*AT% zuDoN8F>q<-(`!|8j>g8qT6Y{*tJLmOBlTi@2iFP0luCSa_v7r`g2h-NDJSPi2d^u( z#@$7a(PE=KoeWj^C(>B(u_=KLZJ#J~&F|5vJ}j3r9<WuZcvpffu0py^h`Epjg(A&A zD~T7w{0s#&v{u?We^n}f{z;IbeLIdOI)AdMvyHZ`0eLk(cBK93=tNLbCLST6y*axa zF~3562R2r5ue-bgL(_C~b}At9`_sQ(dKVP<m5Yl^@-eM_?s^yLSO?wIwBQHiF~Pm> zw*FfG#e2Ph%)q3;{Sn)5vEdFSf?o<_Vvq%6SK4a1moQXreFX(AJfemIU-MhB4HuXC z)N`iK-BB)og?eTDaBHtWGX#g-o9w3ao8k2EnqtfQ%YEX-Z(m;SY2uF}O!j1BY>EgL zqsJo3?OwW2^^Gqd+d$EY^-R5+fu0^A-_Y46InpeKd;`MyowkmAMMY0}g;h`>!__~3 z?)Os$I(GyGf@MHYdAVFgdAGCkyP4_B`mR~HrMtUvY^-x^EX7>C<(azsHmdJuhw;lQ zZL#gcq<57WP|gL&u6&|^jXy?taCy}KYZ)hk7Q;uXU3+B<&C$6j>_7fywY4xzC!oTy z`rJ$v>`#T<zd-kY)q3bL$k)l<Y{KUM-?sl>%EW)`tu~@M{=_@uNo{I%Q@?(_ptygq zx=Oe;M_1LZS!RAVN3A?kxS|lM;^FC8U^*sc&jTohT9KLC${PJE`ctSL_+fA3l_B=& zZ5IXqsneanXw8QTs@)7o^R)`wwd0f`p*M%!b7>%Cy-%kO<_@G9<CRu+>rov<goO9b zkIFW4PtO}-;Xy{wpV8IX$!5Q~S-eFuT5Jos+RB$37n9PMYUHhsU|-Q<d&JDknEa-u zVZWVam~W1hcBeO2aEDqs%e&@tJTTv_p_oBmn49Bv+=bIc3y#bq4fn|_U0o@pqOf}S zc+XC$t7$B$B+k1U7<t3@RNlP#=3Lmw=dv?)TW2CR`!FjJs9{Y_l+;S;SQC5_wlnpT zmi7yo+)%aptnBQMShQX283;%{SRcxB5)yI*Z))UimX)L)%Q3mpYRBxE&v0b!l>X}T z&)&1i)$BvA#DEI^yq#^mtG7w5{*1T6o$wK9+`;Ieq@l5VN#2%6^Ygki27a%!garDn zTR6H}ZP86ZPog;8uGAcm*gM$Ur=+Dp9F)aSE(ZCz>+J=X6LoX*@#eV;SV>4(_~Jme z^0SEqQVoB%;*n%bWXnbw0C(>FOMd+Rtcwvk-lOAVm%Y6rc!Z|)r$d-wUD-;%*{ecl z@*5xq2!&vKNZc#tQA|_l8W_0mb@3`Y+hpKbf4>s)rmL7Hq$xo4(I&b09A&=qktJIC z*xIFc6{G9v7D|h&$;&}yHSNOJBJ1a7cg`<LDb`nLyEM)HewW=!esYdY@1{9w;WYED znU8O!LEZ8Y+n{V#q&jJ*scwPNJAYDCUOo>L)B~BC5bAAfX=&b{Z=|cMpsPE(HewgS zWd4&WH#~J{v1o$tEu;0~!>{iHGe+#bKH$N@9v&Q&h}x`V8-}6f@$PzGmL>@r+LxhN z*Ib*C!rk3nAo9n8??ZMr`27rCOx3iuwzeo|0`U9ukm^wiKF_w9o&Rx5Xoew>AudlH zjR4o-iJ@YzKc`Oee(sAV1A_Pk^qgY{>yWmdHSVi<<~JLUbBTp!ow-Mk%Zk!XR810e z>vTtO<yZIBrGKkk5Q=vWC|%4{AkvZsRU-{e%YwI+)PlH`<!g^f%EO1N!ULKeLZfFb zMhXnOfZ-TvlxnnC4Hn)jopECjalJlT!fD(ql1RTsv|4+Gh$#B&E;_pVHLu;(A%2>4 z)dB?D`@vgR!r4|Q-^9jh!csc~u6K%Q{k>@`T`5{ugJY}SZk--|A>z!ZtK=CT9v&$) z6)>2XYf(;eKD1Q7?O$J4%?8VfqsO6#fm>%yxyP5)^JJ%&DsIGIFIGhU^h^la=~NsT zlpUylEuZl8LdPI(>6N0bW^iU`L}`Sot;SSaLpZ-$_~#v?SK=E8&HBatC-;Q#mCqQ{ zz8fmh_c8S<((!Z%6_AZSr{%Uc9ye_p-lJ@yWK42%4>KFdXLs6<Dk|zYJ*s-@>#f0+ zh^4Ns{xh{!OZV%n2R*$s2lLLhuDZWczfxbCawLPz@Na&vk$m&S)I^)fUvVY_nQrV0 zjCCcC==KgR-v<SedV+dkSX*&8ztnM!1G&=1EBB^f2|b*s6}1@e|1LV#)@d20EK|Hr z>Lh=5aT9m3P~M5-D;K7AQgY2_3|-b3g9V-=L`;$={`vFg#fe+%)Rgl=_*Wwd(xQ^d z0x3YmV6Lh<e3j0El~uXibfB<psmH+76ajz=m(_5gncBu^0Vg#lK@D*9anZ`G*R6LK zw`O%!c+3XYxii!Xn3(Bb@}%;g>_--v^2ei5W&(`B!NI<~v_#ns0ESNQq8-S4=qk}s zP%0K2s^)sg?ji59cn-%0lNaO@=(YUOD|qWAkI}I1?6!{IAqqMCs#ea~OaCHJlyKaV z9nXjg{h>aGBkNl4+3q?9Mhm?(c_5>7L_`EEwS5Bv*x2Ix`?i>Ug!s(HuR@KyZWB0O zR4T{vTxDWn=857sY8}dZy4q6~R&`MWo(lv7c#j^cl^cFwW8heto}R%#*X{GNR!&oD zmc2VZTw%3h$9uY4bDP)1$fQo7!I{M=bg&Kih|9{)iEdMh6*FE#Tr@Z-Qk)W5ZYmi& zD!mLl_Ec<R!tU7-4}a^doEL7AaN`UMA1A1%S@B|RKj~>cQ-6w@<jrWi#j%=}=^dP( zGH59Nw%G;uG#>AcLcxg#(};VIBSRuW^>=oKo{B=xQ$t!k_WE*`;z-2p)7(UN$9N=k zFGqR`#bG$YSg9T#mrYvMP@vWA&gJ8_BK{87R?*u3zt78m)=_^?Wd8d{EiCTvxYXb| z_aV0#ecjvJ>(2U0TkajqcD21LqJ2}nb2jx`8e7qCq5poLlqBS9j9FUBAx0`7Bxqt} zq@wyA4SBqAjDE|%d^y!obuqX4N}l+6NhzDLab?$1+K<Uj@DjtpxyR*5I6JL?Mt=2V z@69IAWse%B^=?JF#~*g5LRJd)gd*Y8{@Bf=q<Z9DE{4d*6fd+4k(d~!P$Mf+!G?N> z5fC({Vq+R@{PnB4TEfyDobH@B)g*9<@e(tW%;o!3?bVsmH$GHFMUCbJ={xToSvxq0 zDsIhZ7v|znU-N3%9oqTx&rc?O>Cd>hRUHo&X-F7ZSy{<ws{50CVlp$!$=JvU$&Zg6 z;khEKw_Prpz_>t{(6j8fa2DDYnQzfE9ji#NYG(H5N518LOCpvO3lYP^B(pLzQ^YNg zkNz7q>*}1~Vl5P<Wu~_^zBpCALe26_BbCaX^})NK{{GM{6w%L5=7hyT-WHN5Sk%6D zM$9vwZ|1Mlwp_G68o4#)j^9U=IaZu!wGqd${>;_Y|735eKUYNu>eH0&r_!6dXLN2p zW44R2)fZ_47A}kn*t5!=2?LonXznsl5X3rf5qWNz+w1PG;>q{+^<BIwCnQqqN%j-o zWLgWN)7+Re>MNxcQ<N?63EA{)YHxR#T%+KsplvNEoM{_5m=#8gH@0Nz?F&ZPP|DJu zDAnsBZRjZ9+3&Q8v^(7%yD#MF3C33NDP}!FdlQ?PT2P-V#1xHSh9{R2n`?LU&b*&Y zCHY$S9>PS2t8b21K9ec{D}}r4ah=`OuU9jA`unkZdpqe85);YGlYErx2p({eC;wa> zw|gb2o)J+oc3ZPe=(#)JQP<;Yt#46*K2+7&@)`JtJ8lnv*;epo3)Rv+eKl&Z*nJ>1 zHVh`9Hn?wJW+i0MVnRL&XlZZVIQ~duC?h=j{z~1(bdy)#wSsECDdwbHs&S@mrx=_j z|9i5ou2=XHVUj~gaOh8ni;$Xghl@AFy;R1MYt-cAkh}JUqhmeH<D&>oZdp(%3F0k* zQM%nXz4_<PXY*qP1Vss%GDa^SX+0Gc?|4<}tUk3uWQYyTLDFLj@}oDSi`T`KqS#z` zsHpT8fAC=17CwrbswPOaSG=Y0@iv9;na<Wb$+l0HmMF1q47i}C<T-vbwCoEOElYTK zH8&5OYDmbSdkyhb6**Rk82oz{V4wfVOmJN0<9l%E<2#SuVZ}>}|N2eMk?;Xv6<VgI zWONRPY;cT6M_U!36h$yW`A)@iIgE8we`G(+`U^RxMHc6DHG;8U^KN%r+|(5$pQ}rn z)tlQS-n{7PQ_5rLPd7#k4ayeDtJj1U9Ld-`ju-PCv)%o3ZVoMyj*OP;0ZC94oy^cf zpNR1R?N=t)ZLC{Y?!(R!Z8*f=Z=|4cs-C#}lD^~tOQ-D0NN=$de+_;=xL&K;Q+CQP z4SC!}DfyjKB5a;aTpSRg5*(VQB4~0%#;MF{2A4M#_6_OXc*2q(7BfLzCG)rf@A{v_ z^A<&{eSO-$c1;&MU%Rm^#p<BsP#!I|t1*lxsa@qqzRef)7IOM6y0a~|vnRQ;)#UpH zTSG+^qHxU3Ju@>siHZBU9dC6k?4^Xh8$fxSj3Q3@{Jp2!R58M{G}j=flEq8RgIc2_ zHT=4~l0ZyJtlt!FkeL&c?kP<CRk)NlgTq4Sne}|MqB&HPl5%${0T1Y-KHV{6&&e_D z?aE(x@+9fxs81zVfIo}tV69TBPp*<<3$<<iLPrFO5_fZbE3f9lGiFW&s@I}>r+xk3 znUe#pnffqWQ|I-wNblU0C6_s$q}*!8W%6Qci7YUsEVsparcv7uU1fE?3Zp1?WqqGq zJqP7eoZ$`>be}e&!D{=iVnp?dYl;F}qT~5n!P)VZRA@4it1=#4ZmxZSD~=r<+|=9F zMygGk%OxYBfjyv*!a+rojAW&oQOL3@2+omWiIU`-RRAA6V)lx0I0*8Hg}NEDbuV4s zudPGx9y#c$VIz<4m8NhC>))@Ta=<Xcr0Y!^fL7I);k2?jQl2)kSJcr~Ye$-d!T^UR zR(B*XV2Z#7cFTc#qbh(y&*5iDTz!G2@sjaQlGEe(iw6wS%UBe5Yo9%sYI{#xw;!t4 z%9^YymKyYlRsJr!3ckt1cUa@u{E5{~D<zupr1CC%?)j%RMe@-3Bd)<CieA|7L1|eP zJ8RbWA~Tc8SsbTR`=x{m**-b3=uzijN*w0>>PS2I{5r?=fz}5X7C4G@ckiApz*_<Q zQPtP4juhzW#Zgl~X0uQ&2v(ptzdLj|k?c)l?|Aig2r5OEL5>)S&@9aF6;S@hM?6@) zk=RHFddzsXF=eWhw!CiDZ@Gq-ww%2L_LpC^jI%LD{!UOJ1@hoOTpO_khzYK}>d0#& zUoxJ#M6qV5iXnm;1%~Ky7Vn?!Hvj8wE4X76#4Qv57h`W3Q03OPi!Mb8k?t<(l5UVt zO1fJ>y1PM;Zlqg4x}+PVySux)o4E(R?|06A&)NIin}2IL>zQ*rW8C+3Ujg%uv;ZG` zKrocDnp;OGYZ`XPze-l7C!Z8g6Iy?QCZxfT)*hZq`gm%r><#*W*bgpg=OQB6J;U*l zq+=r^$j=95+kXyW#5~0)P-5GCUc&=Sz?B{}+pen}Jwc~nm)c(y*r}G3kmk4BGS@WM zYzN3KYhG!7zFJ&O3{Ya-mu&L^OjVg)1B^0aPmBBL$jL9;Iz!~-K!ONs2`D>HQ9uX? zA-}8QeCI6KL^ttie(5b!83-s6@}2;>q&kM#emKEA(4AuttzM-z?CqH%>`gO1#pw<B zuI`TKf<obf#%(q+cVi<)E^Fx)3}Z-1$yy$d0_3um2mAZowlpLh4`wF4Rw8LtO43@a z%Y<_owug1-`ZZ!_TfYbJI2<`{4b&yqSYG12zo{7BrV5i)RRu{Z6LMB9c9(Mwv37Zp z!5&#Lr?TRoKjWVd%`k2agarmBK)QXTwOki2FBEaN7jEH&1Huv>XH(Xqv4+{3Y9ACn z$o5Px4|^Sd$5AjEm~}c)rPeP|t=PRA<Z<F9a)<N_b)IS6BQmPjOFY?*iKZ{Roosk( zW8X$}_AAJbcgZA@Bcn9UYCA%&T?=3uo0>d(W~r!f2ne)*?1ghLos-!Ewd|H`;OV_p z!MOEsey!u-dfnD9O~CDbGkUQuilmgUr`4w+M80*neh=j34UQItI;Di#nHGdhw)T&A zm%!nffyijHZ_?7TBm(NCL{jg$$^l;XK|mjtj;EjE_#7K8fbLpS&TqTN1#Z8LP4r_8 zuV!-!nVRlRpEnb5T=Biql^Bmhr)&y*h=yc+)4`%6VE%bs6hZm%Q+JVO#cbbLrcww+ zXZL5Z&u=0ET_KA#M@tHxpWO*K;uVY-0^4<0qw-Bm(yp8KU222Qoooug6^}{|@shkQ z2aXHW(fl818PNGwx1tlrr>$lZqN5f1G@M;_$2JA97^KC-{+!fb;%RAWcCaJeUF<3~ zCAEjAHb{6CGP_-zj7E}t@92RWxg4)ol9U;CJ3|3;2@t4Jgnk4poqkFq67ZAqigq@a z^*QGOzF1dxrx&Y50X9v>)sh#a350s@>=@s2F1z2i&u1-_S5$m-lr=fqB}b!~%V)uw z2W<Z=Gf`n-D5LJA^<_MVt2T^S{UZVUMi8h8*p$J3o=8MGO*ZqhWy-Ff3`KsK?>D+X zAWQO{oMDJM-%yQIRY!9^P!SuS3KT*f%sSh<y<eh?CU0j$%K&@F+uPS50wyNDwxJHV z5tGVNZPLHhsdGi>{o(5?@^-nwsnjUKGPuIQ$*DnkB2lSNBUTNhwtGJ9!gQiSz-)?u zpi}pic#q@5$sz|dG<5L#Pkaa4gBiG0E}E+_r7q!*l9Fck)q@NSLuWs_BcK3AP@r5) z)68pkrTO8@N^RNk8wm9)rXA(+(NWKp!+@VK<kI16%?X#fr%WK!#QlM=+IUK}3?K~l zn{)IfL*XDriead#gUk8$2I*j$g`J;J6n?F3W#oN#(xhBkbh6t)$E;jC3>zq+`J2~B z$iTSw7+fj1{XrO4aD-xseD<3;%8QJcGfe*|IyiVZYg=1%BRzBTB2Eo3>0v^X?b9fY z1VbgDQnf$2c(-tCG#iY|R#0Ox|H*_E<fc#bX8L)-4$GBU6`c{#Bqk=BO<U}YWk)Ae z3kEE1>$u<ETM5t_*l6?nir^$BQb3kSV-X2>{0`84-nobyJ9j*M>^F4hY@L{R#kgq7 zbAKlwB!-TSE)Raa>WcBO`Lw{20-l+W<e;?W8h<2K4i<~?0v8EWQ`=|w>%!k9A9N_X zf_i$S^+HcA&JGTId|GS{Rq{*nY|-yJQMCvNsxq}><(FKQG#j0F!ECu$ttnHvILZ0; zWR=YRy$7F@^sa)ESZA|bpH1G+EW5q{A~n?nGI*-EfycY#noo$Oz<TyX2Oc5h!`E{v z;*t4j9ctlxKrY<|8_CXMbo@JV%2M@)&bcvCF7l6br`Cnwc1Mni{@z5tr8eDu*&JWG z-2Tri`8C)ct3(VxwZK1M-f(_?W7jEi(dClw{hFJ{dKMQ4C@uvf{&_k$Jd|)LocUbf z>*q%s2YRvj`PtZ~DO%mmzR7gYtIoTsLT-lx;y6I%bpeexvcO}VHPch1HmB_dHuQ*5 zE~l=a;sM^ry$n=BLVo)jjY)ibWd?|-jt&tym_IL880i4DT&>wq8V?bmhImWHGr%)y zEo*C`>=U1}n#(TZP9DhpNQlvV@H|1w9d<IFmS8$WCramZ90-hRhb~%fRG_mdQX=Cc zJD;eNJhEhPp8aV_aIwbcioc_NFMjf?q${8u+)78;X)wvGmR}XB_5iA~Ne*rcK__tn zr)%)DB#D=%@qsilzyKs^9_a7q@q7^39!dop$B%YynFP+;ozZoet3ze?9);ZS=fKCS zfnM6@1L+4M#xJOQ1Z-Zzi#!*d;aI0{q`pZ{r<Hx@9YunVZmC>eyPl(ui#u)iZk>1C zF9d_hh!5>=_XbN+=cqAB6$`e$Y#*qic~5VearkAr|0oPu@9dxEUC=rm``aiU4f0%T zrr?9Zgyu|M=F!;XN%OrISPe)7%rkv`%oG%ky+6G8lOKa-UdEnH0lMY&5zh%&+F6rC zOzt~DXp|83v*FwdL*f?|wv)IXP>&?vVe~5HmkI`6LP2$hL4LYa<VeQT$(x4edT=V8 zZi3Cz_3B`$K}9BGXDS*Tl@^obTwT;oU{jP3P+TH{2#)83QA%U$sH)Z)pQ7S>nkg5{ zy4q6vsCU+4Hc*g~o~=iGy*AdL4)n|B9m{WPv7Y{=+Z2%-y4-yK=c&DWG-SG5ZT*FZ z8&$aVQCn<I7~T$`rlq*wtTe+vsgGuwkX`K6PdOsKeS^WGDl~cy|6cfF3XEM9Md;u0 z&b3w-MF?`MG&s5m2&~?w@Vb}+a4k_y4OpDs*-s6OTD4pb)NDbTKTNUM-uXHYbD~1) zcsyFDIy-;)A{&M~8Bg~#4rm?t6)`n^hlv`GDU)ZXq0j8$V#S$Ko%C!kdU+c2ncCUw zWe+lF8L_yDyiI1~m48mtY%(-4G%RU2W_23{o&rj&QD}B#T{0xN6b}j~QEA!VQ{`Fk zVC?2aQ-;@0l@zP`tUQ|ob%*1lqx(>1_}+*!*~&M@w{W_!(M(xzZERz?KR#Ned!1!? zdpCnpYnX(UbV~p>O@zO>c}QBC=A0<IF`Ehu<>=`r0rWhkv3ZjDJvaFB0Yd|`RPf|o z!Hn?7U)a2GookfYDdYWcX+tS3_;^?X=CV4VkWNGL$%Py&$#AGl|4=^#Yx}FYxuSfs z3fM54wo7L?`Xo6O(X+B4djW?jrjtAKg@xcFV0i1KkbvSXVOQWm{0oemMpLHf04U?m z^$C4;3~rFf0JK=3`v1dpGT$iQVeNp*P>J%;--ceYKV?RBRm$gZ(se32bE)#Vj=iWf zXo-)H(xPgN0=0kiw4JM5?B0IksDP-Lh@uOa|GZsX0COc@4)KDTn$Zf+-VLe3xF35R zeX4Oiq2j%0OFe(<bS?^U<?N}h0W>rer8j^;q%zH_qq8dYW9!i3W?*F(;qP<CRHw8y z@#5(J{Z<uDa<S^k%%C|fKz|1<Lr7Q`6x5ddj)S_lr#<V!=3k$0Z#t4sd?z#FVA^r{ z&)>JY&6KG>sdNnr+!3JspGSAAgUJ6iwlm^Qx(zFcli&MgL`L?|vO;gRyIcvLOg(k} z(MpYX4lwbbOXzQv%hlf>0NzfoUU_+ezVy#FAMe~kb8*Sz!E&^hT|ssXH#HqPw->?1 zduF5k&-YU$cUBXC=e=?1K192IDA0~yXqx_5;tyU6Qg!xFo$8;ay@)}3B$Ghgcyts- zq+@kBS1uymh6g&N>7b;f_Z2M%^SbFJAw#{i?skaJoyK<2LYvIg$Bc~%!8m|5DIsp& zTJVe;4&rx(HOQ7~xB0=h?Zfg>)E<?x+hm$VQ;^74-TxOBV359dSrW%QC4SuH5Bfe5 zn>v>1o}`EAC)s>!iOYx8;GVn=UJf^ct6A{Egg+V%H_j@`8*@I7Iyp}L&(lR`gUybv z99Oqo7q@K+as%jB6KdtZLb)i(OBJeON~IfxD()fJKT=h0Jh3WD1N#5hO|1WoI5B_; z{#kU~L`oAW>yF5EamjXd$-ceW=<0+6zO9myWKK@PPEJ|%4)hK7C~3p{a`c-e(P(MA z`j9u>AG+(IA)hNT(vNQD@M$ngocVGMFx*dMI=C2TJ=O|y=NyWyh(TkuDf^-oElQ&M zI7dniB{5dPSU=}>o=0hZdK4?q9GPWM9Sb8dA-6F5Y8a+Eb)N~0qzgo_c}L+l@Z$KM zjst%tXuhqn9yL?bXerA|OZCesPQ>&w5s@=B6jYSgb{1MH7EJ`Bf|5I<%-@C>#Te0t z0Kd&WP5=lKK7b|k005%FKml<fW}x8G`B|QCT5xNl6S7(?#d>?+238c(cS=`rhFimw z`gl){_wdwlGcmmO+i({#CDlo>WfXcj{#EuolWfL^eGJm1nSJoBXkPRo+R(3Fg~EZm z^zy$a(f#}Oj>PA6xxK-_d;_Z1NrHp72)76N&jXVRF~l^_CyyY2A%Z`fQ@APRxacJ! zeO+COzXNZazHti<w=Hy#iSzb=$KD(ivfG1+)Nw}J8@~RZW@eQzmgy16e0}}rXO$<X z$N$Cr6C8FJR)8!mGHN#;Z9{6SL)NRc?oqHo3I=e*F4VuD@`t|59o9;^Jbf4Hxb?8P zu%LNyYOz>WD%V~gK?qZ2w%Dk#ef4)FUieANnSZiyHo*U5j~*Eml&=Jt|Am*;#R-5` zL7{odNleAZ2eq!*>{#Itk^@@-93@VV@^tO^Qw@I(2S@=T;VA8{ON&K(Y;18Z_=&TX z23s93?~28HsloiyWETfqbr{}ci}kJgco)J*h|!my%he9&vHR7WQ$<I6YZE`y8o-?@ za`DEsWI(~uF&xtV4VMjHZ+#7-S&llJQ<fFr#c5JR+~avwCDm^jU%JTc_GCM+Ja}4e zP|*eN^_U|XkH}PJqvLsQW~dzZ_oWJ`y-v^xajI5IH;1Iz4$TYv{Y2H()LHXXfJ4U3 z#xDFCYzYJKa_&{JTCkk>$)Nqzr03x%9iCixK2HV>Y&{K(44yG_k<z3y`}xPS`yYT* z?d#hCK-4TzM8Tkj<dCGKISzrxjQot*EVBSf6|0}f<bz49z#)BdB+}0qG}VcZn@E9W z^5bKpenzIIq<?>F(+Q!rECTalzinkzRcw6RXGC07LqogPay%T-LIYsBjLjlj)Kr`k zBP0Lx(tu+rP|UgWnFlg6TtPgnxNZ{pioY3YSgT%LR#sLk1KCE&!btS_VLP#xnV$1Q zopo^_@}M|r@?UJyo{%?bz=p}R;eGGlt4YSf_}73V?mu}2KHCUsYvBZv9w)?u-IRmV z9F*+J0Hy@whRWiix0+gE3kz@gc#G<tu+oHY)6Zkl(~kayxg}9hJcD?ama6p6pCa!} zFj#cpa)X?FwWWJ3d#}FU$9~gmNMUTU5Q#$OO0~SB(m?X>18s$ayYama=X5zw$Fjjj z?@Xs-3CI}4S}s1hzi3t3rb?~s?yLXxV=|d7)(<W=Ao1V))4my){?2JWqvl9rzB=@o z2)U!=l%d@;#bKGZzZ2tuYCoS3kLn_oC~wq@`uBUm*e<irpWf*85gGHzoyihKSX>-* zPJgDqHr)-(Rf0_yq$>)IDT04xWn`2>dj{14cdC9Gm?oXAc>fXyC*WVa=<mH^_Cm|l zWNGOKMbwoA&))&g1-IarbG`4mDYcyZaM9qY+IasW<@)~L5jmb*F!SHQ!yhj;v;Ycd z2o@tqkcI`EWXmJKn6R_e?kbnCogQZ?@zuDNgUfrP2wU(vmaOrH98i7bUb~jHDgezu zV3gJH!&gUV=Z-lCJoOrrh~GIE;=tpo1+q%H%JnNJ2NCZ{Szf;UWH}LFD*f?F=DUyg zNOKN5jT^@X;ET{1ymuUlTm^qZAE``&z)Ddp(>AYJOozw9!^SmVs?-MUIb)6a;?>g3 zX^o{O6Dup7395h>1VBJ=rTK{!h7mY?rhOYozL_Zt7l81UaydISi1)k%T|YL?tn{8Q zJxUYs1V*8~C1MA|D@DM^pn5}aMZ{UF-_7t=v2bgo#j6E#F!}Lr{uuBp-oPUfolfn% zc)SO>S>`}0Rn5*08YGPE-|n4#M~n4JrP_xpt?fWN3{qg{8V%-s1hxR8Rie?d3Mgn` zbO{K-)H*L>C0j|sq>Mp}J7j&K(S??lwood0D%dRi2jINv)VqHa70m_BBia%XNGAJ! z))M!ySZbBdW;V^|egi5U#5Q6wGBTSV7289{3w0U_lIN*RSxQqt$?6X#(H!T^s5%At z`Ga>~!8qX84XPa>ukp89^sfg~Rx_-J?bKk`%X`tSUImD;HhUL|dy}Aa@ED$*&5t23 zSoms1w7frE3fQUGHYs^KJHSmd!xeNZnbWwW0pPkdG$0U^Wxx-;zaqkhJgEYPq<M{2 zmOldW!ojlFdjSER>h}(pX?*o&rhTOBtS7Ls%{OZm4rVGO)`{<Jm~n5KJ=~o3r?Mq5 z%sLQ&w_b-a3?hEL%YL=HKOm$aA|Q1BS<MnH+tjEz{O}<sH}@W}<%m=69x7zO)SS)i zYWwU|iGiGqMgM4ex#yTe{bZZ8gGs{dnN*hvbvm8yrFk`ss(=>l3FQw4e;Mw*V_t>> zDFzl6AR@KF>BtqtH>%-7PNK3{1a9p&0(H^4T3W0}bw)>-I?aSZ1A97Ubq=YuS<g`g zQKr+CCTKR;c0h)V8UUDU+mL3E+W4W!+hy4ua&xMGV94fh3H(^dDRX1WMPif9EeyD> z3#|ZYyVC|383u(bf;)Dns@k*t6YI`jdhn0`pa;*a>{iUCUmZ^yolTfH?6Ko>n{RL| zKO*DeQZy?St5+>=L-vlgf>jHgO4EA6HS6tX2PY>-%i_G71p!Gkl8xG93kH!e39w*b ztJ}y(BgyZc?ycU_pNRvy%sV2{O?kke$0SN8Uh?q64+SG}<zjW3!A7kHb{%(qy#1er zS?8mb`C=lsH#fmnb@lbqcVAvIn=TI|yKVL<F~QygRxt8OmF41_e)WrOA`k{oGwm|C zhXI&2u;3Upc^Yb1$E1Iv1xSc<+(hNXamzil<il>jF~~UZaQBc@%j}bSrVtZXnOzgw zq!92pA>r_ffxX+c7`QkQXvqt<0$BE~Xd9dt_*QTy3!OaXUML|lR?ka|isF&L)(3!) zUB~N^ZU0L=;CbnGu+v(gQ~=-uBEdiY2+1H~73$?nkH-g;JFz5}0K`L-z%PHMr;!L; zN~+94HXV5Pdb;K6&^v^iTpa<N=C!X(56IN~#v|X>5_1U`8%VY|T@S#n8!;LNFh{iX zNaE(nVlyn8KOHmJIBX&UF1NQcXasXLSp8vPVG?tg$puQ&Md~(>cVR&G`OH5DdEd46 zyM1wkc#+X)5>wfBMlRF2K|$i`rl#_?w&Id>`Fi)4hfT((KX!>^geQ!3b;EI=OC)Wx zo#Oclv-?P0vQcBO(_oW}t^ItxP-T~_Cz__n_#pRMworLc&MNHYa2hO*<><u3I-7Mv z^h}52(Td~ELcm`rX4ZYEttWKo@GKkK#M<Z&C{)!5fdYbWy_%n5lIIW<U2)0X>C)qj z_JAmvIl%Yt!v~hYL{h0&Og<6ygoFyYpFdSbLF_NzA|O0fN!-3xeeo8Zswg?f&_vFp z!cYp}0TEQDPgVk8FWNlYr0q-2|II}crz$&#Dmk~2#^(mqt(py<9@8a!P<PiD;G&lP z0bJ03Gm-z3ef-|}&D%GoW0eLX9gyQ<K^@dHQlLY})~@kfr)0^6G<{`igT3I(<~wW> zLd^O3`vZSac!~5gEQk;I5_pAca-XW%t3iI-*;6SnQ@hn5r_ToAzJSA`GkibQwjksQ zsltyd2SLM|5W2_PT%u1Agnka6IMQXA&1h)>>0d;Btsl_+ZY@@VuMQTcy;hJr{}_*a zP#cp3Niyw#j4;Y1<NCG9!`)Xtw!Gs9`|L!=E1V*rt03UFwO{%60-Ua+$*ogUj@LsL zI}d_bgrt<G4Qj*duc2kw%qEP-Do<gebCy6e7_65BHfs7MjPQ6v!<@uKwY3Bur$ab5 zSH_r-5cvAl%*?FLc)kWF0k<P}Jv}{uuN&zMeDu;eeO+ZfyU^QfbE+fBgilBq9x1kj zpfV;u0zU=l)`0K~)<Evf+sg~&-km@+;M(&5<iG5bC|Syo5o*tp!J=(5T8De<B+X z2S?3~@s74spv;Z)9c7f99Bc+SZ2=1~v7tc&Xi!cp!O}$}<PEibl?waq-&c$SNM_(3 zO#`!=z{ON>##+I?`n*#R?I$}-zy-%xKYtW)+rrJmgG9)@(5zlOWx;bW@APHepAGQ- zyEW3i_}%)aioXYh?u=C#85{2ahu=>8ATtZBjVag5BaV!n5OY2^$Ll<WT%%)8;5m!W z`n%<OK|@c}cR=CgLZuP*58n~^($h^OgBGokP4^lY=K5j7*QKwqfco&^YTgB~7T>QG zkEYh!TP+qC9L`k%4`zwkF>w0gzEFwK_F!tx(k}+ln1v~aV3@IvwwBCprqq;USIYm0 zf^NCkDA<^8@^G(@qNsbO+rD&XxTLwNCZVoJoxD(`fhD2^R`By}x%7UrfQ$Gwx#Fv; z$P;6j`SPoW)IzO>ru1}T6z*8}NB2W>3$UDG`yL-3qgcnr?^U#OfB!~S!-0W;aq)RY z;0Utm#0+AaiFE`7C`CoH@53b2`|=fXr>zzmEeHF4Y{mWffs2o?nH%o5>tsj!tUc!7 zpxs3IdB!Dx2y1QQ$o&32RWsbq4?ruyO4AP_x3JaJ)J*pTcFA1%_pG(=K+Ph)Dg~%O z{jg~?co!iqd?!z<x#^Ib$C|hTd6Cj|UtiybwClK1)yV>ba}y%z=lgPpI=^*1#6wYV zb7OtIA&|0j`2WEI_N#k|KD!H(QfBO6-h?Hy^Gp@68JxX)E;7^FlM`IP`;q?8-+G?@ z@4VLgPj2onzHRaOG3M>v^XBJ&*LHw4uPpxcIP`CB^`Tk|z7SYQ7X@OMSM2sq@vLxv zNyDyo+4nctO(QG4dD5v1zy7}0PE}-lin(G<$uDs*%#7o6{dIp!uG#o6%JtgXaH^!& zMNg)k5zwQ#iBX_`HPA9$Y6R`v-vXSbVP$o6Ylwi2zPMZl6&D4NWnY2P-a)0PR=_6n z??d|P1$2d)s?5kgN|W}sq9w4KZM}Cq@N>PK@%qd4O7XSZ9&&S5On%?`OB_wG-j@H} zc%{oZDBF1xc)3p3K7ztKi`xN!TEF-y{#M|dJwahomsir~S3{E0LvLY?Y0GM)qc+^q zVmeZJ6I~&m>Z5ZT9i0H=1pR$Pb#`_}1J6_F{$#XkKyBtoU;^l9z;_n7gb$l`Gw=BP zsQ<6{?LT2T@5&WwR?<)S$Sps+|6fM6`|VsK9T|VYH}Fz<MMAfEFQ0!f@&D|e{x{;f zf4{!-(h4;T3oRvw%mXbI74nV}2udy~&Zd6a-Q9gwBPtf0!N|bIuA%;@s;U~f!^PRl z+U@-Ip%nK(l<8`4s8@1OtellaPDSPU{>gi_`8KV*+zy#bEh%|t&lvuKMz|*=mFlRw zsOTVYM^(~J;Yb<Okw0Rdm5eb-ak^Ie<RkkZRaCl{y13c-#n}gLz*-W+=q0ewvr3Ki z%l}YHeXvk_^UJ4A==pmOj>6{+YI1nlG(|TcwTAZNnblA82?z|+60@_jdl6Ho)6z=9 z0mtl<;onvpLP77`H#j)HqO!O2c4m~T&gHpLdQ9F}flH+HUixQdwC?Zs5FCXGM}m<t zxUxI=jbIR9q$qMWW270tOCA9M;qT+zzk=3O&gL^2c>e!Mw-~z<6b~{TfcGKbBGa4r z0(c`d63jHa&dz{dj)jy|$T{dGs9W4U`uROOEdk2_MO;3}Cl~kzfnI1T-mZng#1}Lo zp^-5$nq6niz%1hljJh`%jRx-yRx;Y#Br8oX=WfrjVmuzU7qr25;7Z7tKY!FWX-2QX z%IJ}z-yMFvKfQgjnq^{Q;_vU@*1xuW?6uj)cH0loY*@x=q-8Ha9s$tE8u@D(vSnNX z^c9^uP7qKv+hjKnoKPe1x!CP@zLfn2ZlQ~J2tbBfT~mX1IVE=6Lmo?e+URtA>=j2Q zuFyGG58UI){E-xJSErXf1#H$7Rh@4FYd#_EEMt+GFIG2&H@Gd<69SVWF-e(-prF}? z<8MIFG0vYNFROaeO$4v6rw<sW7gu>v0GLV;_Vj%64@)l5Zn6ZGcZ*Is$U2~*Z=3JF zo+_TtTK0r*2L%DP3-I?`)4=1f*qy9ssHu@LRaYM-T+GVMLc-^q$kz{e9vTmeS&i3U z&Rj21d$^5GyPT}7R%{O!!kNPI&DWTPw1GaV#$>T?b`}m;(5ILEes3k)!tYPS=Nc+j z1}g36RT8UWuv;zc?0wVK+S)7{aU>c}5FPJzzla2j$PYPC5P_;N^m-bw{RkRUFtQ}# zH{VH8>Zc4Psxh6MyToIs2^+7mI<{P_SIpN7o5=&A^i;FW`tk8K9MG0a^-W(|+w8U( zLy4}n-Q6E{n2w(w&aJ9UC-J$zjtsXv1Sfn>X$O?|rMmUob);p-y_u(T#x2qfd3E0m z@79IVt&CEHc98LSdvu>JB;4+sxm0u8!uXzrrNRETuWX%C7L|bD@mipNYv8e7Dp~nE z^xHqA$RA^yo0dHwWKRp4S{gN$w~I~!PwWsR^d+y8FF;GW1`84;wVPa1IU7B?hw}1_ z|DFQE2DjCVqx#(q4*Q|rmRb#=L=f*8J1lhkM!ikbi!3hgsWu{JzT?Jg{x0hL###YS zNU?sv6?UFNx5v#%1{Q-RF3X)oCknFT&CLz&4&HM}`^^SQR8)hbC7|;GPKb7U*P#Df z99G>%b3s5f0u3pX%UH+v07Q^Ec>PeP037~{HENQ$&ew;x2lyP;^42~VDA`#%6noqa z%mQ~<!15SfTs$0EB_sNbACV#px`2+0Sk2F$4>)wZ{2~$CPvK7WWR=FQ{Qdm0+&j-& zqN>^?jVN=|n(h(sM~H&TbUafbn<>Nk`s*O$5d}iRmy?m<U1y<M^9l4RncF8Xzf-<~ zF`nyOZEWPd2nlLeppY`3uMQjQ5se_!DO<C8TWL8dFRXA5Y>2-@Bc5Dd7HT&onH|op zaf1FM5DMHcf&xi7IaA>T4WM5c)yKfcH#h$JPR#p>2PiClmzM*vSf^we{%!7j&9UCf z)FBVFKXiXwDSAH|8X9nLNBKuhLxXxKSD`x`q$LQR*aHTO%lQ_AM)k{9w0d|T^VD?D z&}wi%fe8%_9g`oInAN^$)x~GBeQD3Ox4%zzIFaR6V=|s2;EDh34`N8I-832wqnVjm zhfLtcUl0V5@xAj|o&t=A?%D~s_cz<cBB{cFT=)^VA~R?~ycma0*UMLc2Lc>5no9<d zG*;2)YxZi%3<KM;=~A82kLQMDqKKmJyzxVc{o>-{+_7&7ZzbPiz45~q`z!_w{7t5c z^4%+e>=6ftdiih(F#DN~LqBR7m>JDycr@&?7y{#4;@XGZ?&H|5iPr=KxBU+fKJwKZ zOibchk2*oLuUvq;li2qvlliTST^67iK_Fu97#O(N$R7u9_uQX>qhaT^@y|*=fD|5p zMuuJSDkNych{LW65L(hGnipCiE1`)X!?E1l!hDnk*sEB6`SR@yG!r(yKl)-p2wVej zfWYG@!q6cVQQ%4fD5apTw=4sj>BPy^X{?pHqa#QneyfL-J&MboS6W=m2DyH1p<W|& z2Xi{!Xw@RDXk@OL^I27Vet+dld`gN>GgrrFXFy}Z07)fXIjKAjBHJrj0TG_}m)kT- z1);c)C1FyNYAnx;CXowwnofju0D%bUGkVPyYhYb0fV{ltja6DYJOrXngTDCqc-d&x z$>S?QqXL=+AJ)%;-gNK5vB2-JSJ{`{P+R*`hmNM6*GV1;j~koo7ibvtIH|c@)_zed z<a%hjvleOBlxP8wxWBY`qd71`XIFbL)KrV9Y#K~rFV-ntYWwH~_fcj@^Y<6szof26 zk22sQ0JeQ0nDp>)_MDI0@bfckYBC|uw}g?ac<XrR?zn_2d}8uKqh_boP1bgS<hHb! zXhyR6W#8sAHHFz;1oA?d|H(N?S}tB$d{d&U`C8i0&=9B~@2>Cyd-S&kcERD)DQZ`I zxVG|TxzMQv4vi8Xb#`v9M5ksi-GFvvd#1$0NS`cA0Bb;n%Wzvd6|8UMg)g;c@eF~U z+>Uf+l<MO1A&Et5O>N`j6*9}-Qb|>=7o1;u*94-(+BJaON3b3~h`|OimD};pTI9vE zgmCBfUrI^!c$))IhLuNXdb>Y9q~H^<g)Gi1%GcqKNduvA_3!sJpstqyFnHiZ%=ho# zgM!Lr8J?byfa)1ETz**jzYaf&YG=r*X1O|K2tBGaB!l8-OlbYa^p(s-`pOZQnalfh zm6h{u|1F(k|N9ZmSlan7P<7q#kX+!lhhq}q04sKp;9phYz_|6fWNCWwJFBeWxz@Sk zFlmjBi!)^Sp34E{Sc&;p9HIxLg14_X9}u)$tH2ogJs|jrD5d~~;|CcI4n_f5T8*F6 z>W0dWApf#Ct>n2NhEUvwf01N~uI>2ht!-ul*BiG*@qFZAka0Q7tEg14a)gD+pzg3? z;H4W|=oSEHBv35KF>T&5)R%-;1KTN8k<S$O$J&fD85t-{z{ZT5d+z!9`SL?NJ}3gS zbE=(`?~Dw#jq?ft!{5{ls7j4tFA9Jg9`G~i9~|swr0VJKuc;~18v@@?9{MJPJGMS4 zDb~-#)ev)TvGU?G>z~&Tq)W77T3Q6&jBPpu7W6D=WX}hZ#AW01M~;zkjElcB1ddlk z8^Yj<{tt@8|FvQ;@?qW)2p5uT4im3>7m#uWwE-a;Xx&ao`A)9d%Y7kY($Yse*SXYj zH+KR_52xE_@gWekCI_Id>B)<ZnW#KfFpTA&5A4}VO!qpUbZU7W;0wptU&OTx1ML^X z?6d80eB&!(b2FcgnZo6z<{VXh%>QjYmrlQ{qf084Nz}QuODZWbEiHrd=MK4|m;sC9 zSg8Eo>hx>L(&ff1PQW?Z0%JRi*|OuQMK_SmcyriY=UA=O^5`N6jO<U^CW?;UJFK}0 zWv?En((;k9@G?ud?;f6?03s0Q!SzX$ele~=V(+e9Jhzki{o#Td7^A_*c7ajc`g-~+ z889lclr0TEA$2gGFV{J?Yy-uhVh^qN<p+^>Vu#hjDfVj<bzBt!wlu-0ch|c|*C(f| z>$w34dv51Ld}#Vvw9}Tr;g!AU_?aPRgBqjL;K{>6TWFGXcQ{|In3NG8(E_v>i*DM2 zt-8hPtS0jXIB$-f`G3FXXxHeare5T(L3#t{U{gXK?tb+=0$gykP-iuj#UckxLD7hG z4|L?O76weeb!6;V6tZuRfq8F9z<l^3Oo3wA-gs6>wqIReek3cm!xgEzAIMim#2M+% zDR4NokdctCv))xtPt*F%yu|<H$gU*ZPWImLgDfn=2*~MqB!ZrBbVL{J8i>FbNKKDl z2Cl_`+!uV#<$SS0Fnm9We-I993L=dGT~6pVzbn3K=bWi*OIlagr|hE8zQaywF1OV; z@_NvBcfcM1%}L5!^C2TEH?qRU$)S~7VAf+7r*O(b&^6!SoKlJYy4@-yGfRKkd_j4+ z-J@gVNf$*9B>WoYfK+0aHAq>s5eqZR{ncJ@>_Vl3lcO}EV^i(VF{c;o)gH;1KraD? zfPu^)?}On;R8hrInSIN|%1B`>YJGFvY43ns3IPEh`wT}f1d)h`fB-EdTi+&+Pb5>7 zsc{oR1z_qwlbvww+YFi}bHBWs)An=_<<<1Fqg8sM){XXR>kjx{MZ-S+7Zza6%E4F) zSdEvw3lfPEn?9MD`bdOa-c8>|aFTxl=K|K)G4_JO!T?`?(e94b^>6A0YVEo^KbwOU zNHVZdFc#}SD!8Ps%QAXuuCh2kY;YZL+EntvgkSAV0quNo3>ne>x5L5SK?}$Q8f7Vr zci;{J1^u}%``EyMBB&4)TT0?<h@g)anjqJ~mta(RV?9<|$YH5d>rUXOQo8&}Bc#ji z!!qGLQu+tQU#!A9Edgd6mZH29g>K#LqA~=W?m|?10z&DCNs)$Oc<<g(WH^ZE%3AN7 zP2!Ely(L(1I=|wBRU46iI@u=$sV@0Mjb>lJ)*A29*i+LCLRO-p8?Fe2ej8YroGuP~ zWoD~zVJNTM<lAXD9$3f@w@*ye-uRR8-fc!aGbBf6Y9}49PThRlV6;7rc~VnNmzv#( z7>W21(KRet*}J7v2-w__g}m3yHrG_)rShAK!=m*O8Xs=2TR;Iq(IfzkFy_?qpw`!y zr)igPy?*R`y9%Q(cY6+bz$*+s*-uW#{IVO}6(QK~anYe>gJ^ulQ)$NLx)C|KU)>XJ zl=;HL^^4l!d?h+rY`==tC-ksybn9If4ct{gJg;;v5MLzXSl|>fG*fvC4-q_n7|{CW zNU(|pZMkrzS>qCLGd_BcL@+)+DL4~Gpfwit-CB2bObP1#3Y)){$W%B5Z*97?IX&VF z`XmM_ruPSA!I@DsBV^STE%U7>;clkL_;{z4o}eG3l(B3SydjN3(rH`~THjAzlTavY zXxh(W`KI2lTZJUCTb`W8oC0AAJSL+`Qo#*-=6hB;y~iyApfjrAPm4*{`4$nn_O9#G zC#u#4Y|jhM9h(o4Klf_;`uaX`lBd5R;&|1XO?2CEML@`2YZV`E@uXJwf+<~(4^X9h z0Z3G<$<B5=jWe~dz<RrDA#=G;I=K4P_~&w?I2oYE%9TS-PHRNpwqdZZ6$3Zwj8s~F z85o{<@V`nlx)I3mxg90wM4DGq<%FNrTttUEy%jw|vvZ1qeYsxggdoQiRt+GJ&`3LB z9nkVR0M<hydQCHk@0TFcZy4t0a2y(9m2xMU^d>(k1L~fbC@Z(HkQGg{oQ!F_!Of^< zu6!mhybxZGKZA-*zPpK?{cZ`0sPXL^IJAbtk<cbKcVgT37V2y=;Ldouw$K&R#KFeq zoSDz`Zam(Mj!N`XeYNi&^8t_zIB8>Pvup=Z1_o2uQG$SO_OJ_KAJ8aB{2N@?mBUQ0 zW(ctDdj9akQgm<;L)#Xq5zM|;G`Bu!v8)kd|2shpGZhP>wrCEC&Ppz{3o#7)oeL<g zz#^sC6oZyl65jln#p%TuhF(YLMrMct{YFZpg@oAWPuwClm20Aiq+5=~8b9NJjl@Qi zo7guJui1J71;uHNc4+NJTY`ohL5~OxCtehMVkw_MWQRa>tSL1r?>=0#Upo`c2z$ug zBx_qBNLw5}SmuL$Oz;klUv1`%`IcgKzM>^r9|FSLdZ*o=g@xl~TC^f!!O=g1e=|>8 z_E_?A+pRLo%aRkQ(8StqtgFA~!A&0o*Bw0l9vt-GXllpN+-2sY=hGsTR#Qs~fl^mb z;?&Xqhk$8^-~%K|6&P$Ox~H89b*oQ~4n`@nLe@B-K;9uS3OQnkmUK@Ral-vo?rS{~ zW`tcF8hO|p3YmIrQ)Q>Xz|c?4BAbe^FGm#N3m$H#C0OG|%Vccd_6TGfeFYA|!073d zY+iA;AH1vmYQ~H4k;vCs##o)62#vtDQgl02_T^V}WW+ul<zhVo41(`21)7P!PsC!) z!UMmKE*G*eGY<}YmX$O%BO}d3Sq{u12`)ITWZq0=?&|V)xpfhmRaH+2f^v1O2UgT; z@9V=NXQ)hKHzFU^n>=Zm@c~)I!_@)Q9)y|NNY`@`Ayl3l#98B+Cc<U1OBjKjBt2*W zqmrt!ve;PZBfoU{>}^TRG0-vr<vwzx&DQS+Mk$lv8(La;n|~Szck#vH+dOf&Dh1BO zVOdf5YRs2ZO_Y=@$^7XdIv>?%XZzqkHY4LSP=xL2&v%CthQk)!*eLPRVS=AyUeU$& zk7DW8%HcjEU{;}+w4yOoW$EdS#!^@fH#R<Mr7i7b<>aJvkByJx@#$GxV0FuHC0?^u zBhQnZo?%hiXOE5;63e0m*c69CfISH3?r<WT6ctA1D+@t*DC1b0uo7Du5nsIp1$=p2 zv3g>s%iZ{8r{jesKsnI|4=3bxMI9w9hu2GS0*B0L7oDsMtr@=znB&O#J&@nYcF4+X zKJTlQMLXp<Jcc3-Q-f@vzvlcTsX<G9)N4L!n*~+*$pI#V3X4=R&*<o-uR@Ql#j?Xc zFyig5gm^VapH3#qJZQ5=gNe9+_l}KB%U%3EtDS!!J@sy{V-Vjr!<-!B6^ME@G*>6! z+lZ;^{lgclzl5tkMw4H}BtFrv97ax`CpsN|BaG~IJ11pt|I~D1v=P0bkiXCs8F?~x ztyPFA#bGi3ouL!jVexcU&P6jH!@)S1oU_2r)~;jqN4R^&4p~sRoZywz82-{WSn`y` z^N36e?XC`SbQ;Og(IN5ER!em*-4#YP;pAZvMSo`DWtvx-ET%mxQ#-rs4qb>^k%zXx zCNH`yC7yd$@1SY59P9883ESoQu@?!8cgd>@oj`B&Ga?oN2(+BmDI6$-z9;Il78TFD zkc-RT7%|SsdNrs4_S`Z!y$myp?U4A=x(4nLMj+luZLybXTop&{KwCwT6a0uo_aR<E z(Y~l5*-o6SQ1g6d#@T-GrvTz0OSw*KM!8xB)<E|)iO<K%X4+|sI?sJeHRZ0cHeM!b zwa84m*x6b^E!Mp}(svsL>KZP$cUd7viFRE#SPWWdNEO1OX<r%e*oxfNue6x1UA7(! zL<)Cy+x^{Y8`4^wG2rkvDvuW2z9>|^i6ci}^sDx`evv)@TXAZ}j^^HHB<S{$5q`8R zgq3jYqpFO<r5C{oP0eW{?Khj>Kx0K<yeJ<RqvWEQn1D^@`{oVe$JL<mZ5v|&yXtAn z-ujm|=vsA-lBd-kvA_2XdRKCFX5NvyhKYNMZEe6EuL(igWtv6gUlg}Zrw>zY{y>NO z=A~Q$*=txH(e>8;4$c?`e(7S|$>t|denY?NXAyEdYoYcc&*0-#&2Y;dH3@Y-Acg5o z4~s^3KQ<fVFibH)1Rq^7Ak_pbs1I3cIwW*Ei|f5olAXCU{q*fUn4go`YOG3205#7+ zQ_Jy?PqF(@{8~ZFNu`njNMv6HMZzV&zd97aq!*s1EVr*P`pnJ@I4}l9bo9ZcToeZ* z)tf0+o`TK+mOnA2@N{iAdPi`46>$pCQ`H{boEZE20Q1b~HYsf9G?C9PSeBheMcgC> z#5G&amdP9hw~>ODH#ip~M0fxN85``20tJO;Zx5!|m!M{gH;a=v1Vy*wm!E=rpm0hf zC|VeG&NpJvnT&#(WVcOfh+p!EYzRYND1V+OMpAF=^4(Urdd+5`NF=xl#MH<Ida2#b zET~-Uooca_VZ*+ug!s4&gsU_Wv@sF5{MJvI26wLYupBnn@%+Lyb3;J)dhU5cfJGCS zva$S*9*)@p7`@vTAAUWp1bW^bhipt#!ox3S^bX~r1E0U*;vbmzGuz6`Gc%OhU}!(k z`x1kL9DJD8%Q8@t$qQ$`Qu#xoi-Nh8qbEr$<o=weVr7(7uA_f(KdwywNKhE;8>eR` zcc;jx=IJT;*_`f-+yF;yGbzi8p+U9#4XRK=#lu!^IkKG?Y|txeZA}BxFz+w$y1sfO z+>O>ZY6$`jexDdIxQCX!u8Y^K@{7uBqw9%%&*bEofXUrj1xqmPJ$qj&zY{eDg(YYW z&QN2!F@Ct9M9JxKSgMJ9>I69|OoU(n2OkzlZFHh2*Rf(UaU$3jLIN$5-Tn2VzW#Vq zU(Z}~ENrZF%|}rvXKy1B9tgqj??Q0op>)6#_gawBBKJP<i|>Z)WAyZQ4=+w;GyjSY z)CPkE;6egQALX&EV$gxVe7yea!!t_zsx^88uj?7LSo->(BdGu0^XK0k_6nCz?!to4 zz(89g?+Y);6W{X)F|!ZYD2_}hj!!58hG=Eq?Y;$=6TKN5dow=%jA~@6z>e|N)%n%c z-6kfQLPPKQ`}^3Bea{6x;J@CH2<SX>{ag)55Mt6(i*@yUG-H0jO}-9#Q(lhE1we<< zePTu#%o(wFOwK|%Ax+N?br<!Kui0H(01*z87vrnpUsui2D4)=`;_H(88?-UlN#J=X zO1ARtctISYEYCvc%<0gM<T`R_8TYim>^s9ZZ{CFsQHDPM$A9@7`NZS$Vr*?{9W6Dj z7AW1ZnXVXYEHwev^0Y?1qWiR6+pAm|fiM9#c3PUg&3?vou9}_iFwvGvMSNCiCoj>z z8VTI&kd1E*7B*d{$qGuSug;)Rwy|4b0@4{9n*}st<<YFd>7pW0x@gP8nDwE0#@iny zTH}Rk3f*(K?KPqipV)AxO6VVQ8x02~8Xb#!<LK)h9c6;wz?UKshJMeueR>qC0~t#T z$=p@5M~gyS=$O!tk4|fs`+m2#b4mq@cr0DD+I;BS**SNR3k6F}O>On0r~uK+GJS^v zWu+umGR~V-B!Mp<#wR8`J7A+fg>~5CR|?Xqm?kHgCMHj(Fn`RIz{rLhhkAL&!V<PW zfzp@h%SH!`9n>l)Ca1ABxs{dKD5NLK%JTErimU-IpF=d<+~p$g#1&4vnfGo-t{;)W zR4SQ*QE{OqcEe6ogfV6#;A?@eKjq-COxe5Jq0}|LK+~k8E{A;z5Q6qKWxfUlX9LSa z09ne!P&L6jI@+OB`zq@b9E7?kXnG)#3o!pf0<39Hj$0PJ9?DktCMTD@1itK!`AWtE z=PLDPULJ1sys!2a=9x%DaV?+gZG@W|1t>2bgp`XVJZ^rs24jRxm9SaOp0$SJ)P3Zc z+ddygFr6xDad-K?*>AwOJ*1Qb;EL<ki(R%H=}yj}3d38-14}qsOz!QyfOcixQszeo z$X%hta2mgkyEhY1zHr%7-A>VGm@Af$@DsxdSJBb!>8XWanPKDdKOEM)(QNOdqhvso z(>LJ!ZBri1Z~JSv+9EhAn%D+{I%@Vo|877HnARKMH~gaf3eBK~dNC{joL@~eR96fR z@)efSy~6wTgpG`{nJTg}$J{;Wc^o@V)&(G}c}kM~Gpa3ygE4N`Cvgrnmb>2GE<r)A zh=_1l3>!JwepZXP%@%k*EM!jCnQT;{+|KX6UYb_I?76yvM4sAL=)ppew%afNg#|>e zC=~)#eCtOp()S{^2_%NJ=$j6#VWF%DZ{J&V45fZ@*jssvU2bbIGgX|gt=;3js@2KX z(QutBUCiXd{6hv88kzzD4-g4cXrmZ{7b;-XkkQ^jPfWZk{;j!CXSYSKp1^7us=Hyx z?BjDbKK418H7ep;9Moz|TA0+IALL@IJHXP_z?4Q~_~PQXR5A!qkT^eMws)8u8E+8q zaJ|bC&0kvLl9Nk-nnIvu)aY$;^UE}qn|oz$GSd}?O)}UGQ-{FxQ?8^p0IAIW*1-NE zL%7F<SQxX)OJJ@7xa|TzTl<hPY*qZFH`-+{D=^Ho(cRA8k^b}9n8Q5bU>h3+zew$S zDC||#V^5Tj94=e~nfr7}(TTO1R6${X^;+xqm<A`Pc!oh(*bf=%qu<Zvwgvm+bUi8u z2hkXGs`2>o{SsSSQRb^NhRQJV0@_mW-zHC#GU{-T(dXgc-iaK{DVgmlzWef<_<-ye zRG8`XCpuK8t<e4yuJVWU>gtSWv~Z(<nq}qjkw0^KlznS0!U4d=t@HCc#J6;?(W=!} zL^snqhEhohHI`wv_%)|kjF=l+G!%p<yMcTj-0P!c@1m`J*E5A2#fr3&oiAy8NSLJZ z#5QsDTFA;s7+%xnXB37M6$6s0o(KOnE~dcyV6P9sL{<_CtLm_BL_{121O!DEg36fe z9hElvvs>xBL7MTk*)HPZC~j9Pe<T}igy+XlyWe7B)wywGwu`nr1-Hwz?4%Ii8>jGx zsRwg;;%fwxy-6-D$@(s%)>H4m$q#R98=S5kO!S9J?y;4QCZ3fRzf2d8owz1IYMhn5 zOEAwCQt+@qqE7!5)q1y*wE<a=NI=#IP*`r)@oY87jY>}TZw8_&MwMBw4F+<yCOu{u zHo&*e{SHIqm4bqe?e)~S?6j=raG;v)cD<&bIr+KS4GYSc7y+LE#fpSDvbgU%jF^Nj z@#T{TD-E_-t?lOO^|D5#)$!fsv@w)k@EL^jQ16e+m3hB(sx>?McB1_ww{(NCn5lGH z==;~X>M2K1n2eaqo&O9iu91#l!+sQhozk+<e2*A**CZYtlhz+zjpp$+cvaFy_0=3) z0}7exaB8wGgx{aM_&4b*WTm?cm$S^D|HSGmDk25jqM{<}b9vq6YhUg)+ieG%Ky7r5 zL@2lo;nUL=-q#{BQ01|^R)%LA#4a__^EhErzSU|WWE@2mxO;T+HIS&dynk|I9WGgR z{~q^`k##IvzP|3M^QsUNPoOcXk(aM!p8Nq@{IEcc@pzZjQsY4ab|YSumChd>FB1)o ze!N`B@kQo8iUXW_6oF=C%bhj0XsEmbH~*l}v%d;>HHGE}oA45ofv#uR336*xnGaho zm+*8`Hmst<)p#y_dAcrFxVAAH6?M)3Fw&^S^XrHe0U?U7t@`I^TQg>`I^9>B-=!ET zU55cgBb6cTVgp~hyE5C#<Q#1Npm#b(I-lo66&9+?vEtO*=$GeGLL(0+vRlxkBfX^i zHS%?HY3XcGjxN4pZwdh~kWA-u{+e;?s`rGS!}XDNy1UPcOnyDsSpCbcJB8FBi+7hw z_t#$K@#$^|v3U>Q&;^#zDO;;vplX#joj=|8{91b{UY%A~SF4#1)BrAp%APtN<jKE& z{z0?J$j{$zbcs8hbMd${(Uu6NQ`V?}mc!!bRL#6DQY*)~yW>w1ST_9gO`XUyAwJD= zXU&H%#QIHl!lQ<ju3+E>av)W)%PEv9)#`V(aJAJw<S69KPx!-UJ^43J7>XW8ik@GQ znf<Mnk67&}NX33ZWnCS0!g8M9WR?Wx*%l_Oz)g!2!eg!VogMkY8LwKa7ljSC)CVWx zH8gAkrcmo2B?4&<!@*?A;O*=C>rOl#^h6SJg_h==Ah>ciy#=%;FM%Q1TB>ePG;23? zj9T9UFx7%R3ID!kxr<tSdJ419w+L=%w^l;B)>)3KeuUL*78NS+<hLdE3&!Nb#ln)p z!dlsPT-M$icUMU@ChK>P*REGroEbc!IMElCWaXi>ny8iBV$lg0A@gtG-{1>8VIShy zlE6~PIv78UWD@gHU~U;1uB~BQ2C?uY;kf+BH%;ePWhi(JK}n(-LQ5rvy~kg2g};=w z7{IoP4w-&8g@6Aslz)9VRTvj)`bZ82vDW?cHD*{K@;&#~t_MA=7YaOPixRA$cq}1b zX6L8<0i0hSCalfT`L14u(QXB8!Pp7Y`q^}RK)^8LF-D$32#ai_kn<K(A`Kw1%C_#A zglrR;6TD0{J#J3kJC3l2kMlG4Hdiwm?z_4fj}%k$Y=$^3&t4pt+Q&wGdwYtIq;zVq zuaMiJiCAxgfrN2LqXb+%e`8Rod~P?^P$MB#Od%=9t)H6Wq>#d8{cwO??csLF*dme% z>y4NhypyR!zmA*Z?BXJwV4bbPcp%lD>vnrPEh~PC6xg>eW%Hval?TOWN2N6UGsY)m zHzAb9sT5YY5Mh4kePRt92Zw7S&kxfi<-c!`SI@*3>Jms0d1qmA6>=9Q6hEhhhw8Wc z-v~El$cA1;mI~4Nwd1*gt_g0H$MIiFj*juEm9D!el9EM48n#toy-WQ~YxLR^hGY!C z6D+diU5~2MVX!+3skAvGbH3`U%tA%qG}IP0DG^3Bzs2|AUn2&83PuDUwg1Lp7BSd( zhwewg8L}#b^8#k*rnb4;1&wlF@dDq)nJSFV%0CLBkMYhRVIUCpd#;vHttMLO98=vx zCVuYmz=`!+)k;hHkVFtW8M9W8NqKZ58Gj%e(WOz_*q%*t_JPxZ)D`WX|D7P(&B?S* zg^;j8aZ(blwuHKFtabUPx!&~%fr-kh*d-x;aqYb0odguzU`)BR6y)GLz2C$Ydgl`k z*2pl{#ijPil7_O8z|vdK_T$J%o|b(`L|>9fe}L*Q(-u!AN*TR)17F{t$~GBv>9M?p z8Rf^qnC~z!Nulc>m)xYmo}rz9i$;mbZ-F<Wq^mw*K&=7(VnS-F9||c#n2BaSl+~zE z74%ZF01BF?hzyLY_E*2xuZ`D>-L6ECBdl5OPFDBOC}0bSMb06sF!=ve@ju<@OrqlM z-EYRjuG2j&HqfAV+5!8Ovv{$>o;#VziIHyKA!e69G_)$lYOz1BtOt5T|41voF_qL2 zwm+KCX~xI-*#iaRzBOo8ZxG@ylvXD+B`bURLU3IB?$qB^*i;n1`e;;`s$Li020HUa z#*RWn;}^kEl)&!`*U47aul*kV=8y#_c9i0;(?Ze-d<g`-AgT6;xZ$feEJmi%slhd4 z-+ekT(7NfGF=&v!2u{LOEL70IXAf&p6XDo&e#J7cuh(<pg&vU%tasfa$47Y#prLba zd(BEpscB0hb@;fOO9+p-a*=EMSu;HY2FAoiM4Gb#n6>*Ca;JoM-m9bMV}$&%7U~TS zLTUNxdvzwBQBqPgXl;)U-x*r3mdq~b^_ZQLq03`U9EZ_t06!$P28XNiaMLbMzdKbN zAOJC!&GPRZziJ5edAg-!q|QIe{8(Ec-RvNFph9#1hE|ZF+i8hc4b`Cc$68dhti2Wk z(WjsO$}rRA!M#xCA=PT9Gvb|h4-k4StpSlIR1I$lS+!{8RBpbfb)*X-1HXX&l3!3S zK}WU6pcxn`>5@ji3?1HYCM??B!{;^<j5k#hrm99aJu=!G7U5Nn@o~7cTWDNq>Q{C3 zL!7RQR2M#ve+zdDBs}kBw9ej~5|!!PrMWq2u%)Pi3v#BG$S|y)N3u5*M*rw~DD?d9 z`LI+lx!?=GouPZkXF`Eb@@P=7cPwONgXo3~afQBzAFK4ef*h1?Du1Nc`6s-i<;Lxm zR#V#9okhU&Z+>?G-|24QSCsK{4=U3eDr;h0s@S-pW3{M9Y&MP*MwxCqo&duyjV@QM z!dm=0ZmkYFYH!}%3US}t#ovN))d%w`4|Bw%zi}0E3l?}}a^xNUfiFPJwH+>?i@^*) zpxz}D7AegO1{^l1tCQUHkwTwwz0}+D%R;5|B(DF#+*<`l)pqT=@IrvN5h3nIl(-Wk z?(XhJ+!NxS5aRCc?g_++y9?>KyG!qf_xr!vwfEUtRjX=I98uLI-8JXaV~#QI>#EI@ zw8(>OjApWzD2nnllDLL(dCoV@NAl5ROMbLi<3rdi%>VtsJ${24xSnH^1)gJj(|pC{ z{fXaeN2S(V1lI8=+_;9mpN=FJvWGyv9)E##mwmmr_9%GqO)1P-{+aZCo=E@#_fb%9 zhtrOv=4Q0kv@{~kC_Fq2t#deJmzb331#1wi=;)iLA5_A1VUn6>9VD02n^c<w62u4m zBLklgKEA(7|82uXpG`3lp<ZXX!)}|QoJj9VeZWzw!Mfc8n@zRs#%TD)AgYFTqQv7S zYip>tE+EZqslje%H1vobO~h<?yfMe#KJWAR0x`v1SEIFu0&`5vHl606eFAW@>bT_^ z1IXxjjj_ZKnmz?U8Z`|k=VEjIJ}%R!A~JZmc9%?~VJ#~9aAreSTA}Tblbh*@Ra1p> z@GVLNVKMpxy4Rl<3JhIStq-Mxwgw&&4Z2|l!ke}zOCtC@RPO_c2D-D+3u!Hr_IF%d zmO1W5Mc6UfR1gq{+JkmqBd9kk6bFlKz0J$pID&c<nor#hC4$jfTEv*Qvv5Eb+%;Ct z_Y$uMgY6HprbP-}Go=H<vnfou$C*BZ2fuQxmy(2nd-NU4!6RZ0OZ?y~wS2g=_^c`) zWttn&Hy?C+D~r+Ox8#|UDeH4mHO3!@I^O10M%TsOq;cNKa@WQUjNV#UoX0ZY@Yj(T zBV>$YZGf=a%Gm~dP0d#c>1G$?!1@B2tGoTurIR*)9`w=BnN>GYwvv_>w{T1YC=wT3 zOd}&h%R1~G<x;kgZS)6!W}KY2Q$dLFIFe){eqp0|1NB5HF<!6KB}<R}V8S-0Q`qSK zjPV=m(h8ayL!ZUr5+97!^+kMro&sU+ptrfMLu`6MQOu?^QU2bs;L-D3QE|d7dq=YS z=L;WtUC;H4yB)KzaXbHS%ENbtxG^*#%k}W&g2m(RoMUNjwuA4rEiI?xH7B}#mFCE} z3|bt|Qg~ah=X62C`tdq-ZB92=<abnL{r>WYkqEgryU*}yZEAac3{p|AVfWwSv)=<w z$(pC)<ffS&s@baB32#|yck4;m8uRCPlB3{VbmC83SL2hUk%h)4LAj_40`ct0p;w-& z+1z7Jt2}h*u>(1&<CVPa@VF@_OTp@aHp^7+y(V71Z2%DS2Qci$(Qqu|i1<Jnw88Nm z&vf{+DPalf)^X=^iTb56lgMt$rB?H&m9fgc&ELoTPn%B*rVwp)R!V7_j4P$)poDa; zX6QM5f?qU711hgU4Z&(*V_l*xBEWeI%~q<q|4<hvM2YWD#rveMrhkZ!hn9qg8(+FF zPMCxNX=pv^j8+yI2yc(JMpgP{%H}wd@{RxbyS4!ariHp%7Bgxlx1+JUOwu<k+WSh& z-{`8c@s2OBRDEmF?9*i1|Jw_AZue1+lIw^@fY3P_@n7hOlepjgPfmD<!`XYwH3+3b zJ!V;9(07R5LRxwz+{<4h-;+!moQ5VkSJqs{x{)}n5^aR)=EDXbX{7}O7IQ`4A-yLo z`&O#vnE(4^7{wTCYblJMPo8`ecKn0UE+j`ytuJL50jcjkE{-mijGvd6fw%oO@j6`S z7!jX71Rnz&n?Vp>k|Ip#NoVEF%~}`yH$BxxiFk-toY)5OA1ZSiJp1JJ^_teUaHOOf zLLP~6tWbjLNm~t?4ID@gOm?B-MB`FerS*RbHvN>xx^FMEDyVvudx`Y~-^jP&myq2Q zO4kx{Dm(_g)w6}%OFa4!+w%;xm>2ICV#Yry$@$hQEOyc;{}Bxep-KCaoC(_2s236- za!Za%*p2UUZ51gVyUCsuE3x|^gkmD+s3~jgzxkm{*a!tRJj(@HJJ|_~Ug->^5pv)F zeQi~1pdiauX>PV5qM5y<?mMNBsI`s4kL=vsL*fc!Ng8z2_~^Vp;t*ch{e90Du*xR8 zr9bXh#7ok~yVWGvsZixb6cVqWIL!^Qd{SQg?TCJqws0jqlZSz>oHT<dE^0dp8t8Po z(X2ZE-TtaXXJsv3kL($a4f?X+;|wqbfUF-2!-kegPId>o0UEIXoOu4*5(Tu@#ZDiB z4%)$s3tAjZObe*D1o7V=Pzv)4K@bN7CAPmCanj?b`wdGiL^ne!cd@d-{}w_6MsDg2 zfPU?qsp!`E<^~V{tA@t@<2nA{-$mc`=I`$m^ZI|Iz5MOpF7^MFFO|#qQw(t26l|;W z19Gymsyb+RIP$qE>9?N%B9?;f*JwkS=Z~!Kr!=z(?k!x9p`N_B%{V25qS9h@P4!(q zIxGMn?dzpfscsktTt3Mf2YZljuqxFEpE5BrSzO>rb_0Mhun?MD9D4hSpP!$N{#Q?r z+R565l7gp~(kL@GH{~ZTOmel@lGy|e4RRG#FtX6{^lJ%f$!|^u@MJY?eDuWRcsj!V z;pzFFc`9no`l_nW9bGv<9c*#ka1PsR9vOiEh*3TD^))R0@Mq;A1K6o0D(5kPu2bDL zkC$!K-0W6_X=w>RQm70kKT!?#n84@+G8E8526)#`g%3&rD*=PQzBM$cC|iDXa#|2% zX0FXK+~`G>l8yj>d-Z!)$iRMwjD$?FMz4fjYuH>UxE?R}$CLOR5<+7H7AQXtwHxpJ z>e<}P`g0omQXq=8G*>`mx5}bB3M95eH?m+>d^VM0g9sp!J%pMr_@K-yGqEL2&}#SI z*_R$mns54E6;g{;nH^fLzM|uKaCuisIjS`{G}LPM;H~kcz+YQAyC|98``)12{TRE$ zc?!K7?8FhfcMtWyBz}(ex0w0*vnp|{Tl*n8-_+#(9;{4bL)2>jt^=P*Q+4o>k1&(a zxR3dwpM{G5B3|ENSQ8VIa4wUVX6ixJ|JZQI6~aMEOM4EPSyHR0h@z$C{<>KQ&HXvB zn>2nZ_PDpVPomJ~b|awX8rRfi|8efbY_X~$NYKb(_f|au_=#2I<eJ<!qKc9@kl9Vo z%8xvdJ(`;Jj9xQ&AQ9YLo(~NSw0S-usSs3)ogKB?J*=*FQ-YE4iL1LldI>jAsND?# zm)p`*X-9Bsla>{c;72!F@)obTgRb~gCc87hoK37)>FfAn6>!A+_0rK(kc4f2`{*J1 zA3+Q5nI5V4F6a>R!+wWE8=&C`KcMJSqd5=;lNWc9yu1R*As%ANx|{LPC~Hly{M0i9 zKIBXehicJ8=X}|%8^-a4>b~xNf%9Fs{U)w@%NZpqiHow;s;Qa$1Zic<wcwY}(XaYD znY9!ZXVXqreGWSseY9P$0P@^X;3DG7eY?Cr#!$>RPP^;#-Swy5Z9>%UGes;9CrjOg zD{Au$JqrsS3p4&~s>1q{)8cSd+pyB|ch#zMNagAHr9&pqRHws%rLWvwFxI*T)Dlkd zs%*gKoQ2<F?l-+cjTwx!7T2qUsHo8@-}ZnUtF@9y?qKA@^7s5;dy(}11G{@s(jS4J zj$3^z3DUSBCk88wu`)**aW(&77h3kuVuwV^&bMuR-gr}!ge|`^WkEgPe6oAwp+lF# zB9{hNZL20ced`iLJS+UQ&2y!JiS$j#+0?}xEI1^6#Iz^pUkYUJ8laO>nk|m!eqntu zmAT?zY!cmR*zFLARz7o?kj=}@)mEdz?YQ|_X*?BVu=yG+MmjlFsC%Mq(u{LEj}6II zpLUE1fj6=l8VfcC78}h~uCL@dWkm+c98Z?7x6|JSLRy}2(U>7G>={7|>K~`Q@%`aI zONnp*^;=utW6ODE)04HjE3BA;a%QG|vv^)ny&ZV~XfQ)-){8~-eqz<|SIKhxyU#)| z%GHXpvu*UURNEv7Zf_fHR@H_l*OLSS%0I!2fjf0DCc#bcr@p=og^#&jR&+$n<5mIw zL$7b!GLKvKArhG(DNE)+$}KN~*=k;gS`<C*B|33BIu53}jfsIJX{$U1CwcE+7v8I4 z^S#}N?r&fVA47SC3xA1it#0F6YWN0pj*ePgi=E|kJ!V310#W(=At0lfk7lR%wL^D6 zsQB+~6X^bu#ahckhCgLO`GSR!k=)E;jZ=6Z*Ww~XbH4AO@kBq%g!MrME|k4kPGonX z&HEt3Gcd-y+lPs!>kF|j<-nwpg+wDteqO=vR$&-*k`Xc{Y8Zhe>{+uSOGmRMyeCVc z`x`3riFqsm;&s7^a#c3v^1Ax^Fq70M>2A-e-KKyZaB<K`2YwqKJckB{g$tGx=j;c7 z#d3aPI#<CIVt$6oJeOW?ypYgHQAT2<TwHiW{zb6mAZAbX=A+<5I#cLx>ReF-6y0sC z_nR0a{3JBn+vyJ=DV$`n`z-^SA$&bHKK`?NW$XNEX*L1#+`QKbpwrtNk1$(eA?Rp@ zvfi@h<jNJY;uo|??S_l8uShwK$|*Y7|A{d+QaX&}zHvF`<+7NMEpdIOrzuNK`r1{d zVm&WE)_nzC(v%|#5)fku3=knB&(D%A7nyn^;qW<thLE0$>a&5Y_Y&rIq|yQ)dHV~I zN@(~N?W#=|0&=6j^^E>2cj}J7J3U$bx6~^pNCV7U+a-KT^M7S9l`Q7G)G7(vb|SFE z@<xt_fgjl=Ghge&fj50*w!MKK+v5q#F~5+7D$@6lI$me6uR(S*_zGjCuiJgso5E72 zIhcleqbF#j(vyg3Qov*fD=7cz&D8bLg!trrQCi`Tst_tfCnup-UcG{jhATG-PS?pP z*ttRuo8S2+s_i6d%TdJc^sYv=+bB9%KCuYXezdV)N|3JlJ#%OsE*mJuM9(Mx{E3EQ zRDsxqYJawP<acdiI0;KV#Nl(6e=;)RJiI!|-3?-7Btq50scNOn(ZlL<Z(*0h`$UiX z$C>%t*I?;<cLpHCO5{ff+~BLLg>_ycHs5OB{~#kT+~3;|DW`oN_t|`4k@;b%)j4V{ z%V3AC9(&Np)2qV9%`K_}TtGo@{DLgmd3zHP_gk_XN0&}wZqI=cbxVyf-;D<D9UQOw zxhDXk#|@%RxjyiAINkg%2?`JaEAzVt2k;D^bMKwL?*Upkicv9sJ-BfR`MsD*cT=GQ z$h=5!bbMfK=@^{hXlR)MZHbkuG^>h1N%N}>VbI*q>NFBL1&9ak4}3HkMi$dqqcf>4 z4&nB`zQ6PbB9oyHdkBB4L8{+lZa8dJSS_2!Zg&*q`LlKoHga?IaWP(x1k~P?oed7< znl6L`g!)8+4cnJ6>Ka|(7H*EcE>E>ya2p>OfAImohe@X+S|XXhK!iP+qpYxy+d%GQ z<!zL1hx6NXOT_(V%EG*OTd&QF_ePBh`Bsb7{G_Dt_&QE2+9|9Rs-CR(jt5^iH{ER4 zf)_ZOL(Jb?9nte4i&Nb@r+Tuus1~lSaOu4e$mXFJo-Op2mtF4inGGf1<xOL8&Xe;4 z7IW)02Q|De*l`&#%~nS$hNMQ>EE=qqA@NE$gtk{FD{j!3se#7)Len~{+3{+VdPuGH zTuX8^)KGxy)vG6fp*&u_F<;!(H5X*Z>fel;mR`EfwUrmuEY%&8Ie*JkREGX{Lm^N@ z3{cd|>!*LC#r{CNyz2D`{)oplJ>IGWPM}-#_(2j1HUeHV2D23jUnO-AKOLl`YnL0i zC#qJu7y9(_3FM{#0`-SG?D@q7xGBo%M!@Dn&YYl`uoUONx#%2r6hF%6hQB59|6TPh zShhWwwH1?+QlPD7WCsz+IHHNG19tE+w74A5w9$g3Yd9uDGRL|XFE8&p49J&Fjg8s% zoa%RdGzK_>{s`|SP^kV54%NtG<w;6Qr$Qh6E-xLk+dvM|3(`Zq4s+4wQfYkP3}N)6 zEOP+hgi`}yQBe;!H~7jFAYGIIgU7$mD8qTi8LJ<dai9QvlSrq_^!#K8K#E}}6ciLB z6(uSo*#PFdJ)(K53+NSKxApE_NFxD1(pNh>l@vOPh^SDza_!bQk+*My^YZgKxw*|P zEk7o#b$Im;FPE7_;z(?O!;HuEPkMT~*WKWZ1rm~SsS4`Q#rZj4xmeDWP&>ge$^hb| z|C=koN)ESm0usbiN(Lzj39vubhv4MoG}I9XJamM*x*)e#Rs~V8cW?kAOU1cvz?A8{ z&5>UxAK{_l;vym%2X*VhZ+S^cNu4M`C&VkjJ^7mhBa`o4zS!J^bZk}z0<gt(uDK!| z-9r=s^K4fap1`E3uIECD@z6<UYOo!f)qI`t(lwwp@OWOTX={&kE&mg!uCA`g|H#40 zT5mFfb92mp`@G}^p1qY)+|<-=^L{H@TU*B}Du8!$eY_f)b#&N#0qmaoRz~m9aBy&O z!}A}T^*TUU*t0~l@fai=dC56p+MR?xM^sh+w-*qMu)kKx00*XuUi+7Od3i=X`lYJn z;}a9~LvT_LW<l-kPuEA>c=(pYpYOJI2vgWC3+iUrZTAjW+g&z->Zzbcv!>k6#}=z) z=3m8j*CesnE#|XmC7Zvlla!SH4Uk3acPW2-1_UP{ej5U8<P(0^Z>xQqo12ZI?N`rD zH*uKO)+@SO!#BrEoj?!@f}w)L?%RiVR|hK1%`JU>eeDmc5A!JC0_m{`41@uhq=}2> z-B`PO@B5XXWxIK8^Kos%X@c2pmvu8`5v-+27HnntOU)Hv$;B)CyckU8tWSMk1=H*D z1bf2zecK*M_2#mq7zDY?<r1e>m$eV&m6bOmjcbHlO_k2pSeIFdAJ`NSGM=@XuwhH+ zQrYzceW1ZWXxilZ95G49k?F+;dV2-BBTxTy*YZ6*#;VuORcg`=kYsCiKA&%7`M#>D zscm&S32e&N_rE_c2G|Sj@|JD@6Zwm*ppxKN@2t!`Vc>^`_%@1mw(4(Cye2VLf7#@^ zH~BkOR9aff`DEb%P_Ni4wAmOL<(4ht!VQlX+jl?|)l`;HboL0q%XEj60VUhFhIXs* z&SyB|N*o}h86%p;r!EK}1PFxO-Ud5SbYj%R@iY0BvdGa~z`>}fbqO-a1@_yfqiGKw zd%7X9jOa#i&}WZ3fM3>={_fQM0&Xmgx6$~34SYKmX`P=3(qYA75rl-xjAGHe`=|1I zlh)&kYh3fAs{saj<lYl)a3kBqGzv}h`SOL5mbdq>B6-r@jDiO1rQx)*v+m&NC<5*d zgI*dh-lwY5uX&!p*o?yY8?(4#wMN9jPLS-ombRsCyEA^erQO*XMPDCC*2||c|C0+6 z)I^VHx>5KKqkGJzfX>8dWp3^}0Q(B$4giZrUS57oYiu-~EA*9GGKjL*lzl5QjXn-Z zV`R+o=^P%W&8v@V&^R89w*;ouw=w8JnssJ;CkM^OT5w!*fT2<EHpJ$5=f!B(hRrDe zT%En69G5l3sZP(2BKabTEEj=3&o<`fq30k>{_w!xrSo|mD1RTYdQHDMrh_ML@N7#a zFOXez;%?Dj`A_FO_ETDnVzv}ONOznQ0;(F*#Tc8g%RSfWpONXV^PO56wLspItQ7xt z4ixP7m$OAoA&kKCceuSBwhfLeZZ>+PC*kv$m<H6hf<i*1B&3zPox~k@pNzgoN-Os+ z1O*0V9|OQ&PvT6eayPW8$yMN5gdhISOijW@rs9<LoI4W~vehc!`nkJ>yntYEYijne zOK8$z;o}3p9j_hsO2`0Oyd8Bo)>AVe-TEZZK_9~zfGs!RMV(V=0@a*+Q-7(&Ov!GW zqK2b5Gjwl9H|AG~ZYBLT#S*-F&5=lBZp>LMzORlXK0ZFUF2qOzJ~7XIG2Y=*<?z4O zrlPH4Ry~>hSri!VTU#Dg9$5A}JY>ubJI1S*|LHcpE~Lj(K$@44%jG_WicY%z7!e^* zBCE@f((NCUy-8!h{{bne>FKzU$AK8b+vshrVb73F)NjqrA_pqvK?np?9m0RegGBAY zx5q6Z2;G{LgAUf&+UhFOy5H%rvV!7hDTZtvj{}S_NS#7H1K5C+Rats^`RPe{f{>^G ztvKH3;2@XxBbhs7u;#sEopc5Zst?Gj=#D<Q17obgY21$#8p5}B3J=#uahT=y+W<!- znebd|b5sH@u$)sseB<Nm!2X%CQJxbbGcYjl6X);Rp#ok<JeQNmro*=HcePLKRF6fC zy}L3hiz!fxbnU~-)4A5-J=Jdbxy&eSM=CyIZMu)5UXPO@oqbD}mKJ1>b2J4@GN_-p zSS^&WNDGaJR9^=N=w*R`y}J6su3h(6F|pljA<>?gzmO@zewhGx?CY~DeBOIrH!bp- zs_$1L)+-%CRQI12PvD;qXKI5d6GtT=hY&nm+{7P0GzK}wv|ggRPmzRo)dQugh9*b| zsy60*K*Aok1*)&?>>9pb)=MsUeD-y;lH#(mwv%<__bUN8o*4G3=R5M+fO6giqprFF zj^RqJ_JZ5=4h1%W;Zja+&UGInrRhnZgiunzw00dzu!e!DdFa8Szn454`UXChu}$;@ zUTfv)3sD)izCdo18SJ?c4QhLZfX3AmlgJ51dwGToMnmao|L@S}nodY2BcEZPXl{SR z(VP#8`|<tF$x^dJf86H#fPca<pZ`h@kB$z3{;NOIL)MdKvY*iFcGP3T{d&LDRxc~N zqS|8X6Eib&{)gwsshbno+bq@0=MXWV4{I_y%QV(P*Tzqu$Q8Xhp6ayQ2)gij5ZU4Y zcggN_HLuFg`FRe&<338k2-AH~^>du?IEmVuD2?{_e|2u%`E;(Rp5W&_ER8!yyv}01 z=tyZ=*fig?=HpY-b+lCfv^BTZd3XI*m%sC*Bb{>f#q+TA3&%&`o|vyzp}Qm-yLH9c z{ua~UaT8Uz(@xNSPXc>0nlv%6{udi#9IGqGVeGc)a5Ia+p(?+`Qd>~&mTZGxY+c!S zGNh5~jqHxC{XM<(`K+YKP*-(M4$5${pbY;X*BFhGjt&7=C@4qb33ejSfBqygHKpto zd>tDS_FcK_Hh-A8Zg-pVEcwe19&bE7eRJZ~<MK&nRlP+~=I?OsmYZJzK5>zr-q`Jn z8^~-cIo3g@3J05#L2bILVmY4G;hH$pC$0J2S);`$rm-=)yd3fTt6!XSNOZKUgakc- ztv)Kq3<m|p=j{B2;9}s8lKWIM0S~cR6-!{6b!`cICEZa!UBx|F^er!$?08=<G}>16 z!^*1gZ8X4%wtZh~5X#gB+z^_f_`hr-zPy?MVWeK05&B$6w$Po*3noSX`>Vj3Ujq_j zN3<IXR^cE(LMm(Q1*UkIB4LTl>wj;(d}EB^HC#%b!mc*h6{-9$GUHt%MuMtS`TdHo zS<BaMdJ)Y`%<^tBdE3A7BRpCGAlj!-_qIP+v|Ai4Ci7zcwkCDCJwMVBA8}?%$mtd6 zGL~nS%h3~F*Du&JQ8U#N@hNlIb9<>Bn2PEFO%q5sz`{pYHP#+2XG=e@(FKIbov}xB zdTVK=SzB2JKm})LlqH}O*q{(j+z8VRI!%K+cW0esr?u@H5Yt7EHKf4qz&|}CER~j! zxjWwBx8$C?KYD1kjmCDoyiMLH9EHX3{kQ$itEu)_n^~w9mJ_VMePd=s!xJ1u(3b>j za>+rnlT1p;V?X)3y02*6ALO>Q(k$ActD2fF$3w$|U2E%xg+S}@#Nu-{iE)r)XaE!X zFDq!GHn5LZ^_1*ACXxB3{8O`yzxkmR?GO(JW)Im8uY(a(^d(5}#&<fFscXxs&O!A* ztEgOOJc%-BH$SiE*+uTpJ#9tj`w9Qs(cfJ#P|SFEdkA+PiC7n~LzLP^)EV(H_Ir|% z$$cfm7O*ztFvwEfpEWiHA+oTH+fJ0pyMOs2VUa=v^B+Le2e?4ETc?(qv7XPm3?SuI zO~%VBgi!e1Z*tD({0}jmv~+Q2<C%e9VOw5mt1}_;5dE`E&CP`I5@8QN_kxPJF-)dr z>zpXHdQu{qqvu?dF|<tGqu5F_0pHE@A=|RL(uxk)M^gI-oBkm{M2WrC8he{4tCJ9K zXJ59r@c?92eSPE<<Z~tJ_}vy`HxVO=>29CwPMGYHf_tHv-@juy?DS+jh*vt|Wt(f| zF8%T5U6H>1^A>bUwbglDK7x+PGZB@#D^ikH`EIaf`B2rT^rc2VpS?x=vA2GQJ6g<% z<%{$AhPaM1uw&8&BAfYqZJzg+8&be9{Yo;?Ii1JKDWFYlEZy`+ngwk1qv4O*E8LsC zRpIL?(mU9jF<TzO%(U{I<rYOsEYgv~Buh$qz7PpX_6mLrxu=|4YKG_M<X4IQ=q!-A zl^M1w%jrf%#8<={>!G<WSK72_gm3#yEan@r7wdz*9Qu<|67(2Zn(brHSgp3C=b{$K zAYbr!ZVUKjnHm&i#v9Cge@#unDfV@#)H#<Gp)%3a?Nt0I3O}=yh;`z#ak(-O$0N`` z-{I8yg*Ea*Xq1pQ)4<|8YUcM0+duO;wjbZV8fkMqk$hVrVq$5rySv0<J~!PhaZPmh z7*Tcc*2@5m8K(4}w{_4W%PM?a*l+)Gq7-?GRVpGf;IIvPxKIS{;>j7i@n+mxJU3ES zRsrda;q<1AkwNGsp;T0|p2{)O*t0nnS#p6iPOHI@$!jUtP;val1{_w;EICww#=X09 zGqLdsZl2%ITjh0yXnei$4GD8Za8lsmHPl4Fo_!Xt`VoxEJmsVj;W{MnuA^q-hpF%t z+l*sb>dglw{#(dw>bX*Cfym12QI5iihBMCm_~l-S87Wo7rJL1C?g7UG<+{Fm!<Uh5 z-g~Z;?Lh4X_XWxVcV<oE)t!`1n+@-c<$6OKf|X>dgJvn@n>I{M{8G~#>hPa3YmIVA zN6@YO*IFH!Q&~4erv7b4C(Iu7FiAIM`P7?arb*8GYpZMzXTJVA$ck1tNjs+Sm?IB$ zUu!2rn%xdhpRfyMkc#};B0Pf$p6+o9v)|C)Eg_d__K7ITcDQlpSRB|L;hoFFQf54u ze*hmNgZxcUQ0geZ?5dcw+}yke`SVbt!;s68tChlRMk%ac3$@8ir+RXR{AyK4|0E25 zP(YAsb;IPu1Sb55lym~!J(OYf`Klk;PZ(hO@r5j(7{`WojxFBp6(`><+zp(WSr8E$ zsnyyz^|C|<1!Y9$2EGiUwWfVtnRMA^!DXzSP!JU)qulsL8Jej!#Z)`q_VCB`TUIiD zW`=c4I>V5!h{?f{(#+I*mhvO3;U@>VI6O>rRJ;a<a7v2blCtRMKWbo<W26m?gq6Pb z9OLg8Gkl6=MU1UQ<uOm1Ur-zRN8Rhy$f41~lLpteihDMnD)QRQfUNk)?C)O&tgjKJ znLXYb($0?0>OgI1YqX3tg<G7YBsxU2;kDJ%l^Q3a{{m!m@bUL|N$)l>Qt0BsHRQLc z=~PW8=sOwuUE>Uq!kr%qcPvT|%t(%=ixO-WD9g6xe(_8E#fybsa@o^$*kwA~^d%!B z_1*H&&5e(<&&?H8^%8kb&MAh}e<H}}y#3iU@~vW4aPumO`FzK~+>8%j8>L4O(IN4g zlxu;f^b4zF+5QcV(wfHlZ0Wlmk*-d5V(#-tSlMi+Xq}n*jT5{jTyimaD^xe}zpn6! zQn-n+elNN{hDek_X>CPmMVEz`qS44QO?NfPl*<&C!$ou^3ogu%pC*^J@1GSXZLr5i zL&j#StH$SsB||*1Q)6|{tygy&!eM2;%$cbeNY&^W*vKi|lEHtgVV3ZcG1D=Tu;>s_ z7Sbl>rXc#n*||G`#MLWD4FBI=z?WIB57~A#0g8fZYBgn2Q$4GKA@E@_y*&%4H<fD$ zium}JDGN!Pfq`U$vwXa_zc^1^<F%XI7K(r0-8YylikZW_p)}@o%Mte0F;Fx5LNH51 zL9_I8P^>m0e0-XjeO4?A?clY8>v5qmV2`wGt>9u$Q+JPiA(vNFRGk_honyg)KBQMA zUDn8A6QuH8H!dZi#I|zpUYp&nJ^m?6>$^;@m5M+Z<Y;J!vau<e>s?yyU|MuKgePzh z#8fG_sf@iIXBZtQR#9#*%vKX{Z}L%7@D77&kG1-`U5})?tC^Fn^0z)rk8pd-pTSN< z6Y^e1PE?iJWLH)cXArtUQ+DVwMUnqe9I;$XHp9#l<?&9^?#<nv;@+F7zpDG;WxL$r z#?R845-T2;>Cz@JlH#l!so(|VobLQ&;)=2Z6BT>=dd3FkKkyx|`r1?Hj@=8BXUjFa zr8Ik0iVm<f4+@t%ogZe)Tj%^7N@j|+yTy1}Z}qd>S)(oP_wUSoy+PVV+ah^?zc5Ir z`TCE|=al+d<CIL@q6BT$NbI$ww&AMax#Ro(-PSr=g`+(U3zE84pMz_<%AaCaC8INC zr8EqJ{XYe{`wq6_m!5s8_W^0fgjMS>@-~g`Z`z9JZn~=AIO-$y9gLt`F=@cy0QIuV zvwrY>LPEjVvDXEn49?}u)~yw(6P*x<r6Uq9XnueuuGxT0yXwD1XnX=!DOrty|3A#M zX{EUN51HJ5Y*!kCHLFkPw#oUgTQJh@D_<uU6k8h3S-kNq0ecJbZg_3UT;}R|ayp=Q zBj_z7AQR@RF<6#ezk0NlQ=ZQi|2<Z->Uf|#vypf7eZ)+C<P1xFqL<!WX?4tL=3h~L zynmtCSi30i28=ba?ozpBw9L%MKfe*d`FAPRe_SA~{a5}lN*Tl-nrS};UlV&I1=qq} zZ=>Enn4c1wo?rHnmWO_YpX@G7^)TjOB8D1gpNnE&;|*5}S4djRG&Gv~FhG^}-?SKX z(Et14?;+BEa)<6Le+7zkqH85(DkddTKMal0507EMh1<MSnUb3tSC|@?pPG(+GB=y6 zo6x-WZGUiBwo&%|x9pPV1ZIdOdUA$&LacPH3|j#VOiZ|U*>D%|sLU9fLnMV=IZ7%M zLWr-O5LsCxX$lqzuWG$Z%Zp859@(UNfsGUV89S)4?JIuRbNQzxC-&Sx@%&T1<IZnE zs)foYzGPup&5=R1+LB}d=z5~RiqvS@g^fq>qg-W|{`=DW_)@;-0QNWkmR%&U|0~$Y z|NQX(E$Ytyv6ngt<Q%4@U8TBsvmBJd5_-2d_O|ro8NDyaD~QbeB<V^G@H<tGcP%v$ z>T+^l_YXzvZU?V4FR-3Tc^VU&^LwdnVsgS3Ti{U9aoL^v(sn)wl*GkN<APDny7EB- z9*?`i_uWMP1f5PdfbgNAFU?yyOZ)1Y$>ShUWQN@KRN(cg5&XN&+y&t&Mn|jUd0ML> zn0CMN7YqnP!NEK`waenr>Uec->@Lu++3dD@6D2G5{y8_c+;fjSna^W&X@gJcv3pOI zDzT=~m_~o%_A4xuZ#9FOn|r75F5J}TuDdy06(d*@hmbOIpa^@tQ*M&-9wyy2{|6pV zInaV#bj-~&kzzhym&fP#F5CKm#|YF6O#oE<MM?=qIlK<Tz~OLxup&+MifI&GhqQ7H zQ~4dV-<NVM4NC{E*SKAyHP^%`xEOuy<4{uNuD*(!%ER#8&^u)qnndf?>;8U9IB1M1 zz1J^>3$_Xk9%D!=K;<xg>r5EIf!|WNZa}D>sAvz4gX2%-oSE(s{_ffaM$CJ=yN~Bj zY1h^oR7mjgvf`P$66fM`|FiG$p+71tO1s{BsBnt1b;fyia@x_wsl)S#LXb)l{$hi2 zthu$>YO&#Aa3&QKa~pHp1e>3Z?&-Gp;sKdZl*87<#K6WR1?1t;gkJdrv#xS&V|Zkw z&}AgmdDM>o<?!%5!7;$$XRm|U5+SEMM9S4j37;M7FAl)z9elKujCggi1wI<iF_db& z|75+u+C#9r%d(XN(5ePRg%~?-PiC5ee#+;U=h7tr-87_jedA&LcXdIOn%aKN>xJy? zPQx2tKwvSmv|Lgu_gg8jmsFgZye8!7fR5V%2#KYV%lOoka`PS4vdby9NxkP)pXf`0 zYiBk9ZYGzGT3l^$SOc;1>ffU>^(3UZ7>xtJMpde1lx*-TB%KdAT@N=Gc6ZfOu_&$Z zX%ICx^%zny)w><AD!4dje{P1r0tHFq@%$2GjnZ$RXje!S=pdc%0Yt^Hd>@R%$(6bJ zg27{7r_)YGaq;h?)*C=A(JG^e7nRenIot0d=XPenOo@w&@RYr>xP}n?9vB8*cT7`{ z_46y<2V_x^UI>c4opX=+8&Rz7ucrf{ry<ajsZ^I^ebLNLM}RHHVlAt)Nvv4@*}>uQ z47X3i#JSL0oS+s}!uR#ICv*x+F1F}rxT?)SqOp-to%;%A?~44Rn!@tWrT}3}NqBAT zg^XSa3NngN(I_hBkCxD1hE3i-^Tj|;EHF?V7(%LrWHVa>+yGQtFkjy@uOColdtRBJ z_~usBr!#)L^LXH4VQ1&H+t<?Z{xw*idhBrr8IE$7Tkfm7bhOp=>DOSbDpTlFy8ol5 zsh;rkjls($@yRg9F##o@Yv;~!0E`3mptH`-Jyp=$7t^>hTG)Ip>tXfv<kuakrOZgU zdHQg0@TJ^(%{Ad%ZOhtq@Zh1O=j<;i!O(uC0H1@P>W6Y!`TN8gyMqc#_7hMpue6>_ z6&Nex(QI)L)z;KBp76Qu?uz5laC`#OLKx*jr2MeSxhcAi1~)f1jy5}NLu)(X&`d9| zyg3O6#5#D2>;BQCx?p9_|7}!4x(AX$y4_xMHw6_L!b2k<y+Fv!y6mhrH@B&dX!GNR zyX8HnHob4H<<;Z~$m!`{w$^+06I>qxJXUljSFmDQc<o`W)?;p7%@2&kWBGn%s^r7m zC&ny?U^a;4;mBnKf?Wd@G7_SYp|5syy2srj-833s1NQp(gko@XdY4^@V%=$31HwTB zulJt;*s_Z&O&8u}i*U-%oQHC0#SMq^rLJw%QCa7&{i3BTG~Ds{XhOwZRq^^(=O!Pa zygW=IN1s-K4X9hC&U$8fV4R4V8J=+RRd6)FJ6=F~RFNc==1~4Ty^uIvh=OIHxw3ao zyo_8ROkjSa+10@e^;3@;A9eBG<R{r*#QGe`TzpSS>$Iocb0CIb^KCtCdD)N>$SC=W z^u3}*BvmmmlL15NT@c@+o>eUc;x_b-9SH|dild;q6L<Q8k&W%q{8^XPQYn>Z9p94! zJk3~Hm*|Ol-&|x89M|`^Go#hF8Ta$$JDqymVw;jwqXD>vZ|xFrn{Mr3m8~>s+p(k} zp-cmfJo5h9P_O*;-7isIS`xI6{>T?WIZao|Lty^bTWq1%nIZJ{W~I$b_OrZ7=WPN+ z>Abr#99Yx~yie&H8skR#H#zjzadNa%G0h~Z9q~MAC`Cn{ZkKX^F3*$4xUC{;)US6a z+;*Z<rG9>Pz3z7A<{};6QpVj!N=)r_3v!PHK>jpvz>=Ub-F-m);B<cJhS2zMbM+Rf z!`544JkRbad5YqX;^jk^F}U|FZ2w=V({-g>#31VX#L}9U@ko;En3blZW}6EnrT0NM zgj@xMrKFj)rQxI%k7ebwa&*8_9kM@s2ORUth0+8r7Y&qrP^xD4r|W|9)`!c(Pg%Cn zPr<T(9OXO_?cmIot5&&lgVOmt_9ka=1?7bUn?5K?r{B`cATBu{t7@rS?K_9H3T;*A zHTf1b)?!tJ40XNKvob1bx->3jE66vMN<O7$Ti;HnT=7#Qk#PnbmB|LDTA-H|Axi!6 z!x{9wayUg#mOXau^s3|>k$S1I>3;ox`c5LEd6RD_-lu;I%wfxoV+toUG3NP`+1xtx z%p}hx$pbAEG6IWA<7`}CW~b}`O)KpzFlYXsBXlI&Y$}4I@rs$<7$Fo)(tp0dlH_?H zds0N<Mj9Fd$5k&9ejY)!jnLaGe5N|++Q->&<~Yl#l4hWjKdzuZ&lBWC8UUoNpFut> zTVB(EiSZa^$tEyUEL5HIb+broi50hj7{_(z2-p`cg*M1Cc$5ij!xAdg3M&e(CpPVh z>HslB6n4AKer5Yuo9mC*&+1^=xAc17Uwp=+;0CAQgc$DbLGiMB*vDe~sm(W+d%kvH z@oS+(B=#KNLk&Hxp7A;F%+T|RP+t_jginIzqq_N?vCGb}SHOEn6?Ef;U2skbsvi-> zXY^3iuSI{}^#>!F>S>+Bj#&($m}|GX?SN8zJxQ1`I9^GEs>^QL`fNkG;#Os8QK`PJ z?z3X}+0l{JR(DtoIv?uVbKQ$MZ1nz)NXaa)v0DAOvjzoQoPw5q;vElLV?VA%&c+HR zHHw$#A?3>AnP&OtrVVCeJWL6xfLYE&Ej}FgKDfoz^7gY9tAQ@4#d7*kHU8qP?mim{ zoa#GQHKIQlPmm$w&lg&kntb?>ypOXFR^Zq_u^dho(?LYrJZ|UBdzz(jW<&)oCvROw z(^>;K6YKci5ufSL&dlu1SHwTgW2{?+9EiPkH5-##p_-VO?JCA2ZM0qb#K@6HJH+LF zPOE}UoSrT{^X%oG_a6UCZzDie;o#u-zrE}WLcpD7|H%EYp8N9$8{tU@vjx?no>n+6 zF0OWmyW-a787xPdf*n)9Z@VCopoUvaYMKtGck8KaC2N3%MY~n5|B6AUnLcA%sf+k_ zV)F)<wWw4r<YT;T=i}>4selIXBj6B_dfy5e*XN3x&9%UE`J4^V^Fe=n`Octf?3As= zgSgVZ6KF}xv=jF|sm!%J+H2>JUa%rhiAW_?rGF{rp)vxy<)mC&I1H8)=miHHuvx*U zpwwmc&Y@rgmVL&slw`T<ml<62DC_H2>^D?T;&k?HTodXwR!>T%K92ekMSl0D!Dd2< z$B-mMTwGdl`E{O7RWhKU^rbPS7>?iw%Hw|B?D;SZ$6Th_UoNo1719po_O3gtuhOy^ zy;ry@%p#a5q6n>uUCs1GadCDV&1T;vHmilL5ndtxw-+Gir_e|1ofLoe&1d^K;gTsP zll;55*RyP}mj69L<FRYbKe>hms02VB^~Yek_qV)fqvFGC(<fny7g&&Azx3a2$n9{X zl1_?<tkXaq!5F&V%75ak##iT(4=C@;nnM1nVpW?496t`iC!Bmk2oC{_(ta|;{TcO^ zKcZwUufdmVZy3!0gIsgNyYs3_c@MQEw(^v9p}ccf#Q^V*T6B8->&$#by0XCC@cww! z$F=ACb5mJ=&<0(P(7TN9bEv8tedVnjw@jMxZ-YF^t3_zorI9iP@>ssl7hSVlP+rZ0 zqZiXz;Hl*pTmLU@4Mxd3PD!O^ax#<9o@U<IKn1xpfb=CHR~m&}yM!Soe=%g*7a4W- zgJmEO=42!dmi(hDdhxOa*?ftbx`C&s)OV^M$d)v(WsCID(G3GY!|V-d5CRH%{!P2* zr%$ygy^x;=YlYl=9PbK-=It?bcObZ$ZS`ID;CpiDR$SF;V$j<lPI$5LsA_~-c0-Q5 zi28LN_Ghu8%EHV{N=wdD0qx5h3m}H>165o|BzuXbR1I-y#0G}yn|axHXn^9BjgoxS zbnAMTo{Ej0N;BHbAt~u#_k!@`@X#t-Nx4)l{FRs)=^whGnyOI)9mLb$SYgNdv>o|k zXb=+Qi53ouYx-+B@l<33(Rw*YTsVbyV!@c1c&7O=LJy=b`lCd7R%_fgAgToUw)nGf znOxN<zkm4o2^xt?q%4olzDdnh3h7pDLq%jl=QA|3|5R%fuhq6_cee5`%j{4|L1FS; z*btqL_Wb6|K_es#g%=)>&qS_qg9-VV1&iO83bx%MMTaaq{GqDY%!o_HE>77OXYqHC zP^vq8Bd&E-q1DRyiRKNVy%LPfmwZ~Kf4_Y~oT@bK-n2n~itbT_7A2`^o#c?C>xPM{ z3M;XoS)H$n3!nbVUgr>BX9<H>5sn40)t~teb23NcJX!6+gE%AK9v9yv{%Dd?8npc# z?<FNLBifqxN=Ihvf39{V8S<+sVqnGP4QSqN6`m#;uz#h~beSj{UiBI8vmglrKk@{| z^}|Vc!f(pTgEJ!+HFfonSBn}N>gs5tJjOgklu`JBs7Qpofhuho!5+~S_&xUdiopgV z@pTRFw7ze3t@|3n_LK4P(L}S04CrrcmdQ^i`<)sL_P8*C_E_YpBpwJDSU66U4_a%m z2{913SJLaYayI!euoTg_RC|(3E`Xev-Jw1&6slff63uV4748$4S0R2!<y@!!1g$F$ z{Uc;P456G^q>tJS==~Myg@u8>p*20F>P#a`WSoqWZgbth24O7G=3yqn{Drr<@#lM= zc+E1M>RF`nf=1}m=vMB0jTqNTJkWo@u8cL=AR$J7clk^LJKHL1is!j+F(}QzM(}|% z4Fa6%Q9o65de5Z=Cy@o145acf&nCLaqllJd(r4*XL%YY69x=(qN%<Yr=j+Y)_8^R- z0)B_xWs07XV9Bcb*}+6wk(So{;^mI9wSY5Ia5Rd6X?&~@_{`3NU%jWKFcOC9+}08q zAB5RpxZ5*y&aWGrScE;lcXO6z(yur>u`!<jHs%RmR*$~-o^Kd~T_|N3%+>$HddvBd znyBijLLNz^TQRubRfviO=HK{0%wnZBX1FoC@-Bm`!InHuLb`oEYW6SRjuBj9Qt?+T zw_oZ*b`I#4ZvLR{1KwBmohX#+URWZzEzeNA!?%bfk8o7CZU64)Ln>z`Rh0i54ko4# z)x~PnZX#FyD~TB~q3PtKFJtghbP)bX{k5%^(SfQubGNtK$w3@f=SNL6EU0Us^&%zC zjd{_bkF@f{nMj-gRX%i@{zl^3$m~WijNdZSnQRd;)|9!b>_$akkzTw;k+_ggbli^d z{!F6$jsMUK&vi(}R=DePn~5Bk(>pi}<;g{Q?GB`!BUw|azCze`vEpL$zZcj$^{<D& zbq(;V91j)iAO;d|u+ShAAw%ElK~WPKjEP043>Ee5b-_e)4Z|`aw@#7R;<&D>tN#JX zNV`Fa$(=)>w2mhv7q>h|05L-gC4`9gW2HcKlt23Uj!0nHA8!;;S<jkp^$yM4sx-fl zr+?0X<;E#*d(3arUR+%K4Y!8Sy~P4?y-Z9vt1T}5nj0v$Ju5*4&$^yWmy$Q7y&!(j zAoS5sC;KYZISj*neUep6uzAK=h11^3ibvt=K!D*I=_(u&q9V@AY^I#K3DUPfpR?6I z(cL@7^Jz)7V&(l#ba)p-=bZ=@Lz?t>UVcG*Qm)5#&DWB4FV$J=xP%N}0^R&n+)W(z zvhd|xY;9t+%)2{wj$4U^N7DYWKf{4%sH~8wQhR%{pPf)+VkCH=KQr3?%7xB6oNpVG z^9Au>waH7hZ35KMLrp}VSJAlP&th-S_`I$a_8flpk_%#9Ca$ZA4yv|q3ZbYA;UO5< zY>&q%ZeeHV?OQBo9sg$DVdAvNDyff8tmL;}lbF%~qs-@c*-hM0ohDi&+ogI!0kt!` zinX?nNJK{OJ$@NLAl!A<)D$xGS{*8$>S3+9wEfnp3DRTQZ5GD*#GQEW*Ix&qo!KP) z`ObKW3@4(Fa!DK($bmqw-8@ky{_3uwsd+%*67gV$(|O<OLoB`V&2YEW7HTPn-{1<} zm7&6*lJT7*5hKmBmkDie_X-9vExp5pLJso#WS+Anj9&dtfUeBmhFPGex;1|`xKpH& z2!=n%%Q0<=%e#Dqmdbb(+dMDD@?!U(x}om-+K(K^eb?<p1EYXKFLy_Q&44(9d-VXc zD0UICA!8F0k_Dmx8zk;pk2U>lDhtsc;%&cnmjgdahbx?$nN4U0_Yk8Y2!23{P+&WP z)|={QsM#O!I-n-ewYb}b3E_f@I^m%4xa5&4zK$YHvi~~6!#&erZ&^D%2Kmbt5ipkJ zN+I*QQCzlwqR43SmPvQ`zN#p<M3^SJ@rMl2SO6Jb%V@91Gb5(~k$`i_*=KuvPM&P4 z{!q1rm67Jd%n?(1C1XqF$xyLsEroEEYBGK@hr``<_-73!<37BeAF~MwQxwr3S64{8 zoG=zMIM*Kim||MYChB6;SnYQUdRc$X;y;YD<$A*hcAcGo_0J71ljFutVvU}FlPCgu zp0{{!Gku;Mc(wFhi*EOOn87xe2W8vCohm;$8Tr-j<V#b{_?7&DOfMEUJhbh1nRY=q z)0J2nT4@;)i=F|egd_KGgz{uZJyH9RSklUnZPWWhw_8TAfF0pwN;aw(rpcmzNR_QL z;PB`2W~;FiLe#g1hW}Gg{&uO_>p-^ik>I7rSVj6j{z8(;LO1kBF&MY|4|lsizc57P z2L?_O#0hO+{r@0<w#B4zj&(#-3pIwBNfRPrFbi`K@lRTa8|cpqs{A=`wYT<(>rcl9 zuXMd`a7(aAJ9!PNCf^n1+!NU74nKV0G%_S5t<Llw9v~iIThH_FfYReHxnp>JP_t9t zZBSjtALFsHGmpAw@MfTif<_m%L3e({b0{9{?(6l3Ze@D1>^1U3`}DtE@0YK?I%t}~ zRDIFD136o+0#%T^<j789pl9nBgd^QY?fAECkasjLjnmQM)I&5wg&X^kOXlW#=O;qH z*QvV5AV+phj75qTH80KQdVMPU7Vydi0Wdet297o~So28R0|^Eu*r2i)FB@Fb>9rhn ze5ntl_QcpPNBnt2^Bwo)N=hM?;X;=CJvRxoy5Uyn7HIYBJJ6=Q4QV7|3VYwR=e8Hh zk;`M3$o;veM=}0b^y;DYUClVs_*{EEF`A85Tt4gkgx-uQRQjgW6-Lyl6v6m)o+EvR zlw&d}r!r?H9^2Ky1ITs+GIsBb8J9a<T(SeAe+;t5FyJR%f<~P1>mX0xQ(C$dwl93Q zu?!vYi0qbHlOuFL{^Yrw?*8t7`HLfeb9-CAS7M(`o@cd(AvR3O=88Gn1L;GguD7n= z1;MPqp__1uL)UyGRILtyP;FD%bSx=CJG8ULhfT7urXEeg=H&g*&}xn{?Z19BP0Qj~ zVswA>*fz`N_aQx7Pec;V$GiazK$;-{k@Vc2;FEs(d`*R;RSUV$O}OJnr!OxnqwTSs zDpI<yIbDZ^4X<Kk@AV~#gUeKQT!!QpCB@Qq+~uxiHdySPgiN72l6ca3*{j>SC?U-1 zR^QwtYv#S9^ZH^^0BM8-=6EF78GoCSQ{Vmu507rRQRDdnvVo4e{2sdfbwQMB%ZwV| z8GRJrESQB=vW?(p?}yQcKJuLkJF(o_;uimO2>oZSp4DqzZV~gp=jEj#?A^Bohfb*T zF>U+<Qf*{JRLq(RNpNo0XhTUJ!9LvCe@;ZPtz-I)e(+F9^EBmKY6QBxtxh%!JdFcI zX0(EBwk;9k2}JVcj<nR&Pv3g*1cgZJoa!uj+HDK+6#JRyFyHC`iln_&SZ=&y+wXNU zLM*JxOKg}l#IH{B3KcS!!>@903#d_JKjf!nWi-DVeyLf0DNg$=uh2{}rsXdFwW5lV z`Qsk9@{cTCtI7UMh7@S}?aQ9gl(Pl)rlOB~AcTFU(t-ZYB&0}nuYxrGt-=C->X=SZ z$!tj;dW=DH9%i{9Sg(p>b}d0+KUo%PTW(ZUz1+?Ls92%yw>Or{RT-xm=wsiELq&F- z{Em^&nrT5thGaZEI86)CU?pG+bUAsP+T_QtqUlW>=kxOmANUb|!Ys|{4pT{DVYk1A z+JPOSr}@B>?*3gV5wpYnLo=-g?nNDQ9X@Z+Heuk8`3x-=jrM1$XOV1~rf{do;98{` zVB>{*=YC5ir>OYqj^ELO*}jD5`QgvM;tUMGKYLfd&Hp7b{x>gtt9qJuNh<Jn_(k^k zaF&q*v32;D@Tl~UTUEeI=OwVE29S-ze_tf8PHZuGYj!VXNa|lByWzH`si>&vX>nSp z`}{|#w59lRM<DUIH4{3_Kqcp1W4&O#)O?aTgS!FQ08dHqlj)p3cc3K-VPKD^2V)p; z(D1q5<|QPk%+So9ukU*%AcIM~B@HL5w*9vG!|{{h7bLHH2f;uF5<6Cl+t06!wo<LZ zrc~h29M<C}WK<na)v~HG+^e5Us+yV)g|__tr=Tyt)jhlke%1C0qvS$!!Z9k3?Y+V^ zC>(sGD>e!?F0O8W`!#5%YiXw;5pcTgANKnBb%DID-~=)U7(MBa`R2Nu@G^d4sjFgC zO!*BE?J*hZ&Cbl*hNhazy0Q$Els7$l7eH2Uz-HUnSc`~+D4JazLrjwW6dY~%9Q}`< z1vj^a#h^Fp^=!I_2QnV7&z=U@7gmU(WTY}W`IU<r!<4M99`xo7P`1;|<=x`Rp#pRJ zVl7ncvtCt0gN%Vej>5JSNih9?djaBj`e3C?N-6@Cd$q}FXEQk*r2VSx&VUtlKs6L- zk(E5sy;1$Z!o~Zij~7Y_p5kj6+H*F`vjxV?jf*lc?-JqQZ}558JjM8XxWHG2<&}jq za5&6aFUBOru^gv2dU_Jlt2dY&?@Yye@0^TJ#6Cw8G}<h%P&4g4=wf<bY)Lt>UV(MF zyW2Z<8@09h`BPACYNX&auqi+5G*^6K4W>q4<@9{KtcgG1PvbdWjO6CN#(O;Vzd1iY zPbgnCGBX>`(!sw=1I|~xL+f@gLXy00O`193Exf8r(ChcS{WX6Z&_fO_0}ErJ<%(K6 zN3BS&0|PqP-CZ4}4j%)3e6AKQX=Z1)w@nt!&DDUaH^Wm+NL$-n1FR&wBZkO+{O+|> zktOzlQfT;Z`m?s>l|fvNUTGCjKGa(%b!!5rCOi@nGt(z7pR@g(yR{G4yPyU1^JJaW zF$V;ir0pmMC?j$B#2%GTOWBXLnw<gCg~HD6Y>Fb%iE2<=zc0y6OUn<4>cJbG0ck?K zgv!-`E`L$k2)xD46o33LxSy(SfO_I!?g<(xT|m(%_PD!i1`yAMg{DPX=<yC5E@y*( zp4+7(B2VWEoGyxruzTguLYX4ipoNu;K43QI?!@>!v+n<(uBl;WZl<S>Eozsv@>gS6 zNm%VAIvp^q=$j`cp3NaJL55vnU`>sL`(bZqdn-sp7|x>0uTy29|E9>Wh{Y%13lIPp z5c?&ahEO4tS{CKP%kpW`lCkh~buGV_&rst4#R@{e|3lha$5q*VaiXt9r*w(5bazPz z(%s$C-K8{ABGM%wCEd-D?(XjH?!#<+=l7Y<#JzLx4F4T?9?lbc@3r<?-w+oiopJ_M zKzmh6%3fBSGlOfr(WJZ-5ou|{*E*|(Xe1xR#Ha^3_*f7~$m-EMT7Rq1iL{a$BhqM2 z$2hCv0yCb>DJ)G-8D<#ycOGJsFW0tkq9e4~inz4d(!GG8=S%Sl0qFaatMm?ZC?v$M zbw9-l8F>Z{@M$(Tb8v-pWMl-Ati*0!ZP!Uj4SmDOWJPfY5ckv-|63m3DH`)lH|k;o z3Cm0e6af1F=pE|XVrFL6$0_+MKjRCZs;n%EgMPX5;2<*_(>qQ1FRhz6?_{0~eoA0F zy28l%-A1j|F4HJQaYH2}PBEi}u_ZYO)@}O-q#5*@K)n}36bCWBaC^8|B@4zGYwL6W zSXs>0?ZqyBIuO&V-V#^p>>K+aC-$zFZzAvTTXZzuYkV79Gsn~Z8_@h~sORFy)7rYv zE{Kd|XPQ0q4t6{{9rnH~NyNbpDNuZRi2lh1V~J<+sf3n5W<a;mOD9bh0|*kRYb2%f z`_>uVO~OTig38U}_KKXv!HxwjieA0Pi)V((ssn$$!y-b643kdTzROo9I|ECR!kN;G z_8mlG89cQgZi@YUJwbwirq{76v&En*BPnS!nwJ*bP~fncUy5ey&9im)>&Fk9)LHI{ z-;s?d2pd@jvT&}YKDNjN$7jU8iHS)-96=6W5QYqtXk7<_td}0|%}iae{eA<o3>HAA zV#+YkD%VlcY%zJ+JqAjt`rM5X0|p^L0D2Lk{bHNz!C2I}AKH~tv-#-<b9J<_s$B5y z>_<uI%_DKM!vS`X7Kbg}lMAAyP@0#pR*C7Byb_?P0iN0l##8hOA^*RHDx6!CR#q}G z4Rf;n<4sR*oiPf$k0j)VfEA*gTwh376i)9zeT4ohUBUzwQbB<^9vq{Zfld84Y&!Bq z9L4*<ZK-!FLlxi(Ra`)^+NPKRRL8lw<yxbGp=8D=kY#u+!VgGYVE0L^_XxZyB^=S% z&I57;5jArxZdC#vH4RKFzoovNzYc%G4J%}u8XEd_!$*rdIFujvvaolkj$fW$%1B61 zuaO7FMNHriVvMr^YFc0~VA8#RNB8&cmEB1ke(MfE7rhx*s(=lSxV-#F2aVNSi-%WR zt`lq*0lm590S;g|{}SCV^0X$UI&QrBv#_9|^PsT;>#=7MRgw}N^Vj|=Z}he2UcgjX zR0(nQ9v&Hca!HP^J7lc$DbnY$lvh>)(u7y`k)tATn&YOWooj7vY-cW<gTt>ErueT1 zu`mq}_4J_Yii6&v|Mzq*{Z-O!b+}mECjd)kFWkxp509W@9!V)F&UX}UERJeph2x1- z0^~7IUmy$seZZxh$e;lU`9jKTuC!bb_OG0Xf(hUQK1lMxR}hx!Wb=_cYzT^I(*P|O z@bkYhW!(%0DuSIIZv=g4NJyH)#}X2N@5%h}c|PlN6*MiaIY2ScZuZgugX(+h{CuWC z+wH2Ih2-uF#**;xM?s?A!NJLynVbC?$JVf`^hy&83*o-m+kw=Jd(!eDfsaGo44Arn z&IAO>sFbpNPWrZearAv$5fw3GtAU7tQyrxSBApT5a@TUeH*z=GUGIrQ_!>Ya7;Y?2 zet}aGm<%rWHMWLQHJU5}V`5^iZRV=2q1wm6$BK>j)%}y&XMb=ee2A1fI<+08VaEyt zr*;?r$h)14LlVwRrfm56juw(1=Z3)0YxT_q2AJS%P=LeIEsmqtoOCFpc*5nCQ_7^V zcwL9Ihy*zwj;e@jZS^ri(E5PO`r=OmqZRgxoqwc$CGiX*-#h7?hb*<ly^*=L^oyul zK}0n*zT(^1+$`3qF*rz4nE){l2~HV5%Q~6E`}UH9ot@u#cO0+@H#Wq?#6VjnN0#V{ z)ocjdg9u%rLeuRyYAzR-vXq?E#g%XErxU%8Z!$}5mjrOFcYpMF+};AmQT1};e6Hre zz>RM7HhfN-9|;M{6{Zncpg=A5A!B}a7U8B;v&ur?_;j((QB7X{8<)@3;ev<Dk%56Z zIw4`D!^ZB<W&P|bdJ_#e<X{w{`FfST*49=sVEf4JfEh?IS>otW7^^4$xz@Uc7_nHl zA%}|-a4)Zxh=V7_MkX&W&a|$#G7I;u?B}RtQ-&+e$L3S^m%n|BEl|x`yuCOmu+4)w z_i@<I&N5WZRa!S$Ojv;aME@^|wa(~hbXe3kag43~{a(A{617~%mzQz2Z^2S^1}w=E zna^U{f>B9P1Kt1(L=8hKFFn*URNiR{`L%L!an;xuOR-Kvy-%B%{p(6m+XzAhaM#H- zHny|1)cM=FAu82Q?||r*d2)>v9*<LAOxD^t9_!;=bz!9c;H&iT`FkoxwG=@2?UNg# zLHk;NwrFF<l9wHt^frKM{je#{p_SEJAJIsJs0w*2?S8Vnph>oi=hl~4s-0<ZcVW8p z=X)+6PV24MAEWVi>oo_2mJ?t;A|fCudNgR&6w|8Gjg5}aHhIc*p%67cn5L;m=B>u3 z`*uDO@wzq%9(tF}Au_5Js=py3Vm)Xx2Q=8ujt=)0za<6TiB8k;xvb5>RL_gq3z1-y zriaPyA%Wxw2SDFZp^XR8+MDOD0uhICc4j7>%bkUr8a^862+X~H{o2%<hnI%MVWu2H zM7YoFQ=-ccxx1VjK4#kIV0XT7-kVY_(o``Il+wiZx;o$l?4b+@<PmWB%%szy8}W|v zwH6l^kK$2{-d=HxdT-Ehf3nro=?&uXeOj(6m;!?a<miJ-zKrO75U59Sa>1UOBLu2H zis{5;yI86#F0Lh|<#}1CG5yXyg+v6Fce+Q_^QIiK=P~}^aHzI5sCR8~7*7OTERBaE zCT1%QQWNuM8f}|pWMo8sJy~F@1Z*cH03P1?(Gm{GpC@qzyb{!#T`nZ2W*P3Th#T!r z?h}}e1X6fj1p?9|2x?BQu1htxkm|U}-q=25WD|Zp8ZDk5QH0#Dt>XY!F#IvS#^lPc z0=A0Dr=clSRiT_3@_yQdnu1r(We$ThH|kasTFdHkeLozwh=<rU!{$6XHlm!&+pno6 zC6jVr#6gLoS{{)!GW6Wnmq=3GgWTW~?V835Iw`$kx-(-#Lq4ze;R3Z15{j(z%Ub)j zZy7>JVJmaM40o==b0rhPR9IZ>bK9So%4-su7lcgUax~&SvCE!!nA+e17}^}XT9>rL zkN5tc*NN=~awsVgU5;L3C~s~)8GW|B-{UAEA|(7~)IT(|RAF|sT_av)K0&i=|0f)e z_4$kEP?}y`>-ox=o*wtvN>sCfq=@wh2xRF9(syf9ri#2f1rTEN%@Q>6fj`}be|`bv z*apuln?|qm?U8zC%gduV-^=|v;3{ikY?{L3Tz_4N&tYYEe;o=ao`%=^brqA7D($Cz z@g;7+A@J;~?HKT6d5pW4VJ-*=dEAcsxYMt87qqlRuWWR3hwhEHhe?X7EU&gF2;!ed zM@N6iALlj$BDmqUz{4{HA+au7>akceTXN=zn+*6^>$r&q1dHo*ysjMS7H)ck286{k zz<)s20A>*|i|%I9ii)Sx_D5kgi8U4x;VM#<-ZWbEmQy8&A7pkDTo+?ycumiJ=i&wy zUZ*D8K8($&G{3QVU?T0}rSt4Kc?p5jKzogue0LL+M-asV4B`wOAf{s03m51F-n^sr zzN}>J>hF#w+CQC^!*%_hRr1sb*F^K+{HRKT@fdony<B-F>7efv3W><d&&{p*G}8L3 zeVq}KqIGZ0tCbufH|9}RW?wYh{X9B}-E#S{2ZO5p^t#qfM@OTcf}P!YEN9^1?y4Y^ z`L|k$V)j>Hc8U9^^@+LoW&8)`ix)FP&%h#Y@G=}59o@jj#=zP-HJV!M$m7kMZoFPr zF?I{pnu@Bne{Pq-aPipw0~L=Vz7zCv+g>IS)uE~ReO-<wu=Wlt@_!D+1GZLH?2n+{ z8OGa&V9r>bVbg=m=*WF>$#?m)dL$pAg9E>ZQ-Ma7sY>$iBu&k23DKy<L{>9T0G`TT z-tGZfQO;+RfSJuw0b*McxopUv!NtX5P4?i~D$AvMZ*gcK95J!pQ+lARfOL+`!V0~} zYTeeW_ndNEX?>-uyBI|*C`Q#^w$`O^sBas!$nWmS=Co~R|K3E3s+nT(>iMI)R$R2s z^-R#V%vQ{7E#7!ZMi`xPiC9omGb+m0o~Gs0k#+@F3&yjg$yxToDm0Q;qFcrr*lEYo zdt>9cElLEO4~_S&d#J3@7Nhbw_3TXhm*=KuDf6w9#kXHZdMN1C9QP(=7Ig*my!que zN>EA9g}&#zac5$e$zdWOq=_<Z+srkZ$Gi<QV@#*>_|^ivzzZ^{rEGxyn0`$U)s%ev z#?-K&$MSLp;4Nhe76|#nte{74S7R8bmUq@1EeiE25aPY4<1TmR_1I6?YVv#l!R$++ z>=eV=67kjGFBNLK|I`9_k31HYB7Kw@5HswBgubkP>gkb~<)MJmWNgRl`S3bzAOHFC zVz$!U|0P!ISw>qBNpL`#=*#74X=1^p7r`ilcek`M$TOyfZYQmQ+scOv1zjtdMt$S$ zbd(&j&Gc{glB8w9il?e{=i9NlvGv57#QIen+*LGJ6N@0;%>G-X>+<35d~c>;t2>%3 zl86^DMaPhlkU>QFI+XD%4#m*WsQruNXxswoU?(xmFmsJb&cn2<sh)L&&~(6J&DkQ} zm0!8+qLgQDR(?)>VU5jE)sKyseQD(J=&)H|GAs&gG5j5kS85L|8?5c6dZI4WQseVw z-c<FSk{$#PIjaw1!U}IM_8zAj5U(i*A5oX5$YpjH6|?EHgBtqmT!Y$zBACBehnGEU z+LSWm3bb(O*YXl|q^@FG<~K;q{(A78HM%jApb`4If96xxR2)x5HN<~4f7LuhadSC$ zwde~eY$f7#v9l{Z8ZN_VMZBNMR}#<A#x<}WX`Jy34BOw|ciEo~70u+b0pf4LA>yo& zn}>(Rim@-{RxxD5u<1JmeSIG(q_8jcrsM?OSl-d_%(k{Zzk7{^6(Q*D<wZzDWV=`! zx|6v|iqX=(+^{=Q6c)a*mF`RZL!bcKR+!jrs$1`r@7>@MLn$MGi%;_d#Y1y$I%MM! zg*zcFP2kg?&$2|kk+}RhPE86v?3SM{U(GGAtbDnZ_$d8pwldW81Kj<S3QBN>NY~cA z#jW?r#MCS+h<nU%7!J#}_pHp!iOg$6NcF$~n~I!V|D&kVeoU0WY?-5(wwJbs8jp3< zm8R;PRM{^5(3d5#g>Xi+E&XqYnw5%Po91p>b00iMn>AgJPSVusc|$Pn7}kGn<ONq( zA58v1IO-ro8q!FXVptrAl4-)ZpU5u`kz}AVoA~ZPN;Tc+-gmqr(o~=({sD5cIS%+_ zETdz6G~s1}n5;?(2K7l{eIWS`bTBwpp@}tQJMNt*xK`3eq=c&9h!3UlCv#d-{s?09 zg_aqf_AwgWRtyOUUHcg($jZp{^$h?g^=f%;Sk$1!X6L($DLo8HVr5^W-X8><wr_ZS z2z?DnkO?@(`L>I`JR1l^-1NR)f&HW<Eb%inz>C1)`^-#T_h_P40%CUha`MR_Z|}Y5 z3AG<Yr{PLEg^7VdK=)p`RnKyYhlfi#fl2q>KtH`^t^Q`eEpwB}8TQex0KezuAE&Ls zR3<`dkXrC3>`pWVp?E|07$Ns}KrfVtH|Ieywcc5^1nRgRf?hkmY7v|84VRcWJvO$= zer+>HCi&}4B(U=47c{nWl9uNF_a(S+OS+RN*4dTw!Ym(~mFBMc`lm4Q)trb*z)+Fp zc5C}Eva(diq!v6hRpOPi&B>ZIjkZ0@7%dvjvy@Zk5H6Mru6t)pd3|*vzlF^DyJ0r= z3WKiPQjO6P`d;{GzV2+6aVQ<~r>)KVY%>BcF;OBk)VBG;g}bkH+Z-fwoYu3S*D}7* z=E(Tw%Ir;ER#%(E%E?NCEhV9#fwqD|nW*8a&H^txyUBS1PPNs-?*9Jy*^uM+7^QE- zU{#+=siPovOok3N91XacJ=|7tt*7ax;dY38B2`Ag@9isTWO>|5ud!WNRUDw8q}(hr zw+)MuCZP&N|8p=`b1(;a+$({MG*U1!+V0ne9yMLbc7O3!H*!AO1#UD-_k^4K>6=e^ z<yvQivxC$9PHr9hgQcN(yQ}p=xyg7pdY>AU1gi16OvZgJ*|r&<#~3aMMJ`?7L1l;L z8`Irs0i&STqc50Y%J2G3AJ50G?bn_r&7H%$%5~m$d!4Ybu%&wIyZ%I0XM_}9&%+C9 zrKJR(jVd*&t@TX}%>+5`HTr%*pZjaD<VJ)6(Z>4xd8gUAF(V_RK!*}1{HO=b%h}cG zBV9Wk<_RU$Tl0qQU#;+Gh9#o0?e0rfACm-oh+epN(;V=pH$6DT#SApLeQG=DFC#ke zne%1D3$U~3Pf4ICsZGCYVT6=&@zmMvGTJleZy*aLxw+jSV3k!=T^yg+dfj}Lhi_*0 zvbMGwOh+v!T|YIEV$^Qra@?dFNGa0duwE(y0rZ2gxnG&?g9lD4!!}=dAg03E<^XF2 zi}PwDkl8`Pl$Hitn;d?OEc1)qi8i;C%Qi*)Rn8@&aK_U^odIca@!TXIcG+}prAd)J zo~Onr@T7K^m#$zGY7vUfrv(PuCFTpiJEF6?0)q#JhKA;HZxhGN+Rdy)Yd0s0)Nr1~ zU2YxHx@R{)EH$`2%|@-`^^p(*B}DYjx_|j?W5y2N-wK$9WV1Mg(Nv`D%H}BM%MS+c zLwylxG5GjNY2z40ST^TuA%YI)?}Urv2DJJUm>*K{jt*z5v_KKy*49(BWej5#_;;zu zQSt%Lpp%J)BiYA|_>Kf%FW=~SbvU2C#q97@gQA*QLrN<S)+6S%@dHeB(erb+l)vn6 zfYAO|1Qq>Xz7C!cDVWG3F}bCsf5yj^-LMTHrLKU?QP_)~X7!hlohHi7U8m}?Bz0p| zT3+5i$iOSy+f2(h^Y?uIP@ptQM^7JMhVCaE5M<Jv;*woktEgvrQ~TG_%j5Ni@mBAK z!-|G6O*|PJ-PuMst*}A$@k^s8`q4SLq^txpCuc=P1y&mU<)w=$g1e-oMIy!PNVs0* z75Kk(n{9aK3r#mW`JcyD@F)m>d{pGOug6z2B_EvjjYz7>s-DP~+dWEvC!d&zg}V(X z*6;W*cBcw3eAd7NF8rxorrBLfSzE~w%@?|q-~LoD+U^PDA`@hUD74+qfC|bDRtKRR zQ}`sig*s|9Mr(^?6A5E6*ICZ;tS*}LdpDN1DIJf}e2rdU-jI6uNszw|ciGt5!okEe zHQO@YS_k9~1UWv?83L+Nv{F)a+QstS%$jQWUbrHpI7!}&>TXF10#IA)cMSdL4w(Tl zwtpSNJb1W(m=oGFT3SS<vD{^UH$Ym0yKr!DKtIa<^$Y%Lpe}oP{9`FHCLO<wvC6{* za>s9N5?;w}B%JR<2ohaP|9Oqqb5DhHQL%rEjm9tktvvnz`^Yr&ctygABc8gHM7@`5 zraXi0OB{Y_HAdR4+WocOiE^gOT|~`MNWL?D$&oVu{o!o2w+;?>Z?+zf8_i6~grh** z@9+?e_*kgSa~(;DxB%mB`=Q;|*6dU%E&Lq9>mee6B%JA@*x)*vv(64KM_)lX+6TAd zw}<m9W3Q^}Ib2mRe`)i0YhjNwbyMC6cjuq~<Tz;TFS|_L3fv?j;M(d~>M1*Ru8D?! zHA01=S8Y2={nP1oyTx%c!h_9;j#GJ@HmA1{(}6V0=5DgsL1p)Xzl&wh*=pB3$#Ly? z1UH>y=qAB(@smE|`b>=xVk&=Xk%_Qsd+3A0;lgaaNh%6INyq7d@hb@`6zv~uHdEt^ ze{^f{e&^L<z{>RzI9YGgwWlw+aP>fpf;~`RXnOy|B~X_T@ev+O<y1tOOcrI$F(g+X z7}_y{k@zuw(DwD(P;EPAVx=;LKUIE_>lqAp?%<n-*mS+O&Q{aqNwLabZ?Grsy=2z1 z3a0Eh7$3BDamUHG&jTwOS`kkX*3*!a7n2#`OkF0d${7!5efsJ(i%<p%8YV0--41(O z_@_?GV->G%Q|Ym;dLP2-%!<S`wu%GxAt~`x>No6GTZP{czG@EK%K>GIz29#WG+{W3 z*UTBPzHVsbMiui?RDDbCJ@8KQn4^`9Gd)~3$>s4eR0<ci*_mzB;dgBlg#D$4bU_+D zUqCEvaJr~>wQ2G6<X*;_kKP=ZA!2R5u1hp(5<65?lqeQG9XkDWm4g`xbJ;5Yp>DEZ z!|T5FFjdi!KuU^LDfDO4Ghufv(im0L)9`vPFR9wP)QI-c%EG3nGP%wzuzpRY4312( zE7(*YEFo0eg#D(nQ-hN75&qL$|JF0#qLQ~1_p7Pxe!c@S4Y%y4Rlc9r!c<DX(i~gu zzj|7;#HsX0-KiN!I@Y^Slny6SXfQ}(Gv02tmbFctX(v^h?^$-xa)RC{e*qd_2PJtj zp`bH%ON@LS(o=7D#5X1(TKJe8BmFb_7K;zKBGS=Zygrd-@-ZKagn!pa0h!}~KN6Ha z*OK?i|Nf@=afnZXf~7~W%_TeqyzY=*(oQ+J6eQoFr~iq*g9h1>prp=D?0fh1X)q*T zate}I2p=0~67fC#T|onlt4CUz{9o;AnipTj9#QA)|3rdg^XMM=m>7gMdqnTEQuG|C z#btGM4KnIW<yGYKXlQ6&ZxiQf*X8$Do~Hvr=BFiHPOx3-k(dt;F+<V80%r9^zNn$8 zi2}>X(A5X@ya|h!KLWEKzn`+C>{~NS(mbv4WBXA5TrZPnq*PR}TC9QEZ$*r=U!Hy6 zx%V>BHY|_vCn^X7OJlxEdJCxH?5FTCy5fAH>6)MK@0+KirXW%oxPDqXcbo-VFvRv0 zM_Kq6QeLrq4~y}3vdU~ou4oTfbA7rj3Q-v`Ux_bVnpDHy_D-cT5(8-9_O|mWm~X^Q zB)8T#l9PJ5j-8hJ2QXO@fouGeKVxR@S4!jW=0m@at!ZL4DPxoD#&@3me2%DMF$o02 zN0fSN4H{a7u~_7u^Z%p#_P4^{Q)29+<%KdN2bXtRz@h(!qpI+*fUjS_Udtq)!eMon z7=p^ahX-@S(+c^&SsDY(nA~_Aff!sVVq_#rk!H1%J@pyq^(ZTgurO3sR?=p=6l`TL zOv*h~(20l~IcX#tepyyofJXga^uUnraiz<_EoZLG(PB|SMA5+G;-lTlz5Bsz)d*u; zbTqfaI^qfZiTB<4V!d@kU0??>ZQR$BvGfAfqv^W7i3t^@TDc?LC}y{MB74`FUdW+X zm!@WdE8r*S9od+~YM<T_U+hh?u(K~TTRy_F=2&c&EH#n==g(f+wGKflId9w3cIJ!S zmqxeR)7jsKvoLfCnGY7^;`{G(pB~m%KBX2VVd2$=M^E1szjV*5-B3YZfvfpFrKR}_ zOV26`1|ABthvTe%Wta8gB_P^kQC07{^o-T);rcLqN7!7O-Qd1ffh-tN?(=bS4dl)q z3L3mQ5N2)$l9TwQM<*8ttBK4|pPuo`^Mq-)0HG~L?Me517rQ^uZz8KsPSV<{E-up@ zw1&q48?fVrBw#oyWaC|((aF^URVtX5FGHd+&JP#H8tSKJo%fu-lJMQG4XI=+#aRER z7EmJVg9i*<Zi`}V<vbm4zQzLG$ZJ+w+P=<NO*fW(RPOm==P<y90m$gvyBk?TUVzK$ zLW-L&_eMQc<Pl7CedsI#UH#j;iSC|(un4I?DSc`sWO4OQH%aQtoddi=U)Vc#l55B| z8Sbqwhoo%g>&c!j5-%-(d8aiHk-y$`B2B44^*9uR%K0l0Jku#+*d5Prd&EIR>Fw`F zKy3KD(_dKV*V>BHC4*F~1F^o7t?*5v<)ef%WGc*&?*>{okw0M_EpBh_ZEyE(DI6Uf zN^~J3nHok1iNLZILZ^eZenb^3`TX88M5@+{-Ru3*8wqOa>7~`xRe%l>)U(Z44|YXx zJ$mq5AO3>8H<ifxsMbght}&WqNck9(I9=b!D2u<Vt&NO?L<o`qbSN*6`jrb*2gb)S zvwRW;d;4#1lWoPL@a<2pSE2;2m*R@%ny*hSSM1+^{E-}Qc6Y?j@(F-Yx@Ac|j`oLs z4Nc`X8__C(7@L`e3HrZyC<$B={pdusYV#AK_tSSk$*c`c$KBKYYY$DhP9!eRpO(d9 znSxC?Vpf)lr`9gZdZNc>eqQZ6dU_qt$V6cS(r8?oI8}A^kk1k+WYHgi)SNUqg+co` zb%}<iCY#MX+!zo}a&UFso6NeB!l3$b*3u+SPQ!y8JuoomiZ;MzIa*q1*z4yPlRM;n zcLSTmy@Q7bVbIxFT~CNk+}YGTZB$EL{^JcRjLz-uUT>7>y!TS4(W|IbKJdMy7vibb zWwrq}DHEb2VwEJ&@A>=GHhU(jG@YEnFH>r-U&^7PHW?OwtZeV-u-pV``y(H}lw`H# zlvsF*C@4N%`x+bnlHa&J-}h68P0S^Ead)kJ)t*v$j`XnAa`gtzyI6<zpi)Uva<-Pa zEeLf7azEs}N(jLh;I4DOLw%EvMfh2eV7w?op)tAU@a3yT#58isA!R8rH$9xv@}*3N z-tb=%!}SadU_C15D}!?4!FYa_Y#C()0Z^v2nQIndHR~Eo#a%AYDNyzBxV<CxO8N1l z(4Cs)lmU7~yv)dl^5X6S37+4f?EJ<CX@y?B{C@HP?%?@HULt;<dZ{j#Sypr!m8;X^ ztFsTw&gbps8Eom8n9Hu$+o3#Fe#f~DTI`Oj6=PcrFUQX@z<S+{3q}>2)%F=+R6e*b z3QOZ)VLhDg9bv~|`@<rm>7_EAY<vid*B7RY8Gzbvu2Mk03Mm>IjyAd@E~TDuY-*{i z6LNbvwMsEAg@*i*x{=(tBlekx=;;C7z!m#Xqos=kC9?OHZIg_U^s~u^bdTDG%cC)! zhCeMLU7!p4^IIQsv-kE-0n15iAr*a|cf)!lY9V-Z8RvJ1d<#0vnp98kkXib$liaPY zLAl&X*~)MOQ4sqhulM<h*$6YU>!IlNwcAiK?;I!^di7LzM0|O1J9M)Hdjf{f<zusx zyRHv3f`D@=QNa2<4}JBX*Y&WGb<H<dHa%ahMpkrv!A7US3p&%a3S4{XPz&%Ub~B?O z*U+XKy_(9(zY%Su?ZdqWVwxyW-=3M#I6OSWifi;ZNb(&>N?I}<2?-06l9og`z5@OY zIB%+hRU$|-#ACiI1tIPKU0GuPe7K*vH_#^_u)Hsj?pgl%*8gll5?-!4iQP++&GKnx zD`0tW_~$;tF%ErIvIG(A+>ZH4J%W_w`M;72WPi6<|Lr606-DCfP|>2zk~Dra<)5Oh zOTr{zd}-pjV#O!-A|R;z_tCQ@CO^OMTg#Zg(5obtr+@5Wfk(ubFXj6#;xJiLr~L^6 zH!{{&yWBH6UnrkFIHZQ)q<4B6OH(!5dT#(#d;=016^g8MZI|*I8QDIx?Pl^^Q!ei5 zr+9ci&cfsN{iAdW;r@5U(N`>rijqlTS*f9+PnHd$az%GH{f&vjHr6KSM9B$VCk?$q zA3k(Y&Z=wBU^)Qt$B;DBtDAL}RVr7`tsmpzUM63ZNtxMWdt^)$^Ob-4=1uJS39A@n zNa`s6Qp^W=NTTD@<-^QBb~TezQVvGCaJ%1xpq4wHqP@dB@pscCe+~a!G9VVAF2AX$ z>gfuG0$?Bd8$l+e&j21Y`h)l}VlepHknq1)gOF~xe>1fIj~_c9su$vy24*TAe{vDw zq#w6R*@8{sS5Uz-ZHwfGjZEcZJ<AP@)lgPY7=c1i5u>K_Sq(}WPZqb9`Z=z5;|@II zpeHz#Hj9yNM_DDvjrFID8Lum^vMnwP2$NDhezCAt$kzy~+#H`BfuNCpqg2EoJQo%k zhVwY@x;#v!H#o{b=+1dNWl~UmFiVAN)H_G)bMc_PqA+S>zD6b2*VBXbrh2Fu%1jR2 zl-t|HppD0_sfkgBYgw5_wm=FD?0{KnH&E3_-<{zw&fz$GG|Ra>oEKj!X@s?^$?Alp zCH$b{!?Ww{0tO?^ULcNB=bOh;Yutz&PX!fm{S?Ofy}H;ygU84I27S#h_vfFaDQH~~ zSbb%RRP}0|RPHghtmWSi^fF3n$d`h3v6Zaa{q7LYw&`}I!4@v+`(?B8fDgaRO3mRu zB0Sa`jC|$S@)eyMv{M~|jCu_|ysI`oJ44E3#gZRCo)#Zc<L+Fhendn(vs~dM{_tKY zRt%MR{HLz<%Fg*ajyLH2*}h4VCYyrUX>kkguCtad)zz(I<^#9%)YP#EX*5T5)%16l zyEMufU2~p-tiNn!lWi=mHD*R%_gw1Sc{m@1?-cP~&CJbgu5Ypz>cOhf1q@{cA%{ms zv?0se+cV?OOjvS)C=SMH2AfQk_ZIY^0d>BfXhp4!mzml9&~FK?b<HZCc3t<);jCqg zch79ZoXgQ2ftt`uW1uwcnq}B(y9fx;oy3+LVjsF*!i@ijg~Hh@OYe6Av(^J-q1Tx% zcAqa9k5*sTn$H!FnK33LfvJmVw1(l};7CNYf1-FDF&C{cVpBX(yi^+-pB^>H!%qJ& ze<PL3TRE|abTV-r@C&Gz%r`pcs>*-9?(5pvmr`{ZoJH2Ex}v4!_3W$W?}iCns@+&S zFtM?DG7T~F&5O<67>%_Y9b^5L|GI{TpX_Y^CQLW&Q4cGx6M{;l1u^%W&Zf1Q&@R0M zkW*OL#W4A(H-Z2>MDgQgh-dZTbXbItPLDCmfb2>(h#^0Hgrf+>{m?9@xRZGLYRbwu z)Nc~pp{*Mb4l7=-ePb7wNIm3q5pg-2`EoJ=fgO;t{^KiXN!yp|Da>KLfaS9CRX8JW zbG5J{6R05@aQha|xUG%@6<aNPUv&31Y=gGA)U7s#xmk5yZXSKg(<D$j`Xn{|>Ol1i zqR7H*%ODUpV^GcsZm={}<#?X6DMPS2vEf^Iac);pUfup!b|=w84Tx?X)fwOIb8D@) z78BGLHZyFmn*FQ%Uf5xRoyo29tJ}L;qbr|$>FVQnEF1>ilad_*B8-~#D?tW5#FCvo zYakW7q>SlM=OWb>dA>cXz`#iliB`Tke~)a*VRTl#;85pvVoMv{-U=mM9-}6-=bRmF zeJ(z>d_oVAz@3-z50=~dh^I|A_`I^e2^J+oA=DZ^*=cz>8X3I1$Pndjth@+Q8GMTp zB3pFM#pSq9`oNo*SUEq;N8=XuaP_yRyZ%)NWyFRpowf36PO)|q6aaNyvob+Z^s8!y zhTou9>O%f~+}@E};9Z_fwjvR?3&I|c*FNUryEN#uJzK1aZ()b@ethlGbSeFui|t$; zstg+$+1SWPb5Mz^MuU>-8spYB8P=CbDQ%qUm$V4yS8X?uIaMZIZ|Hg#7bja5Wg8X@ zc~esf2l_D+LYw~3*pU+Ol~ftz+HLtSBDwNztJn#(L~v@dL^jAuJdBCosibVGzbfX+ z%L7T1-q9{gBIedx(ie@D9tSzt1Na2{156mO_+8zt^MqIv)hdpS_FcsfNy(29TCNkv z)EfA46)tTYmB@60e;}RlOGBXyGDj3txs&-sznYk*aZ-J13q?L}*4wOc5I%P@`BanO zZ#~%E@8syr?A99R7%}$6Kg@C-Oz{!MmDAv`5-vS6V7~0Su}2s|&dBIHF)IU$O5D~H z=zqO8s-pfAv3_&3+TeJbz-s+goS0tw@tuBh6)$I{Olq-W-uAegC`*Mycpu-2+gr`A zU^Br+Q{#Jd$i<W(#<_B^LGniJeBsk@34{;exxbDQA|);7>OD>ajRkWhU187Ei!svu zH-^^hs4$m%c*|-co><e5QOyZEM_at^tqBbyWgmSIvhj8{e2Y82BtkolUs|kw(sYod z>0H|#M<9G`wG&k<n6#PHjm*!dZY8pMO-k=NWdVR7jqbF<Uex!K)|JVU`!*88pR?HA zS8+wT`y{(sdzWwm=w|N%UqpS84Q*eqiq{kU$!Z2I`NXqbZO4)Mz@DcjP8wUhR4Jm3 zlVs!~8+keFdWbB<b#WTNJdn(Gf3iivqJ#(Yvdwl8TXJr@US@8DXNysT67<+^d)=g@ z!U7?5Q$BYmF=mhIO&P9HgAaF3OXWr-P=-A^Vs2Ld*eG^V%s0cicfahj>=ar$c;5lT znu<<_!N_SDUS5KJp;^<_>1hAkt9$Pb{Pr9k+SZvsl)<jK3X`+WicLCU7g$ziSo1!K zHF1E-wmocJYB%QcU<-d-tvr9+>Yoaly>lN?ykDB_{p}+Er)rOr2_ty1Z!Al9LDPT& z7BTvS-pSGM=G!pYn>WQux_G{~R=9C=Kla9F&We&a%|SK_NOKo@?6py~wTJWG`tu0} zC@3z|B~7rxWxURouLjZ{!&-6-?V7MSUXPc$xSykM>&{h~udJ?zTt@wo%4N#jogRHA z^RT965W`fP41=0}8O>6w?i61e{ilD5vMI#B+;jmugKeG1>AXDvN4(N%5$sNUtUqxy z--`vNxvs_Oh)1S+d7oa3UF`YXwRzbKOgfyN*8xAE8taAq2I8$X$>AK}yvgo0jI}*K zzt=ytnA&Sw*FsccM_gqvWq0CcFn$IEL^@2~OlkIus{SK>cJswMh=0kp<@*MFD22av zn2%0kYRuiP6yqvdx<D@PW+o*0HUe^=r6;fc`I~S`vlsiltTE>73YFe~aI&b`Vxfe8 zVg=4Nxk*_n?mw?{qf+_&ZS>x)HBJWU3wuo)T{coY_0IKDKhGUSK~e%Q^K}Ya$Edg| zkZZc&wmn_;LZn9b-6^Pu@Q0dTWNcH}`{C{n*pYM%Gp!1ro5q*u4!v9OVap}*MEMjK zF2%(GGsS52Pc`y`;Ou>Ilkb{GaIfuBj!6Nwj1xzvzF;9%8kfm`Y5~4*@~jZLy9%wX zEin|L5EMdsnRiW6I8hBycr7TqENrp;CweYLF6zj1p0KgWWqfB3+pOLD{u@Nvslub_ zW_D6pWv*hxrh3=b?`F_SG$9oY@g;q-DZyKqC_k62pwnBOZ26J=lWklazF4IA>#15l zCE8VnLn!lCK(+nCMu{S5L)p%PP`5KI<ZaJ8+HBp&8|}&rt21gw+!*0VaKcqDoD!GA zqG9(9@;2e8#@p**-B*XNlm69wXkP$i{rA-`>?t<ME=3Xl81hzHQUnR{x)A>%u^P=2 zIP{^E^CDSaMi0PD+F0&{Llpl2OXlWKKsk?NoLld@qi<x*?$NGqF9l|_=rEYktk24B zenOk<%7|G?<(d`U*Gzjv;6G&zp>8i!tFX?K0UCwY{%1fA2XJtugQ}wiVjiGnKr0m{ zhP=D_<GpmmX-06=8bt~L1$@Q0lhffgg981FyUX{Dc@Hl0jHEar&*-e^HR%s^oGxX3 zZ(wMNqiHpnY~%qIYsupw+o!1^qqV7#Z&*g3b6}v~&i0pLf&4!;MS?zep_DEolhw{= zX$w3n;TB8vuj)z8TWh<7bA#%wM+(tpr-sR>+P_16*oPr|OQo%heX1*^nR__U&^3GK zM!Oq}qPLG8&VGz>ks6;+iH)8kztjrR@~u?Qu$q3A5-}~b&-+|7)km97-;P+JIVo)H z+ZS*9yXgi`vvq*n`Rz)Tx!#(!q|Am2XHifZoe)o1#wNcU7(JAAC*r-zL^AuXpcHyi zR4VbKDw!u(?)vI!zGC{URfVdf%)+D0#EyQ%!E0~kZ<w8#y}t3t@<r?AC*9zr8Gn)V z?h@qymUF&aG&8qj16JqREY;}`<lRXzg0uX?P*1~oJWIuD(ubR*r|?TKf6{wI_Exx6 zcX=4Nu~nN-ASr}#L5%J=K7P=rWJ#)J{{RD5HVBGor4mJ2Y!_!2BN~y=!);FJX_U{H z81m}s>u;aB&dV@z(TSG_9cO<?9L!bz*?zYBvgRF@0IBMrdl4fKhc0QfKH^C1z~c#R zD!I6cY&xiwu41v-rl6}82WAbxWxLKQ=_P(ngz;oev8k@+nC4B{Z-cpFq>6UDAIBTF zc&M+kbAmzLj>tm{B_<b&MnPv4!>@ggzaM;o+7d+18-#qQHZ}wci?hLwiWYV*H+@=S ze_L9mP9698N<RjvSRwa{qk8a##qA1yuz%RgqMG>J5;^B7i$QhD@02D)-u@Ad_gN(} zV|4~}Qjmhe<8e2qaA+kF%3u`%=LkYaqim|CP{@VNV&ho05^vdOOLiRlOtwI+0C>!{ zgVTvUPJ42@ptbt%@g?n_l3F&_NCP-%WXX6KXlTUFBh0CCJ=K)hWU|ZGcd*xmfkg=$ z&Ij@rBVSf`Dfswm8NOnCQrX<x#LZ|kHyUq#d)^rlc}->Lets$}fkcC)6i*?OTN#Fm zbS%;pELP&qIH<ygFKWA*9wHw2edI)y*ax~WJtBhohDX54PH%oUqXY*QV+52x&NDA( zjSSbm-H2kV-H%O9YTl{%_i?J<d^)V%X(0+t6h_D0p1P^44neQN33Lf(PR&2^+F$<^ zrR4fP{mrU+5r?)^J3P5^^bauv{G#XPNHSmQoe!~&FPNF)UgE+E`H5R0WjnuXp&yU6 z<V5RT!$!cNsYEzWtFaNcSamzdQHL6(QOU&{C%5z3(%tmeA#Rt`R74qm3$9s~v&Y10 z`scgE_T&i7dGc52Z(1wzTehh1YY)#*bNz=_m?+yDnaq@hac-}xN$AkixSwZ*mY)yR zUW;lg*cGDBz-5zBCLM^Tw#V8u3Sn{3r10XFW9Hhwh)GY6dd7lOXTgD0BOR^4ESzob zl6$IUW7kCsi4xukd^Yno9KoPs#Cyeqa?sVq1(Rw$C#RMyN=~{}r)op+LBzy^`=L`0 zz^JU@i(NvP>~6X?kn>S8*j}-lwb%lCNZg9BC^^g{qdo;Nu5Cwaqo?1H;|}Lf7AO^X z#&1>X(XahJDY+9#vERO8`V#lK8Mt&jEBhAQKrkqt5x$5tl97AYbcontB{`(wU&<En zYLzYXU3xij7F_}Hq~J?+%I9$Ql;x=Kny7>E_O1A?5suKuf?v}4bnkp4ZfTUZWFN_S znT&Jt`JFttp7rtE!VtLMi0dWiII>QwEOzCel;RTc8PpmdLH)V8-9=z7JJX#lVGXPh zTbdsQvutn6_#9}&Bh!;kCJVZMuGXKf{^IP@5I_;}@W|ncXcd-lo?d7o$bzUl{Q!7{ zwtNQVpip?tTrTSB-@V;x(8mdsqgFh_@#ciY#FadVp!e5H>42@(I{H?AwC`nH*;<dh z2jui5LhAIotfZt_XgZ<H(8CAV5kh-BTK9TxPPsGeU(#%;CGw-S1LCLz0j2%R)p**? zExldR0hYo$+@D)Em*PsG+fBX)?2941&eHSs7@;x7XO|1Lr#pqR*@}-!5t2x@YrVlQ zZd=0h4VQ8&3}85?dwZW>vFQz^gn5e3C&E(@>m7GB!Hx2Tq?EFe6I|}|suv~2<ao%C zZ}6}GLUwnauM8by_iB_&<u1YCQ!yoWRxZz1&WYZBFDb_G<NVX77{gUnNNLNOmQTz( zGfroebW^O=fR>KpTT8M|QM-^4#4HoibjBY+&$pq&L4n^Zg)-!;5oom^moqa~o&FTn z)f$9+v9c}<lpNca-Kd#gj#Tp@4je^=oj^cw+bUACqj<lc78^@H7=Pc;(8e-0%3{Zi z(I6zFri$`#n}57rW4Ul2pIu<bF~QI?BZX!`r*nfNmd#9@4>#~Z%9Da8)q;DgN+6~5 zI(RKmQulmLa{jxyt6nU(cjewQ63XJAb#-+~YoAIvMZ!bgYMH@PYK93@7`?>6$Z;4u zU-z^XzYa;5US{>9pjGTfzHGY<{>M@r37m)a!?H%MjjB*#s`h(9%CA$)akKFW8NL6c z9chQfx8g#>yYomcv9)EKm*Z~g;RMw$K=Bxknlvl3BQ79?z~#-#8x%ziTcOIiQeC3; z7p0!v<sT)JF=_DW$!K}Ca_zE$oaIva8BvPKo<%w}xd@06IAnZe42umk7)KR&P<=-r z=E77RLept(cRJ3U;qYw&O|T89z;Tna+B>M$GR}@g5KMN!kr|>$X9=cWF6Pc|6~U1; zf0D+P60=eD6o}KKeTQ}yINH_SeD4!EP0FlW0W#W?5j87C;1xltCQSw(H6MQY8d&mO zU1fNt-*zsa_f8PdJdMDqMw}^spi}qJgu*+fB1^=hvng$(!q!Lhy+6EDgB#+l#zPXH z+cmDmYySPk7a6rg?cASvaqYW_cO(Ktv3#7WEpxYyA6JI1^qOocxW*&6-e`q|SGvu< zjTDdL8eS?%3H%A=v|h+QbH^imOZTkDT089ol?)$L2=-C}VrRsOV3NN!_p-ev;=Ky^ z33H6iCgt=VrVp2|d4n_5!9{87c&D*%*$^W}Da~?D(JTCXc*N6))7b*{0G0ZNG-|$) z&;Fl!x+{eh+=TbHLSD5mQ&}`|It2noe>nrfkk3u|rkYP5@?mYucP<UPnU5c(M|IIr zNS|YdU#@17M!thL`E%pf;9@^TdL$M`78*NG6oC*W0E5vUOg;Bwv73S-TmMf1V9Mor ztviiu?fpPSD5UoJ0#|%~O=V+7F=ToEO=%H|CPPH>;!sOFg;3_vJA~Hp7Vw6`h?)3Y zPLXEKke7C6OYrvxzODaR&bp?j%9A^hAVOLvNv1t~uIXmZro!?v$dk3wJpdg-r$r%v z5PG-8)+EUQA)X9c6gcm;FT3M$+s3U|8jymKn=UW5Pp&y=cDwm44-Yeyx8P}6U>vW4 z?f;Y_bGn@)zj<X1)6m<Sf*%z!l1LTs1xk^gp%kJ<r!7Cyr?20fQscBY|HhSx*qa&S zst~9NI5{|p`ipg<9$Ys?LGsmjue0sR*aPjmqExS2%$7)KLp)lxoi)Nf48o+21gCpP z{X-0Yi6d1(W@0{4c~XX9wg_D^qZk{&w@h=S(>r>T3c2-(lq~8*ZV5LpQFYL(%w;Bz zVxv6#GHe5Lc@SDZ>c0KD2-X1OQ2ruos4Oek>v+c%Xi`eb%DP*Rs-Gy)TWfKOcLksD zN@ppxd6O`(su#A4o^I}8R4oaZwx1#TYCuP}mW(E9&v4nT<O82VdTN@bzfQu*O8oQ& z5D4bfrPn~j4)NJqh-%&)F2=gF1e?+M-*rC%Tq#?5Z5uQ7Vy1;t=-sfwu+q&t9tP%L zK{Axu;6FceU`|vf3E2PS;D&SS)PBO%B1z0b`^9DzRBd}v)9moqW<Sg7-AOb6;aZMK zP2QxM?AVRE(mol2M_(?jMDKBf()?|lwnOFVk50zM#<HnUbe<F41>RS%lXU+rmAws? zOK$0i#1p{fCOH44su~B1f>;o>)eZ#_Na6)+@v~mPRv?hE>s$S^m7aQOPKnA_(6c3j zjLNPEm)Yt4!SeT)??D^wf}kc#sgv+vGlTz8uR&>tp0johMk=#SXcBuQ^s)<PByhF1 zU#k%_l!EO=%BQI|TfBM3A6{z{@D*DRetYSe=X?{4N|T58k3K3+=VjRE5w(*ru>xFy zgjjyvSAq}N^srPP!g3;<G&KQxThiig8(td+JwJq%)?HUiOT&5Ze!hX&C-BFMYAUW_ zJt_)SRk;G4&V>mqlAR-3RiH+)Lf&fn31U&o*`|NEz2e`T%8m+)Q}b-qHA%lq9EFI< zagg*^``$Q$aIg3~<j~>l#<Lcj+IypVy%HN?^K$)@BU)EblZ}5dV8pX=)ix`JOng4p zs8>3*n!5YbhrddXeV8QPK4PwH>mN-i4Nh6CVugmQP6ejlgMGQa=g1tV<&n)$g<;du zg7$j^xd`$0bsK5F_=d3KZ4&*;s<IJybTk@6C%xQ}7bx_HbM2@f;!*QI5>gE;JKfkl zu79#EaaYb{DfMbBsLyS<9JUR-%jA!6MD?%wL}9|8!eu)$3iRj9gCZ)a5fP4cZ5dGq zQeA}&PyHzR1l)a-a->~k8Dy)=6?<#(I?Rof#Hv+&Z~QWPyBPGFLioPHpa~Mu{4i}D zQBq^{X0%a{7Wkk;5<WRJ?R#<{SKGhVWcXa8;mztQ2Aa<vQh{J%?^0Jet`*HKjTJe5 z7M1jkGn8)LZG}S&;yYq+d>yw$e(qY4(v~~0Y-oSzR=;<M$pJrAim-PKrP0=I25j6* z$&rc7XP$f3UK(c+vkv~e#d;1cjD33eypq13v97iOFF7e#r}qmh0|SY|8C+PigG=sx z5k0Kp#itJ&e3E{mD29ls?5d}Y3^#m|%7xk_jC-M(4zk4LP0)MGwcH~)5we#0!a^k9 zmB<z;_(`CMwuNSJzW<+EfD-j5^N%JwPQRxAA$)tV7nX2?7Hm=#yM($&HwK^qk1g^U z;TWoq_`wSMrV#|nIRihc#10m<Aa*A8g$~=qU~4kJJi_UQS&6q#Lkk)h^?B3nzY)_u z5<4W|nnub=-=41FVd=6*zt@GB--WVniSY@(zxT<?4RpKcuugf8Dvgx(=9eWaHtLdp z8`rB&zi1BZZ4z|<+#$gfhWjh4g|ZsCA%^Gt0^l%K(d`{PjW1Ak8b_lD0{e5E3GI|~ zTaPrm+79Zi$#3BfH@nU!{>8#7D=S%4Xo`j>@S!Tl&LN_=f1xetc+Xm5Mo`0_a7GXD z|L={!|DiAVUqAYdv?%H7LP0|cIA<yibhzs;z2V@PbicVFfsMMpb+etV2OAkvz|vif z(la$NJDNSa8kj=|CAt^4muS9iQJ_Dzop0JcWc{@{@xl>EgRjFI?H^bPKDxNr+uQpz zJN!>&tc>&E+va<lNKwPn**->1Ev<pXM_S3hfEhV%&?*XxFWKDOh$7@cgU<z(1nSsV zI1D-+_g>i!?cbiM#$nSZvG;<Wcz>^eCp1%;hG-lTUllt6cKY&9m<?cL0kA=X02>6n zhFxnck_2@M>e{KuRj*E&I9V%7nQ+XKdW}EIeCTQij?Lbe7g4Lyh>nggRsM70vIIlC znX$12l#Y(BvZAUZAXM~<b8(=*zmacYDP7<L=+2XR1mSX8O_l1VCQM(4G>jxfhJroH z$KP1{wxz~vLC&^|Uq4F9wy-J6k1gJ@vC|WcWr#--^EpZXJ(mYB-rd2e(${=Gk9d== zyrK$#UDHn{X(v@x&3Eu_DM0l+x0%IfGUWq89Ur5hul`cnYVJWKA+L_I@_4hg)Ke>T zo7&icld`36p(F1qZ{h=(PoVWfL#LswO-O{XwX*_f*-sE&bpDM@LyV&>DVA(S2@_JP z_x<Y|JAa#-{Iu7|YoO=(e}@tMKf;%SSDZI3`u8qoRyPh6Z(2KF$%)Y?J>Aw!n*lF) zzNG(S7yExbc>f<--v1{D``NdQm2c3Fj*eDsaq)14zu{M80*08mqoZRD&Ib;MUekck z5{yhlI$v@f5CGii<WiVq-SF=LW?+gTm5-0_uXF*A#LG1k6O*Bo3nN+CNIM9CjW@U+ z`ACzKlWRA7Wq&`S0dxwVRnY6IzLch0sac9gko(>t<>S6qRD;}H>DAGjkf6Ro0$;52 zC@UK9)RR`}uI(Q~G!k2T1heU{C$2$bSXjkn0k9klDfq2+CH%wj_8jkiX=-X}W=2Bk zpA+EtQS;*YJ-Z{Y(*5c?i&*D=rfOqj12AWxEpAFF40a|l^jg&nI@N{~#I(;}ya<r& z?(1tC_4D^PF84h!6*c~qFP)PPg>SIS09@wciQnd%n3$N_O)dkIlhyU{@uG%Y!$_!* z=<i9phnqn}U1FK{3k@UGJ=Ee+L?ucM)e#X@@*MtJe%iAKbFP3dbZ>c^n3VLDRUt92 z-mg^{g3peLz)ji>She{RyJuT%rw(Tp6A0Mg_2)_QrI@8zz>FtdoyigVp3VRu5I6S) z9=~ZyR@Mu@U#^c=LIrX3kn4Ml9~xz=Q7V>Di;40Mz(gj0jUf&z-alVzKNf_XtXiy| zRH8h2jtaeQy8^bp)N0)(iaW%#@npxs=d9kHo?o6p!9r>_l*a3Qny1acXvuncBzU~g zPdr%&Z5y0)nMAE{J(>xdAkkp=7zaGBpo~8N7Lwa|qADW@0fg<s!oqaZAqNK<jgGz; zJ>XvFqdxsAUm711lk2R(7R{E3#|d{1`1FduG>CT1^3f?D?(LN{i%9o@Qnbcz4kVHK z#>FHz>|g0I1-We>ucYj!a64{!-;dmJa0tP0PAtdiLvseSHiz`4>z!#|CXx68``AlM zJ9&90r~ZI=U6kW1S0@KPm;LLM8Ns*Z?WeJl8>d*lY&PTHo)D=DvF=<gO7`~XenDA) z)6MUnkmY`sb0nP}bW_rFDOoUipzCE&85nqzo9<oaJ!eWD0nm{!sCW!8ay*%tS*XMa zE$u(@ZHtylPc|elAlJLeUmos4qg0Rym_5dF=tY8%IBJo*&%Mrj%=RXW#n#WSTI3tO zyQ&Aem)@QOCqr9j#v$Ot`W9txsbuI^JZ0wn?+Hsv$m#7YMAd+Yl+>^_po|sr2$P?q z+jKXiS8CV0SK=*r7K}HxbU0VTi9n}a`7#5`5dVOkl8Q=P`~%<(Q78&sJMLeH0)ly4 z<lM}RZk>nqB`RxQepz`nIr;js-;Lni&BPzJQBOo{y0o(~RH=A++xfhacs;MLiFc?0 zgn$J_{b$0r_)qBqYDM$e#mQg$=ihuO%MwKl_}mV)T&01y*(wEb-G%e@-UN>|Of?~q zp*{WGqAsF@HX>zl^htm&w##TXUyIWLPfUCi5bzRU)hO%g>%X$1|C4R@i(vk<<5pW| zWOB%TgqHaV<WV5x<!e&h6P0x<lz@AkTv=-*N?BY%Yy)i5*||Ajl1s|pWc-CiX)Hq| zt?T8eruXeR0y2NVGW?e*0G#?S)V*a~9^JO(n}h^Nun+<S2#`R4;10pv-Q5EOcMlNU z-66QUy9IZ55AOcp){DIRy=UKZ_U?Q7c7N%Q@I$KVsakW@oZ~-+-sT!)Zv;W>=e;m! zt(VzziHgFXpUqb8IyhX#qLDmZO@OX`Zq!ZzcKvuNwr4w)M@I=GnQ-m511j?J`5UA4 z3PXUCg9R%H<dU_bn1u5yzWBVK?>lNscsxIlZ3Y7a6Biq+X$^caW@fJ+lJ83^D(Grn zJFz%fJbNn7#r2VpKLm$b|6mB9QNEey2Xh=2t@d|zAb8<BWQ6F!=@2{ciNAzoM|->W z@4dAi8SSU-CiF(vT1RkWQ^h_;Nm-6gvk8Wkm?&9US<~VcSwI!Ly^RqY%c6gd>sq7? z+!dT2Zc;2(`NtL=(?JyM>@Hwua9Qp%Y4rzJCZNxDqxz*tyo5jNi!|MDuzalr>_&iY zw5*y-&ohlU)|bd@;8HZ*xX6QLEeV$u)-C37u?%VBflHzrk^x{>_rielz)sYP&MeSy zbv`W2tEN|$(ZJe~)K1G}58BIJ_y-5`|15Rcj|U{)S>K2LYpuzP`+NGSqJ<xC5l58; zC#L7-8mZ50N;v^U(&)isDNU2*gW#<GowL5C=5jC*RzRSuq5{$|Ki}HQeZ0L_FC~S8 za}ZlnS;;l-?h0$fetEPC9_sDq5_47ifK=*j32g++@a1V+2s`p-Lagi&27g98yy;8# zJcm<s3YF{pSoPME;%LGl$!Z{``^6zztkP_8&2kuwN#81(8Y(FISYh&%FHYrNtn(zj z^f1+4tN3;t-d%4;J+fSTesv`rn5cDqu#f{*U3p6bg<>_M(HaYoTMp1cf9lG#G`u^S z!9j75RD8UVAk%bzts)B9UNE`|PRz~CjUDXoceI#qFV`P(aCD?Io7@ZGnDRZmHrlUy za6StA5)?Qxbc*)Dx8=v|tPPeUWGgx%Vl2Zz#6l6lLIuFOK)GpiQIYZ_9}O46KU`%q zhiKtqE~yCw)=VsNlhL0=P!#UzMa~I8^}BE7({@Ae6z3GfYiP4x?L;6a>(9(gHQZOO zd~Nf{+sb<3+=GzIv&r!hozAm;#@G0E;6H4S=kn<B6XJz1aSX&?chUiAX09lM%k8wV zOQTG}WFfFySlyC6v3B6)^~}xve%e`yh=>Rchp$C@v3Z5XV2b%A<zX6KV{0ToImGU) zJtG6-uwfxj7w+w)!$FAi4HCP<$yZx(aj?F7!MUI<`O3cbelb_I3oyl{N)`0L03i|f zgKGGf*~Bu71=|`ZO8H9VO%qBBDQ<Umhl^viMo21HSY~F2J(Lm+7OT;cZ<gq|L#OJ8 zey}?``iFS#($)~TxX@F50X~QyKn3*o4_I{6=>-e0-xbF|(%ErWGQHvGv(=F9G-t^2 zjdr;4<xy%k_tnh}P%C2jkv{I0aM&X1sb8ueP_*)7O6O87%9dv(i&sIPh7lu|^F~=5 ze1E4M19f9()O7F-tdt-t*7?|rI?BOGTAIc^6)=egu6!sbj4Rcj<??OKib3Eyz2<Oe zfR;YkZOM6&7+0NhYwPGx$4{nk-IX=rePq3bj?OxbQuwhoT%3gqJ>^NWW#;#pfPerb zXWsrwtO7L<m<iy!fDP<Kf1rfmF9!UmNB@?Qbad2&OF{Q+pBG_V*@Fv<vCNtB=90>e z*HNTE4B))I;&nP#X@t+p8vk49aYIZp6@kOr5|uv%j5S=>dnZ7Wh!JT%dS{^FSXSkc z<ofzLNCnPSD$jb{p-a^!x&P(k*W>nkdzphu{Benc|3i-b7d5}9019jFsDv4N=xl?6 zg2aLuQ*TX~(HX%|3)Joxb{(w*n&a<Vxu?gqhFm+tDLTn@8-API7plUda&?e*iv-is z;PBG)dE|Vksw(Rw@-o?YqU<Twd<zVc>ue=#=%P@Zx4&oE4K3TK-p?Rhc&n*H;56#V zmH+&fZy0g_$!_Ne6pZP5&sR&4>>sw+yEUZG<)o+ULLu?=o(ao-7{URajrH`zR|_gO zI~~JOsl*t<Ru7ZdEYOO5k$yzyI8ASp6Ln-<*M41R#u3T&c7zrR;LBtZ_YL-uvtgcX zZ|M-PEl$_(Ht_w>nJr`ya*!TE8?rkNBUGEMy^v0mCXrFRVK7@598#8lQ|!49TN_Cd zJ2$JcrmtLyJKm`fZ?k!OjK8cz!c_t(SSpRuz_=op>ntpX85Gc8L;IW=98_On1ia8J zSHyji-~)zadionNEA|wpIz(TeM6~kow53^QO2e@%L5r!x6e%=|7kR(`C7waDT2)jB zhz%IKt>O8BVf28QQhz8#zAWV|^MbJ=8!HJoE(|-(Q>B(ArcGOG?X1~UhYR+~0;UFG z@JV`7oun1W=kIykz`rzC_?oy>b-|l)@r0M}6)B&dqM~%bJ<seCoV@Jk*qHQh)W)7M zuN{o{!%7qn875FE2Aq%za2@Q=mdMv=|Lz4C<m&AQ+o)6r3^5;$TX6D-Z3vkfd~8>1 zTpw-hv*&%2X&EW4(f-=SHg8KOKSW&&V!A<*p~{AAI$3jgseIBtRzH~;b&Dt}E;{Y^ z$;>#Zu;9}(7V{A)qf+I_+|8kOriy*~Ut;kn&Nso*K}vQ*KN~W>(HR%S;GIqmnq;@C z*3(xH)mX2E)713ARqlC?A3^Dx5;;!VO(FSzoorEatkrlq^G<2?3dcnkX*jCXe^_Lv zZlMcCkrW@Pm<@AdvRKz9w>F4weM@c*r}5^zRBQb4hW|=^GFwn$S?Y_(;&{{`+uhSE zLpsrY+?^o^t8_JaHYt88n7Lu<5=;>08Ih1~&O|LBrzSOH)ALr^%g7u`A>cuyurYn_ zHj}OTMH~%*z_#L>{hYFuNHo);4H~YEmF11s>XP9S{^Ef_f$G&H@Mco$U*YnsGc`Zk zhsW0|ZtgEMv5m|Xi$gtp(1(i@6(un@maJ<*qiAB#H~X~y(jSsT2Ine~A5QS)x%ECC z>ub5BWw|xw%a}c{4^}7EvTEY}vU1fi@j~kqEiFxdn5iVzPPHUCix|5kL4)~vwGy$# zOcOtahqw?eau~R69u<UEA~>r;MbZoYtz{7glWRK*<P~v3@3-INNpG@iKKRmRB0k;s zv9YGj*F2tVVS}#k;#;b9zUeQ@kJ+)tki1yJDt?1gd!pbbB_+bd^XTnG6xyCM+B^R? zvvp*IJ4-mIK1?=+g5}w-5;g6w{7oO$vI+EHs}Q4g`JNFx4W+40X{gLQp(!7aE|S-C zr#ZG&^;TA+k<r>u>kbm85c-nIFQ6aUA2H*|{Hh1puQ!}LsL}q!x?=R`SroBCTf}qy zWavVcbAy9$l;onwxcV=BwA#W9irr$h5k|}F#uSRv4oaJgenX@);0|GPYSWHty(85@ zJwU6qix9Tu;2@{q+xUI*FatnK@bOFFtd?O#7q!^DC91x+5z$(m`S9zY`wCxQm4&f- zgfgddIF{^mG^;syJ)bO((QLm+GE)_P!GW4DE+H|VRIQq1eza0N1o3Gwjh9Dt;>oW? z4YLH&0ydWOZ}JPjc=)R5v1%5WN}ab~!d=uoZEBtINUeU)d^usTQoGuHt|6gPQxiW& zlHp5F#)es0Y;n6)H2_0X9>qXkXRGjT5g}I<&Dmb}n_HZhtk&{qMrC$pN{R72+19t| ztTQ6y7$&-JQe7DItBTn+iQ_1#`9q{uk*}8I_f_AzTfDWMK+QfcQg&)xEO)+$Zt|9w zYF0Df3Jaakf6iqpmn}CIzEJGm01#~Ch2rc>AGgy8yn{97YbTXWPuzLTgVAiKl0wtZ zIlVPDSE64ho70fv)Ff9^cA_t63A2P7ZPvceH;+kJUi`kcnGX!gd+a#mz6I5a4o1R4 zE5X()6V{T89O+=RF}>RB@j^pBvn~8#{G?EMj@l)x!T&|Z_$x6x>~B{3fBnl56e1$Z z;u1+U#T=5)vZ$!2FCj>Nym*XJanbkXbc`rCFn@SmiPxUOJ-HaZNUsTib)pV8Nz^L{ zQl)axkFrk%WS{$c2JFhJqXb1g^E&?E%R*trWSncjaK$Jq6z(f5w~*B>t&Ao!hXzJM zDEO{I$HZSh=l7$Vn3QE|Y(Occmzq|_zOMFDW=4#tg4XS)$9JMF3lxFfpV<4)Y2J{K zGZ8fA)PSS>BYel<u&5AExmnrLObCzvD2w{%AVZYI)thp21BaLv7_Df%L<t85`q1;9 z|8dXjDkza8h&uAW<&<=L;YE@vd?X33ADbS?M{#(w^@#H2li07Mf-Qh!e<)2Dt-T{v z&aY>G{_F!XA0OW>VLy!LtAes(ZT&yFl>Y+OlOv%m-V%;HaSVJj=7!_1to{ni%H?+$ zI1Pi=-?{#8^Sp{D3GT`$#q{qpiq2`FnG;T^xxmAp{oErv&m6z#_ZfjjOnT%sCHZWG zEyVHQR_K6z@NuItGIltc+1C}E3>3$ssXR_bMn(g-kifvu(B_DUa4ZJn;S?_CxIF^| z?tkDWu#oPzIsQ)04j0N5Wj|?JlKj<h9Yh{C?bk^D{$k%5iaJ2c2G}S>CnYV`Sft;< za074H7_y|L6c^`)NB{$Buf<+^UN$*9CNo)0&bO|Fpo-v{-pXpxgY5ABr0R?s#jUw= zk-5nMYW=gi0U%*tsAna5R~~({v}HmRE`RW9NK^uC+~HXidFn8^)VjP&T>eNeF$d1} zMlwJ>K~EGkw>mmHy1KeRGvYGjY6%AS<3t7ILgUk$9+<=Ci_QeIX4b1p&@xyVQsTJ% zOdEyG1gQqu>dJ)&3wFQyl{lJMbm}C%&b{96jFlU$Lfd3FKQOsx18KR4LXqoz>d2gV za?998x*x{_Mtq*_pyUlnz`%179*Z8=4#FrwVr>7s^O@;cQFd?>>|0t{MTCbV;<C>J z|BnaRTUkZL*zlhx9h=F*!mim8BvHU?&~`Oz;N{DgXlT){x3z{X4avw%ew2-D`vX&; z6*HM2vwo6y!?d=y_nuP14i3&rpQsCfaZ3sX7_{0Yetsh{i#NA9Q@Bp1A1t}Ky~1R? zNE~FP%LDMj^R}GU{d~7ZN=r(B3!bf&6<}On-;0Qfi9INv>T~{R)*A#(wEg{kH8r(j zjpibGbl@Avbt+x>JEgzBpriy2zzu4oM_b2Z-3$O!`^k)@r*DKJS?;aba08!IMiWju ze*R1@XWF+69S;LAzHInE6BENMknh_b?SLs%Mry4DJ|P2ZanK#BaCOfDZ8q2{;2`8h zGTtNx=gP5^KV=q($zXn$weRd?w@}IW$TGW!9av3^7oz1z2ll)m)Gt*AX8=M+C69J? zK`=6Q)9tOyt&*&2WOTH*1>18`?WgejaR~`=vR7jyVpvmM&Gfs~*59Ta2kOWV041PW zpDLY;tRUy|@gmNl%*wnhD(fXglKw2e&O!q`j~U_N;i0O?_YvCK+DW*~X>~DElmY14 zuTiY1EVJeFS65c(b*c1xT$7S;xT8b_MeFRZltHx33d$QFATI@d`geV_hA%HLScCR< z4nK%lhIJ5&p1dGYAb>d#74_s~blFD(cO)giplE1lC@2QIx&$r{nZ92NF5P={2I5@x zbm1CyZpYJ^u5Ii9BN9ZhQsCw1Xm3AWBqx$%NigJxgiA)8DT^l{|69|{X#CB=so_F# zRDkSk6D0rD!BPIJUUZq?ad}0Tb1btr8A;3*Y9GKu|MODr#Y1JtERd{FP$tpZE$+~} z-retpJD%+rHh+rf(R=uEIx)3m?{f4(Uq8FOJ;UJ?t%+rIKkp%_Uq-*x*th`dRwM}p z_x}5XLqN=8kiP?%Zt|0RYJ^{PM|~ICKo6VJe$`8i@|$AmDz#d*lak~E-ZiBoL(`{I z@R~Abi+#3vI9E^mnX2Tg_R{@Q48>62P&07AVHwK~!lCE3&pAlPq_+O1rDZA$?^8)- zpZ97iEsCw#myB%H!ko6Yr|O~+YT@b^3gFboX-^SWqb$y5=^x_harp*w4fBwVYKQcb zx<7Lz`R|@SBebDET1P}-p3{h19qI;<_C3D4hkMeZMkUJe%XJcM5>$5kMF(NCE>fx9 zU21}6EA*|@ob}8SYW>^CeK?)gk!<E`l1f;rE{;F!mH5AbpR%LC-^QT@j!+xLo$T)( zLF}A2f7J`xTHv%HNiYn>`63O|i=^dGnWCnpk3yw+T<SSx{;|~8?BoadKX-g$XoF1q zXp#DW8oi<CMPlR9B%N{t1b(u)6CkLSJL=E00dmPSGe?-M3u~<rE<^kCy|Gtb>z_Y- z9PzKnGD*3=7;xnNx0Xhv0bA4Utielihyb2v80qYlP7Q^V^VJ9!0%x4TdAoM7@iROg z)X`AkPgz+swYj4IsJUtYw<iObg}*FGWp;v<+{RDdKc|@V;SCCkzCiuYhVSh#GfWP! zZ~ZU1Sjpe`J%38jD(p2szBs9D|NgHdupk>4cy8sE1crm4%>Ms}%G9hy=W~vW10J%P zPDkR;R3OdgkYWUtO-gm31|~CkSn~0@p;_NYT3tZ_MqmIpM8jbi(0-(|d&V{^hz=xV zt@i*v(M#zOKM$xbd;3-jbr9l)k_}e#jzr)3&IXkl2bL9}WXSufwQnP*r;mFL9hl5Y zPDG?&{{(Q2*@K>bV_o7&aaUv9iO*t+R0Y~lNVNLS*+d>LMeM0i8EUUYq6?QQ)GjZg zjhsTq%3r;k5RdG2FV-JSJZ^~rNCi3$iP#tz;3Zw|Sf>g{E=A*Hn0<fq?E-psEZO-^ zM{rBZZOcFhf&|sKo<-`K7~l%1iG$Y6d?QBFG2$cDxoBr68`Oh<vJ}m$<Xumg(}Rks zJ!2D6vgr8eCeyL=$Vj?WOVH@+<%w}Skj_!|wIglrL$Xi{(bdOQy)0z8;pXlm{=K_@ zHk(n}8j)Q<?)r~|1oqfPlAoLIR_;K!Ff5XsToNJXdUdAHC?h-ntXv)&o8x5)^qHZ; zrER5hqse9ySf*d`N<eQXjAhL!tH_tp9kdPCpY1Lnj3J)eMx&wCVC>B1E+pN-fKp;E zlMs_^h8O$wt6p7g-CK0@2j{JK2Oez{Y8Lq$+Bz~PP;^q%rC8N_^OcOB2q~H#fv=FO z<t!^ekC_X&FUk~!>M+$j`9zRipkANLSKc`@!{l`CV>(j`V+UMvsuWok-DO|P1CKpq zIIB}Dt(e&=Lx55`Tu$fyh^Ggz*u?=yjx_pR86*S@SON4~Qbsl-wuZ!DIs<&rd+@u& z9UN<}rXYM@KAS!nr2_H|Ey64iPV3d!rd^6&e}2DzxJgPOPZG64fD6<Ic8mj_wy68_ zC~2X6F?XeC>!qEB6oavTUYhu&tB)Ag%nUR0bn!nENV6cycAp>xvD$bpC<%`ZpZ0IC zi1EA#6yhyE(E3%&ks*bZtFY->e8iui-Jcoq^YTZPug4R(UfuoN8fCdzTN`Jt^f<?X zML;}Rs<NUCSK;gEm_|*lh-gj55@wv3?40cx;c}XLZIQ(0Ix^G40<+rjcQ4>LgdS^9 zqh{~mz);7;>*`uSz)1}}H^4CYkxyd)d|H=yDk8N&xyKC;;xe<;!WfV0YL(iJ<UXn? zr@ZZXw24#b!pmk0I5=REiy|Ds##U$Bemv0E*HvY*P`bHM=!?ldVbRf{J;G~|@yN}k z9s@KnQZ=v*c%*|nwA}`q*%1uHv5$|1rmFzm_8yT=YMi9*K7Yz|9C9l6d2NP?38=Gg zCXToqjE6L^s!|P78QPg<0o3P(PpVF2ZOgG@N{2|wAWG&Z15eIN7_oy3>mepSms_p{ zCgULBc2*@gf?MWEkIpfqz}(~XG|JxQrpWn=?>FUdvbqze8z%MZmRBnvhJ?~L{M+}~ zT<KhM|J0}zUe3%%Kt9V>z>S?N`^UXd>XJBJs2dN|VDF%ixKPK-H<m}fdObNGexB?y zn6_bsmE@|=mRLlNz{?jdSRWlx%TkK3X~Yz@ezdi)eZzv{k?rR?fa!FOT>u#Ob1<kf z5D<WAs4j3E<|O5wiU|+D-aVP1E`7PR#U1if@pzNj*f7Nv!7pPinx2AP>t^t7&JMT6 zhNZRGn=w8ui+mx-|7Eko=FS<GYr)JrRBV)Yl0Z7bRd3dgxMTLjc3v|i+toB$?oHzU zEW(_5;OHprvs)4Ix)UcTUkO3wMpIhE=d-9g!t&RvmDh<4wo#^wr2_TntvIO$%R8DS zn+?uHZ@S(pU{tLAY-qT)F$CU#QA?(Nd7OIk!9dSuQe(-&90_6Zg&(d>QEAD<M1T1+ zGq%>s47SLMQsUiMgHRi;tGYWW-gWR$bDUbX{O?P2?{p8vO55`D(bojOlN3p!;P<9z ze--l^tKI_e<%`K|rGZ=1Swykkas^jizET7<tv=;1b9hJnjPFo)cL4DBavBcoC$nJk zg&v+r+Z714UYqWjA__5+Z9b^x=<gD##y_}k`YslOXkt<Ck@Pk(I5X2r4~nW$d!o^) z9yNawm(2weh0%18>o7~n*vrO!&e?i+2x*UY@5%)(noL5F3}aiR+!XHm`Y)OY9-nfH zajwEpz1&-(Fy+Y|-LEta1u%nZx*iPxQ5o4o3s??ZQE4b#UW`WbPhx(8*tYY7k*i7} z%Cz0~*1jdnp!>#pojAZDJX(Hy(I1;s8>%#-cf9-!EG4)le3-TxLM4CFxmd4yp8+=w zu?V#(PIx!xxG%ODKJ~kM$*x=%hDTf9ibeGGLy}o<x^@tz@9&-K%w|f_7t+oV8O-L* zw|kpQ6#ID#(#zqX8K0ncQ#L2yhs8FWp9D+?GM$1q41?zN1SO8m%}t3Us?Np1^HVeZ zRk`QAD>-OsLAtI*r~=8=#!DuqS;Gya{|{&OEp!^apDPjt8_Q>b?DJ<;sd#8kDxb~} zKVWErEQ_!;hFyp}1=WtijRCR4UB(Q5Rg<wSM}~op<H>@G<7>HPR_nd-_@L<zsetA= z{n^Az;KFfr*{AfywJ%Tq`E`vztHTZe!cg8%+4MhBY^onL-kseJw>XC-qbcMqNNu6# zh_Z~B+gaIITDCvsbC8J>b?V8f)`-5FDLl2p_d(>f#n^=FO=fb{T8}@&o~!O8pWJh3 z)?5P7>z>cv`SU5HG=5DSdtR+oe{mlao&#eMLuzd1P<xewVhkOxy0)-|yFt-O{4l6e zoDrp0?=?!bK342%JX&*KK}@;Ku0JUeP%-yL8v?jOzP2R56;_!3L}YeOZ$Y4%Ud3Q# zM2O~XYa`UcC6ah=MSe?oQ19vQ2nF%caOTK1ScNugU>*@oy|g&c?x&mXF;d7CKT9k3 zC*OB~IEn9VOwqcYpXJ{7icofcrFm}z#5hqLBfdDq=^jKsM{By5mn2SIXKHMwLb;qf zt{#z}0fVLZy}wYTc^F1RN%T$f@Xr8(;vAaDkaGTt2q37Zi~%e3(w^ea{a$lXwfOlA za(~|E&1#}~YSz`*S3w*R`m?K%U0jD!0?E4Gx8K;r#2gv~Vj^PAYq0nc^eT`Dz+?PC z_%>1?C2mSFswX8y4Ln{-(dJDV%w}KPsm-oakM;M%qYHkr429;T;rv`%lT<7!ucXp- zZep%~xV+(CF}d$62od(hFKwRQt*i8SwC|{wPTonXdC`vP0cB*^jD8_qBM5)61a~aC zizasW-I<PZx#$2uMyrHa^hcdWC>HwOG&M!4wJz!5D#7)fpVTBd8_+2i#wT5x7N?cT z7-(oPu}P~C*w{yza_FoNYIG)NSggA!gE8Ho-8tH{E%RVwvNF%^j?O5}KM%oVc-@1e zN^G&*j-3ad6JtemIlC3vo(Q&&KEY{kNamkZJpc3t`s`5GM3?@nChmK?=fUwO=#(0u zP1DtZWLGU1PZIT_1}8<z4_#-z1FxK5<EQi(P5X@+a&Syc3=9bd0`PhGRGAW*fQUUl z)h{~o2W)$ARE0M|oqF?}?OTvp<9&E+BE6vN1v2Y0zXrSm(D{d;d}3rQZiSLUyd$4d zScVqp>ckgtuTDpOq>;Y9=*`m?{r&5s>h4S-3W?G@vg!+q^VCnldLRKrvTa419^1>s zO}GjLSz2{MID&s#Kvk(Sra`MOSj*#P0&>dL#^3KI>wg*jBi`l9g;a9)yuFjdO5UFG z0EUehihxrObN0*GY2Q?+61;ZXI3=YTA=2hXKj7KKkAUUrg|sz?oefn5gX&w(L+1D4 zupDWz(?zQf=Iqdch(>s`6FwLHx$8Fr?Agjza!>Ik#X+~>?PK_)1ZWW)4jbq*jb>AF zGOME>i#7CxC5)WzD3xvv$Y{aATMGuoT3IdP>h;2BP9G5xlTb?Ic}ccsbJ-Yjt-7kT zQSxs6_#uJ|583;MFfe#JsXg{L*SDm(!B$9i3P8Kn&fyc?sYqRV+(S$p?-Lo8(<Kye z<5wo{w)}G5*l+C7(()1k9rbI{>MDvwLQ-Vp%GJ>23xB^h#@XS+0DRaVPBLpap{r_@ zrnCnZ7XC@BRygRgiPdz5k}zRD?d{L2N3a+Uf3ZPkPGdmw_s4f_Gc!^@Llfdx2q_uZ zpI*TaXudX0!b{igbu{~~{l>J9?uu%^7uhG;b5vznBl;c#J=wPjH4)#v{ASV8;u1Pk zM>1DVkX_3SV7Q}ib5y$cH_4|z$&5KcB~Gv{l-kwQ?BFI^%44En`II=_6y2>PS5-|i zv-tjaw@SR_YLU?ygrmF+{q{55@DLsX@nCxt^c0ks1Eea)Y9P62LKXB8=BiBZ=T0WN zvp!@UE|kONQP9%DDG;Wr+8;KWRF(1zbKVfB-diLGIoZv-!$4o#xD*wB@mKCyFdHkw z=!|7%o7&j&8>?B*>36f|L^VCiu)r@(WU<}v;ww^5R0f?hpVYXr9i`JRDaF+a#;Wd; z@v2;luuz=euD%S=+vIP5?j=c)l4l_f(CaBJeOdD)U`$Yg@b>f=IeS!v=GTXqta?t- z2n|y!zONsWytlrR^^=d2*f5=?fOmH-`S_0ZeEEl;gEehj5pB;Ai!Prdtvs<#t-<Z? zQ!s2^=-FOW`y5{<oja~n(}G}*_WsO?buX*MN~ZY}2|{Yd7Z|Cx_aD1tT=03X0N-$9 zGehF3EqGbUJ6hv{t;6DA!pugrqWK<s?bq-}P1rQ`M9r31l%TCJV6M`NjdWlGKR9)T z;*4<edCT#Lhz74Fl^1@bPPg36nG`GFTeP1nmF3iGC%n;A9n--?yE+dABVU?|%)90I z!8x%{b+w-xUNk~?<{iB;-8M(ckVz40yC$774h2CwcBV_g^L0AOm6e%UF}a_5nyoay zJXl$tn%@u{AadiXB+yVoZPAa8(hSG>`_b(uj*fTcH8ZSuA9`TOjO^oC1dU%io7IZf zAx3#HDVAL-dUJKp-#%D#rKUGFwxr7-T3MZrv_ZdszTEDg+S3G(?}K7FvcWC1jnQ@m zsRz~%II8Qdi);z%8s=KnU|6A3A_|3?(N#x}uX7r^)zFtW^aTp~>pKV_PqzZ(>56dF z=enh{R?!Xeh?eNy;PC3<HeO`4ghSim8YE<rPJa4C*g^D3tL^oXoc#wJNiVEGGUEHx zg|r~@YZC$rshaZ`xgp<%b#5WvfOPz<An=+XPx|GFj$Dr6r@ZpAvX1b0C}sJlL1nW- zN^~Nf2El|M2^q|dqz1R;G2Wmo@JNcY$&LcaE_j2YUoBKXw$e1;=@6<D%lsKFKMAcF zbLP}gHYj!%{ud;a{SuEHK1CsmaceOX>RxLeg^Pn93H=rlRGQep0M-(E56Hx_4iU9z z$Q^2o($(Xq?I^28J6Na8<)%Lv6Nvkf^nU%~U1|()#5$Vx8`I|ek<kj1?2>;<@w4d5 zMY}#>#m64c<tKsE%eNu^enEjGLglNb?})!03nfCqglw_aXujq*1js+>)$hbyHRh@@ z${!;U8KXC{Yc7}!IrUB&u>3QgFdlp2^yoy#2GFYhK#uCgC7KG^paF7#Y^rP6dEWpp z{6l^nL2*|%zaHYDN)zIZTSRO&t?}qpJqj_i%vqzZh1$zNSQ=75j^#gC*jab2nCJ=% zD_e__nZh98U?<ub92!S>pWU-tAGY-vO`382PAh+vKYE-6T9;|)lS_hk2;b&QD7+bl z<D&aT#S$KYBq@4r{CR``9@=l@zT$>2be{8mn@^!wp>4oEZp;rjT{l{;bhq{}&=>Hr zF8l?IbFjIfjAm=xWC_XhGg=n9&T!%wzQUT{P{^)uelSRV;8IAhYPdz{WcmU+C{jVb zf>e>KVEcB<%XHRYB>{`)(%`xKo|{5+mFnzZ5yK5x8vC8zsFIV?i$FsnU9Nj51J+}v zj7NKt!{_)>uJMseizHAzRCFSN=;_Jr!?C>D(#t9pH=Vs^oJyNn?C;mXi{FQHzV4I0 zGC9G1g=yH4L>HjQ-x>?;;jx6>lwwM}ZFcmq%vXRC(*5KofP_n@Gn)?^+x~7)v%ceC zHM(Yp<AczHZpe`cO;<3^NlW$;HoGke6VrO7kWN^8=Sy#=T_lbhoC~(gQ@%!Ij8wW$ zj)$veI}?belEu+_ga_=%6b%pC)%NHI6UuZZp2zlq9lsl{Z6{gbUGRM}Fd)PN<|!P| z&s;Q0`8oCF$fjpz#4$NuRnx>j+v)?(?F23<gr9#&n34zxkg=9jXN%vvoV)V~h^MgN zQd>XaXQeI|H~)PNoM|H3esa2U3_v#=?|9Cfx^QI|a|Y3yr8QSjx541gd5R;jEY|YO z^=0Dj7p+C>_?rBK#kdP=5$jku0<?^mCk~(Mc$!i=;L~^Bat_y;j@gcL)Kwkpc&9JX z*;`vrW;T}V@Uu1_#jN8x-?J6P3nGCIx}Ym<s9($PtU)L(U6UvGI-TZNfA<2!oOM|{ z(ak@X_PaSd8M?Z>@(YdW47%1D#N*8r)a$q3MK#I~|A+-S0j?To<ss9uU$-IUs?)5` z*AHDFs3(yO>x5KPE8Yl?43OZ3?&caexArpO=*k-aawcAlwN7c^5P`c&6|T7!v@<qg zAQVRAvnq>VSKnz$l?Qw1c+plIYTjzQ(vD2asXIYy=_Hfw>Pf0ye300l?k(f8xRTkO zv4ZDgqlVO++4!AK!Q(}s2@y01>D$T%F953+wI<`>Vc>d!ZxDa57Nb7wii)Kw?vx*B znmC955i){KD|Pi3YE{sW9&T{m2~KZ(>50d(Ah`9K9!(>39tjv&X6l7vg`RTWb;ee( zpB>I_WLiae&I4qBtLpE9oqm)tJM1r}w5khww!HG<E_K}3t3Z3-tDS1U5`d3TrSg1b z3&s7J5%WDQjR+(sZazrp$kGlO2Lb*_$9{3HkLP=uj3+O%IN!i!9s5^Rs>>i1>BK8R zLLE2ew#_Y;VeBne@5z**=ER@`H8EK?H>gj>uU%o~o&nt9ATKertCQ#xVY-Vb<YdC) zrC<Ce1AMD<2C${O+IIG6$C6il0-EjU$v;RYSd}xN7D$7U>lpU6xI7;FI?OBq&!L#x z%kbW;ExtjC0Aq>b6RaO`Ia;cF2$L^O6Hy|<>5!J?aDrbHtxr5Gc=yec?0vYl0G^78 zLq)r!t{3#Z9Iw~&&HG5_HQ$%z<S5p1AEevpr)doR1Bl7sq>>KtNF!F#O2i`5lw~1? znN13+th}85<(zXwN8H>fXNg+Hzz|<7oD09-RC<D?c{ERE6k#rD&AfSn_0hfR@{-p$ z%9hBuBx0&)v=_qd>k}!QxzQurZeAnxeSf`_Kk*xH2)C^9N;*PP5*?{Rv4p6w!Bm!) z(6;6Zs4Ppa`oaWIlzEs^Bc(Uoh>1*g%c~EKaxP2460p?vG$gPe@`ksq&_liV#>xXS zGx<b~-*+<lAnwf7XtB9%S=<c0kl@~~ygE<p?k_N&4}*Cz-f)N|<H!qq#emP~<WXT! zvSS9(7+9i=Uc8vMd*+=(wuMl%P=kts74p+Lv^jaegY8BFQgVy_$9OL7#{2g+GW%b8 ztUaxNH?Rfm{r@w_!T;S90jsRhz49C|kNxq)^$!V=8V=jp*V~)KwA=Ob=lf-sM0P9N z!^OK;K|w(v9u+27l2cXve%syyCWfy>iZq&!I|mY4p#p+~Yk|AqQHhsY%`ga0SsuwR zLj^PTJ3C-g(nzHT!IIHPrn=`71+)Ur*sMWzMMXuuUApJ!=gsllF+ob8<}+%>KA!Y~ zLq9z|{eui#U+E`*iviF8S}!mR-jA~b<9R&%&3o3vC<ToWKfj5k5(orxs--n6g68G3 z^qGWYGzld+)EqK>3~o_WG_;+!oo`CkV<k!8UfTlSy|V)r&GlZnmHg>X?G8#xO0#C5 zwMiB2T@9-{tfXUXyq77W5GhQchxdi{GFqkDR0pbESWrw11Q6|E-t&%9eEcZoq{qe8 zqnDo6u2$6l=%C!Kh_o4(9sjg)<L-8>EBQNvO|Ox-xHEqU#^%=652^D1ZA^fLh2<k% z9Q$hHuO|;6mKBI%6WJYPDPndD?)JA2LAqR%LwObu_M`PD&*f-ArGDBF1W^x8u%;BM zH6>q<xy=rDVrvafqpwcUt4tSOX{mNErGhRw=KHsFK#U42BmR>$DlDwj=F}Tke~8I; zk9VQ2vf6CvsuwKd@n4>r&DR<+hMP=Z<|`DxfQELt?(w0CgGcW1{7=gNEu^<Q#m5^# zDn^sHQE_2R`Uef0Fh~%{`xLb%vj?vI*($Ef*o1@tPDIk{t%xC3HrC*VYvyzA`APy2 z7e4YzlPSI3$$d((_Z;hI3e=~=sckv?gNe)=>+7jFfLS=|kF#1Yc$`%o47I&X@(&0w z|HuI*AiQ`jat;48pkU+IuP1AK|DQm?RiPF>zu9bsZg*%4xGPH8oG$L1HA9Mv55w>U z9xm>E>TQiX09tZE2E@^_Bz(q@b%iA|bvj&H9&SX6*oX3D4Fpk2<%X{<?j2Sx*H6dt zr*7#1egVRNoX_VS+O0m`T#&py0l^}TcjxfWCAyP8BC0g)F;d$)tPU8!mSi>GO^)jJ zVKEv)*3px-H}0W6b_L^3Atk{VmDW{H0kA{mZu6B#6b3qah>c$*WU&50<*e(KiVD_V zYnd)-$<uCbXO7*jw$zVcfQ`}>vOAJb$z4Y%hUxkrEJJjO`A9er3;=OIiR)uRt2Hi; z_)&&DdeD2O_hBemApdYIPp%KEn{uHk=s_h`g}1By!-G`5JQW_%Th2%7U>BaruQSL= z>gUn%vACe%FJ5Ww@cjJzFXeSH`i}f{gDRl}n2hHyc*SE)N7Al{a9uwS9u6-vfv<l# zRv%6i58fJ_7X$|OuM&ylxxK}4LBS#f4qC`eQ3VvlJtHko!9g^#vW16>cw<W>vYY7Y z`i0R1x-LtYnVESS!6t$AhQUlpsW4vTP@Rp%W=}ImyH{0*iJ5guy&w~0#^Pysb-#3- zEY>i)I*E$CywUuYyx91fNvn<@VJR3pd9KPC#+}Hx|38QZuIxWb{mwg9D%00^SQaZ_ zGM-?I4MYaoch^B)US7ZuQ8@FBly7BaWmZXMW@d}m^xVwS9GPE6O3K>H)RA<7{<xdd zx-+cJ0gW2FrF+C7w(L{1cE#Y}i*QBXXk|JxLUH^oWFp|gclinB``v)u87AHRPQKZ} zVxvl#)|IdY`^qPaXG-s*l<&Z>|6sb-Xcl4z133(cqoyvM#>x2J?rN{|;Nnd65Y-c* z*Ko=(s<xlBJ6<SosNr&_<{HwgtiuHK?(HuF;b&)O{l@^|kT)ujLM8vr%q*LDZ+$!N z=TCRPS}VPay&31_w2m_@2JA2PTOc6h4<q&*XZC{C&wwbF!!@iv;U<29)MCFY`EN?0 zG6E#BVnnI#<;v(c<T>#P2;fsGH`^juk~6;ujd^1w%e}2L4xE5de2QM@ZbkA=yTQWi zIA}+Io2$a^hTb;*E^7_X&BjZzyvzuV^q$IG(>3)|MtOvAhMB0d8d*ee5M@y3QBjKr z^l#iO<V7*p%>}7+{#fF-fM(XVe4x%xOeF6-qjT--BC?O>cM+8Q7~95CseISsgF6(* zQVc*1q_W3?K(n>1p^E%nb670!CmOl>8;6S`N#?gv$;GU%PZ+Zf7lUS-ob?G}Yyq(X zh8c`TlNDgaw5(O#Ot%_tc3lFOgrAQOE>q*sGf;{N%lqMGs=)7|tD|d3qeie9{)Fe9 zetQZ2<h!?TV`E}`;(!UXxVX?u1U9lrmxhD#p=Q;(f;Hka01^B`^iNJTny*Rq@~V}^ z%k9U!gSrK>B3jz==c@=<%xm*kr*;SPEsz<jO}oA6nMxz{zyo@NS?Tw3ypev??4acU zqxwhG2RUlix-G2E3dW%=GHZ4Nl+AxI2Sw{vF7fndK?X@UIMQ*(x0j_cq!(x6Cd$=7 zxD%8v)ALL9pP_^JXWhkt&K9B<NsWyS4WUcd_jAR4%8|($K?Y`xBmY_dpDUB4<pC`< zGGgUQ;ZXNJY%EhGX7ORkX|=PdMDu>$FM^QKc=`h&GxT=Ol!g=EXXm8t)esJ&@eIB~ z<rcsMf@Dc{Y56E6{4$wzfsnn4dR*?J8IHj>fo?X9H-nI{bPa1u%R1+q!PXZX0U@Oi zrIr|P#AUJ?l*XF%ETvBhl$O|k|0${;{$F$fyBwekVjqT+TsOr%n_UNlDK_V?sCc1Z z&JQP_6X<kF7%vs=2T%r%5c_cwv43ot>dJ1_&C1Bg$kzA8bsh6rx7#0exGYJHM|j6# zx^h)c)FG#egoN}8o{pAw%tb_AezHR(26=4y?)1Af!Ib^(q{(wH-NyXyf_ACiP|u($ z1YUZL9@@4lf@^bD**v_=CI7f{oCP#1uFw&r<O9ymc<mgPO!oLIL}3w$X3O<ivt~-Q z26LBsTN6)#)d0%oChMzSaDY{16%8oJwI(;gc$JR(8u^dUU>XsJy*t>gfT*R1-l%+F z8V=Z7%0LVPm+W8oX|ia>iw)~Ll}6wh8t3DChnxTz<vs3u_E-u3m*9ibQ|vs**e>Iq zAHxxgDTabA`Sq@}zwl*oZ(}LAJj1+VFV=XIRBtwSm`>$)Wv5)5(jNbXWXQ&tEo>44 zuAs?cetvdZYZ{;ug1h6-bB!*R#N2bG#f{lxrE+&3Po%5oQerN*%=A5*`EU6oQNn8L zSKp>egX_5^3A_s7go>4TYA}*wQ!BpB*Q=m7y_L&WhgZXh4^O4LFk2|q`B5nvXRm#@ zEOI=<#Be5nSa7IVruVNf1EuhU8Jk7CU)1}Pi5aZ9`T?8umx2)#`}0o3Qp8cj1<oJ~ zc2hsdZj;yN-%<wMQ;Lq0hts`7BS-hSG^UAc=IqS))ttmO#`BqKDEeNZD0a+{uZrK3 zg!K+4QgplODD>Pzli%WCVxmQnMk!BUF?^e?vu=c5`;>&ph8C^*K~AyelF?9OYCt+m z_$7zU@9(Nv!jjYWRi;zjQ~X)Nb#=6B(#D2W1@gt{v$c^*XV4_V4vf|c-?9>QO@$3@ zcoU}n?ga$Tju!JJ%d1D{3<n6<{uGxb?KdGCkMqCwaJoDeX@3+r(c^m%RVwS^&g%>Q zsK?vAt!gB~YlQhgBCSYF)7BcU48a|}S1(E9ZfSVW7odgT;MuKX6yn+8Se;vBZm{U2 zdDq>RFCjv2WLGd(r}ll)Av+if(~w5OQUvbf!47%Mfm)}NvTr$H5tcR<ZZ2nX(?SZ_ z9qC8v<LW~#&v<K;R-0ChdQc<|m1E>jSg4q&wTQwSN*$`o!eRG*@d*@m7)oU&aiDAt zS4}-(G!TdEvk2P=SzB(b5%8sJ=`_BLtF|>|LEV@wtaa|p#E*$=QB%*+CCc!|{bI#3 zQr=YWHXnL&aHSLT_RI(2qEr^&zs?bVpf-5rd?ernf+GT?T2@!}<&6DW6;H?$6@A%6 z*S)ZPr*Uovc-cr<!na@7W^MMS7S$Y#cB}drX%=?6@j_I|a>ks@QEv85=c;g}POs>} z-I}Ml_Ci5xT^kwO7V_I6H#8zDTRtyrHB2b%b=gVbZeij^nDD^D?R#?S^|g)9s^a}p zatgAxYBXN5%b4@OCRQF4j1E7uxEc(ZaAk@1NHItAvg8$f$@EIduN4igwXb3FM2}pH zNJG)VPoFA$)utlLH1m#4_La9gQEqL3&En$z97^Ne4&4!wWff;nd&aXa=u9l*<rO2V zbAIWh6v2?*vZIR%5+!#Y&M69A<02ADYMeuxQeLJwkq8O`os_FEi_+t;QmjeuXteH7 zCEd?2=3p=*BW4|IY9q;7o-q-TiA5!Zf3*5$8uF^-gj-JFF+E%MMIc;~?0+9@z^CwI ziF+rVqExt-yyE_0Fp~Ls1@7d?K!JOQ3e3g3JsfoB&GUWQ`XcqbF<s6DSF>9ldr_4< z^P(jyP3IV&XvFa7`>_t=M+_L1_F&BRzYq@He-RGsmQ)6Q81980x=IRH;ZFqPR3sOb z<s9Oa3`G=3X}RL;Stxkan71-ZY^B!t31U9|lul2l72fDEX2bSc^KB28C?wXQOky?J zT6M{+53{6a6*50J7zX2k4GN~?ZQ;1ufO1y+tgjwk^N}pIXzGI-?p}#8HV2894dG&f z2utORWRt&7j?@(#_`eGGI7RtoU*NDNXN1qx&*Y^YW<|+LimzpQC<tqiCo5C=_qUEn zM`0%9a^JP{WswGbX8|>P0e6)K{og<kj7R0QhVVf>G?XUSyNXS{X^y9p2d}`&Hk^nq z6InZxTRUo#-%75w3)y=8`?Jg!`#EByy}Prj+Sb`}oe;f=v#zSI|4j-)uusvE&QN3Z za>OJ7>8l>8iJ|qrdgqroS&9Jm2AYar{b_424+#s|$X|HruIh0Kv@sNN_|^2Mas@CC z=3sO&7w%>x!Kyi{$EC|&RvB(;+dKI0ASh2VIogh0%P`fti<$Q&4bsH@UMO-9{<d{) zRO^7@t`;$Pua{SlpPEXfZ5hRc5!dRbJ7Vec``j5b8qub=K=o&4ww-BUS!w=Qs@lNX zsw1i#k82?f%;989m{XM*YjKHHb+vp>Z{IDrjw5X+Zy%`4U8LI+RRvtlc7GmusI;kF zTO(CXAiR*nsHRBv>%UfT7u7=_|B_R;eivw$D{Y3&gnMxaiI`^tBdO}H6I7_)$nGss zBMA+dW$~>d6f_fPMvJx2APisx|19!>s)Pi8k8|rO7e&r`i(33F<}_+tp~hXXOKTgR z)sfM|YxIkh4DOA6HkJ^$S6l>EyVFC_VSnymd;dR*P+qw`;-NobNpehoM5F&ZJtT>r zK;_fQZKIW%mm(=AEBk4f<I@|zd09Q>>!Hzk(ZBVYT(3z8vh_Z&b4F_F8U(-0l_eSG z7&oMU)*D_@mO@3uxYV;Kk4KH1hxUhcAmVE(dlD8A;ZYdJO%eJLmSEs`NYw2yM#-2v zJi<c_RpC#YERE<HUUtErssy7xh*9bnUEbaZj|^9*QS&;E;C<u<yTslXTG>{hbPMKG ztVKf7R<u*|{`grq-nNf0yB!3idzc6tdjBnJ)dQIZK&i^U`A^YFf6H&nTe+iTTS-r# zxL%;W&GRH_;Q=q8kl2s*+#5nEFh5?A73BT)^8tImEoz=#-hWO^x)XSdih7(th5MSM zq_@dG@voSxe+9gZ(31WO0HgmW&fCYU;s}lUF93{XW5*|t8rUr*tA7h%usvg9Vsg6J zAL{Slo2&%zI7R%`$OtvCGOrM+lLu+{-o;06wI7>|Ly^zqj!6Sni}*<UNX)6FuSRdD z{~|9OYw++7gI%<YH93Fy_}u*98e%k>{dyi!-X3$WTItv|s0K2l<6E5_FY;D?6Ejd~ z0r%pL4sKvRHCtsG%#=T6QdM5Lzqrn%gLe9)WvmKCh}6zYKZ^)%hZVH!wt7M(x1w__ zNt^p8zO6^%hFG6UpyE6g5fMR0N5{p*B_$<YZqCTb*@{xgh8#?sCT@=%ZQeXMT}(`6 z-Palp_%8Dt>+|z(cpk6v2fe3YWd}Xnv+bEm3y-?7rHA(|GT*sJGfAg79?a`BGXPb< zfGc);H8d<+Y2`hupkz!4NL#k2{v!9J47t3*+mf=CL!FZ@Z+o)m=jXvLyv+xx+F)#h z1C>Lq(Q*I!Y!_?tf#BZ2(2&`74{nvHfzG;HGgme~DoR(!gq&3#Xi3$R4$#mx2E~H` zBGO!}NUPVbiGq@j)#B{3^*e-(@io)O3jH;3y(J=r)!}3wDGHpPVh2S<MSCZw`r2A> zYr#GcfDf(r+2zAindhH@P#9=PHJNEi^HWNWIxJ8;jHb-yn#MqI=_|P++rnSzT@v_n zUkwZ_c8p^a3&l7GFx`(2XzhD@1qUVP9xJCrAzWC<QT8xkCs5wJ@q7pe40CPGmxrTO ziIrrK9b?u^URheokAvu{r>p0DH&C4}5cI|2_DBHt)~s*RMC1EarDWx7wZZb?rqkJV zkW?Eqa58T+J1nX{_kPdhB24uL_Z<;l+Qa9}JjE2BuF+A;!983;@%Zl>{WE|`Nn*Fs zyRKjiN&Z6YvSGRtITd<nFkge5Rd2n$c5pBW+5s_y;+zcxvZ+}?yQ@n;iOpPL)Cl|! zf$zFP(Sl^|xNkm5bLdS!tI{0vjPMwE@kq;-552+f|L|c!x=@*ZnIp?)SDvNH41?KP zu+nf)#8qYG@Gv<k=|HWKS>14|DCixN9|#)v3YXaAdnHHlk$QV&-AIk4GC)G`{rUH1 zWFBZuvY{M;dHo~0vixQbx*k5XY^t8e=*y&cQT>E*v9NBYA)oAf2L|{=U!$XMuCC(W zcFi|AclC{dAYLs&;+eU*;;Y@_!9*57ir{-XK6r$HmuGqceEh?ehx@1Z+)<<s;@>Yd zg@|>xWt0)mtN6*6+2_QX<td~MZbpkqYTAkc;gCioAnK-{H=Eh2z3(h7kyt~)`fNo3 z^>&KgkSLNJ=N|AW^|sr$CmDXQv4e?73C)_vpy}Z?>a!K{p3QOlWF5S&Le7qR6iAl9 zXM2BlJv)PmUddYXKOrvu@>X-|2nqxbVy<Kg$-$Mw+S#<bW$*KvK0B8!@)$ParEm;D z_8F@NfM!5e<DK|cYFkm!#A_<&tE=oF;6bBNXSF%VLVItw1Br9A+2!S3+@GxM+e~&g z);p)-D0ju3@I|O9p^E7V>?Y76|Hpzwo|ST_5a#g0Ti~dFjc{)90?|4KP9jjB(EiOw zJRu>W^E3LR{pEK9qJL6;1Pq1kr}MHfOVRFY=)m)8<j%Slvw118WB8lYhS0jInWpQ( z&;Mr<+dFjHcT8>x2`YDvXE=OovQYq30c$lpP1Gw~)<f3J>eZ;v>u0gy#U}6&$?+5E z=~!ALP9*=wb(yXFZ%Sip`QJ=k*ck;L7k-dYTB%I_pJ<GTf6f5<yK>OV$S8gE$cFKF zMW_3?#zJu2@|)^%1XEyA<k6{5AHSoaWne0wBfYsv`l61~;Yv74*+lD}%9XhI{U5vm zhl9vzZmj~|?LfrR&>K|6zYCVj8$Ul#4yA?bIQfNzg{&+pKq5DC-mAZgsQbT(|B<^E z8M+M@1y2ysi~n~1Pd?4&r#~eE@;ody_6y7G`r0}^d-q@uPl{wa(uzTt;3wG6$nqp> zS?5)gt*d`RezyE{3`_}Q;UHiC{N{gg6!`BYsZt$O@2Bak@CUi7-7=mfhD;VLr9D(; zyP8ZhyB^alH)$H&Jg}3^#}J#jz5~Llm&PjE(q%^_252`6A*T{a?AdG<u4#Xz@Wh2T zQ>cJWJ$tI~H?s-IMRN^`g#y)RO^@07+M0Y;#(5o>*NG>-M8N?rNcf9)Tcpb)!=@Gg zz%%Y>qKqS^2QS#KmF=list%Q|yEFjY$VS5t_GGH2bthA`mlxN4s}!nrb+)SviO+y+ zW2Ra`VY%ru+^gt^T5)@-Lvg2p!O5yt?OcQHT?P{gAt4l!?C^lX29PHR*bl&ZYDb<W zR4HVAl{1YxuWL11m_dI-!s<mb_6^r@^&{BPY~B0p8%`c=kEQor53qP6?$ql)v=9dE zfDQ!XuV!zLL^V_Oq--A*3yb3=pI|V@Y#AMWMnDa7=<n~hfNS}M{o}|~_BHT#t8nc{ za)8ZH95+1E2hkb87Mv34;<EjdOdQ$T?=VL71Q2lNk*NmPY+#_}rci3z@WSqN&Te1e z-S~DbL;SkuQUkVRIlsCK`{LH_YNNrfxQa>w*PWxh)z3xQh`)OQ7HGm&P~GMrstJ!} zw8RCQmey+{sJjfvg{r?z!j1ti=U1<Cwzo7x8mB8S4sq02d;<zglx+`Q=3>7uG1x8Q zj>-eUYLB6dglLu^xdnK;018iQ_3rMwLXo=bNxuU~GICix53E)nQRfE!cpzSn(TuM~ z-im)=ajsQcYv0?X8XwQOp^@&)yL+`gx4ehg;GW(Y2C^L-x7kXel|ZS1Fx1`O?!;&| z7gW;II?qZ#UdS^i&%J#}j3@TS_V|^a?ZGeu)h`LBiEEXp#E1Zo@bLJ_GKYw&!g#rw z=Th9-Z+22sN=lp)(1I|>JKjeL+w8StG{DiS(3y<q@uBS7EDr%z9dz<mh9%y!j1Ek! zLu%oO#FIL>jAwIPZmP&jpAQrf5M(Q=sA#!%*gR&*$(#R3EDX}yhfa8<xes<Spq>B@ zW}s~V)e0bwc6&_br<2$fK|pFTJ*{{+-PkPU;h5vl;E(zdb-YYzwU<%ZVk1l^J2>f! ziJ3mjS4j;lBT})1c3!Xvs!DW{N?x2`gMsX)hQ?gc{$?iSlQUkbb(MTbdLz_>Fa##l zsIOkwiZz4o*_IS7^JxY`DcB}s6TZf{E!Bf6GJ%DA<R|jq>K)8uS)Si^#1I7<EM_c+ za8R}&I9dwtfWWOH8B+6GxVA(7jsoR+B`1U6;B!HxWkco?jiD#an57oSH;A4q%nL<g zaL;j*zth9Th-TEs(;HA(oj>zrufbXMN8LJPG?@RaDndh3-oE~O#d8|=V|OQcJ<v&A zU9TMn?M&UB`&`*?+qN$(#T0LkrtSlaQuAfr5AMIj%b&)om+q*)((1@Nt0B=@0WOBX z()}BnidNzW=Q6|ntWB763{dc2h(zOKw)NBRR%!k)>-TK|uC;BN8miy9fo|4fJs<UL zN^)jG^Vhic_OCmntEFsku1XYxApUP<d6{`V>NtDIJGIJdloSF|pPVkXZf7&l+sx)$ zNjyg{pR{Ftp%}nq<WzK6fz+Z4AUG7M<*%*D^7?-+*$b)cMhCK=I*T?(EA)Hs{F?K; zv+7q;9~RmFlK1=j1r(dV#Pb~If&L$*oq0HvZP>=CWE*>!?8dHS%^ojV$28VKG4_26 zNn|T~S+a&+OV$j+lr_7UOm-8p79mSQc459-@B8<69N+u>IddHI9M8-=&vV`Pb^Xrs z++CT@@9(rW<*{tf20C0d=zeGE_ZZrraUKG7#zAN`($H8#%WO`c<@FyPiT`r`wf}Pd zwyArSwXPGFUZ0zbHDJT@hPb$I6ICIu)fk)5hgyQPq%di^2jdf}#Be#gCAqhu1A~Kk z%C?YmIcN09KCVlEr~T;Fz%v-FblI>SvTJ5}`LldQ%gdME-Kv*Guv_hBUj|(#8#+M3 zpp3C_Xm*piaKtH`p$zs?`&f*{yxylN9n6}Zf)b<Mzx<WbjMMV{=EkeTHjn9d)ca%e z!C`G|%UwAfoH7FYKj}1EKYScH*GO)O1M<}eKU9W5G|@t7b`FOSAk?#Xx7Y+b7kTA- ztmzTn{q5Ivg<D?d9eupe%(;I=C_$*R-ONw=_F{c;<?$6sm~>HEQVqyZ=a6k^^9P&F zDw9O06bbty2P34Hmy@Z#i3!5M=2k^__XH-85Dmy}!nJ2vAd9u(KvP3&bQ6=9ec35j zF{o9oWinh+vF>ifG^H=Q4h64SWSsE4&JXducV6pX0Yk|rK5slj=$NH-htO7FPOKn& zFviYZD5cPXI?z3LAL>NpFC{g&jTPk|a4@ctQYsW7=<Vkw0~e2Iutf;b5Zi_A>%lFC zLF;$w+u_NS_wK!p=BMhUs9?jM8{sWY6--!*;Zn$N@jrRJ`nk0>uS(9JoH{-}z7kv+ z3npDTp3~Kp&{f_SUD)cnH|n)DAoGHffBk-bHGs_hFT`;DZgBjN3zq0Gxrk+|j<L!X zUd5*91CgCgpFV}q)vMrs%$NIY5;^jc%7<UJ30U^J+?U_^hhyhf@Z(`b_Gkj5PztK4 zTDL^U0*P5)5Dm6474KOC;{7tkHMo|M3vIbjJzY(TjHqB}9Zd|FnyFugR9<?(pyM(( zy0ZhBe#&#h)Kv4VWpSVQ-oG~Dd~#CzuKqD${Da<aR8f?~>SOo1gYQEl&?|znDhdLc z+mJUIuawTQP48sXQUO8SG$D@AFg<X4)56OOjD9?WgJC$4loTW7nVBv#Lj(u+aCC2V zRCmjlBHSjoFC_GOu<7fmc#ew&r16*MIx*YN0o%soq&`p1S_b0292}kVZiKmlV2E(Z z>>SQ+%0`R`qYZY8a><FRzagc`qPC|r^UZ8r5!pEdjLB11$WXK5il$HNSx&~e+boh3 z5nEONg4=5{u#1r{cBGc@Zc0cg@00LI<2w(vg6&`_;X0i83l$1+GUep};TC2Ug=be| zu|^nFx@Gv3s>K?5X6<9GcfKD5M1j$Ra+Q>vGha*LO2U(bo0f@v6D{bv+Odh+?~`>$ zAcPQ?$n|h@XbUj<tIg;(3{SI`G(n>P(BM7>^!jt=F0)Z=IOy&Afk9r4CjXO?PQ>Ho z3(57^1k>L-m{Cn)C_eCD`$VEIrkX3J5ac`ADGnLXK+Q#9o%LUSL&%RdvBo-|(v1zl z+EWK4QqBRK%!WH+`~E2~j5nm4cKD{h;G1Os*BR<8&2JJ3uhPqI7sidGhb6E}SD@FH z06|fBUwx%;4Xk5cbW)7_&3eIx`!(mpVoN11MP-1!TU1&+^06SzT9xHnHPK|h^-rgJ z>ph?l0yUT$tQwwjtVCXt)C+*;BnA2h<Z93MBvNTjSgG7koBbBwL7kU3dI9bXOV|QI z39;6OkV4n_;9JGK2(<!x5cy_kFaC@@p_z7%GoNl2rXpv2S@EzLevOp3P@e0KfdLQh zGDul0XXe-hLLDAdM2(}VslUQqppWOi;gNJoFnNK#c_}=t4}?1~r1CNpqj5IIr2Nli z9Mj0668H9E<CAGd`?@k;93UP5(TU_=(H#6ns>MwnmW88(kKES&P{ln^g(4u7LT?h} zCiQ1d!f4X4M%G_eq4k<xKh`ng)Q)DCz|zo&Zl}*!!J87pd?{cl7~jKsu@jj4(_X8G z`YQU**FYC}PPPGOy4p-V?qn(JjUr?{<7dK|N<>EX+L|Cd986@KKr{z6pVWMWJe0kY z4Ac2qk=37)6>WK2HNe>|BXNC)`oh7uj_8SwLgfh!`=^-}@e73>oe^rkN?ydJ%0G;v zU+uvfL%X_aQd7_4to^9$j|IfV>G-@dal(){){bJbk_w9;u(7-EOMc-++<?T(v3HuO zc%~0$8Op^s^#mv(LfSzdf2};f6msKU<!SwS=(K3U$E&2sY>~r@F$G{@Ei_<b$y{g? z>-zA)Mtl!tAWwY#YE|#VFz-p8L5c4Bhhf}`qR6V-ZH@pZKPvxg)e)E`K-&mecdIcJ z#cJu9Jss^Xeh7~i#SWUaQMGXL1SaX>r}IoHZe$ss7*i5o4Mazwo8#4Vj|0CXm~y}P z!usVjQr5=HE80!%rKKt4&KMl%<my89LnFW0!QLJ}?R-u4lSz~qXao%YinI>|vh20# z4!;sMB)XEavws1Va>IKZ86VjHzaMPX<{}Ggm48@z+C<OTvcDy_>qahDYNjX6v_D31 zX_mNS(M<h~6L6m&@%Zk{-hX}2BcytGU2%RN890`o*(QR@%z%Kav^hCDE4dyEuj?!G zE|r_rKQFwAe}4tkXkX*N+vl%n1qQ7yY&eU{`z>f-dE%jpBz(D<w}s@rPjKr!cw6L4 zV#@;QwZqtTmETL+8k&qu_`j?4uexX1N7HH5QTjmq+wR5GW$d<EliYvfIo@hf&u2Il z6;%fG(|oCt0Ez#8?LdrwN4OH?0bFNPrFwNMs2oyR-zo4iB{kJp_0ZQ;-A*d8p~2mS zWSd32TV61H964Cq$Q7#Rj27Td>gx^LFRV&p;E<j_1SxaG<?RgySD<PJ2K`B=PBor0 z9CMxbin)0|If3;<acugy=VYQQ<Z}YIG{+qEX$!DQrMt(%ORq-djI*dRw@8mahK;;l zn*TAsAS??hWb>R+R8yZ=9ivre54eXDf@byi^l|KWdKanFJiqE*3|+C<`(O>d#!9@} zRzNRqml1K!{VAROSu@@4A75t80GTv0vSCS|Su3tsN*QTtDk`5DW>p$5gM}FvXJ>5( z5x=GHOG_fe%NIx59nYI-tdo!SZXMRYO(qU?-Gu6?mr*9i7zh|JbN#HGe6RR9Km%IJ zorBH&k!`7wtukxHe2odutp7mnBp(J*zZLqeML}AXwVXlsW&P~Q4$vY!8RY_CEE_@j zd{JS=>k-paMmRM;%w(k1gU>iUGp#5Pf(%1{*12FbN^}*|f%8h*8{_DOW@~NmZ}eyL zoHkJrx5y|ZWW*rc?$6${O^b%?&$#TSD~Ge>#db2wPEwhPivC$|&z*VO)N~M1ofcPj zpXiD}GbBYg5z4_k3%@rI7>BRBpE}I-L6Q@+x_1B%q|@v^_z%RO@?ZK&H?Y7H0PGy? z9lX1?&%coK6b3C#R6fyilRqu=q+?wv8AK@ecwZp<bScj{OprJE-nM^N0w|19A}Qw3 z_YW_^gz|S9u|R`w=S>sg1Gcq>qetTZOb7O9ItYBhHrb#R1}vrj_yztS(|i9vCJq07 z*2Z!ZcuSpqD~1~u&C_U6>(3xIxl|K0Z5VC@$$NmN%zx}J{3qM(f9EC=*8)Bch~KHc zg37Lw&5$j#9jlIR#F*57E=j%Z|9s@Tn+3&wxq(=46Yt7&&T(!+1@1u|>(B9L7RERb z>HIb+4aFmis@?S)E2`XYqf&DZ6W10IpFz=jdh&s9IxG#hGg;wq+{#|Z+&<I<3G>E- z=D9=LaXsfySR{56x;RsGZjRJLC9ClSG1h?G<6ON%N%!?TC+4!ksxMVn2_|$Z&lLIi zP|4UD%^{Sg_qNTfAdNlI`OF@E=f}G|+op^r#RjFcW*>Fu-$!?66d7{I>&9C62|1DK zL049k&S%&3zH%(*W2BC_!R+MA)Q?D$NzV#UWSe~ymwXsuF}dgFfeJmeblggick~pO zo@je(E%%MONKmkK6cHs=`iXeY#)5=|+(TDG&7^bGr8s7G@;*zfjW7%&p`aIX;O2$C zD?K#=8LQ0<PrI5P6M?CJi_u-7UHMU^Wol&@;6XYz@AhHN5bPtIyUwFOF$kd^NNIZb zC@XKoh~alb`s(uVxvF^2L+ceQWXat<AB`-LHr!ps<cXp2tD=qG_$yoqCw-M4SeoAm zj}4-%N<{|@S^9(UGZRbJ*g-JoNJI~!dJu_LgC~In7EV^l9lySK=*-@~)`WU_xV3q} zs`z=1+ey%=RQnW)dXMsQzlJJ%8uv7ASB~A{_rR}%x{l{hE{kGJS8s(qX4iLsd3?l+ zcW!?9{vPcic8U8mD`3yxD()|8$e`_M-rc~-OugBo8&+@I*tY#kDiza)Yafr+LIvDb z{vICv1G62?gl$F!kL1NjF-n<uMu;V?G%}bCRYxBVSA}ei{0jSce4qcGwYh(fvkFBB zt<^wI>($eCXO+9BEOOOR{pB|}3~ahP;<vW#>YB~aLHKQJUjnT*ZZPhXcpFiD;K)8J zNM%opB*xD$LmyVA^tXShy}~`?H+Qce7G%sA27HO)I8l?)FpkZ}`PXnyVfjBF1$*LC zQJE4A?fc|PQx<S=aei-Eh?dgLTJ2frq}edlwuw;%KTX17n>ky}iq4?ek(d21{KiSy z1U&9(lxy3E4<%(?ew=5w=;+VyzO%tN&*LwaUL)<}KlaC!vptIBzD31z>{^6y-iLFw zK97Tvol%?@EP^FF1+H6!NE#_%%FjzFX0F%>+<2hG?E_V3iC7aYKR%_Nc+BM+dEE~C z!s}OvtpY`EV$^roJcF~_MW$K-r!vWN@(qhE&hN0ODWo%{Ku78v8ITfRu39u!E-*G3 zw@-ua_FfTAL|&6=m?-6l!r<c<w{BWY`Byj}ev>!*<IqF7&!n7lP!}D_So|Uf(f7ec zPshx*9hr?Ixn0f^R~-xV4lug@fQd9K+SLN7ab^@-&T_^xB+BtStF51Y_U%{iVD0F~ zPZkihIg2gwkSV_LsiLl(lzhc2Z-e6A%C?y`RFJv#iVJgHS2{Y*3D!tBaJGX9Q^(PG z$(pvT@#Phhk0hxZGc(I=N#`kb^y6{fk95FYtDhVro5U|EIh?oRCKRV{_Jk0t?4R53 zW<=m16i!Y(c@}C<ziz6oreGL#(^U)JrmRKS9N9VD&;5jZnHh0kS641*Vy38*g;c;D zZ^*J1#z;>_AJkofQHFn0<;Qj%I*JWx{38CYU2#}ScX3?KXtnzxZ?73{P{%fkP-Xua z9tQ1Xmz4(n7gy<z0hMPZAs2=VK|RJwDAt|2XgL_^?kztX+7Wy8ra2qIevm0f*SNn< zQcmmGXKrOhVPtxE+F!x&wAdj%Qsr`^CSO>*N{BQa;pWumO8HDH6E>;-$?S@}K=rSq znB2vx-*A>pYx9c3-0(Ln&>xtF)PN0l)+A@&n&*mB&oz+Rm5W~DoEy^1JFkzQZ_MII zxJ%Zr@<SVH43sC!1i>?-Y|Dk)*2|*T&Qj=iWu8`md?svBIw%-#KOQI8w0|V^%RIme z8ESaT?69ipVOkq~#G=xt+F)#9%YnIE^y)18!n9z+0_CfWcc1fGa>lm`DK6ZySDLtd zocJh9yn*)U=T8iKAb2kKTnu?5h|MOGEqApt;rBa~VH_SkK<+6GI@J@uCe}7~O-=au zK8RVvMz;-=J;|Gh8Ek@_{;X`Yv~#?ctQ)Bx-T22@d`G&GJ@xD2sY}&b<3~Hl?C8+Z zSh0Go_Z6h8v%u>GR-SZ}isVhs3{&&*Da5ah3&tkC`8maxc##Ud%`C5X9+>G6(M1(x zR`D9PjajbvX?IDoJ<}1ly7Y&SRz}dpWu;KO^q)&R)DZgw#qb9JxWP`Zy!Ces_#6MD zh0_0C*@2%E6PS{m6>Y;tdMRG-6di$-aP{;vXjx-Xy@x+NlV_X%l2pJM1zSd;F6fZ! zK#`jn_~&KPo0prj)j9A#MvJkf=iF-VMEB?lrc$c=xIHZSa|lPBTZ3mufjvyoK{!ek z<^M`2JM%SWSW(L?GGXCy5Pgy@;THpiyTSNhm7I-1HHw5p1kj=kaF}3fivCnq8h;+* z)}oZFi3e=^%q>fUjUu7o8zXax(FHxbG0XxxPBMxJX3*b=AXtW~ae8*(%#av%bXV`z zps29$U*X_{p6Dytmgt)LS04Bp8YaI>gQNKq7xA|o0ZMSpO*lKB;kUGp4b<|>stuxu z_G}n|EEAZRfEF@*@9xwLbqTx_B>*qLOat31BRiurd~|ujR7%v0Q80@KBE@il5XOjn z(W5(bXlvucPe;^NXeO6T?J6=Cl{~YUj6G$CGwD*~|LjK0=S`BG(vgr5iOM^A3?w8Z d7tiYMc@k46_-#m7CmOs%qN|D2s8qKJ{~rNfiU$Ay literal 0 HcmV?d00001 diff --git a/docs/img/ux13/settings-time-windows.png b/docs/img/ux13/settings-time-windows.png new file mode 100644 index 0000000000000000000000000000000000000000..1614338c1af9a0677ce8bb813db88a2b06e08ac9 GIT binary patch literal 219089 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%0DC=spb>2(C|!3?*(dvLDF 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 XenLzmq4y*3KMy_#Nbr~NYI^-2^BwLF literal 0 HcmV?d00001 diff --git a/docs/img/ux13/setup-step-1-nl.png b/docs/img/ux13/setup-step-1-nl.png new file mode 100644 index 0000000000000000000000000000000000000000..4727b1b846e55226a227bdc3f5c87be7248590fd GIT binary patch literal 138566 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 etjT-il^^Eff7y9*=9 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 LiWj|p^WlF0jcPYP literal 0 HcmV?d00001 diff --git a/docs/img/ux13/setup-step-1.png b/docs/img/ux13/setup-step-1.png new file mode 100644 index 0000000000000000000000000000000000000000..a51f31b4d33425826193703ef854495ce332742b GIT binary patch literal 141516 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�dLu7;V3b9jgr30-oLveNsQB0|2A;n64D^jT#} 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 SY<KsQd(z_X#7aaAKm8AAd*(C% literal 0 HcmV?d00001 diff --git a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md index 310e5b6..e5d16b3 100644 --- a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md +++ b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md @@ -70,6 +70,23 @@ What UX-02 made authoritative stays authoritative: Its tables (`KETTLE`, `SHADOW`) are in `uilayout.py`, and its live checks are rules, so they are in `validate.py` (`setup_checks`). settings.js still names no key. See [[UX-13-setup-wizard]]. +- P5: the page words are in `app/ui_text/en.json` and `nl.json`, one key set, + loaded by `app/uitext.py` with an English fallback per key. The page picks + Dutch when the browser's language is `nl`, as the classic page does. Home's + sentences moved from `homeview.py` into `home_words`, so `/status?lang=nl` + builds them in Dutch. Status rows, banners, hints and validator sentences + (`messages.py`, `validate.py`) stay English: they are shared with + notifications, the log and the start refusal. `test_ui_text.py` checks both + files against STYLE.md and each other, using the rules in + `tools/style_rules.py`, which it shares with test_messages.py. +- P5: "Other time windows" is a list editor (`ui.periods`, control + `period_list`). `uimodel._periods_json()` builds `static_profile` and names + the first bad time, empty price, overlap or gap. Its tiling rule matches + `static_tariff._check_tiling`. A stored profile whose days the editor has no + choice for (for example "mon,wed") is still kept as stored and edited in the + Configuration tab. Supervisor 2026.08.0's `AppOptions` accepted all 133 + wizard blobs, 17 of them with time windows + (`tools/ux13_wizard_blobs.py --supervisor`, run offline on 2026-09-28). ## 4. What this costs diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 8a8712b..72bb441 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -2886,6 +2886,12 @@ works under hourly pricing is an EMS for a minority. `static_profile` is how a two-period day/night tariff or a single fixed price becomes a first-class configuration rather than "turn the price feature off and hope". +On the add-on page, choose **Other time windows** under Settings, Tariff and +prices, or in Setup step 4. Add one row per time window, with its start, end, +days and price. The page names any overlap, gap or empty price before you can +save. You only need the JSON below for days the page cannot choose, such as +Monday and Wednesday only. + It is one option, holding a JSON object, on one line: ```json @@ -3221,6 +3227,18 @@ action log (`Controller.events`). The page no longer shows that log, but the page and add `status` to its address. The action-log tables in this document refer to it.* +### Language and screenshots + +The page is in Dutch when your browser's language is Dutch, and in English +otherwise. Status lines, alarms and the start checks' messages stay in English. + +Screenshots of each screen are in the add-on's repository, under +`docs/img/ux13/`. The battery-mode screens are not built yet, so there are no +screenshots of them. + +*For installers: regenerate the screenshots with +`tools/ux13_screenshots.sh`, which serves the page from test fixtures.* + ### Setup, for a new install The **Setup** tab walks an installer through six steps: the meter, the diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index c6c62c6..1361661 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -16,7 +16,7 @@ section at the bottom and is held to STYLE.md by test_messages.py. from datetime import datetime, timedelta, timezone -from . import arbitrage, messages, peakguard +from . import arbitrage, messages, peakguard, uitext from .maintenance import CHARGE as M_CHARGE, DRAIN as M_DRAIN, HOLD as M_HOLD from .maintenance import IDLE as M_IDLE from .price import Absence, Uncertainty, brussels @@ -54,18 +54,6 @@ def hhmm(t: datetime) -> str: return f"{brussels(t):%H:%M}" -def _kw(w) -> str: - return f"{abs(float(w)) / 1000:.1f} kW" - - -def _eur(v) -> str: - return f"€{float(v):.2f}" - - -def _kwh(v) -> str: - return f"{float(v):.1f} kWh" - - # --------------------------------------------------------------------------- # # Now # --------------------------------------------------------------------------- # @@ -490,8 +478,7 @@ def build_plan(c, now, shadow, running, held=False, settled=True): "day": brussels(now).date().isoformat(), "now_h": round(_hours(now, day0), 3), "hours": int(round(_hours(day1, day0))), - "verdict": (VERDICT[verdict_key] if settled or verdict_key != "held" - else ZERO_GOING), + "verdict": verdict_words(verdict_key, settled), "verdict_key": verdict_key, "head": plan_head(verdict_key, shadow, settled), "prices": bars, @@ -537,7 +524,7 @@ def battery_rows(c, shadow, running, held=False): "stored_kwh": (None if cap is None or inv.soc is None else round(cap * float(inv.soc) / 100.0, 2)), "state": flow(inv.batt, shadow=shadow), - "mode": MODE_HOUSE, + "mode": mode_house(), "maintenance": phase, "now": battery_now(inv.soc, inv.batt, phase=phase, shadow=shadow, running=running, held=held, @@ -549,28 +536,6 @@ def battery_rows(c, shadow, running, held=False): return rows -# Row id -> the title on Home. The row's own sentence is the body. -ATTN_TITLES = { - "controller": "Control is not running", - "meter": "Meter reading", - "meter_frozen": messages.T_METER_FROZEN, - "freeze_check": "Stuck meter check", - "month_peak": "This month's peak", - "peak_guard": "Peak limit", - "peak_forecast": "Peak limit forecast", - "sensor": "Battery readings", - "control": "Inverter control", - "power_too_high": messages.T_OUTPUT_CLAMP, - "not_keeping_up": messages.T_LOOP_BOUND, - "write": "Power request not accepted", - "direction": "Power went the wrong way", - "site_direction": "Power went the wrong way", - "circulating": messages.T_CIRCULATING, - "delivery": messages.S_NOT_DELIVERING, - "estop": "Emergency stop", - "pv": "Solar reading", - None: "Inverter connection", -} # Row id -> the DOCS.md heading under Notifications, where one exists. ATTN_DOCS = { "meter_frozen": messages.T_METER_FROZEN, @@ -594,7 +559,7 @@ def attention(checks): sev = INFO if ok else (WARNING if warn else ALARM) rid = row.get("id") out.append({"severity": sev, "id": rid, - "title": ATTN_TITLES.get(rid, ATTN_TITLES[None]), + "title": attn_title(rid), "body": row.get("text", ""), "docs": ATTN_DOCS.get(rid)}) out.sort(key=lambda a: rank[a["severity"]]) @@ -605,7 +570,7 @@ def month_peak(c, now): """This month's peak against the limit, and the 15-minute period so far.""" limit_w = c.peak.cap_w # the limit the controller parsed at start local = brussels(now) - out = {"month": f"{local:%B}", "limit_w": limit_w, "peak_w": None, + out = {"month": month_name(local), "limit_w": limit_w, "peak_w": None, "pct": None, "period_w": None, "state": "not_covered", "line": ""} if not c.p1_enabled: @@ -644,8 +609,18 @@ def state_of(c, level, shadow): return "running" -def build(c, *, level: str, checks: list, now: datetime | None = None) -> dict: - """The structured half of `/status`. Pure reads of the controller.""" +def build(c, *, level: str, checks: list, now: datetime | None = None, + lang: str = "en") -> dict: + """The structured half of `/status`, in `lang` (UX-13 P5). Pure reads of + the controller.""" + _LANG[0] = uitext.lang_of(lang) + try: + return _build(c, level=level, checks=checks, now=now) + finally: + _LANG[0] = "en" + + +def _build(c, *, level, checks, now): now = now or datetime.now(timezone.utc) shadow = bool(c.shadow) kind = state_of(c, level, shadow) @@ -667,7 +642,7 @@ def build(c, *, level: str, checks: list, now: datetime | None = None) -> dict: "plan": build_plan(c, now, shadow, running, held=held, settled=settled), "attention": ([{"severity": INFO, "id": "shadow", - "title": ATTN_SHADOW, "body": attn_shadow_body(), + "title": attn_shadow(), "body": attn_shadow_body(), "docs": None}] if shadow else []) + attention(checks), "month_peak": month_peak(c, now), "control": {"running": bool(c.auto), "shadow": shadow, @@ -687,279 +662,309 @@ def _docs_url(): # The words. STYLE.md: plain, short, present tense. A plan line is at most # two sentences of at most 12 words each (UX-13 design, section 4); a title at # most 5 words; everything else one sentence of at most 25 words. In shadow -# mode a text says what the add-on WOULD do. test_messages.py renders every -# function below through `text_samples()` and checks it. +# mode a text says what the add-on WOULD do. The sentences themselves are in +# app/ui_text/<lang>.json under `home_words` (UX-13 P5: English and Dutch). +# test_messages.py and test_ui_text.py render every function below through +# `text_samples()` in each language and check it. # =========================================================================== # -MODE_HOUSE = "Follows the house" -ATTN_SHADOW = "Shadow mode is on" +_LANG = ["en"] # the language of the build in progress (build()) +_WORDS: dict = {} + + +def _hw() -> dict: + lang = _LANG[0] + if lang not in _WORDS: + _WORDS[lang] = uitext.words(lang) + return _WORDS[lang] + + +def _t(path, **values) -> str: + node = _hw()["home_words"] + for k in path.split("."): + node = node[k] + return uitext.say(node, **values) + + +def _dec(text) -> str: + """A decimal comma in Dutch.""" + return text.replace(".", ",") if _LANG[0] == "nl" else text + + +def _kw(w) -> str: + return _dec(f"{abs(float(w)) / 1000:.1f}") + " kW" + + +def _eur(v) -> str: + return "€" + _dec(f"{float(v):.2f}") + + +def _kwh(v) -> str: + return _dec(f"{float(v):.1f}") + " kWh" + + +# Row id -> the title on Home. The row's own sentence is the body, and it stays +# in English (app/messages.py). Five titles are the notification's own title, +# which test_ui_text.py checks. +_EN = uitext.words("en")["home_words"] +ATTN_TITLES = {(None if k == "none" else k): v for k, v in _EN["attn"].items()} +ATTN_FROM_MESSAGES = { + "meter_frozen": messages.T_METER_FROZEN, + "power_too_high": messages.T_OUTPUT_CLAMP, + "not_keeping_up": messages.T_LOOP_BOUND, + "circulating": messages.T_CIRCULATING, + "delivery": messages.S_NOT_DELIVERING, +} +VERDICT = dict(_EN["verdict"]) +MODE_HOUSE, ATTN_SHADOW = _EN["mode_house"], _EN["attn_shadow"] +ZERO_HELD, ZERO_GOING = _EN["zero_held"], _EN["zero_going"] + + +def mode_house() -> str: + return _t("mode_house") + + +def attn_shadow() -> str: + return _t("attn_shadow") def attn_shadow_body() -> str: - return "The add-on decides everything, but every inverter stays at 0 W." - -ZERO_HELD, ZERO_GOING = "Held at 0 W", "Going to 0 W" -VERDICT = { - "held": ZERO_HELD, - "stopped": "Stopped", - "cycle": "Monthly cycle today", - "trade": "Trading on price", - "house": "Follows the house", -} + return _t("attn_shadow_body") -def _w(shadow, live, would): - return would if shadow else live +def verdict_words(key, settled=True) -> str: + return _t("verdict." + key) if settled or key != "held" \ + else _t("zero_going") + + +def attn_title(rid) -> str: + table = _hw()["home_words"]["attn"] + return table.get(rid or "none", table["none"]) + + +def month_name(local) -> str: + return _hw()["home_words"]["months"][local.month - 1] + + +def _w(shadow, key, **values) -> str: + """`key`, or its `key_would` form in shadow mode.""" + return _t(key + "_would" if shadow else key, **values) def pill(kind) -> str: - return {"running": "Running", "shadow": "Shadow mode", - "stopped": "Stopped", "alarm": "Needs you now", - "warning": "Running, with a warning"}[kind] + return _t("pill." + kind) def banner_sub(kind) -> str: - return { - "running": "The batteries follow the plan below.", - "shadow": "The plans below say what the add-on would do.", - "stopped": "Start control below when you are ready.", - "alarm": "See Needs attention below for what to do.", - "warning": "See Needs attention below.", - }[kind] + return _t("banner_sub." + kind) def tile_solar(pv_w, has_solar) -> str: if not has_solar: - return "Not set up" + return _t("tile.not_set_up") if pv_w is None: - return "No reading" - return "Producing" if pv_w > IDLE_W else "Not producing" + return _t("tile.no_reading") + return _t("tile.producing") if pv_w > IDLE_W else _t("tile.not_producing") def tile_house(house_w, has_solar, disagree=False) -> str: if not has_solar: - return "Needs a solar reading" + return _t("tile.needs_solar") if disagree: - return "Readings do not add up" - return "No reading" if house_w is None else "Using" + return _t("tile.not_adding_up") + return _t("tile.no_reading") if house_w is None else _t("tile.using") def tile_grid(grid_w) -> str: if grid_w is None: - return "No reading" + return _t("tile.no_reading") if grid_w > IDLE_W: - return "Taking from the grid" + return _t("tile.taking") if grid_w < -IDLE_W: - return "Feeding in" - return "Balanced" + return _t("tile.feeding") + return _t("tile.balanced") def _zero(settled) -> str: - return ZERO_HELD if settled else ZERO_GOING + return _t("zero_held") if settled else _t("zero_going") def tile_batt(batt_w, shadow, settled=True) -> str: if shadow: return _zero(settled) - return {"giving": "Giving power", "charging": "Charging", - "resting": "Resting", None: "No reading"}[flow(batt_w)] + return _t("tile." + {"giving": "giving", "charging": "charging", + "resting": "resting", + None: "no_reading"}[flow(batt_w)]) def battery_now(soc, batt_w, *, phase, shadow, running, held=False, would_w=None, settled=True) -> str: if soc is None or batt_w is None: - return "No reading from this battery." + return _t("now.no_reading") zero = _zero(settled) if shadow: if would_w is None or abs(would_w) <= IDLE_W: - return f"{zero}. Would rest now." - verb = "give" if would_w > 0 else "charge" - return f"{zero}. Would {verb} {_kw(would_w)} now." + return _t("now.would_rest", zero=zero) + verb = "would_give" if would_w > 0 else "would_charge" + return _t("now." + verb, zero=zero, kw=_kw(would_w)) if held: - return f"{zero} until the alarm clears." + return _t("now.held", zero=zero) if not running: - return f"{zero} while control is stopped." + return _t("now.stopped", zero=zero) if phase != M_IDLE: - return {M_DRAIN: "Monthly cycle: emptying.", - M_CHARGE: "Monthly cycle: refilling.", - M_HOLD: "Monthly cycle: holding full."}.get( - phase, "Monthly cycle under way.") + return _t("now." + {M_DRAIN: "cycle_drain", M_CHARGE: "cycle_charge", + M_HOLD: "cycle_hold"}.get(phase, "cycle")) st = flow(batt_w) if st == "giving": - return f"Giving {_kw(batt_w)} now." + return _t("now.giving", kw=_kw(batt_w)) if st == "charging": - return f"Charging {_kw(batt_w)} now." - return "Resting now." + return _t("now.charging", kw=_kw(batt_w)) + return _t("now.resting") def plan_head(key, shadow, settled=True) -> str: if key == "held": - return ("Every inverter is at 0 W until the alarm clears." if settled - else "Every inverter goes to 0 W until the alarm clears.") + return _t("head.held" if settled else "head.held_going") if key == "stopped": - return "Control is stopped, so nothing is planned." + return _t("head.stopped") if not shadow: - return { - "cycle": "A battery runs its monthly cycle today.", - "trade": "Charges in the cheapest hour, gives power in the dearest.", - "house": "Charges from spare solar and covers the house.", - }[key] - return "Shadow mode: this is what the add-on would do. " + { - "cycle": "A battery would run its monthly cycle today.", - "trade": "Would charge when cheapest and give power when dearest.", - "house": "Would charge from spare solar and cover the house.", - }[key] + return _t("head." + key) + return _t("head.shadow") + " " + _t("head." + key + "_would") def run_grid_what(kwh, shadow) -> str: - return _w(shadow, "Charges", "Would charge") + \ - f" up to {_kwh(kwh)} from the grid." + return _w(shadow, "run.grid_what", kwh=_kwh(kwh)) # The trade legs and the price line use the feed's own points (a 15-minute # period on a quarter-hourly feed), so both name the same price and time. def run_grid_why(price) -> str: - return f"Lowest published price, {_eur(price)} per kWh." + return _t("run.grid_why", eur=_eur(price)) def run_grid_amount(eur) -> str: - return f"Costs up to {_eur(eur)}." + return _t("run.grid_amount", eur=_eur(eur)) def run_give_what(kwh, shadow) -> str: - return _w(shadow, "Gives", "Would give") + \ - f" up to {_kwh(kwh)}, to the house first." + return _w(shadow, "run.give_what", kwh=_kwh(kwh)) def run_give_why(price) -> str: - return f"Highest published price, {_eur(price)} per kWh." + return _t("run.give_why", eur=_eur(price)) def run_give_amount(eur) -> str: - return f"Worth up to {_eur(eur)} at that price." + return _t("run.give_amount", eur=_eur(eur)) def run_cycle_what(phase, shadow) -> str: - if phase == M_IDLE: - return _w(shadow, "Starts", "Would start") + \ - " the monthly battery cycle." - return _w(shadow, "Runs", "Would run") + " the monthly battery cycle now." + return _w(shadow, "run.cycle_start" if phase == M_IDLE else "run.cycle_now") def run_cycle_why(shadow=False) -> str: - return _w(shadow, "Empties, refills and holds full", - "Would empty, refill and hold full") + \ - ", so the level reads right." + return _w(shadow, "run.cycle_why") def run_cycle_amount(hours) -> str: if hours is None: - return "How long depends on the battery." - return f"Takes about {max(1, round(hours))} hours." + return _t("run.cycle_amount_unknown") + return _t("run.cycle_amount", hours=max(1, round(hours))) def run_peak_what(limit_w, shadow) -> str: - return _w(shadow, "Gives", "Would give") + \ - f" power to stay under {_kw(limit_w)}." + return _w(shadow, "run.peak_what", kw=_kw(limit_w)) def run_peak_why() -> str: - return "The peak limit comes before everything else." + return _t("run.peak_why") def run_house_what(shadow) -> str: - return _w(shadow, "Follows", "Would follow") + " the house." + return _w(shadow, "run.house_what") def run_house_why(shadow=False) -> str: - return _w(shadow, "Charges from spare solar, gives power", - "Would charge from spare solar, give power") + \ - " when the house needs it." + return _w(shadow, "run.house_why") def run_house_amount() -> str: - return "Amounts depend on the sun and the house." + return _t("run.house_amount") def line_no_trade(key) -> str: - return { - "off": "", - "not_covered": "No trading on price: nothing measures the 15-minute " - "peak.", - "no_prices": "No trading on price yet: no prices have arrived.", - "peak": "No trading on price now: the peak limit comes first.", - "not_firm": "No trading on price yet: the prices are not published.", - "not_worth": "No trading on price today. The price gap is too small.", - "no_level": "No trading on price now: a battery level is unknown.", - }[key] + return "" if key == "off" else _t("no_trade." + key) def line_trade_tomorrow(kind, at, price, shadow) -> str: - verb = {"grid": _w(shadow, "Charges", "Would charge"), - "give": _w(shadow, "Gives power", "Would give power")}[kind] - return f"Tomorrow: {verb.lower()} at {at}, {_eur(price)} per kWh." + return _w(shadow, "tomorrow_trade." + kind, at=at, eur=_eur(price)) def line_cycle_waits(name) -> str: - return f"{name} waits its turn for the monthly cycle." + return _t("cycle_waits", name=name) def line_peak_limit(limit_w, shadow) -> str: - return _w(shadow, "The batteries step in", "The batteries would step in") \ - + f" above {_kw(limit_w)}." + return _w(shadow, "step_in", kw=_kw(limit_w)) def line_prices(now_eur, lo, hi) -> str: parts = [] if now_eur is not None: - parts.append(f"Price now {_eur(now_eur)} per kWh, all in.") + parts.append(_t("prices.now", eur=_eur(now_eur))) if lo is not None and hi is not None: - parts.append(f"Today: lowest {_eur(lo['eur_kwh'])} at " - f"{lo['label']}, highest {_eur(hi['eur_kwh'])} at " - f"{hi['label']}.") - return " ".join(parts) or "No prices for today." + parts.append(_t("prices.today", lo=_eur(lo["eur_kwh"]), + lo_at=lo["label"], hi=_eur(hi["eur_kwh"]), + hi_at=hi["label"])) + return " ".join(parts) or _t("prices.none") def line_tomorrow(known) -> str: - return ("Tomorrow's prices are in." if known else - "Tomorrow's prices usually arrive after 13:00.") + return _t("tomorrow.known" if known else "tomorrow.unknown") def line_region(rid, year) -> str: if rid in REGION_PRESETS and year: - return f"Levies and VAT: {REGION_WORDS.get(rid, rid)}, {year} figures." - return "Levies and VAT: your own figure." - - -REGION_WORDS = {"flanders": "Flanders, Fluvius Antwerpen"} + name = _hw()["choices"]["region"].get(rid, rid) + return _t("region.preset", region=name, year=year) + return _t("region.own") def line_peak_not_covered() -> str: - return "No peak limit: this meter does not measure 15-minute periods." + return _t("peak_not_covered") def line_period(period_w, limit_w, shadow) -> str: - step = _w(shadow, "The batteries step in", "The batteries would step in") + step = _w(shadow, "step_in", kw=_kw(limit_w)) if period_w is None: - return f"{step} above {_kw(limit_w)}." - return (f"This 15-minute period is heading for {_kw(period_w)}. " - f"{step} above {_kw(limit_w)}.") + return step + return _t("period", kw=_kw(period_w)) + " " + step def control_text(running, shadow) -> str: if shadow: - return "Shadow mode: every inverter stays at 0 W." + return _t("control.shadow") if running: - return "Control is running." - return "Control is stopped. Every inverter is at 0 W." + return _t("control.running") + return _t("control.stopped") -def text_samples() -> list: - """`(kind, text)` for every sentence above, rendered with real values, so - test_messages.py can hold each to its STYLE limit. Kinds: title, plan - (2 sentences of 12 words), line (1 sentence of 25 words).""" - out = [("title", t) for t in VERDICT.values()] + [("title", ZERO_GOING)] - out += [("title", t) for t in ATTN_TITLES.values()] - out += [("title", MODE_HOUSE), ("title", ATTN_SHADOW), +def text_samples(lang="en") -> list: + """`(kind, text)` for every sentence above in `lang`, rendered with real + values, so test_messages.py can hold each to its STYLE limit. Kinds: title, + plan (2 sentences of 12 words), line (1 sentence of 25 words).""" + _LANG[0] = uitext.lang_of(lang) + try: + return _samples() + finally: + _LANG[0] = "en" + + +def _samples() -> list: + words = _hw()["home_words"] + out = [("title", t) for t in words["verdict"].values()] + out += [("title", _t("zero_going")), ("title", _t("zero_held"))] + out += [("title", t) for t in words["attn"].values()] + out += [("title", mode_house()), ("title", attn_shadow()), ("line", attn_shadow_body())] for k in ("running", "shadow", "stopped", "alarm", "warning"): out += [("title", pill(k)), ("line", banner_sub(k))] diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index bdce450..d92ceb7 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -5544,7 +5544,7 @@ class Controller: _inv_list.index(ent) + 1)}) return out - def status_payload(self) -> dict: + def status_payload(self, lang: str = "en") -> dict: checks = self.checks() bad = [c for c in checks if not c["ok"] and not c["warn"]] # --- SAFETY-10, AND IT IS FIRST IN THE CASCADE ----------------------- @@ -5730,7 +5730,8 @@ class Controller: # never cost the page its rows: a fault here is logged and the old # fields are served alone (the page then shows the installer details). try: - out.update(homeview.build(self, level=level, checks=checks)) + out.update(homeview.build(self, level=level, checks=checks, + lang=lang)) except Exception: # noqa: BLE001 # Once per process at ERROR: the page polls every 3 s. if not getattr(self, "_home_failed", False): diff --git a/goodwe_controller/app/setuponly.py b/goodwe_controller/app/setuponly.py index 0e0a6b2..bb4ce3e 100644 --- a/goodwe_controller/app/setuponly.py +++ b/goodwe_controller/app/setuponly.py @@ -52,7 +52,7 @@ class SetupOnly: if hint is not None: self.hint = f"{datetime.now().astimezone():%H:%M} {hint}" - def status_payload(self) -> dict: + def status_payload(self, lang: str = "en") -> dict: return {"setup_only": True, "mode": "setup_only", "banner": messages.banner_setup_only(), "level": "warn", "rows": [["Control", "not started, in setup"]], diff --git a/goodwe_controller/app/static/app.css b/goodwe_controller/app/static/app.css index d766298..6e4d52f 100644 --- a/goodwe_controller/app/static/app.css +++ b/goodwe_controller/app/static/app.css @@ -206,6 +206,10 @@ input:disabled{opacity:.6} .ent-all{display:flex;gap:6px;padding:6px 10px;align-items:center;min-height:44px} .elist .erow{padding:6px 0;border-bottom:1px dashed var(--line)} .elist>.btn{margin-top:8px} +.plist .prow{display:grid;gap:6px} +.plist .pf{display:flex;flex-direction:column;gap:2px} +.plist .pf>select.sel{width:100%} +input.txt.time{width:5.5em;text-align:center;font-variant-numeric:tabular-nums} .inv{border:1px solid var(--line);border-radius:10px;padding:0 12px;margin:10px 0} .inv>.hd{display:flex;align-items:center;gap:8px;padding:10px 0;border-bottom:1px solid var(--line);font-weight:600;flex-wrap:wrap} .inv>.f:nth-child(2){border-top:0} diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 2aed6b4..f872379 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -5,7 +5,19 @@ labels) or from /status (sentences built by app/homeview.py), so STYLE.md is checked in Python. Data is always set as text, never as HTML. */ (function () { - const T = JSON.parse(document.getElementById("ui-text").textContent).home; + // P5: English or Dutch, by the browser's language. A word missing in Dutch + // falls back to English, key by key (app/uitext.py does the same). + const ALL = JSON.parse(document.getElementById("ui-text").textContent); + const LANG = /^nl\b/i.test(navigator.language || "") ? "nl" : "en"; + const merge = (a, b) => { + if (!b || typeof a !== "object" || typeof b !== "object" || Array.isArray(a)) return b ?? a; + const out = Object.assign({}, a); + for (const k in b) out[k] = k in a ? merge(a[k], b[k]) : b[k]; + return out; + }; + const WORDS = LANG === "en" ? ALL.en : merge(ALL.en, ALL[LANG]); + document.documentElement.lang = LANG; + const T = WORDS.home; const $ = (s) => document.querySelector(s); const t = (path) => path.split(".").reduce((o, k) => (o == null ? o : o[k]), T); function h(tag, attrs, ...kids) { @@ -24,8 +36,9 @@ } return e; } - const kw = (w) => (Math.abs(Number(w)) / 1000).toFixed(1); - const eur = (v) => "€" + Number(v).toFixed(2); + const dec = (x) => (LANG === "nl" ? x.replace(".", ",") : x); + const kw = (w) => dec((Math.abs(Number(w)) / 1000).toFixed(1)); + const eur = (v) => "€" + dec(Number(v).toFixed(2)); // Fixed labels from ui_text. document.querySelectorAll("[data-t]").forEach((e) => { e.textContent = t(e.dataset.t) || ""; }); @@ -55,7 +68,7 @@ /* ---------------- data ---------------- */ async function getStatus() { - const r = await fetch("status", { cache: "no-store" }); + const r = await fetch("status?lang=" + LANG, { cache: "no-store" }); if (!r.ok) throw new Error("status " + r.status); return r.json(); } @@ -87,7 +100,7 @@ const st = S.state || null; const dot = st ? ({ running: "", shadow: " warn", stopped: " warn", warning: " warn", alarm: " bad" }[st.kind] ?? " warn") : (S.level === "ok" ? "" : S.level === "bad" ? " bad" : " warn"); - const words = st ? [st.pill, st.ran].filter(Boolean).join(". ") : S.banner; + const words = st ? [st.pill, st.ran].filter(Boolean).join(". ") : S.setup_only === true ? t("setup_only.name") : S.banner; $("#pill").replaceChildren(h("span", { class: "dot" + dot, "aria-hidden": "true" }), h("span", {}, words)); } @@ -96,7 +109,7 @@ const structured = S.now && S.plan && !S.home_error; // UX-15: setup-only mode commands nothing and has no control to offer. const setup = S.setup_only === true; - banner($("#home-banner"), S.level, S.banner, structured ? S.state.sub : setup ? t("setup_only.description") : "", S.level === "bad" ? "alert" : null); + banner($("#home-banner"), S.level, setup ? t("setup_only.name") : S.banner, structured ? S.state.sub : setup ? t("setup_only.description") : "", S.level === "bad" ? "alert" : null); ["#c-now", "#c-plan", "#c-peak", "#c-attn"].forEach((id) => { $(id).hidden = !structured; }); if (structured) { renderNow(); renderPlan(); renderPeak(); renderAttention(); } renderControl(structured, setup); @@ -303,7 +316,7 @@ levelBar(b.level_pct, b.name), h("dl", { class: "kv" }, h("dt", {}, t("batteries.level")), h("dd", {}, b.level_pct == null ? "–" : Math.round(b.level_pct) + " %"), - b.stored_kwh != null ? [h("dt", {}, t("batteries.stored")), h("dd", {}, b.stored_kwh.toFixed(1) + " kWh")] : null, + b.stored_kwh != null ? [h("dt", {}, t("batteries.stored")), h("dd", {}, dec(b.stored_kwh.toFixed(1)) + " kWh")] : null, h("dt", {}, t("batteries.now")), h("dd", {}, b.now), h("dt", {}, t("batteries.mode")), h("dd", {}, b.mode))))); } @@ -339,7 +352,7 @@ // Shared with settings.js, which loads after this file. // `first`: the page opened with no route, so settings.js may open the setup // wizard on a new install (UX-13 P4). - window.UX13 = { h, ask, toast, t, maint: (what) => ask(what, () => simple(what)), first: !location.hash }; + window.UX13 = { h, ask, toast, t, words: WORDS, lang: LANG, maint: (what) => ask(what, () => simple(what)), first: !location.hash }; /* ---------------- tabs: hash routes, arrow keys ---------------- */ const TABS = [...document.querySelectorAll(".tab")]; diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index aa3e9ff..ba3164a 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -9,9 +9,9 @@ P4: the Setup tab's wizard is the same page model, drawn one step at a time from each field's `wizard` step, and saved through the same routes. */ (function () { - const ROOT = JSON.parse(document.getElementById("ui-text").textContent); + const ROOT = window.UX13.words; // English or Dutch (app.js) const W = ROOT.settings; - const { h, ask, toast, maint } = window.UX13; + const { h, ask, toast, maint, lang } = window.UX13; const $ = (s) => document.querySelector(s); const ws = (path) => path.split(".").reduce((o, k) => (o == null ? o : o[k]), W); const clone = (x) => (x === undefined ? undefined : JSON.parse(JSON.stringify(x))); @@ -288,8 +288,45 @@ box.append(h("button", { type: "button", class: "btn", onclick: () => put(f, card, arr().concat([{ entity: "", reversed: false }]), true) }, "+ " + W.add_solar)); return box; } + // P5: time windows, each a start, an end, its days and a price. The add-on + // builds the tariff from the rows and names the first overlap or gap. + function periodList(f, card) { + const P = W.periods; + const arr = () => (Array.isArray(get(f, card)) ? get(f, card) : []); + const box = h("div", { class: "elist plist" }); + if (!Array.isArray(get(f, card))) return h("div", { class: "msg info" }, W.derive.custom_profile.description); + arr().forEach((row, i) => { + const set = (k, v) => { const a = clone(arr()); a[i][k] = v; put(f, card, a); }; + const say = (what) => P.window + " " + (i + 1) + ", " + what; + const time = (k) => { + const e = h("input", { class: "txt time", type: "text", inputmode: "numeric", maxlength: "5", placeholder: "00:00", + value: row[k] == null ? "" : row[k], autocomplete: "off", spellcheck: "false", "aria-label": say(P[k]) }); + e.addEventListener("input", () => set(k, e.value.trim())); + return e; + }; + const days = h("select", { class: "sel", "aria-label": say(P.days) }); + for (const [v, label] of f.days || []) days.append(h("option", { value: v, selected: v === row.days }, label)); + days.addEventListener("change", () => set("days", days.value)); + const price = h("input", { class: "num", type: "number", inputmode: "decimal", step: "0.01", + value: row.price == null ? "" : row.price, "aria-label": say(P.price) }); + price.addEventListener("input", () => set("price", price.value === "" || isNaN(+price.value) ? null : +price.value)); + const cell = (label, ...kids) => h("label", { class: "pf" }, h("span", { class: "tiny muted" }, label), ...kids); + box.append(h("div", { class: "erow prow" }, + h("div", { class: "row spread" }, h("strong", { class: "small" }, P.window + " " + (i + 1)), + h("button", { type: "button", class: "btn link tiny", onclick: () => { const a = clone(arr()); a.splice(i, 1); put(f, card, a, true); } }, W.remove)), + h("div", { class: "row" }, cell(P.from, time("from")), cell(P.to, time("to")), + cell(P.price, h("span", { class: "row" }, price, f.unit ? h("span", { class: "unit" }, f.unit) : null))), + cell(P.days, days))); + }); + box.append(h("button", { type: "button", class: "btn", onclick: () => { + const a = arr(), last = a[a.length - 1]; + put(f, card, clone(a).concat([{ from: last ? last.to : "00:00", to: "24:00", days: last ? last.days : "mon-sun", price: null }]), true); + } }, "+ " + P.add)); + return box; + } const CONTROLS = { toggle, segmented: (f, c, l) => radios(f, c, l, false), choice: (f, c, l) => radios(f, c, l, true), - select, slider, number, text, locked, entity, entity_list: entityList, solar_list: solarList }; + select, slider, number, text, locked, entity, entity_list: entityList, solar_list: solarList, + period_list: periodList }; /* ---------------- rows, cards and groups ---------------- */ function keyText(f, card) { @@ -304,7 +341,7 @@ const msg = h("div", { class: "msgs" }); const make = CONTROLS[f.control] || text; const row = h("div", { class: "f" + (f.control === "toggle" ? " inline" : ""), "data-key": f.key, "data-card": card }, - h("div", { class: "head" }, h("div", { class: "lbl", id: lid }, f.label, f.unit && f.control !== "slider" && f.control !== "number" && f.control !== "locked" ? " (" + f.unit + ")" : ""), + h("div", { class: "head" }, h("div", { class: "lbl", id: lid }, f.label, f.unit && !["slider", "number", "locked", "period_list"].includes(f.control) ? " (" + f.unit + ")" : ""), keys ? h("div", { class: "key" }, keys) : null), h("div", { class: "ctl" }, make(f, card, lid)), f.help ? h("div", { class: "help" }, f.help) : null, msg); @@ -469,7 +506,7 @@ const seq = ++vseq; try { const r = await fetch("config/validate", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify(Object.assign({ model: V }, extra || {})) }); + body: JSON.stringify(Object.assign({ model: V, lang }, extra || {})) }); const b = await r.json(); if (seq !== vseq) return null; MSG = b.messages || []; @@ -498,7 +535,7 @@ async function load(after) { let m; try { - const r = await fetch("config/model?lang=en", { cache: "no-store" }); + const r = await fetch("config/model?lang=" + lang, { cache: "no-store" }); if (!r.ok) throw new Error("model " + r.status); m = await r.json(); if (!m.layout || !m.ui) throw new Error("no layout"); @@ -538,7 +575,7 @@ // what is stored now (UX-15 F2). async function postSave(extra) { const r = await fetch("config/save", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify(Object.assign({ model: V, base: ORIG, fingerprint: FP }, extra || {})) }); + body: JSON.stringify(Object.assign({ model: V, base: ORIG, fingerprint: FP, lang }, extra || {})) }); const b = await r.json().catch(() => ({})); if (r.status === 409 && b.kind === "stale") FP = b.fingerprint || FP; return { r, b }; diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 833286e..8903e83 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -24,7 +24,8 @@ "fallback": {"name": "Price when the feed is down", "description": "Used when the price source does not answer."}, "fixed_price": {"name": "Price per kWh, all in", "description": "Energy, supplier costs, grid costs, levies and VAT together."}, "day_price": {"name": "Day price, weekdays 07:00 to 22:00", "description": "All in, as on your bill."}, - "night_price": {"name": "Night and weekend price", "description": "All in, as on your bill."} + "night_price": {"name": "Night and weekend price", "description": "All in, as on your bill."}, + "periods": {"name": "Time windows and prices", "description": "One price per kWh for each time window, all in, as on your bill."} }, "choices": { "contract": {"none": "No prices", "fixed": "Fixed price", "daynight": "Day and night", "dynamic": "Dynamic, hourly", "custom": "Other time windows"}, @@ -34,7 +35,8 @@ "meter_phases": {"1": "1 phase", "3": "3 phases"}, "shadow_mode": {"auto": "Automatic", "on": "Always on", "off": "Off"}, "price_provider": {"generic_dayahead": "Day-ahead market price", "custom_formula": "Your own price formula", "manual_csv": "A price file"}, - "log_level": {"trace": "Everything, for support", "debug": "Detailed, to find a problem", "info": "Normal", "warning": "Warnings and errors", "error": "Errors only"} + "log_level": {"trace": "Everything, for support", "debug": "Detailed, to find a problem", "info": "Normal", "warning": "Warnings and errors", "error": "Errors only"}, + "period_days": {"mon-sun": "Every day", "mon-fri": "Monday to Friday", "sat,sun": "Saturday and Sunday", "mon": "Monday", "tue": "Tuesday", "wed": "Wednesday", "thu": "Thursday", "fri": "Friday", "sat": "Saturday", "sun": "Sunday"} }, "applies": { "restart": {"name": "Applies after a restart"}, @@ -79,7 +81,7 @@ }, "toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."}, "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, - "setup_only": {"description": "Nothing is sent to any inverter until setup is saved and the add-on restarts.", "control": "Control starts after setup.", "open": "Open Setup"}, + "setup_only": {"name": "Setup: nothing is controlled yet", "description": "Nothing is sent to any inverter until setup is saved and the add-on restarts.", "control": "Control starts after setup.", "open": "Open Setup"}, "batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"}, "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, @@ -127,6 +129,7 @@ "remove": "Remove", "add_row": "Add a row", "add_solar": "Add a solar inverter", + "periods": {"window": "Window", "from": "From", "to": "To", "days": "Days", "price": "Price", "add": "Add a time window"}, "reversed": "Reads negative", "phase": "Phase", "raw_roster": {"description": "This inverter list can only be changed in the Configuration tab."}, @@ -156,6 +159,13 @@ "no_source": {"description": "Choose where the dynamic prices come from."}, "custom_profile": {"description": "Other time windows can only be changed in the Configuration tab."}, "no_price": {"description": "Enter a price per kWh."}, + "no_periods": {"description": "Add at least one time window."}, + "period_time": {"description": "Window {row}: write each time as hours and minutes, like 07:00 or 24:00."}, + "period_zero": {"description": "Window {row} starts and ends at the same time, so change one of them."}, + "period_price": {"description": "Window {row}: enter a price per kWh."}, + "period_price_range": {"description": "Window {row}: enter the price in euro per kWh, like 0.34."}, + "period_overlap": {"description": "Windows {a} and {b} both cover {day} {from} to {to}, so change one of them."}, + "period_gap": {"description": "No window covers {day} {from} to {to}, so add one or widen one."}, "unknown": {"description": "The page cannot store this choice, so reload the page."} }, "setup": { @@ -215,5 +225,160 @@ "restart_failed": {"name": "Saved, not running yet", "description": "The restart did not go through, so press Restart now to apply the settings."}, "home": "Open Home" } + }, + "home_words": { + "mode_house": "Follows the house", + "attn_shadow": "Shadow mode is on", + "attn_shadow_body": "The add-on decides everything, but every inverter stays at 0 W.", + "zero_held": "Held at 0 W", + "zero_going": "Going to 0 W", + "verdict": { + "held": "Held at 0 W", + "stopped": "Stopped", + "cycle": "Monthly cycle today", + "trade": "Trading on price", + "house": "Follows the house" + }, + "pill": { + "running": "Running", + "shadow": "Shadow mode", + "stopped": "Stopped", + "alarm": "Needs you now", + "warning": "Running, with a warning" + }, + "banner_sub": { + "running": "The batteries follow the plan below.", + "shadow": "The plans below say what the add-on would do.", + "stopped": "Start control below when you are ready.", + "alarm": "See Needs attention below for what to do.", + "warning": "See Needs attention below." + }, + "tile": { + "not_set_up": "Not set up", + "no_reading": "No reading", + "producing": "Producing", + "not_producing": "Not producing", + "needs_solar": "Needs a solar reading", + "not_adding_up": "Readings do not add up", + "using": "Using", + "taking": "Taking from the grid", + "feeding": "Feeding in", + "balanced": "Balanced", + "giving": "Giving power", + "charging": "Charging", + "resting": "Resting" + }, + "now": { + "no_reading": "No reading from this battery.", + "would_rest": "{zero}. Would rest now.", + "would_give": "{zero}. Would give {kw} now.", + "would_charge": "{zero}. Would charge {kw} now.", + "held": "{zero} until the alarm clears.", + "stopped": "{zero} while control is stopped.", + "cycle_drain": "Monthly cycle: emptying.", + "cycle_charge": "Monthly cycle: refilling.", + "cycle_hold": "Monthly cycle: holding full.", + "cycle": "Monthly cycle under way.", + "giving": "Giving {kw} now.", + "charging": "Charging {kw} now.", + "resting": "Resting now." + }, + "head": { + "held": "Every inverter is at 0 W until the alarm clears.", + "held_going": "Every inverter goes to 0 W until the alarm clears.", + "stopped": "Control is stopped, so nothing is planned.", + "cycle": "A battery runs its monthly cycle today.", + "trade": "Charges in the cheapest hour, gives power in the dearest.", + "house": "Charges from spare solar and covers the house.", + "shadow": "Shadow mode: this is what the add-on would do.", + "cycle_would": "A battery would run its monthly cycle today.", + "trade_would": "Would charge when cheapest and give power when dearest.", + "house_would": "Would charge from spare solar and cover the house." + }, + "run": { + "grid_what": "Charges up to {kwh} from the grid.", + "grid_what_would": "Would charge up to {kwh} from the grid.", + "grid_why": "Lowest published price, {eur} per kWh.", + "grid_amount": "Costs up to {eur}.", + "give_what": "Gives up to {kwh}, to the house first.", + "give_what_would": "Would give up to {kwh}, to the house first.", + "give_why": "Highest published price, {eur} per kWh.", + "give_amount": "Worth up to {eur} at that price.", + "cycle_start": "Starts the monthly battery cycle.", + "cycle_start_would": "Would start the monthly battery cycle.", + "cycle_now": "Runs the monthly battery cycle now.", + "cycle_now_would": "Would run the monthly battery cycle now.", + "cycle_why": "Empties, refills and holds full, so the level reads right.", + "cycle_why_would": "Would empty, refill and hold full, so the level reads right.", + "cycle_amount_unknown": "How long depends on the battery.", + "cycle_amount": "Takes about {hours} hours.", + "peak_what": "Gives power to stay under {kw}.", + "peak_what_would": "Would give power to stay under {kw}.", + "peak_why": "The peak limit comes before everything else.", + "house_what": "Follows the house.", + "house_what_would": "Would follow the house.", + "house_why": "Charges from spare solar, gives power when the house needs it.", + "house_why_would": "Would charge from spare solar, give power when the house needs it.", + "house_amount": "Amounts depend on the sun and the house." + }, + "no_trade": { + "not_covered": "No trading on price: nothing measures the 15-minute peak.", + "no_prices": "No trading on price yet: no prices have arrived.", + "peak": "No trading on price now: the peak limit comes first.", + "not_firm": "No trading on price yet: the prices are not published.", + "not_worth": "No trading on price today. The price gap is too small.", + "no_level": "No trading on price now: a battery level is unknown." + }, + "tomorrow_trade": { + "grid": "Tomorrow: charges at {at}, {eur} per kWh.", + "grid_would": "Tomorrow: would charge at {at}, {eur} per kWh.", + "give": "Tomorrow: gives power at {at}, {eur} per kWh.", + "give_would": "Tomorrow: would give power at {at}, {eur} per kWh." + }, + "cycle_waits": "{name} waits its turn for the monthly cycle.", + "step_in": "The batteries step in above {kw}.", + "step_in_would": "The batteries would step in above {kw}.", + "period": "This 15-minute period is heading for {kw}.", + "prices": { + "now": "Price now {eur} per kWh, all in.", + "today": "Today: lowest {lo} at {lo_at}, highest {hi} at {hi_at}.", + "none": "No prices for today." + }, + "tomorrow": { + "known": "Tomorrow's prices are in.", + "unknown": "Tomorrow's prices usually arrive after 13:00." + }, + "region": { + "preset": "Levies and VAT: {region}, {year} figures.", + "own": "Levies and VAT: your own figure." + }, + "peak_not_covered": "No peak limit: this meter does not measure 15-minute periods.", + "control": { + "shadow": "Shadow mode: every inverter stays at 0 W.", + "running": "Control is running.", + "stopped": "Control is stopped. Every inverter is at 0 W." + }, + "attn": { + "controller": "Control is not running", + "meter": "Meter reading", + "meter_frozen": "Meter reading may be stuck", + "freeze_check": "Stuck meter check", + "month_peak": "This month's peak", + "peak_guard": "Peak limit", + "peak_forecast": "Peak limit forecast", + "sensor": "Battery readings", + "control": "Inverter control", + "power_too_high": "Power request too high", + "not_keeping_up": "Battery is not keeping up", + "write": "Power request not accepted", + "direction": "Power went the wrong way", + "site_direction": "Power went the wrong way", + "circulating": "Inverters working against each other", + "delivery": "An inverter is not delivering", + "estop": "Emergency stop", + "pv": "Solar reading", + "none": "Inverter connection" + }, + "months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] } } diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json new file mode 100644 index 0000000..fc616b0 --- /dev/null +++ b/goodwe_controller/app/ui_text/nl.json @@ -0,0 +1,307 @@ +{ + "groups": { + "meter": {"name": "Meter", "description": "Waar de meting van het net vandaan komt."}, + "inverters": {"name": "Omvormers en batterijen", "description": "De omvormers die de add-on regelt, en uw zonnepanelen."}, + "tariff": {"name": "Tarief en prijzen", "description": "Wat u per kWh betaalt en terugkrijgt."}, + "safety": {"name": "Veiligheidsgrenzen", "description": "De piekgrens, starten en stoppen, en de veiligheidsstops."}, + "maintenance": {"name": "Onderhoud", "description": "De maandelijkse batterijcyclus en het logboek."}, + "tuning": {"name": "Afstelling van de regeling", "description": "Alleen voor support, want deze zijn gemeten op echte hardware."} + }, + "parts": { + "meter.timing": {"name": "Timing"}, + "inverters.solar": {"name": "Zonnepanelen"}, + "tariff.selling": {"name": "Laden en verkopen op prijs"}, + "tariff.feed": {"name": "Details van de prijsfeed"}, + "safety.peak": {"name": "Piekgrens"}, + "safety.start": {"name": "Starten en stoppen"}, + "safety.stops": {"name": "Veiligheidsstops", "description": "Gemeten op echte hardware, dus laat ze zoals ze zijn."}, + "maintenance.support": {"name": "Support"} + }, + "fields": { + "solar": {"name": "Omvormers van de zonnepanelen", "description": "De vermogenssensor van elke zonne-omvormer, die de add-on bijhoudt maar niet gebruikt om te regelen."}, + "contract": {"name": "Uw contract", "description": "Hoe uw leverancier elke kWh prijst die u van het net afneemt."}, + "region": {"name": "Regio", "description": "Vult nettarieven, heffingen en btw in voor het getoonde jaar, nog niet voor Wallonië of Brussel, dus kijk uw factuur na."}, + "fallback": {"name": "Prijs als de feed wegvalt", "description": "Gebruikt als de prijsbron niet antwoordt."}, + "fixed_price": {"name": "Prijs per kWh, alles inbegrepen", "description": "Energie, kosten van de leverancier, nettarieven, heffingen en btw samen."}, + "day_price": {"name": "Dagprijs, weekdagen 07:00 tot 22:00", "description": "Alles inbegrepen, zoals op uw factuur."}, + "night_price": {"name": "Nacht- en weekendprijs", "description": "Alles inbegrepen, zoals op uw factuur."}, + "periods": {"name": "Tijdvakken en prijzen", "description": "Eén prijs per kWh voor elk tijdvak, alles inbegrepen, zoals op uw factuur."} + }, + "choices": { + "contract": {"none": "Geen prijzen", "fixed": "Vaste prijs", "daynight": "Dag en nacht", "dynamic": "Dynamisch, per uur", "custom": "Andere tijdvakken"}, + "fallback": {"none": "Geen", "fixed": "Eén prijs", "daynight": "Dag en nacht", "custom": "Andere tijdvakken"}, + "region": {"flanders": "Vlaanderen, Fluvius Antwerpen", "own": "Ik vul zelf een bedrag in"}, + "meter_source": {"off": "Eén entiteit voor netvermogen", "ha_dsmr": "Entiteiten voor afname en injectie", "mqtt_p1": "Meter via MQTT", "ha_signed": "Eén entiteit voor nettovermogen", "homewizard_local": "HomeWizard-meter op het netwerk"}, + "meter_phases": {"1": "1 fase", "3": "3 fasen"}, + "shadow_mode": {"auto": "Automatisch", "on": "Altijd aan", "off": "Uit"}, + "price_provider": {"generic_dayahead": "Day-aheadprijs van de markt", "custom_formula": "Uw eigen prijsformule", "manual_csv": "Een prijsbestand"}, + "log_level": {"trace": "Alles, voor support", "debug": "Uitgebreid, om een probleem te vinden", "info": "Normaal", "warning": "Waarschuwingen en fouten", "error": "Alleen fouten"}, + "period_days": {"mon-sun": "Elke dag", "mon-fri": "Maandag tot vrijdag", "sat,sun": "Zaterdag en zondag", "mon": "maandag", "tue": "dinsdag", "wed": "woensdag", "thu": "donderdag", "fri": "vrijdag", "sat": "zaterdag", "sun": "zondag"} + }, + "applies": {"restart": {"name": "Geldt na een herstart"}, "now": {"name": "Geldt meteen"}}, + "home": { + "app": {"name": "Batterij-add-on"}, + "tabs": {"home": "Start", "batteries": "Batterijen", "settings": "Instellingen", "setup": "Installatie", "label": "Schermen"}, + "now": {"name": "Nu", "description": "Elke 3 seconden bijgewerkt.", "solar": "Zonnepanelen", "house": "Huis", "grid": "Net", "batteries": "Batterijen"}, + "plan": { + "name": "Plan voor vandaag", + "description": "Wijs een staaf of blok aan voor details, of tik erop op een telefoon.", + "cheap": "Lage prijs", + "dear": "Hoge prijs", + "estimate": "Schatting", + "grid": "Laadt van het net", + "give": "Levert stroom", + "cycle": "Maandelijkse batterijcyclus", + "peak": "Piekgrens", + "house": "Volgt het huis", + "now": "nu", + "time_to": "tot", + "per_kwh": "per kWh", + "cheap_tip": "laag voor vandaag", + "dear_tip": "hoog voor vandaag", + "estimate_tip": "schatting op basis van gisteren", + "none_tip": "Geen prijs bekend", + "no_prices": {"description": "Geen prijzen voor vandaag, dus de grafiek toont alleen het plan."}, + "list": "Het plan in woorden", + "average_tip": "gemiddelde van het uur" + }, + "peak": {"name": "Piekgrens", "this_month": "Piek van deze maand", "limit": "Grens", "none": "Nog niets gemeten", "unreadable": "Nu niet leesbaar"}, + "attention": {"name": "Vraagt aandacht", "nothing": "Niets om na te kijken", "to_look": "na te kijken", "details": "Details", "alarm": "Alarm", "warning": "Waarschuwing", "info": "Info"}, + "control": {"name": "Regeling", "stop": "Regeling stoppen", "start": "Regeling starten", "maint_start": "Nu een batterijcyclus starten", "maint_abort": "Batterijcyclus stoppen", "docs": "Documentatie van de add-on", "more": "Meer acties"}, + "details": {"name": "Details voor installateurs", "rows": "Statusregels", "checks": "Controles", "event": "Laatste gebeurtenis"}, + "dialog": { + "cancel": "Annuleren", + "stop": {"name": "Regeling stoppen?", "description": "Elke omvormer gaat naar 0 W tot u de regeling opnieuw start.", "yes": "Regeling stoppen"}, + "start": {"name": "Regeling starten?", "description": "De add-on regelt de batterijen weer en heft een veiligheidsstop op.", "yes": "Regeling starten"}, + "maint_start": {"name": "Batterijcyclus starten?", "description": "De batterij loopt leeg, laadt weer op en blijft vol, wat enkele uren duurt.", "yes": "Cyclus starten"}, + "maint_abort": {"name": "Batterijcyclus stoppen?", "description": "Elke omvormer gaat even naar 0 W, daarna gaat de regeling verder.", "yes": "Cyclus stoppen"} + }, + "toast": {"started": "Regeling gestart.", "stopped": "Regeling gestopt.", "done": "Klaar.", "failed": "Dat lukte niet. Probeer opnieuw."}, + "offline": {"name": "Add-on niet bereikbaar", "description": "De pagina probeert het elke 3 seconden opnieuw."}, + "setup_only": {"name": "Installatie: nog niets wordt geregeld", "description": "Er gaat niets naar een omvormer tot de installatie bewaard is en de add-on herstart.", "control": "De regeling start na de installatie.", "open": "Installatie openen"}, + "batteries": {"name": "Batterijen", "description": "Batterijmodi en aan- en uitschakelaars komen in een latere update.", "level": "Laadniveau", "now": "Nu", "stored": "Opgeslagen", "mode": "Modus", "settings": "Instellingen van omvormers wijzigen"}, + "settings": {"name": "Instellingen", "description": "De instellingen staan hieronder per taak.", "open": "Instellingen openen"} + }, + "choices_later": {"region": {"wallonia": "Wallonië, nog geen standaardwaarde", "brussels": "Brussel, nog geen standaardwaarde"}}, + "choice_help": { + "meter_source": { + "off": {"description": "Een Home Assistant-entiteit met het netvermogen in W, positief als u van het net afneemt."}, + "ha_dsmr": {"description": "Twee Home Assistant-entiteiten van de DSMR-integratie, een voor afname en een voor injectie."}, + "mqtt_p1": {"description": "De meetwaarden komen via MQTT binnen op een topic dat u opgeeft."}, + "ha_signed": {"description": "Eén Home Assistant-entiteit met het nettovermogen, positief bij afname."}, + "homewizard_local": {"description": "De add-on leest een HomeWizard-meter op uw netwerk en merkt een vastgelopen meter op."} + } + }, + "settings": { + "name": "Instellingen", + "description": "Elke instelling, per taak, en de eenvoudige weergave volgt in een latere update.", + "classic": "Klassieke instellingen", + "search": {"name": "Instelling zoeken", "description": "Zoek een instelling, bijvoorbeeld piek of meter."}, + "no_match": {"description": "Geen instelling past bij uw zoekopdracht."}, + "loading": "Instellingen laden", + "load_failed": {"name": "Instellingen niet leesbaar", "description": "De add-on kon zijn bewaarde instellingen niet lezen, dus gebruik Klassieke instellingen of het tabblad Configuratie."}, + "footer": {"description": "Elke wijziging gaat door de startcontroles van de add-on voor ze bewaard wordt."}, + "to_fix": "op te lossen", + "to_check": "na te kijken", + "changed": "gewijzigd", + "on": "Aan", + "off": "Uit", + "not_set": "Niet ingesteld", + "locked": "Vergrendeld", + "change": "Wijzigen", + "support": {"description": "Deze zijn gemeten op echte hardware, dus wijzig ze alleen als support erom vraagt."}, + "picker": {"choose": "Kies een entiteit", "search": {"description": "Zoek op naam of entiteit-id."}, "all": "Alle entiteiten tonen", "use": "Deze entiteit-id gebruiken", "clear": "Wissen", "missing": "Niet in Home Assistant", "none": {"description": "Niets gevonden, dus kijk de entiteit na in Ontwikkelhulpmiddelen."}}, + "add_inverter": "Omvormer toevoegen", + "inverter": "Omvormer", + "remove": "Verwijderen", + "add_row": "Regel toevoegen", + "add_solar": "Zonne-omvormer toevoegen", + "periods": {"window": "Tijdvak", "from": "Van", "to": "Tot", "days": "Dagen", "price": "Prijs", "add": "Tijdvak toevoegen"}, + "reversed": "Meet negatief", + "phase": "Fase", + "raw_roster": {"description": "Deze lijst met omvormers kan alleen op het tabblad Configuratie wijzigen."}, + "region_year": "cijfers van {year}", + "hour": "{hour}:00 UTC", + "preset": {"description": "Ingevuld door de regio hierboven, dus kies een eigen bedrag om het te wijzigen."}, + "cycle": {"name": "Een cyclus met de hand starten", "description": "Dezelfde acties als op Start, die elk eerst om bevestiging vragen."}, + "savebar": {"label": "Niet bewaarde wijzigingen", "one": "wijziging niet bewaard", "many": "wijzigingen niet bewaard", "discard": "Verwerpen", "save": "Bewaren", "saving": "Bewaren"}, + "saved": {"name": "Bewaard, nog niet actief", "description": "De add-on werkt met de instellingen waarmee hij startte tot u hem herstart."}, + "differs": {"name": "Bewaarde instellingen zijn niet actief", "description": "Sommige bewaarde instellingen verschillen van wat nu draait, dus herstart de add-on om ze toe te passen."}, + "stale": {"name": "Elders gewijzigd", "description": "Deze instellingen zijn elders gewijzigd terwijl u bewerkte, dus bewaar opnieuw om de uwe te houden of verwerp om de andere te laden."}, + "other": "Andere meldingen", + "restart": "Nu herstarten", + "dialog": {"name": "Add-on herstarten?", "description": "Elke omvormer gaat naar 0 W terwijl de add-on herstart, daarna gelden de nieuwe instellingen.", "yes": "Nu herstarten"}, + "toast": {"saved": "Bewaard. Herstart om toe te passen.", "discarded": "Wijzigingen verworpen.", "failed": "Dat lukte niet. Probeer opnieuw.", "blocked": {"description": "Los de rood gemarkeerde instellingen op en bewaar opnieuw."}, "restarting": {"description": "Herstart gevraagd, dus deze pagina antwoordt even niet."}}, + "tier": {"bad": "Oplossen", "warn": "Nakijken", "info": "Opmerking", "ok": "In orde"}, + "derive": { + "raw_roster": {"description": "Deze lijst met omvormers kan alleen op het tabblad Configuratie wijzigen."}, + "no_inverter": {"description": "Voeg minstens één omvormer toe."}, + "flat_named": {"description": "Voeg een tweede omvormer toe voor u deze een naam geeft."}, + "no_source": {"description": "Kies waar de dynamische prijzen vandaan komen."}, + "custom_profile": {"description": "Deze tijdvakken kunnen alleen op het tabblad Configuratie wijzigen."}, + "no_price": {"description": "Vul een prijs per kWh in."}, + "no_periods": {"description": "Voeg minstens één tijdvak toe."}, + "period_time": {"description": "Tijdvak {row}: schrijf elk tijdstip als uren en minuten, zoals 07:00 of 24:00."}, + "period_zero": {"description": "Tijdvak {row} begint en eindigt op hetzelfde uur, dus wijzig een van beide."}, + "period_price": {"description": "Tijdvak {row}: vul een prijs per kWh in."}, + "period_price_range": {"description": "Tijdvak {row}: vul de prijs in euro per kWh in, zoals 0,34."}, + "period_overlap": {"description": "Tijdvakken {a} en {b} vallen allebei op {day} {from} tot {to}, dus wijzig er een."}, + "period_gap": {"description": "Geen tijdvak dekt {day} {from} tot {to}, dus voeg er een toe of maak er een breder."}, + "unknown": {"description": "De pagina kan deze keuze niet bewaren, dus laad de pagina opnieuw."} + }, + "setup": { + "name": "Installatie", + "description": "Voor installateurs: zes stappen naar een werkende installatie, en elke stap kan later wijzigen onder Instellingen.", + "done_before": {"description": "Deze installatie is al ingesteld, dus een wijziging hier vervangt de bewaarde instellingen."}, + "step": "Stap {n} van {total}", + "back": "Terug", + "next": "Volgende", + "skip": "Volgende, of overslaan", + "finish": "Bewaren en herstarten", + "not_now": "Niet nu", + "steps": { + "1": {"name": "Uw meter", "description": "De add-on stuurt de netmeting naar nul, dus eerst is uw meter nodig."}, + "2": {"name": "Omvormers en batterijen", "description": "Eén kaart per omvormer met een batterij, met zijn entiteiten in Home Assistant."}, + "3": {"name": "Zonnepanelen", "description": "Niet verplicht, dus sla deze stap over als de add-on de zonneproductie niet moet bijhouden."}, + "4": {"name": "Prijzen", "description": "Wat u per kWh betaalt, zodat de batterijen laden als stroom goedkoop is."}, + "5": {"name": "Piekgrens", "description": "Het net blijft onder deze grens, gemiddeld over elk kwartier."}, + "6": {"name": "Nakijken en starten", "description": "De add-on kijkt alles na met zijn eigen startcontroles en herstart dan."} + }, + "modes_later": {"description": "Een modus kiezen per batterij komt in een latere update."}, + "kettle": { + "name": "Richting nakijken", + "description": "Lees de meter af, zet een waterkoker aan en lees de meter opnieuw af.", + "read": "Meter aflezen", + "again": "Opnieuw aflezen", + "skip": "Deze test overslaan", + "before": {"description": "De meter geeft nu {w} aan, dus zet een waterkoker aan en druk op Opnieuw aflezen."}, + "unread": {"description": "De meter is nu niet leesbaar, dus kijk de entiteit na en probeer opnieuw."}, + "none": {"description": "De meting veranderde maar {d}, dus zet de waterkoker aan en lees opnieuw af."}, + "ok": {"description": "Goed, de meting steeg met {d} toen de waterkoker aanging."}, + "flip": {"description": "De meting daalde met {d}, dus de add-on keert het teken voor u om."}, + "wrong_signed": {"description": "De meting daalde met {d}, dus kies hierboven “Eén entiteit voor netvermogen”, die het kan omkeren."}, + "wrong_dsmr": {"description": "De meting daalde met {d}, dus kijk na of afname en injectie niet omgewisseld zijn."}, + "self": {"description": "De add-on leest deze meter zelf, dus Start toont de richting na de herstart."}, + "skipped": {"description": "De richting van de meter is niet getest, dus kijk ze na op Start na de herstart."}, + "skipped_wrong": {"description": "Bij de waterkokertest daalde de meting, dus kijk de richting na in stap 1 voor u de regeling start."}, + "skipped_down": {"description": "De meting daalde toen de waterkoker aanging, dus kijk de richting van de meter na voor u de regeling start."}, + "tested": {"description": "De richting van de meter is getest met een waterkoker."}, + "needed": {"description": "Doe eerst de waterkokertest, of sla hem over."} + }, + "check": {"name": "Wat de add-on nakeek", "running": {"description": "Bezig met de startcontroles van de add-on."}, "pass": {"description": "De startcontroles van de add-on zijn in orde."}, "failed": {"description": "De controle liep niet, dus probeer opnieuw."}, "again": "Opnieuw nakijken", "blocked": {"description": "Los de rood gemarkeerde punten op en kijk dan opnieuw na."}}, + "shadow": {"name": "Starten in schaduwmodus", "description": "Aanbevolen, want dan blijft elke omvormer op 0 W tot u de schaduwmodus uitzet onder Instellingen."}, + "dialog": {"name": "Bewaren en herstarten?", "description": "Elke omvormer gaat naar 0 W terwijl de add-on herstart, en de schaduwmodus houdt ze daarna op 0 W.", "yes": "Bewaren en herstarten"}, + "dialog_live": {"name": "Bewaren en herstarten?", "description": "Elke omvormer gaat naar 0 W terwijl de add-on herstart, daarna gelden de nieuwe instellingen.", "yes": "Bewaren en herstarten"}, + "dialog_setup": {"name": "Bewaren en herstarten?", "description": "De add-on herstart met deze instellingen, en de schaduwmodus houdt elke omvormer op 0 W.", "yes": "Bewaren en herstarten"}, + "dialog_setup_live": {"name": "Bewaren en herstarten?", "description": "De add-on herstart met deze instellingen, en dan gelden ze.", "yes": "Bewaren en herstarten"}, + "done": {"name": "Installatie is klaar", "description": "De add-on herstart nu in schaduwmodus, dus open Start over een minuut om te zien wat hij zou doen."}, + "done_live": {"name": "Installatie is klaar", "description": "De add-on herstart nu, dus open Start over een minuut om de regeling te starten."}, + "restart_failed": {"name": "Bewaard, nog niet actief", "description": "De herstart lukte niet, dus druk op Nu herstarten om de instellingen toe te passen."}, + "home": "Start openen" + } + }, + "home_words": { + "mode_house": "Volgt het huis", + "attn_shadow": "Schaduwmodus staat aan", + "attn_shadow_body": "De add-on beslist alles, maar elke omvormer blijft op 0 W.", + "zero_held": "Op 0 W gehouden", + "zero_going": "Gaat naar 0 W", + "verdict": {"held": "Op 0 W gehouden", "stopped": "Gestopt", "cycle": "Vandaag maandelijkse cyclus", "trade": "Handelt op prijs", "house": "Volgt het huis"}, + "pill": {"running": "Actief", "shadow": "Schaduwmodus", "stopped": "Gestopt", "alarm": "Heeft u nu nodig", "warning": "Actief, met een waarschuwing"}, + "banner_sub": {"running": "De batterijen volgen het plan hieronder.", "shadow": "De plannen hieronder tonen wat de add-on zou doen.", "stopped": "Start de regeling hieronder als u klaar bent.", "alarm": "Zie Vraagt aandacht hieronder voor wat u moet doen.", "warning": "Zie Vraagt aandacht hieronder."}, + "tile": {"not_set_up": "Niet ingesteld", "no_reading": "Geen meting", "producing": "Produceert", "not_producing": "Produceert niet", "needs_solar": "Zonnemeting nodig", "not_adding_up": "Metingen kloppen niet samen", "using": "Verbruikt", "taking": "Neemt af van het net", "feeding": "Injecteert", "balanced": "In evenwicht", "giving": "Levert stroom", "charging": "Laadt", "resting": "Rust"}, + "now": { + "no_reading": "Geen meting van deze batterij.", + "would_rest": "{zero}. Zou nu rusten.", + "would_give": "{zero}. Zou nu {kw} leveren.", + "would_charge": "{zero}. Zou nu {kw} laden.", + "held": "{zero} tot het alarm weg is.", + "stopped": "{zero} zolang de regeling gestopt is.", + "cycle_drain": "Maandelijkse cyclus: leegmaken.", + "cycle_charge": "Maandelijkse cyclus: opladen.", + "cycle_hold": "Maandelijkse cyclus: vol houden.", + "cycle": "Maandelijkse cyclus bezig.", + "giving": "Levert nu {kw}.", + "charging": "Laadt nu {kw}.", + "resting": "Rust nu." + }, + "head": { + "held": "Elke omvormer staat op 0 W tot het alarm weg is.", + "held_going": "Elke omvormer gaat naar 0 W tot het alarm weg is.", + "stopped": "De regeling is gestopt, dus er is niets gepland.", + "cycle": "Een batterij doet vandaag zijn maandelijkse cyclus.", + "trade": "Laadt in het goedkoopste uur, levert stroom in het duurste.", + "house": "Laadt met zonne-overschot en dekt het huis.", + "shadow": "Schaduwmodus: dit is wat de add-on zou doen.", + "cycle_would": "Een batterij zou vandaag zijn maandelijkse cyclus doen.", + "trade_would": "Zou laden als het goedkoopst is en leveren als het duurst is.", + "house_would": "Zou laden met zonne-overschot en het huis dekken." + }, + "run": { + "grid_what": "Laadt tot {kwh} van het net.", + "grid_what_would": "Zou tot {kwh} van het net laden.", + "grid_why": "Laagste gepubliceerde prijs, {eur} per kWh.", + "grid_amount": "Kost tot {eur}.", + "give_what": "Levert tot {kwh}, eerst aan het huis.", + "give_what_would": "Zou tot {kwh} leveren, eerst aan het huis.", + "give_why": "Hoogste gepubliceerde prijs, {eur} per kWh.", + "give_amount": "Tot {eur} waard aan die prijs.", + "cycle_start": "Start de maandelijkse batterijcyclus.", + "cycle_start_would": "Zou de maandelijkse batterijcyclus starten.", + "cycle_now": "Doet nu de maandelijkse batterijcyclus.", + "cycle_now_would": "Zou nu de maandelijkse batterijcyclus doen.", + "cycle_why": "Maakt leeg, laadt op en houdt vol, zodat het laadniveau klopt.", + "cycle_why_would": "Zou leegmaken, opladen en vol houden, zodat het laadniveau klopt.", + "cycle_amount_unknown": "Hoe lang hangt af van de batterij.", + "cycle_amount": "Duurt ongeveer {hours} uur.", + "peak_what": "Levert stroom om onder {kw} te blijven.", + "peak_what_would": "Zou stroom leveren om onder {kw} te blijven.", + "peak_why": "De piekgrens gaat voor alles.", + "house_what": "Volgt het huis.", + "house_what_would": "Zou het huis volgen.", + "house_why": "Laadt met zonne-overschot, levert als het huis vraagt.", + "house_why_would": "Zou laden met zonne-overschot, leveren als het huis vraagt.", + "house_amount": "Hoeveel hangt af van de zon en het huis." + }, + "no_trade": { + "not_covered": "Geen handel op prijs: niets meet de kwartierpiek.", + "no_prices": "Nog geen handel op prijs: er zijn geen prijzen binnen.", + "peak": "Nu geen handel op prijs: de piekgrens gaat voor.", + "not_firm": "Nog geen handel op prijs: de prijzen zijn niet gepubliceerd.", + "not_worth": "Vandaag geen handel op prijs. Het prijsverschil is te klein.", + "no_level": "Nu geen handel op prijs: een laadniveau is onbekend." + }, + "tomorrow_trade": {"grid": "Morgen: laadt om {at}, {eur} per kWh.", "grid_would": "Morgen: zou laden om {at}, {eur} per kWh.", "give": "Morgen: levert stroom om {at}, {eur} per kWh.", "give_would": "Morgen: zou stroom leveren om {at}, {eur} per kWh."}, + "cycle_waits": "{name} wacht zijn beurt af voor de maandelijkse cyclus.", + "step_in": "De batterijen springen bij boven {kw}.", + "step_in_would": "De batterijen zouden bijspringen boven {kw}.", + "period": "Dit kwartier gaat richting {kw}.", + "prices": {"now": "Prijs nu {eur} per kWh, alles inbegrepen.", "today": "Vandaag: laagste {lo} om {lo_at}, hoogste {hi} om {hi_at}.", "none": "Geen prijzen voor vandaag."}, + "tomorrow": {"known": "De prijzen van morgen zijn binnen.", "unknown": "De prijzen van morgen komen meestal na 13:00."}, + "region": {"preset": "Heffingen en btw: {region}, cijfers van {year}.", "own": "Heffingen en btw: uw eigen bedrag."}, + "peak_not_covered": "Geen piekgrens: deze meter meet geen kwartieren.", + "control": {"shadow": "Schaduwmodus: elke omvormer blijft op 0 W.", "running": "De regeling is actief.", "stopped": "De regeling is gestopt. Elke omvormer staat op 0 W."}, + "attn": { + "controller": "Regeling is niet actief", + "meter": "Meting van de meter", + "meter_frozen": "Meter staat mogelijk vast", + "freeze_check": "Controle op vastgelopen meter", + "month_peak": "Piek van deze maand", + "peak_guard": "Piekgrens", + "peak_forecast": "Prognose voor de piekgrens", + "sensor": "Metingen van de batterij", + "control": "Regeling van de omvormer", + "power_too_high": "Vermogensvraag te hoog", + "not_keeping_up": "Batterij kan niet volgen", + "write": "Vermogensvraag niet aanvaard", + "direction": "Vermogen de verkeerde kant op", + "site_direction": "Vermogen de verkeerde kant op", + "circulating": "Omvormers werken elkaar tegen", + "delivery": "Een omvormer levert niet", + "estop": "Noodstop", + "pv": "Meting van de zonnepanelen", + "none": "Verbinding met de omvormer" + }, + "months": ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"] + } +} diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index 4eafd2e..0c5b30e 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -23,8 +23,9 @@ CHOICE, ENTITY, ENTITY_LIST, TOGGLE, SEGMENTED, SLIDER = ( "choice", "entity", "entity_list", "toggle", "segmented", "slider") NUMBER, TEXT, SELECT, LOCKED, INVERTER_LIST, SOLAR_LIST = ( "number", "text", "select", "locked", "inverter_list", "solar_list") +PERIOD_LIST = "period_list" # P5: time windows, each with its own price CONTROLS = (CHOICE, ENTITY, ENTITY_LIST, TOGGLE, SEGMENTED, SLIDER, NUMBER, - TEXT, SELECT, LOCKED, INVERTER_LIST, SOLAR_LIST) + TEXT, SELECT, LOCKED, INVERTER_LIST, SOLAR_LIST, PERIOD_LIST) # What an entity picker offers first. `power_w` is a power sensor the add-on # reads as watts with no unit conversion, so validate.py warns on a kW sensor. ENTITY_KINDS = ("power_w", "power", "energy", "pct", "number", "any") @@ -154,6 +155,8 @@ GROUPS = ( show=(("ui.fallback", "==", "daynight"),), wizard=4), Field("ui.night_price", NUMBER, "€/kWh", step=0.01, show=(("ui.fallback", "==", "daynight"),), wizard=4), + Field("ui.periods", PERIOD_LIST, "€/kWh", step=0.01, + show=(("ui.fallback", "==", "custom"),), wizard=4), )), Part("selling", ( # OPT-11: derived from the batteries' selling switches once battery diff --git a/goodwe_controller/app/uimodel.py b/goodwe_controller/app/uimodel.py index ad72b97..332a864 100644 --- a/goodwe_controller/app/uimodel.py +++ b/goodwe_controller/app/uimodel.py @@ -2,8 +2,8 @@ `options_to_ui()` turns the stored blob into what the page edits: always a list of inverter cards, solar rows with a "reads negative" toggle, a contract and -simple prices instead of `static_profile` JSON, and a region preset instead of -the levies figure. `ui_to_options()` turns it back, so the validator and the +simple prices or time windows (P5) instead of `static_profile` JSON, and a +region preset instead of the levies figure. `ui_to_options()` turns it back, so the validator and the Supervisor always see the real blob. The rule that makes the round trip exact: the model carries the stored values @@ -16,12 +16,14 @@ See DECISIONS/UX-13-one-layout-table.md. import copy import json +import re -from .price import FLEMISH_TAXES_COMPONENTS_EUR_KWH -from .static_tariff import ProfileInvalid, parse_static_profile +from .price import FLEMISH_TAXES_COMPONENTS_EUR_KWH, MAX_PLAUSIBLE_EUR_KWH +from .static_tariff import (DAY_NAMES, MINUTES_PER_DAY, Period, ProfileInvalid, + parse_static_profile) __all__ = ["options_to_ui", "ui_to_options", "ui_to_options_partial", - "REGION_PRESETS", + "REGION_PRESETS", "PERIOD_DAYS", "arbitrage_from_batteries", "DeriveError", "COUNT", "GROWN"] @@ -30,9 +32,10 @@ class DeriveError(ValueError): the sentence the page shows (app/ui_text `derive.<code>`), and `field` the page field it is shown beside.""" - def __init__(self, text, code="", field=""): + def __init__(self, text, code="", field="", **values): super().__init__(text) self.code, self.field = code, field + self.values = values # the sentence's {placeholders} (P5) self.keys = () # the option keys the failed derivation writes @@ -213,14 +216,125 @@ def _profile_decode(raw): return "custom", None, None, None +# --- 3b. the time-window editor (UX-13 P5) ---------------------------------- # +# Each row is {"from", "to", "days", "price"} and, when read from a stored +# profile, its "name". `days` is one of these; a profile with any other day set +# is edited in the Configuration tab only (`ui.periods` is None). +PERIOD_DAYS = ("mon-sun", "mon-fri", "sat,sun") + DAY_NAMES +_DAYSETS = {d: frozenset(range(7)) if d == "mon-sun" else + frozenset(range(5)) if d == "mon-fri" else + frozenset((5, 6)) if d == "sat,sun" else + frozenset((DAY_NAMES.index(d),)) for d in PERIOD_DAYS} +_TIME = re.compile(r"^\s*(\d{1,2}):(\d{2})\s*$") + + +def _hhmm(minute) -> str: + return f"{minute // 60:02d}:{minute % 60:02d}" + + +def _periods_decode(raw): + """The rows for a stored profile: [] when unset, None when it cannot be + shown as rows (unparsable, or days the editor has no choice for).""" + try: + prof = parse_static_profile(raw) if isinstance(raw, str) else None + except ProfileInvalid: + return None + if prof is None: + return [] if isinstance(raw, str) else None + rows = [] + for p in prof.periods: + days = next((d for d, s in _DAYSETS.items() if s == p.days), None) + if days is None: + return None + rows.append({"from": _hhmm(p.start_min), "to": _hhmm(p.end_min), + "days": days, "price": p.eur_per_kwh, "name": p.name}) + return rows + + +def _minute(text, *, end): + """"07:00" -> 420, "24:00" -> 1440 as an end, else None.""" + m = _TIME.match(str(text or "")) + if not m: + return None + h, mi = int(m.group(1)), int(m.group(2)) + if mi > 59 or h > 24 or (h == 24 and (mi or not end)): + return None + return h * 60 + mi + + +def _periods_json(rows) -> str: + """The static_profile for the editor's rows, or DeriveError naming the + first problem: a bad time, an empty price, an overlap or a gap.""" + if not rows: + raise DeriveError("add at least one time window", "no_periods", + "ui.periods") + periods = [] + for i, row in enumerate(rows, start=1): + row = row if isinstance(row, dict) else {} + start = _minute(row.get("from"), end=False) + end = _minute(row.get("to"), end=True) + if start is None or end is None: + raise DeriveError(f"window {i} has a bad time", "period_time", + "ui.periods", row=i) + end = end or MINUTES_PER_DAY # "00:00" as an end + if start == end: + raise DeriveError(f"window {i} is empty", "period_zero", + "ui.periods", row=i) + price = _num(row.get("price")) + if price is None: + raise DeriveError(f"window {i} needs a price", "period_price", + "ui.periods", row=i) + if abs(price) > MAX_PLAUSIBLE_EUR_KWH: + raise DeriveError(f"window {i}'s price is out of range", + "period_price_range", "ui.periods", row=i) + if row.get("days") not in _DAYSETS: + raise DeriveError(f"window {i} has no days", "unknown", + "ui.periods") + name = str(row.get("name") or "").strip() or f"window{i}" + periods.append(Period(name=name, start_min=start, end_min=end, + days=_DAYSETS[row["days"]], + eur_per_kwh=price)) + _tiling(periods) + return json.dumps({"periods": [ + {"name": p.name, "from": _hhmm(p.start_min), + "to": _hhmm(p.end_min), "days": row["days"], + "eur_per_kwh": p.eur_per_kwh} + for p, row in zip(periods, rows)]}) + + +def _tiling(periods): + """Each minute of the week in exactly one window, as static_tariff.py + requires. The first overlap or gap, by day and time, is the error.""" + for day in range(7): + start, kind, rows = None, None, None + for minute in range(MINUTES_PER_DAY + 1): + here = [i for i, p in enumerate(periods, start=1) + if minute < MINUTES_PER_DAY and p.covers(day, minute)] + now = ("gap" if not here else "overlap" if len(here) > 1 + else None) if minute < MINUTES_PER_DAY else "end" + if kind is not None and (now != kind or (kind == "overlap" + and here != rows)): + values = {"day": DAY_NAMES[day], "from": _hhmm(start), + "to": _hhmm(minute)} + if kind == "gap": + raise DeriveError("a time has no window", "period_gap", + "ui.periods", **values) + raise DeriveError("two windows cover one time", + "period_overlap", "ui.periods", + a=rows[0], b=rows[1], **values) + if now in ("gap", "overlap") and kind is None: + start, kind, rows = minute, now, here + + def _tariff_decode(o): - kind, fixed, day, night = _profile_decode(o.get("static_profile", "")) + raw = o.get("static_profile", "") + kind, fixed, day, night = _profile_decode(raw) provider = o.get("price_provider") dynamic = not _blank(provider) and provider != "off" return {"ui.contract": "dynamic" if dynamic else kind, "price_provider": provider, "ui.fallback": kind, "ui.fixed_price": fixed, "ui.day_price": day, - "ui.night_price": night} + "ui.night_price": night, "ui.periods": _periods_decode(raw)} def _tariff_encode(m, keep): @@ -243,11 +357,16 @@ def _tariff_encode(m, keep): out["static_profile"] = _daynight_json(_price_of(m, "ui.day_price"), _price_of(m, "ui.night_price")) elif kind == "custom": - if "static_profile" not in keep: + rows = m.get("ui.periods") + if rows is not None: + out["static_profile"] = _periods_json(rows) + elif "static_profile" not in keep: raise DeriveError("odd tariff windows are edited in the " "Configuration tab", "custom_profile", "ui.contract") - out["static_profile"] = keep["static_profile"] + else: + # Days the editor cannot show: kept as stored. + out["static_profile"] = keep["static_profile"] else: raise DeriveError(f"unknown contract {kind!r}", "unknown", "ui.contract") diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py index e4564b2..e91e0b3 100644 --- a/goodwe_controller/app/uipage.py +++ b/goodwe_controller/app/uipage.py @@ -9,26 +9,23 @@ are (DECISIONS/UX-13-one-layout-table.md). """ import copy -import io -import json import os import re from . import uilayout as L +from . import uitext from . import uimodel as U from .configui import help_of, label_of, problems_by_field, split_group from .validate import power_request_entities -UI_TEXT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text", - "en.json") -# A choice the page cannot make, only keep: odd tariff windows (P5 editor). -ONLY_IF_HELD = ("custom",) +# A choice the page cannot make, only keep. None since P5's period editor. +ONLY_IF_HELD = () _TIERS = ("bad", "warn", "info") -def ui_text() -> dict: - with io.open(UI_TEXT, encoding="utf-8") as f: - return json.load(f) +def ui_text(lang="en") -> dict: + """The page words in `lang`, English where Dutch has no key (P5).""" + return copy.deepcopy(uitext.words(lang)) def _roster(): @@ -122,6 +119,10 @@ def _field(fld, schema_ui, translations, lang, T): if hints: out["hints"] = {v: e.get("description", "") for v, e in hints.items()} + if fld.control == L.PERIOD_LIST: + # P5: the day choices of one time window, in the editor's order. + names = T["choices"]["period_days"] + out["days"] = [[d, names.get(d, d)] for d in U.PERIOD_DAYS] if fld.mirror: out["mirror"] = fld.mirror if fld.fills: @@ -145,7 +146,7 @@ def _field(fld, schema_ui, translations, lang, T): def layout(schema_ui, translations, lang="en") -> dict: """Every group, part and field of the Installer view, as the page draws it. Built from the table only: a field the table places is on the page.""" - T = ui_text() + T = ui_text(lang) groups = [] for g in L.GROUPS: parts = [] @@ -220,14 +221,19 @@ def _settle(out: dict, stored: dict | None) -> dict: | {k: v for k, v in out.items() if k not in stored}) -def derive_message(err: U.DeriveError) -> dict: - words = ui_text()["settings"]["derive"] +def derive_message(err: U.DeriveError, lang="en") -> dict: + T = uitext.words(lang) + words = T["settings"]["derive"] text = words.get(err.code, words["unknown"])["description"] + args = dict(getattr(err, "values", None) or {}) + # A time window's day is shown by name (P5 period editor). + if "day" in args: + args["day"] = T["choices"]["period_days"].get(args["day"], args["day"]) return {"field": err.field or None, "card": None, "tier": "bad", - "text": text} + "text": uitext.say(text, **args)} -def derive_messages(errors, problems, notes, model, keys): +def derive_messages(errors, problems, notes, model, keys, lang="en"): """The page's messages when part of the model could not become options: each conversion's own sentence beside its field, then the checks of the rest. A refusal or note about a key the failed conversion writes is left @@ -238,7 +244,7 @@ def derive_messages(errors, problems, notes, model, keys): for t in texts] + list(unanchored) kept = [p for p in problems if p in kept] notes = [n for n in notes if not set(n.keys or ()) & failed] - return ([derive_message(err) for err in errors] + return ([derive_message(err, lang) for err in errors] + anchors(kept, notes, model, keys)) diff --git a/goodwe_controller/app/uitext.py b/goodwe_controller/app/uitext.py new file mode 100644 index 0000000..d6caf53 --- /dev/null +++ b/goodwe_controller/app/uitext.py @@ -0,0 +1,51 @@ +"""UX-13 P5: the page's words, app/ui_text/<lang>.json, in English or Dutch. + +One file per language with the same keys. A key missing from a language falls +back to English, key by key, the way the Supervisor's translations do. +test_ui_text.py holds both files to STYLE.md and to each other. +""" + +import copy +import io +import json +import os + +DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text") +LANGS = ("en", "nl") +_CACHE: dict = {} + + +def lang_of(value) -> str: + """"nl", "nl-BE" or "nl_NL" -> "nl"; anything else -> "en".""" + head = str(value or "").strip().lower().replace("_", "-").split("-")[0] + return head if head in LANGS else "en" + + +def raw(lang: str) -> dict: + """One language file as written, without the English fallback.""" + if lang not in _CACHE: + with io.open(os.path.join(DIR, f"{lang}.json"), encoding="utf-8") as f: + _CACHE[lang] = json.load(f) + return _CACHE[lang] + + +def _merge(base, over): + if not (isinstance(base, dict) and isinstance(over, dict)): + return copy.deepcopy(over) + out = copy.deepcopy(base) + for k, v in over.items(): + out[k] = _merge(base.get(k), v) if k in base else copy.deepcopy(v) + return out + + +def words(lang="en") -> dict: + """Every word in `lang`, English where a key is missing.""" + lang = lang_of(lang) + return raw("en") if lang == "en" else _merge(raw("en"), raw(lang)) + + +def say(template: str, **values) -> str: + """Fill `{name}` placeholders, as settings.js `say()` does.""" + for k, v in values.items(): + template = template.replace("{" + k + "}", str(v)) + return template diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index e21029c..007fbdb 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -43,7 +43,7 @@ from datetime import datetime, timezone from aiohttp import web -from . import messages, selfconfig, uipage +from . import messages, selfconfig, uipage, uitext from .haentities import EntityCache from .homeview import region_of from .validate import config_notes, setup_checks @@ -54,13 +54,12 @@ from .uimodel import DeriveError, options_to_ui _LOG = logging.getLogger("goodwe.web") # UX-13 P1: the page lives in app/static/ as three files - index.html, -# app.css, app.js - plus the page words from app/ui_text/en.json. They are +# app.css, app.js - plus the page words from app/ui_text/<lang>.json (English +# and, since P5, Dutch; the page picks by the browser's language). They are # joined into ONE response here, once, so the page needs no second request # and no route of its own: the route list below is unchanged, and every URL # the page uses stays relative (ingress). No build step, no external file. STATIC = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static") -UI_TEXT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text", - "en.json") def _read(path): @@ -71,7 +70,8 @@ def _read(path): def page() -> str: """The assembled index page. `</` is escaped inside the two inline scripts, so no text in them can close the tag early.""" - ui_text = json.dumps(json.loads(_read(UI_TEXT)), ensure_ascii=False) + ui_text = json.dumps({lang: uitext.raw(lang) for lang in uitext.LANGS}, + ensure_ascii=False) scripts = {} for name in ("app.js", "settings.js"): scripts[name] = _read(os.path.join(STATIC, name)) @@ -129,8 +129,12 @@ def build_app(controller, selfcfg=None) -> web.Application: async def index(_request): return web.Response(text=index_page, content_type="text/html") - async def status(_request): - return web.json_response(controller.status_payload()) + async def status(request): + # UX-13 P5: Home's sentences in the page's language, English or Dutch. + lang = uitext.lang_of(request.query.get("lang")) + if lang == "en": + return web.json_response(controller.status_payload()) + return web.json_response(controller.status_payload(lang=lang)) async def action(request): try: @@ -264,7 +268,9 @@ def build_app(controller, selfcfg=None) -> web.Application: if model is not None: payload["messages"] = ( uipage.derive_messages(errors, problems, notes, model, - _keys_of(options)) if errors + _keys_of(options), + uitext.lang_of(_body.get("lang"))) + if errors else uipage.anchors(problems, notes, model, _keys_of(options))) payload["steps"] = uipage.step_problems(payload["messages"], model) if _body.get("setup"): @@ -316,7 +322,8 @@ def build_app(controller, selfcfg=None) -> web.Application: except DeriveError: model = posted["model"] _opts, errors = uipage.to_options_partial(model, stored_now) - messages_ = [uipage.derive_message(e) for e in errors] + lang = uitext.lang_of(posted.get("lang")) + messages_ = [uipage.derive_message(e, lang) for e in errors] return web.json_response( {"kind": "invalid", "problems": [], "by_key": {}, "unanchored": [], "messages": messages_, diff --git a/goodwe_controller/test_home.py b/goodwe_controller/test_home.py index 2a69591..adfe652 100644 --- a/goodwe_controller/test_home.py +++ b/goodwe_controller/test_home.py @@ -546,12 +546,13 @@ def resolve(path): return node -check("the page is assembled: no placeholder is left and the words parse", +_WORDS = json.loads(PAGE.split('id="ui-text">', 1)[1] + .split("</script>", 1)[0].replace("<\\/", "</")) +check("the page is assembled: no placeholder is left and the words parse, " + "English and Dutch (UX-13 P5)", "/*APP_CSS*/" not in PAGE and "/*APP_JS*/" not in PAGE and "/*UI_TEXT*/" not in PAGE - and json.loads(PAGE.split('id="ui-text">', 1)[1] - .split("</script>", 1)[0].replace("<\\/", "</"))["home"] - == UI) + and _WORDS["en"]["home"] == UI and set(_WORDS) == {"en", "nl"}) check("four tabs with the four hash routes, in a keyboard tablist", re.findall(r'data-hash="(\w+)"', PAGE) == ["home", "batteries", "settings", "setup"] @@ -563,7 +564,7 @@ check(f"no external file and no web font: no URL leaves the add-on " and "<link" not in PAGE and "src=" not in PAGE) _abs = re.findall(r"""(?:fetch\(|href=)["'](/[^"']*)["']""", PAGE) check(f"every fetch and link is relative, for ingress ({_abs})", - not _abs and 'fetch("status"' in JS and 'fetch("action"' in JS) + not _abs and 'fetch("status?lang=' in JS and 'fetch("action"' in JS) _keys = set(re.findall(r'data-t(?:-label)?="([\w.]+)"', PAGE)) | set( re.findall(r'''\bt\("([\w.]+)"\)''', JS)) _missing = sorted(k for k in _keys if not isinstance(resolve(k), str)) @@ -610,6 +611,8 @@ async def _serve(): out["page"] = (r.status, r.content_type, await r.text()) async with s.get(f"http://127.0.0.1:{port}/status") as r: out["status"] = await r.json() + async with s.get(f"http://127.0.0.1:{port}/status?lang=nl-BE") as r: + out["status_nl"] = await r.json() async with s.get(f"http://127.0.0.1:{port}/config/model") as r: out["model"] = await r.json() finally: @@ -618,6 +621,14 @@ async def _serve(): E = asyncio.run(_serve()) +_nl_words = json.load(io.open(os.path.join(HERE, "app", "ui_text", "nl.json"), + encoding="utf-8"))["home_words"] +check("UX-13 P5: /status?lang=nl-BE builds Home in Dutch, and plain /status " + "stays English", + E["status_nl"]["state"]["pill"] in _nl_words["pill"].values() + and E["status_nl"]["control"]["text"] in _nl_words["control"].values() + and E["status"]["state"]["pill"] not in _nl_words["pill"].values() + and set(E["status_nl"]) == set(E["status"])) check("GET / serves the assembled page as HTML", E["page"][0] == 200 and E["page"][1] == "text/html" and E["page"][2] == PAGE) check("GET status over HTTP carries both halves", diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index fe882ca..543bc03 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -47,57 +47,10 @@ def check(name, cond): fails.append(name) -# --- the rule (STYLE.md sections 1 and 4) -------------------------------------- -BANNED = re.compile( - r"\b(?:(?:SAFETY|TARIFF|TEL|CFG|FCST|OPT|UX|HW|FW|WITNESS|PKG|ARCH)-\d+|" - r"integrator|anti-?windup|windup|clamp(?:ed|s)?|i_clamped|saturat\w*|" - r"BUG SIGNAL|latch(?:ed)?|arbiter|allocator|registers?|0x[0-9A-Fa-f]+|" - r"layer [123]|heartbeat|watchdog|telegrams?|ACKs?|CRC|OTA|Modbus|planner|" - r"capaciteitstarief|journalctl|ssh|grep|" - r"\d+\.\d+\.\d+\.\d+|[\w-]+\.(?:py|md|yaml|json|db))\b|§\s?\d", re.I) -ENTITY = re.compile(r"\b(?:sensor|number|binary_sensor|input_\w+|switch|select)" - r"\.[a-z0-9_*]+") -SNAKE = re.compile(r"\b[a-z0-9]+(?:_[a-z0-9]+)+\b") -SHOUT = re.compile(r"\b[A-Z]{2,}[A-Z0-9]*(?:[\s-]+[A-Z]{2,}[A-Z0-9]*)+\b") -PLACEHOLDER = re.compile(r"\{[^{}]*\}|%[-+ #0-9.]*[sdrfgx%]") - - -def words(text): - return [w for w in re.findall(r"\S+", PLACEHOLDER.sub("X", text)) - if re.search(r"[A-Za-z0-9]", w)] - - -def sentences(text): - """Sentence count: a stop followed by a space and a capital, or the end.""" - t = PLACEHOLDER.sub("X", text.strip()) - t = re.sub(r"\b(e\.g|i\.e|etc)\.", "eg", t) - return len([s for s in re.split(r"[.!?](?:\s+|$)", t) if s.strip()]) - - -def title_problems(title): - out = [] - if len(words(title)) > 5: - out.append(f"title over 5 words ({len(words(title))})") - if title.lower().startswith("goodwe"): - out.append("title carries a GoodWe prefix") - if title.rstrip().endswith("."): - out.append("title ends in a full stop") - return out + text_problems(title, keys=False, entities=False) - - -def text_problems(text, *, keys, entities): - t = PLACEHOLDER.sub("X", text) - out = [] - hit = sorted({m.group(0) for m in BANNED.finditer(t)}) - if hit: - out.append("banned: " + ", ".join(hit[:4])) - if not entities and ENTITY.search(t): - out.append("entity id: " + ENTITY.search(t).group(0)) - if not keys and SNAKE.search(ENTITY.sub("", t)): - out.append("option key: " + SNAKE.search(ENTITY.sub("", t)).group(0)) - if SHOUT.search(t): - out.append("capitals: " + SHOUT.search(t).group(0)) - return out +# --- the rule (STYLE.md sections 1 and 4): tools/style_rules.py, shared with +# test_ui_text.py since UX-13 P5. +from style_rules import (BANNED, ENTITY, PLACEHOLDER, SHOUT, SNAKE, # noqa: E402,F401 + sentences, text_problems, title_problems, words) def body_problems(body, severity): @@ -483,10 +436,13 @@ def collect(): if isinstance(v.get("fields"), dict): walk(v["fields"], f"{path}{key}.") walk(tr.get("configuration"), "") - # UX-13: the new page's own words, held to the option texts' rule. + # UX-13: the new page's own words, held to the option texts' rule. Home's + # sentences (`home_words`) are templates, checked rendered in part 8. for f in sorted((APP / "ui_text").glob("*.json")): def walk_ui(node, path): for key, v in node.items(): + if not path and key == "home_words": + continue if isinstance(v, dict): walk_ui(v, f"{path}{key}.") elif isinstance(v, str): @@ -1852,12 +1808,15 @@ def home_problems(kind, text): return out -_home = homeview.text_samples() -_home_bad = [(k, t, p) for k, t in _home for p in [home_problems(k, t)] if p] -for k, t, p in _home_bad: - print(f" {k}: {t!r}: {p}") -check(f"every Home sentence obeys its STYLE limit ({len(_home)} rendered, " - f"{len(_home_bad)} over)", len(_home) > 80 and not _home_bad) +for _lang in ("en", "nl"): # UX-13 P5: Home in English and Dutch + _home = homeview.text_samples(_lang) + _home_bad = [(k, t, p) for k, t in _home for p in [home_problems(k, t)] + if p] + for k, t, p in _home_bad: + print(f" {_lang} {k}: {t!r}: {p}") + check(f"every Home sentence in {_lang} obeys its STYLE limit " + f"({len(_home)} rendered, {len(_home_bad)} over)", + len(_home) > 80 and not _home_bad) _shadowed = [t for k, t in homeview.text_samples() if "ould" in t] check("in shadow mode the Home plan says what the add-on WOULD do: every " "shadow variant of a plan text carries 'would'", diff --git a/goodwe_controller/test_setup.py b/goodwe_controller/test_setup.py index 4de85cf..00f2efe 100644 --- a/goodwe_controller/test_setup.py +++ b/goodwe_controller/test_setup.py @@ -631,6 +631,12 @@ print(f" {len(_all)} blobs from {len(B.starts())} starts; " check(f"every plan from a new install is accepted by the shipped validator " f"({len(_new)} plans)", len(_new) >= 25 and not [n for n, r in _new if r]) +_windows = [(n, b) for n, b, r in _all if "periods" in n and not r] +check(f"UX-13 P5: the time-window plans are among them and write the " + f"windows as typed ({len(_windows)} blobs)", + len(_windows) >= 12 and all( + len(json.loads(b["static_profile"])["periods"]) in (1, 2, 5) + for _n, b in _windows)) _empty = [(n, r) for n, _b, r in _all if n.startswith("empty-")] check(f"every plan from a new install as shipped (no power request entity, " f"setup-only mode) is accepted ({len(_empty)} plans)", diff --git a/goodwe_controller/test_ui_text.py b/goodwe_controller/test_ui_text.py new file mode 100644 index 0000000..beba82d --- /dev/null +++ b/goodwe_controller/test_ui_text.py @@ -0,0 +1,252 @@ +"""UX-13 P5: the page's words, English and Dutch, follow STYLE.md. `python3 test_ui_text.py` + +app/ui_text/en.json and nl.json hold every word the Home, Batteries, Settings +and Setup screens show that is not an option label (those are +translations/*.yaml, test_translations.py) or a status row (app/messages.py, +test_messages.py). This check fails CI and names the offending string when: + +1. the two files differ in keys, or a string's {placeholders} differ; +2. a string breaks STYLE.md: a name or label over 6 words, a description over + 1 sentence of 25 words, any other line over 2 sentences, a semicolon, a + banned or jargon word (English and Dutch lists), an option key or entity id; +3. a string carries its own details (a link, a section number, a file name) + instead of leaving them to the page's DOCS link; +4. Home's sentences, rendered by app/homeview.py in each language, break + the Home rules of test_messages.py part 8 (checked there too); +5. a Dutch string is left in English, outside the short list of words that + are the same in both; +6. the English words that mirror app/messages.py drift from it. +Each rule is shown to catch a spoiled input (habit 1 of MUTATION.md). +""" + +import json +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) + +from style_rules import (PLACEHOLDER, sentences, text_problems, # noqa: E402 + title_problems, words) +from app import homeview, messages, uitext # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def load(lang): + with open(os.path.join(HERE, "app", "ui_text", f"{lang}.json"), + encoding="utf-8") as f: + return json.load(f) + + +EN, NL = load("en"), load("nl") + + +def leaves(node, path=()): + """(path, text) for every string, lists included (the month names).""" + if isinstance(node, dict): + for k, v in node.items(): + yield from leaves(v, path + (k,)) + elif isinstance(node, list): + for i, v in enumerate(node): + yield from leaves(v, path + (i,)) + else: + yield path, node + + +def where(lang, path): + return f"{lang}.json:" + ".".join(str(p) for p in path) + + +# ============================================================================ # +print("1. English and Dutch have the same keys and placeholders") +_en, _nl = dict(leaves(EN)), dict(leaves(NL)) +_only_en = sorted(where("en", p) for p in _en if p not in _nl) +_only_nl = sorted(where("nl", p) for p in _nl if p not in _en) +for x in _only_en + _only_nl: + print(f" MISSING in the other language: {x}") +check(f"every one of the {len(_en)} English strings has a Dutch one, and no " + "Dutch string is extra", not _only_en and not _only_nl and len(_en) > 300) +_holes = sorted( + f"{where('nl', p)}: {sorted(PLACEHOLDER.findall(str(_en[p])))} vs " + f"{sorted(PLACEHOLDER.findall(str(t)))}" + for p, t in _nl.items() if p in _en + and sorted(PLACEHOLDER.findall(str(t))) + != sorted(PLACEHOLDER.findall(str(_en[p])))) +for x in _holes: + print(f" PLACEHOLDERS differ: {x}") +check("every Dutch string fills the same {placeholders} as its English one", + not _holes) + + +# ============================================================================ # +print("\n2. every string follows STYLE.md, in both languages") +# STYLE.md section 4, the "Not" column, plus the Dutch words for the same +# things (translations/nl.yaml keeps "setpoint" in two option names, which the +# page never shows). Matched as whole words, case-insensitive. +JARGON = { + "en": r"controllers?|control loop|setpoints?|SoC|state of charge|BMS|PV|" + r"failsafe|trip(?:ped)?|parked|discharg\w*|P1 feed|quarter-hour|" + r"payload|endpoint|JSON|API|timeout|boolean|config", + "nl": r"setpoints?|SoC|BMS|PV|failsafe|regelaar|regellus|" + r"latch|ontlad\w*|payload|endpoint|JSON|API|time-?out|boolean|" + r"config|kwartuur\w*", +} +JARGON = {k: re.compile(r"\b(?:" + v + r")\b", re.I) for k, v in JARGON.items()} +# Details belong behind the page's DOCS link, never in the string itself. +DETAILS = re.compile(r"https?:|www\.|DOCS|documentation, section|§|" + r"\bsee section\b|\bzie sectie\b", re.I) +NAME_WORDS, DESC_WORDS, LINE_SENTENCES = 6, 25, 2 + + +def kind_of(path): + if path[0] == "home_words": + return "template" # part 4 renders and checks these + return "description" if path[-1] == "description" else "name" + + +def problems(lang, path, text): + kind = kind_of(path) + out = [] + if not isinstance(text, str) or not text.strip(): + return ["empty"] + if kind == "name" and len(words(text)) > NAME_WORDS: + out.append(f"name over {NAME_WORDS} words ({len(words(text))})") + if kind == "name" and sentences(text) > LINE_SENTENCES: + out.append(f"over {LINE_SENTENCES} sentences ({sentences(text)})") + if kind == "description": + if sentences(text) > 1: + out.append(f"description over 1 sentence ({sentences(text)})") + if len(words(text)) > DESC_WORDS: + out.append(f"description over {DESC_WORDS} words " + f"({len(words(text))})") + if ";" in text: + out.append("semicolon") + hit = JARGON[lang].search(PLACEHOLDER.sub("X", text)) + if hit: + out.append(f"jargon: {hit.group(0)!r}") + if DETAILS.search(text): + out.append(f"details belong behind the DOCS link: " + f"{DETAILS.search(text).group(0)!r}") + # The picker's own help names "entity id": the one place it is the word. + ok_entity = path[:2] == ("settings", "picker") + return out + [p for p in text_problems(text, keys=False, entities=False) + if not (ok_entity and p.startswith("entity id"))] + + +_bad = [] +for lang, data in (("en", EN), ("nl", NL)): + for path, text in leaves(data): + for p in problems(lang, path, text): + _bad.append(f"{where(lang, path)}: {p} :: {text!r}") +for x in _bad: + print(f" STYLE {x}") +check(f"every string in en.json and nl.json follows STYLE.md " + f"({len(_en) + len(_nl)} strings, {len(_bad)} breaking it)", not _bad) + + +# ============================================================================ # +print("\n3. the rule catches a spoiled input") +check("a 7-word name is caught", + problems("en", ("fields", "x", "name"), + "One two three four five six seven")) +check("a 2-sentence description is caught", + problems("nl", ("fields", "x", "description"), "Eén zin. Twee zinnen.")) +check("jargon is caught in English and in Dutch", + problems("en", ("x",), "Setpoint sent") and + problems("nl", ("x",), "De SoC is laag")) +check("a link or section in a string is caught", + problems("en", ("x", "description"), + "See https://example.org for the rest.")) +check("a snake_case option key is caught", + problems("nl", ("x",), "Zet peak_cap_w hoger")) + + +# ============================================================================ # +print("\n4. Home's sentences, rendered in each language (as test_messages 8)") +PLAN_WORDS, PLAN_SENTENCES = 12, 2 + + +def home_problems(kind, text): + if "{" in text or "}" in text: + return ["a placeholder was not filled"] + if kind == "title": + return title_problems(text) + out = text_problems(text, keys=False, entities=False) + if kind == "line": + if sentences(text) > 1 or len(words(text)) > 25: + out.append("line over 1 sentence of 25 words") + return out + if sentences(text) > PLAN_SENTENCES: + out.append(f"plan line over {PLAN_SENTENCES} sentences") + out += [f"plan sentence over {PLAN_WORDS} words: {x!r}" + for x in re.split(r"(?<=[.!?])\s+", text) + if len(words(x)) > PLAN_WORDS] + return out + + +for lang in ("en", "nl"): + _samples = homeview.text_samples(lang) + _hb = [f"{lang} {k}: {p} :: {t!r}" for k, t in _samples + for p in home_problems(k, t)] + _hb += [f"{lang}: jargon {JARGON[lang].search(t).group(0)!r} :: {t!r}" + for _k, t in _samples if JARGON[lang].search(t)] + for x in _hb: + print(f" HOME {x}") + check(f"{lang}: every Home sentence follows its rule " + f"({len(_samples)} rendered, {len(_hb)} breaking it)", + len(_samples) > 80 and not _hb) +_en_s = [t for _k, t in homeview.text_samples("en")] +_nl_s = [t for _k, t in homeview.text_samples("nl")] +check("Home in Dutch is not Home in English: most sentences differ, and " + "numbers use a decimal comma", + sum(a != b for a, b in zip(_en_s, _nl_s)) > 0.9 * len(_en_s) + and "2,5 kW" in homeview.text_samples("nl").__repr__() + and "2.5 kW" in _en_s.__repr__()) +check("the language resets after a Dutch build, so English callers stay " + "English", homeview.pill("running") == EN["home_words"]["pill"]["running"]) + + +# ============================================================================ # +print("\n5. no Dutch string is left in English") +# Words that are the same in both, or names. Anything else equal is untranslated. +SAME = {"Meter", "Timing", "Support", "Details", "Alarm", "Info", "per kWh", + "{hour}:00 UTC", "Flanders, Fluvius Antwerpen", "Modus", "Status"} +_same = sorted(f"{where('nl', p)} = {t!r}" for p, t in _nl.items() + if p in _en and t == _en[p] and t not in SAME + and PLACEHOLDER.sub("", t).strip(" .:,")) +for x in _same: + print(f" ENGLISH {x}") +check(f"every Dutch string is Dutch ({len(_same)} still English)", not _same) +check("mutation: an English string in nl.json is caught", + "Save" != NL["settings"]["savebar"]["save"] and "Save" not in SAME) + + +# ============================================================================ # +print("\n6. the words that mirror app/messages.py") +check("the setup-only banner on Home is messages.banner_setup_only()", + EN["home"]["setup_only"]["name"] == messages.banner_setup_only()) +_mirror = {k: (EN["home_words"]["attn"][k], v) + for k, v in homeview.ATTN_FROM_MESSAGES.items()} +_drift = {k: v for k, v in _mirror.items() if v[0] != v[1]} +check(f"five Home titles are the notification's own title ({_drift})", + len(_mirror) == 5 and not _drift) +check("app/uitext.py falls back to English per key and reads nl-BE as nl", + uitext.lang_of("nl-BE") == "nl" and uitext.lang_of("fr") == "en" + and uitext.words("nl")["home"]["tabs"]["home"] + == NL["home"]["tabs"]["home"] + and uitext._merge({"a": {"b": 1, "c": 2}}, {"a": {"b": 3}}) + == {"a": {"b": 3, "c": 2}}) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/test_uimodel.py b/goodwe_controller/test_uimodel.py index 62702d0..7bb32fa 100644 --- a/goodwe_controller/test_uimodel.py +++ b/goodwe_controller/test_uimodel.py @@ -217,6 +217,109 @@ check("the hook answers None while battery modes do not exist", check("so the toggle is stored as the page has it", edit(DEFAULTS, arbitrage_enabled=True)["arbitrage_enabled"] is True) +print("\n7. the time-window editor (UX-13 P5)") + + +def rows(*spec): + return [{"from": a, "to": b, "days": d, "price": p} for a, b, d, p in spec] + + +def periods(r, base=SITE): + return edit(base, ui__contract="custom", ui__fallback="custom", + ui__periods=r) + + +def refused(r): + """(code, values) of the DeriveError the rows give, or None.""" + try: + periods(r) + except U.DeriveError as err: + return err.code, err.values + return None + + +# Five windows the day/night preset cannot say: a weekday peak, a weekday +# night, Saturday split at noon, and Sunday. +_five = rows(("06:30", "21:15", "mon-fri", 0.31), ("21:15", "06:30", "mon-fri", 0.19), + ("00:00", "12:00", "sat", 0.2), ("12:00", "00:00", "sat", 0.25), + ("00:00", "24:00", "sun", 0.18)) +_p5 = periods(_five) +_prof5 = parse_static_profile(_p5["static_profile"]) +check("five odd windows write a profile the tariff parser reads, with every " + "price in place", [p.eur_per_kwh for p in _prof5.periods] + == [0.31, 0.19, 0.2, 0.25, 0.18] and _prof5.periods[3].end_min == 1440) +check("...that the shipped start checks accept, and that reads back as the " + "same rows", not validate_startup_config(_p5) + and U.options_to_ui(_p5)["ui.contract"] == "custom" + and [(r["from"], r["to"], r["days"], r["price"]) + for r in U.options_to_ui(_p5)["ui.periods"]] + == [("06:30", "21:15", "mon-fri", 0.31), ("21:15", "06:30", "mon-fri", 0.19), + ("00:00", "12:00", "sat", 0.2), ("12:00", "24:00", "sat", 0.25), + ("00:00", "24:00", "sun", 0.18)]) +_named = dict(SITE, static_profile=json.dumps({"periods": [ + {"name": "peak", "from": "08:00", "to": "20:00", "days": "mon-sun", + "eur_per_kwh": 0.33}, + {"name": "offpeak", "from": "20:00", "to": "08:00", "days": "mon-sun", + "eur_per_kwh": 0.21}]})) +_rows = U.options_to_ui(_named)["ui.periods"] +_rows[1]["price"] = 0.2 +check("a stored profile's window names are kept when a price changes", + [p.name for p in parse_static_profile(periods(_rows, base=_named) + ["static_profile"]).periods] + == ["peak", "offpeak"]) +check("the day and night preset shows as three rows, so 'Other time windows' " + "starts from what is stored", + [r["days"] for r in U.options_to_ui( + edit(SITE, ui__contract="daynight", ui__day_price=0.3, + ui__night_price=0.2))["ui.periods"]] + == ["mon-fri", "mon-fri", "sat,sun"]) +check("an overlap is named: the two windows, the day and the times", + refused(rows(("07:00", "23:00", "mon-fri", 0.3), + ("22:00", "07:00", "mon-fri", 0.2), + ("00:00", "24:00", "sat,sun", 0.2))) + == ("period_overlap", {"day": "mon", "from": "22:00", "to": "23:00", + "a": 1, "b": 2})) +check("a gap is named: the day and the times", + refused(rows(("07:00", "22:00", "mon-sun", 0.3), + ("22:00", "24:00", "mon-sun", 0.2))) + == ("period_gap", {"day": "mon", "from": "00:00", "to": "07:00"})) +check("a gap on one day only is found on that day", + refused(rows(("00:00", "24:00", "mon-fri", 0.3), + ("00:00", "24:00", "sat", 0.2))) + == ("period_gap", {"day": "sun", "from": "00:00", "to": "24:00"})) +check("bad times are named by window: '7h', '25:00', '07:60', '24:00' as a " + "start", all(refused(rows(("00:00", "24:00", "mon-sun", 0.2), (a, b, "mon", 0.1))) + == ("period_time", {"row": 2}) for a, b in + (("7h", "08:00"), ("25:00", "08:00"), ("07:60", "08:00"), + ("24:00", "08:00"), ("07:00", ""))) + and refused(rows(("7:00", "07:00", "mon-sun", 0.2))) + == ("period_zero", {"row": 1})) +check("an empty price, and a price in cents, are named by window", + refused(rows(("00:00", "24:00", "mon-sun", None))) + == ("period_price", {"row": 1}) + and refused(rows(("00:00", "24:00", "mon-sun", 34))) + == ("period_price_range", {"row": 1})) +check("no windows at all is refused", refused([]) == ("no_periods", {})) +from app import uipage # noqa: E402 +_msg = uipage.derive_message(U.DeriveError("x", "period_overlap", "ui.periods", + day="sat", a=1, b=3, **{ + "from": "06:00", "to": "07:00"})) +_nl = uipage.derive_message(U.DeriveError("x", "period_gap", "ui.periods", + day="sun", **{"from": "00:00", + "to": "07:00"}), "nl") +check(f"the page shows the error beside the editor, with the day by name " + f"({_msg['text']!r}, {_nl['text']!r})", + _msg["field"] == "ui.periods" and "Windows 1 and 3" in _msg["text"] + and "Saturday 06:00 to 07:00" in _msg["text"] + and "zondag 00:00 tot 07:00" in _nl["text"]) +_raw = json.dumps({"periods": [ + {"from": "00:00", "to": "24:00", "days": "mon,wed", "eur_per_kwh": 0.2}, + {"from": "00:00", "to": "24:00", "days": "tue,thu-sun", "eur_per_kwh": 0.3}]}) +check("days the editor has no choice for stay in the Configuration tab, and " + "survive a save", U.options_to_ui(dict(SITE, static_profile=_raw)) + ["ui.periods"] is None and edit(dict(SITE, static_profile=_raw), gain=0.5) + ["static_profile"] == _raw) + print() if fails: print(f"{len(fails)} FAILED") diff --git a/goodwe_controller/tools/style_rules.py b/goodwe_controller/tools/style_rules.py new file mode 100644 index 0000000..2fb29dd --- /dev/null +++ b/goodwe_controller/tools/style_rules.py @@ -0,0 +1,58 @@ +"""STYLE.md sections 1 and 4 as code: the banned words and the counts. + +Shared by test_messages.py (UX-08) and test_ui_text.py (UX-13 P5), so the two +checks cannot drift apart. Moved here unchanged from test_messages.py. +""" + +import re + +BANNED = re.compile( + r"\b(?:(?:SAFETY|TARIFF|TEL|CFG|FCST|OPT|UX|HW|FW|WITNESS|PKG|ARCH)-\d+|" + r"integrator|anti-?windup|windup|clamp(?:ed|s)?|i_clamped|saturat\w*|" + r"BUG SIGNAL|latch(?:ed)?|arbiter|allocator|registers?|0x[0-9A-Fa-f]+|" + r"layer [123]|heartbeat|watchdog|telegrams?|ACKs?|CRC|OTA|Modbus|planner|" + r"capaciteitstarief|journalctl|ssh|grep|" + r"\d+\.\d+\.\d+\.\d+|[\w-]+\.(?:py|md|yaml|json|db))\b|§\s?\d", re.I) +ENTITY = re.compile(r"\b(?:sensor|number|binary_sensor|input_\w+|switch|select)" + r"\.[a-z0-9_*]+") +SNAKE = re.compile(r"\b[a-z0-9]+(?:_[a-z0-9]+)+\b") +SHOUT = re.compile(r"\b[A-Z]{2,}[A-Z0-9]*(?:[\s-]+[A-Z]{2,}[A-Z0-9]*)+\b") +PLACEHOLDER = re.compile(r"\{[^{}]*\}|%[-+ #0-9.]*[sdrfgx%]") + + +def words(text): + return [w for w in re.findall(r"\S+", PLACEHOLDER.sub("X", text)) + if re.search(r"[A-Za-z0-9]", w)] + + +def sentences(text): + """Sentence count: a stop followed by a space and a capital, or the end.""" + t = PLACEHOLDER.sub("X", text.strip()) + t = re.sub(r"\b(e\.g|i\.e|etc)\.", "eg", t) + return len([s for s in re.split(r"[.!?](?:\s+|$)", t) if s.strip()]) + + +def title_problems(title): + out = [] + if len(words(title)) > 5: + out.append(f"title over 5 words ({len(words(title))})") + if title.lower().startswith("goodwe"): + out.append("title carries a GoodWe prefix") + if title.rstrip().endswith("."): + out.append("title ends in a full stop") + return out + text_problems(title, keys=False, entities=False) + + +def text_problems(text, *, keys, entities): + t = PLACEHOLDER.sub("X", text) + out = [] + hit = sorted({m.group(0) for m in BANNED.finditer(t)}) + if hit: + out.append("banned: " + ", ".join(hit[:4])) + if not entities and ENTITY.search(t): + out.append("entity id: " + ENTITY.search(t).group(0)) + if not keys and SNAKE.search(ENTITY.sub("", t)): + out.append("option key: " + SNAKE.search(ENTITY.sub("", t)).group(0)) + if SHOUT.search(t): + out.append("capitals: " + SHOUT.search(t).group(0)) + return out diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py index d430ec9..9b8e0e6 100644 --- a/goodwe_controller/tools/ux13_demo.py +++ b/goodwe_controller/tools/ux13_demo.py @@ -1,7 +1,8 @@ """UX-13: serve the real page and routes over a fixture controller, for a headless browser check. `python3 tools/ux13_demo.py STATE PORT [HOST]` -STATE is running, shadow or alarm. The controller is the shipped `Controller` +STATE is running, shadow, alarm, new (P4) or setup (UX-15's setup-only +mode, P5). The controller is the shipped `Controller` with its readings set by hand (two batteries, solar, today's prices in the mockup's shape, trading on). Nothing here talks to Home Assistant or to an inverter: `/action` changes only this fixture. Used for the P1 render check @@ -35,6 +36,7 @@ from aiohttp import web as aioweb # noqa: E402 from app import homeview, web # noqa: E402 from app.main import Controller # noqa: E402 +from app.setuponly import SetupOnly # noqa: E402 from app.peakguard import PeakDecision # noqa: E402 from app.price import PricePoint, PriceProduct, PriceRead # noqa: E402 from app.static_tariff import TariffPlan # noqa: E402 @@ -203,8 +205,9 @@ class Supervisor: async def info(self): return {"options": json.loads(json.dumps(self.options)), "schema": schema_ui(CONFIG), - "translations": {"en": TL.parse_translation_file( - os.path.join(HERE, "translations", "en.yaml"))}} + "translations": {lang: TL.parse_translation_file( + os.path.join(HERE, "translations", f"{lang}.yaml")) + for lang in ("en", "nl")}} async def write_options(self, options): self.options = json.loads(json.dumps(options)) @@ -255,7 +258,20 @@ def controller(state): return c +class ReadOnlyHass(Hass): + read_only = True # app/setuponly.py serves only on a read-only HA + + async def main(state, port, host="127.0.0.1"): + if state == "setup": + # UX-15's setup-only mode: shipped defaults, nothing controlled. + stored = defaults(CONFIG) + c = SetupOnly(dict(stored), ReadOnlyHass(), Store()) + runner = aioweb.AppRunner(web.build_app(c, Supervisor(stored))) + await runner.setup() + await aioweb.TCPSite(runner, host, port).start() + print(f"serving setup on http://127.0.0.1:{port}/", flush=True) + await asyncio.Event().wait() if state == "new": stored = dict(defaults(CONFIG), setpoint_entity="number.a") store = Store() diff --git a/goodwe_controller/tools/ux13_screenshots.py b/goodwe_controller/tools/ux13_screenshots.py new file mode 100644 index 0000000..6955338 --- /dev/null +++ b/goodwe_controller/tools/ux13_screenshots.py @@ -0,0 +1,96 @@ +"""UX-13 P5: the DOCS screenshots of the new screens, taken from the real page. + +Run by tools/ux13_screenshots.sh, which serves tools/ux13_demo.py fixtures and +runs this inside the Playwright image. Each shot fails the run on a page +error, so a broken screen is never pictured. + + python3 ux13_screenshots.py OUT_DIR # DEMO_<STATE> = the fixture's URL + +The battery-mode screens (P3) are not built, so there is no shot of them: +DOCS.md says so instead of showing a mock-up. +""" + +import os +import sys + +from playwright.sync_api import sync_playwright + +OUT = sys.argv[1] +DESKTOP = {"width": 1000, "height": 900} +PHONE = {"width": 390, "height": 844} + + +def url(state): + return os.environ[f"DEMO_{state.upper()}"] + + +def shot(browser, name, state, route, *, lang="en-GB", size=DESKTOP, + full=True, act=None, only=None): + ctx = browser.new_context(locale=lang, viewport=size, + color_scheme="light", reduced_motion="reduce") + page = ctx.new_page() + errors = [] + page.on("pageerror", lambda e: errors.append(str(e))) + page.goto(url(state) + route) + page.wait_for_load_state("networkidle") + page.wait_for_timeout(1500) # the first /status and checks + if act: + act(page) + page.wait_for_timeout(1500) # the debounced start checks + path = os.path.join(OUT, name + ".png") + if only: + page.locator(only).screenshot(path=path) + else: + page.screenshot(path=path, full_page=full) + ctx.close() + if errors: + raise SystemExit(f"{name}: page errors {errors}") + print(f" {name}.png") + + +def open_tariff(page): + page.locator("details.grp[data-g=tariff] > summary").click() + page.locator("details.grp[data-g=meter] > summary").click() # close it + # The fixture site is on a dynamic contract: its fallback gets windows. + page.get_by_role("radiogroup", name="Price when the feed is down") \ + .get_by_role("radio", name="Other time windows").click() + + +def windows(page, overlap=False): + open_tariff(page) + add = page.get_by_role("button", name="+ Add a time window") + rows = (("07:00", "23:00" if overlap else "22:00", "mon-fri", "0.34"), + ("22:00", "07:00", "mon-fri", "0.26"), + ("00:00", "24:00", "sat,sun", "0.24")) + for i, (a, b, days, price) in enumerate(rows, start=1): + add.click() + page.get_by_label(f"Window {i}, From").fill(a) + page.get_by_label(f"Window {i}, To").fill(b) + page.get_by_label(f"Window {i}, Days").select_option(days) + page.get_by_label(f"Window {i}, Price").fill(price) + page.locator("[data-key='ui.periods']").scroll_into_view_if_needed() + + +def main(): + os.makedirs(OUT, exist_ok=True) + with sync_playwright() as p: + b = p.chromium.launch() + shot(b, "home-running", "running", "#home") + shot(b, "home-running-nl", "running", "#home", lang="nl-BE") + shot(b, "home-shadow", "shadow", "#home") + shot(b, "home-phone", "running", "#home", size=PHONE) + shot(b, "home-setup-only", "setup", "#home", full=False) + shot(b, "settings-installer", "running", "#settings") + shot(b, "settings-installer-nl", "running", "#settings", lang="nl-BE") + tariff = "details.grp[data-g=tariff]" + shot(b, "settings-time-windows", "running", "#settings", + act=windows, only=tariff) + shot(b, "settings-time-windows-overlap", "running", "#settings", + act=lambda page: windows(page, overlap=True), only=tariff) + shot(b, "setup-step-1", "new", "#setup") + shot(b, "setup-step-1-nl", "new", "#setup", lang="nl-BE") + b.close() + + +if __name__ == "__main__": + main() diff --git a/goodwe_controller/tools/ux13_screenshots.sh b/goodwe_controller/tools/ux13_screenshots.sh new file mode 100755 index 0000000..b71ddf0 --- /dev/null +++ b/goodwe_controller/tools/ux13_screenshots.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# UX-13 P5: regenerate the DOCS screenshots in docs/img/ux13/ from the real page. +# +# sh goodwe_controller/tools/ux13_screenshots.sh [OUT_DIR] +# +# Serves tools/ux13_demo.py's fixtures (running, shadow, new, setup) in the CI +# test image, then runs tools/ux13_screenshots.py in the Playwright image on a +# private Docker network (the image has the browsers; the matching Python +# package is installed into the container on each run). Nothing talks to Home Assistant or an inverter. The +# prices and the "now" line follow the clock, so the pictures change a little +# from run to run. Needs Docker and PyPI access; pulls the Playwright image once. +set -eu +HERE=$(cd "$(dirname "$0")/.." && pwd) +OUT=${1:-$HERE/../docs/img/ux13} +PW=mcr.microsoft.com/playwright/python:v1.55.0-noble +NET=ux13-shots-$$ +STATES="running shadow new setup" +mkdir -p "$OUT" +OUT=$(cd "$OUT" && pwd) + +cleanup() { + for s in $STATES; do docker rm -f "$NET-$s" >/dev/null 2>&1 || true; done + docker network rm "$NET" >/dev/null 2>&1 || true +} +trap cleanup EXIT INT TERM + +docker build -q -t goodwe-addon-checks:1 "$HERE/../.gitea/ci" >/dev/null +docker network create "$NET" >/dev/null +ENVS="" +for s in $STATES; do + docker run -d --name "$NET-$s" --network "$NET" -e PYTHONDONTWRITEBYTECODE=1 \ + -v "$HERE:/w:ro" goodwe-addon-checks:1 \ + python3 /w/tools/ux13_demo.py "$s" 8099 0.0.0.0 >/dev/null + ENVS="$ENVS -e DEMO_$(echo "$s" | tr a-z A-Z)=http://$NET-$s:8099/" +done +sleep 3 +# shellcheck disable=SC2086 +docker run --rm --network "$NET" --user "$(id -u):$(id -g)" -e HOME=/tmp \ + $ENVS -v "$HERE/tools:/t:ro" -v "$OUT:/out" "$PW" \ + sh -euc 'pip install -q --disable-pip-version-check --target /tmp/pw \ + playwright==1.55.0 + PYTHONPATH=/tmp/pw python3 /t/ux13_screenshots.py /out' +echo "screenshots in $OUT" diff --git a/goodwe_controller/tools/ux13_wizard_blobs.py b/goodwe_controller/tools/ux13_wizard_blobs.py index d3f7d71..b219b2e 100644 --- a/goodwe_controller/tools/ux13_wizard_blobs.py +++ b/goodwe_controller/tools/ux13_wizard_blobs.py @@ -10,7 +10,8 @@ own validator run over them. The wizard edits the page model one step at a time and saves it through uipage.to_options(), like the Installer view. `blobs()` walks each step's choices (meter source and sign, one to three inverters, solar rows, every -contract and price source, region, peak limit, shadow mode) from a new +contract and price source, time windows (P5), region, peak limit, shadow +mode) from a new install as shipped, one with a power request entity, and the TEST-23 sites, and keeps what the shipped validator accepts, because the wizard saves nothing it refuses. test_setup.py checks the set; `--supervisor` runs it through Supervisor 2026.08.0's `AppOptions` @@ -103,6 +104,29 @@ PRICES = { "csv": {"ui.contract": "dynamic", "price_provider": "manual_csv", "price_csv_path": "/share/prices.csv", "ui.fallback": "fixed", "ui.fixed_price": 0.3}, + # P5: the time-window editor, odd windows the day/night preset cannot say. + "periods": {"ui.contract": "custom", "ui.fallback": "custom", + "ui.periods": [ + {"from": "06:30", "to": "21:15", "days": "mon-fri", + "price": 0.31}, + {"from": "21:15", "to": "06:30", "days": "mon-fri", + "price": 0.19}, + {"from": "00:00", "to": "12:00", "days": "sat", + "price": 0.2}, + {"from": "12:00", "to": "24:00", "days": "sat", + "price": 0.25}, + {"from": "00:00", "to": "24:00", "days": "sun", + "price": 0.18}]}, + "periods_one": {"ui.contract": "custom", "ui.fallback": "custom", + "ui.periods": [{"from": "00:00", "to": "00:00", + "days": "mon-sun", "price": 0.29}]}, + "dynamic_periods": {"ui.contract": "dynamic", + "price_provider": "generic_dayahead", + "ui.fallback": "custom", "ui.periods": [ + {"from": "07:00", "to": "23:00", + "days": "mon-sun", "price": 0.32}, + {"from": "23:00", "to": "07:00", + "days": "mon-sun", "price": 0.21}]}, } REGIONS = {"flanders": {"ui.region": "flanders"}, "own": {"ui.region": "own", "price_taxes_eur_kwh": 0.15}} @@ -139,6 +163,9 @@ def plans(): "shadow": "on"}, {"meter": "mqtt", "roster": "two", "solar": "none", "prices": "formula", "region": "flanders", "peak": "low", + "shadow": "on"}, + {"meter": "dsmr", "roster": "two", "solar": "one", + "prices": "periods", "region": "flanders", "peak": "forecast", "shadow": "on"}): seen.append(plan) return seen -- 2.54.0 From ede01b8a04289fe22f6826cb6a1d137e85c2a11b Mon Sep 17 00:00:00 2001 From: review-agent <noreply@anthropic.com> Date: Mon, 28 Sep 2026 16:54:45 +0200 Subject: [PATCH 065/105] UX-13 P5 review: every STYLE rule has a mutation check, fuller jargon lists, Dutch wording, overlap partner test - test_ui_text.py: key parity, placeholder parity, English-left-in-Dutch, semicolon, 25-word description and 2-sentence line each now fail on a spoiled input (the English-left check was not a real mutation). - Jargon lists now cover the whole 'Not' column of STYLE.md section 4, in English, with the Dutch equivalents. - nl.json: 'gewijzigd worden' where 'wijzigen' read as intransitive, 'Bezig met bewaren' for the saving state, 'Metingen kloppen niet'. - test_uimodel.py: an overlap that changes partners is named piece by piece (a surviving mutant of _tiling's partner check). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/app/ui_text/nl.json | 12 ++--- goodwe_controller/test_ui_text.py | 75 +++++++++++++++++++++------ goodwe_controller/test_uimodel.py | 7 +++ 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index fc616b0..be52870 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -119,12 +119,12 @@ "periods": {"window": "Tijdvak", "from": "Van", "to": "Tot", "days": "Dagen", "price": "Prijs", "add": "Tijdvak toevoegen"}, "reversed": "Meet negatief", "phase": "Fase", - "raw_roster": {"description": "Deze lijst met omvormers kan alleen op het tabblad Configuratie wijzigen."}, + "raw_roster": {"description": "Deze lijst met omvormers kan alleen op het tabblad Configuratie gewijzigd worden."}, "region_year": "cijfers van {year}", "hour": "{hour}:00 UTC", "preset": {"description": "Ingevuld door de regio hierboven, dus kies een eigen bedrag om het te wijzigen."}, "cycle": {"name": "Een cyclus met de hand starten", "description": "Dezelfde acties als op Start, die elk eerst om bevestiging vragen."}, - "savebar": {"label": "Niet bewaarde wijzigingen", "one": "wijziging niet bewaard", "many": "wijzigingen niet bewaard", "discard": "Verwerpen", "save": "Bewaren", "saving": "Bewaren"}, + "savebar": {"label": "Niet bewaarde wijzigingen", "one": "wijziging niet bewaard", "many": "wijzigingen niet bewaard", "discard": "Verwerpen", "save": "Bewaren", "saving": "Bezig met bewaren"}, "saved": {"name": "Bewaard, nog niet actief", "description": "De add-on werkt met de instellingen waarmee hij startte tot u hem herstart."}, "differs": {"name": "Bewaarde instellingen zijn niet actief", "description": "Sommige bewaarde instellingen verschillen van wat nu draait, dus herstart de add-on om ze toe te passen."}, "stale": {"name": "Elders gewijzigd", "description": "Deze instellingen zijn elders gewijzigd terwijl u bewerkte, dus bewaar opnieuw om de uwe te houden of verwerp om de andere te laden."}, @@ -134,11 +134,11 @@ "toast": {"saved": "Bewaard. Herstart om toe te passen.", "discarded": "Wijzigingen verworpen.", "failed": "Dat lukte niet. Probeer opnieuw.", "blocked": {"description": "Los de rood gemarkeerde instellingen op en bewaar opnieuw."}, "restarting": {"description": "Herstart gevraagd, dus deze pagina antwoordt even niet."}}, "tier": {"bad": "Oplossen", "warn": "Nakijken", "info": "Opmerking", "ok": "In orde"}, "derive": { - "raw_roster": {"description": "Deze lijst met omvormers kan alleen op het tabblad Configuratie wijzigen."}, + "raw_roster": {"description": "Deze lijst met omvormers kan alleen op het tabblad Configuratie gewijzigd worden."}, "no_inverter": {"description": "Voeg minstens één omvormer toe."}, "flat_named": {"description": "Voeg een tweede omvormer toe voor u deze een naam geeft."}, "no_source": {"description": "Kies waar de dynamische prijzen vandaan komen."}, - "custom_profile": {"description": "Deze tijdvakken kunnen alleen op het tabblad Configuratie wijzigen."}, + "custom_profile": {"description": "Deze tijdvakken kunnen alleen op het tabblad Configuratie gewijzigd worden."}, "no_price": {"description": "Vul een prijs per kWh in."}, "no_periods": {"description": "Voeg minstens één tijdvak toe."}, "period_time": {"description": "Tijdvak {row}: schrijf elk tijdstip als uren en minuten, zoals 07:00 of 24:00."}, @@ -151,7 +151,7 @@ }, "setup": { "name": "Installatie", - "description": "Voor installateurs: zes stappen naar een werkende installatie, en elke stap kan later wijzigen onder Instellingen.", + "description": "Voor installateurs: zes stappen naar een werkende installatie, en elke stap kan later gewijzigd worden onder Instellingen.", "done_before": {"description": "Deze installatie is al ingesteld, dus een wijziging hier vervangt de bewaarde instellingen."}, "step": "Stap {n} van {total}", "back": "Terug", @@ -209,7 +209,7 @@ "verdict": {"held": "Op 0 W gehouden", "stopped": "Gestopt", "cycle": "Vandaag maandelijkse cyclus", "trade": "Handelt op prijs", "house": "Volgt het huis"}, "pill": {"running": "Actief", "shadow": "Schaduwmodus", "stopped": "Gestopt", "alarm": "Heeft u nu nodig", "warning": "Actief, met een waarschuwing"}, "banner_sub": {"running": "De batterijen volgen het plan hieronder.", "shadow": "De plannen hieronder tonen wat de add-on zou doen.", "stopped": "Start de regeling hieronder als u klaar bent.", "alarm": "Zie Vraagt aandacht hieronder voor wat u moet doen.", "warning": "Zie Vraagt aandacht hieronder."}, - "tile": {"not_set_up": "Niet ingesteld", "no_reading": "Geen meting", "producing": "Produceert", "not_producing": "Produceert niet", "needs_solar": "Zonnemeting nodig", "not_adding_up": "Metingen kloppen niet samen", "using": "Verbruikt", "taking": "Neemt af van het net", "feeding": "Injecteert", "balanced": "In evenwicht", "giving": "Levert stroom", "charging": "Laadt", "resting": "Rust"}, + "tile": {"not_set_up": "Niet ingesteld", "no_reading": "Geen meting", "producing": "Produceert", "not_producing": "Produceert niet", "needs_solar": "Zonnemeting nodig", "not_adding_up": "Metingen kloppen niet", "using": "Verbruikt", "taking": "Neemt af van het net", "feeding": "Injecteert", "balanced": "In evenwicht", "giving": "Levert stroom", "charging": "Laadt", "resting": "Rust"}, "now": { "no_reading": "Geen meting van deze batterij.", "would_rest": "{zero}. Zou nu rusten.", diff --git a/goodwe_controller/test_ui_text.py b/goodwe_controller/test_ui_text.py index beba82d..d23a8cd 100644 --- a/goodwe_controller/test_ui_text.py +++ b/goodwe_controller/test_ui_text.py @@ -68,18 +68,30 @@ def where(lang, path): # ============================================================================ # print("1. English and Dutch have the same keys and placeholders") _en, _nl = dict(leaves(EN)), dict(leaves(NL)) -_only_en = sorted(where("en", p) for p in _en if p not in _nl) -_only_nl = sorted(where("nl", p) for p in _nl if p not in _en) + + +def missing(en, nl): + """The keys only one language has.""" + return (sorted(where("en", p) for p in en if p not in nl), + sorted(where("nl", p) for p in nl if p not in en)) + + +def holes(en, nl): + """The Dutch strings whose {placeholders} differ from the English.""" + return sorted( + f"{where('nl', p)}: {sorted(PLACEHOLDER.findall(str(en[p])))} vs " + f"{sorted(PLACEHOLDER.findall(str(t)))}" + for p, t in nl.items() if p in en + and sorted(PLACEHOLDER.findall(str(t))) + != sorted(PLACEHOLDER.findall(str(en[p])))) + + +_only_en, _only_nl = missing(_en, _nl) for x in _only_en + _only_nl: print(f" MISSING in the other language: {x}") check(f"every one of the {len(_en)} English strings has a Dutch one, and no " "Dutch string is extra", not _only_en and not _only_nl and len(_en) > 300) -_holes = sorted( - f"{where('nl', p)}: {sorted(PLACEHOLDER.findall(str(_en[p])))} vs " - f"{sorted(PLACEHOLDER.findall(str(t)))}" - for p, t in _nl.items() if p in _en - and sorted(PLACEHOLDER.findall(str(t))) - != sorted(PLACEHOLDER.findall(str(_en[p])))) +_holes = holes(_en, _nl) for x in _holes: print(f" PLACEHOLDERS differ: {x}") check("every Dutch string fills the same {placeholders} as its English one", @@ -94,10 +106,14 @@ print("\n2. every string follows STYLE.md, in both languages") JARGON = { "en": r"controllers?|control loop|setpoints?|SoC|state of charge|BMS|PV|" r"failsafe|trip(?:ped)?|parked|discharg\w*|P1 feed|quarter-hour|" - r"payload|endpoint|JSON|API|timeout|boolean|config", - "nl": r"setpoints?|SoC|BMS|PV|failsafe|regelaar|regellus|" - r"latch|ontlad\w*|payload|endpoint|JSON|API|time-?out|boolean|" - r"config|kwartuur\w*", + r"payload|endpoint|JSON|API|timeout|boolean|config|commands?|" + r"charge level|ceiling|billed quarter|quarters?|banked|soft limit|" + r"open block|actuator|ESP32|master|meter source|circulating|" + r"sign disagreement|rail", + "nl": r"setpoints?|setpunt\w*|SoC|laadtoestand|BMS|PV|failsafe|regelaar|" + r"regellus|controller|latch|ontlad\w*|payload|endpoint|JSON|API|" + r"time-?out|boolean|config|kwartuur\w*|commando\w*|geparkeerd|" + r"ESP32|master", } JARGON = {k: re.compile(r"\b(?:" + v + r")\b", re.I) for k, v in JARGON.items()} # Details belong behind the page's DOCS link, never in the string itself. @@ -167,6 +183,22 @@ check("a link or section in a string is caught", "See https://example.org for the rest.")) check("a snake_case option key is caught", problems("nl", ("x",), "Zet peak_cap_w hoger")) +check("a semicolon is caught", + problems("en", ("x",), "Saved; restart to apply")) +check("a 26-word description is caught, and 25 words pass", + problems("en", ("x", "description"), " ".join(["word"] * 26) + ".") + and not problems("en", ("x", "description"), + " ".join(["word"] * 25) + ".")) +check("a 3-sentence line is caught", + problems("en", ("x",), "One. Two. Three.")) +check("a key only one language has is caught, both ways", + missing({("a",): "x", ("b",): "y"}, {("a",): "x"}) == (["en.json:b"], []) + and missing({("a",): "x"}, {("a",): "x", ("c",): "z"}) + == ([], ["nl.json:c"])) +check("a placeholder dropped or renamed in Dutch is caught", + holes({("a",): "Window {row}"}, {("a",): "Tijdvak"}) + and holes({("a",): "{w} now"}, {("a",): "nu {d}"}) + and not holes({("a",): "{a} {b}"}, {("a",): "{b} {a}"})) # ============================================================================ # @@ -219,14 +251,23 @@ print("\n5. no Dutch string is left in English") # Words that are the same in both, or names. Anything else equal is untranslated. SAME = {"Meter", "Timing", "Support", "Details", "Alarm", "Info", "per kWh", "{hour}:00 UTC", "Flanders, Fluvius Antwerpen", "Modus", "Status"} -_same = sorted(f"{where('nl', p)} = {t!r}" for p, t in _nl.items() - if p in _en and t == _en[p] and t not in SAME - and PLACEHOLDER.sub("", t).strip(" .:,")) + + +def english(en, nl): + return sorted(f"{where('nl', p)} = {t!r}" for p, t in nl.items() + if p in en and t == en[p] and t not in SAME + and PLACEHOLDER.sub("", t).strip(" .:,")) + + +_same = english(_en, _nl) for x in _same: print(f" ENGLISH {x}") check(f"every Dutch string is Dutch ({len(_same)} still English)", not _same) -check("mutation: an English string in nl.json is caught", - "Save" != NL["settings"]["savebar"]["save"] and "Save" not in SAME) +_spoiled = dict(_nl) +_spoiled[("settings", "savebar", "save")] = _en[("settings", "savebar", + "save")] +check("mutation: an English string left in nl.json is caught", + english(_en, _spoiled) == ["nl.json:settings.savebar.save = 'Save'"]) # ============================================================================ # diff --git a/goodwe_controller/test_uimodel.py b/goodwe_controller/test_uimodel.py index 7bb32fa..092e1da 100644 --- a/goodwe_controller/test_uimodel.py +++ b/goodwe_controller/test_uimodel.py @@ -283,6 +283,13 @@ check("a gap is named: the day and the times", refused(rows(("07:00", "22:00", "mon-sun", 0.3), ("22:00", "24:00", "mon-sun", 0.2))) == ("period_gap", {"day": "mon", "from": "00:00", "to": "07:00"})) +check("an overlap that changes partners is named piece by piece: windows 1 " + "and 2 first, over their own times only", + refused(rows(("00:00", "24:00", "mon-sun", 0.3), + ("06:00", "08:00", "mon-sun", 0.2), + ("08:00", "10:00", "mon-sun", 0.2))) + == ("period_overlap", {"day": "mon", "from": "06:00", "to": "08:00", + "a": 1, "b": 2})) check("a gap on one day only is found on that day", refused(rows(("00:00", "24:00", "mon-fri", 0.3), ("00:00", "24:00", "sat", 0.2))) -- 2.54.0 From d69fd8fbfd29c4b4b4bfb5c3a1c48849d009d8dd Mon Sep 17 00:00:00 2001 From: Claude dev agent <noreply@anthropic.com> Date: Mon, 28 Sep 2026 18:51:29 +0200 Subject: [PATCH 066/105] OPT-11 P1: per-battery mode limits, on/off, solar order A battery's mode is a soft unit limit (source `mode`, P_MODE 35) kept apart from the hard limits in pre_resolve(). The allocator applies it only while the site target is decided at or below 35 (new Resolution.deciding_priority), so the peak floor releases it and a mode `hi` never meets the site `lo`. At N=1 resolve() applies the same rule to the site target after stage 2. A mode range without 0 W is dropped as a software fault, so REFUSE_SIGN stays unreachable from a mode. compute() gets the loop bound (sum over live units of hard limits with modes applied), so the loop never asks for watts no battery may give and the saturation freeze never parks on them. While charging, Leftover solar weighs 0 so Solar first fills first. Store keys pack_use and pack_mode per battery, set by two new /action values; Off stops and skips maintenance with a log line. Minimal Batteries cards (EN/NL). Off by default (battery_modes_enabled); off, commands are byte-identical to a5dddad at N=1 and N=2 (test_modes.py part 1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 14 + goodwe_controller/DOCS.md | 12 + goodwe_controller/app/allocator.py | 110 ++++- goodwe_controller/app/arbiter.py | 106 +++- goodwe_controller/app/control.py | 46 ++ goodwe_controller/app/homeview.py | 21 +- goodwe_controller/app/main.py | 202 +++++++- goodwe_controller/app/messages.py | 17 + goodwe_controller/app/packmode.py | 103 ++++ goodwe_controller/app/static/app.js | 37 +- goodwe_controller/app/static/index.html | 2 +- goodwe_controller/app/ui_text/en.json | 11 +- goodwe_controller/app/ui_text/nl.json | 11 +- goodwe_controller/app/uilayout.py | 3 + goodwe_controller/app/web.py | 19 +- goodwe_controller/config.yaml | 6 + goodwe_controller/test_alloc.py | 127 +++++ goodwe_controller/test_arbiter.py | 162 +++++- goodwe_controller/test_control.py | 112 +++++ goodwe_controller/test_modes.py | 463 ++++++++++++++++++ goodwe_controller/test_peakguard.py | 41 +- goodwe_controller/tools/alloc_sim.py | 94 +++- goodwe_controller/tools/opt11_identity.py | 212 ++++++++ goodwe_controller/translations/en.yaml | 3 + goodwe_controller/translations/nl.yaml | 3 + 25 files changed, 1873 insertions(+), 64 deletions(-) create mode 100644 goodwe_controller/DECISIONS/OPT-11-battery-modes.md create mode 100644 goodwe_controller/app/packmode.py create mode 100644 goodwe_controller/test_modes.py create mode 100644 goodwe_controller/tools/opt11_identity.py diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md new file mode 100644 index 0000000..d996e48 --- /dev/null +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -0,0 +1,14 @@ +# OPT-11 - battery modes, per battery + +A battery's mode (on/off, Solar first, Leftover solar) is a soft unit limit at +`P_MODE` = 35 that always holds 0 W, applies only while the site target is +decided at or below 35, and is released by anything above it, such as the peak +guard. Design and owner answers: `goodwe-session/OPT-11-design.md` (2026-09-27); +P1 is its section 6 P1, and the pull request lists what was measured. + +- Off by default (`battery_modes_enabled`); off, commands are byte-identical to + a5dddad (`test_modes.py` part 1). +- Off is a mode range, so the peak guard can still use an Off battery (design + sections 2-3). Whether Off should be absolute is an open owner question. +- In P1 only Off closes a direction; Leftover solar differs by charging last. + Price runs, selling (`pack_sell`, reserved) and the forecast are P3/P4. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 72bb441..a23e7ce 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -183,6 +183,7 @@ The label and description each setting shows on the Configuration tab, in tab or | Hardware · Inverter list | Battery power sign is reversed (optional) | `inverters.batt_invert` | Switch this on if this inverter's sensor shows giving power as a negative number. | | Hardware · Inverter list | Usable battery capacity (kWh) (optional) | `inverters.capacity_kwh` | This battery's usable capacity from its datasheet. Fill it in on every inverter or on none. The add-on then shares the work by the energy each battery has left. | | Hardware | RS485 emergency stop is fitted | `estop_fitted` | Switch this on if the emergency stop is installed. It only changes a warning on the status page. | +| Hardware | Battery modes | `battery_modes_enabled` | Give each battery an on and off switch and a mode, set on the Batteries screen. | | Hardware | Solar production entity (W) | `pv_entity` | Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control. | | Hardware | Solar production entities, per inverter (W) | `pv_entities` | Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded. | | Hardware | Reversed-sign solar entities | `pv_invert_entities` | Optional. Add each solar entity above that reads negative while producing, spelled the same way. Its sign is flipped before adding up. | @@ -512,6 +513,17 @@ two of a thing there is one of, and `P1 sample age` is a safety input. Same for status, the maintenance phase, the capacity-tariff peak and the three loop rows below. +### Battery modes (`battery_modes_enabled`) + +Off by default. Turn it on, restart the add-on, and the Batteries screen gives each battery two controls. They apply at once, with no restart. + +- **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, like every battery. +- **Mode.** *Solar first* charges from spare solar before the other batteries. *Leftover solar* charges from the solar they cannot take. Both cover the house at any hour. Charging from the grid in cheap hours, and selling, come in a later update. + +The peak limit, the safety stops and the monthly cycle always come before a battery's mode. + +*For installers:* a mode is a limit at priority 35, kept apart from the hard limits, and released whenever a claim above it (the peak guard) decides the site target. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. + ### Reading the grid-following loop: `Loop integrator`, `Loop integrator lead`, `Loop reason` The control law is a bounded integrator: an accumulator that is **not** the diff --git a/goodwe_controller/app/allocator.py b/goodwe_controller/app/allocator.py index 38872a2..b4bce23 100644 --- a/goodwe_controller/app/allocator.py +++ b/goodwe_controller/app/allocator.py @@ -98,6 +98,12 @@ DROP_STALE = "stale link" DROP_CONTRADICTION = "contradicts itself" DROP_NO_INTEGER = "no integer setpoint in its interval" +# OPT-11: why a unit's MODE layer was not applied this tick. Only the first is +# a fault; the other two are the rule working. +MODE_FAULT = "mode range leaves out 0 W" +MODE_RELEASED = "mode released by a higher claim" +MODE_OUTRANKED = "hard limit leaves no room for the mode" + REFUSE_SCOPE = "mis-routed claim" REFUSE_EMPTY = "no unit available" REFUSE_SIGN = "opposite directions" @@ -213,6 +219,10 @@ class Allocation: # that calls `plan()` for its arithmetic gets None and does not care; # main.py stamps every record it puts on the write path. tick: int | None = None + # OPT-11: ((unit, why), ...) for each unit whose mode range left out 0 W + # this tick. That mode was dropped (see `unit_interval()`); main.py logs it + # as a software fault. Empty on every tick without a mode. + mode_faults: tuple = () @property def ok(self) -> bool: @@ -290,6 +300,87 @@ class Allocation: return out +def unit_interval(b, deciding_priority=None): + """OPT-11. `(lo, hi, note)`: the interval a unit is allocated into. + + The hard limits (`b.lo`, `b.hi`) always apply. The unit's MODE range + (`b.mode_lo`, `b.mode_hi`) narrows them only when the site target was + decided at or below the mode's own priority - `deciding_priority` None + means no higher claim was named, so the mode applies. `note` says why the + mode did not apply, or is None when it did or there is none: + + * MODE_FAULT: the mode range leaves out 0 W. A mode may forbid a direction + and never force one, so this is a software fault and the mode is dropped. + It is what keeps REFUSE_SIGN unreachable from a mode: the fill below + moves every free unit away from 0 in ONE direction, and it starts from 0 + only while every interval holds 0. + * MODE_RELEASED: a higher claim (the peak floor) decided the target. + * MODE_OUTRANKED: the hard limits and the mode do not overlap. The hard + limits win, as they always do. + + A unit without mode fields (`mode_priority` absent or None) gets its hard + limits, unchanged: that is every unit when battery modes are off. + """ + lo, hi = b.lo, b.hi + prio = getattr(b, "mode_priority", None) + if prio is None: + return lo, hi, None + mlo, mhi = b.mode_lo, b.mode_hi + if not (mlo <= 0.0 <= mhi): + return lo, hi, MODE_FAULT + if deciding_priority is not None and deciding_priority > prio: + return lo, hi, MODE_RELEASED + nlo, nhi = max(lo, mlo), min(hi, mhi) + if nlo > nhi: + return lo, hi, MODE_OUTRANKED + return nlo, nhi, None + + +class _Narrowed: + """A unit's bounds with its interval replaced by `unit_interval()`'s.""" + __slots__ = ("lo", "hi") + + def __init__(self, lo, hi): + self.lo, self.hi = lo, hi + + +def loop_bound(bounds, live=None): + """OPT-11. `(lo, hi)`: what the units can place when the LOOP decides. + + The sum, over live units that do not contradict themselves, of each unit's + interval with its mode applied (`unit_interval()` with no higher claim). A + pinned unit adds the span from 0 to its pin, so a probe or a maintenance + pin stays reachable. Every term holds 0, so the sum does too. + + `compute()` keeps the site target inside this, so the loop never asks for + watts no battery may give: the allocator would report them as unmet and the + saturation freeze would park the target on them (SAFETY-73 section 1). + Pure, like `plan()`: it reads numbers and intervals and nothing else. + """ + lo_sum, hi_sum = 0.0, 0.0 + for u in sorted(bounds): + b = bounds[u] + if live is not None and u not in live: + continue + if getattr(b, "contradiction", False): + continue + pv = getattr(b, "pinned_w", None) + if getattr(b, "gate", None) is not None and pv is not None: + lo, hi = _int_envelope(b) + p = float(pv) if lo > hi else float(_clamp_int(round(float(pv)), + lo, hi)) + lo_sum += min(0.0, p) + hi_sum += max(0.0, p) + continue + lo, hi, _ = unit_interval(b) + lo, hi = _int_envelope(_Narrowed(lo, hi)) + if lo > hi: + continue + lo_sum += min(0.0, lo) + hi_sum += max(0.0, hi) + return lo_sum, hi_sum + + def _int_envelope(b): """A unit's interval, narrowed to the integers a 1 W register can hold. @@ -385,7 +476,8 @@ def _fill(order, weights, cap, amount): def plan(target_w, bounds, *, weights=None, live=None, scope_errors=(), - site_priority=None, site_key="site", tick=None) -> Allocation: + site_priority=None, site_key="site", tick=None, + deciding_priority=None) -> Allocation: """Divide the site grid target `target_w` across the units in `bounds`. `bounds` unit name -> that unit's interval for THIS TICK (arbiter stage 1, @@ -411,6 +503,9 @@ def plan(target_w, bounds, *, weights=None, live=None, scope_errors=(), `site_priority` the priority of the SITE claim that chose `target_w`. It is what a unit's own winning SET is weighed against - see PINS. `site_key` the name to use when there are no units at all. + `deciding_priority` OPT-11: the priority that decided `target_w` + (`Resolution.deciding_priority`). Each unit's mode range applies + only at or below it - see `unit_interval()`. None applies them. `tick` an opaque token identifying the tick this record is FOR, handed straight back on the record. SAFETY-28's write gate compares it against the tick it is writing on, so that a record cannot be @@ -497,6 +592,7 @@ def plan(target_w, bounds, *, weights=None, live=None, scope_errors=(), dropped = [] ilo, ihi = {}, {} considered = [] + mode_faults = [] for u in units: b = bounds[u] if live is not None and u not in live: @@ -512,7 +608,12 @@ def plan(target_w, bounds, *, weights=None, live=None, scope_errors=(), # has no interval to allocate into. dropped.append((u, DROP_CONTRADICTION)) continue - lo, hi = _int_envelope(b) + # OPT-11: the mode layer, when it applies, narrows the hard limits. + # A unit with no mode gets exactly its hard limits, as before. + nlo, nhi, note = unit_interval(b, deciding_priority) + if note == MODE_FAULT: + mode_faults.append((u, MODE_FAULT)) + lo, hi = _int_envelope(_Narrowed(nlo, nhi)) if lo > hi: # An interval that contains no integer. The register is 1 W, so # there is no number this unit could be commanded that both bounds @@ -526,7 +627,7 @@ def plan(target_w, bounds, *, weights=None, live=None, scope_errors=(), return Allocation( target_w=float(target_w), sum_w=sum_w, shares={}, plans=(), dropped=tuple(dropped), unmet_w=sum_w, quantisation_w=quant, - refused=why, tick=tick) + refused=why, tick=tick, mode_faults=tuple(mode_faults)) # --- REFUSAL 2: nobody is available ------------------------------------ if not considered: @@ -659,4 +760,5 @@ def plan(target_w, bounds, *, weights=None, live=None, scope_errors=(), return Allocation(target_w=float(target_w), sum_w=sum_w, shares=shares, plans=tuple(plans), dropped=tuple(dropped), - unmet_w=int(unmet), quantisation_w=quant, tick=tick) + unmet_w=int(unmet), quantisation_w=quant, tick=tick, + mode_faults=tuple(mode_faults)) diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index ab5b36d..4eda428 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -86,8 +86,17 @@ P_MAINT_SHAPE = 40 # maintenance shaping the loop (charge-only) # because trading against the meter is the entire point - the grid-following # loop would otherwise cancel every charge the moment it created import. P_ARBITRAGE = 30 # price arbitrage - trades against the meter on purpose +# OPT-11. A battery's mode (Solar first, Leftover solar, Off): a SOFT unit +# limit, kept apart from the hard ones and applied only while the site target +# is decided at or below this priority. Above arbitrage, so a trade stays inside +# each battery's mode; below the peak guard, which releases every mode. +# DECISIONS/OPT-11-battery-modes.md. +P_MODE = 35 P_LOOP = 10 # ordinary grid-following +# The one source filed at P_MODE. pre_resolve() keeps it out of the hard limits. +MODE_SOURCE = "mode" + SET = "set" LIMIT = "limit" @@ -238,6 +247,13 @@ CLAIM_SCOPE = { # this pack to its floor, charge this pack to full, recalibrate this pack's # coulomb counter. Two packs recalibrate on their own schedules. "maintenance": SCOPE_UNIT, + # main.py: `Claim.limit("mode", P_MODE, lo, hi, ...)`, OPT-11. THIS + # battery's mode, chosen per battery by its owner. A unit claim that never + # enters a `lo > hi` test with a site limit: stage 1 keeps it apart from the + # hard limits, and stage 3 applies it only when the site target was decided + # at or below P_MODE. At N=1 it routes to the site like every source, and + # `resolve()` takes it out of stage 2 for the same reason. + "mode": SCOPE_UNIT, } @@ -365,6 +381,13 @@ class UnitBounds: pinned_w: float | None = None pinned_by: str | None = None contradiction: bool = False + # OPT-11: the mode layer, APART from `lo`/`hi` above, which stay the hard + # limits. `mode_priority` is None when no mode claim applies. Whether the + # mode binds is decided at stage 3 (`allocator.unit_interval()`), because it + # depends on the priority that decided the SITE target. + mode_lo: float = -inf + mode_hi: float = inf + mode_priority: int | None = None def explain(self) -> str: if self.contradiction: @@ -410,6 +433,14 @@ class Resolution: # rules drifting apart: this is set by the same line that picks the winner # `explain()` names. winner_priority: int | None = None + # OPT-11. The higher of the winning set's priority and the priority of the + # limit that bound `target_w`. Stage 3 applies each unit's mode only when + # this is at or below that mode's priority (P_MODE), so a peak floor that + # binds S (P_PEAK) releases every mode and never meets a mode `hi`. + deciding_priority: int | None = None + # OPT-11 at N=1: why the site's mode layer was dropped this tick, or None. + # At N>1 the same fact is on `allocation.mode_faults`, per unit. + mode_fault: str | None = None def explain(self) -> str: """One line an operator can act on - this is the point of the module.""" @@ -433,7 +464,8 @@ def pre_resolve(unit_claims: list) -> UnitBounds: of the fault this card removes, and the reason `resolve()` partitions rather than filters twice. """ - sets = sorted((c for c in unit_claims if c.kind == SET), + sets = sorted((c for c in unit_claims + if c.kind == SET and c.source != MODE_SOURCE), key=lambda c: c.priority, reverse=True) gate = pinned_w = pinned_by = None if sets: @@ -441,19 +473,30 @@ def pre_resolve(unit_claims: list) -> UnitBounds: lo, hi = -inf, inf lo_src = hi_src = None + # OPT-11: a mode claim never joins the hard limits, so a mode cannot make a + # unit contradict itself or narrow a pin. A mode SET is not a thing: only + # limits are read. The lowest mode priority is kept (the first to release). + mode_lo, mode_hi, mode_priority = -inf, inf, None for c in unit_claims: if c.kind != LIMIT or (gate is not None and c.priority < gate): continue + if c.source == MODE_SOURCE: + mode_lo, mode_hi = max(mode_lo, c.lo), min(mode_hi, c.hi) + mode_priority = (c.priority if mode_priority is None + else min(mode_priority, c.priority)) + continue if c.lo > lo: lo, lo_src = c.lo, c.source if c.hi < hi: hi, hi_src = c.hi, c.source return UnitBounds(lo, hi, lo_src, hi_src, gate, pinned_w, pinned_by, - contradiction=lo > hi) + contradiction=lo > hi, mode_lo=mode_lo, mode_hi=mode_hi, + mode_priority=mode_priority) def allocate(target_w: float, bounds: dict, *, weights=None, live=None, - scope_errors=(), site_priority=None) -> tuple: + scope_errors=(), site_priority=None, + deciding_priority=None) -> tuple: """STAGE 3. THE SEAM, AND SINCE ALLOC-01 IT IS OCCUPIED. `(shares, allocated)`. ⚠️ THE ALLOCATOR ITSELF IS `app/allocator.py` AND THE REASONING LIVES THERE. @@ -491,11 +534,13 @@ def allocate(target_w: float, bounds: dict, *, weights=None, live=None, """ return allocate_record(target_w, bounds, weights=weights, live=live, scope_errors=scope_errors, - site_priority=site_priority)[:2] + site_priority=site_priority, + deciding_priority=deciding_priority)[:2] def allocate_record(target_w: float, bounds: dict, *, weights=None, live=None, - scope_errors=(), site_priority=None, tick=None) -> tuple: + scope_errors=(), site_priority=None, tick=None, + deciding_priority=None) -> tuple: """`allocate()` plus the record - `(shares, allocated, allocation)`. `tick` is SAFETY-28's freshness token: it identifies the tick the record is @@ -507,7 +552,7 @@ def allocate_record(target_w: float, bounds: dict, *, weights=None, live=None, rec = allocator.plan(target_w, bounds, weights=weights, live=live, scope_errors=scope_errors, site_priority=site_priority, site_key=ACTUATOR_SITE, - tick=tick) + tick=tick, deciding_priority=deciding_priority) return rec.shares, rec.ok, rec @@ -544,19 +589,26 @@ def site_resolve(claims: list) -> Resolution: considered = [f"{c.source}:{c.kind}" for c in claims] if lo > hi: + # OPT-11: 0 W here, and every limit that took part counts as deciding. return Resolution(0.0, winner.source, bound_by=None, contradiction=True, considered=considered, - winner_priority=winner.priority) + winner_priority=winner.priority, + deciding_priority=max(winner.priority, + lo_src.priority, + hi_src.priority)) target = max(lo, min(hi, winner.value)) bound_by = None + deciding = winner.priority if target != winner.value: binder = lo_src if target == lo else hi_src if binder is not None: bound_by = f"{binder.source}({binder.reason})" if binder.reason else binder.source + deciding = max(deciding, binder.priority) return Resolution(float(target), winner.source, bound_by, False, considered, - winner_priority=winner.priority) + winner_priority=winner.priority, + deciding_priority=deciding) def resolve(claims: list, *, units=None, weights=None, live=None, @@ -606,6 +658,12 @@ def resolve(claims: list, *, units=None, weights=None, live=None, written down. """ site_claims = [c for c in claims if c.actuator == ACTUATOR_SITE] + # OPT-11: a mode claim on the site (N=1, where every source routes there) + # never enters stage 2's `lo > hi` test. It is applied after it, below, by + # the same release rule stage 3 uses. + site_modes = [c for c in site_claims if c.source == MODE_SOURCE] + if site_modes: + site_claims = [c for c in site_claims if c.source != MODE_SOURCE] if units is None: units = {c.actuator for c in claims if c.actuator != ACTUATOR_SITE} units = tuple(sorted(units)) @@ -617,6 +675,8 @@ def resolve(claims: list, *, units=None, weights=None, live=None, # STAGE 2 - the site claims become the grid target. At N=1 `site_claims` IS # `claims`, so this is the shipped arbiter on the shipped list. out = site_resolve(site_claims) + if site_modes: + _site_mode(out, site_modes) # STAGE 3 - the seam, and since ALLOC-01 the allocator behind it. # @@ -654,5 +714,33 @@ def resolve(claims: list, *, units=None, weights=None, live=None, out.shares, out.allocated, out.allocation = allocate_record( out.target_w, bounds, weights=weights, live=live, scope_errors=out.scope_errors, site_priority=out.winner_priority, - tick=tick) + tick=tick, deciding_priority=out.deciding_priority) return out + + +def _site_mode(out: Resolution, modes: list) -> None: + """OPT-11 at N=1: the one battery's mode bounds the SITE target, after stage 2. + + The unit rule of `allocator.unit_interval()` on the site: the mode applies + only when stage 2 decided at or below its priority, and a range without 0 W + is a software fault that drops the mode (`out.mode_fault`). A clamp of one + number into a range that holds 0 cannot contradict anything, so the peak + floor still wins by releasing the mode, as at N>1. + """ + out.considered = out.considered + [f"{c.source}:{c.kind}" for c in modes] + lims = [c for c in modes if c.kind == LIMIT] + if not lims or out.contradiction: + return + lo = max(c.lo for c in lims) + hi = min(c.hi for c in lims) + prio = min(c.priority for c in lims) + if not (lo <= 0.0 <= hi): + out.mode_fault = f"mode range [{lo:.0f}, {hi:.0f}] leaves out 0 W" + return + if out.deciding_priority is not None and out.deciding_priority > prio: + return + target = max(lo, min(hi, out.target_w)) + if target != out.target_w: + c = lims[0] + out.bound_by = f"{c.source}({c.reason})" if c.reason else c.source + out.target_w = float(target) diff --git a/goodwe_controller/app/control.py b/goodwe_controller/app/control.py index 89d4ee5..12d1134 100644 --- a/goodwe_controller/app/control.py +++ b/goodwe_controller/app/control.py @@ -293,6 +293,10 @@ REFUSED_BELOW_W = PROBE_ANSWER_W PROBE_EVERY_S = 900.0 PROBE_S = 34.0 +# OPT-11. The loop's reason when the battery modes, not the meter, set the +# command: every battery that may move this way is at its mode's limit. +MODE_BOUND = "mode-bound" + @dataclass(frozen=True) class Tuning: @@ -475,6 +479,7 @@ def compute( i_w: float | None = None, refused: int | None = None, probe: bool = False, + bound: tuple | None = None, ) -> Decision: """One control cycle. A cycle is one meter update (~5 s on a HomeWizard P1). @@ -485,8 +490,16 @@ def compute( `refused` SAFETY-52's carried refused direction, or None to leave it out (the `i_w=None` equivalence path does) `probe` the caller's clock says a refused direction may try PROBE_W now + `bound` OPT-11: `(lo, hi)`, what the batteries may place this tick with + their modes applied (`allocator.loop_bound()`), or None. See + MODE_BOUND below. None is the law as it was. """ reason = "tracking" + # OPT-11: a bound that leaves out 0 W would FORCE a direction, which no + # mode may do. It is dropped rather than obeyed (a software fault, and + # main.py never builds one: every term of `loop_bound()` holds 0). + if bound is not None and not (bound[0] <= 0.0 <= bound[1]): + bound = None # --- saturation, WITH the duration term ------------------------------- # Command and actual diverging means the inverter cannot follow - it is at @@ -589,6 +602,16 @@ def compute( else: i_w = max(moved, i_w) + # OPT-11: the integrator does not wind past what the modes let the + # batteries place. Applied BEFORE the integrator bound below, so a loop + # held by a mode reads as `mode-bound` and not as SAFETY-03's winding into + # the rail (`i_clamped`). That bound still bites where it is the tighter. + if bound is not None: + held = max(float(bound[0]), min(float(bound[1]), i_w)) + if held != i_w: + i_w = held + reason = MODE_BOUND + # ⚠️ Applied EVERY cycle, frozen or not: the freeze is conditional, this # bound is not. It is what makes the worst-case unwind time finite and # knowable instead of a function of how long the error happened to stand. @@ -796,6 +819,22 @@ def compute( target = refused * PROBE_W if probe and wants else 0.0 reason = PROBING if probe and wants else REFUSED + # --- OPT-11: the command stays inside what the modes allow ------------- + # Applied after the slew limit and the freeze, so a mode that closes drops + # the ask at once rather than one slew step per cycle. That moves no + # battery further than the allocator would: it places at most this bound + # when the loop decides. What it removes is the unmet part, which would + # otherwise hold `prev_w` away from `actual_w` and trip the saturation + # freeze on watts no battery was allowed to give. + if bound is not None: + inside = max(float(bound[0]), min(float(bound[1]), target)) + if inside != target: + target = inside + reason = MODE_BOUND + # SAFETY-48's lead cap above may pull the integrator back toward the + # slewed command; what is CARRIED stays inside the bound too. + i_w = max(float(bound[0]), min(float(bound[1]), i_w)) + # --- quantise ---------------------------------------------------------- # 10 W. The register is 1 W and the inverter reports at 1 W, but its # response lands on a coarser ladder (~17.6 W measured at ~900 W, consistent @@ -803,6 +842,13 @@ def compute( # 10 W simply avoids a visible staircase on dashboards. step = max(1, int(tuning.step_w)) target = round(target / step) * step + if bound is not None: + # OPT-11: rounding must not step outside the bound. The bound holds + # 0 W, so one step toward 0 is always inside it. + if target > bound[1]: + target -= step + elif target < bound[0]: + target += step return Decision(float(target), sat_count, frozen, reason, float(i_w), i_clamped, clamped, float(i_bound_w), float(want), diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 1361661..01afa62 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -9,8 +9,9 @@ note, section 3.3. The plan shows only what the add-on does today: trading on price (the arbitrage verdict, the same call the control cycle makes), the monthly battery -cycle, the peak limit and "follows the house". Battery modes (OPT-11) are not -built, so nothing here invents a mode plan. Every sentence is in the words +cycle, the peak limit and "follows the house". OPT-11 P1 adds each battery's +switch and mode to its row; the mode plan arrives with P3/P4, so nothing here +invents one. Every sentence is in the words section at the bottom and is held to STYLE.md by test_messages.py. """ @@ -530,9 +531,17 @@ def battery_rows(c, shadow, running, held=False): running=running, held=held, would_w=shares.get(inv.name), settled=at_zero(inv)), - # Per-battery reasons arrive with battery modes (OPT-11). + # Per-battery reasons arrive with the plan (OPT-11 P3/P4). "why": None, }) + if getattr(c, "modes_on", False): + # OPT-11 P1: the battery's switch and mode, for the Batteries + # screen. Only with battery modes on, so the page is unchanged + # without them. UX-13 P3 builds the real screen on these keys. + pm = c.pack_mode(inv) + rows[-1].update({"use": pm.use, "mode_key": pm.key, + "mode_choice": pm.mode, + "mode": mode_word(pm.key)}) return rows @@ -723,6 +732,11 @@ def mode_house() -> str: return _t("mode_house") +def mode_word(key) -> str: + """OPT-11: a battery's mode, or Off, in the page's language.""" + return _t("modes." + key) + + def attn_shadow() -> str: return _t("attn_shadow") @@ -964,6 +978,7 @@ def _samples() -> list: out = [("title", t) for t in words["verdict"].values()] out += [("title", _t("zero_going")), ("title", _t("zero_held"))] out += [("title", t) for t in words["attn"].values()] + out += [("title", mode_word(k)) for k in words["modes"]] out += [("title", mode_house()), ("title", attn_shadow()), ("line", attn_shadow_body())] for k in ("running", "shadow", "stopped", "alarm", "warning"): diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index d92ceb7..ed80798 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -37,9 +37,11 @@ import aiohttp from . import arbitrage from .arbiter import ( - P_LOOP, P_MAINT_SHAPE, P_MAINTENANCE, P_PEAK, P_SAFETY, - Claim, Resolution, actuator_for, resolve, + P_LOOP, P_MAINT_SHAPE, P_MAINTENANCE, P_MODE, P_PEAK, P_SAFETY, + Claim, Resolution, actuator_for, pre_resolve, resolve, ) +from . import allocator +from . import packmode from . import control as _ctl from .control import Tuning, compute, maintenance_charge_floor, peak_at_risk from .delivery import ( @@ -67,7 +69,8 @@ from .hass import HomeAssistant from .inverter import (LINK_STALE_S, UNIT_A, build_roster, roster_entries, roster_names) from .maintenance import ( - IDLE, POWER_MOVING, MaintConfig, Maintenance, arbitrate as maint_arbitrate, + IDLE, POWER_MOVING, MaintConfig, Maintenance, MaintResult, + arbitrate as maint_arbitrate, ) from .mqtt import (MqttPublisher, announced_units, optional_keys, unit_slugs, unit_state_key) @@ -894,6 +897,13 @@ class Controller: self._peak_saturated = False self._peak_floor_limited = False self._maint_shape_suspended = False + # OPT-11. Battery modes, off by default so an install that has not + # turned them on behaves exactly as before (SAFETY-10 section 1). Each + # battery's mode and on/off switch live in the store, not in options, + # so a change applies at once (`pack_use`, `pack_mode` actions). + self.modes_on = opts.get("battery_modes_enabled") is True + # The units whose mode fault is logged already (edge-logged). + self._mode_faults = set() # [(pack name, why)] for packs that are due and waiting their turn. # Empty at a roster of one, where nothing can defer anything. self._maint_deferred = [] @@ -1953,7 +1963,103 @@ class Controller: that have nothing to do with the allocator, and a weighting held from construction prefers a pack that has since emptied. """ - return packshare.weights(self.pack_energy, target_w) + base = packshare.weights(self.pack_energy, target_w) + if not self.modes_on: + return base + # OPT-11: the solar order. While the site charges, Leftover solar + # batteries weigh 0, so Solar first batteries fill first. A comfort + # choice like the rest of this method: permission is the mode claim. + return packmode.charge_weights(base, self.pack_modes(), target_w) + + def pack_mode(self, inv) -> "packmode.PackMode": + """OPT-11. This battery's on/off switch and mode, read from the store.""" + return packmode.read(getattr(self.store, "data", None) or {}, inv.name) + + def pack_modes(self) -> dict: + return {inv.name: self.pack_mode(inv) for inv in self.inverters} + + def loop_bound(self, claims): + """OPT-11. `(lo, hi)`: what the batteries may place if the loop decides. + + The sum over live units of each unit's hard limits with its mode + applied (`allocator.loop_bound()`), from THIS cycle's unit claims. At + one inverter every claim is on the site, so it is the mode range + itself, or None when no mode is filed (maintenance) or the range + leaves out 0 W (a fault `resolve()` reports). + """ + if len(self.inverters) <= 1: + modes = [c for c in claims if c.source == "mode"] + if not modes: + return None + lo = max(c.lo for c in modes) + hi = min(c.hi for c in modes) + return (lo, hi) if lo <= 0.0 <= hi else None + bounds = {u: pre_resolve([c for c in claims if c.actuator == u]) + for u in self.units} + return allocator.loop_bound(bounds, live=self.live_units()) + + def _mode_fault_log(self, resolution) -> None: + """OPT-11: say once, per battery, that its mode was dropped as a fault. + + A mode range without 0 W would force a direction, which no mode may do, + so it is never applied (allocator.unit_interval()). main.py never + builds one; this is the line that says so if it ever does. + """ + alloc = resolution.allocation + now = {u for u, _ in getattr(alloc, "mode_faults", ())} + if resolution.mode_fault is not None and self.inverters: + now.add(self.inverters[0].name) + for inv in self.inverters: + if inv.name in now and inv.name not in self._mode_faults: + _LOG.error("Battery mode ignored for %s. Software fault " + "MODE_RANGE.", inv.name) + self.log_event(f"battery mode ignored on {inv.name}, a " + f"software fault", hint=messages.hint( + "mode_fault", unit=inv.name)) + self._mode_faults = now + + def _pack_action(self, what, unit, value, now) -> dict: + """OPT-11: switch one battery on or off, or set its mode. + + Store state, not an option, so it applies on the next cycle with no + restart. Written to the action log. Switching a battery off also stops + its maintenance cycle (the owner's 2026-09-27 answer). Refused, with a + plain reason, while battery modes are off or for an unknown battery or + value. + """ + if not self.modes_on: + return {"error": messages.pack_refused("off")} + inv = next((i for i in self.inverters if i.name == unit), None) + if inv is None: + return {"error": messages.pack_refused("unit")} + if what == "pack_use": + if not isinstance(value, bool): + return {"error": messages.pack_refused("value")} + inv.store_set(packmode.USE_KEY, value) + self.log_event(f"{inv.name} switched {'on' if value else 'off'} " + f"by operator", + hint=messages.hint("pack_on" if value + else "pack_off", unit=inv.name)) + if not value: + self._maint_stop_off(self.maints[self.inverters.index(inv)], + now) + else: + if value not in packmode.MODES: + return {"error": messages.pack_refused("value")} + inv.store_set(packmode.MODE_KEY, value) + self.log_event(f"{inv.name} mode set to {value.replace('_', ' ')} " + f"by operator", + hint=messages.hint("pack_mode", unit=inv.name)) + pm = self.pack_mode(inv) + return {"unit": inv.name, "use": pm.use, "mode": pm.mode} + + def _maint_stop_off(self, machine, now) -> None: + """OPT-11: stop this battery's maintenance cycle because it is off.""" + if machine.phase == IDLE: + return + for msg in machine.abort(now, "battery switched off"): + self.log_event(msg, hint=messages.hint("maint_off", + unit=machine.name)) @property def why_words(self) -> str: @@ -2696,9 +2802,27 @@ class Controller: # Calling `tick()` without the answer this produced is the # two-packs-draining-at-once defect with the interlock present but not # wired, which is why the plan is built here and not inside the loop. - maint_plan = maint_arbitrate(self.maints, now) + # OPT-11: a battery switched off starts no cycle and is left out of the + # slot, so it cannot hold the slot from a battery that is on. One that + # is mid-cycle is stopped, with a log line (the owner's 2026-09-27 + # answer). The switch itself stops it at once (`pack_use`); this is + # the same rule for a store that says Off at start-up. + _off = ({inv.name for inv in self.inverters + if not self.pack_mode(inv).use} if self.modes_on else set()) + for inv, machine in zip(self.inverters, self.maints): + if inv.name in _off: + self._maint_stop_off(machine, now) + _on = [m for inv, m in zip(self.inverters, self.maints) + if inv.name not in _off] + _plan_on = iter(maint_arbitrate(_on, now) if _off + else maint_arbitrate(self.maints, now)) + maint_plan = [None if inv.name in _off else next(_plan_on) + for inv, _m in zip(self.inverters, self.maints)] maint_results = [] for inv, machine, blocked in zip(self.inverters, self.maints, maint_plan): + if blocked is None: + maint_results.append(MaintResult(IDLE, False, None, False, [])) + continue res = machine.tick(now, inv.soc, blocked_by=blocked) for msg in res.events: self.log_event(msg, hint=messages.hint("maintenance", @@ -3564,6 +3688,23 @@ class Controller: actuator=self.actuator_of("maintenance", inv))) + # --- OPT-11: each battery's mode, a soft unit limit at P_MODE --------- + # Filed only with battery modes on, and never on a battery in any + # maintenance phase: maintenance at 60/40 outranks the mode. The range + # always holds 0 W (packmode.mode_range()). pre_resolve() keeps it + # apart from the hard limits, and the allocator applies it only while + # the site target is decided at or below P_MODE, so the peak guard's + # site floor (P_PEAK) releases it and never meets it in a `lo > hi`. + if self.modes_on: + for inv, result in zip(self.inverters, maint_results): + if result.phase != IDLE: + continue + pm = self.pack_mode(inv) + lo, hi = packmode.mode_range(pm, inv.max_w) + claims.append(Claim.limit("mode", P_MODE, lo, hi, pm.key, + actuator=self.actuator_of("mode", + inv))) + # --- the grid-following loop ----------------------------------------- # ⚠️ SAFETY-10: `or self.shadow`. The loop is the leg a shadow run most # needs and the one that is switched off by `auto_start: false`, so @@ -3588,6 +3729,28 @@ class Controller: self._unit_refusals() _probing = {inv.name: self._unit_probe(inv) for inv in self.inverters if inv.refused} + # --- SAFETY-73: each refusing unit's own P_SAFETY claim --------------- + # A hard unit limit that always intersects (OPT-11's P_MODE layer sits + # inside it): closed in the refused direction, so the allocator hands + # the share to the others within their own limits. During its probe it + # is a pin at PROBE_W and the others carry the rest. Filed here, before + # the loop, so OPT-11's loop bound sees it. Unit claims only, and still + # the last unit claims filed, so every unit's claim order is as before. + for inv in self.inverters: + if not inv.refused: + continue + if _probing.get(inv.name): + claims.append(Claim.set("refused", P_SAFETY, + inv.refused * _ctl.PROBE_W, + _ctl.PROBING, + actuator=self.actuator_of("refused", + inv))) + else: + claims.append(Claim.limit("refused", P_SAFETY, + *_refused_interval(inv.refused), + _ctl.REFUSED, + actuator=self.actuator_of("refused", + inv))) if (self.auto or self.shadow) and self.inputs_ok: # ⚠️ prev is the ARBITER's last output, not the loop's own last # wish. If something outranked the loop, that is what the hardware @@ -3649,6 +3812,9 @@ class Controller: refused=self.batt_refused if len(self.inverters) == 1 else self._site_refused(), probe=probe, + # OPT-11: None unless battery modes are on, which is the law + # exactly as it was. + bound=self.loop_bound(claims) if self.modes_on else None, ) if decision.frozen and self.sat_count < self.tuning.saturation_cycles: self.log_event(f"saturation freeze ({self.target:.0f} W vs " @@ -3757,26 +3923,6 @@ class Controller: # ability to DELIVER rests on this argument - a weight cannot stop a # unit being commanded and cannot move a failing unit's load to its # sibling. The `pack` claim filed above is the half that constrains. - # --- SAFETY-73: each refusing unit's own P_SAFETY claim --------------- - # A hard unit limit that always intersects (OPT-11's P_MODE layer sits - # inside it): closed in the refused direction, so the allocator hands - # the share to the others within their own limits. During its probe it - # is a pin at PROBE_W and the others carry the rest. - for inv in self.inverters: - if not inv.refused: - continue - if _probing.get(inv.name): - claims.append(Claim.set("refused", P_SAFETY, - inv.refused * _ctl.PROBE_W, - _ctl.PROBING, - actuator=self.actuator_of("refused", - inv))) - else: - claims.append(Claim.limit("refused", P_SAFETY, - *_refused_interval(inv.refused), - _ctl.REFUSED, - actuator=self.actuator_of("refused", - inv))) _live = self.live_units() while True: resolution = resolve(claims, units=self.units, live=_live, @@ -3796,6 +3942,8 @@ class Controller: *_refused_interval(1 if claims[k].value > 0 else -1), _ctl.REFUSED, actuator=claims[k].actuator) self.allocation = resolution.allocation + if self.modes_on: + self._mode_fault_log(resolution) # --- THE TWO REFUSALS, AND THEY ARE NOT THE SAME REFUSAL -------------- # Both do the same thing - REPLACE the resolution with a 0 W failsafe # which is then written like any other cycle at @@ -5743,8 +5891,10 @@ class Controller: out["home_error"] = True return out - async def handle_action(self, what: str): + async def handle_action(self, what: str, *, unit=None, value=None): now = datetime.now(timezone.utc) + if what in ("pack_use", "pack_mode"): + return self._pack_action(what, unit, value, now) if what == "auto_toggle": self.auto = not self.auto self.store.set("auto", self.auto) diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 32bb31d..1481a54 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -919,9 +919,26 @@ HINTS = { "not_delivering_cleared": "{unit}: not-delivering alarm cleared", "maintenance": "Battery maintenance: {phase}", "maint_paused": "Maintenance charging paused to stay under the peak limit", + "pack_on": "{unit}: battery switched on", + "pack_off": "{unit}: battery switched off, it is asked for 0 W", + "pack_mode": "{unit}: battery mode changed", + "maint_off": "{unit}: maintenance stopped, the battery is switched off", + "mode_fault": "{unit}: battery mode ignored because of a software fault", } +# OPT-11: why a battery switch or mode change was refused (the page shows it). +PACK_REFUSED = { + "off": "Battery modes are off. Turn on “Battery modes” first.", + "unit": "There is no battery with that name.", + "value": "That choice is not possible for this battery.", +} + + +def pack_refused(why: str) -> str: + return PACK_REFUSED[why] + + def hint(key: str, **kw) -> str: """The plain words for one event. `w` is formatted as watts, `sw` as watts with their sign (positive gives power, negative charges).""" diff --git a/goodwe_controller/app/packmode.py b/goodwe_controller/app/packmode.py new file mode 100644 index 0000000..df2641d --- /dev/null +++ b/goodwe_controller/app/packmode.py @@ -0,0 +1,103 @@ +"""OPT-11 P1: each battery's mode and on/off switch, as limits and weights. + +Pure: no I/O, no clock. main.py reads the store, calls these, and files the +result as a `mode` claim (arbiter.P_MODE) and as the charge weights. +DECISIONS/OPT-11-battery-modes.md has the record; OPT-11-design section 1 has +the modes. + +Two rules hold for every mode, and they are what keeps modes safe: + +1. A mode range always holds 0 W. A mode may forbid a direction, never force + one, so batteries never move power in opposite directions because of a mode + (allocator.unit_interval() drops a range without 0 as a software fault). +2. A mode is a limit, not a weight. A weight of 0 does not keep a battery out: + allocator._fill()'s last-resort pass still uses it. So "may not" is a range, + and weights only set the order among batteries that may. + +P1 has no price runs and no forecast (P3, P4). So both modes give power to the +house at any hour, and the only mode that closes a direction is Off. What P1 +changes is the solar order: while the site charges, Leftover solar batteries +weigh 0, so they get solar only once the Solar first batteries are full or at +their power limit. Selling (the owner's 2026-09-27 answer) is a per-battery +choice that arrives with the price runs in P3; `PackMode.sell` and the +`pack_sell` store key are reserved for it and read by nothing yet. +""" + +from dataclasses import dataclass + +from .store import unit_key + +SOLAR_FIRST = "solar_first" +LEFTOVER_SOLAR = "leftover_solar" +CHEAP_HOURS = "cheap_hours" # reserved for P3; not accepted in P1 + +# The modes a battery may be set to in this release, in the order the page +# lists them. The first is the default when the store has no value. +MODES = (SOLAR_FIRST, LEFTOVER_SOLAR) +DEFAULT_MODE = SOLAR_FIRST + +# Store keys, per battery: `unit/<name>/<key>` (store.unit_key()). +USE_KEY = "pack_use" +MODE_KEY = "pack_mode" +SELL_KEY = "pack_sell" # reserved for P3 + + +@dataclass(frozen=True) +class PackMode: + """One battery's choice: on or off, its mode, and (P3) selling.""" + use: bool = True + mode: str = DEFAULT_MODE + sell: bool = False # reserved for P3, never read in P1 + + @property + def key(self) -> str: + """The page's word for this state: a mode, or `off`.""" + return self.mode if self.use else "off" + + +def read(data: dict, name: str) -> PackMode: + """Battery `name`'s choice from the store's data. A missing or unknown + value falls back to the default (on, Solar first), never to Off: a store + written by a later version must not switch a battery off here.""" + use = data.get(unit_key(name, USE_KEY), True) + mode = data.get(unit_key(name, MODE_KEY), DEFAULT_MODE) + return PackMode(use=use is not False, + mode=mode if mode in MODES else DEFAULT_MODE, + sell=data.get(unit_key(name, SELL_KEY)) is True) + + +def mode_range(pm: PackMode, rating_w: float) -> tuple: + """`(lo, hi)` in W for this battery's mode claim. Always holds 0 W. + + Off asks for 0 W both ways. In P1 both modes may charge and give power up + to the battery's rating: Leftover solar holds back its power only in the + planned expensive hours, and there are none before P3. + """ + if not pm.use: + return 0.0, 0.0 + r = abs(float(rating_w)) + return -r, r + + +def charge_weights(base, modes: dict, target_w: float): + """The allocator's weights with the solar order applied (design 3.5). + + `base` is packshare.weights()' answer (None for "all 1.0"). While the site + charges (`target_w < 0`), a Leftover solar battery weighs 0 and a Solar + first battery keeps its weight, so the fill gives the Solar first batteries + everything they can take before the last-resort pass reaches the others. + Giving power keeps `base` (P3 adds the expensive-run order). + + When no battery that is on would keep a positive weight (all Leftover + solar, or every Solar first one at 0), `base` is returned unchanged, so the + order among equals stays OPT-09's rather than an equal split. + """ + if float(target_w) >= 0.0 or not modes: + return base + names = sorted(modes) + w = {n: (1.0 if base is None else float(base.get(n, 1.0))) for n in names} + out = {n: (0.0 if modes[n].mode == LEFTOVER_SOLAR else w[n]) + for n in names} + if not any(out[n] > 0.0 for n in names if modes[n].use): + return base + return out diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index f872379..5606652 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -308,9 +308,41 @@ if (open) $("#c-details").open = true; } - /* ---------------- Batteries (placeholder until P3) ---------------- */ + /* ---------------- Batteries (placeholder until UX-13 P3) ---------------- */ + // OPT-11 P1: with battery modes on, each card gets an On/Off switch and a + // mode choice (`mode_key` in /status). UX-13 P3 replaces these cards. + const MODES = ["solar_first", "leftover_solar"]; + let packBusy = false; + async function packAct(what, unit, value) { + if (packBusy) return; + packBusy = true; + try { + const r = await fetch("action", { method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ action: what, unit: unit, value: value }) }); + const j = await r.json().catch(() => ({})); + toast(r.ok ? t("toast.done") : (j.error || t("toast.failed"))); + } catch (e) { toast(t("toast.failed")); } + finally { packBusy = false; } + refresh(); + } + function modeControls(b) { + const sw = h("button", { class: "btn" + (b.use ? " primary" : ""), type: "button", role: "switch", + "aria-checked": String(b.use), "aria-label": b.name + ": " + t("batteries.use"), + onclick: () => packAct("pack_use", b.name, !b.use) }, + b.use ? t("batteries.on") : t("batteries.off")); + const sel = h("select", { class: "sel", "aria-label": b.name + ": " + t("batteries.mode"), disabled: !b.use, + onchange: (e) => packAct("pack_mode", b.name, e.target.value) }, + ...MODES.map((k) => h("option", { value: k, selected: b.mode_choice === k }, t("batteries.choice." + k + ".name")))); + return [h("div", { class: "row spread", style: "margin-top:8px" }, h("span", { class: "small" }, t("batteries.use")), sw), + h("div", { class: "row spread", style: "margin-top:8px" }, h("span", { class: "small" }, t("batteries.mode")), sel), + h("p", { class: "tiny muted", style: "margin:6px 0 0" }, t("batteries.choice." + b.mode_key + ".description"))]; + } function renderBatteries() { if (!S.batteries) { $("#bcards").replaceChildren(); return; } + // Do not rebuild a card under an open mode list or a request in flight. + if (packBusy || ($("#bcards").contains(document.activeElement) && document.activeElement.tagName === "SELECT")) return; + const modes = S.batteries.some((b) => b.mode_key != null); + $("#batt-desc").textContent = t(modes ? "batteries.with_modes.description" : "batteries.description"); $("#bcards").replaceChildren(...S.batteries.map((b) => h("div", { class: "card" }, h("div", { class: "row spread" }, h("strong", {}, b.name), h("span", { class: "small muted" }, b.capacity_kwh ? b.capacity_kwh + " kWh" : "")), levelBar(b.level_pct, b.name), @@ -318,7 +350,8 @@ h("dt", {}, t("batteries.level")), h("dd", {}, b.level_pct == null ? "–" : Math.round(b.level_pct) + " %"), b.stored_kwh != null ? [h("dt", {}, t("batteries.stored")), h("dd", {}, dec(b.stored_kwh.toFixed(1)) + " kWh")] : null, h("dt", {}, t("batteries.now")), h("dd", {}, b.now), - h("dt", {}, t("batteries.mode")), h("dd", {}, b.mode))))); + b.mode_key == null ? [h("dt", {}, t("batteries.mode")), h("dd", {}, b.mode)] : null), + b.mode_key != null ? modeControls(b) : null))); } /* ---------------- control buttons ---------------- */ diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html index 14577db..7518ac8 100644 --- a/goodwe_controller/app/static/index.html +++ b/goodwe_controller/app/static/index.html @@ -96,7 +96,7 @@ <section class="screen" id="s-batt" role="tabpanel" aria-labelledby="t-batt" hidden> <div id="bcards"></div> <div class="card"> - <p class="small muted" style="margin:0 0 10px" data-t="batteries.description"></p> + <p class="small muted" style="margin:0 0 10px" id="batt-desc" data-t="batteries.description"></p> <a class="btn" href="#settings" data-t="batteries.settings"></a> </div> </section> diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 8903e83..4b36fe2 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -10,6 +10,7 @@ "parts": { "meter.timing": {"name": "Timing"}, "inverters.solar": {"name": "Solar"}, + "inverters.modes": {"name": "Battery modes"}, "tariff.selling": {"name": "Charging and selling on price"}, "tariff.feed": {"name": "Price feed details"}, "safety.peak": {"name": "Peak limit"}, @@ -82,7 +83,14 @@ "toast": {"started": "Control started.", "stopped": "Control stopped.", "done": "Done.", "failed": "That did not work. Try again."}, "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, "setup_only": {"name": "Setup: nothing is controlled yet", "description": "Nothing is sent to any inverter until setup is saved and the add-on restarts.", "control": "Control starts after setup.", "open": "Open Setup"}, - "batteries": {"name": "Batteries", "description": "Battery modes and on and off switches arrive in a later update.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings"}, + "batteries": {"name": "Batteries", "description": "To choose a mode for each battery, turn on battery modes in the settings.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings", + "with_modes": {"description": "Each battery follows its mode, after the peak limit and safety stops."}, + "use": "Use this battery", "on": "On", "off": "Off", + "choice": { + "solar_first": {"name": "Solar first", "description": "Charges from solar before the other batteries and covers the house."}, + "leftover_solar": {"name": "Leftover solar", "description": "Charges from solar the other batteries cannot take, and covers the house."}, + "off": {"name": "Off", "description": "The add-on asks this battery for 0 W, unless the peak limit needs it."} + }}, "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, "choices_later": { @@ -228,6 +236,7 @@ }, "home_words": { "mode_house": "Follows the house", + "modes": {"solar_first": "Solar first", "leftover_solar": "Leftover solar", "off": "Off"}, "attn_shadow": "Shadow mode is on", "attn_shadow_body": "The add-on decides everything, but every inverter stays at 0 W.", "zero_held": "Held at 0 W", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index be52870..11b2ec3 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -10,6 +10,7 @@ "parts": { "meter.timing": {"name": "Timing"}, "inverters.solar": {"name": "Zonnepanelen"}, + "inverters.modes": {"name": "Batterijmodi"}, "tariff.selling": {"name": "Laden en verkopen op prijs"}, "tariff.feed": {"name": "Details van de prijsfeed"}, "safety.peak": {"name": "Piekgrens"}, @@ -79,7 +80,14 @@ "toast": {"started": "Regeling gestart.", "stopped": "Regeling gestopt.", "done": "Klaar.", "failed": "Dat lukte niet. Probeer opnieuw."}, "offline": {"name": "Add-on niet bereikbaar", "description": "De pagina probeert het elke 3 seconden opnieuw."}, "setup_only": {"name": "Installatie: nog niets wordt geregeld", "description": "Er gaat niets naar een omvormer tot de installatie bewaard is en de add-on herstart.", "control": "De regeling start na de installatie.", "open": "Installatie openen"}, - "batteries": {"name": "Batterijen", "description": "Batterijmodi en aan- en uitschakelaars komen in een latere update.", "level": "Laadniveau", "now": "Nu", "stored": "Opgeslagen", "mode": "Modus", "settings": "Instellingen van omvormers wijzigen"}, + "batteries": {"name": "Batterijen", "description": "Zet batterijmodi aan in de instellingen om per batterij een modus te kiezen.", "level": "Laadniveau", "now": "Nu", "stored": "Opgeslagen", "mode": "Modus", "settings": "Instellingen van omvormers wijzigen", + "with_modes": {"description": "Elke batterij volgt haar modus, na de piekgrens en de veiligheidsstops."}, + "use": "Deze batterij gebruiken", "on": "Aan", "off": "Uit", + "choice": { + "solar_first": {"name": "Eerst zonne-energie", "description": "Laadt met zonne-energie vóór de andere batterijen en dekt het huis."}, + "leftover_solar": {"name": "Overschot zonne-energie", "description": "Laadt met zonne-energie die de andere batterijen niet opnemen, en dekt het huis."}, + "off": {"name": "Uit", "description": "De add-on vraagt deze batterij 0 W, behalve als de piekgrens haar nodig heeft."} + }}, "settings": {"name": "Instellingen", "description": "De instellingen staan hieronder per taak.", "open": "Instellingen openen"} }, "choices_later": {"region": {"wallonia": "Wallonië, nog geen standaardwaarde", "brussels": "Brussel, nog geen standaardwaarde"}}, @@ -202,6 +210,7 @@ }, "home_words": { "mode_house": "Volgt het huis", + "modes": {"solar_first": "Eerst zonne-energie", "leftover_solar": "Overschot zonne-energie", "off": "Uit"}, "attn_shadow": "Schaduwmodus staat aan", "attn_shadow_body": "De add-on beslist alles, maar elke omvormer blijft op 0 W.", "zero_held": "Op 0 W gehouden", diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index 0c5b30e..9c7f00a 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -126,6 +126,9 @@ GROUPS = ( # pv.py reads each entity's own unit, so a kW sensor is fine here. Part("solar", (Field("ui.solar", SOLAR_LIST, kind="power", wizard=3),)), + # OPT-11: the switch that turns battery modes on. Each battery's mode + # and on/off switch are runtime state on the Batteries screen. + Part("modes", (Field("battery_modes_enabled", TOGGLE),)), )), Group("tariff", ( Part("", ( diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index 007fbdb..93d1a49 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -33,6 +33,10 @@ not options is a Store key, `setup_done`, written when the wizard's save succeeds, so the page stops opening the wizard by itself (uipage.setup_needed). UX-15's setup-only mode serves these routes from `setuponly.SetupOnly`, which commands nothing; there `/action` answers 409. +OPT-11 P1 adds two `/action` values, `pack_use` and `pack_mode`, which set one +battery's on/off switch or mode in the store (Controller._pack_action). They +are the only actions that name a battery; the configuration routes still reach +none of them. """ import io @@ -53,6 +57,9 @@ from .uimodel import DeriveError, options_to_ui _LOG = logging.getLogger("goodwe.web") +# OPT-11: the per-battery actions, which name a battery and a value. +PACK_ACTIONS = ("pack_use", "pack_mode") + # UX-13 P1: the page lives in app/static/ as three files - index.html, # app.css, app.js - plus the page words from app/ui_text/<lang>.json (English # and, since P5, Dutch; the page picks by the browser's language). They are @@ -146,7 +153,17 @@ def build_app(controller, selfcfg=None) -> web.Application: # UX-15: nothing to start or stop until setup is saved. return web.json_response( {"ok": False, "error": messages.row_setup_only()}, status=409) - result = await controller.handle_action(what) + if what in PACK_ACTIONS: + # OPT-11: one battery's switch or mode. Store state for the named + # battery, applied on the next cycle; nothing is written here. + result = await controller.handle_action( + what, unit=body.get("unit"), value=body.get("value")) + if isinstance(result, dict) and "error" in result: + return web.json_response({"ok": False, + "error": result["error"]}, + status=400) + else: + result = await controller.handle_action(what) if result is None: raise web.HTTPBadRequest(text=f"unknown action {what!r}") return web.json_response({"ok": True, "result": result}) diff --git a/goodwe_controller/config.yaml b/goodwe_controller/config.yaml index 3f560ae..6744977 100644 --- a/goodwe_controller/config.yaml +++ b/goodwe_controller/config.yaml @@ -146,6 +146,11 @@ options: # options blob, and the upgrade leaves an add-on that cannot start. inverters: [] estop_fitted: false + # OPT-11: battery modes. Off by default, so an install that has not turned + # them on behaves exactly as before. When on, each battery gets an on/off + # switch and a mode on the Batteries screen, kept in the add-on's store. + # DECISIONS/OPT-11-battery-modes.md. + battery_modes_enabled: false # TEL-11 - THE SITE'S PV PRODUCTION, IN WATTS, AND IT IS READ BY NOTHING THAT # DECIDES ANYTHING. Optional, empty on every install that does not set it, and @@ -943,6 +948,7 @@ schema: capacity_kwh: float(0.1,200)? estop_fitted: bool + battery_modes_enabled: bool # TEL-11. Optional, and OPTIONAL WITHOUT A COMPANION RULE - unlike # `price_now_entity`/`price_avg_entity`, which are legal only while # `price_provider` is `off` and make the add-on REFUSE TO START otherwise. diff --git a/goodwe_controller/test_alloc.py b/goodwe_controller/test_alloc.py index fcda789..a04c55a 100644 --- a/goodwe_controller/test_alloc.py +++ b/goodwe_controller/test_alloc.py @@ -1041,6 +1041,133 @@ check("...and the three that are NOT caught are reported as such, with the " all(b is False for _n, b, _w in MUT[-3:])) + +print() +print("13. OPT-11: the mode layer - applied at or below 35, released above it") +# A mode is a SOFT unit limit beside the hard ones (UnitBounds.mode_*). The +# allocator applies it only when the site target was decided at or below the +# mode's own priority (P_MODE, 35), drops it when its range leaves out 0 W, +# and never lets it narrow a hard limit into nothing. +from app.allocator import (MODE_FAULT, MODE_OUTRANKED, MODE_RELEASED, # noqa: E402 + loop_bound, unit_interval) +from app.arbiter import P_MODE # noqa: E402 + + +def M(lo=-RATING, hi=RATING, mlo=-inf, mhi=inf, prio=P_MODE, **kw): + """A unit's bounds with a mode range beside its hard limits.""" + b = B(lo, hi, **kw) + return UnitBounds(lo=b.lo, hi=b.hi, gate=b.gate, pinned_w=b.pinned_w, + pinned_by=b.pinned_by, contradiction=b.contradiction, + mode_lo=mlo, mode_hi=mhi, mode_priority=prio) + + +_off = {A: M(), Bee: M(mlo=0.0, mhi=0.0)} +_at35 = plan(3000, _off, deciding_priority=P_MODE) +_at50 = plan(3000, _off, deciding_priority=P_PEAK) +_at10 = plan(3000, _off, deciding_priority=P_LOOP) +print(f" B off, 3000 W: decided at 10 {_at10.explain()} | at 35 " + f"{_at35.explain()} | at 50 {_at50.explain()}") +check("⭐ RELEASE AT 35: a target decided at P_MODE itself keeps the mode - " + "B (Off) is held at 0 W and A carries all 3000 W", + _at35.shares == {A: 3000, Bee: 0} and _at35.unmet_w == 0) +check("...and below it too (the loop, 10): the same split", + _at10.shares == _at35.shares) +check("⭐ RELEASE AT 50: a target decided by the peak floor releases the mode " + "and B takes its weighted half", + _at50.shares == {A: 1500, Bee: 1500} and _at50.unmet_w == 0) +check("...and the boundary is exactly 35: at 36 the mode is released", + plan(3000, _off, deciding_priority=P_MODE + 1).shares + == {A: 1500, Bee: 1500}) +check("...and no deciding priority named means the mode applies (the safe " + "reading for a direct caller)", + plan(3000, _off).shares == {A: 3000, Bee: 0}) +check("unit_interval() reports why: None when applied, MODE_RELEASED above " + "35, and the hard limits always", + unit_interval(_off[Bee], P_MODE) == (0.0, 0.0, None) + and unit_interval(_off[Bee], P_PEAK) == (-RATING, RATING, MODE_RELEASED)) + +# CONTAINS 0: a mode that would FORCE a direction is a software fault. +_force = {A: M(mlo=500.0, mhi=RATING), Bee: M()} +_f = plan(-1000, _force, deciding_priority=P_LOOP) +print(f" A's mode is [500, 5000] (leaves out 0 W), site charges 1000 W: " + f"{_f.explain()}, faults {_f.mode_faults}") +check("⭐ CONTAINS 0: a mode range that leaves out 0 W is dropped and named " + "as a fault, so REFUSE_SIGN stays unreachable: both units charge and " + "the split is allowed", + _f.ok and _f.mode_faults == ((A, MODE_FAULT),) + and all(v <= 0 for v in _f.shares.values()) + and sum(_f.shares.values()) == -1000) +_f_obeyed = plan(-1000, {A: B(500.0, RATING), Bee: B(-RATING, RATING)}) +check("...and that is not a hypothetical: the same range obeyed as a hard " + "limit forces A to give 500 W while B charges 1500 W, which the " + "allocator REFUSES as circulating power", + not _f_obeyed.ok and REFUSE_SIGN in _f_obeyed.refused) +check("...and a mode whose own lo is above its own hi is the same fault", + unit_interval(M(mlo=300.0, mhi=-300.0))[2] == MODE_FAULT) +_out = unit_interval(M(lo=-2000.0, hi=-500.0, mlo=0.0, mhi=0.0)) +check("a hard limit that leaves the mode no room wins outright " + "(MODE_OUTRANKED): the unit keeps its hard interval", + _out == (-2000.0, -500.0, MODE_OUTRANKED)) +check("a unit with no mode (every unit with battery modes off) gets exactly " + "its hard limits, and plan() is the same record as before the mode " + "fields existed", + unit_interval(B(-700.0, 900.0)) == (-700.0, 900.0, None) + and plan(1234, TWO, deciding_priority=P_PEAK) == plan(1234, TWO)) + +# The sweep: sum and sign kept whatever the modes, the target and the +# deciding priority; every share inside its effective interval. +_rng = random.Random(1135) +_bad, _nm = [], 0 +for _ in range(20000): + _units = {} + for u in (A, Bee, "inverter-c")[:_rng.choice((2, 3))]: + r = _rng.choice((2000.0, 3600.0, 5000.0)) + mlo = _rng.choice((-r, -700.0, 0.0)) + mhi = _rng.choice((0.0, 450.0, r)) + _units[u] = M(-r, r, mlo, mhi) + _d = _rng.choice((P_LOOP, P_ARBITRAGE, P_MODE, P_MODE + 1, P_PEAK, None)) + _t = _rng.randint(-15000, 15000) + _p = plan(_t, _units, deciding_priority=_d) + _nm += 1 + _eff = {u: unit_interval(b, _d)[:2] for u, b in _units.items()} + _sh = _p.shares + if (not _p.ok or sum(_sh.values()) + _p.unmet_w != _p.sum_w + or (any(v > 0 for v in _sh.values()) + and any(v < 0 for v in _sh.values())) + or any(not (_eff[u][0] <= _sh[u] <= _eff[u][1]) for u in _sh) + or (_d is not None and _d > P_MODE + and any(_eff[u] != (b.lo, b.hi) for u, b in _units.items()))): + _bad.append((_t, _d, _p.explain())) +for x in _bad[:5]: + print(f" BAD {x}") +check(f"over {_nm} random ticks (2-3 units, mode ranges holding 0 W, targets " + f"+-15 kW, deciding at 10/30/35/36/50/None) the shares sum to S with " + f"`unmet`, never split the sign, and each stays inside its interval - " + f"the mode's above 35 released, applied at or below", + not _bad and _nm == 20000) + +# loop_bound(): what the loop may ask when it decides. +_lb = loop_bound({A: M(mlo=-3000.0, mhi=0.0), Bee: M(mlo=0.0, mhi=0.0)}) +check("loop_bound() sums each unit's interval with its mode applied: A may " + "only charge 3000 W, B is off, so the loop may ask [-3000, 0]", + _lb == (-3000.0, 0.0)) +check("...a unit that is not live adds nothing", + loop_bound({A: M(), Bee: M()}, live=(A,)) == (-RATING, RATING)) +check("...a PINNED unit adds the span from 0 to its pin, so a 200 W probe " + "(SAFETY-73: the closed limit becomes a pin) stays reachable", + loop_bound({A: M(gate=P_SAFETY, pin=200.0), + Bee: M(mlo=0.0, mhi=0.0)}) == (0.0, 200.0)) +check("...and the pin is clamped into the hard limits first, as plan() " + "clamps it", + loop_bound({A: M(lo=-RATING, hi=0.0, gate=P_SAFETY, pin=200.0), + Bee: M(mlo=0.0, mhi=0.0)}) == (0.0, 0.0)) +check("...a mode that leaves out 0 W adds the hard interval (dropped, as in " + "plan()), so every term holds 0 and so does the sum", + loop_bound({A: M(mlo=500.0, mhi=900.0), Bee: M(mlo=0.0, mhi=0.0)}) + == (-RATING, RATING)) +check("...and a unit contradicting itself adds nothing", + loop_bound({A: M(contra=True), Bee: M(mlo=0.0, mhi=0.0)}) == (0.0, 0.0)) + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") diff --git a/goodwe_controller/test_arbiter.py b/goodwe_controller/test_arbiter.py index 57fa525..6a8b6fe 100644 --- a/goodwe_controller/test_arbiter.py +++ b/goodwe_controller/test_arbiter.py @@ -149,7 +149,7 @@ check("...and `source` is still the first positional argument, which is what " Claim.limit("device", P_SAFETY, -1, 1).source == "device") print() -print("ARB-03 2. the split: twelve sources, each classified where it is BUILT") +print("ARB-03 2. the split: thirteen sources, each classified where it is BUILT") # The classification is graded against what each claim is ABOUT, restated here # so that the table in arbiter.py and the expectation in a test are not the same # sentence read twice. test_peakguard.py part 10f pins this set against main.py's @@ -193,16 +193,20 @@ UNIT_SOURCES = { "refused": "THIS battery's own reading gave nothing against THIS unit's " "own standing command, so that direction is closed on THIS " "unit and its share goes to the others. Filed at N>1 only", + # OPT-11, added on purpose (test_peakguard.py part 10f says why). + "mode": "THIS battery's mode, chosen by its owner. A soft unit limit " + "that stage 1 keeps apart from the hard ones and stage 3 " + "releases when a claim above P_MODE decides the site target", } for _src, _why in sorted(SITE_SOURCES.items()): print(f" site {_src:<11} {_why}") for _src, _why in sorted(UNIT_SOURCES.items()): print(f" unit {_src:<11} {_why}") -check("all TWELVE claim sources are classified, and only those twelve", +check("all THIRTEEN claim sources are classified, and only those thirteen", set(CLAIM_SCOPE) == set(SITE_SOURCES) | set(UNIT_SOURCES)) check("the six that are about the GRID CONNECTION are site claims", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == set(SITE_SOURCES)) -check("the six that are about a PACK, a DEVICE or one write are per-inverter", +check("the seven that are about a PACK, a DEVICE or one write are per-inverter", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == set(UNIT_SOURCES)) check("a source nobody classified cannot be routed at all - actuator_for() " "raises rather than defaulting to the site, because defaulting to the " @@ -220,7 +224,7 @@ check("with one inverter every source routes to the site, per-inverter ones " all(actuator_for(s, "inverter-a", ONE) == ACTUATOR_SITE for s in CLAIM_SCOPE)) check("...and with none configured at all, likewise", all(actuator_for(s, "inverter-a", ()) == ACTUATOR_SITE for s in CLAIM_SCOPE)) -check("with TWO the identity breaks and the split becomes real: the six " +check("with TWO the identity breaks and the split becomes real: the seven " "per-inverter sources route to the unit this controller drives, the six " "site sources stay on the grid connection", {s: actuator_for(s, "inverter-a", TWO) for s in CLAIM_SCOPE} @@ -540,6 +544,156 @@ check("...and a correctly routed cycle is unaffected, which is what says this " resolve(SITE_SIDE, units=TWO).allocated is True) + +print() +print("OPT-11 9. the mode layer: a unit `hi` never meets the site `lo`") +# A battery's mode is a SOFT unit limit at P_MODE (35). Stage 1 keeps it apart +# from the hard limits; stage 3 applies it only while the site target was +# decided at or below P_MODE. So the peak guard's site floor (P_PEAK) releases +# every mode and SAFETY-25 section 0a's cross-inverter contradiction - 0 W in a +# billed period - still cannot be written down. +from app.arbiter import MODE_SOURCE, P_MODE # noqa: E402 +from app.allocator import MODE_FAULT, MODE_RELEASED # noqa: E402 + + +def _two(loop_w, *, peak_lo=None, modes=None, rating=2000.0, arb=None): + """A two-inverter cycle's claims: ratings, each unit's mode, the loop, + optionally the peak floor and an arbitrage set.""" + cl = [] + for u in TWO: + cl.append(Claim.limit("supervised", P_SAFETY, -rating, rating, + "max_w", actuator=u)) + for u, (lo, hi) in (modes or {}).items(): + cl.append(Claim.limit(MODE_SOURCE, P_MODE, lo, hi, "mode", actuator=u)) + cl.append(Claim.set("loop", P_LOOP, loop_w)) + if arb is not None: + cl.append(Claim.set("arbitrage", P_ARBITRAGE, arb)) + if peak_lo is not None: + cl.append(Claim.limit("peak", P_PEAK, lo=peak_lo)) + return cl + + +check("P_MODE sits between arbitrage and the peak guard, so a trade stays " + "inside each mode and the peak floor releases them all", + P_ARBITRAGE < P_MODE < P_PEAK and P_MODE < P_MAINT_SHAPE) +_off_b = {"inverter-b": (0.0, 0.0)} +r = resolve(_two(-500.0, peak_lo=3000.0, modes=_off_b), units=TWO) +print(f" peak floor 3000 W, loop asks -500 W, B off: {r.explain()}, " + f"deciding {r.deciding_priority}, shares {r.shares}") +check("⭐ at N=2 a mode `hi` of 0 W on B and the peak guard's site `lo` of " + "3000 W do NOT contradict: no 0 W stop, the floor decides S (priority " + "50), the mode is released, and the shares still sum to S", + not r.contradiction and r.allocated and r.target_w == 3000.0 + and r.deciding_priority == P_PEAK + and sum(r.shares.values()) == 3000 and r.allocation.unmet_w == 0) +_forbidden = [c if c.source != MODE_SOURCE + else Claim.limit(MODE_SOURCE, P_MODE, c.lo, c.hi, + actuator=ACTUATOR_SITE) + for c in _two(-500.0, peak_lo=3000.0, modes=_off_b)] +_rf = site_resolve([c for c in _forbidden if c.actuator == ACTUATOR_SITE]) +check("...and the SAME mode filed as a SITE limit is exactly the fault the " + "layer exists to keep out: stage 2 then reads `lo` 3000 > `hi` 0 and " + "stops the site at 0 W (so the check above sees the difference)", + _rf.contradiction and _rf.target_w == 0.0) +check("...and resolve() refuses that mis-filed mode at N=2 (a UNIT claim on " + "the site), rather than dividing a number that may be wrong", + resolve(_forbidden, units=TWO).allocated is False) + +# The sweep: every mode range that holds 0 W, every loop ask, every floor. +_bad = [] +_n = 0 +_spans = [(0.0, 0.0), (-2000.0, 0.0), (0.0, 2000.0), (-2000.0, 2000.0), + (-700.0, 300.0)] +for _ma in _spans: + for _mb in _spans: + for _loop in (-5000.0, -1200.0, 0.0, 800.0, 3900.0): + for _peak in (None, 0.0, 1500.0, 3000.0, 4000.0): + _n += 1 + _r = resolve(_two(_loop, peak_lo=_peak, + modes={"inverter-a": _ma, + "inverter-b": _mb}), units=TWO) + _al = _r.allocation + _sh = list(_r.shares.values()) + if (_r.contradiction or not _r.allocated + or sum(_sh) + _al.unmet_w != _al.sum_w + or (any(x > 0 for x in _sh) and any(x < 0 for x in _sh)) + or (_peak is not None and _r.target_w < _peak)): + _bad.append((_ma, _mb, _loop, _peak, _r.explain(), + _al.explain())) +for x in _bad[:5]: + print(f" BAD {x}") +check(f"over {_n} two-inverter cycles (5x5 mode ranges holding 0 W, 5 loop " + f"asks, 5 peak floors) no cycle contradicts, refuses, loses a watt of " + f"the sum, splits the sign, or goes under the peak floor", + not _bad and _n == 625) + +check("deciding_priority: the loop alone decides at 10", + resolve(_two(800.0), units=TWO).deciding_priority == P_LOOP) +check("...a trade decides at 30, so the modes still apply to it", + resolve(_two(800.0, arb=-1500.0), units=TWO).deciding_priority + == P_ARBITRAGE) +check("...a peak floor that does not bind leaves the loop deciding at 10", + resolve(_two(3500.0, peak_lo=1000.0), units=TWO).deciding_priority + == P_LOOP) +check("...and a peak floor that binds decides at 50", + resolve(_two(500.0, peak_lo=1000.0), units=TWO).deciding_priority + == P_PEAK) +_r35 = resolve(_two(3000.0, modes=_off_b), units=TWO) +check("with the loop deciding, B's Off mode holds: B gets 0 W and A carries " + "what it can, the rest reported as unmet", + _r35.shares == {"inverter-a": 2000, "inverter-b": 0} + and _r35.allocation.unmet_w == 1000) + +_ub = pre_resolve([Claim.limit("supervised", P_SAFETY, -2000, 2000), + Claim.limit(MODE_SOURCE, P_MODE, 0.0, 0.0)]) +check("stage 1 keeps the mode APART from the hard limits: the unit's own " + "interval is still its rating and the mode travels beside it", + (_ub.lo, _ub.hi, _ub.mode_lo, _ub.mode_hi, _ub.mode_priority) + == (-2000, 2000, 0.0, 0.0, P_MODE) and not _ub.contradiction) +_ub2 = pre_resolve([Claim.limit("supervised", P_SAFETY, -2000, 2000), + Claim.limit(MODE_SOURCE, P_MODE, 500.0, 2000.0)]) +check("...so a mode that does not hold 0 W cannot make the unit contradict " + "itself at stage 1; stage 3 drops it as a software fault instead", + not _ub2.contradiction + and allocate(1000.0, {"inverter-a": _ub2, "inverter-b": UnitBounds()})[1] + and resolve(_two(1000.0, modes={"inverter-a": (500.0, 2000.0)}), + units=TWO).allocation.mode_faults + == (("inverter-a", MODE_FAULT),)) +_ubm = pre_resolve([Claim.limit("supervised", P_SAFETY, -2000, 2000), + Claim.set("maintenance", P_MAINTENANCE, 2500.0, "drain"), + Claim.limit(MODE_SOURCE, P_MODE, 0.0, 0.0)]) +check("...and a unit's own maintenance SET (60) gates the mode out, as it " + "gates every lower limit: maintenance outranks the mode", + _ubm.mode_priority is None and _ubm.pinned_by == "maintenance") + +print() +print("OPT-11 10. at N=1 the mode bounds the site target, by the same rule") +_one = [Claim.limit("supervised", P_SAFETY, -5000, 5000, "max_w"), + Claim.limit(MODE_SOURCE, P_MODE, 0.0, 0.0, "off")] +_r1 = resolve(_one + [Claim.set("loop", P_LOOP, 1200.0)], units=ONE) +check("the loop deciding: an Off battery's site target is 0 W, named as the " + "mode's doing, with no contradiction", + _r1.target_w == 0.0 and not _r1.contradiction + and _r1.bound_by == "mode(off)" and _r1.allocated) +_r1p = resolve(_one + [Claim.set("loop", P_LOOP, 1200.0), + Claim.limit("peak", P_PEAK, lo=2000.0)], units=ONE) +check("...a binding peak floor releases it (2000 W, no contradiction), " + "which at N=1 would otherwise be `lo` 2000 > `hi` 0 and a 0 W stop", + _r1p.target_w == 2000.0 and not _r1p.contradiction + and _r1p.deciding_priority == P_PEAK) +_r1a = resolve(_one + [Claim.set("arbitrage", P_ARBITRAGE, -3000.0)], + units=ONE) +check("...a trade (30) stays inside it", _r1a.target_w == 0.0) +_r1f = resolve([Claim.limit(MODE_SOURCE, P_MODE, 100.0, 900.0), + Claim.set("loop", P_LOOP, -1200.0)], units=ONE) +check("...and a mode range without 0 W is dropped and reported, never " + "obeyed: the target stays the loop's -1200 W", + _r1f.target_w == -1200.0 and _r1f.mode_fault is not None) +check("...and with no mode claim at all, stage 2's answer is untouched " + "(the N=1 path with battery modes off)", + resolve([Claim.set("loop", P_LOOP, 1200.0)], units=ONE).target_w + == 1200.0) + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") diff --git a/goodwe_controller/test_control.py b/goodwe_controller/test_control.py index 14cec8e..668d2bd 100644 --- a/goodwe_controller/test_control.py +++ b/goodwe_controller/test_control.py @@ -1156,6 +1156,118 @@ check("...while the GAIN does own it: 0.6 -> 0.3 -> 0.2 falls monotonically, at _R["gain03"]["over"] < _R["rail"]["over"] and _R["gain02"]["over"] < _R["gain03"]["over"]) +print() +print("OPT-11: the loop is told what the battery modes allow") +# compute(bound=(lo, hi)) is the site output bound: the sum over live units of +# (hard limits with the mode applied), allocator.loop_bound(). Without it the +# loop asks for watts no battery may give, the allocator reports them unmet, +# and the saturation freeze parks the target on them (SAFETY-73 section 1). +import random as _random # noqa: E402 +from app.control import MODE_BOUND # noqa: E402 +from named_absence import present # noqa: E402 + +TB = Tuning(gain=0.6, max_w=5000.0, slew_w=400.0, deadband_w=15.0, + step_w=10, target_grid_w=-10.0) + + +def closed_loop(cycles, load, *, bound=None, deliver=None, change=None): + """A plant that follows 94 % of the command each cycle, capped at + `deliver` (what the allocator can place). `change(i)` may return a new + bound. Rows: (command, actual, sat_count, frozen, reason, i_w).""" + prev, actual, sat, i_w, rows = 0.0, 0.0, 0, None, [] + for i in range(cycles): + if change is not None: + bound = change(i, bound) + d = compute(prev, load - actual, actual, TB, sat, i_w, bound=bound) + prev, sat, i_w = d.target_w, d.sat_count, d.i_w + cmd = prev if deliver is None else max(deliver[0], + min(deliver[1], prev)) + actual = actual + 0.94 * (cmd - actual) + rows.append((prev, actual, sat, d.frozen, d.reason, d.i_w)) + return rows + + +# (a) One battery may give 800 W (the other is Off), the house takes 3000 W. +_with = closed_loop(40, 3000.0, bound=(-800.0, 800.0)) +_without = closed_loop(40, 3000.0, deliver=(-800.0, 800.0)) +print(f" house 3000 W, modes allow 800 W: with the bound the command ends " + f"at {nth(_with, -1)[0]:.0f} W (sat {max(r[2] for r in _with)}, reason " + f"{nth(_with, -1)[4]}); without it {nth(_without, -1)[0]:.0f} W with " + f"{sum(r[3] for r in _without)} frozen cycles") +check("⭐ THE LOOP BOUND HOLDS: every command and every integrator value " + "stays inside [-800, 800], and the command settles at the bound", + all(-800.0 <= r[0] <= 800.0 and -800.0 <= r[5] <= 800.0 for r in _with) + and present(nth(_with, -1)) and nth(_with, -1)[0] == 800.0 + and nth(_with, -1)[4] == MODE_BOUND) +_big = [] +_pv, _iw, _sat = 0.0, None, 0 +for _i in range(30): + _d = compute(_pv, 12000.0, _pv, TB, _sat, _iw, bound=(-800.0, 800.0)) + _pv, _iw, _sat = _d.target_w, _d.i_w, _d.sat_count + _big.append(_d) +check("...and a house far beyond what the modes allow (12 kW against 800 W) " + "does not read as the loop winding into its rail: SAFETY-03's flags " + "stay false on every cycle", + _big and not any(d.i_clamped or d.clamped for d in _big) + and all(d.target_w <= 800.0 for d in _big)) +check("⭐ NO SATURATION FREEZE from unmet watts: sat_count never reaches the " + "freeze and no cycle is frozen", + not any(r[3] for r in _with) + and max(r[2] for r in _with) < TB.saturation_cycles) +check("...and the same site WITHOUT the bound is the failure it removes: the " + "loop asks past 800 W, the plant cannot follow and the freeze engages", + any(r[3] for r in _without) and max(r[0] for r in _without) > 800.0) + +# (b) Every battery switched off: the bound is [0, 0]. +_off = closed_loop(20, 2500.0, bound=(0.0, 0.0)) +check("all batteries off: the loop asks 0 W on every cycle, with the " + "integrator at 0, and never freezes", + all(r[0] == 0.0 and r[5] == 0.0 and not r[3] for r in _off)) + +# (c) A mode closes while the battery gives 2000 W: the ask drops at once. +_close = closed_loop(30, 2000.0, bound=(-5000.0, 5000.0), + change=lambda i, b: (0.0, 0.0) if i >= 20 else b) +check("a mode that closes mid-run drops the ask to 0 W on the same cycle " + "(no slew steps of unmet watts) and carries no integrator past it", + present(nth(_close, 20)) and nth(_close, 19)[0] > 1500.0 + and nth(_close, 20)[0] == 0.0 + and nth(_close, 20)[5] == 0.0 and not any(r[3] for r in _close[20:])) + +# (d) Rounding never steps outside the bound. +_q = compute(1000.0, 3000.0, 1000.0, TB, 0, 1236.0, bound=(-5000.0, 1236.0)) +check("quantising to 10 W does not step outside the bound: 1236 W becomes " + "1230 W, not 1240 W", _q.target_w == 1230.0) +_qn = compute(-1000.0, -3000.0, -1000.0, TB, 0, -1236.0, + bound=(-1236.0, 5000.0)) +check("...on the charge side too: -1236 W becomes -1230 W", + _qn.target_w == -1230.0) + +# (e) A bound that leaves out 0 W is a fault and is not obeyed. +_rngc = _random.Random(1131) +_same, _nb = True, 0 +for _ in range(4000): + args = (_rngc.uniform(-5000, 5000), _rngc.uniform(-4000, 4000), + _rngc.uniform(-5000, 5000), TB, _rngc.randint(0, 5), + _rngc.choice((None, _rngc.uniform(-6000, 6000)))) + _nb += 1 + if (compute(*args, bound=(200.0, 900.0)) != compute(*args) + or compute(*args, bound=None) != compute(*args)): + _same = False +check(f"a bound that leaves out 0 W is ignored, and bound=None is the law as " + f"it was: {_nb} random cycles give the identical Decision", + _same and _nb == 4000) + +# (f) Inside the bound nothing changes: a bound wider than every command. +_wide = True +for _ in range(4000): + args = (_rngc.uniform(-4000, 4000), _rngc.uniform(-3000, 3000), + _rngc.uniform(-4000, 4000), TB, _rngc.randint(0, 5), + _rngc.choice((None, _rngc.uniform(-4000, 4000)))) + if compute(*args, bound=(-9000.0, 9000.0)) != compute(*args): + _wide = False +check("a bound wider than the rail changes no Decision (4000 random cycles)", + _wide) + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") diff --git a/goodwe_controller/test_modes.py b/goodwe_controller/test_modes.py new file mode 100644 index 0000000..0acb952 --- /dev/null +++ b/goodwe_controller/test_modes.py @@ -0,0 +1,463 @@ +"""Runnable check for OPT-11 P1, battery modes. `python3 test_modes.py` + +Each battery gets an on/off switch and a mode (Solar first, Leftover solar), +kept in the store and filed as a SOFT unit limit at P_MODE (35). Drives the +REAL `Controller` (read_inputs + cycle) through tools/opt11_identity.py's +harness, in simulated time. DECISIONS/OPT-11-battery-modes.md has the record. + +1. With battery modes off, every command is byte-identical to release/1.0 + a5dddad, at one inverter and at two (digests measured on that tree). +2. Solar order: surplus solar fills the Solar first battery, then spills to the + Leftover solar one; a full Solar first battery hands all of it on. +3. Off: the battery is asked for 0 W, the others carry the site, the loop is + bounded and never freezes on watts no battery may give; all off at N=1 and + N=2 asks 0 W. +4. Off stops and skips maintenance, with a log line; a battery in maintenance + gets no mode claim. +5. The actions: `pack_use` and `pack_mode`, what they store, log and refuse. +6. A mode range without 0 W is dropped as a software fault, logged once. +7. The Batteries screen's data. + +Mutations (MUTATION.md, purged copies, graded over this file and the named +tests) are listed in the pull request and DECISIONS/OPT-11-battery-modes.md. +""" + +import asyncio +import logging +import os +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) + +import opt11_identity as rig # noqa: E402 +from named_absence import nth, present # noqa: E402 +import app.main as app_main # noqa: E402 +from app import homeview, messages, packmode # noqa: E402 +from app.control import MODE_BOUND # noqa: E402 +from app.maintenance import DRAIN, IDLE # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +ON = {"battery_modes_enabled": True} +A, B = "inverter-a", "inverter-b" + + +def store_with(**modes): + """A store where each named battery has (use, mode).""" + s = rig._Store() + for name, (use, mode) in modes.items(): + s.data[unit_key(name, packmode.USE_KEY)] = use + s.data[unit_key(name, packmode.MODE_KEY)] = mode + return s + + +def spy_claims(): + """Record every claim list main.py's own `resolve` is handed.""" + seen, real = [], app_main.resolve + + def _spy(claims, **kw): + seen.append(list(claims)) + return real(claims, **kw) + app_main.resolve = _spy + return seen, lambda: setattr(app_main, "resolve", real) + + +def spy_bounds(): + """Record the `bound` main.py hands `compute()` on every cycle.""" + seen, real = [], app_main.compute + + def _spy(*a, **kw): + seen.append(kw.get("bound", "absent")) + return real(*a, **kw) + app_main.compute = _spy + return seen, lambda: setattr(app_main, "compute", real) + + +def flat(t): + return 0.0 + + +# ============================================================================ # +print("1. battery modes off: byte-identical to release/1.0 a5dddad") +# The digests below were printed by `python3 tools/opt11_identity.py` run on +# the a5dddad tree (the same file copied in, nothing else changed), in the CI +# image, on 2026-09-28. Each hashes 540 cycles: site target, every inverter's +# written value, the loop's reason, integrator and saturation count, the +# arbiter's sentence and the allocation record. +A5DDDAD = { + "n1": "fc3bca170c46920f08d86baee62ea883954a89ea6222d6bbf7d6652877226262", + "n2": "a60003b1930fa3cba21f3220670d9172b9ff438347d77ba9bc3383fca1ceb15a", + "n1_off": "fc3bca170c46920f08d86baee62ea883954a89ea6222d6bbf7d6652877226262", + "n2_off": "a60003b1930fa3cba21f3220670d9172b9ff438347d77ba9bc3383fca1ceb15a", +} +_claims, _undo_c = spy_claims() +_bounds, _undo_b = spy_bounds() +try: + _now = rig.digests() +finally: + _undo_c() + _undo_b() +for k in A5DDDAD: + print(f" {k:7} {'same' if _now[k] == A5DDDAD[k] else 'DIFFERS'} " + f"{_now[k][:16]}") +check("⭐ at N=1 and N=2, with the option absent and with it false, every " + "command, reason and allocation record over 540 cycles each is " + "byte-identical to a5dddad (house steps, a solar surplus, a battery " + "at its cut-out level, and at N=2 a refusal with probes)", + _now == A5DDDAD) +check("...and no cycle in those runs filed a `mode` claim or handed " + "`compute()` a bound", + _claims and not any(c.source == "mode" for cl in _claims for c in cl) + and _bounds and set(_bounds) == {None}) + + +# ============================================================================ # +print("\n2. the solar order: Solar first fills, the rest spills to Leftover") +_surplus = (lambda t: -3200.0) # 3200 W more solar than the house uses +_full_a = (lambda u, t: 100.0 if (u == "a" and t >= 300) else 50.0) +_rows, _c = rig.run(2, extra=ON, dur=600.0, load=_surplus, soc=_full_a, + cut=lambda u, t: False, + store=store_with(**{A: (True, packmode.SOLAR_FIRST), + B: (True, packmode.LEFTOVER_SOLAR)})) +_room = [r for r in _rows if 200 <= r[0] < 300] +_full = [r for r in _rows if r[0] >= 500] + + +def _cmd(r): + """One row's written values, by battery; ABSENTs if the row is missing.""" + return (dict(r[2]) if present(r) + else {"a": nth((), 0, "a"), "b": nth((), 0, "b")}) + + +print(f" A has room: A {_cmd(nth(_room, -1))['a']:+.0f} W, B " + f"{_cmd(nth(_room, -1))['b']:+.0f} W | A full: A {_cmd(nth(_full, -1))['a']:+.0f} " + f"W, B {_cmd(nth(_full, -1))['b']:+.0f} W") +check("⭐ while A (Solar first) has room it takes all it can, 2500 W, and B " + "(Leftover solar) gets only the spill, about 700 W", + present(nth(_room, -1)) + and all(_cmd(r)["a"] == -2500.0 and -800.0 <= _cmd(r)["b"] <= -600.0 + for r in _room)) +check("⭐ once A is full, the surplus spills to B, up to B's rating", + present(nth(_full, -1)) + and all(_cmd(r)["a"] == 0.0 and _cmd(r)["b"] == -2500.0 for r in _full)) +_rows_off, _ = rig.run(2, dur=300.0, load=_surplus, + soc=lambda u, t: 50.0, cut=lambda u, t: False) +check("...and the same site with battery modes off splits 50/50, which is " + "what says the order above comes from the modes", + _cmd(_rows_off[-1])["a"] == _cmd(_rows_off[-1])["b"] < -1500.0) +_give = rig.run(2, extra=ON, dur=300.0, load=lambda t: 3000.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False, + store=store_with(**{A: (True, packmode.SOLAR_FIRST), + B: (True, packmode.LEFTOVER_SOLAR)}))[0] +check("while giving power the modes keep OPT-09's weights: A Solar first and " + "B Leftover solar, both half full, share a 3000 W house equally", + _cmd(_give[-1])["a"] == _cmd(_give[-1])["b"] > 1400.0) + + +# ============================================================================ # +print("\n3. Off: 0 W on that battery, the loop bounded, no freeze") +_rows, _c = rig.run(2, extra=ON, dur=600.0, load=lambda t: 4000.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False, + store=store_with(**{B: (False, packmode.SOLAR_FIRST)})) +_tail = _rows[40:] +print(f" house 4000 W, B off: A {_cmd(_tail[-1])['a']:+.0f} W, B " + f"{_cmd(_tail[-1])['b']:+.0f} W, site {_tail[-1][1]:+.0f} W, reason " + f"{_tail[-1][3]}, {_tail[-1][7]}") +check("⭐ B (Off) is asked for 0 W on every cycle and A carries the house up " + "to its rating", + all(_cmd(r)["b"] == 0.0 for r in _rows) + and all(_cmd(r)["a"] == 2500.0 for r in _tail)) +check("⭐ the loop stays inside what the modes allow (2500 W) and never " + "freezes: no saturated-freeze reason, and the saturation count stays " + "below the freeze", + all(r[1] <= 2500.0 for r in _rows) + and not any(r[3] == "saturated-freeze" for r in _rows) + and max(r[5] for r in _rows) < _c.tuning.saturation_cycles + and _tail[-1][3] == MODE_BOUND) +check("...and nothing is left unmet: the allocation places the whole target", + all("UNMET" not in (r[7] or "") for r in _tail)) +_bounds, _undo_b = spy_bounds() +try: + rig.run(2, extra=ON, dur=100.0, load=lambda t: 4000.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False, + store=store_with(**{B: (False, packmode.SOLAR_FIRST)})) +finally: + _undo_b() +check("...because main.py hands compute() the loop bound, B's 0 W included: " + "[-2500, 2500]", _bounds and set(_bounds) == {(-2500.0, 2500.0)}) + +for _n in (1, 2): + _st = store_with(**{A: (False, packmode.SOLAR_FIRST), + B: (False, packmode.LEFTOVER_SOLAR)}) + if _n == 1: + _st = rig._Store() + _st.data[unit_key(app_main.UNIT_A, packmode.USE_KEY)] = False + _rows, _c = rig.run(_n, extra=ON, dur=300.0, load=lambda t: 3000.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False, + store=_st) + check(f"every battery off at N={_n}: every command is 0 W, the site " + f"target is 0 W, the integrator stays at 0 and nothing freezes", + all(all(v == 0.0 for _u, v in r[2]) and r[1] == 0.0 and r[4] == 0.0 + and r[3] != "saturated-freeze" for r in _rows)) +_rows1, _ = rig.run(1, extra=ON, dur=300.0, load=lambda t: 1800.0, + soc=lambda u, t: 50.0) +_rows1o, _ = rig.run(1, dur=300.0, load=lambda t: 1800.0, + soc=lambda u, t: 50.0) +check("at N=1 a battery that is on (Solar first by default) follows the " + "house exactly as with battery modes off", + [r[:6] for r in _rows1] == [r[:6] for r in _rows1o] + and _cmd(_rows1[-1])["a"] > 1700.0) + + +# ============================================================================ # +print("\n4. Off stops and skips maintenance; maintenance outranks the mode") +MAINT = {"maintenance_enabled": True, "maintenance_start_hour": 11} +_st = store_with(**{A: (False, packmode.SOLAR_FIRST)}) +_rows, _c = rig.run(2, extra={**ON, **MAINT}, dur=60.0, + load=lambda t: 500.0, soc=lambda u, t: 60.0, + cut=lambda u, t: False, store=_st) +print(f" both due at 11:00, A off: A {_c.maints[0].phase}, " + f"B {_c.maints[1].phase}") +check("⭐ a battery that is off starts no cycle, and does not hold the slot: " + "both are due, A (first in the roster) is off, so B starts", + _c.maints[0].phase == IDLE and _c.maints[1].phase == DRAIN) +_st2 = store_with() +_seen, _undo_c = spy_claims() +_msgs = [] + + +async def _switch_b_off(c, t): + if t == 30.0: + _msgs.append(await c.handle_action("pack_use", unit=B, value=False)) + + +try: + _rows, _c = rig.run(2, extra={**ON, **MAINT}, dur=60.0, + load=lambda t: 500.0, soc=lambda u, t: 60.0, + cut=lambda u, t: False, store=_st2, + before=_switch_b_off) +finally: + _undo_c() +_during = [cl for cl in _seen[:6]] +print(f" B off at 30 s while A drains: A {_c.maints[0].phase}, " + f"B {_c.maints[1].phase}; events: " + f"{[e for e in _c.events if 'switched' in str(e) or 'ABORT' in str(e)]}") +check("while A runs its cycle it gets no mode claim (maintenance at 60/40 " + "outranks the mode) and B, idle, gets one", + all({c.actuator for c in cl if c.source == "mode"} == {B} + for cl in _during)) +_st3 = store_with() +_st3.data[unit_key(B, "phase")] = DRAIN +_st3.data["maint_schema_version"] = 1 + + +async def _b_off_now(c, t): + if t == 10.0: + _msgs.append(await c.handle_action("pack_use", unit=B, value=False)) + + +_rows, _c = rig.run(2, extra=ON, dur=30.0, load=lambda t: 500.0, + soc=lambda u, t: 60.0, cut=lambda u, t: False, + store=_st3, before=_b_off_now) +_ev = [str(e) for e in _c.events] +print(f" B mid-drain, switched off at 10 s: B {_c.maints[1].phase}; " + f"{[e for e in _ev if 'switched off' in e or 'ABORT' in e]}") +check("⭐ switching off a battery that is mid-cycle stops its cycle at once, " + "with a log line saying why", + _c.maints[1].phase == IDLE + and any("battery switched off" in e for e in _ev) + and _cmd(_rows[-1])["b"] == 0.0) +_st4 = store_with(**{B: (False, packmode.SOLAR_FIRST)}) +_st4.data[unit_key(B, "phase")] = DRAIN +_st4.data["maint_schema_version"] = 1 +_rows, _c = rig.run(2, extra=ON, dur=20.0, load=lambda t: 500.0, + soc=lambda u, t: 60.0, cut=lambda u, t: False, store=_st4) +check("...and a store that says Off for a battery mid-cycle (a restart) stops " + "it on the first cycle, and it is never asked to drain", + _c.maints[1].phase == IDLE + and all(_cmd(r)["b"] == 0.0 for r in _rows)) + + +# ============================================================================ # +print("\n5. the actions: pack_use and pack_mode") +_rows, _c = rig.run(2, extra=ON, dur=10.0, load=flat, + soc=lambda u, t: 50.0, cut=lambda u, t: False) +_r1 = asyncio.run(_c.handle_action("pack_mode", unit=B, + value=packmode.LEFTOVER_SOLAR)) +_r2 = asyncio.run(_c.handle_action("pack_use", unit=A, value=False)) +print(f" {_r1} {_r2}") +check("pack_mode stores the mode under the battery's own key and says what " + "it now is", + _r1 == {"unit": B, "use": True, "mode": packmode.LEFTOVER_SOLAR} + and _c.store.data[unit_key(B, packmode.MODE_KEY)] + == packmode.LEFTOVER_SOLAR) +check("pack_use stores the switch, and both are written to the action log", + _r2 == {"unit": A, "use": False, "mode": packmode.SOLAR_FIRST} + and _c.store.data[unit_key(A, packmode.USE_KEY)] is False + and any("inverter-a switched off by operator" in str(e) + for e in _c.events) + and any("inverter-b mode set to leftover solar" in str(e) + for e in _c.events)) +_bad = [asyncio.run(_c.handle_action("pack_use", unit="inverter-z", + value=True)), + asyncio.run(_c.handle_action("pack_use", unit=A, value="yes")), + asyncio.run(_c.handle_action("pack_mode", unit=A, + value=packmode.CHEAP_HOURS)), + asyncio.run(_c.handle_action("pack_mode", unit=A, value=None))] +check("an unknown battery, a switch that is not true or false, and a mode " + "this release does not offer (Cheap hours arrives in P3) are refused, " + "with a plain reason, and store nothing", + all(isinstance(x, dict) and set(x) == {"error"} for x in _bad) + and unit_key(A, packmode.MODE_KEY) not in _c.store.data + and _c.store.data[unit_key(A, packmode.USE_KEY)] is False) +_rows, _c0 = rig.run(2, dur=10.0, load=flat, soc=lambda u, t: 50.0, + cut=lambda u, t: False) +_r0 = asyncio.run(_c0.handle_action("pack_use", unit=A, value=False)) +check("with battery modes off the actions are refused and store nothing", + set(_r0) == {"error"} + and unit_key(A, packmode.USE_KEY) not in _c0.store.data) +check("the old actions still take no battery and answer as before", + asyncio.run(_c0.handle_action("nonsense")) is None) +check("a store value from a later version (an unknown mode) reads as the " + "default, Solar first and on, never as Off", + packmode.read({unit_key(A, packmode.MODE_KEY): "grid_only", + unit_key(A, packmode.USE_KEY): "maybe"}, A) + == packmode.PackMode(True, packmode.SOLAR_FIRST)) + + +# ============================================================================ # +print("\n6. a mode range without 0 W is a software fault, never obeyed") +_real_range = packmode.mode_range +packmode.mode_range = lambda pm, r: (100.0, 900.0) +_log = [] + + +class _H(logging.Handler): + def emit(self, rec): + _log.append((rec.levelno, rec.getMessage())) + + +_h = _H() +logging.getLogger("goodwe").addHandler(_h) +try: + _rows, _c = rig.run(2, extra=ON, dur=60.0, load=lambda t: -2000.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False) +finally: + packmode.mode_range = _real_range + logging.getLogger("goodwe").removeHandler(_h) +_errs = [msg for lv, msg in _log if lv >= logging.ERROR and "MODE_RANGE" in msg] +print(f" {_errs}") +check("⭐ both batteries still charge from the surplus (the forced range is " + "dropped, so no battery is made to give power) and no split is refused", + all(v <= 0.0 for _u, v in _rows[-1][2]) + and _cmd(_rows[-1])["a"] < 0.0 + and not any("REFUSED" in (r[7] or "") for r in _rows)) +check("...and it is logged once per battery, as an ERROR naming the fault " + "code, not once per cycle", + len(_errs) == 2 and any(A in e for e in _errs) and any(B in e for e in _errs)) + + +# ============================================================================ # +print("\n7. the Batteries screen's data") +_rows, _c = rig.run(2, extra=ON, dur=10.0, load=flat, soc=lambda u, t: 50.0, + cut=lambda u, t: False, + store=store_with(**{B: (False, packmode.LEFTOVER_SOLAR)})) +_bat = homeview.battery_rows(_c, False, True) +_bat_nl = homeview.build(_c, level="ok", checks=[], lang="nl")["batteries"] +print(f" {[(b['name'], b['use'], b['mode_key'], b['mode']) for b in _bat]}") +check("with battery modes on each row carries its switch, its state and its " + "stored mode, in the page's words", + [(b["use"], b["mode_key"], b["mode_choice"], b["mode"]) for b in _bat] + == [(True, "solar_first", "solar_first", "Solar first"), + (False, "off", "leftover_solar", "Off")] + and _bat_nl[1]["mode"] == "Uit") +_rows, _c0 = rig.run(2, dur=10.0, load=flat, soc=lambda u, t: 50.0, + cut=lambda u, t: False) +check("...and with them off the rows are what they were: no new keys, the " + "mode reads as before", + all("mode_key" not in b and b["mode"] == homeview.mode_house() + for b in homeview.battery_rows(_c0, False, True))) + + +# ============================================================================ # +print("\n8. the page's route: /action and /status over the real web app") +import socket # noqa: E402 + +import aiohttp # noqa: E402 +from aiohttp import web as aioweb # noqa: E402 + +from app import web as app_web # noqa: E402 + +_rows, _c = rig.run(2, extra=ON, dur=10.0, load=flat, soc=lambda u, t: 50.0, + cut=lambda u, t: False) + + +async def _page(): + # The configuration routes are not used here; a stand-in keeps the app + # from building a Supervisor client. + app = app_web.build_app(_c, selfcfg=object()) + runner = aioweb.AppRunner(app) + await runner.setup() + sock = socket.socket() + sock.bind(("127.0.0.1", 0)) + port = sock.getsockname()[1] + sock.close() + await aioweb.TCPSite(runner, "127.0.0.1", port).start() + out = {} + try: + async with aiohttp.ClientSession() as s: + root = f"http://127.0.0.1:{port}/" + for key, body in ( + ("mode", {"action": "pack_mode", "unit": B, + "value": packmode.LEFTOVER_SOLAR}), + ("off", {"action": "pack_use", "unit": A, + "value": False}), + ("bad", {"action": "pack_mode", "unit": A, + "value": "grid_only"})): + async with s.post(root + "action", json=body) as r: + out[key] = (r.status, await r.json(content_type=None)) + async with s.get(root + "status") as r: + out["status"] = (r.status, await r.json(content_type=None)) + async with s.get(root) as r: + out["page"] = (r.status, await r.text()) + finally: + await runner.cleanup() + return out + + +_web = asyncio.run(_page()) +print(f" {_web['mode']} {_web['off']} {_web['bad']}") +check("POST /action with pack_mode and pack_use names a battery and a value, " + "and answers what it stored", + _web["mode"] == (200, {"ok": True, "result": { + "unit": B, "use": True, "mode": packmode.LEFTOVER_SOLAR}}) + and _web["off"][0] == 200 and _web["off"][1]["result"]["use"] is False) +check("...a value this release does not offer is a 400 with the plain reason " + "the page shows", + _web["bad"][0] == 400 and _web["bad"][1]["ok"] is False + and _web["bad"][1]["error"] == messages.pack_refused("value")) +_sb = {b["name"]: b for b in _web["status"][1].get("batteries", [])} +check("...and /status then shows both batteries' switch and mode for the " + "Batteries screen", + _web["status"][0] == 200 + and (_sb.get(A, {}).get("mode_key"), _sb.get(B, {}).get("mode_key")) + == ("off", packmode.LEFTOVER_SOLAR)) +check("the page carries the mode names from app/ui_text for its cards", + _web["page"][0] == 200 and "Leftover solar" in _web["page"][1] + and "Overschot zonne-energie" in _web["page"][1]) + + +print() +if fails: + print(f"{len(fails)} FAILED: {', '.join(fails)}") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 59c1076..53ae9b0 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2653,9 +2653,26 @@ check("...and so does the persistent notification, which outlives the page and " # # If you are here because you added a TWELFTH, that argument is what this line # wants from you, not an edit. +# ⚠️ SAFETY-73 ADDED `refused` (a P_SAFETY unit limit on a measured refusal). +# ⚠️ OPT-11 ADDED `mode`, ON PURPOSE, AND IT IS NOT THE DEFERRED RESERVE EITHER. +# `mode` is `Claim.limit("mode", P_MODE, lo, hi)` on ONE inverter's actuator: +# the owner's per-battery choice (on/off, Solar first, Leftover solar), filed +# only with `battery_modes_enabled` on (default off). It is not conditioned on +# a state of charge, and it cannot bound the site against the peak floor: +# 1. stage 1 keeps it APART from the hard limits (UnitBounds.mode_*), so it +# never enters a `lo > hi` test, not even the unit's own; +# 2. stage 3 applies it only while the site target was decided at or below +# P_MODE (35), so the guard's floor (P_PEAK, 50) RELEASES it, and at N=1 +# `resolve()` applies it to the site by the same rule, after stage 2; +# 3. its range always holds 0 W, so it can forbid a direction and never +# force one (a range without 0 is dropped as a software fault). +# test_arbiter.py part 9 grades the no-contradiction claim at N=2, over 625 +# cycles with the floor, and part 10 at N=1. The sweeps below never reach it: +# their fixtures leave battery modes off, so they still see {device, +# supervised, loop}. DECISIONS/OPT-11-battery-modes.md. CLAIM_SOURCES = {"device", "supervised", "failsafe", "safety", "peak", "arbitrage", "maintenance", "loop", "circulation", - "sign_site", "pack", "refused"} + "sign_site", "pack", "refused", "mode"} # The two appends that file a claim BUILT ELSEWHERE in the method. Named here so # that a THIRD such indirection reads as an unrecognised append rather than as a # silent gap in the scan. @@ -2697,7 +2714,7 @@ check("every `claims.append(...)` in main.py's cycle is one this scan can READ " "- a claim filed through a shape it cannot parse has to fail here rather " "than be counted as nothing, which is how a scan like this goes quietly " "vacuous", len(_appends) >= 10 and None not in _filed) -check("...and the sources that cycle can file are EXACTLY these TWELVE. THIS " +check("...and the sources that cycle can file are EXACTLY these THIRTEEN. THIS " "is what makes part 10 a tripwire: replay_loop() hand-builds the claim " "list, so it cannot see a claim main.py adds - and a loop-side SoC " "reserve is a new source. Filing one takes this line red on the line it " @@ -2849,7 +2866,7 @@ check("...and the split is the one ARB-03 argued, with SAFETY-31's and " == {"loop", "peak", "arbitrage", "safety", "circulation", "sign_site"} and {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == {"device", "supervised", "failsafe", "maintenance", "pack", - "refused"}) + "refused", "mode"}) # The shipped roster is ONE inverter, so §6.2's identity holds and every claim a # real cycle files is a site claim. Observed on the claims main.py's own resolve @@ -2947,6 +2964,7 @@ check("⚠️ AND THIS IS THE BREAKING HALF. Give the same Controller a second " _routed == {"device": "inverter-a", "supervised": "inverter-a", "failsafe": "inverter-a", "maintenance": "inverter-a", "pack": "inverter-a", "refused": "inverter-a", + "mode": "inverter-a", "loop": ACTUATOR_SITE, "peak": ACTUATOR_SITE, "arbitrage": ACTUATOR_SITE, "safety": ACTUATOR_SITE, "circulation": ACTUATOR_SITE, "sign_site": ACTUATOR_SITE}) @@ -3028,13 +3046,13 @@ _unit_sources_unrouted = [ if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT and "," not in r[1]] print(f" {len(_direct)} direct appends, each read at its own line: " + ", ".join(f"main.py:{ln} {s} -> {a}" for s, a, ln in _routing)) -check("all THIRTEEN of `Controller.cycle()`'s DIRECT appends route through " +check("all FOURTEEN of `Controller.cycle()`'s DIRECT appends route through " "`self.actuator_of(<string literal>)`, so this scan can read the routing " "of EVERY one of them. An append that computed its actuator, or omitted " "the argument, or hand-wrote a string, fails HERE rather than being " "silently skipped - which is how a scan like this goes quietly vacuous, " "and 10f is in this file because that already happened once", - len(_direct) == 13 + len(_direct) == 14 and all(a is not None and a.startswith("self.actuator_of('") for _s, a, _ln in _routing)) check("⚠️ AND AT EVERY ONE OF THE ELEVEN THE LITERAL IT ROUTES THROUGH IS THE " @@ -3051,15 +3069,15 @@ check("⚠️ AND EVERY PER-INVERTER APPEND NAMES THE INVERTER IT IS ABOUT. " "site-scoped sources and is the whole defect for a per-inverter one: a " "`device` limit built inside the roster loop and routed without `inv` " "files inverter B's rating on inverter A, where it binds the wrong " - "share. Eight of the thirteen appends are SCOPE_UNIT - `device`, " - "`supervised`, `failsafe`, maintenance's two, OPT-09's `pack` and " - "SAFETY-73's two `refused` - and all eight pass one. " + "share. Nine of the fourteen appends are SCOPE_UNIT - `device`, " + "`supervised`, `failsafe`, maintenance's two, OPT-09's `pack`, " + "SAFETY-73's two `refused` and OPT-11's `mode` - and all nine pass one. " "SAFETY-30's `sign_site` is deliberately NOT one of them: it is filed on " "the site, beside `circulation`, because the number that tripped it is " "the site target", _unit_sources_unrouted == [] and len([r for r in _routing - if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT]) == 8) + if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT]) == 9) check("...and the only appends this pin does NOT reach are the two that file a " "claim BUILT ELSEWHERE - `peak_claim` and `arb_claim` - which have no " "`actuator=` at the call site to mis-type. Their routing is pinned where " @@ -3068,7 +3086,8 @@ check("...and the only appends this pin does NOT reach are the two that file a " "arbitrage.claim() by test_arbitrage.py", sorted(_indirect) == sorted(CLAIM_BUILDERS) and len(_direct) + len(_indirect) == len(_appends)) -check("...and between them the fifteen appends account for exactly the twelve " +check("...and between them the sixteen appends account for exactly the " + "thirteen " "sources 10f pins, so the routing pin and the source set are one scan " "and neither can drift from the other", {s for s, _a, _ln in _routing} | set(CLAIM_BUILDERS.values()) @@ -3129,7 +3148,7 @@ check("...and naming those three is not an accident of this fixture but the " {c.source for c in _cl2} == CLAIM_SOURCES - {"failsafe", "safety", "maintenance", "peak", "arbitrage", "circulation", "sign_site", - "refused"}) + "refused", "mode"}) # ⚠️ AND NOW THE HALF THAT WAS EVIDENCE-SHAPED AND OBSERVED NOTHING. The three # checks above grade WHICH ACTUATOR each claim lands on. They say nothing about # WHOSE NUMBERS the bound is built from - and those are two different defects diff --git a/goodwe_controller/tools/alloc_sim.py b/goodwe_controller/tools/alloc_sim.py index f257d6d..9618c8d 100644 --- a/goodwe_controller/tools/alloc_sim.py +++ b/goodwe_controller/tools/alloc_sim.py @@ -5,6 +5,7 @@ python3 tools/alloc_sim.py --splits # AC 2: split-invariance at the meter python3 tools/alloc_sim.py --sweep # AC 3: gain to 1.0 at every split python3 tools/alloc_sim.py --all + python3 tools/alloc_sim.py --spill # OPT-11: surplus solar, by mode Exit 0 only if every split-invariance run HOLDS; 1 if one FAILS; 2 if no rig. @@ -245,12 +246,98 @@ def sweep(sitesim, control, watchdog, cycles, load_w): return worst +def spill(sitesim, control, arbiter, allocator, packmode, gain=0.6, + cycles=30, load_w=1000.0, pv_w=9000.0): + """OPT-11 P1: surplus solar spills from Solar first to Leftover solar. + + The rig's two plants and the add-on's own `compute()`, `resolve()`, + `loop_bound()` and `packmode.charge_weights()`, with the claims main.py + files for this state: each unit's rating, each unit's mode, the loop, and + OPT-09's `pack` limit (`lo = 0`) once battery A is full. A is Solar first + and B Leftover solar. Three phases of `cycles` each: A has room; A is full; + then B is switched off. The loop is fed the site total (DEV-02). + Returns (rows, verdicts). + """ + from plantsim import INVERTER_A, INVERTER_B, Inverter, Site + names = ("inverter-a", "inverter-b") + specs = [("A", INVERTER_A), ("B", INVERTER_B)] + invs = [Inverter.from_spec(n, dict(sp, **sitesim.INSTANT)) + for n, sp in specs] + site = Site(invs, load=load_w, pv=pv_w) + tun = control.Tuning(gain=gain, max_w=sum(sp["rating_w"] for _n, sp in specs), + slew_w=sitesim.EXPERIMENT_SLEW_W) + C = arbiter.Claim + prev, i_w, sat = 0.0, None, 0 + rows = [] + phases = (("A has room", False, True), ("A full", True, True), + ("A full, B off", True, False)) + for label, a_full, b_on in phases: + modes = {names[0]: packmode.PackMode(True, packmode.SOLAR_FIRST), + names[1]: packmode.PackMode(b_on, packmode.LEFTOVER_SOLAR)} + for _c in range(cycles): + claims = [] + for u, (_n, sp) in zip(names, specs): + r = sp["rating_w"] + claims.append(C.limit("supervised", arbiter.P_SAFETY, -r, r, + actuator=u)) + lo, hi = packmode.mode_range(modes[u], r) + claims.append(C.limit("mode", arbiter.P_MODE, lo, hi, + actuator=u)) + if a_full: + claims.append(C.limit("pack", arbiter.P_SAFETY, lo=0.0, + actuator=names[0])) + bound = allocator.loop_bound( + {u: arbiter.pre_resolve([c for c in claims if c.actuator == u]) + for u in names}) + d = control.compute(prev, site.grid, site.battery, tun, sat, i_w, + bound=bound) + prev, i_w, sat = d.target_w, d.i_w, d.sat_count + claims.append(C.set("loop", arbiter.P_LOOP, d.target_w)) + res = arbiter.resolve( + claims, units=names, + weights=lambda t: packmode.charge_weights(None, modes, t)) + for inv, u in zip(invs, names): + inv.command(float(res.shares[u])) + site.settle(sitesim.CYCLE_S, dt=0.05) + rows.append(dict(phase=label, target=d.target_w, grid=site.grid, + a=res.shares[names[0]], b=res.shares[names[1]], + unmet=res.allocation.unmet_w, frozen=d.frozen, + reason=d.reason, bound=bound)) + return rows + + +def spill_report(rows, cycles): + print("=== OPT-11 P1: surplus solar, A Solar first, B Leftover solar ===") + ok = True + for label in dict.fromkeys(r["phase"] for r in rows): + ph = [r for r in rows if r["phase"] == label] + last = ph[-1] + frozen = sum(r["frozen"] for r in ph) + print(f" {label:15} A {last['a']:+6.0f} W B {last['b']:+6.0f} W " + f"grid {last['grid']:+7.0f} W loop bound " + f"[{last['bound'][0]:.0f}, {last['bound'][1]:.0f}] " + f"unmet {last['unmet']} W frozen cycles {frozen} " + f"({last['reason']})") + ok &= frozen == 0 and all(r["a"] <= 0 and r["b"] <= 0 for r in ph) + if label == "A has room": + ok &= last["a"] == -5000 and last["b"] < 0 + elif label == "A full": + ok &= last["a"] == 0 and last["b"] == -5000 + else: + ok &= last["a"] == 0 and last["b"] == 0 and last["unmet"] == 0 + print(f" -> spill {'HOLDS' if ok else 'FAILS'}: A fills first, the rest " + f"spills to B, a full A and an Off B send the surplus to the grid, " + f"and the loop never freezes on watts no battery may take") + return ok + + def main(): ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) ap.add_argument("--table", action="store_true") ap.add_argument("--splits", action="store_true") ap.add_argument("--sweep", action="store_true") ap.add_argument("--all", action="store_true") + ap.add_argument("--spill", action="store_true") ap.add_argument("--cycles", type=int, default=40) ap.add_argument("--load", type=float, default=2000.0) ap.add_argument("--gain", type=float, default=1.0) @@ -261,7 +348,7 @@ def main(): "or one inverter's power (the PRE-DEV-02 sensing, " "kept because the comparison is the evidence)") a = ap.parse_args() - if not (a.table or a.splits or a.sweep): + if not (a.table or a.splits or a.sweep or a.spill): a.all = True sim = find_sim() @@ -288,6 +375,11 @@ def main(): print() if a.sweep or a.all: sweep(sitesim, control, watchdog, a.cycles, a.load) + print() + if a.spill or a.all: + packmode = sitesim.load_addon("app.packmode", "alloc_sim") + held &= spill_report(spill(sitesim, control, arbiter, allocator, + packmode), 30) return 0 if held else 1 diff --git a/goodwe_controller/tools/opt11_identity.py b/goodwe_controller/tools/opt11_identity.py new file mode 100644 index 0000000..49764f4 --- /dev/null +++ b/goodwe_controller/tools/opt11_identity.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +"""OPT-11: with battery modes off, is every command byte-identical to before? + + python3 tools/opt11_identity.py # prints one digest per scenario + +Drives the REAL `Controller` (read_inputs + cycle: the freshness gate, the +arbiter, the allocator, OPT-09's pack claim, SAFETY-73's refusal claims) in +simulated time, and hashes, per cycle, everything a command depends on: the +site target, each inverter's written value, the loop's reason, integrator and +saturation count, and the allocation record. It uses only the Controller API +that release/1.0 a5dddad already had, so the SAME file runs on the old tree and +the new one. test_modes.py part 1 holds the new tree to the digests this file +printed on a5dddad (they are written there, with that provenance). + +Scenarios: N=1 and N=2, a house that steps, a surplus of solar, a battery +reaching its cut-out level and, at N=2, a battery that refuses (SAFETY-73) and +is probed. +""" + +import asyncio +import hashlib +import os +import sys +from datetime import datetime, timedelta, timezone + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +import app.main as m # noqa: E402 +from app.main import Controller # noqa: E402 + +TICK = 5.0 +BASE = datetime(2026, 9, 20, 11, 0, tzinfo=timezone.utc) + + +class _Store: + def __init__(self): + from app.store import DEFAULTS + self.data = dict(DEFAULTS) + + def set(self, k, v): + self.data[k] = v + + def get_time(self, k): + v = self.data.get(k) + return datetime.fromisoformat(v) if v else None + + def set_time(self, k, when): + self.data[k] = when.isoformat() if when else None + + +class _Pub: + enabled = False + + def publish(self, *a, **k): + pass + + def close(self): + pass + + +def house(t): + """A house that steps, then a solar surplus, then an evening load.""" + if t < 300: + return 800.0 + if t < 900: + return 3200.0 + if t < 1500: + return -2600.0 # more solar than the house uses + if t < 2100: + return 1400.0 + return 4200.0 + + +class _Hass: + """One meter, `units` batteries that follow their command unless `cut`.""" + + def __init__(self, units, soc, cut, load=house): + self.units, self.soc, self.cut, self.load = units, soc, cut, load + self.cmd = {u: 0.0 for u in units} + self.t = 0.0 + + def power(self, u): + c = self.cmd[u] + if self.cut(u, self.t) and c >= -4.0: + return -4.0 + return float(round(c)) + + def grid(self): + return self.load(self.t) - sum(self.power(u) for u in self.units) + + async def limits(self, e): + return (-5000.0, 5000.0, 1.0) + + async def call(self, *a): + return True + + async def number(self, e, invert=False): + if e == "sensor.grid": + return self.grid() + u = e[-1] + if e.startswith("sensor.soc"): + return self.soc(u, self.t) + if e.startswith("sensor.batt"): + return self.power(u) + return None + + async def set_number(self, e, v): + self.cmd[e[-1]] = float(v) + return True + + +def _options(n, extra): + common = {"meter_entity": "sensor.grid", "meter_source": "off", + "gain": 0.6, "slew_w": 400, "target_grid_w": -10, + "deadband_w": 15, "step_w": 10, "heartbeat_s": 10, + "stale_input_s": 15, "auto_start": True} + if n == 1: + common.update({"setpoint_entity": "number.sp_a", + "soc_entity": "sensor.soc_a", + "batt_entity": "sensor.batt_a", "max_w": 5000, + "bms_soc_floor": 10}) + else: + common["inverters"] = [ + {"name": f"inverter-{u}", "setpoint_entity": f"number.sp_{u}", + "soc_entity": f"sensor.soc_{u}", "batt_entity": f"sensor.batt_{u}", + "max_w": 2500, "bms_soc_floor": 10} for u in "ab"[:n]] + common.update(extra or {}) + return common + + +def _soc(u, t): + # A empties toward its cut-out level over the run; B stays half full. + return max(8.0, 60.0 - t / 40.0) if u == "a" else 50.0 + + +def run(n, *, extra=None, dur=2700.0, store=None, on_cycle=None, load=house, + soc=_soc, cut=None, before=None): + """Cycle a real Controller; returns (rows, controller). `before(c, t)` + runs before each cycle, `on_cycle(c, t)` after it.""" + units = tuple("ab"[:n]) + if cut is None: + def cut(u, t): + return n > 1 and u == "a" and 1600.0 <= t < 2300.0 + + async def go(): + hass = _Hass(units, soc, cut, load) + c = Controller(_options(n, extra), hass, store or _Store(), _Pub(), + stop=asyncio.Event()) + for i in c.inverters: + i.dev_min, i.dev_max = -5000.0, 5000.0 + c.auto = True + real_dt = m.datetime + clock = [0.0] + + class _DT(real_dt): + @classmethod + def now(cls, tz=None): + return BASE + timedelta(seconds=clock[0]) + + m.datetime = _DT + rows = [] + try: + t = 0.0 + while t < dur: + hass.t = clock[0] = t + if before is not None: + r = before(c, t) + if asyncio.iscoroutine(r): + await r + await c.read_inputs(now_mono=t) + await c.cycle() + alloc = getattr(c, "allocation", None) + rows.append((t, c.target, tuple(sorted(hass.cmd.items())), + c.loop_reason, round(float(c.i_w), 6), + c.sat_count, c.reason, + alloc.explain() if alloc is not None else None)) + if on_cycle is not None: + on_cycle(c, t) + t += TICK + finally: + m.datetime = real_dt + return rows, c + return asyncio.run(go()) + + +def digest(rows) -> str: + return hashlib.sha256(repr(rows).encode()).hexdigest() + + +SCENARIOS = { + "n1": dict(n=1), + "n2": dict(n=2), + # The option present and false: what an install that saved the new + # option without turning it on runs. The old tree ignores the key. + "n1_off": dict(n=1, extra={"battery_modes_enabled": False}), + "n2_off": dict(n=2, extra={"battery_modes_enabled": False}), +} + + +def digests() -> dict: + return {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} + + +if __name__ == "__main__": + if "--summary" in sys.argv: + for k, v in SCENARIOS.items(): + rows = run(**v)[0] + print(f"{k}: {len(rows)} cycles, loop reasons " + f"{sorted({r[3] for r in rows})}, arbiter " + f"{sorted({r[6].split(' ->')[0] for r in rows})}") + for k, v in digests().items(): + print(f"{k} {v}") diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index 4598deb..7fdf628 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -82,6 +82,9 @@ configuration: estop_fitted: name: "Hardware · RS485 emergency stop is fitted" description: "Switch this on if the emergency stop is installed. It only changes a warning on the status page." + battery_modes_enabled: + name: "Hardware · Battery modes" + description: "Give each battery an on and off switch and a mode, set on the Batteries screen." pv_entity: name: "Hardware · Solar production entity (W)" description: "Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index 49476cd..65e7881 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -63,6 +63,9 @@ configuration: estop_fitted: name: "Hardware · RS485-noodstop is geplaatst" description: "Zet dit aan als de noodstop geïnstalleerd is. Het verandert alleen een waarschuwing op de statuspagina." + battery_modes_enabled: + name: "Hardware · Batterijmodi" + description: "Geef elke batterij een aan- en uitschakelaar en een modus, in te stellen op het scherm Batterijen." pv_entity: name: "Hardware · Entiteit zonneproductie (W)" description: "Optioneel. De vermogenssensor van uw zonne-omvormer, positief tijdens productie. De add-on houdt ze bij en regelt er niet mee." -- 2.54.0 From ffc9a4d7210909ad75546c318e6ce13822e381cd Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Mon, 28 Sep 2026 19:41:36 +0200 Subject: [PATCH 067/105] OPT-11 P1 review: a mode never beats the peak floor; SAFETY-03 kept at the rail - arbiter: a mode now gives way only as far as a site limit above P_MODE needs (_unit_modes at N>1, _site_mode at N=1). Before, the modes were released only when the peak floor bound S, so a trade won above the floor kept them and placed less than the floor (an Off battery at N=1 went to 0 W under a 2000 W floor), and a capped grid charge released an Off battery. While released, held batteries weigh 0 and carry only the shortfall. - control: a side of the loop bound that reaches the rail is left to the rail, so SAFETY-03's i_clamped still fires with every battery on. - opt11_identity: add maintenance scenarios and a 6000-case arbiter digest (peak floor, trades, maintenance, refusals); a5dddad digests pinned. - tests: test_arbiter part 11, test_control (g), test_modes (0/1 refused, loop bound counts live units only). DOCS and DECISIONS say the new rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV --- .../DECISIONS/OPT-11-battery-modes.md | 17 ++- goodwe_controller/DOCS.md | 4 +- goodwe_controller/app/allocator.py | 6 +- goodwe_controller/app/arbiter.py | 128 +++++++++++++++--- goodwe_controller/app/control.py | 14 +- goodwe_controller/app/main.py | 6 +- goodwe_controller/test_arbiter.py | 96 +++++++++++++ goodwe_controller/test_control.py | 24 ++++ goodwe_controller/test_modes.py | 29 +++- goodwe_controller/tools/opt11_identity.py | 81 ++++++++++- 10 files changed, 365 insertions(+), 40 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index d996e48..0f7bfba 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -1,14 +1,21 @@ # OPT-11 - battery modes, per battery A battery's mode (on/off, Solar first, Leftover solar) is a soft unit limit at -`P_MODE` = 35 that always holds 0 W, applies only while the site target is -decided at or below 35, and is released by anything above it, such as the peak -guard. Design and owner answers: `goodwe-session/OPT-11-design.md` (2026-09-27); +`P_MODE` = 35 that always holds 0 W. A SET above 35 (a safety stop) overrides +it; a limit above 35 (the peak guard) makes it give way only as far as that +limit needs, and a battery its mode holds back then carries only what the +others cannot (`arbiter._unit_modes()`, `_site_mode()`). Design and owner answers: `goodwe-session/OPT-11-design.md` (2026-09-27); P1 is its section 6 P1, and the pull request lists what was measured. - Off by default (`battery_modes_enabled`); off, commands are byte-identical to a5dddad (`test_modes.py` part 1). -- Off is a mode range, so the peak guard can still use an Off battery (design - sections 2-3). Whether Off should be absolute is an open owner question. +- Off is a mode range, so the peak guard can still use an Off battery when the + others cannot cover the floor (design sections 2-3). Whether Off should be + absolute is an open owner question. +- Review (PR #149): releasing only when the peak floor bound S let a trade won + above the floor keep the modes and place less than the floor, and let a + capped grid charge release an Off battery. Both are graded in + `test_arbiter.py` part 11. The loop bound leaves a side that reaches the + rail to the rail, so SAFETY-03 still flags a loop winding into it. - In P1 only Off closes a direction; Leftover solar differs by charging last. Price runs, selling (`pack_sell`, reserved) and the forecast are P3/P4. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index a23e7ce..4f36859 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -517,12 +517,12 @@ below. Off by default. Turn it on, restart the add-on, and the Batteries screen gives each battery two controls. They apply at once, with no restart. -- **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, like every battery. +- **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, but only for what the other batteries cannot cover. - **Mode.** *Solar first* charges from spare solar before the other batteries. *Leftover solar* charges from the solar they cannot take. Both cover the house at any hour. Charging from the grid in cheap hours, and selling, come in a later update. The peak limit, the safety stops and the monthly cycle always come before a battery's mode. -*For installers:* a mode is a limit at priority 35, kept apart from the hard limits, and released whenever a claim above it (the peak guard) decides the site target. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. +*For installers:* a mode is a limit at priority 35, kept apart from the hard limits. It gives way only as far as a limit above it (the peak guard) needs. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. ### Reading the grid-following loop: `Loop integrator`, `Loop integrator lead`, `Loop reason` diff --git a/goodwe_controller/app/allocator.py b/goodwe_controller/app/allocator.py index b4bce23..9ddef8b 100644 --- a/goodwe_controller/app/allocator.py +++ b/goodwe_controller/app/allocator.py @@ -304,9 +304,9 @@ def unit_interval(b, deciding_priority=None): """OPT-11. `(lo, hi, note)`: the interval a unit is allocated into. The hard limits (`b.lo`, `b.hi`) always apply. The unit's MODE range - (`b.mode_lo`, `b.mode_hi`) narrows them only when the site target was - decided at or below the mode's own priority - `deciding_priority` None - means no higher claim was named, so the mode applies. `note` says why the + (`b.mode_lo`, `b.mode_hi`) narrows them unless `deciding_priority` is + above the mode's own priority (arbiter._unit_modes() passes None when the + modes hold, and the yielding limit's priority when they give way). `note` says why the mode did not apply, or is None when it did or there is none: * MODE_FAULT: the mode range leaves out 0 W. A mode may forbid a direction diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 4eda428..5d69d1d 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -87,9 +87,9 @@ P_MAINT_SHAPE = 40 # maintenance shaping the loop (charge-only) # loop would otherwise cancel every charge the moment it created import. P_ARBITRAGE = 30 # price arbitrage - trades against the meter on purpose # OPT-11. A battery's mode (Solar first, Leftover solar, Off): a SOFT unit -# limit, kept apart from the hard ones and applied only while the site target -# is decided at or below this priority. Above arbitrage, so a trade stays inside -# each battery's mode; below the peak guard, which releases every mode. +# limit, kept apart from the hard ones. Above arbitrage, so a trade stays inside +# each battery's mode; below the peak guard, to which a mode gives way only as +# far as the floor needs (`_unit_modes()`, `_site_mode()`). # DECISIONS/OPT-11-battery-modes.md. P_MODE = 35 P_LOOP = 10 # ordinary grid-following @@ -250,8 +250,8 @@ CLAIM_SCOPE = { # main.py: `Claim.limit("mode", P_MODE, lo, hi, ...)`, OPT-11. THIS # battery's mode, chosen per battery by its owner. A unit claim that never # enters a `lo > hi` test with a site limit: stage 1 keeps it apart from the - # hard limits, and stage 3 applies it only when the site target was decided - # at or below P_MODE. At N=1 it routes to the site like every source, and + # hard limits, and it gives way to a site limit above P_MODE only as far as + # that limit needs (`_unit_modes()`). At N=1 it routes to the site, and # `resolve()` takes it out of stage 2 for the same reason. "mode": SCOPE_UNIT, } @@ -434,9 +434,10 @@ class Resolution: # `explain()` names. winner_priority: int | None = None # OPT-11. The higher of the winning set's priority and the priority of the - # limit that bound `target_w`. Stage 3 applies each unit's mode only when - # this is at or below that mode's priority (P_MODE), so a peak floor that - # binds S (P_PEAK) releases every mode and never meets a mode `hi`. + # limit that bound `target_w`. Whether the modes hold is decided from the + # limits themselves (`_site_mode()`, `_unit_modes()`): a mode gives way + # only as far as a limit above it (the peak floor) needs, so a mode `hi` + # never meets a site `lo`. deciding_priority: int | None = None # OPT-11 at N=1: why the site's mode layer was dropped this tick, or None. # At N>1 the same fact is on `allocation.mode_faults`, per unit. @@ -676,7 +677,7 @@ def resolve(claims: list, *, units=None, weights=None, live=None, # `claims`, so this is the shipped arbiter on the shipped list. out = site_resolve(site_claims) if site_modes: - _site_mode(out, site_modes) + _site_mode(out, site_modes, site_claims) # STAGE 3 - the seam, and since ALLOC-01 the allocator behind it. # @@ -709,23 +710,67 @@ def resolve(claims: list, *, units=None, weights=None, live=None, # nothing. See `packshare.weights()` on the residual this leaves (the fill's # own direction can differ from the target's sign under a pin, in which case # the weighting is a worse preference and still cannot be unsafe). + # OPT-11: whether each unit's mode holds this tick (`_unit_modes()`). + # Before the weights, because a limit above the modes may move the target. + gate, held = _unit_modes(out, site_claims, bounds, live) if callable(weights): weights = weights(out.target_w) + if held: + weights = {u: (0.0 if u in held else + (1.0 if weights is None else weights.get(u, 1.0))) + for u in bounds} out.shares, out.allocated, out.allocation = allocate_record( out.target_w, bounds, weights=weights, live=live, scope_errors=out.scope_errors, site_priority=out.winner_priority, - tick=tick, deciding_priority=out.deciding_priority) + tick=tick, deciding_priority=gate) return out -def _site_mode(out: Resolution, modes: list) -> None: +def _limits_above(site_claims: list, prio: int) -> tuple: + """OPT-11: `(lo, lo_src, hi, hi_src)` over the site LIMITs above `prio`. + + These are what a mode may never take the site target outside of: the peak + guard (P_PEAK), maintenance shaping (P_MAINT_SHAPE) and the hard limits. + """ + lo, hi = -inf, inf + lo_src = hi_src = None + for c in site_claims: + if c.kind != LIMIT or c.priority <= prio: + continue + if c.lo > lo: + lo, lo_src = c.lo, c + if c.hi < hi: + hi, hi_src = c.hi, c + return lo, lo_src, hi, hi_src + + +def _yield_to(out: Resolution, t1: float, above: tuple): + """OPT-11: the target `t1` the modes allow, moved only as far as the limits + above the mode need (`_limits_above()`). Returns the claim that moved it, + or None when `t1` already satisfies them, and sets `out.target_w`.""" + lo, lo_src, hi, hi_src = above + t2 = max(lo, min(hi, t1)) + out.target_w = float(t2) + if t2 == t1: + return None + binder = lo_src if t2 == lo else hi_src + out.bound_by = (f"{binder.source}({binder.reason})" if binder.reason + else binder.source) + out.deciding_priority = max(out.deciding_priority or binder.priority, + binder.priority) + return binder + + +def _site_mode(out: Resolution, modes: list, site_claims: list) -> None: """OPT-11 at N=1: the one battery's mode bounds the SITE target, after stage 2. - The unit rule of `allocator.unit_interval()` on the site: the mode applies - only when stage 2 decided at or below its priority, and a range without 0 W - is a software fault that drops the mode (`out.mode_fault`). A clamp of one - number into a range that holds 0 cannot contradict anything, so the peak - floor still wins by releasing the mode, as at N>1. + A SET above the mode (a safety stop) decides alone. Otherwise the target is + clamped into the mode range and then back into the site limits above the + mode, so the mode gives way only as far as those limits need: a peak floor + of 2000 W over an Off battery asks it for 2000 W, whether a trade or the + loop won stage 2, and a charge the peak guard merely caps stays at 0 W. A + range without 0 W is a software fault that drops the mode + (`out.mode_fault`). Clamping one number cannot contradict anything. """ out.considered = out.considered + [f"{c.source}:{c.kind}" for c in modes] lims = [c for c in modes if c.kind == LIMIT] @@ -737,10 +782,53 @@ def _site_mode(out: Resolution, modes: list) -> None: if not (lo <= 0.0 <= hi): out.mode_fault = f"mode range [{lo:.0f}, {hi:.0f}] leaves out 0 W" return - if out.deciding_priority is not None and out.deciding_priority > prio: + if out.winner_priority is not None and out.winner_priority > prio: return - target = max(lo, min(hi, out.target_w)) - if target != out.target_w: + before = out.target_w + t1 = max(lo, min(hi, before)) + if _yield_to(out, t1, _limits_above(site_claims, prio)) is None \ + and t1 != before: c = lims[0] out.bound_by = f"{c.source}({c.reason})" if c.reason else c.source - out.target_w = float(target) + + +def _unit_modes(out: Resolution, site_claims: list, bounds: dict, live): + """OPT-11 at N>1: `(gate, held)` for stage 3. + + `gate` is the `deciding_priority` handed to the allocator: None applies + every unit's mode, a number above P_MODE releases them. `held` is the set + of units whose mode holds them back in the target's direction; while the + modes are released they weigh 0, so they carry only what the other units + cannot (the allocator's last-resort pass). + + The rule matches N=1: a SET above the mode decides alone. Otherwise the + target is clamped into what the units can place with their modes + (`allocator.loop_bound()`) and back into the site limits above the mode. + If that point is still placeable with the modes, they hold and the target + is unchanged (what they cannot place is reported unmet, as before). If a + limit above the mode needs more, the target moves only that far, and the + modes are released for it. + """ + mode_units = [u for u, b in bounds.items() + if getattr(b, "mode_priority", None) is not None] + if not mode_units or out.contradiction: + return out.deciding_priority, set() + prio = min(bounds[u].mode_priority for u in mode_units) + if out.winner_priority is not None and out.winner_priority > prio: + return out.deciding_priority, set() + clo, chi = allocator.loop_bound(bounds, live) + t1 = max(clo, min(chi, out.target_w)) + before = out.target_w + binder = _yield_to(out, t1, _limits_above(site_claims, prio)) + if binder is None: + out.target_w = float(before) + return None, set() + held = set() + for u in mode_units: + b = bounds[u] + nlo, nhi, note = allocator.unit_interval(b) + if note is not None: + continue + if (nhi < b.hi) if out.target_w > 0 else (nlo > b.lo): + held.add(u) + return binder.priority, held diff --git a/goodwe_controller/app/control.py b/goodwe_controller/app/control.py index 12d1134..8e01509 100644 --- a/goodwe_controller/app/control.py +++ b/goodwe_controller/app/control.py @@ -17,6 +17,7 @@ exists because its absence produced a specific, observed failure. """ import math +from math import inf from dataclasses import dataclass # --------------------------------------------------------------------------- @@ -500,6 +501,14 @@ def compute( # main.py never builds one: every term of `loop_bound()` holds 0). if bound is not None and not (bound[0] <= 0.0 <= bound[1]): bound = None + # ...and a side of it that reaches the rail is left to the rail, so that + # SAFETY-03's `i_clamped` still fires when the loop winds into it. With + # every battery on, the bound IS the rail, and the law is exactly as it was. + if bound is not None: + _rail = min(tuning.max_w, tuning.max_w if tuning.integrator_max_w is None + else tuning.integrator_max_w) + bound = (float(bound[0]) if bound[0] > -_rail else -inf, + float(bound[1]) if bound[1] < _rail else inf) # --- saturation, WITH the duration term ------------------------------- # Command and actual diverging means the inverter cannot follow - it is at @@ -603,9 +612,8 @@ def compute( i_w = max(moved, i_w) # OPT-11: the integrator does not wind past what the modes let the - # batteries place. Applied BEFORE the integrator bound below, so a loop - # held by a mode reads as `mode-bound` and not as SAFETY-03's winding into - # the rail (`i_clamped`). That bound still bites where it is the tighter. + # batteries place. Only a side tighter than the rail is left in `bound` + # (above), so this never takes SAFETY-03's `i_clamped` away from the rail. if bound is not None: held = max(float(bound[0]), min(float(bound[1]), i_w)) if held != i_w: diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ed80798..4cdaaf2 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -3692,9 +3692,9 @@ class Controller: # Filed only with battery modes on, and never on a battery in any # maintenance phase: maintenance at 60/40 outranks the mode. The range # always holds 0 W (packmode.mode_range()). pre_resolve() keeps it - # apart from the hard limits, and the allocator applies it only while - # the site target is decided at or below P_MODE, so the peak guard's - # site floor (P_PEAK) releases it and never meets it in a `lo > hi`. + # apart from the hard limits, and it gives way to the peak guard's + # site floor (P_PEAK) only as far as the floor needs, so the two never + # meet in a `lo > hi` (arbiter._unit_modes()). if self.modes_on: for inv, result in zip(self.inverters, maint_results): if result.phase != IDLE: diff --git a/goodwe_controller/test_arbiter.py b/goodwe_controller/test_arbiter.py index 6a8b6fe..071fb64 100644 --- a/goodwe_controller/test_arbiter.py +++ b/goodwe_controller/test_arbiter.py @@ -694,6 +694,102 @@ check("...and with no mode claim at all, stage 2's answer is untouched " resolve([Claim.set("loop", P_LOOP, 1200.0)], units=ONE).target_w == 1200.0) +print() +print("OPT-11 11. a mode gives way only as far as the peak limit needs") +# Review of PR #149. The first cut released the modes only when a limit above +# P_MODE bound S. A trade (30) that won above the peak floor then kept the +# modes, and the units placed less than the floor: the mode beat the peak +# guard (a billed peak). And a peak limit that merely capped a charge released +# the modes, so an Off battery was charged from the grid. The rule now: clamp +# into what the modes can place, then back into the limits above the mode. +_offb = {"inverter-b": (0.0, 0.0)} + + +def _placed(r): + return sum(r.shares.values()) + + +_ra = resolve(_two(0.0, arb=3000.0, peak_lo=2000.0, rating=1500.0, + modes=_offb)[:-1] + [ + Claim.set("arbitrage", P_ARBITRAGE, 3000.0), + Claim.limit("peak", P_PEAK, lo=2000.0)], units=TWO) +print(f" trade 3000 W over a 2000 W floor, A 1500 W, B off: {_ra.shares}") +check("⭐ a trade above the peak floor with B Off: the units still place the " + "floor (2000 W), A to its rating and B only the 500 W A cannot give", + _placed(_ra) == 2000 and _ra.shares == {"inverter-a": 1500, + "inverter-b": 500}) +_r1t = resolve(_one + [Claim.set("arbitrage", P_ARBITRAGE, 3000.0), + Claim.limit("peak", P_PEAK, lo=2000.0)], units=ONE) +check("⭐ ...and at N=1 an Off battery under a trade gives the peak floor " + "(2000 W), not 0 W", _r1t.target_w == 2000.0 + and _r1t.bound_by == "peak") +_rc = resolve(_two(0.0, arb=-3000.0, peak_lo=-1000.0, modes=_offb), + units=TWO) +check("⭐ a grid charge the peak limit caps at 1000 W does not release B's " + "Off: A takes it all and B stays at 0 W", + _rc.shares == {"inverter-a": -1000, "inverter-b": 0}) +_r1c = resolve(_one + [Claim.set("arbitrage", P_ARBITRAGE, -3000.0), + Claim.limit("peak", P_PEAK, lo=-1000.0)], units=ONE) +check("...and at N=1 an Off battery is not charged from the grid under a " + "capped trade", _r1c.target_w == 0.0) +_rp = resolve(_two(500.0, peak_lo=1500.0, modes=_offb), units=TWO) +check("a peak floor A can carry alone leaves B Off at 0 W", + _rp.shares == {"inverter-a": 1500, "inverter-b": 0} + and _rp.target_w == 1500.0) +_rall = resolve(_two(0.0, peak_lo=3000.0, + modes={"inverter-a": (0.0, 0.0), + "inverter-b": (0.0, 0.0)}), units=TWO) +check("every battery Off and a 3000 W peak floor: the floor is placed, " + "split between them, and nothing contradicts", + _placed(_rall) == 3000 and not _rall.contradiction + and _rall.allocation.refused is None) + +import random as _rnd # noqa: E402 +_g = _rnd.Random(149) +_worse, _needless, _sign, _nn = [], [], [], 0 +for _ in range(20000): + _units = ("inverter-a", "inverter-b", "inverter-c")[:_g.choice((2, 3))] + _cl = [] + for _u in _units: + _rt = _g.choice((1000.0, 2500.0)) + _cl.append(Claim.limit("supervised", P_SAFETY, -_rt, _rt, + actuator=_u)) + if _g.random() < 0.2: + _cl.append(Claim.limit("pack", P_SAFETY, + *_g.choice(((0.0, inf), (-inf, 0.0))), + actuator=_u)) + _cl.append(Claim.limit(MODE_SOURCE, P_MODE, + _g.choice((0.0, -_rt)), _g.choice((0.0, _rt)), + actuator=_u)) + _src = _g.choice(("loop", "arbitrage")) + _cl.append(Claim.set(_src, P_LOOP if _src == "loop" else P_ARBITRAGE, + _g.uniform(-7000.0, 7000.0))) + _pk = _g.uniform(-4000.0, 6000.0) + _cl.append(Claim.limit("peak", P_PEAK, lo=_pk)) + _r = resolve(_cl, units=_units) + _r0 = resolve([c for c in _cl if c.source != MODE_SOURCE], units=_units) + _nn += 1 + if _r.allocation.refused is not None: + _sign.append(_cl) + continue + if _placed(_r) < _pk - 1 and _placed(_r0) >= _pk - 1: + _worse.append(_cl) + # An Off unit gives power only when the peak floor is short without it. + _off = [c.actuator for c in _cl if c.source == MODE_SOURCE + and c.lo == 0.0 and c.hi == 0.0] + # What the units whose mode lets them give power can give, within it. + _on_cap = sum(max(0.0, min(_r.unit_bounds[u].hi, _r.unit_bounds[u].mode_hi)) + for u in _units if _r.unit_bounds[u].mode_hi > 0.0 + and _r.unit_bounds[u].lo <= 0.0) + if any(_r.shares.get(u, 0) > 0 for u in _off) and _pk <= _on_cap - 1: + _needless.append(_cl) +check(f"over {_nn} random N=2/3 cycles (modes, packs, a trade or the loop, a " + f"peak floor): no split is refused, the placed power never falls under " + f"the floor where the same cycle without modes met it, and an Off " + f"battery gives power only when the others cannot carry the floor " + f"({len(_sign)}, {len(_worse)}, {len(_needless)})", + not _sign and not _worse and not _needless) + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") diff --git a/goodwe_controller/test_control.py b/goodwe_controller/test_control.py index 668d2bd..9db66c2 100644 --- a/goodwe_controller/test_control.py +++ b/goodwe_controller/test_control.py @@ -1268,6 +1268,30 @@ for _ in range(4000): check("a bound wider than the rail changes no Decision (4000 random cycles)", _wide) +# (g) Review of PR #149: a bound EQUAL to the rail - every battery on, the +# default once modes are on - must leave SAFETY-03 exactly as it was. Before +# the fix the mode clamp ran first and took `i_clamped` away from the rail. +_rail_same, _rail_hits = True, 0 +for _tb in (TB, Tuning(gain=0.6, max_w=5000.0, slew_w=400.0, deadband_w=15.0, + step_w=10, target_grid_w=-10.0, + integrator_max_w=7000.0)): + _lim = _tb.max_w + for _ in range(4000): + args = (_rngc.uniform(-5000, 5000), _rngc.uniform(-12000, 12000), + _rngc.uniform(-5000, 5000), _tb, _rngc.randint(0, 5), + _rngc.choice((None, _rngc.uniform(-8000, 8000)))) + _d0 = compute(*args) + _rail_hits += _d0.i_clamped + if compute(*args, bound=(-_lim, _lim)) != _d0: + _rail_same = False +check(f"a bound equal to the rail changes no Decision, SAFETY-03's i_clamped " + f"included ({_rail_hits} of 8000 random cycles wind into the rail), and " + f"with integrator_max_w above max_w too", _rail_same and _rail_hits > 100) +_one_side = compute(4000.0, 12000.0, 4000.0, TB, 0, 4990.0, + bound=(0.0, 5000.0)) +check("...and a bound that closes only the other side still lets the rail " + "flag a loop winding into it", _one_side.i_clamped) + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") diff --git a/goodwe_controller/test_modes.py b/goodwe_controller/test_modes.py index 0acb952..2f47c4f 100644 --- a/goodwe_controller/test_modes.py +++ b/goodwe_controller/test_modes.py @@ -98,6 +98,12 @@ A5DDDAD = { "n2": "a60003b1930fa3cba21f3220670d9172b9ff438347d77ba9bc3383fca1ceb15a", "n1_off": "fc3bca170c46920f08d86baee62ea883954a89ea6222d6bbf7d6652877226262", "n2_off": "a60003b1930fa3cba21f3220670d9172b9ff438347d77ba9bc3383fca1ceb15a", + # Added in review (PR #149), printed on a5dddad the same way: both + # batteries due for maintenance, and the arbiter alone on 6000 seeded + # claim lists with the peak floor, trades, maintenance and refusals. + "n1_maint": "5a21d43ec7cbf95a224bbb9bca13a8e62a00161101b586ae9fa68ab565992977", + "n2_maint": "48a1ad96121592e207a4664fb2da9f5208a49b88e5802a358873a5d30cb8c18e", + "resolve": "43a874216711936e14b9185bcc8d26c58fe4f3cfc3c1c8eaf89bffd95d6e81ef", } _claims, _undo_c = spy_claims() _bounds, _undo_b = spy_bounds() @@ -112,7 +118,8 @@ for k in A5DDDAD: check("⭐ at N=1 and N=2, with the option absent and with it false, every " "command, reason and allocation record over 540 cycles each is " "byte-identical to a5dddad (house steps, a solar surplus, a battery " - "at its cut-out level, and at N=2 a refusal with probes)", + "at its cut-out level, at N=2 a refusal with probes, both batteries " + "due for maintenance), and so is the arbiter on 6000 claim lists", _now == A5DDDAD) check("...and no cycle in those runs filed a `mode` claim or handed " "`compute()` a bound", @@ -194,6 +201,20 @@ finally: _undo_b() check("...because main.py hands compute() the loop bound, B's 0 W included: " "[-2500, 2500]", _bounds and set(_bounds) == {(-2500.0, 2500.0)}) +# Review (PR #149): a unit the allocator drops (stale link) must not count in +# the loop bound either, or the loop asks for watts nobody live can place. +_rows, _c = rig.run(2, extra=ON, dur=10.0, load=flat, soc=lambda u, t: 50.0, + cut=lambda u, t: False) +_both = _c.loop_bound([app_main.Claim.limit( + "supervised", app_main.P_SAFETY, -2500.0, 2500.0, + actuator=_c.actuator_of("supervised", i)) for i in _c.inverters]) +_c.live_units = lambda: (A,) +_one_live = _c.loop_bound([app_main.Claim.limit( + "supervised", app_main.P_SAFETY, -2500.0, 2500.0, + actuator=_c.actuator_of("supervised", i)) for i in _c.inverters]) +check("the loop bound counts only live units: both live [-5000, 5000], B's " + "link stale [-2500, 2500]", + _both == (-5000.0, 5000.0) and _one_live == (-2500.0, 2500.0)) for _n in (1, 2): _st = store_with(**{A: (False, packmode.SOLAR_FIRST), @@ -310,10 +331,14 @@ check("pack_use stores the switch, and both are written to the action log", _bad = [asyncio.run(_c.handle_action("pack_use", unit="inverter-z", value=True)), asyncio.run(_c.handle_action("pack_use", unit=A, value="yes")), + # 0 == False in Python: a stored 0 would read back as ON. + asyncio.run(_c.handle_action("pack_use", unit=A, value=0)), + asyncio.run(_c.handle_action("pack_use", unit=A, value=1)), asyncio.run(_c.handle_action("pack_mode", unit=A, value=packmode.CHEAP_HOURS)), asyncio.run(_c.handle_action("pack_mode", unit=A, value=None))] -check("an unknown battery, a switch that is not true or false, and a mode " +check("an unknown battery, a switch that is not true or false (0 and 1 " + "included), and a mode " "this release does not offer (Cheap hours arrives in P3) are refused, " "with a plain reason, and store nothing", all(isinstance(x, dict) and set(x) == {"error"} for x in _bad) diff --git a/goodwe_controller/tools/opt11_identity.py b/goodwe_controller/tools/opt11_identity.py index 49764f4..3339a97 100644 --- a/goodwe_controller/tools/opt11_identity.py +++ b/goodwe_controller/tools/opt11_identity.py @@ -14,7 +14,8 @@ printed on a5dddad (they are written there, with that provenance). Scenarios: N=1 and N=2, a house that steps, a surplus of solar, a battery reaching its cut-out level and, at N=2, a battery that refuses (SAFETY-73) and -is probed. +is probed; the same with both batteries due for maintenance; and the arbiter +alone on 6000 seeded claim lists (peak floor, trades, maintenance, refusals). """ import asyncio @@ -187,6 +188,11 @@ def digest(rows) -> str: return hashlib.sha256(repr(rows).encode()).hexdigest() +# Both batteries due for their monthly cycle at the run's first cycle, so the +# maintenance slot, its pins and its shaping are in every row (PR #149 review: +# the scenarios above never reach maintenance). +_MAINT = {"maintenance_enabled": True, "maintenance_start_hour": 11} + SCENARIOS = { "n1": dict(n=1), "n2": dict(n=2), @@ -194,11 +200,78 @@ SCENARIOS = { # option without turning it on runs. The old tree ignores the key. "n1_off": dict(n=1, extra={"battery_modes_enabled": False}), "n2_off": dict(n=2, extra={"battery_modes_enabled": False}), + "n1_maint": dict(n=1, extra=_MAINT), + "n2_maint": dict(n=2, extra=_MAINT), } +def resolve_rows(cases=6000, seed=1149): + """The arbiter alone, on seeded random claim lists with no mode claim: + the peak floor, a trade, the loop, maintenance pins and shaping, SAFETY-73 + refusal limits and probe pins, packs, ratings and safety stops, at one to + three inverters. The peak guard needs a P1 meter the cycle runs above do + not have, so its claim is graded here. Uses only a5dddad's API.""" + import random + from math import inf + from app import arbiter as a + rnd = random.Random(seed) + rows = [] + for _ in range(cases): + n = rnd.choice((1, 2, 3)) + units = ("inverter-a", "inverter-b", "inverter-c")[:n] + + def act(src, u): + return a.actuator_for(src, u, units) + cl = [] + for u in units: + r = rnd.choice((1000.0, 2500.0, 5000.0)) + cl.append(a.Claim.limit("supervised", a.P_SAFETY, -r, r, "max_w", + actuator=act("supervised", u))) + x = rnd.random() + if x < 0.15: + cl.append(a.Claim.limit("pack", a.P_SAFETY, *rnd.choice( + ((0.0, inf), (-inf, 0.0))), actuator=act("pack", u))) + elif x < 0.25: + cl.append(a.Claim.limit("refused", a.P_SAFETY, *rnd.choice( + ((-inf, 0.0), (0.0, inf))), "refused", + actuator=act("refused", u))) + elif x < 0.32: + cl.append(a.Claim.set("refused", a.P_SAFETY, + rnd.choice((200.0, -200.0)), "probing", + actuator=act("refused", u))) + elif x < 0.42: + cl.append(a.Claim.set("maintenance", a.P_MAINTENANCE, + rnd.choice((2000.0, -2000.0)), "drain", + actuator=act("maintenance", u))) + elif x < 0.5: + cl.append(a.Claim.limit("maintenance", a.P_MAINT_SHAPE, + hi=-rnd.choice((500.0, 2000.0)), + actuator=act("maintenance", u))) + y = rnd.random() + if y < 0.8: + cl.append(a.Claim.set("loop", a.P_LOOP, rnd.uniform(-8000, 8000))) + if 0.5 < y < 0.9: + cl.append(a.Claim.set("arbitrage", a.P_ARBITRAGE, + rnd.uniform(-6000, 6000))) + if rnd.random() < 0.6: + cl.append(a.Claim.limit("peak", a.P_PEAK, + lo=rnd.uniform(-4000, 6000))) + if rnd.random() < 0.05: + cl.append(a.Claim.set("safety", a.P_SAFETY, 0.0, "stopped")) + rnd.shuffle(cl) + r = a.resolve(cl, units=units if n > 1 else None, + weights=(None if rnd.random() < 0.5 else + {u: rnd.choice((0.0, 0.5, 1.0)) for u in units})) + rows.append((r.target_w, r.winner, r.bound_by, r.contradiction, + tuple(sorted((r.shares or {}).items())), r.allocated, + r.allocation.explain() if r.allocation else None)) + return rows + + def digests() -> dict: - return {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} + out = {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} + out["resolve"] = digest(resolve_rows()) + return out if __name__ == "__main__": @@ -208,5 +281,9 @@ if __name__ == "__main__": print(f"{k}: {len(rows)} cycles, loop reasons " f"{sorted({r[3] for r in rows})}, arbiter " f"{sorted({r[6].split(' ->')[0] for r in rows})}") + rr = resolve_rows() + print(f"resolve: {len(rr)} claim lists, winners " + f"{sorted({r[1] for r in rr})}, bound by " + f"{sorted({str(r[2]).split('(')[0] for r in rr})}") for k, v in digests().items(): print(f"{k} {v}") -- 2.54.0 From 2d2b6afb076583a7fff597263d9f0ff0165f7e53 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Mon, 28 Sep 2026 22:39:43 +0200 Subject: [PATCH 068/105] UX-13 P3: Simple view and Batteries screen - Batteries: one card per battery with On/Off, the mode list (cheap hours and selling greyed out until OPT-11 P3), level, and Now / Today / Why lines built in homeview.py. Replaces the OPT-11 P1 minimal cards and uses the existing pack_use / pack_mode actions and store keys. - An Off battery the peak limit still needs says so with its figure; no line shows 0 W beside moving power (OPT-11 P1 test F2). Today says "Not planned yet" until OPT-11 P3/P4. - Home's plan leaves Off batteries out, except for the peak limit. - Settings opens on Simple: the layout's simple fields with an applies chip and a note, plus the battery switches and modes. Installer is one tap. - English and Dutch words in app/ui_text; test_batteries_screen.py; browser check tools/ux13_browser_check.py (CHECK=1 ux13_screenshots.sh); new and changed screenshots only. No control, allocator, arbiter or command module changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV --- docs/img/ux13/README.md | 4 +- docs/img/ux13/batteries-modes-off.png | Bin 0 -> 60220 bytes docs/img/ux13/batteries-nl.png | Bin 0 -> 92491 bytes docs/img/ux13/batteries-off-peak.png | Bin 0 -> 93537 bytes docs/img/ux13/batteries-phone.png | Bin 0 -> 59100 bytes docs/img/ux13/batteries.png | Bin 0 -> 86721 bytes docs/img/ux13/settings-installer-nl.png | Bin 182800 -> 183415 bytes docs/img/ux13/settings-installer.png | Bin 179464 -> 179047 bytes docs/img/ux13/settings-simple-nl.png | Bin 0 -> 113420 bytes docs/img/ux13/settings-simple.png | Bin 0 -> 106723 bytes .../DECISIONS/UX-13-one-layout-table.md | 8 + goodwe_controller/DOCS.md | 22 +- goodwe_controller/app/homeview.py | 167 +++++++- goodwe_controller/app/static/app.css | 16 + goodwe_controller/app/static/app.js | 138 +++++-- goodwe_controller/app/static/index.html | 27 +- goodwe_controller/app/static/settings.js | 85 +++- goodwe_controller/app/ui_text/en.json | 58 ++- goodwe_controller/app/ui_text/nl.json | 58 ++- goodwe_controller/app/uilayout.py | 6 +- goodwe_controller/app/uipage.py | 2 +- goodwe_controller/test_batteries_screen.py | 367 ++++++++++++++++++ goodwe_controller/tools/ux13_browser_check.py | 184 +++++++++ goodwe_controller/tools/ux13_demo.py | 37 +- goodwe_controller/tools/ux13_screenshots.py | 22 +- goodwe_controller/tools/ux13_screenshots.sh | 7 +- 26 files changed, 1119 insertions(+), 89 deletions(-) create mode 100644 docs/img/ux13/batteries-modes-off.png create mode 100644 docs/img/ux13/batteries-nl.png create mode 100644 docs/img/ux13/batteries-off-peak.png create mode 100644 docs/img/ux13/batteries-phone.png create mode 100644 docs/img/ux13/batteries.png create mode 100644 docs/img/ux13/settings-simple-nl.png create mode 100644 docs/img/ux13/settings-simple.png create mode 100644 goodwe_controller/test_batteries_screen.py create mode 100644 goodwe_controller/tools/ux13_browser_check.py diff --git a/docs/img/ux13/README.md b/docs/img/ux13/README.md index ad3fbd8..9a48082 100644 --- a/docs/img/ux13/README.md +++ b/docs/img/ux13/README.md @@ -4,6 +4,6 @@ Made from the real page by `goodwe_controller/tools/ux13_screenshots.sh`. Do not edit them by hand: run the script again. - `home-*.png`: Home, running, in Dutch, in shadow mode, at phone width, and in setup. -- `settings-*.png`: Settings (Installer view), and the time-window editor with an overlap. +- `settings-*.png`: Settings, Simple and Installer, and the time-window editor with an overlap. +- `batteries*.png`: the Batteries screen with modes on, in Dutch, an Off battery helping the peak limit, a refusal at phone width, and modes off. - `setup-step-1*.png`: Setup, step 1. -- Battery modes (the Batteries screen and the Simple view): not built yet (UX-13 P3), so no screenshot. diff --git a/docs/img/ux13/batteries-modes-off.png b/docs/img/ux13/batteries-modes-off.png new file mode 100644 index 0000000000000000000000000000000000000000..ca3ecdf2b02655d8388afb33a860a00ff5a0a67f GIT binary patch literal 60220 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�y6OO2H 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 TvYPuEw#Z?eJoZ=ZJDT)w_nj>1 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/batteries-nl.png b/docs/img/ux13/batteries-nl.png new file mode 100644 index 0000000000000000000000000000000000000000..96e3a7ee046abe8775e8b70a4aeb682cc3683853 GIT binary patch literal 92491 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%0A^gn#$d0ALEVb&LH{Oh258-;2=@=@wD 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 Ni3v#y<_Wy={$CuPU|9eF literal 0 HcmV?d00001 diff --git a/docs/img/ux13/batteries-off-peak.png b/docs/img/ux13/batteries-off-peak.png new file mode 100644 index 0000000000000000000000000000000000000000..19b0082a8b382674d9e6ec56bc0a2425737ca376 GIT binary patch literal 93537 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%0DlDu*S_0fVJ8~r&ZM~<#6jaCD( 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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/batteries-phone.png b/docs/img/ux13/batteries-phone.png new file mode 100644 index 0000000000000000000000000000000000000000..b22face8dfa4704888f05cf34d8420e26cefc1f1 GIT binary patch literal 59100 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�$nYz2fB38twu|IFipbv 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%0AfSZrek%wVlg|lmx_Wsa4<kH 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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/batteries.png b/docs/img/ux13/batteries.png new file mode 100644 index 0000000000000000000000000000000000000000..6e729e4398987852564458e04eff67bed2520324 GIT binary patch literal 86721 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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/settings-installer-nl.png b/docs/img/ux13/settings-installer-nl.png index 74dd7c9dcdddc7aaa8d6670f219859b23ec95d68..b8bf978cd02f1f1466756b344fd5194d3e666558 100644 GIT binary patch literal 183415 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�{6+^M!6e@XS8?*{+cSNC)U%|u*evduuQKvhK9?- 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≫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 C^ntPf literal 182800 zcmb??Wmr^Q|E`aSD5+A?D$*t0pdcMXBQ4#Gbc29^lG0rgLr8abcgN5jLk|oC44ln# z&U-$b59j)y__X)MHG8r4T5I3GweI+(q$q`hNs9UC(IXrg>CY;U9--|%dW3=Y>@n~c zS)8!7M~_}SlKK2e%`FwSgzklJPK9wIr{d}g&a%j|uy=J0I{4bw^Ml{`@p(A=;?mL* zgGv?w0|DdIQge9o{pOctW{q5G=&_ur7i+>`zheU2_1@EAnt_?o5NQ6<qt)TO&VO&( z$ne@J9_~J3y{SWcxUu->iR;7l5zF^g+=pu>`isSX9&V~0`3pW=zY~4@hVgJS_W0S+ z!}XE&qyI`H2Z<lM2swmaqS&@WlJ?g=7*R?MZH2gnDFrhb{oBl)|Ej+EXCuV|CC&HS z?A$bFe2>|KUpiQ}ev=Rrr_2~Eu)8wnv0Zl98PRh|>|Aqm_o%X5%5%-o7ZA8;C}q>F ztGjP&A5P&pacd&<En#M4)@{0y%Oe^X7+6lKT}2^?Yfh~7FCY*9>yEn)dkVefr{=p4 z`3hE=A1nWmX#6Y`?yRf3%FoZQvDKagrOXr$3@{O~X;oYm(Wtv0f?L_{t@>vxf(crJ zBVTtnk^B%_TWWO0!aOUwAOM<dYkkUi<oum&f&qV@!#O<Ua7#=Ww{vz2v+zQUNv_EK zd^t)Owp@JR@4Ax0WiM7~Hq6!ffrdsR7;!KDPEb&gjW?kn$_I5lfhTx-*MWHb(9L{` zCy0etzxYi%X6M4V94V!~1c-2Ql-RMteLXyAQ=pt295vt-Br}H!NON|4zT7;LQm@hJ zSGae*(>!8)T$vo#{5nia*z>Z^aYs>1%*alkRoKbJMZX5F<5B#DS;PTuA^nXWr^*&; zHkRopDJdCNwJmIYnR=Yyjo4k=m^2@4x;eTH3ma<oL=@{Z2Bj~R8D@WclPKz&e%3JV z#j4lf1-m+}sBmDClLLVw3sfPA$;lO?6PU22S~d}p<-tMgvrU;ZwyBfY$5GNwhYR6t zZEb&He`kudaY#7&78ZhfhzST-z3u}_iG1DnCUQMLwO_i_1O#IrEf(NEtj7~cG0i0H zm!U~2GR0|~O_I?i=j+MammM7)EGe~GT3WSM)6r41u;=)6dd(iy-i<ty5YWXLJehMR z4U3p{VSauj?WQIYgeHcjC*YdQZ!CZU+t|qB^+r$(kJ#Qd9v>~1H`+GxPzbv4`J8R0 z)*ma~n&u#Hj+Pp0?a+NLkvlz-J$bZwT1i@2S%`Vf=CIJvU*YQY9!{hu%N>Yt?C_p& z3Qn`3e4Sc5g>;T^Z$?%TA9y0WJ==z4#A`z^`2NWMKH-pCC>MrUN$|bv-q|K1>I}w- z^d=EB-4Cm(;*wE)c2zZUFbmF{5;23*3;gq?Y_-|*(<khQB}Mj}5TX5&eNg~5TjIiC zM9K2ASM5TCv!9_~jTYh;z5XXSk`h=t#d?(k6BE%<@le$5?Xst<UvMynF!r-&&z?W8 zcRAE<_3?(*TDz{ceWFOm#TirOY7Zq=_Gl=jjLw#dL|?*caav1_tL7GlO+pZv?c%k^ zbDtcI>E@cvkK4s>$apOJ)RHpAPLBMM6-KwwGzQ_M!aS_35%Db!TZ~c|km(}L3WFkU zt`Bavo6iN4f*=H+r6j=f4TsryqKU#f6K{k)T_E^q4K-zE7mO~CL(V)Au$jrp>@~WV zFLy>W@GMr+AK=C9{7v0#h>|WSf!X4dkfM4(V^)?Sl&9G8;~RqH#N=hX=2rK?cy*@x z&2M}W5fOvF_u*0T%c`oA6O$9zIM|gH6-69S9Y4QieSKwic5IY1x6RladcH3_?W>>A zisBafuWEbB(cF<p%YuS>cXzJTxHyS+)X~x##>+vwpve+%!TBOCq1-pOhJ3acKc0ij z@ht14B9B_{u5~Oe83fHbbim~WX>;=nc{#ZpKz|>B-#-E7CS;$fZqmQ7i9V1GqVkXD z)lX%q2uccJS%=WXN%Ik#m6nb9N@*r0IWRaQHr7N6qqlH~M?~Z;ouDV`I{b{9;*i3m z^XTX(d1nj)7In!4XNXYwHvN3+;OO9Ub-L3Ab;ZQOBIQ2gW{-l~?VKZ#Nc8%8{+St# zirEF}!Q0QBs)8;@3(cOqf=$*txEL70Ih$&7a!kg?#`9fvB_&}wy}k|gNhCOY{3u^& zy{?_549Wlas=k#HDtmj&Wb$DB*>@g{X8|wP$+QbI!`lByWO$wR{{g0ze-1iXDT;z~ z23{2oNr6DMGL^K}nxz`NekFD^wKH0c+tbzxxmihGcirnle}|k8X1FXDe=@G9x#B(B z?UQCDef=TYE$ywRt^0hDbn#lj+kmGouorE(s#cJD1^F;XhYBoA%;6z@@3m@wgHQK5 zT3T4>UZktvPPy@b@g2jJW~qMns&%F`cV^fh0P*PPSHr_B7FWy7o-;E%oOvK~RlzKJ zwv^~Ujxv`0_f-1_aq$VE_t!=?gG4OvD5d%Yl72I3mI%AO7*W#-Xf2Z?#tf`|j3yOM zK3@??1vQ|7-J#7VU)7$0<mG=i^U(9<OhEqrEjA7P+Iv-N@iyr&;KO`ZEqKM=)iGwv z?P1Do{Z{YT)HL)-3CQI|5&r%W8GOijbA$JE5Nt}W@9Ae}@PWZW@0S<;X%0v#rV!Z> ziFM899lg{vG&FE;ckdwO_Rdxszh}Jn)g?@eh$x=Q>q>d^d?zq45Ce}gx%KNOMMWGi zT+vNPAB`%5?j>k2hvxk1#}5FUK17r8$tn_>4JX=P!uSW~AN#%G<1<-mz^Q<KwsMpG zbih;G=(2Y<%)6qDHO7FER+}o|?6G|7`fnAn4JhHb7kmEvmnuZjJa~9`_%`{*cBz8l z&Bux09H~)CGz{$50#2VhpW-k*A<UKxOBAwSKN9ww|0Nan+J1LzO(rJq_3PaXKA*pO zjV}KjLRF7e8k}!Dk6Ct?i=iWFP~W?)gwu^>MkY4!LREhT)7|cL5r!&OhR^jWU53w0 z!8tk=m`zU@W#Egngw>t$*Ym^GO7(>yib)*4caOE>i;4!R27L`qW^Jh+fU<VQ#~ZPP z@VGb<?|l07>2Y)8*SWE*2R!^<vqnG^_d!WD&`TU=R3Dpd(ThQlHCwEc%PeS7pG97j z+ze8xDr5dybx9>J!o<`xH#e8tZZXkn850zjps6IhJl@{kBYCD7(q(jdzB3vguAr-% z%Acxf{Y6PBF(U)?t3D+3=4t~J9){D3+9rz|Jwx6mCcf6uA-g<&$B=0xr1y`-=7CNz zBz9|Si-v{<$z}01vvl-fZCJbo;9&g4qN*c$r*GKwhJA7!>9;BKvrTdzkMvd4+Zy}^ zZ4T0D!*8WjVp$(JIXPS3+^4w`4Y>ow+1{Asp^1D3r#N@LcQJ!qM%x=vm*UXmIIQ<8 zCtPFdQ7fUc62b|erD#!D$70fir$@pb;~!UAyszO$-4Bm`WO-B9%KF%ElPq4+Bf6~R zTzjPZq=UOs55`PDw%Da~hWgr~G<19Lnv6_JB=qaUBbltLB^;%Cx{}?OO!KiTEb?yq zdHpP}M)VS16BU`J{ku`jT+Up-Tk!U!Ph*SiLX2ccjd#i{F|Ux>3_i5*NDagP=HP-O z+rQUT+nvO06Dzs`X;;$#MyT2!6UgB&N5-W6y8s_?zgRRNrr0~AIAn2}ZQYPX!;hD{ zD;%!{^D}x$ROhRm^+r0?UBHRIJXC^@a&Lim!AX0Mz`DP%xK8@*g&RCRZK(U#Su<@! zEs>ca7<AA3t!udZ-yh>YLCki~%epFx9$?{NQZ?P)YbwT6ATeW-NE|%5I7t?kQy+f! zND0sPdw~Ym{nk{&g}~h-RSlPsb+9ifN9JheKi*Rcs$agmroca5sUX1-^`xwJ9Brp+ zy-``}!t2O@3A;@#FT0F)xK1hH6H<7>Hs^C<)##*xS<@a1pjVj|iu-so5|Sm9nXg2Z zirjxMh_GT2d;bc3`T5ZT|95XbL^CL!6*)E2ll;(;eAPON&DP;KV%J_fgSq|LHMlq$ zT&c4Q(MhS|f$Mv#*2%@rhHv*|*)VuXH`QD*E#Gk6F`=Z17n~O~l^&md+PfdVoK6{Q z*BeP<zcx|rNL>11`faO7sZ2GIvc9tYYTxtu&cJi?l$0d(>%zsR+Zc1U?afX0hcQs^ zyjc%rBgrqojAB(afV=z4Lh1?JJ&)RH3ec0b{4uYy{3c({l0rQ_p>+kRcPFQl;BX4} zyY=Z23MkoY>FfD~xVVf)r^Ali1GbG<UQNQ{9hB+(z6{jV2g+TXvQTo|9SNr}NTZ2e ze?fuyh+d0_@CR<;Y-RC`=;(<`;?f_YA!F0i1*=%(utPQ0)3!DISZfG~1e{q4HncOd zGJ8ef)v6lo0-u`fBc=lx)R7U0aoZ4^_Y1pN*mcw7CX_7Jd0m*<%lt|RzFAtmIXh5Q z`ttgmBfW%-T-ZKOp(s8{Yo06En%B<U#EkpoGN(G%>-MU@(oRocZ1Lzx;QRNqjr9Ud ze<wD6n$sy7Jj1LvP}3Dl$t!z?k8dn6U+1>flUu}FpdhrU2ZzH|R3_)Pj^=$g?UXDO z?I`s^$0jG8U7Vg_K0m)a%U?Y&U1?$=_~~*e_!+td+qAH;`8<gE919|uZ8~l;f_tf- zegtQH3JiKCrjmVWoJS+EJRxz_+Q=Pa#CvxndakLdKBZj?ju*XD1$FJwf>du8l#`Z( zgv@rOIb$8Hb5F!GqY;1sXXoY3CHFdTd7%)W7ISlxaX@y%lgQ_z=HReDj&JVl?CeeE zrmAsydg)N6>Y06=6FUVQUIr*@PQj=B!B`e=*5}WcZtxJhGwxF-Zy_W4CbK)^F%YQh zA$Yn1`FAhoNYqU_O54zTVuHhNvBB~DvKjXfx=l=QTjj+qv9=e}JFen#Ec&Nxcl9?0 z;%-4cX?Lz}12TfQzhXV`qnw~+RIlz&*)!Rl*1P%=(@?YX<#a0xi#nGL7mqlb`ZR%> z<5>t@WN+@TW?`Y-f>6zpbL8#WSxDth>65^q@#GtB>k6wSA`eE^x0Wk@#!HP(uQ?qo zv@Gk3ia1lYA3m4D$L-A;Zsadj*$V426JbAq(KB3&)V`K!u)n$C_PpACj<dPB+1=H1 zaSV+qJPx=)%uJ8x-tNO-CMG7*Buis$A1}2T{V=L*73||_6M5XdR@2^KmU7`F3}&q! ztY$VWD&|YtndGmB{-d@@$?lYy07(gGw!Ie-&et7|0LyY-oN}=9SWQ<*$iw8eE@TvC zQaFueL$?)5mg^3WXRExS8hLqn*+DpYg*<8TeQfI}bg(acSvPPiFDK{u6R%`Z^_iXF zbe>EDwm^w5TH0QhYmWt*$H&J>ILbg?MjTrX^A6BzyZJId;<PX0T^brhXO65)Y*gGf zFNW(Ciil_)C*-sKhYQHf4Gfg%?`IGZNyi~`gD!ljy#(JebA<ehD;$gJc^Y-GknRin zvrcau^Ji;#)I-Dakr^TeYH9>z2_Fd$Vyn2U<>V+M>9pP@2s$o2aV}L*80_mG{sodZ zq7vZeCm<r!Nz`1fh0gVrWoCYK_tMtR+c0RhCZ~XLRyfWXT3gGxeAJYJ{7Egn6-!PW zA$eaEo4gGj3#PENHl}&?%hACxX`l)`%g8{pHA{E^zkqvt2{kw$t#0nV5&cI`JoDXk z=x)Mek(G`PU1lNxOa|FBDKJs7ck_l6l#vcikYMPz>Q1^)cvWpBj^~vL{Ac?^+5Z^# zwr&<Pfyrn;cbip9iO@}_F_2DFm9jv{RM}p}Od~!aK@cY;F;OXrpZT^tG=_RQ$aGT3 zlTsqkM19Z@8ymh*ZOQ!w)od|!dV1+`eJhcmSbEg{3V`yX^=icS@YM8l{~+7f#v08N zq!}$O><PId&5i`j^6B{G^x!C)NwCB_8ONlQBmh+`ed=4%mw%K~lkDNRj2JXD?6i$X zu4K@Owl}Zdv}fThdz;7CLIj6h+Jg<~nKdaQCa9(-rl+~5W<_1sFw=sakLF6o4IuxP zdv(7Oj_N<1&+1D>>nGn?d{R$xQ0zTbCnvc(v6pK#>%>5q`vUdF`^DW4*$x0N`WXti z+T#vt6*C$?qs?d#A<+Xd*}&5iZ10(M-~9G6h?ngXy*-1Ry;DqUevN#mZD_KRzLYK+ z=}!KZzcDi=xU&~j3%8c-98Te`CnJ!(upw=6<n3xTb(F-3I}pFUP5vS3p{vVW-)y;> z_7x1qi)lr?X~idSxUnniD2hlEaNXTyAk9=Iz9$-<=VNXCIRs1HRv^7`lW9rxys>+x z$q=Dxy43bDqeS~dTvl;SO-1qtyG^O%k;CO&>W4#z5=A~RjlrF-chzE_!3}m0YTZ@O z6sOHrAj%M&jd;7dN>KsMbjs_w234!$>9T;c*tN)a*O&XOo^vg>2S6D+L;C+Rmb$y# z5x{bEWDOQ{y(I7mDO@!*HC;i~rG|7-9+ie54i~P>&CF0&2aJVG2V}e9RDxpeFNs+V zAoqm(1Gu;@s&wJdmYp}#Qw%1q`(q`l82#Rhy<y}P_JbwIK3_(*92orZlnn+G45+Z` z$=GVF4>MAuFE_wU3{rxE{6k41T5EyrZ}EP-d+CWmmQ<4Vc*bt=?hvn)jD&<JA$BM& ztFB+T(Phzf_X^Zn%E7^9b-0om?P~vP9p@s2=S=VV9P`?Dpo=}s1IN2*M7OR2vC7`x z{w@#eu^G^@+-T8%2MYZPP2M?EEJu~qOON+ra_97-E^g&n1+Ma2Av(I=;b{pT$@i~l zfNI7kxW9XQC|~-=KO-dp3^wmn!&jfdk5Nq}hY^}3#-$ls8T~0Wkcn5X70Icp3S%V& z5a`3SRuXn$(ayF<T|Fr&X}<20;>4taf*>7UT3Q+%9i4*P<>DbQ)9g4pMyr{^T(FKS z3@CVC!RpT+=8)kDqM<#(%#~d=A%CD`w0LYwqaX&m35iP~EJOE<0$Q8v?<wXWt8{|G zTTU~!HSGr;dZhM`zh~M@fW{Kj%S!B>LZ_6nXe(NsfrhVV>A#2M^mNk^5fTDC2G7Z5 zA$;M10sW5c?@5t;#Y*7F&@y??rCU7fK*Ao$^rvrRYwX@xr{!P%@i2%DGQ-Xau!zr` zN#NiI6#U-s<Nq^j`OxbBGxhmjXrz#ijp5zic=zAA-+y<%dRS~sj?5ILRRYT}ArJe} zR06Rwdmb%qM8qY4h_~k7FhgZuUj;u2{J~D1=bfSv#`8iWHjwK6Zm*uuC`xIK0XJdR zX*HNdig|l~m*a$uhKO@EBfiJ<nE)@3#p-to6sW=HVB}7`m*Vhng;cP~5Dg6MRqn`? z?C;H=1^z*kideyJlIkokKQ)%Z**L8mB4ego8y~J##Z)oK_lo~>8#CFOC)6@!zpc%L zh{wJqV_A%M-cx44xpnZ@5}Ee+-ue>l{sra{+}FzE`h52bz$t&f$5mUr{|AYVPR4T_ z7A|*kdHJ<VUfw1(AsCvfr8+b`RLF->{)If@Hvu8V!KTGAv`t47aS<<yH0_48S{Wq1 z)Y*&8bJ6eg!QR;4WnXwh&B-K4mp}p3`*Hwmsy>+Ow^mhQw|qa|U)TNeB{4O5Cf^Wk zTcKjx%SXwnzC*g@BRQq!+D;yCK~aCgjRQ8EPqi^=<hZn;Ud16W3E4qJS$g`_Emg_T ze58_hXN%~$G3S%wX1L}1V!CjricR)=ef!g2qNtX_tVl%cFJqg(#Zw9zD%!GCYyjtM zrcb7g@94;R8Gg>UPEs7*;-ikJgN3&N)oVI)U4P||@x}~zK}$_{s#ddhP5kLtBCw0n zYjQB&i)7j!NnhXCQr;uS#0s6UUC>w4oybw{++q7udnoe3djCgHOY{kG#&0(^KAXi| zLwV;X!6Ni53<opS0S(VPBE3}OrdYLV!{#ug5^5+LW8H1VIw{jde1G|DSts`N^_5k( zQt9<(@|74?r1-glS8(hd95M}~l%#jWrg9w36~?{ZIjzG3^TJ85uiQ8$zE&N#l|SE* zA_dqRb(hoq@TMkzphkv;h0He?uQZ7InpOR{x(`T|r4#XNy>gT8-y5Y!+!v(KP*G!~ zT<QOEZZe3w6JZ19D2X}kyb1y1ZtLIA{F3ykq4RX|+|X(+@*w>yadv(lAlA8;-PyV1 zj2bXtOcN2NwjK_$ZAF!Jb#?tH$Yb<Lgo!%+6~C!jYLFHYw$NH(z3W;Y$qPA;ZGH)y zDf3C6AUvGc&YVN`)S|RMxJp*ihR;P&2jlz+T}r7vMxsWYJA-j|XNwxQlT!H{+uPc{ zj^CWu>B<}@lkpyxER`K594EXcB~?ORx~pNUDuAdBb`J_zqD?<9dAeApbx32ZC@S2H zuyfUVl6bvaUtdWN=er4(8}z%xnNEK?^^~x$7B*MZxuI;goj)2eKhIxlhcOSGzc?C~ zILBtF_PxCma!JHIF<`slrhos}vG<Zx|CPhNUr{Bspst2C<tri)pP_Gg0(tVUJ8`RQ zr=xumd9kO*cZx_ww-H>0-+U_sgM&n2<^Ze1aK5nki<xsG8)dB<Fq?iqQLa4+u2XwK zq*HDffpgvi_1wMclzIv54?3S-80%Lidnc+{r&sU-D600--&2@@t#q!!@i@B|ltw|Z z;_g}4F>Q-^8Y+tVy3|9_tC*TA2jzswkA17>7kT?D51`cc7HHb$rldij<G%7qybPh? z!O?r??uAQRZRbOBC4J>j)wg{+%4%*kwUvjnjlpqo=+rFbs_M+VrK@JE!VPK))7GpB zF|pAC9$ha$u9|_}68gG>KPAqLb#JeolIqW{ulc+A`_V-B^UN)-SAXc9f|x^E$`85G z5nWv-<zIw+U_V`ob>ibt#e%_pel34h^tH7w+aYqVUd1HtmsM7mS5^)KyEUrq?X3&} zM|NS($-c3%?s?0vt?63x{EY~ztmnX6x!}Mi%25|7wIniG_C=MI8(sF<uVuJonmtf1 zpFVw}UI|JQtT7(_X{6t?v$F-ApVzH(YF6#7dF)sAx2Y-I7fV3h?ZsW4K?Wu4RVS6i zk7c}_Z+v%v=3q6SO5x6X)so#z(VZss5@cIkd;{N?4Su1@M$i)8VC;ulA~t=l_1G7L zB08Erc;xslXKqlRm#^X0<8wh#^$0vY4>qe~`O*_ijNVLN^x}hp-o^GM_v98k=d7s+ zXbpgmKD9f#PUhQ1_>XsHh+?tip?Pg{X)<HdY(p&!J7Qk@Y1^Z`gmgL~LXC;+U+oz? zXL5tx6y7*_2sh`7Qx5TOLOEAjMuC;wk@4Ks(4sRhHB#T%;f}vvhEfKd<Nx$LjgG;n zW-=K4{4R<WboR^psDlvSI9q?IQSD%h6gP(sL@h4Xd5(oi0khq+sH*x<dL8^r7EYUs zzY0Z&b%o8%3>11d&Nzk3x~Es^UWT{XQ8YvJn|{{BE0*4Vdh+PeX84`hX6sY*mSbOJ zfQn$8gXqnbUYxgz<$K}ja&f`rFxvQwW{vH=HBvX;L?5<^QUMQX{z#wmQ@2GITa?Z< zH#a9Yg-|Al+Hy1rEm-mW`}c}ze0Iyw$?&i+pIh5pC3<(6-GJavZ}A=<KT)nApQ=qL z3XN%OWNIFm>Ctw#N6H#V4~IP$uCDUkuS`MTV~?7x)oI|;@aT8kzIY)GwlL0wfRa`> z*ji)mv)C*8ch>_<jQq;>9rN;E-kr#3Xt=2E#l7&j>Mgv8kKaBXN*1uZ?aSGW9TvRQ zPE1i{QjP#`97~~zET;?S5~5m~J)QR7Fic2EwcZ{^I>*-2MNp;1#57tS*tt+Ohsiy2 zf8le|$FLH#JQ9H$>(kMh@nM4Wewxe=hN)ZUfST*)M7u$dj+L6PrmX^8PT2;7@}Z~` zGYd;Ic=V{M)E8xJYi}>?&1Sk*^VdD4!iPVK7Y?a%#FGt!^EW4xsa)FbW%U*`L55aR z>kTSk-|TDzd_C|uJq~qzb9UmSwYL$f?w(*mXFHRR3`j#=q(6%mmxCQuWzR^%@Y2N& zg43}w{_`|4rLx07gP9CG-CVGydE+1!+psz)_(~1V6$L`uLv{>nVz!9HLc3?bei7VY z(ZsqJN&#)eRG{PE51rVLp-e-n>tB{;eqMwGz721sQWY_jkTej@2KQ*?ZekMIjmEd= zO_g|g|3R~aj-cQpra55ufp&TB0>R&u!tM>uJ0dzd2l~PSlZN+$XVVfA66*IKlz)k& z?M|#GMv03gib7=YS8#M(Xy4N?jjCQsz5ys6UnGYiz(Dv6lN~R3?n<b|T?2f<?JQ7h zsb0N`=HRH53V*!_k<!G8QD(3n(8;EN*+i!E;ZtQ;*qRnNRIpPA?VdQ*94>&S4T$M5 zcr_E2g&S42U7YO|<rT9g1feTwT(+=-{e2sAre7PKPZ8N?-;7i$f~#Vk@7p_RGJH*J znCsd5n#VqP*K0D+k3?v`R@G0H6Fn-%Akz`Jc1dwC-|5A~&u>J^3p3F(UtI>T0H=(_ zoT$<UOBI!g{5vVMf`UB&wVe*rSuWI1kV_3t`@liTvo_-s+BLI5eZ&YxejFU`#Nbsq z+`T28Zo7Kee}L<5@gFXrX0rq>_y%z(GpyJds~wMOdbjE0c2g4#^%n8Cg#{qNmBJfw zTbr9{Lf&f|c-w;fvK~K1)7eiuL9KQxHPvysIr&=J`XcTfuN!(M{<!0ZXjLUx|ArPu zpd1Q2YL#0>5-X2gqHawNz2V%x{OX?!>#rK^HKtO9Q%H2Zb+3i$|9GRJg{+EelZ7AB z@A)YZp8gf<uh-C_LK(LUQ41>u2SwwTaT?M@;xn>(Z%Lcurg^zzVQ6_dzk!6H49`L( zHUyH#-dXTLl-!Wzn<acw{vj##`xVrC?+rV1{bR}fLaRqKF&qmvLFO;H(iu_Iz6zpb z8uI8q&P=0I#IlDvF0khNRpp|1AEzMS(}4>#DMi*q&H&tQt6`}vKLSF+gY9*B!(>{E z<tlc<j&OkLmzOWRGyF3&Gh?=}d1^NSPOGt<=Ah?;%~uku4QeJr<WEo-_NOu{zUL%* zmN~8mW$hgRb>@wjhCFP!Df~UXU&yphnVZ@v$Niee8Z#<ic<$uv+#5l<P_5clNvy0k zkh?FK+X+y>O2`QMVjZLez(HKD8d_;fy4aO`d_zyqY?5I$F_$o$9Jju&^s!%)@^~>P zB`JUxq-n6yr7|s774SFG)6mfH1QmRPM*$gH+t~VK&Y>qz1DQ;jf`?VX;fss6A($d4 zi=VPIG`V|wNd=aBy`T*9-V=2H9c6Z#Z;)pttks;+I*#v^_^^E8KYZrc8yW<Z$ID^X zsAQg~i!ctZ5A;kd#`|*BE#ZY)qj^s&bkdVa9kAqR&W{%7zFi=1+jdO#F9q%>uhFy% z`Dm%S;>ividGwG)SgPe8L{xt(zp3IZn(#Khz9L~{o@&?KvHC<Z9ct<QXX1UeyST8T z&#zrm0a4oUQH?E``j6z~dhJhL<CqLYO$wG;O)Iq~Y0G;1L-SuZeCGU|TvMdD<+pio z;CNxSIze^+&BfuHy}cE*fktZjf&hn#cA!akiDAZ|o-#2#Dk?oaE;|0`E4aw8+sJ4g zV0A|H8U{piqD9pO&d#uyhwcMcK0JMtkMjg^-S$$>=jDJ884(eYa+7Le&v^Ut)YNBp zBWH4Q*e*nBR#DCF-V~V(phzS+kCI`sbBgQd-liPJ<dhV-k2f<=SE?7k^wDw88Sf>l z9M0w39c0{Z)AXXn8XYGomv-!a);lV#(F~Eb4NcjMcetyk&P`2KX(C3nwB~`y(19-t zN_5kR-nWEYicR)}YuCoY+n1WWBb6qUrEI^MJ7Nd=9JDrwA$d-CIK7>D@i;jZ47Qk= znRz~pA>ta}^5O{2LCZVgvA10|h?H5WOF*$e@f7}QUlG_YCp$fQROxpY)axHwD#Re{ z1aaHg@~5WaS2ES}8AvsXYDO<j8@(sXGQgt7M=?5|Pfo7A-gVd{V&uP*LVtZ+ug-Ti zTg9_{z0)ZNapA1y+3L=dd*#K%CTw1$nGsU;nY7e!>)@ZmgK!<!K+%vB>t&OfDH-^; zr929fBrSllxVgWW{#mH%{)XFnVi$5ugt3B$_Z$c7IhLsR(K>{RMd^+*FbEIdlwcl@ zN^rVK%ecX3`j7i$(JUG_yy&e&clS1t*;%iz^*zyagDU=`Hs2=?pOxd?CE1a?)6ll9 zCqbUO=XH+8ozDP1leFCE?Zs%d0ka2aCMu{zs<EC=*)Kk-%e&;NbR`ea!ttmiyx_}= zPet^@;Lvg!t7}PBKZT)uz5Lupqi@IjzB>8?p=HLR6>O|*{hB_{&pmd((R?cW`=?3u zk^0m78Umz}3L^{6{z;)X9oQ<QLPh3&?<XXRpvzaQ<_9YNq;g03Z1U%w6)UdhE6nbR z1M2vAA|cArwziKm_-~j5dl&!88qSU^2hGfP_m9I%Gcy2nCNhCc-G_|3^otWRYV+g% zp}C2nE|jhRGvrJd=0uEBotdE%W$MUl64VvzY;7bBk+1l&YgdGy)M4H@{9!`O%_Cju z?V{#jU@%S9#`Yz9ZUyQH0TViWe@sCqM<I*sxz?TckFG$k*}mT#Ufoi?NhMM3GLo@^ zRPg3ry6y~5c@<3-W}oq(K<35pn4~yVZy^riXo-s3=-aS}{1;xkCCa(hT9|*^JXUE- z*;`SNyHgSq1C9D+&)PXs&93wswffJaJHZ!=2WUE<HQo5!K4t_>toV;+8;_<o=GYmb zJ9W=PJHvf^L9YcT1}DR<zyRsFyM8exv$3buFqf8|lmrk_mWCw|2#CMpukI^x1}#c{ zdu`A#n;4zcji9S|px9fG`ozVa5OO|n`d#~dEAG|mCK!!~!g9e?(Ne!bsjs!=&K9{> zFW`aGplGU(*ANT3KNfX^*?r3of__q2OO2{|s%q*)@}3^vUY$~Vb9tnQM}zv=75(Vb zURHkoRWkgDommQ_(L72SR{SA9Ej$c6L$bwUw#UE#RI0Os3+PgpwyP2sH)R-+HLyiq z^KBD==VH|J$PN-IVI9GUNKF($vUs@dFLqncq9u5v7>0w9J7p`9aa1u{Z^%!rJ!-1x zu0tx(dqvA@*^Aw)ieLPMln%pICQh>75<T@G*HJCOjodhR&o4{Hw@+EGIYi9SAY>+w z5z|~7vTH6zj4xn&Wns>P@->MPR#nYnH`VCT#o7ZYC(+kRTUd5v6S@_}^e<qc+hn1P z-1h$HX)&44If1SEZt+bDnk|hDWDmKvopW3&99Pz&Cnl0qX~)`aY)n39yoykat|^`m zejd85s;u9RyV63I8WS^k>6(xMxrGB&q}Ba^wRv#&)jK`dp9V>Lnf`<fW)r{+c>Ld| zJHc7UoJwE;TIpNV^ilg%#Z5z;3PGYu3j;JTM4a_}(Wpxe&+$k~_uV+Yra2uJR;8)v z{o3A9&DWzacIx22D@~J~!!)g#-{2?h{rv^Gri=|zs#yo{c{$)1T<u&$M4jV{FPmPk z+PNJ-EG%@_Y$I=H)U_NKK2@wg_%d{uTz^)R&h~F{5H5_2oQRSFrP66akf&2)F;gI} zlgGhcZtu8q^Mk_WTNxR<)7OmjXto!s+JD+m7kI7n+FBYX=-|=B+uhSiz>e17wbEp{ z(TouZkfey?rEF&=(PW#OBQ)N}$G}-4g4Aoar8Be@HNU9)3NZP+){UDQkuJKz+8Neu zw7lsx@RB12+1M2C3?<)!a$Vwl`Qzf!*>a{tnu7~I(l0w#{+wV5w9L!P?`ZbSTEde$ zYhaeKuh{H1J87jf-uwENAAfgF$#-l1wp}z2_k`EO_ct=HzJ|(Xbiuvy14Q~Wh=tO0 zc<S-=6=;P`&+*fQWlNJ7K^kqQ(_Jsu0Vqhv%ll33=!BY}Wfp4kWjt8S%GbPRlgq7h zCasjZItI|>sQ7)Z8>xICa*}%_Nr%wtydo`m1yT7g*^<~=wU(Z0PS|O$t^lrownqKa zr>rv})5*z;PW0oU#U@)sHJM+aL^u4G+EQycV6UTUXJ9Ub=nSF~0!7@UxpU?xX_ZHc zj>MhwU#BLfTG^T!+FjP-5~|^ag5+zeYm8bwwN+GP)!kiri6eUS&tZ$YspRTDNR>V| z(bm7_E{kY+92!R~7~YPdov4J{YGi6^Q}o0uVspB{Q?-E6{^8tHm?mmsg41271ZI{T zdt6yj8E23STibw0fznZzgAx_&0I-WiB{nAwiAp$r1N9NeAJ`2L|3o|?VxhF<FLxXc zXq5j{K>x11V^Duqzr<R${^PAs(#n{O=8OzVf^lVDwzrNb&E#3yVGWAea)TVovs`+u zF>d-}c_o+fdaNX?YR*8HRdHauGVtDa01#1G_3Ov~%4FA9=6&N^RDik$i+WAu8wMa9 z^DOTwTeu~O7mW;h$Vf^1sA{=yJ{XQm$vVg;X9qNkMG^<PGfFFFjdC#swp=}W^d=z0 z(|gtaz5RP`VN@Wz^l4t6=?4b`QPZ0qdZED$^$E{JA74-RI)+HdN`V?-jBw6Er4->^ z?5~FUW^G?R)OX9G5uaHF<_RZrr-1_s^Agl-j*Fy6Fcp)eL=X=<dmh!ic%Yz}5-gvq znvRwRVs56_;?UVSE#cEt@6K&kc9ooeGguH-1$DhYR;@KiPy_8fJDjPrYZ0+9ySh)` z;<y$dZ*9F#f&@i4|JIsEEG@UaV=NNX+JA3y8u>I~j1OZ_lPbu`=wvj{Me>^1f6rI; z(8;VXewmCL?(SWX7Ui{iGIw`yW_4-U@kd>qzq~_;kWX-Wl8PAZ(U{7!ql<PZH0=)9 z2}BQ=&$qB+j(T{ye*nL-9@W6--TFbLLuBt#@8AU~TQ+ICxuZ__=6vVZN?#Cu<+awF zc~ir~lP!g9R22;D`vbcbT{Gm4f|lE7$L3{k6esG)&AOcqRunf8I`OhQlvNVI4z<X9 zeyktuJc!?QPg_@4tgCV-TKi^k&lxHXFxgcv8wRFg{`^^=s&XpVopqi^Q4t>D$`CSm z$hKtONcPKxNc%W3aPsgm2_#Z3Tvb(`S{<y<&UWN7pgnRnoUB<wPzf0Y=T=|tm6px` zHfZf9fWvupI6665{|kKoc*?`0?rk-o)nNU{_?$WU{y`}Czx77{Zv=vSpYRosN#?S! z&e{O*AEqe&<Iiq;uye1n)guERMAAo1B+SDKBv)Af)1<BWugduU-^cyG>FYy3{%dCN z|D};t4kf`+1EI*!P-A^a8?;tVPR{bp+qdkr0zpq185#Zk142VW{`C@Ffj@pLEmkj@ zfkA6C3ZekhVQ`>uzEg!(<?=}1P>x@AZ-nh~L)=q<VumQD-JNk~e0b<pTMAk`D#K}i zC~0v~H}BfU)|NU$f(tzJH)Jv)LDTDWOS4F$)DZaLN5xUFs@R{w`L%p5pSFa4HqIwp zi~BJ-O|M?63i_rG-<!BbG?<r4#VYEhwX3OaAn@@ko=ki67xz_E31tO6-?r&%c&*PU z`oU7YXU(&&?7rs{6{4Zaek1Q6w5PyXla7|Q#y+N}(tMbUn>+WkySrP^1s3LZJvG(! z{>_`OS0{$$<!lM8HzF+Dwin6OjR@FMlO<YY@8IAl;P;Ypa^j*nGwclJfA^Xv;6Gfz z9JEO1_s2JxrV5EC@qvNp)3D0QN*rvQOW3ltjg64g+;2O*#)_E0pdkGQCw>-TJ&+~{ zWY8*?zzVxMm@Um{{T4O2b+JERsaZ;ytVs!M30gCAbeq09&a5lPr@J`EM@Uw2maK** z2~<0$7pL);YO^6X)b7^D<8g_m-KKXsS!{}GVkZr0y!;YtV*O_E+M8Kz7n-&-zJ9H> zTM}@BmDxfg5JWy@wg+aUqUJ|JSXk$4ok6F_Tjv8_rH@p?R-23UVBgd31k}xi?cPfC z;MPRn=>}cX#mv=l0!yRM#`PlqvCVSRcu$Yymj4s6wE^`a3|vy_cGOyS@XlyjZB-R1 zx7B-7I6Brcw8~Qa<IUx4iJndaELfdMb8c<{FsctNEEJkziFzE4=ru-C@;BTfRxGX% zqIW+*KU3Jf8-n5hN%4y9$_eB`21d0PhY|Gb5IqM_@kdW=64@!O6VIvRY<84AiGT4d zmWtz#a6S0;1vlr|##kR2NG=j1Ar|X%8Yzh)%tp+Z<2*3X^c|Iyo}~7O=!-7|2@Dq7 zd5GnYj;uRixq2!cMSKK;cO5G!z%|rPgoTrHHSE}AVnN5i(3`S}8G(omTXfI<km+{^ z>;VbIPJfK#rIC@0^{qRcHeey6`n`C`(ny3A^!_^MmG*}XZu+{?*UI4sL_ST?6!6t> zA~i4wHa72RJgb{ph;`-p%SWp>25@?tCA2mvf1AIYaOka?42O=s7&<WTiCA<lx-!(Q zFTy!aYuUcsZu-M9zUJAjpa-8ZU@T+b8aFwrkxsAnFX3?hYZwqzX*QCXj374fA|)qh zCJG%K7%Vsww%#5R@%F$Y=lgmPub^hn%g%1OQj*r<=NB1?hx3gumAhz`%VzHDer*5t zwpnKo?%_oB;6n95QQcVI&M4rnW=g)_l)>M-Kf#FhITv(2OcHW8n#@x;JcKQiir!s^ zr*Ltwu-GDx2Ys&$lM-r)QMYI3pw|04jBam$2?9RYTMSr>mJ?EWZ}$;?;ORSdPD9h6 zTy_M4fyet6du2H>N%I{e@xu;%cWLotbdRU!Iu%`~;<ZeA$<>BayC7<)g$nG9aG&py zL!XG+@*5qnctfMf=WZ(bQ9J<LtEF71@52c4VF1N2#*_D%a>DVX9PLDzP^T<|>BBgp zi&43Y-KOVp9UPW~zTmIprF7@SxD{6xW!;cQ$Msy4Ig#CP1;<u#qTNz+LAwqU#{grO z<4v+kppVn{(^ZWi^(4`QAyo97Q$IF<Dc&`LjbN<o708ziPbIH+If;@!Exfh)YPSa_ zMM1b8URiYj>6Y~~sfISD_vJm${J=ya;;x3-sv#QlH2EAI(h;&(T_xhkV*<b_-*JJl zuxHD@yOEg{Edgd|XedLr>;9Deh~T+)wUtbNop)mmg@BWikD=R@IAcbsUSoteU=K}6 z{N1G%o{^D}olPxhV`ZiCg?=yA3=B?4zhsP(l8_=Jm0d1*`4WVD-0sY{XVBU%VrpVS z;366}LO)e31eC;+V~N1ypE)5YKMCMPi$yY8w<vUw<^`-RW_jTW%{eB^MfGbXDISsQ z14}kel~{q>K|<8tBdH>0j@Qz8VY0=U+JX{ZfO~X5DTH{a)`02t@=RTA#-{5j2*3E6 zSs}M=SVSW33gE(PhHERiH^#Nvvl_eo22)wW>d<b(JB$V+F^DHa3UrX=6bf?@!guK& zFMkmp@d&6fKn5Cq{Zng=->D-<6Pm4No6~E%Ubu6Rqq&5vv<R}zp(8};kP81~qMDiE z6DT$sW+q#hkkM1{5l)ga=crAO-#g(uze$-i!NN#3@YW>-)MTS!CRXBc_rQ85d$o&E z27(E9bTsb3RsG(u@cWrwIr><yQq%Lia3DJZN*8d3?~db;@kEev@86iNFf@Ij<Ao@s z@DxL<%%~>5mqf6ta))3M$`D-x@t<o1RbpbSiLI^k(PCikinkoKqod={(2%K|A@Szg zT9)A!P(kmy^Ie+HZ0<^25535pZ@dy5Zrru#4A79z#r`mfEJmq*VXUfM?KXQBGSE%w zB0z;#sq65ewn}$uLe)33)ew;vBo2Ko3R(kcCmCk;+U^wdmSjJNiU$$Kuu6}-6p|_Y zN_8!8uuUW<yF`NCL387%YvZ&l|NY(7pwmBTjAb-l8s-KH><Q8Af|;eA3=9dkGj~4z z)7PQsI;8|$4l~CSb6-_vTM1VS1%2Zy<3<eR*5ajGd!YlWz6aBPK*32Fcx-@rAte_n zvjf@2q$~Eg(9=<+w)^z!clmY_={JVzO6m)z*H*$zUVbG+fQ49)QLneRyVe#O<O3ME z8=Ma`i}lZ^*V(YKvFpf7q~VO@jrH}RpF1uO7s~M*D=O;+suu*Iwa2?aP76V~bVYcJ zN5ooHRq-dP#Lg~uiR}8S3{M7dfEOpH!vQ3@N5^`a$m<*j*EJYhxkbbv(?srkzk&J* zeH`h{_xJ|0Y{M^{_$s~%)E7NR5yXd#h|(j!dh$${g<tR+gxBOiq8)#vlx+Gs^0^`! zT`G`cmB8>0ADFYYE<&(l;+b^Wha0N=k(WwG<&lTsIDERe=Dl8m`qS4OOir<MPBWiG zz1}(^B=!<K9h)hf1h{VRx7A$l_T!Df1&(`${hrXuVQhX;P({4mo7q_zSLki4UTNm! ztF2iv+sw!tYhns~VUxLUjJ2v(fL7^p=|TzEgctT0sHl!JGvByW6sXct2zb4J_s&1a z*w~0pKE1*g>XJv~FD{m*muhQko0ghZQRz4*x;9l}tK)kg-+Fu5_|fWc!P&Sse6(ns zh2devQ6$T$3X%|hRZ(ITBGhK~WaQWRYCJ%;)c!-oQ;qaKsmf$zxhJZlyx^_tM<!}- zVce}%Li00U{<nMeM>gFDON-Ko<6qTax$H^9T*AjPEAW(2S*iQ<o(KdGQv90rr@EK{ zA^$~2TuM)hX}RDgn()Q5q@)85Hep87LgrfOxs8-qxK|cy<le&E@BLE`p?<3|A<lCe z^gHblgYA>%^+2>?&CxO~!NK@uErm$4ptaL2nfYkDQ%m=byA?>Db<;mIQ`n40rD<UC zm0}&<`|{h!Er9$_Oav4IAVwA9U1*)aD%WyHyS_J>#AyaUS~>_F6;0#zEQyH`*VgVi zSra!OP41r}2z0>1LtyQ&33<R1DTxR+rKF^Mk=?|`y%AcCW)~P#tosYakf^AC;*gqm z^&JBX59aTy(d=8)+KbRF$l22xk7?JcxP-f1+@5S7IbQbFs*^FQU9j$#cSk^-a{Fe# zlFKkMBcO%ek!xIx?Zj^^m^=iH<%UDJIF0S}qb#<<T2Xcsiv#rRF`{PfPq*BYr=!O; zFhhNO%aDya71y;~3tYXI*%b4!VGLIQ3$Z^w^}B!rfYn&LyeeFrRHsnc?nAQON&~mU z@vhZS@A*c%J==6+ofPEYldE08VNgd`_LC=gL~<L>o{b#K4FDuU><j*?T_kD<#^R=C zZ=R`W|KLK(CuU$^kdf&hPT@6fr5gYeFu>;BdMxvwNIHH)Ld-yAW#x)s?#q+$4SvU! zdWSv#ztHPy>)GA+Ycs=|D>B0a1FxP1lG+hIWPbj7?WLK(hVCwll2k0cg1%QY#%vXx z8nNSNFh~#Mb2(0D8#SGI4P32P>1Ih09^q4^j6nDg4yJOlWt5Y4B?{Y=A}wKm>By2& zsr$#AxHB)$@qV%1Z+$*$$D`nz(4;eYPFpPBicI6Aw*9Apb-e9ULI5R4DF)-wMX!vk zVNPHy?CsWtWH>2%H7!x-xq~Afg$Rd3*E3<^C18c1Vc_+*{E)R7D+Lm>chCyVK)n`O z!%Ttn;&09s6aB2O4qNp$?TTWesq5f%HoxJIC4j?05g*1=D@;O!Z?Rq@!e+iAZU70y zEL&P|yuG~4Mw7R;gIuwI7oU=qslU1#JTw1A$Ya(-%i0jWDSLCG{q{eZT&Fl-`TQRz zZvTDe|1Gu)#AHVxp$Q}2$N2N3$4s-6ed-4_KZM;rqXkE%2{>OGRhwPG+^2TrT1sc+ zKEE3uZu2Ci{TVLz<$8k(cG4jMY&+yEz5{VBrWAKH0wN-jXTBY3li75j`I!=`Dpi09 zB4K&yMrUzeBh2;f7LF_yykvhvb1$hBpBhbi&Y|yqTgo(};>mF#cS-U`Wq6sxS<WS_ zKy5Gh6)<RzfWYlnK!Fiirj)0!ceGFEcQ&flSNS&u@v9^at?;7oe<UFUl9cG1ybj|b zjXIrA^@k2#o^z~8u2S5`55La0PJ6s?hV%-IA^>HGc#4>OHQ3HLr~Mnyk^E%&IY7Hy zUOH(eeueeD-QM0FO4%It9h`!R17=7r@o%L-3hWq=YuxJ^0SBXAz0ZxQu77y=R_2{I zGs|84bH=ONu1ymGe0mn9?Bw{yqJw#?gyA8147^=qb8B(@9CH)E0w&DMJKEiCsdT># z2uPlnR9S8c&h1Bff)DZ}KljCUu_vIt*x9iHhF}2K8E5Hec}Ad<0Z-`@c&&E5FFOeR zK8_X3_2z|pTbk&4tpn1{85SlEHsHR7Yjauuv1@#1@cH1xEiyxrmNu`-cCtdeaRzpE zBJ~o8oW#c^RKu+Sf>lsbo4U55>ZjLBAXCBTu=~-aqOl#prrV<N+d%q26j{uUds$<- zN8)-E2ry3z^V)cnV^F}VMXSoMLMyOss{iQ|**(#|hD!bLG<T^`!#n%E2kY1^kdfgU zl3i10gc`V;s5r=)nc;FvNPnqoEIJ=+M_JP8H#j)<wTbAmYA%#1dw5&}p$Nc>wb)E7 z%QC;vD)GI_y}(vML1FGE2?f5UuF8W_UH%2gLyQ3#j;YTY8XB;H%^kwn*f;@xfw9UR zR^6=V$}GQ6iaz=~kNPRIXqKD2+1B?QN#~0lF{r3ONSyj_TON>0+x&v_^YaWzNoR|d zprs{A$si{Wt?prY8Nd%eG&8=YY(1L9FX2wHn~zmbrFfw9c6E}{X0|88s^8<f0cI~< z<b8T};p6RLVdt`-;4_@O0F}A?3Pg$quby~Nj~z97UC^SA_tqqj32M}}28!)>cl*nN zBi)7U<ZW&}&&>u#g=kpBH8p2D7Q<{W$8OdD9T%`=A5Axhc9dw&r!z_wdQBGOEQ$<( zlVn${lST2>C>0r3W*H;dB|Xwk?gFIv`Q7!?qx168^egdbw8RC)|HB0UAc3uCy8k>k z-m~4%u4Kds-5psNuFGmZQ&mg<%66e4)Q5Ng1gJEiR#MB%rlxfmlIc^HVPziZ%zEYr zYucoAVS34z=Jr+z&Vi3lJv<J056h~mc7YfNI&Mh%G9~3ae|_tHeM>nw;Max}4IPA1 z*j{6aQTf{3x||p7c+5l`<ARFaX|*N|gWhah_O9Lx9~F|uZrX$k>RntMYHwFu^7`|~ z7(pSxx_S;ofxVCe!&nI=<9%ag!2qP}LmQ#reVT!Vr^xOvsdB|<e=U?|S!Fe@dwKSB zIUVo^&3(}szfMU>QQ5z~7<FdR;YvYVs)>ttR+H6oPSEEGsnEV<x17DB#%U6oD$W|< z(VTBOqyK=aF)EHs*ol2^oYDG|m7ZCJmkFs^VB;G{9iuvdOU}<q@SJ!k=`BIXC6$1k ziN$Mj(o4Q~(P`5KoW$YbVeis~SDNp?McSoF;ZQm3!@4tne~=^{r0=MR>F(+lj`+=W z%pDT^HY;YCbULs4eyfOg&OF=LK&4X76%l^3771jvmJ5s<Q(=qS3S^UgsNhJ|a`*kN za+cd<yM-1(I^JV2PReiiYF3VDPk_`*HQ`)a$l5t^De3NkrZ?y01jjD+Z;fKW4aqob zc-(GWZhyMbi%rIE($>#O48$e=zEB&p?<hg*?!D^TluZ%l7Ctvy)pOxHu><sU8J|z> zpg~Pf_Xbdg5Gw<XGvbc=Y?7%|=EkL%VdaMBWN!r$+!6KS6{(_5JI~Ff-i=PRjbiT* z3ImVfBa?hVg|K>rn$IM=6@6`FhfdxELOVC(IU^oj+_80B?`w(}I#9+jv<Ny>09NK- zo$GhxzEc9chr@uT)Yc;2n_u=>6wuR^`2Rr}HF|7Z3W7no$t&5tAa@~3y#&bZr#MK( z8D`;0L5ic6I})JX<-@`ks;rb%w6(u{iH(tyIC)1cPVMd8?1%DXOBGF-NUy@j3ie^s z*3we?#hz(vJx~Yt^aczaP8}be+42Ch#8aiE5kT-C9Apt;kE%dV=sg^-#xFLRWu>66 zvGS>}%<cp{MJZfo6e3mk-PXL8LrA&Vp0L;J`|I-P8-O!cx0$j}Q3k4L`HNMsPhaj} z4+i@zp{wo7D5H{eQi(@AR^;U5lz%Co6+XhM7GYwb7}vy2R@=&HT^KZiy}zJa?@p+1 zYGx*hu85Dn@lqV4oV!ETHDlmXvsN`MJj~POKz^1>z}1GBNkLI<8n^!b`_ueBJ^gmb ztFxr@1bV3Q+ZdM@rUM7OU|>w!1lv&_2rgdEb0^nBdX~lkIT@Mkq)ALJt6gKTxfHjh zY;EmvkbDYPdSUU@<0=o=0I@BD_1UK9(;AkmGN0e;rDkC(6o1BeqnDgNV>ZDs0LaDp zKZ}}h;jprHlq3$B{Gm)RRqoCXo6#*Q83Hk%h@<g{4;ik)Vzj-Cu+<3`aqG)N0zxS; zB{Ii+zO8wO&>9Yaw?twDE<&uCNwot?-hN3=nS4F0*OAY)-1gsSd&{UeyQXU}1_=-# z2^KsF!7aGEyL1D=0|a;1h5!L>JV@hijRXkp5FkM4MjQ9wH15*aT)CflzV-f@H8X4G z`^V~aamhJ#PSvT}dskm%OsY1k{;yx{i2;h{zBX2$L-;bAX_@|OI)kDFueJUf&PRYk z1=QCR<wB~eMt}OZ8A<nz_y2Y33{pC&f`^kSFUio2pm_xVjFrPk_>5E}l<nQ-+PVhZ zGMk5+n}Ly4<3bM&#By0PCe3y#5()A1zfB&aINiKunv%nO(<fPP?iRyod01)a`RGMC z!XaC0Yw91t1K{4--gwH9u~Alb=7##}@v(_E7m*)^J4p==OSXA;f})6lU9CPMw7Zdk z^u40y7!u%U_#IWIW!OCeN}hu?d49^tkBp={3N*7rLIh;0fLde35S+$(B`7FJ<T^&3 zjDdxv;CX>Vmd)(EVv{$cVZV_~@>wRu?u<z(Wm?+nvh0a_VApXM>Y1HgnLxU`F~e!~ z$2oHLrj!CoivKL(c#qUW3pUjN;#K}_8G@2<fwS6m+>X{T`L~CM%cn5b!9ir9j47$0 zwBwV-e58xNzl5wd9i?yyigbL|md`#}Wvn2s<VMMArR`}<k`9=VknntO49Jo`6Kt@a zAAvQeE0n3=7Q0Xulx6y^O_#LZJaXj%rM1UZ#%5))g$Osl=4=db6tvFZ_9uj1@$j|8 z#?tReFumGA?SO&`K4qq*Z7>^Znf{mU#Z!w3;+dSRTx4t(6eL;?xIX>@KOZ0YjqNDt zt^{_V4#8rARF=%M6K_BRI%KXO<;Sn{@f#Md@nDvpw|92NdbJrKu)JPoAhgB)d%lM! z;%p4%a83g&0YJ;;Ierp%|Bk<u34%_!G&1=Foo_FO_$w+QieEQb@9Y}~T<YEFK7QQh zVXrqzWOEgVZTKe9`F?R7{Qi}$zP?5rC(F&t+pMCSf~)mMon>fJs3a-sDl{;6dHSUk z5n7oG$&|C93&>wkQ=tDWcv^V-Hjmk`Tpr@M)6mXA6Zm}5?@N^rguLvIU<YOCFgP#l zeL=Oix!akW>&Y=ueHC&6R(-1#lc>IpQko*3pEvBH7HPWwvwR~kMq8F!CRMim4%dV* zd|-O$mLf*|%_n0?#`_8EooyhD9JPLqdvfoi9a=#((vz0yi@$y7R-{59*P|izSYZIY z)z);J*|Dy%FupK&_N(M%(THj=om<rH6l|jL(vYHf-vaK@d@MNf+g|8`$8M|UPiAT@ zz{(sZAyTODb+cOXxoD@Ma$o~a8CGYd#}&CUPeVjMj7-61*+c+~|4V7hHWj)`NlzW? zPYLBI!N!x@(^7=)rDnvJR>U=F?QE7;L)Ns=Mj+qI{$jz5|E$<)pj3*DjU(pgSWy^q z1z=;Y@w3$px)pVR$t%S)G&gFgFTX{R7-eTINOpHIiZ@s-u9+K1Ce=D9;wQ7*>WWfo zN3=bCXJ}QFXEw*ndUkro@IpSQI#BeQyiH4~<J%9Xz*Eod1XvtEVxtE^tV!S7?*7g_ z0Ky`ZU3uLNe$Qq2*zZlINv0J>`<Fyr!^X|Cz;**KV@>C4gRrMS&ZkRU6R)^ghGyYG znuJ0bshLuwqkV|rm7%?sw+7br+5+)j>ea3udEAZ`He@V&Ca(bIa96bC)2*~R?=jhS zz^MXJ7`JjVCA@%=l_?VnKd+or#j+aPMoy&r`1tIK1f=oVy6`b1F603?mK%M=cB(&f zKbZx2V`P&O6GKDVnyo*XEn)8BUMeao9W3H#rR**I83Azfs@cMK!JbPF(?8RD`Go{D z5jB|`A(EpJ6Xei?5At)qG>57Qy|`y*XT|Zi!c4slfojowAa6=5f@)Wn>+@aNlG@tu zyQ8bH-Naf#!QX0`ZG<De*(I}7yCdzmnTNvO#0nEWK3khp?{7xU&WB)uo<VJGBFbyX zrsK31%(jS|phrbT;Cf3fGTq1Sdo=e+C8urLD1QxaevZ;bAf&7s$jDHAxHnyivvggy z6rd%V_?JMatIH?+;K8@B2w%#}z2UlQ6ZGEMs;4oNnv~AHug8JQ?ys5DF}hX}GvsXa z+}W9%5(1&Mm?Rxc7fpt&?Cn{)1LPMJ>TbeUWk)ket>Fg$Wxl1R>WbYpN5K2hm_Dn0 zF`r6@duP*vW~&k`X)$EkbO!#RkEI5Do9h+295_3qack}htnP0dpB$9AyLp`o-F06q z=5nmc;?A}E-m7(#7udTwyHIes6o>X`To!%2S%^iHq|MdX_Cdm8?oY3oXr%Hd?*_}u zzegx30&6w9`|$1Uq~qdDZwE$C3lL%9QBLdJ)f0i=fE`?!%(%z|_@_rp5b(Nm05J-b zy#YM%zmZ~{?P}%x9T1j}6}cmT@GX{7APOR{W6kR@bGCqwu$EJQP5F*hAD~^6`rI#1 zA^dZf0gWSMocQC_zNn8)9t4GXE}|X2$#@(b&c`+O<0G3ZP=G^EU`_eNPXges6hBfV z;ox<gqx9nAXJ_vKz%u@WL<f}8aXVY#HPHnS)h$}L=HHXfw)Lq%2sk+&uJ5^Ds96yW z)tVZ5I64|1vs!x%_-Jo>{={Qbtu#QVMh~C|k0}F(!1v5!vtk0YdwomVn*If4vaUsH z6>chIe5V4C4O3Io<KpFDNUKQdHfSab%3F;&j>j}7cgG4s`IaMZ^8nB@xUEu)%4}5@ zuaL>t$?COX<JN4G)Y=Kd`8w2}!LZRUGj1OTsJNGgf<A(~#M|<XzcQ9stH$8*w6Kze z3`IpL+uAbQGAqse{#EdqObRL>>(iF57{9x4Wb<cjCX#4<9Vq*oP-8A)Mfg#P*rI;{ zAb3E2W&hKCgV2Eb3_!;4`~A}&@NcSk=eyxgn8n1hSBgqXtP7P0!=<sp``LzK1O?+0 z6iQEkt<hh5Tb3!OluG8N-!WR-ztqBB)m)WH3f|zVWdT6xY->PPb1EvzTXu^6pIvN9 z3!6f|r;A2vM|pgc?0YVneSeg^bbGi*vb!u%emmhQ*1_k<+rkN)dTRp-aZ_zdCoOC~ zK4p@zv@mC+(1F|hc&em?u)^2V)dM@LSOF3^b~=`@+4)L!bKl9vI8y5pqb3O9A}6$c zib>>#5RV@B--x+wzF)$5YJB-`u=Am~@gB4_MQ$i%X#?+?SH3DU1R!X@T4U8uH~!|p zHUt|oc#a1V@8|(^jvSY8NIAS7(4e3Qt>g*@5WwGLi29DsF3)|D<5WhvZViqBAHEYT zlADTQ$}ZJSA0rAtm+XHB*9X{pM8NGmJ-}6XiMCKVO{3bHDuI9_Js=a(LrV+bsw|4= z>Uk?SbgfObVS4E$CX`;n4qB7Bn7-fGUXG|uOnp7COP{|kwg5XQMU$s$jEQ3Zdn|=g z`TzGEkOEJh`tKJ73%WH4GttFpw&Vvx9y{XWLWP+yK}Tv=l_Z_yA?F%)29mo7FG@-( za}c|lr~8t^t!HI-dOe*ZOKauB2aDqWOH|I#{BO?de<S&_GVtRsf@CDV+`wi;$Z5*o zblK&_>OcH~rZF+!%;d$Mhato>C7mjjC}fLiSVmqF(R>FATt5S1Q<yinOhscE3qQX9 zLx$sJVH(;ePATD3$z`BX(*7aLMEWlx<7YtTM>%i-4O7V<U96^1KyS{VtC(Cc?-9g= zSo5!v-WQ6vtPe^$DZ}E10H)!wum(qrJn-`aXmNXgg4_GhS>VyE6^+Vj$iI*lfX|ix zLpm-za29wFE2YLu;8h+xAbZO>K^5d%?)3Vt8u%|hWKTWv;(z4=zQ_`$GVpV#<2>81 z>mpdr`<r7GhrZ#Tc=h*RdM=AF{^t*e(tiIwr}RN*Nz&od6dSC7w?x1NIT0^1Y%n_8 zlALb-4iP{r1C{?jPz!W;dPT>?3|H~@NWN7FZ%xjoVkd5s2(bQM`$kBFu627XdCjs= z7~jGO_EnDW(wvrC+#Z@h(GybuWr3@jEIz2_$t_ay_lPa2^Rd!&mkz=fWMNihx~iF| zExb@GkA5!9Qv7pi7I>jz@@M;wc~L20uz+lj`!yRhmPpn1p=b96Wb^{JKj%Fy=hp0` zTA3*1xJGDGd&tD*{pn?P3H!c|;7k+L5qOJ{pEdeVsWS|RfoDfy3wF0Y{A??!;<*t^ zs$8yBsKB*Kv%h<vRf2QuoBN$17H_Dv_TwPCK(ifK^H+J-z<UW905$aBf%`)s@1o{` zJgM%Y=nJ)PYGvZN9#Oma@%W~C#Y`*;SF}EF^SkkD*6}x=7;ZoCymCKCgxb;+$@T^W z<Zct-ToLir2bh?yk2{QqDH|q~hkLdJo_3GxX{B+~U&&;GFH$=WFlcaE1k$r@v)UQx z%UcURb*bs_8&LiG@F$&ZcV9DgNyuFshKl5i(%f*P822|}eO359@0M4YTR`s)QfC|0 zeQHkZj5IVa54(u(C0yN4pIZg>C3~W4$v<0JsB~lDSCXgb&3IoCZ5D-PeN^BY<>9V# zx7`)nqRgtGQps_+39cbeb0a75zW(TdjNIq)|IWbZ<K$tez2fT2F6Qd1Hq*>l8Fh@_ zENqLy=|EQBvyin1*p#bXcgC_iAXK8O+#P3a4uwT%KxD)0tk_~50$g|DS-B-jW2(`D zu|q21O?9>k&i<HC-)w_Lfwk4l#7AY-{Hd_1i#adux)Uqai529{b4rnJxnxguGu~}s zWSfkdM_S@$Cr77cq|2BU5G9-~=$(G*>l0~wMd=cXSoW#k-kE7;7dq})ARvx0Dv9en z!mmu7X-1!=o2<`^o8*S8ITXs=-oFYAuLG@Cn3>zgXH(rDchU~3yj5FBL+~-u^lxdX zRqQhL54%|-t2B~1++NQM-7worIvb(;v+2=Ko);RHeAtYdmU9!=P9%J-H!XOL$&C`t zqBKr{5;{YSRTUFm^YK)gV+x;D{2=*d%3=7-X3?@VFuV{h)A788@ZwLk{QH7PnQ;Ri zQOm!xiLu253V0sH%HYdEfd^7aJU5jb@~++O5f$#RG4k0Bb{K2-yx38dSxF>$OL+P2 zaqN4UC&(Hws<q}mZ2G!VvGpyzwu_grEQ{#b9HAL=U;BxUXL>U?*YeDIG_tw6`RMt{ zVb|o-O<p2%TE1Q3_?6@E>?J1FfjwUHlB`_a-$z8%?jR%5^)q()*Z@E8r$Q9|{$mq^ zkx?vrw`f(RSX{9V8#bZ4(_>UB*2`$YXcxy(nwxn#?4w@d^YSpZ5kAff8=-HQ{1gsE zB=jf3hfdlCPjCxl!a_22)n=08i=~1mNhVv<Z%*-O6gHD9?QTXI5XBV<9Yo+nq(E?R ztXRvQgq**<h*j48&n9F$ANdTa?9<HVwoM`U3@dv0Q)9-eSPV1!kj}^A)beyt{`sld z-YmmS7xCK;1Ai54P68%-Z13$!gLVbRdFp%XR-K*pS|XVlMv|!xxoZUM_QkMvTeNa{ z2`Yo!Q$5Ar#N#;Jm~Mo$=SxVs-g)-z7Scm-CjY1~L?En#GK=)O*m;wqcEj>6Md4|A zm(dHHki<(w#PK-mY*!}&-jj@2*Pt1B@Sjykbb*#ag_){Pz+ifS;b_i)jn4LjOLYOL z&U>M({wUv@$=GCf+^AyC1&6h#e4Z>+_qP}kXJE|p!-LGr%cPKedZ=0Yd5ZWtGCoMT zbOW0So_3ZoUU02%$DYY6MUru&#mV=u!(iP@+rxA%2fuzqe676OT&Bs84kBf4t(Yn! zz=##=X!VhFaL#;hWzOc?`+~HOLLlXWgr{#i-mR|Zn`G~~9$L$+W|Cu!1f51HGdOD! zWt7g^oqnHL`IuP0<l{*>(P7Qc%EZmXG~T4pCr8r2v%>?$Ugoa$j_v333>foXiO<^| z|6_&-3#ea0&V=<|q}G`3_}Z7)*_p13<1@n}ww{OC+=H)*;ypZ8xL~pmk8wB~JYm#i z{4K}!eVF#sZQ5r=>Y|mPrj28Q`T4q(Ar6BykD}!-RoPTm4$^Liq<SWLe3THW_3@!? z(Y>dhsC5iMVKPtBgiG!p-Up0e5DbUsvDmca-a-GVf}bCa5Q=nA*Pk71K1zE<YLHdY zECbAj_#mJtNewY`t@o55s)Ed4nbRi5OR3#l{n@3v53Cu>?{+(j?iy|@eV9zNxen`t zu9<t)Zh4y{`oIxI;d9ZKhucYNTOsV-Y|Xqok_o6SQto|DUfxqbBRx9@MP&_#(wtW5 zj~W#Y!fI;SaUKO0$??#`@qWH9dy-Oi^Xb){h70i5y3^LvY{N+qBc6Y9Nok0+5{W^w zo;K6_yAitQi+73UjEyyA<vA9S*S4AIKW35*9b~NE;;PrR@NZ7&_}74pwzic7$;^L= zyuu0rN5QDi8Ep#3NjmLp)rAmf`yKK$?ZnddCU{MH7&4zK>i$kRKMr103{OLhU?jDI zXFW&X_8A#s<|=x_Pd*J&f|biNn+zxgsq=5M637fw;&LqC=sNgYJTioT+p`jcB0nUg zv62D%kIi$yo4kIVzLO5lUm42VuJ)XJC`{RgAQwB_;i{`;=$l4%mT36SJTWT2Mv<j7 za_>l2F|Mw!u336Es~B!f=eT#}?|?lWC#5v&+1ZDL&Tl`KZZz{8Y)ll1MK`rBL*l-% zGq7n1WcA4hwHz4-HnzSuW+CoRl247LRBzyf+Kn#NFcQt9?%z@$D0@?#-kewc{z-$+ zZkKyF<vLl3%?{YA5$oweLU>60AlB=%qjvUd!q2p1X*0hTJ4Wo`oMgJ%DfyP4SUL#F z>YWaKc&NKO2IUI2c{71cz!UFg#CEcBcj`HJIkfcO(MsH~9KFZG)dvwLmzU>S(;`%2 zAztW)5?+VsOusq4Jzh}}L1B&+;^;~S#t)@-nYK*;5A#7W2f#JUceFE6zx{KEEvGqD zAaC!mnUzV%xbyYRnhxP+A*c~%GPPkSrB<Hzj{*^>fmp<7UL=l+d@-O?(1&UHXfQtL zdw&N;HHc2E1<`J>;Dte#gr|V4nD`#_{fUQoHyj-K@%?}j1U1eej@*-G!4tT%oK8J6 zgs~KA@`WJ^-3%Hc6LMGDT8#1W?-$=a6#FzlA6ldxUpVcnt~Cd2O%VCw3cJq^`aRwe zGI>fnBtGbiq8ZLgYNAzuU(<~4t+rqsP~_xH&Tv*h=X04tD<fLne-DktswPc`kygbT z4GzK?#Y7}{XWD|rd>hC=?~E${yUc*EKNS3fC^?gRH6L9zsufBL1V*?b0lo*CPqVd~ zF?*w1Vp#hT5smf9ag(FN<!Qdw3z8m+7sMj3s27|Z-YIBMvHH*ox9|TMOB<}i>?Jm3 z+QfcuoXElqhq#!NT)%Q(CF0)tAk4=@x4i65rt0src~q!l96A1jb0R*I!u>G)?eGDG znUFU~cVWCYwM{A}B;ONh3?p!_<4;W_>9nY?a5D)cmOC>$SK}Ap!~WrH>tlI;@h<m^ zzhq1~f3+PUk1Ek7sfUe<vyp7F!qSJcAiWaZSgZ@RN=DY-MPY6WpYB)gc1b>#XOJUN z>dp?$$7NejG#QFtDAjmb_(|V%+wNY<X3Eivv<+r;(26!+Z5^u;Fw1Qm_~tT20#Wpr zsfU0oFmpKAUtTKP9&=1N+m4~=O*(fNY-ylAdr8CUiiiG$C_Fn5Yi|vHlmNs(ne=`= zsv9%a7w)0m{-BXx@IaSz{S${>P{m-gdZO6jgg6&DiG+-9wx@P)h;casvo@bmuGBwJ z*Wmpz|Hk%JB{Lk~haI)6m+br5dimbwr9HiMqkr%lG$DLjhmJm&y|s@XFV6iGU0=-G zEMG9T>=ikpzO2_tzjLqVCk}C8s_6Tgf%pd^kB?A1J{eoF8cPGbkW$kRi^Z4=p{*_Q zl)2`M^oH3Va7y{SAT^TBB74J;2#D3ep4iRF?Z6J<hmElaL#1>7#q_<|ag+H?2i9gT zq+@&9$60E$MRA)B;vo*-?~Y%U!>7Oc8u0vh#O0>Gc$l`lq@EWzd>q|ya=gR4ca3Aa zF-C;h+{N{&Q_!P({o;{fezDu=zt;Az<V`W7l)vc&y+5f3qY%nFJr^gX`CGzi(DtwR zYb9-64G$Y{g}}NpN1{IF7g(1~B~?uHWu5S1a7w1Zw>Ya!6#de}(9#7Nff7O~^Cj%^ zgr35_ui3gBuE*?rpDh`k@!5=*?$&F?f~Ui1uTtOTerrorHVhB&f~u<avWXzZdHi*q zCA8z~y7owVOqq(uv@ihg5`rq3&q{x#(qwRzA<gp2g1#-MhVe>&p5Y)wkr)>^Jt>w{ zF#ih*WS+p@pK9<|U7w!Wq2@Zol#ldxT7ezy$py?e?tILOF;Z0oAC8J$n#<6%^Z#ze z)D4frux6(=nzvd0Ghwzd3>+$d1^_2Fd%&+L)&&W*T2mR#pC8_AAcI)4D%uP4V*z8( z4&JQtG^un&RpB3G8<~Bwngr%T>%a?eh==UKe~f^$QeDu$8cFKzz@LHau)lgs{~KlB z|L;I3Ul2dZQRi(>vjZ+RqdYrw(R01K8NwT9IfWzmAeu7XJ@Y#aU%br0{=rJO>RG#d z#fyEhBI>I^L1XE*Ca=ByF%otnSt@>yJ99}+TnYhqS^-)^|36}7-&;+`hG>*k`qOIl z^2`W^jhcJL|AC8K$CeEeYYAqPH%L*-3R{XReQ*3V?{jn?rjyM%tjQcO(IlrVjs5u0 zIP}jQ9d`TuTBgj>+(+G3o@!$glcVC2NPujdf<E4rvC|~doQ-h5cXASQI`va^Sm0BV zwNTxB2;xzGfqoO@zxK3L{{5@bELH{vi^bQ;l}o-<L}mLk37ZwPFbg=oRfs>$=Hwe% zTWuqwD)T9hqRDo&KW@k+lPU#yw%gIRVUaBN!Az-;`+jd&WI)-<FKE4=eSI<VYQB~H ze9iiKz82GMZOQl!|LjiRWcmOsEG7O}2j5ZHG7A>L44DXdwxMgd^@$(gO#G*hz>|wr zlNHYku=~m|9*6JtpC1^-<gM)Om+^sVNTRkRVaUq7yN=~GyJ*_p9%>dQ7nU(E>?=gB zPp;&%?G2tks+o!haSG3809jab^L2L9SDZDj7t}(PFxaM*qm(%eN9TZlW-cX-Z0yto zKO42PV?X06%-%7A=%(E;M`m?fT15qC;))>FU04TH29;HwJnAgmxu}?b7NMqm3ppF= z#T8jF%mj)%L&oipoyEs#i$lGNCbT*Z(?VzEZ^L4ZBcl9KD{G%}D&=T;OpgYIF4&D) zKwyKFWxCYvF%pj5>Xla@00r9aR((i6JQGLgH*C-hg=TJUuZgEinO*wbMgJU8;@j5% zySO{&07)+e3bsvWX|RD`b$TStM7_0EIV<asA@=T6Spu}MsY{Y*5>y|p!GUGKCe?B9 z_#i}RTDN9Ts$%h3v)8SWh6V?ZwT<3JeOuo_m{{2#oLxIWvST2T{4M`3*6mV-7T3&| z4Ve-1z?x)0q(rP>qs?hgRh(SRl`CQV^gDrNg(&2uEkLfbF_lhOzz?u-uxY&>N&Q{S z?}%?{XlOV?HzN2|EXK{F){I)SNh1s<wL|cd)b)5i`qvt_CyAV)VP-@`geAKX8R_<c zkWafV%>kgW3L<eBbvZkA+p{y?6V>a^hp}5)tRp*rE;|*|qU4p7hTGk4E8^k;%j;<8 zO!4Y@x$jpkE0B`{LNooCTe=}3$d~dsL|8I&7nubK%4y|(t1$D=qg6I$_MM_Yn%(7x z)?&}L2W}+ZE4=`{via7V-3&h)OR}p|@9%{njL`+F+rOG@HAatWk9&JV%lHmD$d7;I zwFcqwdg{o{C?mP5QFWtLSbakV`DPP~LurN;A6Ym#IX~+|hrUmnklG-}NE|{#W%vbV zsf7KVClljzXPR^c0FgtP<cbA*<Zpd%{b!jL*)6ZU_}1d$av!$r*(GGP`9+cm({MEu zH`aO+P|M=#{Tc=7Xd<}^ZJ{F_p7icJi~(Cr1JdhRT8oghSW>}ZVV@0bh}CC{&AQ{0 z^&>BM`uU$DS09)<Go`TeQRk}sdXi3)40p~Av3kzUa*m7WX`KAi2Q(IWrUYBKJ5#lR zU4B~xt2fX&w;UuateHka!d=Y5eCtcV4R-`K^=@orf=C;JaMpmg>KLZtEpXpOgs#Qn z;vPxf<HW@+bgH$zd#^07n4h0$;lFP2Bda3DuA694f;%*ZVLcYFInDWa{%mdhISIWG z*)RiSR;S9|++*IPx7OT2hQp9tk;*9cGX?8weA}V?_x%qTSGlT9Qcu)g^V!nT#tPi0 za7<d-sTfBGWc;GQF?&@_>S-G~+bH=aMt=D<inHZ_!=FvrS-|z3K{bmAW$$8C6A6Oi z`Npr$oTL~lyj0I)5&f*h+1|gfqD-UCe(@Gjq?vpa2ACunUT<`(ev&Bby#?Up4$E*2 zBW+y_!zV8yr88I?Qd%{8`(gqWvAi~(j}tNhX*f)yic|eSf94u|u?(@o@JbTg-RS_A z9<)f7LkzHU>s?+AbJOwA*!JVwdQkFDe2*KBr`Eo2HQhP;`2zhU`(`NlR7v%CmOVhf z;p|&-3s;Xp={c)$Lyc}e=F%-tEp$TZqSvLxxDWS+$vt+();Ct1b_bxjk6S$VrqdK9 zr0CfSmg0tD>bXUr%g`y;b+pJSg6=(w>8MTz7jpQB6sNu2hie+Ku>QNB8LYc@)Ht@m zn(OpN_m|pEY-U@RJTtllFQX`s^uS+Aw>~b`(m)bkdlgA)y+ZoI!{0?uwx(A!Ow|Bw zw#P=+WIr4}C=^pM{X^&dtAOhhLAYAQ5MCMIo)Tg}vq?P!nrOe;Z2y$R5ACXI6c`P? zDrhqPv0z8ct`FI8`Se(Aii^Zi<C>who+(-#^=>ik3Kc9Dch0L#xFqIf$;oq^nR8fj zLQGCZ8qqTlq~@Pvpqem>ce~wJH<`47N}V|oy_4|2JGDLD!%spA5M3X(4g0Sg@!K{~ z+*tQ$qiM;=vv1a`wUCp{dgpV!`0Y2WZ#nAng2deKbg&dks48NV0%n{fn|)xzOE>6E z_bi9_;N@iK+;kJAh&%MSwypeZt;tw32gV^*KK+WcusJ#8SQ7Qj?>^Gl->|OD`SEZ! zJ$vPhpSV9dqqU3iz)#`&pHS-!?o_zp_v(euR#|V6%;eWG2A9q~#2&DK^FeG%%FMGl zyxUgO^vHZlj2I1&*tnC)HhS-yS`v$xFDj`r_S$mk&YSP_Wy^d^XY4c<?>;{Zxy9(r zZi+QE{d*WvqJ6hPWmi7UV)eYcwx8DAoT(usX#Dg_$tou<wolIZmdcAy*)@SFhmgkw z9_D7J{>iY$T1-fD-N#1Mja19G9<wh>7@B@QGZk=C<-ynXu&fRs3_m(f6r%tSZ4QK_ zXG2<ohO8?Wu#2eI3)wGE`{pE;-3BUWe4G#t{X7Ivxu8}uzXAA2Iv+nvkUy`T*iHBG zAk&;dW@}Iv$CxObnIX@%97pUv<lIn;OtA>5*40hV=3iyEezN5SXlz-ZB&$n&m1XJ( z-dfeW`j7*<p!T0r-hAsud^Gue80a<wW~)HfYklY-aYesPct7=(@oFIK`rc+B=pO&x zUP>}`B-!+-t3{WO;$l1pGkau**kGexgc)aw8lF<`T9Q+{z!1wcO$;LO>m?R>>Lp8W zcc`vQlz@-1b7(_;N;o-fcx&9_lSR>?Gx`2aB35*=>wrw5QYjpf=kD*xw;5KWOhdmR z{^DfQ9P>|IS2Acx8f+e`rg&|K${x@xiVhgt&zy~-WJ7VCj78Y<soLkhlCN}l=oXU5 zq&YcB%x=2k>39<dCwIF_QDpSxyOVd#`Ru{IcJ$}Y5JOVp-iT7a!A^3bsESLpJ-|IX zH}|2I3Y#&0o*SF~JIEiZd30HRFe?O`UGMmMK!JvLmtWXT{6b(%cC4mXHk5gCZ|1O1 z2YW}rzRM{h7vl58jhZukn*&8E@F@3iZg_JPL^)Tt#rt`q_-$LuliEDEN?1MX2~K3i z0(PpP|5lxT?t)N#uBJKg8dfb<D{PedqXz<T1+Wu(<u+BMr4ANHOuV5KpgYXAWo~+$ zg)62WRb<@l$-Z0QV%892uXpykPo6mvj#DTPt2TkOEflG}?v-!uUWBnsS6cR+=r}r} zPsr~#+H3I$9f~n5RLK++td=vdxMz?{yxOzR(nyx)eg?A>vgo&diMugn<M%*ghX|u( z+D{Qzd-^=ExPC^IFJ5*!kN4Nl9iI5FM_RaWpPXi97^_Q%cza}lQ4|7=z&9p~rSM&8 z{KBDDYrqx_*h_kxJ9R$lf3Q?GHf>D}%8Y$S1{K41yf61oz+}%`wFYXvuWd{mCQD_^ zM65Fp8hC{6FPF_`r>P8Qhwd-snC6l4rH|NrbX=<LewQF5a^uZp7m74G^}TcH=w#Vf zLFe}9R6HesQ8JP$W}C4~t3u|Zr<<~X>pxuuQBr&meC?st5DE2+wxernu5WRt|1LF0 zd_gTc!Xewaax}I@Jm^P?V%(ozhM-DuaI@RJPOLxg2I;N>5C&1}`A=$v@7$cNXLP8C zbFmpFV%d#b=5nK{^GBPM8U_bd7Bg7|URmud-k#EX++=<`Ty44I=He<s=N;Flq`eNf z=<%Dy;1>4zNIjc0M5$NBPQg*E^U>>b4c+3Z?5R$}2&+(RH07w{_&1{{?tYoR_r>X& z%OhG@;wHl$*j5?~X1%|ptD~nJ!hSeDbx*gjwCrJHI8;q>L6ptEb9a201jm00J;~ki zSL!ersc`3-&688hC)E40;=YS0m=Ft4?FMis+Z=9_1suVo(Q=Z5q88@tj-%tr{?)F> zc$6JK%=S3popAdh-ZvVTwO8xI_VzdF$`oARLcI+ZOI5DxD|Jhoa@S(dBd7MY(F#@$ z7H~FZzK$=dX6?o|6~{uqduKJT@>jP9zfl>^jlu|c^p>(Htz5xuF(n%<%En<=es5|n zU)Mk|LGIwqJG*c1EvcWsTngWCJ2Rg&Tot|y<rrCiZqxbPxL;Vg;N!4&`~XE-U#*k* zJCH!C%)s{wQzbK1eSF#2z7#S}Yws22VSehf<bg1%JASkl55!K8fC7P9l&^l{%XPGg z#L(Ds-0xD}{n^i`UBv==tZK^UYSmtlq_%#3)shm@M*3yyY3D7jO!g3{58wY4sqb<` zfu?FQKVu2M!1Ql61N3F1jBJm4wS&S0U4424v@rGBm}JK~C5TgK!01<jW<_u&Poc;8 zOi)LbxdtOG|E|Ik6=m^?>P%*wQMjrSBF}ausvy`=AjD!F>XyJ3Q$g8aJ+n5NKynq* zqrq`Ruy~gN;qA!zz{ry?H^n>kSjyc?IPK~R5eVjJe)(E55I|Zd`_HIjMND$V8tH24 zeFQ5fYd;R|B4O1v0)r(xZWQmB*fr3w`;zmGJrvyI)yULTA>tXgc!xTaWP5qLpjs>a z-kmhlM%B*!yiI_hcktt9OS6f|j+wbJSpk8&Jx%~zBXRQ1j%5%BJF?`X)#p!6N3$aE zd~iu#*<wfed@gg_d`2pCb*lF5b$k-?gW`Zn6pF8mrIDcddG()FYR1OwCNEd{`-;)3 zaKFG$y)DKy!@ab$Vh}2+w^2-!b}Uv~tBcJt2}y>1JPv<G>p(jKW4$Bm{-t?!c67SL znONVA+b=7L{3k4f@d~PsU2xNjTyppH_%7T$P4SgbbR<lzHftk`^uxxmKmPlQf0DG8 z^ionw=X>BSvPGV;U#t)O>OP%&DL#H^e-m^d)<lAC)Ti&awj?liEVa@k*Ng|wu6zZ? ze7HM+<o&}ziRx!GQl++>&~P<X^GdfkOws-7quO+ay0I_t?z+I_>)y<;`aOXx9rcWi zj7i2ES`g)t0;8MWnN6;d16feZhE%e~Yz+^;1))W;!&vi^ORkBTcewvubm1{dHj~ro zl&Dpd;ys8eT1}pZgZJk1vfJ!h(x7o0%+8(#=zFlm`qN7Il@Z<hsa-Se#k|TSkVdfR zcge0ShK44VM&^I~Q~7h$=sl+A5bHB1(~9JZMp~j+<UEI;p6YR1dnur4AFg}8Xw!n? z2bVbFrrzFpx?xV_>2@oaVU8|pH1QV+9&n;U_=nU3ET$-B_0~2%XpME9O?;`rfGPi! zHvb^`l52f}mV-_-EL?sAXe`t9k4cReja*Tk(CR&IA3}S+?WLu^S`R5&@Ploo6Ys+3 zW5tvLilUm~GAL@JjK2_Wj^PD*XcRviUh*)(82+GD`)>^!wCUi68jpB~2OZmzQ`5OH zktQT6U*EAITKB7;61ryW2V!Nal4IS;k%uB%Qdd8ZA}dtS0qk62SoCvTOEpRvcOKcc z_;^iT*_~~aI!_Gy3r(W?WJj@Y*}dBwazG~LKe>R}F2AcZ!^E1f(*q+tZU38HceYri zCVEyH+sQ6RwFBezZI&z6>57Xd=+_-SG*;c`Qk!@cxt|rzIxadcLo%_}{n1N5#o6gM z?=u;uGd_Q|%4t=1cWaDzdXwlZ)%$!;N~f^IMa*Y5?|SOa!x{*0bG%=IYYHZ=-TJA8 z4KwlVZ;LZzeFGyd5FN(992$kQ+_-e@E?$u`t!nJ%oVEJVSd9ji04WBFJ-g}Z?B|&} zTiZ7smcm3+B<yJr_S4a2g5(m~hVr`@Vikel7-reo<+I9@3LW-QC$Aq?#?0)AK{0qb zdp2D0oUX%J-2lx>7y#EK5|?|BxK8*J3rx?9C?eyeWG;Gfg)8Tu=XreEL7xyq#MaB- z(qIl2EnkS<>UyJ&y%cx)*Ik&OJn~R(*ZloqWK8KdWJ08*cJ1Df@UxaObnf^%jS^6L zLv-AygnCl*QxYWq28RW<w||GJE1=4r<+zAI@eO%(;S9UF&=$25jvCj6i(`VaIc|57 z#&P?&(1r&}>tVt0tJh>(mYW+j*^;M6lJ^(elkEisQGL+UM}>ki=f>HuYx_#<9BrAe z2G&Z%Oi`@HHL<#>3r~j=Pp-J=aV^Jdn*?R!>mcrM#pLm=wOnMVrk8hN_E#dJ%9y+r zq^6m*r#JNA&3gBjikVP@nUhQ1)AE)Jl(PFOwGx<(jp6jA+A1tiQAv)|)zhh2UR430 zrP91;hYxzwmX5V98i$d$P)E6uk`rwFY3)!+FcPO`ybox!cy+S(AryY{R5InNrRRF{ z&c0qO^Cd}=v$k5|b4UCFx4Ug!%B&Tn78^5f!ZMsSQsk}410(WN=KunYv!GHHbL5hg z8!CzI;TVP-HM@>2vum?>zkEQI#(GhC0H`SDrpjRxh6B65>ZTV9I1$xX*<C2VEy3ZN zUL*uEY1ay~4Iew}^xvL}O^`V*`HlejmeQ~VJfELQN{lZ?+)c<n@bGxJx;MY{>d-Z# zPWwVUUJfEBQ^Vjw+yA<g%)8p$R9g8R+!qIKGdtPocby_4mRldjZvV1}CM8M`U*{%M zZyI6BTN<JEJ7T`|fHB`0`|+nsiUW<{csR4!b0W{Q?4ArV42yUZ-=dy!@l}32-rsGQ zHokHjy}2}|{Kq<LSG0V5D;LsX+@7j91dc5z`g6=LVG^INfgK`Q>O1=Ot=Lhykck_e zg}pgPvEx+8f${)?xj=gl*?B(@qQ9%B;%(_n6i^NaH>*Rp;6g-)qE{QSxwkD`&^=T4 z;;p;BX2Z<6>jv9}UG$#1k`m6WEfEosN$fjckGNB?f}%o)=lxrus<JXE3kwG=i@A2K znjc~D-QlWY`$|vOfQB5@gy<C9NS(s4=0|`XANJ$a6X*fyiunm4Y<6e&s^I~DcTb&W zw;aDng;}}H%0&y$!885b?McvjF2V{NY!({FTlAg0VME1iytWn2iUjf{SO2C<&c%Eg zzs30nUdPn#h)tweD?thi&70|7oNtk4<|7ZA5P^VL`sZOip5paBy8*;6E%J-ID!Z50 zs+F~a>tgoJZdUFRXj(loQGc|}!9HaQlb`nQ*;c0Puj9|$gva*hAX~~|^@CdN!C)%P zgMd3FRfmU$wmzQcU$t4&)V<rcsarjRx*GNchKl8gj_`0(5|+6cJZg&mAQYhOGI$tV zTB8H0L%-fH@zH|us9Ta0uCH$sD#gqu4b1J7NlW+HxBJ!<9Cy|o2K!n3&K|zb`i&Zu z=QLpZHt(QGTCQcG0ZqbC$5#i;7(h_+a|wAOGuVqA2-Cj_@0FY6hbjsVmf!9nFtTqN zfs}4(VY%@g6i6n*aq1>yI&kJ{?V4RyjUW&R8X|?C4B^O5y5tn~9v_bdNG}E%yNl^u z8p~R@KJH$rDV*+$rtlYHY`VXVO76E;1rj#>t!->f?XB-n*JCq`zHT-IFBzLu^dpOK zQB!Pl{kf3zjRm1PQjs$nrilyGXrO<$1_lIvnX44A!0*37pG3T27J4oUIdW{UDe77* z%@#APUGtQCDg+T}Q$^yOx{YeDOO^%MST7n?w1o}>;@<uJL+KpOPgs+CV@W3)?o+&J zFfa5z*tTxS784qJu(Ow4+MnUcYHlXX`)wpUF5aUP1P&l~C;ByFT)doz=T4}_5_c^N zKzMLC`+mOJs*_Mw?_{p}I31tlUUf8@O(B+SJ`#>R7V(~~w^8g!ms7s`LYK4i$C%Y8 zUH0yH@Tseqp6tt-#)8wZ9vmjtDrR6wmd-~wINdu$b{H>ICKr%@*)aT$N6F-imt`{c z5oDY_c^6G;O<fKZg9x51RG#6UrgNXh8z32>U#Vsx)Q~fM#74CC?M>>&3?6D}@7LAN z<Gvx-@$wg=Ork9N@t>~fg5`V|WbKoq(g`f0vg-*`!+K<_#ocM&Wad-VIbD4`)YMsL zzWi14NUo?^XFQM_KqRx~J!`)>oS6a1_N#qx9>{qbn~hI(&sMG(Y0++HrER3<9#(<L zBV>`rcb@y$Yb_BU)t2KuHeUBX7tNBNpy%vOC2&$De)cs{nrJdi@+O&jD2?+%iJ93I zUq_Bf`Gb~vdhCq*9G-LIJpNsC;6{ZzB5}^Z-$!sK;l4Ka<ZCVgi6*qo^*ZUqGN!yX zH>IQDuM;T0Aydol_^L`N^t3iZ#5)o0sXolMmxv#{9PAU7hR%(wk&^KaDUa3yPPkj| zY>33Xg7?Klo%egA!n;Y&L@D1i1>odHT=zXriL-sbumtm1c_PaN&5Nzt<LWusTYkO6 zC5s*?<~4naquOlX*z&;9;@Z$+ggU-u<TK$1WBdfa{i`NUbHAZKL<3!-E0tj`Nm(nq zjVjAV!oRXz#Z;YN-llVbc*7qXe<-7KNlYdx<MD)t1YoI}Xkb0&G5=k;=zeIEE9v+d zZ19*}=St|YW@${c(($>Q`8J-Gw6^_hgX78Yt`w7VW}91N+Z!Wwbpr#<m90-@`*kSN z8SNyCV_W%&{9kKsA#;yPrJ6c_t1tapb8G-dDk(cV*MdB6GdJ#q1=}?q<6mKw)~RE- zsnBq47iN~%-H7ZK$5HOtPggzx&psmqyb<5+eWy^ublB2;I}r4n-^llS5|sQhw|20x zv->sv$k6-n*eU72jE0?-helK&+MgETnG9nlI(@~~u%R=@&0fpIeXwGadu(Fi5fhov zcJq6@R$0*y%<~;iK_wP_eC7;$k$*gM6ZB5-H#z*wStrLuzc{YMqs+xeFa@9hp}r<q z_^ypZy^(%JZ$veaO8O?Z&?#Uy)-Tzn;yO(|VPP7Ynu~^nhXOlt!~Zlcwd_7kHl0Q& zOj*|(17oE0lsB&ABvyCOp6%XRivGP|vmmw(CO2QAU%Kt(dxLfhdc*q+9`E-me>RTq zC)Ka;G)13VRa<IQ8Q{saXG82oy?A~zn^)uXEP70ou?VXr`0*veHiB6NlEa5B()hWE z11RahGCpZcO$pDh<4LTQrOx`~HB$NWzpa|<7n(~HD!T7*cHc|^B}}+2?*3UQ8!d<@ zM9}~&mphAGCzo(kqnydL$HBCTu22C|s%VMZW)Hg^5~6e<>%Tm_)LN<T9(-T)BW!r< z24pz@q*&k1NvE;v@nI~0parCV^{zahc*^QwJokPf0ky;Dqi<H!M{s`lo!@2hJD6U9 zk#vyE+tX?)kGIePD0<q5{ihy!T#5B>BkQvVoo&2_>)^iy(f^OSX*VzX^j7{=9#g0N zE1|SeM#S+H_Ze_sb=r4NV6ze@6A}O9_x*j4IMF`>&Ckal0g&8(_|gArxq$=!G5amf z3IHtX-mSd;&uuUy!NRsr|MmlRc8gp1TUBMET_cMSU?82s25Q1b-o%X!fB*T5EQRQB z{C`lwOwBrf!~seE2kNn1@hQt3>O#-<-Nk?NY@7`ID-Ngr?oS%%qiN3M$XKz%vqlS3 zSsk?$DO#_8VZiSj*M*s1lJF&zkY{w|y~5mn7WPupV>1H&SBLG(J@3n@oFK~(Do*!j zL>JA{VHN_zNqvl)5r{@p(eA@0)7;P8z;!=6sO1Kh!$}R_>ZlED;WRZ~nNb3~d0)2_ zY*LC6;DQJ0$^Sp~7yrL5G`oLq4PpoA0+R1uh4=ginvIp*y?oSYK&2Ljm>3%~&)EkI zlC<ih0a&xN5@wkLD=V`th5-#ej{ftpub7Mgfl<G9pcyeSQ8F1hsS`g1=Jq4lkK(U^ zdilYCn;P$hcZnOv{`(T4jLgi#1O0p)yyFuRRgHMSy&vYPgF83p^z{Fo%tO!AnI?3z zj{#LOFi|*@Ngr9*SlDE3{<bwz@1LCI>?r;ib#OO9225;~$mf5B@6@|{;jN7YQUA^? zGy=OFAnc+4Y7joK`ec<;Sq78p3=h-;mH|<q{8#;dEeos|)<+N_{eRllS4j~=Kc&C$ zuAEndsb3}EKCb&RqRad!_u0Q9hB=!5#foRvy(5ks)%t4$e}8l`OVyM7f6?*%x^XHD zIQKKqVqjn>p8+jc&CSg@?!R7MUINm48+EyRdF5td1Ox;C0pB|3$Bz$mbfG06K=i+s z6}}3n1MekQbM{kz9vT=>R#mkyiv9Za$t+vZq@tptQM+G>aMr@N(j{gc|L%$01qq>$ z5=OmW<v{c8#n#m1<i8&+9u184(}=9(HJ}Bq4WJ|jsFNt488*4B13kS5#7yq*Zt<yv zKb6M5S_T>kBM=B4HIIWuky$~H%jqgJKmnrgA$B5gL-TDgptWZod3?FDVmixCN=nMD z{4&9V;KYZ5-|0(zWC@Sp?R1T0?6H@P)9i~`iXxjeJ_E{G%34rLTAm8t^XCN#6M_O} zaRLE%t#A+tuwnve-Jm7-_JyDE0R<xq3yaBO4I0@pKQs!a9IYPn93P*W!}JLVQeIFh z3i0qbkE4+T{M%BV3{Fv+73}61!M=M~tdXB`|NII!KxOM)_g5@}`Gtj4K^e<<RaI5M ztbYbP2Gq3ki(itHU-#2z|G@7t<%kZCiYhP(2)OT!CPx%0D=Fo_qt$|R%$xo<7r;Qy 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�SM;e`_m;LCv-dP1_~IL$Nrc!+Q~%aEe02H_ec~*l4S%O-bEjs!#S)bf zH@f8jxEcTUKa;k?*8i>}QWu%QQu9WmBtPd{?E#4l`1$*K%{L|%e~Pk7NqNyM@V`K< ze}yvQ1cd~Lm<QrN0+Z(RX-&;?<Uf$dmWNI|_^ncqh}3Ox8xEry-Qajfk<$2^e*>Fo zK~Wcd{j_kwnbFDrIn=%VnP0M!3$gG&5anR1M^yM>F*_dl<4r~WgP<Pyzri(Z-JbOf zmV7#j22Q+hv=a1RQQzH}`s@=dEyFxI(fW3eEif1=3(gNdK`=v~>_5tpruBDkh9JQ8 z+63=tyl+=CIR+(yshJdm|M!9d;8?Is^_VXBfPufSj1YZVX!(yG{0t9zElQ=mtqZ8E zF>&!Q95|jU^iH9cgC|NAgx6%NOz{ZDCWK6`B-r)8(|ssBb~h5TC<0w=o9V)08j6tw z|G;QLV;UAkJE8Uls%PAJ@?^8dqTo>dmvE%pRU-NV4FmtRM?0Rtt_l8?R3%<AZ1BPP zU!FnN-N3H|czDs98$*-8H7f%f0!C$B5wXgHqdYfY;U&|n^=zM+$&+4_lbKUWZv8%} zfZ>P%h4O&=4VW~c03phS<yzs_uOge(j%(p%QDy#_sLlgPJTn9G1%JJdRtpCBZx8>Z z4?YP93JxZIZ?^vZwI3L#Z1Pvr4=k8sG`$>bLgXi~{yPmhm_KKEU!#n@iTd;32myY@ zspZ+mmkSDUEK`e_1qz@A7ASE(61)59smVdI63i@vO9yUGAsBlhOpPFb50u}c20<lh z{K}$0?q-8%)B!dcJTD<~-gB3OAFw(XJs{Hsqr{#(T4e|GJ}|}3RN9D;jw1pZ?M`2m zKu@j8PvSKI|Jp>{a{Ao730$bItyM@Vm~nY2V9&xu%f&|_tfe*6(UCRk)Dtd5vnfr9 zLu`K$jQHZ`2kKM$`lM6tgW;e0*_sCrPhC6W8W?BwOGIYdMxtnI*iFuoz2w3%)e1Fn zpC8P&jfyY_LeF-X80l;Vn=Qa}nvhYq7T+o9Iz1g0fJwTJAoba~a=aGP6jR2HLc=5; zq>=pdXEZUW<bVU=?FvloV7gAg;CXlK+_aXLSHV7OwKgNbo1~5B>(9^67h1)wXV0^J zNSeC3a%#wZ-VlUPhmxQDZSe!<4v>MvBKt5nS1{CCEUr~)lXQ85M{Il)YYku-Eo3M0 z=8gGAX-=Ht2!H%^y?YtB6bSM0krx$}B_)h(_%Z1UXF%`^bk1{gB#J$2OxiEGuV5q- zg)c}*Xd|RsyxNQMY|zla2wGWB-gacQ01QaWO!_6H<q?(Eoq+P<<>Lcn)C*G5^myU! zv-Z~DhK7bjcJtw4ec??<u%C|KRLJYRNaHM@!Yr+(cGgMW2t8chSkv=7>6_3S=B1{l z9$9E<myQd>BFZSrZgTsB&Bet9TIc_fmVgCLK6h?EEY#svMvqw#4<nXzc73vYygv#b zfx7HjjdiQJ|7~k)OYy$E=vqJtBd!^49n15!UR+@{8*Gkc@C0tV#~5FCrZ3|xn(7s; z@>eeSIhf9nZ$mcfRjLYg`hRjEmp7ETztW6780(^zPZVr{)xsn7Da67^S%a+;=+>2~ z<TG|BtE)>x#HL_3_)q)+2?V^~7qW?N$(-(+H`m`k=MmD@jU)tK9Ibf+GK+8^C9OqC zNr}+s=%m^A8qUK<alKu0^zQ}`4PKUxfC2p6v)~$uEhZ+)2d+$R?&;>i?_Rlpe^G+N zc->x5MM^Pg*NgaAk@N92@KpJsV-hROQ__)Til6O%(wPR+=V$jMMLt4;^ZG)=!j2pq zRoI7ruZ{WBL-gXLGGD(=b2)YKe-p_~xaD(lVz7laJ|b}Sxpr^9uE;jE$-9;6l$JYl ze_Ml7)a6uvK$mY4OIWzIewG*Q-roY{cYl~-@!u;cmgIk@jb*k)$BJkj(Ld)tW)jb{ zAdC#&ppc@A>Nfg^FQc%vF4&!WlBIN}`&3kXKc1(X{AsHzVYa@`yaW(UG3Q-oLor3R zON(Z<Q(Ag@e1s=3EuWJ^UGI~%R|MR5E5&g=`}+08*T1{%b1RFQPcjFUI5ek~e1Bys z%+Ae`enEW<GL!=ryG=aBb0%+JOQJ|Oovr?X!ASXdXb~5tE&+?qAq0K+hGvsJdEv1t zW-0BX$K<#EF%p@fsu0?2h-@UxYlEgqNGHT`tv>~vtE;J~;}jf^geVv=QfJgN^LaRN zu(HZZ8b1y4Z9!<gfq#;|ch5;WL4<}u&X}gC$*Y^vc=3&xHf7J8ws3e!I+<G2?}Q8` z^N)&;SDeu-u$;X`-Y{PezBhJd#ih_zz8ME+_xf~~Z!q6H%36z~go&KrGsDXR8yow{ zVmHU<2+*lfRhBoU0Wk(a$(bILn%h_9sj1EF?KLcpnVFeBR~v)^o&pn77wyN%$;t95 zd}`VQ6we-wjEulpn?X;*Soc@=;YFuQpVb0t+8Ba1`_P?}V}^2>x6i&k36Xwr&Y_r1 zLtQjD+SVnQGVpm<7<>Dqti1f$6MrRl7!u%pYkInUza+Q7<}thV;nI~}n**?n4P_&m zfByWL2ooI(2up(F0z*rc*$|G8Kogp;Z%l&asW^F+*}Tk!L*hbffI=do(U1^xWH?LK z$7eMko9N!>szlz3>}zTzB!+Q$Q~5;VJR|-i0F}$?D?Vo9M5)EbKbx=}ZaYvb)ZQ6S zuL6^;kdU5Ea-ZYYh@%RbqU`J{^VaDz6VJhNcT4b2NcX8or=c6%lub+(0bEw~7&n{O z^Y~lmN`YQgEenUfto%T=%MLeYb!}5MayhU};Cy*0qS8uN;K(lmARIrFBZuIIfqScq z$r<<d*`xGcNA+Kw4eB~pi{(!ADiq}AoLkrHu49T}77nZ}BogTaqQ6(si6L*!2)@B3 zAR;mbETxn_HwA_AyXR%D0T*W``pa=$=xi1)Ov?n;3*c@CoOCBA^wkdbfB)($XUlAk z)WyY`|8Aww*3ki<#k=D{2+NBmpfal|<fGUPs!-M`Y`m|mMfpbG<TopNQ9v-WQV9*) zW@DLNNd2+fv;hWs#Ls0KVP$EGBQ^SioEEm__}UVLy;2uF&9H+G)W$~lqkdXa9!9!` zqN2U7cjJ-3p4ZEi??$$!mS*Zu294Lgf)dmTb8|Wg9QPtR3x2nnS`d&mLuA+88lLB% zZ*OfK<-WB8k4d$#zbf&fMAw;YX3ui?D#!)w9ZnJ}T=(WJN8f)N3U(oalir*6@KExN z9liOxJdGlN#n_#f;BmDfU>fX?uU0C3SjK33rQ{weq3*DEuJ_^l@wV8a@>Ig`pz_v_ z6of&pyb_(|{kNqgU1kzHc%5p6Q^h8&<A0M}37GUww%s45f0WU_+9)IJ37hrVH&b<C z$IPE8*LmehQTX&v|DP$x{YT2yF^Kdi(|+;xwp=f1=^jhU?k7{F+j$rCu5&#GfA1Po z@L5?{F2M<xk)gvcP2qL-*f<;$h-Cr_bg&}7IqGiPELtXrAxKf@&V0|)J~}PgvkkfE zmwT#4COpK;zzu;Y-2~M98L-Xzibz}5iH_<BPdjusxhi8ZZ+Bg1dC$JbV~T<~y2bg+ zdrdKsDqVEw!uLx)<w_)^Ngk`Npq9^P;ADW{ne+#fPTcGPA`&7mcGFc*>StQdV}5oc zOq9TM_)CH^I82s?R&gZ$m|$!gq&bi*yl?2ZxvAc~38p*C#m&yjq|VNui%1ick!EC2 zK`hYHF{Zhi<NNH%X=r!~y_peKm=EacGLyxKl*lOeA7vP7eD>pebZ^%{YiH-}b>Su% zJ^}vF!yi7CMjjqwPF9{q5GxT8ry4KF;PCn8f%SvwaaKup7ps$Loq;1Fw>i5o9!TgH z=t|0`%c*Q~kO13PN>KNT$Bo51uOx$18K+bahFDN@UauhovQ%**1u1Em*{jS2T*$)e zy*^2*{&pl$Ya*%hdA$C9wrJ;5`|+QJ*GfS&Y;W4SdOMoi7MBmrJy8sWS@Y^g<LAi> zmq>DJ#J+H2Q^(0#GcOzRoL$Zc?D5)2?l&yunR!O>kKm7p%yAL9Z<(DD`7CF({nR>& zG@PSyCwjbESxDM({XOP|i}lP|fC;+^yWB+Oz}D%!1HGwj1w(4K(@C&|<IoxCg4Oe4 zPa<Xi@FD(Up3;(@Ud)A~Oq{y^=h?|YaCq?6bcNxFm`}=3Sa{e>-QKsjIC0=IRJ4z@ z@=G@q!I3m_`U!`_GglB*6&iK+N${W&2}*)s5fdsZiU7=vNOAd}fKYUHaNu;KtaQ#> zEzrDLnxYjCPYM1O>f-7+SHj@|61U-4r?hbMq{`jH!{e^r{>qY4VlGbwC5P^0ufV?E zzWjF#Io17gS@qB0BDF591W;(*V4!@K9P!fTVt(!S-u(Oq^ze0N4`Z3B&)yB7WNdS1 zMMFumd+mTKloVbsF4iFi)J#kEHRI#4TCO{!93EejLXNIbrIXlgUO1fT*0D2y#%1#h zm($9AISaXB<)x<07!j)Zx%rgXrcWE0hV+$FUhHWhJaREja{o33Zr@Cm#f~zUIHZpD zo269AT=qx%e<;2#bN$-xuie<_3pXyB$}^WS`F*rCvqp=4W^!%HUssyM!hz^I?r+IF zP4;C7^p;wpT@+|6F0kJ-_hC|tc=Ib6@-CzCW7&Oj1%kLos4Ei;DO3v!F{Wx~r^yXs z5v>ii&Ng|kQ)*G2Q#sCV-_tN`-XCbD;aeU0mLiupQ^VI(xpy(fS0L`Gp^rf$wX{;a zV#E$tZmAZ$dCHF!XlP_qeY;=6#GhbnVIU;Bb<xCN^Fm#od7=?T9C@;%IDn{1EjF9? z)X+NF9AZ0Hl^C#rJ;lWADG<_BWw$xDBR;>$_RoBqsZBP~Ht9BvH`UsN8});hn;!ja zO+PYHk=fBic4A}%dVId&+uCVFegBkf6H#S)eNQ0qQ_CVgv;D!Pr?-&Ouv)qRsIGn7 z2;iwzSPRO{L5Wgn%KlU!-Yn_%P9Z9Sn9J(>rckep?3*`+RAJ=!>I1j4{`6sA9-yDb zc}Z@s7ChTDr`c1~)D#=(`1s*|gQbDR;j824sIDav+M0Cds~8#!?-&_N?3YqsWm4tJ zELoaPrQV8<9Ih2LR@t}PEDdy&SGL36>XF=$GoO8w*~m~gr*bfOK3Uo5{EV~NST<f- zggS4XebD}qqN15`U=m`^j2+^rM5{GoXYU<bAl~4RL>VK&n15SO!!g#~9ye4x1%K{3 z@@tm|y?oKm*!(r$?!nv={a#A6GfA++2z-A}p{k@JgelWyiXd@{YE^floTjhnhAPea zM_2MssgD=l>*-xx@u9uFU=FObqw(rlKB5{1lX-<_Y`oT}4bjl_5c`~hjj4R<Y?t%* zg7V`D%H(}z)~Ks551x!bV&@z76udtIgW|^n0b6+@l9caJNmW+^6`|WtaP4i9w}m3V zW-POsG9~l)Bm{tRlBgd_n{Kr{T-?*$O_?S(CIn<;8aA1yr<L2v3OP%!Y4CG&zBTFT z&`l~^WHbAoTu<a9enkIRT-eoQYL>rEIn&Gb%80th<3irm(=*WDcW`)Yv>Z3?WPwP8 zf6XNe^{gYH0NEcPY_y$e%(}mas=>1F@sH2C3OTMuGhU>dZw~80B2DfYgN2{TVuA{} z6RdV}ysQ!Oj=R$BR~AuE+b<IoQz+X`n)#Qj(DO=)Cc6HCdZ>|T-H_v$TvW`yRWl*a z+4cKZIWrFp9ksg08cYh<-(MgXqw?F{b3ab4_qT`>W=OsI(YX>lI_AZ|@Xno=aV%R$ z=O+?8V-4ADXZpHA+Std(%S;>dc$tkoTt1h2OG-Y5=AlT6BI=h9Z^HR-;2-FDpx3da zODk$g3RU_mo0#3W(v$|dTG%ABw|k@+SP>9z>u$~!9{NGFqv+kpH!49LXiO=O3Ok2J z%E2A!9sjMUpsQ1H3UZ7ZZ#RV>Q>)5;X7Uyjd;d&P#{Eop-M?o7+?>p9O^-lxVEiPf zOTG6>a#35};g0s9f$gju-hsAe#fgZ8PuTtn<nBVno%jxa%_SLW!p>-e$*mCT?O~q1 z`7k;+<dDUzIo*EZTax%xq&(y9Hw=bbGXZIIdChR!E#DydB0`hA+c$>S{pqxE9J_2g zr!8+olas|2I=>|yl4L~3=uEMw9pFy}Uzee}@t#ci^{hB;%-Rp!w6?dGddqnV4M(l% zmwFx8(KFKOH&tjrv`dYV$)$03+|~TN^KKx&$?}=4q%73lk<3syz1}lSFIEL~i&mAC z=92$4wXt#8x!iHsW6vSq-*y*)*Nc(i68aqWqH2=HG}{L9ey{pCRmg`v=6$PD_k_^l z!otqT>FLQ^52vkdt%<yx40ZPi9Gs{e-o4$`-_gvjdx5!(h^|Q*fhNI`X*M=*)L_H# z!g(j|mip^uI0bP$>;7fxosf2)X?Te!`tfL}yobxtZlu7Asmyl?Yid4iD<ltHh_=S^ zvtvcM(94HMmR@SSPi$S`Sm$QEGPyuL^<dw2@a}slwbOUmkdi_G{hR%oxAAqL?V#l< z-N{VH!iSx+n}TZ$p0Hbu5h*XtlO|UyV>v0OY{{l%jf;;?U9^#@lN32oK{3MSij2yS zM;~-ERp5C+UAD9p)Zg3Qys@O0CQF$~x1@$=^a5}6oTQ=aHoqWB^k3x3ZlR~zIWtAT zRgFh0>^t%$W1tW(56k;OpQB10%m*j{g86N>syq=wP~p^WK^8Yr;<fc1i5-n_c6Hnt zD!^^9G%};X3(DzY(3<Ody~V!s$m?AF6`s;!6=)!%^IjRD&BaIyu3Ma|op)xpnbJ2f z5E}YfRD=-pc8@TKNMyGzx9IBt_4I&!iDgI>6A_8i;yiicvdjN0?mMSP+p{qhwai6E zsk&1Ao!$3TX3L{N3|7ZPZm|7(S-E*F=<n|X+kljdvB*bWih{J6;J6rLD&8um{MHdQ zy{-YtaF&wt2@dx3g~j^bt57%by^dai6rYUto$HW%ZBLqf%f!z(o(T|xoyArNj(CdU zs@yf^iha$6KTc3b66DFl-^aZ&bX@ci8H*oc8VVQ~Vr=o!-9k18<-)Oo^JHIKSd%ln z>kWMx_M*USzHJ!~%A<vX8A0>>i72Srv)L`|#?8nymguJJA9G_2KJ}N#9B#|ND-qG| zY}FZ(R@?@GASp>%$2`^p@&DNiaC9CT*)J)5>p2$i%aJ&CHLEx85B6NC)xwI^o-Qjt z$)@skHpjw!nK3XZaK2j;C=eOr_?Ev4cQ0EprR3$Tp%S1dK_0JI?G`<M$r|A>QO$aY zOk7i4R3gaHh@PgcV=V%kz-$XjVBqlChw!ahcqFWx($C#5VWwux$22r1iUW$BK>QI} zkT^}`z5$-O#W~fBf%QVNX=pw>aME0Ca{ZlzrcW0{7Y!*drU(s&JDQMbi;`9|uH>Bd zt6!#T);*^#q$lDh7QEM&QoOaYcuj5>aC_7W)#`upBYS{7jh0IHsxy(KYVW3Tn~9+Z zKuf(@*3fvVoWpSW<QrzBQ|+L*d|9buJh4)lv?09Gjth$QQm4j*74xdnZ3XZ^@tU*j z_i{8m&{SU<qJy_+Op~QeHAA>gL@TpPM#K1VW126&s3h8rmxo6vJm~qq*VmSY({tpQ z7uo6JX(5=m#ewzxD9LmDr9CaR9qk8cc0J)<y-8`_pZAX9Tytb)q-bg0Wps5lK8*-H zE!b)w{kge!zI!cRT59pGfBf(8db)ti;cQuP*OTn+(MIQ6{yFnc%Y!!sNgNDkHv4_w z=_hPi*c!6I{a|RM>Tf)hg_mNrpp$hm-hFdJ%?|lI_=hTii6>cM;yIz>k)~!m(fU%P zr0rwSqyT+@a@DU_-;E{UMfUM^{1+%#ZQulbU}H!R58S>_010aHJTcK0`jPH8_xFB- zgX0mfdr5Nb1?t5*Z4IYY4CBrLksS?pmHAj`fTP2a4WMw!w5V6c_}mHlm+Z-TJ#k3l zB%&&8N4}7fJKQb+d8w3?bP|X8q~c9Inx>qE2U<#Jo!iA_AZvE++<Eag8cpdVs<7Z- z=^x6&KVdJEc`?#;+^&|ncs`04^>*o_u&@{-LYlmn<n{}m(MyK_<RmExenHj?FN>o& z0E|UAG5@!Q6DuL5!;6p!07Y-P)q)nl2zK~vILMvo)Oz^UVuH4Y4_SqA)P0#Ql$JNY zSIo_cNUC<gDlvjx#(ifL!RfrJWaO0J0P6$h<@|zoa5gi<mYc^*Zja&LzdgG?&tsk5 zx&@2ZWDW%kP2HPDHKa%fRw3j?H`#$~wsInyx!ZA@h8{W7<zFD=u`t)~uMDV53Q5Xy zbds5!!ccQKIs~K26U^hJ4;BiVnwo|FT5Ptz>R(z)_bmRv0p8!`(GS$(=p-cc)8}`} zS9=3XLjWsVH^uUye&z@x3mjl`Hq7|NVsD>NE#l(iYOa!ObU`(|v~du2;wE<7YDcFv zyJC0T+b2V*1Xrhg9@KtJ5u<wTuG0KVHPdHgBd~MLfs1CSQ3YsT<aPGA!G(!W%44{B zUXkQ72((w6*c?-?t+XfoNaH`$We5`PoPib!5TDYzp881yvD2w^xVsc!FK-SQCcm~V zYrQ_3`kS1TB+gZ;ZRbNq@R0~s>byq=12=q;k>jnooz)#E1a`fDO?yn<sbX0L`Y73K zUc~?W;jwV&?B(SpJD?L1Caqp&zBZBK4GKR~KS)OEkj=KzvN5WcvIsOa_x65Zd_7bb zj=m#g<@v^c6nj3YT)(HVfaer+jSAIdD(d|*<*3_G?zEn)cRV`fQ>G5@@9n-hn8@6d zdpVbF8Yeq*x;+bZ`_x3%&7-TTdU`z&a(S{V7vgnwe6c63#&Eg91GbRHBB`jDl1-V5 zZ3i&5TwJUsYLjmTY`k8@NUbrc%fVt3_GCHTR~NxZy$NX{XAb{NTyK2TK`xUbqZ5fB zDAK;#a_x4E(V7OoZkeM)wk#R)SmT`B$2$J3j~ajwqXBr0TW-}zw~33DGl86yslVP! zr#e`1ON-m*J$v*4n7h)x-do|<qj_oUGSUMy6Td&?*T2k#j|8u?){;7;ctdOJZYpf@ z;PA&4n<pf%ftaYAAW?KD`9X71NNe^c4_GORFZ{4<W_~ZI@*?%Ydf*rt`-#$MNKjbz zi?uy94h|+Jdip>mVrb-J|0eRri?7`sqmpDS#jY~i51ivx2Bb$Y^4G-2R9Eq9YB(c^ zxH3Loe||2EBp2{X?s&;%Z_?Y<Lbh92PC)Fwxh?7<wTaf7%<ON`44$@{=X*VB0~ddF zPCJzDd-FpUV&`J%+2;p3X9lu&0oWJK1B^pcNTs2R>gU3jB*erDTmn>#y3W23uHC5u zR+YuhaAJ?04(nW(6i%-+ucTOr34pN@_?>z2n=p@0VqAa5ULE9{lg?CtWkR+io=qX+ zb46wgak_D#pz-GB=AIFq)95E}&&YT|4W}^LDKjfu=CC(hP;l*u884>71!A<VS|x-^ zw7vZT^|pG>_iz|s*6>~duWrt1)Wm9ykpQ(qgaP%@!Rh8q9{t#Fl{0R7p1?)u86&BA zgAT%6evV9*A>WG&Zyb5NE`*Whttn&mMS^m;JR8hi_G3XYgzDJQnHSk}NyQj68dtRO zBkUS-Vj`lE0%>%yn-6TK!=_S(<EpWE;nGs5p59{u6c{0dXGe#phcxfr(Y>RSlak|d zJ03kyUh9$lySSZk+Os-Zq26Sk4TuD=br+SMzfAt(uj}q_e5oCXYBr|Lv-R8cKaP<S zGOv?i?FTCf_c0t<E2=h}i>r*$bJ7irjG~j1K|&xgAx5;vsB`28Er;^4T5`yb-9r_U z;1KEj{C7&qBht%+2|1*29RsB&#_QzX8owJsr{}MDo6gA>M8ryuQ%EJRGlz$jDhMyW zXGBA$4@7&^=sP|<^0X&4C6(up-O9w1Yls9$^pGSDHy;k(i{@}OYyF*`gOgKkm(7<a zoi_80S`#zM7g={R_k9;Y7pR<EdkrKvX+t0^o_2a-r<}&O=-4R=6-jjY$A_BxJ6jxk zp8RWG<a^wpHTHLTL^*@B{3)rpi^40&tu}VadHcg{+$7p0B?U4bheuG^N)}mHNG9%s zvMl+m6#z*g*Y=t|8F}3s__g@sD6VKCN-tw5=i{}XxZGj&Z1|2=!(?GF+0n-e>-J*7 zR~aH;9XVL(9MW<PrIpY6`5XAxIjm<`&1bu?thI(W9<jURk!rja78c%o;d#CBZY7ed z#@*v*_xz@BV&v&T(txQWgz+WBLX59OJ%3VM%sU7RCZEdsv`Tn)1dYZ;wZfmMj~tz1 zZ)djV?9)bY1r=2XYgV`^I23;cP(bRPPO1S<YY7L3Z$(ek8V>@D@9#nK?-V1^oG2m8 z?}68f{HI0$PKlGfH8!6aOieAm@}qlj<q00PlL~GN!_F0Xb%d8R6s#e1XJD7<;H*HJ z?ZhO^k5LEH1Toie+f}K99v{p;IoIdUjRP!sEmcA<E>Hz-8s{gz*bZ$x@YvX17Swv- zaGPeUW1HoW%#UHpgM+8P<>9V$&w42TAWZAE)i9>l@o|!SQ_RdkXy`jf$1+#$%FNHn zKyr$iW1hjXiL>05LYAFxzJwO3Sh5{w20y+zh&w8Eq&w-dX&<I>nVDACX|fND6cApH zL)=z7a+J@u-FQ1sC3UoQydA{Gqy&4KS(y>ni0=ae-ad<y&w~exrhiZC)Vdf>rh0>I z7NpzwhbIRsm0{X7-baUHBzL2*dS?KNs6>0v{vvwuqS)A+u0>Nz<8rj1wGq5+h||3u zxZZFDfS76@320XZoN`i90vhT#@~}?NZxbEtx0V|yelT1Mw-!LIQUeFz=BZpLFKMiB z!hT(fceb|l)OFH;KnC-Y7$(wkF1AL1F~fs>rJb1~@O=!cfke|=`teGO`L8(HO)2u= z9*|u}k5s+Br^jvnNnwMe?R01CWX-<^^t0;gKhIPr9?4QED?bjk^--5FwgsFtAjgW8 z>0CU!zur1qATGDun}+H}KbI4YvM?mEse&E6H=Be7Q`I}iHPYn-?diGjKGT8tdb0}) zV&Sm&)jqZsl4G7lQtswXs>=~7B#gR`vj!2lqPSywXvceV)(gWbYJRq0cbU!n9aQa< z*BZqSL^wyp<*n5_qGe(4HLWo$5uqM8jbKU4?|8$)5Ln9%nD^8QdfOTBJb}#Z<t#uu zz#&epJAU#cgeV6mNaTl}`u3{Tz$gtJn(~3lZAz7PScrUiSy>vMx{bk;@NyzNF_pM7 zU?R=k1+AwXv~S18rX<~cYiiu1N#WXk^;AM>-z=7Q3;Vm{%tj=pNyP(wW&;)7J3~UG z9}1<#tO)G3rn+Q2(9%$|Cg1!+NtIb$%c<g~9}$~ba%ME@5aTWac?whdq*ej|K;Qqv z-do016}J1jCMpOhQj!XSFeL<}ySpb{0@B?LBGM&Y(hbs+E|u=?n9@k+Bq!_#ec!d- zwbtJ2?B6-(%lVz{=P3-v9OD_!xbN$}{(Ns;Ti+vSQIWDKetqs%WQy#~wAxeEDtKWe zMi(hQyq*`-^}PUZb>XGIvg;ZMS>?VD+TwPvUgahw5t!AIVZ#L5kfE6@ZY~WpR&j!3 zdLnNipB3jCXT>CYCfqR@H-w!h_T`Ax=qj16XKlcapzTDoG8{UH{ek+lu9kzTByV>3 zD-khFR(9<+b_>vsUtp48Ha*wV(*r}Qw!b$*!NZLyW^Y;Tw34toN>OpsbqqwWbPmw7 zIqer@`fyVm13a$EatgX#1%Q<AGY@c13NGRxJIubHlA#dVlNT?YL#ga|!vlbXIA-qg zXh(gd5!bpM*bHRN<IV6sefW8xg&b%+^G;TN?-b;V0{CPP1>hn;^H;coj`;^%vH~h~ z)1TRY@S0m3xBd~3^WaZm>ej9GTmKOC5Py7~s~ilPg+gREOwujBH$hS*N2l0wfEc3H z#1N&z`r~{{!x5&Wd+?)C9sCC0^H8!s|NCQ*+=t;P{j>t>P`9zN4id<pUyOtGP*`kx z>~oOY*wBxT73)^LzaK^wdxb?3=d-0v4B(ibOGDJb<$%!n!;ZY`?59oZ{A`q?{Opt4 zn0#DB%L2&u<TzG@Jo$6{X`l2W!9xAlptS)kTewqWj6&gEz5ND%j#*elnJ%uS6AKu$ zjzKhSPjCijYRSM7<*VGx9Z(y&mBu$j#XvFlaUi?&v#s0lLNVi*u;@!9-J3U=@LHGq zfGbyyHN06<zI$mnT6)V-Wi5hnyi8k8!h|%AzqbHOJ`@u1Ofm~VT<4%+J&*}MCAm5F zOFX$JSV66TG4mXG8^i3PiJ^j#-zWm2{g@_O<UNg?0#!v~mxCoGs5>g!oWXziSWVdW zB84VnQ~vR=KK@mY0H=bRG+_J~wqi7nlEUOUw5dz%j=J}Zb-;&Dci*RmcDp4^?B|Up zf^Q`1NL%6PzcO50M1L8srGF4W_P74wSH$462G<4v{BHjx`~JHNK}h52>wne)KK{}^ zY{hz>pCv^WGyFE?#|^`DeSeEdaYa_z-~o`XQQbR96nd`p;)z60_xeZXx4#b0xIB1L zF?4Ru$uA30U&(Ya8mz$I)qGTo)~(<KJ3|c6hu=`q7^YFmMKspHMhE%e-9P_?djfK< z>rL9HoU(|QH#pZL<Bmjrt=>-=dO=%a+c!u5Ss)_YS52G$Y1=Cl(>vfc;gia5ES>C| zO8JX(Nl1yaGBLDM?2ZAP%R&5Ruace|O7RCugqRo6f)yr6>M<0|$yatZg+j0i@b}Qs zkN&8%<oFr7J`Ut|e%9Dl0@q$;r{x8efwk5j?HVq)D6kW(%iNd&NJ)H5Agsr*g8=yH zExDILQe+G%R*JL_lg9))Qg}#De%_qsypJ@DFDq5R?*Z4aJXy@a)7hH?ga||getHJk z8S@@gb145s7qM}8_J`##7RGTZ16<^vn+k(RbLr+<m3v7S7d)yh{eS(1fp#YN{H?UR z|K(f%&fRGyyWZjtCe{kb?d<HB`yvw(Ts9FFj;BDgVPf+8-3x3~AFEj!8k*5}D)RC} zp-I*8DmK^r#vloB;}kfGfa>7SovF=w?_|2d>|}nR`BL5GvG1;KiztJuYog&Jj3##7 zMX2NHg$u7%gMA<hC<yq4<Ky5E7nu}KPS#w967)0#$?_r>C-<KfEU{Y5*8y(i-+$&v zwNuIFgb!%P;^@mH^UP$pFiE1JNmm^0!cV5625rf=x3{sDG6_-c$AAL=7dG8t;LVX` zDA}2virSS){s|4|dvSRhHGoH}-F<Tw_@rBycPewGlg7g^FkZ`~5b^E^vtKTEDc*=u z{DInL{F@pc3CU2Y?%-g$Pcjj)$p<O(ty(+09GQfy2BI?6hQ$G;XYJvYFc{67H=ORv z>%M4lY($OA%h6%PobMh!?j0D&?UIm`thSul-&@GsnX5x=PWUIQkVSxSO5|$a3>_Wa z-SZQ4RMYQa@JcsXr0X%kyN94t&|yAV!%j=9Rc7(cY@(Qy-Ia!$d}OA_Y-3a$M!$8c zQEdhK&>R#LN;*35@88qx)@0rtl#H2)h7o!G`kubGx2NNkP~zB_Z(;(tE3aI;-0Yq! zp#C(SsM^j7T$;l1oo&ojEs2U+3Rq|{enCcN+cR!4dT26}a}4+?(9beiPHz!4cC(yo zvb*{zjOkR}6-9Y|I{IhjoaX?rDG6YNKx!ahkrF-BR8^gir;oK8T^SEX=S!~No0)A2 zH`4=E5CN|zmPUMda4@_S*p5~LC?er_v|SN8&#!w*&=5OwyeBgyl+s_nL?*6oZ?CMb zf?nUC*HzoZk=OMFJiwqwWox!FDcR{f1QWzWB3-U9ckOphS5)BhO&<Ql%|^RdAia+9 zpxgs~<#UNdHec@~B~@E0#(hlwHN5hM$;e}QXNSk;C!0xv{bcDi5Wo$d0w!l55xM{6 zhtFzXl7@nUo}uA%mJK;UvumIFhCi69MJIVDH{uE)MrCB>`KDDfIQ@OUyzi<YEB&yz zLY?gFz@R-l^7P_D9#5F+$#CbFFZDkDVe3;ME9<aHQbOkH{kZ7p^R#_zWOM3?A{2`4 zV0Faym0!>g42AtQp%ULaQ6I~7D*5$`(430bW)ZqMUNpJ+0heBz;MeYrsRa$q4)sU! zitsvW9OaXTz=3u;WkfnNJ*|LVuLI{<8_@Xx&ybsGbeqUmd|hoaXA0sU{lkeeBRaxT zYrL+1lr&!oaeuC|m~p?{_t)`6TGSdSbmx{M*X7B9fXyr6Ix{AQf-@z9B^fpT?CL0t zc-re^dt!5<sOpQ=Ssi*3r7VGLwkza&I3efiY!CX2ffU|clKU%Gw3`5f!ACYnK;?F4 zs!w`P;PoD&xa-_pvnCb4jjpeJpqiwdj_*P*H<D^AjQX;sz}?t%dN~3+I$G+GEk^@2 z%G2K+F3{Rs^wmQbnD(DlzsN_@z*OmQwU6o-3Adv=Kz3fsB=3;ZS4RQFP*F(v^KoY< z)!4;A9(Z@JuCA7qk<l%20%((yjg4}{Os%4*<M;mls+t<rs#v!ZX(?&t619%7+(;Ky zRW@Oxpr1jtDLig0p0oIEJ?GxXQ{Ll6>IzRAt#~2r7h{EZe7P8GL~11iLqjhqC}NT+ zX}D%5C&d_cKVBiVx03yi%jxSKcDpg+6B2N6FFgvsa=Rhsnx5G%eBFvfUS596l}!~E z5rHI%y?8QP=aK7m-Slp@QWB3Yt|u&aM@X0dHh7rS2~uGNw_$OlN;UruVYoXcXmkqt zY~elG@N@T9jn$|;{p!MAlF(}&hm9kUUz>N-q<4np=&tOj+!ITi$JW=Bb=!ldnGx;s zypZ0|^R3(D;LGR~ax!w>iz9tUuJ8^f78XPQ+OK%&EU!6dy1K;6aECKRotVHw_x>ul zpRyI&BzeMLM|5geS;2Sui{3+QNkQ1@ZW9vCOUHeA(33Q^F4gPY<^p3Em>DLgr-|5I z-4{OTU>_>v3S78S?-63%z1!yOsP&4S{jA=F_o~di449L?d6a)xqe^79*tje=5|FHj zX%?1}mX3Df&wwGpwvsZ_%LX+_f~tf`&Mxne96ZwfBUWw~Cj>s#F!QOt1*q;#Z~^HQ zPFTXr3I#75b8_efDsppkp%9aiI-Co}H*bRLx^U=#-sPKm<?0eUseE$1#sr<kOr;XW zj{;-b8%FJ$@QWuoxw(YTpHs^&Z7pZHFCl79@2TM7iD*;i!u31Ca#BBkZk5+>C*`t_ zKYwI4Uc5V1Av#gK8}K<}fcK(xdb-YZQ%U5S`1<|$P2j7;_OvgtU~MW^Q(0h{-pjy1 zaYsi-@WfrG@#cf7YW@ULC=OwE7vCI85tQ>7$itt67~G}P<9WJ*^d%g@aWvawh5mZW zqg~IOwq}v*L;50~$-QYWTU1K4H5M{}`Ad+LC+q$8=BAmcVPb3|B~~Czir0Pe3k+tz z!Swc^q(vs_>Z(_bG&aewbx(K3X-i6WAnm9Dv;~vsNtc035bp7IlN|9#4i^^}6aySK zT}Sr70~n~H@@sY$H^8G>3BaF~#}JMEwSrODDCugSQb_tJkICXGukyDnI`l>^k5%*B zel4rnhAyz7w1oVVmlMywl)+5fl(X?d2aXybOq?c}tEX<a|9#Nku-i<`?f5A;*iJ%X zqcq(Ip1QB?+XLD~#~b&*X;<|3&W31HQc$j}tXWMpqzov+3&A<daWeAU8v=$vFxb!G zu(dZgThb%VWIp+2FCgG$i^y;nFeku&?>6>$#yBomHPfip<e8ml?^s&uE&x9JG3j7) zswz#6OlO(?>mA-NbLKqs^z>X@m;NsBa1!PNrHR6=&Io<5Nol(B-jXaR-<@h)3LfC4 zg+MIf`@{uJn+&dSFW$IVFzWFUBV$@l-iG>aWdMO@>Oc!KQ=LpnT4}sDn4Wlb=G$i3 zkB~x7zwhVkdvSIKX)?{91DB+BGf9I(k4Rg5>gu&X?ezdo4{QLRgk)i3BctY_wvwmk zZ4io-XuFi3as7**>iF3u@^YPG<=AHF_1xnoJ-vfP$RT*fcp=(UP6RBKEE;hjbaY{| zV(%xwzKa7=k|x&Uunk^t@B8{%LatG$GZiq#3P7hKMzsC)tErhO0s_-|Q&{YydjcG5 zTRS`54Y%`N83Bl|LHSYF@70|4m|pfYRN@lWhr}IF{*ucfO=V?Apxac;9gth$1piLk z`xJrX)7crymRV8~jyN*6v|KINX^wa2X?8g@44Rc91TOaq{WVL}a{zw=m(M&{x>S-m zl(emUjsIw9lPT-HL;OZ%Y}{88(al)Q(VJY1_79W>Qbdi_#r~h;bj2<0;e<@)>tEC= z)|_3>9Dk47O&#DM&yN$BH$8Hy-kHp<gYUXXt-eY7eM_21UsJ+Gqfg^p1|083olFow zK~S+2II<QJ8p4yrWY;?A%`~43bGuFt>BV!2kU48_r_4iA;xr0ZIu_`b(YKIiWMt}- zk!9rBmT=gZs=FTa)Z<rBJsFA2zs#}>j?Y-ca#cBd^8pGAk`?>l_ON^A$@Aw$CNHr9 zqpQBuQB30rU`0kgKg$-{-}h=RtP}MW7JlcwoJyOJlJb<8kn}kY;nSyDmZUhacTKMD zNgu0@r4&+#H5wf!?6}~2$6$NO5z;+y*pw>C+q=nRvgmw%^TG@f&8l5@+w5;F;YsSl z02S?CcdN+C7##9?#>1gNrZo?bhK$U`I>+rvnEV&LSYQ<aE(>QDm*wSUTpYZi_`G%e z2qCQJ#73s3rY0uo@wTA)okQ797NJUom5>l0f=}sIdNTAZ7kC$vzY<}P1X|1$xD?__ z$5gL%?khfx7}~Kc=0u3d60mj;{otWswip@L(oP{sn3`fyRwnny1Qmp-irvzL+5`|Q zhBGnM6^%z0BQ{|<sb^({cfQv(Dz2}o^;HQkG9jiC_<y)XN<yd!2TLXr9W)vnxg;ed z&$#A4myySubaqaHX?_nbx{2v&+s)#}C6RDzJDZf|_a-Cl=z=@*W)nFEy8JI`;r;Vf zvkpQ*?OtPV0;L-28+mEHehf=?D4SPYm<!;Ym?pFPn+n{#mVTVhqza8|iH(}dlDWTh z=ZyS}jVKIwYpz;4nod8&<_A8)DO$U(s?mMV-KKegL9{(lEz0c$|MW8hC`yOpwYlq1 z;HbZ+ilWlfb!(Nxdb-;~No4NAuVJOItmvMlM0`ToB(gWWAV5OVUKwL&poNS)Q*X65 zu{byPWPN|+u77x!%$+Un(PpcG^V{XYEO<29PoLqH46MC=Md87GE~r76^h?9(lhyol zuC(w23F;}?(=9>N9eagy^}V8q7L<It*51)qWQ>Nxr}Ey%mjhZg!$9@+{#yHJr%&VM z=!o2WCJYvm6Y67p$91B0beVsh9Cb%8q6P-t>%%KIs%>qfV6h~^&KebpF>&9fAw0S^ zR=>I&J7FoFw78s#AFryZST^(d^O9F7I+7_*q3{Sm@R@1uyhrjMK1hie8g?Ko@)0yo z9*$eh_RCN{2`VqQ)1fP%q2(t3KH%?1eZj#7-E$95JHNg4F+V}vlmE7_2}E*t-ifL? ztu!qy?KHJIHzZWHv#U?zDtBwAS1*u_Rn{?GOh5sZ$}jexwSa?!3cP{j=H5=L?yu3& z3LPVJT|*HblxejIYR=9dYGbBnX3Ax$a>M-7plOaTL0LEdy=;DR`@QiKoeED$1&JX4 zdb7q`yhyKkuVh37IOCHZFTgk}Cu>K~NK}N5`bfTqSq@ggxu$xPR`63MrV3EJueQ(` z`FQe)=D9QXpO@P-#9obNL|t7;wl76^NA@|aFxW0NrJR$}YQ8Ed0x!_wTanR#yNZim z_tDlZ17u_*7NY+_WKfe!{-w2GAT$x!gFSn~_74iB^JYqIk5N_vDX<vEiu}=cO7I1d z_kub{azYfFKq%;2+26%j3Ngm!dk0eiu0-6@XkESCi_PwOb(ucM*%F>~>+2(v$-2;) z_A4vrkImtF-9VK_ui3-`lAhc+lRy)rwY9x$>G;iwJB4<P)mkK;+md5Oz}j#@5dhrH zKK~V+Z7=MP8e!7Kjbz((a9?2J;q^4NK2QB}wCsY9?(AHH6Bk_ypQeG(O_h7dPW4zz zRk~R1a-0Yngwyx-cZtXFQhdQDBv@I&W5f~v-{y|qFQ2(hr1+RNUl(ZkqSd-HvoUh` zonwKVKY$r1K^49=h&~Dwho*qgDc$aP5SOPEXZ686I#nmlWIK_d`A!>ysEQRw^80zu zgVCqxz0aLJ{wVXoO`N?xQ=zf;>E|bKTdHZO9h}aRXmN^D7=WtJt_(rF{>g2Ew0pqF z;ndv}q}CpSf3UWJ?j*2dS3`ulzt#Dj@49csk@?}{^|3~@%mi62diBv^oI)2(?G8kd z;0~{x=L8s-7p;~#DhAqVxmOuv)#eW5{($`^KU&cDmJ<tv4-aSLoyMg4XWo#p%~n;a z6ZQS=w45I>#i;d9&(G19<4&j$c_t$wh2!Ql5J-PtkJ(g)$qn=Dt61`WZRf7dqrgnj z$MRYZN|2ol*c-y}9Sr?XA~MO7KSff#CmvzGFQ_B%x&?&t-@W)PJ=2BA#*T{lUPuk} zW<^#Uh(Tl&r)H*y70yH$f~xZ{wwKq_YNkI&z!5_~fA)3`0ychCT1o~CZe(kFPe1xB zAn)$}DXG5j;2xk2A{hfKGRYOu)p5yUB%Vbnv|`y1V>$`b3zvzKMNm;N_w|hl*WS$x zp<O6s!A>42eaC8`E$z7;Yk)>?<aUy{KP8vC!P|Iqgp~JA3IuPK)x0|r+qE$@(f3Vp zvmLv4dd)!HQ2Otnpeat9=resm6w{~7r)IL-avrA-&Bl7!b;1)aZzFq8_j=mAz6AyZ z=@#e?cxS$uFdskKLCifskaF}l<O`5;_jUK@FSnkZ-FMpYW3=*9nLc2Jf0J#J7MC_M z?Oe*$h4B#tgoGh&cj&wIN7b8M)^3Oy2{|{IP6JlMVo7Lkp>q!p&#gHF<FxQCZO)@3 ze8p$vrq(F-q~J9o>7q?^X8gKrePZ|0qY*UPK}dZ&R4Erx1k5`9P;p0@ohHGKigIm@ zPg9N8Vk;9QBsg|Ei#V%&dlDK~I*J`F7OSwp>5jKb9G3-lus1Co5B65ms7wrW+t(Hf z0==FxgT*7kn};OfDE7OSfi@<&V9Pvr9cVx)xS#!M6n{s#eAS{+y&Dr9%VITLn%S+7 z4Um(y{Tg6COjnzRnT|I}qY(ftv5Ka`;>IF$VGH!nI62v!$M$P%F6d&4g~{Z>fW?xZ zx1S%%i6H5Ws>aa4;lUwD?fUX1+Wl&=aujyNk+ReB-~^201j~v^fNH)IXjW=;j95(m z^4!9+H`XuKY!(hSm4i3C#f7OmR>7dwzdE~4KMOr@t8Z$oo1U8P)v4j4rPW`mnnS<4 z8A`;$M}s@^Ganm*9jMN1CBP|Wm(1=}s}|)4DD;@v7;ZNbfMZ;@&`ajX5N$6Tm(*3f zYyUYLf*TqARp4T*Lc?gRFYl)&j-`v5+7#e3^QqVGZjWdCgkSoh#FfnN9a(dFZZtq4 zKuniurA04IPJz`02rJ``(9n=NN6X!{O=)tF^R3GJ{bX=Rk*us{hLiZyox3oY1(18? zGsWdKSXdb`<$2Kq2ypsGFzCeYAF<gVW%>G^eYxF8yw$@S@rs)~s_OHwU7XA|j7GvG z7K}x(nqV(edDV!E7~)Eg*9j|*WeUH*Zf}1LvJR;Yp(L5Er(HQz`Uny>Tw+4e?G`$r zZU1bx=_!`nrC1g}kHts9)7$$aYXI%po`$_AEJESs853r>CHIVth}(|oSs)aGE56R_ zdPBnOKjly3D+1K~`oEDddp1on*hy3jBj5XGPO5e}_`Ki0Z%z@F`D$P#Uby9=+6sU% zs{Ny#p|jTfLu@0H52`}g22H3&&CV33rh69MWJ6{9gw<O+<F!Ztzfx0EXET6zJlJQD z`mGRYHUyJ5R7Qk1)1iM`V|BT_rYhN;b&HRfV`OpZ32Ve=;6+;30V{J~TEs%c5VV$P zv}6q?u1~^?&gs4di=ERvUsJcU8=2abP5*|NyA+OIMnP<wn3&9$X_>KPf@_JB3}Sd0 zuS@QSfV=JC*DFTnRqgWdB?qz4CMk$yy<>Ogvr3fQ?w<z(G-K1Ww292;@6VT$oOXt; zVrTpc`ji%8!R}z$u@ecRoU5#6^nOIfY@Iz*?*}9cH@BunwRxTK*~Z#I?s`5kI4mAd zFa<UVHaJ(OW_R5lJxJD=1SyaXU#QfESLI8@6<ZX_v!YmzNY?={^OlK8tI3v|LOv)S z%q!J-F0pJwqx{f4H5$riHAkg0=)R<evwAqnrueROS)CL*%6HpQWM_f+F(n%z99-Od zZuLASKGLrTAwdkLn7n7h#q~98{fP|hLI`NYW+D$w+mH-*UEz=F94Y*<Is>K+nNqWK z^0yq6VdoBj1IcNj*7Wp(5nP@^@!D?j^`%>zy#LP1%#d-XAvA{Fv*1jyPb^eiI%xC? z@#FP5$JEr6+^q~L_vO|E2J#1PHTC1i2U&ZrfOZ)RoYVZ;5kfSa=6Orn`qDsK*CYXX z9?F?Jpq0q9sfFPm_2q?|sUX-HG$vd0tcH?uyY$PnEZKI1lZYIjKFg(tS&c+)%tGb9 z-Y_keCNubFiivLa+d{`fAb?s(q>b_5oowU7b4;K7{I0K<^TdPI{;_jXQZm_<it-im za>y7-&zw)(O3^^s-oQ0y5dP&oK59P50AplgcCfL{vZbC$c*!%b9X(H_S65pr*O?h2 zhBgGN0LG%jlOi)yJt@v7Bu|wr2@6=_5VUxx!a%#0<(ILVF_10qa~@Yb|K7+PUPX~C zpUyU4W>E;B4)9GY86|q2N879#=76A2lX2L~<R9;I-E;LhIm-Bo78JpwxhHoqzwYGM z)3_dD#!^gX;;{nB`=0{Drm888KTbzE2H|QzHNWb}sanz%v?|(W4_Gb_dYk)djAUSQ zz)ZwF2wD2zb#^)=iDRU+iN+k4c}Nq6(N1uAh6RQi!AJ%|8fFHYotz}m>~=Xwf}$j$ z7kHAb<quM3W@yj0-KxIp_>iV<WPsV{kLv!C2HLM7A_~qK-=je<c5j`UgL5DZm_!tl zRT+k7dVCf=b%)?5`=jqTDSp*_euYX^p3Ap65|YAsLYz}h;rkQNq#+~>@yQ`r!#yim zhK2@Z3xPGY92E%z<Kv0MAg$v5ohhbeDs9CGhk1HQ5JYi#*--CjI-p&aISv!gG&x)s zx}BY!_T81c-T}hO4;C>cRe(cMg$@x=r&TNg3NfEfdZd3E*%-m)&8JFkX97O}m>;>| z-DyKac16_PN*2y<_~LWvgB`MCVNw#}*@IHdT5Wd-?={7LbhY35$dfw21CuQRI4@*a z@$9Py&?5;k%!QSuyPKF_E{?a^7XY_H^f^jUt-=VSX0ndEsy#-Ghvarf^u!8Su!$SM z@Cu3_N*IRY=$k=%m~qDMJv)168$l(24k5n!Ab1~ea0+ee`4<(@C@Op~u-z~RJ9cY? z5qxS|RbKWzh(|_2IcGlIS8{#~ilU=;?ww3fFI!T@+%owNrp~rHUv5$KCkC|9cPE%f zW?JVsOO9;0oSmh5zDt(ydl2?D3oECICv}y>{wSJ6G~9G;tKhkstJ{9ti*5!BjcWYa zW|i8NJf1~wNZ7NEu=mRe7oGb|gjHLK7b~J6DA4{aQb-4nCqb2K3ro;xka53yt)X4x zE%?A{Z(2jm+V`PPac8pI9@@;?-%?VlMnsj8BrjqW$+2<b2J5#RQH9BZQnoaLFoVz8 z!SlgXbl8X={i1KJf*q2}$WD-wFCUhk{!)0dgf}^xEApK8=*%=B7~}2+14KKhO;0)) zl50`83b5C7>U_R_V>WfzY^m_bLT+8<^fgf)lc1Sy31jXE&z4xhq8FPT1YM}DRsQwf z-u?*oirL;$;oeP4E$=??G#!gc4sZddT+A;GZ2EPBigy0EVw4K2?Rl>cGsSlcDrV6< zgs5x3eGB=-IEEdw+g@Peh(P_!!(BJq;1O5ej~wj4cA^X=JnJ*6sBawMcfbL+N|Vi- z&(gNg=SahOD*~45-O9l`NvsyFG4N+ESm{&soYY<Y4x&M+s)FY%Hj=C@(+_<E>{{i} z<J$q9v(`zvE#elP5HnY8q$06Rk(~_?It5_)4rQhVR#8(G-&)A5Z2{4Zx-8B>F{>V6 zx50*?lP>f+_58>;kcHGnYvBmFp3tl`sTJKsNuK&60QwBt_Vfhg;hWCbP9(Eh%)VfR z#D<}Yq{Q=H*{0Z%O?*aehrKH}VLG74ijIy}wv{KIuB@}8e|Iz#WhhO^SYit+g>YSB z!@N|%P|ko(gUH=B3JR6txeuaOdz)B@&i&%0h0Ue5rG3-Ar4d*jAfL58T^!IsFOZh6 zt+7h}XBr%vCeQff_twcIr)LNu^Hzz2#_Cngm&iBC!K6&K0UIIODLZiF5oe#+?`=T) zKs_ZdwxGYariu=W8~wq2f=KQKtL0qZdY9#ju89eQ#R2{b^$g5Zr0imb6j$Nt=-}Y{ zPYpT6%3$+?ORIxCt3J#pQB#E;EnJlA8G-Vm17zdu0s?Obbpn{^gp7{+1=BXYg*KRN z(hvuzmselA1$c0rUoM>($t0bwB}zlZv)_wKVxZA`6|rw)uk_HbUP;AFcf(=|AiYWn zwAUXHz#FNe)#w>~=Q!`_4ab!C6HrgxmfFRy>pu$FJQEy?NF8vw{s$B!H(4MYMHxz9 zJdH0gHd-b403pwF!QaR1*8buAMV_;i1{+|B)bA%rR9ZXQ;$JksY^FUQ86EwsKn+mM zY2lcp2t7Iv|AbzJf7SxZu{EaNG`#VGmFC^9B=tm{=Kc0aU*xjR`2O*;djj&+PSX`| z!EE%ar4n=*3`F?|o@=iWX@8n@L4J7nz*?c!D8P#p@}b9+GN5#Jjn(++ryfed=K}kG zR&cxe`Z6bVEsIz0oFM(f6z^NFe{X_PIXE~Dt2hZN(^gb?URqG&R1va1{-9H=S&?8G zrNvoI&zc}dl|j@se=3W%!8_=37ZR%&I?}n`=D=AvZsFpzh(BgjAwMfFCN|DGc;fB? z(lVNR{USh8wYIIyK&Q2>{UD4(LafZ@5%!Yvfu4~sXQ49AYJqjn^RxSlbp2sLV#pDz z9uQJ3&?oRbktLqE#PQV|3g*!6@6i~Q<|sH-H?*L^PpYx%b)Pi!G^u=*S~PR)3neI2 zYO`oH1L6XE8^iPGI)){W-j#3a4!9y&T7j?c<!gvCH0AK{NC)4!^-(4A%U4TF({Bg` z)x5{hS@;X6&nS<#w>Qt&Tp^bmF(xZy2gJ8Xkd^HR0_3&D|41=8#PxnmmoB!kG2;p~ z8Y<e|yO*Op@>89Ia%c1NG%HEEBbw?8oaFUyXgdnS{1*-W?e7Ylre9T9grX;#ikiZ0 z#w$u6O0)LlVhZdV^mS(<6|NG6V(^r@GJW%p7IM>&EeaNP=SFE^-8!P^p6;f20Hu;k z0_a^GK}n4nKeGUYy^u$IO^M<arD#X%3Ldrs^$@(e_%_MMOZqgXyU;F>;gfH@>=i0Q z<awF}hOD_kir@|AGiLaQO&J8UBx9c?|FolT{deGstV|IuNSg^1`U$R`TOXCN6SRLv zkf)&neximb>>s|T8+=I<1ArU=1426{6#h$5;G}nEz3$*sS|B(n&=2Q^{>3t0Jqh|U zT?jJy0Fo8nvk=hsj}L>4F)q3XQ;i%qtW!s(BCf$y?LUBxFUcBw5swC>if-PvGwI0v zTNVzTfo%%<;!h|X-~F~%V4D7)xCbDp$_otwNTL#wd;T1A5Qqw-^N*mQ%tCAc<R=zS z*oj9cwL@A=Ms)5*<iqEkA+IM<cRN*5_t6SsqeaW0AUI6mTuWJ5q}lEe_3_bh5l!EX z;^pIY)z<8tbUCp$X_9c!6-O3Eeus4&Y+NQe3vhdpy^a-|+B7;k<KjsbZQkd;flW^7 z(_Xy74ipBui5y*s*+C6aF_D5>C|D>BOZ_u1`**O)LTI}1;-VG8jDq)Xj@F7bh@VSM zXd)9otK;ouoUdaRBJtBNZT-nN)$6Rpnf46|+H31E3qwudvwQF#JcKbPj3rC*`OIiP z8YzD_X05Ab%-#Sh*Tg~bVVzgN@>t@+rf>tqq_zJelJ#FGwErc`@;@P%8dn1;7!|}5 zgdo|vTt1J$PrO2#G|K5tP3*?7ex4@}WM+Ykb$l<PV`GMHo4x<OcIa{r<jnsb^Cu9Y z`U-2r%3H2=Apl_I`_OKJEEPG`UOwqGGB+EO{B-Z87~elqvpslhlnUQ{X?=1*h%uww zv%xTCpSt+_!fpSenvz7TX!t}H1XNS^fNJVvyn>r<SyBb}AN=S#IzH0UP%lJsz7TjU zHX<cJqeg&}Q1TB51D#aYh<*4OI{`nB1i*R`9)wC%@813*Bv}8;+yUzCcB*W|qw48G zaJ`vE%pv5vf7LmHzxNjHH<~^w#s$3-P)aZ1*kBH7)tlYEQOVzgT?*-O!E@AsI?6YU z+k@vHrm5R%H>N4@d%$%ILIGFE{{~xr{;NhSyqjLJ@!^LS+1T3QA24b#2(qL1=pQ!{ z@jpdV0-AJq`8Sy1&DZ$f-mU*@-q7t!GYUYEIGwh6+?S0F4Ji+UgvjJU2UH-v^q^w4 z$>TL|^T&J>OaZ~dQqX}0s|_<yoPh>1&83G8um>q$)|&qKDIA(q#bvuZ`Gz(<E$#hj zfIMi##iSY>jGln#r~XmcK=UaF+bQLrFQM`dz^n_Tld7+34@$H+tE$W<VzpD6t!)mX zO)$a`v>LGYH^1lBJ3yv$3#9J>`o?G=u`9=McqO@?yUt0Y+LD}bHvciaSqC1P#3Cvr zgn}~e<<;&6#(v*5efws97+W+^e80Y~E`;Qmcf|l4!NU6fGfj-R*bxvB=C};{pBtn5 zpshYvW_J?V*4&Kma@qQO#K`9pK?pHZ_u$}{cCl=Q#Dn3OH?ASt*H<2#j>ZEr;z<l2 z_V|F^h@ii}f4<z|;v44tn)Qd*Ms!+D<yP?9B&n>Pv#NitB-5vKG5OqJ@(&ao?mjqD zB$>)r^e>z!u4sXVq#o|)A`pluO6i*G7xo*l=Ub<wo?m4jUG&iNm`zmm<)(V&$2%eY zq?>6^Jyt`0kHFoWPEr~RC%zeUq_R0|>_ueOJMI!QxW`9C&}5cqH1F>;UXc4?dK|6q z<LP+z$sm?wc}HYFHhaxf6?t9mulY99E1Qc*NI*EhCMO?WWKdx58w7K^Y%Iz0T);aQ z0KHXieij6}<$n(y4P=eJW}puA1d=SOaC-+EY8sl}uCB83@{G8vtE=drD^cvn>r-*2 z+cx|AW)l`{PKd1PYCPon@86-RY`&CfJm2Y?FCEu^HPtyZ{$4pS2;RKUvH@>Sjmji% z<Z|6Q&41Pbe&SRm8#}w_NfAv6AwK?N5)QqgT{No15xt3GwXs4YOoCm-YReKH<O6h~ z?{v~dsa{v161x^NRS`v&zZX%^lm2GCYJfp0OpR*XhxfocP*4O28t_a?Y8IQEt8c8C zZTmT^NfrS}b8at^)rEzf-L;Oe5>nMvV&~I!hCa8Q%lqfL9l(hNuO%LC_R<ki?%d52 z+s;Dv1lw(GZRat82`~a&5=%qFc5vmT@xSQ1THn`~{=p5#by(<%6+6PVB<<{&HiT~u zWsEY*YoHYiBp)>YCZ$Fx@HchmB8lr*8MgA^xrs9)HQKhZaWwpZ*W3D_=`s8jBjfN$ z3z&2+r<VqBhY>J?fFQN#UpV@w4S1w#j*eBnz94?2565b#G){%saq`E!whMbu*zLGO zJz;kCTB5L&gLmLl1x^XjZ;32E5y#wD^H?O94}ioDiWUR=&x8n4zmJ)TL9aOv#p<^E zm&%TTf$Ff_wN=^~Y<-FQpNce`jyA>wdo=rH`T?8)bv4pyZ)>Z#OF}{tJ%>cP&%i9( zuGm1(`^*$W%+l&=WL#Wo#Qvhl7Il8UxOf+j!{%^ldOE-QdGO{$Dvw(`#$e=`yQjVV z;|qlsPbgpK-kcyMpfs{QK#iEbRvK*>?Yxs7;0@xG-HOgvljxnc=MOuAV${^sK+pWj zxc~Jq<L?Wm`4L9R&2iez@#7pdV>W8)-}Sp*X^QX5_lwk7ET)$`&YA;OV(Bh2Wt+W$ zUQB8QW<1}ZD>qoa@&^A*Fgcb+ZM?=NQzVpNxCbC8fS&qfy3J5l7G&vHR(8XvU1?S( z`UM9E^PU~qB?g1_GcQuXyR@|Cv$wjuDpUZyALy3AV9d>OQ)NHYE}cZkVmV(Zd;P8V z8}h<YLtWi8!FOYpaJ-1!=3sPCm;AwFqVom+ipP&1<DcP}C$W6XE_VW}<BXI0+W0o7 znMz4{S(z@x-w<A-Yhi3`4EOX&tTcZ190$2ZDmkTS0?b1hcP=@#+#Zwin9iTTA%<uB z{=0ej@Cqkh*B)T`Q!0!F`-bm@Q4-n0ZP|}U$xN*g^^R#H|Ck6U5C`eu_3Se$y7Q%_ z)*2c~-D~CtTr}T`tE)F+R-Qjk&<l)jOpwB9ZEK5TFi0UGDJZO{uBfQ0qGRRZ;rTH= z-90)Q{pT!zXD6*n=kn?**uT`())}h_{Ph%7jPPD<gF5+*YM$WPVf&MZpTT2eXQ#NA z@MFi4dVIp$5+woKy4w7*#X^t00sy^m1GSP4b>%ZJUfxRhgUX7EB3o0V4-?(>g*lFn z4h8wiHTCr`EAQUoi|Mj_k@>Pxkw~Z3uq6>)!^dh~t-*b)V(n=nE*6;9Ki_JzB|jnM z0)0d2yPGT)cn{$LZv@NjY!O6UKcN~cC+o`zhw=<%rl9q7KoD3iP(^cLdeyCUQjYI@ z_YYyuxBc{gOY&o<#&v@?lwBgaU;P)$PqTaHi{Lv9w6!oOGMiJljpC^IV4|+OyBnlu zPLX^%U=b1#F;fo!1!LMQ%Rq$hm(N)rL_DeG-7n$01v~P(@=v8-oEb^x<QfTew2O+g z-Hf=;h~B3SEg^wZrde=DMH_V}m&_e=fhJez#h8i?lN`m7%IhaV+81g71;0hCK=wr8 zi_*n7Xr|>#5doh{Yo`?lkt!VCJ}n_DyL;s$npCxm`|y6QjLtho7F$Pqv4Ku085xV& zQhs~$+4InuV96i=DMcm4N$RKg`---;CnUy$IoH8(y#+H?OSJHSkbn?R5)$#DSX>!$ z5M|(TJT0Aw>;+RVWGZ+@E8Fb0m!k=Gc)%G7Ca0GaCwfLlUjfFUO=mM0HP{N?NJ>mh zsLK0-n%$S>mzwhjZO<QNaZ%K<a;mD>fNhA%9ax{c>mPP8TBL7jne)e+(>LP;Z^V<( zSYKR(IZx?;ygW=&UboYAlgza5oG(wX-Gu6!U1oMlOFJ(=eM0(&kL@1;3vm*_9Bgd5 z0Ec1B#=#Lb4iqc`MOo8eG7aV2eN|~)!|g$B3>Su{{hDWx@OuyXV3nlCua}?5rf<!r zly_Udu>@x`k2`4CncbXyO8tt+27-@=jXivef{UD7P$Eyqov~-M^>fhpp_j(&+tL)h zVvh%5h|QVIlx8b_-JymvG!v;35-lGq-=nSZuED|5SxA<F!A(4X_pX<^s=7k=ij8zg zXs-10fzA}ml!lY<5z4fQ5K2!HU?js~G8(r>tq&*R<+eVJ-+J|ZUJ!YK_(uA|4YK&D z?Ty~z;_=z#=d7#}5iesi{b%l*GJAcTJ`axMwW%pC9;JF1TUo8Ww{oIA9q-hopS*d6 z`|A$$f#T^InqobD&SY|#_uchsjZQPYl&92--t`11Ya+xzLm4zUr3oJl-3#GL=6&d~ zyt+t(8z?DxAMU=-Kz^~IuD8_A&o3bjO=zF!FXz7w&siDJ@vvG7nrlxDHL=hr+QJy~ z{tx&ANVzHpDOdk4k8yQ#LA`gUz_cQ2sCMVu)@)obL{f6#;of1oZg&#~1`b#6t31zJ zobOEy1#rwzNBU*L>Q9I>4jlh)xnrvT)g1#Po05>0x|e;Y5^eva(9FPuA21Jt`5&1# zt6ybjIfIq~+TO^uk@r`CJP`c9hdj&~_pVyhKX-|kY@c>T^g6}7&XF3xkQ=9`re<Ja ziA7gA>XR%U<|cWiV501ZIH%=o4=3RlHrrtNrrF5vq8BJ6<*<2^Th=be>rHk5qh6XE zD>L?SkvI{HC=k*|Q1%PSUVXQ%{6jq)>fEyzeQ;5$;~}tc^?Rh$fv`Fh3E#WrMcNka zwCk%~<8JYDG6Lbq0y?B1eowz+Q)TB4{{M`6Fbe_KKVUeVH!2>)_52>LT}nav2L~JI zEQZL6xgKzZM9d+3i)ykyBgYNpZMtH&-MY2?^b7jj+$L&C&*LND%@oYrZTiij=%EJ( zXbC}CSvfPRYGastOsuT+j!4H^C&E!oX9QOURGU0JFqqe6^-fWk#II^WlD7w!jb;P< zm2j`I;-5fNML_hNSkNPoWRBxv{1^hER-VrUGI+>9eSPg)gWkD|^nxB%MwadY`azhZ zbf}K^Vti&HYqHE+D_)n40F>3o4Lo@_?@fH$LkdURQ$=?Cx<4Auf`J*p#oaQzI5{hl z@vaBb>2>H_*~Kk%xlg+j^_&;?Y{uiC3SMb8F35CxV8jW&Od)=bzYbQJVifP&jdf1C z?+)`fg@e`W^q9kYHYb}LI*|{$ckAkF5$ofD^URFzu!Dr4%dth4%U>Ll96$58(>y_? z-UmAZY@FtULu)9W0FF~zy+h-s`D}ShYwPC>b{(B&?@N$xMZ#<`Z9JA3DlFVq>*7MI z@h&tVfUeql17~a2;|1MIo1=i21%<^DZCcTe1})Qbx>AFk`Oh>a*O~S>fapU>CHY2j za_iD)Wfjk~uIw?nm$AI7Vb07yBd#<w)FC$!SGZ&8V4wn9CF$+K43D~M{PX7o4C+G- zU@jfuST*`ajuT8&1%=C6+c_zvyr88ORG_peZWn~Y=!GCLl$6;46pI`rJ3-n(dg0(j zP{K4ZsW8~~fyi@>pDGqq9J#tCR|T?q|5-(HvHq_rl3PlA`P|i5apin{8KW{&$u32p zcJpZB&sSBHacZn*-pNOs@oyTDqD1z!O@=7mwAAOMp0%gp%%Gyyn`E?-*tbTfJ$AJ7 ziQ<iw|7@-|n1#08mw5Y6`-kzb8B#nRwBQc~p}3vJ83KPvhyn~16c5zj&l4hs$`s+( z(fN=>WKV7L+e$O!YO=YHikM;&5xb}12!gw}F#erK*a6eEwvse4;jO*#x9<i;9ZQJ+ zgDj+~54o6Wv3ad}wCMzfbPw@pWW}ZR?MFa2*#sM!iXwus4X<-iTy=OD9>ngnAGBd@ z;J&{v1%_wvUU#rp<S<y}t5`f!8m*r7T4%cpJRtv>ftV`fp~ab3ttsr?)cs&QSuYwl zS<?zqy}b73UlBa}k7kY)22?0(WjTz^V<++w?Rbu8Ya8^$Upzs5aI`Hy(GwK`Uq!SR z)u)H2pbBRw_a(th#-v6%qm1arG55GZhewQN2O;C1#y2%FX3_|z0m6d<^+}i8LCDn_ zy;kPbzhMML4dQ`a`R+WaRS<UOzOJDk?d=l#u}}!N>*5w?@^oTCB9HUwa`&+YSwtSc z$MudDNBJ{jxSGIBl|e@n;3`~iHv#34fhgz<IRX~5_Zv}aode48rptDFa^~xPu(?#+ zZnnupQ7M6c0QuQBEJW%bD1%vDfLQiq!RG>GRZ~!AXXO~}xikP!0rYQ7oj<?;^q?*; zWv=;AM@#)G%4i|3_})m4qwz$6cqR&T%yOcD{bGd#G5e7DIJ=N_XWq+LPj9wFg;fRb zbsNe^(^qz<1Re~;%8$%kS0}HI?|i(>v`dp+6>3xLz@OlAexiUph%!|i#0Q<X^IyQm zPr&*ZG#@HVFTh$ff43t;e~F8GcCt}XYjo__Ob|kM=Ci!N4Chxi4-jDBg9xko(y|a8 z6GP17nCO_mbMo!$*Z%F9QpMqS_Irb6qw@1SA(xU`cyv0s;qhT>mRcOAox5vk$WnP8 z7W`YM155ud21&nuF%k|{Zxg-eeWwzF)EDLD;)(0w4@4Aw`gO(O@O#uU@G`=j)e1fX z=E?m5eQ<49q+Z`PI~#(PbP(-C%9Zt)L(lrU;qp_qS8=9-Q)-G<NJvQ2waZYXPBSYb z<7|xsD`*Y#8mfBoFYHQQXMC6{<>#&>&%bv8x?_Mf5bw$2Mb>Ryl<+#1R)h8iq43@b zJbCZeP!!T%5FoV1*-6#AAmK2X#bs;6Xu<2UQg@y;byD>@x!=diPYyHX=jQg83s_~! zPVtsAs@)r9D_bXroDU)k@d&f_(S6t+GhuZcfEQs!)<#_s`bK~hH8j&l&Mfkp%vTj9 z>NMM|^`7-G%@bPzQy^i58$5z8dB(tyB^#d`AQNb4Ol4xN7#iw{MurC0r<=o0ufuYb zr(qTY{f+*j=%m14B0;UFqm$~<K(z9kM2ll}4ex8CwbFc`gldKE%$nUiy?%G>WtrcB ztAHM3+mScYb+{GkkizEJ+Esy<${p@()m^g}kOyYUuef&6+EC(RQDwf?rajylMa#g9 zyBaw=1VxaJYalG#>0-h&E`zSB%u82F+g$(1G}4U#klpsi@WqKip_G)=bhU|mu?L-Y zEzgJdsZEXb{Yaaal~_fR4)XRAqC-5Rlp!1-FV)WL+yiuKeJ)Pan++z;`#7l=K^okZ zawn3Vv>_=aqS6(q+?HE$y%+dM-*3d`w4)%D*Zm?t(}&mt6?hF5DMK<M&|<$`E+on3 zq2;dpy`(<IQEA$uv!S5mq27hwLY7W+_4ntLmIgqg0Y3Ab$@VRdLH-82p7AxH3JPR^ z?Tqs~JQvtFEb015EQ_IHIm;i6%$^aZitS<$&RUJ`@kje>ekGczG~sX4mnQGxB%YB+ z#)v5VPAsT`p##DS%$fT~atnXh<w$uaEicc|HvU_&Js~M!SR#qpLd^HDduz0=kMsEW z%zQq3OY*)slj1W)#b>CW%!`YFanoY%s|=c4_$SC_?m!m_>Kx4GNle#o=v|9fw3jBT z_qOYklF%9-0}qNt27b;4eax4cYLlsN;)02W=cD^jy<8E)Y9mAlwRvUDSH(5Dp+~ok zUOzC6z3t(qkd~X1mcdN!mM2Pg>~1_}G@$dGF|8WJpwgxbSBSVAbm*8x#7O_B`QADi zFR=^jTT!Tw%}Kk$G4N1-x_#FH3mPZ2JA5^iQe`~OM#-WL8uv5)Ina7vdkp{X!_jH% zqu+A1j!P^!Tlp~@Fbm;|5m7#VE=G>n<oJ#Kcjds<k`qcOhbKmbEidbr7)Lw>R!olf zFjAK8j+=s80|Yv&^IGC_v~fOF%3ngFz`lGb-}4(s*>;bad|s1GegHAc-~>G_t-%LO zum0(#O+JvrknPK!E!AzBD8hJvahEe~U`;WfjhWjAQXaiG8KHa-EEuVvaC~$G`k+OV zA5pw<cxkr3FFXVOQRtqbj)K)oo|h*7%1g-NoOf^09E(rhmc?X6h&u~J7|-PpgOnIR z&%tz~2`bG+6l_fmm2s1d1Ct7wwt3KN*f>qjWjstxU4wH%Cv~fSO0O(rEb0Xnfj1ko zxr}@;X@bal(Idm87qInma!Zdnz3~)YdK=mfbkgn(n=s2M*lg{6X=z;}vp$TyGcIqw zJj*WnVz;ultUcZRL*-Q4SWya8$rUYNM{Dnw$ivC2vulS}GMqCU5tW#-b9mrQDMPQa zv9N<Ua&fjbO$4D}#OhmO8;7kFuT0p@yTKD3G(rlV%<ANRsZTdIXJlj~;ItL1E%esu z>Sj*bynpJ+V&qpAF_dyw6m8jCVO#9y*%~<^Rnyw?vb>A|eN4{h?#_~*xp8oJo}@!a zTt`A8fnw$HjW7d{H8I)wIt(^j4@KsE*?_jpkG6i*^Gx2rF*cHp6FiTn!dm;eALP4A z&*)nioSm9X0%EJOSH`>CViOnK<q%fwo=|;IBm*@8PAQF^&fyAlrOFb``se4TzZ*(; z7rL$2w?2Dc2A_d0DA=?GO&x1j5t7SZ3Je9q<^U&n4hqZYO*rN5E9Xi*p4nj?@R|H{ z>Z2owu^qR}nZG4;`$+~S73)cx%iVk^;w|=@sS4@d-%>vk(Px~w=G~&&A+GkL9s2&h z2bjLAv_M#__}siuVIau$sX9iIZ3oItoxbE@Tz3PB$?t>?kcNfjZg%?1^Qc^HDNRzv zXR6w9m$%$v!dpcxo`zcCWrfv1G4>#sPN2p&A;`zY$)YaQs&P;DTUvaU>L*-Ep5N|; zY$q1E%6i<b5mP&*cS4uEesb-HK3lo_*5ad{4%IzYtLcC@%?^A9z;xdkye6ZA)-;!) zrcWR?(7Q3(#GLI&&_r;#xPit=xH%g)QAmY3Lc?n5TPn_RG&Ewhifo5wfqjS@Cdmk& zuKa#Uu=3yop_XlR)@JwZoa9jSO3alZ*DKGPC*wY7*dF51sr2XI;;zQx;zqBUoNoEP zIe0ZNi|KI*8p~AE!{U)FMTzo@^ms;vXSFIdR4Xj<h2l#nPCMN1cMqNSB}z-e<MIRd zV>YX&t4vuuHflhj`o(v+D8qhHeYu;xLQ}KNCf#;eR3@0Np#^h=Jj3b38EWLT{?fJj zJ`rAad^Tse-~>Y-;+#w)T1q6>S;rWG9h4^-nc~y9mG}ibfsvJ#J+q{E3O|9P7_8Nu zZ)l?!S9(pJU29eZnyz6-)Z3fl;gV!KX5~!rx_fmG^G-PV{|0@+zqJ6ZCfAnlgCDzl zw@wGv8m>DE(4*HtxeO$bDV#y_bNva6A`G))=+v9e53Sac@Cg;UFIrA=l?{!kS6LoE zKHa#`xqrvIHsQIO$!X0sdNzcULO@Y53aHe0T?j<TO&lSHUJNH|fRMA_9hPU9%{0sX zhfO8Mq`+GC3z+ELoLeGJyaM~~4{NK4t?9tVZ=Ho<4;*kN>-WC|>ic^!S^cOabYf(x z$g_wsTO0KQy!W}snW;W`3n*QfGo*0b1$)Eu^}}5Yi*JD1eI0t8dc|wisnj>n_*0m= z8nZHRL-R=O^(#uR!<IXycHOfTMpEe!_P7DAG4ew;qpoBTHS%&E98OPvtwkjyAd#2C zquJ>w`-c%R2;Ky451?d$g=4pfhT^x*M~YqOX0ox&|DHquchlC!O+z>D9$+B~c%du2 zVFe-oN<##Ft98jPmQk+e9zF_r+$KD!E>a*IGa3!E2itwyB}Ii1DyM@pg66I3nZ+0n zHwXEq@GQoHB8Ab+>1HQlObP#>eViS0U0r!Y$1wk-;FMus?nmNX#r-nf`o<Oc{nC$O z&IP(#Lbif1o*Ia@tsIyNi*)Qv+F9@5k(LDq$x2m~RY7MDKdbK^T6vu>%*g)!cArz^ z1vYqXb8gTSW{0&eM?*pCEV+S7P;Sl);3k<0=KM@Occ$@_ils+0taUUMe$HPAzrvEf z-s@RuzV6&%?BiJrb{TcjOJbm4PCobUuD<%PjMrVy#<_t!JTFAW1ncN2ri7RbD=YK3 z?Fz)$ANVGjNoF1T!3KQ7a@O;l%l$_<9Dn^6`4obP%@yqTwddx4pUb$7ImsqBinTew z>$HKk$KXn`DdB`L`Q5|4lk})p3r~llFMzKN<AKv16cE`AitT@q`GL;f4AZ)}-1@Sz zr<p#0`DS8Zp;LLG5)cx!vhNafF>>uB7n3X_BqY?n=d5W;1f*0qS_(Pxn^(*qjT?WP zp%Ba;jfsE6wcy(%{%_O_ePji~va+&d5q~;Lz^jsDi;4WG@_%$I|3A~M{2#>%z*zo2 ztyt0Vsi`^rMabGS*A0DzWieG}v6Mp#T9i`Epxyw48nR^>0RdtJAUy@v{`056YF}(j zjKeiQ)nOeV;VZMUKBF))F<H$u^??=RR>N(uarB{YzA^+XLy$94Z&?Ly3B)1f<V;ND ziX$OCu_X^5)%F-4zc^ZWP{FI`@3cEr4?H0uG<|DB1eqC`39K`H8r8hWBeYcqLT*EM zbyp7bdk^4W-`YTKHdlKnfWNVTKJ_|U7w^E>mQCi#<ht5vbd$urzM9Il1FDkIce_6X z{VU2V5>$+=tm5!V=iXA~MUJ4|`x(xA=03ET-K+8X<x88NS@}S(QqbFqyg2bdEaUXw z(yX<$Sk5aev$44WjsA*QLJwTScjgFCm{ltrk*qpi;`%_|;JMm61=6SPKERl-v9W7E zG7%OQ1`U1ZqxG_c1e5wI3x5n^A{-nfn2@J<olB!#ZVpc9OtmF&IfC+~+4wg!%y8q$ zw*fgew)Ueig@1LnaM_;*RL4z#_GiCN&HBO)i_5SO@F8q{sJ4XjxE$C^NE9@Ilmc)5 zwf^L2JkY4z+L}5f?fv?rDO&6mOln%4Ag!p8#NEem|DfP-Ct4gtH~`cB%>M-VD40=J zRjsidOI*_(AY^`Au%sr+kb+z9FoOVzMfEi`kJsU>RC(ST4IN?0d5RrO%*+lQ{d1$+ z46Lk~4&WjQmC=M*jJQsgzV!3+dk1>ZQ(#n{UbCikVO^fkaceT2|NVOd<)_aG-F9Yu z^A#ygrjmi5qVWO&uX6xdV;o#uw!c1lI#yNvJ=uacq$}gje39A7&Kwms&%+ocJL<Jc z<DsuVDYCl^rIQBZ!8|*!=jG?}Q_f`067@zuy)qvkBw$IZtEx6;a#_)>*?|2Ud5&3C zRi%A&amUCg7o>R^7&o<x&_rA|8H>wUf*fUT*Gpjf0biIr$=H%L3i|VuxH#FRfn-iz zGen0V3T7g!l_gNhA3slgXPMRTM1zp9;0L_^`lE-qM~Gxx$==x|spsVxXvv{@B3+Jk zywufIk4V{~&mX<}k^1I3@jo*v1%x6)F0Gvm?CevAUSB~z+114&MNoCl!0E3m<Y4OB z^`6XHn2zW1_V$bu)QHz+1DoPNtNtVmpQpF8^X;qUonPtXu88%kmWJKP$SB_U<EJ26 z;$mguK1ei6{U7a}byU>*yYEp{wxD2uDCq{JLt0uvx?uomX@-<;P!ZVlMj9N3oFN3H zn^BN%h9QRT8bG??esG_C&hOM+XWeuEx$B<)T&^WcX1?)!p6C6%UMK6?F$~H8*}k*C z@8s-U(8V%4J1by2{)0Gwf;w83*LWZnMCb#F{MH9^O(8BW2^=sbMa5sayX2ry?}Cig zZP=fGmfL8l$<=~Ie83K|8~mCMgR!6W)xNw<d3bUZM|cf#B<5u057M_#vwSUf!1x8h z3lMCO+A}pWqNPaN3M1#d{qrD&+mr6L1{P6sGGOlCbpbUr=g&<0I*p`VQtLj4^}v*2 zLT9+69W8dfFJoV!+gV$<K%qGxow<79?u=4P?F8rRk`=&o8hPQrJF?~Hd(!tJn0S5l z`ZX}>?gxf0p5cP2L)@sdn;?kNfMid?jU1c)OiQEH&mca-%(?UJy=0P(&Xm8v@V6KK zvmYJX+uO-G4G~-a#Gi@lT#5(}$5z<wY_-z*9qm;v_2yMK1oF=fhM0om4DTsMz!{2f z<wbEmyQ6YKLgjRN*iIu_Q#AE;>)W|#g;N=jt{Y{&H9FE{%Gv0F{aHJ>eX@_sDkO!; z>eRaVzWu4R>d1BZ_~X0%y<SVL8dd_N5fmFk<()mSTJZ~9j1&4H#Y0t68UbUcokb<) zRt-gm;lhH|jE%{92Xk{dW0)_n^+_!lBb;j7RwQy^)D>U9GO;nGU6GLqj*TT3D7#5S zBEZkD4s(2Q(Eus9SX|@GR%gCGr6QgrNzZ)E2u0(wx(mey{m6Qfu9{PI2j0V8_d2Xv zkPH<T8k$3pQTGkmn_6x+maHy(QsQ^!W&0N8z1a|w+rG-THnIhBAjZZsD=Uxo_uUrw zL$EPQ>tH6J0v8Jl4~LY6ycoJ(g9b?-mKa7x<ky75;NW1ewS*dAA%(cNw)ejmGUY9b zh){a@@=DxM#9%q7d#!#a?N8FZ38O+xE!bDz(0swiO%v5Q=d@BOMk}{j@FA*H3nu2g zKe)mJ@K74z>0fk;3|~~YS2#>4hJf!fp!NWFX4>2lO&@g8@N?J+ZDwv+ZabPG6}E^| zpy*rLN$TL@J8Lbcx|bX4=YPJ^x-MLIpB4@vPtNnpTi}9MgB5ERrNaHU_Tut~f6zI` zv_#k~kUOKqo!x#$P(mE+?>v0|cKV%)*qJ^Z3L@Pd`eeX~sH?k^HRfFOQ>(Y*i$ya_ zVL?IW{YcfB@vbh2YYdnejK2TEHX0|<oy_kVzvLu6$xy-1&--&v+o<dG&HmSP$s9{C zL_Pv;p}#&EB)I0mCB8A?{-!8(VugO^=g;NAVtnuti<2}@`;c+3W9`-;)#~XVuS|}O z%`Uz=bt{H1mp#LGxDHTdlG!?hRd<b5!ov+o&4t}pz_Rj+(|4GBH5XTLfo??_?eUmi zg->%vvx5KemN#I!9yi4_gjWOpp?dDedfTArsVlI~{2^qu#rkooC|Jxoj+AA}*ufhD zc3yNJknQ-M0IW_pAwABO8-!c{t4XxVUj;Camd)kl<g|uZ#}8WC`&Y1gYoQ5)c5eu* zHo<$Za76h1i^SB_LMws2Fej%B25x>Xt**GlL^DfEne}RGOmftc&#R?7%WN`ZZgx=4 zyb3~1E-tPF4x@A)5{S#iO0bwxGB1Za`yFtF(EWQ=8>$2&>JgJppyk~IL-iqCZ5FI# zN457FKF$E3Ma`bb+n;y5rK&PB13<KEe}k!^LG1f?fsuBEa%z?7(gvW4@ocY|fk%3S z*Pbqd!hXCC;Jd6H95#QkXqv^|%VNG=IRoE{B(z++h-P=7t?f^zw{mjK^qijo@}=!i zv(QN<fb;KO0NEqnuNON@#$~(|4KzNcXF(A-V4n=i%FcF}Dh`X*UO@h3ek<n;O|}A% zD3=c(j-Q2}&P)GAv`K=)X^(%V=ZA$A6&2+sL3OQ@WuN3>Ss-AUReH%CD05bai)1*_ z18B!j<alY^^4BG@_H{M>j!-q%?|&BZU4*#{u|}<+Ylml_b^^B=Q#7mejl+}8@#4K< zBl6SjH3=Rb^oI|P5o^O=9qQ4!XiFfI{MkPTST<v&G6$Yh{=#0kYvklhv9W{3k_0I6 zIZ;F&ldt;0^hoi2T!6yP_I6`alYipDC5fw3X%wMk15mSz?8(IflDvF;XEVW@j7pxB zI;Du*+}tUjz3b+qALPX|Fs;aq*(q|L<I#kk9_2yJ!;LYA_=_z@`jdU+PJH*;zoYH2 z>SM{_{<;vzc*C49#CO<qx8cH%1FWlj?t%WI_UKo9mkW^t`&DH>rEgPe8IvuHjAGUG z3SJ+PyB2q34SfCi8v((IXsz4Vgb94G9tT+lwlMRw2WkOpJDyb*(!(piQsYnWg*-w1 zA}SuaKY9AJnehp~^}{UvtlsW!C1vHUogH(Of&AE=2M-E8bj)LiTO;5uJcpsPT0x+k zLMk`b|EU+3Br1-24EQ*CJ(?$+SL42AW|~@YLZ&hdBl7dZii^24pum~Db@S%ApC7Ih zrBzh#C+e{l9}#-fFZqJV)%9Gz_)AB=YT|QGYw*w^JE&khBLFE)m!DO|rr^!n_xPW2 zI}ki4psFaj#)4KQYZ+akC3zO|S4iys_by7w$9L4v+9oFAJn_L{ov3u!r)l=%yo<BO zoOMwA1-DDxq(0#E73h_-xns(+v!7z3$YexrGoii!eRv6w7*Y$nYg_}J@5^v2h|$%r z4(86|78fmUQ(V)krtMwY!64kE{apL<rLB_<qp^>U3McB_qm<qIbOLcW95@W9fQQ%2 zj2cXniT$&n_x^aj_W_h0yj2N^X}pec)yQB*@F1gT`>*BCIwpr~ClKpbXDA)bW!;o} zQUhcXt@BT5U?R?9EDT!fAOm1Xucp-&Z*J6WRJ~^S0N(*mp9P;=i9+Dmc+x%pT$g7v z7|zsu;~J<*j_WSY^ra6XXayKRO*(`VgoJ=V-rnBc`fyS27oANWK5*48ogbom&j^Uq zjY&ujYFyX+E+#6eh007pU5{V<3Si0{k3WMJcDTEFZ$1Y*8QA<eIzcmxj&^L2NH19c z(-Jk6t>z}(3kNVt1<UbYFQGllZ1%5S#pZ{VW@k%PhiIS&vek2)a#OE5$~z@zW>TNH zmN)^+1NQ)rfj-p{r^AGFTr$XH09QF>cJ1>%et=1-su9XJ068}$dFA5bij3+qwvSJq zJgu#Mjs^fNhLpqx4{g^d!m!YiQYU@=&#|oT;FTQM{1m{by~0zY0UZW?m(AKIua+mS zweqHwUauLL0p<^L({?{xi6VMw!~^UXt{3~iSh)^x@P<iO&Dt+eX*fO4@3qj=(<$Zz zNN}q}<t4B;z5F9-r$NlHU(L~=*3A~n1VA!N0A`^=b%6RuwhzM6Op!`pbtaRMying^ zEYCbM?HF)^Lj#K@s=5b%fb|0+DLS6}F?XA8476o3DuV(+NKo*VRC9$rrcN^q(J|&c zf0+A6o0YqOwtNq`Bb;2mf*inDnQKA<QpUoqA|ejcHWR=Uy*cVW(ly@IF+j&g_X(z0 zd@UKM1M0!5E+|RTN#Kew-k`?HRS7GV1DfX&?`!`<xQ_}<uxNxHJ7_0-uvMjRV{@rW ziKG<$@ZtPl8RI~bZ*AF%7K9LV<;nxWT+M=^=(H|+T;_zFt)A3@^x0PFO@r}#kI3Xe z1@pX{WWY8CLT|GPy~j+90s>KfrMaSlPs`I@xWVz|*QKR{PDp5h!b%6hzyR_o|CQvM zT=^k8J1eDt*Yn#x7wE=;PwE^|HYT<rb{!rRF^RE?{W^kG;v}H<3Qgj%sYy+p%xqO5 zp%RluUUl328}mcN{a?iV5bwJIzym-m$h!V+fnc~B%@xxUMfhdOf1@!@`sI84lY<O* zhe^Wp)Szve>}+#hJE~Xr`)U~w3?ve?YH!KIez<&?P2n_CVGapXupNKSB%2$;f<DCR z@GoEVmz^HvZ`$b>j~$kB71%jiwh!O<wJ%{Eg{WPW&vIeVYn&wfuUXP?J+`sF)Ks{# zBB7k~Fal&^a?(6GscNE|o74Dz=t)x<Er@Tv=V)&zMvsbJ=o$@M>glA}hQZ<Re}Vf< z!v7KO(>ss&KZN^CWg|6Ch7_Md_TroWb4}Wd^%=)%I#*XC1tJBSD1|+!Hu;j6Xl;KY z;KJ~1(-lXQ@8Oa*SyU90QmNCv7^#DXvgr%;egV!nID{!$9&{{*9Y(nf{mO5;Qfd`W zrim24qC?c|ef@q$W|{+kan}<Y>)27rn|6DV+2HW^OKsT=&JCx`zrAJ6e7nHL=!`o4 z*m#CU8n5x&Q=Xt^uAKW%@f>f|_Yox&DLoV(nCw~n-o(gN?1=L?>ku^x(O$5D{2OiA zTkXrunH*7()MMQD1*aO9jVjBFnOT$3%1r?4PZc3CH8VPM2UfB4$DM5`mKyUDn&!-n z9RAI9gC)NloX*ElLBU+;3eMxwDs~zQXZrLh+1}J#Q~X=+_&5%`H?}Zorz$=@y7Py+ zXM_j?$N78`QJE0S`zd12Z*4mVKq@xc>1`<Y--rABJR2PT`}WlhZ2*hx987G90{+qE zaZjUq*Za$3AnF!rMHd@c#lVV}c18Z@nU^~fm!D|f^~dl2g_Ca?=f#3M)9>^~-nz9r zRcEIi@a>)9MD4TWqrtrlDL}$aZe4J-of4Wq$6s)tn9%ojS$nlf@rVMfXR|nUY6&>C z)hG!|(270yEie|`@$8|YMn?>^c_5T{d}0yySI|vz|8*R9(EkOS*IVtRJg{g7zPY@| z0w`6wXlpNRfTOguP;b}qd_soI#o5_GbG?FP_J>0MjeCo=DuA#%CGoR~gQY_K)$;ql z1!f!`UK4QFUbs0h!2QJho~4Wof})J=m78$ezmjjA?k7Njx}<~pp}Fl%qw@6S&q3MM z%sbZGl9g<F9)e@F!{NO_$B>H^rK)_zU-aoqp7#qfRqNh@AK7fGrA*}-ZkC3umxOn| z4e(!A&1Vt=yfbdqu$=Ek-qyjZO){^?xVcMP6wjxpqhmt3Kv<&=sAHl<muI>V>)sDl z8Gq*zq+<y>O6VVL-$^Kh!Wl&AofkhBCHZ%Q`81I4cC|$XPbHi+*V+FSbK`c%qpaM_ zt57!=lUY~r&;)zr{9t}_<()jwf0SaIsPpZ`G&9eiOWrVSZf5-+1rOr7;C`=KW!@^b zSPn+4ztmM}O8FK5h+}G~_P4r<QG{i2yqPsz+4H`b3|`J1DLGam9x)ParPHt+Pj>dM zTf19rS(Vo|STx2q#))9u#)EZm@}>Djom?NsSMNWa{fky=Ye9nyA~OKORi%`b8w^j8 zy!H=Az$kkm@J9=yv{b9x%3!3g+-N0q?lF%>47kn3Jq~}g^?lV#AQs!+oKA>~%Z(Iq zK6ff*xDAr&Yin~D-4$b}?CcNtGRgq(2)0x9)-jl#p&<U1uIf(UPk6)l++!EAxv}~1 z;WDk5Tg}Ti-zM>8z_a;yA7>53O`CbtI_m0Pvt5C0IS+Lgr_bxVy1PG0+$B?@ypEZ2 zUrrQ*Uo1l(!sb9O{@kbMRyn&HZm>FXT{kHy8315Ky|(Lo$KrXn+e_bq;z-4PICikC zQ`@2C=@YOjbDO3wjNvb;P*-O!awvapg&#C4c6Yn>QrzXAd;(EMiHN>qI7x%wHXH6V zdrgERVY|%4>>u@58f`;pbY=|WAP!fnPi)!tO|0w%HX10={voF~k~rca^n{eN*2OmA z7Yj+EzIMFMhXRa^`_GwUJ~TF7imJraO%Vw5Tc5-oqNG!WoSC_Wh9-N0T3+kv444#6 zRY`^kxo)T%6baD>@1rPuPCCj{_OAL6?5}?}bbP(>F!N?)>hqYC6csye*I6q@8E=e% zmYp1C)1x063J@w;*_MNV#}YB~_PNVyh?tUS<Yb`2Fy-I@62`5Xdn1?Tr%Re)jn~}9 zS@3T0{u(AiHw5-+pY>4dx3ibGX$QnPIZ@+FIatzg!iA@aDeVn)ny+8KTJxfzftuJV zcBZpyi!lTf;}i(yfrbb8o5=i4up|<zo|Ax0z{A>#w1>Ss^Xj1G+5r*lP=>T2N<o)* z)??gw4#LDTz2jZ4=;A`9?nS>=6jz6m(cZmAIGE={6XoaOb4)@eU*<sO^SL~<(F?Rn zpS}YI4pLHHC27s0^;%+82AYwgrRe*Xqr!uE)Se*P1q@kbRzu4HD=`j})iPWPo`UfY z79s9g<4tWSa{r%ga`NjS&7S^N(0;IQ-%gM1b;+jzn)-aVCsN?&k*I$C>FF83J_IK9 z$tfv4e*T1kZJUdn8LJFZo}m+=H<dpNsnA2GN7|iFNT@ga3V~#>8-R(jPqU!&AkPpR zAFmAOj{Jm<La}H20LE?3(pTrrbWr(F3zr#FMzBleKUMg)%__u1;4oRN%@Q|JG~Kp^ zc5(aDr%>bg?_L1+Y@Ja&uMPI+oX)1YmtmPLA3bW{;u3YVDfSC>G*M<36%j$k4nL<C z07*L|2hN2+4SpaN6Adf?5)F8?_*!JNC?|bNh4|Ohsrjvo%$sf-qKbfiO$8NR308-C z1>yD$K{(L&@Nl%O-86T2x7COea1hV89_i?QMQc!kuWbr=!`SFT)y3+`sPDTUd~YHY zHwTL}1*9EQaQ^R@W*xS>!z4emC*Y_zf@hW9i{AIGl7Kc4$-vIck==rfNOy}2Q_(+d zr8rI#PvN0wWOScOpR<nQ@;7oIY>0KwRbpfB#%z>WE5wh9tiJC8-Wj1#tNN{w_Sn3I zf&}N~5oYYdr0AravYg)WQjL>yuIRK%YQ4wi_sj!CxXtL7txse&qfOyn@*puyTPF}g zybX+IaVJz5eyM8LIK8X%o4@;9?9e5rN~?EXG`MK0sTFT?L9MM7sqw{WH=!{tsz?qM zzhN_Wg5S^TH7w)YEEmge&fHboC6{sNC#YZgrnZVHv%<>Sja@yJQLO?i#wp1U)vipo zbWn+7PSY*2TCy0Vto=`>?-yv2M&<@7;X_{Dszz?r%+NFTgg+7-X_|-|Sp6gY42;)v zpiiJ9@6?S9H15yEcPFbpRy8EP?#>cVFm)?^M%bOUFAuDkOTmGIO(UreWYMH=uWBeo zH-@gty4?g^B2vDQj4BBeCl*b`Tz-}8R)8}aav@?@XSowjD;oaEXp_bu=Z_xykkvLB zl~l5X*hqllF;pKl1jqU+v-v54hx|DXC;aTEzID0s)()1G)7skTnq*$<Zx+Hr4%2$W zVR?zM=B3WtIUiMgqb}8E*oZt50Dy`NQAoSi(gqis047o(;Q0%-q>e}shbc!j-VYQ9 zmmMuaa!kv<u*a6kOh)}?wJ)XhUeKWZpcgr(5%Q-z-<xEZe0FRLLnQS}XcR@vRaP=b zkZ+NI1q1L1GpEjZxQ)2Gwk6Af-!tD&2$?D9QS1U-Rvr$1p+3MzL?*r-om8vICKSS) zK%ZdjbGzy3%%|?Ob$3$oIQ?e#GwocIKEouZLxGldk7>kRGm0yDpu0N|AX1`tL-Hrg zG4X7bo&Xk-f!|=awzzu)?1szOh%sBsPmwL7JPc?8nbs!s(hLr*NjgaL^RLXIKskQ5 zl&6r&`86k@>x$GYy26?Zrn9r1zLCkv5<1mSpKUW{`H0w1#PzO-;FU+E<P)8c5jAri z;XFSE1`5LbxcK-U3A#MiqaJp;Gaw=MSupNK4p%PgHZR);13p+&`ouxrTzak@SP>w7 zo2ytrSbgwkBQIuzkdScYho~mqO7^OmTst#CRBA@)PaFuS^C;1Wz}CYc-Ag-6+wppk z+97rTypuz2Gn1>&$|);l&caQydz6VCNfQPm%z`gbN%oVMOeKY!FB=<+_eftyHPU4! zWjBX)zF+mIQZv?EmnCE>Q*UMi1w5#nNr#yn)U+&Ef;%n%F(~66TVORvzyb%>Gq6#f zK}k<y41xMRcpw)NFN9ZuEj^X<sPGq{HhO%=O2<Rj%OZa<V$`@f@WJ3)FcN{7nHvot z76H!U4ksInVYS81mz5ai--2YM(O7bjaeNI4c)<rh48^1@^K84gW6G{z#m)0rX@y-Q z?;U|9vo$a8feoNBQia0h8*$fS&A|>^F21R)nWA2EWcp!egN>C{TYMoOwJD*sds1%B zQ>f|k6FgzX2__*DWsErm!i!(V@HRI;zth)B(1O!wuq$0{`J>sSqgy$Wlb9?NyDQAX z5J{X!j!sO;oqVKgrxBYXy?&3$jT6+9RaHMaI_UWLVC%L_k?n(Jx3rhY$yZff;q^7r zoiBkicgPMK{V7>_T_yP1Ui_%1sG;9-GBG2FhfY7eY@&N|u!}Y!3vng)L)jqOnOA*) z|4tLh`%i(!uyjnMnOQDm40@l%)&X0SGNd3FkmnUk3A#8;Or_+!8i{FH5`5a2XdKRZ zvrJyo^EiElR{XYJy)h*w(Evux3@P4JXL}HOt{iU?@){nk8O?0Z(lN3iy}GtmnyvAm z*@k}<H4u@{^k+Zu#;E_`aBHoj>NN0}G4Z%=j08>AJn%UInPmXFnQE<#gs{M#t!E}E zX^-0ck$WfgX!{;{f2U~nr1IDh`;AUcChZFA^~Lz^l&^47&0Hw^Wx6u+$Y%j)LP5tU zh#1#og*ekdyz*O`49I33Qs;9Af$?yWFpce#W3*03jJf&3GhL`q%X#XHCJq}1IiYV( z&PF~BI1Ig3e0*SFbEs)hw7+BHyt#}7x}`5&D)<#petGlx*y>+}eawBkZk>|RxQ;Ar z2HZe^Y#L3sQxH<iYz{X`ss`>fx*i)*kF{LOtsFfqaCh0Img(`6FNo&9=F^21pb zMUAnmcz8_H>Pgrp!!HtyYol=Gbv>J!PQ!mfMl}JCRJ#8;U&NO?%|yD)WW;)vvA&pr z_Wo4)6cGHkoG1Acp!P0NO@onxW#2$`rUUm;hz`6e({y7G9Bd9nQo)@rWk;ya`yKd5 znSNtNfaNK=1$LHLb<RLv`_fg}(B}|)GZZ>0_LIDCxYrf2g&_q#gMGEPPr&J+M>oeX zcf3q30OVw^UB99F)w!(Fdt0O~74@YrB|cg%|7V;y_ILn8Nfp`hSw=8r`@Z*RJ-6;6 zX039BWo0Xd)B4-r<SJXRL*mD?DL_%>v(8|5ku!ro3T5KPVqX_eS*EFPaH1~MHYAZ^ z7yyUP6)}Q2&>8+4Ia~?C>K9>3H!&!8@)YRjVl@y9;3fSlz&XKEUaOxDK7UnIMvko3 zQiI3Sk>S=b_I*ZVR*5@d4FGsvcP|p!zzPH<=cJ-&y(h$}*+FV^c#vBCoGO2a^wA?7 z&;{Ofu~o>0Da$uMeG;GYu7|JRQ8t*B9`z|ND=U_|XyuX!n<4JG@6wH#*2}XQ9IODP z6%s2BI==5hz3m9A$+4B%0?nOn1$sDP7yYfx`jUT1UJi_Ux(g%#znm3?&LcZLfeYVJ zqswBz_oyAWLX=RL@ld|leejQ$d-$ik5s=P*Axe>9p$fnUIFh`)d^f<)r~y0D23APL z^$5(>n0@z=&Hz3K*hS#2Yv4Lx8`HvO*nk~q{Ji=F-kbE&#@IPk;>|nYTxrd9c#%R* zecyln@DYnz0#PlgFDSIS4CDHlavDG~POk^oUrw*7vUI*%8&d2Do|SfXwjJ#HkFJ++ zqE7g7{Jz!3NV7_-zYB{D0ggSmAk_wVrO}GT`+AmvLmp`@>dZKuMy3}avl>V4@@{{N zzE36E(@S)bX3P<#5NMdUdr@qSe_g91?2<7!kn?_fm6%Gbec|np?MO?*XC|Yz{0u9P z!^0JxB~Fb1)oseYN`eCO{qXj%_#%Y0fUhD*IV0L$8#f!Qb4la7#QOb}7wwZNs_7)N zMwjSFm~0D(vpwVfM1}$`y~ap)H<v8p5wN_(UFu|IldEqq)1pWve464(R5(!uBAk5A z*jM`{wB@nlG8n`g76}=?1zge6nRI^IeZGQZ0cQ8E=fZ;FKv_8T;0)Aa62YHmL&=p0 zX8y{ry3SY~U&dF}sw;D`O(9gGo{@g6g?xbXbiw^k)T>bRUpdb%Q~+TYM3q-SApfly z*`@jJxo|vDgSAYa)D@=Rf7h9MVRTet%Ob0B8-t$P?3`^?PAd0Xpkr}%s-}`k))xL0 zO`Zk(45Zr6@(rN6UWninqH>YzTg>;Rxr#nm7Xszuaa>h`oxV>745m~~)!xR*mrf<U zqT%^uo$slW41w@^r`aZ^Z3)!~bIEn4yYm~MV(0soSoYFaYziLERl-YX^}VDQ!7=-y zdfrmn&+eu#VzAjO+o@rdiy=-vxAWCXQb(_1wtF>|`~@Ji;ci|TwFs8F43SO_)3!1` zQR`IwTrl7A+eZm3b5sIlX5jYH>v9AW2S+*vTHW_KQjTzUp`pIuI@zWHtlUl#gMEPa zLi;aQUw-`^au$5D1A&C>nyNQCl15q@<9M}=(biza5IDu+DCLq~3zoA!7sP5?JX!Ey z&xIK<kEwV(c#ytddj&f>iiJ4IliW7C$L^m0=)t<Hxk>!K0c-H_Lr_T7crKj-z-GZ) z6Ft2(kgx%dFd?B4bh!JbxEW`d$$Wyn_W4*nVP5M)Da#^2olJ-uUvSE4(kSe0;?P;= z$}~64dAm_i#-+>TAE{|WxQgtLioZEOJYUzCNgIdq&DXm8J@C%yFG*ScwX^3BJhs`s zfPL=j;|y$cS~y`n0L2pTSH$6LRgKR*J)V#?GcT%7wMgzvKqslnqCh!g7#B7Tf?IBY z(FBM)`NY3k#A(}?vD1WK&Z~d4`29P6QtD@2b}uildm$e|eTIiu0BAv}PM7ZX|FQc0 z|77+1&y&di0a)vjL5BB&;O)bl)TNoby^ZJR%pA-B#{(o1>6Pm0Xi(WFS}Q0i^mg>5 zzaKe#rR!1c{`8)l$E#TEqw>1F8nBEg^-7wD5BW9cITv%1XV|&v8~ES70H#RzFso<) zag9F03qr0wNAQ9@6ZL&S{mPEesY39v%{V=9bZP<^Tsf}SRR)+z-L~0IVq#(_sVUu0 z2L-*>fDE<QhE71-=adbg>u(fJRmH_e>ueajf8jB^d%c{;+H=iFg4wQfzh0N&Px;Ps zT~uJMV6o#C*giAPGsDz$UrqmNfgF6YJ9F9X)3lIp-rDgpAZl>k{7(PR|E00gO;xaU zv?ByrQXT#<kx6*rbOmo(38Z!L#S*y|&?J^$#W{MEv5bgNQ+*!^3oU*P=mcnnjefa# z8*pQP)JDowy92G#<!Ol;aZec23)-+uR)u3_21o1wWCLEYoYAsmdY|G`AHfq{_GjaI zQAg2+ESweN86(l8hR~Y;zS*I{fXo^Yypjy-;r|#2K!q~sB!X3**s-3Bj9D-n)h*a= z!{PMvI9Q8xpWKsbZ9!+mGTsksb~(-%zX~0*a$DfSj%l&PwX~d_Z8&2Ga}ojbRj}F< zmk4sG$?x3sJvp%D;DF7lB4?9M-QL-&ZOF-IS{;#2osOoq)$5mUqRVKc&!nd}CB5G_ znh5%PO0{3iqX19V%5_1EQ)#4LYf@L*k3&{N4L*@DJNwD$L;~(z9j&XC?)JMi$vgiq z64`e<sEe`vt5!VAs?3#-7R1Q!agN=xV>zYI=DE2LsmBtGMhqA}BU3vGu@c(<C^33f zlVq<$)$YzBT!#AWed%UA;Wgd!%g?_1z0J6dWLtgTnENJ5z?14sq0Vj2&4IJGtIL*> zGQaqOGA}WRt}_b7cD@i?1U*Df#e?Bx*92w(v=zhIo|=t}ymsH{b6W}J1N#xZot>z+ zQd+g$Jw1TP@9mHMQPgm<aA35kPWrmcHZC}Y@{HcW7%FDoXmzX&_gx!r&IkM+(%SCs z?tN+z?vpe3+qZTvUY8p(J<v(g>w~_(F7BHNd{-k6F;e|)0WvBKPqUv33vUQNoTyOh z1iPh-*;%+r_aFV=BQsk=LPJtS&i%O@N!J2NFY&5YWTDp$YbbnnwEn2AwSl&W#cap6 z4B1Uuq&d70R<>NVRDyTSZPAGP`mK&jfrSr7l_qIo%7?Fe;qn#Cxuh^SzYVs^e{&=B zy8TF9j73)J&FuTc+Cvvv=K+X{r)9bR=jHvaWBFNSA6w^CV9$l<xRce1o;m@im~Ia! zeGc_g%Ofx?cC`#qv{Dfl6Q@&pyml^YJriJcni(<gSnY2&GK*WjLrpzZ?7K$1uB(Q? zmiY=qgoLTw`guS-QfX<Tz8yJ1(ACxbg`M3UC;HrOVC2Jx44~d^%%Br;R<E?D#(FR^ zo+xNLfScnvSBQpv0@>J?8W~dD1CAr~$OzDsadUAUok3%)Vn#x8@1l-3mf%ai=4Mv1 zF=xAL1Jy>|)hE-xQ%is)Q60fcXm8oaI2!?gk@-W)<h`twg|(2y{GA0Y7B;qH=e-*s zyE;BDBBV=k{rW&#?Ewvqpl8d}urN1wg=JJvcM9)uYq76***MD}$E!U&Rm5?1zNkq# zZY7t8eEGMsGG1iQJtbRHyX@m?)zgXUrN`7uq*a#Pi5ag?LQ(u}$J*xRWgk^6dY|$0 z4>~=L27R9a!}<9I(4Gf6X|@Q#xAU(&JhFmo$KqjXyN<|g^GoCR>JKiLw_po*rV)<H zjw>9is`sCw8MI^?)-Q|FjjRV7`wnB(MdRs(U%jV{WxP)!sdd31;>qFS`lC(dtY~r0 z*ZTlps*);ZRQNJBs-}x=4pvJtw6~unAxs_rK|LLT(g)AY%*R#3@5HqV(Q|F*FTsRP zLlsDKJVZyMCNmj(3$IU|zd1G|4leZ_KL3vIC6Gh=tqm=B)|r=+MoIZdO$bSm7!hZ# zY;V7uiQL^hXlhkyJ#|>FCQ69Y9xju+bEX=&xpZAYCW`9I!;8nea&PM2%}5?=$Ze+3 z`eonTJ@RR;y(uT>j5__;xnMg|vg7&sV?cl}0M`t|yAhR4>Ht|WkYk({FZF17huQK{ zkYuYCA}4%6lQpfZ`7Is)q^h=hKvw>8{s~T4Dy}kwavhY4m>*zszw6`}EbVGwix_*G ztmXj<Xz%FweoJ`T%wCF{K1l;QPg4V1Q6vVl1M?NKZmCYK^W!;z@GoOK(>sE+s*p49 z9bj+h=^}@BWz5tQL|U|Q8uSfR%x}#tfuYOoM}rB`297RzPwpM8O~Aaa*L%CApC%+H zPi8>p05-R;7J*;@^<Y*DdDyGL%)^<n-ch?Z$noMOyr=#4Fk#h6-6}KllL~fdeSsct z=1|(5qX`uvXd)s?LH6`~O=aEI&Wa4Im1V?d(FwSYdAa!qPoyGy>HW^n6^dVNFN`1M z)pn^*&_|v=GnHhd)|SXV=CDhFJ52mpOM<PmlZw#i{FcyY^77^HuH?)+{nu#ykIr&t z0v>t_dJY_3^y4)ft@48SE6W2wNfLzD7y@WdI@Hgw>T~n~qx-t}=|lo;zoksbY3&ga zCBb!das{riRTc<&#y*~ET0G>WIziZk@&;zO3<=3Y`R(*XIg2B~BH!8K`=(ZA-h4j} zsz{paXlP6;%SH6P{TwmB?JxB(c5|Io3aH?pe+1O~0_^ca&sT^Y{#}84ckk{UwbJ%s zS2nGB&*=vfCL5L>uZykcmMKaYi0KGCW(|wKnAdq-z1Y#-gK@&;iVl+HDD@arNqj%s zLR)U#lpCzi+QBQd=P2vWyPffTwMw63eK_q(eNMnD+9~a+3ln2w#6BlE9^ND`z<W*y zJknrN%!x$qEZ<e@=i=J(6Pwic%w^;FJ%q&=*<)yCmT+ZWqaPx8ADCOycr9$~q_#FT zCJ5?lE=SpAWzV#0)$`zhBNv^4=gkdEOi7v`1|yd2s;b0u3^Fl8#P<x(-;J`XThZBh zr@mf<$r3H+?3DydX<9xrHNi-29r<XJw}SD@5&+(UyhVG_ho1#&N+(VmjhYn9Ck*y; zk8N0OFiJ|wa_&wpX?@a7=RkKKO<Dmg9Ua8OxpT_57gkoRjqR0JB3eeqM*qkjD03OT zezte@G*&~HepB$;wZr132C+%o<o?Num$z5Xs=Z7l)Ju>^;RP~Z--hk0)YR)ujhPj; zQwp~~#l@_zYX(Of4g8E0fuEUTZpy8Xm1SK4BpL^?i$9|cJU>6v@ss|r{bznYkCdXd zo+Trr{CY_|uYfl=C}A1wbor1gx%@?L2|9V+gL&o}sbUvEUSB673fc-_t$8qYiNhfM zxdPJNtJC{8(0_=83$dOg5)rLDPsdZDr{wd9ewVAOg4Bu)@HTOh2k-~zyQ^@3&KR{! z_{?x8wovzAHqQklV3Xn`mtK>W<`e>uGK3hfqeQL0n71!eZ)tFlw>(01;}1*;vbT|b zG?K7>VPU}$H?LC;CsG0n%|OInn$zUNIzOom_iKZ=JmxBCY9JP#UY-4%7z<9UIre8K zC7Qg_bPqH%R6#W~5eKMCk8dqc@a*;j;RkS5N!mF>#rFqkR^|0(rC^3ffo3a8lmb4- zA|ed@zvrZi!$#EX?lh~(h!U<!4kd8LM_vJAN6-&-x%S}%6?SfLv77lwoc%R+54I0R zvAdgFAoZ4%_%I(<<)|9qno<E!>co@-QRl@d&yzwFJPOMUq)^hiHO|2m9rR~D^#?RU zC2v>cSt3-Zgg?n2hAOJW=4Yu(Tbr0jEUkfQyOq_Oku0?)0A+_7L4YD;bx&_aqya2! zzNRzSU!q91?R`%VmM_jucGJ$AhF~YW`t@C^AcR(3`g(UZR4>mHeKBHONR!aC@JG%$ z+tG=aek4tB>)gP*ZO;I5qS$z~s1MZfZJYzyY#H@-%+JqvC&;%#<f3TB^~&vcvWn@~ zP+gLj-j7mpPL-tRE#D{iCj(?`0d>F{>;8Va*+L^lb(}P$Ig~Y}nu<7u?`WIdzxu?Q zqo4mzP8~Fd&1j~Ig%a}P!C`wTeQWQl=9b$VQ+iuks&BplmeT+aH*-rd@}<^kc`CR4 zQslbrmjbYvX_JI|a;Hgil7B_KB7(oXYFVnOL|Z)UsR{6|sfd66Zk1L;hzZQ0!Gq|! zxp+jA^YKYk(`$KVFYNDb#Vnchhvhe|$kJ^$=bh+7#8f2=(11^+l=KYS*O%6aA0nH@ zN#Y_J)Vn|?7rOGK>tf!LhcxHS#m{~XA&Hi7s_nH5GT`lenTEnH4*216X;wRyZ-t{A zCOU`h!DOG$Rux{uMY`+lw)WYFOSAlCVuB1c{lyI;UpkyvX!E^aS4P9<<IUB<^xNiv zsRqKdLT<@~Zvdzs%xYWPOdmZpXdb51f!G6flc1+3<lU`2qs{4J4cyVOlez}F_j4_; zdE-S#1PYY0V_NJDhlc?q2o){i%#v%Pm6S=~jV5Y2R0cXoYiFgig*7=~%a+o{h61tC zx{wc|+c|H>>*P!=8D;VsOAZcs__%s{IsFL~RovZ$=zIMrKPfYV9eBEjG<<$pV`n zfuksm;|iI}Xf1)5=L2cVA6mwmn1ch~2M>BCn>MyIMqSCtD%f3Jt%xQJ47?6-tDAEM zPe>$Nq+2{aO9~=XWV6=OS(x`kH$IMQ8)TZuCm-}{jB@mCle6ndy=VJYWbXlL+?OE5 z2UvQUr3BWMqdx`{DbmMf*=xVJMWqJI=+`;H2-ks+2iI4jS?%Dj9&R&KHUl(jdc4rK zHjq_#qyvdZm<NgZd`d9dg300g_-=@Kw6z6LdrM{kX%Z>bsDtx^2V`hZngs_lATV2% zfRNzHuip+>E!9Rr&Yi(a%te`jU+n!EvCYqdJ1QijGOF#pfzd{v2J4`v05O5MM{v*B zp;&(G6zp6JDGlbl6vf)^TZIE4QRi3$<&7It)oZx<7ZW6`3Sl7rcziUdIi`<|62(Z? zQ&~3wD-i~H|IuWs@l3SKYVWrfMs@*AePYLhdo|uh`;W}cm%bXEa2zCf&uRU3LalXK zkfqIn6XUUMp^3-%vN6awE-+YOGFE`?lKHL5L(y5FBG?f1kiGb*@f*UwA4JF>e>0-v z{Gfh2s%JQVQZk52&@m_jZM0T7@D*0joioG9;f%!98g~*48KlOfbS`aS%k415b~e)Z zESZb*i>gX6x-V%EFah-j?bXo3!WyQ~kll^OY=5WfIu7cw3F7FdDWHIN7^~;p-MXKy z3Urir)=4$h!MZyjlNEcSr9mg&B0*Z`Lvo<Bu8xkn8CSH?^w>I#7!22Ss^)ulyKKd2 zi$EF$y$v{n7sJ?YP#&05><ihJuMQPR%B?L0DnMP8BO`IL>vn5;!#3SP1-zoo^kPP+ z^i!wkw6x7>84)}@f^xZ6FCkt4s)<}iXL!b#vkn8j&(h*T1$0z|t?pDwgiK?9bIcUz ziBKHJ^nC2TBWZq+R%(^CiLVRWnCY@zMX%xJcDeQLinCQOwHM=ccJ2v1>tyt~8c6d5 z&4acVMi)O;hy?6|e(oLZey<ns)UPftvz^=phrvyyM=DLE)4=6*zSC&#Dk4fng=3;6 zVy($E2Xkkw!qHu{g96mMZvJKb(BXMm2>8vjv(?0n-=GXTd_~IhRSo{Y;-`IzNDJ9c zRbNC%o>eyc_d%)hIM6rHvY6hd^cvlER4dMP&YSPGsSiL1miG9am}ohz?9h-_i*yi( z6!dm=P;h0Tf@^IFybo|CZ`$D?2kR1Pv-)auPtd{w;Wnfdi+tp{XAqUy8mD2$vEG`B zl{9$7?$Z<x+gm$Qvjp$9?ujN%jR2-hUtohu)^pz&sOF$OT2SopuLcsz6^9t1_2fb{ z$odaU{SxG2rEVIkGo(NHUY7wn)i3YLpiv0Y53T18iJ6(cNvG!z*97b=H`OwSzGpHr zN4r>01x=*7rnoCU<QWIah|UbN%9o1rh?s5CMbggnXEK38GTEJG<_FUXvM!Ep>J5YM zqx}iEL`4I%(m$W(Ot;QCuG|VR35T#`mtHC4;Lx|fjtt0=R=A&#-(wBcOMWiKrNj0> z!(F!cHpIRRkTv<a?}fZ_(fSS?f8*^0*PCO*Mb^2tONwU=2-o=ehpbVnY4z7x#?3LJ zpTsdtW1Z;I@wj7abIT>Cs?XZ;Zw840QUkEUl0|QUw+f^-Iaw>c=8jTrZ{F!rA=t<P z6vT?zhZdTP&T0xLw9K#<eZ#}r4JU+B`y*8zLUviF!|CzX&YB*V1u1J*#Y@r=l!lN2 zqRK}WZNve#as}^<yGnvn(ZPoJ{I=&D#9kTscE51}eC)$J2QzQ0b&^IQ18ZaXDTolj z9?>eC7|$}s$Ct#<tFl~}S4`p6a%9J`vJ+nR)vT|4sI>=f0mwqZ&lP3JZ&@a`a!_V6 zne}zsaur3gzVPs_4~=w^l1)O}3KV&DOqc)Wu=1Zt`TCu|UH(lP{(lR;{_onvm%&0X zo+AFwyMe!Wwm_bZckMFJ{lA49{Lc^hpKs@Xt`j^Vy#L&O@c-fsIDG+b`-=+|*5GaM ghZ~nKaC|)HeR~rIQ+Cj_$HSA8Qhrq^@#e$-0tK>}a{vGU diff --git a/docs/img/ux13/settings-installer.png b/docs/img/ux13/settings-installer.png index 57258b8ccd7024c9177bebb6fb1c039b166594a4..43de13b96ecc95fc937e96f0caf3df57ed4ab7a6 100644 GIT binary patch literal 179047 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 Id*%Dz07!QVu>b%7 literal 179464 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%0Aj)6*4b^~nnG$+U)Z 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 &P#aC3u7#4J!=m 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 QICDl>UR|zO_Ic3102qLQ?*IS* diff --git a/docs/img/ux13/settings-simple-nl.png b/docs/img/ux13/settings-simple-nl.png new file mode 100644 index 0000000000000000000000000000000000000000..94e986d39dc93a90362ce61c230fa5d75713d539 GIT binary patch literal 113420 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 literal 0 HcmV?d00001 diff --git a/docs/img/ux13/settings-simple.png b/docs/img/ux13/settings-simple.png new file mode 100644 index 0000000000000000000000000000000000000000..3be66f48606b88ae03373f2cc540259aa9b5288f GIT binary patch literal 106723 zcmcG$WmsEXw>DY>S}0IKia#yx#R~z_mg4SCiWDg>!Gg53K=I<m9U9yng1fs1cY+2F ze2eG(_SwJAb)EB_efX1kt*p#7$C`84J?=q(l7b{YE;;VKd-w3Ar9P?LyZ3PO-aRbP z;|IVMzPeYB@7;TLPx{jbHP^)5d92Sb%_wjV1aw?n1Tx<dxx_9JwDP|)e)>waW0m4* z$5U+MuAyc-7Z;ZT6&IHPFGcs?P-~VUmB&}Njb6JBf(Y3o#KwZ⪻gtr@-v@?itvA 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�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 V?eK|d0Ny#HsjBz1M)_I9{{V>%8+QNz literal 0 HcmV?d00001 diff --git a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md index e5d16b3..34cb1ac 100644 --- a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md +++ b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md @@ -87,6 +87,14 @@ What UX-02 made authoritative stays authoritative: Configuration tab. Supervisor 2026.08.0's `AppOptions` accepted all 133 wizard blobs, 17 of them with time windows (`tools/ux13_wizard_blobs.py --supervisor`, run offline on 2026-09-28). +- P3: Settings, Simple draws the fields the table marks `simple`, with an + optional `note` under each (words in `settings.simple.note`), plus the + batteries' switches and modes. Those are store state set through the + existing `/action` values, not options, so the table places no key for + them. The Batteries screen's Now, Today and Why lines are built in + `homeview.py` from what the add-on knows this cycle; the plan per mode is + OPT-11 P3/P4, so until then Today says "Not planned yet" + (`test_batteries_screen.py`). ## 4. What this costs diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 4f36859..34318e9 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -515,7 +515,7 @@ below. ### Battery modes (`battery_modes_enabled`) -Off by default. Turn it on, restart the add-on, and the Batteries screen gives each battery two controls. They apply at once, with no restart. +Off by default. Turn it on, restart the add-on, and the Batteries screen (and Settings, Simple) gives each battery two controls. They apply at once, with no restart. - **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, but only for what the other batteries cannot cover. - **Mode.** *Solar first* charges from spare solar before the other batteries. *Leftover solar* charges from the solar they cannot take. Both cover the house at any hour. Charging from the grid in cheap hours, and selling, come in a later update. @@ -3245,12 +3245,28 @@ The page is in Dutch when your browser's language is Dutch, and in English otherwise. Status lines, alarms and the start checks' messages stay in English. Screenshots of each screen are in the add-on's repository, under -`docs/img/ux13/`. The battery-mode screens are not built yet, so there are no -screenshots of them. +`docs/img/ux13/`, including the Batteries screen and Settings, Simple. *For installers: regenerate the screenshots with `tools/ux13_screenshots.sh`, which serves the page from test fixtures.* +### The Batteries screen and Settings, Simple + +The **Batteries** tab has a card per battery: its level, and three lines. +**Now** says what it does, **Today** lists the blocks planned for it (price +trades, the monthly cycle, the peak limit), and **Why** says the reason. With +battery modes on, each card also has the On/Off switch and the mode list; both +apply at once. Charging in cheap hours and selling are greyed out until a later +update, and Today reads "Not planned yet" when nothing is planned for the +battery. + +An Off battery that the peak limit still needs says so, with the power it +gives: "Off, but gives 0.5 kW for the peak limit." + +**Settings** opens on the **Simple** view: the peak limit, the batteries' +switches and modes, and shadow mode, each marked "Applies right away" or +"Applies after a restart". **Installer** shows every setting. + ### Setup, for a new install The **Setup** tab walks an installer through six steps: the meter, the diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 01afa62..90d1943 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -20,6 +20,7 @@ from datetime import datetime, timedelta, timezone from . import arbitrage, messages, peakguard, uitext from .maintenance import CHARGE as M_CHARGE, DRAIN as M_DRAIN, HOLD as M_HOLD from .maintenance import IDLE as M_IDLE +from .packmode import LEFTOVER_SOLAR, SOLAR_FIRST from .price import Absence, Uncertainty, brussels from .static_tariff import static_plan from .tariff import BILLING_TZ @@ -284,6 +285,8 @@ def trade_runs(c, plan, verdict, day0, day1, now, shadow): continue hrs = (end - pt.start).total_seconds() / 3600.0 for i, inv in enumerate(c.inverters): + if _off(c, inv): + continue # OPT-11: an Off battery does not trade kwh = inv.max_w / 1000.0 * hrs cap = inv.capacity_kwh if cap: @@ -317,8 +320,8 @@ def maintenance_runs(c, day0, day1, now, shadow): waiting = [] for i, (inv, m) in enumerate(zip(c.inverters, c.maints)): cfg = m.cfg - if not cfg.enabled: - continue + if not cfg.enabled or _off(c, inv): + continue # OPT-11: no monthly cycle while it is off cap = inv.capacity_kwh if m.phase != M_IDLE: hours = _cycle_hours(m.phase, inv.soc, cap, cfg) @@ -390,12 +393,13 @@ def peak_run(c, day0, day1, now, shadow, limit_w): for i in range(len(c.inverters))] -def house_runs(n, day0, day1, now, shadow): - """"Follows the house" for the rest of the day, drawn under the others.""" +def house_runs(n, day0, day1, now, shadow, skip=()): + """"Follows the house" for the rest of the day, drawn under the others. + `skip`: the batteries that are switched off (OPT-11).""" return [_run(i, "house", max(now, day0), day1, day0, day1, run_house_what(shadow), run_house_why(shadow), run_house_amount()) - for i in range(n)] + for i in range(n) if i not in skip] def region_of(opts): @@ -429,7 +433,8 @@ def build_plan(c, now, shadow, running, held=False, settled=True): # The control cycle trades on the fresh plan only, so this does too. verdict, trade_why = trade_verdict(c, fresh) if running: - runs += house_runs(len(c.inverters), day0, day1, now, shadow) + off = {i for i, inv in enumerate(c.inverters) if _off(c, inv)} + runs += house_runs(len(c.inverters), day0, day1, now, shadow, off) if verdict is not None: trade, later, no_trade = trade_runs(c, fresh, verdict, day0, day1, now, shadow) @@ -507,16 +512,56 @@ def at_zero(inv) -> bool: return inv.last_write is not None and abs(inv.last_write) < 1.0 +def _off(c, inv) -> bool: + """OPT-11: is this battery switched off? Only with battery modes on.""" + return bool(getattr(c, "modes_on", False)) and not c.pack_mode(inv).use + + +def refusing(c, inv) -> int: + """SAFETY-52/73: the direction this battery refuses (+1 give, -1 charge, + 0 none). Per inverter at two or more, the site's own at one.""" + if len(c.inverters) > 1: + return int(getattr(inv, "refused", 0) or 0) + return int(getattr(c, "batt_refused", 0) or 0) + + +def peak_engaged(c) -> bool: + """The peak guard is asking the batteries for power this cycle.""" + pg = getattr(c, "peak_guard", None) + return bool(pg is not None and pg.engaged) + + def battery_rows(c, shadow, running, held=False): shares = {} alloc = getattr(c, "allocation", None) if shadow and alloc is not None and getattr(alloc, "shares", None): shares = dict(alloc.shares) + modes_on = bool(getattr(c, "modes_on", False)) + pms = {inv.name: c.pack_mode(inv) for inv in c.inverters} \ + if modes_on else {} + peak = peak_engaged(c) rows = [] for i, inv in enumerate(c.inverters): m = c.maints[i] if i < len(c.maints) else None phase = m.phase if m is not None else M_IDLE cap = inv.capacity_kwh + pm = pms.get(inv.name) + off = pm is not None and not pm.use + # UX-13 P3: does a Solar first battery that is on come before this one? + sf_ahead = any(o.use and o.mode == SOLAR_FIRST + for n, o in pms.items() if n != inv.name) + # ...and does another battery refuse to give power, so this one + # carries its share (SAFETY-73)? + other = next((o.name for o in c.inverters if o is not inv + and refusing(c, o) > 0 and not _off(c, o)), None) + why = battery_why( + modes_on=modes_on, mode=None if pm is None else pm.mode, off=off, + reading=inv.soc is not None and inv.batt is not None, + phase=phase, shadow=shadow, running=running, held=held, + refused=refusing(c, inv), peak=peak, + moving=flow(inv.batt) in ("giving", "charging"), + giving=flow(inv.batt) == "giving", other_refuses=other, + sf_ahead=sf_ahead) rows.append({ "name": inv.name, "level_pct": None if inv.soc is None else float(inv.soc), @@ -530,21 +575,79 @@ def battery_rows(c, shadow, running, held=False): "now": battery_now(inv.soc, inv.batt, phase=phase, shadow=shadow, running=running, held=held, would_w=shares.get(inv.name), - settled=at_zero(inv)), - # Per-battery reasons arrive with the plan (OPT-11 P3/P4). - "why": None, + settled=at_zero(inv), off=off, peak=peak), + # UX-13 P3: why it does what "now" says, from what the add-on + # knows this cycle. Price and forecast reasons are OPT-11 P3/P4. + "why_key": why, + "why": why_words(why, name=other), }) - if getattr(c, "modes_on", False): + if modes_on: # OPT-11 P1: the battery's switch and mode, for the Batteries # screen. Only with battery modes on, so the page is unchanged - # without them. UX-13 P3 builds the real screen on these keys. - pm = c.pack_mode(inv) + # without them. rows[-1].update({"use": pm.use, "mode_key": pm.key, "mode_choice": pm.mode, "mode": mode_word(pm.key)}) return rows +def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, + held, refused, peak, moving, sf_ahead, giving=False, + other_refuses=None) -> str: + """The key of one battery's "why" line (`home_words.why`), most urgent + first. Pure, so every branch is tested without a controller.""" + if not reading: + return "no_reading" + if held: + return "held" + if not running: + return "stopped" + if shadow: + return "shadow" + if phase != M_IDLE: + return "cycle_mode" if modes_on else "cycle" + if off: + # Off gives way to the peak limit only (OPT-11 design section 2). + return "off_peak" if peak and moving else "off" + if refused: + return "refuses_give" if refused > 0 else "refuses_charge" + if peak: + return "peak" + if giving and other_refuses: + return "other_refuses" + if not modes_on: + return "modes_off" + if giving: + return "covers_house" # both modes cover the house until P3 + if mode == LEFTOVER_SOLAR: + return "leftover" if sf_ahead else "leftover_alone" + return "solar_first" + + +def attach_today(rows, runs, *, modes_on, running=True, held=False, + shadow=False) -> None: + """UX-13 P3: each battery's runs today from the plan (the same blocks as + Home's chart), or one line saying there are none. With battery modes on + and no run, the mode's own plan is OPT-11 P3/P4, so it says so.""" + for i, row in enumerate(rows): + mine = [r for r in runs if r["battery"] == i and r["kind"] != "house"] + row["today"] = [{"from": r["from"], "to": r["to"], "kind": r["kind"], + "what": r["what"]} for r in mine] + if mine: + row["today_line"] = "" + elif held: + row["today_line"] = today_words("held") + elif not running: + row["today_line"] = today_words("stopped") + elif row.get("use") is False: + row["today_line"] = today_words("off") + elif modes_on: + row["today_line"] = today_words("not_planned") + else: + row["today_line"] = today_words("house_would" if shadow + else "house") + + # Row id -> the DOCS.md heading under Notifications, where one exists. ATTN_DOCS = { "meter_frozen": messages.T_METER_FROZEN, @@ -640,6 +743,11 @@ def _build(c, *, level, checks, now): running = (bool(c.auto) or shadow) and not held settled = all(at_zero(inv) for inv in c.inverters) ctl = next((r for r in checks if r.get("id") == "controller"), None) + rows = battery_rows(c, shadow, running, held) + plan = build_plan(c, now, shadow, running, held=held, settled=settled) + attach_today(rows, plan["runs"], + modes_on=bool(getattr(c, "modes_on", False)), + running=running, held=held, shadow=shadow) return { "state": {"kind": kind, "pill": pill(kind), "ran": ctl.get("text", "") if ctl else "", @@ -647,9 +755,9 @@ def _build(c, *, level, checks, now): "now": now_block(grid_w=c.grid, pv_w=c.pv_w, batt_w=c.site_batt_w, has_solar=bool(c.pv_roster), shadow=shadow, settled=settled), - "batteries": battery_rows(c, shadow, running, held), - "plan": build_plan(c, now, shadow, running, held=held, - settled=settled), + "batteries": rows, + "plan": plan, + "modes_on": bool(getattr(c, "modes_on", False)), "attention": ([{"severity": INFO, "id": "shadow", "title": attn_shadow(), "body": attn_shadow_body(), "docs": None}] if shadow else []) + attention(checks), @@ -811,7 +919,7 @@ def tile_batt(batt_w, shadow, settled=True) -> str: def battery_now(soc, batt_w, *, phase, shadow, running, held=False, - would_w=None, settled=True) -> str: + would_w=None, settled=True, off=False, peak=False) -> str: if soc is None or batt_w is None: return _t("now.no_reading") zero = _zero(settled) @@ -828,6 +936,14 @@ def battery_now(soc, batt_w, *, phase, shadow, running, held=False, return _t("now." + {M_DRAIN: "cycle_drain", M_CHARGE: "cycle_charge", M_HOLD: "cycle_hold"}.get(phase, "cycle")) st = flow(batt_w) + if off: + # OPT-11: an Off battery is asked for 0 W, but the peak limit may + # still need it. Say which, and never "0 W" beside a power figure. + if st == "resting": + return _t("now.off_resting") + if st == "giving" and peak: + return _t("now.off_peak", kw=_kw(batt_w)) + return _t("now.off_going", kw=_kw(batt_w)) if st == "giving": return _t("now.giving", kw=_kw(batt_w)) if st == "charging": @@ -835,6 +951,17 @@ def battery_now(soc, batt_w, *, phase, shadow, running, held=False, return _t("now.resting") +def why_words(key, name=None) -> str: + """One battery's "why" line (UX-13 P3), from `battery_why()`'s key. + `name`: the battery that refuses, for `other_refuses`.""" + return _t("why." + key, name=name or "") + + +def today_words(key) -> str: + """One battery's "today" line when the plan has no run for it.""" + return _t("today." + key) + + def plan_head(key, shadow, settled=True) -> str: if key == "held": return _t("head.held" if settled else "head.held_going") @@ -1039,6 +1166,14 @@ def _samples() -> list: ("plan", line_region("flanders", 2026)), ("plan", line_region("own", None)), ("plan", line_peak_not_covered())] + for off in (False, True): + for peak in (False, True): + for w in (2500, -2500, 0, 500): + out.append(("plan", battery_now(62, w, phase=M_IDLE, + shadow=False, running=True, + off=off, peak=peak))) + out += [("plan", why_words(k, name="Battery A")) for k in words["why"]] + out += [("plan", today_words(k)) for k in words["today"]] out += [("plan", line_no_trade(k)) for k in ("not_covered", "no_prices", "peak", "not_firm", "not_worth", "no_level")] diff --git a/goodwe_controller/app/static/app.css b/goodwe_controller/app/static/app.css index 6e4d52f..db67144 100644 --- a/goodwe_controller/app/static/app.css +++ b/goodwe_controller/app/static/app.css @@ -228,3 +228,19 @@ input.txt.time{width:5.5em;text-align:center;font-variant-numeric:tabular-nums} .sev.bad{background:var(--bad-bg);color:var(--bad)} .sev.warn{background:var(--warn-bg);color:var(--warn)} .checklist li{display:flex;gap:8px;align-items:flex-start;overflow-wrap:anywhere} .kettle .row{margin-top:8px} +/* UX-13 P3: the Batteries screen and the Simple settings view */ +.bcard .hd{display:flex;align-items:center;gap:10px;margin-bottom:10px} +.bcard .name{font-weight:700;font-size:16px} +.bcard .modebox .lbl{display:block;margin-bottom:4px} +.bcard .modebox .help{font-size:13px;color:var(--muted);margin-top:4px} +.bcard.off .modebox{opacity:.6} +.bcard .kv dd{overflow-wrap:anywhere} +.switch:disabled{opacity:.45;cursor:not-allowed} +select.sel:disabled{opacity:.6} +.simple .card>.row{margin-bottom:4px} +.vhide{display:none!important} +.simple .card>.f{border-top:0;padding-top:0} +.simple .f>.head{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap} +.simple .card .lbl{font-weight:600;font-size:15px} +.simple .inv .hd{border-bottom:0} +.simple .inv .f{border-top:0;padding-top:0} diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 5606652..2728bb5 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -78,10 +78,12 @@ if (!r.ok) throw new Error("action " + r.status); return r.json(); } - async function refresh() { + // `force`: redraw the battery cards even under a focused mode list, after + // the person used it (P3). + async function refresh(force) { if (busy) return; busy = true; - try { S = await getStatus(); render(); } + try { S = await getStatus(); render(force === true); } catch (e) { offline(); } finally { busy = false; } } @@ -104,7 +106,7 @@ $("#pill").replaceChildren(h("span", { class: "dot" + dot, "aria-hidden": "true" }), h("span", {}, words)); } - function render() { + function render(force) { renderPill(); const structured = S.now && S.plan && !S.home_error; // UX-15: setup-only mode commands nothing and has no control to offer. @@ -114,7 +116,8 @@ if (structured) { renderNow(); renderPlan(); renderPeak(); renderAttention(); } renderControl(structured, setup); renderDetails(!structured && !setup); - renderBatteries(); + renderBatteries(force); + document.dispatchEvent(new CustomEvent("ux13:status")); } /* ---------------- Home: now ---------------- */ @@ -308,50 +311,112 @@ if (open) $("#c-details").open = true; } - /* ---------------- Batteries (placeholder until UX-13 P3) ---------------- */ - // OPT-11 P1: with battery modes on, each card gets an On/Off switch and a - // mode choice (`mode_key` in /status). UX-13 P3 replaces these cards. + /* ---------------- Batteries (UX-13 P3) ---------------- */ + // One card per battery. With battery modes on (`mode_key` in /status) each + // card has an On/Off switch and a mode list, sent as `pack_use` and + // `pack_mode` through /action (OPT-11 P1). Selling and cheap-hours charging + // are shown greyed out until OPT-11 P3. The Now, Today and Why lines are + // homeview.py's sentences. The Simple settings view draws the same switch + // and list into its own card (simpleHost). const MODES = ["solar_first", "leftover_solar"]; + const say = (text, vars) => Object.keys(vars).reduce((x, k) => x.replace("{" + k + "}", vars[k]), text); let packBusy = false; - async function packAct(what, unit, value) { + let simpleHost = null; + async function packAct(what, b, value) { if (packBusy) return; packBusy = true; try { const r = await fetch("action", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ action: what, unit: unit, value: value }) }); + body: JSON.stringify({ action: what, unit: b.name, value: value }) }); const j = await r.json().catch(() => ({})); - toast(r.ok ? t("toast.done") : (j.error || t("toast.failed"))); + if (!r.ok) toast(j.error || t("toast.failed")); + else if (what === "pack_use") toast(say(value ? t("batteries.toast.on") : t("batteries.toast.off"), { name: b.name })); + else toast(say(t("batteries.toast.mode"), { name: b.name, mode: t("batteries.choice." + value + ".name") })); } catch (e) { toast(t("toast.failed")); } finally { packBusy = false; } - refresh(); + await refresh(true); } - function modeControls(b) { - const sw = h("button", { class: "btn" + (b.use ? " primary" : ""), type: "button", role: "switch", - "aria-checked": String(b.use), "aria-label": b.name + ": " + t("batteries.use"), - onclick: () => packAct("pack_use", b.name, !b.use) }, - b.use ? t("batteries.on") : t("batteries.off")); - const sel = h("select", { class: "sel", "aria-label": b.name + ": " + t("batteries.mode"), disabled: !b.use, - onchange: (e) => packAct("pack_mode", b.name, e.target.value) }, - ...MODES.map((k) => h("option", { value: k, selected: b.mode_choice === k }, t("batteries.choice." + k + ".name")))); - return [h("div", { class: "row spread", style: "margin-top:8px" }, h("span", { class: "small" }, t("batteries.use")), sw), - h("div", { class: "row spread", style: "margin-top:8px" }, h("span", { class: "small" }, t("batteries.mode")), sel), - h("p", { class: "tiny muted", style: "margin:6px 0 0" }, t("batteries.choice." + b.mode_key + ".description"))]; + function onSwitch(b, i, where, lid) { + const sw = h("button", { type: "button", class: "switch", role: "switch", id: "bsw-" + where + i, + "aria-checked": String(b.use), "aria-labelledby": lid, + onclick: () => packAct("pack_use", b, !b.use) }); + return h("span", { class: "swrap" }, sw, h("span", { class: "swtext", "aria-hidden": "true" }, b.use ? t("batteries.on") : t("batteries.off"))); } - function renderBatteries() { - if (!S.batteries) { $("#bcards").replaceChildren(); return; } - // Do not rebuild a card under an open mode list or a request in flight. - if (packBusy || ($("#bcards").contains(document.activeElement) && document.activeElement.tagName === "SELECT")) return; - const modes = S.batteries.some((b) => b.mode_key != null); - $("#batt-desc").textContent = t(modes ? "batteries.with_modes.description" : "batteries.description"); - $("#bcards").replaceChildren(...S.batteries.map((b) => h("div", { class: "card" }, - h("div", { class: "row spread" }, h("strong", {}, b.name), h("span", { class: "small muted" }, b.capacity_kwh ? b.capacity_kwh + " kWh" : "")), + function modeSelect(b, i, where, lid) { + return h("select", { class: "sel", id: "bsel-" + where + i, "aria-labelledby": lid, disabled: !b.use, + onchange: (e) => packAct("pack_mode", b, e.target.value) }, + ...MODES.map((k) => h("option", { value: k, selected: b.mode_choice === k }, t("batteries.choice." + k + ".name"))), + h("option", { value: "", disabled: true }, t("batteries.later"))); + } + function sellRow(i, where) { + const lid = "bsl-" + where + i; + return h("div", { class: "f inline" }, + h("div", {}, h("div", { class: "lbl", id: lid }, t("batteries.sell.name")), h("div", { class: "help" }, t("batteries.sell.description"))), + h("div", { class: "ctl" }, h("button", { type: "button", class: "switch", role: "switch", "aria-checked": "false", + "aria-labelledby": lid, disabled: true }))); + } + function todayLines(b) { + if (!b.today || !b.today.length) return b.today_line || "–"; + return b.today.map((r) => h("div", {}, r.from + " " + t("plan.time_to") + " " + r.to + ": " + r.what)); + } + function batteryCard(b, i) { + const modes = b.mode_key != null; + const lid = "bname-" + i; + const lvl = b.level_pct == null ? "–" : Math.round(b.level_pct) + " %"; + const stored = b.stored_kwh != null ? " · " + dec(b.stored_kwh.toFixed(1)) + " kWh " + t("batteries.stored").toLowerCase() : ""; + return h("div", { class: "card bcard" + (modes && !b.use ? " off" : "") }, + h("div", { class: "hd" }, + h("div", { class: "grow" }, h("div", { class: "name", id: lid }, b.name), + h("div", { class: "tiny muted" }, b.capacity_kwh ? dec(Number(b.capacity_kwh).toFixed(1)) + " kWh" : "")), + modes ? onSwitch(b, i, "c", lid) : null), + modes ? h("div", { class: "modebox" }, + h("label", { class: "lbl small", for: "bsel-c" + i }, t("batteries.mode")), + modeSelect(b, i, "c", null), + h("div", { class: "help" }, t("batteries.choice." + b.mode_key + ".description")), + sellRow(i, "c")) : null, levelBar(b.level_pct, b.name), h("dl", { class: "kv" }, - h("dt", {}, t("batteries.level")), h("dd", {}, b.level_pct == null ? "–" : Math.round(b.level_pct) + " %"), - b.stored_kwh != null ? [h("dt", {}, t("batteries.stored")), h("dd", {}, dec(b.stored_kwh.toFixed(1)) + " kWh")] : null, + h("dt", {}, t("batteries.level")), h("dd", {}, lvl + stored), h("dt", {}, t("batteries.now")), h("dd", {}, b.now), - b.mode_key == null ? [h("dt", {}, t("batteries.mode")), h("dd", {}, b.mode)] : null), - b.mode_key != null ? modeControls(b) : null))); + h("dt", {}, t("batteries.today")), h("dd", {}, todayLines(b)), + h("dt", {}, t("batteries.why")), h("dd", { class: "muted" }, b.why || "–"))); + } + function simpleRow(b, i) { + const lid = "bsname-" + i; + return h("div", { class: "inv" }, + h("div", { class: "hd" }, h("span", { class: "grow", id: lid }, b.name), onSwitch(b, i, "s", lid)), + h("div", { class: "f" }, h("label", { class: "lbl", for: "bsel-s" + i }, t("batteries.mode")), + h("div", { class: "ctl" }, modeSelect(b, i, "s", null)), + h("div", { class: "help" }, b.now + " " + (b.why || "")))); + } + // Rebuild without losing the focused control, and never under an open list + // or a request in flight. + function keepFocus(fn) { + const id = document.activeElement && document.activeElement.id; + fn(); + if (id && /^bs(w|el)-/.test(id)) { const e = document.getElementById(id); if (e) e.focus(); } + } + // The modes-off card's button opens Settings on the Installer view, where + // the "Battery modes" switch is (settings.js sets window.UX13.settingsView). + $("#batt-off a").addEventListener("click", () => { if (window.UX13.settingsView) window.UX13.settingsView("installer"); }); + function renderBatteries(force) { + if (!S || !S.batteries) { $("#bcards").replaceChildren(); return; } + const a = document.activeElement; + if (!force && (packBusy || (a && a.tagName === "SELECT" && /^bsel-/.test(a.id)))) return; + const modes = S.modes_on === true || S.batteries.some((b) => b.mode_key != null); + $("#batt-off").hidden = modes; + $("#batt-how").hidden = !modes; + const docs = $("#batt-docs"); + if (S.control && S.control.docs_url) { docs.href = S.control.docs_url; docs.hidden = false; } else docs.hidden = true; + if (S.state && ["shadow", "stopped", "alarm"].includes(S.state.kind)) banner($("#batt-banner"), S.level, S.state.pill, S.state.sub, S.level === "bad" ? "alert" : null); + else $("#batt-banner").replaceChildren(); + keepFocus(() => { + $("#bcards").replaceChildren(...S.batteries.map(batteryCard)); + if (simpleHost && simpleHost.isConnected) { + simpleHost.replaceChildren(...(modes ? S.batteries.map(simpleRow) + : [h("p", { class: "small muted", style: "margin:4px 0" }, t("batteries.modes_off.name") + ". " + t("batteries.description"))])); + } + }); } /* ---------------- control buttons ---------------- */ @@ -385,7 +450,10 @@ // Shared with settings.js, which loads after this file. // `first`: the page opened with no route, so settings.js may open the setup // wizard on a new install (UX-13 P4). - window.UX13 = { h, ask, toast, t, words: WORDS, lang: LANG, maint: (what) => ask(what, () => simple(what)), first: !location.hash }; + window.UX13 = { h, ask, toast, t, words: WORDS, lang: LANG, maint: (what) => ask(what, () => simple(what)), first: !location.hash, + // P3: the Simple settings view's battery card, drawn from /status. + batteries: (host) => { simpleHost = host; if (S) renderBatteries(); refresh(); }, + status: () => S, kw }; /* ---------------- tabs: hash routes, arrow keys ---------------- */ const TABS = [...document.querySelectorAll(".tab")]; diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html index 7518ac8..a915a09 100644 --- a/goodwe_controller/app/static/index.html +++ b/goodwe_controller/app/static/index.html @@ -94,11 +94,23 @@ </section> <section class="screen" id="s-batt" role="tabpanel" aria-labelledby="t-batt" hidden> - <div id="bcards"></div> - <div class="card"> - <p class="small muted" style="margin:0 0 10px" id="batt-desc" data-t="batteries.description"></p> + <div id="batt-banner"></div> + <div class="card" id="batt-off" hidden> + <h2 data-t="batteries.modes_off.name"></h2> + <p class="small muted" style="margin:0 0 10px" data-t="batteries.description"></p> <a class="btn" href="#settings" data-t="batteries.settings"></a> </div> + <div id="bcards"></div> + <details class="grp" id="batt-how" hidden> + <summary><span class="grow"><strong data-t="batteries.how.name"></strong><span class="small muted gdesc" data-t="batteries.how.description"></span></span><span class="chev" aria-hidden="true">›</span></summary> + <div class="body small"> + <p data-t="batteries.how.solar_first.description"></p> + <p data-t="batteries.how.leftover_solar.description"></p> + <p data-t="batteries.how.off.description"></p> + <p class="muted" data-t="batteries.how.rules.description"></p> + <p><a id="batt-docs" hidden target="_top" rel="noopener" data-t="control.docs"></a></p> + </div> + </details> </section> <section class="screen" id="s-set" role="tabpanel" aria-labelledby="t-set" hidden> @@ -106,8 +118,15 @@ <h2 style="margin:0" data-s="name"></h2> <a class="small" href="config" id="set-classic" data-s="classic"></a> </div> - <p class="small muted" style="margin:0 0 10px" data-s="description"></p> + <div class="row" style="margin-bottom:8px"> + <div class="seg" role="radiogroup" id="set-view" data-s-label="view.name"> + <button type="button" role="radio" aria-checked="true" data-v="simple" data-s="view.simple"></button> + <button type="button" role="radio" aria-checked="false" data-v="installer" tabindex="-1" data-s="view.installer"></button> + </div> + <span class="tiny muted grow" id="set-desc"></span> + </div> <div id="set-banner" aria-live="polite"></div> + <div id="simple" class="simple" hidden></div> <div id="set-body"> <input class="search" id="set-search" type="search" autocomplete="off" spellcheck="false" data-s-ph="search.description" data-s-label="search.name"> <div class="card" id="set-other" hidden><h2 data-s="other"></h2><ul class="plain small" id="set-other-list"></ul></div> diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index ba3164a..3503133 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -32,6 +32,10 @@ let FILLED = {}; // field key -> the preset field that fills it let view = null; // "settings" or "setup": the tab drawing V let STEPS = {}; // wizard step -> refusals that block it + // P3: "simple" (the default, for home owners) or "installer". Remembered in + // this browser only; a blocked storage just means Simple each time. + let mode = "simple"; + try { if (localStorage.getItem("ux13.settings.view") === "installer") mode = "installer"; } catch (e) { /* no storage */ } let uid = 0; const ROWS = []; const OPEN = new Set(); @@ -337,7 +341,7 @@ function fieldRow(f, card, gid) { if (f.control === "inverter_list") return cardList(f, gid); const lid = "sf" + (++uid); - const keys = keyText(f, card); + const keys = gid === "simple" ? "" : keyText(f, card); // Simple shows no keys const msg = h("div", { class: "msgs" }); const make = CONTROLS[f.control] || text; const row = h("div", { class: "f" + (f.control === "toggle" ? " inline" : ""), "data-key": f.key, "data-card": card }, @@ -421,10 +425,79 @@ d.append(body); host.append(d); } + renderSimple(); paint(); window.scrollTo(0, y); } + /* ---------------- Settings, Simple (P3) ---------------- */ + // The fields the layout marks `simple`, each in its own card with when it + // applies, and the batteries' switches and modes (runtime state, applied at + // once) drawn by app.js from /status. The Installer rows stay built but + // hidden, so the save bar counts every unsaved change in either view. + const chip = (applies) => h("span", { class: "chip " + (applies === "now" ? "now" : "rs") }, ROOT.applies[applies].name); + // A note with {kw} is filled from /status (app.js sends ux13:status). + function fillNotes() { + const st = window.UX13.status(); + const mp = st && st.month_peak; + document.querySelectorAll("#simple [data-kw-note]").forEach((e) => { + const ok = mp && mp.peak_w != null; + e.hidden = !ok; + e.textContent = ok ? e.dataset.kwNote.replace("{kw}", window.UX13.kw(mp.peak_w) + " kW") : ""; + }); + } + document.addEventListener("ux13:status", fillNotes); + function simpleField(f) { + const row = fieldRow(f, null, "simple"); + row.querySelector(".head").append(chip(f.applies)); + const n = f.note && W.simple.note[f.note]; + if (n && n.description.includes("{kw}")) { + row.append(h("div", { class: "small muted", "data-kw-note": n.description, hidden: true })); + } else if (n) { + // A plain note replaces the option's installer help on this view. + const help = row.querySelector(".help"); + if (help) help.textContent = n.description; + } + return h("div", { class: "card" }, row); + } + function renderSimple() { + const host = $("#simple"); + host.replaceChildren(); + if (mode !== "simple") return; + const cards = allFields().filter((f) => f.simple).map(simpleField); + const batts = h("div", {}); + cards.splice(Math.min(1, cards.length), 0, h("div", { class: "card" }, + h("div", { class: "row spread" }, h("div", { class: "lbl" }, W.simple.batteries.name), chip("now")), batts)); + host.append(...cards, h("p", { class: "small muted", style: "margin:4px 2px" }, W.simple.more.description + " ", + h("button", { type: "button", class: "btn link", onclick: () => setMode("installer", true) }, W.simple.installer))); + window.UX13.batteries(batts); + fillNotes(); + } + function setMode(v, redraw) { + mode = v; + try { localStorage.setItem("ux13.settings.view", v); } catch (e) { /* no storage */ } + document.querySelectorAll("#set-view [role=radio]").forEach((b) => { + const on = b.dataset.v === v; + b.setAttribute("aria-checked", String(on)); b.tabIndex = on ? 0 : -1; + }); + $("#set-desc").textContent = v === "simple" ? W.simple.description : W.description; + $("#simple").hidden = v !== "simple"; + ["#set-search", "#groups", "#set-nomatch"].forEach((id) => { $(id).classList.toggle("vhide", v === "simple"); }); + if (redraw && M && view === "settings") render(); + } + document.querySelectorAll("#set-view [role=radio]").forEach((b, i, all) => { + b.addEventListener("click", () => setMode(b.dataset.v, true)); + b.addEventListener("keydown", (e) => { + const d = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[e.key]; + if (!d) return; + e.preventDefault(); + const j = all[(i + d + all.length) % all.length]; + setMode(j.dataset.v, true); j.focus(); + }); + }); + setMode(mode, false); + window.UX13.settingsView = (v) => setMode(v, true); + /* ---------------- messages, visibility, search, badges ---------------- */ const ICON = { bad: "×", warn: "!", info: "i" }; const RANK = { bad: 0, warn: 1, info: 2 }; @@ -434,11 +507,13 @@ return m.card == null ? r.card === 0 : m.card === r.card; } function paint() { - const q = view === "setup" ? "" : $("#set-search").value.trim().toLowerCase(); + const q = view === "setup" || mode === "simple" ? "" : $("#set-search").value.trim().toLowerCase(); + // A message counts as shown only beside a row of the view on screen. + const onScreen = (r) => view === "setup" || (mode === "simple") === (r.gid === "simple"); const placed = new Set(); for (const r of ROWS) { r.visible = visible(r.f); - const msgs = MSG.filter((m, i) => { const hit = mine(r, m); if (hit && r.visible) placed.add(i); return hit; }) + const msgs = MSG.filter((m, i) => { const hit = mine(r, m); if (hit && r.visible && onScreen(r)) placed.add(i); return hit; }) .sort((a, z) => RANK[a.tier] - RANK[z.tier]); r.tiers = new Set(msgs.map((m) => m.tier)); r.msg.replaceChildren(...msgs.map((m) => h("div", { class: "msg " + m.tier }, @@ -562,7 +637,9 @@ validate(); } function firstBad() { - const r = ROWS.find((x) => x.tiers && x.tiers.has("bad") && x.visible); + if (view === "settings" && mode === "simple" && !ROWS.some((x) => x.gid === "simple" && x.tiers && x.tiers.has("bad") && x.visible) + && ROWS.some((x) => x.tiers && x.tiers.has("bad") && x.visible)) setMode("installer", true); + const r = ROWS.find((x) => x.tiers && x.tiers.has("bad") && x.visible && (view !== "settings" || (mode === "simple") === (x.gid === "simple"))); if (!r) { if (!$("#set-other").hidden) $("#set-other").scrollIntoView({ block: "center" }); return; } for (let p = r.el.parentElement; p; p = p.parentElement) if (p.tagName === "DETAILS") p.open = true; r.el.scrollIntoView({ block: "center" }); diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 4b36fe2..61b9fbf 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -84,13 +84,22 @@ "offline": {"name": "Cannot reach the add-on", "description": "The page tries again every 3 seconds."}, "setup_only": {"name": "Setup: nothing is controlled yet", "description": "Nothing is sent to any inverter until setup is saved and the add-on restarts.", "control": "Control starts after setup.", "open": "Open Setup"}, "batteries": {"name": "Batteries", "description": "To choose a mode for each battery, turn on battery modes in the settings.", "level": "Level", "now": "Now", "stored": "Stored", "mode": "Mode", "settings": "Change inverter settings", - "with_modes": {"description": "Each battery follows its mode, after the peak limit and safety stops."}, - "use": "Use this battery", "on": "On", "off": "Off", + "on": "On", "off": "Off", "choice": { "solar_first": {"name": "Solar first", "description": "Charges from solar before the other batteries and covers the house."}, "leftover_solar": {"name": "Leftover solar", "description": "Charges from solar the other batteries cannot take, and covers the house."}, - "off": {"name": "Off", "description": "The add-on asks this battery for 0 W, unless the peak limit needs it."} - }}, + "off": {"name": "Off", "description": "Rests, and helps only when the peak limit needs it."} + }, + "later": "Cheap hours only, coming later", + "today": "Today", "why": "Why", + "sell": {"name": "Sell in expensive hours", "description": "Selling comes in a later update."}, + "modes_off": {"name": "Battery modes are off"}, + "how": {"name": "How the modes work", "description": "Which battery gets solar first, and when each gives power.", + "solar_first": {"description": "Solar first gets spare solar before the other batteries, and covers the house at any hour."}, + "leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, and also covers the house."}, + "off": {"description": "Off rests the battery and starts no monthly cycle, but the peak limit may still use it."}, + "rules": {"description": "The peak limit and the safety stops always come first, and charging from the grid and selling come later."}}, + "toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}."}}, "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, "choices_later": { @@ -107,7 +116,13 @@ }, "settings": { "name": "Settings", - "description": "Every setting, grouped by task, and the simple view follows in a later update.", + "description": "Every setting, grouped by task.", + "view": {"name": "Settings view", "simple": "Simple", "installer": "Installer"}, + "simple": {"description": "The choices a home owner makes.", + "note": {"month_peak": {"description": "This month's peak so far: {kw}."}, "shadow": {"description": "Use Always on while you test a new installation."}}, + "batteries": {"name": "Batteries"}, + "more": {"description": "Looking for the meter, inverters or prices?"}, + "installer": "Open the installer view"}, "classic": "Classic settings", "search": {"name": "Find a setting", "description": "Find a setting, for example peak or meter."}, "no_match": {"description": "No setting matches your search."}, @@ -223,7 +238,6 @@ "again": "Check again", "blocked": {"description": "Fix the items marked in red, then check again."} }, - "shadow": {"name": "Start in shadow mode", "description": "Recommended, because every inverter then stays at 0 W until you turn shadow mode off under Settings."}, "dialog": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and shadow mode keeps them at 0 W after that.", "yes": "Save and restart"}, "dialog_live": {"name": "Save and restart?", "description": "Every inverter is set to 0 W while the add-on restarts, and then the new settings apply.", "yes": "Save and restart"}, "dialog_setup": {"name": "Save and restart?", "description": "The add-on restarts with these settings, and shadow mode keeps every inverter at 0 W.", "yes": "Save and restart"}, @@ -290,7 +304,37 @@ "cycle": "Monthly cycle under way.", "giving": "Giving {kw} now.", "charging": "Charging {kw} now.", - "resting": "Resting now." + "resting": "Resting now.", + "off_resting": "Off. Resting now.", + "off_peak": "Off, but gives {kw} for the peak limit.", + "off_going": "Off. Still at {kw}, going to 0 W." + }, + "why": { + "no_reading": "No reading, so the add-on cannot tell.", + "held": "An alarm stopped control. See Needs attention.", + "stopped": "Control is stopped.", + "shadow": "Shadow mode: the add-on only shows what it would do.", + "cycle": "The monthly cycle keeps its level reading right.", + "cycle_mode": "The monthly cycle comes first. Its mode resumes after.", + "off": "You switched it off.", + "off_peak": "The peak limit comes before Off. It rests again after.", + "refuses_give": "The battery refuses to give power. The add-on tries again every 15 minutes.", + "refuses_charge": "The battery refuses to charge. The add-on tries again every 15 minutes.", + "peak": "The peak limit needs power, so every battery gives.", + "modes_off": "Battery modes are off, so it follows the house.", + "solar_first": "Solar first: it gets spare solar before the others.", + "leftover": "It gets the solar that Solar first batteries cannot take.", + "leftover_alone": "No Solar first battery is on, so it gets solar first.", + "covers_house": "It gives power to cover the house.", + "other_refuses": "{name} refuses to give power, so this battery takes over." + }, + "today": { + "not_planned": "Not planned yet.", + "off": "Off, so no monthly cycle today.", + "house": "Follows the house.", + "house_would": "Would follow the house.", + "stopped": "Nothing planned while control is stopped.", + "held": "Nothing planned until the alarm clears." }, "head": { "held": "Every inverter is at 0 W until the alarm clears.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 11b2ec3..0a0c2d1 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -81,13 +81,22 @@ "offline": {"name": "Add-on niet bereikbaar", "description": "De pagina probeert het elke 3 seconden opnieuw."}, "setup_only": {"name": "Installatie: nog niets wordt geregeld", "description": "Er gaat niets naar een omvormer tot de installatie bewaard is en de add-on herstart.", "control": "De regeling start na de installatie.", "open": "Installatie openen"}, "batteries": {"name": "Batterijen", "description": "Zet batterijmodi aan in de instellingen om per batterij een modus te kiezen.", "level": "Laadniveau", "now": "Nu", "stored": "Opgeslagen", "mode": "Modus", "settings": "Instellingen van omvormers wijzigen", - "with_modes": {"description": "Elke batterij volgt haar modus, na de piekgrens en de veiligheidsstops."}, - "use": "Deze batterij gebruiken", "on": "Aan", "off": "Uit", + "on": "Aan", "off": "Uit", "choice": { "solar_first": {"name": "Eerst zonne-energie", "description": "Laadt met zonne-energie vóór de andere batterijen en dekt het huis."}, "leftover_solar": {"name": "Overschot zonne-energie", "description": "Laadt met zonne-energie die de andere batterijen niet opnemen, en dekt het huis."}, - "off": {"name": "Uit", "description": "De add-on vraagt deze batterij 0 W, behalve als de piekgrens haar nodig heeft."} - }}, + "off": {"name": "Uit", "description": "Rust, en helpt alleen als de piekgrens haar nodig heeft."} + }, + "later": "Alleen goedkope uren, volgt later", + "today": "Vandaag", "why": "Waarom", + "sell": {"name": "Verkopen in dure uren", "description": "Verkopen komt in een latere update."}, + "modes_off": {"name": "Batterijmodi staan uit"}, + "how": {"name": "Zo werken de modi", "description": "Welke batterij eerst zonne-energie krijgt, en wanneer elke batterij levert.", + "solar_first": {"description": "Eerst zonne-energie krijgt het overschot vóór de andere batterijen, en dekt het huis op elk uur."}, + "leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, en dekt ook het huis."}, + "off": {"description": "Uit laat de batterij rusten en start geen maandelijkse cyclus, maar de piekgrens mag haar nog gebruiken."}, + "rules": {"description": "De piekgrens en de veiligheidsstops gaan altijd voor, en laden van het net en verkopen volgen later."}}, + "toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}."}}, "settings": {"name": "Instellingen", "description": "De instellingen staan hieronder per taak.", "open": "Instellingen openen"} }, "choices_later": {"region": {"wallonia": "Wallonië, nog geen standaardwaarde", "brussels": "Brussel, nog geen standaardwaarde"}}, @@ -102,7 +111,13 @@ }, "settings": { "name": "Instellingen", - "description": "Elke instelling, per taak, en de eenvoudige weergave volgt in een latere update.", + "description": "Elke instelling, per taak.", + "view": {"name": "Weergave van de instellingen", "simple": "Eenvoudig", "installer": "Installateur"}, + "simple": {"description": "De keuzes die een eigenaar maakt.", + "note": {"month_peak": {"description": "De piek van deze maand tot nu: {kw}."}, "shadow": {"description": "Kies Altijd aan terwijl u een nieuwe installatie test."}}, + "batteries": {"name": "Batterijen"}, + "more": {"description": "Zoekt u de meter, de omvormers of de prijzen?"}, + "installer": "De installateursweergave openen"}, "classic": "Klassieke instellingen", "search": {"name": "Instelling zoeken", "description": "Zoek een instelling, bijvoorbeeld piek of meter."}, "no_match": {"description": "Geen instelling past bij uw zoekopdracht."}, @@ -197,7 +212,6 @@ "needed": {"description": "Doe eerst de waterkokertest, of sla hem over."} }, "check": {"name": "Wat de add-on nakeek", "running": {"description": "Bezig met de startcontroles van de add-on."}, "pass": {"description": "De startcontroles van de add-on zijn in orde."}, "failed": {"description": "De controle liep niet, dus probeer opnieuw."}, "again": "Opnieuw nakijken", "blocked": {"description": "Los de rood gemarkeerde punten op en kijk dan opnieuw na."}}, - "shadow": {"name": "Starten in schaduwmodus", "description": "Aanbevolen, want dan blijft elke omvormer op 0 W tot u de schaduwmodus uitzet onder Instellingen."}, "dialog": {"name": "Bewaren en herstarten?", "description": "Elke omvormer gaat naar 0 W terwijl de add-on herstart, en de schaduwmodus houdt ze daarna op 0 W.", "yes": "Bewaren en herstarten"}, "dialog_live": {"name": "Bewaren en herstarten?", "description": "Elke omvormer gaat naar 0 W terwijl de add-on herstart, daarna gelden de nieuwe instellingen.", "yes": "Bewaren en herstarten"}, "dialog_setup": {"name": "Bewaren en herstarten?", "description": "De add-on herstart met deze instellingen, en de schaduwmodus houdt elke omvormer op 0 W.", "yes": "Bewaren en herstarten"}, @@ -232,7 +246,37 @@ "cycle": "Maandelijkse cyclus bezig.", "giving": "Levert nu {kw}.", "charging": "Laadt nu {kw}.", - "resting": "Rust nu." + "resting": "Rust nu.", + "off_resting": "Uit. Rust nu.", + "off_peak": "Uit, maar levert {kw} voor de piekgrens.", + "off_going": "Uit. Nog {kw}, gaat naar 0 W." + }, + "why": { + "no_reading": "Geen meting, dus de add-on weet het niet.", + "held": "Een alarm stopte de regeling. Zie Vraagt aandacht.", + "stopped": "De regeling is gestopt.", + "shadow": "Schaduwmodus: de add-on toont alleen wat hij zou doen.", + "cycle": "De maandelijkse cyclus houdt de meting van het laadniveau juist.", + "cycle_mode": "De maandelijkse cyclus gaat voor. Daarna volgt ze weer haar modus.", + "off": "U hebt haar uitgezet.", + "off_peak": "De piekgrens gaat voor Uit. Daarna rust ze weer.", + "refuses_give": "De batterij weigert te leveren. De add-on probeert het elke 15 minuten opnieuw.", + "refuses_charge": "De batterij weigert te laden. De add-on probeert het elke 15 minuten opnieuw.", + "peak": "De piekgrens vraagt vermogen, dus elke batterij levert.", + "modes_off": "Batterijmodi staan uit, dus ze volgt het huis.", + "solar_first": "Eerst zonne-energie: ze krijgt het overschot vóór de andere.", + "leftover": "Ze krijgt de zonne-energie die de batterijen met Eerst zonne-energie niet opnemen.", + "leftover_alone": "Geen batterij met Eerst zonne-energie staat aan, dus zij krijgt eerst zonne-energie.", + "covers_house": "Ze levert stroom om het huis te dekken.", + "other_refuses": "{name} weigert te leveren, dus deze batterij neemt het over." + }, + "today": { + "not_planned": "Nog niet gepland.", + "off": "Uit, dus vandaag geen maandelijkse cyclus.", + "house": "Volgt het huis.", + "house_would": "Zou het huis volgen.", + "stopped": "Niets gepland zolang de regeling gestopt is.", + "held": "Niets gepland tot het alarm weg is." }, "head": { "held": "Elke omvormer staat op 0 W tot het alarm weg is.", diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index 9c7f00a..317fcb5 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -46,6 +46,7 @@ class Field: wizard: int = 0 # setup wizard step 1-6, 0 = not in the wizard mirror: str = "" # a choice also copied to this field, if offered fills: str = "" # a preset choice fills this field (uimodel) + note: str = "" # P3: a line under it on Settings, Simple @property def text(self) -> str: @@ -180,12 +181,13 @@ GROUPS = ( Group("safety", ( Part("peak", ( Field("peak_cap_w", SLIDER, "kW", scale=1000, step=100, - simple=True, wizard=5), + simple=True, wizard=5, note="month_peak"), Field("peak_forecast_entity", ENTITY, kind="power_w", wizard=5), Field("peak_soc_floor", LOCKED, "%"), )), Part("start", ( - Field("shadow_mode", SEGMENTED, simple=True, wizard=6), + Field("shadow_mode", SEGMENTED, simple=True, wizard=6, + note="shadow"), Field("auto_start", TOGGLE), Field("estop_fitted", TOGGLE), Field("stale_input_s", SLIDER, "s"), diff --git a/goodwe_controller/app/uipage.py b/goodwe_controller/app/uipage.py index e91e0b3..f6ecf1a 100644 --- a/goodwe_controller/app/uipage.py +++ b/goodwe_controller/app/uipage.py @@ -99,7 +99,7 @@ def _field(fld, schema_ui, translations, lang, T): "help": text, "unit": fld.unit, "scale": fld.scale, "step": fld.step, "kind": fld.kind, "show": [list(c) for c in fld.show], "applies": fld.applies, - "wizard": fld.wizard, + "wizard": fld.wizard, "simple": fld.simple, "note": fld.note, "type": value_type, "optional": not node.get("required", False), # A choice mirrored into a field also shows (and finds) its keys. "writes": sorted(k for k, how in L.DERIVED.items() diff --git a/goodwe_controller/test_batteries_screen.py b/goodwe_controller/test_batteries_screen.py new file mode 100644 index 0000000..a2f2347 --- /dev/null +++ b/goodwe_controller/test_batteries_screen.py @@ -0,0 +1,367 @@ +"""UX-13 P3: the Batteries screen and Settings, Simple. `python3 test_batteries_screen.py` + +1. Each battery's Now, Today and Why lines, in English and Dutch, for the six + states the brief names: modes off, modes on, a battery Off, an Off battery + giving way to the peak limit, a refusal hold, and the monthly cycle. +2. The OPT-11 P1 test's F2 contradictions stay gone: a battery that moves + power never reads "0 W" beside it, the Off help names no watts, and no + battery line says the peak limit "holds back" a battery it asks for power. +3. The plan leaves an Off battery out, except for the peak limit. +4. `battery_why()` is pure and picks the most urgent reason first. +5. The screen's `/action` round trips over the real web app: the switch and + the mode list post `pack_use` and `pack_mode`, `/status` shows the result + in both languages, and a refused value comes back as a plain 400. +6. The page: the cards, the Simple view and its fields come from the layout + table and ui_text, and the scripts post only the existing actions. +7. The screen changes no control path: homeview.py reads the controller and + calls nothing that writes, and the page adds no /action value. +The headless-browser check is in the PR, not in CI (the CI image has no +browser). Mutating a module this file grades? Read MUTATION.md first. +""" + +import ast +import asyncio +import io +import json +import os +import re +import socket +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) + +import aiohttp # noqa: E402 +from aiohttp import web as aioweb # noqa: E402 + +import ux13_demo as D # noqa: E402 +from app import homeview, packmode, uilayout as L, uipage, web # noqa: E402 +from app.maintenance import IDLE, DRAIN # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def words(lang): + with io.open(os.path.join(HERE, "app", "ui_text", f"{lang}.json"), + encoding="utf-8") as f: + return json.load(f) + + +EN, NL = words("en"), words("nl") +LANGS = {"en": EN, "nl": NL} + + +def build(state, lang="en", c=None): + c = c or D.controller(state) + s = c.status_payload() + return homeview.build(c, level=s["level"], checks=s["checks"], lang=lang) + + +# The six states and what each battery's Why line must be. +WANT = { + "running": ("modes_off", "modes_off"), + "modes": ("solar_first", "leftover"), + "off": ("solar_first", "off"), + "off_peak": ("peak", "off_peak"), + "refusal": ("refuses_give", "other_refuses"), + "maint": ("cycle_mode", "leftover"), +} + +# ============================================================================ # +print("1. Now, Today and Why per battery, English and Dutch") +ROWS = {(st, lang): build(st, lang) for st in WANT for lang in LANGS} +for st, want in WANT.items(): + got = tuple(b["why_key"] for b in ROWS[(st, "en")]["batteries"]) + en = ROWS[(st, "en")]["batteries"] + nl = ROWS[(st, "nl")]["batteries"] + print(f" {st}: " + " / ".join(f"{b['now']} | {b['why']} | " + f"{b['today_line'] or b['today']}" + for b in en)) + check(f"{st}: the Why lines are {want}, in each language's own words", + got == want + and all(b["why"] == homeview.uitext.say( + W["home_words"]["why"][b["why_key"]], + name=D.OPTS["inverters"][0]["name"]) + for W, rows in ((EN, en), (NL, nl)) for b in rows)) + check(f"{st}: every battery has a Now, a Why and a Today, and the Dutch " + f"lines differ from the English", + all(b["now"] and b["why"] and (b["today"] or b["today_line"]) + for b in en + nl) + and all(e["why"] != n["why"] and e["now"] != n["now"] + for e, n in zip(en, nl))) + +_modes = ROWS[("modes", "en")] +check("modes on: each row carries its switch and mode, and Today says the " + "mode's plan is not made yet (OPT-11 P3/P4), without inventing one", + _modes["modes_on"] is True + and [(b["use"], b["mode_key"]) for b in _modes["batteries"]] + == [(True, "solar_first"), (True, "leftover_solar")] + and all(b["today_line"] == EN["home_words"]["today"]["not_planned"] + for b in _modes["batteries"])) +_off = ROWS[("running", "en")] +check("modes off: no switch, no mode, and Today and Why say it follows the " + "house", _off["modes_on"] is False + and all("mode_key" not in b and "use" not in b + and b["today_line"] == EN["home_words"]["today"]["house"] + for b in _off["batteries"])) +_b = ROWS[("off", "en")]["batteries"][1] +check("a battery Off: 'Off. Resting now.', 'You switched it off.', and no " + "monthly cycle today", (_b["mode_key"], _b["now"], _b["why"], + _b["today_line"]) + == ("off", EN["home_words"]["now"]["off_resting"], + EN["home_words"]["why"]["off"], EN["home_words"]["today"]["off"])) +_b = ROWS[("off_peak", "en")]["batteries"][1] +_bn = ROWS[("off_peak", "nl")]["batteries"][1] +check("Off giving way to the peak limit says so plainly, with the figure: " + "'Off, but gives 0.5 kW for the peak limit.'", + _b["now"] == "Off, but gives 0.5 kW for the peak limit." + and _bn["now"] == "Uit, maar levert 0,5 kW voor de piekgrens." + and _b["why"] == EN["home_words"]["why"]["off_peak"]) +_a, _b = ROWS[("refusal", "en")]["batteries"] +check("a refusal hold: the refusing battery says it refuses and when it " + "tries again, the other says it takes over", + _a["why"] == EN["home_words"]["why"]["refuses_give"] + and _b["why"] == "Battery A refuses to give power, so this battery " + "takes over.") +_a = ROWS[("maint", "en")]["batteries"][0] +check("maintenance: the cycle comes first, the mode resumes after, and Today " + "shows the cycle block", _a["maintenance"] == DRAIN + and _a["why"] == EN["home_words"]["why"]["cycle_mode"] + and [r["kind"] for r in _a["today"]] == ["cycle"]) +_sh = build("shadow")["batteries"] +_al = build("alarm")["batteries"] +check("shadow mode and an alarm: Why says which, and Today plans nothing " + "the add-on does not do", + all(b["why_key"] == "shadow" and b["today_line"] + == EN["home_words"]["today"]["house_would"] for b in _sh) + and all(b["why_key"] == "held" and b["today_line"] + == EN["home_words"]["today"]["held"] for b in _al)) + +# ============================================================================ # +print("\n2. the OPT-11 P1 test's F2: no line contradicts the power shown") +ZERO = re.compile(r"\b0 W\b") +GOING = (EN["home_words"]["zero_going"], NL["home_words"]["zero_going"], + "going to 0 W", "gaat naar 0 W") +_bad = [] +for (st, lang), payload in sorted(ROWS.items()): + for b in payload["batteries"]: + moving = b["power_w"] is not None and abs(b["power_w"]) > homeview.IDLE_W + if moving and b.get("maintenance", IDLE) == IDLE: + kw = homeview._dec(f"{abs(b['power_w']) / 1000:.1f}") + kw = kw.replace(".", ",") if lang == "nl" else kw + if kw not in b["now"]: + _bad.append(f"{st}/{lang}/{b['name']}: no figure in {b['now']!r}") + for line in (b["now"], b["why"]): + if ZERO.search(line) and not any(g in line for g in GOING): + _bad.append(f"{st}/{lang}/{b['name']}: 0 W beside power: " + f"{line!r}") + if "held back" in b["why"] or "tegengehouden" in b["why"]: + _bad.append(f"{st}/{lang}/{b['name']}: {b['why']!r}") +print(f" {_bad}") +check("a battery that moves power shows the figure, and no line beside it " + "says 0 W", not _bad) +check("the Off help names no watts, in either language, and says the peak " + "limit may use the battery", + all(not ZERO.search(W["home"]["batteries"]["choice"]["off"] + ["description"]) for W in LANGS.values()) + and "peak limit" in EN["home"]["batteries"]["choice"]["off"] + ["description"]) +_going = homeview.battery_now(62, 900, phase=IDLE, shadow=False, running=True, + off=True, peak=False) +check("an Off battery still moving without the peak limit reads 'going to " + "0 W' with its figure, never a bare 0 W", + _going == "Off. Still at 0.9 kW, going to 0 W.") + +# ============================================================================ # +print("\n3. the plan leaves an Off battery out, except for the peak limit") +_c = D.controller("off") +_c.maints[1].cfg = _c.maints[0].cfg # both due, so both would be drawn +_p = build("off", c=_c) +_kinds = {i: {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == i} + for i in (0, 1)} +print(f" {_kinds}") +check("Off: no 'follows the house', no trade, no monthly cycle for B", + not _kinds[1] and "house" in _kinds[0]) +_p = build("off_peak") +check("...but the peak block stays on it while the peak limit needs it", + {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == 1} + == {"peak"}) + +# ============================================================================ # +print("\n4. battery_why(): pure, most urgent first") +BASE = dict(modes_on=True, mode=packmode.SOLAR_FIRST, off=False, reading=True, + phase=IDLE, shadow=False, running=True, held=False, refused=0, + peak=False, moving=False, sf_ahead=False) + + +def why(**kw): + return homeview.battery_why(**dict(BASE, **kw)) + + +_cases = [ + (dict(reading=False, held=True), "no_reading"), + (dict(held=True, shadow=True), "held"), + (dict(running=False, off=True), "stopped"), + (dict(shadow=True, phase=DRAIN), "shadow"), + (dict(phase=DRAIN, off=True), "cycle_mode"), + (dict(phase=DRAIN, modes_on=False), "cycle"), + (dict(off=True, peak=True, moving=True), "off_peak"), + (dict(off=True, peak=True, moving=False), "off"), + (dict(off=True, moving=True), "off"), + (dict(refused=1, peak=True), "refuses_give"), + (dict(refused=-1), "refuses_charge"), + (dict(peak=True, giving=True, other_refuses="B"), "peak"), + (dict(giving=True, other_refuses="B", modes_on=False), "other_refuses"), + (dict(modes_on=False, giving=True), "modes_off"), + (dict(giving=True, mode=packmode.LEFTOVER_SOLAR), "covers_house"), + (dict(mode=packmode.LEFTOVER_SOLAR, sf_ahead=True), "leftover"), + (dict(mode=packmode.LEFTOVER_SOLAR), "leftover_alone"), + ({}, "solar_first"), +] +_wrong = [(kw, want, why(**kw)) for kw, want in _cases if why(**kw) != want] +print(f" {_wrong}") +check(f"{len(_cases)} cases, each the expected reason", not _wrong) +check("every reason it can return has words in both languages", + {w for _k, w in _cases} == set(EN["home_words"]["why"]) + == set(NL["home_words"]["why"])) + +# ============================================================================ # +print("\n5. /action round trips from the screen, over the real web app") + + +async def _serve(state, calls): + c = D.controller(state) + stored = dict(D.defaults(D.CONFIG), **D.OPTS) + runner = aioweb.AppRunner(web.build_app(c, D.Supervisor(stored))) + await runner.setup() + sock = socket.socket() + sock.bind(("127.0.0.1", 0)) + port = sock.getsockname()[1] + sock.close() + await aioweb.TCPSite(runner, "127.0.0.1", port).start() + out = [] + try: + async with aiohttp.ClientSession() as s: + root = f"http://127.0.0.1:{port}/" + for body, lang in calls: + if body is not None: + async with s.post(root + "action", json=body) as r: + out.append((r.status, + await r.json(content_type=None))) + async with s.get(root + "status?lang=" + lang) as r: + out.append((r.status, await r.json(content_type=None))) + finally: + await runner.cleanup() + return out + + +A, B = (i["name"] for i in D.OPTS["inverters"]) +# Exactly what app.js posts: {action, unit, value}. +_r = asyncio.run(_serve("modes", [ + ({"action": "pack_use", "unit": B, "value": False}, "en"), + ({"action": "pack_mode", "unit": A, "value": packmode.LEFTOVER_SOLAR}, + "nl"), + ({"action": "pack_use", "unit": B, "value": True}, "en"), + ({"action": "pack_mode", "unit": A, "value": "cheap_hours"}, "en"), +])) +(_s1, _j1), (_, _st1), (_s2, _j2), (_, _st2), (_s3, _), (_, _st3), \ + (_s4, _j4), (_, _st4) = _r +check("switch B off: 200, and /status shows B Off with 'You switched it off.'", + _s1 == 200 and _j1["result"]["use"] is False + and _st1["batteries"][1]["mode_key"] == "off" + and _st1["batteries"][1]["why"] == EN["home_words"]["why"]["off"]) +check("set A to Leftover solar: 200, and /status?lang=nl shows it in Dutch", + _s2 == 200 and _st2["batteries"][0]["mode_choice"] + == packmode.LEFTOVER_SOLAR + and _st2["batteries"][0]["mode"] + == NL["home_words"]["modes"]["leftover_solar"]) +check("switch B back on: its stored mode returns", + _s3 == 200 and _st3["batteries"][1]["mode_key"] + == packmode.LEFTOVER_SOLAR) +check("a mode the list only shows greyed out is refused with a plain 400, and " + "nothing changes", _s4 == 400 and _j4["ok"] is False and _j4["error"] + and _st4["batteries"][0]["mode_choice"] == packmode.LEFTOVER_SOLAR) +_r = asyncio.run(_serve("running", [ + ({"action": "pack_use", "unit": B, "value": False}, "en")])) +check("with battery modes off the switch is refused with the plain reason, " + "and the batteries stay on", _r[0][0] == 400 and _r[0][1]["error"] + and "mode_key" not in _r[1][1]["batteries"][1]) + +# ============================================================================ # +print("\n6. the page") +PAGE = web.page() +JS = io.open(os.path.join(HERE, "app", "static", "app.js"), + encoding="utf-8").read() +SJS = io.open(os.path.join(HERE, "app", "static", "settings.js"), + encoding="utf-8").read() +check("the Batteries screen has its cards, the modes-off card and 'How the " + "modes work'", all(f'id="{i}"' in PAGE for i in + ("bcards", "batt-off", "batt-how", "batt-banner"))) +check("Settings has a Simple / Installer choice as a radio group, and Simple " + "comes first", re.search(r'id="set-view"[^>]*>\s*<button[^>]*' + r'data-v="simple"', PAGE) is not None + and PAGE.count('role="radio"') >= 2 and 'id="simple"' in PAGE) +_acts = set(re.findall(r'packAct\("(\w+)"', JS)) +check(f"the cards post only the existing actions ({sorted(_acts)}), as " + f"{{action, unit, value}}", _acts == set(web.PACK_ACTIONS) + and "action: what, unit: b.name, value: value" in JS) +check("the switch is a real switch and the list names cheap hours as coming " + "later, not choosable", 'role: "switch"' in JS and '"aria-checked"' in JS + and 'h("option", { value: "", disabled: true }, t("batteries.later"))' + in JS) +check("the selling switch is greyed out until OPT-11 P3 (no pack_sell is " + "posted)", "pack_sell" not in JS and "disabled: true })" in JS) +_T = uipage.ui_text("en") +_lay = uipage.layout(D.schema_ui(D.CONFIG), {"en": {}}) +_simple = [f for g in _lay["groups"] for p in g["parts"] for f in p["fields"] + if f.get("simple")] +check("Settings, Simple draws the fields the layout marks, and each note " + "has words in both languages", + sorted(f["key"] for f in _simple) + == sorted(f.key for g in L.GROUPS for p in g.parts for f in p.fields + if f.simple) + and all(f["note"] in EN["settings"]["simple"]["note"] + and f["note"] in NL["settings"]["simple"]["note"] + for f in _simple if f["note"])) +check("settings.js picks them by the `simple` flag and names no option key", + "f.simple" in SJS and not any(f'"{f.key}"' in SJS for g in L.GROUPS + for p in g.parts for f in p.fields)) + +# ============================================================================ # +print("\n7. no control path changes: the screen reads, it does not write") +SRC = io.open(os.path.join(HERE, "app", "homeview.py"), encoding="utf-8").read() +WRITES = {"set_number", "store_set", "set", "set_time", "handle_action", + "log_event", "abort", "tick", "publish", "call", "write", + "_pack_action", "_maint_stop_off"} +_calls = sorted({n.func.attr for n in ast.walk(ast.parse(SRC)) + if isinstance(n, ast.Call) + and isinstance(n.func, ast.Attribute) + and n.func.attr in WRITES}) +check(f"homeview.py calls nothing that writes state or commands an inverter " + f"({_calls})", not _calls) +_imports = sorted({(n.module or "") for n in ast.walk(ast.parse(SRC)) + if isinstance(n, ast.ImportFrom)}) +check(f"...and imports no module that sends power requests ({_imports})", + not {"main", "inverter", "hass", "control", "allocator", + "arbiter"} & {m.lstrip(".") for m in _imports}) +_c = D.controller("off_peak") +_before = (json.dumps(_c.store.data, sort_keys=True, default=str), + [(i.last_write, i.target) for i in _c.inverters]) +for lang in LANGS: + build("off_peak", lang, c=_c) +check("building the screen twice leaves the store and every power request " + "as it was", _before + == (json.dumps(_c.store.data, sort_keys=True, default=str), + [(i.last_write, i.target) for i in _c.inverters])) + +print() +if fails: + print(f"{len(fails)} FAILED") + sys.exit(1) +print("all passed") diff --git a/goodwe_controller/tools/ux13_browser_check.py b/goodwe_controller/tools/ux13_browser_check.py new file mode 100644 index 0000000..56d80ef --- /dev/null +++ b/goodwe_controller/tools/ux13_browser_check.py @@ -0,0 +1,184 @@ +"""UX-13 P3: the headless-browser check of the Batteries screen and Settings, +Simple. Run by `CHECK=1 tools/ux13_screenshots.sh`, like the screenshots. + +For every battery-mode fixture (tools/ux13_demo.py) it opens both screens at +phone and desktop width, light and dark, in English and Dutch, and fails on a +page error, a console error or a sideways scroll. Then it clicks the switch +and the mode list on both screens and checks what was posted and what the +cards show after. + + python3 ux13_browser_check.py # DEMO_<STATE> = the fixture's URL +""" + +import json +import os +import sys + +from playwright.sync_api import sync_playwright + +STATES = ("running", "modes", "off", "off_peak", "refusal", "maint") +SIZES = {"phone": {"width": 390, "height": 844}, + "desktop": {"width": 1000, "height": 900}} +FAILS = [] + + +def url(state): + return os.environ[f"DEMO_{state.upper()}"] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + FAILS.append(name) + + +def open_page(browser, state, route, *, size, scheme, lang): + ctx = browser.new_context(locale=lang, viewport=SIZES[size], + color_scheme=scheme, reduced_motion="reduce") + page = ctx.new_page() + errors = [] + page.on("pageerror", lambda e: errors.append(f"pageerror {e}")) + page.on("console", lambda m: errors.append(f"console {m.text}") + if m.type == "error" else None) + page.goto(url(state) + route) + page.wait_for_load_state("networkidle") + page.wait_for_timeout(1200) + return ctx, page, errors + + +def sweep(browser): + n = 0 + for state in STATES: + for route in ("#batteries", "#settings"): + for size in SIZES: + for scheme in ("light", "dark"): + for lang in ("en-GB", "nl-BE"): + ctx, page, errors = open_page( + browser, state, route, size=size, scheme=scheme, + lang=lang) + wide = page.evaluate( + "document.documentElement.scrollWidth > " + "document.documentElement.clientWidth") + if route == "#batteries": + cards = page.locator("#bcards .bcard").count() + texts = page.locator("#bcards dd").all_inner_texts() + ok = cards == 2 and all(t.strip() for t in texts) + else: + ok = (page.locator("#simple .card").count() >= 3 + and page.locator("#groups").is_hidden()) + where = f"{state} {route} {size} {scheme} {lang}" + if errors or wide or not ok: + FAILS.append(f"{where}: errors={errors} " + f"wide={wide} drawn={ok}") + print(f" FAIL {where}: {errors} wide={wide} " + f"drawn={ok}") + n += 1 + ctx.close() + check(f"{n} views: 0 page errors, 0 console errors, no sideways scroll, " + f"every card drawn", not [f for f in FAILS if " #" in f]) + + +def posts(page): + sent = [] + page.on("request", lambda r: sent.append(json.loads(r.post_data)) + if r.url.endswith("/action") and r.method == "POST" else None) + return sent + + +def actions(browser): + # The Batteries screen: switch B off, then set A to Leftover solar. + ctx, page, errors = open_page(browser, "modes", "#batteries", + size="desktop", scheme="light", lang="en-GB") + sent = posts(page) + page.locator("#bsw-c1").click() + page.wait_for_timeout(1500) + card_b = page.locator("#bcards .bcard").nth(1) + check("Batteries: B's switch posts pack_use false, and B's card turns Off " + "with its mode list greyed out", + sent[-1:] == [{"action": "pack_use", "unit": "Battery B", + "value": False}] + and "off" in (card_b.get_attribute("class") or "") + and page.locator("#bsel-c1").is_disabled() + and "You switched it off." in card_b.inner_text()) + page.locator("#bsel-c0").focus() + page.locator("#bsel-c0").select_option("leftover_solar") + page.wait_for_timeout(1500) + check("...A's list posts pack_mode leftover_solar and the card keeps it", + sent[-1:] == [{"action": "pack_mode", "unit": "Battery A", + "value": "leftover_solar"}] + and page.locator("#bsel-c0").input_value() == "leftover_solar" + and "Leftover solar" in page.locator("#bcards .bcard").nth(0) + .inner_text()) + check("...the cheap-hours choice and the selling switch are greyed out", + page.locator("#bsel-c0 option[disabled]").count() == 1 + and page.locator("#bcards .bcard .f .switch[disabled]").count() == 2) + check("...and the focus stays on the control that was used", + page.evaluate("document.activeElement.id") == "bsel-c0") + check("...with 0 page errors", not errors) + ctx.close() + # Settings, Simple: the same switch, and the Installer view is one tap. + ctx, page, errors = open_page(browser, "modes", "#settings", + size="phone", scheme="dark", lang="nl-BE") + sent = posts(page) + page.locator("#bsw-s1").click() + page.wait_for_timeout(1500) + check("Simple (NL, phone, dark): B's switch posts pack_use true and reads " + "Aan", sent[-1:] == [{"action": "pack_use", "unit": "Battery B", + "value": True}] + and page.locator("#bsw-s1").get_attribute("aria-checked") == "true") + page.locator("#set-view [data-v=installer]").click() + page.wait_for_timeout(500) + check("...Installer shows the groups and hides Simple", + page.locator("#groups").is_visible() + and page.locator("#simple").is_hidden()) + check("...with 0 page errors", not errors) + ctx.close() + + +def modes_off(browser): + ctx, page, errors = open_page(browser, "running", "#batteries", + size="phone", scheme="light", lang="en-GB") + page.locator("#batt-off a").click() + page.wait_for_timeout(1500) + check("modes off: the card's button opens Settings on the Installer view", + page.url.endswith("#settings") and page.locator("#groups") + .is_visible() and not errors) + ctx.close() + + +def month_peak(browser): + # The fixture has no month peak yet, so give /status one on the way in. + ctx = browser.new_context(locale="en-GB", viewport=SIZES["desktop"]) + page = ctx.new_page() + + def with_peak(route): + r = route.fetch() + body = r.json() + body["month_peak"]["peak_w"] = 2860.0 + route.fulfill(response=r, json=body) + page.route("**/status*", with_peak) + page.goto(url("modes") + "#settings") + page.wait_for_load_state("networkidle") + page.wait_for_timeout(1500) + check("Simple: the peak card shows this month's peak from /status", + "This month's peak so far: 2.9 kW." in page.locator("#simple") + .inner_text()) + ctx.close() + + +def main(): + with sync_playwright() as p: + b = p.chromium.launch() + sweep(b) + actions(b) + month_peak(b) + modes_off(b) + b.close() + if FAILS: + print(f"{len(FAILS)} FAILED") + sys.exit(1) + print("all passed") + + +if __name__ == "__main__": + main() diff --git a/goodwe_controller/tools/ux13_demo.py b/goodwe_controller/tools/ux13_demo.py index 9b8e0e6..90b2177 100644 --- a/goodwe_controller/tools/ux13_demo.py +++ b/goodwe_controller/tools/ux13_demo.py @@ -2,7 +2,9 @@ headless browser check. `python3 tools/ux13_demo.py STATE PORT [HOST]` STATE is running, shadow, alarm, new (P4) or setup (UX-15's setup-only -mode, P5). The controller is the shipped `Controller` +mode, P5). P3 adds the battery-mode states in `P3`: modes (on, B on Leftover +solar), off (B switched off), off_peak (B off but giving for the peak limit), +refusal (A refuses to give power) and maint (A in its monthly cycle). The controller is the shipped `Controller` with its readings set by hand (two batteries, solar, today's prices in the mockup's shape, trading on). Nothing here talks to Home Assistant or to an inverter: `/action` changes only this fixture. Used for the P1 render check @@ -34,8 +36,9 @@ sys.path.insert(0, os.path.join(HERE, "tools")) from aiohttp import web as aioweb # noqa: E402 -from app import homeview, web # noqa: E402 +from app import homeview, packmode, web # noqa: E402 from app.main import Controller # noqa: E402 +from app.maintenance import DRAIN # noqa: E402 from app.setuponly import SetupOnly # noqa: E402 from app.peakguard import PeakDecision # noqa: E402 from app.price import PricePoint, PriceProduct, PriceRead # noqa: E402 @@ -231,8 +234,14 @@ OPTS = {"meter_entity": "sensor.grid", "meter_source": "off", "max_w": 2500, "capacity_kwh": 5.4}]} +# UX-13 P3: the battery-mode states, each with battery modes on. +P3 = ("modes", "off", "off_peak", "refusal", "maint") + + def controller(state): opts = dict(OPTS, shadow_mode="on" if state == "shadow" else "off") + if state in P3: + opts["battery_modes_enabled"] = True c = Controller(opts, Hass(), Store(), Pub(), stop=asyncio.Event()) c.auto = True now = datetime.now(timezone.utc) @@ -255,6 +264,29 @@ def controller(state): c.pv_w = 3900.0 if state == "alarm": c.inverters[0].sign_wd.tripped = True + if state in P3: + a, b = c.inverters + b.store_set(packmode.MODE_KEY, packmode.LEFTOVER_SOLAR) + if state in ("off", "off_peak"): + b.store_set(packmode.USE_KEY, False) + b.batt = 0.0 + if state == "off_peak": + # A cloudy evening: the house takes 6 kW and the peak limit needs + # both batteries, so B gives 0.5 kW although it is switched off. + c.pv_w, c.grid = 0.0, 3490.0 + a.batt, b.batt = 2000.0, 510.0 + c.peak_guard = PeakDecision(engaged=True, floor_w=2500.0, + ceiling_w=3500.0, ceiling_from="cap", + projected_w=3600.0) + if state == "refusal": + # A is at its cut-out level and refuses: asked 0 W, B takes over. + c.pv_w, c.grid = 0.0, 5.0 + a.soc, a.batt, a.refused = 9.0, -4.0, 1 + b.batt = 1210.0 + if state == "maint": + c.maints[0].store.set("phase", DRAIN) # MAINT-05: A's own key + c.pv_w, c.grid = 0.0, 0.0 + a.batt, b.batt = 2000.0, 0.0 return c @@ -290,6 +322,7 @@ async def main(state, port, host="127.0.0.1"): p1_net_entity="sensor.grid", price_provider="generic_dayahead", peak_forecast_entity="sensor.peak_forecast", shadow_mode=c.o.get("shadow_mode", "off"), + battery_modes_enabled=state in P3, inverters=[dict(i, bms_soc_floor=10) for i in OPTS["inverters"]]) runner = aioweb.AppRunner(web.build_app(c, Supervisor(stored))) diff --git a/goodwe_controller/tools/ux13_screenshots.py b/goodwe_controller/tools/ux13_screenshots.py index 6955338..8e5220f 100644 --- a/goodwe_controller/tools/ux13_screenshots.py +++ b/goodwe_controller/tools/ux13_screenshots.py @@ -6,8 +6,8 @@ error, so a broken screen is never pictured. python3 ux13_screenshots.py OUT_DIR # DEMO_<STATE> = the fixture's URL -The battery-mode screens (P3) are not built, so there is no shot of them: -DOCS.md says so instead of showing a mock-up. +P3 adds the Batteries screen and Settings, Simple (the default Settings +view), so the Installer shots click Installer first. """ import os @@ -48,7 +48,12 @@ def shot(browser, name, state, route, *, lang="en-GB", size=DESKTOP, print(f" {name}.png") +def installer(page): + page.locator("#set-view [data-v=installer]").click() + + def open_tariff(page): + installer(page) page.locator("details.grp[data-g=tariff] > summary").click() page.locator("details.grp[data-g=meter] > summary").click() # close it # The fixture site is on a dynamic contract: its fallback gets windows. @@ -80,8 +85,17 @@ def main(): shot(b, "home-shadow", "shadow", "#home") shot(b, "home-phone", "running", "#home", size=PHONE) shot(b, "home-setup-only", "setup", "#home", full=False) - shot(b, "settings-installer", "running", "#settings") - shot(b, "settings-installer-nl", "running", "#settings", lang="nl-BE") + shot(b, "settings-installer", "running", "#settings", act=installer) + shot(b, "settings-installer-nl", "running", "#settings", lang="nl-BE", + act=installer) + shot(b, "batteries", "modes", "#batteries") + shot(b, "batteries-nl", "modes", "#batteries", lang="nl-BE") + shot(b, "batteries-off-peak", "off_peak", "#batteries") + shot(b, "batteries-phone", "refusal", "#batteries", size=PHONE, + full=False) + shot(b, "batteries-modes-off", "running", "#batteries", full=False) + shot(b, "settings-simple", "modes", "#settings") + shot(b, "settings-simple-nl", "modes", "#settings", lang="nl-BE") tariff = "details.grp[data-g=tariff]" shot(b, "settings-time-windows", "running", "#settings", act=windows, only=tariff) diff --git a/goodwe_controller/tools/ux13_screenshots.sh b/goodwe_controller/tools/ux13_screenshots.sh index b71ddf0..daf4993 100755 --- a/goodwe_controller/tools/ux13_screenshots.sh +++ b/goodwe_controller/tools/ux13_screenshots.sh @@ -2,6 +2,7 @@ # UX-13 P5: regenerate the DOCS screenshots in docs/img/ux13/ from the real page. # # sh goodwe_controller/tools/ux13_screenshots.sh [OUT_DIR] +# CHECK=1 sh goodwe_controller/tools/ux13_screenshots.sh # P3 browser check # # Serves tools/ux13_demo.py's fixtures (running, shadow, new, setup) in the CI # test image, then runs tools/ux13_screenshots.py in the Playwright image on a @@ -14,7 +15,9 @@ HERE=$(cd "$(dirname "$0")/.." && pwd) OUT=${1:-$HERE/../docs/img/ux13} PW=mcr.microsoft.com/playwright/python:v1.55.0-noble NET=ux13-shots-$$ -STATES="running shadow new setup" +STATES="running shadow new setup modes off off_peak refusal maint" +RUN=/t/ux13_screenshots.py +[ "${CHECK:-}" = 1 ] && RUN=/t/ux13_browser_check.py mkdir -p "$OUT" OUT=$(cd "$OUT" && pwd) @@ -39,5 +42,5 @@ docker run --rm --network "$NET" --user "$(id -u):$(id -g)" -e HOME=/tmp \ $ENVS -v "$HERE/tools:/t:ro" -v "$OUT:/out" "$PW" \ sh -euc 'pip install -q --disable-pip-version-check --target /tmp/pw \ playwright==1.55.0 - PYTHONPATH=/tmp/pw python3 /t/ux13_screenshots.py /out' + PYTHONPATH=/tmp/pw python3 '"$RUN"' /out' echo "screenshots in $OUT" -- 2.54.0 From 7c4c8f5c661cfce28a407b38475de591418a5417 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Mon, 28 Sep 2026 23:09:39 +0200 Subject: [PATCH 069/105] SAFETY-79: peak guard keeps a margin below the limit New option peak_margin_w (default 50 W, 0-500 W). The peak guard, the forecast checks and the maintenance charge sizing aim at peak_cap_w - peak_margin_w; the month peak, the bill, headroom, warnings and every notice keep the real cap. Owner decision 2026-09-28. peak_margin_w 0 is byte-identical to ed739d4 (tools/safety79_identity.py, test_peak_margin.py part 1). validate.py rule 12 refuses a value outside 0-500, not whole, or not below the peak limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV --- .../DECISIONS/SAFETY-79-peak-margin.md | 39 +++ goodwe_controller/DOCS.md | 3 + goodwe_controller/app/main.py | 15 +- goodwe_controller/app/messages.py | 1 + goodwe_controller/app/peakguard.py | 51 +++- goodwe_controller/app/ui_text/en.json | 2 +- goodwe_controller/app/ui_text/nl.json | 2 +- goodwe_controller/app/uilayout.py | 1 + goodwe_controller/app/validate.py | 25 +- goodwe_controller/config.yaml | 3 + goodwe_controller/test_arbitrage.py | 4 +- goodwe_controller/test_messages.py | 2 +- goodwe_controller/test_peak_margin.py | 270 ++++++++++++++++++ goodwe_controller/test_peakguard.py | 62 ++-- goodwe_controller/tools/replay_ac3.py | 2 +- goodwe_controller/tools/safety79_identity.py | 114 ++++++++ goodwe_controller/translations/en.yaml | 3 + goodwe_controller/translations/nl.yaml | 3 + 18 files changed, 549 insertions(+), 53 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md create mode 100644 goodwe_controller/test_peak_margin.py create mode 100644 goodwe_controller/tools/safety79_identity.py diff --git a/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md b/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md new file mode 100644 index 0000000..72a34bc --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md @@ -0,0 +1,39 @@ +# SAFETY-79 — the peak guard keeps a margin below the peak limit + +**Status: DECIDED 2026-09-28 (owner decision).** + +## Decision + +The peak guard aims at `peak_cap_w - peak_margin_w`, not at `peak_cap_w`. +`peak_margin_w` is a setting: default 50 W, range 0-500 W, whole watts. An +install without the key gets 50. + +**Why (owner):** the guard aimed exactly at the cap, and in the OPT-11 P1 test +a quarter banked 3501.9 W against a 3500 W limit (OPT-11-P1-test-report.md, +check 4). A peak even 1 W over still sets the billed peak. It is a setting and +not a constant because the add-on is sold to several sites. + +## What uses which number + +- **cap - margin (the aim):** `peakguard.decide()` (the claim's floor, and so + arbitrage's `charge_headroom_w()` and OPT-11's give-way, which read it), + `shaping_suspended()` and `maintenance_charge_floor()` (the forecast checks, + via `Controller.peak_aim_w()`). +- **the real cap (reporting and billing):** `PeakTracker` (month peak, + headroom, 80 % warning), the decision's `ceiling_w` and every notice and + status row built from it, Home's limit, and `validate.config_notes()`. + +A month peak already banked above cap - margin is aimed at as it stands +(`quarter_target_w()` is `quarter_ceiling_w()` on the lowered cap), so the +margin never holds a quarter below a peak that is already paid for. + +## Checks + +`peak_margin_w: 0` is byte-identical to ed739d4 (test_peak_margin.py part 1, +digests from tools/safety79_identity.py). validate.py rule 12 refuses a value +outside 0-500, not whole, or not below `peak_cap_w`. + +## Open + +Whether the margin should also apply below a banked month peak above the cap +is not decided here; today it does not. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 4f36859..e56c26a 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -204,6 +204,7 @@ The label and description each setting shows on the Configuration tab, in tab or | Limits | Inverter rating (W) | `max_w` | Your own number: the most power the add-on may ever ask of the inverter. Start low and raise it after commissioning. | | Limits | Battery cut-out level (%) | `bms_soc_floor` | The level where the battery's own management system stops giving power. Read it off your battery rather than copying a figure. | | Limits | Peak limit (W) | `peak_cap_w` | Your own number: the 15-minute average power the add-on keeps the grid under. Take it from your grid contract. | +| Limits | Margin below the peak limit (W) | `peak_margin_w` | The add-on aims this much below the peak limit, so a 15-minute period that ends a little high still stays under it. | | Limits | 15-minute demand forecast entity (W) | `peak_forecast_entity` | Optional. A forecast of this 15-minute period's average power. Leave it empty and there is no peak limit. | | Limits | Peak reserve (%) | `peak_soc_floor` | Peak limiting will not draw the battery below this level, but ordinary use can. Derived value, leave it unchanged. | | Tariff | Dynamic price source | `price_provider` | Where prices come from. Choosing a source starts the price fetch, even with trading off. | @@ -274,6 +275,7 @@ When the add-on refuses to start, each reason names the setting by its label and - **Inverter rating** (`max_w`): your own number, not a derived one. It is not read when the inverter list is filled in, since each entry carries its own and the site limit is their sum. Several safety thresholds must stay below it, and the add-on refuses to start if one does not. - **Battery cut-out level** (`bms_soc_floor`, `inverters.bms_soc_floor`): measured, not chosen. Register 0x0560 reads 10 % on the reference GW5000S-BP. It exists so the add-on can refuse a “Peak reserve” at or below it, which could never take effect. Each inverter entry states its own, because one default for two different batteries protects the shallower one with the deeper one's number. - **Peak limit** (`peak_cap_w`): your own number, from your grid contract. In Belgium it is the capacity-tariff peak your distribution charge is billed on. +- **Margin below the peak limit** (`peak_margin_w`): 50 W by default, 0 to 500 W (SAFETY-79). Peak limiting aims at the peak limit minus this margin, because a 15-minute period aimed exactly at the limit can end a watt or two over it (3501.9 W against 3500 W in a test), and even 1 W over sets the billed peak. The bill, this month's peak and the warnings still compare against the peak limit itself. 0 aims at the limit, as before. - **Peak reserve** (`peak_soc_floor`): derived, not picked (SAFETY-24). The reference battery holds 13.8 kWh usable and the worst modelled peak day asks for 878 Wh, or 6.4 %. 20 % sits ten points above the cut-out level and leaves about 1.6 worst days of room. It bounds peak limiting only: ordinary use goes on down to the cut-out level. It must stay above “Battery cut-out level”. - **Dynamic price source** (`price_provider`): selecting a provider is what starts the fetch, every half hour, whether or not trading is on. It may not be combined with the two older price entities. engie_dynamic, totalenergies_dynamic and eneco_eddy are withdrawn and refuse to start: their endpoints never existed. They stay in the list only so such a site gets that explanation. - **Supplier markup** (`price_markup_eur_kwh`): under manual_csv, whose prices are all in, it is ignored and logged as ignored. @@ -1612,6 +1614,7 @@ help - see "Why the tuning is what it is". |---|---| | `peak_forecast_entity` | Quarter-hour demand forecast, for capacity-tariff markets. Empty = no cap | | `peak_cap_w` | The site's capacity-tariff target | +| `peak_margin_w` (50) | Watts the peak guard aims under `peak_cap_w` (SAFETY-79). Reports and the bill use `peak_cap_w` itself | | `peak_soc_floor` (20) | **The percent below which the capacity-peak guard will not discharge the battery.** ⚠️ It bounds **the peak guard only** — it is **not a pack-wide reserve**, and ordinary self-consumption discharges straight past it (SAFETY-25, see below). Not optional and not the same thing as `maintenance_soc_floor` | | `bms_soc_floor` (10) | The pack's **own** cut-out percent, the number the BMS enforces whatever you set above. `peak_soc_floor` must be **strictly above** it or the add-on refuses to start. ⚠️ **At a declared `inverters:` roster this key moves INTO each entry and is REQUIRED there** (SAFETY-32): it describes a battery, and two packs of different models have different cut-outs, so one number for both protects the shallower pack with the deeper pack's BMS. Nothing is inherited — an entry that omits it is refused **by name** at startup, and the flat key below is then not read at all | | `price_now_entity`, `price_avg_entity` | Dynamic tariff. Empty = never force a paid grid top-up | diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 4cdaaf2..754f0c3 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -893,6 +893,10 @@ class Controller: # every option family this file builds: no numeric fallback in main.py # that config.yaml has not shipped. self.peak_guard = None + # SAFETY-79. The guard aims this far under `peak_cap_w`; the bill and + # every report keep the real cap (`self.peak.cap_w`). + self.peak_margin_w = float(opts.get( + "peak_margin_w", peakguard.PEAK_OPTION_DEFAULTS["peak_margin_w"])) self._peak_engaged = False self._peak_saturated = False self._peak_floor_limited = False @@ -1823,6 +1827,11 @@ class Controller: """ return float(sum(inv.rating_w() for inv in self.inverters)) + def peak_aim_w(self) -> float: + """SAFETY-79. `peak_cap_w` less `peak_margin_w`: what the forecast + checks aim at. Reports and the bill use the real cap.""" + return float(self.o.get("peak_cap_w", 3500)) - self.peak_margin_w + def site_dev_bound(self, which: str): """The roster's summed device floor / ceiling, or None if unknown. @@ -3390,6 +3399,7 @@ class Controller: # fraction of the discharge already happening. batt_w=self.site_batt_w, cap_w=float(self.o.get("peak_cap_w", 3500)), + margin_w=self.peak_margin_w, reading=self.peak.peak(now), # ⚠️ SUMMED FROM THE PER-UNIT CONJUNCTION, WHICH IS AC 4. Each # unit contributes `min(its max_w, |its own device bounds|)`, so @@ -3650,8 +3660,7 @@ class Controller: # charge together, this flag would have to become per-pack - and # so would the reasoning above it. if peakguard.shaping_suspended( - self.peak_guard, self.peak_fc, - float(self.o.get("peak_cap_w", 3500))): + self.peak_guard, self.peak_fc, self.peak_aim_w()): # Edge-logged: level-logging here would write one line per # cycle for as long as the event lasts and flush the 40-line # action log of the very context that explains it. @@ -3678,7 +3687,7 @@ class Controller: # rate the pack in front of us is charging at. floor = maintenance_charge_floor( self.maint.cfg.charge_w, - self.peak_fc, float(self.o.get("peak_cap_w", 3500))) + self.peak_fc, self.peak_aim_w()) if floor > 0: hi, reason = -floor, "cheap-window charge" # PER-INVERTER, like the SET above and for the same reason - diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 1481a54..81e471b 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -1152,6 +1152,7 @@ LABELS = { "integrator_max_w": "Catch-up limit", "maintenance_discharge_w": "Draw-down rate", "peak_cap_w": "Peak limit", + "peak_margin_w": "Margin below the peak limit", "peak_forecast_entity": "15-minute demand forecast entity", "meter_entity": "Grid power entity", "soc_entity": "Battery level entity", diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index 0276899..eb1d70b 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -143,6 +143,10 @@ because the money is spent on `max(month's peak so far, this quarter)`: ceiling_w = max(peak_cap_w, the month's banked peak) +SAFETY-79: the guard AIMS at `max(peak_cap_w - peak_margin_w, banked peak)` +(`quarter_target_w()`), so a quarter that lands a little high still stays under +the cap. `ceiling_w` stays the real limit for reports and the bill. + Once a month's peak already stands at 5013 W, holding every later quarter to 3500 W buys nothing - the bill for that month is already 5013 W - while the holding itself costs real charging the site wanted. Raising the ceiling to a peak @@ -453,7 +457,13 @@ PEAK_OPTION_DEFAULTS = { # and it is consistent with DoD 90 on a full pack. It exists so validate.py # rule 8 can refuse a `peak_soc_floor` at or below it - see that rule. "bms_soc_floor": 10, + # SAFETY-79. Watts the guard aims under `peak_cap_w`, so a quarter that + # lands a little high still stays under the cap. Owner decision 2026-09-28. + "peak_margin_w": 50, } +# SAFETY-79. config.yaml's schema range for `peak_margin_w`, mirrored so +# validate.py can refuse it in words; test_peakguard.py pins it to the file. +PEAK_MARGIN_RANGE_W = (0, 500) @dataclass(frozen=True) @@ -474,6 +484,7 @@ class PeakDecision: projected_w: float | None = None excess_w: float = 0.0 wanted_w: float | None = None # the floor before `achievable_w` clamped it + target_w: float | None = None # SAFETY-79: what the guard aims at saturated: bool = False # SAFETY-24. True when a forced discharge WAS wanted and the EMS-side SoC # floor refused to size it. Mutually exclusive with `saturated` by @@ -524,6 +535,13 @@ def quarter_ceiling_w(cap_w, reading) -> tuple[float, str]: return cap, CEILING_CAP +def quarter_target_w(cap_w, margin_w, reading) -> float: + """SAFETY-79. The average the guard AIMS at: `quarter_ceiling_w()` with the + cap lowered by `margin_w`. A month peak already paid for is aimed at as it + stands. Reports and the bill keep the real cap (`ceiling_w`).""" + return quarter_ceiling_w(float(cap_w) - float(margin_w), reading)[0] + + def excess_w(projection, ceiling_w) -> float: """Watts that must come off the meter NOW to land the quarter on the ceiling. @@ -713,8 +731,8 @@ def binding_soc_floor(packs, soc_floor): return max(floors) -def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, - max_hold_s=None, frozen: bool = False) -> PeakDecision: +def decide(projection, *, batt_w, cap_w, margin_w, reading, achievable_w, soc, + soc_floor, max_hold_s=None, frozen: bool = False) -> PeakDecision: """The whole guard. Pure: no clock, no I/O, no state carried between calls. `batt_w` MEASURED battery power, positive = discharge. None when the @@ -732,8 +750,13 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, the pack for money. REQUIRED, and deliberately without a default: a default here would be CFG-03's fourth defaults site and TEST-14's quiet fallback in one line. + `margin_w` SAFETY-79. Watts to aim under `cap_w` (`peak_margin_w`). + REQUIRED for the same reason. `ceiling_w` stays the real + limit for every report; only `excess_w` uses the target. """ ceiling, from_where = quarter_ceiling_w(cap_w, reading) + target = quarter_target_w(cap_w, margin_w, reading) + aim = "" if target == ceiling else f", aiming at {target:.0f} W" ceil_top = abs(float(achievable_w)) blind = blindness(projection, max_hold_s, frozen) @@ -743,7 +766,7 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, # see", which is one-directional and cannot cost pack energy. return PeakDecision( engaged=True, floor_w=0.0, ceiling_w=ceiling, ceiling_from=from_where, - blind=blind, projected_w=None, + target_w=target, blind=blind, projected_w=None, reason=(f"PEAK_GUARD_BLIND: {blind}. The battery may not charge " f"while this 15-minute period cannot be measured, so it " f"is asked for no charging, floor 0 W")) @@ -755,7 +778,7 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, # measurement that is not there is a made-up number. return PeakDecision( engaged=False, floor_w=None, ceiling_w=ceiling, - ceiling_from=from_where, projected_w=projected, + ceiling_from=from_where, target_w=target, projected_w=projected, reason="no battery measurement to size a floor from") if QUARTER_S - float(projection.elapsed_s) <= 0.0: # A block with no seconds left cannot be influenced. This is degenerate @@ -763,10 +786,10 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, # the battery's own current output would be a claim that says nothing. return PeakDecision( engaged=False, floor_w=None, ceiling_w=ceiling, - ceiling_from=from_where, projected_w=projected, + ceiling_from=from_where, target_w=target, projected_w=projected, reason="the quarter has no seconds left to influence") - ex = excess_w(projection, ceiling) + ex = excess_w(projection, target) wanted = float(batt_w) + ex if wanted <= 0.0: # ⚠️ THE TEST IS ON THE FLOOR, NOT ON `excess > 0`, AND THE REPLAY IS WHY. @@ -787,7 +810,8 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, # the quantity being thresholded is simply the right one. return PeakDecision( engaged=False, floor_w=None, ceiling_w=ceiling, - ceiling_from=from_where, projected_w=projected, excess_w=ex, + ceiling_from=from_where, target_w=target, projected_w=projected, + excess_w=ex, wanted_w=wanted, reason="the load is under the level this quarter can afford") @@ -805,7 +829,8 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, # not the grid-following loop, which still has no SoC guard. return PeakDecision( engaged=True, floor_w=0.0, ceiling_w=ceiling, - ceiling_from=from_where, projected_w=projected, excess_w=ex, + ceiling_from=from_where, target_w=target, projected_w=projected, + excess_w=ex, wanted_w=wanted, floor_limited=True, soc=soc, soc_floor=soc_floor, soc_floor_reason=denied, # UX-10: plain sentences, every figure kept (test_messages.py @@ -813,8 +838,8 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, reason=( f"PEAK_GUARD_FLOOR_LIMITED: this 15-minute period heads for " f"{projected:.0f} W against a {ceiling:.0f} W limit " - f"({from_where}), and {wanted:+.0f} W from the battery would " - f"hold it. But {denied}" + f"({from_where}){aim}, and {wanted:+.0f} W from the battery " + f"would hold it. But {denied}" + ("" if soc is None else f", at {float(soc):.0f} %") + ("" if soc is None or soc_floor is None else f" against {float(soc_floor):.0f} %") @@ -825,11 +850,11 @@ def decide(projection, *, batt_w, cap_w, reading, achievable_w, soc, soc_floor, saturated = floor < wanted return PeakDecision( engaged=True, floor_w=floor, ceiling_w=ceiling, ceiling_from=from_where, - blind=None, projected_w=projected, excess_w=ex, wanted_w=wanted, - saturated=saturated, soc=soc, soc_floor=soc_floor, + target_w=target, blind=None, projected_w=projected, excess_w=ex, + wanted_w=wanted, saturated=saturated, soc=soc, soc_floor=soc_floor, reason=( f"PEAK_GUARD: this 15-minute period heads for {projected:.0f} W " - f"against a {ceiling:.0f} W limit ({from_where}), with " + f"against a {ceiling:.0f} W limit ({from_where}){aim}, with " f"{QUARTER_S - projection.elapsed_s:.0f} s left, so {ex:.0f} W must " f"come off the meter. The battery measured {float(batt_w):+.0f} W " f"and is asked for {floor:+.0f} W" diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 4b36fe2..e3ca7c5 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -13,7 +13,7 @@ "inverters.modes": {"name": "Battery modes"}, "tariff.selling": {"name": "Charging and selling on price"}, "tariff.feed": {"name": "Price feed details"}, - "safety.peak": {"name": "Peak limit"}, + "safety.peak": {"name": "Peak limit", "description": "The add-on aims a little below your limit, to be safe."}, "safety.start": {"name": "Starting and stopping"}, "safety.stops": {"name": "Safety stops", "description": "Measured on real hardware, so leave them unchanged."}, "maintenance.support": {"name": "Support"} diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 11b2ec3..3f0cb61 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -13,7 +13,7 @@ "inverters.modes": {"name": "Batterijmodi"}, "tariff.selling": {"name": "Laden en verkopen op prijs"}, "tariff.feed": {"name": "Details van de prijsfeed"}, - "safety.peak": {"name": "Piekgrens"}, + "safety.peak": {"name": "Piekgrens", "description": "De add-on mikt iets onder uw grens, voor de zekerheid."}, "safety.start": {"name": "Starten en stoppen"}, "safety.stops": {"name": "Veiligheidsstops", "description": "Gemeten op echte hardware, dus laat ze zoals ze zijn."}, "maintenance.support": {"name": "Support"} diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index 9c7f00a..63add7e 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -181,6 +181,7 @@ GROUPS = ( Part("peak", ( Field("peak_cap_w", SLIDER, "kW", scale=1000, step=100, simple=True, wizard=5), + Field("peak_margin_w", SLIDER, "W", step=10), # SAFETY-79 Field("peak_forecast_entity", ENTITY, kind="power_w", wizard=5), Field("peak_soc_floor", LOCKED, "%"), )), diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 525e94b..0b8b269 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -243,6 +243,9 @@ NOT READY banner already names the problem, (b) does not apply. note below on `gain`, which is the term that owns that and which SAFETY-39 measured and did not change. + 12. `peak_margin_w` outside 0-500 W, not whole, or not below `peak_cap_w`. + SAFETY-79; the Supervisor checks the range too, but not for sim/inject.py. + WHAT IS DELIBERATELY *NOT* REFUSED, because it is untidy rather than unsafe: - `integrator_max_w` above `max_w`. DOCS.md is right that the only thing the @@ -333,7 +336,7 @@ from .inverter import roster_entries from .maintenance import MAINT_OPTION_DEFAULTS from .p1 import ( SOURCE_HA, SOURCE_HA_SIGNED, is_enabled, validate_meter_options) -from .peakguard import PEAK_OPTION_DEFAULTS +from .peakguard import PEAK_MARGIN_RANGE_W, PEAK_OPTION_DEFAULTS from .price import ( PRICE_OPTION_DEFAULTS, PROVIDERS, RETIRED_PROVIDERS, SUPERSEDED_TAXES_DEFAULTS_EUR_KWH) @@ -1194,6 +1197,9 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None, f"reserve above {bms_floor:.0f} %, or correct the cut-out " "level.") + # --- 12. SAFETY-79: the margin the peak guard keeps under the limit ----- + problems += _margin_problems(opts) + # --- warnings: real, but not worth refusing over ------------------------- integ = opts.get("integrator_max_w") integ_w = None if not integ else _number(opts, "integrator_max_w", None) @@ -2022,6 +2028,23 @@ def _price_check(notes, opts, running, prices_known) -> None: "Prices are fetched after the restart, and Home shows them.") +def _margin_problems(opts: dict) -> list[str]: + """Rule 12: `peak_margin_w` is a whole number in the schema's range, and + below the peak limit, which would leave nothing to aim at.""" + raw = opts.get("peak_margin_w") + margin = _number(opts, "peak_margin_w", + PEAK_OPTION_DEFAULTS["peak_margin_w"]) + lo, hi = PEAK_MARGIN_RANGE_W + if margin is None or margin != int(margin) or not lo <= margin <= hi: + return [f"{S('peak_margin_w')} must be a whole number from {lo} to " + f"{hi} W. It is {messages.shown(raw)}."] + cap = _number(opts, "peak_cap_w", None) + if cap is not None and margin >= cap: + return [f"{S('peak_margin_w')} is {margin:.0f} W, not below the " + f"{S('peak_cap_w')} of {cap:.0f} W. Lower the margin."] + return [] + + def _number(opts: dict, key, default): raw = opts.get(key, default) if raw is None or raw == "": diff --git a/goodwe_controller/config.yaml b/goodwe_controller/config.yaml index 6744977..4c332f6 100644 --- a/goodwe_controller/config.yaml +++ b/goodwe_controller/config.yaml @@ -290,6 +290,8 @@ options: # protects the shallower pack with the deeper pack's number. bms_soc_floor: 10 peak_cap_w: 3500 + # SAFETY-79: the peak guard aims this many watts under peak_cap_w. + peak_margin_w: 50 peak_forecast_entity: "" # The peak guard can COMMAND a discharge to hold a billed quarter under @@ -1019,6 +1021,7 @@ schema: max_w: int(100,5000) bms_soc_floor: int(0,50) peak_cap_w: int(500,15000) + peak_margin_w: int(0,500) peak_forecast_entity: str? # SAFETY-24. No "off" value: a guard that can command a discharge does not get diff --git a/goodwe_controller/test_arbitrage.py b/goodwe_controller/test_arbitrage.py index 9a40478..5faf5c6 100644 --- a/goodwe_controller/test_arbitrage.py +++ b/goodwe_controller/test_arbitrage.py @@ -1039,7 +1039,7 @@ def s45_loop(*, sized: bool, cap_w=S45_CAP_W, load_w=S45_LOAD_W, now = t0 + timedelta(seconds=t) claims = [] pk = _pg.decide(PeakTracker.project(avg, now), batt_w=batt, - cap_w=cap_w, reading=None, achievable_w=MAX_W, + cap_w=cap_w, margin_w=0.0, reading=None, achievable_w=MAX_W, soc=50.0, soc_floor=20.0, max_hold_s=900.0, frozen=False) pc = _pg.claim(pk) @@ -1380,7 +1380,7 @@ def _s47_headroom(*, meter_w, batt_w, elapsed_s=450.0): t += 5.0 pk = _pg.decide( PeakTracker.project(avg, S45_T0 + timedelta(seconds=elapsed_s)), - batt_w=batt_w, cap_w=S45_CAP_W, reading=None, achievable_w=MAX_W, + batt_w=batt_w, cap_w=S45_CAP_W, margin_w=0.0, reading=None, achievable_w=MAX_W, soc=50.0, soc_floor=20.0, max_hold_s=900.0, frozen=False) return _pg.charge_headroom_w(pk) diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 543bc03..c6654e4 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -964,7 +964,7 @@ def _peak_texts(): proj = Projection(projected_w=4338.0, elapsed_w=4338.0, elapsed_s=799.0, covered_frac=1.0, complete=False, block_start=_T0, held_w=0.0) - kw = dict(cap_w=3500.0, reading=None, soc_floor=30.0, max_hold_s=30.0) + kw = dict(cap_w=3500.0, margin_w=0.0, reading=None, soc_floor=30.0, max_hold_s=30.0) sat = _pg.decide(proj, batt_w=1500.0, achievable_w=5000.0, soc=80.0, **kw) low = _pg.decide(proj, batt_w=1500.0, achievable_w=5000.0, soc=20.0, **kw) unread = _pg.decide(proj, batt_w=1500.0, achievable_w=5000.0, soc=None, **kw) diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py new file mode 100644 index 0000000..f333846 --- /dev/null +++ b/goodwe_controller/test_peak_margin.py @@ -0,0 +1,270 @@ +"""Runnable check for SAFETY-79, the margin under the peak limit. +`python3 test_peak_margin.py` + +The peak guard aims at `peak_cap_w - peak_margin_w` (default 50 W); the bill +and every report keep the real `peak_cap_w`. DECISIONS/SAFETY-79-peak-margin.md +has the record. Drives the REAL Controller through tools/safety79_identity.py. + +1. `peak_margin_w: 0` is byte-identical to release/1.0 ed739d4. +2. The guard aims at cap - margin at N=1 and N=2, and with OPT-11 modes on an + Off battery covers the shortfall to cap - margin. +3. The bill and the reports still use the real cap. +4. Each call site in main.py passes the value its side needs. +5. The setting: default, range, refusals in plain words. +""" + +import ast +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) + +import safety79_identity as rig # noqa: E402 +from named_absence import nth, present # noqa: E402 +from style_rules import text_problems # noqa: E402 +from app import messages, peakguard # noqa: E402 +from app.control import maintenance_charge_floor # noqa: E402 +from app.peakguard import (PEAK_MARGIN_RANGE_W, # noqa: E402 + PEAK_OPTION_DEFAULTS, quarter_target_w) +from app.validate import config_notes, validate_startup_config # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +CAP = float(rig.CAP_W) + +# ============================================================================ # +print("1. peak_margin_w 0: byte-identical to release/1.0 ed739d4") +# Printed by `python3 tools/safety79_identity.py 0` on the ed739d4 tree (the +# tool copied in, nothing else changed; that tree ignores the key), in the CI +# image, 2026-09-28. 540 cycles each: every command, the loop and arbiter +# sentences, the allocation, and the guard's floor, limit and sentence. +ED739D4 = { + "n1": "36f2dc6cd82ed63b93125dc3f8ea5f475e494255c614a4d2f353dad06e44f884", + "n2": "1d388daf1bcfc3e16b1ef696377ae2a01831963374e2a6a4d2f998b5c6d997c2", + "n1_off": "76e41db45667fffebd3ce99a49873a31d0b86fcc0c520057bbf38cc4f27138ca", + "n2_off": "196653957e2fdf227daa42447ac170c45292e6c3f4184196dd99c1140359e415", +} +_zero = rig.digests(0) +_default = rig.digests() +for k in ED739D4: + print(f" {k:7} margin 0 {'same' if _zero[k] == ED739D4[k] else 'DIFFERS'}" + f" {_zero[k][:16]}, default {_default[k][:16]}") +check("⭐ at N=1 and N=2, with and without battery modes, margin 0 is " + "byte-identical to ed739d4", _zero == ED739D4) +check("...and the default (key absent) changes every scenario, so the " + "scenarios do reach the margin", all(_default[k] != ED739D4[k] + for k in ED739D4)) + +# ============================================================================ # +print("\n2. the guard aims at cap - margin") +_runs = {} +for name, spec in rig.SCENARIOS.items(): + for m in (None, 0, 120): + _runs[name, m] = rig.run(**spec, margin=m, dur=3600.0) +for name in rig.SCENARIOS: + g = _runs[name, None][1].peak_guard + print(f" {name}: margin {_runs[name, None][1].peak_margin_w:.0f} W, " + f"aims at {g.target_w:.0f} W, limit {g.ceiling_w:.0f} W") +check("test_target_is_cap_minus_margin: with the key absent every scenario " + "(N=1, N=2, modes on and off) aims at cap - 50 and reports the cap", + all(_runs[n, None][1].peak_margin_w == 50.0 + and _runs[n, None][1].peak_guard.target_w == CAP - 50 + and _runs[n, None][1].peak_guard.ceiling_w == CAP + for n in rig.SCENARIOS)) +check("...and a margin of 120 moves the aim to cap - 120, a margin of 0 to " + "the cap", all(_runs[n, 120][1].peak_guard.target_w == CAP - 120 + and _runs[n, 0][1].peak_guard.target_w == CAP + for n in rig.SCENARIOS)) + + +def banked(ctl): + return {b.start.strftime("%H:%M"): round(b.offtake_avg_w, 2) + for b in ctl.p1.blocks} + + +_b = {m: banked(_runs["n1_off", m][1]) for m in (0, None, 120)} +print(f" N=1, the battery Off: quarters banked {_b}") +check("test_off_battery_n1: at N=1 with the battery Off, the guard makes it " + "give just enough to bank the 11:30 quarter at cap - margin (2500, " + "2450, 2380 W for margins 0, 50, 120)", + [_b[m]["11:30"] for m in (0, None, 120)] + == [CAP, CAP - 50, CAP - 120]) + + +def meter_at(rows, t): + row = next((r for r in rows if r[0] == t), None) + if row is None: + return None, {} + return rig.load(t) - sum(w for _u, w in row[2]), dict(row[2]) + + +_g0, _c0 = meter_at(_runs["n2_off", 0][0], 1800.0) +_g50, _c50 = meter_at(_runs["n2_off", None][0], 1800.0) +print(f" N=2, B Off, 6000 W house: margin 0 -> {_c0}, meter {_g0} W; " + f"margin 50 -> {_c50}, meter {_g50} W") +check("test_off_battery_n2: at N=2 with B Off and A at its rating, B covers " + "the shortfall to cap - margin, not to the cap", + _c0["b"] == 1000.0 and _g0 == CAP + and _c50["b"] == 1050.0 and _g50 == CAP - 50) + +_obs = type("R", (), {"is_observed": True, "peak_w": 2480.0})() +check("test_month_peak_not_lowered: a month peak already paid for is aimed " + "at as it stands (2480 W with cap 2500, margin 50), and a higher one " + "too; no peak aims at cap - margin", + quarter_target_w(CAP, 50, _obs) == 2480.0 + and quarter_target_w(CAP, 50, + type("R", (), {"is_observed": True, + "peak_w": 3000.0})()) == 3000.0 + and quarter_target_w(CAP, 50, None) == CAP - 50) + +# ============================================================================ # +print("\n3. the bill and the reports keep the real cap") +_c = _runs["n1_off", None][1] +_pk = _c.peak.peak().peak_w +print(f" month peak {_pk:.0f} W, tracker cap {_c.peak.cap_w:.0f} W, " + f"warning {_c.peak.warning_frac():.3f}, headroom " + f"{_c.peak.headroom_w():.0f} W") +check("test_billing_uses_cap: the month-peak tracker (bill, headroom, 80 % " + "warning) is built on the real cap, not cap - margin", + _c.peak.cap_w == CAP and _c.peak.warning_frac() == _pk / CAP + and _c.peak.headroom_w() == CAP - _pk) +_eng = [g for r in _runs["n1_off", None][0] for g in (r[-1],) + if g and g[0] and g[1]] +print(f" {len(_eng)} engaged cycles; one: {_eng[0][4] if _eng else None}") +check("test_reports_use_cap: every engaged sentence names the real limit and " + "the aim beside it", _eng and all( + g[2] == CAP and "against a 2500 W limit (peak_cap_w), aiming at " + "2450 W" in g[4] for g in _eng)) +check("...and the settings note compares the month peak with the real cap: " + "a 2480 W peak under a 2500 W cap is no warning, 2520 W is", + config_notes({"peak_cap_w": 2500, "peak_margin_w": 50}, + month_peak_w=2480) == [] + and [n.keys for n in config_notes({"peak_cap_w": 2500, + "peak_margin_w": 50}, + month_peak_w=2520)] + == [("peak_cap_w",)]) +_lim = _eng[0][2] if _eng else 0.0 +_notice = messages.peak_saturated(_lim) +check("...and the user-facing peak notice built from the decision's limit " + "says the cap", messages.watts(CAP) in _notice.body + and messages.watts(CAP - 50) not in _notice.body) + +# ============================================================================ # +print("\n4. each call site in main.py") +with open(os.path.join(HERE, "app", "main.py"), encoding="utf-8") as f: + _src = f.read() +_tree = ast.parse(_src) + + +def calls(name): + return [n for n in ast.walk(_tree) if isinstance(n, ast.Call) + and isinstance(n.func, (ast.Attribute, ast.Name)) + and getattr(n.func, "attr", getattr(n.func, "id", "")) == name] + + +def kw(call, key): + if not present(call): + return "absent" + return next((ast.get_source_segment(_src, k.value) for k in call.keywords + if k.arg == key), "absent") + + +def arg(call, i): + if not present(call) or len(call.args) <= i: + return "absent" + return ast.get_source_segment(_src, call.args[i]) + + +_dec = [c for c in calls("decide") + if getattr(c.func, "value", None) is not None + and getattr(c.func.value, "id", "") == "peakguard"] +_shape = calls("shaping_suspended") +_maint = calls("maintenance_charge_floor") +_tracker = calls("PeakTracker") +_d, _s, _m, _t = (nth(_dec, 0, "peakguard.decide()"), + nth(_shape, 0, "shaping_suspended()"), + nth(_maint, 0, "maintenance_charge_floor()"), + nth(_tracker, 0, "PeakTracker()")) +print(f" decide(cap_w={kw(_d, 'cap_w')}, margin_w={kw(_d, 'margin_w')})") +print(f" shaping_suspended(..., {arg(_s, 2)})") +print(f" maintenance_charge_floor(..., {arg(_m, 2)})") +print(f" PeakTracker(cap_w={kw(_t, 'cap_w')})") +check("test_call_sites: the guard gets the real cap AND the margin; the " + "forecast checks get cap - margin; the month-peak tracker gets the " + "real cap", + len(_dec) == 1 and "peak_cap_w" in kw(_d, "cap_w") + and kw(_d, "margin_w") == "self.peak_margin_w" + and len(_shape) == 1 and len(_maint) == 1 + and arg(_s, 2) == "self.peak_aim_w()" + and arg(_m, 2) == "self.peak_aim_w()" + and len(_tracker) == 1 + and kw(_t, "cap_w") == 'float(opts.get("peak_cap_w", 3500))') +check("test_aim_w: `peak_aim_w()` is cap - margin, and the forecast sizing " + "gives a maintenance charge only what is left under it", + _c.peak_aim_w() == CAP - 50 + and maintenance_charge_floor(2000.0, 2400.0, _c.peak_aim_w()) == 50.0 + and peakguard.shaping_suspended(None, 2470.0, _c.peak_aim_w()) + and not peakguard.shaping_suspended(None, 2470.0, CAP)) + +# ============================================================================ # +print("\n5. the setting") + + +def _cfg_pair(key): + """(default, schema) lines for `key` at two spaces in config.yaml.""" + with open(os.path.join(HERE, "config.yaml"), encoding="utf-8") as f: + hits = re.findall(rf"^ {key}:\s*(\S+)", f.read(), re.M) + return hits + + +_hits = _cfg_pair("peak_margin_w") +print(f" config.yaml: {_hits}") +check("config.yaml ships 50, int(0,500), and the in-code mirror matches", + _hits == ["50", "int(0,500)"] + and PEAK_OPTION_DEFAULTS["peak_margin_w"] == 50 + and PEAK_MARGIN_RANGE_W == (0, 500)) + +BASE = {"setpoint_entity": "number.sp", "meter_entity": "sensor.grid", + "max_w": 2000, "peak_cap_w": 3500} +_base_problems = validate_startup_config(BASE) + + +def refused(value, **more): + opts = dict(BASE, peak_margin_w=value, **more) + return [p for p in validate_startup_config(opts) + if p not in _base_problems] + + +_ok = {v: refused(v) for v in (0, 50, 500)} +_bad = {v: refused(v) for v in (-1, 501, 12.5, "abc")} +for v, p in _bad.items(): + print(f" {v!r}: {p}") +check("test_margin_range: 0, 50 and 500 are accepted, and so is the key " + "absent", not any(_ok.values()) and _base_problems == []) +check("...and below 0, above 500, not whole, or not a number is refused, " + "once, naming the setting and the range", + all(len(p) == 1 and "“Margin below the peak limit” (peak_margin_w)" + in p[0] and "from 0 to 500 W" in p[0] for p in _bad.values())) +_high = refused(500, peak_cap_w=500) +print(f" 500 under a 500 W limit: {_high}") +check("...and a margin that leaves nothing under the limit is refused", + len(_high) == 1 and "not below" in _high[0]) +_style = [text_problems(p[0], keys=("peak_margin_w", "peak_cap_w"), + entities=False) for p in list(_bad.values()) + [_high]] +check(f"...in plain words (STYLE.md): {_style}", not any(_style)) + + +print() +if fails: + print(f"{len(fails)} FAILED: {', '.join(fails)}") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 53ae9b0..4e653b3 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -368,7 +368,7 @@ check("...and it grows monotonically through the quarter, so the guard is at " BATT_NOW = 400.0 a_edge = averager_at(CEIL, 450.0) p_edge = PeakTracker.project(a_edge, B + timedelta(seconds=450)) -d_edge = decide(p_edge, batt_w=BATT_NOW, cap_w=CAP_W, reading=None, +d_edge = decide(p_edge, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) e_edge = excess_w(p_edge, CEIL) print(f" held exactly AT the ceiling for 450 s: projected " @@ -383,7 +383,7 @@ check("at the engagement boundary the excess is zero, so the floor is exactly " # than on the excess. Re-derived here rather than described: a guard that # released as soon as `excess <= 0` hands the actuator back at the exact instant # it is working, and the load springs straight back. -released = decide(p_edge, batt_w=BATT_NOW, cap_w=CAP_W, reading=None, +released = decide(p_edge, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) would_release_on_excess = excess_w(p_edge, CEIL) <= 0.0 # ⚠️ `floor_w` IS FORMATTED DEFENSIVELY, AND MUTATION.md's OWN LEDGER IS WHY. @@ -404,7 +404,7 @@ check("...and the claim is held there, not released. `excess` falls to zero as " "arithmetic read as a level", would_release_on_excess and released.engaged) d_gone = decide(PeakTracker.project(averager_at(500.0, 450.0), B + timedelta(seconds=450)), - batt_w=BATT_NOW, cap_w=CAP_W, reading=None, + batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) check("...and it DOES release once the load falls under what the quarter can " "afford, so 'threshold the floor' is not 'never let go'", @@ -413,7 +413,7 @@ check("...and it DOES release once the load falls under what the quarter can " # A hair over, and the floor is the battery plus the excess. Not a constant. a_over = averager_at(CEIL + 200.0, 450.0) p_over = PeakTracker.project(a_over, B + timedelta(seconds=450)) -d_over = decide(p_over, batt_w=BATT_NOW, cap_w=CAP_W, reading=None, +d_over = decide(p_over, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) print(f" 200 W over for 450 s: {d_over.explain()}") check("a quarter projected over the ceiling engages, and the floor is the " @@ -422,7 +422,7 @@ check("a quarter projected over the ceiling engages, and the floor is the " and near(d_over.floor_w, BATT_NOW + excess_w(p_over, CEIL), 1e-6)) check("...and the floor moves with the battery measurement, so it is a claim " "about delivered power rather than a fixed setpoint", - not near(decide(p_over, batt_w=BATT_NOW + 250.0, cap_w=CAP_W, reading=None, + not near(decide(p_over, batt_w=BATT_NOW + 250.0, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR).floor_w, d_over.floor_w, 1.0)) @@ -433,7 +433,7 @@ intent = 0.0 delivered_floor = [] intent_floor = [] for _ in range(5): - d_del = decide(p_over, batt_w=stuck_batt, cap_w=CAP_W, reading=None, + d_del = decide(p_over, batt_w=stuck_batt, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) delivered_floor.append(d_del.floor_w) intent = intent + excess_w(p_over, CEIL) # what the intent form would do @@ -516,7 +516,7 @@ check(f"a loop already discharging harder ({BIG:.0f} W) than the floor is not " absurd = averager_at(LIVE_MAX_W * 4, 870.0) p_absurd = PeakTracker.project(absurd, B + timedelta(seconds=870)) DEV_MAX = LIVE_MAX_W - 500.0 # a device rating tighter than max_w -d_absurd = decide(p_absurd, batt_w=1000.0, cap_w=CAP_W, reading=None, +d_absurd = decide(p_absurd, batt_w=1000.0, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=min(LIVE_MAX_W, DEV_MAX), max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) r6 = resolve([Claim.limit("device", P_SAFETY, -DEV_MAX, DEV_MAX, "rating"), Claim.limit("supervised", P_SAFETY, -LIVE_MAX_W, LIVE_MAX_W, "max_w"), @@ -599,7 +599,7 @@ print(f" a real PeakStore on a missing volume: state={rd_broken.state}, " f"headroom_w()={tr_broken.headroom_w(B)}") check("the real store answers NOT_OBSERVED rather than a peak of 0 W", rd_broken.state == NOT_OBSERVED and rd_broken.peak_w is None) -d_broken = decide(p_over, batt_w=BATT_NOW, cap_w=CAP_W, reading=rd_broken, +d_broken = decide(p_over, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=rd_broken, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) print(f" {d_broken.explain()}") check("AND THE GUARD STILL ENGAGES ON IT. An unreadable peak must not disarm " @@ -627,7 +627,7 @@ print("4. blindness: three ways a projection is not evidence") # (a) NO OPEN BLOCK. A fresh averager projects 0 W - under every ceiling. fresh = QuarterAverager(phases=1, max_hold_s=MAX_HOLD_S) p_fresh = PeakTracker.project(fresh, B) -d_fresh = decide(p_fresh, batt_w=0.0, cap_w=CAP_W, reading=None, +d_fresh = decide(p_fresh, batt_w=0.0, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) print(f" fresh averager: projected {p_fresh.projected_w:.0f} W, " f"block_start={p_fresh.block_start}; {d_fresh.explain()}") @@ -655,7 +655,7 @@ p_frozen = PeakTracker.project(frozen_av, B + timedelta(seconds=600)) RAILED = LIVE_MAX_W # the loop has wound to the rail is_frozen = looks_frozen(FREEZE_S + 1.0, -RAILED, LIVE_MAX_W, FreezeWatchdogConfig(hold_s=FREEZE_S)) -d_frozen = decide(p_frozen, batt_w=-RAILED, cap_w=CAP_W, reading=None, +d_frozen = decide(p_frozen, batt_w=-RAILED, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR, frozen=is_frozen) print(f" meter stuck at -4000 W with the command at {-RAILED:+.0f} W: " @@ -680,7 +680,7 @@ check("...and the same command NOT frozen is left alone, so the blind branch is "not simply always on", near(resolve(SAFE + [Claim.set("loop", P_LOOP, -RAILED, "grid"), peakguard.claim(decide( - p_frozen, batt_w=-RAILED, cap_w=CAP_W, + p_frozen, batt_w=-RAILED, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR, frozen=False)) or Claim.limit("noop", P_PEAK)]).target_w, @@ -692,7 +692,7 @@ gapped = averager_at(4200.0, 600.0, gap_at=200.0, gap_s=GAP) p_gap = PeakTracker.project(gapped, B + timedelta(seconds=600)) clean = averager_at(4200.0, 600.0) p_clean = PeakTracker.project(clean, B + timedelta(seconds=600)) -d_gap = decide(p_gap, batt_w=0.0, cap_w=CAP_W, reading=None, +d_gap = decide(p_gap, batt_w=0.0, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) print(f" a {GAP:.0f} s hole at 4200 W: uncovered {uncovered_s(p_gap):.0f} s, " f"projected {p_gap.projected_w:.0f} W vs {p_clean.projected_w:.0f} W with " @@ -756,7 +756,7 @@ check("a renamed held value now raises AttributeError on the first cycle. The " OLD = (p_held.partial_ws if hasattr(p_held, "partial_ws") else HELD * 300.0) # acc, which the old form would still have had old_projected = (HELD * 300.0 + 0.0 * (QUARTER_S - 300.0)) / QUARTER_S -d_true = decide(p_held, batt_w=0.0, cap_w=CAP_W, reading=None, +d_true = decide(p_held, batt_w=0.0, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) print(f" same fixture: shipped projection {p_held.projected_w:.0f} W " f"(engaged={d_true.engaged}), the defaulted form's " @@ -832,7 +832,7 @@ def replay(path, *, guarded: bool, cap_w=CAP_W, max_w=LIVE_MAX_W, pack=None, next_cycle = t + timedelta(seconds=CYCLE_S) cycles += 1 d = decide(PeakTracker.project(ing.averager, t), - batt_w=batt, cap_w=cap_w, reading=tracker.peak(t), + batt_w=batt, cap_w=cap_w, margin_w=0.0, reading=tracker.peak(t), achievable_w=max_w, max_hold_s=MAX_HOLD_S, soc=soc, soc_floor=floor_pct, frozen=False) if d.floor_w is not None and d.floor_w < 0.0: @@ -1417,7 +1417,8 @@ check("B3: main.py sizes the floor from the MEASURED battery power, not from " # `datetime.now()`. Every number below therefore comes from ONE instant, and the # tolerances that used to absorb the wall clock are gone. _proj3 = _seen["projection"] -_kw = dict(cap_w=CAP_W, reading=b3.peak.peak(), achievable_w=LIVE_MAX_W, +_kw = dict(cap_w=CAP_W, margin_w=b3.peak_margin_w, reading=b3.peak.peak(), + achievable_w=LIVE_MAX_W, max_hold_s=b3.p1.averager.max_hold_s, soc=SOC_OK, soc_floor=SOC_FLOOR) _intent = _shipped_decide(_proj3, batt_w=STANDING, **_kw) @@ -1554,7 +1555,8 @@ check("SAFETY-24 adds exactly the two keys it names and no more: §14's kW/W " "trap `capacity_peak_limit_kw` stays declined, and no speculative " "`peak_guard`/`peak_shave` block appeared beside it", _peak_keys == [] - and sorted(PEAK_OPTION_DEFAULTS) == ["bms_soc_floor", "peak_soc_floor"]) + and sorted(PEAK_OPTION_DEFAULTS) == ["bms_soc_floor", "peak_margin_w", + "peak_soc_floor"]) # + SAFETY-79 # Graded on the parsed call syntax, not on the text: the module docstring names # `peak_cap_w` while arguing that it does not read it, so a grep would be # satisfied by deleting the explanation and would fail on writing one. @@ -1634,13 +1636,13 @@ check("...and the defaulting form that was ACTUALLY shipped once in this " discharge_permitted(float(None or 100), SOC_FLOOR) is None) # --- the decision ----------------------------------------------------------- -d_ok = decide(p_hungry, batt_w=BATT_NOW, cap_w=CAP_W, reading=None, +d_ok = decide(p_hungry, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) -d_lim = decide(p_hungry, batt_w=BATT_NOW, cap_w=CAP_W, reading=None, +d_lim = decide(p_hungry, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_FLOOR, soc_floor=SOC_FLOOR) -d_unread = decide(p_hungry, batt_w=BATT_NOW, cap_w=CAP_W, reading=None, +d_unread = decide(p_hungry, batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=None, soc_floor=SOC_FLOOR) print(f" with battery: {d_ok.explain()}") @@ -1682,7 +1684,7 @@ check("floor-limited and saturated are MUTUALLY EXCLUSIVE, by construction: the # notification that matters. d_quiet = decide(PeakTracker.project(averager_at(500.0, 450.0), B + timedelta(seconds=450)), - batt_w=BATT_NOW, cap_w=CAP_W, reading=None, + batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_FLOOR - 5.0, soc_floor=SOC_FLOOR) print(f" an EMPTY pack on a quiet quarter: {d_quiet.explain()}") @@ -1694,7 +1696,7 @@ check("an empty pack on a quarter that does not need shaving is IDLE, not " and d_quiet.floor_w is None) # And the BLIND branch is untouched: it never forces a discharge, so there is # nothing for an energy floor to bound there. -d_blind_low = decide(p_frozen, batt_w=-RAILED, cap_w=CAP_W, reading=None, +d_blind_low = decide(p_frozen, batt_w=-RAILED, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_FLOOR - 5.0, soc_floor=SOC_FLOOR, frozen=True) check("...and an empty pack does not disturb the BLIND branch either: SAFETY-" @@ -1751,7 +1753,7 @@ for load in (0.0, CEIL - 500.0, CEIL, CEIL + 300.0, CEIL + 3000.0, for bw in (-2000.0, 0.0, 400.0, 4000.0): for sc in (None, 0.0, BMS_FLOOR, SOC_FLOOR, SOC_FLOOR + 0.5, 100.0): for fl in (SOC_FLOOR, BMS_FLOOR + 1.0, 55.0): - _d = decide(_pr, batt_w=bw, cap_w=CAP_W, reading=None, + _d = decide(_pr, batt_w=bw, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=sc, soc_floor=fl) SWEEP_N += 1 @@ -1798,8 +1800,8 @@ check("`soc` and `soc_floor` are REQUIRED keyword-only arguments of decide() " "with no default. A default on either is TEST-14's exact shape and would " "be the quiet fallback this card exists to remove - and a default on " "`soc_floor` would additionally be CFG-03's fourth defaults site", - _required_kw == {"batt_w", "cap_w", "reading", "achievable_w", "soc", - "soc_floor"}) + _required_kw == {"batt_w", "cap_w", "margin_w", "reading", + "achievable_w", "soc", "soc_floor"}) _req_fields = tuple(f.name for f in dataclasses.fields(PeakDecision) if f.default is dataclasses.MISSING and f.default_factory is dataclasses.MISSING) @@ -1948,7 +1950,7 @@ check("...and it reaches the action log too", any("FLOOR_LIMITED" in e for e in c24.events)) # A missing SoC sensor, through the same real cycle. `inputs_ok` stops the loop # at 0 W in that state, so the guard's own answer is what is graded here. -d_nosoc = decide(p_hungry, batt_w=0.0, cap_w=CAP_W, reading=None, +d_nosoc = decide(p_hungry, batt_w=0.0, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=None, soc_floor=SOC_FLOOR) check("decide() handed soc=None answers floor-limited rather than a full " @@ -2226,7 +2228,7 @@ def replay_loop(window, *, start_soc, soc_floor, usable_wh=REF_PACK_WH): next_cycle = t + timedelta(seconds=CYCLE_S) cycles += 1 d = decide(PeakTracker.project(ing.averager, t), batt_w=batt, - cap_w=CAP_W, reading=tracker.peak(t), + cap_w=CAP_W, margin_w=0.0, reading=tracker.peak(t), achievable_w=LOOP_MAX_W, max_hold_s=MAX_HOLD_S, soc=soc, soc_floor=soc_floor, frozen=False) dec = compute(prev_w, w - batt, batt, LOOP_TUNING, sat_count=sat, @@ -5462,7 +5464,7 @@ MUT.append(("blindness() returns None - the degenerate 0 W projection is graded" # 2. the frozen term dropped from the guard's inputs. MUT.append(("frozen=False - SAFETY-18's term dropped", - not decide(p_frozen, batt_w=-RAILED, cap_w=CAP_W, reading=None, + not decide(p_frozen, batt_w=-RAILED, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR, frozen=False).engaged and d_frozen.engaged, "part 4: 'THE BACKSTOP: SAFETY-18's runaway ... cut to 0 W'")) @@ -5533,7 +5535,7 @@ _early = sum(1 for _t in (500.0, 1000.0, 2000.0) if discharge_permitted(SOC_FLOOR - 1.0, SOC_FLOOR) is not None and not decide(PeakTracker.project( averager_at(_t, 450.0), B + timedelta(seconds=450)), - batt_w=BATT_NOW, cap_w=CAP_W, reading=None, + batt_w=BATT_NOW, cap_w=CAP_W, margin_w=0.0, reading=None, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_FLOOR - 1.0, soc_floor=SOC_FLOOR).engaged) MUT.append((f"the SoC gate moved above the `wanted > 0` test ({_early} quiet " @@ -5963,7 +5965,7 @@ print("13. SAFETY-38 round 4: the ORDERED PAIR inside PeakDecision.explain()") _S38_PROJ = PeakTracker.project(averager_at(CAP_W - 1200.0, 450.0), B + timedelta(seconds=450)) _S38_CEIL_W, _S38_CEIL_FROM = quarter_ceiling_w(CAP_W, obs_hi) -_S38_IDLE = decide(_S38_PROJ, batt_w=0.0, cap_w=CAP_W, reading=obs_hi, +_S38_IDLE = decide(_S38_PROJ, batt_w=0.0, cap_w=CAP_W, margin_w=0.0, reading=obs_hi, achievable_w=LIVE_MAX_W, max_hold_s=MAX_HOLD_S, soc=SOC_OK, soc_floor=SOC_FLOOR) # UX-08 2d: the row is in plain words now, and the pair is still ordered. @@ -6042,7 +6044,7 @@ def _proj_at(net_w, elapsed): def _decide_on(projection, *, batt_w, soc=SOC_OK, cap_w=CAP_W, achievable_w=LIVE_MAX_W, reading=None, frozen=False): - return decide(projection, batt_w=batt_w, cap_w=cap_w, reading=reading, + return decide(projection, batt_w=batt_w, cap_w=cap_w, margin_w=0.0, reading=reading, achievable_w=achievable_w, soc=soc, soc_floor=SOC_FLOOR, max_hold_s=MAX_HOLD_S, frozen=frozen) diff --git a/goodwe_controller/tools/replay_ac3.py b/goodwe_controller/tools/replay_ac3.py index f11de9a..92bae6a 100644 --- a/goodwe_controller/tools/replay_ac3.py +++ b/goodwe_controller/tools/replay_ac3.py @@ -176,7 +176,7 @@ def replay(paths, *, guarded: bool, cap_w, max_w, max_hold_s, cycle_s, next_cycle = t + timedelta(seconds=cycle_s) cycles += 1 d = decide(PeakTracker.project(ing.averager, t), batt_w=batt, - cap_w=cap_w, reading=tracker.peak(t), + cap_w=cap_w, margin_w=0.0, reading=tracker.peak(t), achievable_w=max_w, max_hold_s=max_hold_s, soc=soc, soc_floor=soc_floor, frozen=False) if d.engaged: diff --git a/goodwe_controller/tools/safety79_identity.py b/goodwe_controller/tools/safety79_identity.py new file mode 100644 index 0000000..c93cdaa --- /dev/null +++ b/goodwe_controller/tools/safety79_identity.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +"""SAFETY-79: with `peak_margin_w: 0`, is every command byte-identical to before? + + python3 tools/safety79_identity.py # prints one digest per scenario + +tools/opt11_identity.py's harness (the REAL Controller, read_inputs + cycle, in +simulated time) with a P1 meter, so the peak guard runs, and a peak limit the +house goes over. Each row hashes opt11_identity's fields plus the guard's floor, +limit and sentence. It uses only the API release/1.0 ed739d4 already had, so +the same file runs on the old tree (which ignores `peak_margin_w`) and the new. +test_peak_margin.py part 1 holds the new tree to the digests printed on ed739d4. +""" + +import functools +import hashlib +import os +import sys +import tempfile +import time +from datetime import timedelta + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +from app import packmode # noqa: E402 +from app.p1 import make_sample, split_signed # noqa: E402 +from app.store import unit_key # noqa: E402 + +CAP_W = 2500 + + +def load(t): + """A house under the limit, over it, a solar surplus, far over, over.""" + if t < 300: + return 800.0 + if t < 900: + return 3200.0 + if t < 1500: + return -2600.0 + if t < 2100: + return 6000.0 + return 4200.0 + + +def soc(u, t): + return 60.0 # above the peak reserve: the guard may discharge + + +def _feed(c, t): + """One P1 telegram per cycle: the meter reads what the house and the + batteries' measured power leave.""" + imp, exp = split_signed(c.hass.grid()) + c.p1.submit(make_sample("ha_signed", imp, exp, phases=1, + ingest_ts=rig.BASE + timedelta(seconds=t), + ingest_mono=time.monotonic())) + + +def store_off(name): + """A store where battery `name` is switched Off (OPT-11).""" + s = rig._Store() + s.data[unit_key(name, packmode.USE_KEY)] = False + return s + + +P1 = {"meter_source": "ha_signed", "p1_net_entity": "sensor.net", + "meter_phases": 1, "peak_cap_w": CAP_W} +MODES = {"battery_modes_enabled": True} + +SCENARIOS = { + "n1": dict(n=1), + "n2": dict(n=2), + # OPT-11: the only battery Off, so only the peak guard makes it give. + "n1_off": dict(n=1, modes=True, off="inverter-a"), + # OPT-11: B Off, so B covers what A cannot. + "n2_off": dict(n=2, modes=True, off="inverter-b"), +} + + +def run(n, *, margin=None, modes=False, off=None, dur=2700.0): + """Rows for one scenario; `margin=None` leaves the key out.""" + extra = dict(P1, **(MODES if modes else {})) + if margin is not None: + extra["peak_margin_w"] = margin + guard = [] + + def on_cycle(c, t): + g = c.peak_guard + guard.append(None if g is None else (g.engaged, g.floor_w, g.ceiling_w, + g.ceiling_from, g.reason)) + db = os.path.join(tempfile.mkdtemp(prefix="s79-"), "tariff.db") + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + try: + rows, c = rig.run(n, extra=extra, dur=dur, load=load, soc=soc, + cut=lambda u, t: False, before=_feed, + on_cycle=on_cycle, + store=store_off(off) if off else None) + finally: + rig.Controller = real + return [r + (g,) for r, g in zip(rows, guard)], c + + +def digest(rows) -> str: + return hashlib.sha256(repr(rows).encode()).hexdigest() + + +def digests(margin=None) -> dict: + return {k: digest(run(**v, margin=margin)[0]) for k, v in SCENARIOS.items()} + + +if __name__ == "__main__": + m = None if len(sys.argv) < 2 else int(sys.argv[1]) + for k, v in digests(m).items(): + print(f"{k} {v}") diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index 7fdf628..db33d5b 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -145,6 +145,9 @@ configuration: peak_cap_w: name: "Limits · Peak limit (W)" description: "Your own number: the 15-minute average power the add-on keeps the grid under. Take it from your grid contract." + peak_margin_w: + name: "Limits · Margin below the peak limit (W)" + description: "The add-on aims this much below the peak limit, so a 15-minute period that ends a little high still stays under it." peak_forecast_entity: name: "Limits · 15-minute demand forecast entity (W)" description: "Optional. A forecast of this 15-minute period's average power. Leave it empty and there is no peak limit." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index 65e7881..e9b4e6d 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -126,6 +126,9 @@ configuration: peak_cap_w: name: "Grenzen · Piekgrens (W)" description: "Uw eigen getal: het gemiddelde vermogen per kwartier waaronder de add-on de afname houdt. Neem het over uit uw netcontract." + peak_margin_w: + name: "Grenzen · Marge onder de piekgrens (W)" + description: "De add-on mikt zoveel onder de piekgrens, zodat een kwartier dat iets hoger uitvalt er toch onder blijft." peak_forecast_entity: name: "Grenzen · Entiteit kwartierprognose (W)" description: "Optioneel. Een prognose van het gemiddelde vermogen in het lopende kwartier. Laat u dit leeg, dan is er geen piekgrens." -- 2.54.0 From b310282729ba146d142a4e6f5c345d7d7970a352 Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Mon, 28 Sep 2026 23:12:04 +0200 Subject: [PATCH 070/105] OPT-11 P2: HA entities for battery modes Each battery gets an MQTT-discovered Mode select and Use switch, only while battery_modes_enabled is true. Commands go through handle_action(), the /action path; refusals are logged once. Retained commands are never applied. Turning modes off removes exactly the configs announced (kept in the store). With modes off the announcement is byte-identical to ed739d4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 7 + goodwe_controller/DOCS.md | 4 + goodwe_controller/app/main.py | 74 ++- goodwe_controller/app/messages.py | 5 + goodwe_controller/app/mqtt.py | 186 +++++++- goodwe_controller/app/packmode.py | 6 + goodwe_controller/test_messages.py | 4 +- goodwe_controller/test_mqtt.py | 450 +++++++++++++++++- 8 files changed, 716 insertions(+), 20 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 0f7bfba..39f02b2 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -17,5 +17,12 @@ P1 is its section 6 P1, and the pull request lists what was measured. capped grid charge release an Off battery. Both are graded in `test_arbiter.py` part 11. The loop bound leaves a side that reaches the rail to the rail, so SAFETY-03 still flags a loop winding into it. +- P2 (HA entities): a select and a switch per battery, only while modes are + on; commands go through `handle_action()`, the page's path. A retained + command is dropped, not applied: the store already holds the last choice, + and a replay after a restart could otherwise undo a newer one. The config + topics announced are kept in the store (`mqtt_mode_configs`), so turning + modes off removes exactly those, and an install that never turned them on + publishes what ed739d4 did (`test_mqtt.py` part 10). - In P1 only Off closes a direction; Leftover solar differs by charging last. Price runs, selling (`pack_sell`, reserved) and the forecast are P3/P4. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 4f36859..059fdde 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -522,6 +522,10 @@ Off by default. Turn it on, restart the add-on, and the Batteries screen gives e The peak limit, the safety stops and the monthly cycle always come before a battery's mode. +**In Home Assistant.** With MQTT set up, each battery also gets a *Mode* list and a *Use* switch, for example `select.goodwe_inverter_a_mode` and `switch.goodwe_inverter_a_use`. They do the same as the Batteries screen. Turn battery modes off and restart, and they are removed. + +*For installers:* commands arrive on `goodwe_ctl/unit/<battery>/mode/set` (a *Mode* option, such as `Solar first`) and `.../use/set` (`ON` or `OFF`). They go through the same checks as the Batteries screen, and a refusal is logged once. A retained command is never applied, so the broker cannot replay an old choice after a restart; the add-on keeps the last choice itself. + *For installers:* a mode is a limit at priority 35, kept apart from the hard limits. It gives way only as far as a limit above it (the peak guard) needs. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. ### Reading the grid-following loop: `Loop integrator`, `Loop integrator lead`, `Loop reason` diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 4cdaaf2..b700dd5 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -72,7 +72,9 @@ from .maintenance import ( IDLE, POWER_MOVING, MaintConfig, Maintenance, MaintResult, arbitrate as maint_arbitrate, ) -from .mqtt import (MqttPublisher, announced_units, optional_keys, unit_slugs, +from .mqtt import (MODE_CONFIGS_KEY, MODE_LABELS, USE_OFF, USE_ON, + MqttPublisher, announced_units, mode_payloads, + mode_retractions, optional_keys, parse_command, unit_slugs, unit_state_key) from . import peakguard from . import packshare @@ -901,9 +903,11 @@ class Controller: # turned them on behaves exactly as before (SAFETY-10 section 1). Each # battery's mode and on/off switch live in the store, not in options, # so a change applies at once (`pack_use`, `pack_mode` actions). - self.modes_on = opts.get("battery_modes_enabled") is True + self.modes_on = packmode.enabled(opts) # The units whose mode fault is logged already (edge-logged). self._mode_faults = set() + # OPT-11 P2: (topic, reason) of MQTT commands refused and logged once. + self._mqtt_refused = set() # [(pack name, why)] for packs that are due and waiting their turn. # Empty at a roster of one, where nothing can defer anything. self._maint_deferred = [] @@ -2053,6 +2057,56 @@ class Controller: pm = self.pack_mode(inv) return {"unit": inv.name, "use": pm.use, "mode": pm.mode} + def mode_values(self) -> dict: + """OPT-11 P2: each battery's mode and switch, for their HA state + topics. Read from the store, so they are right after a restart. Empty + while battery modes are off.""" + if not self.modes_on: + return {} + out = {} + names = [inv.name for inv in self.inverters] + for inv, slug in zip(self.inverters, unit_slugs(names)): + pm = self.pack_mode(inv) + out[unit_state_key(slug, "mode")] = MODE_LABELS.get(pm.mode, + pm.mode) + out[unit_state_key(slug, "use")] = USE_ON if pm.use else USE_OFF + return out + + async def mqtt_command(self, topic, payload, retained) -> None: + """OPT-11 P2: one command from a battery's HA switch or mode list. + + It goes through handle_action(), the page's /action path, so the + checks and the store write are the same. A retained command (one the + broker replays on subscribe, e.g. after a restart) is never applied: + the store already holds the last choice. A refusal is logged once per + topic and reason. Never raises: MQTT must not reach control. + """ + try: + slug, action, value, why = parse_command( + topic, payload, retained, packmode.MODES) + if why is None: + names = [inv.name for inv in self.inverters] + unit = dict(zip(unit_slugs(names), names)).get(slug) + result = await self.handle_action(action, unit=unit, + value=value) + if not (isinstance(result, dict) and "error" in result): + self.mqtt.publish(self.mode_values()) + return + why = result["error"] + else: + why = messages.pack_refused(why) + topic_s = str(topic)[:128] + _LOG.debug("Home Assistant command %s %s refused: %s", topic_s, + repr(payload)[:48], why) + if (topic_s, why) in self._mqtt_refused \ + or len(self._mqtt_refused) >= 32: + return + self._mqtt_refused.add((topic_s, why)) + _LOG.warning("Home Assistant command on %s ignored: %s", topic_s, + why) + except Exception: # noqa: BLE001 + _LOG.exception("Home Assistant command could not be handled") + def _maint_stop_off(self, machine, now) -> None: """OPT-11: stop this battery's maintenance cycle because it is off.""" if machine.phase == IDLE: @@ -5144,6 +5198,8 @@ class Controller: values[unit_state_key(slug, "soc")] = inv.soc values[unit_state_key(slug, "sign_latch")] = ( "tripped" if inv.sign_wd.tripped else "clear") + # OPT-11 P2: each battery's mode and switch; nothing while modes are off. + values.update(self.mode_values()) self.mqtt.publish(values) async def shutdown(self) -> None: @@ -6189,6 +6245,16 @@ async def amain() -> None: # took the control loop down with it. broker = None try: + # OPT-11 P2: each battery's switch and mode list, only while + # battery modes are on. The config topics are kept in the store, + # so turning modes off removes exactly the ones announced. + _modes = packmode.MODES if packmode.enabled(opts) else () + _mode_cfgs = [t for t, _ in mode_payloads(roster_names(opts), + _modes)] + _retract = mode_retractions(store.data.get(MODE_CONFIGS_KEY), + _mode_cfgs) + if _modes: + store.set(MODE_CONFIGS_KEY, _mode_cfgs) broker = await hass.mqtt_service() pub = MqttPublisher( broker.get("host") if broker else None, @@ -6208,6 +6274,8 @@ async def amain() -> None: # is what `build_roster()` itself reads. At a roster of one this # announces nothing new - see `announced_units()`. units=roster_names(opts), + modes=_modes, + retract=_retract, ) except Exception as err: # noqa: BLE001 _LOG.warning("MQTT unavailable (%s) - continuing without status entities", err) @@ -6221,6 +6289,8 @@ async def amain() -> None: stop = asyncio.Event() controller = Controller(opts, hass, store, pub, stop=stop) + if callable(getattr(pub, "bind", None)): + pub.bind(asyncio.get_running_loop(), controller.mqtt_command) runner = await web.start(controller, port=INGRESS_PORT) loop = asyncio.get_running_loop() diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 1481a54..e9dfac1 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -932,6 +932,11 @@ PACK_REFUSED = { "off": "Battery modes are off. Turn on “Battery modes” first.", "unit": "There is no battery with that name.", "value": "That choice is not possible for this battery.", + # OPT-11 P2: a Home Assistant command dropped before it reaches a battery. + "retained": "A saved command is not used after a restart.", + "size": "That command is too long.", + "encoding": "That command is not plain text.", + "topic": "That is not a battery command.", } diff --git a/goodwe_controller/app/mqtt.py b/goodwe_controller/app/mqtt.py index 94fc13d..91da048 100644 --- a/goodwe_controller/app/mqtt.py +++ b/goodwe_controller/app/mqtt.py @@ -7,8 +7,10 @@ That separation is deliberate; observability must never be able to take down control. """ +import asyncio import json import logging +import re try: import paho.mqtt.client as mqtt @@ -375,7 +377,26 @@ def _payload(name, object_id, unique_id, state_topic, device, return cfg -def discovery_payloads(units=(), omit=(), include=()) -> list: +def unit_unique_id(slug: str, key: str) -> str: + """One unit's entity `unique_id` (also its config topic's middle part).""" + return f"{BASE}_unit_{slug}_{key}" + + +def _unit_places(names): + """`(slug, device, prefix)` for each roster name, in order.""" + slugs = unit_slugs(names) + for i, (name, slug) in enumerate(zip(names, slugs)): + # ⚠️ `i == 0` IS THE ASYMMETRY, IN ONE LINE. The first roster entry + # keeps the device it already has and carries its name in the ENTITY + # name instead; every later one gets its own device and does not. + # Either way HA composes device-name + entity-name into the same + # string, which is why `object_id` can be written once for both. + device = DEVICE if i == 0 else unit_device(name, slug) + prefix = f"{_title(name)} " if i == 0 else "" + yield slug, device, prefix + + +def discovery_payloads(units=(), omit=(), include=(), modes=()) -> list: """Every `(topic, payload)` this add-on announces, in announcement order. Split out of `_announce()` so that the acceptance criterion can be graded as @@ -389,6 +410,8 @@ def discovery_payloads(units=(), omit=(), include=()) -> list: the output here (`_payload()`'s note, and test_mqtt.py part 1 asserts an ordered LIST precisely because a re-order is a zero-byte edit that re-announces every entity on a live install). + + `modes` (OPT-11 P2) is the battery modes offered, empty when they are off. """ omit = set(omit) include = [k for k in include if k not in omit] @@ -400,19 +423,10 @@ def discovery_payloads(units=(), omit=(), include=()) -> list: f"homeassistant/sensor/{BASE}_{key}/config", _payload(name, object_id, f"{BASE}_{key}", f"{BASE}/{key}", DEVICE, unit, dev_class, state_class, icon))) - names = announced_units(units) - slugs = unit_slugs(names) site_slug = _slug(DEVICE["name"]) - for i, (name, slug) in enumerate(zip(names, slugs)): - # ⚠️ `i == 0` IS THE ASYMMETRY, IN ONE LINE. The first roster entry - # keeps the device it already has and carries its name in the ENTITY - # name instead; every later one gets its own device and does not. - # Either way HA composes device-name + entity-name into the same - # string, which is why `object_id` below can be written once for both. - device = DEVICE if i == 0 else unit_device(name, slug) - prefix = f"{_title(name)} " if i == 0 else "" + for slug, device, prefix in _unit_places(announced_units(units)): for key, oid, label, unit, dev_class, state_class, icon in UNIT_SENSORS: - unique_id = f"{BASE}_unit_{slug}_{key}" + unique_id = unit_unique_id(slug, key) out.append(( f"homeassistant/sensor/{unique_id}/config", _payload(prefix + label, @@ -427,12 +441,124 @@ def discovery_payloads(units=(), omit=(), include=()) -> list: f"homeassistant/sensor/{BASE}_{key}/config", _payload(name, object_id, f"{BASE}_{key}", f"{BASE}/{key}", DEVICE, unit, dev_class, state_class, icon))) + # OPT-11 P2: last, and only when battery modes are on. + out.extend(mode_payloads(units, modes)) return out +# --- OPT-11 P2: each battery's switch and mode, as HA entities --------------- +# Announced only when battery modes are on, after every other row, so no +# existing row moves. A command goes through Controller.handle_action(), the +# page's /action path. DECISIONS/OPT-11-battery-modes.md has the record. +# +# The select's options are these labels, in `packmode.MODES` order. A new mode +# (P3) is a new entry here and a new option at the end; no id changes. +MODE_LABELS = {"solar_first": "Solar first", "leftover_solar": "Leftover solar"} +USE_ON, USE_OFF = "ON", "OFF" +# A longer command payload is refused before it is decoded. +MAX_COMMAND_BYTES = 64 +# The store key holding the mode config topics last announced, so that turning +# modes off can remove exactly those (an empty retained config) and an install +# that never turned them on publishes nothing new. +MODE_CONFIGS_KEY = "mqtt_mode_configs" +_MODE_CONFIG_RE = re.compile( + rf"homeassistant/(select|switch)/{BASE}_unit_[a-z0-9_]+_(mode|use)/config") +_COMMAND_RE = re.compile(rf"{BASE}/unit/([a-z0-9_]+)/(mode|use)/set") +# (entity key, HA component, entity name, icon) +MODE_ENTITIES = [ + ("mode", "select", "Mode", "mdi:battery-sync"), + ("use", "switch", "Use", "mdi:power"), +] + + +def mode_payloads(units, modes) -> list: + """The `(topic, payload)` for each battery's select and switch. + + Every roster entry gets them, also at a roster of one. The device rule is + TEL-07's: the first battery's rows go on the site device with its name in + front, each later battery's on its own device. Empty when `modes` is empty. + """ + if not modes: + return [] + site_slug = _slug(DEVICE["name"]) + options = [MODE_LABELS[m] for m in modes] + out = [] + for slug, device, prefix in _unit_places([str(u) for u in units]): + for key, component, label, icon in MODE_ENTITIES: + unique_id = unit_unique_id(slug, key) + state = f"{BASE}/{unit_state_key(slug, key)}" + cfg = { + "name": prefix + label, + "object_id": f"{site_slug}_{slug}_{key}", + "unique_id": unique_id, + "state_topic": state, + "command_topic": f"{state}/set", + } + if component == "select": + cfg["options"] = options + else: + cfg["payload_on"] = USE_ON + cfg["payload_off"] = USE_OFF + # HA sends commands unretained; a retained one is ignored anyway. + cfg["retain"] = False + cfg["availability_topic"] = AVAILABILITY + cfg["device"] = device + cfg["icon"] = icon + out.append((f"homeassistant/{component}/{unique_id}/config", cfg)) + return out + + +def mode_retractions(stored, current) -> list: + """Config topics announced before and not now: each gets an empty + retained config, which removes the entity from HA. Anything in the store + that is not one of our mode config topics is ignored.""" + if not isinstance(stored, list): + return [] + keep = set(current) + return [t for t in stored if isinstance(t, str) + and _MODE_CONFIG_RE.fullmatch(t) and t not in keep] + + +def parse_command(topic, payload, retained, modes): + """`(slug, action, value, reject)` for one message on a command topic. + + `action` is `pack_use` or `pack_mode`. `value` is what /action would be + sent: a bool for the switch, a mode key for the select, or None for a + payload that is neither (the store path then refuses it). `reject` is a + reason when the message is dropped here: replayed by the broker (retained), + too long, not UTF-8, or not a command topic. + """ + m = _COMMAND_RE.fullmatch(topic) if isinstance(topic, str) else None + if m is None: + return None, None, None, "topic" + slug, key = m.group(1), m.group(2) + action = "pack_use" if key == "use" else "pack_mode" + if retained: + return slug, action, None, "retained" + if not isinstance(payload, (bytes, bytearray)) \ + or len(payload) > MAX_COMMAND_BYTES: + return slug, action, None, "size" + try: + text = bytes(payload).decode("utf-8") + except UnicodeDecodeError: + return slug, action, None, "encoding" + if key == "use": + value = {USE_ON: True, USE_OFF: False}.get(text) + else: + value = next((k for k in modes if MODE_LABELS.get(k) == text), None) + return slug, action, value, None + + class MqttPublisher: + # OPT-11 P2. Class defaults, so a publisher built without them (and every + # test fixture that builds one with __new__) behaves as before. + modes = () + retract = () + _loop = None + _handler = None + def __init__(self, host, port, username=None, password=None, omit=(), - units=(), include=()): + units=(), include=(), modes=(), retract=()): # `omit` drops sensor keys from discovery entirely. ⚠️ Announcing a # sensor that nothing will ever publish to is not harmless here: # p1_sample_age_s is a watchdog input, and an entity that exists but is @@ -448,6 +574,10 @@ class MqttPublisher: # second reading of the option. Defaults to empty, so a caller that has # not been taught about it announces exactly what it announced before. self.include = [str(k) for k in include] + # OPT-11 P2: the modes offered (empty when battery modes are off), and + # the mode config topics to remove (`mode_retractions()`). + self.modes = tuple(modes) + self.retract = [str(t) for t in retract] self.enabled = mqtt is not None and bool(host) self.client = None if not self.enabled: @@ -470,7 +600,8 @@ class MqttPublisher: # paho DROPS QoS-0 publishes when disconnected, silently. The result is # an add-on that logs "MQTT connected" and creates no entities at all. # As a bonus, this also re-announces after every reconnect. - self.client.on_connect = lambda *_args, **_kw: self._announce() + self.client.on_connect = lambda *_args, **_kw: self._on_connect() + self.client.on_message = self._on_message try: self.client.connect(host, int(port), keepalive=60) self.client.loop_start() @@ -485,10 +616,35 @@ class MqttPublisher: # diffing what actually goes on the wire - and a payload built here # instead would be one this add-on publishes and no check has ever seen. for topic, cfg in discovery_payloads(self.units, self.omit, - self.include): + self.include, self.modes): self.client.publish(topic, json.dumps(cfg), retain=True) + for topic in self.retract: + self.client.publish(topic, "", retain=True) self.client.publish(AVAILABILITY, "online", retain=True) + def _on_connect(self) -> None: + self._announce() + if self.modes: + for key in ("mode", "use"): + self.client.subscribe(f"{BASE}/unit/+/{key}/set") + + def bind(self, loop, handler) -> None: + """OPT-11 P2: hand each command to `handler(topic, payload, retained)`, + a coroutine function run on `loop` (the controller's).""" + self._loop, self._handler = loop, handler + + def _on_message(self, _client, _userdata, msg) -> None: + # paho's network thread: nothing is done here but the handoff. + loop, handler = self._loop, self._handler + if loop is None or handler is None: + _LOG.debug("MQTT command before start-up ignored: %s", msg.topic) + return + try: + asyncio.run_coroutine_threadsafe( + handler(msg.topic, bytes(msg.payload), bool(msg.retain)), loop) + except RuntimeError as err: # the loop has closed + _LOG.debug("MQTT command dropped: %s", err) + def publish(self, values: dict) -> None: if not self.enabled or self.client is None: return diff --git a/goodwe_controller/app/packmode.py b/goodwe_controller/app/packmode.py index df2641d..a4989dd 100644 --- a/goodwe_controller/app/packmode.py +++ b/goodwe_controller/app/packmode.py @@ -42,6 +42,12 @@ MODE_KEY = "pack_mode" SELL_KEY = "pack_sell" # reserved for P3 +def enabled(opts) -> bool: + """Battery modes are on only when the option is exactly true. One answer, + read by the controller and by the MQTT announcement.""" + return opts.get("battery_modes_enabled") is True + + @dataclass(frozen=True) class PackMode: """One battery's choice: on or off, its mode, and (P3) selling.""" diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 543bc03..0e29a8d 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -845,7 +845,7 @@ DATA = { "main.py:'cancelled' if task.cancelled() else repr(exc) if exc else 'returned'", "main.py:EXIT_CONTROL_DIED", "main.py:first.name", "main.py:OPTIONS_PATH", "main.py:err", "main.py:', '.join(sorted(stranded))", - "main.py:sorted(on_roster)", "main.py:inv.name", + "main.py:sorted(on_roster)", "main.py:inv.name", "main.py:topic_s", "main.py:inv.batt_fresh.bound.release_s", "main.py:inv.batt_fresh.bound.move_w", "main.py:inv.batt_fresh.bound.unchanged_s", "main.py:inv.batt_fresh.held", "main.py:value", "main.py:float(value)", @@ -1058,6 +1058,8 @@ TEXT = { "main.py:rep.explain()": _migration_texts, "store.py:rep.explain()": _migration_texts, "main.py:plan.words": _tariff_texts, + # OPT-11 P2: why an MQTT command was ignored. + "main.py:why": lambda: list(messages.PACK_REFUSED.values()), # Families: every builder of the text, as a template. "main.py:refusal": lambda: (_static(("main.py", "return", "write_refusal")) + _static(("allocator.py", "return", "authorises"))), diff --git a/goodwe_controller/test_mqtt.py b/goodwe_controller/test_mqtt.py index 75da0d1..bf5f4fd 100644 --- a/goodwe_controller/test_mqtt.py +++ b/goodwe_controller/test_mqtt.py @@ -42,6 +42,7 @@ part is a diff against it, reported as `N topics, M missing, C changed, A added` re-executed from mutated source, each one named with the property it breaks. A property nothing breaks is a property nothing is watching. Part 9 What these checks CANNOT see, enumerated and sized. + Part 10 OPT-11 P2: each battery's select and switch, commands, removal. ⚠️ THE FIXTURE GIVES A AND B DIFFERENT NAMES, DIFFERENT RATINGS, DIFFERENT SoC, DIFFERENT BATTERY POWER AND DIFFERENT LATCH STATES, ON PURPOSE. A fixture whose @@ -821,8 +822,8 @@ MUTATIONS = [ ("per-unit entities announced at a roster of ONE", [("PER_UNIT_MIN_ROSTER = 2", "PER_UNIT_MIN_ROSTER = 1")]), ("the unit is dropped from the unique_id", - [('unique_id = f"{BASE}_unit_{slug}_{key}"', - 'unique_id = f"{BASE}_unit_{key}"')]), + [('return f"{BASE}_unit_{slug}_{key}"', + 'return f"{BASE}_unit_{key}"')]), ("the unit is dropped from the state topic", [('return f"unit/{slug}/{key}"', 'return f"unit/{key}"')]), ("the slug de-collision is removed (rule 9(c) does not cover this)", @@ -944,6 +945,451 @@ for line in [ ]: print(" " + line) +# --------------------------------------------------------------------------- +print("\n10. OPT-11 P2: each battery's switch and mode as HA entities") +# --------------------------------------------------------------------------- +import logging # noqa: E402 +import os # noqa: E402 +import tempfile # noqa: E402 + +from app import messages, packmode # noqa: E402 +from app.store import Store, unit_key # noqa: E402 + + +def announce_p2(units=(), omit=(), include=(), modes=(), retract=(), + module=mqtt): + """What `_on_connect()` sends: the announcement, then any subscriptions.""" + pub = module.MqttPublisher.__new__(module.MqttPublisher) + pub.omit, pub.units, pub.include = set(omit), [str(u) for u in units], \ + [str(k) for k in include] + pub.modes, pub.retract = tuple(modes), list(retract) + pub.enabled, pub.client = True, FakeClient() + subs = [] + pub.client.subscribe = lambda topic, *a: subs.append(topic) + pub._on_connect() + return pub.client.msgs, subs + + +# --- 10a. modes off: byte-identical to ed739d4 -------------------------------- +# The digest below is GENERATED from release/1.0 at ed739d4 (the base of this +# PR): the same matrix run through that commit's `_announce()`. Reproduce with +# `git show ed739d4:goodwe_controller/app/mqtt.py` and this loop. +ROSTERS = [[], ["inverter-a"], ["inverter-a", "inverter-b"], ["a", "b", "c"], + ["inverter-b", "Inverter B", "x", "y"], ["café"]] +ED739D4_OFF = "501a7d93782a260b" +_h, _n, _subs_off = hashlib.sha256(), 0, [] +for _r in ROSTERS: + for _om in [(), ("p1_age",), ("p1_age", "grid")]: + for _inc in [(), ("pv",)]: + _m, _s = announce_p2(_r, _om, _inc) + _h.update(repr(_m).encode()) + _subs_off += _s + _n += 1 +print(f" modes off, {_n} configurations: digest {_h.hexdigest()[:16]} " + f"(ed739d4: {ED739D4_OFF})") +check("modes off: every configuration announces byte-for-byte what ed739d4 " + "announces, in the same order, and subscribes to nothing", + _h.hexdigest()[:16] == ED739D4_OFF and not _subs_off) + + +# --- 10b. modes on: the ordered payload diff ---------------------------------- +MODES = packmode.MODES +ON1, SUB1 = announce_p2(["inverter-a"], modes=MODES) +m, c, a = report("roster of one, modes on", ON1) +_opt = '["Solar first", "Leftover solar"]' +MODE_N1 = [ + ("homeassistant/select/goodwe_ctl_unit_inverter_a_mode/config", + '{"name": "Inverter A Mode", "object_id": "goodwe_inverter_a_mode", ' + '"unique_id": "goodwe_ctl_unit_inverter_a_mode", ' + '"state_topic": "goodwe_ctl/unit/inverter_a/mode", ' + '"command_topic": "goodwe_ctl/unit/inverter_a/mode/set", ' + '"options": ' + _opt + ', "retain": false, ' + '"availability_topic": "goodwe_ctl/availability", "device": ' + _DEV + ', ' + '"icon": "mdi:battery-sync"}', True), + ("homeassistant/switch/goodwe_ctl_unit_inverter_a_use/config", + '{"name": "Inverter A Use", "object_id": "goodwe_inverter_a_use", ' + '"unique_id": "goodwe_ctl_unit_inverter_a_use", ' + '"state_topic": "goodwe_ctl/unit/inverter_a/use", ' + '"command_topic": "goodwe_ctl/unit/inverter_a/use/set", ' + '"payload_on": "ON", "payload_off": "OFF", "retain": false, ' + '"availability_topic": "goodwe_ctl/availability", "device": ' + _DEV + ', ' + '"icon": "mdi:power"}', True), +] +check("modes on at a roster of one: every existing message byte-identical and " + "in place, then exactly the select and the switch, then availability", + ON1 == SITE_NOW[:-1] + MODE_N1 + SITE_NOW[-1:]) +check("...and it subscribes to the two command topics, and nothing else", + SUB1 == ["goodwe_ctl/unit/+/mode/set", "goodwe_ctl/unit/+/use/set"]) + +ON2, _ = announce_p2(NAMES2, modes=MODES) +m, c, a = report("roster of two, modes on", ON2, TWO) +check("modes on at a roster of two: nothing missing or changed, four added, " + "and the modes-off list is an unchanged prefix", + (m, c) == ([], []) and len(a) == 4 and ON2[:len(TWO) - 1] == TWO[:-1] + and ON2[-1] == TWO[-1]) +_mc = cfgs(ON2)[-4:] +check("...A's two stay on the site device with its name in front; B's two are " + "on B's own device, as TEL-07's rule has it", + [c_["name"] for c_ in _mc] == ["Inverter A Mode", "Inverter A Use", + "Mode", "Use"] + and _mc[0]["device"] == mqtt.DEVICE == _mc[1]["device"] + and _mc[2]["device"] == _mc[3]["device"] + == mqtt.unit_device("inverter-b", "inverter_b")) +check("...unique_ids are stable per battery and distinct from every other id", + [c_["unique_id"] for c_ in _mc] + == ["goodwe_ctl_unit_inverter_a_mode", "goodwe_ctl_unit_inverter_a_use", + "goodwe_ctl_unit_inverter_b_mode", "goodwe_ctl_unit_inverter_b_use"] + and len({c_["unique_id"] for c_ in cfgs(ON2)}) == len(cfgs(ON2))) +_ids = [compose(c_["device"]["name"], c_["name"]).split(".", 1)[1] + for c_ in _mc] +print(f" composed ids: {_ids}") +check("...and HA composes the ids the design names: " + "goodwe_inverter_<x>_mode and goodwe_inverter_<x>_use", + _ids == ["goodwe_inverter_a_mode", "goodwe_inverter_a_use", + "goodwe_inverter_b_mode", "goodwe_inverter_b_use"]) +check("every mode has a plain label, in MODES order, and a later mode only " + "appends an option: no existing option or id changes", + all(k in mqtt.MODE_LABELS for k in MODES) + and len(set(mqtt.MODE_LABELS.values())) == len(mqtt.MODE_LABELS) + and json.loads(MODE_N1[0][1])["options"] + == [mqtt.MODE_LABELS[k] for k in MODES]) +_later = dict(mqtt.MODE_LABELS, cheap_hours="Cheap hours only") +_orig = mqtt.MODE_LABELS +mqtt.MODE_LABELS = _later +try: + _p3 = mqtt.mode_payloads(NAMES2, MODES + ("cheap_hours",)) +finally: + mqtt.MODE_LABELS = _orig +_p2 = mqtt.mode_payloads(NAMES2, MODES) +check("...(simulated P3: adding `cheap_hours` changes only the options list, " + "by one entry at its end)", + [t for t, _ in _p3] == [t for t, _ in _p2] + and all({k: v for k, v in x.items() if k != "options"} + == {k: v for k, v in y.items() if k != "options"} + for (_, x), (_, y) in zip(_p3, _p2)) + and _p3[0][1]["options"] == _p2[0][1]["options"] + ["Cheap hours only"]) + + +# --- 10c. modes turned off: removal ------------------------------------------ +_cur2 = [t for t, _ in mqtt.mode_payloads(NAMES2, MODES)] +_ret = mqtt.mode_retractions(_cur2, []) +OFF2, _subs = announce_p2(NAMES2, retract=_ret) +check("modes turned off: the modes-off list, then an EMPTY retained config " + "for each of the four, then availability, and no subscription", + OFF2 == TWO[:-1] + [(t, "", True) for t in _cur2] + TWO[-1:] + and not _subs) +check("...the store keeps what was announced, so a roster that shrinks removes " + "only the battery that left", + mqtt.mode_retractions(_cur2, [t for t, _ in + mqtt.mode_payloads(["inverter-a"], MODES)]) + == _cur2[2:]) +check("...and nothing from the store is removed that is not one of our mode " + "configs: a non-list, a number, a site sensor, another add-on's select", + mqtt.mode_retractions("homeassistant/select/x/config", []) == [] + and mqtt.mode_retractions( + [3, None, "homeassistant/sensor/goodwe_ctl_grid/config", + "homeassistant/select/other_mode/config", + "homeassistant/select/goodwe_ctl_unit_a_mode/config/x", + "homeassistant/select/goodwe_ctl_unit_a_mode/config"], []) + == ["homeassistant/select/goodwe_ctl_unit_a_mode/config"]) + + +# --- 10d. state topics, from the store ---------------------------------------- +_tmp = tempfile.mkdtemp() +OPTS2M = dict(OPTS2, battery_modes_enabled=True) + + +def ctl_for(opts, path): + pub = _Pub() + pub.sent = [] + pub.publish = lambda values, _p=pub: (_p.sent.append(dict(values)), + setattr(_p, "last", dict(values))) + return Controller(dict(opts), None, Store(path), pub, + stop=asyncio.Event()), pub + + +_path = os.path.join(_tmp, "state.json") +ctlm, pubm = ctl_for(OPTS2M, _path) +ctlm.publish() +_fed = {f"{mqtt.BASE}/{k}" for k in pubm.last + if k.endswith("/mode") or k.endswith("/use")} +check("every announced mode entity is fed, and nothing else is: the state " + "topics published are exactly the ones announced", + _fed == {c_["state_topic"] for c_ in _mc}) +check("...defaults with nothing in the store: both On, both Solar first", + [pubm.last[k] for k in ("unit/inverter_a/mode", "unit/inverter_a/use", + "unit/inverter_b/mode", "unit/inverter_b/use")] + == ["Solar first", "ON", "Solar first", "ON"]) +_c_off, _p_off = ctl_for(dict(OPTS2, battery_modes_enabled=False), + os.path.join(_tmp, "off2.json")) +_c_off.publish() +_c_abs, _p_abs = ctl_for(OPTS2, os.path.join(_tmp, "off3.json")) +_c_abs.publish() +check("modes off (false or absent): the controller publishes the same keys as " + "before, with no mode or switch topic", + set(_p_off.last) == set(_p_abs.last) == set(vals2) + and not [k for k in _p_off.last if k.endswith(("/mode", "/use"))]) + + +# --- 10e. commands: the /action path, validated ------------------------------- +class _Logs(logging.Handler): + def __init__(self): + super().__init__(logging.DEBUG) + self.rows = [] + + def emit(self, record): + self.rows.append((record.levelno, record.getMessage())) + + +_logs = _Logs() +logging.getLogger("goodwe").addHandler(_logs) +logging.getLogger("goodwe").setLevel(logging.DEBUG) +_calls = [] +_real_handle = ctlm.handle_action + + +async def _spy(what, **kw): + _calls.append((what, kw)) + return await _real_handle(what, **kw) + + +ctlm.handle_action = _spy + + +def cmd(topic, payload, retained=False, ctl=None): + ctl = ctl or ctlm + asyncio.run(ctl.mqtt_command(topic, payload, retained)) + + +def stored(ctl=None): + d = (ctl or ctlm).store.data + return {k: d.get(k) for k in (unit_key("inverter-a", "pack_use"), + unit_key("inverter-a", "pack_mode"), + unit_key("inverter-b", "pack_use"), + unit_key("inverter-b", "pack_mode"))} + + +T_A = "goodwe_ctl/unit/inverter_a" +T_B = "goodwe_ctl/unit/inverter_b" +pubm.sent.clear() +cmd(f"{T_B}/use/set", b"OFF") +cmd(f"{T_A}/mode/set", b"Leftover solar") +check("good commands go through handle_action() with the /action arguments", + _calls == [("pack_use", {"unit": "inverter-b", "value": False}), + ("pack_mode", {"unit": "inverter-a", + "value": "leftover_solar"})]) +check("...and reach the store under P1's keys, and nowhere else", + stored() == {unit_key("inverter-a", "pack_use"): None, + unit_key("inverter-a", "pack_mode"): "leftover_solar", + unit_key("inverter-b", "pack_use"): False, + unit_key("inverter-b", "pack_mode"): None}) +check("...and the state topics say so at once, from the store", + pubm.sent and pubm.sent[-1] == { + "unit/inverter_a/mode": "Leftover solar", "unit/inverter_a/use": "ON", + "unit/inverter_b/mode": "Solar first", "unit/inverter_b/use": "OFF"}) +check("...and the action log records each change", + any("inverter-b switched off" in e for e in ctlm.events) + and any("inverter-a mode set to leftover solar" in e + for e in ctlm.events)) + +_before = stored() +_n_calls = len(_calls) +BAD = [ + (f"{T_A}/use/set", b"on"), (f"{T_A}/use/set", b"ON\n"), + (f"{T_A}/use/set", b"true"), (f"{T_A}/use/set", b"1"), + (f"{T_A}/use/set", b""), + (f"{T_A}/mode/set", b"solar_first"), # a key, not the option + (f"{T_A}/mode/set", b"Cheap hours only"), # not offered before P3 + (f"{T_A}/mode/set", b"solar first"), + (f"{T_A}/mode/set", "Sοlar first".encode()), # Greek omicron + (f"{T_A}/mode/set", b"Solar first\x00"), + (f"{T_A}/mode/set", b'{"action": "pack_use", "value": false}'), + (f"{T_A}/mode/set", b"Solar first; rm -rf /"), + (f"{T_A}/mode/set", b"' OR 1=1 --"), + (f"{T_A}/use/set", b"\xff\xfe"), # not UTF-8 + (f"{T_A}/mode/set", b"Solar first" * 10), # too long + ("goodwe_ctl/unit/inverter_z/use/set", b"OFF"), # no such battery + ("goodwe_ctl/unit/../use/set", b"OFF"), + ("goodwe_ctl/unit/inverter_a/soc/set", b"OFF"), + ("goodwe_ctl/unit/inverter_a/use/set/x", b"OFF"), + ("goodwe_ctl/unit/Inverter_A/use/set", b"OFF"), + (f"{T_A}/use/set", None), +] +for _t, _p in BAD: + cmd(_t, _p) +check(f"all {len(BAD)} bad commands are refused: the store is unchanged", + stored() == _before) +_passed = [c_ for c_ in _calls[_n_calls:]] +check("...those that reach handle_action() carry a value /action also refuses " + "(None) or no known battery; nothing is coerced into a valid choice", + all(kw["value"] is None or kw["unit"] is None for _, kw in _passed)) + +# Log once per topic and reason. +_logs.rows.clear() +for _ in range(5): + cmd(f"{T_B}/use/set", b"maybe") +_warn = [r for r in _logs.rows if r[0] >= logging.WARNING] +check("a refused command repeated 5 times is logged once at WARNING, in plain " + "words, and at DEBUG the other times", + len(_warn) == 1 and messages.pack_refused("value") in _warn[0][1] + and len([r for r in _logs.rows if r[0] == logging.DEBUG]) == 5) +_logs.rows.clear() +_flood, _ = ctl_for(OPTS2M, os.path.join(_tmp, "flood.json")) +for _i in range(100): + cmd(f"goodwe_ctl/unit/x{_i}/use/set", b"OFF", ctl=_flood) +check("...and a flood of 100 different bad topics logs 32 WARNINGs, no more", + len([r for r in _logs.rows if r[0] >= logging.WARNING]) == 32) + +# Modes off: refused on the same path, even if a message arrives. +cmd(f"{T_A}/use/set", b"OFF", ctl=_c_off) +check("with modes off a command is refused by the same check /action makes", + stored(_c_off)[unit_key("inverter-a", "pack_use")] is None) + + +# --- 10f. a retained command after a restart ---------------------------------- +_logs.rows.clear() +_before = stored() +_n_calls = len(_calls) +cmd(f"{T_A}/use/set", b"OFF", retained=True) +cmd(f"{T_B}/use/set", b"ON", retained=True) +check("a RETAINED command (the broker replays it on subscribe, e.g. after a " + "restart) is never applied, and never reaches handle_action()", + stored() == _before and len(_calls) == _n_calls) +check("...and it is logged once, in plain words", + any(messages.pack_refused("retained") in r[1] + for r in _logs.rows if r[0] >= logging.WARNING)) +ctl_r, pub_r = ctl_for(OPTS2M, _path) # a restart: same state file +ctl_r.publish() +check("after a restart the state topics come from the store: A Leftover solar " + "and on, B off", + [pub_r.last[k] for k in ("unit/inverter_a/mode", "unit/inverter_a/use", + "unit/inverter_b/use")] + == ["Leftover solar", "ON", "OFF"]) +logging.getLogger("goodwe").removeHandler(_logs) + + +# --- 10g. the paho side ---------------------------------------------------------- +class _Msg: + def __init__(self, topic, payload, retain): + self.topic, self.payload, self.retain = topic, payload, retain + + +_got = [] + + +async def _handler(*args): + _got.append(args) + + +async def _drive(): + pub = mqtt.MqttPublisher.__new__(mqtt.MqttPublisher) + pub._on_message(None, None, _Msg("t", b"x", 0)) # not bound: dropped + pub.bind(asyncio.get_running_loop(), _handler) + pub._on_message(None, None, _Msg(f"{T_A}/use/set", b"OFF", 1)) + await asyncio.sleep(0.05) + +asyncio.run(_drive()) +check("paho's thread hands (topic, bytes, retained) to the controller's loop, " + "and drops a message that arrives before the controller exists", + _got == [(f"{T_A}/use/set", b"OFF", True)]) + +_kws = {k.arg: ast.unparse(k.value) for c_ in _call for k in c_.keywords} +_main_src = (HERE / "app" / "main.py").read_text() +check("(source read) main() passes modes and retractions to the publisher, " + "and binds its commands to the controller", + _kws.get("modes") == "_modes" and _kws.get("retract") == "_retract" + and "pub.bind(asyncio.get_running_loop(), controller.mqtt_command)" + in _main_src) + + +# --- 10h. the guards, broken one at a time -------------------------------------- +def p2_properties(mod): + out = {} + try: + off, s_off = announce_p2(NAMES2, module=mod) + on1, s_on = announce_p2(["inverter-a"], modes=MODES, module=mod) + on2, _ = announce_p2(NAMES2, modes=MODES, module=mod) + out["off identical"] = off == TWO and not s_off + out["on payloads"] = on1 == ON1 and on2 == ON2 + out["subscribes when on"] = s_on == SUB1 + cur = [t for t, _ in mod.mode_payloads(NAMES2, MODES)] + out["retract filters store"] = mod.mode_retractions( + [3, "homeassistant/sensor/goodwe_ctl_grid/config", + "homeassistant/select/other/config"] + cur, cur) == [] + out["retract keeps current"] = mod.mode_retractions(cur, cur) == [] + out["retract published"] = announce_p2( + NAMES2, retract=cur[:1], module=mod)[0] == \ + TWO[:-1] + [(cur[0], "", True)] + TWO[-1:] + pc = mod.parse_command + out["retained dropped"] = pc(f"{T_A}/use/set", b"OFF", True, + MODES)[3] == "retained" + out["size capped"] = pc(f"{T_A}/mode/set", b"Solar first" * 10, + False, MODES)[3] == "size" + out["utf-8 only"] = pc(f"{T_A}/use/set", b"\xff", False, + MODES)[3] == "encoding" + out["switch exact"] = ( + pc(f"{T_A}/use/set", b"on", False, MODES)[2] is None + and pc(f"{T_A}/use/set", b"OFF", False, MODES)[2] is False) + out["select labels only"] = ( + pc(f"{T_A}/mode/set", b"solar_first", False, MODES)[2] is None + and pc(f"{T_A}/mode/set", b"Leftover solar", False, + MODES)[2] == "leftover_solar") + out["select offered only"] = pc( + f"{T_A}/mode/set", b"Solar first", False, ("leftover_solar",))[2] \ + is None + out["topic exact"] = all( + pc(t, b"OFF", False, MODES)[3] == "topic" + for t in ("goodwe_ctl/unit/../use/set", "goodwe_ctl/unit/a/b/use/set", + "goodwe_ctl/unit/a/use/set/x", "x/goodwe_ctl/unit/a/use/set")) + except Exception as err: # noqa: BLE001 + out["did not raise"] = False + out["__error__"] = repr(err)[:70] + return out + + +P2_SHIPPED = p2_properties(mqtt) +check("the shipped module has every P2 property (so a red below is the " + "mutation)", all(v is True for v in P2_SHIPPED.values())) +P2_MUTATIONS = [ + ("mode entities announced with modes off", + [(" if not modes:\n return []\n", " modes = modes or ('solar_first', 'leftover_solar')\n")]), + ("subscribed with modes off", [(" if self.modes:\n", " if True:\n")]), + ("retained commands applied", [(" if retained:\n", " if False:\n")]), + ("no payload size cap", [("or len(payload) > MAX_COMMAND_BYTES", "or False")]), + ("bad UTF-8 replaced, not refused", + [('.decode("utf-8")', '.decode("utf-8", "replace")')]), + ("switch payload case-folded", + [("{USE_ON: True, USE_OFF: False}.get(text)", + "{USE_ON: True, USE_OFF: False}.get(text.upper())")]), + ("select accepts mode keys too", + [("if MODE_LABELS.get(k) == text", "if text in (k, MODE_LABELS.get(k))")]), + ("select accepts any labelled mode, offered or not", + [("(k for k in modes if MODE_LABELS.get(k) == text)", + "(k for k in MODE_LABELS if MODE_LABELS.get(k) == text)")]), + ("command topic loosened", [('/([a-z0-9_]+)/(mode|use)/set")', '/(.+)/(mode|use)/set")')]), + ("command topic matched as a prefix", + [("_COMMAND_RE.fullmatch(topic)", "_COMMAND_RE.search(topic)")]), + ("store list not filtered", + [("and _MODE_CONFIG_RE.fullmatch(t) and t not in keep", "and t not in keep")]), + ("current configs also removed", [("_MODE_CONFIG_RE.fullmatch(t) and t not in keep", "_MODE_CONFIG_RE.fullmatch(t)")]), + ("commands published retained by HA", [('cfg["retain"] = False', 'cfg["retain"] = True')]), + ("retractions not published", + [(' self.client.publish(topic, "", retain=True)\n', " pass\n")]), +] +_p2_surv = [] +for label, pairs in P2_MUTATIONS: + got = properties(load(pairs)) + got.update(p2_properties(load(pairs))) + broke = sorted(k for k, v in {**SHIPPED, **P2_SHIPPED}.items() + if v is True and got.get(k) is not True) + print(f" {'RED ' if broke else 'GREEN'} {label}" + + (f" (breaks: {', '.join(broke)})" if broke else "")) + if not broke: + _p2_surv.append(label) +check(f"all {len(P2_MUTATIONS)} P2 mutations of app/mqtt.py are red", + not _p2_surv) + + # --------------------------------------------------------------------------- print() if fails: -- 2.54.0 From a9f7d785273f5bf6b291d460008b3128a2ec8761 Mon Sep 17 00:00:00 2001 From: goodwe-review-agent <noreply@anthropic.com> Date: Mon, 28 Sep 2026 23:20:33 +0200 Subject: [PATCH 071/105] UX-13 P3 review: truthful peak lines, a clock-proof test, Simple stays default - The peak limit's Why and plan block need a real power request (floor above 0 W), not a blind or floor-limited guard. An Off battery gets the peak block only while it gives power. Why no longer says every battery gives. - test_batteries_screen pins the fixture clock: unpinned it failed every morning. New checks cover the trade and cycle filters, the blind guard and an Off battery that A covers alone. - Settings keeps only a picked view; a link to Installer is not remembered. - Browser check: badges, unsaved change across views, locked value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- docs/img/ux13/batteries-off-peak.png | Bin 93537 -> 93351 bytes .../DECISIONS/UX-13-one-layout-table.md | 4 +- goodwe_controller/DOCS.md | 7 +- goodwe_controller/app/homeview.py | 19 +++-- goodwe_controller/app/static/settings.js | 10 ++- goodwe_controller/app/ui_text/en.json | 2 +- goodwe_controller/app/ui_text/nl.json | 4 +- goodwe_controller/test_batteries_screen.py | 79 ++++++++++++++++-- goodwe_controller/tools/ux13_browser_check.py | 49 +++++++++++ 9 files changed, 148 insertions(+), 26 deletions(-) diff --git a/docs/img/ux13/batteries-off-peak.png b/docs/img/ux13/batteries-off-peak.png index 19b0082a8b382674d9e6ec56bc0a2425737ca376..354d3927a0f32a3f9fd8ac7a4fd85e8f833711fb 100644 GIT binary patch literal 93351 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 rm46}h{O%_&XfC&9lBnEdK2pQ;}U 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 Zn)>E8?*_V^33voeK~_bkRLUsme*+~qGPD2y literal 93537 zcmb@ubyQp3w>H}MrO-l=wm@-ckzxgk7cWrU-JukBcL)>;6fa)f3GQww?(P~qcyJAH zclsOW{B`db=eys@KYNdm%&fKcTys71na?CdQC<QIgBat<lP6eGl3$dcJVDuc^5iMz z^M8SNLaV6@pFDZ_MCyyMs(b3eGU{hM59qUF!|!>`&BC8wp-@{N939P6FY;~3j~*Qz z*&Z;9bSEhPI<nPt2Mt~y95TK0&))YDV!?qA9ZZd2!>%4v9*3m!%#2w9<4>L(JH>wc zd$S4-Ud2Y<y+wPu^bhi;>xn-f^6E$U+5Q>w<|WGWBjokTw<qmn$m?g!w+$%Bo1gzY zbwggCu=@Q^j6gMo-v#$dzL|hi%D*~uq5e%N6+(#(R*YGba=;)$+VOi7wSP3l2&1m@ zm<SY$ku||*eT^#i8Z$~X;|2H^Ep5_h^!38==)qF$-N^>+LB)?BKN^!P?maJbYR-Sf zyoQh7mP6jm&(B{T%;#*%^hTyV$Hq?PyTU;OY_HCC8?Nf~vBV8A{3?~UBoHpn#^1&V zU0{fc3ZbH+@=TXY2wm(?5BCqJ@cBM0d7Lp;9TZJlZ4Vo~C2Vy)^h_*UPRi)?dc1lS z9i7*PNB-(T@U0(m#jf+R)*rAo38c4<bCc{MLJu4H%bv!v4AWm1p-xXv^+u2|651@} zo?N5jK0AkNRGSW;5`>3_#>60CagwsKvQqM<$hoi5`mO4#1&Y1qX@R>FT5QF<ZjnAu zdi9ZwD;HW>d17rF6&AKw5C7xk>swY+lm1=*%ygKT+w%Oxs4p8r@a)+$DM?98GOlco zGt(#vA?z0~6y&Ayl~7OuAO!bfgKzNh(*&J*W?}SLpLnM2plxX_E&Ot@6L%`{NPWar zhX#v*!D)-Nt!+YjLgm+X{&v9+T2)gyff6WYX3;*3E@pFyZ0zhf<owrr!z4^{!)-pd z&sn;UdOCxn8YY(1OSKd3j*{x_p!$uThemx8i^O#{+VxdcRo}oA{LY`4IBOkZd+sie zz&7(!6+{A-)OW7PIfF!Y7*uG)#ALZ3GtBMY5{R-hvH0P`-QC@0w?j3J*#e!}XnOg% z`&*m_pF39+*sW+VHWxQLg@ETlt<`L8ZEa6Dk%@&=<xD6VF{d+ypf%mSx}swCxPGhP z)rUu$jvpv@I6OSFZca`DZfhMotVWX)6G`jT_nZB(&v3{`(%B`1_1k*}Zg(n;SXo&Q zl%+yKXysE&EbLgS>`V?ZTjMe^gzU$D4W?@dBy+pj+h2Q~OzaexxBL4(wi;jTxzur5 z)|jt3Jah!|xxo`IF5xS!i>(sno11aAdQAfZediP(#|8((eCYW<42{CO59T2$zmw08 zme1y^VX^P!4F9fydO?GR)Vt1`p!<cvCFy8t8_Af$9Vb)D9Lhpjc@(WAA{K*Iu8(8T zDvzAxWMUQFwR}>3hYoiY6%}F^2Zxi3i&iI?{QgX70VxP^jZQB`U&k!Z{uB+(AusQ# z$tk<ph^N=hQiH3Qo@ju$PM!65n<&`l?rL&jjtHAf&~bf})r!$-;Dk}VtjT@%wC`1? z#qInVfp(2~R%Yhgs*J6Jq5fE~APC|9fY8D<GV(06O>44QtTju-c#iqWd$TVTe~{PZ zKr%-znPYdUQKqmrtD@p~REU7fX5t4kYK010bydDxhRfXy77-D1grN7i`EoL+%|czi zAsJbk?Xp)-SI^$w&PU`@2vMjm75~ssm3wwv%tcL0+q;sww^EVS+^q9WWW8*;IV?2n z($mw^O1(TgQ+E33=g&Sfg^d3G0UBy*b>mtba>1I9+&H(#?Tfv^pp_OMD;pCr6n`S# z8as)?G<s07T(j#Tv%#e?*r3I}(q^%aMniLC<of!S%XaCf++o+y&{SXFFS5%EpZxs% zm8^Rhsluxk`DNa`BYRCvLe!JC`-ffA$r7#VuCAw0aN7Z0X@=Y(rci?wd$$ex-v|T# z5$Y9xj8V+kFd4+qLLZ%?A}T7{?0g8i9ZDi!zKQzT=zMe9=5q&yTxn=%R9930VPI-< zy136$$Ol74T6U?<CiwV^0GVEUMMy}<*9N&oF0ZS@v#Tp`m7A`&$VLyAjGmbmA1=`= z3xj<FJu8mTK?F4=rHH6#TIUVSzM!}`I4~IEe&X0Olynehp#rY6nB-++3#Dhyd#n!b z5kKd9f9q6EBH-iGE<=j`fKgptjSRbf8L$1l;_=jHX~K%Ee@ZVzMn+y8ErVAd5RK6D zUBH1-+bkx<>lFH`Oa|$>HH-yx%WCxGnwe6#;yD9q&V{083J(<rmpYct2Br}$2(D5c zbO^QL$jF#jz}%eXT9T8a<NQCK^t`;<*Lf|v4>DX_Gdf(pE8I3V4-0sB_(UL*w?#n_ z!!Vw+(;aU7gL$PUwm(RB_=)ZuUl`MoZ7B^>n^%;Vm;dsmAvBZ$%ge*V!rUC2gjaPe zHf5svt2}dJN_^VIXaOcSA9wxEBX<w)OxgYAh0a>?d8v*Y0-+yQyNrFfpx5d-Jvmto zM3TG_V0crmC1jWMx*yGSb#?9Sk73L9C22`XL}!nh3iv(-P_V2+X8o-YKE6q^a!wEy z)^+PO3`@}c`WHw?M~59bzIC+rdxE&wlwnuVtJ6zCw}%d3gG-2uyO@u{O>AvV(_>;t z3Gw<y8ch$I!b^ravPbJ%iHQmMy|3xcCu!TwEu{xcMo0CgB_c?(ii)^Q_BbB>{LatM zacSirxIo^@%1Jn$cF-&zP0devkDeEM3A~~_e3M`|_>Zoxv}RWoW*lscbY2^@LrlJu z=9Cm8n_zrKb!Be_X<6MWV+(nG+rs_C_~<P4_M>Glx^e<MyfM#9INw~c29B_s2XX?e z{;Ll!vK#o_j}>o;*o@~U@?_{&kLFt^ySoGREoWM^n(J)%T=t}eY!+%YlvPRRAdt7- zZifqMVp<-5{Dhgb>$3Aw)6(>aIWm`^rCy`WS4V|b=A@r06!i3372s|1Bh0-DshSYm z(qM_|D%Z}gxw(;%G9ZSV3<K*=NVvnIb9%MXdUtqWb#W+^snUxLybhFsSFw621_nl% z2DH&(avQb9|6KrDVr|HHj>N_OqFcvx2&dKb(O6-1TI*r>?&M$Sz)BsR9^L)fBo8(i zf3|l)u-j})9n`ZG&mL7p+M821F*UNlrfjf-nL~X)e3T+9Dfu%bq_Va)J`T?(0eD#C z@qaFyT{t;8lh&WrJbU_-j*gC)nE1Kp4{%-{I6og$X*;}evP8nk<9O`X80fL(8Z>ZN z<02z7sNCG=`}`rZG^aE-x64~f-q!Z(*UXSg^u<7ANcc?p4hZf%?E<`wnS&Eix>D$T zRP&BU-@|1GqU7j*FDVrp7;)z7LO(Y6+BrBlR8=`Hx*a^ne7@A^#P=6ssRe-tyjdQi zdBntq!fkoeQsbOnT)VjsNGHZX*{fcpjN)8I^%;WR1xJxCxA_DYChcC@==@!f>o;S) z_g?gLt3u&o>4P}?&yJ|EbgzI=khy6c>WGMXo1xK#5XqNK-+X*HR2v=iw^Kv{Pd^3` z`^O`Zjnm6z>0Crv5uMfye?L(Rt4?QzZ&&>z(rrHPj;U=o>v*$qW%NeDv0zWfcl_R4 z;_{jQ2U{ATwBO%hgbc=Resme$T33ES`T8uPHdmr{<^xYka`xuL_gl=rW{6%cK?n-h zd-?VXr0qzozM$OC97Cpe%G*3C>kCYc&meY^p(=9FKS+f9<Qqo&y;tQ-ViuHfv`ha| zF8<fo+&n^2tlfyjburU0$pJ7_-IMJ<hUbxnQCxP%OF7GK^6ml=PJ<R-zP0sP4>+cp za^mxGD*iorp9}=Cd@YJOh45S~-fkQG;c&R6@bEwc{m9MDEsJyoUzS?URv8sp4|OGl zZI4b&Onoi-KzF?{|04aB()g`sQ^b<ql3r??<q5E7S8+1-KFyT$4N-`8Vp9kR*p1+A zTX|2v$9VCALh#aJX)KWJKIj>8CJ!$Z9UiBbFubeoPbyd4L5ZF+OtIs(KKvzmgUKF8 zCH+BYw_;*qf(rL_M@#jqR~DX4yt31>w>G(<Ri^}I8z=7EaQ=_%taWv4EG|L6=Nf8L zT-`Y=K6!R!ZpPIJ+(qT)<<;73wX4nr|Elo9q0soKrZJ*nL&?nozurCbU)66%iBFBW zU9EHzB`|YwQA4`vLnpQG<2?=<17o>jav?KY45~pYEa)+Zm3CVK+zorPIgW#+>*>|2 z-rFHk9mgWl<al4#TwGmM6$2pftnVvf8g{j{oYT{)b}LP0CO15?25p{`U40)RZy%5D zC0hJD0wfgL&Tu%!W>pk_jgIuw^F+Tnx%9C$w3Sx#9@x??JFirMnTNKtwA8(Mbl}a( z=omF<@_fvi-LHpNS34cp*x=#gOZ%|&Dx`sR`J5Fgw1|k*@J(n;#OyN6YC6wf+Z=V| zSt+#m6b8v*;UtUjWhBM>Y|ON#)Wgk8O_EZQ`A<AtZ}uV@8h&WlL3Ms7<>!HYpWnp& z`t7`p*t&Hg+rWKof#r525E`aXQS~v0>hsO@Maq>N@d*h}RI5*C2USD_<`>tH%Ns<V z)k@na8(Vcj|GO%5PpYZ82GIUW#Nw5xNT;kEW}~jHsxxNua%Zo+&<Q9xF7;IK?N98m z@9E55nWv{`G6LakqXxQdj<I!O)kHgczf+RNl#xD*2wr>fyC`=d9aW_rOR2QgA6Jau z_k@>=Yh-GUj+-04z5L97H!k4p^wc~XHm$RwkP$`5`zI@Zxu>*wH&2;1X21Su8+PWk zy5xI(J>)Sef4Jy;IAsg}zTt2Z5?4KIw_;&!{mEL90)U6WiKeG_SmjDj$*@q^mh-g+ zl(xVQjs$<NhofMV@lBUVbsp*Q>YumBHzvGq^E|VKwi~&SS&fhIpLt0|C$BfCq%9;9 z?~yIksVXUjhJ-X<t)ARV=$B!oDo;)%l+J%qa^Ly0QWG!QD<5XP&^tR?>|Wd9FBFvC z>|X0b5+!`^sdU}uc$m=lo-VCi7cyPxI_!{xHrU^9GhZ2%@Y;HIxm0*RVVH)7hod^M zuyFNryeFY(CuJnL&|*!r)u?TnW0g}xIOZG&4zO^KCddpT=5-*d*!1{y7M7ZE9ZrZL zern%>?=|(b!(;(zTJ(6K5s<P(#7)&G!-o2Y4_6vnTUvDQn`)!d`DI?j@hVA4DY+Ml z+cG!tBJ5JwxVazj$Vb*B?WuW&iJK?mdLncc(pvlCB3z~Q%i?sN7xc+7{o};`!1;rV zDMhKV>AQ*^asIl1S5{`3(IF0nsBYRm5#i1=pXXWq2maAYtTF@-!s9mw-Ha}z2lIJN zZb!$nG4TS;E_f?ln<qKaw%iO1`I&DGl!Vh6_BX__4QVm#M1ls>1YGzR&039`6a3Mu zod5h67l0Q2wb?nsKl!WwJw0qrTwGjBJ6TIdYpnQUZ^{!+VXV=a4CJJKk6cf$7}gZi z%Mw;c3N`H?wIh~E%q=aux@i=HT%F1cMp7NCs^UJ(8`4Wj4J1!YOwiDVK6S&A<8<|7 zq)AJOEzT<IiBD*Axyo`9=zSK|a$s#UFrV$;qN}Y<U;6X+Z+C&TQ5R1Ey|jj|+|k8} z>lP*p`ofkaM9hncp}2I5x4gVPJqs~u1$l+~nwoKOsYBjUD6pniN=l5gHt}l%n%c=+ z7CS}dU`GCcA3vT3Ui?}8<&W@IQ;W~e&Q49$T{}$3+ce~0=M;208Ax$^;9bxjHE7!% zuSG!~ijN-1XHGie);}4)@+&aN0hP9j?yd4a4N_DZOiaVU`hu7c1$iamcG$={p1|4Z z*_>g>L>r~_x(t-0JNkMSGcYian0OD^$90E-Z>c&D$MVH^2DP<+LtZ?`3r9osU8)F# zMtsrMmbTY=%OYf;b>gHVEVBNBwmLVLn(t5iHjp2@a18+!)A`;wq^c^yXNwo1FHEDz zIDhwUkO_jsjnP;#%zyxnc6lg#CY$y#IWoP^bx`^A<0*+48=FSi@`Bs7yC^q|_|XoT z`v37I0`RvaD?j$xay6fgKbLAWk3{oD;p&%H<io@Q?mJ>A0|NsL0|SO@uQ<G~+BfVL zBZS^ZQlIb5Sgbd^!t>`z9R)+hM)x1Sw^Op$Tdq*QUF`%Sr^P2K_Wh|wnMmwQ4&CDX zWn4Je`U42jRUc_oTEzv<DoajI(06PK2v`o&C}(HC!4dJfp6l)CP(6VP^ig=-33{$m zRZY!@X~?IqT^){3DVD1=zai-j<bIX$TXk?`W@0H$8XlE??I_*lP*gHFFkozK{Lw%J zt}Uw9Y5=#Ld>?MH&=-NENIq*MF=YE!m8j~ge;>MPQK<dN^-igBy1rzst@SE9R0v!7 zPj}%;(u;IE=(D-S1!wq#;aQ}QqhnRwjCwNkoPHyjm{`?Z$g4fpfE;EY`aAo(kLRAb zm435FqCS2h<Nlr{4*8fDbPZQk1^nyqXz$=?z&Fxs)RxTcK(N8SpI943>^Ra!C!v-{ z6y-iOH8oIXR&iWgZKpkK<YMpmF0FjwGta_j1Gn?B@02fYuWwH<Ud+?ZJ?C(Bo3Ap0 z8px;*4i1`_nnVzBNgCr0lQfeFc-YSGMVvaG0^2ToGcAeccE{(Am@6!yJO>(Zdu2Re zYGVPqStzBV9XVAfrfhnf$?yJ|h2aL7Hyl#{u;Ui(6eG{k1G=x|!xnR+JCaE8^u}gu zYpb`bhnR$j4LXH7y6@50D9{9I!#!U!vU~JfeI<IASp8gWrjsh?+{Gm~_hGtER#H}3 zSvA-6iAq^VM@Pl6q$r9&bhnhNtGugxWYdBMKWUol`^de${{H+P@u>=W7u*`70cq(i z{w7v_N@Y>e)~P#NRCSv<X#!GGOVER02>>6of2UMM6+J};kq=L=?5H50nh98;uhr&F zK6y-}Vz|V-dcmUK+UkDext}0cXii3kd)GHuZxviu8^-s?uOilrSrMhZ^gAy8QYU3j zi%+^-(nr7{kZ$1j_z^IeUm-~uOgqdNW88)+g`QqwOb)wq`Ew&YF*z9^_(R!pc5=G1 z>Z6*n^0!QmXr*xg3$U}XVPT$^d>Deb+aSFO<njCnO4#kD|0;N$?>>L6Tsxr?Ps$O4 zzRHPu=c=9wiVPBd?w!MhP(q39pH%I!rl7P3Cg9B{$L#;xq$bkp|1~rEKQN*e|N4Y$ zefr`@R2zD`pjN-qspV~Q!ie_v2pTq%8rC7v6FQBrW6uCGO+bJQz;v0quXl;GFcEKo zFh_)*FMQt=?!LaY)$*zSdO6-jEU+b}T-u)ca8b_XfH#qfX7~?FZb8A$#o|@v3Hl{x z$;E{;QGtIm4mky%hrEIW*sh#;M*R%{RX)!H@RilQrDFp;y6n3n)=41*+M8~z&ZQ21 z#VBQ1eq=`!_l8V!1~YCOs;f<OaT~OF%(VAD5);8t2j{t7-y$LYH2je&=(5}Z%!Lv! z)}98E=<Pv!>iY#?oBd7!DitL+KhFm0vT9`hJ1~%5rOW%8(9+hD-?Qs2zR6bT2l88b zU14E;85PlwG#@Bq7>B2)$G;WHfaJIHJg_D<1l5gAX>86$WHOv`8^S-ilO-fZtMp+r z_BqOO<f(2#yiyp-Gk4~Dmy*SGX&N&M?p=2WBK$IOC~-YdQJwdalL<Mk)<LVsQp}0_ z<28oCbxe?kx*uKCMU#_-RtB9xAa=EvxVVW1zwC_7|NIoXb<(f%%&E=m&U_Hy<eVDJ zxFI1I1rBQofYhsBjmlbdCGYDSGT$1{mFcbH*jnmloV8olsc~NZ9UbstSPs$<ltVkZ zFjH|fkrnZEAjv7wrKa}wa&JI2kpTQy^3{@-0}M?PyYOWC)<&WLDH+z76zthfWXIWp z&qO*x+*D$tW9ZE4#K1AQ6CSsF2%(7cl8!$+h!dMQU#lGD5lXwxvynT~iDVhF(w}i9 z9fmsVQ3~S@A74dnW2vZ8^D5SLbcpa;WI)^xcNE#Vxv#DZ&up~0tma#!Ze-FR&ckg% zwRw3&SY{?>6at_+gA7{$H*k2~U$(}@)r4#Wv43Oa<ea|SeQ_K0g!6lyjpj-B4Wk35 z7&bA0Y5#q>R6Jdq;zpl8*k|7xMWjAihQ?Q^1G{t%@t$q#ES|MHoG7%hipn1vWn%8z zzmF)T#Le4^v#KSt(=7I|bUqGyQLJp_A86pS-#9Z?nHE{gct-Z+{YgHB<fgRrRQ<1L zI=)y5>NlzGsTTQ60=b3CH;e}dxgQIcVY#3IMx&KV<K%AzO4}4K0=?jwOI6~GB05^9 z_q<fww4yHO$}+n$8aB_d!sfhI39;(oQ)Ob+;#=jgLg-*(`O5vxoih!M7%^7VPu)7t z*zaxWdRY6838y~WX2zMl*f3+*t)TBX*o?r{SrL*xG@HqAF-_uzcCnwAQ`(OpjZEdg zI-OoTNKG9%)X^}0kR}z44ghu~<jK=3%b1ju`nx~T8s$);o!tmBPR-5aPl4Bs)%n)T zm5&D=qX32s#@UltOD~Me&Zf)&gX~srCo8H|(zGw@4$i~UXVdn0^^aQ;;^S2yWul_> zXi+WR8Q1*NiYiu%1EOQY@7Z{7FP9}OEG#&!OGuh{2JL0$u^#tzerJnBha8$_M1ihW z7xwh)hJ#%1@75lag2Vz*MVi$Jz3t#`7)Nl*(}DxOa<KMY)2SBE;{vOPR%FRJ>_bMn z-VQ(Qsh&Ie87IHxz_3w_k%~Lsk_96{hDrM6K<+LFkWF}_FwUzHDBHI7=M$k>hwrN@ z2!6==>|T>dB4oPknRa-?FB8*Q<NV7`OD9tAERw|Hd`~N5D02r9*gDN^AVW5#sU)Wq zqc7e6VabJ&iLU8S`<JHXu<WuT>gGO_$JD{ms`W|tZC+)nWX64j@9oulNAA5TbRz^x zz{cy>A7tf*Wg$x|&#|y(CuY9l(z3E~5OP|-RZE^94<9PAnzfVY?gA+E=H^d@#f9R% zUF5v3yfmDLEwp-Jo^ySr?aOyj<|D(4R{%400bjl!=6g(CTDo<yqy^{RUJJSvn7BQh z*0wCQ5Ob-kcA9FW#K+&ShPWw?NzjO)YG<k31C&34EYrj%qfJsy2JF=4GH7a9#2{On zbJ|!#{Rn9Vke{;ZuPgI~ov<+PL)LT9En;LjIDAalYyB+zVXm}vXkM&LAEH+u8BmvC zYOLzK1GdM)y4dH2GcYiWjn`Fim;rSnFtsW7m(ao=UAf(iGs>3W27a%eAIe@;6JI?0 zho_TFbCPglW0It^_IGJVb=f$^s%vX`J+?cN&JyQ$RUP<U_fkWmv%;K~H^3~Zf^Ih< zSCiWjB-=2863uFQ?kEbgfB;eT(q--0O7%xUftZ*Ww<De}=sBD3m1UaWU96=`3HHKZ zrqrzs4awh{T8iXD^8Wn|&++SpmuCHm|8$tPE65^!9i0E%)TlWMhVR{I75v#&c>HK_ zmzN=?E(n2!nRm&VsBGq@wk)8&*cx>3Lm&iBb;dgtdsRSFUPyhTW3`1gQ$?9mGnLM_ zTg;pvZj;Af6nNTCOT=fFU&#pdqD`CdP*oPzFbnkW$hMiCRIa+d6EAGND<YIW9(-1` zUnqsO{8~aPEg$NWBCzo}yE1<>^L^-)?OwAW7f(R1YS^I{w(Wc+{Cr;KMPgaj1WPRg z!1GwmmsB<;RsQ(VML<yhksS*iz1jQ1)YTQ6FYrxb;s*CuItOO0N_izIhq=r)JZ>PP zj!sT4D#{j#2PJ2L$es~b)O@tk*PXJP&Q5B!LLolJdG2}Q@9Xvf^$LLEN(1%Pm97qD zZU8Calvu`wNP&3l*B{8rNs;hY;MD2?-b+Syuw`sw(CSeS`=i9fgcW6qRmdq~1`-!X zQ)%6?3uRUxGt4#Q_2evJVyv2)B^Q-(8V?X3j?ct-bhc~ufEns~|BI!#1Oe?c-v|3+ zX9Apq&lnuVpAe`}(r2yflXY}ZuCL<)g|*LG;MDotyj--4!>r;`vB#gFY~tUZNol!- z+TubTD$X@GG)|W9mV9?;+{c33%8sh0Np_(|mq|XZbzIg0Y#*;Ta%cq^-;Bn_#8lN* zCbL<A+}-2y0(aXtzza2&wsuycXXghqC-AL(?~GRSRqETCfuSx18aMirNk&c-9kl@B z9+!nKU+?rJJbE@!p3#g#`4fvkvc&G8z3hbw@gy?e(L2*yP#@EW51u6H3aEDhxHX$5 z*C$h&DxMy`E;=ZnpLQA&5B_#DIets8hT~Txwg(+(bW4TG72P>_lj@I@2cr9V6Fd=S z-^z%xh1DJ-FYxCmn|zHQ$|?~!%(Rag+g%HT^y;2VYr{A99!;EznVtx=(Hb$IsdP|Z zE%$n))o}Ss?#kHxt+ImbV;{z&gW*C-w;Xao*X@-6+K%dZO|3XzC(G6*?0KGf+7aDM z{JlMM5~7`Ejsh!<0N>=aX7@n(kr}4siI4H2Ioa7j?kZSdpuo%2sB1A0&GDJVf%-av znejz+jGM8ksVS%JPKTfhCzHTNHzOz$%+Aln47#jAj|(p>lU;jg^?l2kQuxHq+WgNE z6RKF6ocMon0iN25!ouGR#p4#-;6kTEa5X)NXO_h(-}2SZug5!gh7%xPX(F?pb_!X@ z2$)kA+*hw&?H>5rW4O2Af|);D8xaFIS%~84)t+MCu~AY}sHK>xx&~}i{ej6BuRPFB zUa#Kb8Q)7HB02QW$L@j{I(WlEfnpWy%S&Cq)8y$5G&I8WvkiH8v`lDd2A*nZ%>z~H zan?%f;h0SVJVjeZq9q<>JSi2KqxhJ*LaF6C%OKYqEele5TSH;}ki4#d%qXwVsw*DQ z5+%OZBg0c_@vu+Hj`vh&*vq5OLk4j|7&9epvd#h_nX?(E7#KHtCOg4tB2524S4jts zIF>3w^dWm<lIcbNnzh1URET%)g+4?>cl+k0O&?p&M;O1^oafnK<rZ%JxpAz#Tf9kb zR+7mclf_@>hW{(l*>SJma^kUlwYZaomnIbCovlg#X)D`k9rrcv?{d}NtT%jbSy)nH zJ0Z=V<<w}nxuc49rKP2{=I8tS>Dj8-IF@^QPA~6+!xG9k$7VS>rre5Pn$e7C(9pNF zvkoOZ-z0^I^GwCRjs;uQAGwzNG4g1GvZ|^ny@^8)$Gl+i)CV}wcBWEb`QHJ{|5m9B z=b8VHU+L+>H=4%e0(xY1D8+q41~gRcD%3ye82Vr^-y^G$=v&|K>i*Gj2v`o7CNwm3 zVq(%_ZemGw<59q)Af^cMC|KJu6+xE0vP8!tFa*cAANveO<+e%2^z^k#>{A|6_$-s; z<R0USYF0N68#x&AA^jy|=;KXda@)FT?O2`c82MiJ*5_DXTzHLO=2x6n0o|ZOUEC|# zEJLTm(JeKbcxCDB{v`fniHhe~_B1yc7DhUaUcP%?w<ZSO$sW5}+dYhhz2H5~T~IGe z{p+RF+gi7rgiy8`tAN|{$x55z>HT`WM%OSAGjZ|!_`Iay#|#5`l!+LFD+(GZDXBF_ z&c((s%Za11kr#=jPR<oCu(7A7roO^a!O+1sBNrZ*9ap<fP#6odUZbGZf;)<U!1i4Z z*<vMZ6=0vqEaxK#`TfM}kCrG1GQQeajOUwFW0Y-@katq%pF3$NML*ISe107NZ2RoV z_08J`jbO?UUwnELf1!f~FHPfgCDCVNocA&8zW7XXSPUEh!BbRl{Gvz78J(Z0)gNk8 zn4d3AB&n{RaG3fB&#gsCiFxav50>w<+tZ2;4owX{aRP<WSSY7~h<|KKw5lWh_T4Xr zk=i5=v1Jmvn)}Dnj1M03zDMhlquaFj7X9V6ucaIXS-f_HZ|zDSJvcV&NHV;NRkoTH zcSLc?ImcsiO>E9{r{e|9&Z8=Cv>CQs99U;!nCU*ec5ac9g-N|hoS7#-L?LFJP|y@< z9~*Xn`LKcAipES*85k~XrvR)&z+y1zXLP6?YU0+jdV=w&UstE6g9C2Lfc%hAQp!?i zTKqNkk$7feBJ(-pr!64$rumeCgUu;CFQbN7Tc=V~UHj%MYrVwx=*LW^tx{k!1}+P1 zq+iT5@v8CSu#pr}P1J98Xil81KGNg+2u-rLq!6%HRC*;;3-O`&T<Fu$ur{G=a1FQL zip=U0j*Ur>mAmuqc~6sPZ2EA9MZQb)xP<Zg<;yRRWQq)>-GKf`h}7T9<!jguWsd4# z4Kv77^z(7=poVQ6=b1)j6$kh?XyvRYvrWLAf8{1jW4EI|uu)1ZA%4v<g~Pekdn-R8 zo(KOj{jPPvXLV<14Ta2dA!Nv6-hTDYDh1=kgU7m|V^?!#u*5T)yEtN8S>bo5!)Z|~ zW<LnlBpphLaZKByh|v)K``NMmFmJZOM&(!Oe;}t{a~|<&EHUQq;CYa+zLbgY6f<i0 zpXNO>jK(bBLw#NU-mRyomtN$FuAc%x_`pd2hlE~<@gZiT%t-!+{n5vclHpn9E2tcV zRY5_taOgm=rf{O>K4h7gZia0eO#&7*PXukMLxhhMokh~BkbLd_j75eoh3^qbnrL() zFnHK8*Q^u>R(y)^y16}HFXn);7-VpJRaGhP;>^dzZ8kK{2)XWg3;#3PU1)1+y1ifj z08nw~M=MGCHuEk0Wj?{ndZ}`9;n~?nTsBaZde>5NJw7&smEr>YK41=H007g|Q%5)g zC2fD!kl`&QTXIKPXlRwE1I|lJNKp};imQ<QxvIMB<+1R+c_7B=sV-4jdK>mx8oF|G zYbjQqYx1dDVOrq<D;|&e#oi~~7VorVW>Tqs6bX4c1_bUfP^z$7_K}Pr(ncHw^y2gP zJ$a&d4<v*rI$s{avGykg>5<rXSTKujwa?KSjMLG-4RTXI*>(Z-3<4&-l++lJyoT}4 zXKF13b^wisLoUF1Rldc*fOt8RV-*}zm{zc(GrRZkeyg#&1J@^VI47fO=3vgHtjabp zJzWW1oLCumk-@+-{r+6kLqP#tu{a@I);ySKC%)t=5CI|td8AizuiKIp_OJBw7FRDc zq@A?2Hx|wZ+K_JX@zGa|dR30Y_KKuk^@%pjDXVSb^80qmSd$@#^7a`d^o+yh`F5mb zTJn~(<h7foZfYcLoaz7amS)tk<>Nmxx+Gp`7`U+JbxsiaaQ2T~`^(E?r0w}aNf>4B zw^h}pr5W-r6NZV;FkaX}y>?(%`BEEf85dIhY%JVxfNj0QAp<L+iUp1wE>`T0jkmX% zB}M{JQB_S{N>0H_5n_ACmEq+zTU9UMxNfcKZk+OFcyHPzQ^f(AwQ)r*NVEjuKBIBY zqXXnKXA5#o*D9)-gt!C>HseXLy;x*(u=7R$_Lk)D%Tzj?V5ROiewsFFqg|U4bftzI zHu;QxFPA<n86Xo~3s8qd=0FFz0gOD%(g*JH1z)45e876};S{stvIb-}<9(kYUNBdH z6GFsMPq0@JUXP^Twl39P9rwLMq4V`VG~ep#rd2#IUz#1>+}wOm{hpY32cRxkgs%3W z!?>dNzcCcK9jqT=D8dBKD-(1S@d)GXvZ#gy&BXm8FBgCEi(=8MdC2!G1wC?*F#N;b zgbzC99VUGlFJbef-&d%LGo!Z!b671VHZ$=zyacgIp7CogTZ^jbAC-tYg;8cXlE!!l zR})_6%7RiA{7v5C&ptZdtxu`Gt&8E|L%EyA?dQMe+=~RPEG$17RDsUqot#wG_yiyI z+eT`I1ujE&omuyc`e=E0=1&z)?bb2%q8ePv^YtQFsS41C=NsW;VTpE@nmYGfo<D2O zH4Hu$b|JTdloY+k&5b|Y<}I?&*Wzun)&iggo|BLeyrtr^AUyz#GXT`kGbwbCZdhal z)`v*paaM=$u|u#mlrUO@hNk%Zr;knPfUjt7Ny!iaN<?l=_~5UI^cN|3_@FhV^|;yP zAiEn*WxnX>m;w`B>2LW8)%maLOO%3qRSss!{<%dQV#>_F)O%WB_pVbltg4MCp1$qT z@F5!?s2XP)N{9NF|HJ&OyS>V`K9iG>geW1ktf1htkiXJegO;G>r&jNanFMBwq!elz z@YAQLDl7O1B}r*%^+h+#N`t=7g=s5PI-cc*Hd>8SBdU9Zp`;v_S!#LN3E`Dl{~*yM zD*$J{8n(ktKme<zY+!QN^Rva$&~^Z^#4)sY2~9d*KY-c^%*GKz=}Q)C({#a$-jS-D zF5N+vIfYqm<_{%T4+yif#hD6b7~eC{Pf%-f+9w~-^evO@Nj0{MOO2QF;oIvsYkO{6 zJ!xZO6+p%Ey7rP)lyOBgpLl0~kHdDS2cUjG0rdt;5rX@|ZCZpTX8Re1SUR?p7^kOH z!`OAKOo%(l&7L?yBIC!`jFL?{4^AIB88bO2TG3$jqM%F6KfZG#t-<Lxt>1#ftPVvP zHLL&?>{p~Xwk>04XYPExc{C)ckX0EF$*Q9Mw^Wwm|3nD;KcIV&A3;iT*I*`mJgMIq zydWb#k=*ymf6I0Mv*jS0Q_cXd1d!s`mJHIE2#Wt6k;Y#Y$p289i?r~+&tm&}q4Kwh z=)Wqj_!Sfu8VY2hPy7th0Lefc^_u;s13zjMD4zda{TCtuZtn7mf}ir5L_`2<MPF9K zk=BMRi~lK)#7OkGLA|*_J?G<Q$>^m2wdP1a%zhjpnF~mnkC_ys1sG{1)Psuiv%8Q} zK-ANK^HqdZ^yL#Uk}<tse2Rpkak5UbSJPEd)dCLs<Ryk!5rcH$ZW3NB;q@DU%0|PW zt2Hww+O_&C={mN1HSQpdak_J=?*eR7HA6!~dHM8&AO_@jpU{{W6`R7gm5je-S^`Je z4_|Ie{q*qgni9-J<g@X6P4~WEQbxtNBj>W{d3&q$b(GHs<FRt2XgZVBvPc>)X>7hV z^yLy`ly<}oDysVe74Vlo1WLvOEPt*RRnbMv;>Q|$<9n))k>=X`D3X3H6r;7bo)+}? zF@A^>|EtHoejO@{m#XMcj`3q;VB?va{yPnAWX<=9pQBQDt6%V{KF#wZH4$2h+rJ`h z?`WWCsqBUS?*Er$8!-F->KESoX0^nE-)gcddG3sibc!GS+EcjffQ0>nZy`{^?Nw+2 zYRW+PXz?I<^{U^S`|gq=Q(&pZgyio!3OxgKo;saDN4T^IaTKw@KpYAI{bpN$Q=a-g zPBp0Yqj%$CZy7#RxG^#!e-IZK_J-SX%D&^;Vd%=?@K%nD>~Npk_JPY56KM@P+<B!{ zZ(!E;ygx*a{-*+CACUYp$V4(`<$cJ@VNmPUoyke?*TM2Y12H{6nwHbk8y=nxBy)9h zdx4JL>T?(QwgCo%33(k!pah|PF%S`<WMBy0&Z38}Kv-5!4i2rMZC)7(>Ey3o37fbt z5_4HvTFN@833716^)lAf)X+7KPfgVTI!7xj#{7Q)=^7wnnJv+0HC)Fl+9x3<MhaVx z<?xSx=isQ!8p!^X+hT=24}7Tj;eC68HL~I$pd}&ZC`~)Oa>Sq<gNY!1x#U|>Qu0BL zNzV0px_H*eH|1AstdXs0LQKp+^ya}r<zaVNVsI3Bj)uaw=ZZ`J#Ra7C78m4x@;!o+ zaM|Yb13JbF`VZbcHS`yIg}@wbCpIm1iHNk5leOlxiZx0LHZ)V-G}^CCWOYh3x$K|z zF5Spq><RduOu&=s{r&%KRn^qoS^9Io-d*k4)I{0rytT*a#yxv^xBzIT6N4lo34t*C z<PW#9W|!`{oPmqrI}YZILSlx+ahCjoFVXrU{tpsz{`1d_>J1c<=f$dh1ZW;OUOEBG z&qPn3#IPmnV0Z^8$15EiWZtlRGgzpy@yZE08cbj|4V8iW++r_P+dcYw_}17gE=(<X zKD0pR%h-A&Ne`x*Gct>1<!za}@0rv1<kHwe#P3o5y~QE)J{qE@q7o&JP>}rOvNzQI z0#;J`K~I-NujydESwkTiv_C^8!#D^4N8MJ>R+r)gUFJlP0R)7C>}XgeX*%cdS!nyc zgcxuOF`VnuS2fQZvDhlu{8sukk0qzPJ#SYj#6wuAQQ=?q@;j3+G-rh9@{-mMajmQq z%CAew@QMC2w~rrxNpE99?xgqjXYJlABxjbD^|aO448Cu-2DSq^`LMTl2FM{0HfkU# zBV%?q981i_g@%R(8!`B5<fEu~eAHY&G(2qnTN)0$WgKv~TW!|tx~uAFLqtS$MZvGz z_>Bmw-g5feK?Ayj!^y&eHZn%4Cc&!DPxx}eitrZbYYB=N@#HMaSt}afXzUpTI$NRe z+*-hMc_D7&-xp6vm}%deNN;XBh}(uNa446@#=b^b$82wHYHZ+`tFl1hBPAi>HrhVW zs(zenFl34V$SHC`$MdbhSs)O?p?50ut>3H92sC!!6u*A``b^`o7Q!`?A)%(GHa{ib z<h<MBvKYDZo6v*j29Vd6={L4)E|lp(3{6dm5o;*-ef|AP0qOaeq+?M)yz(pZpor#k zaFd-@X-;<>&nnF43Ub^U68{eR!gwg|DvdJpLmZ6HhH199Lg+-co7_`{`IG7C6@`?9 zgxB?P*8MZgbat<xwzh{<C=94ZJ8m8uQb}M}SJy5#+dbCqb3+<pT3Qgik+m%PpLF($ z9jhJ@J`3|R6{UtwM@y(49z0Ro!}B9Ylw}4GdRoR_ecZP}L1?pOdJ@PeTR^FAIBv(6 zUA!ckKPD})e$2t{<B}9Qq_FmY&^>!777h6J!s(1B)~#1p=PPBuu$`Mj;Oaxb*5>Az zorlK_APB66jldVHCp&X^?j|O|qx1h@2U9UI>CsJzz#JRT!GqX~i;HP|zUc#JRcslL zK`eTgC0dg!Q(d{6+n(n;u6t8NJRUbvxV?!@?De+LlM~N^va%8RtR(PgYFbQ;NW2&F z)Mwc53#iH5;m^m|VQavPg;@WRLRH}lGu7w)TtB*3;ZJG%S(W^-=g)fv%%8O0|ERba z*~#Z+++9%|tyJ4R_y^i7*5qq`prXpj&2_);83tNHq}K)$$}yi~erVH4rC3Van{D=e z{0`8Fk+l^3?p+`!l{;6P`1trl7K8qclMGrht8{)7UWx2;g*u&CX81h{B_(Athpp=A zGzqsY&y4HKT-S+wIYud|k!h=0Bp@j$2~X`%gT4L@R5S>um21C8u${&0TC150Yo`Wj zWGG0EKA7TU{;&*M)n6tT^qwkq6T02y{yO%6@@%orqSo{RBfsHio9A@s83A)+Be#Q- zU21wdtIr-DgG;px4<Db+TtlN;%H?7mJXa|ZZA77^CB>tLnBBG|H1zZ&Cpbgkik-EZ zjf2ae*7GoALn1sPLVCF=Ki?EMjMDgAV&Xn*C6&#VLCqIxLXPpo#JWx8QYQWaEQY}| zEpcV>_;oft3yoNo)H$h)!Z>uY3v&l;sc*dSfiqdOuGlZ0;%`vmMevVm!aq>?*laIm zX*WY4klOh876hd2Fg$dhLeP7Ng|4EmDlTT-%|0|dJX}GtqOvX__RiZ*T0}&|*0$`s zum?2p%a(WO-D16Mnbu@Fa<f>nnkWnv(pt#k<DHz|a>wWhPWcy>Xn6^df_^c*>pz5Q zn#_MrV;P}%L*8ihI1c1Gq9{I5`B(r!Vp#NnpFv(rscmZSo$AxuhDTjv6Jt`VS!SNJ z&NWRfEer)#y7&BnMZ2=|F|n~gQ1sf|Vbvqk%LQ6={PysoHS^%w4C@=Ug*th6!^zXC zg3dw#GZ*i+2lWnBlqcUX>CDzt?&nr^;>N~ak$;l!ZdWIlBfQQ6G{O+dPuHE-A+a={ zUX#p}n*xtNlQ@u8^-xAR3?r$-Kl#1dEn1$Z`asQVZ8crXb^^0D=dJv_K#RwfWe$$1 z5~g7Z%tN<>shfjT(%X|3*L|PQ#}jHK^#@B7Bm|?MIRT+^xxHi2<6ie<X$p4&G!eNa z+8VEG7@#=XeJbj|OpE*=?(fR|`EUsl<HOxjA1w_{DQOu=2+vt*X|E0fivh+&mXNQ- z_E39p*4i+W_&*>CaS-~u$j5F{ql}uKM@;U*Kp{d^MMX|(%WZNLkPprl7XwN-pnx`1 zQc`n{iB|ODFXsMpm6wOWvh59*88IyST;VR}DlV+gOm${}lhHpk^eu-!er0P*NQh8W zTRQY!oVbAeKV5au!~|(Iif5GX+C6ZS2UP!IVpc+MvMk`w5y`x$zIqV$A8)w+u^Fcd z2oBx&qyetem-KJbogaK~WrwkCzXtF1>+m0&WDo|QKwMu3bSdq4Jyh48oRGVFi4_nF zbj)5|{qk}-SewJDpy2K3ADqBmVWiI6+n{uxj=aqv-m~#(XEgs6wZoAgVqiI&I3vbs zhB0KVV4{eZ&-bQTqp(5H;h-YzE>clbL0TSAbd~zT%P<k<*Z<}Z+>smn0hB^dAn5?; zs|)K`34*c3t91=B4#`l=N?ROdCJ)V~)WfEa7L!PcO!$lf_g}~|wtdxf&yB202**sk zd2@^^tM;Re4Y2V9ng|r%HY15;)$DVrbB*f_LOf32N8U)Uz}K&qf97-(q4yW2aX>7! zjHm+a;uo^^00^#QtH07aRso2g98I4;yp&GNlWxN!B8yE(U?$94Q!sqxKMrU+{0%KB z%*<dvB)*s!8zX<~IH%TCwLn_I4IMr52X!KC9*1MC!Ivcs#0EK029NcYllHGS_3SY= zDqv~o`ct7d{$8~UjqpA|V+<5pw3|F9551zKN9=D~V0J1Xh|5)bzKz!vIY0C1p4cdf z-8~9w4&KqM^-?=FI5(GByN;QaHHmDw#fRcv(5an$NAx)ow+a#CFKgh8M@N@+P-#); zeo{V_@(3jZ`K~_F=TXXxSs%jqB}Y_pQB4{q_Jj9X-;My&9bLTo{_2%d*!D2t1Y|bV zVgoMVF5=>_Mr3}z7s1E)kk03M{im_|Js>1gB4sfP%zrPgs%~a=Rt`n&8|)YGItdN3 zpbYMej*T@jlaZ2pagV33dXClBfJ`44hF3IQmp|&|SJB<F$4roxDeKmK>lGr0e}ZQu z8f>F_ds@H({VpLw`AHV9(CK$0sLrjiiZAU+uE&p6llE|l@NG;@WuudWcDb><?rw=l zh@P7spZcuKEhFnElx>yKg56hD>RVf9h{~(Uen>=tq0!BDnh?{)k<Vv9W}^?eu-h7^ ze!CNp7f8<s14#XHXcPD?%P8Zf95J^)G6+(DMSW;2=tBUs<8;cPq8R&Y70`Y0=xz;p z_umAI)Egk?7Ni!Z^#>O;yFaUZH~lHwhlwfUbISD)s$lJ$Of4ZEK~?&eim}=!TsUlD zhnngVSW_I6a~(GdWu8>awdiqHfE*o?jR-W8l$4A~Ow?(#EzSwJPdZB{Cbk5$xo^^i z{U51>wGbosz3kxdoO3%XBeDIgRdV7ttj=FEWHjtf-2;W&-*KerQB$!y%}hbfzanZH z0qi{>eVu~}kU!Ddd<^MnCj7P%s*=`%XBUEIZlFZBq@9C<)_Rr8rJqdeTkK*j>xncp z)Oou!==5q*9z5t$Wl8Bvm#jgq;sv#j7{Hhnu&f3FU4lZ=JvcJK)KEzY1>8jG7WwAb zJ<D)y@Xf=>)+xm}FTj|x7(j~k2IW7Z)DGVV_yd*w14~UA=~Kol&O>Y4l}3t;Uw}kc zSSBfn5EacA6LCDAqb2GZ?dd`~_YaL&;Ly+qWUTR{D9f)LI)n^G3Q6mEy?e(Me-$r7 zVCEKC^HeCuDXbw>_FYuQ!n|N*x50FmJ@u{{nc7jV{K7qPq4e5r7z6{5yi8Z?1ap-p zZ*Og@aQZAB1#CZ-HSF*2np;^^6sG<DO{g^WMoUyvbJHIRet3XYxt69B7Zni_?Sa8& zg5C#4c2>j3PTmoT<<NYvSwV4O)!AS_=xBEYPKfMK7J7y;c~4S2Hfr=(qEpU(FSy;6 zkJkmpH`XY55%I+V&|R)eDkf}r>wo!AQds<6ZC0dB%!Y=*iswH`VX*Qw(0~w(b2LcD zrf{#{3OWNxKI(G_@V;l}qYV~m(FwREsXyFZs4NY~<mO_2Sibvnl(raBlA9-CWMQ!@ zf2d6+<m7N(@efD$%E;~BaPt`qD4Q{ivS`&-y2|k(&!w*KKni+m_=Mp}d+RM7U7wCl z@~Bn?hmeqgy!_Es60V8K4cSQ9aubj;KENm@3)WZiL{o0U)TN#BfaZi?>;opc)G+g% zZSTwV>4F_i?XH=g0io4^@8plnE|=;WR*X)_UwHyz`YZcW#fa*a8SG=5n0;8t`?m3# z&OVV-6u|K2nm?kyldH`jp_re6n7e9fRd!1*HSe;<Ylfrg2>BUDWj+-|u4Hr@9BJ*z z|5E4oUt9mT?c@JnMzB$)`)1neioG@fwN!gtMTNbn(OF1rzPj<r@$qx*RAg}Tdn5<E zkcOU~o`&ZBIwbMyK)(u@iHQkGNdd%3R<UgDy8Wl+CRahH?bPNJM!v13n=n0IH^e!8 zI9XouZMx5$kk74Z@3_O#+&JF3#X2qv+^AO`NaNi0=7cMXGBa1HdLx5_f_SHjI4#!Q zwb}m?9T4W+*1eflo!PKNX4vNTL`7n~LaFwpv~=i!3_3cxUeiT^O7rEwmdyP<$~KFp zBreLo|Mo_v94|JoPUg$=+8@8<GgDPn9bLI!($jm;zlPmiJrt{#8zD!%nux^60DuMh zj@q12TM5_xiwihm!^#ly&9Z`x_$OkM@-JoiG|Q*)nwy&sCG*_Roopl}CH2au9!xfa zf&RDj^pzbYsyUvkgJo#3+0`2+eoRbE^%70b<FPda!uvl?r3Ym0p{-0n&-Dn9nPwLF zz#js(hf^^0u`n^JDn6P81N|5tEggV>v_io!AtB-5i=LjI>)Y$jUY&aQ`7ZY_P)|6S zot<4`YH9~^?0?E%_$>MQMUpMBTsys*p4F+h?7#eG);}=N)7@R&3AE#%>&WPYy%(2| zsKx~<Npt^*p$3-e@kTw`eE7Stk5~l_k57OWK_G+Cu5#8&WKR15u0J*hUF=;<O>qzl z`fQgp12H62I!F8nET3U`*9Bjxj!LVR+gB%G*8k>&2zZ9m?7ZLqcQh<m_*WD;03sf} z*Pn8=f0;f9EZLtwnIn45jEwa23p2=MSngoC7zX6^e9k+R^fWw%hz6kN`xJICcBG=I zS%1{ZLyC?n)(v?`?fs8UIZ6Slu<z1qC+-$RTH?10L)`Jv(Lj%4*45+DLCMaJISrsM z6cbwuQ4NX;31Q`AHAH?7<hiEgFc5m$asOkjICK4BQt88cHYEjx^3BvLHa5va<YyjV z{V#1xA!R_|1QKKsg1lvcWL8xCLT;7o8~abBWi@fmCsF>XA5esz``<+gvkJVUkAFbh zVG&jmjzl}YfB+vnc3MAiS2f;DBtAQ3uXf~^R{cbZj#fnGe~0rcHbtUPPeo5mJ!lX) zV#HEG3!Q`zAe=~zjU~Y+DK9JwB~(F{14;5O&%-~63NRrZ?ekLKzyRT%MK5jsad7l< zF+uQm%dX2`;}eP|NGn}$0+W7p#dTy;q7}UYAlWyszQ1kb-{eL0XjtjvzgzxT)%Rhm zb^<!!?3K`gZ-D-BtYTAEj?tRu!BiyxY7?;;25<Y@{{c=7KZB>JDJ_V90r>7{e37*( zkMD*Y!fN8@_V*O+t;Fvn)F~`u9A6>-DaNXXa620Q)!q+MEgztv?}SMP_~h|m=GTC7 zP`Uj7(Zley1fF@h0mS3>ps_YSFE%!ID6!4uViH^dB;SmTGWk`nadD%_`Lc?0CX3X< zxb2`kQ$>XZ1wi=}*fvqf&H)d=aV~cGzAl_=MMo<E%&N29+~x^x`6&SpXnixmW-*Cj zXDP2YAUKMWlFG<v!}H?kYHg!8l*MZ|1~zWg`=9PmY=HarDAj=|2`jDjt)U!DLg{gF z$hc0E;IVLxf1@Hpq~xXA+^*g?cmJ#?mpt5D%aL$AJw*~uPrRQ!KN2cWEZ66@n^8SZ zlWX<5Pz73d;^R#uGK8-9+#W=9b-k-i<(ga$DS;SU<t{HjGNR{2E&!sWqB63z<+AMh zC?Ft^+-7q(BIx6p#^c2N@uU6xM7RHq-BN?g#`duPzbid*Izz)l3$<3&7H2c>0-jBX z1CpKaurPL3)|E;pw^8zCJ>pLkf{sIjgM2J3<)(7Yl}6%|Gr^c7H<yQe^z{8#@O$43 zfywr)H^_*wZrwYg2L$w)nVHwJS*yUmZ0L@r3SvE`$}AolEw&}=rILs;Xs{3I-593} z?zC9UuZ_cll)4<=MjQ#;Ny<3!xgAM%1_Wb+e=}EIcZkW*NtJ8X8Q;|n7cnrTHJ#JZ zt@_fRT$1s*9n9gsdL`vx;10sL;^N}MYfno{E3qj7L|1CXv+u#VV>0FXtxeuH1MA&` zOS-xMO{r0)?F0ndAgpE2iv#&2(2^alMLIB<nIaPdaO6f8I)o^N5LumgI|4-WFIw3; zSNfHe4hML|nd6W*4{{fLXrQO6OTPNmX2ZFJ0=9@R-SeTfmJ72bYEE;%+Qr3#&L^N@ ziAqe~D@!~aOEpp(J#zf=89cKP1B$h7fTuAxv$C?b{?ZxyJ`!5%#WLMtHC-f?1Hb=& zXgkZeD%&pYd*2Ew5-KGipeRxTN;e7u0+O4M7U}LzQCdKxBsU?k>FyAaknV2j?v8ii zJ<rTLznKs7VdgV?Z{XV3b)M^7$8r4E*}?h*O+M$XTRTIg93acED-sd|9tGdEzjvo4 zFUfm(Fh`_*Vxk%vC$O0iVpUXB0EwaJ#Z|q90=>@GU#$iHaOvIO8uga%g=dWl^1Ccg zBppQdQt4x0b)}(vMOz8TFi&s5&BRDVw7y}bE5qkHGY3uQ){ob*;jUO8=@*C8)5C`k zW4UuQ_25}4C@68-nGa~50k{Zs$+n=W<nfXJ)hproxjD)wlzEIYtGd;9@w=fL8O37o zTIk>ehfG;XS=zTsZItcu-aS<=EGp`V<LgdR)WBGQ5Pd4m^z@x4Pa0FDND0?@uJ+$l z({Z((pVyTW(<pnt<atXE7zsF}Twmp4YA89sdN@E|!fI#x6~U>=>Gv&MD!0>nvKhMV zTQvbm4)zUdI`__ziEKMzp9mv4G*8=C6qg53zt`57EqeL_W6Qe(F9Xt>M%}%=+zzKV z)Yej)J5u%$RDsKj&NhDTW@xo%RQPv^l_!6(($b1OYv?EzCT$vFVq#KOR))ntAptqG zbgEZX<EUkz`LNR7*}3lM7NMQ-Xuk2%%!jKdy&k^4qHXK~l+MS!v7B1Vdq#24Gsnch z-rsT&1B1`~5t7Rl&K3Xo_*hSp6mmAKEG+ST9ej&_yW(9tK!!%53|vwjwHgE6wzeq| zr|n`O>9`zB)Mz#Bt1{Si#ed+oThm<`gGm2p-+;A|qJqsCh-l%h7Ze=XWfBk&WWOy_ zR#y)^BG}&EKE}D9uf2q^Z~GQY0t?D6P)CT1i}Sa)_kVSE>cO7@YpUkiF6#H`VPM~R z(!<h=%7IK}O&y*7DiJe5Evo}ziB3o*EKaE-aB&@%f+qDMqoa#VCQ*?h88$2I>qFI^ zQFV2#&_!fWJzU7WlXSdGGE^yKWXG;ZLK40E88f9NZTN*^J9GwOh)YX0x{?K(7{mz~ z-$PDzd3&ihRl#H=N3G-otnTg_o_Tq9!X}6gyZ>maX?SEo5#hl)-!;19)L}QqM=CvF zXYb_yG5JD61E?#r$%TcxK0Y_nZ3{Ymp8D#>KQ=KlYnpaGAy9U7JYHcpqi<{XJSop} z5)ZhRe()#pm2r}8FUU+s*K(^m3B4NH33KvN|A=`8zz3k>!M+Pu<bTFhiu<kZ!f_uv zsOe7;=z0^+xVq_4YQj^Ffqri~`mhL%AD16>dY5`gx>7T~9IS5S1_mhSKRu&EdFk9> zVe=eeDCfL8jMX(CUM`KB;@}XIvAEpG`bAz!vemdpgoOOrwtdQ0W5)g_lL9sM!!jht zvtW<E`xWtL19=|tB{UtCU3b}r%Tc%=_$j5_(D^;a<p(|}rf$<WN)vni`k8b9?D5f= zn2JiG4=HFFsMs$%|5t9);k~O%nxSrMZZ;=MQ!hnMUH>vIMzUx?^*C93VOG@gG3?-_ zJ+fdv|DytTdN=)^n<JcEAjBgem?zx)yjw(ccn6d+%<}y2$q7+Hzj$jNJYwd~Ib^*2 zLjNgYXqmRf1DI6h@rlq~Z(r&L>XHiTftNqNa!B##a{N!ZRhMu1@5FI9cu+&C{zot( zM7NEcRdYT(_9O%$Yw%v#v9Wnl_Zfd594ecnqQy@dPjA$c3of*2v^Y~L8}6S{;>U2( za@mf=)XXy~AJIJZK;^^P7FICk$>V~P;tWzYTSHx41)+J&ARmn5+p?C2{u7nAzHzva zA*$BL+$s%5)#p<m9`-eV=0C^2iKSI7I~V>p9C9AOA*aY`vKu}Oo1{<gti@9~ig<@0 z`?aWqR{H0r-)iNSJ1#GtA!s-`%W%jXa#YS2;$3;aY4kxqizkXznZwM>H}4@rr%6f! z$W*%3MH_`9jEU55?o`fh5<-(8fSfn<$m~Q0c^U7y4yUF)U*7<?)wA84vR?YOH~NJl z5&IAh#KJs(TR-xZCYxNN%r#o^htXuQXP76E#INS&%9ANyw|BW7mCoWpjp6etAeNM@ z^I2Qx^4qM-1~HK47ZjL{RZDeiNGgQW)n~1|^$*7g`dn_ap!vo)CK6?lV@e8pj6Q|Q z;`yVE)6-MseO6@$mOB%4w0q-~J5a+ewt3PqNZJ@!?X3({FFMqZw2bwaO@KS@fZS1M zVYW*gYdprlbyAP9Urs)Iyb{1M<9TZ0q$XMQO&wifpE^jDd&$C`TO+c^;vFA1%w@-p zw3wH%JZIpm-5FUMDz%S7KC$GuFyw{!$b{3>9u1GIqDY3yLa~^i-yP^5S#0&l$^u9r zipTYP^OLj*(Gx~0Dsk?2@u}j79%d#;cZfG3RK!0H<YcEfE-g#cMC1TkAp6-}6BSmv zva1x))Me<?^bG1{582pUHxhmq89@p3TV`2L@tpXzt!?1K-e@hkz~U9#l|BU}B~(vF zmFr5}rpS{@e8(Wg?8#rPon}2<p1izpG>Wt5Px>f~yToi`g>qXQGC=AvKBnaS@RA&B z*XCM%K}ulK5%Rcdd*4Bl${jI2B0*f%gI5z_#?se6QH}FPLOjWehUIBYv5GHlkWj!i zv&n^<zP}X0b=A0w6O#4)X<Nh!Lm;1NV>oEsn@`lPASd@qf^mc;79X;@l!Jl+ovnkW zXl^%>i5%@V9@EhY;tF+4bmjU$xQRE4O`9;`iC7gEHpaH)F1yh6SL%|N=_|GY0!kbj z(t7rd)1}TY3NzBZ#hD=qQk@+vV1+h1I8U<fs9;N*OgohF8tJEGf0#HcyQ-3M^|jmh z?m}nWl|rg)tYuU>b?;^pRkgJk3DI(|Q!4*N?&b}y2(Chtm)FxM^d10K=n=RNI#Y9R zn9xhG72&o}`xCZVW-q+14^7M-FCDG1V;7?(DPCou-Cy|H4@Y&}Mog>hjZ(w$0qBQe zyuhOgjN@5Yltw5iSuCYX;C*cjAbtu*IZb5^DXNFh4Z8Dfpt<ISvra-l=CC{Kpv+l> zl}7y<r4Q|)(2x#|@+Xyw>FKng=`@Q&{kbWJua%}Zx0plQsHrO*cU%Y0A7!bqB$IO6 ztTUmZMO{Gp+B*<wI`OkASmmQlv|V@9XvtPQkwVs_u%?`Sdtr&Vf~k4>0>@EFFq8;J z?CbHqeP(uPaKQP89oY8m;(%89Xz0$zI*LT<%o~h%kzWo6dy0T`7sqCSmmCAGZ01vS zhUak7NL}nLP4I7im|S$kvq!>NSo5KJy<DP#`XN360fTzphx*`q{JJ+tdH3Hbt9(N& zGxZG?6h5Q3x&Db=W|{aC`$)1NiM;&W6D&2Fz3}5<7Yi)y;bjR<PR>G{-CBC(>OkGJ zT|-ZPrr@j?zK!7wrzV1SV$)HZFT^q|IvcgWUy=);<17wWh@^(-G0H?4FAlg9Kigfh zGn^E&|E9aY?I4-O)Z(GWRa`dZ@X?YPF(%7pF;Btjy4WWnCYg}c`%^5&{*A>hkHb7g zmfPv#L%7ick>xLN;n*-yzH=pZ2e%RXVB6(<Dh~${^PQY$pX~W}@;T*BqmplTi&w`w zgTH)ZF)j7*I4xGYt}phhAYyy{!=qH{rX3tJ_4DCdilKP;`{aD0R)J)EUj$AYO`L`# z8SA`5ZBM`?$kkMCXCNXH6vZ+ZgE>3akRd@*fwelS)p?%ONA{g2*;L@wujEDjt}+S2 zTH-S9oVOL8#Dy$d^RXw;JzS-ba*h*vCDi+)yq$Zg20g@;<Yj7$M?(e*UoDvVHk^Cm zu)7DxvEYaZx;;v<m@`Ma<n()#sfD|{eTCM3d%aHrQv^^Tr<_-@GqJpLB106e4HsSQ zp9TIN=hyq`?`0**g?5DH{z_IveR<;$<>x79L&9zOtUt)0efo|}XaY?VH7zZ03jAn$ z>!MSp^i6dIR1*3c6t*FAO(Sk#n1(Ey8cr3_!>Dj99|@hM=E?JatD-zKkZWm?ZKNG< z_FnsSz;#-y9s<FOaTlKFz5<q9l)B2Clr_V>jlHjE`w?pc<NdzGH_sexTn>MFW63`C z6T7t_nY#K~;!ca`Lu8#nXXH%aU`S)YJEO)r>Of4QE^#H%Jgbv|T}f2k@o9sRsOYbC zwUJ)UgmN<=EJ>T+=$F99!%Jfm<;=_^y=|P>$9lu8Z(=}MSh#Vl@7r>0va79z>LmlA zAm55wx`(f;DL6V>q&Ay21K(MjqRCq<YqzW~za&dBl^{CT$#&)SM%2IyMXEH{H>m-r zyoV;9QK7|b;dS*aJCMV_dTgC!OX@;_x0^FjTA!^TCTnSa5jTHf=Ap3u^O5!Y-aV{z zT*OEU^Q_v7+uT*Q^oHDTX=$5#iD|l+8~V4PJKTLFx~5*dd6C0R{~Q8(h|m$F^^t(G za@3P>9w!3}E?hDvUY$e2K=rPP9`ZYCeTnn9u>#h72>;-09H0BL<zJ<L(8b%mJSnq1 zLaxqv=1Zarm?)2kj!=^#rH~Y9RcZrIKKVWsTJxi0U+)Um=I3it-Y>kHf_X>gxplt} z#*Q_;Y3m53wc3jRp9PQxxN3ZU7#JRgkvIH`@!}0$$bNmqNYzO<)&0yf9ZTgvx>y>4 z00f=Z4&|BCo4-QQsb#xrx)jaEl4Z%m{D$cc0c*Vlt&T)zV(&=x(pYsq44VO1u^ zPnB6rwDsc^J6xk8iSw??$mAI>;0jQ#4IN&yeTxtbAO$y5GRO82y?GfY=S6xcA_`m* z%wdHz?9%U3#82h!eD?XAl3CyJf^h5BE&sH)bZ<XJ(HZNxU^s_9po!31m?bb%3krPm zOD*|hV+zZA<1})7+~|mC5&U*wI^^S`jFFLhIV3EtBY)LC(f8UOe2_S+chJBpotWJE zNZ`5{_Y=0j9>Zisy2IvIi%a?iSD!QrZ=4=Ua2p=V+~MV<43m8tOVX#T)j~jo?*g6n zRz-frQhB-1^BT7LyH*PGKa(;rD)vcz1AUWzNRaa;%iETR&o2=86c*wY8Gf5tmtQrI zTKwq~7>KWqgCDol`Qe;J{~N`sS(5iNotP>twOG&(xAjLhK>-5+LB=GyxWcjCwl>|c zUygwDJDzjUeSU6(`M<f=P@LUGS}Mo--|}S+b+4ykNcz^qNQ4&P#r}ehma$+|*YGwC zPkttSAlU$t?@4DyN!r$wbZ@pqYl?;w_SGxyr7z5L_-u;@M1Rr9{YVmE<<>chqF)=e z@8U1Hf3sUo%)oLo0k<A~&tP@Jy`|H`?IYSzShg2}H4vlGnm3jS3!m74;!JB}eYp+$ z7DN=;5%)(JRI95Oe&iilrGyqBjjvFsX0uT86o<Y}5ED}JJraZ1coK4T^?r+}HPj@> zI-wf~*`8}=AEv#{<o&W%L%oAs$Q+J3qK-+>TpVqh7ilOe9(zdGAia0CS^N6*y_fV) zpKHBWs*qd8mcET=ETEuJe9G!WeRR2zs4}q2FQ#Z4Ca0yR$>|j7kRkyRL#xYt8pIf6 zf^IyVhwP}2L^R2K<F=T8@92n*V1okpgG+hDYKWSpRT%eHU>t|I;@$a<s8>p-?G^54 z-ctF!lwy^3;54O_DL!Cxx+8p#a;YuTxRyH0kN9zNTvc|*-aaW083`ddE{Rl;iQ!9` z^c2$DW!(aYyghr@_dEP>9wO7)t<JYu{kGo>4|SXghzJ*F{`rcMcLNvG(JDy#>W(fn zkgs08{EItiYBu#N&skU7Zez&?=c}xw9A59guDnnMH``u<wSeLg&V9ay^WKxGV0L*H z6O&A_SWZ4Z86_oOhIoWwYUTxv>h41?xsaqv?p(72rC!%0`=5<}FC5!Iji)nsvAtJO z=0>mQhjg@993t}4XzqiOfSQI<sg^Y5Z_Y5P;fXv@r!8pL12rtb5^!4O%sY3Jwyjs^ zFEPc!5Sx`g*cLrp-b}}y1VIKF-#>)Xza`P;zM-;86e6(fWa_5(BboCjX%6)Y4!F1> zk0_EB^98H8iahu~$;!@3y%CFJTVOPNdXrK19Q)bnIf=&Gs|e?^k1nBlsOnO5#~`^x zT_*w=p>Tokv03u{iYi|ZnE6vmUABLo5V>62mFc;&(v^aiY+LTWbK0=dX(oc;ox2#t zC(G7onuh4eYVOoiTKPH2%F<6iQvy_nPoBWut=po|Tiuw&jbreDj{D?XkTF=1zFh)( zH8h^Rn-IkBhyex*hZ9ZvV2(;OgLd~GdCFnSmHzJGXm&tXBxkT4^EuJvZ+o^5<X>;8 zYx~qeaO{K^nQ$tV1r@k2#wOQDl<~%s<6DUhu`4?VHC_RfC!1+qQq#Njc$1&FERK1& zaH(f{g-A>!umF6NFNx3f;GkvQ5>CJT{7_x?=YFUfG#xn_?c>+h(J5qQr3xfbH^jLu zpd;DB;&xgTGyi?Nz#pL&tY?XMC@m~JKlE!S)Pm+V;d7x!-n*&h!u>xTZYctvL%;T6 z!=5Dgc$UP@G9CQ!XXluin5iz<@;#im<IN8CqV3w_N<LwYjdPc1RSVOf5chFJGOb97 zv7rnM>d_C9hh_)j`Oq@UZYfGfrM_V{7`rhoq+FseFi13iQRQdb-+&5C@e)3gqA(k- z+(KDJ7?2q@Vv_eo42bfFG-9P5h_i~fq>OVF;X1?#A94S{OKsa8d~u(2)ozv7dTo9@ zF9|(jEQ2xorJ$fmU+!O!3sIDpNlD+&ME!<xDWh8XPTvziEgoBKEf1Am<9cqKdFZ(V zHZ0SLydaFBLN>1FfB${N+iWy462s>d>G7^+Le10r`rb;J$>0ajK6~cVta;<54)TlT z%W%!4C&}b=QsvUq(z+6rl1g;=y)2vECt4NE68EpDDH;q{1~-!?;-xH&;87ZLJ+MxG z-*WBTtA)#HTrC#LWj4*WXSSgX8^&Yh-cjawCTcM&;gvxifjdyi?Ly?)MC+#R{Hz59 z^9?>$LxG6$9gVS9s1zyU3d?Z?xDUdwyAbRbpGr!^jug#GIj>4cFghYwJUe18Q@*3$ z1-M<_>?RZ_z82$^C*ySx%PRfK4g!RG>6h1?FD9GB62;ys3x@|+?+-G33yuUK2$hkv z*T7kjpKo<B`RnC1w1Kg)vGb~myd=C^)CZr*>)q09)z$fgu1)VD#)ErE<W*3HuRnwx z5zCbz6l7^@G|V{D?h)bQ0-f@q^NKda)WalM`}$i(68-X-lATljUd+l1TDeob74by) zl`tao&e8|zTGF&;;vvf?qYg=yM)Ai+s?L>h*&QWnSw4&3IQ*8t;V@?wF+&>r@QE;b zq4Kn*BRmJ8N?~+eGU=97WNOk(eK}pD3GCT9sR#um?r}jPePq;WMui(%=fvW-w_N;a z2jV{QHM>9|a<qeUVzTL(KXQbSU53E175%uJ;yM)=U(~d3$Gs+3vbV=m^fIEgKB*my zqrGya|G_^7wM??OO`#j>VTwyr=Mp@7PC{YbfosaN)XgHoLX$3=-|Y^-rOfdUDwq-g zXV7`7BqtdYRaP!{>+)_+yO;i}KQ~|c{5V?Vvd@!_<>7>%5L9t5>3he;d5Ys7@#1v* zKRD-3dkL+Ae>zM#bJuN2&U0SErpb|Y`QG@R|9IK|5e^-G%YWNe`Y*jH4otZmX1z`c z0C+d&2JaA_;@`b1d)~%wItK03gb#KbXHv0zDwbX*qjp}OyqMloJbb7*ejETQ>YHR} znDxv65&h49>4tM@WGZsnh+<u7he+n$Qv0+yIwmnO0fBnQY01Xe)}D*l)pKxQbZSs@ z*6%F1($Jtje*;l2#rDRWS&FQFEr=Ktmq~&jZn)(wav9L)zu0P81=x45d4>Z0?A#n+ zVvLQ)qFur$49qvLtBexM%Hp4?+8R$%@I-|~uPhwY6?+AwryDBye{wy3Oi!uv?%faP zo9&SyA&B}$Vf*)%mX^k<G0m?8oZ>)GGBcwBDMylqmiBmaT1(xv+Ow<-4mv6KNJvPz zEjRs1&SutS+T)0Mpk-f&i;$HS5a3r*QikIU6aEX5#H8=(iD2V7n3&W6FXvFRk22!V zg^;>gTctcVKR;1!<BhehJ^$IjBSIlZ$!_f!3q+1|QJni-HEuP0_)40+^Yn^ORc2OK z3!NKiF^26n#uXJ5Tu=7L$M|(|h<ILW&x7>u8<MK5{C0L>AvHBMN25d;fv}oRq<on0 z(8+G&`_Oo@QIO5bz|io3xuq=$kNwp7RqwVp68c3Iwx)vv1BoBDaG&&g=<25AsMj1h zO(Ws82`L`QVQb)k?`nhCW$5?WX~FA-g)EOKC`3LJYnkXIC!n@weFwd4j54#b5|fhD z#-l&EVyYI{y1aNXwQmwVOiIFJJli}iSoGtygU7#m0YydP>*~KsPIs4fR7%WxZM?vJ z%3EP48{%$xTDVj|?Tjdx2Jz+OV9nOfDw(rlZ;{ur&u1V@xo0y=rDV`-%z1jufSi01 zi-et<qpy6`LFe~zQ4Rv3cfnWUDPm>F3gYNwm6Zyb6+he{Qj|6BA{P(95alVynRM}7 z=#7r(v%7ciAM@W76~)HKO-_DHbjS()=?ri=BiI6bK3f}1Wj<h>EHuCcAv8+z!^v)B zL0m)!;^w!z+N1lip93&SSPc*5>G-YoPltP{(y%3L*7r#(Fv(b?!8vR1MN}|vy)<UA zn-<LCygRg&_xni<kA?O8XB53k5x33pYQaKhh0Tf>DmIpriK%C0%Y_!%8Mo6ki|P%$ z&y{O>CVVVa+x_S|>M7~Hdwo@UNbiG<=H`~Jw&^=}aLC6JK7gmBhlGgPakl#G`f`6( z#o<Pc{!G@WU7Wpxj5*<|=z*zPbcudgWF#s+{>#^><MXPT=xC$C^(wK;%f3WDRpUH- zm-yZ@^X6JXZxKxLa+^_X$JW6d^%URr>}=3o4qUh0vvosl;{X2p<9$-2$qK6wFK7g@ z88z;Lf#X>NJ7y&ahvVayFtyv{We!K2We&S$EIR?xi>ZqmuOmtwc$7ICZYmL_cZf1? zCM9USC|VxMs~Y@$T@Gj8Y0I)d%BEeVP}hvJ%IQEofS7G#;)LIIMu<@+;dno`qD|3o zqLOCR2|(zf>D?&Q#qvp9ObpyD%vY~o9l3UvhC=afZA*%Z28V^IRT&;t9=W-m-V@j} zs6FL%+JDDgWxY0XbbjV7r<6K?w)R-<c6<Zi6y!t0$oU=WI(UqSZrlFo>wC<`7LJ~V zW_i{qk#5p!2weRng-@Fu-~k&<mtX18ks_{k+*1aZxq+0}c-2?4-XsSr+aDbrY!noU zhl}InEV=yLc_KlkecAD9IxXQbp)8uGW~<NE76M}{g6{K5jwbG-UuN@sf-6r?3qNOq zf{{3b;Uq)!EnUb_`6|#ALy;Q4n#6yUc=$Ql^mcd0J#)QZUxQ#?339k~u3lLva*z$O zdL&UKA7Aw<51uF}*xzy<FAjFt_I0$j61uWdP<(X-LNvy4ycCkn69i-TkAn1&CorI) znZ~HXjA+GPTw3nlDC{fT+}uoC)UTD4eKpYAtK;1-*MBWqw}jhtRbNeQJcLRr>uuS{ z#6-4U(7GHk;RLcHmP@^S7V;{cbc)#$kxY3p<G2YK8THuaWl$Zc65qIW3!$ip+x8;B z`{$=uDaOa>$Hqvfe2e<>dXYfW(Q2)Z4Xc&@3~rNU?c!*x%SSL!*2&hEfj@-M+xGaP zr$@GDcO&hw_gPbDlj65dy5`P>?v=X@7m5a+o}PWLzUXNi&;c-xW4E8`=~L&{0h7x> zjtF>3VMX}8<PdhAPHmNeLP^H4d~ms>xl5?U9;KvtNz|O|uK$`i5Y1Zn@<kd83yWAC z7NQGR7bzsC({vqWaqkULajA<7Q*Rl0bp%3CO|5>sJs^r`b@xk`G)xpY&JjjMCtZ`W z%4hDC_atK0!@1WbW$y*%AbQn84vs^?SK8mT)<%rY8Ep<;`Rray*Ra~K8p`C>TR%h1 zn(1r5u4iImvYz`8OGZe}SZU^=34mKetu7pT4!eoJ%U}H&O~TKAe85f@tx-k0{t)qM zj*U}^DA<i6`S2c*S8I41D7xP$e7|0NR=96M6M`HE%k3iDj@ISj>^U17=vb=x)(#Nu za&@iF+2{?+7+^7*2#snW<u0sQb?{8-HHI#ppjUwN`B>0V3MO0t4sLKJ#E|k@Z1-(g zE%g2X+tB(%1;0g|nOg_4M1QNNt?iAi*BZC24%m|C=GI2tazSLpv*orimcq9##yFpt zbesB-Kv8A!35$&D{YhZ#QA1v}dKH&kcf{$zRTUOi)@XJkE}P>v?6uLb0w?_E`cqd7 zExYhBy)J&V^U8je-CG_=o>rh&v3J-)dPp%s(j;%zV^?>Dy9_jTq555#zU;LJ5D|wG z<a7+o39A>W`-zDHLTJZ&3dJ$6BpJIgSyZ;vGUV4Vq@o$9*S>PdUA;Wm_|1tc7n_#o ztk@E#FtLS|T&N#XVL>HgzWAjU>JK*7=P4tbnUTHYs%qcNOnMuOz#Or;we_pHt*|h6 zsMrQKc@riIFsfDhM9tExIIi-Wn;-ef-?~tK!94m_g|mX?J3(c6`N)T>P6ilix9{;- z+mG6k&f()N(vGdGjiUUJh%u$)?|Ul>jBj&uO<f4NxmC*DpSewt_fRS?^pV};*WC8n zGin*(O?i*LyK%Cm^%{1LZ!@P=Zj+`uI+Vog14XTSB<w0hrc|}lZ;)I%zvt;GZqZUx z-{&htVypprKd&(VjgQpZDo0Kzb2f34W@F{Y1ii9~GN@@V93#V}z`n05+1mVlF8!@t zDyg*Wmy8y%c*}oNj>W3}F?(qg$-R8}@|Cu>rKMkNR#to}D;*!-L+}|)Ost>qO2mjw zg<3#r%Er27)Pzc}#Kp;OX=O#|)hpR;0#_C%d;4o)({w{<{Jgwpd(kC@=<@hser+1H z<8=6HC?6l6G?{wg*+sN#*OnKTLu;VPCbKI^N@`?PrV0Z86jgY11Tr>6d@It@=W8O* z0Ui1N*XW3d;NbR)h$=&riljoy-Ok9HL4F8@(42STSH&*N=oU1)ydUUxh5~=`ioNj| z#5y>x7vJgx3}{4wZZ^LHqk}+sO@B-I-I7~qGl#zXQK{mc<5EGIV$)$D3t!s$esn&r ziFbFY)6&!o_Hd@$XiY@(uSrIU#f}?Tj1Zxx6JEX?Oe2>!-4Cghcy~8NeT%YK#L`zz z`q%!1FgWAw5d$^#&j==YX1Pn>)s>%D<y(dsm1h*_nZ(7#70>)5)6Rap*c14po!`be zWnjRp`RIg?{LWAx#-L5|m;7)fEx*#;YJ&0>c=r__?>Y+C;EJ@gT)&d=o*5w_`K$;+ ze2P*<_J3+@i){(oaq0;FN7iANzwI{8ec#SsS@DKa)-;C%IG=*2rU1%K@+aNlZvW1z z;?t*Ba418d725aL9E5%}lgzUH$NV+(@@u`D`y-uoNUEe@=x?Q8w-Xip*}Uxa=yJBw z1G4YQl$2?!9n-V3^V{}el@*0BS_QOl1%ZtB=`WOtOT-lZ?JwGTKq<;0_cS6jR7_G- zlNOv_VKoHUskCLW;SuR02kb8?{~5jHbKP$>pGmc43|1vDw*h>qO)*g@-_p`xi`F(Q zVf<bE$Uj*YA2471nklb%9MKve^`@=!!mmQkVE*vaD@Zs105sK-`}o)CZBYJcnYeU8 z&MH`7jAS)?j`f%_!Y<h8aL6DsQi&z^{Tcya2w8H?mqxe`$eG_SlB}0a>4(zN(~lnv zi>H)#MUNDkFz#5bLUnygC_NP(5|WTuQ5edi7$x3K!OmVnajVCeg*n+)S$gyBua?y- z^<CJ{HXmIUe`^)kklbfDGwRqDa$~VI%hew)&nYj^emA)e++zI5oxH)`lc36PNa2Qq zO25DPKaEvdA&)pu<u2zV)L^EUwjyjJW?v&P7g}C5{FI@|O<OgSON`L>0+V!9BtZgN zMo&eoEVpCH1$AkgOctM~2q@#;RUC8c%b~Hc2<WT(t3fnYF=rC%{9bxia(59z#fG(C zmN3Z2FE~700U__Od;lHJCEtUB=CnnwBBNr1;m_*HVKJO;lw3~~5Q4l<*y08r<sU*e z12|kMt=a)3<$X4pLJ0lqJfOp$-%d=*>d!)`=;$P8uC9tmIUCF=noSh3u&?wc^?q#P z17Ui2SlMo=OF91#hn0tEc_7yNd7g!CN@G>IjrL>*Bq5+{oDw#epVQrv^h<HAEEgiW zj(c+}c7U1yt$SQ`nOVnahvCQQfrG&N{IF!D!9Wu-zOAZ72VP3b0F2W|-uvM8NojXD z;Q{cJMY>7_kg}D3Zp@Kj*|2iqL9fWg(V8IBZ~QskEoNeD%wy<Lh<f|zCeeM}9T4Cb z>WX8rw9@sv*s(jAc%&SZ9T*NxqXxT_zTdFkNZ(X7Fu3X93(Zrn)?_#7o?d2IMDOgZ z_T1cTDbr~bS9^%Y7bLXkF9v$~*X0r-!a|bV{4;t)y$C`gLWHOy$#38v80u*0<mvtn z1k^Z<cCWtwe1LZ87<hLY=-A9T?*4AVl#!Jk%hj<{3eZhY5)o?Za-Z}cRIwv7&)(qB zTs3E$TnNoFm;vQ(iE*c-TM!d#7sdO|%!t0ycrkU8)CpTAYGb(ScQCFVzn53{Pn`^Q zNNRp2eeOfCmpHegUoou234*`#-aN0wDIUQ~Cvo}@&`zeLN{!*NizE<z{U-4i+J6#t zqwd{1-8x*l6{;YDL-OKi55@v$6fM;4lkt%4KGfcHkE?RB=5pA-OL@o?NGXW*8K}s% z`lIjvU6z!tAF1mvBV%<fw=qpkPhW*l%w`@li(o{c34{Gae42!KH-=P9**!w!lxnAp zy-A@KsQ$y#KXAy0BhRjS?2~f6%nF8-goApOP4^DEL?sL%_}Db@$ZOZiM0#>(BnxBx z4XO!h!1x~O7j!f&2!hn~ikQmE%uHi-*O%`t#k93|o4TZr6aFG@Z|_Wn$A#9`By}+- z?LkoAxfXbmGL)d5UR+`MyJJYyDy98s#kZ3=>JXH;W5MN#<f^ZU6!`D0EUi9z2v(P- zj}$?yM5PBQ{qfj_hKA`h-PZbKfUNK<@bRG`;XjrofNxFv3GyEI7ME<-yPnX~p8;qX z)~z!qyCeap1?(&<s~zf`-WVDb3dFY5_m+c_Ce(rmr6^@WX!zth%{i>uK4KryHHp$( zZLS4-1vrmExh&*_tw~786NM|>JyLDh>AAN$kf)K8z007_58P8kdqw767lQ;D|JQ7M zh+H68+z4;KssKv)i=@yXfGslGtCM%7M*HR^B$v^!Ud;w|kKr}pA^O3FfvIktoO|#G zKGFbyt`>T=HatIr%nvmGWaVXwpD}A@9O4g0$_8EX45ZOQ$>l=v7Lk2349ra6eFN`> zpO{!ngTA}40Y%l%oFXgQ$dRL}WgVSR{JE_FasK;J68(PXKd5<oal#rm#+=@;T9VSY z-!QyQMaigI9v<t>U<tHw7YljisO8lwMJ_Z}z3xSxN68uNG&+t)JfONK^UF*hX}zDh z#;RM~dR^Y1rs<Y$SATb)Zvb=OU`RxgLIq|8)$Ziq`|^gF3-engcZu*rzPS4?LYn6v zU%<C}vZ}dM!d}OaO$yCL`JI9%01O0dYy|XCYyb_-IE=gHFZKF6lY^xgEv1$+bMi#~ zKu83##%MAa+Jz&dvNfliOti<V4H*$Rt_*$|Y1DaF@#Z2iaG&aEntlxqjtq_z>UVS; zTzv(rDR5K#*51%G1u$4&))(@R>cdiyryd^8$K*M=J`8ggCp~9_^ENk?Jp?bPUX}?d zi^+;%@Q%0<TpHD6)i%Aq2(M#(n|U)<9niEBk#qGUzwDEgdk0OQeKm^MeD5B7G)l`j z;&aP0?UgiC3nJlsJ1gI^MHCsi`pi@7SR!BtA_29Sa!iWyN0x!#*-9!htV-^ZE<&iL zJ^QF`Zp8`vel))x24b3*uvn+bm0M*6p8oEK;4c6%Nm$8>jMsvVmEL7NQ#3SgvhvoD z+u`@c?3Q0xtG(lmBLdpx+NhGg*RS#L@Nz%awck9Jdcge!(1ChL!v$Cx4fSQFV`%vF z@y8>X0!g6qVSh+ZDa4O?+GGAJ>3DHjf4ux;^Ek`Nc*Os6;LRW(CU#boVyeQXw=~-u z1Vs$nLe4fhu2Ogf4sv&O#A5kp_odu_n{nF^y8WFRn<plSc6;zy<XPMV#YUEhgXO8m zcqEXGxK%P3O&iKwW2q*jhCiSDqY<Tk0P5>~E?ci@#a`B!Wlk}LVgq$KIT(b}mmqOV zY;Bm6vs0szL2v%w#1;~VOR<H@&>$`Kw1!o-Ca`||IuiMkW~e?N%qti-j$d$p2@6~M zebV{+3Cco<97`e<T@=emyj<+<Kl;oPWx28CMS>#Q<!&J?iL6kSw0i)zz?HuW+tP8= z(ukSgcb(T$Ng@yAWE2uHOgGkJGqc*3l0|=e<xJ$N!H!Zml7*<qkE2EKRS*vV1TD$y z!z+ueQY-I))g-OAYs&1%67#v3Bk>Sf*^xs17TcFZtj0g0utw$OLs1;OM#~(OLJdF1 zX17ab=4JWW7~&L!BDz47@xmh<0VC4)GbF27o<}85{~pLHUr~4?|I#PYNBYp?`_Zqt zQX9>`ba9f_Jn6=TE}|#6R;pYGU*LjmE5E=>w^O4hGj9}JbR}zC&)mAjxYAi%ULe=! zj7MOi0q%xgubW0QxovhtczA~-J3FiT<^e6(VO!R%^dwSf1kra>!f_}!#wt(4+ey&S zT{4?H3QfBUXDuEP=8S!xq_DdS3(S>Jm~FK+x85gB`)|(FoOWl*mf$TI?XvudN|pgM zb2fNn#{wQfd=VSTQK3J9X}blv;hONw;YwTIO&&PlYu=F|UQWmBigcS00#@v0?_be` zfsql(aI1^;ny~%_%1>&~@)k2LC#O;hMzvu?-J>MTy$hSJMH4SqjMREMdFO^_P><G6 zQ`6DOo0||D8UjFWl{%~*_5mmBr5B2i_32dC`Ae|6ypwZM1&z+rV`&@!P;%v*8_b@5 zW|l&!M}N*5V%HBg9`Zf30H+k`Xi;B(cgnP$YtF89QESfgdcwTgDz^>O%QmeXjKu(M zjpBq9{#fLU3hmj|kEm+M1->^lK9uj2{2(iX>mxSLHA4LbE|N1$DV2x(hXcRLKhD}n zc;_8cNeErSn)kmo!u0aP{yQt^f9cu(U#SN<rkcLbcNntWh>jSZ@PgabeM2xf<6V3v zZ~jXS_K<SSE6#}fH*eAy(AdaRIw--ZEBGHMLEZ1I9;SS7&eByk3)NI4Nw(3`(!PfR zK^Zf9(B%_?Q8e)J)hm-x>3)gjezFY<IDgKE5uraPwJ0s_r7?8V_&y4{_|S)aMLHIn zhku7>84F(iQp`};R+8arKN_SOjmupiLFB$HH23w9E8)E>hkUX<Ohjo6i(pw^M|T1z zwDj8FxPnCR1K1_u2mhX&QPWA6LbRg8moCR`goQxAQjNo)81=_<?BZ%PLLS5l<Oton zckiC9SZiLHI+2!_(f-HV>|&GEK28XmigbY2z>3mjE~GssKScQ@#$ZOk`xi<T)hXkC zOETpb1RmLwxlJE&ak>AwXo{k}zkVc?Xo*<aJc8dxLnA5*O(A(5G=rs_3YEK^7C98x z4q7r)|GAmW;EYVc^JiAp|IDWS=g|1SHADBy>DdAQy)>Y~CyrG*<5PP2F<S05s)>pQ zMx|rytQ~@O`ZX#gE4fy#CGR&?@y3wN!8)%f4Gl9hqIMUCmlm5$I-LIe1#>w^u#3Kb ze>G~4<nyFgsh+8=7h%APNls2S@N;|NUJ{g36o!w`gqWJqpb3Zhru3^<-%()m5m>rz z1#Rp?=FYRz?~f@10s_Q4%-2snAs<LeYEm025=2%5jp@e5C{mZ>-C_TT93U7C%b1ZP zgUAK+r)C<&i;TFR@q2@a1y({sBcsb4L``Dh?i-?P7Vmn^cv<tQbZDsKz?i3RX3K#1 zJpb$Eo8+e|)s~azAG5O=SPlCQ&w?EMBc5udnoZ{Ibk>{~mlUk@W(<1ckSmw0-6kQS z%3t*f)<VZ#%t=V7w(M6<DJ5doYBUxUyqZ#%CfWsg4`G2syPUZ5^S>aaa|`=i+OoJ^ zr8t(~t+qZ15|K-@G`)<frE->W{)CJ*E(enKVwRRIe)2}wlCI;B9yx8v)-DD=YWh9% zyS~02hm^BL&M(Vl4LX?f(OhoRJr#Bve=@Z_kSCJ*u$+mkqp-FvoSmC(LBd!CMkd;k zpF=*h2XFdeFe~VI>-+5)02F3fUX^oO$mRv9POf~SQs=~TClz%~vR9?ZusaW-NLwWp zvl;zv7zkcEIyz2H+`PQwKx}$`s_i_~9qc!#AycIe9FzDDR~rMT87Io+TRr{5oloz* zH!yg}BW3*tGi=suqO@)ub8WeAiFtfnjg_U^-1EcyO(H@8|COcXp2go(>M(2<uL#sY zgIyR(%bX&Gb>_A$DK6gG($Ul34Xa4slcWDndSid|=y(4LI}h0gV5o+bhHY(&SB<T2 zdZ;HR@<p`btMkBQOZmjaI&5)qQKEaN84e*|zT5^Puhtp9A}GCAruc8vo;B@kySQ$* z38|1|<oZxQx>}|A@fgO#4VBt#6l1jx8Hp}1s6)_btv6{09Q4SeszlDSt2o8_18HF* zxG5Oe<eVc#;#7Wh5Z%EuH0sM$sxf7ifS!qJg)SvYs1mvtx`Ts5U298ov$nQw*9$}C zC^)aGs-8}`T<?hGY><2V{{4)ne?&NgQfNrXZ}QvkwDmdMCN?PbAm!yzQ4#%4uiSR2 z(tayHy2KO_T;12-^MRPd{58OVj`!9i*8D_p$PX5~1EQ!QjR1S#!3KZ)6d5i_w1)Hx z!s|m*u8W)9?(XiF0Xb{CXilxDW{m$vxm!Fm9xCO8ksCj1>!Di<3B;Yxr0nV%8puFl zm^Vv$-Nb~RoLnQSy*6P$r<0CkFee})B$~q^J=qhj$bV74H({W!@B5w<@;NsJQ%}c0 zc+17jt(%wo<_j3C=#~pGHMNt#wiu?4k)9Y~cGFR-nKrbR#rvX{4TTl1fkfX4sk0{m zB-01m?e$dEt>;lmK!UV67~Y9k)HmwS)@hO>2rGdr!lDhr>84NVp?yoy%0RZQ!PL`- z52w2;Bi|LTt{S&gJo3iDRabcVGC`^LNx{PD%LKR6Lksb6dgL?L7(YKIgl3_QUnLOU z&fy8>;^Kn%+xlcqXQHQ@UuXsmZgg}c0BG3Rfe*-F6Kh@eZg<fFsBfVo27T@Q4WmsF z9w)!4r1ZZ<Q6H@H-{aAb&*?-c4x+Du$ej>61p~Fk*SsAi86XFoEuWFH$#t;CFP&pL z-r#m2R1e@JhnYDcBM#fycz9S@GZb_8oVc)IlB{vPR%07yuU;Eht{V>4^=s(e@;**> zrak5nro0u_>l}`KuZj5_R}Y6Qa3$k79H;A&MS{qCF?X|<D1_@9+y9UZnc{;^aOTMm zUwXB+x3;?NFu1!G7O`kRvZ1>yA)^;+KNdlO_p&lF!P$WXXm;sM-d;jo#$a>a-LsCX zv2T}qX>7a-W6Xtvh%I&+!}O}99IZFl47OQ<TeupAUw-tq*%&B-tRRJdXB?~6=F|u7 zVzY#Ce_!9^#KRc=dHO@EhhaTJ^JAdrf3x^4Zp_QT&v?-opn|8u%NSeZb}#@5Q0i{K zHsJ;XvLGrRAsAb$O{L`NDHM|WCY7N1^Acj12BZonhm)=!AygCD3|KHu-2UQR&~S(6 zV8_bV^8ErReI`Ancevjf7!Z*?biD47p1us-bCj(lJ(gjov>{>S2g6h7x-%W_>}uAd zPgYw+$Z}v&QBg|V>)g-?{g-<95qN-$A`%j7z7cj}Vi-kqBPB+y#qxdq{cCHqla~}f zcMUR#4HF>0P}fdZ?%-&<QRi2b4Wuq%jT1{Vq`tVA3NA7F=*R*oUrugrk!PuJWDh7p zL!iMi8-(*veS^2k%8o6wz9<x`uEcxWjBIVVL{rd?_ESVT`Y16gwe@+?CahTJQEXZR zyQmPFnTsOxyk=ukuELexiipL5u&{}f6RAj^m+)=TWG8|CkGxylY+PQ>1zKPof{BS) z=-8*A*mzh0MgbR5sMomGOIlbM+$JU#qyMzfdA8hVQJDJ-)cozeJ(vB}vI2xl?eWsL zg8Dv>#0DV+ko*>vm{a*3cS|i0K?5e-(vMzgqnE3{6h~!b<Rv|6z^M{_JyoK<i?yqx zeV7oFP13dD?*0NE|KqI#oNs(47_6_M`UwrYD0}lTXA@tF`fs>q7sS?KN3}2+ljH8) z%T}QXGgHC0nN@v5V_=1e4UeCoCO?a65xH*QIS8Sl)yDYx{(?Be8~nbkm2Wm*>R$Y- z7x48fEsv)x$H_Yp%Z2r-vK@k_r&iV8B0H7}`6eflfJtj_dt>lcQ1D|*W9V0*`EJ-2 z947VFMzHY=J+1OXLqp%K{2f4CPR`~0iFQCPS=aB@CZk66X+@#erx2?%$VL_w=POrQ zALTu|Zs3>h=Lds|vqp;tEz^GSb>u7crm&k%`1yRs8~dB?^_mWVL3zvVlF5nrK(YTE zS#TY5k&5n7{j{^Xw1h<1H2)xzpUdv!(SW9|E_aM&k0!M|?#Wa;sp4NRU-CbG9Eu$g z7iX%i{r#OvpE*>wSFW_U`@vJH+8Hd?49O%Nzn!sjK`Q9W>S`Fy4orD0*eEFxVPUzh zS{X@S!04Ys>vQ@9Xs5Rh7-M6eH_O$2sl5u8mN$RJj_)ScM5LvsODmNFVxpm?Up)LN zzq7vE5h_+}8w@is9GdqVCQmD!Qx3PD5=Y@XCh{aNL&o@`%HF`x5azZAOjNs2jT(7U zY>YX$$p%MXWRI(w7!74l=K3!89vvNJ3}zY)*Cq9NOR|~IAGjLyrwb`7j|7mE4Ef4g z^IIRL8GY>J9U)=0<aa(y^B0G@1|5eq&!tIngavCbLs3LsT{52|aCCGS9K(LmbO5v9 zw4Hg31^Qx^dPOz_V4>))qe~z)omzE1Y+eX_K_wY??6U4m9FLZxRzpPE-gyiQW`Y>c z<&jew9n`*27~Z<%O*+s$pju^J`{{Z8fZ2qOu3^lVZ?o&meM#a@`|@^#sknL!*vo?- zNo}li&4x3#R*%HN@Cc(oPj(kodpo>Pf2W^kYg9O%{-o(+ix(?Kp_Zz7E7D${?ypsV zlcX0Di{#8IM;kd&rI4liB;SjlkRb}deo#ST;gIuL&wNMS^u0+@k{7N8Hl1F*4%4ZT zuAVxI$1K`yi!!{9)=AL4kAxKbGj?_>JG+q3(6Kz1oi5EsK!2QrITZOCRfY~n8L_-p z=xc9x<|Pc201Ky5vSw~$qp4vymZoW{9)~zPe&d;?QQ}zZ;c2r{F*H0ZTNlT_fwQ0g zVzRmlbqva3k;CtD9q|jY=Z0@8uw(1%A1x1L2_nR@_5NMrOt2-cnlw>i?|yaNTN$@8 zXr*7z9ZpkKRcfh$Fr5vaSEfJET4@@&tDqkOnngGLDU^mh6fMoKHRdNf<u2hQtTddS zvgd>+_HwH4-hF`%8H%*2Mhu)(f{z51h$3^8X}P(%pHch3Ao~tuDAd6&wY<FC7W4uu zdeCe_)>e<asl(4VfWDdWcIZXDKX(NQ2}xMdUD{DdDknnh=oBjlvnJu|OU0YJdwcL# zxoar@fxz&{58O+G6mZLl*Ci4YI0yie6<Yj<dwU5Yz7)u={JiqNdan5|v-sTWU$DY# z;f_6(gHNerr7rvc&N{N-$x)4Ea~VkM{=L6Cj{N$yP7*w&Z%bUYKw?GttCr6~f%+)L zP`%3WtZ57lgm~56gPydsw0zwPmxXnx>z_zQId0FwE~sefl`4f)D|3{v7h6n~g4^Ks z=f<Cn>tkgq&%{Q#EO$9B@BIg+5L)eT=RUw8<=)wMaevnW#%SCS*SF^U&a*=hrH}e{ z&u(R)p>soMqxvfF8Vnr4tPW@w0PLW|(a^4Ydy2>z-+BYK#FC((=ATsR6KCj{3JMCu zT{%G@vab}AlJh#MS}H}EtXHA|E+tF3h{JOA5DYb8F$-nLNuXDLN`<9{K|TK|14A4s z5M0+a{0T&WhLU6l$giy#w1582F8P!w(L((JeaKG%{i}64w8zjdz(2LiSUZi8a&MeJ zN(xy=a9Xx`*e$rX+@IXdmZcJKpVbytuhs~9@HTMS&c0K+B^k*hW6wgx9wAU;f<+?M z=HUyF3c!6D85&B)anV12zBCdhUgvK-TCBBBUI1<np?Z2{dl+3~I$S<JJ}zNTrVP`; z>7#fo1aj1Q_4^VOvYxanvzQHhn%8SdPEUMqW@dL$TTeD#(UTStQR3y*SapIk)DEtp zvHs+js9UlFIJa(PDD|oXst#!v5wbJE|3X7bN<<|3@~%6y0NAl<dvvL|n3#HngOs+T zv%pLYnm7yvaG7dG{VF(rBPrV6(m}>!$TVl~$a<)?2vjz`1<V_#xe%^MY1v=n?<%zr zWGgBNf2z)+*YT7%{<siT#)>74<$4h3vYG*l?_P{5wf3bO47d~eE!+4R=gNn6U_FSS z*HD@q4p3<BaM&B!lZ>s1<*~U$<5=cfQlMhnzVQ_q^gi*B0f&@wSu>9-qq^{`SJq2C zzNE>;ue|rycrM22gs;gDP)SCK`A#N(C@48tVB!y31NYbQRP91FZ)Y68on<;>{<{*g zswGmJ)v<sH?5aB$2dlfW+;%1U!}~vfA;{=Q;iwRq(#4%@gtwYeFY*~Y9FMtq^fz<C z`}t>S*#Js(xv2SLVeBQh{kpKvZBM6{M(xP+^NPRm8MFaaYotGSB;Ts0GA5=dtPH6B zyUVSE8&K8=@`GWXxkeFUoZ9KDTCdZ<t+0tlPcK2McuQ(&4D~y?HEwki{9<6}fW*}& zJq|G6L3E`P$t$$vJiINB7v;b+@%>k?LXL9YyYsPvR4E?&L+YnbRkeHN`Um>E?|cT6 zWrb)+BgM|EPa@yGeKRjpt;NH|{hgMkpMn`$iE6BI?6(9M5@7_odPD75)g>-78LE#_ zyY-$xN-8RF$aFc1F}VJ2Y<IFVQ?E3)?O2VBE;df40fQEuVh*p>@z0(He})+DDu>o$ zc)W`M19Y(N0u6xQYrjEUs`)GY*M&ac@bJJpxSOt2lR!us(yDK@4K&4moh<qmc%UGK z46}1hRM_-HMoaeXH^@W7<6aiz)t>dQ*tJKqI4>Xgc_FLp)oM&lQd)X?deZhgu@U%X zQZ*lTcSa9I>vjr_2Iu=T6j$4mB63vMh7zip#iH2F3{6diuR?ta_+BVXmx%g)Huv@R zCi_Az4=T%FG;=mH7dtsZcq!i4M30$b2Oe44Wd;_5@mn25$7#RVoZfF#Vmk2vzKtYk zf&d2tsJ}tvPBK2Jud^O7UhEDti|xpLX0*XNJKhTp3r_e8f&2U0x3^xCB<Flp8gPCj zPC0nJ5jyhB`U3?GCqNIL`R##eX=iIMSuOE!B27~e^xG>_P5{z;etfVrf7Tb26(3T1 zc<neV^LumPGM;w>C?|xe<#I-yZEcC#lhEmgsRzIlEA8p=;LNCdp}`MsIMPc~4PZ)S z(p=UTsCaPjr&NlKEsonbX`dl(m=0w6Hj7<58yRLeDMS{&4k8=Z?KmIbY3b*z>6{a@ zT3cHc8~>1*nF;PnFK-dB;Yh*%KPxYGI(<=%7EXN43mu(u@b?O=I^#}PukWUw;jI>f z9SnHL&f7m*0p*>-Vl=Q@`%$DbF04n&D>)^l5&N|{$C1OSE4Q_IU*Gvs5sd2m_T|g# zIp?7H(_`L-<N5Zevhq?M=iS437=S9SdfAS;a#(x`6cC$$w8MDO1vT1B;TbFKAgR~d z8WN!YPC}4=*)V;1IX$&QE!)6M%UJtMT%^PAecq;#{kD>>N(V#>5?U!N#(H|<e<`Mv z&OS{PhlpcmOmd>-j;_RzqwSHUr4?|#tZi(rUi}E9bg*<PEC&?J-P!2LO7-+S%8niV zWQLBfKeZYf5pgnAD_9%qbU@BxI+ivI)4DB5*fW#80Ak~mR<z@=HDkICHFmm633dRR z;i4qxMCV4b6;W-~V*v3iF5au94x7fpI%-G93DUJ&A4{%WUtb@obm#@z%S6pZyrv-g zzkl<ZBZbDoVdI-V)G0nP3JR9#iYNQL=UAc8lY-G^nLrOz2q#Zk>C1LFnGp1jvR&PT zY4<gv*X_I}u~M?)vL{wKt%k{H0Gc~gYGCziIEvjUDkdi1pmhM7^7vOM?IT`Z9-bHv z2=?Q8&U@Uoi)A{+o+|-d$8OU`0hPr4PP6hG!&Q2dp0`e;mGJTL0WMx`d)D~*GbS-F zpo9dR1yTc(R|VUZ_vLcofVDh^y6SX`#=^?Pe1Gg{q=<BA5A0`~M^-hto934c_V>rT z>vIP)XsplfL8Y%@@2C!yG^Lw-0P!)OOG;+u8<IW!iPhO(z1Y~;P(AI+!Wj|@^6+E* zORAGQgbFS+Iqr9Ky{tm(6oauw4?GW*b_jxEVSi+|J6%jz-32`2V@k?3!%gItY-b*U zVw91NW~1{hkWa7gZv+PVq84UH3LRRzwOmyW2a%Nild23QY87lU!7|3k5Jqt9!2MIB z)5_M;)f%3q-;>z@mCdX9NG=y$kftyG`iK?KK8zF&;6K=yEV+nZ2+LUAY$NIg`*W<? zm;t5J{yM+CdCq24I%NPU^D?-Xjjxly;%R+P?fhaESls=N&`!!w^hP}^$9V2E{~7G& z*2_IET~nH)#ir>hO~EM$bvp|S)3>LaV&{e{gGM8>J2vhx6UF5O=h`*&KM%uX)PGhD zYUX}d{hq;v84jc-5-G$ov4{2EL9B*DK0MD;ETO%;w6RfRx@Kt00+z!5s;%Jq>&8ZM z+X-~=M8KK_ZL+qYFG%DCIHHRJii{1;eBe^Y&wwlhia1(lqkE1gfUU~(jpU8A_44}l z=SlMN3pwl;H+^waF)^_clM<^cVH~*S-rjCxi!5#9=>u4Vv9XK(^kK-cYDue~;{?t3 z^Z=VC&R)Grc+OVv>c>{XPE;E8C4U7ZdYBmRFqxEb*&h3mg8_QO4gCM3i5>qcl%4j< zEYBnzg}pZMbSRU-3ZbAq+`GU~Vle#X<;%FE6ksivYz*Pwz6S)(;UXhK#Rznd2nHwh zGMf`gXbqE!G{NB!h<M?uJdBJRUDHYG>Jxrqez1O<4HWuLCBy!xUTU6~o0}#hcwjnS z4r5xF<Qso)*=`J<%*<uLT;CCe4RzicLo+lo*pgSvCc7Sfgea@QF7$}ZCaZAcG}{(~ z=W;%DndLq(`ByKXxY&4{4DY_NsqRFgkX3EMXt9gl$^bp|hrz5L!|Bw~I0BaCz$3@G znCZX4Kdw>ZDrheTcI~Xpr=F=le>SRD+DCT0sSWk;@Q{cu+20sc6c-PP&9~?c|Lg1| z9fitEf(Zr0?6#jn@y>C<pmH(wOu7n$R7jV`g@l~Qi>qx`LPDy+`7(b@%4HMa=a+I# zwIJo}@McJ{>1b_rp-WQ-|Hbj>L`Sw%jymwP^~Z|^jg4cPXP}F}#%=9zF;N4KYDhIk za+x&7Rh<k+fI+`Aw&X`oPriHxfk+@JlKmp*tBTvva#)6w*1XZ@d#sH+Ek&>^6d4ZB z3~hzf3x7^OoWOV`B7zW5E^;(cRwm}2n@MhkeskRpFdri-{vUI16;{<7h5M?A3W|u7 zfPjE>cb9a>BBVt`x=UKR1f+Y>-Q6H1-JOf>?&f^!@80`dos0dPeV*rdi7V!u>x=P? zG2Y)xayzz=4g2HY)n%?#_YN2L*Ns_gi;&n<43z&uN<u>44U^k`Kc2^q3!-0jUMciR zD2{OH)<^1Kq0yj8o713%;kq4+Xzy%s8<D}}si`Sm=L;mcRN?(C$F+sVo88UMP@-Pd zf;yWE=$F&6t#UZ`@57S^2BqYx!g$8pnnahC^E)7o%FE4rp`G^D8elyW3kpDA7VuX2 z;-q9t<JXoN(7Gc5zzAD`fykoIoRo9FLC)>$?bYj@NV)Thv)RpWGjxUgFtCo<ET-L- zZjAtDDPDG|UN5@{@SPGlme`j%U`?(duYf9url75DzBPi`=KGos2ysBf5<xDTqH0tp zRH!Z!Uun2dAQ6N`@X%14lf!PY0Aw{FJk>Y-COjQONtXi=SCm&u*+V9LIswE&l>Kux z>)mVCMiq`H-z(p5JKbCkT~n7;KPmtIzz8C9U@jOiR#DL%K{jSp(62OAwnlAdYg=VH z^CyJO(%yL7S0^Nsy-e>W`Zy*t|2^=JU^O)b6>$9v5H^Av#Yeer?^Tah=dRGw!pC0< z0A(&fe3lQ0;bqbh?wp44|CyQ+2WEq-nZO`#0+1fx<IH51l=y>o`s-NZnOSP;la0ad zZpQ;c0fV5B5c}MnZ1hF2(t$oZto3y!Ce4{@&?q=0ssjdjQk0p2LGNKg@id6~d%C;T zG}J&FF@rKXHZ~y^mT0it(#}T^)><7Qu}!EDGsigHPJ`7D$M*A6NDo(=2v!Exmr=6d zEh-eizt_@oadCA%-4t!J^#)Kbu)t3hnqcFCVwxI)fdRa!7Y1;BN7_wp?D`YQljaLr zRZgSf%6OFR%(wC8+aTp43vK){d~zL~q_jc()xhm=3cxf`ng+EsYwev|D{4VGs?5gv zS!jG>Y-Hbn<=sRhupL+aRzF|wfX}v?jFD#XML;56kvlWF(nO_<GgkkLp+I-|Gg&B) znW3qyhp#W?=}VpK4a~#S(=)@LPt=5kg#mJNYAe#4tHNT#@htu@E1CC%+wE3Z-FU_~ zIDyiIxno{6p3TAzoRvT-8<l`5(Hh#dptz_}_9N^=LLLP*P!g<dti_a9D~V+{&I7s4 zVkThlK^n^G_Wuf8g(t;^K~wY6Tu#;tL0|a-$Sm{TXVML%c{_mW3S|WOi-XxlZuYYv zm>ZC2xw^Q(Pt^4x5sO+wnZL$OCKOij8Lj(bOII%TxQB{_4D!axibtF+)`z$I;%q>8 zx-;u8|F`)D0(yK=Y1ONe`1H<Cx61uq;R});g6_(AVD}<H`<qlMhF-lPvP$ZT6_nma zde~@blPG1c=*)wsSmocmXEx_S(X4d}o_W_9lKhU#bd}HsyJRO->dnrCMTX47eWy#y zEIBs4w%g$$QDxSqUf{353`$T@$>Qa-I*t_UWn&4W^svtbN!HU5z@r6tHG+5VgjM+s zBV`K_o}(sn_VP2s8ZQo}a%Z<j4M5>!B1hr`7#}E_CD?Owk@;$MFOhVr6seOm%+z1( zLyj~UW^$!2G^))<1;BCAXalT4=aa3?JKXgOJ0VFPA>)?;5D;|=iE$J0c_e+FII6Cw zs<*#;ws)T18S2BXK7m8$$wv<&$PG98%^uW7?CTe?*2B<Ik<`dBCG`jN;=xQOuouDp z1~=L5ymnUSyEw_$X{H0Yh(im&WBmepg(G_bMR`YakP(2fE)b;#wdy7cA+vz!vbAj} z2Qc32j`z!Fdd1nhw?K$49mmikAQ$5c{BiB~N0j5U?P=>l2WY*msSr9L-}#l<>F+>O z^$S?#>}>Uc{L=5h6qa3h-H8iR>;UG@V9mkbBL69g&nz%{f?xF!#THNwaj~+Vt>sTr z$Ixd|qQS|2WUb>m;Ix_jAg5Fif<KFw@J_)SWIa9vXJuu{B=Xo@jgTtQXWNc9>0wLO zt+?Y+H@w)31?bo>k;Lk5Zf;)B29yZsOe_H1(#Qfa)3zt_`D+3$_j6l8!KTCb+^>=` zxH)4oneKrH;IZ@n_(EU#To?=c1rkywOvwWaYN)GA$Fse@P6b-N5S6M_E3!ADg7GF5 zII=$5pLPl6<wDZ-7Rm?PZX7@p7G=gjJYypy`?a(c_7!m0sI9LLFlAw3v2FKH%~zpI zXG0R1qSdIDNn~(4PvlQbOk5wlN%|hkXftq%Q~r7vCX~<wDD;JUK!bI3bOiRAY`I{* ztaX`$zn$bmrYv&vTp<-*ARRVQG|QlOt>o)|wbq`8*^A3&i@mT3B20>K#R2W=@0h`g zUf<TXD=P+p!;Gyr<yKv7-B_`X+>bC2Adcm0I2^%l2NeF*)>wZG30y~-?U@v-HG1w{ zKP<L*0X5$!r$C$8Y!v~gwdsZ|zDAX?)&87Msov#$at?|RGc%^mzq5Q#PnY~0tU`Zh zVV)b5-i6T;;}vb+l7S?s>Fw1i#m*%*CZ;0#+EJTxruGhnqi;~k_YrW;t6`eEKHI*& zYSgSV?eK7QE|5~XR#Q?-e%NS*kcZ~x<qT!NfBW`RKP?w@fv;)oey+lCHh;2sEA4ru zshGPf5+Pt9I>Lu5D8+$uET}Yo_U%10oapM^z(Kir{*2w$?(0UbzK#&XLwjkPQdAVI z3H7wWo|>4LizrOT&;b+*meAd{=-B9pno|VCG=i=qBTHZ7^Br$^))J3WilXB36gXEG zooyfOxSyZfN07@5-CtY-Z7PMm{1p#f2&|lkm&B`Z1sRlC%SjK*8h%_UYHLFkxltfr z2{=+<Amg&u_pk+-@|J*16l>9r;Anlbpo|z^m?+fnbG6&9z<Ieo7!`)LCpS`Iq-Xrm z6jtT9PiQ0ip1(CLa?XA6OLqq%NWVYjjRZBV3jklfOVy)@^@~Th6<h&9jI>pA3a|pN zBNNbH!DTgVXmF)yB>hM>A_A&((4kj(d3j*j$jX0g`?2#Eff`dKI;D}(`FBm^bPPwz zNC2^3sDJp<wdk??s?8TA%U^=C((xp#`d}fG^5Uxab(5NAT$9y`N)T4RYcij*l2S^# zFt-5zSW}wFR7ZbbpRl5{M8yM$VGa0QZETol<hw%y7T|)M-1hq;y%(%G6qPZWg8)cP znKg>|xbCM7NaRpej5?>XCes#m`uX^PYKEd-Xl|_A-L<@N_WwwD;HH$9y4F{jjw%3M z-NJxu$wMZAJ3(=Y`$N;(sr*~cHW7{q`@=&+`}5NPez)XCvz;t$US}GO(z3C$p$>|= zAx4Y+1E;!MUv_;5ki0)-940NmWt*^Ng7jW3G(J~qm6MX|yz2+&2tY~a|E%fa86KYY zMM+GGnKlUq0gPKA!TS^DZ<{){f{Hx0yQh^27r^GZkfx6UUvWH+jB7l<(dJ+YIPQWz z_5Fv?8%(jay@+gCLT)GVnl>cJ`_#X8Y^C~AsCl8$m8KwBu;oX&{|g{WVcgY4Tie_I zb334$*2wV7pUB|#NqJT5Uy54^k{$Z}w~H-pYBu+u!Is)Z!q)@S=vj^&%vqF7rDczC zHz-Ml1@#s50gtK3>Zj!jPBsoUjwkE*5H<u?SAtM5x6DjU0levteO5B-jzgF$$bv&c zp^ZlTgV6e+T*%FGH4XtLzKorTy)OZ8-4><}=X8zk{1S;+wHb_Y<DzzKHI~h;?649M zD+$4~Xu~!M9EzigOowI_R3C2NyhYb@8<7zgHyzD7+h*MXb#r@r*<$GY)@Qq|ISBxz zB{u!`4Wm)8<@FFUsJM5%240jGk4rbheJm6DyM}(h_Uz(W`5Q7ZKF;fSJQf(0pBpz> zE_Q*|<`>v!1F*cX&9{D~3ZMwNYre6*T4lN<sQQYc)k(W{CR55FtMzH9ZrGyb@yT%z z>L<@b=5MPHFu$gP6*+K<?p1g1W=_QAY-KJ<8bjO+1m~<y$s#}F^OKE-tDD3)Ti#Sa z3Evftd4>X_GC-Zx3QU$9t5Ik}Czk_BM8n0~arX|e<>~wcj!z1REL#urqY_^g%d(#F zw}JysJL$(6rrVeMfIwqvv32R)p3lB7i^E^0jsG0ib@vRk=fX~6zq$hR_zOZu{uAd) z%Y|Qo7D>j=knDbt72<I}kL)T8bl6`=;I?RK<==4r!9s604HSg9xHyVkU&JV_0Q6K; zq*H!9C6KaXM>H6>j9x*vM(o0zILPMXJ*6d>!GMU1ESjFK_bXV6vPMyMzQ*VzQwj>& zE-|;_k2@MskdUI*CClf_f&%NU4!A9cKo+g&nS2PK_{Mx0SY5>sgi=RUR$`jnwRT7; zWdp@~TGY@PaG}8no8IgK#~o0~>>NGWE=tnCaXV85a?V1anoV|~WQhzeRGP_dkm5h3 z9Ia1DqQRLfFE7gp`>U<{;w36O!;mTjlBwIX%*HnHs<~)za0pm#+3vM=b^TTu$qD0b z6lVQlj0qQ4YAZvOqgKU7^q<-%QRe3MJ#b&gC|g8dUUUi*27ig{ne`=I<}37D_;5o2 z*azIevg|R!wSq`u+tr5oN;5V+9-HkU017j95IK);S4vy;X1Lbd8w^03?f0&0%gIGl zq)<YC^|{yG$EaUnrG(NeZrY}`_q~p^yX|$l(N9`xZAlvF2C7=S{V~DA4I#?8lnNDj zZSDK`acXeTm4ot}wD%^sx>4L|SNxE0`PABubUQ(&bsNWI_Dl;4coGeQJVWHqA}0RN zykgIB)NlZMF?M+XKt30&t(F~54CjW{Cg%NilZ-(&@hkPdW5<~t@N3HASWa%f9mG#I zN7;roUC8UmiB(=suVSKMV9cdLCe<sA_h)KlI4U6_+16X(q`jzwGxXtJxgYAx@BY?s zxEWndpKPF$$%X_50#CgrJyl(zP!x6&u~$0vZY0hTYqclXZ<o=zFdYoBzU!M|5+?sy z5ZxMXz@Zi444`xqCoRl#t=~Qhi~nD_0OFI;M6YM4&S%^GwdL8~5NA$jDP@BhjdOx_ ze(XMO5JlaT8?Zm*#_UWMK|zzkS_ja^7O2(pQBwz5Gy5=5Ioj{dsC~0S8_kxTF0)H0 z2K^}rl7IF72Fp>R%^~TxgUFtWigJ7F$ig_oOCZy*3g!Ht@--6lE;0kL>WJN=teVH7 zB8KN|2xy$OwSY*RdE#Nc)D1D1sWK}}O&td3q#3QO%T$*9$s&`<s$iERWn3=k&G~^r zeG?F1PgOe0jV|Y-(`r<Si%U1SKM+9@Ik4%}8!R3Kvoxz%O+N|om$r>H9628mfBfjZ z1mnGG9X*i*EDMo!LLS?8fb^bzDF|w30KOMNGtho+Z@=64SlTL-%!Jx4DDt~TjbXr- zX`odeHP=wn0N#*+1yyd1bwECD`X1EmDIj!QG$1wlD`dU;oB4dx$^qdYS^Bffm~v>@ zfMwQYS_=SU$1Ue$0r*B7n=4j5r{wAhHVv4F2HllLMn+|*4#`aV%Ojb+(*bmJ1BCp( z4UTscsVXwKne4Lep-LqV*4Hi@kCNPMHtxEM-h)vGoD8HzeYssnVgcDv2k>4YpMT6o z_j6aQIh>ipW>(rdhvIA=vP_41(o3DJ9LELZs`culPp}Gy#wVy~sJ5po+W_`(>WpKo zB5J9prrxCk(>~Ak*>m^LO<ytZUXbxQ+Va!V1{X@Ro1PBJBxB5gs{J`g&8z3>zeF`N zE6jzELH4cejW!qMgNSRYq9?W>ozn|{nGK{9xXgUZgX%%OGcd5H#miZWFZcKQdyW$K zo7YK{3xyi>P8S1vB%;C7r8d|iZ2*8Cv#SFH)JEr&lM}4Q$Ye!YjUxjCRRxWi?4O*a z%)-O(#t?H_N*pc*0DohDx<2`Bd1U0rC=oN0!=QpSnuSumn~c>AwDiA<Yuq0`q?jjh z?P^7(mD?FMZysby#oYFXDCRnY<Eh!KU8JgfO3wul7*CrMjIE}8x@ix9&=k_-hLt;= z9f#+qaq8*m;jx+%preoG+4Vws>qgr_GeDNtM3K-2@EDot?#G)fWd_L)Q_v=B>hLmj zU1n>jw0cU>$bBa|7#wR0A)Sm&#AO=Qbf7apuSbM4Dqa+y%YJXFbRGmd27`&i?u&1F zVlddN&F0$|R;f(y>c(GU(G+OFeE6^f6HYenTC_<wXRFzjVTA<+hU77{YQoQNSGSmz z%#+zK;F$A~)GSxf{{TX+?Xgm!?)j9cJ}7ItMkpUH?l!zRZf{Y3fNvB@;vio&`LS^x z6^KkdMfKD=n`uBM4_tZHt}M2M;g9h^eMnZnt)0c!@82a=i9m1KaJAflwTe`KUT{Jc zNC1Z5zT2J7%ugrTd^tHZPs_rhbXXzDH2@kgHYcmuXU_q9?tvrV^q0kLCEo+SQr$ln zn(s|MfSwf}j~n=KZ$1X(r=TH;v)0`;h<qG6%FK*%Kc7Ux&TjFSFi3?q4wQwM$NhUo z2!%cYoxHNLlCZWUFma!05KqQJ0|~#ep|LkKQYZ+n2zTN6*9$qf(ntY(@_7N#F5WI` z6vIu9Cn^$Zxns`<V=9S|r<FcbS5&-l44|q<Lkj~whEi<SIj-ZC&c&1T$v$q^O22hJ zl$rjpGH_UW{yT;qbXR;}_?@<d-HfmDv#8?pXZ4b}sGe0&4A+?bT%Mkp7J3g9*^%=; z{5`Q#pJyDa98k1iDG0L6FD?{P@lD3-?t<}Dd(@fx1<0lQ<IklL4=s+QrA8+wv7w&_ zj_9S}xj*Af`I=&dwk%J%(dUmYEs+1~w0|H2)<-b7fC0u<qlznX4x}#pPRse(`SXBC z`^=5gb8+A{jUo*6*j=>xNCDnW`FA%jdSk>#Ka<hnoTL1{;txE;dEf{Q6e^5|)JzOR z0LFrMBJ~m(*?c6!Dz~u>q^5uR1Uj$Xef*dFF8vt@-nb0cDF0_R{XbLJ|7U?m#e9J9 z%)&HQUBzM`2ING;lcS|TK__;=ds<e;ASEr?Gf1BUK+jhLt*s=DF3CaCwsu7^;qmIc z-12!p|Dbl~<^qvxZ#)qoy&aEh@YdU>ES<y@aZVPeXXp33NJtvbfPRrW2XlJLZr!}$ zEt{Cx3e&6<;C06ibZCxu=Xd5wGfe#Xo!W9+=*3#Sa0dA0L>_DBZKsd7FQ7&XFgUGV zPUBS{JTN;ggGyxItb+&0PB4u7vt2BYYqS`i9sDc-Hga;wjWh<ny9J3sQ1+>%KZ~I_ zadFa!tLy7m&!2*DdgRcjcaq&~wpS_WC6t}1yzJejJwQIwYt<?oUHS0uFNUVBWZ$>A z5Q6qHpwlt@z{5mE#|H<NU%mznC!vi=D2Nby4q~SG&Xq=|6DU4tv;Q3xrl1PJ?0cX5 zTihz*${d8RPIf!u{A7Q9zmtjXGHAV_FnA6uNpklDSr3jUrH?3pW8t^2(xyCx^52O2 z&)2mC3_m}`M_%9QkL8IjQg|UslCEbsS`opL7!5t*`@q3|aB{z6Xflw@EFvkn4f!l= z>hj50oy#mHTqQRj<<<2&d~|XqMsQv&Qt+3i+4(6f(m8U285f(BBt#n=E+z{4l#$&* zs7tJI^$u6G9+(xiE4^~HBoyL1`r$*WgM9x+{oV-(A~zXE?t}V7Gxt+aiB9Qy)T+kh zYBQ{5GwAoBkM6qtO@pvbQD0>Z0=;rn67j8-pP2A4W2%E#n<rxLG`bT#PMnUp?XW25 zRv^#LC|W3S9c)=)$pkzw+5~nwgD^$@q_Wpw)c$0ElT9mk%>d0<?BQ>IZl1i8;X?b} z^`0}vb4sD-PZ3|%4GlHVJr7Cj>F+;7y%o@{^ME7))Lhl6;Ye419OVFYg2S!`hXdEi zeB|8Y_|3JO+ts+BDmE1$p8{!gK+MG4vi~F#R+(V`IX2Gi#g#BU4j%3=e9qWsIge_M zcC>kU@dL?#j1EwvA<7Eh1D%nRnr+7yCVZ{80gl!{<}Nt?O)K@B!=|vY`V7b~0Ghev z{2*od{d-o^pM}9|2kvw>CDnItt^;5r6jZoOB^N;0Tgfs8LwqU&2)(aOzkWSlReSk* zf97yA;9%C_F^Gx`2Ap5-!yrF`Y?C~UL7BNMa+~5}vZN}J!~Pwp1e`XzozO{M0jvhb zu`lYjiJ89k#N*Vi8q@yoyjo_CoVB-}Pq?CYd*Erfi~9&CJ7Wcxv5ArQd^N>g&b4kk z+VTvAe2KklBUL={Y`a5Mh%)Y1*Yi+>PUET1BbW$gX8oLi^Sc%X*`TApvSEX0%4T8S zvpKy$Nv^d74nVU-m7V{ijUWF6m1hdT`+!4e?6NF(L+huWN{}>^dWeTi5M}o7%{a6V zx9|Z?+Na9`%I4w6ss0k#nm>d;;?n_Od$t@dq_@ep%afE}ANYj;T{2c*+}H2MeHc0f zsZ!GJ_l$*OD`XAMOq%=HgXcn>0~y%{85vm;Qc^PSxPM`#mK%bUIB0+seRj>A+z5Pt zS*^wSmqP2SyppPmb?jfe*GP~|lA*9l&ZGC-RWPq-{pB0f9x~>xFi{(T4k3e7rX=}0 zSFY`CV`}Wd%z#;Y!VH^G+3;YE3-j5MU$R8;KlYcEXM*{7xni!jBAuq--F0u_6C1dN zdO+zAi@yiYFI+vZGMoMt*zQ)mfbsky6cEpMP34lCHA{a$%fgBE{aNv<xhEZLjpPrO z^a$Am=IU;S<}>+Dc%$Y#Kr03^7H}QZ)4;~7-s7}d{{(|-31dl%OPkN;UDYUfQ8xC+ zSFiRV4nnoKO<{IJ{grMT=Y>YT3DtxJ^EE5Q%cnwujy>KAwgR!sno^GqL1(w8auVNx z#M%h(jEur$6!}O-`oO41%*qMqkj6LrUMB`}3i7|R*E<1H6Oop9q}V}KL<G^8CYX@9 zVpTGyo6*HG`R_hmWb*euE#Y*fVSdN;x8nlXw|r6O-ipV-E_1T*lA52tc?`k&c$ZWQ z-|Re?$NlKKbP|G_!r-*MyM~gFrQj8O{@W9u^&_xW5w4Ooc(TWq^h(J-2~a53v><wI zwA>ev9tXf@-}8fE)9^ZMse?2zyZO9Olye=Qkg6$h`qvy&>8;-(8=%Q;>*Al3LC7K^ zo)NGthKDD<-e|y_54~qN*Df0Q+^(PaNI9sIXI)}>E`}0~&G0xJN!r@(_H>*WE`u&V zcGKxbt20<x8B^=a=xfSJyMnW>9ZI~pMi(d`&x@fXl*xW<*>}`#*1DgTO$O}D>z{n{ zhCjCQg8f31aM*HCwR+R4uw0v1N;Nj@(X$6Lo9V+s6VwBC*!D6^=vg!epkM+09G@_f zt$7a}(uGy+{AqP$-sHk`<w_^-OS6=lw4YKnnHgUcx84j*YSe1K$t6s})OY2|B(Mi% zpp>UzeN$25awU8tyhVE{<X;(us7yD#z|_)0WY1bK?MOr0N5L}sGcG^@WLrePX943v zrC%A>#I&1xHw~%z%<zHqn5q$S7WM>Piz0<E52yLZRn@8|24Sv}Gy-T%h#UbvoN|L* zFHnMpM#jEiXLwR%F8zAt)@hq(kWWS3>`J)lxThj4%;MwL;spE?q%eDO(ZwV{?HLo2 zZ7*{zGd+`-><~P4BS=dt9T6TLhnyabnQ4!^Xq`#<jU0>qX1kwTkHmFGZsq~7%c*>t z+%|N;VicOIYjyke68ke>Os0{U(z}Jm2MSE9TnT3T_7q^+KGcCMxyO={pDyAot2_m^ zkP3=S`*`t$lYd!T{8@EYvs`5X*6%ZflEEO^DD_lLO)V0a5?ApkHiUBzlNLZLg>1@p zCWnWwm+>QP=jgO*LGO<1^)D_5!~VZwGZE1Q$v1BD2@$W$4rS1!t@zUv`SrOl79N@( z$3L6XO6uhdds=_dQJ!R<B2w<VYe`c5%r<`b5$$ZYfdSPm1oJj+!>-O!!7V$<`urm^ zb-i<pz0O=j!S4IIoL0BU3Mx!YQm)sn+!7WK0T;}^uoRgz)}c=IiEPNWE<p8DAi)V3 z76vw#mvNz~y1vh@ZMB-9>1{3P*%6SOv?S4o!15FMZ{MC%>@(hmQ2)vcEDMh6Xd~wX zOBu#k(*;CQa{rP32c*}2MQ=++DI?__D_1>%dy3~1&T%hrkX~82S_+Van)*E+$#tc! z!n;n@%PyX85VP>ho2kGUFPX-n7?!s-21$tp1p2CaaS==Xn%zhG&~{#s$N0w!aBVqC zy<5V>V#3T)n$y&^`pD7n#BI<y@Zgl>#{sa^U>zUNJyYI(EFsk^|NEiAj?2lk&FdK! zeXJ{Bzb84r#y<RU>ed-bkXBIevCIzn!c*5y`F=PkNbb!7DL$<X@}{&Ewa=5}ygW%6 z?u6x%doC_AKtaT>uO6FtyBiDS9;qG#+y$AbEiT<a99;x!atG!ab)R+BT{aL{`Iphd zBYo_Jq@=vc3Jw+ZU3&mJ=62Q-!E5VMKEZoNWGzwLbN*&|TK0KhNt>~8UTy8I#*;L? zWvt@Q$uY@telcbbF9vcHqsqzi@_KgTbimx4wX({q52j;f$pLs}4X)`v>0dquhMN;# zhDR#L*nS*#CCrpcPbbUf`Xzw~j^Z%@N)9)70*OT^^m1nQXlF;MXmnyEW!oABFaH=j z!~HV%Lw0fg%Kd|<xm_Cd4bbTJpzl&VWHpYMr>0M}uN+NP;9|$5q!taV%Tl#LIHM`| zdF37lF;RD9{oe`1tV<*(U9@D2yNv7846C+s8|(W^6V7pmW=HBwPgjel7?>Ew)8inL ziNepk%O0UrwwL1lU~Eifg%nWr>R~h^ux2q!gI8;h=+1dq?)&$N<tV(Oxth^>XYw!< zBp9&-0ONPrPWcqSliwX3lh1z4W%xW4nx>ljPHyR-IMaket;)RRfL6vY$o_MQo^2UY zTJzJ5UW-JmgPBs4JNey(+Ka=jlbEevpv@#Zo{<|tMovN^GeYG@ZW*6`)@4H`YRnVf z1WhoRyd8>f%ahU=I&`YAe>ge$njf7A3~D!gGV4HWmeaFnJaoKXJ~8&;GY=WE<aGXI zRu#C5wD&Bj!Z!7n8{X#5*}<sRY7r_#Psq+r+4!p?|5*Z~5e?)VKA#N0VMbCwHO`on zoLXw_5AgP#sJOXBWk#8EJ@iI)UZbD-lPfFy?KI)yv8<g5^LWUUucF_{W(7UJPXAMe z&~f6eje%HZ^c7GRTo5{s@<GCx*;$*cZcc<4EMU$RCNMORsT;MZ+x>&FF${PVNGhN7 zrGSnk@4B9AGQE-!rfx-kToX8Wu&j9js3E(`p1_G(O4TewNCB*MFA-0d%21zi+U>uc z^+kGh&0)0eQnm3+ghkSWNz=R=W!MzB_UZ)|b3S!{WoMr!gbljF^j)Aw%!caf*K7IJ zQ{;1yyV<FsKb@0<0~7Hhc?|`cLw<u=g*n$ZV+W)fv4cH5+Ew3ez8rRj&(;AjOyhGo zVKPNMqrQx3iv>i6jz%a=pNxLZZOAT&p51ouez{KccTlr$%8Zv(VQ7~W$i=Z(TL|39 z9rWhbw8<gLWgHLM&v*ctM_F=LWr9Nj%W8El^6^XCipr@?>1@dI10GK+A$yX=R^(7n zGMUmDZ>lerSx0IXExw}(^~sa_#;!EnTGpCH$D{#+DlwVdWLY&oUJ??UjV6*}SQGsB zx<>`>ilV9HL`2<lrzgsG*M7-qP_tlqr8xi*0=Q|+)rZantw(HD_pXnc$?O~)5CSo% zF&y6QGwDiC#Xdq{TR%@`)Y}|F`lZ`8KcA$SL2Ku5!M1lJ6SCH?m|9Wr=KSvV=Dbl; z7OGjaa&x=i-66m!p2A3EF6+FPiOB!3ytE&<Or001C;F<W?p+-zK+{<C--C`nR7Ab8 zUdEF`b~5+lwF@HMrH+n{u7dI`xfW^i=QpWd*SbxOg)$=gYg1uD_n)iP%uGmpU&o%^ zKRi1>&^OVe<>BGDpIUjIJb<)2rE<%lzb8+4x9%r$;C36;1SPN@=eB74{*|UUT*X-c zn4h4d;RO3AZ12Ic>wmb*Wz-pT2H$SiBi7Z`<)BM_R3GH!t();Ro2pm|wM$S`98Jby z|8zS=XV31?ay)<Yy0iT+%I>5Fr+rSa`%8R${8EIWnPxZ;YD(gd#7ME~#RdP}--#LI zgI1vA(YR#It)u^D!VH0|=|4pSjz6%t^PTOppqPgc2P$&*i!)U+UAG55-nS8u5*fiT z8kqBq3=mUSqNv=^c~xg~ha}V|FtgE(T?yyinTi<^Hu@V`xc}NmyANqc#r%cG`^q&B zmH(kCBLgF$BU#ylI3>Svo`d}8lS>2d(647zPnoS!^=|eNW)vx%&}v?Ix%NYk>b9A* zo*)c${<x20TyBeBNHRv{e!|P88rw#60F>w%Q89z`{<-8Bu{I|!wcZ~*^e3TqRNG*a zIL@&zKRCY$SYAfg(tMv!`!1c~s@cL#{ptj@o6;zUkIGNwWgvpjHzQNi45xG_K?RWk zYKk}L#w0<3A$HcbLtyLbZO!S*%F>UFipp)GNL@$pT&^n(QyAyI7U^v7rlN|3Mdc%t z9^$bd^u?c3MVD5UDd9b)Pc|~s*W6GLnx5v2Q=9hBU=4m*XSs#D5IMj)2Yn&PM$0?e z*{j7`nD!|#J{s80X^yg)IK|}W-3h;)zc2;dd_gItW_DGwe1VH+7Wq)<^>=01zIVnq zTlIFY>EF@2Q?4J__#SUPECf-}CfyH^`!5<huomWJIb_eY$qJu(2S`b?va%K2^plID zJopSfiYb0JAMD>MaxWG;^VqR#w)d_nXnJ-!r@sZ3ed#F3>YuI5pFYjOGpDuF#PB5g zn9V)UnCru`{6XH_yr#E$Ds)dxtDyNH(6|pM{vPhVtt!JI5R=-OpHMH3SZ&O_-AeZK zEQi{>8MzED=w1)1O+HJ?bvpU&$)3s{1zQHGtn6zL1-DkdY?$wwbNIBMW}<plqpUny z582ZtCni?x2z0(<Rqt?pNL{HhUnq8PSaH8{V?rT%;Op9)`YzLe=wwOJvc7>m#(2p$ zO^{rE*F;<Ewi11rRPgm1A>(Oo-aOL3PeEX;nbaXcjUpl@CLS?-wU5%C$^<%+goSZ` zwj=>QqQ5u-Lk&6__-FL!nFDwcF)_-YMOpYOG9JI13xL0b<&hUR{1su(zF2~b10VG0 z)js?c|DSzGfB;HLW+rJw_fz=S<zW(|dqxO=>st7r7?4p>p!os(HBFs}NrDvIQ7icK zCVMpFf44D@N*odGDR9=oxPL|tbuRe#M^y<U9EdYQ>9V#v$5qB#U=;t~9Sys7ePc4q z^`34ddN+qBtbrFpL&aQfgZST<3VydIAdXO?!ps5BVFy)9G(Z^8=>U?dgEaFA{BbCI z#40H&26lNbwg);3G1Rd8yHva~MB0j*{`cQu(P6YvFOJ*W#}*jCWm*?+7Nw`>(*{dP z>(9d<y*Sb^1s|odoLFE<yR~!MQ4tf0Px+f>YHI2uZf<fpIn~M5IbrynUR(6`4N%k4 zidaE3H1O8!8JQG>41viX^4J&91kU7Rt>(kwCaNl?Atr{`e8u?+{uX+HH&nFL^wiXy z7SibjxwKK@n6Wd2$SQM$ua9h%=BBk&=*Z=ceMCCCj=nNN!PRVb`@YMd4c%1t7gYC5 zIdMo$%DvOowRAUZ57W2|w!zq-KCTna57*g~0>AqM{<1^5@k7$&m2xgBw%1Kt#u>Z* zVECFn{HqV-|JsV4yCZ-<cQQx82M__*|KXu^e;C!fO7$(OED%{5lw6VFV^NL^;D^m9 z#Xr8a`b0G()UkNaK$H$h2P#S`%iiOo0AD-|G&U_;)NjCV$Gat8L-X(X9E6WB1!QQ- zsbU*xr}zm|(>Kef_&pXmZ(aWC%Buw+KOXR>(@aZEj*2J)DvuZ}h)(Z*yeE8Z%Xor} zj5ZxN1D_<1QoH8*K9UzdVw6bn^T53DOL?Em+dR}Utn%Mjbq|!2WMyPp{e9u9*U^{? z%F=;BQf38x|At!Y%t%8{21b}fim$Gv#ha^a1u3bsQ(GW@|M&k-7$xMyo`(fg&zO98 zcJV9>c3%2vu?GII)6_r5CVXJBDshHSbV8?K{k64*SrTxE!>&Y3QBfy1X1Ly|<${*` zTib`)m+<FwK@=)2y@%4asO`SV)I&vO`)`)-KMzA{3BbJY{jyoW?`RpLyt%#k0{(g> zYNfee{r@q~IIcMU!pH7rQ-&fXm{I>G-T$$*<3jZ8c$E^gjlInd{`Ct;-)D0ni+IIy zVdBO&*W*1sJvJNk6^09QV`IXJHYe+}Ha0c}2INaehD7iQc{dAYu?9d-WXU<Bqeo$4 z0!c{{ySqnK)wu~oJ69hwPMXd9mRW<{Vt0s0An~LlMh9pU?PkW<z1;<Q)y2Who<Wo} z)jum~Dypl5xF6_a=1d@+0p<&7lw?JwBCi&{kdP|^ua*at=GA_1|Hw$1O}2nlom9+# zg2FH$yFmUf1HBRuTIse<BfUSu1`;lReTI$mB<{-y^Zm))i9POGM@P_bW-yop?@R}% zsg#@^pjBK!U6`HC-<Gwpwg$~lF0QWL&#HgJCr;qpZEHay&+RNN&&L-CYimrmDTKcx zRDZs)(ESeBP835Co-KE1)HE~|Ri#+j7IQD$?)r^D-~}Zh09)<b+|?M&-Xa}T^?El1 z=zN1?LTSKJHlcfs<?!Iq5fUPz4}fQu!=TeeNgV)N4~svt2fhKpm3F!cOLK(H7NawS z`MYzqH-nY%-if2(&g5qmCJtv#LzUFn0EmC61hkKSAzGkvz5c~Q=K||38k$1e8a9@` z{zmFwI*O4haWkC4W~4J8IzcBgV}~nXVhJ#MPmK7UUHpxXi}R7>Bm-I(0Q`U`LYl9x zrH*n*d!rq8X4YmobzTOJ+<0e`-&Yx*86>-~SS~(tkb}wbU&+6xD%YKlw^~V7cpXJa zM=3Z*$mlXv5NENZD{i=1J}5KOWLFNnuL-g;vn>`H>?Q~Hn)ntxlIlS7pu=rVX{`Hd z7o!E?fic9Hmi8l<LC<>VDI|OQMCHXki{Ybm&vgy`0o?>ZQmHET{AFZxR8(XnCKfg} z29~PQi?;z8L`V4ZUSq##G+I2T?~uTjGzHk3@=VyPZK~FuUKRsCOqkdq?f)|u5TBXp zb2(N<8Wa_@wYhn^HM#@Z$}Z*?L-4r)$FW^uYp6m3ot!)y@T~(&@Au~qbwUY`PEY@^ zNP>Lz?pv=L;889b^6ot4zf1KMDCA`&(U8}?7B#PCU@a|Uf%L9*9bPgrvx=4tcJ&SP z^iPh2v#ipgZGOziFql@4!^6XQk<ksG7GJ(}k_KT1jslyCa+vEw;|0HZg(U$276wLv zRy7|51qU13`9RW}$PsS)O-mSxueWzrc6R#5Vy^OlgGRsg_4TjDerP1V^jcLwABTf~ z1Id;hyj!Y&ZU&!v;~El1YBR9hMnGNa7+w(2DUM!4+bk@k0n((Ew-I5}xIg^ZBd_di zE6!}~o{oHO=!B(zGcdS0?xhDXb`nNLG*te}!wCM#BGlcfrCxgeW>@OXh*17N`V}|k z85I=;GA0j~Q{v;vgiXmLd?qOm50f3Y@vLSO72UwW9B4y^vmGp~N^TG;;j?D@`P#{t z?bQpMZ}zEWt@G2R=VL|Q9VI2V+7_57*YBw9gTJ~9?W+rgzNg*~{cL5$=!S=j3v988 z2#c@H^pp7-JF@9?ny6$`{0h_4A*shPS^4=vJ0{DvC+lu6mMI2T%HlZ;E})IH>MRZp zHu-h+jC!JG3k~Cch7Jq2AU@AcQw88lNtCL*60p&o(^OI4-Zjj>`4DA6V`^d+_B%2w zKYKFeXkUNL@Yw-#dhKT`3)5vW{v(^?)h!)&jk7HSomVc#KWl4ip-^Z*z!9)O07&Ps z*5<o?zo8O_QjK4W1Vc^p-4WT5ct-OeJDAJ-b<p`R#RK%|!dx%Bq{$vExvF^d*16vn zZo{S(NW|ulkb*-)4~83Oy{hEFhLq;i!ap51?HEfzPtVTC#=_Y2AY#FqMfUeITK-EE zukS1+)^ee5sP}{SfTh7DS~jqtf5tcdu&2iSR0Pd+KNL2Y$a>QiriU4YiID8HoutOR zL0iK<(IDja^XerQKA$y4_e~{b@l*TVpMH(krxp_hTVM{b7wG_RiC65XgjU_nY(+M9 zcDeQkz-3;m-ri`UB3FsZb?Cn(<PHNPisEmjYD&-g7uCT88oiDo|IfEC7k;<w8zSK9 zSvSk&0t;>08#@_sLyo+_z1b>Uey7-)(eUt*WGvdjfdTweB|<{_(At+VI5@aXJX=QW zss<kSuIi3gK2OG9-k)2;4@G9cKB@8?AeVFq2`f`6FPVe<{o6^|bO<fX%p4u4frONn zw=tl&*rTPfx$*S$G(7w*n5gPiq1JrM_s5z1)rQ0HI5bT(EIuqrN8a1r=gh7W7$|Mm z;}CJNrPfru@8C;)EFFweNZW6$vp!nv#=^$*p80D@Y3Z=93^$cePxV6VuPfE!=Y;%r z<`WgFjCUKph0)RLUe^~`+cb2Hn9jwSPU4k%9d}1*#o3cHu;y(STN_uG2IUP7%A5f~ zR;?U0pp>^fECep!Q?t{|l^~91%{sPL1N3%Dw=A;npAbGsV`J#+LQrtFwAJmCkJ!XF zfUbhDfp`3mfLl-y&;~S}4Un^2_<`q1!0A?3l5<&HSZ@o8%7}>dbsT%>72t4ADxbdi z?&2Zv@X$YZ)WA@p0*fvd9z-dSe6oyzJt`}B)vaOp2!c*xn&II!)`8kFPW+LkwOQGQ zvC<1#WNy<;)>6IC!8HY-I%=^ASFC4d+k5)o3^#W-7x&ia<n?qr?wW}|q}&DXTs&~W z&lgUcJ(y~0Dn#g=^%Hn1oub~pVcq)?H_YW_re^n6IIz|^9&Yl<>F$<+zv^Nd^*%c2 zeJo5&)>ihXN5^k+O8=c_SbhDhQO`sHkw<b15%J;j)i*c6$H;q6c#Ypv34!T(dN6W- zvl81uO8N<b#nLWJ$tn4AV`s&Y{Isad?<cbB)O=S~(*k(;zoX6r9V4~W$MCs1p47)B zPD1;LR}OmnHjtQev)iB`sR@f2A_~QuYnfSqQ`V?nPNF5?ef{5=>)K&!Ya0VIM*QOl zP?|f}U&F+4^YutjYBPUL#oo}QWZxV)Tl8x*SYLCiO7`~f%xUufFo+ijeZ0`wcz+*! z13$kEM?BBvWh70nso`K|CMj{n!%w<ak_8ffIxUo{l8Uj(Negj%hqCG>3wvy!;gQG) z_v5Hby0EhN@V~ABG?h}5lx**8!GirUw%5#sBf-*ARb?-vSYH%kj}PJgtfqFzoEwVy zU!b1mj-6KJQ;Wn@-Q*!CsV=JS<a_uNz^VZivBU|Xcihld05_<mQ9(qwW3B-|?>2W! zG>?=t^Z0<Ano2Pt`FCW&bt;xLNU~59`Yr^^%Xa=H1?Zj54svi}g~ybqIXG!kMcFUO z$lyR5ItrJcr9A+)B-m0dBO_DlB*d2(Xk9-H)5#Z(_Xl57czHHh$bC-b{xtPkqqGQC z;kq=Uv$7H~wtg_<ys07{d#w9i<y<aE#eWn8JvwgO{3Ik&E|(|A%9o9H8`_#G=<tYD zL1=jXZ;$5l;pw5Fsi{*S1Ol~qJ2kYRBu@9?srIp<KP5yk7{Je`Jbq%tw4j`&AW@l_ z?8Z=juK%X8x2Jc{)Xe+F%E3lZ4gY9<q?PB=J}1?qC2EHq$iY40HbbbJb2+%lu}c^F z$7?+ZKY@Xq<~uYxURqftF5Az-$eN2mHK<d!y|li(x26C=16w6A4>1)L*F<0Ill;xi zZJ;f(&N#0NHP7xu2P-eKdmPBf)L#(tIp13=SXqrD_Vfaq=&9>DZ-q*WjoXg=oXVAh zS|jv>glZvpj5$PvaPtfnF6Xxpe0Xk+9n;{pGI6Xkxx3)-j?@Kyh9RKT6GC{dK@Apj z2m~S}l|Oaa?j<IxS&M~%haLJ!Lrsm-jlsiDwRoQ6$0Y|=Nky5;tMK9ciw`&%uH1Mp zchx_jbOt)FgmqKBeH+eZ0mC1vvNKk{<|cGGI&x-yzx!at-W{xAe||9ACeVC+WT1Xb zNc-(bk9@F+`vm3oF}umK4f(411)axm=@Gqb;!nEA=ho~z$R{1j$1jl=63)PAXu7j9 z*KW!UD1~pJp&?<ZO+j8}ipIXe#N*?m)O1um{q)kkT~ySxQQhA>mtTg<Yl_uWmsE_f zGrT$Y2ss!lN~f(XFC81#U3GqYsAbBtdEj=rZ%aszdPH<R+9{Xh>a_b}?MV$57IyOG z?j>&TUX<q>a1A^>J;k}jm-wc%xAE`!?3rkJ+y2f-s;WL$1z>fOHe%wN(`~Avks=vt ztJe0Z9AH@l&z)?Bwee4z51ey4BI2lVcCGy-Bdb}}Rv^kRh;+Y{k&=2DN1&^f_p?j8 z8I9@lcxzw#*pz$<Iii>IN(&*BsnRQ{(9T*ie)~!Oq#01dU4I?mktPR4<@*iM$Pu89 z&a9I*HElH@9JoF_v3QQMX=ZM|zPuY7qiP9A((C;$h>jr^xEL<f^z^Wi<%Mjy$PVY% z@brvRL2TT+rR<WLrw`ZIF_F>f3v~H!%IhuZoA^IR;pcxSFzG$ODmF3v&>RpfAcqA) zarC!XO?I74s0O{wEH!Cq%iCv*AYH4+Mafy2Q!_O>e|CZjQ=z-<j^US1WSE)kgqV@s zUE6{JA*kX${4K1{YB+tr&T?@w?|xZx8K?RX?FPH8>1y^#hX0E3Aeu(yf1-d75+qPE zK5gDQM7ImDRfoTQdQp_b<*$E?AQmDf*6DgbJZlG2njFBd+M7v^ja=URGFcEHCvNB+ z;l;ZSHlrnn@ftbsfx_{!)btOJ_aEf)ECs3A;b-h~LDgR%KWT3*u=HPQ=z7rqzkHwR zVodXWOzHCdiyt-h|0M~8Q9b{Eoc8*kS&|QEIcTouSJ*JO2e0kKzP^Hsg$K(v-{$Qy zE-V!d`1#xao&*H-QNqMgk{L^AXg!>OrBMpn(Bc2(Z`_f}6f6lQxJ<&tWD%mHvtxjb zr>FVlO?6LS7Y1QkmfQJU?XNy*Rf8BPZ@r#l->+YRb+$)kN*c4x%2I1tz>|PZyDkzM zwzRuCmhC`qB>^^NVkgDY<%Ox4DkC6C3I-@g!LY8R#P=wtXC2wcCnqs<8vDz;Jm1H< zR##W?x$SkogC41wN<63Y-Qi*j;Os;1FZJEPfL`Y)C?<R3FjWYQ08|1lVt6uU7(KY9 zu~bc6y{4{at_F>UqGzx0PJ=r66P?9)86xtbsHiByv(skVD{Bb}B;Y4i0nAHTLC^C- zVSdeOT=~XKwZ&|K8U&ai52uSk`P~J{B9Pz%<#csfK2B5_Si{1OhnXgeNmBgg8@az; zmW*bPb{K#)5UhmlMyofV$2Ku>4ygL0X*K+r!4`Bt8y6j&6opTi{DIHb))pXISilhl z{%ALmKwjy^2mgb)O1!f(AcM{gkpZNIZs2y6-GN+J8c<pkA}ebjvMoI{Ic~Cd00W|6 z_}c4#kH?|3jy5zpYBJn#)#Q4kQGKqO1S?P*1=$GD5T|!NQ@OLS00jgOKE4IjB5lmh z_GC^Q70oh7o8}Ze_V)LL1O!dC)5!mQ7}T(!h9B2|7l?WX1_tt&H7ZTR!o$nHZ85pJ zx;i`8Bdv7me!n^2TV6rOqE#mjlLVLpoVQq1I%UeeeSI{mb{M<EDDSww{f19aVL6t< zhTBgb+lYt<bGM(cJN;a+&%v*=y!;i^!^h(|IXT5ox;FEe6?_K=x<NkwE&P56oUH<K zv;O)j<|?H)fe5ZNJv)UBLfaWsQCayfBL*L#|8LUA_Y~dV%8+vk3VtguSHmy#^fJuQ zNaAB4=)a%}dvWT|0G<KR8j@z}D+W|34vqZP`T6>uxB{LsPU}Rqen}Nv7AUFaDB_qY zt*Yu*x)%1u(*3FYcX~?7(a~|iY-M<2&Z!}_fg&nGuJ;?JNJocLUEMFn;7~9aQ`^+F z>6lrD;E{tr3(9d_s)w6|Q5*-YJjwEsxzh3roUxhza&y5x3=l<iD*2VKmKI8x`fGJu z4LyS3VsSzKwz?+vMW*Zb|CtMzZd72bVJC=_CVP$c?{gDx@0s4x#ua=@`3sWRKR{OS z63rBTRbNwx1AdTz(Ad&~2Q%t;HsxQ2^QmJ;QcEKm_!KCznvXY34gOf<ke?>>AiH^e zTUmNeiYF(cPui>xf9}wC$Ei%W+ZUqk{~PIi2XYq|;P(Oi87Ez@0s{kqY9D+Q2vwGj zqQk?1_KprdVHJ`XYxtWyEfxX;LyB&WLB=iA-yh(&DCy`zLPOnC?C_?6bJei;e}i@V zmyka6J?Q`3o2e`>tN6pBSYH)sK?k4r5nj`>Cy~+73ypZtgcuWD^QHB5W599)LZaAM zKz1R-#!i4jqr;$aNfCvanNblDvuQrbAW{S^E4I?6Kp9mUmKqck6c>k6<#pUpTN?+) zL(TNqSVd2dBsceL-fU+%#cvRI*3@yVP`V<xTF}#vlj+_7IDy*qG#A%Q6<gJ3DbD6? zw{d{E_wk*lrKSb_$K|D^_6`o%t4Y5L!k39jNYd+<(9Da9V(H<Bo|QW13%dKOiOEUT zfv^panjeIO79IqMucL+;#K(cQ8I;I?wxZA@wI#0nn33Gc$w_6R3l_EheO)Cwx~XXa zWKuv|zfAl!@eLp=CGxqF@zD*mv}nWrEUxA<i(gGCxe2-%ZfdPX3w`<oTH@yUptO{f z0l)kk9Cz3h>j860J%0eo8(Q?_xUMnD_1%5Xf$z&e#*6WNRb^e>B|rh0o1f#d+umGR z@j4|$!wI;WR#QVl3IKiU0CB~}$cP1g&>X8JomIRRcDY0jH6>dMTWYeyLs3i1Z%P#c zp--syao0g62$VYs2_0MTGB+FM8n_)k%~l*?JGTKo$ya4=Hac02z~yR`EWNK^K_2V+ z;(&T$fSQ`h%hUXWG&eVAGKV8_?fV^K0X-ZIjfBO;gmH77-w(A|;5eQ)J_FY0OoNPz z-C-@7g>){uur6-z%`nw^9Zh6;twyc-D$s8qD{uwt@8_ju?e85$M@5?hW|V0SAK=41 zxVw9pk!IK2O|Ydqf*gPVLO5gp2<efKh&^`(zr!;Jl!&l6fC>$|q~q)B@1>@p$Z?Ho zXwbydz+>d~%FGneRUkU91Ixz!IlzQAG&C%uztz-CM5{5GZYubc^&TNzk}7IuW(LaZ zu+THoGuGGscjg)XPxbTsL<C=7Uv>3xkkti#i7vM~f=yLbA(xS1rDzaP9~(~htRu*? z&N(6~STSx$sgVt#z5>huReT<y;D8pbHUR(ptf5Bz>~ELuC#u@PAK4?I?jRYaAt!g= zNfx2JSe>75quIbyL*7naVLE->G^^S_mj~d=iO?`KY&^ehH$y`pw#M7utlU+lWTxH$ zS)UsDFM4Ks>-*7BaZ%y%RD7AmoevaXkn&1iIy3`aZP&j4?hpU5g>+|j1cZBpyDo+r zlXrR~E0U?7-XoAu@R1Pb($$zOxqr&!2+p$y^sVFE-CY{9+^VoJqO7DOEug{yeQD~7 z>c)jHcI@Vw0FV?pvL~$J2m(4d-oACZkrm&WxQAa485fq1`|7=O?>GII@TGd{PxE?C zJt4RKC#ked@x5oDHhpWktyh?n!@)``bLI7JZ*LC=A2T8<%Etf<pdqB!_0HAXfmvB( zMq4=kW3l#DR+QneX<k8jmnzoNeJy%=IjfY~(o(dM^C)Unt;D1b%$*unWk*LxztHyq z!NEeto!^JiKq@O*G80^ngsN)xC$hFcPoC+GkL2Y4T@r`j=Y!#NJjl(;Pt1!>^+eBO zUB91?u(3B(?r8@TISsxT$}1^>4)vM#NpK|;?&*<kmt6`UkH7Z=kkiys&ssiUNK$yz z*VKItv6e6}$TpeuI@EC4TwIio*~@1F@yJYNZ(+hEj20h136ue3Jv=;bJ>zw0Z!n2^ zva_<%l4cZhJyLa<o4>cTu){YGr^I(SI7p}OhI)GGF><uOF{zomr3R&&;m6QZ(6BMN zaJ03`ONu4Uwzp?QThSb^udT<&$ERJ=4hTwU=;##F5mMy#p662mB_svKe@NYXF~5@Y zyR^9wS0IHwj-Z3@LmM8;GMZoWa!XU0;)cAwc4(0h$*JDxi{>4w0tRC$SLfU<Up~*! zc|Ma;4p;N}ow1Qossqt~t9;@A#s+@)G8Q*fIE~b86#mv>^hYhvjzs@$YZVn0?Zr%_ z@Ed;eVG0}r$iSI{BubL%vlaZ1Ob&_&nZiM^tg#;;qz%2*5RaP$``4y~0%a)s6INV; zUGU;A>V2j-Y50ykV!6ho2E0X-dcau}?2k%yTwJ7?Yw(h5m@g=jPEL+u=D@c|;J79z zr<z@pq4eL|KEGgga^iZzN(a82EDAKTR=f-f)Ng2e1>R_c8&{B4k|PXCs69)2!67<- zPG2kvv$G7*)6qs5E&VEv{23kXZNLv+${S6UQl@C7YEsw}C@F-%3tw_B#6)#eRgY3b zkZ<WAw}Ssw%|Z!90u-bInbMVr$8~d$!ayZ8GK1qLljjD$H*enmZ#>%n=lcBR9)Ga$ z*-W#WRwDs_^TX9-mDbJI6?6i_Gf*n~U1FJ9>b(%mVZZ!qrf<}Mexb%Ln=b!3B8<;@ zsq7GFSucOsN+-(eBvc<r40d4<`1Td-j#ZrcHBHyemfi?hORCEZrkTy!@3#qmRqXlO z&+Wri<HEXm*=_SFJ<%C(0Cyf{v|~u43PIcgP+r*JzV7khxoi@@*T8{U>{XzDAg9ae zSk97HU%&KDjd`uK{r>X!e_6F?;J`FFT3%U-MPQ*4jRmZgi+aOlTpGSH#T~{bIrpe! zW@N&UP;4A*;M>(b!n-*_6j0u^kh@saAj%mguEEB}hSi}*$4BdaH66>cdr2ZBL=zE_ zfbDW3>n7*{?67xK`V~TXZ1xrPMLM8&ehI8+XSNQ?8UkYVRSxJP6TtG0=GW%{pW&aI zQ$K{j(wH+<uxqMnkiG6E(@v`J83;-kSXmhv*@~KuJSU<|*hfZ~3kqpwtIx0vzM2dV zTV?9&6POS1EkGZp?5qQYrQXK;j*W|3+gjRRS)&_hw&P|YqEu5Ao9vuz>mJrNqu-qU z@Eqj9wzoGgSx?YL8C0w+OX}TLR2*vy9GP{-E9Gt3Sy<j+Q`1lZq}BOxLv=ccw;CwG zVcIioTT?+n*TNuZt9~iWyl7zg2}czNN6)%0PQlyc-`?x2Cd+`Y1G!mPy3NebxtIK? zKGpHFiFc<-P1!I!DswG3!GVgJ`Y^<wK6|E;fti?zjE_h`MPX@aJ<X-GC*3cY<>&|` z5wY_Gw)=tkXn7?aEiKUewisES$mSGQ+6iz!)T1dlw57k_HM0sA{}|rdO5Bi*85L!` z0kww2#Z3cyWswdMj<A9Pnwd%?Qm7wC?!LG0#`^lw#}?^C3)X&VY01|}L4R<T*S50e zOf_AI)jd~scfTD>j;R*jea#1XMf14^Ev3)iDt3Ew!+m4$wg;y)tDHU(uZ)C<2opX1 zfM1mdi;Ui}+VkAN{u7_q?U~J+!gG9{?fvzUYE_4isU)4UICwZ9bS`DPr!^}q%%hX< zZ34bL^g1ZU(`jmh=1GwMi@3Lpib4zfM{QITL<FRj4gryFX{EbEKsrXcK?Ou<RJywv ziJ@VXMmmOup}T7sV3@l(=RNDjy5IgcKD!iQ*n2<EFV%)$vUOIdHt(yis+4TaRM@_E z>6!Uz)zje0_+)~Bv$MNpd!;1GruxexYX^tXJnd>w4dr-xOJb_68yJeMM(bjb$K=(~ zbsBNXN=hQ``>)8Ro1tC3`tF}ULvTYraa*q^jH^!Zg4YE8^Lt`x6$$rak?=msDYQpD zHNTHABOeJDBzU$hA_@(XfWq6s&xbWm_Ite(n@%zwZX^>ko2F<^UY_^4Qhd!`?^K5A z%|||*pwu|j`n{tub^mX??Y`vt_!L^?U@fjTknz^L-*a(w6!cmEA!#Pt-Z%i}BDa;t z@fO0y_O=PQP8S#c+GC;sauR1{<!S)*G2~^BRubcpdEHGBtdc~o|2=-!>V?>*5b`9p zRD~5#4#WW^dlYr$(5oZNFNes|PoxRD!4auakYD~tsyFT9xfhM{ijtA?+tcbZ8WwK6 zWMKglaOFsF4{~cxU+(zICR1$HyWD?0b~F@|o@imZ(7DgGMpp@$+HiXlU!&Mi+CBF9 zWrgfm#M+0D-8hyq%@em#qn*<Bwav3?sWio_k9-K++f^U|C;j#5*r*|+a+<7;xGwp! zJ=?cz`_0&|x_3=L#WGXlDoMJHL1tc2Q3;#$XU{@o4k?A7-l|3JF25vo3hG|73As8u z?o8Du6@25Qc|ojn=KZu1H>BOIYW!<ny?zJ{?U$KwsU4|%qwSOTgZ6ByEg+TwI+3%W z&cfEK&gZH7K(9XK%}E`-#4HJlfu`f$sf};Q<{sgf=_Nn1ZW_J&wV+GKs~e<XtV~h@ zY5<rD;f38<BVLC}I*|@3`*LNmp+9~+<<2O8;@cF}D16c!;==krstvBUwb9d4Rprd3 zrO8CF41iUM)A7J@j|rbv((L@+x2~!x)csjSpT<3}GTn>5&Q7Tu;TOV>b%`-d%J|xR ze3rt+zPq1IFTR1<tTbVKN@UMM6CgX4cC!y43D7v4I#QkzL}|Ex@QMA0zI4tSuYiw5 z)6MJ7ByANE`2o$DnGx6R9bI$6{hgCNuG?ew`xYdm3gxurz^6I&xhd5MWNCmmG3nIf zo8$##_I_JeK=``~kviAr7(%*p8_Uea)y-{dYm<oHkT|JZ`_oJvwa>?@wfUBPc*Y}Y zg9MbUD+^D$6|eTuJD0X&<B4Zp35oIPem?U<Jk%WMsP91F|AaPrrR_Ed^#s^dG_FwP zvFr_2R*q^|)yaWWl(WVR-om?W+<Xbx`H`;Ypth_mj;s37!&Y>A`<I14DHicqqNQ5i z{^n+d<Zn+w0S93bCs!jM6B3Zk>FL)9Cnjpg0vwoGk2G-`zkEThq%#<*g}u<5Y*J*^ zfbuy^fRwd&5Xe}rChmL1<pX}vI>E^`v9I{Oy$VBI6|L5UKfM2_vP1(_BeS-+i?gGf zL_VwnChq=5SyfKEdGKBnk*S$I8*$ho;bYZuS68<)@AF*$Y6ECyxth_;*pQ&lR<@Jt zO`P*dlu=0?<b=B8@0`*8_~ayuC}%+~3;<+~_tzzUHvWeNWN<sYOOK=tp^87<LTvt# zk-6iEzAZ8H>?f^rH=~OS!RNLFe&wHxUB0BG7+;0ToL6nSbg4t6{{FmUL(LD^irp-X zjGCP0!ucg046I9_{ZW@K9?IKWb{C1KbN3^`o^+Jf0i+3!%2g9&!e7#H3v&x+Y93nL zeH**75^(28OTWC<nDF8mrHoV?g@E7L#D3PTlJghO7=9H#idGGwI?yl%0@j}vF?`<9 zRt3gRgQKIMZTN|7HNZ&_@H=eBq=I#VO!?ZBWhL3u8VNLb8&;dobWrPvhr?igx0(eh zH8CyAZ5GdFvS?VNJN0$ge~?~KF2D+RE+I8|ANCK9lc$9h@<oE=ab=a0zkLmn!B8cD zZWac5o)Y!o6NH1TzG@RCcX}lM-Sae##`Z>}Hd~Trj<D7%U4ic|inf$uu6UM%;EjuF z0QWl!J3GOuSqzn-(6*4r6Ky90!{k8!G^xx>r-Aim>5t$&*b!1^iD5Z^S{~xfLE+gb z|Lz*Y!NFmG!?dXL<<MN-*%iEk^`u}q?0n`-TW{8kXd{^CF(xp6ln6|!;je5Ad=^qM zvQY*Eo2nnBXk;BE)5Xu2*<&N`6u4a%=X4W(&iU5fxE76W5=~v;pQ|T`hE@Ir?mRjT z3XB1n8=pizxjV_~0GveTs}#MC{ipHMTY)b<4;`jKGn4d)q=;q%d2To?rljQIjpU7k zn$&kTrWBb^sc8M~54ZG6*H9ZcGchxZzjJlgG=55X?LDe~UiCCQt>zXw529&%Q3#w& zieV30hypHISy%`@Z+i5L6Pjg#BcGUBvS`uLO#62L&Kx&WM+j6p+QWMMCVIS(FC!7= znqnFQ4G9;L?bo;UjO)lWbak19=?Yh8eQWD$rDWPPm_B>>NDQ4Ap4%p_Z!JCZyGt|- z=(_se{DUVFI72Nnn({^MScL>K^3Z@RshY{C_~a`%S0qEn(f@sehzPq;ZE93}7{x@r zY@DR5GED<bU<Tc{z!E4l`1K*U-a}sKOy{WMaGDDW@Y_wfUMq6hegaz0{!~kV%Oj(- zxDMJ!Ihj`PAwcs=Pg}bmTA*xd8a|)v{O%ls6Zu>tqjMXK4-}_<#-AuBQ-q!UR#O9* zu!~+29UrS~aKWm*ple^?CT-p}cl}_)S|1zB^ocf|ww2ZpZ*5rJKE}`2i$d53P;mFx zD<scHBM{*%ssS!L8yg1Ci}HD+>-hzUiHN=hWB}SvrL@#sUHN!3Xyv)&D#;TsuNp*| zOSp_tBXM$cG$O+{$qO>tIq+d|g_56vnAl=rZ^veA1JQW6|HE=$4(QktPrZs7)%oZ6 zIR}!wzVdz0NcEnncPaLLdqj75aNxcr`f-zRO=lsy(3&AJ*k}_B@lVox?4#39zuFHo z%$_=r*O_sYQay?Ld9pqM%cY!ul<}j&epU2He$ecmnw0-?J`ne2GKOgx`DMI5ruotJ zpS*#Ni<Nv?6CuEaTv=L5h<{2-j=?hC;Nq$X4}aJ;m7!rc=e5W7Brm3AK-1jZQa?Tk z*EK37#mvG&@BC{-;fIWCMNA!)Oc{6~H=L$MOUj*`Ui9?*EFf#s-Z%SNRW-`9jmzel zzTXS7unte0WGS^ho;o=>JHA7d-WkC&gaWFZRX+60o>*HI3{PLi!zEs+6>OLk)Dhp` z^F(_hn#Qn?5zf0!DzaeP)u@*@gK;??Un8ZoHgdI4a-d>=J)xst*sC4jXDDMqeEFeO zRTJE5{GtC4J3i_DI&X=9dWQfu!p<a`mw%DJfaS2THtN3dnC-3N+tP>v$_<q6?@35k zaD#)Hd4V9#+wQY8XR@L1<EMdpU#+qmgJULd$3)JLQnH-E@=ogPh*Q!EF=>Ui^QO{f zxo-1m;26wPLcJizHkMkA>fz~6*)`+zE3zQY$cn24uIo2YXp0<$od39gJQDI(PMy$f z9vS%AMOF2iVQ-svcvNb%wW(cpULNDsk#GcS(KD^-bz^ONk>d=>?TKR5qJHds;z+Oz z<}>`?h^hHfd$xqH;M27(Q)@r0_q_qhKL8>2(7Tdqt2X{WEW7+)(0#wTWn(Z_YK*lV zjzwx?%bZtBfmCLaq{&x^?iI^@!na*r+E7Di-ESaP8s>U+>tS?Sn*V9%AOMmwjKES- z=4EYN@DI3;Y?+(QS4tD`UK=1Fx801mP6==WKa8)Yg@qPdckq{>cBu|i8UX?H*|E)M zZ$OQznnb5Rmy_=XO@GnwAg@0m!FZJHtgQba>zCgA8o8=KSL8d8{)sK|++-45AEl{A zQc{6A=HC0dBj1OIhA1c~=)Tvv<uiz)!Zun!<I8vrKaRIINE}bp5)U$BiPq84xr+** zFBA6`5<(;Zu_h32+HgJR;Q_fKBZGqkl#dY!<@ZSiStchBxPTgTA*PFC#yt;ZPi1qm zwx^@7U(ol0g+)%e{}&84I6O?aaZTvet(!L!6k>n=%!a&sXKr0E=>Z^(%#Qm3-dQXh ztoZlt5d{c6SVJnKM}X)Hf^1q`UMC=hm8ie#z@xmeQU0e^te2X{DKI$r{PHGFclTe3 zmK~aMMg|5vvLlUErIZn3nXuVk`yBe@NlppH+1VaI@YvqoUXR+64)mQze_P{yp<8Zu z5$M>7LH3|a)!)t4;*u1zu>pBQTH0yxw{Q34W;XdQG}R33{z*N0X?prnTbqRLJW}-1 zWi9Ft(5=b}##vb_rd~YeO^S)ZbR>#_3o=|W42U=x!>BDSEy22Wxa}_1hhFKH435ms z&K5;&4V$+38Dl{1m7#)yLJ==?Lq6i$w|YXSy!`y9-3nfQG;SdjaO>gN?4|cE<POs{ z`^~uh-rk-jUFO}|Zkwa9T4OE+WG$i7(fB?e(&HgLHmf57lw0B8Abq@=Yg#ii*`}(_ zc|i8CR%~>%z&d($BmN3zp<;cddz)RcdoR-TcB!5A{o{s)l4np;z#*MRzafI(_7VnQ zRH3M^m;HDRGb?L%ON*hgaz9vviA;O&aqGRe&yLsCky2YSA3=20y^!JA*;)L`{i3nY zvmU<pHwLV&*F*h{)Oczj6Llpp|Dv6ldXqB{KeRb&?{SRiS`+R`g70m>HaR&tLBgZ7 z4GBqKU)SYa<3#>z$V`>*qHz)f{9-6Nt7Fgj){;{X_&P8A+)t(i1rOAjxVQ+1<Hvu^ zLyNSb?z^+cTeZ%BfuNOn(4ugpNs~oGFdf5YJ(b(5e7FK6?$78+h>1W2yN9PIn_*R^ z&0%3v&(hDO!7Lfmg)yX`nE$-#7<&o;`(t8LMHfq~<JY&BYu&cL;LoO&6cy<Yf0BEv z=<Mj|xw@SYf9cs(o_B^qp&;~3qAwp&Q}5>7#enfBF|)zoOQN>9v}ER)SXZ@%?kB~+ zEPs~?jO6w83)y1sALW<fBJx4*7W&eAH=T-tggWxE(8ltDtdgXpBtUx!e|)E*q22#k zQo`0;y7w`W*PbSV>d)@N!a`=If0!@Fix*)L5xmvEezWhHy|em?)RB>uwcLsy6mr{= znwFi@Vn>$R>pM=rN#ZTpoqZ^4F2c>-Gds%;E*aJpk|pw|Yi1G#HO_H;3%5e{YikAK zUvj@}pnU9fv<Bp~54ay3dn4L`#wmmcqJV62tv3%{;o*U9blU+HHvgwHFD;AQg|(o0 zvLOBn`zc;4-csSaJb*e_n<>iUx3{wTuyK?Cx-LzOJ<tl<z!@X1V$8wZ#<S>@?KU#L zudcc*o6Ny|jn_y^&j>g|GMipUJ^>P*UO+@?L#aNSN}Zoj)}L%mj8!Ra7H=gFEqn)! z9*(3qINtBw=dV8x2q83`lNr(SB{ugH-+!*Xd>aZf8$<X!9NpX`eDzo`vK&e;asm<x z64IZFN3a2Uj)nZ&SCBi-qC`$g#_S&MC&mDHb_WXwx8;KvkcLZRQVlq$P2{{$APp*f zZti4z>Nc`r0t!jfOU%22qmmpYm$Mv#Uua=rPDVz?Lh>4(^GwV*KLIFC`B$hI!l)xh z{0>IeLF8CnZ7ulAQ%Ms*bin<oIJ3O6(!g)?jwg2<KID(s@<AEf<DZ?&Z?Bm&W!?~b zb<2UygAM)a7|TS$tEs0|%8Ff$%R$M0`O~-$8gMAZ98E_$2^J*ZFGo<`aF}iQ2IpT= zqNQzV^7RT;2CU;18jc^6L8FgT3CX*dX0(}KFuE$R%#i#II5nVP_!=OSo?mmiYhjtr z0<p6T3u<g^9O$j72FdX;IrNuiD%(3zb7k2zFH2eMW*c~Znc*OA>%r{Gyiv2@quAP_ z&_Gs{m)qJHQ5q$hxG7cfhX*A5NTPMPwce1uG+WfE{q3MI?RA@L00?oM$6<9qmJ!C? zy+Uf&_JjTX39^VJCzcBgWmymigsQ$wVNMRy-!A8>26hfCV}1Ga3CjBKmhNom-|heu z#*48Qj*TToqi=(_CnhGQ-$;EIm!3ZX!HL}a(h)}x#4G+&h85g{Nw<AaU1Dl#78Lxq zxp}%}2IP*iF0^#VLG7lRZW4l2?2HT(UoRAyphst_?>P|twcb`r77nt#VYNEpOajhZ zkW7^g;xUoSzC{FhZQ+=z!pV#mncy*Y1Xc>p(fYc&IXHt2pPjh!HK;ELfClky`8l4h zgUr7c!_(jGU+&~7rNqi*mzI`(zGxEZrJ>Eb-PRTk$c@6%uO#Qke8`ZSegncJmX;|j zSOmD{y{6|vT&xqec1Mf~BK77lmzd@oI>qxX7QcAUt{pd3aPeFThi#7X2|zlVpx;H{ zGwRUHfY-vNrz#5PryihU!+L&!el#`~yrw|bfjT&PLRFQQMuj>YS{_tY1%k{fUfzDu zbMDJMkhjk3)cV0d@9@ypYv-c&CJr7RIRoT-W6Df2#D8EkmJG;ykA`sL18{G^p?Zz) z{?Lf{`W}rjiii>9IKZw8$Srn+&%m5f+Q$BybMMlUl7!yxr59?CUSRY~jp2?Lr)4}m z%K1q^jh~&9$6;{9mAfxt<YV%9V=dlcxbAp+%6+BZIG;ZHXmbiRzQ1V0y0N~l=!eb$ z0vCrj*zVC$UNH{;t#MVrJ`66FR2ncuME$A!lxjq|dj^y_zdks=wKfmf+yN4WGq1WE zJc9otv{+tJBj!H-4-5E5bb&)2#tz5v)Y4KlA$VNklnrAN6BA=(l-<@^!zY<cPEGw} zP(;COR03J?K`r3+CnY49o0}KF7`eD`O$-}I`+SK=NEqoD1o`=&j`|p*y||%zHEPi* zDdrFe)a?kQRVXSb+CX0Oj`sX*kGUQ(1wg0{1J7E8OKS~rQ9natW0W}L<TE0AhW<cx z@8NxNLBThi_!p5D|4>KIv9J<8t!Z-dy0%d*t<Rb~%A~A!u?!al`LnTQZeQ-(aIvug zkEx>E+1VMs%lh0WaLYI%fB(+dxTv!mFc80j_8Kz!jB;!4-C}q&vFR8pgAS+c&MCjI zd$TCeN=D?f5YMBI8g-sj-xX^hb-x;XsTdD9v>!ug)tT4U5r@vYI;xy~xt{`NSUuf4 z+dD#pG+TOmuOu9q9bxe?1XDSWOT6NGU`y^vgN6CUcJBr$_1|?hMwcyISsAlQSy*>t zrpfsgq*-Ek8`g|eTi7zz!NmDLf7q7xH{_0A6Jf3KAdZ!lS$?!*{uM10ZIQ1Mxc&D| zq|={`29kOP)BoI$|0;;HN$I|O2c3k3+?g57`BXHV)%@?jr&<|!@WuC~Mw3?nd}|+h zR`sTk^dGxnv<0|#^$uE#HMR5@xUT_aGg*8Cj4o^^Jp3O~+8eH~lIE3_bil)POttfw zs7#QThC8h4XEoqd{@oE0#aW`?EF&8OZ*j1_V0pX&0{QO(HL>2qr`w;M>ZO{WPK<lB zUJ*>(U#hCA7K)VVb8^gqf2sLqGYcRrbQ(YL{TvybPq{~Z{a>wFxFd9peek;+?C=ox zJ^lf+=8G`Rr9tCN#BZnipUWq*pKuyg%~zLpggoq~`h4}>x7wt{O-$Huv1M-RZ@)D# z`p)g`uf_8#Y)$y{A2|f3f1)z&j*-pMla_89<lL7q`x7b%=%+mo?k`u8HK3)UJ2=Ig z{0baG%dWb(p(ZB9nNJyqKRSV^L-y|N$h%+;7W6!82&$dvG`T7Jka}rxyUY?B9fE^y zng;-;VKU`r`FoH^F!PmZzDyMr%cmlzca}2na(;hLhX;I()TfU<U1Z$GzGr%{$E+-^ z0DH^mfnvVLecX4P_MRhSvE13yrSxkXZv^TvswTk&s^;&_-SO-=l)Sy`vUXXEqTbR? zwzaiY?*!)Ln#VsShgr`wcMklTL{yY7`#S-37SOJO%#mo-G9Vx+?NjQ-B+lvDE$I!g zUFedLlP)i<m<ZVvF*4)@21);Yzbq=6sv{re-qigW5|o{rla!cPX^m+9{TdGVG2vHt z$l;!hBcqdo=_z7@*Z$>K^s8;yFEdQ@+$CB7FMh>10Yc?u5){gmz4xr`ndq8@7VO@H z8E695RO-Egk3?p1W^+q#TlX+<1DLAGX}H({{;MRMCown{S>sus|LgAU%hD8~#Dv6m z?*B*H%2deF<HvXP`=OyXC(l^<=y@MZ{c(}A@p@~0FEN<*OK3C*!T@<wsZ=|nMkq2M z5v3xJ`xszhYG;6I*YKVOzhfKXEHP{A8$iE<J1O`%HoGP}JHO_swGmF+2j<JJ7_2wj z56z!ovsjXx@2;fN^T4ZZG$}B|6^hwokBY<-QV9P$JG#<YHr)B=?u5s9@we)TD&Dg{ z=Xg|-VVj7?A3!TJxM*p!!7VEzy+{-HOgZfyQ1AjqaOZz#ZiGEoZd~$uyKTNVF#*b3 z=gMkzLp~AO!;y8|5=>IH?WX_!5Uesxp{LcaySv-lWjpXiJ?b~X7K#7VAHLmIM!MrQ zviRr(*R{2`N7v6#+p0P`F3VmowZvb}H12-=5#SrAbRGEB<4SLtFl1tvZN=XdiPX7C z`8~Yfgn7-T?YeS7ZwK-!-L|LB%p$G6sRZnGu61h%=z;$23jNieBiss8Q@Y-@^<-Ix zi^!pYfon4Xpz$3vmKVFS!Z-OGXv@3FqoO>}li{GO{^-62==%c)_UkaSwRKt9z4$l( z&`jkD47T%QODiQp3!8PWj7JV0bmcX1!Bf5Z&t2^lU>)HALzs<fK0b<~RgsL_*r55f z`Lp|dezE21`$cNsi+4BhIn`5FU0us`B-MmQ+jf8tnC%Wqh9?~o8OxS9+dx>p1Km!l z+Kvc|Xj2$*fYE)gD$(EA+@vj`d7F2c^2~OAA@IEeNLSok-vJ^pmd>I{0X9sc32ko@ zI@i*o$X9O}5In|Q#?D;o7pK)Wss<XM_B2q<1yB(xRw&52wwBQq5J(RQcfmWA(rmSW zgs8k_ZhfKsrxzi>!$a9W+d#Cjxcw<uCtbE$DZ`ysg;w@)OicID@zUAJ#+MQim2OR# z?P4Uuyk>ez4bvxw*NRh)|4}?;sj2K|58g6cTYU#S1eKuRct)={AH?;6m6^45#AA=w z=c6Fv4tGNB8?oRWCU0EVcP188PX|W32CqXDf0^Q%xYJ_vd1XCk0UH#Y84+G^Qgfvq zefW`e9z5Eo)iUJRp*5?`4VFv#Q8*5vM__`798FB5E!5aXTVoSeMt=`VBnC_+!})tS zD`O)hV&J|7--2?oXk>oy?{KFrz&^K`yDV!r?fAPhnk{;_SktM!^{f@nnwl7&u5ra- zCd6C^#NE0WocK8-V?Sn>tb%`u_H>jo&}{jJMQ*M@ZEZa5E{s*wC9{YY3;A^VLU40U z^=`<{b-knvrtyHBAX4^zPtUq6VYoNe<ifqBudf~YEwZ*&cSgUIMNA9}!o`^OvV=ad z6&doW1f_PZSCFW7%1-SeY05kcL7xy5XGV><Z9na$WAoo3iF_`}7H`}6sMvJzoE$Kt z5fh_~Qlg_xA{OMDeaY3g9l5w)J_5&|Oh%uDnu4}S<u|sd_;-x=GR%8FNh=5^^E8(6 z+k(>e!Twfpxfn0dbSMKjFJ#m-oOr&*{4kf(ai5vl`m5K!OoU&0$=gDo`Gn|bpIhkY z#k>#V#oE<<HvKdmp{RU<rTLoID${qX^7D0SKPqS$#Zi2dcVr5z-q)snjii5h4Sx84 zLh)T4Y6}<h`ZA=#<q7$vK*j?RN!&=~5}<DfE}ttOgSwd4CYM`5-8Q&uYa8k00TF?d zJ|!EXY5|pO=k>RYN)PsZ61HZ0UP%*=MUQb;IxeeH%#`|^G=&$e*Ia2oo~TK8T9kX2 zJLW4a0?*~Wd$@2)CvA$>&l`4HS`jc<Oi`#A@X9>RjlO%u8+cXh%}KP-PQe@y)$XWE z-@2^F#V5r-vV0YaFGd6NNq2=@Uhr`s+qwwsU*{OuDJVHK1vGB^qCS`VzSjuj@1Yfa zZhc;giGSTJlR!cEwSsD=^dXwqoFX{3H|aTymMJuA$o6|u+V1A!xAd@ez&b1_sGFIY zLt1CrbUpFq%yDf$kEIqrtyb65BPPONtCPaQm0v?{5w1l6w^-)J+}b<p$7C5g<=k7l z+ekPkf|9SsON5_OKpKoyG<DP`-DH}m(od`G1~OV)F9&3G`O;J1DJ2)Y42|9{0xm~% zAq#JcnEr;Kcf|!Jr*6+Q<kVo(iO=qo=<~R{I;x3=-oQr8;8bl-YpdvtWF~MFPR37^ zILmI41i5KoRF{B)lH?p8ws+vt-`(Aj`+@SI?Ki$I>&aH~sfju>DCnjJ({oy?VbIzC zVCgVe4p4#vhO`Lpv-ZYx2BtPNj+Q3N)%Exy@r;h)?;<oP2na(3j2KK^-UYic_9r82 zSKsOCCgkLJ0!{$7HP+J0M)T@UBZGpsR}B$n#=X3%yp^~zXR_vi-{a%Os~biKmjNA7 z4c+Fi;JHnvxVuyFK;f++;_%4jFe2S!_a9}kp7mAof(FOkj#_jOdjtxqRwOPc`=z4t zrFK$ULX4rS1tmRwo>7C3{b|(o1xY)9R8xy`BzZ=i0&wNInY_13r`TregurzY;?gWF zY|fr}6aMWsza11*^Cex73&iMXKd>uiBTxvs<B`tr4=j&eOrJMjcy%Kp+v8BqplM)e zNJ6<FLZ9mu_Yk6S%+I9^7=u7vT};dmGZTw1JAqDJVAJK|Qitga&Q^0GsQAE;jQv{E zssS>fV3G5xGgpQPP^h6zKCqcGdAp5K6gb!%f~TdKdb;}~!{zt(K4|LSVXoL%eMSGc z1V?fEvyV?hrOjDua`5A~)cJ31#C25~6c9q~!UM~ph5Cd~I7V~-vRM^kj<)}~AHa@C zQ;4fIy$PKqLiyh-tnFeh$luMZv$MZ<yn82#NerHzSw1w<s&h5H-vMz5p8#Rxl%BY` zwe*qt6V+ogGunTU@BRP(b4dO(Wc;uFPf+c|NzoTwrMJcJRsT2~x}AxoGc%-RRG-oo z6rGtUDFOI*qD*E^PDz%%wS#Fslu?Ct=>H-KoY9_e-99by_cZ_{-J|Gd3O0ORPQUpJ zq*xw-Se93OTvgm$1?LC<qseE+Rv0Tk{zN9P=GM+iE@o=OsCKppiVnYB$qt7UCIo<7 zhyDi7mG`IObdBuOSB-S)`khH7@MGuJa&!3fIy}g1n!JC15BCNEMqNjy68sOziYhA= z{uT5c$fF%^(75Kjx+F>a`X<2f!3Q&7v}osQg~q*>!j3eL%7RZe97tJM|5dO<PJCkB z`=6<Shw<1hi2y9i)-Rm7%s!Ff0xy(fWhL74$P#>^?KU^FDWU2oAQ^>AH=dOI*TU>q z4{Fp|QHSsJb9nxTmbON6=<Y+M`$S(ae{3lh-%QpEhlq>}4_)0?idk$iWNVuVNo4D5 z!sB`Lp46y2rXQg2v)fnXMkW?$4(}`&nuB)>e2@R1=h=X93x*xoXAlMBbZK*o^SWGA zMuzyIMN@MCD_i$dhwlHd05%LL>^NNIc$)MSpYm0Wc0bj^g=BEVbe*rhYu8wALnago z6$E&{+j{vjke2Vl`KEsVzUC|;Aqh?$4n7%^Fc9l!UYW=NNI*_Xs#*UUbRm9u=x<o# z(bd)_@bcH<$4g8hdxdX@5{Gg>FuX9WCJQ+8a&g(N4gC2BcLICLL$cGKr+dw9q4aGz z4i2S^%BhL``?~Y{zg(wI7@C@Tlg|I~*JuLrM@lv#Eg~YEgsQM;3=$YPOGITLF8*ik zIqlB$JyIbHmnmL*i$;<2YNU3k^7dpSBl`~ZHsDTF^?eUmp^82`x&U{l_Dc>92Fm>k zOZe{A7M<|d>FEZ(yvAcdBRqNXM63Rq+WA@;VPC44nAcIKg<{fW!}|#kqhG{cWjjU% zOO*jt*eJ2fY@eEyeph2(5n1$ynY!@KeMd(}|5AO95&4RhOVz=_W=WXY>JDhf`bVFM zxbm#1sHzeWl0z&l&GMNH$1=0Cxu0`(^&+HM?5*-PM@y!F(aF>NKz>2;=k{t3`Z9-v z(L|7u&%IrLc(U>YYCQuY*VWb4N4`)}Y#IBYHN{iI#;P2E>8CJ8#nKzKopwHa(JzWV z1=TY=Y!&wBcs~#Q4QmZ(qT#au-#ywC%a@IG0JU2%NP~Qwk}5=so}N)?d}?ui!g+NN z=k>_R2ltK^R_)S0KTEA6WEVLmxH(h8Td3ZKFG%!WDILhB$jFE0<s|`1jrKHGfuY_{ zBtQRGXFoKd<|(`Q95Zkx7#bQP5LsrXJ%4%>l1B$e-JH&3Q4GNM#KQ)>?N>q(DGe?l zVBH1E!KA7ko6%NAUeUp}uKAqRv?j{Obyn-U-Nb&Zxrpuh6JRD(c*^C|vO=j{I`jMc za}!%IoR7kl@iVRqy4?L8d5}?TurjyyOlfs>IVmZDO4Nr=m}Y2fEDuynn#%tKyx;-u z!ENc*>Z)=%Ma6Sp1oc$412I)=Z&J0tZrRAtP+_dOsp*2=d9~Wk4Cv%kHr^ds=lUzo zVe=uKLCMEtsgs~zScD1_!j;z_LCVGQVyiSRj?s$&{CY}!P*!@&%*xTxcAc{ZTkGa) zWo0!GK38fe2p2lHhdl(XUJ8E4JizJCYFp&I+Q*TM1<6i^HEXND=p;5;Y(G}@@Uu{? zCnmfgA|isHtgNhzAFry47ZlPpn}W*u=?Zsb=Iz6w2OxJletCOYQ%ma$d+TSkb4f`_ z8OGfLPMsDtH&#sg7rSn~ekDa#eFzk*Wm{Xx##$xb?knU?v#B06Rud3^`<ZWH?9p<i z$QneIt9(zx2lS*qM4^e;<?yIh9(lQY6TE&SGf3<axsX0NHufPUzAs?C$oW2lXqYGi z|I?k>cff=`&6nG>ym6!N>#lqpyYXSiZlT#U5E^(LZ|z^=Py+x%IpwUK59!Bezd;UU z{mlU$?k6uU`ntMG%t?)nca8lqjWsno)8~kyv8eBhi$&B98b(H<=6}i8!k@twO;(jY zk+2&{d=T^Ap~zLu7IQop$zEkNs`IE-&x=@K0bw_9_WDK6x!nfYpM989zo~)qx1|u_ zUuipavI)HmUI#4>DMJ2K`s2SG6v5#W>%|xqBNzE^-MZy-))gF|irK;0?eW`<M8Hi1 zxwqI$C6f6W;HfW7N5(;Ck&@>zkpdL?YyX%p*Z#~F)0a};pDYr3TP3?gI;?cY`=6_a z2P6{6zMy*{0bEv<m0K&@Di`CEI>z{Q;Eh4R)PDno<geFWG8X3MIUp<kv(Uyq0B&@) zfbTskU<L@Tnp=R<A^c-f(hq>iu=K4@RGg3S85=iktwxHS%|XLA>D1OY#76T=jxW7I z^KxR1Df%%thk!uaOz(C;q$qmpkmJ>>S0k|(%VS7mZ?i%bjx3poU*%O)LObh<Nmb7z z;n?{OPz5j52;cZlL=?ki(exuRmiIhGcOe;|&B^c&1ca-7hHFp8%YaV<{07UUt!}_< zDR1l;+PwBp2Mt9Ffz{RS1~KfPYHQJe3sx113=7*Bt|w8epS+R3pCz`}ob7#R>}CD< zOybRaeBa-mWZq*%w3OE9a<?|<yX#98iljE+<9EOO>@j}zFyNJxRaV;VbVTM{rSyb@ zk*gI*nk(tPPdztTkdy-1FOz1OwyP1weF?#@{Wp4olqjc6KrXVDs%n|jTRv@#5X!(i zn=?g>ez)3uwcEqI&&H!~Qc+P+`<^yAUH>LEl;b=HPI6J{RI&9ius>jZ_YvRQa2ere zlPmC1MmoC7-B2hA`{`TPvgeX_JiWc|9cN}`Rk-yQQi3wa*~T#h!W=!+w(GxFR#D-M zppSc@%WKkHv-kBYun(CcgkORbRTmdIIhKthdt#1((a|axtkz|H2-rc=0BY>W=It#+ z;p|8z!sH?`!h7DnslK(n&1XM(fx&l9;zN-OSsX3J8EY6m6J@8e1zyvy_%jB})eq#9 z<4{HvDHO*?OBoc}_x6OixfNJqLP8r4PZR)ApPE|gg-_Z-wo`PK89@guhfeM7GLP9x z9J9WJ;2+}Nzb)<N;_g}n<nD@?=4IOoq?ch-q!K5H`cPvBOD(w2UU2^gv`>m*GA5CS zh#EXuqvPZJoXn&=D}bp}d@80?`(8_{Dj>iYMy^}sW1cqKC?Y(~X%GBp<(z8eldnLH z4v+6n1-nWqm4GQf_~{4B1wdxE@?UWqGp9>>8_@3^@1wo?+{s6~p!o4g39u6g%w^&r zwnXn4%na0siQrR;0-1RF)*B{uZ^Z!!DVG<W-^)hN?y8C1ChW9x|JvsITRM~$aFBFB zj&u^aqmj{EoSgUIg9Q@ehOSnke#%e9v@Ud5KKp5CaO06g*holxb}|OG(0?zwD_`s8 zK&dM*WC3;bE$LK!%&M_BJ{3{g#%S$gUn9=(@o{nSQW?~_<0KAxdwHcx?6IDX&e68A zSa6W+{f8fxHxSmtmUIjZA^367)0|9+FQ*YSD15QYqu~ay7X{_thZ<JTLlu)`BPfhq zam&ga0VkX&y8W;fSw8ei+|iqu)s{8G<dLV?<<cRSWuNKU<Z*gLN?nS8H{NjdZeaSf zsNb}X%ge%2`dsuS<{UWis03Z4lD}o1r`e9VZ+JkYysI4yM}dnmK_W%b%kkiVh}F?V zJPKt$2@1U45IHu~rcpOnr>~WUkqO-Bc%w2+;=j{?4!9#~Ze^8UN3e7nK`97QlvI7b zg7oN)wEH2SUV{uXCAsgG7;qH^1qS|O-{g7M)>wwA^AhoEwHDIftaTPmI+>Km^}B3q znc)$kt&q?A$Vt27YpD|V`y;$+$LpVH&(V@Z)FuLhQHFyciN9UFNiQutaN!IRH+vEV zZqm=<eKORC*#Nh)gRNPG`Jv3n_uC?kNPj~C-}YjppRxVBcj+Z;80#JU-bCJ#x}bje z=|KR>GL)L!7rji92j^iGp~b|+85f$})H|z|<S|Tkm@=Zu6>_;dUgv4%=l2KP>L7C% z9J5-Gz@*ECOx!zizJ7h1!>C~-PkFc6vNzwiVizt%{%~`qK2L+?;nujxdO1;w;O!7) z*WFQAb|rVZuXjctaZlR$gr#w%J@wk^*n@lL!^)zMA=cQV;YC$n)c!u&bMOMP>cfLZ zjNN%iN(HPPRrcgP1$8NHp(_u`Iae0iLf7(u*qKeg?kSh!Ql6r(*>vFQi=N&@aIjBM zW76QoCD6<P-w2aRV>($%lJVMt6)U&S+qc#RKAEARS+io0>qeR&=iNe!SMAcb!(&8M zNy*{8#?Rp3dXFqe`kz?f^4uc>**cpwP|#9jNn(lF5EYmN)^jPD$thqJ6}%rQVPs^q z*Q?*TQz*+UK%WDmgwZMLjv;?`N=w;!>~EQSQ>cMFI-z?1WG*xsT_d-bZ$t*J+N^)G zM>YHwLaCkv0MXdLe%zy0vk(6TwEVvxsQKR_`wX+!5_zjI4)}vW>>(FnRvol_cdiV$ zVK|iCmy>}^GchR<Xaep=c7o^c;-GssIFgEujrn+ge{^W*@oHXPp8x3}W6|a5Fruw( zbo8X7_K+CcP??^d4uku{rY5SfuYvtND=TY{W4zHD0s_Q~ii-ArVGcHTyJMjZUfYRP z8hYC&K=&BSuJ3r+EWNC(>R1+BUq5Ne&)?J}3K+z{0_41xKt8ZC_l`q!y2;EENW@Z7 zQcgc~kJ_Jkoq?#LLUL7+6(uDl3Evd3y9m=X1Lcm#6Oh^U*oAhyW2!#)_J=odP@Rb~ zGaQA*Iep!$+#y_4KtP4*GIV>Y`o|l(s~t3Vy5R<h^t+5}nDv+=L(H2oVyAx{kEW<B zCxg%ui}x1yB0JrY*wd-qBG7_7Tj7mbX7x+B94!Ww2m1v;iPhiP>9Yu9o}D!U0;?G? zBI5pFaNC_N$yKD}_qe;SonK+mi^<B&vNdMl<J$%6RD2CN6%{!Nhp?R(hi;WwM<380 zd3x0J$D{kelvBhG%$9YakqIFHJZ%UE7FHpB*FKQTHwH!K`<xz+Axrh);^@61=;~9_ z0(Z1VWbNKZqg3JBhPNHhrqQ^JO36>C2$JvcliKJ$6BF~Fy^ux`H+iuM3CRKjKr_uz zA~0&bY&2cw;Ie3>1+qj;$A^3c+To3<qN!b5UOz0N1L4L8Tr!VT43a5fFzj*likHeG zo33EIE$IwOeBiYO5qidf-EaGqpFF8OY{5t3Yy6bv6tOt!%meuhyS$<DaywsU>_>~O z*|udJ>Ir<*8GabTsWdcnmR83U?5`XAt#M{-ot*S)FRmtdkH0k~;@s|%p#`Wc;K;T) zmkt7k(yzeGeScgt(oN0jpaG2wdiz#)R=xy-HK}6Ovl{G4Ao8j(6f~!woqF|q*e33M zym3<~)0j>v%Raw}TF8$>p`*Q>lssvCVxq7l)2rut@ZF9-o#S`eG>q;M%r_oF5OM;9 zGvuwv&Q2z&6Qxg-F`;c8j6fPh_VfaKOku}GM>m2%+=goB>kfpI*YLl?qK>btf-fp( zV>8U4s9_0gH1FWx4H2C+5=6LK+f;+m5D^T-V5+LBAQ29@xTL5L4q}QFeSBZAvF$&Z zY%rN2Q<xJ84-fBu)6eg{;}g2l3qmFUnwW{b16XzaT`I$Dwe?Rej3X;uWu0#SVF7tL zmOgtE$vm6Y7iA8IVJOl5zkSRvSQ3vm9xQnXlT(pmR(kN;=p|cdR@e>LxyONyq&<v^ zKG*Ff7nkozLZ18f<d5iR&iRCI&ofMneR)=U3n0Dm=#z+)dOrKvF9~<+VRkRs*)M}g z7=eP#elFcaHiC-qiNNdxf{T$++hA@J($t1;GmcAwF;G)G=tzX=SKDh(bpqvK@Iz{t z^<nH=jwZWw$j6b01TeM@X12+L_9CC8s@HWyap0t%o!;xeA0lzQ7j5<n`MgD@)X*JT z=({npZsdCgnW^*b`fjc)b}sCNYa=w-<ZB5^(%VMxKm{WoAD58NQvReVsFHt^!^v3& zhn|^XzJR!9iIQLMQK`NlX3=!<O=UrWb-d@!H2Pb=NPy^TE32nez!E|KEInmI&!)q` z&cA;aGj>sXf_}@P>@{zG%b}-LJRbgzz^E^n+LvWCRa!o-B<yQgE2nY8sS#d#1^>ue z{6lh4vS5wmS_t;jrSd}=lgqX^BlOy0KR{R!WRZ9>NWYuN1k9z-ZbM}CV@-R<1R!7Q zf;OB?ZmMgSoS6+o%`^Q#3VjiB6UAPH0zIk`%*J)KRD_@a!FvklfVZ1d9JSgA8i;tK z>OJ<qr}Oju0;jpL4B!?sUPpNM9;WcG=cLrTfq57=m=YJ1#MXMBncm1-D;Ulj%=x4H zGs+{aIsk}*-!_MMn+<=rYCLGJK=$homB`DQ(Mm2~EW<A+TE{knEIUlRy8a?g(N-re zz&d6t&IgQHckefWoVrJpgy29qEl-96Uqs*?$yN$ZpZpC9W9l?8F9dz(l1qA{k>&@y z(RkNC)9?ui2q-3<$!wDggB`F*L<lUIkG9$){LgyU30Dx|h9?IHttUx5D6I7k$|j(V zKpA9+o|IDRgB+4a#QHFY$OUe>l7))#gWq{~wk8|%Je|dar|aF3QO^S+)A+x2Ho2ql zws2ihp8|qw>-a$$>v1r(zZc|02s9=WJh@qL6)5nwXa|>IdU%oA8+CN_MnOT%*4{yB zC!G8bhoT=0Y)^n66YJGKoyenpNGkj$AMbB}zX*0A849<WP`kV{j{?%;_ApY{lM6Hn zgW`k8ul#-sQa>1)w4p}3j|PlfrD0|frB}7!O-YBKh~C$c;toFLr@NxZy<@lA2GG=S zESTBZ3yVND<Z}0qyra!A%jQ$Zg=Fv{Qi|5#!)#i?uRzl*+}PNlJ|1kg{>7Ii_DQ2U z*D#z0AL226FJN(xC@DcRZ>ZSi9$TsQ1FBc1T|?%>d5Y4I>+{~2I-Z&j1jKIcN8|VM zl&K_@cgM>J<>OwolZOz2Hw>&eAwjr)Y7X~j9<*-q6#1*y8>kSvK&tE}Kf04@voJKi z^j!ZgZDoU;Z4|vYt;k~x(`G-}*{bgC?R7xjOTZ3Cg12ta{~pj}frl$|XsVmC%Nt`n z_0w5izFVTX8Ruk^O_V}7y+0+Y9{4zQ9{izncDRMynaSE*w&i>2yX^Jhyy{XSAmdtb z2_~}aVP}(Tj}C&2(<h$ap&n=@cXoCx`%?+29{rtSDhj1u14h#7>gw*lmmN6QzTi`b z%&{x&f@cGuiye_^R+E+YOs4_71vSK%KrXJ8EiTyVmK}_N07DQC1m|5Q`bW=C!yH={ zV`pz4t%V?Vc5<@;=*-#UG~cs*WidZ7Y#y~J$O<hCy>}2zH$lkQG+wRDVP1#_Jo=!5 z_iF=ag9mVqeRZiJ=$;KngDjoxM~|M3Y<Z~w%=Niiy$6L#Nk=GA+QHtQiu^X>z7^7l z!el5@`mm>`2Q1F=aUA62<Qe22Zw68G@$v1yE*KmgBo%Xb!2pbFjvj4yvfKj$e8AvR z9G@C(VqxQTl6=u?_|m@=2IE;-bdu81@$hNJj=@#=v5q?pIbs~e=cfrDPqteRJCN`g zuuqQvv6`6_d;VM;J&1et1iS+9+v3E%EOvvYFZb(CU-Ga~!W9+6+JfDxcu&L2ZQs4t zADINjgwb2xuDd=WYZh`gb)^vzPF-I<{Hj)#JCpq+z{xx~(`%T|u_UovnUZ1;Huk-b zJ-t0DX?`dSK5AzQ`zM%sb7PGcb*OH5g)MZR#IYMTIV~5a8FRfzi;B{TGX7Xsej0EU z(bD!kl(>(Yd#wOyuTQJ*J>{{uNMLEadvyO-=>~-hS>bH=?fw1p-IZrDq4+n!%i9tV zN~B3Hwz)k~!{oR(VDjX$O(5mQO%8*GrxZTJ%ABW7?ocW#85<itIl23V=Muf($}D+O zroXhX@I5xx4Ki7)<esF8mo9rr{DhkPcc^rufoJ-Fq<Z}<jYOZ8+w9i%R;zMEds`bl z13mLtn>U?X>59*}Z_(&>6MAK8d|am(sMTpozw+IsECeq>z4@kFM&D1=5=i^jGAbfC zk9`&6cooQl)dlu0t7o2(WW0NEh|T5aZ#RwJE6ewPaE<OLKMGU0s4A-hU}Z%mH?qN3 zIdnyFPs2$3PevA_-Z>u$)fb~iFNfLkV~~LQQ{28k)faPiOt1l>^dtpRK#;K=P(ah% zC4RC5bb0p=BB^pG#>c<nzM(_>JOMM2goK2U>-`6~^_xK0HS1l05M5%4k&_LlXtLZD zW&0*Y0sS0kX<|}(vBy+LLmbi>D$=xn_T(bH_;Q~yjm_W)sG3tW_z)$waUdYK`|sb! zyIo&z_^7B1XdC;Kj%Hu2yd(>A6ylBvH-hCof5>V=8hFjee?13&$n+uX=utuZaE?6C z+OJ(bEjtungYoe2W{r&G<JfjVo0$qLXqQK9xT>j@A85t!%t*-F`yp5viC0$CzG--- zmpeNJZhT24AtKIfV2kZCTU<y^UP7UOIYS}|wB9qb6B1EwuWXP}r|lhnH!sr0OoGHP zamVgHA@`kdN4^0*9S}2IrvtnIWI`5|r#oU&dV0nDkHD2gfW>&fPu&<RDz1FNE~=XU zL_tyU#w40r#PQA{Q0rhP>$>4N)M`RhRr?Ufqt<mTwu{zvu%U?lyuS0&;wT?Lw{2n^ zL{Eq&z>g*JTe$Cj&|4Ukh>D8S|4(LMppEF08e0_AK3?Q1he2zsklWqYTU0O8kw7*3 z^6(@jid7rRN+QEdnW1Hmi}v(n+M!W%UwbrAWuJ7gapz6gQ_crM65{T!v3?%>E}id| zPJ0wQwHd)29~5U)>vgOrE-rrlQ3)6#NS^2-!O7l8(UeLNa<>_+ocJ6R8ofoJxq8VB zH%5x~g?RB+?SW4cu+<K;bv$4*PbWVRm-9eC8_oppBih>$2K#r{o>5nc+HY)vS%+4{ z(C=PbXJ<Z$Z!6M*imw|Q<bpO_TL4odn@UtzrA)RK0HyGG!MUhg`{I?y!0$<I>!H@_ zjeQLS)EIdb_P}uscXo%P>4NNGQJqfN!q49~)`sjR8(impUym2CTbol%;tiz@-3bg- zNIo?MRTQ(P!cTU`Qhz1`Vg>8}u1;DWZEphZ-!J&&pV@!x{o=8mq!SdBLGO(rwKTn1 zmBF>e_#oh%HsJAkXn&;kEcyGt@`MBn$n&MmG342`XseB%ByH&J$x4Z%BU=`DnoRvD zo2#pfZ-a1P@O9S#F)d7$JMt1hG_E_7W}8*p<b1`A5JzsBR|jC7R8t!sS;<NiLUrtR zgnL`;MG-*ZoX15#V?FxO*nb-#9qLcTYkD+Ydzk8L@!1Itq{Cw8Gbl!3E`mQA0>iDX zmC}bR^06-@C(lo&cD;`_&NrSME4Q9i+XSghl}qC~3cG;%;=zfhAmtKFs6b%uwGy_T zB6NG90Onts$_Kf=Amp~+%>nOE&hQhHr9cpM`^(7SZ;h~}o5d9uZ$X+a)qGf9y|O`U zh`q!ahAQ}xa(Z<RMEjmU+?s~vfz{Wk%qGJR+cQk~;cIK~T4Orrf~95#m?7S@Ux(p+ zz;WU7GpxPX6hKCh3S~&XBWXo;alm!XSpx1noNlz-9d}et6LhVcyuH`QZdkq+!wg;g z=(0Q5(Kb;#sZ5@QVP<BYsYBtd4b&Qfp1n9ThK(aN`}N=AlCoiB=ldOL*t2e@7a-00 zTQ`q~rEFxvUVGB8Wp8{$H-U|QOFbNn?KQ!^_?IBGeE}Z_@)uxTx7#q$AIPpka+Lp5 zDBte9QYFjk&(FVAl!q2S*|IAMk_kNc0G^i6P-n_Ge-JY-#-XRO9Ul%-mj?z^V7rf` z(ZuK)S6l!0=7^vl>S}+x|E6f(vFFfldPPU~{<5KVp#@z1N``e%{d3uhT*V+gfYmcH zg7o2?ywSqe*4ES0TU&Y*8-{Eng9Ja>G~0h_#{g!FPq=xiyW(UjP0Xblf^>9o;^yNj z>TX_pEF~??vwvK&Ouilx5+c#koXBgPd3J|+-sx}W;Ns_iQmKyCxe`?j6;s2vP9*qJ zHpX~Ce%fws5guj<GQd@2&jI1^6%o1OyrupP$kC%puQLOju|I8%*d;g}*}1vL`Dj)R z@`cXmtTcer=?~`$3JB5DGo-*jIQGx_uJ)&Ttp#Kk=>46$%0<KA0<jYati8NU`h!8b zfi&-m)xMy>FB#K2TT4d(k+y+f#}$#v?*PW7Cy-eXW_dIK0uLSmQ0QMnAA&N#`{uq| z6!;|m-|JSnBK-m6({SN~5Xfa<0KQh;IM-@B<e>)K2qdaCO9Cbq=F`TJVPe8NI!Y@W z0Z0l}^hj#sc?5+>Y)Z;ZuIr{Y13ViFHFiB78X5wZubBVkXV5G#@I1i#cq_wa1I%^c z_AkuO-x`H==d03Ys}&5qdzG*Syhv~=m#oap8|P$V4qG>2TI(YP!(c-523I%WsXRQ^ z2BP(=Aw}$alRvd>kT>2L%g3_A$*FeM=O?NmkmU^hDxc+#*D=D=Gr+xNH&X>jObAG2 zZw@G0exP0F%eXZ6N3ziQ4n7%(KPwSr6reXBD;44Aig5-T90|7JXu>kJs;rE7^@U!; zQmtiL)vsTVsM!rFPs7KIheucZGlA6u`xaOlfqq#CMFAr1Jkw!rJ0cn?I!wYEq@<*h zU&4WfP2z^bU?zIR8Uox_5<WKQkeD>=ZqbULA7OhqND+Vf^1~ZBxxz`1sCYXdI1FGO z?}3pCG>a!3pKO6Gi%ryZ=OQRl4Bay|Rqu~&+T^vnSQ^G^&UgdFA*IfRgsOE(+j#1J z_Vw)luz>pA*SkiIXQ<73lf~RP2Dlz-l!cz2{`qqZzq=8j==m+jc0?Q<_Y1q%*49QQ zA9>oO?e(;t1_r9q%J2&bHSVue^7xk$rqzL$3mk#HY@M=$IMRw)0<vOVXKenO)x7F> znKKF)9s+T+yGcv$@1CM@Ni<j2)(X?az>NdPG|9Q*Jx0$qo+~BuGmC=uhqIk?>PSkl z44)d$Zr)r_Mxxf@|CFr%_hsWPPlG-|m!qWtaSXs{e=27LQc#jZ(xDKDWfnMy$spa8 zCi=}wbyp#vt&Impo~4DQfhalNatK&D4_7X)LN`Bnm~H5DG@eRG2W_p=cf0S5F8~+_ zeHSSi96o(Imb*SYt6_-wm!nrDCV2Sp;mW@ZJ)ma&F5w)O3Ta;~IpLb!u_9i_+cQP7 z$R^)QtSddkY=dWgcJ|U%?O`c9duP+<%=Cz;_wVfjF@;pO1_7BAZGlHQ4lv8mU_js5 zOcZVhg^~c&zEW!)R3@Cw1)zR~Igx;slWR6{G#3U}u|)cz0>G&NTvuB#rO>S-e>tOw zHeB5@pSRna3oNq#!A6<o-i&muJv|R(Z|-_1Ze~^oU;waO&=>aYTW^2A>^E)USE!&x zipP&PHa1L6O*2nMj?<rEwMu@<-cbzs2RiyaHInJ+tgene00ghQgoI-iz__&PeUq;N zs{&B>8>OatdDU4>h0i68uODxUO9x5&`SsrNM8Vc3kDuMVdDEC0LQ6}VVFL19P0h>( z(Hf0P-$4v`V(e_|n5_N0O(dLOjDv$ZSXv-2m&?Fj`skYX$y!7ack|7S5$3&x9C@?$ zux9RvUokO=F7-SxzkUh^%hvjMMgY(e94UiLQZEqUZP|oEe`@J~r_`S&QIkAx#XU%L z=sQpItFWFbHT1@3*Zn4FoKv$`P(cDmo6P61j-e>|1-G{&%}f_VLqZuF1!-xy<PGNL zq6s(o?4jL$pjQPwgo{m+ph!uM%8s6l_FKUm1;htPEA=V8iH#qxv<|H(V!ZJ%m*7m3 z1JnK294`Vd{`Ira$Vh5V(|CUBw^p5V;@&7~m6_uh)-g~3!^+3#KA)LJ&~&?PF9uv| zP_*;*;SZzKqvq~TPn#0yx$~7xj+lv&o{^E}=FH;C;@Hv5h=|e4vniHk_03U;RKua> z1GCpnPb^pd6FR(~IEayrq$G*-hZTiJ?Ohtw`>ljo7upLsZvDzySO)0u?n0ZqWnc0! zgfQKQsOBdpDi8g&;fJy3Hf$`fRPVSW{dtRO0a03;?Jgn@3x2Hu{dsa!(Z7my7A6V| zmOa|$+e?|)g&+2vb2RXi((i!)-k!)v<=6O2Ndib;^fAR237Ut4qkk$-*TEq*{SEq4 zO8qze*N=R*!wcfatFhP4o&r?;ctIZObF^={;P&C3>E&nXaR9gY7W$xn*^Z^E=P76L z1ywUY=e+K$ReC|hhPEAE5yhl7D`ec~ww{|a@vs5zu@>0~Jly)wB5IGX>YI@~w$%<l z(h>m4_JEStraRXD97Vl0nuP)oqso*_#gFel+QI=bHV;4@wVADbLPpgKEl~<Ey+zZ? za&p@AcyRlz?WtnV7m7|O1+&~4**}``xSsU@9(lnkFE1yQ%U1Amw#g5WX%ZDc1W;5r zoY?n)#{&*p*Gi4*BUr^e*gSAS9oupZ)6bM20o!Rp{!k77%ZngBWV{pTdD*W7IHcbB zi9OK0W%`@8fvOxPCMkA*&!J(;Nf<jb8)mOUVCsMC?yaMuY}>G36crVvBveX4LQ<6O z#y~<!T0o^4M!FS58bm~t4rxglI+T`1y1R3Ru9@%TdER&Lwb%as_`bc?UVE+mFA5AZ z_kG>hb)3iXJDljR^I1)%Sy!yBSxvZ_-2YPMDz?9R&^nD7@V4oQ-OU05b(+(vP`<~W zCkOcWH+sJjGJX*E{g&Qo;BMDK=rDvjk+3X*3sq){L{3F<Z)xm_5Pd^;1dDPNrcm_v zt)yz0CR4}YYR<m>?lvQD3!@8gr_fi&_z0nqXd4@wtUf~lfq_;p7PjuLBp>}TJ(48; zAG$t%K&bCAZ9BB-5XgvP)W1q6eD;yka!g)!uJ;FrrO`(RB%}~U|6$TZ#7aESs{>x7 zB2Deb3TekC?Fk~q)_1wN)yD3#rIq%+eJ1c2_kWm07Kt-*askL6GLa#f-LZ|qsCx{S z*|E@CTa&9asCK*Ut?L$<iP!QN4;?yKs;DU>(~3FPE=4qf-HG(sM9fJ?zLCti29krs zL~8wVd(9DZdsyuMaAWuDN){t-)pBW<TOAf<f+VaeDfufs!QKD->zbqAB0ndNOm+~1 zJLnmfd=$Jl>8Yt>)gA;JH^<Y)#oW?TQ%!g{dWxS~{<v>4Ke9E?9Sho-l;^=*-hU-H z5f6w*`+sj9+VVOiCGNg`V6-k;G}PaJLE-wN61((YkW|ggEwtF7UmGqyIb=VW%=p)c z;`w*$8k$SMavj$*y3vq?gTSM!<)L~k{#QCd+h6Q?mE!J$U7jaLHWSrbI|H+I30;1_ zYo*6%gzfk1(RGKeuKq_sQ5+{H1Cg++kw2%Pb(zKJ_3PII>w8LJ(V<?iUY##zHC0Z? z*ws<!d!To<{1F`0dir{-Cvw+NmQr@rC)hBJngh+u?I0Cx-1ZhXKVtZW&Fc?NLTqf8 z$2e&^38}b~aAo@ouLQh(klpxVBX@}nYFXfnMF)h7L5Mo()6#x-R9snF-d*ZjJ8oeA zN_2^EWB9J5UK;r6TjtVhu%F5@mvTgm+=yuc!jvC(exw=}akBC{jIFef`V?)TX<%b& z$tZg3<qz1b9UcD+>zikkmylRWg@kyqB}*QT53w!)x$t7#sHdYNzcE3}LS`l=d=3P7 zV_L009sQad?*?Z7BcO?-g@0uc-)mbJbF<VI2P@*R?gOf}m~8&*`Z=iPmu8T4x2`ue z1=HV8Wr_YCHG1X0KTVzN$-ZzO9n6G@?_16Y2dI}HhVf}=X~95SBUGjQ8rglAQcM$v zCcU{~&tfZO0-G6cV?7l)Ii}o8iB_XU<`G*|TntsIrY|Rxe}jCO59K(p>#CWyzzdx{ z?e>ZumV)-X<9l4StPI@JF33lJ0wU54zVfQ-O{PXM-!^7Q-(4TuT13x$wR?tL{azQ? zvYjNOaJakXv4nXAmMa=2UOb6KLn8{L12Hi%s@H&GSOQM{=rNF-e}!gMKXv9LAf}ZM z5W9c>GA-Np-K>#sm}PeVrP5n(2?aselue?|JFh#QmeB;$r^qi~5`VJvwm;}pl(cAi zUlC*Z=FMehTYe%sUX@j09UYxhA+ES)c!oPdL-c612NkUHOr)-_Xcy6!uAFDBi#=Sd z+l%7V7qwaaim1UQ4X;falXKa-W6*v?yO>acLbq&9PBi}%nPv}jwcxjIJ8|SR`Qv@a zY8<;ifI)ae;1MH`5p9f(f4G~On#9Gh(BBP@i9x({-k`g`Po@8j90r|pzoxEnb%cr= z&^`3a5H@)YkiW>9ypX_9F|Q?ysG1qiv82i>I4oXW!Ku^QGO#lAQX`Z$2J(oPQ}}X5 zDzuc3F9!a;Zqg{`vD$nFyf>&$*Lf;(K@p)#e03N=9k=+gdZei9_0+=M=DFb$Rt^1L zC|&p7ah;dQ*$3o$q{ELN&n8@{c3g9nGLnMH+Q*X5LAR?MmS~)}=B<-nD}{#M|Hi?? z^QW(`;ZOG?8b#c=8+{haWq;Giq%l-Mq{Mnc$ZGIKLu>F8#mCZPI(jeKzN!)hva^7E zX;@)%QaHyBGO>xh(0Dwb%+9d)#f7(T7KL&nUYagUwp=g>O`WTX`B+-k5@F-&+Nh>{ z_3Kg3S-pBzHa0o|N8Zpr|EW4KERq;qBO^nfjlBBng2EMgHl+%|f!zxMwtu8iozTS) z?2}mB2JLhOB_$I@=39FbZE{d8_q991&{Ng=8@PL_0-n(1a$&JK^{=DIqaZ{~pml}B z2n1OP<9b_ADNBsHKRs-D+)7SxTYrb{{s*tHq`aklpX?yJrz3f;A5tPx%HIk;)W4)9 z3OfQ72a${+ufwGUde2R+TozHj#2Uc|`6f+4QCtuOKF_xPxVK7opoZUi*RsFJ#E$^W z&J61ESx}d+P;|A`_@&Fpzy5-X6s?8Iz|=HT-fOc|qhS26@BRzOt|MaF1fiWsM{Av_ zsiCbXlbJcjFw&I~l(hq<&6j<^#vT1<wS0pXRi%xn(FGB}WaKp}jEzpjb9zQu{AhYh z`DlAdf32K=n9k7=Dc?*&&w#v1O$~JxjCP5}fzD$&x?1SF<R3sVOf4>#UBMB?&d<L_ zL$SBtqep*obNk5k!quoau`YY-RhF8#Tz=lU>YR|k!2a$&QomPPY#)#?0(=U##L}B@ zX@rc91?N6#YY(-EYH=DG(yw|f<c?+ZfRXP7V`==y$he&1>!HCve{OZBG{IeuYi&vO zt~|8tOSN0zNl_TLd}d#CT~~EjVZ4EO{8i;;-a-poZZ-~CmZz1qB-B(3v$JMKMxo{} z(acYwV?*CCJ_*bRwrjNw4L7Kl`f~{5rLWRed5>4QO=}a{*=5QGwqBg(hkEh%H3WwP z>WKcsg^~9q@&_by)(dP%`jOv+<c2fzoFniE#M;56GO$z@gG=DYF0UXAU6FtN=qp)R zrFX;Z7A^(G|CyBXDYh9wPX7A6Ho~82O-UPe?2V&8G_;=6y@W9IZdrO?&!N<7e{AV` zz!x`_^_zBKcG!U$WV+<zEvd^+S-Di|Iy$>Oqx6v20Ph=Q=Fg+CN&6?@QiOoJasu;) z_4IUSTZ!pRp`@gw8)zRHmx&@>>W5J_sp)x6=oSYlp68C8SjKl}Fh+D^6&L7)Javx0 z56`bvKqGBtay1AUtgH;!P%#`XpcBxRAl43d|L)L3A~5BpZUXMj`QgA9*nc&5zppox zChX0Uz=V6rZfBo`(Dn1(Pz{!v*7Bqk4*YTa9`bO=+3&?r)TpaB*V}Hj%tkG6KELDH z{N^Y$4qUW#<oMAV2m6QLQ&WTJQ&z$G*e|U_MlO(9p9aVKjAGF*?w)_22-u8{R$KqH zu*geAWeBIBrcFsCaH|nlSNi=WYEIZ{R_452>?T~?m@(7;r=hI5{h|@8ODK(yp0xuX z)D)M!Tq=ALHA^oldEXPZ%R?I8BDWa1bgTak)(`%c!Y0Ynoco;IAU+uP@ngU>L)kRI zEt}DIT^cxZPLAM;oEh5Wf<@qy$6$jYU%-DemDa9HKt%K6)hj-W*^9hdDx;rY|Hmwr zQTo_trp#i;0=f8PLfpgiV5cNLF#8&e5}tN83%X#65+BBbk9-FP`R{f9qq)Y)@68YI ztRzg0{Qa*M06qin<DQ6tz4fty8ZQad97~m;3p@>{eG@^{`^T~Nt+WhyK0|m?Jjs6s z6vi1FjN#{oyctW9xsWm>UOf(_YZfuEKe3kbe0RMGr&nQ+K|$0CL)eH<vtr-=^{fSM zWs6}^R;Ncn6+PbPh4y8Mr54ET!Ge+r7v)h}G7w%pc#Mt*vvh%%Pl;F;x0~M<va7yk zdf|eje{gX54fkw~R!V1os?Zt*@>Tq^>mG0L(kGe{+_`LGA%sD(r=X~;ycbtu5L5Bu zVBNzH&VLtnSHxZ>x@YW7p7CH{NSQd<XMgDfxj9|7mTV=WT^WL%quJJtHEU}&Huk1a z8cb7p`?Mp##nRHV2bea`<mRXRy+KC@4{eEQ1);6cZxLl>WyY_{ElY5?E*9yLFbQ`z zAhG=D%R|rumR|dT>8(Bci>t#~8c$?x0ht69?|~^H6LBZIKT1rUF0R5M8DMC|uiG~? zHq`x@Sd`oyH$P7KJ8dnrpE%56VCq{8W*Ywwc{Tj0%lm;(V@mv;%66@XrG@OqN9m7` zqx*VwDoKhcJw9d4^hS0W?ZXc8bUVMc*Y~h(c=*|8xfs4kDs4+`515XA)BYA==s_E~ z(bWYrh++SPEOkSx=1K0F=m!fidG&s*4$7|RxpzJvZr;3+ggIH^Zf!84TYQt)CGK&k zh@eN<znSki$z4v%fBE?F<C66%=ukK!UKDU_Giy6`?9dW4^Z9TkEGS5U(aV6>P_NW! z!=UE)utIP&S$QK~(0*FMN_E(<{AD-0ngOCG%|Y6|7IeF`ryepH6mQtd<z+sE!gjdp zvzDO?ZfvMi$^Fa$8Paa(Z^N{oo(AVviM^kl)n+5&BpZa&^RVN;W5DEmxP;EAKHA?; z44?4aVj|j4<J48P!OhMPE5{3m$b=L-EdBj6IQVj~>$XPByO2uU_^PT2Gx%_bp!(1& zTN71ugXNCFK<TAUFmJ*BG<}t~9~Qo6tv5XPH&tIc>D~Fg9X8=50<b9&hoz~hsnBc^ zHG{b0?e}Pu73El#Tu>C~gS50)(5r<dKh;8gSB6vVfN+Yji4^R}*2JOPdS)7`=}%oy zkm!?`&D%NHkX+*Wr%y=J`FgU+^pBjJVBEo220R`c0nm8?w@<0u8xNhou~?zll<(i| zcNGk=`|auF<-*d8(%QoJ*;?xA#zxx|*D@<BMSJJ_8jCW3#ZXjO{46&p^j%7XN#E0x z5fx8)>00W*XtO@u=7DnoyYub3%xTPh<IdG-w6|ZTNUpD~rS6imRX{&$j_#4x+H9g1 z-<$2y$wc;U9-g^Za~3O&cP~_AkH4*S1m6^hwEiFVP8^>z>6xQ3yJQd8TV|cs-|zFI zDd;r`5gz~g6%nuAJidIBJ2dzA&Q%&)jznSk^H*0SUO)@ak;U+R%3qgylI84@h-T^0 zZS4;B_Udukt?0Z*oTjC0+s{bWWB9F~HB~HKBRvslU`mU=NiF_)Lk)*GO;`C*kFHz| zKe15R{AL#gbm#<HiN}d7q4!G(m09m#fYP-wS~k+tGgIY6UrU7|14v51@2Yp;7=A=T zm9RMRHxH3#b5<-MHkJm0F^bN~V^!4SDGGZQ3Vzo>(}FeP&`ptT{U0?PI+ZUNHvop{ z|Gmoc|C>2dn9FN+e+i@(_9uksDNwA?U4Lu!+?}VlUG!<=76(h;*S`eb@|59+6B@xc z)BSPx`smfJMGThiH=0YLr0W=fKOGlGW1*9npJ8^ijt_x(W7np2d<b<jH$r4-NT^I? zkIrg&g)!XhQdr4WR4(u;bab`*kuH@*k=gxpg7%~R{f&*~xt3!CV6HB<nsCFk9RNxf z$}aTvX_3{6%(^w^M}X*rY`xf+eq;~q=lQHH=CT}stPEbt+G|rFWPr@N>&P#SpF!8C zLqrR`D=Y$elFC{N4B;2mxkYV5SlEPjHw)BS{8spFMBprslQ_1F0scbHh!H3tmqRXA z$UIgPw>rL%ak+{bdGJ_;laQQ(63X`;o`S2}xLHY-6Cpfxhqtn@@N5qV=X#Z^PE$zV zs4yRuy*Xfp!s$c8%GQfT!ENexnLD4^pTItl`vHO}Yl7Wt*OS#i->vTt(#j=X9Qo;x zJ)hOXXPs4AI$NJ<cV14ew#IH27h)~nR1fFB{%sE7{!H^F>ADQM@}}eWcK`qb^t>7K z^#R#$e}Iau;!uIy3f;fQ#0M}pWo-|?qU|g7Pp1rLmZy1bdR2}~%Y@xZ%lv!b?1SP> zgi(Y?n6%u*?DLQ3TVm5c$A0>7HLJbe7%DO4n;K_SE)v`91`lXtM_zjLXOQpa-DZ*P z13+^;dAxy|=;%M}A%1OPX$eJ#>EBZqfc;V9>)TiP@%Y#q5R-F(E#I6NlVLd3M@dvc z9k8bwtMpi@VH`;+@9++$FM2~Nx`a{M`FDu?hikI{WXO<W424Ii0}WymMZH@8B<0(< zslPsn&S4BGCf#4NsGC;EO#89o(@$})b`Fs#e&PZ~>VQ~yt>kfDi%;|9AZp)AT~Tj9 zi54IW$ovwGILh^fY6Sxo8m{Bptm)Zw!j<P2bMAKLT9iOA!B<PCRXdQ%e{K$8hL#vt zscaSG*pE1#5Rf=OahcS#v4Lg0{95#<LmZ-izq{^mXFa!^K?$E`GuqLQLZ-GB$^Y7P zfz_0aSl`^-ye~>+&60}Tlt`EYyhbN}5RX3*TU5D0Xt(uL*J)?DyFt<rx9ZF8FXB&Z zeXN^U<g#;kRlDp5U|09|AmlW&mot(?U9t)>R_Jis-)^NZa<CuOi#;b-kMkV=1ju(n z;y++Ux}&25Gi5S*%@Nqxyf?vivTtDscWDG~(vkL+YY?K0Sp4&GF<WY~FWY`IvUJAR zkl&>2&JB_HBIS#T*`R8yZ%Fy*HCt~EO#RaQTdeYzPYNxpAuw(+)$Gf89BphUc<Ulh zbI^0V2LNvvDDa@>%)w2NCXaxctw2QWzw~XxBh<hz1U2WE;1%=b3vzXKD0={WY@#dk z^O&tbjX!@fE&CDZ9duD)k>uBy`zKYZbr;shyv{{YeLU{cp+^v}s_rl)wpFeU@S!gS z=sK;}{d`W^?SjTkIIWBMldT3$^t%FwhWPETy+&R7moH!6F0dY{qR%AyM%)UL^0g?H zP3GmLWrjmsk?p~so`r~K&ww+qHa~6kiiw_qg52G$BP<9W|F+J1G=hH%JalQ}yxcox zr{`9lJ5BsHF}uT63tU`5;buQh4Y6S7nCc_*M^^5}>gpWcuhWUv^3jL|u8u$LW7U?p zzQh=Pk@J&X)<e|<8}nai-OxlppWT6o3#ujzI4p9T9-w?ezWs~>FbX_iiilc`lE@_( zQ+%jcZ9jJitP~)u`1f!|3-IyY%h+9I<BpnYzO@uDY?t(fQDUj@h7ysZ9TkVdMBkr3 zNy9QFCY|pLwGh8vMWnEFOg5KTk3Cx(<Gs)OwZxgp@x6fAR<W4bCkqAj_Xg9k^i*KK zow}-jFrs7k;KB9_<TK9am{#A`0n#2YjjTlMnHE`&Jrl)8f0$;X5kc;D6{x+V-F&?? zc}2?acU~s<xIZWza#P3KWkCdCv67}&5LL@%Y^+>@?gwk4tK=2WOUy;aIjmf|3nxDN zk+%P;NO8Y(;lg2G^=@9ZZX#27n_(rH*xy|*TqYT*IRlX1Zg~o#(ATMN2n!7|THJD+ zAi6|7m`4>@KVUN|Yk#qd8a$a#^j0x_i5oT8bLZ97mppZfXv}Zrn^Zt8hvUkql**OQ z8)Sn9`vMx)l1fVJ+}ZtA(3xq7Q090$iyr8YQx2m|DmHeN?}zEygtG(LW1kHVOnZNv z8|;D$kE8hFL{RkN&Ulo9P`6Pj$Bx}Yi+CIRceI)3O~1Vus95Z=hlR4?AEV^n%+uXX z8&#=a-dlKIKj~gwT72wr*caC7rN6aw^dKbo3hsG{3odEKI7Y5BnBLsV>iwJf-T?#k zk=lTs1+;-Xu1|qz*O9eidgs(Ge(}enM|UOMPcBhPHochoWJuM1a=8ZpZi}6_!jcP* z4t41hH4lG_^yKd;SMOt?vh-_>`HIbFGl?Tx%Hc4<{f1bVtr{GCbP?EvE}49AS|Y#2 z+PLVaAdj*dSIlAhT_RI`GA*;cPNH0cHTqq-f%OyAT{EhGb#B`r-pkSIC-XQ|*gw(C z_54@Qm*2+yN6t@OoQf56SnrF9m+4pN-mBhV3_M)7;mWeJ^-RY1NyZcn7)V>83JPh& zjPK27D*;_x!5|3(Ps$*#!<&99omX{Xx#W1qQN7v3&Dqv&8(Uy$-`HCmu*EOLM1i2x zlqEO74eUZfE;CL7Mqct)>3f+}Jdg45huif_D=im@7B5>oN!_U2x%pa0SNHTW?$$yG zPy5nR^bo-V(taL#F^1!-yBj?+4wj^<Jlx9BT~$wR<$i3#?mrP#r_K)zHB&Q06kY2X z+}L&!Z#1kLHX1EkNW?Iy9}OdiCo^G=W?a22C&a*TNNgOIuF7XU?ZL9m^@$)bu3Fpx z&M_1UtuQr8`oO|9vo?2|$ZgZsPAZA3CNU90Sf#_EcivHO>y-xvt=86LTHs69GN{PO z3rjhWNEGw;gKJDfpOn_D*PbUSCnu!s{r!7fhbg0GCe}>3X2!<BwmyfvU%p`vpUkJF z0Vius%=V7B_@yMnGTL)@dxK4%dTFplUUu*yr1DM{U0qsVUSDQ-O^e{(gBnX=n=?$d z=WNhwWw6{Tx;n-tvVPoKu|w#cE7u*Y-gm*PBn1??$=O%>ZX(ni-0NcyjFLf1LpR9U z^0dE}pH_(F#f<L^p(f%ti`^!SdXY$y55zZA_)z%cHuwz+LdddT!!4NkwPB)^zyHYQ zaYTWdQ|-$=*&_!*TJ`Cxt5zR}c~qnJNaIM>yy$kz-H%J&K_~(l+wf6;Evcu$vZovC zu;Z#;+Rf?if!Q*?dzi4sE8h$F6<VcPH$C2r;T4%qmPBhy^`^N2Q*UqN3ncGm)GM^p ztzt-LakJK+%e~YVj~0%XCcdWs1Dr8gCRJS&3KmW0qW#2Ps|yX;4zdK(hGsKSap}uo z`uqBF%1Jf&;`rab{-?YfJi1wBh7l<05_$P1VG*Insh=EkbaS+8nAoW)*7T6Fz*1B- z!Hgsm{8tNLR`O33SD*ZNJ9^)FDzGvrf-x5xl({{jhC1_*y7XCC_PJ^I+1u(~*}49| z(t{sgyaAR3b92mBZ|`JG@?ie&lLn(jFPp(Plbe?+X~^#uXaX*!6ff}ed0#nDf8qrl zJez-2OOGusF9lv}K5Uus*==THTP{6cNoWvnGtH~RK3>YqDW<ks=Wk{8<0Cv<#rnjs zwAQH@v6iM4#=0p5mwJ_cRPpBt%&SJ~2x2<1GC&mRUA5J6FT#rxKz+HMG5WS)wCzV} z>Gv;n8J|J4PX4PdLcKCtdF<8>Rg)~s7;zo#Xm$nXpn7o%e%9j{E8Msz%8w|0dLW_7 zYqA*~S(C#V^~bhDF%ILMnHjK5Y1_U$_6<QN<Y)m8LzMsp#N`76&I-dy_q7Fz>>LhG zQ8B#+vFZAiZa&+ozZ08U9}=F9>;+Tvo!fdc%NXt%8XVa0$$-u#P_0NWr#*{6FPSMk zGTTcXKk9BZ)>Fz{`^L@Htn15ZqMg|qJ?1Hb;+m&>o`uuGsqeh%FFRu^dPkMx303*( zYnn2+1gxjkjsjU<q$sYKAy`5S&0hLTk#TZ<S41aO-q9W-U?)|9%A@DZ%1@t`6c&+3 zTy5FRpd<{G=1abUp(LBd$~2iOdC1Y|dhH(14eq-oG|HecIRXY;Y+TqyuZg7QlP<Tr zd?8f@`S)5|%J<Mx?~7Ztylpc8@E$2}T}lPoK{HJ}@AKccSQ;n-wAQptr3Lzex3dtV zpSUl*mG#_)Wy$KG8eeHjZ&s}QqrpGj)oFG6VPZF_GYt$Rv1;RL&sH{6R~=mF0Wec$ zw~^HL!|IjCUfaPF2((}IVzi*&c|Ylv7tTi`OyD*`6;JDz;O$+T=k>gFqpJX&;+JWC zZH%*^iQ*bHZq8{7Ss=X@-8dXF0^9(8^isFCb3~UI!TAOSIn@y^Rd=OrR1{0#fU>O; z>^?hA=G6*{aIIMmwLT-omh?n3ru5Yz2IYzScs?pCMwv?}LN){gyz^18+f0$>q3|tX zY*H@Ste_gWhdk~TBJZ^{EHIIb*?<2%#z`6wcZ4CiG8O#?=g+sOGGyb9EjNCrXi&*m zfZ3OrQgT$(W%ulGaN^R^y6fU%Rm=-IF{Jzz$<)AdMlO+yf&OJCooD9cp`0DEtSUPj zy-Bpi%%WC;*gtpsM)AMvE`*k*-5y`sSVTWqAfHi$-LmIyEk$o7PnG4w?d?ZUXF%vc zGMKbh5MkPo>>PZIA0A|j*G=uRma~T#C!!#i^MLf7n0{5(ib1KpM&*+~Fv`oo9P;ht zEZxhh?V}d+s0z}W?Y<`<fcQt7weI_p*?P1%wLV;~v1O>0M`c+TuF69|M4NEWu~a2H zzapGnE2p(N!}`UurwRs7;dUAES{YMrKr$~%ClUb3ExWkgx?;CexAIx#0kION3_iY? z*iKy#6_e-S&4p!pOM!p~1ypVI$VTEr1T^kUe<~d`w&B8&tmTL#O~3O{0UZL|>BbgK zkK$FwesTVD0MODEm#D$>69#Y@=*n2P(<ZQoo=Z#LnvJIGG&!ShHwjp}CIpH+yEy$h zJn3EWE~9fRNn~2p?qBZ&FR3h<^EXo$dHOu=kd8rDOl-+(ufXU6uO|{{ptn`=97J%} z5MLtX=HikckLL5Z{2I1e#I(J{TmKg^&;mLh?SK8)!wKYjagX>3Kg4gMcRQZ!5qd{E z5}2?<o`e~L!Xjev7?W4#@7R_sBNCbv+a4(@x!`&b=j3`lH`WBeNYrb?_?%N61@4sY z3VN^9ymUW`36~YVYbGvz$8}C=x36&<U`2@Jlx)^l@)V!xlJ01&9tH_Pd_d9mUb>Qt z>W^kkx9b{9OH0Pwu)&?E+OSo$8vW%7*ec$vnIl1m7Q%<W5FN+OZEfV-j>9Y5nV!E& zbl`l+q7=6>kgeO7wD6dZ)+LF^ucN+ce+bD~b7=DpBBoh0WC8tlfmsI<B|}~-9Ug)w zR@OPB6UYmiCpIZj%wkpcbIaG#JK^J!5HR9(t%d0Hb28f7#~POdpV0UZY;?HezuI`B z<ui_*B&?hf#3zvGW4V1>+gWl(o>*od3nk+K7e*GLn+#OuG{0tXC#ChsQ;d_+Sj6J@ zc}jW%ThmI%<-qrBA7P;5zv!!)fE^k1+GvBn$X>`kj_!R}>Aox#l|sQ_ro5*}Gs08n zV2c<!>@&2pJdf@YsY@Fd78HaJr?047?_g&oL2&dmCnuZ4(a?T2yqNWV;On=@97huj z1Qpe%$MoV>oP(%I9}j1m-)JGrV|zbew5>?by%$|>^qievoRmF_ZaJDLB^ubHmX_=@ z(F(=ASaG%~VVO4;(G}T0H&y!VXEplXEN(8pq@aM+oX=W~Is0OmzjP{1>biwM=zwp> zSHGB`eVgRUla}5gLyyB;%!oHsagdNwJg^+j_MR4B7o2QS_UOeQ_VFZ-PCr(WMSbQ@ z`ZAy-yM6B8cJUua?JN(kf_alq$F>HF@oZ#!;lA~!s-1a!WAr>j2xgqc5I|!NW&<~q zZakvZ`X%gOrL|*|E-Tw>du9D<{iK0c2<7M=y>RHt%!#X$05)oarH3SA2A=)=me0~} zPs)ac!JY76fvcgu(e&l3q$~8-yNW?EBer+&1^gyBP2XJy%2v2v3z$zy&3R7|M}BIj z_}Bk05J&&(B@#fUk_5`{e_FcL*=3o}vAnza_IH)kcd|$3+GVFy8d;R|%TJHNPx~Ie z+=bvU`G>t*PA|*MdH&sUkjdzZvgqDF1(FQqc@Skz+XZ#73Tumb#PkXC=AXE8^3lgX zFNdF9`spSEoPYmfelBhG*RL1;$>OW~K);48Gc-x7;NL49pf3+53y@XNrH=B1Ne-BW zfM9l(C-eJv^6*Q)11R=Bys$-(9GKncB7?H1fB%_*lTnwAbT%L$v&slw=Bz=tzJh|5 z?#-yLE#=S#OBzm=tm^(OD?XImC}3{)!;Jo`o0m;*dunNFPCGd&K@KR_w=CfFFWsK_ z@-0qFM<;MP4Tv)>YsN2=Km6MW`Wv>UFE7s(UPc}V=Y|#o9^Z4z?)vGs7{0xwuA^xH z(7}nX^4e;;Y~gJ8P!i<ez@wR7$|(I=@k383eik&r@R<f<QFt}o5m$L0>e6+iNPLRU zNiA$hi>Mvd)lOo&{25C&sTWu~v}PRwG?{9Kqu}Dfiqvn&_hCiywz8kmLtm!fqZLF; zJX0%>@8Q)Z1uq4!;x53K!%W%WN0W-#|4#}`K);1c67Rpc^ZzY?+Q}4q)E|vzwpSDs zUvq!_03aAFKK9_77=HHg;hpLC>WO}VzfX*$<)O+uC*w!`rR?-m+kH-UicgQ$DZ9}1 zZ<4L{f8HNpZ<9SLi_hiyTPaB#@J~k$F@E5xZ$ksnJt<!^!|n~TD7u<TbeE%n?8|C) zdHdd`pg7H<@jL}NL*YOBa?&%>;bq?*DH)tG{v=6^&%RD9CG^bgw5#=$-3Hkr@`TS8 z#xI+1Z(MB(bd%9gS0|^68h-xm)KV|2?u$xwQGIlmAwu#hbe!D6D5re+0vvI`Zv1;G zo;Us!A4<e<4S^bvgmr<TX3fO+7xMJYmPO^?6Oej2{o)^%nZ))@py|4lD4YV#j-+3* zu`le6@LrTL^_d*)>6@zBJiYVRW$3<r9i|54KDO)CXASkmf7?UHh#9VVUt?dt`nyZp z3p2@;4gH({6xwHKW|T&?{^vfk#UO)Euib8sN2$+F@2LL*um7KXz#CHI8IaV4<W_b^ znFq@qHesE8r}yta0E_8j*t-=eDR@HGn%rVyqS)|0eHXu*!>i~s#T~tYoPU;G^%1rS z$V?P;pL9!XymoeI=IUIwC~ZcnWt^{6?qL-mbVx;q-xNyURB`K{<?kj8vXkF`@P!c0 zDR3O@Q$#*TCf}2jjlopVq#WN%R`lU2^<U^hZaW6{lzxT%E*jmq4gDKXTd8|=WFjmo zdX~pyGx1$ZUk%P^9sEI14b3e209n78bgeP$+JYhRWt|cm9~7#+ej(n`)|SK+ip#N3 zfdXYR753}Aj;m&ndqp)uZkJZvy~w<W8Ej(@czK-<8csp|Wwza&P=;d(wH=?eSYp0@ z?d^Tt4W3A7=FZAV5nDP4$kNSq902>h<$$%I7gidi)gVewm@djGC@47OKv(rC*bSWV z^>YR1D;=TP5vc%u+}Io)NU;CVt>NL|_yP6VCQZSG#l?+3;r$hHTnA{(APm{TDm;Z^ zEx8-<M-z+DO&G7LuX_S-`nKSV%D1NGC_@jQ1R$$9F8y7C<jX0<<lck*`SuVmYci_m z`7gQ=H93^&xZxt8zQ{R1gAu{r#>7BJhvQ+9fQZxbosLS|scG<I5iL%14h}931#knn z?ZrHxh~z_V;CkO;4Uac|zOSzb&I?0r79aE7yDme4kwKK)H^i+TLKY-{Jr+^Z+0x>< z6A82d`ftJ>uQ{zhR2}WsoODzuD_{4UqvFtu1@>@9p83FYWP5^Th2t97qZXm2VBFcR zT*s|Tc`zTH*OT7)LKreyDPa;LUXvg9dx0Q;N*#W<hJS%5G&q=s&*Gfxd9bhs1P0dr zT)J^1Tl0ixVTAtUu*MO^B3qm5(O7<k)3;%`ksdMvesIt;R)kn0%T83xun{q<r0%7a z`&@W4^NjQ249Fgv`QeNo_SSliDmJ{1_fv>T<OvCbPP-YtvqwHArV%ZAy|a-uBIQ~Q z%!B5x47+s6xwhV-B8h<?wX&V@VxEWQ*qub`3_GuVbUNZ`!f@&n(>5<$)leOD`1~}b zU!Jpg8WIqoU*?_(F-=97q_ObxuMZf0F@cp$d~PQbRWvk0g5vx9UoBu{B?eI~gOeI< zs6CKCZ6nxiex~UgmfD){=eq&f$ja4KzE8%l)N6Y%pxWaoR@5O&`)3-|XS?ivgWcz! z%*;#x`?Y)S;X4WJr9PpAs}DGU>WYeOl?OqTTpyk8*zWx5>zg~J;2r**Yn|>FKiKwy z5W*8rozv2BQuDI_GZ+y;bOwiosAIR6dURvyZ&H3pF8um7=~XKwl&7<n>@5#5-WG?x zGE99y1Q;KrUWmEv>OpqDP^5Oz!)c&OR||Qzb!2#ml8Pcp&*Nw}ZgX=Jd?Nu8%>a)w z$SThT+Os2zlAEjREgJUpATTgJer#!B=cuG)uc+8bCsuy|vo!;Qc<<zA20gietO!g# zdT+|?iCJ2JB98omg52Tw@haCf30u5t0L+L!+2znv1lO0a{o=jDJ6{8a5AuzC!iO7t zM^KhQU;KN_Rt5`FGz9p-udQ2bW7(ILDqAaY29}q<SKw*O1)wV?GR{7si+K=ixNzZu zeuaaW>-KXPyF&8>oXRBtWPn1U?o$qQ!1+LkGx8x?gi*#*w{drESV&kXa0^g7`I=WK zwNkRP)7yT3-N#8S1b&N@e)ZHE&hC`6brU$R{gC2f$F+)hhzFkfgRI7206sOLby5J) z@Hmm;NmRDYDL=4u-gZWQ6O8#ahZrwN;D&)a3*t18iOm*#t4-EGNDgq^WTqBB07|u( zTS1e+j}yC{?^Fh!^Gj$D)c<)9nuN_YHu(kxsR15GXSgaRj)jQ@*j<Ott$v1JYhGzC zm|-n~9F~EqgSh?dVu5&-o95WX<tB<q3e-mP@842}h7(=Q`EaeHn*b2g-u~3t*}522 zAk_l+GO~pf{)Dez)sJ%P>KI2y^(NxPRwmz7QTOMRQPX*%|Gq+vO(jd!RC`cz8cffu z`DUM~a@`p%FrlIZ7-LW+Pe%v9AX<EVd=M^fS`yB*T6kZMD>EQ#UrJM8KXe&Ro&FE6 z0iugb_}n?*kfUBq87oFbMuM9>5u%hix~+&?J$Z%+ut@MCx@pY&Mn;|(8gk#c!wYP& zzL5RH!|BY~&!2T1-!C5j4T>P~dT@VsrWtPJ-k(|%b_*+Z5j)YtR%T{`uD#6(Q7r`Z zRFss}501n{bz5^)Z+baS6GEp}b!qAKt(+e@DoJ}gJDKH8kQ-hd@k+EaJy1Y^M-JsQ z;YmYKa8CkO`;lS<l^davk<$QT5NK`zef%S1WBN3K4=m?(Yp}(aPp+Q+MT-SZN%zAD zIXQDCymSvRvs!*vXm3!_Z_LddY$YE|U$g=sB!A9H1)F%+-DW@6Jy~9bgR*7$XnwQ< z5=qDF{QSsqO_Rg$Sx@!27s3&mf=lSCRL>5O6#=56Ctj?akQmi&=!qU`%~N!-=;~Ts zUA;8Zbbj99hsQt+f9}zAYaYI^qtsRLJG`?ah-%0DlDu*S_0fVJ8~r&ZM~<#6jaCD( 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 diff --git a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md index 34cb1ac..72118a4 100644 --- a/goodwe_controller/DECISIONS/UX-13-one-layout-table.md +++ b/goodwe_controller/DECISIONS/UX-13-one-layout-table.md @@ -93,8 +93,8 @@ What UX-02 made authoritative stays authoritative: existing `/action` values, not options, so the table places no key for them. The Batteries screen's Now, Today and Why lines are built in `homeview.py` from what the add-on knows this cycle; the plan per mode is - OPT-11 P3/P4, so until then Today says "Not planned yet" - (`test_batteries_screen.py`). + OPT-11 P3/P4, so until then Today says "Not planned yet" when no block + is planned for the battery (`test_batteries_screen.py`). ## 4. What this costs diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 34318e9..7bc4033 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3263,9 +3263,10 @@ battery. An Off battery that the peak limit still needs says so, with the power it gives: "Off, but gives 0.5 kW for the peak limit." -**Settings** opens on the **Simple** view: the peak limit, the batteries' -switches and modes, and shadow mode, each marked "Applies right away" or -"Applies after a restart". **Installer** shows every setting. +**Settings** opens on the **Simple** view, or on the view you last picked: +the peak limit, the batteries' switches and modes, and shadow mode, each +marked "Applies right away" or "Applies after a restart". **Installer** shows +every setting. ### Setup, for a new install diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 90d1943..efee29d 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -380,9 +380,10 @@ def _cycle_hours(phase, soc, cap_kwh, cfg): def peak_run(c, day0, day1, now, shadow, limit_w): """While the batteries hold the grid under the peak limit, one block for - the current 15-minute period on every battery.""" + the current 15-minute period on every battery. An Off battery gets it + only while it gives power (OPT-11: Off covers only the shortfall).""" pg = c.peak_guard - if pg is None or not pg.engaged: + if not peak_engaged(c): return [] start = now - timedelta(minutes=now.minute % 15, seconds=now.second, microseconds=now.microsecond) @@ -390,7 +391,8 @@ def peak_run(c, day0, day1, now, shadow, limit_w): return [_run(i, "peak", start, end, day0, day1, run_peak_what(pg.ceiling_w or limit_w, shadow), run_peak_why(), None) - for i in range(len(c.inverters))] + for i, inv in enumerate(c.inverters) + if not _off(c, inv) or flow(inv.batt) == "giving"] def house_runs(n, day0, day1, now, shadow, skip=()): @@ -526,9 +528,11 @@ def refusing(c, inv) -> int: def peak_engaged(c) -> bool: - """The peak guard is asking the batteries for power this cycle.""" + """The peak guard asks the batteries for power this cycle. Not when it is + blind or floor-limited: those are engaged with a 0 W floor (no charging + only), so no battery gives power for it.""" pg = getattr(c, "peak_guard", None) - return bool(pg is not None and pg.engaged) + return bool(pg is not None and pg.engaged and (pg.floor_w or 0.0) > 0.0) def battery_rows(c, shadow, running, held=False): @@ -559,7 +563,6 @@ def battery_rows(c, shadow, running, held=False): reading=inv.soc is not None and inv.batt is not None, phase=phase, shadow=shadow, running=running, held=held, refused=refusing(c, inv), peak=peak, - moving=flow(inv.batt) in ("giving", "charging"), giving=flow(inv.batt) == "giving", other_refuses=other, sf_ahead=sf_ahead) rows.append({ @@ -592,7 +595,7 @@ def battery_rows(c, shadow, running, held=False): def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, - held, refused, peak, moving, sf_ahead, giving=False, + held, refused, peak, sf_ahead, giving=False, other_refuses=None) -> str: """The key of one battery's "why" line (`home_words.why`), most urgent first. Pure, so every branch is tested without a controller.""" @@ -608,7 +611,7 @@ def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, return "cycle_mode" if modes_on else "cycle" if off: # Off gives way to the peak limit only (OPT-11 design section 2). - return "off_peak" if peak and moving else "off" + return "off_peak" if peak and giving else "off" if refused: return "refuses_give" if refused > 0 else "refuses_charge" if peak: diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index 3503133..b80dc7c 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -473,9 +473,11 @@ window.UX13.batteries(batts); fillNotes(); } - function setMode(v, redraw) { + // `remember`: only the person's own pick of a view is kept for next time; + // a jump to Installer (a link, a setting to fix) is not. + function setMode(v, redraw, remember) { mode = v; - try { localStorage.setItem("ux13.settings.view", v); } catch (e) { /* no storage */ } + if (remember) try { localStorage.setItem("ux13.settings.view", v); } catch (e) { /* no storage */ } document.querySelectorAll("#set-view [role=radio]").forEach((b) => { const on = b.dataset.v === v; b.setAttribute("aria-checked", String(on)); b.tabIndex = on ? 0 : -1; @@ -486,13 +488,13 @@ if (redraw && M && view === "settings") render(); } document.querySelectorAll("#set-view [role=radio]").forEach((b, i, all) => { - b.addEventListener("click", () => setMode(b.dataset.v, true)); + b.addEventListener("click", () => setMode(b.dataset.v, true, true)); b.addEventListener("keydown", (e) => { const d = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[e.key]; if (!d) return; e.preventDefault(); const j = all[(i + d + all.length) % all.length]; - setMode(j.dataset.v, true); j.focus(); + setMode(j.dataset.v, true, true); j.focus(); }); }); setMode(mode, false); diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 61b9fbf..13777c9 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -320,7 +320,7 @@ "off_peak": "The peak limit comes before Off. It rests again after.", "refuses_give": "The battery refuses to give power. The add-on tries again every 15 minutes.", "refuses_charge": "The battery refuses to charge. The add-on tries again every 15 minutes.", - "peak": "The peak limit needs power, so every battery gives.", + "peak": "The peak limit needs power from the batteries.", "modes_off": "Battery modes are off, so it follows the house.", "solar_first": "Solar first: it gets spare solar before the others.", "leftover": "It gets the solar that Solar first batteries cannot take.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 0a0c2d1..956cff9 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -259,10 +259,10 @@ "cycle": "De maandelijkse cyclus houdt de meting van het laadniveau juist.", "cycle_mode": "De maandelijkse cyclus gaat voor. Daarna volgt ze weer haar modus.", "off": "U hebt haar uitgezet.", - "off_peak": "De piekgrens gaat voor Uit. Daarna rust ze weer.", + "off_peak": "De piekgrens gaat voor op Uit. Daarna rust ze weer.", "refuses_give": "De batterij weigert te leveren. De add-on probeert het elke 15 minuten opnieuw.", "refuses_charge": "De batterij weigert te laden. De add-on probeert het elke 15 minuten opnieuw.", - "peak": "De piekgrens vraagt vermogen, dus elke batterij levert.", + "peak": "De piekgrens vraagt vermogen van de batterijen.", "modes_off": "Batterijmodi staan uit, dus ze volgt het huis.", "solar_first": "Eerst zonne-energie: ze krijgt het overschot vóór de andere.", "leftover": "Ze krijgt de zonne-energie die de batterijen met Eerst zonne-energie niet opnemen.", diff --git a/goodwe_controller/test_batteries_screen.py b/goodwe_controller/test_batteries_screen.py index a2f2347..4ddc917 100644 --- a/goodwe_controller/test_batteries_screen.py +++ b/goodwe_controller/test_batteries_screen.py @@ -27,6 +27,7 @@ import os import re import socket import sys +from datetime import datetime, timedelta, timezone HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(HERE, "tools")) @@ -54,13 +55,35 @@ def words(lang): EN, NL = words("en"), words("nl") +B_NAME = D.OPTS["inverters"][1]["name"] LANGS = {"en": EN, "nl": NL} -def build(state, lang="en", c=None): +# The fixture's prices are for the day it is built, so the plan depends on +# the hour. Pin the clock (review of #150: unpinned, this file failed every +# morning): the fixture is built at 00:15 on 2026-09-28, Brussels time. Part 1 +# looks at 23:30, when the day's trades and cycle start are past, and part 3 +# at 00:30, with all of them ahead. +_BUILT = datetime(2026, 9, 27, 22, 15, tzinfo=timezone.utc) + + +class _Clock(datetime): + @classmethod + def now(cls, tz=None): + return _BUILT.astimezone(tz) if tz else _BUILT.replace(tzinfo=None) + + +D.datetime = _Clock +_DAY0 = homeview.local_day(_BUILT)[0] +EVENING = _DAY0 + timedelta(hours=23, minutes=30) +MORNING = _DAY0 + timedelta(minutes=30) + + +def build(state, lang="en", c=None, now=None): c = c or D.controller(state) s = c.status_payload() - return homeview.build(c, level=s["level"], checks=s["checks"], lang=lang) + return homeview.build(c, level=s["level"], checks=s["checks"], lang=lang, + now=now or EVENING) # The six states and what each battery's Why line must be. @@ -188,16 +211,60 @@ _kinds = {i: {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == i} print(f" {_kinds}") check("Off: no 'follows the house', no trade, no monthly cycle for B", not _kinds[1] and "house" in _kinds[0]) +_p = build("off", now=MORNING) +_m = build("modes", now=MORNING) +_kinds = {i: {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == i} + for i in (0, 1)} +print(f" morning: {_kinds}, lines {_p['plan']['lines']}") +check("in the morning, with trades and a cycle ahead: A has them, Off B has " + "no block and waits for no cycle (with B on, it does)", + {"house", "grid", "give", "cycle"} <= _kinds[0] and not _kinds[1] + and not any(B_NAME in x for x in _p["plan"]["lines"]) + and {"grid", "give"} <= {r["kind"] for r in _m["plan"]["runs"] + if r["battery"] == 1} + and any(B_NAME in x for x in _m["plan"]["lines"])) _p = build("off_peak") check("...but the peak block stays on it while the peak limit needs it", {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == 1} == {"peak"}) +# Review: an Off battery that A covers alone rests, so it gets no peak block, +# and a card never says "every battery gives" beside it. +_c = D.controller("off_peak") +_c.inverters[1].batt = 0.0 +_p = build("off_peak", c=_c) +_a, _b = _p["batteries"] +check("peak limit covered by A alone: Off B rests, has no peak block, and " + "A's Why does not claim every battery gives", + _b["why_key"] == "off" and _b["now"] == EN["home_words"]["now"] + ["off_resting"] and not _b["today"] + and {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == 0} + >= {"peak"} and _a["why_key"] == "peak" + and "every" not in _a["why"] and "elke" not in + build("off_peak", "nl", c=_c)["batteries"][0]["why"]) +# Review: a blind or floor-limited guard is engaged with a 0 W floor. It +# forbids charging only, so no battery gives power for it. +_bad = [] +for _kw in (dict(blind="meter gap"), dict(floor_limited=True)): + _c = D.controller("off_peak") + _c.peak_guard = homeview.peakguard.PeakDecision( + engaged=True, floor_w=0.0, ceiling_w=3500.0, ceiling_from="cap", + projected_w=None, **_kw) + _c.inverters[1].batt = 300.0 # B still going to 0 W + _p = build("off_peak", c=_c) + _a, _b = _p["batteries"] + if (_a["why_key"] == "peak" or _b["why_key"] == "off_peak" + or "peak limit" in _b["now"] + or any(r["kind"] == "peak" for r in _p["plan"]["runs"])): + _bad.append((_kw, _a["why_key"], _b["why_key"], _b["now"])) +print(f" {_bad}") +check("a blind or floor-limited peak guard (floor 0 W) draws no peak block " + "and no line says the peak limit takes power", not _bad) # ============================================================================ # print("\n4. battery_why(): pure, most urgent first") BASE = dict(modes_on=True, mode=packmode.SOLAR_FIRST, off=False, reading=True, phase=IDLE, shadow=False, running=True, held=False, refused=0, - peak=False, moving=False, sf_ahead=False) + peak=False, giving=False, sf_ahead=False) def why(**kw): @@ -211,9 +278,9 @@ _cases = [ (dict(shadow=True, phase=DRAIN), "shadow"), (dict(phase=DRAIN, off=True), "cycle_mode"), (dict(phase=DRAIN, modes_on=False), "cycle"), - (dict(off=True, peak=True, moving=True), "off_peak"), - (dict(off=True, peak=True, moving=False), "off"), - (dict(off=True, moving=True), "off"), + (dict(off=True, peak=True, giving=True), "off_peak"), + (dict(off=True, peak=True, giving=False), "off"), # charging or resting + (dict(off=True, giving=True), "off"), (dict(refused=1, peak=True), "refuses_give"), (dict(refused=-1), "refuses_charge"), (dict(peak=True, giving=True, other_refuses="B"), "peak"), diff --git a/goodwe_controller/tools/ux13_browser_check.py b/goodwe_controller/tools/ux13_browser_check.py index 56d80ef..ad5df4a 100644 --- a/goodwe_controller/tools/ux13_browser_check.py +++ b/goodwe_controller/tools/ux13_browser_check.py @@ -135,6 +135,54 @@ def actions(browser): ctx.close() +def switching(browser): + # Review: an unsaved change survives the view switch both ways, the + # Installer's locked values still need "Change", and only the person's + # own pick of a view is remembered. + ctx, page, errors = open_page(browser, "modes", "#settings", + size="desktop", scheme="light", lang="en-GB") + chips = [c.locator(".chip").first.inner_text() + for c in page.locator("#simple > .card").all()] + check(f"Simple's badges: the peak limit and shadow mode need a restart, " + f"the batteries apply at once ({chips})", + chips == ["Applies after a restart", "Applies right away", + "Applies after a restart"]) + num = page.locator("#simple .card input.num").first + num.fill("4.2") + num.dispatch_event("change") + page.wait_for_timeout(600) + n1 = page.locator("#sb-text").inner_text() + page.locator("#set-view [data-v=installer]").click() + page.wait_for_timeout(600) + val = page.locator("#groups [data-key=peak_cap_w] input.num").input_value() + n2 = page.locator("#sb-text").inner_text() + locked = (page.locator("#groups [data-key=peak_soc_floor] input").count(), + page.locator("#groups [data-key=peak_soc_floor] button.link") + .count()) + page.locator("#set-view [data-v=simple]").click() + page.wait_for_timeout(600) + back = page.locator("#simple .card input.num").first.input_value() + n3 = page.locator("#sb-text").inner_text() + check("an unsaved peak limit survives Simple -> Installer -> Simple, and " + "the save bar counts it once", n1.startswith("1 ") and n2 == n1 + and n3 == n1 and val == "4.2" and back == "4.2" + and page.locator("#savebar").is_visible()) + check("...the Installer's locked value has no input until 'Change'", + locked == (0, 1)) + ctx.close() + ctx, page, errors = open_page(browser, "running", "#batteries", + size="desktop", scheme="light", lang="en-GB") + page.locator("#batt-off a").click() + page.wait_for_timeout(800) + page.reload() + page.wait_for_load_state("networkidle") + page.wait_for_timeout(1200) + check("a jump to Installer from a link is not remembered: Settings " + "opens on Simple again", page.locator("#simple").is_visible() + and page.locator("#groups").is_hidden() and not errors) + ctx.close() + + def modes_off(browser): ctx, page, errors = open_page(browser, "running", "#batteries", size="phone", scheme="light", lang="en-GB") @@ -172,6 +220,7 @@ def main(): sweep(b) actions(b) month_peak(b) + switching(b) modes_off(b) b.close() if FAILS: -- 2.54.0 From e5a0ba23d724533bdc3a7e85585f46b952d48cc1 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Mon, 28 Sep 2026 23:37:55 +0200 Subject: [PATCH 072/105] SAFETY-79: CI fixes - MUTATION.md pointer, no key-taking helper, fixture sized on the aim test_peakguard's over-limit fixture now sizes its load against cap - margin, so the floor it asks for is exact wherever in the quarter the suite runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV --- goodwe_controller/test_peak_margin.py | 12 ++++-------- goodwe_controller/test_peakguard.py | 4 +++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py index f333846..2416be5 100644 --- a/goodwe_controller/test_peak_margin.py +++ b/goodwe_controller/test_peak_margin.py @@ -11,6 +11,8 @@ has the record. Drives the REAL Controller through tools/safety79_identity.py. 3. The bill and the reports still use the real cap. 4. Each call site in main.py passes the value its side needs. 5. The setting: default, range, refusals in plain words. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. """ import ast @@ -219,14 +221,8 @@ check("test_aim_w: `peak_aim_w()` is cap - margin, and the forecast sizing " print("\n5. the setting") -def _cfg_pair(key): - """(default, schema) lines for `key` at two spaces in config.yaml.""" - with open(os.path.join(HERE, "config.yaml"), encoding="utf-8") as f: - hits = re.findall(rf"^ {key}:\s*(\S+)", f.read(), re.M) - return hits - - -_hits = _cfg_pair("peak_margin_w") +with open(os.path.join(HERE, "config.yaml"), encoding="utf-8") as f: + _hits = re.findall(r"^ peak_margin_w:\s*(\S+)", f.read(), re.M) print(f" config.yaml: {_hits}") check("config.yaml ships 50, int(0,500), and the in-code mirror matches", _hits == ["50", "int(0,500)"] diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 4e653b3..909ccfe 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1175,7 +1175,9 @@ def wired_over_limit(db, want_floor_w, opts=None, store=None, batt_w=0.0, int(now.timestamp() // QUARTER_S) * QUARTER_S, timezone.utc) span = int((now - blk).total_seconds()) remaining = max(1.0, QUARTER_S - (now - blk).total_seconds()) - net_w = CAP_W + want_floor_w * remaining / QUARTER_S + # SAFETY-79: sized against what the guard aims at, cap - margin. + net_w = (CAP_W - ctl.peak_margin_w + + want_floor_w * remaining / QUARTER_S) for i in range(0, span + 1, 5): ctl.p1.submit(sample(blk + timedelta(seconds=i), net_w)) # ⚠️ AND ONE TELEGRAM AT `now` ITSELF. The averager credits a sample's -- 2.54.0 From c664e38ef44619893eff568d507c17d297751f46 Mon Sep 17 00:00:00 2001 From: goodwe-review <gschrooyen@gmail.com> Date: Mon, 28 Sep 2026 23:58:34 +0200 Subject: [PATCH 073/105] OPT-11 P2 review: refusals stay counted, removals survive a start with no broker - A refusal past the log-once set or the 32 cap is counted in the log at 1, 10, 100 and so on, so a repeated attack stays visible. - The logged topic is printable only (no forged log lines). - mode_announcement(): the start-up store logic, now tested with a real Store. A removed config topic stays stored, so a start with no broker cannot forget it (rename case tested). - A test ties each HA mode option to the page's English name. - packmode.enabled() is tested for "true", 1 and "false". - Retained-command text, DOCS and DECISIONS updated to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 6 +- goodwe_controller/DOCS.md | 2 +- goodwe_controller/app/main.py | 45 ++++++--- goodwe_controller/app/messages.py | 2 +- goodwe_controller/app/mqtt.py | 14 ++- goodwe_controller/test_messages.py | 1 + goodwe_controller/test_mqtt.py | 95 ++++++++++++++++++- 7 files changed, 141 insertions(+), 24 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 39f02b2..3ded348 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -23,6 +23,10 @@ P1 is its section 6 P1, and the pull request lists what was measured. and a replay after a restart could otherwise undo a newer one. The config topics announced are kept in the store (`mqtt_mode_configs`), so turning modes off removes exactly those, and an install that never turned them on - publishes what ed739d4 did (`test_mqtt.py` part 10). + publishes what ed739d4 did (`test_mqtt.py` part 10). A removed topic stays + in that list and its empty config is re-sent on each start, so a start with + no broker cannot lose it; re-sending is harmless. The HA options are the + page's English names, pinned by a test, and are not renamed with the page: + automations send them. - In P1 only Off closes a direction; Leftover solar differs by charging last. Price runs, selling (`pack_sell`, reserved) and the forecast are P3/P4. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 059fdde..bfe7b20 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -524,7 +524,7 @@ The peak limit, the safety stops and the monthly cycle always come before a batt **In Home Assistant.** With MQTT set up, each battery also gets a *Mode* list and a *Use* switch, for example `select.goodwe_inverter_a_mode` and `switch.goodwe_inverter_a_use`. They do the same as the Batteries screen. Turn battery modes off and restart, and they are removed. -*For installers:* commands arrive on `goodwe_ctl/unit/<battery>/mode/set` (a *Mode* option, such as `Solar first`) and `.../use/set` (`ON` or `OFF`). They go through the same checks as the Batteries screen, and a refusal is logged once. A retained command is never applied, so the broker cannot replay an old choice after a restart; the add-on keeps the last choice itself. +*For installers:* commands arrive on `goodwe_ctl/unit/<battery>/mode/set` (a *Mode* option, such as `Solar first`) and `.../use/set` (`ON` or `OFF`). They go through the same checks as the Batteries screen. A refusal is logged once, and later refusals are counted in the log. A retained command is never applied, so the broker cannot replay an old choice after a restart; the add-on keeps the last choice itself. *For installers:* a mode is a limit at priority 35, kept apart from the hard limits. It gives way only as far as a limit above it (the peak guard) needs. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index b700dd5..fb44d97 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -73,9 +73,8 @@ from .maintenance import ( arbitrate as maint_arbitrate, ) from .mqtt import (MODE_CONFIGS_KEY, MODE_LABELS, USE_OFF, USE_ON, - MqttPublisher, announced_units, mode_payloads, - mode_retractions, optional_keys, parse_command, unit_slugs, - unit_state_key) + MqttPublisher, announced_units, mode_configs, + optional_keys, parse_command, unit_slugs, unit_state_key) from . import peakguard from . import packshare from . import pv as pv_read @@ -908,6 +907,7 @@ class Controller: self._mode_faults = set() # OPT-11 P2: (topic, reason) of MQTT commands refused and logged once. self._mqtt_refused = set() + self._mqtt_refused_more = 0 # [(pack name, why)] for packs that are due and waiting their turn. # Empty at a roster of one, where nothing can defer anything. self._maint_deferred = [] @@ -2079,7 +2079,8 @@ class Controller: checks and the store write are the same. A retained command (one the broker replays on subscribe, e.g. after a restart) is never applied: the store already holds the last choice. A refusal is logged once per - topic and reason. Never raises: MQTT must not reach control. + topic and reason, at most 32, and further refusals are counted in the + log at 1, 10, 100 and so on. Never raises: MQTT must not reach control. """ try: slug, action, value, why = parse_command( @@ -2095,11 +2096,19 @@ class Controller: why = result["error"] else: why = messages.pack_refused(why) - topic_s = str(topic)[:128] + # Printable only: a topic is sender-chosen, so no log injection. + topic_s = "".join(c if c.isprintable() else "?" + for c in str(topic)[:128]) _LOG.debug("Home Assistant command %s %s refused: %s", topic_s, repr(payload)[:48], why) if (topic_s, why) in self._mqtt_refused \ or len(self._mqtt_refused) >= 32: + # Not logged again, but counted: 1, 10, 100... stay visible. + self._mqtt_refused_more += 1 + more = self._mqtt_refused_more + if str(more).rstrip("0") == "1": + _LOG.warning("Home Assistant commands still ignored: %d " + "more so far.", more) return self._mqtt_refused.add((topic_s, why)) _LOG.warning("Home Assistant command on %s ignored: %s", topic_s, @@ -6115,6 +6124,21 @@ class ControlTaskDied(RuntimeError): """The control task ended while nothing had asked it to stop.""" +def mode_announcement(opts, store) -> tuple: + """OPT-11 P2: `(modes, retract)` for the MQTT publisher at start-up. + + The config topics announced are kept in the store, so turning modes off + removes exactly those (`mqtt.mode_configs()`). An install that never + turned modes on gets nothing, and its store is not written. + """ + modes = packmode.MODES if packmode.enabled(opts) else () + stored = store.data.get(MODE_CONFIGS_KEY) + keep, retract = mode_configs(roster_names(opts), modes, stored) + if keep and keep != stored: + store.set(MODE_CONFIGS_KEY, keep) + return modes, retract + + def control_task_done(task: asyncio.Task, *, controller, stop: asyncio.Event, died: list) -> None: """Done-callback on the control task: log its death now and wake amain() @@ -6246,15 +6270,8 @@ async def amain() -> None: broker = None try: # OPT-11 P2: each battery's switch and mode list, only while - # battery modes are on. The config topics are kept in the store, - # so turning modes off removes exactly the ones announced. - _modes = packmode.MODES if packmode.enabled(opts) else () - _mode_cfgs = [t for t, _ in mode_payloads(roster_names(opts), - _modes)] - _retract = mode_retractions(store.data.get(MODE_CONFIGS_KEY), - _mode_cfgs) - if _modes: - store.set(MODE_CONFIGS_KEY, _mode_cfgs) + # battery modes are on (`mode_announcement()`). + _modes, _retract = mode_announcement(opts, store) broker = await hass.mqtt_service() pub = MqttPublisher( broker.get("host") if broker else None, diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index e9dfac1..6fea64e 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -933,7 +933,7 @@ PACK_REFUSED = { "unit": "There is no battery with that name.", "value": "That choice is not possible for this battery.", # OPT-11 P2: a Home Assistant command dropped before it reaches a battery. - "retained": "A saved command is not used after a restart.", + "retained": "An old saved command is not used.", "size": "That command is too long.", "encoding": "That command is not plain text.", "topic": "That is not a battery command.", diff --git a/goodwe_controller/app/mqtt.py b/goodwe_controller/app/mqtt.py index 91da048..b7716d6 100644 --- a/goodwe_controller/app/mqtt.py +++ b/goodwe_controller/app/mqtt.py @@ -515,8 +515,18 @@ def mode_retractions(stored, current) -> list: if not isinstance(stored, list): return [] keep = set(current) - return [t for t in stored if isinstance(t, str) - and _MODE_CONFIG_RE.fullmatch(t) and t not in keep] + return list(dict.fromkeys(t for t in stored if isinstance(t, str) + and _MODE_CONFIG_RE.fullmatch(t) + and t not in keep)) + + +def mode_configs(units, modes, stored) -> tuple: + """`(keep, retract)` at start-up: the mode config topics to store, and the + ones to remove now. A removal stays in `keep`, so a start with no broker + does not forget it; resending an empty config is harmless.""" + current = [t for t, _ in mode_payloads(units, modes)] + retract = mode_retractions(stored, current) + return current + retract, retract def parse_command(topic, payload, retained, modes): diff --git a/goodwe_controller/test_messages.py b/goodwe_controller/test_messages.py index 0e29a8d..2a48012 100644 --- a/goodwe_controller/test_messages.py +++ b/goodwe_controller/test_messages.py @@ -846,6 +846,7 @@ DATA = { "main.py:EXIT_CONTROL_DIED", "main.py:first.name", "main.py:OPTIONS_PATH", "main.py:err", "main.py:', '.join(sorted(stranded))", "main.py:sorted(on_roster)", "main.py:inv.name", "main.py:topic_s", + "main.py:more", "main.py:inv.batt_fresh.bound.release_s", "main.py:inv.batt_fresh.bound.move_w", "main.py:inv.batt_fresh.bound.unchanged_s", "main.py:inv.batt_fresh.held", "main.py:value", "main.py:float(value)", diff --git a/goodwe_controller/test_mqtt.py b/goodwe_controller/test_mqtt.py index bf5f4fd..29dc4f4 100644 --- a/goodwe_controller/test_mqtt.py +++ b/goodwe_controller/test_mqtt.py @@ -1053,6 +1053,15 @@ check("every mode has a plain label, in MODES order, and a later mode only " and len(set(mqtt.MODE_LABELS.values())) == len(mqtt.MODE_LABELS) and json.loads(MODE_N1[0][1])["options"] == [mqtt.MODE_LABELS[k] for k in MODES]) +# Review of #152: the HA options are what automations send, so they are kept +# apart from the page's words on purpose. They start equal; if the page's +# English changes, this goes red and the author decides: keep the HA option +# (and change this pin) or rename it (a breaking change, in DECISIONS). +_en = json.loads((HERE / "app" / "ui_text" / "en.json").read_text()) +check("each HA mode option is the page's English name for that mode, in " + "both places the page names it", + all(mqtt.MODE_LABELS[k] == _en["home_words"]["modes"][k] + == _en["home"]["batteries"]["choice"][k]["name"] for k in MODES)) _later = dict(mqtt.MODE_LABELS, cheap_hours="Cheap hours only") _orig = mqtt.MODE_LABELS mqtt.MODE_LABELS = _later @@ -1094,6 +1103,59 @@ check("...and nothing from the store is removed that is not one of our mode " == ["homeassistant/select/goodwe_ctl_unit_a_mode/config"]) +_on1 = [t for t, _ in mqtt.mode_payloads(["inverter-a"], MODES)] +_k, _r = mqtt.mode_configs(["inverter-a"], MODES, _cur2) +check("start-up (`mode_configs`): a battery that left is removed, and stays " + "in the store, so a start with no broker does not forget it", + _r == _cur2[2:] and _k == _on1 + _cur2[2:]) +_k, _r = mqtt.mode_configs(NAMES2, (), _cur2 + _cur2[:1]) +check("...modes turned off: all four are removed, once each, and kept", + _r == _cur2 and _k == _cur2) +check("...never turned on: nothing to store and nothing to remove, so the " + "store is not written", + mqtt.mode_configs(NAMES2, (), None) == ([], [])) +_k, _r = mqtt.mode_configs(NAMES2, MODES, _cur2) +check("...turned on again: nothing removed, and the list does not grow", + _r == [] and _k == _cur2) + + +from app.main import mode_announcement # noqa: E402 +_st = Store(os.path.join(tempfile.mkdtemp(), "ann.json")) +_OPTS1M = dict(OPTS2, battery_modes_enabled=True, + inverters=OPTS2["inverters"][:1]) +_seen = [mode_announcement(dict(OPTS2), _st), + dict(_st.data)] +_seen += [mode_announcement(dict(OPTS2, battery_modes_enabled=True), _st), + list(_st.data.get(mqtt.MODE_CONFIGS_KEY) or [])] +_seen += [mode_announcement(_OPTS1M, _st), + list(_st.data.get(mqtt.MODE_CONFIGS_KEY) or [])] +_seen += [mode_announcement(dict(OPTS2, battery_modes_enabled=False), _st), + list(_st.data.get(mqtt.MODE_CONFIGS_KEY) or [])] +check("main's start-up, through a real Store: never on announces and stores " + "nothing; on stores the four; a roster of one removes B's two and keeps " + "them; off removes all four and the store keeps them", + _seen[0] == ((), []) and mqtt.MODE_CONFIGS_KEY not in _seen[1] + and _seen[2] == (MODES, []) and _seen[3] == _cur2 + and _seen[4] == (MODES, _cur2[2:]) and sorted(_seen[5]) == sorted(_cur2) + and _seen[6] == ((), _seen[5]) + and sorted(_seen[7]) == sorted(_cur2)) +_st = Store(os.path.join(tempfile.mkdtemp(), "ren.json")) +mode_announcement(dict(OPTS2, battery_modes_enabled=True), _st) +_ren = dict(OPTS2, battery_modes_enabled=True, inverters=[ + OPTS2["inverters"][0], dict(OPTS2["inverters"][1], name="inverter-c")]) +_r = mode_announcement(_ren, _st)[1] +_kept = list(_st.data.get(mqtt.MODE_CONFIGS_KEY) or []) +check("...B renamed C while on: B's two are removed and stay stored beside " + "A's and C's, so a start with no broker does not forget them", + _r == _cur2[2:] and _kept[-2:] == _cur2[2:] and len(_kept) == 6 + and mode_announcement(_ren, _st)[1] == _cur2[2:]) +check("battery modes are on only for exactly `true`: not \"true\", 1 or " + "\"false\"", + [packmode.enabled({"battery_modes_enabled": v}) + for v in (True, "true", 1, "false", None)] + == [True, False, False, False, False]) + + # --- 10d. state topics, from the store ---------------------------------------- _tmp = tempfile.mkdtemp() OPTS2M = dict(OPTS2, battery_modes_enabled=True) @@ -1237,8 +1299,30 @@ _logs.rows.clear() _flood, _ = ctl_for(OPTS2M, os.path.join(_tmp, "flood.json")) for _i in range(100): cmd(f"goodwe_ctl/unit/x{_i}/use/set", b"OFF", ctl=_flood) -check("...and a flood of 100 different bad topics logs 32 WARNINGs, no more", - len([r for r in _logs.rows if r[0] >= logging.WARNING]) == 32) +_w = [r[1] for r in _logs.rows if r[0] >= logging.WARNING] +_per = [w for w in _w if "still ignored" not in w] +_more = [w for w in _w if "still ignored" in w] +print(f" flood: {len(_per)} per-topic WARNINGs, then {_more}") +check("...and a flood of 100 different bad topics logs 32 WARNINGs, then the " + "rest only as a count, at 1 and 10 more (review of #152)", + len(_per) == 32 and len(_more) == 2 + and "1 more so far" in _more[0] and "10 more so far" in _more[1]) +_logs.rows.clear() +for _ in range(100): + cmd(f"{T_B}/use/set", b"maybe", ctl=_flood) +_more = [r[1] for r in _logs.rows + if r[0] >= logging.WARNING and "still ignored" in r[1]] +check("...so a repeated attack on ONE topic still shows it goes on: the count " + "reaches 100 in 3 lines, not 100", + len(_more) == 1 and "100 more so far" in _more[0]) +_logs.rows.clear() +_inj, _ = ctl_for(OPTS2M, os.path.join(_tmp, "inj.json")) +cmd("goodwe_ctl/unit/a\nERROR forged line\x1b[31m/use/set", b"OFF", ctl=_inj) +_w = [r[1] for r in _logs.rows if r[0] >= logging.WARNING] +check("...and a topic with a newline or an escape code cannot forge a log " + "line: it is logged printable only", + len(_w) == 1 and "\n" not in _w[0] and "\x1b" not in _w[0] + and "a?ERROR forged line?[31m" in _w[0]) # Modes off: refused on the same path, even if a message arrives. cmd(f"{T_A}/use/set", b"OFF", ctl=_c_off) @@ -1299,7 +1383,8 @@ check("(source read) main() passes modes and retractions to the publisher, " "and binds its commands to the controller", _kws.get("modes") == "_modes" and _kws.get("retract") == "_retract" and "pub.bind(asyncio.get_running_loop(), controller.mqtt_command)" - in _main_src) + in _main_src + and "_modes, _retract = mode_announcement(opts, store)" in _main_src) # --- 10h. the guards, broken one at a time -------------------------------------- @@ -1370,8 +1455,8 @@ P2_MUTATIONS = [ ("command topic matched as a prefix", [("_COMMAND_RE.fullmatch(topic)", "_COMMAND_RE.search(topic)")]), ("store list not filtered", - [("and _MODE_CONFIG_RE.fullmatch(t) and t not in keep", "and t not in keep")]), - ("current configs also removed", [("_MODE_CONFIG_RE.fullmatch(t) and t not in keep", "_MODE_CONFIG_RE.fullmatch(t)")]), + [("and _MODE_CONFIG_RE.fullmatch(t)\n", "and True\n")]), + ("current configs also removed", [("and t not in keep))", "))")]), ("commands published retained by HA", [('cfg["retain"] = False', 'cfg["retain"] = True')]), ("retractions not published", [(' self.client.publish(topic, "", retain=True)\n', " pass\n")]), -- 2.54.0 From ce0aea30b6ac938ce63d71bb6d9ab8a450a09ae0 Mon Sep 17 00:00:00 2001 From: Review Agent <review@local> Date: Tue, 29 Sep 2026 00:49:16 +0200 Subject: [PATCH 074/105] SAFETY-79 review: margin under a banked month peak too; identity harness reaches headroom and maintenance - quarter_target_w() is now the margin under quarter_ceiling_w(): a peak banked between cap - margin and the cap was aimed at exactly, so one overshoot crossed the cap; above the cap the same overshoot raised the bill. - safety79_identity.py hashes charge_headroom_w() and the shaping suspension, and adds n1_maint/n2_maint (cheap window, forecast across cap - 50 .. cap). Digests re-printed on ed739d4 and pinned; margin 0 still identical. - test_margin_under_banked_peak; DECISIONS and DOCS updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-79-peak-margin.md | 38 ++++++----- goodwe_controller/DOCS.md | 2 +- goodwe_controller/app/peakguard.py | 14 ++-- goodwe_controller/test_peak_margin.py | 66 ++++++++++++++----- goodwe_controller/tools/safety79_identity.py | 60 ++++++++++++++--- 5 files changed, 130 insertions(+), 50 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md b/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md index 72a34bc..2dd7adb 100644 --- a/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md +++ b/goodwe_controller/DECISIONS/SAFETY-79-peak-margin.md @@ -4,36 +4,38 @@ ## Decision -The peak guard aims at `peak_cap_w - peak_margin_w`, not at `peak_cap_w`. -`peak_margin_w` is a setting: default 50 W, range 0-500 W, whole watts. An -install without the key gets 50. +The peak guard aims `peak_margin_w` under the limit it holds: under +`peak_cap_w`, or under a month peak already banked above it +(`quarter_target_w()`). `peak_margin_w` is a setting: default 50 W, range +0-500 W, whole watts. An install without the key gets 50. **Why (owner):** the guard aimed exactly at the cap, and in the OPT-11 P1 test a quarter banked 3501.9 W against a 3500 W limit (OPT-11-P1-test-report.md, check 4). A peak even 1 W over still sets the billed peak. It is a setting and not a constant because the add-on is sold to several sites. +**Banked peak (review, 2026-09-29):** the PR first aimed at a banked month +peak as it stood. That can bank a few W over it, which raises the bill the +same way; and a peak banked between cap - margin and the cap (common in the +month an install upgrades, since the old guard held quarters at the cap) was +aimed at exactly, so one overshoot went over the cap. The margin now applies +under it too. Cost: up to `peak_margin_w` of a peak already paid for goes +unused (more discharge, less charge headroom); no bill cost. Undo is one line +in `quarter_target_w()`. + ## What uses which number -- **cap - margin (the aim):** `peakguard.decide()` (the claim's floor, and so - arbitrage's `charge_headroom_w()` and OPT-11's give-way, which read it), - `shaping_suspended()` and `maintenance_charge_floor()` (the forecast checks, - via `Controller.peak_aim_w()`). +- **the aim:** `peakguard.decide()` (the claim's floor, and so arbitrage's + `charge_headroom_w()` and OPT-11's give-way, which read it), and, as cap - + margin, `shaping_suspended()` and `maintenance_charge_floor()` (the forecast + checks, via `Controller.peak_aim_w()`). - **the real cap (reporting and billing):** `PeakTracker` (month peak, headroom, 80 % warning), the decision's `ceiling_w` and every notice and status row built from it, Home's limit, and `validate.config_notes()`. -A month peak already banked above cap - margin is aimed at as it stands -(`quarter_target_w()` is `quarter_ceiling_w()` on the lowered cap), so the -margin never holds a quarter below a peak that is already paid for. - ## Checks `peak_margin_w: 0` is byte-identical to ed739d4 (test_peak_margin.py part 1, -digests from tools/safety79_identity.py). validate.py rule 12 refuses a value -outside 0-500, not whole, or not below `peak_cap_w`. - -## Open - -Whether the margin should also apply below a banked month peak above the cap -is not decided here; today it does not. +digests from tools/safety79_identity.py, which also runs a maintenance charge +with a forecast). validate.py rule 12 refuses a value outside 0-500, not +whole, or not below `peak_cap_w`. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 3045f84..67a56e9 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -275,7 +275,7 @@ When the add-on refuses to start, each reason names the setting by its label and - **Inverter rating** (`max_w`): your own number, not a derived one. It is not read when the inverter list is filled in, since each entry carries its own and the site limit is their sum. Several safety thresholds must stay below it, and the add-on refuses to start if one does not. - **Battery cut-out level** (`bms_soc_floor`, `inverters.bms_soc_floor`): measured, not chosen. Register 0x0560 reads 10 % on the reference GW5000S-BP. It exists so the add-on can refuse a “Peak reserve” at or below it, which could never take effect. Each inverter entry states its own, because one default for two different batteries protects the shallower one with the deeper one's number. - **Peak limit** (`peak_cap_w`): your own number, from your grid contract. In Belgium it is the capacity-tariff peak your distribution charge is billed on. -- **Margin below the peak limit** (`peak_margin_w`): 50 W by default, 0 to 500 W (SAFETY-79). Peak limiting aims at the peak limit minus this margin, because a 15-minute period aimed exactly at the limit can end a watt or two over it (3501.9 W against 3500 W in a test), and even 1 W over sets the billed peak. The bill, this month's peak and the warnings still compare against the peak limit itself. 0 aims at the limit, as before. +- **Margin below the peak limit** (`peak_margin_w`): 50 W by default, 0 to 500 W (SAFETY-79). Peak limiting aims at the peak limit minus this margin, because a 15-minute period aimed exactly at the limit can end a watt or two over it (3501.9 W against 3500 W in a test), and even 1 W over sets the billed peak. Once this month's peak is already above the limit, it aims the same margin below that peak. The bill, this month's peak and the warnings still compare against the peak limit itself. 0 aims at the limit, as before. - **Peak reserve** (`peak_soc_floor`): derived, not picked (SAFETY-24). The reference battery holds 13.8 kWh usable and the worst modelled peak day asks for 878 Wh, or 6.4 %. 20 % sits ten points above the cut-out level and leaves about 1.6 worst days of room. It bounds peak limiting only: ordinary use goes on down to the cut-out level. It must stay above “Battery cut-out level”. - **Dynamic price source** (`price_provider`): selecting a provider is what starts the fetch, every half hour, whether or not trading is on. It may not be combined with the two older price entities. engie_dynamic, totalenergies_dynamic and eneco_eddy are withdrawn and refuse to start: their endpoints never existed. They stay in the list only so such a site gets that explanation. - **Supplier markup** (`price_markup_eur_kwh`): under manual_csv, whose prices are all in, it is ignored and logged as ignored. diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index eb1d70b..e21a7ac 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -143,9 +143,9 @@ because the money is spent on `max(month's peak so far, this quarter)`: ceiling_w = max(peak_cap_w, the month's banked peak) -SAFETY-79: the guard AIMS at `max(peak_cap_w - peak_margin_w, banked peak)` +SAFETY-79: the guard AIMS `peak_margin_w` under that ceiling (`quarter_target_w()`), so a quarter that lands a little high still stays under -the cap. `ceiling_w` stays the real limit for reports and the bill. +it. `ceiling_w` stays the real limit for reports and the bill. Once a month's peak already stands at 5013 W, holding every later quarter to 3500 W buys nothing - the bill for that month is already 5013 W - while the @@ -536,10 +536,12 @@ def quarter_ceiling_w(cap_w, reading) -> tuple[float, str]: def quarter_target_w(cap_w, margin_w, reading) -> float: - """SAFETY-79. The average the guard AIMS at: `quarter_ceiling_w()` with the - cap lowered by `margin_w`. A month peak already paid for is aimed at as it - stands. Reports and the bill keep the real cap (`ceiling_w`).""" - return quarter_ceiling_w(float(cap_w) - float(margin_w), reading)[0] + """SAFETY-79. The average the guard AIMS at: `margin_w` under + `quarter_ceiling_w()`, so under a month peak already banked as well as + under the cap. Aiming AT a banked peak can bank a few W over it, which + raises the bill as surely as going over the cap. Reports and the bill keep + the real limit (`ceiling_w`).""" + return quarter_ceiling_w(cap_w, reading)[0] - float(margin_w) def excess_w(projection, ceiling_w) -> float: diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py index 2416be5..116562a 100644 --- a/goodwe_controller/test_peak_margin.py +++ b/goodwe_controller/test_peak_margin.py @@ -47,20 +47,25 @@ CAP = float(rig.CAP_W) print("1. peak_margin_w 0: byte-identical to release/1.0 ed739d4") # Printed by `python3 tools/safety79_identity.py 0` on the ed739d4 tree (the # tool copied in, nothing else changed; that tree ignores the key), in the CI -# image, 2026-09-28. 540 cycles each: every command, the loop and arbiter -# sentences, the allocation, and the guard's floor, limit and sentence. +# image; re-printed 2026-09-29 (review) after adding the charge headroom, the +# shaping suspension and the two maintenance scenarios. 540 cycles each. ED739D4 = { - "n1": "36f2dc6cd82ed63b93125dc3f8ea5f475e494255c614a4d2f353dad06e44f884", - "n2": "1d388daf1bcfc3e16b1ef696377ae2a01831963374e2a6a4d2f998b5c6d997c2", - "n1_off": "76e41db45667fffebd3ce99a49873a31d0b86fcc0c520057bbf38cc4f27138ca", - "n2_off": "196653957e2fdf227daa42447ac170c45292e6c3f4184196dd99c1140359e415", + "n1": "82316f7d4362fae4c035a1bed5e7907cf362faba994c634d0b1c356c501f53e5", + "n2": "0dc24e16a8390ec42edacf735eaf20273847b33b9c67d7cdc536df0ca739e421", + "n1_off": "eed44f058f3fcc6e7651c5c84c6fa6313e7520035ad7cac282012cf6909668a0", + "n2_off": "69796c107b9f78892e04d282b754f889590acf9fe1b96f09525f5ea2005e9c0a", + "n1_maint": + "bd4a88a10aa840a360ac781ac04e30b040a5aac5426fabba1fb259d71dfeba67", + "n2_maint": + "0656bc5a4a2fa3a7455822fdd7da5f68f57fd9593f374e869a0d30ba7e429275", } _zero = rig.digests(0) _default = rig.digests() for k in ED739D4: print(f" {k:7} margin 0 {'same' if _zero[k] == ED739D4[k] else 'DIFFERS'}" f" {_zero[k][:16]}, default {_default[k][:16]}") -check("⭐ at N=1 and N=2, with and without battery modes, margin 0 is " +check("⭐ at N=1 and N=2, with and without battery modes and with a " + "maintenance charge, margin 0 is " "byte-identical to ed739d4", _zero == ED739D4) check("...and the default (key absent) changes every scenario, so the " "scenarios do reach the margin", all(_default[k] != ED739D4[k] @@ -118,15 +123,42 @@ check("test_off_battery_n2: at N=2 with B Off and A at its rating, B covers " _c0["b"] == 1000.0 and _g0 == CAP and _c50["b"] == 1050.0 and _g50 == CAP - 50) -_obs = type("R", (), {"is_observed": True, "peak_w": 2480.0})() -check("test_month_peak_not_lowered: a month peak already paid for is aimed " - "at as it stands (2480 W with cap 2500, margin 50), and a higher one " - "too; no peak aims at cap - margin", - quarter_target_w(CAP, 50, _obs) == 2480.0 - and quarter_target_w(CAP, 50, - type("R", (), {"is_observed": True, - "peak_w": 3000.0})()) == 3000.0 - and quarter_target_w(CAP, 50, None) == CAP - 50) +def _peak(w, observed=True): + return type("R", (), {"is_observed": observed, "peak_w": w})() + + +# Review (SAFETY-79 point 2): the margin applies under a month peak already +# banked, too. Aiming AT it can bank a few W over it, which raises the bill; +# and a banked peak between cap - margin and the cap (a quarter the old guard +# held at the cap, say) was aimed at exactly, so one overshoot crossed the cap. +check("test_margin_under_banked_peak: the aim is the margin under the limit " + "that holds - the cap, or a month peak already banked above it", + quarter_target_w(CAP, 50, _peak(2499.0)) == CAP - 50 + and quarter_target_w(CAP, 50, _peak(3000.0)) == 2950.0 + and quarter_target_w(CAP, 50, _peak(3000.0, observed=False)) == CAP - 50 + and quarter_target_w(CAP, 50, None) == CAP - 50 + and quarter_target_w(CAP, 0, _peak(3000.0)) == 3000.0) + + +def _decide(banked_w, projected_w): + """Half a quarter at `projected_w`, battery idle, a month peak banked.""" + from datetime import datetime, timezone + from app.tariff import Projection + pr = Projection(projected_w, projected_w, 450.0, 1.0, False, + datetime(2026, 9, 1, 12, 0, tzinfo=timezone.utc), + projected_w) + return peakguard.decide(pr, batt_w=0.0, cap_w=CAP, margin_w=50, + reading=_peak(banked_w), achievable_w=5000.0, + soc=60.0, soc_floor=20.0) + + +_d1, _d2 = _decide(2499.0, 2600.0), _decide(3000.0, 3100.0) +print(f" banked 2499 W: floor {_d1.floor_w}, limit {_d1.ceiling_w}; " + f"banked 3000 W: floor {_d2.floor_w}, limit {_d2.ceiling_w}") +check("...and decide() sizes the floor to land the quarter 50 W under it " + "(2449 and 2950 W), while the reported limit stays the cap or the peak", + _d1.floor_w == 2 * (2600.0 - 2450.0) and _d1.ceiling_w == CAP + and _d2.floor_w == 2 * (3100.0 - 2950.0) and _d2.ceiling_w == 3000.0) # ============================================================================ # print("\n3. the bill and the reports keep the real cap") @@ -139,7 +171,7 @@ check("test_billing_uses_cap: the month-peak tracker (bill, headroom, 80 % " "warning) is built on the real cap, not cap - margin", _c.peak.cap_w == CAP and _c.peak.warning_frac() == _pk / CAP and _c.peak.headroom_w() == CAP - _pk) -_eng = [g for r in _runs["n1_off", None][0] for g in (r[-1],) +_eng = [g for r in _runs["n1_off", None][0] for g in (r[-1][1],) if g and g[0] and g[1]] print(f" {len(_eng)} engaged cycles; one: {_eng[0][4] if _eng else None}") check("test_reports_use_cap: every engaged sentence names the real limit and " diff --git a/goodwe_controller/tools/safety79_identity.py b/goodwe_controller/tools/safety79_identity.py index c93cdaa..61eed07 100644 --- a/goodwe_controller/tools/safety79_identity.py +++ b/goodwe_controller/tools/safety79_identity.py @@ -6,7 +6,11 @@ tools/opt11_identity.py's harness (the REAL Controller, read_inputs + cycle, in simulated time) with a P1 meter, so the peak guard runs, and a peak limit the house goes over. Each row hashes opt11_identity's fields plus the guard's floor, -limit and sentence. It uses only the API release/1.0 ed739d4 already had, so +limit and sentence, its charge headroom (what arbitrage is sized to) and the +maintenance shaping's suspension. The two `_maint` scenarios run a maintenance +charge in a cheap window with a demand forecast that crosses cap - 50 .. cap, +so `shaping_suspended()` and `maintenance_charge_floor()` are both reached. +It uses only the API release/1.0 ed739d4 already had, so the same file runs on the old tree (which ignores `peak_margin_w`) and the new. test_peak_margin.py part 1 holds the new tree to the digests printed on ed739d4. """ @@ -22,7 +26,7 @@ from datetime import timedelta sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import opt11_identity as rig # noqa: E402 -from app import packmode # noqa: E402 +from app import packmode, peakguard # noqa: E402 from app.p1 import make_sample, split_signed # noqa: E402 from app.store import unit_key # noqa: E402 @@ -62,9 +66,43 @@ def store_off(name): return s +def forecast(t): + """A demand forecast that sweeps 2300-2600 W every 10 minutes: across + cap - 50 and the cap, so the margin moves the forecast checks.""" + return 2300.0 + (t % 600) / 600 * 300 + + +def _feed_maint(c, t): + """`_feed`, plus the forecast and a cheap price (now under average).""" + if not getattr(c.hass, "_s79", False): + read = c.hass.number + fixed = {"sensor.pnow": 0.05, "sensor.pavg": 0.20} + + async def number(e, invert=False): + if e == "sensor.fc": + return forecast(c.hass.t) + if e in fixed: + return fixed[e] + return await read(e, invert) + c.hass.number, c.hass._s79 = number, True + _feed(c, t) + + +def store_charging(n): + """A store where the first battery is in its maintenance CHARGE phase.""" + s = rig._Store() + for k in ("phase", "phase_started"): + s.data[k if n == 1 else unit_key("inverter-a", k)] = ( + "charge" if k == "phase" else rig.BASE.isoformat()) + return s + + P1 = {"meter_source": "ha_signed", "p1_net_entity": "sensor.net", "meter_phases": 1, "peak_cap_w": CAP_W} MODES = {"battery_modes_enabled": True} +MAINT = {"maintenance_enabled": True, "maintenance_start_hour": 11, + "peak_forecast_entity": "sensor.fc", "price_now_entity": "sensor.pnow", + "price_avg_entity": "sensor.pavg"} SCENARIOS = { "n1": dict(n=1), @@ -73,28 +111,34 @@ SCENARIOS = { "n1_off": dict(n=1, modes=True, off="inverter-a"), # OPT-11: B Off, so B covers what A cannot. "n2_off": dict(n=2, modes=True, off="inverter-b"), + # A maintenance charge in a cheap window, with a demand forecast. + "n1_maint": dict(n=1, maint=True), + "n2_maint": dict(n=2, maint=True), } -def run(n, *, margin=None, modes=False, off=None, dur=2700.0): +def run(n, *, margin=None, modes=False, off=None, maint=False, dur=2700.0): """Rows for one scenario; `margin=None` leaves the key out.""" - extra = dict(P1, **(MODES if modes else {})) + extra = dict(P1, **(MODES if modes else {}), **(MAINT if maint else {})) if margin is not None: extra["peak_margin_w"] = margin guard = [] def on_cycle(c, t): g = c.peak_guard - guard.append(None if g is None else (g.engaged, g.floor_w, g.ceiling_w, - g.ceiling_from, g.reason)) + guard.append((c._maint_shape_suspended, None if g is None else ( + g.engaged, g.floor_w, g.ceiling_w, g.ceiling_from, g.reason, + peakguard.charge_headroom_w(g)))) db = os.path.join(tempfile.mkdtemp(prefix="s79-"), "tariff.db") real = rig.Controller rig.Controller = functools.partial(real, peak_db_path=db) try: rows, c = rig.run(n, extra=extra, dur=dur, load=load, soc=soc, - cut=lambda u, t: False, before=_feed, + cut=lambda u, t: False, + before=_feed_maint if maint else _feed, on_cycle=on_cycle, - store=store_off(off) if off else None) + store=(store_off(off) if off else + store_charging(n) if maint else None)) finally: rig.Controller = real return [r + (g,) for r, g in zip(rows, guard)], c -- 2.54.0 From 902524ae5e76f40ce0f3a2bce58960074672f1af Mon Sep 17 00:00:00 2001 From: Claude dev agent <noreply@anthropic.com> Date: Tue, 29 Sep 2026 02:37:44 +0200 Subject: [PATCH 075/105] OPT-11 P3: price runs per battery Cheap and expensive hours as runs of consecutive firm price slots (priceruns.py); each battery's role per tick from its mode (modetrade.py): grid charging for Leftover solar / Cheap hours only, never Solar first; holding for the expensive runs; selling per battery (pack_sell) above the spread and the floor. The site trade is sized inside the modes (loop bound) and the peak guard's headroom; a run edge reseeds the loop. Cheap hours only and selling are enabled on the Batteries screen and in the HA select (appended). The site Why row no longer says "held back" when the peak limit pushes power up (F2). Modes off: byte-identical to 7a00f12 on the trade path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 32 +- goodwe_controller/DOCS.md | 23 +- goodwe_controller/app/homeview.py | 157 ++++- goodwe_controller/app/main.py | 304 ++++++++- goodwe_controller/app/messages.py | 12 +- goodwe_controller/app/modetrade.py | 230 +++++++ goodwe_controller/app/mqtt.py | 3 +- goodwe_controller/app/packmode.py | 46 +- goodwe_controller/app/priceruns.py | 203 ++++++ goodwe_controller/app/static/app.js | 23 +- goodwe_controller/app/ui_text/en.json | 30 +- goodwe_controller/app/ui_text/nl.json | 30 +- goodwe_controller/app/web.py | 5 +- goodwe_controller/test_batteries_screen.py | 76 ++- goodwe_controller/test_modes.py | 4 +- goodwe_controller/test_modes_p3.py | 613 ++++++++++++++++++ goodwe_controller/test_mqtt.py | 20 +- goodwe_controller/tools/opt11p3_identity.py | 110 ++++ goodwe_controller/tools/opt11p3_replay.py | 394 +++++++++++ 19 files changed, 2202 insertions(+), 113 deletions(-) create mode 100644 goodwe_controller/app/modetrade.py create mode 100644 goodwe_controller/app/priceruns.py create mode 100644 goodwe_controller/test_modes_p3.py create mode 100644 goodwe_controller/tools/opt11p3_identity.py create mode 100644 goodwe_controller/tools/opt11p3_replay.py diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 3ded348..2345e92 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -29,4 +29,34 @@ P1 is its section 6 P1, and the pull request lists what was measured. page's English names, pinned by a test, and are not renamed with the page: automations send them. - In P1 only Off closes a direction; Leftover solar differs by charging last. - Price runs, selling (`pack_sell`, reserved) and the forecast are P3/P4. +- P3 (price runs, `priceruns.py`, `modetrade.py`): each battery's range is + narrowed by its role this tick (hold, give, charge, rest, sell); main.py + files the intersection with the switch, so it still holds 0 W. With modes on + the site trade is filed by the modes, sized from the loop bound (so no + battery a mode or a refusal holds is asked for watts, P1's unmet share) and + the guard's headroom; `arbitrage.decide()` runs only with modes off, which + stays byte-identical to 7a00f12 (`test_modes_p3.py` part 1). +- SAFETY-46 item 2 is decided as the owner answered (2026-09-25): a trade is + a run of consecutive firm slots. It applies with battery modes on; the + modes-off trade keeps its one-period shape, because that path must not move. +- Choices that were measured, not assumed (tools/opt11p3_replay.py): + - a sale needs the guard to have measured the quarter, not to be clear: a + 5 kW discharge alone reads "engaged" on export and flipped the sale every + 5 s; + - a grid charge makes the others rest, so it starts only at 500 W and, once + the guard or the headroom stops it, stays off for that 15-minute period + (without: 13 flips in 4 minutes under a 3.5 kW house); + - stored energy is valued at the last cheap run for 12 h, and a charge + needs its own run to clear the spread (without: a night charge was spent + on flat morning prices, then charging went on at them); + - a run edge reseeds the loop at the house's level (a 3 kW import spike + removed; about 0.1 x rating still overshoots as export). +- Replay (tools/opt11p3_replay.py, 16 recorded days, EPEX prices a year + earlier, modelled batteries): P3 does not beat the P2 baseline on money + (net 19.57 / 19.60 EUR against 19.33; the old one-period trade 18.14). + A sale is judged on import prices but exports earn the injection price, + so selling lost money in the model. The owner should see this before + selling is recommended. +- Not done in P3: the forecast (P4: Leftover solar acts as Cheap hours only), + a headroom too short for the run moving the rest to the next cheap periods, + and an HA switch for selling. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 67a56e9..5589c11 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -520,9 +520,26 @@ below. Off by default. Turn it on, restart the add-on, and the Batteries screen (and Settings, Simple) gives each battery two controls. They apply at once, with no restart. - **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, but only for what the other batteries cannot cover. -- **Mode.** *Solar first* charges from spare solar before the other batteries. *Leftover solar* charges from the solar they cannot take. Both cover the house at any hour. Charging from the grid in cheap hours, and selling, come in a later update. +- **Mode.** + - *Solar first* charges from spare solar before the other batteries and covers the house at any hour. It never charges from the grid and never sells. + - *Leftover solar* charges from the solar the others cannot take, and from the grid in the cheapest hours. It saves its power for the expensive hours and covers the house then. + - *Cheap hours only* does the same with the grid. Until the solar forecast arrives, *Leftover solar* also tops up from the grid like this. +- **Sell in expensive hours.** For *Leftover solar* and *Cheap hours only*. In the most expensive hours the battery gives its full power: the house first, the rest to the grid. It stops at *Trading keeps at least* (`arbitrage_soc_floor`). -The peak limit, the safety stops and the monthly cycle always come before a battery's mode. +With battery modes on, these choices replace the *Charging and selling on price* switch (`arbitrage_enabled`); that switch is only read with modes off. + +**Cheap and expensive hours.** They come from the published day-ahead prices, as runs of consecutive 15-minute periods, not a single period. +- The cheap run is the cheapest stretch long enough to fill the batteries that may charge, at their power. +- An expensive hour costs at least *Battery cycle cost* (`cycle_cost_threshold_eur`, widened as for trading) more than the cheap run. The batteries hold their power until then. +- The sale uses the most expensive stretch inside those hours, and never a period below 0. +- A carried (not yet published) price is never used. A run that has started runs to its end. +- With no prices, or too small a gap, every battery follows the house. + +**What always comes first.** +- The peak limit, the safety stops and the monthly cycle come before a battery's mode. +- A grid charge is sized so the 15-minute period stays under the peak limit less its margin (`peak_margin_w`). It starts only at 500 W or more. Once the peak limit stops it, it stays off for the rest of that 15-minute period. +- While one battery charges from the grid, the others rest, and the house uses the grid. +- A battery that refuses to charge or give power takes no part in a run in that direction. **In Home Assistant.** With MQTT set up, each battery also gets a *Mode* list and a *Use* switch, for example `select.goodwe_inverter_a_mode` and `switch.goodwe_inverter_a_use`. They do the same as the Batteries screen. Turn battery modes off and restart, and they are removed. @@ -530,6 +547,8 @@ The peak limit, the safety stops and the monthly cycle always come before a batt *For installers:* a mode is a limit at priority 35, kept apart from the hard limits. It gives way only as far as a limit above it (the peak guard) needs. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. +*For installers:* when a charge or sale ends, the loop restarts at the house's own level rather than at the trade's watts. On the replay model that removes a ~3 kW import spike after a 2.5 kW charge and halves the settling time; about 0.1 × the battery's power still overshoots as export. Selling is the `pack_sell` action (and the *Mode* list gains *Cheap hours only* in Home Assistant, at the end). + ### Reading the grid-following loop: `Loop integrator`, `Loop integrator lead`, `Loop reason` The control law is a bounded integrator: an accumulator that is **not** the diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index efee29d..de8241e 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -10,8 +10,9 @@ note, section 3.3. The plan shows only what the add-on does today: trading on price (the arbitrage verdict, the same call the control cycle makes), the monthly battery cycle, the peak limit and "follows the house". OPT-11 P1 adds each battery's -switch and mode to its row; the mode plan arrives with P3/P4, so nothing here -invents one. Every sentence is in the words +switch and mode to its row; P3 adds each battery's price runs and its role this +cycle (`Controller.mode_runs`, `mode_tick`), read as the control cycle left +them, so nothing here invents a plan. Every sentence is in the words section at the bottom and is held to STYLE.md by test_messages.py. """ @@ -20,7 +21,7 @@ from datetime import datetime, timedelta, timezone from . import arbitrage, messages, peakguard, uitext from .maintenance import CHARGE as M_CHARGE, DRAIN as M_DRAIN, HOLD as M_HOLD from .maintenance import IDLE as M_IDLE -from .packmode import LEFTOVER_SOLAR, SOLAR_FIRST +from .packmode import CHEAP_HOURS, LEFTOVER_SOLAR, SOLAR_FIRST from .price import Absence, Uncertainty, brussels from .static_tariff import static_plan from .tariff import BILLING_TZ @@ -312,6 +313,73 @@ def trade_runs(c, plan, verdict, day0, day1, now, shadow): return runs, later, None +PRICE_MODES = (LEFTOVER_SOLAR, CHEAP_HOURS) + + +def mode_runs(c, day0, day1, now, shadow): + """OPT-11 P3: each battery's price runs today, as the control cycle keeps + them (`c.mode_runs`): the cheap run on the batteries that may charge + from the grid, the give runs on Leftover solar and Cheap hours, and the + sell run on those with selling on. Amounts are upper bounds ("up to"), + from the battery's own room, rating and the run's length. Returns + `(runs, no_trade_key)`.""" + rp = getattr(c, "mode_runs", None) + if getattr(c, "mode_tick", None) is None: + return [], None # no cycle yet: nothing is known + if rp is None: + return [], "no_prices" + if not rp.on: + return [], "not_worth" + floor, ceiling = arbitrage.soc_bounds(c.o) + out = [] + for i, inv in enumerate(c.inverters): + pm = c.pack_mode(inv) + if not pm.use or pm.mode not in PRICE_MODES: + continue + soc, cap = inv.soc, inv.capacity_kwh + + def room(kind, hrs): + kwh = inv.max_w / 1000.0 * hrs + if cap and soc is not None: + kwh = min(kwh, max(0.0, (ceiling - soc) if kind == "grid" + else (soc - floor)) / 100.0 * cap) + return kwh + blocks = [] + if rp.charge_useful(): + blocks.append(("grid", rp.cheap)) + sell = rp.sell if pm.sell else None + for g in rp.give: + if sell is not None and g.start <= sell.start < g.end: + blocks.append(("sell", sell)) + else: + blocks.append(("give", g)) + for kind, run in blocks: + if run.end <= now or not (run.start < day1 and run.end > day0): + continue + hrs = (run.end - run.start).total_seconds() / 3600.0 + kwh = room(kind, hrs) + if kwh < MIN_KWH: + continue + price = run.mean_eur_kwh + if kind == "grid": + what, why, amount = (run_grid_what(kwh, shadow), + run_cheap_why(price), + run_grid_amount(kwh * price)) + elif kind == "sell": + what, why, amount = (run_sell_what(kwh, shadow), + run_dear_why(price), + run_give_amount(kwh * price)) + else: + what, why, amount = (run_give_what(kwh, shadow), + run_dear_why(price), + run_give_amount(kwh * price)) + out.append(_run(i, "give" if kind == "sell" else kind, + max(run.start, day0), min(run.end, day1), day0, + day1, what, why, amount, kwh=kwh, + eur=kwh * price, price=price)) + return out, None + + def maintenance_runs(c, day0, day1, now, shadow): """The monthly battery cycle: under way now, or starting later today. The cycle starts in the hour `maintenance_start_hour` names, read as the @@ -434,10 +502,17 @@ def build_plan(c, now, shadow, running, held=False, settled=True): runs, lines = [], [] # The control cycle trades on the fresh plan only, so this does too. verdict, trade_why = trade_verdict(c, fresh) + modes_on = bool(getattr(c, "modes_on", False)) if running: off = {i for i, inv in enumerate(c.inverters) if _off(c, inv)} runs += house_runs(len(c.inverters), day0, day1, now, shadow, off) - if verdict is not None: + if modes_on: + # OPT-11 P3: with battery modes on, each battery's price runs. + mine, no_trade = mode_runs(c, day0, day1, now, shadow) + runs += mine + if no_trade: + lines.append(line_no_trade(no_trade)) + elif verdict is not None: trade, later, no_trade = trade_runs(c, fresh, verdict, day0, day1, now, shadow) runs += trade @@ -544,6 +619,11 @@ def battery_rows(c, shadow, running, held=False): pms = {inv.name: c.pack_mode(inv) for inv in c.inverters} \ if modes_on else {} peak = peak_engaged(c) + # OPT-11 P3: each battery's role this cycle and the price runs, as the + # control cycle left them. + tick = getattr(c, "mode_tick", None) if modes_on else None + rp = getattr(c, "mode_runs", None) + now = datetime.now(timezone.utc) rows = [] for i, inv in enumerate(c.inverters): m = c.maints[i] if i < len(c.maints) else None @@ -558,13 +638,22 @@ def battery_rows(c, shadow, running, held=False): # carries its share (SAFETY-73)? other = next((o.name for o in c.inverters if o is not inv and refusing(c, o) > 0 and not _off(c, o)), None) + role = None if tick is None else tick.roles.get(inv.name) + # Only once a cycle has run with modes on (`tick`): before that + # nothing is known, so nothing is claimed about the prices. + plan = (None if tick is None or pm.mode not in PRICE_MODES + else "no_prices" if rp is None + else "no_spread" if not rp.on else None) + nxt = rp.next_give(now) if rp is not None and rp.on else None + at = "" if nxt is None else ( + f"{hhmm(nxt.start)} - {hhmm(nxt.end)}") why = battery_why( modes_on=modes_on, mode=None if pm is None else pm.mode, off=off, reading=inv.soc is not None and inv.batt is not None, phase=phase, shadow=shadow, running=running, held=held, refused=refusing(c, inv), peak=peak, giving=flow(inv.batt) == "giving", other_refuses=other, - sf_ahead=sf_ahead) + sf_ahead=sf_ahead, role=role, plan=plan, has_at=bool(at)) rows.append({ "name": inv.name, "level_pct": None if inv.soc is None else float(inv.soc), @@ -582,7 +671,7 @@ def battery_rows(c, shadow, running, held=False): # UX-13 P3: why it does what "now" says, from what the add-on # knows this cycle. Price and forecast reasons are OPT-11 P3/P4. "why_key": why, - "why": why_words(why, name=other), + "why": why_words(why, name=other, at=at), }) if modes_on: # OPT-11 P1: the battery's switch and mode, for the Batteries @@ -590,13 +679,18 @@ def battery_rows(c, shadow, running, held=False): # without them. rows[-1].update({"use": pm.use, "mode_key": pm.key, "mode_choice": pm.mode, - "mode": mode_word(pm.key)}) + "mode": mode_word(pm.key), + # P3: selling, for Leftover solar and Cheap + # hours only (Solar first never sells). + "sell": pm.sell, "can_sell": pm.can_sell, + "role": role}) return rows def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, held, refused, peak, sf_ahead, giving=False, - other_refuses=None) -> str: + other_refuses=None, role=None, plan=None, + has_at=False) -> str: """The key of one battery's "why" line (`home_words.why`), most urgent first. Pure, so every branch is tested without a controller.""" if not reading: @@ -620,18 +714,31 @@ def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, return "other_refuses" if not modes_on: return "modes_off" + # OPT-11 P3: the battery's role in the price runs this cycle. + if role in ROLE_WHY: + if role == "hold" and not has_at: + return "saves_later" + return ROLE_WHY[role] + if plan in ("no_prices", "no_spread"): + return plan if giving: - return "covers_house" # both modes cover the house until P3 - if mode == LEFTOVER_SOLAR: + return "covers_house" + if mode in PRICE_MODES: return "leftover" if sf_ahead else "leftover_alone" return "solar_first" +# OPT-11 P3: a role (modetrade) -> its Why key. +ROLE_WHY = {"charge": "grid_charge", "rest": "rests_charge", + "sell": "selling", "give": "expensive", "hold": "saves"} + + def attach_today(rows, runs, *, modes_on, running=True, held=False, shadow=False) -> None: """UX-13 P3: each battery's runs today from the plan (the same blocks as - Home's chart), or one line saying there are none. With battery modes on - and no run, the mode's own plan is OPT-11 P3/P4, so it says so.""" + Home's chart), or one line saying there are none. With battery modes on, + a Leftover solar or Cheap hours battery with no price run left today + says so; the others follow the house.""" for i, row in enumerate(rows): mine = [r for r in runs if r["battery"] == i and r["kind"] != "house"] row["today"] = [{"from": r["from"], "to": r["to"], "kind": r["kind"], @@ -644,8 +751,11 @@ def attach_today(rows, runs, *, modes_on, running=True, held=False, row["today_line"] = today_words("stopped") elif row.get("use") is False: row["today_line"] = today_words("off") - elif modes_on: - row["today_line"] = today_words("not_planned") + elif modes_on and row.get("mode_choice") in PRICE_MODES: + # OPT-11 P3: a price mode with no run left today, or no plan + # made yet (no cycle has run with modes on). + row["today_line"] = today_words("no_runs" if row.get("role") + else "not_planned") else: row["today_line"] = today_words("house_would" if shadow else "house") @@ -954,10 +1064,11 @@ def battery_now(soc, batt_w, *, phase, shadow, running, held=False, return _t("now.resting") -def why_words(key, name=None) -> str: +def why_words(key, name=None, at="") -> str: """One battery's "why" line (UX-13 P3), from `battery_why()`'s key. - `name`: the battery that refuses, for `other_refuses`.""" - return _t("why." + key, name=name or "") + `name`: the battery that refuses, for `other_refuses`; `at`: the + give run's time, for `saves`.""" + return _t("why." + key, name=name or "", at=at) def today_words(key) -> str: @@ -989,6 +1100,18 @@ def run_grid_amount(eur) -> str: return _t("run.grid_amount", eur=_eur(eur)) +def run_sell_what(kwh, shadow) -> str: + return _w(shadow, "run.sell_what", kwh=_kwh(kwh)) + + +def run_cheap_why(price) -> str: + return _t("run.cheap_why", eur=_eur(price)) + + +def run_dear_why(price) -> str: + return _t("run.dear_why", eur=_eur(price)) + + def run_give_what(kwh, shadow) -> str: return _w(shadow, "run.give_what", kwh=_kwh(kwh)) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index b2df2f3..75c968c 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -37,11 +37,13 @@ import aiohttp from . import arbitrage from .arbiter import ( - P_LOOP, P_MAINT_SHAPE, P_MAINTENANCE, P_MODE, P_PEAK, P_SAFETY, - Claim, Resolution, actuator_for, pre_resolve, resolve, + ACTUATOR_SITE, P_LOOP, P_MAINT_SHAPE, P_MAINTENANCE, P_MODE, P_PEAK, + P_SAFETY, SET, Claim, Resolution, actuator_for, pre_resolve, resolve, ) from . import allocator +from . import modetrade from . import packmode +from . import priceruns from . import control as _ctl from .control import Tuning, compute, maintenance_charge_floor, peak_at_risk from .delivery import ( @@ -80,7 +82,9 @@ from . import packshare from . import pv as pv_read from . import shadow from .p1 import P1Ingest, build_source, is_enabled -from .price import Uncertainty, brussels, price_option, provider_configured +from .price import Absence, Uncertainty, brussels, price_option, provider_configured +from .price import required_spread as price_required_spread +from .price import uncertainty_of as price_uncertainty_of from .price_history import PriceHistory from .static_tariff import resolve_tariff, static_status from .tariff import PeakStore, PeakTracker @@ -226,6 +230,24 @@ def load_options() -> dict: +# OPT-11 P3: how long the last cheap run stays the price stored energy is +# valued at (`priceruns.plan(ref_eur_kwh=)`): the rest of that day. +REF_CHEAP_KEEP = timedelta(hours=12) + + +def why_raised(resolution, claims) -> bool: + """F2 (OPT-11 P1 test): did the limit that bound the site target push it + ABOVE what the winner asked (the peak floor asking for more power)? Then + the Why line must not say "held back". False when nothing bound it.""" + if not resolution.bound_by or resolution.contradiction: + return False + asked = next((c.value for c in sorted( + (c for c in claims if c.kind == SET + and c.actuator == ACTUATOR_SITE and c.source == resolution.winner), + key=lambda c: c.priority, reverse=True)), None) + return asked is not None and resolution.target_w > float(asked) + + def pack_energy_of(inv): """OPT-09. ONE roster entry as the view `packshare` consumes. @@ -909,6 +931,17 @@ class Controller: self.modes_on = packmode.enabled(opts) # The units whose mode fault is logged already (edge-logged). self._mode_faults = set() + # OPT-11 P3: the price runs (`priceruns.RunPlan`, or None), the key + # they were built for, this tick's roles (`modetrade.Tick`), the + # batteries that left a run (full, or at the floor) keyed by the run, + # and whether last tick filed a mode trade (a run edge reseeds). + self.mode_runs = None + self._runs_key = None + self.mode_tick = None + self._run_done = {} + self._mode_trade_was = False + self._charge_blocked_q = None + self._ref_cheap = None # OPT-11 P2: (topic, reason) of MQTT commands refused and logged once. self._mqtt_refused = set() self._mqtt_refused_more = 0 @@ -1982,7 +2015,11 @@ class Controller: # OPT-11: the solar order. While the site charges, Leftover solar # batteries weigh 0, so Solar first batteries fill first. A comfort # choice like the rest of this method: permission is the mode claim. - return packmode.charge_weights(base, self.pack_modes(), target_w) + w = packmode.charge_weights(base, self.pack_modes(), target_w) + # P3: in a price run, the batteries whose run it is carry it first. + tick = self.mode_tick + return w if tick is None else modetrade.weights(tick.roles, w, + target_w) def pack_mode(self, inv) -> "packmode.PackMode": """OPT-11. This battery's on/off switch and mode, read from the store.""" @@ -2011,6 +2048,214 @@ class Controller: for u in self.units} return allocator.loop_bound(bounds, live=self.live_units()) + # --- OPT-11 P3: price runs, per battery ------------------------------- + def _mode_packs(self, maint_results=None) -> list: + """Each battery as `modetrade.Pack`, in roster order.""" + live = set(self.live_units()) + out = [] + for i, inv in enumerate(self.inverters): + pm = self.pack_mode(inv) + idle = (maint_results is None + or maint_results[i].phase == IDLE) + refused = (inv.refused if len(self.inverters) > 1 + else self.batt_refused) or 0 + out.append(modetrade.Pack( + inv.name, pm.use, pm.mode, pm.sell and pm.can_sell, + float(inv.max_w), inv.soc, inv.capacity_kwh, + live=inv.name in live, idle=idle, refused=int(refused))) + return out + + def _price_runs(self, now, packs, floor_pct, ceiling_pct): + """The kept run plan, rebuilt at most once per price slot (15 min) or + when the prices or a battery's choice change; a run under way is + kept to its end (`priceruns.keep_started()`). None with no fresh + firm prices: then no battery holds or trades (design section 5).""" + plan = self.fresh_tariff_plan(now) + if plan is None or not plan.has_prices: + self.mode_runs, self._runs_key = None, None + return None + slot = int(now.timestamp() // 900) + key = (id(plan), slot, tuple((p.name, p.use, p.mode, p.sell) + for p in packs)) + if key != self._runs_key: + done_c = self._run_done.get("charge", (None, set()))[1] + done_s = self._run_done.get("sell", (None, set()))[1] + e = modetrade.energy(packs, floor_pct, ceiling_pct, done_c, + done_s) + required = price_required_spread( + arbitrage.threshold_eur_kwh(self.o), + price_uncertainty_of(plan.read.product) + | {Uncertainty.NO_WEATHER}) + ref = self._ref_cheap + if ref is not None and now - ref.end > REF_CHEAP_KEEP: + ref = self._ref_cheap = None + new = priceruns.plan( + plan.read.points, now, required_eur_kwh=required, + charge_kwh=e[0], charge_kw=e[1], sell_kwh=e[2], + sell_kw=e[3], + ref_eur_kwh=None if ref is None else ref.mean_eur_kwh) + self.mode_runs = priceruns.keep_started(self.mode_runs, new, now) + self._runs_key = key + runs = self.mode_runs + # The cheapest cheap run under way lately is the price the stored + # energy was bought at; it stays the reference for REF_CHEAP_KEEP + # after it ends, unless a cheaper one comes. + ref = self._ref_cheap + if runs is not None and runs.cheap is not None \ + and runs.cheap.holds(now) and ( + ref is None or now - ref.end > REF_CHEAP_KEEP + or runs.cheap.mean_eur_kwh <= ref.mean_eur_kwh): + self._ref_cheap = runs.cheap + return runs + + def _mode_roles(self, now, maint_results): + """OPT-11 P3: each battery's role and range this tick. Grid charging + and selling need a fresh plan that `TariffPlan.arbitrage()` allows + with the MEASURED peak guard (None refuses: nothing measures the + quarter), exactly the gate `arbitrage.decide()` has.""" + floor_pct, ceiling_pct = arbitrage.soc_bounds(self.o) + packs = self._mode_packs(maint_results) + runs = self._price_runs(now, packs, floor_pct, ceiling_pct) + guard = arbitrage.guard_state(self.peak_guard) + plan = self.fresh_tariff_plan(now) + charge_ok = sell_ok = False + trade_why = "not_covered" + + def allowed(active): + return plan.arbitrage( + peak_guard_active=active, + min_spread_eur_kwh=arbitrage.threshold_eur_kwh(self.o), + uncertainty=frozenset({Uncertainty.NO_WEATHER})).match( + allowed=lambda _v: True, refused=lambda _v: False) + if guard is not None and plan is not None and runs is not None: + # A charge asks the guard (section 9.1 interlock); a sell only + # needs it to have measured the quarter, since discharge is never + # capped by it (a big discharge alone engages it on export). + sell_ok = allowed(False) + charge_ok = sell_ok and allowed(guard) + trade_why = (None if charge_ok else "peak" if sell_ok + else "not_worth") + price_now = None + if plan is not None: + try: + pt = plan.read.match(series=lambda r: r.at(now), + no_data=lambda _r: None) + price_now = (None if pt is None or pt.provisional + else float(pt.eur_per_kwh)) + except Absence: + price_now = None + house = (None if self.grid is None or self.site_batt_w is None + else float(self.grid) + float(self.site_batt_w)) + done_c = self._run_mark("charge", runs and runs.cheap, packs, + lambda p: p.soc is not None + and p.soc >= ceiling_pct) + done_s = self._run_mark("sell", runs and runs.sell, packs, + lambda p: p.soc is not None + and p.soc <= floor_pct) + quarter = int(now.timestamp() // 900) + was = self.mode_tick is not None and \ + self.mode_tick.action == modetrade.CHARGE + self.mode_tick = modetrade.decide( + runs, now, packs, charge_ok=charge_ok, sell_ok=sell_ok, + trade_why=trade_why, price_now=price_now, + headroom_w=self.arb_headroom_w, floor_pct=floor_pct, + ceiling_pct=ceiling_pct, house_w=house, charging_now=was, + blocked=self._charge_blocked_q == quarter, + done_charge=done_c, done_sell=done_s) + # A charge the guard or the headroom stopped stays off this period. + if was and self.mode_tick.action != modetrade.CHARGE and \ + self.mode_tick.why in ("peak", "headroom"): + self._charge_blocked_q = quarter + return self.mode_tick + + def _run_mark(self, kind, run, packs, out) -> set: + """The batteries that left run `run` (full, or at the floor); they + stay out until it ends, so a level edge does not re-arm them.""" + key = None if not run else (run.start, run.end) + was_key, done = self._run_done.get(kind, (None, set())) + if key != was_key: + done = set() + if key is not None: + done |= {p.name for p in packs if out(p)} + self._run_done[kind] = (key, done) + return done + + def _mode_trade(self, claims, now) -> bool: + """OPT-11 P3: file the site trade the roles ask for, sized inside the + modes and the hard limits (the loop bound) and, for a charge, the + billed quarter's headroom (SAFETY-45, aim cap - margin, SAFETY-79). + So no battery that its mode or a refusal holds is asked for watts it + may not give (P1's unmet share). Returns True when a trade is filed. + """ + tick = self.mode_tick + if tick is None: + return False + size = modetrade.size(tick, self.loop_bound(claims) + if tick.action else None, self.arb_headroom_w) + runs = self.mode_runs + if tick.action and (size == 0.0 or runs is None): + # Nothing the batteries may place (a refusal, a hard limit): no + # trade, and the roles say so rather than "charging". + back = {modetrade.CHARGE: modetrade.HOLD, + modetrade.REST: modetrade.HOUSE, + modetrade.SELL: modetrade.GIVE} + tick = self.mode_tick = modetrade.Tick( + tick.ranges, {n: back.get(r, r) for n, r in tick.roles.items()}, + None, 0.0, "size") + if size == 0.0 or runs is None: + reason = ("battery modes: no price run now" if tick.why is None + else f"battery modes: no trade ({tick.why})") + self.arb = arbitrage.ArbitrageDecision( + action=None, power_w=None, reason=reason, + spread_eur_kwh=None, required_eur_kwh=None, + price_now_eur_kwh=None) + else: + charge = tick.action == modetrade.CHARGE + run = runs.cheap if charge else runs.sell + who = ", ".join(n for n, r in sorted(tick.roles.items()) + if r == tick.action) + act = arbitrage.CHARGE if charge else arbitrage.DISCHARGE + self.arb = arbitrage.ArbitrageDecision( + action=act, power_w=size, + reason=(f"{act}: battery modes, " + f"{'cheap' if charge else 'sell'} run " + f"{run.start.isoformat()} to {run.end.isoformat()} " + f"at {run.mean_eur_kwh:.4f} EUR/kWh; " + f"{abs(size):.0f} W on {who}"), + spread_eur_kwh=None, required_eur_kwh=runs.level_eur_kwh, + price_now_eur_kwh=None) + claims.append(arbitrage.claim(self.arb)) + if self.arb.action != self._arb_action: + self._arb_action = self.arb.action + self.log_event(self.arb.explain(), hint=messages.hint( + "trade_charge" if self.arb.action == arbitrage.CHARGE else + "trade_give" if self.arb.action == arbitrage.DISCHARGE + else "trade_off")) + return self.arb.action is not None + + def _reseed_run_edge(self, claims) -> None: + """OPT-11 P3: a mode trade just ended, so the loop takes over from a + command no loop chose. Start it at the house's own point E, the + command that brings the grid to its target now (`site battery + grid + - target`, inside the loop bound), instead of at the trade's watts + (the trade began with the same unslewed step). This tick's error still + measures the trade's command (it is exactly E - battery), so the + integrator is seeded that much short and lands on E after its step. + Measured (tools/opt11p3_replay.py, lagged battery, 2.5 kW charge + ending under an 800 W house): no reseed -258 W export then a 2976 W + import, settled in 55 s; this -257 W / +615 W, settled in 20 s. + """ + batt = self.site_batt_w + if batt is None or self.grid is None: + return + want = float(batt) + float(self.grid) - self.tuning.target_grid_w + bound = self.loop_bound(claims) + if bound is not None: + want = max(bound[0], min(bound[1], want)) + want = float(round(max(-self.site_max_w, min(self.site_max_w, want)))) + self.target = want + self.i_w = want - self.tuning.gain * (want - float(batt)) + def _mode_fault_log(self, resolution) -> None: """OPT-11: say once, per battery, that its mode was dropped as a fault. @@ -2032,7 +2277,8 @@ class Controller: self._mode_faults = now def _pack_action(self, what, unit, value, now) -> dict: - """OPT-11: switch one battery on or off, or set its mode. + """OPT-11: switch one battery on or off, set its mode, or (P3) turn + its selling on or off. Store state, not an option, so it applies on the next cycle with no restart. Written to the action log. Switching a battery off also stops @@ -2056,6 +2302,13 @@ class Controller: if not value: self._maint_stop_off(self.maints[self.inverters.index(inv)], now) + elif what == "pack_sell": + if not isinstance(value, bool): + return {"error": messages.pack_refused("value")} + inv.store_set(packmode.SELL_KEY, value) + self.log_event(f"{inv.name} selling switched " + f"{'on' if value else 'off'} by operator", + hint=messages.hint("pack_sell", unit=inv.name)) else: if value not in packmode.MODES: return {"error": messages.pack_refused("value")} @@ -2064,7 +2317,10 @@ class Controller: f"by operator", hint=messages.hint("pack_mode", unit=inv.name)) pm = self.pack_mode(inv) - return {"unit": inv.name, "use": pm.use, "mode": pm.mode} + out = {"unit": inv.name, "use": pm.use, "mode": pm.mode} + if what == "pack_sell": + out["sell"] = pm.sell + return out def mode_values(self) -> dict: """OPT-11 P2: each battery's mode and switch, for their HA state @@ -3579,15 +3835,20 @@ class Controller: # decision presented as current. self.arb, self.arb_at = None, now self.arb_headroom_w = None - if arbitrage.enabled(self.o): - floor_pct, ceiling_pct = arbitrage.soc_bounds(self.o) - charge_w, discharge_w = self.trade_power_w(floor_pct, ceiling_pct) + # OPT-11 P3: with battery modes on, each battery's mode decides who + # trades (`_mode_roles()`, `_mode_trade()`, below, which read the + # same headroom), and this site-wide trade is not run. + site_trade = arbitrage.enabled(self.o) and not self.modes_on + if site_trade or self.modes_on: # SAFETY-47. HOISTED OUT OF THE CALL, NOT COPIED. One evaluation of # the shipped expression feeds both the sizing below and # `arbitrage.sized_from_meter()` in `_shadow_settle()`, so the # caveat on the recorded watts can never be answered from a # different cycle's guard than the watts were. self.arb_headroom_w = peakguard.charge_headroom_w(self.peak_guard) + if site_trade: + floor_pct, ceiling_pct = arbitrage.soc_bounds(self.o) + charge_w, discharge_w = self.trade_power_w(floor_pct, ceiling_pct) self.arb = arbitrage.decide( self.fresh_tariff_plan(now), now, peak_guard_active=arbitrage.guard_state(self.peak_guard), @@ -3767,12 +4028,17 @@ class Controller: # apart from the hard limits, and it gives way to the peak guard's # site floor (P_PEAK) only as far as the floor needs, so the two never # meet in a `lo > hi` (arbiter._unit_modes()). + # P3: the range is the switch's, narrowed by the battery's role in + # the price runs this tick (`modetrade.decide()`); both hold 0 W. if self.modes_on: + tick = self._mode_roles(now, maint_results) for inv, result in zip(self.inverters, maint_results): if result.phase != IDLE: continue pm = self.pack_mode(inv) lo, hi = packmode.mode_range(pm, inv.max_w) + rlo, rhi = tick.ranges.get(inv.name, (lo, hi)) + lo, hi = max(lo, rlo), min(hi, rhi) claims.append(Claim.limit("mode", P_MODE, lo, hi, pm.key, actuator=self.actuator_of("mode", inv))) @@ -3823,6 +4089,13 @@ class Controller: _ctl.REFUSED, actuator=self.actuator_of("refused", inv))) + # --- OPT-11 P3: the site trade, after every unit claim -------------- + # Sized from what the batteries may place with their modes and hard + # limits (the loop bound), so none is asked for watts it may not give. + mode_trade, trade_was = False, self._mode_trade_was + if self.modes_on: + mode_trade = self._mode_trade(claims, now) + self._mode_trade_was = mode_trade if (self.auto or self.shadow) and self.inputs_ok: # ⚠️ prev is the ARBITER's last output, not the loop's own last # wish. If something outranked the loop, that is what the hardware @@ -3840,6 +4113,9 @@ class Controller: # stale period as power. if self.loop_w is None or self.target != self.loop_w: self.i_w = self.target + # OPT-11 P3: a run edge (a mode trade ended) reseeds the loop. + if trade_was and not mode_trade: + self._reseed_run_edge(claims) # SAFETY-52: another writer overrode the loop, so a refusal learned # against the loop's own ask no longer describes the wire. A gap # (`loop_w` None: blind or stopped) keeps it: the stale-reading stop @@ -4172,7 +4448,8 @@ class Controller: else: self.why_words = messages.why( _why, resolution.target_w, resolution.bound_by, - contradiction=resolution.contradiction) + contradiction=resolution.contradiction, + raised=why_raised(resolution, claims)) # --- DEV-02: EACH INVERTER IS TOLD ITS OWN SHARE --------------------- # ⚠️ ITS OWN SHARE, NEVER THE SITE TARGET. `resolution.shares` is the # allocator's answer and `sum(shares) + unmet_w == round(target_w)` is @@ -5934,8 +6211,11 @@ class Controller: # instead of inferring it, and separates "trading is off" from "no # decision was reached this cycle"; `cycle_at` and `arb_at` are what # make the second one an observation rather than a guess. + # OPT-11 P3: with battery modes on the modes trade, whatever the + # switch says, so the row reports their decision. ("Arbitrage", arbitrage_row( - on=arbitrage.enabled(self.o), decision=self.arb, + on=arbitrage.enabled(self.o) or self.modes_on, + decision=self.arb, decided_at=self.arb_at, cycle_at=self.cycle_at, now=datetime.now(timezone.utc), why=self.why_words)), ] @@ -5967,7 +6247,7 @@ class Controller: async def handle_action(self, what: str, *, unit=None, value=None): now = datetime.now(timezone.utc) - if what in ("pack_use", "pack_mode"): + if what in ("pack_use", "pack_mode", "pack_sell"): return self._pack_action(what, unit, value, now) if what == "auto_toggle": self.auto = not self.auto diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 8e9da7d..b4fa6f7 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -839,17 +839,22 @@ WHY_LIMIT = { } -def why(winner, target_w, bound_by=None, *, contradiction=False) -> str: +def why(winner, target_w, bound_by=None, *, contradiction=False, + raised=False) -> str: """`winner` is the arbiter's winning source, or its reason for the two that share a source ("stopped", "inputs missing", "no claim was made"). - `bound_by` is `Resolution.bound_by`, e.g. "peak(quarter peak)".""" + `bound_by` is `Resolution.bound_by`, e.g. "peak(quarter peak)". + `raised` is True when that limit pushed the power UP (the peak limit + asking for more): then it did not hold anything back (OPT-11 P1 test F2). + """ if contradiction: return "Two limits clash, so every inverter is set to 0 W" out = f"{WHY_WINNER.get(winner, 'Other')}: {signed_watts(target_w)}" if bound_by: limit = WHY_LIMIT.get(bound_by) or WHY_LIMIT.get( str(bound_by).split("(")[0], "another limit") - out += f", held back by {limit}" + out += f", raised for {limit}" if raised else \ + f", held back by {limit}" return out @@ -922,6 +927,7 @@ HINTS = { "pack_on": "{unit}: battery switched on", "pack_off": "{unit}: battery switched off, it is asked for 0 W", "pack_mode": "{unit}: battery mode changed", + "pack_sell": "{unit}: selling switched", "maint_off": "{unit}: maintenance stopped, the battery is switched off", "mode_fault": "{unit}: battery mode ignored because of a software fault", } diff --git a/goodwe_controller/app/modetrade.py b/goodwe_controller/app/modetrade.py new file mode 100644 index 0000000..1c5b4a6 --- /dev/null +++ b/goodwe_controller/app/modetrade.py @@ -0,0 +1,230 @@ +"""OPT-11 P3: each battery's role this tick, from its mode and the price runs. + +Pure: no I/O, no clock. main.py hands in the run plan (`priceruns`), each +battery's state and the peak guard's answers, files each battery's range as +its `mode` claim (P_MODE), and files the site trade as the `arbitrage` claim +(P_ARBITRAGE), sized inside the modes (`size()`), only with battery modes on. +With them off, `arbitrage.decide()` runs exactly as before. + +Roles (the page's Why line names them): + off Off: [0, 0]. + house follows the house: charges from spare solar, gives power at any + hour (Solar first always; the other modes when there is no plan). + hold Leftover solar / Cheap hours outside a give run: may charge from + spare solar, gives nothing, so its energy is kept for the run. + give the same inside a give run: covers the house. + sell inside the sell run, with selling on: gives its rating, to the + house first and the rest to the grid. + charge inside the cheap run: charges from the grid. + rest another battery charges from the grid, so this one may not charge + (the owner's 2026-09-27 answer 3: while one battery charges from the + grid the others cannot give power either; the allocator never + splits a target both ways). + +Rules that keep this safe (tests: test_modes_p3.py): + * every range holds 0 W (a mode may forbid a direction, never force one); + * a Solar first battery never charges from the grid (no forecast yet, P4); + * grid charging needs a measured peak guard that is clear and a measured + headroom (SAFETY-45); the trade is sized to that headroom, whose aim is + `peak_cap_w - peak_margin_w` (SAFETY-79). It starts only at START_W or + more, and once the guard or the headroom stops it, it stays stopped for + the rest of that 15-minute period (`blocked`): a charge makes the other + batteries stop giving power, so a few watts of charge flipping on and + off would swing the house between them and the grid (measured on the + 2026-09-09 replay: 13 flips in 4 minutes at a 3.5 kW house); + * selling needs selling on for that battery, the sell run, a price >= 0 + now, and the battery above `arbitrage_soc_floor`; it stops there. The + peak guard never stops a sell (section 9.1: discharge is never capped); + it must only have measured the quarter; + * a battery out of a run (full, or at the floor) stays out until the run + ends, so the ceiling and the floor do not re-arm within one run; + * a battery that refuses a direction (SAFETY-52/73) takes no part in a + run in that direction: the refusal wins over the run. +""" + +from dataclasses import dataclass + +from .packmode import CHEAP_HOURS, LEFTOVER_SOLAR, SOLAR_FIRST + +OFF, HOUSE, HOLD, GIVE, SELL, CHARGE, REST = ( + "off", "house", "hold", "give", "sell", "charge", "rest") +PRICE_MODES = (LEFTOVER_SOLAR, CHEAP_HOURS) + +# The smallest grid charge worth starting, in W. Under it the other batteries +# would stop covering the house for less than they give. +START_W = 500.0 + + +@dataclass(frozen=True) +class Pack: + """One battery as this module needs it.""" + name: str + use: bool + mode: str + sell: bool + rating_w: float + soc: float | None + capacity_kwh: float | None + live: bool = True + idle: bool = True # not in a maintenance phase + refused: int = 0 # SAFETY-52/73: +1 refuses to give, -1 to charge + + +@dataclass(frozen=True) +class Tick: + ranges: dict # name -> (lo, hi), only for idle batteries + roles: dict # name -> role + action: str | None # "charge" | "sell" | None + ask_w: float # signed site ask before sizing (0 if none) + why: str | None # why no trade when a run is on, else None + + +def _room_kwh(p: Pack, pct: float) -> float: + """kWh to `pct` (charging) or above it (selling); a battery with no + capacity set counts one hour at its rating, so a run is still sized.""" + if p.capacity_kwh is None or p.soc is None: + return abs(p.rating_w) / 1000.0 + return max(0.0, abs(pct - p.soc)) / 100.0 * float(p.capacity_kwh) + + +def chargers(packs, ceiling_pct, done=()) -> list: + """Batteries that may charge from the grid in a cheap run (P3: no + forecast, so Leftover solar acts as Cheap hours only; owner answer 4).""" + return [p for p in packs + if p.use and p.idle and p.live and p.mode in PRICE_MODES + and p.soc is not None and p.soc < ceiling_pct + and p.refused >= 0 and p.name not in done] + + +def sellers(packs, floor_pct, done=()) -> list: + """Batteries that may sell in the sell run. Solar first never sells.""" + return [p for p in packs + if p.use and p.idle and p.live and p.sell + and p.mode in PRICE_MODES + and p.soc is not None and p.soc > floor_pct + and p.refused <= 0 and p.name not in done] + + +def energy(packs, floor_pct, ceiling_pct, done_charge=(), done_sell=()): + """`(charge_kwh, charge_kw, sell_kwh, sell_kw)` for `priceruns.plan()`.""" + ch = chargers(packs, ceiling_pct, done_charge) + se = sellers(packs, floor_pct, done_sell) + return (sum(_room_kwh(p, ceiling_pct) for p in ch), + sum(abs(p.rating_w) for p in ch) / 1000.0, + sum(_room_kwh(p, floor_pct) for p in se), + sum(abs(p.rating_w) for p in se) / 1000.0) + + +def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, + headroom_w, floor_pct, ceiling_pct, house_w, charging_now=False, + blocked=False, done_charge=(), done_sell=()) -> Tick: + """This tick's ranges, roles and site ask. + + `runs` is the kept `priceruns.RunPlan` or None (no fresh prices). + `charge_ok` is True only when `TariffPlan.arbitrage()` allowed a trade + this tick with the MEASURED peak guard clear; `sell_ok` when it allowed + one with the guard measured (either state); else `trade_why` says why. + `headroom_w` is `peakguard.charge_headroom_w()` (None: unmeasured). + `house_w` is the measured house (grid + batteries), or None. + `charging_now` says last tick charged (then any headroom above 0 keeps + it going); `blocked` that the guard or the headroom stopped a charge in + this 15-minute period. + """ + plan_on = runs is not None and runs.on + in_cheap = plan_on and runs.cheap.holds(now) and runs.charge_useful() + in_give = plan_on and runs.give_at(now) is not None + in_sell = plan_on and runs.sell is not None and runs.sell.holds(now) + + why = None + ch = chargers(packs, ceiling_pct, done_charge) if in_cheap else [] + charging = False + if ch: + need = 0.0 if charging_now else START_W + if blocked: + why = "headroom" + elif not charge_ok: + why = trade_why + elif headroom_w is None or not headroom_w > need: + why = "headroom" + else: + charging = True + se = sellers(packs, floor_pct, done_sell) if in_sell and not charging \ + else [] + selling = False + if se: + if not sell_ok: + why = why or trade_why + elif price_now is None or price_now < 0.0 or house_w is None: + why = why or "negative" + else: + selling = True + + ranges, roles = {}, {} + ch_names = {p.name for p in ch} if charging else set() + se_names = {p.name for p in se} if selling else set() + for p in packs: + r = abs(float(p.rating_w)) + if not p.use: + role, lo, hi = OFF, 0.0, 0.0 + elif p.name in ch_names: + role, lo, hi = CHARGE, -r, 0.0 + elif charging: + # Another battery charges from the grid: this one may not charge + # (it would be grid charging too), and cannot give (one sign). + role, lo, hi = REST, 0.0, (r if p.mode == SOLAR_FIRST + or not plan_on or in_give else 0.0) + elif p.name in se_names: + role, lo, hi = SELL, -r, r + elif p.mode == SOLAR_FIRST or not plan_on: + role, lo, hi = HOUSE, -r, r + elif in_give: + role, lo, hi = GIVE, -r, r + else: + role, lo, hi = HOLD, -r, 0.0 + roles[p.name] = role + if p.idle: + ranges[p.name] = (lo, hi) + + if charging: + ask = -sum(abs(p.rating_w) for p in ch) + return Tick(ranges, roles, CHARGE, ask, None) + if selling: + ask = sum(abs(p.rating_w) for p in se) + max(0.0, float(house_w)) + return Tick(ranges, roles, SELL, ask, None) + return Tick(ranges, roles, None, 0.0, + why if (in_cheap or in_sell) else None) + + +def size(tick: Tick, bound, headroom_w) -> float: + """The site trade in W, inside what the batteries may place with their + modes (`bound` = main's loop bound) and, for a charge, the billed + quarter's headroom. 0.0 means no trade (a 0 W trade is a park order and + is never filed).""" + if tick.action is None or bound is None: + return 0.0 + lo, hi = bound + if tick.action == CHARGE: + cap = min(-float(tick.ask_w), -float(lo), + float(headroom_w) if headroom_w is not None else 0.0) + return -max(0.0, cap) + return max(0.0, min(float(tick.ask_w), float(hi))) + + +def weights(roles: dict, base, target_w: float): + """Who carries the site target first (design 3.5). Selling: the sellers. + Giving power: batteries in a give run before Solar first. Charging from + the grid: only the chargers. Otherwise `base` unchanged. Comfort only; + the ranges above are the permission.""" + names = sorted(roles) + first = None + if target_w > 0 and any(r == SELL for r in roles.values()): + first = {n for n in names if roles[n] == SELL} + elif target_w > 0 and any(r == GIVE for r in roles.values()): + first = {n for n in names if roles[n] in (GIVE, SELL)} + elif target_w < 0 and any(r == CHARGE for r in roles.values()): + first = {n for n in names if roles[n] == CHARGE} + if not first: + return base + w = {n: (1.0 if base is None else float(base.get(n, 1.0))) for n in names} + out = {n: (w[n] if n in first else 0.0) for n in names} + return out if any(v > 0.0 for v in out.values()) else base diff --git a/goodwe_controller/app/mqtt.py b/goodwe_controller/app/mqtt.py index b7716d6..56d54cf 100644 --- a/goodwe_controller/app/mqtt.py +++ b/goodwe_controller/app/mqtt.py @@ -453,7 +453,8 @@ def discovery_payloads(units=(), omit=(), include=(), modes=()) -> list: # # The select's options are these labels, in `packmode.MODES` order. A new mode # (P3) is a new entry here and a new option at the end; no id changes. -MODE_LABELS = {"solar_first": "Solar first", "leftover_solar": "Leftover solar"} +MODE_LABELS = {"solar_first": "Solar first", "leftover_solar": "Leftover solar", + "cheap_hours": "Cheap hours only"} # OPT-11 P3 USE_ON, USE_OFF = "ON", "OFF" # A longer command payload is refused before it is decoded. MAX_COMMAND_BYTES = 64 diff --git a/goodwe_controller/app/packmode.py b/goodwe_controller/app/packmode.py index a4989dd..e13f05a 100644 --- a/goodwe_controller/app/packmode.py +++ b/goodwe_controller/app/packmode.py @@ -1,4 +1,4 @@ -"""OPT-11 P1: each battery's mode and on/off switch, as limits and weights. +"""OPT-11: each battery's mode and on/off switch, as limits and weights. Pure: no I/O, no clock. main.py reads the store, calls these, and files the result as a `mode` claim (arbiter.P_MODE) and as the charge weights. @@ -14,13 +14,11 @@ Two rules hold for every mode, and they are what keeps modes safe: allocator._fill()'s last-resort pass still uses it. So "may not" is a range, and weights only set the order among batteries that may. -P1 has no price runs and no forecast (P3, P4). So both modes give power to the -house at any hour, and the only mode that closes a direction is Off. What P1 -changes is the solar order: while the site charges, Leftover solar batteries -weigh 0, so they get solar only once the Solar first batteries are full or at -their power limit. Selling (the owner's 2026-09-27 answer) is a per-battery -choice that arrives with the price runs in P3; `PackMode.sell` and the -`pack_sell` store key are reserved for it and read by nothing yet. +`mode_range()` is the switch alone (Off is [0, 0]). P3 adds the price runs: +`modetrade.decide()` narrows each battery's range by its role this tick +(hold for the expensive hours, charge from the grid, sell), and main.py files +the intersection. Selling is a per-battery choice (`pack_sell`, the owner's +2026-09-27 answer), for Leftover solar and Cheap hours only. """ from dataclasses import dataclass @@ -29,17 +27,18 @@ from .store import unit_key SOLAR_FIRST = "solar_first" LEFTOVER_SOLAR = "leftover_solar" -CHEAP_HOURS = "cheap_hours" # reserved for P3; not accepted in P1 +CHEAP_HOURS = "cheap_hours" # OPT-11 P3 -# The modes a battery may be set to in this release, in the order the page -# lists them. The first is the default when the store has no value. -MODES = (SOLAR_FIRST, LEFTOVER_SOLAR) +# The modes a battery may be set to, in the order the page and the HA select +# list them. The first is the default when the store has no value. A new mode +# is appended, never inserted: automations send the HA labels (P2). +MODES = (SOLAR_FIRST, LEFTOVER_SOLAR, CHEAP_HOURS) DEFAULT_MODE = SOLAR_FIRST # Store keys, per battery: `unit/<name>/<key>` (store.unit_key()). USE_KEY = "pack_use" MODE_KEY = "pack_mode" -SELL_KEY = "pack_sell" # reserved for P3 +SELL_KEY = "pack_sell" # OPT-11 P3: sell in the sell run def enabled(opts) -> bool: @@ -50,10 +49,15 @@ def enabled(opts) -> bool: @dataclass(frozen=True) class PackMode: - """One battery's choice: on or off, its mode, and (P3) selling.""" + """One battery's choice: on or off, its mode, and selling.""" use: bool = True mode: str = DEFAULT_MODE - sell: bool = False # reserved for P3, never read in P1 + sell: bool = False + + @property + def can_sell(self) -> bool: + """Selling applies to the price modes only; Solar first never sells.""" + return self.mode in (LEFTOVER_SOLAR, CHEAP_HOURS) @property def key(self) -> str: @@ -73,11 +77,10 @@ def read(data: dict, name: str) -> PackMode: def mode_range(pm: PackMode, rating_w: float) -> tuple: - """`(lo, hi)` in W for this battery's mode claim. Always holds 0 W. + """`(lo, hi)` in W for this battery's switch. Always holds 0 W. - Off asks for 0 W both ways. In P1 both modes may charge and give power up - to the battery's rating: Leftover solar holds back its power only in the - planned expensive hours, and there are none before P3. + Off asks for 0 W both ways; On allows the rating both ways. main.py files + this intersected with the role range from `modetrade.decide()`. """ if not pm.use: return 0.0, 0.0 @@ -92,7 +95,7 @@ def charge_weights(base, modes: dict, target_w: float): charges (`target_w < 0`), a Leftover solar battery weighs 0 and a Solar first battery keeps its weight, so the fill gives the Solar first batteries everything they can take before the last-resort pass reaches the others. - Giving power keeps `base` (P3 adds the expensive-run order). + Giving power keeps `base`; `modetrade.weights()` adds the run order. When no battery that is on would keep a positive weight (all Leftover solar, or every Solar first one at 0), `base` is returned unchanged, so the @@ -102,7 +105,8 @@ def charge_weights(base, modes: dict, target_w: float): return base names = sorted(modes) w = {n: (1.0 if base is None else float(base.get(n, 1.0))) for n in names} - out = {n: (0.0 if modes[n].mode == LEFTOVER_SOLAR else w[n]) + out = {n: (0.0 if modes[n].mode in (LEFTOVER_SOLAR, CHEAP_HOURS) + else w[n]) for n in names} if not any(out[n] > 0.0 for n in names if modes[n].use): return base diff --git a/goodwe_controller/app/priceruns.py b/goodwe_controller/app/priceruns.py new file mode 100644 index 0000000..848b78e --- /dev/null +++ b/goodwe_controller/app/priceruns.py @@ -0,0 +1,203 @@ +"""OPT-11 P3: price runs. Which consecutive firm price slots are cheap, which +are expensive, and which one a battery may sell in. + +Pure: prices, the time and a few energy figures in, a `RunPlan` out. No I/O, +no clock. `modetrade.py` turns the plan into each battery's range and the +site's trade; main.py rebuilds the plan at most once per 15 minutes and keeps +a run that has started until its end (`keep_started()`). + +The owner's SAFETY-46 answer (2026-09-25): a trade is a run of consecutive +slots, not one 15-minute interval. OPT-11-design section 2 ("Prices") and +DECISIONS/OPT-11-battery-modes.md have the record. + +* The CHEAP run is the cheapest consecutive firm window long enough to put + the planned energy in at the chargers' combined rating. +* A slot is EXPENSIVE when its price is above the cheap run's mean by at + least the required spread (`cycle_cost_threshold_eur`, widened as + `TariffPlan.arbitrage()` widens it). Give runs are the maximal consecutive + expensive slots. Holding batteries cover the house in them. The mean is + the lower of the next cheap run's and `ref_eur_kwh`, the cheap run the + batteries last filled in (main.py keeps it for 12 h): energy bought at + 03:00 is still worth that price at 08:00, when the next cheap run in sight + is today's dearer midday (measured: without it a Cheap hours battery spent + its night charge on flat morning prices, then had nothing at 19:00). +* The SELL run is the dearest consecutive window inside one give run long + enough to sell the sellers' energy at their rating, with no slot below 0 + (section 17 of the spec: never export at a negative price). +* A provisional (carried) price is never part of any run (section 8.3). +""" + +import math +from dataclasses import dataclass +from datetime import datetime, timedelta + +from .price import _cover_table + +# How far ahead runs are looked for. A day: tonight's cheap hours and the next +# evening's expensive ones, without holding a battery for a peak two days out. +HORIZON = timedelta(hours=24) + +# No plan, and why (the page words are in homeview / ui_text). +NO_PRICES = "no_prices" # fewer than two firm slots ahead +NOT_WORTH = "not_worth" # no slot clears the required spread + + +@dataclass(frozen=True) +class Run: + start: datetime + end: datetime + mean_eur_kwh: float + + def holds(self, when: datetime) -> bool: + return self.start <= when < self.end + + +@dataclass(frozen=True) +class RunPlan: + """What the prices say for the next day. `reason` is None when there is + a plan (a cheap run and at least one give run), else why there is none.""" + cheap: Run | None + give: tuple + sell: Run | None + level_eur_kwh: float | None + reason: str | None + # A slot after the cheap run clears the spread over the CHEAP RUN'S OWN + # price (not the reference): only then is buying in it worth a cycle. + charge_worth: bool = False + + @property + def on(self) -> bool: + return self.reason is None + + def give_at(self, when): + return next((g for g in self.give if g.holds(when)), None) + + def next_give(self, when): + """The give run under way at `when`, else the next one, else None.""" + return next((g for g in self.give if g.end > when), None) + + def charge_useful(self) -> bool: + """Charging in the cheap run pays only if, after it, a slot clears + the spread over the cheap run's own price.""" + return self.cheap is not None and self.charge_worth + + +def firm_slots(points, now: datetime, horizon: timedelta = HORIZON) -> list: + """`[(start, end, eur_kwh)]`, ascending: the firm slots that have not + ended and start within the horizon. A slot's span is TARIFF-14's rule + (`price._cover_table()`), so 15-minute and hourly series both work.""" + out = [] + for start, end, p in _cover_table(points): + if p.provisional or end <= now or start >= now + horizon: + continue + if end > start: + out.append((start, end, float(p.eur_per_kwh))) + return out + + +def _segments(slots) -> list: + """Split slots into runs of consecutive ones (each starts where the last + ended). A gap or a provisional slot breaks a run.""" + segs, cur = [], [] + for s in slots: + if cur and s[0] != cur[-1][1]: + segs.append(cur) + cur = [] + cur.append(s) + if cur: + segs.append(cur) + return segs + + +def _hours(s) -> float: + return (s[1] - s[0]).total_seconds() / 3600.0 + + +def _mean(win) -> float: + h = sum(_hours(s) for s in win) + return sum(_hours(s) * s[2] for s in win) / h + + +def _windows(segs, need_h): + """Every consecutive window that lasts at least `need_h` hours, shortest + such from each start. If no segment is that long, each whole segment.""" + out = [] + for seg in segs: + for i in range(len(seg)): + h, j = 0.0, i + while j < len(seg) and h < need_h - 1e-9: + h += _hours(seg[j]) + j += 1 + if h >= need_h - 1e-9: + out.append(seg[i:j]) + return out or [seg for seg in segs] + + +def need_hours(kwh, kw, slots) -> float: + """How long a run must last: `kwh` at `kw`, and at least one slot.""" + one = min((_hours(s) for s in slots), default=1.0) + if not (kwh and kw) or kwh <= 0 or kw <= 0: + return one + return max(one, float(kwh) / float(kw)) + + +def plan(points, now: datetime, *, required_eur_kwh: float, charge_kwh, + charge_kw, sell_kwh, sell_kw, horizon: timedelta = HORIZON, + ref_eur_kwh=None) -> RunPlan: + """The run plan for the next `horizon`. Ties go to the earliest window.""" + if not (isinstance(required_eur_kwh, (int, float)) + and math.isfinite(required_eur_kwh) and required_eur_kwh >= 0): + raise ValueError("required_eur_kwh must be a finite number >= 0") + slots = firm_slots(points, now, horizon) + if len(slots) < 2: + return RunPlan(None, (), None, None, NO_PRICES) + segs = _segments(slots) + wins = _windows(segs, need_hours(charge_kwh, charge_kw, slots)) + best = min(wins, key=lambda w: (round(_mean(w), 9), w[0][0])) + cheap = Run(best[0][0], best[-1][1], _mean(best)) + base = cheap.mean_eur_kwh if ref_eur_kwh is None else min( + cheap.mean_eur_kwh, float(ref_eur_kwh)) + level = base + float(required_eur_kwh) + # Expensive: clears the spread, strictly dearer than the cheap mean, and + # not part of the cheap run itself (a threshold of 0 must not overlap). + dear = [s for s in slots + if s[2] >= level and s[2] > cheap.mean_eur_kwh + and not (cheap.start <= s[0] < cheap.end)] + give_segs = _segments(dear) + give = tuple(Run(g[0][0], g[-1][1], _mean(g)) for g in give_segs) + worth = any(s[0] >= cheap.end and s[2] >= cheap.mean_eur_kwh + + float(required_eur_kwh) for s in dear) + if not give: + return RunPlan(cheap, (), None, level, NOT_WORTH) + # Sell: inside one give run, never over a slot priced below 0. + sellable = [part for g in give_segs + for part in _segments([s for s in g if s[2] >= 0.0])] + sell = None + if sellable: + sw = _windows(sellable, need_hours(sell_kwh, sell_kw, slots)) + top = max(sw, key=lambda w: (round(_mean(w), 9), + -w[0][0].timestamp())) + sell = Run(top[0][0], top[-1][1], _mean(top)) + return RunPlan(cheap, give, sell, level, None, worth) + + +def keep_started(old: RunPlan | None, new: RunPlan, now: datetime) -> RunPlan: + """A run under way keeps going to its end (no flapping on a new plan): the + cheap run, the give run and the sell run each come from `old` while `old` + holds `now` in it. The rest is `new`. A safety or peak rule can still stop + a run at any tick; that is not decided here.""" + if old is None or not old.on: + return new + cheap = old.cheap if old.cheap and old.cheap.holds(now) else new.cheap + sell = old.sell if old.sell and old.sell.holds(now) else new.sell + g_old = old.give_at(now) + give = new.give + if g_old is not None: + give = (g_old,) + tuple(g for g in new.give + if g.start >= g_old.end) + if cheap is new.cheap and sell is new.sell and g_old is None: + return new + worth = old.charge_worth if cheap is old.cheap else new.charge_worth + return RunPlan(cheap, give, sell, new.level_eur_kwh if new.on + else old.level_eur_kwh, None if give else new.reason, + worth) diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 2728bb5..ce1f46b 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -314,11 +314,11 @@ /* ---------------- Batteries (UX-13 P3) ---------------- */ // One card per battery. With battery modes on (`mode_key` in /status) each // card has an On/Off switch and a mode list, sent as `pack_use` and - // `pack_mode` through /action (OPT-11 P1). Selling and cheap-hours charging - // are shown greyed out until OPT-11 P3. The Now, Today and Why lines are + // `pack_mode` through /action (OPT-11 P1), and a selling switch, sent as + // `pack_sell` (P3; Leftover solar and Cheap hours only). The Now, Today and Why lines are // homeview.py's sentences. The Simple settings view draws the same switch // and list into its own card (simpleHost). - const MODES = ["solar_first", "leftover_solar"]; + const MODES = ["solar_first", "leftover_solar", "cheap_hours"]; const say = (text, vars) => Object.keys(vars).reduce((x, k) => x.replace("{" + k + "}", vars[k]), text); let packBusy = false; let simpleHost = null; @@ -331,6 +331,7 @@ const j = await r.json().catch(() => ({})); if (!r.ok) toast(j.error || t("toast.failed")); else if (what === "pack_use") toast(say(value ? t("batteries.toast.on") : t("batteries.toast.off"), { name: b.name })); + else if (what === "pack_sell") toast(say(value ? t("batteries.toast.sell_on") : t("batteries.toast.sell_off"), { name: b.name })); else toast(say(t("batteries.toast.mode"), { name: b.name, mode: t("batteries.choice." + value + ".name") })); } catch (e) { toast(t("toast.failed")); } finally { packBusy = false; } @@ -345,15 +346,17 @@ function modeSelect(b, i, where, lid) { return h("select", { class: "sel", id: "bsel-" + where + i, "aria-labelledby": lid, disabled: !b.use, onchange: (e) => packAct("pack_mode", b, e.target.value) }, - ...MODES.map((k) => h("option", { value: k, selected: b.mode_choice === k }, t("batteries.choice." + k + ".name"))), - h("option", { value: "", disabled: true }, t("batteries.later"))); + ...MODES.map((k) => h("option", { value: k, selected: b.mode_choice === k }, t("batteries.choice." + k + ".name")))); } - function sellRow(i, where) { + function sellRow(b, i, where) { const lid = "bsl-" + where + i; + const can = b.use && b.can_sell === true; return h("div", { class: "f inline" }, - h("div", {}, h("div", { class: "lbl", id: lid }, t("batteries.sell.name")), h("div", { class: "help" }, t("batteries.sell.description"))), - h("div", { class: "ctl" }, h("button", { type: "button", class: "switch", role: "switch", "aria-checked": "false", - "aria-labelledby": lid, disabled: true }))); + h("div", {}, h("div", { class: "lbl", id: lid }, t("batteries.sell.name")), + h("div", { class: "help" }, b.can_sell === true ? t("batteries.sell.description") : t("batteries.sell.off"))), + h("div", { class: "ctl" }, h("button", { type: "button", class: "switch", role: "switch", id: "bsw-sell-" + where + i, + "aria-checked": String(can && b.sell === true), "aria-labelledby": lid, disabled: !can, + onclick: () => packAct("pack_sell", b, !(b.sell === true)) }))); } function todayLines(b) { if (!b.today || !b.today.length) return b.today_line || "–"; @@ -373,7 +376,7 @@ h("label", { class: "lbl small", for: "bsel-c" + i }, t("batteries.mode")), modeSelect(b, i, "c", null), h("div", { class: "help" }, t("batteries.choice." + b.mode_key + ".description")), - sellRow(i, "c")) : null, + sellRow(b, i, "c")) : null, levelBar(b.level_pct, b.name), h("dl", { class: "kv" }, h("dt", {}, t("batteries.level")), h("dd", {}, lvl + stored), diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index ee0118f..abd574f 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -87,19 +87,20 @@ "on": "On", "off": "Off", "choice": { "solar_first": {"name": "Solar first", "description": "Charges from solar before the other batteries and covers the house."}, - "leftover_solar": {"name": "Leftover solar", "description": "Charges from solar the other batteries cannot take, and covers the house."}, + "leftover_solar": {"name": "Leftover solar", "description": "Gets solar the others cannot take, charges in cheap hours and gives power in expensive ones."}, + "cheap_hours": {"name": "Cheap hours only", "description": "Charges in the cheapest hours and gives power in the expensive ones."}, "off": {"name": "Off", "description": "Rests, and helps only when the peak limit needs it."} }, - "later": "Cheap hours only, coming later", "today": "Today", "why": "Why", - "sell": {"name": "Sell in expensive hours", "description": "Selling comes in a later update."}, + "sell": {"name": "Sell in expensive hours", "description": "Also sells to the grid in the most expensive hours.", "off": "Not for Solar first."}, "modes_off": {"name": "Battery modes are off"}, "how": {"name": "How the modes work", "description": "Which battery gets solar first, and when each gives power.", "solar_first": {"description": "Solar first gets spare solar before the other batteries, and covers the house at any hour."}, - "leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, and also covers the house."}, + "leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, charges in cheap hours, and saves its power for expensive hours."}, + "cheap_hours": {"description": "Cheap hours only charges in the cheapest hours and gives power in the expensive ones."}, "off": {"description": "Off rests the battery and starts no monthly cycle, but the peak limit may still use it."}, - "rules": {"description": "The peak limit and the safety stops always come first, and charging from the grid and selling come later."}}, - "toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}."}}, + "rules": {"description": "The peak limit and the safety stops come first, and while one battery charges from the grid the others rest."}}, + "toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}.", "sell_on": "{name} sells in expensive hours.", "sell_off": "{name} does not sell."}}, "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, "choices_later": { @@ -250,7 +251,7 @@ }, "home_words": { "mode_house": "Follows the house", - "modes": {"solar_first": "Solar first", "leftover_solar": "Leftover solar", "off": "Off"}, + "modes": {"solar_first": "Solar first", "leftover_solar": "Leftover solar", "cheap_hours": "Cheap hours only", "off": "Off"}, "attn_shadow": "Shadow mode is on", "attn_shadow_body": "The add-on decides everything, but every inverter stays at 0 W.", "zero_held": "Held at 0 W", @@ -326,10 +327,19 @@ "leftover": "It gets the solar that Solar first batteries cannot take.", "leftover_alone": "No Solar first battery is on, so it gets solar first.", "covers_house": "It gives power to cover the house.", - "other_refuses": "{name} refuses to give power, so this battery takes over." + "other_refuses": "{name} refuses to give power, so this battery takes over.", + "grid_charge": "Prices are low, so it charges from the grid.", + "rests_charge": "Another battery charges from the grid, so it rests.", + "selling": "Prices are high, so it sells to the grid.", + "expensive": "Prices are high, so it covers the house.", + "saves": "Saves its power for {at}.", + "saves_later": "Saves its power for higher prices.", + "no_prices": "No prices, so it follows the house.", + "no_spread": "Prices differ too little, so it follows the house." }, "today": { "not_planned": "Not planned yet.", + "no_runs": "No cheap or expensive hours left today.", "off": "Off, so no monthly cycle today.", "house": "Follows the house.", "house_would": "Would follow the house.", @@ -356,6 +366,10 @@ "give_what": "Gives up to {kwh}, to the house first.", "give_what_would": "Would give up to {kwh}, to the house first.", "give_why": "Highest published price, {eur} per kWh.", + "sell_what": "Sells up to {kwh}, to the house first.", + "sell_what_would": "Would sell up to {kwh}, to the house first.", + "cheap_why": "Cheapest hours, about {eur} per kWh.", + "dear_why": "Expensive hours, about {eur} per kWh.", "give_amount": "Worth up to {eur} at that price.", "cycle_start": "Starts the monthly battery cycle.", "cycle_start_would": "Would start the monthly battery cycle.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 2f3f83a..f374c88 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -84,19 +84,20 @@ "on": "Aan", "off": "Uit", "choice": { "solar_first": {"name": "Eerst zonne-energie", "description": "Laadt met zonne-energie vóór de andere batterijen en dekt het huis."}, - "leftover_solar": {"name": "Overschot zonne-energie", "description": "Laadt met zonne-energie die de andere batterijen niet opnemen, en dekt het huis."}, + "leftover_solar": {"name": "Overschot zonne-energie", "description": "Krijgt zonne-energie die de andere niet opnemen, laadt in goedkope uren en levert in dure uren."}, + "cheap_hours": {"name": "Alleen goedkope uren", "description": "Laadt in de goedkoopste uren en levert in de dure uren."}, "off": {"name": "Uit", "description": "Rust, en helpt alleen als de piekgrens haar nodig heeft."} }, - "later": "Alleen goedkope uren, volgt later", "today": "Vandaag", "why": "Waarom", - "sell": {"name": "Verkopen in dure uren", "description": "Verkopen komt in een latere update."}, + "sell": {"name": "Verkopen in dure uren", "description": "Verkoopt ook aan het net in de duurste uren.", "off": "Niet voor Eerst zonne-energie."}, "modes_off": {"name": "Batterijmodi staan uit"}, "how": {"name": "Zo werken de modi", "description": "Welke batterij eerst zonne-energie krijgt, en wanneer elke batterij levert.", "solar_first": {"description": "Eerst zonne-energie krijgt het overschot vóór de andere batterijen, en dekt het huis op elk uur."}, - "leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, en dekt ook het huis."}, + "leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, laadt in goedkope uren en spaart haar stroom voor dure uren."}, + "cheap_hours": {"description": "Alleen goedkope uren laadt in de goedkoopste uren en levert in de dure uren."}, "off": {"description": "Uit laat de batterij rusten en start geen maandelijkse cyclus, maar de piekgrens mag haar nog gebruiken."}, - "rules": {"description": "De piekgrens en de veiligheidsstops gaan altijd voor, en laden van het net en verkopen volgen later."}}, - "toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}."}}, + "rules": {"description": "De piekgrens en de veiligheidsstops gaan voor, en terwijl een batterij van het net laadt rusten de andere."}}, + "toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}.", "sell_on": "{name} verkoopt in dure uren.", "sell_off": "{name} verkoopt niet."}}, "settings": {"name": "Instellingen", "description": "De instellingen staan hieronder per taak.", "open": "Instellingen openen"} }, "choices_later": {"region": {"wallonia": "Wallonië, nog geen standaardwaarde", "brussels": "Brussel, nog geen standaardwaarde"}}, @@ -224,7 +225,7 @@ }, "home_words": { "mode_house": "Volgt het huis", - "modes": {"solar_first": "Eerst zonne-energie", "leftover_solar": "Overschot zonne-energie", "off": "Uit"}, + "modes": {"solar_first": "Eerst zonne-energie", "leftover_solar": "Overschot zonne-energie", "cheap_hours": "Alleen goedkope uren", "off": "Uit"}, "attn_shadow": "Schaduwmodus staat aan", "attn_shadow_body": "De add-on beslist alles, maar elke omvormer blijft op 0 W.", "zero_held": "Op 0 W gehouden", @@ -268,10 +269,19 @@ "leftover": "Ze krijgt de zonne-energie die de batterijen met Eerst zonne-energie niet opnemen.", "leftover_alone": "Geen batterij met Eerst zonne-energie staat aan, dus zij krijgt eerst zonne-energie.", "covers_house": "Ze levert stroom om het huis te dekken.", - "other_refuses": "{name} weigert te leveren, dus deze batterij neemt het over." + "other_refuses": "{name} weigert te leveren, dus deze batterij neemt het over.", + "grid_charge": "De prijs is laag, dus ze laadt van het net.", + "rests_charge": "Een andere batterij laadt van het net, dus deze rust.", + "selling": "De prijs is hoog, dus ze verkoopt aan het net.", + "expensive": "De prijs is hoog, dus ze dekt het huis.", + "saves": "Spaart haar stroom voor {at}.", + "saves_later": "Spaart haar stroom voor hogere prijzen.", + "no_prices": "Geen prijzen, dus ze volgt het huis.", + "no_spread": "De prijzen verschillen te weinig, dus ze volgt het huis." }, "today": { "not_planned": "Nog niet gepland.", + "no_runs": "Vandaag geen goedkope of dure uren meer.", "off": "Uit, dus vandaag geen maandelijkse cyclus.", "house": "Volgt het huis.", "house_would": "Zou het huis volgen.", @@ -298,6 +308,10 @@ "give_what": "Levert tot {kwh}, eerst aan het huis.", "give_what_would": "Zou tot {kwh} leveren, eerst aan het huis.", "give_why": "Hoogste gepubliceerde prijs, {eur} per kWh.", + "sell_what": "Verkoopt tot {kwh}, eerst aan het huis.", + "sell_what_would": "Zou tot {kwh} verkopen, eerst aan het huis.", + "cheap_why": "Goedkoopste uren, ongeveer {eur} per kWh.", + "dear_why": "Dure uren, ongeveer {eur} per kWh.", "give_amount": "Tot {eur} waard aan die prijs.", "cycle_start": "Start de maandelijkse batterijcyclus.", "cycle_start_would": "Zou de maandelijkse batterijcyclus starten.", diff --git a/goodwe_controller/app/web.py b/goodwe_controller/app/web.py index 93d1a49..ea953fa 100644 --- a/goodwe_controller/app/web.py +++ b/goodwe_controller/app/web.py @@ -34,7 +34,8 @@ succeeds, so the page stops opening the wizard by itself (uipage.setup_needed). UX-15's setup-only mode serves these routes from `setuponly.SetupOnly`, which commands nothing; there `/action` answers 409. OPT-11 P1 adds two `/action` values, `pack_use` and `pack_mode`, which set one -battery's on/off switch or mode in the store (Controller._pack_action). They +battery's on/off switch or mode in the store (Controller._pack_action); P3 adds +`pack_sell`, that battery's selling switch. They are the only actions that name a battery; the configuration routes still reach none of them. """ @@ -58,7 +59,7 @@ from .uimodel import DeriveError, options_to_ui _LOG = logging.getLogger("goodwe.web") # OPT-11: the per-battery actions, which name a battery and a value. -PACK_ACTIONS = ("pack_use", "pack_mode") +PACK_ACTIONS = ("pack_use", "pack_mode", "pack_sell") # UX-13 P1: the page lives in app/static/ as three files - index.html, # app.css, app.js - plus the page words from app/ui_text/<lang>.json (English diff --git a/goodwe_controller/test_batteries_screen.py b/goodwe_controller/test_batteries_screen.py index 4ddc917..4654f01 100644 --- a/goodwe_controller/test_batteries_screen.py +++ b/goodwe_controller/test_batteries_screen.py @@ -120,13 +120,15 @@ for st, want in WANT.items(): for e, n in zip(en, nl))) _modes = ROWS[("modes", "en")] -check("modes on: each row carries its switch and mode, and Today says the " - "mode's plan is not made yet (OPT-11 P3/P4), without inventing one", +check("modes on: each row carries its switch and mode; Today says Solar " + "first follows the house and, before any cycle has made the price " + "runs (OPT-11 P3), that Leftover solar is not planned yet", _modes["modes_on"] is True and [(b["use"], b["mode_key"]) for b in _modes["batteries"]] == [(True, "solar_first"), (True, "leftover_solar")] - and all(b["today_line"] == EN["home_words"]["today"]["not_planned"] - for b in _modes["batteries"])) + and [b["today_line"] for b in _modes["batteries"]] + == [EN["home_words"]["today"]["house"], + EN["home_words"]["today"]["not_planned"]]) _off = ROWS[("running", "en")] check("modes off: no switch, no mode, and Today and Why say it follows the " "house", _off["modes_on"] is False @@ -212,13 +214,19 @@ print(f" {_kinds}") check("Off: no 'follows the house', no trade, no monthly cycle for B", not _kinds[1] and "house" in _kinds[0]) _p = build("off", now=MORNING) -_m = build("modes", now=MORNING) +# OPT-11 P3: with modes on the plan shows each battery's price runs, which a +# control cycle makes; make them as the cycle does (`_mode_roles()`). +_mc = D.controller("modes") +_mc._mode_roles(MORNING, None) +_m = build("modes", c=_mc, now=MORNING) _kinds = {i: {r["kind"] for r in _p["plan"]["runs"] if r["battery"] == i} for i in (0, 1)} print(f" morning: {_kinds}, lines {_p['plan']['lines']}") -check("in the morning, with trades and a cycle ahead: A has them, Off B has " - "no block and waits for no cycle (with B on, it does)", - {"house", "grid", "give", "cycle"} <= _kinds[0] and not _kinds[1] +check("in the morning, with trades and a cycle ahead: Solar first A follows " + "the house and has its cycle but no price block (OPT-11 P3: Solar first " + "never trades), Off B has no block and waits for no cycle; with B on " + "(Leftover solar) B has its cheap and expensive runs and waits", + {"house", "cycle"} == _kinds[0] and not _kinds[1] and not any(B_NAME in x for x in _p["plan"]["lines"]) and {"grid", "give"} <= {r["kind"] for r in _m["plan"]["runs"] if r["battery"] == 1} @@ -290,6 +298,22 @@ _cases = [ (dict(mode=packmode.LEFTOVER_SOLAR, sf_ahead=True), "leftover"), (dict(mode=packmode.LEFTOVER_SOLAR), "leftover_alone"), ({}, "solar_first"), + # OPT-11 P3: the battery's role in the price runs, and no plan. + (dict(mode=packmode.CHEAP_HOURS, role="charge"), "grid_charge"), + (dict(role="rest"), "rests_charge"), + (dict(mode=packmode.CHEAP_HOURS, role="sell", giving=True), "selling"), + (dict(mode=packmode.LEFTOVER_SOLAR, role="give", giving=True), + "expensive"), + (dict(mode=packmode.LEFTOVER_SOLAR, role="hold", has_at=True), "saves"), + (dict(mode=packmode.CHEAP_HOURS, role="hold"), "saves_later"), + (dict(mode=packmode.CHEAP_HOURS, role="house", plan="no_prices"), + "no_prices"), + (dict(mode=packmode.LEFTOVER_SOLAR, role="house", plan="no_spread", + giving=True), "no_spread"), + # ...and the urgent reasons still come first. + (dict(role="charge", refused=-1), "refuses_charge"), + (dict(role="sell", peak=True), "peak"), + (dict(role="hold", off=True), "off"), ] _wrong = [(kw, want, why(**kw)) for kw, want in _cases if why(**kw) != want] print(f" {_wrong}") @@ -336,9 +360,13 @@ _r = asyncio.run(_serve("modes", [ "nl"), ({"action": "pack_use", "unit": B, "value": True}, "en"), ({"action": "pack_mode", "unit": A, "value": "cheap_hours"}, "en"), + ({"action": "pack_sell", "unit": A, "value": True}, "en"), + ({"action": "pack_sell", "unit": A, "value": "yes"}, "en"), + ({"action": "pack_mode", "unit": A, "value": "sell_only"}, "en"), ])) (_s1, _j1), (_, _st1), (_s2, _j2), (_, _st2), (_s3, _), (_, _st3), \ - (_s4, _j4), (_, _st4) = _r + (_s4, _j4), (_, _st4), (_s5, _j5), (_, _st5), (_s6, _j6), (_, _st6), \ + (_s7, _j7), (_, _st7) = _r check("switch B off: 200, and /status shows B Off with 'You switched it off.'", _s1 == 200 and _j1["result"]["use"] is False and _st1["batteries"][1]["mode_key"] == "off" @@ -351,9 +379,17 @@ check("set A to Leftover solar: 200, and /status?lang=nl shows it in Dutch", check("switch B back on: its stored mode returns", _s3 == 200 and _st3["batteries"][1]["mode_key"] == packmode.LEFTOVER_SOLAR) -check("a mode the list only shows greyed out is refused with a plain 400, and " - "nothing changes", _s4 == 400 and _j4["ok"] is False and _j4["error"] - and _st4["batteries"][0]["mode_choice"] == packmode.LEFTOVER_SOLAR) +check("OPT-11 P3: Cheap hours only is a mode now: 200, and /status shows it", + _s4 == 200 and _st4["batteries"][0]["mode_choice"] + == packmode.CHEAP_HOURS and _st4["batteries"][0]["can_sell"] is True) +check("...selling on for A: 200, stored, and /status says so", + _s5 == 200 and _j5["result"]["sell"] is True + and _st5["batteries"][0]["sell"] is True) +check("...a selling value that is not true or false, and a mode that does not " + "exist, are refused with a plain 400, and nothing changes", + _s6 == 400 and _j6["error"] and _s7 == 400 and _j7["error"] + and _st7["batteries"][0]["sell"] is True + and _st7["batteries"][0]["mode_choice"] == packmode.CHEAP_HOURS) _r = asyncio.run(_serve("running", [ ({"action": "pack_use", "unit": B, "value": False}, "en")])) check("with battery modes off the switch is refused with the plain reason, " @@ -378,12 +414,16 @@ _acts = set(re.findall(r'packAct\("(\w+)"', JS)) check(f"the cards post only the existing actions ({sorted(_acts)}), as " f"{{action, unit, value}}", _acts == set(web.PACK_ACTIONS) and "action: what, unit: b.name, value: value" in JS) -check("the switch is a real switch and the list names cheap hours as coming " - "later, not choosable", 'role: "switch"' in JS and '"aria-checked"' in JS - and 'h("option", { value: "", disabled: true }, t("batteries.later"))' - in JS) -check("the selling switch is greyed out until OPT-11 P3 (no pack_sell is " - "posted)", "pack_sell" not in JS and "disabled: true })" in JS) +check("the switch is a real switch and the list offers the three modes, " + "cheap hours included, with nothing greyed out", + 'role: "switch"' in JS and '"aria-checked"' in JS + and 'const MODES = ["solar_first", "leftover_solar", "cheap_hours"];' + in JS and "batteries.later" not in JS) +check("the selling switch posts pack_sell, and is greyed out where selling " + "does not apply (Off, Solar first)", + 'packAct("pack_sell", b, ' in JS + and "const can = b.use && b.can_sell === true;" in JS + and "disabled: !can" in JS) _T = uipage.ui_text("en") _lay = uipage.layout(D.schema_ui(D.CONFIG), {"en": {}}) _simple = [f for g in _lay["groups"] for p in g["parts"] for f in p["fields"] diff --git a/goodwe_controller/test_modes.py b/goodwe_controller/test_modes.py index 2f47c4f..15280a4 100644 --- a/goodwe_controller/test_modes.py +++ b/goodwe_controller/test_modes.py @@ -335,11 +335,11 @@ _bad = [asyncio.run(_c.handle_action("pack_use", unit="inverter-z", asyncio.run(_c.handle_action("pack_use", unit=A, value=0)), asyncio.run(_c.handle_action("pack_use", unit=A, value=1)), asyncio.run(_c.handle_action("pack_mode", unit=A, - value=packmode.CHEAP_HOURS)), + value="sell_only")), asyncio.run(_c.handle_action("pack_mode", unit=A, value=None))] check("an unknown battery, a switch that is not true or false (0 and 1 " "included), and a mode " - "this release does not offer (Cheap hours arrives in P3) are refused, " + "that does not exist are refused, " "with a plain reason, and store nothing", all(isinstance(x, dict) and set(x) == {"error"} for x in _bad) and unit_key(A, packmode.MODE_KEY) not in _c.store.data diff --git a/goodwe_controller/test_modes_p3.py b/goodwe_controller/test_modes_p3.py new file mode 100644 index 0000000..33dc83e --- /dev/null +++ b/goodwe_controller/test_modes_p3.py @@ -0,0 +1,613 @@ +"""Runnable check for OPT-11 P3, price runs per battery. `python3 test_modes_p3.py` + +Drives the pure modules (priceruns, modetrade) and the REAL Controller +(tools/opt11p3_replay.py: read_inputs + cycle on a P1 meter, the arbiter, the +allocator and the peak guard, with two lagged model batteries), in simulated +time. DECISIONS/OPT-11-battery-modes.md has the record. + +1. With battery modes off, every command and trade is byte-identical to + release/1.0 7a00f12 on the trade path P3 changed (digests measured there), + and the harness would see a change there. +2. Price runs: consecutive, firm, sized by energy; give runs clear the spread; + the sell run sits in a give run with no slot below 0; a started run is kept. +3. Roles: a fuzz of modetrade.decide() and size() against the invariants. +4. The real controller over a day: no opposite-direction split, no grid + charge on Solar first, the quarter never above the aim while charging, no + sell below the floor or the spread, holding outside the expensive hours. +5. A refusal wins over a run. +6. No prices or too small a gap: the price modes follow the house; Solar first + alone never trades. +7. A run edge reseeds the loop (handover measured with and without). +8. The site Why row: a limit that pushes power up does not "hold it back" (F2). +9. The selling switch (`pack_sell`). +10. The Batteries screen: Why and Today lines from the roles and runs. + +Mutations (MUTATION.md, purged copies, graded over this file and the named +tests) are listed in the pull request. +""" + +import asyncio +import logging +import os +import random +import sys +from datetime import datetime, timedelta, timezone + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +from named_absence import nth, present # noqa: E402 +import opt11p3_identity as ident # noqa: E402 +import opt11p3_replay as rp # noqa: E402 +from app import homeview, messages, modetrade, packmode, priceruns # noqa +from app import arbitrage # noqa: E402 +from app.arbiter import Claim, P_ARBITRAGE, P_LOOP, P_PEAK, Resolution # noqa +from app.main import Controller, why_raised # noqa: E402 +from app.price import PricePoint, brussels # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +L = timezone(timedelta(hours=2)) +A, B = "inverter-a", "inverter-b" + +# ============================================================================ # +print("1. modes off: byte-identical to 7a00f12 on the trade path") +# Printed by tools/opt11p3_identity.py on release/1.0 7a00f12 (2026-09-29), +# goodwe-addon-checks:1. 1080 cycles each; the trade CHARGEs and DISCHARGEs. +AT_7A00F12 = { + "n1": "71245b227ca40bada4f71f57ea6154475f4b0bd60239c9ad4f80bffb0094514c", + "n2": "56cf28010b06765c29e5479abb815d7503d570b39240d82dfc818efa90c93722", + "n1_off": "71245b227ca40bada4f71f57ea6154475f4b0bd60239c9ad4f80bffb0094514c", + "n2_off": "56cf28010b06765c29e5479abb815d7503d570b39240d82dfc818efa90c93722", +} +_rows = {k: ident.run(**v)[0] for k, v in ident.SCENARIOS.items()} +_got = {k: ident.digest(v) for k, v in _rows.items()} +for k in AT_7A00F12: + print(f" {k} {'same' if _got[k] == AT_7A00F12[k] else 'DIFFERS'} " + f"{_got[k][:16]}") +check("with battery modes off (option absent or false), every command, " + "integrator, allocation and trade sentence equals 7a00f12's, at one " + "inverter and at two", _got == AT_7A00F12) +_acts = {r[-1][0] for r in _rows["n2"] if r[-1]} +check("...and the runs reach the trade P3 now skips with modes on: a charge " + "and a sale", {arbitrage.CHARGE, arbitrage.DISCHARGE} <= _acts) + + +def _moved(scn, patch): + """Does `patch` (applied before each cycle) move scenario `scn`?""" + real = ident._feed + + def feed(c, t): + patch(c) + real(c, t) + ident._feed = feed + try: + return ident.digest(ident.run(**ident.SCENARIOS[scn])[0]) \ + != AT_7A00F12[scn] + finally: + ident._feed = real + + +def _as_if_trade_ended(c): + c._mode_trade_was = True # the run-edge reseed, leaking to modes off + + +def _moved_headroom(scn): + """Does an unmeasured headroom (the expression P3 hoisted) move it?""" + from app import peakguard + real = peakguard.charge_headroom_w + peakguard.charge_headroom_w = lambda g: None + try: + return ident.digest(ident.run(**ident.SCENARIOS[scn])[0]) \ + != AT_7A00F12[scn] + finally: + peakguard.charge_headroom_w = real + + +check("non-vacuous: a run-edge reseed leaking into modes off moves n2, and so " + "does the headroom P3 hoisted, if it went unmeasured", + _moved("n2", _as_if_trade_ended) and _moved_headroom("n1")) + +# ============================================================================ # +print("\n2. price runs") +D0 = datetime(2026, 9, 9, 0, 0, tzinfo=L) + + +def pts(prices, start=D0, minutes=15, provisional=()): + return [PricePoint(start=brussels(start + timedelta(minutes=minutes * i)), + eur_per_kwh=p, provisional=i in provisional) + for i, p in enumerate(prices)] + + +# 24 h of quarters: cheap 02:00-04:00 (and one cheaper single quarter at +# 05:00), dear 18:00-20:00 with a peak quarter at 19:00, flat otherwise. +DAY = [0.30] * 96 +for i in range(8, 16): + DAY[i] = 0.10 +DAY[20] = 0.05 +for i in range(72, 80): + DAY[i] = 0.50 +DAY[76] = 0.70 +P = pts(DAY) +NOW = D0 + timedelta(minutes=5) +r1 = priceruns.plan(P, NOW, required_eur_kwh=0.25, charge_kwh=5.0, + charge_kw=2.5, sell_kwh=0.0, sell_kw=0.0) +r2 = priceruns.plan(P, NOW, required_eur_kwh=0.25, charge_kwh=0.0, + charge_kw=0.0, sell_kwh=2.5, sell_kw=2.5) +print(f" 2 h need: {r1.cheap}; give {r1.give}") +check("the cheap run lasts what the energy needs at the rating (5 kWh at " + "2.5 kW = 2 h) and is the cheapest such consecutive window, not the " + "cheapest single quarter", + r1.cheap.start == D0 + timedelta(hours=2) + and r1.cheap.end == D0 + timedelta(hours=4) + and abs(r1.cheap.mean_eur_kwh - 0.10) < 1e-9) +check("...with nothing to charge, one quarter: the cheapest one", + r2.cheap.start == D0 + timedelta(hours=5) + and r2.cheap.end == D0 + timedelta(hours=5, minutes=15)) +check("give runs are the consecutive quarters at least the required spread " + "above the cheap run (0.10 + 0.25): 18:00-20:00, one run", + r1.on and len(r1.give) == 1 + and r1.give[0].start == D0 + timedelta(hours=18) + and r1.give[0].end == D0 + timedelta(hours=20)) +check("the sell run is the dearest window inside a give run, sized by the " + "sellers' energy (2.5 kWh at 2.5 kW = 1 h)", + r2.sell.end - r2.sell.start == timedelta(hours=1) + and r1.give[0].start <= r2.sell.start < r2.sell.end <= r1.give[0].end + and r2.sell.start <= D0 + timedelta(hours=19) < r2.sell.end) +_flat = priceruns.plan(pts([0.3] * 96), NOW, required_eur_kwh=0.1, + charge_kwh=5, charge_kw=2.5, sell_kwh=0, sell_kw=0) +_thr0 = priceruns.plan(pts([0.3] * 96), NOW, required_eur_kwh=0.0, + charge_kwh=5, charge_kw=2.5, sell_kwh=0, sell_kw=0) +check("a flat day has no plan (`not_worth`), even with a threshold of 0: the " + "cheap run never counts as its own expensive run", + _flat.reason == priceruns.NOT_WORTH and not _flat.give + and _thr0.reason == priceruns.NOT_WORTH) +_prov = priceruns.plan(pts(DAY, provisional=set(range(74, 96))), NOW, + required_eur_kwh=0.25, charge_kwh=5, charge_kw=2.5, + sell_kwh=2.5, sell_kw=2.5) +check("a provisional (carried) price is never part of a run (section 8.3)", + all(g.end <= D0 + timedelta(hours=18, minutes=30) for g in _prov.give) + and (_prov.sell is None + or _prov.sell.end <= D0 + timedelta(hours=18, minutes=30))) +_neg = list(DAY) +_neg[76] = -0.05 +_rn = priceruns.plan(pts(_neg), NOW, required_eur_kwh=0.25, charge_kwh=0, + charge_kw=0, sell_kwh=10.0, sell_kw=2.5) +check("the sell run never spans a quarter priced below 0 (section 17)", + _rn.sell is not None and not (_rn.sell.start <= D0 + timedelta( + hours=19) < _rn.sell.end)) +# All prices below 0 but one: the give run holds negative quarters (they +# clear the spread over an even lower cheap run), and the sale must skip them. +_allneg = [-0.30] * 96 +for i in range(8, 16): + _allneg[i] = -0.40 +for i in range(72, 80): + _allneg[i] = -0.05 +_allneg[76] = 0.10 +_rneg = priceruns.plan(pts(_allneg), NOW, required_eur_kwh=0.15, + charge_kwh=0, charge_kw=0, sell_kwh=2.5, sell_kw=2.5) +check("...even when the whole give run is below 0 but one quarter: the sale " + "is that quarter only", + _rneg.on and _rneg.sell is not None + and _rneg.sell.start == D0 + timedelta(hours=19) + and _rneg.sell.end == D0 + timedelta(hours=19, minutes=15)) +# A spike inside the cheap run clears the spread over the run's own mean: +# it must not also be a give run (charge and give would overlap). +_sp = [0.50] * 96 +for i in range(8, 16): + _sp[i] = 0.02 +_sp[15] = 0.20 +_rsp = priceruns.plan(pts(_sp), NOW, required_eur_kwh=0.05, charge_kwh=5.0, + charge_kw=2.5, sell_kwh=0, sell_kw=0) +check("no give run overlaps the cheap run, even a quarter inside it that " + "clears the spread over the run's mean", + _rsp.cheap.start == D0 + timedelta(hours=2) + and all(g.end <= _rsp.cheap.start or g.start >= _rsp.cheap.end + for g in _rsp.give)) +_few = priceruns.plan(pts([0.1]), NOW, required_eur_kwh=0.1, charge_kwh=1, + charge_kw=1, sell_kwh=0, sell_kw=0) +check("fewer than two firm slots: no plan (`no_prices`)", + _few.reason == priceruns.NO_PRICES) +_mid = D0 + timedelta(hours=3) +_new = priceruns.plan(P, _mid, required_eur_kwh=0.25, charge_kwh=0.0, + charge_kw=0.0, sell_kwh=0.0, sell_kw=0.0) +_kept = priceruns.keep_started(r1, _new, _mid) +check("a run under way is kept to its end when a new plan would move it " + "(no flapping), and a run not yet started is not", + _new.cheap != r1.cheap and _kept.cheap == r1.cheap + and priceruns.keep_started(r1, _new, NOW).cheap == _new.cheap) +_late = priceruns.plan(P, D0 + timedelta(hours=20, minutes=5), + required_eur_kwh=0.25, charge_kwh=5, charge_kw=2.5, + sell_kwh=0, sell_kw=0) +check("a run that has ended is not planned again, and nothing beyond the " + "firm prices is invented", + all(g.start >= D0 + timedelta(hours=20) for g in _late.give) + and not _late.on) + +# ============================================================================ # +print("\n3. roles: modetrade.decide() fuzz") +rnd = random.Random(311) +_bad = [] +_seen = set() +for _ in range(20000): + n = rnd.choice((1, 2, 3)) + packs = [] + for k in range(n): + packs.append(modetrade.Pack( + f"inv-{k}", rnd.random() > 0.15, + rnd.choice(packmode.MODES), rnd.random() > 0.5, + rnd.choice((1000.0, 2500.0, 5000.0)), + rnd.choice((None, 5.0, 19.0, 20.0, 21.0, 60.0, 95.0, 99.0)), + rnd.choice((None, 5.0, 10.0)), live=rnd.random() > 0.1, + idle=rnd.random() > 0.1, refused=rnd.choice((0, 0, 0, 1, -1)))) + t = D0 + timedelta(minutes=rnd.randrange(0, 24 * 60)) + runs = rnd.choice((None, r1, r2, _flat)) + ok_s = rnd.random() > 0.3 + ok_c = ok_s and rnd.random() > 0.3 + hr = rnd.choice((None, 0.0, 100.0, 499.0, 501.0, 3000.0)) + price = rnd.choice((None, -0.1, 0.0, 0.5)) + house = rnd.choice((None, -500.0, 800.0)) + was = rnd.random() > 0.7 + blocked = rnd.random() > 0.8 + tk = modetrade.decide(runs, t, packs, charge_ok=ok_c, sell_ok=ok_s, + trade_why="x", price_now=price, headroom_w=hr, + floor_pct=20.0, ceiling_pct=95.0, house_w=house, + charging_now=was, blocked=blocked) + _seen.add(tk.action) + by = {p.name: p for p in packs} + for name, (lo, hi) in tk.ranges.items(): + if not lo <= 0.0 <= hi: + _bad.append(("range without 0", name, lo, hi)) + for name, role in tk.roles.items(): + p = by[name] + if role == modetrade.CHARGE and (p.mode == packmode.SOLAR_FIRST + or p.refused < 0 or not p.use + or p.soc is None or p.soc >= 95.0): + _bad.append(("bad charger", p)) + if role == modetrade.SELL and (not p.sell or p.refused > 0 + or p.mode == packmode.SOLAR_FIRST + or p.soc is None or p.soc <= 20.0): + _bad.append(("bad seller", p)) + if not p.use and tk.ranges.get(name, (0.0, 0.0)) != (0.0, 0.0): + _bad.append(("off not 0", p)) + if tk.action == modetrade.CHARGE: + need = 0.0 if was else modetrade.START_W + if not (ok_c and hr is not None and hr > need and not blocked + and runs is not None and runs.cheap.holds(t)): + _bad.append(("charge without leave", ok_c, hr, blocked)) + for name, (lo, hi) in tk.ranges.items(): + if tk.roles[name] != modetrade.CHARGE and lo < 0.0: + _bad.append(("grid charge on a non-charger", by[name])) + s = modetrade.size(tk, (-7000.0, 7000.0), hr) + if not (s < 0 and -s <= min(-tk.ask_w, hr) + 1e-9): + _bad.append(("charge size", s, tk.ask_w, hr)) + if modetrade.size(tk, (-300.0, 300.0), hr) < -300.0: + _bad.append(("charge over the bound",)) + if tk.action == modetrade.SELL: + if not (ok_s and price is not None and price >= 0.0 and runs + is not None and runs.sell.holds(t) and house is not None): + _bad.append(("sell without leave", ok_s, price)) + s = modetrade.size(tk, (-7000.0, 2000.0), hr) + if not 0.0 < s <= 2000.0: + _bad.append(("sell size", s)) + if tk.action is None and modetrade.size(tk, (-1e4, 1e4), hr) != 0.0: + _bad.append(("no action but a size",)) +print(f" actions seen {sorted(map(str, _seen))}; {len(_bad)} bad: {_bad[:3]}") +check("20000 random ticks: every range holds 0 W; Off is [0, 0]; no Solar " + "first, refusing, full or unknown battery charges; no Solar first, " + "refusing or at-floor battery sells; while one charges no other may " + "charge; a charge needs the guard, the headroom (500 W to start) and " + "no stop this period, and is sized under the headroom; a sale needs a " + "price >= 0 in the sell run", not _bad + and {modetrade.CHARGE, modetrade.SELL, None} <= _seen) + +# ============================================================================ # +print("\n4. the real controller over a day (A Solar first, B Cheap hours + sell)") +# Wholesale; all-in (x + 0.12) x 1.06: cheap 0.148, flat 0.339, dear 0.551. +# With a cycle cost of 0.20 (0.30 widened) only 19:00-20:00 clears it. +DAYW = [0.20] * 96 * 2 +for i in list(range(4, 12)) + list(range(100, 108)): + DAYW[i] = 0.02 # 01:00-03:00 wholesale +for i in list(range(76, 80)) + list(range(172, 176)): + DAYW[i] = 0.40 # 19:00-20:00 +UTC0 = D0.astimezone(timezone.utc) +WPTS = [(UTC0 + timedelta(minutes=15 * i), 900, p) for i, p in enumerate(DAYW)] + + +def house_flat(w): + return [(UTC0.timestamp() - 10, float(w))] + + +AIM = rp.PEAK_CAP - 50 + + +def run_day(variant, *, house_w=2600.0, start_h=0.75, hours=21.0, + soc0=None, choice=None, refuse=(), n=2, check_cb=None, + patch=None, house=None, limits=None): + rows = [] + + def cb(c, h, now, pr): + sh = dict(c.allocation.shares) if c.allocation is not None and \ + c.allocation.shares else {} + rows.append(dict( + now=now, grid=h.grid(), shares=sh, + action=getattr(c.arb, "action", None), + winner=c.reason.split(" ->")[0], + roles=dict(c.mode_tick.roles) if c.mode_tick else {}, + soc={u: p.soc for u, p in h.plants.items()}, + p={u: p.p for u, p in h.plants.items()}, + runs=c.mode_runs, price=pr, why=c.why_words, + unmet=getattr(c.allocation, "unmet_w", 0) or 0)) + if check_cb: + check_cb(c, h, now, pr) + st, c = rp.run(variant, house or house_flat(house_w), WPTS, + UTC0 + timedelta(hours=start_h), 3600 * hours, check=cb, + soc0=soc0, choice=choice, refuse=refuse, n=n, patch=patch, + extra={"cycle_cost_threshold_eur": 0.20}, limits=limits) + return rows, st, c + + +ROWS, ST, _c4 = run_day("p3_ch_sell", soc0={"a": 60.0, "b": 30.0}) +charge = [r for r in ROWS if r["action"] == arbitrage.CHARGE] +sell = [r for r in ROWS if r["action"] == arbitrage.DISCHARGE] +print(f" {len(ROWS)} cycles, {len(charge)} charging, {len(sell)} selling; " + f"{rp.summary(ST)}") +check("B charged from the grid in the cheap run and sold in the dear one, " + "and A never took part in either", + charge and sell + and all(r["roles"][A] in (modetrade.REST, modetrade.HOUSE) + for r in charge + sell) + and all(r["now"].astimezone(L).hour in (0, 1, 2, 3) for r in charge) + and all(r["runs"].cheap.holds(r["now"]) for r in charge) + and all(r["now"].astimezone(L).hour == 19 for r in sell)) +_mixed = [r for r in ROWS if any(v > 0 for v in r["shares"].values()) + and any(v < 0 for v in r["shares"].values())] +check("no opposite-direction split on any cycle (every share one sign)", + not _mixed) +check("no grid charge on Solar first: while the site charges from the grid, " + "A's share is never below 0 W", + all(r["shares"].get(A, 0) >= 0 for r in charge)) +# The quarters the add-on itself banked (the P1 blocks, as the bill reads). +_chq = {int(r["now"].timestamp() // 900) for r in charge} +_qc = [b.offtake_avg_w for b in _c4.p1.blocks + if int(b.start.timestamp() // 900) in _chq] +print(f" banked quarters with a grid charge: {len(_qc)}, highest " + f"{max(_qc):.2f} W, aim {AIM} W") +check("never above the SAFETY-79 aim while grid charging: every banked " + "15-minute period with a grid charge is at most cap - margin", + _qc and max(_qc) <= AIM + 0.5) +check("...and the charge is sized to the headroom, not the rating: under a " + "2.6 kW house B charges well under its 2.5 kW", + max(-r["shares"].get(B, 0) for r in charge) < 1200) +_sold = [r for r in sell] +check("no sale below the floor or the spread: every sale cycle has B above " + "arbitrage_soc_floor (20 %) and a price at least cheap + required", + all(r["soc"]["b"] > 19.9 for r in _sold) + and all(r["price"] is not None and rp.all_in(r["price"]) + >= r["runs"].cheap.mean_eur_kwh + 0.30 - 1e-9 for r in _sold)) +_hold = [r for r in ROWS if r["roles"].get(B) == modetrade.HOLD] +check("outside the expensive hours B holds its power: never gives while " + "holding", _hold and all(r["shares"].get(B, 0) <= 0 for r in _hold)) +_give = [r for r in ROWS if r["roles"].get(B) in (modetrade.GIVE, + modetrade.SELL)] +check("...and gives only in the expensive hours (19:00-20:00)", + all(r["now"].astimezone(L).hour == 19 for r in _give)) + + +def starts(rows, kind): + return sum(1 for a, b in zip(rows, rows[1:]) + if a["action"] != kind and b["action"] == kind) + + +check("the sale starts once and runs to its end: no on-off while the two " + "batteries' 5 kW discharge makes the peak guard read 'engaged'", + starts(ROWS, arbitrage.DISCHARGE) == 1) + +# B's inverter can only take 1000 W: the trade asks for that, not its rating. +ROWS_U, _, _ = run_day("p3_ch_sell", hours=1.0, house_w=800.0, + soc0={"a": 60.0, "b": 30.0}, + limits={"b": (-1000.0, 1000.0)}) +_cu = [r for r in ROWS_U if r["action"] == arbitrage.CHARGE] +print(f" B limited to 1 kW: charge {min(r['shares'].get(B, 0) for r in _cu)}" + f" W, unmet {max(abs(r['unmet']) for r in _cu)} W") +check("SAFETY-45 sizing inside the modes: the charge is sized to what the " + "batteries may place, so none of it is left unmet (P1's gap)", + _cu and all(abs(r["unmet"]) < 1 for r in _cu) + and min(r["shares"].get(B, 0) for r in _cu) >= -1000) + +# A house that swings over the limit every minute during the cheap run. +_sw = [(UTC0.timestamp() + 60 * k, 2000.0 if k % 2 else 3900.0) + for k in range(0, 200)] +ROWS_W, _, _ = run_day("p3_ch_sell", hours=1.5, house=_sw, + soc0={"a": 60.0, "b": 30.0}) +_per_q = {} +for a_, b_ in zip(ROWS_W, ROWS_W[1:]): + if a_["action"] != arbitrage.CHARGE and b_["action"] == arbitrage.CHARGE: + q = int(b_["now"].timestamp() // 900) + _per_q[q] = _per_q.get(q, 0) + 1 +print(f" house swinging 2.0/3.9 kW each minute: charge starts per period " + f"{sorted(_per_q.values())}") +check("a charge the peak guard or the headroom stopped stays off for the " + "rest of that 15-minute period (at most one start per period)", + _per_q and max(_per_q.values()) == 1) + +# At the floor: B starts the sale just above it. +ROWS_F, _, _ = run_day("p3_ch_sell", start_h=18.75, hours=1.5, + soc0={"a": 60.0, "b": 24.0}) +_sf = [r for r in ROWS_F if r["action"] == arbitrage.DISCHARGE] +_after = [r for r in ROWS_F if r["now"].astimezone(L).hour == 19 + and r["soc"]["b"] <= 20.0] +_lastf = nth(ROWS_F, -1, "the last cycle") +print(f" from 24 %: sold {len(_sf)} cycles, B ends at " + f"{_lastf['soc']['b'] if present(_lastf) else _lastf} %") +check("the sale stops at arbitrage_soc_floor and does not re-arm in the run", + _sf and _after and all(r["action"] != arbitrage.DISCHARGE + for r in _after)) + +# N=1: one Cheap hours battery. +ROWS1, _, _ = run_day("p3_ch_sell", n=1, soc0={"a": 30.0}, + choice={"a": (True, "cheap_hours", False)}, + hours=3.0) +_c1 = [r for r in ROWS1 if r["action"] == arbitrage.CHARGE] +check("at one inverter the same rules: it charges in the cheap run, sized " + "under the aim", _c1 and max(r["grid"] for r in _c1) < AIM + 400) + +# ============================================================================ # +print("\n5. a refusal wins over a run") +ROWS_R, _, _ = run_day("p3_ch_sell", hours=1.0, soc0={"a": 60.0, "b": 30.0}, + refuse=("b",)) +_first = nth(ROWS_R, 0, "the first cycle") +_ref = [r for r in ROWS_R if present(_first) + and r["now"] > _first["now"] + timedelta(minutes=3)] +print(f" B refuses to charge; after 3 min: trades " + f"{sorted({str(r['action']) for r in _ref})}, B roles " + f"{sorted({r['roles'].get(B) for r in _ref})}") +check("B refusing to charge: no grid trade is filed after the refusal is " + "learned, B's role is no longer 'charge', and A covers the house", + _ref and all(r["action"] is None for r in _ref) + and all(r["roles"].get(B) != modetrade.CHARGE for r in _ref) + and sum(r["shares"].get(A, 0) > 0 for r in _ref) > len(_ref) / 2) + +# ============================================================================ # +print("\n6. no prices, no gap, Solar first alone") + + +def _no_plan(c): + c.tariff_plan = None + c.fresh_tariff_plan = lambda now: None + + +ROWS_N, _, _ = run_day("p3_ch_sell", hours=1.0, patch=_no_plan, + soc0={"a": 60.0, "b": 60.0}, house_w=1500.0) +check("no prices: no trade, and Leftover solar / Cheap hours follow the " + "house (they give power, not held forever)", + all(r["action"] is None for r in ROWS_N) + and all(r["roles"].get(B) == modetrade.HOUSE for r in ROWS_N) + and any(r["shares"].get(B, 0) > 0 for r in ROWS_N)) +ROWS_S, _, _ = run_day("p3_ch_sell", hours=21.0, + choice={"a": (True, "solar_first", False), + "b": (True, "solar_first", True)}) +check("both batteries Solar first: never a grid charge or a sale all day, " + "even with selling switched on", + all(r["action"] is None for r in ROWS_S)) + +# ============================================================================ # +print("\n7. a run edge reseeds the loop") + + +def _no_reseed(c): + c._reseed_run_edge = lambda claims: None + + +def edge(rows, kind): + for i in range(1, len(rows)): + if rows[i - 1]["action"] == kind and rows[i]["action"] != kind: + w = [r["grid"] for r in rows[i:i + 36]] + return min(w), max(w) + return None + + +_e_on = edge(run_day("p3_ch_sell", hours=3.0, house_w=800.0, + soc0={"a": 60.0, "b": 70.0})[0], arbitrage.CHARGE) +_e_off = edge(run_day("p3_ch_sell", hours=3.0, house_w=800.0, + soc0={"a": 60.0, "b": 70.0}, patch=_no_reseed)[0], + arbitrage.CHARGE) +print(f" grid in the 3 min after a 2.5 kW charge ends, 800 W house: " + f"reseeded {_e_on}, not reseeded {_e_off}") +check("reseeded, the loop takes over without the import spike the trade's " + "watts leave behind (and exports no more than without)", + _e_on and _e_off and _e_on[1] < 1000 and _e_off[1] > 2000 + and _e_on[0] > _e_off[0] - 100) + +# ============================================================================ # +print("\n8. the site Why row (OPT-11 P1 test, F2)") +_cl = [Claim.set("loop", P_LOOP, 1200.0), Claim.limit("peak", P_PEAK, + lo=2500.0)] +_up = Resolution(2500.0, "loop", bound_by="peak(quarter peak)") +_dn = Resolution(800.0, "loop", bound_by="peak(quarter peak)") +check("a peak floor that raised the power reads 'raised for the peak limit', " + "never 'held back'", + why_raised(_up, _cl) is True and "held back" not in messages.why( + "loop", 2500.0, "peak(quarter peak)", raised=True) + and "raised for the peak limit" in messages.why( + "loop", 2500.0, "peak(quarter peak)", raised=True)) +check("...a limit that lowered it still reads 'held back'", + why_raised(_dn, _cl) is False + and "held back by" in messages.why("loop", 800.0, "pack")) +check("...and a trade the peak floor raised reads the same way", + why_raised(Resolution(2000.0, "arbitrage", bound_by="peak"), + [Claim.set("arbitrage", P_ARBITRAGE, -1000.0)]) is True) + +# ============================================================================ # +print("\n9. the selling switch") +_st = rp._Store() +_ctl = Controller(dict(rp.options(True, False)), rp.Hass(("a", "b"), + lambda t: 0.0), _st, rp._Pub(), stop=asyncio.Event()) +_r1 = asyncio.run(_ctl.handle_action("pack_sell", unit=B, value=True)) +_bad9 = [asyncio.run(_ctl.handle_action("pack_sell", unit=B, value=v)) + for v in ("yes", 1, 0, None)] +_bad9.append(asyncio.run(_ctl.handle_action("pack_sell", unit="x", + value=True))) +check("pack_sell stores true/false per battery, logs it, and returns it", + _r1 == {"unit": B, "use": True, "mode": packmode.SOLAR_FIRST, + "sell": True} + and _st.data[unit_key(B, packmode.SELL_KEY)] is True + and any("selling switched on" in str(e) for e in _ctl.events)) +check("...anything else (1, 0, 'yes', None, an unknown battery) is refused " + "with a plain reason and stores nothing", + all(set(x) == {"error"} for x in _bad9) + and _st.data[unit_key(B, packmode.SELL_KEY)] is True) +check("...Solar first never sells, even with the switch on", + packmode.read(_st.data, B).sell is True + and packmode.read(_st.data, B).can_sell is False) +_off_ctl = Controller(dict(rp.options(False, False)), rp.Hass( + ("a", "b"), lambda t: 0.0), rp._Store(), rp._Pub(), stop=asyncio.Event()) +check("...and with battery modes off it is refused like the others", + "error" in asyncio.run(_off_ctl.handle_action("pack_sell", unit=B, + value=True))) + +# ============================================================================ # +print("\n10. the Batteries screen") +_keys = set(homeview.ROLE_WHY.values()) | {"saves_later", "no_prices", + "no_spread"} +_en, _nl = homeview.uitext.words("en"), homeview.uitext.words("nl") +check("every role's Why line has words in English and Dutch, and they differ", + all(k in _en["home_words"]["why"] and k in _nl["home_words"]["why"] + and _en["home_words"]["why"][k] != _nl["home_words"]["why"][k] + for k in _keys)) +_c10 = run_day("p3_ch_sell", start_h=18.0, hours=0.5, + soc0={"a": 60.0, "b": 80.0})[2] +_now10 = D0 + timedelta(hours=18, minutes=30) +_plan = homeview.mode_runs(_c10, *homeview.local_day(_now10.astimezone( + timezone.utc)), _now10.astimezone(timezone.utc), False) +print(f" plan blocks for B at 18:30: " + f"{[(r['from'], r['to'], r['kind'], r['what']) for r in _plan[0]]}") +check("the plan draws B's expensive run, the sale inside it, and nothing " + "for Solar first A", _plan[0] + and {r["battery"] for r in _plan[0]} == {1} + and any(r["kind"] == "give" for r in _plan[0])) +_why = homeview.battery_why( + modes_on=True, mode=packmode.CHEAP_HOURS, off=False, reading=True, + phase="idle", shadow=False, running=True, held=False, refused=0, + peak=False, sf_ahead=True, role="hold", has_at=True) +check("a holding battery's Why names when it gives power", + _why == "saves" and "18:00 - 19:00" in homeview.why_words( + _why, at="18:00 - 19:00")) + +print() +if fails: + print(f"{len(fails)} FAILED:") + for f in fails: + print(f" - {f}") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/test_mqtt.py b/goodwe_controller/test_mqtt.py index 29dc4f4..5e4a5b7 100644 --- a/goodwe_controller/test_mqtt.py +++ b/goodwe_controller/test_mqtt.py @@ -996,7 +996,8 @@ check("modes off: every configuration announces byte-for-byte what ed739d4 " MODES = packmode.MODES ON1, SUB1 = announce_p2(["inverter-a"], modes=MODES) m, c, a = report("roster of one, modes on", ON1) -_opt = '["Solar first", "Leftover solar"]' +# P2 announced the first two; OPT-11 P3 appended "Cheap hours only". +_opt = '["Solar first", "Leftover solar", "Cheap hours only"]' MODE_N1 = [ ("homeassistant/select/goodwe_ctl_unit_inverter_a_mode/config", '{"name": "Inverter A Mode", "object_id": "goodwe_inverter_a_mode", ' @@ -1062,16 +1063,19 @@ check("each HA mode option is the page's English name for that mode, in " "both places the page names it", all(mqtt.MODE_LABELS[k] == _en["home_words"]["modes"][k] == _en["home"]["batteries"]["choice"][k]["name"] for k in MODES)) -_later = dict(mqtt.MODE_LABELS, cheap_hours="Cheap hours only") +# OPT-11 P3 added `cheap_hours`: against P2's two modes (7a00f12), only the +# options list changes, by one entry at its end; no topic, id or label moves. +_p3 = mqtt.mode_payloads(NAMES2, MODES) _orig = mqtt.MODE_LABELS -mqtt.MODE_LABELS = _later +mqtt.MODE_LABELS = {k: v for k, v in _orig.items() if k != "cheap_hours"} try: - _p3 = mqtt.mode_payloads(NAMES2, MODES + ("cheap_hours",)) + _p2 = mqtt.mode_payloads(NAMES2, MODES[:2]) finally: mqtt.MODE_LABELS = _orig -_p2 = mqtt.mode_payloads(NAMES2, MODES) -check("...(simulated P3: adding `cheap_hours` changes only the options list, " - "by one entry at its end)", +check("...P3 appended `cheap_hours`: against P2's list only the options " + "change, by one entry at the end, and P2's two labels are unchanged", + MODES[:2] == ("solar_first", "leftover_solar") + and _p2[0][1]["options"] == ["Solar first", "Leftover solar"] and [t for t, _ in _p3] == [t for t, _ in _p2] and all({k: v for k, v in x.items() if k != "options"} == {k: v for k, v in y.items() if k != "options"} @@ -1261,7 +1265,7 @@ BAD = [ (f"{T_A}/use/set", b"true"), (f"{T_A}/use/set", b"1"), (f"{T_A}/use/set", b""), (f"{T_A}/mode/set", b"solar_first"), # a key, not the option - (f"{T_A}/mode/set", b"Cheap hours only"), # not offered before P3 + (f"{T_A}/mode/set", b"Sell only"), # not an offered mode (f"{T_A}/mode/set", b"solar first"), (f"{T_A}/mode/set", "Sοlar first".encode()), # Greek omicron (f"{T_A}/mode/set", b"Solar first\x00"), diff --git a/goodwe_controller/tools/opt11p3_identity.py b/goodwe_controller/tools/opt11p3_identity.py new file mode 100644 index 0000000..279777e --- /dev/null +++ b/goodwe_controller/tools/opt11p3_identity.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +"""OPT-11 P3: with battery modes off, is every command byte-identical to +release/1.0 7a00f12, on the paths P3 changed? + + python3 tools/opt11p3_identity.py # prints one digest per scenario + +tools/safety79_identity.py's harness (the REAL Controller on a P1 meter, so +the peak guard runs) plus a day-ahead price series and `arbitrage_enabled`, +so the site trade P3 now skips with modes on (`arbitrage.decide()`, its +claim, the sizing to the guard's headroom) runs on every cycle, with a buy +period, a sell period and periods in between, and a house that goes over the +limit. Each row hashes safety79's fields plus the trade's action, watts and +sentence. Uses only the API 7a00f12 has, so the same file runs on both trees; +test_modes_p3.py part 1 holds this tree to the digests printed on 7a00f12. +""" + +import functools +import hashlib +import os +import sys +import tempfile +from datetime import timedelta + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +import safety79_identity as s79 # noqa: E402 +from app.price import PricePoint, PriceProduct, PriceRead, brussels # noqa +from app.static_tariff import TariffPlan # noqa: E402 + +DUR = 5400.0 + + +def prices(): + """15-minute firm prices: the cheapest period 15-30 min into the run, + the dearest 75-90 min in, and ones in between.""" + pts = [] + for i in range(-8, 40): + s = rig.BASE + timedelta(minutes=15 * i) + p = 0.08 if i == 1 else 0.52 if i == 5 else 0.20 + 0.003 * (i % 7) + pts.append(PricePoint(start=brussels(s), eur_per_kwh=p, + provisional=False)) + return TariffPlan(PriceRead.series(pts, PriceProduct.DAY_AHEAD, + "generic_dayahead", rig.BASE), None, + "provider") + + +PLAN = prices() + + +def _feed(c, t): + c.tariff_plan, c.tariff_at = PLAN, rig.BASE + timedelta(seconds=t) + s79._feed(c, t) + + +def load(t): + """Under the limit, over it, a surplus, a big evening load.""" + k = int(t // 600) % 5 + return (900.0, 3200.0, -2200.0, 1500.0, 4200.0)[k] + + +def soc(u, t): + return 55.0 if u == "a" else 45.0 + + +ARB = {"arbitrage_enabled": True, "cycle_cost_threshold_eur": 0.05} +SCENARIOS = { + "n1": dict(n=1), + "n2": dict(n=2), + # The option present and false: an install that saved it off. + "n1_off": dict(n=1, extra={"battery_modes_enabled": False}), + "n2_off": dict(n=2, extra={"battery_modes_enabled": False}), +} + + +def run(n, *, extra=None, dur=DUR): + opts = dict(s79.P1, **ARB, **(extra or {})) + trade = [] + + def on_cycle(c, t): + a = c.arb + trade.append(None if a is None else (a.action, a.power_w, a.reason)) + db = os.path.join(tempfile.mkdtemp(prefix="p3id-"), "tariff.db") + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + try: + rows, c = rig.run(n, extra=opts, dur=dur, load=load, soc=soc, + cut=lambda u, t: False, before=_feed, + on_cycle=on_cycle) + finally: + rig.Controller = real + return [r + (x,) for r, x in zip(rows, trade)], c + + +def digest(rows) -> str: + return hashlib.sha256(repr(rows).encode()).hexdigest() + + +def digests() -> dict: + return {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} + + +if __name__ == "__main__": + if "--summary" in sys.argv: + for k, v in SCENARIOS.items(): + rows = run(**v)[0] + acts = sorted({str(r[-1][0]) if r[-1] else "None" for r in rows}) + print(f"{k}: {len(rows)} cycles, trade actions {acts}") + for k, v in digests().items(): + print(f"{k} {v}") diff --git a/goodwe_controller/tools/opt11p3_replay.py b/goodwe_controller/tools/opt11p3_replay.py new file mode 100644 index 0000000..58b00ef --- /dev/null +++ b/goodwe_controller/tools/opt11p3_replay.py @@ -0,0 +1,394 @@ +#!/usr/bin/env python3 +"""OPT-11 P3: replay days of recorded house load and real prices through the +REAL Controller (read_inputs + cycle, the arbiter, the allocator, the peak +guard on a P1 meter), with two modelled batteries, and report energy, cycles +and money, plus the P3 invariants on every tick. + + python3 tools/opt11p3_replay.py --days 16 --variant p3_ls + python3 tools/opt11p3_replay.py --captured # 2026-09-09/10 + +The same file runs on release/1.0 7a00f12 (the P2 baseline) and on this +branch: it uses only the Controller API 7a00f12 has, and sets the batteries' +choices through the store keys P1 defined (`pack_sell` was reserved there). + +REAL: the house (grid + battery power recorded 2026-09-02..17 on the live +install, scenarios/loop-2026-09-02_2026-09-17: the house's own net demand, +solar included), the prices (EPEX BE day-ahead, hourly, same weekday one year +earlier (364 days), or the captured quarter-hourly energy-charts bodies for +2026-09-09/10), the decision code. +MODELLED: the batteries (a first-order lag, 3 s, 800 W/s ramp, SoC +integrated, 95 % each way, a reading that jitters by a few watts, and +optionally a device limit or a refusal to charge), the all-in price (the EPEX file's own stated +assumption: (wholesale + 0.02 + 0.10) x 1.06), export paid at the wholesale +price, tomorrow's prices known from 13:00 local. The absolute money is +therefore an estimate; the comparison between variants is the point. +""" + +import argparse +import asyncio +import gzip +import json +import math +import os +import sys +import time +from datetime import datetime, timedelta, timezone + +HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, HERE) + +import app.main as m # noqa: E402 +from app.main import Controller # noqa: E402 +from app.p1 import make_sample, split_signed # noqa: E402 +from app.price import PricePoint, PriceProduct, PriceRead, brussels # noqa +from app.static_tariff import TariffPlan # noqa: E402 +from app.store import unit_key # noqa: E402 + +LOOP = os.path.join(HERE, "scenarios", "loop-2026-09-02_2026-09-17") +EPEX = os.path.join(HERE, "scenarios", + "epex-be-dayahead-2025-09-01_2026-09-01.json") +QH = os.path.join(HERE, "scenarios", + "energy-charts-be-price-2026-09-09_2026-09-10-twoday.json") +TICK = 5.0 +CAP_KWH = 10.0 +RATING = 2500.0 +PEAK_CAP = 3500 + + +def all_in(wholesale_kwh): + return round((wholesale_kwh + 0.02 + 0.10) * 1.06, 6) + + +def load_house(days): + """[(t_utc_epoch, house_w)] from the recording: grid + battery power.""" + out = [] + for d in days: + def rd(kind): + f = os.path.join(LOOP, f"{d}-{kind}.jsonl.gz") + rows = [] + with gzip.open(f, "rt") as fh: + for line in fh: + r = json.loads(line) + try: + v = float(r["v"]) + except ValueError: + continue + rows.append((datetime.fromisoformat(r["t"]).timestamp(), + v)) + return rows + g, b = rd("grid"), rd("batt") + j = 0 + for t, gw in g: + while j + 1 < len(b) and b[j + 1][0] <= t: + j += 1 + bw = b[j][1] if b and b[j][0] <= t else 0.0 + out.append((t, gw + bw)) + out.sort() + return out + + +def epex_points(shift_days=364): + d = json.load(open(EPEX))["prices"] + pts = [] + for r in d: + s = datetime.fromisoformat(r["start"]) + timedelta(days=shift_days) + pts.append((s.astimezone(timezone.utc), 3600, + float(r["eur_per_kwh"]))) + return pts + + +def qh_points(): + d = json.load(open(QH)) + return [(datetime.fromtimestamp(t, timezone.utc), 900, p / 1000.0) + for t, p in zip(d["unix_seconds"], d["price"]) + if p is not None] + + +class Plant: + def __init__(self, soc, refuse_charge=False): + self.cmd, self.p, self.soc = 0.0, 0.0, float(soc) + self.refuse_charge = refuse_charge + + def step(self, dt, floor): + c = self.cmd + if c > 0 and self.soc <= floor: + c = 0.0 + if c < 0 and (self.soc >= 100.0 or self.refuse_charge): + c = 0.0 + want = self.p + (c - self.p) * (1 - math.exp(-dt / 3.0)) + dp = max(-800.0 * dt, min(800.0 * dt, want - self.p)) + self.p += dp + e = self.p * dt / 3600.0 / 1000.0 # kWh, + = out + eff = 1 / 0.95 if e > 0 else 0.95 + self.soc -= e * eff / CAP_KWH * 100.0 + self.soc = max(0.0, min(100.0, self.soc)) + + +class Hass: + def __init__(self, units, house_at, soc0=None, refuse=(), limits=None): + self.units = units + self.lim = limits or {} + self.plants = {u: Plant((soc0 or {}).get(u, 50.0), u in refuse) + for u in units} + self.house_at = house_at + self.t = 0.0 + + def grid(self): + return self.house_at(self.t) - sum(p.p for p in self.plants.values()) + + async def limits(self, e): + lo, hi = self.lim.get(e[-1], (-5000.0, 5000.0)) + return (lo, hi, 1.0) + + async def call(self, *a): + return True + + async def number(self, e, invert=False): + if e == "sensor.grid": + return self.grid() + u = e[-1] + if e.startswith("sensor.soc"): + return round(self.plants[u].soc, 1) + if e.startswith("sensor.batt"): + # A real reading jitters by a few watts; a dead-flat one is a + # stale register to the add-on (SAFETY-37), which is not modelled. + j = (ord(u) * 31 + int(self.t)) % 7 - 3 + return float(round(self.plants[u].p) + j) + return None + + async def set_number(self, e, v): + self.plants[e[-1]].cmd = float(v) + return True + + +class _Store: + def __init__(self): + from app.store import DEFAULTS + self.data = dict(DEFAULTS) + + def set(self, k, v): + self.data[k] = v + + def get_time(self, k): + v = self.data.get(k) + return datetime.fromisoformat(v) if v else None + + def set_time(self, k, when): + self.data[k] = when.isoformat() if when else None + + +class _Pub: + enabled = False + + def publish(self, *a, **k): + pass + + def close(self): + pass + + +VARIANTS = { + # (modes on, arbitrage_enabled, {unit: (use, mode, sell)}) + "modes_off": (False, False, {}), + "arb_only": (False, True, {}), + "p2_sf_ls": (True, False, {"a": (True, "solar_first", False), + "b": (True, "leftover_solar", False)}), + "p2_arb": (True, True, {"a": (True, "solar_first", False), + "b": (True, "leftover_solar", False)}), + "p3_ls": (True, False, {"a": (True, "solar_first", False), + "b": (True, "leftover_solar", False)}), + "p3_ch_sell": (True, False, {"a": (True, "solar_first", False), + "b": (True, "cheap_hours", True)}), + "p3_both_ch": (True, False, {"a": (True, "cheap_hours", False), + "b": (True, "cheap_hours", True)}), +} + + +def options(modes, arb, n=2): + o = {"meter_entity": "sensor.grid", "meter_source": "ha_signed", + "p1_net_entity": "sensor.net", "meter_phases": 1, + "peak_cap_w": PEAK_CAP, "gain": 0.6, "slew_w": 400, + "target_grid_w": -10, "deadband_w": 15, "step_w": 10, + "heartbeat_s": 10, "stale_input_s": 15, "auto_start": True, + "battery_modes_enabled": modes, "arbitrage_enabled": arb, + "cycle_cost_threshold_eur": 0.10, + "inverters": [{"name": f"inverter-{u}", + "setpoint_entity": f"number.sp_{u}", + "soc_entity": f"sensor.soc_{u}", + "batt_entity": f"sensor.batt_{u}", + "max_w": int(RATING), "bms_soc_floor": 10, + "capacity_kwh": CAP_KWH} for u in "ab"[:n]]} + return o + + +def plan_at(now, pts): + """The firm day-ahead points a site holds at `now`: today, and tomorrow + once published (13:00 local).""" + loc = brussels(now) + day0 = loc.replace(hour=0, minute=0, second=0, microsecond=0) + end = day0 + timedelta(days=2 if loc.hour >= 13 else 1) + sel = [PricePoint(start=brussels(s), eur_per_kwh=all_in(p), + provisional=False) + for s, span, p in pts if day0 <= s < end] + if len(sel) < 2: + return None + return TariffPlan(PriceRead.series(sel, PriceProduct.DAY_AHEAD, + "generic_dayahead", now), None, + "provider") + + +def run(variant, house, pts, start, dur, *, check=None, stride=1, n=2, + soc0=None, refuse=(), extra=None, choice=None, patch=None, + limits=None): + modes, arb, var_choice = VARIANTS[variant] + choice = var_choice if choice is None else choice + units = tuple("ab"[:n]) + import bisect + ts = [h[0] for h in house] + + def house_at(t): + i = bisect.bisect_right(ts, start.timestamp() + t) - 1 + return house[max(0, i)][1] + + wholesale = {s: (span, p) for s, span, p in pts} + starts = sorted(wholesale) + + def price_at(now): + i = bisect.bisect_right(starts, now) - 1 + if i < 0: + return None + s = starts[i] + span, p = wholesale[s] + return p if now < s + timedelta(seconds=span) else None + + store = _Store() + for u, (use, mode, sell) in choice.items(): + store.data[unit_key(f"inverter-{u}", "pack_use")] = use + store.data[unit_key(f"inverter-{u}", "pack_mode")] = mode + store.data[unit_key(f"inverter-{u}", "pack_sell")] = sell + stats = dict(imp_kwh=0.0, exp_kwh=0.0, cost=0.0, exp_rev=0.0, + out_kwh={u: 0.0 for u in "ab"[:n]}, + in_kwh={u: 0.0 for u in "ab"[:n]}, + ticks=0, quarters={}, trade_ticks=0) + + async def go(): + hass = Hass(units, house_at, soc0, refuse, limits) + import tempfile + db = os.path.join(tempfile.mkdtemp(prefix="p3r-"), "tariff.db") + c = Controller(dict(options(modes, arb, n), **(extra or {})), hass, + store, _Pub(), stop=asyncio.Event(), peak_db_path=db) + for i in c.inverters: + i.dev_min, i.dev_max = (limits or {}).get(i.name[-1], + (-5000.0, 5000.0)) + if patch is not None: + patch(c) + c.auto = True + real_dt = m.datetime + clock = [start] + + class _DT(real_dt): + @classmethod + def now(cls, tz=None): + return clock[0] if tz is None else clock[0].astimezone(tz) + + m.datetime = _DT + plan_hour = None + try: + t = 0.0 + while t < dur: + now = start + timedelta(seconds=t) + hass.t = t + clock[0] = now + if plan_hour != now.replace(minute=0, second=0, + microsecond=0): + plan_hour = now.replace(minute=0, second=0, + microsecond=0) + c.tariff_plan, c.tariff_at = plan_at(now, pts), now + else: + c.tariff_at = now + imp, exp = split_signed(hass.grid()) + c.p1.submit(make_sample("ha_signed", imp, exp, phases=1, + ingest_ts=now, + ingest_mono=time.monotonic())) + await c.read_inputs(now_mono=t) + await c.cycle() + for p in hass.plants.values(): + p.step(TICK, 10.0) + g = hass.grid() + pr = price_at(now) + dt_h = TICK / 3600.0 + if g > 0: + stats["imp_kwh"] += g / 1000 * dt_h + stats["cost"] += g / 1000 * dt_h * (all_in(pr) if pr + is not None else 0) + else: + stats["exp_kwh"] += -g / 1000 * dt_h + stats["exp_rev"] += -g / 1000 * dt_h * (pr or 0.0) + for u, p in hass.plants.items(): + if p.p > 0: + stats["out_kwh"][u] += p.p / 1000 * dt_h + else: + stats["in_kwh"][u] -= p.p / 1000 * dt_h + q = int(now.timestamp() // 900) + acc = stats["quarters"].setdefault(q, [0.0, 0, False]) + acc[0] += max(0.0, g) + acc[1] += 1 + if (getattr(c.arb, "action", None) or "").endswith("CHARGE"): + acc[2] = True + stats["trade_ticks"] += 1 + stats["ticks"] += 1 + if check is not None: + check(c, hass, now, pr) + t += TICK + finally: + m.datetime = real_dt + return c + c = asyncio.run(go()) + return stats, c + + +def summary(stats): + qs = stats["quarters"] + worst = max((a[0] / a[1] for a in qs.values()), default=0.0) + worst_trade = max((a[0] / a[1] for a in qs.values() if a[2]), + default=0.0) + cyc = {u: round(v / CAP_KWH, 2) for u, v in stats["out_kwh"].items()} + return {"import_kwh": round(stats["imp_kwh"], 2), + "export_kwh": round(stats["exp_kwh"], 2), + "import_eur": round(stats["cost"], 2), + "export_eur": round(stats["exp_rev"], 2), + "net_eur": round(stats["cost"] - stats["exp_rev"], 2), + "cycles": cyc, "worst_quarter_w": round(worst, 1), + "worst_charge_quarter_w": round(worst_trade, 1), + "charge_ticks": stats["trade_ticks"]} + + +LOOP_DAYS = [f"2026-09-{d:02d}" for d in range(2, 18)] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--variant", default="p3_ls") + ap.add_argument("--days", type=int, default=16) + ap.add_argument("--captured", action="store_true") + a = ap.parse_args() + if a.captured: + days = ["2026-09-09", "2026-09-10"] + pts = qh_points() + else: + days = LOOP_DAYS[:a.days] + pts = epex_points() + house = load_house(days) + start = datetime.fromisoformat(days[0] + "T00:00:00+02:00") \ + .astimezone(timezone.utc) + dur = 86400.0 * len(days) + t0 = time.time() + stats, _c = run(a.variant, house, pts, start, dur) + out = summary(stats) + out["variant"], out["days"] = a.variant, len(days) + out["wall_s"] = round(time.time() - t0, 1) + print(json.dumps(out)) + + +if __name__ == "__main__": + main() -- 2.54.0 From b014fd2e16f85e584a1a4b4c952e9dc1ab24dc1d Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Tue, 29 Sep 2026 03:51:15 +0200 Subject: [PATCH 076/105] OPT-11 P3 review: sale shows no money, honest sell text, tests for four surviving mutants - A sale block on the plan no longer says "Worth up to" at the import price: a sale earns the lower injection price. - The selling switch help (EN/NL) and DOCS say the grid pays less than power costs; DECISIONS records why P3 loses on the replay. - test_modes_p3 part 11: modes on ignore the site trade switch (R13), a battery in maintenance takes no part (R10), a headroom stop latches for the period (R8). All three mutants survived before and are red now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 22 +++++--- goodwe_controller/DOCS.md | 2 +- goodwe_controller/app/homeview.py | 8 +-- goodwe_controller/app/ui_text/en.json | 2 +- goodwe_controller/app/ui_text/nl.json | 2 +- goodwe_controller/test_modes_p3.py | 53 +++++++++++++++++++ 6 files changed, 77 insertions(+), 12 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 2345e92..5d806af 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -51,12 +51,22 @@ P1 is its section 6 P1, and the pull request lists what was measured. on flat morning prices, then charging went on at them); - a run edge reseeds the loop at the house's level (a 3 kW import spike removed; about 0.1 x rating still overshoots as export). -- Replay (tools/opt11p3_replay.py, 16 recorded days, EPEX prices a year - earlier, modelled batteries): P3 does not beat the P2 baseline on money - (net 19.57 / 19.60 EUR against 19.33; the old one-period trade 18.14). - A sale is judged on import prices but exports earn the injection price, - so selling lost money in the model. The owner should see this before - selling is recommended. +- Replay (tools/opt11p3_replay.py, 16 recorded days, EPEX hourly prices a + year earlier, modelled batteries), net EUR, lower is better: P2 19.33, P3 + Solar first + Leftover solar 19.57, with a sale 19.60, the old one-period + trade 18.14. Review of #153 (same model, with a per-action split): + - the cheapest hours were at midday on 15 of 16 days, so Leftover solar (acting + as Cheap hours until P4) bought 12.2 kWh there that the sun would have + given: 7 kWh more exported, 12 kWh less solar stored. Holding for the + expensive hours saved 4 kWh of import, not enough. With no grid charge on + Leftover solar: 19.44; + - the old trade charged one hour, so the afternoon sun still fit; + - a sale earned the wholesale price (2.27 EUR for 11.4 kWh) and the house + then bought the same energy back (2.29 EUR): a wash before wear. It pays + only when the sale hour's wholesale price beats the later import price, + levies included (about 0.13 EUR/kWh above that hour's wholesale here); + - valuing the charge left at the end, wear and real Flemish levies make + selling worse and do not change the order. - Not done in P3: the forecast (P4: Leftover solar acts as Cheap hours only), a headroom too short for the run moving the rest to the next cheap periods, and an HA switch for selling. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 5589c11..1deffb8 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -524,7 +524,7 @@ Off by default. Turn it on, restart the add-on, and the Batteries screen (and Se - *Solar first* charges from spare solar before the other batteries and covers the house at any hour. It never charges from the grid and never sells. - *Leftover solar* charges from the solar the others cannot take, and from the grid in the cheapest hours. It saves its power for the expensive hours and covers the house then. - *Cheap hours only* does the same with the grid. Until the solar forecast arrives, *Leftover solar* also tops up from the grid like this. -- **Sell in expensive hours.** For *Leftover solar* and *Cheap hours only*. In the most expensive hours the battery gives its full power: the house first, the rest to the grid. It stops at *Trading keeps at least* (`arbitrage_soc_floor`). +- **Sell in expensive hours.** For *Leftover solar* and *Cheap hours only*. In the most expensive hours the battery gives its full power: the house first, the rest to the grid. It stops at *Trading keeps at least* (`arbitrage_soc_floor`). The sale is judged on the price you pay, but the grid pays you the lower injection price, so selling rarely pays; on the replay it did not (`DECISIONS/OPT-11-battery-modes.md`). With battery modes on, these choices replace the *Charging and selling on price* switch (`arbitrage_enabled`); that switch is only read with modes off. diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index de8241e..89d0641 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -366,9 +366,10 @@ def mode_runs(c, day0, day1, now, shadow): run_cheap_why(price), run_grid_amount(kwh * price)) elif kind == "sell": + # No money line: the price is what the house pays, and a sale + # earns the lower injection price (OPT-11 P3 review). what, why, amount = (run_sell_what(kwh, shadow), - run_dear_why(price), - run_give_amount(kwh * price)) + run_dear_why(price), None) else: what, why, amount = (run_give_what(kwh, shadow), run_dear_why(price), @@ -376,7 +377,8 @@ def mode_runs(c, day0, day1, now, shadow): out.append(_run(i, "give" if kind == "sell" else kind, max(run.start, day0), min(run.end, day1), day0, day1, what, why, amount, kwh=kwh, - eur=kwh * price, price=price)) + eur=None if kind == "sell" else kwh * price, + price=price)) return out, None diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index abd574f..565ca62 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -92,7 +92,7 @@ "off": {"name": "Off", "description": "Rests, and helps only when the peak limit needs it."} }, "today": "Today", "why": "Why", - "sell": {"name": "Sell in expensive hours", "description": "Also sells to the grid in the most expensive hours.", "off": "Not for Solar first."}, + "sell": {"name": "Sell in expensive hours", "description": "Also sells to the grid in the most expensive hours, but you are paid less than you pay for power.", "off": "Not for Solar first."}, "modes_off": {"name": "Battery modes are off"}, "how": {"name": "How the modes work", "description": "Which battery gets solar first, and when each gives power.", "solar_first": {"description": "Solar first gets spare solar before the other batteries, and covers the house at any hour."}, diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index f374c88..9151605 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -89,7 +89,7 @@ "off": {"name": "Uit", "description": "Rust, en helpt alleen als de piekgrens haar nodig heeft."} }, "today": "Vandaag", "why": "Waarom", - "sell": {"name": "Verkopen in dure uren", "description": "Verkoopt ook aan het net in de duurste uren.", "off": "Niet voor Eerst zonne-energie."}, + "sell": {"name": "Verkopen in dure uren", "description": "Verkoopt ook aan het net in de duurste uren, maar u krijgt minder dan u voor stroom betaalt.", "off": "Niet voor Eerst zonne-energie."}, "modes_off": {"name": "Batterijmodi staan uit"}, "how": {"name": "Zo werken de modi", "description": "Welke batterij eerst zonne-energie krijgt, en wanneer elke batterij levert.", "solar_first": {"description": "Eerst zonne-energie krijgt het overschot vóór de andere batterijen, en dekt het huis op elk uur."}, diff --git a/goodwe_controller/test_modes_p3.py b/goodwe_controller/test_modes_p3.py index 33dc83e..5a8207b 100644 --- a/goodwe_controller/test_modes_p3.py +++ b/goodwe_controller/test_modes_p3.py @@ -21,6 +21,8 @@ time. DECISIONS/OPT-11-battery-modes.md has the record. 8. The site Why row: a limit that pushes power up does not "hold it back" (F2). 9. The selling switch (`pack_sell`). 10. The Batteries screen: Why and Today lines from the roles and runs. +11. Review additions: modes on ignore the site trade switch, a battery in + maintenance takes no part, the headroom stop latches for the period. Mutations (MUTATION.md, purged copies, graded over this file and the named tests) are listed in the pull request. @@ -596,6 +598,10 @@ check("the plan draws B's expensive run, the sale inside it, and nothing " "for Solar first A", _plan[0] and {r["battery"] for r in _plan[0]} == {1} and any(r["kind"] == "give" for r in _plan[0])) +_sale = [r for r in _plan[0] if r["what"].startswith("Sells")] +check("a sale block shows no money: the price shown is what the house pays, " + "and a sale earns the lower injection price", + _sale and all(r["amount"] is None and r["eur"] is None for r in _sale)) _why = homeview.battery_why( modes_on=True, mode=packmode.CHEAP_HOURS, off=False, reading=True, phase="idle", shadow=False, running=True, held=False, refused=0, @@ -604,6 +610,53 @@ check("a holding battery's Why names when it gives power", _why == "saves" and "18:00 - 19:00" in homeview.why_words( _why, at="18:00 - 19:00")) +# ============================================================================ # +print("\n11. review additions (PR #153): gaps four mutants survived") +import types # noqa: E402 +import app.main as _main # noqa: E402 + +# Modes on with the site switch on: only the modes trade (R13). +ROWS_X, _, _ = run_day("p2_arb", hours=3.0, soc0={"a": 30.0, "b": 30.0}, + choice={"a": (True, "solar_first", False), + "b": (True, "solar_first", False)}) +check("modes on, 'Trade on the price spread' on, both batteries Solar first: " + "no trade all through the cheap hours (the site trade is not run)", + ROWS_X and all(r["action"] is None for r in ROWS_X) + and all(v >= 0 for r in ROWS_X for v in r["shares"].values()) + and not any(r["winner"].startswith("arbitrage") for r in ROWS_X)) + +# A battery in a maintenance phase takes no part in a run (R10). +ROWS_M, _, _cm = run_day("p3_ch_sell", hours=0.6, house_w=800.0, + soc0={"a": 60.0, "b": 30.0}) +_lm = nth(ROWS_M, -1, "the last cycle") +_nm = _lm["now"] if present(_lm) else None +_tm = _cm._mode_roles(_nm, [types.SimpleNamespace(phase=_main.IDLE), + types.SimpleNamespace(phase="CHARGE")]) \ + if _nm is not None else None +check("a battery in its monthly cycle is not a charger: no range, no charge " + "role, and no grid charge when it is the only price battery", + _tm is not None and B not in _tm.ranges + and _tm.roles.get(B) != modetrade.CHARGE and _tm.action is None) + +# The headroom stopping a charge latches it off for the period (R8). +_cm2 = run_day("p3_ch_sell", hours=0.6, house_w=800.0, + soc0={"a": 60.0, "b": 30.0})[2] +_ok8 = False +if _nm is not None and _cm2.mode_tick is not None \ + and _cm2.mode_tick.action == modetrade.CHARGE: + _q = int(_nm.timestamp() // 900) + _cm2.arb_headroom_w = 0.0 + _t1 = _cm2._mode_roles(_nm, None) + _cm2.arb_headroom_w = 3000.0 + _t2 = _cm2._mode_roles(_nm + timedelta(seconds=5), None) + _nq = datetime.fromtimestamp((_q + 1) * 900 + 5, timezone.utc) + _cm2.tariff_at = _nq + _t3 = _cm2._mode_roles(_nq, None) + _ok8 = (_t1.why == "headroom" and _cm2._charge_blocked_q in (_q, _q + 1) + and _t2.action is None and _t3.action == modetrade.CHARGE) +check("a charge the headroom stopped stays off for the rest of the period, " + "even when the headroom comes back, and may start in the next one", _ok8) + print() if fails: print(f"{len(fails)} FAILED:") -- 2.54.0 From 6dab4ec16b719fcb150951ea310cb3953de4e0aa Mon Sep 17 00:00:00 2001 From: Claude dev agent <noreply@anthropic.com> Date: Tue, 29 Sep 2026 10:42:58 +0200 Subject: [PATCH 077/105] OPT-11 P3, owner option A: selling off, Leftover solar takes solar only Owner decision 2026-09-29. Selling is off until it can be judged on the price the grid pays: packmode.SELLING_ENABLED = False makes read() answer sell=False whatever the store holds, pack_sell is refused ("Selling is off for now."), and the page has no selling switch; the sell code stays. Until the P4 forecast, only Cheap hours only charges from the grid (packmode.GRID_CHARGE_MODES); Leftover solar holds and gives in the expensive runs. Help, Today and plan lines, DOCS and DECISIONS follow. Replay, 16 days: Solar first + Leftover solar 19.44 EUR net (P2 19.33). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 11 +- goodwe_controller/DOCS.md | 13 +-- goodwe_controller/app/homeview.py | 6 +- goodwe_controller/app/main.py | 2 + goodwe_controller/app/messages.py | 2 + goodwe_controller/app/modetrade.py | 9 +- goodwe_controller/app/packmode.py | 19 +++- goodwe_controller/app/static/app.js | 18 +-- goodwe_controller/app/ui_text/en.json | 7 +- goodwe_controller/app/ui_text/nl.json | 7 +- goodwe_controller/test_batteries_screen.py | 41 ++++--- goodwe_controller/test_modes_p3.py | 104 ++++++++++++++---- 12 files changed, 154 insertions(+), 85 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 5d806af..5c58558 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -67,6 +67,11 @@ P1 is its section 6 P1, and the pull request lists what was measured. levies included (about 0.13 EUR/kWh above that hour's wholesale here); - valuing the charge left at the end, wear and real Flemish levies make selling worse and do not change the order. -- Not done in P3: the forecast (P4: Leftover solar acts as Cheap hours only), - a headroom too short for the run moving the rest to the next cheap periods, - and an HA switch for selling. +- Owner decision 2026-09-29 (option A): selling is off until it can be judged + on the price the grid pays (`packmode.SELLING_ENABLED`, code kept), and + Leftover solar takes solar only until P4's forecast + (`packmode.GRID_CHARGE_MODES`); Cheap hours only still charges from the grid. Replayed + (16 days, as above): Solar first + Leftover solar 19.44 EUR net against + P2's 19.33; Solar first + Cheap hours only 19.57. +- Not done in P3: the forecast (P4), and a headroom too short for the run + moving the rest to the next cheap periods. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 1deffb8..2da5da8 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -522,9 +522,9 @@ Off by default. Turn it on, restart the add-on, and the Batteries screen (and Se - **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, but only for what the other batteries cannot cover. - **Mode.** - *Solar first* charges from spare solar before the other batteries and covers the house at any hour. It never charges from the grid and never sells. - - *Leftover solar* charges from the solar the others cannot take, and from the grid in the cheapest hours. It saves its power for the expensive hours and covers the house then. - - *Cheap hours only* does the same with the grid. Until the solar forecast arrives, *Leftover solar* also tops up from the grid like this. -- **Sell in expensive hours.** For *Leftover solar* and *Cheap hours only*. In the most expensive hours the battery gives its full power: the house first, the rest to the grid. It stops at *Trading keeps at least* (`arbitrage_soc_floor`). The sale is judged on the price you pay, but the grid pays you the lower injection price, so selling rarely pays; on the replay it did not (`DECISIONS/OPT-11-battery-modes.md`). + - *Leftover solar* charges from the solar the others cannot take, never from the grid (until the solar forecast arrives). It saves its power for the expensive hours and covers the house then. + - *Cheap hours only* charges from the grid in the cheapest hours, saves its power for the expensive hours and covers the house then. +- **Selling** is off until it can be judged on the price the grid pays (owner decision 2026-09-29, option A). With battery modes on, these choices replace the *Charging and selling on price* switch (`arbitrage_enabled`); that switch is only read with modes off. @@ -547,7 +547,7 @@ With battery modes on, these choices replace the *Charging and selling on price* *For installers:* a mode is a limit at priority 35, kept apart from the hard limits. It gives way only as far as a limit above it (the peak guard) needs. A mode range always holds 0 W, so a mode can forbid a direction and never force one. With one inverter the mode also bounds the loop. The record is `DECISIONS/OPT-11-battery-modes.md`. -*For installers:* when a charge or sale ends, the loop restarts at the house's own level rather than at the trade's watts. On the replay model that removes a ~3 kW import spike after a 2.5 kW charge and halves the settling time; about 0.1 × the battery's power still overshoots as export. Selling is the `pack_sell` action (and the *Mode* list gains *Cheap hours only* in Home Assistant, at the end). +*For installers:* when a charge or sale ends, the loop restarts at the house's own level rather than at the trade's watts. On the replay model that removes a ~3 kW import spike after a 2.5 kW charge and halves the settling time; about 0.1 × the battery's power still overshoots as export. The *Mode* list gains *Cheap hours only* in Home Assistant, at the end. ### Reading the grid-following loop: `Loop integrator`, `Loop integrator lead`, `Loop reason` @@ -3282,9 +3282,8 @@ The **Batteries** tab has a card per battery: its level, and three lines. **Now** says what it does, **Today** lists the blocks planned for it (price trades, the monthly cycle, the peak limit), and **Why** says the reason. With battery modes on, each card also has the On/Off switch and the mode list; both -apply at once. Charging in cheap hours and selling are greyed out until a later -update, and Today reads "Not planned yet" when nothing is planned for the -battery. +apply at once. Today reads "Not planned yet" until the add-on has made the +day's price runs. An Off battery that the peak limit still needs says so, with the power it gives: "Off, but gives 0.5 kW for the peak limit." diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 89d0641..72520d4 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -21,7 +21,7 @@ from datetime import datetime, timedelta, timezone from . import arbitrage, messages, peakguard, uitext from .maintenance import CHARGE as M_CHARGE, DRAIN as M_DRAIN, HOLD as M_HOLD from .maintenance import IDLE as M_IDLE -from .packmode import CHEAP_HOURS, LEFTOVER_SOLAR, SOLAR_FIRST +from .packmode import CHEAP_HOURS, GRID_CHARGE_MODES, LEFTOVER_SOLAR, SOLAR_FIRST from .price import Absence, Uncertainty, brussels from .static_tariff import static_plan from .tariff import BILLING_TZ @@ -345,9 +345,9 @@ def mode_runs(c, day0, day1, now, shadow): else (soc - floor)) / 100.0 * cap) return kwh blocks = [] - if rp.charge_useful(): + if rp.charge_useful() and pm.mode in GRID_CHARGE_MODES: blocks.append(("grid", rp.cheap)) - sell = rp.sell if pm.sell else None + sell = rp.sell if pm.sell and pm.can_sell else None for g in rp.give: if sell is not None and g.start <= sell.start < g.end: blocks.append(("sell", sell)) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 75c968c..ac2962b 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -2303,6 +2303,8 @@ class Controller: self._maint_stop_off(self.maints[self.inverters.index(inv)], now) elif what == "pack_sell": + if not packmode.SELLING_ENABLED: + return {"error": messages.pack_refused("sell_off")} if not isinstance(value, bool): return {"error": messages.pack_refused("value")} inv.store_set(packmode.SELL_KEY, value) diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index b4fa6f7..4445a60 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -938,6 +938,8 @@ PACK_REFUSED = { "off": "Battery modes are off. Turn on “Battery modes” first.", "unit": "There is no battery with that name.", "value": "That choice is not possible for this battery.", + # OPT-11 P3, owner decision 2026-09-29: selling is off for now. + "sell_off": "Selling is off for now.", # OPT-11 P2: a Home Assistant command dropped before it reaches a battery. "retained": "An old saved command is not used.", "size": "That command is too long.", diff --git a/goodwe_controller/app/modetrade.py b/goodwe_controller/app/modetrade.py index 1c5b4a6..81fa61d 100644 --- a/goodwe_controller/app/modetrade.py +++ b/goodwe_controller/app/modetrade.py @@ -44,7 +44,8 @@ Rules that keep this safe (tests: test_modes_p3.py): from dataclasses import dataclass -from .packmode import CHEAP_HOURS, LEFTOVER_SOLAR, SOLAR_FIRST +from .packmode import (CHEAP_HOURS, GRID_CHARGE_MODES, LEFTOVER_SOLAR, + SOLAR_FIRST) OFF, HOUSE, HOLD, GIVE, SELL, CHARGE, REST = ( "off", "house", "hold", "give", "sell", "charge", "rest") @@ -88,10 +89,10 @@ def _room_kwh(p: Pack, pct: float) -> float: def chargers(packs, ceiling_pct, done=()) -> list: - """Batteries that may charge from the grid in a cheap run (P3: no - forecast, so Leftover solar acts as Cheap hours only; owner answer 4).""" + """Batteries that may charge from the grid in a cheap run: the modes in + `packmode.GRID_CHARGE_MODES` (Cheap hours only until P4's forecast).""" return [p for p in packs - if p.use and p.idle and p.live and p.mode in PRICE_MODES + if p.use and p.idle and p.live and p.mode in GRID_CHARGE_MODES and p.soc is not None and p.soc < ceiling_pct and p.refused >= 0 and p.name not in done] diff --git a/goodwe_controller/app/packmode.py b/goodwe_controller/app/packmode.py index e13f05a..5fd71fe 100644 --- a/goodwe_controller/app/packmode.py +++ b/goodwe_controller/app/packmode.py @@ -40,6 +40,17 @@ USE_KEY = "pack_use" MODE_KEY = "pack_mode" SELL_KEY = "pack_sell" # OPT-11 P3: sell in the sell run +# Owner decision 2026-09-29 (option A): selling is off until it can be judged +# on the price the grid pays. While False, `read()` answers `sell=False` +# whatever the store holds, the page shows no switch and `pack_sell` is +# refused; the sell code in modetrade/priceruns stays, unreachable. +SELLING_ENABLED = False + +# The modes that may charge from the grid in a cheap run. Leftover solar joins +# when the solar forecast exists (P4); until then it takes solar only (owner +# decision 2026-09-29, option A). +GRID_CHARGE_MODES = (CHEAP_HOURS,) + def enabled(opts) -> bool: """Battery modes are on only when the option is exactly true. One answer, @@ -56,8 +67,9 @@ class PackMode: @property def can_sell(self) -> bool: - """Selling applies to the price modes only; Solar first never sells.""" - return self.mode in (LEFTOVER_SOLAR, CHEAP_HOURS) + """Selling applies to the price modes only; Solar first never sells. + False for every battery while SELLING_ENABLED is False.""" + return SELLING_ENABLED and self.mode in (LEFTOVER_SOLAR, CHEAP_HOURS) @property def key(self) -> str: @@ -73,7 +85,8 @@ def read(data: dict, name: str) -> PackMode: mode = data.get(unit_key(name, MODE_KEY), DEFAULT_MODE) return PackMode(use=use is not False, mode=mode if mode in MODES else DEFAULT_MODE, - sell=data.get(unit_key(name, SELL_KEY)) is True) + sell=SELLING_ENABLED + and data.get(unit_key(name, SELL_KEY)) is True) def mode_range(pm: PackMode, rating_w: float) -> tuple: diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index ce1f46b..8c3fca9 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -314,8 +314,8 @@ /* ---------------- Batteries (UX-13 P3) ---------------- */ // One card per battery. With battery modes on (`mode_key` in /status) each // card has an On/Off switch and a mode list, sent as `pack_use` and - // `pack_mode` through /action (OPT-11 P1), and a selling switch, sent as - // `pack_sell` (P3; Leftover solar and Cheap hours only). The Now, Today and Why lines are + // `pack_mode` through /action (OPT-11 P1). Selling has no switch while it + // is off (owner decision 2026-09-29). The Now, Today and Why lines are // homeview.py's sentences. The Simple settings view draws the same switch // and list into its own card (simpleHost). const MODES = ["solar_first", "leftover_solar", "cheap_hours"]; @@ -331,7 +331,6 @@ const j = await r.json().catch(() => ({})); if (!r.ok) toast(j.error || t("toast.failed")); else if (what === "pack_use") toast(say(value ? t("batteries.toast.on") : t("batteries.toast.off"), { name: b.name })); - else if (what === "pack_sell") toast(say(value ? t("batteries.toast.sell_on") : t("batteries.toast.sell_off"), { name: b.name })); else toast(say(t("batteries.toast.mode"), { name: b.name, mode: t("batteries.choice." + value + ".name") })); } catch (e) { toast(t("toast.failed")); } finally { packBusy = false; } @@ -348,16 +347,6 @@ onchange: (e) => packAct("pack_mode", b, e.target.value) }, ...MODES.map((k) => h("option", { value: k, selected: b.mode_choice === k }, t("batteries.choice." + k + ".name")))); } - function sellRow(b, i, where) { - const lid = "bsl-" + where + i; - const can = b.use && b.can_sell === true; - return h("div", { class: "f inline" }, - h("div", {}, h("div", { class: "lbl", id: lid }, t("batteries.sell.name")), - h("div", { class: "help" }, b.can_sell === true ? t("batteries.sell.description") : t("batteries.sell.off"))), - h("div", { class: "ctl" }, h("button", { type: "button", class: "switch", role: "switch", id: "bsw-sell-" + where + i, - "aria-checked": String(can && b.sell === true), "aria-labelledby": lid, disabled: !can, - onclick: () => packAct("pack_sell", b, !(b.sell === true)) }))); - } function todayLines(b) { if (!b.today || !b.today.length) return b.today_line || "–"; return b.today.map((r) => h("div", {}, r.from + " " + t("plan.time_to") + " " + r.to + ": " + r.what)); @@ -375,8 +364,7 @@ modes ? h("div", { class: "modebox" }, h("label", { class: "lbl small", for: "bsel-c" + i }, t("batteries.mode")), modeSelect(b, i, "c", null), - h("div", { class: "help" }, t("batteries.choice." + b.mode_key + ".description")), - sellRow(b, i, "c")) : null, + h("div", { class: "help" }, t("batteries.choice." + b.mode_key + ".description"))) : null, levelBar(b.level_pct, b.name), h("dl", { class: "kv" }, h("dt", {}, t("batteries.level")), h("dd", {}, lvl + stored), diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 565ca62..ddb987b 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -87,20 +87,19 @@ "on": "On", "off": "Off", "choice": { "solar_first": {"name": "Solar first", "description": "Charges from solar before the other batteries and covers the house."}, - "leftover_solar": {"name": "Leftover solar", "description": "Gets solar the others cannot take, charges in cheap hours and gives power in expensive ones."}, + "leftover_solar": {"name": "Leftover solar", "description": "Gets solar the others cannot take, and gives power in expensive hours."}, "cheap_hours": {"name": "Cheap hours only", "description": "Charges in the cheapest hours and gives power in the expensive ones."}, "off": {"name": "Off", "description": "Rests, and helps only when the peak limit needs it."} }, "today": "Today", "why": "Why", - "sell": {"name": "Sell in expensive hours", "description": "Also sells to the grid in the most expensive hours, but you are paid less than you pay for power.", "off": "Not for Solar first."}, "modes_off": {"name": "Battery modes are off"}, "how": {"name": "How the modes work", "description": "Which battery gets solar first, and when each gives power.", "solar_first": {"description": "Solar first gets spare solar before the other batteries, and covers the house at any hour."}, - "leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, charges in cheap hours, and saves its power for expensive hours."}, + "leftover_solar": {"description": "Leftover solar gets the solar the Solar first batteries cannot take, and saves its power for expensive hours."}, "cheap_hours": {"description": "Cheap hours only charges in the cheapest hours and gives power in the expensive ones."}, "off": {"description": "Off rests the battery and starts no monthly cycle, but the peak limit may still use it."}, "rules": {"description": "The peak limit and the safety stops come first, and while one battery charges from the grid the others rest."}}, - "toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}.", "sell_on": "{name} sells in expensive hours.", "sell_off": "{name} does not sell."}}, + "toast": {"on": "{name} is on.", "off": "{name} is off.", "mode": "{name}: {mode}."}}, "settings": {"name": "Settings", "description": "The settings are grouped by task below.", "open": "Open the settings page"} }, "choices_later": { diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 9151605..086cb56 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -84,20 +84,19 @@ "on": "Aan", "off": "Uit", "choice": { "solar_first": {"name": "Eerst zonne-energie", "description": "Laadt met zonne-energie vóór de andere batterijen en dekt het huis."}, - "leftover_solar": {"name": "Overschot zonne-energie", "description": "Krijgt zonne-energie die de andere niet opnemen, laadt in goedkope uren en levert in dure uren."}, + "leftover_solar": {"name": "Overschot zonne-energie", "description": "Krijgt zonne-energie die de andere niet opnemen, en levert in dure uren."}, "cheap_hours": {"name": "Alleen goedkope uren", "description": "Laadt in de goedkoopste uren en levert in de dure uren."}, "off": {"name": "Uit", "description": "Rust, en helpt alleen als de piekgrens haar nodig heeft."} }, "today": "Vandaag", "why": "Waarom", - "sell": {"name": "Verkopen in dure uren", "description": "Verkoopt ook aan het net in de duurste uren, maar u krijgt minder dan u voor stroom betaalt.", "off": "Niet voor Eerst zonne-energie."}, "modes_off": {"name": "Batterijmodi staan uit"}, "how": {"name": "Zo werken de modi", "description": "Welke batterij eerst zonne-energie krijgt, en wanneer elke batterij levert.", "solar_first": {"description": "Eerst zonne-energie krijgt het overschot vóór de andere batterijen, en dekt het huis op elk uur."}, - "leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, laadt in goedkope uren en spaart haar stroom voor dure uren."}, + "leftover_solar": {"description": "Overschot zonne-energie krijgt wat de batterijen met Eerst zonne-energie niet opnemen, en spaart haar stroom voor dure uren."}, "cheap_hours": {"description": "Alleen goedkope uren laadt in de goedkoopste uren en levert in de dure uren."}, "off": {"description": "Uit laat de batterij rusten en start geen maandelijkse cyclus, maar de piekgrens mag haar nog gebruiken."}, "rules": {"description": "De piekgrens en de veiligheidsstops gaan voor, en terwijl een batterij van het net laadt rusten de andere."}}, - "toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}.", "sell_on": "{name} verkoopt in dure uren.", "sell_off": "{name} verkoopt niet."}}, + "toast": {"on": "{name} staat aan.", "off": "{name} staat uit.", "mode": "{name}: {mode}."}}, "settings": {"name": "Instellingen", "description": "De instellingen staan hieronder per taak.", "open": "Instellingen openen"} }, "choices_later": {"region": {"wallonia": "Wallonië, nog geen standaardwaarde", "brussels": "Brussel, nog geen standaardwaarde"}}, diff --git a/goodwe_controller/test_batteries_screen.py b/goodwe_controller/test_batteries_screen.py index 4654f01..cb457c1 100644 --- a/goodwe_controller/test_batteries_screen.py +++ b/goodwe_controller/test_batteries_screen.py @@ -36,7 +36,7 @@ import aiohttp # noqa: E402 from aiohttp import web as aioweb # noqa: E402 import ux13_demo as D # noqa: E402 -from app import homeview, packmode, uilayout as L, uipage, web # noqa: E402 +from app import homeview, messages, packmode, uilayout as L, uipage, web # noqa from app.maintenance import IDLE, DRAIN # noqa: E402 fails = [] @@ -225,11 +225,14 @@ print(f" morning: {_kinds}, lines {_p['plan']['lines']}") check("in the morning, with trades and a cycle ahead: Solar first A follows " "the house and has its cycle but no price block (OPT-11 P3: Solar first " "never trades), Off B has no block and waits for no cycle; with B on " - "(Leftover solar) B has its cheap and expensive runs and waits", + "(Leftover solar) B has its expensive run but no grid block (it takes " + "solar only until the forecast, owner decision 2026-09-29) and waits", {"house", "cycle"} == _kinds[0] and not _kinds[1] and not any(B_NAME in x for x in _p["plan"]["lines"]) - and {"grid", "give"} <= {r["kind"] for r in _m["plan"]["runs"] - if r["battery"] == 1} + and "give" in {r["kind"] for r in _m["plan"]["runs"] + if r["battery"] == 1} + and "grid" not in {r["kind"] for r in _m["plan"]["runs"] + if r["battery"] == 1} and any(B_NAME in x for x in _m["plan"]["lines"])) _p = build("off_peak") check("...but the peak block stays on it while the peak limit needs it", @@ -381,14 +384,15 @@ check("switch B back on: its stored mode returns", == packmode.LEFTOVER_SOLAR) check("OPT-11 P3: Cheap hours only is a mode now: 200, and /status shows it", _s4 == 200 and _st4["batteries"][0]["mode_choice"] - == packmode.CHEAP_HOURS and _st4["batteries"][0]["can_sell"] is True) -check("...selling on for A: 200, stored, and /status says so", - _s5 == 200 and _j5["result"]["sell"] is True - and _st5["batteries"][0]["sell"] is True) -check("...a selling value that is not true or false, and a mode that does not " - "exist, are refused with a plain 400, and nothing changes", - _s6 == 400 and _j6["error"] and _s7 == 400 and _j7["error"] - and _st7["batteries"][0]["sell"] is True + == packmode.CHEAP_HOURS) +check("owner decision 2026-09-29 (option A): selling is off, so a posted " + "pack_sell is refused with the plain reason 'Selling is off for now.', " + "and /status says no battery sells or can", + _s5 == 400 and _j5["error"] == messages.pack_refused("sell_off") + and _s6 == 400 and all(b["sell"] is False and b["can_sell"] is False + for b in _st5["batteries"] + _st6["batteries"])) +check("...a mode that does not exist is refused with a plain 400, and " + "nothing changes", _s7 == 400 and _j7["error"] and _st7["batteries"][0]["mode_choice"] == packmode.CHEAP_HOURS) _r = asyncio.run(_serve("running", [ ({"action": "pack_use", "unit": B, "value": False}, "en")])) @@ -412,18 +416,19 @@ check("Settings has a Simple / Installer choice as a radio group, and Simple " and PAGE.count('role="radio"') >= 2 and 'id="simple"' in PAGE) _acts = set(re.findall(r'packAct\("(\w+)"', JS)) check(f"the cards post only the existing actions ({sorted(_acts)}), as " - f"{{action, unit, value}}", _acts == set(web.PACK_ACTIONS) + f"{{action, unit, value}}; selling has no control while it is off", + _acts == set(web.PACK_ACTIONS) - {"pack_sell"} + and packmode.SELLING_ENABLED is False and "action: what, unit: b.name, value: value" in JS) check("the switch is a real switch and the list offers the three modes, " "cheap hours included, with nothing greyed out", 'role: "switch"' in JS and '"aria-checked"' in JS and 'const MODES = ["solar_first", "leftover_solar", "cheap_hours"];' in JS and "batteries.later" not in JS) -check("the selling switch posts pack_sell, and is greyed out where selling " - "does not apply (Off, Solar first)", - 'packAct("pack_sell", b, ' in JS - and "const can = b.use && b.can_sell === true;" in JS - and "disabled: !can" in JS) +check("no selling switch anywhere on the page or in Settings, and no words " + "for one", "pack_sell" not in JS and "sell" not in SJS + and "batteries.sell" not in JS + and all("sell" not in W["home"]["batteries"] for W in LANGS.values())) _T = uipage.ui_text("en") _lay = uipage.layout(D.schema_ui(D.CONFIG), {"en": {}}) _simple = [f for g in _lay["groups"] for p in g["parts"] for f in p["fields"] diff --git a/goodwe_controller/test_modes_p3.py b/goodwe_controller/test_modes_p3.py index 5a8207b..5dc2fa2 100644 --- a/goodwe_controller/test_modes_p3.py +++ b/goodwe_controller/test_modes_p3.py @@ -19,11 +19,13 @@ time. DECISIONS/OPT-11-battery-modes.md has the record. alone never trades. 7. A run edge reseeds the loop (handover measured with and without). 8. The site Why row: a limit that pushes power up does not "hold it back" (F2). -9. The selling switch (`pack_sell`). +9. Selling is off (owner, 2026-09-29): `pack_sell` refused, read as false. 10. The Batteries screen: Why and Today lines from the roles and runs. 11. Review additions: modes on ignore the site trade switch, a battery in maintenance takes no part, the headroom stop latches for the period. +12. Option A: no sale in a day; Leftover solar never grid-charges (P4). + Mutations (MUTATION.md, purged copies, graded over this file and the named tests) are listed in the pull request. """ @@ -272,7 +274,7 @@ for _ in range(20000): _bad.append(("range without 0", name, lo, hi)) for name, role in tk.roles.items(): p = by[name] - if role == modetrade.CHARGE and (p.mode == packmode.SOLAR_FIRST + if role == modetrade.CHARGE and (p.mode != packmode.CHEAP_HOURS or p.refused < 0 or not p.use or p.soc is None or p.soc >= 95.0): _bad.append(("bad charger", p)) @@ -359,6 +361,11 @@ def run_day(variant, *, house_w=2600.0, start_h=0.75, hours=21.0, return rows, st, c +# Selling is off (owner, 2026-09-29, option A). Its code is kept behind +# packmode.SELLING_ENABLED, and these checks turn it on to hold that code to +# its invariants; part 12 checks it is unreachable with the flag as shipped. +_SELL_SHIPPED = packmode.SELLING_ENABLED +packmode.SELLING_ENABLED = True ROWS, ST, _c4 = run_day("p3_ch_sell", soc0={"a": 60.0, "b": 30.0}) charge = [r for r in ROWS if r["action"] == arbitrage.CHARGE] sell = [r for r in ROWS if r["action"] == arbitrage.DISCHARGE] @@ -455,6 +462,7 @@ print(f" from 24 %: sold {len(_sf)} cycles, B ends at " check("the sale stops at arbitrage_soc_floor and does not re-arm in the run", _sf and _after and all(r["action"] != arbitrage.DISCHARGE for r in _after)) +packmode.SELLING_ENABLED = _SELL_SHIPPED # N=1: one Cheap hours battery. ROWS1, _, _ = run_day("p3_ch_sell", n=1, soc0={"a": 30.0}, @@ -551,32 +559,24 @@ check("...and a trade the peak floor raised reads the same way", [Claim.set("arbitrage", P_ARBITRAGE, -1000.0)]) is True) # ============================================================================ # -print("\n9. the selling switch") +print("\n9. the selling switch is off (owner decision 2026-09-29, option A)") _st = rp._Store() +_st.data[unit_key(B, packmode.SELL_KEY)] = True # an old stored "on" +_st.data[unit_key(B, packmode.MODE_KEY)] = packmode.CHEAP_HOURS _ctl = Controller(dict(rp.options(True, False)), rp.Hass(("a", "b"), lambda t: 0.0), _st, rp._Pub(), stop=asyncio.Event()) -_r1 = asyncio.run(_ctl.handle_action("pack_sell", unit=B, value=True)) -_bad9 = [asyncio.run(_ctl.handle_action("pack_sell", unit=B, value=v)) - for v in ("yes", 1, 0, None)] -_bad9.append(asyncio.run(_ctl.handle_action("pack_sell", unit="x", - value=True))) -check("pack_sell stores true/false per battery, logs it, and returns it", - _r1 == {"unit": B, "use": True, "mode": packmode.SOLAR_FIRST, - "sell": True} +_r9 = [asyncio.run(_ctl.handle_action("pack_sell", unit=B, value=v)) + for v in (True, False, "yes")] +check("pack_sell is refused with the plain reason 'Selling is off for now.' " + "and stores nothing", + all(x == {"error": messages.pack_refused("sell_off")} for x in _r9) and _st.data[unit_key(B, packmode.SELL_KEY)] is True - and any("selling switched on" in str(e) for e in _ctl.events)) -check("...anything else (1, 0, 'yes', None, an unknown battery) is refused " - "with a plain reason and stores nothing", - all(set(x) == {"error"} for x in _bad9) - and _st.data[unit_key(B, packmode.SELL_KEY)] is True) -check("...Solar first never sells, even with the switch on", - packmode.read(_st.data, B).sell is True - and packmode.read(_st.data, B).can_sell is False) -_off_ctl = Controller(dict(rp.options(False, False)), rp.Hass( - ("a", "b"), lambda t: 0.0), rp._Store(), rp._Pub(), stop=asyncio.Event()) -check("...and with battery modes off it is refused like the others", - "error" in asyncio.run(_off_ctl.handle_action("pack_sell", unit=B, - value=True))) + and not any("selling switched" in str(e) for e in _ctl.events)) +check("...a stored 'on' reads as false: no battery sells or can, whatever " + "the store holds", packmode.SELLING_ENABLED is False + and packmode.read(_st.data, B).sell is False + and packmode.read(_st.data, B).can_sell is False + and all(p.sell is False for p in _ctl._mode_packs())) # ============================================================================ # print("\n10. the Batteries screen") @@ -587,11 +587,13 @@ check("every role's Why line has words in English and Dutch, and they differ", all(k in _en["home_words"]["why"] and k in _nl["home_words"]["why"] and _en["home_words"]["why"][k] != _nl["home_words"]["why"][k] for k in _keys)) +packmode.SELLING_ENABLED = True # the kept sell code, as in part 4 _c10 = run_day("p3_ch_sell", start_h=18.0, hours=0.5, soc0={"a": 60.0, "b": 80.0})[2] _now10 = D0 + timedelta(hours=18, minutes=30) _plan = homeview.mode_runs(_c10, *homeview.local_day(_now10.astimezone( timezone.utc)), _now10.astimezone(timezone.utc), False) +packmode.SELLING_ENABLED = _SELL_SHIPPED print(f" plan blocks for B at 18:30: " f"{[(r['from'], r['to'], r['kind'], r['what']) for r in _plan[0]]}") check("the plan draws B's expensive run, the sale inside it, and nothing " @@ -657,6 +659,60 @@ if _nm is not None and _cm2.mode_tick is not None \ check("a charge the headroom stopped stays off for the rest of the period, " "even when the headroom comes back, and may start in the next one", _ok8) +# ============================================================================ # +print("\n12. option A: no sale, and Leftover solar takes solar only (P4)") +ROWS_A, _, _ = run_day("p3_ch_sell", soc0={"a": 60.0, "b": 30.0}, + choice={"a": (True, "solar_first", False), + "b": (True, "cheap_hours", True)}) +print(f" Cheap hours B with a stored sell 'on': " + f"{sum(r['action'] == arbitrage.CHARGE for r in ROWS_A)} charging, " + f"{sum(r['action'] == arbitrage.DISCHARGE for r in ROWS_A)} selling") +check("with selling on in the store, a whole day has no sale and no sell " + "role, while Cheap hours only still charges from the grid", + all(r["action"] != arbitrage.DISCHARGE for r in ROWS_A) + and all(modetrade.SELL not in r["roles"].values() for r in ROWS_A) + and any(r["action"] == arbitrage.CHARGE for r in ROWS_A)) +ROWS_L, _, _c12 = run_day("p3_ch_sell", soc0={"a": 60.0, "b": 30.0}, + choice={"a": (True, "solar_first", False), + "b": (True, "leftover_solar", True)}) +_lh = [r for r in ROWS_L if r["roles"].get(B) == modetrade.HOLD] +_lg = [r for r in ROWS_L if r["roles"].get(B) == modetrade.GIVE] +print(f" Leftover solar B: {len(_lh)} holding, {len(_lg)} giving, " + f"grid trades {sorted({str(r['action']) for r in ROWS_L})}") +check("Leftover solar never charges from the grid before the forecast: no " + "grid trade and no charge role all day, in the same cheap run", + all(r["action"] is None for r in ROWS_L) + and all(r["roles"].get(B) != modetrade.CHARGE for r in ROWS_L)) +check("...it still saves its power and gives it in the expensive hours", + _lh and _lg and all(r["now"].astimezone(L).hour == 19 for r in _lg)) +_pk = [modetrade.Pack("x", True, m, False, 2500.0, 30.0, 10.0) + for m in packmode.MODES] +check("...only Cheap hours only is a grid charger (packmode.GRID_CHARGE_MODES)", + [p.mode for p in modetrade.chargers(_pk, 95.0)] + == [packmode.CHEAP_HOURS]) +_c12b = run_day("p3_ch_sell", start_h=0.75, hours=0.25, + soc0={"a": 60.0, "b": 30.0}, + choice={"a": (True, "solar_first", False), + "b": (True, "leftover_solar", True)})[2] +_n12 = UTC0 + timedelta(hours=1) +_plan12 = homeview.mode_runs(_c12b, *homeview.local_day(_n12), _n12, + False)[0] +print(f" Leftover solar plan at 01:00: " + f"{[(r['from'], r['to'], r['kind']) for r in _plan12]}") +check("...and the plan draws no grid block for it, only its expensive run", + _plan12 and all(r["kind"] != "grid" for r in _plan12)) +_enw, _nlw = homeview.uitext.words("en"), homeview.uitext.words("nl") +check("...and its help text promises no grid charging (EN and NL)", + all("cheap" not in t.lower() and "goedkop" not in t.lower() + for t in (_enw["home"]["batteries"]["choice"]["leftover_solar"] + ["description"], + _nlw["home"]["batteries"]["choice"]["leftover_solar"] + ["description"], + _enw["home"]["batteries"]["how"]["leftover_solar"] + ["description"], + _nlw["home"]["batteries"]["how"]["leftover_solar"] + ["description"]))) + print() if fails: print(f"{len(fails)} FAILED:") -- 2.54.0 From 71045152295f1d9a52b017c2fe03246c8a7bf68c Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Tue, 29 Sep 2026 11:21:32 +0200 Subject: [PATCH 078/105] OPT-11 P3 option A review: wizard no longer says modes come later Step 5 said "Choosing a mode for each battery comes in a later update", stale since P1. It now points to battery modes on the Batteries screen (EN/NL); test_setup checks the new line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/app/ui_text/en.json | 2 +- goodwe_controller/app/ui_text/nl.json | 2 +- goodwe_controller/test_setup.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index ddb987b..57d70c9 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -209,7 +209,7 @@ "5": {"name": "Peak limit", "description": "The grid stays under this limit, averaged over each 15-minute period."}, "6": {"name": "Check and start", "description": "The add-on checks everything with its own start checks, then restarts."} }, - "modes_later": {"description": "Choosing a mode for each battery comes in a later update."}, + "modes_later": {"description": "After setup, turn on battery modes to choose a mode for each battery on the Batteries screen."}, "kettle": { "name": "Check the direction", "description": "Read the meter, switch on a kettle, then read the meter again.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 086cb56..5690fc7 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -190,7 +190,7 @@ "5": {"name": "Piekgrens", "description": "Het net blijft onder deze grens, gemiddeld over elk kwartier."}, "6": {"name": "Nakijken en starten", "description": "De add-on kijkt alles na met zijn eigen startcontroles en herstart dan."} }, - "modes_later": {"description": "Een modus kiezen per batterij komt in een latere update."}, + "modes_later": {"description": "Zet na de installatie batterijmodi aan om per batterij een modus te kiezen op het scherm Batterijen."}, "kettle": { "name": "Richting nakijken", "description": "Lees de meter af, zet een waterkoker aan en lees de meter opnieuw af.", diff --git a/goodwe_controller/test_setup.py b/goodwe_controller/test_setup.py index 00f2efe..bf37557 100644 --- a/goodwe_controller/test_setup.py +++ b/goodwe_controller/test_setup.py @@ -76,8 +76,8 @@ check("the mockup's six steps: meter, inverters, solar, prices, peak limit, " and [WS["steps"][str(n)]["name"] for n in range(1, 7)] == ["Your meter", "Inverters and batteries", "Solar", "Prices", "Peak limit", "Check and start"]) -check("battery modes are not a step yet (OPT-11): step 5 says they come later", - "later update" in WS["modes_later"]["description"] +check("battery modes are not a wizard step (OPT-11): step 5 points to the Batteries screen", + "Batteries screen" in WS["modes_later"]["description"] and not any("mode" in k for k in BY_STEP[5])) SPEC = uipage.setup_spec() check("the spec the page reads is the table's", -- 2.54.0 From eb10537aee1f68cd02dcea555b06e88fb6a5ab33 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Tue, 29 Sep 2026 19:29:32 +0200 Subject: [PATCH 079/105] OPT-11 P4: solar forecast and day plan A Home Assistant solar forecast (Forecast.Solar, Solcast or Open-Meteo shapes) and the add-on's own hourly house use decide, before each cheap run, whether the sun will fill each battery before the expensive hours. Leftover solar then buys from the grid only the shortfall; Cheap hours only skips the part the sun covers; Solar first never grid-charges. No, stale or failed forecast: P3 option A exactly (12 digests pinned from 5a4cdc2). Replay (16 recorded days, forecast errors from Elia's day-ahead BE solar): year-earlier prices P4 19.15 vs P2 19.33 / option A 19.44 / old trade 18.14; real 2026 prices P4 29.19 vs 32.26 / 32.01 / 31.40 EUR net. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 41 ++ goodwe_controller/DOCS.md | 15 +- goodwe_controller/app/dayplan.py | 256 +++++++ goodwe_controller/app/homeview.py | 87 ++- goodwe_controller/app/main.py | 121 ++- goodwe_controller/app/messages.py | 5 + goodwe_controller/app/modetrade.py | 63 +- goodwe_controller/app/packmode.py | 9 +- goodwe_controller/app/solarfc.py | 251 +++++++ goodwe_controller/app/static/app.js | 3 + goodwe_controller/app/static/index.html | 1 + goodwe_controller/app/static/settings.js | 11 + goodwe_controller/app/ui_text/en.json | 8 +- goodwe_controller/app/ui_text/nl.json | 8 +- goodwe_controller/app/uilayout.py | 9 +- goodwe_controller/app/validate.py | 47 +- goodwe_controller/config.yaml | 10 + ...-be-solar-price-2026-09-01_2026-09-17.json | 1 + goodwe_controller/test_batteries_screen.py | 9 + goodwe_controller/test_modes_p4.py | 692 ++++++++++++++++++ goodwe_controller/tools/opt11p4_identity.py | 112 +++ goodwe_controller/tools/opt11p4_replay.py | 242 ++++++ goodwe_controller/translations/en.yaml | 9 + goodwe_controller/translations/nl.yaml | 9 + 24 files changed, 1984 insertions(+), 35 deletions(-) create mode 100644 goodwe_controller/app/dayplan.py create mode 100644 goodwe_controller/app/solarfc.py create mode 100644 goodwe_controller/scenarios/energy-charts-be-solar-price-2026-09-01_2026-09-17.json create mode 100644 goodwe_controller/test_modes_p4.py create mode 100644 goodwe_controller/tools/opt11p4_identity.py create mode 100644 goodwe_controller/tools/opt11p4_replay.py diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 5c58558..b5d970c 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -75,3 +75,44 @@ P1 is its section 6 P1, and the pull request lists what was measured. P2's 19.33; Solar first + Cheap hours only 19.57. - Not done in P3: the forecast (P4), and a headroom too short for the run moving the rest to the next cheap periods. + +## P4: the solar forecast and the day plan (2026-09-29) +- Input: a Home Assistant forecast sensor (`pv_forecast_entity`, kWh left + today; `pv_forecast_tomorrow_entity` optional), read by `app/solarfc.py`. + Supported shapes: Forecast.Solar (state only), Solcast (`detailedForecast`) + and Open-Meteo Solar Forecast (`wh_period`). The unit is read, not guessed; + older than 3 h is stale (one missed hourly poll must not flag it). +- Trust: `solar_trust_pct`, default 70 (owner answer 5). +- House use: nothing the add-on recorded fitted. `tariff.db` holds grid + import per quarter, which the batteries shape. So `dayplan.HouseProfile` + keeps grid + battery per local hour for 7 days in the store + (`house_profile`), median per hour. It is net of the solar the house used, + so the solar sum never takes it below the night median. Solar readings are + not used (TEL-11). The first plan needs one day of it. +- Verdict (`dayplan.plan()`): trust x sum max(0, forecast - house) x 0.95 + until the expensive run the cheap run is for. Solar first takes it first. + - Leftover solar may then charge from the grid up to min(ceiling, floor + + the house's use in the expensive runs / 0.95), less its sun share: only + the shortfall. + - Cheap hours only charges up to the ceiling less its sun share. + - Solar first never charges from the grid (owner, 2026-09-29). +- The level is kept unless it moves by min(1 kWh, 10 %). With no plan + (no, stale or failed forecast, no house profile, no capacity) every mode + is P3 option A exactly: `test_modes_p4.py` part 1 pins 12 digests from + 5a4cdc2 (modes on, with and without an unavailable forecast). +- The plan is made with the runs (every 15 min, or at once when the forecast + comes or goes). A lost forecast drops the levels at the next cycle. +- Not done: the design's scaling by measured solar from 10:00 (it needs the + solar readings TEL-11 keeps out), the HA `goodwe_<inv>_plan` sensor, and + FCST-01. +- Replay (`tools/opt11p4_replay.py`, 16 recorded days, Solar first + Leftover + solar, net EUR, lower is better; site solar rebuilt from the recording, + forecast errors from Elia's day-ahead Belgian solar forecast): + - year-earlier hourly prices: P2 19.33, P3 option A 19.44, old one-period + trade 18.14, P4 19.15 (perfect forecast 19.14, 1.5 x too high 19.16, + missing 19.44); + - the days' real 2026 quarter-hourly prices (held out): P2 32.26, option A + 32.01, old trade 31.40, P4 29.19 (perfect 29.21, too high 29.28, missing + 32.01). + No threshold was tuned to these days. The 2026-09-24 PV recording could not + be replayed: it is only in the live Home Assistant. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 2da5da8..9b139fa 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -184,6 +184,9 @@ The label and description each setting shows on the Configuration tab, in tab or | Hardware · Inverter list | Usable battery capacity (kWh) (optional) | `inverters.capacity_kwh` | This battery's usable capacity from its datasheet. Fill it in on every inverter or on none. The add-on then shares the work by the energy each battery has left. | | Hardware | RS485 emergency stop is fitted | `estop_fitted` | Switch this on if the emergency stop is installed. It only changes a warning on the status page. | | Hardware | Battery modes | `battery_modes_enabled` | Give each battery an on and off switch and a mode, set on the Batteries screen. | +| Hardware | Solar forecast, today (kWh) | `pv_forecast_entity` | Optional. A forecast sensor with today's remaining solar energy, such as Forecast.Solar or Solcast. A battery then buys only what the sun will not give. | +| Hardware | Solar forecast, tomorrow (kWh) | `pv_forecast_tomorrow_entity` | Optional. The same forecast for tomorrow. It helps plan a cheap hour before midnight. | +| Hardware | Trust in the forecast (%) | `solar_trust_pct` | Forecasts are often too sunny. At 70 % the add-on plans with 7 of every 10 kWh forecast. | | Hardware | Solar production entity (W) | `pv_entity` | Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control. | | Hardware | Solar production entities, per inverter (W) | `pv_entities` | Optional. Use one row per solar inverter instead of “Solar production entity” when you have several. If one stops reporting, no total is recorded. | | Hardware | Reversed-sign solar entities | `pv_invert_entities` | Optional. Add each solar entity above that reads negative while producing, spelled the same way. Its sign is flipped before adding up. | @@ -522,7 +525,7 @@ Off by default. Turn it on, restart the add-on, and the Batteries screen (and Se - **On or off.** Off asks the battery for 0 W and starts no monthly cycle on it. A cycle that is running stops, and the add-on log says so. The peak limit may still use it, but only for what the other batteries cannot cover. - **Mode.** - *Solar first* charges from spare solar before the other batteries and covers the house at any hour. It never charges from the grid and never sells. - - *Leftover solar* charges from the solar the others cannot take, never from the grid (until the solar forecast arrives). It saves its power for the expensive hours and covers the house then. + - *Leftover solar* charges from the solar the others cannot take. With a solar forecast it may also charge from the grid, but only what the sun will not give (see below). It saves its power for the expensive hours and covers the house then. - *Cheap hours only* charges from the grid in the cheapest hours, saves its power for the expensive hours and covers the house then. - **Selling** is off until it can be judged on the price the grid pays (owner decision 2026-09-29, option A). @@ -535,6 +538,16 @@ With battery modes on, these choices replace the *Charging and selling on price* - A carried (not yet published) price is never used. A run that has started runs to its end. - With no prices, or too small a gap, every battery follows the house. +**Solar forecast** (`pv_forecast_entity`, optional). A Home Assistant sensor with the solar energy still to come today, in kWh. These work: Forecast.Solar (`sensor.energy_production_today_remaining`), Solcast PV Forecast (`sensor.solcast_pv_forecast_forecast_remaining_today`) and Open-Meteo Solar Forecast (`sensor.energy_production_today_remaining`). Set `pv_forecast_tomorrow_entity` to the matching *tomorrow* sensor to plan a cheap run before midnight. +- Before each cheap run the add-on asks: will the sun fill the batteries before the expensive hours? It counts on `solar_trust_pct` of the forecast (70 %), less what the house uses. Solar first batteries get that sun first. +- *Leftover solar* then charges from the grid only the shortfall: what the house will draw from it in the expensive hours, less its share of the sun. Not up to the top level. +- *Cheap hours only* fills to the top level less its share of the sun. +- *Solar first* never charges from the grid. +- The house use is the add-on's own measurement (grid + battery power) per hour, over the last 7 days. It needs one day of it before the first plan. +- The plan is checked every 15 minutes. A planned level moves only by 1 kWh or 10 %, so a wobbling forecast does not flip it. +- No forecast, one older than 3 hours, or no house use yet: *Leftover solar* takes solar only and *Cheap hours only* fills to the top level. The Batteries screen says so. +- A battery needs its capacity (`inverters.capacity_kwh`) for a plan. + **What always comes first.** - The peak limit, the safety stops and the monthly cycle come before a battery's mode. - A grid charge is sized so the 15-minute period stays under the peak limit less its margin (`peak_margin_w`). It starts only at 500 W or more. Once the peak limit stops it, it stays off for the rest of that 15-minute period. diff --git a/goodwe_controller/app/dayplan.py b/goodwe_controller/app/dayplan.py new file mode 100644 index 0000000..89ac1e7 --- /dev/null +++ b/goodwe_controller/app/dayplan.py @@ -0,0 +1,256 @@ +"""OPT-11 P4: the day plan. Will the sun fill each battery before the +expensive hours? If not, how much should it take from the grid? + +Pure: the forecast (`solarfc`), the house profile, the price runs and the +batteries in; a level per battery (`Plan.targets`) out. `modetrade.charge_to()` +turns the level into permission to charge from the grid; main.py rebuilds the +plan with the price runs (at most every 15 minutes) and keeps a level unless +it moves by `HYST_KWH` or `HYST_FRAC` (`hold()`). + +The sums (OPT-11-design section 1, "Excess solar", with the owner's answers): +* `sun`: trust x the solar the house will not use, between now and the + expensive run the cheap run is for, x the charge efficiency: + `trust x sum_h max(0, forecast_h - house_h) x EFF`. +* Solar first batteries take it first, up to the ceiling. What is left is + shared by the Leftover solar and Cheap hours batteries by their room. +* A Cheap hours battery charges from the grid up to `ceiling - its share`. +* A Leftover solar battery charges only up to what the house will draw from + it in the expensive runs before the next cheap run, less its share: + `min(ceiling, floor + house use / EFF) - share`. So it buys only the + shortfall, not up to the ceiling. +* Solar first never charges from the grid (owner, 2026-09-29). + +The house profile is the add-on's own measurement, grid + battery power, per +local hour, over the last `PROFILE_DAYS` days; the estimate for an hour is the +median of that hour. It is net of the solar the house used itself, so for +the solar sum it is never taken below the night-time median (`base()`). +The site's own solar readings are not used: TEL-11 keeps them out of every +control decision. +""" + +import statistics +from dataclasses import dataclass +from datetime import datetime, timedelta, timezone + +from .packmode import CHEAP_HOURS, LEFTOVER_SOLAR, SOLAR_FIRST +from .tariff import BILLING_TZ + +EFF = 0.95 # charge (and discharge) efficiency +HYST_KWH = 1.0 # a kept level moves only by this much... +HYST_FRAC = 0.10 # ...or this share of the battery's shortfall +PROFILE_DAYS = 7 +MIN_HOURS = 20 # hours of a day recorded before it counts +NIGHT_HOURS = (0, 1, 2, 3, 4, 5, 22, 23) +DEFAULT_TRUST_PCT = 70 + +# Site verdicts (the page's forecast line). +SUNNY, PARTLY, DARK = "sunny", "partly", "dark" + + +# --------------------------------------------------------------------------- # +# The house profile +# --------------------------------------------------------------------------- # +def _local(t: datetime): + return t.astimezone(BILLING_TZ) + + +class HouseProfile: + """Hourly means of the house's net use (grid + battery power), kept per + local day and hour: `{"YYYY-MM-DD": {hour: [mean_w, samples]}}`. The + store holds `dump()`; `load()` takes it back and drops what is bad.""" + + def __init__(self, data=None): + self.days = {} + self._cur = None # (day, hour, sum, n) + if isinstance(data, dict): + self.load(data) + + def load(self, data): + for day, hours in data.items(): + if not isinstance(hours, dict): + continue + row = {} + for h, v in hours.items(): + try: + hi, w = int(h), float(v) + except (TypeError, ValueError): + continue + if 0 <= hi < 24 and abs(w) < 1e6: + row[hi] = w + if row: + self.days[str(day)] = row + + def dump(self) -> dict: + return {d: {str(h): round(w, 1) for h, w in sorted(r.items())} + for d, r in sorted(self.days.items())} + + def add(self, now: datetime, house_w) -> bool: + """One reading. Returns True when an hour closed (then store it).""" + lt = _local(now) + key = (lt.strftime("%Y-%m-%d"), lt.hour) + closed = False + if self._cur is not None and self._cur[:2] != key: + day, hour, s, n = self._cur + if n >= 60: # about 5 minutes of readings + self.days.setdefault(day, {})[hour] = s / n + closed = True + self._cur = None + self._prune(lt) + if house_w is None: + return closed + if self._cur is None: + self._cur = (key[0], key[1], 0.0, 0) + d, h, s, n = self._cur + self._cur = (d, h, s + float(house_w), n + 1) + return closed + + def _prune(self, lt): + keep = (lt.date() - timedelta(days=PROFILE_DAYS)).isoformat() + for d in [d for d in self.days if d < keep]: + del self.days[d] + + def ready(self) -> bool: + """At least one day with `MIN_HOURS` hours recorded.""" + return any(len(r) >= MIN_HOURS for r in self.days.values()) + + def hour_w(self, hour: int): + vals = [r[hour] for r in self.days.values() if hour in r] + return statistics.median(vals) if vals else None + + def base(self): + vals = [w for h in NIGHT_HOURS if (w := self.hour_w(h)) is not None] + return statistics.median(vals) if vals else None + + def estimator(self): + """`f(hour) -> W`, or None when not ready. Fixed at call time.""" + if not self.ready(): + return None + base = self.base() or 0.0 + table = {} + for h in range(24): + w = self.hour_w(h) + table[h] = base if w is None else w + return lambda h: table[h], max(0.0, base) + + +# --------------------------------------------------------------------------- # +# The plan +# --------------------------------------------------------------------------- # +@dataclass(frozen=True) +class Plan: + verdict: str # SUNNY / PARTLY / DARK + sun_kwh: float # solar the batteries can count on + fc_kwh: float # the forecast over the same span + until: datetime # the expensive run the plan is for + targets: dict # name -> level % (LS and CH only) + need_kwh: dict # name -> kWh from the grid (0: none) + share_kwh: dict # name -> kWh of solar counted for it + + +def _hour_slices(t0, t1): + """Local-hour slices of [t0, t1): (start, end, local hour).""" + out, t = [], t0 + while t < t1: + lt = _local(t) + nxt = (lt.replace(minute=0, second=0, microsecond=0) + + timedelta(hours=1)).astimezone(timezone.utc) + e = min(nxt, t1) + out.append((t, e, lt.hour)) + t = e + return out + + +def _room(p, to_pct): + if p.capacity_kwh is None or p.soc is None: + return 0.0 + return max(0.0, float(to_pct) - float(p.soc)) / 100.0 * float( + p.capacity_kwh) + + +def plan(forecast, house, runs, now, packs, *, trust_pct, floor_pct, + ceiling_pct): + """The day plan, or None when there is none to make: no forecast, no + house profile yet, no price plan, or no expensive run after the cheap + run. `house` is `HouseProfile.estimator()`'s answer. `packs` are + `modetrade.Pack`s.""" + if forecast is None or house is None or runs is None or not runs.on \ + or runs.cheap is None: + return None + house_w, base_w = house + until = next((g for g in runs.give if g.start >= runs.cheap.end), None) + if until is None: + return None + trust = max(0.0, min(1.0, float(trust_pct) / 100.0)) + sun = fc_sum = 0.0 + for s, e, h in _hour_slices(now, until.start): + pv = forecast.between(s, e) + if pv is None: + return None # the span reaches a day with no forecast + hrs = (e - s).total_seconds() / 3600.0 + use = max(house_w(h), base_w) * hrs / 1000.0 + sun += max(0.0, pv - use) + fc_sum += pv + sun *= trust * EFF + + usable = [p for p in packs if p.use and p.live and p.idle + and p.soc is not None and p.capacity_kwh] + sf = [p for p in usable if p.mode == SOLAR_FIRST] + price = [p for p in usable if p.mode in (LEFTOVER_SOLAR, CHEAP_HOURS)] + sf_room = sum(_room(p, ceiling_pct) for p in sf) + excess = max(0.0, sun - sf_room) + rooms = {p.name: _room(p, ceiling_pct) for p in price} + total_room = sum(rooms.values()) + + # What the house draws in the expensive runs from the one this plan is + # for until the next cheap run (or a day), from the profile. + horizon = until.start + timedelta(hours=24) + use_kwh = 0.0 + for g in runs.give: + if g.start < until.start or g.start >= horizon: + continue + for s, e, h in _hour_slices(g.start, g.end): + use_kwh += max(0.0, house_w(h)) * ( + e - s).total_seconds() / 3600.0 / 1000.0 + caps = {p.name: float(p.capacity_kwh) for p in price} + cap_sum = sum(caps.values()) or 1.0 + + targets, need, share = {}, {}, {} + for p in price: + sh = excess * rooms[p.name] / total_room if total_room > 0 else 0.0 + sh_pct = sh / caps[p.name] * 100.0 + if p.mode == CHEAP_HOURS: + top = float(ceiling_pct) + else: + want = use_kwh * caps[p.name] / cap_sum / EFF + top = min(float(ceiling_pct), + float(floor_pct) + want / caps[p.name] * 100.0) + level = max(0.0, top - sh_pct) + targets[p.name] = round(level, 2) + need[p.name] = round(_room(p, level), 3) + share[p.name] = round(sh, 3) + if sun < sf_room: + verdict = DARK + elif any(v > 0.05 for v in need.values()): + verdict = PARTLY + else: + verdict = SUNNY + return Plan(verdict, round(sun, 3), round(fc_sum, 3), until.start, + targets, need, share) + + +def hold(old: dict | None, new: dict, capacity: dict) -> dict: + """Hysteresis: a battery keeps its old level unless the new one differs + by at least `HYST_KWH`, or by `HYST_FRAC` of the larger level's energy + (whichever is less). A battery new to the plan takes its level at once; + one that left the plan is dropped at once.""" + out = {} + for name, level in new.items(): + was = (old or {}).get(name) + cap = float(capacity.get(name) or 0.0) + if was is None or cap <= 0: + out[name] = level + continue + moved = abs(level - was) / 100.0 * cap + step = min(HYST_KWH, HYST_FRAC * max(was, level) / 100.0 * cap) + out[name] = level if moved >= step else was + return out diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 72520d4..923a66c 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -345,7 +345,10 @@ def mode_runs(c, day0, day1, now, shadow): else (soc - floor)) / 100.0 * cap) return kwh blocks = [] - if rp.charge_useful() and pm.mode in GRID_CHARGE_MODES: + # P4: with a day plan, the grid block is the planned shortfall. + need = plan_need(c, inv.name) + if rp.charge_useful() and (need > 0.0 if need is not None + else pm.mode in GRID_CHARGE_MODES): blocks.append(("grid", rp.cheap)) sell = rp.sell if pm.sell and pm.can_sell else None for g in rp.give: @@ -358,6 +361,8 @@ def mode_runs(c, day0, day1, now, shadow): continue hrs = (run.end - run.start).total_seconds() / 3600.0 kwh = room(kind, hrs) + if kind == "grid" and need is not None: + kwh = min(kwh, need) if kwh < MIN_KWH: continue price = run.mean_eur_kwh @@ -382,6 +387,56 @@ def mode_runs(c, day0, day1, now, shadow): return out, None +def plan_need(c, name): + """P4: kWh this battery buys from the grid by the day plan, or None when + there is no plan for it (then P3 option A applies).""" + targets = c.plan_targets() if hasattr(c, "plan_targets") else None + if not targets or name not in targets: + return None + inv = next((i for i in c.inverters if i.name == name), None) + if inv is None or inv.soc is None or not inv.capacity_kwh: + return None + return max(0.0, targets[name] - float(inv.soc)) / 100.0 * float( + inv.capacity_kwh) + + +def plan_state(c): + """P4: `"plan"` (a day plan is made), `"learning"` (no house profile + yet), `"no_forecast"` (set but missing or stale), or None (not set, or + battery modes off).""" + if not getattr(c, "modes_on", False) or \ + getattr(c, "fc_entity", None) is None: + return None + if getattr(c, "solar_fc", None) is None: + return "no_forecast" + hp = getattr(c, "house_profile", None) + if hp is not None and not hp.ready(): + return "learning" + return "plan" if getattr(c, "day_plan", None) is not None else None + + +def solar_block(c, now): + """P4: the solar forecast line for the Batteries screen and the Simple + settings view: `{state, fc_kwh, count_kwh, updated, line}`.""" + st = plan_state(c) + out = {"state": st, "fc_kwh": None, "count_kwh": None, "updated": None, + "line": ""} + if st is None and getattr(c, "solar_fc", None) is None: + return out + fc = getattr(c, "solar_fc", None) + if fc is not None: + trust = float(getattr(c, "solar_trust_pct", 70)) / 100.0 + out.update(fc_kwh=round(fc.today.kwh, 1), + count_kwh=round(fc.today.kwh * trust, 1), + updated=hhmm(fc.at)) + if st in ("no_forecast", "learning"): + out["line"] = _t("solar." + st) + elif fc is not None: + out["line"] = line_solar(fc.today.kwh, out["count_kwh"], + out["updated"]) + return out + + def maintenance_runs(c, day0, day1, now, shadow): """The monthly battery cycle: under way now, or starting later today. The cycle starts in the hour `maintenance_start_hour` names, read as the @@ -655,7 +710,9 @@ def battery_rows(c, shadow, running, held=False): phase=phase, shadow=shadow, running=running, held=held, refused=refusing(c, inv), peak=peak, giving=flow(inv.batt) == "giving", other_refuses=other, - sf_ahead=sf_ahead, role=role, plan=plan, has_at=bool(at)) + sf_ahead=sf_ahead, role=role, plan=plan, has_at=bool(at), + day=None if pm is None or pm.mode not in PRICE_MODES + else day_key(c, inv.name)) rows.append({ "name": inv.name, "level_pct": None if inv.soc is None else float(inv.soc), @@ -689,10 +746,25 @@ def battery_rows(c, shadow, running, held=False): return rows +def day_key(c, name): + """P4: the day plan's word for one Leftover solar or Cheap hours + battery: `sun_fills`, `tops_up`, `no_forecast`, or None.""" + st = plan_state(c) + if st == "no_forecast": + mode = c.pack_mode(next(i for i in c.inverters if i.name == name)) + return "no_forecast" if mode.mode == LEFTOVER_SOLAR else None + if st != "plan": + return None + need = plan_need(c, name) + if need is None: + return None + return "tops_up" if need >= MIN_KWH else "sun_fills" + + def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, held, refused, peak, sf_ahead, giving=False, other_refuses=None, role=None, plan=None, - has_at=False) -> str: + has_at=False, day=None) -> str: """The key of one battery's "why" line (`home_words.why`), most urgent first. Pure, so every branch is tested without a controller.""" if not reading: @@ -717,6 +789,8 @@ def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, if not modes_on: return "modes_off" # OPT-11 P3: the battery's role in the price runs this cycle. + if role == "hold" and day is not None: + return day # P4: what the day plan decided if role in ROLE_WHY: if role == "hold" and not has_at: return "saves_later" @@ -864,6 +938,7 @@ def _build(c, *, level, checks, now): modes_on=bool(getattr(c, "modes_on", False)), running=running, held=held, shadow=shadow) return { + "solar": solar_block(c, now), "state": {"kind": kind, "pill": pill(kind), "ran": ctl.get("text", "") if ctl else "", "sub": banner_sub(kind)}, @@ -1160,6 +1235,10 @@ def run_house_amount() -> str: return _t("run.house_amount") +def line_solar(fc_kwh, count_kwh, at) -> str: + return _t("solar.line", kwh=_kwh(fc_kwh), count=_kwh(count_kwh), at=at) + + def line_no_trade(key) -> str: return "" if key == "off" else _t("no_trade." + key) @@ -1302,6 +1381,8 @@ def _samples() -> list: off=off, peak=peak))) out += [("plan", why_words(k, name="Battery A")) for k in words["why"]] out += [("plan", today_words(k)) for k in words["today"]] + out += [("plan", line_solar(9.2, 6.4, "10:15")), + ("plan", _t("solar.no_forecast")), ("plan", _t("solar.learning"))] out += [("plan", line_no_trade(k)) for k in ("not_covered", "no_prices", "peak", "not_firm", "not_worth", "no_level")] diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ac2962b..5b20a46 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -41,9 +41,11 @@ from .arbiter import ( P_SAFETY, SET, Claim, Resolution, actuator_for, pre_resolve, resolve, ) from . import allocator +from . import dayplan from . import modetrade from . import packmode from . import priceruns +from . import solarfc from . import control as _ctl from .control import Tuning, compute, maintenance_charge_floor, peak_at_risk from .delivery import ( @@ -234,6 +236,11 @@ def load_options() -> dict: # valued at (`priceruns.plan(ref_eur_kwh=)`): the rest of that day. REF_CHEAP_KEEP = timedelta(hours=12) +# OPT-11 P4: the store key of the house profile (dayplan.HouseProfile), and +# how often the forecast sensors are read (they change hourly at most). +HOUSE_PROFILE_KEY = "house_profile" +FORECAST_READ_S = 60.0 + def why_raised(resolution, claims) -> bool: """F2 (OPT-11 P1 test): did the limit that bound the site target push it @@ -942,6 +949,25 @@ class Controller: self._mode_trade_was = False self._charge_blocked_q = None self._ref_cheap = None + # OPT-11 P4: the solar forecast and the day plan. Only with battery + # modes on AND `pv_forecast_entity` set; otherwise none of this runs + # and every mode acts as in P3 option A. + self.fc_entity = (opts.get("pv_forecast_entity") or None) \ + if self.modes_on else None + self.fc_tomorrow_entity = opts.get("pv_forecast_tomorrow_entity") \ + or None + self.solar_trust_pct = opts.get("solar_trust_pct", + dayplan.DEFAULT_TRUST_PCT) + self.solar_fc = None + self.solar_fc_why = (solarfc.NOT_SET if self.fc_entity is None + else solarfc.MISSING) + self._fc_read_mono = None + self.day_plan = None + self._plan_targets = None + self.house_profile = None + if self.fc_entity is not None: + self.house_profile = dayplan.HouseProfile( + (getattr(store, "data", None) or {}).get(HOUSE_PROFILE_KEY)) # OPT-11 P2: (topic, reason) of MQTT commands refused and logged once. self._mqtt_refused = set() self._mqtt_refused_more = 0 @@ -2073,10 +2099,14 @@ class Controller: plan = self.fresh_tariff_plan(now) if plan is None or not plan.has_prices: self.mode_runs, self._runs_key = None, None + self.day_plan = None return None slot = int(now.timestamp() // 900) key = (id(plan), slot, tuple((p.name, p.use, p.mode, p.sell) for p in packs)) + if self.fc_entity is not None: + # P4: a forecast arriving or going rebuilds the plan at once. + key += (self.solar_fc is None,) if key != self._runs_key: done_c = self._run_done.get("charge", (None, set()))[1] done_s = self._run_done.get("sell", (None, set()))[1] @@ -2094,6 +2124,9 @@ class Controller: charge_kwh=e[0], charge_kw=e[1], sell_kwh=e[2], sell_kw=e[3], ref_eur_kwh=None if ref is None else ref.mean_eur_kwh) + if self.fc_entity is not None: + new = self._day_plan(now, packs, floor_pct, ceiling_pct, + new, plan, required, ref, done_c, e) self.mode_runs = priceruns.keep_started(self.mode_runs, new, now) self._runs_key = key runs = self.mode_runs @@ -2108,6 +2141,42 @@ class Controller: self._ref_cheap = runs.cheap return runs + def _day_plan(self, now, packs, floor_pct, ceiling_pct, runs, plan, + required, ref, done_c, e): + """OPT-11 P4: the day plan (`dayplan.plan()`) on the runs just made, + its levels held by the hysteresis (`dayplan.hold()`), then the runs + made again with each battery's shortfall as the charge, so the cheap + run is only as long as the shortfall needs. With no plan (no or stale + forecast, no house profile yet) the levels are dropped: P3 option A. + Returns the runs to keep.""" + dp = dayplan.plan( + self.solar_fc, + None if self.house_profile is None + else self.house_profile.estimator(), + priceruns.keep_started(self.mode_runs, runs, now), now, packs, + trust_pct=self.solar_trust_pct, floor_pct=floor_pct, + ceiling_pct=ceiling_pct) + self.day_plan = dp + if dp is None: + self._plan_targets = None + return runs + self._plan_targets = dayplan.hold( + self._plan_targets, dp.targets, + {p.name: p.capacity_kwh for p in packs}) + e2 = modetrade.energy(packs, floor_pct, ceiling_pct, done_c, (), + targets=self._plan_targets) + return priceruns.plan( + plan.read.points, now, required_eur_kwh=required, + charge_kwh=e2[0], charge_kw=e2[1], sell_kwh=e[2], sell_kw=e[3], + ref_eur_kwh=None if ref is None else ref.mean_eur_kwh) + + def plan_targets(self): + """P4: each battery's planned level, or None (no day plan). Dropped + at once when the forecast goes (stale or missing).""" + if self.solar_fc is None: + return None + return self._plan_targets + def _mode_roles(self, now, maint_results): """OPT-11 P3: each battery's role and range this tick. Grid charging and selling need a fresh plan that `TariffPlan.arbitrage()` allows @@ -2146,9 +2215,22 @@ class Controller: price_now = None house = (None if self.grid is None or self.site_batt_w is None else float(self.grid) + float(self.site_batt_w)) - done_c = self._run_mark("charge", runs and runs.cheap, packs, - lambda p: p.soc is not None - and p.soc >= ceiling_pct) + if self.house_profile is not None and \ + self.house_profile.add(now, house): + self.store.set(HOUSE_PROFILE_KEY, self.house_profile.dump()) + targets = self.plan_targets() + if targets is None: + done_c = self._run_mark("charge", runs and runs.cheap, packs, + lambda p: p.soc is not None + and p.soc >= ceiling_pct) + else: + # P4: out of the run at its planned level. A level the + # hysteresis moved opens the run to it again (a new mark key). + def full(p): + to = modetrade.charge_to(p, ceiling_pct, targets) + return p.soc is not None and (to is None or p.soc >= to) + done_c = self._run_mark("charge", runs and runs.cheap, packs, + full, tuple(sorted(targets.items()))) done_s = self._run_mark("sell", runs and runs.sell, packs, lambda p: p.soc is not None and p.soc <= floor_pct) @@ -2161,17 +2243,20 @@ class Controller: headroom_w=self.arb_headroom_w, floor_pct=floor_pct, ceiling_pct=ceiling_pct, house_w=house, charging_now=was, blocked=self._charge_blocked_q == quarter, - done_charge=done_c, done_sell=done_s) + done_charge=done_c, done_sell=done_s, targets=targets) # A charge the guard or the headroom stopped stays off this period. if was and self.mode_tick.action != modetrade.CHARGE and \ self.mode_tick.why in ("peak", "headroom"): self._charge_blocked_q = quarter return self.mode_tick - def _run_mark(self, kind, run, packs, out) -> set: + def _run_mark(self, kind, run, packs, out, extra=None) -> set: """The batteries that left run `run` (full, or at the floor); they - stay out until it ends, so a level edge does not re-arm them.""" + stay out until it ends, so a level edge does not re-arm them. + `extra` (P4: the planned levels) is part of the run's key.""" key = None if not run else (run.start, run.end) + if key is not None and extra is not None: + key += (extra,) was_key, done = self._run_done.get(kind, (None, set())) if key != was_key: done = set() @@ -2487,6 +2572,22 @@ class Controller: self.pv_w, self.pv_why, self.pv_parts = pv_read.total( list(zip(roster, states)), pv_read.inverted(self.o)) + async def _read_forecast(self) -> None: + """OPT-11 P4: the solar forecast sensors (`solarfc.read()`). A + failed or stale read is no forecast, never a zero.""" + today = await self.hass.state(self.fc_entity) + tomorrow = (await self.hass.state(self.fc_tomorrow_entity) + if self.fc_tomorrow_entity else None) + now = datetime.now(timezone.utc) + fc, why = solarfc.read(today, tomorrow, now) + if (fc is None) != (self.solar_fc is None) or why != self.solar_fc_why: + self.log_event( + "solar forecast: " + ("read" if fc is not None else + f"none ({why})"), + hint=messages.hint("forecast_read" if fc is not None + else "forecast_none")) + self.solar_fc, self.solar_fc_why = fc, why + async def read_inputs(self, now_mono: float | None = None) -> None: """Every input this cycle needs, and SAFETY-37's freshness verdict. @@ -2538,6 +2639,14 @@ class Controller: _reads = [self._read_unit(inv, now_mono) for inv in self.inverters] if self.pv_roster: _reads.append(self._read_pv()) + # OPT-11 P4: the solar forecast, in the same gather (a slow sensor + # must not delay control), at most once per FORECAST_READ_S. + if self.fc_entity is not None and ( + self._fc_read_mono is None + or now_mono - self._fc_read_mono >= FORECAST_READ_S + or now_mono < self._fc_read_mono): + self._fc_read_mono = now_mono + _reads.append(self._read_forecast()) await asyncio.gather(*_reads) if o.get("peak_forecast_entity"): raw = await self.hass.number(o["peak_forecast_entity"]) diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 4445a60..b3cfef3 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -906,6 +906,8 @@ HINTS = { "trade_charge": "Trading: charging while the price is low", "trade_give": "Trading: giving power while the price is high", "trade_off": "Trading: waiting for a better price", + "forecast_read": "Solar forecast read, the day plan uses it", + "forecast_none": "No solar forecast, so Leftover solar takes solar only", "split": "The power split between inverters changed", "clash": "Two limits clash, inverters set to 0 W", "no_setpoint": "An inverter has no “Setpoint entity”, inverters stay at 0 W", @@ -1172,6 +1174,9 @@ LABELS = { "batt_entity": "Battery power entity", "pv_entity": "Solar production entity", "pv_entities": "Solar production entities, per inverter", + "pv_forecast_entity": "Solar forecast, today", + "pv_forecast_tomorrow_entity": "Solar forecast, tomorrow", + "solar_trust_pct": "Trust in the forecast", "p1_phase_import_entities": "Import entities per phase", "p1_phase_export_entities": "Export entities per phase", } diff --git a/goodwe_controller/app/modetrade.py b/goodwe_controller/app/modetrade.py index 81fa61d..5dcbc06 100644 --- a/goodwe_controller/app/modetrade.py +++ b/goodwe_controller/app/modetrade.py @@ -23,7 +23,11 @@ Roles (the page's Why line names them): Rules that keep this safe (tests: test_modes_p3.py): * every range holds 0 W (a mode may forbid a direction, never force one); - * a Solar first battery never charges from the grid (no forecast yet, P4); + * a Solar first battery never charges from the grid; + * P4: with a day plan (`targets`), a Leftover solar or Cheap hours battery + charges from the grid only up to its planned level, never above the + ceiling; with none, Cheap hours fills to the ceiling and Leftover solar + takes solar only (P3 option A, `charge_to()`); * grid charging needs a measured peak guard that is clear and a measured headroom (SAFETY-45); the trade is sized to that headroom, whose aim is `peak_cap_w - peak_margin_w` (SAFETY-79). It starts only at START_W or @@ -45,7 +49,7 @@ Rules that keep this safe (tests: test_modes_p3.py): from dataclasses import dataclass from .packmode import (CHEAP_HOURS, GRID_CHARGE_MODES, LEFTOVER_SOLAR, - SOLAR_FIRST) + PLAN_CHARGE_MODES, SOLAR_FIRST) OFF, HOUSE, HOLD, GIVE, SELL, CHARGE, REST = ( "off", "house", "hold", "give", "sell", "charge", "rest") @@ -88,13 +92,34 @@ def _room_kwh(p: Pack, pct: float) -> float: return max(0.0, abs(pct - p.soc)) / 100.0 * float(p.capacity_kwh) -def chargers(packs, ceiling_pct, done=()) -> list: - """Batteries that may charge from the grid in a cheap run: the modes in - `packmode.GRID_CHARGE_MODES` (Cheap hours only until P4's forecast).""" - return [p for p in packs - if p.use and p.idle and p.live and p.mode in GRID_CHARGE_MODES - and p.soc is not None and p.soc < ceiling_pct - and p.refused >= 0 and p.name not in done] +def charge_to(p: Pack, ceiling_pct, targets=None): + """The level this battery may charge to from the grid, or None. + + `targets` is the day plan (`dayplan.plan()`: name -> level), or None + when there is none (no forecast, stale, or not configured). With no plan + this is P3 option A exactly: Cheap hours to the ceiling, the others never. + With a plan, a Leftover solar or Cheap hours battery charges only to its + planned level (the sun fills the rest), and a battery the plan leaves out + falls back to the no-plan answer. Solar first never charges.""" + if targets is None or p.name not in targets: + return float(ceiling_pct) if p.mode in GRID_CHARGE_MODES else None + if p.mode not in PLAN_CHARGE_MODES: + return None + t = targets[p.name] + return None if t is None else min(float(ceiling_pct), float(t)) + + +def chargers(packs, ceiling_pct, done=(), targets=None) -> list: + """Batteries that may charge from the grid in a cheap run: below the + level `charge_to()` allows them (P4: the day plan's).""" + out = [] + for p in packs: + to = charge_to(p, ceiling_pct, targets) + if (to is not None and p.use and p.idle and p.live + and p.soc is not None and p.soc < to + and p.refused >= 0 and p.name not in done): + out.append(p) + return out def sellers(packs, floor_pct, done=()) -> list: @@ -106,11 +131,15 @@ def sellers(packs, floor_pct, done=()) -> list: and p.refused <= 0 and p.name not in done] -def energy(packs, floor_pct, ceiling_pct, done_charge=(), done_sell=()): - """`(charge_kwh, charge_kw, sell_kwh, sell_kw)` for `priceruns.plan()`.""" - ch = chargers(packs, ceiling_pct, done_charge) +def energy(packs, floor_pct, ceiling_pct, done_charge=(), done_sell=(), + targets=None): + """`(charge_kwh, charge_kw, sell_kwh, sell_kw)` for `priceruns.plan()`. + With a day plan the charge is each battery's shortfall, so the cheap run + is only as long as the shortfall needs.""" + ch = chargers(packs, ceiling_pct, done_charge, targets) se = sellers(packs, floor_pct, done_sell) - return (sum(_room_kwh(p, ceiling_pct) for p in ch), + return (sum(_room_kwh(p, charge_to(p, ceiling_pct, targets)) + for p in ch), sum(abs(p.rating_w) for p in ch) / 1000.0, sum(_room_kwh(p, floor_pct) for p in se), sum(abs(p.rating_w) for p in se) / 1000.0) @@ -118,7 +147,8 @@ def energy(packs, floor_pct, ceiling_pct, done_charge=(), done_sell=()): def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, headroom_w, floor_pct, ceiling_pct, house_w, charging_now=False, - blocked=False, done_charge=(), done_sell=()) -> Tick: + blocked=False, done_charge=(), done_sell=(), + targets=None) -> Tick: """This tick's ranges, roles and site ask. `runs` is the kept `priceruns.RunPlan` or None (no fresh prices). @@ -129,7 +159,7 @@ def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, `house_w` is the measured house (grid + batteries), or None. `charging_now` says last tick charged (then any headroom above 0 keeps it going); `blocked` that the guard or the headroom stopped a charge in - this 15-minute period. + this 15-minute period. `targets` is the day plan (`charge_to()`). """ plan_on = runs is not None and runs.on in_cheap = plan_on and runs.cheap.holds(now) and runs.charge_useful() @@ -137,7 +167,8 @@ def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, in_sell = plan_on and runs.sell is not None and runs.sell.holds(now) why = None - ch = chargers(packs, ceiling_pct, done_charge) if in_cheap else [] + ch = chargers(packs, ceiling_pct, done_charge, targets) if in_cheap \ + else [] charging = False if ch: need = 0.0 if charging_now else START_W diff --git a/goodwe_controller/app/packmode.py b/goodwe_controller/app/packmode.py index 5fd71fe..39f79db 100644 --- a/goodwe_controller/app/packmode.py +++ b/goodwe_controller/app/packmode.py @@ -46,10 +46,13 @@ SELL_KEY = "pack_sell" # OPT-11 P3: sell in the sell run # refused; the sell code in modetrade/priceruns stays, unreachable. SELLING_ENABLED = False -# The modes that may charge from the grid in a cheap run. Leftover solar joins -# when the solar forecast exists (P4); until then it takes solar only (owner -# decision 2026-09-29, option A). +# The modes that may charge from the grid in a cheap run with no day plan. +# Leftover solar takes solar only then (owner decision 2026-09-29, option A). GRID_CHARGE_MODES = (CHEAP_HOURS,) +# OPT-11 P4: with a fresh solar forecast, the day plan (dayplan.py) may also +# let Leftover solar charge from the grid, by the shortfall only. Solar first +# never charges from the grid. +PLAN_CHARGE_MODES = (LEFTOVER_SOLAR, CHEAP_HOURS) def enabled(opts) -> bool: diff --git a/goodwe_controller/app/solarfc.py b/goodwe_controller/app/solarfc.py new file mode 100644 index 0000000..a2b262d --- /dev/null +++ b/goodwe_controller/app/solarfc.py @@ -0,0 +1,251 @@ +"""OPT-11 P4: the solar forecast, read from a Home Assistant sensor. + +Pure: HA state dicts and the time in, a `Forecast` (or None and why) out. +main.py reads the entities; dayplan.py uses the answer. FCST-01 replaces +this later with the add-on's own forecast (owner answer, 2026-09-27). + +Two options name the sensors: `pv_forecast_entity`, the solar energy still +to come TODAY, and `pv_forecast_tomorrow_entity`, TOMORROW's (optional; it +is only needed for a cheap run before midnight). Supported, by the entities +they create (DOCS.md lists them): + +* Forecast.Solar (HA core): `sensor.energy_production_today_remaining` and + `sensor.energy_production_tomorrow`. The state only; no hourly split. +* Solcast PV Forecast (HACS `solcast_solar`): + `sensor.solcast_pv_forecast_forecast_remaining_today` and + `..._forecast_tomorrow`, with `detailedForecast` (or `detailedHourly`): + `[{period_start, pv_estimate}]`, kW per period. +* Open-Meteo Solar Forecast (HACS `open_meteo_solar_forecast`): + `sensor.energy_production_today_remaining` / `..._tomorrow`, with + `wh_period`: `{period start: Wh}`. + +Any other sensor whose state is energy in Wh, kWh or MWh works too, as a +state only. The unit is read, never guessed (the rule `pv.watts()` has). +Without an hourly split, the day's energy is spread over a fixed bell from +06:00 to 20:00 local time (`BELL_FROM_H`, `BELL_TO_H`). + +A reading older than `FRESH_S` is stale, and a stale or missing forecast is +no forecast: the day plan is off and every mode acts as in P3 option A. +""" + +import math +from dataclasses import dataclass +from datetime import datetime, timedelta, timezone + +from .hass import BAD_STATES +from .tariff import BILLING_TZ + +KWH_PER = {"Wh": 0.001, "kWh": 1.0, "MWh": 1000.0} + +# Stale after 3 h. The integrations above refresh at least hourly, so a +# 2 h limit would flag a site whose hourly poll was missed once. +FRESH_S = 3 * 3600.0 + +# The bell a state-only forecast is spread over, in local hours. +BELL_FROM_H, BELL_TO_H = 6.0, 20.0 + +# Why there is no forecast (the page words are in ui_text `home_words`). +NOT_SET, MISSING, UNIT, STALE, BAD = ( + "not_set", "missing", "unit", "stale", "bad") + + +@dataclass(frozen=True) +class Day: + """One day's forecast: `kwh` still to come (today) or in all (tomorrow), + and the hourly split if the sensor has one: `((start, end, kwh), ...)`.""" + day0: datetime # local midnight, as UTC + kwh: float + periods: tuple = () + + +@dataclass(frozen=True) +class Forecast: + today: Day + tomorrow: Day | None + at: datetime # when the sensor last reported + + def between(self, t0: datetime, t1: datetime) -> float | None: + """kWh the sun should give between `t0` (now or later) and `t1`. + None when the span reaches the sunny hours of a day with no + forecast (tomorrow, when its sensor is not set).""" + if t1 <= t0: + return 0.0 + last = self.tomorrow or self.today + if t1 > last.day0 + timedelta(days=1, hours=BELL_FROM_H): + return None + total = 0.0 + for day in (self.today, self.tomorrow): + if day is None: + continue + a = max(t0, day.day0) + b = min(t1, day.day0 + timedelta(days=1)) + if b > a: + total += _day_between(day, a, b, t0) + return total + + +def _local_hour(t: datetime) -> float: + lt = t.astimezone(BILLING_TZ) + return lt.hour + lt.minute / 60.0 + lt.second / 3600.0 + + +def _bell(h: float) -> float: + """Cumulative share of a day's sun by local hour `h` (0..1).""" + if h <= BELL_FROM_H: + return 0.0 + if h >= BELL_TO_H: + return 1.0 + x = (h - BELL_FROM_H) / (BELL_TO_H - BELL_FROM_H) + return (1.0 - math.cos(math.pi * x)) / 2.0 + + +def _hours_since(day0, t): + return (t - day0).total_seconds() / 3600.0 + + +def _day_between(day: Day, a: datetime, b: datetime, now: datetime) -> float: + if day.periods: + out = 0.0 + for s, e, kwh in day.periods: + lo, hi = max(a, s), min(b, e) + if hi > lo: + out += kwh * (hi - lo).total_seconds() / (e - s).total_seconds() + return out + # State only: `kwh` is what is left from `max(now, day0)` to the day's + # end, spread over the bell. + h_from = _hours_since(day.day0, max(now, day.day0)) + left = 1.0 - _bell(h_from) + if left <= 1e-9: + return 0.0 + share = (_bell(_hours_since(day.day0, b)) + - _bell(_hours_since(day.day0, a))) / left + return day.kwh * max(0.0, share) + + +def _parse_time(v): + try: + t = datetime.fromisoformat(str(v).replace("Z", "+00:00")) + except (TypeError, ValueError): + return None + return t if t.tzinfo else t.replace(tzinfo=timezone.utc) + + +def _periods(attrs: dict, day0: datetime) -> tuple: + """The hourly split, if the sensor has one, for the day at `day0`.""" + d1 = day0 + timedelta(days=1) + out = [] + for key in ("detailedForecast", "detailedHourly"): + rows = attrs.get(key) + if isinstance(rows, list) and rows: + starts = [] + for r in rows: + if not isinstance(r, dict): + continue + t = _parse_time(r.get("period_start")) + try: + kw = float(r.get("pv_estimate")) + except (TypeError, ValueError): + continue + if t is not None and math.isfinite(kw) and kw >= 0: + starts.append((t, kw)) + starts.sort() + for i, (t, kw) in enumerate(starts): + step = (starts[i + 1][0] - t if i + 1 < len(starts) + else timedelta(minutes=30 if key == + "detailedForecast" else 60)) + if step <= timedelta(0) or step > timedelta(hours=1): + step = timedelta(minutes=30 if key == "detailedForecast" + else 60) + if day0 <= t < d1: + out.append((t, t + step, + kw * step.total_seconds() / 3600.0)) + if out: + return tuple(out) + wh = attrs.get("wh_period") + if isinstance(wh, dict) and wh: + rows = [] + for k, v in wh.items(): + t = _parse_time(k) + try: + e = float(v) + except (TypeError, ValueError): + continue + if t is not None and math.isfinite(e) and e >= 0: + rows.append((t, e / 1000.0)) + rows.sort() + for i, (t, kwh) in enumerate(rows): + nxt = rows[i + 1][0] if i + 1 < len(rows) else t + timedelta( + hours=1) + if nxt - t > timedelta(hours=1) or nxt <= t: + nxt = t + timedelta(hours=1) + if day0 <= t < d1: + out.append((t, nxt, kwh)) + return tuple(out) + + +def _day(state, day0, now, *, today): + """`(Day, None)` or `(None, why)` from one sensor's state dict.""" + if state is None: + return None, MISSING + raw = str(state.get("state", "")).strip() + if raw.lower() in BAD_STATES: + return None, MISSING + try: + v = float(raw) + except ValueError: + return None, BAD + attrs = state.get("attributes") or {} + unit = str(attrs.get("unit_of_measurement") or "").strip() + if unit not in KWH_PER: + return None, UNIT + kwh = v * KWH_PER[unit] + if not math.isfinite(kwh) or kwh < 0: + return None, BAD + periods = _periods(attrs, day0) + if periods and today: + # The split is the whole day; keep what is still to come, scaled so + # it adds up to the state (the state is what the integration says + # is left). + left = sum(k * max(0.0, min(1.0, (e - max(s, now)).total_seconds() + / (e - s).total_seconds())) + for s, e, k in periods) + if left > 1e-6: + f = kwh / left + periods = tuple((s, e, k * f) for s, e, k in periods) + return Day(day0, kwh, periods), None + + +def _reported(state): + ts = [_parse_time(state.get(k)) for k in + ("last_reported", "last_updated", "last_changed")] + ts = [t for t in ts if t is not None] + return max(ts) if ts else None + + +def read(today_state, tomorrow_state, now: datetime, *, + configured=True): + """`(Forecast, None)` or `(None, why)`. `tomorrow_state` may be None + (the option is not set, or the sensor is missing): the forecast then + covers today only.""" + if not configured: + return None, NOT_SET + here = now.astimezone(BILLING_TZ) + d0 = datetime(here.year, here.month, here.day, tzinfo=BILLING_TZ) + nd = d0.date() + timedelta(days=1) + d1 = datetime(nd.year, nd.month, nd.day, tzinfo=BILLING_TZ) + day0, day1 = d0.astimezone(timezone.utc), d1.astimezone(timezone.utc) + today, why = _day(today_state, day0, now, today=True) + if today is None: + return None, why + at = _reported(today_state) + if at is None or (now - at).total_seconds() > FRESH_S \ + or (at - now).total_seconds() > 300: + return None, STALE + tomorrow = None + if tomorrow_state is not None: + t, _w = _day(tomorrow_state, day1, now, today=False) + t_at = _reported(tomorrow_state) + if t is not None and t_at is not None \ + and (now - t_at).total_seconds() <= FRESH_S: + tomorrow = t + return Forecast(today, tomorrow, at), None diff --git a/goodwe_controller/app/static/app.js b/goodwe_controller/app/static/app.js index 8c3fca9..e5354b8 100644 --- a/goodwe_controller/app/static/app.js +++ b/goodwe_controller/app/static/app.js @@ -403,6 +403,9 @@ else $("#batt-banner").replaceChildren(); keepFocus(() => { $("#bcards").replaceChildren(...S.batteries.map(batteryCard)); + // OPT-11 P4: the solar forecast line under the cards. + const sl = $("#batt-solar"), line = modes && S.solar ? S.solar.line : ""; + if (sl) { sl.textContent = line || ""; sl.hidden = !line; } if (simpleHost && simpleHost.isConnected) { simpleHost.replaceChildren(...(modes ? S.batteries.map(simpleRow) : [h("p", { class: "small muted", style: "margin:4px 0" }, t("batteries.modes_off.name") + ". " + t("batteries.description"))])); diff --git a/goodwe_controller/app/static/index.html b/goodwe_controller/app/static/index.html index a915a09..24a34eb 100644 --- a/goodwe_controller/app/static/index.html +++ b/goodwe_controller/app/static/index.html @@ -101,6 +101,7 @@ <a class="btn" href="#settings" data-t="batteries.settings"></a> </div> <div id="bcards"></div> + <p class="small muted" id="batt-solar" hidden></p> <details class="grp" id="batt-how" hidden> <summary><span class="grow"><strong data-t="batteries.how.name"></strong><span class="small muted gdesc" data-t="batteries.how.description"></span></span><span class="chev" aria-hidden="true">›</span></summary> <div class="body small"> diff --git a/goodwe_controller/app/static/settings.js b/goodwe_controller/app/static/settings.js index b80dc7c..8e5cc2e 100644 --- a/goodwe_controller/app/static/settings.js +++ b/goodwe_controller/app/static/settings.js @@ -446,7 +446,17 @@ e.textContent = ok ? e.dataset.kwNote.replace("{kw}", window.UX13.kw(mp.peak_w) + " kW") : ""; }); } + // OPT-11 P4: the solar forecast card shows the add-on's forecast line. + function fillSolar() { + const st = window.UX13.status(); + const line = st && st.solar ? st.solar.line : ""; + document.querySelectorAll("#simple [data-solar-note]").forEach((e) => { + e.textContent = line || ""; + e.hidden = !line; + }); + } document.addEventListener("ux13:status", fillNotes); + document.addEventListener("ux13:status", fillSolar); function simpleField(f) { const row = fieldRow(f, null, "simple"); row.querySelector(".head").append(chip(f.applies)); @@ -458,6 +468,7 @@ const help = row.querySelector(".help"); if (help) help.textContent = n.description; } + if (f.note === "forecast") row.append(h("div", { class: "small muted", "data-solar-note": "", hidden: true })); return h("div", { class: "card" }, row); } function renderSimple() { diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 57d70c9..dfe9347 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -119,7 +119,7 @@ "description": "Every setting, grouped by task.", "view": {"name": "Settings view", "simple": "Simple", "installer": "Installer"}, "simple": {"description": "The choices a home owner makes.", - "note": {"month_peak": {"description": "This month's peak so far: {kw}."}, "shadow": {"description": "Use Always on while you test a new installation."}}, + "note": {"month_peak": {"description": "This month's peak so far: {kw}."}, "shadow": {"description": "Use Always on while you test a new installation."}, "forecast": {"description": "With a forecast, a battery buys only what the sun will not give."}}, "batteries": {"name": "Batteries"}, "more": {"description": "Looking for the meter, inverters or prices?"}, "installer": "Open the installer view"}, @@ -334,8 +334,12 @@ "saves": "Saves its power for {at}.", "saves_later": "Saves its power for higher prices.", "no_prices": "No prices, so it follows the house.", - "no_spread": "Prices differ too little, so it follows the house." + "no_spread": "Prices differ too little, so it follows the house.", + "sun_fills": "Enough sun is forecast, so it does not charge from the grid.", + "tops_up": "Too little sun is forecast, so it charges some from the grid.", + "no_forecast": "No solar forecast, so it charges from solar only." }, + "solar": {"line": "Solar forecast today: {kwh}, we count on {count}. Updated {at}.", "no_forecast": "No solar forecast now, so Leftover solar charges from solar only.", "learning": "The add-on is learning your house's use. The plan starts tomorrow."}, "today": { "not_planned": "Not planned yet.", "no_runs": "No cheap or expensive hours left today.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 5690fc7..532a5b4 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -114,7 +114,7 @@ "description": "Elke instelling, per taak.", "view": {"name": "Weergave van de instellingen", "simple": "Eenvoudig", "installer": "Installateur"}, "simple": {"description": "De keuzes die een eigenaar maakt.", - "note": {"month_peak": {"description": "De piek van deze maand tot nu: {kw}."}, "shadow": {"description": "Kies Altijd aan terwijl u een nieuwe installatie test."}}, + "note": {"month_peak": {"description": "De piek van deze maand tot nu: {kw}."}, "shadow": {"description": "Kies Altijd aan terwijl u een nieuwe installatie test."}, "forecast": {"description": "Met een prognose koopt een batterij alleen wat de zon niet geeft."}}, "batteries": {"name": "Batterijen"}, "more": {"description": "Zoekt u de meter, de omvormers of de prijzen?"}, "installer": "De installateursweergave openen"}, @@ -276,8 +276,12 @@ "saves": "Spaart haar stroom voor {at}.", "saves_later": "Spaart haar stroom voor hogere prijzen.", "no_prices": "Geen prijzen, dus ze volgt het huis.", - "no_spread": "De prijzen verschillen te weinig, dus ze volgt het huis." + "no_spread": "De prijzen verschillen te weinig, dus ze volgt het huis.", + "sun_fills": "Er is genoeg zon voorspeld, dus ze laadt niet van het net.", + "tops_up": "Te weinig zon voorspeld, dus ze laadt wat van het net.", + "no_forecast": "Geen zonneprognose, dus ze laadt alleen met zonne-energie." }, + "solar": {"line": "Zonneprognose vandaag: {kwh}, we rekenen op {count}. Bijgewerkt om {at}.", "no_forecast": "Nu geen zonneprognose, dus Overschot zonne-energie laadt alleen met zon.", "learning": "De add-on leert eerst het verbruik van uw huis. Het plan start morgen."}, "today": { "not_planned": "Nog niet gepland.", "no_runs": "Vandaag geen goedkope of dure uren meer.", diff --git a/goodwe_controller/app/uilayout.py b/goodwe_controller/app/uilayout.py index 1b8a151..04a8e80 100644 --- a/goodwe_controller/app/uilayout.py +++ b/goodwe_controller/app/uilayout.py @@ -129,7 +129,14 @@ GROUPS = ( wizard=3),)), # OPT-11: the switch that turns battery modes on. Each battery's mode # and on/off switch are runtime state on the Batteries screen. - Part("modes", (Field("battery_modes_enabled", TOGGLE),)), + Part("modes", ( + Field("battery_modes_enabled", TOGGLE), + # OPT-11 P4: the solar forecast; today's also on Settings, Simple. + Field("pv_forecast_entity", ENTITY, kind="energy", simple=True, + note="forecast"), + Field("pv_forecast_tomorrow_entity", ENTITY, kind="energy"), + Field("solar_trust_pct", SLIDER, "%", step=5), + )), )), Group("tariff", ( Part("", ( diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 0b8b269..4741263 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -246,6 +246,10 @@ NOT READY banner already names the problem, (b) does not apply. 12. `peak_margin_w` outside 0-500 W, not whole, or not below `peak_cap_w`. SAFETY-79; the Supervisor checks the range too, but not for sim/inject.py. + 13. OPT-11 P4: `solar_trust_pct` outside 30-100 or not whole, or a solar + forecast entity that is not a `sensor.` id. A trust of 0 or 500 % would + make the day plan buy everything or nothing, which no one means. + WHAT IS DELIBERATELY *NOT* REFUSED, because it is untidy rather than unsafe: - `integrator_max_w` above `max_w`. DOCS.md is right that the only thing the @@ -326,7 +330,7 @@ WHAT IS DELIBERATELY *NOT* REFUSED, because it is untidy rather than unsafe: import logging from typing import NamedTuple -from . import messages, pv +from . import dayplan, messages, pv, solarfc from .arbitrage import enabled as arbitrage_on from .control import SLEW_RAIL_FRAC, LOOP_TICK_S, PLANT_SETTLE_S from .custom_formula import ( @@ -1199,6 +1203,7 @@ def validate_startup_config(opts: dict, dev_min=None, dev_max=None, # --- 12. SAFETY-79: the margin the peak guard keeps under the limit ----- problems += _margin_problems(opts) + problems += _forecast_problems(opts) # --- warnings: real, but not worth refusing over ------------------------- integ = opts.get("integrator_max_w") @@ -1751,6 +1756,8 @@ def _entities_read(opts: dict) -> list[tuple[str, str, str]]: add("pv_entities" if solar else "pv_entity", list(pv.entities(opts))) for key in ("peak_forecast_entity", "price_now_entity", "price_avg_entity"): add(key, opts.get(key)) + for key in FORECAST_KEYS: + add(key, opts.get(key)) return out @@ -1790,6 +1797,19 @@ def _entity_notes(notes, opts: dict, entities: dict, bad=()) -> None: _advise(notes, "warn", (key,), f"{entity} reads in {unit}, but {S(key, where)} is " "taken as watts, so pick a sensor in W.") + if key in FORECAST_KEYS and unit not in solarfc.KWH_PER: + _advise(notes, "warn", (key,), + f"{entity} does not read in kWh, so pick a solar " + "forecast sensor in kWh.") + if any(opts.get(k) for k in FORECAST_KEYS) and \ + opts.get("battery_modes_enabled") is not True: + _advise(notes, "info", ("pv_forecast_entity",), + "The solar forecast is used only with battery modes on.") + if opts.get("pv_forecast_tomorrow_entity") and \ + not opts.get("pv_forecast_entity"): + _advise(notes, "warn", ("pv_forecast_tomorrow_entity",), + "Tomorrow's forecast is used only with today's, so set " + f"{S('pv_forecast_entity')} too.") # --------------------------------------------------------------------------- # @@ -2045,6 +2065,31 @@ def _margin_problems(opts: dict) -> list[str]: return [] +TRUST_RANGE_PCT = (30, 100) +FORECAST_KEYS = ("pv_forecast_entity", "pv_forecast_tomorrow_entity") + + +def _forecast_problems(opts: dict) -> list[str]: + """Rule 13 (OPT-11 P4): the trust is a whole percentage in range, and + each forecast entity set is a sensor.""" + out = [] + raw = opts.get("solar_trust_pct") + trust = _number(opts, "solar_trust_pct", dayplan.DEFAULT_TRUST_PCT) + lo, hi = TRUST_RANGE_PCT + if trust is None or trust != int(trust) or not lo <= trust <= hi: + out.append(f"{S('solar_trust_pct')} must be a whole number from {lo} " + f"to {hi} %. It is {messages.shown(raw)}.") + for key in FORECAST_KEYS: + e = opts.get(key) + if e is None or e == "": + continue + if not isinstance(e, str) or not e.strip().startswith("sensor."): + out.append(f"{S(key)} must be a sensor, like " + f"sensor.energy_production_today_remaining. It is " + f"{messages.shown(e)}.") + return out + + def _number(opts: dict, key, default): raw = opts.get(key, default) if raw is None or raw == "": diff --git a/goodwe_controller/config.yaml b/goodwe_controller/config.yaml index 4c332f6..4fcff8e 100644 --- a/goodwe_controller/config.yaml +++ b/goodwe_controller/config.yaml @@ -151,6 +151,13 @@ options: # switch and a mode on the Batteries screen, kept in the add-on's store. # DECISIONS/OPT-11-battery-modes.md. battery_modes_enabled: false + # OPT-11 P4: a Home Assistant solar forecast (kWh left today; tomorrow's is + # optional) and how much of it to count on. Read only with battery modes + # on; empty means no day plan (P3 option A). app/solarfc.py lists the + # integrations whose sensors fit. + pv_forecast_entity: "" + pv_forecast_tomorrow_entity: "" + solar_trust_pct: 70 # TEL-11 - THE SITE'S PV PRODUCTION, IN WATTS, AND IT IS READ BY NOTHING THAT # DECIDES ANYTHING. Optional, empty on every install that does not set it, and @@ -951,6 +958,9 @@ schema: estop_fitted: bool battery_modes_enabled: bool + pv_forecast_entity: str? + pv_forecast_tomorrow_entity: str? + solar_trust_pct: int(30,100) # TEL-11. Optional, and OPTIONAL WITHOUT A COMPANION RULE - unlike # `price_now_entity`/`price_avg_entity`, which are legal only while # `price_provider` is `off` and make the add-on REFUSE TO START otherwise. diff --git a/goodwe_controller/scenarios/energy-charts-be-solar-price-2026-09-01_2026-09-17.json b/goodwe_controller/scenarios/energy-charts-be-solar-price-2026-09-01_2026-09-17.json new file mode 100644 index 0000000..9fdbf21 --- /dev/null +++ b/goodwe_controller/scenarios/energy-charts-be-solar-price-2026-09-01_2026-09-17.json @@ -0,0 +1 @@ +{"source":"api.energy-charts.info (Fraunhofer ISE), fetched 2026-09-29 by the OPT-11 P4 dev agent","queries":{"solar_actual":"/public_power?country=be&start=2026-09-01&end=2026-09-18 (production type 'Solar')","solar_dayahead":"/public_power_forecast?country=be&production_type=solar&forecast_type=day-ahead&start=2026-09-01&end=2026-09-18","price":"/price?bzn=BE&start=2026-09-01&end=2026-09-18"},"units":{"solar":"MW, Belgium, hourly (value at the hour's start)","price":"EUR/MWh, day-ahead, 15-minute"},"solar":{"unix_seconds":[1788213600,1788217200,1788220800,1788224400,1788228000,1788231600,1788235200,1788238800,1788242400,1788246000,1788249600,1788253200,1788256800,1788260400,1788264000,1788267600,1788271200,1788274800,1788278400,1788282000,1788285600,1788289200,1788292800,1788296400,1788300000,1788303600,1788307200,1788310800,1788314400,1788318000,1788321600,1788325200,1788328800,1788332400,1788336000,1788339600,1788343200,1788346800,1788350400,1788354000,1788357600,1788361200,1788364800,1788368400,1788372000,1788375600,1788379200,1788382800,1788386400,1788390000,1788393600,1788397200,1788400800,1788404400,1788408000,1788411600,1788415200,1788418800,1788422400,1788426000,1788429600,1788433200,1788436800,1788440400,1788444000,1788447600,1788451200,1788454800,1788458400,1788462000,1788465600,1788469200,1788472800,1788476400,1788480000,1788483600,1788487200,1788490800,1788494400,1788498000,1788501600,1788505200,1788508800,1788512400,1788516000,1788519600,1788523200,1788526800,1788530400,1788534000,1788537600,1788541200,1788544800,1788548400,1788552000,1788555600,1788559200,1788562800,1788566400,1788570000,1788573600,1788577200,1788580800,1788584400,1788588000,1788591600,1788595200,1788598800,1788602400,1788606000,1788609600,1788613200,1788616800,1788620400,1788624000,1788627600,1788631200,1788634800,1788638400,1788642000,1788645600,1788649200,1788652800,1788656400,1788660000,1788663600,1788667200,1788670800,1788674400,1788678000,1788681600,1788685200,1788688800,1788692400,1788696000,1788699600,1788703200,1788706800,1788710400,1788714000,1788717600,1788721200,1788724800,1788728400,1788732000,1788735600,1788739200,1788742800,1788746400,1788750000,1788753600,1788757200,1788760800,1788764400,1788768000,1788771600,1788775200,1788778800,1788782400,1788786000,1788789600,1788793200,1788796800,1788800400,1788804000,1788807600,1788811200,1788814800,1788818400,1788822000,1788825600,1788829200,1788832800,1788836400,1788840000,1788843600,1788847200,1788850800,1788854400,1788858000,1788861600,1788865200,1788868800,1788872400,1788876000,1788879600,1788883200,1788886800,1788890400,1788894000,1788897600,1788901200,1788904800,1788908400,1788912000,1788915600,1788919200,1788922800,1788926400,1788930000,1788933600,1788937200,1788940800,1788944400,1788948000,1788951600,1788955200,1788958800,1788962400,1788966000,1788969600,1788973200,1788976800,1788980400,1788984000,1788987600,1788991200,1788994800,1788998400,1789002000,1789005600,1789009200,1789012800,1789016400,1789020000,1789023600,1789027200,1789030800,1789034400,1789038000,1789041600,1789045200,1789048800,1789052400,1789056000,1789059600,1789063200,1789066800,1789070400,1789074000,1789077600,1789081200,1789084800,1789088400,1789092000,1789095600,1789099200,1789102800,1789106400,1789110000,1789113600,1789117200,1789120800,1789124400,1789128000,1789131600,1789135200,1789138800,1789142400,1789146000,1789149600,1789153200,1789156800,1789160400,1789164000,1789167600,1789171200,1789174800,1789178400,1789182000,1789185600,1789189200,1789192800,1789196400,1789200000,1789203600,1789207200,1789210800,1789214400,1789218000,1789221600,1789225200,1789228800,1789232400,1789236000,1789239600,1789243200,1789246800,1789250400,1789254000,1789257600,1789261200,1789264800,1789268400,1789272000,1789275600,1789279200,1789282800,1789286400,1789290000,1789293600,1789297200,1789300800,1789304400,1789308000,1789311600,1789315200,1789318800,1789322400,1789326000,1789329600,1789333200,1789336800,1789340400,1789344000,1789347600,1789351200,1789354800,1789358400,1789362000,1789365600,1789369200,1789372800,1789376400,1789380000,1789383600,1789387200,1789390800,1789394400,1789398000,1789401600,1789405200,1789408800,1789412400,1789416000,1789419600,1789423200,1789426800,1789430400,1789434000,1789437600,1789441200,1789444800,1789448400,1789452000,1789455600,1789459200,1789462800,1789466400,1789470000,1789473600,1789477200,1789480800,1789484400,1789488000,1789491600,1789495200,1789498800,1789502400,1789506000,1789509600,1789513200,1789516800,1789520400,1789524000,1789527600,1789531200,1789534800,1789538400,1789542000,1789545600,1789549200,1789552800,1789556400,1789560000,1789563600,1789567200,1789570800,1789574400,1789578000,1789581600,1789585200,1789588800,1789592400,1789596000,1789599600,1789603200,1789606800,1789610400,1789614000,1789617600,1789621200,1789624800,1789628400,1789632000,1789635600,1789639200,1789642800,1789646400,1789650000,1789653600,1789657200,1789660800,1789664400,1789668000,1789671600,1789675200,1789678800,1789682400,1789686000,1789689600,1789693200,1789696800,1789700400,1789704000,1789707600,1789711200,1789714800,1789718400,1789722000,1789725600,1789729200,1789732800,1789736400,1789740000,1789743600,1789747200,1789750800,1789754400,1789758000,1789761600,1789765200],"actual_mw":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,114.2,727.9,1795.6,2975.4,4152.6,4776.3,5060.0,5008.0,4769.2,4214.3,3123.2,1785.2,562.2,10.9,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,239.0,1152.6,2390.5,4109.2,5007.6,4605.0,4081.8,4021.1,3269.8,2573.1,1817.2,1013.0,347.4,9.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,82.3,409.7,617.9,926.0,1321.1,2109.5,2820.2,2437.3,1991.8,2042.2,1634.3,789.5,188.4,1.9,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,89.4,523.5,1018.8,1829.1,2278.5,2171.7,1935.4,1826.6,1602.5,1399.9,1364.0,649.9,90.3,0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,231.2,1101.9,2818.2,4429.7,5025.5,5602.2,5867.7,6134.0,5736.9,4874.9,3547.5,2040.9,612.7,14.8,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,273.5,1651.3,3127.0,4962.8,6487.6,7290.2,7738.9,7678.3,6752.6,4974.2,2970.4,1176.5,208.6,3.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,186.4,1269.8,2663.0,4342.6,5950.7,6952.1,7100.3,6669.3,5082.1,3329.3,2176.2,1026.7,253.7,1.7,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,105.9,699.2,1474.3,2499.7,3709.1,4432.7,4692.1,4138.1,2714.1,1336.2,530.6,468.6,249.4,1.9,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,229.0,1363.2,2907.2,4156.2,4636.4,4739.1,4359.9,3858.8,3924.7,3439.0,2506.1,1451.3,385.2,3.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,166.4,1302.4,2891.5,4667.7,6100.6,6561.2,6345.8,5839.1,5238.4,4359.7,3104.7,1523.4,286.4,0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,42.4,522.1,1210.9,1860.8,2570.2,2983.2,3386.0,3243.2,3053.6,2819.0,2209.5,1296.1,317.4,0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,74.3,809.8,2135.0,3659.9,4665.3,5282.2,5795.2,5377.6,4478.5,3348.8,2103.9,922.4,160.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.7,146.9,445.4,716.1,826.9,800.3,1071.0,1563.0,1688.9,1187.6,837.5,509.4,101.4,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,15.6,194.1,574.0,1015.5,1604.0,2296.5,2906.4,3495.3,3890.8,3586.0,2424.4,1352.6,285.7,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,117.8,1325.2,2984.4,4799.4,6173.9,6854.3,6621.2,5843.8,4587.6,3345.7,2034.7,899.5,151.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,64.7,921.0,2446.8,3716.5,4561.2,5240.0,5652.1,5521.4,5072.2,4196.4,2557.7,1124.3,174.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,30.5,552.4,1685.5,2813.2,3861.4,3806.6,3110.2,2338.1,1741.2,1280.2,806.7,423.5,86.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,75.5,1116.1,2859.4,4623.4,5413.3,5489.7,5656.1,5533.0,5292.3,4425.7,2814.5,1287.5,98.8,0.0,0.0,0.0,0.0],"dayahead_unix_seconds":[1788213600,1788217200,1788220800,1788224400,1788228000,1788231600,1788235200,1788238800,1788242400,1788246000,1788249600,1788253200,1788256800,1788260400,1788264000,1788267600,1788271200,1788274800,1788278400,1788282000,1788285600,1788289200,1788292800,1788296400,1788300000,1788303600,1788307200,1788310800,1788314400,1788318000,1788321600,1788325200,1788328800,1788332400,1788336000,1788339600,1788343200,1788346800,1788350400,1788354000,1788357600,1788361200,1788364800,1788368400,1788372000,1788375600,1788379200,1788382800,1788386400,1788390000,1788393600,1788397200,1788400800,1788404400,1788408000,1788411600,1788415200,1788418800,1788422400,1788426000,1788429600,1788433200,1788436800,1788440400,1788444000,1788447600,1788451200,1788454800,1788458400,1788462000,1788465600,1788469200,1788472800,1788476400,1788480000,1788483600,1788487200,1788490800,1788494400,1788498000,1788501600,1788505200,1788508800,1788512400,1788516000,1788519600,1788523200,1788526800,1788530400,1788534000,1788537600,1788541200,1788544800,1788548400,1788552000,1788555600,1788559200,1788562800,1788566400,1788570000,1788573600,1788577200,1788580800,1788584400,1788588000,1788591600,1788595200,1788598800,1788602400,1788606000,1788609600,1788613200,1788616800,1788620400,1788624000,1788627600,1788631200,1788634800,1788638400,1788642000,1788645600,1788649200,1788652800,1788656400,1788660000,1788663600,1788667200,1788670800,1788674400,1788678000,1788681600,1788685200,1788688800,1788692400,1788696000,1788699600,1788703200,1788706800,1788710400,1788714000,1788717600,1788721200,1788724800,1788728400,1788732000,1788735600,1788739200,1788742800,1788746400,1788750000,1788753600,1788757200,1788760800,1788764400,1788768000,1788771600,1788775200,1788778800,1788782400,1788786000,1788789600,1788793200,1788796800,1788800400,1788804000,1788807600,1788811200,1788814800,1788818400,1788822000,1788825600,1788829200,1788832800,1788836400,1788840000,1788843600,1788847200,1788850800,1788854400,1788858000,1788861600,1788865200,1788868800,1788872400,1788876000,1788879600,1788883200,1788886800,1788890400,1788894000,1788897600,1788901200,1788904800,1788908400,1788912000,1788915600,1788919200,1788922800,1788926400,1788930000,1788933600,1788937200,1788940800,1788944400,1788948000,1788951600,1788955200,1788958800,1788962400,1788966000,1788969600,1788973200,1788976800,1788980400,1788984000,1788987600,1788991200,1788994800,1788998400,1789002000,1789005600,1789009200,1789012800,1789016400,1789020000,1789023600,1789027200,1789030800,1789034400,1789038000,1789041600,1789045200,1789048800,1789052400,1789056000,1789059600,1789063200,1789066800,1789070400,1789074000,1789077600,1789081200,1789084800,1789088400,1789092000,1789095600,1789099200,1789102800,1789106400,1789110000,1789113600,1789117200,1789120800,1789124400,1789128000,1789131600,1789135200,1789138800,1789142400,1789146000,1789149600,1789153200,1789156800,1789160400,1789164000,1789167600,1789171200,1789174800,1789178400,1789182000,1789185600,1789189200,1789192800,1789196400,1789200000,1789203600,1789207200,1789210800,1789214400,1789218000,1789221600,1789225200,1789228800,1789232400,1789236000,1789239600,1789243200,1789246800,1789250400,1789254000,1789257600,1789261200,1789264800,1789268400,1789272000,1789275600,1789279200,1789282800,1789286400,1789290000,1789293600,1789297200,1789300800,1789304400,1789308000,1789311600,1789315200,1789318800,1789322400,1789326000,1789329600,1789333200,1789336800,1789340400,1789344000,1789347600,1789351200,1789354800,1789358400,1789362000,1789365600,1789369200,1789372800,1789376400,1789380000,1789383600,1789387200,1789390800,1789394400,1789398000,1789401600,1789405200,1789408800,1789412400,1789416000,1789419600,1789423200,1789426800,1789430400,1789434000,1789437600,1789441200,1789444800,1789448400,1789452000,1789455600,1789459200,1789462800,1789466400,1789470000,1789473600,1789477200,1789480800,1789484400,1789488000,1789491600,1789495200,1789498800,1789502400,1789506000,1789509600,1789513200,1789516800,1789520400,1789524000,1789527600,1789531200,1789534800,1789538400,1789542000,1789545600,1789549200,1789552800,1789556400,1789560000,1789563600,1789567200,1789570800,1789574400,1789578000,1789581600,1789585200,1789588800,1789592400,1789596000,1789599600,1789603200,1789606800,1789610400,1789614000,1789617600,1789621200,1789624800,1789628400,1789632000,1789635600,1789639200,1789642800,1789646400,1789650000,1789653600,1789657200,1789660800,1789664400,1789668000,1789671600,1789675200,1789678800,1789682400,1789686000,1789689600,1789693200,1789696800,1789700400,1789704000,1789707600,1789711200,1789714800,1789718400,1789722000,1789725600,1789729200,1789732800,1789736400,1789740000,1789743600,1789747200,1789750800,1789754400,1789758000,1789761600,1789765200],"dayahead_mw":[0.0,0.0,0.0,0.0,0.0,0.0,0.4,216.8,970.2,1764.6,2632.7,3541.0,4193.7,4455.6,4397.4,4093.4,3438.9,2603.6,1544.1,532.9,33.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.2,229.5,1139.6,2380.4,3495.0,4040.3,4075.9,3816.1,3349.8,2825.6,2266.2,1671.4,1024.5,378.5,19.9,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,96.5,453.4,828.2,1198.3,1711.3,2324.8,2792.9,3042.9,3026.8,2635.1,1879.1,1095.4,395.5,17.8,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,99.7,495.9,1021.1,1557.0,2058.4,2387.2,2364.9,2093.4,1729.9,1386.8,998.8,586.9,202.7,7.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,201.6,1236.4,2781.8,4162.3,5028.8,5460.7,5777.0,5827.4,5469.8,4722.4,3461.3,1787.2,469.6,15.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,201.8,1350.0,3063.8,4509.0,5599.3,6385.8,6741.5,6595.2,5984.5,4926.2,3361.5,1638.5,451.2,11.8,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,186.9,1206.6,2818.4,4465.9,5667.5,6276.1,6168.8,5559.8,4724.5,3723.5,2535.8,1311.3,379.6,7.7,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,107.9,632.7,1274.3,1990.8,2671.8,3026.4,3066.6,2829.2,2260.1,1531.2,887.6,416.4,118.2,1.7,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,166.6,1277.6,2941.7,4171.6,4781.4,5014.0,4967.6,4637.6,3959.4,3200.6,2224.8,1240.6,322.5,4.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,153.6,1267.9,3169.3,4881.5,5991.8,6225.3,5928.2,5330.3,4600.3,3718.3,2569.7,1355.4,324.5,2.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,60.7,394.8,904.1,1551.7,2229.4,2766.4,3180.6,3329.4,3176.2,2793.1,2131.7,1211.2,282.7,1.4,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,113.0,885.8,2077.2,3360.1,4519.9,5344.4,5608.2,5436.0,4890.1,4055.2,2806.9,1398.3,293.1,0.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,29.3,202.3,417.5,601.6,747.3,883.8,973.5,1142.9,1322.1,1310.2,1079.3,640.1,148.2,0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,46.4,358.3,780.1,1257.9,1778.8,2303.7,2715.1,2953.3,2894.0,2528.8,1914.0,1051.9,210.3,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,114.2,1209.6,3154.6,4922.3,6232.4,6986.1,7017.0,6445.2,5349.5,3941.9,2367.9,1093.5,202.2,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,93.0,1002.2,2592.9,3944.7,4621.7,4890.2,4988.8,4918.6,4583.5,3928.1,2748.8,1284.6,205.4,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,54.5,515.3,1190.5,1774.4,2228.6,2377.4,2132.7,1682.6,1311.8,1044.7,735.4,376.4,68.6,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,84.0,1077.3,2940.8,4618.6,5669.8,6127.5,6085.3,5699.0,5050.0,4026.0,2593.9,1120.8,158.6,0.0,0.0,0.0,0.0]},"price":{"unix_seconds":[1788213600,1788214500,1788215400,1788216300,1788217200,1788218100,1788219000,1788219900,1788220800,1788221700,1788222600,1788223500,1788224400,1788225300,1788226200,1788227100,1788228000,1788228900,1788229800,1788230700,1788231600,1788232500,1788233400,1788234300,1788235200,1788236100,1788237000,1788237900,1788238800,1788239700,1788240600,1788241500,1788242400,1788243300,1788244200,1788245100,1788246000,1788246900,1788247800,1788248700,1788249600,1788250500,1788251400,1788252300,1788253200,1788254100,1788255000,1788255900,1788256800,1788257700,1788258600,1788259500,1788260400,1788261300,1788262200,1788263100,1788264000,1788264900,1788265800,1788266700,1788267600,1788268500,1788269400,1788270300,1788271200,1788272100,1788273000,1788273900,1788274800,1788275700,1788276600,1788277500,1788278400,1788279300,1788280200,1788281100,1788282000,1788282900,1788283800,1788284700,1788285600,1788286500,1788287400,1788288300,1788289200,1788290100,1788291000,1788291900,1788292800,1788293700,1788294600,1788295500,1788296400,1788297300,1788298200,1788299100,1788300000,1788300900,1788301800,1788302700,1788303600,1788304500,1788305400,1788306300,1788307200,1788308100,1788309000,1788309900,1788310800,1788311700,1788312600,1788313500,1788314400,1788315300,1788316200,1788317100,1788318000,1788318900,1788319800,1788320700,1788321600,1788322500,1788323400,1788324300,1788325200,1788326100,1788327000,1788327900,1788328800,1788329700,1788330600,1788331500,1788332400,1788333300,1788334200,1788335100,1788336000,1788336900,1788337800,1788338700,1788339600,1788340500,1788341400,1788342300,1788343200,1788344100,1788345000,1788345900,1788346800,1788347700,1788348600,1788349500,1788350400,1788351300,1788352200,1788353100,1788354000,1788354900,1788355800,1788356700,1788357600,1788358500,1788359400,1788360300,1788361200,1788362100,1788363000,1788363900,1788364800,1788365700,1788366600,1788367500,1788368400,1788369300,1788370200,1788371100,1788372000,1788372900,1788373800,1788374700,1788375600,1788376500,1788377400,1788378300,1788379200,1788380100,1788381000,1788381900,1788382800,1788383700,1788384600,1788385500,1788386400,1788387300,1788388200,1788389100,1788390000,1788390900,1788391800,1788392700,1788393600,1788394500,1788395400,1788396300,1788397200,1788398100,1788399000,1788399900,1788400800,1788401700,1788402600,1788403500,1788404400,1788405300,1788406200,1788407100,1788408000,1788408900,1788409800,1788410700,1788411600,1788412500,1788413400,1788414300,1788415200,1788416100,1788417000,1788417900,1788418800,1788419700,1788420600,1788421500,1788422400,1788423300,1788424200,1788425100,1788426000,1788426900,1788427800,1788428700,1788429600,1788430500,1788431400,1788432300,1788433200,1788434100,1788435000,1788435900,1788436800,1788437700,1788438600,1788439500,1788440400,1788441300,1788442200,1788443100,1788444000,1788444900,1788445800,1788446700,1788447600,1788448500,1788449400,1788450300,1788451200,1788452100,1788453000,1788453900,1788454800,1788455700,1788456600,1788457500,1788458400,1788459300,1788460200,1788461100,1788462000,1788462900,1788463800,1788464700,1788465600,1788466500,1788467400,1788468300,1788469200,1788470100,1788471000,1788471900,1788472800,1788473700,1788474600,1788475500,1788476400,1788477300,1788478200,1788479100,1788480000,1788480900,1788481800,1788482700,1788483600,1788484500,1788485400,1788486300,1788487200,1788488100,1788489000,1788489900,1788490800,1788491700,1788492600,1788493500,1788494400,1788495300,1788496200,1788497100,1788498000,1788498900,1788499800,1788500700,1788501600,1788502500,1788503400,1788504300,1788505200,1788506100,1788507000,1788507900,1788508800,1788509700,1788510600,1788511500,1788512400,1788513300,1788514200,1788515100,1788516000,1788516900,1788517800,1788518700,1788519600,1788520500,1788521400,1788522300,1788523200,1788524100,1788525000,1788525900,1788526800,1788527700,1788528600,1788529500,1788530400,1788531300,1788532200,1788533100,1788534000,1788534900,1788535800,1788536700,1788537600,1788538500,1788539400,1788540300,1788541200,1788542100,1788543000,1788543900,1788544800,1788545700,1788546600,1788547500,1788548400,1788549300,1788550200,1788551100,1788552000,1788552900,1788553800,1788554700,1788555600,1788556500,1788557400,1788558300,1788559200,1788560100,1788561000,1788561900,1788562800,1788563700,1788564600,1788565500,1788566400,1788567300,1788568200,1788569100,1788570000,1788570900,1788571800,1788572700,1788573600,1788574500,1788575400,1788576300,1788577200,1788578100,1788579000,1788579900,1788580800,1788581700,1788582600,1788583500,1788584400,1788585300,1788586200,1788587100,1788588000,1788588900,1788589800,1788590700,1788591600,1788592500,1788593400,1788594300,1788595200,1788596100,1788597000,1788597900,1788598800,1788599700,1788600600,1788601500,1788602400,1788603300,1788604200,1788605100,1788606000,1788606900,1788607800,1788608700,1788609600,1788610500,1788611400,1788612300,1788613200,1788614100,1788615000,1788615900,1788616800,1788617700,1788618600,1788619500,1788620400,1788621300,1788622200,1788623100,1788624000,1788624900,1788625800,1788626700,1788627600,1788628500,1788629400,1788630300,1788631200,1788632100,1788633000,1788633900,1788634800,1788635700,1788636600,1788637500,1788638400,1788639300,1788640200,1788641100,1788642000,1788642900,1788643800,1788644700,1788645600,1788646500,1788647400,1788648300,1788649200,1788650100,1788651000,1788651900,1788652800,1788653700,1788654600,1788655500,1788656400,1788657300,1788658200,1788659100,1788660000,1788660900,1788661800,1788662700,1788663600,1788664500,1788665400,1788666300,1788667200,1788668100,1788669000,1788669900,1788670800,1788671700,1788672600,1788673500,1788674400,1788675300,1788676200,1788677100,1788678000,1788678900,1788679800,1788680700,1788681600,1788682500,1788683400,1788684300,1788685200,1788686100,1788687000,1788687900,1788688800,1788689700,1788690600,1788691500,1788692400,1788693300,1788694200,1788695100,1788696000,1788696900,1788697800,1788698700,1788699600,1788700500,1788701400,1788702300,1788703200,1788704100,1788705000,1788705900,1788706800,1788707700,1788708600,1788709500,1788710400,1788711300,1788712200,1788713100,1788714000,1788714900,1788715800,1788716700,1788717600,1788718500,1788719400,1788720300,1788721200,1788722100,1788723000,1788723900,1788724800,1788725700,1788726600,1788727500,1788728400,1788729300,1788730200,1788731100,1788732000,1788732900,1788733800,1788734700,1788735600,1788736500,1788737400,1788738300,1788739200,1788740100,1788741000,1788741900,1788742800,1788743700,1788744600,1788745500,1788746400,1788747300,1788748200,1788749100,1788750000,1788750900,1788751800,1788752700,1788753600,1788754500,1788755400,1788756300,1788757200,1788758100,1788759000,1788759900,1788760800,1788761700,1788762600,1788763500,1788764400,1788765300,1788766200,1788767100,1788768000,1788768900,1788769800,1788770700,1788771600,1788772500,1788773400,1788774300,1788775200,1788776100,1788777000,1788777900,1788778800,1788779700,1788780600,1788781500,1788782400,1788783300,1788784200,1788785100,1788786000,1788786900,1788787800,1788788700,1788789600,1788790500,1788791400,1788792300,1788793200,1788794100,1788795000,1788795900,1788796800,1788797700,1788798600,1788799500,1788800400,1788801300,1788802200,1788803100,1788804000,1788804900,1788805800,1788806700,1788807600,1788808500,1788809400,1788810300,1788811200,1788812100,1788813000,1788813900,1788814800,1788815700,1788816600,1788817500,1788818400,1788819300,1788820200,1788821100,1788822000,1788822900,1788823800,1788824700,1788825600,1788826500,1788827400,1788828300,1788829200,1788830100,1788831000,1788831900,1788832800,1788833700,1788834600,1788835500,1788836400,1788837300,1788838200,1788839100,1788840000,1788840900,1788841800,1788842700,1788843600,1788844500,1788845400,1788846300,1788847200,1788848100,1788849000,1788849900,1788850800,1788851700,1788852600,1788853500,1788854400,1788855300,1788856200,1788857100,1788858000,1788858900,1788859800,1788860700,1788861600,1788862500,1788863400,1788864300,1788865200,1788866100,1788867000,1788867900,1788868800,1788869700,1788870600,1788871500,1788872400,1788873300,1788874200,1788875100,1788876000,1788876900,1788877800,1788878700,1788879600,1788880500,1788881400,1788882300,1788883200,1788884100,1788885000,1788885900,1788886800,1788887700,1788888600,1788889500,1788890400,1788891300,1788892200,1788893100,1788894000,1788894900,1788895800,1788896700,1788897600,1788898500,1788899400,1788900300,1788901200,1788902100,1788903000,1788903900,1788904800,1788905700,1788906600,1788907500,1788908400,1788909300,1788910200,1788911100,1788912000,1788912900,1788913800,1788914700,1788915600,1788916500,1788917400,1788918300,1788919200,1788920100,1788921000,1788921900,1788922800,1788923700,1788924600,1788925500,1788926400,1788927300,1788928200,1788929100,1788930000,1788930900,1788931800,1788932700,1788933600,1788934500,1788935400,1788936300,1788937200,1788938100,1788939000,1788939900,1788940800,1788941700,1788942600,1788943500,1788944400,1788945300,1788946200,1788947100,1788948000,1788948900,1788949800,1788950700,1788951600,1788952500,1788953400,1788954300,1788955200,1788956100,1788957000,1788957900,1788958800,1788959700,1788960600,1788961500,1788962400,1788963300,1788964200,1788965100,1788966000,1788966900,1788967800,1788968700,1788969600,1788970500,1788971400,1788972300,1788973200,1788974100,1788975000,1788975900,1788976800,1788977700,1788978600,1788979500,1788980400,1788981300,1788982200,1788983100,1788984000,1788984900,1788985800,1788986700,1788987600,1788988500,1788989400,1788990300,1788991200,1788992100,1788993000,1788993900,1788994800,1788995700,1788996600,1788997500,1788998400,1788999300,1789000200,1789001100,1789002000,1789002900,1789003800,1789004700,1789005600,1789006500,1789007400,1789008300,1789009200,1789010100,1789011000,1789011900,1789012800,1789013700,1789014600,1789015500,1789016400,1789017300,1789018200,1789019100,1789020000,1789020900,1789021800,1789022700,1789023600,1789024500,1789025400,1789026300,1789027200,1789028100,1789029000,1789029900,1789030800,1789031700,1789032600,1789033500,1789034400,1789035300,1789036200,1789037100,1789038000,1789038900,1789039800,1789040700,1789041600,1789042500,1789043400,1789044300,1789045200,1789046100,1789047000,1789047900,1789048800,1789049700,1789050600,1789051500,1789052400,1789053300,1789054200,1789055100,1789056000,1789056900,1789057800,1789058700,1789059600,1789060500,1789061400,1789062300,1789063200,1789064100,1789065000,1789065900,1789066800,1789067700,1789068600,1789069500,1789070400,1789071300,1789072200,1789073100,1789074000,1789074900,1789075800,1789076700,1789077600,1789078500,1789079400,1789080300,1789081200,1789082100,1789083000,1789083900,1789084800,1789085700,1789086600,1789087500,1789088400,1789089300,1789090200,1789091100,1789092000,1789092900,1789093800,1789094700,1789095600,1789096500,1789097400,1789098300,1789099200,1789100100,1789101000,1789101900,1789102800,1789103700,1789104600,1789105500,1789106400,1789107300,1789108200,1789109100,1789110000,1789110900,1789111800,1789112700,1789113600,1789114500,1789115400,1789116300,1789117200,1789118100,1789119000,1789119900,1789120800,1789121700,1789122600,1789123500,1789124400,1789125300,1789126200,1789127100,1789128000,1789128900,1789129800,1789130700,1789131600,1789132500,1789133400,1789134300,1789135200,1789136100,1789137000,1789137900,1789138800,1789139700,1789140600,1789141500,1789142400,1789143300,1789144200,1789145100,1789146000,1789146900,1789147800,1789148700,1789149600,1789150500,1789151400,1789152300,1789153200,1789154100,1789155000,1789155900,1789156800,1789157700,1789158600,1789159500,1789160400,1789161300,1789162200,1789163100,1789164000,1789164900,1789165800,1789166700,1789167600,1789168500,1789169400,1789170300,1789171200,1789172100,1789173000,1789173900,1789174800,1789175700,1789176600,1789177500,1789178400,1789179300,1789180200,1789181100,1789182000,1789182900,1789183800,1789184700,1789185600,1789186500,1789187400,1789188300,1789189200,1789190100,1789191000,1789191900,1789192800,1789193700,1789194600,1789195500,1789196400,1789197300,1789198200,1789199100,1789200000,1789200900,1789201800,1789202700,1789203600,1789204500,1789205400,1789206300,1789207200,1789208100,1789209000,1789209900,1789210800,1789211700,1789212600,1789213500,1789214400,1789215300,1789216200,1789217100,1789218000,1789218900,1789219800,1789220700,1789221600,1789222500,1789223400,1789224300,1789225200,1789226100,1789227000,1789227900,1789228800,1789229700,1789230600,1789231500,1789232400,1789233300,1789234200,1789235100,1789236000,1789236900,1789237800,1789238700,1789239600,1789240500,1789241400,1789242300,1789243200,1789244100,1789245000,1789245900,1789246800,1789247700,1789248600,1789249500,1789250400,1789251300,1789252200,1789253100,1789254000,1789254900,1789255800,1789256700,1789257600,1789258500,1789259400,1789260300,1789261200,1789262100,1789263000,1789263900,1789264800,1789265700,1789266600,1789267500,1789268400,1789269300,1789270200,1789271100,1789272000,1789272900,1789273800,1789274700,1789275600,1789276500,1789277400,1789278300,1789279200,1789280100,1789281000,1789281900,1789282800,1789283700,1789284600,1789285500,1789286400,1789287300,1789288200,1789289100,1789290000,1789290900,1789291800,1789292700,1789293600,1789294500,1789295400,1789296300,1789297200,1789298100,1789299000,1789299900,1789300800,1789301700,1789302600,1789303500,1789304400,1789305300,1789306200,1789307100,1789308000,1789308900,1789309800,1789310700,1789311600,1789312500,1789313400,1789314300,1789315200,1789316100,1789317000,1789317900,1789318800,1789319700,1789320600,1789321500,1789322400,1789323300,1789324200,1789325100,1789326000,1789326900,1789327800,1789328700,1789329600,1789330500,1789331400,1789332300,1789333200,1789334100,1789335000,1789335900,1789336800,1789337700,1789338600,1789339500,1789340400,1789341300,1789342200,1789343100,1789344000,1789344900,1789345800,1789346700,1789347600,1789348500,1789349400,1789350300,1789351200,1789352100,1789353000,1789353900,1789354800,1789355700,1789356600,1789357500,1789358400,1789359300,1789360200,1789361100,1789362000,1789362900,1789363800,1789364700,1789365600,1789366500,1789367400,1789368300,1789369200,1789370100,1789371000,1789371900,1789372800,1789373700,1789374600,1789375500,1789376400,1789377300,1789378200,1789379100,1789380000,1789380900,1789381800,1789382700,1789383600,1789384500,1789385400,1789386300,1789387200,1789388100,1789389000,1789389900,1789390800,1789391700,1789392600,1789393500,1789394400,1789395300,1789396200,1789397100,1789398000,1789398900,1789399800,1789400700,1789401600,1789402500,1789403400,1789404300,1789405200,1789406100,1789407000,1789407900,1789408800,1789409700,1789410600,1789411500,1789412400,1789413300,1789414200,1789415100,1789416000,1789416900,1789417800,1789418700,1789419600,1789420500,1789421400,1789422300,1789423200,1789424100,1789425000,1789425900,1789426800,1789427700,1789428600,1789429500,1789430400,1789431300,1789432200,1789433100,1789434000,1789434900,1789435800,1789436700,1789437600,1789438500,1789439400,1789440300,1789441200,1789442100,1789443000,1789443900,1789444800,1789445700,1789446600,1789447500,1789448400,1789449300,1789450200,1789451100,1789452000,1789452900,1789453800,1789454700,1789455600,1789456500,1789457400,1789458300,1789459200,1789460100,1789461000,1789461900,1789462800,1789463700,1789464600,1789465500,1789466400,1789467300,1789468200,1789469100,1789470000,1789470900,1789471800,1789472700,1789473600,1789474500,1789475400,1789476300,1789477200,1789478100,1789479000,1789479900,1789480800,1789481700,1789482600,1789483500,1789484400,1789485300,1789486200,1789487100,1789488000,1789488900,1789489800,1789490700,1789491600,1789492500,1789493400,1789494300,1789495200,1789496100,1789497000,1789497900,1789498800,1789499700,1789500600,1789501500,1789502400,1789503300,1789504200,1789505100,1789506000,1789506900,1789507800,1789508700,1789509600,1789510500,1789511400,1789512300,1789513200,1789514100,1789515000,1789515900,1789516800,1789517700,1789518600,1789519500,1789520400,1789521300,1789522200,1789523100,1789524000,1789524900,1789525800,1789526700,1789527600,1789528500,1789529400,1789530300,1789531200,1789532100,1789533000,1789533900,1789534800,1789535700,1789536600,1789537500,1789538400,1789539300,1789540200,1789541100,1789542000,1789542900,1789543800,1789544700,1789545600,1789546500,1789547400,1789548300,1789549200,1789550100,1789551000,1789551900,1789552800,1789553700,1789554600,1789555500,1789556400,1789557300,1789558200,1789559100,1789560000,1789560900,1789561800,1789562700,1789563600,1789564500,1789565400,1789566300,1789567200,1789568100,1789569000,1789569900,1789570800,1789571700,1789572600,1789573500,1789574400,1789575300,1789576200,1789577100,1789578000,1789578900,1789579800,1789580700,1789581600,1789582500,1789583400,1789584300,1789585200,1789586100,1789587000,1789587900,1789588800,1789589700,1789590600,1789591500,1789592400,1789593300,1789594200,1789595100,1789596000,1789596900,1789597800,1789598700,1789599600,1789600500,1789601400,1789602300,1789603200,1789604100,1789605000,1789605900,1789606800,1789607700,1789608600,1789609500,1789610400,1789611300,1789612200,1789613100,1789614000,1789614900,1789615800,1789616700,1789617600,1789618500,1789619400,1789620300,1789621200,1789622100,1789623000,1789623900,1789624800,1789625700,1789626600,1789627500,1789628400,1789629300,1789630200,1789631100,1789632000,1789632900,1789633800,1789634700,1789635600,1789636500,1789637400,1789638300,1789639200,1789640100,1789641000,1789641900,1789642800,1789643700,1789644600,1789645500,1789646400,1789647300,1789648200,1789649100,1789650000,1789650900,1789651800,1789652700,1789653600,1789654500,1789655400,1789656300,1789657200,1789658100,1789659000,1789659900,1789660800,1789661700,1789662600,1789663500,1789664400,1789665300,1789666200,1789667100,1789668000,1789668900,1789669800,1789670700,1789671600,1789672500,1789673400,1789674300,1789675200,1789676100,1789677000,1789677900,1789678800,1789679700,1789680600,1789681500,1789682400,1789683300,1789684200,1789685100,1789686000,1789686900,1789687800,1789688700,1789689600,1789690500,1789691400,1789692300,1789693200,1789694100,1789695000,1789695900,1789696800,1789697700,1789698600,1789699500,1789700400,1789701300,1789702200,1789703100,1789704000,1789704900,1789705800,1789706700,1789707600,1789708500,1789709400,1789710300,1789711200,1789712100,1789713000,1789713900,1789714800,1789715700,1789716600,1789717500,1789718400,1789719300,1789720200,1789721100,1789722000,1789722900,1789723800,1789724700,1789725600,1789726500,1789727400,1789728300,1789729200,1789730100,1789731000,1789731900,1789732800,1789733700,1789734600,1789735500,1789736400,1789737300,1789738200,1789739100,1789740000,1789740900,1789741800,1789742700,1789743600,1789744500,1789745400,1789746300,1789747200,1789748100,1789749000,1789749900,1789750800,1789751700,1789752600,1789753500,1789754400,1789755300,1789756200,1789757100,1789758000,1789758900,1789759800,1789760700,1789761600,1789762500,1789763400,1789764300,1789765200,1789766100,1789767000,1789767900],"eur_mwh":[182.03,182.08,163.28,155.31,168.81,160.82,164.97,167.69,156.01,155.57,146.35,145.44,146.69,146.37,149.45,147.28,149.26,148.72,145.56,147.7,147.33,151.33,162.33,168.84,180.54,191.08,194.58,196.65,207.79,211.97,207.84,197.55,216.93,204.28,187.62,166.56,187.7,188.26,168.07,150.0,178.94,122.2,116.91,105.77,111.31,96.33,81.06,71.29,73.51,68.0,64.33,56.68,76.2,63.4,57.4,47.0,58.47,46.18,55.09,80.26,53.66,65.32,94.89,86.13,66.74,88.82,115.99,126.09,115.31,130.11,156.77,174.04,142.64,175.72,194.13,204.72,199.91,205.53,221.75,233.83,224.78,233.27,239.0,236.56,228.69,220.16,217.27,206.27,213.25,201.21,196.88,191.48,190.34,181.2,178.66,174.58,194.46,182.01,169.2,152.41,170.2,167.55,166.76,161.96,163.12,155.28,153.5,152.62,151.59,152.03,151.97,150.27,152.45,151.74,150.43,152.81,157.85,166.29,170.37,184.22,187.2,195.15,200.27,209.0,214.55,212.65,209.49,204.25,221.56,209.82,197.34,177.79,194.36,184.14,169.27,144.53,188.01,156.4,140.72,122.83,154.42,133.16,116.15,104.4,113.32,109.08,108.56,150.43,130.52,137.9,138.82,135.7,137.82,141.22,143.67,147.38,232.43,130.0,115.37,114.01,160.0,125.72,140.79,158.02,142.75,163.99,177.84,190.19,167.76,194.57,198.0,218.7,199.84,214.08,246.85,248.38,238.02,237.86,243.6,245.93,236.03,217.07,210.98,197.7,199.81,194.09,198.45,187.02,177.64,167.0,163.41,152.38,200.92,178.86,170.0,163.9,181.24,169.22,170.84,163.97,172.61,156.62,148.96,145.82,146.87,147.96,143.97,139.58,137.69,140.49,140.43,135.4,142.24,140.1,144.26,155.01,155.0,171.78,180.22,180.24,194.9,194.04,187.76,180.92,206.59,188.03,176.99,150.0,185.21,156.62,135.0,121.5,132.84,128.3,119.46,116.55,110.16,100.16,84.2,82.16,88.59,75.48,55.09,57.63,93.86,84.82,61.83,35.85,79.14,61.36,51.42,53.09,45.58,49.19,84.78,84.44,100.03,66.93,74.01,99.08,92.39,116.94,148.0,162.91,140.35,161.34,178.54,212.27,172.95,185.5,212.77,244.9,207.46,227.72,227.31,214.6,220.58,198.97,191.38,179.26,189.35,171.38,178.98,178.93,169.58,165.8,177.92,156.76,167.45,154.22,141.41,130.92,151.79,137.23,133.12,120.63,125.63,120.91,122.4,117.43,120.54,120.22,117.84,119.91,116.54,117.1,117.74,121.36,121.34,127.07,123.19,137.17,140.9,162.5,167.46,164.68,182.76,173.25,170.49,163.06,194.34,174.96,162.69,147.0,170.53,146.27,123.23,107.71,119.96,101.22,83.68,70.9,62.47,60.14,43.82,39.16,42.03,36.8,32.28,26.64,20.93,25.21,23.4,19.94,30.32,25.63,25.11,25.38,23.04,22.96,30.29,35.71,33.63,33.41,28.76,41.57,28.7,40.29,83.0,121.26,97.79,132.6,152.52,156.73,168.48,160.96,167.99,190.0,170.9,180.0,189.53,183.88,185.12,170.64,166.54,147.65,158.36,153.79,175.48,167.6,183.34,158.64,160.93,159.51,120.85,113.18,79.9,81.15,114.0,129.21,113.85,95.0,93.19,82.47,71.88,71.07,67.89,64.66,57.43,63.17,59.85,62.68,58.69,55.37,60.7,60.5,62.88,61.17,75.0,81.0,74.3,69.7,91.75,82.63,88.41,53.14,139.17,80.81,40.46,38.62,90.33,62.91,26.65,12.61,10.84,8.01,2.45,0.7,6.38,2.86,2.36,-0.25,10.1,11.11,7.67,1.94,0.0,2.11,4.5,5.14,5.21,3.6,3.72,5.37,3.75,3.13,1.95,4.02,2.33,6.54,21.4,47.18,41.44,80.65,121.78,162.9,151.95,184.59,228.13,230.8,195.0,210.0,227.74,254.99,216.55,209.24,213.41,206.43,242.72,212.97,207.75,191.2,204.27,200.0,215.09,215.05,216.85,194.24,195.39,161.31,200.0,181.4,164.0,190.0,190.44,180.0,185.0,164.5,176.14,171.11,166.5,155.38,160.07,154.27,151.56,153.85,142.89,142.44,146.03,149.27,142.45,143.52,148.8,147.16,145.82,148.24,148.01,144.3,147.14,140.58,130.41,119.91,137.86,125.05,101.35,82.62,81.44,59.6,11.17,6.46,1.86,0.38,0.01,0.0,0.0,0.0,-0.01,0.08,0.21,0.52,0.56,0.61,0.67,0.7,0.62,0.45,0.44,0.26,-0.1,-0.06,-0.02,-0.01,0.0,0.01,0.01,1.94,20.0,57.83,57.23,92.4,149.52,187.76,154.38,181.12,203.57,231.26,200.15,222.35,225.67,240.47,224.99,228.57,235.06,222.0,230.95,207.44,200.0,186.23,203.97,191.26,185.8,176.51,182.72,172.25,170.83,154.9,170.64,157.34,149.89,145.97,157.58,150.45,149.74,146.89,149.6,149.3,148.62,147.58,151.0,147.89,148.01,148.14,147.81,149.63,150.89,159.77,154.85,165.11,178.69,193.19,195.97,206.62,212.62,218.5,221.23,224.63,223.89,216.37,230.04,219.95,206.24,193.0,210.91,208.46,175.75,163.68,186.35,167.47,154.05,128.12,163.95,149.14,119.1,113.04,111.9,108.75,89.94,85.54,84.2,81.24,76.54,71.22,88.66,93.99,94.0,91.11,84.95,79.8,108.5,122.0,76.72,98.29,152.66,175.0,120.3,151.06,176.44,212.78,174.56,192.43,207.21,253.27,223.41,238.42,256.31,251.52,231.09,236.2,240.78,227.76,234.26,208.47,199.27,182.15,196.74,190.39,189.67,181.83,184.32,176.62,178.67,167.72,206.48,177.9,169.38,165.08,177.17,170.08,168.0,162.55,159.7,157.7,158.04,157.37,153.22,155.0,154.56,154.92,152.87,153.88,154.58,152.48,155.13,160.05,169.53,188.53,188.04,204.34,213.46,215.19,228.76,224.12,217.31,213.47,230.01,215.61,199.98,157.34,199.88,174.17,152.17,126.24,167.32,155.91,130.94,136.67,148.69,106.43,94.0,125.0,143.12,102.46,84.77,74.62,76.0,77.0,95.42,113.5,100.0,107.4,122.47,143.41,105.96,143.02,148.2,162.25,167.9,186.28,235.1,210.72,200.0,182.0,210.19,209.85,200.49,199.34,207.1,237.47,207.72,230.83,252.1,264.0,240.95,248.69,242.39,226.87,238.95,220.97,211.83,197.31,207.15,196.89,194.8,186.29,190.45,180.93,177.47,161.86,150.93,151.41,150.99,147.59,153.25,147.26,144.04,141.53,147.79,146.53,143.55,139.93,145.58,139.56,139.11,138.06,138.92,138.52,138.04,138.65,137.29,139.03,144.59,150.34,154.12,174.5,178.43,186.62,199.35,200.21,200.11,197.43,220.07,202.0,196.01,174.03,198.32,167.49,152.54,142.05,161.5,145.45,128.61,100.85,139.18,115.83,94.41,80.39,111.25,89.61,84.99,74.38,80.53,70.58,62.27,57.1,62.24,64.95,68.99,71.19,66.9,87.32,109.0,123.12,68.48,125.53,155.99,161.9,138.77,160.57,167.35,173.0,142.2,172.83,196.19,211.26,205.85,218.77,217.08,222.0,210.98,208.46,208.88,210.02,209.77,202.61,200.27,191.49,194.39,195.04,197.26,190.92,188.39,198.05,203.05,191.84,216.08,216.08,214.92,200.0,223.37,201.43,196.32,190.0,199.53,194.83,180.53,172.23,179.88,175.77,167.1,173.89,163.29,165.99,171.41,178.73,170.27,177.37,187.71,201.07,193.62,207.61,218.27,226.77,227.17,234.05,236.99,229.94,248.93,227.5,216.08,195.67,215.99,195.01,177.1,155.09,174.91,152.71,139.59,123.83,140.77,123.19,114.96,94.5,102.77,96.63,94.57,116.34,114.63,126.82,129.89,123.95,105.0,119.11,121.0,136.79,123.41,135.01,135.0,156.68,146.88,152.16,162.02,181.78,154.76,184.28,194.3,215.76,197.23,234.15,253.03,296.58,345.32,389.16,482.99,559.0,551.11,446.41,358.97,295.9,271.39,268.06,241.43,238.01,239.7,226.41,223.05,211.56,218.21,210.61,197.78,171.79,184.6,186.52,186.74,180.73,196.82,178.05,175.47,172.53,175.32,172.46,169.94,168.45,166.32,163.94,165.68,164.16,166.06,167.17,167.35,168.62,170.54,174.27,176.92,183.52,192.19,202.17,206.23,214.04,221.47,223.98,224.54,223.09,233.86,225.04,214.23,187.32,213.95,202.65,192.88,180.75,204.6,175.08,169.13,169.97,163.06,185.0,198.43,198.91,182.87,179.23,177.77,162.73,172.1,166.28,155.17,143.51,163.3,152.98,152.18,152.57,186.6,181.0,177.17,172.6,162.46,166.67,180.7,192.1,175.84,198.95,206.97,221.91,217.12,238.1,260.78,278.05,275.22,286.93,301.36,307.06,298.22,284.97,273.08,267.9,266.11,244.68,236.0,228.79,234.01,225.01,222.31,218.53,217.02,207.13,202.55,192.08,212.37,206.92,204.04,198.97,205.88,199.05,197.21,194.0,197.97,198.57,195.0,194.0,190.18,189.82,188.6,188.6,184.5,182.43,185.0,185.0,184.5,185.2,186.37,190.1,190.15,192.46,196.26,192.84,199.21,196.7,191.12,186.8,200.75,188.62,161.01,158.44,182.81,150.39,145.6,153.79,118.45,97.3,73.99,35.77,52.68,34.2,13.46,4.74,3.21,0.04,0.03,0.01,0.01,-0.02,-0.02,-0.04,-0.23,-0.03,0.11,0.31,0.16,0.46,0.71,2.85,0.09,5.21,33.89,66.56,70.11,101.9,121.52,152.39,147.85,180.52,192.56,195.82,194.44,204.81,206.31,212.48,210.99,211.17,210.92,207.69,210.75,204.94,202.7,201.72,199.85,202.7,206.1,201.8,198.01,194.39,194.96,190.65,191.99,180.01,173.3,166.01,176.4,165.98,164.26,163.74,168.52,163.79,160.6,159.2,163.59,162.26,161.37,159.7,164.44,163.8,163.6,164.38,165.12,166.31,168.69,172.0,171.24,176.28,181.79,180.65,185.77,184.13,181.4,170.89,190.1,173.56,159.78,158.28,156.27,160.0,206.87,216.22,204.03,210.0,210.15,208.74,201.09,200.0,198.91,200.0,190.0,197.52,192.03,190.17,190.0,187.41,183.56,179.49,176.61,183.24,189.84,189.26,184.13,189.99,190.0,173.41,192.5,170.63,162.67,159.67,181.0,181.46,195.22,208.01,196.33,203.18,210.52,228.64,217.28,228.31,234.49,239.96,228.8,235.0,237.53,233.99,235.33,235.0,231.65,227.5,232.43,227.5,227.5,222.41,220.53,208.58,207.24,206.0,218.18,205.79,196.0,186.85,192.1,187.5,189.38,182.59,185.42,185.05,183.47,182.75,183.46,184.16,183.8,184.05,180.24,181.2,183.46,190.12,184.46,194.47,208.57,219.61,217.24,233.14,248.07,253.46,271.31,290.75,295.11,297.14,322.65,289.62,274.69,252.89,279.63,264.53,239.64,214.12,240.16,219.56,201.43,183.63,211.71,193.52,196.52,184.4,195.27,181.38,176.86,168.87,175.0,161.89,155.25,154.82,159.82,161.77,155.63,166.0,152.91,155.59,169.1,182.0,152.0,170.08,190.0,201.52,175.17,205.53,233.51,270.47,229.77,270.89,333.46,415.67,404.29,435.53,453.89,473.23,459.76,414.74,364.86,331.14,321.33,292.9,266.69,248.81,267.01,248.59,241.74,224.4,235.05,222.94,217.32,205.7,220.0,217.99,206.05,192.24,211.24,198.43,194.29,188.1,189.9,187.33,188.68,188.05,185.3,185.99,187.33,184.0,184.06,184.3,184.53,181.31,184.37,187.02,199.91,215.55,221.26,234.39,236.48,246.4,255.55,251.15,248.71,243.93,268.06,241.51,225.01,197.87,227.5,212.6,189.51,158.02,181.16,162.59,128.03,112.06,146.77,133.17,101.37,109.96,76.07,63.14,58.9,57.88,40.35,38.99,38.55,35.67,55.47,50.01,57.1,85.42,64.43,90.0,111.1,140.0,136.6,129.01,156.17,190.22,162.47,197.9,215.77,230.55,205.94,223.22,243.09,278.93,255.4,280.48,282.39,280.88,262.25,251.19,245.93,238.7,231.3,226.54,223.45,208.0,212.98,202.8,199.21,187.03,194.58,187.06,180.29,171.04,182.54,179.17,174.97,171.33,173.51,170.97,170.88,170.12,167.75,167.9,170.37,169.89,169.85,168.72,167.11,168.69,170.17,167.23,169.14,170.0,167.9,177.37,187.37,220.0,197.69,217.11,230.8,237.77,243.9,239.69,235.5,231.64,247.01,237.79,223.17,192.0,219.85,202.29,185.57,182.2,200.69,193.13,182.29,171.96,162.72,155.32,141.29,135.83,138.48,116.46,114.76,102.69,105.87,97.8,95.13,90.54,100.42,102.58,103.54,105.57,106.16,114.22,126.39,126.41,126.98,137.06,158.59,177.36,173.45,189.85,198.98,216.92,204.26,222.42,235.62,263.72,238.62,248.91,263.27,269.75,264.58,248.79,240.28,234.85,237.58,229.52,215.47,199.19,216.13,202.96,198.3,191.83,200.09,190.81,184.75,168.7,197.58,185.08,176.47,169.98,174.1,168.39,165.03,162.09,162.3,158.05,155.7,154.95,160.56,161.19,155.07,155.33,154.59,155.12,157.61,158.65,154.1,153.69,161.44,169.37,170.77,191.92,204.03,212.71,226.18,219.37,212.21,205.04,215.92,205.03,195.31,176.24,200.0,179.57,153.31,124.7,150.69,127.84,99.53,71.89,65.19,42.21,37.72,35.01,53.75,39.37,33.61,29.35,31.66,33.1,33.84,33.14,36.32,40.0,49.88,73.6,51.78,80.0,102.17,117.18,67.26,110.88,158.88,171.2,135.28,183.35,195.15,196.4,175.59,197.09,210.32,215.1,208.86,214.85,220.55,242.65,222.4,220.21,221.71,219.19,222.96,214.97,207.21,191.66,201.88,193.56,197.36,190.04,189.25,187.6,181.63,168.09,154.93,147.78,139.31,135.34,140.08,134.35,132.41,132.98,131.48,130.65,137.82,137.95,132.5,133.98,135.29,143.31,132.55,137.72,134.35,138.47,143.38,142.42,153.72,166.12,178.99,187.39,194.1,208.47,214.08,224.71,227.72,216.8,229.11,212.83,208.23,190.36,210.3,182.39,150.0,114.83,166.0,110.0,83.5,55.06,70.83,66.52,36.32,36.23,20.47,9.17,5.7,1.8,6.13,4.83,5.32,5.13,16.92,18.22,18.6,26.34,0.38,2.33,4.15,6.38,16.45,9.75,63.59,61.63,32.01,64.31,116.25,154.15,135.57,166.57,198.45,218.22,183.16,189.31,197.36,215.28,206.78,205.44,198.66,195.15,193.79,190.4,180.77,171.21,179.84,176.32,171.21,150.91,164.19,146.47,137.36,118.64]},"license":"CC BY 4.0 (creativecommons.org/licenses/by/4.0) from Bundesnetzagentur | SMARD.de"} \ No newline at end of file diff --git a/goodwe_controller/test_batteries_screen.py b/goodwe_controller/test_batteries_screen.py index cb457c1..e4d0fb7 100644 --- a/goodwe_controller/test_batteries_screen.py +++ b/goodwe_controller/test_batteries_screen.py @@ -317,6 +317,15 @@ _cases = [ (dict(role="charge", refused=-1), "refuses_charge"), (dict(role="sell", peak=True), "peak"), (dict(role="hold", off=True), "off"), + # OPT-11 P4: the day plan's word, while holding only. + (dict(mode=packmode.LEFTOVER_SOLAR, role="hold", has_at=True, + day="sun_fills"), "sun_fills"), + (dict(mode=packmode.LEFTOVER_SOLAR, role="hold", day="tops_up"), + "tops_up"), + (dict(mode=packmode.LEFTOVER_SOLAR, role="hold", day="no_forecast"), + "no_forecast"), + (dict(mode=packmode.LEFTOVER_SOLAR, role="charge", day="tops_up"), + "grid_charge"), ] _wrong = [(kw, want, why(**kw)) for kw, want in _cases if why(**kw) != want] print(f" {_wrong}") diff --git a/goodwe_controller/test_modes_p4.py b/goodwe_controller/test_modes_p4.py new file mode 100644 index 0000000..7847e3c --- /dev/null +++ b/goodwe_controller/test_modes_p4.py @@ -0,0 +1,692 @@ +"""Runnable check for OPT-11 P4, the solar forecast and the day plan. +`python3 test_modes_p4.py` + +Drives the pure modules (solarfc, dayplan, modetrade) and the REAL Controller +(tools/opt11p3_replay.py's engine, with a forecast sensor in the fake Home +Assistant), in simulated time. DECISIONS/OPT-11-battery-modes.md has the +record. + +1. No usable forecast (none set, or set and unavailable): every command, + trade and role is byte-identical to release/1.0 5a4cdc2 (digests measured + there), and the harness sees a change there. +2. The forecast sensors: the three supported shapes, units, stale, missing. +3. The house profile: hours, days kept, the night floor, ready. +4. The day plan: sunny, partly, dark; Solar first never gets a level; a + Leftover solar level is the shortfall; hysteresis. +5. modetrade with a plan: a fuzz against the invariants, and no plan = P3. +6. The real controller over a night and a day: sunny (no grid charge), + dark (Leftover solar buys the shortfall only, and stops there), Cheap + hours skips the part the sun covers, a forecast that goes away mid-run, + and every P1-P3 and SAFETY-79 invariant on every cycle. +7. The Batteries screen and the Simple view: the forecast line and Why. +8. Options: validation of the trust and the entities. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import asyncio +import logging +import os +import random +import sys +from datetime import datetime, timedelta, timezone + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11p3_replay as rp # noqa: E402 +from app import arbitrage, dayplan, homeview, modetrade, packmode # noqa +from app import priceruns, solarfc, validate # noqa: E402 +from app.tariff import BILLING_TZ # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +L = timezone(timedelta(hours=2)) +A, B = "inverter-a", "inverter-b" +D0 = datetime(2026, 9, 21, tzinfo=L) +UTC0 = D0.astimezone(timezone.utc) + +# ============================================================================ # +print("1. no usable forecast: byte-identical to 5a4cdc2 (P3 option A)") +# Printed by tools/opt11p4_identity.py on release/1.0 5a4cdc2 (2026-09-29), +# goodwe-addon-checks:1. 1080 cycles each, battery modes on. +BASE_DIGESTS = { + "n1_ls": + "13f11c330263c91625acde7628426ff16dae3a9af99aebeef3051dc5b5a884ea", + "n1_ch": + "ff3fb2cdf849bc74185864e0fd87c04c70a947b2f2b08d3f5c9b35ee8b75f490", + "n2_sf_ls": + "9424e1837b805a6a31293a28b8fbad6ba611ea0bfe3240d636d68d62dc5e9f22", + "n2_ch_ls": + "63e09c4323148ec4e1e6766a3c50ab270b6575ec13c35aaa1115d2c5cabc342b", + "n2_ls_ls": + "98e180d43fa2aeecbe693838d2097dd4cb698c60aba8213c198d80d4e7166265", + "n2_sf_ch": + "95908916505bc5fa460db7b9829d5b56ec216038caa47be4bbf7be775241c7a2", + "n1_ls_fc_down": + "13f11c330263c91625acde7628426ff16dae3a9af99aebeef3051dc5b5a884ea", + "n1_ch_fc_down": + "ff3fb2cdf849bc74185864e0fd87c04c70a947b2f2b08d3f5c9b35ee8b75f490", + "n2_sf_ls_fc_down": + "9424e1837b805a6a31293a28b8fbad6ba611ea0bfe3240d636d68d62dc5e9f22", + "n2_ch_ls_fc_down": + "63e09c4323148ec4e1e6766a3c50ab270b6575ec13c35aaa1115d2c5cabc342b", + "n2_ls_ls_fc_down": + "98e180d43fa2aeecbe693838d2097dd4cb698c60aba8213c198d80d4e7166265", + "n2_sf_ch_fc_down": + "95908916505bc5fa460db7b9829d5b56ec216038caa47be4bbf7be775241c7a2", +} +import opt11p4_identity as ident # noqa: E402 + +got = ident.digests() +for k, v in BASE_DIGESTS.items(): + check(f"{k}: same digest as 5a4cdc2", got.get(k) == v) +check("every scenario is pinned", set(got) == set(BASE_DIGESTS)) +for k in [k for k in got if k.endswith("_fc_down")]: + check(f"{k}: a set but unavailable forecast equals no forecast", + got[k] == got[k[:-len('_fc_down')]]) + + +def _moved(scn, patch, undo): + patch() + try: + return ident.p3.digest(ident.run(**ident.SCENARIOS[scn])[0]) \ + != BASE_DIGESTS[scn] + finally: + undo() + + +_gcm = modetrade.GRID_CHARGE_MODES +check("the harness bites: Leftover solar grid-charging with no plan moves " + "n2_sf_ls", + _moved("n2_sf_ls", + lambda: setattr(modetrade, "GRID_CHARGE_MODES", + (packmode.LEFTOVER_SOLAR, packmode.CHEAP_HOURS)), + lambda: setattr(modetrade, "GRID_CHARGE_MODES", _gcm))) +_read = solarfc.read + + +def _as_sunny(today, tomorrow, now, **kw): + return _read({"state": "200", "attributes": {"unit_of_measurement": + "kWh"}, + "last_updated": now.isoformat()}, None, now) + + +check("...and an unavailable forecast read as a sunny one moves " + "n2_sf_ch_fc_down (Cheap hours would skip its charge)", + _moved("n2_sf_ch_fc_down", lambda: setattr(solarfc, "read", _as_sunny), + lambda: setattr(solarfc, "read", _read))) + +# ============================================================================ # +print("2. the forecast sensors") +NOW = datetime(2026, 9, 21, 9, 0, tzinfo=L).astimezone(timezone.utc) + + +def st(state, unit="kWh", at=NOW, **attrs): + a = dict(attrs) + if unit is not None: + a["unit_of_measurement"] = unit + return {"state": state, "attributes": a, + "last_updated": at.isoformat(), "last_reported": at.isoformat()} + + +fc, why = solarfc.read(st("12.5"), None, NOW) +check("Forecast.Solar shape (state only, kWh): read", fc is not None + and abs(fc.today.kwh - 12.5) < 1e-9 and fc.today.periods == ()) +check("...the rest of the day adds up to the state", + abs(fc.between(NOW, UTC0 + timedelta(days=1)) - 12.5) < 1e-6) +check("...and nothing comes after sunset (20:00 local)", + fc.between(datetime(2026, 9, 21, 20, tzinfo=L), UTC0 + + timedelta(days=1)) < 1e-9) +fc2, _ = solarfc.read(st("12500", unit="Wh"), None, NOW) +fc3, _ = solarfc.read(st("0.0125", unit="MWh"), None, NOW) +check("Wh and MWh are converted, never guessed", + abs(fc2.today.kwh - 12.5) < 1e-9 and abs(fc3.today.kwh - 12.5) < 1e-9) +check("a sensor with no unit, or in W, is refused (unit)", + solarfc.read(st("12.5", unit=None), None, NOW) == (None, solarfc.UNIT) + and solarfc.read(st("12.5", unit="W"), None, NOW)[1] == solarfc.UNIT) +check("unavailable, unknown and a missing entity are no forecast", + solarfc.read(st("unavailable"), None, NOW)[1] == solarfc.MISSING + and solarfc.read(st("unknown"), None, NOW)[1] == solarfc.MISSING + and solarfc.read(None, None, NOW)[1] == solarfc.MISSING) +check("a negative or non-numeric state is no forecast", + solarfc.read(st("-1"), None, NOW)[1] == solarfc.BAD + and solarfc.read(st("lots"), None, NOW)[1] == solarfc.BAD) +old = NOW - timedelta(seconds=solarfc.FRESH_S + 1) +check("older than 3 h is stale, and stale is no forecast", + solarfc.read(st("12.5", at=old), None, NOW) == (None, solarfc.STALE) + and solarfc.read(st("12.5", at=NOW - timedelta(hours=2, minutes=59)), + None, NOW)[0] is not None) +check("a report from the future is stale too", + solarfc.read(st("12.5", at=NOW + timedelta(hours=1)), None, + NOW)[1] == solarfc.STALE) +check("not configured says so", solarfc.read(None, None, NOW, + configured=False)[1] + == solarfc.NOT_SET) +# Solcast: detailedForecast, kW per 30 min, the whole day. +sol = [{"period_start": (UTC0 + timedelta(minutes=30 * i)).isoformat(), + "pv_estimate": 2.0 if 20 <= i < 36 else 0.0} for i in range(48)] +fc4, _ = solarfc.read(st("8.0", detailedForecast=sol), None, NOW) +# 10:00-18:00 local at 2 kW = 16 kWh in all; from 09:00 all 16 is to come, +# scaled to the state's 8. +check("Solcast shape: periods read and scaled to the state (kWh left)", + fc4.today.periods and abs(fc4.between(NOW, UTC0 + timedelta(days=1)) + - 8.0) < 1e-6) +check("...the split is used: 10:00-12:00 is a quarter of the day's sun", + abs(fc4.between(datetime(2026, 9, 21, 10, tzinfo=L), + datetime(2026, 9, 21, 12, tzinfo=L)) - 2.0) < 1e-6) +# Open-Meteo: wh_period, Wh per hour. +wh = {(UTC0 + timedelta(hours=h)).isoformat(): (1000.0 if 8 <= h < 16 + else 0.0) + for h in range(24)} +fc5, _ = solarfc.read(st("7.0", wh_period=wh), None, NOW) +check("Open-Meteo shape: wh_period read (8 x 1 kWh, 7 left at 09:00)", + abs(fc5.between(NOW, UTC0 + timedelta(days=1)) - 7.0) < 1e-6 + and abs(fc5.between(datetime(2026, 9, 21, 14, tzinfo=L), + datetime(2026, 9, 21, 16, tzinfo=L)) - 2.0) < 1e-6) +TOM = UTC0 + timedelta(days=1) +check("without tomorrow's sensor, a span into tomorrow's sun is unknown", + fc.between(NOW, TOM + timedelta(hours=9)) is None + and fc.between(NOW, TOM + timedelta(hours=5)) is not None) +fct, _ = solarfc.read(st("12.5"), st("20.0"), NOW) +check("with it, tomorrow's sun is counted", + abs(fct.between(TOM, TOM + timedelta(days=1)) - 20.0) < 1e-6) +fcs, _ = solarfc.read(st("12.5"), st("20.0", at=old), NOW) +check("a stale tomorrow is dropped, today is kept", + fcs is not None and fcs.tomorrow is None) + +# ============================================================================ # +print("3. the house profile") + + +def profile(day_w=None, days=1, evening=None, start=UTC0 - timedelta(days=1)): + hp = dayplan.HouseProfile() + t = start + end = start + timedelta(days=days) + while t < end: + h = t.astimezone(L).hour + w = (evening if evening is not None and 17 <= h < 22 else + day_w if day_w is not None else 600.0) + hp.add(t, w) + t += timedelta(seconds=5) + hp.add(t, None) + return hp + + +hp = profile(day_w=600.0, evening=3000.0) +check("a full day recorded is ready, with 24 hours", + hp.ready() and sum(len(r) for r in hp.days.values()) == 24) +check("an hour's figure is its mean", abs(hp.hour_w(18) - 3000.0) < 1e-6 + and abs(hp.hour_w(3) - 600.0) < 1e-6) +hp_half = dayplan.HouseProfile() +for i in range(12 * 60 * 10): + hp_half.add(UTC0 + timedelta(seconds=5 * i), 500.0) +check("ten hours are not ready (MIN_HOURS)", not hp_half.ready()) +neg = profile(day_w=-2000.0) +f, base = neg.estimator() +check("a sunny net use (negative) is lifted to the night floor for the " + "solar sum", f(12) == -2000.0 and base == -2000.0 or base >= 0.0) +hp9 = profile(days=9) +check("only the last 7 days are kept", len(hp9.days) <= 8) +hp_rt = dayplan.HouseProfile(hp.dump()) +check("dump and load give the same figures", hp_rt.hour_w(18) == round( + hp.hour_w(18), 1) and hp_rt.ready()) +check("a bad stored profile is ignored, not fatal", + not dayplan.HouseProfile({"x": "y", "2026-09-20": {"99": 1, + "a": "b"}}).ready()) + +# ============================================================================ # +print("4. the day plan") +P = modetrade.Pack + + +def pk(name, mode, soc, cap=10.0, **kw): + return P(name, True, mode, False, 2500.0, soc, cap, **kw) + + +# Prices: cheap 01:00-03:00, dear 19:00-20:00 local (as in test_modes_p3). +DAYW = [0.20] * 96 * 2 +for i in list(range(4, 12)) + list(range(100, 108)): + DAYW[i] = 0.02 +for i in list(range(76, 80)) + list(range(172, 176)): + DAYW[i] = 0.40 +WPTS = [(UTC0 + timedelta(minutes=15 * i), 900, p) for i, p in enumerate(DAYW)] +from app.price import PricePoint # noqa: E402 + + +def runs_at(now): + pts = [PricePoint(start=s, eur_per_kwh=rp.all_in(p), provisional=False) + for s, _n, p in WPTS] + return priceruns.plan(pts, now, required_eur_kwh=0.30, charge_kwh=6.0, + charge_kw=2.5, sell_kwh=0.0, sell_kw=0.0) + + +T0 = datetime(2026, 9, 21, 0, 30, tzinfo=L).astimezone(timezone.utc) +R0 = runs_at(T0) +check("the price plan has a cheap run at night and a dear one at 19:00", + R0.on and R0.cheap.holds(datetime(2026, 9, 21, 1, 30, tzinfo=L)) + and any(g.start.astimezone(L).hour == 19 for g in R0.give)) + + +def fc_of(kwh, now=T0): + wh = {(UTC0 + timedelta(hours=h)).isoformat(): + (kwh * 1000.0 / 10 if 8 <= h < 18 else 0.0) for h in range(24)} + return solarfc.read(st(f"{kwh}", wh_period=wh, at=now), None, now)[0] + + +EST = profile(day_w=600.0, evening=3000.0).estimator() +PACKS = [pk(A, packmode.SOLAR_FIRST, 60.0), pk(B, packmode.LEFTOVER_SOLAR, + 30.0)] + + +def dplan(kwh, packs=PACKS, trust=70, est=EST): + return dayplan.plan(fc_of(kwh), est, R0, T0, packs, trust_pct=trust, + floor_pct=20.0, ceiling_pct=95.0) + + +sunny, partly, dark = dplan(40.0), dplan(12.0), dplan(1.0) +print(f" sunny {sunny.verdict} {sunny.targets}; partly {partly.verdict} " + f"{partly.targets}; dark {dark.verdict} {dark.targets}") +check("40 kWh forecast: sunny, and B needs nothing from the grid", + sunny.verdict == dayplan.SUNNY and sunny.need_kwh[B] == 0.0) +check("1 kWh forecast: dark (not even A fills from the sun)", + dark.verdict == dayplan.DARK) +check("Solar first never gets a level (never charges from the grid)", + all(A not in p.targets for p in (sunny, partly, dark))) +_use = 3000.0 / 1000.0 # the 19:00-20:00 run at 3 kW +_want = 20.0 + _use / dayplan.EFF / 10.0 * 100.0 +check("dark: B's level is what the house draws in the dear run (floor + " + f"use / eff = {_want:.1f} %), not the 95 % ceiling", + abs(dark.targets[B] - _want) < 0.1 and dark.targets[B] < 95.0) +check("...so it buys only the shortfall", abs(dark.need_kwh[B] - ( + _want - 30.0) / 10.0) < 0.01) +check("the level falls as the forecast rises (partly between dark and " + "sunny)", sunny.targets[B] <= partly.targets[B] <= dark.targets[B]) +ch = dplan(12.0, packs=[pk(A, packmode.SOLAR_FIRST, 60.0), + pk(B, packmode.CHEAP_HOURS, 30.0)]) +ch_dark = dplan(1.0, packs=[pk(A, packmode.SOLAR_FIRST, 60.0), + pk(B, packmode.CHEAP_HOURS, 30.0)]) +check("Cheap hours: dark fills to the ceiling (as P3)", + abs(ch_dark.targets[B] - 95.0) < 1e-6) +check("...and skips the part the sun covers on a partly sunny day", + ch.targets[B] < 95.0 and ch.share_kwh[B] > 0 + and abs(ch.targets[B] - (95.0 - ch.share_kwh[B] * 10.0)) < 0.01) +check("trust 100 % counts more sun than 70 %: a lower or equal level", + dplan(12.0, trust=100).targets[B] <= partly.targets[B]) +check("no forecast, no house profile or no price plan: no plan", + dayplan.plan(None, EST, R0, T0, PACKS, trust_pct=70, floor_pct=20, + ceiling_pct=95) is None + and dplan(12.0, est=None) is None + and dayplan.plan(fc_of(12.0), EST, None, T0, PACKS, trust_pct=70, + floor_pct=20, ceiling_pct=95) is None) +# A plan for a run beyond today's forecast (after 20:00, cheap run tomorrow +# night, give run tomorrow evening) with no tomorrow sensor: no plan. +T_EVE = datetime(2026, 9, 21, 21, 0, tzinfo=L).astimezone(timezone.utc) +check("the sun before the dear run is unknown (no tomorrow sensor): no plan", + dayplan.plan(fc_of(12.0, T_EVE), EST, runs_at(T_EVE), T_EVE, PACKS, + trust_pct=70, floor_pct=20, ceiling_pct=95) is None) +off = [pk(A, packmode.SOLAR_FIRST, 60.0), + P(B, False, packmode.LEFTOVER_SOLAR, False, 2500.0, 30.0, 10.0)] +check("an Off battery gets no level", B not in dplan(1.0, packs=off).targets) +maint = [pk(A, packmode.SOLAR_FIRST, 60.0), + pk(B, packmode.LEFTOVER_SOLAR, 30.0, idle=False)] +check("a battery in maintenance gets no level", + B not in dplan(1.0, packs=maint).targets) +# Hysteresis. +cap = {B: 10.0} +check("hysteresis: a 0.3 kWh move on a 40 % level is ignored", + dayplan.hold({B: 40.0}, {B: 43.0}, cap) == {B: 40.0}) +check("...a 1 kWh move is taken", dayplan.hold({B: 40.0}, {B: 50.0}, cap) + == {B: 50.0}) +check("...10 % of a small level is enough (0.3 kWh on a 25 % level)", + dayplan.hold({B: 25.0}, {B: 28.0}, cap) == {B: 28.0}) +check("...a battery new to the plan takes its level, one gone is dropped", + dayplan.hold({A: 50.0}, {B: 33.0}, cap) == {B: 33.0}) +_flips = 0 +_kept = None +rnd = random.Random(4) +for i in range(400): + lvl = 40.0 + rnd.uniform(-2.0, 2.0) # a noisy forecast + new = dayplan.hold(_kept, {B: lvl}, cap) + if _kept is not None and new != _kept: + _flips += 1 + _kept = new +check(f"a forecast wobbling by +-0.2 kWh moves the level rarely " + f"({_flips} of 400)", _flips <= 8) + +# ============================================================================ # +print("5. modetrade with a plan") + + +def p3_chargers(packs, ceiling, done=()): + """P3 option A's rule, as 5a4cdc2 wrote it.""" + return [p for p in packs if p.use and p.idle and p.live + and p.mode in packmode.GRID_CHARGE_MODES and p.soc is not None + and p.soc < ceiling and p.refused >= 0 and p.name not in done] + + +rnd = random.Random(11) +bad = [] +same = 0 +for i in range(20000): + packs = [P(n, rnd.random() > 0.1, rnd.choice(packmode.MODES), False, + 2500.0, rnd.choice([None, rnd.uniform(0, 100)]), + rnd.choice([None, 10.0, 5.0]), live=rnd.random() > 0.05, + idle=rnd.random() > 0.1, refused=rnd.choice([0, 0, 0, 1, -1])) + for n in (A, B, "c")] + ceiling = rnd.choice([90.0, 95.0, 100.0]) + if [p.name for p in modetrade.chargers(packs, ceiling)] == \ + [p.name for p in p3_chargers(packs, ceiling)]: + same += 1 + targets = {p.name: rnd.uniform(0, 120) for p in packs + if rnd.random() > 0.3} + ch = modetrade.chargers(packs, ceiling, targets=targets) + for p in ch: + to = modetrade.charge_to(p, ceiling, targets) + if p.mode == packmode.SOLAR_FIRST or to is None or to > ceiling \ + or p.soc >= to or p.refused < 0 or not (p.use and p.idle + and p.live): + bad.append((p, targets, ceiling)) + if p.mode == packmode.LEFTOVER_SOLAR and p.name not in targets: + bad.append(("LS without a level", p)) +check("no plan: chargers() is P3 option A's rule on 20 000 random rosters", + same == 20000) +check("with a plan: never Solar first, never above the ceiling or the " + "level, never refusing, Off, not live or in maintenance, and Leftover " + f"solar only with a level ({len(bad)} bad)", not bad) +# decide() with a plan, in the cheap run: every range holds 0, only chargers +# charge, SF never charges. +now_c = R0.cheap.start + timedelta(minutes=5) +bad = [] +for i in range(5000): + packs = [P(n, rnd.random() > 0.1, rnd.choice(packmode.MODES), False, + 2500.0, rnd.uniform(0, 100), 10.0, live=rnd.random() > 0.05, + idle=rnd.random() > 0.1, refused=rnd.choice([0, 0, 1, -1])) + for n in (A, B)] + targets = {p.name: rnd.uniform(0, 100) for p in packs} + t = modetrade.decide(R0, now_c, packs, charge_ok=True, sell_ok=True, + trade_why=None, price_now=0.1, headroom_w=3000.0, + floor_pct=20.0, ceiling_pct=95.0, house_w=500.0, + targets=targets) + for p in packs: + lo, hi = t.ranges.get(p.name, (0.0, 0.0)) + if not lo <= 0.0 <= hi: + bad.append(("range without 0", p, lo, hi)) + if t.roles[p.name] == modetrade.CHARGE and ( + p.mode == packmode.SOLAR_FIRST + or p.soc >= min(95.0, targets[p.name])): + bad.append(("charges past its level", p, targets)) +check(f"decide() with a plan on 5000 random cases: ranges hold 0, nothing " + f"charges at or past its level, Solar first never ({len(bad)} bad)", + not bad) +t_ls = modetrade.decide(R0, now_c, [pk(A, packmode.SOLAR_FIRST, 50.0), + pk(B, packmode.LEFTOVER_SOLAR, 30.0)], + charge_ok=True, sell_ok=True, trade_why=None, + price_now=0.1, headroom_w=3000.0, floor_pct=20.0, + ceiling_pct=95.0, house_w=500.0, + targets={B: 50.0}) +check("a Leftover solar battery below its level charges in the cheap run, " + "Solar first rests", t_ls.roles == {A: modetrade.REST, + B: modetrade.CHARGE}) +e = modetrade.energy([pk(B, packmode.LEFTOVER_SOLAR, 30.0)], 20.0, 95.0, + targets={B: 45.0}) +check("the cheap run is sized by the shortfall (1.5 kWh), not the room to " + "95 % (6.5 kWh)", abs(e[0] - 1.5) < 1e-9) + +# ============================================================================ # +print("6. the real controller over a night and a day") +AIM = rp.PEAK_CAP - 50 +FC_KWH = [None] # today's forecast in the fake sensor (None: down) + + +async def _sensor(self, e): + now = rp_start[0] + timedelta(seconds=self.t) + kwh = FC_KWH[0](now) if callable(FC_KWH[0]) else FC_KWH[0] + if kwh is None: + return {"state": "unavailable", "attributes": {}, + "last_updated": now.isoformat()} + if e.endswith("tomorrow"): + return None + loc = now.astimezone(L) + d0 = loc.replace(hour=0, minute=0, second=0, microsecond=0) + wh = {(d0 + timedelta(hours=h)).astimezone(timezone.utc).isoformat(): + (kwh * 100.0 if 8 <= h < 18 else 0.0) for h in range(24)} + left = sum(v for k, v in wh.items() + if datetime.fromisoformat(k) >= now) / 1000.0 + return {"state": f"{left:.3f}", + "attributes": {"unit_of_measurement": "kWh", "wh_period": wh}, + "last_updated": now.isoformat(), "last_reported": now.isoformat()} + + +rp.Hass.state = _sensor +rp_start = [UTC0] +FC_OPTS = {"pv_forecast_entity": "sensor.energy_production_today_remaining", + "cycle_cost_threshold_eur": 0.20} + + +def seed_profile(c): + if c.house_profile is not None: + c.house_profile = profile(day_w=600.0, evening=3000.0) + + +def house_flat(w): + return [(UTC0.timestamp() - 10, float(w))] + + +def run_day(choice, *, fc, soc0, hours=21.0, start_h=0.75, house_w=800.0, + refuse=(), extra=None, patch=seed_profile): + FC_KWH[0] = fc + start = UTC0 + timedelta(hours=start_h) + rp_start[0] = start + rows = [] + + def cb(c, h, now, pr): + sh = dict(c.allocation.shares) if c.allocation is not None and \ + c.allocation.shares else {} + rows.append(dict( + now=now, grid=h.grid(), shares=sh, + action=getattr(c.arb, "action", None), + roles=dict(c.mode_tick.roles) if c.mode_tick else {}, + soc={u: p.soc for u, p in h.plants.items()}, + targets=c.plan_targets(), plan=c.day_plan, runs=c.mode_runs)) + st_, c = rp.run("p3_ls", house_flat(house_w), WPTS, start, 3600 * hours, + check=cb, soc0=soc0, choice=choice, refuse=refuse, + extra=dict(FC_OPTS, **(extra or {})), patch=patch) + return rows, st_, c + + +SF_LS = {"a": (True, "solar_first", False), "b": (True, "leftover_solar", + False)} +SF_CH = {"a": (True, "solar_first", False), "b": (True, "cheap_hours", + False)} + + +def invariants(tag, rows, c): + charge = [r for r in rows if r["action"] == arbitrage.CHARGE] + mixed = [r for r in rows if any(v > 0 for v in r["shares"].values()) + and any(v < 0 for v in r["shares"].values())] + check(f"{tag}: no opposite-direction split on any cycle", not mixed) + check(f"{tag}: Solar first never charges from the grid (A's share >= 0 " + "while the site charges)", + all(r["shares"].get(A, 0) >= 0 for r in charge)) + q = {int(r["now"].timestamp() // 900) for r in charge} + banked = [b.offtake_avg_w for b in c.p1.blocks + if int(b.start.timestamp() // 900) in q] + check(f"{tag}: every banked quarter with a grid charge <= cap - margin " + f"(max {max(banked, default=0):.1f} W, aim {AIM})", + not banked or max(banked) <= AIM + 0.5) + return charge + + +# Sunny: 40 kWh forecast. B (Leftover solar) at 30 % needs nothing. +rows, st_, c = run_day(SF_LS, fc=40.0, soc0={"a": 60.0, "b": 30.0}) +charge = invariants("sunny", rows, c) +print(f" sunny: verdict {rows[-1]['plan'] and rows[-1]['plan'].verdict}, " + f"{len(charge)} charge cycles") +check("sunny: a day plan is made, and says sunny", + any(r["plan"] is not None and r["plan"].verdict == dayplan.SUNNY + for r in rows)) +check("sunny: no grid charge at all", not charge) + +# Dark: 1 kWh. B buys the evening's shortfall only, in the cheap run. +rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}) +charge = invariants("dark", rows, c) +tgt = next(r["targets"][B] for r in rows if r["targets"]) +top = max(r["soc"]["b"] for r in rows) +print(f" dark: B level {tgt:.1f} %, B reached {top:.1f} %, " + f"{len(charge)} charge cycles") +check("dark: Leftover solar charges from the grid in the cheap run", + charge and all(r["runs"].cheap.holds(r["now"]) for r in charge) + and all(r["roles"][B] == modetrade.CHARGE for r in charge)) +check("dark: ...only up to its level (the shortfall), not 95 %", + tgt < 60.0 and top <= tgt + 2.0) +check("dark: A rests while B charges", all(r["roles"][A] == modetrade.REST + for r in charge)) + +# Cheap hours on a partly sunny day: skips the part the sun covers. +rows, st_, c = run_day(SF_CH, fc=14.0, soc0={"a": 60.0, "b": 30.0}) +charge = invariants("cheap hours, partly", rows, c) +tgt = next(r["targets"][B] for r in rows if r["targets"]) +top = max(r["soc"]["b"] for r in rows) +print(f" cheap hours partly: B level {tgt:.1f} %, reached {top:.1f} %") +check("Cheap hours with sun forecast: charges, but stops below 95 %", + charge and tgt < 90.0 and top <= tgt + 2.0) +rows_nf, _s, c_nf = run_day(SF_CH, fc=None, soc0={"a": 60.0, "b": 30.0}) +check("...and with the forecast down it fills towards 95 % as in P3", + max(r["soc"]["b"] for r in rows_nf) > top + 10.0) + +# The forecast goes away mid-run: Leftover solar stops at once (P3 option A). +DROP = UTC0 + timedelta(hours=1, minutes=30) +rows, st_, c = run_day(SF_LS, fc=lambda now: 1.0 if now < DROP else None, + soc0={"a": 60.0, "b": 10.0}) +invariants("forecast lost mid-run", rows, c) +before = [r for r in rows if r["now"] < DROP and r["action"] + == arbitrage.CHARGE] +late = [r for r in rows if r["now"] > DROP + timedelta( + seconds=2 * 60 + 10) and r["action"] == arbitrage.CHARGE] +check("forecast lost mid-run: Leftover solar was charging, and stops within " + "a forecast read (60 s) and a cycle", before and not late) + +# The forecast is far too high (40 kWh, and there is no sun at all): no grid +# charge, so B covers less of the evening - a money risk, never a safety one. +rows, st_, c = run_day(SF_LS, fc=40.0, soc0={"a": 30.0, "b": 30.0}) +invariants("forecast too high", rows, c) +check("forecast too high: no grid charge, and B still keeps its power for " + "the dear run", not [r for r in rows if r["action"] + == arbitrage.CHARGE] + and all(r["roles"].get(B) != modetrade.GIVE for r in rows + if r["now"].astimezone(L).hour not in (19,))) + +# A refusal wins over the plan. +rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}, + refuse=("b",)) +invariants("refusal", rows, c) +check("refusal: B refuses to charge, so the plan's charge ends and B is " + "never a charger after it", rows and not [ + r for r in rows[len(rows) // 3:] + if r["roles"].get(B) == modetrade.CHARGE]) + +# Off wins over the plan. +rows, st_, c = run_day({"a": (True, "solar_first", False), + "b": (False, "leftover_solar", False)}, + fc=1.0, soc0={"a": 60.0, "b": 30.0}) +check("Off: an Off battery never charges from the grid, whatever the plan", + not [r for r in rows if r["action"] == arbitrage.CHARGE] + and all(abs(r["shares"].get(B, 0)) < 1e-6 for r in rows)) + +# No house profile yet (first day): no plan, P3 option A. +rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}, + patch=None) +check("no house profile yet: no plan, and Leftover solar takes solar only", + all(r["plan"] is None for r in rows) + and not [r for r in rows if r["action"] == arbitrage.CHARGE]) +check("...while the profile learns and the store keeps each closed hour", + c.house_profile is not None and len( + c.store.data.get("house_profile") or {}) >= 1) +check("selling stays off (option A)", packmode.SELLING_ENABLED is False) + +# ============================================================================ # +print("7. the Batteries screen and the Simple view") +rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}, + hours=0.6) +rp.m.datetime = datetime +sb = homeview.solar_block(c, c.solar_fc.at) +check("the forecast line names the forecast, what is counted and when", + sb["line"].startswith("Solar forecast today:") and "we count on" in + sb["line"] and sb["state"] == "plan") +why = homeview.day_key(c, B) +check("B's Why key (plan, dark) is tops_up", why == "tops_up") +check("...and says so in plain words", homeview.why_words(why) + == "Too little sun is forecast, so it charges some from the grid.") +c.solar_fc = None +check("a lost forecast says so: no forecast, Leftover solar solar only", + homeview.solar_block(c, datetime.now(timezone.utc))["state"] + == "no_forecast" and homeview.day_key(c, B) == "no_forecast") +check("the Why line wins over 'saves its power' only while holding", + homeview.battery_why(modes_on=True, mode="leftover_solar", off=False, + reading=True, phase="idle", shadow=False, + running=True, held=False, refused=0, peak=False, + sf_ahead=True, role="hold", has_at=True, + day="sun_fills") == "sun_fills" + and homeview.battery_why(modes_on=True, mode="leftover_solar", + off=False, reading=True, phase="idle", + shadow=False, running=True, held=False, + refused=0, peak=False, sf_ahead=True, + role="charge", has_at=True, day="tops_up") + == "grid_charge") +for lang in ("en", "nl"): + homeview._LANG[0] = lang + t = [homeview.why_words(k) for k in ("sun_fills", "tops_up", + "no_forecast")] + t += [homeview._t("solar.no_forecast"), homeview._t("solar.learning"), + homeview.line_solar(9.2, 6.4, "10:15")] + check(f"{lang}: every P4 sentence is there and short (<= 2 x 12 words)", + all(t) and all(len(s.split()) <= 24 for s in t)) +homeview._LANG[0] = "en" +from app import uilayout # noqa: E402 +simple = [f.key for _g, _p, f in uilayout.fields() if f.simple] +check("the Simple view has the solar forecast card", + "pv_forecast_entity" in simple) + +# ============================================================================ # +print("8. options") +BASE_OPTS = {"setpoint_entity": "number.x", "max_w": 2500} +for v, ok in ((70, True), (30, True), (100, True), (29, False), (101, False), + (70.5, False), ("x", False)): + probs = validate._forecast_problems(dict(solar_trust_pct=v)) + check(f"solar_trust_pct {v!r}: {'accepted' if ok else 'refused'}", + (not probs) == ok) +check("a forecast entity that is not a sensor is refused, in plain words", + validate._forecast_problems({"pv_forecast_entity": "number.x"}) + and "must be a sensor" in validate._forecast_problems( + {"pv_forecast_entity": "number.x"})[0]) +check("empty entities are fine", not validate._forecast_problems( + {"pv_forecast_entity": "", "pv_forecast_tomorrow_entity": ""})) +notes = [] +validate._entity_notes(notes, {"pv_forecast_entity": "sensor.f", + "battery_modes_enabled": True}, + {"sensor.f": {"unit": "W"}}) +check("a forecast sensor not in kWh gets a warning", + any("kWh" in n.text for n in notes)) +notes = [] +validate._entity_notes(notes, {"pv_forecast_entity": "sensor.f"}, + {"sensor.f": {"unit": "kWh"}}) +check("a forecast with battery modes off gets a note that it is unused", + any("battery modes on" in n.text for n in notes)) + +print() +if fails: + print(f"FAILED: {len(fails)}") + for f in fails: + print(" -", f) + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/tools/opt11p4_identity.py b/goodwe_controller/tools/opt11p4_identity.py new file mode 100644 index 0000000..92ec7e8 --- /dev/null +++ b/goodwe_controller/tools/opt11p4_identity.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +"""OPT-11 P4: with no usable solar forecast, is every command byte-identical +to release/1.0 5a4cdc2 (P3, owner option A)? + + python3 tools/opt11p4_identity.py # one digest per scenario + +tools/opt11p3_identity.py's harness (the REAL Controller on a P1 meter, a +cheap slot, a dear slot, a house over the limit, `arbitrage_enabled`), now +with battery modes ON and each battery's mode set in the store, so P3's run +code runs on every cycle. Each row adds the trade and the roles. Scenarios: +* `ls`, `ch`, `ls_ls`, `ch_ls`: no `pv_forecast_entity` (the day plan never + runs); N=1 and N=2. +* `*_fc_down`: `pv_forecast_entity` set but the sensor reads `unavailable`, + with a ready house profile in the store (the plan falls back); 5a4cdc2 + ignores both keys, so the digest must match the scenario without them. +Uses only the API 5a4cdc2 has; test_modes_p4.py part 1 holds this tree to the +digests printed on 5a4cdc2. +""" + +import functools +import os +import sys +import tempfile + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +import opt11p3_identity as p3 # noqa: E402 +import safety79_identity as s79 # noqa: E402 +from app.store import unit_key # noqa: E402 + +FC = {"pv_forecast_entity": "sensor.energy_production_today_remaining", + "pv_forecast_tomorrow_entity": "sensor.energy_production_tomorrow"} + + +async def _unavailable(self, e): + return {"state": "unavailable", "attributes": {}, + "last_updated": "2026-09-20T11:00:00+00:00"} + + +rig._Hass.state = _unavailable + +SCENARIOS = { + "n1_ls": dict(n=1, modes={"inverter-a": "leftover_solar"}), + "n1_ch": dict(n=1, modes={"inverter-a": "cheap_hours"}), + "n2_sf_ls": dict(n=2, modes={"inverter-a": "solar_first", + "inverter-b": "leftover_solar"}), + "n2_ch_ls": dict(n=2, modes={"inverter-a": "cheap_hours", + "inverter-b": "leftover_solar"}), + "n2_ls_ls": dict(n=2, modes={"inverter-a": "leftover_solar", + "inverter-b": "leftover_solar"}), + "n2_sf_ch": dict(n=2, modes={"inverter-a": "solar_first", + "inverter-b": "cheap_hours"}), +} +for _k, _v in list(SCENARIOS.items()): + SCENARIOS[_k + "_fc_down"] = dict(_v, extra=FC) + + +def run(n, *, modes, extra=None, dur=p3.DUR): + opts = dict(s79.P1, **p3.ARB, battery_modes_enabled=True, + **(extra or {})) + if n == 2: + # A capacity on each battery, so a day plan could size a level; + # small, so the cheap run is the one cheap slot. + opts["inverters"] = [ + {"name": f"inverter-{u}", "setpoint_entity": f"number.sp_{u}", + "soc_entity": f"sensor.soc_{u}", "batt_entity": f"sensor.batt_{u}", + "max_w": 2500, "bms_soc_floor": 10, "capacity_kwh": 1.0} + for u in "ab"] + store = rig._Store() + # At N=1 the one battery is named after the site; the key is per name. + for name, mode in modes.items(): + store.data[unit_key(name, "pack_mode")] = mode + if extra: + # A ready house profile (a day, 600 W, 3 kW 17:00-22:00), so only + # the missing forecast stops a plan here. 5a4cdc2 ignores the key. + store.data["house_profile"] = {"2026-09-19": { + str(h): (3000.0 if 17 <= h < 22 else 600.0) for h in range(24)}} + trade = [] + + def on_cycle(c, t): + a, tick = c.arb, getattr(c, "mode_tick", None) + trade.append((None if a is None else (a.action, a.power_w, a.reason), + None if tick is None else + tuple(sorted(tick.roles.items())))) + db = os.path.join(tempfile.mkdtemp(prefix="p4id-"), "tariff.db") + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + try: + rows, c = rig.run(n, extra=opts, dur=dur, load=p3.load, soc=p3.soc, + cut=lambda u, t: False, before=p3._feed, + on_cycle=on_cycle, store=store) + finally: + rig.Controller = real + return [r + (x,) for r, x in zip(rows, trade)], c + + +def digests() -> dict: + return {k: p3.digest(run(**v)[0]) for k, v in SCENARIOS.items()} + + +if __name__ == "__main__": + if "--summary" in sys.argv: + for k, v in SCENARIOS.items(): + rows = run(**v)[0] + acts = sorted({str(r[-1][0][0]) if r[-1][0] else "None" + for r in rows}) + roles = sorted({x for r in rows if r[-1][1] + for x in (y for _n, y in r[-1][1])}) + print(f"{k}: {len(rows)} cycles, trade {acts}, roles {roles}") + for k, v in digests().items(): + print(f"{k} {v}") diff --git a/goodwe_controller/tools/opt11p4_replay.py b/goodwe_controller/tools/opt11p4_replay.py new file mode 100644 index 0000000..38f833e --- /dev/null +++ b/goodwe_controller/tools/opt11p4_replay.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python3 +"""OPT-11 P4: does the solar forecast pay? Replays recorded days through the +REAL Controller with tools/opt11p3_replay.py's engine (house, batteries, +prices, peak guard), plus a solar forecast sensor in Home Assistant. + + python3 tools/opt11p4_replay.py --variant p4_ls --fc recorded + python3 tools/opt11p4_replay.py --variant p3_ls --prices real2026 + +Runs unchanged on release/1.0 7a00f12 (P2) and 5a4cdc2 (P3): an older tree +ignores `pv_forecast_entity` and never reads the sensor. + +HOW THE FORECAST IS MADE (the site's own solar was not recorded for these +days; the 2026-09-24 PV recording is only in the live Home Assistant): +* The site's solar, hour by hour, is rebuilt from the recording: the house's + net use (grid + battery) is house - solar, so solar = max(0, H - net), + where H is the median net use of the night hours (22:00-06:00) over all + days (`--fc perfect` feeds exactly this). +* `recorded`: that solar times the day's error of the real Belgian day-ahead + solar forecast (Elia, via energy-charts): forecast / actual, per day. +* `national`: the Belgian day-ahead forecast itself, scaled to the site + (one factor: the site's total over the national total, all days). It + carries local weather differences too, so it is the harder test. +* `high`: `national` x 1.5. `missing`: the sensor is configured but reads + `unavailable`. The sensor has Open-Meteo's shape (state = kWh left today, + `wh_period` = Wh per hour); `--shape state` drops `wh_period` + (Forecast.Solar's shape). + +MONEY: as opt11p3_replay.py (all-in import (wholesale + 0.12) x 1.06, export +at wholesale), plus `stored_eur`: the change in usable energy (above the +10 % cut-out) from start to end, x 0.95, at the median all-in import price +of the run. `net_after_eur` = net - stored_eur. +""" + +import argparse +import bisect +import json +import os +import statistics +import sys +import time +from datetime import datetime, timedelta, timezone + +HERE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) + +import opt11p3_replay as rp # noqa: E402 + +EC = os.path.join(HERE, "scenarios", + "energy-charts-be-solar-price-2026-09-01_2026-09-17.json") +FC_ENTITY = "sensor.energy_production_today_remaining" +FC_TOMORROW = "sensor.energy_production_tomorrow" + +rp.VARIANTS.update({ + "p4_ls": (True, False, {"a": (True, "solar_first", False), + "b": (True, "leftover_solar", False)}), + "p4_ch": (True, False, {"a": (True, "solar_first", False), + "b": (True, "cheap_hours", False)}), +}) +LOCAL = timezone(timedelta(hours=2)) # CEST for every replayed day + + +def ec(): + return json.load(open(EC)) + + +def real2026_points(): + """The real day-ahead prices of the replayed days (15-minute).""" + d = ec()["price"] + return [(datetime.fromtimestamp(t, timezone.utc), 900, p / 1000.0) + for t, p in zip(d["unix_seconds"], d["eur_mwh"]) if p is not None] + + +def site_solar(house): + """{hour start (UTC epoch): site solar kWh}, and H (W).""" + by_h = {} + for t, w in house: + by_h.setdefault(int(t // 3600) * 3600, []).append(w) + net = {h: statistics.fmean(v) for h, v in by_h.items() if len(v) > 20} + night = [w for h, w in net.items() + if datetime.fromtimestamp(h, LOCAL).hour in + (22, 23, 0, 1, 2, 3, 4, 5)] + base = statistics.median(night) + return {h: max(0.0, base - w) / 1000.0 for h, w in net.items()}, base + + +def national(): + s = ec()["solar"] + act = dict(zip(s["unix_seconds"], s["actual_mw"])) + fc = dict(zip(s["dayahead_unix_seconds"], s["dayahead_mw"])) + return act, fc + + +def forecast_table(kind, house, days): + """{hour start epoch: forecast kWh}, and a report of its accuracy.""" + pv, base = site_solar(house) + act, fc = national() + day_of = {h: datetime.fromtimestamp(h, LOCAL).date() for h in pv} + if kind in ("perfect", "missing"): + out = dict(pv) + elif kind == "recorded": + ratio = {} + for d in set(day_of.values()): + hs = [h for h in pv if day_of[h] == d] + a = sum(act.get(h) or 0.0 for h in hs) + f = sum(fc.get(h) or 0.0 for h in hs) + ratio[d] = f / a if a > 0 else 1.0 + out = {h: pv[h] * ratio[day_of[h]] for h in pv} + else: + k = sum(pv.values()) / max(1e-9, sum(act.get(h) or 0.0 for h in pv)) + out = {h: (fc.get(h) or 0.0) * k * (1.5 if kind == "high" else 1.0) + for h in pv} + rep = [] + for d in sorted(set(day_of.values())): + a = sum(pv[h] for h in pv if day_of[h] == d) + f = sum(out[h] for h in out if day_of[h] == d) + rep.append((d.isoformat(), round(a, 1), round(f, 1))) + return out, base, rep + + +def install_sensor(table, kind, shape): + """Give opt11p3_replay's Hass a `state()` for the forecast sensors.""" + hours = sorted(table) + t0 = rp_start[0] + + def day_bounds(now): + loc = now.astimezone(LOCAL) + d0 = loc.replace(hour=0, minute=0, second=0, microsecond=0) + return d0, d0 + timedelta(days=1) + + def sensor(now, tomorrow): + d0, d1 = day_bounds(now) + if tomorrow: + d0, d1 = d1, d1 + timedelta(days=1) + a, b = d0.timestamp(), d1.timestamp() + i, j = bisect.bisect_left(hours, a), bisect.bisect_left(hours, b) + rows = [(h, table[h]) for h in hours[i:j]] + if not rows: + return None + n = now.timestamp() + left = 0.0 + for h, kwh in rows: + if tomorrow or h >= n: + left += kwh + elif h + 3600 > n: + left += kwh * (h + 3600 - n) / 3600.0 + attrs = {"unit_of_measurement": "kWh"} + if shape == "periods": + attrs["wh_period"] = { + datetime.fromtimestamp(h, timezone.utc).isoformat(): + round(kwh * 1000.0, 1) for h, kwh in rows} + # The forecast refreshes every hour. + rep = datetime.fromtimestamp(int(n // 3600) * 3600, timezone.utc) + return {"state": f"{left:.3f}", "attributes": attrs, + "last_updated": rep.isoformat(), + "last_reported": rep.isoformat()} + + async def state(self, e): + now = t0 + timedelta(seconds=self.t) + if kind == "missing": + return {"state": "unavailable", "attributes": {}, + "last_updated": now.isoformat()} + if e == FC_ENTITY: + return sensor(now, False) + if e == FC_TOMORROW: + return sensor(now, True) + return None + rp.Hass.state = state + + +rp_start = [None] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--variant", default="p4_ls") + ap.add_argument("--fc", default="recorded", + choices=("none", "recorded", "national", "perfect", + "high", "missing")) + ap.add_argument("--prices", default="epex2025", + choices=("epex2025", "real2026")) + ap.add_argument("--shape", default="periods", + choices=("periods", "state")) + ap.add_argument("--first", type=int, default=2) + ap.add_argument("--days", type=int, default=16) + ap.add_argument("--trust", type=int, default=None) + ap.add_argument("--report", action="store_true", + help="print the forecast's accuracy and exit") + a = ap.parse_args() + days = [f"2026-09-{d:02d}" for d in range(a.first, a.first + a.days)] + house = rp.load_house(days) + pts = rp.epex_points() if a.prices == "epex2025" else real2026_points() + start = datetime.fromisoformat(days[0] + "T00:00:00+02:00") \ + .astimezone(timezone.utc) + rp_start[0] = start + extra = {} + if a.fc != "none": + table, base, rep = forecast_table(a.fc, house, days) + if a.report: + print(json.dumps({"fc": a.fc, "night_base_w": round(base), + "days": rep})) + return + install_sensor(table, a.fc, a.shape) + extra = {"pv_forecast_entity": FC_ENTITY, + "pv_forecast_tomorrow_entity": FC_TOMORROW} + if a.trust is not None: + extra["solar_trust_pct"] = a.trust + socs = {} + + def check(c, hass, now, pr): + if "start" not in socs: + socs["start"] = {u: p.soc for u, p in hass.plants.items()} + socs["end"] = {u: p.soc for u, p in hass.plants.items()} + dp = getattr(c, "day_plan", None) + if dp is not None: + socs.setdefault("verdicts", {})[ + now.astimezone(LOCAL).date().isoformat()] = dp.verdict + t0 = time.time() + stats, _c = rp.run(a.variant, house, pts, start, 86400.0 * len(days), + extra=extra, check=check) + out = rp.summary(stats) + prices = sorted(rp.all_in(p) for _s, _n, p in pts + if start <= _s < start + timedelta(days=len(days))) + med = prices[len(prices) // 2] + + def usable(soc): + return sum(max(0.0, v - 10.0) / 100.0 * rp.CAP_KWH + for v in soc.values()) + d_kwh = usable(socs["end"]) - usable(socs["start"]) + out["stored_change_kwh"] = round(d_kwh, 2) + out["stored_eur"] = round(d_kwh * 0.95 * med, 2) + out["net_after_eur"] = round(out["net_eur"] - out["stored_eur"], 2) + out["end_soc"] = {u: round(v, 1) for u, v in socs["end"].items()} + out.update(variant=a.variant, fc=a.fc, prices=a.prices, shape=a.shape, + first=days[0], days=len(days), + verdicts=socs.get("verdicts", {}), + wall_s=round(time.time() - t0, 1)) + print(json.dumps(out)) + + +if __name__ == "__main__": + main() diff --git a/goodwe_controller/translations/en.yaml b/goodwe_controller/translations/en.yaml index db33d5b..f7f8631 100644 --- a/goodwe_controller/translations/en.yaml +++ b/goodwe_controller/translations/en.yaml @@ -85,6 +85,15 @@ configuration: battery_modes_enabled: name: "Hardware · Battery modes" description: "Give each battery an on and off switch and a mode, set on the Batteries screen." + pv_forecast_entity: + name: "Hardware · Solar forecast, today (kWh)" + description: "Optional. A forecast sensor with today's remaining solar energy, such as Forecast.Solar or Solcast. A battery then buys only what the sun will not give." + pv_forecast_tomorrow_entity: + name: "Hardware · Solar forecast, tomorrow (kWh)" + description: "Optional. The same forecast for tomorrow. It helps plan a cheap hour before midnight." + solar_trust_pct: + name: "Hardware · Trust in the forecast (%)" + description: "Forecasts are often too sunny. At 70 % the add-on plans with 7 of every 10 kWh forecast." pv_entity: name: "Hardware · Solar production entity (W)" description: "Optional. Your solar inverter's power sensor, positive while producing. The add-on records it and does not use it for control." diff --git a/goodwe_controller/translations/nl.yaml b/goodwe_controller/translations/nl.yaml index e9b4e6d..a4f910b 100644 --- a/goodwe_controller/translations/nl.yaml +++ b/goodwe_controller/translations/nl.yaml @@ -66,6 +66,15 @@ configuration: battery_modes_enabled: name: "Hardware · Batterijmodi" description: "Geef elke batterij een aan- en uitschakelaar en een modus, in te stellen op het scherm Batterijen." + pv_forecast_entity: + name: "Hardware · Zonneprognose, vandaag (kWh)" + description: "Optioneel. Een prognosesensor met de zonne-energie die vandaag nog komt, zoals Forecast.Solar of Solcast. Een batterij koopt dan alleen wat de zon niet geeft." + pv_forecast_tomorrow_entity: + name: "Hardware · Zonneprognose, morgen (kWh)" + description: "Optioneel. Dezelfde prognose voor morgen. Ze helpt een goedkoop uur voor middernacht te plannen." + solar_trust_pct: + name: "Hardware · Vertrouwen in de prognose (%)" + description: "Prognoses zijn vaak te zonnig. Bij 70 % plant de add-on met 7 van elke 10 kWh uit de prognose." pv_entity: name: "Hardware · Entiteit zonneproductie (W)" description: "Optioneel. De vermogenssensor van uw zonne-omvormer, positief tijdens productie. De add-on houdt ze bij en regelt er niet mee." -- 2.54.0 From 5d27f8496fb933dae6abd19a895a4067b44e918f Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Tue, 29 Sep 2026 19:52:51 +0200 Subject: [PATCH 080/105] SAFETY-78: maintenance drain at N=2 no longer stalls At two inverters the drain pins its pack and the site target is split around the pin. Below the pin the other pack had to charge, the allocator refused the opposite directions, and the site sat at 0 W with an ARBITER line every cycle (house below or above the drain rate, or a grid charge). main.py now files a site limit `drain` (lo = what the pin places, at P_MAINTENANCE) at N>=2 while a pack drains, so the other pack only adds power in the same direction. A drain that cannot give power waits with one log line. With battery modes on, no grid charge while a pack drains, and the other battery's card says why. N=1 is byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../MAINT-05-per-pack-maintenance.md | 29 +- .../DECISIONS/SAFETY-78-drain-at-two.md | 38 ++ goodwe_controller/DOCS.md | 5 + goodwe_controller/app/allocator.py | 17 +- goodwe_controller/app/arbiter.py | 6 + goodwe_controller/app/homeview.py | 15 +- goodwe_controller/app/main.py | 51 ++- goodwe_controller/app/messages.py | 1 + goodwe_controller/app/modetrade.py | 12 +- goodwe_controller/app/ui_text/en.json | 1 + goodwe_controller/app/ui_text/nl.json | 1 + goodwe_controller/test_arbiter.py | 14 +- goodwe_controller/test_batteries_screen.py | 11 +- goodwe_controller/test_maintenance.py | 50 +-- goodwe_controller/test_modes.py | 14 +- goodwe_controller/test_peakguard.py | 30 +- goodwe_controller/test_safety78.py | 343 ++++++++++++++++++ goodwe_controller/tools/safety78_identity.py | 110 ++++++ 18 files changed, 653 insertions(+), 95 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md create mode 100644 goodwe_controller/test_safety78.py create mode 100644 goodwe_controller/tools/safety78_identity.py diff --git a/goodwe_controller/DECISIONS/MAINT-05-per-pack-maintenance.md b/goodwe_controller/DECISIONS/MAINT-05-per-pack-maintenance.md index 546af20..305db50 100644 --- a/goodwe_controller/DECISIONS/MAINT-05-per-pack-maintenance.md +++ b/goodwe_controller/DECISIONS/MAINT-05-per-pack-maintenance.md @@ -285,32 +285,11 @@ cross-inverter `lo > hi` contradiction at `arbiter.py:114`. The only line this card changed there is **which** roster entry the claim is filed on: the one whose state machine produced the result, rather than `inverters[0]`. -## 6. FOUND AND NOT FIXED: the site loop still contradicts a drain at N>=2 +## 6. FIXED BY SAFETY-78: the site loop contradicted a drain at N>=2 -Measured while wiring this card, and **pre-existing on `release/1.0` at -`2d025ee`** — the same drain filed on `inverters[0]` produces the identical -refusal with the two unit names swapped. - -The maintenance SET **pins** its pack. The loop's target is a **site** claim. -When the site target is *below* the pin — a 2000 W drain while the house imports -less than that, which is most of a night — the only split that sums to the site -target asks the sibling to **charge** while the maintained pack **discharges**, -and `allocator.plan()` refuses it by name as circulating power. The refusal is -correct and fails safe: the whole site goes to 0 W with an `ARBITER: REFUSED` -line in the action log. - -**The consequence an operator would see is a misdiagnosis.** The pack is held at -0 W while its state machine believes it is draining, so after 12 h the DRAIN -timeout fires and reports *"drain stuck"* — §12's words for a battery that is not -following commands. The battery is fine; the site refused to allocate. - -**Why it is not fixed here.** The fix is to change what the site loop's target -*means* while a unit is pinned — regulate the meter using only the unpinned -packs — which is loop and allocator territory and changes the integrator's -subject. MAINT-05 moves which pack is pinned and nothing else about it. It is -pinned as a running check (`test_maintenance.py` part 12) rather than left as a -comment, so it cannot be forgotten or quietly tuned away, and it wants a card of -its own. +Found here and pre-existing: below the pin the other pack had to charge, the +allocator refused it and the site sat at 0 W. Fixed by a site `drain` floor; +see [[SAFETY-78]] (`DECISIONS/SAFETY-78-drain-at-two.md`). ## 7. FOUND AND NOT FIXED: `migrate_unit_keys()` has the same hole, and it is a LATCH diff --git a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md new file mode 100644 index 0000000..29511b2 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md @@ -0,0 +1,38 @@ +# SAFETY-78 - a maintenance drain at two inverters + +**Status: DECIDED 2026-09-29.** Fixes MAINT-05 §6 (OPT-11 P1 F1, UX-13 P3 +check 5, OPT-11 P3 F4). Tests: `test_safety78.py`. + +**The defect.** At N>=2 the drain pins its pack (a unit SET at +`P_MAINTENANCE`) and the site target is split around the pin. Whenever the +site target was below the pin, the other pack had to charge. The allocator +refuses opposite directions (SAFETY-25 §0a, SAFETY-31), so the site went to +0 W and logged `ARBITER: REFUSED` every cycle. That covers a house below the +drain rate, a grid-charge trade, and a house above it too: after a refusal the +loop restarts from 0 W and its 400 W slew step is below the pin again. + +**The fix.** While a pack drains at N>=2, main.py files a site limit +`drain`, `lo` = what the pin really places (`allocator.pin_w()`: the drain +rate inside that pack's own hard limits), at `P_MAINTENANCE`. So the site +target is never below the pin and the other pack only adds power in the same +direction. Opposite splits stay forbidden. + +- The order is the arbiter's own: a safety SET (100) outranks the limit and + the pin, so everything parks; the peak floor (50) and the drain floor are + both applied, so the higher wins; a trade or the loop below the drain is + lifted to it. +- Below the drain rate the drained pack exports the rest, as the drain does at + N=1 (`maintenance.py`: "forced discharge, exports the surplus"). Holding it + to the house load would make N=2 drain differently from N=1; that is an + owner question, not this fix. +- A draining pack that can place nothing (a refusal, a stale link) adds no + floor, and the wait is logged once per episode. +- With battery modes on, no pack is a grid charger while another drains + (`modetrade.decide(draining=)`, why `cycle`), and the other battery's card + says why (`other_cycle`). +- Not filed at N=1, where the drain is the site SET itself: byte-identical + (`tools/safety78_identity.py`, which hashes the claims too). + +**Not changed.** At N=1 a drain (60) still outranks the peak floor (50), so +the peak guard does not add to a drain there. That is pre-existing and kept by +the N=1 identity. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 2da5da8..96bc604 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -539,6 +539,7 @@ With battery modes on, these choices replace the *Charging and selling on price* - The peak limit, the safety stops and the monthly cycle come before a battery's mode. - A grid charge is sized so the 15-minute period stays under the peak limit less its margin (`peak_margin_w`). It starts only at 500 W or more. Once the peak limit stops it, it stays off for the rest of that 15-minute period. - While one battery charges from the grid, the others rest, and the house uses the grid. +- While one battery empties for its monthly cycle, no battery charges from the grid. - A battery that refuses to charge or give power takes no part in a run in that direction. **In Home Assistant.** With MQTT set up, each battery also gets a *Mode* list and a *Use* switch, for example `select.goodwe_inverter_a_mode` and `switch.goodwe_inverter_a_use`. They do the same as the Batteries screen. Turn battery modes off and restart, and they are removed. @@ -1647,6 +1648,10 @@ under `peak_cap_w`, and if the forecast goes over the cap the charge-only clamp is dropped so the battery can shave the peak instead. Money outranks the maintenance schedule. +With two or more batteries, the one being emptied gives its drain rate and the +others only add power when the house needs more; none charges while it drains +(SAFETY-78). Below the drain rate the rest is exported, as with one battery. + #### Capacity-tariff exposure of the grid-following loop ⚠️ **This section described the exposure BEFORE SAFETY-07. The loop is now diff --git a/goodwe_controller/app/allocator.py b/goodwe_controller/app/allocator.py index 9ddef8b..a84ef55 100644 --- a/goodwe_controller/app/allocator.py +++ b/goodwe_controller/app/allocator.py @@ -344,6 +344,16 @@ class _Narrowed: self.lo, self.hi = lo, hi +def pin_w(b): + """The watts a unit's own SET places once held inside its hard limits, + as `plan()` places a standing pin, or None when the unit has no SET.""" + pv = getattr(b, "pinned_w", None) + if getattr(b, "gate", None) is None or pv is None: + return None + lo, hi = _int_envelope(b) + return float(pv) if lo > hi else float(_clamp_int(round(float(pv)), lo, hi)) + + def loop_bound(bounds, live=None): """OPT-11. `(lo, hi)`: what the units can place when the LOOP decides. @@ -364,11 +374,8 @@ def loop_bound(bounds, live=None): continue if getattr(b, "contradiction", False): continue - pv = getattr(b, "pinned_w", None) - if getattr(b, "gate", None) is not None and pv is not None: - lo, hi = _int_envelope(b) - p = float(pv) if lo > hi else float(_clamp_int(round(float(pv)), - lo, hi)) + p = pin_w(b) + if p is not None: lo_sum += min(0.0, p) hi_sum += max(0.0, p) continue diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 5d69d1d..42b7a18 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -184,6 +184,12 @@ CLAIM_SCOPE = { # the banner and the claim an install has had since SAFETY-02 shipped. # `Controller.cycle()` does not even arm the site detector there. "sign_site": SCOPE_SITE, + # main.py: `Claim.limit("drain", P_MAINTENANCE, lo=...)`, SAFETY-78. At + # N>=2, while a pack's maintenance drain is pinned, the site target may + # not go below what that pin places: below it a sibling would have to + # charge against the drain (circulation, refused, 0 W). A site `lo`, + # never filed at N=1. DECISIONS/SAFETY-78-drain-at-two.md. + "drain": SCOPE_SITE, # --- UNIT: about one pack, one inverter, one device ------------------- # main.py: `Claim.limit("device", P_SAFETY, self.dev_min, self.dev_max, diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 72520d4..550ddfd 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -640,6 +640,11 @@ def battery_rows(c, shadow, running, held=False): # carries its share (SAFETY-73)? other = next((o.name for o in c.inverters if o is not inv and refusing(c, o) > 0 and not _off(c, o)), None) + # SAFETY-78: another battery drains for its monthly cycle, so this + # one never charges now. + cycling = next((o.name for j, o in enumerate(c.inverters) + if o is not inv and j < len(c.maints) + and c.maints[j].phase == M_DRAIN), None) role = None if tick is None else tick.roles.get(inv.name) # Only once a cycle has run with modes on (`tick`): before that # nothing is known, so nothing is claimed about the prices. @@ -655,7 +660,8 @@ def battery_rows(c, shadow, running, held=False): phase=phase, shadow=shadow, running=running, held=held, refused=refusing(c, inv), peak=peak, giving=flow(inv.batt) == "giving", other_refuses=other, - sf_ahead=sf_ahead, role=role, plan=plan, has_at=bool(at)) + sf_ahead=sf_ahead, role=role, plan=plan, has_at=bool(at), + other_cycle=cycling) rows.append({ "name": inv.name, "level_pct": None if inv.soc is None else float(inv.soc), @@ -673,7 +679,8 @@ def battery_rows(c, shadow, running, held=False): # UX-13 P3: why it does what "now" says, from what the add-on # knows this cycle. Price and forecast reasons are OPT-11 P3/P4. "why_key": why, - "why": why_words(why, name=other, at=at), + "why": why_words(why, name=cycling if why == "other_cycle" + else other, at=at), }) if modes_on: # OPT-11 P1: the battery's switch and mode, for the Batteries @@ -692,7 +699,7 @@ def battery_rows(c, shadow, running, held=False): def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, held, refused, peak, sf_ahead, giving=False, other_refuses=None, role=None, plan=None, - has_at=False) -> str: + has_at=False, other_cycle=None) -> str: """The key of one battery's "why" line (`home_words.why`), most urgent first. Pure, so every branch is tested without a controller.""" if not reading: @@ -712,6 +719,8 @@ def battery_why(*, modes_on, mode, off, reading, phase, shadow, running, return "refuses_give" if refused > 0 else "refuses_charge" if peak: return "peak" + if other_cycle: + return "other_cycle" if giving and other_refuses: return "other_refuses" if not modes_on: diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ac2962b..a610540 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -71,7 +71,7 @@ from .hass import HomeAssistant from .inverter import (LINK_STALE_S, UNIT_A, build_roster, roster_entries, roster_names) from .maintenance import ( - IDLE, POWER_MOVING, MaintConfig, Maintenance, MaintResult, + DRAIN, IDLE, POWER_MOVING, MaintConfig, Maintenance, MaintResult, arbitrate as maint_arbitrate, ) from .mqtt import (MODE_CONFIGS_KEY, MODE_LABELS, USE_OFF, USE_ON, @@ -948,6 +948,9 @@ class Controller: # [(pack name, why)] for packs that are due and waiting their turn. # Empty at a roster of one, where nothing can defer anything. self._maint_deferred = [] + # SAFETY-78: names of draining packs that cannot give power now, so + # the "waits" line is logged once, not every cycle. + self._drain_waits = set() # Set by amain() once the transport is built, so the status page can show # what only the transport knows (homewizard_local's unchanged_s). Stays # None when P1 is off, or under a transport that has no such counter. @@ -2161,7 +2164,8 @@ class Controller: headroom_w=self.arb_headroom_w, floor_pct=floor_pct, ceiling_pct=ceiling_pct, house_w=house, charging_now=was, blocked=self._charge_blocked_q == quarter, - done_charge=done_c, done_sell=done_s) + done_charge=done_c, done_sell=done_s, + draining=any(r.phase == DRAIN for r in maint_results or ())) # A charge the guard or the headroom stopped stays off this period. if was and self.mode_tick.action != modetrade.CHARGE and \ self.mode_tick.why in ("peak", "headroom"): @@ -2383,6 +2387,42 @@ class Controller: except Exception: # noqa: BLE001 _LOG.exception("Home Assistant command could not be handled") + def _drain_floor(self, claims, maint_results): + """SAFETY-78: the site `lo` for a pinned maintenance drain, or None. + + At N>=2 the drain pins its pack and the site target is split around + the pin. Below the pin a sibling would have to charge (opposite + directions, refused, 0 W, and the drain never moves). So the site + target may not go below what the pin places: the drained pack covers + the house up to its drain rate and exports the rest, as at N=1, and + a sibling only ever adds power in the same direction. At N=1 the + drain is the site SET itself, so nothing is filed. + A draining pack whose own limits leave it nothing to give (a refusal, + a stale link) adds no floor, and that is logged once. + """ + if len(self.inverters) < 2: + return None + live = set(self.live_units()) + floor, waits = 0.0, set() + for inv, res in zip(self.inverters, maint_results): + if res.phase != DRAIN or not res.owns_setpoint \ + or not (res.setpoint_w or 0.0) > 0.0: + continue + u = self.actuator_of("maintenance", inv) + b = pre_resolve([c for c in claims if c.actuator == u]) + p = (None if u not in live or b.contradiction + or b.pinned_by != "maintenance" else allocator.pin_w(b)) + if p is not None and p > 0.0: + floor += p + else: + waits.add(inv.name) + for name in sorted(waits - self._drain_waits): + self.log_event(f"maintenance: {name} cannot give power now, so " + f"its monthly cycle waits", + hint=messages.hint("maint_waits", unit=name)) + self._drain_waits = waits + return floor if floor > 0.0 else None + def _maint_stop_off(self, machine, now) -> None: """OPT-11: stop this battery's maintenance cycle because it is off.""" if machine.phase == IDLE: @@ -4091,6 +4131,13 @@ class Controller: _ctl.REFUSED, actuator=self.actuator_of("refused", inv))) + # --- SAFETY-78: a pinned drain is a floor under the site target ----- + # After every unit claim, so the floor is what the pin really places. + drain = self._drain_floor(claims, maint_results) + if drain is not None: + claims.append(Claim.limit("drain", P_MAINTENANCE, lo=drain, + reason="maintenance drain", + actuator=self.actuator_of("drain"))) # --- OPT-11 P3: the site trade, after every unit claim -------------- # Sized from what the batteries may place with their modes and hard # limits (the loop bound), so none is asked for watts it may not give. diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index 4445a60..c7bf2f7 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -929,6 +929,7 @@ HINTS = { "pack_mode": "{unit}: battery mode changed", "pack_sell": "{unit}: selling switched", "maint_off": "{unit}: maintenance stopped, the battery is switched off", + "maint_waits": "{unit} cannot give power now, so its monthly cycle waits", "mode_fault": "{unit}: battery mode ignored because of a software fault", } diff --git a/goodwe_controller/app/modetrade.py b/goodwe_controller/app/modetrade.py index 81fa61d..bf734b4 100644 --- a/goodwe_controller/app/modetrade.py +++ b/goodwe_controller/app/modetrade.py @@ -39,7 +39,9 @@ Rules that keep this safe (tests: test_modes_p3.py): * a battery out of a run (full, or at the floor) stays out until the run ends, so the ceiling and the floor do not re-arm within one run; * a battery that refuses a direction (SAFETY-52/73) takes no part in a - run in that direction: the refusal wins over the run. + run in that direction: the refusal wins over the run; + * no grid charge while another battery drains for its monthly cycle + (`draining`, SAFETY-78): it would charge against the drain. """ from dataclasses import dataclass @@ -118,7 +120,8 @@ def energy(packs, floor_pct, ceiling_pct, done_charge=(), done_sell=()): def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, headroom_w, floor_pct, ceiling_pct, house_w, charging_now=False, - blocked=False, done_charge=(), done_sell=()) -> Tick: + blocked=False, done_charge=(), done_sell=(), + draining=False) -> Tick: """This tick's ranges, roles and site ask. `runs` is the kept `priceruns.RunPlan` or None (no fresh prices). @@ -129,7 +132,8 @@ def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, `house_w` is the measured house (grid + batteries), or None. `charging_now` says last tick charged (then any headroom above 0 keeps it going); `blocked` that the guard or the headroom stopped a charge in - this 15-minute period. + this 15-minute period. `draining` says a battery drains for its + monthly cycle, so none may charge from the grid (why "cycle"). """ plan_on = runs is not None and runs.on in_cheap = plan_on and runs.cheap.holds(now) and runs.charge_useful() @@ -138,6 +142,8 @@ def decide(runs, now, packs, *, charge_ok, sell_ok, trade_why, price_now, why = None ch = chargers(packs, ceiling_pct, done_charge) if in_cheap else [] + if ch and draining: + ch, why = [], "cycle" charging = False if ch: need = 0.0 if charging_now else START_W diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 57d70c9..44fdda7 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -327,6 +327,7 @@ "leftover_alone": "No Solar first battery is on, so it gets solar first.", "covers_house": "It gives power to cover the house.", "other_refuses": "{name} refuses to give power, so this battery takes over.", + "other_cycle": "{name} is emptying for its monthly cycle. This one does not charge.", "grid_charge": "Prices are low, so it charges from the grid.", "rests_charge": "Another battery charges from the grid, so it rests.", "selling": "Prices are high, so it sells to the grid.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 5690fc7..90cb2fc 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -269,6 +269,7 @@ "leftover_alone": "Geen batterij met Eerst zonne-energie staat aan, dus zij krijgt eerst zonne-energie.", "covers_house": "Ze levert stroom om het huis te dekken.", "other_refuses": "{name} weigert te leveren, dus deze batterij neemt het over.", + "other_cycle": "{name} loopt leeg voor haar maandelijkse cyclus. Deze laadt niet.", "grid_charge": "De prijs is laag, dus ze laadt van het net.", "rests_charge": "Een andere batterij laadt van het net, dus deze rust.", "selling": "De prijs is hoog, dus ze verkoopt aan het net.", diff --git a/goodwe_controller/test_arbiter.py b/goodwe_controller/test_arbiter.py index 071fb64..0df5eac 100644 --- a/goodwe_controller/test_arbiter.py +++ b/goodwe_controller/test_arbiter.py @@ -149,7 +149,7 @@ check("...and `source` is still the first positional argument, which is what " Claim.limit("device", P_SAFETY, -1, 1).source == "device") print() -print("ARB-03 2. the split: thirteen sources, each classified where it is BUILT") +print("ARB-03 2. the split: fourteen sources, each classified where it is BUILT") # The classification is graded against what each claim is ABOUT, restated here # so that the table in arbiter.py and the expectation in a test are not the same # sentence read twice. test_peakguard.py part 10f pins this set against main.py's @@ -171,6 +171,10 @@ SITE_SOURCES = { "offending number is the SITE target, which no single " "inverter owns - parking one of them would leave the rest " "pushing the same way with the guard satisfied", + # SAFETY-78. + "drain": "the site target may not go below a pinned maintenance " + "drain, or a sibling would charge against it. Filed at N>1 " + "only", } UNIT_SOURCES = { "device": "one inverter's own reported min/max rating", @@ -202,9 +206,9 @@ for _src, _why in sorted(SITE_SOURCES.items()): print(f" site {_src:<11} {_why}") for _src, _why in sorted(UNIT_SOURCES.items()): print(f" unit {_src:<11} {_why}") -check("all THIRTEEN claim sources are classified, and only those thirteen", +check("all FOURTEEN claim sources are classified, and only those fourteen", set(CLAIM_SCOPE) == set(SITE_SOURCES) | set(UNIT_SOURCES)) -check("the six that are about the GRID CONNECTION are site claims", +check("the seven that are about the GRID CONNECTION are site claims", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == set(SITE_SOURCES)) check("the seven that are about a PACK, a DEVICE or one write are per-inverter", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == set(UNIT_SOURCES)) @@ -225,8 +229,8 @@ check("with one inverter every source routes to the site, per-inverter ones " check("...and with none configured at all, likewise", all(actuator_for(s, "inverter-a", ()) == ACTUATOR_SITE for s in CLAIM_SCOPE)) check("with TWO the identity breaks and the split becomes real: the seven " - "per-inverter sources route to the unit this controller drives, the six " - "site sources stay on the grid connection", + "per-inverter sources route to the unit this controller drives, the " + "seven site sources stay on the grid connection", {s: actuator_for(s, "inverter-a", TWO) for s in CLAIM_SCOPE} == {**{s: "inverter-a" for s in UNIT_SOURCES}, **{s: ACTUATOR_SITE for s in SITE_SOURCES}}) diff --git a/goodwe_controller/test_batteries_screen.py b/goodwe_controller/test_batteries_screen.py index cb457c1..2f51ce3 100644 --- a/goodwe_controller/test_batteries_screen.py +++ b/goodwe_controller/test_batteries_screen.py @@ -93,7 +93,8 @@ WANT = { "off": ("solar_first", "off"), "off_peak": ("peak", "off_peak"), "refusal": ("refuses_give", "other_refuses"), - "maint": ("cycle_mode", "leftover"), + # SAFETY-78: the other battery says why it does not charge. + "maint": ("cycle_mode", "other_cycle"), } # ============================================================================ # @@ -317,6 +318,14 @@ _cases = [ (dict(role="charge", refused=-1), "refuses_charge"), (dict(role="sell", peak=True), "peak"), (dict(role="hold", off=True), "off"), + # SAFETY-78: another battery drains for its monthly cycle. + (dict(other_cycle="A"), "other_cycle"), + (dict(other_cycle="A", modes_on=False, giving=True), "other_cycle"), + (dict(other_cycle="A", mode=packmode.CHEAP_HOURS, role="charge"), + "other_cycle"), + (dict(other_cycle="A", peak=True), "peak"), + (dict(other_cycle="A", refused=-1), "refuses_charge"), + (dict(other_cycle="A", off=True), "off"), ] _wrong = [(kw, want, why(**kw)) for kw, want in _cases if why(**kw) != want] print(f" {_wrong}") diff --git a/goodwe_controller/test_maintenance.py b/goodwe_controller/test_maintenance.py index 2f492b6..b090c36 100644 --- a/goodwe_controller/test_maintenance.py +++ b/goodwe_controller/test_maintenance.py @@ -1363,50 +1363,24 @@ check("...while the second pack's write reaches only its own namespace", # --------------------------------------------------------------------------- # print() -print("12. RECORDED, NOT FIXED: the site loop still contradicts a drain at N>=2") +print("12. FIXED (SAFETY-78): a drain at N>=2 no longer parks the site") -# ⚠️ THIS IS A DEFECT THIS CARD FOUND AND DELIBERATELY DID NOT FIX, AND IT IS -# WRITTEN DOWN AS A RUNNING CHECK RATHER THAN AS A COMMENT SO IT CANNOT BE -# FORGOTTEN OR QUIETLY "FIXED" BY A TUNING CHANGE. -# -# WHAT IT IS. The maintenance SET is a per-unit claim and PINS its pack. The -# loop's target is a SITE claim. When the site target is BELOW the pin - a -# drain of 2000 W while the house is importing less than that, which is most of -# a night - the only split that sums to the site target asks the sibling to -# CHARGE while the maintained pack DISCHARGES, and `allocator.plan()` refuses it -# by name as circulating power. The refusal is correct and fails safe: the whole -# site goes to 0 W with an ARBITER line in the action log. -# -# WHY IT IS NOT THIS CARD'S. It is PRE-EXISTING - measured on release/1.0 at -# 2d025ee, where the same drain filed on `inverters[0]` produces the identical -# refusal with the two unit names swapped - and fixing it means changing what -# the site loop's target MEANS while a unit is pinned (regulate the meter using -# only the unpinned packs), which is loop and allocator territory, not -# maintenance's. MAINT-05 moves which pack is pinned and nothing else about it. -# -# ⚠️ AND THE CONSEQUENCE AN OPERATOR WOULD SEE IS A MISDIAGNOSIS, WHICH IS WHY -# IT MATTERS ENOUGH TO PIN. The pack is held at 0 W while its FSM believes it is -# draining, so after 12 h the DRAIN timeout fires and reports "drain stuck" - -# §12's words for "the battery is not following commands, a fault". The battery -# is fine; the site refused to allocate. That is the same class of wrong story -# this card's own notes warn about for the deferral. +# This section used to pin the defect: with the house below the drain, the +# only split summing to the site target asked the sibling to CHARGE, the +# allocator refused it and the site sat at 0 W while the FSM believed it was +# draining. SAFETY-78 files a site `drain` floor at the pin, so the sibling +# only ever adds power the same way. test_safety78.py grades it in full. _cX, _ = controller(TWO_OPTS, grid=0.0) _cX.maints[1].force_start(_now) one_cycle(_cX) print(f" house at 0 W, B draining 2000 W -> reason {_cX.reason!r}; " f"{_cX.allocation.explain()}") -check("a maintenance drain BELOW the site target is refused by the allocator " - "and the site parks at 0 W - recorded here so the next card can find it, " - "not asserted as desirable", - _cX.target == 0.0 and _cX.allocation.refused - and "circulating power" in _cX.allocation.explain()) -check("...and the pack that is supposedly draining is commanded 0 W, so its " - "12 h DRAIN timeout would eventually report 'drain stuck' - a fault " - "message about a healthy battery", - _cX.maints[1].phase == DRAIN and _cX.inverters[1].target == 0.0) -check("...while the SAME site with the house importing more than the drain " - "allocates cleanly, which is what makes this a CONDITION rather than " - "'maintenance does not work at two inverters'", +check("a maintenance drain above the loop's site target is allocated, not " + "refused: B drains at its rate and A is held at 0 W", + _cX.allocation.refused is None and _cX.target == 2000.0 + and _cX.inverters[1].target == 2000.0 and _cX.inverters[0].target == 0.0) +check("...and the SAME site with the house importing more than the drain " + "still allocates cleanly", _cB.allocation.refused is None and _cB.inverters[1].target == 2000.0) diff --git a/goodwe_controller/test_modes.py b/goodwe_controller/test_modes.py index 15280a4..a4e4fc8 100644 --- a/goodwe_controller/test_modes.py +++ b/goodwe_controller/test_modes.py @@ -112,6 +112,11 @@ try: finally: _undo_c() _undo_b() +# SAFETY-78 changes n2_maint ON PURPOSE: on a5dddad and 5a4cdc2 its N=2 drain +# was refused on 392 of 540 cycles (site at 0 W); now none is. Printed on the +# SAFETY-78 tree the same way. Every other digest is unchanged. +SAFETY78_N2_MAINT = \ + "cd4d9cb5b7e29ff4ab4fe65dab5106683d8a599f09323fbdee4018ad9b28fcd1" for k in A5DDDAD: print(f" {k:7} {'same' if _now[k] == A5DDDAD[k] else 'DIFFERS'} " f"{_now[k][:16]}") @@ -119,8 +124,13 @@ check("⭐ at N=1 and N=2, with the option absent and with it false, every " "command, reason and allocation record over 540 cycles each is " "byte-identical to a5dddad (house steps, a solar surplus, a battery " "at its cut-out level, at N=2 a refusal with probes, both batteries " - "due for maintenance), and so is the arbiter on 6000 claim lists", - _now == A5DDDAD) + "due for maintenance; n2_maint apart, below), and so is the arbiter " + "on 6000 claim lists", + {k: v for k, v in _now.items() if k != "n2_maint"} + == {k: v for k, v in A5DDDAD.items() if k != "n2_maint"}) +check("...and n2_maint is the SAFETY-78 digest: the N=2 drain that a5dddad " + "refused on 392 of 540 cycles now runs (test_safety78.py)", + _now["n2_maint"] == SAFETY78_N2_MAINT != A5DDDAD["n2_maint"]) check("...and no cycle in those runs filed a `mode` claim or handed " "`compute()` a bound", _claims and not any(c.source == "mode" for cl in _claims for c in cl) diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 909ccfe..22683d6 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2674,9 +2674,15 @@ check("...and so does the persistent notification, which outlives the page and " # cycles with the floor, and part 10 at N=1. The sweeps below never reach it: # their fixtures leave battery modes off, so they still see {device, # supervised, loop}. DECISIONS/OPT-11-battery-modes.md. +# ⚠️ SAFETY-78 ADDED `drain`, AND IT IS NOT THE DEFERRED RESERVE. It is a +# site `lo` at P_MAINTENANCE, filed only at N>=2 while a pack's maintenance +# drain is pinned, equal to what that pin places. It is not conditioned on a +# state of charge, it never closes discharge (a `lo`, not a `hi`), and it is +# never filed at N=1, so the sweeps below still see {device, supervised, +# loop}. DECISIONS/SAFETY-78-drain-at-two.md. CLAIM_SOURCES = {"device", "supervised", "failsafe", "safety", "peak", "arbitrage", "maintenance", "loop", "circulation", - "sign_site", "pack", "refused", "mode"} + "sign_site", "pack", "refused", "mode", "drain"} # The two appends that file a claim BUILT ELSEWHERE in the method. Named here so # that a THIRD such indirection reads as an unrecognised append rather than as a # silent gap in the scan. @@ -2718,7 +2724,7 @@ check("every `claims.append(...)` in main.py's cycle is one this scan can READ " "- a claim filed through a shape it cannot parse has to fail here rather " "than be counted as nothing, which is how a scan like this goes quietly " "vacuous", len(_appends) >= 10 and None not in _filed) -check("...and the sources that cycle can file are EXACTLY these THIRTEEN. THIS " +check("...and the sources that cycle can file are EXACTLY these FOURTEEN. THIS " "is what makes part 10 a tripwire: replay_loop() hand-builds the claim " "list, so it cannot see a claim main.py adds - and a loop-side SoC " "reserve is a new source. Filing one takes this line red on the line it " @@ -2858,7 +2864,7 @@ print(" site: " + ", ".join(sorted(s for s, v in CLAIM_SCOPE.items() + " | per-inverter: " + ", ".join(sorted(s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT))) check("...and the split is the one ARB-03 argued, with SAFETY-31's and " - "SAFETY-30's and OPT-09's additions: the six about the GRID CONNECTION " + "SAFETY-30's, OPT-09's and SAFETY-78's additions: the seven about the GRID CONNECTION " "are site claims and the five about a pack, a device or one write are " "per-inverter. `circulation` is a site claim because its quantity is " "defined over the roster and is identically zero for any one unit; " @@ -2867,7 +2873,8 @@ check("...and the split is the one ARB-03 argued, with SAFETY-31's and " "per-inverter because since SAFETY-30 it grades one unit's command " "against that unit's OWN measured power", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} - == {"loop", "peak", "arbitrage", "safety", "circulation", "sign_site"} + == {"loop", "peak", "arbitrage", "safety", "circulation", "sign_site", + "drain"} and {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == {"device", "supervised", "failsafe", "maintenance", "pack", "refused", "mode"}) @@ -2971,7 +2978,8 @@ check("⚠️ AND THIS IS THE BREAKING HALF. Give the same Controller a second " "mode": "inverter-a", "loop": ACTUATOR_SITE, "peak": ACTUATOR_SITE, "arbitrage": ACTUATOR_SITE, "safety": ACTUATOR_SITE, - "circulation": ACTUATOR_SITE, "sign_site": ACTUATOR_SITE}) + "circulation": ACTUATOR_SITE, "sign_site": ACTUATOR_SITE, + "drain": ACTUATOR_SITE}) check("...and the roster it was restored to is the shipped one, so nothing " "below inherits a two-inverter Controller", c_src.units == (app_main.UNIT_A,) and len(c_src.inverters) == 1) @@ -3050,13 +3058,13 @@ _unit_sources_unrouted = [ if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT and "," not in r[1]] print(f" {len(_direct)} direct appends, each read at its own line: " + ", ".join(f"main.py:{ln} {s} -> {a}" for s, a, ln in _routing)) -check("all FOURTEEN of `Controller.cycle()`'s DIRECT appends route through " +check("all FIFTEEN of `Controller.cycle()`'s DIRECT appends route through " "`self.actuator_of(<string literal>)`, so this scan can read the routing " "of EVERY one of them. An append that computed its actuator, or omitted " "the argument, or hand-wrote a string, fails HERE rather than being " "silently skipped - which is how a scan like this goes quietly vacuous, " "and 10f is in this file because that already happened once", - len(_direct) == 14 + len(_direct) == 15 and all(a is not None and a.startswith("self.actuator_of('") for _s, a, _ln in _routing)) check("⚠️ AND AT EVERY ONE OF THE ELEVEN THE LITERAL IT ROUTES THROUGH IS THE " @@ -3073,7 +3081,7 @@ check("⚠️ AND EVERY PER-INVERTER APPEND NAMES THE INVERTER IT IS ABOUT. " "site-scoped sources and is the whole defect for a per-inverter one: a " "`device` limit built inside the roster loop and routed without `inv` " "files inverter B's rating on inverter A, where it binds the wrong " - "share. Nine of the fourteen appends are SCOPE_UNIT - `device`, " + "share. Nine of the fifteen appends are SCOPE_UNIT - `device`, " "`supervised`, `failsafe`, maintenance's two, OPT-09's `pack`, " "SAFETY-73's two `refused` and OPT-11's `mode` - and all nine pass one. " "SAFETY-30's `sign_site` is deliberately NOT one of them: it is filed on " @@ -3090,8 +3098,8 @@ check("...and the only appends this pin does NOT reach are the two that file a " "arbitrage.claim() by test_arbitrage.py", sorted(_indirect) == sorted(CLAIM_BUILDERS) and len(_direct) + len(_indirect) == len(_appends)) -check("...and between them the sixteen appends account for exactly the " - "thirteen " +check("...and between them the seventeen appends account for exactly the " + "fourteen " "sources 10f pins, so the routing pin and the source set are one scan " "and neither can drift from the other", {s for s, _a, _ln in _routing} | set(CLAIM_BUILDERS.values()) @@ -3152,7 +3160,7 @@ check("...and naming those three is not an accident of this fixture but the " {c.source for c in _cl2} == CLAIM_SOURCES - {"failsafe", "safety", "maintenance", "peak", "arbitrage", "circulation", "sign_site", - "refused", "mode"}) + "refused", "mode", "drain"}) # ⚠️ AND NOW THE HALF THAT WAS EVIDENCE-SHAPED AND OBSERVED NOTHING. The three # checks above grade WHICH ACTUATOR each claim lands on. They say nothing about # WHOSE NUMBERS the bound is built from - and those are two different defects diff --git a/goodwe_controller/test_safety78.py b/goodwe_controller/test_safety78.py new file mode 100644 index 0000000..cd10119 --- /dev/null +++ b/goodwe_controller/test_safety78.py @@ -0,0 +1,343 @@ +"""Runnable check for SAFETY-78: a maintenance drain at N=2 no longer stalls. +`python3 test_safety78.py` + +At two inverters the drain pins its battery at the drain rate and the site +target is split around the pin. Below the pin the other battery had to charge, +the allocator refused the opposite directions, the site sat at 0 W and the +drain never moved (OPT-11 P1 F1, UX-13 P3 check 5, OPT-11 P3 F4). Now a site +`lo` (`drain`, P_MAINTENANCE) keeps the site target at or above what the pin +places. Drives the REAL Controller (tools/opt11_identity.py's harness). +DECISIONS/SAFETY-78-drain-at-two.md has the record. + +1. N=2, house below, at and above the drain rate, a solar surplus: the drain + runs at its rate, no opposite split, no refusal, no log spam, and it ends. +2. A drain that cannot give power waits with ONE log line. +3. Battery modes on, a Cheap hours battery in a cheap run during the drain: + no grid charge, and its card says why. +4. The peak guard binds during a drain, and the arbiter's order holds. +5. N=1 is byte-identical to release/1.0 5a4cdc2, and the harness bites. +""" + +import functools +import logging +import os +import sys +import tempfile + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11_identity as rig # noqa: E402 +import opt11p3_identity as p3 # noqa: E402 +import safety78_identity as s78 # noqa: E402 +import safety79_identity as s79 # noqa: E402 +from app import arbitrage, homeview, packmode # noqa: E402 +from app.arbiter import (Claim, P_ARBITRAGE, P_LOOP, P_MAINTENANCE, # noqa + P_PEAK, P_SAFETY, resolve) +from app.main import Controller # noqa: E402 +from app.maintenance import CHARGE, DRAIN # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +M = {"maintenance_enabled": True, "maintenance_start_hour": 11} +A, B = "inverter-a", "inverter-b" + + +def cmd(r): + return dict(r[2]) + + +def refused(rows): + return sum(1 for r in rows if r[7] and "REFUSED" in r[7]) + + +def opposite(rows): + return sum(1 for r in rows if cmd(r)["a"] * cmd(r)["b"] < 0) + + +def drain_run(house, dur=600.0, soc=lambda u, t: 50.0, cut=None, **kw): + return rig.run(2, extra=dict(M, **kw.pop("extra", {})), dur=dur, + load=lambda t: house(t) if callable(house) else house, + soc=soc, cut=cut or (lambda u, t: False), **kw) + + +def with_peak_db(fn): + """Run `fn()` with the Controller's peak store in a temporary file.""" + db = os.path.join(tempfile.mkdtemp(prefix="s78t-"), "tariff.db") + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + try: + return fn() + finally: + rig.Controller = real + + +# ============================================================================ # +print("1. N=2: the drain runs whatever the house uses") +RUNS = {h: drain_run(h) for h in (1200.0, 2000.0, 3000.0, -1500.0)} +for h, (rows, c) in RUNS.items(): + print(f" house {h:+.0f} W: last A {cmd(rows[-1])['a']:+.0f} W, B " + f"{cmd(rows[-1])['b']:+.0f} W, grid {h - sum(cmd(rows[-1]).values()):+.0f}" + f" W; {rows[-1][6]}; refusals {refused(rows)}") +check("⭐ below, at and above the drain rate and under a solar surplus, " + "battery A is commanded its 2000 W drain on EVERY cycle, so the drain " + "moves (it used to sit at 0 W from the first cycle)", + all(cmd(r)["a"] == 2000.0 for rows, _c in RUNS.values() for r in rows) + and all(c.maints[0].phase == DRAIN for _r, c in RUNS.values())) +check("⭐ no cycle splits the site both ways and the allocator refuses " + "nothing: battery B never charges while A drains", + all(opposite(rows) == 0 and refused(rows) == 0 + and all(cmd(r)["b"] >= 0.0 for r in rows) + for rows, _c in RUNS.values())) +check("...and nothing is logged per cycle: no ARBITER line in the action log", + not any("ARBITER" in e for _r, c in RUNS.values() for e in c.events)) +_r3 = RUNS[3000.0][0] +check("above the drain rate, B covers the rest of the house in the SAME " + "direction and the grid settles at the loop's aim", + 990.0 <= cmd(_r3[-1])["b"] <= 1030.0 + and abs(3000.0 - sum(cmd(_r3[-1]).values()) + 10.0) <= 30.0) +check("at or below the drain rate, B is held at 0 W and A exports the rest, " + "as the drain does at one inverter ('exports the surplus')", + all(cmd(RUNS[h][0][-1])["b"] == 0.0 for h in (1200.0, 2000.0, -1500.0)) + and all(RUNS[h][0][-1][6].startswith("loop -> 2000 W") + for h in (1200.0, 2000.0, -1500.0))) +check("...and where the loop alone would ask less, the Why names the drain", + "limited by drain" in RUNS[1200.0][0][-1][6]) + +# The drain ends: A's level falls to the floor, and the cycle moves on. +_end_rows, _end = drain_run(1200.0, dur=500.0, + soc=lambda u, t: max(5.0, 50.0 - t / 10.0) + if u == "a" else 50.0) +check("⭐ and the drain ENDS: A reaches the 11 % floor and the cycle moves " + "to its charge phase, with no refusal on the way", + _end.maints[0].phase == CHARGE and refused(_end_rows) == 0) + +# The check bites: without the floor, the same site stalls as it did. +_real = Controller._drain_floor +Controller._drain_floor = lambda self, claims, results: None +try: + _bite, _bc = drain_run(1200.0, dur=120.0) +finally: + Controller._drain_floor = _real +print(f" without the drain floor: refusals {refused(_bite)}/{len(_bite)}, " + f"last A {cmd(_bite[-1])['a']:+.0f} W") +check("non-vacuous: with the floor taken out, the same fixture refuses every " + "cycle and parks A at 0 W (the reported defect)", + refused(_bite) == len(_bite) and cmd(_bite[-1])["a"] == 0.0 + and any("ARBITER" in e for e in _bc.events)) + +# ============================================================================ # +print("\n2. a drain that cannot give power waits, with one log line") +_w_rows, _w = drain_run(1500.0, cut=lambda u, t: u == "a") +_waits = [e for e in _w.events if "cannot give power now" in e] +print(f" A refuses to give: {_waits}; last {_w_rows[-1][2]}") +check("⭐ A refuses to give power (SAFETY-73): the cycle waits, the line is " + "logged ONCE over 120 cycles, and nothing is refused", + len(_waits) == 1 and _w.inverters[0].refused == 1 + and refused(_w_rows) == 0 and _w.maints[0].phase == DRAIN) +check("...and B covers the house on its own meanwhile", + 1400.0 <= cmd(_w_rows[-1])["b"] <= 1600.0) + + +def reject_a(c, t): + """Every write to A is rejected, so A's link goes stale (not live).""" + if not getattr(c.hass, "_rej", False): + real = c.hass.set_number + + async def set_number(e, v): + return False if e == "number.sp_a" else await real(e, v) + c.hass.set_number, c.hass._rej = set_number, True + + +_l_rows, _l = drain_run(1500.0, dur=400.0, before=reject_a) +print(f" A's writes rejected: {_l_rows[-1][2]}, {_l_rows[-1][7][-40:]}") +check("⭐ a draining battery that is dropped (stale link) adds no floor: B " + "covers the 1500 W house, not the 2000 W drain rate, and the wait is " + "logged once", + "dropped inverter-a" in _l_rows[-1][7] + and cmd(_l_rows[-1])["b"] == 1500.0 + and sum("cannot give power now" in e for e in _l.events) == 1) + +# ============================================================================ # +print("\n3. battery modes on: no grid charge during the drain") + + +def cheap_b(): + s = rig._Store() + s.data[unit_key(A, packmode.MODE_KEY)] = packmode.SOLAR_FIRST + s.data[unit_key(B, packmode.MODE_KEY)] = packmode.CHEAP_HOURS + return s + + +def modes_run(maint): + extra = dict(s79.P1, **p3.ARB, battery_modes_enabled=True, + **(M if maint else {})) + ticks = [] + + def on_cycle(c, t): + ticks.append(c.mode_tick) + rows, c = with_peak_db(lambda: rig.run( + 2, extra=extra, dur=1800.0, load=lambda t: 800.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False, before=p3._feed, + on_cycle=on_cycle, store=cheap_b())) + cheap = [(r, k) for r, k in zip(rows, ticks) if 900.0 <= r[0] < 1800.0] + return rows, c, cheap + + +_base_rows, _base_c, _base_cheap = modes_run(False) +_m_rows, _m_c, _m_cheap = modes_run(True) +check("baseline: with no drain, B (Cheap hours only) charges from the grid " + "in the cheap run, so the fixture reaches the charge", + any(cmd(r)["b"] < 0.0 for r, _k in _base_cheap) + and all(k.roles[B] == "charge" for _r, k in _base_cheap)) +check("⭐ with A draining, B never charges in that run: its role is not " + "'charge', no trade is filed, and the modes say why ('cycle')", + all(cmd(r)["b"] >= 0.0 and k.roles[B] != "charge" and k.action is None + and k.why == "cycle" for r, k in _m_cheap) + and _m_c.maints[0].phase == DRAIN) +check("...and the drain runs through the run: A at 2000 W, nothing refused", + all(cmd(r)["a"] == 2000.0 for r in _m_rows) and refused(_m_rows) == 0) + +# Battery modes off: the site trade (`arbitrage.decide()`) buys in the cheap +# period. It is a site SET at P_ARBITRAGE, below the drain floor. +_t_trades = [] +_t_rows, _t_c = with_peak_db(lambda: rig.run( + 2, extra=dict(s79.P1, **p3.ARB, **M), dur=1800.0, load=lambda t: 800.0, + soc=lambda u, t: 50.0, cut=lambda u, t: False, before=p3._feed, + on_cycle=lambda c, t: _t_trades.append(c.arb and c.arb.action))) +print(f" modes off, trades seen: {sorted({str(a) for a in _t_trades})}") +check("⭐ battery modes off: the site trade still asks to buy in the cheap " + "period, and the drain floor keeps it from charging B against the drain: " + "A drains at 2000 W, B never charges, nothing is refused", + arbitrage.CHARGE in _t_trades + and all(cmd(r)["a"] == 2000.0 and cmd(r)["b"] >= 0.0 for r in _t_rows) + and refused(_t_rows) == 0) +_cards = homeview.battery_rows(_m_c, False, True) +print(f" cards: {[(b['name'], b['now'], b['why']) for b in _cards]}") +check("⭐ B's card tells the truth: it names the draining battery and says " + "it does not charge (it said 'charges from the grid' while resting)", + _cards[1]["why_key"] == "other_cycle" and A in _cards[1]["why"] + and _cards[0]["why_key"] == "cycle_mode") + +# ============================================================================ # +print("\n4. the peak guard during a drain, and the order of the claims") + + +def off_b(): + s = rig._Store() + s.data[unit_key(B, packmode.USE_KEY)] = False + return s + + +_p_rows, _p = with_peak_db(lambda: rig.run( + 2, extra=dict(s79.P1, battery_modes_enabled=True, **M), dur=600.0, + load=lambda t: 6000.0, soc=lambda u, t: 60.0, cut=lambda u, t: False, + before=s79._feed, store=off_b())) +print(f" house 6000 W, limit {s79.CAP_W} W, B Off: {_p_rows[-1][2]}, " + f"{_p_rows[-1][6]}") +check("⭐ the peak guard binds during the drain: the site goes above the " + "drain to the guard's floor, A keeps draining at 2000 W and B (Off) " + "gives only the shortfall, in the same direction", + _p.peak_guard.engaged and _p_rows[-1][1] >= _p.peak_guard.floor_w > 2000.0 + and all(cmd(r)["a"] == 2000.0 and cmd(r)["b"] >= 0.0 for r in _p_rows) + and "limited by peak" in _p_rows[-1][6] and refused(_p_rows) == 0) + + + +def blind_at(t0): + """The site meter stops answering at `t0`: a safety SET at P_SAFETY.""" + def before(c, t): + if t >= t0 and not getattr(c.hass, "_blind", False): + real = c.hass.number + + async def number(e, invert=False): + return None if e == "sensor.grid" else await real(e, invert) + c.hass.number, c.hass._blind = number, True + return before + + +_s_rows, _s = drain_run(3000.0, dur=300.0, before=blind_at(150.0)) +print(f" meter lost at 150 s: {_s_rows[-1][2]}, {_s_rows[-1][6]}") +check("⭐ a safety stop outranks the drain at N=2: with the meter gone the " + "safety SET parks both batteries at 0 W, and the drain ran before", + cmd(_s_rows[20])["a"] == 2000.0 + and all(cmd(r) == {"a": 0.0, "b": 0.0} for r in _s_rows if r[0] >= 175.0) + and _s_rows[-1][6].startswith("safety -> 0 W")) + +UNITS = (A, B) +_drain = [Claim.set("maintenance", P_MAINTENANCE, 2000.0, "drain", actuator=A), + Claim.limit("drain", P_MAINTENANCE, lo=2000.0, reason="drain")] +_order = { + "loop under the drain": ([Claim.set("loop", P_LOOP, 500.0)], 2000.0), + "a grid charge (trade)": ([Claim.set("arbitrage", P_ARBITRAGE, -2500.0)], + 2000.0), + "a sale bigger than the drain": ([Claim.set("arbitrage", P_ARBITRAGE, + 3000.0)], 3000.0), + "a peak floor above the drain": ([Claim.set("loop", P_LOOP, 500.0), + Claim.limit("peak", P_PEAK, lo=3500.0)], + 3500.0), + "a safety stop": ([Claim.set("loop", P_LOOP, 500.0), + Claim.set("safety", P_SAFETY, 0.0, "stopped")], 0.0), +} +_got = {} +for k, (extra, want) in _order.items(): + r = resolve(_drain + extra, units=UNITS) + _got[k] = (r.target_w, dict(r.shares), r.allocated) + print(f" {k}: target {r.target_w:+.0f} W, shares {dict(r.shares)}") +check("⭐ the order holds: a safety stop parks everything; the peak floor " + "above the drain wins; a sale above it runs; a grid charge and the " + "loop below it are lifted to it; never an opposite split", + all(_got[k][0] == want and _got[k][2] + and not (min(_got[k][1].values()) < 0 < max(_got[k][1].values())) + for k, (_e, want) in _order.items()) + and _got["a safety stop"][1] == {A: 0, B: 0} + and _got["a grid charge (trade)"][1] == {A: 2000, B: 0}) + +# ============================================================================ # +print("\n5. N=1: byte-identical to release/1.0 5a4cdc2") +# Printed by `python3 tools/safety78_identity.py` on release/1.0 5a4cdc2 (the +# same file copied in, nothing else changed), goodwe-addon-checks:1, +# 2026-09-29. 480 cycles each, draining throughout, every claim and the +# newest action-log line hashed. +AT_5A4CDC2 = { + "n1_drain": + "55fcfc4a0b9251746f315cfdea607a33640d3a81faf6604c4718a04bbc7dd776", + "n1_drain_modes": + "93867eb4ee4132b47c030668bd7f07587a353bced2461524e09421125c3c4edf", +} +_now = s78.digests() +for k in AT_5A4CDC2: + print(f" {k} {'same' if _now[k] == AT_5A4CDC2[k] else 'DIFFERS'} " + f"{_now[k][:16]}") +check("⭐ at one inverter a drain under a house below, at and above its " + "rate, a surplus and a load over the peak limit, with battery modes " + "off and on, is byte-identical to 5a4cdc2: commands, reasons, roles, " + "trades and every claim", + _now == AT_5A4CDC2) +Controller._drain_floor = lambda self, claims, results: ( + 2000.0 if any(r.phase == DRAIN for r in results) else None) +try: + _leak = s78.digest(s78.run(**s78.SCENARIOS["n1_drain"], dur=60.0)[0]) + _same = s78.digest(s78.run(**s78.SCENARIOS["n1_drain"], dur=60.0)[0]) +finally: + Controller._drain_floor = _real +_ref = s78.digest(s78.run(**s78.SCENARIOS["n1_drain"], dur=60.0)[0]) +check("non-vacuous: filing the drain floor at N=1 (which moves no watt " + "there) moves the digest, because the harness hashes the claims", + _leak != _ref and _leak == _same) + +print() +if fails: + print(f"{len(fails)} FAILED: {', '.join(fails)}") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/tools/safety78_identity.py b/goodwe_controller/tools/safety78_identity.py new file mode 100644 index 0000000..0304829 --- /dev/null +++ b/goodwe_controller/tools/safety78_identity.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +"""SAFETY-78: at one inverter, is a maintenance drain byte-identical to before? + + python3 tools/safety78_identity.py # prints one digest per scenario + +tools/safety79_identity.py's harness (the REAL Controller on a P1 meter, so +the peak guard runs) with the battery draining for its monthly cycle from the +first cycle, under a house below, at and above the drain rate, a solar +surplus and a load over the peak limit. Each row hashes safety79's fields, +the modes' roles and the trade, the action log's newest line, and every claim +main.py hands `resolve()`, so a claim or a log line added at N=1 that changes +no watt still moves the digest. The `_modes` scenarios run battery modes on, +Cheap hours only, over opt11p3_identity's prices. Uses only the API release/1.0 5a4cdc2 has, so the same file runs on +both trees; test_safety78.py part 5 holds this tree to the digests printed +there. +""" + +import functools +import hashlib +import os +import sys +import tempfile + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +import opt11p3_identity as p3 # noqa: E402 +import safety79_identity as s79 # noqa: E402 +import app.main as m # noqa: E402 +from app import packmode # noqa: E402 +from app.store import unit_key # noqa: E402 + +DUR = 2400.0 +DRAIN = {"maintenance_enabled": True, "maintenance_start_hour": 11} + + +def load(t): + """Below the 2000 W drain, at it, above it, a surplus, over the limit.""" + k = int(t // 480) + return (1200.0, 2000.0, 3000.0, -1500.0, 6000.0)[min(k, 4)] + + +def store_cheap(n): + s = rig._Store() + for u in ("inverter-a", "inverter-b")[:n]: + s.data[unit_key(u, packmode.MODE_KEY)] = packmode.CHEAP_HOURS + return s + + +SCENARIOS = { + "n1_drain": dict(n=1), + "n1_drain_modes": dict(n=1, modes=True), +} + + +def run(n, *, modes=False, dur=DUR): + extra = dict(s79.P1, **DRAIN) + if modes: + extra.update(p3.ARB, battery_modes_enabled=True) + seen, extra_rows = [], [] + real_resolve = m.resolve + + def spy(claims, **kw): + seen.append(tuple((c.source, c.priority, c.kind, c.value, c.lo, c.hi, + c.reason, c.actuator) for c in claims)) + return real_resolve(claims, **kw) + + def on_cycle(c, t): + g, tick, a = c.peak_guard, c.mode_tick, c.arb + extra_rows.append(( + seen[-1] if seen else None, + None if g is None else (g.engaged, g.floor_w, g.reason), + None if tick is None else (tuple(sorted(tick.roles.items())), + tick.action, tick.why), + None if a is None else (a.action, a.power_w, a.reason), + [mm.phase for mm in c.maints], + len(c.events), c.events[0] if c.events else None)) + db = os.path.join(tempfile.mkdtemp(prefix="s78-"), "tariff.db") + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + m.resolve = spy + try: + rows, c = rig.run(n, extra=extra, dur=dur, load=load, soc=s79.soc, + cut=lambda u, t: False, + before=p3._feed if modes else s79._feed, + on_cycle=on_cycle, + store=store_cheap(n) if modes else None) + finally: + rig.Controller = real + m.resolve = real_resolve + return [r + (x,) for r, x in zip(rows, extra_rows)], c + + +def digest(rows) -> str: + return hashlib.sha256(repr(rows).encode()).hexdigest() + + +def digests() -> dict: + return {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} + + +if __name__ == "__main__": + if "--summary" in sys.argv: + for k, v in SCENARIOS.items(): + rows = run(**v)[0] + print(f"{k}: {len(rows)} cycles, phases " + f"{sorted({str(r[-1][-1]) for r in rows})}, targets " + f"{sorted({r[1] for r in rows})[:6]}") + for k, v in digests().items(): + print(f"{k} {v}") -- 2.54.0 From 6eb67c0f9cb653027f60af62f458f6e3cb1b35a9 Mon Sep 17 00:00:00 2001 From: goodwe-agent <noreply@anthropic.com> Date: Tue, 29 Sep 2026 19:55:38 +0200 Subject: [PATCH 081/105] SAFETY-81: no false 'Load too high' alarms The alarm now also needs peakguard.load_too_high(): with the battery at full power, the quarter still ends more than 10 W over the real limit. The battery reading is the lower of this cycle's and the last, so a meter sample from before the battery's last increase is not counted twice. At most one alarm per quarter. Control outputs unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-81-load-too-high.md | 47 ++++ goodwe_controller/DOCS.md | 11 +- goodwe_controller/app/main.py | 31 ++- goodwe_controller/app/peakguard.py | 31 +++ goodwe_controller/test_safety81.py | 117 ++++++++++ goodwe_controller/tools/safety81_sim.py | 203 ++++++++++++++++++ 6 files changed, 433 insertions(+), 7 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md create mode 100644 goodwe_controller/test_safety81.py create mode 100644 goodwe_controller/tools/safety81_sim.py diff --git a/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md b/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md new file mode 100644 index 0000000..bb56bc2 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md @@ -0,0 +1,47 @@ +# SAFETY-81 — no false "Load too high for battery" alarms + +**Status: 2026-09-29, owner go for the card. The 10 W tolerance is this PR's choice, for review.** + +## Defect + +The SAFETY-79 test (SAFETY-79-test-report.md, F1/F2) saw 6 false alarms in 7. +The alarm fired whenever `decide()` clamped its floor to the rating +(`saturated`). Three things set that while the quarter landed on target: + +- **Double count.** `decide()` sizes from the held meter reading plus the + battery reading. When the meter sample predates the battery's last increase, + the increase is counted twice. It happens under noise, and at each quarter + start, where the battery is back while the held sample is still the spike. +- **The aim, not the cap.** `saturated` is graded against cap − margin, so at + margin 50 noise needs 50 W less to trip it (F2). +- **Last seconds.** The gain 900 / remaining turns a few W over the aim into + thousands of W wanted, with the battery far from its rating. + +## Decision + +The alarm needs `saturated` and `peakguard.load_too_high()`: with the battery +at full power from now on, the quarter still ends more than `ALARM_MISS_W` +(10 W) over the real limit (`ceiling_w`). That is the miss itself, without the +gain. The battery reading it uses is the lower of this cycle's and the last +one's. At most one alarm per quarter, because near the threshold the test +flickers with the meter. + +**Why 10 W:** at margin 0 the guard itself lands up to +5.7 W over (SAFETY-79 +test, check 5), and those misses are real but tiny; the alarm would fire in +the last second of most guarded quarters. The margin (default 50) is the fix +for them. Cost: a real miss of 10 W or less is not alarmed. + +**Cost:** a load that climbs slowly through the band between the aim and the +cap alarms when the quarter will end over the cap, not at the aim (10 s later +in `ramp6500`). A step overload alarms in the same cycle as before; a real +overload shows on the meter before the battery moves, so the lower reading +costs it nothing. A quarter already over that the battery cannot win back +still alarms (test_peakguard.py's saturated fixture). + +## Not changed: the 1 s spike itself + +The cycle after a quarter boundary and before the new quarter's first meter +sample still sees 0 s left, files no claim, and an Off battery drops to 0 W for +one cycle. That is the same edge tick as OPT-15 F1, so it is left to OPT-15. +Control is unchanged here: every command in `tools/safety81_sim.py` is +byte-identical to 5a4cdc2 (test_safety81.py part 1). diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 2da5da8..47386dc 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1739,7 +1739,8 @@ control action and goes to the action log and the status page. A *saturated* guard — asking for everything the inverter has while the quarter is still projected over — raises one notification (`goodwe_peak_saturated`), because that is the one state where the money will be spent and shedding load is the only -thing left that changes the bill. +thing left that changes the bill. SAFETY-81 keeps a 1 s meter spike, noise and +a quarter's last seconds from raising it: see `peakguard.load_too_high()`. **And it sizes a price-driven charge, not only a forced discharge (SAFETY-45).** The same arithmetic read the other way answers *"how hard may this site charge @@ -3211,9 +3212,11 @@ reason code `OUTPUT_CLAMP`. **Load too high for battery.** The capacity-peak guard (SAFETY-07) asks for everything the inverter can discharge and the running 15-minute average is still projected over the peak limit, so the month's billed peak -(capaciteitstarief) goes up. In shadow mode the guard's projection is made on a -plant that did not respond (SAFETY-47), and the text says so. See *The -capacity-peak guard*. +(capaciteitstarief) goes up. It fires only when, with the battery at full +power, the period will still end more than 10 W over the real limit (not the +margin's aim), and at most once per period (SAFETY-81). In shadow mode the +guard's projection is made on a plant that did not respond (SAFETY-47), and +the text says so. See *The capacity-peak guard*. **Battery stopped limiting the peak.** The peak guard may not discharge below `peak_soc_floor` (label “Peak reserve”, SAFETY-24). It also stops when the diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ac2962b..954cacc 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -922,6 +922,10 @@ class Controller: "peak_margin_w", peakguard.PEAK_OPTION_DEFAULTS["peak_margin_w"])) self._peak_engaged = False self._peak_saturated = False + # SAFETY-81: what the alarm is graded on, beside the guard's decision. + self._peak_proj = None + self._peak_batt_prev = None + self._peak_alarm_block = None self._peak_floor_limited = False self._maint_shape_suspended = False # OPT-11. Battery modes, off by default so an install that has not @@ -3712,8 +3716,10 @@ class Controller: # is not measured on that path, and the honest report is NOT COVERED - # the same answer, for the same reason, that the status page already # gives for SAFETY-18 on a transport that cannot see `unchanged_s`. + self._peak_proj = (None if not self.p1_enabled + else self.peak.project(self.p1.averager, now)) self.peak_guard = None if not self.p1_enabled else peakguard.decide( - self.peak.project(self.p1.averager, now), + self._peak_proj, # ⚠️ THE SITE SUM. The guard sizes a floor from what the battery is # ALREADY removing from the meter, and the meter sees every # inverter. One unit's power here would size the floor from a @@ -4816,15 +4822,34 @@ class Controller: available to it. That is the one state where the money is going to be spent and a human is the only remaining actuator. + SAFETY-81: `g.saturated` alone is not enough. It is graded against the + aim, and a 1 s meter spike, noise or the last seconds of a quarter set + it while the quarter lands on target; `peakguard.load_too_high()` must + agree too. The battery reading it gets is the lower of this cycle's and + the last one's - see there. + Edge-triggered, and de-asserting arms it again - the same shape as FreezeWatchdog's `evaluate()`, and for the same reason: one notification - per episode, not one per cycle. + per episode, not one per cycle. SAFETY-81: and at most one per quarter. """ g = self.peak_guard - saturated = bool(g is not None and g.saturated) + batt, prev = self.site_batt_w, self._peak_batt_prev + self._peak_batt_prev = batt + if batt is not None and prev is not None: + batt = min(float(batt), float(prev)) + saturated = bool( + g is not None and g.saturated and self._peak_proj is not None + and peakguard.load_too_high( + self._peak_proj, batt_w=batt, ceiling_w=g.ceiling_w, + achievable_w=self.site_rating_w)) was, self._peak_saturated = self._peak_saturated, saturated if not saturated or was: return + # SAFETY-81: at most once per quarter. Near its threshold the test + # above flickers with the meter, and each flicker would re-alarm. + if self._peak_proj.block_start == self._peak_alarm_block: + return + self._peak_alarm_block = self._peak_proj.block_start self.log_event("PEAK_GUARD_SATURATED - " + g.reason, hint=messages.hint("peak_saturated")) _LOG.error( diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index e21a7ac..15df274 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -866,6 +866,37 @@ def decide(projection, *, batt_w, cap_w, margin_w, reading, achievable_w, soc, if saturated else ""))) +# SAFETY-81. A quarter must end this many W over the real limit before +# "Load too high for battery" fires. Above the guard's own landing error at +# margin 0 (up to +5.7 W, SAFETY-79 test check 5), which margin 0 accepts. +ALARM_MISS_W = 10.0 + + +def load_too_high(projection, *, batt_w, ceiling_w, achievable_w) -> bool: + """SAFETY-81. May "Load too high for battery" fire? Only if, with the + battery at full power from now on, the quarter still ends more than + `ALARM_MISS_W` over the real limit (`ceiling_w`, not the aim). + + This is the miss itself, in W of the quarter average, so it does not have + `decide()`'s gain (900 / remaining): near a quarter's end that gain turns + a watt over the aim into thousands of W wanted. + + The load is the held meter reading plus `batt_w`. The caller passes the + lower of this cycle's and the last cycle's battery reading, so a meter + sample taken before the battery's last increase is not counted twice + (DECISIONS/SAFETY-81-load-too-high.md). A real overload shows on the meter + before the battery moves, so that filter costs it no cycle. + """ + remaining = QUARTER_S - float(projection.elapsed_s) + if batt_w is None or remaining <= 0.0: + return False + rest = float(projection.held_w) + float(batt_w) - float(achievable_w) + done_ws = (QUARTER_S * float(projection.projected_w) + - max(float(projection.held_w), 0.0) * remaining) + ends_w = (done_ws + max(rest, 0.0) * remaining) / QUARTER_S + return ends_w - float(ceiling_w) > ALARM_MISS_W + + def charge_headroom_w(decision) -> float | None: """SAFETY-45. The hardest this SITE may charge without putting the billed quarter over the ceiling, in W, positive - or None when nothing measured it. diff --git a/goodwe_controller/test_safety81.py b/goodwe_controller/test_safety81.py new file mode 100644 index 0000000..64da0fa --- /dev/null +++ b/goodwe_controller/test_safety81.py @@ -0,0 +1,117 @@ +"""Runnable check for SAFETY-81, no false "Load too high for battery" alarms. +`python3 test_safety81.py` + +Drives the REAL Controller through tools/safety81_sim.py (a 1 s cycle on a +plant shaped like the SAFETY-79 rig, one sample in ten late). +DECISIONS/SAFETY-81-load-too-high.md has the record. + +1. Every command is byte-identical to release/1.0 5a4cdc2. +2. No alarm on the quarter-edge spike, the last seconds, noise (margin 50 + and 0) or a burst the quarter absorbs. +3. Real overloads still alarm, as fast as on 5a4cdc2. +4. peakguard.load_too_high() on its own. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import os +import sys +from types import SimpleNamespace + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(HERE, "tools")) + +import safety81_sim as sim # noqa: E402 +from app.peakguard import load_too_high # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +# Printed by `python3 tools/safety81_sim.py` on release/1.0 5a4cdc2 (the tool +# copied in, nothing else changed), in the CI image: (alarm times, digest). +BASE = { + "const4500": ([2699.0], "6ba6b8634f0df9526adc04f03c82db7d083973268deda0d1f07c5519bc2e5e9d"), + "const4500_m0": ([2699.0], "2bede28f3ea6ba9294be134c9b9733e43d22a7c24deac3bf8210bbbbe09b2039"), + "sine4500": ([2699.0], "bf70c2c23a0eede40c34478d1354b7daa1858e0a0f920693e2dd15fb5046120f"), + "edge4600": ([2.0, 902.0, 1802.0, 2699.0], "3cc0c6fec0c70f138530955babc2b416fe7307373037c1b2e927b6ccdaad3a4d"), + "edge4600_m0": ([2.0, 902.0, 1802.0, 2699.0], "ba9ba2c042ee42b043315b996ece38b3478dc9866aaf833256c9c29c02f0fe9f"), + "burst_end": ([881.0, 1781.0, 2681.0], "5f70e1eb4244820f1d44b494cb80e51f1a4486dee03357c9a8e8f7d371c5d9af"), + "noise5000_m50": ([292.0, 2551.0, 2698.0], "48b446e1a78e6d6032b31cb68a4eadb0f74e3aec4cc1e184162e9c65449bfdc5"), + "noise5000_m0": ([292.0, 2552.0, 2698.0], "1a0527dee6c2b03dc95a90b4682858c7bf5edf7205c2aced249112f04328c960"), + "step6500": ([1201.0, 1801.0], "95e5c90e4a6814526cb4f3bea76286063b449d86a420f888c014531fb6e913a3"), + "miss5560": ([1201.0, 1801.0], "cd991cfe1685750598236701a5a2f2f0342d66645609c536d42ab7ba07216e6c"), + "ramp6500": ([1296.0, 1801.0], "8db7675535f1a01abf38bd6bfb996a6fe57711d3ecca53541bb1c0870748c46b"), + "step7500_reserve": ([], "21eb9c07a4582f47f347084d1c75a28a5d767bc068bc3f74f32433d3239e9ccb"), +} +RUN = {k: sim.run(**v)[:2] for k, v in sim.SCENARIOS.items()} + +# ============================================================================ # +print("1. every command byte-identical to release/1.0 5a4cdc2") +check("the same scenarios as 5a4cdc2", set(RUN) == set(BASE)) +for k, (alarms, digest) in RUN.items(): + check(f"{k}: digest {digest[:12]}", digest == BASE[k][1]) + +# ============================================================================ # +print("2. no false alarm (5a4cdc2's are listed)") +for k in ("edge4600", "edge4600_m0", "const4500", "const4500_m0", "sine4500", + "noise5000_m50", "noise5000_m0", "burst_end"): + check(f"{k}: none (5a4cdc2: {BASE[k][0]})", RUN[k][0] == []) + +# ============================================================================ # +print("3. real overloads still alarm, as fast as 5a4cdc2") +for k in ("step6500", "miss5560"): + print(f" {k}: load steps up at 1200 s; alarms at {RUN[k][0]}, " + f"5a4cdc2 {BASE[k][0]}") + check(f"{k}: the same second as 5a4cdc2, and again only at the next " + f"quarter (at most once per quarter)", RUN[k][0] == BASE[k][0]) +# By design: until 1306 s this quarter would end at most ALARM_MISS_W over the +# real 3500 W cap; 5a4cdc2 alarmed when it crossed the aim (cap - 50). +print(f" ramp6500: alarms at {RUN['ramp6500'][0]}, " + f"5a4cdc2 {BASE['ramp6500'][0]}") +check("ramp6500: alarms once the quarter will end over the real cap by " + "more than ALARM_MISS_W", + RUN["ramp6500"][0] == [1306.0, 1801.0]) +check("step7500 under the peak reserve: not this alarm (the guard is not " + "allowed to discharge)", RUN["step7500_reserve"][0] == []) + +# ============================================================================ # +print("4. load_too_high()") + + +def proj(elapsed, done_avg, held): + """A projection `elapsed` s in, averaging `done_avg` so far.""" + r = 900.0 - elapsed + return SimpleNamespace(elapsed_s=elapsed, held_w=held, + projected_w=(done_avg * elapsed + max(held, 0) * r) + / 900.0) + + +def ltl(p, batt, cap=3500.0, rail=2000.0): + return load_too_high(p, batt_w=batt, ceiling_w=cap, achievable_w=rail) + + +check("load 6000 W vs 3500 + 2000: yes", ltl(proj(300, 3450, 4000), 2000)) +check("already over, the battery can carry the load but not catch up: yes", + ltl(proj(450, 7200, 7200), 0, rail=5000)) +check("the last second, a 7 W miss (under ALARM_MISS_W): no", + not ltl(proj(899, 3509, 2500), 1000)) +check("a miss of exactly ALARM_MISS_W: no", + not ltl(proj(450, 3520, 3500), 2000)) +check("...and 1 W more: yes", ltl(proj(450, 3522, 3500), 2000)) +check("over cap + battery, but the quarter lands under the cap: no", + not ltl(proj(880, 3450, 4000), 2000)) +check("...and when it does not: yes", ltl(proj(700, 3450, 4000), 2000)) +check("no battery reading: no", not ltl(proj(300, 3450, 5000), None)) +check("no seconds left: no", not ltl(proj(900, 4000, 5000), 2000)) + +print() +if fails: + print(f"FAILED: {len(fails)} check(s)") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/tools/safety81_sim.py b/goodwe_controller/tools/safety81_sim.py new file mode 100644 index 0000000..f91d07b --- /dev/null +++ b/goodwe_controller/tools/safety81_sim.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +"""SAFETY-81: when does "Load too high for battery" fire? + + python3 tools/safety81_sim.py # alarms and a control digest per run + +The REAL Controller (read_inputs + cycle) at a 1 s cycle, on a plant shaped +like the SAFETY-79 test rig: one battery switched Off (so only the peak guard +makes it give, max 2000 W), a 3500 W cap, and a P1 meter that publishes +0.3 s before each cycle. The battery reaches a new command 0.5 s after it is +written. One meter sample in ten arrives late (the add-on still holds the one +before), so the held meter reading can predate the battery's last change: +the double count behind the rig's false alarms. The cycle on a quarter +boundary, before the new quarter's first sample, files no peak claim, which +is the rig's 1 s grid spike at each quarter change. Each run returns the +alarm times and a digest of every command, so the same runs show both what +changed and what did not. +""" + +import asyncio +import hashlib +import os +import random +import sys +import tempfile +import time +from datetime import timedelta + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +import app.main as m # noqa: E402 +from app import packmode # noqa: E402 +from app.main import Controller # noqa: E402 +from app.p1 import make_sample, split_signed # noqa: E402 +from app.store import unit_key # noqa: E402 + +TICK = 1.0 +SAMPLE_LEAD_S = 0.3 # the meter publishes this long before each cycle +RESPONSE_S = 0.5 # a new command reaches the battery this much later +LATE_P = 0.1 # share of meter samples that arrive late +ALARM = "goodwe_peak_saturated" + + +def constant(w): + return lambda t: w + + +def noisy(mean, amp, seed=81): + """`mean` +/- `amp`, a new uniform value every second.""" + rnd = random.Random(seed) + table = {} + + def f(t): + k = int(t) + if k not in table: + table[k] = mean + rnd.uniform(-amp, amp) + return table[k] + return f + + +def sine(mean, amp, period=120.0, noise=50.0): + import math + n = noisy(0.0, noise, seed=79) + return lambda t: mean + amp * math.sin(2 * math.pi * t / period) + n(t) + + +def step(before, after, at): + return lambda t: before if t < at else after + + +def ramp(before, after, at, secs): + return lambda t: before + (after - before) * min(max(t - at, 0.0) / secs, 1.0) + + +class _Plant: + """One battery that reaches its command RESPONSE_S after the write.""" + + def __init__(self, load, rating, soc): + self.load, self.rating, self.soc = load, rating, soc + self.t = 0.0 + self.hist = [(-1e9, 0.0)] # (time the command takes effect, W) + self.notes = [] + self.meter = 0.0 # the last meter reading delivered + + def batt(self, at): + w = 0.0 + for when, v in self.hist: + if when <= at: + w = v + return max(-self.rating, min(self.rating, float(round(w)))) + + def grid(self, at): + return self.load(at) - self.batt(at) + + async def limits(self, e): + return (-5000.0, 5000.0, 1.0) + + async def call(self, domain, service, data): + if service == "create": + self.notes.append((self.t, data.get("notification_id"))) + return True + + async def number(self, e, invert=False): + if e in ("sensor.grid", "sensor.net"): + return self.meter + if e.startswith("sensor.soc"): + return self.soc + if e.startswith("sensor.batt"): + return self.batt(self.t) + return None + + async def set_number(self, e, v): + self.hist.append((self.t + RESPONSE_S, float(v))) + return True + + +def run(load, *, margin=50, dur=2700.0, rating=2000.0, cap=3500.0, + late_at=(), soc=60.0): + """Alarm times (s from the start of the first quarter) and a digest of + every cycle's target and written command. A sample is also late at each + `t % 900` in `late_at`.""" + opts = rig._options(1, { + "meter_source": "ha_signed", "p1_net_entity": "sensor.net", + "meter_phases": 1, "peak_cap_w": cap, "peak_margin_w": margin, + "battery_modes_enabled": True, "max_w": rating}) + store = rig._Store() + store.data[unit_key("inverter-a", packmode.USE_KEY)] = False + store.data[packmode.USE_KEY] = False + db = os.path.join(tempfile.mkdtemp(prefix="s81-"), "tariff.db") + + async def go(): + plant = _Plant(load, rating, soc) + c = Controller(opts, plant, store, rig._Pub(), stop=asyncio.Event(), + peak_db_path=db) + for i in c.inverters: + i.dev_min, i.dev_max = -5000.0, 5000.0 + c.auto = True + real_dt, clock = m.datetime, [0.0] + + class _DT(real_dt): + @classmethod + def now(cls, tz=None): + return rig.BASE + timedelta(seconds=clock[0]) + m.datetime = _DT + rows, late = [], random.Random(8100) + try: + t = 0.0 + while t < dur: + plant.t = clock[0] = t + ts = t - SAMPLE_LEAD_S + if late.random() >= LATE_P and t % 900 not in late_at: + plant.meter = plant.grid(ts) + imp, exp = split_signed(plant.meter) + c.p1.submit(make_sample( + "ha_signed", imp, exp, phases=1, + ingest_ts=rig.BASE + timedelta(seconds=ts), + ingest_mono=time.monotonic())) + await c.read_inputs(now_mono=t) + await c.cycle() + rows.append((t, c.target, round(plant.hist[-1][1], 6))) + t += TICK + finally: + m.datetime = real_dt + return plant, c, rows + plant, c, rows = asyncio.run(go()) + alarms = [t for t, nid in plant.notes if nid == ALARM] + return alarms, hashlib.sha256(repr(rows).encode()).hexdigest(), c, rows + + +# Three quarters each (2700 s); a new quarter starts at 900 s and 1800 s. +SCENARIOS = { + # F1: constant and sine loads the battery carries, across quarter edges. + "const4500": dict(load=constant(4500.0)), + "const4500_m0": dict(load=constant(4500.0), margin=0), + "sine4500": dict(load=sine(4500.0, 400.0)), + # F1 at the start of a quarter: the sample after the battery's return + # is late, so the held reading is the 1 s spike (the battery at 0 W). + "edge4600": dict(load=constant(4600.0), late_at=(2.0,)), + "edge4600_m0": dict(load=constant(4600.0), margin=0, late_at=(2.0,)), + # 6000 W in a quarter's last 20 s: over cap + battery, but the quarter + # still lands between the aim and the cap. + "burst_end": dict(load=lambda t: 6000.0 if t % 900 >= 880 else 4500.0), + # F2: a noisy load the battery carries, at margin 50 and 0. + "noise5000_m50": dict(load=noisy(5000.0, 150.0)), + "noise5000_m0": dict(load=noisy(5000.0, 150.0), margin=0), + # Real: from 1200 s the house needs 1000 W more than cap + battery. + "step6500": dict(load=step(4500.0, 6500.0, 1200.0)), + # Real, small: from 1200 s, 60 W (+/- 20 W noise) more than cap + battery. + "miss5560": dict(load=lambda t: step(4500.0, 5560.0, 1200.0)(t) + + noisy(0.0, 20.0)(t)), + # Real, slow: 4500 -> 6500 W over 200 s from 1200 s, through the band + # between the aim (cap - 50) and the real cap. + "ramp6500": dict(load=ramp(4500.0, 6500.0, 1200.0, 200.0)), + # The pack under its peak reserve (20 %), and a load far over cap + + # battery: that is "Battery stopped limiting the peak", not this alarm. + "step7500_reserve": dict(load=step(4500.0, 7500.0, 1200.0), soc=15.0), +} + + +if __name__ == "__main__": + for k, v in SCENARIOS.items(): + a, d, _, _ = run(**v) + print(f"{k:16s} alarms at {a} digest {d}") -- 2.54.0 From af39c1089322210dcd74b5adfc30b6db09ac7f57 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Tue, 29 Sep 2026 20:14:33 +0200 Subject: [PATCH 082/105] SAFETY-78: test_safety78 points at MUTATION.md (test_bytecode) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_safety78.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/goodwe_controller/test_safety78.py b/goodwe_controller/test_safety78.py index cd10119..8cecbb2 100644 --- a/goodwe_controller/test_safety78.py +++ b/goodwe_controller/test_safety78.py @@ -16,6 +16,9 @@ DECISIONS/SAFETY-78-drain-at-two.md has the record. no grid charge, and its card says why. 4. The peak guard binds during a drain, and the arbiter's order holds. 5. N=1 is byte-identical to release/1.0 5a4cdc2, and the harness bites. + +Mutations (MUTATION.md, purged copies, graded over this file and the named +tests) are listed in the pull request. """ import functools -- 2.54.0 From aabc2a27fd87c1e8e43019a120a96c067c7410f3 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Tue, 29 Sep 2026 20:22:16 +0200 Subject: [PATCH 083/105] OPT-11 P4: tests for eight surviving mutants; guarded reads Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 4 ++ goodwe_controller/test_modes_p4.py | 68 +++++++++++++++++-- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index b5d970c..5a68ede 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -114,5 +114,9 @@ P1 is its section 6 P1, and the pull request lists what was measured. - the days' real 2026 quarter-hourly prices (held out): P2 32.26, option A 32.01, old trade 31.40, P4 29.19 (perfect 29.21, too high 29.28, missing 32.01). + - Solar first + Cheap hours only: 19.57 on both P3 and P4 (year-earlier + prices); on real 2026 prices P4 29.72 against P3's 29.41. Skipping the + sun's share does not pay for Cheap hours there; Leftover solar is the + mode the forecast pays for. No threshold was tuned to these days. The 2026-09-24 PV recording could not be replayed: it is only in the live Home Assistant. diff --git a/goodwe_controller/test_modes_p4.py b/goodwe_controller/test_modes_p4.py index 7847e3c..74b5b2e 100644 --- a/goodwe_controller/test_modes_p4.py +++ b/goodwe_controller/test_modes_p4.py @@ -36,6 +36,7 @@ sys.path.insert(0, HERE) sys.path.insert(0, os.path.join(HERE, "tools")) logging.disable(logging.WARNING) +from named_absence import nth, present # noqa: E402 import opt11p3_replay as rp # noqa: E402 from app import arbitrage, dayplan, homeview, modetrade, packmode # noqa from app import priceruns, solarfc, validate # noqa: E402 @@ -320,8 +321,21 @@ check("Cheap hours: dark fills to the ceiling (as P3)", check("...and skips the part the sun covers on a partly sunny day", ch.targets[B] < 95.0 and ch.share_kwh[B] > 0 and abs(ch.targets[B] - (95.0 - ch.share_kwh[B] * 10.0)) < 0.01) -check("trust 100 % counts more sun than 70 %: a lower or equal level", - dplan(12.0, trust=100).targets[B] <= partly.targets[B]) +check("trust 100 % counts more sun than 70 %: a lower level", + dplan(12.0, trust=100).targets[B] < partly.targets[B]) +check("...and the sun counted scales with the trust exactly", + abs(dplan(12.0, trust=100).sun_kwh * 0.7 - partly.sun_kwh) < 0.01) +_room_a = (95.0 - 60.0) / 10.0 * 10.0 / 10.0 # A: 60 % -> 95 % of 10 kWh +check("Solar first takes the sun first: B's share is what is left after " + f"A's {_room_a:.1f} kWh of room", + abs(partly.share_kwh[B] - max(0.0, partly.sun_kwh - _room_a)) < 0.01 + and partly.share_kwh[B] < partly.sun_kwh) +_flat = (lambda h: 600.0, 600.0) +_sunny_net = (lambda h: -2000.0 if 9 <= h < 17 else 600.0, 600.0) +check("the house's net use in sunny hours (negative) is lifted to the night " + "floor: the same sun as a flat 600 W house", + abs(dplan(12.0, est=_flat).sun_kwh - dplan(12.0, est=_sunny_net) + .sun_kwh) < 1e-6) check("no forecast, no house profile or no price plan: no plan", dayplan.plan(None, EST, R0, T0, PACKS, trust_pct=70, floor_pct=20, ceiling_pct=95) is None @@ -530,7 +544,8 @@ def invariants(tag, rows, c): # Sunny: 40 kWh forecast. B (Leftover solar) at 30 % needs nothing. rows, st_, c = run_day(SF_LS, fc=40.0, soc0={"a": 60.0, "b": 30.0}) charge = invariants("sunny", rows, c) -print(f" sunny: verdict {rows[-1]['plan'] and rows[-1]['plan'].verdict}, " +_last = nth(rows, -1, "a cycle") +print(f" sunny: verdict {present(_last) and _last['plan'] and _last['plan'].verdict}, " f"{len(charge)} charge cycles") check("sunny: a day plan is made, and says sunny", any(r["plan"] is not None and r["plan"].verdict == dayplan.SUNNY @@ -540,7 +555,7 @@ check("sunny: no grid charge at all", not charge) # Dark: 1 kWh. B buys the evening's shortfall only, in the cheap run. rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}) charge = invariants("dark", rows, c) -tgt = next(r["targets"][B] for r in rows if r["targets"]) +tgt = nth([r["targets"][B] for r in rows if r["targets"]], 0, "a level") top = max(r["soc"]["b"] for r in rows) print(f" dark: B level {tgt:.1f} %, B reached {top:.1f} %, " f"{len(charge)} charge cycles") @@ -548,18 +563,18 @@ check("dark: Leftover solar charges from the grid in the cheap run", charge and all(r["runs"].cheap.holds(r["now"]) for r in charge) and all(r["roles"][B] == modetrade.CHARGE for r in charge)) check("dark: ...only up to its level (the shortfall), not 95 %", - tgt < 60.0 and top <= tgt + 2.0) + present(tgt) and tgt < 60.0 and top <= tgt + 2.0) check("dark: A rests while B charges", all(r["roles"][A] == modetrade.REST for r in charge)) # Cheap hours on a partly sunny day: skips the part the sun covers. rows, st_, c = run_day(SF_CH, fc=14.0, soc0={"a": 60.0, "b": 30.0}) charge = invariants("cheap hours, partly", rows, c) -tgt = next(r["targets"][B] for r in rows if r["targets"]) +tgt = nth([r["targets"][B] for r in rows if r["targets"]], 0, "a level") top = max(r["soc"]["b"] for r in rows) print(f" cheap hours partly: B level {tgt:.1f} %, reached {top:.1f} %") check("Cheap hours with sun forecast: charges, but stops below 95 %", - charge and tgt < 90.0 and top <= tgt + 2.0) + charge and present(tgt) and tgt < 90.0 and top <= tgt + 2.0) rows_nf, _s, c_nf = run_day(SF_CH, fc=None, soc0={"a": 60.0, "b": 30.0}) check("...and with the forecast down it fills towards 95 % as in P3", max(r["soc"]["b"] for r in rows_nf) > top + 10.0) @@ -614,6 +629,30 @@ check("...while the profile learns and the store keeps each closed hour", c.store.data.get("house_profile") or {}) >= 1) check("selling stays off (option A)", packmode.SELLING_ENABLED is False) +# A forecast arriving mid-period makes the plan at once, not at the next +# 15-minute period. +COME = datetime(2026, 9, 21, 1, 3, tzinfo=L).astimezone(timezone.utc) +rows, st_, c = run_day(SF_LS, fc=lambda now: None if now < COME else 1.0, + soc0={"a": 60.0, "b": 30.0}, hours=0.5) +first = next((r["now"] for r in rows if r["targets"]), None) +check("a forecast that arrives at 01:03 makes the plan before 01:15", + first is not None and first < COME + timedelta(minutes=3)) + +# Battery modes off: the forecast is never read. +READS = [0] +_real_sensor = rp.Hass.state + + +async def _counted(self, e): + READS[0] += 1 + return await _real_sensor(self, e) +rp.Hass.state = _counted +FC_KWH[0] = 1.0 +rp.run("modes_off", house_flat(800.0), WPTS, UTC0 + timedelta(hours=1), + 600.0, extra=dict(FC_OPTS)) +rp.Hass.state = _real_sensor +check("battery modes off: the forecast sensor is never read", READS[0] == 0) + # ============================================================================ # print("7. the Batteries screen and the Simple view") rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}, @@ -627,7 +666,22 @@ why = homeview.day_key(c, B) check("B's Why key (plan, dark) is tops_up", why == "tops_up") check("...and says so in plain words", homeview.why_words(why) == "Too little sun is forecast, so it charges some from the grid.") +_d0, _d1 = homeview.local_day(c.solar_fc.at) +_blocks, _ = homeview.mode_runs(c, _d0, _d1, c.solar_fc.at, False) +_grid = [b for b in _blocks if b["kind"] == "grid" and b["battery"] == 1] +_need = homeview.plan_need(c, B) +check(f"Today: B's grid block is the planned shortfall ({_need:.2f} kWh), " + "not its room to 95 %", _grid and abs(_grid[0]["kwh"] - _need) < 0.01 + and _need < 3.0) +_run = c.mode_runs.cheap +_packs = c._mode_packs() +_m1 = c._run_mark("charge", _run, _packs, lambda p: True, ((B, 40.0),)) +_m2 = c._run_mark("charge", _run, _packs, lambda p: False, ((B, 50.0),)) +check("a level the hysteresis moved opens the run to that battery again", + _m1 and not _m2) c.solar_fc = None +check("the levels are dropped as soon as the forecast goes, even before " + "the plan is rebuilt", c._plan_targets and c.plan_targets() is None) check("a lost forecast says so: no forecast, Leftover solar solar only", homeview.solar_block(c, datetime.now(timezone.utc))["state"] == "no_forecast" and homeview.day_key(c, B) == "no_forecast") -- 2.54.0 From f967073cfe5192dafcdbf38348c9fda430929b20 Mon Sep 17 00:00:00 2001 From: goodwe-review-agent <gschrooyen@gmail.com> Date: Tue, 29 Sep 2026 20:58:37 +0200 Subject: [PATCH 084/105] SAFETY-81 review: 10 s hold, ERROR line per episode, more scenarios - The alarm must hold for peakguard.ALARM_HOLD_S (10 s) on the projection's clock. A load that tops cap + battery for ~5 s every 30 s alarmed at every quarter start while the quarter landed under the aim (sine4500_fast). - A cycle with no battery reading leaves the hold alone. - Notified once per quarter, but the ERROR line is written per episode. - New sim scenarios (sine4500_fast, twice7000, step6500_gap) with 5a4cdc2 digests; control still byte-identical. Unit checks for export and the hold across a missing reading. test_peakguard's saturated fixture moves the hold start back instead of waiting it out. - DECISIONS and DOCS updated: costs of the hold, tolerance reasoning, the double count in control left to a follow-up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-81-load-too-high.md | 36 ++++++--- goodwe_controller/DOCS.md | 7 +- goodwe_controller/app/main.py | 44 +++++++---- goodwe_controller/app/peakguard.py | 3 + goodwe_controller/test_peakguard.py | 7 ++ goodwe_controller/test_safety81.py | 74 ++++++++++++++++--- goodwe_controller/tools/safety81_sim.py | 46 +++++++++--- 7 files changed, 170 insertions(+), 47 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md b/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md index bb56bc2..c94559d 100644 --- a/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md +++ b/goodwe_controller/DECISIONS/SAFETY-81-load-too-high.md @@ -1,6 +1,7 @@ # SAFETY-81 — no false "Load too high for battery" alarms -**Status: 2026-09-29, owner go for the card. The 10 W tolerance is this PR's choice, for review.** +**Status: 2026-09-29, owner go for the card. Review kept the 10 W tolerance +as a constant and added the 10 s hold.** ## Defect @@ -23,20 +24,31 @@ The alarm needs `saturated` and `peakguard.load_too_high()`: with the battery at full power from now on, the quarter still ends more than `ALARM_MISS_W` (10 W) over the real limit (`ceiling_w`). That is the miss itself, without the gain. The battery reading it uses is the lower of this cycle's and the last -one's. At most one alarm per quarter, because near the threshold the test -flickers with the meter. +one's. It must hold for `ALARM_HOLD_S` (10 s). At most one notification per +quarter, because near the threshold the test flickers with the meter; the +ERROR log line is written for every episode. **Why 10 W:** at margin 0 the guard itself lands up to +5.7 W over (SAFETY-79 test, check 5), and those misses are real but tiny; the alarm would fire in the last second of most guarded quarters. The margin (default 50) is the fix -for them. Cost: a real miss of 10 W or less is not alarmed. +for them. Cost: a real miss of 10 W or less is not alarmed; at a capacity +tariff of the order of EUR 50 per kW a year, 10 W in one month is cents. +Review measured +13 W on a 10 kW two-unit site at margin 0, not saturated, so +no alarm: the tolerance only matters when the battery is at its rating. A +constant, not an option: `peak_margin_w` is the owner's knob. -**Cost:** a load that climbs slowly through the band between the aim and the -cap alarms when the quarter will end over the cap, not at the aim (10 s later -in `ramp6500`). A step overload alarms in the same cycle as before; a real -overload shows on the meter before the battery moves, so the lower reading -costs it nothing. A quarter already over that the battery cannot win back -still alarms (test_peakguard.py's saturated fixture). +**Why the hold (review):** the test assumes the load now lasts the rest of +the quarter. A load over cap + battery for ~5 s every 30 s (`sine4500_fast`, +a cycling hob or heater) alarmed at each quarter start while the quarter +landed under the aim. The hold stops that. + +**Cost:** a real alarm comes 10-12 s later than on 5a4cdc2 (`step6500` at +1211 s, not 1201 s); a slow ramp 20 s later (`ramp6500`), as it waits for the +real cap. While the battery refuses or its reading is lost, the alarm waits +until the quarter is lost even at full battery (27-60 s later in review runs); +those faults have their own alarms. A load over cap + battery for more than +10 s still alarms even if the quarter later lands under. `ALARM_HOLD_S = 0` +removes the hold. ## Not changed: the 1 s spike itself @@ -45,3 +57,7 @@ sample still sees 0 s left, files no claim, and an Off battery drops to 0 W for one cycle. That is the same edge tick as OPT-15 F1, so it is left to OPT-15. Control is unchanged here: every command in `tools/safety81_sim.py` is byte-identical to 5a4cdc2 (test_safety81.py part 1). + +The double count also moves control, not only the alarm: on a late sample the +guard asks for the full rating for one cycle (edge4600 at 902 s: 2000 W where +1150 W holds the aim). Left to a follow-up card. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 47386dc..78f4b10 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3212,9 +3212,10 @@ reason code `OUTPUT_CLAMP`. **Load too high for battery.** The capacity-peak guard (SAFETY-07) asks for everything the inverter can discharge and the running 15-minute average is still projected over the peak limit, so the month's billed peak -(capaciteitstarief) goes up. It fires only when, with the battery at full -power, the period will still end more than 10 W over the real limit (not the -margin's aim), and at most once per period (SAFETY-81). In shadow mode the +(capaciteitstarief) goes up. It fires only when, for 10 s, the period would +still end more than 10 W over the real limit (not the margin's aim) with the +battery at full power. It notifies at most once per period; later overloads +in the same period go to the log (SAFETY-81). In shadow mode the guard's projection is made on a plant that did not respond (SAFETY-47), and the text says so. See *The capacity-peak guard*. diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 954cacc..7089ada 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -926,6 +926,7 @@ class Controller: self._peak_proj = None self._peak_batt_prev = None self._peak_alarm_block = None + self._peak_high_since = None self._peak_floor_limited = False self._maint_shape_suspended = False # OPT-11. Battery modes, off by default so an install that has not @@ -4825,38 +4826,53 @@ class Controller: SAFETY-81: `g.saturated` alone is not enough. It is graded against the aim, and a 1 s meter spike, noise or the last seconds of a quarter set it while the quarter lands on target; `peakguard.load_too_high()` must - agree too. The battery reading it gets is the lower of this cycle's and - the last one's - see there. + agree too, for `ALARM_HOLD_S`. The battery reading it gets is the lower + of this cycle's and the last one's - see there. Edge-triggered, and de-asserting arms it again - the same shape as FreezeWatchdog's `evaluate()`, and for the same reason: one notification - per episode, not one per cycle. SAFETY-81: and at most one per quarter. + per episode, not one per cycle. SAFETY-81: the notification and action + log line at most once per quarter; the ERROR line once per episode. """ g = self.peak_guard batt, prev = self.site_batt_w, self._peak_batt_prev + if batt is None: + # Unknown, not "fine": the hold below neither grows nor restarts. + return self._peak_batt_prev = batt - if batt is not None and prev is not None: + if prev is not None: batt = min(float(batt), float(prev)) - saturated = bool( - g is not None and g.saturated and self._peak_proj is not None + p = self._peak_proj + high = bool( + g is not None and g.saturated and p is not None + and p.block_start is not None and peakguard.load_too_high( - self._peak_proj, batt_w=batt, ceiling_w=g.ceiling_w, + p, batt_w=batt, ceiling_w=g.ceiling_w, achievable_w=self.site_rating_w)) + # SAFETY-81: and for ALARM_HOLD_S, on the projection's clock. + saturated = False + if high: + t = p.block_start + timedelta(seconds=float(p.elapsed_s)) + if self._peak_high_since is None: + self._peak_high_since = t + saturated = ((t - self._peak_high_since).total_seconds() + >= peakguard.ALARM_HOLD_S) + else: + self._peak_high_since = None was, self._peak_saturated = self._peak_saturated, saturated if not saturated or was: return - # SAFETY-81: at most once per quarter. Near its threshold the test - # above flickers with the meter, and each flicker would re-alarm. - if self._peak_proj.block_start == self._peak_alarm_block: - return - self._peak_alarm_block = self._peak_proj.block_start - self.log_event("PEAK_GUARD_SATURATED - " + g.reason, - hint=messages.hint("peak_saturated")) _LOG.error( "Switch off large loads, the battery alone cannot keep this " "15-minute period under the peak limit: %s.", messages.reason_code(g.reason)) _LOG.debug("Evidence: %s.", g.reason) + # SAFETY-81: notified once per quarter; a later episode is logged only. + if p.block_start == self._peak_alarm_block: + return + self._peak_alarm_block = p.block_start + self.log_event("PEAK_GUARD_SATURATED - " + g.reason, + hint=messages.hint("peak_saturated")) # A fixed notification_id, and a DIFFERENT one from every other alarm # here - check_meter_frozen() gives the reasoning. A saturated peak guard # is not a frozen meter and is not an out-of-range setpoint. diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index 15df274..9e4bf65 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -870,6 +870,9 @@ def decide(projection, *, batt_w, cap_w, margin_w, reading, achievable_w, soc, # "Load too high for battery" fires. Above the guard's own landing error at # margin 0 (up to +5.7 W, SAFETY-79 test check 5), which margin 0 accepts. ALARM_MISS_W = 10.0 +# ...and for this long without a break, so a load that peaks for a few seconds +# (a hob or heater cycling) is not read as the rest of the quarter. +ALARM_HOLD_S = 10.0 def load_too_high(projection, *, batt_w, ceiling_w, achievable_w) -> bool: diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 909ccfe..f6186a6 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -1259,6 +1259,13 @@ check(f"the saturating fixture ({NET2:.0f} W) is a load the real ingest " f"accepts, not one it rejects as implausible", NET2 < PLAUSIBLE_MAX_W) print(f" saturated case: {c2.peak_guard.explain()}") check("a load larger than the inverter saturates the guard", c2.peak_guard.saturated) +# SAFETY-81 review: the alarm must hold ALARM_HOLD_S first. The fixture runs on +# the wall clock, so the start of the hold is moved back instead of waited out. +check("...but not on its first cycle: it must hold peakguard.ALARM_HOLD_S " + "(SAFETY-81)", hass2.notifications.count("goodwe_peak_saturated") == 0 + and c2._peak_high_since is not None) +c2._peak_high_since -= timedelta(seconds=peakguard.ALARM_HOLD_S) +asyncio.get_event_loop_policy().new_event_loop().run_until_complete(c2.cycle()) check("...and THAT raises exactly one notification, with its own id - the one " "state where the money will be spent and a human is the only remaining " "actuator", hass2.notifications.count("goodwe_peak_saturated") == 1) diff --git a/goodwe_controller/test_safety81.py b/goodwe_controller/test_safety81.py index 64da0fa..5721f69 100644 --- a/goodwe_controller/test_safety81.py +++ b/goodwe_controller/test_safety81.py @@ -8,20 +8,24 @@ DECISIONS/SAFETY-81-load-too-high.md has the record. 1. Every command is byte-identical to release/1.0 5a4cdc2. 2. No alarm on the quarter-edge spike, the last seconds, noise (margin 50 and 0) or a burst the quarter absorbs. -3. Real overloads still alarm, as fast as on 5a4cdc2. +3. Real overloads still alarm, ALARM_HOLD_S after 5a4cdc2. 4. peakguard.load_too_high() on its own. +5. The hold across a cycle with no battery reading (review). Mutations (MUTATION.md, purged copies) are listed in the pull request. """ +import asyncio import os import sys +from datetime import datetime, timedelta, timezone from types import SimpleNamespace HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.join(HERE, "tools")) import safety81_sim as sim # noqa: E402 +from app.main import Controller # noqa: E402 from app.peakguard import load_too_high # noqa: E402 fails = [] @@ -48,8 +52,14 @@ BASE = { "miss5560": ([1201.0, 1801.0], "cd991cfe1685750598236701a5a2f2f0342d66645609c536d42ab7ba07216e6c"), "ramp6500": ([1296.0, 1801.0], "8db7675535f1a01abf38bd6bfb996a6fe57711d3ecca53541bb1c0870748c46b"), "step7500_reserve": ([], "21eb9c07a4582f47f347084d1c75a28a5d767bc068bc3f74f32433d3239e9ccb"), + # Added in review, printed the same way. + "sine4500_fast": (["112, about one per 30 s"], "710008fd8f2d33a0e2cbb9a626bedafd6d87bc23712bbc5b74a4af9b3ec21897"), + "twice7000": ([1001.0, 1502.0, 2699.0], "1cddda8cf35859efb2ad503f1683f744cb812a6325a390c4fa3df19d717af043"), + "step6500_gap": ([1201.0, 1801.0], "95e5c90e4a6814526cb4f3bea76286063b449d86a420f888c014531fb6e913a3"), } -RUN = {k: sim.run(**v)[:2] for k, v in sim.SCENARIOS.items()} +OUT = {k: sim.run(**v) for k, v in sim.SCENARIOS.items()} +RUN = {k: v[:2] for k, v in OUT.items()} +ERR = {k: v[4] for k, v in OUT.items()} # ============================================================================ # print("1. every command byte-identical to release/1.0 5a4cdc2") @@ -60,23 +70,33 @@ for k, (alarms, digest) in RUN.items(): # ============================================================================ # print("2. no false alarm (5a4cdc2's are listed)") for k in ("edge4600", "edge4600_m0", "const4500", "const4500_m0", "sine4500", - "noise5000_m50", "noise5000_m0", "burst_end"): + "noise5000_m50", "noise5000_m0", "burst_end", "sine4500_fast"): check(f"{k}: none (5a4cdc2: {BASE[k][0]})", RUN[k][0] == []) # ============================================================================ # -print("3. real overloads still alarm, as fast as 5a4cdc2") -for k in ("step6500", "miss5560"): +print("3. real overloads still alarm, ALARM_HOLD_S after 5a4cdc2") +# ALARM_HOLD_S (10 s) plus up to 2 s of late meter samples; at 1800 s the +# quarter-edge tick restarts the hold. +for k, want in (("step6500", [1211.0, 1813.0]), + ("miss5560", [1213.0, 1813.0])): print(f" {k}: load steps up at 1200 s; alarms at {RUN[k][0]}, " f"5a4cdc2 {BASE[k][0]}") - check(f"{k}: the same second as 5a4cdc2, and again only at the next " - f"quarter (at most once per quarter)", RUN[k][0] == BASE[k][0]) -# By design: until 1306 s this quarter would end at most ALARM_MISS_W over the -# real 3500 W cap; 5a4cdc2 alarmed when it crossed the aim (cap - 50). + check(f"{k}: after the hold, and again only at the next quarter", + RUN[k][0] == want) +check("step6500_gap: cycles stopped by a lost battery reading do not " + "restart the hold", + RUN["step6500_gap"][0] == [1215.0, 1813.0]) +check("twice7000: notified once in the quarter (5a4cdc2: " + f"{BASE['twice7000'][0]})", RUN["twice7000"][0] == [1011.0]) +check("twice7000: the ERROR line for both overloads", + ERR["twice7000"] == [1011.0, 1512.0]) +# By design: until 1306 s (then the hold) this quarter would end at most +# ALARM_MISS_W over the real 3500 W cap; 5a4cdc2 alarmed at the aim (cap - 50). print(f" ramp6500: alarms at {RUN['ramp6500'][0]}, " f"5a4cdc2 {BASE['ramp6500'][0]}") check("ramp6500: alarms once the quarter will end over the real cap by " "more than ALARM_MISS_W", - RUN["ramp6500"][0] == [1306.0, 1801.0]) + RUN["ramp6500"][0] == [1316.0, 1813.0]) check("step7500 under the peak reserve: not this alarm (the guard is not " "allowed to discharge)", RUN["step7500_reserve"][0] == []) @@ -109,6 +129,40 @@ check("over cap + battery, but the quarter lands under the cap: no", check("...and when it does not: yes", ltl(proj(700, 3450, 4000), 2000)) check("no battery reading: no", not ltl(proj(300, 3450, 5000), None)) check("no seconds left: no", not ltl(proj(900, 4000, 5000), 2000)) +check("a quarter already over is not won back by export: yes", + ltl(proj(800, 3950, 1000), 0)) + +# ============================================================================ # +print("5. the hold across a cycle with no battery reading") +# A reading the stale detector drops (STALE_READING) reaches the alarm as None +# while the cycle still runs. Unknown is not "fine": it must not restart the +# hold. Driven on Controller.check_peak_saturated() itself, with stubs. +Q0 = datetime(2026, 9, 20, 11, 0, tzinfo=timezone.utc) +notes = [] + + +async def _call(domain, service, data): + notes.append(data.get("notification_id")) + + +stub = SimpleNamespace( + peak_guard=SimpleNamespace(saturated=True, ceiling_w=3500.0, + reason="PEAK_GUARD: fixture"), + site_rating_w=2000.0, shadow=False, events=[], + _peak_batt_prev=None, _peak_alarm_block=None, _peak_high_since=None, + _peak_saturated=False, hass=SimpleNamespace(call=_call), + log_event=lambda msg, hint=None: None) +first = None +for sec in range(0, 30): + stub.site_batt_w = None if 4 <= sec < 8 else 2000.0 + p = proj(300 + sec, 3450, 6000) + p.block_start = Q0 + stub._peak_proj = p + asyncio.run(Controller.check_peak_saturated(stub)) + if notes and first is None: + first = sec +check(f"a 4 s gap in the battery reading: alarm at {first} s, not 18 s", + first == 10) print() if fails: diff --git a/goodwe_controller/tools/safety81_sim.py b/goodwe_controller/tools/safety81_sim.py index f91d07b..9d00ad8 100644 --- a/goodwe_controller/tools/safety81_sim.py +++ b/goodwe_controller/tools/safety81_sim.py @@ -18,6 +18,7 @@ changed and what did not. import asyncio import hashlib +import logging import os import random import sys @@ -75,8 +76,9 @@ def ramp(before, after, at, secs): class _Plant: """One battery that reaches its command RESPONSE_S after the write.""" - def __init__(self, load, rating, soc): + def __init__(self, load, rating, soc, batt_gap=()): self.load, self.rating, self.soc = load, rating, soc + self.batt_gap = batt_gap # (from, to): the battery reading is lost self.t = 0.0 self.hist = [(-1e9, 0.0)] # (time the command takes effect, W) self.notes = [] @@ -106,6 +108,8 @@ class _Plant: if e.startswith("sensor.soc"): return self.soc if e.startswith("sensor.batt"): + if self.batt_gap and self.batt_gap[0] <= self.t < self.batt_gap[1]: + return None return self.batt(self.t) return None @@ -115,10 +119,11 @@ class _Plant: def run(load, *, margin=50, dur=2700.0, rating=2000.0, cap=3500.0, - late_at=(), soc=60.0): - """Alarm times (s from the start of the first quarter) and a digest of - every cycle's target and written command. A sample is also late at each - `t % 900` in `late_at`.""" + late_at=(), soc=60.0, batt_gap=()): + """Alarm times (s from the start of the first quarter), a digest of every + cycle's target and written command, the Controller, the rows, and the + times of the ERROR log line. A sample is also late at each `t % 900` in + `late_at`.""" opts = rig._options(1, { "meter_source": "ha_signed", "p1_net_entity": "sensor.net", "meter_phases": 1, "peak_cap_w": cap, "peak_margin_w": margin, @@ -129,7 +134,7 @@ def run(load, *, margin=50, dur=2700.0, rating=2000.0, cap=3500.0, db = os.path.join(tempfile.mkdtemp(prefix="s81-"), "tariff.db") async def go(): - plant = _Plant(load, rating, soc) + plant = _Plant(load, rating, soc, batt_gap) c = Controller(opts, plant, store, rig._Pub(), stop=asyncio.Event(), peak_db_path=db) for i in c.inverters: @@ -143,6 +148,14 @@ def run(load, *, margin=50, dur=2700.0, rating=2000.0, cap=3500.0, return rig.BASE + timedelta(seconds=clock[0]) m.datetime = _DT rows, late = [], random.Random(8100) + errors = [] + + class _Err(logging.Handler): + def emit(self, r): + if "battery alone cannot keep" in r.getMessage(): + errors.append(plant.t) + h = _Err() + logging.getLogger("goodwe").addHandler(h) try: t = 0.0 while t < dur: @@ -161,10 +174,12 @@ def run(load, *, margin=50, dur=2700.0, rating=2000.0, cap=3500.0, t += TICK finally: m.datetime = real_dt - return plant, c, rows - plant, c, rows = asyncio.run(go()) + logging.getLogger("goodwe").removeHandler(h) + return plant, c, rows, errors + plant, c, rows, errors = asyncio.run(go()) alarms = [t for t, nid in plant.notes if nid == ALARM] - return alarms, hashlib.sha256(repr(rows).encode()).hexdigest(), c, rows + return (alarms, hashlib.sha256(repr(rows).encode()).hexdigest(), c, rows, + errors) # Three quarters each (2700 s); a new quarter starts at 900 s and 1800 s. @@ -194,10 +209,21 @@ SCENARIOS = { # The pack under its peak reserve (20 %), and a load far over cap + # battery: that is "Battery stopped limiting the peak", not this alarm. "step7500_reserve": dict(load=step(4500.0, 7500.0, 1200.0), soc=15.0), + # Review: a load swinging 4500 +/- 1200 W every 30 s (a hob or heater + # cycling). It tops cap + battery for about 5 s a swing, and the quarter + # still lands under the aim. + "sine4500_fast": dict(load=sine(4500.0, 1200.0, period=30.0, noise=200.0)), + # Review: two real overloads in one quarter, 1000-1100 s and 1500-1700 s. + "twice7000": dict(load=lambda t: 7000.0 if (1000 <= t < 1100 + or 1500 <= t < 1700) + else 4500.0), + # Review: step6500, and the battery reading is lost 1203-1215 s. + "step6500_gap": dict(load=step(4500.0, 6500.0, 1200.0), + batt_gap=(1203.0, 1215.0)), } if __name__ == "__main__": for k, v in SCENARIOS.items(): - a, d, _, _ = run(**v) + a, d, _, _, _ = run(**v) print(f"{k:16s} alarms at {a} digest {d}") -- 2.54.0 From 044fc0d5bd6ec806892430b6b71ef8e4e41b1353 Mon Sep 17 00:00:00 2001 From: goodwe-review <noreply@anthropic.com> Date: Tue, 29 Sep 2026 21:13:31 +0200 Subject: [PATCH 085/105] SAFETY-78 review: card truth while the drain waits, more checks - homeview: no "This one does not charge" while the draining battery waits (no floor then, so the other battery may charge from solar). - test_safety78: one wait line across a probe, a second episode logs again, the card while waiting, and a seeded sweep of the floor against every other claim (part 6). - DECISIONS: the wait case, and the measured N=1 peak and N=2 charge follow-ups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-78-drain-at-two.md | 14 +++- goodwe_controller/app/homeview.py | 7 +- goodwe_controller/test_safety78.py | 82 ++++++++++++++++++- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md index 29511b2..7604c47 100644 --- a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md +++ b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md @@ -29,10 +29,16 @@ direction. Opposite splits stay forbidden. floor, and the wait is logged once per episode. - With battery modes on, no pack is a grid charger while another drains (`modetrade.decide(draining=)`, why `cycle`), and the other battery's card - says why (`other_cycle`). + says why (`other_cycle`). Not while the drain waits: no floor is filed + then, so the other battery may charge from solar. - Not filed at N=1, where the drain is the site SET itself: byte-identical (`tools/safety78_identity.py`, which hashes the claims too). -**Not changed.** At N=1 a drain (60) still outranks the peak floor (50), so -the peak guard does not add to a drain there. That is pre-existing and kept by -the N=1 identity. +**Not changed (measured in the PR #154 review, follow-ups).** +- At N=1 a drain (60) outranks the peak floor (50), so the guard does not add + to it: a 5000 W house imports 3000 W against a 2500 W limit, a 6000 W house + 4000 W. Pre-existing, kept by the N=1 identity. +- At N=2 a maintenance CHARGE in a cheap window has the same stall: the + charging pack's `hi = -floor` against the loop asking the other to give is + refused on 141 of 261 cycles. The mirror fix is a site `hi`, which can meet + the peak floor's `lo` (0 W), so it is not this card. diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 550ddfd..e37274f 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -641,10 +641,13 @@ def battery_rows(c, shadow, running, held=False): other = next((o.name for o in c.inverters if o is not inv and refusing(c, o) > 0 and not _off(c, o)), None) # SAFETY-78: another battery drains for its monthly cycle, so this - # one never charges now. + # one never charges now. Not while that drain waits: it files no + # floor then, so this battery may charge from solar. + waits = getattr(c, "_drain_waits", ()) cycling = next((o.name for j, o in enumerate(c.inverters) if o is not inv and j < len(c.maints) - and c.maints[j].phase == M_DRAIN), None) + and c.maints[j].phase == M_DRAIN + and o.name not in waits), None) role = None if tick is None else tick.roles.get(inv.name) # Only once a cycle has run with modes on (`tick`): before that # nothing is known, so nothing is claimed about the prices. diff --git a/goodwe_controller/test_safety78.py b/goodwe_controller/test_safety78.py index 8cecbb2..c3019a4 100644 --- a/goodwe_controller/test_safety78.py +++ b/goodwe_controller/test_safety78.py @@ -16,6 +16,8 @@ DECISIONS/SAFETY-78-drain-at-two.md has the record. no grid charge, and its card says why. 4. The peak guard binds during a drain, and the arbiter's order holds. 5. N=1 is byte-identical to release/1.0 5a4cdc2, and the harness bites. +6. A seeded sweep of the floor against the loop, trades, the peak floor, a + safety stop, refusals and an Off battery. Mutations (MUTATION.md, purged copies, graded over this file and the named tests) are listed in the pull request. @@ -24,6 +26,7 @@ tests) are listed in the pull request. import functools import logging import os +import random import sys import tempfile @@ -36,9 +39,9 @@ import opt11_identity as rig # noqa: E402 import opt11p3_identity as p3 # noqa: E402 import safety78_identity as s78 # noqa: E402 import safety79_identity as s79 # noqa: E402 -from app import arbitrage, homeview, packmode # noqa: E402 +from app import allocator, arbitrage, homeview, packmode # noqa: E402 from app.arbiter import (Claim, P_ARBITRAGE, P_LOOP, P_MAINTENANCE, # noqa - P_PEAK, P_SAFETY, resolve) + P_MODE, P_PEAK, P_SAFETY, pre_resolve, resolve) from app.main import Controller # noqa: E402 from app.maintenance import CHARGE, DRAIN # noqa: E402 from app.store import unit_key # noqa: E402 @@ -151,6 +154,22 @@ check("⭐ A refuses to give power (SAFETY-73): the cycle waits, the line is " check("...and B covers the house on its own meanwhile", 1400.0 <= cmd(_w_rows[-1])["b"] <= 1600.0) +# PR #154 review: one line per episode, across a probe and a second episode. +_pr_rows, _pr = drain_run(1500.0, dur=1300.0, cut=lambda u, t: u == "a") +check("the SAFETY-73 probe (A pinned at 200 W, not by maintenance) does not " + "end the wait: still ONE line over 1300 s with a probe in it", + any(cmd(r)["a"] == 200.0 for r in _pr_rows) + and sum("cannot give power now" in e for e in _pr.events) == 1) +_e2_rows, _e2 = drain_run(1500.0, dur=2600.0, cut=lambda u, t: u == "a" and ( + t < 600.0 or t >= 1400.0)) +check("...and a second episode, after the probe ends the first, logs again", + sum("cannot give power now" in e for e in _e2.events) == 2) +_cw_rows, _cw = drain_run(-1500.0, dur=300.0, cut=lambda u, t: u == "a") +_cw_cards = homeview.battery_rows(_cw, False, True) +check("while A waits, B may take the solar surplus, so its card does not " + "say 'This one does not charge'", + cmd(_cw_rows[-1])["b"] < 0.0 and _cw_cards[1]["why_key"] != "other_cycle") + def reject_a(c, t): """Every write to A is rejected, so A's link goes stale (not live).""" @@ -339,6 +358,65 @@ check("non-vacuous: filing the drain floor at N=1 (which moves no watt " "there) moves the digest, because the harness hashes the claims", _leak != _ref and _leak == _same) +# ============================================================================ # +print("\n6. the floor against every other claim (PR #154 review, seeded sweep)") +_rnd = random.Random(78) +_bad, _peak_above, _off_gave = [], 0, 0 +for _i in range(20000): + ma, mb = _rnd.choice((2500., 3000., 5000.)), _rnd.choice((1500., 2500.)) + ua = [Claim.limit("supervised", P_SAFETY, -ma, ma, actuator=A), + Claim.set("maintenance", P_MAINTENANCE, + _rnd.choice((500., 2000., 6000.)), "drain", actuator=A)] + if _rnd.random() < .2: + ua.append(Claim.limit("pack", P_SAFETY, -ma, + _rnd.choice((0., 800.)), actuator=A)) + ub = [Claim.limit("supervised", P_SAFETY, -mb, mb, actuator=B)] + _offb = _rnd.random() < .4 + if _offb: + ub.append(Claim.limit("mode", P_MODE, 0., 0., "off", actuator=B)) + if _rnd.random() < .15: + ub.append(Claim.limit("refused", P_SAFETY, -mb, 0., actuator=B)) + pin = allocator.pin_w(pre_resolve(ua)) + site = [Claim.set("loop", P_LOOP, _rnd.uniform(-6000., 8000.))] + if pin is not None and pin > 0.0: + site.append(Claim.limit("drain", P_MAINTENANCE, lo=pin)) + if _rnd.random() < .3: + site.append(Claim.set("arbitrage", P_ARBITRAGE, + _rnd.choice((-3000., 1000., 4000.)))) + pk = _rnd.uniform(0., 8000.) if _rnd.random() < .4 else None + if pk is not None: + site.append(Claim.limit("peak", P_PEAK, lo=pk)) + stop = _rnd.random() < .05 + if stop: + site.append(Claim.set("safety", P_SAFETY, 0.0, "stopped")) + r = resolve(ua + ub + site, units=UNITS) + s = dict(r.shares) + why = [] + if min(s.values()) < 0 < max(s.values()) or r.contradiction: + why.append("opposite or contradiction") + if stop and (r.target_w != 0.0 or any(s.values())): + why.append("stop not parked") + if not stop and pin is not None and pin > 0.0: + if r.target_w < pin or s[B] < 0: + why.append("below the floor, or B charges") + if pk is not None and pk > pin: + _peak_above += 1 + if r.allocated and r.target_w < min(pk, pin + mb): + why.append("peak floor not honoured") + if _offb and s[B] > 0: + _off_gave += 1 + if not (pk is not None and pk > pin): + why.append("Off B used for the drain") + if why: + _bad.append((_i, why, r.target_w, s, pin, pk)) +print(f" {_bad[:3]}; peak above the drain {_peak_above}, Off B gave for " + f"the peak {_off_gave}") +check("⭐ over 20000 seeded claim lists: never an opposite split or a " + "contradiction; a safety stop parks both; the site never goes below " + "the pin and B never charges; a peak floor above the drain is met; an " + "Off battery gives only for the peak floor, never for the drain", + not _bad and _peak_above > 1000 and _off_gave > 100) + print() if fails: print(f"{len(fails)} FAILED: {', '.join(fails)}") -- 2.54.0 From fbd884797d6ac95b9126d8273f72b95dc9a467d8 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Tue, 29 Sep 2026 22:08:47 +0200 Subject: [PATCH 086/105] OPT-11 P4 review: Cheap hours ignores the plan; midnight-stale forecast; stricter ids - Cheap hours only fills to the ceiling with or without a forecast, as the design (section 1) says. Skipping the sun's share cost 0.31 EUR on real 2026 prices (29.72 against P3's 29.41) and saved nothing on the P3 set. - A forecast reading from before local midnight is stale: until the integration refreshes, "left today" is still yesterday's 0 and "tomorrow" is really today. - Forecast entity ids must be sensor.[a-z0-9_]+ (they go into the /api/states/<id> path). - House profile: a stored day that is not a date, or is after today, is dropped instead of kept forever. - Text: the forecast line says "for the rest of today"; the learning line no longer promises "tomorrow" (a plan needs one full day). - Tests for four surviving review mutants (hour sample floor, the dear run after the cheap run, share by room, daytime use) and the fixes above. - Replay tool: `--fc zero` (a forecast of no sun). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/DOCS.md | 2 +- goodwe_controller/app/dayplan.py | 30 ++++--- goodwe_controller/app/modetrade.py | 21 ++--- goodwe_controller/app/packmode.py | 8 +- goodwe_controller/app/solarfc.py | 11 ++- goodwe_controller/app/ui_text/en.json | 2 +- goodwe_controller/app/ui_text/nl.json | 2 +- goodwe_controller/app/validate.py | 5 +- goodwe_controller/test_modes_p4.py | 96 ++++++++++++++++++----- goodwe_controller/tools/opt11p4_replay.py | 6 +- 10 files changed, 127 insertions(+), 56 deletions(-) diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 9b139fa..c0c4710 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -545,7 +545,7 @@ With battery modes on, these choices replace the *Charging and selling on price* - *Solar first* never charges from the grid. - The house use is the add-on's own measurement (grid + battery power) per hour, over the last 7 days. It needs one day of it before the first plan. - The plan is checked every 15 minutes. A planned level moves only by 1 kWh or 10 %, so a wobbling forecast does not flip it. -- No forecast, one older than 3 hours, or no house use yet: *Leftover solar* takes solar only and *Cheap hours only* fills to the top level. The Batteries screen says so. +- No forecast, one older than 3 hours or from before midnight, or no house use yet: *Leftover solar* takes solar only and *Cheap hours only* fills to the top level. The Batteries screen says so. - A battery needs its capacity (`inverters.capacity_kwh`) for a plan. **What always comes first.** diff --git a/goodwe_controller/app/dayplan.py b/goodwe_controller/app/dayplan.py index 89ac1e7..4bd8ecc 100644 --- a/goodwe_controller/app/dayplan.py +++ b/goodwe_controller/app/dayplan.py @@ -12,8 +12,10 @@ The sums (OPT-11-design section 1, "Excess solar", with the owner's answers): expensive run the cheap run is for, x the charge efficiency: `trust x sum_h max(0, forecast_h - house_h) x EFF`. * Solar first batteries take it first, up to the ceiling. What is left is - shared by the Leftover solar and Cheap hours batteries by their room. -* A Cheap hours battery charges from the grid up to `ceiling - its share`. + shared by the Leftover solar batteries by their room. +* Cheap hours only ignores the plan and fills to the ceiling, as in P3 and + the design (section 1). Skipping the sun's share cost money in the replay + (PR #156 review: 29.72 against 29.41 EUR on real 2026 prices). * A Leftover solar battery charges only up to what the house will draw from it in the expensive runs before the next cheap run, less its share: `min(ceiling, floor + house use / EFF) - share`. So it buys only the @@ -32,7 +34,7 @@ import statistics from dataclasses import dataclass from datetime import datetime, timedelta, timezone -from .packmode import CHEAP_HOURS, LEFTOVER_SOLAR, SOLAR_FIRST +from .packmode import LEFTOVER_SOLAR, SOLAR_FIRST from .tariff import BILLING_TZ EFF = 0.95 # charge (and discharge) efficiency @@ -67,6 +69,10 @@ class HouseProfile: def load(self, data): for day, hours in data.items(): + try: + datetime.strptime(str(day), "%Y-%m-%d") + except ValueError: + continue if not isinstance(hours, dict): continue row = {} @@ -105,8 +111,11 @@ class HouseProfile: return closed def _prune(self, lt): + """Keep the last `PROFILE_DAYS` days; a day after today (the clock + was wrong once) would never age out, so it goes too.""" keep = (lt.date() - timedelta(days=PROFILE_DAYS)).isoformat() - for d in [d for d in self.days if d < keep]: + today = lt.date().isoformat() + for d in [d for d in self.days if d < keep or d > today]: del self.days[d] def ready(self) -> bool: @@ -142,7 +151,7 @@ class Plan: sun_kwh: float # solar the batteries can count on fc_kwh: float # the forecast over the same span until: datetime # the expensive run the plan is for - targets: dict # name -> level % (LS and CH only) + targets: dict # name -> level % (Leftover solar only) need_kwh: dict # name -> kWh from the grid (0: none) share_kwh: dict # name -> kWh of solar counted for it @@ -195,7 +204,7 @@ def plan(forecast, house, runs, now, packs, *, trust_pct, floor_pct, usable = [p for p in packs if p.use and p.live and p.idle and p.soc is not None and p.capacity_kwh] sf = [p for p in usable if p.mode == SOLAR_FIRST] - price = [p for p in usable if p.mode in (LEFTOVER_SOLAR, CHEAP_HOURS)] + price = [p for p in usable if p.mode == LEFTOVER_SOLAR] sf_room = sum(_room(p, ceiling_pct) for p in sf) excess = max(0.0, sun - sf_room) rooms = {p.name: _room(p, ceiling_pct) for p in price} @@ -218,12 +227,9 @@ def plan(forecast, house, runs, now, packs, *, trust_pct, floor_pct, for p in price: sh = excess * rooms[p.name] / total_room if total_room > 0 else 0.0 sh_pct = sh / caps[p.name] * 100.0 - if p.mode == CHEAP_HOURS: - top = float(ceiling_pct) - else: - want = use_kwh * caps[p.name] / cap_sum / EFF - top = min(float(ceiling_pct), - float(floor_pct) + want / caps[p.name] * 100.0) + want = use_kwh * caps[p.name] / cap_sum / EFF + top = min(float(ceiling_pct), + float(floor_pct) + want / caps[p.name] * 100.0) level = max(0.0, top - sh_pct) targets[p.name] = round(level, 2) need[p.name] = round(_room(p, level), 3) diff --git a/goodwe_controller/app/modetrade.py b/goodwe_controller/app/modetrade.py index 5dcbc06..0b78e45 100644 --- a/goodwe_controller/app/modetrade.py +++ b/goodwe_controller/app/modetrade.py @@ -24,10 +24,10 @@ Roles (the page's Why line names them): Rules that keep this safe (tests: test_modes_p3.py): * every range holds 0 W (a mode may forbid a direction, never force one); * a Solar first battery never charges from the grid; - * P4: with a day plan (`targets`), a Leftover solar or Cheap hours battery - charges from the grid only up to its planned level, never above the - ceiling; with none, Cheap hours fills to the ceiling and Leftover solar - takes solar only (P3 option A, `charge_to()`); + * P4: with a day plan (`targets`), a Leftover solar battery charges from + the grid only up to its planned level, never above the ceiling; with + none it takes solar only (P3 option A). Cheap hours only fills to the + ceiling either way (`charge_to()`); * grid charging needs a measured peak guard that is clear and a measured headroom (SAFETY-45); the trade is sized to that headroom, whose aim is `peak_cap_w - peak_margin_w` (SAFETY-79). It starts only at START_W or @@ -98,12 +98,13 @@ def charge_to(p: Pack, ceiling_pct, targets=None): `targets` is the day plan (`dayplan.plan()`: name -> level), or None when there is none (no forecast, stale, or not configured). With no plan this is P3 option A exactly: Cheap hours to the ceiling, the others never. - With a plan, a Leftover solar or Cheap hours battery charges only to its - planned level (the sun fills the rest), and a battery the plan leaves out - falls back to the no-plan answer. Solar first never charges.""" - if targets is None or p.name not in targets: - return float(ceiling_pct) if p.mode in GRID_CHARGE_MODES else None - if p.mode not in PLAN_CHARGE_MODES: + With a plan, a Leftover solar battery charges only to its planned level + (the sun fills the rest); a battery the plan leaves out, Cheap hours only + included, gets the no-plan answer. Solar first never charges.""" + if p.mode in GRID_CHARGE_MODES: + return float(ceiling_pct) + if targets is None or p.name not in targets \ + or p.mode not in PLAN_CHARGE_MODES: return None t = targets[p.name] return None if t is None else min(float(ceiling_pct), float(t)) diff --git a/goodwe_controller/app/packmode.py b/goodwe_controller/app/packmode.py index 39f79db..82cac1e 100644 --- a/goodwe_controller/app/packmode.py +++ b/goodwe_controller/app/packmode.py @@ -49,10 +49,10 @@ SELLING_ENABLED = False # The modes that may charge from the grid in a cheap run with no day plan. # Leftover solar takes solar only then (owner decision 2026-09-29, option A). GRID_CHARGE_MODES = (CHEAP_HOURS,) -# OPT-11 P4: with a fresh solar forecast, the day plan (dayplan.py) may also -# let Leftover solar charge from the grid, by the shortfall only. Solar first -# never charges from the grid. -PLAN_CHARGE_MODES = (LEFTOVER_SOLAR, CHEAP_HOURS) +# OPT-11 P4: with a fresh solar forecast, the day plan (dayplan.py) lets +# Leftover solar charge from the grid, by the shortfall only. Cheap hours only +# ignores the plan (fills to the ceiling); Solar first never grid-charges. +PLAN_CHARGE_MODES = (LEFTOVER_SOLAR,) def enabled(opts) -> bool: diff --git a/goodwe_controller/app/solarfc.py b/goodwe_controller/app/solarfc.py index a2b262d..89977cd 100644 --- a/goodwe_controller/app/solarfc.py +++ b/goodwe_controller/app/solarfc.py @@ -24,8 +24,9 @@ state only. The unit is read, never guessed (the rule `pv.watts()` has). Without an hourly split, the day's energy is spread over a fixed bell from 06:00 to 20:00 local time (`BELL_FROM_H`, `BELL_TO_H`). -A reading older than `FRESH_S` is stale, and a stale or missing forecast is -no forecast: the day plan is off and every mode acts as in P3 option A. +A reading older than `FRESH_S`, or from before local midnight, is stale, +and a stale or missing forecast is no forecast: the day plan is off and +every mode acts as in P3 option A. """ import math @@ -238,14 +239,16 @@ def read(today_state, tomorrow_state, now: datetime, *, if today is None: return None, why at = _reported(today_state) - if at is None or (now - at).total_seconds() > FRESH_S \ + # A reading from before local midnight is yesterday's "left today" (0 + # after sunset) until the integration refreshes: stale, not a dark day. + if at is None or at < day0 or (now - at).total_seconds() > FRESH_S \ or (at - now).total_seconds() > 300: return None, STALE tomorrow = None if tomorrow_state is not None: t, _w = _day(tomorrow_state, day1, now, today=False) t_at = _reported(tomorrow_state) - if t is not None and t_at is not None \ + if t is not None and t_at is not None and t_at >= day0 \ and (now - t_at).total_seconds() <= FRESH_S: tomorrow = t return Forecast(today, tomorrow, at), None diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index dfe9347..27d8534 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -339,7 +339,7 @@ "tops_up": "Too little sun is forecast, so it charges some from the grid.", "no_forecast": "No solar forecast, so it charges from solar only." }, - "solar": {"line": "Solar forecast today: {kwh}, we count on {count}. Updated {at}.", "no_forecast": "No solar forecast now, so Leftover solar charges from solar only.", "learning": "The add-on is learning your house's use. The plan starts tomorrow."}, + "solar": {"line": "Solar forecast for the rest of today: {kwh}, we count on {count}. Updated {at}.", "no_forecast": "No solar forecast now, so Leftover solar charges from solar only.", "learning": "The add-on is learning your house's use. The plan starts after one full day."}, "today": { "not_planned": "Not planned yet.", "no_runs": "No cheap or expensive hours left today.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 532a5b4..410e29d 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -281,7 +281,7 @@ "tops_up": "Te weinig zon voorspeld, dus ze laadt wat van het net.", "no_forecast": "Geen zonneprognose, dus ze laadt alleen met zonne-energie." }, - "solar": {"line": "Zonneprognose vandaag: {kwh}, we rekenen op {count}. Bijgewerkt om {at}.", "no_forecast": "Nu geen zonneprognose, dus Overschot zonne-energie laadt alleen met zon.", "learning": "De add-on leert eerst het verbruik van uw huis. Het plan start morgen."}, + "solar": {"line": "Zonneprognose voor de rest van vandaag: {kwh}, we rekenen op {count}. Bijgewerkt om {at}.", "no_forecast": "Nu geen zonneprognose, dus Overschot zonne-energie laadt alleen met zon.", "learning": "De add-on leert eerst het verbruik van uw huis. Het plan start na één volle dag."}, "today": { "not_planned": "Nog niet gepland.", "no_runs": "Vandaag geen goedkope of dure uren meer.", diff --git a/goodwe_controller/app/validate.py b/goodwe_controller/app/validate.py index 4741263..e49e0ca 100644 --- a/goodwe_controller/app/validate.py +++ b/goodwe_controller/app/validate.py @@ -328,6 +328,7 @@ WHAT IS DELIBERATELY *NOT* REFUSED, because it is untidy rather than unsafe: """ import logging +import re from typing import NamedTuple from . import dayplan, messages, pv, solarfc @@ -2066,6 +2067,8 @@ def _margin_problems(opts: dict) -> list[str]: TRUST_RANGE_PCT = (30, 100) +# A Home Assistant sensor id; it goes into the /api/states/<id> path. +_SENSOR_ID = re.compile(r"sensor\.[a-z0-9_]+") FORECAST_KEYS = ("pv_forecast_entity", "pv_forecast_tomorrow_entity") @@ -2083,7 +2086,7 @@ def _forecast_problems(opts: dict) -> list[str]: e = opts.get(key) if e is None or e == "": continue - if not isinstance(e, str) or not e.strip().startswith("sensor."): + if not isinstance(e, str) or not _SENSOR_ID.fullmatch(e): out.append(f"{S(key)} must be a sensor, like " f"sensor.energy_production_today_remaining. It is " f"{messages.shown(e)}.") diff --git a/goodwe_controller/test_modes_p4.py b/goodwe_controller/test_modes_p4.py index 74b5b2e..a2c3e42 100644 --- a/goodwe_controller/test_modes_p4.py +++ b/goodwe_controller/test_modes_p4.py @@ -116,15 +116,15 @@ check("the harness bites: Leftover solar grid-charging with no plan moves " _read = solarfc.read -def _as_sunny(today, tomorrow, now, **kw): - return _read({"state": "200", "attributes": {"unit_of_measurement": - "kWh"}, +def _as_dark(today, tomorrow, now, **kw): + return _read({"state": "0", "attributes": {"unit_of_measurement": + "kWh"}, "last_updated": now.isoformat()}, None, now) -check("...and an unavailable forecast read as a sunny one moves " - "n2_sf_ch_fc_down (Cheap hours would skip its charge)", - _moved("n2_sf_ch_fc_down", lambda: setattr(solarfc, "read", _as_sunny), +check("...and an unavailable forecast read as a dark one moves " + "n2_sf_ls_fc_down (Leftover solar would buy its shortfall)", + _moved("n2_sf_ls_fc_down", lambda: setattr(solarfc, "read", _as_dark), lambda: setattr(solarfc, "read", _read))) # ============================================================================ # @@ -204,6 +204,18 @@ check("with it, tomorrow's sun is counted", fcs, _ = solarfc.read(st("12.5"), st("20.0", at=old), NOW) check("a stale tomorrow is dropped, today is kept", fcs is not None and fcs.tomorrow is None) +# Review (PR #156): just after local midnight the integration may not have +# refreshed yet, so "left today" is still yesterday's 0 and "tomorrow" is +# really today. That is stale, not a dark day. +MID = datetime(2026, 9, 22, 0, 10, tzinfo=L).astimezone(timezone.utc) +EVE = datetime(2026, 9, 21, 21, 30, tzinfo=L).astimezone(timezone.utc) +check("a today reading from before local midnight is stale (not 0 kWh)", + solarfc.read(st("0.0", at=EVE), st("15", at=EVE), MID) + == (None, solarfc.STALE)) +fcm, _ = solarfc.read(st("15", at=MID - timedelta(minutes=2)), + st("18", at=EVE), MID) +check("...and a tomorrow reading from before midnight is dropped", + fcm is not None and fcm.tomorrow is None) # ============================================================================ # print("3. the house profile") @@ -241,6 +253,14 @@ check("only the last 7 days are kept", len(hp9.days) <= 8) hp_rt = dayplan.HouseProfile(hp.dump()) check("dump and load give the same figures", hp_rt.hour_w(18) == round( hp.hour_w(18), 1) and hp_rt.ready()) +bogus = dayplan.HouseProfile({"2099-01-01": {str(h): 9e5 for h in range(24)}, + "zz": {str(h): 9e5 for h in range(24)}}) +check("a stored day that is not a date is dropped on load", + "zz" not in bogus.days) +bogus.add(UTC0, 500.0) +bogus.add(UTC0 + timedelta(hours=1), 500.0) +check("a stored day after today (a wrong clock) is pruned, not kept forever", + "2099-01-01" not in bogus.days) check("a bad stored profile is ignored, not fatal", not dayplan.HouseProfile({"x": "y", "2026-09-20": {"99": 1, "a": "b"}}).ready()) @@ -316,11 +336,38 @@ ch = dplan(12.0, packs=[pk(A, packmode.SOLAR_FIRST, 60.0), pk(B, packmode.CHEAP_HOURS, 30.0)]) ch_dark = dplan(1.0, packs=[pk(A, packmode.SOLAR_FIRST, 60.0), pk(B, packmode.CHEAP_HOURS, 30.0)]) -check("Cheap hours: dark fills to the ceiling (as P3)", - abs(ch_dark.targets[B] - 95.0) < 1e-6) -check("...and skips the part the sun covers on a partly sunny day", - ch.targets[B] < 95.0 and ch.share_kwh[B] > 0 - and abs(ch.targets[B] - (95.0 - ch.share_kwh[B] * 10.0)) < 0.01) +check("...and on a partly sunny day too: Cheap hours ignores the plan " + "(design section 1; review of PR #156)", B not in ch.targets + and B not in ch_dark.targets + and modetrade.charge_to(pk(B, packmode.CHEAP_HOURS, 30.0), 95.0, + {B: 40.0}) == 95.0) +# Review of PR #156: four mutants that survived. +_hi = {h: (3000.0 if 17 <= h < 22 else 2000.0 if 8 <= h < 17 else 600.0) + for h in range(24)} +check("a house that uses more by day leaves less sun: a higher level", + dplan(20.0, est=(lambda h: _hi[h], 600.0)).targets[B] + > dplan(20.0).targets[B] + 1.0) +_two = dplan(40.0, packs=[pk(A, packmode.SOLAR_FIRST, 60.0), + pk(B, packmode.LEFTOVER_SOLAR, 30.0), + pk("inverter-c", packmode.LEFTOVER_SOLAR, 80.0)]) +check("two Leftover solar batteries share the sun by their room (65:15)", + abs(_two.share_kwh[B] / _two.share_kwh["inverter-c"] - 6.5 / 1.5) + < 0.01) +_h = lambda hh: datetime(2026, 9, 21, hh, tzinfo=L).astimezone(timezone.utc) +_rp = priceruns.RunPlan(priceruns.Run(_h(13), _h(14), 0.02), + (priceruns.Run(_h(8), _h(9), 0.4), + priceruns.Run(_h(19), _h(20), 0.4)), + None, 0.3, None, True) +_pl = dayplan.plan(fc_of(12.0), EST, _rp, T0, PACKS, trust_pct=70, + floor_pct=20.0, ceiling_pct=95.0) +check("the plan is for the dear run after the cheap run, not an earlier one", + _pl is not None and _pl.until == _h(19)) +_hp = dayplan.HouseProfile() +for i in range(30): + _hp.add(_h(10) + timedelta(seconds=5 * i), 500.0) +_hp.add(_h(11), 500.0) +check("an hour with under 5 minutes of readings is not kept", + not any(10 in r for r in _hp.days.values())) check("trust 100 % counts more sun than 70 %: a lower level", dplan(12.0, trust=100).targets[B] < partly.targets[B]) check("...and the sun counted scales with the trust exactly", @@ -437,7 +484,8 @@ for i in range(5000): bad.append(("range without 0", p, lo, hi)) if t.roles[p.name] == modetrade.CHARGE and ( p.mode == packmode.SOLAR_FIRST - or p.soc >= min(95.0, targets[p.name])): + or p.soc >= (95.0 if p.mode == packmode.CHEAP_HOURS + else min(95.0, targets[p.name]))): bad.append(("charges past its level", p, targets)) check(f"decide() with a plan on 5000 random cases: ranges hold 0, nothing " f"charges at or past its level, Solar first never ({len(bad)} bad)", @@ -567,17 +615,17 @@ check("dark: ...only up to its level (the shortfall), not 95 %", check("dark: A rests while B charges", all(r["roles"][A] == modetrade.REST for r in charge)) -# Cheap hours on a partly sunny day: skips the part the sun covers. +# Cheap hours on a partly sunny day: ignores the plan, fills as in P3. rows, st_, c = run_day(SF_CH, fc=14.0, soc0={"a": 60.0, "b": 30.0}) charge = invariants("cheap hours, partly", rows, c) -tgt = nth([r["targets"][B] for r in rows if r["targets"]], 0, "a level") top = max(r["soc"]["b"] for r in rows) -print(f" cheap hours partly: B level {tgt:.1f} %, reached {top:.1f} %") -check("Cheap hours with sun forecast: charges, but stops below 95 %", - charge and present(tgt) and tgt < 90.0 and top <= tgt + 2.0) +print(f" cheap hours partly: B reached {top:.1f} %") +check("Cheap hours gets no planned level", + not any(r["targets"] and B in r["targets"] for r in rows)) rows_nf, _s, c_nf = run_day(SF_CH, fc=None, soc0={"a": 60.0, "b": 30.0}) -check("...and with the forecast down it fills towards 95 % as in P3", - max(r["soc"]["b"] for r in rows_nf) > top + 10.0) +check("Cheap hours with a sun forecast charges as with none (P3)", + charge and abs(max(r["soc"]["b"] for r in rows_nf) - top) < 1.0 + and top > 80.0) # The forecast goes away mid-run: Leftover solar stops at once (P3 option A). DROP = UTC0 + timedelta(hours=1, minutes=30) @@ -660,8 +708,8 @@ rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}, rp.m.datetime = datetime sb = homeview.solar_block(c, c.solar_fc.at) check("the forecast line names the forecast, what is counted and when", - sb["line"].startswith("Solar forecast today:") and "we count on" in - sb["line"] and sb["state"] == "plan") + sb["line"].startswith("Solar forecast for the rest of today:") + and "we count on" in sb["line"] and sb["state"] == "plan") why = homeview.day_key(c, B) check("B's Why key (plan, dark) is tops_up", why == "tops_up") check("...and says so in plain words", homeview.why_words(why) @@ -723,6 +771,12 @@ check("a forecast entity that is not a sensor is refused, in plain words", validate._forecast_problems({"pv_forecast_entity": "number.x"}) and "must be a sensor" in validate._forecast_problems( {"pv_forecast_entity": "number.x"})[0]) +check("an entity id with a path or odd characters is refused", + all(validate._forecast_problems({"pv_forecast_entity": e}) for e in + ("sensor.x/../config", "sensor.x?y=1", "sensor.X", "sensor.", + " sensor.x", "sensor.a b")) + and not validate._forecast_problems( + {"pv_forecast_entity": "sensor.energy_production_today_remaining"})) check("empty entities are fine", not validate._forecast_problems( {"pv_forecast_entity": "", "pv_forecast_tomorrow_entity": ""})) notes = [] diff --git a/goodwe_controller/tools/opt11p4_replay.py b/goodwe_controller/tools/opt11p4_replay.py index 38f833e..2559a3c 100644 --- a/goodwe_controller/tools/opt11p4_replay.py +++ b/goodwe_controller/tools/opt11p4_replay.py @@ -20,6 +20,8 @@ days; the 2026-09-24 PV recording is only in the live Home Assistant): * `national`: the Belgian day-ahead forecast itself, scaled to the site (one factor: the site's total over the national total, all days). It carries local weather differences too, so it is the harder test. +* `zero`: a forecast of no sun at all (is the gain the forecast's, or only + Leftover solar buying the evening's shortfall?). * `high`: `national` x 1.5. `missing`: the sensor is configured but reads `unavailable`. The sensor has Open-Meteo's shape (state = kWh left today, `wh_period` = Wh per hour); `--shape state` drops `wh_period` @@ -98,6 +100,8 @@ def forecast_table(kind, house, days): day_of = {h: datetime.fromtimestamp(h, LOCAL).date() for h in pv} if kind in ("perfect", "missing"): out = dict(pv) + elif kind == "zero": + out = {h: 0.0 for h in pv} elif kind == "recorded": ratio = {} for d in set(day_of.values()): @@ -176,7 +180,7 @@ def main(): ap.add_argument("--variant", default="p4_ls") ap.add_argument("--fc", default="recorded", choices=("none", "recorded", "national", "perfect", - "high", "missing")) + "high", "missing", "zero")) ap.add_argument("--prices", default="epex2025", choices=("epex2025", "real2026")) ap.add_argument("--shape", default="periods", -- 2.54.0 From 0b96e3191cd88f3a713fee502e6d6b6ab1c39167 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Tue, 29 Sep 2026 22:29:00 +0200 Subject: [PATCH 087/105] OPT-11 P4 review: records and text - DECISIONS: the Cheap hours change and why; the no-sun replay (the gain is Leftover solar buying the evening's shortfall; the forecast added 0.14 EUR); the reconstruction bias stated plainly. - DOCS: Cheap hours ignores the forecast; a reading from before midnight is stale. - The forecast line: "Solar still to come today: ..." (it is what is left, and it stays within the 12-word limit). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/OPT-11-battery-modes.md | 17 ++++++++++++----- goodwe_controller/DOCS.md | 2 +- goodwe_controller/app/ui_text/en.json | 2 +- goodwe_controller/app/ui_text/nl.json | 2 +- goodwe_controller/test_modes_p4.py | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md index 5a68ede..93897d6 100644 --- a/goodwe_controller/DECISIONS/OPT-11-battery-modes.md +++ b/goodwe_controller/DECISIONS/OPT-11-battery-modes.md @@ -94,7 +94,8 @@ P1 is its section 6 P1, and the pull request lists what was measured. - Leftover solar may then charge from the grid up to min(ceiling, floor + the house's use in the expensive runs / 0.95), less its sun share: only the shortfall. - - Cheap hours only charges up to the ceiling less its sun share. + - Cheap hours only ignores the plan and fills to the ceiling (design + section 1; review of #156, see the replay below). - Solar first never charges from the grid (owner, 2026-09-29). - The level is kept unless it moves by min(1 kWh, 10 %). With no plan (no, stale or failed forecast, no house profile, no capacity) every mode @@ -114,9 +115,15 @@ P1 is its section 6 P1, and the pull request lists what was measured. - the days' real 2026 quarter-hourly prices (held out): P2 32.26, option A 32.01, old trade 31.40, P4 29.19 (perfect 29.21, too high 29.28, missing 32.01). - - Solar first + Cheap hours only: 19.57 on both P3 and P4 (year-earlier - prices); on real 2026 prices P4 29.72 against P3's 29.41. Skipping the - sun's share does not pay for Cheap hours there; Leftover solar is the - mode the forecast pays for. + - Solar first + Cheap hours only, skipping its sun share (the first + build): 19.57 (same as P3) and 29.72 against P3's 29.41. The shorter, + moved runs left B lower, so later midday top-ups rested A while the sun + shone. Cheap hours now ignores the plan, which is P3 exactly. + - A forecast of no sun at all gives 19.14 and 29.33. So nearly all of the + gain is Leftover solar buying the evening's shortfall in the cheap run; + the forecast itself was worth 0.14 EUR in 16 September days. + - Bias: the site's solar is rebuilt from the same net use the replay + plays, and "recorded" keeps its hourly shape and adds only the national + daily error. Both favour P4; "national" (no house leakage) gives 29.25. No threshold was tuned to these days. The 2026-09-24 PV recording could not be replayed: it is only in the live Home Assistant. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 95e7be9..7c1060f 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -541,7 +541,7 @@ With battery modes on, these choices replace the *Charging and selling on price* **Solar forecast** (`pv_forecast_entity`, optional). A Home Assistant sensor with the solar energy still to come today, in kWh. These work: Forecast.Solar (`sensor.energy_production_today_remaining`), Solcast PV Forecast (`sensor.solcast_pv_forecast_forecast_remaining_today`) and Open-Meteo Solar Forecast (`sensor.energy_production_today_remaining`). Set `pv_forecast_tomorrow_entity` to the matching *tomorrow* sensor to plan a cheap run before midnight. - Before each cheap run the add-on asks: will the sun fill the batteries before the expensive hours? It counts on `solar_trust_pct` of the forecast (70 %), less what the house uses. Solar first batteries get that sun first. - *Leftover solar* then charges from the grid only the shortfall: what the house will draw from it in the expensive hours, less its share of the sun. Not up to the top level. -- *Cheap hours only* fills to the top level less its share of the sun. +- *Cheap hours only* ignores the forecast and fills to the top level. - *Solar first* never charges from the grid. - The house use is the add-on's own measurement (grid + battery power) per hour, over the last 7 days. It needs one day of it before the first plan. - The plan is checked every 15 minutes. A planned level moves only by 1 kWh or 10 %, so a wobbling forecast does not flip it. diff --git a/goodwe_controller/app/ui_text/en.json b/goodwe_controller/app/ui_text/en.json index 27d8534..e7f429b 100644 --- a/goodwe_controller/app/ui_text/en.json +++ b/goodwe_controller/app/ui_text/en.json @@ -339,7 +339,7 @@ "tops_up": "Too little sun is forecast, so it charges some from the grid.", "no_forecast": "No solar forecast, so it charges from solar only." }, - "solar": {"line": "Solar forecast for the rest of today: {kwh}, we count on {count}. Updated {at}.", "no_forecast": "No solar forecast now, so Leftover solar charges from solar only.", "learning": "The add-on is learning your house's use. The plan starts after one full day."}, + "solar": {"line": "Solar still to come today: {kwh}, we count on {count}. Updated {at}.", "no_forecast": "No solar forecast now, so Leftover solar charges from solar only.", "learning": "The add-on is learning your house's use. The plan starts after one full day."}, "today": { "not_planned": "Not planned yet.", "no_runs": "No cheap or expensive hours left today.", diff --git a/goodwe_controller/app/ui_text/nl.json b/goodwe_controller/app/ui_text/nl.json index 410e29d..291acb7 100644 --- a/goodwe_controller/app/ui_text/nl.json +++ b/goodwe_controller/app/ui_text/nl.json @@ -281,7 +281,7 @@ "tops_up": "Te weinig zon voorspeld, dus ze laadt wat van het net.", "no_forecast": "Geen zonneprognose, dus ze laadt alleen met zonne-energie." }, - "solar": {"line": "Zonneprognose voor de rest van vandaag: {kwh}, we rekenen op {count}. Bijgewerkt om {at}.", "no_forecast": "Nu geen zonneprognose, dus Overschot zonne-energie laadt alleen met zon.", "learning": "De add-on leert eerst het verbruik van uw huis. Het plan start na één volle dag."}, + "solar": {"line": "Nog verwachte zon vandaag: {kwh}, we rekenen op {count}. Bijgewerkt om {at}.", "no_forecast": "Nu geen zonneprognose, dus Overschot zonne-energie laadt alleen met zon.", "learning": "De add-on leert eerst het verbruik van uw huis. Het plan start na één volle dag."}, "today": { "not_planned": "Nog niet gepland.", "no_runs": "Vandaag geen goedkope of dure uren meer.", diff --git a/goodwe_controller/test_modes_p4.py b/goodwe_controller/test_modes_p4.py index a2c3e42..b0f1234 100644 --- a/goodwe_controller/test_modes_p4.py +++ b/goodwe_controller/test_modes_p4.py @@ -708,7 +708,7 @@ rows, st_, c = run_day(SF_LS, fc=1.0, soc0={"a": 60.0, "b": 30.0}, rp.m.datetime = datetime sb = homeview.solar_block(c, c.solar_fc.at) check("the forecast line names the forecast, what is counted and when", - sb["line"].startswith("Solar forecast for the rest of today:") + sb["line"].startswith("Solar still to come today:") and "we count on" in sb["line"] and sb["state"] == "plan") why = homeview.day_key(c, B) check("B's Why key (plan, dark) is tops_up", why == "tops_up") -- 2.54.0 From d77f1b1fdfdeca2377222f8f928808c11579c8ce Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Tue, 29 Sep 2026 22:40:14 +0200 Subject: [PATCH 088/105] SAFETY-83: peak guard outranks the maintenance drain at N=1 At N=1 the drain is the site SET at P_MAINTENANCE (60), so the peak floor (P_PEAK, 50) was not applied and the house imported what the drain left. Where the floor asks for more than the drain rate, main.py now refiles the peak claim at P_MAINTENANCE, so it wins; safety SETs still park everything. Nothing else changes: safety78_identity --diff against 35cdffe changes only cycles where the guard wanted more than the drain; N=2 is byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-78-drain-at-two.md | 5 +- .../DECISIONS/SAFETY-83-peak-over-drain.md | 35 +++ goodwe_controller/DOCS.md | 4 +- goodwe_controller/app/arbiter.py | 4 + goodwe_controller/app/main.py | 31 ++- goodwe_controller/test_safety78.py | 36 +-- goodwe_controller/test_safety83.py | 234 ++++++++++++++++++ goodwe_controller/tools/safety78_identity.py | 80 +++++- 8 files changed, 402 insertions(+), 27 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md create mode 100644 goodwe_controller/test_safety83.py diff --git a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md index 7604c47..8e03c3a 100644 --- a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md +++ b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md @@ -35,9 +35,8 @@ direction. Opposite splits stay forbidden. (`tools/safety78_identity.py`, which hashes the claims too). **Not changed (measured in the PR #154 review, follow-ups).** -- At N=1 a drain (60) outranks the peak floor (50), so the guard does not add - to it: a 5000 W house imports 3000 W against a 2500 W limit, a 6000 W house - 4000 W. Pre-existing, kept by the N=1 identity. +- At N=1 a drain (60) outranked the peak floor (50): a 5000 W house imported + 3000 W against a 2500 W limit. Fixed by [[SAFETY-83]]. - At N=2 a maintenance CHARGE in a cheap window has the same stall: the charging pack's `hi = -floor` against the loop asking the other to give is refused on 141 of 261 cycles. The mirror fix is a site `hi`, which can meet diff --git a/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md b/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md new file mode 100644 index 0000000..36ac6ff --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md @@ -0,0 +1,35 @@ +# SAFETY-83 - the peak guard outranks the maintenance drain at N=1 + +**Status: DECIDED 2026-09-29 (owner go, P1).** Follows SAFETY-78's "Not +changed" list. Tests: `test_safety83.py`. + +**The defect.** At N=1 the drain is the site SET at `P_MAINTENANCE` (60). The +peak floor is a limit at `P_PEAK` (50), and clause 2 applies only limits at or +above the winner, so the floor was ignored and the house imported what the +drain left. A 5000 W house under a 2500 W limit and a 2000 W drain banked +3000 W quarters; on the owner's settings (limit 3500, drain 2500, margin 50) a +breach starts at about 5950 W. + +**The fix.** While a drain owns the setpoint at N=1 and the peak floor asks +for more than the drain rate, `main.py` (`_peak_over_drain()`) refiles that +peak claim at `P_MAINTENANCE`. The arbiter then applies it: the target is the +floor, still inside the safety limits, and a safety SET (100) still parks +everything. Where the floor is at or below the drain rate nothing changes. + +- The order in effect is now the same at N=1 and N=2: safety limits and the + SAFETY-73 refusal > peak guard (with the SAFETY-79 margin) > maintenance > + modes > trade > loop (`arbiter.py`, beside the priorities). +- The drain keeps counting: the battery discharges at least the drain rate on + every cycle, so the cycle is not reset or stalled; it only ends sooner. +- Below the drain rate the rest is still exported (owner, 2026-09-29). +- Identity: `tools/safety78_identity.py --diff` against 35cdffe changes only + cycles where the guard asked for more than the drain; after such an episode + the commands are identical again and only the log and the idle loop's + integrator differ. N=2 is unchanged. + +**Not changed.** +- Between the drain rate and the peak aim, the house still imports what the + drain leaves (N=1 behaviour kept by the identity). At N=2 the loop covers it. +- A maintenance HOLD (0 W, 120 min, battery full) still outranks the peak + guard at N=1. Discharging there spends the charge the BMS balances on; it is + an owner question, not this fix. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 8f20953..3bc1834 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1626,7 +1626,7 @@ help - see "Why the tuning is what it is". | `maintenance_enabled` | false | Enable the monthly cycle | | `maintenance_interval_days` | 28 | Minimum gap between cycles | | `maintenance_start_hour` | 10 | Hour of day a due cycle begins | -| `maintenance_discharge_w` | 2000 | Drain rate (exports the surplus). Above `max_w` it is **clamped** to `max_w` — the drain phase SETs the setpoint and the arbiter bounds it, saying so on the status page (`limited by supervised(max_w)`). Warned about, not refused: the cycle still completes, just slower | +| `maintenance_discharge_w` | 2000 | Drain rate (exports the surplus). The peak guard may ask for more (SAFETY-83). Above `max_w` it is **clamped** to `max_w` — the drain phase SETs the setpoint and the arbiter bounds it, saying so on the status page (`limited by supervised(max_w)`). Warned about, not refused: the cycle still completes, just slower | | `maintenance_charge_w` | 2000 | Charge ceiling, capped again by peak headroom. Must stay **at or below `max_w`** or the cheap-window shaping (`hi = -maintenance_charge_w`) contradicts the supervised limit (`lo = -max_w`), the arbiter resolves it to **0 W**, and maintenance silently never charges in a cheap window — **the add-on refuses to start** | | `maintenance_soc_floor` | 11 | Drain target — stay just above the inverter's own floor. ⚠️ **This is not `peak_soc_floor`.** It is the depth the monthly recalibration deliberately goes to, once, on purpose; `peak_soc_floor` is the depth a money-saving discharge may never reach on any day. The right values differ (11 vs 20 as shipped), which is why they are two keys | | `maintenance_soc_target` | 99 | Charge target | @@ -1651,6 +1651,8 @@ maintenance schedule. With two or more batteries, the one being emptied gives its drain rate and the others only add power when the house needs more; none charges while it drains (SAFETY-78). Below the drain rate the rest is exported, as with one battery. +If the house would still go over the peak limit, the battery being emptied +gives more than its drain rate, with one battery too (SAFETY-83). #### Capacity-tariff exposure of the grid-following loop diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 42b7a18..ea1685c 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -76,6 +76,10 @@ from . import allocator P_SAFETY = 100 # stopped, inputs missing, shutting down, device limits P_MAINTENANCE = 60 # maintenance owns the actuator outright (drain, hold) P_PEAK = 50 # capacity-tariff peak shaving - costs real money +# The order in effect: safety limits and the SAFETY-73 refusal > the peak +# guard > maintenance > modes > trade > loop. A peak floor above a drain still +# binds: the `drain` site floor at N>=2 (SAFETY-78), refiled at P_MAINTENANCE +# at N=1 (SAFETY-83). Not a maintenance HOLD at N=1 (DECISIONS/SAFETY-83). P_MAINT_SHAPE = 40 # maintenance shaping the loop (charge-only) # OPT-04. §10.1 priority 3 - price arbitrage. ⚠️ ITS POSITION IS THE SPEC, NOT A # preference: P_PEAK (50) is ABOVE it so clause 2 lets the capacity-tariff floor diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index b33519e..fadcf1a 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -25,6 +25,7 @@ battery to zero on its own. Never "hold the last value to be safe". import asyncio import contextlib +import dataclasses import functools import json import logging @@ -2428,6 +2429,25 @@ class Controller: self._drain_waits = waits return floor if floor > 0.0 else None + def _peak_over_drain(self, claims, maint_results) -> None: + """SAFETY-83: at N=1 a peak floor above the drain rate outranks it. + + The drain is the site SET at P_MAINTENANCE, above the peak floor + (P_PEAK), so the floor did not bind and the house imported what the + drain left. Where the floor asks for more than the drain rate, it is + refiled at P_MAINTENANCE and wins; nothing else changes. Safety claims + (P_SAFETY) still outrank it. At N>=2 the `drain` floor does this. + """ + if len(self.inverters) != 1: + return + res = maint_results[0] + if res.phase != DRAIN or not res.owns_setpoint: + return + rate = float(res.setpoint_w or 0.0) + for i, c in enumerate(claims): + if c.source == peakguard.SOURCE and c.lo > rate: + claims[i] = dataclasses.replace(c, priority=P_MAINTENANCE) + def _maint_stop_off(self, machine, now) -> None: """OPT-11: stop this battery's maintenance cycle because it is off.""" if machine.phase == IDLE: @@ -3740,12 +3760,10 @@ class Controller: # claim is not sticky. Filed once and skipped next cycle, the floor # lapses and the actuator goes silently back to whatever was pushing the # peak. Which of the higher-priority claims outranks it is arbiter.py's - # business, not this block's - and the answer is already right: a - # maintenance DRAIN or HOLD owns the setpoint at P_MAINTENANCE and - # commands discharge or zero, neither of which can create offtake, while - # a maintenance CHARGE is only ever a P_MAINT_SHAPE limit (40) and is - # therefore bound by this floor. That is §9.1's "money outranks the - # maintenance schedule", now as a consequence of the priorities. + # business, not this block's: a maintenance DRAIN or HOLD owns the + # setpoint at P_MAINTENANCE, and a maintenance CHARGE is only ever a + # P_MAINT_SHAPE limit (40), bound by this floor. A floor above the drain + # rate still wins (SAFETY-78 at N>=2, `_peak_over_drain()` at N=1). # # ⚠️ AND IT IS NOT RUN AT ALL WITHOUT P1. `meter_source: off` is the # legacy single-entity path: there is no telegram stream, so @@ -4145,6 +4163,7 @@ class Controller: claims.append(Claim.limit("drain", P_MAINTENANCE, lo=drain, reason="maintenance drain", actuator=self.actuator_of("drain"))) + self._peak_over_drain(claims, maint_results) # --- OPT-11 P3: the site trade, after every unit claim -------------- # Sized from what the batteries may place with their modes and hard # limits (the loop bound), so none is asked for watts it may not give. diff --git a/goodwe_controller/test_safety78.py b/goodwe_controller/test_safety78.py index c3019a4..2757003 100644 --- a/goodwe_controller/test_safety78.py +++ b/goodwe_controller/test_safety78.py @@ -15,7 +15,7 @@ DECISIONS/SAFETY-78-drain-at-two.md has the record. 3. Battery modes on, a Cheap hours battery in a cheap run during the drain: no grid charge, and its card says why. 4. The peak guard binds during a drain, and the arbiter's order holds. -5. N=1 is byte-identical to release/1.0 5a4cdc2, and the harness bites. +5. The N=1 and N=2 digests hold, and the harness bites. 6. A seeded sweep of the floor against the loop, trades, the peak floor, a safety stop, refusals and an Off battery. @@ -326,26 +326,32 @@ check("⭐ the order holds: a safety stop parks everything; the peak floor " and _got["a grid charge (trade)"][1] == {A: 2000, B: 0}) # ============================================================================ # -print("\n5. N=1: byte-identical to release/1.0 5a4cdc2") -# Printed by `python3 tools/safety78_identity.py` on release/1.0 5a4cdc2 (the -# same file copied in, nothing else changed), goodwe-addon-checks:1, +print("\n5. the N=1 and N=2 digests") +# Printed by `python3 tools/safety78_identity.py`, goodwe-addon-checks:1, # 2026-09-29. 480 cycles each, draining throughout, every claim and the -# newest action-log line hashed. -AT_5A4CDC2 = { +# newest action-log line hashed. N=2: the same on release/1.0 35cdffe. N=1: +# re-pinned by SAFETY-83, whose `--diff` against 35cdffe changes only cycles +# where the peak guard asked for more than the drain (test_safety83.py). +PINNED = { "n1_drain": - "55fcfc4a0b9251746f315cfdea607a33640d3a81faf6604c4718a04bbc7dd776", + "b0f9ef44149163bc0acece537fe047871c00f0d9ea213e7a7fc8efc4ad3aa500", "n1_drain_modes": - "93867eb4ee4132b47c030668bd7f07587a353bced2461524e09421125c3c4edf", + "95ab82426e23bce308db3edebe18b1ab37d956952e9f521adce37150ce87ee8a", + "n1_drain_owner": + "10f7f42a6a952e899d739eb10c674874215c440f41ead7a9f2408bc9b4cb9ea4", + "n2_drain": + "055d83de0552d3a014dc73d87fdd697dde8b5933b8032f9b3a464ff0d08795fb", + "n2_drain_owner": + "05750347f1829c249f99154613f068f442a59ef59f409093907f6d0add78dd4c", } _now = s78.digests() -for k in AT_5A4CDC2: - print(f" {k} {'same' if _now[k] == AT_5A4CDC2[k] else 'DIFFERS'} " +for k in PINNED: + print(f" {k} {'same' if _now[k] == PINNED[k] else 'DIFFERS'} " f"{_now[k][:16]}") -check("⭐ at one inverter a drain under a house below, at and above its " - "rate, a surplus and a load over the peak limit, with battery modes " - "off and on, is byte-identical to 5a4cdc2: commands, reasons, roles, " - "trades and every claim", - _now == AT_5A4CDC2) +check("⭐ a drain under a house below, at and above its rate, a surplus and a " + "load over the peak limit, at N=1 (modes off and on) and N=2, matches " + "the pinned digests: commands, reasons, roles, trades and every claim", + _now == PINNED) Controller._drain_floor = lambda self, claims, results: ( 2000.0 if any(r.phase == DRAIN for r in results) else None) try: diff --git a/goodwe_controller/test_safety83.py b/goodwe_controller/test_safety83.py new file mode 100644 index 0000000..da2ec0a --- /dev/null +++ b/goodwe_controller/test_safety83.py @@ -0,0 +1,234 @@ +"""Runnable check for SAFETY-83: the peak guard outranks the drain at N=1. +`python3 test_safety83.py` + +At one inverter the monthly drain is the site SET at P_MAINTENANCE, above the +peak floor, so the house imported what the drain left and quarters went over +the peak limit. Now a peak floor above the drain rate is refiled at +P_MAINTENANCE and wins. Drives the REAL Controller (tools/opt11_identity.py's +harness on a P1 meter). DECISIONS/SAFETY-83-peak-over-drain.md has the record. + +1. A house of 5000, 6000 and 7000 W during a drain, limits 2500 and 3500, + margins 0 and 50: every quarter banks at or under the aim, the drain keeps + running, and without the fix the same runs go over. +2. The drain never makes the banked quarter worse than no drain, below and + above the drain rate; below it the rest is still exported. +3. The drain still ends, and the order holds: a lost reading parks the + battery, the rating caps the floor without a clash. +4. Only cycles where the guard wanted more than the drain change, and N=2 is + untouched. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import functools +import logging +import os +import sys +import tempfile + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11_identity as rig # noqa: E402 +import safety78_identity as s78 # noqa: E402 +import safety79_identity as s79 # noqa: E402 +from app.arbiter import P_MAINTENANCE, P_PEAK # noqa: E402 +from app.main import Controller # noqa: E402 +from app.maintenance import CHARGE, DRAIN # noqa: E402 + +fails = [] +TOL = 1.0 # watts over the aim a banked quarter may show + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def run(house, cap, margin, drain_w, *, maint=True, dur=2700.0, soc=None, + before=None, store=None, **extra): + """N=1 on a P1 meter; returns (rows, controller, banked quarters).""" + opts = dict(s79.P1, peak_cap_w=cap, peak_margin_w=margin, **extra) + if maint: + opts.update(maintenance_enabled=True, maintenance_start_hour=11, + maintenance_discharge_w=drain_w) + db = os.path.join(tempfile.mkdtemp(prefix="s83-"), "tariff.db") + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + try: + rows, c = rig.run(1, extra=opts, dur=dur, + load=house if callable(house) else lambda t: house, + soc=soc or (lambda u, t: 60.0), + cut=lambda u, t: False, before=before or s79._feed, + store=store) + finally: + rig.Controller = real + return rows, c, {b.start.strftime("%H:%M"): b.offtake_avg_w + for b in c.p1.blocks} + + +def without_fix(fn): + real = Controller._peak_over_drain + Controller._peak_over_drain = lambda self, claims, results: None + try: + return fn() + finally: + Controller._peak_over_drain = real + + +def cmd(r): + return dict(r[2])["a"] + + +# ============================================================================ # +print("1. banked quarters during a drain, N=1") +CASES = [(cap, drain, m, h) for cap, drain in ((2500, 2000), (3500, 2500)) + for m in (0, 50) for h in (5000.0, 6000.0, 7000.0)] +RES, OLD = {}, {} +for k in CASES: + cap, drain, m, h = k + RES[k] = run(h, cap, m, drain) + OLD[k] = without_fix(lambda: run(h, cap, m, drain)) + print(f" limit {cap} drain {drain} margin {m:>2} house {h:.0f}: " + f"banked {[round(v) for v in RES[k][2].values()]} W " + f"(before the fix {[round(v) for v in OLD[k][2].values()]} W)") +check("⭐ every quarter banks at or under the aim (limit - margin) plus 1 W, " + "for a 5000, 6000 and 7000 W house, limits 2500 and 3500, margins 0 " + "and 50", + all(len(b) >= 2 and max(b.values()) <= k[0] - k[2] + TOL + for k, (_r, _c, b) in RES.items())) +check("⭐ the drain keeps running: the phase is drain on every run and the " + "battery gives at least the drain rate on every cycle", + all(c.maints[0].phase == DRAIN and all(cmd(r) >= k[1] for r in rows) + for k, (rows, c, _b) in RES.items())) +check("...and where the house is over drain + aim, the battery gives more " + "than the drain rate, bound by the peak floor", + all(any(cmd(r) > k[1] and "limited by peak" in r[6] for r in rows) + for k, (rows, _c, _b) in RES.items() if k[3] - k[1] > k[0] - k[2])) +check("non-vacuous: without the fix the same runs bank over the limit " + "wherever the house is above drain + aim (the reported defect: 3000 W " + "at a 5000 W house against 2500 W)", + all(max(b.values()) > k[0] + 100.0 for k, (_r, _c, b) in OLD.items() + if k[3] - k[1] > k[0]) + and round(OLD[(2500, 2000, 50, 5000.0)][2]["11:15"]) == 3000) + +# ============================================================================ # +print("\n2. the drain never makes the banked quarter worse, N=1") +CAP, DRAIN_W, MARGIN = 3500, 2500, 50 # the owner's settings +AIM = CAP - MARGIN +WORSE = {} +for h in (1200.0, 3000.0, 5000.0, 6500.0, 7000.0): + _rows, _c, b = run(h, CAP, MARGIN, DRAIN_W) + _r0, _c0, b0 = run(h, CAP, MARGIN, DRAIN_W, maint=False) + WORSE[h] = (b, b0, _rows) + print(f" house {h:.0f}: with the drain {[round(v) for v in b.values()]}" + f" W, without {[round(v) for v in b0.values()]} W") +check("⭐ below and above the drain rate, every quarter with the drain banks " + "no more than the larger of the aim and the same quarter without it", + all(b[q] <= max(AIM, b0[q]) + TOL for b, b0, _r in WORSE.values() + for q in b)) +_r12 = WORSE[1200.0][2] +check("below the drain rate the battery gives the drain rate and exports the " + "rest (owner, 2026-09-29): 2500 W against a 1200 W house", + all(cmd(r) == DRAIN_W for r in _r12[1:])) + +# ============================================================================ # +print("\n3. the drain ends, and the order holds") +_e_rows, _e, _eb = run(6500.0, CAP, MARGIN, DRAIN_W, dur=1200.0, + soc=lambda u, t: max(5.0, 60.0 - t / 20.0)) +check("⭐ with the guard binding, the drain still reaches its floor and moves " + "to the charge phase, with no abort", + _e.maints[0].phase == CHARGE + and not any("abort" in e.lower() for e in _e.events)) + + +def blind_at(t0): + """The battery power reading goes missing at `t0`: a safety SET.""" + def before(c, t): + s79._feed(c, t) + if t >= t0 and not getattr(c.hass, "_blind", False): + real = c.hass.number + + async def number(e, invert=False): + return None if e == "sensor.batt_a" else await real(e, invert) + c.hass.number, c.hass._blind = number, True + return before + + +_s_rows, _s, _sb = run(6500.0, CAP, MARGIN, DRAIN_W, dur=600.0, + before=blind_at(300.0)) +print(f" reading lost at 300 s: last {cmd(_s_rows[-1]):+.0f} W, " + f"{_s_rows[-1][6]}") +check("⭐ a safety SET outranks the refiled peak floor: before the reading " + "goes the battery gives above the drain rate, after it it is at 0 W", + any(cmd(r) > DRAIN_W for r in _s_rows if r[0] < 300.0) + and all(cmd(r) == 0.0 for r in _s_rows if r[0] >= 400.0) + and _s_rows[-1][6].startswith("safety -> 0 W")) +_m_rows, _m, _mb = run(7000.0, 2500, 50, 2000, dur=900.0, max_w=3000) +print(f" max_w 3000, house 7000: last {cmd(_m_rows[-1]):+.0f} W, " + f"{_m_rows[-1][6]}") +check("⭐ the rating caps the floor without a clash: at max_w 3000 the " + "battery gives 3000 W, never 0 W, and nothing contradicts", + all(cmd(r) >= 2000.0 for r in _m_rows) + and cmd(_m_rows[-1]) == 3000.0 + and not any("CONTRADICTION" in (r[6] or "") for r in _m_rows)) + +# ============================================================================ # +print("\n4. only the cycles where the guard wanted more change") + + +def promoted(row): + return [c for c in row[-1][0] if c[0] == "peak"] + + +_id = {k: s78.run(**v)[0] for k, v in s78.SCENARIOS.items()} +_bad = [] +for k, rows in _id.items(): + for r in rows: + claims, guard = r[-1][0], r[-1][1] + rate = [c[3] for c in claims if c[0] == "maintenance" and c[2] == "set"] + pk = promoted(r) + if k.startswith("n2"): + ok = all(c[1] == P_PEAK for c in pk) + elif s78.wanted_more(r): + ok = ([c[1] for c in pk] == [P_MAINTENANCE] + and r[1] == guard[1] and "limited by peak" in r[6]) + else: + ok = (all(c[1] == P_PEAK for c in pk) + and (not rate or r[1] == rate[0])) + if not ok: + _bad.append((k, r[0], r[1], r[6], pk)) +_more = {k: sum(map(s78.wanted_more, rows)) for k, rows in _id.items()} +print(f" cycles with the guard above the drain: {_more}; bad {_bad[:3]}") +check("⭐ at N=1, on every cycle where the guard asks for more than the drain " + "the peak claim is refiled at P_MAINTENANCE and the target is its floor; " + "on every other cycle the peak claim stays at P_PEAK and the target is " + "the drain rate", + not _bad and all(_more[k] > 50 for k in _id if k.startswith("n1"))) +check("⭐ at N=2 the peak claim is never refiled (the SAFETY-78 floor does " + "that job), and test_safety78.py part 5 holds N=2 to the digests of " + "release/1.0 35cdffe", not _bad) + + + +def store_hold(): + st = rig._Store() + st.data["phase"], st.data["phase_started"] = "hold", rig.BASE.isoformat() + return st + + +_h_rows, _h, _hb = run(6000.0, 2500, 50, 2000, dur=600.0, store=store_hold()) +check("a maintenance HOLD at N=1 is not changed (DECISIONS/SAFETY-83, not " + "changed): the battery stays at 0 W with the house over the limit", + _h.maints[0].phase == "hold" and _h.peak_guard.engaged + and _h.peak_guard.floor_w > 0.0 + and all(cmd(r) == 0.0 for r in _h_rows)) + +print() +if fails: + print(f"{len(fails)} FAILED: {', '.join(fails)}") + sys.exit(1) +print("all checks passed") diff --git a/goodwe_controller/tools/safety78_identity.py b/goodwe_controller/tools/safety78_identity.py index 0304829..06af703 100644 --- a/goodwe_controller/tools/safety78_identity.py +++ b/goodwe_controller/tools/safety78_identity.py @@ -13,11 +13,18 @@ no watt still moves the digest. The `_modes` scenarios run battery modes on, Cheap hours only, over opt11p3_identity's prices. Uses only the API release/1.0 5a4cdc2 has, so the same file runs on both trees; test_safety78.py part 5 holds this tree to the digests printed there. + +SAFETY-83 adds the owner's settings (limit 3500, drain 2500, margin 50) with a +house that goes over drain + aim and back, and N=2 runs of both. At N=1 the +peak floor now outranks the drain where it asks for more, so the N=1 digests +moved; `--dump FILE` on the base tree and `--diff FILE` here list every +changed cycle and whether the peak guard wanted more than the drain on it. """ import functools import hashlib import os +import pickle import sys import tempfile @@ -47,14 +54,25 @@ def store_cheap(n): return s +def load_owner(t): + """Below the 2500 W drain, above it, over drain + aim (5950 W), back.""" + return (1200.0, 3000.0, 6500.0, 3000.0, -1500.0)[min(int(t // 480), 4)] + + +OWNER = {"peak_cap_w": 3500, "peak_margin_w": 50, + "maintenance_discharge_w": 2500} + SCENARIOS = { "n1_drain": dict(n=1), "n1_drain_modes": dict(n=1, modes=True), + "n1_drain_owner": dict(n=1, load=load_owner, extra=OWNER), + "n2_drain": dict(n=2), + "n2_drain_owner": dict(n=2, load=load_owner, extra=OWNER), } -def run(n, *, modes=False, dur=DUR): - extra = dict(s79.P1, **DRAIN) +def run(n, *, modes=False, dur=DUR, load=load, extra=None): + extra = dict(s79.P1, **DRAIN, **(extra or {})) if modes: extra.update(p3.ARB, battery_modes_enabled=True) seen, extra_rows = [], [] @@ -99,7 +117,65 @@ def digests() -> dict: return {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} +FIELDS = ("t", "target", "commands", "loop reason", "integrator", + "saturation", "why", "allocation") +XFIELDS = ("claims", "guard", "roles", "trade", "phase", "log length", + "newest log line") + + +def wanted_more(row) -> bool: + """Did the peak guard ask for more than the drain rate on this cycle?""" + claims, guard = row[-1][0] or (), row[-1][1] + rate = [c[3] for c in claims if c[0] == "maintenance" and c[2] == "set"] + return (bool(rate) and guard is not None and bool(guard[0]) + and guard[1] is not None and guard[1] > max(rate)) + + +def diff(base: dict, now: dict) -> dict: + """Per scenario: (cycles, changed, changed where the guard wanted more on + either tree, changed cycles whose commands differ without that).""" + out = {} + for k, rows in now.items(): + old = base.get(k) + if old is None: + continue + ch = [i for i, (a, b) in enumerate(zip(old, rows)) if a != b] + ch += list(range(min(len(old), len(rows)), max(len(old), len(rows)))) + more = [i for i in ch if i < min(len(old), len(rows)) + and (wanted_more(old[i]) or wanted_more(rows[i]))] + cmd = [i for i in ch if i not in more + and (i >= min(len(old), len(rows)) + or old[i][1:3] != rows[i][1:3])] + fields = set() + for i in set(ch) - set(more) - set(cmd): + fields |= {FIELDS[j] for j in range(8) if old[i][j] != rows[i][j]} + fields |= {XFIELDS[j] for j in range(7) + if old[i][8][j] != rows[i][8][j]} + out[k] = (len(rows), ch, more, cmd, sorted(fields)) + return out + + +def all_rows() -> dict: + return {k: run(**v)[0] for k, v in SCENARIOS.items()} + + if __name__ == "__main__": + if "--dump" in sys.argv: + with open(sys.argv[sys.argv.index("--dump") + 1], "wb") as f: + pickle.dump(all_rows(), f) + sys.exit(0) + if "--diff" in sys.argv: + with open(sys.argv[sys.argv.index("--diff") + 1], "rb") as f: + base = pickle.load(f) + for k, (n, ch, more, cmd, fields) in diff(base, all_rows()).items(): + rest = sorted(set(ch) - set(more)) + print(f"{k}: {n} cycles, {len(ch)} changed, {len(more)} with the " + f"guard above the drain, {len(rest)} others " + f"({len(cmd)} with a different target or command" + + (f"; the rest differ only in {', '.join(fields)}" + if fields else "") + ")" + + (f", first changed t={ch[0] * rig.TICK:.0f} s" if ch else "")) + sys.exit(0) if "--summary" in sys.argv: for k, v in SCENARIOS.items(): rows = run(**v)[0] -- 2.54.0 From 3f69c174afa3a3fcfc7dda22a3ce70bd5e1a9951 Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Tue, 29 Sep 2026 22:50:46 +0200 Subject: [PATCH 089/105] SAFETY-83: grade the refile at its boundary, and N=2 on its own A floor exactly at the drain rate stays at P_PEAK (kills `lo >= rate`), and part 4's N=2 check no longer shares its failure list with N=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_safety83.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/goodwe_controller/test_safety83.py b/goodwe_controller/test_safety83.py index da2ec0a..25ce45a 100644 --- a/goodwe_controller/test_safety83.py +++ b/goodwe_controller/test_safety83.py @@ -25,6 +25,7 @@ import logging import os import sys import tempfile +import types HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) @@ -34,9 +35,9 @@ logging.disable(logging.WARNING) import opt11_identity as rig # noqa: E402 import safety78_identity as s78 # noqa: E402 import safety79_identity as s79 # noqa: E402 -from app.arbiter import P_MAINTENANCE, P_PEAK # noqa: E402 +from app.arbiter import Claim, P_MAINTENANCE, P_PEAK # noqa: E402 from app.main import Controller # noqa: E402 -from app.maintenance import CHARGE, DRAIN # noqa: E402 +from app.maintenance import CHARGE, DRAIN, MaintResult # noqa: E402 fails = [] TOL = 1.0 # watts over the aim a banked quarter may show @@ -201,18 +202,33 @@ for k, rows in _id.items(): and (not rate or r[1] == rate[0])) if not ok: _bad.append((k, r[0], r[1], r[6], pk)) +_bad1 = [b for b in _bad if b[0].startswith("n1")] +_bad2 = [b for b in _bad if b[0].startswith("n2")] _more = {k: sum(map(s78.wanted_more, rows)) for k, rows in _id.items()} print(f" cycles with the guard above the drain: {_more}; bad {_bad[:3]}") check("⭐ at N=1, on every cycle where the guard asks for more than the drain " "the peak claim is refiled at P_MAINTENANCE and the target is its floor; " "on every other cycle the peak claim stays at P_PEAK and the target is " "the drain rate", - not _bad and all(_more[k] > 50 for k in _id if k.startswith("n1"))) + not _bad1 and all(_more[k] > 50 for k in _id if k.startswith("n1"))) check("⭐ at N=2 the peak claim is never refiled (the SAFETY-78 floor does " "that job), and test_safety78.py part 5 holds N=2 to the digests of " - "release/1.0 35cdffe", not _bad) + "release/1.0 35cdffe", not _bad2) +# The rule itself, at the boundary: a floor AT the drain rate changes nothing. +_one = types.SimpleNamespace(inverters=[None]) +_edge = {} +for lo in (1999.5, 2000.0, 2000.5): + cl = [Claim.set("maintenance", P_MAINTENANCE, 2000.0, DRAIN), + Claim.limit("peak", P_PEAK, lo=lo, reason="quarter peak")] + Controller._peak_over_drain(_one, cl, [MaintResult(DRAIN, True, 2000.0, + False, [])]) + _edge[lo] = cl[1].priority +check("at the boundary: a floor at or below the 2000 W drain stays at P_PEAK, " + "a floor 0.5 W above it is refiled at P_MAINTENANCE", + _edge == {1999.5: P_PEAK, 2000.0: P_PEAK, 2000.5: P_MAINTENANCE}) + def store_hold(): st = rig._Store() -- 2.54.0 From 56cafefa79c7eacfce6b19fc72b110b2b414a1b2 Mon Sep 17 00:00:00 2001 From: admin <gschrooyen@gmail.com> Date: Tue, 29 Sep 2026 22:52:52 +0200 Subject: [PATCH 090/105] SAFETY-83: a refiled peak floor stays under a safety SET, graded directly Kills M5 (refiled at P_SAFETY) on its own sentence, not only through the per-cycle claim check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_safety83.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/goodwe_controller/test_safety83.py b/goodwe_controller/test_safety83.py index 25ce45a..10c77f1 100644 --- a/goodwe_controller/test_safety83.py +++ b/goodwe_controller/test_safety83.py @@ -35,7 +35,8 @@ logging.disable(logging.WARNING) import opt11_identity as rig # noqa: E402 import safety78_identity as s78 # noqa: E402 import safety79_identity as s79 # noqa: E402 -from app.arbiter import Claim, P_MAINTENANCE, P_PEAK # noqa: E402 +from app.arbiter import (Claim, P_MAINTENANCE, P_PEAK, P_SAFETY, # noqa + resolve) from app.main import Controller # noqa: E402 from app.maintenance import CHARGE, DRAIN, MaintResult # noqa: E402 @@ -229,6 +230,15 @@ check("at the boundary: a floor at or below the 2000 W drain stays at P_PEAK, " "a floor 0.5 W above it is refiled at P_MAINTENANCE", _edge == {1999.5: P_PEAK, 2000.0: P_PEAK, 2000.5: P_MAINTENANCE}) +_stop = [Claim.set("maintenance", P_MAINTENANCE, 2000.0, DRAIN), + Claim.limit("peak", P_PEAK, lo=4000.0, reason="quarter peak"), + Claim.set("safety", P_SAFETY, 0.0, "inputs missing")] +Controller._peak_over_drain(_one, _stop, [MaintResult(DRAIN, True, 2000.0, + False, [])]) +check("⭐ and a refiled floor stays under a safety SET: the site resolves " + "to 0 W", _stop[1].priority == P_MAINTENANCE + and resolve(_stop).target_w == 0.0) + def store_hold(): st = rig._Store() -- 2.54.0 From bc6d744c6cfaffe2c46e8c40f79941e3947c0d9c Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Wed, 30 Sep 2026 13:41:47 +0200 Subject: [PATCH 091/105] SAFETY-83 review: banked month peak and no false alarm during a drain test_safety83 part 1: under a month peak banked above the limit the drain is lifted to peak - margin, and a drain the guard raises (steady or with 5 s spikes that saturate it) gives no 'Load too high' alarm; the part 3 overload still does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_safety83.py | 54 ++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/goodwe_controller/test_safety83.py b/goodwe_controller/test_safety83.py index 10c77f1..bd020ff 100644 --- a/goodwe_controller/test_safety83.py +++ b/goodwe_controller/test_safety83.py @@ -9,7 +9,8 @@ harness on a P1 meter). DECISIONS/SAFETY-83-peak-over-drain.md has the record. 1. A house of 5000, 6000 and 7000 W during a drain, limits 2500 and 3500, margins 0 and 50: every quarter banks at or under the aim, the drain keeps - running, and without the fix the same runs go over. + running, no 'Load too high' alarm, and without the fix the same runs go over. + Under a month peak banked above the limit the aim is that peak - margin. 2. The drain never makes the banked quarter worse than no drain, below and above the drain rate; below it the rest is still exported. 3. The drain still ends, and the order holds: a lost reading parks the @@ -35,6 +36,7 @@ logging.disable(logging.WARNING) import opt11_identity as rig # noqa: E402 import safety78_identity as s78 # noqa: E402 import safety79_identity as s79 # noqa: E402 +from app import tariff # noqa: E402 from app.arbiter import (Claim, P_MAINTENANCE, P_PEAK, P_SAFETY, # noqa resolve) from app.main import Controller # noqa: E402 @@ -51,13 +53,19 @@ def check(name, cond): def run(house, cap, margin, drain_w, *, maint=True, dur=2700.0, soc=None, - before=None, store=None, **extra): - """N=1 on a P1 meter; returns (rows, controller, banked quarters).""" + before=None, store=None, month_peak=None, **extra): + """N=1 on a P1 meter; returns (rows, controller, banked quarters). + `month_peak` banks that quarter earlier in the month.""" opts = dict(s79.P1, peak_cap_w=cap, peak_margin_w=margin, **extra) if maint: opts.update(maintenance_enabled=True, maintenance_start_hour=11, maintenance_discharge_w=drain_w) db = os.path.join(tempfile.mkdtemp(prefix="s83-"), "tariff.db") + if month_peak is not None: + tariff.PeakStore(db)._db.execute( + "INSERT INTO monthly_peak VALUES (?, ?, ?, NULL)", + (tariff.month_key(rig.BASE), month_peak, + "2026-09-02T10:00:00+00:00")).connection.commit() real = rig.Controller rig.Controller = functools.partial(real, peak_db_path=db) try: @@ -85,6 +93,11 @@ def cmd(r): return dict(r[2])["a"] +def alarmed(c): + """Did SAFETY-81's 'Load too high' alarm fire on this run?""" + return any("PEAK_GUARD_SATURATED" in e for e in c.events) + + # ============================================================================ # print("1. banked quarters during a drain, N=1") CASES = [(cap, drain, m, h) for cap, drain in ((2500, 2000), (3500, 2500)) @@ -116,6 +129,39 @@ check("non-vacuous: without the fix the same runs bank over the limit " all(max(b.values()) > k[0] + 100.0 for k, (_r, _c, b) in OLD.items() if k[3] - k[1] > k[0]) and round(OLD[(2500, 2000, 50, 5000.0)][2]["11:15"]) == 3000) +# A hob cycling: one 5 s spike to 11000 W every 150 s on a 6000 W house. Each +# spike saturates the guard for one cycle, shorter than ALARM_HOLD_S. +_sat = [] + + +def _spiky_feed(c, t): + s79._feed(c, t) + _sat.append(bool(c.peak_guard is not None and c.peak_guard.saturated)) + + +_k_rows, _k, _kb = run(lambda t: 11000.0 if t % 150 < 5 else 6000.0, + 3500, 50, 2500, before=_spiky_feed) +check("⭐ a drain the guard raises gives no 'Load too high' alarm (SAFETY-81), " + "steady or with 5 s spikes that saturate the guard", + not any(alarmed(c) for _r, c, _b in RES.values()) + and any(_sat) and not alarmed(_k)) + +# Owner (SAFETY-79): under a month peak banked above the limit, the aim is that +# peak - margin, during a drain too. Owner's settings, peak banked at 4500 W. +BANK = {h: (run(h, 3500, 50, 2500, month_peak=4500.0), + without_fix(lambda: run(h, 3500, 50, 2500, month_peak=4500.0))) + for h in (6500.0, 7500.0)} +for h, (new, old) in BANK.items(): + print(f" month peak 4500, house {h:.0f}: banked " + f"{[round(v) for v in new[2].values()]} W (before the fix " + f"{[round(v) for v in old[2].values()]} W)") +check("⭐ under a month peak of 4500 W: a 7500 W house banks at 4450 W " + "(peak - margin, not the 3450 W cap aim), was 5000 W; a 6500 W house " + "stays under the drain alone at 4000 W", + all(4430.0 <= v <= 4450.0 + TOL for v in BANK[7500.0][0][2].values()) + and max(BANK[7500.0][1][2].values()) > 4900.0 + and all(round(v) in (4000, 4014) + for v in BANK[6500.0][0][2].values())) # ============================================================================ # print("\n2. the drain never makes the banked quarter worse, N=1") @@ -177,6 +223,8 @@ check("⭐ the rating caps the floor without a clash: at max_w 3000 the " all(cmd(r) >= 2000.0 for r in _m_rows) and cmd(_m_rows[-1]) == 3000.0 and not any("CONTRADICTION" in (r[6] or "") for r in _m_rows)) +check("...and there, with the battery at its rating and the house still over, " + "the 'Load too high' alarm does fire", alarmed(_m)) # ============================================================================ # print("\n4. only the cycles where the guard wanted more change") -- 2.54.0 From 43a52e7f60cd000d1aab6bdf4b407032eadab41c Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Wed, 30 Sep 2026 19:47:15 +0200 Subject: [PATCH 092/105] SAFETY-84: maintenance charge at N=2 no longer stalls At N>=2 a cheap-window maintenance charge files a site `hi` (`charge`, P_MAINT_SHAPE) equal to what the charging pack's own `hi` places, so the other pack never has to give against it. The charge is sized to the quarter's headroom under the peak aim so it yields to the peak guard, and to 0 W under a site safety stop. N=1 byte-identical (safety84_identity). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-78-drain-at-two.md | 2 +- .../DECISIONS/SAFETY-84-charge-at-two.md | 46 ++ goodwe_controller/DOCS.md | 3 + goodwe_controller/app/allocator.py | 5 + goodwe_controller/app/arbiter.py | 8 + goodwe_controller/app/main.py | 40 ++ goodwe_controller/app/messages.py | 1 + goodwe_controller/test_arbiter.py | 12 +- goodwe_controller/test_peak_margin.py | 12 +- goodwe_controller/test_peakguard.py | 26 +- goodwe_controller/test_safety84.py | 452 ++++++++++++++++++ goodwe_controller/tools/safety84_identity.py | 119 +++++ 12 files changed, 709 insertions(+), 17 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md create mode 100644 goodwe_controller/test_safety84.py create mode 100644 goodwe_controller/tools/safety84_identity.py diff --git a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md index 8e03c3a..8c8b0e0 100644 --- a/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md +++ b/goodwe_controller/DECISIONS/SAFETY-78-drain-at-two.md @@ -40,4 +40,4 @@ direction. Opposite splits stay forbidden. - At N=2 a maintenance CHARGE in a cheap window has the same stall: the charging pack's `hi = -floor` against the loop asking the other to give is refused on 141 of 261 cycles. The mirror fix is a site `hi`, which can meet - the peak floor's `lo` (0 W), so it is not this card. + the peak floor's `lo` (0 W), so it is not this card. Fixed by [[SAFETY-84]]. diff --git a/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md b/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md new file mode 100644 index 0000000..a12a744 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md @@ -0,0 +1,46 @@ +# SAFETY-84 - a maintenance charge at two inverters + +**Status: DECIDED 2026-09-30.** Follows SAFETY-78's "Not changed" list. +Tests: `test_safety84.py`; identity: `tools/safety84_identity.py`. + +**The defect.** In a cheap window the charging pack files its own +`hi = -charge` (P_MAINT_SHAPE). At N>=2 the loop's site target sat above it +(a house to cover, or its 400 W slew step from 0 W), so the other pack had to +give while this one charged. The allocator refuses opposite directions +(SAFETY-31), so the site sat at 0 W whatever the house +(`tools/safety84_identity.py` on 9d5b7d1: 436 of 480 cycles refused). N=1 +was fine. + +**The fix.** +- While a pack's own limits make it charge at N>=2, `main.py` files a site + limit `charge`, `hi` = what that pack's own `hi` places + (`allocator.hi_w()`, whole W as the allocator rounds). The site target is + never above it, so the other pack only adds power in the same direction. + Opposite splits stay forbidden. Mirror of SAFETY-78's `drain` floor. +- Peak guard first (owner order, SAFETY-83). The charge is sized to the + quarter's headroom under the aim (`charge_headroom_w()`, cap or banked peak + minus `peak_margin_w`), so it charges less instead of stopping: the meter + sits on the aim and the guard does not need to step in. Where the house + alone is over the aim the guard engages, the shaping is suspended as before + (`shaping_suspended()`) and no `charge` is filed, so the guard's `lo` and + this `hi` never meet in one cycle (no `lo > hi`, no park at 0 W). + Without the headroom sizing the aim still held (the suspension did it), but + a battery gave power back on 285 of 540 cycles at a 3000 W house + (test_safety84.py part 2). +- A site stop (a safety SET above P_MAINT_SHAPE) sizes the charge to 0 W: + the unit `hi` is a hard limit, so a charge under a 0 W stop needs the other + pack to give. It was refused, with an ARBITER line, on most cycles of the + stop (test_safety84.py part 4). The stop still parked the site at 0 W. +- A pack that cannot take the charge (a refusal, a full pack, a stale link) + files no ceiling; the other pack follows the loop. +- Not filed at N=1: byte-identical (`tools/safety84_identity.py`, which hashes + every claim, in and out of a cheap window and under a banked peak). + +**Not changed.** +- At N=1 the charge is not sized to the headroom: the guard still suspends it + and the battery gives until the quarter is safe. The same sizing would fit + there; that is an owner question, not this fix. +- Outside a cheap window (`hi = 0`, solar only) nothing is filed, at any N. +- A HOLD (SAFETY-86) and the "Battery is not keeping up" alarm (SAFETY-85) + are untouched. In the identity runs that alarm's log line comes as often at + N=2 as at N=1 (2 in 480 cycles). diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 36e9935..4eeabac 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1666,6 +1666,9 @@ others only add power when the house needs more; none charges while it drains (SAFETY-78). Below the drain rate the rest is exported, as with one battery. If the house would still go over the peak limit, the battery being emptied gives more than its drain rate, with one battery too (SAFETY-83). +In a cheap window the battery being filled charges and the others only add +charge; none gives while it charges. The charge is cut to what keeps the +15-minute peak at the limit minus `peak_margin_w` (SAFETY-84). #### Capacity-tariff exposure of the grid-following loop diff --git a/goodwe_controller/app/allocator.py b/goodwe_controller/app/allocator.py index a84ef55..5640fbf 100644 --- a/goodwe_controller/app/allocator.py +++ b/goodwe_controller/app/allocator.py @@ -354,6 +354,11 @@ def pin_w(b): return float(pv) if lo > hi else float(_clamp_int(round(float(pv)), lo, hi)) +def hi_w(b): + """A unit's upper hard limit as `plan()` narrows it to whole W (SAFETY-84).""" + return float(_int_envelope(b)[1]) + + def loop_bound(bounds, live=None): """OPT-11. `(lo, hi)`: what the units can place when the LOOP decides. diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index ea1685c..0cb2999 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -80,6 +80,8 @@ P_PEAK = 50 # capacity-tariff peak shaving - costs real money # guard > maintenance > modes > trade > loop. A peak floor above a drain still # binds: the `drain` site floor at N>=2 (SAFETY-78), refiled at P_MAINTENANCE # at N=1 (SAFETY-83). Not a maintenance HOLD at N=1 (DECISIONS/SAFETY-83). +# A cheap-window charge is suspended while the peak guard holds and, at N>=2, +# sized to the quarter's headroom (SAFETY-84). P_MAINT_SHAPE = 40 # maintenance shaping the loop (charge-only) # OPT-04. §10.1 priority 3 - price arbitrage. ⚠️ ITS POSITION IS THE SPEC, NOT A # preference: P_PEAK (50) is ABOVE it so clause 2 lets the capacity-tariff floor @@ -194,6 +196,12 @@ CLAIM_SCOPE = { # charge against the drain (circulation, refused, 0 W). A site `lo`, # never filed at N=1. DECISIONS/SAFETY-78-drain-at-two.md. "drain": SCOPE_SITE, + # main.py: `Claim.limit("charge", P_MAINT_SHAPE, hi=...)`, SAFETY-84. The + # mirror of `drain` for a cheap-window maintenance charge at N>=2: the site + # target may not go above what the charging pack's own `hi` asks, or a + # sibling would have to give against it. Never filed at N=1. + # DECISIONS/SAFETY-84-charge-at-two.md. + "charge": SCOPE_SITE, # --- UNIT: about one pack, one inverter, one device ------------------- # main.py: `Claim.limit("device", P_SAFETY, self.dev_min, self.dev_max, diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 92258ea..0b23909 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -2533,6 +2533,39 @@ class Controller: if c.source == peakguard.SOURCE and c.lo > rate: claims[i] = dataclasses.replace(c, priority=P_MAINTENANCE) + def _charge_headroom(self, floor: float, claims) -> float: + """SAFETY-84: at N>=2 a cheap-window charge pulls no more than the + quarter's headroom under the peak aim (`charge_headroom_w()`), so it + yields just enough to the peak guard, and nothing under a site stop + (its 0 W would need the other pack to give). N=1 is unchanged.""" + if len(self.inverters) < 2: + return floor + if any(c.kind == SET and c.actuator == ACTUATOR_SITE + and c.priority > P_MAINT_SHAPE for c in claims): + return 0.0 + room = peakguard.charge_headroom_w(self.peak_guard) + return floor if room is None else min(floor, room) + + def _charge_ceiling(self, claims): + """SAFETY-84: the site `hi` for a cheap-window charge at N>=2, or None. + + The charging pack's own `hi` (P_MAINT_SHAPE) makes it charge; above + that the other pack would have to give (opposite directions, refused, + 0 W). So the site target stays at or below it. Not filed at N=1, nor + when the pack's own limits cancel the charge (a refusal, a stale link). + DECISIONS/SAFETY-84-charge-at-two.md. + """ + if len(self.inverters) < 2: + return None + live = set(self.live_units()) + ceiling = 0.0 + for inv in self.inverters: + u = self.actuator_of("maintenance", inv) + b = pre_resolve([c for c in claims if c.actuator == u]) + if u in live and not b.contradiction and b.hi < 0.0: + ceiling += allocator.hi_w(b) + return ceiling if ceiling < 0.0 else None + def _maint_stop_off(self, machine, now) -> None: """OPT-11: stop this battery's maintenance cycle because it is off.""" if machine.phase == IDLE: @@ -4188,6 +4221,7 @@ class Controller: floor = maintenance_charge_floor( self.maint.cfg.charge_w, self.peak_fc, self.peak_aim_w()) + floor = self._charge_headroom(floor, claims) if floor > 0: hi, reason = -floor, "cheap-window charge" # PER-INVERTER, like the SET above and for the same reason - @@ -4273,6 +4307,12 @@ class Controller: reason="maintenance drain", actuator=self.actuator_of("drain"))) self._peak_over_drain(claims, maint_results) + # --- SAFETY-84: a cheap-window charge is a ceiling over the site ---- + charge = self._charge_ceiling(claims) + if charge is not None: + claims.append(Claim.limit("charge", P_MAINT_SHAPE, hi=charge, + reason="maintenance charge", + actuator=self.actuator_of("charge"))) # --- OPT-11 P3: the site trade, after every unit claim -------------- # Sized from what the batteries may place with their modes and hard # limits (the loop bound), so none is asked for watts it may not give. diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index f571e33..fa6a4b4 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -835,6 +835,7 @@ WHY_LIMIT = { "pack": "the battery level", "reserve": "the battery reserve", "maintenance": "battery maintenance", + "charge": "battery maintenance", "refused": "a battery that refuses power", } diff --git a/goodwe_controller/test_arbiter.py b/goodwe_controller/test_arbiter.py index 0df5eac..b367003 100644 --- a/goodwe_controller/test_arbiter.py +++ b/goodwe_controller/test_arbiter.py @@ -149,7 +149,7 @@ check("...and `source` is still the first positional argument, which is what " Claim.limit("device", P_SAFETY, -1, 1).source == "device") print() -print("ARB-03 2. the split: fourteen sources, each classified where it is BUILT") +print("ARB-03 2. the split: fifteen sources, each classified where it is BUILT") # The classification is graded against what each claim is ABOUT, restated here # so that the table in arbiter.py and the expectation in a test are not the same # sentence read twice. test_peakguard.py part 10f pins this set against main.py's @@ -175,6 +175,10 @@ SITE_SOURCES = { "drain": "the site target may not go below a pinned maintenance " "drain, or a sibling would charge against it. Filed at N>1 " "only", + # SAFETY-84. + "charge": "the site target may not go above a cheap-window maintenance " + "charge, or a sibling would give against it. Filed at N>1 " + "only", } UNIT_SOURCES = { "device": "one inverter's own reported min/max rating", @@ -206,9 +210,9 @@ for _src, _why in sorted(SITE_SOURCES.items()): print(f" site {_src:<11} {_why}") for _src, _why in sorted(UNIT_SOURCES.items()): print(f" unit {_src:<11} {_why}") -check("all FOURTEEN claim sources are classified, and only those fourteen", +check("all FIFTEEN claim sources are classified, and only those fifteen", set(CLAIM_SCOPE) == set(SITE_SOURCES) | set(UNIT_SOURCES)) -check("the seven that are about the GRID CONNECTION are site claims", +check("the eight that are about the GRID CONNECTION are site claims", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == set(SITE_SOURCES)) check("the seven that are about a PACK, a DEVICE or one write are per-inverter", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == set(UNIT_SOURCES)) @@ -230,7 +234,7 @@ check("...and with none configured at all, likewise", all(actuator_for(s, "inverter-a", ()) == ACTUATOR_SITE for s in CLAIM_SCOPE)) check("with TWO the identity breaks and the split becomes real: the seven " "per-inverter sources route to the unit this controller drives, the " - "seven site sources stay on the grid connection", + "eight site sources stay on the grid connection", {s: actuator_for(s, "inverter-a", TWO) for s in CLAIM_SCOPE} == {**{s: "inverter-a" for s in UNIT_SOURCES}, **{s: ACTUATOR_SITE for s in SITE_SOURCES}}) diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py index 116562a..0631b57 100644 --- a/goodwe_controller/test_peak_margin.py +++ b/goodwe_controller/test_peak_margin.py @@ -64,9 +64,19 @@ _default = rig.digests() for k in ED739D4: print(f" {k:7} margin 0 {'same' if _zero[k] == ED739D4[k] else 'DIFFERS'}" f" {_zero[k][:16]}, default {_default[k][:16]}") +# SAFETY-84 changes n2_maint ON PURPOSE: on 9d5b7d1 its N=2 cheap-window +# charge was refused on 214 of 540 cycles (site at 0 W); now none is. +# Printed on the SAFETY-84 tree the same way (margin 0). +SAFETY84_N2_MAINT = \ + "95722b262f1bcf504493d7b5babc3895799ac56cc15f5d2ccdbe7c9f04adfcbb" check("⭐ at N=1 and N=2, with and without battery modes and with a " "maintenance charge, margin 0 is " - "byte-identical to ed739d4", _zero == ED739D4) + "byte-identical to ed739d4 (n2_maint apart, below)", + {k: v for k, v in _zero.items() if k != "n2_maint"} + == {k: v for k, v in ED739D4.items() if k != "n2_maint"}) +check("...and n2_maint at margin 0 is the SAFETY-84 digest: the N=2 charge " + "that 9d5b7d1 refused on 214 of 540 cycles now runs (test_safety84.py)", + _zero["n2_maint"] == SAFETY84_N2_MAINT != ED739D4["n2_maint"]) check("...and the default (key absent) changes every scenario, so the " "scenarios do reach the margin", all(_default[k] != ED739D4[k] for k in ED739D4)) diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 87e8137..d936a45 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2687,9 +2687,13 @@ check("...and so does the persistent notification, which outlives the page and " # state of charge, it never closes discharge (a `lo`, not a `hi`), and it is # never filed at N=1, so the sweeps below still see {device, supervised, # loop}. DECISIONS/SAFETY-78-drain-at-two.md. +# ⚠️ SAFETY-84 ADDED `charge`, ITS MIRROR, AND IT IS NOT THE RESERVE EITHER. A +# site `hi` at P_MAINT_SHAPE, filed only at N>=2 while a pack's cheap-window +# maintenance charge makes it charge, equal to that pack's own `hi`. Never at +# N=1. DECISIONS/SAFETY-84-charge-at-two.md. CLAIM_SOURCES = {"device", "supervised", "failsafe", "safety", "peak", "arbitrage", "maintenance", "loop", "circulation", - "sign_site", "pack", "refused", "mode", "drain"} + "sign_site", "pack", "refused", "mode", "drain", "charge"} # The two appends that file a claim BUILT ELSEWHERE in the method. Named here so # that a THIRD such indirection reads as an unrecognised append rather than as a # silent gap in the scan. @@ -2731,7 +2735,7 @@ check("every `claims.append(...)` in main.py's cycle is one this scan can READ " "- a claim filed through a shape it cannot parse has to fail here rather " "than be counted as nothing, which is how a scan like this goes quietly " "vacuous", len(_appends) >= 10 and None not in _filed) -check("...and the sources that cycle can file are EXACTLY these FOURTEEN. THIS " +check("...and the sources that cycle can file are EXACTLY these FIFTEEN. THIS " "is what makes part 10 a tripwire: replay_loop() hand-builds the claim " "list, so it cannot see a claim main.py adds - and a loop-side SoC " "reserve is a new source. Filing one takes this line red on the line it " @@ -2871,7 +2875,7 @@ print(" site: " + ", ".join(sorted(s for s, v in CLAIM_SCOPE.items() + " | per-inverter: " + ", ".join(sorted(s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT))) check("...and the split is the one ARB-03 argued, with SAFETY-31's and " - "SAFETY-30's, OPT-09's and SAFETY-78's additions: the seven about the GRID CONNECTION " + "SAFETY-30's, OPT-09's, SAFETY-78's and SAFETY-84's additions: the eight about the GRID CONNECTION " "are site claims and the five about a pack, a device or one write are " "per-inverter. `circulation` is a site claim because its quantity is " "defined over the roster and is identically zero for any one unit; " @@ -2881,7 +2885,7 @@ check("...and the split is the one ARB-03 argued, with SAFETY-31's and " "against that unit's OWN measured power", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == {"loop", "peak", "arbitrage", "safety", "circulation", "sign_site", - "drain"} + "drain", "charge"} and {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == {"device", "supervised", "failsafe", "maintenance", "pack", "refused", "mode"}) @@ -2986,7 +2990,7 @@ check("⚠️ AND THIS IS THE BREAKING HALF. Give the same Controller a second " "loop": ACTUATOR_SITE, "peak": ACTUATOR_SITE, "arbitrage": ACTUATOR_SITE, "safety": ACTUATOR_SITE, "circulation": ACTUATOR_SITE, "sign_site": ACTUATOR_SITE, - "drain": ACTUATOR_SITE}) + "drain": ACTUATOR_SITE, "charge": ACTUATOR_SITE}) check("...and the roster it was restored to is the shipped one, so nothing " "below inherits a two-inverter Controller", c_src.units == (app_main.UNIT_A,) and len(c_src.inverters) == 1) @@ -3065,13 +3069,13 @@ _unit_sources_unrouted = [ if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT and "," not in r[1]] print(f" {len(_direct)} direct appends, each read at its own line: " + ", ".join(f"main.py:{ln} {s} -> {a}" for s, a, ln in _routing)) -check("all FIFTEEN of `Controller.cycle()`'s DIRECT appends route through " +check("all SIXTEEN of `Controller.cycle()`'s DIRECT appends route through " "`self.actuator_of(<string literal>)`, so this scan can read the routing " "of EVERY one of them. An append that computed its actuator, or omitted " "the argument, or hand-wrote a string, fails HERE rather than being " "silently skipped - which is how a scan like this goes quietly vacuous, " "and 10f is in this file because that already happened once", - len(_direct) == 15 + len(_direct) == 16 and all(a is not None and a.startswith("self.actuator_of('") for _s, a, _ln in _routing)) check("⚠️ AND AT EVERY ONE OF THE ELEVEN THE LITERAL IT ROUTES THROUGH IS THE " @@ -3088,7 +3092,7 @@ check("⚠️ AND EVERY PER-INVERTER APPEND NAMES THE INVERTER IT IS ABOUT. " "site-scoped sources and is the whole defect for a per-inverter one: a " "`device` limit built inside the roster loop and routed without `inv` " "files inverter B's rating on inverter A, where it binds the wrong " - "share. Nine of the fifteen appends are SCOPE_UNIT - `device`, " + "share. Nine of the sixteen appends are SCOPE_UNIT - `device`, " "`supervised`, `failsafe`, maintenance's two, OPT-09's `pack`, " "SAFETY-73's two `refused` and OPT-11's `mode` - and all nine pass one. " "SAFETY-30's `sign_site` is deliberately NOT one of them: it is filed on " @@ -3105,8 +3109,8 @@ check("...and the only appends this pin does NOT reach are the two that file a " "arbitrage.claim() by test_arbitrage.py", sorted(_indirect) == sorted(CLAIM_BUILDERS) and len(_direct) + len(_indirect) == len(_appends)) -check("...and between them the seventeen appends account for exactly the " - "fourteen " +check("...and between them the eighteen appends account for exactly the " + "fifteen " "sources 10f pins, so the routing pin and the source set are one scan " "and neither can drift from the other", {s for s, _a, _ln in _routing} | set(CLAIM_BUILDERS.values()) @@ -3167,7 +3171,7 @@ check("...and naming those three is not an accident of this fixture but the " {c.source for c in _cl2} == CLAIM_SOURCES - {"failsafe", "safety", "maintenance", "peak", "arbitrage", "circulation", "sign_site", - "refused", "mode", "drain"}) + "refused", "mode", "drain", "charge"}) # ⚠️ AND NOW THE HALF THAT WAS EVIDENCE-SHAPED AND OBSERVED NOTHING. The three # checks above grade WHICH ACTUATOR each claim lands on. They say nothing about # WHOSE NUMBERS the bound is built from - and those are two different defects diff --git a/goodwe_controller/test_safety84.py b/goodwe_controller/test_safety84.py new file mode 100644 index 0000000..09492fe --- /dev/null +++ b/goodwe_controller/test_safety84.py @@ -0,0 +1,452 @@ +"""Runnable check for SAFETY-84: a maintenance charge at N=2 no longer stalls. +`python3 test_safety84.py` + +In a cheap window the charging battery's own `hi` makes it charge. At two +inverters the loop's site target sat above it, the other battery had to give, +the allocator refused the opposite directions and the site sat at 0 W. Now a +site `hi` (`charge`, P_MAINT_SHAPE) keeps the site target at or below the +charge, and the charge is sized to the quarter's headroom so it yields to the +peak guard. Drives the REAL Controller (tools/safety84_identity.py's harness). +DECISIONS/SAFETY-84-charge-at-two.md has the record. + +1. N=2 in a cheap window, house below, at and above the charge rate and a + solar surplus: the charge runs, no opposite split, no refusal, and it ends. +2. The peak guard: the charge yields just enough to hold the aim (cap - + margin, and a banked month peak - margin); over the aim the guard wins + and nothing parks; no false 'Load too high'. +3. Outside a cheap window nothing changes. +4. A safety stop parks both batteries without a refusal, and the charge + resumes after it. +5. One battery refusing, or dropped, and B Off with battery modes on. +6. A trade outranked by the charge (P_ARBITRAGE < P_MAINT_SHAPE). +7. A seeded sweep of the ceiling against the loop, trades, refusals, packs + and modes. +8. The N=1 digests equal release/1.0 9d5b7d1, and the N=2 ones are pinned. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import logging +import os +import random +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11_identity as rig # noqa: E402 +import opt11p3_identity as p3 # noqa: E402 +import safety84_identity as s84 # noqa: E402 +from app import arbitrage, packmode # noqa: E402 +from app.arbiter import (Claim, P_ARBITRAGE, P_LOOP, P_MAINT_SHAPE, # noqa + P_MODE, P_SAFETY, resolve) +from app.main import Controller # noqa: E402 +from app.maintenance import CHARGE, HOLD # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +A, B = "inverter-a", "inverter-b" +AIM = 3450.0 # peak_cap_w 3500 - peak_margin_w 50 +TOL = 10.0 # W over the aim a banked quarter may show (SAFETY-81) + + +def cmd(r): + return dict(r[2]) + + +def refused(rows): + return sum(1 for r in rows if r[7] and "REFUSED" in r[7]) + + +def opposite(rows): + return sum(1 for r in rows if cmd(r)["a"] * cmd(r)["b"] < 0) + + +def charge_claims(r): + """The site `charge` claims main.py handed resolve() on row `r`.""" + return [c for c in r[-1][0] if c[0] == "charge"] + + +def banked(c): + return [b.offtake_avg_w for b in c.p1.blocks] + + +def alarmed(c): + """Did SAFETY-81's 'Load too high' alarm fire on this run?""" + return any("PEAK_GUARD_SATURATED" in e for e in c.events) + + +def run(house, n=2, **kw): + return s84.run(n, load=house if callable(house) else lambda t: house, + **kw) + + +def rise(u, t): + """A fills from 60 % (1 % a cycle); B stays at 50 %.""" + return min(100.0, 60.0 + t / 5.0) if u == "a" else 50.0 + + +# ============================================================================ # +print("1. N=2 in a cheap window: the charge runs whatever the house uses") +RUNS = {h: run(h, dur=900.0) for h in (800.0, 2000.0, 3000.0, -1500.0)} +for h, (rows, c) in RUNS.items(): + print(f" house {h:+.0f} W: last A {cmd(rows[-1])['a']:+.0f} W, B " + f"{cmd(rows[-1])['b']:+.0f} W; {rows[-1][6]}; refusals " + f"{refused(rows)}") +check("⭐ below, at and above the charge rate and under a solar surplus, " + "battery A charges on EVERY cycle (it used to sit at 0 W from the " + "first cycle)", + all(cmd(r)["a"] < 0.0 for rows, _c in RUNS.values() for r in rows) + and all(c.maints[0].phase == CHARGE for _r, c in RUNS.values())) +check("⭐ no cycle splits the site both ways and the allocator refuses " + "nothing: battery B never gives while A charges", + all(opposite(rows) == 0 and refused(rows) == 0 + and all(cmd(r)["b"] <= 0.0 for r in rows) + for rows, _c in RUNS.values())) +check("...and nothing is logged per cycle: no ARBITER line in the action log", + not any("ARBITER" in e for _r, c in RUNS.values() for e in c.events)) +check("with the quarter's headroom above the charge rate, A charges at the " + "full 2000 W and the Why names the charge", + all(cmd(r)["a"] == -2000.0 for h in (800.0, -1500.0) + for r in RUNS[h][0]) + and "limited by charge" in RUNS[800.0][0][-1][6]) +print(f" Why: {RUNS[800.0][1].why_words}") +check("...and the page's Why reads as at one battery: 'held back by battery " + "maintenance'", + RUNS[800.0][1].why_words.endswith("held back by battery maintenance")) + +_end_rows, _end = run(800.0, dur=600.0, soc=rise) +check("⭐ and the charge ENDS: A reaches its 99 % target and the cycle moves " + "on to its hold, with no refusal on the way", + _end.maints[0].phase == HOLD and refused(_end_rows) == 0 + and any("charge complete" in e for e in _end.events)) + +_real = Controller._charge_ceiling +Controller._charge_ceiling = lambda self, claims: None +try: + _bite, _bc = run(800.0, dur=120.0) +finally: + Controller._charge_ceiling = _real +print(f" without the ceiling: refusals {refused(_bite)}/{len(_bite)}, " + f"last A {cmd(_bite[-1])['a']:+.0f} W") +check("non-vacuous: with the ceiling taken out, the same fixture refuses " + "every cycle and parks A at 0 W (the reported defect)", + refused(_bite) == len(_bite) and cmd(_bite[-1])["a"] == 0.0) + +# ============================================================================ # +print("\n2. the peak guard outranks the charge") +_q_rows, _q = run(3000.0, dur=2700.0) +print(f" house 3000: banked {[round(v) for v in banked(_q)]} W, last A " + f"{cmd(_q_rows[-1])['a']:+.0f} W") +check("⭐ house 3000 W, aim 3450 W: the charge yields just enough - every " + "banked quarter lands on the aim, not on house + 2000 W", + len(banked(_q)) >= 2 + and all(AIM - TOL <= v <= AIM + TOL for v in banked(_q))) +check("...and it yields by charging less, not by stopping: A charges and B " + "is 0 W on every cycle, nothing is refused, no 'Load too high'", + all(cmd(r)["a"] < 0.0 and cmd(r)["b"] == 0.0 for r in _q_rows) + and refused(_q_rows) == 0 and not alarmed(_q)) +check("...and the peak guard never has to step in (the charge stays under " + "what the quarter can afford)", + not any(r[-1][1] and r[-1][1][0] for r in _q_rows)) + +_o_rows, _o = run(5000.0, dur=2700.0) +_both = [r for r in _o_rows + if charge_claims(r) and any(c[0] == "peak" for c in r[-1][0])] +print(f" house 5000: banked {[round(v) for v in banked(_o)]} W, last " + f"{cmd(_o_rows[-1])}, {_o_rows[-1][6]}") +check("⭐ house 5000 W, over the aim alone: the peak guard wins - every " + "banked quarter is at or under the aim, both batteries give in the " + "same direction, nothing is refused and nothing parks at 0 W", + all(v <= AIM + TOL for v in banked(_o)) and opposite(_o_rows) == 0 + and refused(_o_rows) == 0 + and sum(cmd(r)["a"] + cmd(r)["b"] > 0.0 for r in _o_rows) > 100) +check("...and the guard's `lo` never meets the charge's `hi` in one cycle " + "(the charge is suspended while the guard holds)", not _both) +check("...with no false 'Load too high' alarm", not alarmed(_o)) + +_k_rows, _k = run(3000.0, dur=2700.0, month_peak=4000.0) +print(f" month peak 4000 banked, house 3000: banked " + f"{[round(v) for v in banked(_k)]} W") +check("⭐ under a month peak banked at 4000 W the aim is 3950 W: the charge " + "takes the extra headroom and every banked quarter lands on 3950 W", + len(banked(_k)) >= 2 + and all(3950.0 - TOL <= v <= 3950.0 + TOL for v in banked(_k)) + and refused(_k_rows) == 0 and not alarmed(_k)) + +_real = Controller._charge_headroom +Controller._charge_headroom = lambda self, floor, claims: floor +try: + _nh_rows, _nh = run(3000.0, dur=2700.0) +finally: + Controller._charge_headroom = _real +_gave = sum(1 for r in _nh_rows if cmd(r)["a"] > 0.0 or cmd(r)["b"] > 0.0) +print(f" without the headroom: cycles a battery gives {_gave}, banked " + f"{[round(v) for v in banked(_nh)]} W") +check("non-vacuous: charging at the full rate instead, the guard has to " + "step in and the batteries give back on many cycles", + _gave > 50) + +# ============================================================================ # +print("\n3. outside a cheap window nothing changes") +_d = {h: run(h, cheap=False, dur=600.0) for h in (800.0, -1500.0)} +check("⭐ no `charge` claim is filed outside a cheap window: B covers the " + "house, the charge takes solar only, nothing is refused", + not any(charge_claims(r) for rows, _c in _d.values() for r in rows) + and cmd(_d[800.0][0][-1]) == {"a": 0.0, "b": 800.0} + and cmd(_d[-1500.0][0][-1])["a"] < 0.0 + and all(refused(rows) == 0 for rows, _c in _d.values())) + + +# ============================================================================ # +print("\n4. a safety stop outranks the charge") + + +def blind_at(t0, t1): + """A's power reading is missing from `t0` to `t1`: a safety SET.""" + def before(c, t): + s84.feed(True)(c, t) + if not getattr(c.hass, "_blind", False): + real = c.hass.number + + async def number(e, invert=False): + if e == "sensor.batt_a" and t0 <= c.hass.t < t1: + return None + return await real(e, invert) + c.hass.number, c.hass._blind = number, True + return before + + +_s_rows, _s = run(800.0, dur=600.0, before=blind_at(150.0, 400.0)) +_stop = [r for r in _s_rows if 175.0 <= r[0] < 400.0] +_last = _s_rows[79] # t = 395 s, still without the reading +print(f" A's reading lost 150-400 s: {_last[2]}, {_last[6]}; after: " + f"{_s_rows[-1][2]}") +check("⭐ with a reading gone the safety SET parks both batteries at 0 W " + "with no refusal and no ARBITER line (it used to refuse every cycle)", + all(cmd(r) == {"a": 0.0, "b": 0.0} for r in _stop) + and _last[0] == 395.0 and _last[6].startswith("safety -> 0 W") + and refused(_s_rows) == 0 and not any("ARBITER" in e for e in _s.events)) +check("...and the charge ran before and runs again after", + cmd(_s_rows[20])["a"] == -2000.0 and cmd(_s_rows[-1])["a"] == -2000.0) + + +_full = _s._charge_headroom(2000.0, []) +check("the stop test reads only SITE SETs: a unit's own safety SET (on B) " + "or a site limit does not cut A's charge, a site safety SET does", + _s._charge_headroom(2000.0, [Claim.set("failsafe", P_SAFETY, 0.0, + actuator=B)]) == _full > 0.0 + and _s._charge_headroom(2000.0, [Claim.limit("peak", P_SAFETY, + lo=0.0)]) == _full + and _s._charge_headroom(2000.0, [Claim.set("safety", P_SAFETY, + 0.0)]) == 0.0) + + +def stop_at(t0): + def before(c, t): + s84.feed(True)(c, t) + if t >= t0: + c.auto = False + return before + + +_st_rows, _st = run(800.0, dur=400.0, before=stop_at(200.0)) +check("control switched off mid-charge: both batteries at 0 W, no refusal", + cmd(_st_rows[-1]) == {"a": 0.0, "b": 0.0} and refused(_st_rows) == 0) + +# ============================================================================ # +print("\n5. one battery refusing, dropped, or Off") + + +def a_takes_nothing(c, t): + """A reads 0 W whenever it is asked to charge (a battery that refuses).""" + s84.feed(True)(c, t) + if not getattr(c.hass, "_rt", False): + real = c.hass.power + c.hass.power = lambda u: (0.0 if u == "a" and c.hass.cmd["a"] < 0.0 + else real(u)) + c.hass._rt = True + + +_r_rows, _r = run(800.0, dur=900.0, before=a_takes_nothing) +print(f" A refuses to charge: {_r_rows[-1][2]}, {_r_rows[-1][6]}") +check("⭐ A refuses to charge (SAFETY-73): no ceiling is filed for it, B " + "covers the 800 W house, and no cycle is split both ways or refused", + _r.inverters[0].refused == -1 and cmd(_r_rows[-1]) == {"a": 0.0, + "b": 800.0} + and not charge_claims(_r_rows[-1]) + and opposite(_r_rows) == 0 and refused(_r_rows) == 0) + +_g_rows, _g = run(3000.0, dur=600.0, cut=lambda u, t: u == "b") +check("B refuses to give: A still charges and nothing is refused", + all(cmd(r)["a"] < 0.0 for r in _g_rows) and refused(_g_rows) == 0) + + +def reject_a(c, t): + """Every write to A is rejected, so A's link goes stale (not live).""" + s84.feed(True)(c, t) + if not getattr(c.hass, "_rej", False): + real = c.hass.set_number + + async def set_number(e, v): + return False if e == "number.sp_a" else await real(e, v) + c.hass.set_number, c.hass._rej = set_number, True + + +_l_rows, _l = run(1500.0, dur=400.0, before=reject_a) +print(f" A's writes rejected: {_l_rows[-1][2]}, {_l_rows[-1][7][-40:]}") +check("⭐ a charging battery that is dropped (stale link) adds no ceiling: " + "B covers the 1500 W house instead of charging for A", + "dropped inverter-a" in _l_rows[-1][7] + and 1490.0 <= cmd(_l_rows[-1])["b"] <= 1530.0 + and not charge_claims(_l_rows[-1])) + + +def modes_store(b_mode=None, b_off=False): + s = rig._Store() + for k in ("phase", "phase_started"): + s.data[unit_key(A, k)] = ("charge" if k == "phase" + else rig.BASE.isoformat()) + if b_mode: + s.data[unit_key(B, packmode.MODE_KEY)] = b_mode + if b_off: + s.data[unit_key(B, packmode.USE_KEY)] = False + return s + + +_m = {h: run(h, dur=600.0, extra={"battery_modes_enabled": True}, + store=modes_store(b_off=True)) for h in (800.0, -3000.0)} +print(f" B Off: {[(h, cmd(rows[-1])) for h, (rows, _c) in _m.items()]}") +check("⭐ battery modes on, B Off: A charges at 2000 W over an 800 W house " + "and takes 2500 W of a 3000 W surplus, B stays at 0 W, nothing is " + "refused", + cmd(_m[800.0][0][-1]) == {"a": -2000.0, "b": 0.0} + and cmd(_m[-3000.0][0][-1]) == {"a": -2500.0, "b": 0.0} + and all(refused(rows) == 0 and opposite(rows) == 0 + for rows, _c in _m.values())) + +# ============================================================================ # +print("\n6. a trade does not outrank the charge") + + +def sell_feed(c, t): + p3._feed(c, t) + s84.feed(True)(c, t) + + +_trades = [] +_t_rows, _t = run(800.0, dur=5400.0, before=sell_feed, + extra=dict(p3.ARB), + soc=lambda u, t: 60.0) +print(f" modes off, a sell at 75-90 min: last {_t_rows[-1][2]}") +_sells = [r for r in _t_rows if any(c[0] == "arbitrage" and c[3] > 0.0 + for c in r[-1][0])] +check("⭐ battery modes off: the site trade asks to SELL while A charges; " + "the charge (P_MAINT_SHAPE) outranks it, so A keeps charging and " + "nothing is refused", + len(_sells) > 50 + and all(cmd(r)["a"] < 0.0 and cmd(r)["b"] <= 0.0 for r in _sells) + and refused(_t_rows) == 0) + +# ============================================================================ # +print("\n7. a seeded sweep of the ceiling") +_c = run(800.0, dur=30.0)[1] +_rnd = random.Random(84) +_bad = [] +for _i in range(20000): + ra, rb = _rnd.choice((2000.0, 2500.0)), _rnd.choice((1000.0, 2500.0)) + f = _rnd.uniform(1.0, ra) + cl = [Claim.limit("supervised", P_SAFETY, -ra, ra, actuator=A), + Claim.limit("supervised", P_SAFETY, -rb, rb, actuator=B), + Claim.limit("maintenance", P_MAINT_SHAPE, hi=-f, actuator=A)] + x = _rnd.random() + if x < 0.1: + cl.append(Claim.limit("refused", P_SAFETY, 0.0, actuator=A)) + elif x < 0.2: + cl.append(Claim.limit("pack", P_SAFETY, 0.0, actuator=A)) + y = _rnd.random() + if y < 0.15: + cl.append(Claim.limit("refused", P_SAFETY, *_rnd.choice( + ((0.0, float("inf")), (float("-inf"), 0.0))), actuator=B)) + elif y < 0.3: + cl.append(Claim.limit("mode", P_MODE, *_rnd.choice( + ((0.0, 0.0), (0.0, rb), (-rb, 0.0))), actuator=B)) + cl.append(Claim.set("loop", P_LOOP, _rnd.uniform(-6000, 6000))) + if _rnd.random() < 0.4: + cl.append(Claim.set("arbitrage", P_ARBITRAGE, + _rnd.uniform(-5000, 5000))) + ceil = _c._charge_ceiling(cl) + if ceil is not None: + cl.append(Claim.limit("charge", P_MAINT_SHAPE, hi=ceil)) + res = resolve(cl, units=(A, B), live={A, B}) + sh = res.shares or {} + why = [] + if not res.allocated or res.contradiction: + why.append("refused or contradicted") + if sh.get(A, 0.0) * sh.get(B, 0.0) < 0.0: + why.append("opposite") + a_free = x >= 0.2 + if a_free and (ceil is None or sh.get(A, 0.0) > -f + 1.0): + why.append("A does not charge") + if not a_free and ceil is not None: + why.append("ceiling filed for a pack that cannot charge") + if why: + _bad.append((_i, why)) +print(f" 20000 claim lists, bad {len(_bad)}: {_bad[:3]}") +check("⭐ 20000 random N=2 claim lists (a charge on A, refusals, a full " + "pack, B's mode, the loop and trades in both directions): never " + "refused, never both ways, A always charges at least its rate, and " + "no ceiling for a pack that cannot charge", not _bad) + +# ============================================================================ # +print("\n8. the N=1 and N=2 digests") +# Printed by `python3 tools/safety84_identity.py` in goodwe-addon-checks:1, +# 2026-09-30, 480 cycles each, every claim hashed. N=1 and n2_charge_dear: +# the same on release/1.0 9d5b7d1 (the tool copied in). N=2 in a cheap +# window: new, the charge that 9d5b7d1 refused on every cycle. +PINNED = { + "n1_charge": + "0ed25c856456b97acb07a39299a8cb7b1a762c4d0005b88a0823c03057a80be5", + "n1_charge_dear": + "c25340b56060d4581f7204e200b07e7c8618711be2baca3b1667b7ebeb600dc3", + "n1_charge_banked": + "2619acdd06b04e56c000b168d64e1d044346c6ba3f929c94258d6ad8189ec609", + "n2_charge": + "748abe785a79084bc738c82d0d6f90b951e1cb78e9629195c0c01d3bb67b55e2", + "n2_charge_dear": + "c34f08b3b5b6256e68cf05030fb0c29522916dc8f57c351008f48384657966c0", + "n2_charge_banked": + "fb600ee1dd3202910715c97c5809584d50c6b8b57b55aaa4dc83bcaaa97627ef", +} +_now = s84.digests() +for k in PINNED: + print(f" {k} {'same' if _now[k] == PINNED[k] else 'DIFFERS'} " + f"{_now[k][:16]}") +check("⭐ at N=1 a charge in and out of a cheap window and under a banked " + "month peak is byte-identical to 9d5b7d1 (commands, reasons and every " + "claim), and so is N=2 outside a cheap window", + all(_now[k] == PINNED[k] for k in ("n1_charge", "n1_charge_dear", + "n1_charge_banked", + "n2_charge_dear"))) +check("...and the N=2 cheap-window digests match the pins", + _now["n2_charge"] == PINNED["n2_charge"] + and _now["n2_charge_banked"] == PINNED["n2_charge_banked"]) +_n1 = s84.run(1, dur=600.0)[0] +check("...and no N=1 cycle files a `charge` claim", + not any(charge_claims(r) for r in _n1)) + +print() +if fails: + print(f"{len(fails)} FAILED: " + ", ".join(fails)) + sys.exit(1) +print("all SAFETY-84 checks passed") diff --git a/goodwe_controller/tools/safety84_identity.py b/goodwe_controller/tools/safety84_identity.py new file mode 100644 index 0000000..87730c0 --- /dev/null +++ b/goodwe_controller/tools/safety84_identity.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +"""SAFETY-84: at one inverter, is a maintenance charge byte-identical to before? + + python3 tools/safety84_identity.py # prints one digest per scenario + +safety78_identity's harness (the REAL Controller on a P1 meter, every claim +hashed) with the battery in its maintenance CHARGE phase from the first cycle, +on the owner's settings (limit 3500, margin 50, charge 2000 W). The house steps +below the charge rate, at it, under the aim, over it and into a solar surplus, +in a cheap window, outside one, and under a month peak banked at 4000 W. Uses +only the API release/1.0 9d5b7d1 has, so the same file runs on both trees; +test_safety84.py holds this tree to the digests printed there (N=1) and to the +new N=2 ones. +""" + +import functools +import hashlib +import os +import sys +import tempfile + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +import safety79_identity as s79 # noqa: E402 +import app.main as m # noqa: E402 +from app import tariff # noqa: E402 + +DUR = 2400.0 +OPT = {"peak_cap_w": 3500, "peak_margin_w": 50, "maintenance_enabled": True, + "maintenance_start_hour": 11, "maintenance_charge_w": 2000, + "price_now_entity": "sensor.pnow", "price_avg_entity": "sensor.pavg"} + + +def load(t): + """Below the 2000 W charge, at it, under the aim, over it, a surplus.""" + return (800.0, 2000.0, 3000.0, 5000.0, -1500.0)[min(int(t // 480), 4)] + + +def feed(cheap): + """s79's P1 feed plus a price now under (cheap) or over the average.""" + now = 0.05 if cheap else 0.30 + + def before(c, t): + if not getattr(c.hass, "_s84", False): + read = c.hass.number + + async def number(e, invert=False): + if e == "sensor.pnow": + return now + if e == "sensor.pavg": + return 0.20 + return await read(e, invert) + c.hass.number, c.hass._s84 = number, True + s79._feed(c, t) + return before + + +SCENARIOS = { + "n1_charge": dict(n=1), + "n1_charge_dear": dict(n=1, cheap=False), + "n1_charge_banked": dict(n=1, month_peak=4000.0), + "n2_charge": dict(n=2), + "n2_charge_dear": dict(n=2, cheap=False), + "n2_charge_banked": dict(n=2, month_peak=4000.0), +} + + +def run(n, *, cheap=True, month_peak=None, dur=DUR, load=load, soc=None, + before=None, cut=None, extra=None, store=None): + """Rows (opt11_identity's fields plus every claim, the guard and the + phases) and the controller. `month_peak` banks that peak this month.""" + seen, extra_rows = [], [] + real_resolve = m.resolve + + def spy(claims, **kw): + seen.append(tuple((c.source, c.priority, c.kind, c.value, c.lo, c.hi, + c.reason, c.actuator) for c in claims)) + return real_resolve(claims, **kw) + + def on_cycle(c, t): + g = c.peak_guard + extra_rows.append(( + seen[-1] if seen else None, + None if g is None else (g.engaged, g.floor_w, g.reason), + c._maint_shape_suspended, [mm.phase for mm in c.maints], + len(c.events), c.events[0] if c.events else None)) + db = os.path.join(tempfile.mkdtemp(prefix="s84-"), "tariff.db") + if month_peak is not None: + tariff.PeakStore(db)._db.execute( + "INSERT INTO monthly_peak VALUES (?, ?, ?, NULL)", + (tariff.month_key(rig.BASE), month_peak, + "2026-09-02T10:00:00+00:00")).connection.commit() + real = rig.Controller + rig.Controller = functools.partial(real, peak_db_path=db) + m.resolve = spy + try: + rows, c = rig.run(n, extra=dict(s79.P1, **OPT, **(extra or {})), + dur=dur, load=load, soc=soc or s79.soc, + cut=cut or (lambda u, t: False), + before=before or feed(cheap), on_cycle=on_cycle, + store=store or s79.store_charging(n)) + finally: + rig.Controller = real + m.resolve = real_resolve + return [r + (x,) for r, x in zip(rows, extra_rows)], c + + +def digest(rows) -> str: + return hashlib.sha256(repr(rows).encode()).hexdigest() + + +def digests() -> dict: + return {k: digest(run(**v)[0]) for k, v in SCENARIOS.items()} + + +if __name__ == "__main__": + for k, v in digests().items(): + print(f"{k} {v}") -- 2.54.0 From 5c9f64d87a6ba9421cf5219bddd38277f20b2d4c Mon Sep 17 00:00:00 2001 From: SAFETY-84 review <gschrooyen@gmail.com> Date: Wed, 30 Sep 2026 20:36:46 +0200 Subject: [PATCH 093/105] SAFETY-84 review: check the charging pack gives under the guard, and no-P1 at N=2 A 6500 W house needs more than B alone: A must give (the N>=2 suspension), with a non-vacuous run without it (banks over the cap, 'Load too high'). Without P1 the charge is not sized, as at N=1: A charges at 2000 W. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_safety84.py | 55 ++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/goodwe_controller/test_safety84.py b/goodwe_controller/test_safety84.py index 09492fe..fcc0d4e 100644 --- a/goodwe_controller/test_safety84.py +++ b/goodwe_controller/test_safety84.py @@ -12,8 +12,9 @@ DECISIONS/SAFETY-84-charge-at-two.md has the record. 1. N=2 in a cheap window, house below, at and above the charge rate and a solar surplus: the charge runs, no opposite split, no refusal, and it ends. 2. The peak guard: the charge yields just enough to hold the aim (cap - - margin, and a banked month peak - margin); over the aim the guard wins - and nothing parks; no false 'Load too high'. + margin, and a banked month peak - margin); over the aim the guard wins, + the charging battery gives too, and nothing parks; no false 'Load too + high'. Without P1 the charge is not sized, as at N=1. 3. Outside a cheap window nothing changes. 4. A safety stop parks both batteries without a refusal, and the charge resumes after it. @@ -197,6 +198,56 @@ check("non-vacuous: charging at the full rate instead, the guard has to " "step in and the batteries give back on many cycles", _gave > 50) + +def peak_run(house): + rows, c = run(house, dur=1800.0) + return rows, c, [r for r in rows if r[-1][1] and r[-1][1][0]] + + +# A 6500 W house needs 3050 W off the meter: more than B's 2500 W alone. +_p_rows, _p, _p_eng = peak_run(6500.0) +print(f" house 6500: banked {[round(v) for v in banked(_p)]} W, A gives " + f"on {sum(cmd(r)['a'] > 0.0 for r in _p_eng)} of {len(_p_eng)} " + f"engaged cycles") +check("⭐ house 6500 W, more than B alone can cover: the charge is suspended " + "and A, the battery being filled, gives too; the quarter lands on the " + "aim, nothing is refused, no 'Load too high'", + len(_p_eng) > 100 and all(cmd(r)["a"] > 0.0 for r in _p_eng) + and all(v <= AIM + TOL for v in banked(_p)) + and refused(_p_rows) == 0 and not alarmed(_p)) +_real = s84.m.peakguard.shaping_suspended +s84.m.peakguard.shaping_suspended = lambda *a: False +try: + _ns_rows, _ns, _ns_eng = peak_run(6500.0) +finally: + s84.m.peakguard.shaping_suspended = _real +check("non-vacuous: with the suspension taken out, A is held at 0 W, the " + "quarter goes over the cap and 'Load too high' fires", + not any(cmd(r)["a"] > 0.0 for r in _ns_eng) + and max(banked(_ns)) > 3500.0 and alarmed(_ns)) + + +def prices_only(c, t): + """A cheap price and no P1 telegram (`meter_source: off`).""" + if not getattr(c.hass, "_px", False): + read, px = c.hass.number, {"sensor.pnow": 0.05, "sensor.pavg": 0.20} + + async def number(e, invert=False): + return px[e] if e in px else await read(e, invert) + c.hass.number, c.hass._px = number, True + + +_p1 = s84.s79.P1 +s84.s79.P1 = {"meter_source": "off", "peak_cap_w": 3500} +try: + _off_rows, _off = run(800.0, dur=600.0, before=prices_only) +finally: + s84.s79.P1 = _p1 +check("⭐ with no P1 meter nothing measures the quarter and the charge is not " + "sized, as at N=1: A charges at 2000 W on every cycle, nothing refused", + _off.peak_guard is None and all(cmd(r)["a"] == -2000.0 for r in _off_rows) + and refused(_off_rows) == 0) + # ============================================================================ # print("\n3. outside a cheap window nothing changes") _d = {h: run(h, cheap=False, dur=600.0) for h in (800.0, -1500.0)} -- 2.54.0 From 513183aba3930b65af3763a2a7dfb1551d7d5feb Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Thu, 1 Oct 2026 00:56:34 +0200 Subject: [PATCH 094/105] test_peak_margin: read the month peak on the runs' clock, not today's Part 3 read the simulated September's peak with the wall clock, so from 2026-10-01 it read no peak and crashed on every tree (4ad8298 too). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/test_peak_margin.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py index 0631b57..f8da15c 100644 --- a/goodwe_controller/test_peak_margin.py +++ b/goodwe_controller/test_peak_margin.py @@ -173,14 +173,15 @@ check("...and decide() sizes the floor to land the quarter 50 W under it " # ============================================================================ # print("\n3. the bill and the reports keep the real cap") _c = _runs["n1_off", None][1] -_pk = _c.peak.peak().peak_w +_t = rig.rig.BASE # the runs' clock, not the wall clock (a new month) +_pk = _c.peak.peak(_t).peak_w print(f" month peak {_pk:.0f} W, tracker cap {_c.peak.cap_w:.0f} W, " - f"warning {_c.peak.warning_frac():.3f}, headroom " - f"{_c.peak.headroom_w():.0f} W") + f"warning {_c.peak.warning_frac(_t):.3f}, headroom " + f"{_c.peak.headroom_w(_t):.0f} W") check("test_billing_uses_cap: the month-peak tracker (bill, headroom, 80 % " "warning) is built on the real cap, not cap - margin", - _c.peak.cap_w == CAP and _c.peak.warning_frac() == _pk / CAP - and _c.peak.headroom_w() == CAP - _pk) + _c.peak.cap_w == CAP and _c.peak.warning_frac(_t) == _pk / CAP + and _c.peak.headroom_w(_t) == CAP - _pk) _eng = [g for r in _runs["n1_off", None][0] for g in (r[-1][1],) if g and g[0] and g[1]] print(f" {len(_eng)} engaged cycles; one: {_eng[0][4] if _eng else None}") -- 2.54.0 From ba31e7c8b1e506e8bc4e6fe2c29caf805ce1c2f5 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Thu, 1 Oct 2026 00:56:34 +0200 Subject: [PATCH 095/105] SAFETY-86: peak guard outranks the maintenance hold During a HOLD the holding battery gives what keeps the quarter at the peak aim. N=1: the peak floor is refiled at P_MAINTENANCE, as for a drain (SAFETY-83). N>=2: the hold's pin is raised to the floor minus what the other live batteries may place, so they give first. A site stop still decides alone. The hold ends on its clock even if the level dipped. Below the aim nothing changes (rows identical). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-83-peak-over-drain.md | 5 +- .../DECISIONS/SAFETY-84-charge-at-two.md | 6 +- .../DECISIONS/SAFETY-86-peak-over-hold.md | 46 +++ goodwe_controller/DOCS.md | 4 + goodwe_controller/app/arbiter.py | 2 +- goodwe_controller/app/main.py | 50 ++- goodwe_controller/test_safety83.py | 7 +- goodwe_controller/test_safety86.py | 366 ++++++++++++++++++ 8 files changed, 473 insertions(+), 13 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md create mode 100644 goodwe_controller/test_safety86.py diff --git a/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md b/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md index 36ac6ff..8d12cc6 100644 --- a/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md +++ b/goodwe_controller/DECISIONS/SAFETY-83-peak-over-drain.md @@ -30,6 +30,5 @@ everything. Where the floor is at or below the drain rate nothing changes. **Not changed.** - Between the drain rate and the peak aim, the house still imports what the drain leaves (N=1 behaviour kept by the identity). At N=2 the loop covers it. -- A maintenance HOLD (0 W, 120 min, battery full) still outranks the peak - guard at N=1. Discharging there spends the charge the BMS balances on; it is - an owner question, not this fix. +- A maintenance HOLD (0 W, 120 min, battery full) still outranked the peak + guard at N=1. Fixed by [[SAFETY-86]]. diff --git a/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md b/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md index a12a744..21a9af0 100644 --- a/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md +++ b/goodwe_controller/DECISIONS/SAFETY-84-charge-at-two.md @@ -41,6 +41,6 @@ was fine. and the battery gives until the quarter is safe. The same sizing would fit there; that is an owner question, not this fix. - Outside a cheap window (`hi = 0`, solar only) nothing is filed, at any N. -- A HOLD (SAFETY-86) and the "Battery is not keeping up" alarm (SAFETY-85) - are untouched. In the identity runs that alarm's log line comes as often at - N=2 as at N=1 (2 in 480 cycles). +- A HOLD (later fixed by [[SAFETY-86]]) and the "Battery is not keeping up" + alarm (SAFETY-85) are untouched. In the identity runs that alarm's log line + comes as often at N=2 as at N=1 (2 in 480 cycles). diff --git a/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md b/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md new file mode 100644 index 0000000..2be80e8 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md @@ -0,0 +1,46 @@ +# SAFETY-86 - the peak guard outranks the maintenance HOLD + +**Status: DECIDED 2026-09-30 (owner).** Follows SAFETY-83's "Not changed" +list. Tests: `test_safety86.py`. + +**The defect.** The HOLD (battery resting full after the maintenance charge) +is a SET of 0 W at `P_MAINTENANCE` (60), above the peak floor (`P_PEAK`, 50), +so the floor did not bind. At N=1 a 6500 W house banked 6500 W quarters and +'Load too high' fired (SAFETY-83 rig test, check 4). At N=2 only the other +battery gave: 4500 W against a 3950 W aim (SAFETY-84 rig test, check 6). + +**The fix** (`main.py`, `_peak_over_hold()`). +- N=1: during a HOLD a peak floor above 0 W is refiled at `P_MAINTENANCE`, as + for a drain (SAFETY-83). The battery gives the floor; the Why reads "raised + for the peak limit". +- N>=2: the holding battery's pin is raised to the floor minus what the other + live batteries may place (their hard `hi`, or their pin). The others give + first, the holding one only the shortfall. Why this split and not the + allocator's shares: the hold is maintenance and outranks the others' use + (owner order), and the owner rule for an Off battery is the same, "give way + only for the shortfall". A battery Off by its mode (P_MODE, below + maintenance) therefore still gives before the holding one. +- Below the aim nothing changes: the floor is 0 W, the hold is 0 W, the rows + are identical to before (test_safety86.py part 2). +- A site stop (a SET above `P_PEAK`) decides alone: nothing is raised at N>=2, + and the refiled floor at N=1 stays under `P_SAFETY`. If another battery is + pinned to charge (a SAFETY-73 probe) the pin is not raised, so the site is + never split both ways. +- The hold resumes by itself: the rule is evaluated each cycle, so when the + guard lets go the command is 0 W again. + +**The level dips below the target: the hold finishes anyway.** The HOLD does +not read the level; it ends on its clock (`maintenance_hold_min`). Topping up +would mean going back to CHARGE, which waits for sun or a cheap window (up to +36 h, `CHARGE_TIMEOUT_MIN`) while the pack keeps the site's one maintenance +slot, so the other battery's cycle waits, and then a new full hold that the +guard can interrupt again. The guard only gives while the quarter is at risk, +and the next monthly cycle balances again. If the owner wants a top-up +instead, it is a change to `maintenance.py`'s HOLD branch, not to this rule. + +**Not changed.** +- The peak guard still grades the emptiest battery (SAFETY-32): at N=2 with + B under `peak_soc_floor` the floor is limited and A holds even when it is + full (SAFETY-87). +- "Battery is not keeping up" during maintenance (SAFETY-85), the N=2 charge + flapping (SAFETY-88) and the N=1 charge headroom sizing are untouched. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 4eeabac..e4130d4 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1669,6 +1669,10 @@ gives more than its drain rate, with one battery too (SAFETY-83). In a cheap window the battery being filled charges and the others only add charge; none gives while it charges. The charge is cut to what keeps the 15-minute peak at the limit minus `peak_margin_w` (SAFETY-84). +While a full battery rests after its charge (the hold), it gives just enough +to keep the 15-minute peak at that aim if the house needs it; with two +batteries the other one gives first. The hold still ends on its clock +(SAFETY-86). #### Capacity-tariff exposure of the grid-following loop diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 0cb2999..14dbd51 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -79,7 +79,7 @@ P_PEAK = 50 # capacity-tariff peak shaving - costs real money # The order in effect: safety limits and the SAFETY-73 refusal > the peak # guard > maintenance > modes > trade > loop. A peak floor above a drain still # binds: the `drain` site floor at N>=2 (SAFETY-78), refiled at P_MAINTENANCE -# at N=1 (SAFETY-83). Not a maintenance HOLD at N=1 (DECISIONS/SAFETY-83). +# at N=1 (SAFETY-83); over a HOLD, `_peak_over_hold()` (SAFETY-86). # A cheap-window charge is suspended while the peak guard holds and, at N>=2, # sized to the quarter's headroom (SAFETY-84). P_MAINT_SHAPE = 40 # maintenance shaping the loop (charge-only) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 0b23909..e507731 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -74,7 +74,7 @@ from .hass import HomeAssistant from .inverter import (LINK_STALE_S, UNIT_A, build_roster, roster_entries, roster_names) from .maintenance import ( - DRAIN, IDLE, POWER_MOVING, MaintConfig, Maintenance, MaintResult, + DRAIN, HOLD, IDLE, POWER_MOVING, MaintConfig, Maintenance, MaintResult, arbitrate as maint_arbitrate, ) from .mqtt import (MODE_CONFIGS_KEY, MODE_LABELS, USE_OFF, USE_ON, @@ -2533,6 +2533,50 @@ class Controller: if c.source == peakguard.SOURCE and c.lo > rate: claims[i] = dataclasses.replace(c, priority=P_MAINTENANCE) + def _peak_over_hold(self, claims, maint_results) -> None: + """SAFETY-86: a peak floor outranks a maintenance HOLD (0 W). + + At N=1 the floor is refiled at P_MAINTENANCE, as for a drain. At N>=2 + the holding pack gives only what the others cannot: its pin is raised + to the floor minus what they may place. A site stop still decides + alone. DECISIONS/SAFETY-86-peak-over-hold.md. + """ + hold = {self.actuator_of("maintenance", inv) + for inv, res in zip(self.inverters, maint_results) + if res.phase == HOLD and res.owns_setpoint} + peak = [i for i, c in enumerate(claims) + if c.source == peakguard.SOURCE and c.lo > 0.0] + if not hold or not peak: + return + if len(self.inverters) == 1: + for i in peak: + claims[i] = dataclasses.replace(claims[i], + priority=P_MAINTENANCE) + return + if any(c.kind == SET and c.actuator == ACTUATOR_SITE + and c.priority > P_PEAK for c in claims): + return + live = set(self.live_units()) + others = 0.0 + for inv in self.inverters: + u = self.actuator_of("maintenance", inv) + if u in hold or u not in live: + continue + b = pre_resolve([c for c in claims if c.actuator == u]) + if b.contradiction: + continue + p = allocator.pin_w(b) + if p is not None and p < 0.0: + return # a pack pinned to charge: never split both ways + others += allocator.hi_w(b) if p is None else p + give = max(claims[i].lo for i in peak) - others + if give <= 0.0: + return + for i, c in enumerate(claims): + if c.source == "maintenance" and c.kind == SET \ + and c.actuator in hold: + claims[i] = dataclasses.replace(c, value=give) + def _charge_headroom(self, floor: float, claims) -> float: """SAFETY-84: at N>=2 a cheap-window charge pulls no more than the quarter's headroom under the peak aim (`charge_headroom_w()`), so it @@ -3905,7 +3949,8 @@ class Controller: # business, not this block's: a maintenance DRAIN or HOLD owns the # setpoint at P_MAINTENANCE, and a maintenance CHARGE is only ever a # P_MAINT_SHAPE limit (40), bound by this floor. A floor above the drain - # rate still wins (SAFETY-78 at N>=2, `_peak_over_drain()` at N=1). + # rate still wins (SAFETY-78 at N>=2, `_peak_over_drain()` at N=1), and + # so does a floor over a HOLD (`_peak_over_hold()`, SAFETY-86). # # ⚠️ AND IT IS NOT RUN AT ALL WITHOUT P1. `meter_source: off` is the # legacy single-entity path: there is no telegram stream, so @@ -4307,6 +4352,7 @@ class Controller: reason="maintenance drain", actuator=self.actuator_of("drain"))) self._peak_over_drain(claims, maint_results) + self._peak_over_hold(claims, maint_results) # --- SAFETY-84: a cheap-window charge is a ceiling over the site ---- charge = self._charge_ceiling(claims) if charge is not None: diff --git a/goodwe_controller/test_safety83.py b/goodwe_controller/test_safety83.py index bd020ff..00567ea 100644 --- a/goodwe_controller/test_safety83.py +++ b/goodwe_controller/test_safety83.py @@ -295,11 +295,10 @@ def store_hold(): _h_rows, _h, _hb = run(6000.0, 2500, 50, 2000, dur=600.0, store=store_hold()) -check("a maintenance HOLD at N=1 is not changed (DECISIONS/SAFETY-83, not " - "changed): the battery stays at 0 W with the house over the limit", +check("a maintenance HOLD at N=1 now gives way to the guard too (SAFETY-86, " + "test_safety86.py): the battery gives with the house over the limit", _h.maints[0].phase == "hold" and _h.peak_guard.engaged - and _h.peak_guard.floor_w > 0.0 - and all(cmd(r) == 0.0 for r in _h_rows)) + and cmd(_h_rows[-1]) > 0.0 and "limited by peak" in _h_rows[-1][6]) print() if fails: diff --git a/goodwe_controller/test_safety86.py b/goodwe_controller/test_safety86.py new file mode 100644 index 0000000..5cb22fd --- /dev/null +++ b/goodwe_controller/test_safety86.py @@ -0,0 +1,366 @@ +"""Runnable check for SAFETY-86: the peak guard outranks the maintenance HOLD. +`python3 test_safety86.py` + +During the HOLD the battery rests full at 0 W (P_MAINTENANCE, above the peak +floor), so the house imported everything and quarters went over the peak +limit. Now the holding battery gives what keeps the quarter at the aim: at N=1 +the peak floor is refiled at P_MAINTENANCE, at N>=2 the hold's pin is raised +to what the other batteries cannot give. Drives the REAL Controller +(tools/safety84_identity.py's harness). DECISIONS/SAFETY-86-peak-over-hold.md. + +1. N=1, house over the aim: every quarter lands on the aim, the hold goes on, + no 'Load too high'; without the fix the quarter goes over and it fires. +2. Under the aim nothing changes, at N=1 and N=2 (rows identical). +3. N=2, house over the aim: the other battery gives first, the holding one + only the shortfall; with battery modes on and B Off too. +4. A month peak banked above the limit: the aim is that peak - margin. +5. A safety stop still parks everything, and the hold gives again after. +6. The level dips below the target: the hold still ends on its clock. +7. The rule at its boundaries, on claim lists. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import logging +import os +import sys +import types + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11_identity as rig # noqa: E402 +import safety84_identity as s84 # noqa: E402 +from app import control as _ctl # noqa: E402 +from app import packmode # noqa: E402 +from app.arbiter import (Claim, P_MAINTENANCE, P_PEAK, P_SAFETY, # noqa + resolve) +from app.main import Controller # noqa: E402 +from app.maintenance import DRAIN, HOLD, IDLE, MaintResult # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] +A, B = "inverter-a", "inverter-b" +AIM = 3450.0 # peak_cap_w 3500 - peak_margin_w 50 +TOL = 10.0 # W over the aim a banked quarter may show (SAFETY-81) + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def store_hold(n, b_off=False): + """A store with battery A in its HOLD from the first cycle.""" + s = rig._Store() + for k in ("phase", "phase_started"): + s.data[k if n == 1 else unit_key(A, k)] = ( + "hold" if k == "phase" else rig.BASE.isoformat()) + if b_off: + s.data[unit_key(B, packmode.USE_KEY)] = False + return s + + +def full(u, t): + """A rests full; B is half full.""" + return 99.0 if u == "a" else 60.0 + + +def run(house, n, *, hold_min=600, b_off=False, extra=None, **kw): + kw.setdefault("soc", full) + kw.setdefault("dur", 2700.0) + return s84.run(n, load=house if callable(house) else lambda t: house, + cheap=False, store=store_hold(n, b_off), + extra=dict({"maintenance_hold_min": hold_min}, + **(extra or {})), **kw) + + +def without_fix(fn): + real = Controller._peak_over_hold + Controller._peak_over_hold = lambda self, claims, results: None + try: + return fn() + finally: + Controller._peak_over_hold = real + + +def cmd(r): + return dict(r[2]) + + +def banked(c): + return [b.offtake_avg_w for b in c.p1.blocks] + + +def on_aim(c, aim=AIM): + b = banked(c) + return len(b) >= 2 and all(aim - TOL <= v <= aim + TOL for v in b) + + +def alarmed(c): + """Did SAFETY-81's 'Load too high' alarm fire on this run?""" + return any("PEAK_GUARD_SATURATED" in e for e in c.events) + + +def refused(rows): + return sum(1 for r in rows if r[7] and "REFUSED" in r[7]) + + +def peak_prio(r): + return [c[1] for c in r[-1][0] if c[0] == "peak"] + + +def hold_pin(r): + return [c[3] for c in r[-1][0] if c[0] == "maintenance" and c[2] == "set"] + + +# ============================================================================ # +print("1. N=1: a house over the aim during the HOLD") +N1 = {h: run(h, 1) for h in (5000.0, 6500.0, 7000.0)} +N1_OLD = {h: without_fix(lambda: run(h, 1)) for h in N1} +for h in N1: + print(f" house {h:.0f}: banked {[round(v) for v in banked(N1[h][1])]} W" + f" (before the fix {[round(v) for v in banked(N1_OLD[h][1])]} W), " + f"last {N1[h][0][-1][6]}") +check("⭐ every quarter lands on the aim (3450 W) for a 5000, 6500 and " + "7000 W house, and 'Load too high' never fires", + all(on_aim(c) and not alarmed(c) for _r, c in N1.values())) +check("...the battery gives, raised for the peak limit, and stays in its " + "HOLD: the phase is hold and the claim still says so", + all(c.maints[0].phase == HOLD and cmd(rows[-1])["a"] > 1000.0 + and "limited by peak" in rows[-1][6] + and c.why_words.endswith("raised for the peak limit") + for rows, c in N1.values())) +check("non-vacuous: without the fix the battery sits at 0 W, the quarter " + "banks the whole house and 'Load too high' fires", + all(all(cmd(r)["a"] == 0.0 for r in rows) and min(banked(c)) >= h - 1 + and alarmed(c) for h, (rows, c) in N1_OLD.items())) + + +def hob(t): + """A 6000 W house with a 5 s spike to 11000 W every 150 s.""" + return 11000.0 if t % 150 < 5 else 6000.0 + + +_sp_rows, _sp = run(hob, 1) +check("...and 5 s spikes that saturate the guard for a cycle do not fire it " + "(SAFETY-81's 10 s hold)", + any(r[-1][1] and r[-1][1][1] >= 5000.0 for r in _sp_rows) + and not alarmed(_sp)) + +# ============================================================================ # +print("\n2. under the aim the HOLD is as before") +BELOW = {(n, h): (run(h, n, dur=1800.0), + without_fix(lambda: run(h, n, dur=1800.0))) + for n, h in ((1, 1200.0), (1, 3000.0), (1, -1500.0), + (2, 1500.0), (2, 3000.0), (2, 5000.0))} +check("⭐ N=1 at a 1200 W and 3000 W house and a 1500 W surplus, N=2 at " + "1500, 3000 and 5000 W (B covers it): battery A is at 0 W on every " + "cycle and every row equals the run without the fix", + all(all(cmd(r)["a"] == 0.0 for r in new[0]) and new[0] == old[0] + for new, old in BELOW.values())) +check("...and the peak claim stays at P_PEAK on every cycle", + all(p == P_PEAK for new, _o in BELOW.values() for r in new[0] + for p in peak_prio(r))) + +# ============================================================================ # +print("\n3. N=2: the other battery gives first, the holding one the rest") +N2 = {h: run(h, 2) for h in (6500.0, 7000.0)} +N2_OLD = {h: without_fix(lambda: run(h, 2)) for h in N2} +for h, (rows, c) in N2.items(): + print(f" house {h:.0f}: banked {[round(v) for v in banked(c)]} W " + f"(before the fix {[round(v) for v in banked(N2_OLD[h][1])]} W), " + f"last {rows[-1][2]}") +check("⭐ house 6500 and 7000 W, B at most 2500 W: every quarter lands on " + "the aim, nothing is refused or split both ways, no 'Load too high'", + all(on_aim(c) and refused(rows) == 0 and not alarmed(c) + and all(cmd(r)["a"] * cmd(r)["b"] >= 0.0 for r in rows) + for rows, c in N2.values())) +_gives = [r for rows, _c in N2.values() for r in rows if cmd(r)["a"] > 0.0] +check("⭐ A gives only the shortfall: on every cycle A gives, B is at its " + "2500 W and A's pin is the guard's floor minus 2500 W", + len(_gives) > 500 + and all(cmd(r)["b"] == 2500.0 and hold_pin(r) + and abs(hold_pin(r)[0] - (r[-1][1][1] - 2500.0)) < 1e-6 + for r in _gives)) +check("...A stays in its HOLD, and its last command is the shortfall " + "(6500 - 3450 - 2500 = 550 W, give or take the meter's 1 W)", + all(c.maints[0].phase == HOLD for _r, c in N2.values()) + and 540.0 <= cmd(N2[6500.0][0][-1])["a"] <= 560.0) +check("non-vacuous: without the fix A sits at 0 W, the quarter goes over " + "the limit and 'Load too high' fires", + all(all(cmd(r)["a"] == 0.0 for r in rows) and max(banked(c)) > 3900.0 + and alarmed(c) for rows, c in N2_OLD.values())) + +_off_rows, _off = run(6500.0, 2, b_off=True, + extra={"battery_modes_enabled": True}) +print(f" B Off, house 6500: banked {[round(v) for v in banked(_off)]} W, " + f"last {_off_rows[-1][2]}") +check("⭐ battery modes on, B Off: the Off battery still gives before the " + "holding one (maintenance outranks a mode), the quarter lands on the " + "aim, nothing refused", + on_aim(_off) and cmd(_off_rows[-1])["b"] == 2500.0 + and 540.0 <= cmd(_off_rows[-1])["a"] <= 560.0 + and refused(_off_rows) == 0 and not alarmed(_off)) + +# ============================================================================ # +print("\n4. a month peak banked above the limit") +BANK = {n: (run(6500.0, n, month_peak=4000.0), + without_fix(lambda: run(6500.0, n, month_peak=4000.0))) + for n in (1, 2)} +for n, (new, old) in BANK.items(): + print(f" N={n} house 6500, month peak 4000: banked " + f"{[round(v) for v in banked(new[1])]} W (before the fix " + f"{[round(v) for v in banked(old[1])]} W)") +check("⭐ under a month peak of 4000 W the aim is 3950 W (peak - margin), " + "at N=1 and N=2, and no 'Load too high'", + all(on_aim(new[1], 3950.0) and not alarmed(new[1]) + for new, _old in BANK.values())) +check("non-vacuous: before the fix N=1 banks the whole house and N=2 banks " + "4000 W, over that aim", + min(banked(BANK[1][1][1])) >= 6499.0 + and min(banked(BANK[2][1][1])) >= 3999.0) + +# ============================================================================ # +print("\n5. a safety stop still wins") + + +def blind_at(t0, t1): + """A's power reading is missing from `t0` to `t1`: a site safety SET.""" + def before(c, t): + s84.feed(False)(c, t) + if not getattr(c.hass, "_blind", False): + real = c.hass.number + + async def number(e, invert=False): + if e == "sensor.batt_a" and t0 <= c.hass.t < t1: + return None + return await real(e, invert) + c.hass.number, c.hass._blind = number, True + return before + + +STOP = {n: run(6500.0, n, dur=900.0, before=blind_at(300.0, 600.0)) + for n in (1, 2)} +for n, (rows, _c) in STOP.items(): + print(f" N={n} reading lost 300-600 s: at {rows[100][0]:.0f} s " + f"{rows[100][2]}, {rows[100][6]}; after {rows[-1][2]}") +check("⭐ with a reading gone the safety SET parks every battery at 0 W, at " + "N=1 and N=2, with nothing refused", + all(all(v == 0.0 for r in rows if 330.0 <= r[0] < 600.0 + for v in cmd(r).values()) + and any(r[6].startswith("safety -> 0 W") for r in rows) + and refused(rows) == 0 for rows, _c in STOP.values())) +check("...the hold gave before the stop and gives again after it", + all(cmd(rows[50])["a"] > 0.0 and cmd(rows[-1])["a"] > 0.0 + for rows, _c in STOP.values())) + +# ============================================================================ # +print("\n6. the level dips below the hold's target") + + +def draining(u, t): + """A's level falls 1 % a minute from 99 % (set, not integrated); B 60 %.""" + return max(20.0, 99.0 - t / 60.0) if u == "a" else 60.0 + + +DIP = {n: run(6500.0, n, hold_min=30, dur=2400.0, soc=draining) + for n in (1, 2)} +for n, (rows, c) in DIP.items(): + print(f" N={n}: phases {sorted({tuple(x[-1][3]) for x in rows})}, " + f"last event {[e for e in c.events if 'maintenance' in e][:1]}") +check("⭐ the level falls from 99 % to 70 % while the hold gives, and " + "the hold still ends on its 30 min clock: HOLD -> IDLE, cycle " + "COMPLETE, never back to CHARGE, at N=1 and N=2", + all(c.maints[0].phase == IDLE + and any("cycle COMPLETE" in e for e in c.events) + and {x[-1][3][0] for x in rows} == {HOLD, IDLE} + and all(x[-1][3][0] == HOLD for x in rows if x[0] < 1795.0) + for rows, c in DIP.values())) +check("...the hold gave on the way (the level really dipped)", + all(any(cmd(r)["a"] > 0.0 for r in rows if r[0] < 1795.0) + for rows, _c in DIP.values())) + +# ============================================================================ # +print("\n7. the rule at its boundaries") +_c = run(1500.0, 2, dur=10.0)[1] +_c1 = run(1500.0, 1, dur=10.0)[1] +HOLDING = [MaintResult(HOLD, True, 0.0, False, []), + MaintResult(IDLE, False, None, False, [])] + + +def pin_after(floor, *extra, live=(A, B), results=HOLDING, c=_c): + fake = types.SimpleNamespace(inverters=c.inverters, + actuator_of=c.actuator_of, + live_units=lambda: tuple(live)) + cl = [Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=A), + Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=B), + Claim.set("maintenance", P_MAINTENANCE, 0.0, HOLD, actuator=A), + Claim.limit("peak", P_PEAK, lo=floor, reason="quarter peak"), + *extra] + Controller._peak_over_hold(fake, cl, results) + return next((x.value for x in cl + if x.source == "maintenance" and x.kind == "set"), None), cl + + +check("⭐ at N=2 a floor under or at B's 2500 W leaves A at 0 W (never " + "charging); 0.5 W above it raises A's pin to 0.5 W", + pin_after(1000.0)[0] == 0.0 and pin_after(2500.0)[0] == 0.0 + and pin_after(2500.5)[0] == 0.5) +check("⭐ B not live, contradicting itself, or refusing to give: A gives the " + "whole floor", + pin_after(2000.0, live=(A,))[0] == 2000.0 + and pin_after(2000.0, Claim.limit("pack", P_SAFETY, 10.0, -10.0, + actuator=B))[0] == 2000.0 + and pin_after(2000.0, Claim.limit("refused", P_SAFETY, hi=0.0, + actuator=B))[0] == 2000.0) +_probe = _ctl.PROBE_W +check("⭐ B probing: giving counts its probe (A gives the rest), charging " + "leaves A at 0 W so the site is never split both ways", + pin_after(2000.0, Claim.set("refused", P_SAFETY, _probe, "probe", + actuator=B))[0] == 2000.0 - _probe + and pin_after(2000.0, Claim.set("refused", P_SAFETY, -_probe, "probe", + actuator=B))[0] == 0.0) +_p, _cl = pin_after(4000.0, Claim.set("safety", P_SAFETY, 0.0, + "inputs missing")) +check("⭐ a site safety SET: A stays at 0 W and the site resolves to 0 W; " + "a unit safety SET on B does not stop A giving", + _p == 0.0 and resolve(_cl, units=(A, B), live={A, B}).target_w == 0.0 + and pin_after(3000.0, Claim.set("failsafe", P_SAFETY, 0.0, + actuator=B))[0] == 3000.0) +check("only a HOLD: a DRAIN pin or an idle pack is not raised", + pin_after(4000.0, results=[MaintResult(DRAIN, True, 0.0, False, []), + HOLDING[1]])[0] == 0.0 + and pin_after(4000.0, results=[HOLDING[1], HOLDING[1]])[0] == 0.0) + + +def refile(lo, results=(HOLDING[0],)): + fake = types.SimpleNamespace(inverters=_c1.inverters, + actuator_of=_c1.actuator_of) + cl = [Claim.set("maintenance", P_MAINTENANCE, 0.0, HOLD), + Claim.limit("peak", P_PEAK, lo=lo, reason="quarter peak")] + Controller._peak_over_hold(fake, cl, list(results)) + return cl + + +check("⭐ at N=1 a floor of 0 W stays at P_PEAK, 0.5 W is refiled at " + "P_MAINTENANCE, and a blind claim (a ceiling only) is not refiled", + refile(0.0)[1].priority == P_PEAK + and refile(0.5)[1].priority == P_MAINTENANCE + and refile(float("-inf"))[1].priority == P_PEAK) +_stop = refile(3000.0) + [Claim.set("safety", P_SAFETY, 0.0, + "inputs missing")] +check("⭐ at N=1 a refiled floor stays under a safety SET: 0 W", + resolve(_stop).target_w == 0.0) +check("at N=1 outside a HOLD the claim is not touched by this rule", + refile(3000.0, (MaintResult(IDLE, False, None, False, []),))[1] + .priority == P_PEAK) + +print() +if fails: + print(f"{len(fails)} FAILED: " + ", ".join(fails)) + sys.exit(1) +print("all SAFETY-86 checks passed") -- 2.54.0 From 1c41a1e412619eff3f3125622a343c398d98ad14 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Thu, 1 Oct 2026 02:00:20 +0200 Subject: [PATCH 096/105] SAFETY-86 review: hold the site at the peak floor while a HOLD gives At N>=2 the holding pack's pin follows the guard's floor while the loop still asks for +5000 W, so the ALLOCATOR "could not be placed" row was re-logged on every 1 W change and filled the 40-row action log. While the pin is raised, cycle() now files a site `hold` ceiling at the floor (P_MAINTENANCE), as SAFETY-84 does for a charge. Filed only when the holding pack gives; hi == the floor, so it never clashes with it. Tests: a noisy N=2 house logs no ALLOCATOR row and at most one clamp row (20 and 20 without the ceiling); the ceiling is the floor itself; a CHARGE is not refiled at N=1. The DECISIONS entry records the owner's 2026-10-01 decision: the HOLD ends on its clock, no top-up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../DECISIONS/SAFETY-86-peak-over-hold.md | 17 +++--- goodwe_controller/app/arbiter.py | 4 ++ goodwe_controller/app/main.py | 19 ++++-- goodwe_controller/app/messages.py | 1 + goodwe_controller/test_arbiter.py | 13 ++-- goodwe_controller/test_peakguard.py | 24 +++++--- goodwe_controller/test_safety86.py | 61 ++++++++++++++++++- 7 files changed, 108 insertions(+), 31 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md b/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md index 2be80e8..612efb0 100644 --- a/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md +++ b/goodwe_controller/DECISIONS/SAFETY-86-peak-over-hold.md @@ -20,6 +20,10 @@ battery gave: 4500 W against a 3950 W aim (SAFETY-84 rig test, check 6). (owner order), and the owner rule for an Off battery is the same, "give way only for the shortfall". A battery Off by its mode (P_MODE, below maintenance) therefore still gives before the holding one. +- N>=2, while the holding battery gives: a site `hold` ceiling at the floor + (P_MAINTENANCE), so the loop does not ask for watts the hold keeps back. + Without it the moving pin re-logged the ALLOCATOR "could not be placed" + row each cycle and filled the action log (review, PR #161). - Below the aim nothing changes: the floor is 0 W, the hold is 0 W, the rows are identical to before (test_safety86.py part 2). - A site stop (a SET above `P_PEAK`) decides alone: nothing is raised at N>=2, @@ -29,14 +33,11 @@ battery gave: 4500 W against a 3950 W aim (SAFETY-84 rig test, check 6). - The hold resumes by itself: the rule is evaluated each cycle, so when the guard lets go the command is 0 W again. -**The level dips below the target: the hold finishes anyway.** The HOLD does -not read the level; it ends on its clock (`maintenance_hold_min`). Topping up -would mean going back to CHARGE, which waits for sun or a cheap window (up to -36 h, `CHARGE_TIMEOUT_MIN`) while the pack keeps the site's one maintenance -slot, so the other battery's cycle waits, and then a new full hold that the -guard can interrupt again. The guard only gives while the quarter is at risk, -and the next monthly cycle balances again. If the owner wants a top-up -instead, it is a change to `maintenance.py`'s HOLD branch, not to this rule. +**The level dips below the target: the hold finishes anyway.** Owner +decision 2026-10-01: the HOLD ends on its clock (`maintenance_hold_min`) even +when the peak guard pulls the level down; no top-up. A top-up would re-enter +CHARGE (up to 36 h, `CHARGE_TIMEOUT_MIN`) and keep the site's one maintenance +slot meanwhile. **Not changed.** - The peak guard still grades the emptiest battery (SAFETY-32): at N=2 with diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 14dbd51..2ec7bee 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -202,6 +202,10 @@ CLAIM_SCOPE = { # sibling would have to give against it. Never filed at N=1. # DECISIONS/SAFETY-84-charge-at-two.md. "charge": SCOPE_SITE, + # main.py: `Claim.limit("hold", P_MAINTENANCE, hi=...)`, SAFETY-86. While a + # holding pack gives the peak shortfall at N>=2, the site target stays at + # the peak floor, what the pin and the others place. Never filed at N=1. + "hold": SCOPE_SITE, # --- UNIT: about one pack, one inverter, one device ------------------- # main.py: `Claim.limit("device", P_SAFETY, self.dev_min, self.dev_max, diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index e507731..3881917 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -2533,13 +2533,14 @@ class Controller: if c.source == peakguard.SOURCE and c.lo > rate: claims[i] = dataclasses.replace(c, priority=P_MAINTENANCE) - def _peak_over_hold(self, claims, maint_results) -> None: + def _peak_over_hold(self, claims, maint_results): """SAFETY-86: a peak floor outranks a maintenance HOLD (0 W). At N=1 the floor is refiled at P_MAINTENANCE, as for a drain. At N>=2 the holding pack gives only what the others cannot: its pin is raised - to the floor minus what they may place. A site stop still decides - alone. DECISIONS/SAFETY-86-peak-over-hold.md. + to the floor minus what they may place, and the floor is returned as + the site `hold` ceiling (else None). A site stop still decides alone. + DECISIONS/SAFETY-86-peak-over-hold.md. """ hold = {self.actuator_of("maintenance", inv) for inv, res in zip(self.inverters, maint_results) @@ -2569,13 +2570,15 @@ class Controller: if p is not None and p < 0.0: return # a pack pinned to charge: never split both ways others += allocator.hi_w(b) if p is None else p - give = max(claims[i].lo for i in peak) - others + floor = max(claims[i].lo for i in peak) + give = floor - others if give <= 0.0: return for i, c in enumerate(claims): if c.source == "maintenance" and c.kind == SET \ and c.actuator in hold: claims[i] = dataclasses.replace(c, value=give) + return floor def _charge_headroom(self, floor: float, claims) -> float: """SAFETY-84: at N>=2 a cheap-window charge pulls no more than the @@ -4352,7 +4355,13 @@ class Controller: reason="maintenance drain", actuator=self.actuator_of("drain"))) self._peak_over_drain(claims, maint_results) - self._peak_over_hold(claims, maint_results) + # --- SAFETY-86: while a HOLD gives, the site stays at the peak floor -- + # So the loop never asks for watts the hold keeps back. + hold_hi = self._peak_over_hold(claims, maint_results) + if hold_hi is not None: + claims.append(Claim.limit("hold", P_MAINTENANCE, hi=hold_hi, + reason="maintenance hold", + actuator=self.actuator_of("hold"))) # --- SAFETY-84: a cheap-window charge is a ceiling over the site ---- charge = self._charge_ceiling(claims) if charge is not None: diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index fa6a4b4..d353b16 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -836,6 +836,7 @@ WHY_LIMIT = { "reserve": "the battery reserve", "maintenance": "battery maintenance", "charge": "battery maintenance", + "hold": "battery maintenance", "refused": "a battery that refuses power", } diff --git a/goodwe_controller/test_arbiter.py b/goodwe_controller/test_arbiter.py index b367003..8fe90d4 100644 --- a/goodwe_controller/test_arbiter.py +++ b/goodwe_controller/test_arbiter.py @@ -149,7 +149,7 @@ check("...and `source` is still the first positional argument, which is what " Claim.limit("device", P_SAFETY, -1, 1).source == "device") print() -print("ARB-03 2. the split: fifteen sources, each classified where it is BUILT") +print("ARB-03 2. the split: sixteen sources, each classified where it is BUILT") # The classification is graded against what each claim is ABOUT, restated here # so that the table in arbiter.py and the expectation in a test are not the same # sentence read twice. test_peakguard.py part 10f pins this set against main.py's @@ -179,6 +179,9 @@ SITE_SOURCES = { "charge": "the site target may not go above a cheap-window maintenance " "charge, or a sibling would give against it. Filed at N>1 " "only", + # SAFETY-86. + "hold": "the site target stays at the peak floor while a holding pack " + "gives the shortfall. Filed at N>1 only", } UNIT_SOURCES = { "device": "one inverter's own reported min/max rating", @@ -210,9 +213,9 @@ for _src, _why in sorted(SITE_SOURCES.items()): print(f" site {_src:<11} {_why}") for _src, _why in sorted(UNIT_SOURCES.items()): print(f" unit {_src:<11} {_why}") -check("all FIFTEEN claim sources are classified, and only those fifteen", +check("all SIXTEEN claim sources are classified, and only those sixteen", set(CLAIM_SCOPE) == set(SITE_SOURCES) | set(UNIT_SOURCES)) -check("the eight that are about the GRID CONNECTION are site claims", +check("the nine that are about the GRID CONNECTION are site claims", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == set(SITE_SOURCES)) check("the seven that are about a PACK, a DEVICE or one write are per-inverter", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == set(UNIT_SOURCES)) @@ -234,7 +237,7 @@ check("...and with none configured at all, likewise", all(actuator_for(s, "inverter-a", ()) == ACTUATOR_SITE for s in CLAIM_SCOPE)) check("with TWO the identity breaks and the split becomes real: the seven " "per-inverter sources route to the unit this controller drives, the " - "eight site sources stay on the grid connection", + "nine site sources stay on the grid connection", {s: actuator_for(s, "inverter-a", TWO) for s in CLAIM_SCOPE} == {**{s: "inverter-a" for s in UNIT_SOURCES}, **{s: ACTUATOR_SITE for s in SITE_SOURCES}}) @@ -515,7 +518,7 @@ check("...and at N=1, where every source legitimately routes to the site, the " Claim.limit("maintenance", P_MAINT_SHAPE, hi=0.0)]) == []) check("an unclassified ninth source is a violation wherever it is filed", scope_violations([Claim.limit("reserve", P_LOOP, hi=0.0)]) != []) -check("and the eight, routed by actuator_for() at a two-inverter site, are " +check("and the sixteen, routed by actuator_for() at a two-inverter site, are " "clean - which is what says the router and the checker agree", scope_violations( [Claim.limit(s, P_SAFETY, -1, 1, diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index d936a45..29bae44 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -2691,9 +2691,12 @@ check("...and so does the persistent notification, which outlives the page and " # site `hi` at P_MAINT_SHAPE, filed only at N>=2 while a pack's cheap-window # maintenance charge makes it charge, equal to that pack's own `hi`. Never at # N=1. DECISIONS/SAFETY-84-charge-at-two.md. +# SAFETY-86 added `hold`: a site `hi` at the peak floor while a holding pack +# gives at N>=2. Not a reserve either. DECISIONS/SAFETY-86-peak-over-hold.md. CLAIM_SOURCES = {"device", "supervised", "failsafe", "safety", "peak", "arbitrage", "maintenance", "loop", "circulation", - "sign_site", "pack", "refused", "mode", "drain", "charge"} + "sign_site", "pack", "refused", "mode", "drain", "charge", + "hold"} # The two appends that file a claim BUILT ELSEWHERE in the method. Named here so # that a THIRD such indirection reads as an unrecognised append rather than as a # silent gap in the scan. @@ -2735,7 +2738,7 @@ check("every `claims.append(...)` in main.py's cycle is one this scan can READ " "- a claim filed through a shape it cannot parse has to fail here rather " "than be counted as nothing, which is how a scan like this goes quietly " "vacuous", len(_appends) >= 10 and None not in _filed) -check("...and the sources that cycle can file are EXACTLY these FIFTEEN. THIS " +check("...and the sources that cycle can file are EXACTLY these SIXTEEN. THIS " "is what makes part 10 a tripwire: replay_loop() hand-builds the claim " "list, so it cannot see a claim main.py adds - and a loop-side SoC " "reserve is a new source. Filing one takes this line red on the line it " @@ -2875,7 +2878,7 @@ print(" site: " + ", ".join(sorted(s for s, v in CLAIM_SCOPE.items() + " | per-inverter: " + ", ".join(sorted(s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT))) check("...and the split is the one ARB-03 argued, with SAFETY-31's and " - "SAFETY-30's, OPT-09's, SAFETY-78's and SAFETY-84's additions: the eight about the GRID CONNECTION " + "SAFETY-30's, OPT-09's, SAFETY-78's, SAFETY-84's and SAFETY-86's additions: the nine about the GRID CONNECTION " "are site claims and the five about a pack, a device or one write are " "per-inverter. `circulation` is a site claim because its quantity is " "defined over the roster and is identically zero for any one unit; " @@ -2885,7 +2888,7 @@ check("...and the split is the one ARB-03 argued, with SAFETY-31's and " "against that unit's OWN measured power", {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_SITE} == {"loop", "peak", "arbitrage", "safety", "circulation", "sign_site", - "drain", "charge"} + "drain", "charge", "hold"} and {s for s, v in CLAIM_SCOPE.items() if v == SCOPE_UNIT} == {"device", "supervised", "failsafe", "maintenance", "pack", "refused", "mode"}) @@ -2990,7 +2993,8 @@ check("⚠️ AND THIS IS THE BREAKING HALF. Give the same Controller a second " "loop": ACTUATOR_SITE, "peak": ACTUATOR_SITE, "arbitrage": ACTUATOR_SITE, "safety": ACTUATOR_SITE, "circulation": ACTUATOR_SITE, "sign_site": ACTUATOR_SITE, - "drain": ACTUATOR_SITE, "charge": ACTUATOR_SITE}) + "drain": ACTUATOR_SITE, "charge": ACTUATOR_SITE, + "hold": ACTUATOR_SITE}) check("...and the roster it was restored to is the shipped one, so nothing " "below inherits a two-inverter Controller", c_src.units == (app_main.UNIT_A,) and len(c_src.inverters) == 1) @@ -3069,13 +3073,13 @@ _unit_sources_unrouted = [ if CLAIM_SCOPE.get(r[0]) == SCOPE_UNIT and "," not in r[1]] print(f" {len(_direct)} direct appends, each read at its own line: " + ", ".join(f"main.py:{ln} {s} -> {a}" for s, a, ln in _routing)) -check("all SIXTEEN of `Controller.cycle()`'s DIRECT appends route through " +check("all SEVENTEEN of `Controller.cycle()`'s DIRECT appends route through " "`self.actuator_of(<string literal>)`, so this scan can read the routing " "of EVERY one of them. An append that computed its actuator, or omitted " "the argument, or hand-wrote a string, fails HERE rather than being " "silently skipped - which is how a scan like this goes quietly vacuous, " "and 10f is in this file because that already happened once", - len(_direct) == 16 + len(_direct) == 17 and all(a is not None and a.startswith("self.actuator_of('") for _s, a, _ln in _routing)) check("⚠️ AND AT EVERY ONE OF THE ELEVEN THE LITERAL IT ROUTES THROUGH IS THE " @@ -3109,8 +3113,8 @@ check("...and the only appends this pin does NOT reach are the two that file a " "arbitrage.claim() by test_arbitrage.py", sorted(_indirect) == sorted(CLAIM_BUILDERS) and len(_direct) + len(_indirect) == len(_appends)) -check("...and between them the eighteen appends account for exactly the " - "fifteen " +check("...and between them the nineteen appends account for exactly the " + "sixteen " "sources 10f pins, so the routing pin and the source set are one scan " "and neither can drift from the other", {s for s, _a, _ln in _routing} | set(CLAIM_BUILDERS.values()) @@ -3171,7 +3175,7 @@ check("...and naming those three is not an accident of this fixture but the " {c.source for c in _cl2} == CLAIM_SOURCES - {"failsafe", "safety", "maintenance", "peak", "arbitrage", "circulation", "sign_site", - "refused", "mode", "drain", "charge"}) + "refused", "mode", "drain", "charge", "hold"}) # ⚠️ AND NOW THE HALF THAT WAS EVIDENCE-SHAPED AND OBSERVED NOTHING. The three # checks above grade WHICH ACTUATOR each claim lands on. They say nothing about # WHOSE NUMBERS the bound is built from - and those are two different defects diff --git a/goodwe_controller/test_safety86.py b/goodwe_controller/test_safety86.py index 5cb22fd..ce761d0 100644 --- a/goodwe_controller/test_safety86.py +++ b/goodwe_controller/test_safety86.py @@ -38,7 +38,8 @@ from app import packmode # noqa: E402 from app.arbiter import (Claim, P_MAINTENANCE, P_PEAK, P_SAFETY, # noqa resolve) from app.main import Controller # noqa: E402 -from app.maintenance import DRAIN, HOLD, IDLE, MaintResult # noqa: E402 +from app.maintenance import (CHARGE, DRAIN, HOLD, IDLE, # noqa: E402 + MaintResult) from app.store import unit_key # noqa: E402 fails = [] @@ -206,6 +207,47 @@ check("⭐ battery modes on, B Off: the Off battery still gives before the " and 540.0 <= cmd(_off_rows[-1])["a"] <= 560.0 and refused(_off_rows) == 0 and not alarmed(_off)) + + +def noisy(t): + """A 6500 W house that moves up to 150 W from one second to the next.""" + return 6500.0 + ((int(t) * 7919) % 301) - 150.0 + + +def no_ceiling(fn): + """Run with the pin raised but no `hold` site ceiling (review check).""" + real = Controller._peak_over_hold + + def pin_only(self, claims, results): + real(self, claims, results) + Controller._peak_over_hold = pin_only + try: + return fn() + finally: + Controller._peak_over_hold = real + + +def rows_logged(c, word): + return sum(1 for e in c.events if word in e) + + +_nz_rows, _nz = run(noisy, 2) +_nz_old = no_ceiling(lambda: run(noisy, 2))[1] +print(f" noisy house: ALLOCATOR rows {rows_logged(_nz, 'ALLOCATOR')}, " + f"clamp rows {rows_logged(_nz, 'OUTPUT_CLAMP')} (without the site " + f"ceiling {rows_logged(_nz_old, 'ALLOCATOR')} and " + f"{rows_logged(_nz_old, 'OUTPUT_CLAMP')})") +check("⭐ while A gives, the site target is the guard's floor (the `hold` " + "ceiling), so a noisy house does not fill the action log: no ALLOCATOR " + "row and at most one clamp row", + on_aim(_nz) and all(abs(r[1] - r[-1][1][1]) < 1e-6 for r in _nz_rows + if cmd(r)["a"] > 0.0) + and rows_logged(_nz, "ALLOCATOR") == 0 + and rows_logged(_nz, "OUTPUT_CLAMP") <= 1) +check("non-vacuous: without the ceiling the loop asks 5000 W and the " + "ALLOCATOR and clamp rows fill the 40-row log", + rows_logged(_nz_old, "ALLOCATOR") >= 10 and len(_nz_old.events) == 40) + # ============================================================================ # print("\n4. a month peak banked above the limit") BANK = {n: (run(6500.0, n, month_peak=4000.0), @@ -301,7 +343,8 @@ def pin_after(floor, *extra, live=(A, B), results=HOLDING, c=_c): Claim.set("maintenance", P_MAINTENANCE, 0.0, HOLD, actuator=A), Claim.limit("peak", P_PEAK, lo=floor, reason="quarter peak"), *extra] - Controller._peak_over_hold(fake, cl, results) + ceiling = Controller._peak_over_hold(fake, cl, results) + pin_after.ceiling = ceiling return next((x.value for x in cl if x.source == "maintenance" and x.kind == "set"), None), cl @@ -331,6 +374,15 @@ check("⭐ a site safety SET: A stays at 0 W and the site resolves to 0 W; " _p == 0.0 and resolve(_cl, units=(A, B), live={A, B}).target_w == 0.0 and pin_after(3000.0, Claim.set("failsafe", P_SAFETY, 0.0, actuator=B))[0] == 3000.0) +_p, _cl = pin_after(2600.0) +_hi = pin_after.ceiling +_cl += [Claim.limit("hold", P_MAINTENANCE, hi=_hi, actuator="site"), + Claim.set("loop", 10, 5000.0, "the loop asks for the whole house")] +pin_after(2500.0) +check("⭐ at N=2 the `hold` site ceiling is the floor itself, only when A " + "gives, and a 5000 W loop ask resolves to that floor", + _hi == 2600.0 and pin_after.ceiling is None + and resolve(_cl, units=(A, B), live={A, B}).target_w == 2600.0) check("only a HOLD: a DRAIN pin or an idle pack is not raised", pin_after(4000.0, results=[MaintResult(DRAIN, True, 0.0, False, []), HOLDING[1]])[0] == 0.0 @@ -355,8 +407,11 @@ _stop = refile(3000.0) + [Claim.set("safety", P_SAFETY, 0.0, "inputs missing")] check("⭐ at N=1 a refiled floor stays under a safety SET: 0 W", resolve(_stop).target_w == 0.0) -check("at N=1 outside a HOLD the claim is not touched by this rule", +check("at N=1 outside a HOLD (idle, or a CHARGE) the claim is not touched " + "by this rule", refile(3000.0, (MaintResult(IDLE, False, None, False, []),))[1] + .priority == P_PEAK + and refile(3000.0, (MaintResult(CHARGE, False, None, True, []),))[1] .priority == P_PEAK) print() -- 2.54.0 From d0db5b8c393e1507f969c7ee82a746668ffb157f Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Thu, 1 Oct 2026 09:29:30 +0200 Subject: [PATCH 097/105] SAFETY-87: peak guard uses every battery that can still give At N>=2 a battery at or under its own peak reserve is held: it gives nothing for the peak (weight 0 while the site gives) and the guard's need is placed on the live, non-refusing batteries above theirs. The guard is floor-limited, and alarms, only when those cannot hold the limit at full power for ALARM_HOLD_S. The peak alarms no longer read "Not ready" or hold the Home page at 0 W, because control keeps running. N=1 is byte-identical. DECISIONS/SAFETY-87-guard-uses-able-batteries.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr --- .../DECISIONS/SAFETY-32-per-pack-bms-floor.md | 2 + .../SAFETY-87-guard-uses-able-batteries.md | 73 +++ goodwe_controller/DOCS.md | 10 +- goodwe_controller/app/arbiter.py | 9 +- goodwe_controller/app/homeview.py | 11 +- goodwe_controller/app/main.py | 120 +++- goodwe_controller/app/messages.py | 25 +- goodwe_controller/app/peakguard.py | 47 +- goodwe_controller/test_peakguard.py | 94 ++-- goodwe_controller/test_safety86.py | 3 +- goodwe_controller/test_safety87.py | 512 ++++++++++++++++++ goodwe_controller/tools/safety87_identity.py | 66 +++ 12 files changed, 901 insertions(+), 71 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md create mode 100644 goodwe_controller/test_safety87.py create mode 100644 goodwe_controller/tools/safety87_identity.py diff --git a/goodwe_controller/DECISIONS/SAFETY-32-per-pack-bms-floor.md b/goodwe_controller/DECISIONS/SAFETY-32-per-pack-bms-floor.md index 2b0cdc9..d9a5dce 100644 --- a/goodwe_controller/DECISIONS/SAFETY-32-per-pack-bms-floor.md +++ b/goodwe_controller/DECISIONS/SAFETY-32-per-pack-bms-floor.md @@ -69,6 +69,8 @@ which does not run the startup gate) the absence costs a shave and never a pack. ## 3. DECISION 2 — the site verdict is the MAXIMUM of the packs' own floors +*At N>=2 one pack at its floor no longer stops the others: [[SAFETY-87]].* + `Controller.pack_floor_soc` — the **minimum** measured SoC, the emptiest pack — **is unchanged**, exactly as the card instructed. What changed is the floor it is graded against. `peakguard.binding_soc_floor()` reduces the roster's per-pack diff --git a/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md b/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md new file mode 100644 index 0000000..4555605 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md @@ -0,0 +1,73 @@ +# SAFETY-87 - the peak guard uses every battery that can still give + +**Status: DECIDED 2026-10-01 (owner card).** Follows SAFETY-86's "Not +changed" list. Tests: `test_safety87.py`; identity: +`tools/safety87_identity.py`. + +**The defect.** At N>=2 the guard graded the emptiest battery against the +highest floor ([[SAFETY-32]] §3). One battery under `peak_soc_floor` made the +whole site floor-limited: the claim asked for 0 W and the reserve alarm fired, +even with the other battery full. Measured: a maintenance charge (A at 11 %) +raised the alarm 10 times while both batteries gave 2000 W and the quarter +landed on the aim (SAFETY-84 rig test, check 3); a HOLD (A at 99 %, B at +15 %) left A at 0 W and banked 4051 W, raising the month peak (SAFETY-86 +review; rig case 7a: 4563.8 W). + +**The fix.** +- `decide()` and its call are unchanged. At N>=2 `Controller._peak_on_able()` + then grades each battery on its own floor (`peakguard.reserve_split()`). + One at or under it is *held*. The others that are live and not refusing + (SAFETY-73) are *able*. +- A floor-limited decision is re-taken on the able batteries + (`peakguard.place_on_able()`): their own permission (min SoC against max + floor, among them), and a floor of `min(need, able_w)`. `able_w` is their + rating plus the drain a held battery gives anyway (its maintenance pin). +- The held batteries weigh 0 in the split while the site gives + (`arbiter.resolve(reserve=)`), so the floor lands on the able ones. During a + HOLD, a held battery is not counted among the "others" (`_peak_over_hold()`), + so the holding battery covers the need. +- Floor-limited now means: some battery is held and the able ones cannot hold + the aim. The claim still asks them for `able_w`. The alarm fires only if + they miss the real limit at full power for `ALARM_HOLD_S`, the same test as + 'Load too high' (`_reserve_short()`), so a one-cycle miss at a quarter's end + is not an alarm. With nothing able (all held, or the rest refusing or + dropped) it is the old state: 0 W, immediate alarm. +- The alarm and the row name `held`, each battery graded on its own floor. The + old code named batteries against the site's highest floor. +- Page: the two peak rows carry `runs`. A red `runs` row gives the banner its + title without "Not ready", and the Home page is not shown as held at 0 W. + Rows that do stop control still outrank it. + +**How SAFETY-32's concern is still covered.** SAFETY-32 took min(SoC) against +max(floor) so the guard never sizes a forced discharge a battery's own BMS +stops. Now no battery at or under its own floor is asked for the peak: it is +graded on its own floor, and an unread SoC or unknown cut-out counts as held. +The min/max pairing still decides permission, over the able batteries. The +roster verdict `decide()` echoes (`soc`, `soc_floor`) is kept, so SAFETY-32's +call-site and reduction checks still bite. What changed is only that one held +battery no longer stops the others. + +**Before -> after** (test_safety87.py, rig of 2 x 2500 W, aim 3450 W): + +| case | before | after | +|---|---|---| +| charge, A 11 %, house 4500 | 3 reserve alarms, quarter 3450 | 0 alarms, 3450 | +| HOLD, A 99 % / B 15 %, house 5500 | A 0 W, B 2488 W, 3 alarms | A 2054 W, B 0 W, 0 alarms, 3450 | +| HOLD, house 6500 | A 0 W, B 2488 W, 4051 W | A 2500 W, B 0 W, 4014 W, 1 alarm (A alone is short) | +| HOLD, month peak 4000, house 6000 | A 0 W, B 2488 W, 3551 W, alarms | A 2054 W, B 0 W, 3950 (peak - margin), 0 alarms | +| both under the reserve | alarm | alarm (unchanged) | +| N=1, every scenario | | byte-identical | + +**Open, for the owner.** +- The loop still draws a held battery (SAFETY-25 option A: the reserve binds + the peak guard only). It gives last, after the able ones. So with house 6500 + in the charge case, B alone cannot hold the aim, the alarm fires as + specified, and the loop then lands the quarter on the aim from A. The text + says "cannot keep … alone", not "will go over", so it stays true. +- Battery modes on, A Off and B held: when B alone can place the floor, OPT-11 + keeps A resting and B gives it. When B cannot, A gives first. Making Off give + before a held battery in the first case needs a third allocator tier. +- The notification and row text live in `messages.py`, which has no NL layer + yet (UX-19). The Home page text, which has NL, is unchanged. + +**Not changed.** N=1. 'Load too high' (SAFETY-81). SAFETY-85, -88, -89, -90. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index e4130d4..8fac634 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -3157,6 +3157,10 @@ and what to do: - **A battery cut-out level is not known.** Fill in “Battery cut-out level” for each inverter in the settings. +With several inverters, a battery at its peak reserve does not give for the +peak and the others do. This alarm then comes only when the others cannot +keep the period under the limit alone. Control keeps running meanwhile. + The peak reserve only applies to keeping the peak down. Normal home use can still draw the battery below it, down to the battery cut-out level, where the battery switches itself off. @@ -3252,7 +3256,9 @@ state of charge is unread, or when an inverter's `bms_soc_floor` (label “Battery cut-out level”) is missing, because the reserve is graded against it. Charging from the grid stays blocked meanwhile. With several inverters the notification names the battery at its limit (SAFETY-32), each graded against -its own cut-out level. ⚠️ **The reserve binds the peak guard only +its own cut-out level. That battery is held (weight 0 while the site gives) +and the guard's need goes to the others, up to their rating; the alarm fires +only if they miss the limit at full power for `ALARM_HOLD_S` (SAFETY-87). ⚠️ **The reserve binds the peak guard only (SAFETY-25).** Self-consumption has no such floor. See *What `peak_soc_floor` does not protect*. @@ -3390,7 +3396,7 @@ for a new install*. | Meter reading may be stuck | See *Meter reading may be stuck* under Notifications. | | Month peak | This month's highest 15-minute average, when it happened, and how close it is to your peak limit. Amber from 80 %. | | 15-minute periods measured this month | How many 15-minute periods the add-on has measured and saved this month. | -| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. *Idle, heading for …* is where this 15-minute period is heading. *Waiting for meter readings* after a restart means the battery does not charge until the add-on can measure the period again. | +| Peak guard, Load too high for battery, Battery at its peak reserve | What the add-on does to keep your peak down. *Idle, heading for …* is where this 15-minute period is heading. *Waiting for meter readings* after a restart means the battery does not charge until the add-on can measure the period again. A red peak row is an alarm while control keeps running, so the banner shows its title without *Not ready*. | | Battery level, Battery power, Grid power | The reading of that entity. *No usable reading* means the entity is missing, or its reading is too old. Check it in Developer Tools before replacing it. | | Inverter control | Whether the inverter can be controlled, and how much it can charge and give. | | *name*: battery power reading stopped changing | The reading did not change while the add-on asked for a change. It may be stuck, or the battery may be refusing. The add-on sets the inverters to 0 W until it changes. | diff --git a/goodwe_controller/app/arbiter.py b/goodwe_controller/app/arbiter.py index 2ec7bee..e9136b9 100644 --- a/goodwe_controller/app/arbiter.py +++ b/goodwe_controller/app/arbiter.py @@ -635,7 +635,7 @@ def site_resolve(claims: list) -> Resolution: def resolve(claims: list, *, units=None, weights=None, live=None, - tick=None) -> Resolution: + tick=None, reserve=()) -> Resolution: """The three stages, in order, over one cycle's claims. `units` is the site's roster of inverters. Left None it is derived from the @@ -737,6 +737,13 @@ def resolve(claims: list, *, units=None, weights=None, live=None, gate, held = _unit_modes(out, site_claims, bounds, live) if callable(weights): weights = weights(out.target_w) + # SAFETY-87: units under their peak reserve weigh 0 while the site gives, + # so the others carry the peak floor. An Off battery gives the peak's + # shortfall, so it goes before them when no other unit is left. + reserve = set(reserve) if out.target_w > 0.0 else set() + if held and reserve and not set(bounds) - held - reserve: + held = set() + held = held | reserve if held: weights = {u: (0.0 if u in held else (1.0 if weights is None else weights.get(u, 1.0))) diff --git a/goodwe_controller/app/homeview.py b/goodwe_controller/app/homeview.py index 18d9820..6cfccc7 100644 --- a/goodwe_controller/app/homeview.py +++ b/goodwe_controller/app/homeview.py @@ -923,24 +923,25 @@ def state_of(c, level, shadow): def build(c, *, level: str, checks: list, now: datetime | None = None, - lang: str = "en") -> dict: + lang: str = "en", held: bool | None = None) -> dict: """The structured half of `/status`, in `lang` (UX-13 P5). Pure reads of the controller.""" _LANG[0] = uitext.lang_of(lang) try: - return _build(c, level=level, checks=checks, now=now) + return _build(c, level=level, checks=checks, now=now, held=held) finally: _LANG[0] = "en" -def _build(c, *, level, checks, now): +def _build(c, *, level, checks, now, held=None): now = now or datetime.now(timezone.utc) shadow = bool(c.shadow) kind = state_of(c, level, shadow) # A red banner means every inverter is at 0 W (the status cascade), so # nothing is planned until it clears. Shadow mode still plans: it is - # what the add-on would do. - held = level == "bad" and not shadow + # what the add-on would do. `held` False: an alarm while control runs + # (SAFETY-87, the peak alarms). + held = level == "bad" and not shadow and held is not False running = (bool(c.auto) or shadow) and not held settled = all(at_zero(inv) for inv in c.inverters) ctl = next((r for r in checks if r.get("id") == "controller"), None) diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 3881917..45ceeda 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -936,6 +936,9 @@ class Controller: self._peak_alarm_block = None self._peak_high_since = None self._peak_floor_limited = False + # SAFETY-87: the reserve alarm's hold, as SAFETY-81's above. + self._reserve_batt_prev = None + self._reserve_high_since = None self._maint_shape_suspended = False # OPT-11. Battery modes, off by default so an install that has not # turned them on behaves exactly as before (SAFETY-10 section 1). Each @@ -2514,6 +2517,44 @@ class Controller: self._drain_waits = waits return floor if floor > 0.0 else None + def _peak_on_able(self, decision, maint_results): + """SAFETY-87: at N>=2, `decision` placed on the batteries that can + still give: live, not refusing, above their own reserve. `able_w` is + their rating plus the drain a held battery gives anyway (its + maintenance pin). Unchanged when no battery is held back. + DECISIONS/SAFETY-87-guard-uses-able-batteries.md.""" + if len(self.inverters) < 2: + return decision + floor = float(self.o.get( + "peak_soc_floor", peakguard.PEAK_OPTION_DEFAULTS["peak_soc_floor"])) + ok, held = peakguard.reserve_split(self.packs, floor) + if not held: + return decision + live = set(self.live_units()) + able = [p for p, inv in zip(self.packs, self.inverters) + if p in ok and inv.name in live and not (inv.refused or 0) > 0] + if not able: + return dataclasses.replace(decision, held=held) + drain = sum(min(float(r.setpoint_w), i.rating_w()) + for i, r in zip(self.inverters, maint_results) + if i.name in held and r.phase == DRAIN + and r.owns_setpoint and (r.setpoint_w or 0.0) > 0.0) + names = {p.name for p in able} + return peakguard.place_on_able( + decision, held, + able_w=drain + sum(i.rating_w() for i in self.inverters + if i.name in names), + soc=min(float(p.soc) for p in able), + soc_floor=peakguard.binding_soc_floor(able, floor)) + + def _peak_reserve(self) -> frozenset: + """SAFETY-87: the batteries that give nothing for the peak this + cycle: under their reserve while the others carry a peak floor.""" + g = self.peak_guard + if g is None or g.able_w is None or not (g.floor_w or 0.0) > 0.0: + return frozenset() + return frozenset(g.held) + def _peak_over_drain(self, claims, maint_results) -> None: """SAFETY-83: at N=1 a peak floor above the drain rate outranks it. @@ -2558,10 +2599,11 @@ class Controller: and c.priority > P_PEAK for c in claims): return live = set(self.live_units()) + reserve = self._peak_reserve() # SAFETY-87: they give nothing others = 0.0 for inv in self.inverters: u = self.actuator_of("maintenance", inv) - if u in hold or u not in live: + if u in hold or u not in live or inv.name in reserve: continue b = pre_resolve([c for c in claims if c.actuator == u]) if b.contradiction: @@ -4021,6 +4063,11 @@ class Controller: dev_min=self.site_dev_bound("dev_min"), dev_max=self.site_dev_bound("dev_max")), ) + # SAFETY-87: at N>=2 a battery at or under its own reserve gives + # nothing for the peak, and the others carry the guard's need. + if self.peak_guard is not None: + self.peak_guard = self._peak_on_able(self.peak_guard, + maint_results) # SITE, and peakguard.claim() says so on the object it builds. The # quantity is the 15-minute average OFFTAKE AT THE GRID CONNECTION, # which is what the capacity tariff bills; there is one quarter-hour @@ -4553,7 +4600,8 @@ class Controller: _live = self.live_units() while True: resolution = resolve(claims, units=self.units, live=_live, - weights=self.pack_weights, tick=self.alloc_tick) + weights=self.pack_weights, tick=self.alloc_tick, + reserve=self._peak_reserve()) # SAFETY-73: a probe pin stands only while the resolved site target # asks at least PROBE_W its way. Below that a sibling would carry # the opposite direction (circulation), so the pin goes back to the @@ -5169,6 +5217,8 @@ class Controller: floor-limited the guard asked for NOTHING, because the pack is at or under the EMS floor, or its SoC could not be read. Nothing is being discharged for this quarter at all. + (SAFETY-87, N>=2: or the batteries above their + reserve give all they can and it is not enough.) They cannot both be true: peakguard.decide()'s floor-limited branch returns before the `achievable_w` clamp that sets `saturated`. @@ -5189,6 +5239,10 @@ class Controller: """ g = self.peak_guard limited = bool(g is not None and g.floor_limited) + if limited and (g.floor_w or 0.0) > 0.0: + limited = self._reserve_short(g) + else: + self._reserve_batt_prev = self._reserve_high_since = None was, self._peak_floor_limited = self._peak_floor_limited, limited if not limited or was: return @@ -5211,13 +5265,8 @@ class Controller: # think the pack is AT it. `decide()` guards its own reason string the # same way; a f-string that formats a None here would turn the one # notification that matters into a traceback. - # ⚠️ SAFETY-32. WHICH PACK STOPPED THE SITE. `g.soc_floor` is the floor - # the decision was actually taken with, so this re-grades nothing and - # cannot disagree with the alarm it is printed inside. At a roster of one - # no pack is named - there is exactly one. - _blocked = [name for name, why - in peakguard.pack_permissions(self.packs, g.soc_floor) - if why is not None] + # SAFETY-32/87: which battery is at its reserve, each graded on its own + # floor (`g.held`). At a roster of one no battery is named. # ⚠️ SAFETY-25's sentence (the reserve binds the peak guard only) is # part of messages.peak_reserve() on every branch, the unreadable-SoC # one included. @@ -5226,8 +5275,31 @@ class Controller: g.ceiling_w, soc_unread=g.soc is None, floor_unknown=(g.soc is not None and g.soc_floor is None), - packs=(_blocked if len(self.inverters) > 1 - else ())).data()) + packs=(g.held if len(self.inverters) > 1 + else ()), + others=(g.floor_w or 0.0) > 0.0).data()) + + def _reserve_short(self, g) -> bool: + """SAFETY-87: the batteries that can still give, at full power, miss + the limit (`load_too_high()` on `g.able_w`), for ALARM_HOLD_S, as + SAFETY-81 grades 'Load too high'.""" + p, batt = self._peak_proj, self.site_batt_w + if batt is None: + return self._peak_floor_limited + prev, self._reserve_batt_prev = self._reserve_batt_prev, batt + if prev is not None: + batt = min(float(batt), float(prev)) + if not (p is not None and p.block_start is not None + and peakguard.load_too_high(p, batt_w=batt, + ceiling_w=g.ceiling_w, + achievable_w=g.able_w)): + self._reserve_high_since = None + return False + t = p.block_start + timedelta(seconds=float(p.elapsed_s)) + if self._reserve_high_since is None: + self._reserve_high_since = t + return ((t - self._reserve_high_since).total_seconds() + >= peakguard.ALARM_HOLD_S) async def check_circulating(self) -> None: """SAFETY-31 + SAFETY-34. The alarm, and it must survive a restart. @@ -5998,8 +6070,10 @@ class Controller: "text": messages.row_peak_guard_waiting()}) elif _pg.saturated: out.append({"ok": False, "warn": False, "id": "peak_guard", + "runs": True, "text": messages.row_peak_saturated(_pg.ceiling_w)}) - elif _pg.floor_limited: + elif _pg.floor_limited and (not (_pg.floor_w or 0.0) > 0.0 + or self._peak_floor_limited): # SAFETY-24. NOT ok, like saturation: in both states the money # is going to be spent and a human is the only actuator left. A # separate row from saturation because the two ask for opposite @@ -6025,18 +6099,17 @@ class Controller: # UX-08: the same three branches, and the same pack naming, as # check_peak_floor_limited()'s notification. The figures stay in # `_pg.reason`, on the log and the event list. - _blocked = [name for name, why - in peakguard.pack_permissions(self.packs, - _pg.soc_floor) - if why is not None] + # SAFETY-87: `runs`, control goes on (status_payload()). out.append({"ok": False, "warn": False, "id": "peak_guard", + "runs": True, "banner": messages.banner_peak_reserve(), "text": messages.row_peak_reserve( _pg.ceiling_w, soc_unread=_pg.soc is None, floor_unknown=(_pg.soc is not None and _pg.soc_floor is None), - packs=(_blocked if len(self.inverters) > 1 - else ()))}) + packs=(_pg.held if len(self.inverters) > 1 + else ()), + others=(_pg.floor_w or 0.0) > 0.0)}) elif _pg.blind: out.append({"ok": False, "warn": True, "id": "peak_guard", "text": messages.row_peak_guard_blind( @@ -6359,6 +6432,11 @@ class Controller: def status_payload(self, lang: str = "en") -> dict: checks = self.checks() bad = [c for c in checks if not c["ok"] and not c["warn"]] + # SAFETY-87: a red row with `runs` (the peak alarms) is an alarm while + # control goes on, so it neither reads "Not ready" nor holds the page. + runs = [c for c in bad if c.get("runs")] + bad = [c for c in bad if not c.get("runs")] + running_alarm = False # --- SAFETY-10, AND IT IS FIRST IN THE CASCADE ----------------------- # "The battery is NOT being controlled" is the one sentence on this # page that may never be displaced by another condition. A banner that @@ -6411,6 +6489,9 @@ class Controller: level, banner = "bad", messages.banner_not_ready(bad[0]) elif not self.auto: level, banner = "warn", messages.banner_stopped() + elif runs: + level, running_alarm = "bad", True + banner = runs[0].get("banner") or messages.headline(runs[0]["text"]) elif any(i.delivery_wd.tripped for i in self.inverters): # ⚠️ SAFETY-42, AND IT IS A `warn` BANNER RATHER THAN A `bad` ONE, # WHICH IS THE WHOLE "reports, does not act" DECISION IN ONE LINE. @@ -6532,6 +6613,7 @@ class Controller: decided_at=self.arb_at, cycle_at=self.cycle_at, now=datetime.now(timezone.utc), why=self.why_words)), ] + held = level == "bad" and not running_alarm out = { "banner": banner, "level": level, "rows": rows, "checks": checks, "hint": self.hint, @@ -6546,7 +6628,7 @@ class Controller: # fields are served alone (the page then shows the installer details). try: out.update(homeview.build(self, level=level, checks=checks, - lang=lang)) + lang=lang, held=held)) except Exception: # noqa: BLE001 # Once per process at ERROR: the page polls every 3 s. if not getattr(self, "_home_failed", False): diff --git a/goodwe_controller/app/messages.py b/goodwe_controller/app/messages.py index d353b16..b40d730 100644 --- a/goodwe_controller/app/messages.py +++ b/goodwe_controller/app/messages.py @@ -217,7 +217,7 @@ def peak_saturated(ceiling_w, *, shadow: bool = False) -> Notice: def peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, - packs=()) -> Notice: + packs=(), others: bool = False) -> Notice: """SAFETY-24/25/32: the peak guard may not draw the battery any lower. The last sentence is SAFETY-25 and must stay: the reserve binds the peak @@ -227,7 +227,8 @@ def peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, roster means some inverter's cut-out level is missing (the peak reserve itself always has a value) - so the action names the cut-out level. Both are named by their setting labels, "Peak reserve (%)" and "Battery - cut-out level (%)". + cut-out level (%)". `others`: the other batteries give all they can and + it is not enough (SAFETY-87), so the limit MAY be passed. """ if soc_unread: why = "The battery level cannot be read" @@ -241,6 +242,12 @@ def peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, why = (f"The battery of {names(packs)} is at its peak reserve" if packs else "The battery is at its peak reserve") act = "Switch off large loads, or lower the peak reserve." + if others: + return Notice(ID_PEAK_RESERVE, ALARM, T_PEAK_RESERVE, + f"{why}, and the other batteries cannot keep this " + f"15-minute period under your {watts(ceiling_w)} peak " + f"limit alone. {act} Home use can still draw a battery " + f"below its reserve, down to its cut-out level.") return Notice(ID_PEAK_RESERVE, ALARM, T_PEAK_RESERVE, f"{why}, so this 15-minute period will go over your " f"{watts(ceiling_w)} peak limit and raise this month's peak. " @@ -470,8 +477,9 @@ def row_peak_saturated(ceiling_w) -> str: def row_peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, - packs=()) -> str: - """SAFETY-24/25/32. The second sentence is SAFETY-25 and must stay.""" + packs=(), others: bool = False) -> str: + """SAFETY-24/25/32. The last sentence is SAFETY-25 and must stay. + `others`: as in `peak_reserve()` (SAFETY-87).""" if soc_unread: why = "Battery level cannot be read" elif floor_unknown: @@ -479,6 +487,10 @@ def row_peak_reserve(ceiling_w, *, soc_unread: bool, floor_unknown: bool, else: why = (f"{names(packs)} battery at its peak reserve" if packs else "Battery at its peak reserve") + if others: + return (f"{why}. The others cannot hold the {watts(ceiling_w)} peak " + f"limit alone. Home use still draws it lower, to the cut-out " + f"level.") return (f"{why}, so the {watts(ceiling_w)} peak limit will be passed. Home " f"use still draws the battery below it, down to the cut-out level.") @@ -1014,6 +1026,9 @@ def status_samples() -> list: ("row_peak_guard_off", AMBER, row_peak_guard_off()), ("row_peak_reserve", RED, row_peak_reserve( 5000, soc_unread=False, floor_unknown=False, packs=["inverter-b"])), + ("row_peak_reserve", RED, row_peak_reserve( + 5000, soc_unread=False, floor_unknown=False, packs=["inverter-b"], + others=True)), ("row_peak_reserve", RED, row_peak_reserve( 5000, soc_unread=True, floor_unknown=False)), ("row_peak_reserve", RED, row_peak_reserve( @@ -1116,6 +1131,8 @@ def samples() -> list: peak_reserve(5000, soc_unread=False, floor_unknown=False), peak_reserve(5000, soc_unread=False, floor_unknown=False, packs=["inverter-b"]), + peak_reserve(5000, soc_unread=False, floor_unknown=False, + packs=["inverter-b"], others=True), peak_reserve(5000, soc_unread=True, floor_unknown=False), peak_reserve(5000, soc_unread=False, floor_unknown=True), circulating(["inverter-a"], ["inverter-b"]), diff --git a/goodwe_controller/app/peakguard.py b/goodwe_controller/app/peakguard.py index 9e4bf65..2ecaae8 100644 --- a/goodwe_controller/app/peakguard.py +++ b/goodwe_controller/app/peakguard.py @@ -397,7 +397,7 @@ function, so whichever way the owner answers, this file does not change and does not need re-testing. Nothing here indexes a phase. """ -from dataclasses import dataclass +from dataclasses import dataclass, replace from . import messages from .arbiter import ACTUATOR_SITE, P_PEAK, Claim @@ -490,11 +490,18 @@ class PeakDecision: # floor refused to size it. Mutually exclusive with `saturated` by # construction: this branch asks for nothing, so it cannot have run out of # inverter. `soc_floor_reason` says WHICH of the two ways it bound. + # SAFETY-87: at N>=2 it may ask the batteries above their reserve for + # `able_w`, all they have, when that is not enough (`place_on_able()`). floor_limited: bool = False soc: float | None = None soc_floor: float | None = None soc_floor_reason: str | None = None reason: str = "" + # SAFETY-87, N>=2 only: the batteries at or under their own reserve, + # which give nothing for the peak, and what the others can give (None + # when they are not asked). See `place_on_able()`. + held: tuple = () + able_w: float | None = None def explain(self) -> str: """Idle: the status row's plain words (UX-08). Engaged: `reason`, the @@ -733,6 +740,43 @@ def binding_soc_floor(packs, soc_floor): return max(floors) +def reserve_split(packs, soc_floor) -> tuple[list, tuple]: + """SAFETY-87: `(packs the guard may spend, names of those it may not)`, + each pack graded on its own floor by `pack_permissions()`.""" + perms = pack_permissions(packs, soc_floor) + return ([p for p, (_n, why) in zip(packs, perms) if why is None], + tuple(n for n, why in perms if why is not None)) + + +def place_on_able(decision, held, *, able_w, soc, soc_floor) -> PeakDecision: + """SAFETY-87: `decision` with the batteries in `held` (at or under their + own reserve) giving nothing for the peak. `able_w`, `soc` and `soc_floor` + describe the others, as `decide()`'s arguments do for the roster. A + floor-limited decision is re-taken on them: they are asked for the need + up to `able_w`, and it stays floor-limited only if that is not enough. + `soc` and `soc_floor` keep the roster's verdict, as `decide()` echoed it. + DECISIONS/SAFETY-87-guard-uses-able-batteries.md.""" + held = tuple(held) + if not decision.floor_limited or decision.wanted_w is None \ + or discharge_permitted(soc, soc_floor) is not None: + return replace(decision, held=held) + wanted = float(decision.wanted_w) + floor = min(wanted, float(able_w)) + head = (f"this 15-minute period heads for {decision.projected_w:.0f} W " + f"against a {decision.ceiling_w:.0f} W limit " + f"({decision.ceiling_from}), aiming at {decision.target_w:.0f} W. " + f"At the peak reserve, so giving nothing for the peak: " + f"{messages.names(held)}. The others are asked for {floor:+.0f} W") + if floor >= wanted: + return replace(decision, floor_limited=False, floor_w=floor, + soc_floor_reason=None, held=held, able_w=float(able_w), + reason=f"PEAK_GUARD: {head}") + return replace(decision, floor_w=floor, held=held, able_w=float(able_w), + reason=(f"PEAK_GUARD_FLOOR_LIMITED: {head}, all they can " + f"give, but {wanted:+.0f} W was needed, so this " + f"period may go over the limit")) + + def decide(projection, *, batt_w, cap_w, margin_w, reading, achievable_w, soc, soc_floor, max_hold_s=None, frozen: bool = False) -> PeakDecision: """The whole guard. Pure: no clock, no I/O, no state carried between calls. @@ -1097,5 +1141,6 @@ def claim(decision: PeakDecision) -> Claim | None: return Claim.limit(SOURCE, P_PEAK, lo=float(decision.floor_w), reason=("blind" if decision.blind else "SoC floor" if decision.floor_limited + and not decision.floor_w else "quarter peak"), actuator=ACTUATOR_SITE) diff --git a/goodwe_controller/test_peakguard.py b/goodwe_controller/test_peakguard.py index 29bae44..ac02b5f 100644 --- a/goodwe_controller/test_peakguard.py +++ b/goodwe_controller/test_peakguard.py @@ -109,6 +109,7 @@ import re import shutil import sys import tempfile +import types import time from datetime import datetime, timedelta, timezone from math import inf, isinf @@ -2537,12 +2538,18 @@ print(f" banner ({len(_pay25['banner'])} chars): {_pay25['banner']}") # that is going over the ceiling. # UX-08: the banner is the notification's own title, and the row below keeps # the SAFETY-25 sentence. -check("the Not ready banner is a short headline - the notification's title - " - "and NOT the row repeated at the top of the page. A headline that is a " - "paragraph is a headline nobody reads", +# SAFETY-87: control goes on while the guard is floor-limited, so the banner +# does not say "Not ready". This fixture also has a row that does stop control +# (no SoC entity), which outranks it; the peak row alone is graded below. +c25.checks = lambda: rows25 +_pay25 = c25.status_payload() +del c25.checks +print(f" banner, peak row alone: {_pay25['banner']}") +check("the banner is a short headline - the notification's title, without " + "'Not ready' (control goes on) - and NOT the row repeated at the top of " + "the page. A headline that is a paragraph is a headline nobody reads", _pay25["level"] == "bad" - and _pay25["banner"] == (f"{messages.NOT_READY} — " - f"{messages.T_PEAK_RESERVE}") + and _pay25["banner"] == messages.T_PEAK_RESERVE and not _row_scope(_pay25["banner"])) check("...and shortening the banner did NOT shorten the row: the SAFETY-25 " "sentence is still what the checks list carries, which is the surface the " @@ -4139,18 +4146,22 @@ check("⚠️ ...AND THE SAME PAIR SWAPPED GIVES THE SAME SITE FLOOR, so no " and _g_deepa.soc_floor != _g_shallow.soc_floor and [pk.bms_floor for pk in _g_ctl_deepa.packs] == [B_PACK_FLOOR_DEEP_SIM, B_PACK_FLOOR_SIM]) -check("...and it is not just a number in a report - THE SITE'S VERDICT FLIPS. " - "With both packs at 25 % the shallow site is permitted and the guard " - "sizes a positive forced discharge; BOTH deep sites are FLOOR-LIMITED, " - "because 25 % is at or below the 35 % cut-out wherever on the roster it " - "sits. Grading the roster against one position would spend a pack its " - "BMS stops - through `sim/inject.py`, which does not run rule 8 - and " - "this line is what goes red when it does", +# SAFETY-87 changed what the verdict is at N>=2: the pack at or under its own +# floor is HELD (named, gives nothing for the peak) and the others still shave. +check("...and it is not just a number in a report - THE HELD PACK FOLLOWS IT. " + "With both packs at 25 % the shallow site holds nobody back; on BOTH deep " + "sites the pack whose 35 % cut-out is at or above 25 % is held, wherever " + "it sits, gives nothing for the peak (weight 0), and the other pack " + "carries a positive floor (SAFETY-87). Holding a position instead of " + "the pack would spend a pack its BMS stops", _g_shallow.floor_limited is False and _g_shallow.floor_w > 0.0 - and _g_deep.floor_limited is True and _g_deep.floor_w == 0.0 - and _g_deep.soc_floor_reason == FLOOR_AT_SOC_FLOOR - and _g_deepa.floor_limited is True and _g_deepa.floor_w == 0.0 - and _g_deepa.soc_floor_reason == FLOOR_AT_SOC_FLOOR) + and _g_shallow.held == () + and _g_deep.floor_limited is False and _g_deep.floor_w > 0.0 + and _g_deep.held == ("inverter-b",) + and _g_ctl_deep._peak_reserve() == {"inverter-b"} + and _g_deepa.floor_limited is False and _g_deepa.floor_w > 0.0 + and _g_deepa.held == ("inverter-a",) + and _g_ctl_deepa._peak_reserve() == {"inverter-a"}) check("...and the precondition that makes the three runs comparable (habit 1): " "the two deep runs carry THE SAME PAIR of cut-outs in opposite orders, " "those two numbers really are different, and all six packs are at the " @@ -4221,14 +4232,14 @@ check("⚠️ THE POSITIONAL PIN, AND IT NEEDS THREE PACKS TO EXIST. On a roster for r in _g3_runs) and [[pk.bms_floor for pk in r[2].packs] for r in _g3_runs] == [r[1] for r in _g3_runs]) -check("...and the VERDICT flips with it, on all three: 25 % is at or below the " - "35 % cut-out wherever it sits, so every one of these sites is " - "FLOOR-LIMITED and sizes no forced discharge at all - where the " - "all-shallow two-pack baseline above was permitted and sized a positive " - "one. A slice that dropped the deep position would spend, through " - "`sim/inject.py`, a pack its BMS stops", - all(r[3].floor_limited is True and r[3].floor_w == 0.0 - and r[3].soc_floor_reason == FLOOR_AT_SOC_FLOOR for r in _g3_runs) +check("...and the HELD pack follows it, on all three (SAFETY-87): 25 % is at " + "or below the 35 % cut-out wherever it sits, so that pack and only that " + "pack is held and gives nothing for the peak, while the two others carry " + "a positive floor. A slice that dropped the deep position would spend, " + "through `sim/inject.py`, a pack its BMS stops", + all(r[3].floor_limited is False and r[3].floor_w > 0.0 + and r[3].held == (r[2].inverters[r[1].index(_G3_DEEP_SIM)].name,) + and r[2]._peak_reserve() == set(r[3].held) for r in _g3_runs) and _g_shallow.floor_limited is False and _g_shallow.floor_w > 0.0) check("...and the precondition that makes the three comparable (habit 1): every " "pack in all three rosters is at the SAME state of charge, so neither the " @@ -4386,12 +4397,18 @@ async def _notify32(packs_socs, floors): inv_b, _ = second_inverter(ctl) for inv, so, fl in zip(ctl.inverters, packs_socs, floors): inv.soc, inv.bms_soc_floor = so, fl - ctl.peak_guard = PeakDecision( + # SAFETY-87: the full pack refuses to give (SAFETY-73), so no battery + # can carry the peak and the alarm still fires; it names the held one. + inv.refused = 1 if so > SOC_FLOOR else 0 + _idle = [types.SimpleNamespace(phase="idle", owns_setpoint=False, + setpoint_w=None)] * 2 + ctl.peak_guard = ctl._peak_on_able(PeakDecision( engaged=True, floor_w=0.0, ceiling_w=CAP_W, ceiling_from=CEILING_CAP, projected_w=CAP_W + 500.0, excess_w=500.0, wanted_w=500.0, floor_limited=True, soc=min(packs_socs), soc_floor=binding_soc_floor(ctl.packs, SOC_FLOOR), - soc_floor_reason=FLOOR_AT_SOC_FLOOR, reason="PEAK GUARD FLOOR-LIMITED: x") + soc_floor_reason=FLOOR_AT_SOC_FLOOR, reason="PEAK GUARD FLOOR-LIMITED: x"), + _idle) ctl._peak_floor_limited = False await ctl.check_peak_floor_limited() return hs.last_message("goodwe_peak_soc_floor") @@ -4581,18 +4598,19 @@ check("...and the TWO-pack mirror, which is what production reaches the moment " [r[3].soc for r in _s2_runs] == [_S_EMPTY_SIM] * 2 and [[inv.soc for inv in r[2].inverters] for r in _s2_runs] == [[_S_EMPTY_SIM, _S_FULL_SIM], [_S_FULL_SIM, _S_EMPTY_SIM]]) -check("⚠️ ...AND THE SITE'S VERDICT FLIPS WITH IT, which is what makes this a " - "defect rather than a reporting difference. With the emptiest pack at " - "11 % - below the 20 % EMS floor - every one of those five sites is " - "FLOOR-LIMITED and sizes NO forced discharge at all, where the baseline " - "with its emptiest pack at 25 % is permitted and sizes a positive one. A " - "reduction that dropped the empty pack's position would grade this site " - "for PERMISSION against a pack 39 points fuller and spend, through " - "`sim/inject.py`, a pack its own BMS stops", - all(r[3].floor_limited is True and r[3].floor_w == 0.0 +# SAFETY-87: at N>=2 the emptiest pack is HELD and the others still shave. +check("⚠️ ...AND THE HELD PACK FOLLOWS IT, which is what makes this a defect " + "rather than a reporting difference. With the emptiest pack at 11 % - " + "below the 20 % EMS floor - that pack and only that pack is held on " + "every one of those five sites and gives nothing for the peak, while " + "the fuller ones carry a positive floor (SAFETY-87); the baseline holds " + "nobody back. A reduction that dropped the empty pack's position would " + "spend, through `sim/inject.py`, a pack its own BMS stops", + all(r[3].floor_limited is False and r[3].floor_w > 0.0 + and r[3].held == (r[2].inverters[r[1].index(_S_EMPTY_SIM)].name,) for r in _s3_runs + _s2_runs) and _s_ok.floor_limited is False and _s_ok.floor_w > 0.0 - and _s_ok.soc == SOC_BETWEEN) + and _s_ok.held == () and _s_ok.soc == SOC_BETWEEN) check("...and the precondition that makes the six runs comparable (habit 1): " "every pack in every roster carries the SAME cut-out, so " "`binding_soc_floor()` answers the SAME site floor on all of them and the " @@ -5727,8 +5745,8 @@ MUT.append(("main.py grading the site against ONE roster position - " _g_deep.soc_floor == float(B_PACK_FLOOR_DEEP_SIM) and _g_deepa.soc_floor == float(B_PACK_FLOOR_DEEP_SIM) and _g_shallow.soc_floor == float(SOC_FLOOR) - and _g_deep.floor_limited and _g_deepa.floor_limited - and not _g_shallow.floor_limited, + and _g_deep.held == ("inverter-b",) + and _g_deepa.held == ("inverter-a",) and _g_shallow.held == (), "part 12g, REWRITTEN as behaviour: real two-pack cycles, the SAME " "pair of cut-outs carried in both orders, and both the floor " "reaching decide() and the site's verdict follow the ROSTER rather " diff --git a/goodwe_controller/test_safety86.py b/goodwe_controller/test_safety86.py index ce761d0..35a4d4a 100644 --- a/goodwe_controller/test_safety86.py +++ b/goodwe_controller/test_safety86.py @@ -337,7 +337,8 @@ HOLDING = [MaintResult(HOLD, True, 0.0, False, []), def pin_after(floor, *extra, live=(A, B), results=HOLDING, c=_c): fake = types.SimpleNamespace(inverters=c.inverters, actuator_of=c.actuator_of, - live_units=lambda: tuple(live)) + live_units=lambda: tuple(live), + _peak_reserve=frozenset) cl = [Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=A), Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=B), Claim.set("maintenance", P_MAINTENANCE, 0.0, HOLD, actuator=A), diff --git a/goodwe_controller/test_safety87.py b/goodwe_controller/test_safety87.py new file mode 100644 index 0000000..e410ba2 --- /dev/null +++ b/goodwe_controller/test_safety87.py @@ -0,0 +1,512 @@ +"""Runnable check for SAFETY-87: the peak guard uses every battery that can +still give. `python3 test_safety87.py` + +At N>=2 the guard graded the EMPTIEST battery (SAFETY-32), so one battery under +the peak reserve stopped the guard for all of them: it asked for nothing and +raised the reserve alarm while the other battery was full. Now a battery at or +under its own reserve is HELD (it gives nothing for the peak, weight 0) and +the guard's need is placed on the others; the reserve alarm fires only when +they cannot hold the limit. Drives the REAL Controller (tools/ +safety84_identity.py's harness). DECISIONS/SAFETY-87-guard-uses-able-batteries.md. + +1. Maintenance charge at N=2 (A under the reserve, B able), house over the + aim: no reserve alarm, the quarter on the aim, A gives nothing for the + peak while B can carry it. When B cannot, the alarm fires and names A. +2. HOLD at N=2 (A full holding, B under the reserve): A gives, B gives + nothing, the quarter lands on the aim; at a banked month peak too. +3. Both under the reserve, or the other one refusing: the alarm still fires + and names the right battery. +4. The alarm at the quarter's edge: a one-cycle miss does not fire it. +5. place_on_able() at its boundaries, and the claim it files. +6. The allocator: a held battery gives last, after an Off one. +7. A held battery draining for maintenance counts for its drain. +8. The page: a peak alarm does not say "Not ready" or "0 W until the alarm + clears" while control goes on. +9. N=1 is byte-identical to release/1.0 b8ddfd7 (tools/safety87_identity.py). + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import asyncio +import dataclasses +import json +import logging +import os +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11_identity as rig # noqa: E402 +import safety84_identity as s84 # noqa: E402 +import safety87_identity as s87 # noqa: E402 +from app import messages, packmode, peakguard # noqa: E402 +from app.arbiter import (Claim, P_MODE, P_PEAK, P_SAFETY, # noqa: E402 + UnitBounds, resolve) +from app.main import Controller # noqa: E402 +from app.maintenance import DRAIN, HOLD, IDLE, MaintResult # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] +A, B = "inverter-a", "inverter-b" +AIM = 3450.0 # peak_cap_w 3500 - peak_margin_w 50 +TOL = 10.0 # W over the aim a banked quarter may show (SAFETY-81) + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +def store(phase, *, b_off=False): + """Battery A in `phase` from the first cycle (B idle, cycle done).""" + s = rig._Store() + s.data[unit_key(A, "phase")] = phase + s.data[unit_key(A, "phase_started")] = rig.BASE.isoformat() + s.data[unit_key(B, "last_completed")] = rig.BASE.isoformat() + if phase == IDLE: + s.data[unit_key(A, "last_completed")] = rig.BASE.isoformat() + if b_off: + s.data[unit_key(B, packmode.USE_KEY)] = False + return s + + +def run(house, phase, socs, *, cheap=False, n=2, **kw): + """Rows, controller, the notifications raised and one record per cycle: + (floor_limited, held, floor_w, reserve set, alarm latched).""" + notes, seen = [], [] + real_check = Controller.check_peak_floor_limited + + async def spy(self): + await real_check(self) + g = self.peak_guard + seen.append(None if g is None else ( + g.floor_limited, g.held, g.floor_w, self._peak_reserve(), + self._peak_floor_limited)) + + def before(c, t): + if not getattr(c.hass, "_s87", False): + real = c.hass.call + + async def call(*a): + if a[:2] == ("persistent_notification", "create"): + notes.append(a[2]) + return await real(*a) + c.hass.call, c.hass._s87 = call, True + return s84.feed(cheap)(c, t) + + kw.setdefault("dur", 2700.0) + extra = dict({"maintenance_hold_min": 600}, **kw.pop("extra", {})) + Controller.check_peak_floor_limited = spy + try: + rows, c = s84.run( + n, load=house if callable(house) else lambda t: house, + cheap=cheap, store=kw.pop("store", None) or store(phase), + soc=lambda u, t: socs[u], before=before, extra=extra, **kw) + finally: + Controller.check_peak_floor_limited = real_check + return rows, c, notes, seen + + +def without_fix(fn): + """The shipped b8ddfd7 behaviour: no battery is ever held back.""" + real = Controller._peak_on_able + Controller._peak_on_able = lambda self, decision, results: decision + try: + return fn() + finally: + Controller._peak_on_able = real + + +def cmd(r): + return dict(r[2]) + + +def banked(c): + return [b.offtake_avg_w for b in c.p1.blocks] + + +def on_aim(c, aim=AIM): + b = banked(c) + return len(b) >= 2 and all(aim - TOL <= v <= aim + TOL for v in b) + + +def reserve_notes(notes): + return [x for x in notes + if x["notification_id"] == messages.ID_PEAK_RESERVE] + + +def limited_events(c): + return sum(1 for e in c.events if "PEAK_GUARD_FLOOR_LIMITED" in e) + + +def show(tag, rows, c, notes, seen): + a = [cmd(r)["a"] for r in rows] + b = [cmd(r)["b"] for r in rows] + print(f" {tag}: banked {[round(v, 1) for v in banked(c)]} W, mean A " + f"{sum(a) / len(a):.0f} W, B {sum(b) / len(b):.0f} W, reserve " + f"alarms {len(reserve_notes(notes))}, held " + f"{sorted({h for s in seen if s for h in s[1]})}") + + +# ============================================================================ # +print("1. maintenance charge at N=2: A under the reserve, B able") +LOW_A = {"a": 11.0, "b": 60.0} +CH = run(4500.0, "charge", LOW_A, cheap=True) +CH_OLD = without_fix(lambda: run(4500.0, "charge", LOW_A, cheap=True)) +show("house 4500", *CH) +show("house 4500, before the fix", *CH_OLD) +check("⭐ house 4500 W, B can carry the guard alone: no reserve alarm (no " + "notification, no PEAK_GUARD_FLOOR_LIMITED line) and every quarter on " + "the aim", + not reserve_notes(CH[2]) and limited_events(CH[1]) == 0 + and on_aim(CH[1])) +check("...A is held (it gives nothing for the peak) on every cycle the guard " + "asks for power, and the guard asks for a positive floor", + any(s and s[2] and s[2] > 0.0 for s in CH[3]) + and all(s[1] == (A,) and s[3] == {A} for s in CH[3] + if s and s[2] and s[2] > 0.0)) +check("non-vacuous: before the fix the same run raised the reserve alarm " + "(the SAFETY-84 rig test's check 2/3 false alarm)", + len(reserve_notes(CH_OLD[2])) >= 1 and limited_events(CH_OLD[1]) >= 1) +_b_carry = [r for r, s in zip(CH[0], CH[3]) + if s and s[3] == {A} and r[1] <= 2500.0 and r[1] > 0.0] +check("...and while B can carry the site target (at most its 2500 W) A is " + "not asked to give at all (weight 0 behind B)", + len(_b_carry) >= 3 and all(cmd(r)["a"] <= 0.0 for r in _b_carry)) + +CH65 = run(6500.0, "charge", LOW_A, cheap=True) +show("house 6500", *CH65) +_n65 = reserve_notes(CH65[2]) +check("⭐ house 6500 W, B (2500 W) cannot hold the 3450 W aim alone: the " + "reserve alarm fires and names A, the battery under its reserve, and " + "says the others cannot hold the limit alone", + len(_n65) >= 1 + and all("inverter-a is at its peak reserve" in x["message"] + and "inverter-b" not in x["message"] + and "cannot keep this 15-minute period under your 3 500 W peak " + "limit alone" in x["message"] for x in _n65)) +check("...and while it is limited the guard still asks B for everything B " + "has (floor 2500 W), so B is never left idle", + any(s and s[0] and s[2] == 2500.0 for s in CH65[3]) + and all(s[2] == 2500.0 for s in CH65[3] if s and s[0])) + +# ============================================================================ # +print("\n2. HOLD at N=2: A full and holding, B under the reserve") +LOW_B = {"a": 99.0, "b": 15.0} +HD = run(5500.0, HOLD, LOW_B) +HD_OLD = without_fix(lambda: run(5500.0, HOLD, LOW_B)) +show("house 5500", *HD) +show("house 5500, before the fix", *HD_OLD) +check("⭐ house 5500 W: A gives, B gives nothing, every quarter lands on the " + "aim, no reserve alarm, and A stays in its HOLD", + on_aim(HD[1]) and not reserve_notes(HD[2]) + and limited_events(HD[1]) == 0 + and all(cmd(r)["b"] == 0.0 for r in HD[0]) + and max(cmd(r)["a"] for r in HD[0]) > 2000.0 + and HD[1].maints[0].phase == HOLD) +check("non-vacuous: before the fix A sat at 0 W, B (at 15 %) gave through " + "the loop and the reserve alarm fired (SAFETY-86 rig case 7a)", + all(cmd(r)["a"] == 0.0 for r in HD_OLD[0]) + and max(cmd(r)["b"] for r in HD_OLD[0]) > 2000.0 + and len(reserve_notes(HD_OLD[2])) >= 1) + +HD65 = run(6500.0, HOLD, LOW_B) +HD65_OLD = without_fix(lambda: run(6500.0, HOLD, LOW_B)) +show("house 6500", *HD65) +show("house 6500, before the fix", *HD65_OLD) +_n = reserve_notes(HD65[2]) +check("⭐ house 6500 W, A alone (2500 W) cannot hold the aim: A gives all it " + "has, B still gives nothing, and the reserve alarm fires ONCE naming B", + all(cmd(r)["b"] == 0.0 for r in HD65[0]) + and max(cmd(r)["a"] for r in HD65[0]) == 2500.0 + and len(_n) == 1 and "inverter-b is at its peak reserve" in + _n[0]["message"] and "inverter-a" not in _n[0]["message"]) +check("...and the quarter is no worse than before the fix (4051 W in the " + "SAFETY-86 review), with B kept at its reserve", + max(banked(HD65[1])) <= max(banked(HD65_OLD[1])) + 1.0) + +BK = run(6000.0, HOLD, LOW_B, month_peak=4000.0) +show("house 6000, month peak 4000", *BK) +check("⭐ under a banked month peak of 4000 W the aim is 3950 W (peak - " + "margin): A gives, B nothing, every quarter on 3950 W, no alarm", + on_aim(BK[1], 3950.0) and not reserve_notes(BK[2]) + and all(cmd(r)["b"] == 0.0 for r in BK[0])) + +# ============================================================================ # +print("\n3. a real loss of peak limiting still alarms") +BOTH = run(5500.0, IDLE, {"a": 15.0, "b": 12.0}) +show("both under", *BOTH) +_nb = reserve_notes(BOTH[2]) +check("⭐ both batteries under the reserve: the reserve alarm fires and " + "names both, the guard asks for nothing (claim lo 0 W, 'SoC floor')", + len(_nb) >= 1 + and all("inverter-a and inverter-b" in x["message"] for x in _nb) + and all(not s[2] for s in BOTH[3] if s and s[0]) + and any(c[0] == "peak" and c[4] == 0.0 and c[6] == "SoC floor" + for r in BOTH[0] for c in r[-1][0])) + + +_ctl2 = BOTH[1] +for _inv, _s, _r in zip(_ctl2.inverters, (15.0, 60.0), (0, 1)): + _inv.soc, _inv.refused = _s, _r # SAFETY-73: B refuses to give +_ref = _ctl2._peak_on_able(_lim_all := peakguard.PeakDecision( + engaged=True, floor_w=0.0, ceiling_w=3500.0, + ceiling_from=peakguard.CEILING_CAP, projected_w=4000.0, excess_w=550.0, + wanted_w=2000.0, target_w=3450.0, floor_limited=True, soc=15.0, + soc_floor=20.0, soc_floor_reason=peakguard.FLOOR_AT_SOC_FLOOR, + reason="PEAK_GUARD_FLOOR_LIMITED: x"), + [MaintResult(IDLE, False, None, False, [])] * 2) +check("⭐ A under the reserve and B refusing to give (SAFETY-73): nothing can " + "give for the peak, so it stays limited at 0 W (the alarm fires) and " + "only A is named (test_peakguard.py part 12h drives the notification)", + _ref.floor_limited and _ref.floor_w == 0.0 and _ref.held == (A,) + and _ref.able_w is None and _ctl2._peak_reserve() == frozenset()) +_ctl2.inverters[1].refused = 0 +_ctl2.live_units = lambda: (A,) # B dropped from the split +_drop = _ctl2._peak_on_able(_lim_all, [MaintResult(IDLE, False, None, False, + [])] * 2) +del _ctl2.live_units +check("...and the same with B dropped (not live): nothing can give, the " + "alarm state stands at 0 W, only A named", + _drop.floor_limited and _drop.floor_w == 0.0 and _drop.held == (A,) + and _drop.able_w is None) + + +async def _notify(ctl, socs, cutouts, refused): + """The shipped check_peak_floor_limited() on `ctl`, its notification.""" + sent = [] + + async def call(*a): + sent.append(a) + return True + for inv, so, cut, ref in zip(ctl.inverters, socs, cutouts, refused): + inv.soc, inv.bms_soc_floor, inv.refused = so, cut, ref + real, ctl.hass.call = ctl.hass.call, call + ctl.peak_guard = ctl._peak_on_able(dataclasses.replace( + _lim_all, soc=min(socs), soc_floor=peakguard.binding_soc_floor( + ctl.packs, 20.0)), [MaintResult(IDLE, False, None, False, [])] * 2) + ctl._peak_floor_limited = False + try: + await ctl.check_peak_floor_limited() + finally: + ctl.hass.call = real + for inv in ctl.inverters: + inv.bms_soc_floor, inv.refused = 10, 0 + return [a[2]["message"] for a in sent + if a[2].get("notification_id") == messages.ID_PEAK_RESERVE] + + +# Cut-outs A 10 % / B 35 % (simulated; rule 8 refuses it, sim/inject.py does +# not run rule 8), A at 25 % refusing, B at 30 %. Only B is at its own floor; +# A is above its own but under the site's highest (35 %). +_msg = asyncio.run(_notify(_ctl2, (25.0, 30.0), (10, 35), (1, 0))) +print(f" differing cut-outs: {_msg}") +check("⭐ the alarm names the battery at ITS OWN floor (B, 30 % <= 35 %), not " + "every battery under the site's highest floor (A at 25 % is above its " + "own 20 %)", + len(_msg) == 1 and "inverter-b is at its peak reserve" in _msg[0] + and "inverter-a" not in _msg[0]) + + +# ============================================================================ # +print("\n4. the reserve alarm at the quarter's edge") +def spiky(t): + """A 5000 W house (B alone can hold the aim) with a 5 s spike to + 11000 W every 150 s, which B alone cannot.""" + return 11000.0 if t % 150 < 5 else 5000.0 + + +LOW_A_IDLE = {"a": 15.0, "b": 60.0} +SP = run(spiky, IDLE, LOW_A_IDLE) +_flips = sum(1 for s in SP[3] if s and s[0]) +show("spiky house", *SP) +print(f" {_flips} cycles floor-limited (B alone short during a spike)") +check("⭐ a 5 s spike that B alone cannot cover makes the guard limited for a " + "cycle, and that does not fire the alarm: the miss must hold for " + "ALARM_HOLD_S, as for 'Load too high'. No quarter goes over the aim", + _flips >= 5 and not reserve_notes(SP[2]) + and not any(s[4] for s in SP[3] if s) + and len(banked(SP[1])) >= 2 and max(banked(SP[1])) <= AIM) + + +def ungated(fn): + real = Controller._reserve_short + Controller._reserve_short = lambda self, g: True + try: + return fn() + finally: + Controller._reserve_short = real + + +_ug = ungated(lambda: run(spiky, IDLE, LOW_A_IDLE)) +check("non-vacuous: without the hold the same run raises the alarm", + len(reserve_notes(_ug[2])) >= 1) + +# ============================================================================ # +print("\n5. place_on_able() at its boundaries") +_lim = peakguard.PeakDecision( + engaged=True, floor_w=0.0, ceiling_w=3500.0, + ceiling_from=peakguard.CEILING_CAP, projected_w=4000.0, excess_w=550.0, + wanted_w=2000.0, target_w=3450.0, floor_limited=True, soc=15.0, + soc_floor=20.0, soc_floor_reason=peakguard.FLOOR_AT_SOC_FLOOR, + reason="PEAK_GUARD_FLOOR_LIMITED: x") + + +def place(d=_lim, held=("b",), able_w=2000.0, soc=60.0, floor=20.0): + return peakguard.place_on_able(d, held, able_w=able_w, soc=soc, + soc_floor=floor) + + +_eq, _short = place(), place(able_w=1999.0) +check("⭐ the others can give exactly the need (2000 W): not limited, floor " + "2000 W, the claim reads 'quarter peak' (the page says 'the peak " + "limit')", + not _eq.floor_limited and _eq.engaged and _eq.floor_w == 2000.0 + and _eq.held == ("b",) and _eq.able_w == 2000.0 + and peakguard.claim(_eq).lo == 2000.0 + and peakguard.claim(_eq).reason == "quarter peak" + and _eq.reason.startswith("PEAK_GUARD: ")) +check("...1 W short: limited, but the claim still asks them for all they " + "have (1999 W), not 0 W", + _short.floor_limited and _short.floor_w == 1999.0 + and peakguard.claim(_short).lo == 1999.0 + and peakguard.claim(_short).reason == "quarter peak" + and _short.reason.startswith("PEAK_GUARD_FLOOR_LIMITED: ")) +check("...the others' own permission is graded: at or under their floor, or " + "unread, nothing is asked (0 W, 'SoC floor')", + all(place(soc=s).floor_w == 0.0 and place(soc=s).floor_limited + and peakguard.claim(place(soc=s)).reason == "SoC floor" + for s in (20.0, 19.0, None))) +check("...the roster's verdict is kept as decide() echoed it (soc 15 %, " + "floor 20 %), and a decision that was not limited is only labelled", + _eq.soc == 15.0 and _eq.soc_floor == 20.0 + and all(place(d=d) == dataclasses.replace(d, held=("b",)) + for d in (dataclasses.replace( + _lim, floor_limited=False, engaged=False, + floor_w=None), + dataclasses.replace(_lim, wanted_w=None)))) +check("...and at N=1 the floor-limited claim is unchanged: 0 W, 'SoC floor'", + peakguard.claim(_lim).lo == 0.0 + and peakguard.claim(_lim).reason == "SoC floor") + +# ============================================================================ # +print("\n6. the allocator: a held battery gives last") + + +def split(target, reserve, modes=(), floor=1500.0): + cl = [Claim.set("loop", 10, target), + Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=A), + Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=B), + Claim.limit("peak", P_PEAK, lo=min(target, floor))] + cl += [Claim.limit("mode", P_MODE, 0.0, 0.0, "off", actuator=u) + for u in modes] + r = resolve(cl, units=(A, B), live=(A, B), weights={A: 1.0, B: 3.0}, + reserve=reserve) + return {u: round(v) for u, v in r.shares.items()} + + +check("⭐ B held: A carries the site target first (B's weight 3.0 ignored) " + "and B only takes what A cannot: 1500 -> A 1500 / B 0, 4000 -> A 2500 " + "/ B 1500", + split(1500.0, {B}) == {A: 1500, B: 0} + and split(4000.0, {B}) == {A: 2500, B: 1500}) +check("...no one held: the weights decide, as before", + split(1500.0, set()) == {A: 375, B: 1125}) +check("...charging is not touched: a held battery may still charge first", + split(-2000.0, {B}) == split(-2000.0, set())) +check("⭐ A Off and B under the reserve, a 3000 W floor B cannot place: the " + "Off battery gives first (2500 W) and B only the last 500 W - not an " + "equal 1500/1500 split", + split(3000.0, {B}, modes=(A,), floor=3000.0) == {A: 2500, B: 500}) +check("...OPEN, recorded: when B alone CAN place the floor, OPT-11 keeps the " + "Off battery resting and B gives it (1500 W). See the DECISIONS entry", + split(1500.0, {B}, modes=(A,)) == {A: 0, B: 1500}) +check("...and with B Off and nobody held, Off still gives way to the other " + "battery, as before (OPT-11)", + split(1500.0, set(), modes=(B,)) == {A: 1500, B: 0}) + +# ============================================================================ # +print("\n7. a held battery draining for maintenance") +_ctl = HD[1] + + +def able_w(results, socs=(15.0, 60.0)): + for inv, s in zip(_ctl.inverters, socs): + inv.soc, inv.refused = s, 0 + d = _ctl._peak_on_able(dataclasses.replace( + _lim, wanted_w=6000.0), results) + return d.able_w, d.held, d.floor_w + + +_idle = [MaintResult(IDLE, False, None, False, [])] * 2 +_drain = [MaintResult(DRAIN, True, 2000.0, False, []), + MaintResult(IDLE, False, None, False, [])] +print(f" A at 15 % idle: {able_w(_idle)}; draining 2000 W: " + f"{able_w(_drain)}") +check("⭐ A under the reserve but draining 2000 W for its monthly cycle: " + "that drain still counts (able 4500 W = B 2500 + 2000), so B is not " + "asked to carry it; idle, only B's 2500 W", + able_w(_idle) == (2500.0, (A,), 2500.0) + and able_w(_drain) == (4500.0, (A,), 4500.0)) + +# ============================================================================ # +print("\n8. the page while a peak alarm stands and control goes on") +_rows65, _c65 = CH65[0], CH65[1] +_c65._peak_floor_limited = True +_c65.peak_guard = dataclasses.replace( + _lim, floor_w=2500.0, held=(A,), able_w=2500.0) +_pay = _c65.status_payload() +_txt = json.dumps(_pay, ensure_ascii=False) +_row = [r for r in _pay["checks"] if r.get("id") == "peak_guard"] +print(f" banner: {_pay['banner']}; row: {_row[0]['text'] if _row else '-'}") +check("⭐ the banner is the alarm's title without 'Not ready', and nothing " + "on the page says the inverters go to 0 W or that an alarm stopped " + "control", + _pay["banner"] == messages.T_PEAK_RESERVE and _pay["level"] == "bad" + and "Not ready" not in _txt and "until the alarm clears" not in _txt + and "An alarm stopped control" not in _txt) +check("...the row names A and says the others cannot hold the limit alone, " + "in three short sentences", + len(_row) == 1 and _row[0]["text"].startswith( + "inverter-a battery at its peak reserve. The others cannot hold " + "the 3 500 W peak limit alone.")) +_c65.auto = False +_stopped = _c65.status_payload() +_c65.auto = True +check("...a stopped controller still says so: the peak alarm does not take " + "the banner from it", _stopped["banner"] != messages.T_PEAK_RESERVE + and _stopped["level"] != "bad") + +# ============================================================================ # +print("\n9. N=1 is byte-identical to release/1.0 b8ddfd7") +PINNED = { # tools/safety87_identity.py on b8ddfd7 + "n1_under": + "d2395ef8d74fb23607ad864d5a4bf62c03044bbd9367e873675d7ad10e8c169f", + "n1_crossing": + "97f7321017d9d34ee17a40dfd4abf73d915f25b9faef086a483d2b5cd124b198", + "n1_above": + "45726a285aa84f40542d56482652397c3c1e212ba4fe2009f6cc52f537ccad52", + "n1_under_banked": + "a2876c7cc873bc4c974d2b4bd98e23bba2d007b84545587d2fe0b713b0a6249b", + "n1_charge_low": + "91336e3c0314985a3b00f314c79b5ffb5a740d218de3ad44f88a4db6e4235b32", + "n1_hold": + "0a1df347754c69166b20d04c15ee878bbcefb02abb824b9b452334f68f03e46d", +} +_now = s87.digests() +for k in PINNED: + print(f" {k} {'same' if _now[k] == PINNED[k] else 'DIFFERS'}") +check("⭐ every N=1 digest (claims, commands, the guard's decision and the " + "log) equals b8ddfd7's, under, crossing and above the reserve, in a " + "charge and a HOLD, and under a banked peak", + _now == PINNED) + +print() +if fails: + print(f"{len(fails)} FAILED: " + ", ".join(fails)) + sys.exit(1) +print("all SAFETY-87 checks passed") diff --git a/goodwe_controller/tools/safety87_identity.py b/goodwe_controller/tools/safety87_identity.py new file mode 100644 index 0000000..209c2a6 --- /dev/null +++ b/goodwe_controller/tools/safety87_identity.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""SAFETY-87: at one inverter, is the peak guard byte-identical to before? + + python3 tools/safety87_identity.py # prints one digest per scenario + +safety84_identity's harness (the REAL Controller on a P1 meter, every claim +and the guard's decision hashed) with the battery under, crossing and above +the peak reserve, the house over the aim, in a maintenance charge and HOLD, +and under a month peak banked at 4000 W. Uses only the API release/1.0 +b8ddfd7 has, so the same file runs on both trees; test_safety87.py holds this +tree to the digests printed there. +""" + +import os +import sys +from datetime import timedelta + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import opt11_identity as rig # noqa: E402 +import safety84_identity as s84 # noqa: E402 + +DUR = 1800.0 + + +def crossing(u, t): + """30 % falling 1 % a minute to 12 %: crosses the 20 % reserve.""" + return max(12.0, 30.0 - t / 60.0) + + +def store(phase=None): + """In `phase` from the first cycle, or idle with a cycle done yesterday.""" + s = rig._Store() + if phase is None: + s.data["last_completed"] = (rig.BASE - timedelta(days=1)).isoformat() + else: + s.data["phase"], s.data["phase_started"] = phase, rig.BASE.isoformat() + return s + + +SCENARIOS = { + "n1_under": dict(soc=lambda u, t: 15.0, load=lambda t: 5500.0), + "n1_crossing": dict(soc=crossing, load=lambda t: 5000.0), + "n1_above": dict(soc=lambda u, t: 60.0, load=lambda t: 5500.0), + "n1_under_banked": dict(soc=lambda u, t: 15.0, load=lambda t: 6000.0, + month_peak=4000.0), + "n1_charge_low": dict(soc=lambda u, t: 11.0, load=lambda t: 5000.0, + store="charge"), + "n1_hold": dict(soc=lambda u, t: 99.0, load=lambda t: 5500.0, + store="hold", cheap=False, + extra={"maintenance_hold_min": 600}), +} + + +def digests() -> dict: + out = {} + for k, v in SCENARIOS.items(): + v = dict(v) + st = store(v.pop("store", None)) + out[k] = s84.digest(s84.run(1, dur=DUR, store=st, **v)[0]) + return out + + +if __name__ == "__main__": + for k, v in digests().items(): + print(f"{k} {v}") -- 2.54.0 From d89c09331814e7da9363087766323862d41e3f98 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Thu, 1 Oct 2026 09:55:29 +0200 Subject: [PATCH 098/105] SAFETY-87: grade the surviving mutants (dropped battery, own-floor naming, pair permission, latched row) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr --- goodwe_controller/test_safety87.py | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/goodwe_controller/test_safety87.py b/goodwe_controller/test_safety87.py index e410ba2..0f5ff80 100644 --- a/goodwe_controller/test_safety87.py +++ b/goodwe_controller/test_safety87.py @@ -33,6 +33,7 @@ import json import logging import os import sys +import types HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) @@ -393,6 +394,33 @@ check("...and at N=1 the floor-limited claim is unchanged: 0 W, 'SoC floor'", peakguard.claim(_lim).lo == 0.0 and peakguard.claim(_lim).reason == "SoC floor") + + +def three(socs, cuts): + """`_peak_on_able()` on a stub roster of three (SIMULATED packs).""" + names = ("x", "y", "z") + invs = [types.SimpleNamespace(name=n, refused=0, rating_w=lambda: 2500.0) + for n in names] + stub = types.SimpleNamespace( + inverters=invs, o={"peak_soc_floor": 20}, + packs=[peakguard.Pack(n, so, c) for n, so, c in zip(names, socs, cuts)], + live_units=lambda: names) + return Controller._peak_on_able(stub, _lim, [MaintResult( + IDLE, False, None, False, [])] * 3) + + +# x 25 % (cut-out 10 -> floor 20), y 40 % (cut-out 30), z 15 % (held). x and +# y each clear their own floor, but 25 % is not above y's 30 %: the pair is +# graded min SoC against max floor (SAFETY-32), so nothing is asked. +_t3 = three((25.0, 40.0, 15.0), (10, 30, 10)) +_t3ok = three((35.0, 40.0, 15.0), (10, 30, 10)) +check("⭐ three batteries, z held: the two others are graded as a pair, the " + "EMPTIEST of them (25 %) against the HIGHEST of their floors (30 %), " + "so nothing is asked; at 35 % they are asked for the need", + _t3.held == ("z",) and _t3.floor_limited and _t3.floor_w == 0.0 + and _t3ok.held == ("z",) and not _t3ok.floor_limited + and _t3ok.floor_w == 2000.0) + # ============================================================================ # print("\n6. the allocator: a held battery gives last") @@ -474,6 +502,13 @@ check("...the row names A and says the others cannot hold the limit alone, " len(_row) == 1 and _row[0]["text"].startswith( "inverter-a battery at its peak reserve. The others cannot hold " "the 3 500 W peak limit alone.")) +_c65._peak_floor_limited = False +_blip = [r for r in _c65.checks() if r.get("id") == "peak_guard"] +_c65._peak_floor_limited = True +check("...and while the alarm is not latched (a one-cycle miss) the row is " + "the ordinary amber guard row, not the red reserve row", + len(_blip) == 1 and _blip[0]["warn"] and not _blip[0].get("runs") + and "peak reserve" not in _blip[0]["text"]) _c65.auto = False _stopped = _c65.status_payload() _c65.auto = True -- 2.54.0 From aa501ffec7d1c0ae1f9a02a82f120a3fb064fcd0 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Thu, 1 Oct 2026 10:50:01 +0200 Subject: [PATCH 099/105] SAFETY-87 review: maintenance pins beside a held battery A draining battery that may still give is raised from its drain rate towards its rating for the peak floor while another battery is held (peak > drain); before, the floor's rest landed on the held battery. In a HOLD, a held battery's own pin counts among the others: a held drain no longer over-places the site, and a held charge probe no longer parks it. Tests: test_safety87.py part 10 (drain beside a held battery, N=3 HOLD, unknown cut-out and unread level at N=3, a stopping row outranks the running peak alarm). DECISIONS entry updated, incl. the modes-on exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr --- .../SAFETY-87-guard-uses-able-batteries.md | 14 +- goodwe_controller/app/main.py | 65 +++++++++- goodwe_controller/test_safety87.py | 120 +++++++++++++++++- 3 files changed, 193 insertions(+), 6 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md b/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md index 4555605..5f366c5 100644 --- a/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md +++ b/goodwe_controller/DECISIONS/SAFETY-87-guard-uses-able-batteries.md @@ -45,7 +45,15 @@ graded on its own floor, and an unread SoC or unknown cut-out counts as held. The min/max pairing still decides permission, over the able batteries. The roster verdict `decide()` echoes (`soc`, `soc_floor`) is kept, so SAFETY-32's call-site and reduction checks still bite. What changed is only that one held -battery no longer stops the others. +battery no longer stops the others. One exception, with battery modes on: see +Open. + +**Maintenance pins beside a held battery** (review). A draining battery that +may still give is raised from its drain rate towards its rating for the peak +floor, after the others (`_drain_over_reserve()`; peak > drain), else the +floor's rest landed on the held battery. In a HOLD, a held battery counts its +own pin (a drain) among the others, and a held battery pinned to charge stops +the raise (never split both ways). **Before -> after** (test_safety87.py, rig of 2 x 2500 W, aim 3450 W): @@ -66,7 +74,9 @@ battery no longer stops the others. says "cannot keep … alone", not "will go over", so it stays true. - Battery modes on, A Off and B held: when B alone can place the floor, OPT-11 keeps A resting and B gives it. When B cannot, A gives first. Making Off give - before a held battery in the first case needs a third allocator tier. + before a held battery in the first case needs a third allocator tier. The + same at N=3: A Off, B held, C able, floor 4000 W gives C 2500, B 1500, A 0. + Until then, with modes on, a held battery can give for the peak. - The notification and row text live in `messages.py`, which has no NL layer yet (UX-19). The Home page text, which has NL, is unchanged. diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 45ceeda..2e257b0 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -2562,9 +2562,11 @@ class Controller: (P_PEAK), so the floor did not bind and the house imported what the drain left. Where the floor asks for more than the drain rate, it is refiled at P_MAINTENANCE and wins; nothing else changes. Safety claims - (P_SAFETY) still outrank it. At N>=2 the `drain` floor does this. + (P_SAFETY) still outrank it. At N>=2 the `drain` floor does this, and + `_drain_over_reserve()` when a battery is held at its reserve. """ if len(self.inverters) != 1: + self._drain_over_reserve(claims, maint_results) return res = maint_results[0] if res.phase != DRAIN or not res.owns_setpoint: @@ -2574,6 +2576,59 @@ class Controller: if c.source == peakguard.SOURCE and c.lo > rate: claims[i] = dataclasses.replace(c, priority=P_MAINTENANCE) + def _held_pin(self, claims, u): + """SAFETY-87: what held unit `u` places anyway (its own pin), or None + when that pin charges, so the site is never split both ways.""" + b = pre_resolve([c for c in claims if c.actuator == u]) + p = None if b.contradiction else allocator.pin_w(b) + return None if p is not None and p < 0.0 else max(p or 0.0, 0.0) + + def _drain_over_reserve(self, claims, maint_results) -> None: + """SAFETY-87, N>=2: while a battery is held at its peak reserve, a + draining battery that may still give is raised from its drain rate + towards its rating for the peak floor, after the others. Otherwise + the floor's rest lands on the held battery (its weight 0 only orders + the split; the drain pin binds). A site stop still decides alone.""" + reserve = self._peak_reserve() + floor = max((c.lo for c in claims if c.source == peakguard.SOURCE), + default=0.0) + if not reserve or not floor > 0.0 or any( + c.kind == SET and c.actuator == ACTUATOR_SITE + and c.priority > P_PEAK for c in claims): + return + live = set(self.live_units()) + drains, others = [], 0.0 + for inv, res in zip(self.inverters, maint_results): + u = self.actuator_of("maintenance", inv) + if u not in live: + continue + if inv.name in reserve: + p = self._held_pin(claims, u) + if p is None: + return + others += p + continue + b = pre_resolve([c for c in claims if c.actuator == u]) + if b.contradiction: + continue + p = allocator.pin_w(b) + if p is not None and p < 0.0: + return # a pack pinned to charge: never split both ways + if res.phase == DRAIN and b.pinned_by == "maintenance" \ + and p is not None and p > 0.0: + drains.append((u, p, allocator.hi_w(b))) + others += allocator.hi_w(b) if p is None else p + give = floor - others + for u, p, hi in drains: + if give <= 0.0: + break + up = max(p, min(hi, p + give)) + give -= up - p + for i, c in enumerate(claims): + if c.source == "maintenance" and c.kind == SET \ + and c.actuator == u: + claims[i] = dataclasses.replace(c, value=up) + def _peak_over_hold(self, claims, maint_results): """SAFETY-86: a peak floor outranks a maintenance HOLD (0 W). @@ -2603,7 +2658,13 @@ class Controller: others = 0.0 for inv in self.inverters: u = self.actuator_of("maintenance", inv) - if u in hold or u not in live or inv.name in reserve: + if u in hold or u not in live: + continue + if inv.name in reserve: # only its own pin, never both ways + p = self._held_pin(claims, u) + if p is None: + return + others += p continue b = pre_resolve([c for c in claims if c.actuator == u]) if b.contradiction: diff --git a/goodwe_controller/test_safety87.py b/goodwe_controller/test_safety87.py index 0f5ff80..2d5bede 100644 --- a/goodwe_controller/test_safety87.py +++ b/goodwe_controller/test_safety87.py @@ -44,8 +44,8 @@ import opt11_identity as rig # noqa: E402 import safety84_identity as s84 # noqa: E402 import safety87_identity as s87 # noqa: E402 from app import messages, packmode, peakguard # noqa: E402 -from app.arbiter import (Claim, P_MODE, P_PEAK, P_SAFETY, # noqa: E402 - UnitBounds, resolve) +from app.arbiter import (Claim, P_MAINTENANCE, P_MODE, P_PEAK, # noqa: E402 + P_SAFETY, UnitBounds, resolve) from app.main import Controller # noqa: E402 from app.maintenance import DRAIN, HOLD, IDLE, MaintResult # noqa: E402 from app.store import unit_key # noqa: E402 @@ -540,6 +540,122 @@ check("⭐ every N=1 digest (claims, commands, the guard's decision and the " "charge and a HOLD, and under a banked peak", _now == PINNED) +# ============================================================================ # +print("\n10. review: maintenance pins beside a held battery, N=3, the page") + + +def _drain_store(): + s = rig._Store() + s.data[unit_key(B, "phase")] = DRAIN + s.data[unit_key(B, "phase_started")] = rig.BASE.isoformat() + s.data[unit_key(A, "last_completed")] = rig.BASE.isoformat() + return s + + +def _drain_run(): + return run(8000.0, IDLE, {"a": 15.0, "b": 60.0}, store=_drain_store(), + dur=900.0) + + +DR = _drain_run() +_real_dor = Controller._drain_over_reserve +Controller._drain_over_reserve = lambda self, claims, results: None +try: + DR_OLD = _drain_run() +finally: + Controller._drain_over_reserve = _real_dor + + +def _a_for_peak(rows): + """A's command on the cycles where the site target is the peak floor + and B alone (2500 W) could place it.""" + return [cmd(r)["a"] for r in rows + if r[-1][1] and r[-1][1][1] and r[1] <= 2500.0 + and abs(r[1] - r[-1][1][1]) < 1.0] + + +print(f" B draining, A held: A for the peak {_a_for_peak(DR[0])[:4]}, " + f"without the raise {_a_for_peak(DR_OLD[0])[:4]}") +check("⭐ B draining (2000 W pin) while A is held: B is raised to its rating " + "for the peak floor, so A gives nothing for it (peak > drain)", + DR[1].maints[1].phase == DRAIN and _a_for_peak(DR[0]) + and all(a <= 0.0 for a in _a_for_peak(DR[0]))) +check("non-vacuous: without the raise A gave the floor's rest above B's pin", + any(a > 0.0 for a in _a_for_peak(DR_OLD[0]))) + + +def _stub(names, reserve, live=None): + """A Controller stand-in for the pin rules, on SIMULATED units.""" + s = types.SimpleNamespace( + inverters=[types.SimpleNamespace(name=n) for n in names], + actuator_of=lambda src, inv=None: inv.name, + live_units=lambda: tuple(live or names), + _peak_reserve=lambda: frozenset(reserve)) + s._held_pin = lambda cl, u: Controller._held_pin(s, cl, u) + return s + + +def _hold(floor, names, reserve, extra=(), results=None): + """`_peak_over_hold()`: x HOLDs; returns (x's pin, resolved shares).""" + s = _stub(names, reserve) + cl = [Claim.limit("supervised", P_SAFETY, -2500.0, 2500.0, actuator=n) + for n in names] + cl += [Claim.set("maintenance", P_MAINTENANCE, 0.0, HOLD, actuator="x"), + Claim.limit("peak", P_PEAK, lo=floor, reason="quarter peak"), + *extra] + res = results or ([MaintResult(HOLD, True, 0.0, False, [])] + + [MaintResult(IDLE, False, None, False, [])] + * (len(names) - 1)) + hi = Controller._peak_over_hold(s, cl, res) + if hi is not None: + cl.append(Claim.limit("hold", P_MAINTENANCE, hi=hi)) + r = resolve(cl + [Claim.set("loop", 10, floor)], units=tuple(names), + live=set(names), reserve=reserve) + pin = next((c.value for c in cl + if c.source == "maintenance" and c.actuator == "x"), None) + return pin, {u: round(v) for u, v in r.shares.items()} + + +_h3 = _hold(3000.0, ("x", "y", "z"), {"z"}) +_h3b = _hold(2000.0, ("x", "y", "z"), {"z"}) +print(f" N=3 HOLD x, y able, z held: floor 3000 {_h3}, 2000 {_h3b}") +check("⭐ HOLD at N=3 with one held: the able battery gives first, the " + "holding one the rest (3000 -> y 2500, x 500), the held one nothing", + _h3 == (500.0, {"x": 500, "y": 2500, "z": 0}) + and _h3b == (0.0, {"x": 0, "y": 2000, "z": 0})) +_hd = _hold(2000.0, ("x", "z"), {"z"}, + (Claim.set("maintenance", P_MAINTENANCE, 1500.0, DRAIN, + actuator="z"),), + [MaintResult(HOLD, True, 0.0, False, []), + MaintResult(DRAIN, True, 1500.0, False, [])]) +_hp = _hold(2000.0, ("x", "z"), {"z"}, + (Claim.set("refused", P_SAFETY, -50.0, "probe", actuator="z"),)) +print(f" held z draining 1500: {_hd}; held z charge probe: {_hp}") +check("⭐ a held battery's own pin counts: draining 1500 W, the hold gives " + "only the 500 W rest (no over-placement); a charge probe leaves the " + "hold at 0 W (never split both ways, no park)", + _hd == (500.0, {"x": 500, "z": 1500}) and _hp[0] == 0.0) + +_unk = three((60.0, 60.0, 60.0), (10, None, 10)) +_unr = three((60.0, None, 60.0), (10, 10, 10)) +check("⭐ N=3: an unknown cut-out or an unread level holds that battery " + "only; the two others are asked for the need", + _unk.held == ("y",) and not _unk.floor_limited + and _unk.floor_w == 2000.0 and _unr.held == ("y",) + and not _unr.floor_limited and _unr.floor_w == 2000.0) + +_stop_row = {"ok": False, "warn": False, "id": "meter", "text": "Meter down."} +_peak_rows = [r for r in _c65.checks() if r.get("id") == "peak_guard"] +_c65.checks = lambda: _peak_rows[:1] + [_stop_row] +_both = _c65.status_payload() +del _c65.checks +check("⭐ a row that stops control outranks the running peak alarm: the " + "banner says 'Not ready' for it and the Home page shows the hold", + len(_peak_rows) == 1 and _peak_rows[0].get("runs") + and _both["banner"].startswith(messages.NOT_READY) + and "Meter down" in _both["banner"] + and "until the alarm clears" in json.dumps(_both, ensure_ascii=False)) + print() if fails: print(f"{len(fails)} FAILED: " + ", ".join(fails)) -- 2.54.0 From a4a04d203c516e9d631bd48ce1d7eb085d264365 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Thu, 1 Oct 2026 11:07:43 +0200 Subject: [PATCH 100/105] SAFETY-87 review: grade the three surviving review mutants A battery refusing only to charge stays able; the reserve alarm is graded on the real limit, not the aim; 'control still runs' is set on the two peak rows only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr --- goodwe_controller/test_safety87.py | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/goodwe_controller/test_safety87.py b/goodwe_controller/test_safety87.py index 2d5bede..b354775 100644 --- a/goodwe_controller/test_safety87.py +++ b/goodwe_controller/test_safety87.py @@ -656,6 +656,52 @@ check("⭐ a row that stops control outranks the running peak alarm: the " and "Meter down" in _both["banner"] and "until the alarm clears" in json.dumps(_both, ensure_ascii=False)) +for _inv, _s, _r in zip(_ctl2.inverters, (15.0, 60.0), (0, -1)): + _inv.soc, _inv.refused = _s, _r # B refuses only to CHARGE +_chg = _ctl2._peak_on_able(_lim_all, [MaintResult(IDLE, False, None, False, + [])] * 2) +_ctl2.inverters[1].refused = 0 +check("⭐ a battery that refuses only to charge can still give: it stays " + "able and carries the floor (2000 W of 2500 W)", + not _chg.floor_limited and _chg.floor_w == 2000.0 + and _chg.able_w == 2500.0 and _chg.held == (A,)) + + +def _short_for(held_w, secs=30.0): + """`_reserve_short()` over `secs` of a steady quarter: the meter at + `held_w` with the able batteries already at their full 2500 W.""" + s = types.SimpleNamespace(_reserve_batt_prev=None, + _reserve_high_since=None, + _peak_floor_limited=False, site_batt_w=2500.0) + g = dataclasses.replace(_lim, floor_w=2500.0, able_w=2500.0) + out = [] + for k in range(int(secs / 5.0) + 1): + s._peak_proj = types.SimpleNamespace( + block_start=rig.BASE, elapsed_s=450.0 + 5.0 * k, + projected_w=held_w, held_w=held_w) + out.append(Controller._reserve_short(s, g)) + return out + + +_aim_miss, _limit_miss = _short_for(3480.0), _short_for(3600.0) +check("⭐ the reserve alarm is graded on the real limit, not the aim: a " + "quarter ending at 3480 W (over the 3450 W aim, under 3500 W) never " + "alarms; one ending at 3600 W alarms once it holds ALARM_HOLD_S", + not any(_aim_miss) and not any(_limit_miss[:2]) + and all(_limit_miss[2:])) + +_runs_src = {} +for _f in ("main.py", "homeview.py"): + with open(os.path.join(HERE, "app", _f), encoding="utf-8") as _fh: + _src = _fh.read() + for _part in _src.split('out.append({')[1:]: + if '"runs": True' in _part.split("})", 1)[0]: + _runs_src.setdefault(_f, []).append( + _part.split('"id": "', 1)[-1].split('"', 1)[0]) +check("⭐ 'control still runs' is set on the two peak rows only (saturated " + "and reserve); no row that stops control carries it", + _runs_src == {"main.py": ["peak_guard", "peak_guard"]}) + print() if fails: print(f"{len(fails)} FAILED: " + ", ".join(fails)) -- 2.54.0 From b4d25dd485950ef2f1a9586766315fee1e827c71 Mon Sep 17 00:00:00 2001 From: Claude <noreply@anthropic.com> Date: Thu, 1 Oct 2026 11:08:42 +0200 Subject: [PATCH 101/105] SAFETY-87 review: DOCS, the drain rate may rise for the peak at N>=2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr --- goodwe_controller/DOCS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index 8fac634..a03194f 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1639,7 +1639,7 @@ help - see "Why the tuning is what it is". | `maintenance_enabled` | false | Enable the monthly cycle | | `maintenance_interval_days` | 28 | Minimum gap between cycles | | `maintenance_start_hour` | 10 | Hour of day a due cycle begins | -| `maintenance_discharge_w` | 2000 | Drain rate (exports the surplus). The peak guard may ask for more (SAFETY-83). Above `max_w` it is **clamped** to `max_w` — the drain phase SETs the setpoint and the arbiter bounds it, saying so on the status page (`limited by supervised(max_w)`). Warned about, not refused: the cycle still completes, just slower | +| `maintenance_discharge_w` | 2000 | Drain rate (exports the surplus). The peak guard may ask for more (SAFETY-83; at N≥2 while another battery is at its peak reserve, SAFETY-87). Above `max_w` it is **clamped** to `max_w` — the drain phase SETs the setpoint and the arbiter bounds it, saying so on the status page (`limited by supervised(max_w)`). Warned about, not refused: the cycle still completes, just slower | | `maintenance_charge_w` | 2000 | Charge ceiling, capped again by peak headroom. Must stay **at or below `max_w`** or the cheap-window shaping (`hi = -maintenance_charge_w`) contradicts the supervised limit (`lo = -max_w`), the arbiter resolves it to **0 W**, and maintenance silently never charges in a cheap window — **the add-on refuses to start** | | `maintenance_soc_floor` | 11 | Drain target — stay just above the inverter's own floor. ⚠️ **This is not `peak_soc_floor`.** It is the depth the monthly recalibration deliberately goes to, once, on purpose; `peak_soc_floor` is the depth a money-saving discharge may never reach on any day. The right values differ (11 vs 20 as shipped), which is why they are two keys | | `maintenance_soc_target` | 99 | Charge target | -- 2.54.0 From 4b81387908751a970dce4023acfc62177010fd66 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <glenn@dsgpartners.be> Date: Thu, 1 Oct 2026 19:02:51 +0200 Subject: [PATCH 102/105] SAFETY-85: no false 'not keeping up' while maintenance or the peak guard sets the battery The loop's integrator bound counts only on a cycle the loop decided. A battery another owner set (maintenance, the peak guard, a safety limit) alarms only when it gives more than saturation_w less than told for saturation_cycles cycles. At N>=2 the loop is bounded while maintenance holds a battery, so it does not wind and control comes back one slew step a cycle. The status row counts episodes, not cycles. Digests re-pinned where behaviour changed on purpose; DECISIONS/SAFETY-85-no-false-not-keeping-up.md has the list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DBUfvndgHwaV339Fvd2gr --- .../SAFETY-85-no-false-not-keeping-up.md | 80 +++++ goodwe_controller/DOCS.md | 14 +- goodwe_controller/app/clamp.py | 26 ++ goodwe_controller/app/control.py | 8 +- goodwe_controller/app/main.py | 60 +++- goodwe_controller/test_clamp.py | 12 +- goodwe_controller/test_modes.py | 26 +- goodwe_controller/test_peak_margin.py | 4 +- goodwe_controller/test_safety78.py | 7 +- goodwe_controller/test_safety84.py | 19 +- goodwe_controller/test_safety85.py | 303 ++++++++++++++++++ goodwe_controller/test_safety86.py | 30 +- 12 files changed, 554 insertions(+), 35 deletions(-) create mode 100644 goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md create mode 100644 goodwe_controller/test_safety85.py diff --git a/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md b/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md new file mode 100644 index 0000000..09cf889 --- /dev/null +++ b/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md @@ -0,0 +1,80 @@ +# SAFETY-85 - no false "not keeping up" while another owner sets the battery + +**Status: implemented 2026-10-01, for review.** Tests: `test_safety85.py`. + +**The defect.** "Battery is not keeping up" (SAFETY-40, `goodwe_integrator_bound`) +fired about every 2.5 min during maintenance (drain, charge, HOLD) and under the +peak guard, while the battery gave exactly what it was told. Each warning +re-created the HA notification. Rig counts: 24 in an hour (SAFETY-83 F1), 43 in +7 episodes (SAFETY-86), 35 in 16 (SAFETY-87), 12 in 6 (SAFETY-84). The page +counter counted cycles (861), not episodes. + +**Cause, measured on the real Controller.** +- N=1: when a higher claim decides, `cycle()` re-seeds the integrator from the + target each cycle, then `compute()` adds `gain * error` for a grid error the + loop does not own. Target + kick crosses the rail and sets `i_clamped`. The + carried integrator is not wound (SAFETY-48 caps the lead at one slew step), + so control comes back one slew step at a time. +- N>=2: a maintenance pin is a unit claim. The loop stays the site winner and + winds to its rail for watts the pinned battery may not give. When the pin + lifts, the site jumps: 2500 W in one cycle when a HOLD ends under a 4500 W + house, 1390 W when a charge pin lifts (`s84 n2_charge_dear`, t=1800 s). + +**Decision.** Three rules; the alarm, its text and its id are unchanged. +1. **The loop's clamp counts only on a cycle the loop decided.** The winner is + the loop. Its number is on the wire, or only a rating (`device`, + `supervised`) cut it. No bound held it, and nothing was unmet. + (`Controller._loop_alarm_input`.) +2. **A battery another owner set alarms when it gives less than it was told.** + This covers every battery on a cycle the loop did not decide, and a battery + with its own pin otherwise. The test is more than `saturation_w` short in + the told direction, for `saturation_cycles` cycles in a row, against what + stands on the wire (`clamp.delivery_short`). It covers a real shortfall + during maintenance. Before, that shortfall was silent unless the kick + happened to reach the rail (house 1000 W, drain 2000 W, battery gives + nothing: 0 warnings before, 4 in 10 min now). +3. **At N>=2, while maintenance holds a battery, the loop is bounded** by + OPT-11's `loop_bound()` (what the batteries may place). It does not wind, + and control comes back one slew step a cycle. Why maintenance only: that is + where the jump was measured and where the owner order puts maintenance + above the loop. Other N>=2 limits (pack cut-out, SAFETY-73 refusal) keep + the old law. Rule 1 still silences them (the target is unmet), so they no + longer warn either. + +Fixing the windup was chosen over only ignoring the wound part, because at +N>=2 the wound integrator moves real watts at hand-back. At N=1 there was +nothing to fix: re-seeding already prevents windup. + +**What SAFETY-03/40 protect is kept.** With the loop in charge, the integrator +bound still warns (a runaway, a house above the rating), and a saturated +inverter under the loop's own command still does not alarm (SAFETY-03 AC 2): +rule 2 grades only batteries another owner set. + +**The counter.** `ClampWatchdog.bound_episodes` counts episodes that had a +bound engagement. The status row shows it ("N times since start"). +`bound` (cycles) stays for the log and the tests. + +**Re-pinned digests.** Every change is intended; nothing at N=1 moves a watt. + +| digest | what changed | +|---|---| +| s78 `n1_drain_owner` | the false clamp rows are gone from the log; commands identical | +| s78 `n2_drain`, s84 `n2_charge`, `n2_charge_banked`, s79 `n2_maint` (test_peak_margin) | loop reason (`mode-bound`), integrator and loop claim while bounded; commands identical | +| opt11 `n2_maint` (test_modes) | A drops out at t=1655 s: B follows the house at once, 8 cycles differ (max 920 W) | +| s84 `n2_charge_dear` | A's pin lifts at t=1800 s: 400 W a cycle, not a 1390 W jump; the surplus step after it; 98 cycles | + +test_safety86's "without the ceiling the log floods" now needs the ceiling +and the bound both removed: either one alone keeps the loop inside what the +batteries can give. The `alarmed()` helpers in test_safety84/86 also read +SAFETY-81's quarter stamp, because ALLOCATOR rows can push its row out of +the 40-row log. + +**Not changed, open for the owner.** +- With the loop in charge and the house above the batteries' total rating, + it still warns (SAFETY-40). On the rig's 2 x 2000 W N=2, most of SAFETY-84's + count came from houses of 4500 and 6500 W. +- A battery that tapers near full during a charge, more than `saturation_w` + under its command for 15 s, now warns (rule 2). The text already says + "check it is not empty or full". +- TEL-10's `loop_reason` reads `mode-bound` while the maintenance bound holds + the loop, with modes off. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index a03194f..d246895 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -1953,6 +1953,13 @@ over the rating is logged as a software fault, at `ERROR`, and it has its own notification budget. Why: [`DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md`](DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md). +The integrator bound counts only on a cycle the loop decided. While +maintenance, the peak guard or a safety limit sets a battery, the same alarm +fires only when that battery gives more than `saturation_w` less than it was +told, for `saturation_cycles` cycles. At two or more inverters the loop does not +wind while maintenance holds a battery. +Why: [`DECISIONS/SAFETY-85-no-false-not-keeping-up.md`](DECISIONS/SAFETY-85-no-false-not-keeping-up.md). + ### The frozen-meter alarm A meter that has died is easy — it stops answering, the sample age climbs past @@ -3122,7 +3129,9 @@ The battery gives less power than the add-on asks for. This is normal for a short time, for example just after a large load switches on or the sun comes out. It is not a fault, and control keeps running. If it keeps coming back, check that the battery is switched on, and that it is not empty (when it should -give power) or full (when it should charge). +give power) or full (when it should charge). During the monthly maintenance or +while the peak limit is guarded, it only shows when the battery gives less than +it was told. The status page counts how many times it happened. ### Power request too high @@ -3227,7 +3236,8 @@ section without a link. The documentation tab adds no heading anchors, so the link cannot jump to the section. **Battery is not keeping up.** The grid-following loop's integrator reached its -anti-windup bound (`integrator_max_w`, SAFETY-40). No command went over the +anti-windup bound (`integrator_max_w`, SAFETY-40), or a battery that another +owner set gave less than it was told (SAFETY-85). No command went over the rating. The log line is a WARNING with reason code `OUTPUT_CLAMP`. See *The winding-loop alarm*. diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index 31aeb80..e690faf 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -260,6 +260,24 @@ def loop_clamp_note(d) -> str: return "" +def shortfall_note(named) -> str: + """SAFETY-85: the alarm text while another owner sets the batteries. + `named` is `[(inverter name or None, asked W, given W)]`, one per battery + that gave less than asked.""" + return f"{REASON_CODE}: " + ", ".join( + f"{name or 'the battery'} gives {given:+.0f} W of the {asked:+.0f} W " + f"asked" for name, asked, given in named) + + +def delivery_short(asked_w, given_w, margin_w) -> bool: + """SAFETY-85: did a battery give more than `margin_w` less than asked, in + the asked direction? Giving more than asked, or 0 W asked, is not short.""" + asked, given = float(asked_w), float(given_w) + if asked == 0.0: + return False + return (asked - given) * (1.0 if asked > 0 else -1.0) > abs(float(margin_w)) + + def write_clamp_note(named) -> str: """The write-side alarm text: `named` is `[(inverter name or None, ClampResult)]` for every inverter whose write was cut back this cycle. @@ -382,6 +400,10 @@ class ClampWatchdog: self.over_rating = 0 # bug=True: "Power request too high" self.bound = 0 # bug=False: "Battery is not keeping up" self.episodes = 0 # rising edges + # SAFETY-85: episodes with a bug=False engagement. The status row + # counts these; counting cycles read 861 on one rig run. + self.bound_episodes = 0 + self._bound_counted = False self.since: datetime | None = None self.last_alarm: datetime | None = None self.reason = "" @@ -436,6 +458,10 @@ class ClampWatchdog: self.spoken = False self.bug = False self.bug_spoken = False + self._bound_counted = False + if not bug and not self._bound_counted: + self._bound_counted = True + self.bound_episodes += 1 if bug or not self.bug: self.reason = reason self.facts = tuple(facts) diff --git a/goodwe_controller/app/control.py b/goodwe_controller/app/control.py index 8e01509..1f2713a 100644 --- a/goodwe_controller/app/control.py +++ b/goodwe_controller/app/control.py @@ -382,6 +382,9 @@ class Decision: # SAFETY-52. The refused direction to carry back in (+1 discharge, -1 # charge, 0 none), or None when the caller does not carry it. refused: int | None = None + # SAFETY-85. The `bound` held the integrator or the command this cycle, + # so the batteries' limits, not the loop, decided it. + held: bool = False def slew_limit_w(tuning: Tuning) -> float: @@ -614,11 +617,13 @@ def compute( # OPT-11: the integrator does not wind past what the modes let the # batteries place. Only a side tighter than the rail is left in `bound` # (above), so this never takes SAFETY-03's `i_clamped` away from the rail. + held_by_bound = False if bound is not None: held = max(float(bound[0]), min(float(bound[1]), i_w)) if held != i_w: i_w = held reason = MODE_BOUND + held_by_bound = True # ⚠️ Applied EVERY cycle, frozen or not: the freeze is conditional, this # bound is not. It is what makes the worst-case unwind time finite and @@ -839,6 +844,7 @@ def compute( if inside != target: target = inside reason = MODE_BOUND + held_by_bound = True # SAFETY-48's lead cap above may pull the integrator back toward the # slewed command; what is CARRIED stays inside the bound too. i_w = max(float(bound[0]), min(float(bound[1]), i_w)) @@ -860,7 +866,7 @@ def compute( return Decision(float(target), sat_count, frozen, reason, float(i_w), i_clamped, clamped, float(i_bound_w), float(want), - float(clamped_w), refused) + float(clamped_w), refused, held_by_bound) def maintenance_charge_floor( diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index 2e257b0..ec4617f 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -59,7 +59,8 @@ from .circulation import ( ) from .clamp import ( REASON_CODE as CLAMP_REASON, ClampWatchdog, - clamp_to_rating, is_commandable, loop_clamp_note, write_clamp_note, + clamp_to_rating, delivery_short, is_commandable, loop_clamp_note, + shortfall_note, write_clamp_note, ) from . import freshness from . import homeview @@ -1179,6 +1180,10 @@ class Controller: self.loop_clamped: tuple[bool, str, bool] = (False, "", False) # UX-08: the numbers of a loop-side over-rating, for the notification. self.loop_clamp_facts: tuple = () + # SAFETY-85: this cycle's loop Decision, and how many cycles in a row + # a battery set by another owner gave less than asked. + self._loop_decision = None + self._short_run = 0 self.stopping = False # SAFETY-61. time.monotonic() at the end of the last run_control() pass. self.loop_pass_mono = None @@ -4547,9 +4552,13 @@ class Controller: refused=self.batt_refused if len(self.inverters) == 1 else self._site_refused(), probe=probe, - # OPT-11: None unless battery modes are on, which is the law - # exactly as it was. - bound=self.loop_bound(claims) if self.modes_on else None, + # OPT-11: None unless battery modes are on. SAFETY-85: or while + # maintenance holds a battery at N>=2, so the loop does not + # wind past what the others can give and jump when it ends. + bound=(self.loop_bound(claims) if self.modes_on or ( + len(self.inverters) > 1 + and any(r.phase != IDLE for r in maint_results)) + else None), ) if decision.frozen and self.sat_count < self.tuning.saturation_cycles: self.log_event(f"saturation freeze ({self.target:.0f} W vs " @@ -4558,6 +4567,7 @@ class Controller: self.sat_count = decision.sat_count self.i_w = decision.i_w self.loop_w = decision.target_w + self._loop_decision = decision if len(self.inverters) == 1: self._refusal_update(decision, loop_prev, site_batt, probe) # --- TEL-10 ------------------------------------------------------ @@ -4637,6 +4647,7 @@ class Controller: # de-assert when control is stopped. self.loop_clamped = (False, "", False) self.loop_clamp_facts = () + self._loop_decision = None # SAFETY-28. A new resolution is a new tick, and the previous record is # stale from this line onwards. Incremented BEFORE resolve() so that the @@ -4856,6 +4867,8 @@ class Controller: # That is the dropped-link case: the inverter holds its last command # FOREVER, so "not in the split" must mean zero on the wire, not # silence. The write is the same clamped, budgeted path as every other. + # SAFETY-85, before the writes: the wire still holds last cycle's. + self._loop_alarm_input(resolution) writes = [] for inv in self.inverters: inv.target = float(resolution.shares.get(inv.name, 0.0)) @@ -5069,6 +5082,38 @@ class Controller: for inv in self.inverters: inv.target = shadow.WIRE_W + def _loop_alarm_input(self, resolution) -> None: + """SAFETY-85. The loop's clamp counts only on a cycle the loop decided + (a rating may cut it). A battery another owner set counts when it gave + less than it was told for `saturation_cycles` cycles in a row. + DECISIONS/SAFETY-85-no-false-not-keeping-up.md.""" + d = self._loop_decision + if d is None: + self._short_run = 0 + return + unmet = self.allocation.unmet_w if self.allocation is not None else 0 + cut = (resolution.bound_by or "").split("(")[0] + owns = (resolution.winner == "loop" and not d.held and not unmet + and (resolution.target_w == d.target_w + or cut in ("device", "supervised"))) + # Graded against what stands on the wire (0 W in shadow mode). + others = [inv for inv in self.inverters if not owns + or allocator.pin_w(resolution.unit_bounds.get(inv.name)) + is not None] + short = [(inv, inv.standing_w(), inv.batt) for inv in others + if inv.batt is not None + and delivery_short(inv.standing_w(), inv.batt, + self.tuning.saturation_w)] + self._short_run = self._short_run + 1 if short else 0 + if owns and self.loop_clamped[0]: + return + engaged = self._short_run >= self.tuning.saturation_cycles + named = len(self.inverters) > 1 + self.loop_clamped = (engaged, shortfall_note( + [(inv.name if named else None, a, g) for inv, a, g in short]) + if engaged else "", False) + self.loop_clamp_facts = () + async def check_output_clamp(self) -> None: """SAFETY-03. Alarm whenever a clamp actually engaged this cycle. @@ -6291,7 +6336,8 @@ class Controller: elif _cw.active: # SAFETY-40: the integrator bound alone is amber, not red. out.append({"ok": False, "warn": True, "id": "not_keeping_up", - "text": messages.row_not_keeping_up(_cw.bound)}) + "text": messages.row_not_keeping_up( + _cw.bound_episodes)}) # No over-rating in THIS episode (`bug` would be set), so any count # is from an earlier one: keep that software-fault evidence shown. if _cw.over_rating: @@ -6303,10 +6349,10 @@ class Controller: out.append({"ok": False, "warn": True, "id": "power_too_high", "text": messages.row_before( messages.T_OUTPUT_CLAMP, _cw.over_rating)}) - if _cw.bound: + if _cw.bound_episodes: out.append({"ok": False, "warn": True, "id": "not_keeping_up", "text": messages.row_before( - messages.T_LOOP_BOUND, _cw.bound)}) + messages.T_LOOP_BOUND, _cw.bound_episodes)}) for inv in self.inverters: if inv.last_write_ok is False: diff --git a/goodwe_controller/test_clamp.py b/goodwe_controller/test_clamp.py index 98e9a52..b3cc1b2 100644 --- a/goodwe_controller/test_clamp.py +++ b/goodwe_controller/test_clamp.py @@ -553,12 +553,14 @@ check("the status page flags it WHILE it is engaged - amber, since it is the " any(not c["ok"] and c["warn"] and c.get("id") == "not_keeping_up" and c["text"].startswith(messages.T_LOOP_BOUND) for c in ctl_r.red_snapshot)) -check("...and once clear, a warn row still says how many times it engaged, " - "under the integrator bound's own title", +# SAFETY-85: the row counts episodes, not cycles. +check("...and once clear, a warn row still says how many times it happened " + "(episodes, not cycles), under the integrator bound's own title", any(c["warn"] and c.get("id") == "not_keeping_up" - and c["text"].startswith(messages.T_LOOP_BOUND) - and messages.times(ctl_r.clamp_wd.bound) in c["text"] - and "fine now" in c["text"] for c in ctl_r.checks())) + and c["text"] == messages.row_before( + messages.T_LOOP_BOUND, ctl_r.clamp_wd.bound_episodes) + for c in ctl_r.checks()) + and 0 < ctl_r.clamp_wd.bound_episodes < ctl_r.clamp_wd.bound) # UX-07 item 1: the after-episode row used to say "output clamp ... engaged N # time(s)" for integrator-bound cycles. Each count now sits under its own name. check("UX-07 item 1: bound-only engagements are counted as the bound, and no " diff --git a/goodwe_controller/test_modes.py b/goodwe_controller/test_modes.py index a4e4fc8..6e38ed3 100644 --- a/goodwe_controller/test_modes.py +++ b/goodwe_controller/test_modes.py @@ -108,15 +108,27 @@ A5DDDAD = { _claims, _undo_c = spy_claims() _bounds, _undo_b = spy_bounds() try: - _now = rig.digests() + _now = {k: rig.digest(rig.run(**v)[0]) + for k, v in rig.SCENARIOS.items() if k != "n2_maint"} + _now["resolve"] = rig.digest(rig.resolve_rows()) +finally: + _undo_b() +# SAFETY-85: n2_maint (maintenance at N=2) is the one run with a bound. +_bounds_m, _undo_b = spy_bounds() +try: + _now["n2_maint"] = rig.digest(rig.run(**rig.SCENARIOS["n2_maint"])[0]) finally: _undo_c() _undo_b() # SAFETY-78 changes n2_maint ON PURPOSE: on a5dddad and 5a4cdc2 its N=2 drain # was refused on 392 of 540 cycles (site at 0 W); now none is. Printed on the # SAFETY-78 tree the same way. Every other digest is unchanged. +# SAFETY-85 changes it again ON PURPOSE: while A's drain pin stands the loop +# is bounded by what the batteries can place, so when A drops out at t=1655 B +# follows the house down at once instead of unwinding 920 W too high. Was +# cd4d9cb5b7e29ff4ab4fe65dab5106683d8a599f09323fbdee4018ad9b28fcd1. SAFETY78_N2_MAINT = \ - "cd4d9cb5b7e29ff4ab4fe65dab5106683d8a599f09323fbdee4018ad9b28fcd1" + "1afcd46b1b987868b110d2b0f4a7555848c9aa4728a836d4a2ce2a2107268497" for k in A5DDDAD: print(f" {k:7} {'same' if _now[k] == A5DDDAD[k] else 'DIFFERS'} " f"{_now[k][:16]}") @@ -129,12 +141,14 @@ check("⭐ at N=1 and N=2, with the option absent and with it false, every " {k: v for k, v in _now.items() if k != "n2_maint"} == {k: v for k, v in A5DDDAD.items() if k != "n2_maint"}) check("...and n2_maint is the SAFETY-78 digest: the N=2 drain that a5dddad " - "refused on 392 of 540 cycles now runs (test_safety78.py)", + "refused on 392 of 540 cycles now runs (test_safety78.py), bounded by " + "SAFETY-85", _now["n2_maint"] == SAFETY78_N2_MAINT != A5DDDAD["n2_maint"]) -check("...and no cycle in those runs filed a `mode` claim or handed " - "`compute()` a bound", +check("...and no cycle in those runs filed a `mode` claim, and only " + "n2_maint's (SAFETY-85: maintenance at N=2) handed `compute()` a bound", _claims and not any(c.source == "mode" for cl in _claims for c in cl) - and _bounds and set(_bounds) == {None}) + and _bounds and set(_bounds) == {None} + and any(b is not None for b in _bounds_m)) # ============================================================================ # diff --git a/goodwe_controller/test_peak_margin.py b/goodwe_controller/test_peak_margin.py index f8da15c..19f09d9 100644 --- a/goodwe_controller/test_peak_margin.py +++ b/goodwe_controller/test_peak_margin.py @@ -67,8 +67,10 @@ for k in ED739D4: # SAFETY-84 changes n2_maint ON PURPOSE: on 9d5b7d1 its N=2 cheap-window # charge was refused on 214 of 540 cycles (site at 0 W); now none is. # Printed on the SAFETY-84 tree the same way (margin 0). +# SAFETY-85: the loop is bounded while A charges (reasons change, commands +# do not). Was 95722b262f1bcf504493d7b5babc3895799ac56cc15f5d2ccdbe7c9f04adfcbb. SAFETY84_N2_MAINT = \ - "95722b262f1bcf504493d7b5babc3895799ac56cc15f5d2ccdbe7c9f04adfcbb" + "ef97ae2e13668b3e0b2d22f3f5f37835ea46cd306c2cc475c97e284f9dcc6545" check("⭐ at N=1 and N=2, with and without battery modes and with a " "maintenance charge, margin 0 is " "byte-identical to ed739d4 (n2_maint apart, below)", diff --git a/goodwe_controller/test_safety78.py b/goodwe_controller/test_safety78.py index 2757003..9b3907f 100644 --- a/goodwe_controller/test_safety78.py +++ b/goodwe_controller/test_safety78.py @@ -332,15 +332,18 @@ print("\n5. the N=1 and N=2 digests") # newest action-log line hashed. N=2: the same on release/1.0 35cdffe. N=1: # re-pinned by SAFETY-83, whose `--diff` against 35cdffe changes only cycles # where the peak guard asked for more than the drain (test_safety83.py). +# SAFETY-85 re-pinned two: n1_drain_owner loses its false 'not keeping up' +# rows (commands unchanged); n2_drain's loop is bounded while A drains +# (reasons and the loop claim change, commands unchanged). PINNED = { "n1_drain": "b0f9ef44149163bc0acece537fe047871c00f0d9ea213e7a7fc8efc4ad3aa500", "n1_drain_modes": "95ab82426e23bce308db3edebe18b1ab37d956952e9f521adce37150ce87ee8a", "n1_drain_owner": - "10f7f42a6a952e899d739eb10c674874215c440f41ead7a9f2408bc9b4cb9ea4", + "607c2583c7ae4bdafb90d780b3414c62d76c430ca67798cd117d1a46f3bb40ae", "n2_drain": - "055d83de0552d3a014dc73d87fdd697dde8b5933b8032f9b3a464ff0d08795fb", + "5806a6f457b7baf8dfb44daddced502f1939c114e15b84029dbb2659be8c8b0f", "n2_drain_owner": "05750347f1829c249f99154613f068f442a59ef59f409093907f6d0add78dd4c", } diff --git a/goodwe_controller/test_safety84.py b/goodwe_controller/test_safety84.py index fcc0d4e..9fc4502 100644 --- a/goodwe_controller/test_safety84.py +++ b/goodwe_controller/test_safety84.py @@ -83,8 +83,11 @@ def banked(c): def alarmed(c): - """Did SAFETY-81's 'Load too high' alarm fire on this run?""" - return any("PEAK_GUARD_SATURATED" in e for e in c.events) + """Did SAFETY-81's 'Load too high' alarm fire on this run? Its quarter + stamp too, since ALLOCATOR rows can push its row out of the 40-row log + (SAFETY-85).""" + return c._peak_alarm_block is not None or any( + "PEAK_GUARD_SATURATED" in e for e in c.events) def run(house, n=2, **kw): @@ -465,6 +468,10 @@ print("\n8. the N=1 and N=2 digests") # 2026-09-30, 480 cycles each, every claim hashed. N=1 and n2_charge_dear: # the same on release/1.0 9d5b7d1 (the tool copied in). N=2 in a cheap # window: new, the charge that 9d5b7d1 refused on every cycle. +# SAFETY-85 re-pinned the three N=2 ones: the loop is bounded while A's +# charge pin stands. n2_charge and _banked change only the loop's reason and +# claim on 2 cycles; n2_charge_dear changes commands on 98 cycles, where A's +# pin lifts (t=1800) and B no longer jumps 1390 W, and after the surplus step. PINNED = { "n1_charge": "0ed25c856456b97acb07a39299a8cb7b1a762c4d0005b88a0823c03057a80be5", @@ -473,11 +480,11 @@ PINNED = { "n1_charge_banked": "2619acdd06b04e56c000b168d64e1d044346c6ba3f929c94258d6ad8189ec609", "n2_charge": - "748abe785a79084bc738c82d0d6f90b951e1cb78e9629195c0c01d3bb67b55e2", + "b16d692128f14bcce3d87b142d290e0d6b13724289680e44a05215c9eaa24a7c", "n2_charge_dear": - "c34f08b3b5b6256e68cf05030fb0c29522916dc8f57c351008f48384657966c0", + "00a197d89a5dd1e8b3ae6a5d1af66329a4dc4850476569c5931c125fa4d9eaee", "n2_charge_banked": - "fb600ee1dd3202910715c97c5809584d50c6b8b57b55aaa4dc83bcaaa97627ef", + "a6973faea916e4c88ca1770047f94478346eeb1efa4889b154fad0747f91267f", } _now = s84.digests() for k in PINNED: @@ -485,7 +492,7 @@ for k in PINNED: f"{_now[k][:16]}") check("⭐ at N=1 a charge in and out of a cheap window and under a banked " "month peak is byte-identical to 9d5b7d1 (commands, reasons and every " - "claim), and so is N=2 outside a cheap window", + "claim), and N=2 outside a cheap window matches its SAFETY-85 pin", all(_now[k] == PINNED[k] for k in ("n1_charge", "n1_charge_dear", "n1_charge_banked", "n2_charge_dear"))) diff --git a/goodwe_controller/test_safety85.py b/goodwe_controller/test_safety85.py new file mode 100644 index 0000000..28af008 --- /dev/null +++ b/goodwe_controller/test_safety85.py @@ -0,0 +1,303 @@ +"""Runnable check for SAFETY-85: no false 'not keeping up' while another owner +sets the battery. `python3 test_safety85.py` + +The loop's integrator bound fired every ~2.5 min during maintenance and under +the peak guard, though the battery gave what it was told: the loop's own ask, +re-seeded and pushed by a grid error it did not own, crossed its rail. Now the +loop's clamp counts only on a cycle the loop decided, a battery another owner +set alarms only when it gives less than told, and at N>=2 the loop is bounded +while maintenance holds a battery. Drives the REAL Controller +(tools/safety84_identity.py's harness). DECISIONS/SAFETY-85-no-false-not-keeping-up.md. + +1. N=1 and N=2: a drain, a charge and a HOLD with the house above what the + battery is set to, an hour each: no warning; without the fix they warn. +2. A battery that gives less than told during a drain does alarm (N=1, N=2); + a two-cycle dip does not. +3. Control coming back from maintenance does not jump (N=2 hold end, N=2 + charge pin lifting, N=1 hold end). +4. The loop's own alarm stays (house over the rating); a safety limit at N=2 + (a battery at its cut-out) does not warn. +5. The status row counts episodes, not cycles. +6. The rules at their boundaries. + +Mutations (MUTATION.md, purged copies) are listed in the pull request. +""" + +import logging +import os +import sys +from datetime import datetime, timedelta, timezone + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +sys.path.insert(0, os.path.join(HERE, "tools")) +logging.disable(logging.WARNING) + +import opt11_identity as rig # noqa: E402 +import safety79_identity as s79 # noqa: E402 +import safety84_identity as s84 # noqa: E402 +import app.main as app_main # noqa: E402 +from app import clamp, messages # noqa: E402 +from app.main import Controller # noqa: E402 +from app.store import unit_key # noqa: E402 + +fails = [] +A = "inverter-a" +HOUR = 3600.0 +SLEW = 400.0 # the rig's slew_w +OPT0 = dict(s84.OPT) + + +def check(name, cond): + print(f" {'ok ' if cond else 'FAIL'} {name}") + if not cond: + fails.append(name) + + +async def _call(self, *a): + """The rig's Home Assistant, recording each notification id it is sent.""" + if len(a) >= 3 and a[1] == "create" and isinstance(a[2], dict): + self.__dict__.setdefault("notes", []).append( + a[2].get("notification_id")) + return True + + +rig._Hass.call = _call + + +def store(n, phase): + """Battery A in `phase` from the first cycle ('drain': due at 11:00; + 'idle': only with `maint=False`).""" + if phase == "drain": + return rig._Store() + if phase == "charge": + return s79.store_charging(n) + s = rig._Store() + if phase == "hold": + for k, v in (("phase", "hold"), ("phase_started", + rig.BASE.isoformat())): + s.data[k if n == 1 else unit_key(A, k)] = v + return s + + +def run(n, phase, house, cap, *, dur=HOUR, soc=None, cut=None, extra=None, + maint=True): + """Rows and controller; `cap` is the peak limit (20000: never binds).""" + s84.OPT = dict(OPT0, peak_cap_w=cap, maintenance_enabled=maint) + if soc is None: + def soc(u, t): + return 99.0 if phase == "hold" and u == "a" else 60.0 + try: + return s84.run(n, load=lambda t: house, cheap=(phase == "charge"), + store=store(n, phase), soc=soc, dur=dur, cut=cut, + extra=dict({"maintenance_hold_min": 600, + "maintenance_discharge_w": 2000}, + **(extra or {}))) + finally: + s84.OPT = OPT0 + + +def warned(c): + """'Battery is not keeping up': notifications, cycles, episodes.""" + return (getattr(c.hass, "notes", []).count(messages.ID_LOOP_BOUND), + c.clamp_wd.bound, c.clamp_wd.bound_episodes) + + +def patched(obj, name, value): + """Run `fn` with `obj.name` replaced (the 'without the fix' runs).""" + def wrap(fn): + real = getattr(obj, name) + setattr(obj, name, value) + try: + return fn() + finally: + setattr(obj, name, real) + return wrap + + +no_gate = patched(Controller, "_loop_alarm_input", lambda self, r: None) +no_bound = patched(Controller, "loop_bound", lambda self, claims: None) + + +def cmd(r): + return dict(r[2]) + + +def steps(rows, lo, hi): + """The largest change in the total command between cycles in [lo, hi].""" + tot = [(r[0], sum(cmd(r).values())) for r in rows] + return max(abs(b - a) for (t0, a), (t1, b) in zip(tot, tot[1:]) + if lo <= t1 <= hi) + + +# ============================================================================ # +print("1. the house above what the battery is set to, an hour each") +CASES = [ + # (n, phase, house, cap): the peak guard raises the drain / the HOLD at a + # 3500 W limit; the rest are the phase alone under a house that pushes the + # loop's re-seeded ask past its rail. + (1, "drain", 6500.0, 3500), (1, "drain", 7500.0, 20000), + (1, "charge", 10000.0, 20000), + (1, "hold", 6500.0, 3500), (1, "hold", 9000.0, 20000), + (2, "drain", 6500.0, 3500), (2, "charge", 10000.0, 20000), + (2, "hold", 4500.0, 20000), (2, "hold", 6500.0, 3500), +] +NEW, OLD = {}, {} +for k in CASES: + NEW[k] = run(*k) + OLD[k] = no_gate(lambda: no_bound(lambda: run(*k))) + print(f" N={k[0]} {k[1]:6} house {k[2]:5.0f} limit {k[3]:5}: phases " + f"{sorted({p for r in NEW[k][0] for p in r[-1][3]})}, warnings " + f"(notes, cycles, episodes) {warned(NEW[k][1])}, without the fix " + f"{warned(OLD[k][1])}") +check("⭐ no 'Battery is not keeping up' notification, cycle or episode in any " + "of the nine hours, at N=1 and N=2", + all(warned(c) == (0, 0, 0) for _r, c in NEW.values())) +check("...the phase held all hour (the battery was set by maintenance, or by " + "the guard over it, throughout)", + all(all(r[-1][3][0] == k[1] for r in NEW[k][0]) for k in CASES)) +check("non-vacuous: without the fix every one of the nine warns, the " + "notification re-created on the re-assert cadence", + all(warned(c)[0] >= 1 and warned(c)[1] > 0 for _r, c in OLD.values()) + and sum(warned(c)[0] for _r, c in OLD.values()) >= 9 * 5) + +# ============================================================================ # +print("\n2. a battery that really gives less than told still alarms") + + +def gone(t0, t1): + """Battery A gives nothing from t0 to t1.""" + return lambda u, t: u == "a" and t0 <= t < t1 + + +SHORT = {n: run(n, "drain", 1000.0, 20000, dur=1200.0, cut=gone(600, 1200)) + for n in (1, 2)} +for n, (rows, c) in SHORT.items(): + print(f" N={n}: {warned(c)}, log " + f"{[e for e in c.events if 'OUTPUT_CLAMP' in e][:1]}") +_r1, _c1 = SHORT[1] +check("⭐ N=1, a drain of 2000 W that gives nothing: it warns, and the log " + "says what was asked and what came", + warned(_c1)[0] >= 1 and any( + "the battery gives -4 W of the +2000 W asked" in e + for e in _c1.events)) +_r2, _c2 = SHORT[2] +check("⭐ N=2, the same on battery A while B follows the house: it warns and " + "names inverter-a", + warned(_c2)[0] >= 1 and any( + "inverter-a gives -4 W of the +2000 W asked" in e + for e in _c2.events)) +_hb = run(2, "hold", 4500.0, 20000, dur=1200.0, + cut=lambda u, t: u == "b" and t >= 600) +print(f" N=2 HOLD on A, B gives nothing: {warned(_hb[1])}") +check("⭐ N=2, A in its HOLD and B, which the loop drives, gives nothing: the " + "loop stands at what B may give, and it warns naming inverter-b", + warned(_hb[1])[0] >= 1 and any( + "inverter-b gives -4 W of the +2500 W asked" in e + for e in _hb[1].events)) +check("...it starts no earlier than the saturation cycles allow (3 x 5 s)", + all(e.split(" ", 1)[0] >= "11:10:10" for c in (_c1, _c2) + for e in c.events if "OUTPUT_CLAMP" in e)) +_quiet = patched(app_main, "delivery_short", lambda *a: False)( + lambda: run(1, "drain", 1000.0, 20000, dur=1200.0, cut=gone(600, 1200))) +check("non-vacuous: without the delivery rule the N=1 drain that gives " + "nothing is silent (the loop's clamp never reaches its rail here)", + warned(_quiet[1]) == (0, 0, 0)) +_dip = run(1, "drain", 1000.0, 20000, dur=900.0, cut=gone(600, 610)) +check("a dip of two cycles is not an alarm", warned(_dip[1]) == (0, 0, 0)) + +# ============================================================================ # +print("\n3. control coming back from maintenance does not jump") +END = {"maintenance_hold_min": 10} +_h2 = run(2, "hold", 4500.0, 20000, dur=900.0, extra=END) +_h2_old = no_bound(lambda: run(2, "hold", 4500.0, 20000, dur=900.0, + extra=END)) +_h1 = run(1, "hold", 4500.0, 20000, dur=900.0, extra=END) +s84.OPT = dict(OPT0) +_cd = s84.run(2, cheap=False) +_cd_old = no_bound(lambda: s84.run(2, cheap=False)) +print(f" N=2 hold end: largest step {steps(_h2[0], 560, 700):.0f} W " + f"(without the bound {steps(_h2_old[0], 560, 700):.0f} W); N=1 " + f"{steps(_h1[0], 560, 700):.0f} W; N=2 charge pin lifts at 1800 s: " + f"{steps(_cd[0], 1780, 1840):.0f} W (without " + f"{steps(_cd_old[0], 1780, 1840):.0f} W)") +check("⭐ N=2, the HOLD ends under a 4500 W house: the batteries move at most " + "one slew step a cycle", + _h2[1].maints[0].phase != "hold" and steps(_h2[0], 560, 700) <= SLEW) +check("⭐ N=2, A's charge pin lifts at a quarter's start: at most one slew " + "step a cycle", steps(_cd[0], 1780, 1840) <= SLEW) +check("...and N=1 already moved one slew step at a time (re-seeded each " + "cycle), unchanged", steps(_h1[0], 560, 700) <= SLEW) +check("non-vacuous: without the bound the N=2 loop stands wound at its rail " + "and both jump (2500 W at the hold's end)", + steps(_h2_old[0], 560, 700) >= 2000.0 + and steps(_cd_old[0], 1780, 1840) >= 1000.0) + +# ============================================================================ # +print("\n4. what still warns, and what a safety limit does") +_rail = run(1, "drain", 6500.0, 20000, dur=600.0, maint=False) +print(f" N=1 no maintenance, house 6500 over a 5000 W rating: " + f"{warned(_rail[1])}") +check("⭐ the loop in charge at its rail (house over the rating) still warns, " + "as SAFETY-40 decided", warned(_rail[1])[0] >= 1) + + +def at_cutout(u, t): + return 9.0 if u == "a" else 60.0 + + +_cut = run(2, "idle", 6000.0, 20000, dur=900.0, soc=at_cutout, maint=False) +_cut_old = no_gate(lambda: run(2, "idle", 6000.0, 20000, dur=900.0, + soc=at_cutout, maint=False)) +print(f" N=2, A at its cut-out, house 6000: {warned(_cut[1])}, without " + f"the fix {warned(_cut_old[1])}") +check("⭐ N=2, A at its cut-out level (a safety limit sets it to 0 W) and B " + "at its rating: no warning, each battery gives what it is told", + warned(_cut[1]) == (0, 0, 0) and cmd(_cut[0][-1]) == {"a": 0.0, + "b": 2500.0}) +check("non-vacuous: without the fix it warns", + warned(_cut_old[1])[0] >= 1) + +# ============================================================================ # +print("\n5. the status row counts episodes") +_wd = clamp.ClampWatchdog() +_t = datetime(2026, 9, 20, 11, 0, tzinfo=timezone.utc) +for ep in range(3): + for i in range(10): + _wd.note(True, "x", _t, bug=False) + _t += timedelta(seconds=5) + for i in range(clamp.CLEAR_CYCLES): + _wd.note(False, "", _t) + _t += timedelta(seconds=5) +_wd.note(True, "y", _t, bug=True) +check("three bound episodes of ten cycles and one over-rating: 3 episodes, " + "30 cycles", (_wd.bound_episodes, _wd.bound, _wd.episodes) == (3, 30, 4)) +_rows = [x for x in _c1.checks() if x.get("id") == "not_keeping_up"] +check("⭐ the page row reads the episodes, not the cycles " + f"({_c1.clamp_wd.bound_episodes} vs {_c1.clamp_wd.bound})", + _rows and _c1.clamp_wd.bound > _c1.clamp_wd.bound_episodes >= 1 + and _rows[0]["text"].startswith(messages.T_LOOP_BOUND + ": " + + messages.times( + _c1.clamp_wd.bound_episodes))) + +# ============================================================================ # +print("\n6. the rules at their boundaries") +DS = [((2000, 1499, 500), True), ((2000, 1500, 500), False), + ((2000, 2600, 500), False), ((-2000, -1499, 500), True), + ((-2000, -2600, 500), False), ((0, -900, 500), False), + ((0, 900, 500), False), + ((2000, -4, 500), True), ((-2000, 600, 500), True)] +check("delivery_short: more than the margin short in the asked direction; " + "more than asked, or 0 W asked, is never short", + all(clamp.delivery_short(*a) is want for a, want in DS)) +check("the note names each battery, asked before given", + clamp.shortfall_note([("inverter-a", 2000.0, -4.0)]) + == "OUTPUT_CLAMP: inverter-a gives -4 W of the +2000 W asked" + and clamp.shortfall_note([(None, -2000.0, 0.0)]) + == "OUTPUT_CLAMP: the battery gives +0 W of the -2000 W asked") + +print() +if fails: + print(f"{len(fails)} FAILED: " + ", ".join(fails)) + sys.exit(1) +print("all SAFETY-85 checks passed") diff --git a/goodwe_controller/test_safety86.py b/goodwe_controller/test_safety86.py index 35a4d4a..253d6b1 100644 --- a/goodwe_controller/test_safety86.py +++ b/goodwe_controller/test_safety86.py @@ -102,8 +102,11 @@ def on_aim(c, aim=AIM): def alarmed(c): - """Did SAFETY-81's 'Load too high' alarm fire on this run?""" - return any("PEAK_GUARD_SATURATED" in e for e in c.events) + """Did SAFETY-81's 'Load too high' alarm fire on this run? Its quarter + stamp too, since ALLOCATOR rows can push its row out of the 40-row log + (SAFETY-85).""" + return c._peak_alarm_block is not None or any( + "PEAK_GUARD_SATURATED" in e for e in c.events) def refused(rows): @@ -231,8 +234,21 @@ def rows_logged(c, word): return sum(1 for e in c.events if word in e) +def no_bound(fn): + """Run without SAFETY-85's loop bound (modes are off here).""" + real = Controller.loop_bound + Controller.loop_bound = lambda self, claims: None + try: + return fn() + finally: + Controller.loop_bound = real + + _nz_rows, _nz = run(noisy, 2) -_nz_old = no_ceiling(lambda: run(noisy, 2))[1] +# SAFETY-85's loop bound also keeps the loop inside what the batteries can +# give, so the flood needs both the ceiling and the bound taken out. +_nz_old = no_bound(lambda: no_ceiling(lambda: run(noisy, 2)))[1] +_nz_nc = no_ceiling(lambda: run(noisy, 2))[1] print(f" noisy house: ALLOCATOR rows {rows_logged(_nz, 'ALLOCATOR')}, " f"clamp rows {rows_logged(_nz, 'OUTPUT_CLAMP')} (without the site " f"ceiling {rows_logged(_nz_old, 'ALLOCATOR')} and " @@ -244,9 +260,13 @@ check("⭐ while A gives, the site target is the guard's floor (the `hold` " if cmd(r)["a"] > 0.0) and rows_logged(_nz, "ALLOCATOR") == 0 and rows_logged(_nz, "OUTPUT_CLAMP") <= 1) -check("non-vacuous: without the ceiling the loop asks 5000 W and the " - "ALLOCATOR and clamp rows fill the 40-row log", +check("non-vacuous: without the ceiling and SAFETY-85's bound the loop asks " + "5000 W and the ALLOCATOR and clamp rows fill the 40-row log", rows_logged(_nz_old, "ALLOCATOR") >= 10 and len(_nz_old.events) == 40) +check("...and either one alone keeps it clean (without the ceiling: " + f"{rows_logged(_nz_nc, 'ALLOCATOR')} ALLOCATOR rows)", + on_aim(_nz_nc) and rows_logged(_nz_nc, "ALLOCATOR") == 0 + and rows_logged(_nz_nc, "OUTPUT_CLAMP") <= 1) # ============================================================================ # print("\n4. a month peak banked above the limit") -- 2.54.0 From 7b723a6cd5d83a989457aaeaba811e0a211c0425 Mon Sep 17 00:00:00 2001 From: SAFETY-85 review <gschrooyen@gmail.com> Date: Thu, 1 Oct 2026 20:25:41 +0200 Subject: [PATCH 103/105] SAFETY-85 review: grade discharge only, over the plant's settle time Rule 2 graded each battery against last cycle's command and graded charges too. On plantsim's battery (10 s lag) at the 2 s meter it warned at every drain or charge start and 15 times an hour under the peak guard at N=2; a charge tapering near full warned 11 times in 50 min (SAFETY-42 section 7). Now a discharge is graded against the least it stood at over SHORT_CYCLES / SHORT_SPAN_S. DOCS lists `mode-bound` under Loop reason. test_safety85 part 7: peak guard with a dead battery, lagging plant, taper; part 3: the bound ends with maintenance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- .../SAFETY-85-no-false-not-keeping-up.md | 37 ++-- goodwe_controller/DOCS.md | 22 ++- goodwe_controller/app/clamp.py | 8 +- goodwe_controller/app/main.py | 34 +++- goodwe_controller/test_safety85.py | 165 +++++++++++++++++- 5 files changed, 222 insertions(+), 44 deletions(-) diff --git a/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md b/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md index 09cf889..778e326 100644 --- a/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md +++ b/goodwe_controller/DECISIONS/SAFETY-85-no-false-not-keeping-up.md @@ -25,14 +25,16 @@ counter counted cycles (861), not episodes. the loop. Its number is on the wire, or only a rating (`device`, `supervised`) cut it. No bound held it, and nothing was unmet. (`Controller._loop_alarm_input`.) -2. **A battery another owner set alarms when it gives less than it was told.** - This covers every battery on a cycle the loop did not decide, and a battery - with its own pin otherwise. The test is more than `saturation_w` short in - the told direction, for `saturation_cycles` cycles in a row, against what - stands on the wire (`clamp.delivery_short`). It covers a real shortfall - during maintenance. Before, that shortfall was silent unless the kick - happened to reach the rail (house 1000 W, drain 2000 W, battery gives - nothing: 0 warnings before, 4 in 10 min now). +2. **A battery another owner set to discharge alarms when it gives less than + it was told.** This covers every battery on a cycle the loop did not + decide, and a battery with its own pin otherwise. The test is more than + `saturation_w` short of the least it stood at over `SHORT_CYCLES` cycles + and `SHORT_SPAN_S` (the plant's measured settle, SAFETY-13/73), for + `saturation_cycles` cycles in a row (`clamp.delivery_short`). It covers a + real shortfall during maintenance or under the peak guard. Before, that + shortfall was silent unless the kick happened to reach the rail (house + 1000 W, drain 2000 W, battery gives nothing: 0 warnings before, 4 in 10 min + now). 3. **At N>=2, while maintenance holds a battery, the loop is bounded** by OPT-11's `loop_bound()` (what the batteries may place). It does not wind, and control comes back one slew step a cycle. Why maintenance only: that is @@ -69,12 +71,21 @@ batteries can give. The `alarmed()` helpers in test_safety84/86 also read SAFETY-81's quarter stamp, because ALLOCATOR rows can push its row out of the 40-row log. +**Review (PR #163).** The first draft graded each battery against last +cycle's command and graded charges too. On plantsim's battery (10 s lag) at +the live 2 s meter, every drain or charge start warned once, and an N=2 drain +or HOLD under the peak guard with a stepping house warned 15 times an hour. A +maintenance charge tapering near full warned 11 times in 50 min, which +SAFETY-42 section 7 had ruled out. With the settle window and discharge only: +0 in all of those cases. A battery that gives nothing still warns, lagging +or not. At a hypothetical 20 s lag, it warns at most twice an hour. The cost: +a battery that does not take a charge another owner set is not named by this +alarm (the same gap SAFETY-42 states; the charge has its 36 h timeout). +`test_safety85.py` part 7. + **Not changed, open for the owner.** - With the loop in charge and the house above the batteries' total rating, it still warns (SAFETY-40). On the rig's 2 x 2000 W N=2, most of SAFETY-84's count came from houses of 4500 and 6500 W. -- A battery that tapers near full during a charge, more than `saturation_w` - under its command for 15 s, now warns (rule 2). The text already says - "check it is not empty or full". -- TEL-10's `loop_reason` reads `mode-bound` while the maintenance bound holds - the loop, with modes off. +- TEL-10's `Loop reason` reads `mode-bound` while the maintenance bound holds + the loop, with modes off. DOCS lists the value with both meanings. diff --git a/goodwe_controller/DOCS.md b/goodwe_controller/DOCS.md index d246895..2d0964b 100644 --- a/goodwe_controller/DOCS.md +++ b/goodwe_controller/DOCS.md @@ -577,7 +577,7 @@ accumulator is doing: | `Loop integrator lead` | W | that value minus **the command it was computed against**, i.e. the command the previous cycle left standing | | `Loop reason` | — | the law's own word for this cycle | -`Loop reason` takes one of ten values: +`Loop reason` takes one of eleven values: | value | what happened | |---|---| @@ -588,6 +588,7 @@ accumulator is doing: | `slew-limited` | the command could not move as far as the integrator asked for; `slew_w` is what stopped it | | `saturated-freeze` | the inverter is not following, so the command's magnitude may fall but not rise | | `freeze-released` | the freeze had run out of plant-shaped explanations and the command was let move again | +| `mode-bound` | the batteries' limits set the command, not the meter: their battery modes, or, with two or more inverters, a battery in its monthly maintenance | | `not-running` | control is stopped **and** shadow mode is off, so the loop did not run | | `battery refuses` | the battery gave less than 100 W for 12 cycles (a minute at a 5-second meter) while asked for more than 500 W, so the add-on asks 0 W in that direction (see below) | | `battery probe` | the add-on asks 200 W to test whether a refusing battery gives power again | @@ -1954,10 +1955,12 @@ notification budget. Why: [`DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md`](DECISIONS/SAFETY-40-the-integrator-bound-is-not-a-bug.md). The integrator bound counts only on a cycle the loop decided. While -maintenance, the peak guard or a safety limit sets a battery, the same alarm -fires only when that battery gives more than `saturation_w` less than it was -told, for `saturation_cycles` cycles. At two or more inverters the loop does not -wind while maintenance holds a battery. +maintenance, the peak guard or a safety limit sets a battery to discharge, the +same alarm fires only when that battery gives more than `saturation_w` less +than the least it was told over the plant's settle time (at least 23 s), for +`saturation_cycles` cycles. A charge is not graded: a full battery takes less +as it tops up. At two or more inverters the loop does not wind while +maintenance holds a battery. Why: [`DECISIONS/SAFETY-85-no-false-not-keeping-up.md`](DECISIONS/SAFETY-85-no-false-not-keeping-up.md). ### The frozen-meter alarm @@ -3130,8 +3133,9 @@ short time, for example just after a large load switches on or the sun comes out. It is not a fault, and control keeps running. If it keeps coming back, check that the battery is switched on, and that it is not empty (when it should give power) or full (when it should charge). During the monthly maintenance or -while the peak limit is guarded, it only shows when the battery gives less than -it was told. The status page counts how many times it happened. +while the peak limit is guarded, it only shows when the battery gives +clearly less than it was told. The status page counts how many times it +happened. ### Power request too high @@ -3237,8 +3241,8 @@ link cannot jump to the section. **Battery is not keeping up.** The grid-following loop's integrator reached its anti-windup bound (`integrator_max_w`, SAFETY-40), or a battery that another -owner set gave less than it was told (SAFETY-85). No command went over the -rating. The log line is a WARNING with reason code `OUTPUT_CLAMP`. See *The +owner set to discharge gave less than it was told (SAFETY-85). No command went +over the rating. The log line is a WARNING with reason code `OUTPUT_CLAMP`. See *The winding-loop alarm*. **Power request too high.** A computed command above a limit was cut before it diff --git a/goodwe_controller/app/clamp.py b/goodwe_controller/app/clamp.py index e690faf..16816a3 100644 --- a/goodwe_controller/app/clamp.py +++ b/goodwe_controller/app/clamp.py @@ -270,12 +270,10 @@ def shortfall_note(named) -> str: def delivery_short(asked_w, given_w, margin_w) -> bool: - """SAFETY-85: did a battery give more than `margin_w` less than asked, in - the asked direction? Giving more than asked, or 0 W asked, is not short.""" + """SAFETY-85: did a battery asked to discharge give more than `margin_w` + less? A charge is never short: a full pack tapers (SAFETY-42 section 7).""" asked, given = float(asked_w), float(given_w) - if asked == 0.0: - return False - return (asked - given) * (1.0 if asked > 0 else -1.0) > abs(float(margin_w)) + return asked > 0.0 and asked - given > abs(float(margin_w)) def write_clamp_note(named) -> str: diff --git a/goodwe_controller/app/main.py b/goodwe_controller/app/main.py index ec4617f..a673fe3 100644 --- a/goodwe_controller/app/main.py +++ b/goodwe_controller/app/main.py @@ -281,6 +281,11 @@ def pack_energy_of(inv): # ordinary load steps. At 2 s and slower this changes nothing. REFUSED_SPAN_S = (_ctl.SETTLE_CYCLES - 1) * _ctl.LOOP_TICK_S +# SAFETY-85 review: a battery another owner set is graded against the least it +# was told over the same span as above (the plant's measured settle time), so +# a healthy battery still settling on a new command is not short. +SHORT_CYCLES, SHORT_SPAN_S = _ctl.SETTLE_CYCLES, REFUSED_SPAN_S + def _refused_interval(sign: int) -> tuple: """SAFETY-73: the (lo, hi) a refusing unit may be asked: 0 W that way.""" @@ -1180,9 +1185,11 @@ class Controller: self.loop_clamped: tuple[bool, str, bool] = (False, "", False) # UX-08: the numbers of a loop-side over-rating, for the notification. self.loop_clamp_facts: tuple = () - # SAFETY-85: this cycle's loop Decision, and how many cycles in a row - # a battery set by another owner gave less than asked. + # SAFETY-85: this cycle's loop Decision, each battery's recent + # standing commands, and how many cycles in a row a battery set by + # another owner gave less than asked. self._loop_decision = None + self._asked_hist: dict = {} self._short_run = 0 self.stopping = False # SAFETY-61. time.monotonic() at the end of the last run_control() pass. @@ -5084,25 +5091,36 @@ class Controller: def _loop_alarm_input(self, resolution) -> None: """SAFETY-85. The loop's clamp counts only on a cycle the loop decided - (a rating may cut it). A battery another owner set counts when it gave - less than it was told for `saturation_cycles` cycles in a row. - DECISIONS/SAFETY-85-no-false-not-keeping-up.md.""" + (a rating may cut it). A battery another owner set to discharge counts + when it gave less than it was told for `saturation_cycles` cycles in a + row. DECISIONS/SAFETY-85-no-false-not-keeping-up.md.""" d = self._loop_decision if d is None: self._short_run = 0 + self._asked_hist = {} return unmet = self.allocation.unmet_w if self.allocation is not None else 0 cut = (resolution.bound_by or "").split("(")[0] owns = (resolution.winner == "loop" and not d.held and not unmet and (resolution.target_w == d.target_w or cut in ("device", "supervised"))) - # Graded against what stands on the wire (0 W in shadow mode). + # Graded against the least that stood on the wire (0 W in shadow + # mode) over SHORT_CYCLES cycles and SHORT_SPAN_S seconds. + now, asked = self._now_mono, {} + for inv in self.inverters: + h = self._asked_hist.setdefault(inv.name, []) + h.append((now, inv.standing_w())) + while len(h) > SHORT_CYCLES and ( + now is None or h[0][0] is None + or now - h[0][0] > SHORT_SPAN_S): + h.pop(0) + asked[inv.name] = min(w for _t, w in h) others = [inv for inv in self.inverters if not owns or allocator.pin_w(resolution.unit_bounds.get(inv.name)) is not None] - short = [(inv, inv.standing_w(), inv.batt) for inv in others + short = [(inv, asked[inv.name], inv.batt) for inv in others if inv.batt is not None - and delivery_short(inv.standing_w(), inv.batt, + and delivery_short(asked[inv.name], inv.batt, self.tuning.saturation_w)] self._short_run = self._short_run + 1 if short else 0 if owns and self.loop_clamped[0]: diff --git a/goodwe_controller/test_safety85.py b/goodwe_controller/test_safety85.py index 28af008..ed70653 100644 --- a/goodwe_controller/test_safety85.py +++ b/goodwe_controller/test_safety85.py @@ -19,6 +19,8 @@ while maintenance holds a battery. Drives the REAL Controller (a battery at its cut-out) does not warn. 5. The status row counts episodes, not cycles. 6. The rules at their boundaries. +7. Review: a battery the peak guard sets that gives nothing warns; a battery + that lags (10 s) and a charge that tapers do not. Mutations (MUTATION.md, purged copies) are listed in the pull request. """ @@ -82,13 +84,15 @@ def store(n, phase): def run(n, phase, house, cap, *, dur=HOUR, soc=None, cut=None, extra=None, maint=True): - """Rows and controller; `cap` is the peak limit (20000: never binds).""" + """Rows and controller; `cap` is the peak limit (20000: never binds); + `house` is watts or a function of time.""" s84.OPT = dict(OPT0, peak_cap_w=cap, maintenance_enabled=maint) if soc is None: def soc(u, t): return 99.0 if phase == "hold" and u == "a" else 60.0 try: - return s84.run(n, load=lambda t: house, cheap=(phase == "charge"), + load = house if callable(house) else (lambda t: house) + return s84.run(n, load=load, cheap=(phase == "charge"), store=store(n, phase), soc=soc, dur=dur, cut=cut, extra=dict({"maintenance_hold_min": 600, "maintenance_discharge_w": 2000}, @@ -209,7 +213,20 @@ check("a dip of two cycles is not an alarm", warned(_dip[1]) == (0, 0, 0)) # ============================================================================ # print("\n3. control coming back from maintenance does not jump") END = {"maintenance_hold_min": 10} -_h2 = run(2, "hold", 4500.0, 20000, dur=900.0, extra=END) +_bounds = [] +_real_compute = app_main.compute + + +def _spy_compute(*a, **kw): + _bounds.append(kw.get("bound")) + return _real_compute(*a, **kw) + + +app_main.compute = _spy_compute +try: + _h2 = run(2, "hold", 4500.0, 20000, dur=900.0, extra=END) +finally: + app_main.compute = _real_compute _h2_old = no_bound(lambda: run(2, "hold", 4500.0, 20000, dur=900.0, extra=END)) _h1 = run(1, "hold", 4500.0, 20000, dur=900.0, extra=END) @@ -224,6 +241,14 @@ print(f" N=2 hold end: largest step {steps(_h2[0], 560, 700):.0f} W " check("⭐ N=2, the HOLD ends under a 4500 W house: the batteries move at most " "one slew step a cycle", _h2[1].maints[0].phase != "hold" and steps(_h2[0], 560, 700) <= SLEW) +_held = [any(p != "idle" for p in r[-1][3]) for r in _h2[0]] +print(f" bound per cycle: {len(_bounds)} calls, {len(_held)} rows, " + f"{sum(_held)} in maintenance, " + f"{sum(b is not None for b in _bounds)} bounded") +check("...and the bound is on while A holds and off from the cycle the HOLD " + "ends (review)", + len(_bounds) == len(_held) and any(not h for h in _held) + and all((b is not None) == h for b, h in zip(_bounds, _held))) check("⭐ N=2, A's charge pin lifts at a quarter's start: at most one slew " "step a cycle", steps(_cd[0], 1780, 1840) <= SLEW) check("...and N=1 already moved one slew step at a time (re-seeded each " @@ -283,12 +308,11 @@ check("⭐ the page row reads the episodes, not the cycles " # ============================================================================ # print("\n6. the rules at their boundaries") DS = [((2000, 1499, 500), True), ((2000, 1500, 500), False), - ((2000, 2600, 500), False), ((-2000, -1499, 500), True), - ((-2000, -2600, 500), False), ((0, -900, 500), False), - ((0, 900, 500), False), - ((2000, -4, 500), True), ((-2000, 600, 500), True)] -check("delivery_short: more than the margin short in the asked direction; " - "more than asked, or 0 W asked, is never short", + ((2000, 2600, 500), False), ((2000, -4, 500), True), + ((0, -900, 500), False), ((0, 900, 500), False), + ((-2000, -1499, 500), False), ((-2000, 600, 500), False)] +check("delivery_short: a discharge more than the margin short; more than " + "asked, 0 W asked, or a charge (a full pack tapers) is never short", all(clamp.delivery_short(*a) is want for a, want in DS)) check("the note names each battery, asked before given", clamp.shortfall_note([("inverter-a", 2000.0, -4.0)]) @@ -296,6 +320,129 @@ check("the note names each battery, asked before given", and clamp.shortfall_note([(None, -2000.0, 0.0)]) == "OUTPUT_CLAMP: the battery gives +0 W of the -2000 W asked") +# ============================================================================ # +print("\n7. review: the peak guard, a battery that lags, a charge that tapers") +import math # noqa: E402 + + +def under_guard(n, cut): + """A HOLD the peak guard raises (house 6500, limit 3500), 20 min.""" + return run(n, "hold", 6500.0, 3500, dur=1200.0, cut=cut) + + +_g1 = under_guard(1, lambda u, t: t >= 600) +_g2 = under_guard(2, lambda u, t: u == "a" and t >= 600) +print(f" under the guard, the battery gives nothing: N=1 {warned(_g1[1])}, " + f"N=2 {warned(_g2[1])}") +check("⭐ the peak guard sets the battery and it gives nothing: it warns at " + "N=1, and at N=2 (A, raised for the peak, gives nothing; B gives all " + "it is told)", + warned(_g1[1])[0] >= 1 and warned(_g2[1])[0] >= 1 + and all("peak" in r[6] for rows, _c in (_g1, _g2) for r in rows + if 600 <= r[0] <= 620)) +check("...and it gives what it is told until then (no warning before 600 s)", + all(e.split(" ", 1)[0] >= "11:10:00" for c in (_g1[1], _g2[1]) + for e in c.events if "OUTPUT_CLAMP" in e)) + + +def lagging(fn, lag=10.0): + """Run `fn` on plantsim's battery (800 W/s ramp, `lag` s first-order lag) + at the live 2 s meter tick.""" + real_p, real_t = rig._Hass.power, rig.TICK + + def power(self, u): + st = self.__dict__.setdefault("_plant", {}) + a, tgt, tl = st.get(u, (0.0, 0.0, self.t)) + for _ in range(int(round((self.t - tl) / 0.1))): + d = self.cmd[u] - tgt + tgt += math.copysign(min(abs(d), 80.0), d) + a += (tgt - a) * (1 - math.exp(-0.1 / lag)) + st[u] = (a, tgt, self.t) + if self.cut(u, self.t) and self.cmd[u] >= -4.0: + return -4.0 + return float(round(a)) + rig._Hass.power, rig.TICK = power, 2.0 + try: + return fn() + finally: + rig._Hass.power, rig.TICK = real_p, real_t + + +def kettle(t): + """800 W, plus 2 kW 3 min in 10, plus 3 kW 1 min in 4.""" + return (800.0 + (2000.0 if t % 600 < 180 else 0.0) + + (3000.0 if t % 240 < 60 else 0.0)) + + +def lag_runs(): + return [run(n, ph, kettle, 3500, dur=1800.0) + for n, ph in ((1, "drain"), (2, "drain"), (2, "hold"))] + + +_lag = lagging(lag_runs) +_lag_old = patched(app_main, "SHORT_CYCLES", 1)( + lambda: patched(app_main, "SHORT_SPAN_S", 0.0)( + lambda: lagging(lag_runs))) +_lag_dead = lagging(lambda: run(1, "drain", 1000.0, 20000, dur=900.0, + cut=gone(600, 900))) +print(f" lagging battery, house steps under the guard: " + f"{[warned(c) for _r, c in _lag]}, graded on last cycle's command " + f"{[warned(c) for _r, c in _lag_old]}; gives nothing " + f"{warned(_lag_dead[1])}") +check("⭐ a battery that lags (10 s) behind maintenance and peak-guard steps " + "at a 2 s meter does not warn (N=1 drain, N=2 drain and HOLD, 30 min)", + all(warned(c) == (0, 0, 0) for _r, c in _lag)) +check("non-vacuous: graded on last cycle's command alone, it warns", + sum(warned(c)[0] for _r, c in _lag_old) >= 3) +check("...and a lagging battery that gives nothing still warns", + warned(_lag_dead[1])[0] >= 1) + + +def taper(fn): + """Battery A takes the full charge until 600 s, then its acceptance falls + to 150 W over 30 min (constant-voltage taper).""" + real_p = rig._Hass.power + + def power(self, u): + c = self.cmd[u] + if c < 0 and u == "a": + c = max(c, -max(150.0, 2500.0 - max(0.0, self.t - 600) / 1800 + * 2350.0)) + return float(round(c)) + rig._Hass.power = power + try: + return fn() + finally: + rig._Hass.power = real_p + + +def charge_runs(): + s84.OPT = dict(OPT0, peak_cap_w=20000) + try: + return [s84.run(n, load=lambda t: 800.0, cheap=True, + store=s79.store_charging(n), soc=lambda u, t: 60.0, + dur=2400.0) for n in (1, 2)] + finally: + s84.OPT = OPT0 + + +def both_ways(asked, given, margin): + asked, given = float(asked), float(given) + return asked != 0.0 and (asked - given) * math.copysign(1.0, asked) > margin + + +_tp = taper(charge_runs) +_tp_old = patched(app_main, "delivery_short", both_ways)( + lambda: taper(charge_runs)) +print(f" a charge that tapers: {[warned(c) for _r, c in _tp]}, grading " + f"charges too {[warned(c) for _r, c in _tp_old]}") +check("⭐ a maintenance charge that tapers near full does not warn (N=1, N=2)", + all(warned(c) == (0, 0, 0) for _r, c in _tp) + and all("charge" in {p for r in rows for p in r[-1][3]} + for rows, _c in _tp)) +check("non-vacuous: grading charges too, the taper warns", + all(warned(c)[0] >= 3 for _r, c in _tp_old)) + print() if fails: print(f"{len(fails)} FAILED: " + ", ".join(fails)) -- 2.54.0 From 28cab039471021d0fb2af2cbc0f2662d3f3c13a6 Mon Sep 17 00:00:00 2001 From: glenn schrooyen <gschrooyen@gmail.com> Date: Fri, 2 Oct 2026 09:04:47 +0200 Subject: [PATCH 104/105] REL-0.13.0: cut 0.13.0 Bump config.yaml version 0.12.0 -> 0.13.0 and close a ## 0.13.0 CHANGELOG section covering every merge since 0.12.0 (a45ed06), with the known issues SAFETY-90/91/92/93/94. Option surface 77 -> 83, none removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/CHANGELOG.md | 84 ++++++++++++++++++++++++++++++++++ goodwe_controller/config.yaml | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/goodwe_controller/CHANGELOG.md b/goodwe_controller/CHANGELOG.md index 6e298b6..01e0a37 100644 --- a/goodwe_controller/CHANGELOG.md +++ b/goodwe_controller/CHANGELOG.md @@ -1,5 +1,89 @@ # Changelog +## 0.13.0 + +**A minor bump: new behaviour, a new settings page, and six new options.** +No option was removed or renamed, and no default of an existing option +changed (77 options -> 83). The live options blob on record passes this +version's validator (`tools/predeploy_check.py`, offline). + +New options, and what they do if you leave them alone: + +| option | default | left alone | +|---|---|---| +| `peak_margin_w` | `50` | the peak guard aims 50 W below your peak limit; set `0` for the old aim ([[SAFETY-79]]) | +| `battery_modes_enabled` | `false` | no battery modes, control as before ([[OPT-11]]) | +| `pv_forecast_entity`, `pv_forecast_tomorrow_entity` | empty | no solar forecast is used ([[OPT-11]]) | +| `solar_trust_pct` | `70` | only used with a solar forecast ([[OPT-11]]) | +| `pv_invert_entities` | `[]` | PV readings as before ([[TEL-14]]) | + +⚠️ **Turn on Watchdog** on the add-on's Info tab. If control stops, the +add-on now sets the batteries to 0 W and exits; Home Assistant only starts it +again when Watchdog is on ([[SAFETY-61]], [[DOC-5]]). + +Contents of this release, in merge order since 0.12.0 (`a45ed06`): + +| | | +|---|---| +| `fa3d237` | Docs name the right P1 age entity and a battery list that starts ([[DOC-1]]) | +| `6e65272` | If control stops, the batteries go to 0 W and the add-on exits ([[SAFETY-61]]) | +| `3e38baf` | The check tools refuse a file they cannot read, instead of saying all clear ([[SAFETY-60]], [[SAFETY-62]]) | +| `43b2740` | A missing value in a check is a named failure (tests only) ([[TEST-26]]) | +| `20260e8` | Docs: turn on Watchdog ([[DOC-5]]) | +| `16c796f` | New option `pv_invert_entities`: flip the sign of a PV sensor that reads backwards ([[TEL-14]]) | +| `6a8a5ff` | CI tests against the real inverter simulator (CI only) ([[CI-12]]) | +| `82f032e` | CI pin checks report failures properly (CI only) ([[TOOL-9]]) | +| `fe13251` | CI pin update (CI only) | +| `397dd15` | Alarm cards come back after a Home Assistant restart ([[SAFETY-34]]) | +| `59415ea` | CI pin update (CI only) | +| `2503de1` | The integrator limit is a warning, not a "bug" alarm; alarm figures are correct ([[SAFETY-40]]) | +| `48ef06a` | Shorter, plainer notifications ([[UX-08]]) | +| `5c151a3` | CI pin update (CI only) | +| `d57767f` | Shorter, plainer status rows and banners ([[UX-08]]) | +| `e1d0970` | Details link works on current Home Assistant; plainer words ([[UX-09]]) | +| `a02cd4b` | Shorter refusals, errors and option texts ([[UX-08]]) | +| `32b9e56` | Plainer log lines and docs ([[UX-08]]) | +| `125b070` | CI pin update (CI only) | +| `2b14b88` | Last plain-language fixes in logs and the status page ([[UX-10]]) | +| `c4032eb` | CI pin update (CI only) | +| `d1f7e33` | Safety log lines: one plain sentence and a code ([[UX-11]]) | +| `652097a` | A battery that stops responding is asked for 0 W, with a 200 W test every 15 min ([[SAFETY-52]]) | +| `afd6af0` | Groundwork for the new settings pages ([[UX-13]]) | +| `a36dca6` | New page with a Home screen ([[UX-13]]) | +| `28a49cc` | With two or more inverters, a battery that stops responding is held on its own ([[SAFETY-73]]) | +| `515c11b` | New Installer settings view ([[UX-13]]) | +| `4de9675` | New setup wizard for installers ([[UX-13]]) | +| `8c34647` | A new install with no inverter opens the setup wizard instead of stopping ([[UX-15]]) | +| `a5dddad` | Dutch text and a time-period editor ([[UX-13]]) | +| `ed739d4` | Battery modes (off by default): per-battery limits, on/off, solar order ([[OPT-11]]) | +| `7995e4d` | Simple settings view and a Batteries screen ([[UX-13]]) | +| `7337b79` | Battery modes in Home Assistant, when modes are on ([[OPT-11]]) | +| `7a00f12` | New option `peak_margin_w`: the peak guard keeps a margin below the limit ([[SAFETY-79]]) | +| `5a4cdc2` | Battery modes: charge in cheap hours, hold for expensive hours; selling is off for now ([[OPT-11]]) | +| `4f25b24` | No false "Load too high" alarms at quarter edges or with a noisy load (10 s hold) ([[SAFETY-81]]) | +| `35cdffe` | Maintenance drain with two batteries no longer stalls ([[SAFETY-78]]) | +| `1145a93` | Battery modes: a solar forecast decides how much to buy from the grid ([[OPT-11]]) | +| `9d5b7d1` | With one battery, the peak guard wins over the maintenance drain ([[SAFETY-83]]) | +| `4ad8298` | Maintenance charge with two batteries no longer stalls; it gives way to the peak guard ([[SAFETY-84]]) | +| `b8ddfd7` | The peak guard wins over the maintenance hold; the hold ends on time, with no top-up ([[SAFETY-86]]) | +| `9358781` | With two or more batteries, the peak guard uses every battery that can still give; peak alarms no longer say control stopped ([[SAFETY-87]]) | +| `61072ca` | No false "Battery is not keeping up" during maintenance; real shortfalls still warn; the counter counts episodes ([[SAFETY-85]]) | + +### Known issues + +- A false "Battery is not keeping up" can still show when the peak guard pauses a maintenance charge ([[SAFETY-92]]). +- Two inverters: at the end of a maintenance charge one battery can charge from the grid while the house uses a lot. Do not add a second inverter before the next release ([[SAFETY-93]]). +- A healthy battery that turns from charging to giving can be held at 0 W for up to 15 min ([[SAFETY-94]]). +- After a gap in the P1 meter, the peak guard is blind for the rest of that quarter hour ([[SAFETY-90]]). +- Two batteries: one at its peak reserve can be used before a draining battery has used its room ([[SAFETY-91]]). + +### If you are crossing from a version older than 0.10.0 + +`## 0.10.0` below can refuse an old config: `slew_w` above its limit, and the +withdrawn `price_provider` ids `engie_dynamic`, `totalenergies_dynamic` and +`eneco_eddy`. Read it before you update. Run `tools/predeploy_check.py` with the +bare options (`jq '.data.options'`) first. + ## 0.12.0 **A MINOR BUMP FOR ONE NEW OPTION: `pv_entities` ([[TEL-12]]), for sites with diff --git a/goodwe_controller/config.yaml b/goodwe_controller/config.yaml index 4fcff8e..973f5a3 100644 --- a/goodwe_controller/config.yaml +++ b/goodwe_controller/config.yaml @@ -1,5 +1,5 @@ name: GoodWe RS485 Controller -version: "0.12.0" +version: "0.13.0" slug: goodwe_controller description: >- Drives a GoodWe ES/BP battery inverter over RS485 by emulating its smart -- 2.54.0 From b37b7f95dc0696e599857d6aec64a4b5e99cb6fb Mon Sep 17 00:00:00 2001 From: "REL-0.13.0 review" <gschrooyen@gmail.com> Date: Fri, 2 Oct 2026 09:37:34 +0200 Subject: [PATCH 105/105] REL-0.13.0 review: plainer, truer 0.13.0 changelog Crash, not stop, for SAFETY-61; Watchdog off by default; its own warning for the 50 W peak margin (also under a higher month peak); "refuses power" for SAFETY-52/73; no one-house options claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --- goodwe_controller/CHANGELOG.md | 36 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/goodwe_controller/CHANGELOG.md b/goodwe_controller/CHANGELOG.md index 01e0a37..f496b85 100644 --- a/goodwe_controller/CHANGELOG.md +++ b/goodwe_controller/CHANGELOG.md @@ -2,41 +2,47 @@ ## 0.13.0 -**A minor bump: new behaviour, a new settings page, and six new options.** -No option was removed or renamed, and no default of an existing option -changed (77 options -> 83). The live options blob on record passes this -version's validator (`tools/predeploy_check.py`, offline). +**A minor bump: new behaviour, a new add-on page (Home, Settings, Batteries, +Setup), and six new options.** No option was removed or renamed, and no +default of an existing option changed (77 options -> 83). The only new +start-up checks are on the new options, so options that start 0.12.0 also +start 0.13.0. New options, and what they do if you leave them alone: | option | default | left alone | |---|---|---| -| `peak_margin_w` | `50` | the peak guard aims 50 W below your peak limit; set `0` for the old aim ([[SAFETY-79]]) | +| `peak_margin_w` | `50` | the peak guard aims 50 W below your peak limit, or below a higher peak already reached this month; `0` is the old aim ([[SAFETY-79]]) | | `battery_modes_enabled` | `false` | no battery modes, control as before ([[OPT-11]]) | | `pv_forecast_entity`, `pv_forecast_tomorrow_entity` | empty | no solar forecast is used ([[OPT-11]]) | | `solar_trust_pct` | `70` | only used with a solar forecast ([[OPT-11]]) | | `pv_invert_entities` | `[]` | PV readings as before ([[TEL-14]]) | -⚠️ **Turn on Watchdog** on the add-on's Info tab. If control stops, the -add-on now sets the batteries to 0 W and exits; Home Assistant only starts it -again when Watchdog is on ([[SAFETY-61]], [[DOC-5]]). +⚠️ **Turn on Watchdog** on the add-on's Info tab. It is off by default. If +the control loop crashes, the add-on now sets the batteries to 0 W and stops. +Home Assistant only starts it again when Watchdog is on ([[SAFETY-61]], +[[DOC-5]]). + +⚠️ **The peak guard now starts a little earlier.** It aims 50 W below your +peak limit, so the batteries give a bit more at peak times. Set +`peak_margin_w: 0` for the old aim ([[SAFETY-79]]). Contents of this release, in merge order since 0.12.0 (`a45ed06`): | | | |---|---| | `fa3d237` | Docs name the right P1 age entity and a battery list that starts ([[DOC-1]]) | -| `6e65272` | If control stops, the batteries go to 0 W and the add-on exits ([[SAFETY-61]]) | -| `3e38baf` | The check tools refuse a file they cannot read, instead of saying all clear ([[SAFETY-60]], [[SAFETY-62]]) | +| `6e65272` | If the control loop crashes, the batteries go to 0 W and the add-on stops ([[SAFETY-61]]) | +| `3e38baf` | The check tools refuse a file they cannot read, instead of saying all clear (tools only) ([[SAFETY-60]], [[SAFETY-62]]) | | `43b2740` | A missing value in a check is a named failure (tests only) ([[TEST-26]]) | | `20260e8` | Docs: turn on Watchdog ([[DOC-5]]) | | `16c796f` | New option `pv_invert_entities`: flip the sign of a PV sensor that reads backwards ([[TEL-14]]) | | `6a8a5ff` | CI tests against the real inverter simulator (CI only) ([[CI-12]]) | | `82f032e` | CI pin checks report failures properly (CI only) ([[TOOL-9]]) | | `fe13251` | CI pin update (CI only) | -| `397dd15` | Alarm cards come back after a Home Assistant restart ([[SAFETY-34]]) | +| `397dd15` | Alarm notifications that are still active come back after a Home Assistant restart ([[SAFETY-34]]) | | `59415ea` | CI pin update (CI only) | -| `2503de1` | The integrator limit is a warning, not a "bug" alarm; alarm figures are correct ([[SAFETY-40]]) | +| `2503de1` | "Battery is not keeping up" is a warning with its own notification, not a "bug" alarm; its figures are correct ([[SAFETY-40]]) | | `48ef06a` | Shorter, plainer notifications ([[UX-08]]) | | `5c151a3` | CI pin update (CI only) | | `d57767f` | Shorter, plainer status rows and banners ([[UX-08]]) | @@ -47,10 +53,10 @@ Contents of this release, in merge order since 0.12.0 (`a45ed06`): | `2b14b88` | Last plain-language fixes in logs and the status page ([[UX-10]]) | | `c4032eb` | CI pin update (CI only) | | `d1f7e33` | Safety log lines: one plain sentence and a code ([[UX-11]]) | -| `652097a` | A battery that stops responding is asked for 0 W, with a 200 W test every 15 min ([[SAFETY-52]]) | +| `652097a` | A battery that refuses power (e.g. empty) is asked for 0 W, and tried at 200 W for 34 s every 15 min ([[SAFETY-52]]) | | `afd6af0` | Groundwork for the new settings pages ([[UX-13]]) | | `a36dca6` | New page with a Home screen ([[UX-13]]) | -| `28a49cc` | With two or more inverters, a battery that stops responding is held on its own ([[SAFETY-73]]) | +| `28a49cc` | With two or more inverters, a battery that refuses power is held on its own; the others take over ([[SAFETY-73]]) | | `515c11b` | New Installer settings view ([[UX-13]]) | | `4de9675` | New setup wizard for installers ([[UX-13]]) | | `8c34647` | A new install with no inverter opens the setup wizard instead of stopping ([[UX-15]]) | @@ -67,7 +73,7 @@ Contents of this release, in merge order since 0.12.0 (`a45ed06`): | `4ad8298` | Maintenance charge with two batteries no longer stalls; it gives way to the peak guard ([[SAFETY-84]]) | | `b8ddfd7` | The peak guard wins over the maintenance hold; the hold ends on time, with no top-up ([[SAFETY-86]]) | | `9358781` | With two or more batteries, the peak guard uses every battery that can still give; peak alarms no longer say control stopped ([[SAFETY-87]]) | -| `61072ca` | No false "Battery is not keeping up" during maintenance; real shortfalls still warn; the counter counts episodes ([[SAFETY-85]]) | +| `61072ca` | No false "Battery is not keeping up" during maintenance; real shortfalls still warn; the status row counts each episode once ([[SAFETY-85]]) | ### Known issues -- 2.54.0