[OH3] Main UI - main_widget - part 1 - The main_widget [3.3.0;3.4.9)

The “main_widget” project is a series of widgets to create a new mobile view for controlling your openHAB installation. For full functionality, you will need to install all widgets listed in the development thread.

Installation:

  • Add the non semantic tag “Floor” to all your floors and if you like, also add the widgetOrderIndex to them
  • Add the name of the floor group 8e.g. gGroundfloor) as a new non semantic tag to each room in that particular floor
  • If you want a specific ordering in the floors and/or rooms menu, please add the widgetOrderIndex as metadata to your items in the model.
  • Install all needed widgets for this projekt from the marketplace.
  • Create an new layout page in openHAB MainUI
  • Enter the code tab for the new page and paste the following code
config:
  label: openPage
  sidebar: true
  hideNavbar: true
  showFullscreenIcon: false
  hideSidebarIcon: true
  style:
    --f7-block-padding-horizontal: 0px
    --f7-navbar-height: 0
blocks:
  - component: oh-block
    config:
      stylesheet: |
        .block:first-child{
          margin-top: 15px;
          }
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config: {}
                slots:
                  default:
                    - component: widget:main_widget
                      config:
                        locationTitle:
                        scenesGroup:
                        securityGroup:
                        securityMode:
                        referencePIN:
masonry: null
grid: []

configure the main_widget on your new page with the missing information (some items/groups need to be definded.

Screenshots


Changelog

Version 0.4

Version 0.3

  • fixed top and bottom spacing [@Nic0205]
  • changed bottom tabs from button to oh link for further improvements [@Nic0205]
  • refactored repeater usage to remove need of additional tags [@hmerk]
  • code splitting, moved informationa middle part to separate widgets. [@hmerk]

Version 0.3

  • fixed menu sorting and coloring
  • changed margins to better use screen space

Version 0.2

  • added menu entry sorting for floors and rooms [@Nic0205]
  • new config options for scene and security group and security mode [@hmerk]

Version 0.1

  • initial release

Resources

uid: main_widget
tags: []
props:
  parameters:
    - description: Set default color for Text
      label: Text color
      name: textColor
      required: false
      type: TEXT
    - defaultValue: RGB(96, 96, 96)
      description: Set default color for Text
      label: Bottom-Navbar-Color
      name: bnavColor
      required: false
      type: TEXT
    - defaultValue: Somewhere
      description: Name for your weather location
      label: Weather Location
      name: locationTitle
      required: false
      type: TEXT
    - context: item
      description: Name of scenes group item
      label: Scenes Group
      name: scenesGroup
      required: false
      type: TEXT
    - description: Hide Security menu
      label: hide
      name: hideSecurity
      required: false
      type: BOOLEAN
      groupName: security
  parameterGroups:
    - name: security
      label: Security Configuration Parameters
component: f7-block
config:
  style:
    --f7-button-text-color: "#8c8c8c"
    --menu-text-color: '= (!props.textColor) ? (themeOptions.dark=="light")? black : white : props.textColor'
    --opmw-menu-text-color: =(themeOptions.dark=="light")?("#8C8C8C"):("#848484")
    background: =(themeOptions.dark=="light") ? ("white"):("black")
    display: flex
    flex-direction: column
    height: calc(100vh - var(--f7-toolbar-height) - var(--f7-safe-area-bottom) - var(--f7-safe-area-top))
    justify-content: space-between
    margin: 0
    padding: 0
    width: 100%
  stylesheet: >
    .selected_menu_item {
      color: var(--menu-text-color);
      text-decoration-color: #F8BB00 !important;
      text-decoration: underline;
      text-underline-offset: 2px;
      font-weight: bold;
    } 

    .unselected_menu_item {
      color: #8C8C8C;
      font-weight: 300;
    }

    .selected_bottom_navbar_item {
     color: white;
     
     font-size: 12px;
     height: auto;
     --f7-button-bg-color: transparent;  
     display: flex;
     flex-direction: column;
     align-items: center;
     padding-top: 1%;
     padding-bottom: 1%;

    }  

    .unselected_bottom_navbar_item {
     
     color: #8c8c8c;
     font-size: 12px;
     height: auto;
     --f7-button-bg-color: transparent 
          display: flex;
     flex-direction: column;
     padding-top: 2%;
     padding-bottom: 2%;
    } 
slots:
  default:
    - component: f7-block
      config:
        style:
          flex: 0 0 auto
          overflow: scroll
      slots:
        default:
          - component: f7-segmented
            config:
              style:
                flex: 1 1 auto
                gap: 10px
                justify-content: center
                margin-left: 2%
                margin-right: 2%
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: baseMenu
                    fragment: true
                    in:
                      - name: Home
                      - name: Floors
                      - name: Rooms
                    map: loop.baseMenu.name
                    sourceType: array
                  slots:
                    default:
                      - component: oh-button
                        config:
                          action: variable
                          actionVariable: objVar
                          actionVariableValue:
                            selectSection: ="SECTION" + loop.baseMenu_idx
                          class: '=vars.objVar.selectSection=="SECTION" + loop.baseMenu_idx ? "selected_menu_item" : "unselected_menu_item"'
                          large: true
                          style:
                            flex: 0 1 auto
                            font-size: 24px
                            font-weight: 200
                            width: auto
                          text: =loop.baseMenu
          - component: f7-row
            config:
              style:
                align-items: center
                display: flex
                flex-direction: row
                flex-wrap: nowrap
                height: 2em
                justify-content: space-between
                width: 100%
              visible: false
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariable: buttonIndexHome
                    actionVariableValue: =(vars.buttonIndexHome || 0) + 1
                    iconF7: chevron_left
                    style:
                      color: "#F8BB00"
                      flex: 0 0 auto
                      height: 2em
                - component: oh-repeater
                  config:
                    fetchMetadata: metadata,semantics,widgetOrder
                    filter: (loop.menuArray.metadata) && (loop.menuArray.metadata.semantics.value).includes("Floor")
                    for: menuArray
                    fragment: true
                    itemTags: ","
                    map: loop.menuArray_source
                    sourceType: itemsWithTags
                  slots:
                    default:
                      - component: f7-row
                        config:
                          style:
                            display: flex
                            height: 2em
                            justify-content: center
                            overflow: hidden
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                filter: loop.menuArray_idx == 0
                                for: menuButtonHome
                                fragment: true
                                in: =loop.menuArray
                                map: ((loop.menuButtonHome.metadata && loop.menuButtonHome.metadata.widgetOrder && loop.menuButtonHome.metadata.widgetOrder.value) || 0).toString().padStart(3,'0') + '&' + loop.menuButtonHome_idx
                              slots:
                                default:
                                  - component: oh-button
                                    config:
                                      action: variable
                                      actionVariable: objVar
                                      actionVariableValue:
                                        floor: =loop.menuArray[loop.menuButtonHome_source.sort()[loop.menuButtonHome_idx].split('&')[1]].name
                                        selectSection: = vars.objVar.selectSection
                                      style:
                                        flex: 0 0 auto
                                        height: 2em
                                        order: =(((vars.buttonIndexHome || 0) % loop.menuButtonHome_source.length) + loop.menuButtonHome_source.length + loop.menuButtonHome_idx) % loop.menuButtonHome_source.length
                                      text: =loop.menuArray[loop.menuButtonHome_source.sort()[loop.menuButtonHome_idx].split('&')[1]].label
                - component: oh-button
                  config:
                    action: variable
                    actionVariable: buttonIndexHome
                    actionVariableValue: =(vars.buttonIndexHome || 0) - 1
                    iconF7: chevron_right
                    style:
                      color: "#F8BB00"
                      flex: 0 0 auto
                      height: 2em
          - component: f7-row
            config:
              style:
                align-items: center
                display: flex
                flex-direction: row
                flex-wrap: nowrap
                height: 2em
                justify-content: center
                width: 100%
              visible: '=vars.objVar ? (vars.objVar.selectSection=="SECTION1") ? true : false : false'
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariable: buttonIndexFloor
                    actionVariableValue: =(vars.buttonIndexFloor || 0) + 1
                    iconF7: chevron_left
                    style:
                      color: "#F8BB00"
                      flex: 0 0 auto
                      height: 2em
                - component: oh-repeater
                  config:
                    fetchMetadata: metadata,semantics,widgetOrder
                    filter: (loop.menuArray.metadata) && (loop.menuArray.metadata.semantics.value).includes("Floor")
                    for: menuArray
                    fragment: true
                    itemTags: ","
                    map: loop.menuArray_source
                    sourceType: itemsWithTags
                  slots:
                    default:
                      - component: f7-row
                        config:
                          style:
                            display: flex
                            height: 2em
                            justify-content: center
                            overflow: hidden
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                filter: loop.menuArray_idx == 0
                                for: menuButtonFloor
                                fragment: true
                                in: =loop.menuArray
                                map: ((loop.menuButtonFloor.metadata && loop.menuButtonFloor.metadata.widgetOrder && loop.menuButtonFloor.metadata.widgetOrder.value) || 0).toString().padStart(3,'0') + '&' + loop.menuButtonFloor_idx
                              slots:
                                default:
                                  - component: oh-button
                                    config:
                                      action: variable
                                      actionVariable: objVar
                                      actionVariableValue:
                                        floor: =loop.menuArray[loop.menuButtonFloor_source.sort()[loop.menuButtonFloor_idx].split('&')[1]].name
                                        selectSection: SECTION2
                                      class: '=(vars.objVar.floor ==(loop.menuArray[loop.menuButtonFloor_source.sort()[loop.menuButtonFloor_idx].split("&")[1]].name)) ? "selected_menu_item" : "unselected_menu_item"'
                                      style:
                                        flex: 0 0 auto
                                        height: 2em
                                        order: =(((vars.buttonIndexFloor || 0) % loop.menuButtonFloor_source.length) + loop.menuButtonFloor_source.length + loop.menuButtonFloor_idx) % loop.menuButtonFloor_source.length
                                        text-underline-offset: 4px
                                      text: =loop.menuArray[loop.menuButtonFloor_source.sort()[loop.menuButtonFloor_idx].split('&')[1]].label
                - component: oh-button
                  config:
                    action: variable
                    actionVariable: buttonIndexFloor
                    actionVariableValue: =(vars.buttonIndexFloor || 0) - 1
                    iconF7: chevron_right
                    style:
                      color: "#F8BB00"
                      flex: 0 0 auto
                      height: 2em
          - component: f7-row
            config:
              style:
                align-items: center
                display: flex
                flex-direction: row
                flex-wrap: nowrap
                height: 2em
                justify-content: center
                width: 100%
              visible: '=vars.objVar ? (vars.objVar.selectSection=="SECTION2") ? true : false : false'
            slots:
              default:
                - component: oh-button
                  config:
                    action: variable
                    actionVariable: buttonIndexRoom
                    actionVariableValue: =(vars.buttonIndexRoom || 0) + 1
                    iconF7: chevron_left
                    style:
                      color: "#F8BB00"
                      flex: 0 0 auto
                      height: 2em
                - component: oh-repeater
                  config:
                    fetchMetadata: metadata,semantics,widgetOrder
                    filter: (loop.menuArrayRoom.metadata) && (loop.menuArrayRoom.metadata.semantics.value).includes("Room")
                    for: menuArrayRoom
                    fragment: true
                    groupItem: =vars.objVar.floor
                    map: loop.menuArrayRoom_source
                    sourceType: itemsInGroup
                    visible: "=!vars.objVar ? false : (vars.objVar.selectSection==SECTION1) ? false : true"
                  slots:
                    default:
                      - component: f7-row
                        config:
                          style:
                            display: flex
                            height: 2em
                            justify-content: center
                            overflow: hidden
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                filter: loop.menuArrayRoom_idx == 0
                                for: menuButtonRoom
                                fragment: true
                                in: =loop.menuArrayRoom
                                map: ((loop.menuButtonRoom.metadata && loop.menuButtonRoom.metadata.widgetOrder && loop.menuButtonRoom.metadata.widgetOrder.value) || 0).toString().padStart(3,'0') + '&' + loop.menuButtonRoom_idx
                              slots:
                                default:
                                  - component: oh-button
                                    config:
                                      action: variable
                                      actionVariable: objVar
                                      actionVariableValue:
                                        floor: =vars.objVar.floor
                                        room: =loop.menuArrayRoom[loop.menuButtonRoom_source.sort()[loop.menuButtonRoom_idx].split('&')[1]].name
                                        selectSection: =vars.objVar.selectSection
                                      class: '=(vars.objVar.room ==(loop.menuArrayRoom[loop.menuButtonRoom_source.sort()[loop.menuButtonRoom_idx].split("&")[1]].name)) ? "selected_menu_item" : "unselected_menu_item"'
                                      style:
                                        flex: 0 0 auto
                                        height: 2em
                                        order: =(((vars.buttonIndexRoom || 0) % loop.menuButtonRoom_source.length) + loop.menuButtonRoom_source.length + loop.menuButtonRoom_idx) % loop.menuButtonRoom_source.length
                                        text-underline-offset: 4px
                                      text: =loop.menuArrayRoom[loop.menuButtonRoom_source.sort()[loop.menuButtonRoom_idx].split('&')[1]].label
                - component: oh-repeater
                  config:
                    fetchMetadata: metadata,semantics,widgetOrder
                    filter: (loop.menuArrayRoom.metadata) && (loop.menuArrayRoom.metadata.semantics.value).includes("Room") && (loop.menuArrayRoom.metadata.semantics.config.hasLocation == vars.objVar.floor)
                    for: menuArrayRoom
                    fragment: true
                    itemTags: ","
                    map: loop.menuArrayRoom_source
                    sourceType: itemsWithTags
                    visible: "=!vars.objVar ? false : (vars.objVar.selectSection==SECTION1) ? false : true"
                  slots:
                    default:
                      - component: f7-row
                        config:
                          style:
                            display: flex
                            height: 2em
                            justify-content: center
                            overflow: hidden
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                filter: loop.menuArrayRoom_idx == 0
                                for: menuButtonRoom
                                fragment: true
                                in: =loop.menuArrayRoom
                                map: ((loop.menuButtonRoom.metadata && loop.menuButtonRoom.metadata.widgetOrder && loop.menuButtonRoom.metadata.widgetOrder.value) || 0).toString().padStart(3,'0') + '&' + loop.menuButtonRoom_idx
                              slots:
                                default:
                                  - component: oh-button
                                    config:
                                      action: variable
                                      actionVariable: objVar
                                      actionVariableValue:
                                        floor: =vars.objVar.floor
                                        room: =loop.menuArrayRoom[loop.menuButtonRoom_source.sort()[loop.menuButtonRoom_idx].split('&')[1]].name
                                        selectSection: =vars.objVar.selectSection
                                      class: '=(vars.objVar.room ==(loop.menuArrayRoom[loop.menuButtonRoom_source.sort()[loop.menuButtonRoom_idx].split("&")[1]].name)) ? "selected_menu_item" : "unselected_menu_item"'
                                      style:
                                        flex: 0 0 auto
                                        height: 2em
                                        order: =(((vars.buttonIndexRoom || 0) % loop.menuButtonRoom_source.length) + loop.menuButtonRoom_source.length + loop.menuButtonRoom_idx) % loop.menuButtonRoom_source.length
                                        text-underline-offset: 4px
                                      text: =loop.menuArrayRoom[loop.menuButtonRoom_source.sort()[loop.menuButtonRoom_idx].split('&')[1]].label
                - component: oh-button
                  config:
                    action: variable
                    actionVariable: buttonIndexRoom
                    actionVariableValue: =(vars.buttonIndexRoom || 0) - 1
                    iconF7: chevron_right
                    style:
                      color: "#F8BB00"
                      flex: 0 0 auto
                      height: 2em
          - component: f7-row
            config:
              style:
                align-items: center
                display: flex
                flex-direction: row
                flex-wrap: nowrap
                height: 2em
                justify-content: center
                width: 100%
              visible: "=!vars.objVar ? false : !vars.objVar.floor ? false : true"
            slots:
              default:
                - component: oh-repeater
                  config:
                    fetchMetadata: semantics,metadata,widgetOrder
                    filter: loop.floorItem.name==vars.objVar.floor
                    for: floorItem
                    itemTags: ","
                    sourceType: itemsWithTags
                  slots:
                    default:
                      - component: f7-chip
                        config:
                          style:
                            background: "#F8BB00"
                          text: =loop.floorItem.label
    - component: widget:main_widget_Home_Card
      config:
        locationTitle: =props.locationTitle
        referencePIN: =props.referencePIN
        scenesGroup: =props.scenesGroup
        securityGroup: =props.securityGroup
        securityMode: =props.securityMode
    - component: widget:main_widget_FloorsAndRooms
    - component: f7-block
      config:
        style:
          background: =props.bnavColor
          border-radius: 0px 0px 10px 10px
          flex: 0 0 auto
          margin-bottom: -4em
          overflow: scroll
        visible: '=vars.objVar ? (vars.objVar.selectSection=="SECTION0") ? true : false : false'
      slots:
        default:
          - component: f7-segmented
            config:
              style:
                display: flex
                flex-direction: row
                justify-content: space-around
            slots:
              default:
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Security
                    badgeColor: '=(vars.objVar && (vars.objVar.selectThing=="Security")) ? "orange" : "red"'
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Security")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    icon-f7: shield_fill
                    iconBadge: =(Number(items.gDoorsOpen.state)+Number(items.gWindowsOpen.state)+Number(items.motionDetected.state))
                    text: Security
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Scenes
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Scenes")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    icon-f7: rectangle_on_rectangle_angled
                    text: Scenes
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Appliances
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Weather")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    iconMaterial: power
                    text: Appliances
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Energy
                    badgeColor: green
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Energy")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    icon-f7: bolt_fill
                    iconBadge: ""
                    text: Energy
    - component: f7-block
      config:
        style:
          background: =props.bnavColor
          border-radius: 0px 0px 10px 10px
          flex: 0 0 auto
          margin-bottom: -4em
          overflow: scroll
        visible: '=vars.objVar ? (vars.objVar.selectSection=="SECTION0") ? false : true : false'
      slots:
        default:
          - component: f7-segmented
            config:
              style:
                display: flex
                flex-direction: row
                justify-content: space-around
            slots:
              default:
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Lights
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Lights")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    icon-f7: lightbulb_fill
                    text: Lights
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Rollers
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Rollers")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    icon-f7: archivebox
                    text: Shades
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Climate
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Climate")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    icon-f7: snow
                    text: Climate
                - component: oh-link
                  config:
                    action: variable
                    actionVariable: objVar
                    actionVariableValue:
                      floor: =vars.objVar.floor
                      room: =vars.objVar.room
                      selectSection: =vars.objVar.selectSection
                      selectThing: Appliances
                    class: '=(vars.objVar && (vars.objVar.selectThing=="Appliances")) ? "selected_bottom_navbar_item" : "unselected_bottom_navbar_item"'
                    iconMaterial: power
                    text: Appliances
2 Likes