Aller au contenu

setTimeout seule solution?


Messages recommandés

Posté(e)

Bonsoir à tous. 

 

J'aimerai savoir si il y' a d'autre méthode dans un Q.A mise à part le settimeout? je m'explique: 

 

Ce soir j'ai fais un bout de code qui est le suivant: 

local Volet = fibaro.getValue(Walli, "value")

function QuickApp:ActiveWalli()
    if Volet ==  0 then
    self:setVariable("EtatVolet", "Fermé")
    fibaro.call(Walli, 'setRingOnColor', "green") 
    fibaro.call(Walli, 'setRingOffColor', "blue") 
    self:debug("Volet fermé")
    else
    self:setVariable("EtatVolet", "Ouvert")
    fibaro.call(Walli, 'setRingOnColor', "none") 
    fibaro.call(Walli, 'setRingOffColor', "none")
    self:debug("Volet ouvert")
    end
end

Est-ce qu'il n'y a pas possibilité de faire une lecture instantanée des variables lors d'un changement d'état du volet par exemple
J'ai bien pensé à faire un self:ActiveWalli(), mais tout logiquement il me Lit la variable à l'infini tant qu'il n'y a pas de changement d'état


Si jamais il y a des méthodes plus pertinentes que le settimeout


Je suis preneur

 

Merci. 

 

 

Posté(e)

Pour être sûr de bien comprendre, tu aimerais (par exemple) :

- que lorsque tu bouges ton volet à la main (interrupteur ou autre automatisme)

- ton QA soit au courant ?

 

Franchement à part demander à ton QA de surveiller (donc tourner en boucle), je n'ai qu'une seule idée que je ne trouve pas du tout intéressante :

- avoir une scène avec comme trigger ton module de volet, qui ensuite appelle l'exécution de ton QA en cas de changement d'état.

 

Maintenant je te réponds en live sans trop y avoir réfléchis longuement, mais c'est ce qu'il me vient à l'esprit.

Car sans boucle dans ton QA, de lui-même il ne surveillera pas ce qu'il se passe. Soit il tourne en continue, soit tu as quelque chose qui le prévient volontairement.

 

A défaut du setTimeout il y a bien setInterval, mais d'un point de vue boucle temporelle qui check ce qu'il se passe, tu ne seras pas plus avancé avec ça.

 

 

Question : pourquoi veux-tu trouver une autre solution qu'un QA qui boucle pour vérifier ce qu'il se passe ? Le fait que ce ne soit pas quasiment instantané ?

  • Like 1
Posté(e)

Effectivement tu as mit le doigt dessus! 

Il y'a plusieurs raison à cela. 

1- Pour éviter de solliciter la box pour rien. Si mon volet change 4 fois max d'état par jours je trouve cela dommage de faire une boucle toute les 30 secondes pour vérifier l'état. 

2- Effectivement, j'aurai bien aimé qu'il y ai un peu d'instantanéité à la fin de la lecture de la fonction. 

 

Il n'y a donc pas possibilité de détecter instantanément un changement de variable (local ou global) ? Cela pourrait permettre de résoudre mon problème. 

 

 

 

 

 

Posté(e)

Si, selon moi avec un trigger dans une scène ou ton QA qui vérifie toutes x secondes. En dehors de ça je ne vois pas, mais je ne suis pas le plus fort en LUA ou QA.

Après si ton QA n’est pas gargantuesque, quel est le problème à le faire tourner. Ton contrôleur Fibaro en est capable facilement :D

Posté(e)

Même si je comprends complètement ton raisonnement 1. de ne pas vouloir « solliciter » ta box que pour ça…

Posté(e)

Bah disons qu'au lieu de faire une boucle toutes les 10 secondes, j aurais une fonction qui prenne en compte en temps réel et qu'une seul fois un changement d état du volet sa éviterai à la machine de tourner pour rien. 

 

Après, si il n y a aucun impact sur la machine autant faire cela puisque ça marche.

 

Je m étai dis que si il y a 20 Q.A qui ont des settimeout toutes les 10 secondes sa doit tirer sur la machine. ( je n ai pas de recul suffisant pour savoir ce que peut supporter la hc3) .

Posté(e)

It's not the setTimeout - it's what you do inside the setTimeouts...

Here I start 1 million setTimeouts in parallell.

local t = os.time()
for i=1,1000000 do   -- Start a million setTimeouts
   fibaro.setTimeout(1,function() end)
end
fibaro.setTimeout(30,function() 
   print("OK2")
   print(os.time()-t)
end)

The last setTimeout with 30ms timer will not be allowed to run until all the 1 million  have completed (that's how we time it).

It takes 41s on the HC3

[27.05.2021] [12:07:13] [DEBUG] [SCENE24]: OK2
[27.05.2021] [12:07:13] [DEBUG] [SCENE24]: 41

That's actually quite ok.

 

The trick with polling for state changes is  not to do it with a setTimeout loop doing fibaro.getValue. It's to do http:requests to the /refreshStates api as the http request will hang if there are no events and not consume any cpu during that time. When an event is available the http request will return immediately.

Granted is that you will get all kinds of events and need an efficient way to filter for events that you look for (devices changing state  or globals changing value) - but that is easy to do with  a table lookup.

 

I have a ready made library 'fibaroExtra.lua' that implements an event/sourceTrigger callback function that is as efficient as  it gets.

 

 

 

  • Like 1
Posté(e)

En complément... j'avais fait des tests de charge avec l'API refreshStates, et il s'avère que l'impact sur la charge CPU est relativement minime :

 

 

Perso j'ai plusieurs QA qui exploitent cette API en parallèle. Actuellement 4 je crois :

Il y a notamment GEA, mais aussi Evénements, la gestion de ma porte de garage, et d'un Velux.

 

  • Like 2
Posté(e)

Merci @jang et @Lazer

Bon il ne reste plus qu'à investiguer l'utilisation de cette API :P

Bonnes soirées de lecture et de cerveau qui brule en perspective, on ne s'ennuie jamais ici :2:

  • Like 1
Posté(e) (modifié)

Try to install this QA

TriggerQA.fqa v1.21

 

and then create another QA:

function QuickApp:subscribeTrigger(event)
  local s = self:getVariable('TRIGGER_SUB')
  if s == nil or s == "" then s = {} end
  s[#s+1]=event
  self:setVariable('TRIGGER_SUB',s)
end

function QuickApp:sourceTrigger(tr)
   self:debug(json.encode(tr))
end

function QuickApp:onInit()
    self:debug("onInit")
    self:subscribeTrigger({type='device'})
end

This will call QuickApp: sourceTrigger with the trigger as soon as it happens.

You can be more specific and do

self:subscribeTrigger({type='device', id=88})
self:subscribeTrigger({type='device', id=99})

to only get triggers from deviceId 88 and 99 etc.

 

Inside QuickApp: sourceTrigger you need to look at the trigger to see what trigger it is if you subscribe to different triggers.

If you don't need super optimized trigger handling (then you run your own / refreshStates loop) then the TriggerQA is a simple helper

that makes it easy for other QAs to receive sourceTrigger with very little overhead - similar to how scenes gets them - and it scales very well.

 

 

Modifié par jang
  • Like 3
  • Thanks 1
Posté(e) (modifié)

Updated TriggerQA to v1.21

 

Supported triggers

{type='alarm', property='armed', id=<id>, value=<value>}
{type='alarm', property='breached', id=<id>, value=<value>}
{type='alarm', property='homeArmed', value=<value>}
{type='alarm', property='homeBreached', value=<value>}
{type='alarm', property='activated', id=<id>, seconds=<seconds>}
{type='weather', property=<prop>, value=<value>, old=<value>}
{type='global-variable', property=<name>, value=<value>, old=<value>}
{type='quickvar', id=<id>, name=<name>, value=<value>; old=<old>}
{type='device', id=<id>, property=<property>, value=<value>, old=<value>}
{type='device', id=<id>, property='centralSceneEvent', value={keyId=<value>, keyAttribute=<value>}}
{type='device', id=<id>, property='accessControlEvent', value=<value>}
{type='profile', property='activeProfile', value=<value>, old=<value>}
{type='custom-event', name=<name>}
{type='deviceEvent', id=<id>, value='removed'}
{type='deviceEvent', id=<id>, value='changedRoom'}
{type='deviceEvent', id=<id>, value='created'}
{type='deviceEvent', id=<id>, value='modified'}
{type='sceneEvent', id=<id>, value='started'}
{type='sceneEvent', id=<id>, value='finished'}
{type='sceneEvent', id=<id<, value='instance', instance=<number>}
{type='sceneEvent', id=<id>, value='removed'}
{type='sceneEvent', id=<id>, value='modified'}
{type='sceneEvent', id=<id>, value='created'}
{type='onlineEvent', value=<boolean>}
{type='room', id=<id>, value='created'}
{type='room', id=<id>, value='removed'}
{type='room', id=<id>, value='modified'}
{type='section', id=<id>, value='created'}
{type='section', id=<id>, value='removede'}
{type='section', id=<id>, value='modified'}
{type='location',id=<userid>,property=<locationid>,value=<geofenceaction>,timestamp=<number>}
{type='ClimateZone',...}
{type='ClimateZoneSetpoint',...}

It also supports time/cron events

Time subscription:
{type='cron', time=<cronString>, tag=<string>}

cron  string format:
"<min> <hour> <day> <month> <wday> <year>"

min:   0-59
hour:  0-23
day:   1-31
month: 1-12
wday:  1-7   1=sunday
year:  YYYY

Ex.
"0 * * * * *"                  Every hour
"0/15 * * * * *"               Every 15 minutes
"0,20 * * * * *"               At even hour and 20min past
"0 * * 1-3 * *"                Every hour, January to March
"0 7 lastw-last * 1 *"         7:00, every sunday in the last week of the month
"sunset -10 lastw-last * 1 *"  10min before sunset every sunday in the last week of the month

Ex. 

self:subscribeTrigger({type='cron', time="0/15 * * * * *", tag="Quarter"})

will send back a source trigger ever 15min in the format

{type='cron', time="0/15 * * * * *", tag="Quarter"}

'tag' can be useful to match timers to actions...

 

This gives more or less the same or more functionality than what you get from Scene conditions.

Modifié par jang
  • Like 2
  • Thanks 2
×
×
  • Créer...