Fonction wait dans PHP

Tags: #<Tag:0x00007f7534733628> #<Tag:0x00007f75347334e8>

Bonjour,

Je reprends un sujet fréquemment ouvert mais jamais traité… du wait qui ne fonctionne pas en PHP (par ex : Scénario "function" : passer une commande à un scénario via tag)

Un simple test d’appel à scenarioExpression::wait($condition,300); ne sort qu’après les 300s et pas dès que la condition est remplie.

// récup tags
$tags = $scenario->getTags();

$tagVolet = trim($tags['#tagAction#'],'\"');
$cmdVolet = cmd::byString('#'.$tagVolet.'#');

$contOpen = trim($tags['#tagDo#'],'\"');

// attendre que le DO se ferme...
$condition = "#".$contOpen."#==0";
$scenario->setLog('Attente de '.$condition);
scenarioExpression::wait($condition,300);

// ... pour fermer le volet
$scenario->setLog('Volet : '.$tagVolet);
$cmdVolet->execCmd();

Comment puis-je utiliser wait dans un script php ?
Merci

Dans les blocs code tu as tout PHP à ta disposition et notamment while ou do while.

https://www.php.net/manual/fr/control-structures.do.while.php

https://www.php.net/manual/fr/control-structures.while.php

De base je ne sais pas, sinon tu peux aussi utiliser la fonction native de PHP (quitte à être dans un bloc code) et faire plutôt une sorte de :

while($x < 300) {
  if ("#".$contOpen."#" == 0) {
    break;
  }
  sleep 1
  $x++;
}
2 J'aimes

Avant la boucle, il faut définir l’objet commande info.

A chaque itération, il faut récupérer sa valeur.

2 J'aimes

L’initialisation était fait avant dans son code et oui tu as raison il faut aussi le refaire dans le while pour mettre à jour la valeur :+1:

Bonjour,

Pourquoi est-ce que le wait sortirait avent les 300s puisqu’aucune action n’a été exécutée avant ?
Aucune raison que la condition soit vrai.

1 J'aime

Bonsoir,

  1. Il semblerai que la fonction scenarioExpression::wait($condition,300);n’accepte pas une chaine de caractère reconstitué. ($condition = "#".$contOpen."#==0")
  2. Ensuite dans ton code actuel, tu ne contrôle pas le retour de la fonction wait, donc ta commande $cmdVolet->execCmd(); sera exécuté dans tous les cas.

Voici un code qui devrait fonctionner :

// récup tags
$tags = $scenario->getTags();

$tagVolet = trim($tags['#tagAction#'],'\"');
$cmdVolet = cmd::byString('#'.$tagVolet.'#');

$contOpen = trim($tags['#tagDo#'],'\"');
$id_contOpen = cmd::byString('#'.$contOpen.'#')->getId(); // id de la commande

// attendre que le DO se ferme...
$condition = '#'.$id_contOpen.'# == 0'; // pour log
$condition_log = '#'.$contOpen.'# == 0'; // pour fonction wait
$scenario->setLog('Attente de '.$condition_log);
if (scenarioExpression::wait($condition,300)) {
  $scenario->setLog('[OK] la condition a été remplie, exécution de la commande #'.$tags['#tagAction#'].'#');
  $cmdVolet->execCmd();
}
else $scenario->setLog('[NOK] Timeout dépassé !!!');

Dans l’exemple ci-dessus, j’ai contourné le problème (1), en envoyant plutôt l’id que le nom de commande.
if (scenarioExpression::wait($condition,300)) ici j’attend que la fonction renvoie « true » pour exécuter la commande $cmdVolet->execCmd();

1 J'aime

Hello tous,
Merci pour vos réponses.

  1. @Mips

J’ai la modification en parallèle, la condition est bien remplie mais la boucle ne sort pas.

  1. @Bison @Jeandhom
    Ce sont de très bonnes idées mais dommage de réimplémenter la roue … La fonction est utilisée dans Jeedom via « wait » ca m’embête de tout refaire.

  2. @Phpvarious
    Ah oui super top ça merci beaucoup, excellentes idées. Je vais essayer d’implémenter avec ce bloc.

Encore merci à tous (je reviens dans la semaine confirmer que ca roule comme ça)

1 J'aime

Pour info, la fonction wait du core.

public static function wait($_condition, $_timeout = 7200) {
	$result = false;
	$occurence = 0;
	$limit = 7200;
	$timeout = jeedom::evaluateExpression($_timeout);
	$limit = (is_numeric($timeout)) ? $timeout : 7200;
	while ($result !== true) {
		$result = jeedom::evaluateExpression($_condition);
		if ($occurence > $limit) {
			return 0;
		}
		$occurence++;
		sleep(1);
	}
	return 1;
}

Yeap j’étais tombé dessus merci :+1:

Oui mais ce que vous ne comprenez pas c’est que en quelques sorte la condition est évaluée une seule fois dans votre bloc code…

extrait:

$condition = '#'.$id_contOpen.'# == 0'; // pour log
$condition_log = '#'.$contOpen.'# == 0'; // pour fonction wait
$scenario->setLog('Attente de '.$condition_log);
if (scenarioExpression::wait($condition,300)) {
  $scenario->setLog('[OK] la condition a été remplie, exécution de la commande #'.$tags['#tagAction#'].'#');
  $cmdVolet->execCmd();
}

La première ligne ci-dessus est « composée » une seule fois, au début. Donc le wait va toujours évaluer le même test.

Hum, je ne vois pas tellement pourquoi, pour moi $condition n’est ni vrai ni false c’est une chaine de char.
Comment faudrait-il faire pour passer la référence à la condition sans qu’elle soit évaluée ?

A priori ca fonctionne correctement chez moi avec le code de @Phpvarious , merci !
J’ai même pu utiliser une condition telle que scenario(#18#) == 0 pour m’assurer que le scenario à l’ID 18 est bien arrêté.

# equiv. wait("scenario(#[Volets][Bureau][Arrêter Volet Bureau]#) == 0",10) ;
$condition = 'scenario(#'.$id_scenario_arret_volet_bureau.'#) == 0';
$scenario->setLog('Attente de '.$condition);
if (scenarioExpression::wait($condition,10)) {
  $scenario->setLog('[OK] la condition a été remplie');
}
else {
	$scenario->setLog('[NOK] Timeout dépassé !!!');
}

EDIT confirmation aux logs :

[2021-10-11 16:43:11][SCENARIO] Attente de scenario(#164#) == 0
[2021-10-11 16:43:12][SCENARIO] [OK] la condition a été remplie
[2021-10-11 16:43:12][SCENARIO] 2458 valeur :72
[2021-10-11 16:43:12][SCENARIO] Commande : fermer-redboule
[2021-10-11 16:43:12][SCENARIO] Attente de #2458# == 50
[2021-10-11 16:43:18][SCENARIO] [OK] la condition a été remplie
[2021-10-11 16:43:18][SCENARIO] 2458 valeur :50
[2021-10-11 16:43:18][SCENARIO] Fin correcte du scénario

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.