|
| 1 | +--- |
| 2 | +applyTo: '**' |
| 3 | +description: Playwright MCP browser automation patterns for Home Assistant |
| 4 | +globs: ['**'] |
| 5 | +alwaysApply: false |
| 6 | +--- |
| 7 | + |
| 8 | +# Playwright MCP Browser Automation |
| 9 | + |
| 10 | +Patterns for browser automation using the Playwright MCP server with Home Assistant. |
| 11 | + |
| 12 | +## Core Concept: Snapshot-Based Interaction |
| 13 | + |
| 14 | +The MCP pattern uses accessibility tree snapshots instead of CSS selectors. |
| 15 | + |
| 16 | +**Workflow:** |
| 17 | + |
| 18 | +1. Capture snapshot with `browser_snapshot()` |
| 19 | +2. Parse element refs from YAML output |
| 20 | +3. Interact using `browser_click(ref=...)` or `browser_type(ref=..., text=...)` |
| 21 | +4. Re-snapshot after each interaction (refs change) |
| 22 | + |
| 23 | +**Snapshot element format:** |
| 24 | + |
| 25 | +```yaml |
| 26 | +button "Submit" [ref=e5355] [cursor=pointer]: |
| 27 | + - generic [ref=e5356]: Submit |
| 28 | +``` |
| 29 | +
|
| 30 | +The `ref` attribute uniquely identifies elements for the current page state. |
| 31 | + |
| 32 | +## Environment Setup |
| 33 | + |
| 34 | +### Starting Home Assistant |
| 35 | + |
| 36 | +```bash |
| 37 | +uv run hass -c config |
| 38 | +``` |
| 39 | + |
| 40 | +Wait 30-60 seconds for startup. UI available at `http://localhost:8123`. |
| 41 | + |
| 42 | +### Resetting to Clean State |
| 43 | + |
| 44 | +```bash |
| 45 | +git clean -fdX config/ |
| 46 | +``` |
| 47 | + |
| 48 | +Removes database, state files, and cached data while preserving tracked sensor packages. |
| 49 | + |
| 50 | +## Element Identification |
| 51 | + |
| 52 | +Identify elements in snapshots by: |
| 53 | + |
| 54 | +| Pattern | Example | |
| 55 | +| ---------------- | -------------------------------------- | |
| 56 | +| Role and name | `button "Submit" [ref=e5355]` | |
| 57 | +| Text content | `generic [ref=e733]: Sigenergy System` | |
| 58 | +| Nested structure | Parent-child hierarchy in YAML | |
| 59 | + |
| 60 | +## UI Component Patterns |
| 61 | + |
| 62 | +### Text Input (textbox) |
| 63 | + |
| 64 | +```yaml |
| 65 | +textbox "Load Name*" [ref=e5331]: |
| 66 | + - text: Load |
| 67 | +``` |
| 68 | + |
| 69 | +``` |
| 70 | +browser_type(element="Load Name textbox", ref="e5331", text="My Load") |
| 71 | +``` |
| 72 | +
|
| 73 | +### Button |
| 74 | +
|
| 75 | +```yaml |
| 76 | +button "Submit" [ref=e5355] [cursor=pointer]: |
| 77 | + - generic: Submit |
| 78 | +``` |
| 79 | + |
| 80 | +``` |
| 81 | +browser_click(element="Submit button", ref="e5355") |
| 82 | +``` |
| 83 | + |
| 84 | +### Combobox Dropdown |
| 85 | + |
| 86 | +**Closed state:** |
| 87 | + |
| 88 | +```yaml |
| 89 | +combobox "Connection*" [ref=e5337]: |
| 90 | + - generic: Switchboard |
| 91 | +``` |
| 92 | +
|
| 93 | +**Pattern:** |
| 94 | +
|
| 95 | +1. Click combobox to open |
| 96 | +2. Re-snapshot to see options |
| 97 | +3. Click option ref |
| 98 | +
|
| 99 | +``` |
| 100 | +browser_click(element="Connection combobox", ref="e5337") |
| 101 | +# snapshot shows: option "Inverter" [ref=e5361] |
| 102 | +browser_click(element="Inverter option", ref="e5361") |
| 103 | +``` |
| 104 | + |
| 105 | +### Entity Picker Dialog |
| 106 | + |
| 107 | +Entity pickers open a dialog with search and results. |
| 108 | + |
| 109 | +**Closed state:** |
| 110 | + |
| 111 | +```yaml |
| 112 | +listitem [ref=e5348]: |
| 113 | + - generic: Select an entity |
| 114 | +``` |
| 115 | +
|
| 116 | +**Pattern:** |
| 117 | +
|
| 118 | +1. Click listitem to open picker dialog |
| 119 | +2. Type in Search textbox to filter |
| 120 | +3. Click matching sensor in results |
| 121 | +
|
| 122 | +``` |
| 123 | +browser_click(element="Entity picker", ref="e5348") |
| 124 | +# dialog opens with: textbox "Search" [ref=e5378] |
| 125 | +browser_type(element="Search textbox", ref="e5378", text="General Price") |
| 126 | +# results show: listitem [ref=e5650]: Home - General Price |
| 127 | +browser_click(element="Home - General Price", ref="e5650") |
| 128 | +``` |
| 129 | + |
| 130 | +**Search behavior:** |
| 131 | + |
| 132 | +- Matches **friendly names**, not entity_ids |
| 133 | +- Use distinctive keywords: "General Price", "consumed", "charging" |
| 134 | +- Partial matches work: "solar" finds all solar sensors |
| 135 | + |
| 136 | +### Multi-Select Entity Picker |
| 137 | + |
| 138 | +For fields accepting multiple sensors, an "Add entity" button appears after first selection. |
| 139 | + |
| 140 | +``` |
| 141 | +# Select first |
| 142 | +browser_click(element="Forecast picker", ref="e5348") |
| 143 | +browser_type(element="Search", ref="e5378", text="East solar") |
| 144 | +browser_click(element="East solar sensor", ref="e5650") |
| 145 | +
|
| 146 | +# Add more |
| 147 | +browser_click(element="Add entity button", ref="e5975") |
| 148 | +browser_type(element="Search", ref="e5378", text="North solar") |
| 149 | +browser_click(element="North solar sensor", ref="e5651") |
| 150 | +``` |
| 151 | + |
| 152 | +### Numeric Input (spinbutton) |
| 153 | + |
| 154 | +```yaml |
| 155 | +spinbutton "Import Limit" [ref=e5400] |
| 156 | +... |
| 157 | +``` |
| 158 | + |
| 159 | +``` |
| 160 | +browser_type(element="Import Limit", ref="e5400", text="55") |
| 161 | +``` |
| 162 | + |
| 163 | +### Alert Dialog |
| 164 | + |
| 165 | +Success dialogs block all other interactions until closed. |
| 166 | + |
| 167 | +```yaml |
| 168 | +alertdialog "Success" [ref=e6060]: |
| 169 | + - paragraph: Created configuration for Load. |
| 170 | + - button "Finish" [ref=e6067] |
| 171 | +``` |
| 172 | +
|
| 173 | +**Always close immediately:** |
| 174 | +
|
| 175 | +``` |
| 176 | +browser_click(element="Finish button", ref="e6067") |
| 177 | +``` |
| 178 | + |
| 179 | +## Critical Rules |
| 180 | + |
| 181 | +### Re-snapshot After Every Interaction |
| 182 | + |
| 183 | +Element refs change after any interaction. |
| 184 | + |
| 185 | +``` |
| 186 | +browser_click(element="Submit", ref="e5355") |
| 187 | +browser_snapshot() # REQUIRED - get new refs |
| 188 | +browser_click(element="Finish", ref="e6067") # New ref from new snapshot |
| 189 | +``` |
| 190 | + |
| 191 | +### Close Dialogs Before Continuing |
| 192 | + |
| 193 | +Unacknowledged success dialogs block all subsequent interactions. |
| 194 | +Look for `alertdialog` in snapshot and click Finish/Close. |
| 195 | + |
| 196 | +### Search by Friendly Name |
| 197 | + |
| 198 | +Entity picker search matches friendly names, not entity_ids. |
| 199 | + |
| 200 | +✅ `"General Price"` → matches "Home - General Price" |
| 201 | +✅ `"max active power"` → matches "Sigen Plant Max Active Power" |
| 202 | +❌ `"sensor.home_general_price"` → no match |
| 203 | + |
| 204 | +### Descriptive Element Names |
| 205 | + |
| 206 | +Always provide meaningful `element` descriptions. |
| 207 | + |
| 208 | +✅ `browser_click(element="Connection combobox", ref="e5337")` |
| 209 | +❌ `browser_click(element="combobox", ref="e5337")` |
| 210 | + |
| 211 | +## Navigation |
| 212 | + |
| 213 | +| Page | URL | |
| 214 | +| -------------------- | -------------------------------------------------------------- | |
| 215 | +| Home | `http://localhost:8123` | |
| 216 | +| Integrations | `http://localhost:8123/config/integrations` | |
| 217 | +| Specific integration | `http://localhost:8123/config/integrations/integration/{name}` | |
| 218 | + |
| 219 | +``` |
| 220 | +browser_navigate(url="http://localhost:8123/config/integrations") |
| 221 | +``` |
| 222 | + |
| 223 | +## Troubleshooting |
| 224 | + |
| 225 | +### No Search Results |
| 226 | + |
| 227 | +- Try broader search terms |
| 228 | +- Search matches friendly names only |
| 229 | +- Check available sensors in config/packages/ |
| 230 | + |
| 231 | +### Dialog Blocking |
| 232 | + |
| 233 | +Take snapshot, find `alertdialog`, click its Finish/Close button. |
| 234 | + |
| 235 | +### Wrong Element Clicked |
| 236 | + |
| 237 | +Using stale ref from old snapshot. Always re-snapshot after interactions. |
| 238 | + |
| 239 | +### Element Not Found |
| 240 | + |
| 241 | +Element may not be visible. Check if scrolling needed or if it's in a closed dropdown/dialog. |
| 242 | + |
| 243 | +## Common Snapshot Patterns |
| 244 | + |
| 245 | +| Component | Pattern | |
| 246 | +| -------------- | ------------------------------------------------------- | |
| 247 | +| Text input | `textbox "Field*" [ref=...]` | |
| 248 | +| Button | `button "Text" [ref=...]` | |
| 249 | +| Dropdown | `combobox "Field*" [ref=...]` | |
| 250 | +| Entity picker | `listitem: Select an entity` | |
| 251 | +| Success dialog | `alertdialog "Success"` | |
| 252 | +| Numeric input | `spinbutton "Field" [ref=...]` | |
| 253 | +| Option in list | `option "Name" [ref=...]` or `listitem [ref=...]: Name` | |
0 commit comments