Very basic help needed. Learning to code

Just a custom app, custom driver. Is there settings to link those together?

If the app creates the devices (using addChildDevice()), then that device is a "child" device of the "parent" app and you can do the above. If there's a good reason for the app and devices to be "linked," then that is a good idea (e.g., Hubitat's Hue Bridge Integration app probably does this for Hue Bridge bulbs and groups; I do in my custom integration as well, giving the "parent" app access to things on the Bridge child device that make a lot of things easier to do than they would otherwise be). If there's no reason for the app to create the device, this might make less sense or even make things harder for the user, but if the user is just you, I guess you can do whatever works. :slight_smile:

This isn't something you can see in the UI (they just show as "regular" devices, though there are also parent/child apps and parent/child devices where this structure is apparent), and it's not something you can change after the fact (it can only be a child device by virtue of having been created by the parent app).

Got another one.

I'm trying to do the following. It doesn't like me using the variable, but if I type in the text it will work. If I change $var to what it actually is, it will work.

Any clues?

httpGet([uri:"http://192.168.100/site"], { response ->
def blah = response.data.devices.$var.status
log.debug "The variable blah is $blah"

    })
1 Like

Try either:

response.data.devices."$var".status
or
response.data.devices[var].status

There is some useful discussion along these lines here: groovy - How to use a variable for the key part of a map - Stack Overflow

Here's a demo:

def traceRandomCode()
{
    def subMap = [blue:"b", red:"r"]
    def superMap = [subMap1: subMap, name: "superMap"]
    
    logDebug("superMap = ${superMap}")
    
    def var = "subMap1"
    
    logDebug("superMap[var].blue = ${superMap[var].blue}")
    logDebug("superMap.\"\$var\".blue = ${superMap."$var".blue}")
}




[dev:3423](http://10.0.0.4/logs#dev3423)2020-06-01 01:06:05.299 pm [debug](http://10.0.0.4/device/edit/3423)superMap."$var".blue = b

[dev:3423](http://10.0.0.4/logs#dev3423)2020-06-01 01:06:05.298 pm [debug](http://10.0.0.4/device/edit/3423)superMap[var].blue = b

[dev:3423](http://10.0.0.4/logs#dev3423)2020-06-01 01:06:05.296 pm [debug](http://10.0.0.4/device/edit/3423)superMap = [subMap1:[blue:b, red:r], name:superMap]
2 Likes

This worked! Thanks man!

1 Like

Stumbled across this thread, as I am trying to do exactly what you described - I have a method defined in the driver for a child device, and trying to call that method from the parent app. Do you have an example of the syntax for such a call?

Now I'm wondering if I have it backwards. I'm trying to find an example I thought I did but can't. (By "backwards," I mean that child devices can call arbitrary methods on the parent app--not that there's any other options since apps don't have "commands.") It may not actually be possible. Someone can correct me if I'm wrong here.

Yes, I can successfully call parent.appMethod() from the child driver, but calling child.driverMethod() throws an error - wondered if I was simply calling it incorrectly.

It sounds like I would have to expose it as a command for the device, in order to call it from the app? In reality, I'm trying to get/set a state variable on the child device... Any alternative tips?

I think exposing it as a command might be the only way. To set the state variable, you can make a command with a parameter and pass it that way. Getting it from the child if you're calling from the parent is a bit harder since to my knowledge there is no documentation for command methods returning values, but if this value is of possible use to the user, you could use an attribute (generate an event) instead, or you could create a method on the parent device to "set" some state value and call that from the child to pass it up that way. The best solution to this likely depends on what these values really mean and whether a user would likely want to use them.

You need a reference to the child device.

getChildDevice(DNI) is the interesting method. I frequently follow a pattern of getChildDevices() followed by iterating over the resulting list to find the specific child that I wanted to operate on. You can call a driver method directly that way, including all (or most?) of the methods on the device object: https://docs.hubitat.com/index.php?title=Device_Object

I'm not sure exactly how to get and set state directly, but I'd make get/set accessor methods personally (similar to what @bertabcd1234) described.

Hmm - I have a reference to the device - I think as a generic DeviceWrapper object, perhaps I need to make this more specifically a ChildDeviceWrapper via getChildDevice(device)? Will give this a try...

Here's how I do it:

In the app:
getChildDevice(getGroupName()).unbindGroupFromApp()

getGroupName() is a method in the app that creates the DNI format (a string) that the app uses when creating child devices

In the driver:

def unbindGroupFromApp()
{
    logDebug("unbindGroupFromApp()")
    
    unbindGroup()
}

unbindGroupFromApp() is not a command on the driver
unbindGroup() is another method in the driver that happens to be a command implementation, but this shouldn't be necessary.

I did it this way in case I wanted to do anything additionally from the app when executing that command.

1 Like

I literally figured it out, at least for me.

def updateChildDevice() {

child = getChildDevice("deviceNetworkId")
log.debug "$child"

if(child) {

child.updateSetting("inputNameVar", "$var_content")

}
1 Like

Yes, it seems that a DeviceWrapper is not sufficient - even if that device is a child of the app - getChildDevice(device.getNetworkId()).childMethod works great! Thanks for the help arriving at this conclusion!