-
Notifications
You must be signed in to change notification settings - Fork 52
Add Lovelace strategies (dashboard, view, section) for dynamic UI generation #536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: beta
Are you sure you want to change the base?
Conversation
83da353 to
227620f
Compare
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## beta #536 +/- ##
==========================================
+ Coverage 80.86% 81.81% +0.95%
==========================================
Files 19 28 +9
Lines 2341 2563 +222
Branches 0 24 +24
==========================================
+ Hits 1893 2097 +204
- Misses 448 466 +18
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a Lovelace dashboard and view strategy feature to dynamically generate the Keymaster UI, providing an alternative to the existing manual copy/paste YAML workflow. The implementation includes both frontend TypeScript modules and backend Python websocket APIs to support the strategy system.
Key Changes:
- Adds TypeScript/JavaScript frontend strategy modules that register custom Lovelace strategies for dashboard and view generation
- Implements a websocket API that returns view configurations dynamically based on lock names or config entry IDs
- Refactors the existing lovelace generation code to separate view config generation from file writing, enabling reuse for both strategies
- Adds resource registration/cleanup logic to automatically manage the frontend module in Home Assistant's lovelace resources
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | TypeScript configuration for the frontend strategy module |
| tsconfig.build.json | Build-specific TypeScript configuration that excludes test files |
| package.json | Node.js package configuration with build scripts and frontend dependencies |
| rollup.config.js | Rollup bundler configuration to compile TypeScript into a single JavaScript file |
| lovelace_strategy/*.ts | TypeScript source files implementing dashboard and view strategies |
| custom_components/keymaster/www/keymaster.js | Compiled JavaScript output from TypeScript sources |
| custom_components/keymaster/const.py | Adds constants for strategy file paths and URLs |
| custom_components/keymaster/lovelace.py | Refactors to extract view config generation logic for reuse |
| custom_components/keymaster/websocket.py | New websocket API handler for retrieving view configurations |
| custom_components/keymaster/resources.py | Helper functions for registering/unregistering lovelace resources |
| custom_components/keymaster/init.py | Updates to register websocket API, expose strategy files, and manage resources |
| custom_components/keymaster/manifest.json | Adds "http" to after_dependencies |
| tests/conftest.py | Adds mock for hass.http to support static path registration in tests |
| tests/test_lovelace.py | Comprehensive tests for view generation and file operations |
| tests/test_resources.py | Tests for resource registration and cleanup logic |
| tests/test_websocket.py | Tests for websocket API endpoint |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@raman325 this is one of the features that I love about LCM! It's working for the first case, but if I do it in a view I get the following error: I'm adding I've tried it In my views section of an existing dashboard and I tried the entire code block in a fresh dashboard which got me the same error. |
|
I'm going to try this on one of my more complex HA setups with 7 locks to see how it does 😆 |
|
Thx for testing I can fix that bug shortly, holdover from before I changed the configuration approach. Will post and tag you again once it's fixed. I tested the dashboard strategy but forgot to test the view strategy so glad you did and nice catch |
|
Give me a tag when you update that as well, I prefer doing views vs whole dashboards for keymaster. |
- Dashboard strategy uses config_entry_id (efficient, no lookup) - Manual view config uses lock_name (user-friendly) - View strategy validates exactly one identifier is provided - Views sorted alphabetically by lock name 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
@firstof9 fixed |
- Set up vitest for TypeScript testing - Add view-strategy tests covering: - Validation of exactly one identifier (config_entry_id XOR lock_name) - Error handling when neither or both provided - WebSocket call with correct identifier - Error view on failed WebSocket calls - Starting view when HA not running - Add dashboard-strategy tests covering: - Alphabetical sorting of views by lock name - Single view placeholder hack - Error handling for failed individual lock fetch - Parallel fetching of view configs - Using config_entry_id for efficiency - Add GitHub workflow for vitest (only runs on lovelace_strategy changes) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update vitest workflow to match lock_code_manager pattern - Add branch filtering (beta, main) - Add codecov integration for TypeScript coverage - Add yarn.yaml workflow for lint and build validation - Runs lint:fix and fails if repo becomes dirty - Runs build and fails if generated files change - Only triggers on TypeScript/JavaScript file changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add codecov.yml with flag management for both languages - Update pytest workflow to use python flag - Enable carryforward for flags (maintains coverage when only one language changes) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Tab view strategy isn't currently generating a view name so it's getting set as |
Only run Python tests when Python-related files change: - **.py files - custom_components/** and tests/** - pyproject.toml, requirements*.txt - The workflow file itself Scheduled runs still execute regardless of paths. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Configure paths for each flag so status checks only appear when relevant files change: - Python checks: custom_components/, tests/ - TypeScript checks: lovelace_strategy/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users can now customize the view tab title by adding a `title` parameter
to the view strategy config:
```yaml
views:
- strategy:
type: custom:keymaster
lock_name: Front Door
title: My Custom Title
```
This addresses the "Unnamed View" issue where HA's UI editor shows a
placeholder before the strategy generates content. Users can now set
their preferred title directly in the strategy config.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for standard Lovelace view parameters in the strategy config: - icon: tab icon (e.g., mdi:door) - path: URL path for the view - theme: theme override - title: tab title (moved from previous commit) - visible: visibility conditions These are exposed at the strategy config level for convenience since strategy-generated views cannot be edited through the UI. Also: - Add slugify utility for consistent path generation - Dashboard strategy ensures title fallback from config entry - View strategy sets default path from slugified title if backend doesn't provide one - Reuse types from LovelaceViewConfig via Pick<> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add .eslintrc.cjs with TypeScript ESLint configuration - Fix lint script to point to lovelace_strategy/ instead of ts/ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The backend's websocket response always includes the title derived from CONF_LOCK_NAME in config entry data. Using configEntry.title as a fallback was both unnecessary and potentially incorrect since that value is set once at setup and may become stale. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backend always provides title and never provides path, so remove unnecessary conditional checks. Path is always generated from title. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Dashboard now returns view strategy configs instead of resolved views. HA calls KeymasterViewStrategy for each view, centralizing all view generation logic (path, overrides, error handling) in one place. - Dashboard only fetches config entries (single WS call) - Returns strategy configs with title for tab display - View strategy handles WS call, path generation, and overrides 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
configEntry.title is set once at setup and may become stale. configEntry.data.lock_name is the current authoritative value. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Title now explicitly defaults to backend's response, with strategy config able to override. This ensures the backend's authoritative title is used while still allowing user overrides. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Path generation now:
- Default (backend title): keymaster-{slugified-title}
- Custom title override: {slugified-custom-title}
Also adds strategy property to LovelaceViewConfig type stub.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Works fine in masonry view however. |
|
@firstof9 Sections are within a view, what do you expect the frontend logic to generate at that level? We could do the exact same thing we do at the view level (as in all the code slot cards for the lock), I just don't know if it would look good |
|
I wasn't sure if there was an easy way to just clone the entities from the masonry view into a sections view. |
- Convert lovelace.py functions from async to sync with @callback - Add ws_get_view_metadata and ws_get_section_config websocket handlers - Update tests for new sync API and websocket endpoints - Add section-strategy.ts for section-level generation - Update TypeScript types and strategy utilities Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
OK so now we do sections, and the section strategy requires the code slot number since that emulates what we do in the view. So basically @firstof9 , what you tried the first time will now work as long as you provide a slot num. Everything looks good to me so I am marking this as ready for review shortly. Also worth noting that I checked the lovelace before and after this PR and they are the exact same. I have a refactor coming after this one to clean up the lovelace code and get rid of some extra parts of the payload that are redundant but one step at a time |
Clarify that the file-writing function is async while the config generation functions are sync. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Here's the documentation I will push to the wiki with this PR so you can test all of the functionality: Lovelace ViewKeymaster provides two ways to add a Lovelace dashboard for managing your locks:
Option 1: Lovelace Strategy (Recommended)The Lovelace Strategy dynamically generates your dashboard and keeps it in sync with your lock configuration. No manual updates needed when you add or remove locks. PrerequisitesInstall the Keymaster frontend component. This is typically done automatically when you install Keymaster, but you can verify it's loaded by checking your browser's developer console for the Dashboard Strategy (Easiest)Create a dedicated Keymaster dashboard that automatically shows all your locks:
strategy:
type: custom:keymaster
The dashboard will automatically create a tab for each configured lock. View Strategy (Single Lock)Add a Keymaster view to an existing dashboard:
views:
# ... your existing views ...
- strategy:
type: custom:keymaster
lock_name: Front DoorConfiguration Options:
Example with overrides: - strategy:
type: custom:keymaster
lock_name: Front Door
title: Front Door Codes
icon: mdi:doorSection Strategy (Advanced)For advanced users who want to embed individual code slot sections into custom views: sections:
- strategy:
type: custom:keymaster
lock_name: Front Door
slot_num: 1Configuration Options:
This generates the section for a single code slot, allowing you to compose custom layouts. Option 2: Manual YAML (Legacy)If you prefer manual control or the strategy doesn't work for your setup, you can copy the generated YAML. Copy the Lovelace YAMLKeymaster generates a lovelace YAML file for each lock. Find it at:
Required Frontend ComponentsFor the manual YAML to work, install these frontend cards via HACS:
|
Section strategy now accepts lock_name as an alternative to config_entry_id, matching the view strategy pattern. View strategy passes through whichever identifier it received. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This reverts commit fb53a96.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update _generate_lock_badges to accept lock_entity and door_sensor params - Update _get_entity_id to return original value when registry lookup fails - Remove _add_lock_and_door_to_badges (no longer needed) - Fix test mock to properly simulate real registry behavior Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
here's the before and after JSON for the view for this PR (on beta branch and with this PR), they both match 1 for 1 |

Summary
Adds Lovelace dashboard, view, and section strategies for Keymaster to dynamically generate the UI, replacing the current copy/paste YAML workflow.
Proposed change
Lovelace strategies allow custom frontend modules to auto-generate dashboard views. This PR extracts lovelace generation code and adds WebSocket commands that return configs to the frontend. A TypeScript module registers the
keymasterstrategy at dashboard, view, and section levels.Key features:
lock_name- User-friendly option for manual configurationconfig_entry_id- Internal use by dashboard/view strategies (efficient, no lookup)title,icon,path,theme,visiblekeymaster-to avoid conflictsWebSocket APIs:
keymaster/get_view_metadata- Returns lock metadata, badges, slot infokeymaster/get_section_config- Returns single code slot section configArchitecture changes:
lovelace.pyto use sync functions with@callbackdecoratorgenerate_view_config,generate_badges_config,generate_section_configas public APIBenefits:
Usage
Full Dashboard (all locks)
Single Lock View (by lock name)
With view overrides
Section strategy (advanced)
Type of change
Additional information
🤖 Generated with Claude Code