Skip to content

[yamlcomposer] Add !for loops, scoped local variables (!var), and enhance conditionals (!elseif, !else) - #21408

Merged
lsiepel merged 10 commits into
openhab:mainfrom
jimtng:yamlcomposer-loops
Aug 22, 2026
Merged

[yamlcomposer] Add !for loops, scoped local variables (!var), and enhance conditionals (!elseif, !else)#21408
lsiepel merged 10 commits into
openhab:mainfrom
jimtng:yamlcomposer-loops

Conversation

@jimtng

@jimtng jimtng commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR introduces several significant enhancements to the YAML Composer, focusing on dynamic content generation, improved conditional logic, and expanded expression support.

Key Features

  • Loop Support (!for): Add a new directive that allows for dynamic sequence iteration and templating within YAML definitions.
  • Key-Level !if: Introduce a shorthand form for the !if tag to streamline conditional blocks and improve readability.
  • Range Expressions: Add support for Jinjava range() functions and Ruby-style range syntax ([1..5] for inclusive and [1...5] for exclusive ranges).
  • Enumerate Support: Add enumerate as both a filter and a function, supporting list and map iteration with .key and .value accessors.
  • Local Variables (!var): Introduce the !var directive to declare scoped variables within maps or list contexts, improving modularity and local configuration reuse.

Internal Changes

  • Directive Processing Phase: Introduce a dedicated directive processing phase to the composer's transformation pipeline. This provides a more robust framework for handling structural tags like !for and !if.
  • Test Suite Reorganization: The existing test suite has been split into multiple specialized files. This reorganization improves maintainability and makes it easier to navigate the growing number of test cases.

Examples:

variables:
  environment: prod
  dev_ip: 192.168.1.50
  prod_ip: 10.0.0.20
  local_ip: 127.0.0.1

  things:
    - livingroom
    - bedroom

  channels:
    temperature:
      type: number
      label: Room Temperature
    humidity:
      type: number
      label: Humidity
    battery:
      type: number
      label: Battery Level
      stateDescription:
        pattern: "%.1f %%"

things:
  mqtt:broker:main:
    label: Main MQTT Broker
    config:
      # Key-Level if/elseif/else conditional
      !if environment == 'dev':
        host: ${dev_ip}
      !elseif environment == 'prod':
        host: ${prod_ip}
      !else ~: # Note the extra ~ is required for yaml compliance
        host: ${local_ip}

      # That can also be done with VARS (existing feature)
      host_with_vars: ${VARS[environment + '_ip']}


  # Looping through a list
  !for thing_id in things:
    mqtt:topic:${thing_id}:
      label: ${thing_id | label} MQTT Topic
      bridge: mqtt:broker:main
      channels:
        # Looping through a map
        !for id, channel in channels:
          ${id}:
            type: ${channel.type}
            label: ${channel.label}
            # Another Key-Level if conditional
            !if channel.stateDescription:
              stateDescription: ${channel.stateDescription}

  # Looping through a fixed range
  !for i in [1..4]:
    !var room_name: Room ${i} # Define a local variable here
    mqtt:topic:room${i}:
      label: ${room_name} MQTT Topic
      bridge: mqtt:broker:main
      channels:
        temperature:
          type: number
          label: ${room_name} Temperature

Output:

things:
  mqtt:broker:main:
    label: Main MQTT Broker
    config:
      host: 10.0.0.20
      host_with_vars: 10.0.0.20

  mqtt:topic:livingroom:
    label: Livingroom MQTT Topic
    bridge: mqtt:broker:main
    channels:
      temperature:
        type: number
        label: Room Temperature
      humidity:
        type: number
        label: Humidity
      battery:
        type: number
        label: Battery Level
        stateDescription:
          pattern: '%.1f %%'

  mqtt:topic:bedroom:
    label: Bedroom MQTT Topic
    bridge: mqtt:broker:main
    channels:
      temperature:
        type: number
        label: Room Temperature
      humidity:
        type: number
        label: Humidity
      battery:
        type: number
        label: Battery Level
        stateDescription:
          pattern: '%.1f %%'

  mqtt:topic:room1:
    label: Room 1 MQTT Topic
    bridge: mqtt:broker:main
    channels:
      temperature:
        type: number
        label: Room 1 Temperature

  mqtt:topic:room2:
    label: Room 2 MQTT Topic
    bridge: mqtt:broker:main
    channels:
      temperature:
        type: number
        label: Room 2 Temperature

  mqtt:topic:room3:
    label: Room 3 MQTT Topic
    bridge: mqtt:broker:main
    channels:
      temperature:
        type: number
        label: Room 3 Temperature

  mqtt:topic:room4:
    label: Room 4 MQTT Topic
    bridge: mqtt:broker:main
    channels:
      temperature:
        type: number
        label: Room 4 Temperature

@jimtng
jimtng force-pushed the yamlcomposer-loops branch from 84e3953 to 3c50d2b Compare August 16, 2026 09:25
@jimtng jimtng changed the title [yamlcomposer] Add !for loop support and a simplified !if/!elseif/!else syntax [yamlcomposer] Add Loop support (!for) and enhance Conditionals Aug 16, 2026
@openhab-bot

Copy link
Copy Markdown
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/kudo-for-yamlcomposer-indicator-and-zigbee-lights-creation-of-items-groups-etc/170091/5

@jimtng
jimtng marked this pull request as ready for review August 16, 2026 09:50
@jimtng
jimtng force-pushed the yamlcomposer-loops branch from 3c50d2b to 1d17beb Compare August 16, 2026 10:14
@lsiepel lsiepel added the enhancement An enhancement or new feature for an existing add-on label Aug 16, 2026
@jimtng
jimtng force-pushed the yamlcomposer-loops branch 6 times, most recently from f587b97 to abddf22 Compare August 17, 2026 09:59
@jimtng

jimtng commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

rebased

@jimtng
jimtng force-pushed the yamlcomposer-loops branch from fe8cff1 to 957c21b Compare August 21, 2026 02:01
@jimtng jimtng changed the title [yamlcomposer] Add Loop support (!for) and enhance Conditionals [yamlcomposer] Add control flow directives (!if, !else, !for) and local variables (!var) Aug 21, 2026
@jimtng
jimtng force-pushed the yamlcomposer-loops branch 3 times, most recently from 2b49b05 to 1eca69a Compare August 21, 2026 04:32
@jimtng
jimtng requested a review from a team as a code owner August 21, 2026 04:32
@jimtng
jimtng force-pushed the yamlcomposer-loops branch from 1eca69a to 9fbd162 Compare August 21, 2026 04:53
@jimtng jimtng changed the title [yamlcomposer] Add control flow directives (!if, !else, !for) and local variables (!var) [yamlcomposer] Add !for loops, scoped local variables (!var), and enhance conditionals (!elseif, !else) Aug 21, 2026

@lsiepel lsiepel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My codex friend looked at it and found these three comments.

This is an initial AI-assisted review.

Comment thread bundles/org.openhab.io.yamlcomposer/doc/CHANGELOG.md Outdated
@jimtng
jimtng force-pushed the yamlcomposer-loops branch 2 times, most recently from 915763d to 80816f9 Compare August 22, 2026 00:46
@jimtng
jimtng requested a review from lsiepel August 22, 2026 09:10
jimtng added 4 commits August 23, 2026 06:10
…local variables (`!var`), `range()` function, and `enumerate` support

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
…ainState parameter

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
jimtng added 6 commits August 23, 2026 06:10
…g parser

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
…!else ~:` syntax

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
@jimtng
jimtng force-pushed the yamlcomposer-loops branch from 5d9b457 to e10f46a Compare August 22, 2026 20:10
@jimtng

jimtng commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

rebased

@lsiepel lsiepel left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM

@lsiepel
lsiepel merged commit 2676d1b into openhab:main Aug 22, 2026
2 checks passed
@lsiepel lsiepel added this to the 5.3 milestone Aug 22, 2026
@jimtng
jimtng deleted the yamlcomposer-loops branch August 23, 2026 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement An enhancement or new feature for an existing add-on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants