iRobot 9xx on openHAB

Hey guys,
I have problem with connection to my roomba. Don’t know why, but I’m not able to establish connection with broker.
My thing file:

Bridge mqtt:broker:roomba “Roomba” [ clientID=“XXX”, host=“10.1.0.9”, port=8883, secure=true, username=“XXX”, password=“XXX”, certificatepin=true, publickeypin=true ]
{
Thing topic state “Roomba state” {
Channels:
Type string : wifistat “WiFi” [ stateTopic=“wifistat” ]
Type string : shadow “Status” [ stateTopic=“$aws/things/CLIENTID/shadow/#”]
}
}

And log:

2020-05-24 23:05:25.936 [hingStatusInfoChangedEvent] - ‘mqtt:broker:roomba’ changed from OFFLINE to OFFLINE (COMMUNICATION_ERROR): io.netty.channel.ConnectTimeoutException: connection timed out: /10.1.0.9:8883

Connection to another broker which is on same rpi works fine, but this one not.
Any idea?
Thanks

Resumed my work on the binding. Can read and display some states, but sending commands doesn’t work.
It turns out quite tricky to tame a Roomba. Its mqtt server has some quirks and attempt to publish a message causes it to drop the connection. With Python code it works. Seems there is some subtle difference between Hivemq and Paho.

1 Like

Victory!!! I can send commands. Need to do some research on how to better represent all the states and i will release the first version.

3 Likes

Hello everyone! Finally i proudly present v1.0 for testing: https://github.com/Sonic-Amiga/openhab2.roomba/releases/tag/1.0 . Not everything is in place, but this is a start. You can see all the states and give commands. No map, sorry, this is gonna be tricky and will take some time.

Has anyone tested it yet ?

5 Likes

Good work. Got the binding working with my 960 just now. Found the following:

  • Discovery did not work, but then my Roomba is on a dedicated IoT network segment. The OpenHAB machine has access to it, but it’s not the default one. Setting the ip configuration manually did work.

  • Connecting to the Roomba is a bit flacky. Sometimes I need to force my network to reconnect the Roomba to make the binding work again. This again can be related to my IoT network

  • Found the following warnings in my logs, not using mqtt for anything else so I guess they might be related:

      2020-06-12 14:01:03.125 [WARN ] [.incoming.MqttIncomingPublishService] - No publish flow registered for MqttStatefulPublish{stateless=MqttPublish{topic=wifistat, payload=169byte, qos=AT_MOST_ONCE, retain=false}, packetIdentifier=-1, dup=false, topicAlias=0, subscriptionIdentifiers=[]}.
      2020-06-12 14:01:03.128 [WARN ] [.incoming.MqttIncomingPublishService] - No publish flow registered for MqttStatefulPublish{stateless=MqttPublish{topic=wifistat, payload=68byte, qos=AT_MOST_ONCE, retain=false}, packetIdentifier=-1, dup=false, topicAlias=0, subscriptionIdentifiers=[]}.
    

Other than that, it seems to work fine. I am getting correct values on all items so far. I am gonna try to move my Roomba to my normal nettwork to se if it works better.

@Sonic can you provide an example for a file based configuration?

@espenaf Yes, the discovery is based on a UDP broadcast, so of course it doesn’t work across subnets.
@wertzui Sorry, no, i don’t have one. But from the readme it shoud be straightforward:
ipaddress = roomba_ip_address
password = your_roomba_password.
I’m not sure how authorization would work though, if you don’t know the password, because it’s based on a binding’s ability to update own config. I don’t know if it’s possible to store ipaddress in a file and password in jsondb.

1 Like

roomba.things:

irobot:roomba:roomba960 [ ipaddress="_IP_", password="_PASSWORD_" ]

roomba.items:

String	RoombaCommand	"Roomba Command [%s]"	<roomba>					{channel="irobot:roomba:roomba960:command"}
String	RoombaMission	"Roomba Mission [%s]"	<roomba>					{channel="irobot:roomba:roomba960:cycle"}
String	RoombaState	    "Roomba State [%s]"		<roomba>					{channel="irobot:roomba:roomba960:phase"}
Number	RoombaBattery	"Roomba Battery [%s]"	<battery>					{channel="irobot:roomba:roomba960:battery"}
String	RoombaBin		"Roomba Bin [%s]"		<roomba>					{channel="irobot:roomba:roomba960:bin"}
String	RoombaError	    "Roomba Error [%s]"		<error>		(gError)		{channel="irobot:roomba:roomba960:error"}
Number  RoombaRSSI      "Roomba RSSI [%.0f]"    <signal>                    {channel="irobot:roomba:roomba960:rssi"}
Number  RoombaSNR       "Roomba SNR [%d]"       <signal>                    {channel="irobot:roomba:roomba960:snr"}

Nice !!!
After many hours trying to get it working with mqtt, I gave up. I had an issue with the mqtt versions. But with your binding, I’s working after 2 minutes.

First impression, everything works as expected.
I couldn’t do a discovery, since I’m using different networks. But a manual add is working.

I can start it again through some rules!. Most important thing (the basics) are back online…

Roomba’s MQTT is tricky and not fully compliant. It only accepts a subset of commands and barfs on everything else. And it only accepts qos = 1.
BTW, so you’ve tried to set it up with an mqtt binding, is there a protocol documentation available anywhere ? I’ve got all my knowledge from Roomba980-Python

Hello, how did you get the @Sonic binding work? I downloaded the jar, but in the bundle list the addon is installed, but not active. By running the bundle:start command I get an hivemq import error. Thanks

Hi and welcome to the community.

To make it work I also had to add the mqtt binding to the addons.cfg config file, like this:

binding = exec,weather1,astro,http1,network,ntp,tradfri,zwave,snmp1,knx,unifi,mqtt

You can probably also do it via the PaperUI

Hm, interesting. Does anyone know if there’s a way to sort this somehow? I guess bundling hivemq in the binding .jar would create conflicts.
To tell the truth i thought that HiveMQ is a part of core, but looks like it’s not.

Another update - managed to get Braava to work!
I had to use dorita980 to get password, manually entered it into Thing configuration.
Initially Braava was rejecting MQTT connections from the local network:

2020-08-25 19:05:05.713 [INFO ] [binding.irobot.handler.RoombaHandler] - Connecting to 192.168.*.*
2020-08-25 19:05:05.831 [ERROR] [binding.irobot.handler.RoombaHandler] - MQTT connection failed: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /192.168.*.*:8883

The solution was to reboot Braava while openhab was running and now everything is working!
I suspect that it only keeps local connection open for a period of time after reboot.
Thanks Sonic for the binding!
Now to cleaning!

Cool, so does Braava work out of the box? Neat!
By the way the binding should be able to automatically retireve the password, the procedure is described in the README file. Or doesn’t it work with Braava?
And i know about this connection problem, hit it once. Sometimes the device’s local connectivity gets stuck. I have no idea where it’s coming from, there’s definitely nothing i could do about it on the binding’s side. I think this has something to do with the limit of one local socket only. The robot can apparently fail to recognize disconnect, and the only available socket hangs forever. In my situation i also had to reboot the Roomba. Even the official app fails to locate it in this state (it uses local connection for setup only). Thanks iRobot for the crappy firmware :frowning:

Braava does work “out of the box”, thank you! Obviously, Braava-specific settings are missing (e.g., dry vs. wet cycle, amount of cleaning solution to dispense, tank sensor), but that is expected.
Automatic password retrieval did not work for me for some reason, I did try the described procedure.
Thanks again for your binding!

All the settings are missing. If you mean preferences. Not implemented yet, i initially just focused on getting basic functions running.

Well, looks like Braava has some differences there.

1 Like

1.1 release: https://github.com/Sonic-Amiga/openhab2.roomba/releases/tag/1.1
Full functionality except schedule time editing (no UI provided by OH) and map (don’t know how do draw it yet, will figure out over time). However further development of this is a low priority for me; i have more projects lying around in my apartment.

4 Likes

Thanks for working on this. The binding works great! I haven’t worked with java or any language since college 10+ years ago because I took my career in a different direction. But OpenHAB and this project specifically have inspired me to take up the hobby again so thank you. Although I have no experience with Eclipse/Maven and Github didn’t exist when I was in school…

More to the point, I’ve been trying to add my own effort to this project but I’m not getting very far so I figured I’d share what I’ve learned so far and hopefully it will be of some use. If you have any thoughts on how to accomplish this stuff, let me know.

I have a Roomba i7 which uses smart maps and has extra arguments it expects to see for room-specific cleaning. I’ve had no problem sending commands through node with dorita980 and javascript. I actually got the Roomba to do room-specific tasks directly after observing the MQTT broker logs and using what I found in your RoombaHandler.java and from dorita980. See below:

Javascript

...
const args = {
	"ordered": 1, //Binary switch
	"pmap_id": "7BWzb9_ZRNmbNZe4rkE0fw", //Main Floor
	"regions": [
	{"region_id": "21", "type": "rid"}, //Master Bedroom
	{"region_id": "25", "type": "rid"}, //Master Bathroom
	{"region_id": "20", "type": "rid"}, //Office
	{"region_id": "19", "type": "rid"}, //Guest Bath
	{"region_id": "1", "type": "rid"}, //Hallway
	{"region_id": "22", "type": "rid"} //Living Room
],
	"user_pmapv_id": "201006T004121" //MapIterationCreationDate
};
myRobotViaLocal.cleanRoom(args)
...

Based on how your code is written, I think the “start” command can still be used. I don’t think you need the cleanRoom command to execute the additional arguments. Just need to add a couple request.put lines in RoombaHandler.java under the JSONObject for CMD_CLEAN. But while trying to add that code to the binding, I hit some roadblocks. Basic syntax and operational stuff. I’m sure I could remember the proper syntax if I kept at it but the biggest challenge was simply creating the jar file. I’ve been stuck there for several days and the guides I’ve found online have not helped at all.

Ultimately, I think my contribution may be more useful by providing information rather than actually coding this, given how rusty I am. So, my findings on the Roomba i7 requests are below. I don’t think it would be too difficult to implement these but like I said, I haven’t touched Java in a long while.

Message Log

  "lastCommand": {
    "command": "start",
    "initiator": "localApp",
    "time": 1602439782,
    "ordered": 1,
    "pmap_id": "7BWzb9_ZRNmbNZe4rkE0fw",
    "regions": [
      {
        "region_id": "24",
        "type": "rid"
      },
      {
        "region_id": "1",
        "type": "rid"
      },
      {
        "region_id": "19",
        "type": "rid"
      }
    ],
    "user_pmapv_id": "201006T004121",
    "robot_id": null,
    "select_all": null
  },

Definitions

  • “ordered” is a binary value to execute regions in order of appearance but it can be sent even if there is only one region in the array. I don’t see a reason to ever change this from 1 so could likely be hardcoded instead of a string.

  • “pmap_id” is the ID of the map file itself. Could probably just be a setting in the thing config like the device password

  • “regions” is an array of rooms. There are other array variables but region_id and type are all that are needed. The IDs are unique and would need to be defined and labeled in OpenHAB by the user.

  • “user_pmapv_id” is the current iteration of the map file being used for the task. It’s basically just a time stamp of it’s creation date. It should be a user-defined value as well because it may change often.

  • robot_id and select_all seem to only be defined when initiating from the remote app and should not be sent from the binding.

When you set all values to null, it performs a whole home cleaning so null should be default and we would not need to create multiple request templates. These values could possibly be discovered automatically but that would obviously require a bit more work and seems unnecessary at the moment.

I imagine the request.put lines that should be added look like the following and then just let the strings be defined elsewhere in the binding.

	request.put("ordered", 1);
	request.put("pmap_id", mapid);
	request.put("regions", regionid[]);
	request.put("user_pmapv_id", mapvid);

This is about where I left off. Me trying to stumble through creating arrays, variables, and binding config isn’t useful when I can’t even figure out how to export a jar to test. I hope this information helps add to the functionality of the binding. I’m happy to provide more info, if needed. I can perform testing for the i7 too, if that helps.

It sounds like you’re the only one working on this so I’m happy to help you out in any way moving forward. I know you said this project is now a low priority for you so just let me know when you have some more time for it and when you are able to share your thoughts. Thanks!

Hi! I took this for the wishlist. I’ll try to code something may be next week. OTOH i guess i’ll be busy satisfying all the requirements for submission to the official tree, this seems difficult and labor-intensive