Salve de messages MQTT incontrôlés

Bonjour à tous,

Depuis quelques semaines, je suis confronté à des séries de messages MQTT incontrolés de temps en temps : genre lumières qui se mettent clignoter, prises Z-Wave / Chacon qui s’allument ou s’éteignent. Les index de mes compteurs d’impulsions qui se retrouvent effacés, du coup, ça ne compte plus. Quand c’est la prise du frigo ou du home cinema avec le vidéoproj qui s’éteint, ça pue vraiement ! Le WAF pense que « je joue » avec les lumières.

Mon environnement est le suivant. J’ai installé Mosquitto en local sur la machine Jeedom via le plugin JMQTT. Récemment, j’ai remplacé le plugin OpenZWave par ZWave-JS UI qui tourne de façon indépendante sous Docker. De plus, j’ai exporté certaines commandes des equipements RFPlayer via le plugin JMQTT. Ainsi, toutes les données dont j’ai besoin sont publiées en MQTT. Ensuite, j’utilise Node-RED pour gérer presque tous les scénarios.

Jusque là, ça tourne presque sans interface utilisateur final côté Jeedom.
J’ai environ 4000 topics qui proviennent des différents protocoles (dont 3500 avec ZWave-JS) et 1000 topics utilisables pour les équipements JMQTT et les scénarios. Cela commence à faire du monde.

Au passage, j’avais installé quelques applis MQTT sur mon smartphone pour des faires des interfaces très basiques. Bon, c’est bien, mais comme j’ai 700 commandes à ajouter à la main, je passe à JMQTT.

Avec le super plugin JMQTT, je remplace presque 200 équipements des plugins Virtuel et OpenZWave par des équipements JMQTT. Au passage, je salue la fonction ‹ template › de JMQTT. Dans les commandes des équipements JMQTT, j’historise sans moyenner et en autorisant la répétition des commandes afin de bien voir lorsque je réçois plusieurs fois le même ordre.

Au début, j’avais laissé le QoS à 1 par défaut un peu partout dans les différents outils et mis QoS à 2 pour les trucs plus critiques comme les impulsions et les SMS afin d’éviter de les avoir plusieurs fois. Aussi, je coche l’option Retain pour tous les messages car je veux voir ce qui se passe.

Tout tourne bien. Mais, de temps en temps, je me prend une salve de messages qui viennent de je ne sais où. C’est comme si certaines actions sur le modules étaient renvoyées (certains à ON, d’autres à OFF, d’autres rien du tout).

Pour éviter les répétions de messages, je reconfigure tous les outils et les commandes action JMQTT avec un QoS à 0, mais toujours avec l’option Retain. Là, j’ai encore le problème. Je reçois aussi de nouveau des SMS que j’ai déjà eu.

Me voilà maintenant à la recherche du coupable qui envoie ces messages.
Mosquitto, je ne le sens pas. Je souhaite redémarrer Mosquitto car cela fait un long moment qu’il tourne et vu les problèmes, je tente un Réparer


Et là, cela fait n’importe quoi pendant plusieurs dizaines de secondes.

Exemple avec un module Chacon qui fait du ON / OFF pendant 1 minute (Ceci peut s’expliquer en partie par le fait que les commandes du RFPlayer font plusieurs allers-retours avec Mosquitto)


D’autres modules ne font qu’un seul ON ou OFF ou rien.
Je retrouve le comportement à la con et je me demande pourquoi Mosquitto renvoie tout un tas de messages alors que tout est en QoS à 0. Maintenant, je soupçonne l’option Retain qui renverrait les messages qu’il a retenus lorsque les différents clients se reconnectent au redémarrage de Mosquitto. Je suppose aussi qu’il y a truc inconnu qui redémarre pour une raison inconnue.

Auriez-vous des pistes pour debugger le MQTT et mieux observer ce qui se passe entre les clients MQTT, les brokers JMQTT, Mosquitto, etc… ?

J’ai effectué plusieurs essais. Si je redémarre le daemon JMQTT, les valeurs des commandes sont rafraichis avec l’état actuel, donc pas de souci.
Si je repare Mosquitto, ceux sont bien 5000 topics qui sont renvoyées. Ce qui fait tourner les scénarios Node-RED en masse. Comme il y a 5000 topics à traiter, cela prend 2 ou 3 minutes où rien ne va plus. Même en désactivant tous les scénarios, les ordres vont vers ZWave-JS et les modules font n’importe quoi.

Bref, ce n’est pas top, tout ça. Je sens que vais tout passer en QoS à 0 et Retain Flag à false. Les clients devront être connectés pour ne pas louper les messages.

Quand je pense que le MQTT est prévu pour des réseaux instables avec des déconnections et reconnections, j’ai dû louper un truc…

La fiabilité de la domotique vient de prendre un coup !

Hello @Domatizer,

La répartition de Mosquitto le désinstalle et le réinstalle complètement en vidant les messages retain, ce n’est un test très probant et ça aura forcément les répercussions que tu constates.

Il faudrait plutôt lancer le service Mosquitto en mode debug et regarder dans les logs quel client envoie quoi sur un topic qui part en brioche.

J’ai le sentiment que le problème se situe plutôt au niveau des clients mqtt qui se connectent/déconnectent furtivement et renvoient une salve des messages antagonistes. J’ai déjà eu le cas avec ESPEsay, notamment avec des messages retain.

Ou alors encore au niveau du décodage des payload JSON si des valeurs attendues sont manquants ou le payload est null. Je ne sais pas comment tu le gères, par exemple, la réception du payload {"ts":4242}, là où tu t’attends à trouver {"ts":4242, "value":true}. Dans ce cas, le fait d’avoir d’avoir des messages retain peut aussi avoir une incidence.
Ce sera probablement plutôt dans nodered, car jMQTT ne change pas la valeur de la commande si le contenu du payload ne contient pas la clé attendue.

Bad

Oui, il faut que je réssaie ça quand personne est là :wink:

J’ai du traffic, environ 1000 message par minute (la téléinfo et l’ebus de la chaudière causent souvent). Il faut que je trouve un moyen de filtrer un peu le log.

Ça me rassure un peu ton histoire de messages antagonistes, mais pas pour trouver le coupable.

J’ai très peu de payloads JSON. Et là où ça déconne, il y a aucun JSON, le paylaod est juste la valeur.

Côté Jeedom, JMQTT me permet de faire une interface utilisateur et ne sert que pour afficher les données et appuyer facilement sur des boutons tous en QoS 0. De base, je ne voulais pas que les commandes « actions » puissent être répétées. Il faudra peut-être que je décoche aussi l’option Retain pour les actions.

Ben, ça fait 1 an que je l’utilise dans les scénarios avec un QoS à 1 + Retain, je n’avais pas eu de souci de ce genre.

Mon problème est depuis la migration des modules ZWave vers ZWave-JS UI qui causent en MQTT et la création des 200 équipements JMQTT.

Là, où je me méfie, c’est lorsque j’étiens une prise Z-Wave via MQTT et que j’allume avec son bouton physique. Il est problable que l’ordre d’extinction mémorisé soit renvoyé pour une raison encore que j’ignore et c’est le drame. Il va falloir investiguer…

Merci @Bad

J’ai eaucou lu et investigué plusieurs trucs.
Comme je m’étais amusé à télécharger des applis mobile MQTT, je suis retourné voir les réglages de ces applis. Et certaines avaient l’option Clean session désactivée.

Au début, j’étais en QoS à 1 et Retain partout.

D’après ce tableau ci-dessous et mes lectures, lorsqu’un client qui ce coche pas l’option Clean session, le broker s’efforce de retenir l’historique de tous les messages.
image

Si le client ne se reconnecte jamais (ce qui était le cas avec certaines applis), au bout d’un moment, le broker n’en peut plus et il fait boum ! Puis, lorsque ça redémarre, les clients connectés récupère les messages retenus. Comme il y en a des miliers, c’est long, ça fait ramer certains clients.

La suppression de la databse de Mosquitto a fait du bien. J’ai tout mis en QoS à 0. J’ai viré le Retain côté protocoles/modules style Truc2mqtt et dans Node-RED. Il faut que je passe maintenant dans les 200 équipements JMQTT pour enlever l’option Retain dans toutes les commandes Actions

J’ai compris aussi que si on envoie un message sans Retain après un message avec Retain, alors lorsqu’un client se reconnectera, il récupérera le message retenu avec Retain qui n’est pas le dernier message. :thinking:
Du coup, il faut d’abord supprimer le message retenu en envoyant un message vide (ce qui peut déjà mettre le bazard) avec Retain puis envoyer ensuite les messages sans Retain. Côté Node-RED, je filtre les messages vides afin de ne pas écraser les données dans Node-RED. Si je supprime « Retained » depuis MQTT Explorer, cela modifie les données dans JMQTT (une température passe à zéro). L’astuce constistera à déconnecter temporairement JMQTT, puis supprimer les messages « Retained » ou tous les messages 50 par 50 pour être tranquille et enfin reconnecter JMQTT…

Dernier truc, lorsque j’ai fait la mise à jour du plugin JMQTT, dans la minute qui a suivi, ça m’a fingué les index de mes compteurs eau et gaz (que je surveille de près avec une alerte SMS). Pour l’eau, il y avait le Retain, pour le gaz, non. J’ai corrigé à la main l’index du compteur d’eau (j’aurais dû tirer une chasse d’eau pour voir si ça repartais du bon pied). Celui du gaz s’est corrigé tout seul (c’est Node-RED qui compte et c’est lui qui a le bon index). Pour les impulsions, ça a buggué pareil, du coup, j’ai regardé le timestamp et j’ai pu constaté que l’impulsion pourrie retenue datait de fin Janvier. D’où elle sort celle là !

Je sens que je ne suis pas sorti de l’auberge avec ce MQTT…

En effet, c’est certainement pour ça que tes équipements font du ON/OFF à la reco au Broker.

Attention, il me semble qu’il faut envoyer un payload retained null (option -r -n de mosquitto_pub) pas un payload retain vide (-r -m ""), sinon le topic reste sur le Broker mais ne contient rien.

Soit dit en passant, dans jMQTT, l’envoi d’un payload vide est remplacé par un payload null.

C’est peut être pour ça que tu as eu des problèmes de chasse d’eau :sweat_smile:

J’ai continué le nettoyage des Retain et viré mes apps mobiles. J’ai donné un ID explicite pour chaque client MQTT afin de savoir qui est qui. Ensuite, j’ai effectué plusieurs redémarrages : Mosquittto / JMQTT / ZWaveJS / Node-RED. Au début, c’était le festival avec les lumières et les prises.

Je n’ai pas vu l’option Clean session dans JMQTT. Par défaut, s’il n’y en a pas, c’est comme si c’était false ? Du coup, Mosquitto retient tout et à la reconnection de JMQTT, il "rejoue la séquence entière de tous les ordres. Oui, genre une dizaine de ON/OFF à la suite, comme ceci

[2023-02-06 16:42:02]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:05]INFO : Cmd #[Couloir RDC][Lumiere][Etat SET]# <- 1
[2023-02-06 16:42:07]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:07]INFO : Cmd #[Couloir RDC][Lumiere][Etat SET]# <- 0
[2023-02-06 16:42:07]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 1
[2023-02-06 16:42:07]INFO : Cmd #[Couloir RDC][Lumiere][Etat SET]# <- 1
[2023-02-06 16:42:07]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 1
[2023-02-06 16:42:08]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:08]INFO : Cmd #[Couloir RDC][Lumiere][Etat SET]# <- 0
[2023-02-06 16:42:08]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:08]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 1
[2023-02-06 16:42:08]INFO : Cmd #[Couloir RDC][Lumiere][Etat SET]# <- 1
[2023-02-06 16:42:09]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:09]INFO : Cmd #[Couloir RDC][Lumiere][Etat SET]# <- 0
[2023-02-06 16:42:09]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:09]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0
[2023-02-06 16:42:09]INFO : Cmd #[Couloir RDC][Lumiere][Etat]# <- 0

Je me demande si je ne vais pas mettre à false le paramètre persistence true dans le fichier mosquitto.conf pour être sûr qu’il n’enregistre rien.

De plus, j’ai l’impression qu’au redémarrage de ZWaveJS-UI, ce dernier renvoie toutes les infos. En effet, après suppression des Retain de tous les topics de ZWaveJS-UI dans MQTT Explorer, tout est revenu. Il faudra que je creuse ce point… Pour les impulsions, c’est chiant car ça incrémente. Bref, il ne faut pas redémarrer souvent ou alors enlever 1 impulsion après redémarrage…
De même, j’ai des scénarios d’éclairage sur l’ouverture des portes. Pour les portes qui sont ouvertes, le fait de renvoyer l’info, ça allume les lumières des pièces correspondantes pendant 1 minute.

Je passe par MQTT Explorer pour en faire 50 à la fois. Même 50 par 50, c’est assez lourd de retirer le Retain des milliers de topics de ZWaveJS-UI.

Capture d’écran du 2023-02-06 19-37-34

L’option Retain est bien décochée dans ZWaveJS-UI


Enuite, j’ai déconnecté tous les clients sauf MQTT Explorer et je me suis lancé dans la suppression des messages « Retained »
C’est au re démarrage que c’est revenu, mais les messages sont bien sans le flag « Retained » dans MQTT Explorer.

J’ai vérifié que lorsque je redémarre ZWaveJS-UI, il renvoie bien les 3500 topics comme un bourrin !

1 « J'aime »

en même temps comment faire autrement. entre le temps de l’arrêt et du redémarrage, les états ont pu changer et il faut bien se synchroniser avec les différents partenaires de communication. il doit interroger tous les devices zwave et updater jeedom et ses autres partenaires de comm.

tu ne peux pas juste te baser sur le cache local, c’est forcément à un moment où l’autre erroné. par contre le fait qu’il bagotte sur les états c’est bizarre… j’ai plus de 5000 topics rien qu’avec zwave et pas le moindre souci de ce type. en même temps je n’utilise pas node-red, je l’ai sur une vm pour autre chose mais pas pour jeedom qui est déjà je trouve très complet pour gérer la domotique.

C’est justement l’intérêt du Retain afin que celui que se reconnecte en cours de route récupèr la dernière info retenue (qui n’est pas forcément le dernier message envoyé) pour un topic donné.

Sans l’option Retain, le client qui n’est pas connecté au moment où le message a été envoyé ne recevra pas le message. C’est ce que je souhaite en ce moment !

Actuellement, je n’ai plus aucun message (sauf oubli) envoyé par ZWaveJS-UI/JMQTT/Node-RED avec l’option Retain. Et je n’ai plus de bug depuis.

A l’avenir, je vais remettre avec parcimonie le Retain sur certaines informations. En revanche, côté actions (souvent avec un topic xxx/set), il faut éviter d’utiliser le Retain.

Exemple, pour une lumière, si on allume avec une commande lumiere/etat/set à true avec Retain, puis on éteint la lumière avec le bouton physique, lorsqu’un client se connecte, la commande pour allumer sera renvoyée.

Pour éviter cela, j’ai synchronisé les commandes xxx/etat/set avec la valeur du topic xxx/etat si elles sont différentes. De plus, cela permet de synchroniser les (actions) curseurs via le retour d’état lorsqu’on modifie la valeur depuis l’extérieur, bouton physique (ou l’interface du module).

L’inconvénient est que cela revoie un ordre supplémentaire au module + un retour d’état : au début, etat = false et etat/set = false, j’allume via l’inter, etat = true, comme etat/set est différent de etat, etat/set se synchronise et passe à true, donc, un ordre d’allumage est envoyé au module qui va renvoyé à sont tour un retour d’état pour dire qu’il est allumé etat = true de nouveau. Mais comme etat/set = true, il ne se passe plus rien.

je crois que j’ai saisi et je suis navré que tu ais autant de soucis avec mqtt, peut être que ton utilisation des interfaces actuelles de jeedom dépasse simplement les capacités d’une petite centrale de domotique censée gérer l’installation de monsieur tout le monde et pas des A/R avec des tonnes de traitements externes via MQTT.

Mosquitto c’est loin d’être le meilleur à ce genre d’exercice de bavardage si l’on s’en remet aux benchmarks, mais bon ça dépanne bien pour des petites installs et si ça ne convient pas, il existe des alternatives.

Personnellement je trouve qu’on a pas gagné au change avec ces nouvelles technos mqtt et node-js… c’est pas le sujet mais l’envoi de salves de messages rament gravement par rapport à avant.

Oui, j’en suis conscient, je sais qu’il me faut un truc robuste pour faire de que je veux faire.

Même avec une surcouche MQTT, avec Node-RED, j’ai beaucoup moins de latence qu’avec Jeedom pour l’exécution d’un même type de scénario. J’ai énormément de scénarios pour gérer la lumière, il faut que ça tourne ! Ça ne suivait pas toujours dans Jeedom. Par conséquent, j’ai presque exporté tous les scénarios.

Node-RED me sert de « gros automate » tout en MQTT. Et Jeedom me sert d’interface graphique via JMQTT.

Avant, j’utilisais massivement des Virtuel sous Jeedom pour avoir un niveau abstraction. Mais ce n’est pas recommandé parait-il (il y a plusieurs sujets sur ce point). Maintenant, mon niveau d’abstraction est réalisé en MQTT.
Tour d’abord, je m’arrange que tous les protocoles envoient leurs infos en MQTT, les formats sont assez disparates, certains en JSON, d’autres pas, la hiérarchie est différente. Puis, Node-RED va créer tous les commandes utiles sous la forme d’un topic nodered/object/equipment/command.

Ensuite, mes automatismes se font avec les nouveaux équipements sans que je me soucie des protocoles.

Côté Jeedom, j’ai crée autant d’équipements JMQTT que de topic nodered/object/equipment. Donc, j’ai viré tous les Virtuels (Jeedom est content). Si Jeedom est éteint, tous les automatismes de base tournent de façon autonome.

Pour moi, la domotique, ce n’est pas juste une télécommande sur son smartphone, tout doit être automatisé au maximum.

Hier, j’avais tout fait avec des Virtuels Jeedom.
Aujourd’hui, je fais tout en MQTT.
Demain, je ferai tout en Matter.

1 « J'aime »

J’ai trouvé la commande magique pour afficher les topics des messages retenus par mosquitto.

mosquitto_sub -u user -P pass -t "#" -v --retained-only

Pour revenir à mon souci de départ.

J’ai eu de nouveau mes index de compteurs qui ont sauté dans Node-RED uniquement. J’ai regardé un peu plus près. Il a perdu la mémoire. Comme j’avais pris des précautions afin qu’un topic vide évite d’effacer une variable global de Node-RED. Le problème ne vient plus de MQTT.

Je vois que le container Docker de Node-RED a redémarré. Je pense que Node-RED a crashé, c’est-à-dire a redémarré sans pouvoir sauvegarder les variables (qui sont bien persistantes lors d’un redémarrage propre).

Dans le log, je vois que j’ai un problème de mémoire. :cry: C’est une VM de 1GB de RAM avec Node-RED dedans. Il va me falloir encore une machine avec plus de mémoire…


<--- Last few GCs --->
) [19:0x564b4875cf80] 1580575105 ms: Mark-sweep (reduce) 506.8 (518.4) -> 505.6 (519.4) MB, 366.9 / 0.0 ms  (+ 120.6 ms in 18 steps since start of marking, biggest step 26.6 ms, $

<--- JS stacktrace --->

FATAL ERROR: MarkCompactCollector: young object promotion failed Allocation failed - JavaScript heap out of memory
^[[?25l[^[[90m..................^[[0m] | : ^[[32minfo^[[0m ^[[35mlifecycle^[[0m node-red-docker@2.0.5~start: node-red-d^[[0m^[[K

^[[K^[[?25h
> node-red-docker@2.0.5 start /usr/src/node-red
> node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"

14 Feb 15:59:09 - [info]

Welcome to Node-RED
===================

14 Feb 15:59:09 - [info] Node-RED version: v2.0.5
14 Feb 15:59:09 - [info] Node.js  version: v14.17.3
14 Feb 15:59:09 - [info] Linux 4.19.0-17-amd64 x64 LE
14 Feb 15:59:10 - [info] Loading palette nodes
14 Feb 15:59:11 - [info] Dashboard version 3.0.4 started at /ui
14 Feb 15:59:12 - [info] Settings file  : /data/settings.js
14 Feb 15:59:12 - [info] Context store  : 'default' [module=memory]
14 Feb 15:59:12 - [info] User directory : /data
14 Feb 15:59:12 - [warn] Projects disabled : editorTheme.projects.enabled=false
14 Feb 15:59:12 - [info] Flows file     : /data/flows.json
14 Feb 15:59:12 - [info] Server now running at http://127.0.0.1:1880/
14 Feb 15:59:12 - [warn]

En m’intéressant à la façon dont Node-RED gère la sauvegarde des variables global, j’apprends que par défaut, il enregistre les données dans sa mémoire et non pas dans un fichier.


14 Feb 15:59:12 - [info] Context store  : 'default' [module=memory]

Donc, en cas de crash, tout saute ! Il perds les valeurs de tous les topics type nodered/object/equipment/command. De plus, comme j’ai supprimé partout l’option « Retain » des messages MQTT, Node-RED ne peut plus recevoir les dernières valeurs de chaque topic.
Ce qui revient pour Node-RED de partir de zéro. En fonction des automatismes, c’est plus ou moins gênant comme les index des compteurs.

Maintenant l’idée est d’utiliser un fichier pour sauvegarder les variables toutes les 30 secondes.
Ainsi, en cas de crash, je perds seulement les changements des 30 dernières secondes.

Petit tuto ici (pas encore testé) Working with context : Node-RED