Sonos Player

@johannesbonn There is nothing to change on the widget because we are not performing a parent loop.

I checked the snapshot version 2160 but it seams that the issue still occours if you place serval widgets on the same page.

@ysc Unfortunately your bug fix is not working :frowning: When I open a page with serval widgets it always shows the result of the last oh-repeater in all 3 widgets. To be sure I forced a cache refresh but unfortunately this was not solving the issue. In the Dev messages I can see that all commands are send with the “Bathroom” flag which was set to my last widget.

@opus can you share the yaml code of one widget?
By the way, are you placing serval player widgets on the same page or are you using the player widget on different pages? There is a bug if you run the player widget multiple times on the same page as described in the previous discussion. (Hopefully ysc can help t fix this.
But if you use the widget on a per room page than it is working without any issues if it is properly configured :wink:

The yaml:

component: widget:widget_Sonos_Player
config:
  itemTitle: PlayBuero
  itemPlayer: PlayBuero_Fernbedienung
  itemSonosRule: Sonos_Multiroom_Controll
  itemCover: PlayBuero_Coverbild
  propZoneArray: '["Wohnzimmer"; "PlayWohnzimmer_Fernbedienung";
    "PlayWohnzimmer_Lautstarke"; "PlayWohnzimmer_Master"]["Buero",
    "PlayBuero_Fernbedienung"; "PlayBuero_Lautstarke";
    "PlayBuero_Master"]["Kueche"; "PlayKueche_Fernbedienung";
    "PlayKueche_Lautstarke"; "PlayKueche_Master"]["Gaestezimmer",
    "PlayGaestezimmer_Fernbedienung"; "PlayGaestezimmer_Lautstarke";
    "PlayGaestezimmer_Master"]'
  itemVolume: PlayBuero_Lautstarke
  itemCoordinator: PlayBuero_Master

…and I use only one widget.

@opus If you want to use the “grouping” feature you need to provide the ZoneName parameter as well. Thie is related to the ZoneArray parameter. So the ZoneName identifies the current controlled group.

Try this YAML code and have a look at the last line to see which value I added.

component: widget:widget_Sonos_Player
config:
  itemTitle: PlayBuero
  itemPlayer: PlayBuero_Fernbedienung
  itemSonosRule: Sonos_Multiroom_Controll
  itemCover: PlayBuero_Coverbild
  propZoneArray: '["Wohnzimmer"; "PlayWohnzimmer_Fernbedienung";
    "PlayWohnzimmer_Lautstarke"; "PlayWohnzimmer_Master"]["Buero",
    "PlayBuero_Fernbedienung"; "PlayBuero_Lautstarke";
    "PlayBuero_Master"]["Kueche"; "PlayKueche_Fernbedienung";
    "PlayKueche_Lautstarke"; "PlayKueche_Master"]["Gaestezimmer",
    "PlayGaestezimmer_Fernbedienung"; "PlayGaestezimmer_Lautstarke";
    "PlayGaestezimmer_Master"]'
  itemVolume: PlayBuero_Lautstarke
  itemCoordinator: PlayBuero_Master
  propZoneName: Buero

Bingo, that worked.
One more question:
As I understand ATM the intended use is one widget per room(page), the grouping would be used to group several rooms. Is that correct?

Yes at the moment you can only place one widget on a page because a bug in the oh-repeater. So e.g. one in a room page “living room”. The widget aways controls the living room speaker. But it can add other speakers to the same zone or add itself to another running zone.

1 Like

Thank you for your reply! Is it possible to use several labels on one page with popups of the widget for every zone?

All understood now.
The last problem I had was that the rule needs to be triggered on a command (otherwise the variable command is not defined. IMHO that isn’t stated as needed.

Does the rule work for you when using it to Add a player? I get an Error Fail to execute action: 2.
On my system the internally used function isSpeakerActive is the problem (more precise the itemRegistry.getItem(mySpeaker + itemPlayExtensionName).getState().toString() is producing the error).

[Edit:]
Without the double if-clause which uses the above function, using only the addSpeaker(getSpeakerName(coordinator), getSpeakerUUID(speakerToControl)); in any case it is working if the coordinator is palying or not.

[Edit2:]
DISREGARD all the above.using Item
I observed a “curious” REST behaviour (Add not working, other Rule-parts using itemRegistry working, saving any Widgit-config not possible), did a restart of openHAB and REST is working again normal.
In other words: No problem with the rule!! Sorry for the hussle.

1 Like

I’m receiving a WARN whenever (re)loading the widget: Attempting to send a state update of an item which doesn't exist: undefined.
I have all needed items created, looked thrpugh the complete widget yaml code, can’t find a hint what is missing.

Thank you! After some work it works flawlessly. For all other who might be struggling … check your capitalizations! In the description for the multiroom rule there are a few suffixes like _control used with a lower case first letter, but the standard values in the rules use a capital first letter (like _Control).

I still have a visual issues with the volume item though:

  • all individual volume controls work
  • the master volume control works

But:

  • The “red” bar that visualizes the master volume seems to be totally off. I have set the ZoneVolume in the item Selector as described in the first post.

edit: I just noticed, I created all the ZoneVolume items as “dimmers” like the original volume items. But that wasn’t really specified in the multiroom rule (there is no info about the type of the zone volume items). So I changed them all to “number”, but it has the same effect.

It seems the scale of the volume control is completely off, see how far I have to drag the slider to get 100%. If I actually set it to 20, 25 or whatever, the proper value gets set to the zones though.
grafik

Edit 4: the workaround to this is, to add the widget into a row->column block. It doesn’t work in cell or masonry :frowning:

I also have one other question: i have seen some screenshots where the widget seems to be a bit broader. Yet, for me, it’s always quite narrow, no matter whether I place it in masonry or in a row. How did you do that?

edit3:
I just implemented this through a rule, I set a place holder image, whenever the cover art item changes to UNDEF. See here
And one more thing: When I change the input to “TV” sadly there doesn’t seem to a way for the sonos binding to indicate this. The album art then changes to “undef” and makes a broken image appear. It would be nice to intercept this in the widget.

@buschif4 - Great work here!

While I don’t have a Sonos device, have a bunch of Amazon Echo’s; to my surprise your widget already works quite well with the Amazon Echo Binding accept of course the multi-room control stuff. In my spare time I might rework the code to support selecting the target Amazon Echo, as well as zones.

Thanks for sharing!

@buschif4

Hi Flo,

i have added all the Items Groups and so on. but when i click on the Widget for “Volume” nothing appears. The same by clicking on the Multiroom rule.
I have also changed the “Endings” in the Script to German Items.
nothing appears.

The same by click on the Speaker Selection

Widget YAML:
component: widget:widget_Sonos_Player
config:
itemTitle: SonosMoveWohnzimmer_Titel
itemAlbum: SonosMoveWohnzimmer_Album
itemArtist: SonosMoveWohnzimmer_Kunstler
itemCover: SonosMoveWohnzimmer_Coverbild
itemPlayer: SonosMoveWohnzimmer_Fernbedienung
itemVolume: SonosMoveWohnzimmer_ZoneVolume
itemShuffle: SonosMoveWohnzimmer_Shuffle
itemRepeat: SonosMoveWohnzimmer_Wiederholen
itemSonosRule: Sonos_Multiroom_Controll
propZoneArray: “[“Kueche”; “SonosOneKuche_Fernbedienung”;
“SonosOneKuche_Lautstarke”; “SonosOneKuche_Master”][“Bad”;
“SonosOneBad_Fernbedienung”; “SonosOneBad_Lautstarke”;
“SonosOneBad_Master”]”
propWidgetTitle: Wohnzimmer
propZoneName: Wohnzimmer
itemCoordinator: SonosMoveWohnzimmer_Master

Rule Volume:
triggers:

  • id: “3”
    configuration:
    groupName: Group_Sonos_ZoneVolume
    type: core.GroupCommandTrigger

  • id: “4”
    configuration:
    groupName: Group_Sonos_Volumes
    type: core.GroupStateChangeTrigger

  • id: “1”
    configuration:
    groupName: Group_Sonos_Coordinators
    type: core.GroupStateChangeTrigger
    conditions: []
    actions:

  • inputs: {}
    id: “2”
    configuration:
    type: application/javascript
    script: >-

    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    
    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ User inputrequired! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    
    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    
    
    //group where all sonos items belong to (can be a nested group)
    
    var itemGroupName = "Group_Sonos";
    
    
    //Volume item extension (controls the volume of the player)
    
    var itemVolumeExtensionName = "_Lautstarke";
    
    
    //Zone volume item for the widget. Not connected to any thing item.
    
    var itemZoneVolumeExtensionName = "_ZoneVolume";
    
    
    //Coordinator item extension (displays the master of this zone)
    
    var itemMasterExtensionName = "_Master";
    
    
    
    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    

Rule Multiroom:
triggers:

  • id: “1”
    configuration:
    itemName: Sonos_Multiroom_Controll
    type: core.ItemCommandTrigger
    conditions: []
    actions:

  • inputs: {}
    id: “2”
    configuration:
    type: application/javascript
    script: "//speaker array needs to be filled for each player → “zone name”,
    “device name”, “device UUID”

    var sonosSpeakers = [
    
    \  [\"Wohnzimmer\", \"SonosMoveWohnzimmer\",
    \"RINCON_XXXXX1400\"],
    
    \  [\"Kueche\", \"SonosOneKuche\",
    \"RINCON_XXXX1400\"],
    
    \  [\"Bad\", \"SonosOneBad\", \"RINCON_XXXXXX1400\"]
    
    ];
    
    
    //default volume in hours
    
    var defaultSpeakerVolume = [8, 8, 8, 8, 8, 8, 8, 10, 12, 14, 16,
    18, 18, 20, 20, 20, 20, 18, 18, 16, 14, 12, 10, 8]
    
    
    //default play uri can pe a uri or tunein station id depending
    of the playuri item
    
    var defaultPlayUri = \"24878\"
    
    
    //group where all sonos items belong to (can be a nested group)
    
    var itemGroupName = \"Group_Sonos\";
    
    
    //Player item extension (defines the player status)
    
    var itemPlayExtensionName = \"_Fernbedienung\";
    
    
    //Volume item extension (controls the volume of the player)
    
    var itemVolumeExtensionName = \"_Lautstarke\";
    
    
    //Add-speaker item extension (adds a speaker to the zone
    coordinator)
    
    var itemAddExtensionName = \"_Hinzufugen\";
    
    
    //Remove-speaker item extension (removes speaker from the zone
    coordinator)
    
    var itemRemoveExtensionName = \"_Entfernen\";
    
    
    //Play-Uri item extension (needed to play a uri on a new group)
    
    var itemPlayUriExtensionName = \"_Tuneinstationid\";
    
    
    //Standalone item extension (needed to remove player if this is
    the coordinator in a multiroom zone)
    
    var itemStandaloneExtensionName = \"_StandAlone\";
    
    
    //Coordinator item extension (displays the master of this zone)
    
    var itemMasterExtensionName = \"_Master\";
    

I have no Idea where is the fault…

I think the Rule is not running an action…
But why? You have an Idea.
Openhab 3.2.0M1 in Docker auf Synology

Thanks

Danke
Stefan

@vally your issue is located in the propZoneArray. It is not correct formated.

The correct formating would be

propZoneArray: '[“Kueche”; “SonosOneKuche_Fernbedienung”;
“SonosOneKuche_Lautstarke”; “SonosOneKuche_Master”][“Bad”;
“SonosOneBad_Fernbedienung”; “SonosOneBad_Lautstarke”;
“SonosOneBad_Master”]'

Hello

Is it somehow possible to import the widget into the habpanel?
Or could this be adapted with little effort?

Hi thanks for the beautiful widget.
I allowed myself to add some additional features:

  • Loudness on/off
  • Mute on/off
  • base slider
  • treble slider
  • up to 4 InTunes Radion stations
  • up to 4 Sonos Favorites
  • up to 4 Sonos Playlists
  • Display Sonos icon in case no albumart is available (you’ll need /static/sonos_logo.jpg)

Looks like this now:

Here’s the widget code in case anyone is interested:

uid: widget_Sonos_Player
tags: []
props:
  parameters:
    - description: (optional) widget title
      label: (optional) widget title
      name: propWidgetTitle
      required: false
      type: TEXT
    - context: item
      description: item to display the title
      label: item title
      name: itemTitle
      required: true
      type: TEXT
    - context: item
      description: (optional) item to display the album
      label: (optional) item album
      name: itemAlbum
      required: false
      type: TEXT
    - context: item
      description: (optional) item to display the artist
      label: (optional) item artist
      name: itemArtist
      required: false
      type: TEXT
    - context: item
      description: (optional) item to display a cover image
      label: (optional) item cover image
      name: itemCover
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the player
      label: (optional) item player
      name: itemPlayer
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the volume
      label: (optional) item volume
      name: itemVolume
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control base
      label: (optional) item base
      name: itemBase
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control treble
      label: (optional) item treble
      name: itemTreble
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control loundness
      label: (optional) item loudness
      name: itemLoudness
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control mute
      label: (optional) item mute
      name: itemMute
      required: false
      type: TEXT
    - context: item
      description: (optional) item for shuffle option
      label: (optional) item shuffle
      name: itemShuffle
      required: false
      type: TEXT
    - context: item
      description: (optional) item for repeat option
      label: (optional) item repeat
      name: itemRepeat
      required: false
      type: TEXT
    - description: (optional) Name of the zone player
      label: (optional) Zone name
      name: propZoneName
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item of the zone coordinator channel
      label: (optional) item coordinator
      name: itemCoordinator
      required: false
      type: TEXT
      advanced: true
    - description: (optional) speaker array like this -> ["<zoneName>", "<player>", "<volume>", "<coordinator>"]["<zoneName2>", "<player2>", "<volume2>", "<coordinator2>"]
      label: (optional) speaker array
      name: propZoneArray
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item for the sonos mulltiroom rule. e.g. Sonos_Multiroom_Control
      label: (optional) item to control the multiroom control rule
      name: itemSonosRule
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item to control the TuneinStations
      label: (optional) item TuneinStation
      name: itemTuneinStation
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 1
      label: (optional) TuneinStation 1
      name: propTuneinStation1
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 2
      label: (optional) TuneinStation 2
      name: propTuneinStation2
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 3
      label: (optional) TuneinStation 3
      name: propTuneinStation3
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 4
      label: (optional) TuneinStation 4
      name: propTuneinStation4
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the Favorites
      label: (optional) item Favorite
      name: itemFavorite
      required: false
      type: TEXT
    - description: (optional) name of Favorite 1
      label: (optional) Favorite 1
      name: propFavorite1
      required: false
      type: TEXT
    - description: (optional) name of Favorite 1 Icon
      label: (optional) Favorite 1 Icon
      name: propFavorite1IconUrl
      required: false
      type: TEXT
    - description: (optional) name of Favorite 2
      label: (optional) Favorite 2
      name: propFavorite2
      required: false
      type: TEXT
    - description: (optional) name of Favorite 2 Icon
      label: (optional) Favorite 2 Icon
      name: propFavorite2IconUrl
      required: false
      type: TEXT
    - description: (optional) name of Favorite 3
      label: (optional) Favorite 3
      name: propFavorite3
      required: false
      type: TEXT
    - description: (optional) name of Favorite 3 Icon
      label: (optional) Favorite 3 Icon
      name: propFavorite3IconUrl
      required: false
      type: TEXT
    - description: (optional) name of Favorite 4
      label: (optional) Favorite 4
      name: propFavorite4
      required: false
      type: TEXT
    - description: (optional) name of Favorite 4 Icon
      label: (optional) Favorite 4 Icon
      name: propFavorite4IconUrl
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the playlist
      label: (optional) item playlist
      name: itemPlaylist
      required: false
      type: TEXT
    - description: (optional) name of playlist 1
      label: (optional) playlist 1
      name: propPlaylist1
      required: false
      type: TEXT
    - description: (optional) name of playlist 1 Icon
      label: (optional) playlist 1 Icon
      name: propPlaylist1IconUrl
      required: false
      type: TEXT
    - description: (optional) name of playlist 2
      label: (optional) playlist 2
      name: propPlaylist2
      required: false
      type: TEXT
    - description: (optional) name of playlist 2 Icon
      label: (optional) playlist 2 Icon
      name: propPlaylist2IconUrl
      required: false
      type: TEXT
    - description: (optional) name of playlist 3
      label: (optional) playlist 3
      name: propPlaylist3
      required: false
      type: TEXT
    - description: (optional) name of playlist 3 Icon
      label: (optional) playlist 3 Icon
      name: propPlaylist3IconUrl
      required: false
      type: TEXT
    - description: (optional) name of playlist 4
      label: (optional) playlist 4
      name: propPlaylist4
      required: false
      type: TEXT
    - description: (optional) name of playlist 4 Icon
      label: (optional) playlist 4 Icon
      name: propPlaylist4IconUrl
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Dec 8, 2021, 5:09:24 PM
component: f7-card
config:
  title: =props.propWidgetTitle
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-row
            slots:
              default:
                - component: Label
                  config:
                    text: "Title: "
                    class:
                      - display-flex
          - component: f7-row
            config:
              style:
                position: relative
                top: -10px
                height: 30px
              class:
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    text: =items[props.itemTitle].displayState || items[props.itemTitle].state
                    style:
                      fontSize: 28px
                      white-space: nowrap
                      overflow: hidden
          - component: f7-row
            config:
              visible: "=(props.itemAlbum) ? true : false"
            slots:
              default:
                - component: Label
                  config:
                    text: "Album: "
                    class:
                      - display-flex
          - component: f7-row
            config:
              visible: "=(props.itemAlbum) ? true : false"
              style:
                position: relative
                top: -10px
                height: 30px
              class:
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    text: =items[props.itemAlbum].displayState || items[props.itemAlbum].state
                    style:
                      fontSize: 28px
                      white-space: nowrap
                      overflow: hidden
          - component: f7-row
            config:
              visible: "=(props.itemArtist) ? true : false"
            slots:
              default:
                - component: Label
                  config:
                    text: "Artist: "
                    class:
                      - display-flex
          - component: f7-row
            config:
              visible: "=(props.itemArtist) ? true : false"
              style:
                position: relative
                top: -10px
                height: 30px
              class:
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    text: =items[props.itemArtist].displayState || items[props.itemArtist].state
                    style:
                      fontSize: 28px
                      white-space: nowrap
                      overflow: hidden
          - component: f7-row
            config:
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: oh-image
                  config:
                    visible: '=( (props.itemCover) && items[props.itemCover].state !== "UNDEF") ? true : false'
                    item: =props.itemCover
                    style:
                      width: 70%
                - component: oh-image
                  config:
                    visible: '=(!(props.itemCover) || items[props.itemCover].state === "UNDEF") ? true : false'
                    url: /static/sonos_logo.jpg
                    style:
                      width: 70%
          - component: f7-row
            config:
              visible: "=(props.itemPlayer) ? true : false"
              class:
                - justify-content-space-around
                - display-flex
                - align-items-center
                - align-content-stretch
                - margin-top
              style:
                position: relative
                top: +5px
            slots:
              default:
                - component: f7-icon
                  config:
                    f7: '=(props.itemShuffle) ? "shuffle" : ""'
                    size: 20
                    color: '=(items[props.itemShuffle].state === "ON") ? "green" : ""'
                    style:
                      position: relative
                      left: +7%
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: command
                          actionItem: =props.itemShuffle
                          actionCommand: '=(items[props.itemShuffle].state !== "ON") ? "ON" : "OFF"'
                          style:
                            position: absolute
                            width: 100%
                            height: 100%
                            top: 0px
                - component: oh-player-item
                  config:
                    style:
                      width: 150px
                    item: =props.itemPlayer
                    class:
                      - display-flex
                      - margin-
                      - align-content-stretch
                      - align-items-center
                      - justify-content-space-around
                - component: f7-icon
                  config:
                    f7: '=(props.itemRepeat) ? (items[props.itemRepeat].state === "ALL") ? "repeat" : (items[props.itemRepeat].state === "ONE") ? "repeat_1" : "repeat" : ""'
                    size: 20
                    color: '=(items[props.itemRepeat].state === "ALL") ? "green" : (items[props.itemRepeat].state === "ONE") ? "green" : ""'
                    style:
                      position: relative
                      left: -8%
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: command
                          actionItem: =props.itemRepeat
                          actionCommand: '=(items[props.itemRepeat].state === "ALL") ? "ONE" : (items[props.itemRepeat].state === "ONE") ? "OFF": "ALL"'
                          style:
                            position: absolute
                            width: 100%
                            height: 100%
                            top: 0px
          - component: f7-row
            config:
              visible: "=(props.itemVolume) ? true : false"
              class:
                - justify-content-space-around
                - display-flex
                - align-items-center
                - align-content-stretch
            slots:
              default:
                - component: f7-card
                  config:
                    noShadow: true
                    class: margin display-flex align-items-center
                    style:
                      fontSize: 20px
                      min-width: calc(100% - 20px)
                  slots:
                    default:
                      - component: oh-slider
                        config:
                          label: true
                          scale: true
                          style:
                            height: +40px
                            width: calc(100% - 35px)
                          min: 0
                          item: =props.itemVolume
                          class:
                            - display-flex
                            - margin-horizontal
                            - align-content-stretch
                            - align-items-center
                            - justify-content-space-around
                      - component: f7-button
                        config:
                          class: '=(props.propZoneArray) ? "" : "display-none"'
                          style:
                            position: absolute
                            height: 100%
                            width: 100%
                            top: 0px
                          popoverOpen: .popoverVolume
                        slots:
                          default:
                            - component: f7-popover
                              config:
                                class: popoverVolume
                                style:
                                  min-width: 350px
                              slots:
                                default:
                                  - component: oh-repeater
                                    config:
                                      for: zoneVolume
                                      in: =props.propZoneArray.split("]")
                                      containerClasses:
                                        - display-flex
                                        - flex-direction-column
                                    slots:
                                      default:
                                        - component: f7-card
                                          config:
                                            class: '=(loop.zoneVolume.split("\"")[1] && items[loop.zoneVolume.split("\"")[7]].state === items[props.itemCoordinator].state) ? "display-flex flex-direction-row justify-content-flex-start align-items-center" : "display-none"'
                                            style:
                                              height: 40px
                                          slots:
                                            default:
                                              - component: Label
                                                config:
                                                  style:
                                                    fontSize: 20px
                                                  class:
                                                    - margin-left
                                                  text: =(loop.zoneVolume.split("\"")[1])
                                              - component: oh-slider
                                                config:
                                                  label: true
                                                  style:
                                                    height: +40px
                                                    width: calc(100% - 40%)
                                                  min: 0
                                                  item: =(loop.zoneVolume.split("\"")[5])
                                                  class:
                                                    - display-flex
                                                    - margin
                                                    - align-content-stretch
                                                    - align-items-center
                      - component: f7-icon
                        config:
                          visible: "=(props.itemMute) ? true : false"
                          f7: '=(items[props.itemMute].state !== "ON") ? "speaker_3" : "speaker_slash"'
                          class: margin-horizontal margin
                          size: 30
                        slots:
                          default:
                            - component: oh-button
                              config:
                                action: command
                                actionItem: =props.itemMute
                                actionCommand: '=(items[props.itemMute].state !== "ON") ? "ON" : "OFF"'
                                style:
                                  position: absolute
                                  width: 100%
                                  height: 100%
                                  top: 0px
          - component: f7-row
            config:
              visible: "=(props.itemBase || props.itemTreble) ? true : false"
              class:
                - justify-content-space-around
                - display-flex
                - align-items-center
                - align-content-stretch
            slots:
              default:
                - component: f7-card
                  config:
                    noShadow: true
                    class: margin display-flex align-items-center
                    style:
                      fontSize: 20px
                      min-width: calc(100% - 20px)
                  slots:
                    default:
                      - component: oh-slider
                        config:
                          visible: "=(props.itemTreble) ? true : false"
                          label: true
                          scale: true
                          min: -10
                          max: 10
                          scaleSteps: 10
                          scaleSubSteps: 1
                          style:
                            height: +40px
                            width: calc(100% - 35px)
                          item: =props.itemTreble
                          class:
                            - display-flex
                            - margin-horizontal
                            - align-content-stretch
                            - align-items-center
                            - justify-content-space-around
                      - component: oh-slider
                        config:
                          visible: "=(props.itemBase) ? true : false"
                          label: true
                          scale: true
                          min: -10
                          max: 10
                          scaleSteps: 10
                          scaleSubSteps: 1
                          style:
                            height: +40px
                            width: calc(100% - 35px)
                          item: =props.itemBase
                          class:
                            - display-flex
                            - margin-horizontal
                            - align-content-stretch
                            - align-items-center
                            - justify-content-space-around
                      - component: f7-icon
                        config:
                          visible: "=(props.itemLoudness) ? true : false"
                          f7: '=(items[props.itemLoudness].state !== "ON") ? "speaker" : "speaker_3_fill"'
                          class: margin-horizontal margin
                          size: 30
                        slots:
                          default:
                            - component: oh-button
                              config:
                                action: command
                                actionItem: =props.itemLoudness
                                actionCommand: '=(items[props.itemLoudness].state !== "ON") ? "ON" : "OFF"'
                                style:
                                  position: absolute
                                  width: 100%
                                  height: 100%
                                  top: 0px
          - component: f7-row
            config:
              visible: "=(props.itemTuneinStation) ? true : false"
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation1 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation1 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation1
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation2 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation2 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation2
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation4 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation3 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation3
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation4 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation4 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation4
                          style:
                            width: 80%
          - component: f7-row
            config:
              visible: "=(props.itemFavorite) ? true : false"
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite1Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          url: =props.propFavorite1IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite1
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite2Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          url: =props.propFavorite2IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite2
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite3Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsFavorite4Url !== "UNDEF") ? true : false'
                          url: =props.propFavorite3IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite3
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite4Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsFavorite4Url !== "UNDEF") ? true : false'
                          url: =props.propFavorite4IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite4
                          style:
                            width: 80%
          - component: f7-row
            config:
              visible: "=(props.itemPlaylist) ? true : false"
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist1Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist1IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist1
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist2Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist2IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist2
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist3Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist3IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist3
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist4Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist4IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist4
                          style:
                            width: 80%
          - component: f7-row
            config:
              class: '=(props.propZoneName && props.itemPlayer) ? "justify-content-space-around align-items-center align-content-stretch" : "display-none"'
              style:
                position: relative
                top: -26px
                height: 50px
            slots:
              default:
                - component: f7-card
                  config:
                    noShadow: true
                    class: display-flex align-items-center
                    style:
                      fontSize: 20px
                      min-width: 130px
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: hifispeaker
                          size: 30
                          class: margin
                      - component: Label
                        config:
                          class: margin-right
                          text: =props.propZoneName
                          style:
                            fontSize: 20px
                      - component: f7-icon
                        config:
                          f7: '=(items[props.itemPlayer].state === "PLAY") ? "chart_bar_alt_fill" : ""'
                          class: margin-right
                          size: 20
                      - component: f7-button
                        config:
                          class: '=(props.propZoneArray) ? "" : "display-none"'
                          style:
                            position: absolute
                            height: 100%
                            width: 100%
                            top: 0px
                          popoverOpen: .popoverPlayer
                        slots:
                          default:
                            - component: f7-popover
                              config:
                                class: popoverPlayer
                                style:
                                  min-width: 280px
                              slots:
                                default:
                                  - component: oh-repeater
                                    config:
                                      for: zoneSpeaker
                                      in: =props.propZoneArray.split("]")
                                      containerClasses:
                                        - display-flex
                                        - flex-direction-column
                                    slots:
                                      default:
                                        - component: f7-card
                                          config:
                                            class: '=(loop.zoneSpeaker.split("\"")[1]) ? "display-flex flex-direction-row align-items-center" : "display-none"'
                                            style:
                                              height: 40px
                                          slots:
                                            default:
                                              - component: oh-button
                                                config:
                                                  style:
                                                    position: absolute
                                                    top: 0px
                                                    width: 100%
                                                    height: 100%
                                                  action: command
                                                  actionItem: =props.itemSonosRule
                                                  actionCommand: '=(items[loop.zoneSpeaker.split("\"")[7]].state === items[props.itemCoordinator].state) ? "Remove:" + loop.zoneSpeaker.split("\"")[1] + "" : "Add:" + loop.zoneSpeaker.split("\"")[1] + "@" + props.propZoneName'
                                              - component: f7-col
                                                config:
                                                  class: margin display-flex flex-direction-row align-items-center
                                                slots:
                                                  default:
                                                    - component: f7-icon
                                                      config:
                                                        f7: '=(items[loop.zoneSpeaker.split("\"")[7]].state === items[props.itemCoordinator].state) ? "checkmark_alt_circle_fill" : "circle"'
                                                    - component: Label
                                                      config:
                                                        class: margin-left
                                                        text: =loop.zoneSpeaker.split("\"")[1]
                                                        style:
                                                          fontSize: 20px
                                              - component: f7-col
                                                config:
                                                  class: margin align-items-center
                                                slots:
                                                  default:
                                                    - component: f7-icon
                                                      config:
                                                        f7: '=(items[loop.zoneSpeaker.split("\"")[3]].state === "PLAY") ? "chart_bar_alt_fill" : ""'

Here’s the Sonos Logo jpg:
sonos_logo

P.S.: I did not test this version with the ZoneArray logic though (didn’t understand it yet :slight_smile: )…

1 Like

@Carlo_Caprez:
As far as I know there’s no way of importing OH3 widgets into habpanel but if you are looking for a Sonos Control for habpanel take a look at this post (I just posted an update of the habpanel sonos controller recently):

I took a look at the ZoneArray logic and decided it’s too complicated for the limited capabilities of my brain so I tweaked the widget code to work w/o the scripts/rules (some minor draw backs though - see below).

The grouping/ungrouping can be done by simply clicking an item in the list (not sure if that already was the case before)

Some drawback/prerequisites though:

  • The item for making a speaker “standalone” (Sonos “standalone” channel - to remove it from a group) needs to follow this naming convention:
    Sonos_<zone_name>_Standalone
    Example: for a Zone named “Buero” the standalone-item would need to be named:
    Sonos_Buero_Standalone
    Alternatively you can adjust the widget code (line 861) to fit your naming convention for standalone items:

  • No automatic ungrouping for inactive speakers in a group

  • No more default uri to play on all speakers of a group

here’s the updated widget code:

uid: widget_Sonos_Player
tags: []
props:
  parameters:
    - description: (optional) widget title
      label: (optional) widget title
      name: propWidgetTitle
      required: false
      type: TEXT
    - context: item
      description: item to display the title
      label: item title
      name: itemTitle
      required: true
      type: TEXT
    - context: item
      description: (optional) item to display the album
      label: (optional) item album
      name: itemAlbum
      required: false
      type: TEXT
    - context: item
      description: (optional) item to display the artist
      label: (optional) item artist
      name: itemArtist
      required: false
      type: TEXT
    - context: item
      description: (optional) item to display a cover image
      label: (optional) item cover image
      name: itemCover
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the player
      label: (optional) item player
      name: itemPlayer
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the volume
      label: (optional) item volume
      name: itemVolume
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control base
      label: (optional) item base
      name: itemBase
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control treble
      label: (optional) item treble
      name: itemTreble
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control loundness
      label: (optional) item loudness
      name: itemLoudness
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control mute
      label: (optional) item mute
      name: itemMute
      required: false
      type: TEXT
    - context: item
      description: (optional) item for shuffle option
      label: (optional) item shuffle
      name: itemShuffle
      required: false
      type: TEXT
    - context: item
      description: (optional) item for repeat option
      label: (optional) item repeat
      name: itemRepeat
      required: false
      type: TEXT
    - description: (optional) Name of the zone player
      label: (optional) Zone name
      name: propZoneName
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item of the zone coordinator channel
      label: (optional) item coordinator
      name: itemCoordinator
      required: false
      type: TEXT
      advanced: true
    - description: (optional) speaker array like this -> ["<zoneName>", "<player>", "<volume>", "<coordinator>"]["<zoneName2>", "<player2>", "<volume2>", "<coordinator2>"]
      label: (optional) speaker array
      name: propZoneArray
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item for the sonos mulltiroom rule. e.g. Sonos_Multiroom_Control
      label: (optional) item to control the multiroom control rule
      name: itemSonosRule
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item for the adding another zone
      label: (optional) item to add another zone
      name: itemAdd
      required: false
      type: TEXT
      advanced: true
    - context: item
      description: (optional) item to control the TuneinStations
      label: (optional) item TuneinStation
      name: itemTuneinStation
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 1
      label: (optional) TuneinStation 1
      name: propTuneinStation1
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 2
      label: (optional) TuneinStation 2
      name: propTuneinStation2
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 3
      label: (optional) TuneinStation 3
      name: propTuneinStation3
      required: false
      type: TEXT
    - description: (optional) name of TuneinStation 4
      label: (optional) TuneinStation 4
      name: propTuneinStation4
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the Favorites
      label: (optional) item Favorite
      name: itemFavorite
      required: false
      type: TEXT
    - description: (optional) name of Favorite 1
      label: (optional) Favorite 1
      name: propFavorite1
      required: false
      type: TEXT
    - description: (optional) name of Favorite 1 Icon
      label: (optional) Favorite 1 Icon
      name: propFavorite1IconUrl
      required: false
      type: TEXT
    - description: (optional) name of Favorite 2
      label: (optional) Favorite 2
      name: propFavorite2
      required: false
      type: TEXT
    - description: (optional) name of Favorite 2 Icon
      label: (optional) Favorite 2 Icon
      name: propFavorite2IconUrl
      required: false
      type: TEXT
    - description: (optional) name of Favorite 3
      label: (optional) Favorite 3
      name: propFavorite3
      required: false
      type: TEXT
    - description: (optional) name of Favorite 3 Icon
      label: (optional) Favorite 3 Icon
      name: propFavorite3IconUrl
      required: false
      type: TEXT
    - description: (optional) name of Favorite 4
      label: (optional) Favorite 4
      name: propFavorite4
      required: false
      type: TEXT
    - description: (optional) name of Favorite 4 Icon
      label: (optional) Favorite 4 Icon
      name: propFavorite4IconUrl
      required: false
      type: TEXT
    - context: item
      description: (optional) item to control the playlist
      label: (optional) item playlist
      name: itemPlaylist
      required: false
      type: TEXT
    - description: (optional) name of playlist 1
      label: (optional) playlist 1
      name: propPlaylist1
      required: false
      type: TEXT
    - description: (optional) name of playlist 1 Icon
      label: (optional) playlist 1 Icon
      name: propPlaylist1IconUrl
      required: false
      type: TEXT
    - description: (optional) name of playlist 2
      label: (optional) playlist 2
      name: propPlaylist2
      required: false
      type: TEXT
    - description: (optional) name of playlist 2 Icon
      label: (optional) playlist 2 Icon
      name: propPlaylist2IconUrl
      required: false
      type: TEXT
    - description: (optional) name of playlist 3
      label: (optional) playlist 3
      name: propPlaylist3
      required: false
      type: TEXT
    - description: (optional) name of playlist 3 Icon
      label: (optional) playlist 3 Icon
      name: propPlaylist3IconUrl
      required: false
      type: TEXT
    - description: (optional) name of playlist 4
      label: (optional) playlist 4
      name: propPlaylist4
      required: false
      type: TEXT
    - description: (optional) name of playlist 4 Icon
      label: (optional) playlist 4 Icon
      name: propPlaylist4IconUrl
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Dec 9, 2021, 12:44:31 PM
component: f7-card
config:
  title: =props.propWidgetTitle
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-row
            slots:
              default:
                - component: Label
                  config:
                    text: "Title: "
                    class:
                      - display-flex
          - component: f7-row
            config:
              style:
                position: relative
                top: -10px
                height: 30px
              class:
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    text: =items[props.itemTitle].displayState || items[props.itemTitle].state
                    style:
                      fontSize: 28px
                      white-space: nowrap
                      overflow: hidden
          - component: f7-row
            config:
              visible: "=(props.itemAlbum) ? true : false"
            slots:
              default:
                - component: Label
                  config:
                    text: "Album: "
                    class:
                      - display-flex
          - component: f7-row
            config:
              visible: "=(props.itemAlbum) ? true : false"
              style:
                position: relative
                top: -10px
                height: 30px
              class:
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    text: =items[props.itemAlbum].displayState || items[props.itemAlbum].state
                    style:
                      fontSize: 28px
                      white-space: nowrap
                      overflow: hidden
          - component: f7-row
            config:
              visible: "=(props.itemArtist) ? true : false"
            slots:
              default:
                - component: Label
                  config:
                    text: "Artist: "
                    class:
                      - display-flex
          - component: f7-row
            config:
              visible: "=(props.itemArtist) ? true : false"
              style:
                position: relative
                top: -10px
                height: 30px
              class:
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    text: =items[props.itemArtist].displayState || items[props.itemArtist].state
                    style:
                      fontSize: 28px
                      white-space: nowrap
                      overflow: hidden
          - component: f7-row
            config:
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: oh-image
                  config:
                    visible: '=( (props.itemCover) && items[props.itemCover].state !== "UNDEF") ? true : false'
                    item: =props.itemCover
                    style:
                      width: 70%
                - component: oh-image
                  config:
                    visible: '=(!(props.itemCover) || items[props.itemCover].state === "UNDEF") ? true : false'
                    url: /static/sonos_logo.jpg
                    style:
                      width: 70%
          - component: f7-row
            config:
              visible: "=(props.itemPlayer) ? true : false"
              class:
                - justify-content-space-around
                - display-flex
                - align-items-center
                - align-content-stretch
                - margin-top
              style:
                position: relative
                top: +5px
            slots:
              default:
                - component: f7-icon
                  config:
                    f7: '=(props.itemShuffle) ? "shuffle" : ""'
                    size: 20
                    color: '=(items[props.itemShuffle].state === "ON") ? "green" : ""'
                    style:
                      position: relative
                      left: +7%
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: command
                          actionItem: =props.itemShuffle
                          actionCommand: '=(items[props.itemShuffle].state !== "ON") ? "ON" : "OFF"'
                          style:
                            position: absolute
                            width: 100%
                            height: 100%
                            top: 0px
                - component: oh-player-item
                  config:
                    style:
                      width: 150px
                    item: =props.itemPlayer
                    class:
                      - display-flex
                      - margin-
                      - align-content-stretch
                      - align-items-center
                      - justify-content-space-around
                - component: f7-icon
                  config:
                    f7: '=(props.itemRepeat) ? (items[props.itemRepeat].state === "ALL") ? "repeat" : (items[props.itemRepeat].state === "ONE") ? "repeat_1" : "repeat" : ""'
                    size: 20
                    color: '=(items[props.itemRepeat].state === "ALL") ? "green" : (items[props.itemRepeat].state === "ONE") ? "green" : ""'
                    style:
                      position: relative
                      left: -8%
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: command
                          actionItem: =props.itemRepeat
                          actionCommand: '=(items[props.itemRepeat].state === "ALL") ? "ONE" : (items[props.itemRepeat].state === "ONE") ? "OFF": "ALL"'
                          style:
                            position: absolute
                            width: 100%
                            height: 100%
                            top: 0px
          - component: f7-row
            config:
              visible: "=(props.itemVolume) ? true : false"
              class:
                - justify-content-space-around
                - display-flex
                - align-items-center
                - align-content-stretch
            slots:
              default:
                - component: f7-card
                  config:
                    noShadow: true
                    class: margin display-flex align-items-center
                    style:
                      fontSize: 20px
                      min-width: calc(100% - 20px)
                  slots:
                    default:
                      - component: oh-slider
                        config:
                          label: true
                          scale: true
                          style:
                            height: +40px
                            width: calc(100% - 35px)
                          min: 0
                          item: =props.itemVolume
                          class:
                            - display-flex
                            - margin-horizontal
                            - align-content-stretch
                            - align-items-center
                            - justify-content-space-around
                      - component: f7-button
                        config:
                          class: '=(props.propZoneArray) ? "" : "display-none"'
                          style:
                            position: absolute
                            height: 100%
                            width: 100%
                            top: 0px
                          popoverOpen: .popoverVolume
                        slots:
                          default:
                            - component: f7-popover
                              config:
                                class: popoverVolume
                                style:
                                  min-width: 350px
                              slots:
                                default:
                                  - component: oh-repeater
                                    config:
                                      for: zoneVolume
                                      in: =props.propZoneArray.split("]")
                                      containerClasses:
                                        - display-flex
                                        - flex-direction-column
                                    slots:
                                      default:
                                        - component: f7-card
                                          config:
                                            class: '=(loop.zoneVolume.split("\"")[1] && items[loop.zoneVolume.split("\"")[7]].state === items[props.itemCoordinator].state) ? "display-flex flex-direction-row justify-content-flex-start align-items-center" : "display-none"'
                                            style:
                                              height: 40px
                                          slots:
                                            default:
                                              - component: Label
                                                config:
                                                  style:
                                                    fontSize: 20px
                                                  class:
                                                    - margin-left
                                                  text: =(loop.zoneVolume.split("\"")[1])
                                              - component: oh-slider
                                                config:
                                                  label: true
                                                  style:
                                                    height: +40px
                                                    width: calc(100% - 40%)
                                                  min: 0
                                                  item: =(loop.zoneVolume.split("\"")[5])
                                                  class:
                                                    - display-flex
                                                    - margin
                                                    - align-content-stretch
                                                    - align-items-center
                      - component: f7-icon
                        config:
                          visible: "=(props.itemMute) ? true : false"
                          f7: '=(items[props.itemMute].state !== "ON") ? "speaker_3" : "speaker_slash"'
                          color: '=(items[props.itemMute].state === "ON") ? "green" : ""'
                          class: margin-horizontal margin
                          size: 30
                        slots:
                          default:
                            - component: oh-button
                              config:
                                action: command
                                actionItem: =props.itemMute
                                actionCommand: '=(items[props.itemMute].state !== "ON") ? "ON" : "OFF"'
                                style:
                                  position: absolute
                                  width: 100%
                                  height: 100%
                                  top: 0px
          - component: f7-row
            config:
              visible: "=(props.itemBase || props.itemTreble) ? true : false"
              class:
                - justify-content-space-around
                - display-flex
                - align-items-center
                - align-content-stretch
            slots:
              default:
                - component: f7-card
                  config:
                    noShadow: true
                    class: margin display-flex align-items-center
                    style:
                      fontSize: 20px
                      min-width: calc(100% - 20px)
                  slots:
                    default:
                      - component: oh-slider
                        config:
                          visible: "=(props.itemTreble) ? true : false"
                          label: true
                          scale: true
                          min: -10
                          max: 10
                          scaleSteps: 10
                          scaleSubSteps: 1
                          style:
                            height: +40px
                            width: calc(100% - 35px)
                          item: =props.itemTreble
                          class:
                            - display-flex
                            - margin-horizontal
                            - align-content-stretch
                            - align-items-center
                            - justify-content-space-around
                      - component: oh-slider
                        config:
                          visible: "=(props.itemBase) ? true : false"
                          label: true
                          scale: true
                          min: -10
                          max: 10
                          scaleSteps: 10
                          scaleSubSteps: 1
                          style:
                            height: +40px
                            width: calc(100% - 35px)
                          item: =props.itemBase
                          class:
                            - display-flex
                            - margin-horizontal
                            - align-content-stretch
                            - align-items-center
                            - justify-content-space-around
                      - component: f7-icon
                        config:
                          visible: "=(props.itemLoudness) ? true : false"
                          f7: '=(items[props.itemLoudness].state !== "ON") ? "speaker" : "speaker_3_fill"'
                          color: '=(items[props.itemLoudness].state === "ON") ? "green" : ""'
                          class: margin-horizontal margin
                          size: 30
                        slots:
                          default:
                            - component: oh-button
                              config:
                                action: command
                                actionItem: =props.itemLoudness
                                actionCommand: '=(items[props.itemLoudness].state !== "ON") ? "ON" : "OFF"'
                                style:
                                  position: absolute
                                  width: 100%
                                  height: 100%
                                  top: 0px
          - component: f7-row
            config:
              visible: "=(props.itemTuneinStation) ? true : false"
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation1 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation1 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation1
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation2 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation2 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation2
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation4 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation3 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation3
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsTuneinStation4 !== "UNDEF") ? true : false'
                          url: =('https://cdn-radiotime-logos.tunein.com/s' + props.propTuneinStation4 + 'q.png')
                          action: command
                          actionItem: =props.itemTuneinStation
                          actionCommand: =props.propTuneinStation4
                          style:
                            width: 80%
          - component: f7-row
            config:
              visible: "=(props.itemFavorite) ? true : false"
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite1Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          url: =props.propFavorite1IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite1
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite2Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          url: =props.propFavorite2IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite2
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite3Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsFavorite4Url !== "UNDEF") ? true : false'
                          url: =props.propFavorite3IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite3
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    visible: '=(props.propsFavorite4Url !== "UNDEF") ? true : false'
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsFavorite4Url !== "UNDEF") ? true : false'
                          url: =props.propFavorite4IconUrl
                          action: command
                          actionItem: =props.itemFavorite
                          actionCommand: =props.propFavorite4
                          style:
                            width: 80%
          - component: f7-row
            config:
              visible: "=(props.itemPlaylist) ? true : false"
              class:
                - margin-vertical
                - justify-content-center
            slots:
              default:
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist1Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist1IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist1
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist2Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist2IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist2
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist3Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist3IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist3
                          style:
                            width: 80%
                - component: f7-col
                  config:
                    width: auto
                  slots:
                    default:
                      - component: oh-image
                        config:
                          visible: '=(props.propsPlaylist4Url !== "UNDEF") ? true : false'
                          url: =props.propPlaylist4IconUrl
                          action: command
                          actionItem: =props.itemPlaylist
                          actionCommand: =props.propPlaylist4
                          style:
                            width: 80%
          - component: f7-row
            config:
              class: '=(props.propZoneName && props.itemPlayer) ? "justify-content-space-around align-items-center align-content-stretch" : "display-none"'
              style:
                position: relative
                top: -26px
                height: 50px
            slots:
              default:
                - component: f7-card
                  config:
                    noShadow: true
                    class: display-flex align-items-center
                    style:
                      fontSize: 20px
                      min-width: 130px
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          f7: hifispeaker
                          size: 30
                          class: margin
                      - component: Label
                        config:
                          class: margin-right
                          text: =props.propZoneName
                          style:
                            fontSize: 20px
                      - component: f7-icon
                        config:
                          f7: '=(items[props.itemPlayer].state === "PLAY") ? "chart_bar_alt_fill" : ""'
                          class: margin-right
                          size: 20
                      - component: f7-button
                        config:
                          class: '=(props.propZoneArray) ? "" : "display-none"'
                          style:
                            position: absolute
                            height: 100%
                            width: 100%
                            top: 0px
                          popoverOpen: .popoverPlayer
                        slots:
                          default:
                            - component: f7-popover
                              config:
                                class: popoverPlayer
                                style:
                                  min-width: 280px
                              slots:
                                default:
                                  - component: oh-repeater
                                    config:
                                      for: zoneSpeaker
                                      in: =props.propZoneArray.split("]")
                                      containerClasses:
                                        - display-flex
                                        - flex-direction-column
                                    slots:
                                      default:
                                        - component: f7-card
                                          config:
                                            class: '=(loop.zoneSpeaker.split("\"")[1]) ? "display-flex flex-direction-row align-items-center" : "display-none"'
                                            style:
                                              height: 40px
                                          slots:
                                            default:
                                              - component: oh-button
                                                config:
                                                  style:
                                                    position: absolute
                                                    top: 0px
                                                    width: 100%
                                                    height: 100%
                                                  action: command
                                                  actionItem: '=(items[loop.zoneSpeaker.split("\"")[7]].state === items[props.itemCoordinator].state) ? ("Sonos_" + (loop.zoneSpeaker.split("\"")[1]) + "_Standalone") : props.itemAdd'
                                                  actionCommand: '=(items[loop.zoneSpeaker.split("\"")[7]].state === items[props.itemCoordinator].state) ? "ON" : (loop.zoneSpeaker.split("\"")[1])'
                                              - component: f7-col
                                                config:
                                                  class: margin display-flex flex-direction-row align-items-center
                                                slots:
                                                  default:
                                                    - component: f7-icon
                                                      config:
                                                        f7: '=(items[loop.zoneSpeaker.split("\"")[7]].state === items[props.itemCoordinator].state) ? "checkmark_alt_circle_fill" : "circle"'
                                                    - component: Label
                                                      config:
                                                        class: margin-left
                                                        text: =loop.zoneSpeaker.split("\"")[1]
                                                        style:
                                                          fontSize: 20px
                                              - component: f7-col
                                                config:
                                                  class: margin align-items-center
                                                slots:
                                                  default:
                                                    - component: f7-icon
                                                      config:
                                                        f7: '=(items[loop.zoneSpeaker.split("\"")[3]].state === "PLAY") ? "chart_bar_alt_fill" : ""'

Hi Folks hope I can get some advise;

@buschif4

So from the example for the speaker array mine looks like this, added in the settings in the widget

[“Sonos Keuken”; “Sonos_Keuken_Player”; “Sonos_Keuken_Volume”; “Sonos_Keuken_Coordinator”][“Sonos Slaapkamer”; “Sonos_Slaapkamer_player”; “Sonos_Slaapkamer_Volume”; “Sonos_Slaapkamer_Coordinator”]

But it ends up in the YAML as like this;


  propZoneArray: "[“Sonos_Keuken”; “Sonos_Keuken_Player”; “Sonos_Keuken_Volume”;
    “Sonos_Keuken_Coordinator”][“Sonos_Slaapkamer”; “Sonos_Slaapkamer_player”;
    “Sonos_Slaapkamer_Volume”; “Sonos_Slaapkamer_Coordinator”]"

As I am not able to get the multizone working I read it needs to be in single ’ ’
But whatever I tried, every time it is being saved it is changed to double quote.

Can this also be the WARN " Attempting to send a state update of an item which doesn't exist: undefined."

Screenshot from 2023-02-01 16-53-03

Adding the array in the widget and saving it;
Screenshot from 2023-02-01 16-55-08

Checking the YAML it shows as following;
Screenshot from 2023-02-01 16-56-34

Modifying it to single in the YAML
Screenshot from 2023-02-01 16-57-49

Saving it and it is back with double as saving it from the GUI

And would be great if you can advise me as this is the last part from my migration from OH2 to OH3 and it drives me mad

Thanks already,

Aldo