Actually, the rest API allows for the same feedback from the device to allow you to confirm if the action took place or not. The current version of the driver that I am using allows for capture of local changes as well as positive feedback from the device when a command is issued.
// Original driver developed by Brett Sheleski.
// Ported to Hubitat and updated to include switchNumber by ryan780.
metadata {
definition(name: "Sonoff-Tasmota RPC", namespace: "ryan780", author: "ryan780") {
capability "Actuator"
capability "Switch"
capability "Momentary"
capability "Polling"
capability "Refresh"
}
preferences {
section("Sonoff Host") {
input(name: "ipAddress", type: "string", title: "IP Address", displayDuringSetup: true, required: true)
input(name: "port", type: "number", title: "Port", displayDuringSetup: true, required: true, defaultValue: 80)
input(name: "switchNumber", type: "number", title: "Switch Number", displayDuringSetup: true, required: false, defaultValue: null)
}
section("Authentication") {
input(name: "username", type: "string", title: "Username", displayDuringSetup: false, required: false)
input(name: "password", type: "password", title: "Password (sent cleartext)", displayDuringSetup: false, required: false)
}
section("Logging"){
input(name: "logEnable", type: "bool", title: "Debug Logging", required: false, defaultValue: false)
}
}
}
def parse(String description) {
def message = parseLanMessage(description)
// parse result from current and legacy formats
def resultJson = {}
if (message?.json) {
// current json data format
resultJson = message.json
if (logEnable) log.debug resultJson
}
else {
// legacy Content-Type: text/plain
// with json embedded in body text
def STATUS_PREFIX = "STATUS = "
def RESULT_PREFIX = "RESULT = "
if (message?.body?.startsWith(STATUS_PREFIX)) {
resultJson = new groovy.json.JsonSlurper().parseText(message.body.substring(STATUS_PREFIX.length()))
}
else if (message?.body?.startsWith(RESULT_PREFIX)) {
resultJson = new groovy.json.JsonSlurper().parseText(message.body.substring(RESULT_PREFIX.length()))
}
/* else if (message?.header?.contains("HTTP/1.1 200 OK")) {
if (logEnable) log.debug $message?.header
}*/
}
// consume and set switch state
if ((resultJson?."POWER$switchNumber" in ["ON", 1, "1"])) {
setSwitchState(true)
}
else if ((resultJson?."POWER$switchNumber" in ["OFF", 0, "0"])) {
setSwitchState(false)
}
else if ((resultJson?."POWER" in ["ON", 1, "1"])) {
setSwitchState(true)
}
else if ((resultJson?."POWER" in ["OFF", 0, "0"])) {
setSwitchState(false)
}
else {
// log.error "can not parse result with header: $message.header"
// log.error "...and raw body: $message.body"
}
}
def setSwitchState(Boolean on) {
if (logEnable) log.info "switch is " + (on ? "ON" : "OFF")
sendEvent(name: "switch", value: on ? "on" : "off")
}
def push() {
sendCommand("Power$switchNumber", "Toggle")
}
def on() {
sendCommand("Power$switchNumber", "On")
}
def off() {
sendCommand("Power$switchNumber", "Off")
}
def poll() {
sendCommand("Power$switchNumber", null)
}
def refresh() {
sendCommand("Power$switchNumber", null)
}
private def sendCommand(String command, String payload) {
if (logEnable) log.debug "sendCommand(${command}:${payload}) to device at $ipAddress:$port"
if (!ipAddress || !port) {
log.warn "aborting. ip address or port of device not set"
return null;
}
def hosthex = convertIPtoHex(ipAddress)
def porthex = convertPortToHex(port)
def path = "/cm"
if (payload){
path += "?cmnd=${command}%20${payload}"
}
else{
path += "?cmnd=${command}"
}
if (username){
path += "&user=${username}"
if (password){
path += "&password=${password}"
}
}
def result = new hubitat.device.HubAction(
method: "GET",
path: path,
headers: [
HOST: "${ipAddress}:${port}"
]
)
return result
}
private String convertIPtoHex(ipAddress) {
String hex = ipAddress.tokenize( '.' ).collect { String.format( '%02x', it.toInteger() ) }.join()
return hex
}
private String convertPortToHex(port) {
String hexport = port.toString().format('%04x', port.toInteger())
return hexport
}