Thank you for providing this sample, I will share it with the team so they can replicate the issue and give us feedback.
Great sample @rossetyler
Hi, @rossetyler. Sorry for the delay, the engineering team mentioned the following about your sample:
- In the driver you arenât using any sockets at all, so there are no calls to
receive
but you use bothcosock.socket.sleep
andcosock.socket.select
-
In this file it is not clear if one of those functions is getting called in the
added
lifecycle and that is blockinginit
. - You should check if the creation of the devices was successful using
assert(driver.try_create_device(...))
orlocal success, err = driver.try_create_device(...)
. This way, you can see if there were immediate errors.- Especially because, in your sample, youâre calling
try_create_device
in a hot loop100
times and this might be reaching the rate limit of devices created in a given timespan.
- Especially because, in your sample, youâre calling
In this case, this number of devices was an example, or do you actually have drivers that create 100
devices? If so, could you share the details of that use case?
- Any time something could block the current thread, you can avoid that entirely by calling
cosock.spawn
. So, something likecosock.spawn(function() local value, err = socket:receive() end)
would allow the use of the device thread for any other device events. For example:
This sample shows how the device thread can be blocked
-- This driver will lock up any device thread by
-- yielding the thread into a deadlock because
-- init cannot be processed until added is complete
-- but added is relying on init to complete
local tx, rx = cosock.channel.new()
local function added(driver, device)
-- wait for init
local init, err = rx:receive()
end
local function init(driver, device)
-- send init
tx:send(device.id)
end
local driver = Driver("...", {
lifecycle_handlers = {
added = added,
init = init,
}
})
Considering the previous implementation, this is how we can avoid the blockage using cosock.spawn
local tx, rx = cosock.channel.new()
local function added(driver, device)
cosock.spawn(function()
local init, err = rx:receive()
end)
-- wait for init
end
local function init(driver, device)
-- send init
tx:send(device.id)
end
local driver = Driver("...", {
lifecycle_handlers = {
added = added,
init = init,
}
})
I have said most of this before âŚ
There are two drivers that I have discussed
- Legrand RFLC
- Bug
Legrand RFLC tries to create ~35 devices all at once: one for the LC7001 lighting controller (bridge) and the rest for the lights that it controls.
Bug was created in an attempt to simply illustrate the issue.
Neither of these has an added lifecycle handler so neither could block my init lifecycle handler.
Yet my Legrand RFLC logs added events and some are not followed by inits.
Failed try_create_device calls and rate limiting do not explain this.
Legrand RFLC does use cosock sockets (see lc7001 module).
Bug does not use any cosock features nor does it explicitly block anywhere (see code).
An LC7001 lighting controller can control up to 100 lights (that is where 100 comes from). Mine, currently, only has ~34.
What is the rate limit on try_create_device calls?
Where else are rate limits going to bite me?
I am concerned about the refresh capability on my parent LC7001 controller that refreshes each of its children.
For each, it will make
-
device:online or device:offline
-
device:emit_event switch on or off
-
device:emit_event switch level
So, refreshing ~33 dimmers will make ~100 such calls all at once.
If this is a problem, how can I deal with it?
Reviving this threadâŚI found nearly the same issue with driver switches. During creation, many developers have been working around this by slowing down the device creation. During a driver switch, this canât be done. When switching my driver, I can see the added
and driverSwitched
called for all of the devices, but many of them miss their init
calls. The hub has to be restarted to force the init to be called. The added
and driverSwitched
donât do anything other than call device:set_field()
so I donât think they are blocking. Some of the fields are persisted.
Hi @rossetyler - I realize this thread is ancient, but I have a client with an LC7001 who spent many thousands investing in Legrandâs Adorne switches and would like to get them doing more automated things vs just used in the Legrand app. Is this Edge driver available for the public? Would be a huge problem solver for me. Hope youâre still around the forum!
That sounds like me.
Yes, but perhaps not in the form you want. I have not published a public channel that you can subscribe to. I no longer use my own private channel for such as I have bit the bullet and migrated away from Legrand Adorne (know anyone that wants a deal on thousands of dollars of such equipment?)
The code and build instructions for this SmartThings Edge Driver are public.