Skip to content

Nested element groups in the app

How to configure elementsJson and controlPages for a group -> groups -> devices structure in Spectoda Connect.

In Spectoda Connect, a Network JSON can define a group -> groups -> devices structure. This is done in elementsJson, where a group is a regular element with a childElementIds field.

A group can contain:

  • other groups,
  • end devices with spectodaId,
  • or a combination of both.

A complete copyable example is available in the GitHub repository: network-nested-element-groups.

An end device has its own spectodaId and a reference to one or more control pages:

{
"id": "element-stage-left-main",
"name": "Stage Left Main",
"spectodaId": 11,
"controlPageRefs": [
{
"id": "DIMMA"
}
]
}

A group does not necessarily need its own spectodaId. During rendering, the app calculates the list of Spectoda IDs from its children:

{
"id": "element-group-stage-left",
"name": "Stage Left",
"childElementIds": [
"element-stage-left-main",
"element-stage-left-ambient"
],
"controlPageRefs": [
{
"id": "DIMMA"
}
]
}

This creates a normal group that can be opened in the app and controlled as a logical unit.

If the group page should show child cards immediately, add expandedElements to the relevant controlPageRefs item:

{
"id": "element-group-stage",
"name": "Stage",
"childElementIds": [
"element-group-stage-left",
"element-group-stage-right",
"element-backdrop-rgb"
],
"controlPageRefs": [
{
"id": "DIMMA",
"expandedElements": [
{
"id": "element-group-stage-left",
"controlPageRef": {
"id": "DIMMA"
}
},
{
"id": "element-backdrop-rgb",
"controlPageRef": {
"id": "COLOR"
}
}
]
}
]
}

expandedElements tells the app which direct children should be displayed inline and which control page each child should use.

  • expandedElements[].id must be a direct child of the current group, so it must appear in childElementIds.
  • A group must not expand itself.
  • The child must include the same page in its own controlPageRefs as the parent references through controlPageRef.id.
  • The target control page must exist in controlPages.
  • For another nesting level, repeat the same pattern on the next group element.

In other words: the parent decides which of its direct children are shown inline; the child decides which control pages it actually supports.

The control page must exist in the controlPages array and must have either eventControlPage or component. For inline expanded children, use eventControlPage.

A minimal brightness page can look like this:

{
"id": "DIMMA",
"name": "Brightness",
"eventControlPage": {
"id": "brightness-control-page",
"config": {
"columns": 1,
"maxWidth": "default"
},
"eventControls": [
{
"id": "brightness-slider",
"name": "Brightness",
"type": "slider",
"EVS": {
"type": 30,
"label": "brigh"
},
"config": {
"min": 0,
"max": 100,
"step": 1,
"unit": "%",
"icon": "SunIcon"
}
}
]
}
}

In a real project, EVS.label must match what the firmware and TNGL/Berry logic use. If the project uses a label other than brigh, change it in the control page.

To show groups directly on the home screen, add a reference to the group element into homepage.sections:

{
"id": "deco-stage",
"layout": "grid-tight",
"source": {
"type": "element",
"element": {
"id": "element-group-stage"
}
}
}

This is not required for nested groups to work, but it helps keep app navigation clear.

  • Every id in childElementIds exists in elementsJson.
  • Every controlPageRefs[].id exists in controlPages.
  • Every inline child in expandedElements is a direct child of the current group.
  • Every inline child has the page referenced in controlPageRef.id in its own controlPageRefs.
  • Every controllable end element has a spectodaId in the 0..255 range.

The full example for elementsJson, controlPages and homepage is here: Spectoda examples / network-nested-element-groups.