Aller au contenu
Fredmas

Questions de débutant en Quick Apps sur HC3

Recommended Posts

il y a 22 minutes, Fredmas a dit :

Merci, car c'est effectivement une question qui me trotte dans la tête. Grâce à mes petits débuts en QA je suis en train de supprimer mes variables globales qui étaient utilisées dans les scènes.

Mais du coup, que penser des variables non spécifiées "local" dans le code du QA, mais dans l'onglet "variable" du QA ? Si j'ai bien compris elles ne sont pas globales dans le sens LUA/Fibaro, mais d'un point de vue calcul et lenteur dans le QA comparé aux variables locales dans le code du QA ? 

Alors attention, car là aussi il y a confusion.

Depuis le début de la discussion, on parlait de langage LUA, donc les notions de variables "locales" et "globales" sont propres au LUA, avec la portée inhérente.

 

Maintenant, tu parles des variables au sens Fibaro, c'est à dire stockées dans la base de données de la box domotique : HC2, HC3, etc.

=> Ce qu'on appelle Variable Globale (=VG) sur le forum depuis des années.

Ou plus récemment, les Variables de QuickApp depuis la HC3.


Ces 2 types des variables portent mal leur nom, car elles induisent en erreur avec les "variables" au sens langage de programmation (LUA)

Disons qu'elle sont un moyen de stocker des données de manière persistante, comme le ferait un logiciel sur un ordinateur/smartphone : dans un fichier, dans la base de registre, dans une base de données, etc.

On lit ces données avec des fonctions getVariable() et getGlobalVariable(), qui retournent une valeur, qu'on stocke dans une variable (une vraie variable cette fois-ci, au sens LUA du terme), qu'elle soit d'une portée locale ou globale dans notre code LUA, c'est notre responsabilité de programmeur.

Que la variable LUA soit globale ou locale, elle est perdue en cas de redémarrage du QA, donc il faut l'écrire avec setVariable() pour la mémoriser de manière persistante dans la box.

 

Mais finalement, le principe est le même pour les variable de la box que les variables LUA => il faut réduire leur portée au strict nécessaire.

En pratique sur HC2 on utilisait massivement les Variables Globales car on n'avait pas le choix, c'était notre seule méthode de stockage possible, et on s'en servait même pour échanger des données (communiquer) entre différents Modules Virtuels et Scènes.

Sur HC3, cela est terminé, il n'y a quasiment plus aucune raison d'utiliser les Variables Globales, perso sur mon HC3 de production, j'en ai très très peu.

Partager ce message


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

@Lazer

https://stackoverflow.com/questions/6067369/forward-define-a-function-in-lua

 

<edit>

Pour illustrer, to QA Synology Surveillance Station appelle la fonction loop déclarée après onInit...

</edit>

Et ?

La réponse apportée à la question est très claire, et abonde dans mon sens, puisqu'il déclare bien ses variables locales a et b avant de pouvoir les utiliser.

 

Et @jang dit la même chose dans l'un de ses messages.

 

Ce que précise @jang en complément, c'est que dans le cas de QuickApp:onInit(), il est exécuté après l'exécution du fichier. Du coup les variables locales ont bien été déclarées/définies.

 

 

Du coup, je ne comprends pas ta remarque pour le QA Surveillance Station, car la fonction loop est déclarée comme étant un membre de la classe QuickApp, donc non concernée par la notion de "forward" (j'ai appris ce terme aujourd'hui d'ailleurs)

function QuickApp:loop()

end

(et oui je sais, ça ne respecte pas ce que j'ai écris quelques messages plus haut, à savoir que cette boucle n'est pas censée être publiée et être partagée aux autres QA, mais c'est un vieux code, parmi mes premiers QA il y a 1 an)

Partager ce message


Lien à poster
Partager sur d’autres sites

Je crains que tu ne confonde deux aspects :

1) Lua n'impose pas syntactiquement parlant de déclarer une fonction avant son emploi, le fait que cette variable appartienne ou non à la classe QuickApp n'y change rien.

2) La référence que tu fais à onInit, est relative à l'exécution du programme qui ne commence qu'après sa "compilation", donc une fois que l'ensemble du programme a été lu et donc les différentes variables déclarées connues. Le test de @jang ne fait référence qu'à la vitesse d'exécution selon la portée de la variable.

 

function QuickApp:onInit()
    f1("toto");
end
function f1(a) 
    return f2(a);
end -- f1
function f2(a)
    print(a);
end

Désolé, mais ça marche, mon avis se limite à cette considération langagière...

 

Citation

Because many languages force you to declare all local variables at the beginning of a block (or a procedure), some people think it is a bad practice to use declarations in the middle of a block. Quite the opposite: By declaring a variable only when you need it, you seldom need to declare it without an initial value (and therefore you seldom forget to initialize it). Moreover, you shorten the scope of the variable, which increases readability.

https://www.lua.org/pil/4.2.html

 

Modifié par Barelle
Complément

Partager ce message


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

I'm afraid you are confusing two aspects :

1) Lua does not require syntactically speaking to declare a function before its use, the fact that this variable belongs or not to the QuickApp class does not change anything.

2) The reference that you make to onInit, relates to the execution of the program which does not begin until after its "compilation", therefore once the whole program has been read and therefore the various variables declared known. The test of@jang refers only to the speed of execution depending on the scope of the variable.

 




 
    
 

Sorry, but it works, my opinion is limited to this linguistic consideration ...

Yes, but your example is only globally declared functions. We were talking about "forward declaring" local functions.

 

This don't work

function QuickApp:onInit()
    f1("toto");
end
function f1(a) 
    return f2(a);
end -- f1
local function f2(a)
    print(a);
end

This do

function QuickApp:onInit()
    f1("toto");
end
local f2
function f1(a) 
    return f2(a);
end -- f1
function f2(a)
    print(a);
end
Modifié par jang

Partager ce message


Lien à poster
Partager sur d’autres sites

Yes, off course, when the variable if locally declared, its scope is known only after its declaration.

Partager ce message


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

Alors attention, car là aussi il y a confusion.

Depuis le début de la discussion, on parlait de langage LUA, donc les notions de variables "locales" et "globales" sont propres au LUA, avec la portée inhérente.

 

Maintenant, tu parles des variables au sens Fibaro, c'est à dire stockées dans la base de données de la box domotique : HC2, HC3, etc.

=> Ce qu'on appelle Variable Globale (=VG) sur le forum depuis des années.

Ou plus récemment, les Variables de QuickApp depuis la HC3.


Ces 2 types des variables portent mal leur nom, car elles induisent en erreur avec les "variables" au sens langage de programmation (LUA)

Disons qu'elle sont un moyen de stocker des données de manière persistante, comme le ferait un logiciel sur un ordinateur/smartphone : dans un fichier, dans la base de registre, dans une base de données, etc.

On lit ces données avec des fonctions getVariable() et getGlobalVariable(), qui retournent une valeur, qu'on stocke dans une variable (une vraie variable cette fois-ci, au sens LUA du terme), qu'elle soit d'une portée locale ou globale dans notre code LUA, c'est notre responsabilité de programmeur.

Que la variable LUA soit globale ou locale, elle est perdue en cas de redémarrage du QA, donc il faut l'écrire avec setVariable() pour la mémoriser de manière persistante dans la box.

 

Mais finalement, le principe est le même pour les variable de la box que les variables LUA => il faut réduire leur portée au strict nécessaire.

En pratique sur HC2 on utilisait massivement les Variables Globales car on n'avait pas le choix, c'était notre seule méthode de stockage possible, et on s'en servait même pour échanger des données (communiquer) entre différents Modules Virtuels et Scènes.

Sur HC3, cela est terminé, il n'y a quasiment plus aucune raison d'utiliser les Variables Globales, perso sur mon HC3 de production, j'en ai très très peu.

OK, merci de m'avoir corrigé :P

Effectivement je pense avoir fait un raccourci facile/tentant entre variable à portée globale et son stockage dans le contrôleur Fibaro.

Du coup, d'un point de vue contrôleur Fibaro, l'utilisation de variables stockées de manière persistante dans le QA, bien en dur dans l'onglet variable, possède les mêmes désavantages que les VG (d'un point de vue mémoire et contrôleur) ?

Je suis en train de supprimer mes VG, mais au final il faut que je fasse attention à ne pas les remplacer "cotes pour cotes" par des variables persistantes dans le QA, mais autant que possible en local dans le code, en tout cas à chaque fois que je n'ai pas besoin qu'elles soient persistantes ?

Modifié par Fredmas

Partager ce message


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

1) Lua n'impose pas syntactiquement parlant de déclarer une fonction avant son emploi, le fait que cette variable appartienne ou non à la classe QuickApp n'y change rien.

Tout à fait, et je n'ai jamais prétendu le contraire (ou alors je me suis mal exprimé ?)

 

Il y a 5 heures, Barelle a dit :

2) La référence que tu fais à onInit, est relative à l'exécution du programme qui ne commence qu'après sa "compilation", donc une fois que l'ensemble du programme a été lu et donc les différentes variables déclarées connues. Le test de @jang ne fait référence qu'à la vitesse d'exécution selon la portée de la variable.

Je ne faisais pas référence au test de performance de @jang, mais à son message précédent ;)

 

Il y a 5 heures, Barelle a dit :

Because many languages force you to declare all local variables at the beginning of a block (or a procedure), some people think it is a bad practice to use declarations in the middle of a block. Quite the opposite: By declaring a variable only when you need it, you seldom need to declare it without an initial value (and therefore you seldom forget to initialize it). Moreover, you shorten the scope of the variable, which increases readability.

Voilà, on est bien d'accord en fait.

 

 

Il y a 3 heures, Fredmas a dit :

Du coup, d'un point de vue contrôleur Fibaro, l'utilisation de variables stockées de manière persistante dans le QA, bien en dur dans l'onglet variable, possède les mêmes désavantages que les VG (d'un point de vue mémoire et contrôleur) ? 

Je suis en train de supprimer mes VG, mais au final il faut que je fasse attention à ne pas les remplacer "cotes pour cotes" par des variables persistantes dans le QA, mais autant que possible en local dans le code, en tout cas à chaque fois que je n'ai pas besoin qu'elles soient persistantes ?

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.

Je considère cette remarque valable pour toutes les écritures, donc aussi bien les variables que les propriétés des modules ("value", etc).

Si tu regardes mes codes, tu verras que je m'applique à faire autant que possible une vérification de la valeur précédente, une comparaison, avant d"éventuellement stocker la nouvelle valeur si elle diffère. Cela permet d'afficher un petit message de log dans la console, cela réduit l'usure de la flash, les risques de plantage, et de façon assez intéressante, c'est plus rapide, bien que plus d'opérations soient impliquées. En effet, supposons que la variable/propriété ne change qu'une fois sur 10, alors 10 lecture et 1 écriture, c'est beaucoup plus rapide que 10 écritures seules.

 

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.

L'exemple typique, ce sont les adresses IP configurées par l'utilisateur, le user/password, etc....

Il n'y a pas de raison de stocker une valeur pour le plaisir.

Tu peux t'amuser à faire des petits benchmarks de performance, avec une petite boucle sur le modèle déjà partagé par @jang, pour écrire une VG, une Variable QA, un Label, etc... et la même chose en lecture... tu verras la différence flagrante de performance.

Alors quelques microsecondes c'est rien, mais sur un système lourdement chargé, avec des dizaines de QA qui tournent en boucle, ça finit par faire beaucoup.

 

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

Partager ce message


Lien à poster
Partager sur d’autres sites

Add to this that the QuickApp: setVariable (name, value) looks something like this:


    
        
            
        
    

(Similar search for QuickApp: getVariable)

So, the quickAppVariables are stored in a linear list and the time to retrieve / store a variable depends on where in the list it is : o

I don't understand why they didn't use a hash table (!)

I hope that fibaro global variables are stored / retrieved more efficiently.

Modifié par jang

Partager ce message


Lien à poster
Partager sur d’autres sites
il y a 57 minutes, 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)

C'est bien ce que je pensais avoir compris jusque-là.

Sauf que je n'avais pas encore compris que les variables des QA étaient en DB comme les VG. Même si une fois que cela est dit ça semble très logique :P

 

 

il y a 57 minutes, Lazer a dit :

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

Je considère cette remarque valable pour toutes les écritures, donc aussi bien les variables que les propriétés des modules ("value", etc).

Si tu regardes mes codes, tu verras que je m'applique à faire autant que possible une vérification de la valeur précédente, une comparaison, avant d"éventuellement stocker la nouvelle valeur si elle diffère. Cela permet d'afficher un petit message de log dans la console, cela réduit l'usure de la flash, les risques de plantage, et de façon assez intéressante, c'est plus rapide, bien que plus d'opérations soient impliquées. En effet, supposons que la variable/propriété ne change qu'une fois sur 10, alors 10 lecture et 1 écriture, c'est beaucoup plus rapide que 10 écritures seules.

C'est exactement aussi ce que je m'applique à coder. J'essaie autant que possible de vérifier une variable avant de la modifier pour rien.

Je préfère lire et décider d'agir, que d'agir par défaut :D

 

 

il y a 57 minutes, Lazer a dit :

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.

Il n'y a pas de raison de stocker une valeur pour la plaisir.

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

 

 

il y a 57 minutes, Lazer a dit :

Tu peux t'amuser à faire des petits benchmarks de performance, avec une petite boucle sur le modèle déjà partagé par @jang, pour écrire une VG, une Variable QA, un Label, etc... et la même chose en lecture... tu verras la différence flagrante de performance.

Alors quelques microsecondes c'est rien, mais sur un système lourdement chargé, avec des dizaines de QA qui tournent en boucle, ça finit par faire beaucoup.

Je suis bien d'accord avec toi. Ce n'est pas tant l'optimisation de la vitesse que je recherche, mais plus l'optimisation du code, peu importe la puissance du hardware qui le supporte.

En aparté, parlant de la philosophie d'optimisation du code pour un HW plus light, après avoir vécu des 25ans sous Windows à bidouiller des PC, c'est une des raisons (bonne ou mauvaise) qui m'a fait basculer sur MacBook il y a 2 ans. Un HW fait pour son SW. Et plus des HW surdimensionnés pour faire fonctionner un SW commun., même si évidemment tout n'est pas parfait chez Apple, surtout pour un ancien comme moi qui a grandi en assemblant ces ordinateurs et bidouillant Windows.

 

 

il y a 57 minutes, Lazer a dit :

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

Sans savoir pourquoi, je l'avais remarqué effectivement. Merci pour la précision.

 

 

il y a 43 minutes, jang a dit :

Add to this that the QuickApp:setVariable(name,value) looks something like this:

(...)

So, the quickAppVariables are stored in a linear list and the time to retrieve/store a variable depends on where in the list it is :o

I don't understand why they didn't used a hash table(!)

I hope that fibaro global variables are stored/retrieved more efficiently.

Thanks for your accurate technical addition.

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

 

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

Du coup afin de ne pas polluer les autres topics :D, et histoire de continuer la discussion démarrée ici à propos des variables, de leur impact, et possible appel depuis un autre QA.

 

Le 25/07/2021 à 13:06, Lazer a dit :

-- Cette fonction est membre de la classe QuickApp. Elle est donc automatiquement publiée et accessible depuis l extérieur du QA
function QuickApp:test()
	self:debug("hello")
end

-- Cette fonction est "globale" (par défaut), c'est à dire accessible dans tous les fichiers du QA :
function test(self)
	self:debug("hello")
end

-- Cette fonction est locale (car spécifié) donc accessible uniquement dans le fichier en cours (ou bloc de code en cours si la fonction a été définie à l'intérieur d'une autre fonction/boucle/etc) :
local function test(self)
	self:debug("hello")
end

 

 

 

Pour être sûr de bien comprendre :

 

#1 En écrivant cet exemple

local mavariable

function QuickApp:onInit()
	mavariable = "Hello"
end

function QuickApp:ModifyVariable(value)
	mavariable = value
end

- "mavariable" a une portée locale (à tout le fichier qui la contient), le code ne fait pas appel à la table super-globale _G durant son exécution

- elle ne peut pas être utilisée dans un autre fichier du QA qui la contient

- elle peut être modifiée depuis l'extérieure grâce à l'appel de la fonction ModifyVariable avec un paramètre

- performance exécution code théoriquement maxi

 

 

#2 En écrivant cet exemple

function QuickApp:onInit()
	self.mavariable = "Hello"
end

function QuickApp:ModifyVariable(value)
	self.mavariable = value
end

- "mavariable" a une portée locale (à tout le QA qui la contient), le code ne fait pas appel à la table "super-globale _G" durant son exécution

- elle est membre de la classe de ce QA et peut donc être utilisée dans tous les fichiers du QA qui la contient

- elle peut être modifiée depuis l'extérieure grâce à l'appel de la fonction ModifyVariable avec un paramètre

- performance exécution code théoriquement maxi

 

 

#3 En écrivant cet exemple

function QuickApp:onInit()
	mavariable = "Hello"
end

function QuickApp:ModifyVariable(value)
	mavariable = value
end

- "mavariable" a une portée globale, le code fait appel à la table "super-globale _G" durant son exécution

- elle n'est pas membre de la classe de ce QA mais peut être utilisée dans tous les fichiers du QA qui la contient

- elle peut être modifiée depuis l'extérieure grâce à l'appel de la fonction ModifyVariable avec un paramètre

- performance exécution code théoriquement moins bonne que #1 et #2 (tout dépend du référentiel d'exécution évidemment et de la taille du code)

 

 

Soyez indulgents, mais ai-je bon ? :unsure:

J'imagine bien que certaines subtilités m'ont probablement échappé, notamment quand je relis pour la dixième fois cette phrase "Elle est donc automatiquement publiée et accessible depuis l extérieur du QA". Mais j'essaie d'apprendre :)

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Dans l'ensemble, OUI.... mais je vais te reprendre sur 2 points :

 

Dans l'exemple #2 :

 

- "mavariable" a une portée locale (à tout le QA qui la contient), le code ne fait pas appel à la table "super-globale _G" durant son exécution => Il est incorrect de parler de portée, car mavariable est en réalité un élément de la table QuickApp. C'est là que le LUA est un peu étrange, et différent d'un vrai langage de programmation orienté objet (C++, Java, etc). QuickApp est donc une table, qui contient différents éléments : function, string, number, table, etc... La subtilité c'est que dans les fonctions, "self" pointe sur la table QuickApp elle-même, donc on a accès à tous les autres variables et fonctions de cette table, y compris notre fameuse mavariable. Du coup, par abus de langage, on dit que la portée de mavariable est celle de QuickApp, c'est à dire utilisable dans tous les fonctions membres de QuickApp.

 

- performance exécution code théoriquement maxi => en fait non pas du tout, car pour aller chercher mavariable, le programme va devoir parcourir la table QuickApp.... donc la performance est plus ou moins similaire à celle d'une variable globale qu'on va rechercher dans _G. En fait, pour savoir lequel des 2 est plus rapide, il faut compter le nombre d'éléments dans les tables _G et QuickApp.... du coup, ben ça dépend de chaque programme.

 

Après il ne faut pas non plus se focaliser sur cette histoire de performance d'accès aux variables, car c'est de l'ordre des nanosecondes (microseconde à tout casser), c'est inmesurable en pratique, sauf à avoir une boucle qui effectue un gros calcul et accès 1 millions de fois à la même variable.

C'est sans commune mesure avec les performances d'accès à la base de données, qui se compte en millisecondes.

 

Bien souvent quand on cherche à optimiser les performances d'un programme informatique, le gros des gains se fait sur l'algorithme utilisé, pas sur l'accès à telle ou telle variable. Et puis quand on cherche la performance maxi, on n'utilise pas du LUA (qui est déjà relativement rapide cela dit), mais plutôt du C... voire de l'assembleur. C'est un tout autre domaine, qu'on va rencontrer dans les moteurs de rendus 3D des jeux vidéos, le calcul scientifique, etc.

 

 

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)

 

  • Like 3

Partager ce message


Lien à poster
Partager sur d’autres sites

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:

Modifié par Fredmas

Partager ce message


Lien à poster
Partager sur d’autres sites

Oui, il vaut mieux prendre les bonnes habitudes dès le début :)

 

A noter qu'un code optimisé tout court ça n'existe pas. On optimise dans un but précis, par exemple la performance CPU, ou bien l'empreinte mémoire. Et parfois, un code plus rapide consomme plus de RAM. Et/ou devient illisible. Je me souviens avoir appris à une époque étudiante qu'un appel de fonction c'est relativement long (ça consomme des cycles CPU), et un code rapide utilise le moins de fonctions possible.... donc on se retrouve avec des bouts de codes répétés plusieurs fois par ci par là dans le code... ça devient illisible et inmaintenable, mais c'est rapide.

Ce qu'il faut trouver, c'est le juste milieu en fonction de l'effet recherché.

Nous ça va, on veux juste faire des QA pour afficher 2 ou 3 informations dans un cadre domotique, ça reste simple.

 

 

Tiens pendant que j'y pense en parlant performance et algorithme.

J'ai mon QA Événements (partagé sur le forum) qui est le plus consommateur de RAM et de CPU de ma box, juste pour afficher les 25 derniers événements. Je sais pourquoi, il manipule de grosses tables, plusieurs centaines d'éléments, et le LUA n'est pas très bien optimisé à ce petit jeu là. Pendant mes vacances, il s'est emballé, a consommé jusqu'à 150 Mo de RAM (là où la plupart des QA consomment autour de 1 Mo seulement), et plusieurs pourcents de CPU. La box n'a pas crashé, pas rebooté, elle a tué le QA, et ne l'a pas redémarré (alors qu'il y a normalement un watchdog qui surveille le redémarrage des QA plantés). Bravo Fibaro pour la stabilité et la robustesse de la box :)

Et pourtant dans ce QA, j'avais fait plein de micro-optimisations, notamment redéclarer toutes les variables et fonctions globales en local, etc.... mais c'était inutile en fin de compte, l'erreur était dans l'algorithme, la méthode que j'ai employé n'était pas la bonne (interrogation de l'API /events/history)

J'ai commencé la réécriture en utilisant une autre méthode (/api/refreshStates), et les premiers résultats sont très encourageants, ça semble consommer moins de CPU et moins de RAM. Combo gagnant. Et cerise sur le gâteau, au lieu d'avoir un intervalle de rafraichissement de 60s, il est maintenant de 1s seulement !
Comme quoi, il faut parfois prendre le problème par un autre bout, et tout recommencer à zéro quand ça ne va pas.

  • Like 1

Partager ce message


Lien à poster
Partager sur d’autres sites

Je ne sais pas si c’est ta passion pour le sujet, ton implication, ou ton altruisme, mais ta capacité à prendre le temps d’expliquer en profondeur ta pensée sur le sujet continue de me surprendre positivement ;)

  • Like 2

Partager ce message


Lien à poster
Partager sur d’autres sites

#4 Question 4 : définir correctement la méthode de débogage dans la console d'un QA

 

Cette fois, rien de bien compliqué, c'est davantage une question "café-philo" à propos des bonnes pratiques.

Après avoir lu le sujet rédigé par @Krikroff et du coup relu le manuel Quick Apps de Fibaro , il me reste quelques doutes quand au choix des différentes méthodes de de débogage dans la console d'un QA.

En fait je ne sais pas vraiment quand il vaut mieux utiliser "debug, "trace", "warning", "error" ou simplement "print".

Je crois avoir compris que la seule différence concerne l'identification et la recherche de messages dans la console via les filtres, mais je passe peut-être à côté de quelque chose ou simplement de bonnes pratiques.

 

Sans savoir l'expliquer, depuis le début que je code en LUA avec Fibaro (c'est à dire quelques mois seulement :D) j'ai pris l'habitude d'utiliser tout simplement des "print", mais peut-être n'est-ce pas le mieux dans un QA.

Et j'ai pris par exemple l'habitude de toujours mettre des "print" quand je vérifie des conditions dans mon QA qui tourne en boucle, afin de savoir quels tests sont en cours de vérification et savoir ceux qui tournent et ne tournent pas en boucle.

 

De votre côté, vous utilisez quoi ? principalement self:debug ? Ou avez-vous des règles de codage bien établies permettant de naviguer entre les différentes méthodes de débogage à disposition ?

Partager ce message


Lien à poster
Partager sur d’autres sites

print() c'est la fonction normale en LUA pour afficher un message à l'écran.

Dans un QA, Fibaro l'intercepte et réalise la même chose que self:debug(), donc elle affiche un message de niveau "DEBUG" dans la console.

Les 3 autres niveaux TRACE WARNING et ERROR permettent de classer les messages par ordre d'importance, de criticité, de l'attention que devrait leur porter l'administrateur (donc toi)

 

DEBUG : message informatif, sans importance autre que d'informer d'une action, afficher un message permettant de débugguer, etc

TRACE : message un peu plus important qui peut potentiellement donner une information utile : par exemple je l'utilise quand je notifie le changement d'état d'un QA (modification de la propriété "value", etc)

WARNING : avertissement, il se passe quelque chose d'important

ERROR : attention, là c'est plus grave, quelque chose n'a pas fonctionné. Exemple : la connexion réseau vers un appareil externe a échoué

 

Tu remarqueras que les crashs de ton code LUA son affichés avec un niveau ERROR.

 

La console de log permet de filtrer les messages, donc on peut visualiser d'un coup d'oeil toutes les erreurs et agir en conséquence.


C'est vraiment pratique, et une grosse évolution par rapport à la HC2.

 

Personnellement, je n'utilise jamais print(), sauf pour tester un bout de code à la va-vite.

Je n'utilise même plus les self:debug() ... trace, warning, error() car j'ai ma propre librairie tools qui s'utilise de la même façon, mais présente entre autres avantages de colorer les messages (avec des balises HTML), pour une visualisation entre plus claire dans la console de log.

La syntaxe est la même : tools:debug(), etc, donc ça ne modifie pas vraiment mon code LUA (et j'ai paramétré la coloration syntaxique dans mon éditeur Notepad++ pour que ça soit encore plus lisible pour moi)

Autre avantage de tools, c'est quelle est utilisable partout dans mes codes LUA, même dans les fonctions qui ne sont pas membres de QuickApp (et qui ne connaissent donc pas self)

Tous mes QuickApps utilisent ce principe (sauf les tous premiers partagés il y a plus d'un an)

  • Like 2

Partager ce message


Lien à poster
Partager sur d’autres sites

Merci @Lazer ;)

Je comprends tes différents niveaux d'importance. Histoire de faire propre, je prendrai le temps de formater correctement mes "print" et autres "debug" dans mes QA ;)

 

Bien que je l'ai peut-être déjà lu quelque part et oublié ensuite, tu éveilles ma curiosité avec ton "tools" :D Est-il partagé et trouvable dans le forum ? :unsure:

Partager ce message


Lien à poster
Partager sur d’autres sites

Oui comme je le disais, tools est intégré dans tous mes QuickApps

 

Tu trouveras le fichier dans le tuto sur GEA par exemple :

 

 

Je n'ai jamais fait de tuto spécifique pour mes tools, cela dit la plupart des fonctions ont un en-tête avec la syntaxe pour l'utiliser.

  • Like 1

Partager ce message


Lien à poster
Partager sur d’autres sites

Je viens de télécharger ton fichier "tools : Library - tools v2.12.lua" et l'ouvrir dans un Note histoire de voir :P

Mais oh punaise, je ne m'attendais pas à avoir autant de lignes à ligne et déchiffrer :2:

Mais c'est bien, ça me renvoie à mon niveau et le reste à apprendre pour progresser :lol:

Partager ce message


Lien à poster
Partager sur d’autres sites

Tu n'as pas besoin de comprendre comment ça fonctionne pour utiliser tools, tout l'intérêt d'une librairie comme ça c'est justement de se simplifier la vie : réutiliser des bouts de codes fonctionnels.

 

Après, c'est sûr, pour apprendre, progresser, s'occuper l'esprit, c'est mieux d'étudier en détail le fonctionnement.

 

Mais bon... ce n'est pas du code très évolué.... très loin de ce que peut produire @jang dans ses librairies partagées sur le forum Fibaro officiel.

Partager ce message


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

Tu n'as pas besoin de comprendre comment ça fonctionne pour utiliser tools, tout l'intérêt d'une librairie comme ça c'est justement de se simplifier la vie : réutiliser des bouts de codes fonctionnels.

Tu as raisons, mais je ne saurais même pas comment l'utiliser pour l'instant... J'aime comprendre, j'adore en fait (mais ça tu l'as bien compris depuis le temps), mais je fais aussi confiance tant que je sais comment m'en servir :2:

Comme tu le dirais mieux que moi, je pense toujours à la maintenance en cas de problème...

 

il y a 3 minutes, Lazer a dit :

Après, c'est sûr, pour apprendre, progresser, s'occuper l'esprit, c'est mieux d'étudier en détail le fonctionnement.

:D oui c'est un peu un passe-temps entre 2 bricolages de rénovation :D

 

il y a 3 minutes, Lazer a dit :

Mais bon... ce n'est pas du code très évolué.... très loin de ce que peut produire @jang dans ses librairies partagées sur le forum Fibaro officiel.

Ca je ne sais pas, mais déjà ce que je lis de ton "tools" est bien plus évolué que mes pauvres petits  if, then, else, end...

Mais bon, partant uniquement des modes blocs HCL depuis fin 2014, déjà je n'ai plus de variables "persistantes" (au sens onglet variables box), quasiment plus aucunes scènes et que des QA... donc j'avance petit à petit grâce à vous et mes heures de lecture... :unsure:

 

 

 

Partager ce message


Lien à poster
Partager sur d’autres sites

Pour l'utiliser c'est facile, il suffit de copier/coller le contenu dans un fichier tools d'un QuickApp (ou bien directement dans le fichier main, mais c'est moins propre... on a maintenant la possibilité d'avoir plusieurs fichiers dans les QA, autant s'en servir)

 

Ainsi toutes les fonctions de tools seront accessibles n'importe où dans ton code LUA (depuis le fichier main ou n'importe quel autre fichier)... car tools est une variable de type table avec une portée globale.

 

Ensuite dans ton code LUA tu peux afficher un texte en couleur de cette façon :

tools:debug("Texte coloré en vert")

Ou bien :

tools:error("Texte coloré en rouge")

Mieux encore :

tools:print("blue", "Texte de niveau DEBUG coloré en bleu")

Avec tools:print() tu peux utiliser n'importe quelle couleur prédéfinie en HTML (chercher la liste sur Google)

Je m'en sert beaucoup dans mes QA quand j'ai beaucoup d'informations à afficher, les couleurs permettent de distinguer facilement les messages avec nos yeux d'humains sur un écran rempli de texte.

 

Une fonction bien pratique aussi pour déboguer et afficher sous forme d'arborescence le contenu d'une table :

local ma_table = {"blah", "pouf", truc = {"machine", "chose", bidule = {1,2}}}
tools:deepPrint(ma_table)

 

Après tu peux parcourir la liste des fonctions dans tools, il y en a de différentes sortes : manipulation des labels, sliders, variables QA et globales, urlencode & base64, split, etc... et même gestion des modules enfants et de leurs interfaces.

Partager ce message


Lien à poster
Partager sur d’autres sites

Moi aussi j'ai des fichiers tools dans chacun de mes QA.
J'ai quelques fonctions "empruntées" à Lazer dedans....
Petite question justement : est-il possible d'avoir un fichier master-tools qui serait copié automatiquement dans tous les QA qui en ont besoin ? On pourrait mettre à jour certaines fonctions en central...

Envoyé de mon RMX1993 en utilisant Tapatalk

Partager ce message


Lien à poster
Partager sur d’autres sites

ça a déjà été discuté avec @jjacques68 et une astuce donnée par @jang pour importer / mettre à jour automatiquement un fichier dans les QA.
 

Mais perso je ne suis pas fan du tout, car ça empêche de partager facilement ses QA sur le forum (à cause des dépendances, le QA n'est plus autonome).

Et une mise à jour du fichier pourrait très bien casser la compatibilité avec tous les QA existants. En effet, une évolution d'une fonction de la librairie pourrait par exemple prendre des arguments différents ou retourner des valeurs différentes et faire planter un QA qui utilisait une précédente version.

 

Après si vous êtes rigoureux, dans le principe la solution est bonne.

 

@jjacques68 avait fait un tuto :

 

 

Partager ce message


Lien à poster
Partager sur d’autres sites

×