Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for 600 Wifi enabled series / other Roombas #71

Closed
ahorseman opened this issue Sep 13, 2018 · 21 comments
Closed

Support for 600 Wifi enabled series / other Roombas #71

ahorseman opened this issue Sep 13, 2018 · 21 comments

Comments

@ahorseman
Copy link

Hello,

I wanted to ask whether you guys are also planning to support other Roombas than just the 980?

The Wifi enabled 600 series (currently on a firmware 3.x) would also be interesting to support, as they are much more for the mass market (given the price) and I would be happy to help discovering supported features and requests.

Is there a way to get an API overview of the robot's API (something like wsdl was for web services) that I can post here for enhancing (or forking) dorita980 for 600 series?

@koalazak
Copy link
Owner

koalazak commented Dec 3, 2018

the best way is reversing the mobile app and sniffing the netword trafic between the mobile app and roomba or cloud. I dont own a 600 robot to try.
Let me know if you start a 600's fork!
thanks!

@Zefau
Copy link

Zefau commented Dec 3, 2018

I don't own a Roomba 600 or any other with v3 firmware, but according to information in the ioBroker forum, the v3 software uses MQTT via port 8883.
See https://forum.iobroker.net/viewtopic.php?f=20&t=8092&p=199686#p199367

@Zefau
Copy link

Zefau commented Dec 3, 2018

@koalazak How are you sniffing the network traffic? What software are you using and how do you reverse?

@koalazak
Copy link
Owner

koalazak commented Dec 4, 2018

im sniffing with wireshark and charles proxy in mac. And for reversing the app I grab the .apk file from Android store and decompile it with online tools.

@crashf
Copy link

crashf commented Dec 18, 2018

Im not sure if this will help you or not, but, I spent some time sniffing packets with wireshark. Here is a dump of just traffic from/to the roomba 675. Opened the app and performed a "return to duck" request.

filtereddump-roomba675-fromrouter.zip

@crashf
Copy link

crashf commented Dec 18, 2018

I will also try to dump during the wireless setup etc later today. I am not great with python so if anyone is up for picking around let me know what else I can dump.

@koalazak
Copy link
Owner

koalazak commented Jan 4, 2019

Hi, sorry for the delay. That dumps are ssl encryted. Did you sign the trafic with your own CA? you need to do that to decrypt the dump content

@Jeff-Cortese
Copy link

Hi, I was able to get this library working with my Roomba 690 (firmware 3.2). A tip that might be useful is that you can get the Roomba's IP address from the iRobot HOME app by tapping More (...) > Settings > Wi-Fi Settings > Robot Wi-Fi Details. Using that IP, I could use the getpassword npm script to look up the blid and password (via checkV2() function in bin/getpassword.js).

With that...

const dorita980 = require('dorita980');
const myLocalRobot = new dorita980.Local('blid_here', 'password_here', 'ip_here');
myLocalRobot.on('connect', () => { console.log('connected'); });

...works as expected

@Zefau
Copy link

Zefau commented Jan 6, 2019

The connection works with Firmware v3.0, but no data is received as far as I know.
Do you have a running instance of ioBroker? I made an adapter for Roomba on this plattform (see https://github.com/Zefau/ioBroker.roomba).

Other users report, that a connection is successful with Firmware v3, but no data is received.

Are you able to execute any commands after connection or able to retrieve preferences?

Kind regards,
Zefau

@koalazak
Copy link
Owner

koalazak commented Jan 6, 2019

Hi @Jeff-Cortese, can you run this code and share the output please?

const dorita980 = require('dorita980');
const myLocalRobot = new dorita980.Local('blid_here', 'password_here', 'ip_here');
myLocalRobot.on('connect', () => { 
  console.log('connected'); 
  myLocalRobot.on('packetreceive', function (packet) {
    console.log(packet); 
  });
});

thank you!

@Jeff-Cortese
Copy link

Jeff-Cortese commented Jan 7, 2019

@Zefau I'm not sure what ioBroker is, so probably not if it's not a part of dorita and running as a side-effect of the code I posted earlier. And yes, a few commands did work (I have only tried start, pause, resume, and end).

@koalazak I tweaked it a little to format the packet payload buffer:

  const dorita980 = require('dorita980');
  const myLocalRobot = new dorita980.Local('blid_here', 'password_here', 'ip_here');

  myLocalRobot.on('connect', () => { 
    console.log('connected'); 
    myLocalRobot.on('packetreceive', packet =>  {
      packet.payload = JSON.parse(packet.payload);
      console.log(JSON.stringify(packet, null, 2));
    });
  });

The output is as follows (I redacted some info using X's because I'm not sure what is sensitive info).
Packets started to repeat, so I terminated it after about 10 seconds. I can run it longer if you'd like.

connected
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 182,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "netinfo": {
          "dhcp": true,
          "addr": xxxxxxxxxx,
          "mask": xxxxxxxxxx,
          "gw": xxxxxxxxxx,
          "dns1": xxxxxxxxxx,
          "dns2": xxxxxxxxxx,
          "bssid": "xxxxxxxxxx",
          "sec": 4
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 78,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "wifistat": {
          "wifi": 1,
          "uap": false,
          "cloud": 1
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 182,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "netinfo": {
          "dhcp": true,
          "addr": xxxxxxxxxx,
          "mask": xxxxxxxxxx,
          "gw": xxxxxxxxxx,
          "dns1": xxxxxxxxxx,
          "dns2": xxxxxxxxxx,
          "bssid": "xxxxxxxxxx",
          "sec": 4
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 84,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "wlcfg": {
          "sec": 7,
          "ssid": "XXXXXXXXXXXXXXXXXXXXXX"
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 60,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "mac": "XX:XX:XX:XX:XX:XX"
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 84,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "country": "US"
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 87,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "cloudEnv": "prod"
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 105,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "svcEndpoints": {
          "svcDeplId": "v007"
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 85,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "name": "Jarvis"
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 515,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "cap": {
          "ota": 1,
          "eco": 1,
          "svcConf": 1
        },
        "bbrun": {
          "nCliffsF": 261,
          "nPanics": 42,
          "hr": 7,
          "min": 58,
          "nScrubs": 74,
          "sqft": 0,
          "nStuck": 0,
          "nPicks": 0,
          "nCliffsR": 0,
          "nMBStll": 0,
          "nWStll": 0,
          "nCBump": 0
        },
        "bbmssn": {
          "aMssnM": 31,
          "nMssnF": 12,
          "nMssnOk": 13,
          "nMssn": 25,
          "nMssnC": 0,
          "aCycleM": 0
        },
        "bbpause": {
          "pauses": [0, 0, 18, 0, 0, 0, 0, 0, 0, 0]
        },
        "cleanSchedule": {
          "cycle": ["none", "start", "start", "start", "start", "start", "none"],
          "h": [0, 14, 14, 14, 14, 14, 9],
          "m": [0, 0, 0, 0, 0, 0, 0]
        },
        "language": 0
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 365,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "cleanMissionStatus": {
          "cycle": "none",
          "phase": "charge",
          "expireM": 0,
          "rechrgM": 0,
          "error": 0,
          "notReady": 0,
          "mssnM": 0,
          "sqft": 0,
          "initiator": "",
          "nMssn": 25
        },
        "dock": {
          "known": false
        },
        "bin": {
          "present": true,
          "full": false
        },
        "batteryType": "lith",
        "batPct": 100,
        "mobilityVer": "6985",
        "bootloaderVer": "4",
        "soundVer": "13"
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 531,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "langs": [
          { "en-US": 0 },
          { "en-GB": 15 },
          { "fr-FR": 1 },
          { "de-DE": 2 },
          { "es-ES": 3 },
          { "es-XL": 11 },
          { "pt-PT": 12 },
          { "pt-BR": 19 },
          { "it-IT": 4 },
          { "nl-NL": 5 },
          { "da-DK": 6 },
          { "sv-SE": 7 },
          { "nb-NO": 8 },
          { "fi-FI": 16 },
          { "pl-PL": 10 },
          { "cs-CZ": 17 },
          { "ru-RU": 18 },
          { "he-IL": 20 },
          { "ja-JP": 13 },
          { "zh-CN": 14 },
          { "zh-TW": 9 }
        ],
        "audio": {
          "active": false
        },
        "binPause": false,
        "carpetBoost": false,
        "noAutoPasses": false,
        "noPP": false,
        "openOnly": false,
        "twoPass": false,
        "vacHigh": false,
        "sku": "R690020",
        "timezone": "America/Chicago"
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 295,
  "topic": "$aws/things/XXXXXXXXXXXXXXXX/shadow/update",
  "payload": {
    "state": {
      "reported": {
        "tz": {
          "ver": 6,
          "events": [
            {
              "dt": 1541073600,
              "off": -300
            },
            {
              "dt": 1541314801,
              "off": -360
            },
            {
              "dt": 1552204801,
              "off": -300
            }
          ]
        },
        "ecoCharge": false,
        "wifiSwVer": "3.2.40+69",
        "softwareVer": "3.2.40+69",
        "hardwareRev": 2,
        "wifiAnt": 0,
        "schedHold": false
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 65,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "signal": {
          "rssi": -40,
          "snr": 46
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 65,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "signal": {
          "rssi": -43,
          "snr": 45
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 65,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "signal": {
          "rssi": -34,
          "snr": 56
        }
      }
    }
  }
}
{
  "cmd": "publish",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 65,
  "topic": "wifistat",
  "payload": {
    "state": {
      "reported": {
        "signal": {
          "rssi": -34,
          "snr": 56
        }
      }
    }
  }
}
{
  "cmd": "pingresp",
  "retain": false,
  "qos": 0,
  "dup": false,
  "length": 0,
  "topic": null,
  "payload": null
}

@koalazak
Copy link
Owner

koalazak commented Jan 7, 2019

Hi, @Jeff-Cortese, thanks a lot! this was very helpful.
I think the problem with the other features is that dorita980 is waiting for the pose state and your robot (600 series) is not reporting that postion, then dorita980 wait forever.
I will work on fix this, seems easy to do. If you want to test the fix just open node_modules/dorita980/lib/v2/local.js and remove the occurences of pose string or objects (like line 35, 36, 107, 109, etc)

thanks again guys,

@gik007
Copy link

gik007 commented Jan 7, 2019

Hi @koalazak,

im sniffing with wireshark and charles proxy in mac. And for reversing the app I grab the .apk file from Android store and decompile it with online tools.

I know that your project is focused on the 980 model (or it was like that at the beginning). I have another model (e5) and have tried to use your library without success. I have the impression that your implementation is close to working with that model, but I fail to get the password ("Error getting password. Follow the instructions and try again." which hints at a short response to the MQTT request. The response I get is "f005efcc3b2903", which is pretty close to the request your code sends to get the password.

I could try to reverse engineer the network traffic, but where should I start? Your implementation shows that you have understood pretty well what happens between client and server (at least for your model), do you have that information somewhere so that we can start creating an unofficial documentation of the communication used by the different roomba models?

Gracias!

@Zefau
Copy link

Zefau commented Jan 7, 2019

We discussed e5 support in Zefau/ioBroker.roomba#1. Remove "pose" from preferences worked here as well.

@gik007
Copy link

gik007 commented Jan 7, 2019

@Zefau thanks, that is a great hint. I just did that, unfortunately that didn't help to get the password. I wonder how other e5 users (like @kgerlich) have managed to get the password out of the device.

@gik007
Copy link

gik007 commented Jan 7, 2019

Good news. The error was sitting between keyboard and chair. I did not correctly understand the message about pressing the HOME button (I was pressing the "CLEAN" button). There was a message in another thread giving that hint and it was helpful. So I can confirm that things are working well on the e5. Thanks for making it possible!

@koalazak
Copy link
Owner

koalazak commented Jan 8, 2019

600 and e5 series supported in dorita980@3.1.0
thanks guys

@koalazak koalazak closed this as completed Jan 8, 2019
@kgerlich
Copy link