node Red -> MQTT

  • bloody27370
  • Auteur du sujet
  • Hors Ligne
  • Nouveau membre
  • Nouveau membre
Plus d'informations
16 Aoû 2023 20:58 #1 par bloody27370
node Red -> MQTT a été créé par bloody27370
Bonjour,

Je cherche à récupérer toutes les secondes certaines valeurs du M'Sun PV pour les utiliser dans ma domotique. J'ai eu l'idée peut être un peu bête d'utiliser Node RED pour convertir le XML status en MQTT. Pour qu'ensuite je puisse utiliser les valeurs dans ma domotique sans charger le processeur de la domotique à gérer les scénario d'analyse du XML.

Ma connaissance de Node Red est très limité car je le découvre aujourd'hui. Après plusieurs heures à chercher en m'aidant un peu de chatGPT je sèche. Et MQTT je l'utilise depuis quelques mois mais j'essaye d'apprendre encore son fonctionnement.
Je vous joint une capture de mon Node pour comprendre.

1) un timestamp à la seconde pour l'actualisation en continue => fonctionnel
2) http request avec le lien "http://mon-ip/status.xml" => fonctionnel
3) un node xml pour convertir le XML en JSON. Cela me donne le JSON suivant :
{
  "xml": {
    "rtcc": [
      "22:41:58 ME"
    ],
    "paramSys": [
      "22:41:58;16/08/2023;On;01:00;0,0;MS_PV2_2;5.0.1;0000220;102e;102c;00:00;00:00"
    ],
    "inAns": [
      "493,0;-3,3; 0; 0;228,2;0,0;0,0;0,0; 0; 0; 0; 0; 0; 0; 0; 0;"
    ],
    "survMm": [
      "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;"
    ],
    "cmdPos": [
      "a;a;0;0;0;0;0;1;"
    ],
    "outStat": [
      "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;"
    ],
    "cptVals": [
      "24c67;fffff15d;fffdeded;fe80e657;0;0;0;0;"
    ],
    "chOutVal": [
      "0;0;0;ff;:0,0;0,0;0,0;0,0;"
    ]
  }
}

4) Ensuite et c'est là que je pense être ma première erreur, je voulais le convertir, j'ai essayé avec ChatGPT, mais rien n'a l'air de fonctionner. Une de ses propositions est :
var inAnsData = msg.payload.xml.inAns[0];
var cptValsData = msg.payload.xml.cptVals[0];
var outStatData = msg.payload.xml.outStat[0];
var cmdPosData = msg.payload.xml.cmdPos[0];

// Traitement des données de inAns
var inAnsValues = inAnsData.split(';');
// ... Traitez les données de inAns comme vous le faisiez dans la fonction PHP

// Traitement des données de cptVals
var cptValsValues = cptValsData.split(';');
// ... Traitez les données de cptVals comme vous le faisiez dans la fonction PHP

// Traitement des données de outStat
var outStatValues = outStatData.split(';');
// ... Traitez les données de outStat comme vous le faisiez dans la fonction PHP

// Traitement des données de cmdPos
var cmdPosValues = cmdPosData.split(';');
// ... Traitez les données de cmdPos comme vous le faisiez dans la fonction PHP

Pour finir j'ai le MQTT Out, j'ai bien renseigné mon brocker et il s'y connecte mais je ne sais pas quoi mettre en payload

Si vous avez d'autres solution je suis preneur ...

En l'occurence je n'ai que 5 infos qu'il m'intéresse de récupérer en gras ci-dessous :

"inAns": [
"493,0;-3,3; 0; 0;228,2;0,0;0,0;0,0; 0; 0; 0; 0; 0; 0; 0; 0;"

cptVals": [
"24c67;fffff15d;fffdeded;fe80e657;0;0;0;0;"
Pièces jointes :
Les utilisateur(s) suivant ont remercié: ilco

Connexion ou Créer un compte pour participer à la conversation.

  • bloody27370
  • Auteur du sujet
  • Hors Ligne
  • Nouveau membre
  • Nouveau membre
Plus d'informations
17 Aoû 2023 09:01 #2 par bloody27370
Réponse de bloody27370 sur le sujet node Red -> MQTT
Je me réponds à moi même, après avoir été guidé sur le forum Jeedom.

Voici la solution que m'a donné chatGPT et qui fonctionne pour récupérer les deux premières valeurs de InAns qui m'intéresse.
// Récupérer le message JSON d'entrée
var inputJSON = msg.payload;

// Extraire l'objet "inAns"
var inAnsArray = inputJSON.xml.inAns;

// Join des éléments de l'array et remplacement des virgules par des points
var inAnsString = inAnsArray.join('').replace(/,/g, '.');

// Séparer les valeurs par des points-virgules et prendre les 2 premières
var numericValues = inAnsString.split(';').slice(0, 2).map(item => parseFloat(item));

// Créer l'objet de sortie avec les valeurs numériques
var outputObj = { "inAns": numericValues };

// Envoyer l'objet de sortie
msg.payload = outputObj;
return msg;

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
11 Fév 2024 12:55 - 11 Fév 2024 13:53 #3 par ilco
Réponse de ilco sur le sujet node Red -> MQTT
Salut,

J’ai un peu complété le code avec l’envoi de toutes les infos sur un topic msunpv/data. J’ai converti la valeur des compteurs avec le fameux complément a 2 pour avoir les nombres negatifs!
[{"id":"5c1f49a2f0842fa0","type":"function","z":"999280016ff24882","name":"function 1","func":"// Récupérer le message JSON d'entrée\nvar inputJSON = msg.payload;\n\n// Extraire l'objet \"inAns\"\n\nvar inRTCC = inputJSON.xml.rtcc;\nvar inParamSys = inputJSON.xml.paramSys;\nvar inAnsArray = inputJSON.xml.inAns;\nvar inSurvMm = inputJSON.xml.survMm;\nvar inCmdPos = inputJSON.xml.cmdPos;\nvar inOutStat = inputJSON.xml.outStat;\nvar inCptVals = inputJSON.xml.cptVals;\nvar inChOutVal = inputJSON.xml.chOutVal;\n\n\nvar RTCCStringValues = inRTCC.join('').split(' ');\nvar ParamSysStringValues = inParamSys.join('').split(';');\n\n// Join des éléments de l'array et remplacement des virgules par des points\nvar ansStringValues = inAnsArray.join('').replace(/,/g, '.').replace(/\\;$/,'');\n// Séparer les valeurs par des points-virgules et prendre les 2 premières\nvar ansNumericValues = ansStringValues.split(';').map(item => parseFloat(item));\n\nvar SurvMmStringValues = inSurvMm.join('').replace(/\\;$/, '').split(';').map(item => parseInt(item));\nvar CmdPosStringValues = inCmdPos.join('').replace(/\\;$/, '').split(';').map(item => parseInt(item));\nvar OutStatStringValues = inOutStat.join('').replace(/\\;$/, '').split(';').map(item => parseInt(item));\nvar CptValsNumericValues = inCptVals.join('').replace(/\\;$/, '').split(';').map(item => hexToInt(item));\nvar ChOutValStringValues = inChOutVal.join('').replace(/\\;$/, '').split(';');\n\n// Créer l'objet de sortie avec les valeurs numériques\nvar outputObj = {\"RTCC\": RTCCStringValues, \"ParamSys\": ParamSysStringValues, \"inAns\": ansNumericValues, \"SurvMm\": SurvMmStringValues, \"CmdPos\": CmdPosStringValues, \"OutStat\": OutStatStringValues, \"CptVals\": CptValsNumericValues, \"ChOutVal\": ChOutValStringValues};\n\n// Envoyer l'objet de sortie\nmsg.payload = outputObj;\nreturn msg;\n\nfunction hexToInt(hex) {\n    if (hex.length % 2 != 0) {\n        hex = \"0\" + hex;\n    }\n    var num = parseInt(hex, 16);\n    var maxVal = Math.pow(2, hex.length / 2 * 8);\n    if (num > maxVal / 2 - 1) {\n        num = num - maxVal\n    }\n    return num;\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":500,"wires":[["7d266cee5180b2e6","e1cf2e08bb917aa2"]]}]

Il me manque encore la partie de « surveille un topic msunpv/data pour envoyer les commandes POST » et modifier le routeur. Je ne sais pas trop quelle strategie adopter…
Dernière édition: 11 Fév 2024 13:53 par ilco.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
10 Mar 2024 14:25 #4 par ilco
Réponse de ilco sur le sujet node Red -> MQTT
Et voila enfin avec la commande qui fonctionne !! Si je publie sur topic msunpv/cmd/cmd1 un 2 ca met le ballon en auto en envoyant la bonne commande sur index.xml, si c'est 1 un en manu, et 0 ben OFF :)
[{"id":"999280016ff24882","type":"tab","label":"MSunPV","disabled":false,"info":"","env":[]},{"id":"03b797d2b3224219","type":"inject","z":"999280016ff24882","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3","crontab":"","once":true,"onceDelay":"90","topic":"","payload":"","payloadType":"date","x":150,"y":220,"wires":[["2709667b90776444"]]},{"id":"2709667b90776444","type":"http request","z":"999280016ff24882","name":"","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.139/status.xml","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":310,"y":220,"wires":[["b6f1891b2e985037"]]},{"id":"b6f1891b2e985037","type":"xml","z":"999280016ff24882","name":"","property":"payload","attr":"","chr":"","x":450,"y":220,"wires":[["5c1f49a2f0842fa0","90c320ffa0d9e270"]]},{"id":"7d266cee5180b2e6","type":"debug","z":"999280016ff24882","name":"debug 11","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":780,"y":220,"wires":[]},{"id":"5c1f49a2f0842fa0","type":"function","z":"999280016ff24882","name":"function 1","func":"// Récupérer le message JSON d'entrée\nvar inputJSON = msg.payload;\n\n// Extraire l'objet \"inAns\"\n\nvar inRTCC = inputJSON.xml.rtcc;\nvar inParamSys = inputJSON.xml.paramSys;\nvar inAnsArray = inputJSON.xml.inAns;\nvar inSurvMm = inputJSON.xml.survMm;\nvar inCmdPos = inputJSON.xml.cmdPos;\nvar inOutStat = inputJSON.xml.outStat;\nvar inCptVals = inputJSON.xml.cptVals;\nvar inChOutVal = inputJSON.xml.chOutVal;\n\n\nvar RTCCStringValues = inRTCC.join('').split(' ');\nvar ParamSysStringValues = inParamSys.join('').split(';');\n\n// Join des éléments de l'array et remplacement des virgules par des points\nvar ansStringValues = inAnsArray.join('').replace(/,/g, '.').replace(/\\;$/,'');\n// Séparer les valeurs par des points-virgules et prendre les 2 premières\nvar ansNumericValues = ansStringValues.split(';').map(item => parseFloat(item));\n\nvar SurvMmStringValues = inSurvMm.join('').replace(/\\;$/, '').split(';').map(item => parseInt(item));\nvar CmdPosNumericValues = inCmdPos.join('').replace(/\\;$/, '').split(';').map(item => hexToInt(item));\nvar OutStatStringValues = inOutStat.join('').replace(/\\;$/, '').split(';').map(item => parseInt(item));\nvar CptValsNumericValues = inCptVals.join('').replace(/\\;$/, '').split(';').map(item => hexToInt(item));\nvar ChOutValStringValues = inChOutVal.join('').replace(/\\;$/, '').split(';');\n\nlet cmd1;\nlet cmd2;\n\nswitch (CmdPosNumericValues[0]) {\n    case 0:\n        cmd1 = 0; //off\n        cmd2 = 0;\n        break;\n    case 1:\n        cmd1 = 1; //manu\n        cmd2 = 0;\n        break;\n    case 2:\n        cmd1 = 2; //auto\n        cmd2 = 0;\n        break;\n    case 4:\n        cmd1 = 0;\n        cmd2 = 1;\n        break;\n    case 5:\n        cmd1 = 1;\n        cmd2 = 1;\n        break;\n    case 6:\n        cmd1 = 2;\n        cmd2 = 1;\n        break;\n    case 8:\n        cmd1 = 0;\n        cmd2 = 2;\n        break;\n    case 9:\n        cmd1 = 1;\n        cmd2 = 2;\n        break;\n    case 10:\n        cmd1 = 2;\n        cmd2 = 2;\n        break;\n    default:\n        cmd1 = 0; //off\n        cmd2 = 0;\n        console.log(`Error`);\n}\n\nvar CmdPosValues = [cmd1, cmd2, CmdPosNumericValues[7]];\n\n// Créer l'objet de sortie avec les valeurs numériques\nvar outputObj = { \"RTCC\": RTCCStringValues, \"ParamSys\": ParamSysStringValues, \"inAns\": ansNumericValues, \"SurvMm\": SurvMmStringValues, \"CmdPos\": CmdPosValues, \"OutStat\": OutStatStringValues, \"CptVals\": CptValsNumericValues, \"ChOutVal\": ChOutValStringValues };\n\n\n// Envoyer l'objet de sortie\nmsg.payload = outputObj;\nreturn msg;\n\nfunction hexToInt(hex) {\n    if (hex.length % 2 != 0) {\n        hex = \"0\" + hex;\n    }\n    var num = parseInt(hex, 16);\n    var maxVal = Math.pow(2, hex.length / 2 * 8);\n    if (num > maxVal / 2 - 1) {\n        num = num - maxVal\n    }\n    return num;\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":220,"wires":[["7d266cee5180b2e6","e1cf2e08bb917aa2","2ddc9ea8d81ba2a9"]]},{"id":"90c320ffa0d9e270","type":"debug","z":"999280016ff24882","name":"debug 12","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":160,"wires":[]},{"id":"9c980b5856077a0e","type":"mqtt out","z":"999280016ff24882","name":"","topic":"","qos":"0","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"c6b88f19.cc3fb","x":990,"y":280,"wires":[]},{"id":"362f878fc7372f25","type":"mqtt in","z":"999280016ff24882","name":"","topic":"msunpv/cmd/#","qos":"2","datatype":"json","broker":"c6b88f19.cc3fb","nl":false,"rap":true,"rh":0,"inputs":0,"x":120,"y":580,"wires":[["0b881a8881ba03fa"]]},{"id":"e1cf2e08bb917aa2","type":"change","z":"999280016ff24882","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"msunpv/data","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":280,"wires":[["9c980b5856077a0e"]]},{"id":"c1e7b1f4288a8051","type":"debug","z":"999280016ff24882","name":"debug 13","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1000,"y":580,"wires":[]},{"id":"95ece56e027bbfa5","type":"http request","z":"999280016ff24882","name":"","method":"POST","ret":"txt","paytoqs":"ignore","url":"http://192.168.1.139/index.xml","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":670,"y":580,"wires":[["5f580393ab3426ff"]]},{"id":"13737083e0019043","type":"function","z":"999280016ff24882","name":"SETTING REQUEST","func":"msg.headers = {};\nmsg.headers = {\n    'Content-Type': 'application/x-www-form-urlencoded'\n};\n\nvar cmd1 = newOrOld(msg.payload['msunpv/cmd/cmd1'], msg.payload.current[0]);\nvar cmd2 = newOrOld(msg.payload['msunpv/cmd/cmd2'], msg.payload.current[1]);\n\nvar cmd;\n\nswitch (cmd1 + 4 * cmd2) {\n    case 1: case 2: case 4: case 5: case 6: case 8: case 9: case 10: //send 10 and not a (even while receiving a)\n        cmd = cmd1 + 4 * cmd2;\n        break;\n    default:\n        cmd = 2;\n}\n\nlet test;\n\nswitch (newOrOld(msg.payload['msunpv/cmd/test'], msg.payload.current[2])) {\n    case 1: case 2: case 4: case 8:\n        test = newOrOld(msg.payload['msunpv/cmd/test'], msg.payload.current[2]);\n        break;\n    default:\n        test = 2;\n}\n\nmsg.payload = 'parS=' + cmd + ';0;0;0;0;0;0;' + test + ';';\n\nreturn msg;\n\nfunction newOrOld(nnew, old) {\n    if (nnew === undefined) {\n        return old;\n    }\n    return nnew;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":580,"wires":[["95ece56e027bbfa5","0cfee7360b6fdae2"]]},{"id":"2ddc9ea8d81ba2a9","type":"function","z":"999280016ff24882","name":"extract current cmd","func":"msg.payload = msg.payload.CmdPos;\nmsg.topic = \"current\";\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":190,"y":440,"wires":[["0b881a8881ba03fa"]]},{"id":"0b881a8881ba03fa","type":"join","z":"999280016ff24882","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":300,"y":580,"wires":[["13737083e0019043","d18ecd3c0e10bea4"]]},{"id":"5f580393ab3426ff","type":"xml","z":"999280016ff24882","name":"","property":"payload","attr":"","chr":"","x":850,"y":580,"wires":[["c1e7b1f4288a8051"]]},{"id":"0cfee7360b6fdae2","type":"debug","z":"999280016ff24882","name":"debug 14","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":440,"wires":[]},{"id":"d18ecd3c0e10bea4","type":"debug","z":"999280016ff24882","name":"debug 15","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":460,"y":440,"wires":[]},{"id":"c6b88f19.cc3fb","type":"mqtt-broker","name":"Mosquitto","broker":"192.168.1.27","port":"1883","clientid":"16","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"autoUnsubscribe":true,"birthTopic":"Node-red-router","birthQos":"2","birthRetain":"false","birthPayload":"1","birthMsg":{},"closeTopic":"Node-red-router","closeQos":"2","closeRetain":"false","closePayload":"0","closeMsg":{},"willTopic":"Node-red-router","willQos":"2","willPayload":"0","willMsg":{},"userProps":"","sessionExpiry":""}]

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
08 Mai 2024 19:07 #5 par bobendylon
Réponse de bobendylon sur le sujet node Red -> MQTT
Quelle est ta domotique?
Cela est super intéressant et je l'adapterais bien sur Jeedom.

Bob

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
08 Mai 2024 19:10 - 08 Mai 2024 19:11 #6 par ilco
Réponse de ilco sur le sujet node Red -> MQTT
Moi c’est Jeedom aussi. J’utilise simplement MQTT Manager pour l’interfacer, 0 programmation coté Jeedom tout se passe sur NodeRED qui publie et surveille le bon topic.

Par contre Jeedom n’aime pas trop un scenario (il dit l’execution du scenario precedent n’a pas eu le temps de se terminer blabla) sur chaque variation de donnée du MSunPV, si on actualise toutes les 10 secondes ou moins. Je suis monté a 20 secondes et c’est bon.
Dernière édition: 08 Mai 2024 19:11 par ilco.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
15 Juil 2024 21:03 #7 par Forhorse
Réponse de Forhorse sur le sujet node Red -> MQTT
Après des années avec un script PHP dans un scenario Jeedom qui fonctionnait parfaitement bien, j'ai eu envie moi aussi de publier les données de mon Maxisun par MQTT, j'étais sur le point de me casser à tête à écrire un flux moi même quand je suis tombé sur ce sujet.
Merci, ça m'a déjà donné une bonne ébauche !

(J'ai du modifier un peu car j'ai un Maxisun dont le firmware n'a jamais été mis à jour, la structure du fichier XML est un peu différente)
Maintenant j'aimerais publier les valeurs des sondes qui m’intéressent dans des topics séparés plutôt que d'avoir un bloc JSON avec tout dedans. ça devrait être jouable.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
15 Juil 2024 21:14 #8 par ilco
Réponse de ilco sur le sujet node Red -> MQTT
Si tu fais la modif de manière élégante ca m'intéresse!! Perso je ne sais que le faire séparer avec plein de blocs, donc quand il y 3 information ca va, mais quand il y en a 30 c’est vite beaucoup de blocs qui se perdent sur le graph, et pas très générique…

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
15 Juil 2024 22:01 #9 par Forhorse
Réponse de Forhorse sur le sujet node Red -> MQTT
J'ai fait ça d'une façon qui me va pas mal.
Déjà il faut virer ton nœud qui définit le topic juste avant le nœud d'envois MQTT.
Le topic MQTT reprend celui du "msg" nodeRED donc pour définir le topic dans la fonction, il suffit d'écrire un truc genre msg.topic = "msunpv/data"
Donc chaque topic différent peut être publié par ce mécanisme.
pour la payload c'est parreil...
ensuite il suffit d'utiliser node.send(msg) autant de fois que nécessaire après avoir définit les differents couples topic/payload.

Pour mes sondes, j'ai créer un tableau avec mes différents topics, ensuite une boucle for vient parcourir à la fois mon tableau de topic (qui est ajouté au topic "racine"), et à la fois les valeurs de inAns avec un chaque fois un node.send
ça fonctionne nickel.

Connexion ou Créer un compte pour participer à la conversation.

Propulsé par Kunena