Aller au contenu
Fredmas

Questions de débutant en Quick Apps sur HC3

Recommended Posts

Merci à tous pour les réponses !

Qui m'ont fait bien plaisir...

 

il y a une heure, Fredmas a dit :

ce topic est plus à considérer comme un café philo du débutant passionné

C'est bien comme cela que je le voyais - je suis aussi du genre à créer par moi-même, pas de clé-en-main !

 

Il y a 1 heure, Fredmas a dit :

J'aurais pu tout faire dans le même facilement, mais pour l'instant je préfère séparer pour ne pas tout craquer en cas de crash du QA.

D'accord aussi sur cela. De petites structures sont bien plus faciles à maintenir qu'une grosse (usine à gaz !).

A propos je n'ai pas compté (il faudra que je le fasse à l'occasion), mais je dois avois installé une cinquantaine de modules divers...

 

Et c'est certain que ca va fumer !!! Mais quoi de plus plaisant ?

 

Très joyeux Noël à tous !

Partager ce message


Lien à poster
Partager sur d’autres sites
il y a 10 minutes, Sowliny a dit :

Et c'est certain que ca va fumer !!! Mais quoi de plus plaisant ?

 

Très joyeux Noël à tous !

Parfaitement d'accord :2:

Joyeux Noël à toi également !

  • Like 1

Partager ce message


Lien à poster
Partager sur d’autres sites

Bienvenue Sowliny dans le club des débutants chevronnés ! :)

 

tout comme Fredmas, je n'ai plus une seule variable globale dans le panneau ad'hoc et c'est ma plus grande "victoire" :)

 

et joyeux Noel à tous !

 

Stef

 

Modifié par couillerot
  • Like 3

Partager ce message


Lien à poster
Partager sur d’autres sites

Merci Couillerot,

 

Hé ouiii... J'en suis à environ 150 VG ! (ce n'est pas bien sûr un critère de gloire :mellow:)

Avec une quarantaine de scène...

Mais tout cela est un héritage direct et adapté de ma HC2. Ce qui veut dire que je n'exploite pas du tout encore les possibilités intrinsèques de la HC3.

(ouf... j'ai trouvé une excuse !).

 

Comme tout tourne bien maintenant (comme je l'ai déjà dit, ma HC3 est passée directement en prod - et je suis conscient que ce n'est pas la meilleure chose que j'aie faite :wacko:) je vais pouvoir expérimenter les "nouvelles technologies" :74:.

 

Et je repenserai à cette discussion quand j'aurai moi aussi apuré toutes (?) mes VG.

Partager ce message


Lien à poster
Partager sur d’autres sites

salut @Fredmas,

merci pour ce sujet très détaillé.

Comme il m'est impossible de parcourir tous les posts de ce sujet et que ma question TRES basique a surement déjà été posée, pourrais-tu me répéter la réponse SVP ?

 

Question :

Depuis la fonction B du QA A,

je souhaite appeler la fonction D du QA C, en lui passant un paramètre.

 

J'ai essayé ceci, et évidemment ça ne fonctionne pas :

dans le QA A
function QuickApp:B()
	...
	C:D("test")
	...
end

dans le QA C
function QuickApp:D(param)
	...
end

merci pour la future réponse que je suspecte être facile

Partager ce message


Lien à poster
Partager sur d’autres sites

tout est dans hub.call() (comme d'hab) :13:

(merci pour le lien et l'indication du chapitre :74:)

Partager ce message


Lien à poster
Partager sur d’autres sites

Hello everybody, 

 

Je poste ce petit message, car je vais enfin entammer ma migration HC2->HC3 (depuis presque un an que j'ai mon HC3), car cela représente un travail monstre (bcp de LUA sur mon HC2) !

Ne m'en voulez pas, je débute avec les QA :-) 

 

Mon premier cas, je souhaite faire un QA pour faire clignoter un voyant lumineux.

J'ai donc fait ce QA avec deux boutons ON / OFF que je pourrais activer via d'autres scenes ou QA.

 

ça marche presque ! j'arrive bien à passer du OFF au ON, mais pas l'inverse. 

Quand je suis dans ma boucle while, je press OFF, et rien ne se passe. Ma variable ne passe pas à OFF, et donc la boucle ne s'arrête pas ! 

 

Pouvez vous me guider ? Merci bien

-- TEST QA

function QuickApp:onInit()
    self:debug("onInit")
end

function QuickApp:Cligno_ON()
    self:setVariable("ClignoRouge", "ON")
    self.cligno = self:getVariable("ClignoRouge") 
    self:trace("var cligno = "..cligno)
    self:loop()
    self:trace("Mise en marche du cligno via le bouton")
end

function QuickApp:Cligno_OFF()
    self:setVariable("ClignoRouge", "OFF")
    self.cligno = self:getVariable("ClignoRouge") 
    self:trace("var cligno = "..cligno)
    self:loop()
    self:trace("Mise en arret du cligno via le bouton")
end

----------------------------------------------------------
--- Boucle loop
----------------------------------------------------------
function QuickApp:loop()
self.cligno = self:getVariable("ClignoRouge")
self:trace("var cligno = "..cligno)
    while self.cligno == "ON" do
        hub.sleep(1000) 
        hub.call(79, 'turnOn')
        self:updateView("label1", "text", "ON")

        hub.sleep(1000)
        hub.call(79, 'turnOff')
        self:updateView("label1", "text", "OFF")

        self.cligno = self:getVariable("ClignoRouge")
        self:trace("var cligno = "..cligno)
    end
end

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Your while loop will not give any time for button callbacks to call your Lua functions or update UI

i.e. function QuickApp:Cligno_ON() and function QuickApp:Cligno_OFF()

 

You need to use something like setTimeout to give time to your button handlers...

 

 

Partager ce message


Lien à poster
Partager sur d’autres sites
Il y a 14 heures, jang a dit :

Your while loop will not give any time for button callbacks to call your Lua functions or update UI

i.e. function QuickApp:Cligno_ON() and function QuickApp:Cligno_OFF()

 

You need to use something like setTimeout to give time to your button handlers...

 

 

Hello jang, 

 

I've tried with setTimeout function in below code. I get the blinking ok, but I don't understand how should I do to stop it ? 

It seems I have the same problem as before and can't stop it.

 

Thanks, 

function QuickApp:loop(timer)
        self:trace("loop")
        hub.sleep(1000) 
        hub.call(79, 'turnOn')
        hub.sleep(1000) 
        hub.call(79, 'turnOff')

        fibaro.setTimeout(2000, function() 
            self:loop()
        end)
end

 

Partager ce message


Lien à poster
Partager sur d’autres sites
-- TEST QA

function QuickApp:onInit()
  self:debug("onInit")
end

local timer

function QuickApp:Cligno_ON()
  self:setVariable("ClignoRouge", "ON")
  self.cligno = self:getVariable("ClignoRouge") 
  self:trace("var cligno = "..cligno)
  if not timer then self:loop() end
  self:trace("Mise en marche du cligno via le bouton")
end

function QuickApp:Cligno_OFF()
  self:setVariable("ClignoRouge", "OFF")
  self.cligno = self:getVariable("ClignoRouge") 
  self:trace("var cligno = "..cligno)
  if timer then timer=fibaro.clearTimeout(timer) end
  self:trace("Mise en arret du cligno via le bouton")
end

----------------------------------------------------------
--- Boucle loop
----------------------------------------------------------
function QuickApp:loop()
  self:trace("loop")
  hub.sleep(1000) 
  hub.call(79, 'turnOn')
  hub.sleep(1000) 
  hub.call(79, 'turnOff')

  timer = fibaro.setTimeout(2000, function() 
      self:loop()
    end)
end

 

Modifié par jang

Partager ce message


Lien à poster
Partager sur d’autres sites

@mikael2235, juste pour ma "culture",

self.cligno

c'est la même chose que

local cligno

?

Partager ce message


Lien à poster
Partager sur d’autres sites

Alors à mon tour de poser une question de base su comment coder proprement en QuickApp: J'ai une fonction, qui travaille en asynchrone (socket TPC) et qui va lire un registre sur mon onduleur.

J'ai par ailleurs une fonction, à la logique synchrone, qui fait une boucle for et qui permet de lire l'ensemble des registres.

Ceci a pour effet de m'envoyer une rafale de commandes asynchrones dont chacune a sa fonction callback. Et ce que je voudrais, c'est qu'une fois le dernier callback asynchrone effectué, je puisse reprendre le cours de mon exécution synchrone, sachant que rien ne me dit que le dernier callback à terminer soit celui du dernier registre lu.

Donc en gros, on parle d'une situation où on n'est plus à gérer avec un unique callback mais une fonction où il y en a 10 qui tournent en parallèle.

Ca ressemble donc à un truc du style:

for _, register in pairs(register) do

        registerscan(registerNumber, register.callback)

end

self:debug("Scan terminé")

 

Et registerscan envoie un message via un TCP socket, recoit une réponse et la traite

et je voudrais que le self:debug ne se produise que quand chaque callback a fini de s'exécuter

A ce stade, le seul moyen que j'arrive à envisager pour ca est qu'à chaque appel à registerscan, j'incrémente un compteur (variable globale) et qu'à chaque fin de chaque callback, je décrémente ce compteur et que mon self.debug soit une boucle infinie, stoppé quand le compteur vaut 0. Mais je trouve ca mochissime et je veux croire qu'il existe une manière propre de faire que ce soit appelé via une utilisation intelligente de callbacks plutot que via une boucle infinie et une variable globale. Si vous avez une idée pour résoudre ce challenge, je suis preneur!

Partager ce message


Lien à poster
Partager sur d’autres sites

Ok, I think I got it for the join callback. However, I have a few remaining understanding questions:

- why do you use this "complicated" syntax :

for i=1,2*n,2 do
    local a=args[i+1]
    a[#a+1]=nsucc
    a[#a+1]=nerr
    args[i](table.unpack(a))
  end

and not this simple one:

for i=1,2*n,2 do 
    args[i](args[i+1],nsucc, nerr)
  end

I don't understand why you populate a table with values to then unpack the table because your function needs values and not a table.

 

then my second point is that your join callback function calls a predefined number of requests. It can be 3, 4, 5 or whatever http requests I want, but this number is fixed by the syntax (5 calls in your example). In my case, I have a loop and the number of calls it will generate will only be known at execution time, depending on how many registers are described in my registers table. Thus, at the time of writing code, I'm not in a position to know the correct number of arguments to pass to join. Is there a syntax trick to build the correct join call at execution time ? Something like building a string in my loop with the right syntax and then passing that string to something that will execute it?

 

Last, I'm not sure I understand correctly this part of the http request:

error = err or function(err) error(url,err) end

So please, correct me if I'm wrong: My understanding is that if err is provided as an argument in the call to SendRequest, then this function will be called in case of error while calling http:request. But if err is not provided in the list of arguments when calling SendRequest, a default function will be used and it will be the standard error function function of http:request but with the url parameter fixed, making it a one parameter function. So I understand that the second "err" of the line are just "blind" ((local?) variables = they could have been replaced by any name. So, this code would also have worked:

error = err or function(err1) error(url,err1) end

To say it differently, the first err has to be err and nothing else and refers to the last argument of SendRequest. the next 2 occurrences of err just refer to a local variable and it's just a coincidence that it bears the same name as the first occurrence of err. Am I correct?

 

Thanks again for your help, much appreciated!

 

 

Partager ce message


Lien à poster
Partager sur d’autres sites
Il y a 9 heures, vravolta a dit :

Ok, I think I got it for the join callback. However, I have a few remaining understanding questions:

- why do you use this "complicated" syntax:


 
    
  

and not this simple one:


  
  

I don't understand why you populate a table with values to then unpack the table because your function needs values and not a table.

 

It's just to cater for a variable number of arguments in the provided table. Now it's just a table with an single url so it is kind of an overkill (and then we tuck on the success and error handlers at the end). By allowing join to take a function with unknown number of arguments we keep it generic and let the sendRequest deal with the number of args.

Il y a 9 heures, vravolta a dit :

 

then my second point is that your join callback function calls a predefined number of requests. It can be 3, 4, 5 or whatever http requests I want, but this number is fixed by the syntax (5 calls in your example). In my case, I have a loop and the number of calls it will generate will only be known at execution time, depending on how many registers are described in my registers table. Thus, at the time of writing code, I'm not in a position to know the correct number of arguments to pass to join. Is there a syntax trick to build the correct join call at execution time? Something like building a string in my loop with the right syntax and then passing that string to something that will execute it?

Yes you need the count the number of calls and use that later to count down... because register is a key/value table you can't just use #register...
I'm not sure how your 'registerscan' is implemented but I assume that the callback is called at success.

Then I would add another callback for errors and implement it something like this

local function scallAll(register)
  local n,finish=0
  for _, register in pairs(register) do
    n=n+1
    local cb = register.callback
    registerscan(registerNumber, 
      function(res) cb(res) isFinished() end,          -- success callback
      function(err) print("Err:",err) isFinished() end -- error callback
    )                         
  end
  function isFinished() n=n-1 if n==0 then self:debug("Scan completed") end end
end

 

Il y a 9 heures, vravolta a dit :

 

Last, I'm not sure I correctly understand this part of the http request:


  

So please, correct me if I'm wrong: My understanding is that if err is provided as an argument in the call to SendRequest, then this function will be called in case of error while calling http:request. But if err is not provided in the list of arguments when calling SendRequest, a default function will be used and it will be the standard error function function of http:request but with the url parameter fixed, making it a one parameter function. So I understand that the second "err" of the line are just "blind" ((local?) variables = they could have been replaced by any name. So, this code would also have worked:


  

To say it differently, the first err has to be err and nothing else and refers to the last argument of SendRequest. the next 2 occurrences of err just refer to a local variable and it's just a coincidence that it bears the same name as the first occurrence of err. Am I correct?

 

Thanks again for your help, much appreciated!

Yes, it's just a reuse of the name 'err'. The second err in "function(err) ..." shadows the previous definition. 

What's bother me now is that the code is buggy as the call to the builtin error function can't take two string error messages.

The correct code would have been error(url..err)

Partager ce message


Lien à poster
Partager sur d’autres sites

Now that I could manage my issue with the join callback trrick, here comes another challenge:

 with the syntax for a,b in pairs(MyTable) do blabla end, I can perform a full scan of a table. But is there a way to stop the scan once I've found what I wanted in MyTable. In other words, is there a syntax to exit a for loop before the fullscan is terminated or is there a possibility to have a while loop on a table?

Partager ce message


Lien à poster
Partager sur d’autres sites

Hello, j'ai une question un peu naze... mais je ne trouve pas la solution

 

J'ai déclaré dans une QA plusieurs ID de devices

local ID_1 1234

local ID_2 4567

...

 

Je souaiterai appeler avec un for ces devices mais je n'arrive pas à faire évaluer une variable qui est une chaine de caractère et qui doit représenter l'ID d'un device...

J'ai essayé plusieurs chose, mais sans le statement adéquate "evaluate" ou autre qui permet dévaluer ID_1, je reste bloqué

for i=1,2 do
        print(i)
        local ID_device_string  = 'ID_'..i
        local ID_device_number  = evaluate(ID_device_string)
        print("Device : ",ID_device_string, " under analysis...",ID_device_number)

        value = hub.getValue(ID_device_number, "power")
        print("value_"..i.." :",value)

    end

Merci pour votre aide.

Modifié par TitiXsi

Partager ce message


Lien à poster
Partager sur d’autres sites

Tu ne peux pas manipuler les noms des variables, il faut travailler avec des tableaux ("table" en LUA)

 

Exemple de code, à tester :

 

local ids = {
	[1] = 1234,
	[2] = 4567,
}

for _, ID_device in ipairs(ids)
	print("Device under analysis :", ID_device)
	local value = hub.getValue(ID_device, "power")
	print("value_" .. ID_device .. " :", value)
end

 

Partager ce message


Lien à poster
Partager sur d’autres sites

C'est évidemment plus simple... la non évaluation des variables string c'est une spécificité LUA ou un bloquage de fibaro qui n'a pas porté la feature ?

Partager ce message


Lien à poster
Partager sur d’autres sites

Ce n'est ni lié à Fibaro, ni au LUA, mais au mode de fonctionnement des compilateurs de langage de programmation en général.
Tu connais un language de programmation où tu peux manipuler le nom d'une variable et en évaluer son contenu ?

En LUA, ce que tu peux manipuler, ce sont les noms (sous forme de string) des index des tableaux.

J'aurais pu t'écrire un bout de code en sens là d'ailleurs, mais c'était plus lourd que la solution très basique que je t'ai proposé.

 

D'ailleurs ta question n'a rien à voir avec les QuickApp directement, mais plutôt aux possibilités du langage LUA en général.

 

Modifié par Lazer

Partager ce message


Lien à poster
Partager sur d’autres sites

C'est évidemment plus simple... la non évaluation des variables string c'est une spécificité LUA ou un bloquage de fibaro qui n'a pas porté la feature ?

Partager ce message


Lien à poster
Partager sur d’autres sites
il y a 18 minutes, Lazer a dit :

Tu connais un language de programmation où tu peux manipuler le nom d'une variable et en évaluer son contenu ?

Le TCL avec la commande eval, tous les Shells notamment le Cshell ou le Tcsh avec le back quote `

Modifié par TitiXsi

Partager ce message


Lien à poster
Partager sur d’autres sites

×