Kudo for YAMLcomposer: Indicator and zigbee lights creation of items, groups, etc

This add-on “YAMLcomposer” rocks, at least for my use cases :slight_smile:

I only came across it when reading Reimplement my Sitemap (>1000 Items) to WebUI using the yamlcomposer and yaml based widget templates .

At first, and I repeat my commentary here:

The first use case was creating things, items and groups (~50 per battery) for my five 5kWh 48V LiFePO4 batteries connected to my inverter.charger. So far so good…

Then I thought I could realise an indicator light ==> a RGB LED in each room (integrated into a central light fixture) indicates a few events around the house; e.g., when mail has been delivered, the gate is opened, irrigation is running, tank is filling; each with a different colour.

While I have only one dummy light to prototype, YAMLcomposer was ideal in creating the items and groups for it.

version: 1

# Indicator causes are independent state Items. A source rule owns each cause;
# indicator.rules is the only component allowed to control the indicator lights.
items:
  grp_Indicator_Causes:
    type: Group
    label: Indicator causes

  grp_Indicator_Red:
    type: Group
    label: Red indicator causes

  grp_Indicator_Orange:
    type: Group
    label: Orange indicator causes

  grp_Indicator_Green:
    type: Group
    label: Green indicator causes

  grp_Indicator_Blue:
    type: Group
    label: Blue indicator causes

  grp_Indicator_Yellow:
    type: Group
    label: Yellow indicator causes

  grp_Indicator_Purple:
    type: Group
    label: Purple indicator causes

  grp_Indicator_Lights_Power:
    type: Group
    group:
      type: Switch
    label: Indicator lights power

  grp_Indicator_Lights_Colour:
    type: Group
    group:
      type: Color
    label: Indicator lights colour

  grp_Indicator_Lights_Online:
    type: Group
    group:
      type: Switch
    label: Indicator lights online

  Indicator_Cause_SmartPlugAlert:
    type: Switch
    label: Smart-plug fault
    groups: ["grp_Indicator_Causes", "grp_Indicator_Red"]

  Indicator_Cause_IrrigationRunning:
    type: Switch
    label: Irrigation running
    groups: ["grp_Indicator_Causes", "grp_Indicator_Green"]

  Indicator_Cause_TankFilling:
    type: Switch
    label: Tank filling
    groups: ["grp_Indicator_Causes", "grp_Indicator_Blue"]

  Indicator_Cause_MailWaiting:
    type: Switch
    label: Mail waiting
    groups: ["grp_Indicator_Causes", "grp_Indicator_Yellow"]

  Indicator_Cause_Doorbell:
    type: Switch
    label: Doorbell
    groups: ["grp_Indicator_Causes", "grp_Indicator_Yellow"]

  Indicator_Cause_GateEvent:
    type: Switch
    label: Gate event
    groups: ["grp_Indicator_Causes", "grp_Indicator_Yellow"]

  Indicator_Cause_GateOpen:
    type: Switch
    label: Gate open
    groups: ["grp_Indicator_Causes", "grp_Indicator_Yellow"]

  Indicator_Cause_WashingMachineRunning:
    type: Switch
    label: Washing machine running
    groups: ["grp_Indicator_Causes", "grp_Indicator_Purple"]

  Indicator_ActiveCause:
    type: String
    label: Indicator active cause

  Indicator_ActiveColour:
    type: String
    label: Indicator active colour

Now this is not even the thing that thrilled me; I initially created the items and groups referenced to a location (shed_indicator); yet later realised it should have been location-less (indicator). Instead of using the UI and delete and recreate the items and groups, I created a new .yaml file with the location reference removed; deleted the old .yaml, saved the new; change the item/group names in my text-based rule files, and made a change that could easily have taken 2 hours in less than 15 minutes.

As said I elsewhere: kudo to @jimtng for creating this add-on. I love it (and I am not even a yaml guy) :slight_smile:

Nothing in your posted yaml content actually needs YAML Composer. It’s a standard openhab YAML config.

Standard OH config; I need to check this out!

Well, point taken; lets give it a YAMLcomposer example then (see,I said I am not a YAML guy; never used it in context with openHAB).

The battery set-up here is a YAMLcomposer example :slight_smile:

This is another composer example; creating LEDs…

variables:
  group_prefix: grp_${item_prefix}
  power_groups: []
  colour_groups: []
  online_groups: []

things:
  mqtt:topic:mosquitto:${package_id}:
    bridge: mqtt:broker:mosquitto
    label: ${thing_label}
    location: ${location}

    channels:
      online:
        type: switch
        label: Online
        config:
          stateTopic: ${topic_base}/availability
          transformationPattern:
            - JSONPATH:$.state
          "on": online
          "off": offline

      power:
        type: switch
        label: Power
        config:
          stateTopic: ${topic_base}/state
          commandTopic: ${topic_base}/set/state

      brightness:
        type: dimmer
        label: Brightness
        config:
          stateTopic: ${topic_base}/brightness
          commandTopic: ${topic_base}/set
          transformationPattern:
            - JS:light_brightness_in.js
          transformationPatternOut:
            - JS:light_brightness_out.js
          formatBeforePublish: '{"brightness":%s,"transition":3}'
          min: 0
          max: 100

      colour:
        type: color
        label: Colour
        config:
          colorMode: XYY
          stateTopic: ${topic_base}
          commandTopic: ${topic_base}/set
          transformationPattern:
            - JS:light_xyy_in.js
          transformationPatternOut:
            - JS:light_xyy_out.js

      colour_temperature:
        type: dimmer
        label: Colour temperature
        config:
          stateTopic: ${topic_base}/color_temp
          commandTopic: ${topic_base}/set
          transformationPattern:
            - JS:light_temp_in.js
          transformationPatternOut:
            - JS:light_temp_out.js
          formatBeforePublish: '{"color_temp":%s,"transition":3}'
          min: 0
          max: 100

      colour_mode:
        type: string
        label: Colour mode
        config:
          stateTopic: ${topic_base}/color_mode

      link_quality:
        type: number
        label: Link quality
        config:
          stateTopic: ${topic_base}/linkquality
          min: 0
          max: 255

      command:
        type: string
        label: Combined JSON command
        config:
          commandTopic: ${topic_base}/set

items:
  ${group_prefix}:
    type: Group
    label: ${thing_label}

  ${item_prefix}_Power:
    type: Switch
    label: ${thing_label} power
    icon: switch
    groups: "${[group_prefix] + power_groups}"
    channel: mqtt:topic:mosquitto:${package_id}:power

  ${item_prefix}_Brightness:
    type: Dimmer
    label: ${thing_label} brightness
    icon: light
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:brightness

  ${item_prefix}_Colour:
    type: Color
    label: ${thing_label} colour
    icon: colorwheel
    groups: "${[group_prefix] + colour_groups}"
    channel: mqtt:topic:mosquitto:${package_id}:colour

  ${item_prefix}_ColourTemperature:
    type: Dimmer
    label: ${thing_label} colour temperature
    icon: colorwheel
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:colour_temperature

  ${item_prefix}_Online:
    type: Switch
    label: ${thing_label} online
    icon: network
    groups: "${[group_prefix] + online_groups}"
    channel: mqtt:topic:mosquitto:${package_id}:online

  ${item_prefix}_ColourMode:
    type: String
    label: ${thing_label} colour mode
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:colour_mode

  ${item_prefix}_LinkQuality:
    type: Number
    label: ${thing_label} link quality
    icon: network
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:link_quality

  ${item_prefix}_Command:
    type: String
    label: ${thing_label} combined command
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:command

version: 1

packages:
  house_led_001: !include
    file: $pkg/zigbee-rgbcct-light.inc.yaml
    vars:
      topic_base: ArgyleCourt/House/LED_001
      item_prefix: House_LED_001
      thing_label: House LED 001
      location: House

  house_led_002: !include
    file: $pkg/zigbee-rgbcct-light.inc.yaml
    vars:
      topic_base: ArgyleCourt/House/LED_002
      item_prefix: House_LED_002
      thing_label: House LED 002
      location: House

  # ...through House_LED_050

I don’t know though if there is a loop or range [1..50] option.

I’ve just started working on this!

Notably: I haven’t added a break or continue because I don’t think they’re necessary for the case of building a YAML output. If you can think of a reason why they are important to have, please let me know. Currently if you must, you could use several alternatives: using for filtering, or using if inside the loop.

I’ve updated the PR description to show an example of the loop and the new if/elseif/else syntax.

The old if syntaxes are still supported. They actually serve as a value replacement, so they are still useful.

@jimtng Wow, can’t wait for !for to get merged!

I tested a few ideas, this makes my yaml so much smaller and manageable, being able to create a huge amount of things and items from a list of device id’s

Love to see more examples of yamlcomposer to get more ideas.

Using @Max_G’s example with a few tweaks:

The main file:

version: 1

packages:
  !for i in [1..2]: # change this to 1..50 if needed
    house_led_${"%03d" | format(i)}: !include $pkg/zigbee-rgbcct-light.inc.yaml

The package - I only changed the variables section, the rest is the same

variables:
  thing_label: ${package_id | replace("_", " ") | replace("led", "LED") | label}
  item_prefix: ${thing_label | replace(" ", "_")}
  group_prefix: grp_${item_prefix}

  location: ${item_prefix | split("_") | first}
  topic_tail: ${item_prefix | split("_", 2) | last}
  topic_base: ArgyleCourt/${location}/${topic_tail}

  power_groups: []
  colour_groups: []
  online_groups: []

things:
  mqtt:topic:mosquitto:${package_id}:
    bridge: mqtt:broker:mosquitto
    label: ${thing_label}
    location: ${location}

    channels:
      online:
        type: switch
        label: Online
        config:
          stateTopic: ${topic_base}/availability
          transformationPattern:
            - JSONPATH:$.state
          "on": online
          "off": offline

      power:
        type: switch
        label: Power
        config:
          stateTopic: ${topic_base}/state
          commandTopic: ${topic_base}/set/state

      brightness:
        type: dimmer
        label: Brightness
        config:
          stateTopic: ${topic_base}/brightness
          commandTopic: ${topic_base}/set
          transformationPattern:
            - JS:light_brightness_in.js
          transformationPatternOut:
            - JS:light_brightness_out.js
          formatBeforePublish: '{"brightness":%s,"transition":3}'
          min: 0
          max: 100

      colour:
        type: color
        label: Colour
        config:
          colorMode: XYY
          stateTopic: ${topic_base}
          commandTopic: ${topic_base}/set
          transformationPattern:
            - JS:light_xyy_in.js
          transformationPatternOut:
            - JS:light_xyy_out.js

      colour_temperature:
        type: dimmer
        label: Colour temperature
        config:
          stateTopic: ${topic_base}/color_temp
          commandTopic: ${topic_base}/set
          transformationPattern:
            - JS:light_temp_in.js
          transformationPatternOut:
            - JS:light_temp_out.js
          formatBeforePublish: '{"color_temp":%s,"transition":3}'
          min: 0
          max: 100

      colour_mode:
        type: string
        label: Colour mode
        config:
          stateTopic: ${topic_base}/color_mode

      link_quality:
        type: number
        label: Link quality
        config:
          stateTopic: ${topic_base}/linkquality
          min: 0
          max: 255

      command:
        type: string
        label: Combined JSON command
        config:
          commandTopic: ${topic_base}/set

items:
  ${group_prefix}:
    type: Group
    label: ${thing_label}

  ${item_prefix}_Power:
    type: Switch
    label: ${thing_label} power
    icon: switch
    groups: "${[group_prefix] + power_groups}"
    channel: mqtt:topic:mosquitto:${package_id}:power

  ${item_prefix}_Brightness:
    type: Dimmer
    label: ${thing_label} brightness
    icon: light
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:brightness

  ${item_prefix}_Colour:
    type: Color
    label: ${thing_label} colour
    icon: colorwheel
    groups: "${[group_prefix] + colour_groups}"
    channel: mqtt:topic:mosquitto:${package_id}:colour

  ${item_prefix}_ColourTemperature:
    type: Dimmer
    label: ${thing_label} colour temperature
    icon: colorwheel
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:colour_temperature

  ${item_prefix}_Online:
    type: Switch
    label: ${thing_label} online
    icon: network
    groups: "${[group_prefix] + online_groups}"
    channel: mqtt:topic:mosquitto:${package_id}:online

  ${item_prefix}_ColourMode:
    type: String
    label: ${thing_label} colour mode
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:colour_mode

  ${item_prefix}_LinkQuality:
    type: Number
    label: ${thing_label} link quality
    icon: network
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:link_quality

  ${item_prefix}_Command:
    type: String
    label: ${thing_label} combined command
    groups: ["${group_prefix}"]
    channel: mqtt:topic:mosquitto:${package_id}:command

The output:

# ==============================================================================
# Generated by openHAB 5.3.0 (Build #5542) YAML Composer, DO NOT EDIT
# Source:    yamlcomposer/test2.yaml
# Generated: 2026-08-20T10:14:20.073157654+10:00[Australia/Brisbane]
# ==============================================================================

version: 1

things:
  mqtt:topic:mosquitto:house_led_001:
    bridge: mqtt:broker:mosquitto
    label: House LED 001
    location: House
    channels:
      online:
        type: switch
        label: Online
        config:
          stateTopic: ArgyleCourt/House/LED_001/availability
          transformationPattern:
            - JSONPATH:$.state
          on: online
          off: offline
      power:
        type: switch
        label: Power
        config:
          stateTopic: ArgyleCourt/House/LED_001/state
          commandTopic: ArgyleCourt/House/LED_001/set/state
      brightness:
        type: dimmer
        label: Brightness
        config:
          stateTopic: ArgyleCourt/House/LED_001/brightness
          commandTopic: ArgyleCourt/House/LED_001/set
          transformationPattern:
            - JS:light_brightness_in.js
          transformationPatternOut:
            - JS:light_brightness_out.js
          formatBeforePublish: '{"brightness":%s,"transition":3}'
          min: 0
          max: 100
      colour:
        type: color
        label: Colour
        config:
          colorMode: XYY
          stateTopic: ArgyleCourt/House/LED_001
          commandTopic: ArgyleCourt/House/LED_001/set
          transformationPattern:
            - JS:light_xyy_in.js
          transformationPatternOut:
            - JS:light_xyy_out.js
      colour_temperature:
        type: dimmer
        label: Colour temperature
        config:
          stateTopic: ArgyleCourt/House/LED_001/color_temp
          commandTopic: ArgyleCourt/House/LED_001/set
          transformationPattern:
            - JS:light_temp_in.js
          transformationPatternOut:
            - JS:light_temp_out.js
          formatBeforePublish: '{"color_temp":%s,"transition":3}'
          min: 0
          max: 100
      colour_mode:
        type: string
        label: Colour mode
        config:
          stateTopic: ArgyleCourt/House/LED_001/color_mode
      link_quality:
        type: number
        label: Link quality
        config:
          stateTopic: ArgyleCourt/House/LED_001/linkquality
          min: 0
          max: 255
      command:
        type: string
        label: Combined JSON command
        config:
          commandTopic: ArgyleCourt/House/LED_001/set

  mqtt:topic:mosquitto:house_led_002:
    bridge: mqtt:broker:mosquitto
    label: House LED 002
    location: House
    channels:
      online:
        type: switch
        label: Online
        config:
          stateTopic: ArgyleCourt/House/LED_002/availability
          transformationPattern:
            - JSONPATH:$.state
          on: online
          off: offline
      power:
        type: switch
        label: Power
        config:
          stateTopic: ArgyleCourt/House/LED_002/state
          commandTopic: ArgyleCourt/House/LED_002/set/state
      brightness:
        type: dimmer
        label: Brightness
        config:
          stateTopic: ArgyleCourt/House/LED_002/brightness
          commandTopic: ArgyleCourt/House/LED_002/set
          transformationPattern:
            - JS:light_brightness_in.js
          transformationPatternOut:
            - JS:light_brightness_out.js
          formatBeforePublish: '{"brightness":%s,"transition":3}'
          min: 0
          max: 100
      colour:
        type: color
        label: Colour
        config:
          colorMode: XYY
          stateTopic: ArgyleCourt/House/LED_002
          commandTopic: ArgyleCourt/House/LED_002/set
          transformationPattern:
            - JS:light_xyy_in.js
          transformationPatternOut:
            - JS:light_xyy_out.js
      colour_temperature:
        type: dimmer
        label: Colour temperature
        config:
          stateTopic: ArgyleCourt/House/LED_002/color_temp
          commandTopic: ArgyleCourt/House/LED_002/set
          transformationPattern:
            - JS:light_temp_in.js
          transformationPatternOut:
            - JS:light_temp_out.js
          formatBeforePublish: '{"color_temp":%s,"transition":3}'
          min: 0
          max: 100
      colour_mode:
        type: string
        label: Colour mode
        config:
          stateTopic: ArgyleCourt/House/LED_002/color_mode
      link_quality:
        type: number
        label: Link quality
        config:
          stateTopic: ArgyleCourt/House/LED_002/linkquality
          min: 0
          max: 255
      command:
        type: string
        label: Combined JSON command
        config:
          commandTopic: ArgyleCourt/House/LED_002/set

items:
  grp_House_LED_001:
    type: Group
    label: House LED 001

  House_LED_001_Power:
    type: Switch
    label: House LED 001 power
    icon: switch
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:power

  House_LED_001_Brightness:
    type: Dimmer
    label: House LED 001 brightness
    icon: light
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:brightness

  House_LED_001_Colour:
    type: Color
    label: House LED 001 colour
    icon: colorwheel
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:colour

  House_LED_001_ColourTemperature:
    type: Dimmer
    label: House LED 001 colour temperature
    icon: colorwheel
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:colour_temperature

  House_LED_001_Online:
    type: Switch
    label: House LED 001 online
    icon: network
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:online

  House_LED_001_ColourMode:
    type: String
    label: House LED 001 colour mode
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:colour_mode

  House_LED_001_LinkQuality:
    type: Number
    label: House LED 001 link quality
    icon: network
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:link_quality

  House_LED_001_Command:
    type: String
    label: House LED 001 combined command
    groups:
      - grp_House_LED_001
    channel: mqtt:topic:mosquitto:house_led_001:command

  grp_House_LED_002:
    type: Group
    label: House LED 002

  House_LED_002_Power:
    type: Switch
    label: House LED 002 power
    icon: switch
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:power

  House_LED_002_Brightness:
    type: Dimmer
    label: House LED 002 brightness
    icon: light
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:brightness

  House_LED_002_Colour:
    type: Color
    label: House LED 002 colour
    icon: colorwheel
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:colour

  House_LED_002_ColourTemperature:
    type: Dimmer
    label: House LED 002 colour temperature
    icon: colorwheel
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:colour_temperature

  House_LED_002_Online:
    type: Switch
    label: House LED 002 online
    icon: network
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:online

  House_LED_002_ColourMode:
    type: String
    label: House LED 002 colour mode
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:colour_mode

  House_LED_002_LinkQuality:
    type: Number
    label: House LED 002 link quality
    icon: network
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:link_quality

  House_LED_002_Command:
    type: String
    label: House LED 002 combined command
    groups:
      - grp_House_LED_002
    channel: mqtt:topic:mosquitto:house_led_002:command

Would the ability to define local variables be useful? (Note this isn’t a part of the above PR. I don’t want to make the PR any bigger than it already is) I’ve decided to just combine them into that one PR!

For example:

variables:
  thingid: global # global var - will be shadowed by the local var but only within that scope
  items:
    - LivingRoom_Light
    - LivingRoom_Motion

items:
  !for id in items:
    !var thingid: ${id | lower} # thingid is a local variable scoped within the for block only
    ${id}_Power:
      channel: mqtt:topic:${thingid}:power
    ${id}_Color:
      channel: mqtt:topic:${thingid}:color

  AnotherItem:
    channel: mqtt:topic:${thingid}:channelid # thingid == `global` here.

The combined feature PR has been merged! It is now available in snapshot, and the docs are also live: