Question sur fonction stateChangesBetween

Bonsoir
J’ai une petite question sur l’utilisation de la fonction stateChangesBetween.
Je m’en sers dans le contexte suivant : en cas de détection d’une fuite, lorsque le sol redevient sec, il s’écoule une période plus ou moins longue où le sol passe alternativement de sec à humide, parfois dans de courts laps de temps et où par conséquent le capteur d’humidité va envoyer alternativement des 1 et des 0 à répétition. Les infos de ce capteur déclenchant un scénario, je souhaite éviter que le scénario déclenche également alternativement dans des courts laps de temps des actions contraires.
Je sais que la bonne solution n’est pas dans l’informatique, mais tout simplement dans le fait de régler définitivement le problème de fuite et de sécher correctement le sol, mais je ne serai pas forcément sur place lorsque la fuite se déclenche et ce problème de fuite est par ailleurs récurrent (je ne vais pas vous ennuyer avec mes problèmes de cuisine !)

Je pense qu’il y a moultes façons de traiter ce besoin ; pour ma part j’ai retenu l’utilisation de la fonction stateChangesBetween appliquée au capteur. Je fais donc un test sur le nombre de changements d’état au cours des 10 dernières minutes ; si ce nombre est supérieur à 4, par exemple, rien ne se passe.
Mais je me suis aperçu que les expressions suivantes 1 et 2 renvoyaient un résultat correct :

  1. stateChangesBetween(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 1, 10 min ago, now)
  2. stateChangesBetween(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 0, 10 min ago, now)
    Par contre, l’expression suivante me renvoie toujours 0 :
  3. stateChangesBetween(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 10 min ago, now)

En fait, ce n’est pas très grave, je peux très bien me contenter des expressions 1 et 2 (ou même faire leur somme éventuellement).
Donc ma question est plutôt générale : quelle erreur est-ce que je commets dans l’expression 3 ?

Merci de votre aide


Informations Jeedom

Core : 4.4.19 (master)
DNS Jeedom : oui

Bonjour,

La réponse est dans la doc

Pour cette fonction il faut 4 arguments et tu n’en mets que 3 dans la 3.

Bonjour
C’est ce que je pense également, mais quand je mets l’expression :
stateChangesBetween(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, , 10 min ago, now), j’obtiens dans le testeur d’expression la réponse suivante :

Donc, il doit y avoir encore une erreur dans ma syntaxe ; j’ai essayé avec ou sans espace entre les 2 virgules, j’ai droit au même message d’erreur.

Tu as mis l’argument de la valeur mais qui est totalement vide, comment penses-tu que Jeedom va réussir à chercher quelque chose ?

Il lui faut à cet endroit la valeur qu’il doit rechercher dans l’historique pour savoir combien de fois il y a eu ce changement de valeur.

oui mais la description laisse penser que le 2eme (la valeur) est optionnel, donc n’en mettre que 3 semble possible.
Je n’ai pas (encore) vérifié le code pour savoir où se trouve le problème: doc ou code

Hello,

Hum, en effet

La value est considérée comme null dans ce cas (en 4.4.19)

		if ($args == 3) {
			$_startDate = func_get_arg(1);
			$_endDate = func_get_arg(2);
			$_value = null;
		}

Faudra creuser alors en effet, mais de ce que j’ai regardé rapidement je vois pas bien comment la requête SQL pourrait donner un résultat un null dans la value

Mon besoin est donc de savoir s’il est possible directement d’avoir le nombre de fois où le capteur a changé d’état et si oui, quelle est la bonne syntaxe. J’ai été influencé par l’exemple donné dans la doc pour la fonction voisine stateChanges :
stateChanges(prise,période) Renvoie 3 : la prise a changé 3 fois d’état pendant la période

Il n’y a pas vraiment besoin du Between dans ton cas donc juste :
stateChanges(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 1, 10 min ago)

Si tu veux également voir le passage par 0 alors il faudra ajouter stateChanges(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 0, 10 min ago)

Bonsoir
Merci de l’info.
Ce que je constate :
L’expression suivante, 1’, équivalent de 1 : stateChanges(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 1, 10 min ago) donne un résultat OK
L’expression suivante, 2’, équivalent de 2 : stateChanges(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 0, 10 min ago) donne un résultat OK
et plus intéressant :
L’expression suivante, 3’, équivalent de 3, avec 2 paramètres seulement : stateChanges(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 10 min ago) donne un résultat OK

Il semblerait donc qu’il y ait une contrainte non documentée avec l’expression 3.

J’ai parlé trop vite. L’expression 3’ renvoie bien un résultat, mais ça devrait être plus ou moins la somme de 1’ + 2’. Or, c’est égal à 1’ (et 2’ également). Il faut que je poursuive les tests.

Si tu ne fournit pas de valeur il prend normalement la valeur en cours

OK. Mais ce n’est pas ce que je lis dans la doc (si je sais lire), en particulier dans l’exemple que je recite :

Par ailleurs, il reste toujours la question pendante à propos de l’expression 3 qui renvoie comme résultat 0 avec 3 paramètres (stateChangesBetween(#[Cuisine][Détecteur de fuite lave vaisselle (Sonoff)][water_leak]#, 10 min ago, now)

Qu’est ce que tu ne trouves pas normal du coup ?
L’exemple que tu cites est complètement bidon puisque la fonction est utilisée avec « prise » et « période ». Utilisée comme ça, elle ne risques pas de sortir 3. C’est juste un « exemple ».

Pour l’expression 3, pour moi la fonction stateChangesBetween est buggée si on ne fournit pas de valeur.

Je n’ai pas la même doc (origine https://doc.jeedom.com/fr_FR/core/4.0/scenario:


Mais, bon, ok, c’est ta doc qui est donc la bonne. Je n’ai donc pas la possibilité d’obtenir directement le total des changements d’état.
Quant à l’exemple que je cite, je ne vois pas ce qu’il a de complètement bidon. Il est tiré du même lien et je le donne dans son intégralité :

La cohérence entre les 3 exemples n’est probablement pas fortuite.

Tu es en 4.4.19, il faut choisir la version 4.4. de la doc

https://doc.jeedom.com/fr_FR/core/4.4/scenario

Avec les 2 autres exemples on comprend mieux ce qu’ils ont voulu dire et ça pourrait coller si c’était le total des changements mais maintenant ce n’est plus le cas …

OK, merci. Je n’avais jamais pris garde au fait que la doc était également versionnée, ce qui est logique pourtant.
Dommage que Jeedom ait modifié le sens de la fonction stateChanges avec 2 paramètres. Quand il n’y a que 2 états possibles, c’est facile d’obtenir la somme de tous les changements d’état ; quand il y en a 5 par exemple, ça veut dire additionner 20 valeurs (5 !/(5-2) ! = 4 x 5 = 20 où ! = factorielle), si mes souvenirs de combinatoire ne sont pas totalement rouillés. Mais, bon, peut-être que ça n’a peut-être pas grand intérêt.
En tout cas, merci pour m’avoir confirmé que la fonction stateChangesBetween avec 3 paramètres est boguée (sachant qu’elle n’aurait pas répondu à mon besoin), et que la fonction stateChanges avec 3 paramètres me suffit (la fonction avec 2 paramètres ne répondant pas à mon besoin).
Question : quand un bug est identifié, y a-t-il une procédure à suivre ou est-ce que les équipes de Jeedom en surveillant le forum en prennent connaissance ?

PS : dans la doc 4.4, il y a toujours les mêmes 3 exemples sur la prise, manifestement, la doc n’est pas à jour.

Bonsoir,

Pour info il y a bien un « bug » dans la fonction stateChangesBetween lorsqu’on utilise que 3 arguments.

@Loic , je me permet de t’identifier, voici ce que je constate :

public static function stateChangesBetween($_cmd_id, $_value, $_startDate, $_endDate = null) {
...
if ($args == 3) {
			$_startDate = func_get_arg(1);
			$_endDate = func_get_arg(2);
			$_value = null;
		}

A partir du moment ou on modifie un argument
$_startDate = func_get_arg(1); (« $_startDate » c’est le même nom que l’argument initié dans la fonction), cela semble affecter la func_get_arg car lors de l’appel suivant $_endDate = func_get_arg(2); retourne une valeur vide.

Je me demande si cette note y fait pas référence :

En gros pour résumer avec stateChangesBetween('#[...][...][...]#', '10 min ago', 'now'):

$args = func_num_args();
if ($args == 3) {
  $scenario->setLog('func_get_arg(1) > ' . func_get_arg(1));
  $scenario->setLog('func_get_arg(2) > ' . func_get_arg(2));
  $_startDate = func_get_arg(1);
  $_endDate = func_get_arg(2);
  $scenario->setLog('$_startDate > ' . $_startDate);
  $scenario->setLog('$_endDate > ' . $_endDate);
  $scenario->setLog('func_get_arg(1) > ' . func_get_arg(1));
  $scenario->setLog('func_get_arg(2) > ' . func_get_arg(2));
}
[2025-03-06 21:02:33][SCENARIO] func_get_arg(1) > 10 min ago
[2025-03-06 21:02:33][SCENARIO] func_get_arg(2) > now
[2025-03-06 21:02:33][SCENARIO] $_startDate > 10 min ago
[2025-03-06 21:02:33][SCENARIO] $_endDate > 10 min ago
[2025-03-06 21:02:33][SCENARIO] func_get_arg(1) > 10 min ago
[2025-03-06 21:02:33][SCENARIO] func_get_arg(2) > 10 min ago

Pour contourner ce soucis, il faut commencer par le dernier argument :

$args = func_num_args();
if ($args == 3) {
  $scenario->setLog('func_get_arg(1) > ' . func_get_arg(1));
  $scenario->setLog('func_get_arg(2) > ' . func_get_arg(2));
  $_endDate = func_get_arg(2); // commencer par l'argument 2
  $_startDate = func_get_arg(1);
  $scenario->setLog('$_startDate > ' . $_startDate);
  $scenario->setLog('$_endDate > ' . $_endDate);
  $scenario->setLog('func_get_arg(1) > ' . func_get_arg(1));
  $scenario->setLog('func_get_arg(2) > ' . func_get_arg(2));
}
[2025-03-06 21:04:40][SCENARIO] func_get_arg(1) > 10 min ago
[2025-03-06 21:04:40][SCENARIO] func_get_arg(2) > now
[2025-03-06 21:04:40][SCENARIO] $_startDate > 10 min ago
[2025-03-06 21:04:40][SCENARIO] $_endDate > now
[2025-03-06 21:04:40][SCENARIO] func_get_arg(1) > 10 min ago
[2025-03-06 21:04:40][SCENARIO] func_get_arg(2) > 10 min ago

Ou autre méthode, qui a mon avis plus propre, est d’utiliser la func_get_args qui retourne un tableau et qui ne semble pas impactée :

$args = func_get_args(); // utilisation de func_get_args
if (count($args) == 3) { // count
  $scenario->setLog('$args[1] > ' . $args[1]);
  $scenario->setLog('$args[2] > ' . $args[2]);
  $_startDate = $args[1];
  $_endDate = $args[2];
  $scenario->setLog('$_startDate > ' . $_startDate);
  $scenario->setLog('$_endDate > ' . $_endDate);
  $scenario->setLog('$args[1] > ' . $args[1]);
  $scenario->setLog('$args[2] > ' . $args[2]);
}
[2025-03-06 21:19:42][SCENARIO] $args[1] > 10 min ago
[2025-03-06 21:19:42][SCENARIO] $args[2] > now
[2025-03-06 21:19:42][SCENARIO] $_startDate > 10 min ago
[2025-03-06 21:19:42][SCENARIO] $_endDate > now
[2025-03-06 21:19:42][SCENARIO] $args[1] > 10 min ago
[2025-03-06 21:19:42][SCENARIO] $args[2] > now

Vu que la fonction stateChanges utilise le même fonctionnement, je pense que celle-ci est impactée aussi.

Bonne soirée.

5 « J'aime »

Subtile cette problématique :clap:

stateChanges n’a pas le même soucis, sûrement parce qu’il n’y a pas ce double remplacement du coup.

		if ($args == 2) {
			if (is_numeric(func_get_arg(1))) {
				$_value = func_get_arg(1);
			} else {
				$_period = func_get_arg(1);
				$_value = null;
			}
		}
1 « J'aime »

Salut,

Merci pour ton analyse. C’est fou ce bug (et la c’est bien un bug coté php). Pour la résolution l’idée du tableau est la meilleure car pas de changement tout du long.

Tu fais un PR ou tu veux que je le fasse ?

Pas de soucis je fait un PR dans le WE.
Bon week-end.

1 « J'aime »