Extract value from json

I have a rest sensor reading from a camera. It is creating the json as a state

In the template editor I can see the value:

{% set my_test_json = states('sensor.motion_test') %}
{{ my_test_json }}

Which returns:

[
   {
      "cmd" : "GetMdState",
      "code" : 0,
      "value" : {
         "state" : 0
      }
   }
]

I just don’t seem to be able to extract the state…

How about this in the restful sensor config:

value_template: '{{ value_json.value.state }}'

Error rendering template: UndefinedError: ‘str object’ has no attribute ‘value’

I wonder if it is because ‘value’ is a reserved word.

Try:

value_template: '{{ value_json.[2].[0] }}'

same error.
You can use
{% set my_test_json = [ { “cmd” : “GetMdState”, “code” : 0, “value” : { “state” : 0 } } ] %}
{{ my_test_json.[2].[0] }}

is you want to try a few things.

1 Like

Got it.

{{ my_test_json.0.value.state }}

It was the top level list ‘[…]’ stuffing it up.

1 Like

f’k me! I swear I have been screwing around for f’king HOURS

1 Like

Always handy to have an extra pair of eyes. This place is great for that.

1 Like

Also tried removing the [ and ] with replace but doesn’t work. Also tried string…
nope.

This is eerily familiar:

The string is coming from here:

  - platform: rest
    resource: http://192.168.1.44/api.cgi?cmd=GetMdState&user=admin&password=xxxxx
    name: motion_test

@pnbruckner @petro feel free to weigh in.

Try this:

{{ states('sensor.motion.test') |regex_findall_index('\d', index=1) }}

Tom’s solution will always get the 2nd digit, I.E. The digit after the word state. If the shape of the object changes, that won’t work. If you wan’t to ensure that you always get the state…

{% set value = my_test_json | regex_findall_index('\"state\" : \d+', index=0) %}
{{ value.split(':')[-1].strip() }}

This is finding the first instance of the phrase "state" : <number>. Then, we split the returned value on the colon. Select the last value (the number), and remove the extra white space.

EDIT: This of course assumes that the state is a string. If you change your rest sensor… you can have it just plop out that value.

  - platform: rest
    resource: http://192.168.1.44/api.cgi?cmd=GetMdState&user=admin&password=xxxxx
    name: motion_test
    value_template: "{{ value_json[0].value.state }}"
    json_attributes:
      - 0

This should put the whole object as a 0 attribute. Don’t know if that portion will work, never tried it. If it does work, your attributes will be accessible as json object too.

Last EDIT: I think we need a PR that depreciates json_attributes and replaces it with json_attributes_template, like MQTT sensors. There are too many of these topics that return a list of objects and that would require a template to extract.

1 Like

Thanks @petro
Is there a way I can make the rest sensor write the whole text string like a normal rest sensor rather than just that one attribute?

don’t think so, that’s why we need an update to json_attributes as a template.

What I don’t understand… in Tom’s example he used index 1 and you use index 0 - this is very fuzzy… both work but I’m not 100% sure I understand why… (well I’m 100% sure I don’t understand actually)

What if I wanted the value of the cmd or code?

Because my expression was very sloppy and returned 2 results. Petro’s regex is more exact and will only return one result.

hmm… ok… what if I want the value of “cmd” - even from the docs I don’t understand what the regex_findall_index is doing

FWIW, you can use a capturing group within the regex pattern to pluck out the desired value directly.

{{ my_test_json | regex_findall_index('\"state\" : (\d+)')  }}

The regex pattern is:

  • \"
    escape the meaning of a double-quote and match it
  • state
    match the literal word state
  • \"
    escape the meaning of a double-quote and match it
  • :
    match literal space followed by a colon followed by another space
  • (\d+)
    everything matched within the parentheses will be captured. The pattern within the parentheses will match one or more digits.

So if fed a string like this:

blablabla"state" : 12345abcdefg

it will return 12345

When given your example, it returns 0 as shown in the following screenshot from regex101.com

1 Like

so \d+ means it’s looking for digits? what if I wanted text? like the value of “cmd”?

just saw your edit… I’ll play on that site there! thanks.

{{ my_test_json | regex_findall_index(\"cmd\" : \"(\w+)\"')  }}

1 Like