Berale64 Posté(e) le 28 novembre 2016 Signaler Posté(e) le 28 novembre 2016 J'ai un scheduler maison qui toutes les minutes inspecte une table pour voir s'il y a quelque chose à faire. Et ce soir, au coucher du soleil, les lumières du salon ne se sont pas allumées. Je suis donc allé voir de plus près et j'ai constaté un dérive de temps dans l'heure d’exécution des actions. Je m'explique: en toute rigueur, les secondes au moment de l'exécution devraient être les mêmes quelque soit l'heure et minute et en fait correspondre aux secondes au moment du démarrage de la scène. Et bien non. On a par exemple: 12:20:48 13:15:49 15:40:51 18:10:53 etc ... Et donc ce soir on est passé de 59s à 01s en zappant ainsi une minute. Ce n'est pas grave en soit, c'était juste pour allumer des lumières, mais ça pourrait être des actions plus critiques pour la maison. Va falloir que je me penche sur le problème.
Nico Posté(e) le 28 novembre 2016 Signaler Posté(e) le 28 novembre 2016 Oui, mais ta scène ne tourne peut être toutes les secondes piles, car je crois de mémoire qu'ils indiquaient un mini de 3s déjà non ?
Lazer Posté(e) le 28 novembre 2016 Signaler Posté(e) le 28 novembre 2016 Si tu fais un sleep(60*1000), le temps total entre 2 exécution de la scène est plus long que 60s, car il faut rajouter le temps d'exécution de toutes les instructions de ta scène. Cela peut prendre 1ms, comme plusieurs secondes.... Le seul moyen d'être certain que ta scène démarre, par exemple à 00s toutes les minutes, est de prendre le timestamp du temps courant (avec os.date()) et et calculer le delta à attendre. La plupart du temps tu attendras 60s, par à certains tours tu attendras 1s de moins, pour compenser le décalage temporel. Ne pas oublier qu'en parallèle, il y a la synchro de temps NTP. Enfin le NTP c'est la théorie, car Fibaro n'a jamais su le faire fonctionner..... d'où le VD Clock Sync de Krikroff qui te resynchronise ton horloge 1 fois par nuit... donc à ce moment précis, tu as un gros saut temporel de plusieurs secondes d'un coup (car l'horloge interne de la carte mère, basée sur un quartz, dérive seule) 1
Lazer Posté(e) le 28 novembre 2016 Signaler Posté(e) le 28 novembre 2016 @Nico non les 3s c'est pour la Main Loop d'un VD. Dans une scène, il n'y a pas de boucle, donc pas de "3s". Quand le code atteint la fin de la scène, l'instance s'arrête. Si tu veux une boucle, c'est à toi de le faire explicitement. 1
Fred le ouf Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Salut Berale24, j'ai eu le même problème que toi. ci dessous un squelette de scene qui doit te permettre de résoudre ton problème. --[[ %% properties %% autostart %% globals --]] --------------------------------------------------------------------------- -- -- SCENE XXXXXXXXXX 0.10 -- -- Version 0.10 -- * Version initiale --------------------------------------------------------------------------- --------------------------------------------------------------- -- RECALLAGE HORAIRE DE SCENE -- Constructor --------------------------------------------------------------- local DemarrerA = 20 -- exécuter quand Seconde = 20 local Seconde -- Fin du bloc Constructor --------------------------------------------------------------- --------------------------------------------------------------- -- RECALLAGE HORAIRE DE SCENE -- Execution --------------------------------------------------------------- Seconde = os.date('%S') if tonumber(Seconde) ~= DemarrerA then if tonumber(Seconde) < DemarrerA then DeltaAttente = DemarrerA - Seconde else DeltaAttente = (60 - tonumber(Seconde)) + DemarrerA end fibaro:sleep(DeltaAttente * 1000) else fibaro:sleep(60 * 1000) end -- Fin du bloc Execution --------------------------------------------------------------- --------------------------------------------------------------------------- -- Démarrage de la scène --------------------------------------------------------------------------- while true do -------------------------------------------------------------------- -- DEBUT des actions à réaliser à chaque nouvelle minute -------------------------------------------------------------------- fibaro:debug("test") -------------------------------------------------------------------- -- FIN des actions à réaliser à chaque nouvelle minute -------------------------------------------------------------------- --------------------------------------------------------------- -- RECALLAGE HORAIRE DE SCENE -- Execution --------------------------------------------------------------- Seconde = os.date('%S') if tonumber(Seconde) ~= DemarrerA then if tonumber(Seconde) < DemarrerA then DeltaAttente = DemarrerA - Seconde else DeltaAttente = (60 - tonumber(Seconde)) + DemarrerA end fibaro:sleep(DeltaAttente * 1000) else fibaro:sleep(60 * 1000) end -- Fin du bloc Execution RECALLAGE HORAIRE DE SCENE --------------------------------------------------------------- end Dans cet exemple, le code s'exécute toutes les minutes lorsque les secondes sont à 20. 15:18:20 15:19:20 15:20:20 etc. la boucle de recalage en fin de scène permet justement de se recaler, et ce même si ton propre code met 10,15 ou même 48 secondes à s'exécuter. En espérant que cela te serve. 2
Nico Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Lazert, oui, tu as raison, cela n'impacte pas les scènes.
Berale64 Posté(e) le 29 novembre 2016 Auteur Signaler Posté(e) le 29 novembre 2016 Merci Lazer pour les conseils. Merci Fred pour le code. Nico, faut arrêter de m'enduire avec de l'erreur !!!
Lazer Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Peso, je trouve qu'il y a quand même un intérêt à ne pas faire de recalage temporel, et à laisser dériver les scènes dans le temps : c'est de lisser la charge CPU de la box. En effet, si toutes les boucles de toutes les scènes se réveillaient toutes à la même seconde chaque minute, cela ferait un pic de charge qui ralentirait l'ensemble. Et la plupart du temps, on n'a pas besoin d'un intervalle très précis, donc ce n'est pas gênant de dériver de quelques millisecondes par cycle. Je pense que je ne dois avoir que 2 scènes sur ma box qui font du recalage temporel : GEA et Domocharts. Il n'y a pas longtemps j'ai fait l'expérience de monitorer la charge CPU/RAM/HDD de ma box pendant 24h, et j'ai été impressionné par la régularité du lissage de la charge, pourtant j'ai beaucoup de scènes et de VD qui se réveillent à intervalle régulier et font énormément de requêtes http dans tous les sens. Résultat, ma box est stable et performance (réactive) 2
Berale64 Posté(e) le 29 novembre 2016 Auteur Signaler Posté(e) le 29 novembre 2016 Entièrement d'accord avec toi sur le principe. Je n'ai que deux scènes qui bouclent en permanence, les autres démarrent sur trigger et les VD n'ont pas de main loop mais sont actionnés par mon scheduler qui fait du pressbutton. Sinon, le code de Fred recale à partir de la variable DemarrerA, donc on peut changer la valeur de scène en scène pour éviter les surcharges.
Lazer Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 ah non mais moi j'ai PLEIN de boucles (que ce soit des scènes ou VD). Simplement je les laisse dériver dans le temps car je ne suis pas à la seconde près. Certaines ne se réveillent que toutes les heures (ex : Network Monitor) donc ce n'est vraiment pas gênant. C'est juste que je n'ai que 2 scènes (GEA et Domocharts) qui font du recalage temporel, car pour ces 2 là j'ai besoin de plus de précision. Mais ton scheduler fait pareil, si il fait du pressButon à intervalle régulier ça revient au même. Reste que si ton scheduler est la seule boucle à déclencher les actions, tu vas te retrouver avec des pics de charges si il clique sur plusieurs boutons au même moment. Et donc je préfère ma méthode avec pleins de boucles infinies dans tous les sens, car cela lisse mieux la charge CPU sur la durée, statistiquement parlant. Effectivement le code de Fred le ouf permet de choisir à quel moment la scène va se réveiller, donc is on générale son code à toutes les scènes, alors il faut prendre soin de choisir des instants de démarrage différents pour les scènes.
Lazer Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 J'ai l'impression que le nouveau trigger de scène timer va bien nous simplifier la vie pour les déclenchements à intervalle régulier :
Krikroff Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Je vous conseille vivement de ne plus utiliser fibaro:sleep dans vos scènes mais setTimeout (asynchrone) 3
mprinfo Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 @krikroff merci pour cette information.Envoyé de mon SM-G901F en utilisant Tapatalk
Lazer Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Yes Krikroff, merci C'est déjà le cas pour mes nouvelles scènes, mais pas pour les anciennes (qui fonctionnent encore bien avec les fibaro:sleep().... mais pour combien de temps ?) Par contre, je n'ai jamais testé, mais pour les main loop ce n'est pas possible ? Ca fonctionne toujours avec la boucle infinie je crois : while true do -- code utilisateur fibaro:sleep(3000) end
Krikroff Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Oui pas possible !Mainloop = VDVD = Ancien moteur LUA de la V3 Envoyé de mon iPhone en utilisant Tapatalk
BenjyNet Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Il y avait pas un thread sur l'utilisation du setTimout ?
Steven Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Il y a 1 heure, Lazer a dit : J'ai l'impression que le nouveau trigger de scène timer va bien nous simplifier la vie pour les déclenchements à intervalle régulier : Je pense qu'on devrait prendre de l'avance et trouvez déjà un correctif à ce futur trigger ... ben oui quoi, notre box n'est pas à l'heure, on trouve un palliatif, nos scènes se stoppent, on trouve un palliatif ... je pense donc qu'on devrait déjà se pencher sur le problème et être proactif sur les futurs bugs. Ok, je sors ‼ 4
pepite Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 Sors pas, moi je dis oui, en avance de phase ;-) Adieu les "slips" alors ;-), et bonjour à SetTimeout ,-) des que possible 1
Berale64 Posté(e) le 29 novembre 2016 Auteur Signaler Posté(e) le 29 novembre 2016 Moi, je me suis acheté un chronomètre de compétition et je reste derrière mon écran et quand c'est l'heure, je clique, je clique, je clique .... 3
Krikroff Posté(e) le 29 novembre 2016 Signaler Posté(e) le 29 novembre 2016 il y a 32 minutes, Steven a dit : Je pense qu'on devrait prendre de l'avance et trouvez déjà un correctif à ce futur trigger ... ben oui quoi, notre box n'est pas à l'heure, on trouve un palliatif, nos scènes se stoppent, on trouve un palliatif ... je pense donc qu'on devrait déjà se pencher sur le problème et être proactif sur les futurs bugs. Ok, je sors ‼ Mais non Steven, en fait c'est pour notre bien, Fibaro nous pousse à nous surpasser, je suis agile et proactif, j'aime ma box 4
OJC Posté(e) le 26 octobre 2017 Signaler Posté(e) le 26 octobre 2017 (modifié) Bonsoir à tous, Vu l'injonction de @Krikroff, j'ai repris le code de @Fred le ouf pour le faire fonctionner avec setTimeout, en ajoutant la possibilité de spécifier un intervalle supérieur à la minute. --[[ %% properties %% events %% globals --]] Interval = 60 -- Intervalle exprimé en secondes (min. 60 s.) StartSecond = nil -- Exécution lorsque les secondes = StartSecond ou nil si indifférent Initialize = true -- Pour caler la première exécution sur StartSecond function SceneRun() -- Initialisation if ((Initialize) and (StartSecond ~= nil)) then CurrentSecond = os.date('%S') if tonumber(CurrentSecond) < StartSecond then Delta = StartSecond - CurrentSecond elseif tonumber(CurrentSecond) > StartSecond then Delta = (60 - tonumber(CurrentSecond)) + StartSecond else Delta = 60 end fibaro:debug("Première exécution dans "..Delta.." s.") setTimeout(SceneRun,Delta * 1000) Initialize = false else -------------------------------------------------------------------- -- DEBUT des actions à réaliser à chaque nouvelle minute -------------------------------------------------------------------- fibaro:debug("Exécution en cours...") -------------------------------------------------------------------- -- FIN des actions à réaliser à chaque nouvelle minute -------------------------------------------------------------------- -- Mise en attente if (StartSecond ~= nil) then CurrentSecond = os.date('%S') if tonumber(CurrentSecond) < StartSecond then Delta = StartSecond - CurrentSecond elseif tonumber(CurrentSecond) > StartSecond then Delta = (60 - tonumber(CurrentSecond)) + StartSecond else Delta = 60 end else Delta = 0 end if (Interval < 60) then Interval = 60 end fibaro:debug("Prochaine exécution dans "..Delta + Interval.." s.") setTimeout(SceneRun,(Delta + Interval) * 1000) end end -------------------------------------------------------------------- -- LANCEMENT de la scène -------------------------------------------------------------------- SceneRun() Modifié le 26 octobre 2017 par omc 2
Messages recommandés