A more compact way to do "conditional" label/icon/color/whatever in MainUI page

Using different icons/colors based on item state

          config:
            icon: ={ON:'if:mdi:lightbulb-on', OFF:'if:mdi:lightbulb-off'}
              [@'LoungeRoom_Light2']
            iconColor: ={ON:'green', OFF:'red'}[@'LoungeRoom_Light2']
  • If you don’t have any spaces after : within the object i.e. ON:xx, yaml won’t complain about invalid syntax, without having to enclose the whole expression in quotes
  • @'itemname' is a shorthand for items.itemname.state. This is documented in Building Pages - Components & Widgets | openHAB
  • It isn’t that much different to using ternary operator, but when you have multiple possible states, this could be more easily readable.

Granular icon states

openHAB 4.2+:

          config:
            icon: |
              =[
              "if:tabler:battery",
              "if:tabler:battery-1",
              "if:tabler:battery-2",
              "if:tabler:battery-3",
              "if:tabler:battery-4"
              ][Math.min(~~(#"Back_Door_Battery" / 20), 4)]

Note | tells yaml that you are going to specify the values in multiple lines. You can also use >. The difference is | keeps the newlines, > converts the newlines into spaces. Either one would work.

openHAB 4.2 adds items['itemname'].numericState so you don’t have to do Number.parseFloat(items['itemname'].state) any more. Furthermore, a shorthand is added in mainUI for numericState: #'ItemName' (this PR is not yet merged, but hopefully soon!) EDIT: This has now been merged and should be in 4.2M1

in openHAB 4.1 you’d have to write this as:

          config:
            icon: |
              =[
              "if:tabler:battery",
              "if:tabler:battery-1",
              "if:tabler:battery-2",
              "if:tabler:battery-3",
              "if:tabler:battery-4"
              ][Math.min(~~(Number.parseFloat(items.Back_Door_Battery.state) / 20), 4)]

Here I’m trying to show battery level (0-100) using the following icons:

  • if:tabler:battery
  • if:tabler:battery-1
  • if:tabler:battery-2
  • if:tabler:battery-3
  • if:tabler:battery-4

We’ll put them in an array and use the array index to pick the icon based on the battery level

We need to map 0-100 into 0-4 using integer division

A trick to do “integer division without using Math.floor”: ~~(a / b). You could choose to use Math.floor if that’s easier to understand at a glance

Since there are 5 icons, we’ll divide by 20. This maps:
0 - 19 => 0
20 - 39 => 1
40 - 59 => 2
60 - 79 => 3
80 - 99 => 4
100 is a special case, since 100 / 5 = 5, we need to map this to 4 because our array only goes from 0-4. We do this using Math.min()

You could also write that more compactly like this:

          config:
            icon: ="if:tabler:battery" + ["", "-1", "-2", "-3", "-4"][Math.min(~~(#"Back_Door_Battery" / 20), 4)]
10 Likes

Will that expression work everywhere, ie. also in a floorplan marker setting?

Yes, anywhere you can enter a “javascript” expression that starts with a =. For ternary situation it isn’t very different I guess. You could at least convert items.Alarm.state to @'Alarm'.

1 Like

Great, that makes a lot of my expressions much easier to read.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.