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

cool. fyi, ive already changed it into the code below, so i can show, and do so, the time below the Mode-Badge. The variable is there, now how to show it on the summary sensor.
Please note that i changed profile in mode, did that system-wide, so no confusion can be created elsewhere. In my setup there’s only activity and mode, no more profile or other variants :wink:

mode_desc = ''
state = hass.states.get('input_select.ha_mode')
# Get info
dt = datetime.datetime.now() #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
    
    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 was activated\n at: '.format(summary, state.state)
  • btw if would like the normal mode to be displayed also (have a nice HA icon for that) how would i ‘unhide’ this? Im confused by this syntax: hidden = False if (state.state != 'Normal') else True which seems to say that if state is Normal, hidden is False. So why wont it show then?

  • About Order: im not sure what is does, or put differently if to does what it is supposed to. I believed it to be responsible for ordering the badges, but that doesn’t seem to be very consistent? The badges keep being displayed in different ways. If its not very reliable, couldn’t we better take them out completely? making the code as efficient as possible.
    Ill try a bit more and report back, but please respond if im making big mistakes here.

Cheers,
Marius

Something like:
mode_desc = ‘{}*{} mode was activated at: {}\n’.format(summary, state.state, time)

Yes, same here.

You’re right, it supposed be the displayed order (the attribute exists in hass), but for some reason is not respected, and I get random orders too. Have to dig around…

Force hidden = False always instead of hidden = False if (state.state != ‘Normal’) else True (this is a phyton ternay operator, can be confusing at first look)

Note that is using the system time at the call, it will not be the correct mode time.For the right time you need the commented part (last_triggered), but this way, for me, has the timezone issue, not solved yet.

indeed!

53

i know, but ive added +1, so the timing seems to be perfect now for my zone

ok cool, confusing indeed. Been wanting to ask: thanks for the link, ill check and learn for these python programming

1 Like

the temporary measure ive used just now is take the most dangerous items out of the panel-iframe altogether and put them in a developer_link group of links. With ive put in the developer group made in the developer package…
a bit of a workaround, but effective nonetheless. Still hope that oneway we can slide the left panel put of span, preferably in kiosk mode of course> to be honest, i find it rather unexpected to slide the tabs out of picture, while these could most definitely be of use in Kiosk mode…

panel iframe before
58

in developer group now, only shown when developer mode is selected

1708

2 Likes

HI MArkus,
How you’re doing? Back again for a small question:
what i don’t get is why i need the automation:

- alias: 'Call Service Event (Switch)'
  id: '1511601488008'
  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

to get the mode selection to kick in correctly. As far as i can follow whats happening, this has nothing to do with a switch anywhere. I commented out the automation, and then the mode doesn’t switch visually (it does change in the last command and shows on the card…

Since summary is called very very often, and i think it is hogging the system, i was trying to take out as many redundant operations, and thought to be one of them… apparently not?

Please explain if you can?

Next to the family group, ive made 2 other groups for the summary. Both of these consist of binary sensors, that only change state when any entities in these groups go offline, which shouldn’t happen at all. In any case, state changes almost never occur, and i would have thought the summary py to be run only then.

On the contrary, it goes off every couple of seconds, and sometimes more than once in a second… must be some kind of loop, or maybe i have double automatons, im checking thoroughly.

If you could comment on the assumption of my binary sensors, please do.
Some of these binary sensors are built upon regulars sensor reading the output of power usage, which of course changes constantly. Might i be possible that that works through into these binary sensors? If i check the state inspector that doesn’t show.

A second thought: might it be that the ping command is constantly resulting in state changes? it gives the most reliable ‘home’ indication for the devices om tracking, but might be very processor intensive and create a lot of changes and thus calls to the summary.py?

Cheers,
Marius

Hi, did you have any news on that?
The automation should not impact on the mode selection. This automation only call the summary script on any switch change (on/off).
The ping and binary sensor also should not call the script…

You could try add the event info, like (last 2 lines):

  # 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:
          event: "{{ trigger.event }}"

And in the summary.py print the event info:

event = data.get(‘event’)
logger.error("\n\nSUMMARY: " + str(event))

HI MArkus!

Thanks for this.
The thing is I don’t have a switch anymore in the 3 groups of Summary, so this service trigger isn used for the summary card either. Ive commented it out for the moment, to make sure no unnecessary events take place in my HA setup.

there are 6 events triggering summary.py to run:

changes in the 3 groups: in my case a family group of devicetrackers, and 2 groups of binary sensors reading state on/off.
the mode selector
the activity selector
the alarm-clock

Ive got it all on the summary card with the exception of the activity selector, which i hope the above addition to the summary might take care of, maybe have to edit that a bit.

Where would we place this extra bit of code in the summary.py?

just this:

if i comment out the automation service trigger (switch), only the Home, In use and Activity badges are shown.
No Status and Mode Badge.

Also, the Summary card isn’t created.

enabling the automation again, makes things work as they should…

this is my code for now:

## Call service trigger (Switch)
- alias: 'Call Service Event (Switch)'
  id: '1511601488008'
  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

this is the error code:

2018-01-10 09:43:30 INFO (SyncWorker_3) [homeassistant.components.python_script] Executing summary.py: {}
2018-01-10 09:43:31 ERROR (SyncWorker_3) [homeassistant.components.python_script.summary.py] Error executing script: list index out of range
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 "summary.py", line 90, in <module>
  File "/usr/lib/python3.6/site-packages/RestrictedPython/Eval.py", line 35, in default_guarded_getitem
    return ob[index]
IndexError: list index out of range

At the firt line of the script.

It’s odd that only some items are updated…
Try to comment the automation and use a time based: home-assistant-config/config/packages/summary.yaml at master · maattdiy/home-assistant-config · GitHub
If this works is because the summary is not called ofen enough.

About the error, what is the code on line 35?

isn’t that referencing the eval.py? i wouldn’t know to be honest…?

it is very strange, but i think it was an underlying problem, not as much the summary.
I had changed several things in the developer module, added a group and a script, and thought that to be safe. reverted for now, and indeed i see the card back and the badges…

also, some of my binary sensors measuring subscribing to a mqtt state are off, which is very odd, since the objects are not off, and not publishing an off -state.

An in all, i suspect a communication issue between HA and the Mqtt publisher causing this to trickle through to the summary.

ok, and that would show the selected activity on the summary card?
preferably below the mode activation-line:

12

never mind Markus for now, my system collapsed, and i luckily had just backed up yesterday…
After a few anxious moments, (internal server error and worse) I managed to revert to that, and things are running fine as i write this (fingerscrossed)

still, id love the activity to show up in the summary card…

will experiment some further, hope you can follow suit.

building on the developer groups: would you know how to show these in a Tab/view created upon selecting the developer mode? Ive tried it with the view: yes, but then it always shows the tab. Empty when not in developer mode, with groups when in developer mode. Would like to have it only show the tab/view when in developer mode.

Cheers,
Marius

As far as I know it’s not possible right now, only groups can dinamically show/hide.

Get the activity (this is all new, place before the summary = ‘{}\n{}\n{}’.format(summary, alarms_desc, profile_desc)

 ## Get activity description
 state = hass.states.get('input_select.activity')
 activity_desc = 'Activity: {}'.format(state.state)

After that concat on the final summary. Replace the atual summary = ‘{}\n{}\n{}’.format(summary, alarms_desc, profile_desc for this:

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

cool! almost:

18

i need something like this for the activity also:

if not hidden:
mode_desc = ‘{}*{} mode was activated at: {}\n’.format(summary, state.state, time)
Can i just adapt and put in in?

Something like this, but i need to have a separate time selection for the activity. Now it sees the same time as the mode selection :wink:

25

##########################################################################################
## 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.ha_mode')
# Get info
dt = datetime.datetime.now() #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
    
    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 was activated at: {}\n'.format(summary, state.state, time)

 ######################################################################################
## Activity:
## 
####################################################################################
## Get activity description
state = hass.states.get('input_select.activity')
# Get info
dt = datetime.datetime.now() #state.attributes.get('last_triggered')
time = "%02d:%02d" % (dt.hour, dt.minute)

activity_desc = 'Activity: {} was selected at: {}\n'.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)

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

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

there are 2 things now:
the time just keeps up with the actual time, not the event time, fo both.

also the activity selection doesn’t trigger the summary card to update immediately, and needs an extra nudge somehow.
but, getting there!

Use dt = state.attributes.get(‘last_triggered’)

You will need create a automation for the input_select change, like:

automation:
  - alias: 'Activity change'
    hide_entity: True
    initial_state: 'on'
    trigger:
      - platform: state
        entity_id: input_select.activity
    action:
      - delay: 00:00:02
      - service: python_script.summary
        data_template:
          event: "{{ trigger.event }}"

Cool!
i already have this one, would it be best to combine that, or would you advise to make 2 separates?

  - alias: 'Activity selection'
    id: '1511601479001'
    hide_entity: True
    initial_state: 'on'
    trigger:
      platform: state
      entity_id: input_select.activity
    condition: []
    action:
      service: python_script.activity
      data_template:
        event: "{{ trigger.event }}"

btw, the python_script.activity takes care of the activity badge like this as you know:

# 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 = datetime.datetime.now() #state.attributes.get('last_triggered')
    time = "%02d:%02d" % (dt.hour, 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'
    })

shouldn’t i change the datetime.datetime.now also in last_triggered then? Somehow i feel we have double automations which interfere. Do we need both the python script and the automations?

Cheers,
Marius

an error:
File “summary.py”, line 168, in
TypeError: %d format: a number is required, not NoneType

line 168 is the time-line.:

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

activity_desc = 'Activity:{} was selected at: {}\n'.format(state.state, time)

must declare the time in a different formatting, because like this the activity and mode selection don’t get updated…

my activity selector is declared outside of the summary.py and gets its last_changed time updated correctly. The summary card wont take that time (yet) and uses the declaration in the summary itself so both the activity and mode(profile) selection times are the same, since there is no distinction between the two.

The question now is: how can we have the 2 selectors show the correct last_changed time on the badge, and in the summary_card.

Ive tried to take the mode/profile out of the summary, and vice versa, tried to put the complete activity in the summary, but was unsuccesful.

Asking you as my python wizard how this can be accomplished. I feel we’re almost there, only the last final touch is missing…

if using the dt = datetime.datetime.now() in the definition itself (both in summary for mode/profile and outside summary for activity) things run alright. It’s putting the 2 together that makes it difficult. Using the combination of

dt = state.attributes.get('last_triggered')
time = "%02d:%02d" % (dt.hour, dt.minute)

obviously doesn’t work since the formats are not equal giving the mentioned error. I don’t know how to change that though.

What i also don’t understand is why the system gives the number is required-error for the activity in Summary, but doesn’t so so for Mode or my separate Activity.py when using the double line:

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

if i inspect the state-inspector the input_select’s don’t have a last_triggered… the automations do have that so shouldn’t we be using that for displaying the time?
Cheers,
Marius

You can use the same automation, just adding another action service python_script.summary.

Yes and no. The automation is for capture the event (selection change) and call the script. And the python script generate the sensor with dinamically image name. Could be done in yaml with template but I think that with script is more natural and powerfull. Also you could avoid the python_script.activity, updating the sensor in the summary. I did a specific script (and in tihs case you will need an automation to call it) for a couple of reasons:

  • Not worry about timezones (last_triggered), since I get the actual clock time when the script is called.
  • Modular: Can work by itself. If we add in the summary and other user only want to use that, he will need a lot more effort.
  • I plan to improve the script like keep the actual activity and the last activity, send notification when specific
    activity starts, do different actions if activity starts day or night… Again this could be done in automations with template but for more complex rules I prefer script.

Of course if you start from the ground up there are many different ways to accomplish that… each one with advantages and disadvantages…

About the error and last_triggered:
I will try later on, but could be:

  • The attribute last_triggered really do not exists in input_select, in this case we need another work arround.
  • The first time the date is not set and throw an error (in tihs case a try will solve).

magic, thanks for your elaborate answer.

maybe a quick one for now: how come the time and datetime are no accepted together?
see above. If i would create a quick fix for the current summary, that would be the only thing.

(could of course get the time out of the card altogether, but i think it really adds to the value of the card:

19

if the time were to be correct of course :wink:

since the 2 (mode and activity selection) are in the same python script and in the current configuration get the same time, couldn’t we change their names entity specific?

something like dt_activity and dt_mode ? time_activity and time_mode. Would make it possible to distinguish the 2 from each other, and keep them together in the same python.py

I’m away from my dev env right now, but looking I see that the correct time is already in the friendly_name… so a quick fix would be sometinhg like:

# SINCE I DIDN'T TEST TRY EACH ONE
time = state.attributes.get('friendly_name')    # First try
time = state.friendly_name                      # Second try
activity_desc = 'Activity:{} was selected at: {}\n'.format(state.state, time)
1 Like