koalazak / dorita980

Unofficial iRobot Roomba and Braava (i7/i7+, 980, 960, 900, e5, 690, 675, m6, etc) node.js library (SDK) to control your robot
MIT License
942 stars 150 forks source link

roomba 980 firmware 2.0.0-34 ready? #10

Closed koalazak closed 7 years ago

koalazak commented 7 years ago

What about this new firmware update? Does anyone here upgrade their roomba? I heard that the new firmware no longer listens on port 443. For now I recommend deny internet access to your roomba to keep v1.6.6 and enjoy dorita980.

iosdeveloper commented 7 years ago

Maybe there is difference between holding only the Wi-Fi button (same password?) and holding both the Wi-Fi and the home button (new password?).

jb-home commented 7 years ago

For me the password changed sometime ago. I am not absolutely sure how it happened. I think I changed my home WiFi SSID so I had to reconnect the robot to a new network. It was just an idea, what might have happened.

koalazak commented 7 years ago

ok, im connected and getting data now :) you dont believe that: The password is in the :1:number:pass format and the number is not a timestamp generated at connection time. Its generated when you connect the roomba for the first time to a wifi, and continues hardcoded as part of the password forever. (I try everything (generatng the timestamp) but I never tried a password exaclty as i see in the sniff data hahaha)

@iosdeveloper, @JensBonse the password changes when you connect to another wifi. but not when press home for 2 seconds.

Im going to my real work :p. Today later I will continue with this.

thanks guys!

jb-home commented 7 years ago

So I kind of pushed you in the right direction ;)

fgomecs commented 7 years ago

You both rule! :) Go to work... cya later on (I will do the same)

Sent from my iPhone

On Feb 13, 2017, at 7:46 AM, JensBonse notifications@github.com wrote:

So I kind of pushed you in the right direction ;)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

thoro commented 7 years ago

For anyone interested, here's the full state reported for $aws/things/MY_ROBOT_ID/shadow/update

{ state:
   { reported:
      { country: 'US',
        cloudEnv: 'prod',
        svcEndpoints: { svcDeplId: 'v006' },
        batPct: 9,
        dock: { known: true },
        bin: { present: true, full: false },
        audio: { active: false },
        cleanMissionStatus:
         { cycle: 'quick',
           phase: 'charge',
           expireM: 90,
           rechrgM: 73,
           error: 0,
           notReady: 0,
           mssnM: 88,
           sqft: 386,
           initiator: 'rmtApp',
           nMssn: 60 },
        language: 0,
        noAutoPasses: false,
        noPP: false,
        ecoCharge: false,
        vacHigh: false,
        binPause: false,
        carpetBoost: true,
        openOnly: false,
        twoPass: false,
        schedHold: false,
        lastCommand: { command: 'resume', time: 1487008413, initiator: 'rmtApp' },
        langs:
         [ { 'en-UK': 0 },
           { 'fr-FR': 1 },
           { 'es-ES': 2 },
           { 'it-IT': 3 },
           { 'de-DE': 4 },
           { 'ru-RU': 5 } ],
        bbnav: { aMtrack: 97, nGoodLmrks: 7, aGain: 51, aExpo: 92 },
        bbpanic: { panics: [ 8, 8, 1, 8, 11 ] },
        bbpause: { pauses: [ 2, 0, 0, 13, 0, 6, 16, 0, 2, 2 ] },
        bbmssn:
         { nMssn: 59,
           nMssnOk: 20,
           nMssnC: 32,
           nMssnF: 6,
           aMssnM: 21,
           aCycleM: 22 },
        bbrstinfo: { nNavRst: 9, nMobRst: 0, causes: '0000' },
        cap: { pose: 1, ota: 2, multiPass: 2 },
        sku: 'R960040',
        batteryType: 'li26',
        soundVer: '32',
        uiSwVer: '4582',
        navSwVer: '01.09.09',
        wifiSwVer: '20902',
        mobilityVer: '5309',
        bootloaderVer: '4042',
        umiVer: '5',
        softwareVer: 'v2.0.0-34',
        tz:
         { events: [ { dt: 0, off: 60 }, { dt: 0, off: 120 }, { dt: 0, off: 0 } ],
           ver: 2 },
        timezone: 'Europe/Vienna',
        name: 'Staubi',
        cleanSchedule:
         { cycle: [ 'none', 'start', 'start', 'start', 'start', 'start', 'none' ],
           h: [ 9, 9, 9, 9, 9, 9, 0 ],
           m: [ 0, 0, 0, 0, 0, 0, 0 ] },
        bbchg3:
         { avgMin: 435,
           hOnDock: 944,
           nAvail: 78,
           estCap: 7451,
           nLithChrg: 24,
           nNimhChrg: 0,
           nDocks: 22 },
        bbchg: { nChgOk: 22, nLithF: 0, aborts: [ 0, 0, 0 ] },
        bbswitch: { nBumper: 21981, nClean: 84, nSpot: 11, nDock: 22, nDrops: 146 },
        bbrun:
         { hr: 27,
           min: 52,
           sqft: 109,
           nStuck: 13,
           nScrubs: 8,
           nPicks: 160,
           nPanics: 56,
           nCliffsF: 308,
           nCliffsR: 642,
           nMBStll: 5,
           nWStll: 0,
           nCBump: 0 },
        bbsys: { hr: 1006, min: 54 } } } }

Edit: also there's maximum 1 connection at any time, so if your app is connected, the mobile app only works via cloud access

rwscott1961 commented 7 years ago

On Mon, 2017-02-13 at 04:25 -0800, Facu ZAK wrote:

ok, im connected and getting data now :) you dont believe that: The password is in the :1:number:pass format and the number is not a timestamp generated at connection time. Its generated whe you connect the roomba for the first time to a wifi, and continues hardcoded as part of the password every time. (I try everything (generatng the timestamp) but I never tried a password exaclty as i see in the sniff data hahaha)

@iosdeveloper, @JensBonse the password changes when you connect to other wifi. but not when press home for 2 seconds.

When you say the password changes, do you mean the "number" part, the "pass" part, or both?

Im going to my real work :p today later i will continue with this.

thanks guys!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

rwscott1961 commented 7 years ago

I'm guessing that this timestamp is not the same as the one used for the cloud communications.

I have still not managed to get a successful sslsnif to work. in tcp mode it connects right up, but all of the logs are encrypted. In ssl, or https, mode I get:

Connecting to [192.168.1.102]:8883 ===> Original server certificate: Subject DN: /C=US/O=iRobot/L=Bedford/ST=MA/CN=Roomba-3107462000221890 Common Names: Roomba-3107462000221890 Fingerprint: A3:2C:D7:7D:B4:46:3A:0B:69:7B7C:FD:AC:1D:A2:F7:8B:D4:85:67 Certificate cache: MISS ===> Forged server certificate: Subject DN: /C=US/O=iRobot/L=Bedford/ST=MA/CN=Roomba-3107462000221890 Common Names: Roomba-3107462000221890 Fingerprint: 9D:4A:FC:5D:06:17:A4:9C:25:6D82:F6:6F:0B:CA:43:A0:71:BD:8A SSL connected to [192.168.1.102]:8883 TLSv1.2 DHE-RSA-AES256-SHA256 Received privsep req type 01 sz 109 on srvsock 9 Error from bufferevent: 0:- 336151574:1046:sslv3 alert certificate unknown:20:SSL routines:148:SSL3_READ_BYTES SSL disconnected to [192.168.1.102]:8883 SSL disconnected from [192.168.1.101]:52849

Has anyone done a successful sniff with the android app??

On Mon, 2017-02-13 at 04:25 -0800, Facu ZAK wrote:

ok, im connected and getting data now :) you dont believe that: The password is in the :1:number:pass format and the number is not a timestamp generated at connection time. Its generated whe you connect the roomba for the first time to a wifi, and continues hardcoded as part of the password every time. (I try everything (generatng the timestamp) but I never tried a password exaclty as i see in the sniff data hahaha)

@iosdeveloper, @JensBonse the password changes when you connect to other wifi. but not when press home for 2 seconds.

Im going to my real work :p today later i will continue with this.

thanks guys!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

koalazak commented 7 years ago

Hi @rwscott1961 Im not sure but I think both change. I use iOS :/

koalazak commented 7 years ago

Hi everyone! dorita980 v3.0 released! and support firmware 2.0.0 for local mqtt API. I preserve the old methods and add others taking advantage of the new mqtt API. Also add some events to handle all the new data.

To upgrade change your package.json to use dorita980: "^3.0.0" then npm update in your project.

TODO:

I will close this issue and open a new one for getPassword in firmware 2.0.0 and other for Cloud API

thanks for everyone!

sheppy99 commented 7 years ago

Very very well done - thanks everyone!!

fgomecs commented 7 years ago

Awesome!

Sent from my iPhone

On Feb 14, 2017, at 4:15 PM, Facu ZAK notifications@github.com wrote:

Hi everyone! dorita980 v3.0 released! and support fireware 2.0.0 for local mqtt API. I preserve the old methods and add others taking advantage of the new mqtt API. Also add some events to handle all the new data.

To upgrade, change your package.json to use dorita980: "^3.0.0" then npm update in your project.

TODO:

getPassword Cloud API I will close this issue and open a new one for getPassword in firmware 2.0.0 and other for Cloud API

thanks for everybody!

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

iosdeveloper commented 7 years ago

Yay! Do you even sleep? Jk, thanks a lot 🎉👍

sheppy99 commented 7 years ago

All working again ;-) Question, is it possible to leave it connected and bridge the MQTT traffic to a local MQTT server and control it by just sending MQTT commands via the bridge? Presumably the IOS app will then just go via the cloud? Right now I poll it every minute and wonder if there is a better way

iosdeveloper commented 7 years ago

Where is the end() method as mentioned in the v2 readme defined?

koalazak commented 7 years ago

@sheppy99 you can leave dorita980 connected forever without calling end() method. Meanwhile is connected you can call other methods to send commands and listen for the events to get data. Just not call .end() method. And meanwhile de iOs app will then just go via the cloud.

@iosdeveloper Is inherited from the tls connection.

sheppy99 commented 7 years ago

Thanks, do you reckon the MQTT broker can be bridged to another? I've tried to connect to it with my username and password on port 8883 with TLS turned on with MQTT.fx It doesn't work. What is the exact security settings it needs to connect? If I can get in this way, I'll try and work out a bridge to my local MQTT Broker

koalazak commented 7 years ago

ah! Now I understand you. I cant connect with MQTT.fx i think cos it reject the roomba self signed Cert. And they dont have an option to allow selfsigned certs. You can use the undocumented event packetreceive in dorita980 to receive the raw mqtt packets sent by the robot and then you can send it to another broker.

sheppy99 commented 7 years ago

How can I get packetreceive going? I'm new to node but very good at googling ;-) It may be in the too hard basket of course as thanks to your excellent work, all is well again with Openhab and Roomba. Do you think polling the robot uses a lot of power? I've noticed that when it got stuck with the old Dorita for an hour or 2 the battery was empty

iosdeveloper commented 7 years ago

I noticed flags was removed from cleanMissionStatus. They were used to check idle, bin full, bin removed and beeping. Do you know the replacement for this?

Edit: I think bin.present, bin.full, audio.active but what is idle?

koalazak commented 7 years ago

@sheppy99

var dorita980 = require('dorita980');
var myRobotViaLocal = new dorita980.Local('MyUsernameBlid', 'MyPassword', '192.168.1.104');

myRobotViaLocal.on('packetreceive', function (rawpacket) {
 console.log(rawpacket.toString());
});

Now in firmware 2.0.0 the robot is who push the data. dorita980 doesnt pull when you use the get methods. dorita980 just return the stored data he collects on every robot push. The only think to mention is that the robot pull more data when a client is connected. So yes, I think if you are connecting and disconnecting all the time maybe the battery goes down.

sheppy99 commented 7 years ago

That gives me a screen full of "[object Object]" one per line - looks like

[object Object] [object Object] [object Object] [object Object] [object Object] [object Object] [object Object] [object Object] [object Object] [object Object]

It also stops the status polling from working

koalazak commented 7 years ago

@iosdeveloper now that info is in other state properties. bin: { present: true, full: false } and audio: { active: true }

i will put bin in getMission()

koalazak commented 7 years ago

@sheppy99 sorry, remove the .toString()

sheppy99 commented 7 years ago

That's more like it although the payload doesn't mean much. With

 var dorita980 = require('dorita980');
 var myRobotViaLocal = new dorita980.Local('MyUsernameBlid', 'MyPassword', '192.168.1.104');
 myRobotViaLocal.getRobotState(['batPct', 'bbchg3']).then((actualState) => {
 console.log(actualState);
  }).catch((err) => {
    console.log(err);
  });
});

Is that all that is needed and then Dorita980 listens in the background? Running that every minute doesn't wake the Robot as Dorita980 is always listening?

koalazak commented 7 years ago

@sheppy99 the payload in packetreceive is a Buffer you can convert it with rawpacket.payload.toString() (if payload exist. cos not all messages has payload). But to send to another broker you can use exacly rawpacket without changes. Its a mqtt valid packet.

about your last question:

the only part in that code you can just call every minute without problems is:

myRobotViaLocal.getRobotState(['batPct', 'bbchg3']).then((actualState) => {
 console.log(actualState);
  }).catch((err) => {
    console.log(err);
  });

That part doesnt hit the robot.

But if you call this every minute:

var myRobotViaLocal = new dorita980.Local('MyUsernameBlid', 'MyPassword', '192.168.1.104');

there is a reconnection and hit the robot every minute.

sheppy99 commented 7 years ago

After a reboot, presumably

var myRobotViaLocal = new dorita980.Local('MyUsernameBlid', 'MyPassword', '192.168.1.104');

needs calling once to establish a connection, and then everything else can use that connection? Does it reestablish if the WiFi drops? I'm calling individual js files from a command line in Openhab in case its relevant. Apologies if these are dumb questions, I'm learning a lot here.

koalazak commented 7 years ago

no, you need to handle the reconnections for now.

sheppy99 commented 7 years ago

All good, I'll experiment. Thanks again for bringing this back so quickly

sheppy99 commented 7 years ago

Having thought about this I think I'll wait until Rest980 is updated to work with the new firmware as that, I think, will handle the status collecting and I can poll that using the REST interface. Right now it spits errors relating to port 443 so I think its trying to talk to the Robot the old way

iosdeveloper commented 7 years ago

Did anybody look into getPassword in firmware 2.0 and want to share?

koalazak commented 7 years ago

Hi guys, Im working on reversing the password thing but meanwhile to get your password you can use this snippet:

var tls = require('tls');

var options = {
  rejectUnauthorized: false
};
var client = tls.connect(8883, '192.168.1.104', options, function (e) {
  var packetfull = 'f005efcc3b2900';
  client.write(new Buffer(packetfull, 'hex'));
});
client.on('data', function (data) {
  console.log(new Buffer(data).slice(13).toString());
});
client.setEncoding('utf-8');

Edit the IP address.

First press the HOME button for 3 seconds, then run this script. You should see the password.

regards,

twentworth12 commented 7 years ago

I generated the password, but I'm getting "Connection refused: Not authorized" when I try and connect.

I assume the password is the last part of the string i.e. ��;):1:1486868728:i7ssaGIoO3Gc3mjY

koalazak commented 7 years ago

the password is all this shit :1:1486868728:i7ssaGIoO3Gc3mjY :p

koalazak commented 7 years ago

that shit makes me crazy ¬¬

twentworth12 commented 7 years ago

Well, in my defense the last part matched the length of the old password but IT WORKS. Thanks for doing this! Now to fix https://github.com/steedferns/homebridge-roomba980

koalazak commented 7 years ago

yes! when I realized that I lost a half day dealing with timestamps ¬¬

rwscott1961 commented 7 years ago

Fabulous!!!!

I think your commands for making the certs a incorrect though. Nowhere do you make a "server.crt". I got it working with the following:

openssl req -days 365 -out server.crt -new -x509 -newkey rsa:2048 -keyout server.key -nodes -subj "/CN=localhost"

Nice, control packet type: Reserved Forbidden

:)

On Wed, 2017-02-15 at 17:44 -0800, Facu ZAK wrote:

Hi guys, Im working on reversing the password thing but meanwhile to get your password you can use this snippet:

var tls = require('tls'); var fs = require('fs'); var options = { key: fs.readFileSync('server.key'), cert: fs.readFileSync('server.crt'), rejectUnauthorized: false }; var client = tls.connect(8883, '192.168.1.104', options, function (e) { var packetfull = 'f005efcc3b2900f005efcc3b2903f005efcc3b2900f005efcc3b2903'; client.write(new Buffer(packetfull, 'hex')); }); client.on('data', function (data) { console.log(data); }); client.setEncoding('utf-8');

Edit the IP address and create a cert files with this commands:

openssl genrsa -des3 -out server.key 2048 openssl req -new -key server.key -out server.csr cp server.key server.key.org openssl rsa -in server.key.org -out server.key

First press the HOME button for 3 seconds, then run this script. You should see a weird characters and the password string.

regards,

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

rwscott1961 commented 7 years ago

It seems that only the first packet is necessary

"f005efcc3b2900"

On Wed, 2017-02-15 at 17:44 -0800, Facu ZAK wrote:

Hi guys, Im working on reversing the password thing but meanwhile to get your password you can use this snippet:

var tls = require('tls'); var fs = require('fs'); var options = { key: fs.readFileSync('server.key'), cert: fs.readFileSync('server.crt'), rejectUnauthorized: false }; var client = tls.connect(8883, '192.168.1.104', options, function (e) { var packetfull = 'f005efcc3b2900f005efcc3b2903f005efcc3b2900f005efcc3b2903'; client.write(new Buffer(packetfull, 'hex')); }); client.on('data', function (data) { console.log(data); }); client.setEncoding('utf-8');

Edit the IP address and create a cert files with this commands:

openssl genrsa -des3 -out server.key 2048 openssl req -new -key server.key -out server.csr cp server.key server.key.org openssl rsa -in server.key.org -out server.key

First press the HOME button for 3 seconds, then run this script. You should see a weird characters and the password string.

regards,

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

koalazak commented 7 years ago

Hi @rwscott1961, Yes I update my snippet 10min after published removing the cert thing (its not necesary), using the first packet only and parsing the uggly response to show the password. BTW, dorita980 is updated and getpassword is back! :) with a little changes in onscreen instructions.

next stop: cloud API

iosdeveloper commented 7 years ago

Do you know how if it is possible to check the robot protocol is http or mqtt like in the discovery payload but given only the IP address?

iosdeveloper commented 7 years ago

Also, how to get blid/username given only IP address (and password).

koalazak commented 7 years ago

i click reopen by misstake :p

@iosdeveloper I just publish the v3.0.4 with the discovery method exposed and return all the discovery data, including ip address, blid and protocol version.

iosdeveloper commented 7 years ago

So you need discovery first. Is there a way if the network doesn't allow discovery (i.e. no broadcast)?

koalazak commented 7 years ago

mmm i think is not possible. maybe resolving the hostname for that ip but i think is needed a brodcast too.

iosdeveloper commented 7 years ago

Ok, thanks 👌

rwscott1961 commented 7 years ago

On Thu, 2017-02-16 at 05:03 -0800, iosdeveloper wrote:

Also, how to get blid given only IP address (and password).

The BLID is the part after Roomba- in the discovery "hostname". It is also the SSID of the network during the setup.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

jeffqchen commented 7 years ago

I'm on FW 2.0.0-34 but when I try to get the password it throws an error "Error getting password" after showing all the robot information.

koalazak commented 7 years ago

are you using node 6 or 7? I just push version 3.0.5 fixing a bug in getpassword for node 6 and 7.

jeffqchen commented 7 years ago

I just purged everything and cloned again, this time it works but the password I got was nothing something like :1:1486868728:XXXXXXXXX, but only 16 characters.