Washing machine status widget

Oh and btw: I will probably be adding my dishwasher soon as well so I will probably create another widget for that :wink:

it is pretty simple to add an action to show a group in case of clicking the widget. Add this to your widget and define the group to show in the props.

  >  - component: oh-link
>       config:
>         action: group
>         actionGroupPopupItem: =[props.itemGroup]
>         style:
>           position: absolute
>           z-index: 1
>           width: 100%
>           height: 100%
>           top: 0
>           left: 0

I hope this is what you were searching for.

I was thinking about something like this as well but havenā€™t tried it. Looks good and very simple! Thank you for sharing

Iā€™d love to have the dishwasher not looking like a washing machine :smiley: But in terms of designing something out of simple elements Iā€™m quiteā€¦ well bad.

Thanks @muelli1967! Works like a charm. I still donā€™t really understand where to put what, but it worked out :smiley:

Here you go:

:smiley:

1 Like

the widget is working nicely here. Thanks Thomas for your efforts and the clear explanations!

2 Likes

Can anyone tell me how to get the status of your washing machine in openHab ? Does anyone measures the used Ampere of the machine ? which kind of hardware ? thanks

Stefan mentioned that he owns a smart Miele machine. I own a dumb Miele machine and use a Shelly plug S that can measure the energy consumption of the attached device (Iā€™m sure however there are lots of alternatives on the market). By analysing the typical energy usage during and after the washing you can figure out thresholds to determine when the machine is finished. In contrast to Stefan I canā€™t do any more than that but thatā€™s in fact all I need.

Connecting the washing machine and dryer to a KNX actuator which can measure the current was one of the oversights in my installation. Now I am using switchable plugs from AVM, which are connected via Dect, this works fine.

To get the state I am using a openHAB rule with a simple state machine, based on the current. This needed some trying, to get the limits correct but now it is very reliable.

I have connected my Washingmachine to a plug that measures Wh. You can use any, i have one homematic and a tasmota. The tasmota has a bigger variance, i might replace it at some point. You need to monitor the consumption for the states and set the parameters in a rule. You also need to check how much timer you need in case the machine stops and starts the program again depending on the program. i am using 5 min. I am currently using the below rule, although i disabled the mode standby as this was not reliable and not needed as well. There is a pretty large thread here in the forum as well. Just look for washing machineā€¦

val MODE_OFF = 0
val MODE_STANDBY = 1
val MODE_ACTIVE = 2
val MODE_FINISHED = 3

var Timer tWashing_Machine = null

rule "Washingmachine Consumption State Machine"
when
    Item Washingmachine_Power changed
then
    if(!(Washingmachine_Power.state instanceof Number)) {
        logWarn("washing","Can't get valid power! {}",Washingmachine_Power.state)
        return;
    }
    
    val nPower = (Washingmachine_Power.state as Number).floatValue
//  logInfo("washing", "Washing Machine rule initiated.")

    if (nPower < 0.21 && Washingmachine_OpState2.state != MODE_OFF) { 

        Washingmachine_OpState2.postUpdate(MODE_OFF) 
        logInfo("washing", "Washing Machine OFF.") 

    } else if(nPower > 15 && Washingmachine_OpState2.state != MODE_ACTIVE) {

        Washingmachine_OpState2.postUpdate(MODE_ACTIVE)
        logInfo("washing", "Washing Machine ACTIVE.")

        if(tWashing_Machine !== null) {

            tWashing_Machine.cancel
            logInfo("washing", "Timer cancelled.")

        } else {

            logInfo("washing", "Timer not cancelled due to it being null.")

        }
    } else if (nPower < 3.5) {

//        if(Washingmachine_OpState2.state == MODE_OFF) {
//
//            Washingmachine_OpState2.postUpdate(MODE_STANDBY) 
//            logInfo("washing", "Washing Machine STANDBY") 
//
//        } else 
		
		if (Washingmachine_OpState2.state == MODE_ACTIVE) {

            if(tWashing_Machine === null) {

                logInfo("washing", "Timer created.")
                tWashing_Machine = createTimer(now.plusMinutes(5), [ |

                    Washingmachine_OpState2.postUpdate(MODE_FINISHED)
                    logInfo("washing", "Timer expired. Washing Machine FINISHED.")
                    tWashing_Machine = null

                ])
            }
        }
    }
end

Hi,
first off all awsome work on the widget and thank you for sharing. Implimenetation worked great just one part I am strunggling with:

State: Can be one of OFF, RUNNING or FINISHED and should be filled in via an expression as well depending on the current state of your machine

Canā€™t get the expression to work. I use an item to represent the status auf the washing machine (Washer_OpState_CE_Utilityroom). The state is given by a numeric value (0-3) that translate to/ repersent the staes: Off, Standby, Active and Finished.

Now my question, what expression to use to get the widget state to OFF, RUNNING, FINISHED? Maybe someone can point me in the right direction.

Thanks

i believe you are almost there. I also work with a numbers item that represents the state of my washing machine as you can also see in the rule i posted, so i changed the YAML file from @DrRSatzteil to replace the values OFF, RUNNING etc. with my numbers like this:

f7: '=items[props.state].state == "3" ? "circle_bottomthird_split" : "circle"'

1 Like

You can either do it like suggested by Jan or use an expression like this:

=items.washing_machine_state.state == 1 ? "OFF" : items.washing_machine_state.state == 2 ? "RUNNING" : "FINISHED"

Where washing_machine_state is the name of your status item.

1 Like

Thats it! Thank you very much ā€¦
ā€¦ sometimes it is that little nudge and the help of others that put you back on track!

Is a rule like this not easier?
When: cron everyminute
But only if: Washingmachine_State == Running
Then: Washingmachine_Runtime.state + 1

And in your washingmachine_state rule add, when wassingmachine_state == OFF postUpdate(Washingmachine_Runtime, 0)

Yes I think your solution is simple and would work just like my more complicated rule. Thanks for sharing!

When you set the runtime to 0 is more a matter of taste in my opinion. I set it to 0 when the machine is starting so I am able to see how long the last washing was running after the washing is finished. However I agree that this information is pretty useless so it does not really matter

Thanks a lot @DrRSatzteil for this great Widget :slight_smile:

I use it with the Siemens/Bosch HomeConnect Binding.
I did some small modifications today to implement some parameters provided by the HomeConnect Binding for Washer and Dryer.

I replaced the ā€œdummyā€ buttons with the ā€œRemainingTimeā€ used from the binding.

The following parameters are added to your wonderful :slight_smile: widget as well.

  • Progress (used in a progress)
  • SpinSpeed
  • Temperatur
  • ProgramMode

When the Widget is set in ā€œDryerā€ mode, then the colors are changing from blue to red.

uid: washing_machine_v3
tags: []
props:
  parameters:
    - description: Title of the card
      label: Title
      name: title
      required: false
      type: TEXT
    - description: Header text above washing machine
      label: Header
      name: header
      required: false
      type: TEXT
    - context: item
      description: Set Washer/Dryer Item (BSH HomeConnect)
      label: Washer/Dryer Item
      name: item
      required: true
      type: TEXT
    - description: Set On if Dryer is defined to change the color of Widged
      label: Item is Dryer?
      name: isDryer
      required: false
      type: BOOLEAN
  parameterGroups: []
timestamp: Mar 14, 2021, 6:59:23 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%
                      width: 90px
                  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: 9px 9px 5px 5px
                            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-space-between
                                  - align-items-center
                                  - flex-shrink-0
                                  - no-margin
                                style:
                                  height: 23px
                                  width: 85px
                                  padding-right: 5px
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      size: 10
                                      color: gray
                                  - component: f7-icon
                                    config:
                                      size: 10
                                      color: gray
                                  - component: Label
                                    config:
                                      text: =Math.floor(items[props.item + '_Remainingprogramtime' ].state.split(' ')[0] /3600) + ':' + (Math.floor(items[props.item +  '_Remainingprogramtime'].state.split(' ')[0] /60)  - Math.floor(items[props.item + '_Remainingprogramtime'].state.split(' ')[0] /3600)  * 60)
                                      visible: "=(items[props.item + '_Remainingprogramtime' ].state === 'UNDEF' || items[props.item + '_Remainingprogramtime' ].state === '0 s') ? false : true"
                                      style:
                                        font-size: 10px
                                  - component: f7-icon
                                    config:
                                      f7: "=(items[props.item + '_OperationState'].state === 'UNDEF' || items[props.item + '_OperationState'].state === 'Ready') ? 'circle_fill' : 'sun_min'"
                                      size: 10
                                      style:
                                        align-self: center
                                        color: "=(items[props.item + '_OperationState'].state === 'UNDEF' || items[props.item + '_OperationState'].state === 'Ready') ? 'gray' : 'green'"
                            - component: f7-progressbar
                              config:
                                progress: =Number.parseInt(items[props.item + '_ProgressState'].state)
                                infinite: false
                                style:
                                  --f7-progressbar-progress-color: "=Number.parseInt(items[props.item + '_ProgressState'].state) == 100 ? '#00ff00' : props.isDryer === true ? 'red' : '#179cd1'"
                                  --f7-progressbar-bg-color: "#ededed"
                                  --f7-progressbar-height: 2px
                                  width: 85px
                                  z-index: 999
                            - component: f7-block
                              config:
                                class:
                                  - display-flex
                                  - justify-content-center
                                  - align-items-center
                                style:
                                  height: 60px
                                  width: 60px
                                  border: 5pt solid lightgray
                                  border-radius: 50%
                                  margin-top: 7px
                              slots:
                                default:
                                  - component: f7-preloader
                                    config:
                                      size: 50
                                      colorTheme: "=props.isDryer === true ? 'red' : 'lightblue'"
                                      visible: =items[props.item + '_OperationState'].state == 'Run'
                                      style:
                                        position: absolute
                                  - component: f7-icon
                                    config:
                                      f7: "=items[props.item + '_OperationState'].state ==  'Finished' ? 'circle_bottomthird_split' : 'circle'"
                                      size: 50
                                      style:
                                        color: "=(items[props.item + '_OperationState'].state === 'UNDEF' || items[props.item + '_OperationState'].state === 'Ready') ? 'lightgray' : props.isDryer === true ? '#ff4f4f' : 'lightblue'"
                                        border-radius: 50%
                                        box-shadow: 0 0 16px 8px rgba(0, 0, 0, 0.25) inset
                                  - component: f7-block-header
                                    config:
                                      visible: =items[props.item + '_OperationState'].state == 'Run'
                                      class:
                                        - no-margin
                                      style:
                                        position: absolute
                                        text-align: center
                                    slots:
                                      default:
                                        - component: Label
                                          config:
                                            text: "=items[props.item + '_SpinSpeed'].displayState === NULL ? items[props.item + '_SpinSpeed'].state.split('RPM')[1] : items[props.item + '_SpinSpeed'].displayState.split(' ')[0]"
                                            style:
                                              font-size: 11px
                                              color: black
                                        - component: Label
                                          config:
                                            text: "=items[props.item + '_WashingProgramTemperature'].displayState === NULL ? items[props.item + '_WashingProgramTemperature'].state.split('.')[4] : items[props.item + '_WashingProgramTemperature'].displayState"
                                            style:
                                              font-size: 11px
                                              color: black
                            - component: Label
                              config:
                                text: "=items[props.item + '_ActiveProgram'].state !== 'UNDEF' ? items[props.item + '_ActiveProgram'].state : ''"
                                style:
                                  font-size: 10px
                                  color: black

3 Likes

Hi,

I also canā€™t get the expression to work. I am very new to openHab and donā€™t have an idea how to implement the expression for OFF, RUNNING, etc.
I have the rule implemented that you posted above. This is working fine. I have an Item ā€œWaschmaschine_Statusā€ which gets values from 0-3.
I have also changed the YAML file as you described it.
But when I write Waschmaschine_Status in the state props field nothing happens.
Can you please give me a hint what I am doing wrong?
Thank you!

If you have already changed the yaml to work with values 0, 1, 2 and 3 you should set the expression to:

=items.Waschmaschine_Status.state

And you should be all set. Let me know if that works for you :blush: