Common Composite (Child) Device Handlers

Eric, the child device handlers have stopped working. I installed your Child Switch as a child to Sinope. Sinope did correctly create the child switch. However, when the switch issues the parent.childon(…) I get an error that parent is null. The childon(…) method is correctly installed in the parent, and in the simulator I can trigger it and get the right reaction. But toggling the switch does not call the childon(…) in the parent.

Are you aware of what might be going on?

If you remove the device and re-create them does it change anything?

Did it just stop working for you? Or have you just noticed it? Which of the device handlers are you using? I have found that quite a few of Eric’s handlers have been published, so perhaps some of them have changed as a result, but I dont think that is recent.

I was using the Switch Child Device with the Sinope Device Handler. But I
also tested the problem with a very simple switch child and a very simple
parent which just printed debug statements.

In the Child, the statement parent.childon(dni) triggers the debug
statement that parent is null. The device clearly shows my parent device as
the parent, and the parent device clearly shows the Child Device as a
child. Therefore, the statement parent.childon(dni) never triggers the
method childon(dni) in the parent. There is no communication between parent
and child.

Eric has updated his Switch since last I used it, so it is something in the
architecture which does not recognize the keyword parent or child.

I got my new devices working by restructuring the switch as a standalone
(i.e. not a child) and using a SmartApp to establish the communication.
But, as best I can see, the concept of a Composite Device does not work at
this time due to the keywords not being recognized.

I would probably suggest you post the exact code that is used in the web IDE as the easiest way to investigate (if you have github integration then be aware this can sometimes make it hard to ensure you are using a specific version of a DTH). I have parent child relationships in 6 or so different devices (several of which I wrote) and have no problems, so without seeing the code (and maybe attempting to reproduce it, it will probably be hard to go any further).

OK, here is what you asked for. For testing purposes I created a device handler named Test Child DH which does nothing but call the parent,childon(dni) method. I put in lots of debugging statements so that you can see what is happening. Then I created both a device handler named Test Parent DH and a device named TestParent which uses this device handler. The device does nothing more than create the child and provide some debug messages. In particular, the parent method childon(dni) throws a trace message that it has been reached. These were published to me and showed up in the Smartthings phone app.

I set the IDE to Live Logging, and triggered the TestChild on the phone app. Tthe debug statements verified that the parent was indeed the TestParent, that the dni was correct and the parent.childon(dni) was called. However, the Live Debugging also revealed that the TestParent’s childon(dni) method was NOT invoked. This is the failure I have been describing.

Hopefully I simply missed a step. The two device handlers are listed below as you had requested.

Parent device handler:

/**

  • Test Parent DH
  • Copyright 2017 RALPH MILLER
  • 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.

*/
metadata {
definition (name: “Test Parent DH”, namespace: “rlmillerx”, author: “RALPH MILLER”) {
capability "Switch"
capability "Sensor"
capability “Actuator”
}
}

preferences {

    command "childon", ["string"]
    command "childoff", ["string"]
         
}

simulator {
    
}

tiles (scale: 2) {

   standardTile("thermPresence", "device.switch", inactiveLabel: false, width: 3, height: 3) { //, decoration: "flat"
		state "on", label:'Home', action:'off', backgroundColor: "#44b621", icon: "st.Home.home2", nextState:"Updating"
		state "off", label:'Away', action:'on', backgroundColor: "#ADD8E6", icon: "st.Home.home2", nextState:"Updating"
        state "Updating", label:"Updating", backgroundColor: "#ffffff", icon: "st.secondary.secondary" 	//, defaultState: true
        
	}

}

def installed() {
initialize()
}

def updated() {
initialize()
}
def initialize() {
// create child switch
// first check if child device is already installed
def childDevices = getChildDevices()
log.debug "${childDevices}"
log.debug "${childDevices.size()}"
if (childDevices.size() == 0) {
log.trace "Creating Child"
try {
addChildDevice(“Test Child DH”,“testchild”,null, [completedSetup: true, label: “TestChild”, isCompenent: false, componentLabel: “TestChild”])
} catch(Exception e) {
log.debug “${e}”}
log.trace “Child created”
}
}
// handle commands
def parse(String description) {
log.debug “parse: description = ${description}”

}

def on() {
log.trace "on command received"
sendEvent(name: “switch”, value: “on”)
}

def off() {
log.trace "off command received"
sendEvent(name: “switch”, value: “off”)
}

// Test child integration
void childon(x){
log.debug “On command from ${x}”
}
void childoff(x){
log.debug “Off command from ${x}”
}

Child device handler:

/**

  • Test Child DH

*/
metadata {
definition (name: “Test Child DH”, namespace: “rlmillerx”, author: “Ralph Miller”) {
capability "Switch"
capability "Actuator"
capability "Sensor"
capability “Refresh”
}

tiles {
	standardTile("controller", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
		state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"on"
		state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC", nextState:"off"
						}
	}

}

void on() {
log.trace "Child was turned on"
try {
log.debug " Parent is ${parent.name}"
log.debug "Device ID is ${device.deviceNetworkId}"
parent.childOn(device.deviceNetworkId)
log.debug “parent.childOn was just called”
} catch(Exception ex) {
log.debug “Exception ${ex}”
}
}

void off() {
log.trace "Child was turned off"
try {
log.debug "Parent is ${parent.name}"
log.debug "Device ID is ${device.deviceNetworkId}"
parent.childOn(device.deviceNetworkId)
log.debug “parent.childOn was just called”
} catch(Exception ex) {
log.debug “Exception ${ex}”
}
}

@rlmillerx
Can you edit the post and use the pre-formatted text flags, that way it appears correctly and will be easier to check in my own IDE. From a quick glance I agree it does look like it should be working and print the ‘On/Off command from x’ message. Unless something is failing before that to mean it never gets called.

Two suggestions:

  1. It is likely that the SmartThings team may have created a device called testchild while they are doing their own testing. If they happen to have done some craziness with publishing it publically (quite likely) then it may not be using the child device handler you have created or the right child. I would suggest picking a slightly less common name or adding a number at the end for example. I would also probably ensure you specify the namespace as the first parameter since they could also have a public DTH called ‘Test Child DH’…
  2. I would try adding the hub as location, rather than null. I have found null sometimes doesnt work well for me, but using the correct location helps. Instead of the ‘null’ part use ‘device.hub.id

I tried both your suggestions and they made no difference. So here are the revised files using the pre-formatted text flag.

/**
  • Test Parent DHx
  • Copyright 2017 RALPH MILLER
  • 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.

*/
metadata {
definition (name: “Test Parent DHx”, namespace: “rlmillerx”, author: “RALPH MILLER”) {
capability "Switch"
capability "Sensor"
capability “Actuator”
}
}

preferences {

    command "childon", ["string"]
    command "childoff", ["string"]
         
}

simulator {
    
}

tiles (scale: 2) {

   standardTile("thermPresence", "device.switch", inactiveLabel: false, width: 3, height: 3) { //, decoration: "flat"
		state "on", label:'Home', action:'off', backgroundColor: "#44b621", icon: "st.Home.home2", nextState:"Updating"
		state "off", label:'Away', action:'on', backgroundColor: "#ADD8E6", icon: "st.Home.home2", nextState:"Updating"
        state "Updating", label:"Updating", backgroundColor: "#ffffff", icon: "st.secondary.secondary" 	//, defaultState: true
        
	}

}

def installed() {
initialize()
}

def updated() {
initialize()
}
def initialize() {
// create child switch
// first check if child device is already installed
def childDevices = getChildDevices()
log.debug "${childDevices}"
log.debug "${childDevices.size()}"
if (childDevices.size() == 0) {
log.trace "Creating Child"
try {
addChildDevice(“rlmillerx”, “Test Child DHx”,“testchildx”,device.hub.id, [completedSetup: true, label: “TestChildx”, isCompenent: false, componentLabel: “TestChild”])
} catch(Exception e) {
log.debug “${e}”}
log.trace “Child created”
}
}
// handle commands
def parse(String description) {
log.debug “parse: description = ${description}”

}

def on() {
log.trace "on command received"
sendEvent(name: “switch”, value: “on”)
}

def off() {
log.trace "off command received"
sendEvent(name: “switch”, value: “off”)
}

// Test child integration
void childon(x){
log.debug “On command from ${x}”
}
void childoff(x){
log.debug “Off command from ${x}”
}

/**
  • Test Child DHx

*/
metadata {
definition (name: “Test Child DHx”, namespace: “rlmillerx”, author: “Ralph Miller”) {
capability "Switch"
capability "Actuator"
capability "Sensor"
capability “Refresh”
}

tiles {
	standardTile("controller", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
		state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"on"
		state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC", nextState:"off"
						}
	}

}

void on() {
log.trace "Child was turned on"
try {
log.debug " Parent is ${parent.name}"
log.debug "Device ID is ${device.deviceNetworkId}"
parent.childOn(device.deviceNetworkId)
log.debug “parent.childOn was just called”
} catch(Exception ex) {
log.debug “Exception ${ex}”
}
}

void off() {
log.trace "Child was turned off"
try {
log.debug "Parent is ${parent.name}"
log.debug "Device ID is ${device.deviceNetworkId}"
parent.childOn(device.deviceNetworkId)
log.debug “parent.childOn was just called”
} catch(Exception ex) {
log.debug “Exception ${ex}”
}
}

When using the preformatted text flag it should appear like this, can you edit the post with these, just so nothing gets lost. Ideally one for parent and child so it is easier for other people to follow and copy aswell.
Thanks

def off() {
log.trace "off command received"
sendEvent(name: “switch”, value: “off”)
}

// Test child integration
void childon(x){
log.debug “On command from ${x}”
}
void childoff(x){
log.debug “Off command from ${x}”
}

/**
Test Child DHx
*/
metadata {
definition (name: “Test Child DHx”, namespace: “rlmillerx”, author: “Ralph Miller”) {
capability "Switch"
capability "Actuator"
capability "Sensor"
capability “Refresh”
}

tiles {
	standardTile("controller", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
		state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"on"
		state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC", nextState:"off"
						}
	}
}

void on() {
log.trace "Child was turned on"
try {
log.debug " Parent is ${parent.name}"
log.debug "Device ID is ${device.deviceNetworkId}"
parent.childOn(device.deviceNetworkId)
log.debug “parent.childOn was just called”
} catch(Exception ex) {
log.debug “Exception ${ex}”
}
}

void off() {
log.trace "Child was turned off"
try {
log.debug "Parent is ${parent.name}"
log.debug "Device ID is ${device.deviceNetworkId}"
parent.childOn(device.deviceNetworkId)
log.debug “parent.childOn was just called”
} catch(Exception ex) {
log.debug “Exception ${ex}”
}
}

If you could post the code that shows the creation of the child devices, that would be helpful as well. You could use something like pastebin if the preformatted option isn’t working for you.

A couple things with the posted code (that probably aren’t related to your problem but maybe), the method name is case sensitive. So the parent method is named childon, but the child is calling childOn.

Also, you don’t need to declare the commands childon and childoff as you have (plus, they wouldn’t be declared in the preferences section but under the capabilities).

I have not been able to figure out how to do pre-formatted text. Can you give me a detailed explanation and I will do it.

I tried the two things you mentioned, and they did not make any difference.

The code which creates the child is already shown in the parent device handler initialize() section.

Believe it or not, I just got it working. In my code both the childOn and the childOff were calling the off() command. That was the whole problem.

Thanks so much for your help. I can now go back to my real device handlers and get them working.

2 Likes

Hi Eric,

Been following your posts with regard to 2 gang switches. I can see you have solved many issues for people and seems you are the best in the business. You have made my learning curve a little easier so cheers for that.

I have used your app to create virtual switches but just can’t see why the app does not pick up any endpoints from the DH I am using. The DH works fine with 2 switches but of course they can not be used in automation unless 2 buttons are presented on the “things” page of the ST app. In Australia or (Fraggle Rock when it comes to technology) we are limited to devices/switches we can use here. I’m using a Zigbee 2 gang in wall switch made by “Feibit Inc co” and would love to get these things working in automation. Sorry if posted in wrong area but any advice/direction would be good. Happy to post the DH if needed.

I’m not sure I follow, can you break it or a bit so I know what you have and what works. You have a working DTH but with child switches all on one page and not as separate devices. You can create children but then they don’t respond, is that correct?

Solved!!!
Sorry for the confusion. The issue was related to virtual switches. The device handler I am using for my 2 gang in wall zigbee switch works just fine. I can go into the ST app click on the sw1, which takes me to a second page, where I find sw1 and sw2 switches. However, when setting up automation in the ST app to control these switches, only sw1 was showing as an option, hence the need for virtual switches.

I was using the “Virtual Device Sync” app by Eric to attempt to solve the problem. Although the app allowed me to produce 2 virtual switches, they did not operate the switch. I followed the instructions from Eric and noticed during the setup that “0” endpoints were found and is the reason why I was not able to operate the switch via the virtual switches.

I eventually found another ST app that works with the DH I am using along with the Feibit zigbee switches (http://3asmarthome.com/products) I now have 2 virtual switches working perfectly.

Sorry if I have only created more confusion here but as a newbie, I’m not able to explain any other way. Still learning the jargon and what ever the hell else I need to know getting “things” to work. In any case, if some else has this problem with these switches, I can at least attempt to explain how I solved the problem. Thanks for the response though…awesome!

Hi Eric, I am using your Fibaro Dimmer and Motion sensor device handlers with success. I have additionally installed your ‘Metering child handler’ and the Fibaro Double Switch device handlers. I can not get the second switch button to work, I am only getting one button and it handles but ‘switches’. Anything I have done wrong!

Hmm, so the child devices don’t show below the main tile? You could try hitting the gear icon and then hitting “save” to see if they get created. Also, watch the IDE logs while you do this to see if any errors appear.

Hi Eric,
Thanks for responding. I am a newbie to SmartThings and I probably selected the wrong Child Device handler. I had selected the Common Child DH you have created, and after installing your METERING Child DH it is now working fine!

During installation I several times received the error msg “not auth. by the specified access token”, but now it’s working fine.

I have minor problems with device status: sometimes it take long time to change from “turningon” to “on”, and synchronization between child and main status on the switch seems also to be slow (minutes). I hope it isn’t a nw coverage issue since this is only a small pilot to test the Fibaro Motion, Switch, and Dimmers before rolling out in 400sqm house.

Again, thanks for your excellent work to develop and mature this segment.

Hmmm, I don’t remember mine taking minutes to update, but I haven’t used the device in quite a while. If you back out of the device in the app and go back in does it update quicker?

Hi Barry,
Would you mind going into more detail how you solved the Feibit multi gang light switch issue?
I have the same products and am trying to get each switch in the gang to appear on Action Tiles.
Background for others, the zibee light switch device has multiple switches on the light switch plate. Each switch in the device controls different sets of lights, e.g. One for kitchen lights, one for hallway lights. When adding the device to Action Tiles or performing Automation, only the device appears and not the individual switches in the device.

I have a three gang zigbee light switch which I have set up with Child devices. (Feibit brand)
The child devices appear to be registered correctly. However, when click on the child icon in the mobile app, I am unable to turn the child switch on. I have put the same code in the Parent On function and it works fine.
Is there a special technique to call the On and Off commands in the Child On functions?
The code I have tried in the parent DH for the child is as follows. I have hardcoded the device ID for ease of testing. It will be part of the dni when I get something working
def relayOn(String dni){
//First try
sendEvent(name: “switch”, value: “on”)
“st cmd 0x886B 0x11 0x0006 0x1 {}”
// Second try
device.endpointId = “11”
zigbee.on()
}