Washing machine status widget

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:

Ok, now it works.
Thank you :slight_smile:

I added dryer mode as a small update in the first post :+1:

@muelli1967 could you explain what you have modified to show the widget in the rounded cell style?

I am using only these rounded cells, would be nice to add this widget in the same style as well.
Thanks!

I am away from my computer for a couple of days and will send it once back.

sorry guys, but I donĀ“t get where I have to let the widget know what device/item IĀ“m talking about. I can configure the states but still the widget wonĀ“t know which item it should watch.

edit: Ok, I found itā€¦

I made an update to the first post: The look and feel of the washing machine will now be the same on android and iOS devices. Thanks goes to @Nico_R who created this custom component for the dishwasher status widget.

Hi, everyone.

I get the following error on the UI when trying to install this widget and the Dishwasher Status :

Installation of add-on 116621 failed

On the Karaf console I get the following:

12/26/2022 20:45:52.656 [ERROR] [mmunity.CommunityUIWidgetAddonHandler] - Widget from marketplace is invalid: Couldn't find the widget in the add-on entry

I installed other widgets from Rich Koshak and Thomas Lauterbach without problems.
Iā€™m running OpenHAB 3.2 (stable) on a Raspberry Pi 4B with CentOS 8 (64bits).

Does anyone have any idea why this may happen?

1 Like

Maybe my post is in the wrong format!? The post is older than the community marketplace so this might be the case. I donā€™t find a lot of time during the holidays but I will check asap whether this could be the problem.

Could you please try again to install the widget from the marketplace? I just updated the first post so that it matches the required structure. Thank you!