Shouldn’t it work with?
=Math.round(items.SiemensGeschirrspuler_Remainingprogramtime.state.split(' ')[0] / 60)
Shouldn’t it work with?
=Math.round(items.SiemensGeschirrspuler_Remainingprogramtime.state.split(' ')[0] / 60)
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]
Oh you were faster
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?
@DrRSatzteil & @Nico_R - I’m also experiencing this too (weird animation effects on mobile); haven’t been able to pin it down yet…
@Bernhard_R & @Nico_R - great Widget here! I also have a ‘smart’ Samsung dishwasher, but as I’m using openHAB didn’t want to fuss with adding a SmartThings hub into the mix just for polling the dishwasher via their 3rd party proprietary Cloud APIs. Sooo, I ended up hacking this together instead:
RUNNING:
triggers:
- id: "1"
configuration:
itemName: DW_Online
state: ON
previousState: OFF
type: core.ItemStateChangeTrigger
conditions: []
actions:
- inputs: {}
id: "2"
configuration:
itemName: DW_State
state: RUNNING
type: core.ItemStateUpdateAction
OFF
triggers:
- id: "1"
configuration:
itemName: DW_Online
state: OFF
previousState: ON
type: core.ItemStateChangeTrigger
conditions: []
actions:
- inputs: {}
id: "2"
configuration:
itemName: DW_State
state: FINISHED
type: core.ItemStateUpdateAction
And then finally rewired the Widget code to work with the new OH items:
uid: dishwasher_v6
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
- context: item
description: Expression that evaluates to minutes since the begin of washing
label: Minutes running
name: runtime
required: true
type: TEXT
- context: item
description: Expression that evaluates to OFF, RUNNING or FINISHED
label: State
name: state
required: true
type: TEXT
parameterGroups: []
timestamp: Mar 12, 2021, 9:56:07 PM
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: '=items[props.state].state == "OFF" ? "circle_fill" : "sun_min"'
size: 10
style:
color: '=items[props.state].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: '=items[props.state].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: '=items[props.state].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: '=items[props.state].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: '=items[props.state].state == "RUNNING" ? "white" : "whitesmoke"'
transition: transform 0.6s
transform: '=items[props.state].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: '=items[props.state].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: '=items[props.state].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: '=items[props.state].state == "RUNNING" ? "scale(1, 1) translate(-50%, -50%)" : "scale(0, 0) translate(-50%, -50%)"'
transform-origin: left center
- component: f7-card-footer
slots:
default:
- component: Label
config:
text: =props.footer
And after all of that, add the widget to the desired Page, and connect the Widget configuration to necessary items to finalize.
Cool that this works by only monitoring the ‘Things’ local network presence (via ping); no cloud dependencies! I’m happy with it ‘as is’, but always room for improvement.
Best regards,
.
I assume you are using an iPhone? Thanks for sharing your setup by the way!
I’m on Android actually! The mobile animation issue is effecting the main UI in both the native mobile app and chrome.
Hi @DrRSatzteil
please excuse the late reply. At the moment there is a lot going on and there is little time left for the hobby.
I have checked the error pattern, but I cannot find a quick and easy solution. e.g. one line solution.
I can suggest removing the F7 preloader and building this structure myself. So you have everything in hand and can design yourself. Maybe there are professionals who will find a faster and better way.
I hope this is a solution for all of you, even if it is not a quick one. Maybe this can also help @d0t .
It is working on my mobile phone and browser.
all the best,
Nico
My suggestion:
delete the f7-preloader and paste this snipped:
- component: f7-block
config:
colorTheme: lightblue
class: custom-preloader-container-dummy
style:
display: '=props.state == "RUNNING" ? "" : "none"'
margin: 0
padding: 0
--f7-preloader-size: 50px
--f7-preloader-color: var(--f7-theme-color)
position: absolute
left: 50%
top: 50%
transform: translate(-50%, -50%)
slots:
default:
- component: f7-block
config:
class: custom-preloader-dummy
style:
margin: 0
padding: 0
width: var(--f7-preloader-size)
height: var(--f7-preloader-size)
slots:
default:
- component: f7-block
config:
class: custom-preloader-inner-dummy
style:
margin: 0
padding: 0
position: absolute
left: 0
top: 0
width: 100%
height: 100%
slots:
default:
- component: f7-block
config:
class: custom-preloader-inner-circle-dummy
style:
margin: 0
padding: 0
border-radius: 50%
border: calc(var(--f7-preloader-size)/8) solid var(--f7-preloader-color)
border-top-color: transparent
box-sizing: border-box
animation: aurora-preloader-rotate 1s linear infinite
position: absolute
left: 0
top: 0
width: 100%
height: 100%
Complete Code:
uid: dishwasher_Nico
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: Mar 14, 2021, 12:35:30 PM
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-block
config:
colorTheme: lightblue
class: custom-preloader-container-dummy
style:
display: '=props.state == "RUNNING" ? "" : "none"'
margin: 0
padding: 0
--f7-preloader-size: 50px
--f7-preloader-color: var(--f7-theme-color)
position: absolute
left: 50%
top: 50%
transform: translate(-50%, -50%)
slots:
default:
- component: f7-block
config:
class: custom-preloader-dummy
style:
margin: 0
padding: 0
width: var(--f7-preloader-size)
height: var(--f7-preloader-size)
slots:
default:
- component: f7-block
config:
class: custom-preloader-inner-dummy
style:
margin: 0
padding: 0
position: absolute
left: 0
top: 0
width: 100%
height: 100%
slots:
default:
- component: f7-block
config:
class: custom-preloader-inner-circle-dummy
style:
margin: 0
padding: 0
border-radius: 50%
border: calc(var(--f7-preloader-size)/8) solid var(--f7-preloader-color)
border-top-color: transparent
box-sizing: border-box
animation: aurora-preloader-rotate 1s linear infinite
position: absolute
left: 0
top: 0
width: 100%
height: 100%
- 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
No worries Nico. For me my old version with the animation properties works fine even though this can only be considered luck given that these properties should not work…
I will look at your approach in the next couple of days, it is definitely better to have code that works without weird workarounds Thanks for your efforts!
I finally updated my widget with your code @Nico_R. Seems to work fine for me, thank you! However the front door is still invisible on my iPads…
Maybe @d0t can try if this solves his issues.
I’m back on an iPhone since my new employer hands out iOS devices. So I finally wanted to have this fixed for iOS devices as well. The solution is a hack I got from here: javascript - iOS 8 css rotate element disappears - Stack Overflow
I still have no clue why this is necessary but it does the trick for me and my iOS devices without breaking anything on other devices.
I updated the code in the first post!
So i had a xiaomi smart plug lying around and your excellent widget made me use it to monitor my dump dishwasher.I use this rule reading the power consumption and it works …ok
val Number MODE_OFF = 0
val Number MODE_ACTIVE = 1
val Number MODE_FINISHED = 2
rule "dishwasher"
when Item XiaomiMiSmartSocketPlug_ProvidedPower changed
then
logInfo("Dishwasher Consumption State Machine","I am running this rule (Status "+DishwasherState.state+")")
if (XiaomiMiSmartSocketPlug_ProvidedPower.state < 1.5 | W) {
DishwasherState.postUpdate(MODE_OFF)
logInfo("Dishwasher Consumption State Machine","Dishwasher is OFF (Status "+DishwasherState.state+")")
}
else if (XiaomiMiSmartSocketPlug_ProvidedPower.state > 30.0 | W) {
DishwasherState.postUpdate(MODE_ACTIVE)
logInfo("Dishwasher Consumption State Machine","Dishwasher is ON (Status "+DishwasherState.state+")")
}
else if (XiaomiMiSmartSocketPlug_ProvidedPower.state < 3.0 | W) {
logInfo("Dishwasher Consumption State Machine","I am now checking if it's FINISHED (Status "+DishwasherState.state+")")
if (DishwasherState.state == MODE_ACTIVE) {
DishwasherState.postUpdate(MODE_FINISHED)
logInfo("Dishwasher Consumption State Machine","Dishwasher is FINISHED as it was ACTIVE before")
}
else {
logInfo("Dishwasher Consumption State Machine","I did not enter here (Status "+DishwasherState.state+")")
}
}
end
my expression is
=items.DishwasherState.state == '0' ? "OFF" : items.DishwasherState.state == '1' ? "RUNNING" : items.DishwasherState.state == '2' ? "FINISHED" : "OFF"
and now i am out of ideas how to get the runtime…Any ideas?
I’m using the PersistenceExtensions: See my post here: Washing machine status widget - #3 by DrRSatzteil
You may also just reset an item to 0 when you enter MODE_ACTIVE and increase this number by one every minute while the current mode is still == MODE_ACTIVE.
Thanks for the great widget! Works as it should with my installation.
And then a question: is there some configuration to disable the “incoming” animation? The washer-widget doesn’t have that and some of my devices struggle with that animation. I’m not so firm in CSS and stuff, so I’m a bit at a loss here
Thanks!
Hi and thanks!
I think to remove the animations it should be enough to remove the lines with „transition: transform 0.6s“ nodes in the yaml code.
Thanks! works!
How do you get the footer texts to change according to the dishwasher state? My footer is empty…
You can use an expression like this for the footer field:
'=items.dishwasher_status.state == "RUNNING" ? "Spült" :
items.dishwasher_status.state == "FINISHED" ? "Beendet" : "Aus"'