Plugin and childs

Hello,

I have a question concerning plugins and their childs.

The question comes from this subject:

To summarize: the plugin Arduino for MySensors on Vera (GitHub - mysensors/Vera: MySensors plugin for the Vera controller) manages the communication with the MySensors network. It creates child modules in the Vera UI, which represent the sensors.
For the RGB LED Strip, it reuses a stand-alone plugin by declaring as its child : the RGB Controller plugin.

This plugin has handleChildren=1, so it’s its implementation file that handles all the actions of its child.
For simple devices, as temperature sensors, it’s just an update of their variables.
For the RGB Controller, it’s more complicated.

I’ve not tested it by myself, thus I am only supposing the behavior.
It seems that the parent (Arduino plugin) is able to call functions present in the file declared in the implementation file of the child (the RGB Controller device).
Besides, the function for the startup declared in the child devices, seems to be called with the id of the parent.

1/ I do not understand the process of initialisation of the devices.
When is used the startup section of the plugin ? Just for the parent and not the childs ? Or called for all children ?

2/ Besides it seems that the functions of the child are in the same context that the parent.
Does it mean that there can be collisions and namespaces should be used in plugins ?
It seems to show that the code of a plugin, wich was designed to be stand-alone, can be reused… the developers which use the encryption of their sources are going to be happy :slight_smile:

[quote=“vosmont, post:1, topic:189244”]Hello,

I have a question concerning plugins and their childs.

The question comes from this subject:

To summarize: the plugin Arduino for MySensors on Vera (GitHub - mysensors/Vera: MySensors plugin for the Vera controller) manages the communication with the MySensors network. It creates child modules in the Vera UI, which represent the sensors.
For the RGB LED Strip, it reuses a stand-alone plugin by declaring as its child : the RGB Controller plugin.

This plugin has handleChildren=1, so it’s its implementation file that handles all the actions of its child.
For simple devices, as temperature sensors, it’s just an update of their variables.
For the RGB Controller, it’s more complicated.

I’ve not tested it by myself, thus I am only supposing the behavior.
It seems that the parent (Arduino plugin) is able to call functions present in the file declared in the implementation file of the child (the RGB Controller device).
Besides, the function for the startup declared in the child devices, seems to be called with the id of the parent.

1/ I do not understand the process of initialisation of the devices.
When is used the startup section of the plugin ? Just for the parent and not the childs ? Or called for all children ?

2/ Besides it seems that the functions of the child are in the same context that the parent.
Does it mean that there can be collisions and namespaces should be used in plugins ?
It seems to show that the code of a plugin, wich was designed to be stand-alone, can be reused… the developers which use the encryption of their sources are going to be happy :)[/quote]

Vosmont, that is not going to solve all your question but I had implemented something similar for the IPX plugin MiOS Apps and the IPhoneLocator MiOS Apps

regarding the function calls , I try to only call UPNP action even on child devices using luup actions api.

regarding the startup , the IPhoneLocator creates child and indeed the startup managed the initialization of child on behalf of child… see the source code of the .lua startup file

[quote=“vosmont, post:1, topic:189244”]The question comes from this subject:
http://forum.mysensors.org/topic/2160/my-mysensors-rgbw-plug-in-has-an-init-problem[/quote]
I tried to help out with that question on that board, but I’m glad to see you’ve been consulted!

For the RGB LED Strip, it reuses a stand-alone plugin by declaring as its child : the RGB Controller plugin.
Let's be quite clear about this. I [i]think[/i] it reuses the device type and service file, this is [b]not[/b] the same as actually accessing the plugin code.
This plugin has handleChildren=1, so it's its implementation file that handles all the actions of its child.
Yes, that [b]would[/b] be true, but the (Arduino) plugin doesn't have code to handle some of the actions.
For simple devices, as temperature sensors, it's just an update of their variables. For the RGB Controller, it's more complicated.
My impression was that it uses the plugin to group RGBW devices, rather than having four separate simple dimmers (as, say, Fibaro does.)
I've not tested it by myself, thus I am only supposing the behavior. It seems that the parent (Arduino plugin) is able to call functions present in the file declared in the implementation file of the child (the RGB Controller device).
This is where it gets hazy. I don't think so. The implementation file should not, I believe, be instantiated by luup.chdev.append, which makes the child device for the parent (Arduino) plugin.
Besides, the function for the startup declared in the child devices, seems to be called with the id of the parent.

1/ I do not understand the process of initialisation of the devices.
When is used the startup section of the plugin ? Just for the parent and not the childs ? Or called for all children ?


Plugin code entry point, defined in the implementation file, should never be called for a child device (I think.)

2/ Besides it seems that the functions of the child are in the same context that the parent. Does it mean that there can be collisions and namespaces should be used in plugins ? It seems to show that the code of a plugin, wich was designed to be stand-alone, can be reused... the developers which use the encryption of their sources are going to be happy :)

No, I don’t think so.

It’s not really clear what modifications BartE have done on the MySensors plugin.

I even copied all action implementations (with dummy debug log) from the I_RGBController1.xml to I_Arduino1.xml so the "no implementation errors" where all gone.

He seems to have just modified the implementation file to add the actions (and some code in the specific file for the Rgb Controller plugin).
Normally the code bound to these actions uses functions in an external file declared in the implementation file (of the RGB Controller).
So if this code is the same, it means that the implementation file of the child is used by the master.

It is this point which I find surprising.

I think I will have to check by myself.

[quote=“vosmont, post:4, topic:189244”]It is this point which I find surprising.

I think I will have to check by myself.[/quote]

Do please report your findings!

To me, I struggle with understanding the meaning of a ‘child device’ if it has its own independent existence. But maybe I have this very wrong.

What a strange animal Vera is!!

The results are surprising.

I’ve created a dummy plugin to test parent-child relationship (1 parent with handleChildren and 2 childs with specific implementation file).

The startup sequence :

09	10/18/15 17:45:40.193	JobHandler_LuaUPnP::Run device 274 Test Child 1 room 0 type urn:schemas-vosmont-github-io:device:TestChildChild:1 cat 0:-1 id  parent 273/0xf8aec0 upnp: 0 plugin:0 pnp:0 mac: ip:
09	10/18/15 17:45:40.194	JobHandler_LuaUPnP::Run device 275 Test Child 2 room 0 type urn:schemas-vosmont-github-io:device:TestChildChild:1 cat 0:-1 id  parent 273/0xf8c8f0 upnp: 0 plugin:0 pnp:0 mac: ip:
09	10/18/15 17:45:40.194	JobHandler_LuaUPnP::Run device 273 Test Master room 0 type urn:schemas-vosmont-github-io:device:TestChildMaster:1 cat 0:-1 id  parent 0/0xf8aaf8 upnp: 0 plugin:0 pnp:0 mac: ip:
50	10/18/15 17:45:47.362	luup_log:273: TestChild_Master#273 - startup
50	10/18/15 17:45:47.363	luup_log:273: TestChild_Master#273 - myLocalDeviceId:MasterId
50	10/18/15 17:45:47.363	luup_log:273: TestChild_Master#273 - globalVar:Child
50	10/18/15 17:45:47.364	luup_log:273: TestChild_Master#273 - localVar:Master
50	10/18/15 17:45:47.365	luup_log:273: TestChild_Master#273 - localChildVar:nil
50	10/18/15 17:45:47.366	luup_log:273: TestChild_Child#273 - startup
50	10/18/15 17:45:47.367	luup_log:273: TestChild_Child#273 - myLocalDeviceId:ChildId
50	10/18/15 17:45:47.377	luup_log:273: TestChild_Child#273 - globalVar:Child
50	10/18/15 17:45:47.378	luup_log:273: TestChild_Child#273 - localVar:Child
50	10/18/15 17:45:47.379	luup_log:273: TestChild_Child#273 - localChildVar:DeclaredJustInChild

→ the startup function declared in childs is called just one time with the id of the parent (and seems to be launched before the startup function of the parent).
→ local variables are really local: parent doesn’t see local variables of its childs.
→ global variables are shared between parent and childs (and child variable initialisation seems to be the last)

EDIT: the order of initialisation between parent and child is random.

EDIT: startup functions of parent and child HAVE to have different names (to avoid collision because they are global)

Call action :

08	10/18/15 17:50:21.181	JobHandler_LuaUPnP::HandleActionRequest device: 275 service: urn:upnp-vosmont-github-io:serviceId:TestChildChild1 action: SetStatus
08	10/18/15 17:50:21.182	JobHandler_LuaUPnP::HandleActionRequest argument serviceId=urn:upnp-vosmont-github-io:serviceId:TestChildChild1
50	10/18/15 17:50:21.186	luup_log:273: TestChild_Child#275 - set status '1'
50	10/18/15 17:50:21.187	luup_log:273: TestChild_Child#275 - myLocalDeviceId:273
50	10/18/15 17:50:21.187	luup_log:273: TestChild_Child#275 - globalVar:Child
50	10/18/15 17:50:21.190	luup_log:273: TestChild_Child#275 - localVar:Child
50	10/18/15 17:50:21.190	luup_log:273: TestChild_Child#275 - localChildVar:DeclaredJustInChild
06	10/18/15 17:50:21.191	Device_Variable::m_szValue_set device: 275 service: urn:upnp-vosmont-github-io:serviceId:TestChildChild1 variable: Status was: EMPTY now: 1 #hooks: 0 upnp: 0 skip: 0 v:0x11ea880/NONE duplicate:0

→ The action implementation called is the function of the child (with the id of the child)

EDIT:
I’ve done the same tests with actions which return values : the behavior is the same.

Some additional tests:

If the action is not present in the parent implementation file :

ERROR: No implementation

→ The action has to be present in the implementation file of the parent (but its code is not used)

If the action is not present in the child implementation file :

08	10/18/15 17:58:25.262	JobHandler_LuaUPnP::HandleActionRequest device: 275 service: urn:upnp-vosmont-github-io:serviceId:TestChildChild1 action: SetStatus
08	10/18/15 17:58:25.262	JobHandler_LuaUPnP::HandleActionRequest argument serviceId=urn:upnp-vosmont-github-io:serviceId:TestChildChild1
02	10/18/15 17:58:25.265	JobHandler_LuaUPnP::RunAction device 275 action urn:upnp-vosmont-github-io:serviceId:TestChildChild1/SetStatus failed with 501/No implementation
08	10/18/15 18:09:59.746	JobHandler_LuaUPnP::HandleActionRequest device: 275 service: urn:upnp-vosmont-github-io:serviceId:TestChildChild1 action: SetStatus
08	10/18/15 18:09:59.748	JobHandler_LuaUPnP::HandleActionRequest argument serviceId=urn:upnp-vosmont-github-io:serviceId:TestChildChild1 <0x709eb520>
50	10/18/15 18:09:59.750	luup_log:273: TestChild_Master#275 - set status '3' <0x772d9320>
50	10/18/15 18:09:59.751	luup_log:273: TestChild_Master#275 - myLocalDeviceId:273 <0x772d9320>
50	10/18/15 18:09:59.751	luup_log:273: TestChild_Master#275 - globalVar:Child <0x772d9320>
50	10/18/15 18:09:59.752	luup_log:273: TestChild_Master#275 - localVar:Master <0x772d9320>
50	10/18/15 18:09:59.752	luup_log:273: TestChild_Master#275 - localChildVar:nil <0x772d9320>
01	10/18/15 18:09:59.753	LuaInterface::CallFunction_Job device 275 function STestChildChild1_TestChildChild1_SetStatus_job failed [string "..."]:22: attempt to index global 'TestChild' (a nil value)

→ If the action is not present in the implementation file of the child, the linked function in the implementation file of the parent is used (with the id of the child, but local variables of the child are not reachable, like module declaration for example)

So… BartE is right :slight_smile: and I now understand the remark “with dummy debug log”

[quote=“vosmont, post:1, topic:189244”]Besides it seems that the functions of the child are in the same context that the parent.
Does it mean that there can be collisions and namespaces should be used in plugins ?
It seems to show that the code of a plugin, wich was designed to be stand-alone, can be reused… the developers which use the encryption of their sources are going to be happy :)[/quote]

They are actually using the same global context, so namespaces have to be used.
But local variables ar not exposed, so no problem with encrypted sources (besides I confused module and file of functions).

You’re not joking. Surprising and previously undocumented, I believe. Great piece of work!

I wouldn’t rely on much for this for an actual plugin implementation myself, though. Safest thing is definitely for parent to handle all of the child actions.

Unfortunately, I do not reproduce this behavior with the plugin MySensors and a module created by the plugin RGBController and linked as a child of the Arduino module.

By calling the actions of the child, it is the code of the implementation file of the parent that is used.
There must be some hidden parameters that I have not yet discovered.

Hi,

For my several of my plug ins I have the child actions in the implementation file of the child as they have a different service ID, but all code for functions and start-up is in the parent implementation file. The code for all actions is actually in a LUA file included in the parent implementation file only. Not sure if that makes any difference. It may for the scope of variables.

Cheers Rene

@reneboer

Thanks. I’m now a bit lost.
Are you sure that your device files for your childs (“D_xxx.xml”) declare an implementation file (“I_xxx.xml”) ?

		<implementationList>
			<implementationFile>I_TestChild_Child1.xml</implementationFile>
		</implementationList>

Generally, plugins with childs use the child as an empty shell without code inside (so no implementation file for the childs).

Hi Vosmont,

Indeed. I have a separate device file as the deviceType is different than that of the parent device. That points to the child JSON, service and implementation files.

The implementation file only defines the actions that calls functions from the parent. The is empty indeed.

I struggled a lot when I had the child actions in the implementation file of the parent, so this is what I ended up with.

Cheers Rene

But the implementation file of the parent doesn’t have handleChildren=1 ?
Otherwise, you should have the error “No implementation” when trying to call an action of a child.

Besides, your functions reachable from the childs are global ?

Hi, yes I do have handleChildren=1 in the parent implementation file.

In the LUA file all functions that are called from either the parent or child implementation file are declared without ‘local’ prefix.

Cheers Rene

I’ve tested that and it seems that handleChildren=1 in the implementation file of the parent is not taken into account.
So you have parent and children which share their resources and are independant.

Hi i finally had some time to look at your new version. it works a lot better now. The RGB plugin now starts and generates the correct calls.

There is one blocking issue left, for some unknown reason the master plugin (in this case the Arduino plugin) is initialized twice which gives an serial port conflict and thus blocks communication.

I did try to build in a check mechanism if (p == nil) then end but no effect.