Aller au contenu

Messages recommandés

Posté(e)

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.

 

Posté(e)

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 ?

Posté(e)

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)

  • Upvote 1
Posté(e)

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

  • Upvote 1
Posté(e)

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.

 

  • Upvote 2
Posté(e)

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

  • Upvote 2
Posté(e)

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.

 

 

Posté(e)

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.

Posté(e)

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 :

 

 

Posté(e)

Je vous conseille vivement de ne plus utiliser fibaro:sleep dans vos scènes mais setTimeout (asynchrone) ;)

  • Upvote 3
Posté(e)

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

 

Posté(e)

Oui pas possible !

Mainloop = VD
VD = Ancien moteur LUA de la V3 :(


Envoyé de mon iPhone en utilisant Tapatalk

Posté(e)
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 ‼

  • Upvote 4
Posté(e)

Sors pas, moi je dis oui, en avance de phase ;-)

 

Adieu les "slips" alors ;-), et bonjour à SetTimeout ,-) des que possible

 

 

  • Upvote 1
Posté(e)

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 .... :angry:

  • Upvote 3
Posté(e)
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 :74:

  • Upvote 4
  • 10 mois après...
Posté(e) (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é par omc
  • Upvote 2
×
×
  • Créer...