Xiaomi Vacuum Control

Great to hear that you are still further enhancing the widget!
Looking forward to your rule as mine is a bit “basic”.

Thank you for all your awesome feedback and ideas / inspiration.

Talking about rules: Wich flavor of rules would you implement? I decided for me to go with a “new” filebased jscript rule in conf/automation/js - would that be something you support or rather wish for something else? (Quite sure that I wont change it - even if you wish for something else though! :stuck_out_tongue: But maybe you got good reasons why that is not the best choice.)

Will have to look how installation from marketplace works at all - as I published this one, there was no marketplace.

1 Like

I see. Let me know if you need me to test it again and I’ll do it.

hello,thnx for this super widget.I have a weird small problem with room cleaning,if the room number is 1 then it sends

Item 'MiRobotVacuumV2_Actions_ExecuteCommand' received command app_segment_clean[]

and not

Item 'MiRobotVacuumV2_Actions_ExecuteCommand' received command app_segment_clean[1]

as it should be.Any ideas?All the other numbers from 2 and up are working fine.

Hi @Constantinos_Contis,
think you’re using a modified version based on my post where I tried to help you.

I can only guess and hint you to have a look at the line in the widget, maybe there’s some check of yours wrong:

Or maybe post that line and I can see if I can help you!

1 Like

got it …thnx.At 50 years old my eyes and my brain arent work together well :slight_smile:

1 Like

is there a way to add a button to select 1 or 2 clean passes for roborock S5?

Currently not implemented and I’m also not aware of any function that allows to set the reptition for room cleaning. :confused:

My time is sadly limited to go on with development, but I will have an eye on it as soon as I find some time.

2 Likes

Dear all,
since i moved to a new appartment i am getting warnings and errors using the miio binding and roborock s7.
I got a new internet / WLAN router, however, i configured the same WLAN name and password. So the openhab RPI and roborock connect directly to the WLAN.
Strange thing is that the roborock values / items are available in openhab and they are changing correct. But the thing is changing from offline to online all the time and i am not getting an updated cleaning map. These are the values i get in the log:

2022-10-31 12:09:12.057 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:10:15.399 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:11:42.006 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:13:12.072 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:15:11.643 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'miio:generic:1BC50A3B' changed from ONLINE to OFFLINE (CONFIGURATION_ERROR)
2022-10-31 12:15:11.670 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing 'miio:generic:1BC50A3B' changed from OFFLINE (CONFIGURATION_ERROR) to ONLINE
2022-10-31 12:15:42.078 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:17:12.083 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:18:42.087 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:20:12.047 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016
2022-10-31 12:21:42.020 [INFO ] [miio.internal.cloud.MiCloudConnector] - Error logging on to Xiaomi cloud (0): Error getting logon location URL. Return code: 70016

I am using openHab 3.2 on a RPI 3b+.
I am using the Xiaomi Home App and read the token again. Device ID and Token didnt change compared to the thing configuration.

Can someone help?
Thank you!

The error is typically related to problems logging on to the cloud.
This is also why getting the map may be difficult.

Resolving cloud login problems is unfortunately not straightforward.
Sometimes it helps to reset your xiaomi cloud password or simply restarting opeenhab

1 Like

Hi marcel, unfortunately no luck. I changed the password and restarted openhab. No change. Any other suggestion what to do? :frowning:

Edit: forgot to change the login details in the binding settings… now i do have the map in openhab :slight_smile:

1 Like

Hi Guys,

first off thanks to @Tetsuo for this Widget nice work :+1:

I’m trying to adopt it for my ecovas Deebot. I got everything done and working fine. Just got one problem with the area cleaning. I got no numbers for the room i got letters. My skills are just to low to figure out how to send the correct command.

If i select a room i need to send the command: “spotArea:A;B;C” and so on…

Here is the part that’s needs attention:

    - component: oh-repeater
      config:
        sourceType: range
        for: i
        rangeStart: 0
        rangeStop: =JSON.parse(props.rooms).length / props.chunkSize
        fragment: true
        visible: =items[props.itemPrefix+"_State"].state !== "cleaning"
      slots:
        default:
          - component: f7-row
            config: {}
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: roomChunk
                    in: =JSON.parse(props.rooms).slice(loop.i * props.chunkSize, props.chunkSize * (loop.i + 1))
                    fragment: true
                  slots:
                    default:
                      - component: f7-col
                        slots:
                          default:
                            - component: f7-card
                              config:
                                style:
                                  height: 3rem
                                  line-height: 3rem
                              slots:
                                default:
                                  - component: f7-card-content
                                    config:
                                      style:
                                        padding: 0
                                        marging: 0
                                        height: 3rem
                                    slots:
                                      default:
                                        - component: oh-button
                                          config:
                                            iconF7: =loop.roomChunk.icon
                                            iconSize: 1.2em
                                            active: '=vars["clean" + loop.roomChunk.roomId] ? true : false'
                                            text: =loop.roomChunk.label
                                            large: true
                                            action: variable
                                            actionVariable: ="clean" + loop.roomChunk.roomId
                                            actionVariableValue: '=undefined === vars["clean" + loop.roomChunk.roomId] ? true : !vars["clean" + loop.roomChunk.roomId]'
                                            style:
                                              height: 3rem
                                              line-height: 3rem
                                              text-align: center
                                              font-size: 1.1em
    - component: f7-row
      config: {}
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: f7-card
                  slots:
                    default:
                      - component: f7-card-content
                        config:
                          style:
                            padding: 0
                        slots:
                          default:
                            - component: oh-button
                              config:
                                visible: =items[props.itemPrefix+"_State"].state !== "cleaning"
                                iconF7: map_pin_ellipse
                                iconSize: 1.2em
                                text: '=items[props.itemPrefix+"_State"].state === "cleaning" ? "Wird ausgeführt" : "Bereiche reinigen"'
                                large: true
                                action: command
                                actionItem: =props.itemPrefix+"_Command"
                                actionCommand: "='spotArea:' + ((vars.cleanA ? 'A';'') + (vars.cleanB ? 'B';'') + (vars.cleanC ? 'C';'') + (vars.cleanD ? 'D';'') + (vars.cleanD ? 'D';'') + (vars.cleanE ? 'E';'') + (vars.cleanF ? 'F';'') + (vars.cleanG ? 'G';'') + (vars.cleanH ? 'H';''))"
                                style:
                                  height: 2.5em
                                  line-height: 2.5em
                                  text-align: center
                                  font-size: 2em

My props for Room looks like this:

{"icon": "chat_bubble_2","roomId": "A","label": "Testraum1"},{"icon": "chat_bubble_2","roomId": "B","label": "Testraum2"},{"icon": "chat_bubble_2","roomId": "C","label": "Testraum3"},{"icon": "chat_bubble_2","roomId": "D","label": "Testraum4"},{"icon": "chat_bubble_2","roomId": "E","label": "Testraum5"},{"icon": "chat_bubble_2","roomId": "F","label": "Testraum6"},{"icon": "chat_bubble_2","roomId": "G","label": "Testraum7"},{"icon": "chat_bubble_2","roomId": "H","label": "Testraum8"}]

i think the problem is that this script use calculation for the room numbers and i use letters :frowning:

Thanks for the help
Cheers

Hey @mari0,

glad you like it - and I hope I can help you.

I’m not calculating anything by roomId, so it should work with the letters as well.

Not had much time to look at the code, but from a first sight, I think the error is in the “calculation” of your command:

actionCommand: "='spotArea:' + ((vars.cleanA ? 'A';'') + (vars.cleanB ? 'B';'') + (vars.cleanC ? 'C';'') + (vars.cleanD ? 'D';'') + (vars.cleanD ? 'D';'') + (vars.cleanE ? 'E';'') + (vars.cleanF ? 'F';'') + (vars.cleanG ? 'G';'') + (vars.cleanH ? 'H';''))"

Just looking at the small part

spotArea:' + ((vars.cleanA ? 'A';'') + (vars.cleanB ? 'B';'')

would mean, that if vars.cleanA and vars.cleanB is true the result will be

spotArea:AB

if not an error in calculation.
In my opinion would be correct:

spotArea:' + ((vars.cleanA ? 'A;':'') + (vars.cleanB ? 'B;':'')

So the true option is not just the letter, but always a letter and ;. and the true and false options are seperated by : instead.

You need to change that in the whole line, but afterwards it should work.

Hope that helps
Tetsuo

Edit: Link to shorthand if statement might help to better understand the syntax of this “command-calculation”: Java Short Hand If...Else (Ternary Operator)
Edit 2: Be aware that I linked to Java instead of JavaScript but the syntax is identical.

Just had some more time to look at it - maybe you try to replace just this one line:

actionCommand: "='spotArea:' + ((vars.cleanA ? 'A;':'') + (vars.cleanB ? 'B;':'') + (vars.cleanC ? 'C;':'') + (vars.cleanD ? 'D;':'') + (vars.cleanD ? 'D;':'') + (vars.cleanE ? 'E;':'') + (vars.cleanF ? 'F;':'') + (vars.cleanG ? 'G;':'') + (vars.cleanH ? 'H;':''))"

i’m trying to find a room unfortunately i have a problem with Execute_Command has anyone used it in xiaomi mi robot vacuum mop 2 pro or is able to help me? I don’t know what I’m doing wrong anymore ?

I have a good connection… becomes Execute Command - app_segment_clean
Unfortunately, the vacuum cleaner does not respond.
I found information roomid max 255… I tried a lot of options unfortunately to no avail

uid: tetsuo-repo-oh3-widget-vacuum
tags:
  - vacuum
  - room
  - map
  - control
props:
  parameters:
    - description: Prefix of item names. Look in your items for e.g. _CleaningMap and use everything before the underscore as prefix
      label: Item prefix
      name: itemPrefix
      required: true
      type: TEXT
    - description: 'json array with key value rooms like this [{"icon": "chat_bubble_2","roomId": 16,"label": "Roomname"}]'
      label: Rooms
      name: rooms
      required: true
      type: TEXT
    - description: Number of buttons for each row
      label: Chunk size
      name: chunkSize
      required: false
timestamp: Dec 29, 2022, 4:24:48 PM
component: f7-block
config: {}
slots:
  default:
    - component: f7-row
      config: {}
      slots:
        default:
          - component: f7-block
            config:
              style:
                - width: 75%
                - margin: 0
                - padding: 0
            slots:
              default:
                - component: oh-image-card
                  config:
                    item: =props.itemPrefix+"Cleaning_Map"
                    hidden: =items[props.itemPrefix+"Cleaning_Map"] === undefined
                    style:
                      borderRadius: 2em
          - component: f7-block
            config:
              style:
                - width: 25%
                - margin: auto
                - padding: 0
            slots:
              default:
                - component: f7-gauge
                  config:
                    style:
                      - width: 100%
                      - height: 100%
                    value: =(items[props.itemPrefix+"Battery"].state/100)
                    valueText: =(items[props.itemPrefix+"Battery"].state) + "%"
                    valueTextColor: '=items[props.itemPrefix+"Battery"].state < 25 ? "#f32617" : items[props.itemPrefix+"Battery"].state < 60 ? "#ffe81e" : "#6ec071"'
                    borderWidth: 18
                    labelText: '=items[props.itemPrefix+"Vacuum_Action"].state !== "dock"? "Bateria" : "Wird aufgeladen"'
                    borderColor: '=items[props.itemPrefix+"Battery"].state < 25 ? "#f32617" : items[props.itemPrefix+"Battery"].state < 60 ? "#ffe81e" : "#6ec071"'
                - component: oh-trend
                  config:
                    trendItem: =props.itemPrefix+"Battery"
                    trendStrokeWidth: 2
                    trendGradient:
                      - "#6ec071"
                    style:
                      --f7-theme-color-bg-color: transparent
                      background: transparent
                      filter: opacity(20%)
                      width: 100%
                      height: 100%
                      top: 0
                      left: 0
                      z-index: 0
                - component: f7-card
                  slots:
                    default:
                      - component: f7-card-content
                        slots:
                          default:
                            - component: f7-card-header
                              slots:
                                default:
                                  - component: Label
                                    config:
                                      text: '=items[props.itemPrefix+"Vacuum_Action"].state === "vacuum" ? "Dauer" : "Czas trwania"'
                                      style:
                                        - fontWeight: 100
                                        - color: rgb(136, 136, 136)
                            - component: Label
                              config:
                                text: =items[props.itemPrefix+"Clean_time"].state
                                style:
                                  height: 2.5em
                                  line-height: 2.5em
                                  text-align: center
                                  color: var(--f7-theme-color)
                                  font-weight: bold
                                  font-size: 2em
                            - component: f7-progressbar
                              config:
                                visible: =items[props.itemPrefix+"Vacuum_Action"].state === "vacuum"
                                infinite: true
                                class: color-blue
    - component: f7-row
      config:
        visible: =items[props.itemPrefix+"Vacuum_Action"].state !== "vacuum"
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: f7-card
                  slots:
                    default:
                      - component: f7-card-header
                        slots:
                          default:
                            - component: Label
                              config:
                                text: Akcja
                                style:
                                  - fontWeight: 100
                                  - color: rgb(136, 136, 136)
                      - component: f7-card-content
                        slots:
                          default:
                            - component: oh-button
                              config:
                                style:
                                  height: 2.5em
                                  line-height: 2.5em
                                  font-size: 2em
                                text: =items[props.itemPrefix+"Vacuum_Action"].displayState
                                large: true
                                action: options
                                actionItem: =props.itemPrefix+"Vacuum_Action"
                                item: =props.itemPrefix+"Vacuum_Action"
          - component: f7-col
            slots:
              default:
                - component: f7-card
                  slots:
                    default:
                      - component: f7-card-header
                        slots:
                          default:
                            - component: Label
                              config:
                                text: Moc
                                style:
                                  - fontWeight: 100
                                  - color: rgb(136, 136, 136)
                      - component: f7-card-content
                        slots:
                          default:
                            - component: oh-button
                              config:
                                style:
                                  height: 2.5em
                                  line-height: 2.5em
                                  font-size: 2em
                                text: =items[props.itemPrefix+"suction_grade"].displayState
                                large: true
                                action: options
                                actionItem: =props.itemPrefix+"suction_grade"
                                item: =props.itemPrefix+"suction_grade"
    - component: oh-repeater
      config:
        sourceType: range
        for: i
        rangeStart: 0
        rangeStop: =JSON.parse(props.rooms).length / props.chunkSize
        fragment: true
        visible: =items[props.itemPrefix+"Vacuum_Action"].state !== "vacuum"
      slots:
        default:
          - component: f7-row
            config: {}
            slots:
              default:
                - component: oh-repeater
                  config:
                    for: roomChunk
                    in: =JSON.parse(props.rooms).slice(loop.i * props.chunkSize, props.chunkSize * (loop.i + 1))
                    fragment: true
                  slots:
                    default:
                      - component: f7-col
                        slots:
                          default:
                            - component: f7-card
                              config:
                                style:
                                  height: 3rem
                                  line-height: 3rem
                              slots:
                                default:
                                  - component: f7-card-content
                                    config:
                                      style:
                                        padding: 0
                                        marging: 0
                                        height: 3rem
                                    slots:
                                      default:
                                        - component: oh-button
                                          config:
                                            iconF7: =loop.roomChunk.icon
                                            iconSize: 1.2em
                                            active: '=vars["clean" + loop.roomChunk.roomId] ? true : false'
                                            text: =loop.roomChunk.label
                                            large: true
                                            action: variable
                                            actionVariable: ="clean" + loop.roomChunk.roomId
                                            actionVariableValue: '=undefined === vars["clean" + loop.roomChunk.roomId] ? true : !vars["clean" + loop.roomChunk.roomId]'
                                            style:
                                              height: 3rem
                                              line-height: 3rem
                                              text-align: center
                                              font-size: 1.1em
    - component: f7-row
      config: {}
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: f7-card
                  slots:
                    default:
                      - component: f7-card-content
                        config:
                          style:
                            padding: 0
                        slots:
                          default:
                            - component: oh-button
                              config:
                                visible: =items[props.itemPrefix+"Vacuum_Action"].state !== "vacuum"
                                iconF7: rocket
                                iconSize: 1.2em
                                text: '=items[props.itemPrefix+"Vacuum_Action"].state === "vacuum" ? "Wird ausgeführt" : "Rozpocznij"'
                                large: true
                                action: command
                                actionItem: =props.itemPrefix+"Execute_Command"
                                actionCommand: "='app_segment_clean[' + ((vars.clean16 ? '16,': '') + (vars.clean17 ? '17,': '') + (vars.clean18 ? '18,': '') + (vars.clean19 ? '19,': '') + (vars.clean20 ? '20,': '') + (vars.clean21 ? '21,': '') + (vars.clean22 ? '22,': '') + (vars.clean23 ? '23,': '') + (vars.clean24 ? '24,': '')).slice(0, -1) + ']'"
                                style:
                                  height: 2.5em
                                  line-height: 2.5em
                                  text-align: center
                                  font-size: 2em
                            - component: oh-button
                              config:
                                visible: =items[props.itemPrefix+"Vacuum_Action"].state === "vacuum"
                                iconF7: stop_circle
                                iconSize: 1.2em
                                text: Zurück zum Dock
                                large: true
                                action: command
                                actionItem: =props.itemPrefix+"Execute_Command"
                                actionCommand: ='app_charge'
                                style:
                                  height: 2.5em
                                  line-height: 2.5em
                                  text-align: center
                                  font-size: 2em

Just figured it out how to send the room details to the Xiaomi Robot Mop 2S (thats to this and this post) , maybe it helps you as well.

actionItem: =props.itemPrefix+"_Execute_Command"
actionCommand: ='action{"siid":7,"aiid":3,"in":[{"piid":24,"value":"' + ((vars.clean10 ? "10,":"") + (vars.clean11 ? "11,":"")).slice(0, -1) + '"},{"piid":25,"value":0},{"piid":26,"value":1}]}'

@Tetsuo I needed to change .state to .displayState for the condition checks to work, e.g. text: '=items[props.itemPrefix+"_Status"].displayState === "Sweeping" ? "Wird ausgeführt" : "Ausführen"' instead of text: '=items[props.itemPrefix+"_Status"].state === "Sweeping" ? "Wird ausgeführt" : "Ausführen"', otherwise I would always see “Ausführen” (in this example).

Hello friend!
Tetsuo has moved on from openHAB so this widget is no longer getting updates unfortunately.

Well, I’m no developer but I can leave some hints if anyone is lost:
When configuring the widget, check all of your items and make sure they all begin with the same string, e.g.: “RoborockS6MaxV_BatteryLevel” and “RoborockS6MaxV_FanPower”.

Because the first thing you’ll configure is the “item prefix” and if you have different items with different prefixes it won’t work.

Additionally, to map the rooms and names you’ll want to follow this format:
[{“icon”: “chat_bubble_2”,“roomId”: 16,“label”: “Hallway”},{“icon”: “chat_bubble_2”,“roomId”: 17,“label”: “Kitchen”},{“icon”: “chat_bubble_2”,“roomId”: 18,“label”: “Bathroom”},{“icon”: “chat_bubble_2”,“roomId”: 19,“label”: “Living Room”}]

Replace the names for the ones you get, copy and paste to the widget config and you’re done.

Additionally, all of the items are hard coded in the widget. When it works it’s great, but when it doesn’t you need to edit the code of the widget, for example, I had to change the item name for battery because the widget is in German, and the item name mapped was “BatterieLandung”. Changed it to the name of my item “BatteryLevel” and all was good. If you like to edit channel names, I’m sorry to say you’ll probably have to do this on all of them.

I’m now considering translating the fields to English since I’m going to use this anyway. I’ll share it later here.

If anyone is interested in further developing this widget, I have an idea I’d like to see implemented: add the possibility of using the repeat function to tell the robot to clean the same room multiple times (seems like the limit is 3).

Anyone has a Xiaomi Vacuum X10+ running?

– Used “create support” according to the wiki page:
test-dreame.vacuum.p2114a-20231009-162035.txt (58.7 KB)

  • Channels are fine, getting data and I can start & stop the vacuum and change mode,…

MISSING: Is there any chance that I can get map-channel (as an image) or room channel added somehow? Dont know what to do with map-frame-info (NULL), map_extended_data (NULL) and map_mult_map_info ({“object_name”:“…”,“md5”:“…”})

map support for dreame… This is an open request, but currently no progress.

@marchino started some investigations in this area
https://community.openhab.org/t/xiaomi-miio/147365/6