refactor: Unify substream actions into substream_{on,off} (#2497)

## Summary

- Collapse `live_substream_{on,off,select}` into a unified
`substream_{on,off}` pair, symmetric with `call_{start,end}`.
- Rename the `camera` field on the former `live_substream_select` to
`stream` (it always was a stream ID).
- Add optional `camera` field to both new actions for targeting a
non-selected base camera.
- YAML configs are migrated automatically; URL bookmarks must be updated
by hand.

## Migration

### Cycling between camera and substream (toggle button)

Before:
```yaml
tap_action:
  action: custom:advanced-camera-card-action
  advanced_camera_card_action: live_substream_on
```

After:
```yaml
tap_action:
  action: custom:advanced-camera-card-action
  advanced_camera_card_action: substream_on
```

### Selecting a specific substream

Before:
```yaml
tap_action:
  action: custom:advanced-camera-card-action
  advanced_camera_card_action: live_substream_select
  camera: camera.front_door_hd
```

After:
```yaml
tap_action:
  action: custom:advanced-camera-card-action
  advanced_camera_card_action: substream_on
  stream: camera.front_door_hd
```

### Turning the substream off

Before:
```yaml
tap_action:
  action: custom:advanced-camera-card-action
  advanced_camera_card_action: live_substream_off
```

After:
```yaml
tap_action:
  action: custom:advanced-camera-card-action
  advanced_camera_card_action: substream_off
```

### URL querystrings (manual update required)

| Before | After |
| --- | --- |
|
`?advanced-camera-card-action.live_substream_select=camera.front_door_hd`
| `?advanced-camera-card-action.substream_on=camera.front_door_hd` |
This commit is contained in:
Dermot Duffy
2026-06-30 17:45:13 -07:00
committed by dermotduffy
parent 15e335a647
commit f18e4cd4b8
32 changed files with 878 additions and 386 deletions
@@ -71,10 +71,7 @@ export const setRemoteControlEntityFromConfig = (api: CardConfigLoaderAPI) => {
actions: [
cameraPriority === 'entity'
? // Set the currently selected camera to the state of the entity.
createCameraAction(
'camera_select',
`{{ hass.states["${cameraControlEntity}"].state }}`,
)
createCameraAction(`{{ hass.states["${cameraControlEntity}"].state }}`)
: // Set the selected option in the entity to the current camera ID.
createInternalCallbackAction(async (api: CardActionsAPI) => {
const camera = api.getViewManager().getView()?.camera ?? undefined;
@@ -92,10 +89,7 @@ export const setRemoteControlEntityFromConfig = (api: CardConfigLoaderAPI) => {
],
actions: [
// When the entity state changes, updated the selected option.
createCameraAction(
'camera_select',
'{{ advanced_camera_card.trigger.state.to }}',
),
createCameraAction('{{ advanced_camera_card.trigger.state.to }}'),
],
tag: automationTag,
},