How to handle variable records in MQTT?

Hello

I am reading MQTT records from a device but this MQTT record can have one or two strings of data like this:

{"gwIntervalDatas":[{"utcEndtime":1643956800000,"sensorId":4,"index0Delta":39,"index1Delta":0,"temperature":154,"humidity":88,"battLevel":100,"version":1}]}
{"gwIntervalDatas":[{"utcEndtime":1643957100000,"sensorId":4,"index0Delta":11,"index1Delta":0,"temperature":151,"humidity":88,"battLevel":100,"version":1},{"utcEndtime":1643957100000,"sensorId":5,"index0Delta":5,"index1Delta":0,"temperature":140,"humidity":100,"battLevel":100,"version":1}]}

To load some data from these input in Home Assistant, I am using sensors with the following code:

- platform: mqtt
  state_topic: "servicelocation/8853e98f-b96e-4c14-8b60-32718b54f9f6/aggregatedGW"
  name: "Smappee Sensor Index 1"
  value_template: "{{ value_json.gwIntervalDatas[0].sensorId | int(default=0) }}" 

- platform: mqtt
  state_topic: "servicelocation/8853e98f-b96e-4c14-8b60-32718b54f9f6/aggregatedGW"
  name: "Smappee Sensor Index 2"
  value_template: "{{ value_json.gwIntervalDatas[1].sensorId | int(default=0) }}" 

but I am getting the following error if there is only one string of data:

2022-02-04 08:40:01 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: list object has no element 1 when rendering '{{ value_json.gwIntervalDatas[1].sensorId | int(default=0) }}'

I tried this but this is not working neither (same error):

- platform: mqtt
  state_topic: "servicelocation/8853e98f-b96e-4c14-8b60-32718b54f9f6/aggregatedGW"
  name: "Smappee Sensor Index 3"
  value_template: >
      {% if value_json.gwIntervalDatas[1].sensorId is defined %}
         "{{ value_json.gwIntervalDatas[1].sensorId | int(default=0) }}" 
      {% else %}
         {{ 6 }}
      {% endif %}

How to avoid this ā€œerrorā€ message ?

Thanks !

I finally found a work aroundā€¦ In case we have two strings of data in the same MQTT record, I should have a ā€˜},{ā€™ in the middle of the value_jsonā€¦ So I m testing that this string of characters is there in the value_json like this:

- platform: mqtt
  state_topic: "servicelocation/8853e98f-b96e-4c14-8b60-32718b54f9f6/aggregatedGW"
  name: "Smappee Sensor Index 2"
  value_template: >
      {%if '},{' in value_json %}
         "{{ value_json.gwIntervalDatas[1].sensorId | int(default=0) }}"   # two records 
      {% else %}
         {{ only one record }}
      {% endif %}

Done !

In case we have two strings of data in the same MQTT record, I should have a ā€˜},{ā€™ in the middle of the value_json but this is only working if the record is less than 255 charactersā€¦ and It is not my caseā€¦
So still no solutionā€¦

I finally found the solution by combining different tips found on HA forumā€¦
I am reading the record from MQTT (exceeding 255 characters) and than I split it based on the ā€˜}ā€™ character which is the last character of the first stringā€¦
Than I test if the second part of the record is not just equal to ā€˜]ā€™ (in this case, there is only one string in the record) and than I publish one or two new records to MQTT (after removing useless headers (
{ā€œgwIntervalDatasā€:[) and adding the necessary characters ā€˜{}ā€™ to be read as a json input in HA. Than I read them back in HA to create my sensorsā€¦

Here is the code for the automation:

- alias: read_smappee_record
  trigger:
    platform: mqtt
    topic: servicelocation/8853e98f-b96e-4c14-8b60-32718b54f9f6/aggregatedGW
  action:
    - variables:
        data: "{{ trigger.payload.split('}') }}"
    - service: mqtt.publish
      data:
        topic: 'homeassistant/smappee/record1'
        payload: '{{ (data[0])[20:] }}}'
    - condition: '{{ ((data[1])[0:1]) != "]" }}'
    - service: mqtt.publish
      data:
        topic: 'homeassistant/smappee/record2'
        payload: '{{(data[1])[1:]}}}'

By confirming the list contains more than one item before you attempt to access the second item.

The problem with the template is that it is checking if the key named sensorId is defined but itā€™s making an assumption that the gwIntervalDatas list contains more than one item (because it is referring to the second item in the list). If it doesnā€™t contain a second item, the template fails with an error (like the one you posted above).

I suggest replacing this:

  value_template: >
      {% if value_json.gwIntervalDatas[1].sensorId is defined %}
         "{{ value_json.gwIntervalDatas[1].sensorId | int(default=0) }}" 
      {% else %}
         {{ 6 }}
      {% endif %}

With this:

  value_template: >
      {{ value_json.gwIntervalDatas[1].sensorId | int(0) if value_json.gwIntervalDatas | count > 1 else 6 }}

It reports the value of the second list itemā€™s sensorId but only if the list contains more than 1 item. Otherwise it reports 6.

2 Likes