Help converting template to json

I’ve been bitten by the new move to templates returning their native types. I think…

I’ve used hass-variables by @rogro82 for a long while now.

it has an option to create attributes by templates but the templates need to be in valid json format.

this used to work perfectly fine in the older versions before the templates update since it is valid json (also verified with an online json validator):

attributes_template: >
            {
              "history_1": "{{ states('variable.last_motion') }}",
              "history_2": "{{ state_attr('variable.last_motion','history_1') }}",
              "history_3": "{{ state_attr('variable.last_motion','history_2') }}",
              "history_4": "{{ state_attr('variable.last_motion','history_3') }}"
              }

now with the recent templates update I get the following error in the logs and the automation fails to run:

2020-11-18 19:31:20 ERROR (MainThread) [homeassistant.components.automation.as_update_last_motion] While executing automation automation.as_update_last_motion
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/automation/__init__.py", line 426, in async_trigger
    await self.action_script.async_run(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 1010, in async_run
    await asyncio.shield(run.async_run())
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 245, in async_run
    await self._async_step(log_exceptions=False)
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 253, in _async_step
    await getattr(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 460, in _async_call_service_step
    await service_task
  File "/usr/src/homeassistant/homeassistant/core.py", line 1402, in async_call
    processed_data = handler.schema(service_data)
  File "/usr/local/lib/python3.8/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
  File "/usr/local/lib/python3.8/site-packages/voluptuous/schema_builder.py", line 594, in validate_dict
    return base_validate(path, iteritems(data), out)
  File "/usr/local/lib/python3.8/site-packages/voluptuous/schema_builder.py", line 432, in validate_mapping
    raise er.MultipleInvalid(errors)
voluptuous.error.MultipleInvalid: template value should be a string for dictionary value @ data['attributes_template']

The error says the template should return a string but I don’t want it to return a string. I want it to return json. If I force the template to return a string by inserting a " | string" at the end I don’t get that error but instead I then get the following because the component expects json:

2020-11-18 20:03:28 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/config/custom_components/variable/__init__.py", line 219, in async_set_variable
    attributes = json.loads(
  File "/usr/local/lib/python3.8/json/__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.8/json/decoder.py", line 340, in decode
    raise JSONDecodeError("Extra data", s, end)

Any idea how I would force the template to return json and stop the string error?

@Mariusthvdb I believe you also use the same automation since I’m pretty sure I stole the automation from you. Have you run into this and/or solved it?

yes we have:

automation:
# Update Last Motion variable
  - alias: Update Last Motion
    id: Update Last Motion
    trigger:
      platform: state
      entity_id:
        - binary_sensor.laundry_sensor_motion
        - binary_sensor.dining_table_sensor_motion
...
        - binary_sensor.guest_room_sensor_motion
        - binary_sensor.dorm_sensor_motion
...
        - binary_sensor.parking_trash_buiten_sensor_motion
      to: 'on'
    condition:
      >
        {{trigger.to_state is not none and
          trigger.from_state is not none and
          trigger.to_state.state != trigger.from_state.state}}
    mode: restart
    action:
      - delay:
          seconds: 2
      - service: variable.set_variable
        data:
          variable: last_motion
          attributes:
            history_1: "{{states('variable.last_motion')}}"
            history_2: "{{state_attr('variable.last_motion','history_1')}}"
            history_3: "{{state_attr('variable.last_motion','history_2')}}"
            history_4: "{{state_attr('variable.last_motion','history_3')}}"
            history_5: "{{state_attr('variable.last_motion','history_4')}}"
            history_6: "{{state_attr('variable.last_motion','history_5')}}"
            history_7: "{{state_attr('variable.last_motion','history_6')}}"
            history_8: "{{state_attr('variable.last_motion','history_7')}}"
            history_9: "{{state_attr('variable.last_motion','history_8')}}"
            history_10: "{{state_attr('variable.last_motion','history_9')}}"
          value: >
            {{trigger.to_state.name|replace(' sensor motion','')}}:
            {{as_timestamp(trigger.to_state.last_changed)|timestamp_custom('%X')}}

read up on that here: https://github.com/rogro82/hass-variables/issues/47

btw, using the @Wibias forked version right now since @Rogro82 seems to have abandoned the repo.

2 Likes

That’s awesome. Thanks!

I looked at the issues there but didn’t see it because it had been closed already.

I’ve updated to the new repo now with the changes noted there and everything is back to working again.

Resolved, started working after a reboot.

Not sure if this is no longer supported, but not able to set attributes using template like below.

Any ideas?

        variable: last_water_motor
        attributes:
            {
              "last_on": "{{ states.switch.motor.last_changed }}",
              "last_off": ""
            }
        value_template: "{{ relative_time(now()) }}"

I see the below wrong state, should be a value.