custom-cards / button-card

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

New display precision in entity is not taken into account... #662

Closed Protoncek closed 1 year ago

Protoncek commented 1 year ago

Checklist

Describe the bug Today HA was updated to 2023.3 and with it a new function was added: possibility to set precision for entities. I have Xiaomi sensors which by default show humidity to one decimal (say: 49.1%) and temperature to two decimals (say: 23.13°C), which is too much. So i changed that into: humidity=zero decimals (=49%), temperature only one decimal (=23.1°C. In HA, "entities card" shows correctly 49% and 23.1°C, but in "custom:button-card" it still shows original values.

Version of the card Version: 3.4.2

To Reproduce This is the configuration I used:

type: custom:button-card
entity: sensor.greenhouse_23b8_humidity
show_state: true
aegjoyce commented 1 year ago

Same here. I don't think this will be fixed though as the project appears to be abandoned.

Protoncek commented 1 year ago

Uh, i didn't notice that... it really seems that project is very old. That's very sad, since this card is one of the best cards in HA... you can do practically everything with it... definitely the most usefull card out there.

pvprodk commented 1 year ago

same problem here

pvprodk commented 1 year ago

A manual workaround is adding the following to the card configuration:

state_display: | [[[ return Math.round((Number(entity.state) + Number.EPSILON) * 100) / 100; ]]]

Protoncek commented 1 year ago

Uau… A bit complicated, but at least it’s a solution, many thanks! I’d say that for occasional things it will be great, but for more frequent things it’s better to create additional sensor with less accuracy, as i have now: i have 8 xiaomi temp/humidity sensors, which shows humidity to one decimal and temp to two decimals, which is an exaggeration, so i created template sensors with smaller resolution. Now i hoped that i’ll be able to remove them… EDIT: hm... for some reason it doesn't work for me... humidity is still hown with two decimals, only % sign is missing...?

pejotigrek commented 1 year ago

@Protoncek I use this template with my pressure sensor:

state_display: "[[[ return parseFloat(states['sensor.4_out_pressure'].state).toFixed(0); ]]]"

you can change number of decimals by changing 0 in toFixed() to other number .

Protoncek commented 1 year ago

Thanks, i found one working command, too: [Math.round(states['[[temperature]]'].state).toFixed(1) + '°C'] (It’s template for decluttering card) i guess that “epsilon” was the culprit for non-working.. I wonder what’s difference between two…

pejotigrek commented 1 year ago

@Protoncek Math.round() rounds the number to nearest integer [which means it would make more sense for me to use it - and ditch the .toFixed(0), but as I have this in lot of places with different number of decimals - it's easier for me to find all occurences of the template when I search the code; without changing the query]. so in your case - you first round the number to nearest integer and then you add one decimal to it.

parseFloat() tells the template to treat sensor value as float number [without rounding] and then by toFixed() you just tell it to cut the decimals to desired count [and then it rounds it as it should]

Protoncek commented 1 year ago

Aha… thanks for explanation. So, basically, end effect is the same…

pejotigrek commented 1 year ago

if you want 0 decimals, then yes, effect should be the same, but if you want the float number with some decimals, I'd stick with .toFixed() [but also: I'm not a programmer, so maybe there's something I don't know about those both ways ;)]

Alfamonk commented 1 year ago

Same issue in here. All other cards take the new "Display precision" into account, but custom:button-card does not. Please fix this! Thanks!

alexruffell commented 1 year ago

What about this method I found?

type: custom:button-card
entity: sensor.office_multi_sensor_temperature
state_display: |
  [[[
    var result = Number(entity.state).toFixed(1);
    return result.concat("°C");
  ]]]
styles:
  card:
    - height: 100%
    - width: 58px
    - padding: 0px 0px 0px 2px
  name:
    - text-transform: uppercase
    - font-size: 12px
    - font-weight: normal
    - justify-self: center
    - letter-spacing: 2px
    - padding: 0%
tap_action:
  action: none
show_icon: false
show_name: false
show_state: true
layout: name_state

Sounds like it just chops the decimals to 1 without doing any rounding so 21.19 would turn into 21.1 instead of 21.2... if so, not what I want. Is that the case? I liked this method simply because it doesn't reference the entity name. Anyhow, one issue the few methods I tried have is that if the entity is deleted/name changed/etc then you get a huge burgundy error that messes up the dashboard. Is there some way to have it fail more "discretely"?

Protoncek commented 1 year ago

Same issue in here. All other cards take the new "Display precision" into account, but custom:button-card does not..

Actually.. not all... i found another one who doesn't: custom:simple-thermostat. I didn't report a problem for that one (yet)... I'm starting to think that it's a HA problem, not custom cards one... it seems that this decimals setting is not valid for all things in HA...weird...

Alexruffel: thanks, that also works!

Mariusthvdb commented 1 year ago

please stop posting you experience the same issue only. Of course you do, everyone does, as this now is the state of the affairs with changed HA Frontend handling not taken into account in an unchanged custom:button-card...

It causes many email/notifications without additional value for all followers of this repo.

on the rounding: simply check the js instructions you find in the various online tutorials, they all can be used inside button-card, depending on your needs. It's still the best card ever ;-)

We might be lucky Romrider would update button-card to implement the new HA Dashboard techniques.

Until that moment, we just will have to manage.

RomRider commented 1 year ago

This should be fixed with the latest beta 4.0.0-dev7

Mariusthvdb commented 1 year ago

on b8 still not seeing it:

Scherm­afbeelding 2023-07-24 om 23 24 35

also, wondering if this is for all numeric entities on the button? or just state asking because I have quite a few buttons with more than 1 numeric entity, eg in custom fields notifications:

custom_fields:
  notification: >
    [[[ return Math.round(states['sensor.pond_buiten_sensor_temperature'].state); ]]]
name: >
  [[[ return 'Vijver: ' + states['sensor.vijver_thermometer_temperature'].state + ' °C'; ]]]

, and, use things like that name template. Would these all be influenced using that

numeric_precision: 0

?

Update

after updating to b9

Scherm­afbeelding 2023-07-25 om 08 27 46

that fixed it ;-) (and dont worry it should now in fact show 21.... its early in the morning to temp has fallen a bit..)

RomRider commented 1 year ago

If you're not seeing the result of numeric_precision it's because of a caching issue probably.

Also that doesn't apply to a direct access to the state, you'd have to use the new localize function on the custom_field state access (check the dev branch readme about that).

RomRider commented 1 year ago

Fixed in next version

github-actions[bot] commented 1 year ago

:tada: This issue has been resolved in version 4.0.0-dev.9 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket:

Protoncek commented 1 year ago

Hm... new dev version causes that this card doesn't work in browser-mod's popup - i have a popup where i change station on my internet radio. I click on one button, but nothing happens. Going back to 3.5.0 works again.

And, this decimals issue is solved only if i set to show state "as is" (showstate: true and that's it) . If i set template like this:

state_display:
  [[[
  return "outside is: " + states['sensor.temperature_outside'].states + "°C"
  ]]]

then still shows too many decimals.

Also, as you said: card-mod styles are totally off...

Mariusthvdb commented 1 year ago

If you're not seeing the result of numeric_precision it's because of a caching issue probably.

Also that doesn't apply to a direct access to the state, you'd have to use the new localize function on the custom_field state access (check the dev branch readme about that).

just for reporting that I can now use:

name: >
  [[[ return 'Vijver: ' + localize(states['sensor.vijver_thermometer_temperature']); ]]]
numeric_precision: 0

and it magically works... even adds the unit, so I can take that out of the name template.. cool

Scherm­afbeelding 2023-07-25 om 21 23 12
Mariusthvdb commented 1 year ago

there is another issue see this custom_field:

  co2: >
    [[[ return `Co2:
        <span style='color: var(--text-color-sensor);'>
        ${states['sensor.co2_living'].state} ppm</span>`; ]

showing as

Scherm­afbeelding 2023-07-25 om 21 27 19

so, with a .0

precision is set to be without:

Scherm­afbeelding 2023-07-25 om 21 28 10

which it does in the regular dashboard:

Scherm­afbeelding 2023-07-25 om 21 28 22
RomRider commented 1 year ago

precision is set to be without:

It's displayed without, but the state is stored with the 1 decimal after the .. Accessing states['sensor.co2_living'].state is the raw data.

localize takes new parameters now in the last release (check the README in the dev branch), so you can do: If you didn't define the numeric_precision in the main config:

 co2: >
    [[[ return `Co2:
        <span style='color: var(--text-color-sensor);'>
        ${localize(states['sensor.co2_living'])} ppm</span>`; ]

or if you defined it, you have to force it for this value specifically (this behaviour will change, it's not going to take into account the main numeric_precision for localize but for now it does...):

 co2: >
    [[[ return `Co2:
        <span style='color: var(--text-color-sensor);'>
        ${localize(states['sensor.co2_living'], undefined, 0)} ppm</span>`; ]
RomRider commented 1 year ago

Hm... new dev version causes that this card doesn't work in browser-mod's popup - i have a popup where i change station on my internet radio. I click on one button, but nothing happens. Going back to 3.5.0 works again.

Without the config, there's not much I can do about it 🤷‍♂️

then still shows too many decimals.

Expected as you access the raw state value. For it to be as you want, you have to do:

state_display: |
  [[[
  return "outside is: " + localize(states['sensor.temperature_outside'])
  ]]]

Also, as you said: card-mod styles are totally off...

The only modification in the code is on ha-icon vs ha-state-icon, so again, without the config and screenshots, there's not much I can do.

Also, we can't have all the shiny new features and expect backwards compatibility forever, there's a tradeoff. 🤷‍♂️

alexruffell commented 1 year ago

First of all, thank you @RomRider for implementing all these fixes! I use button-card a lot and love it!

While waiting on a fix for the precision issue, I found an alternative solution which may help @Protoncek. The rounding was handled within the state_display as shown below:

type: custom:button-card
entity: sensor.office_multi_sensor_temperature
state_display: |
  [[[
    var result = Number(entity.state).toFixed(1);
    return result.concat("°C");
  ]]]
styles:
  card:
    - height: 100%
    - width: 58px
    - padding: 0px 0px 0px 2px
  name:
    - text-transform: uppercase
    - font-size: 12px
    - font-weight: normal
    - justify-self: center
    - letter-spacing: 2px
    - padding: 0%
tap_action:
  action: none
show_icon: false
show_name: false
show_state: true
layout: name_state

With your latest revision I can now use this but I wonder whether there is any way to avoid repeating the sensor name. In the example above entity.state enabled me to not have to write the entity twice in the card. Just helps with keeping the code as concise as possible, and when copying the YAML for all the other cards that share this code.

type: custom:button-card
entity: sensor.office_multi_sensor_temperature
state_display: |
  [[[
    return localize(states['sensor.office_multi_sensor_temperature'])
  ]]]
styles:
  card:
    - height: 100%
    - width: 58px
    - padding: 0px 0px 0px 2px
  name:
    - text-transform: uppercase
    - font-size: 12px
    - font-weight: normal
    - justify-self: center
    - letter-spacing: 2px
    - padding: 0%
tap_action:
  action: none
show_icon: false
show_name: false
show_state: true
layout: name_state

The YAML above is for the temp card shown below:

image
RomRider commented 1 year ago

@alexruffell, for the state of the main entity, no need to use state_display at all. Optionally, you can force the number of decimals of the state of the main entity with numeric_precision: X

But you can do localize(entity) that would work too, but that's what button card does for you by default on the main entity, so it's useless in the state field but useful in other fields than the state (eg. label or custom_fields)

Protoncek commented 1 year ago

RomRIder, thanks for all! Thanks for explaining some of my problems! Here are two pictures of displaying card with v3.5.0 and with latest. Note that latter icons are partly hidden. image image

code for first one is this (others are similar): (note however that i made these cards quite a while ago when i didn't know so much about programming, so they might be somewhat" oddly" written... perhaps a better option is possible).

type: custom:button-card
name: CAME
size: 100%
tap_action:
  action: fire-dom-event
  browser_mod:
    service: browser_mod.popup
    data:
      style: |
        --popup-border-color: lime;
        --popup-border-width: 5px;
        text-align: center;
      content: |
        [[[
        if (states['binary_sensor.zunaj_vrata_odprta'].state =='off')
          return "ODPREM vrata CAME?"
        else
          return "ZAPREM vrata CAME?"
        ]]]
      right_button: JA itaq, ane!
      left_button: JOJ, NE! Prst mi je zdrsnu
      right_button_action:
        service: switch.toggle
        data:
          entity_id: switch.zunaj_odpiranje
      left_button_action:
        service: browser_mod.popup
        data:
          style: |
            --popup-border-color: lime;
            --popup-border-width: 5px;
            text-align: center;
          content: ...pol pa nič, ane?
          dismissable: true
          title: Ja, prav...
          timeout: 3000
hold_action:
  action: call-service
  service: |
    [[[
    if(states['switch.zunaj_stop'].state=='on')
    return "script.came_start"
    else
    return "script.came_stop"
    ]]]
double_tap_action:
  action: more-info
  entity: binary_sensor.zunaj_vrata_odpiranje
entity: switch.zunaj_odpiranje
show_icon: true
icon: |
  [[[
    if (states['binary_sensor.zunaj_vrata_odprta'].state =='off')
      return "mdi:gate"
    else
      return "mdi:gate-open"
  ]]]
show_label: true
label: |
  [[[
    if (states['switch.zunaj_stop'].state=='on')
      return "BLOKRIANA"
    if (states['binary_sensor.zunaj_vrata_odprta'].state =='off')
      return "ZAPRTA"
    if (states['binary_sensor.zunaj_vrata_zapiranje'].state =='on')
      return "ZAPIRANJE"
    if (states['binary_sensor.zunaj_vrata_odpiranje'].state =='on')
      return "ODPIRANJE"
   return "ODPRTA"
  ]]]
styles:
  card:
    - height: 65px
    - box-shadow: 0 0 0.30rem 0.2rem rgb(100,100,100)
  label:
    - font-size: 15px
    - font-weight: bold
  name:
    - font-size: 15px
    - font-weight: bold
style: |
  ha-card {
  {% if is_state('binary_sensor.zunaj_vrata_odpiranje', 'on') %}  
        background: cyan;
        --paper-item-icon-color: blue;
        {%elif is_state('binary_sensor.zunaj_vrata_zapiranje', 'on') %}  
        background: red;
        --paper-item-icon-color: lime;
        {%elif is_state('binary_sensor.zunaj_vrata_odprta', 'on') %}
        background: lime;
        --paper-item-icon-color: black;        
        {%else%} 
        background: black;
        --paper-item-icon-color: lime;        
        {% endif %};

  }

Regarding "not working popup" , here's the code:

type: custom:button-card
styles:
  card:
    - height: 75px
    - background-size: 100% 100%
    - box-shadow: inset 0 0 2px 4px red
    - background-image: |
        [[[
          if(states['sensor.trenutna_postaja_num'].state=="1")
            return 'url("/local/pictures/veseljak.jpg")'
        else
          if(states['sensor.trenutna_postaja_num'].state=="2")
            return 'url("/local/pictures/radio1.jpg")'              
        else
          if(states['sensor.trenutna_postaja_num'].state=="3")
            return 'url("/local/pictures/radio1-80ta.jpg")'              
        else
          if(states['sensor.trenutna_postaja_num'].state=="4")
            return 'url("/local/pictures/aktual.jpg")'
        else
          if(states['sensor.trenutna_postaja_num'].state=="5")
            return 'url("/local/pictures/ekspres.jpg")' 
        else
          return 'url("/local/pictures/protoncek.jpg")'
        ]]]
tap_action:
  action: fire-dom-event
  browser_mod:
    service: browser_mod.popup
    data:
      style: |
        --popup-border-color: lime;
        --popup-border-width: 40px;
        --popup-background-color: blue;
        --popup-max-width: 1600px;
      autoclose: true
      timeout: 10000
      content:
        type: vertical-stack
        cards:
          - type: custom:button-card
            name: 'Izberi postajo: '
            styles:
              card:
                - font-size: 100px
                - font-weight: bold
                - border-radius: 30px
                - color: white
                - background: blue
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                tap_action:
                  action: call-service
                  service: script.radio_dnevna_veseljak
                styles:
                  card:
                    - height: 100px
                    - background-image: url("/local/pictures/veseljak.jpg")
                    - background-size: 100% 100%
                    - box-shadow: |
                        [[[
                          if(states['sensor.trenutna_postaja_num'].state=="1")
                            return '0 0 10px 10px  red'
                          else
                            return 'none'
                        ]]]
              - type: custom:button-card
                tap_action:
                  action: call-service
                  service: script.radio_dnevna_ena
                styles:
                  card:
                    - height: 100px
                    - background-image: url("/local/pictures/radio1.jpg")
                    - background-size: 100% 100%
                    - box-shadow: |
                        [[[
                          if(states['sensor.trenutna_postaja_num'].state=="2")
                            return '0 0 10px 10px  red'
                          else
                            return 'none'
                        ]]]
              - type: custom:button-card
                tap_action:
                  action: call-service
                  service: script.radio_dnevna_dve
                styles:
                  card:
                    - height: 100px
                    - background-image: url("/local/pictures/radio1-80ta.jpg")
                    - background-size: 100% 100%
                    - box-shadow: |
                        [[[
                          if(states['sensor.trenutna_postaja_num'].state=="3")
                            return '0 0 10px 10px  red'
                          else
                            return 'none'
                        ]]]
              - type: custom:button-card
                tap_action:
                  action: call-service
                  service: script.radio_dnevna_aktual
                styles:
                  card:
                    - height: 100px
                    - background-image: url("/local/pictures/aktual.jpg")
                    - background-size: 100% 100%
                    - box-shadow: |
                        [[[
                          if(states['sensor.trenutna_postaja_num'].state=="4")
                            return '0 0 10px 10px  red'
                          else
                            return 'none'
                        ]]]
              - type: custom:button-card
                tap_action:
                  action: call-service
                  service: script.radio_dnevna_ekspres
                styles:
                  card:
                    - height: 100px
                    - background-image: url("/local/pictures/ekspres.jpg")
                    - background-size: 100% 100%
                    - box-shadow: |
                        [[[
                          if(states['sensor.trenutna_postaja_num'].state=="5")
                            return '0 0 10px 10px  red'
                          else
                            return 'none'
                        ]]]
RomRider commented 1 year ago

Could you create a new issue for this please, as this is unrelated and I'll forget it's here. Thanks

Protoncek commented 1 year ago

Sure...sorry about that...

Mariusthvdb commented 1 year ago

this no longer set precision on b14 even though helpers it set:

name: >
  [[[ return 'Vijver: ' + helpers.localize(states['sensor.vijver_thermometer_temperature']); ]]]
numeric_precision: 0

showing the 2 decimals once again:

Scherm­afbeelding 2023-07-26 om 13 38 18
RomRider commented 1 year ago

Yes, that's expected. localize doesn't use the numeric precision from the card anymore (there was a note I think in some of the release notes). You can do now:

name: >
  [[[ return 'Vijver: ' + helpers.localize(states['sensor.vijver_thermometer_temperature'], undefined, 'card'); ]]]
numeric_precision: 0

The third parameter is to set the numeric precision ('card' makes it use the one defined in the card, or you can set any number also). The dev README has been updated with examples ;)

Mariusthvdb commented 1 year ago

thanks that works. However, and I must be going daft here, so sorry for all of my questions, when I use the show_units: false option, it still shows then unit on that localized entity

or, if I try to set a units: X for that matter.

I did read the notes but am confused (cant make it happen..)

name: >
  [[[ return 'Vijver: ' + helpers.localize(states['sensor.vijver_thermometer_temperature'], undefined, 'card'); ]]]
numeric_precision: 0
show_units: false

could you please post a simple example of how to do that?

helpers.localize(entity, state?, numeric_precision?, show_units?, units?)

is the fixed order of options and

helpers.localize(states['sensor.temperature'], undefined, 1, undefined, 'Celcius')

considering that, I dont see how I managed to change the precision, as that 'card' option is set on the 'units'... unless that first 'undefined' is for the state? parameter, and the last 2 are simply left out?

testing a second 'card' for the show_units? options yield nothing either... arrgghh what am I not seeing:

helpers.localize(states['sensor.vijver_thermometer_temperature'], undefined,'card','card')

edit

wait, these dont take 'card' option:

helpers.localize(states['sensor.vijver_thermometer_temperature'], undefined,'card',undefined, 'Celsius')

or

helpers.localize(states['sensor.vijver_thermometer_temperature'], undefined,'card',false)

work...

RomRider commented 1 year ago

localize doesn't use the cards config (but for numeric_precision specifically). helpers.localize(states['sensor.temperature'], undefined, 1, false) will make the unit disappear. (first undefined is for the state parameter)

RomRider commented 1 year ago

Maybe I should do a localize which just uses the card config and a localizeMore with all those options :D

Mariusthvdb commented 1 year ago

I've just discovered that...

wouldn't be a bad idea though, also being able to use a 'card' wide option for those 2 (show_units and units)?

so we could set those on card level and apply to all other localized templates?

btw the units: should in fact be unit: ?

Mariusthvdb commented 1 year ago

Maybe I should do a localize which just uses the card config and a localizeMore with all those options :D

well, yes, I suppose that would be what I just suggested above: by default use the card options for those 3 parameters, unless set in the individual template. Imho, that would make a lot of sense, and be way simpler for the average button-card (user) if must be, under a localize object:

localize:
  numeric_precision: 2
  show_unit: true
  unit: 'unit'

and then simply use

[[[ helpers.localize(states['sensor.temperature'] ]]]

If no localize is set, use all defaults. if one needs individual options, use the format you have

helpers.localize(entity, state?, numeric_precision?, show_units?, units?)

with the undefined to skip one parameter

github-actions[bot] commented 1 year ago

:tada: This issue has been resolved in version 4.0.0 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket: