Bloug Posté(e) le 27 janvier 2023 Signaler Posté(e) le 27 janvier 2023 (modifié) Ayant eu pas mal de pb pour la création de childs devices et leurs mises à jour ! Je poste ici une méthode (ma) pour leurs créations. Certes c’est loin d’être la meilleure…. Les Chuck Norris du lua y arrivent avec seulement deux lignes de codes …. Bref … c’est pas la meilleure méthode ! mais elle fonctionne ! Je n’ai pas la prétention d’expliquer le comment, le pourquoi ( c’est le travail de @lazer ) mais simplement d’indiquer ma méthode de débutant et je l’espère vous permettre d’avoir un exemple simple… le manipuler et comprendre ! Bon ! Comme dans toutes grandes sectes qui se respectent, celle-ci pour « les Nuls » se déroule en six étapes ! Alors voici un petit schéma avec les 6 étapes que j’utilise pour faire mes Childs 1 - Création du Child Pour l’exemple nous allons créer un Child température ! ------------------------------- -- 1 - Création d'un Child ------------------------------- -- Child Température : function QuickApp:createChildTmps(Nom) local child = self:createChildDevice({name = Nom, type = "com.fibaro.temperatureSensor",}, NOM_Temps) child:setVariable("Nappe_Child_ID" , "Child_Temps") end 2 - Définition des classes ------------------------------- -- 2 - Définition des classes ------------------------------- class 'NOM_Temps' (QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" 3 - Constructeur ------------------------------- -- 3 - Constructeur ------------------------------- -- Constructeur __init pour la classe NOM_Temps function NOM_Temps:__init(device) QuickAppChild.__init(self, device) end Normalement arrivé ici votre code ressemble à cela : ------------------------------- -- 1 - Création d'un Child ------------------------------- -- Child Température : function QuickApp:createChildTmps(Nom) local child = self:createChildDevice({name = Nom, type = "com.fibaro.temperatureSensor",}, NOM_Temps) child:setVariable("Nappe_Child_ID" , "Child_Temp") end ------------------------------- -- 2 - Définition des classes ------------------------------- class 'NOM_Temps' (QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" ------------------------------- -- 3 - Constructeur ------------------------------- -- Constructeur __init pour la classe NOM_Temps function NOM_Temps:__init(device) QuickAppChild.__init(self, device) end 4 - Initialisation des Childs -------------------------------- -- 4 - Initialisation des Childs -------------------------------- self:initChildDevices({ ["com.fibaro.temperatureSensor"] = NOM_Temps -- Température }) local i = 0 for id,device in pairs(self.childDevices) do i=i+1 self:debug("[", id, "]", device.name, ", type of: ", device.type) end if i == 0 then local Nom = "Température" self:createChildTmps(Nom) end 5 - Identification des Childs ------------------------------------- -- 5 - Identification des Childs ------------------------------------- for _, childDevice in pairs(self.childDevices) do if childDevice:getVariable("Nappe_Child_ID") == "Child_Temps" then ID_Child_1 = childDevice.id end end self:Mise_a_jour_des_Childs() end ------------------------- Fin du OnInit 6 - Mises à jour des variables -------------------------------- -- 6 - Mises à jours des Childs -------------------------------- -- Childs ID_Child_1 function QuickApp:Mise_a_jour_des_Childs() variable_qui_donne_la_temperature = 37 --- pour l'ex du tuto variable_pour_le_log = " I'm bad " --- pour l'ex du tuto self.childDevices[ID_Child_1]:updateProperty("value", variable_qui_donne_la_temperature ) self.childDevices[ID_Child_1]:updateProperty("log", variable_pour_le_log) end C’est peut être pas une bonne habitude !? A Confirmer au prochain Crash Voici : Le fichier svg plus facile à lire que sur le forum : Les Childs pour les nuls.svg Le fichier lua à coller dans un QA générique : Child_Temps.lua Et comme nous "les nuls " nous savons que le tuto machin truc qui explique ne parle jamais du child que l'on souhaite faire ! voici un fichier lua avec un multiChild ! : A coller dans un QA générique : Les_Childs_pour_les_Nuls.lua ou le QA à importer : Les_Childs_pour_les_Nuls.fqa PS : J'espère sincèrement ne pas avoir avoir raconté trop de bêtises ! ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Autres méthodes J'ajoute ici le liens direct d'autres méthodes plus complexes abordées ici : Contribution de Jang : ICI Création de Child qui sont définis dans la table (Ex de 6 Childs) Elle supprime les Childs qui ne sont pas dans la table, si vous modifiez le nombre d'enfants. Chaque Child dispose d'un identifiant unique qui est utilisé pour appeler des méthodes sur les childs ------------------------------------------------------------------------------------------------------------------------------ Modifié le 28 janvier 2023 par Bloug 3 2
jang Posté(e) le 27 janvier 2023 Signaler Posté(e) le 27 janvier 2023 (modifié) Could also simplify like this. This assumes that child name is unique. You can index on some quickAppVariable too. local children = {} ------------------------------- -- 1 - Création d'un Child ------------------------------- -- Child Température : function QuickApp:createChildTmps(Nom) local child = self:createChildDevice({name = Nom, type = "com.fibaro.temperatureSensor",}, NOM_Temps) end ------------------------------- -- 2 - Définition des classes ------------------------------- class 'NOM_Temps'(QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" ------------------------------- -- 3 - Constructeur ------------------------------- -- Constructeur __init pour la classe NOM_Temps function NOM_Temps:__init(device) QuickAppChild.__init(self, device) children[self.name]=self -- Keep table with all children indexed by name. Assumes name unique. end -------------------------------- -- 4 - Initialisation des Childs -------------------------------- local Nom = "Température" function QuickApp:onInit() self:initChildDevices({ ["com.fibaro.temperatureSensor"] = NOM_Temps -- Température }) if not children[Nom] then self:createChildTmps(Nom) end self:Mise_a_jour_des_Childs() end function QuickApp:Mise_a_jour_des_Childs() local variable_qui_donne_la_temperature = 37 --- pour l'ex du tuto local variable_pour_le_log = " I'm bad " --- pour l'ex du tuto children[Nom]:updateProperty("value", variable_qui_donne_la_temperature) children[Nom]:updateProperty("log", variable_pour_le_log) end Modifié le 28 janvier 2023 par jang 3
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 (modifié) Thank you very much @jang for your addition ! My example for 1 Child itself comes from my file indicated below for the 6 Childs ( " who can do more, can do less " => dummies power !! ) Can you help me, with your example, I have the following error: main.lua:33: attempt to index a nil value (global 'children') if not children[Name] then by ? if children == nil then Thx Modifié le 28 janvier 2023 par Bloug
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 Sorry, local children = {} in the beginning of the code didn't come along when I copied the code. I fixed it in the previous post.
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 without children = {} its still works if if I replace by if children == nil then at L33 . the Child or Children tables are they created automatically ?
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 (modifié) If you have 6 predefined children with unique names local children ------------------------------- -- 1 - Création d'un Child ------------------------------- -- Child Température : function QuickApp:createChildTmps(Nom) local child = self:createChildDevice({name = Nom, type = "com.fibaro.temperatureSensor",}, NOM_Temps) end ------------------------------- -- 2 - Définition des classes ------------------------------- class 'NOM_Temps'(QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" ------------------------------- -- 3 - Constructeur ------------------------------- -- Constructeur __init pour la classe NOM_Temps function NOM_Temps:__init(device) QuickAppChild.__init(self, device) children[self.name]=self -- Keep table with all children indexed by name. Assumes name unique. end -------------------------------- -- 4 - Initialisation des Childs -------------------------------- children = { ["Température1"] = false, ["Température2"] = false, ["Température3"] = false, ["Température4"] = false, ["Température5"] = false, ["Température6"] = false, } function QuickApp:onInit() self:initChildDevices({ ["com.fibaro.temperatureSensor"] = NOM_Temps -- Température }) for Nom,c in pairs(children) do if c==false then self:createChildTmps(Nom) end end self:Mise_a_jour_des_Childs("Température5") end function QuickApp:Mise_a_jour_des_Childs(Nom) local variable_qui_donne_la_temperature = 37 --- pour l'ex du tuto local variable_pour_le_log = " I'm bad " --- pour l'ex du tuto children[Nom]:updateProperty("value", variable_qui_donne_la_temperature) children[Nom]:updateProperty("log", variable_pour_le_log) end Modifié le 28 janvier 2023 par jang
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 (modifié) 10 minutes ago, Blog said: without children = {} its still works if if I replace by if children == nil then at L33 . the Child or Children tables are they created automatically? It should not work. children={} is a table you define where you keep a map <name> -> <child>. The "builtin" table, self.childDevices keep a map <deviceID> -> <child>, which is not as useful when working with the children. However, deviceID is always unique so that is the reason why they have that mapping. If we know that the names are unique it is more helpful to have a name to child mapping, like in the example. Otherwise we can also give our children a unique id that we store in a quickAppVariable, like in your example, and index on that. Modifié le 28 janvier 2023 par jang
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 (modifié) il y a 9 minutes, jang a dit : It should not work. you are right ! The child is created (physically) but it generates the error: main.lua:20: attempt to index a nil value (global 'children') Modifié le 28 janvier 2023 par Bloug
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 (modifié) The problem with using the name as the unique key is that you may want the children to have the same name - or the user can change the name in the Web UI of your child... So, instead you can store the unique id in a quickAppVariable, similar to in your own example, and then create a table mapping these unique ids to the child objects. It becomes a little bit more complex. local children local childID = 'Nappe_Child_ID' ------------------------------- -- 1 - Création d'un Child ------------------------------- -- Child Température : function QuickApp:createChildTmps(ID,Nom) local child = self:createChildDevice({ name = Nom, type = "com.fibaro.temperatureSensor", initialProperties = { quickAppVariables = {{name=childID,value=ID}}}, }, NOM_Temps) end ------------------------------- -- 2 - Définition des classes ------------------------------- class 'NOM_Temps'(QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" ------------------------------- -- 3 - Constructeur ------------------------------- -- Constructeur __init pour la classe NOM_Temps function NOM_Temps:__init(device) QuickAppChild.__init(self, device) children[self:getVariable(childID)]=self -- Keep table with all children indexed by name. Assumes name unique. end -------------------------------- -- 4 - Initialisation des Childs -------------------------------- children = { -- Unique ID -> Name ["Child_Temps1"] = "Température1", ["Child_Temps2"] = "Température2", ["Child_Temps3"] = "Température3", ["Child_Temps4"] = "Température4", ["Child_Temps5"] = "Température5", ["Child_Temps6"] = "Température6", } function QuickApp:onInit() self:initChildDevices({ ["com.fibaro.temperatureSensor"] = NOM_Temps -- Température }) for uid,Nom in pairs(children) do if type(Nom)=='string' then -- Uninitialized child self:createChildTmps(uid,Nom) -- ...create child end end self:Mise_a_jour_des_Childs("Child_Temps5") end function QuickApp:Mise_a_jour_des_Childs(Nom) local variable_qui_donne_la_temperature = 37 --- pour l'ex du tuto local variable_pour_le_log = " I'm bad " --- pour l'ex du tuto children[Nom]:updateProperty("value", variable_qui_donne_la_temperature) children[Nom]:updateProperty("log", variable_pour_le_log) end . Modifié le 28 janvier 2023 par jang
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 (modifié) Citation for uid,Nom in pairs(children) do if type(children[Nom])=='string' then -- Uninitialized child self:createChildTmps(uid,Nom) -- ...create child endend sorry maybe I corrected it wrong by testing your code. I have the following error: main.lua:59: attempt to call a nil value (method 'updateProperty') Modifié le 28 janvier 2023 par Bloug
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 No problem, just fixed it myself.
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 (modifié) I made a change in the original code if type ( Name )== 'string' instead of the wrong code type(children[Name])=='string' Did you change that? Otherwise you will create the children every time you restart. Modifié le 28 janvier 2023 par jang
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 You could also add code to automatically delete children that you don't use/need (e.g. children not in the children table)
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 I think I have to restart my hc3 because it is still looping lol
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 So, there was another bug in creating the childDevice. The initialProperties should be quickAppVariables = ... If you copy the last post in full it should work.
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 This version will remove children that are not in the children table. It can be useful if you change the number of children (reduce them), or the code creates children infinitely like the last version... ;-) local childrenToDelete,children = {} local childID = 'Nappe_Child_ID' ------------------------------- -- 1 - Création d'un Child ------------------------------- -- Child Température : function QuickApp:createChildTmps(ID,Nom) local child = self:createChildDevice({ name = Nom, type = "com.fibaro.temperatureSensor", initialProperties = {quickAppVariables = {{name=childID,value=ID}}}, }, NOM_Temps) end ------------------------------- -- 2 - Définition des classes ------------------------------- class 'NOM_Temps'(QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" ------------------------------- -- 3 - Constructeur ------------------------------- -- Constructeur __init pour la classe NOM_Temps function NOM_Temps:__init(device) QuickAppChild.__init(self, device) local uid = self:getVariable(childID) or "" if children[uid] then children[uid]=self -- Keep table with all children indexed by name. Assumes name unique. else childrenToDelete[#childrenToDelete+1]=self.id -- child to remove end end -------------------------------- -- 4 - Initialisation des Childs -------------------------------- children = { -- Unique ID -> Name ["Child_Temps1"] = "Température1", ["Child_Temps2"] = "Température2", ["Child_Temps3"] = "Température3", ["Child_Temps4"] = "Température4", ["Child_Temps5"] = "Température5", ["Child_Temps6"] = "Température6", } function QuickApp:onInit() self:initChildDevices({ ["com.fibaro.temperatureSensor"] = NOM_Temps -- Température }) for uid,Nom in pairs(children) do if type(Nom)=='string' then -- Uninitialized child self:createChildTmps(uid,Nom) -- ...create child end end for _,deviceId in ipairs(childrenToDelete) do self:removeChildDevice(deviceId) end self:Mise_a_jour_des_Childs("Child_Temps5") end function QuickApp:Mise_a_jour_des_Childs(Nom) local variable_qui_donne_la_temperature = 37 --- pour l'ex du tuto local variable_pour_le_log = " I'm bad " --- pour l'ex du tuto children[Nom]:updateProperty("value", variable_qui_donne_la_temperature) children[Nom]:updateProperty("log", variable_pour_le_log) end 1
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 (modifié) Yes ! I am therefore not the only one to have heated with your example! Thanks again for your time ! Modifié le 28 janvier 2023 par Bloug
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 (modifié) I think this became a good example, I will repost the code in the (main) Fibaro forum with credits to you. https://forum.fibaro.com/topic/49113-hc3-quickapps-coding-tips-and-tricks/?do=findComment&comment=260188 Modifié le 28 janvier 2023 par jang
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 It is above all YOUR job !
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 il y a 10 minutes, Bloug a dit : It is above all YOUR job! ...but you needed to reboot your HC3
Bloug Posté(e) le 28 janvier 2023 Auteur Signaler Posté(e) le 28 janvier 2023 @Lazer t'as toi aussi une méthode de Jedi bien spécifique avec ta librairie tools pour la création de QA ! si jamais t'as le temps pour qq lignes de code pour montrer comment tu appelles via ta librairie.
mprinfo Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 Dans sa librairie il y a un exempleEn plus il y a la possibilité d'ajouter des interface Envoyé de mon BLA-L29 en utilisant Tapatalk
jang Posté(e) le 28 janvier 2023 Signaler Posté(e) le 28 janvier 2023 (modifié) So, if we refine the code and create a library of it do local childID = 'ChildID' local classID = 'ClassName' local defChildren children = {} local undefinedChildren = {} local createChild = QuickApp.createChildDevice class 'QwikAppChild'(QuickAppChild) function QwikAppChild:__init(device) QuickAppChild.__init(self, device) local uid = self:getVariable(childID) or "" if defChildren[uid] then children[uid]=self -- Keep table with all children indexed by uid. uid is unique. else -- If uid not in our children table, we will remove this child undefinedChildren[#undefinedChildren+1]=self.id end end function QuickApp:createChildDevice(uid,props,interfaces,className) __assert_type(uid,'string') __assert_type(className,'string') props.initialProperties = props.initialProperties or {} local qas = {{name=childID,value=uid},{name=classID,value=className}} props.initialProperties.quickAppVariables = qas props.initialInterfaces = interfaces return createChild(self,props,_G[className]) end local function getVar(child,varName) for _,v in ipairs(child.properties.quickAppVariables or {}) do if v.name==varName then return v.value end end return "" end function QuickApp:loadExistingChildren(chs) __assert_type(chs,'table') defChildren = chs self.children = children function self.initChildDevices() end local cdevs,n = api.get("/devices?parentId="..self.id) or {},0 -- Pick up all my children for _,child in ipairs(cdevs) do local uid = getVar(child,childID) local className = getVar(child,classID) local childObject = _G[className] and _G[className](child) or QuickAppChild(child) self.childDevices[child.id]=childObject childObject.parent = self end end function QuickApp:createMissingChildren() for uid,data in pairs(defChildren) do if not self.children[uid] then local props = { name = data.name, type = data.type, } self:createChildDevice(uid,props,data.interfaces,data.className) end end end function QuickApp:removeUndefinedChildren() for _,deviceId in ipairs(undefinedChildren) do -- Remove children not in children table self:removeChildDevice(deviceId) end end end do local childID = 'ChildID' local classID = 'ClassName' local defChildren children = {} local undefinedChildren = {} local createChild = QuickApp.createChildDevice class 'QwikAppChild'(QuickAppChild) function QwikAppChild:__init(device) QuickAppChild.__init(self, device) local uid = self:getVariable(childID) or "" if defChildren[uid] then children[uid]=self -- Keep table with all children indexed by uid. uid is unique. else -- If uid not in our children table, we will remove this child undefinedChildren[#undefinedChildren+1]=self.id end end function QuickApp:createChildDevice(uid,props,interfaces,className) __assert_type(uid,'string') __assert_type(className,'string') props.initialProperties = props.initialProperties or {} local qas = {{name=childID,value=uid},{name=clsID,value=className}} props.initialProperties.quickAppVariables = qas props.initialInterfaces = interfaces return createChild(self,props,_G[className]) end local function getVar(child,varName) for _,v in ipairs(child.properties.quickAppVariables or {}) do if v.name==varName then return v.value end end return "" end function QuickApp:loadExistingChildren(chs) __assert_type(chs,'table') defChildren = chs self.children = children function self.initChildDevices() end local cdevs,n = api.get("/devices?parentId="..self.id) or {},0 -- Pick up all my children for _,child in ipairs(cdevs) do local uid = getVar(child,childID) local className = getVar(child,classID) local childObject = _G[className] and _G[className](child) or QuickAppChild(child) self.childDevices[child.id]=childObject childObject.parent = self end end function QuickApp:createMissingChildren() for uid,data in pairs(defChildren) do if not self.children[uid] then local props = { name = data.name, type = data.type, } self:createChildDevice(uid,props,data.interfaces,data.className) end end end function QuickApp:removeUndefinedChildren() for _,deviceId in ipairs(undefinedChildren) do -- Remove children not in children table self:removeChildDevice(deviceId) end end end then we can use it like this ------------------------------- -- 1 - Definition of class ------------------------------- class 'Class_Temp'(QwikAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor" ------------------------------- -- 2 - Class constructor ------------------------------- function Class_Temp:__init(device) QwikAppChild.__init(self, device) end -------------------------------- -- 3 - Definition of children -------------------------------- local myChildren = { -- Unique ID (uid) -> child initialization data, in our case the name ["Child_Temps1"] = { name="Température1", type="com.fibaro.temperatureSensor", className='Class_Temp', interfaces = {'battery'}, }, ["Child_Temps2"] = { name="Température2", type="com.fibaro.temperatureSensor", className='Class_Temp', interfaces = {'battery'}, }, ["Child_Temps3"] = { name="Température3", type="com.fibaro.temperatureSensor", className='Class_Temp', interfaces = {'battery'}, }, ["Child_Temps4"] = { name="Température4", type="com.fibaro.temperatureSensor", className='Class_Temp', interfaces = {'battery'}, }, ["Child_Temps5"] = { name="Température5", type="com.fibaro.temperatureSensor", className='Class_Temp', interfaces = {'battery'}, }, ["Child_Temps6"] = { name="Température6", type="com.fibaro.temperatureSensor", className='Class_Temp', interfaces = {'battery'}, }, } -------------------------------- -- 4 - Initialization of children -------------------------------- function QuickApp:onInit() self:loadExistingChildren(myChildren) self:createMissingChildren() self:removeUndefinedChildren() self:update_child("Child_Temps5") -- example, update child with uid 'Child_Temps5' -- for uid,_ in pairs(self.children) do -- update all children -- self:update_child(uid) -- end end -------------------------------- -- 5 - Accessing children -------------------------------- function QuickApp:update_child(uid) local default_temp = 37 --- pour l'ex du tuto local default_log = " I'm bad " --- pour l'ex du tuto self.children[uid]:updateProperty("value", default_temp) self.children[uid]:updateProperty("log", default_log) end Modifié le 29 janvier 2023 par jang 4
Messages recommandés