Files
heating-mpc-ha/scripts/validate_package.py
T
buzeraandClaude Opus 5.5 ec3a0738fe Add integration icon
Home Assistant 2026.3+ shows custom integrations' own brand images from
custom_components/<domain>/brand/. Add a radiator with a forecast curve
(solid past, "now" marker, dashed prediction) as icon.png/icon@2x.png
(256/512 px, transparent) plus dark-theme variants, so the integration
is easy to spot in Devices & services. Older HA versions ignore the
folder and show the generic placeholder; the integration is unaffected.

scripts/make_brand_icons.py regenerates the images with Pillow from the
test requirements; the package check verifies sizes and transparency.
Listed under 0.2.3, which has not been deployed yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 22:13:20 +02:00

41 lines
2.1 KiB
Python

"""Small local packaging and translation checks; not a replacement for hassfest."""
import json
from pathlib import Path
import struct
import subprocess
root = Path(__file__).resolve().parents[1]
component = root / "custom_components" / "heating_mpc"
manifest = json.loads((component / "manifest.json").read_text())
assert manifest["domain"] == "heating_mpc"
assert manifest["config_flow"] is True
assert manifest["iot_class"] == "local_polling"
assert not manifest["requirements"], "Model inference should remain dependency-free"
json.loads((root / "hacs.json").read_text())
# A version bump needs release notes (AGENTS.md: no version without documentation).
assert f"## {manifest['version']} " in (root / "CHANGELOG.md").read_text(), \
f"CHANGELOG.md has no entry for {manifest['version']}"
def keys(value, prefix=()):
if not isinstance(value, dict):
return {prefix}
return set().union(*(keys(child, (*prefix, key)) for key, child in value.items()))
strings = json.loads((component / "strings.json").read_text())
for language in ("en", "ro"):
translated = json.loads((component / "translations" / f"{language}.json").read_text())
assert keys(strings) == keys(translated), f"Translation keys differ: {language}"
# Brand icons (HA 2026.3+): square transparent PNGs; see scripts/make_brand_icons.py.
for name, size in (("icon.png", 256), ("icon@2x.png", 512),
("dark_icon.png", 256), ("dark_icon@2x.png", 512)):
png = (component / "brand" / name).read_bytes()
assert png[:8] == b"\x89PNG\r\n\x1a\n" and png[12:16] == b"IHDR", f"{name} is not a PNG"
width, height, _depth, color_type = struct.unpack(">IIBB", png[16:26])
assert (width, height) == (size, size), f"{name} is {width}x{height}, expected {size}x{size}"
assert color_type == 6, f"{name} needs an alpha channel"
tracked = subprocess.check_output(["git", "ls-files", "custom_components"], cwd=root, text=True).splitlines()
assert not any("__pycache__" in path or path.endswith((".pyc", ".pyo")) for path in tracked)
print("Package metadata, translations, brand icons and tracked component files passed")