Robotic vacuums have come a long way since 2008 when I bought my refurbished Roomba 530. Today on the hookup we’re going learn how to add some of the best features of newer botvacs to older Roomba vacuums for just couple of bucks.
Recently I was browsing r slash homeautomation and saw a post about how cool the neato botvac D7 was. I watched a few youtube videos comparing the features on the most recent botvacs, and quickly realized that all of my biggest problems with my Roomba had been fixed, and a few of these new features seemed like “must haves” to me. Specifically, the most important new features to me were remote start, advanced scheduling, and the ability for the botvac to return to base, recharge, then go back out to finish cleaning. An amazon search for these youtube recommended botvacs lead me to some pretty steep price tags in the 400-800 range and I immediately re-evaluated my plans. When I told my wife this story she looked me dead in the eye and said “just make the old one do the new stuff”…
Smart woman, and also, Challenge Accepted.
I retrieved the Roomba from the box in the garage and began removing screws. I took the bottom off and didn’t find many exposed wires. I flipped it over and removed the top cover, and to my surprise there was an exposed port for some kind of a PS/2 looking cable port. Bingo. I thought to myself “all I need to do is reverse engineer the signal coming from this port” and I’ll be in control! Before going through this trouble I figured I’d do a quick google search about this port. It turns out there is a well documented API for this port and my long term tinkering project got a whole lot simpler.
Lets take a look at the pins on this port. It’s got 2 power pins, 2 ground pins, a pin for changing the serial baud rate, a serial RX pin and a serial TX pin. Reading though the Roomba open interface document it seemed like all I needed was an RX/TX serial connection so an ESP-01 was a perfect solution for adding wifi and getting my old Roomba into home assistant.
The wiring schematic looks like this. There is one semi complicated bit: For some reason the Roomba TX pin doesn’t output a strong enough signal to register in the ESP-01, so we have to boost it up with PNP transistor. Attach the base of the PNP transistor to the TX pin on the Roomba, the collector to your common ground, and the emitter to the RX pin on the ESP-01. Other than that the connections are simple: ESP-01 TX to Roomba RX, power and ground of the Roomba to the buck converter, and buck converter output to the ESP-01. If you’ve never used a buck converter before you basically just hook up your voltage source and turn the screw at the top to set your output voltage, I just tweak mine and check with a multimeter until I get the voltage I want.. somewhere around 3.2V in this case.
Amazon links for the exact stuff I used are down in the description.
The Roomba uses a pretty simple protocol to send commands. If you send a serial byte of “128” to the roomba’s RX pin it starts the open interface and begins listening for other commands. To make the Roomba clean we send a series of serial bytes 128, 131, 135.
Where 128 starts the open interface, 131 puts the roomba into safe mode telling it to use all of its safety sensors like the cliff sensor and bump sensors, and finally 135 starts the roomba’s cleaning mode.
If we want the Roomba to go back to it’s dock we similarly send 128, 131, 143. The only difference here being that we send 143 which is the “seek dock” command.
And that’s really it for sending commands, you can do all kinds of other things like playing specific tones and songs, turning on LEDs, and even controlling the motors directly, but I wasn’t really interested in those for this project. If I had just stopped here my total project would have taken 30 minutes, but I wanted MORE.
The next thing I wanted to do was gather information from my Roomba. This proved to be MUCH more difficult. The open interface documentation seemed to suggest that all I needed to do was send 128, 142, and then the sensor I wanted to read. Unfortunately, all of my attempts to use this command returned jibberish instead of the unsigned long variable it was supposed to return. I spent significantly more time trying to figure this out than I’m comfortable admitting, but I eventually found an Arduino library made by a guy named Mike McCauley that really helped me get a working program together. The sensors that I’m utilizing in my sketch are the battery capacity sensor, the battery maximum capacity sensor, and the charging state sensor.
My entire smart home runs on MQTT, so it was the obvious choice of protocol for my Roomba. I publish MQTT messages to three topics with my Roomba: Roomba/battery which receives a percentage value calculated by dividing the “current battery capacity” by the “max battery capacity” and then multiplying by 100… Roomba/charging which returns an integer between 0-5 corresponding to THESE different charging states, and Roomba/status which updates when the clean or seek dock command is sent to the Roomba.
Alright, are we ready to make it?
First, Load up my Arduino sketch from down in the description, put in your wifi information and mqtt information. You can change the MQTT ClientID and topics if you’d like, but you don’t need to.
Next, you'll flash the program to your ESP-01 using a USB to TTL adapter, hook up the pins according to this diagram.
After you’ve got the program loaded you can use your MQTT client of choice to make sure it works. Just power up the chip and you should see an “rebooted” message in the topic" checkIn/roomba". That means your flash was successful.
Once we're sure it's working we can make it as small as possible. You can desolder the pins from the ESP-01 by pushing them through from the top using a hot soldering iron. Once they are pushed through you can pull them out individually with a pair of nippers
Solder up your parts as shown in the schematic, and after you’re done you should have something that looks like this. Plug it in to your Roomba, press the roomba’s power button and you should see data start streaming in.
Now that our Roomba communicates with us and we can issue commands to it the rest of the setup will happen in home assistant and node red. In my configuration.yaml file I added two MQTT sensors for the battery and the status, and an MQTT switch to issue commands and restarted home assistant to load them in. I also did a little bit of customization to get the battery to show as a percent, and I changed the icons on each entry to make them look nicer.
To get an accurate status for the Roomba I use a little bit of nodeRED magic. I didn’t write this into the Arduino code because I still wanted to get battery status 0-5, but I wasn’t happy with just having 0-5 listed as a status in home assistant.
What I do, is I read the Roomba/status mqtt feed and save it to a flow wide variable called Roomba, then I read the charging feed and send it to a change node. If the charging state is 1, 2, or 3 that means the Roomba is on the charger and it sends an mqtt message of charging to the topic attached to the mqtt sensor in home assistant. If the charging state is 0 or 4 that means the Roomba is not on the charger, so I want the status to tell me the class command issued, which will either be cleaning, or returning. If the charging state is 5, something is wrong, so the status will read “error”.
Finally, I needed to get those must-have features implemented… The first one was done: Remote start is accomplished via the home assistant switch we just installed. Easy.
Next was advanced scheduling, for me this meant that I generally wanted the Roomba to run while my wife and I are at work, I never wanted the Roomba to run when people are home for days off, and I also wanted to be able to disable the schedule when we have company in town since that usually means there are suitcases and clothes on the ground that could cause problems. Here’s how I accomplished this in NodeRED.
One of my favorite nodes is this light scheduler node, if you don’t have it yet I highly recommend you install it in pallet manager by searching for node-red-contrib-light-scheduler (I’ll put that name in the description). I use this to generate a schedule with a “start” payload for turning on the Roomba. Next it checks the current state of two home assistant components: House guests is a simple input Boolean in home assistant that I toggle when we have people staying with us, and Home Occupied uses my google wifi to sense when my wife and I are home by detecting when our phones are connected to wifi. Both of these states from home assistant are read and each has the ability to halt the flow if they are true. If the flow makes it to the end it will send the “start” command via MQTT to the roomba.
The last must have feature is that I wanted my Roomba to clean as much as possible while was gone, in other words, I want it to clean until it needs to dock, charge back up to 95%, then go clean again as long as it will be done by the time I get home from work. To do this, we start with the previous Roomba schedule. I have my On payload set to “start” which is the MQTT command that needs to be sent to the Roomba, and I have my off payload set to “off” which isn’t a command the Roomba will recognize.
You’ll notice that in addition to using this schedule to initially start the Roomba at 8am, it also goes to this change node. In this change node I set a flow wide variable called roombaSchedule using the value from my payload which will either be “start” or “off”.
Below that I have an MQTT feed from the Roomba/charging topic, this message is sent every 5 seconds and flows into a “report by exception” node that only continues the feed when the value has changed from the previous value. After that it checks for a charging value of 3, which corresponds to the roomba’s “trickle charge” that activates when the battery reaches about 95%. If the charging state goes to trickle charge it sends the flow on, sets the payload to that flow wide variable from before called roombaSchedule and sends it on to the Roomba. If it is between the hours of 8am and 1pm roombaSchedule will be equal to “start” and it will send the Roomba out again to clean, if it’s not within those hours it will send an MQTT message of off, which essentially does nothing.
Now that I had my Roomba doing exactly what I wanted I decided to spend a little bit of money to upgrade the old Nickle Cadmium battery to lithium ion, and I bought a replacement pack of brushes for my now 10 year old Roomba.
I’ve gotta say, this thing cleans like a champ. I clean the bin once a week, and I’m always dumbfounded by the amount of crap that it finds in my house, where does it all come from?
One last note: If you’re going to mess around with this (and I encourage you to do so), I finally figured out that occasionally when unplugging and plugging in wires to the OI port I made the Roomba angry and it would stop responding to any commands on TX or RX. The only way to fix this is to pull the battery momentarily and then reconnect it. I was hours into troubleshooting before I figured this out and it was driving me CRAZY, I might have just saved you 5 hours of your life.
I hope this video inspired you to pull that old Roomba out of storage, or maybe buy one off craigslist and breath some new life into it. I’m confident that if you follow the instructions in this video you’ll be able to upgrade your old Roomba in about 1% of the time it took me to google around to hundreds of dead forum posts and outdated how-to articles. I’m going to fill the video description with every link you need to be successful hacking your Roomba. If you enjoyed this video please consider subscribing! And as always, thanks for watching the hookup.
NodeRED scheduling node:
Roomba OI Document:
Meh, I'll just buy a new one:
Ecovac Deebot N79 on sale: https://amzn.to/2HtjGab
Music by BenSound.com