Aller au contenu

QA Réveil - conseils


jjacques68

Messages recommandés

Hello tout le monde, 

 

Petite question de bon sens... avant de me lancer dans de longues heures de codage et tout recommencer :) 

 

Actuellement, j'ai 2 scènes qui me gère mes lampes de chevet (gauche et droite) pour simuler le réveil.

Ce qui est bête c'est que ce sont 2 scènes exactement identiques !

Y a juste l'ID du dimmer qui change !!!

J'ai un QA type générique qui me permet d'activer/désavtiver les scènes et de régler l'heure.

Celle-ci est stockée dans une VG spécifique à chaque réveil (gauche et droite).

On est complement dans l'esprit de la HC2 :( 

 

Donc l'idée serait de créer un QA Parent avec 2 Child (une pour chaque lumière)

Ces Child serait de type binarySwitch, pour activer/désactiver le réveil - logique... :)

 

Le soucis va être le réglage de l'heure de chacun !

Le QA parent aura toujours un IHM pour effectuer ces réglages.

 

MAIS où stocker l'information ????

 

dans une VG ? :( 

dans une VG du QA Child ?

dans une VG du QA Parent ?

 

Dans le cas des VG QA, je ne pourrais pas récupérer ce paramètre depuis un autre QA :( (du moins facilement...)

Nécessaire afin de mettre en place le trigger (ça c'est un autre sujet).

 

Le top aurait été de pouvoir créé un QA Child de plus pour lui donner l'heure de réglage comme value "07:00"...

Mais c'est pas possible ça...

A moins de prendre un multiLevelSensor et de stocker non pas l'heure sous la forme "07:00" mais sous la forme d'un nombre entier !

mais c'est un peu bof comme méthode... Mais là je pourrais interroger l'heure depuis n'importe où !

 

Si vous avez de meilleurs idées ?!

 

merci pour vos conseils !!! :) 

 

 

Lien vers le commentaire
Partager sur d’autres sites

ça ressemble sacrément à ce que je vais faire pour le QA Alarm de GEA (transposition du VD)

 

Dans un QA, on ne peut plus stocker d'information dans les Labels car l'info n'est plus persistante, donc les labels sont utilisables uniquement pour afficher l'information
Donc je pense qu'il faut stocker l'information dans une variable du QuickApp (chaque Child), car elle est persistante (stockée dans son JSON).

 

Après ce qui est pénible c'est qu'on ne puisse pas personnaliser l'IHM des QA enfants.... y ajouter des labels et boutons serait pratique.

 

Je ne comprend pas pourquoi tu dis qu'on ne peut pas lire une variable dans un QA.

Il suffit d'aller chercher.... dans le JSON du module justement !

Je me suis fait une petite fonction dans ma librairie tools, on peut obtenir la variable dans self, un child, ou bien n'importe quel QA en donnant juste son ID sous forme numérique.

Cerise sur le gâteau, on n'a pas de message d'avertissement disgracieux dans la console si la variable n'existe pas. Dans ce cas, au lieu de récupérer une variable contenant "" (une chaine vide), on obtient nil, ce qui est quand même plus parlant :

--
-- Get variable silently without showing warning message in case variable does not exist
--
-- Usage :
-- local mavariable = tools.getVariable(self, "debug")
-- local mavariable = tools.getVariable(child, "debug")
-- local mavariable = tools.getVariable(1234, "debug")
--
function tools:getVariable(variable)
	local id = type(self) == "userdata" and self ~= tools and self.id or type(self) == "number" and self > 0 and self
	if id then
		if type(variable) == "string" and name ~= "" then
			local device
			if type(self) == "userdata" then
				device = self
			else
				device = api.get('/devices/' .. tostring(id))
			end
			if device then
				if type(device.properties) == "table" and type(device.properties.quickAppVariables) == "table" then
					for _, v in ipairs(device.properties.quickAppVariables) do
						if v.name == variable then
							return v.value
						end
					end
				else
					tools:warning("tools:getVariable() : can't find any QuickApp variable")
				end
			else
				tools:error("tools:getVariable() : can't find device", type(self), tostring(self))
			end
		else
			tools:error("tools:getVariable() : invalid variable name :", type(variable), tostring(variable))
		end
	else
		tools:error("tools:getVariable() : invalid self device :", type(self), tostring(self))
	end
end

 

 

 

Lien vers le commentaire
Partager sur d’autres sites

il y a 48 minutes, Lazer a dit :

e ne comprend pas pourquoi tu dis qu'on ne peut pas lire une variable dans un QA.

si ! je sais qu'on peut, mais c'est pas "simple"...

 

après pourquoi pas utilisé l'option "fichier" des QA, qui permet de partager des fonctions...

Il faudrait alors juste créer une fonction qui renvoie la variable locale au QA qui partage sa fonction.

avec un simple :

function QuickApp:ReturnVG(MaVg)

	return self:getVariable(MaVg)

end

Mais bon...

Faut partager le fichier, l'inclure dans le QA qui a besoin de cette ressource...

Y a moins de ligne de code que ta solution, 

Mais c'est pas plus "simple" non plus !

Mais c'est pas bête ! nan ?

Lien vers le commentaire
Partager sur d’autres sites

pas simple ?

Pour un enfant c'est exactement la même méthode que pour le parent, en 1 seule ligne, je ne vois pas où est la difficulté ? Tu y mets de la mauvaise volonté là :P

child:getVariable("mavariable")

Ma fonction est un peu longue car elle effectue des vérifications, affiche des messages d'erreurs, permet d'obtenir la variable de n'importe quel module, bref elle se veut juste générique, et c'est pour cela que je l'ai incluse dans ma librairie d'outils, ainsi je peux l'utiliser dans n'importe quel QuickApp, simplement en 1 seule ligne (comme la commande Fibaro officielle)

 

 

Je trouve que la méthode que tu proposes avec fichiers bien lourde, complexe à maintenir, et qui détourne totalement l'usage prévu des fichiers.

Bref, c'est sale.

 


Je ne comprend vraiment pas ce qui te déplait dans les variables de Quickapp ? C'est typiquement fait pour cet usage.

1 seule ligne de code LUA, simple, efficace, portable, pérenne.

 

 

Parfois faut pas chercher la complication, juste utiliser les outils mis à notre disposition par Fibaro.

 

Ah oui et aussi, faut arrêter de raisonner "HC2", comme tu t'en es rendu compte.

On oublie les Variables Globales, il n'y a plus beaucoup de cas de figure où on a encore besoin des VG à vrai dire.

Même pour gérer le statut de la maison (présent, absence, nuit, vacances, etc) on n'en a plus besoin, les profils font tout cela et bien plus (mais c'est un autre sujet)

Lien vers le commentaire
Partager sur d’autres sites

il y a 19 minutes, Lazer a dit :

et c'est pour cela que je l'ai incluse dans ma librairie d'outils

cette librairie d'outil est un bien un partage de fichier entre QA ? non ?

où tu copies/colles la fonction ?

 

Citation

Je ne comprend vraiment pas ce qui te déplait dans les variables de Quickapp ? C'est typiquement fait pour cet usage.

on s'est mal compris, je n'utilise pas les VG !

mais bien les variable des quickapp que j'appelle "VG Quickapp"..;

 

il y a 19 minutes, Lazer a dit :

On oublie les Variables Globales, il n'y a plus beaucoup de cas de figure où on a encore besoin des VG à vrai dire.

 

ben justement actuellement, j'en ai 3

2 qui stockent l'heure, justement pour chaque réveil

et 1 pour le backup auto.

alors que sur la HC2, j'en avais des dizaines !

 

Citation

et qui détourne totalement l'usage prévu des fichiers.

alors là, j'ai vraiment pas compris l'intérêt de partager des fonctions entre quickapp !!

Modifié par jjacques68
Lien vers le commentaire
Partager sur d’autres sites

Les fichiers des QuickApp permettent de découper son code.... en plusieurs fichiers !

Exactement comme on le ferait avec n'importe quel langage de programmation, allant du C jusqu'au PHP

 

L'idée, c'est plutôt que d'avoir un seul fichier monolithique de plusieurs milliers de lignes, on a plusieurs petits fichiers dans lesquels il est facile de retrouver la fonction recherchée.

 

Après pour l'organisation, c'est à l'appréciation de chacun, mais perso ce que j'aime bien faire pour les QuickApp :

- main : le code de QuickApp lui-même, c'est à dire toutes les fonctions qui appartiennent à la classe QuickApp, donc sont accessibles par l'utilisateur au travers de l'API fibaro.call(). On va retrouver la gestion de actions, des boutons, etc

- tools : ma librairie d'outils avec pleins de fonctions utiles dans mes différents codes, et qui manquent dans le LUA natif proposé par Fibaro ("print" améliorés avec des couleurs, createChild amélioré, getVariable amélioré, createVG, Wake-on-LAN, round(), split(), base64(), log(), getView(), etc ...)

- notification : pour envoyer des notifcations (Push, SMS, etc)

- config : pour que l'utilisateur y stocke ses paramètres (s'ils sont trop nombreux pour tenir dans les variables du QA, comme par exemple GEA, Network Monitor, etc... et prochainement IPX800v4/EDRT2)

- XXX : celui là est dépendant du QA, il contient le cœur du QA, c'est à dire toutes les fonctions spécifiques au QA. Donc ça va être SNMP pour l'onduleur Eaton, ou bien KODI pour gérer l'API Kodi, etc

 

Dans cette liste, certains fichiers (notification, tools) vont se retrouver dans plusieurs QA différents, il me suffit de faire un copier/coller pour en bénéficier automatiquement, facile, rien à intégrer dans le code "main", c'est un fichier à part.

Note : je n'utilise pas la méthode de recopie automatique des fichiers proposée par @jang, personnellement je n'aime pas ce genre d'automatisme, une nouvelle version de ma librairie tools pourrait casser la compatibilité avec l'existant et rendre inopérant toute une tripotée de QA existants. (pour des raisons un peu similaires, je n'utilise jamais, ou rarement, la dernière version des logiciels, aussi bien sur mon PC, que mon Smartphone, ou bien ma box domotique... je préfère faire les mises à jour manuellement en cliquant sur un bouton, avec un décalage, je n'ai pas envie d'avoir la primeur des nouveaux bugs qui s'installent automatiquement)

 

Lien vers le commentaire
Partager sur d’autres sites

interessant, mais lors des modifications, tu dois te taper tous les QA où tu utilises ces fonctions !!!

 

pour ma culture, je ne comprends absolument pas cette ligne de code ???

y a eu un loupé dans le copier/coller ?

local id = type(self) == "userdata" and self ~= tools and self.id or type(self) == "number" and self > 0 and self

 

Lien vers le commentaire
Partager sur d’autres sites

Pas besoin de me retaper les QA, puisqu'ils fonctionnent avec l'ancienne librairie tools

Si par contre je souhaite reprendre le QA pour lui apporter des nouvelles possibilités, améliorations, corrections de bugs, etc, alors là c'est l'occasion de lui "installer" la nouvelle librairie.

 

Cette ligne de code est une astuce pour récupérer l'ID du module passé en paramètre (variable self implicite correspondant au 1er paramètre lors de l'appel de la fonction)

- SI type(self) == "userdata" (c'est à dire le quickapp lui-même ou l'un de ses enfants) ET que ce n'est pas tools lui-même (test inutile car en pratique tools est de type "table") ALORS on renvoie self.id

- SI type(self) == "number" ET qu'il est positif (on ne sait jamais, dès fois qu'un ID négatif se perde par là), ALORS on renvoie directement le nombre lui-même (contenu dans self)

 

Dans les commentaires je t'ai justement mis la façon de l'utiliser.

 

 

Cette astuce, je l'utilise dans plusieurs de mes fonctions de cette librairie tools, c'est hyper pratique à l'usage, je peux faire ce que je veux sur un module, qu'il soit self, child, ou un ID quelconque.

Tu verras tools 2.0 quand je le partagerai dans IPX800/EDRT, mais la version 1 a déjà été partagée dans des QA (Kodi, Surv Station, ...)

Lien vers le commentaire
Partager sur d’autres sites

Ah OK, c'est de l'optimisation de code LUA en une seule ligne avec uniquement des AND et OR, sans utiliser le lourd if .... then ... end

Donc rien à avoir avec Fibaro, QuickApp, etc.... c'est du LUA pur et dur

 

Mais cela rend le code moins compréhensible quand on n'a pas l'habitude

 

Un peu dans l'esprit de ce qui est présenté dans ce mini benchmark (test n°5) : https://springrts.com/wiki/Lua_Performance#TEST_5:_Nil_Checks_.28.27if.27_vs._.27or.27.29

Lien vers le commentaire
Partager sur d’autres sites

Cela sera peut être plus clair ainsi, avec les parenthèses :

local id = (type(self) == "userdata" and self ~= tools and self.id) or (type(self) == "number" and self > 0 and self)

Ou bien en syntaxe traditionnelle :

local id
if type(self) == "userdata" and self ~= tools then
	id = self.id
elseif type(self) == "number" and self > 0 then
	id = self
end

 

Lien vers le commentaire
Partager sur d’autres sites

oh punaise j'y étais pas du tout :) 

merci !!

 

Je viens de regarder vite fait ton QA KODI, 

 

En fait j'avais pas du tout pensé à cette manière utiliser les "fichiers".

C'est de la bombe !!

 

Je me permets

 

pour commences tu tes librairies avec tools = {} ou encore KODI = {}

C'est obligatoire ?

Lien vers le commentaire
Partager sur d’autres sites

Oui il faut le déclarer en tant que table {}, avant de pouvoir y ajouter des functions(), ou n'importe quel autre variable de type string, number, boolean, etc

 

Là encore, c'est du LUA pur, j'en usais largement dans mes VD sur HC2.
Et pour tout dire, je me suis inspiré à l'époque des codes des maitres @Krikroff et @Steven

 

Le LUA a ceci de génial que tout est "rangé" dans une table.

Mêmes les variables dont la portée est globale (le cas de tools qui nous intéresse, mais aussi QuickApp.... et absolument toutes les fonctions qu'on utilise (fibaro.*, math.*, json.*, etc) font en réalité partie d'un super tableau appelé _G dont l'appel est implicite.

 

Voir à ce sujet ma petite exploration (j'ai découvert après coup que @jang avait partagé un code tout à fait similaire sur le forum officiel.... promis cette fois-ci je n'ai pas copié)

 

Lien vers le commentaire
Partager sur d’autres sites

En fait, QuickApp, tools, KODI, etc.... ce sont tous des tables contenant des fonctions, et leur utilisation permet de faire de la programmation orientée objet.

Même si ce n'est pas de la vraie POO au sens C++ du terme, cela s'en approche pas mal.

 

Par exemple, ma pseudo classe SNMP utilisée pour l'onduleur (en réalité une table avec des variables et des fonctions) a été portée en un temps record sur la HC3, il m'a juste suffit de modifier les appels aux fonctions propriétaires (sockets UDP), et la classe entière devenant utilisable comme par magie dans un QuickApp.

 

Pour GEA j'ai poussé le concept plus loin encore, puisque j'utilise le mécanisme de "class" proposé par Fibaro et qu'on utilise pour les QA enfants.

Je l'ai adapté à GEA, j'en ai fait une classe, ce qui me permet d'en instancier 2 objets, avec chacune leur constructeur (la fonction __init()), et leur espace mémoire propre et bien distinct.

Pour le coup cela devient propriétaire car le mécanisme de class proposé par Fibaro est spécifique à la HC3. Mais l'esprit est totalement dans le style POO.

Lien vers le commentaire
Partager sur d’autres sites

oui la tu vas trop vite pour moi :) 

Je viens juste de comprendre que tout était rangé dans des tableaux, 

Je me rends compte que moi-même il m'arrive de faire des tableaux de fonctions, mais ça s'arrête là...

Je découvre cette manière de coder.

C'est un vrai état d'esprit !

on sort du codage conventionnel, séquentiel, procédural, ...

Faut s'y faire...

 

 

Lien vers le commentaire
Partager sur d’autres sites

je développe énormément sous Windev au boulo...

Qui est un "langage" si je peux dire ainsi, très très très très évolué.

La POO est tout à fait réalisable avec, mais j'avoue resté à "l'ancienne".

En même temps, leur système de base de données intégré (= HFSQL qui fonctionne à merveille) ne nous pousse pas à faire de la POO...

Même pour des très gros projet, ça passe tout seul.

Après je développe des applications. Pas des applications, pour créer des applications :) Là la POO serait plus que obligatoire...

Lien vers le commentaire
Partager sur d’autres sites

j'ai relu plusieurs fois cette discussion... c'est vachement intéressant !!

Il y a 12 heures, Lazer a dit :

Après pour l'organisation, c'est à l'appréciation de chacun, mais perso ce que j'aime bien faire pour les QuickApp :

[...]

- notification : pour envoyer des notifcations (Push, SMS, etc)

c'est marrant justement, pour les notifications, moi j'ai un QA spécifique.

Avec tout dedans (Push, Mail, TTS, Prowl)

Pour envoyer une notification je fais appel à une méthode de ce QA avec par exemple :

fibaro.call(ID_QA, "sendPush", "blablabla")

ça fonctionne très bien.

 

Mais la question se pose :

est-il plus efficace (performance, réactivité, maintenabilité, ...) d'appeler une méthode d'un QA ou d'intégrer le code dans d'envoi dans un fichier comme tu le fais ?

Lien vers le commentaire
Partager sur d’autres sites

Performance : il est plus rapide d'appeler une fonction dans le QuickApp lui-même que dans un autre QuickApp (car cela va alors passer par l'API, communication entre processus différents, etc.... opérations relativement lourde)

Mais il faut relativiser, ce serait un problème si tu envoyais 10 notifications par seconde.

En pratique, des notifications, c'est de l'ordre de quelques unes par jour... donc il n'y a aucune souci de performance en pratique.

 

Ce qui nous amène à la maintenabilité, et c'est bien là le plus important.

Organiser son code LUA dans des fonctions dans des "objets" dans fichiers dans des QuickApps dans la box domotique :D

L'essentiel est de s'y retrouver, de pouvoir facilement utiliser un bout de code nécessaire entre plusieurs QuickApps, etc.

Je ne sais pas s'il y a une meilleure façon de faire.

 

Mon objet de notifications, tu peux le voir dans quelques QuickApps (Network Monitor, Onduleur Eaton, etc), j'ai préféré la copier/coller.

Elle me sert à uniformiser l'envoie d'email, notification push, etc. dans mes différents codes. Et je ne dépend pas d'un QuickApp externe (dont l'ID pourrait changer) pour envoyer des notifications aussi basiques que email et push

Mais pour l'envoi des SMS, elle se base elle même sur un QuickApp dédié, pour JPI. Car j'ai considéré que JPI étant une application externe sur un smartphone externe, cela nécessité un QuickApp dédié. Et facilement partageable en plus, un QuickApp utilisable par tous en tant qu'outil prêt à l'emploi.

 

Lien vers le commentaire
Partager sur d’autres sites

Ce sujet de l'ID qui change est un problème chez Fibaro.

Il manque toujours un truc sur la HC3, c'est la possibilité de se réaliser une vraie librairie d'outils partageables entre tous les QA.

Difficile à stocker ça dans un QA quand tu sais que tu es lié à son ID.... qu'on ne peut pas choisir !

Il faudrait pouvoir nommer les QA (ou scènes) de manière unique pour les appeler sans ambuiguité depuis n'importe quel code LUA.

 

L'ID on ne le choisit pas (et il change si on exporte/importe le module)

Et le nom n'est pas unique car plusieurs QA peuvent porter le même nom.

 

Il manque aussi un autre élément fondamental, c'est la possibilité de récupérer la valeur de retour d'une méthode appelée dans un autre QA.

Là encore, @jang a proposé une solution, mais que je trouve un peu lourde, j'aurais préféré un truc prévu en standard par Fibaro, plus facilement maintenable.

 

 

Donc en attendant, on organise notre code avec les fichiers, et l'appel de méthodes avec paramètres entre QA, c'est déjà un gros progrès par rapport à la HC2.

Lien vers le commentaire
Partager sur d’autres sites

Shared code/modules are an interesting topic. It would be nice if the community could agree about a "module" format that made it easy to use each other's modules without polluting the Lua global namespace too much...

https://forum.fibaro.com/topic/49113-hc3-quickapps-coding-tips-and-tricks/?do=findComment&comment=223070

 

  • Like 1
Lien vers le commentaire
Partager sur d’autres sites

Je me suis rendu compte pendant mes essais, que commencer un fichier avec 

class 'WAKEUP' (QuickAppChild)

function WAKEUP:MyFunction()
[...]
end

avait visiblement le même effet que si j'avais fait 

WAKEUP = {}

function WAKEUP:MyFunction()
[...]
end

Dans les 2 cas, Les fonctions sont accessibles dans le main en faisant :

WAKEUP:MyFunction()

C'est normal ça ??

est-ce la même chose ?

 

D'ailleurs visiblement, on est pas obligé d'utilisé une class ou un tableau de fonctions dans un fichier !

On peut simplement y déplacer des fonctions du main !

Ce que j'ai fait pour le code des actions sur les boutons. Histoire de pas polluer le code dans le main...

ça permet de ranger un peu la structure du code...


Ne suis-je pas encore entrain de détourner son l'utilisation ?

 

ça reste encore un peu obscure tout ça... il manque une sorte de représentation graphique de la structure d'un QA...

Ce qui aiderait à mieux comprendre je pense.

Bien que la petite phrase de @Lazer :

Citation

Le LUA a ceci de génial que tout est "rangé" dans une table.

a résonné tout la journée dans la tête et m'a ouvert pas mal les yeux :) 

 

@jang : I have read your link more and more. I don't understand anymore with the "shared" :) sorry, it's too strange for me :) 

Modifié par jjacques68
Lien vers le commentaire
Partager sur d’autres sites

×
×
  • Créer...