Closed DDevine closed 3 years ago
A work-around I am considering is something like the following:
ReceivedFromProxy
is not fired from irrelevant controllers.The architecture for Control4 bindings is not designed for many-to-many connections. A single provider can be connected to many consumers, and vice versa.
When you are designing for multiple controllers and clients, is a client bound to any one specific controller, or is it to be bound to all of them?
If a client is connected to just one controller, then you should be able to use the existing architecture, albeit with autobind disabled and instead using C4:Bind ()
dynamically instead in the response to AddDevice
. I have actually already developed this for recent drivers and will update the sample drivers today to reflect this: watch this space!
If it's a true full-duplex many-to-many then there isn't a "simple" solution that arbitrarily scales without abandoning connections altogether and doing dynamic runtime discovery (using C4:GetDevicesByC4iName ()
) of all of the client/controller devices in the project and doing direct C4:SendToDevice ()
commands to do the transit.
I'm doing one-to-many (from a single controller to multiple clients - A client must only have a single controller) but to work around the initalisation issue each client must be initialised with all the possible IDC connections. Dynamically adding them after initalisation doesn't seem to work. I need multiple IDC controllers to be present in the project, but the IDC clients need to be specific to that controller.
Since I am passing a message with the proxy id in my comissioning message this is a simple way to know which connection to keep and the rest can be removed. No pinging or listing out drivers by name is needed. I have written the code but I didn't get a chance to test it today - I expect it to work though.
This might be a silly question but I have been unable to find the answer - why does autobind need to be disabled? I assumed that it should do nothing.
I did consider using C4:Bind()
but it seemed overkill.
If you use autobind, then any added clients will autobind to the first controller in the project, regardless of which one added them.
I've updated the IDC code example (see the commit referenced above) so that autobind is removed, and the controller device adding the clients does the bind after the add is successful (and then waits a little before sending the init information to the client).
This is how it is deployed (and tested) in multiple released drivers in production now, and is how we will do this in similar scenarios going forward.
I noticed now that isProvider
is true
in the example code for the IDC Client example in the first post . This is wrong but I don't think I made this mistake in my actual code. So now I understand why you must have thought I was doing many-to-many.
I'm a lot more confident with using C4:Bind as a solution with that example, thanks!
To answer the first question you asked though: yes, you should recreate any known bindings on driver startup before any OnDriverInit or OnDriverLateInit callbacks (i.e. in the main scope of the driver). The bindings must be recreated at this point in order for the ConnectionManager component of Director to reconnect bindings at startup that were previously connected. If they don't exist, they won't be rebound once the driver loads.
Where we have done this in the past, we have used PersistData (which is available immediately on driver main scope) to store the details for dynamic connections that should be recreated, where there is a non-standard number that should be created.
I am creating a drivers that have an IDC Controller and an IDC Client. I do not know how many controllers and how many clients there will be ahead of time, so I am trying to use
AddDynamicBinding
andAddDevice
to allow a driver to automatically commission the system.The IDC Controller side of things seems to work just fine. I can create the binding anywhere ( eg. inside
OnDriverLateInit
) and it seems to work in any scenario.Example IDC Controller.
However, in an IDC Client I must run
AddDynamicBinding
outside of all functions. This is mentioned in the documentation https://control4.github.io/docs-driverworks-api/#adddynamicbinding and I can confirm this seems to be true when it comes to the IDC Client. When I do this with a static/known binding ID, everything works fine. But a static ID will not work for my use-case.Because I am creating instances of the IDC Client using
AddDevice
I do not know the bindingID at the time the driver is loaded. When I try sending the binding ID directly to the device (withSendToDevice
on a static binding) and then runningAddDynamicBinding
the new binding is added but is not connected to the to the IDC Controller. The "Connected To" / "Connections" fields in Composer Pro are empty and I cannot send/receive over the IDC.Example IDC Client.
So it seems like you can create a dynamic binding anywhere, but if you want to connect to that dynamic binding you must do it when the driver is loaded.
Can someone confirm this behaviour? Is this a bug? Any work-arounds? Is there a way to create the connection on the newly created binding?