Aller au contenu

Messages recommandés

  • 1 an après...
Posté(e)

Pour information à destination de ceux qui se poseraient la question ^_^ setTimeout est incompatible avec la boucle while : si cette dernière tourne au moment du timeout, la fonction définie dans setTimeout ne s'exécute pas...

Posté(e)

En fait, ce n'est pas spécialement une boucle "while" qui pose problème, c'est tout traitement synchrone commencé doit être terminé en entier avant que le code appelé par Settimeout commence à s'exécuter en asynchrone.

 

Facile à mettre en évidence avec un simple sleep() de plusieurs secondes, lequel serait la dernière instruction d'une suite de commandes (sans boucle donc)... on voit clairement que le code appelé par settimout ne commence qu'après ce sleep.

 

Posté(e)

@Lazer C'est exactement ça, dit bien mieux que je ne saurais le faire.

 

Concrètement, je suis sur Heating Manager avec le cycle de chauffage qui est relancé à intervalles réguliers via setTimeout.

 

Pour prendre en compte les changements de consigne de manière satisfaisante et pouvoir faire passer une information entre deux instances d'une scène, j'ai essayé de passer par une variable globale qui est scannée en permanence par une boucle while. Et pendant qu'elle tourne, le cycle n'est pas relancé...

Posté(e)

D'une manière générale j’évite l'utilisation des boucles "while" dans les scripts LUA si je n'ai pas la maîtrise à 100% de son comportement. Après tu peux très bien mixer synchrone et asynchrone mais cela demande d’écrire du code pour le gérer correctement et surtout une  réflexion préliminaire afin de bien penser l'architecture.

 

Bon, a tout problème existe une solution, tu peux peut-être adapter simplement ton code, deux pistes:

  1. Tu peux utiliser un autre setTimeout pour vérifier régulièrement ta variable (cohérent avec ta démarche asynchrone).
  2. Tu peux mettre un trigger sur la variable afin de déclencher un traitement en cas de modification de cette dernière ? J'utilise cette technique ici par exemple https://www.domotique-fibaro.fr/topic/1956-notification-center/?tab=comments#comment-24645.

Posté(e) (modifié)

@Krikroff Après tests, j'avais écarté le trigger sur la variable (je ne sais plus pourquoi, j'ai tellement tourné le truc dans tous les sens -_-)

 

Mon problème était de recalculer la commande de chauffe à chaque modification de la consigne, plutôt que d'arrêter ou lancer le chauffage jusqu'à la fin du cycle en cours (ce que j'avais fait initialement et qui est une solution passable sur un cycle de 10' mais un peu bâtarde sur un cycle de 30' ou 45'), et ce en faisant en sorte que le setTimeout du cycle principal ne fasse pas sa life en coupant le chauffage selon la commande de chauffe précédente alors que la nouvelle imposerait de continuer à chauffer. Donc il me fallait faire passer l'info non seulement du VD à la scène, mais entre deux instances de la scène...

 

Je me suis bien arraché les cheveux, et au final, j'ai utilisé setTimeout pour scanner en permanence non pas une variable mais le VD directement. Au final, c'est incomparablement plus simple et cela me permet, en plus, de virer tous les triggers et de n'avoir en permanence qu'une seule instance de la scène (au lieu d'une instance pour le cycle principal et d'une nouvelle instance de courte durée à chaque modification de la température de consigne). C'est le même code qui est utilisé dans les deux cas, avec juste un paramètre de plus pour éviter l'arrêt non désiré de la chauffe.

 

  • Bref... J'imagine que c'est plus clair pour moi qui ai le nez dedans que pour vous... :2:
Modifié par OJC
Posté(e) (modifié)

Voilà le code pour mieux comprendre mon propos :

Révélation

function HeatingManager:startCycle(item, P, hC, isOverride)
  if (auto_kP and params_kP.learning[tostring(item.heater)]) then HeatingManager:setCoefficients(item) end
  item.stopTime = os.time() + hC
  if (P > 0) then
    HeatingManager:startHeater(item, hC)
    if (P < 1) then 
      params_kP.learning[tostring(item.heater)] = not (isOverride)
      setTimeout(function() if (os.time() >= item.stopTime) then HeatingManager:stopHeater(item) end end, hC * 1000)
    end
  else
    if (logInfo) then lib:log("[INFO] Heating is not required in ".. item.room .. "( " .. item.name .. ")") end
    HeatingManager:stopHeater(item)
  end
end

function StartHeatingManager()
  local P, hC = 0, 0
  for _, item in ipairs(collection) do
    if (logInfo) then lib:log("[INFO] Checking " .. item.room .. "( " .. item.name .. ")...") end
    P, hC = HeatingManager:getCommand(item)
    HeatingManager:startCycle(item, P, hC)
  end
  setTimeout(StartHeatingManager, maxCycle * 60 * 1000)
end

function StartOverrideManager()
  local curSetpoint, P, hC = 0, 0, 0
  for _, item in ipairs(collection) do
    curSetpoint = lib:temp2num(fibaro:getValue(getLinkedID("Panel"), "ui." .. item.panel .. ".value"))
    if curSetpoint ~= item.lastSetpoint then
      lib:log("[INFO] Setpoint has changed for " .. item.room)
      P, hC = HeatingManager:getCommand(item)
      HeatingManager:startCycle(item, P, hC, true)
    end
  end
  setTimeout(StartOverrideManager, 1000)
end

 

 

C'est la fonction StartOverrideManager() qui scanne en permanence le VD pour détecter un changement de la consigne et qui recalcule la commande de chauffe. Dans la fonction StartCycle() se trouve la fonction setTimeout qui se charge de couper le chauffage à la fin de la période de chauffe en vérifiant s'il a le droit de le faire.

Modifié par OJC
  • Like 1
×
×
  • Créer...