Custom Button Card value comparison issue

Been playing with the custom:button-card and have run into strange behaviour.

I am trying to create a card that looks at the temperature and an the dewpoint of a sensor (dewpoint is calculated from the T and H of the same sensor).
When the temperature is less than or equal to dewpoint temperature the card text should change colour and show an alert .

It seemed to work until I notice that is the dewpoint temperature is say 9.0C and the temperature is say 10.0C then it seems to return that 9.0C is greater than 10.0C.

To further test this I created a couple of input_number helpers and used the config below.

type: custom:button-card
variables:
  entity_4: sensor.living_room_sensor_dewpoint
  entity_3: sensor.living_room_sensor_temperature
  entity_2: input_number.test_temperature_slider
  entity_1: input_number.test_dewpoint_slider
  color_condensation: '#0000FF'
  color_normal: '#00FF00'
  color_unavailable: '#252525'
entity: '[[[return variables.entity_1]]]'
triggers_update:
  - '[[[return variables.entity_2]]]'
label: |
  [[[
    if (entity.state == 'unavailable')
      return 'Unknown';
    else if (entity.state >= states[variables.entity_2].value)
      return "Condensation";
    else if (entity.state < states[variables.entity_2].value)
      return "OK";
  ]]]
show_label: true
name: Dewpoint
show_name: true
show_state: false
color-type: icon
styles:
  grid:
    - position: relative
  custom_fields:
    temperature:
      - border-radius: 10%
      - position: absolute
      - left: 0%
      - top: 20%
      - height: 20px
      - width: 50px
      - font-size: 14px
    dewpoint:
      - border-radius: 10%
      - position: absolute
      - left: 0%
      - top: 10%
      - height: 20px
      - width: 50px
      - font-size: 14px
    alert:
      - border-radius: 10%
      - position: absolute
      - left: 70%
      - top: 10%
      - height: 80px
      - width: 50px
      - font-size: 70px
      - color: red
      - font-weight: bold
      - animation: blink 0.5s ease infinite
  icon:
    - color: |
        [[[
        if (entity.state == 'unavailable')
          return variables.color_unavailable;
        else if (entity.state >= states[variables.entity_2].state)
          return variables.color_condensation;
        else if (entity.state < states[variables.entity_2].state)
          return variables.color_normal;
        ]]]
  label:
    - color: |
        [[[
        if (entity.state == 'unavailable')
          return variables.color_unavailable;
        else if (entity.state >= states[variables.entity_2].state)
          return variables.color_condensation;
        else if (entity.state < states[variables.entity_2].state)
          return variables.color_normal;
        ]]]
custom_fields:
  dewpoint: |
    [[[
      if (entity.state == 'unavailable')
        return '--';
      else 
        return (entity.state) + " °C";
    ]]]
  alert: |
    [[[
      if (entity.state >= states[variables.entity_2].state)
        return '!';
      else
        return '';
    ]]]
  temperature: |
    [[[ return states[variables.entity_2].state]]]

but I still get odd results

The result below is fine because dewpoint is lower than temperature
image

The result below is also OK because dewpoint = temperature
image

Again - below is OK
image

However the result below though is wrong as dewpoint is greater than temperature
image

If I make the dewpoint 2.5C then every temperature value from 10C to 24.9C is incorrect.

So, basically what am I misunderstanding / doing wrong?

You seem to be doing string comparisons instead of comparing actual numeric values. I had the exact same problem today and found this thread with a Google search, and thought I’d try to help. So, let’s look at part of an example of yours:

In if (entity.state == 'unavailable') the value of entity.state is expected to be a string, so this is ok.

In the else if (entity.state >= states[variables.entity_2].state) part you’d probably like to compare decimal numbers (floats) instead of strings, so those comparisons need a little help to make them work as expected. You’d want to enclose both sides of those comparisons in the parseFloat() functions, like this:

else if (parseFloat(entity.state) >= parseFloat(states[variables.entity_2].state))

That will basically tell JavaScript to treat those states as decimal numbers.

Another thing I’d probably do is to substitute the entity_1...4 variables with the actual entity names, as I think the code is more readable that way (ok, the lines get a bit long that way, and this is strictly a personal preference anyway :slight_smile: ). I’d do something like this:

    - color: |
        [[[
        if (entity.state == 'unavailable')
          return variables.color_unavailable;
        else if (parseFloat(entity.state) >= parseFloat(states['input_number.test_temperature_slider'].state))
          return variables.color_condensation;
        else if (parseFloat(entity.state) < parseFloat(states['input_number.test_temperature_slider'].state))
          return variables.color_normal;
        ]]]

Thank you! Thank you! It works as expected now.

I had suspected it must be text based comparisons, but did not know how to ‘convert’ the strings to numbers. Simple when you know how…

As for the variables thing, I totally agree that using the entities directly is easier to understand.
My intention is to use this as a template for multiple sensors and doing with variables means I only have to change the variable names at the top of the code rather than changing the entities multiple times for each sensor. Unless you know a better way (please).

Thanks so much again!

You’re very much welcome! Glad I could be of help.

I actually suspected you might have had an idea for using the variables that way, and think that your idea of using the variables to simplify templating is a good solution. In this case I honestly would use the variables the same way you do. I actually almost didn’t write the variables thing, but decided to include it since thinking about readability and maintainability is something I always try to remember to do.