One-window install: profile, wifi, USB flash and pairing hints (0.2.27)
"Nieuw scherm" used to span two dialogs plus a copy/download of the installation YAML. It is now one dialog: board, name (node name derived, editable), wifi only when secrets.yaml lacks it, the detected USB port, and Installeren. The add-on writes the profile with unique API/OTA keys, merges just the missing wifi lines into secrets.yaml (comments and other secrets untouched, result re-parsed before writing), then builds and flashes with the live ESPHome log and stage in the same dialog; a failed build offers a retry without a second profile. The YAML download endpoint is gone: the profile already lives in the ESPHome folder. Pairing happens in Home Assistant itself, so the done view and a sidebar card per not-yet-paired profile say so, with a button to Apparaten & diensten, the API key to copy and the reminder to allow HA actions. One profile per screen; the dialog says that too. Tests: wifi merge cases, install pre-checks, pending list, profile metadata; the date-anchored hourly forecast test now follows the clock. Firmware 0.2.22 stays current. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@ import tile_icons
|
||||
from updates import Updater
|
||||
|
||||
from aiohttp import ClientSession, ClientTimeout, WSMsgType, web
|
||||
from core import BUILTIN, TILE_BACKGROUNDS, controls_catalogue, discover, extras, installation_yaml, min_firmware, packets, state_message, validate_layout, validate_settings
|
||||
from core import BUILTIN, TILE_BACKGROUNDS, controls_catalogue, discover, extras, min_firmware, packets, state_message, validate_layout, validate_settings
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
LOG = logging.getLogger('screen_manager')
|
||||
@@ -291,6 +291,19 @@ class Manager:
|
||||
for listener in self.listeners:
|
||||
listener.set()
|
||||
|
||||
def pending_profiles(self, screens, profiles):
|
||||
"""ESP Screens profiles without a paired screen: flashed but not yet added in Home Assistant, or not flashed yet.
|
||||
|
||||
Pairing happens in Home Assistant itself, outside this page; the sidebar shows these so nobody wonders
|
||||
where the freshly flashed screen went."""
|
||||
nodes = {s.get('node') for s in screens}
|
||||
devices = {s.get('device') for s in screens}
|
||||
installed = getattr(self.firmware, 'installed', set())
|
||||
return [{'file': file, 'node': meta['node'], 'friendly': meta.get('friendly') or meta['node'] or file,
|
||||
'installed': file in installed, 'api_key': meta.get('api_key')}
|
||||
for file, meta in profiles.items()
|
||||
if meta.get('screen') and meta.get('node') not in nodes and (meta.get('friendly') or None) not in devices]
|
||||
|
||||
def watched_entities(self):
|
||||
"""Entities whose state changes matter: tiles on any layout plus the screens' own diagnostics."""
|
||||
watched = {tile['entity'] for layout in self.layouts.values() for tile in layout['tiles']}
|
||||
@@ -431,6 +444,7 @@ def create_app(manager, development=False):
|
||||
screen['delivery'] = manager.status.get(screen['id'], 'Kies je eerste tegels')
|
||||
screen['update'] = manager.updates.state_for(screen, profiles)
|
||||
return {'csrf': csrf, 'connected': manager.ha.online, 'screens': screens,
|
||||
'pending': manager.pending_profiles(screens, profiles),
|
||||
'updates': manager.updates.summary(screens, profiles)}, entities
|
||||
async def inventory(request):
|
||||
payload, entities = light_payload()
|
||||
@@ -478,10 +492,6 @@ def create_app(manager, development=False):
|
||||
async def update_settings(request):
|
||||
manager.updates.set_auto((await request.json()).get('auto'))
|
||||
return web.json_response(manager.updates.summary())
|
||||
async def download(request):
|
||||
data = await request.json()
|
||||
content = installation_yaml(data)
|
||||
return web.Response(text=content, content_type='text/yaml', headers={'Content-Disposition': f'attachment; filename="{data["name"]}.yaml"'})
|
||||
async def inspector(request):
|
||||
inbox=request.match_info['inbox']
|
||||
if inbox not in {s['id'] for s in manager.inventory()[0]}: raise ValueError('Onbekend scherm.')
|
||||
@@ -493,7 +503,9 @@ def create_app(manager, development=False):
|
||||
'options':t.get('options',{})} for i,t in enumerate(layout['tiles'])]})
|
||||
async def firmware_status(request): return web.json_response(manager.firmware.status())
|
||||
async def firmware_start(request): return web.json_response(manager.firmware.start(await request.json()))
|
||||
async def firmware_create(request): return web.json_response(manager.firmware.create(await request.json()))
|
||||
async def firmware_create(request):
|
||||
# Profile, missing wifi secrets and (with a USB port) the build and flash in one request.
|
||||
return web.json_response(manager.firmware.install(await request.json()))
|
||||
async def shutdown(app):
|
||||
for task in (manager.updates.task, manager.firmware.task):
|
||||
if task and not task.done():
|
||||
@@ -511,7 +523,6 @@ def create_app(manager, development=False):
|
||||
app.router.add_get('/api/inventory', inventory)
|
||||
app.router.add_get('/api/events', events)
|
||||
app.router.add_put('/api/screens/{inbox}', save)
|
||||
app.router.add_post('/api/install', download)
|
||||
app.router.add_static('/static/', static)
|
||||
return app
|
||||
|
||||
|
||||
Reference in New Issue
Block a user