OH3 Color/White Bulb Widget

FYI @DrRSatzteil You can set your own keyframe animations now (see Add stylesheet configuration to widgets by hubsif · Pull Request #979 · openhab/openhab-webui · GitHub)

That offers a whole new world of possibilities for the creation of custom widgets. :slight_smile:

1 Like

That’s really cool, thanks for pointing that out! I’m already looking forward for the first cool examples and probably something comes to my mind as well :slight_smile:

By the way I stumbled upon the same problem a couple of days ago: the espmilight binding also uses a 0 - 100 range for the temperature. I still wanted the Kelvin value to be displayed and it can actually be done conpletely in the widget code: https://community.openhab.org/t/light-widget-with-temperature-control

You may of course stick with your version, I don’t see any disadvantages besides the additional item.

Thanks for sharing! I like having it all in the widget better, I just didn’t have the time to try and sort it out so I went with what I knew

I really like this widget.
Everything works fine, but when i press the color select button and the color wheel is displayed. It closes the color wheel card before I am able to chose a color…
Any suggestions or clues?

I’m not sure exactly what you mean. Would it be possible to post a gif file here?

Do you happen to use the miio binding? If so please try to set the profile of the color mode channel to “follow” and try if that works for you.

Brilliant!
I now realize my description was really poor.
But you solved it for me anyways. It was indeed MIIO binding. Changed to “follow”. Now it works. Many thanks

Great, so it was a good guess by me :wink:

I happen to control a light via the miio binding with this widget as well. The binding always sets the color mode back to white light after a second or so. I don’t know if this is a bug or not but it was easy enough to solve it via the profile so I did not bother to investigate any further.

Here is my Hue modification

uid: color_hue_light_v3
tags: []
props:
  parameters:
    - description: Header text
      label: Header
      name: header
      required: false
      type: TEXT
    - context: item
      description: Choose Lamp to control
      label: Lamp
      name: lamp
      required: true
      type: TEXT
    - description: Choose if your Bulb has Color
      label: Color
      name: color
      required: false
      type: BOOLEAN
    - context: item
      description: Choose the Temperature Item if your Bulb has Temperature
      label: Temperature
      name: temperature
      required: false
      type: TEXT
    - context: item
      description: Timer
      label: Shutdown Timer Item
      name: shutdowntimer
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Apr 13, 2021, 12:00:22 AM
component: f7-card
slots:
  default:
    - component: f7-card-content
      config:
        class:
          - display-flex
          - flex-direction-column
          - justify-content-flex-start
          - align-items-center
        style:
          height: 175px
          --f7-color-picker-slider-size: 18px
          --f7-color-picker-slider-knob-size: 22px
      slots:
        default:
          - component: f7-row
            config:
              style:
                position: absolute
            slots:
              default:
                - component: f7-block-header
                  slots:
                    default:
                      - component: Label
                        config:
                          text: =props.header
          - component: f7-block
            config:
              class:
                - no-padding
              style:
                width: 100%
                height: 100%
                margin-top: 2px
            slots:
              default:
                - component: f7-block
                  config:
                    visible: "=vars.color != true ? true : false"
                    class:
                      - display-flex
                      - flex-direction-column
                      - justify-content-flex-end
                    style:
                      animation: f7-circle-circle-in 300ms
                      height: 60%
                      margin-top: 10px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          visible: "=(props.temperature) ? true : false"
                          class:
                            - display-flex
                            - justify-content-space-between
                            - align-items-center
                          style:
                            width: calc(100% + 20px)
                            margin-left: -10px
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: thermometer
                                size: 20
                                style:
                                  margin-left: 20px
                                  color: var(--f7-block-header-text-color)
                            - component: Label
                              config:
                                text: '=items[props.temperature].state == "NULL" ? "-" : items[props.temperature].state + " %"'
                                style:
                                  margin-right: 20px
                                  color: var(--f7-block-header-text-color)
                      - component: f7-row
                        config:
                          visible: "=(props.temperature) ? true : false"
                          class:
                            - display-flex
                            - justify-content-center
                            - align-items-center
                          style:
                            width: 100%
                        slots:
                          default:
                            - component: oh-slider
                              config:
                                color: white
                                label: true
                                min: 0
                                max: 100
                                item: =props.temperature
                                style:
                                  margin-top: 7px
                                  --f7-range-bar-size: 18px
                                  --f7-range-bar-border-radius: 10px
                                  --f7-range-knob-size: 20px
                                  --f7-range-bar-active-bg-color: transparent
                                  --f7-range-bar-bg-color: linear-gradient(to right, rgba(215, 226, 255), rgba(255, 255, 255),rgba(255, 147, 44, 0.5),rgba(255, 147, 44, 0))
                                  --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                                  --f7-range-label-text-color: black
                                  width: 100%
                                  z-index: 99 !important
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-space-between
                            - align-items-center
                          style:
                            width: calc(100% + 20px)
                            margin-left: -10px
                            margin-top: 20px
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: sun_min
                                size: 20
                                style:
                                  margin-left: 20px
                                  color: var(--f7-block-header-text-color)
                            - component: Label
                              config:
                                text: =items[props.lamp].state.split(",")[2] + " %"
                                style:
                                  margin-right: 20px
                                  color: var(--f7-block-header-text-color)
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-items-center
                          style:
                            width: 100%
                            margin-top: 5px
                        slots:
                          default:
                            - component: oh-slider
                              config:
                                color: white
                                label: true
                                item: =props.lamp
                                style:
                                  --f7-range-bar-size: 18px
                                  --f7-range-bar-border-radius: 10px
                                  --f7-range-knob-size: 20px
                                  --f7-range-bar-active-bg-color: rgba(246,246,0,0.5)
                                  --f7-range-bar-bg-color: linear-gradient(to right, rgba(169,169,169,0.8), rgba(246,158,81,0))
                                  --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                                  --f7-range-label-text-color: black
                                  width: 100%
                                  z-index: 99 !important
                - component: f7-block
                  config:
                    visible: "=vars.color != true ? false : true"
                    class:
                      - no-margin
                    style:
                      animation: f7-circle-circle-in 300ms
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                        slots:
                          default:
                            - component: f7-block
                              config:
                                style:
                                  width: 100%
                              slots:
                                default:
                                  - component: oh-colorpicker
                                    config:
                                      style:
                                        margin-top: 7px
                                        --f7-range-bar-size: 18px
                                        --f7-range-bar-border-radius: 10px
                                        --f7-range-knob-size: 20px
                                        --f7-range-bar-active-bg-color: transparent
                                        --f7-range-bar-bg-color: linear-gradient(to right, rgba(246,158,81,0.8), rgba(246,158,81,0))
                                        --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                                        --f7-range-label-text-color: black
                                        width: 100%
                                        z-index: 99 !important
                                      item: =props.lamp
                                      modules:
                                        - hsb-sliders
          - component: f7-block
            config:
              class:
                - display-flex
                - justify-content-center
                - align-items-center
                - no-padding
                - no-margin
              style:
                position: absolute
                width: 40px
                height: 40px
                left: 30px
                bottom: 20px
                border-top: none
                background: var(--f7-searchbar-search-icon-color)
                box-shadow: var(--f7-actions-bg-color) 0px 0px 16px inset
                border-radius: 50%
            slots:
              default:
                - component: f7-block
                  config:
                    class:
                      - no-margin
                    style:
                      animation: '=items[props.shutdowntimer].state.split(" ")[0] > 0 ? "skeleton-effect-fade 0.2s linear infinite" : "none"'
                      position: absolute
                      width: 100%
                      height: 100%
                      box-shadow: '=items[props.lamp].state.split(",")[2] > 0 ? "0 0 7px #000, 0px 0px 7px rgba(0,255,0,0.5)" : "none"'
                      border-radius: 50%
                      transition: transform 0.2s
                      background: '=items[props.lamp].state.split(",")[2] > 0 ? "rgba(0, 255, 0, 0.9)" : "transparent"'
                      transform: '=items[props.lamp].state.split(",")[2] > 0 ? "scale(1)" : "scale(0,0)"'
                - component: f7-block
                  config:
                    style:
                      position: absolute
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      border-radius: 50%
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: power
                    iconSize: 13
                    action: toggle
                    actionItem: =props.lamp
                    actionCommand: '=items[props.lamp].state.split(",")[2] > "0" ? "0" : "100"'
                    style:
                      border-radius: 50%
                      background-color: var(--f7-actions-bg-color)
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      backdrop-filter: opacity(88%)
                      z-index: 99 !important
                      box-shadow: 0px 0px 7px 2px var(--f7-actions-bg-color)
          - component: oh-link
            config:
              text: Timer
              visible: "=props.shutdowntimer ? true : false"
              action: popover
              popoverOpen: .timerpopover
              style:
                position: absolute
                bottom: 10px
            slots:
              default:
                - component: f7-popover
                  config:
                    class:
                      - timerpopover
                  slots:
                    default:
                      - component: oh-stepper-card
                        config:
                          item: =props.shutdowntimer
                          title: Ausschalten in Minuten
          - component: f7-block
            config:
              visible: "=(props.color) == true ? true : false"
              class:
                - display-flex
                - justify-content-center
                - align-items-center
                - no-padding
                - no-margin
              style:
                position: absolute
                bottom: 20px
                right: 30px
                width: 40px
                height: 40px
                border-top: none
                background: var(--f7-searchbar-search-icon-color)
                box-shadow: var(--f7-actions-bg-color) 0px 0px 16px inset
                border-radius: 50%
            slots:
              default:
                - component: f7-block
                  config:
                    class:
                      - no-margin
                    style:
                      position: absolute
                      width: 100%
                      height: 100%
                      box-shadow: '=vars.color == true ? "rgb(0 0 0) 0px 0px 4px, rgb(255 0 0 / 50%) -1px -1px 4px, rgb(255 255 0 / 50%) 1px -1px 4px, rgb(0 255 0 / 50%) 1px 1px 4px, rgb(0 0 255 / 50%) -1px 1px 4px" : "none"'
                      border-radius: 50%
                      transition: transform 0.5s
                      background: '=vars.color == true ? "linear-gradient(135deg, red, red, orange, yellow, green, blue, blue)" : "transparent"'
                      transform: '=vars.color == true ? "rotate(360deg) scale(1,1)" : "rotate(0deg) scale(0,0)"'
                - component: f7-block
                  config:
                    style:
                      position: absolute
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      background: var(--f7-actions-bg-color)
                      border-radius: 50%
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: paintbrush
                    iconSize: 17
                    action: variable
                    actionVariable: color
                    actionVariableValue: true
                    style:
                      display: '=(vars.color == false || vars.color != true) ? "block" : "none"'
                      border: solid 2pt var(--f7-actions-bg-color)
                      border-radius: 50%
                      background-color: var(--f7-actions-bg-color)
                      background-image: "linear-gradient(135deg, #f7f7f7: none, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      box-shadow: 0px 0px 7px 2px var(--f7-actions-bg-color)
                      backdrop-filter: opacity(88%)
                    class:
                      - nextSlide
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: paintbrush_fill
                    iconSize: 17
                    action: variable
                    actionVariable: color
                    actionVariableValue: false
                    style:
                      display: '=(vars.color) ? "block" : "none"'
                      border: solid 2pt var(--f7-actions-bg-color)
                      border-radius: 50%
                      background-color: var(--f7-actions-bg-color)
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      backdrop-filter: opacity(88%)
                    class:
                      - previousSlide
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: '=items[props.lamp].state.split(",")[2] > 0 ? "Licht an" : "Licht aus"'

I also made some other modifications. Should work with all Hue Lights (Color and non-color) and Groups

3 Likes

Awesome, your widget! As a beginner working with widgets and Jython rules, I try to understand how this stuff works. I have two issues to integrate the color light widget with my RGBW color lamp which basically works as an RGB lamp plus a separate tunable white lamp.

Issue #1: I do not have an item to select between color mode and white mode. I understand that I need to create a kind of virtual item without a counterpart outside OpenHAB. Upon toggling the color mode item between color and white, the respective other color channels should be turned off to avoid a parallel activation: If color mode = color then white switch = off. If color mode = white then RGB switch = off. However, I get lost whether I can implement this functionality inside the widget (and where to start) or whether I need to write a rule what I have never done before, at least not in Jython so that the rule does not depend on a particular item for exactly one lamp.

Issue #2: I do not have separate switch item, as I added the switch functionality to the respective color / dimmer type as specified in the things file:

Type color : RGBW "DG Dachraum Farbe" [ hsb="232.600:4/5/85+<4/5/100", switch="1.001:4/5/84+<4/5/99", position="5.001:4/5/89+<4/5/104", increaseDecrease="3.007:4/5/92" ]
Type dimmer : TWdim "DG Dachraum Weiß Helligkeit" [ switch="1.001:4/5/84+<4/5/99", position="5.001:4/5/95+<4/5/107", increaseDecrease="3.007:4/5/98" ]
Type number : TWcol "DG Dachraum Weiß Farbtemperatur" [ ga="7.600:4/5/94+<4/5/106" ]

Is there a way to switch on/off the color light in the widget on the basis of non-explicitly available switch items?

Best regards,
Peter

Hi Peter,

let me share my first thoughts on this:

Regarding issue #1: I think you are on the right track here. You are assuming correctly that you would need a rule to simultaneously switch color on/off while switching white off/on. I never used Jython rules so I can’t really help you with these. However I would recommend to simply create a rule from the UI. Since this is pretty basic stuff there is no real need to write a single line of code.

Regarding issue #2: I think I would go for the same solution as with issue #1 (slightly more complex): Create a virtual on/off switch and use a rule to switch off both channels when the switch is turned off. When it is turned on you would need to check what state your color mode switch from issue #1 has and only switch on the corresponding channel (color or dimmer).

Hi Thomas,

Thank you very much for pointing me to the rules to be created from the UI. In order to do so, I created a model first, assigned equipment (things) and points (items). However, I did not find a way to separate business logic from particular items by doing this way. The reason is that I have a number of lamps and would liketo avoid copy-paste the code with different items.

According to what I saw in the rules UI is that I may select a particular item and apply a script. It would be great if somebody could give me a hint as how to abstract the script so that I can re-use it for a number of different items, but following the same business logic.

Best regards,
Peter

Hi Thomas

I also really like your widget. I have made some minor changes to make it compatible with my Hue Hub (%Temperature for lights).

Can you clarify how the “Timer” works? I have created an Item for the shutdowntimer and when it is >0 I see the Power Icon “pulse”. However not clear how and where the countdown happens as I cannot see it in the widget. Does this has to be set externally somehow?

BTW I also see a delay on the Temperature slider when you power on the lights. The label can stay on UNDEF for quiet some time before changing to the correct %. Assuming this is a delay from the Hue Hub?

Thanks again
Mark

Hi Peter,

so far this has not been a big issue with regard to my own home setup. However this is of course a problem that many had before and Rich wrote a very comprehensive article about this topic here: Design Pattern: Working with Groups in Rules

It’s a bit lengthy but worth the read if you want to avoid duplication even though you might need to recreate some items to be able to use the techniques described there.

Regards,
Thomas

1 Like

Oh yes the timer is probably something that would not work out of the box for a lot of users. I control a milight bulb with this widget that has a shutdown timer built into the device that can be controlled via a channel.

For devices that do not support this out of the box you would need to create your own timer Item and add a rule that gets triggered whenever the Item receives a command. The simplest approach would be in my opinion to create a rule that cancels any running timers, switches the light off when the Item received a 0 (0 minutes) or sets up a one minute timer when the Item is > 0 and sends a command to the same item with the Item value decreased by one. This will in turn trigger the rule again and starts a timer for the next minute and so on until you reached 0 and the rule will turn off the light.

Regarding the delays: The delay from the Hue Hub should really only matter if you set “autoupdate” to “false” in your Item config (this is the reason in my setup). If autoupdate is enabled I would guess that it is more likely a network delay between your device and the OpenHab Rest API.

1 Like

I created a TripleToggle Python script which automatically creates and manages timers when needed. The timers are kept in an array, the key is the item name. This rule could serve as inspiration (see e.g. where the timers array is initialised, how it is automatically created and how the timers are reset when needed):

Thanks for contributing to comminity!
Can you please help me to adopt my version for Yeelight color lamps? Code is:

uid: yeelight_color_light_v3
tags: []
props:
  parameters:
    - description: Header text
      label: Header
      name: header
      required: false
      type: TEXT
    - description: Background image, located in static/ folder
      label: Background image
      name: bg_image_url
      required: false
      type: TEXT
    - context: item
      description: Toggle ON/OFF
      label: Toggle
      name: lampToggle
      required: true
      type: TEXT
    - context: item
      description: Brightness
      label: Brightness
      name: brightness
      required: true
      type: TEXT
    - context: item
      description: Temperature in K
      label: Temperature
      name: temperature
      required: true
      type: TEXT
    - context: item
      description: Color mode (1 = RGB, 2 = Temperature, 4 = Color flow)
      label: Color Mode Item
      name: colorMode
      required: true
      type: TEXT
    - context: item
      description: Color
      label: Color Item
      name: color
      required: true
      type: TEXT
    - context: item
      description: Timer
      label: Shutdown Timer Item
      name: shutdowntimer
      required: false
      type: TEXT
    - context: item
      label: Item_flow
      name: item_flow
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Jul 13, 2021, 2:47:31 AM
component: f7-card
config:
  style:
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
    background-image: "=props.bg_image_url ? 'url(/static/' + props.bg_image_url + ')' : ''"
    background-repeat: no-repeat;
    background-size: cover
    background-brightness: 60%
    margin-left: 5px
    margin-right: 5px
    font-size: 15px
slots:
  default:
    - component: f7-card-content
      config:
        class:
          - display-flex
          - flex-direction-column
          - justify-content-flex-start
          - align-items-center
        style:
          height: 175px
      slots:
        default:
          - component: f7-row
            config:
              style:
                position: absolute
            slots:
              default:
                - component: f7-block-header
                  slots:
                    default:
                      - component: Label
                        config:
                          text: =props.header
          - component: f7-block
            config:
              class:
                - no-padding
              style:
                width: 110%
                height: 100%
                margin-top: 20px
            slots:
              default:
                - component: f7-block
                  config:
                    visible: '=items[props.colorMode].state == "2" ? true : false'
                    class:
                      - display-flex
                      - flex-direction-column
                      - justify-content-flex-end
                    style:
                      animation: f7-fade-in 300ms
                      height: 60%
                      margin-top: 10px
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-space-between
                            - align-items-center
                          style:
                            width: calc(100% - 20px)
                            margin-left: 15px
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: thermometer
                                size: 20
                                style:
                                  color: var(--f7-block-header-text-color)
                            - component: Label
                              config:
                                text: =items[props.temperature].state + "K"
                                style:
                                  color: var(--f7-block-header-text-color)
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-items-center
                          style:
                            width: 95%
                            margin-left: 10px
                        slots:
                          default:
                            - component: oh-slider
                              config:
                                color: white
                                label: true
                                min: 1700
                                max: 6500
                                item: =props.temperature
                                style:
                                  --f7-range-bar-size: 18px
                                  --f7-range-bar-border-radius: 10px
                                  --f7-range-knob-size: 20px
                                  --f7-range-bar-active-bg-color: transparent
                                  --f7-range-bar-bg-color: linear-gradient(to right, rgba(255,121,0,1.8), rgba(50,249,255,1))
                                  --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                                  --f7-range-label-text-color: black
                                  width: 100%
                                  z-index: 99 !important
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-space-between
                            - align-items-center
                          style:
                            width: calc(100% - 20px)
                            margin-left: 15px
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: sun_min
                                size: 20
                                style:
                                  color: var(--f7-block-header-text-color)
                            - component: Label
                              config:
                                text: =items[props.brightness].state + "%"
                                style:
                                  color: var(--f7-block-header-text-color)
                      - component: f7-row
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-items-center
                          style:
                            margin-left: 10px
                            width: 95%
                        slots:
                          default:
                            - component: oh-slider
                              config:
                                color: white
                                label: true
                                item: =props.brightness
                                style:
                                  --f7-range-bar-size: 18px
                                  --f7-range-bar-border-radius: 10px
                                  --f7-range-knob-size: 20px
                                  --f7-range-bar-active-bg-color: rgba(100,100,0,0.5)
                                  --f7-range-bar-bg-color: linear-gradient(to right, rgba(100,100,0,0.1), rgba(255,255,0,1))
                                  --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                                  --f7-range-label-text-color: black
                                  width: 100%
                                  z-index: 99 !important
                - component: f7-block
                  config:
                    visible: '=items[props.colorMode].state == "1" ? true : false'
                    class:
                      - display-flex
                      - justify-content-center
                      - align-items-center
                    style:
                      width: 107%
                      margin-left: -20px
                      animation: f7-fade-in 500ms
                  slots:
                    default:
                      - component: f7-row
                        config:
                          style:
                            width: 100%
                          class:
                            - display-flex
                            - justify-content-center
                        slots:
                          default:
                            - component: f7-block
                              config:
                                style:
                                  width: 100%
                                  heigth: 120%
                              slots:
                                default:
                                  - component: oh-colorpicker
                                    config:
                                      item: =props.color
                                      modules:
                                        - hsb-sliders
          - component: f7-block
            config:
              class:
                - display-flex
                - justify-content-center
                - align-items-center
                - no-padding
                - no-margin
              style:
                position: absolute
                width: 40px
                height: 40px
                left: 10px
                bottom: 10px
                border-top: '=items[props.lampToggle].state == "ON" ? "none" : "2px solid #ddd"'
                box-shadow: "inset 0px 1px 2px #eee"
                background: white
                border-radius: 50%
            slots:
              default:
                - component: f7-block
                  config:
                    class:
                      - no-margin
                    style:
                      animation: '=items[props.shutdowntimer].state.split(" ")[0] > 0 ? "skeleton-effect-fade 2s linear infinite" : "none"'
                      position: absolute
                      width: 100%
                      height: 100%
                      box-shadow: '=items[props.lampToggle].state == "ON" ? "0 0 20px #fff, 0px 0px 30px rgba(0,255,0,0.5)" : "none"'
                      border-radius: 50%
                      transition: transform 0.2s
                      background: '=items[props.lampToggle].state == "ON" ? "rgba(124, 252, 0, 0.5)" : "transparent"'
                      transform: '=items[props.lampToggle].state =="ON" ? "scale(1,1)" : "scale(0,0)"'
                - component: f7-block
                  config:
                    style:
                      position: absolute
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      background: rgba(255,255,255,0.8)
                      border-radius: 50%
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: power
                    iconSize: 17
                    action: toggle
                    actionItem: =props.lampToggle
                    actionCommand: '=items[props.lampToggle].state == "ON" ? "OFF" : "ON"'
                    style:
                      border: solid 2pt white
                      border-radius: 50%
                      background-color: "#f7f7f7"
                      background-image: "linear-gradient(135deg, #f7f7f7, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      box-shadow: 0px 3px 8px
                      backdrop-filter: opacity(88%)
                      z-index: 99 !important
          - component: oh-link
            config:
              text: =items[props.shutdowntimer].state
              visible: "=props.shutdowntimer ? true : false"
              action: popover
              popoverOpen: .timerpopover
              style:
                position: absolute
                bottom: 10px
            slots:
              default:
                - component: f7-popover
                  config:
                    class:
                      - timerpopover
                  slots:
                    default:
                      - component: oh-stepper-card
                        config:
                          item: =props.shutdowntimer
                          title: Таймер в минутах
          - component: f7-block
            config:
              class:
                - display-flex
                - justify-content-center
                - align-items-center
                - no-padding
                - no-margin
              style:
                position: absolute
                bottom: 10px
                right: 10px
                width: 40px
                height: 40px
                border-top: '=items[props.colorMode].state == 1 ? "none" : "2px solid #ddd"'
                box-shadow: "inset 0px 1px 2px #eee"
                background: white
                border-radius: 50%
            slots:
              default:
                - component: f7-block
                  config:
                    class:
                      - no-margin
                    style:
                      position: absolute
                      width: 100%
                      height: 100%
                      box-shadow: '=items[props.colorMode].state == 1 ? "0 0 15px #fff, -7px -7px 15px rgba(255,0,0,0.5), 7px -7px 15px rgba(255,255,0,0.5), 7px 7px 15px rgba(0,255,0,0.5), -7px 7px 15px rgba(255,255,0,0.5)" : "none"'
                      border-radius: 50%
                      transition: transform 0.2s
                      background: '=items[props.colorMode].state == 1 ? "linear-gradient(135deg, red, orange, yellow, green, blue)" : "transparent"'
                      transform: '=items[props.colorMode].state == 1 ? "rotate(360deg) scale(1,1)" : "rotate(0deg) scale(0,0)"'
                - component: f7-block
                  config:
                    style:
                      position: absolute
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      background: rgba(255,255,255,0.8)
                      border-radius: 50%
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: paintbrush
                    iconSize: 17
                    action: command
                    actionItem: =props.colorMode
                    actionCommand: 1
                    style:
                      display: '=items[props.colorMode].state == 2 ? "block" : "none"'
                      border: solid 2pt white
                      border-radius: 50%
                      background-color: "#f7f7f7"
                      background-image: "linear-gradient(135deg, #f7f7f7, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      box-shadow: 0px 3px 8px
                      backdrop-filter: opacity(88%)
                    class:
                      - nextSlide
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: paintbrush_fill
                    iconSize: 17
                    action: command
                    actionItem: =props.colorMode
                    actionCommand: 2
                    style:
                      display: '=items[props.colorMode].state == 1 ? "block" : "none"'
                      border: solid 2pt white
                      border-radius: 50%
                      background-color: "#f7f7f7"
                      background-image: "linear-gradient(135deg, #f7f7f7, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      box-shadow: 0px 3px 8px
                      backdrop-filter: opacity(88%)
                    class:
                      - previousSlide
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: '=items[props.lampToggle].state == "ON" ? "Включено" : "Выключено"'

Issues: changed colorwheel to hsb-sliders, which are better to control Yeelight, and can’t understand how to place them in a small cell on mobile phone - they become too small and hard to control.
Is there any way to design widgets other than Openhab`s web ui?

Hi @11194

As far as I know there is no out-of-the-box way to resize the color controls to your needs, I remember that I had a hard time trying to fit the wheel in there (had to absolutely position the buttons on top of the wheel due to space restrictions) and I think the sliders use a lot more space (at least if you want to have a reasonable size to be able to control them). I figured that for this use case (small screen, touch handling) the wheel works pretty well. So, sorry I don’t think there can be an easy solution unless you increase the size of the widget.

I always used the openHAB UI to develop the widgets. I don’t know of any other way to do this unless you can live without the preview panel.

1 Like

Deleted absolute positions and condensed as much as i could.

uid: color_light_v2
tags: []
props:
  parameters:
    - description: Header text
      label: Header
      name: header
      required: false
      type: TEXT
    - description: Background image, located in static/ folder
      label: Background image
      name: bg_image_url
      required: false
      type: TEXT
    - context: item
      description: Toggle ON/OFF
      label: Toggle
      name: lampToggle
      required: true
      type: TEXT
    - context: item
      description: Brightness
      label: Brightness
      name: brightness
      required: true
      type: TEXT
    - context: item
      description: Temperature in K
      label: Temperature
      name: temperature
      required: true
      type: TEXT
    - context: item
      description: Color mode (1 = RGB, 2 = Temperature, 4 = Color flow)
      label: Color Mode Item
      name: colorMode
      required: true
      type: TEXT
    - context: item
      description: Color
      label: Color Item
      name: color
      required: true
      type: TEXT
    - context: item
      description: Timer
      label: Shutdown Timer Item
      name: shutdowntimer
      required: false
      type: TEXT
    - context: item
      label: Item_flow
      name: item_flow
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Aug 1, 2021, 3:06:38 PM
component: f7-card
config:
  style:
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
    background-image: "=props.bg_image_url ? 'url(/static/' + props.bg_image_url + ')' : ''"
    background-repeat: no-repeat;
    background-size: cover
    background-brightness: 60%
    margin: 5px
    textColor: white
    height: 150px
    padding: 0
    font-size: medium
    line-height: 1
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
slots:
  default:
    - component: f7-card-content
      config:
        style:
          margin: 0px
          margin-top: -10px
          width: 100%
      slots:
        default:
          - component: f7-block
            config:
              visible: "=props.header ? true : false"
              style:
                margin-top: -3px
                margin-left: 0px
                margin-bottom: 5px
                width: 100%
              class:
                - display-flex
                - flex-direction-column
                - align-items-center
            slots:
              default:
                - component: Label
                  config:
                    text: =props.header
                    style:
                      white-space: nowrap
          - component: f7-block
            config:
              visible: '=items[props.colorMode].state == "2" ? true : false'
              style:
                animation: f7-fade-in 300ms
                margin-top: 0px
                margin-left: 0px
                width: 100%
            slots:
              default:
                - component: f7-row
                  config:
                    class:
                      - justify-content-space-between
                    style:
                      width: 100%
                      color: var(--f7-block-text-color)
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: thermometer
                          size: 20
                      - component: Label
                        config:
                          text: =items[props.temperature].state + "K"
                - component: f7-row
                  slots:
                    default:
                      - component: oh-slider
                        config:
                          color: white
                          label: true
                          min: 1700
                          max: 6500
                          item: =props.temperature
                          style:
                            --f7-range-bar-size: 13px
                            --f7-range-bar-border-radius: 10px
                            --f7-range-knob-size: 15px
                            --f7-range-bar-active-bg-color: transparent
                            --f7-range-bar-bg-color: linear-gradient(to right, rgba(255,121,0,1.8), rgba(50,249,255,1))
                            --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                            --f7-range-label-text-color: black
                            width: 100%
                            z-index: 99 !important
                - component: f7-row
                  config:
                    class:
                      - justify-content-space-between
                      - align-items-center
                    style:
                      width: 100%
                      color: var(--f7-block-text-color)
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: sun_min
                          size: 20
                      - component: Label
                        config:
                          text: =items[props.brightness].state + "%"
                - component: f7-row
                  slots:
                    default:
                      - component: oh-slider
                        config:
                          color: white
                          label: true
                          item: =props.brightness
                          style:
                            --f7-range-bar-size: 13px
                            --f7-range-bar-border-radius: 10px
                            --f7-range-knob-size: 15px
                            --f7-range-bar-active-bg-color: rgba(100,100,0,0.5)
                            --f7-range-bar-bg-color: linear-gradient(to right, rgba(100,100,0,0.1), rgba(255,255,0,1))
                            --f7-range-knob-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3)
                            --f7-range-label-text-color: black
                            width: 100%
                            z-index: 99 !important
          - component: f7-block
            config:
              visible: '=items[props.colorMode].state == "1" ? true : false'
              style:
                margin-top: 0px
                animation: f7-fade-in 500ms
            slots:
              default:
                - component: oh-colorpicker
                  config:
                    item: =props.color
                    modules:
                      - hsb-sliders
    - component: f7-card-footer
      config:
        class:
          - display-flex
          - justify-content-space-between
        style:
          width: 99%
          padding: 7px
      slots:
        default:
          - component: f7-block
            config:
              class:
                - display-flex
                - justify-content-center
                - align-items-center
                - no-padding
                - no-margin
              style:
                width: 40px
                height: 40px
                border-top: '=items[props.lampToggle].state == "ON" ? "none" : "2px solid #ddd"'
                box-shadow: "inset 0px 1px 2px #eee"
                background: white
                border-radius: 50%
            slots:
              default:
                - component: f7-block
                  config:
                    class:
                      - no-margin
                    style:
                      animation: '=items[props.shutdowntimer].state.split(" ")[0] > 0 ? "skeleton-effect-fade 2s linear infinite" : "none"'
                      position: absolute
                      width: 100%
                      height: 100%
                      box-shadow: '=items[props.lampToggle].state == "ON" ? "0 0 20px #fff, 0px 0px 30px rgba(0,255,0,0.5)" : "none"'
                      border-radius: 50%
                      transition: transform 0.2s
                      background: '=items[props.lampToggle].state == "ON" ? "rgba(124, 252, 0, 0.5)" : "transparent"'
                      transform: '=items[props.lampToggle].state =="ON" ? "scale(1,1)" : "scale(0,0)"'
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: power
                    iconSize: 17
                    action: toggle
                    actionItem: =props.lampToggle
                    actionCommand: '=items[props.lampToggle].state == "ON" ? "OFF" : "ON"'
                    style:
                      border: solid 2pt white
                      border-radius: 50%
                      background-color: "#f7f7f7"
                      background-image: "linear-gradient(135deg, #f7f7f7, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      text-align: center
                      box-shadow: 0px 3px 8px
                      backdrop-filter: opacity(88%)
                      z-index: 99 !important
          - component: oh-link
            config:
              text: "=items[props.shutdowntimer].state > 0 ? items[props.shutdowntimer].state : 'Timer'"
              visible: "=props.shutdowntimer ? true : false"
              action: popover
              popoverOpen: .timerpopover
              class:
                - display-flex
                - justify-content-center
                - align-items-center
              style:
                margin-top: 16px
              z-index: 98
            slots:
              default:
                - component: f7-popover
                  config:
                    class:
                      - timerpopover
                  slots:
                    default:
                      - component: oh-stepper-card
                        config:
                          item: =props.shutdowntimer
                          title: Таймер
          - component: f7-block
            config:
              class:
                - display-flex
                - justify-content-center
                - align-items-center
                - no-padding
                - no-margin
              style:
                width: 40px
                height: 40px
                border-top: '=items[props.colorMode].state == 1 ? "none" : "2px solid #ddd"'
                box-shadow: "inset 0px 1px 2px #eee"
                background: white
                border-radius: 50%
            slots:
              default:
                - component: f7-block
                  config:
                    class:
                      - no-margin
                    style:
                      position: absolute
                      width: 100%
                      height: 100%
                      box-shadow: '=items[props.colorMode].state == 1 ? "0 0 15px #fff, -7px -7px 15px rgba(255,0,0,0.5), 7px -7px 15px rgba(255,255,0,0.5), 7px 7px 15px rgba(0,255,0,0.5), -7px 7px 15px rgba(255,255,0,0.5)" : "none"'
                      border-radius: 50%
                      transition: transform 0.2s
                      background: '=items[props.colorMode].state == 1 ? "linear-gradient(135deg, red, orange, yellow, green, blue)" : "transparent"'
                      transform: '=items[props.colorMode].state == 1 ? "rotate(360deg) scale(1,1)" : "rotate(0deg) scale(0,0)"'
                - component: f7-block
                  config:
                    style:
                      position: absolute
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      background: rgba(255,255,255,0.8)
                      border-radius: 50%
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: paintbrush
                    iconSize: 19
                    action: command
                    actionItem: =props.colorMode
                    actionCommand: 1
                    style:
                      display: '=items[props.colorMode].state == 2 ? "block" : "none"'
                      border: solid 4pt white
                      border-radius: 50%
                      background-color: "#f7f7f7"
                      background-image: "linear-gradient(135deg, #f7f7f7, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      align-items: center
                      justify-content: center
                      box-shadow: 0px 3px 8px
                      backdrop-filter: opacity(88%)
                    class:
                      - nextSlide
                - component: oh-link
                  config:
                    iconOnly: true
                    iconF7: paintbrush_fill
                    iconSize: 19
                    action: command
                    actionItem: =props.colorMode
                    actionCommand: 2
                    style:
                      display: '=items[props.colorMode].state == 1 ? "block" : "none"'
                      border: solid 4pt white
                      border-radius: 50%
                      background-color: "#f7f7f7"
                      background-image: "linear-gradient(135deg, #f7f7f7, #e7e7e7)"
                      color: "#a7a7a7"
                      width: calc(100% - 10px)
                      height: calc(100% - 10px)
                      box-shadow: 0px 3px 8px
                      backdrop-filter: opacity(88%)
                    class:
                      - previousSlide

Hi,

Thanks for sharing, it works perfectly to control my Hue lights.