I am building an integration between Control4 and Smartthings as my house was primarily automated using C4 but I like several Smartthings features.
I updated the web2way C4 driver which allows me to query C4 controller and discover all switches and dimmers (for now… maybe I will expand it in the future). I also decided to use DHs to handle all the work instead of SmartApps for no other reason than I thought it was easier.
I did some previous tests by creating a dedicated DH for one of my dimmers and it worked like a charm. It’s basically a HubAction call and as long as you have the device network ID set to the hexadecimal value of the C4 Controller IP and the hub selected, the device will work like a charm.
Now the odd behaviour… I created a parent DH called C4 Controller which queries the actual controller and after parsing the results creates one child DH for each C4 switch and dimmer. This proved I was capable of sending messages and receiving them from the controller. I can see the messages returning from the controller in the live logging view.
However, every time I turn on or off a switch using a device created from a child DH, the message is sent but nothing happens. I can’t see any messages returning. I am not a Groovy expert so not sure if parent/child relationship has anything to do with this behaviour.
Please forgive the copy and paste but I don’t know how to make it look pretty.
Below a copy of the messages with a successfully returned message in bold followed by two request (on and off) without a response back.
12:22:57 AM: debug GET /?command=set&proxyID=208&variableID=1000&newValue=0 HTTP/1.1
Accept: */*
User-Agent: Linux UPnP/1.0 SmartThings
HOST: 10.0.0.50:9000
12:22:57 AM: debug childOff(208)
12:22:55 AM: debug GET /?command=set&proxyID=208&variableID=1000&newValue=1 HTTP/1.1
Accept: */*
User-Agent: Linux UPnP/1.0 SmartThings
HOST: 10.0.0.50:9000
12:22:55 AM: debug childOn(208)
**12:22:46 AM: debug {"1000":"1"}**
12:22:45 AM: debug GET /?command=get&proxyID=201&variableID=1000 HTTP/1.1
Accept: */*
User-Agent: Linux UPnP/1.0 SmartThings
HOST: 10.0.0.50:9000
12:22:45 AM: debug Executing 'refresh()'
The code I am using follows.
C4 Controller DH code:
import groovy.json.JsonSlurper
metadata {
definition (name: "C4 Controller", namespace: "lsilva171", author: "Luis Carlos Silva") {
capability "Configuration"
capability "Refresh"
capability "Polling"
}
preferences {
input("ControllerIP", "string", title:"C4 Controller IP Address", description: "Enter C4 controller's IP Address", required: true, displayDuringSetup: true)
input("DriverPort", "string", title:"C4 Driver Port", description: "Enter web2Way C4 driver's port", required: true, displayDuringSetup: true)
}
}
simulator {
}
tiles (scale:2) {
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:'Refresh', action: "refresh.refresh", icon: "st.secondary.refresh-icon"
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "configure", label:'Configure', action:"configuration.configure", icon:"st.secondary.tools"
}
childDeviceTiles("all")
}
def installed() {
}
def updated() {
}
def initialize() {
}
def configure() {
log.debug "Executing 'configure()'"
def hosthex = convertIPtoHex(ControllerIP).toUpperCase()
def porthex = convertPortToHex(DriverPort).toUpperCase()
device.deviceNetworkId = "$hosthex:$porthex"
log.debug "The C4 Controller DNI configured is $device.deviceNetworkId"
sendMsg("GET", "?command=getitems")
}
def refresh() {
log.debug "Executing 'refresh()'"
sendMsg("GET", "?command=get&proxyID=201&variableID=1000")
}
def parse(String description) {
def msg = parseLanMessage(description)
def body = msg.body
log.debug msg.body
def json = msg.json
if (msg.body.contains("item")) {
def wswitch = json.item.findAll { it.type == "6" && it.name.contains("Switch") }
wswitch.each {
def proxyid = it.proxyid.toInteger()
def index = json.item.findIndexOf { it.proxyid == "${proxyid}" } + 1
try {
log.trace "Switch: ${json.item[index].name} : ${json.item[index].proxyid}"
addChildDevice("C4 Child Switch", "C4_child_switch:${json.item[index].proxyid}", null,
[completedSetup: true, label: "C4 ${json.item[index].name}", isComponent: false,
componentName: "C4_child_switch:${json.item[index].proxyid}", componentLabel: "${json.item[index].name}"])
} catch (e) {
log.error "Child device creation failed with error = ${e}"
state.alertMessage = "Child device creation failed. Please make sure that the C4 Child Switch DH is installed and published."
runIn(2, "sendAlert")
}
}
def wdimmer = json.item.findAll { it.type == "6" && it.name.contains("Dimmer") }
wdimmer.each {
def proxyid = it.proxyid.toInteger()
def index = json.item.findIndexOf { it.proxyid == "${proxyid}" } + 1
try {
log.trace "Dimmer: ${json.item[index].name} : ${json.item[index].proxyid}"
addChildDevice("C4 Child Dimmer", "C4_child_dimmer:${json.item[index].proxyid}", null,
[completedSetup: true, label: "C4 ${json.item[index].name}", isComponent: false,
componentName: "C4_child_dimmer:${json.item[index].proxyid}", componentLabel: "${json.item[index].name}"])
} catch (e) {
log.error "Child device creation failed with error = ${e}"
state.alertMessage = "Child device creation failed. Please make sure that the C4 Child Dimmer DH is installed and published."
runIn(2, "sendAlert")
}
}
} else if (msg.body.contains("variable")) {
// Placeholder
} else {
// Placeholder
}
}
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
}
private sendMsg(String method, String path) {
try {
def result = new physicalgraph.device.HubAction(
method: "${method}",
path: "/${path}",
headers: [ HOST: "$ControllerIP:$DriverPort" ]
)
log.debug result
return result
}
catch (Exception e) {
log.debug "Hit Exception $e on $result"
}
}
private sendAlert() {
sendEvent(
descriptionText: state.alertMessage,
eventType: "ALERT",
name: "childDeviceCreation",
value: "failed",
displayed: true,
)
}
def childOn(String dni) {
def proxyid = dni.split(":")[-1]
log.debug "childOn($proxyid)"
sendMsg("GET", "?command=set&proxyID=${proxyid}&variableID=1000&newValue=1")
}
def childOff(String dni) {
def proxyid = dni.split(":")[-1]
log.debug "childOff($proxyid)"
sendMsg("GET", "?command=set&proxyID=${proxyid}&variableID=1000&newValue=0")
}
def childSetLevel(String dni, value) {
def proxyid = dni.split(":")[-1]
log.debug "childSetLevel($proxyid), level = ${value}"
sendMsg("GET", "?command=set&proxyID=${proxyid}&variableID=1001&newValue=${value}")
}
and the C4 Dimmer Child DH code:
metadata {
definition (name: "C4 Child Dimmer", namespace: "lsilva171", author: "Luis Carlos Silva") {
capability "Switch"
capability "Relay Switch"
capability "Switch Level"
capability "Actuator"
}
}
simulator {
}
tiles (scale:2) {
multiAttributeTile(name:"switch", type: "lighting", width: 3, height: 4, canChangeIcon: true) {
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00a0dc", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00a0dc", nextState:"turningOff"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
}
main "switch"
details(["switch"])
}
void on() {
parent.childOn(device.deviceNetworkId)
sendEvent(name: "switch", value: "on", isStateChange: "true")
}
void off() {
parent.childOff(device.deviceNetworkId)
sendEvent(name: "switch", value: "off", isStateChange: "true")
}
def setLevel(value) {
log.debug "setLevel >> value: $value"
def level = Math.max(Math.min(value as Integer, 99), 0)
if (level > 0) {
sendEvent(name: "switch", value: "on")
} else {
sendEvent(name: "switch", value: "off")
}
def SwitchPathLevel = "/?command=set&proxyID=${ProxyID}&variableID=1001&newValue=${level}"
sendEvent(name: "level", value: level, unit: "%")
parent.childSetLevel(device.deviceNetworkId, level)
}
def setLevel(value, duration) {
log.debug "setLevel >> value: $value, duration: $duration"
def level = Math.max(Math.min(value as Integer, 99), 0)
setLevel(level)
}
def generateEvent(String name, String value) {
//log.debug("Passed values to routine generateEvent in device named $device: Name - $name - Value - $value")
sendEvent(name: "switch", value: value)
}
Any help is appreciated.