3e959b3df9
Everything a user sees or reads is now English: both boards' labels, status replies and logs, the ESP Screens editor and Alerts cheatsheet, and the README and guides (docs/TILES.md, CALIBRATING.md, ACCEPTANCE.md and TROUBLESHOOTING.md replace the Dutch file names). Labels follow Home Assistant's own English names (Heat/Cool modes, Heating/Cooling actions, Away, Returning to dock, weather conditions), dates use English abbreviations and the top bar writes numbers the English way. Docs use HA 2026.9's menu names (Settings -> Apps, App store, Settings -> Tools). Unused legacy files (home-like.yaml, buttons.yaml, a.out) are removed. Firmware 0.2.34 names its entities in English. Home Assistant registers a renamed ESPHome entity under a new entity ID, so the inbox text.<screen>_tegelinstellingen becomes text.<screen>_tile_settings and the layout stored under the old ID would be lost. The manager now recognises the screen by its device, during a run or after a restart, and moves its layout and update history along; the Update button and the nightly round follow the screen through the rename. Screens that still run 0.2.33 or older keep working: both languages are matched. Main is the only release branch from now on. Tested on a Home Assistant Yellow (HA 2026.9.1) with both bench boards: see docs/TEST_RESULTS_0240.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
64 lines
3.0 KiB
Python
64 lines
3.0 KiB
Python
"""Export an allowlisted, neutral starter ZIP (never copies local secrets/logs)."""
|
|
import argparse
|
|
from pathlib import Path
|
|
import re
|
|
import zipfile
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
FILES = ['.gitignore', 'README.md', 'AGENTS.md', 'requirements.txt', 'device.example.yaml',
|
|
'calibration.example.yaml', 'secrets.yaml.example', 'cyd_ui.h', 'light_controls.h', 'LICENSE',
|
|
'guition_diagnostics.h', 'guition-4848s040.yaml', 'guition-device.example.yaml', 'TILE_CONFIGURATION.md', 'CYD_STABILITY.md', 'TEST_RESULTS.md', 'repository.yaml']
|
|
FOLDERS = ['docs', 'tools', 'tests', 'components', 'diagnostics', 'fonts']
|
|
SUFFIXES = {'.py', '.cpp', '.h', '.md', '.ttf', '.txt'}
|
|
|
|
|
|
def neutral_base(root):
|
|
defaults = '\n'.join((root / name).read_text() for name in ['device.example.yaml', 'calibration.example.yaml'])
|
|
replacements = dict(re.findall(r'^ (\w+): ("[^"\n]*")', defaults, re.M))
|
|
base = (root / 'home-like-2432s028.yaml').read_text()
|
|
def replace(match):
|
|
key = match[1]
|
|
return f' {key}: {replacements.get(key, match[2])}'
|
|
return re.sub(r'^ (\w+): ("[^"\n]*")', replace, base, flags=re.M)
|
|
|
|
|
|
def export(root, output):
|
|
root, output = Path(root).resolve(), Path(output)
|
|
paths = [root / name for name in FILES]
|
|
for folder in FOLDERS:
|
|
for path in (root / folder).rglob('*'):
|
|
if path.is_file() and '__pycache__' not in path.parts and (path.suffix in SUFFIXES or path.name == 'LICENSE'):
|
|
paths.append(path)
|
|
# Dedicated distribution directories only; never recursively include owner YAML.
|
|
for folder in ['screen_manager', 'packages', 'installers']:
|
|
for path in (root / folder).rglob('*'):
|
|
if path.is_file() and '__pycache__' not in path.parts and (path.suffix in SUFFIXES | {'.yaml', '.html', '.js', '.css'} or path.name == 'Dockerfile'):
|
|
paths.append(path)
|
|
for path in paths:
|
|
if path.is_symlink() or not path.resolve().is_relative_to(root):
|
|
raise ValueError(f'No files outside the source folder or symlinks allowed: {path}')
|
|
if not path.is_file():
|
|
raise ValueError(f'Missing bundle file: {path}')
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
# Exclusive mode refuses to replace a previously delivered bundle.
|
|
with zipfile.ZipFile(output, 'x', zipfile.ZIP_DEFLATED) as archive:
|
|
archive.writestr('cyd-display/home-like-2432s028.yaml', neutral_base(root))
|
|
for path in sorted(set(paths)):
|
|
archive.write(path, 'cyd-display/' + path.relative_to(root).as_posix())
|
|
return output
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--output', type=Path, default=ROOT / 'dist' / 'cyd-starter.zip')
|
|
args = parser.parse_args()
|
|
try:
|
|
print(f'Share this ZIP: {export(ROOT, args.output)}')
|
|
print('No local secrets, device.yaml, calibration measurements, logs or firmware backups included.')
|
|
except (OSError, ValueError) as exc:
|
|
parser.exit(1, f'Error: {exc}\n')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|