Help with iRobot MQTT

I'm trying to connect to my Roomba 980 directly using MQTT, but I'm not having any luck. I was hoping someone here with more experience using MQTT could help give me some guidance.

For context, I have dorita980 and rest980 installed on a Raspberry Pi, and I use that within Hubitat to control my Roomba. It works great, but it drives me nuts that it has to poll the REST API, rather than directly subscribing via MQTT. I've run out of other HA projects to do, so I thought I'd try to see if I could write a driver that connects directly to the Roomba via MQTT, just for fun.

I've been browsing the dorita980 code on Github, and the code to connect via MQTT seems really straightforward:

  const url = 'tls://' + host;

  var options = {
    port: 8883,
    clientId: user,
    rejectUnauthorized: false,
    protocolId: 'MQTT',
    protocolVersion: 4,
    ciphers: process.env.ROBOT_CIPHERS || 'AES128-SHA256',
    clean: false,
    username: user,
    password: password
  };

  const client = mqtt.connect(url, options);

I believe host is simply the IP address of my Roomba, user is the blid, and password comes from the Roomba. I have all of these things in the configuration of rest980, and I can confirm that they're working there.

I borrowed code from @dman2306 to create a very simple driver to test the connection:
https://community.hubitat.com/t/my-god-anyone-attempted-an-lg-thinq-integration/51925/257
and I changed the hostname, port, username, and password to match the information used in rest980.

But the only response I ever get is:

Unable to connect to server (32103) - java.net.ConnectException: Connection refused (Connection refused)

I thought I might be doing something wrong with the driver in Hubitat, so I tried testing the connection in MQTT Explorer, but I get a similar response there:

I wondered if it has to do with the ciphers specified in dorita980, but I can't find anywhere to enter that information in MQTT Explorer. It only has options for the CA certificate, client certificate, and client key (just like the MQTT API in Hubitat).

Does anyone know what I could be doing wrong? I'm pretty far out of my league on this one, so any advice is appreciated!

Are you sure your robot is listening on port 8883? Mine isn't:

C:\Users\dmegl_000>telnet 192.168.1.80 8883
Connecting To 192.168.1.80...Could not open connection to the host, on port 8883: Connect failed

I don't think you're getting an MQTT issue, the error you're getting indicates that nothing is listening on that port.

Hmm, that’s a good question. The iRobot webpage for Optimal firewall configurations suggests that the MQTT communication happens on port 8883:

Internal Network Traffic

  • UDP port 5353/5678 for discovery.
  • TCP/HTTPS 443 for data traffic.
  • TCP/MQTT 8883 for data traffic.

The port number doesn’t seem to be configurable in dorita980 or rest980, but I did have some trouble connecting to it yesterday.

I’ll try again today and make sure I reset the Roomba beforehand in order to kick off any existing connections.

That’s the outgoing port it uses to connect to the iRobot cloud MQTT. That doesn’t mean it’s running a local broker. IRobot, to my knowledge, is only an MQTT client, not server. I could be wrong though.

I couldn’t find any evidence of dorita980 connecting to a separate broker, so I’m hopeful that the Roomba is running one itself.

I found this thread in the dorita980 Github issues that seems to follow when they were first discovering and implementing the MQTT communication:
https://github.com/koalazak/dorita980/issues/10
I haven’t made it all the way through the thread, but so far, it sounds like, in addition to the cloud MQTT broker, there is a local MQTT broker that the app can communicate with directly.

So, fingers crossed!

Ok, making some progress. I’ve read that the Roomba MQTT server only allows a single connection at a time, so my rest980 instance may have been occupying that connection. I shut down my Raspberry Pi and did a soft reset of the Roomba to disconnect any other clients and tried again with MQTT Explorer. Now I get a Connection Refused error, instead of Disconnected from server. Better than no change, right?

I wondered if the soft reset would cause the password to change, but when I reconnected the rest980 instance, it’s working again without any modifications, so scratch that theory...

Got it!

My theory that rest980 was occupying the MQTT connection was correct. Once I shut down the rest980 instance, I was able to connect using this Python script:
https://github.com/koalazak/dorita980/issues/10#issuecomment-296666429

When reviewing that code, I noticed that the client ID was set to the blid, which matched what I saw in the dorita980 code. That appears to have been a crucial piece. Once I made that change, I was able to connect with MQTT Explorer.

Next step is to work on the driver in Hubitat!

I've hit a wall. I've tried everything I can think of, but I can't get Hubitat to connect to the local Roomba MQTT broker. The code in the driver is pretty straightforward:

try
{
    interfaces.mqtt.connect(
        "ssl://192.168.1.196:8883", 
        "xxx", //blid from my Roomba
        "xxx", //blid from my Roomba
        "yyy", //password from my Roomba
        tlsVersion: "1.2", 
        privateKey: privateKey, 
        caCertificate: caCert, 
        clientCertificate: clientCert
    )
    if (interfaces.mqtt.isConnected()) {
        interfaces.mqtt.disconnect()
    } else {
        log.debug "MQTT failed to connect..."
    }
}
catch (e) {
   log.debug e
}

But the only response I ever get is Connection refused.

I am able to connect to the Roomba with this Python code:
https://github.com/koalazak/dorita980/issues/10#issuecomment-296666429
and I've used it to confirm that the MQTT connection is available and that the private key, client cretificate, and CA certificate are all valid. I've tried it with TLS 1, 1.1, and 1.2. I've tried it without TLS. But nothing seems to work.

I don't know what could be wrong or what else to try, so I'm going to have to give up on this for now. As an alternative, I'm going to try setting up Mosquitto as an MQTT bridge and have Hubitat communicate through that instead. I had wanted to eliminate the dependency on my Raspberry Pi, but it doesn't look like I'm going to be able to accomplish that. With Mosquitto, I'm hoping to get real-time updates from the Roomba, instead of having to poll the REST API through rest980.

Wish me luck!

How did you validate the certificates? The python script, by my eye, seems to be ignoring certificate validation -- I am able to connect to my Roomba using MQTT Explorer with cert validation disabled -- but not sure what certificates (I tried creating my own, with no success in using them to connect) to plug in?

I don't know much about MQTT, been doing some reading -- had been thinking along the same lines, to try to remove the rPi from the middle.

I’m thinking along the same lines as you: the certificates are ultimately the problem.

To answer your question, I got different errors in Hubitat when the private key and the client certificate didn’t line up. I got similar errors in the Python script until I generated them correctly. When it went back to Connection refused on Hubitat, I assumed the key and certificate were correct.

I went through several iterations of the CA certificate. I tried sample ones and I tried generating my own self-signed certificate, but those didn’t work. The Python script uses the ones stored the Raspberry Pi, but that didn’t work in Hubitat either. I eventually figured out how to pull the real certificates directly from the Roomba, but that didn’t work either. They appear to be self-signed too, and that may ultimately be what Hubitat can’t handle.

I also failed in my attempt to set up an MQTT bridge today. I think it is due to similar issues. Mosquitto gives slightly better error messages. I believe the last one I got was something like dh key too small. I’m not certain but I think this has to do with the ciphers, but neither Hubitat nor the Mosquitto bridge connection allow you to change which ciphers are being used.

Have you tried using TLS but NO certs? Maybe it supports that? Something like:

interfaces.mqtt.connect(
"ssl://192.168.1.196:8883",
"xxx", //blid from my Roomba
"xxx", //blid from my Roomba
"yyy", //password from my Roomba
tlsVersion: "1.2"
)

Edit: actually, maybe remove the tlsVersion too... let it auto negotiate

Edit 2: client.tls_set("/etc/ssl/certs/ca-certificates.crt", None, None, cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1, ciphers=None)

Yeah, that's the paho MQTT call, it provices the CA cert but no client cert or key and says the cert_reqs is none for the client. so Try just the caCertificate but remove privateKey and clientCertificate

I think I tried that, but I’ve tried so many things now, I really don’t know... :stuck_out_tongue:

I remember reading this in the Hubitat MQTT documentation:

Note, all 4 parameters (tlsVersion, privateKey, caCertificate, clientCertificate) are required for TLS secure connection

So at some point, I just started using them all.

I just tried it to see, but I still get Connection refused.

They're definitely not all required. Not sure why it says that. My Rheem integration uses none of them and connects via TLS. Connection refused doesn't sound like an SSL error to me. In Java, that's a ConnectionException which means you didn't even connect to the IP/port. SSL/TLS isn't negotiated until after connection and if it fails I think you'd get a disconnection error, not a connection refused. I'm surprised though because you said MQTT explorer works... Hmm. I'll unplug my Dorita tomorrow and see if I can connect to my Roomba. I have an i7.

No firewalls between your HE and Roomba, right?

Not that I know of. I have an access point with the same SSID, and I’ve had issues with other products (e.g. Konnected) not working when one device is connected to the AP and one is connected directly to the router. But in this case, I’ve been able to connect using MQTT Explorer on multiple computers around my house (some wired, some wireless).

I haven’t run MQTT Explorer directly from the Raspberry Pi though. I wasn’t able to get it to run. But I have been able to connect using the Python script and dorita980, so I think that rules out networking issues on the Pi itself.

Not sure if that makes any difference for Hubitat.

Sorry, why would we be talking about network issues on the rpi? I thought you're trying to connect HE -> Roomba directly, right? So no rpi involved?

Yep, you’re right. I should call it a night as I’m clearly not thinking straight any more!

No firewalls that I know of between HE and Roomba.

1 Like

Ok. I'll play around tomorrow too. As a note, it does appear to be self-signed certs which if we do get it connected will be an issue. The HE team is considering supporting self-signed certs in a future firmware release.

Release 2.2.5 might be the key to getting this working? Haven't had a chance to play with it yet.

It was a necessary addition to make this work, but it won’t resolve a connection refused error.

Agree that the error/exception doesn't seem to align with a cert issue, but wondered if the cert exception might be getting caught and swallowed somewhere in the HE sw. It doesn't seem to make much sense, since we've proven that the Roomba will accept a connection on the ip/port. Even a firewall would likely end in a Connection Timeout, dropping the packets, instead of outright refusing?