EDGE_CHILD creation - We solved it, but is this the right way?

ey everyone,

We’re working on an MQTT driver that uses a “Creator” device to dynamically create virtual energy meters. Needless to say, we had a heck of a time trying to get EDGE_CHILD devices to spawn…

We ran into the “Silent Rejection” issue: the log says everything is fine, try_create_device runs, but the device is nowhere to be found. After days of debugging and digging through the forums (thanks to everyone for the previous posts!), we finally figured it out.

It seems the platform is dead serious about how child devices are created, and there’s a “holy trinity” of parameters that, if you don’t get them exactly right, it just silently drops your request.

The code that finally worked:

Here’s our create_energy_device function that’s now doing its job. The magic is all in the new_device_args table.

-- Required libraries
local log = require "log"
local socket = require "cosock.socket"
local utils = require "st.utils"

-- ...

function create_energy_device(driver, device, command)
    local deviceName = command.args.deviceName
    if not deviceName or deviceName == "" then
        log.warn("Device name cannot be empty.")
        return
    end

    log.info(string.format("Creating new virtual energy meter named '%s'...", deviceName))

    -- Generating the key to make sure it's unique
    local child_key = "MQTT_Energy_" .. deviceName:gsub("%s+", "_") .. "_" .. socket.gettime()

    -- The "Holy Trinity" - the key part that was missing
    local new_device_args = {
        type = "EDGE_CHILD",
        parent_device_id = device.id,
        parent_assigned_child_key = child_key,
        label = deviceName,
        profile = "mqtt-energy-st-energy.v1",
        manufacturer = "SmartThingsCommunity",
        model = "Virtual-Energy-Meter"
    }
    
    -- Just in case, logging what we're sending
    log.info("Sending device creation request with the following metadata:")
    log.info(utils.stringify_table(new_device_args))

    local success, err_msg = driver:try_create_device(new_device_args)
    if success then
        log.info(string.format("Creation request for device '%s' sent successfully.", deviceName))
    else
        log.error(string.format("Failed to send creation request: %s", tostring(err_msg)))
    end
end


Our key takeaways were:

  1. type absolutely must be EDGE_CHILD.

  2. parent_device_id is mandatory.

  3. You have to use parent_assigned_child_key instead of device_network_id.

So, our question to the more experienced folks here: Does this look right to you? Is there anything we missed or could be doing better?

Thanks in advance for any feedback!

Looks good!

The timestamp in the child_key is a bit of overkill for my taste - it’s very unique, but makes it difficult to identify a specific device later on. Usually something like this is enough:

local function create_child_devices(driver, device)
  local children_amount = get_children_amount(device)
  for i = 2, children_amount+1, 1 do
    local name = string.sub(device.label, 1, 9)
    if find_child(device, i) == nil then
      local metadata = {
        type = "EDGE_CHILD",
        parent_assigned_child_key = string.format("%02X", i),
        label = name ..' '..i,
        profile = "profile-name",
        parent_device_id = device.id,
        vendor_provided_label = name ..' '..i,
      }
      driver:try_create_device(metadata)
    end
  end
  device:refresh()
end

Haven’t seen a dot in a profile name before, so maybe mqtt-energy-st-energy.v1mqtt-energy-st-energy-v1 .

Everything else looks like the standard way to do it.

​Hi,

​Thanks a lot for the quick and very helpful feedback! It was great to get confirmation that we’re on the right track, especially after struggling with the “Silent Rejection” issue.

​Your suggestions make perfect sense, and we’ve already implemented them:

  • ​We’ve made the child_key deterministic by removing the timestamp.

  • ​We’ve also changed the dot to a dash in the profile name to stick to the convention.

​Thanks again for the help!