Universal Toggle

Hi,

I hereby present you my universal toggle widget. The widget can be used in three different ways:

  1. Toggle a single switch
  2. Toggle a number of similar switches (e.g. some light switches)
  3. Toggle a number of similar switches (like 2.) together with a main switch to toggle all switches at the same time

Note that the widget does not care what switches you give it when you are using it in mode 3. The way I described it is just the way I am using it/the way it is meant to be used.

This is what it looks like:

And in action:
universal_toggle

Configuration:

Title: Card title (leave empty for no title bar)
Footer: Card footer (leave empty for no footer) NOTE: There appears to be a bug that sometimes prevents the scrolling of the grouptoggle swiper slide that I filed here: oh-repeater does not work correctly to populate f7-swiper-slides in f7-swiper · Issue #840 · openhab/openhab-webui · GitHub Setting a card footer with an expression (as in the example) seems to “fix” this but unfortunately not reliably. Please let me know if this is also an issue for you or if you know how to fix it.
F7 Icon: The name of the icon that should be shown in the widget
Color: The color scheme to use for the widget
Main toggle item: The “main switch” for the group or just a single switch if no group is configured (leave empty if you only want to switch a group of items without main switch)
Group toggle array: The array of switches that should be shown on the second slide or the single slide if the Main toggle item is omitted. Syntax: “<Label shown above icon of item 1>”,“<Name of item 1>”|“<Label shown above icon of item 2>”,“<Name of item 2>”, repeat as needed (leave empty if you only need the main switch)

Resources

The Code:

uid: universal_toggle_v4
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - description: The card footer
      label: Footer
      name: footer
      required: false
      type: TEXT
    - description: Name of the Icon (see https://framework7.io/icons/ for available icons)
      label: F7 Icon
      name: icon
      required: true
      type: TEXT
    - description: Color scheme for icons and toggles (see https://framework7.io/docs/color-themes.html for available color schemes)
      label: Color
      name: color
      required: true
      type: TEXT
    - context: item
      description: Main toggle item (use for single toggle or as main switch for group)
      label: Item
      name: maintoggle
      required: false
      type: TEXT
    - description: Group toggles (use as group with or without main toggle)
      label: Group toggle Array
      name: grouptogglearray
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Aug 27, 2023, 5:49:59 PM
component: f7-card
config:
  title: =(props.title)
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-swiper
            config:
              init: true
              pagination: "=(props.maintoggle) && (props.grouptogglearray) ? true : false"
              params:
                pagination:
                  clickable: true
                slidesPerView: 1
              style:
                height: 175px
                width: 100%
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    style:
                      height: 100%
                      width: 100%
                    visible: "=(props.maintoggle) ? true : false"
                  slots:
                    default:
                      - component: f7-col
                        config:
                          class:
                            - display-flex
                            - flex-direction-column
                            - align-items-center
                            - justify-content-space-evenly
                          style:
                            height: 100%
                            width: 100%
                        slots:
                          default:
                            - component: oh-link
                              config:
                                action: toggle
                                actionItem: =props.maintoggle
                                actionCommand: ON
                                actionCommandAlt: OFF
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      color: '=items[props.maintoggle].state == "ON" ? props.color : items[props.maintoggle].state > 0 ? props.color : "gray"'
                                      f7: =props.icon
                                      size: '=(props.grouptogglearray) ? "100" : "120"'
                            - component: oh-toggle
                              config:
                                colorTheme: =props.color
                                item: =props.maintoggle
                            - component: f7-block
                              config:
                                style:
                                  display: '=(props.grouptogglearray) ? "block" : "none"'
                                  height: 35px
                - component: f7-swiper-slide
                  config:
                    visible: "=(props.grouptogglearray) ? true : false"
                  slots:
                    default:
                      - component: f7-swiper
                        config:
                          params:
                            direction: vertical
                            mousewheel: true
                            scrollbar:
                              hide: true
                            slidesPerView: 1
                          scrollbar: true
                          style:
                            height: 100%
                            width: 100%
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                for: item
                                fragment: true
                                in: =props.grouptogglearray.split("|")
                              slots:
                                default:
                                  - component: f7-swiper-slide
                                    config:
                                      style:
                                        height: 100%
                                        width: 100%
                                    slots:
                                      default:
                                        - component: f7-col
                                          config:
                                            class:
                                              - display-flex
                                              - flex-direction-column
                                              - align-items-center
                                              - justify-content-space-evenly
                                            style:
                                              height: 100%
                                              width: 100%
                                          slots:
                                            default:
                                              - component: f7-block-title
                                                config:
                                                  style:
                                                    margin-bottom: -2px
                                                    margin-top: 10px
                                                slots:
                                                  default:
                                                    - component: Label
                                                      config:
                                                        text: =loop.item.split("\"")[1]
                                              - component: oh-link
                                                config:
                                                  action: toggle
                                                  actionItem: =(loop.item.split("\"")[3])
                                                  actionCommand: ON
                                                  actionCommandAlt: OFF
                                                slots:
                                                  default:
                                                    - component: f7-icon
                                                      config:
                                                        color: '=items[loop.item.split("\"")[3]].state == "ON" ? props.color : "gray"'
                                                        f7: =props.icon
                                                        size: 70
                                              - component: oh-toggle
                                                config:
                                                  colorTheme: =props.color
                                                  item: =(loop.item.split("\"")[3])
                                              - component: f7-block
                                                config:
                                                  style:
                                                    display: '=(props.maintoggle) ? "block" : "none"'
                                                    height: 35px
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: =props.footer

Please let me see screenshots of what you are using them for :slight_smile:

18 Likes

Forgot to mention that there is actually a fourth mode: if you pass a single item into the group array you get the functionality of a single switch (mode 1.) but with a label on top of the icon.

Your Widghets (also the washing machine and the dishwasher) looks very nice.

if my skills in openhab are better i sure will implement this to my project. Maybe some will work a tutorial out for this? :slight_smile:

Thank you Bernhard! You mean a tutorial for the widgets? I hope I wrote down everything you need to know in the first post. If you have any questions feel free to ask here!

First thank you :slightly_smiling_face:
You wanted some use case screenshot. That’s not much but I use it to control the power outlet of my pellet stove.
That thing consumes too much power while on standby (up to 15W) so I got a script that shut off the power when I’m done using it. But then when I want to start a fire, I need to turn the plug on first.
So I’m using your widget to turn the power plug on, get the status of it and the live power consumption.
I’m actually using a dummy switch so that one cannot turn the power plug off manually. I have a script that will turn it off automatically when the cool down cycle is finished (which I detect through the power consumption)
Here is what it looks like :
image
image

1 Like

Nice thanks for sharing!

I just recently added one more widget to be able to temporarily disable my Adblocker on the network. As I have two Pi-holes in the network it would be a bit of a pain to do this for both instances separately. With a swipe to the right I can see the status of both individual Pi-hole instances (second screenshot):


Nice implementation!

I also want to use this to turn “ON” and “OFF” a switch item, that I have created. But I meet some problems. No matter how I click the toggle in UI, the state of my switch never changes:

{
    "link": "http://137.226.248.161:8080/rest/items/gateway_switch",
    "state": "OFF",
    "editable": true,
    "type": "Switch",
    "name": "gateway_switch",
    "label": "gateway_switch",
    "category": "",
    "tags": [],
    "groupNames": []
}

And the color of the icon does not change either.
Screenshot 2023-05-16 222616
Screenshot 2023-05-16 222637

Here is also how I configure the widget.

Can someone help me out? Thanks a lot!

The icon color only changes when the actual item state changes whereas the toggle will just react immediately when you touch it. So especially when autoupdate is set to false there may be a delay between the toggle and the icon color change. If the item does not change its state at all then the icon will remain grey and the toggle will go back to being grey as well after a short time. So to me it looks as if the device you want to control is not reacting. I’m not familiar with the json you posted on your previous post especially the „link“ part. Could you explain where this comes from?

Nice widget. Thank you

Unfortunately I have the following situation: the widget works in editor mode, if “run mode” is on. But the same cell will not work, if I open the same page using the main ui webpage. In this case, I only see the header, but no icon (cell is blank). On the other hand the widget works by using the openhab app.

Hm I never experienced this behaviour. Which browser do you use?

It was in chrome, but works after restarting openhab container. No idea why.

Thanks for this relay cool widget!
I have a suggestion for improvement:
Is it possible to make the icon also “clickable”, that you don´t need to push the toggle?

Hi Gorilla,

thank you for your feedback! I like the idea and I guess it should be easy to achieve. I‘ll see if I find a bit of time to look into it later that day.

1 Like

I just updated the code in the first post. The Icons are now clickable as well. Thanks go to JustinG who brought me on the right track (in the end it was a little bit trickier than I thought). Thank again for proposing this change Gorilla.

Works fine. Thanks alot!

Thanks for that easy and very nice widget.

I have the situation, that I see some list bullet points in front of the swiper and the icon?
image
How can that be removed?

Thx

I’ve never seen this. Could you post a screenshot of you configuration please?

This is the configuration yaml

component: widget:universal_toggle_v4
config:
  icon: f7:thermometer
  maintoggle: Buro_Raumtemperaturregler_1004_ABB700C733A4_Activate

and here goes the widget yaml itself

uid: universal_toggle_v4
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - description: The card footer
      label: Footer
      name: footer
      required: false
      type: TEXT
    - description: Name of the Icon (see https://framework7.io/icons/ for available icons)
      label: F7 Icon
      name: icon
      required: true
      type: TEXT
    - description: Color scheme for icons and toggles (see https://framework7.io/docs/color-themes.html for available color schemes)
      label: Color
      name: color
      required: true
      type: TEXT
    - context: item
      description: Main toggle item (use for single toggle or as main switch for group)
      label: Item
      name: maintoggle
      required: false
      type: TEXT
    - description: Group toggles (use as group with or without main toggle)
      label: Group toggle Array
      name: grouptogglearray
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Sep 11, 2023, 1:07:08 PM
component: f7-card
config:
  title: =(props.title)
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-swiper
            config:
              init: true
              pagination: "=(props.maintoggle) && (props.grouptogglearray) ? true : false"
              params:
                pagination:
                  clickable: true
                slidesPerView: 1
              style:
                height: 175px
                width: 100%
            slots:
              default:
                - component: f7-swiper-slide
                  config:
                    style:
                      height: 100%
                      width: 100%
                    visible: "=(props.maintoggle) ? true : false"
                  slots:
                    default:
                      - component: f7-col
                        config:
                          class:
                            - display-flex
                            - flex-direction-column
                            - align-items-center
                            - justify-content-space-evenly
                          style:
                            height: 100%
                            width: 100%
                        slots:
                          default:
                            - component: oh-link
                              config:
                                action: toggle
                                actionItem: =props.maintoggle
                                actionCommand: ON
                                actionCommandAlt: OFF
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      color: '=items[props.maintoggle].state == "ON" ? props.color : items[props.maintoggle].state > 0 ? props.color : "gray"'
                                      f7: =props.icon
                                      size: '=(props.grouptogglearray) ? "100" : "120"'
                            - component: oh-toggle
                              config:
                                colorTheme: =props.color
                                item: =props.maintoggle
                            - component: f7-block
                              config:
                                style:
                                  display: '=(props.grouptogglearray) ? "block" : "none"'
                                  height: 35px
                - component: f7-swiper-slide
                  config:
                    visible: "=(props.grouptogglearray) ? true : false"
                  slots:
                    default:
                      - component: f7-swiper
                        config:
                          params:
                            direction: vertical
                            mousewheel: true
                            scrollbar:
                              hide: true
                            slidesPerView: 1
                          scrollbar: true
                          style:
                            height: 100%
                            width: 100%
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                for: item
                                fragment: true
                                in: =props.grouptogglearray.split("|")
                              slots:
                                default:
                                  - component: f7-swiper-slide
                                    config:
                                      style:
                                        height: 100%
                                        width: 100%
                                    slots:
                                      default:
                                        - component: f7-col
                                          config:
                                            class:
                                              - display-flex
                                              - flex-direction-column
                                              - align-items-center
                                              - justify-content-space-evenly
                                            style:
                                              height: 100%
                                              width: 100%
                                          slots:
                                            default:
                                              - component: f7-block-title
                                                config:
                                                  style:
                                                    margin-bottom: -2px
                                                    margin-top: 10px
                                                slots:
                                                  default:
                                                    - component: Label
                                                      config:
                                                        text: =loop.item.split("\"")[1]
                                              - component: oh-link
                                                config:
                                                  action: toggle
                                                  actionItem: =(loop.item.split("\"")[3])
                                                  actionCommand: ON
                                                  actionCommandAlt: OFF
                                                slots:
                                                  default:
                                                    - component: f7-icon
                                                      config:
                                                        color: '=items[loop.item.split("\"")[3]].state == "ON" ? props.color : "gray"'
                                                        f7: =props.icon
                                                        size: 70
                                              - component: oh-toggle
                                                config:
                                                  colorTheme: =props.color
                                                  item: =(loop.item.split("\"")[3])
                                              - component: f7-block
                                                config:
                                                  style:
                                                    display: '=(props.maintoggle) ? "block" : "none"'
                                                    height: 35px
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: =props.footer

Hmmm, this looks simple enough. Only thing I notice is that you should simply use „thermometer“ without the „f7:“ prefix. Can you try if this makes a difference?

I guess the yaml is unchanged? Does it look like this on the saved page or only when you are in edit mode? In edit mode things sometimes don’t look right…

Wow…i did remove the f7: now it works! Thx