Same automations, different behavior, last_triggered not set at startup

hi,

have a python-script Summary which shows on/oflline status if entities in several groups. Switches, lights, etc.

time of change in these entities is set by last_triggered of an automation checking the state change of these entities.

Upon first run (after a reboot) and when all are off, the script shows the lights just fine (No lights on) but wont load the switches. When any entities are online, they show perfectly.

for as far as my eyes can check, scripts and automations are identical, so I wonder if the entity type has got something to do with the difference.

What could be the reason for this behavioral difference?

As a temporarily fix, I have created an automation that runs the sense_switches_change at startup unconditionally, to set the last_triggered, and that works alright. Still, that should not be necessary of course, and the underlying issue isnā€™t tackledā€¦
Apparently the lights automation gets set at startup and the others donā€™t. both are set to initial_state: 'on'.

automation:

- alias: 'Sense Lights change'
  id: '1511601488008'
#  hide_entity: True
  initial_state: 'on'
  trigger:
    platform: state
    entity_id: 'light.dining_corner,light.dining_table_lamp_1,light.dining_table_lamp_2,
                light.dining_table_lamp_3,light.kist,light.cabinet,light.home_theater,
                light.corridor_cabinet,light.bedside_table,light.lounge_chair_long,
                light.drawer,light.gamer_den,light.table,light.bureau,light.inside,
                light.outside,light.hue_go_1'
  condition: []
  action:
    - service: python_script.anything_on
    - delay: 00:00:02
    - service: python_script.summary

# Call Summary after Switches change
- alias: 'Sense Switches change'
  id: '1511601488009'
#  hide_entity: True
  initial_state: 'on'
  trigger:
    platform: state
    entity_id: 'switch.sw_audio_auditorium_template,switch.sw_tv_auditorium_template,
                switch.sw_espresso_keuken_template,switch.sw_tv_library_template,
                switch.sw_kantoor_template,switch.sw_audio_gym_template,
                switch.sw_tester_template,switch.sw_dorm_template'
  condition: []
  action:
    - service: python_script.anything_on
    - delay: 00:00:02
    - service: python_script.summary

python script relevant bit:

##########################################################################################
# Lights:
# Badges images: /config/www/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 = []
lights_picture = []
lights_uom = []

total_lights_on = hass.states.get('input_boolean.anything_on').attributes.get('lights_on')

if hass.states.get('automation.sense_lights_change').attributes.get('last_triggered'):
    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=2)
        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"])

    if len(lights_on) > 0:
        lights_picture = '/local/lights/hue_pl.png'
        lights_message = ', '.join(lights_on)
        sensor_lights_message = 'Lights on: ' +', '.join(lights_on)
        lights_desc = '=- Lights on: {} -- {} since {}'.format(total_lights_on,lights_message,time)
        lights_uom = 'Lights'

        if len(lights_on) == 1:
            lights_uom = 'Light'
    else:
        lights_picture = '/local/lights/bulboff.png'
        lights_message= ''
        sensor_lights_message= 'No lights on'
        lights_desc = '!|-> No lights on since {}'.format(time)
        lights_uom = 'Lights'

    sensor_lights_desc = '{}'.format(sensor_lights_message)

    hass.states.set('sensor.lights_badge', total_lights_on, {
#        'custom_ui_state_card': 'state-card-value_only',
        'text': sensor_lights_message,
        'unit_of_measurement': lights_uom,
        'friendly_name': time,
        'entity_picture': lights_picture
         })

##########################################################################################
# Switches:
# Badges images: /config/www/buttons
##########################################################################################
switches_group = 'group.iungo_switch_switches_template'
switches_message = []
sensor_switches_message = []
sensor_switches_desc = []
switches_desc = []
switches_on = []
switches_picture = []
switches_uom = []

total_switches_on = hass.states.get('input_boolean.anything_on').attributes.get('switches_on')

if hass.states.get('automation.sense_switches_change').attributes.get('last_triggered'): 
    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=2)
        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"])

    if len(switches_on) > 0:
        switches_picture = '/local/buttons/button_power_on.png'
        switches_message = ', '.join(switches_on)
        sensor_switches_message = 'Switches on: ' +', '.join(switches_on)
        switches_desc = '#- Switches on: {} -- {} since {}'.format(total_switches_on,switches_message,time)
        switches_uom = 'Switches'

        if len(switches_on) == 1:
            switches_uom = 'Switch'
    else:
        switches_picture = '/local/buttons/button_power_off.png'
        switches_message= ''
        sensor_switches_message= 'No switches on'
        switches_desc = '!|-> No switches on since {}'.format(time)
        switches_uom = 'Switches'

    sensor_switches_desc = '{}'.format(sensor_switches_message)

    hass.states.set('sensor.switches_badge', total_switches_on, {
#        'custom_ui_state_card': 'state-card-value_only',
            'text': sensor_switches_message,
            'unit_of_measurement': switches_uom,
            'friendly_name': time,
            'entity_picture': switches_picture
         })

anything_on script called in the python script above:

for entity_id in lightEntities:
    state = hass.states.get(entity_id)
  # filter out bulbs not on
    if (state.state == 'on'):
        if ('tradfri' not in state.name):
            lightStatus = 'on'
            lightsOn = lightsOn + 1

for entity_id in switchEntities:
    state = hass.states.get(entity_id)
    if (state.state == 'on'):
        lightStatus = 'on'
        switchesOn = switchesOn + 1

for entity_id in applianceEntities:
    state = hass.states.get(entity_id)
    if (state.state == 'on'):
        lightStatus = 'on'
        appliancesOn = appliancesOn + 1

if lightStatus == 'on':
    whichIcon = "mdi:lightbulb-on-outline"

totalOn = switchesOn + lightsOn + appliancesOn

# Return sensor state
hass.states.set('input_boolean.anything_on', lightStatus, { 
    'friendly_name': 'Anything On?',
    'icon': whichIcon,
    'lights_on': lightsOn,
    'switches_on': switchesOn,
    'appliances_on': appliancesOn,
    'total_on': totalOn,
    'extra_data_template':'{total_on}  on'
})

Man, You could avoid a lot of this headache by making methods instead of copying an pasting codeā€¦ Example:

def CountMyEntities(entity_list, entity_state, filter_out=''):
    cnt = 0
    for entity_id in entity_list:
        if filter_out in entity_id:
            continue
        else:
            state = hass.states.get(entity_id)
            if state.state == entity_state:
                cnt += 1
    return cnt

lightsOn = CountMyEntities(lightEntities, 'on', 'tradfri')
switchesOn = CountMyEntities(switchEntities, 'on')
appliancesOn = CountMyEntities(applianceEntities, 'on')

if lightsOn > 0:
    whichIcon = "mdi:lightbulb-on-outline"

totalOn = switchesOn + lightsOn + appliancesOn

etc.

That way, when you run into issues they affect all sections and you fix it in one place. That top section of code you posted is long, I suggest you put each piece (switch, light) into its own file text file. Then use a text file compare tool to look at the differences. I use diffmerge.

yes! thank you so much, youā€™re so right.
I did the copying to get started and be certain not to make mistakesā€¦ but am always looking to methodize repetitive patterns.

in my current setup/script, it is not so much the scenario following the ā€˜Ifā€™, more the scenario ā€˜if notā€™ā€¦ of course the script should be correct in all situations, having entities on or not at all.
But a safeguard apparently is needed just in case. Ive made the mentioned extra automation for now, but the script should be optimized for that (at leastā€¦)

Will test your code first, and see what happens. Thanks a million.

get this error though:

  File "whats_on.py", line 39, in CountMyEntities
NameError: name 'hass' is not defined

has to do with the tradfri i think, taking that out solves the issue and runs the script.

created a new sensor based on this new code, which runs (edit) not yet as expected thoughā€¦

the sensor created below a the bottom of the script shows the values created. They dont add up when entities are on. Doesnā€™t entity_list need to be defined as a list of lists of the mentioned entities? I donā€™t get any errors.

the state = 'on' I added for the sensor isnt switched to in either consequently.

switchEntities = ["switch.sw_audio_auditorium_template",
                  "switch.sw_tv_auditorium_template",
                  "switch.sw_espresso_keuken_template",
                  "switch.sw_dorm_template"]
lightEntities =  ["light.bedside_table",
                  "light.bureau",
                  "light.lounge_chair_long",
                  "light.outside"]

applianceEntities = ["switch.sw_boiler_bijkeuken_template",
                     "switch.sw_quooker_keuken_template"]

whichIcon = "mdi:lightbulb-outline"
status = 'off'

def CountMyEntities(entity_list, entity_state, filter_out=''):
    cnt = 0
    for entity_id in entity_list:
        if filter_out in entity_id:
            continue
        else:
            state = hass.states.get(entity_id)
            if state.state == entity_state:
                cnt += 1
                status = 'on'
    return cnt

lightsOn = CountMyEntities(lightEntities, 'on')
switchesOn = CountMyEntities(switchEntities, 'on')
appliancesOn = CountMyEntities(applianceEntities, 'on')

if lightsOn > 0:
    whichIcon = "mdi:lightbulb-on-outline"

totalOn = switchesOn + lightsOn + appliancesOn

hass.states.set('input_boolean.whats_on', status, { 
    'friendly_name': "What's On?",
    'icon': whichIcon,
    'lights_on': lightsOn,
    'switches_on': switchesOn,
    'appliances_on': appliancesOn,
    'total_on': totalOn,
    'extra_data_template':'{total_on} on'
})

Marius

No, you may have to pass hass to the countmyentities. I thought hass would be global, but aparently it isnā€™t. So just pass it as the first argument.

that error is specifically calling out ā€˜hass.states.get(entity_id)ā€™ inside CountMyEntities.

def CountMyEntities(hass, entity_list, entity_state, filter_out=''):
    .... same as before

lightsOn = CountMyEntities(hass, lightEntities, 'on')

ok, thanks, i understand.
if i fill in anything at all as 4th argument (filter_out) in the CountMyEntitities, this error pops up:

Log Details (ERROR)
Wed Apr 04 2018 14:20:19 GMT+0200 (CEST)

Error executing script: name '_inplacevar_' is not defined
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 "whats_on.py", line 44, in <module>
  File "whats_on.py", line 40, in CountMyEntities
NameError: name '_inplacevar_' is not defined

and, even when nothing is there, and no errors are reported, the script returns nothing, the input_boolean stays of and no entities are countedā€¦

22

its gotta be a string, I was mimicing your ā€˜tradafiā€™ string. Thats what the ā€˜ā€™ mean after filter, itā€™s expecting a string.

sure, understand that. But the thing is, when I enter a string, i get the error-message stated above. If i fill in nothing, and/or leave the ā€˜ā€™ in place no error message appears, no result eitherā€¦

That doesnā€™t make sense. Its a simple if statement. Where is _inplacevar_ coming from?

Please post your whole code. Please use mark up. use three ` before your code to use markup.

Happens when something is used as 4th argument in the line

lightsOn = CountMyEntities(hass, lightEntities, 'on','dining')

full code:

switchEntities = ["switch.sw_audio_auditorium_template",
                  "switch.sw_tv_auditorium_template",
                  "switch.sw_espresso_keuken_template",
                  "switch.sw_dorm_template"]
lightEntities =  ["light.bedside_table",
                  "light.bureau",
                  "light.cabinet",
                  "light.dining_corner",
                  "light.dining_table_lamp_1",
                  "light.dining_table_lamp_2",
                  "light.dining_table_lamp_3",
                  "light.lounge_chair_long",
                  "light.outside"]

applianceEntities = ["switch.sw_boiler_bijkeuken_template",
                     "switch.sw_quooker_keuken_template"]

whichIcon = "mdi:lightbulb-outline"
status = 'off'

def CountMyEntities(hass, entity_list, entity_state, filter_out=''):
    cnt = 0
    for entity_id in entity_list:
        if filter_out in entity_id:
            continue
        else:
            state = hass.states.get(entity_id)
            if state.state == entity_state:
                cnt += 1
                status = 'on'
    return cnt

lightsOn = CountMyEntities(hass, lightEntities, 'on','dining')
switchesOn = CountMyEntities(hass, switchEntities, 'on')
appliancesOn = CountMyEntities(hass, applianceEntities, 'on')

if lightsOn > 0:
    whichIcon = "mdi:lightbulb-on-outline"

totalOn = switchesOn + lightsOn + appliancesOn

hass.states.set('input_boolean.whats_on', status, { 
    'friendly_name': "What's On?",
    'icon': whichIcon,
    'lights_on': lightsOn,
    'switches_on': switchesOn,
    'appliances_on': appliancesOn,
    'total_on': totalOn,
    'extra_data_template':'{total_on} on'
})

Maybe continue doesnā€™t work in this? Iā€™ve never seen that error before. Iā€™m starting to think they implemented python scripts poorly.

Try this:

def CountMyEntities(hass, entity_list, entity_state, filter_out=''):
    cnt = 0
    for entity_id in entity_list:
        if not (filter_out in entity_id):
            state = hass.states.get(entity_id)
            if state.state == entity_state:
                cnt += 1
                status = 'on'
    return cnt

I mean, you could also filter the list out before passing it into the method:

switchEntities = ["switch.sw_audio_auditorium_template",
                  "switch.sw_tv_auditorium_template",
                  "switch.sw_espresso_keuken_template",
                  "switch.sw_dorm_template"]
lightEntities =  ["light.bedside_table",
                  "light.bureau",
                  "light.cabinet",
                  "light.dining_corner",
                  "light.dining_table_lamp_1",
                  "light.dining_table_lamp_2",
                  "light.dining_table_lamp_3",
                  "light.lounge_chair_long",
                  "light.outside"]

applianceEntities = ["switch.sw_boiler_bijkeuken_template",
                     "switch.sw_quooker_keuken_template"]

whichIcon = "mdi:lightbulb-outline"

def CountMyEntities(hass, entity_list, entity_state):
    cnt = 0
    for entity_id in entity_list:
        state = hass.states.get(entity_id)
        if state.state == entity_state:
            cnt += 1
    return cnt

filteredLightEntities = [ entity_id for entity_id in lightEntities if 'dining' not in entity_id ]

lightsOn = CountMyEntities(hass, filteredLightEntities, 'on')
switchesOn = CountMyEntities(hass, switchEntities, 'on')
appliancesOn = CountMyEntities(hass, applianceEntities, 'on')

if lightsOn > 0:
    whichIcon = "mdi:lightbulb-on-outline"

totalOn = switchesOn + lightsOn + appliancesOn
status = 'on' if totalOn > 0 else 'off'

hass.states.set('input_boolean.whats_on', status, { 
    'friendly_name': "What's On?",
    'icon': whichIcon,
    'lights_on': lightsOn,
    'switches_on': switchesOn,
    'appliances_on': appliancesOn,
    'total_on': totalOn,
    'extra_data_template':'{total_on} on'
})

gee, let me say i really appreciate your effortā€¦

unfortunately thereā€™s no change. No final result showing, and the same error if I put something in the filter_out.

try the other solution, FYI I reorganized some things because your globals were a little goofy.

Sorry, reorganized againā€¦

switchEntities = ["switch.sw_audio_auditorium_template",
                  "switch.sw_tv_auditorium_template",
                  "switch.sw_espresso_keuken_template",
                  "switch.sw_dorm_template"]
lightEntities =  ["light.bedside_table",
                  "light.bureau",
                  "light.cabinet",
                  "light.dining_corner",
                  "light.dining_table_lamp_1",
                  "light.dining_table_lamp_2",
                  "light.dining_table_lamp_3",
                  "light.lounge_chair_long",
                  "light.outside"]

applianceEntities = ["switch.sw_boiler_bijkeuken_template",
                     "switch.sw_quooker_keuken_template"]

def CountMyEntities(hass, entity_list, entity_state):
    cnt = 0
    for entity_id in entity_list:
        state = hass.states.get(entity_id)
        if state.state == entity_state:
            cnt += 1
    return cnt

filteredLightEntities = [ entity_id for entity_id in lightEntities if 'dining' not in entity_id ]

lightsOn = CountMyEntities(hass, filteredLightEntities, 'on')
switchesOn = CountMyEntities(hass, switchEntities, 'on')
appliancesOn = CountMyEntities(hass, applianceEntities, 'on')

totalOn = switchesOn + lightsOn + appliancesOn
whichIcon = "mdi:lightbulb-on-outline" if totalOn else "mdi:lightbulb-outline" # will evaluate "off" if totalOn == 0.
status = 'on' if totalOn else 'off' # will evaluate "off" if totalOn == 0.

hass.states.set('input_boolean.whats_on', status, { 
    'friendly_name': "What's On?",
    'icon': whichIcon,
    'lights_on': lightsOn,
    'switches_on': switchesOn,
    'appliances_on': appliancesOn,
    'total_on': totalOn,
    'extra_data_template':'{total_on} on'
})

almost dare not say, but no, no difference.
With this, i get the error, even when taking out the filter option completely, and change to lightEntities.

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 "whats_on.py", line 30, in <module>
  File "whats_on.py", line 25, in CountMyEntities
NameError: name '_inplacevar_' is not defined

the error keeps turning up.

move filteredLightEntities to the 3d line to see if that would move the error also, but that it didnt. SO it must be the CountMyEntities construction itself?

Error executing script: name '_inplacevar_' is not defined
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 "whats_on.py", line 29, in <module>
  File "whats_on.py", line 23, in CountMyEntities
NameError: name '_inplacevar_' is not defined

What line is line 23 in your file?

empty :wink:


typoā€¦

so fixed? If not, it appears to not like the line:

cnt += 1

no, not fixed.
what could be used instead of cnt +=1 ?