Aller au contenu

Les Childs pour les Nuls


Bloug

Messages recommandés

 

 

 

 

 

Title.thumb.png.cde1e851318eb72d15f46dbf75aa3330.png

 

 

 

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  :D) 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.thumb.png.63f556402c11bc192ac81d0a33f50deb.png

 

1 -  Création du Child

Pour l’exemple nous allons créer un Child température ! 

 

2.thumb.png.2b1a3ca37f8748791c04bd805d407541.png

-------------------------------
-- 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

 

3.png.70c771131605190c270713c85b9c7722.png

-------------------------------
-- 2 - Définition des classes
-------------------------------

class 'NOM_Temps'      (QuickAppChild) -- Class NOM_Temps pour "com.fibaro.temperatureSensor"

 

 

3 -  Constructeur

 

5.png.bb69039128fde28c54f1a7738b605ce2.png

-------------------------------
-- 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 

 

6.png.a58b99f815ff02551cc209eb7fcf61af.png

 

--------------------------------
-- 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

7.thumb.png.1b87709406736d3a912ff8c2df738a2e.png

 

 

-------------------------------------
-- 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

 

 

8.png.00b3ce39b23c7a1ec2417e3de9496d1b.png

--------------------------------
-- 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 :P

 

 

10.png.4e1a7c0b0ad0955a615a5590cccdc4b9.png

 

 

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

 

 

 

11.png.b5ce4374475afb0d524841136a9ca46c.png

 

fin.thumb.JPG.d9f2dfc42bdc07ed3ceddb082445d40f.JPG

 

 

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é par Bloug
  • Like 3
  • Thanks 2
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
  • Like 3
Lien vers le commentaire
Partager sur d’autres sites

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é par Bloug
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
Lien vers le commentaire
Partager sur d’autres sites

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')  :60:

 

Modifié par Bloug
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
Lien vers le commentaire
Partager sur d’autres sites

 

Citation

  for uid,Nom in pairs(children) do
  if type(children[Nom])=='string' then -- Uninitialized child
    self:createChildTmps(uid,Nom)       -- ...create child
  end
end

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é par Bloug
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
Lien vers le commentaire
Partager sur d’autres sites

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

 

  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
Lien vers le commentaire
Partager sur d’autres sites

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é par jang
  • Like 4
Lien vers le commentaire
Partager sur d’autres sites

×
×
  • Créer...