Wait necessary after trigger

My trigger is an MQTT message. The message is a JSON of 32 comma separated zeros where any one, but only one, could be a 1. I’ll call this the table. If I put in a delay of 5 seconds, I can access the JSON.

Asking why doesn’t help. It just does. But Is there a way I can get the JSON from the trigger state? I’ve tried states(trigger.to_state) but that doesn’t seem to work (Is there a way to determine what states(trigger.to_state) actually is?

Thanks for your help.

triggers:
  - topic: SIP/zones
    trigger: mqtt
actions:
  - delay: "00:00:05"
  - action: input_number.set_value
    data:
      value: |
        {% if 1 in (states('sensor.sip')|from_json) %}
          {{ (states('sensor.sip')|from_json).index(1)+1 }}
        {% else %}0{% endif %}
    target:
      entity_id: input_number.zonetowaternumber
  - delay: "00:00:02"

The template works. First I must check to see if there is a 1 in the table. If there is I extract its index number ((1) searches for a 1, where [1] extracts the value at index 1) and add 1 to it. If there is no 1, I set the result to zero. I put the result into ZoneToWaterNumber which is a helper.

But if I don’t wait for 5 seconds, the last value of ZoneToWaterNumber is used.

You see the next delay. I have to have this for the next section to work. I don’t know why.

The other two delays are because it take 2 seconds for the data to reach its destination

  - if:
      - condition: template
        value_template: "{{ states('input_number.zonetowaternumber')|int == 0 }}"
    then:
      - data:
          value: "0"
        target:
          entity_id: text.zone
        action: text.set_value
      - delay: "00:00:02"
      - action: switch.turn_off
        metadata: {}
        data: {}
        target:
          entity_id:
            - switch.start
    else:
      - data:
          value: "{{ states('input_number.zonetowaternumber')|int }}"
        target:
          entity_id: text.zone
        action: text.set_value
      - delay: "00:00:02"
      - action: switch.turn_on
        metadata: {}
        data: {}
        target:
          entity_id:
            - switch.start
mode: single

There seems to be some confusion about a couple things:

MQTT triggers do not have a to_state. The trigger variable for an MQTT trigger will contain the available data for that trigger type. That will include the payload json. You can see the values of the trigger variable in the automation’s trace in the “Changed variables” section.

The states() function requires an entity_id string as its first argument… trigger.to_state would return a complete state object, not an entity ID.

Since it uses an invalid first argument, states(trigger.to_state) is nonsensical.

If you were using a State, Numeric State, Zone, or some Device triggers, trigger.to_state.state, on it’s own, would provide the state value.

Why don’t you just trigger on the entity using a state trigger?

You can use trigger.payload_json as documented here.

I followed @PeteRage 's suggested and came up with this:
The first version failed with the error Error: value should be a string for dictionary value @ data['value'].
The second version worked.
The differences are:

      - data:
          value: {{ ( ( (states('sensor.sip')|from_json).index(1)|int ) + 1 )|string }}
      - data:
          value: >-
            {{ ( ( (states('sensor.sip')|from_json).index(1)|int ) + 1 )|string
            }}

After the automation is triggered, the code of the former changes to the following:

      - data:
          value:
            "[object Object]": null

I was under the impression that both values were identical. Where did I go wrong?

--------------------------------------------------------------------------
FORMER:(fails)

triggers:
  - trigger: state
    entity_id: sensor.sip
actions:
  - delay: "00:00:01"
  - if:
      - condition: template
        value_template: |
          {% if 1 in (states('sensor.sip')|from_json) %}
            true
          {% else %}
            false
          {% endif %} 
    then:
      - data:
          value: {{ ( ( (states('sensor.sip')|from_json).index(1)|int ) + 1 )|string }}
        target:
          entity_id: text.zone
        action: text.set_value
      - delay: "00:00:02"
      - action: switch.turn_on
        metadata: {}
        data: {}
        target:
          entity_id:
            - switch.start
    else:
      - data:
          value: "0"
        target:
          entity_id: text.zone
        action: text.set_value
      - delay: "00:00:02"
      - action: switch.turn_off
        metadata: {}
        data: {}
        target:
          entity_id:
            - switch.start
mode: single

LATTER: (works)

triggers:
  - trigger: state
    entity_id: sensor.sip
actions:
  - delay: "00:00:01"
  - if:
      - condition: template
        value_template: |
          {% if 1 in (states('sensor.sip')|from_json) %}
            true
          {% else %}
            false
          {% endif %} 
    then:
      - data:
          value: >-
            {{ ( ( (states('sensor.sip')|from_json).index(1)|int ) + 1 )|string
            }}
        target:
          entity_id: text.zone
        action: text.set_value
      - delay: "00:00:02"
      - action: switch.turn_on
        metadata: {}
        data: {}
        target:
          entity_id:
            - switch.start
    else:
      - data:
          value: "0"
        target:
          entity_id: text.zone
        action: text.set_value
      - delay: "00:00:02"
      - action: switch.turn_off
        metadata: {}
        data: {}
        target:
          entity_id:
            - switch.start
mode: single

Templates should be enclosed in " ", that is why it fails.

You should be able to get rid of the delay and use the trigger value instead of using states

Toss it in a variable for easier use later.

{% set v = trigger.to_state.state  %}

When I enclose in " "

- data:
          value: "{{ ( ( (states('sensor.sip')|from_json).index(1)|int ) + 1 )|string }}"

The result is “IndexValue” *with quotes), which doesn’t work downstream, instead of IndexValue (without quotes). And if that were the case, why did the succesful evaluation work? Note putting quotes around the succesful evaluation also produced “IndexValue”

It should not create the quotes with that code.
Only if you did both quotes and the >- and new line will that happen

1 Like

I agree that it should not create quotes, but that doesn’t change the fact that it does.

I refuse to believe there is something that dysfunctional in your install.
This is something that has not changed in many many years, or perhaps ever.
If you are right then it’s a major issue with the yaml decoder and/or Jinja.

Yeah, I had a hard time with my assertion, too, so I recreated the conditions and, lo and behold, no quotes. mea culpa!

But I did put the template into the Settings–>Developer tools–>Template–>Template editor The result with quotes produces quotes and no quotes without.

The template editor works differently than the automation engine when it parses the jinja.

The automation interpreter expects quotes on a single line template to denote the beginning and end of the template.

the template editor has no requirement and parses the templates exactly as written. so when you add quotes outside of the template there then the editor just renders them as a string character before and after the template result just as it would with any other string character.

1 Like

What is “adding the quotes” I believe that’s the disconnect here.


As a sidebar, I’m curious what’s creating that sip sensor? I feel like this whole process you have here can likely get changed to make this automation a lot easier to read and understand without heavy templates.

Well yes and no, that’s why I’m curious where he’s putting the template. The template selectors in the automation UI add the quotes for you and do not show quotes when you add to the field. Meaning, it acts the same way as the template editor.

I am using a program called SIP (Sustainable Irrigation Platform) as the front end to my irrigation controller. It sends its output to the topic SIP/zones on an MQTT broker.

My irrigation controller (which I designed and built: RPi+16 channel relay board) uses MySensors for data communication. It has two inputs, zone and valve open/close

I have no control how the SIP and MS programs communicate with the MQTT broker so I use HA as a go between.

I create an MQTT sensor by putting this code in mqtt.yaml

- name: SIP
  state_topic: SIP/zones
  unique_id: "SIP"
  availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  value_template: "{{ value_json.zone_list }}"

My first template detects if there is a 1 in the JSON which indicates a valve is to be opened. Without this search, getting the index value of the 1 will fail if there is no 1

If there is no 1 from SIP, indicating to turn off all valves, sending a zone of 0 via MS will tell the controller to de-energize all valves.

If there is a 1 in the JSON from SIP, the second template determines the index number of the 1 and increments the index number (which is now non-zero) which will be sent via MS to the controller which will energize the appropriate valve.

Previously I was stepping completely through the JSON in search of a 1. Combined with the necessary delay after the trigger, it was taking tens of seconds from the time I activated or deactivated a valve in SIP to when the valve actually changed states.

With the suggestion from @PeteRage and the illumination of a few of the subtleties of templates, that time is down to about four seconds.

(side note: The irrigation is gravity fed, on nine levels with four microclimates. A 25 zone commercial controller is upwards to USD$700. My hardware costs were about USD$70, all software open source or mine)

And on a final note, I’m in the process of reading the templating documentation.

Can you post the results of the SIP/zones topic?

Basically, where I"m going with this, you can really reduce your automation and likely everything related to this into simple automations with almost no templates.

The reason it’s so complicated now is because of the way you’re handling the sip mqtt entity.

I am under the impression that templates process faster than equivalent YAML code.

The MySensors entities are: text.zone and switch.start

This was extracted via the template editor using the template {{ states('sensor.sip')|from_json }}

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

The following was extracted this using MQTT explorer
{
“zone_list”: [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
“zone_dict”: {
“Front T0 S01”: 0,
“Courtyard T0 S02”: 0,
“North T0 S03”: 0,
“south of steps T1 S04”: 0,
“(no valve) T1 S05”: 0,
“T2 S06”: 0,
“T2 S07”: 0,
“T3 S08”: 0,
“T3 S09”: 0,
“(no valve) T4 S10”: 0,
“South Hill T4 S11”: 0,
“SE Hill T4 S12”: 0,
“T5 S13”: 0,
“T5 S14”: 0,
“SE Hill T6 S15”: 0,
“T6 S16”: 0,
“T7 S17”: 0,
“T8 S18”: 0,
“T9 S19”: 0,
“Jim’s lower T9 S20”: 0,
“Jim’s upper T9 S21”: 0,
“(no valve) S22”: 0,
“(no valve) S23”: 0,
“Blueberries T1 S24”: 0,
“flats East T1 S25”: 0,
“S26”: 0,
“S27”: 0,
“S28”: 0,
“S29”: 0,
“S30”: 0,
“S31”: 0,
“S32”: 0
},
“master_on”: 0
}

Ok, in my opinion, you should change your MQTT configuration to:

mqtt:
- binary_sensor:
  - unique_id: sip_front_t0_s01
    default_entity_id: binary_sensor.front_t0_s01
    name: Front T0 S01
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('Front T0 S01', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_courtyard_t0_s02
    default_entity_id: binary_sensor.courtyard_t0_s02
    name: Courtyard T0 S02
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('Courtyard T0 S02', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_north_t0_s03
    default_entity_id: binary_sensor.north_t0_s03
    name: North T0 S03
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('North T0 S03', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_south_of_steps_t1_s04
    default_entity_id: binary_sensor.south_of_steps_t1_s04
    name: south of steps T1 S04
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('south of steps T1 S04', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_no_valve_t1_s05
    default_entity_id: binary_sensor.no_valve_t1_s05
    name: (no valve) T1 S05
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('(no valve) T1 S05', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t2_s06
    default_entity_id: binary_sensor.t2_s06
    name: T2 S06
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T2 S06', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t2_s07
    default_entity_id: binary_sensor.t2_s07
    name: T2 S07
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T2 S07', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t3_s08
    default_entity_id: binary_sensor.t3_s08
    name: T3 S08
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T3 S08', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t3_s09
    default_entity_id: binary_sensor.t3_s09
    name: T3 S09
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T3 S09', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_no_valve_t4_s10
    default_entity_id: binary_sensor.no_valve_t4_s10
    name: (no valve) T4 S10
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('(no valve) T4 S10', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_south_hill_t4_s11
    default_entity_id: binary_sensor.south_hill_t4_s11
    name: South Hill T4 S11
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('South Hill T4 S11', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_se_hill_t4_s12
    default_entity_id: binary_sensor.se_hill_t4_s12
    name: SE Hill T4 S12
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('SE Hill T4 S12', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t5_s13
    default_entity_id: binary_sensor.t5_s13
    name: T5 S13
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T5 S13', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t5_s14
    default_entity_id: binary_sensor.t5_s14
    name: T5 S14
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T5 S14', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_se_hill_t6_s15
    default_entity_id: binary_sensor.se_hill_t6_s15
    name: SE Hill T6 S15
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('SE Hill T6 S15', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t6_s16
    default_entity_id: binary_sensor.t6_s16
    name: T6 S16
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T6 S16', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t7_s17
    default_entity_id: binary_sensor.t7_s17
    name: T7 S17
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T7 S17', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t8_s18
    default_entity_id: binary_sensor.t8_s18
    name: T8 S18
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T8 S18', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_t9_s19
    default_entity_id: binary_sensor.t9_s19
    name: T9 S19
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('T9 S19', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_jim_s_lower_t9_s20
    default_entity_id: binary_sensor.jim_s_lower_t9_s20
    name: Jim's lower T9 S20
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('Jim's lower T9 S20', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_jim_s_upper_t9_s21
    default_entity_id: binary_sensor.jim_s_upper_t9_s21
    name: Jim's upper T9 S21
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('Jim's upper T9 S21', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_no_valve_s22
    default_entity_id: binary_sensor.no_valve_s22
    name: (no valve) S22
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('(no valve) S22', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_no_valve_s23
    default_entity_id: binary_sensor.no_valve_s23
    name: (no valve) S23
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('(no valve) S23', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_blueberries_t1_s24
    default_entity_id: binary_sensor.blueberries_t1_s24
    name: Blueberries T1 S24
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('Blueberries T1 S24', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_flats_east_t1_s25
    default_entity_id: binary_sensor.flats_east_t1_s25
    name: flats East T1 S25
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('flats East T1 S25', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s26
    default_entity_id: binary_sensor.s26
    name: S26
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S26', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s27
    default_entity_id: binary_sensor.s27
    name: S27
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S27', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s28
    default_entity_id: binary_sensor.s28
    name: S28
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S28', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s29
    default_entity_id: binary_sensor.s29
    name: S29
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S29', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s30
    default_entity_id: binary_sensor.s30
    name: S30
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S30', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s31
    default_entity_id: binary_sensor.s31
    name: S31
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S31', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_s32
    default_entity_id: binary_sensor.s32
    name: S32
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_dict.get('S32', 0) == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""

This will give you 32 binary sensors that represent each valve. You can remove or disable the ones you don’t want.

I used this template to generate the config:

{% set value_json = {
  "zone_list": [
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0
  ],
  "zone_dict": {
    "Front T0 S01": 0,
    "Courtyard T0 S02": 0,
    "North T0 S03": 0,
    "south of steps T1 S04": 0,
    "(no valve) T1 S05": 0,
    "T2 S06": 0,
    "T2 S07": 0,
    "T3 S08": 0,
    "T3 S09": 0,
    "(no valve) T4 S10": 0,
    "South Hill T4 S11": 0,
    "SE Hill T4 S12": 0,
    "T5 S13": 0,
    "T5 S14": 0,
    "SE Hill T6 S15": 0,
    "T6 S16": 0,
    "T7 S17": 0,
    "T8 S18": 0,
    "T9 S19": 0,
    "Jim's lower T9 S20": 0,
    "Jim's upper T9 S21": 0,
    "(no valve) S22": 0,
    "(no valve) S23": 0,
    "Blueberries T1 S24": 0,
    "flats East T1 S25": 0,
    "S26": 0,
    "S27": 0,
    "S28": 0,
    "S29": 0,
    "S30": 0,
    "S31": 0,
    "S32": 0
  },
  "master_on": 0
} %}

mqtt:
- binary_sensor:
{%- for k, v in value_json.zone_dict.items() %}
  {%- set slug = slugify(k) %}
  - unique_id: sip_{{ slug }}
    default_entity_id: binary_sensor.{{ slug }}
    name: {{ k }}
    state_topic: SIP/zones
    value_template: {% raw %}"{{ value_json.zone_dict.get('{% endraw %}{{ k }}{% raw %}', 0) == 1 }}"{% endraw %}
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""

{%- endfor %}

Then, once you incorporate that. Your automation becomes:

triggers:
- trigger: state
  entity_id: binary_sensor.courtyard_t0_s02
  not_to:
  - unknown
  - unavailable
actions:
  - action: switch.turn_{{ trigger.to_state.state }}
    target:
      entity_id: switch.start

It also gives you the ability to make binary sensor groups in case you need to turn on that switch with any binary_sensor.

Either way, the upfront configuration is what holds the complication, however it’s managed with a small template if you want to go that route. You can also just manage the 32 switches manually. Still the maintenance burden lessens because your automations become simple and the configuration which rarely changes holds the complication.

1 Like

The drawback of the post above is that you’ll need to change the value_template if you update the names in your source software. If you want to avoid that, this will do it.

Configuration:

mqtt:
- binary_sensor:
  - unique_id: sip_zone_1
    default_entity_id: binary_sensor.front_t0_s01
    name: Front T0 S01
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[0] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_2
    default_entity_id: binary_sensor.courtyard_t0_s02
    name: Courtyard T0 S02
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[1] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_3
    default_entity_id: binary_sensor.north_t0_s03
    name: North T0 S03
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[2] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_4
    default_entity_id: binary_sensor.south_of_steps_t1_s04
    name: south of steps T1 S04
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[3] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_5
    default_entity_id: binary_sensor.no_valve_t1_s05
    name: (no valve) T1 S05
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[4] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_6
    default_entity_id: binary_sensor.t2_s06
    name: T2 S06
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[5] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_7
    default_entity_id: binary_sensor.t2_s07
    name: T2 S07
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[6] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_8
    default_entity_id: binary_sensor.t3_s08
    name: T3 S08
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[7] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_9
    default_entity_id: binary_sensor.t3_s09
    name: T3 S09
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[8] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_10
    default_entity_id: binary_sensor.no_valve_t4_s10
    name: (no valve) T4 S10
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[9] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_11
    default_entity_id: binary_sensor.south_hill_t4_s11
    name: South Hill T4 S11
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[10] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_12
    default_entity_id: binary_sensor.se_hill_t4_s12
    name: SE Hill T4 S12
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[11] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_13
    default_entity_id: binary_sensor.t5_s13
    name: T5 S13
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[12] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_14
    default_entity_id: binary_sensor.t5_s14
    name: T5 S14
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[13] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_15
    default_entity_id: binary_sensor.se_hill_t6_s15
    name: SE Hill T6 S15
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[14] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_16
    default_entity_id: binary_sensor.t6_s16
    name: T6 S16
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[15] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_17
    default_entity_id: binary_sensor.t7_s17
    name: T7 S17
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[16] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_18
    default_entity_id: binary_sensor.t8_s18
    name: T8 S18
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[17] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_19
    default_entity_id: binary_sensor.t9_s19
    name: T9 S19
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[18] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_20
    default_entity_id: binary_sensor.jim_s_lower_t9_s20
    name: Jim's lower T9 S20
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[19] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_21
    default_entity_id: binary_sensor.jim_s_upper_t9_s21
    name: Jim's upper T9 S21
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[20] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_22
    default_entity_id: binary_sensor.no_valve_s22
    name: (no valve) S22
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[21] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_23
    default_entity_id: binary_sensor.no_valve_s23
    name: (no valve) S23
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[22] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_24
    default_entity_id: binary_sensor.blueberries_t1_s24
    name: Blueberries T1 S24
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[23] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_25
    default_entity_id: binary_sensor.flats_east_t1_s25
    name: flats East T1 S25
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[24] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_26
    default_entity_id: binary_sensor.s26
    name: S26
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[25] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_27
    default_entity_id: binary_sensor.s27
    name: S27
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[26] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_28
    default_entity_id: binary_sensor.s28
    name: S28
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[27] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_29
    default_entity_id: binary_sensor.s29
    name: S29
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[28] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_30
    default_entity_id: binary_sensor.s30
    name: S30
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[29] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_31
    default_entity_id: binary_sensor.s31
    name: S31
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[30] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""
  - unique_id: sip_zone_32
    default_entity_id: binary_sensor.s32
    name: S32
    state_topic: SIP/zones
    value_template: "{{ value_json.zone_list[31] == 1 }}"
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""

Template that generates the yaml:

{% set value_json = {
  "zone_list": [
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0
  ],
  "zone_dict": {
    "Front T0 S01": 0,
    "Courtyard T0 S02": 0,
    "North T0 S03": 0,
    "south of steps T1 S04": 0,
    "(no valve) T1 S05": 0,
    "T2 S06": 0,
    "T2 S07": 0,
    "T3 S08": 0,
    "T3 S09": 0,
    "(no valve) T4 S10": 0,
    "South Hill T4 S11": 0,
    "SE Hill T4 S12": 0,
    "T5 S13": 0,
    "T5 S14": 0,
    "SE Hill T6 S15": 0,
    "T6 S16": 0,
    "T7 S17": 0,
    "T8 S18": 0,
    "T9 S19": 0,
    "Jim's lower T9 S20": 0,
    "Jim's upper T9 S21": 0,
    "(no valve) S22": 0,
    "(no valve) S23": 0,
    "Blueberries T1 S24": 0,
    "flats East T1 S25": 0,
    "S26": 0,
    "S27": 0,
    "S28": 0,
    "S29": 0,
    "S30": 0,
    "S31": 0,
    "S32": 0
  },
  "master_on": 0
} %}

mqtt:
- binary_sensor:
{%- for k, v in value_json.zone_dict.items() %}
  {%- set slug = slugify(k) %}
  - unique_id: sip_zone_{{ loop.index }}
    default_entity_id: binary_sensor.{{ slug }}
    name: {{ k }}
    state_topic: SIP/zones
    value_template: {% raw %}"{{ value_json.zone_list[{% endraw %}{{ loop.index - 1 }}{% raw %}] == 1 }}"{% endraw %}
    device_class: moisture
    availability:
    - topic: "SIP"
      payload_available: "\"UP\""
      payload_not_available: "\"DOWN\""

{%- endfor %}