Summary card and badges for people, devices and status (with python script and custom card)

@mviezzer
HI Markus,

After trying just about anything in the customize department, trying to get the badges to show a condition based color (all is right show green_badge, attention show blue_badge, alert show red_badge (default)) I must conclude the badges or sensors can’t be customized?

They are top of the page sensors in my setup, showing on the front page, and the View/tab. I know top of the page badges are mentioned in custom-ui 26-1 update, but no further info is available…

If i try below code in the templating tool, it shows just fine, and the themes I call show fine too, when i set Hassio to that theme. Somehow i can not get to the sensors, created in this summary.py…

Please have a look, cause it could at the moment be the final touch to a very fine project thus far :+1:

Ive tried all version behind the ## comments also, unfortunately they wont result in the desired effect:

sensor.status_badge:
  templates:
    theme: >
       {%  if is_state('sensor.status_badge', '0') %} green_badge
       {% else %} default
       {% endif %}
#      if (state === 0) return 'green_badge'; else return 'default';

sensor.inuse_badge:
  templates:
    theme: >
       {%  if is_state('sensor.inuse_badge', '7') %} green_badge
       {% else %} default
       {% endif %}
#      if (state === 7) return 'green_badge'; else return 'default';
#        theme_template: "if (states.sensor.inuse_badge.state === 7) return 'green_badge'; else return null"

sensor.home_badge:
  templates:
    theme: >
      {%  if is_state('sensor.home_badge', '0') %} default
      {% else %} green_badge
      {% endif %}
#      if (state ==> 0) return 'green_badge'; else return 'default';
#     theme_template: "if (states.sensor.home_badge.state !== 0) return 'green_badge'; else return null"

Exactly. Dealing with web/linux is always safer use lower case and no spaces (or use underscore)

Cool, thanks. I’ll incorporate that.

This it will be a nice touch.
Already have my TO DO list growing, Try to do some updates this weekend.

Hi, badges theme working :slight_smile:

To work properly:

  1. The syntax should be in JavaScript (like in your #), not in Jinja2 (since runs on browser, not the server). I found in this page https://github.com/andrey-git/home-assistant-custom-ui/blob/master/docs/templates.md
  2. The sensor must pre exists to use customize (for example declared in sensor template instead of created by python). So I did the theme logic directly in summary.py, trying to simplify… so you don’t need create the customize and sensor template.

To implement:

  1. Create the themes green, purple, oragen, red… in frontend themes
  2. Update the summary py
    • See the new theme configuration (can use the theme name or an expression)
    • Apply the theme in here and here

WARNING: I rename the state-card-value_only to state-card-text, so be aware if you copy and paste… I think the new name fits better, since and i using in other sensors like the Quote of the day.

cool!

Thank you, this has been big search… finally solved! Ive seen that instruction in @andrey s page too of course, but couldn’t connect it here.

Now let’s play around with these themes, and create some nice logic!

I wanted to have the color follow the logic of the images. (0 offline: green_badge,1 offline: yellow_badge, 2 offline: orange_badge, more offline: red_badge) etc etc.

Since that would be too long for the configuration line, I declared it in a separate section/line and then imported it into the configuration line.
Especially considering the option to do that for the 3 badges, it would have built up some big chunk of if-,then-else code… :wink:

check:

groups_theme = [home_theme, in_use_theme, status_theme]

and:

home_theme = 'if (value == 0) return "black_badge";else if (value == 1) \
              return "yellow_badge";else if (value == 2) return "blue_badge"; \
                 else return "green_badge"'
in_use_theme = 'if (value == 0) return "red_badge";else if (value == 1) \
                 return "orange_badge";else if (value == 2) return "yellow_badge"; \
                 else return "green_badge"'
status_theme = 'if (value == 0) return "green_badge";else if (value == 1) \
                return "brown_badge";else if (value == 2) return "orange_badge"; \
                 else return "red_badge"'

btw: Is there a better way to wrap this over the lines than this? I’ve tried parenthesis etc, according to the python-style guide without the desired effect… https://www.python.org/dev/peps/pep-0008/#id19

please let me get back on 2 other searches:

  • I’d love to have the Nobody home line display the time too, but cant seem to get that done correctly. Im not sure where the best place of calculating that would be done in the summary.

  • im trying to have the summary card show some extra text-colors (eg my lights line in yellow) and also, try to display that in italics. If i add the color to the state-card-value_only like the other colors, it doesn’t work:

      <style is="custom-style" include="iron-flex iron-flex-alignment"></style>
      <style>
        .normal {
          @apply(--paper-font-body1);
          color: var(--primary-text-color);
          margin-left: 8px;
          text-align: left;
          line-height: 20px;
        }
        .bold {
          @apply(--paper-font-body1);
          color: var(--primary-text-color);
          font-style: italic;
          margin-left: 8px;
          text-align: left;
          line-height: 20px;
        }
        .red {
          @apply(--paper-font-body1);
          color: var(--google-red-500);
          margin-left: 8px;
          text-align: left;
          line-height: 20px;
        }
        .green {
          @apply(--paper-font-body1);
          color: var(--google-green-500);
          margin-left: 8px;
          text-align: left;
          line-height: 20px;
        }
        .yellow {
          @apply(--paper-font-body1);
          color: var(--google-yellow-500);
          margin-left: 8px;
          text-align: left;
          line-height: 20px;
        }
      </style>
      
      <template is="dom-repeat" items="[[computeStateDisplay(stateObj)]]">
        <div class$="[[computeClass(item)]]">[[computeItem(item)]]</div>
      </template>
      
    </template>
    

Cheers!
Marius

been having a go and a bit of fun…
ordered 8 badge_themes along severity, crowdedness or use-count. Take your pick.

home_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge";else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else return "green_badge"'
in_use_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge";else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else return "green_badge"'
status_theme = 'if (value == 7) return "red_badge"; else if (value == 6) \
              return "yellow_badge"; else if (value == 5) return "blue_badge"; \
              else if (value == 4) return "orange_badge"; else if (value == 3) \
              return "brown_badge";else if (value == 2) return "black_badge"; \
              else if (value == 1) return "grey_badge"; else return "green_badge"'

btw. Spent the better part of the morning debugging a horrid 404 error caused by the logger, according to the system log. one minor glitch in frontend_themes.yaml (light_grey, instead of lightgrey) and the whole Frontend wouldn’t load. This seems somewhat unrobust. Ridiculous infact such a minor error blocking the full system.

Anyways, backup again :wink:

new through-development:

just letting you know adding an extra sensor was easier than nothing, expanding on the blocks available in Summary.py.

Needed a at a glance overview of the media players in the house…added a few bits and pieces,et voila!

18

all i did was:

home_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge"; else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else return "green_badge"'
in_use_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge"; else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else return "green_badge"'
status_theme = 'if (value == 7) return "red_badge"; else if (value == 6) \
              return "yellow_badge"; else if (value == 5) return "blue_badge"; \
              else if (value == 4) return "orange_badge"; else if (value == 3) \
              return "brown_badge"; else if (value == 2) return "black_badge"; \
              else if (value == 1) return "grey_badge"; else return "green_badge"'
avg_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge"; else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else return "green_badge"'

# Entities summary by group name # Groups need to have same member_count
groups = ['group.family', 'group.hubs_binary_pinged', 'group.critical_devices_state', 'group.tracked_avg_summary'] 
groups_format = ['+{} at home: {}', '{} in use: {}', '!{} offline: {}', ' {} playing: {}'] # Message prefix
groups_filter = ['home', 'on|playing|home', 'off|idle|not_home', 'home|playing|on'] # Filter to list
groups_badge = ['Home', 'In use', 'Status', 'Playing'] # Badge 'belt' (unit_of_measurement)
groups_badge_pic = ['', '', 'ok|bug|critical', ''] # Pictures: none, one, or a list of pictures (in this case the picture position will match the count)
groups_min_show = [0, 0, 0,0] # Mininum count to show
groups_theme = [home_theme, in_use_theme, status_theme, avg_theme] # Theme template
groups_desc = ['!Nobody home', '', '+System ok', '+At ease'] # Can set the default description, for use in case count = 0
groups_count = [0, 0, 0,0]

might fiddle about with the options possible (badge_colors obviously ), but worked right out of the box. So cool.

Cheers,
Marius

somehow it does work now somewhat… One discrepancy is that where * should render bold text, it shows italic. grey, brown and blue are also not working yet. Why would that be?

.green {
        @apply(--paper-font-body1);
        color: var(--google-green-500);
        margin-left: 8px;
        text-align: left;
        line-height: 20px;
      }
      .yellow {
        @apply(--paper-font-body1);
        color: var(--google-yellow-500);
        margin-left: 8px;
        text-align: left;
        line-height: 20px;
      }
      .grey {
        @apply(--paper-font-body1);
        color: grey;
        margin-left: 8px;
        text-align: left;
        line-height: 20px;
      }
      .brown {
        @apply(--paper-font-body1);
        color: brown;
        margin-left: 8px;
        text-align: left;
        line-height: 20px;
      }
      .blue {
        @apply(--paper-font-body1);
        color: blue;
        margin-left: 8px;
        text-align: left;
        line-height: 20px;
      }

and

  computeClass: function (item) {
      switch(item.trim().substring(0,1)) {
      case "*": return "bold";
      case "!": return "red";
      case "+": return "green";
      case "=": return "yellow";
      case "%": return "grey";
      case "$": return "brown";
      case "#": return "blue";
      default:  return "normal";
      }
  },

ive expanded a bit, and changed the place in summary.py where to put the special characters. Depending on the syntax and logic of the building blocks the special characters need to go in the desc bit, or the groups at the top of the script.

real easy to test, because of the ‘hot’ effect of python scripts. So much easier than yaml needing to restart each time of a change…

Only wish left for now: show the time after "Nobody home since: ".

Cool.

things are progressing: fixed the state-card-text_only to show bold And italic (failed to show brown and grey still, working on that)

also, changed the theme selection a bit further, though it must be possible to do that smarter in a loop or so (separate thread on community: Smarter (shorter) template possible? loop in Python with help from @gpbenton …)

04

up_theme = 'if (value == 0) return "red_badge"; else if (value == 1) \
              return "yellow_badge"; else if (value == 2) return "blue_badge"; \
              else if (value == 3) return "orange_badge"; else if (value == 4) \
              return "brown_badge"; else if (value == 5) return "black_badge"; \
              else if (value == 6) return "grey_badge"; else if (value == 7) \
              return "green_badge"'

down_theme = 'if (value == 7) return "red_badge"; else if (value == 6) \
              return "yellow_badge"; else if (value == 5) return "blue_badge"; \
              else if (value == 4) return "orange_badge"; else if (value == 3) \
              return "brown_badge"; else if (value == 2) return "black_badge"; \
              else if (value == 1) return "grey_badge"; else if (value == 0) \
              return "green_badge"'

and

groups_theme = [up_theme, up_theme, down_theme, up_theme ]

Hi @Mariusthvdb, cool updates!

Addressing some issues, need more tests, but the main idea is there!
I change diferent places, so I will hint the key word for you to search in source or check the github diff.
Full summary py
Only diffs summary py

"Nobody home line since:"
I added dt_prevstate, to keep the last previous change, so will contains the time that the last person go out.

"Smarter (shorter) template possible? loop in Python"
I simplify adding the similar logic for conditional pictures (in status). So set themes in a list separed by | (the index in the “list” will the value considered to apply the theme). All in phyton, no need deal with JS.
Like: groups_theme = [‘entity_green’, ‘entity_purple’, ‘entity_green|entity_orange|entity_red’]
Search for theme

"failed to show brown and grey still, working on that"
Try the color in hex

sounds like the solution, but gives me this for now:

  File "summary.py", line 84, in <module>
TypeError: '>' not supported between instances of 'NoneType' and 'datetime.datetime'

line 84 being: if (state.last_changed > dt_prevstate):

maybe the last_changed wasn’t set yet somehow? or isn’t it recorded? I am really out of my options here, tried it all as far as i can imagine, no syntax errors at all. If i take out these 2 lines, the full script runs, and adds the ‘since : time’ to the 0 values. Its just this comparison that won’t pass the python logic…

27

btw: it shows this message now on all group items, while i needed it only on the Home group. Can this be adopted/change from a global setting to a setting for just one group?

i fail to understand why the used code isn’t correct while it is for the others used. I purposely used the codes of the imported ha_style…
your suggestion of Hex colors worked btw. As a second best option this will do. Still need an answer to understand why the first option won’t work, if only for educational purposes :wink:

Of course!. Magic!!
tried immediately, changed it a bit and taken the lists out again, and import them from this declaration i put above:

up_theme = '[red_badge|yellow_badge|blue_badge|orange_badge|brown_badge|black_badge|grey_badge|green_badge|default]'

down_theme = '[default|green_badge|grey_badge|black_badge|brown_badge|orange_badge|blue_badge|yellow_badge|red_badge]'

with:

groups_theme = [up_theme, up_theme, down_theme, up_theme, up_theme ]

it does work, though the reverse (down_theme) isn’t correct yet. Would you be able to have a look at that? I think it has to do with the fact my lists start with count =0?

hoped to establish something like this:

theme = ["red_badge","yellow_badge","blue_badge","orange_badge","brown_badge",\
             "black_badge","grey_badge","green_badge"]

groups_theme = ['return theme[value]', 'return theme[value]', 'return theme[len(theme)-value]', 'return theme[value]' ]  

(idea by @gpbenton)

duh…
no [ ]…

up_theme = ‘red_badge|yellow_badge|blue_badge|orange_badge|brown_badge|black_badge|grey_badge|green_badge’

down_theme = ‘green_badge|grey_badge|black_badge|brown_badge|orange_badge|blue_badge|yellow_badge|red_badge’

if there could be a simple way to reverse the theme, (instead of the second down_theme) that would make it even better.

about the colors in text-only_card: cant we just use these color codes? or these:https://github.com/PolymerElements/paper-styles/blob/master/color.html

must the codes used in the html file be defined anywhere else? i cant understand now why i can use the other colors, and only brown and grey are not shown. I don’t get an error at all, just a default font color.

HI @mviezzer,

just as with the customization if the badges themes, isn’t it possible to have these badges in a group, and show them as badges using state_card_mode: badges ?

Now that all creating badges is about to reach its final stages (…) embellishing and formatting is in order. really would love to have them put in a group showing the badges as shown above 36, and not like this…
37

I added a check… yes, some entity do not have the state.last_changed setted yet.

I added a way to configure that, it will only show when has the word "since’ (Nobody in home since )

My guess is brow and grey are not so basic colors like red, green, blue… so the engine (?) do not understand the names. Either way I usually set in hex, because most time I do not use blue BLUE, it’s blue-ish.

Not working because the badges are set in python (even using state_card_mode: badges). The other badges are working in groups… need find a way to workaround.

I didn’t implement that yet, but the idea is use a special char (like ‘<’) for indicate reverse order in the begining of theme string.

Ill check all of your developments… Cool.

made a few myself. Added 2 badges, and changed the presentation in Summary a bit. View at a glance is so much more revealing now:

23

accompanied with this in a simple dashboard (will add the other inputs also), gives a super control-center :wink:

26

the time settings in the 0 setting need checking, seems not to take the setting of the individual badges, but an all over time setting. Might be the error I spotted, will see if your correction takes that away.

What is was wondering is why the Nobody home doesn’t simply show the time even in case the count = 0 ? Wouldn’t that be even simpler?
one strange thing: if you log out a family member, but leave someone else, you don’t see that time of last change, only the time the member that is left is shown. Which of course isn’t the last change time…

Anyways, keep on developing :+1:

Cheers,
Marius

HI Markus!

Before, we discussed that all groups need the same entity count, and otherwise the summary wouldn’t run.
Only this week i discovered that isn’t necessary anymore! Which is one of my biggest wishes of all. I am so happy to tell you we can have any group in the summary card now, and are not forced to create special arranged groups. Which makes it so much more user friendly and usable!! Ive rearranged immediately, with great result!
Cool.

nice! took out the word ‘since’ in the group_des line, because it would show twice than in the summary :wink:

    if (group_desc.find(' since ') > 0): #if (group_desc != ''):
        dt = dt_prevstate + datetime.timedelta(hours=+1)
        group_desc = '{} {}'.format(group_desc, '%02d:%02d' % (dt.hour, dt.minute))

in my lights section, which works perfectly, showing lights time on and off, i use:

dt = hass.states.get('automation.sense_lights_change').attributes.get('last_triggered')

and

lights_desc = '{} since {}'.format(lights_message,time)

lights_message being either:

lights_message = '=- Lights on: ' +', '.join(lights_on)

or
lights_message= '!- No lights on'

Might we not try that for the badges too?
needs adapting for the various groups, and equally called automations of course something like

dt = hass.states.get(‘automation.sense_{{group_format}}_change’).attributes.get(‘last_triggered’)`

check:

48

full code if your interested, and copied that for my switches too:

##########################################################################################
## Lights:
##########################################################################################
lights_group = 'group.all_lights_only'
#show only lights, not light groups
excluded = ['light.custom_group_for_group','light.custom_group_for_lights_2']
lights_message = []
sensor_lights_message = []
sensor_lights_desc = []
lights_desc = []
lights_on = []
total_on = hass.states.get('input_boolean.anything_on').attributes.get('lights_on')

for entity_id in hass.states.get(lights_group).attributes['entity_id']:
    dt = hass.states.get('automation.sense_lights_change').attributes.get('last_triggered')
    dt = dt + datetime.timedelta(hours=+1)
    time = '%02d:%02d' % (dt.hour, dt.minute)

    if hass.states.get(entity_id).state is 'on' and entity_id not in excluded:
        lights_on.append(hass.states.get(entity_id).attributes["friendly_name"])
        state = hass.states.get(entity_id)

if len(lights_on) > 0:

    lights_message = '=- Lights on: ' +', '.join(lights_on) # was: 'Text' + ', '.join(entities_on)
    sensor_lights_message = 'Lights on: ' +', '.join(lights_on) # was: 'Text' + ', '.join(entities_on)
else:
    lights_message= '!- No lights on'
    sensor_lights_message= 'No lights on'
sensor_lights_desc = '{}'.format(sensor_lights_message)
lights_desc = '{} since {}'.format(lights_message,time)
hass.states.set('sensor.lights_badge', total_on, {
#        'custom_ui_state_card': 'state-card-value_only',
        'text': sensor_lights_message,
        'unit_of_measurement': 'Lights',
        'friendly_name': time,
        'entity_picture': '/local/hue_pl.png'
     })
##########################################################################################
## Switches:
##########################################################################################
switches_group = 'group.iungo_switch_switches_template'
switches_message = []
sensor_switches_message = []
sensor_switches_desc = []
switches_desc = []
switches_on = []
total_on = hass.states.get('input_boolean.anything_on').attributes.get('switches_on')

for entity_id in hass.states.get(switches_group).attributes['entity_id']:
    dt = hass.states.get('automation.sense_switches_change').attributes.get('last_triggered')
    dt = dt + datetime.timedelta(hours=+1)
    time = '%02d:%02d' % (dt.hour, dt.minute)

    if hass.states.get(entity_id).state is 'on' and entity_id not in excluded:
        switches_on.append(hass.states.get(entity_id).attributes["friendly_name"])
        state = hass.states.get(entity_id)

if len(switches_on) > 0:

    switches_message = '#- Switches on: ' +', '.join(switches_on) 
    sensor_switches_message = 'Switches on: ' +', '.join(switches_on) 
else:
    switches_message= '!- No switches on'
    sensor_switches_message= 'No switches on'
sensor_switches_desc = '{}'.format(sensor_switches_message)
switches_desc = '{} since {}'.format(switches_message,time)
hass.states.set('sensor.switches_badge', total_on, {
#        'custom_ui_state_card': 'state-card-value_only',
        'text': sensor_switches_message,
        'unit_of_measurement': 'Switches',
        'friendly_name': time,
        'entity_picture': '/local/switch.png'
     })

that would be great indeed. Considering the functionality of the summary, I’ve called the 2 themes off_line and on_line, the first ‘counting’ up from 0 to 7 , the latter counting down obviously. Thus reflecting the ‘health’ of the system in signifying colors.

HI,

Had some fun today tweaking the settings, and adding a few badges with dedicated groups to monitor. A complete system at a glance, with colors and symbols in sync with the functional values.

0815

btw @mviezzer, how can i split this over 2 lines in the python script? the \ doesn’t work alright, stopping the list there, while it should continue:

this works fine, but is too long:

on_theme ='red_badge|yellow_badge|grey_badge|blue_badge|orange_badge|brown_badge|black_badge|green_badge'

No place to put the …

have a fine weekend, thanks!
Marius

hi @mviezzer

i noticed you started using the state-card-mode: badges.
Any luck with that? Ive also given it a try and put all badges in a card, but no effect at all…

Hi, just for testing purposes, no luck yet…

I see, same here. Ive tried to badge these sensors through customize, but that didn’t work either…
Made my way with it, and show them either on the top of the page, or changed the attributes to be of better use in a regular card for some of them:

quite satisfying as it is, still, always interested in follow-up development :+1: