Zwave JS Multicast Area Lights & Switches

The indentation is fine

my bad, I just compared the posted code to code that I use and know to work.

Indentation in yaml is odd if you aren’t used to it. As long as objects are at the same level, the number of leading spaces doesn’t matter.

Hi! Love this feature. It does seem to work on my current configuration, however, I have some errors in the log that I am wondering about.

I have groups with both lights and switches which are controlling non-dimmable lights. These lights are also set up with helpers as “Switch as lights”, however I am using the original switch entities in the multicast. I regularly get this:

TemplateError('ValueError: Template error: int got invalid input 'None' when rendering template '{%- set entities = expand('group.garderobe_z_wave') %} {%- set lights = entities | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') %} {%- set levels = lights | map(attribute='attributes.brightness') | map('int') | list %} {{- levels | average if levels else 0 }}' but no default was specified') while processing template 'Template<template=({%- set entities = expand('group.garderobe_z_wave') %} {%- set lights = entities | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') %} {%- set levels = lights | map(attribute='attributes.brightness') | map('int') | list %} {{- levels | average if levels else 0 }}) renders=610>' for attribute '_brightness' in entity 'light.garderobe_z_wave'

My group.yaml for this group looks like this:

garderobe_z_wave:
  entities:
    - light.garderobe_taklys
    - switch.garderobe_nattlys
    - switch.garderobe_nattlys_2

My configuration.yaml has this:

      garderobe_z_wave:
        unique_id: garderobe_z_wave
        friendly_name: Garderobe Z-Wave
        value_template: >
          {{ is_state('group.garderobe_z_wave', 'on') }}
        level_template: >
          {%- set entities = expand('group.garderobe_z_wave') %}
          {%- set lights = entities | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') %}
          {%- set levels = lights | map(attribute='attributes.brightness') | map('int') | list %}
          {{- levels | average if levels else 0 }}
        availability_template: >
          {{- expand('group.garderobe_z_wave') | selectattr('state','in',['unavailable','unknown']) | list | length == 0 }}
        turn_on:
          - service: script.zwave_multicast_group
            data:
              group: group.garderobe_z_wave
              level: 255
        turn_off:
          - service: script.zwave_multicast_group
            data:
              group: group.garderobe_z_wave
              level: 0
        set_level:
          - service: script.zwave_multicast_group
            data:
              group: group.garderobe_z_wave
              level: >
                {{- brightness }}

And my scripts.yaml contains this, where I have added special command class endpoints for my switches with two relays:


zwave_multicast_group:
  mode: parallel
  alias: Multicast to Zwave Group
  fields:
    group:
      description: (Required) The group of lights & switches
      example: group.bonus_room_area
    level:
      description: (Optional) The brightness level, switches will be on if the level
        is greater than 0.
      example: '99'
  variables:
    brightness_pct: '{%- set brightness_pct = (level | int(0) / 255 * 100) | int %}
      {%- set brightness_pct = [ 0, brightness_pct ] | max %} {%- set brightness_pct
      = [ 99, brightness_pct] | min %} {{- brightness_pct }}

      '
    value: '{%- set value = brightness_pct > 0 %} {{- value }}

      '
    settings:
      light:
        command_class: 38
        property: targetValue
        endpoint: 1
        value: '{{ brightness_pct }}'
      switch:
        command_class: 37
        property: targetValue
        endpoint: 1
        value: '{{ value }}'
      switch.garasje_taklys_2:
        command_class: 37
        property: targetValue
        endpoint: 2
        value: '{{ value }}'
      switch.garderobe_nattlys_2:
        command_class: 37
        property: targetValue
        endpoint: 2
        value: '{{ value }}'
      switch.gjestebad_nattlys_2:
        command_class: 37
        property: targetValue
        endpoint: 2
        value: '{{ value }}'
      cover:
        command_class: 38
        property: targetValue
        endpoint: 0
        value: '{{ brightness_pct }}'
    lights: "{% if value %}\n  {% set off_lights = expand(group) \n    | selectattr('domain',
      'eq', 'light')\n    | selectattr('state', 'eq', 'off')\n    | map(attribute='entity_id')
      | list %}\n  {% set on_lights = expand(group) \n    | selectattr('domain', 'eq',
      'light')\n    | selectattr('state', 'eq', 'on')\n    | selectattr('attributes.brightness',
      'defined') \n    | rejectattr('attributes.brightness','eq', level)\n    | map(attribute='entity_id')
      | list %}\n  {{ (off_lights + on_lights) or none }}\n{% else %}\n  {{ expand(group)
      \n    | selectattr('domain', 'eq', 'light')\n    | selectattr('state', 'eq',
      'on')\n    | map(attribute='entity_id') | list or none }}\n{% endif %}\n"
    covers: "{% if value %}\n  {% set off_lights = expand(group) \n    | selectattr('domain',
      'eq', 'cover')\n    | selectattr('state', 'eq', 'closed')\n    | map(attribute='entity_id')
      | list %}\n  {% set on_lights = expand(group) \n    | selectattr('domain', 'eq',
      'cover')\n    | selectattr('state', 'eq', 'open')\n    | selectattr('attributes.current_position',
      'defined') \n    | rejectattr('attributes.current_position','eq', brightness_pct)\n
      \   | map(attribute='entity_id') | list %}\n  {{ (off_lights + on_lights) or
      none }}\n{% else %}\n  {{ expand(group) \n    | selectattr('domain', 'eq', 'cover')\n
      \   | selectattr('state', 'eq', 'open')\n    | map(attribute='entity_id') |
      list or none }}\n{% endif %}\n"
    switches: '{%- set switches = expand(group) | selectattr(''domain'', ''eq'', ''switch'')
      %} {%- set switches = switches | selectattr(''state'',''eq'', ''off'' if value
      else ''on'') %} {%- set switches = switches | map(attribute=''entity_id'') |
      list %} {{- switches or none }}

      '
    items: "{%- set ns = namespace(items={}, spool={}) %} {%- set fmat = \"('{0}':
      {1})\" %} {%- set items = (switches or []) + (lights or []) + (covers or [])
      %} {%- for item in items %}\n  {%- set state_obj = expand(item) | first | default(none)
      %}\n  {%- if state_obj and state_obj.domain in ['light','switch','cover'] %}\n
      \   {%- set domain = state_obj.domain %}\n    {%- set entity_id = state_obj.entity_id
      %}\n    {%- set entity_ids = lights if domain == 'light' else switches %}\n
      \   {%- set entity_ids = covers if domain == 'cover' else entity_ids %}\n    {%-
      set current = settings[domain] %}\n    {%- set current = dict(current, **settings[entity_id])
      if entity_id in settings else current %}\n    {%- set key = domain ~ '_' ~ current.items()
      | list | string | lower | regex_findall('[a-z0-9_]+') | join('_') %}\n    {%-
      if key in ns.spool %}\n      {%- set ns.spool = dict(ns.spool, **{key:ns.spool[key]
      + [entity_id]}) %}\n    {%- else %}\n      {%- set ns.spool = dict(ns.spool,
      **{key:[entity_id]}) %}\n    {%- endif %}\n    {%- set entity_ids = ns.spool[key]
      %}\n    {%- set current = dict(domain=domain, **current) %}\n    {%- set current
      = dict(current, entity_id=entity_ids) %}\n    {%- set ns.items = dict(ns.items,
      **{key:current | string}) %}\n  {%- endif %}\n{%- endfor %} [{{ ns.items.values()
      | unique | sort | list | join(', ') }}]\n"
    execute: '{{ items is not none or items != [] }}

      '
    total: '{{ items | length if execute else 0 }}

      '
  sequence:
  - condition: template
    value_template: '{{ execute }}'
  - repeat:
      count: '{{ total }}'
      sequence:
      - service: zwave_js.multicast_set_value
        target:
          entity_id: '{{ items[repeat.index - 1].entity_id }}'
        data:
          command_class: '{{ items[repeat.index - 1].command_class }}'
          property: '{{ items[repeat.index - 1].property }}'
          endpoint: '{{ items[repeat.index - 1].endpoint }}'
          value: '{{ items[repeat.index - 1].value }}'
  max: 100

Anything wrong? I am wondering whether or not this slows down my setup.

I had to change the light templates this weekend… Here’s an example

    outside_sunset:
      unique_id: outside_sunset
      friendly_name: Outside Sunset
      value_template: >
        {{ is_state('group.outside_sunset', 'on') }}
      level_template: >
        {%- set entities = expand('group.outside_sunset') %}
        {%- set lights = entities | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') %}
        {%- set levels = lights | selectattr('attributes.brightness', 'defined') | map(attribute='attributes.brightness') | reject('none') | list %}
        {{- levels | average if levels else 0 }}
      availability_template: >
        {{- expand('group.outside_sunset') | selectattr('state','in',['unavailable','unknown']) | list | length == 0 }}
      turn_on:
      - service: script.zwave_multicast_group
        data:
          group: group.outside_sunset
          level: 255
      turn_off:
      - service: script.zwave_multicast_group
        data:
          group: group.outside_sunset
          level: 0
      set_level:
      - service: script.zwave_multicast_group
        data:
          group: group.outside_sunset
          level: >
            {{- brightness }}

@petro thanks for your fast reply!

The error is gone but I am now getting these warnings thrown houndreds of times;

You somehow copy/pasted the value_template incorrectly. It seems you’re missing line 2 of that template.

Oh, so sorry for the embarrassing mistake. I was so focused on making sure the edited line was correct that I didn’t see that I replaced the wrong line…! Thank you so much for your quick reply and work on this :slight_smile:

2 Likes

Thanks for posting this, it works great except for one issue: Our HA Z-Wave integration is connected to 2x Z-Wave networks (2x remote Z-Wave JS UI servers) due to the Z-Wave 800 Controller hang issues everyone is seeing. When we call the script with a light group that contains lights from both groups we get the error:

Failed to call service script.zwave_multicast_group. Multicast commands only work on devices in the same network.

Can you suggest a modification to the script so that it further groups the switches by Z-Wave network and calls zwave_js.multicast_set_value for each set?