custom-cards / button-card

❇️ Lovelace button-card for home assistant
MIT License
1.97k stars 242 forks source link

nested template in variables confusion in 4.1.0. dev.1 #743

Closed Mariusthvdb closed 1 year ago

Mariusthvdb commented 1 year ago

Checklist

Describe the bug A clear and concise description of what the bug is.

not this is a bug, or a user misconception of the new feature introduces in 410 dev-1 (pull https://github.com/custom-cards/button-card/pull/741)

have a nested variable ( binary == 'on') with a card external entity used as state inside the second throws no error, but doesnt do anything either.

Not sure if the 'evaluate once' of this new feature is referring to the loading of the card config, or, as it seems now, also pertains to the actual entity being evaluated or not after loading of the card.

Version of the card Version:

To Reproduce This is the configuration I used:

original working config, without secondary variable (but repeated entity in the config templates on several spots)

type: custom:button-card
template: button_body
entity: sensor.last_motion_triggered #variable.last_motion
variables:
  action_color: >
    [[[ return states['binary_sensor.motion_sensors_all'].state === 'on' ? 'red' : 'grey'; ]]]
tap_action:
  action: more-info
hold_action:
  action: navigate
  navigation_path: >
    [[[ return (window.location.pathname.split('/')[2] != 'beweging')
        ? '/ui-instellingen/beweging' : null; ]]]
icon: >
  [[[ return states['binary_sensor.motion_sensors_all'].state === 'on'
        ? 'mdi:motion-sensor' : 'mdi:motion-sensor-off'; ]]]
name: >
  [[[ var location = `<span style="color:${variables.action_color};font-size:11px;word-wrap:break-word;">
      ${entity.state}</span>`;
      return 'Last motion' + '<br>' + location; ]]]
show_state: false
show_last_changed: true
styles:
  card:
    - color: grey
  icon:
    - color: >
        [[[ return variables.action_color; ]]]

added the binary == 'on' as a second variable, and used it inside the action_color variable. This no longer updates that color variable. It does work correctly for the animation and changing the icon:

type: custom:button-card
template:
  - button_body
  - extra_styles
entity: sensor.last_motion_triggered
variables:
  trigger_on: >
    [[[ return states['binary_sensor.motion_sensors_all'].state === 'on'; ]]]
  action_color: >
    [[[ return (variables.trigger_on) ? 'red' : 'grey'; ]]]
tap_action:
  action: more-info
hold_action:
  action: navigate
  navigation_path: >
    [[[ return (window.location.pathname.split('/')[2] != 'beweging')
        ? '/ui-instellingen/beweging' : null; ]]]
icon: >
  [[[ return (variables.trigger_on)
        ? 'mdi:motion-sensor' : 'mdi:motion-sensor-off'; ]]]
name: >
  [[[ var location = `<span style="color:${variables.action_color};font-size:11px;word-wrap:break-word;">
      ${entity.state}</span>`;
      return 'Last motion' + '<br>' + location; ]]]
show_state: false
show_last_changed: true
styles:
  card:
    - color: grey
    - animation: >
        [[[ if (variables.trigger_on) return 'wiggle 2s ease infinite';
            return 'none'; ]]]
  icon:
    - color: >
        [[[ return variables.action_color; ]]]

Screenshots If applicable, add screenshots to help explain your problem. working state without wiggle

Scherm­afbeelding 2023-07-31 om 09 44 33

with second variable

Scherm­afbeelding 2023-07-31 om 09 43 40

ofc we can use both the color and the wiggle ;-)

Scherm­afbeelding 2023-07-31 om 09 46 46

but this requires to verbosely repeat the condition on all places, which was the reason to try the new variable option:

variables:
  action_color: >
    [[[ return (states['binary_sensor.motion_sensors_all'].state === 'on') ? 'red' : 'grey'; ]]]
tap_action:
  action: more-info
hold_action:
  action: navigate
  navigation_path: >
    [[[ return (window.location.pathname.split('/')[2] != 'beweging')
        ? '/ui-instellingen/beweging' : null; ]]]
icon: >
  [[[ return (states['binary_sensor.motion_sensors_all'].state === 'on')
        ? 'mdi:motion-sensor' : 'mdi:motion-sensor-off'; ]]]
name: >
  [[[ var location = `<span style="color:${variables.action_color};font-size:11px;word-wrap:break-word;">
      ${entity.state}</span>`;
      return 'Last motion' + '<br>' + location; ]]]
show_state: false
show_last_changed: true
styles:
  card:
    - color: grey
    - animation: >
        [[[ if (states['binary_sensor.motion_sensors_all'].state === 'on') return 'wiggle 2s ease infinite';
            return 'none'; ]]]
  icon:
    - color: >
        [[[ return variables.action_color; ]]]

Expected behavior A clear and concise description of what you expected to happen.

Nothing 'expected' here, merely hoping this would be possible, so please close if this cant be done after all.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Working alternative: use the same binary in both variable declarations:

variables:
  trigger_on: >
    [[[ return states['binary_sensor.motion_sensors_all'].state === 'on'; ]]]
  action_color: >
    [[[ return (states['binary_sensor.motion_sensors_all'].state === 'on') ? 'red' : 'grey'; ]]]

saves some code repetition in the button config. This however might be the purest illustration of what I was hoping to do.

RomRider commented 1 year ago

That doesn't work because you make action_color depend on trigger_on, but the variables are evaluated in their alphabetical order. That means trigger_on is still undefined in action_color when accessed. Rename them so that trigger_on comes before action_color. Eg: a_trigger_on and b_action_color

Also this is unrelated to the PR you mention.

Mariusthvdb commented 1 year ago

yes, confirm this works:

type: custom:button-card
template:
  - button_body
  - extra_styles
entity: sensor.last_motion_triggered
variables:
  a_trigger_on: >
    [[[ return states['binary_sensor.motion_sensors_all'].state === 'on'; ]]]
  b_action_color: >
    [[[ return (variables.a_trigger_on) ? 'red' : 'grey'; ]]]
tap_action:
  action: more-info
hold_action:
  action: navigate
  navigation_path: >
    [[[ return (window.location.pathname.split('/')[2] != 'beweging')
        ? '/ui-instellingen/beweging' : null; ]]]
icon: >
  [[[ return (variables.a_trigger_on)
        ? 'mdi:motion-sensor' : 'mdi:motion-sensor-off'; ]]]
name: >
  [[[ var location = `<span style="color:${variables.b_action_color};font-size:11px;word-wrap:break-word;">
      ${entity.state}</span>`;
      return 'Last motion' + '<br>' + location; ]]]
show_state: false
show_last_changed: true
styles:
  card:
    - color: grey
    - animation: >
        [[[ return variables.a_trigger_on ? 'wiggle 2s ease infinite' : 'none'; ]]]
  icon:
    - color: >
        [[[ return variables.b_action_color; ]]]

nice.

btw is it expected there is an error when using

        [[[ if variables.a_trigger_on return 'wiggle 2s ease infinite';
            return 'none'; ]]]

while:

        [[[ if (variables.a_trigger_on) return 'wiggle 2s ease infinite';
            return 'none'; ]]]

works, and

        [[[ return variables.a_trigger_on ? 'wiggle 2s ease infinite' : 'none'; ]]]

does not require the brackets?

even when not using the variable but the original

[[[ return states['binary_sensor.motion_sensors_all'].state === 'on'; ]]]

we can leave out the brackets

no issue, I tend to always put brackets around those if's, only asking for 100% security

btw some renaming does make it feel less 'hacky'

variables:
# nested variables are evaluated in their alphabetical order
  action: >
    [[[ return states['binary_sensor.motion_sensors_all'].state === 'on'; ]]]
  color: >
    [[[ return (variables.action) ? 'red' : 'grey'; ]]]
RomRider commented 1 year ago

btw is it expected there is an error when using

        [[[ if variables.a_trigger_on return 'wiggle 2s ease infinite';
            return 'none'; ]]]

if always requires the conditions to be enclosed with () else there's no way for if to know where the condition stops (it's not intelligent 😄 ).

Mariusthvdb commented 1 year ago

a yes, ofc, its the if.. sorry....temporary blackout.

closing as no issue cool.