This commit is contained in:
Mateusz Gruszczyński committed 2026-10-20 22:52:13 +02:00
1 parent f376f0a7b6
commit 8059e16d12
36 files changed
+1140 -193

No files matched your search

+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Static release checks for the two-node Simple day/night heating Flows.
Does not replace `cargo test` or hardware verification.
"""
from __future__ import annotations
import json
import subprocess
import sys
import tomllib
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PROFILE_DIR = ROOT / "flows" / "simple-heating"
ROOMS = {
"sypialnia": ("9a0bb37d-0306-4f87-9b14-fabf3b4c6164", 20.5, 10),
"jan-pieczara": ("7feae66a-747e-4205-8cff-91cc0b7924f6", 20.8, 8),
"igor": ("dd451f3e-4fc0-4189-b1cf-0c814b65cefc", 20.8, 10),
}
TRANSLATIONS = [
"flow.node.simpleHeat", "flow.simpleHeatDay", "flow.simpleHeatNight",
"flow.simpleHeatMinimum", "flow.simpleHeatBoostMinutes",
"flow.simpleHeatOffMinutes", "flow.simpleHeatHint", "zones.flowDayOff", "zones.flowDayPendingOff",
"flow.constantDescription", "flow.constantHelp", "flow.simpleHeatDescription", "flow.simpleHeatHowItWorks",
"flow.simpleHeatHelpIntro", "flow.simpleHeatHelpNightTitle", "flow.simpleHeatHelpNightSleep",
"flow.simpleHeatHelpNightBrake", "flow.simpleHeatHelpNightGentle", "flow.simpleHeatHelpNightBoost",
"flow.simpleHeatHelpDayTitle", "flow.simpleHeatHelpDayOff", "flow.simpleHeatHelpDayHeat",
"flow.simpleHeatHelpDayStop", "flow.simpleHeatHelpSensors", "flow.simpleHeatHelpSchedule",
"flow.simpleHeatHelpControl", "flow.simpleHeatDayTip", "flow.simpleHeatNightTip",
"flow.simpleHeatMinimumTip", "flow.simpleHeatBoostTip", "flow.simpleHeatOffTip",
]
def main() -> None:
version = tomllib.loads((ROOT / "Cargo.toml").read_text())["package"]["version"]
for name, (zone_id, target, boost) in ROOMS.items():
path = PROFILE_DIR / f"{name}-simple-heat-v5.flow.json"
doc = json.loads(path.read_text())
assert doc["format"] == "gree-controller-flow" and doc["version"] == 1, name
graph = doc["flow"]
assert graph["enabled"] and not graph["draft"], name
assert len(graph["nodes"]) == 2 and len(graph["edges"]) == 1, name
conditions = [node for node in graph["nodes"] if node["kind"] == "constant"]
actions = [node for node in graph["nodes"] if node["kind"] == "zone_heat_cycle"]
assert len(conditions) == len(actions) == 1, name
assert conditions[0]["config"]["value"] is True, name
assert graph["edges"][0]["from"] == conditions[0]["id"], name
assert graph["edges"][0]["to"] == actions[0]["id"], name
conf = actions[0]["config"]
assert conf["zone_id"] == zone_id, name
assert conf["night_target"] == target, name
assert conf["day_target"] == 20 and conf["day_min"] == 19.7, name
assert conf["boost_after_minutes"] == boost, name
assert conf["day_off_after_minutes"] == 30, name
assert "Wymaga wersji aplikacji 0.16.2" in graph["description"], name
for lang in ("pl", "en"):
translations = json.loads((ROOT / "lang" / f"{lang}.json").read_text())["translations"]
assert all(translations.get(key) for key in TRANSLATIONS), lang
# Validate every distributable JSON input, not only the three new Flow exports.
json_files = list(ROOT.rglob("*.json"))
for path in json_files:
json.loads(path.read_text())
assert len(json_files) > 30, len(json_files)
js_files = list((ROOT / "web").rglob("*.js"))
for path in js_files:
subprocess.run(["node", "--check", str(path)], check=True, capture_output=True, text=True)
rust = (ROOT / "src" / "api" / "flows.rs").read_text()
engine = (ROOT / "src" / "engine" / "zone_control.rs").read_text()
auto = (ROOT / "src" / "engine" / "automations.rs").read_text()
status = (ROOT / "web" / "js-dynamic" / "entities.js").read_text()
ui = (ROOT / "web" / "js-dynamic" / "flows.js").read_text()
html = (ROOT / "web" / "index.html").read_text()
for value in ("zone_heat_cycle", "boost_after_minutes", "day_off_after_minutes"):
assert value in rust and value in ui, value
assert "simple_heat_step(" in engine and "action_zone_simple_heat" in auto
assert "zone.simple_heat" in engine and "enabled_heat_actions" in engine
assert "automation.flow" in status and "zones.flowDayOff" in status
assert 'data-flow-add="zone_heat_cycle"' in html
assert "day_target_20_starts_at_21_then_boosts_to_22" in (ROOT / "src" / "engine" / "simple_heat.rs").read_text()
lock = (ROOT / "Cargo.lock").read_text()
assert f'name = "gree-controller"\nversion = "{version}"' in lock
for manifest in [
ROOT / "ha-addon" / "repository" / "gree-controller" / "config.yaml",
ROOT / "ha-addon" / "home-assistant" / "custom_components" / "gree_controller" / "manifest.json",
]:
assert version in manifest.read_text(), manifest
assert json.loads((ROOT / "docs" / "openapi.json").read_text())["info"]["version"] == version
print(f"OK: {len(ROOMS)} Flow imports, {len(json_files)} JSON files, {len(js_files)} JS scripts, translations, linked controller source, version {version}")
if __name__ == "__main__":
try:
main()
except (AssertionError, subprocess.CalledProcessError) as exc:
print(f"FAIL: {exc}", file=sys.stderr)
raise