From 3eef6fda59b5a98bfe5c36b30d640fec390e2910 Mon Sep 17 00:00:00 2001 From: Facu Date: Sun, 5 Dec 2021 11:55:27 -0300 Subject: [PATCH] Support get robot password from Cloud. thanks mjg59! --- .eslintrc.json | 2 +- README.md | 63 +++++++++++++++++++---- bin/getPasswordCloud.js | 111 ++++++++++++++++++++++++++++++++++++++++ lib/v2/local.js | 2 +- package.json | 8 +-- 5 files changed, 172 insertions(+), 14 deletions(-) create mode 100644 bin/getPasswordCloud.js diff --git a/.eslintrc.json b/.eslintrc.json index b6802e7..d1016a7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,7 @@ "standard" ], "rules": { - "complexity": ["warn", 10], + "complexity": 0, "max-depth": ["warn", 4], "no-unused-vars": ["warn", { "vars": "all", "args": "after-used" }] } diff --git a/README.md b/README.md index 9d45846..c5b8ffa 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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 @@ -141,10 +138,57 @@ 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 [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 [Optional API-Key] +``` + +** Option 3 ** + +Docker run command: + +``` +docker run -it node sh -c "npm install -g dorita980 && get-roomba-password-cloud " +``` +** Example Output ** + +``` +$ npm install -g dorita980 +$ get-roomba-password-cloud myemail@example.com 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 :) +``` + +
+ Show old firmwares method (local call) + +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 @@ -152,7 +196,7 @@ $ npm install -g dorita980 $ get-roomba-password ``` -** Option 2 ** +** Local Option 2 ** Clone the repo and then run the npm script: @@ -163,7 +207,7 @@ $ npm install $ npm run getpassword ``` -** Option 3 ** +** Local Option 3 ** Docker run command: @@ -171,7 +215,7 @@ Docker run command: docker run -it node sh -c "npm install -g dorita980 && get-roomba-password " ``` -** Example Output ** +** Example Output in local method ** ``` $ npm install -g dorita980 @@ -194,6 +238,7 @@ Password=> :1:1486937829:gktkDoYpWaDxCfGh <= Yes, all this string. Use this credentials in dorita980 lib :) ``` +
### Troubleshoot - Getting the password @@ -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 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!) diff --git a/bin/getPasswordCloud.js b/bin/getPasswordCloud.js new file mode 100644 index 0000000..affbee0 --- /dev/null +++ b/bin/getPasswordCloud.js @@ -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 [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); + } +} + diff --git a/lib/v2/local.js b/lib/v2/local.js index efaca58..1304d3a 100644 --- a/lib/v2/local.js +++ b/lib/v2/local.js @@ -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), diff --git a/package.json b/package.json index 0dc9be4..d012e5e 100644 --- a/package.json +++ b/package.json @@ -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": { @@ -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",