OH3 my layouts

Just thought will share my layouts that i managed to create in OH3.
First one is for an old IPAD in an always on mode. It displays the status of a few things including on top row, the air quality outside (which in my area is quite bad during this time of the year) - these are custom widgets. On second and third row, cell widgets to display status of smarthome devices. The ones with the elipses can expand to display additional controls. Each cell widget has an action associated such as either power on/ off for TV, computer, Air purifiers, Geysers (boilers), or can analyze in a chart.
On last row, weather glimpse. The last widget was inspired by this (UI Widget: Weather - #22 by RGroll) thanks to @RGroll also for the first one

These are the location and equipment tabs.

9 Likes

I realy like your layout - especially the coloured room- & equipment-cards with the images. Great work and happy to see that the weather-widgets fits your needs. :slight_smile:

Thank you. Its a tricky one. Please do share suggestions to improve this.
The collapsed card is basically an f7-card with width dependent on the window size.
So what is ending up happening is that in layouts greater than 768px window size, the collapsed card size is at limited at 340px, so the glance slot can be placed accordingly. But with smaller sizes, like on phone, the collapsed card is 100% of the width, hence the with can be anywhere between 0px and 768px. So its difficult to always place the image on the right edge of the collapsed card on smaller screens.


here is the code

     Hall:
        - component: oh-location-card
          config:
            invertText: true
          slots:
            glance:
              - component: f7-block
                config:
                  style:
                    position: absolute
                    left: 0px
                    top: 15px
                    width: 100%
                    height: 80%
                    padding-top: 0px
                    margin-top: 0px
                    background-image: url(https://www.flaticon.com/svg/static/icons/svg/3939/3939300.svg)
                    background-size: contain
                    background-repeat: no-repeat
                    background-position: center
                    opacity: 70%
1 Like

I never heard/read about that ‘glance’ slot for f7-cards? What exactly is it doing? Is it a replacement for the default slot in location-cards?

From a pure css-perspective I would probably align the background-image with an offset at the right like this:

background-position: right -80px center

to prevent the image from shrinking you could assign a fixed background-size - but it will work without it, I think, as phone-screens are not that small anymore. :slight_smile:

I’ll experiment with it a bit more if I find time to set-up my semantic model.

Read @ysc notes on M4 release. It was very well descibed there as a newly introduced feature…

1 Like

Thanks for the info - got it now :slight_smile:

@candiesdoodle IIRC you have another slot, background, specifically for card header backgrounds, the size of which will be the actual width and height of the header, you can therefore use things like width: 100% and position: absolute; right: 10px
Never mind this slot is only found in cells, not model cards. Probably should add it though.

show how you did it?
image

Hi @Olymp

You could archieve this by using the relativeTime plugin from dayjs like this:

=dayjs(items.YourDateTimeItem.state).fromNow()

At least I assume this is how @candiesdoodle has done this.

1 Like

Well done.

I love these widgets and Layout. It just show that I lack a creative part in my brain. It take me ages to do anything artistic.

1 Like

Works!
Thanks, very good. cool!

The constraint with the UI is that values/text/expressions are only updated the first time the page loads, or when a state changes in an already loaded page. Hence just using the dayjs library will result in static relative time. Example, if the last change time stamp is X pm, then the dayjs().fromNow will result in a relative time at the moment the expression is evaluated but will not update it again until the page is reloaded or the last changed timestamp changes due to another event (like associated item state change).
So I created a shadow item which oscillates between null and the last changed timestamp every 1 minute by a rule.
something like this:

value = itemRegistry.getItem(item_name).getState();
events.postUpdate(item_name+'_ForDisplay', null);
events.postUpdate(item_name+'_ForDisplay', value);

so every time the item_name_ForDisplay goes from value to null to value, the dayjs.fromNow() updates it to the relative time to current time :slight_smile: and the effect is that the relative time keeps updating every time

Thanks for the clarification - I like this soloution! Did you make any observations on how much these constant updates influences the performance of the UI?

Not really. i have 3 items that keep refreshing like this but issue on the UI side. The only issue is that during the intermediate null state, the dayjs libary will not calculate the relative time. So the UI displays undefined or something.
I went around that too.
The actual timestamps are like this:
2020-12-26T16:58:45.623+0XXX
Since the objective is to create a shadow item following this timestamp but with a changing state, the triggered script is like this, (triggering every minute):

value = itemRegistry.getItem(item_name).getState();
value1 = value.toString().replace("+",'');
events.postUpdate(item_name+'_ForDisplay', value1);
events.postUpdate(item_name+'_ForDisplay', value);

Removing the + sign from the timestamp has no impact on dayjs calculation, but since the state changed, dayjs calculation is re-triggered. And consequently, no null value is passed to dayjs

1 Like

Could i get the code of your home page widgets. The ones that have your air purifier and computer power and such?

Hi @Christopher_Hemmings
Here you go. sorry for the delay

config:
  label: Home
  sidebar: true
blocks:
  - component: oh-block
    config:
      title: Air Quality
    slots:
      default:
       
  - component: oh-block
    config:
      title: Air Purifiers
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 25
                  large: 35
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        item: Hall_AP_Power
                        header: Hall Air Puifier
                        icon: f7:power
                        action: toggle
                        actionItem: Hall_AP_Power
                        actionCommand: ON
                        actionCommandAlt: OFF
                        expandable: true
                        color: =(items.Hall_AP_Power.state==="ON"?"lightblue":"")
                        stateStyle:
                          fontSize: 37px
                        footer: '="Mode:
                          "+items.AirPurifier_Hall_Mode.state+(items.AirPurifier_Hall_Mode.state==="favorite"?("
                          ("+items.Hall_AP_FavoriteLevel.state+")"):"")'
                        backdrop: true
                        swipeToClose: true
                        actionFeedback: '{ "text":"Done",
                          "closeButton":"true" }'
                      slots:
                        default:
                          - component: f7-card-content
                            config:
                              style:
                                padding: 50px
                                margin-top: 20px
                            slots:
                              default:
                                - component: widget:Airpurifier_widget8
                                  config:
                                    Title: Hall Air Purifier
                                    BGColor: lightblue
                                    Power_item: Hall_AP_Power
                                    Mode_item: AirPurifier_Hall_Mode
                                    Fav_item: Hall_AP_FavoriteLevel
                                    AQI_item: Hall_AQI
                                    Temp_item: Hall_Temperature
                                    Humidity_item: Hall_Humidity
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 25
                  large: 15
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        color: =(items.Hall_AQI.state>140)?"red":""
                        on: true
                        title: AQI
                        expandable: false
                        icon: f7:smoke
                        actionAnalyzerCoordSystem: time
                        action: analyzer
                        actionAnalyzerItems:
                          - Hall_AQI
                        item: Hall_AQI
                        footer: '=("Temp: "+items.Hall_Temperature.displayState+" Rh:
                          "+items.Hall_Humidity.displayState)'
                        stateStyle:
                          fontSize: 37px
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 25
                  large: 35
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        item: Bedroom_AP_Power
                        header: Bedroom AP
                        icon: f7:power
                        footer: '="Mode:
                          "+items.Bedroom_AP_Mode.state+(items.Bedroom_AP_Mode.state==="favorite"?("
                          ("+items.Bedroom_AP_FavoriteLevel.state+")"):"")'
                        action: toggle
                        actionItem: Bedroom_AP_Power
                        actionCommand: ON
                        actionCommandAlt: OFF
                        expandable: true
                        color: =(items.Bedroom_AP_Power.state==="ON"?"green":"")
                        stateStyle:
                          fontSize: 37px
                        backdrop: true
                        swipeToClose: true
                      slots:
                        default:
                          - component: f7-card-content
                            config:
                              style:
                                padding: 50px
                                margin-top: 20px
                            slots:
                              default:
                                - component: widget:Airpurifier_widget8
                                  config:
                                    Title: Bedroom Air Purifier
                                    BGColor: lightgreen
                                    Power_item: Bedroom_AP_Power
                                    Mode_item: Bedroom_AP_Mode
                                    Fav_item: Bedroom_AP_FavoriteLevel
                                    AQI_item: Bedroom_AQI
                                    Temp_item: Bedroom_Temperature
                                    Humidity_item: Bedroom_Humidity
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 25
                  large: 15
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        color: =(items.Bedroom_AQI.state>70)?"red":""
                        on: true
                        action: analyzer
                        actionAnalyzerItems:
                          - Bedroom_AQI
                        item: Bedroom_AQI
                        title: AQI
                        expandable: false
                        icon: f7:smoke
                        footer: '=("Temp: "+items.Bedroom_Temperature.displayState+" Rh:
                          "+items.Bedroom_Humidity.displayState)'
                        actionAnalyzerCoordSystem: time
                        stateStyle:
                          fontSize: 37px
  - component: oh-block
    config:
      title: Others
    slots:
      default:
        - component: oh-grid-row
          config: {}
          slots:
            default:
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 20
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        header: Computer Power
                        footer: '="Last seen: "+(items.Computer_LastSeen_ForDisplay.displayState)'
                        icon: f7:device_desktop
                        stateStyle:
                          fontSize: 40px
                        item: ComputerPower
                        color: =(items.ComputerPower.state=="ON")?"green":""
                        action: toggle
                        actionCommand: ON
                        actionCommandAlt: OFF
                        actionItem: ComputerPower
                        on: =(items.ComputerPower.state=="ON")
                        expandable: false
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 20
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        header: TV Power
                        footer: '="Input: "+(items.RoomTVMode.state)'
                        icon: f7:tv
                        stateStyle:
                          fontSize: 40px
                        color: =(items.RoomTVPower.state=="ON")?"green":""
                        item: RoomTVPower
                        action: toggle
                        actionItem: RoomTVPower
                        actionCommand: ON
                        actionCommandAlt: OFF
                      slots:
                        default:
                          - component: oh-button
                            config:
                              text: FireTV
                              action: command
                              actionItem: =props.Mode_item
                              actionCommand: FireTV
                              outline: true
                              round: true
                              raised: true
                              color: =(items[props.Mode_item].state=="FireTV")?"green":"transparent"
                              style:
                                --f7-button-outline-border-color: green
                                --f7-button-border-width: 1px
                                --f7-button-text-color: black
                                --f7-button-border-radius: 8px
                                min-width: 30%
                                width: 400px
                                --f7-button-height: 70px
                                --f7-button-hover-bg-color: rgba(0, 255, 0, 0.4)
                          - component: oh-button
                            config:
                              text: Computer
                              action: command
                              actionItem: =props.Mode_item
                              actionCommand: Computer
                              outline: true
                              round: true
                              raised: true
                              color: =(items[props.Mode_item].state=="Computer")?"green":"transparent"
                              style:
                                --f7-button-outline-border-color: green
                                --f7-button-border-width: 1px
                                --f7-button-text-color: black
                                --f7-button-border-radius: 8px
                                min-width: 30%
                                margin-top: 20px
                                margin-bottom: 20px
                                --f7-button-width: 400px
                                --f7-button-height: 70px
                                --f7-button-hover-bg-color: rgba(0, 255, 0, 0.4)
                          - component: oh-button
                            config:
                              text: RaspberryPi
                              action: command
                              actionItem: =props.Mode_item
                              actionCommand: RaspberryPi
                              outline: true
                              color: =(items[props.Mode_item].state=="RaspberryPi")?"green":"transparent"
                              round: true
                              raised: true
                              style:
                                --f7-button-outline-border-color: green
                                --f7-button-border-width: 1px
                                --f7-button-text-color: black
                                --f7-button-border-radius: 8px
                                min-width: 30%
                                --f7-button-width: 400px
                                --f7-button-height: 70px
                                --f7-button-hover-bg-color: rgba(0, 255, 0, 0.4)
                                margin-bottom: 20px
                          - component: oh-button
                            config:
                              text: HDMI3
                              action: command
                              actionItem: =props.Mode_item
                              actionCommand: HDMI3
                              outline: true
                              color: =(items[props.Mode_item].state=="HDMI3")?"green":"transparent"
                              round: true
                              raised: true
                              style:
                                --f7-button-outline-border-color: green
                                --f7-button-border-width: 1px
                                --f7-button-text-color: black
                                --f7-button-border-radius: 8px
                                min-width: 30%
                                --f7-button-width: 400px
                                --f7-button-height: 70px
                                --f7-button-hover-bg-color: rgba(0, 255, 0, 0.4)
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 20
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        header: Geyser Power
                        icon: f7:line_horizontal_3_decrease_circle
                        stateStyle:
                          fontSize: 40px
                        color: =(items.Geyser.state=="ON")?"green":""
                        item: Geyser
                        action: toggle
                        actionItem: Geyser
                        actionCommand: ON
                        actionCommandAlt: OFF
                        footer: '="Since: "+(items.Geyser_LastChange_ForDisplay.displayState)'
                        expandable: false
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 20
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        header: V Geyser Power
                        icon: f7:line_horizontal_3_decrease_circle
                        stateStyle:
                          fontSize: 40px
                        color: =(items.VGeyser_VGetserySwitch.state=="ON")?"green":""
                        item: VGeyser_VGetserySwitch
                        action: toggle
                        actionItem: VGeyser_VGetserySwitch
                        actionCommand: ON
                        actionCommandAlt: OFF
                        footer: '="Since: "+(items.VGeyser_Switch_LastChange_ForDisplay.displayState)'
                        expandable: false
              - component: oh-grid-col
                config:
                  width: 100
                  xsmall: 50
                  small: 20
                slots:
                  default:
                    - component: oh-label-cell
                      config:
                        header: Switch (Tuya)
                        icon: f7:arrow_right_arrow_left_circle
                        stateStyle:
                          fontSize: 40px
                        color: =(items.TuyaSwitch1.state=="ON")?"lime":""
                        item: TuyaSwitch1
                        action: toggle
                        actionItem: TuyaSwitch1
                        actionCommand: ON
                        actionCommandAlt: OFF
                        footer: ""
                        expandable: false
  
masonry: null

The widget Airpurifier_widget8 is an additional list based widget. you can anything else in place of it

1 Like

@candiesdoodle any chance you can share the widget8?

here you go:

uid: Airpurifier_widget8
tags: []
props:
  parameters:
    - description: Title
      label: Title
      name: Title
      required: false
      type: TEXT
    - description: Background Color
      label: Background Color
      name: BGColor
      required: false
    - context: item
      description: An item to control power
      label: Power control Item
      name: Power_item
      required: false
      type: TEXT
    - context: item
      description: An item to control mode
      label: Mode control Item
      name: Mode_item
      required: false
      type: TEXT
    - context: item
      description: An item to control favorite level
      label: Fav control Item
      name: Fav_item
      required: false
      type: TEXT
    - context: item
      description: An item to display AQI
      label: AQI display Item
      name: AQI_item
      required: false
      type: TEXT
    - context: item
      description: An item to display temp
      label: Temperature display Item
      name: Temp_item
      required: false
      type: TEXT
    - context: item
      description: An item to control Humidity
      label: Humidity display Item
      name: Humidity_item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Dec 13, 2020, 3:03:38 AM
component: oh-list
config:
  style:
    background-color: =props.BGColor
    font-size: min(max(14px, 4vw), 15px)
    --f7-list-inset-border-radius: 5px
    box-shadow: 5px 5px 5px grey
    position: relative
  class: inset
slots:
  default:
    - component: Label
      config:
        text: =props.Title?props.Title:"Label"
        style:
          padding: 7px
          border-bottom: 1px solid grey
          font-weight: 600
    - component: oh-toggle-item
      config:
        title: Power
        icon: f7:power
        item: =props.Power_item
        color: green
    - component: oh-list-item
      config:
        title: Mode
        icon: f7:gear
        style:
          margin-top: 0px
          margin-bottom: 0px
          --f7-list-item-border-color: transparent
      slots:
        after:
          - component: f7-chip
            config:
              text: =(items[props.Mode_item].state)
              style:
                --f7-chip-bg-color: "#4cd964"
                --f7-chip-text-color: white
    - component: f7-segmented
      config:
        style:
          margin-left: 10px
          margin-right: 10px
        strong: true
        class: segmented-round
      slots:
        default:
          - component: oh-button
            config:
              text: favorite
              action: command
              actionItem: =props.Mode_item
              actionCommand: favorite
              active: =(items[props.Mode_item].state=="favorite")
              color: =(items[props.Mode_item].state=="favorite")?"green":"transparent"
          - component: oh-button
            config:
              text: auto
              action: command
              actionItem: =props.Mode_item
              actionCommand: auto
              active: =(items[props.Mode_item].state=="auto")
              color: =(items[props.Mode_item].state=="auto")?"green":"transparent"
          - component: oh-button
            config:
              text: silent
              action: command
              actionItem: =props.Mode_item
              actionCommand: silent
              active: =(items[props.Mode_item].state=="silent")
              color: =(items[props.Mode_item].state=="silent")?"green":"transparent"
    - component: oh-slider-item
      config:
        item: =props.Fav_item
        min: 1
        max: =(props.Mode_item=="Bedroom_AP_Mode")?16:14
        icon: f7:gear_alt
        label: true
        scale: true
        step: 1
        title: Favorite Level
        color: green
        disabled: =(items[props.Mode_item].state!=='favorite')
        style:
          visibility: visible
          --f7-range-knob-color: green
          --f7-range-size: 8px
          --f7-badge-padding: 8px
          --f7-badge-size: 20px
          --f7-badge-bg-color: lightgreen
          --f7-badge-text-color: white
    - component: oh-list-item
      config:
        item: =props.AQI_item
        title: AQI
        icon: f7:smoke
        action: analyzer
        actionAnalyzerItems: =[props.AQI_item]
        actionAnalyzerCoordSystem: time
        badgeColor: green
        style:
          --f7-badge-padding: 8px
          --f7-badge-size: 20px
          --f7-badge-bg-color: lightgreen
          --f7-badge-text-color: white
      slots:
        after:
          - component: f7-chip
            config:
              text: =(items[props.AQI_item].state)
              style:
                --f7-chip-bg-color: =((items[props.AQI_item].state>=401)?'rgb(126,0,35)':(items[props.AQI_item].state>=301)?'rgb(102,0,153)':(items[props.AQI_item].state>=201)?'rgb(204,0,51)':(items[props.AQI_item].state>=101)?'rgb(255,153,51)':(items[props.AQI_item].state>=51)?'rgb(255,222,51)':(items[props.AQI_item].state>=0)?'#4cd964':'rgb(204,204,204)')
                --f7-chip-text-color: white
    - component: oh-label-item
      config:
        item: =props.Temp_item
        title: Temperature
        icon: f7:thermometer
    - component: oh-label-item
      config:
        item: =props.Humidity_item
        title: Humidity
        icon: f7:drop

image

1 Like

Have you seen the background image disappear on the cards if the screen height is under 670? The card sizes don’t change, but something get unapplied.

It is also the point that the cards popup to fill the pane, instead of in a modal, when clicked. But, the background does display in both of those!

This looks like the only style change:
@media (min-height: 670px) and (min-width: 768px)
.card-expandable:not(.card-tablet-fullscreen)
max-width: 670px;
max-width: var(–f7-card-expandable-tablet-width);

@candiesdoodle
Did u find a solution to always place the glance / icon at the right edge of the card?