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

Working :slight_smile: , with restictions…
I updated the code at https://github.com/maattdiy/home-assistant-config/blob/master/python_scripts/summary.py#L162
I far as I can see the input_select don’t have last_triggered, but the automation have (automation.activity_change) so I get the date form there. The only downside is when the summary is called from the automation.activity_change, since the event is still running the last_triggered isn’t updated yet. But when other automations (device tracker, etc) call the summary it will be ok.
Or you could uncomment the alternative way (isn’t ok for me because I don’t use the time in friendly_name on badge).

summary4

yes!
this is working much better!

this is perfect, since the automation is always needed to make the input_select do anything at all isnt it? It is the automation that actually creates the action so taking that as source for the time display is an elegant solution.

09

Next we need to change the time display for the mode selection like this too, can we fit that in somehow in the mode selection section:

mode_desc = ''
state = hass.states.get('input_select.ha_mode')
# Get info
dt = datetime.datetime.now()
time = "%02d:%02d" % (dt.hour, dt.minute)

if (not state is None):
    hidden = False #if (state.state != 'Normal') else True
    
    hass.states.set('sensor.mode_badge', '', {
      'entity_picture': '/local/modes/{''}.png'.format(state.state.replace(' ','').lower()),
      'friendly_name': time, #was: ''
      'unit_of_measurement': 'Mode',
      'hidden': hidden,
      'order': order
    })

    if not hidden:
        mode_desc = '{}*{} activated at: {}\n'.format(summary, state.state, time)

because obviously that doesn’t work as it should now, showing the current time…

i am trying this now and see what will happen:

mode_desc = ''
state = hass.states.get('input_select.ha_mode')
# Get info
#dt = datetime.datetime.now()
#time = "%02d:%02d" % (dt.hour, dt.minute)

if (not state is None):
    hidden = False #if (state.state != 'Normal') else True
    if (state.state != 'Unknown'):
        dt = hass.states.get('automation.ha_mode_selection').attributes.get('last_triggered')
        if (not dt is None):
            time = "%02d:%02d" % (dt.hour, dt.minute)
    
    hass.states.set('sensor.mode_badge', '', {
      'entity_picture': '/local/modes/{''}.png'.format(state.state.replace(' ','').lower()),
      'friendly_name': time, #was: ''
      'unit_of_measurement': 'Mode',
      'hidden': hidden,
      'order': order
    })

    if not hidden:
        mode_desc = '{}*{} mode selected at: {}\n'.format(summary, state.state, time)

Also im +1 hour off in my timezone.
that should be changed in this definition .

in the group count ive managed it like this:

if (state.state in filter.split('|') or debug):
          dt = state.last_changed
          dt = dt + datetime.timedelta(hours=+1)
          time = '%02d:%02d' % (dt.hour, dt.minute)

can that be altered here too?

maybe this can point to a final solution:
i have 3 related sensors. last.command, activity_selection, and mode_selection. Put them for testing purposes in this alternative card:

26

the bottom 2, last_command and activity_selection are created outside of summary.py, and are correct, just out of the box :wink: taking into account system time i guess. mode_selection however, is created inside the summary.py and is off. Because the time definition in the python script is different and not based on the system time. Since the new activity line in the summary is also based on the python definition, it also shows off one hour on the summary card.

Should be fixable in a robust way, whithout having to hardcode for every instance of time needed in the summary. Compare for example with the times displayed behind the devices tracked in the in use and home badges. If we could somehow elevate that +1 timezone to the full script, and have all others inherit that?

anyways, as always:

thanks!
Marius

Nice.
Yes the time script in ha_mode should work (creating the automation.ha_mode_selection).
I think that the best way is always get from last_triggered. I started from that, but the lack of Imports in phyton script makes harder to transform the UTC to the local time. Every sigle way that I have tried needs a Imports. But this is in my todo list.

already had those didnt we? or do you have some other way to implement these mode changes??

automation:
  - alias: 'Mode selection'
    id: '1511601479005'
    hide_entity: True
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: input_select.ha_mode
    condition: []
    action:
      - service: python_script.summary

  - alias: 'Run script after mode selection' 
    id: '1511601479006'
    trigger:
      platform: state
      entity_id: input_select.ha_mode
    condition: []
    action:
      service_template: >
        {% if is_state ('input_select.ha_mode','Normal') %} script.mode_normal
        {% elif is_state ('input_select.ha_mode', 'Full house') %} script.mode_full_house
        {% elif is_state ('input_select.ha_mode','Kiosk') %} script.mode_kiosk
        {% elif is_state ('input_select.ha_mode', 'Developer') %} script.mode_developer
        {% endif %}

thinking of combining this into one automation, but not sure if that frustrates future building upon.

I dind’t had yet. I’ll add :ok_hand:

cool.
but how then did you change your mode/profile? only having a input_select doesn’t do anything does it??

Marius

well if anything,

this has killed the sensor.mode_badge … and summary card for that matter… time for a reboot maybe
what could be wrong in the code, preventing the creation of the badge and consequently summary card?

mode_desc = ''
state = hass.states.get('input_select.ha_mode')
# Get info
#dt = datetime.datetime.now()
#time = "%02d:%02d" % (dt.hour, dt.minute)

if (not state is None):
    hidden = False #if (state.state != 'Normal') else True
    if (state.state != 'Unknown'):
        dt = hass.states.get('automation.ha_mode_selection').attributes.get('last_triggered')
        if (not dt is None):
            time = "%02d:%02d" % (dt.hour, dt.minute)
    
    hass.states.set('sensor.mode_badge', '', {
      'entity_picture': '/local/modes/{''}.png'.format(state.state.replace(' ','').lower()),
      'friendly_name': time, #was: ''
      'unit_of_measurement': 'Mode',
      'hidden': hidden,
      'order': order
    })

    if not hidden:
        mode_desc = '{}*{} mode selected at: {}\n'.format(summary, state.state, time)

never mind the above, i believe it had to do with me calling the wrong automation.ha_mode_selection, that i had changed names just before that… (you might want to consider creating a way to show the card, but with a warning of some kind some elements could not be loaded. as it stands now, the card just doesn’t show, and one has to be very thoughtful where to start finding the cause…)

just letting you know:
for now ive found a way to show he correct times everywhere. Ive changed the activity.py to have the time triggered from the automation too, so that we’re sure both the python scripts use the same time sources.

# Get params
event = data.get('event')

# Get the state object from the name
state_value = hass.states.get('input_select.activity').state

    # Get info
    dt = hass.states.get('automation.activity_change').attributes.get('last_triggered')  #datetime.datetime.now()
    time = "%02d:%02d" % (dt.hour+1, dt.minute)

    # Sensor update
    hass.states.set('sensor.activity_badge', state_value, {
        'friendly_name': time, #state_value,
        'entity_picture': '/local/activities/{' '}.png'.format(state_value.replace(' ','').lower()),
        'unit_of_measurement': 'Act'
    })

Also, ive changed the time calculating by adding +1 for my timezone.

time = "%02d:%02d" % (dt.hour+1, dt.minute)

Ive done that both in summary.py and activity.py, so again, with are calculating the same time.

Final detail now: whenever i select a mode/profile, the time change isnt automatically updated. I can see the system registers, because the last_activity shows it immediately.

It is only after i also change an activity, the mode-time changes. It does so to the correct time, but only after an extra push.
Must recheck the mode-automation to see why that isnt happening.

Still, getting better with each iteration!

solved!
added delay to the mode automation and summary runs fine, updating the time correctly on the card:

utomation:
  - alias: 'Mode selection'
    id: '1511601479005'
    hide_entity: True
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: input_select.ha_mode
    condition: []
    action:
      - delay: 00:00:02
      - service: python_script.summary

somehow i had time= ‘?’ in the activity bit of Summary.py leading to an initial ? on the summary card at first run. Since it wasn’t in the mode definition and that works like it should, ive taken the ? out in the activity definition. Result: all is working and showing beautifully !

one discrepancy left: there’s a call to mode selection at start up, and a call in developer module. One of them could be taken out since they confuse the system somehow, and cause the card to show only the first mode selection time, not the latter.

Hope to have clinched it with this, and most of all, be of some help to you too…

Thanks Markus. a lot.

HI @mviezzer!

some new findings:

both the alarm_clock automations to call the Summary after a state change of the Alarm only run when they are set on/off.
Whne i charge the alarm time, this isnt triggering the state_change apparently.
Thus the shown time on the summary card only updates after a forced run of Summary, or when one of the other triggers triggers it…

Could these automations be changed, as to have the time-settings of the alarms trigger a state change too?

# Call Python:Summary after AlarmClock state change
  - alias: 'Sense Alarmclock_wd state-change and update Summary'
    id: '1511601479003'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: group.alarmclock_wd
    condition: []
    action:
      service: python_script.summary

# Call Python:Summary after AlarmClock state change
  - alias: 'Sense Alarmclock_we state-change and update Summary'
    id: '1511601479004'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: group.alarmclock_we
    condition: []
    action:
      service: python_script.summary 

Ive have experienced this behavior before, automations not seeing the states of all group.entities, but only of the group itself. Changed group to all individual entities of the group, and will see what happens (when my isp is back on again…)

# Call Python:Summary after AlarmClock state change
  - alias: 'Sense Alarmclock_wd state-change and update Summary'
    id: '1511601479003'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: 'sensor.alarmclock_wd_time_template, input_boolean.alarmclock_wd_enabled,
                 input_number.alarmclock_wd_hour, 
                 input_number.alarmclock_wd_minutegroup.alarmclock_wd'
    condition: []
    action:
      service: python_script.summary

# Call Python:Summary after AlarmClock state change
  - alias: 'Sense Alarmclock_we state-change and update Summary'
    id: '1511601479004'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: 'sensor.alarmclock_we_time_template,input_boolean.alarmclock_we_enabled,
                  input_number.alarmclock_we_hour, 
                  input_number.alarmclock_we_minutegroup.alarmclock_we'
    condition: []
    action:
      service: python_script.summary

HI @mviezzer

we previously discussed using the groups as entity_id or all members of those groups as separate entity_id’s.

i just stumbled on this post https://ledstripsandcode.blogspot.nl/2017/12/home-assistant-notify-when-light-was.html where the author Abilio Costa (that you @abmantis ?) mentions this phenomenon and solves it using the ‘anchor’ *lights_group_entities in is setting of a group of lights.

Maybe this could help (me) in my setup, but i thought it might be of interest to you too?

Anyways, when one wants to check the state of individual members of a group, this might very well be the answer i’ve been looking for.

Cheerio,
Marius

Could we use that also in the at home part of the Summary?
Id like to show
groups_desc = ['!Nobody home since: ', ‘’, ‘+System ok’]
been playing a bit with the time and groups_desc, but havent found a boring solution yet…

Don’t want to jeopardize the working summary as it is, but feel a simple addition should be possible in the declaration of the groups (and badges) section of Summary?

43

Cheers,
Marius

You’re welcome. Of cource, nice contributions and insights…

I think the only way is sending the current value, maybe using data_template: like you mention on the other thread.
I guess that is because the event is still running so you don’t have the new value updated yet.

This is nice, I’ll check it out.

Probably, checking for all devices and getting the max date for not_home. Or with an automation in device tracker state (if works properly for this). I’ll play around…

this works perfectly and immediately:

# Call Python:Summary after AlarmClock state change
  - alias: 'Sense Alarmclock_wd state-change and update Summary'
    id: '1511601479003'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: 'sensor.alarmclock_wd_time_template, input_boolean.alarmclock_wd_enabled,
                 input_number.alarmclock_wd_hour, 
                 input_number.alarmclock_wd_minute' #group.alarmclock_wd
    condition: []
    action:
      service: python_script.summary

# Call Python:Summary after AlarmClock state change
  - alias: 'Sense Alarmclock_we state-change and update Summary'
    id: '1511601479004'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: 'sensor.alarmclock_we_time_template,input_boolean.alarmclock_we_enabled,
                  input_number.alarmclock_we_hour, 
                  input_number.alarmclock_we_minute' #group.alarmclock_we
    condition: []
    action:
      service: python_script.summary

forgot to report back, sorry…

not really sure of course, but the logical bit has already been done,since Nobody Home is already showing. only need to show the time of that state change? No need to check all devices maybe?

I even think the last_changed is already there, my problem arose when trying to show that in the summary, and finding the right place in the code, not breaking the current code…

hmmm. suddenly ‘Nobody Home’ wont show up anymore when nobody is home :wink: or connected to wifi that is.

What is wrong here (sorry for the big code-snippet) ? I can’t find it. Only thing i’ve changed is the if debug: event addition. Could that be it??

group_desc = ''
summary = ''
idx = 0

if debug:
    event = data.get('event')
    logger.error("\n\nSUMMARY: " + str(event))

##########################################################################################
## Group count (people and devices)
## Groups config: https://github.com/maattdiy/home-assistant-config/blob/master/config/groups.yaml#L267
##########################################################################################

# Entities summary by group name
groups = ['group.family', 'group.hubs_pinged', 'group.critical_devices_threshold'] # Groups need to have same member_count
groups_format = ['{} at home: {}', '{} in use: {}', '!{} offline: {}'] # Message prefix
groups_filter = ['home', 'on|playing|home', 'off|idle|not_home'] # Filter to list
groups_badge = ['Home', 'In use', 'Status'] # 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] # Mininum count to show
groups_desc = ['!Nobody home since: ', '', '+System ok'] # Can set the default description, for use in case count = 0
groups_count = [0, 0, 0]

for group in groups:
    group_count = 0
    group_desc = ''

    for entity_id in hass.states.get(group).attributes['entity_id']:
        state = hass.states.get(entity_id)
        filter = groups_filter[idx]

        if (state.state in filter.split('|') or debug):
          dt = state.last_changed
          dt = dt + datetime.timedelta(hours=+1)
          time = '%02d:%02d' % (dt.hour, dt.minute)

          # If state changed in the past days show the date too
          if dt.date() < datetime.datetime.now().date():
              time = '{} {}'.format('%02d/%02d' % (dt.day, dt.month), time)

          group_count = group_count + 1
          group_desc = '{} {} ({}), '.format(group_desc, state.name, time)

    # Final format for this group
    if (group_count >= groups_min_show[idx]):
        if (group_count == 0):
            group_desc = groups_desc[idx]
        else:
            group_desc = groups_format[idx].format(group_count, group_desc[:-2])

        groups_desc[idx] = group_desc
        groups_count[idx] = group_count

    idx = idx + 1

Also, i found the following piece of python that would fit nicely into the summary, to get a first look at the house. Experimenting somewhat with this but not yet working in my setup.
What would you suggest to change to et it to work in the Summary, and add it to the lineup of current trackers?
The notify would be less necessary, but i use it now for testing purposes. Then again, in case of errors or Bugs, it might be useful to have a notification accompanying the badges? Just a thought.

lights_group = 'all_lights'
excluded = ['light.keyboard', 'light.gamers_den']

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

if len(entities_on) > 0:
    notification_title = "Some lights are on - Home Assistant"
    notification_message = "The following lights are on: " + ', '.join(entities_on)

    hass.services.call('notify', 'notify', {'title' : notification_title, 'message': notification_message})

Been experimenting a bit, starting to work as i would like to:

added this module (still needing fine detail of course, like adding the time)

##########################################################################################
## Lights_on
##########################################################################################
lights_group = 'group.all_lights'
excluded = ['light.custom_group_for_group',
            'light.custom_group_for_lights','light.custom_group_for_lights_2',
            'light.custom_group_for_lights_3','light.custom_group_for_lights_4',
            'light.group_for_wakeup','light.group_group5_huelabshalloween']

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

for entity_id in hass.states.get(lights_group).attributes['entity_id']:
    if hass.states.get(entity_id).state is 'on' and entity_id not in excluded:
        state = hass.states.get(entity_id)

if len(entities_on) > 0:

#     if (not state is None):
#         hidden = False #if (state.state != 'Normal') else True
#         if (state.state != 'Unknown'):
#             dt = hass.states.get('group.all_lights').attributes.get('last_changed')
#             if (not dt is None):
#                 time = "%02d:%02d" % (dt.hour+1, dt.minute)
#         if not hidden:
    lights_on_desc = "The following lights are on: " + ', '.join(entities_on)
    hass.states.set('sensor.lights_on', '', {
        'custom_ui_state_card': 'state-card-value_only',
        'text': lights_on_desc
     })

changed the Summary Card as follows:

## Add to final summary
summary = '{}\n{}\n{}\n{}\n{}'.format(summary, alarms_desc, mode_desc, activity_desc, lights_on_desc)

if show_card:
    hass.states.set('sensor.summary', '', {
        'custom_ui_state_card': 'state-card-value_only',
        'text': summary
    })

result:

25

learned we can also create notifications with this command:

if len(entities_on) > 0:
    notification_title = "Home Assistant - Some lights are on"
    notification_message = "The following lights are on: " + ', '.join(entities_on)
    hass.services.call('notify', 'marijn', {'title' : notification_title, 'message': notification_message})

At the moment i took that out again, because it notifies on each summary call… :wink:

anyways, thought i’d share.

Cheers,
Marius

thought id share the following progress:

##########################################################################################
## Lights_on
##########################################################################################
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 = []
lights_on_desc = []
entities_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:
        entities_on.append(hass.states.get(entity_id).attributes["friendly_name"])
        state = hass.states.get(entity_id)

if len(entities_on) > 0:

    lights_on_desc = '=Lights  ' +', '.join(entities_on)
else:
    lights_on_desc= '!No lights '


lights_message = '{} on since: {}'.format(lights_on_desc,time)
hass.states.set('sensor.lights_on', lights_on_desc, {
        'custom_ui_state_card': 'state-card-value_only',
        'text': lights_message,
        'unit_of_measurement': 'Lights',
        'friendly_name': time,
        'entity_picture': '/local/hue_pl.png'
     })

and:

summary = '{}\n{}\n{}\n{}\n{}'.format(summary, alarms_desc, mode_desc, activity_desc, lights_message)

Had to create a separate automation using all entities ( as opposed to using the group of all lights, or using a call_service on domain light). Time selection based in last_triggered of that automation.

0307

Id love to have the Lights On display with another font-color, and tried to change the custom_ui state_card_value_only.html and added

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

case "=": and

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

That won’t work though, and no matter which key I select, the frontend just shows the key, instead of the colored font.

Cheers,
Marius

Hello, thank you very much to ‘mviezzer’ for this great feature and to you ‘Marius’ for keeping it evolving. I’m having the same kind of issue with the 'Nobody Home’ wont showing up. Did you find a way to solve this problem?
I have updated the clock like you and it’s working fine for my harmony activity but for the users i still have a 2 hours delay. Any idea where can i change this?
Don’t know if it’s necessary but here is my complete summary.py and automations.yaml codes:

debug = False
show_badges = True
show_card = True

group_count = 0
group_desc = ''
summary = ''
idx = 0

if debug:
    event = data.get('event')
    logger.error("\n\nSUMMARY: " + str(event))

##################################################
## Groups summary (people and devices)
## Groups config: https://github.com/maattdiy/home-assistant-config/blob/master/config/groups.yaml#L267
##################################################

# Summary by groups
groups = ['group.users_tracker']
groups_format = ['{} at home: {}', '{} in use: {}', '!{} to check it out: {}'] # Message prefix
groups_filter = ['home', 'on|playing', 'off|not_home'] # Filter to list
groups_badge = ['Home', 'In use', 'Status'] # Badge 'belt' (unit_of_measurement)
groups_badge_pic = ['', '', 'ok|bug|critical'] # Pictures: none, on picure or a list of picture (in this case the picture position will match the count)
groups_min_show = [0, 1, 1] # Mininum count to show
groups_desc = ['!Nobody in home', '', ''] # Can set the default description, for use in case count = 0
#groups_desc = ['!Nobody in home', '', '+System ok']
groups_count = [0, 0, 0]

for group in groups:
    group_count = 0
    group_desc = ''
    
    for entity_id in hass.states.get(group).attributes['entity_id']:
        state = hass.states.get(entity_id)
        filter = groups_filter[idx]
        
        if (state.state in filter.split('|') or debug):
            dt = state.last_changed
            dt = dt + datetime.timedelta(hours=-2) # For time zone :( How to do native?
            time = "%02d:%02d" % (dt.hour+1, dt.minute)
            
            # If state changed in the past days show the date too
            if dt.date() < datetime.datetime.now().date():
                time = '{} {}'.format('%02d/%02d' % (dt.day, dt.month), time)
            
            group_count = group_count + 1
            group_desc = '{} {} ({}), '.format(group_desc, state.name, time)
    
    # Final format for this group
    if (group_count >= groups_min_show[idx]):
        if (group_count == 0):
            group_desc = groups_desc[idx]
        else:
            group_desc = groups_format[idx].format(group_count, group_desc[:-2])
        
        groups_desc[idx] = group_desc
        groups_count[idx] = group_count
        
    idx = idx + 1

##################################################
## Badges updates
## Badges images: https://github.com/maattdiy/home-assistant-config/tree/master/www/badges
##################################################

idx = 0
order = 2

if show_badges:
    for badge in groups_badge:
        if (badge != ''):
            entity_id = 'sensor.{}_badge'.format(badge.replace(' ', '').lower());
            hidden = False if (groups_count[idx] >= groups_min_show[idx] or debug) else True
            fname = groups_desc[idx] if debug else ' '
            picture = groups_badge_pic[idx].replace(' ', '').lower()
            
            # Check for picture X index/count
            if (picture != ''):
                list = picture.split('|')
                if (len(list) in [1, groups_count[idx]]):
                    picture = list[len(list)-1]
                else:
                    picture = list[groups_count[idx]]
                
                if (picture != ''):
                    picture = '/local/badges/{}.png'.format(picture)
            
            hass.states.set(entity_id, groups_count[idx], {
              'friendly_name': fname,
              'unit_of_measurement': badge, 
              'entity_picture': picture,
              'hidden': hidden,
              'order': order
            })
        
        order = order + 1
        idx = idx + 1

##################################################
## Alarm clock
## Package: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/alarmclock.yaml
##################################################

alarms_prefix = ['alarmclock_wd', 'alarmclock_we']
alarms_wfilter = ['1|2|3|4|5', '6|7']
alarms_desc = ''
idx = 0

for entity_id in alarms_prefix:
    state = hass.states.get('input_boolean.{}_enabled'.format(entity_id))
    if (not state is None):
        if (state.state == 'on'):
            # Show the alarm for the next day
            if (str(datetime.datetime.now().isoweekday()) in alarms_wfilter[idx].split('|')):
                state = hass.states.get('sensor.{}_time_template'.format(entity_id))
                alarms_desc = '{}{}, '.format(alarms_desc, state.state)
    idx = idx + 1

if (alarms_desc == ''):
    alarms_desc = '!Alarm clock is disabled'
else:
    alarms_desc = 'Alarm clock at ' + alarms_desc[:-2]

##################################################
## Profile/mode
## General package: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/profiles.yaml
## Developer package: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/developer.yaml
## Badges images: https://github.com/maattdiy/home-assistant-config/tree/master/www/profiles
##################################################

profile_desc = ''
state = hass.states.get('input_select.ha_mode')

if (not state is None):
    hidden = False if (state.state != 'Normal') else True
    
    hass.states.set('sensor.profile_badge', '', {
      'entity_picture':  '/local/profiles/{}.png'.format(state.state.replace(' ', '').lower()),
      'friendly_name': ' ',
      'unit_of_measurement': 'Mode',
      'hidden': hidden,
      'order': order
    })
    
    if not hidden:
        profile_desc = '*{} profile is activated'.format(state.state)

##################################################
## Activity
## Package: https://github.com/maattdiy/home-assistant-config/blob/master/python_scripts/activity.py
##################################################

activity_desc = ''
state = hass.states.get('input_select.harmony_hub')
time = '?'

if (not state is None):
    if (state.state != 'Unknown'):
        dt = hass.states.get('automation.activity_change').attributes.get('last_triggered')        
        if (not dt is None):
            time = "%02d:%02d" % (dt.hour+1, dt.minute)
        
        # Alternative way for time
        #time = hass.states.get('sensor.activity_badge').attributes.get('friendly_name')
        activity_desc = 'Activity: {} ({})'.format(state.state, time)

##################################################
## Summary update
## Custom card: https://github.com/maattdiy/home-assistant-config/blob/master/www/custom_ui/state-card-value_only.html
##################################################

for group_desc in groups_desc:
    if (group_desc != '' and not group_desc.endswith(': ')):
        summary = '{}{}\n'.format(summary, group_desc)

summary = '{}\n{}\n{}\n{}'.format(summary, alarms_desc, profile_desc, activity_desc)

if show_card:
    hass.states.set('sensor.summary', '', {
      'custom_ui_state_card': 'state-card-value_only',
      'text': summary
    })

###############################################################################
automation:
###############################################################################

  # Call service trigger (Script)
  - alias: 'Call Service Event (Script)'
    hide_entity: True
    initial_state: 'on'
    trigger:
      - platform: event
        event_type: call_service
        event_data:
          domain: script
    action:
      - delay: 00:00:02
      - service: python_script.summary
        data_template:
          entity_id: "{{ trigger.entity_id }}"

  # Call service trigger (Switch)
  - alias: 'Call Service Event (Switch)'
    hide_entity: True
    initial_state: 'on'
    trigger:
      - platform: event
        event_type: call_service
        event_data:
          domain: switch
    action:
      - delay: 00:00:02
      - service: python_script.summary
        data_template:
          entity_id: "{{ trigger.entity_id }}"
      
  # Time interval update (each 1 minute)
  - alias: 'Time interval updates'
    hide_entity: True
    initial_state: 'on'
    trigger:
      - platform: time
        minutes: '/1'
        seconds: 00
    action:
      - service: python_script.summary
        data_template:
          entity_id: "{{ trigger.entity_id }}"

I also get this errors related to the ‘last_cmd.py’ script in the log

2018-02-15 19:04:42 ERROR (SyncWorker_7) [homeassistant.components.python_script.last_cmd.py] Error executing script: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "last_cmd.py", line 23, in <module>
TypeError: 'NoneType' object is not callable
2018-02-15 19:04:42 ERROR (SyncWorker_3) [homeassistant.components.python_script.last_cmd.py] Error executing script: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "last_cmd.py", line 23, in <module>
TypeError: 'NoneType' object is not callable
2018-02-15 19:04:43 ERROR (SyncWorker_6) [homeassistant.components.python_script.last_cmd.py] Error executing script: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "last_cmd.py", line 23, in <module>
TypeError: 'NoneType' object is not callable
2018-02-15 19:04:43 ERROR (MainThread) [homeassistant.core] Timer got out of sync. Resetting
2018-02-15 19:04:45 ERROR (SyncWorker_18) [homeassistant.components.python_script.last_cmd.py] Error executing script: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "last_cmd.py", line 23, in <module>
TypeError: 'NoneType' object is not callable
2018-02-15 19:04:46 ERROR (SyncWorker_7) [homeassistant.components.python_script.last_cmd.py] Error executing script: 'NoneType' object is not callable
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/homeassistant/components/python_script.py", line 166, in execute
    exec(compiled.code, restricted_globals, local)
  File "last_cmd.py", line 23, in <module>
TypeError: 'NoneType' object is not callable

Any kind of help would be really appreciated

Thank you.

Yes, Nobody is showing again, it was a syntax error.

here’s my complete summary.py, ive changed several things, and added the lights section, working perfectly at the moment!

30

accompanying dashboard to check all went well:

44
Only thing i would love to see changed is a color for the lights in Summary card (cant seem to adapt the text-only html file doing so)

I have automations for the groups, rather then call the summary every 15 seconds or so. Works magic.

the error message for last_cmd, or any other .py file is because one of the mentioned objects isn’t available (yet). Not always very clear which one that is…

##########################################################################################
## https://github.com/maattdiy/home-assistant-config
## Screenshot: https://github.com/maattdiy/home-assistant-config/blob/master/screenshots/summary.png
## Script call: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/ha_triggers.yaml#L39

## Resources:
## https://home-assistant.io/components/python_script/
## https://home-assistant.io/docs/configuration/state_object/
##########################################################################################
debug = False
show_badges = True
show_card = True

group_count = 0
group_desc = ''
summary = ''
idx = 0

if debug:
    event = data.get('event')
    logger.error("\n\nSUMMARY: " + str(event))

##########################################################################################
## Group count (people and devices)
## Groups config: https://github.com/maattdiy/home-assistant-config/blob/master/config/groups.yaml#L267
##########################################################################################

# Entities summary by group name
groups = ['group.family', 'group.hubs_binary_pinged', 'group.critical_devices_state'] # Groups need to have same member_count
groups_format = ['+{} at home: {}', '{} in use: {}', '!{} offline: {}'] # Message prefix
groups_filter = ['home', 'on|playing|home', 'off|idle|not_home'] # Filter to list
groups_badge = ['Home', 'In use', 'Status'] # 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] # Mininum count to show
groups_desc = ['!Nobody home', '', '+System ok'] # Can set the default description, for use in case count = 0
groups_count = [0, 0, 0]

for group in groups:
    group_count = 0
    group_desc = ''

    for entity_id in hass.states.get(group).attributes['entity_id']:
        state = hass.states.get(entity_id)
        filter = groups_filter[idx]

        if (state.state in filter.split('|') or debug):
            dt = state.last_changed
            dt = dt + datetime.timedelta(hours=+1)
            time = '%02d:%02d' % (dt.hour, dt.minute)

          # If state changed in the past days show the date too
            if dt.date() < datetime.datetime.now().date():
                time = '{} {}'.format('%02d/%02d' % (dt.day, dt.month), time)

            group_count = group_count + 1
            group_desc = '{} {} ({}), '.format(group_desc, state.name, time)

    # Final format for this group
    if (group_count >= groups_min_show[idx]):
        if (group_count == 0):
            group_desc = groups_desc[idx]
        else:
            group_desc = groups_format[idx].format(group_count, group_desc[:-2])

        groups_desc[idx] = group_desc
        groups_count[idx] = group_count

    idx = idx + 1

##########################################################################################
## Badges updates
##########################################################################################

idx = 0
order = 2

if show_badges:
    for badge in groups_badge:
        if (badge != ''):
            entity_id = 'sensor.{}_badge'.format(badge.replace(' ', '').lower());
            hidden = False if (groups_count[idx] >= groups_min_show[idx] or debug) else True
            fname = groups_desc[idx] if debug else ' '
            picture = groups_badge_pic[idx].replace(' ', '').lower()

            # Check for picture X index/count
            if (picture != ''):
                list = picture.split('|')
                if (len(list) in [1, groups_count[idx]]):
                    picture = list[len(list)-1]
                else:
                    picture = list[groups_count[idx]]

                if (picture != ''):
                    picture = '/local/badges/{}.png'.format(picture)


            hass.states.set(entity_id, groups_count[idx], {
              'friendly_name': fname,
              'unit_of_measurement': badge, 
              'entity_picture': picture,
              'hidden': hidden,
              'order': order
            })

        order = order + 1
        idx = idx + 1

##########################################################################################
## Alarm clock
## Package: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/alarmclock.yaml
##########################################################################################

alarms_prefix = ['alarmclock_wd', 'alarmclock_we']
alarms_wfilter = ['1|2|3|4|5', '6|7']
alarms_desc = ''
idx = 0

for entity_id in alarms_prefix:
    state = hass.states.get('input_boolean.{}_enabled'.format(entity_id))
    if (not state is None):
        if (state.state == 'on'):
            # Show the alarm for the next day
            if (str(datetime.datetime.now().isoweekday()) in alarms_wfilter[idx].split('|')):
                state = hass.states.get('sensor.{}_time_template'.format(entity_id))
                alarms_desc = '{}{}, '.format(alarms_desc, state.state)
    idx = idx + 1

if (alarms_desc == ''):
    alarms_desc = '!Alarm clock is disabled'
else:
    alarms_desc = 'Alarm clock set at ' + alarms_desc[:-2]

##########################################################################################
## Mode:
## General package: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/profiles.yaml
## Developer package: https://github.com/maattdiy/home-assistant-config/blob/master/config/packages/developer.yaml
## Badges images: https://github.com/maattdiy/home-assistant-config/tree/master/www/profiles
##########################################################################################

mode_desc = ''
state = hass.states.get('input_select.mode')

# Get info
#dt = datetime.datetime.now()
#time = "%02d:%02d" % (dt.hour, dt.minute)

if (not state is None):
    hidden = False #if (state.state != 'Normal') else True
    if (state.state != 'Unknown'):
        dt = hass.states.get('automation.mode_selection').attributes.get('last_triggered')
        if (not dt is None):
            time = "%02d:%02d" % (dt.hour+1, dt.minute)

        hass.states.set('sensor.mode_badge',state.state, {
         'entity_picture': '/local/modes/{''}.png'.format(state.state.replace(' ','').lower()),
         'friendly_name': time, #was: ''
         'unit_of_measurement': 'Mode',
         'hidden': hidden,
         'order': order
          })
    if not hidden:
        mode_desc = '{}*{} mode selected at: {}\n'.format(summary, state.state, time)

##########################################################################################
## Activity:
##
##########################################################################################

activity_desc = ''
## Get activity description
state = hass.states.get('input_select.activity')
state_value = hass.states.get('input_select.activity').state
#time = '?'
# Get info
#dt = state.attributes.get('last_triggered')
#time = '%02d:%02d' % (dt.hour, dt.minute)

if not state is None:
    hidden = False #if (state.state != 'Normal') else True
    if state.state != 'Unknown':
        dt = hass.states.get('automation.activity_selection').attributes.get('last_triggered')
        if not dt is None:
            time = "%02d:%02d" % (dt.hour+1, dt.minute)
    if not hidden:
        activity_desc = '{}*{} activity selected at: {}\n'.format(summary, state.state, time)
        
        hass.states.set('sensor.activity_badge', state_value, {
            'friendly_name': time, #state_value,
            'entity_picture': '/local/activities/{' '}.png'.format(state_value.replace(' ','').lower()),
            'unit_of_measurement': 'Act'
            })

##########################################################################################
## 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_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_message = 'Lights on: ' +', '.join(lights_on) # was: 'Text' + ', '.join(entities_on)
else:
    lights_message= '!No lights on'
    sensor_message= 'No lights on'
sensor_lights_desc = '{}'.format(sensor_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_message,
        'unit_of_measurement': 'Lights',
        'friendly_name': time,
        'entity_picture': '/local/hue_pl.png'
     })

##########################################################################################
## Summary update
## Custom card: https://github.com/maattdiy/home-assistant-config/blob/master/www/custom_ui/state-card-value_only.html
##########################################################################################

for group_desc in groups_desc:
    if group_desc != '' and not group_desc.endswith(': '):
        summary = '{}{}\n'.format(summary, group_desc)

# original
# summary = '{}\n{}\n{}'.format(summary, alarms_desc, mode_desc)
## Add to final summary
summary = '{}\n{}\n{}\n{}\n{}'.format(summary, alarms_desc, activity_desc, mode_desc, lights_desc)

if show_card:
    hass.states.set('sensor.summary', '', {
        'custom_ui_state_card': 'state-card-value_only',
        'text': summary
    })