Felig Posté(e) le 2 juin 2022 Signaler Posté(e) le 2 juin 2022 (modifié) Pour ceux qui connaissent HC2 mais débutent en HC3, voici des réponses aux principales questions que je me suis posées ces derniers jours. Rien de nouveau, tout est sur le forum (et en plusieurs exemplaires !) mais l'idée est de faire un post avec les principes de base et questions fréquentes (actualisé si besoin en fonction de vos commentaires/corrections), pour les débutants en HC3 qui comme moi sont très mauvais avec les moteurs de recherche. Sources et liens essentiels: ils sont indiqués par @Lazer ici. Un grand merci à lui, beaucoup de mes apprentissages viennent de ses posts. Qu'est-ce qu'un QuickApp (QA) ? Un QA est 3 composants en 1 : Un script LUA, qui peut être organisé en plusieurs fichiers: par exemple un fichier pour votre programme principal ("main"), un fichier pour une librairie de tools, un fichier pour la config utilisateur, etc. Pour utiliser une fonction du fichier tools, il suffit de l'appeler par son nom dans l'onglet principal. Pour créer un nouveau fichier, cliquer sur l’icône Files dans la marge à gauche de l'interface UI. Un module virtuel (device). Contrairement aux VD de HC2, le module virtuel d'un QA simule un module physique (interrupteur, détecteur, sonde, etc.). C'est pour ça que chaque fois qu'on crée un QA il faut choisir le type de device associé. En fonction du type, vous aurez des propriétés ("lastBreached" pour un détecteur par exemple), des icônes, et une interface utilisateur spécifiques équivalentes à ce que vous auriez pour un QA physique du même type. L'idée est que ce module virtuel soit piloté par la HC3 de la même manière que s’il était réel, via des appels fibaro.get(), fibaro.getValue(), fibaro.call() et même via l’API. Le grand avantage est que vous pouvez personnaliser et modifier son « micro-programme » et son interface (UI), ce qui n'est pas possible pour un module réel. La liste des types disponibles et propriétés associées est ici (fichier excel à la fin du post). C'est aussi si besoin une interface (UI) avec des labels, boutons, sliders, comme un VD de HC2. Attention, l'interface par défaut dépend du type de device que vous sélectionnez à la création du QA (cf. ci-dessus). Chaque composant est optionnel. Comme illustré ici il est possible d'avoir des modules QA qui fonctionnent sans une ligne de code (pilotés par des calls externes). Et inversement, si vous n'avez pas besoin de module virtuel, vous pouvez sélectionner l'option "Appareil désactivé" ("Device disabled") dans l'onglet "Avancé" du QA : le QA ne pourra plus être appelé par des calls fibaro, mais le programme LUA fonctionnera normalement et l'interface UI aussi (par contre j'ai l'impression que ça fait disparaitre le QA de l'interface mobile, donc pas forcément une bonne idée...). Comment fonctionnent les variables persistantes dans un QA ? Dans HC2, si on veut une variable persistante, on a le choix entre un label de VD ou une variable globale. Les variables globales existent toujours dans la HC3, elles sont gérées par les fonctions fibaro.getGlobalVariable(var) et fibaro.setGlobalVariable(var, value). Par contre les labels de QA ne sont plus persistants (réinitialisés à chaque démarrage du QA), et leur contenu n'est pas facile à lire (pas de fonction fibaro, il faut passer par le JSON du QA). Mais heureusement ils sont remplacés par les "variables QA" (« quickVars ») : des variables persistantes, mais internes au QA. Ces variables sont gérées par les fonctions QuickApp:getVariable(var) et QuickApp:setVariable(var, value). A noter : Si la "quickVar" n'existe pas, QuickApp:getVariable() renverra une valeur "" et non nil. Il y aura juste un warning dans le log du QA si la variable n'existe pas. Si vous utilisez QuickApp:setVariable() sur une quickVar qui n'existe pas, elle sera créée. Les quickVars peuvent aussi être créées, modifiées ou supprimées dans les paramètres du QA (onglet Variables). MAIS : toute valeur saisie manuellement dans l’interface Web sera convertie en format string (« 99 » au lieu de 99). Pour utiliser un autre format (numérique ou table), il faut utiliser QuickApp:setVariable(). Il est possible de récupérer le contenu des quickVars d'autres QA par des fonctions détournées (mais ce n'était pas l'intention des développeurs). Les variables globales HC3 peuvent être gérées dans l'onglet Variables du menu Réglages/Général (basique, mais j'ai mis du temps à le trouver!). Comment fonctionnent les fonctions dans un QA ? Compte tenu de ce qui précède, ça ne devrait pas vous étonner qu’on ait deux types de fonction : les fonctions normales de n’importe quel code LUA (function test(x) return x+x end) et les fonctions QuickApp qui sont ajoutées au code du module virtuel (son « micro-programme » pour reprendre mon image initiale). L’intérêt principal des fonctions QuickApp est qu’elles sont appelables par d’autres QA. L’autre intérêt est que chaque QA vient avec des fonctions déjà existantes qui sont bien utiles (ex : QuickApp:debug(), QuickApp:getVariable(), etc.). La fonction de gestion de l’interface UI notamment est une fonction QuickApp. Le QA simule une logique de langage orienté objet. Pour faire un parallèle avec Python (le seul langage orienté objet que je pratique un peu), QuickApp est une classe qui contient des fonctions (ou méthodes) mais aussi des variables (QuickApp.id est l'id du QA par exemple). Au sein d'une fonction QuickApp les autres fonctions et variables du QA peuvent être appelées par self:fonction() ou self.variable. L’appel d'une fonction d’un autre QA se fait via fibaro.call(id, "maFonction", arg1, arg2, etc.). L'inconvénient de cette méthode est qu'il n'y a pas de retour (pas de confirmation de succès, ni possibilité de renvoyer une variable au QA d'origine). Là aussi, il est possible de régler le problème par des contournements, comme expliqué ici. Comment est structuré le code LUA d’un QA ? La structure normale du code LUA d’un QuickApp est comme suit : Le code est exécuté une première fois de haut en bas. C'est l'occasion de déclarer les variables et fonctions. Ensuite, le QA lance la fonction QuickApp:onInit() si elle existe. C'est dans cette fonction que votre code doit commencer normalement. Voici un exemple (fonctionne avec un QA de type "multilevel sensor", qui accepte des valeurs numériques pour sa propriété "value"): function QuickApp:turnOn() -- appelable par fibaro.call(id, "turnOn") self:updateProperty("value", "99") afficheValeur(self) end function QuickApp:turnOff() -- appelable par fibaro.call(id, "turnOff") self:updateProperty("value", "0") afficheValeur(self) end function afficheValeur(self) self:debug("Valeur du module "..self.id.." : "..self.properties.value) end function QuickApp:onInit() self:debug("onInit - Démarrage du module "..self.id) --afficheValeur(self) setTimeout(function() afficheValeur(self) end, 0) end Contrairement au code des VD HC2, le code des QA ne s’exécute qu’une seule fois. Si vous souhaitez une boucle, il faut créer une fonction mainLoop() appelée via une fonction setInterval(). Tout est expliqué ici. Pourquoi on voit souvent l'instruction setTimeout(function() maFonction(self) end, 0) à la fin de la fonction QuickApp:onInit() ? C’est expliqué ici. En résumé, ça permet d’avoir accès à une variable LUA globale « quickApp » qui contient toutes les propriétés et méthodes de la classe QuickApp (instanciation), mais qui ne s’initialise que si la fonction QuickApp:onInit() est terminée. Même si on n'utilise pas cette variable, c'est une bonne habitude de laisser la fonction QuickApp:onInit() se terminer avant de lancer la fonction suivante. Modifié le 2 juin 2022 par Felig Incorporation des corrections suggérées par Lazer et ajout d'un exemple de code LUA. 6 2
Lazer Posté(e) le 2 juin 2022 Signaler Posté(e) le 2 juin 2022 Génial, bravo et merci J'ai épinglé ton message du coup, il restera en haut de la page de cette section tutoriels. Juste 2 ou 3 précisions : Les "onglets" du QuickApp qui nous permettent d'organiser notre code LUA, sont en réalité appelés des fichiers. Pour les développeurs, c'est exactement comme quand on réalise un programme avec plusieurs fichiers, qui sont ensuite compilés et liés ensemble avant l'exécution. Le QuickApp lui-même est un programme, qui s'exécute dans un processus géré par le système d'exploitation (Linux) Si tu vas voir le JSON de tes modules QuickApp via l'API HTTP (ou après exportation du QuickApp sur ton PC avec l'extension FQA), tu verras que ces fichiers apparaissent dans le champ files, qui est bien la traduction anglaise de fichier. Le fait de créer un second fichier "tools" pour reprendre ton exemple n'a rien à voir avec le fait d'appeler ses fonctions avec tools:xxx(). Le nom du fichier n'a aucune importance dans l'exécution du programme LUA. En revanche, lors du développement de mes QA, j'ai choisi comme bonne pratique de nommer mes fichiers de la même façon que la librairie qu'elle comporte. Mes librairies, sont en réalité des tables au sens LUA du terme, c'est à dire un tableau qui comprend des fonctions. Basiquement : tools = {} function tools:maFonction(...) -- Fait des trucs end Et c'est bien le nom de la table tools qui importe, car c'est ainsi qu'elle sera connue dans tout le programme LUA (c'est à dire dans l'ensemble des fichiers, ou onglets, du QuickApp) LUA n'est pas un vrai langage de programmation orienté objet, néanmoins Fibaro a construit les QuickApps avec une approche objet. "QuickApp" est assimilable à une classe, donc la représentation théorique de l'objet. "quickApp" (sans la majuscule donc) est assimilable à l'instanciation d'un objet à partir de la classe QuickApp. Et le mot clé self permet d'accéder aux éléments de l'objet en cours. Donc si on est dans une fonction de QuickApp, alors self pointe également sur quickApp, ça revient au même. En pratique on n'a pas besoin d'utiliser quickApp (sans la majuscule), sauf quelques cas particuliers, notamment la communication d'un Child Device vers le QuickApp parent. Et donc justement, il est peu important de comprendre ces notions quand on développe un QuickApp "célibataire", mais il devient primordial d'assimiler ces concepts quand on commence à élever des enfants. 2 1
Phil1789 Posté(e) le 24 janvier 2023 Signaler Posté(e) le 24 janvier 2023 Ce post semble fort interessant mais ne correspond pas vraiment au titre "QA pour les nuls", je suis mais je n'ai pas vraiment compris on devrait faire des posts pour les nuls de chez nuls, comme moi
mprinfo Posté(e) le 24 janvier 2023 Signaler Posté(e) le 24 janvier 2023 Alors pas vraiment d'accord avec toi Avant d'écrire un QA il est indispensable de connaître la théorie et le mécanisme. Tu remarqueras que l'auteur ne donne pas ou peu de commande lua il explique juste le fonctionnement théorique des QA Pour ce qui est de la pratique il faut relever les manches et étudier les différents exemples de codes que l'on trouve sur le forum Je te de conseil de commencé avec les codes partagés par[mention=133]Lazer[/mention] ou encore pire ceux de[mention=3]Krikroff[/mention] Envoyé de mon BLA-L29 en utilisant Tapatalk
Phil1789 Posté(e) le 24 janvier 2023 Signaler Posté(e) le 24 janvier 2023 ce n'était absolument pas une critique que du contraire, simplement difficile à comprendre pour un nul comme moi qui démarre sur HC3 1
Felig Posté(e) le 24 janvier 2023 Auteur Signaler Posté(e) le 24 janvier 2023 @Phil1789 le post s'adresse à des gens qui sont très à l'aise avec le concept de Virtual Device dans la HC2, ce qui était mon cas. Pour moi un VD c'était juste des ligne des code avec une interface, et je ne comprenais rien au concept de QA, auquel on devait donner un "type" quand on le créait. Par contre, si tu as programmé des VD, et que ça te semble obscur, ça veut dire que j'ai été trop rapide, et en me relisant c'est vrai qu'il n'y a pas beaucoup d'exemples. Si tu as des suggestions de concepts à éclaircir, ou un exemple de QA que tu veux développer, je compléterai le post initial.
mprinfo Posté(e) le 24 janvier 2023 Signaler Posté(e) le 24 janvier 2023 ce n'était absolument pas une critique que du contraire, simplement difficile à comprendre pour un nul comme moi qui démarre sur HC3Je n'ai pas pris cela pour une critiqueEnvoyé de mon BLA-L29 en utilisant Tapatalk
fel-x Posté(e) le 23 mai Signaler Posté(e) le 23 mai Salut les amis, je parcours des dizaines de forums et de topics ces derniers mois pour me familiariser avec les quickapps durant mon temps libre. J'ai écrits des scénarios en LUA qui fonctionnent individuellement... mais je voudrais les combiner dans une quickapp. Et évidemment ça ne marche pas du premier coup, surtout en l'absence de connaissances profondes en programmation. Ci-dessus dans ce post je pense avoir trouvé une piste pour ce que je veux faire. En gros, je voudrais séparer plusieurs fonctions dans des fichiers (certains disent "onglets" mais ce sont bien des fichiers LUA) de la même QA afin de ne pas l'alourdir. Disons que je crée une QA qui s'appelle QA_Test avec dedans 3 fichiers lua : main (il est obligatoire lui), tools et utils Ma structure serait : QA_Test ├─ main.lua ├─ tools.lua ├─ utils.lua Disons aussi que tools.lua contient un long code rempli de variables locales et de fonctions et exécute ces fonctions et termine par enregistrer les résultats obtenus dans des variables de la QA avec setVariable() Disons enfin que utils.lua est du même acabit mais sert à faire d'autres calculs et exécuter d'autres fonctions, et termine lui aussi par enregistrer les résultats obtenus dans des variables de la QA avec setVariable() Si je comprends bien il n'y a pas de fonction aussi simple que "require()" ou "include()" en Lua sur HC3. Cependant on peut appeler une fonction ou plusieurs fonctions d'un autre fichier de la même QA ? Mais peut-on simplement faire exécuter tout le code lua d'un fichier ? Dans mon cas, main.lua devrait par exemple vérifier une variable "machin" et si elle est vide (= "") alors il exécute tools.lua et sinon il exécute utils.lua. C'est possible ça ? Ou bien je dois lui faire exécuter un scénario via son ID ? Car en effet le contenu de tools.lua et de utils.lua provient de 2 scénarios que j'ai écrits et qui fonctionnent. Ce serait quand même plus propre d'avoir tout le code dans une seule QA, de façon à pouvoir la partager non ? Merci pour vos conseils avisés
Lazer Posté(e) le 23 mai Signaler Posté(e) le 23 mai il y a une heure, fel-x a dit : Si je comprends bien il n'y a pas de fonction aussi simple que "require()" ou "include()" en Lua sur HC3. Non mais le simple fait d'ajouter un autre fichier LUA dans un QA, c'est comme si un require ou include était fait implicitement. il y a une heure, fel-x a dit : Cependant on peut appeler une fonction ou plusieurs fonctions d'un autre fichier de la même QA ? Oui, justement, c'est bien l'objectif de pouvoir attacher ces fichiers additionnels au QA. il y a une heure, fel-x a dit : Mais peut-on simplement faire exécuter tout le code lua d'un fichier ? Pas sûr de comprendre ta question. Au démarrage du QA, tout le code LUA contenu dans le fichier main et les fichiers additionnels, est exécuté. Littérallement. Si on organise le code dans des fonctions, c'est pour éviter que le contenu des fonctions soit exécuté au démarrage du QA. Dit autrement, le code LUA qui n'est pas dans une fonction est exécuté au démarrage du QA. On s'en sert généralement pour définir des variables, mais aussi les fonctions... car en LUA les fonctions sont des variables ! Une fois que le QA a démarré, et donc exécuté tout son code, la HC3 appelle la function QuickApp:onInit() Et c'est là dedans qu'on commence réellement à faire des trucs, des choses, et des machins. En option, on peut même faire des bidules. il y a une heure, fel-x a dit : Dans mon cas, main.lua devrait par exemple vérifier une variable "machin" et si elle est vide (= "") alors il exécute tools.lua et sinon il exécute utils.lua. C'est possible ça ? Oui mais attention, on n'exécute pas tools.lua ou utils.lua. Comme dit précédemment, ils sont automatiquement exécutés au démarrage du QA. Ce que tu peux faire, c'est exécuter des fonctions qui se trouvent dans les fichiers tools ou utils. Mais tu devrais commencer doucement. Te familiariser avec un QA de base, c'est à dire avec le fameux onOnit(), puis créer une boucle infinie avec setTimeout(), ajouter des fonctions, réagir aux éléments de l'interface (boutons...), et ensuite tu verras pour ajouter des fichiers avec des fonctions dedans. 1
jojo Posté(e) le 24 mai Signaler Posté(e) le 24 mai lit par exemple ceci où @Lazer utilise dans le LUA de main des fonction définies dans d'autres fichiers 1
fel-x Posté(e) le 30 mai Signaler Posté(e) le 30 mai Merci @Lazer ! Grâce à ta réponse, j'ai compris un élément essentiel : Le 23/05/2025 à 18:48, Lazer a dit : Au démarrage du QA, tout le code LUA contenu dans le fichier main et les fichiers additionnels, est exécuté. Littérallement. Dès lors, j'ai vu les choses autrement et ça m'a permis d'avancer à grands pas... Ma première QA est écrite et fonctionnelle Je l'ai mise à disposition dans le sujet en question et sur marketplace.
jojo Posté(e) le 30 mai Signaler Posté(e) le 30 mai j'ai rien dit, mais je n'ai pas compris ce point. Pour moi : il vérifiait la syntaxe il n'exécutait que la fonction onInit() à la sauvegarde ...
fel-x Posté(e) le 30 mai Signaler Posté(e) le 30 mai Oui c'est perturbant mais il faut se dire qu'avant d'exécuter onInit() (que ce soit automatique ou parce que tu sauvegardes) la HC3 va relire tout le code et toutes les pages du QA, et donc inclure les fonctions des pages annexes. C'est pourquoi il faut faire attention à ce que tu déclares dans les pages autres que main.lua ! 1
Messages recommandés