971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 (modifié) 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é le 18 novembre 2021 par 971jmd
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 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
Fredmas Posté(e) le 18 novembre 2021 Auteur Signaler Posté(e) le 18 novembre 2021 (modifié) 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 Modifié le 18 novembre 2021 par Fredmas
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 (modifié) Petite parenthèse tu sais comment on appuie sur un bouton d'un QA avec GEA GEA.add(true, 0, "", {{"QA", 58, "onReleased", "ON24_S1_C1" }}) ca fonctionne pas Modifié le 18 novembre 2021 par 971jmd
Fredmas Posté(e) le 18 novembre 2021 Auteur Signaler Posté(e) le 18 novembre 2021 (modifié) Non pas du tout car je n'ai pas installé GEA bien qu'il ait l'air puissant 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 Modifié le 18 novembre 2021 par Fredmas
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 (modifié) 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é le 18 novembre 2021 par 971jmd
Fredmas Posté(e) le 18 novembre 2021 Auteur Signaler Posté(e) le 18 novembre 2021 J'ai fait une faute de frappe dans mon précédent message, il manque le "e" à setTimeout Et dis-donc, tu aurais pu le voir tout seul ça 1
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 oui mai j'ai pas encore arrêté la fatigue
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 ça fonctionne merci, mai quel est le role de la variable decal1 et 2
Fredmas Posté(e) le 18 novembre 2021 Auteur Signaler Posté(e) le 18 novembre 2021 (modifié) 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é le 18 novembre 2021 par Fredmas
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 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
Fredmas Posté(e) le 18 novembre 2021 Auteur Signaler Posté(e) le 18 novembre 2021 (modifié) 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 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 Modifié le 18 novembre 2021 par Fredmas
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 (modifié) 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é le 18 novembre 2021 par 971jmd
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 Alors je sais que tu avais fait beaucoup mieux que moi, et moi je fais que débuter dans le QA
Fredmas Posté(e) le 18 novembre 2021 Auteur Signaler Posté(e) le 18 novembre 2021 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 Bref ça fonctionne comme tu le voulais et c'est le plus important
971jmd Posté(e) le 18 novembre 2021 Signaler Posté(e) le 18 novembre 2021 OUI mai grace à ton aide Merci encore j'ai appris pas mal de choses.
Fredmas Posté(e) le 19 novembre 2021 Auteur Signaler Posté(e) le 19 novembre 2021 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.
Fredmas Posté(e) le 19 novembre 2021 Auteur Signaler Posté(e) le 19 novembre 2021 (modifié) 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 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 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 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 Modifié le 20 novembre 2021 par Fredmas 2
Fredmas Posté(e) le 23 novembre 2021 Auteur Signaler Posté(e) le 23 novembre 2021 (modifié) #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 Modifié le 23 novembre 2021 par Fredmas
jang Posté(e) le 23 novembre 2021 Signaler Posté(e) le 23 novembre 2021 (modifié) 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é le 23 novembre 2021 par jang 1
henri-allauch Posté(e) le 23 novembre 2021 Signaler Posté(e) le 23 novembre 2021 (modifié) 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é le 23 novembre 2021 par henri-allauch
Fredmas Posté(e) le 23 novembre 2021 Auteur Signaler Posté(e) le 23 novembre 2021 (modifié) 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 ;-) 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 But until now my period configured is 60s 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 Modifié le 23 novembre 2021 par Fredmas
Fredmas Posté(e) le 23 novembre 2021 Auteur Signaler Posté(e) le 23 novembre 2021 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.
henri-allauch Posté(e) le 23 novembre 2021 Signaler Posté(e) le 23 novembre 2021 (modifié) 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é le 23 novembre 2021 par henri-allauch
Messages recommandés