Optimize a value template with that has a lot of repeats?

So I’m working on updating one of my packages. Someone else here has done some good work that I’d like to incorporate. Problem (not really a problem), is that my door locks can have up to 30 codes, and I have muptiple locks Just was wondering if there was a better way to do something like this

        value_template: >
          {% if is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '0') %}
            Master Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '1') %}
            Person 1 Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '2') %}
            Person 2 Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '3') %}
            Person 3 Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '4') %}
            Person 4 Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '5') %}
            Person 5 Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '6') %}
            Person 6 Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '7') %}
            User Code Slot 7 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '8') %}
            User Code Slot 8 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '9') %}
            User Code Slot 9 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '10') %}
            User Code Slot 10 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '11') %}
            User Code Slot 11 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '12') %}
            User Code Slot 12 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '13') %}
            User Code Slot 13 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '14') %}
            User Code Slot 14 Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '15') %}
            Use'r Code Slot 15 Changed
          {% else %}
            N/A
          {% endif %}

The only thing changing is the alarm level which is the door code. If it’s a pain or makes it overly complex, then I’m good, just feel like there might be a way to say within a range, then use that number as a variable? I’ve done stuff like that in automations, but not in a sensor

Try something like (untested):

          {% if is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '0') %}
            Master Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and  states('sensor.front_door_db_alarm_level')|int >=1 and states('sensor.front_door_db_alarm_level')|int <=15 %}
            Person {{states('sensor.front_door_db_alarm_level')}} Code Changed
          {% else %}
            N/A
          {% endif %}
1 Like

Thank you, I will work on verifying but ended up with this, went from 60+ lines to this

        value_template: >
          {% if is_state('sensor.front_door_db_alarm_type', '112') and is_state('sensor.front_door_db_alarm_level', '0') %}
            Master Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '113') and is_state('sensor.front_door_db_alarm_level', '0') %}
            Master Code Duplicate
          {% elif is_state('sensor.front_door_db_alarm_type', '33') and is_state('sensor.front_door_db_alarm_level', '0') %}
            Master Code Deleted
          {% elif is_state('sensor.front_door_db_alarm_type', '112') and  states('sensor.front_door_db_alarm_level')|int >=1 and states('sensor.front_door_db_alarm_level')|int <=18 %}
            User {{states('sensor.front_door_db_alarm_level')}} Code Changed
          {% elif is_state('sensor.front_door_db_alarm_type', '113') and  states('sensor.front_door_db_alarm_level')|int >=1 and states('sensor.front_door_db_alarm_level')|int <=18 %}
            User {{states('sensor.front_door_db_alarm_level')}} Code Duplicate
          {% elif is_state('sensor.front_door_db_alarm_type', '33') and  states('sensor.front_door_db_alarm_level')|int >=1 and states('sensor.front_door_db_alarm_level')|int <=18 %}
            User {{states('sensor.front_door_db_alarm_level')}} Code Deleted
          {% else %}
            N/A
          {% endif %}

Can you put a value in another value. Like this for example

        value_template: >
          {% if is_state('sensor.front_door_db_alarm_type', '18') %}
           {% if is_state('sensor.front_door_db_alarm_level', '1') %}
            {{ states.input_text.door_keypad_1_name.state }}
          {% elif is_state('sensor.lock_garage_door_lock_alarm_level', '2') %}
            {{ states.input_text.door_keypad_2_name.state }}

Same goal as above, but I have 18 input texts, each with a persons name. Probably a bit too much to pull the value from the alarm level and then use that in the input text entity name.

Something like this: No nested if statements, fully expandable…

{% set number = states('sensor.front_door_db_alarm_level') %}
{% set sensor_codes = {'112':'Code Changed','113':'Code Duplicate','33':'Code Deleted'} %}
{% set sensor_code = states('sensor.front_door_db_alarm_type') %}
{% set code_status = sensor_codes[sensor_code] if sensor_code in sensor_codes else 'Code Error' %}
{% set user = 'Master' if number == '0' else 'User ' + number  %}
{{ user }} {{ code_status }}

for your second question:

{% set number = states('sensor.front_door_db_alarm_level') %}
{% set entity_id = 'input_text.door_keypad_' + number + '_name' %}
{{ states(entity_id) }}
2 Likes

That looks amazing. I have been seeing more and more of that kind of stuff lately. Has it always been an option, something that came out recently, or just the types of stuff I’m enquiring about, haha.

So if I understand the formatting, this would be my sensor

sensor:
  - platform: template
    sensors:
      front_door_report:
        friendly_name: 'Front Door Report'
        value_template: >
          {% set number = states('sensor.front_door_db_alarm_level') %}
          {% set sensor_codes = {'112':'Code Changed','113':'Code Duplicate','33':'Code Deleted'} %}
          {% set sensor_code = states('sensor.front_door_db_alarm_type') %}
          {% set code_status = sensor_codes[sensor_code] if sensor_code in sensor_codes else 'Code Error' %}
          {% set user = 'Master' if number == '0' else 'User ' + number  %}
          {{ user }} {{ code_status }}

      frontdoor_code:
        friendly_name: 'Front Door Code'
        value_template: >
          {% set number = states('sensor.front_door_db_alarm_level') %}
          {% set entity_id = 'input_text.door_keypad_' + number + '_name' %}
          {{ states(entity_id) }}

This is standard in pretty much any code language. It’s just adding 2 strings together. There are many ways to do this, some specific to jinja.

Correct. That should be it. You’ll get a new message now if your code isn’t 112,113, or 33: “User X Code Error” or “Master Code Error”.

Ahh, that makes sense. There are many other alarm levels other than 112, 113, and 33, but those are the three I care about for this template. I’ll have to do some real world testing on my locks tonight to see what comes up as my results.

I also realized that I need this

      frontdoor_code:
        friendly_name: 'Front Door Code'
        value_template: >
          {% set number = states('sensor.lock_front_door_deadbolt_alarm_level') %}
          {% set entity_id = 'input_text.door_keypad_' + number + '_name' %}
          {{ states(entity_id) }}

To also be tied to alarm type 19 or 18 (keypad lock or unlock),
{% if is_state(‘sensor.front_door_db_alarm_type’, ‘18’) %}

I think it wont work for me as is, but… not 100% sure either, haha. I’ll also see what kind of results I get when I get home

1 Like

What changes when it’s equal to that or not?

That’s the part I need to test. Maybe nothing. That is how my template was set up. Basically it pulled the name (input text), when a door was locked or unlocked with the keypad only. I believe that when the door is manually locked/unlocked the alarm level becomes null. But, it’s possible it will just stay as the last user, and my template as it was before is what caused it change.

Because you are using the states() method in both cases, if anything returns a ‘bad’ value, you’ll get ‘undefined’ as the state instead of errors. You should be good to go.

OK, Yeah, that sounds right. What about this one though

      front_door_report:
        friendly_name: 'Front Door Report'
        value_template: >
          {% set number = states('sensor.lock_front_door_deadbolt_alarm_level') %}
          {% set sensor_codes = {'112':'Code Changed','113':'Code Duplicate','33':'Code Deleted'} %}
          {% set sensor_code = states('sensor.lock_front_door_deadbolt_alarm_type') %}
          {% set code_status = sensor_codes[sensor_code] if sensor_code in sensor_codes else 'Code Error' %}
          {% set user = 'Master' if number == '0' else 'User ' + number  %}
          {{ user }} {{ code_status }}

below are other possible values, that are pretty common, that would not be tied to a code slot change. The 112, 113, and 33 values are much less common, but I was thinking it would be a good “audit” sort of template. Can I have it only update the sensor by just removing "else ‘Code Error’ "

other values

      frontdoor_action:
        friendly_name: 'Front Door Lock'
        value_template: >
          {% if is_state('sensor.lock_front_door_deadbolt_alarm_type', '9') %}
            Lock Jammed
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '17') %}
            Keypad Lock Jammed
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '18') %}
            Keypad Lock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '19') %}
            Keypad Unlock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '21') %}
            Manual Lock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '22') %}
            Manual Unlock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '23') %}
            HA Lock Jammed
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '24') %}
            HA Lock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '25') %}
            HA Unlock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '26') %}
            Auto Lock Jammed
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '27') %}
            Auto Lock
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '161') %}
            Lock Code Failure
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '167') %}
            Battery Low
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '168') %}
            Battery Critical
          {% elif is_state('sensor.lock_front_door_deadbolt_alarm_type', '169') %}
            Battery Low No Operate
          {% else %}
            HA Controlled
          {% endif %}
          

I’d just create a code dictionary and check to see if the code is in the dictionary. That’s what these 3 lines are doing:

          # create a dictionary of key:value pairs.
          {% set sensor_codes = {'112':'Code Changed','113':'Code Duplicate','33':'Code Deleted'} %}
          # get the key we want a value for.
          {% set sensor_code = states('sensor.lock_front_door_deadbolt_alarm_type') %}
          # if the key is in our dictionary, get the value, otherwise spit out a default value.
          {% set code_status = sensor_codes[sensor_code] if sensor_code in sensor_codes else 'Code Error' %}

Getting a item out of a dictionary is like getting a specific index value in a list. For example, i have a list set mylist = ['a','b','c'].

If I want to get out the first item, that’s index 0.

mylist[0]

would return a.

A dictionary is the same, accept instead of an index, you use a name:

set mydict = { 'a':'letter a', 'b': 'letter b','c':'letter c' }

so to get the value ‘letter a’, you need to call out the ‘a’ from the dictionary:

mydict['a']

which would return letter a.

so with your other thing, the code dictionary would change to:

          {% set sensor_codes = {
            '9':'Lock Jammed',
            '17':'Keypad Lock Jammed',
            '18':'Keypad Lock',
            '19':'Keypad Unlock',
            '21':'Manual Lock',
            '22':'Manual Unlock',
            '23':'HA Lock Jammed',
            '24':'HA Lock',
            '25':'HA Unlock',
            '26':'Auto Lock Jammed',
            '27':'Auto Lock',
            '161':'Lock Code Failure',
            '167':'Battery Low',
            '168':'Battery Critical',
            '169':'Battery Low No Operate'} %}

Thanks so much, but am I wrong thinking that I would be getting a lot of these.

if sensor_code in sensor_codes else 'Code Error' 

That’s what I meant by “error” not an actual HA error. probably 95% of my sensor codes will be the normal day to day. Code changes are not something that happen often but something I’d like to track. So I was hoping to ONLY update the template if the value was 112, 113 or 33. Otherwise nothing. I hope that makes sense.

hmm, not sure if templates can reference themselves but you could try this:

      front_door_report:
        friendly_name: 'Front Door Report'
        value_template: >
          {% set sensor_codes = {'112':'Code Changed','113':'Code Duplicate','33':'Code Deleted'} %}
          {% set sensor_code = states('sensor.lock_front_door_deadbolt_alarm_type') %}
          {% if sensor_code in sensor_codes %}
            {% set number = states('sensor.lock_front_door_deadbolt_alarm_level') %}
            {% set user = 'Master' if number == '0' else 'User ' + number  %}
            {{ user }} {{ sensor_codes[sensor_code] }}
          {% else %}
            {{ states('sensor.front_door_report') }}
          {% endif %}
1 Like

So, if I understand the logic, is this what would happen.
User code 1 slot if changed,
sensor.front_door_report - Value template changes to “User 1 Code Changed”

Then I use user code 1 to unlock the door
sensor.lock_front_door_deadbolt_alarm_type changes to 19 which is keypad unlock

sensor.front_door_report would just stay the same (if they can refrence themselves).

Do you think that would cause a new even in the history or logbook for the sensor? I’d think not, because it really did not “change”

Thanks so much, for all of this, and thanks for answering the questions, I’m learning quite a bit and appreciate the education

It would probably cause a new event.

I’m planning on getting 2 locks at some point, until then I don’t have too many definitive answers in terms of how Home assistant will behave.

1 Like

I’ll play around with these tonight if I get the chance, and let you know. You’ve given me enough info here to be dangerous. Maybe combining them all into a single “master report” would work. Basically just add all of the possible values into the data dictionary, but then add a little extra logic for the code changes/duplicate/deletes. That would probably solve my problem. It’s not 100% what I wanted, but I think with another sensor maybe, I could figure something out.

Thanks so much for the eductation!

1 Like

What do you think about this? It looks pretty good to me. I feel pretty excited to try it out. Should just be a catch all for all options.

      front_door_report:
        friendly_name: 'Front Door Report'
        value_template: >
          {% set number = states('sensor.lock_front_door_deadbolt_alarm_level') %}
          {% set sensor_codes = {
            '9':'Lock Jammed',
            '17':'Keypad Lock Jammed',
            '18':'Keypad Lock',
            '19':'Keypad Unlock',
            '21':'Manual Lock',
            '22':'Manual Unlock',
            '23':'HA Lock Jammed',
            '24':'HA Lock',
            '25':'HA Unlock',
            '26':'Auto Lock Jammed',
            '27':'Auto Lock',
            '32':'All Codes Deleted',
            '161':'Bad Code Entered',
            '162':'Lock Code Attempt Outside of Schedule',
            '167':'Battery Low',
            '168':'Battery Critical',
            '169':'Battery Too Low To Operate Lock'} %}
          {% set sensor_lock_codes = {
            '33':'Code Deleted',
            '112':'Code Changed',
            '113':'Duplicate Code'} %}
          {% set sensor_code = states('sensor.lock_front_door_deadbolt_alarm_type') %}
          {% if sensor_code in sensor_lock_codes %}
            {% set number = states('sensor.lock_front_door_deadbolt_alarm_level') %}
            {% set user = 'Master' if number == '0' else 'User ' + number  %}
            {{ user }} {{ sensor_lock_codes[sensor_code] }}
           {% elif sensor_code in sensor_codes % %}
             {{ sensor_codes[sensor_code] }}
          {% else %}
            Unknown Event {{ sensor.lock_front_door_deadbolt_alarm_type  }}
          {% endif %}