Context for developing and debugging Hubitat Elevation apps, drivers, and hub environment — sandbox constraints, lifecycle idioms, capability contracts, plus grounded deploy/log-tail/lint mechanisms.
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
High
Do not use without reviewing
A Hubitat device can own other devices. The owner is a parent, the owned are children, and the set is one physical thing (or one cloud account) projected as several hub devices — a power strip's outlets, a Hue bridge's bulbs, a dual switch's two loads.
Sources: Hubitat's Parent/Child Drivers
doc and its genericComponentParentDemo.groovy / genericComponentDimmer.groovy examples, plus the
/hub2/devicesList tree verified live on 2.5.1.128 (C-8 Pro) against a hub of 151 top-level
devices and one parent owning 5 children.
rules/device-lifecycle.md). These are harder to see: the device is not indented anywhere,
and its only tell is a "Parent app" row in the Device Details table on the device page's
Device Info tab (/device/fullJson/<id> exposes it as parentApp — skills/_reference/endpoints.md).Both make the device a child. Only the reporting differs.
GET /hub2/devicesListReturns {suggestBackup, devices:[...]}, and devices is a tree, not a flat list. Each entry
is {key, data, children, parent, child}:
key — DEV-<id>parent — bool: this device is a parent. It is not a pointer to one.child — bool: this device is a child.children[] — the owned entries, same shape, nested.Children appear only nested — never at the top level. The grounded hub returns 151 top-level
entries and 5 children reachable only by walking children[] (156 devices in all). Iterating
devices[] without recursing silently misses every child device.
Verified child entry: parent:false, child:true, driver type Zooz Power Strip Outlet Component,
DNI 1A-CH1…1A-CH5 under parent DNI 1A. Deriving a child DNI from the parent's is the common
pattern, not a requirement — the docs state authors may use any convention, and Hubitat's own
example keys on the parent's device.id instead ("${device.id}-${type}").
data.source is System | User | Linked. Linked marks a hub-mesh device owned by another
hub — orthogonal to parent/child (2 on the grounded hub).
rules/zwave-zigbee-mesh.md)./device/fullJson/<id> lists child devices, so
the removal blast radius includes them (rules/device-lifecycle.md).skills/device-migration/SKILL.md.addChildDevice(namespace, typeName, deviceNetworkId, properties).
Hubitat's example: addChildDevice("hubitat", "Generic Component Switch", "${device.id}-Switch", [name: "...", isComponent: true]). Built-in component drivers use namespace hubitat; a
custom child driver uses its own.Xyz() calls componentXyz(cd) on the parent,
passing the child device as the first parameter (componentOn(cd), componentSetLevel(cd, level, transitionTime)). The parent does all the Z-Wave/Zigbee/Matter/LAN talking.parse() on the child with a List of Event
maps — getChildDevice(cd.deviceNetworkId).parse([[name:"switch", value:"on", descriptionText:"..."]]). Component drivers turn those into events. This is the convention, not
sendEvent on the parent (rules/state-vs-attributes.md).getChildDevice(dni) / getChildDevices().input (rules/app-lifecycle.md).