How to write custom widgets? Looking for step by step tutorial

  • Platform information:
    • Hardware: x64/8GB/A LOT
    • OS: Win SRV 2019 - for now
    • Java Runtime Environment: Zulu11.50+19-CA
    • openHAB version: 3.1.0
  • Issue of the topic:
    Hello, I’m fresh openHab user and I would like to learn how to create custom widgets to be able to customise my default layout page with custom widgets for my GREE air conditioners, Xiaomi Airpurifiers etc.
    I was looking through openHab documentations, but sadly couldn’t find any step by step tutorial explaining different components, their properties and how to write customised widget from the begioning to the end.

Maybe some experienced users can point me in to the write direction? Thx

1 Like

Have you seen Pages - Custom Widgets | openHAB? Even if you are not new to OH you should use the Getting Started Tutorial as a first place to look.

Step 1: Choose the base widget type
Step 2: Configure the widget’s parameters
Step 3: Apply the widget to your Pages

A full reference for all the widgets and all it’s parameters is located at Component Reference | openHAB

There are lots of examples at

Thanks for response rlkoshak.

I’ve seen https://www.openhab.org/docs/tutorial/custom_widgets.html, but I think it’s to messy, trying to explain all things together. Another thing is that it uses examples from openHab tutorial which is difficult to follow without those “Smart things” they used.

I’ve been poking the https://www.openhab.org/docs/ui/components/ also, but having some problems to combine the knowledge from those two pages. That’s why I’m looking for step by step beginner tutorial for custom widgets.

Let’s try different approach. I’m trying to recreate the sitemap example from GREE bindings page using custom widget. I have two GREE air conditioners, so seems perfect scenario for using one custom widget for both of them.

Problems I have:

  • Where I should edit the widget: openHAB, VSCode, notepadd++? How to import/save it to openHab?
  • How to create the base frame?
  • How to achieve mappings?
sitemap GREEAmberSM label="Amber Sitemap" {
Frame label="Controls"
{
   Switch item="Unit Mode" label="Mode" mappings=["auto"="Auto", "cool"="Cool", "eco"="Eco", "dry"="Dry", "fan"="Fan", "turbo"="Turbo", "heat"="Heat", "on"="ON", "off"="OFF"]
   Setpoint item="Target Temperature" label="Set target temperature" icon=temperature minValue=16 maxValue=30 step=1
}
Frame label="Current Temperature"
{
   Text item="Current Temperature" label="Current temperature [%.1f °C]" icon="temperature"
}
Frame label="Fan Speed"
{
   Switch item="Wind Speed" label="Fan Speed" mappings=[0="Auto", 1="Low", 2="Medium Low", 3="Medium", 4="Medium High", 5="High"] icon=fan
}
Frame label="Fan-Swing Direction"
{
   Switch item="Vertical Swing Mode" label="Direction V" mappings=[0="Off", 1="Full", 2="Up", 3="Mid-up", 4="Mid", 5="Mid-low", 6="Down"] icon=flow
   Switch item="Horizontal Swing Mode" label="Direction H" mappings=[0="Off", 1="Full", 2="Left", 3="Mid-left", 4="Mid", 5="Mid-right", 6="Right"] icon=flow
}
Frame label="Options"
{
   Switch item="Turbo Mode" label="Turbo" icon=fan
   Switch item="Light" label="Light" icon=light
   Switch item="Air Mode" label="Air" icon=flow
   Switch item="Dry Mode" label="Dry" icon=rain
   Switch item="Health Mode" label="Health" icon=smiley
   Switch item="Power Save" label="Power Saving" icon=poweroutlet
}
}

You might check my intesis widget as an example

As with most things in OH, there will never be a ste-by-step tutorial because any such tutorial will be

that it uses examples from openHab tutorial which is difficult to follow without those “Smart things” they used.

The steps change depending on the Things and Items in use. Any such tutorial will look a whole lot like the Getting Started Tutorial.

As the Getting Started Tutorial page says:

Where to Create Custom Widgets

In MainUI under Developer Tools there is a “Widgets” option.

That’s where you create custom widgets. There is no mention of VSCode nor Notepad++ nor importing and exporting because OH doesn’t support any of those. You can create a custom widget in that one place. You can “import” a widget (for now) by copy and pasting the YAML code from an example into that Widget page.

It doesn’t use Frames. Widgets are 100% and completely separate from and works nothing like Sitemaps. If you have a complex widget in mind, you choose an appropriate container widget. For a stand alone widget F7-card might be a good choice. For a List widget an oh-listitem might be a good choice.

There is no such thing as Mappings in Page widgets. Again, Pages are completely different from Sitemaps. It’s entirely new concepts with very little to no overlap.

If you want a button, you can create an f7-card and put an oh-button on that card. You can use an expression to change the label of the button based on the state of an Item. Or you can use the Item metadata to define the mappings and use an oh-list widget to display and select from them.

Pages presents you with a big box of Legos. But to see some ways for how they can fit together your best bet is to look at examples like Hans-Jörg posted. Find something in an example that looks close to what you want and look at the code to see how it’s constructed.

Or stick with Sitemaps. There is nothing wrong with that either.

Thanks hmerk, thanks rlkoshak.

Let’s throw some more questions :slight_smile: if I may:

  1. Where I can find the proper syntax for YAML used in openHab?
  2. Component list uses oh-components, but hmerk used f7-components. What’s the difference? Should I start learning HTML5+CSS+JS etc…? :frowning:
  3. Can I nest components? What are slots and defaults for?
  4. How to customize components look, it seems like CSS? Any good examples or starting point?
  5. Where I can find or how to search for examples or ready to use widgets like the one linked by hmerk here [SOLVED] UI Widget: Intesis aircon controller; No commands send to items ?
  6. hmerk How you embedded different post? Links looks different.
  7. rlkoshak can You elaborate on those item-metadata or toss another link? Muuuuch appreciate :kiss:
  8. Maybe some example of three state button using expressions.

I’m almost on the other side Alice. More and more things starts to fit.

Simply search for „UI Widget:“

Just paste the full URL into message text gives a linke like I posted, but you can also mark a word and add a link via the edit buttons, which gives a link like @rlkoshak used …

In some cases, f7-components allow more configuration than oh-components. I would first try with oh-components. There is no real need to learn HTML5….

The Widget builder will give relatively meaningful errors when you get it wrong which is nice. TAML is pretty straight forward. It’s hierarchical. Indentation indicates the hierarchy.

When looking at the reference for a given widget it starts with the widget type (e.g. component: oh-button). Under that you’ll have a config which will be any of the config parameters indicated in the reference page for that component.

There are additional advanced options that one can set which come from some of the upstream frameworks like f7 or CSS. But that’s really advanced stuff I can’t help with.

No but if you will be doing very fine tuned customizations learning a bit about F7 could help. F7 is the JavaScript UI framework upon which MainUI is built. The oh-components are simplified f7 widgets that do not require as much knowledge of F7 to use properly. But they are also more limited if they don’t work exactly like you want it to.

Yes. defaults is where the properties for the container widget are defined. slots are where you will add widgets to that container. You can have widgets embedded in widgets as deep down as necessary.

Note I’m far from an expert on custom widgets so I might misstate something here.

CSS can be used for some things but others can be achieved through expressions and the standad properties on the widgets. It depends on what you want to customize.

In addition to just searching, The Getting Started Tutorial states

A growing number of very impressive custom widgets have been posted to Add-ons → UI on the forum (opens new window).

If you paste a link to a forum post inline with other text you’ll just get the title of the post. E.g. [SOLVED] UI Widget: Intesis aircon controller; No commands send to items.

NOTE: the conversion of the URL to title doesn’t always work as expected.

You can also embed the link like Hans-Jörg described. But I’m lazy and just paste in the URL and let the forum handle the rest.

If you post the link by itself on its own line it embeds the first few lines. E.g.

Pages - Item Widgets | openHAB talks a lot about Item metadata. The metadata that I mentioned above in particular is the State Description metadata. Navigate to the Item, click on “Add Metadata” and choose “State Description” from the list. Then populate the “Options” with your value=name pairs. Those pairs will be used as the command/label in the oh-list widget (and others I think).

Take note of the Default X Widget Item metadata. Here is where you would assign one of your custom widgets to be used by default for a given Item.

I don’t have buttons but an example three state expression to choose the color for an icon based on a battery Item’s state:

=(Number.parseInt(items[props.item].state) > 75) ? "green" : (Number.parseInt(items[props.item].state) > 25) ? "yellow" : "red"

More examples can be found at Example Custom List Widgets (which is one of the pages you’ll find when clicking on the link in the Getting Started Tutorial). I really did try to give all the resources I could in the tutorial, so much so that the developer for MainUI indicated there was too much.

2 Likes

Oh right. Made some progress thanks to Your help guys. I would like to share it with You.

uid: GREEAirCon
tags: []
props:
  parameters:
    - context: item
      description: Item for power channel
      label: Power
      name: itemPower
      required: true
      type: TEXT
    - context: item
      description: Item for power channel
      label: Light
      name: itemLight
      required: false
      type: TEXT
    - context: item
      description: Item for ambient temperature channel
      label: Ambient temperature
      name: itemAmbientTemp
      required: false
      type: TEXT
    - context: item
      description: Item for outdoor temperature channel
      label: Outdoor temperature
      name: itemOutdoorTemp
      required: false
      type: TEXT
    - context: item
      description: Item for target temperature channel
      label: Target temperature
      name: itemTargetTemp
      required: true
      type: TEXT
    - context: item
      description: Item for operation mode channel
      label: Operation mode
      name: itemMode
      required: true
      type: TEXT
    - context: item
      description: Item for fan speed channel
      label: Fan speed
      name: itemFanSpeed
      required: true
      type: TEXT
    - context: item
      description: Item for vanes up/down channel
      label: Vanes up/down
      name: itemVanesUD
      required: false
      type: TEXT
    - context: item
      description: Item for vanes left/right channel
      label: Vanes left/right
      name: itemVanesLR
      required: false
      type: TEXT
    - context: item
      description: Item for health channel
      label: Health
      name: itemHealth
      required: false
      type: TEXT
    - context: item
      description: Item for Turbo channel
      label: Turbo
      name: itemTurbo
      required: false
      type: TEXT
    - context: item
      description: Item for Quiet channel
      label: Quiet
      name: itemQuiet
      required: true
      type: TEXT
    - description: The Label at the top of the card
      label: Friendly name of your aircon eg. Lounge
      name: title
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Aug 26, 2021, 12:34:50 PM
component: f7-block
config:
  style:
    --f7-button-text-color: var(--f7-text-color)
    --f7-button-bg-color: var(--f7-card-bg-color)
    --f7-theme-color-rgb: var(--f7-color-blue-rgb)
  class:
    - no-padding
slots:
  default:
    - component: Label
      config:
        class:
          - margin
          - no-padding
        text: =props.title
        style:
          text-align: center
          height: auto
          font-size: 16px
          --f7-button-text-color: var(--f7-text-color)
          --f7-button-bg-color: var(--f7-card-bg-color)
          --f7-theme-color-rgb: var(--f7-color-blue-rgb)
    - component: f7-row
      config:
        class:
          - margin
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    action: toggle
                    actionItem: =(props.itemPower)
                    actionCommand: ON
                    actionCommandAlt: OFF
                    icon-f7: power
                    iconColor: '=(items[props.itemPower].state === "OFF") ? "red" : "green"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
          - component: f7-col
            config:
              visible: "=(props.itemLight === undefined) ? false : true"
              style:
                text-align: center
            slots:
              default:
                - component: oh-button
                  config:
                    action: toggle
                    actionItem: =(props.itemLight)
                    actionCommand: ON
                    actionCommandAlt: OFF
                    icon-f7: '=(items[props.itemLight].state === "ON") ? "lightbulb_fill" : "lightbulb"'
                    iconColor: '=(items[props.itemLight].state === "ON") ? "yellow" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
          - component: f7-col
            config:
              visible: "=(props.itemAmbientTemp === undefined) ? false : true"
              style:
                text-align: center
            slots:
              default:
                - component: f7-icon
                  config:
                    f7: house
                    color: green
                - component: Label
                  config:
                    text: =items[props.itemAmbientTemp].displayState
                    style:
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: elipsis
          - component: f7-col
            config:
              visible: "=(props.itemOutdoorTemp === undefined) ? false : true"
              style:
                text-align: center
            slots:
              default:
                - component: f7-icon
                  config:
                    f7: tree
                    color: green
                - component: Label
                  config:
                    text: =items[props.itemOutdoorTemp].displayState
                    style:
                      white-space: nowrap
                      overflow: hidden
                      text-overflow: elipsis
    - component: f7-row
      config:
        class:
          - justify-content-center
      slots:
        default:
          - component: oh-knob
            config:
              min: 18
              max: 30
              stepSize: 1
              size: 250
              item: =props.itemTargetTemp
    - component: f7-row
      config:
        class:
          - margin
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: command
                    actionItem: =(props.itemMode)
                    actionCommand: auto
                    icon-f7: arrow_2_circlepath
                    iconColor: '=(items[props.itemMode].state === "auto") ? "red" : "gray"'
                    text: AUTO
                    textColor: '=(items[props.itemMode].state === "auto") ? "red" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: command
                    actionItem: =(props.itemMode)
                    actionCommand: cool
                    icon-f7: thermometer_snowflake
                    iconColor: '=(items[props.itemMode].state === "cool") ? "blue" : "gray"'
                    text: COOL
                    textColor: '=(items[props.itemMode].state === "cool") ? "blue" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: command
                    actionItem: =(props.itemMode)
                    actionCommand: heat
                    icon-f7: thermometer_sun
                    iconColor: '=(items[props.itemMode].state === "heat") ? "orange" : "gray"'
                    text: HEAT
                    textColor: '=(items[props.itemMode].state === "heat") ? "orange" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: command
                    actionItem: =(props.itemMode)
                    actionCommand: eco
                    icon-f7: leaf_arrow_circlepath
                    iconColor: '=(items[props.itemMode].state === "eco") ? "green" : "gray"'
                    text: ECO
                    textColor: '=(items[props.itemMode].state === "eco") ? "green" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
    - component: f7-row
      config:
        class:
          - margin
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: command
                    actionItem: =(props.itemMode)
                    actionCommand: dry
                    icon-f7: drop
                    iconColor: '=(items[props.itemMode].state === "dry") ? "brown" : "gray"'
                    text: DRY
                    textColor: '=(items[props.itemMode].state === "dry") ? "brown" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: command
                    actionItem: =(props.itemMode)
                    actionCommand: fan
                    icon-f7: wind
                    iconColor: '=(items[props.itemMode].state === "fan") ? "white" : "gray"'
                    text: FAN
                    textColor: '=(items[props.itemMode].state === "fan") ? "white" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: toggle
                    actionItem: =(props.itemHealth)
                    actionCommand: ON
                    actionCommandAlt: OFF
                    icon-f7: tree
                    iconColor: '=(items[props.itemHealth].state === "ON") ? "green" : "gray"'
                    text: HEALTH MODE
                    textColor: '=(items[props.itemHealth].state === "ON") ? "green" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: toggle
                    actionItem: =(props.itemTurbo)
                    actionCommand: ON
                    actionCommandAlt: OFF
                    icon-f7: airplane
                    iconColor: '=(items[props.itemTurbo].state === "ON") ? "red" : "gray"'
                    text: TURBO
                    textColor: '=(items[props.itemTurbo].state === "ON") ? "red" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: options
                    actionItem: =(props.itemQuiet)
                    icon-f7: '=(items[props.itemQuiet].state === "auto") ? "moon_zzz" : (items[props.itemQuiet].state === "quiet") ? "moon_zzz_fill" : "moon_zzz"'
                    iconColor: '=(items[props.itemQuiet].state === "auto") ? "blue" : (items[props.itemQuiet].state === "quiet") ? "blue" : "gray"'
                    text: '=(items[props.itemQuiet].state === "auto") ? "AUTO" : (items[props.itemQuiet].state === "quiet") ? "QUIET" : "OFF"'
                    textColor: '=(items[props.itemQuiet].state === "auto") ? "blue" : (items[props.itemQuiet].state === "quiet") ? "blue" : "gray"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
    - component: f7-row
      config: {}
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    action: options
                    actionItem: =(props.itemFanSpeed)
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    icon-f7: chart_bar
                    iconColor: gray
                    text: '=(items[props.itemFanSpeed].state === "0") ? "AUTO" : (items[props.itemFanSpeed].state === "1") ? "LOW" : (items[props.itemFanSpeed].state === "2") ? "MIDLOW" : (items[props.itemFanSpeed].state === "3") ? "MID" : (items[props.itemFanSpeed].state === "4") ? "MIDHIGH" : (items[props.itemFanSpeed].state === "5") ? "HIGH" : "WHAT"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            config:
              visible: "=(props.itemVanesUD === undefined) ? false : true"
            slots:
              default:
                - component: oh-button
                  config:
                    action: options
                    actionItem: =(props.itemVanesUD)
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    icon-f7: arrow_up_down_circle
                    iconColor: gray
                    text: '=(items[props.itemVanesUD].state === "0") ? "OFF" : (items[props.itemVanesUD].state === "1") ? "FULL SWING" : (items[props.itemVanesUD].state === "2") ? "UP" : (items[props.itemVanesUD].state === "3") ? "MID UP" : (items[props.itemVanesUD].state === "4") ? "MID" : (items[props.itemVanesUD].state === "5") ? "MID DOWN" : (items[props.itemVanesUD].state === "6") ? "DOWN" : "WHAT"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      font-size: 10px
                      height: auto
          - component: f7-col
            config:
              visible: "=(props.itemVanesLR === undefined) ? false : true"
            slots:
              default:
                - component: oh-button
                  config:
                    action: options
                    actionItem: =(props.itemVanesLR)
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    icon-f7: arrow_left_right_circle
                    iconColor: gray
                    text: '=(items[props.itemVanesLR].state === "0") ? "OFF" : (items[props.itemVanesLR].state === "1") ? "FULL SWING" : (items[props.itemVanesLR].state === "2") ? "LEFT" : (items[props.itemVanesLR].state === "3") ? "LEFT MID" : (items[props.itemVanesLR].state === "4") ? "MID" : (items[props.itemVanesLR].state === "5") ? "MID RIGHT" : (items[props.itemVanesLR].state === "6") ? "RIGHT" : "WHAT"'
                    style:
                      --f7-button-bg-color: transparent
                      --f7-button-hover-bg-color: transparent
                      --f7-button-pressed-bg-color: transparent
                      height: auto
                      font-size: 10px

Few things I would like to change:

  1. Widget defines all the channels separately. I would like to change this so I choose only let’s say Thing and widgets would use some hard coded channel names. Any hint?
  2. On mobile phone widget tends to overlaps each other when I put two cells with them side by side. I would like to set minimal width of whole widget.

I’m having difficult to understand channel-link-item relation and the type definition on Item. For example I have two channels in my GREE aircon:

  • Wind speed (number)
  • Quiet mode (string)

I messed around when learning at the beginning so I have no clue are those default settings for them. But as You see in widget code first Item Wind speed stores state as number so I have to map numbers to state descriptions for setting text/icon/color properties of component.

 - component: oh-button
                  config:
                    action: options
                    actionItem: =(props.itemFanSpeed)
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    icon-f7: chart_bar
                    iconColor: gray
                    text: '=(items[props.itemFanSpeed].state === "0") ? "AUTO" : (items[props.itemFanSpeed].state === "1") ? "LOW" : (items[props.itemFanSpeed].state === "2") ? "MIDLOW" : (items[props.itemFanSpeed].state === "3") ? "MID" : (items[props.itemFanSpeed].state === "4") ? "MIDHIGH" : (items[props.itemFanSpeed].state === "5") ? "HIGH" : "WHAT"'

But on the other one Quiet mode store string so I have to map differently.

- component: oh-button
                  config:
                    class:
                      - margin
                      - display-flex
                      - flex-direction-column
                    action: options
                    actionItem: =(props.itemQuiet)
                    icon-f7: '=(items[props.itemQuiet].state === "auto") ? "moon_zzz" : (items[props.itemQuiet].state === "quiet") ? "moon_zzz_fill" : "moon_zzz"'
                    iconColor: '=(items[props.itemQuiet].state === "auto") ? "blue" : (items[props.itemQuiet].state === "quiet") ? "blue" : "gray"'
                    text: '=(items[props.itemQuiet].state === "auto") ? "AUTO" : (items[props.itemQuiet].state === "quiet") ? "QUIET" : "OFF"'
                    textColor: '=(items[props.itemQuiet].state === "auto") ? "blue" : (items[props.itemQuiet].state === "quiet") ? "blue" : "gray"'

On both Items I don’t see any metadata. And in Item channels area somehow I see channels with value definitions which I don’t know how they are already filled automatically.

I’ve missing some implicit conversion that’s going on under the hood. I wonder if I change data type on Item form string to number for example, how openHab manages to send proper command using that Item?

I’m also wondering how options action knows what options to show to user on those two channels/items and where it gets them from?

As always much appreciate any help and answers. Thanks in advance.

Btw. Sorry for any English mistakes, it’s my second language and I’m little rusty in using it.

It is really super important to use the proper terminology in OH. “Thing” has a really specific and technical meaning in openHAB. “Channel”, “Link” and “Item” too have very specific meanings. These terms are not generic nor are they interchangeable. To make the distinction between using the work “thing” generically or when specifically referring to openHAB Things I use the capital T for the latter. I try to avoid the former.

Why this is important is because widgets (and almost everything else in OH like Rules and Persistence) exclusively deal with Items, not Things and not Channels and not Links.

So you can never choose a Thing and the widget can never find the Channel names. Widgets can’t see Things and Channels, only Items.

But you have full control over how your Items are named. If you look at the example Chromecast widget in the Getting started tutorial you will see an “Item Prefix” is one of the Properties that can be set. Then each part of the widget constructs the name of the Item to refer to based on that prefix. For example, the Image Item is item: =props.prefix+"_Image".

When creating that Items using “create equipment from Thing” this sort of naming scheme will happen automatically with the prefix being the name of the Thing and the rest being the name of the Channel.

See Layout Pages | openHAB.

As discussed above, this is important to understand. The best place to start is Concepts | openHAB. The Concepts section of the docs is probably the most important to read and reread until you understand them. Not much will make sense in OH if you don’t understand the concepts.

But as a tl;dr:

  • Things represent a device. A device typically has one or more actuators or sensors. A special type of Thing represents a bridge to a given technology (e.g. Zwave controller, OpenWeatherMap Account, MQTT Broker etc.).
  • Each actuator and sensor on a given Thing is represented with a Channel. A Channel will have a type.
  • Channels can be linked to Items of the same type. So you can link a Switch Channel to a Switch Item but not a DateTime Item. (There is one exception to this that I’ll ignore for now.)
  • Items are the coin of the realm in OH. Widgets, Rules, Persistence, and everything else almost exclusively works with Items.

When you create Equipment from Thing, OH will choose the correct Item type for you.

Those are the types of Items those Channels can be linked to. Wind speed can be linked to a Number Item, Quiet Mode to a String Item.

Some bindings will apply some metadata to Items as hints for how to display that Channel. But most of the time all Item metadata is something you have to define yourself. Navigate to the Item under Settings and there is an “add metadata” option. The Metadata that handles things like mappings is State Description.