ha-mcp-dev 6.3.1.dev137__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ha_mcp/__init__.py +51 -0
- ha_mcp/__main__.py +753 -0
- ha_mcp/_pypi_marker +0 -0
- ha_mcp/auth/__init__.py +10 -0
- ha_mcp/auth/consent_form.py +501 -0
- ha_mcp/auth/provider.py +786 -0
- ha_mcp/client/__init__.py +10 -0
- ha_mcp/client/rest_client.py +924 -0
- ha_mcp/client/websocket_client.py +656 -0
- ha_mcp/client/websocket_listener.py +340 -0
- ha_mcp/config.py +175 -0
- ha_mcp/errors.py +399 -0
- ha_mcp/py.typed +0 -0
- ha_mcp/resources/card_types.json +48 -0
- ha_mcp/resources/dashboard_guide.md +573 -0
- ha_mcp/server.py +189 -0
- ha_mcp/smoke_test.py +108 -0
- ha_mcp/tools/__init__.py +11 -0
- ha_mcp/tools/backup.py +457 -0
- ha_mcp/tools/device_control.py +687 -0
- ha_mcp/tools/enhanced.py +191 -0
- ha_mcp/tools/helpers.py +184 -0
- ha_mcp/tools/registry.py +199 -0
- ha_mcp/tools/smart_search.py +797 -0
- ha_mcp/tools/tools_addons.py +343 -0
- ha_mcp/tools/tools_areas.py +478 -0
- ha_mcp/tools/tools_blueprints.py +279 -0
- ha_mcp/tools/tools_bug_report.py +570 -0
- ha_mcp/tools/tools_calendar.py +391 -0
- ha_mcp/tools/tools_camera.py +149 -0
- ha_mcp/tools/tools_config_automations.py +508 -0
- ha_mcp/tools/tools_config_dashboards.py +1502 -0
- ha_mcp/tools/tools_config_entry_flow.py +223 -0
- ha_mcp/tools/tools_config_helpers.py +925 -0
- ha_mcp/tools/tools_config_info.py +258 -0
- ha_mcp/tools/tools_config_scripts.py +267 -0
- ha_mcp/tools/tools_entities.py +76 -0
- ha_mcp/tools/tools_filesystem.py +589 -0
- ha_mcp/tools/tools_groups.py +306 -0
- ha_mcp/tools/tools_hacs.py +787 -0
- ha_mcp/tools/tools_history.py +714 -0
- ha_mcp/tools/tools_integrations.py +297 -0
- ha_mcp/tools/tools_labels.py +713 -0
- ha_mcp/tools/tools_mcp_component.py +305 -0
- ha_mcp/tools/tools_registry.py +1115 -0
- ha_mcp/tools/tools_resources.py +622 -0
- ha_mcp/tools/tools_search.py +573 -0
- ha_mcp/tools/tools_service.py +211 -0
- ha_mcp/tools/tools_services.py +352 -0
- ha_mcp/tools/tools_system.py +363 -0
- ha_mcp/tools/tools_todo.py +530 -0
- ha_mcp/tools/tools_traces.py +496 -0
- ha_mcp/tools/tools_updates.py +476 -0
- ha_mcp/tools/tools_utility.py +519 -0
- ha_mcp/tools/tools_voice_assistant.py +345 -0
- ha_mcp/tools/tools_zones.py +387 -0
- ha_mcp/tools/util_helpers.py +199 -0
- ha_mcp/utils/__init__.py +30 -0
- ha_mcp/utils/domain_handlers.py +380 -0
- ha_mcp/utils/fuzzy_search.py +339 -0
- ha_mcp/utils/operation_manager.py +442 -0
- ha_mcp/utils/usage_logger.py +290 -0
- ha_mcp_dev-6.3.1.dev137.dist-info/METADATA +229 -0
- ha_mcp_dev-6.3.1.dev137.dist-info/RECORD +71 -0
- ha_mcp_dev-6.3.1.dev137.dist-info/WHEEL +5 -0
- ha_mcp_dev-6.3.1.dev137.dist-info/entry_points.txt +7 -0
- ha_mcp_dev-6.3.1.dev137.dist-info/licenses/LICENSE +21 -0
- ha_mcp_dev-6.3.1.dev137.dist-info/top_level.txt +2 -0
- tests/__init__.py +1 -0
- tests/test_constants.py +15 -0
- tests/test_env_manager.py +336 -0
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
# Home Assistant Dashboard Guide
|
|
2
|
+
|
|
3
|
+
Complete guide for designing Home Assistant dashboards: structure, built-in cards, custom cards, CSS styling, and HACS integration.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Part 1: Dashboard Structure
|
|
8
|
+
|
|
9
|
+
### Modern Dashboard Best Practices
|
|
10
|
+
|
|
11
|
+
**Modern Home Assistant dashboards** (2024+) use:
|
|
12
|
+
- **Sections view type** (default) with grid-based layouts
|
|
13
|
+
- **Multiple views** with navigation and deep linking
|
|
14
|
+
- **Grid cards** for organizing content into columns
|
|
15
|
+
- **Tile cards** with integrated features for quick controls
|
|
16
|
+
- **Navigation paths** between views for hierarchical organization
|
|
17
|
+
|
|
18
|
+
**Legacy patterns to avoid:**
|
|
19
|
+
- Single-view dashboards with all cards in one long scroll
|
|
20
|
+
- Excessive use of vertical-stack/horizontal-stack instead of grid
|
|
21
|
+
- Masonry view (auto-layout) - use sections for precise control
|
|
22
|
+
- Putting all entities in generic "entities" cards
|
|
23
|
+
|
|
24
|
+
### Dashboard Structure
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"title": "My Home",
|
|
29
|
+
"icon": "mdi:home",
|
|
30
|
+
"config": {
|
|
31
|
+
"views": [
|
|
32
|
+
{
|
|
33
|
+
"title": "Overview",
|
|
34
|
+
"path": "home",
|
|
35
|
+
"type": "sections",
|
|
36
|
+
"max_columns": 4,
|
|
37
|
+
"sections": [
|
|
38
|
+
{"title": "Climate", "cards": [...]},
|
|
39
|
+
{"title": "Lights", "cards": [...]}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"title": "Energy",
|
|
44
|
+
"path": "energy",
|
|
45
|
+
"type": "sections",
|
|
46
|
+
"icon": "mdi:lightning-bolt",
|
|
47
|
+
"sections": [...]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Critical Validation Rules
|
|
55
|
+
|
|
56
|
+
**url_path MUST contain hyphen (-)**
|
|
57
|
+
- Valid: "my-dashboard"
|
|
58
|
+
- Invalid: "mydashboard" → REJECTED
|
|
59
|
+
|
|
60
|
+
**Dashboard ID vs url_path:**
|
|
61
|
+
- `dashboard_id`: Internal identifier (returned on create, used for update/delete)
|
|
62
|
+
- `url_path`: URL identifier (user-facing, used in dashboard URLs)
|
|
63
|
+
|
|
64
|
+
### View Types
|
|
65
|
+
|
|
66
|
+
| Type | Use For |
|
|
67
|
+
|------|---------|
|
|
68
|
+
| `sections` | Most dashboards (RECOMMENDED) - grid-based, responsive |
|
|
69
|
+
| `panel` | Full-screen single cards (maps, cameras, iframes) |
|
|
70
|
+
| `sidebar` | Two-column layouts with primary/secondary content |
|
|
71
|
+
| `masonry` | Legacy - auto-arranges cards, less control |
|
|
72
|
+
|
|
73
|
+
### View Configuration
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"title": "View Name",
|
|
78
|
+
"path": "unique-path",
|
|
79
|
+
"type": "sections",
|
|
80
|
+
"icon": "mdi:icon",
|
|
81
|
+
"theme": "theme-name",
|
|
82
|
+
"badges": ["sensor.entity_id"],
|
|
83
|
+
"max_columns": 4,
|
|
84
|
+
"sections": [...],
|
|
85
|
+
"subview": false,
|
|
86
|
+
"visible": true,
|
|
87
|
+
"background": {"image": "url(/local/background.jpg)", "opacity": 0.3}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Part 2: Built-in Cards
|
|
94
|
+
|
|
95
|
+
### Card Categories
|
|
96
|
+
|
|
97
|
+
| Category | Cards |
|
|
98
|
+
|----------|-------|
|
|
99
|
+
| **Modern Primary** | tile, area, button, grid |
|
|
100
|
+
| **Container** | vertical-stack, horizontal-stack, grid |
|
|
101
|
+
| **Logic** | conditional, entity-filter |
|
|
102
|
+
| **Display** | sensor, history-graph, statistics-graph, gauge, energy, calendar |
|
|
103
|
+
| **Legacy Control** | entity, entities, light, thermostat (use tile instead) |
|
|
104
|
+
|
|
105
|
+
**Recommendation:** Use `tile` card for most entities.
|
|
106
|
+
|
|
107
|
+
### Tile Card (Modern Entity Control)
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"type": "tile",
|
|
112
|
+
"entity": "climate.bedroom",
|
|
113
|
+
"name": "Master Bedroom",
|
|
114
|
+
"icon": "mdi:thermostat",
|
|
115
|
+
"features": [
|
|
116
|
+
{"type": "target-temperature"},
|
|
117
|
+
{"type": "climate-hvac-modes", "style": "dropdown"}
|
|
118
|
+
],
|
|
119
|
+
"tap_action": {"action": "more-info"}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Grid Card (Layout Tool)
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"type": "grid",
|
|
128
|
+
"columns": 3,
|
|
129
|
+
"square": false,
|
|
130
|
+
"cards": [
|
|
131
|
+
{"type": "tile", "entity": "light.kitchen"},
|
|
132
|
+
{"type": "tile", "entity": "light.dining"},
|
|
133
|
+
{"type": "tile", "entity": "light.hallway"}
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Features (Quick Controls)
|
|
139
|
+
|
|
140
|
+
Available on: tile, area, humidifier, thermostat cards
|
|
141
|
+
|
|
142
|
+
**Climate:** climate-hvac-modes, climate-fan-modes, climate-preset-modes, target-temperature
|
|
143
|
+
**Light:** light-brightness, light-color-temp
|
|
144
|
+
**Cover:** cover-open-close, cover-position, cover-tilt
|
|
145
|
+
**Fan:** fan-speed, fan-direction, fan-oscillate
|
|
146
|
+
**Media:** media-player-playback, media-player-volume-slider
|
|
147
|
+
**Other:** toggle, button, alarm-modes, lock-commands, numeric-input
|
|
148
|
+
|
|
149
|
+
Feature `style` options: "dropdown" or "icons"
|
|
150
|
+
|
|
151
|
+
### Actions
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"tap_action": {"action": "toggle"},
|
|
156
|
+
"hold_action": {"action": "more-info"},
|
|
157
|
+
"double_tap_action": {"action": "navigate", "navigation_path": "/lovelace/lights"}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Action types: toggle, call-service, more-info, navigate, url, none
|
|
162
|
+
|
|
163
|
+
### Visibility Conditions
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"visibility": [
|
|
168
|
+
{"condition": "user", "users": ["user_id_hex"]},
|
|
169
|
+
{"condition": "state", "entity": "sun.sun", "state": "above_horizon"}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Part 3: Custom Cards (JavaScript Modules)
|
|
177
|
+
|
|
178
|
+
For functionality beyond built-in cards, create custom cards using JavaScript modules.
|
|
179
|
+
|
|
180
|
+
### When to Use Custom Cards
|
|
181
|
+
|
|
182
|
+
- Built-in cards don't support your visualization
|
|
183
|
+
- Need complex interactive behavior
|
|
184
|
+
- Want to integrate external libraries
|
|
185
|
+
- Creating reusable components
|
|
186
|
+
|
|
187
|
+
### Minimal Custom Card
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
class MySimpleCard extends HTMLElement {
|
|
191
|
+
setConfig(config) {
|
|
192
|
+
if (!config.entity) {
|
|
193
|
+
throw new Error("Please define an entity");
|
|
194
|
+
}
|
|
195
|
+
this.config = config;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
set hass(hass) {
|
|
199
|
+
if (!this.content) {
|
|
200
|
+
this.innerHTML = `
|
|
201
|
+
<ha-card header="${this.config.title || 'My Card'}">
|
|
202
|
+
<div class="card-content"></div>
|
|
203
|
+
</ha-card>
|
|
204
|
+
`;
|
|
205
|
+
this.content = this.querySelector(".card-content");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const state = hass.states[this.config.entity];
|
|
209
|
+
this.content.innerHTML = state
|
|
210
|
+
? `State: ${state.state}`
|
|
211
|
+
: "Entity not found";
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
getCardSize() {
|
|
215
|
+
return 2;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
customElements.define("my-simple-card", MySimpleCard);
|
|
220
|
+
|
|
221
|
+
window.customCards = window.customCards || [];
|
|
222
|
+
window.customCards.push({
|
|
223
|
+
type: "my-simple-card",
|
|
224
|
+
name: "My Simple Card",
|
|
225
|
+
description: "A simple custom card"
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Custom Card with Shadow DOM Styling
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
class StyledCard extends HTMLElement {
|
|
233
|
+
setConfig(config) {
|
|
234
|
+
this.config = config;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
set hass(hass) {
|
|
238
|
+
if (!this.shadowRoot) {
|
|
239
|
+
this.attachShadow({ mode: "open" });
|
|
240
|
+
this.shadowRoot.innerHTML = `
|
|
241
|
+
<style>
|
|
242
|
+
:host { display: block; }
|
|
243
|
+
.card {
|
|
244
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
245
|
+
border-radius: 16px;
|
|
246
|
+
padding: 20px;
|
|
247
|
+
color: white;
|
|
248
|
+
}
|
|
249
|
+
.value { font-size: 2em; font-weight: bold; }
|
|
250
|
+
</style>
|
|
251
|
+
<div class="card">
|
|
252
|
+
<div class="label"></div>
|
|
253
|
+
<div class="value"></div>
|
|
254
|
+
</div>
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const state = hass.states[this.config.entity];
|
|
259
|
+
if (state) {
|
|
260
|
+
this.shadowRoot.querySelector(".label").textContent =
|
|
261
|
+
state.attributes.friendly_name || this.config.entity;
|
|
262
|
+
this.shadowRoot.querySelector(".value").textContent =
|
|
263
|
+
`${state.state} ${state.attributes.unit_of_measurement || ""}`;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
getCardSize() {
|
|
268
|
+
return 2;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
customElements.define("styled-card", StyledCard);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Using Custom Cards
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
type: custom:my-simple-card
|
|
279
|
+
entity: sensor.temperature
|
|
280
|
+
title: Temperature
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Hosting Custom Cards
|
|
284
|
+
|
|
285
|
+
Use `ha_create_dashboard_resource` to convert inline code to a hosted URL:
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
result = ha_create_dashboard_resource(
|
|
289
|
+
content=card_code,
|
|
290
|
+
resource_type="module"
|
|
291
|
+
)
|
|
292
|
+
# Returns: {"url": "https://...", "size": ...}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Then register the URL as a dashboard resource.
|
|
296
|
+
|
|
297
|
+
**Size limits:** ~24KB source code (32KB encoded URL)
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Part 4: CSS Styling
|
|
302
|
+
|
|
303
|
+
### CSS Resource for Theme Overrides
|
|
304
|
+
|
|
305
|
+
```css
|
|
306
|
+
:root {
|
|
307
|
+
--primary-color: #03a9f4;
|
|
308
|
+
--accent-color: #ff5722;
|
|
309
|
+
--ha-card-background: rgba(26, 26, 46, 0.9);
|
|
310
|
+
--ha-card-border-radius: 16px;
|
|
311
|
+
--ha-card-box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Card-Specific Styling
|
|
316
|
+
|
|
317
|
+
```css
|
|
318
|
+
/* Style all entity cards */
|
|
319
|
+
hui-entities-card ha-card {
|
|
320
|
+
background: linear-gradient(180deg, #1a1a2e 0%, #16213e 100%);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* Style specific card by data attribute */
|
|
324
|
+
ha-card[data-card="weather"] {
|
|
325
|
+
border: 2px solid var(--primary-color);
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Using CSS Resources
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
result = ha_create_dashboard_resource(
|
|
333
|
+
content=css_code,
|
|
334
|
+
resource_type="css"
|
|
335
|
+
)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Card-mod Integration
|
|
339
|
+
|
|
340
|
+
For per-card styling, use the card-mod custom component from HACS:
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
type: entities
|
|
344
|
+
card_mod:
|
|
345
|
+
style: |
|
|
346
|
+
ha-card {
|
|
347
|
+
--ha-card-background: teal;
|
|
348
|
+
color: var(--primary-color);
|
|
349
|
+
}
|
|
350
|
+
entities:
|
|
351
|
+
- light.bed_light
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Part 5: HACS Integration
|
|
357
|
+
|
|
358
|
+
HACS (Home Assistant Community Store) provides 700+ custom cards.
|
|
359
|
+
|
|
360
|
+
### When to Use HACS vs Inline Resources
|
|
361
|
+
|
|
362
|
+
| Use Case | Solution |
|
|
363
|
+
|----------|----------|
|
|
364
|
+
| Popular community card | HACS - `ha_hacs_search` + `ha_hacs_download` |
|
|
365
|
+
| Small custom styling | Inline CSS - `ha_create_dashboard_resource` |
|
|
366
|
+
| One-off custom card | Inline module - `ha_create_dashboard_resource` |
|
|
367
|
+
| Large/complex card | HACS or filesystem (`/config/www/`) |
|
|
368
|
+
|
|
369
|
+
### Finding Cards
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
# Search for cards
|
|
373
|
+
result = ha_hacs_search(query="mushroom", category="lovelace")
|
|
374
|
+
|
|
375
|
+
# Get repository details
|
|
376
|
+
result = ha_hacs_repository_info(repository_id="piitaya/lovelace-mushroom")
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Installing Cards
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
# Install from HACS (requires user confirmation)
|
|
383
|
+
result = ha_hacs_download(repository_id="piitaya/lovelace-mushroom")
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Note:** HACS install operations have `destructiveHint: True` - clients will ask for user confirmation.
|
|
387
|
+
|
|
388
|
+
### Popular HACS Cards
|
|
389
|
+
|
|
390
|
+
- **mushroom** - Modern, clean card collection
|
|
391
|
+
- **button-card** - Highly customizable buttons
|
|
392
|
+
- **mini-graph-card** - Compact graphs
|
|
393
|
+
- **card-mod** - CSS styling for any card
|
|
394
|
+
- **layout-card** - Advanced layout control
|
|
395
|
+
- **apexcharts-card** - Professional charts
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Part 6: Complete Examples
|
|
400
|
+
|
|
401
|
+
### Multi-View Dashboard
|
|
402
|
+
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"title": "Modern Home",
|
|
406
|
+
"icon": "mdi:home",
|
|
407
|
+
"config": {
|
|
408
|
+
"views": [
|
|
409
|
+
{
|
|
410
|
+
"title": "Overview",
|
|
411
|
+
"path": "home",
|
|
412
|
+
"type": "sections",
|
|
413
|
+
"max_columns": 4,
|
|
414
|
+
"badges": ["person.john", "person.jane"],
|
|
415
|
+
"sections": [
|
|
416
|
+
{
|
|
417
|
+
"title": "Quick Actions",
|
|
418
|
+
"cards": [{
|
|
419
|
+
"type": "grid",
|
|
420
|
+
"columns": 4,
|
|
421
|
+
"square": false,
|
|
422
|
+
"cards": [
|
|
423
|
+
{"type": "button", "name": "Lights", "icon": "mdi:lightbulb", "tap_action": {"action": "navigate", "navigation_path": "/lovelace/lights"}},
|
|
424
|
+
{"type": "button", "name": "Climate", "icon": "mdi:thermostat", "tap_action": {"action": "navigate", "navigation_path": "/lovelace/climate"}},
|
|
425
|
+
{"type": "button", "name": "Security", "icon": "mdi:shield-home", "tap_action": {"action": "navigate", "navigation_path": "/lovelace/security"}},
|
|
426
|
+
{"type": "button", "name": "Energy", "icon": "mdi:lightning-bolt", "tap_action": {"action": "navigate", "navigation_path": "/lovelace/energy"}}
|
|
427
|
+
]
|
|
428
|
+
}]
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
"title": "Favorites",
|
|
432
|
+
"cards": [{
|
|
433
|
+
"type": "grid",
|
|
434
|
+
"columns": 3,
|
|
435
|
+
"square": false,
|
|
436
|
+
"cards": [
|
|
437
|
+
{"type": "tile", "entity": "light.living_room", "features": [{"type": "light-brightness"}]},
|
|
438
|
+
{"type": "tile", "entity": "climate.bedroom", "features": [{"type": "target-temperature"}]},
|
|
439
|
+
{"type": "tile", "entity": "lock.front_door"}
|
|
440
|
+
]
|
|
441
|
+
}]
|
|
442
|
+
}
|
|
443
|
+
]
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"title": "Lights",
|
|
447
|
+
"path": "lights",
|
|
448
|
+
"type": "sections",
|
|
449
|
+
"icon": "mdi:lightbulb",
|
|
450
|
+
"max_columns": 3,
|
|
451
|
+
"sections": [
|
|
452
|
+
{
|
|
453
|
+
"title": "Living Room",
|
|
454
|
+
"cards": [{
|
|
455
|
+
"type": "grid",
|
|
456
|
+
"columns": 3,
|
|
457
|
+
"cards": [
|
|
458
|
+
{"type": "tile", "entity": "light.overhead", "features": [{"type": "light-brightness"}]},
|
|
459
|
+
{"type": "tile", "entity": "light.lamp", "features": [{"type": "light-brightness"}]},
|
|
460
|
+
{"type": "tile", "entity": "light.accent", "features": [{"type": "light-color-temp"}]}
|
|
461
|
+
]
|
|
462
|
+
}]
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Custom Card Workflow
|
|
472
|
+
|
|
473
|
+
```python
|
|
474
|
+
# 1. Create the card code
|
|
475
|
+
card_code = '''
|
|
476
|
+
class QuickStatusCard extends HTMLElement {
|
|
477
|
+
setConfig(config) { this.config = config; }
|
|
478
|
+
set hass(hass) {
|
|
479
|
+
const state = hass.states[this.config.entity];
|
|
480
|
+
this.innerHTML = `<ha-card>
|
|
481
|
+
<div style="padding:16px;text-align:center;">
|
|
482
|
+
<div style="font-size:2em;">${state?.state || "?"}</div>
|
|
483
|
+
<div>${this.config.name || this.config.entity}</div>
|
|
484
|
+
</div>
|
|
485
|
+
</ha-card>`;
|
|
486
|
+
}
|
|
487
|
+
getCardSize() { return 2; }
|
|
488
|
+
}
|
|
489
|
+
customElements.define("quick-status-card", QuickStatusCard);
|
|
490
|
+
'''
|
|
491
|
+
|
|
492
|
+
# 2. Get hosted URL
|
|
493
|
+
result = ha_create_dashboard_resource(content=card_code, resource_type="module")
|
|
494
|
+
|
|
495
|
+
# 3. Register as dashboard resource
|
|
496
|
+
|
|
497
|
+
# 4. Use in dashboard
|
|
498
|
+
card_config = {
|
|
499
|
+
"type": "custom:quick-status-card",
|
|
500
|
+
"entity": "sensor.temperature",
|
|
501
|
+
"name": "Living Room"
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Common Pitfalls
|
|
508
|
+
|
|
509
|
+
| Issue | Solution |
|
|
510
|
+
|-------|----------|
|
|
511
|
+
| url_path rejected | Add hyphen: "my-dashboard" not "mydashboard" |
|
|
512
|
+
| Entity not found | Use full ID: "light.living_room" not "living_room" |
|
|
513
|
+
| Features not working | Match feature type to entity domain |
|
|
514
|
+
| Custom card not loading | Check resource type is "module", verify URL |
|
|
515
|
+
| Card too large for inline | Use HACS or filesystem instead |
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Part 7: Advanced Workflow - Visual Iteration
|
|
520
|
+
|
|
521
|
+
For iterative dashboard design with visual feedback, add a browser automation MCP server:
|
|
522
|
+
|
|
523
|
+
### Recommended MCP Servers
|
|
524
|
+
|
|
525
|
+
- **Playwright MCP** (`@anthropic/mcp-playwright`) - Take screenshots, interact with pages
|
|
526
|
+
- **Puppeteer MCP** - Similar browser automation capabilities
|
|
527
|
+
- **Browser DevTools MCP** - Inspect elements, debug layouts
|
|
528
|
+
|
|
529
|
+
### Visual Iteration Workflow
|
|
530
|
+
|
|
531
|
+
```
|
|
532
|
+
1. Create/update dashboard with ha_update_dashboard_view()
|
|
533
|
+
2. Navigate browser to dashboard URL (e.g., http://homeassistant.local:8123/lovelace/my-dashboard)
|
|
534
|
+
3. Take screenshot to see current layout
|
|
535
|
+
4. Analyze screenshot for issues (spacing, alignment, colors)
|
|
536
|
+
5. Adjust configuration and repeat
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Example with Playwright MCP
|
|
540
|
+
|
|
541
|
+
```python
|
|
542
|
+
# Get base URL from system overview
|
|
543
|
+
overview = ha_get_overview(detail_level="minimal")
|
|
544
|
+
base_url = overview["system_info"]["base_url"] # e.g., "http://homeassistant.local:8123"
|
|
545
|
+
|
|
546
|
+
# After updating dashboard
|
|
547
|
+
ha_update_dashboard_view(dashboard_id="...", view_index=0, config={...})
|
|
548
|
+
|
|
549
|
+
# Use Playwright MCP to capture result
|
|
550
|
+
browser_navigate(f"{base_url}/lovelace/my-dashboard")
|
|
551
|
+
browser_screenshot() # Returns image for visual analysis
|
|
552
|
+
|
|
553
|
+
# Analyze and iterate based on what you see
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Benefits
|
|
557
|
+
|
|
558
|
+
- See actual rendered output, not just JSON config
|
|
559
|
+
- Catch visual issues (card overlap, responsive breakpoints)
|
|
560
|
+
- Verify custom card styling
|
|
561
|
+
- Test on different viewport sizes
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## Related Tools
|
|
566
|
+
|
|
567
|
+
- `ha_get_dashboard_guide` - This guide
|
|
568
|
+
- `ha_get_overview` - Get system info including base_url for browser navigation
|
|
569
|
+
- `ha_config_set_inline_dashboard_resource` - Host inline JS/CSS
|
|
570
|
+
- `ha_config_set_dashboard_resource` - Register external resources
|
|
571
|
+
- `ha_update_dashboard_view` - Update dashboard views
|
|
572
|
+
- `ha_hacs_search` - Find HACS cards
|
|
573
|
+
- `ha_hacs_download` - Install HACS cards
|