Aller au contenu
Fredmas

Questions de débutant en Quick Apps sur HC3

Recommended Posts

if timeoutClim1 > 0 then clearTimeout(timeoutClim1) timeoutClim1 = 0 end
  timeoutClim1 = setTimeout(function() self:OFF_S1_C1() end, duration)
end



function test2(self)
  ---self:ON24_S1_C2()
  if timeoutClim2 > 0 then clearTimeout(timeoutClim2) timeoutClim2 = 0 end
  timeoutClim2 = setTimeout(function() self:OFF_S1_C2() end, duration)
end


function test3(self)
  ---self:ON24_S1_C3()
  if timeoutClim3 > 0 then clearTimeout(timeoutClim3) timeoutClim3 = 0 end
  timeoutClim3 = setTimeout(function() self:OFF_S1_C3() end, duration)
end




 

Idée l'idée serait de mettre une Tampo de cinq secondes devant le self:OFF_S1_C1() et self:OFF_S1_C2() et self:OFF_S1_C3()

 

un fibaro:sleep

 

 

Modifié par 971jmd

Partager ce message


Lien à poster
Partager sur d’autres sites

j'ai essayer avec 3 Duration 

 


--2H
function QuickApp:buttonClim2()
self:debug("BOUTON 2H")
 duration1 = 7*1000
  test1(self) 
self:updateView("etat", "text", "Dernière action >> 2 Heurs")
end

--2H
function QuickApp:buttonClim2()
self:debug("BOUTON 2H")
 duration2 = 10*1000
  test2(self) 

end

--2H
function QuickApp:buttonClim2()
self:debug("BOUTON 2H")
 duration3 = 12*1000
  test3(self) 

end

 

 


function test1(self)
  ---self:ON24_S1_C1()
  if timeoutClim1 > 0 then clearTimeout(timeoutClim1) timeoutClim1 = 0 end
  timeoutClim1 = setTimeout(function() self:OFF_S1_C1() end, duration1)
end

function test2(self)
  ---self:ON24_S1_C1()
  if timeoutClim2 > 0 then clearTimeout(timeoutClim2) timeoutClim1 = 0 end
  timeoutClim2 = setTimeout(function() self:OFF_S1_C2() end, duration2)
end

function test3(self)
  ---self:ON24_S1_C1()
  if timeoutClim3 > 0 then clearTimeout(timeoutClim2) timeoutClim1 = 0 end
  timeoutClim3 = setTimeout(function() 
  self:OFF_S1_C3()  end, duration3)
end

 

ami rien 

Partager ce message


Lien à poster
Partager sur d’autres sites
Il y a 3 heures, 971jmd a dit :

Idée l'idée serait de mettre une Tampo de cinq secondes devant le self:OFF_S1_C1() et self:OFF_S1_C2() et self:OFF_S1_C3()

#1. Ou alors tu lances tes 3 fonctions test1, test2, et test3 en décalage de 5s par exemple

--2H
function QuickApp:buttonClim2()
  self:debug("BOUTON 2H")
  duration = (value)*1000
  test1(self)
  decal1 = setTimeout(function() test2(self) end, 5000)
  decal2 = setTimeout(function() test3(self) end, 10000)
  -- self:DH() 
  self:updateView("etat", "text", "Dernière action >> 2 Heurs")
end

En déclarant tes variables decal1 et decal2 où tu veux comme tu veux.

 

 

 

#2. Ou alors tu augmentes le timeout de tes OFF comme ça par exemple :

timeoutClim2 = setTimeout(function() self:OFF_S1_C2() end, duration2+5000)

 

 

Bref des idées il y en a plein :D

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

 

 

Petite parenthèse tu sais comment on appuie sur un bouton d'un QA avec GEA

GEA.add(true0"", {{"QA"58"onReleased",  "ON24_S1_C1" }})
 
ca fonctionne pas 

 

 

 

Modifié par 971jmd

Partager ce message


Lien à poster
Partager sur d’autres sites

Non pas du tout car je n'ai pas installé GEA bien qu'il ait l'air puissant :P

Au risque d'y passer énormément d'heures, comme tu l'as compris dans ce sujet depuis le début, apprenant étape par étape j'ai choisi de développer mon propre QA de gestion automatique des actions en partant de zéro, mais avec une maintenance que je maitrise car j'ai écrit le code (avec l'aide du forum).

C'est long, c'est peut-être moins bien fait, moins puissant, mais il grossit, il s'améliore et j'apprends :D

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

je comprend pas trop 

 

le decal1 et 2 

decal1 = setTimout(function() test2(self) end, 5000) --- 5 S
  decal2 = setTimout(function() test3(self) end, 10000) ---  10 S

j'ai une erreur 

Unknown error occurred: handleJsonRpc

 

Modifié par 971jmd

Partager ce message


Lien à poster
Partager sur d’autres sites

J'ai fait une faute de frappe dans mon précédent message, il manque le "e" à setTimeout :P

 

Et dis-donc, tu aurais pu le voir tout seul ça :D

  • Like 1

Partager ce message


Lien à poster
Partager sur d’autres sites

oui :D mai j'ai pas encore arrêté la fatigue 

Partager ce message


Lien à poster
Partager sur d’autres sites

ça fonctionne merci, mai quel est le role de la variable   decal1 et 2

Partager ce message


Lien à poster
Partager sur d’autres sites

A la place de ça :

decal1 = setTimeout(function() test2(self) end, 5000)

 

tu dois pouvoir écrire ça :

setTimeout(function() test2(self) end, 5000)

 

Mais j'ai pris "la bonne ou mauvaise" habitude de toujours mettre le setTimeout dans une variable, ce qui permet de tester l'indexation de cette variable de sorte à pouvoir faire par exemple un clearTimeout si besoin...

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

voila comment j'ai fait 

 

function QuickApp:B2H()

--- ON 24
setTimeout(function() self:ON24_S1_C1() end, 1000)
setTimeout(function() self:ON24_S1_C2() end, 5000)

--- Auto OFF
  duration =   30 *1000
  setTimeout(function() test1(self) end, 5000)
  setTimeout(function() test2(self) end, 10000) 
  self:updateView("etat", "text", "Dernière action >> 2 Heurs")

    self:debug("BOUTON 2H")
end

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Donc lorsque tu appuies sur le bouton B2H ça fait :

1. Dans 1s exécute ON24_S1_C1()

2. Dans 5s exécute ON24_S1_C2()

3. Définit d'un timer de 30s pour les extinctions à exécuter par test1() et test2()

4. Dans 5s exécute test1()

5. Dans 10s exécute test2()

 

1. Pourquoi tu définis un timeout de 1s pour ON24_S1_C1() ? Je ne vois pas l'utilité car il ne se passe rien pendant cette seconde.

4. Pourquoi tu définis un timeout de 5s pour test1() ? Je ne vois pas l'utilité car tu veux décaler le deuxième OFF (donc test2) par rapport au premier, pas décaler le premier par rapport à rien.

 

 

 

Après je me permets de te rappeler que même si je t'ai répondu pas mal de fois (et parfois beaucoup cherché) j'ai essayé de répondre à tes questions les unes après les autres pour te faire comprendre, pas à faire ton QA à ta place :P

Désormais je trouve que tu enchaines beaucoup de timeout, avec des risques de décalage ou autres crash (notamment avec ton histoire de plusieurs OFF en même temps que ta clim n'aime pas). Sur le papier ça a l'air de fonctionner, mais dans la vraie vie avec des aléas, je ne suis pas sûr qu'il soit secure à toute épreuve.

Je maintiens que je ferais autrement, par exemple (mais il faudrait y réfléchir plus longtemps) en ayant une seule boucle temporelle régulière façon intervalRunner, qui contrôle ce qui se passe et qui incrémente des variables lors des passages de la boucle, faire des comparaisons de ces variables, etc. Je pense que les timer seraient plus fiables, les fonctions moins nombreuses (ou pas) et la maintenance de ton code plus facile. Par contre niveau perf HW je ne peux pas te dire.

Mais bon comme déjà dit, tu as ta première étape, et celle-ci terminée tu auras tout le temps de repartir d'une page blanche si tu en as le courage et l'envie :D

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

le Pourquoi tu définis un timeout de 1s pour ON24_S1_C1()

 

C'est pour éviter d'avoir allumé 2 climatiseurs en même temps, question de délestage électrique 

 

 

j'ai refait 

 

function QuickApp:B2H()
--- ON 24
self:ON24_S1_C1()
setTimeout(function() self:ON24_S1_C2() end, 5000)
--- Auto OFF
  duration =   30 *1000
  test1(self) 
  setTimeout(function() test2(self) end, 10000) 
  self:updateView("etat", "text", "Dernière action >> 2 Heurs")

    self:debug("BOUTON 2H")
end

 

Modifié par 971jmd

Partager ce message


Lien à poster
Partager sur d’autres sites

Alors je sais que tu avais fait beaucoup :Dmieux que moi, et moi je fais que débuter dans le  QA 

Partager ce message


Lien à poster
Partager sur d’autres sites

:D alors ça je n'en sais rien du tout si j'ai fait mieux ou pas, je n'avais jamais vu du LUA de ma vie il y a à peine 6 mois, et encore moins un QA, donc niveau débutant j'en suis. Et puis on s'en fiche d'ailleurs ce n'est pas de la compétition mais de l'entraide. Je ne voulais pas te dire quoi faire juste faire attention à ne pas t'avoir donné de mauvais conseils :P

Bref ça fonctionne comme tu le voulais et c'est le plus important :60:

 

Partager ce message


Lien à poster
Partager sur d’autres sites

OUI mai grace à ton aide :60: Merci encore j'ai appris pas mal de choses.

 

 

Partager ce message


Lien à poster
Partager sur d’autres sites
Le 17/11/2021 à 21:33, jang a dit :

The general advice to declare your variables in the beginning of the code/functions is usually a very good advice.

 

Actually, the QA is "executed" when the code is loaded. It's just that fibaro helps us by collecting a lot of nice-to-have functions in the QuickApp class and when the code is loaded is creates a QuickApp object and calls its :onInit() function as an "entry point" for our code.

Clear, thanks @jang ;)

As my main QA which is checking automatically daily actions to be done is stable now and growing, this week I've started to modify it for code improvement.

And as an example, I started by variables definition and localisation.

At the beginning, I put main of them as global ones in the onInit. Now they are all as local ones at the very beginning of the code. I didn't measure the performances, and I don't care really, but I am trying to reduce the reach of them as you and @Lazer advised.

Next step, probably, to move much of them directly in the local functions in the code, to reduce again the reach. But not sure yet, because they would be more disseminated in the code, thinking about the maintenance.

:P

Partager ce message


Lien à poster
Partager sur d’autres sites
Le 25/07/2021 à 19:22, Lazer a dit :

Désavantages de l'écriture en DB (que ça soit une variable QA ou Globale) :

- lent

- usure mémoire flash

- mène à un crash aléatoire (à priori quand il y a trop d'écritures simultanées, j'ai l'impression que le process dédié à cette tâche dans la box le gère mal... problème connu depuis la v4 sur HC2... même si ça va mieux depuis)

Donc oui, on évite autant que possible les écritures en DB.

(...)

En tout cas, ce que tu stockes dans une variable QA/Globale, doit nécessairement avoir besoin d'être persistent, c'est à dire conservé au prochain reboot.

 

PS : les labels ne sont pas persistants en DB sur HC3 contrairement à la HC2, mais leur écriture est tout de même relativement lente.

 

En effet, chaque modification de label entraine l'émissions d'événements récupérables dans les API refreshStates et events/history, donc le rafraichissement des différentes interfaces graphiques (Web, appli mobile...)

Le 25/07/2021 à 20:19, Fredmas a dit :

Je vais relire mon code, et probablement me forcer à le repenser autant que nécessaire, pour être sûr que ce que je garde en DB soit indispensable lors d'un redémarrage/plantage.

Et passer le reste en variable dans le QA, que leur portée soit locale ou globale ;)

(...)

Due to that, as I said, even if I needed time to understand, I will try now to work in local way, out of DB as much as possible :D

Le 03/09/2021 à 20:18, Lazer a dit :

Bref, l'important dans cette histoire, c'est la portée des variables, qu'on doit limiter à leur strict nécessaire, c'est une bonne pratique pour éviter les collisions de 2 variables qui porteraient le même nom dans 2 bouts de codes différents.

C'est particulièrement vrai quand on réutilise des bouts de codes qu'on a déjà développé (sous forme de "librairie", que ça soit dans le même fichier LUA ou dans un autre fichier LUA du QuickApp)

Le 03/09/2021 à 20:27, Fredmas a dit :

Merci :13:

Après comme tu l'as compris, l'idée est davantage de progresser, apprendre, et éventuellement  faire évoluer le code dans le bon sens.

Pour l'instant, mon installation et mes QA n'ont que faire de gains de performance au niveau de la milliseconde ;)

Mais comme je l'ai déjà lu de ta part quelque part, peu importe la taille de la machine, un code optimisé reste une bonne idée, évitant le surdimensionnement des machines et usages, de manière générale. Bref tu m'as compris :2:

 

Bon, et bien résultat des courses quelques temps plus tard :

- Je n'ai plus de variable globale persistante dans l'onglet Variable dans Général

- Je n'ai qu'une seule variable persistante (que je ne réécris quasiment jamais) dans l'onglet Variable de chaque QA automatique, qui me permet simplement de savoir si j'avais éteint la boucle automatique ou pas en cas de redémarrage afin de ne pas la redémarrer involontairement

- La quasi totalité de mes variables à l'intérieur des QA est passée en local. Mais je n'ai pas encore terminé de réduire leur portée au stricte nécessaire

 

Donc tout simplement merci les gars pour tous les conseils que vous nous apportez en partageant votre savoir qui nous fait comprendre et progresser :13:

 

 

Modifié par Fredmas
  • Like 2

Partager ce message


Lien à poster
Partager sur d’autres sites

#6 Question 6 : respecter de bonnes pratiques d'architecture logicielle pour le code d'un QA

 

C'est davantage un sujet de partage, et à la rigueur de café-philo me concernant, qu'une question répondant à un besoin à proprement parler. Mais maintenant que mes QA sont stables et continuent d'être modifiés et améliorés, je me pose la question d'une meilleure architecture du code et de comment mieux le structurer tant pour la performance que pour sa compréhension et sa maintenance.

Le sujet est vaste, mais ici je vais rester sur l'exemple discuté depuis le début du topic (libre à chacun d'étendre cette réflexion à d'autres exemples), un QA qui tourne en boucle pour agir quand il y a besoin. Je passe donc sur les déclarations des variables, la fonction onInit() et autres fonctions qui permettent de gérer la boucle, les boutons et le QA dans son ensemble, pour me concentrer sur la principale.

Dans ce QA j'ai donc créé une fonction principale qui est exécutée avec une période définie (sur la base intervalRunner de @jang), et cette fonction contient en enchaînement de toutes les conditions à vérifier et les actions à réaliser en fonction. La structure visuelle de cette fonction (et ses centaines de lignes) est principalement réalisée par des commentaires, aujourd'hui. Réfléchissant à ce sujet, je me dis :

 

qu'au lieu de coder cette fonction principale comme ça :

function mainCode(self)
  conditions1
  actions1
  conditions2
  actions2
  conditions3
  actions3
  etc.
end

je pourrais, je devrais, la coder de cette manière là :

function mainCode(self)
  conditions1
  self:actions1()
  conditions2
  self:actions2()
end

function QuickApp:actions1() --"QuickApp definition" if need to be called from out
end

function QuickApp:actions2() --"QuickApp definition" if need to be called from out
end

 

Qu'en pensez-vous les experts du code LUA et des QA ? C'est une bonne idée ou il serait mieux de faire encore autrement en considérant "le monde merveilleux de l'asynchronisme" (comme dirait @Lazer).

Mais je me dis que cette architecture serait peut-être plus fonctionnelle et plus lisible. La boucle mainCode() vérifierait uniquement les conditions, et appellerait d'autres fonctions qui elles contiendraient uniquement les actions à réaliser, et si besoin qui peuvent être disponibles pour être appelées par d'autres QA.

Je me trompe peut-être complètement, je ne suis pas informaticien et encore moins ingénieur logiciel. Je me base sur ma propre compréhension qui évolue au fil du temps depuis que j'ai adopté les QA  :P

 

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

I guess it's something like

if (conditions1) then self:actions1() end

?

 

You could make your conditions into self:condition1() too.

if self:condition1() then self:action1() end

The important thing is that your conditions need to return true/false.

 

Then you could put them into an list

function QuickApp:condition1() return true end
function QuickApp:condition2() return math.random(1,3) > 1 end
function QuickApp:condition3() return false end
function QuickApp:action1() fibaro.call(...) end
function QuickApp:action2() fibaro.call(...) end

local rules = {
  {condition='condition1',action='action1'},
  {condition='condition2',action='action2'},
  {condition='condition3',action='action2'}
}

function mainCode(self)
    for _,r in ipairs(rules) do  -- Test conditions and run actions if true
       if self[r.condition](self) then self[r.action](self) end
    end
end

Then you run the mainCode every 30s and rename your QA to GEA ;-) 

 

P.S I probably wouldn't declare conditions/actions as QuickApp methods.

Modifié par jang
  • Like 1

Partager ce message


Lien à poster
Partager sur d’autres sites

J'ai un doute 

 

Soit une variable MyVar déclaré dans la fonction OnInit() d'un QA de la manière suivante self.MyVar = 1 

J'utilise cette forme de déclaration depuis mon premier QA vu des exemples de ce forum.

A chaque init du QA MyVar prendra la valeur 1. 

Cette variable est utilisable dans les fonctions du QA par self.MyVar 

Elle n'est pas accessible depuis un autre QA ( donc pas de conflit )

 

Qu'elle est la différence avec un variable déclaré Hors de  toute fonction y compris OnInit()  par local MyVar = 1

Dans ce type d'utilisation,  la bonne méthode est  self ou local ?

 

Je m'embrouille 

 

 

Modifié par henri-allauch

Partager ce message


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

I guess it's something like


if (conditions1) then self:actions1() end

?

Yes something like that. I didn't think exactly in this way, but why not.

Most of conditions are not a single one, but more linked to others. But anyway this is not the issue about the size of conditions.

The purpose of this discussion was more to understand if the interest I imagined to separate the long list of several different conditions from the long list of several different actions, was a good idea (or not) from pure code point of view.

As an example, to have a place to check easily all conditions to be checked regularly, and a place with different actions in different function to be called, to modify them easily without touching conditions code.

From pure architecture point of view, in a general way.

 

 

Il y a 4 heures, jang a dit :

You could make your conditions into self:condition1() too.

if self:condition1() then self:action1() end

The important thing is that your conditions need to return true/false.

 

Then you could put them into an list


function QuickApp:condition1() return true end
function QuickApp:condition2() return math.random(1,3) > 1 end
function QuickApp:condition3() return false end
function QuickApp:action1() fibaro.call(...) end
function QuickApp:action2() fibaro.call(...) end

local rules = {
  {condition='condition1',action='action1'},
  {condition='condition2',action='action2'},
  {condition='condition3',action='action2'}
}

function mainCode(self)
    for _,r in ipairs(rules) do  -- Test conditions and run actions if true
       if self[r.condition](self) then self[r.action](self) end
    end
end

Then you run the mainCode every 30s and rename your QA to GEA ;-) 

:D ok so maybe I am reinventing my own GEA step by step without knowing the content of GEA... But anyway I learn and become more and more autonomous :P

But until now my period configured is 60s :ph34r:

 

Here I understand the philosopy of working of your example, a little bit different from the idea I mentionned in the prior post (putting conditions in main, and just calling action functions). But the idea to separate conditions and actions in the code is the same.

Maybe I missed something, but what is the advantage of writting the content you put in local rules table (condition='condition1',action='action1'), instead of listing this same content directly in the mainCode(self) without using a function ipairs?

 

 

Il y a 4 heures, jang a dit :

 

P.S I probably wouldn't declare conditions/actions as QuickApp methods.

Thanks for the advise. I don't know. I don't care to do it as QuickApp methods (or not) if it is a better way to code and to work, I can ;) But I feel it a little bit heavy...

Each new step is pushing me to do in a different better way, and this is good ^_^

But for this reason, I wonder why not put all conditions as a list in mainCode(), only calling QuickApp:function() for actions... (able to be called from another QA if needed).

I need to think more about it to clean my mind  :2:

 

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites
il y a 13 minutes, henri-allauch a dit :

J'ai un doute 

 

Soit une variable MyVar déclaré dans la fonction OnInit() d'un QA de la manière suivante self.MyVar = 1 

J'utilise cette forme de déclaration depuis mon premier QA vu des exemples de ce forum.

A chaque init du QA MyVar prendra la valeur 1. 

Cette variable est utilisable dans les fonctions du QA par self.MyVar 

Elle n'est pas accessible depuis un autre QA ( donc pas de conflit )

 

Qu'elle est la différence avec un variable déclaré Hors de  toute fonction y compris OnInit()  par local MyVar = 1

Dans ce type d'utilisation,  la bonne méthode est  self ou local ?

 

Je m'embrouille

Je crois que nous en parlons un peu à partir d'ici dans différents post : https://www.domotique-fibaro.fr/topic/15182-questions-de-débutant-en-quick-apps-sur-hc3/?do=findComment&comment=240845

Sinon pour essayer de te répondre, si dans onInit() :

- tu déclares une variable locale, elle n'existera que dans la fonction onInit()

- tu déclares une variable globale, sera disponible dans tout ton QA

- tu déclares une variable self, elle sera un élément de la table du QA, utilisable également dans tout ton QA

Mais c'est mieux expliqué dans le lien que je t'ai donné ;)

 

Contrairement au début, désormais j'utilise majoritairement des variables locales déclarées dans le code du QA, en dehors de onInit() autant que possible que j'essaie de considérer uniquement que comme une fonction (avec son contenu) lancée automatiquement après le load du code.

Uniquement lorsque le besoin est réel, j'utilise une variable gobale ou self.

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Oui j'ai lu tout ça et je vois les différences

 

Sauf que pour une variable que je souhaite initialisée, et utilisable exclusivement dans mon QA je ne comprend pas la différence entre

     local myVar déclaré hors init() et fonction() donc Globale au fichier QA

et self.Myvar déclarée dans le Init()

Modifié par henri-allauch

Partager ce message


Lien à poster
Partager sur d’autres sites

×