Skip to content

Commit

Permalink
Support get robot password from Cloud. thanks mjg59!
Browse files Browse the repository at this point in the history
  • Loading branch information
koalazak committed Dec 5, 2021
1 parent 206c003 commit 3eef6fd
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"standard"
],
"rules": {
"complexity": ["warn", 10],
"complexity": 0,
"max-depth": ["warn", 4],
"no-unused-vars": ["warn", { "vars": "all", "args": "after-used" }]
}
Expand Down
63 changes: 54 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ With this library you can send commands to your wifi enabled Roomba through the

See [rest980](https://github.com/koalazak/rest980) if you need a HTTP REST API interface.

## Help wanted to support J7 robot!

[Help here](https://github.com/koalazak/dorita980/issues/142)

# Advice

If you enjoy dorita980 and it works nice for you, I recommend blocking the internet access to your robot to avoid the OTA firmware updates. New firmware changes can cause dorita980 to stop working. Blocking firmware updates can be performed using the parental control options on your router.
Expand Down Expand Up @@ -64,6 +60,7 @@ Video: Realtime cleaning map using dorita980 lib in [rest980](https://github.com
| Get BLID and Password | yes | - | yes | - | yes |
| Support multiples clients at the same time | yes | yes | no | pending | no |

Note: some new firmwares are not reporting robot position ('pose' property) to local env.

# Install

Expand Down Expand Up @@ -141,18 +138,65 @@ function init () {

(Needed for Cloud and Local requests)

You need to know your robot IP address (look in your router or scan your LAN network with nmap to find it). Or use the `dorita980.getRobotIP()` method.
You need your iRobot account credentials (username and password).

** Option 1 **

Install `dorita980` globally and then run the `get-roomba-password-cloud` command:

```bash
$ npm install -g dorita980
$ get-roomba-password-cloud <iRobot Username> <iRobot Password> [Optional API-Key]
```

** Option 2 **

Clone the repo and then run the npm script:

```bash
$ git clone https://github.com/koalazak/dorita980.git
$ cd dorita980
$ npm install
$ npm run get-password-cloud <iRobot Username> <iRobot Password> [Optional API-Key]
```

** Option 3 **

Docker run command:

```
docker run -it node sh -c "npm install -g dorita980 && get-roomba-password-cloud <robotIP>"
```
** Example Output **

```
$ npm install -g dorita980
$ get-roomba-password-cloud [email protected] myeasypassword
Found 1 robot(s)!
Robot "Dorita" (sku: R98---- SoftwareVer: v2.4.16-126):
BLID=> xxxxxxxxxxxxx
Password=> :1:1486937829:gktkDoYpWaDxCfGh <= Yes, all this string.
Use this credentials in dorita980 lib :)
```

<details>
<summary>Show old firmwares method (local call)</summary>

This method stop working for latest firmwares. If you have problems using this method please use the cloud method.

You need to know your robot IP address (look in your router or scan your LAN network with nmap to find it). Or use the `dorita980.getRobotIP()` method.

** Local Option 1 **

Install `dorita980` globally and then run the `get-roomba-password` command:

```bash
$ npm install -g dorita980
$ get-roomba-password <robotIP>
```

** Option 2 **
** Local Option 2 **

Clone the repo and then run the npm script:

Expand All @@ -163,15 +207,15 @@ $ npm install
$ npm run getpassword <robotIP>
```

** Option 3 **
** Local Option 3 **

Docker run command:

```
docker run -it node sh -c "npm install -g dorita980 && get-roomba-password <robotIP>"
```

** Example Output **
** Example Output in local method **

```
$ npm install -g dorita980
Expand All @@ -194,6 +238,7 @@ Password=> :1:1486937829:gktkDoYpWaDxCfGh <= Yes, all this string.
Use this credentials in dorita980 lib :)
```
</details>

### Troubleshoot - Getting the password

Expand All @@ -202,7 +247,7 @@ Most common issues getting your password are related with:
- Mobile application is open: You must close iRobot mobile application on your phone. The robot only support ONE connection at time. You will get a connection error if this is the case.
- Other applications are using your robot: Close all your applications or scripts using the robot. Same as frist bullet.
- Network connectivity issues: Make sure your computer can reach your robot: `nc -zv <robot_ip> 8883` if this command fails check your network.
- Slow networks: On some slow networks you need to run the `get-roomba-password` a couple of times until you get it. This is because UDP packages may be lost.
- Slow networks using local method: On some slow networks you need to run the `get-roomba-password` a couple of times until you get it. This is because UDP packages may be lost.
- node.js version: Mostly tested on v10 but also works on v12, v14 and v16. Try using v10.
- Wrong button: It is really common people touching CLEAN button on 980 robots instead of HOME button when prompted. Make sure you are pressing the correct button. Some model (like 675) do not have HOME button and you need to press DOCK+SPOT.
- Make sure your robot is docked on the Home Base and powered on (short press Clean button once to turn it on. But do not start a cleaning session!)
Expand Down
111 changes: 111 additions & 0 deletions bin/getPasswordCloud.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env node

'use strict';

const request = require('request');

if (!process.argv[2] || !process.argv[3]) {
console.log('Usage: npm run get-password-cloud <iRobot username> <iRobot password> [Gigya API Key]');
process.exit();
}

const username = process.argv[2];
const password = process.argv[3];
const apiKey = process.argv[4] || process.env.GIGYA_API_KEY || '3_rWtvxmUKwgOzu3AUPTMLnM46lj-LxURGflmu5PcE_sGptTbD-wMeshVbLvYpq01K';

const gigyaLoginOptions = {
'method': 'POST',
'uri': 'https://accounts.us1.gigya.com/accounts.login',
'json': true,
'qs': {
'apiKey': apiKey,
'targetenv': 'mobile',
'loginID': username,
'password': password,
'format': 'json',
'targetEnv': 'mobile'
},
'headers': {
'Connection': 'close'
}
};

request(gigyaLoginOptions, loginGigyaResponseHandler);

function loginGigyaResponseHandler (error, response, body) {
if (error) {
console.log('Fatal error login into Gigya API. Please check your credentials or Gigya API Key.');
console.log(error);
process.exit(1);
}

if (response.statusCode === 401 || response.statusCode === 403) {
console.log('Authentication error. Check your credentials.');
console.log(response);
process.exit(1);
} else if (response.statusCode === 400) {
console.log(response);
process.exit(1);
} else if (response.statusCode === 200) {
if (body && body.statusCode && body.statusCode === 403) {
console.log('Authentication error. Please check your credentials.');
console.log(body);
process.exit(1);
}
if (body && body.statusCode && body.statusCode === 400) {
console.log('Error login into Gigya API.');
console.log(body);
process.exit(1);
}
if (body && body.statusCode && body.statusCode === 200 && body.errorCode === 0 && body.UID && body.UIDSignature && body.signatureTimestamp && body.sessionInfo && body.sessionInfo.sessionToken) {
const iRobotLoginOptions = {
'method': 'POST',
'uri': 'https://unauth2.prod.iot.irobotapi.com/v2/login',
'json': true,
'body': {
'app_id': 'ANDROID-C7FB240E-DF34-42D7-AE4E-A8C17079A294',
'assume_robot_ownership': 0,
'gigya': {
'signature': body.UIDSignature,
'timestamp': body.signatureTimestamp,
'uid': body.UID
}
},
'headers': {
'Connection': 'close'
}
};
request(iRobotLoginOptions, loginIrobotResponseHandler);
} else {
console.log('Error login into iRobot account. Missing fields in login response.');
console.log(body);
process.exit(1);
}
} else {
console.log('Unespected response. Checking again...');
}
}

function loginIrobotResponseHandler (error, response, body) {
if (error) {
console.log('Fatal error login into iRobot account. Please check your credentials or API Key.');
console.log(error);
process.exit(1);
}
if (body && body.robots) {
const robotCount = Object.keys(body.robots).length;
console.log('Found ' + robotCount + ' robot(s)!');
Object.keys(body.robots).map(function (r) {
console.log('Robot "' + body.robots[r].name + '" (sku: ' + body.robots[r].sku + ' SoftwareVer: ' + body.robots[r].softwareVer + '):');
console.log('BLID=> ' + r);
console.log('Password=> ' + body.robots[r].password + ' <= Yes, all this string.');
console.log('');
});
console.log('Use this credentials in dorita980 lib :)');
} else {
console.log('Fatal error login into iRobot account. Please check your credentials or API Key.');
console.log(body);
process.exit(1);
}
}

2 changes: 1 addition & 1 deletion lib/v2/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ var dorita980 = function localV2 (user, password, host, emitIntervalTime) {
getWeek: () => waitPreferences(false, ['cleanSchedule'], true),
getPreferences: (decode) => waitPreferences(decode, ['cleanMissionStatus', 'cleanSchedule', 'name', 'vacHigh', 'signal'], false),
getRobotState: (fields) => waitPreferences(false, fields, false),
getMission: (decode) => waitPreferences(decode, ['cleanMissionStatus', 'pose', 'bin', 'batPct'], true),
getMission: (decode) => waitPreferences(decode, ['cleanMissionStatus', 'bin', 'batPct'], true),
getBasicMission: (decode) => waitPreferences(decode, ['cleanMissionStatus', 'bin', 'batPct'], true),
getWirelessConfig: () => waitPreferences(false, ['wlcfg', 'netinfo'], true),
getWirelessStatus: () => waitPreferences(false, ['wifistat', 'netinfo'], true),
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dorita980",
"version": "3.1.10",
"version": "3.1.11",
"description": "Unofficial iRobot Roomba 980 and wifi other enabled series library sdk",
"main": "./index.js",
"directories": {
Expand All @@ -13,10 +13,12 @@
"test:coverage:run": "istanbul cover _mocha -- $npm_package_config_mocha",
"test:coverage:check": "istanbul check-coverage --functions 80",
"test:coverage": "npm run test:coverage:run && npm run test:coverage:check",
"getpassword": "node ./bin/getpassword.js"
"getpassword": "node ./bin/getpassword.js",
"get-password-cloud": "node ./bin/getPasswordCloud.js"
},
"bin": {
"get-roomba-password": "./bin/getpassword.js"
"get-roomba-password": "./bin/getpassword.js",
"get-roomba-password-cloud": "./bin/getPasswordCloud.js"
},
"repository": {
"type": "git",
Expand Down

0 comments on commit 3eef6fd

Please sign in to comment.