Files
advanced-camera-card/docs/configuration/elements/custom/README.md
T
Dermot DuffyandClaude Opus 4.8 b701366762 feat: Align automations with Home Assistant triggers and conditions (#2527)
Split automations into HA-style `triggers`, ongoing `conditions`, and
`actions`, with compatibility migrations for existing Advanced Camera
Card configs.

## Summary

At a glance (details below):

- **Added** `triggers:` -- a required, HA-shaped block: stock `state` /
`numeric_state` / `template` plus card-specific triggers (`camera`,
`view`, `fullscreen`, ...).
- **Added** the HA-native `if` / `then` / `else` action.
- **Removed** `actions_not` (replaced by `if` / `then` / `else`).
- **Removed** the ambient `advanced_camera_card` template namespace (use
`acc` instead).
- **Changed** the trigger template surface to a top-level `trigger.*`
variable (as in HA); the nested `acc.trigger.*` paths are removed.
- **Changed** `conditions:` to ongoing gates only -- they no longer wake
an automation, and change-only forms (`config`, valueless `camera` /
`view` / `state`) become triggers, not conditions.
- **Changed** action templates to render per step, so a later action
sees state an earlier one changed.
- **Compatibility:** HA-shaped YAML is accepted (singular keys,
single-or-list, `and` / `or` / `not` shorthand, `entity` / `entity_id`).
- **Migration:** existing configs upgrade automatically; anything that
cannot be converted faithfully is recorded under `__UPGRADE_FAILURE__`
for manual fixup.

## Breaking Changes

### 1. Automations now require triggers

Before this PR, `automations[].conditions` served two roles:

- They decided whether the automation should run.
- They also acted as the thing that woke the automation up.

After this PR:

- `triggers` wake the automation.
- `conditions` only gate it at the instant a trigger fires.

Most existing automations are migrated automatically from `conditions:`
to `triggers:`.

### 2. `actions_not` is retired

Legacy `actions_not` is replaced by an HA-style `if` action with `then`
/ `else`.

Faithful conversions are automatic. Cases that cannot be faithfully
converted are recorded under `__UPGRADE_FAILURE__.automations` and must
be migrated manually.

### 3. Template surface aligned with Home Assistant

Two related template changes, both auto-migrated:

- **Top-level `trigger.*`.** Automation actions now receive a top-level
`trigger` template variable, like Home Assistant. Legacy nested paths
such as `acc.trigger.state.to` and
`advanced_camera_card.trigger.camera.to` are migrated automatically when
they appear inside template strings.
- **The ambient `advanced_camera_card` template namespace is removed.**
The long-form ambient namespace (`advanced_camera_card.camera`,
`advanced_camera_card.view`, `advanced_camera_card.config`) is retired
in favour of its shorter `acc` alias -- supported since v7.1.0, and the
only spelling the new trigger surface uses. Existing templates are
migrated automatically by rewriting the `advanced_camera_card.` prefix
to `acc.`.

### 4. Trigger-only condition forms are no longer valid conditions

Some legacy "conditions" were really change detectors. These are now
triggers only:

- `condition: config`
- valueless `camera`
- valueless `view`
- valueless `state` / picture-elements state condition with neither
`state` nor `state_not`

These are automatically promoted in automations and stripped from
overrides/elements where they would no longer be meaningful as ongoing
conditions.

### 5. Template truthiness now follows Home Assistant behavior

Template conditions and template triggers intentionally use different
truthiness rules, matching HA:

- A template condition passes only when the rendered value is `true`
(case-insensitive), matching HA's `condition.py`.
- A template trigger uses HA's broader `result_as_boolean` coercion: a
non-zero number, or `1` / `true` / `yes` / `on` / `enable`
(case-insensitive), counts as true.

### 6. Action templates render when each action executes

Action templates are now rendered per action step, not once for the
whole sequence. This means a later action can see card-local state
changed by an earlier action in the same sequence.

The `trigger` context is fixed for the automation run. HA entity state
updates still depend on the frontend receiving updated HASS state over
the websocket.

## Automatic Migrations

### Automation `conditions:` to `triggers:`

Simple legacy automation:

```yaml
# Before
automations:
  - conditions:
      - condition: fullscreen
        fullscreen: true
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: substream_on
```

```yaml
# After, automatic
automations:
  - triggers:
      - trigger: fullscreen
        fullscreen: true
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: substream_on
```

State conditions become HA-style state triggers:

```yaml
# Before
automations:
  - conditions:
      - condition: state
        entity_id: binary_sensor.front_door
        state: 'on'
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: live
```

```yaml
# After, automatic
automations:
  - triggers:
      - trigger: state
        entity_id: binary_sensor.front_door
        to: 'on'
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: live
```

Multiple conditions become both triggers and ongoing conditions:

```yaml
# Before
automations:
  - conditions:
      - condition: camera
        cameras: [front_door]
      - condition: fullscreen
        fullscreen: true
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: substream_on
```

```yaml
# After, automatic
automations:
  - triggers:
      - trigger: camera
        cameras: [front_door]
      - trigger: fullscreen
        fullscreen: true
    conditions:
      - condition: camera
        cameras: [front_door]
      - condition: fullscreen
        fullscreen: true
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: substream_on
```

The flattened trigger list is an implicit OR. The retained `conditions:`
list is an implicit AND checked when any trigger fires.

### Trigger-only legacy conditions

Legacy `config` conditions become `config` triggers:

```yaml
# Before
automations:
  - conditions:
      - condition: config
        paths: [menu.style]
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: status_bar
```

```yaml
# After, automatic
automations:
  - triggers:
      - trigger: config
        paths: [menu.style]
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: status_bar
```

Trigger-only leaves are removed from retained `conditions:` blocks
because they no longer describe an ongoing state.

### `actions_not` to `if` / `then` / `else`

```yaml
# Before
automations:
  - conditions:
      - condition: state
        entity_id: input_boolean.camera_alerts
        state: 'on'
    actions:
      - action: custom:advanced-camera-card-action
        advanced_camera_card_action: live
    actions_not:
      - action: none
```

```yaml
# After, automatic
automations:
  - triggers:
      - trigger: state
        entity_id: input_boolean.camera_alerts
    actions:
      - if:
          - condition: state
            entity_id: input_boolean.camera_alerts
            state: 'on'
        then:
          - action: custom:advanced-camera-card-action
            advanced_camera_card_action: live
        else:
          - action: none
```

If the legacy automation had no conditions, or only trigger-only
conditions, `actions_not` is dropped because the old `else` branch could
not be reproduced as an ongoing predicate.

### Trigger template paths

```yaml
# Before
message: 'Door is {{ acc.trigger.state.to }} from {{ acc.trigger.state.from }}'
```

```yaml
# After, automatic
message: 'Door is {{ trigger.to_state.state }} from {{ trigger.from_state.state }}'
```

Path rewrites performed automatically:

| Old path                   | New path                   |
| -------------------------- | -------------------------- |
| `acc.trigger.state.entity` | `trigger.entity_id`        |
| `acc.trigger.state.from`   | `trigger.from_state.state` |
| `acc.trigger.state.to`     | `trigger.to_state.state`   |
| `acc.trigger.camera.from`  | `trigger.from_acc.camera`  |
| `acc.trigger.camera.to`    | `trigger.to_acc.camera`    |
| `acc.trigger.view.from`    | `trigger.from_acc.view`    |
| `acc.trigger.view.to`      | `trigger.to_acc.view`      |
| `acc.trigger.config.from`  | `trigger.from_acc.config`  |
| `acc.trigger.config.to`    | `trigger.to_acc.config`    |

The same rewrites are applied for the older
`advanced_camera_card.trigger.*` namespace.

### Ambient template namespace

Any remaining long-form ambient `advanced_camera_card.*` references
(outside the trigger surface) are rewritten to the `acc.*` alias:

```yaml
# Before
title: 'Now viewing {{ advanced_camera_card.camera }}'
```

```yaml
# After, automatic
title: 'Now viewing {{ acc.camera }}'
```

## Manual Migration Cases

### `__UPGRADE_FAILURE__.automations`

If a legacy automation cannot be converted faithfully, the original
automation is recorded under:

```yaml
__UPGRADE_FAILURE__:
  automations:
    - ...
```

These entries require manual migration.

The main known case is legacy `actions_not` with a condition whose
trigger can only fire on a rising edge, such as:

- `condition: template`
- `condition: screen`
- `condition: numeric_state` without an entity-backed state to watch

Those conditions can start the `then` branch, but cannot reliably start
the `else` branch when they stop matching.

### Unsupported HA conditions and triggers

This PR aligns the card with HA where supported, but it is not a full HA
automation engine.

Unsupported HA condition families include:

- `time`
- `zone`
- `sun`
- `location`
- `device`
- `condition: trigger`

Unsupported HA trigger platforms include:

- `event`
- `time`
- `time_pattern`
- `sun`
- `zone`
- `calendar`
- `webhook`
- `tag`
- `device`
- `mqtt`

The card-specific camera `triggers:` feature (which auto-selects and
wakes the card on camera events such as motion) is a separate feature
from automation `triggers:`, despite the shared word.

### Trigger IDs and variables

HA keys such as `id`, `alias`, and `variables` are accepted so pasted HA
YAML validates, but they are ignored by the card. There is no
`trigger.id` support in this PR.

## New Compatibility Features

This PR also makes card config more forgiving for HA-style YAML:

- `trigger`, `condition`, and `action` singular keys are accepted and
normalized to `triggers`, `conditions`, and `actions`.
- Single trigger, condition, and action objects are accepted where lists
are expected.
- `if`, `then`, and `else` accept a single item or a list.
- Composite condition shorthand is accepted:
  - `{ and: [...] }`
  - `{ or: [...] }`
  - `{ not: [...] }`
  - `{ condition: [...] }` as an implicit AND
- State conditions resolve expected state values that name another
entity, matching HA/Lovelace behavior.
- Both `entity` and `entity_id` are accepted on state and numeric
conditions and triggers (a superset of HA's two dialects), so there is
no forced rename.
- `state_not` remains supported as a card/Lovelace-friendly extension.

## Trigger Payloads

Automation action templates receive a top-level `trigger` object.

For stock `state` and `numeric_state` triggers:

```yaml
trigger.platform
trigger.entity_id
trigger.entity
trigger.from_state
trigger.to_state
```

For template triggers:

```yaml
trigger.platform
```

For card-specific triggers:

```yaml
trigger.platform # "acc"
trigger.type
trigger.from_acc
trigger.to_acc
```

The card does not currently expose HA's `id`, `idx`, `for`, `attribute`,
`above`, `below`, or `alias` trigger fields.

BREAKING CHANGE: Automations now follow Home Assistant's `triggers:` /
`conditions:` / `actions:` model. Automations require a `triggers:`
block and `conditions:` no longer wake an automation; `actions_not` is
removed in favour of an `if` / `then` / `else` action; the nested
`acc.trigger.*` template paths and the ambient `advanced_camera_card`
template namespace are removed (use the top-level `trigger.*` surface
and the `acc` alias); trigger-only condition forms (`config`, valueless
`camera` / `view` / `state`) are no longer valid conditions; and
template-condition vs template-trigger truthiness now follow HA.
Existing configs are upgraded automatically where a faithful conversion
exists; anything that cannot be converted is recorded under
`__UPGRADE_FAILURE__` for manual migration.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 17:45:13 -07:00

38 KiB

Custom Elements

conditional

Restrict a set of elements to only render when the card is matches a set of conditions. This is analogous to the stock conditional element except supporting a rich set of Advanced Camera Card conditions.

elements:
  - type: custom:advanced-camera-card-conditional
    # [...]

Parameters for the custom:advanced-camera-card-conditional element:

Parameter Description
type Must be custom:advanced-camera-card-conditional.
conditions A list of conditions that must evaluate to true in order for the elements to be rendered.
elements The elements to render. Can be any supported element.

See the conditional elements example.

menu-icon

Add an arbitrary icon to the Advanced Camera Card menu.

elements:
  - type: custom:advanced-camera-card-menu-icon
    # [...]

Configuration is similar to a stock Picture Elements Icon.

Parameter Default Description
type Must be custom:advanced-camera-card-menu-icon.
alignment matching Whether this menu item should have an alignment that is matching the menu alignment or opposing the menu alignment. Can be used to create two separate groups of buttons on the menu. The priority option orders buttons within a given alignment.
enabled true Whether or not to show this menu item.
entity An optional Home Assistant entity for use with actions.
icon An required icon to display, e.g. mdi:car. See also custom icons.
permanent false If false the menu item is hidden when the menu has the hidden style and the menu is closed, otherwise it is shown (and sorted to the front).
priority 50 The menu item priority. Higher priority items are ordered closer to the start of the menu alignment (i.e. a button with priority 70 will order further to the left than a button with priority 60). Priority applies separately to matching and opposing groups (see alignment above). Minimum 0, maximum 100.
style Position and style the element using CSS.
tap_action, double_tap_action, hold_action, start_tap, end_tap The actions to take when this item is interacted with.
title An optional title to display.

menu-submenu

Add a configurable submenu dropdown.

elements:
  - type: custom:advanced-camera-card-menu-submenu
    # [...]
Parameter Default Description
type Must be custom:advanced-camera-card-menu-submenu.
alignment matching Whether this menu item should have an alignment that is matching the menu alignment or opposing the menu alignment. Can be used to create two separate groups of buttons on the menu. The priority option orders buttons within a given alignment.
enabled true Whether or not to show this menu item.
entity An optional Home Assistant entity for use with actions.
icon An required icon to display, e.g. mdi:car. See also custom icons.
items A list of menu items, as described below.
permanent false If false the menu item is hidden when the menu has the hidden style and the menu is closed, otherwise it is shown (and sorted to the front).
priority 50 The menu item priority. Higher priority items are ordered closer to the start of the menu alignment (i.e. a button with priority 70 will order further to the left than a button with priority 60). Priority applies separately to matching and opposing groups (see alignment above). Minimum 0, maximum 100.
style Position and style the element using CSS.
tap_action, double_tap_action, hold_action, start_tap, end_tap The actions to take when this item is interacted with.
title An optional title to display.

Submenu items

Parameter Default Description
enabled true Whether or not to show this item as enabled / selectable.
entity An optional Home Assistant entity from which title, icon and style can be automatically computed.
icon An optional item icon to display, e.g. mdi:car. See also custom icons.
selected false Whether or not to show this item as selected.
state_color true Whether or not the title and icon should be stylized based on state.
style Position and style the element using CSS.
subtitle Optional additional text to display.
tap_action, double_tap_action, hold_action, start_tap, end_tap The actions to take when this item is interacted with.
title An optional title to display.

menu-submenu-select

Add a submenu based on a select or input_select. This element allows you to convert a Home Assistant Select Entity or Home Assistant Input Select Entity (an entity either starting with select or input_select) into an overridable submenu. This could be done by hand using a regular submenu (above) -- this element is a convenience.

elements:
  - type: custom:advanced-camera-card-menu-submenu-select
    # [...]
Parameter Default Description
type Must be custom:advanced-camera-card-menu-submenu-select.
alignment matching Whether this menu item should have an alignment that is matching the menu alignment or opposing the menu alignment. Can be used to create two separate groups of buttons on the menu. The priority option orders buttons within a given alignment.
enabled true Whether or not to show this menu item.
entity An optional Home Assistant entity for use with actions.
icon An required icon to display, e.g. mdi:car. See also custom icons.
options An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in Submenu Items above.
permanent false If false the menu item is hidden when the menu has the hidden style and the menu is closed, otherwise it is shown (and sorted to the front).
priority 50 The menu item priority. Higher priority items are ordered closer to the start of the menu alignment (i.e. a button with priority 70 will order further to the left than a button with priority 60). Priority applies separately to matching and opposing groups (see alignment above). Minimum 0, maximum 100.
style Position and style the element using CSS.
tap_action, double_tap_action, hold_action, start_tap, end_tap The actions to take when this item is interacted with.
title An optional title to display.

See the select submenu example.

menu-state-icon

Add a state icon to the Advanced Camera Card menu that represents the state of a Home Assistant entity.

elements:
  - type: custom:advanced-camera-card-menu-state-icon
    # [...]

Configuration is similar to a stock Picture Elements State Icon.

Parameter Default Description
type Must be custom:advanced-camera-card-menu-state-icon.
alignment matching Whether this menu item should have an alignment that is matching the menu alignment or opposing the menu alignment. Can be used to create two separate groups of buttons on the menu. The priority option orders buttons within a given alignment.
enabled true Whether or not to show this menu item.
entity An optional Home Assistant entity for use with actions.
icon An required icon to display, e.g. mdi:car. See also custom icons.
permanent false If false the menu item is hidden when the menu has the hidden style and the menu is closed, otherwise it is shown (and sorted to the front).
priority 50 The menu item priority. Higher priority items are ordered closer to the start of the menu alignment (i.e. a button with priority 70 will order further to the left than a button with priority 60). Priority applies separately to matching and opposing groups (see alignment above). Minimum 0, maximum 100.
tap_action, double_tap_action, hold_action, start_tap, end_tap The actions to take when this item is interacted with.
state_color true Set to true to have icons colored when entity is active.
style Position and style the element using CSS.
title An optional title to display.

status-bar-icon

Add an arbitrary icon to the status bar.

elements:
  - type: custom:advanced-camera-card-status-bar-icon
    # [...]
Parameter Default Description
type Must be custom:advanced-camera-card-status-bar-icon.
actions Actions to performs when the status bar item is interacted with. See actions.
enabled true true to enable this status bar item, false to disable.
exclusive false Whether or not this item should evict non-exclusive items from the status bar.
expand false If false this status bar item will consume the minimum possible space, if true will expand to the available space.
icon The icon to show in the status bar, e.g. mdi:camera-front. See also custom icons.
priority 50 The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority 70 will order further to the left than an item with priority 60). Minimum 0, maximum 100.
severity An optional severity level, one of low, medium or high. Colors the item accordingly.
sufficient false Whether or not this item is sufficient to display the status bar if it's otherwise hidden (e.g. with the popup status bar style).
title An optional tooltip shown on hover.

status-bar-image

Add an arbitrary image to the status bar.

elements:
  - type: custom:advanced-camera-card-status-bar-image
    # [...]
Parameter Default Description
type Must be custom:advanced-camera-card-status-bar-image.
actions Actions to performs when the status bar item is interacted with. See actions.
enabled true true to enable this status bar item, false to disable.
exclusive false Whether or not this item should evict non-exclusive items from the status bar.
expand false If false this status bar item will consume the minimum possible space, if true will expand to the available space.
image The image to show in the status bar, e.g. https://my.site.com/status.png.
priority 50 The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority 70 will order further to the left than an item with priority 60). Minimum 0, maximum 100.
severity An optional severity level, one of low, medium or high. Colors the item accordingly.
sufficient false Whether or not this item is sufficient to display the status bar if it's otherwise hidden (e.g. with the popup status bar style).
title An optional tooltip shown on hover.

status-bar-string

Add an arbitrary string to the status bar.

elements:
  - type: custom:advanced-camera-card-status-bar-string
    # [...]
Parameter Default Description
type Must be custom:advanced-camera-card-status-bar-string.
actions Actions to performs when the status bar item is interacted with. See actions.
enabled true true to enable this status bar item, false to disable.
exclusive false Whether or not this item should evict non-exclusive items from the status bar.
expand false If false this status bar item will consume the minimum possible space, if true will expand to the available space.
string The string to show in the status bar, e.g. Intruder detected!
priority 50 The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority 70 will order further to the left than an item with priority 60). Minimum 0, maximum 100.
severity An optional severity level, one of low, medium or high. Colors the item accordingly.
sufficient false Whether or not this item is sufficient to display the status bar if it's otherwise hidden (e.g. with the popup status bar style).
title An optional tooltip shown on hover.

Fully expanded reference

Note

Actions are omitted for simplicity.

elements:
  - type: custom:advanced-camera-card-menu-icon
    alignment: matching
    enabled: true
    entity: light.office_main_lights
    icon: mdi:car
    permanent: false
    priority: 50
    style:
      color: white
    title: Vroom
  - type: custom:advanced-camera-card-menu-state-icon
    alignment: matching
    enabled: true
    entity: light.office_main_lights
    icon: mdi:chair-rolling
    permanent: false
    priority: 50
    state_color: true
    style:
      color: white
    title: Office lights
  - type: custom:advanced-camera-card-menu-submenu
    alignment: matching
    enabled: true
    entity: light.office_main_lights
    icon: mdi:menu
    items:
      - enabled: true
        entity: light.office_main_lights
        icon: mdi:lightbulb
        selected: false
        state_color: true
        style:
          color: white
        tap_action:
          action: toggle
        title: Lights
      - enabled: true
        icon: mdi:google
        selected: false
        state_color: false
        style:
          color: white
        tap_action:
          action: url
          url_path: https://www.google.com
        title: Google
    permanent: false
    priority: 50
    style:
      color: white
    title: Office lights
  - type: custom:advanced-camera-card-menu-submenu-select
    alignment: matching
    enabled: true
    entity: input_select.kitchen_scene
    icon: mdi:lamps
    options:
    items:
      scene.kitchen_cooking_scene:
        enabled: true
        icon: mdi:chef-hat
        selected: false
        state_color: true
        style:
          color: white
        title: Cooking time!
      scene.kitchen_tv_scene:
        icon: mdi:television
        title: TV!
    permanent: false
    priority: 50
    style:
      color: white
    title: 'Kitchen Scene'
    # Show a pig icon if a variety of conditions are met.
  - type: custom:advanced-camera-card-conditional
    elements:
      - type: icon
        icon: mdi:pig
        title: Oink
        style:
          left: 300px
          top: 100px
    conditions:
      - condition: view
        views:
          - live
      - condition: fullscreen
        fullscreen: true
      - condition: expand
        expand: true
      - condition: camera
        cameras: camera.front_door
      - condition: media_loaded
        media_loaded: true
      - condition: display_mode
        display_mode: single
      - condition: triggered
        triggered:
          - camera.front_door
      - condition: interaction
        interaction: true
      - condition: microphone
        muted: true
        connected: true
      - condition: state
        entity: light.office_main_lights
        state: on
        state_not: off
      - condition: numeric_state
        entity: sensor.light_level
        above: 20
        below: 100
      - condition: user
        users:
          - 581fca7fdc014b8b894519cc531f9a04
  - type: custom:advanced-camera-card-status-bar-string
    enabled: true
    exclusive: false
    expand: false
    string: 'Intruder alert!'
    priority: 50
    severity: high
    sufficient: false
  - type: custom:advanced-camera-card-status-bar-icon
    enabled: true
    exclusive: false
    expand: false
    icon: 'mdi:cow'
    priority: 50
    severity: medium
    sufficient: false
  - type: custom:advanced-camera-card-status-bar-image
    enabled: true
    exclusive: false
    expand: false
    image: https://my.site.com/status.png
    priority: 50
    severity: low
    sufficient: false