Assigning numeric value that was set a loop

My mission: To assign a numeric value in the last row of the script.

My problem: value: “{{ counter }}” in the code below does not get an numeric value from counter.

  - alias: "Count people at home"
    initial_state: true
    trigger:
      - platform: state
        entity_id:
        - device_tracker.galaxynote8
        - device_tracker.galaxynote8_2
    action:
      - service_template: >-
          {%- set counter = 0 %} 
          {%- for device in states.device_tracker %}
            {%- if device.state == "home" and
              (device.entity_id == "device_tracker.galaxynote8_2" or
              device.entity_id == "device_tracker.galaxynote8"  )  %}
              {%- set counter = counter + 1 %}  
            {%- endif %}
          {%- endfor %}      
            variable.set_variable
        data: 
          variable: count_pepole_home
          value: "{{ counter }}"

The code above is ment to count people at home and store the amount of people in a variable using the custom component Variable. That custom component works fine, so that’s not an issue here.

When this automation has ran and when i check variable.count_pepole_home in the entities list, it’s state is not the expected numeric value, it’s the string “{{ counter }}” , but of course without quotes. :slight_smile:

If both of us are at home, I’d like the value at the end of the script to be set to 2.

I guess the solution is quite simple when you know where to look. :slight_smile:
Any piece of advice or other kind of assistans would be very appreciated.

Instead of an automation you can simply use a template sensor to achieve the same.
Try like this:

sensor:
  - platform: template
    sensors:
      people_home_count:
        value_template: >-
          {{ states.device_tracker | selectattr('state', 'eq', 'home') 
          | selectattr('entity_id', 'in', ['device_tracker.galaxynote8_2','device_tracker.galaxynote8'])
          | list | count}}
2 Likes

There are multiple problems with your code:

  1. I’d do what Burningstone suggested unless there’s an insurmountable obstacle. But I’m going to go over the problems I’m seeing in your code nonetheless.

  2. If you want "{{ counter }}" to be interpreted you need a data_template, not data.

  3. Also the service you call seems to be constant, so you can use service there instead of service_template.

  4. The computation you have in service_template appears to me to be used only for the value data field you pass to the service. It should be moved to the value of the value field. AFAICT each template has its own scope. So if you set a variable in one template, it won’t be seen in other templates. So you have to have the computation where you use the result of that computation.

  5. You’re running into an annoying quirk of jinja: loops create their own scope, and setting a variable in a loop creates a new variable for that scope, which is lost when the scope ends. See this question on SO, for instance.

So something like:

    action:
      - service:  variable.set_variable
        data: 
          variable: count_people_home
        data_template:
          value: >-
            {%- set ns = namespace(counter=0) %} 
            {%- for device in states.device_tracker %}
              {%- if device.state == "home" and
                (device.entity_id == "device_tracker.galaxynote8_2" or
                device.entity_id == "device_tracker.galaxynote8"  )  %}
                {%- set ns.counter = ns.counter + 1 %}  
              {%- endif %}
            {%- endfor %}     
            {{ ns.counter }}

I’ve used the workaround of creating a namespace (set ns = namespace(...)) in order for the loop to have a lasting effect after its scope ends.

4 Likes

@Burningstone and @lddubeau , I can’t thank you enough. Both for the template-solution as well as for the correction of my code. It is when other forum members says “you’re totally wrong, here’s some other solutions” that me and others can learn how to do things right.

Again, thanks a lot!

2 Likes