Skip to content

Sitemap YAML serialization and parsing#5482

Draft
lolodomo wants to merge 28 commits intoopenhab:mainfrom
lolodomo:sitemap_yaml
Draft

Sitemap YAML serialization and parsing#5482
lolodomo wants to merge 28 commits intoopenhab:mainfrom
lolodomo:sitemap_yaml

Conversation

@lolodomo
Copy link
Copy Markdown
Contributor

This PR creates a new YAML format for sitemaps.

This PR builds on #5459 and partially replaces #4945 (covering YAML).
It also makes further steps towards #5007

mherwege added 27 commits March 27, 2026 09:19
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
@lolodomo lolodomo requested a review from a team as a code owner April 11, 2026 11:40
@lolodomo lolodomo marked this pull request as draft April 11, 2026 11:40
@lolodomo
Copy link
Copy Markdown
Contributor Author

@mherwege for information
I will rebase the PR when #5459 is finally merged.
This is still work in progress, even if almost finished.

@mherwege
Copy link
Copy Markdown
Contributor

Yes, I agree. What do you propose ?

argument inside the condition and value for the result?

@lolodomo
Copy link
Copy Markdown
Contributor Author

version: 1
sitemaps:
  demo:
    label: Demo Sitemap
    widgets:
      - type: Frame
        label:
          text: Demo Items
        widgets:
          - type: Text
            item: DemoContact
            label:
              text: Contact
              format: MAP(en.map):%s
          - type: Text
            item: DemoString
            label:
              text: Message
              format: '%s'
            widgets:
              - type: Default
                item: DemoSwitch
                label:
                  text: Default widget
              - type: Default
                item: DemoLocation
                height: 10
          - type: Text
            item: DemoDateTime
            label:
              text: Date
              format: "%1$tA, %1$td.%1$tm.%1$tY"
              textColor:
                - and:
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                  value: blue
                - value: orange
              valueColor:
                - and:
                    - item: DemoSwitch
                      operator: ==
                      argument: "OFF"
                  value: green
                - value: yellow
          - type: Group
            item: DemoSwitchGroup
            icon:
              name: oh:classic:Garage
      - type: Frame
        label:
          text: Switch & Selection
        widgets:
          - type: Switch
            item: DemoSwitch
          - type: Switch
            item: DemoSwitch
            mappings:
              - command: "ON"
                label: "On"
              - command: "OFF"
                label: "Off"
          - type: Switch
            item: DemoSwitch
            mappings:
              - command: "ON"
                label: "On"
                icon: switch-on
              - command: "OFF"
                label: "Off"
                icon: switch-off
          - type: Selection
            item: DemoSwitch
            label:
              text: Test Selection
            icon:
              name: switch
            mappings:
              - command: "ON"
                label: Switch ON
              - command: "OFF"
                label: Switch OFF
          - type: Switch
            item: DemoSwitch
            label:
              text: Button with release
            mappings:
              - command: "ON"
                releaseCommand: "OFF"
                label: Switch ON
      - type: Frame
        label:
          text: "Input, Slider & Setpoinnt"
        widgets:
          - type: Input
            item: DemoNumber
            label:
              text: Test Input
          - type: Input
            item: DemoNumber
            hint: number
          - type: Text
            item: DemoNumber
            label:
              text: Test Text
              format: '%d'
              textColor:
                - and:
                    - operator: <
                      argument: "50"
                  value: green
                - and:
                    - operator: <=
                      argument: "75"
                  value: orange
                - value: red
              valueColor:
                - and:
                    - operator: <
                      argument: "50"
                  value: blue
                - and:
                    - operator: <=
                      argument: "75"
                  value: violet
                - value: cyan
            icon:
              name: Garden
              color:
                - value: red
              static: true
          - type: Slider
            item: DemoNumber
            label:
              text: Test Slider
          - type: Slider
            item: DemoNumber
            switchSupport: true
          - type: Slider
            item: DemoNumber
            releaseOnly: true
          - type: Slider
            item: DemoNumber
            min: 25
            max: 75
            step: 5
          - type: Setpoint
            item: DemoNumber
            label:
              text: Test Setpoint
          - type: Setpoint
            item: DemoNumber
            min: 25
            max: 75
            step: 5
      - type: Frame
        label:
          text: Colorpicker & Colortemperaturepicker
        widgets:
          - type: Colorpicker
            item: DemoColor
          - type: Colortemperaturepicker
            item: DemoColorTemp
            label:
              text: Test Colortemperaturepicker
          - type: Colortemperaturepicker
            item: DemoColorTemp
            min: 3000
            max: 5000
      - type: Frame
        label:
          text: Image & Video
        widgets:
          - type: Image
            item: DemoImage
            label:
              text: Test Image
            url: https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png
          - type: Image
            url: https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png
            refresh: 600000
          - type: Video
            label:
              text: Test Video
            url: https://demo.openhab.org/Hue.m4v
          - type: Video
            url: https://demo.openhab.org/Hue.m4v
            encoding: hls
      - type: Frame
        label:
          text: Magic Test Items
        widgets:
          - type: Colorpicker
            item: MagicColor
          - type: Switch
            item: MagicOnOff
          - type: Slider
            item: MagicDimmer
      - type: Frame
        label:
          text: Location
        widgets:
          - type: Mapview
            item: DemoLocation
            visibility:
              - and:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
          - type: Mapview
            item: DemoLocation
            label:
              text: Test Mapview
            height: 10
            visibility:
              - and:
                  - item: DemoSwitch
                    operator: '!='
                    argument: "ON"
      - type: Frame
        label:
          text: WEB
        widgets:
          - type: Webview
            url: https://www.openhab.org/
            visibility:
              - and:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
          - type: Webview
            label:
              text: Test Webview
            height: 15
            url: https://www.openhab.org/
            visibility:
              - and:
                  - item: DemoSwitch
                    operator: '!='
                    argument: "ON"

@mherwege
Copy link
Copy Markdown
Contributor

mherwege commented Apr 12, 2026

visibility:
  item: DemoSwitch
  operator: '!='
  argument: "ON"

I also like the short form if there is only one condition.

@lolodomo
Copy link
Copy Markdown
Contributor Author

Rather than label => text + format + textColor + valueColor, I will change to text => label + labelColor + valueFormat + valueColor.

@mherwege
Copy link
Copy Markdown
Contributor

@lolodomo, for video encoding, does it matter if the encoding value is lower or uppercase? The documentation says mjpeg or HLS (in uppercase). The ui code was respecting that, so fails with the sitemap above.

@spacemanspiff2007
Copy link
Copy Markdown
Contributor

spacemanspiff2007 commented Apr 13, 2026

Rather than label => text + format + textColor + valueColor, I will change to text => label + labelColor + valueFormat + valueColor.

In the yaml item definition we have the label and format - I think it makes sense if the names of the keys align.

So how about

text:
  label: MyLabel
  format: "%d"
  labelColor: ...   # <-- should be label rather than text because it applies to the thing configured under "label"
  valueColor: ...

Do you think it makes sense to not allow the short form?

@spacemanspiff2007
Copy link
Copy Markdown
Contributor

spacemanspiff2007 commented Apr 13, 2026

            visibility:
              - and:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"

Why is the and in a list? I would have expected it to be either

            visibility:
              and:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"

or the short form

            visibility:
                item: DemoSwitch
                operator: ==
                argument: "ON"

@spacemanspiff2007
Copy link
Copy Markdown
Contributor

spacemanspiff2007 commented Apr 13, 2026

textColor:
  - and:
      - operator: <
        argument: "50"
    value: green
  - and:
      - operator: <=
        argument: "75"
    value: orange
  - value: red

I find this very hard to read and understand. I also don't think the and should be in a list and and doesn't make sense here.
How about this where both value and conditional is optional?

textColor:
  value: red
  conditional:
    - operator: <
      argument: "50"
      value: green
    - operator: <=
      argument: "75"
      value: orange

@mherwege
Copy link
Copy Markdown
Contributor

textColor:
  - and:
      - operator: <
        argument: "50"
    value: green
  - and:
      - operator: <=
        argument: "75"
    value: orange
  - value: red

and should indeed not be in a list.

I find this very hard to read and understand. I also don't think the and should be in a list and and doesn't make sense here. How about this where both value and conditional is optional?

textColor:
  value: red
  conditional:
    - operator: <
      argument: "50"
      value: green
    - operator: <=
      argument: "75"
      value: orange

I don't understand this one. Look at the DSL code:

labelcolor=[< 50="green", <= 75="orange", "red"]

This is just sequence dependent or. And and should be optional there if there is only one condition inside the or.
By the way, you switched sequence, `"red"´ only applies if the previous 2 conditions do not apply. So it needs to remain conditional.

But how would it look for AND?

labelcolor=[item1<50 AND item2>50="green", <=75="orange","red"]

That's what I was trying to discuss.

@spacemanspiff2007
Copy link
Copy Markdown
Contributor

spacemanspiff2007 commented Apr 13, 2026

By the way, you switched sequence

Yes - the idea was that value gets selected if none of the condition matches.
It's more or less the default and thus should not be in the condition group.
Maybe conditions is a better word? Good objections.
I'm starting to think maybe another approach makes it more clear:

# convenience for 
# labelcolor=["red"]
textColor: red
# labelcolor=[< 50="green", <= 75="orange", "red"]
textColor:
  - color: green
    condition:
      operator: ''<'
      argument: "50"

  - color: orange
    condition:
      operator: <=
      argument: "75"

  - color: red

But how would it look for AND?

# labelcolor=[item1<50 AND item2>50="green", <=75="orange","red"]
textColor:
  - color: green
    condition:
      and:
        - item: item1
          operator: '<'
          argument: "50"
        - item: item2
          operator: '>'
          argument: "50"

  - color: orange
    condition:
      operator: <=
      argument: "75"

  - color: red

It's the same condition structure which we already use for visibility but with optional item
condition would be optional and textColor contains a list of statements.
Under condition there can be the condition directly or the and block.

@mherwege
Copy link
Copy Markdown
Contributor

mherwege commented Apr 13, 2026

# labelcolor=[item1<50 AND item2>50="green", <=75="orange","red"]
textColor:
  - color: green
    condition:
      and:
        - item: item1
          operator: '<'
          argument: "50"
        - item: item2
          operator: '>'
          argument: "50"

  - color: orange
    condition:
      operator: <=
      argument: "75"

  - color: red

Why do you need the condition level at all in this? Can’t you just put item, operator and argument directly under color if there are not multiple and statements?

# labelcolor=[item1<50 AND item2>50="green", <=75="orange","red"]
textColor:
  - color: green
    and:
       - item: item1
         operator: '<'
         argument: "50"
       - item: item2
         operator: '>'
         argument: "50"
  - color: orange
    operator: <=
     argument: "75"
  - color: red

Also, item and operator are also optional.

@lolodomo
Copy link
Copy Markdown
Contributor Author

lolodomo commented Apr 13, 2026

@lolodomo, for video encoding, does it matter if the encoding value is lower or uppercase? The documentation says mjpeg or HLS (in uppercase). The ui code was respecting that, so fails with the sitemap above.

DSL syntax does not define any constraint. I have not defined one in YAML.
Note that Basic UI ignores case and consider two values: jpeg and hls.

@mherwege
Copy link
Copy Markdown
Contributor

DDL syntax does not define any constraint. I have not defined one in YAML.
Note that Basic UI ignores case and consider two values: jpeg and hls.

The UI does because it has a dropdown with the allowed values. But I will make it case agnostic.

@lolodomo
Copy link
Copy Markdown
Contributor Author

So how about

text:
  label: MyLabel
  format: "%d"
  labelColor: ...   # <-- should be label rather than text because it applies to the thing configured under "label"
  valueColor: ...

Do you think it makes sense to not allow the short form?

I will consider that:

label:
  label: MyLabel
  format: "%d"
  labelColor: ...
  valueColor: ...

With this short form:

label: "MyLabel [%d]"

@lolodomo
Copy link
Copy Markdown
Contributor Author

lolodomo commented Apr 13, 2026

Why is the and in a list? I would have expected it to be either

The and is in a list because you define different rules each one with a list of conditions (and) and a value (color or icon).
First the conditions of the first rule is evaluated. If true, the corresponding color0icon is considered. If false we try the second rule. And so on.
Each list element is a rule.

and should indeed not be in a list.

Of course it should, I just explained why.

@lolodomo
Copy link
Copy Markdown
Contributor Author

Can’t you just put item, operator and argument directly under color if there are not multiple and statements?

# labelcolor=[item1<50 AND item2>50="green", <=75="orange","red"]
textColor:
  - color: green
    and:
       - item: item1
         operator: '<'
         argument: "50"
       - item: item2
         operator: '>'
         argument: "50"
  - color: orange
    operator: <=
     argument: "75"
  - color: red

Also, item and operator are also optional.

It is exactly what I implemented yesterday evening (not yet pushed).

@lolodomo
Copy link
Copy Markdown
Contributor Author

I will enhance my sitemap example to cover one unique or multiple and condition.

@mherwege
Copy link
Copy Markdown
Contributor

I will enhance my sitemap example to cover one unique or multiple and condition.

And while you are at it, what about Buttongrid with buttons, with Buttons and with a combination?

@lolodomo
Copy link
Copy Markdown
Contributor Author

And while you are at it, what about Buttongrid with buttons, with Buttons and with a combination?

Yes also.
I am just telling me that there is no reason to consider both ways to define buttons in a Buttongrid in YAML. It was kept in DSL just for backward compatibility.

@mherwege
Copy link
Copy Markdown
Contributor

I am just telling me that there is no reason to consider both ways to define buttons in a Buttongrid in YAML. It was kept in DSL just for backward compatibility.

True. But we still have it in the core object representation as well. And at the moment I still have it in the UI code. It is shorter with the buttons= representation if you don't need the extras. If we drop it, we should maybe drop it from the core registry and do the translation when going from DSL to the registry?

@lolodomo
Copy link
Copy Markdown
Contributor Author

DSL sitemap:

sitemap demo label="Demo Sitemap" {
	Frame label="Demo Items"  {
		Text item=DemoContact label="Contact [MAP(en.map):%s]" labelcolor=["green"] valuecolor=["blue"] iconcolor=["red"]
		Text item=DemoString label="Message [%s]" {
            Default item=DemoSwitch label="Default widget"
            Default item=DemoLocation height=10
		}
		Text item=DemoDateTime label="Date [%1$tA, %1$td.%1$tm.%1$tY]"
		    labelcolor=[DemoSwitch == ON = "blue", "orange"]
            valuecolor=[DemoSwitch == OFF = "green", "yellow"]
            iconcolor=[DemoSwitch == ON = "red", "yellow"]
		Group item=DemoSwitchGroup
	}
    Frame label="Switch & Selection"  {
        Switch item=DemoSwitch
        Switch item=DemoSwitch mappings=[ON=On, OFF=Off]
        Switch item=DemoSwitch mappings=[ON=On=switch-on, OFF=Off=switch-off]
        Selection item=DemoSwitch label="Test Selection" icon=switch mappings=[ON="Switch ON", OFF="Switch OFF"]
        Switch item=DemoSwitch label="Button with release" mappings=[ON:OFF="Switch ON"]
    }
    Frame label="Input, Slider & Setpoinnt"  {
        Input item=DemoNumber label="Test Input"
        Input item=DemoNumber inputHint="number"
        Text item=DemoNumber label="Test Text [%d]" staticIcon=Garden
            labelcolor=[< 50 AND DemoSwitch == ON = "green",<= 75 = "orange"]
            valuecolor=[< 50 AND DemoSwitch == ON = "blue",<= 75 = "violet"]
            iconcolor=[< 50 AND DemoSwitch == ON = "red",<= 75 = "yellow"]
        Slider item=DemoNumber label="Test Slider" staticIcon=oh:classic:Garden
        Slider item=DemoNumber switchSupport icon=oh:classic:Garage
        Slider item=DemoNumber releaseOnly icon=Garage iconcolor=["green"]
        Slider item=DemoNumber minValue=25 maxValue=75 step=5
        Setpoint item=DemoNumber label="Test Setpoint"
        Setpoint item=DemoNumber minValue=25 maxValue=75 step=5
    }
    Frame label="Colorpicker & Colortemperaturepicker" {
       Colorpicker item=DemoColor
       Colortemperaturepicker item=DemoColorTemp label="Test Colortemperaturepicker"
       Colortemperaturepicker item=DemoColorTemp minValue=3000 maxValue=5000
    }
    Frame label="Image & Video" {
       Image label="Test Image" item=DemoImage url="https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png"
       Image url="https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png" refresh=600000
       Video label="Test Video" url="https://demo.openhab.org/Hue.m4v"
       Video url="https://demo.openhab.org/Hue.m4v" encoding="hls"
    }
    Frame label="Buttongrid" {
        Buttongrid item=DemoString buttons=[2:2:HOME="Go Home"=material:home] {
            Button row=1 column=1 item=DemoSwitch click=ON label="Off" icon=switch-off stateless visibility=[DemoSwitch != ON]
            Button row=1 column=1 item=DemoSwitch click=OFF label="On" icon=switch-on stateless visibility=[DemoSwitch == ON]
            Button row=1 column=2 item=DemoString click=START label="Start" stateless visibility=[DemoSwitch == ON]
            Button row=1 column=3 item=DemoString click=STOP label="Stop" stateless visibility=[DemoSwitch == ON]
        }
    }
	Frame label="Magic Test Items" {
	   Colorpicker item=MagicColor
	   Switch item=MagicOnOff
	   Slider item=MagicDimmer
	}
	Frame label="Location" {
		Mapview item=DemoLocation visibility=[DemoSwitch==ON]
        Mapview item=DemoLocation label="Test Mapview" height=10 visibility=[DemoSwitch!=ON]
	}
    Frame label="WEB" {
        Webview url="https://www.openhab.org/" visibility=[DemoSwitch==ON]
        Webview label="Test Webview" height=15 url="https://www.openhab.org/" visibility=[DemoSwitch!=ON]
    }
}

Equivalent sitemap in YAML:

version: 1
sitemaps:
  demo:
    label: Demo Sitemap
    widgets:
      - type: Frame
        label: Demo Items
        widgets:
          - type: Text
            item: DemoContact
            label:
              label: Contact
              format: MAP(en.map):%s
              labelColor: green
              valueColor: blue
            icon:
              color: red
          - type: Text
            item: DemoString
            label:
              label: Message
              format: '%s'
            widgets:
              - type: Default
                item: DemoSwitch
                label: Default widget
              - type: Default
                item: DemoLocation
                height: 10
          - type: Text
            item: DemoDateTime
            label:
              label: Date
              format: "%1$tA, %1$td.%1$tm.%1$tY"
              labelColor:
                - value: blue
                  item: DemoSwitch
                  operator: ==
                  argument: "ON"
                - value: orange
              valueColor:
                - value: green
                  item: DemoSwitch
                  operator: ==
                  argument: "OFF"
                - value: yellow
            icon:
              color:
                - value: red
                  item: DemoSwitch
                  operator: ==
                  argument: "ON"
                - value: yellow
          - type: Group
            item: DemoSwitchGroup
      - type: Frame
        label: Switch & Selection
        widgets:
          - type: Switch
            item: DemoSwitch
          - type: Switch
            item: DemoSwitch
            mappings:
              - command: "ON"
                label: "On"
              - command: "OFF"
                label: "Off"
          - type: Switch
            item: DemoSwitch
            mappings:
              - command: "ON"
                label: "On"
                icon: switch-on
              - command: "OFF"
                label: "Off"
                icon: switch-off
          - type: Selection
            item: DemoSwitch
            label: Test Selection
            icon: switch
            mappings:
              - command: "ON"
                label: Switch ON
              - command: "OFF"
                label: Switch OFF
          - type: Switch
            item: DemoSwitch
            label: Button with release
            mappings:
              - command: "ON"
                releaseCommand: "OFF"
                label: Switch ON
      - type: Frame
        label: "Input, Slider & Setpoinnt"
        widgets:
          - type: Input
            item: DemoNumber
            label: Test Input
          - type: Input
            item: DemoNumber
            hint: number
          - type: Text
            item: DemoNumber
            label:
              label: Test Text
              format: '%d'
              labelColor:
                - value: green
                  and:
                    - operator: <
                      argument: "50"
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                - value: orange
                  operator: <=
                  argument: "75"
              valueColor:
                - value: blue
                  and:
                    - operator: <
                      argument: "50"
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                - value: violet
                  operator: <=
                  argument: "75"
            icon:
              name: Garden
              color:
                - value: red
                  and:
                    - operator: <
                      argument: "50"
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                - value: yellow
                  operator: <=
                  argument: "75"
              static: true
          - type: Slider
            item: DemoNumber
            label: Test Slider
            icon:
              name: oh:classic:Garden
              static: true
          - type: Slider
            item: DemoNumber
            icon: oh:classic:Garage
            switchSupport: true
          - type: Slider
            item: DemoNumber
            icon:
              name: Garage
              color: green
            releaseOnly: true
          - type: Slider
            item: DemoNumber
            min: 25
            max: 75
            step: 5
          - type: Setpoint
            item: DemoNumber
            label: Test Setpoint
          - type: Setpoint
            item: DemoNumber
            min: 25
            max: 75
            step: 5
      - type: Frame
        label: Colorpicker & Colortemperaturepicker
        widgets:
          - type: Colorpicker
            item: DemoColor
          - type: Colortemperaturepicker
            item: DemoColorTemp
            label: Test Colortemperaturepicker
          - type: Colortemperaturepicker
            item: DemoColorTemp
            min: 3000
            max: 5000
      - type: Frame
        label: Image & Video
        widgets:
          - type: Image
            item: DemoImage
            label: Test Image
            url: https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png
          - type: Image
            url: https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png
            refresh: 600000
          - type: Video
            label: Test Video
            url: https://demo.openhab.org/Hue.m4v
          - type: Video
            url: https://demo.openhab.org/Hue.m4v
            encoding: hls
      - type: Frame
        label: Buttongrid
        widgets:
          - type: Buttongrid
            item: DemoString
            widgets:
              - type: Button
                item: DemoString
                label: Go Home
                icon: material:home
                row: 2
                column: 2
                command: HOME
              - type: Button
                item: DemoSwitch
                label: "Off"
                icon: switch-off
                row: 1
                column: 1
                command: "ON"
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: '!='
                    argument: "ON"
              - type: Button
                item: DemoSwitch
                label: "On"
                icon: switch-on
                row: 1
                column: 1
                command: "OFF"
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
              - type: Button
                item: DemoString
                label: Start
                row: 1
                column: 2
                command: START
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
              - type: Button
                item: DemoString
                label: Stop
                row: 1
                column: 3
                command: STOP
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
      - type: Frame
        label: Magic Test Items
        widgets:
          - type: Colorpicker
            item: MagicColor
          - type: Switch
            item: MagicOnOff
          - type: Slider
            item: MagicDimmer
      - type: Frame
        label: Location
        widgets:
          - type: Mapview
            item: DemoLocation
            visibility:
              - item: DemoSwitch
                operator: ==
                argument: "ON"
          - type: Mapview
            item: DemoLocation
            label: Test Mapview
            height: 10
            visibility:
              - item: DemoSwitch
                operator: '!='
                argument: "ON"
      - type: Frame
        label: WEB
        widgets:
          - type: Webview
            url: https://www.openhab.org/
            visibility:
              - item: DemoSwitch
                operator: ==
                argument: "ON"
          - type: Webview
            label: Test Webview
            height: 15
            url: https://www.openhab.org/
            visibility:
              - item: DemoSwitch
                operator: '!='
                argument: "ON"

You will find short form for label, icon and labelColor/valueColor/(icon)color.

@lolodomo
Copy link
Copy Markdown
Contributor Author

lolodomo commented Apr 14, 2026

If we drop it, we should maybe drop it from the core registry and do the translation when going from DSL to the registry?

Yes that would be my suggestion
We should also log a deprecation warning in DSL provider but continue to accept it (with automatic conversion into Button widgets in the registry).
WDYT?

@mherwege
Copy link
Copy Markdown
Contributor

If we drop it, we should maybe drop it from the core registry and do the translation when going from DSL to the registry?

Yes that would be my suggestion We should also log a deprecation warning in DSL provider but continue to accept it (with automatic conversion into Button widgets in the registry). WDYT?

Completely agree. Question is if we still include it in the DSL PR, or we do it in a separate step.
Also the uicomponent storage to registry will be impacted.
Also, as you split out format in a separate field in YAML, I am wondering if we should also make it a separate field in the registry.

@lolodomo
Copy link
Copy Markdown
Contributor Author

Completely agree. Question is if we still include it in the DSL PR, or we do it in a separate step.

Maybe a new separate PR.
As your DSL PR is fully ready for a merge I still have a little hope to see it merged in the coming days.

Also, as you split out format in a separate field in YAML, I am wondering if we should also make it a separate field in the registry.

Yes, probably.

This PR creates a new YAML format for sitemaps.

This PR builds on openhab#5459 and partially replaces openhab#4945 (covering YAML).
It also makes further steps towards openhab#5007

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
@lolodomo
Copy link
Copy Markdown
Contributor Author

lolodomo commented Apr 14, 2026

Extended example with icon rules.
I will certainly rename "definition" into "name" so that "name" can be used either to provide direct icon name or icon definition rules.

sitemap demo label="Demo Sitemap" {
	Frame label="Demo Items"  {
		Text item=DemoContact label="Contact [MAP(en.map):%s]" labelcolor=["green"] valuecolor=["blue"] iconcolor=["red"]
		Text item=DemoString label="Message [%s]" {
            Default item=DemoSwitch label="Default widget"
            Default item=DemoLocation height=10
		}
		Text item=DemoDateTime label="Date [%1$tA, %1$td.%1$tm.%1$tY]" icon=material:home
		    labelcolor=[DemoSwitch == ON = "blue", "orange"]
            valuecolor=[DemoSwitch == OFF = "green", "yellow"]
            iconcolor=[DemoSwitch == ON = "red", "pink"]
		Group item=DemoSwitchGroup
	}
    Frame label="Switch & Selection"  {
        Switch item=DemoSwitch
        Switch item=DemoSwitch mappings=[ON=On, OFF=Off]
        Switch item=DemoSwitch mappings=[ON=On=switch-on, OFF=Off=switch-off]
        Selection item=DemoSwitch label="Test Selection" icon=switch mappings=[ON="Switch ON", OFF="Switch OFF"]
        Switch item=DemoSwitch label="Button with release" mappings=[ON:OFF="Switch ON"]
    }
    Frame label="Input, Slider & Setpoinnt"  {
        Input item=DemoNumber label="Test Input"
        Input item=DemoNumber inputHint="number"
        Text item=DemoNumber label="Test Text [%d]" staticIcon=material:settings
            labelcolor=[< 50 AND DemoSwitch == ON = "green",<= 75 = "orange"]
            valuecolor=[< 50 AND DemoSwitch == ON = "blue",<= 75 = "red"]
            iconcolor=[< 50 AND DemoSwitch == ON = "red",<= 75 = "green"]
        Slider item=DemoNumber label="Test Slider" staticIcon=oh:classic:Garden
        Slider item=DemoNumber switchSupport icon=oh:classic:Garage
        Slider item=DemoNumber releaseOnly icon=[DemoSwitch==ON=material:home, material:favorite] iconcolor=["blue"]
        Slider item=DemoNumber minValue=25 maxValue=75 step=5
        Setpoint item=DemoNumber label="Test Setpoint"
        Setpoint item=DemoNumber minValue=25 maxValue=75 step=5
    }
    Frame label="Colorpicker & Colortemperaturepicker" {
       Colorpicker item=DemoColor
       Colortemperaturepicker item=DemoColorTemp label="Test Colortemperaturepicker"
       Colortemperaturepicker item=DemoColorTemp minValue=3000 maxValue=5000
    }
    Frame label="Image & Video" {
       Image label="Test Image" item=DemoImage url="https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png"
       Image url="https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png" refresh=600000
       Video label="Test Video" url="https://demo.openhab.org/Hue.m4v"
       Video url="https://demo.openhab.org/Hue.m4v" encoding="hls"
    }
    Frame label="Buttongrid" {
        Buttongrid item=DemoString buttons=[2:2:HOME="Go Home"=material:home] {
            Button row=1 column=1 item=DemoSwitch click=ON label="Off" icon=switch-off stateless visibility=[DemoSwitch != ON]
            Button row=1 column=1 item=DemoSwitch click=OFF label="On" icon=switch-on stateless visibility=[DemoSwitch == ON]
            Button row=1 column=2 item=DemoString click=START label="Start" stateless visibility=[DemoSwitch == ON]
            Button row=1 column=3 item=DemoString click=STOP label="Stop" stateless visibility=[DemoSwitch == ON]
        }
    }
	Frame label="Magic Test Items" {
	   Colorpicker item=MagicColor
	   Switch item=MagicOnOff
	   Slider item=MagicDimmer
	}
	Frame label="Location" {
		Mapview item=DemoLocation visibility=[DemoSwitch==ON]
        Mapview item=DemoLocation label="Test Mapview" height=10 visibility=[DemoSwitch!=ON]
	}
    Frame label="WEB" {
        Webview url="https://www.openhab.org/" visibility=[DemoSwitch==ON]
        Webview label="Test Webview" height=15 url="https://www.openhab.org/" visibility=[DemoSwitch!=ON]
    }
}

And the YAML:

version: 1
sitemaps:
  demo:
    label: Demo Sitemap
    widgets:
      - type: Frame
        label: Demo Items
        widgets:
          - type: Text
            item: DemoContact
            label:
              label: Contact
              format: MAP(en.map):%s
              labelColor: green
              valueColor: blue
            icon:
              color: red
          - type: Text
            item: DemoString
            label:
              label: Message
              format: '%s'
            widgets:
              - type: Default
                item: DemoSwitch
                label: Default widget
              - type: Default
                item: DemoLocation
                height: 10
          - type: Text
            item: DemoDateTime
            label:
              label: Date
              format: "%1$tA, %1$td.%1$tm.%1$tY"
              labelColor:
                - value: blue
                  item: DemoSwitch
                  operator: ==
                  argument: "ON"
                - value: orange
              valueColor:
                - value: green
                  item: DemoSwitch
                  operator: ==
                  argument: "OFF"
                - value: yellow
            icon:
              name: material:home
              color:
                - value: red
                  item: DemoSwitch
                  operator: ==
                  argument: "ON"
                - value: pink
          - type: Group
            item: DemoSwitchGroup
      - type: Frame
        label: Switch & Selection
        widgets:
          - type: Switch
            item: DemoSwitch
          - type: Switch
            item: DemoSwitch
            mappings:
              - command: "ON"
                label: "On"
              - command: "OFF"
                label: "Off"
          - type: Switch
            item: DemoSwitch
            mappings:
              - command: "ON"
                label: "On"
                icon: switch-on
              - command: "OFF"
                label: "Off"
                icon: switch-off
          - type: Selection
            item: DemoSwitch
            label: Test Selection
            icon: switch
            mappings:
              - command: "ON"
                label: Switch ON
              - command: "OFF"
                label: Switch OFF
          - type: Switch
            item: DemoSwitch
            label: Button with release
            mappings:
              - command: "ON"
                releaseCommand: "OFF"
                label: Switch ON
      - type: Frame
        label: "Input, Slider & Setpoinnt"
        widgets:
          - type: Input
            item: DemoNumber
            label: Test Input
          - type: Input
            item: DemoNumber
            hint: number
          - type: Text
            item: DemoNumber
            label:
              label: Test Text
              format: '%d'
              labelColor:
                - value: green
                  and:
                    - operator: <
                      argument: "50"
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                - value: orange
                  operator: <=
                  argument: "75"
              valueColor:
                - value: blue
                  and:
                    - operator: <
                      argument: "50"
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                - value: red
                  operator: <=
                  argument: "75"
            icon:
              name: material:settings
              color:
                - value: red
                  and:
                    - operator: <
                      argument: "50"
                    - item: DemoSwitch
                      operator: ==
                      argument: "ON"
                - value: green
                  operator: <=
                  argument: "75"
              static: true
          - type: Slider
            item: DemoNumber
            label: Test Slider
            icon:
              name: oh:classic:Garden
              static: true
          - type: Slider
            item: DemoNumber
            icon: oh:classic:Garage
            switchSupport: true
          - type: Slider
            item: DemoNumber
            icon:
              definition:
                - value: material:home
                  item: DemoSwitch
                  operator: ==
                  argument: "ON"
                - value: material:favorite
              color: blue
            releaseOnly: true
          - type: Slider
            item: DemoNumber
            min: 25
            max: 75
            step: 5
          - type: Setpoint
            item: DemoNumber
            label: Test Setpoint
          - type: Setpoint
            item: DemoNumber
            min: 25
            max: 75
            step: 5
      - type: Frame
        label: Colorpicker & Colortemperaturepicker
        widgets:
          - type: Colorpicker
            item: DemoColor
          - type: Colortemperaturepicker
            item: DemoColorTemp
            label: Test Colortemperaturepicker
          - type: Colortemperaturepicker
            item: DemoColorTemp
            min: 3000
            max: 5000
      - type: Frame
        label: Image & Video
        widgets:
          - type: Image
            item: DemoImage
            label: Test Image
            url: https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png
          - type: Image
            url: https://raw.githubusercontent.com/wiki/openhab/openhab/images/features.png
            refresh: 600000
          - type: Video
            label: Test Video
            url: https://demo.openhab.org/Hue.m4v
          - type: Video
            url: https://demo.openhab.org/Hue.m4v
            encoding: hls
      - type: Frame
        label: Buttongrid
        widgets:
          - type: Buttongrid
            item: DemoString
            widgets:
              - type: Button
                item: DemoString
                label: Go Home
                icon: material:home
                row: 2
                column: 2
                command: HOME
              - type: Button
                item: DemoSwitch
                label: "Off"
                icon: switch-off
                row: 1
                column: 1
                command: "ON"
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: '!='
                    argument: "ON"
              - type: Button
                item: DemoSwitch
                label: "On"
                icon: switch-on
                row: 1
                column: 1
                command: "OFF"
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
              - type: Button
                item: DemoString
                label: Start
                row: 1
                column: 2
                command: START
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
              - type: Button
                item: DemoString
                label: Stop
                row: 1
                column: 3
                command: STOP
                stateless: true
                visibility:
                  - item: DemoSwitch
                    operator: ==
                    argument: "ON"
      - type: Frame
        label: Magic Test Items
        widgets:
          - type: Colorpicker
            item: MagicColor
          - type: Switch
            item: MagicOnOff
          - type: Slider
            item: MagicDimmer
      - type: Frame
        label: Location
        widgets:
          - type: Mapview
            item: DemoLocation
            visibility:
              - item: DemoSwitch
                operator: ==
                argument: "ON"
          - type: Mapview
            item: DemoLocation
            label: Test Mapview
            height: 10
            visibility:
              - item: DemoSwitch
                operator: '!='
                argument: "ON"
      - type: Frame
        label: WEB
        widgets:
          - type: Webview
            url: https://www.openhab.org/
            visibility:
              - item: DemoSwitch
                operator: ==
                argument: "ON"
          - type: Webview
            label: Test Webview
            height: 15
            url: https://www.openhab.org/
            visibility:
              - item: DemoSwitch
                operator: '!='
                argument: "ON"
``

@spacemanspiff2007
Copy link
Copy Markdown
Contributor

Why do you need the condition level at all in this? Can’t you just put item, operator and argument directly under color if there are not multiple and statements?

Yes, but the idea is to have one condition mechanism or condition configuration which works the same throughout the complete structure. So every time the user writes/sees condition it's clear what substructure can and must follow.

Currently there are multiple places where there are conditions are defined and I think it would be really good if
there is a common key which indicates that the value that follows is a condition configuration and the configuration of a condition works everywhere the same.

visibility, where value is implicit set to true

visibility:
  - item: DemoSwitch
    operator: '!='
    argument: "ON"

icons

icon:
  definition:
    - value: material:home
      item: DemoSwitch
      operator: ==
      argument: "ON"
    - value: material:favorite

colors for label, value, icon, ...

valueColor:
  - value: blue
    and:
      - operator: <
        argument: "50"
      - item: DemoSwitch
        operator: ==
        argument: "ON"
  - value: red
    operator: <=
    argument: "75"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants