Inkew Posté(e) le 31 août 2021 Signaler Posté(e) le 31 août 2021 Bonjour, Je souhaite créer un QA qui me calcule la moyenne glissante des températures (d'un périphérique ZWave ou QA Netatmo) sur les 5 derniers jours. Est-ce que quelqu'un aurait une idée de comment procéder?
Lazer Posté(e) le 31 août 2021 Signaler Posté(e) le 31 août 2021 Une boucle infinie, avec une table suffisamment grande pour stocker l'historique des mesures sur 5 jours. Par exemple chaque minute sur 5 jours ça fait : 60*24*5 = 7200 éléments dans le tableau, rien de méchant. Puis avec une petite boucle for tu additionnes toutes les valeurs, tu divises par le nombre d'éléments. A chaque passage dans la boucle infinie, il faut faire un table.insert() pour ajouter la nouvelle valeur, et faire un table.delete() si l'historique dépasse 7200 valeurs.
jang Posté(e) le 31 août 2021 Signaler Posté(e) le 31 août 2021 Not exactly a moving average but still "smoothing" out the value can be achieved by subtracting the average... no buffer needed. function smoothFilter(size) local sum,n,average=0,0 return function(x) sum,n=sum+x,n+1 average = sum/n if n >= size then sum,n=sum-average,n-1 end return average end end local filter = smoothFilter(40) for i=1,10000 do print(filter(math.random(1,500))) end 1
Inkew Posté(e) le 1 septembre 2021 Auteur Signaler Posté(e) le 1 septembre 2021 Bonjour, Je n'ai pas du tout un gros niveau en lua, mais je comprend le principe. Une question cependant : est-ce qu'une table dans un QA est sauvegardée en dehors de ce QA (en gros si la HC3 s'éteint par exemple, est-ce que cette table est toujours accessible par ce QA?) Savez-vous où je peux trouver de la doc pour la manipulation de ces tables en lua? Merci!
Lazer Posté(e) le 1 septembre 2021 Signaler Posté(e) le 1 septembre 2021 La table c'est une variable en RAM, donc non elle n'est pas sauvegardée lors du redémarrage du QA, comme tout programme informatique en fait. On pourrait imaginer sauvegarder cette table dans une variable du QA (donc stocké dans la base de données de la HC3), mais je ne te le conseille pas du tout (impact sur les performances, usure de la mémoire flash) La solution de @jang est élégante, mais ce n'est pas une vraie moyenne glissante comme tu le voulais, et elle ne résout pas non plus le problème du redémarrage du QA. Après là tu as plusieurs notions à prendre en compte : - du LUA pur, mais c'est un faux problème car la manipulation des tables est hyper simple (je t'ai donné les 2 fonctions à utiliser) , donc on en revient à un principe de programmation en général (du coup est-ce que tu es à l'aise sur un autre langage, car tout ceci n'est que de l'algorithme) - des mathématiques.... c'est à dire comment calculer une moyenne glissante - le QA en particulier, et la façon que Fibaro propose pour mémoriser des données de façon persistante Pour ce dernier point, comme dit plus haut, je ne te conseille pas du tout de mémoriser la table complète à chaque passage dans la boucle. De toute façon le QA va calculer sa moyenne glissante via sa table en mémoire vive, et mettre à jour sa propriété "value", puisque ton QA aura comme type "com.fibaro.temperaturesensor" je suppose. Du coup, en cas de redémarrage du QA, dans le onInit() je relirais la valeur courante de la value (puisque celle-ci est bien persistante), et je m'en servirait pour initialiser ma table de 7200 valeurs. Je trouve que c'est un moyen simple et efficace de résoudre la problème du redémarrage du QA.
Inkew Posté(e) le 1 septembre 2021 Auteur Signaler Posté(e) le 1 septembre 2021 Merci pour ton retour, je pense avoir compris la méthode. Non je ne suis pas très à l'aise avec la programmation, mais je vais me tester. Je reviendrai sur ce forum si je coince quelque part. Merci encore pour tes éclairages.
Inkew Posté(e) le 1 septembre 2021 Auteur Signaler Posté(e) le 1 septembre 2021 Bon, j'ai essayé mais je sèche sur plusieurs choses. La première est que je découvre que la table est vide dans ma fonction loop. Visiblement la variable TempMoy également. Ensuite, je ne sais pas comment m'y prendre ni pour extraire les valeurs de la table et calculer leur moyenne, ni pour connaitre le nombre d'entrées de cette table, ni pour supprimer première ligne.. function QuickApp:onInit() self:debug("onInit") local TempMoy, TempMoyGliss, i local Table = {}; TempMoy = fibaro.getValue(309, "value") for i = 1, 10 do table.insert(Table, TempMoy) end self:debug(json.encode(Table)) self:loop("Calcul_Temp_Moy_Gliss") end function QuickApp:loop(text) self:debug("Text from loop: ", text) fibaro.sleep(3000) --table.insert self:debug(json.encode(Table)) self.updateProperty("value", TempMoy) self:loop(text) end Un peu d'aide serait bienvenu!!!
Lazer Posté(e) le 1 septembre 2021 Signaler Posté(e) le 1 septembre 2021 C'est un bon début Alors c'est normal, car tu as déclaré tes variables en local, donc elles ne sont connues que dans la fonction onInit(), mais pas dans loop() Voir : Ensuite, il ne faut surtout pas utiliser sleep(), ça va bloquer ton QA, donc mener à un plantage de celui-ci, voire à un reboot de la box. Il faut utiliser setTimeout() C'est de l'asynchronisme, un mécanisme pas évident à comprendre.... Voir ici : Ce que tu peux faire, c'est affecter tes variables à self (l'objet qui désigne le QuickApp en mémoire), ainsi tu peux utiliser les variables dans toutes les fonctions du QA. Pour accéder à un élément particulier d'une table, il faut utiliser les crochets, et le dièse pour compter le nombre d'éléments de la table : for i=1, #Table do print(Table[i]) end ce qui devrait donner un truc dans le genre (non testé, à affiner, mais ça te donne une base de travail) : function QuickApp:onInit() self:debug("onInit") local tempOld = self.properties.value self.Table = {} for i = 1, 10 do table.insert(self.Table, tempOld) end self:debug(json.encode(self.Table)) fibaro.setTimeout(0, function() loop() end) -- on lance la boucle end function QuickApp:loop() self:debug("loop !") table.remove(self.Table, 1) local newValue = fibaro.getValue(123, "value") -- il s'agit de l'ID de ton module température Z-Wave ou Netatmo table.insert(self.Table, newValue) self:debug(json.encode(self.Table)) local tempSum = 0 for i = 1, #self.Table do tempSum = tempSum + self.Table[i] end local tempMoy = tempSum / #self.Table self:debug("Nouvelle moyenne :", tempMoy) self.updateProperty("value", tempMoy) fibaro.setTimeout(3000, function() loop() end) -- prochaine boucle dans 3 secondes end
Inkew Posté(e) le 1 septembre 2021 Auteur Signaler Posté(e) le 1 septembre 2021 Merci pour toutes ces infos! Je vais lire ce que tu as posté pour que je comprenne mieux, et je teste ton code dans la foulée
Inkew Posté(e) le 1 septembre 2021 Auteur Signaler Posté(e) le 1 septembre 2021 Salut Lazer, Tu verras qu'il y a beaucoup de début dans mon code, mais il n'y a qu'une chose qui a l'air de ne pas fonctionner : la fonction settimeout. Lorsque je la fais à l'ancienne (pas bien), ça tourne rond : function QuickApp:onInit() self:debug("onInit") self:updateProperty("value", -100) local tempOld = self.properties.value self:debug(tempOld) self.Table = {} for i = 1, 10 do table.insert(self.Table, tempOld) end self:debug(json.encode(self.Table)) --self:loop("Calcul_Temp_Moy_Gliss") -- on lance la boucle fibaro.setTimeout(0, function() loop() end) -- on lance la boucle end function QuickApp:loop() self:debug("loop!") table.remove(self.Table, 1) self:debug(json.encode(self.Table)) local newValue = fibaro.getValue(309, "value") -- il s'agit de l'ID de ton module température Z-Wave ou Netatmo self:debug(newValue) table.insert(self.Table, newValue) self:debug(json.encode(self.Table)) local tempSum = 0 for i = 1, #self.Table do tempSum = tempSum + self.Table[i] end self:debug(tempSum) local tempMoy = tempSum / #self.Table self:debug(tempMoy) self:updateProperty("value", tempMoy) ---fibaro.sleep(3000) fibaro.setTimeout(3000, function() loop() end) -- prochaine boucle dans 3 secondes self:loop(text) end
Lazer Posté(e) le 1 septembre 2021 Signaler Posté(e) le 1 septembre 2021 En effet, normal, il fallait écrire avec self : fibaro.setTimeout(0, function() self:loop() end) fibaro.setTimeout(3000, function() self:loop() end) Je t'ai dis, c'est pas testé, et écris à l'arrache
Inkew Posté(e) le 1 septembre 2021 Auteur Signaler Posté(e) le 1 septembre 2021 T'inquiète j'avais bien compris que tu n'avais pas eu le temps de tester! Et en même temps ça aide à comprendre! Ca fonctionne, je suis trop content! Merci encore!
Inkew Posté(e) le 2 septembre 2021 Auteur Signaler Posté(e) le 2 septembre 2021 Petite question bonus : peut-on supprimer des valeurs qui construisent la courbe dans l'onglet Advanced du QA (avec les tests du début ça ne ressemble pas à grand chose)!
Lazer Posté(e) le 2 septembre 2021 Signaler Posté(e) le 2 septembre 2021 Je ne sais pas.... je suppose que ça va tout supprimer. Sinon tu attends, ça va se purger automatiquement.
Messages recommandés