Dishwasher Status Widget

UPDATE2: Removed unecessary animation properties

UPDATE: Thanks to the wonderful heating widget of @Nico_R i finally understood how to create animations. This is getting a bit silly but since it also reduces the amount of code I now animated the opening and closing of the dishwasher. Be sure not to miss the magic moment :rofl:

Demo:
washing2

I’m happy to present you the latest addition to my widget collection: The dishwasher widget. The widget is designed to work together with my washing machine widget and thus reuses parts of the code.

If you are already familiar with my washing machine widget then you already know how to use it. If not: Please see this thread for instructions: Washing machine status widget

Here you can see the widget in action (Running, Off, Finished washing):

And the widget code:

uid: dishwasher_v4
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - description: The card footer
      label: Footer
      name: footer
      required: false
      type: TEXT
    - description: Header text above dishwasher
      label: Header
      name: header
      required: false
      type: TEXT
    - description: Expression that evaluates to minutes since the begin of washing
      label: Minutes running
      name: runtime
      required: true
      type: TEXT
    - description: Expression that evaluates to OFF, RUNNING or FINISHED
      label: State
      name: state
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Feb 15, 2021, 9:44:05 AM
component: f7-card
config:
  title: =(props.title)
slots:
  default:
    - component: f7-card-content
      config:
        style:
          height: 175px
      slots:
        default:
          - component: f7-row
            config:
              class:
                - display-flex
                - justify-content-center
              style:
                width: 100%
            slots:
              default:
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - flex-direction-column
                      - align-items-center
                      - justify-content-space-evenly
                    style:
                      height: 100%
                  slots:
                    default:
                      - component: f7-block-header
                        slots:
                          default:
                            - component: Label
                              config:
                                text: =props.header
                      - component: f7-block
                        config:
                          style:
                            height: 120px
                            width: 90px
                            border-radius: 2px 2px 4px 4px
                            background: rgba(255,255,255,1)
                            box-shadow: rgba(0, 0, 0, 0.25) 0px 14px 28px, rgba(0, 0, 0, 0.22) 0px 10px 10px
                          class:
                            - display-flex
                            - flex-direction-column
                            - align-items-center
                        slots:
                          default:
                            - component: f7-block
                              config:
                                class:
                                  - display-flex
                                  - justify-content-flex-end
                                  - align-items-center
                                  - flex-shrink-0
                                  - no-margin
                                style:
                                  height: 23px
                                  width: 85px
                                  border-bottom: 1pt solid lightgray
                                  padding-right: 10px
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      f7: circle_fill
                                      size: 10
                                      color: gray
                                  - component: f7-icon
                                    config:
                                      f7: circle_fill
                                      size: 10
                                      color: gray
                                  - component: f7-icon
                                    config:
                                      f7: '=props.state == "OFF" ? "circle_fill" : "sun_min"'
                                      size: 10
                                      style:
                                        color: '=props.state == "OFF" ? "gray" : "red"'
                            - component: f7-block
                              config:
                                class:
                                  - no-padding
                                style:
                                  height: calc(100% - 23px)
                                  width: 90%
                                  bottom: 0px
                                  position: absolute
                                  background: whitesmoke
                            - component: f7-block
                              config:
                                class:
                                  - display-flex
                                  - justify-content-center
                                  - align-items-center
                                style:
                                  position: absolute
                                  bottom: 0px
                                  left: 30%
                                  width: 40px
                                  height: 40px
                                  background: beige
                                  box-shadow: 0 0 16px 8px rgba(0, 0, 0, 0.10) inset
                                  border-radius: 50%
                                  transition: transform 0.6s
                                  transform: '=props.state == "FINISHED" ? "translate(-50%, -45px)" : "translate(-50%, 0)"'
                                  transform-origin: left center
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      f7: circle
                                      size: 40
                                      style:
                                        color: beige
                            - component: f7-block
                              config:
                                class:
                                  - display-flex
                                  - justify-content-center
                                  - align-items-center
                                style:
                                  position: absolute
                                  bottom: 0px
                                  left: 50%
                                  width: 40px
                                  height: 40px
                                  background: beige
                                  box-shadow: 0 0 16px 8px rgba(0, 0, 0, 0.10) inset
                                  border-radius: 50%
                                  transition: transform 0.6s
                                  transform: '=props.state == "FINISHED" ? "translate(-50%, -47px)" : "translate(-50%, 0)"'
                                  transform-origin: left center
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      f7: circle
                                      size: 40
                                      style:
                                        color: beige
                            - component: f7-block
                              config:
                                class:
                                  - display-flex
                                  - justify-content-center
                                  - align-items-center
                                style:
                                  position: absolute
                                  bottom: 0px
                                  left: 70%
                                  width: 40px
                                  height: 40px
                                  background: beige
                                  box-shadow: 0 0 16px 8px rgba(0, 0, 0, 0.10) inset
                                  border-radius: 50%
                                  transition: transform 0.6s
                                  transform: '=props.state == "FINISHED" ? "translate(-50%, -49px)" : "translate(-50%, 0)"'
                                  transform-origin: left center
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      f7: circle
                                      size: 40
                                      style:
                                        color: beige
                            - component: f7-block
                              config:
                                class:
                                  - display-flex
                                  - flex-direction-column
                                  - justify-content-flex-start
                                  - align-items-center
                                style:
                                  height: 100%
                                  width: 90px
                                  backgroundColor: '=props.state == "RUNNING" ? "white" : "whitesmoke"'
                                  transition: transform 0.6s
                                  transform: '=props.state != "RUNNING" ? "perspective(600px) rotateX(-55deg)" : "perspective(0px) rotateX(0deg)"'
                                  transform-origin: bottom center
                                  margin-top: auto
                                  box-shadow: rgba(0, 0, 0, 0.25) 0px 14px 28px, rgba(0, 0, 0, 0.22) 0px 10px 10px
                              slots:
                                default:
                                  - component: f7-block
                                    config:
                                      style:
                                        height: 10px
                                        width: 90px
                                        position: absolute
                                        margin-top: -10px
                                        backgroundColor: white
                                        transition: transform 0.6s
                                        transform: '=props.state != "RUNNING" ? "perspective(600px) rotateX(35deg)" : "perspective(600px) rotateX(90deg)"'
                                        transform-origin: bottom center
                                        border-radius: 2px
                                  - component: f7-block
                                    config:
                                      style:
                                        backgroundColor: gray
                                        margin-top: 10px
                                        height: 5px
                                        width: 5px
                                        border-radius: 2px 2px 0px 0px
                                  - component: f7-block
                                    config:
                                      class:
                                        - no-padding
                                      style:
                                        margin-top: 10px
                                        height: calc(100% - 40px)
                                        width: 100%
                                    slots:
                                      default:
                                        - component: f7-preloader
                                          config:
                                            size: 50
                                            colorTheme: lightblue
                                            style:
                                              position: absolute
                                              top: 50%
                                              left: 50%
                                              transition: transform 0.6s
                                              transform: '=props.state == "RUNNING" ? "scale(1, 1) translate(-50%, -50%)" : "scale(0, 0) translate(-50%, -50%)"'
                                              transform-origin: left center
                                        - component: f7-block-header
                                          config:
                                            class:
                                              - no-margin
                                            style:
                                              position: absolute
                                              top: 50%
                                              left: 50%
                                              transition: transform 0.6s
                                              transform: '=props.state == "RUNNING" ? "scale(1, 1) translate(-50%, -50%)" : "scale(0, 0) translate(-50%, -50%)"'
                                              transform-origin: left center
                                          slots:
                                            default:
                                              - component: Label
                                                config:
                                                  text: '=Math.floor(props.runtime / 60) + ":" + ((props.runtime % 60) < 10 ? ("0" + props.runtime % 60) : (props.runtime % 60))'
                                                  style:
                                                    color: black
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: =props.footer

Happy dishwashing!

14 Likes

I realized that on Safari on an iPad the widget is not shown correctly when it has been added to a page but it looks fine in the editor also in Safari…

Maybe someone can reproduce this!?

Hi @DrRSatzteil

nice widget and good work.
One statement from my side:

The animations doesn’t work because you cant define a animation in the yaml. All animations defined in the f7 core.
So in your code the parts like animation: open 0.3s linear both aren’t necessary because they doesn’t work.
The animation in your code is only based on the transition part.
You can delete the animation prop and the widget works as well. :wink:

(i hope my understanding of the current F7 hints is correct :smiley: )

best,
Nico

Hi Nico,

thank you for your explanation. I will get rid of this part then!

Even after my latest update the problem remains that in Safari the 3d rotated blocks are only shown in the editor but not on an actual page… So I can see in the editor that the browser is capable of displaying it correctly but it just doesn’t on a page… Couldn’t fix it with a higher z-index either…

Which transformation you are referring to? Made a quick check on my iPad and everything looks clean at first glance.

Thanks for checking: the door of the dishwasher disappears on my iPad. But only when I add the widget to a page. In the editor it works just fine.

Even if I have no ad-hoc idea why it works in the editor and not on the pages… but generally this might depend on the Safari version you’re using - older Safari versions might need a prefix. Try to add:

-webkit-transform: '=props.state != "RUNNING" ? "perspective(600px) rotateX(-55deg)" : "perspective(0px) rotateX(0deg)"'
transform-box: fill-box

The second property could be a soloution if your Safari version having problems with the interpretation of the transform-origin.

I tried the -webkit-transform lready but without success. It should not be necessary in my case anyway since my Safari is up to date…

I will try the transform-box suggestion later. Thank you!

Unfortunately the transform-box did not help either. I use this widget mainly on an android phone so this is not a really big issue. It is still weird and somehow unsatisfying… Thank you for your valuable input anyway!

No problem, as it wasn’t very helpfull :stuck_out_tongue:
And yes, strange why it works for me then. The last idea I have, would be some kind of a caching problem, which is related to your testing while developing the widget, but just guessing here.

I think I can rule this out as well. The incognito mode does not help and I tried on another iPad yesterday where I had the same effect. I’m also it of ideas here… Thank you for your efforts with this issue

Hi.
First of all - thank you for sharing your widget. I think the community is really nice in openhab!
After i while a begin understanding how the code works. Just a Beginner - Sorry :slight_smile:

I have a smart dishwasher, so all items are available in items of bindings. So i have used this code:

Blockquote
- component: widget:dishwasher_v4
config:
runtime: =(items.SiemensGeschirrspuler_Remainingprogramtime.state)/60
title: Geschirrspüler
state: =items.SiemensGeschirrspuler_PowerState.state
header: “=(items.SiemensGeschirrspuler_SelectedProgram != “UNDEF” ) ? items.SiemensGeschirrspuler_SelectedProgram.state : “”’”
footer: “=(items.SiemensGeschirrspuler_ActiveProgram.state != “UNDEF” ) ? items.SiemensGeschirrspuler_ActiveProgram.state : “”’”
Blockquote

Every works fine, but if the dishwasher is running, i doesnt see the time - it just see NaN:NaN

I am sure the code from you is working and the fault is mine - but i dont find it. :slight_smile: in your widgt i doesnt do anything on the runtime (i just have to delete Fininshed to OFF - couse my smart dishwasher brings other status back.

For better understanding: My dishwasher gives seconds back in the item SiemensGeschirrspuler_Remainingprogramtime. If i put this item to the header or the footer it gives me the seconds back.

Maybe any hints?

Hi Bernhard,

Maybe items.SiemensGeschirrspuler_Remainingprogramtime.state is a typed Number? I’m not entirely sure if your expression is working like that then. Do you know that there is an expression tester you can reach via the developer tools (the link is not available on a mobile phone afaik)? I recommend to paste the code there. First without the ‘/60’ and then add the ‘/60’ to see if that works.

Hello.
I think its a Point Number:Date and Not a String. If i Type String i get a NULL Back. So dont think that this works. I will search the Expression Tester and will Test it. Withoit /60 it was the Same result. Thank you for your Help.

Ok. It is a Number:Time - semantic class Point Status
If i do in the Widgets Expression Tester : =items.SiemensGeschirrspuler_Remainingprogramtime.state) then it sends back the seconds - for example “10680 s”. If i do /60 at the backwards it gets a NaN. So at the end of the code in the widget there is props.runtime / 60 - and thats why it becomes NaN in the Widget.

I dont know how i can resolve it this way…

Shouldn’t it work with?

=Math.round(items.SiemensGeschirrspuler_Remainingprogramtime.state.split(' ')[0] / 60) 
1 Like

Even though I guess there is probably be a more elegant way you could try the following. I think that should work as well:

=items.SiemensGeschirrspuler_Remainingprogramtime.state.split(" ")[0]

1 Like

Oh you were faster :joy:

And your solution looks complete (compared to mine). You should try Rainer’s suggestion, Bernhard.

Thank you for the Support! It works fine!

In the meantime i have found an alternative to the running time. My dishwasher also delivers an percentage state, so i have changed the runtime piece of your code to:

slots:
default:
- component: Label
config:
text: =Math.floor(props.runtime) + “%”

in this case it shows me the percentage of the actual program like 75%.

Now, that the remaining time is shown, i dont need the percentage, but just for others…

Hi @Nico_R

This is weird: I realised that after I removed the animation properties from the preloader it goes wild on my mobile devices (Chrome on Android phone and iPad Safari): the preloader no longer is hidden/resized and rotates around a point close to the center of the preloader. Adding the animation tags again solved this. However in Chrome on Windows and Linux I do not observe this strange behaviour. Do you have any ideas why this happens?

1 Like