"""Saves screenshots of the web UI tabs in Pictures/web-ui/, with Microsoft Edge (or Chrome) in headless mode. python tools/make_webui_screenshots.py [ESP32 address, default 10.1.1.198] Each tab is opened by its address (http:///#settings); the page editor with #pages/. Edge runs with its own temporary profile. Only the Python standard library is used. """ import json import os import shutil import subprocess import sys import tempfile import urllib.parse import urllib.request ESP = 'http://' + (sys.argv[1] if len(sys.argv) > 1 else '10.1.1.198') OUT = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'Pictures', 'web-ui') BROWSERS = [ r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe', r'C:\Program Files\Microsoft\Edge\Application\msedge.exe', r'C:\Program Files\Google\Chrome\Application\chrome.exe', 'microsoft-edge', 'google-chrome', 'chromium', ] WIDTH = 1000 # File name, address part, window height SHOTS = [ ('show', 'show', 2150), ('pages', 'pages/Weer', 3000), # the page list and the editor (tall: nothing has to scroll) ('schedule', 'schedule', 1150), ('stopwatch', 'stopwatch', 560), ('bitmaps', 'bitmaps', 1600), ('icons', 'icons', 1900), ('draw', 'draw', 820), ('settings', 'settings', 1550), ('home-assistant', 'ha', 780), ('system', 'system', 1080), ] def browser(): for b in BROWSERS: path = shutil.which(b) or (b if os.path.exists(b) else None) if path: return path sys.exit('No Edge or Chrome found') def read_ha_values(): """Reads the Home Assistant values of all pages, so the previews show them""" with urllib.request.urlopen(ESP + '/api/pages', timeout=20) as r: pages = json.loads(r.read())['pages'] for entity in {(e['entity'], e.get('attribute', '')) for p in pages for e in p['page']['elements'] if e.get('entity')}: query = urllib.parse.urlencode({'entity': entity[0], 'attribute': entity[1]}) try: urllib.request.urlopen(ESP + '/api/ha/value?' + query, timeout=10).read() except Exception: pass def shoot(exe, profile, path, address, height): for attempt in range(3): try: subprocess.run([exe, '--headless=new', '--disable-gpu', '--hide-scrollbars', '--user-data-dir=' + profile, '--window-size=%d,%d' % (WIDTH, height), '--virtual-time-budget=20000', '--screenshot=' + path, address], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=90) return True except subprocess.TimeoutExpired: pass # the browser hung: try again return False def main(): exe = browser() read_ha_values() os.makedirs(OUT, exist_ok=True) profile = tempfile.mkdtemp(prefix='flipdot-edge-') try: for name, hash_part, height in SHOTS: path = os.path.join(OUT, name + '.png') ok = shoot(exe, profile, path, ESP + '/#' + hash_part, height) print(name, os.path.getsize(path) if ok and os.path.exists(path) else 'failed') finally: shutil.rmtree(profile, ignore_errors=True) if __name__ == '__main__': main()