I decided to create a separate topic for this portion of the driver so that it did not clutter the other thread. This thread is for developers that would like to use Virtual Containers within their smartApps.
As of v1.1.20181118 VC allow smartApps to dynamically create a container, populate them with child devices and also allow these child devices to communicate through their container back to the smartApp that created them.
Currently only one child parameter can be passed through the Virtual Container
The following methods can be utilized for this function
-
appCreateDevice("childDeviceLabel", "driverName", "driverNameSpace", "uniqueIdentifier") - method for use by smartApps to dynamically create a child device within a Virtual Container. The "uniqueIdentifier" parameter allows the smartapp to index all the children in some way.
-
childList() - to be used by parent smartApps to request a list of all the container's childDevices.
-
childComm("Command to execute", "parameter", "Child Device Id") - this method needs to be used from the child driver code. It allows child devices to communicate through the container and back up to the parent smartApp (single parameter only). This is only possible with custom (non hubitat) child drivers for obvious reasons.
Sample Code uses a Playlist Container that houses "Preset Stations" as child devices
Part 1A. Sample code for creating a container with you smartApp:
def createContainer(){
def container = getChildDevices().find{it.typeName == "Virtual Container"}
if(!container){
log.info "Creating Playlist Virtual Container"
try {
container = addChildDevice("stephack", "Virtual Container", "Playlist${app.id}", null, [name: "Playlist-Container", label: "Playlist-Container", completedSetup: true])
} catch (e) {
log.error "Container device creation failed with error = ${e}"
}
}
}
The above will create a Virtual Container with:
label - "Playlist-Container"
deviceNetworkId - "Playlist${app.id}"
Part 1B. Sample code for creating a child within the above container (appCreateDevice method):
def createVchild(uniqueIdentifier){
def container = getChildDevices().find{it.typeName == "Virtual Container"}
if(container){
container.appCreateDevice("My Container Child Playlist l", "stephack", "Sonos Playlist", uniqueIdentifier)
}
}
The above will create a Virtual Container child device with:
label - "My Container Child Playlist l"
driver - type is "Sonos Playlist" in namespace "stephack"
data value "vcId" - the vcId data value will hold the unique identifier that can reference a specific child in the container.
Part 2. Sample code to retrieve a list of child devices stored in the Virtual Container (childList method):
def getContainerChildren(){
def container = getChildDevices().find{it.typeName == "Virtual Container"}
def vChildren = container.childList()
if(vChildren.find{it.data.vcId == "stationID"}){
log.info "Found the Play List with Station ID 'stationID' that you are looking for"
}
}
Part 3. Custom Driver Sample Code:
Continuing from the example above, let's say you want one of the child devices to execute playTrack(uri) method in your smartApp. The code in the child driver would look something like this
def sendUri(stationURI) {
log.debug "Playing track = '${stationURI}'"
def childID = device.data.vcId
if(childID) parent.childComm("play", stationURI, childID)
}
This will tell the container device that you would like to execute the play(stationURI, childID)
command from the parent smartApp.
To link back to the appCreateDevice command in Part 1B that created the child in the first place....childId would have a value of "uniqueIdentifier" when you created the device.
Part 4. smartApp sample code:
def play(stationURI, childId){
log.info "Starting PlayList ${childId}"
playTrack(stationURI)
}
The above will play the track that the child device requested.