Pulling my hair out - payload_json array item comparison

Help! I’m literally at my wits end trying to figure out something that I thought would be relatively simple. I am using Frigate’s frigate/reviews MQTT topic as an automation trigger to send out a notification. I am trying to build logic to only pull certain objects detected in a review topic.

An example message:

trigger:
  id: '0'
  idx: '0'
  alias: null
  platform: mqtt
  topic: frigate/reviews
  payload: >-
    {"type": "end", "before": {"id": "1740765619.832969-b4tgkm", "camera":
    "doorbell", "start_time": 1740765619.832969, "end_time": null, "severity":
    "detection", "thumb_path":
    "/media/frigate/clips/review/thumb-doorbell-1740765619.832969-b4tgkm.webp",
    "data": {"detections": ["1740765616.092773-ja4l4g"], "objects": ["car"],
    "sub_labels": [], "zones": [], "audio": []}}, "after": {"id":
    "1740765619.832969-b4tgkm", "camera": "doorbell", "start_time":
    1740765619.832969, "end_time": 1740765622.916183, "severity": "detection",
    "thumb_path":
    "/media/frigate/clips/review/thumb-doorbell-1740765619.832969-b4tgkm.webp",
    "data": {"detections": ["1740765616.092773-ja4l4g"], "objects": ["car"],
    "sub_labels": [], "zones": [], "audio": []}}}
  qos: 0
  description: mqtt topic frigate/reviews
  payload_json:
    type: end
    before:
      id: 1740765619.832969-b4tgkm
      camera: doorbell
      start_time: 1740765619.832969
      end_time: null
      severity: detection
      thumb_path: /media/frigate/clips/review/thumb-doorbell-1740765619.832969-b4tgkm.webp
      data:
        detections:
          - 1740765616.092773-ja4l4g
        objects:
          - car
        sub_labels: []
        zones: []
        audio: []
    after:
      id: 1740765619.832969-b4tgkm
      camera: doorbell
      start_time: 1740765619.832969
      end_time: 1740765622.916183
      severity: detection
      thumb_path: /media/frigate/clips/review/thumb-doorbell-1740765619.832969-b4tgkm.webp
      data:
        detections:
          - 1740765616.092773-ja4l4g
        objects:
          - car
        sub_labels: []
        zones: []
        audio: []

I have a template evaluation condition, but this fails evaluates to false with the message above.

{% set ns = namespace(count=0') %}
{% set objects = trigger.payload_json["after"]["data"]["objects"] %}
{% set detect_list = ['car','truck','bus','person'] %}
{% for items in objects %}
  {% if items in detect_list %}
    {% set ns.count = ns.count + 1 %}
    {{ ns.count }}
  {% endif %}
{% endfor %}
{{ ns.count > 0 }}

Can anyone shine some light on what am I overlooking? the [‘car’] object should be in detect_list.

Thanks.

You didn’t mention how it fails (error message or unexpected result), so I can only suggest basic troubleshooting.

I would try getting each part of the JSON in the dev tools area. That will give you a clearer picture of the issue. I’m wondering if there is a parent object you are missing in the JSON call.

Apologies, “failed” isn’t the right word. The evaluation {{ ns.count > 0 }} always evaluates to false because the {% if items.in detect_list %} never matches, even though car is in the list.

If I hardcode the “car” the evaluation evaluates correctly.

{% set ns = namespace(count=0,items='') %}
{% set objects = ['car'] %}
{% set detections = ["car", "truck", "bus", "person"] %}
{% for items in objects %}
  {{ items }}
  {% if items|string in detections %}
    {% set ns.count = ns.count + 1 %}
    {{ ns.count }}
  {% endif %}
{% endfor %}
{{ ns.count > 0 }}

I think it would be good to see the entire YAML that you’re using to create the template. I pasted your stuff into the template area of the dev tool and got back True when I tried it. Here specifically is what I used to test:

{% set test_json = {"type": "end", "before": {"id": "1740765619.832969-b4tgkm", "camera":
    "doorbell", "start_time": 1740765619.832969, "end_time": null, "severity":
    "detection", "thumb_path":
    "/media/frigate/clips/review/thumb-doorbell-1740765619.832969-b4tgkm.webp",
    "data": {"detections": ["1740765616.092773-ja4l4g"], "objects": ["car"],
    "sub_labels": [], "zones": [], "audio": []}}, "after": {"id":
    "1740765619.832969-b4tgkm", "camera": "doorbell", "start_time":
    1740765619.832969, "end_time": 1740765622.916183, "severity": "detection",
    "thumb_path":
    "/media/frigate/clips/review/thumb-doorbell-1740765619.832969-b4tgkm.webp",
    "data": {"detections": ["1740765616.092773-ja4l4g"], "objects": ["car"],
    "sub_labels": [], "zones": [], "audio": []}}}
%}
{{ test_json["after"]["data"]["objects"] }}
{% for item in test_json["after"]["data"]["objects"] %}
item: {{ item }}
{%- endfor %}
{% set ns = namespace(count=0,items='') %}
{% set objects = test_json["after"]["data"]["objects"] %}
{% set detect_list = ['car','truck','bus','person'] %}
{% for items in objects %}
  {% if items in detect_list %}
    {% set ns.count = ns.count + 1 %}
    {{ ns.count }}
  {% endif %}
{% endfor %}
{{ ns.count > 0 }}

And I got back:

['car']
item: car
1
True

That is quite interesting. Here is the entire yaml for the automation:

alias: f_zone_bard_notify_end_v3
description: ""
triggers:
  - topic: frigate/reviews
    trigger: mqtt
conditions:
  - condition: state
    entity_id: input_boolean.telegram_notify
    state: "on"
  - condition: template
    value_template: "{{ trigger.payload_json['type'] == 'end' }}"
  - condition: template
    value_template: |
      {% set ns = namespace(count=0,items='') %}
      {% set objects = trigger.payload_json["after"]["data"]["objects"] %}
      {% set detect_list = ['car','truck','bus','person'] %}
      {% for items in objects %}
        {% if items|string in detect_list %}
          {% set ns.count = ns.count + 1 %}
          {{ ns.count }}
        {% endif %}
      {% endfor %}
      {{ ns.count > 0 }}
    enabled: true

I would remove the offending condition and then edit the automation that will send you trigger.payload_json as the notification so you can see what it is. Or maybe set it to an input text so you can see it in the state. Something so you can see what that is.

You can try this without namespace

      {% set objects = set(trigger.payload_json["after"]["data"]["objects"]) %}
      {% set detects = set(['car','truck','bus','person']) %}
      {{ detects.intersection(objects) | length > 0 }}

but your code should work. Are you getting any errors? What does your atuomation trace show?

Looks like for some reason, if I do string comparisons by going through each list element, it didn’t work. I’m using this logic comparison, and somehow it worked:

{{ [“person”, “car”, “truck”, “bus”] | select(“in”, trigger.payload_json[‘after’][‘data’][‘objects’]) | list | length > 0 }}

Which lets me to believe the intersection method should work as well.