Latest (2019) iRobot Roomba integration methods

NOTE: There may be a bug in the start button below. It needs a bit more troubleshooting. Your experience may vary.

I picked up a Roomba 980 during the black friday sale and finally had some time to try and set it up with Smartthings. After reviewing the options, I settled on this code, since I did not want to build and maintain a node server. I haven’t been able to set up the UI with the new UI model, but this should at least get folks started with this device handler.
Please follow the instructions below to set it up!

Step 1: Copy the code below into your favorite text editor

/**
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
    in compliance with the License. You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
    on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
    for the specific language governing permissions and limitations under the License.

    Initial Code Copyright November 2019 FieldsJM
    Modified Jan 2020 C. Niggel
*/

preferences {
section("WebHook_Command_Input"){
input "start_command", "text", title: "Start Command", required: false
input "pause_command", "text", title: "Pause Command", required: false
input "stop_command", "text", title: "Stop Command", required: false
input "dock_command", "text", title: "Dock Command", required: false
input "key", "password", title: "iFTT Maker Key", required: true
}
}

metadata {
definition (name: "Roomba Control via iFTT", namespace: "SmartThingsDHs", author: "fieldsjm", mnmn: "SmartThings", vid: "generic-doorbell-2") {
capability "Actuator"
capability "Alarm"
capability "Button"
capability "Lock"
capability "Sensor"
capability "Switch"
capability "motionSensor"
capability "Health Check"

    command "start"
    command "pause"
    command "dock"
    command "stop"
    command "reset"
}

simulator {
}

tiles (scale: 2){

/Status tile based on intended action/
multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
attributeState ("Ready", label: "Ready", icon:"st.samsung.da.RC_ic_rc", backgroundColor:"#8CFC03")
attributeState ("Running", label: "In-Process", icon:"st.Health & Wellness.health7", backgroundColor:"#078bf7")
attributeState ("Paused", label: "Paused", icon:"st.sonos.pause-icon", backgroundColor:"#FC030F")
attributeState ("Docking", label: "Docking", icon:"st.presence.house.unlocked", backgroundColor:"#5F07F7")
attributeState ("Docked", label: "Docked", icon:"st.presence.house.secured", backgroundColor:"#5F07F7")
attributeState ("Stopped", label: "Stopped", icon:"st.sonos.stop-btn", backgroundColor:"#FC030F")
attributeState ("Ended", label: "Complete", icon:"st.samsung.da.RC_ic_rc", backgroundColor:"#8CFC03")
attributeState ("Error", label: "Error", icon:"st.Office.office6", backgroundColor:"#FC030F")
}
tileAttribute("device.motion", key: "SECONDARY_CONTROL") {
attributeState ("active", label: "Cleaning")
attributeState ("inactive", label: "Docked")
}
}
/Start/
standardTile("start", "device.button", width: 3, height: 2, decoration: "flat") {
state "default", label: "Start", icon:"st.samsung.da.RC_ic_rc", backgroundColor: "#ffffff", action: "start"
}
/Pause/
standardTile("pause", "device.button", width: 3, height: 2, decoration: "flat") {
state "default", label: "Pause", icon:"st.sonos.pause-btn", backgroundColor: "#ffffff", action: "pause"
}
/Dock/
standardTile("dock", "device.button", width: 3, height: 2, decoration: "flat") {
state "default", label: "Dock", icon:"st.nest.nest-home", backgroundColor: "#ffffff", action: "dock"
}
/Stop/
standardTile("stop", "device.button", width: 3, height: 2, decoration: "flat") {
state "default", label: "Stop", icon:"st.sonos.stop-btn", backgroundColor: "#ffffff", action: "stop"
}
/Reset/
standardTile("reset", "device.button", width: 6, height: 2, decoration: "flat") {
state "default", label: "Reset", icon:"st.secondary.refresh-icon", backgroundColor: "#ffffff", action: "reset"
}
/Switch for IFTT feedback of Started - Hidden by default/
standardTile("switch", "device.switch", inactiveLabel: false, width: 6, height: 2, decoration: "flat"){
state("off", label: "Ready", action: "switch.on", backgroundColor: "#ffffff", nextState: "on", defaultState: "true")
state("on", label: "Cleaning", action: "switch.off", backgroundColor: "#00a0dc", nextState: "off")
}
/Alarm for IFTT feedback of Error - Hidden by default/
standardTile("alarm", "device.alarm", inactiveLabel: false, width: 6, height: 2, decoration: "flat") {
state("off", label:"Ready / Pending", action:"alarm.strobe", icon:"st.alarm.alarm.alarm", backgroundColor:"#ffffff", nextState: "strobe", defaultState: "true")
state("strobe", label:"Error", action:"alarm.off", icon:"st.alarm.alarm.alarm", backgroundColor:"#e86d13", nextState: "off")
}
/Lock for IFTT feedback of mission complete - Hidden by default/
standardTile("lock", "device.lock", inactiveLabel: false, width: 6, height: 2, decoration: "flat"){
state("unlocked", label: "Ready / Pending", action: "lock.lock", backgroundColor: "#ffffff", nextState: "locked", defaultState: "true")
state("locked", label: "Mission Complete", action: "lock.unlock", backgroundColor: "#00a0dc", nextState: "unlocked")
}

    main "status"
    details(["status","start","pause","dock","stop","reset"])
}

}

def parse(String description) {

}

/Start - Sends iFTT Webhook - if Roomba starts successfully, iFTT will turn on switch/
def start() {
push(1)

	def cmd = "https://maker.ifttt.com/trigger/${settings.start_command}/with/key/${settings.key}";

  log.debug "Sending request cmd[${cmd}]"

  	httpGet(cmd) {resp ->
  		if (resp.data) {
  			log.info "${resp.data}"
  		} 
  	}

//sendHubCommand(result)
log.debug "Executing Roomba Start"
//log.debug result
}

/Pause - Sends iFTT Webhook - no feedback available/
def pause() {
push(2)
sendEvent(name: "status", value: "Paused")
sendEvent(name: "motion", value: "active")

	def cmd = "https://maker.ifttt.com/trigger/${settings.pause_command}/with/key/${settings.key}";

  log.debug "Sending request cmd[${cmd}]"

  	httpGet(cmd) {resp ->
  		if (resp.data) {
  			log.info "${resp.data}"
  		} 
  	}

//sendHubCommand(result)
log.debug "Executing pause"
//log.debug result
}

/Dock - Sends iFTT Webhook - minimal feedback available, once docked iFTT will also send docking mission complete (fail safe of conversational delay to Docked then Ready Status)/
def dock() {
push(3)
sendEvent(name: "status", value: "Docking")
sendEvent(name: "motion", value: "active")
runIn(60, docked)

	def cmd = "https://maker.ifttt.com/trigger/${settings.dock_command}/with/key/${settings.key}";

  log.debug "Sending request cmd[${cmd}]"

  	httpGet(cmd) {resp ->
  		if (resp.data) {
  			log.info "${resp.data}"
  		} 
  	}

//sendHubCommand(result)
log.debug "Executing dock"
//log.debug result
}

def docked() {
sendEvent(name: "status", value: "Docked")
sendEvent(name: "motion", value: "inactive")
runIn(10, reset)
}

/Stop - Sends iFTT Webhook - no feedback available/
def stop() {
push(4)
sendEvent(name: "status", value: "Stopped")
sendEvent(name: "motion", value: "active")

	def cmd = "https://maker.ifttt.com/trigger/${settings.stop_command}/with/key/${settings.key}";

  log.debug "Sending request cmd[${cmd}]"

  	httpGet(cmd) {resp ->
  		if (resp.data) {
  			log.info "${resp.data}"
  		} 
  	}

//sendHubCommand(result)
log.debug "Executing stop"
//log.debug result
}

/Status Reset/
def reset() {
push(5)
unlock()
off()
sendEvent(name: "status", value: "Ready")
sendEvent(name: "motion", value: "inactive")
}

private push(button) {
  log.debug "$device.displayName button $button was pushed"
  sendEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
}

/Feedback Mechanisms/
/Started - iFTT turns on if Roomba starts successfully/
def on(){
sendEvent(name: "switch", value: "on")
sendEvent(name: "status", value: "Running")
sendEvent(name: "motion", value: "active")
log.debug "$device.displayName (iFTT) has reported starting"
}
def off(){
sendEvent(name: "switch", value: "off")
sendEvent(name: "alarm", value: "off")
sendEvent(name: "status", value: "Ready")
sendEvent(name: "motion", value: "inactive")
}
/Misson Complete - iFTT turns on if Roomba completes task/
def lock() {
sendEvent(name: "lock", value: "locked")
sendEvent(name: "status", value: "Ended")
sendEvent(name: "motion", value: "inactive")
log.debug "$device.displayName (iFTT) has reported mission complete"
}
def unlock() {
sendEvent(name: "lock", value: "unlocked")
sendEvent(name: "status", value: "Ready")
sendEvent(name: "motion", value: "inactive")
}
/Error - iFTT turns on if Roomba encounters an error (stuck, low battery, etc)/
def strobe() {
sendEvent(name: "alarm", value: "strobe")
sendEvent(name: "status", value: "Error")
sendEvent(name: "motion", value: "active")
log.debug "$device.displayName (iFTT) has reported an error"
}

def installed() {
initialize()
}

def updated() {
initialize()
}

def initialize() {
sendEvent(name: "numberOfButtons", value: 5)
sendEvent(name: "status", value: "Ready")
sendEvent(name: "motion", value: "inactive")
sendEvent(name: "healthStatus", value: "online")
}

Step 2: Run a Find & Replace on all of the Quotes (") and replace them with quotes. This is important because there are some unicode problems either with the original code that was posted or with the forum. This is what was causing the Line 13 errors noted by ajk79 above. You may need to do this twice for the open quotes and the close quotes.
Step 2.5: You may also want to ensure there are no other single quotes in there - I had found one pair in the original code.
Step 3: Install the Device Handler by going into the IDE, Creating a new Device Handler from Code, and pasting in the repaired text from your text editor. With luck, it will compile.
Step 4: Create the required Webhooks in IFTTT:

  • There are instructions available here: https://www.learnrobotics.org/blog/control-irobot-roomba-siri/. Follow Step 1 to create 4 Webhooks. You can set the event names to be anything you like, just write down what they are
    • Event Name for start_roomba
    • Event Name for stop_roomba
    • Event Name for pause_roomba
    • Event Name for dock_roomba
  • Follow Step 2 on the page to get your IFTTT API Key. Put that in a safe place as well

Step 5: Go back into your Smartthings IDE and create the new Device using your Handler. See this page for instructions: https://community.smartthings.com/t/how-do-i-add-a-thing-after-adding-a-custom-device-handler/58636/2
Step 6: Still in the IDE, click on the device name to go to the properties. Fill out the Preferences with the event names and API keys you created in Step 4.


Step 7: You should be ready to clean your floors! On your mobile device, tap on the switch, and it should take off.

As noted above, the UI is not complete in the new Smartthings app. Hopefully this will become documented and it can be fixed. It is also worth noting that there is no feedback from the Roomba back to Smartthings, so if it gets stuck or the bin is full, you’ll need the iRobot mobile app to be alerted. Hopefully that can be added to this handler in the future. For now, at least, you can automate kicking off a job.