Count people that are home

What this error means:

expected an indented block in on statement: state = hass.states.get(entity_id)

Hi, very good python script.
Is it possible to filter some people by the friendly_name ?

Found it by myself

for entity_id in hass.states.entity_ids('device_tracker'):
  state = hass.states.get(entity_id)
  if state.name == 'XXXXX':
   continue
  if state.state == 'home':
			home = home + 1	

You can also use the persons:

home_count = 0
home_desc = ""
inuse_count = 0
inuse_desc = ""
summary = ""

for entity_id in hass.states.entity_ids('person'):
    state = hass.states.get(entity_id)
    if state.state == 'home':
        home_count = home_count + 1
        home_desc = home_desc + state.name + ', '

if home_count > 0:
    home_desc = str(home_count) + ' Personen: ' + home_desc[:-2]
else:
    home_desc = 'Niemand zu Hause'

summary = home_desc

hass.states.set('sensor.people_home', home_desc, {
    'friendly_name': 'Personen zu Hause'
})
1 Like

o dear this has been a long timeā€¦

evolved from the summary script quite extensively, and, using the people counter has become this in my setup:

familyEntities = 'group.family_home'
daughterEntities = 'group.daughters_home'
familyColor = ['grey',  # count_home = 0 #808080
               'steelblue',  # = 1
               'saddlebrown',      # = 2 #00f
               'gold',   # = 3 #fbd229
               'darkorange',    # = 4 #ff8700
               'maroon',     # = 5 #ff0f00
               'green']      # = 6

familyIcon = ['mdi:account-off',      # count_home = 0
              'mdi:account',          # = 1
              'mdi:account-multiple', # = 2
              'mdi:account-multiple-check', # = 3
              'mdi:account-group']    # > 3

utc_offset = hass.states.get('sensor.utc_offset').state
timeDifference = float(utc_offset)

def CountMyEntities(hass, entity_list, entity_state=None, not_state=None):
    cnt = 0
    for entity_id in hass.states.get(entity_list).attributes['entity_id']:
        state = hass.states.get(entity_id)
        if entity_state is not None and state.state == entity_state:
            cnt = cnt + 1
        if not_state is not None and state.state != not_state:
            cnt = cnt + 1
    return cnt


count_home = CountMyEntities(hass, familyEntities, 'home')
count_away = CountMyEntities(hass, familyEntities, not_state='home')


daughter_count_home =  CountMyEntities(hass, daughterEntities, 'home')
daughter_count_away =  CountMyEntities(hass, daughterEntities, not_state='home')

def NameMyEntities(hass, entity_list, entity_state=None, not_state=None):
    global timeDifference
    names = []
    for entity_id in hass.states.get(entity_list).attributes['entity_id']:
        state = hass.states.get(entity_id)
        dt = state.last_changed + datetime.timedelta(hours= timeDifference)
        time = '%02d:%02d' % (dt.hour, dt.minute)
        if entity_state is not None and state.state == entity_state:
            name = '{} ({})'.format(state.attributes['friendly_name'], time)
            names.append(name)
        if not_state is not None and state.state != not_state:
            name = '{} ({})'.format(state.attributes['friendly_name'], time)
            names.append(name)

    return names

home = NameMyEntities(hass,familyEntities,'home')
away = NameMyEntities(hass,familyEntities,not_state='home')


daughter_home = NameMyEntities(hass,daughterEntities,'home')
daughter_away = NameMyEntities(hass,daughterEntities,not_state='home')


familyCount = count_home + count_away
daughterCount= daughter_count_home + daughter_count_away

daughterIcon = familyIcon[daughter_count_home] if daughter_count_home <= 3 else familyIcon[-1]
whichIcon = familyIcon[count_home] if count_home <= 3 else familyIcon[-1]

# the % symbol is mod, that means it will cycle through the list and never get 'Index out of range'
icon_color = familyColor[count_home%len(familyColor)]
daughter_icon_color = familyColor[daughter_count_home%len(familyColor)]

hass.states.set('sensor.family_home',count_home,{
    'friendly_name':'Family Home?',
    'home':', '.join(home),
    'away':', '.join(away),
    'icon':whichIcon,
    'count_home':count_home,
    'count_away':count_away,
    'family_count':familyCount,
    'icon_color':icon_color
     })

hass.states.set('sensor.daughters_home',daughter_count_home,{
    'friendly_name':'Daughters Home?',
    'home':', '.join(daughter_home),
    'away':', '.join(daughter_away),
    'icon':daughterIcon,
    'count_home':daughter_count_home,
    'count_away':daughter_count_away,
    'daughter_count':daughterCount,
    'icon_color':daughter_icon_color
     })

does a few more things, guards for None entities, checks the correct time using sensor.utc_offset and customizes (because python created entities cant be customized using regular ha customize: )

2 Likes

Isnā€™t this easier to just use?

{{states.person|selectattr('state', '==', 'home')|list|count}}
2 Likes

I did the same and actually it works quite fine for meā€¦ just counting the persons at home of courseā€¦ YAMIL script works as sensor in my case, actually I would test a group with the ā€œexpandā€ function so that it would be easy to enlarge or reduce the group when necessary instead of listing person.person1ā€¦X in the sensor code.

Iā€™d suggest, yes :slight_smile:

Thanks, saved me the effort of working this out :grinning_face_with_smiling_eyes:

Using a recent version of Home Assistant it is even easier, as zones now have a state representing the number of persons in it:

{{ states('zone.home') | int }}
1 Like

Thanks. That is great, but not intuitive as to what is being counted. It could just as easily be counting areas. If I came back to it Iā€™d be wondering what that was :laughing:

But it is more efficient, especially when defining triggers on it. As the alternative template is iterating over states, I guess it reverts to polling to check for changes, whereas a single entitiy state is a simple event. And in the gui, it can be used without reverting to yaml / jinja.

As to intuitiveness, thereā€™s not that much zones do, other then checking if persons enter it. So what else could it truely be? Areaā€™s have no relation to zones.

1 Like

Well, it is in the document:
Zone - Home Assistant (home-assistant.io)

ā€¦ also mentioned in the release notes, with screenshots and examples:
2022.4 - Zones now have a state!
It counts people, even when you have multiple device trackers tying to different persons.

Obviously one could still do complex templating and scripting to fit whatever specific needs - there are many ways to skin a cat.

1 Like

Iā€™m old fashioned - I was taught that variables/states should have meaningful names like zone.person_home_count. But hey ho - the ā€˜modernā€™ way :frowning:

They briefly considered renaming ā€œstateā€ to ā€œnumber_of_persons_in_itā€ but that resulted on people staring at their lightbulbs to check there was no one there :crazy_face:

But you can name your zone entities anything you like, so that is not a problem. Only not home, but you could create an extra zone in the same place too. Although, that might lead to other trouble.