Trying to understand json parsing

Hi !
First of all, two thumbs up to all the developpers of this amazing Home Assistant !
I have a problem understanding how to parse json dictionnary.
I have a sensor that returns a json payload with two values and I try to use both in a automation but it does not work. I used the Templates in home assistant to perform tests and here’s what I get

```
{% set my_test_json = {"Message": "Unknown due to HA restart", "Severity": "warning"} %}

{% set m_test_json = states.sensor.front_door_last_state.state %}

{{my_test_json}}
{{m_test_json}}

Result with the values : 
   Message: {{ my_test_json.Message }}
   Severity: {{ my_test_json.Severity }}

Result with the Sensor state 
   Message: {{ m_test_json.Message }}
   Severity: {{ m_test_json.Severity }}
```

And here is the result I get

```
{'Severity': 'warning', 'Message': 'Unknown due to HA restart'}
{"Message": "Unknown due to HA restart", "Severity": "warning" }

Result with the values : 
   Message: Unknown due to HA restart
   Severity: warning

Result with the Sensor state 
   Message: 
   Severity:
```

I should get the same result wheter I use the direct variable or the sensor result but not…
Could somebody help me ?
Thanks a lot !

Please provide the configuration of sensor.front_door_last_state.

Technically JSON requires double quotes.
jsonlint.com it a good site for validating JSON syntax.

You’re right but, in this case, that’s what Jinja2 produces when it evaluates this:

{% set my_test_json = {"Message": "Unknown due to HA restart", "Severity": "warning"} %}

{{my_test_json}}

here it is :slight_smile:

sensor:
  - platform: template
    sensors:
      front_door_last_state:
        friendly_name: Front Door Last Code
        entity_id:
          - sensor.frontlock_alarm_type
          - sensor.frontlock_alarm_level
        value_template: >-
          {% if is_state('sensor.frontlock_alarm_type', '19') %}
            {% if is_state('sensor.frontlock_alarm_level', '1') %}
              {"Message": "Unlocked by laurent", "Severity": "good" }
            {% elif is_state('sensor.frontlock_alarm_level', '2') %}
              {"Message": "Unlocked by Valerie", "Severity": "good" }
            {% elif is_state('sensor.frontlock_alarm_level', '3') %}
              {"Message": "Unlocked by Juliette", "Severity": "good" }
            {% elif is_state('sensor.frontlock_alarm_level', '4') %}
              {"Message": "Unlocked by Lucas", "Severity": "good" }
            {% elif is_state('sensor.frontlock_alarm_level', '5') %}
              {"Message": "Unlocked by Chloé", "Severity": "good" }
            {% elif is_state('sensor.frontlock_alarm_level', '6') %}
              {"Message": "Unlocked by Any and Hubert", "Severity": "good" }              
            {% elif is_state('sensor.frontlock_alarm_level', '7') %}
              {"Message": "Unlocked by Myriam and Hervé", "Severity": "good" }
            {% elif is_state('sensor.frontlock_alarm_level', '8') %}
              {"Message": "Unlocked by Agnès", "Severity": "good" }
            {% else %}
              {"Message": "Unlocked by an Untracked User Code", "Severity": "good" }              
            {% endif %}
          {% elif is_state('sensor.frontlock_alarm_type', '18') %}
            {"Message": "Locked via Outside Button", "Severity": "good" }
          {% elif is_state('sensor.frontlock_alarm_type', '21') %}
            {"Message": "Locked via Thumbturn", "Severity": "good" }
          {% elif is_state('sensor.frontlock_alarm_type', '22') %}
            {"Message": "Unlocked via Thumbturn", "Severity": "good" }            
          {% elif is_state('sensor.frontlock_alarm_type', '25') %}
            {"Message": "Wireless Unlock", "Severity": "good"}            
          {% elif is_state('sensor.frontlock_alarm_type', '24') %}
            {"Message": "Wireless Lock", "Severity": "good" }            
          {% elif is_state('sensor.frontlock_alarm_type', '9') %}
            {"Message": "Lock Jammed", "Severity": "danger" }            
          {% elif is_state('sensor.frontlock_alarm_type', '161') %}
            {"Message": "Tamper Alarm", "Severity": "danger" }            
          {% elif is_state('sensor.frontlock_alarm_type', '27') %}
            {"Message": "Auto Locked", "Severity": "good" }            
          {% else %}
            {"Message": "Unknown due to HA restart", "Severity": "warning" }            
          {% endif %}

I modified your sensor to work within my Home Assistant environment. Here is the sensor’s state as seen in the States page:
Screenshot%20from%202019-03-30%2010-30-31

The issue is that the sensor’s state looks like a JSON object but is actually just a string. That’s why your template, {{ m_test_json.Message }}, doesn’t work.

You are grabbing the state, which is a string. You need to turn it into json before accessing it.

{% set m_test_json = states.sensor.front_door_last_state.state | tojson %}
Result with the Sensor state 
   Message: {{ m_test_json.Message }}
   Severity: {{ m_test_json.Severity }}

EDIT: This won’t work. Back to drawing board.

I had tried tojson and it escapes all the quotations. I tried safe | json and that failed as well (i.e. made no difference).

FWIW, googling “Jinja2 convert string to JSON” didn’t produce anything usable. That’s where I got the idea to use tojson but it didn’t have the desired effect. I gave up trying … but it seems there must be an elegant way to do it.


EDIT

Kind of surprising there’s no filter to convert a well-formed JSON string into a JSON object. I know there’s a node in Node-red that does it.

So if you just rewrote your if else if statements to output comma separated values (without keywords) instead of json objects. I.e “message, severity”, You could do this:

{% set m_test_json = states.sensor.front_door_last_state.state.split(',') %}
Result with the Sensor state 
   Message: {{ m_test_json[0] }}
   Severity: {{ m_test_json[1] }}

Also, if you were feeling up to it, you could attempt to streamline your if statements so that there is less overhead if you have to add codes or names into your sensor. This is what I would use because you’d just need to add a code and a name, or a code and a statement.

sensor:
  - platform: template
    sensors:
      front_door_last_state:
        friendly_name: Front Door Last Code
        entity_id:
          - sensor.frontlock_alarm_type
          - sensor.frontlock_alarm_level
        value_template: >-
          {% set danger = [ 9, 161 ] %}
          {% set who = {
            1: 'laurent',
            2: 'Valerie',
            3: 'Juliette',
            4: 'Lucas',
            5: 'Chloé',
            6: 'Any and Hubert',
            7: 'Myriam and Hervé',
            8: 'Agnès',
            } %}
          {% set statements = {
            9: 'Lock Jammed',
            18: 'Locked via Outside Button',
            21: 'Locked via Thumbturn',
            22: 'Unlocked via Thumbturn',
            24: 'Wireless Lock',
            25: 'Wireless Unlock',
            27: 'Auto Locked',
            161: 'Tamper Alarm',
            } %}
            
          {% set alarm_type = states('sensor.frontlock_alarm_type') | int %}
          {% set alarm_level = states('sensor.frontlock_alarm_level') | int %}
          {% if alarm_type == 19 %}
            {% if alarm_level in who %}
              Unlocked by {{ who[alarm_level] }}, good
            {% else %}
              Unlocked by an Untracked User Code, good
          {% else %}
            {% if alarm_type in statements %}
              {{ statements[alarm_type] }}, {{ 'danger' if alarm_type in danger else 'good' }}
            {% else %}
              Unknown due to HA restart, warning
            {% endif %}
          {% endif %}
1 Like

There are Python commands for that. I think for a string json.loads([string_var]) would work.

I had hoped tojson worked in the same manner … unfortunately it doesn’t. It escapes the meaning of all quotes so you end up with this:

Yep, i assumed it worked too but it doesn’t.

  - platform: template
    sensors:
      front_door_last_state:
        friendly_name: Front Door Last Code
        entity_id:
          - sensor.frontlock_alarm_type
          - sensor.frontlock_alarm_level
        value_template: >-
          {% set danger = [ 9, 161 ] %}
          {% set who = {
            1: 'laurent',
            2: 'Valerie',
            3: 'Juliette',
            4: 'Lucas',
            5: 'Chloé',
            6: 'Any and Hubert',
            7: 'Myriam and Hervé',
            8: 'Agnès',
            } %}
          {% set statements = {
            9: 'Lock Jammed',
            18: 'Locked via Outside Button',
            21: 'Locked via Thumbturn',
            22: 'Unlocked via Thumbturn',
            24: 'Wireless Lock',
            25: 'Wireless Unlock',
            27: 'Auto Locked',
            161: 'Tamper Alarm',
            } %}
            
          {% set alarm_type = states('sensor.frontlock_alarm_type') | int %}
          {% set alarm_level = states('sensor.frontlock_alarm_level') | int %}
          {% if alarm_type == 19 %}

Good Idea Petro. I like your solution. Much more easy to read than the one I suggested !
I’m going to give your solution a try tomorrow and let you know !
I’m a home assistant beginner but I love it.

Thank you very much everybody for your help !
It’s really appreciated :smiley:

The sensor Works perfect (If someone needs to use this code, there is a {% endif %} missing).
now, i’m wondering how may I “parse” the sensor state in an automation.
I’d like to use the part before the comma as a message and the part after the comma for the color of the message I will send as a notification

1 Like

Ok, replying to my own question. The split function does the trick :slight_smile:
Just use {{ states.sensor.xxx.state.split(",")[0]}} or [1] for the part of the message before or after the comma !
Thank you a lot. I learned many things thanx to you today

1 Like

I am back to really wanting this functionality to work in templates. How hard is it to add a filter to the templating language? I’ll even attempt it myself.

1 Like

You’d have to fork home assistant and add the filter to this file:

Then get them to merge your change. Or you’d have to use your custom version of home assistant with the filter.

This was fairly straightforward. Here’s my PR:

Rooting for your PR to quickly run the gamut and get included in the next release. Like the recent inclusion of the expand filter, the from_json filter will open up new ways of solving old templating problems. :+1: