🔠 WIKI : Modbus sur V5

Bonjour à tous,
L’IPX800 V5 a introduit de nombreuses nouveautés, notamment le support du protocole Modbus. Ce protocole, bien que méconnu de certains, est une véritable porte d’entrée vers la communication avec des appareils industriels, intelligents et communicants.

Modbus, qui existe depuis plus de 40 ans, est largement développé et déployé, et il est aujourd’hui complètement ouvert. Grâce à lui, il devient possible de piloter des climatiseurs, des pompes, des installations photovoltaïques, de faire des relevés de compteurs, utiliser des capteurs complexes, piloter/interroger/surveiller des bornes de recharges pour véhicules électriques et bien plus encore.

Pour ceux qui hésitent à faire le premier pas ou qui connaissent le protocole mais ne savent pas l’exploiter avec l’IPX800 V5, j’ai créé un nouveau wiki. Ce guide n’est pas exhaustif, mais il vient en complément des guides utilisateurs existants pour vous aider à intégrer Modbus dans votre installation.

Modbus et IPX800 V5 — GCE Electronics (gce-electronics.com)

Bonne lecture.

Bonjour,

merci @fgtoul pour avoir, encore une fois, fait un wiki exhaustif et à la portée de tous…
Sacré challenge :wink:
Hélas le fabricant de ma VMC DF thermodynamique ne documente pas les registres de ses ports ModBus… :cry:, j’aurais adoré l’interfacer avec ma domotique…

Bonne journée

Bonjour @grocrabe

Même avec un scanner de données modbus ?

En lisant le wiki de @fgtoul il y avait la piste … :stuck_out_tongue_winking_eye:
Pour lire les trames sur le bus RTU, vous pouvez utiliser divers logiciels gratuits disponibles sur le Web (Modbus Doctor, Simply Modbus Master, Open ModScan, ModRSsim)

@fgtoul

Super tuto comme d’hab (survolé, lecture en détail ce soir quand tout le monde dort ! :slight_smile:

Intéressant la partie adaptateur usb rs485, il faudra que j’essaie de voir ce que cela pourrait donner si il était relié entre l’ipx800v5 et le nrx800 et avec les nodes et flows modbus de node-red :thinking:

Super tuto !

Merci @fgtoul
J’ai lu le dossier et appris plein de chose ! Merci !

Je crois avoir déjà la réponse mais pour être sur de ne rien raté, je n’ai aucune possibilité pour faire communiquer 2 équipements Maitres en TCP, l’IPX ne peut pas être configurée en esclave ?

Détail :
J’ai un CMI pour le contrôle de mon installation solaire thermique qui me permet d’accéder à distance et de faire le logging des données. Il se trouve qu’il peut réémettre en modbus TCP les valeurs ana mesurées sur la ligne du bus propriétaire. Mais il ne fonctionne qu’en Maitre.

Merci et @+

plusieurs possibilités :

  • Certains appareils sont à la fois maitres et esclaves. L’ipx ne pouvant pas être esclave, il faut vérifier si l’autre équipement a des fonctions esclaves (dans ce cas 2 réseaux rtu donc 2 ports série sinon passerelle TCP).
  • il est peut-être possible de développer à moindre frais un équipement avec un esp32, qui pourrait être esclave des 2 dispositifs. Il faut alors créer 2 bus RTU distincts, 1 pour l’ipx, l’autre pour le CMI. Sur esp32 il faudra donc 2 ports série, chacun correctement configuré pour le maître connecté). Il faut analyser les possibilités lecture/écriture de chaque appareil pour connaitre la faisabilité. Il faudra 2 convertisseurs UART/RS485 type MAX485

Grand grand merci Fgtoul,

c’était tellement nécessaire, et attendu (au moins par moi).

@fgtoul

J’ai pris le temps de lire hier le wiki et :+1:

Pas certain de résister à l’envie de commander un adaptateur et voir ce qu’il est possible de faire entre le NRX800 et l’IPX800V5 ! :thinking:

Quand on voit le prix de certaines passerelles industrielles (par ex # Passerelle Modbus RTU / Modbus TCP – MR-GW à presque 300€) et

On se dit que si @GCE manque d’idée :exploding_head:de modules à développer, on peut lui en trouver ! :joy:

Merci pour les idées !

Mon CMI ne peut fonctionner qu’en TCP et qu’en Master.

Les solutions de développement de passerelle à base d’ESP32 me font de l’oeil (surtout que j’ai des ESP32 qui dorment dans le tiroir) mais honnêtement le temps à passer sur la solution relativement à ce que je vais pouvoir faire de ces infos dans l’IPX ne vaut pas la chandelle.

En revanche, le fait que @cce66 parle du NRX800 me fait penser à une solution potentielle à tester.
Je crois qu’il existe des noeuds Modbus dans NodeRed.
Si j’arrive à avoir un noeud Slave sur un port qui reçoit les infos du CMI, puis à transférer ces infos (sous forme d’objet json) à un autre Noeud Slave sur un autre port, l’IPX pourrait venir lire les données.
C’est qu’un concept mais à voir.

Merci en tout cas pour le partage de réflexion !

@Mistoukwak

Le nrx800 ayant 4 port usb…cela devrait permettre de faire communiquer plusieurs réseau RTU (donc plusieurs maitre RTU) à travers node-red

Oui, il faut charger le node @kenke7/node-red-contrib-modbus via la palette

après il y a des exemples de flux, en voila un (il faudra changer les ip dans les nodes fonctions (ça peut être remplacé par une variable globale)

exemple modbus

[
{
« id »: « 9ac44469.cc7228 »,
« type »: « tab »,
« label »: « ModBus Video2 »,
« disabled »: false,
« info »: «  »
},
{
« id »: « 96de127a.bd15c8 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Read 32bit Float »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 380,
« wires »: [
[
« 566b0e78.c05cd8 »
]
]
},
{
« id »: « ddf1db44.1476d8 »,
« type »: « debug »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« active »: true,
« tosidebar »: true,
« console »: false,
« tostatus »: false,
« complete »: « true »,
« x »: 980,
« y »: 320,
« wires »:
},
{
« id »: « 31e61877.807318 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 16 Bit INT 16001 »,
« func »: « var fc=3;\nvar sa=3;\nvar addresses=1;\nvar slave_ip=msg.payload.slave_ip;\n\nmsg.slave_ip="192.168.1.31";\n\nmsg.payload={value: msg.payload, ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 360,
« y »: 80,
« wires »: [
[
« 34dfb4ef.ddcd54 »
]
]
},
{
« id »: « baa3384.02ce6c8 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write-Float -6001.5 »,
« func »: « \nvar fc=16;\nvar sa=70;\nvar addresses=2;\nvar value=16001.5;\nbuf=Buffer.alloc(4);\nbuf.writeFloatBE(value);\n//buf.writeFloatBE(16001.5);\nvar values=[(buf[0]*256+buf[1]),(buf[2]*256)+buf[3]]\nmsg.slave_ip="192.168.1.31";\nmsg.payload={"value":values , ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 370,
« y »: 730,
« wires »: [
[
« f4fc3e03.1f01a8 »
]
]
},
{
« id »: « cabf85be.1bf138 »,
« type »: « debug »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« active »: true,
« tosidebar »: true,
« console »: false,
« tostatus »: false,
« complete »: « true »,
« x »: 840,
« y »: 700,
« wires »:
},
{
« id »: « 7119790f.f69ae8 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Read 16bit Integer »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 80,
« wires »: [
[
« 31e61877.807318 »
]
]
},
{
« id »: « c5845d88.636798 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« func »: « const buf = Buffer.from(msg.payload.buffer);\nconst value = buf.readUInt16BE();\nmsg.value = value;\n\nnode.status({fill:"red",shape:"ring",text:msg.value});\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 770,
« y »: 120,
« wires »: [
[
« ddf1db44.1476d8 »
]
]
},
{
« id »: « caa6eb97.8c27a8 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write32Float »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 730,
« wires »: [
[
« baa3384.02ce6c8 »
]
]
},
{
« id »: « cb22647c.70bd8 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Read 32bit Integer »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 180,
« wires »: [
[
« c01fcee9.65817 »
]
]
},
{
« id »: « cb59ac65.5600e8 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« func »: « const buf = Buffer.from(msg.payload.buffer);\nconst value = buf.readUInt32BE();\nmsg.value = value;\n\nnode.status({ fill: "red", shape: "ring", text: msg.value });\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 770,
« y »: 220,
« wires »: [
[
« ddf1db44.1476d8 »
]
]
},
{
« id »: « c01fcee9.65817 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 32bit int »,
« func »: « var fc=3;\nvar sa=5;\nvar addresses=2;\nvar slave_ip=msg.payload.slave_ip;\nmsg.slave_ip="192.168.1.31";\nmsg.payload={value: msg.payload, ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 340,
« y »: 180,
« wires »: [
[
« 3eed334e.35f204 »
]
]
},
{
« id »: « 566b0e78.c05cd8 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: "32Bit Float ",
« func »: « var fc=3;\nvar sa=10;\nvar addresses=2;\nvar slave_ip=msg.payload.slave_ip;\nmsg.slave_ip="192.168.1.31";\nmsg.payload={value: msg.payload, ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 340,
« y »: 380,
« wires »: [
[
« e230adfe.a4fec8 »
]
]
},
{
« id »: « 47d293d3.7b1884 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« func »: « const buf = Buffer.from(msg.payload.buffer);\nconst value = buf.readFloatBE();\nmsg.value = value;\n\nnode.status({ fill: "red", shape: "ring", text: msg.value });\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 770,
« y »: 420,
« wires »: [
[
« ddf1db44.1476d8 »
]
]
},
{
« id »: « 64392f40.43711 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write32INT »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 140,
« y »: 670,
« wires »: [
[
« f50b840c.c18bf »
]
]
},
{
« id »: « f50b840c.c18bf »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « write 100-32 bit »,
« func »: « \nvar fc=16;\nvar sa=50;\nvar addresses=2;\nvar buf=Buffer.alloc(4);\nbuf.writeInt32BE(68001);\nvar values=[(buf[0]*256+buf[1]),(buf[2]*256)+buf[3]]\nmsg.slave_ip="192.168.1.76";\nmsg.payload={"value":values , ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 360,
« y »: 670,
« wires »: [
[
« af670de6.a7f78 »
]
]
},
{
« id »: « d362d1d1.1b4be8 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write16INT »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 140,
« y »: 630,
« wires »: [
[
« d7ebe300.c793b »
]
]
},
{
« id »: « d7ebe300.c793b »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write 16001-16bit »,
« func »: « \nvar fc=6;\nvar sa=40;\nvar addresses=1;\nvar value=16001;\n\nmsg.slave_ip="192.168.1.76";\nmsg.payload={"value":value , ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 370,
« y »: 630,
« wires »: [
[
« aaf7e636.b5f6c »
]
]
},
{
« id »: « 52e66b6f.961fbc »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Buffer »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « str »,
« x »: 120,
« y »: 120,
« wires »: [
[
« 53259c2b.78ee8c »
]
]
},
{
« id »: « 53259c2b.78ee8c »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 16 Bit INT 16001 »,
« func »: « msg.payload={};\nvar buf=Buffer.alloc(2);\nbuf.writeInt16BE(16001);\nmsg.payload.buffer=buf;\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 360,
« y »: 120,
« wires »: [
[
« c5845d88.636798 »
]
]
},
{
« id »: « 476b2785.d6a77 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 32 bit INT 16001 »,
« func »: « msg.payload={};\nvar buf=Buffer.alloc(4);\nbuf.writeInt32BE(16001);\nmsg.payload.buffer=buf;\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 360,
« y »: 220,
« wires »: [
[
« cb59ac65.5600e8 »
]
]
},
{
« id »: « d0b659df.000dd »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Buffer »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « str »,
« x »: 120,
« y »: 220,
« wires »: [
[
« 476b2785.d6a77 »
]
]
},
{
« id »: « 4945ef0e.4d3a08 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 32Bit Float 16001.5 »,
« func »: « msg.payload={};\nvar buf=Buffer.alloc(4);\nbuf.writeFloatBE(16001.5);\nmsg.payload.buffer=buf;\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 370,
« y »: 420,
« wires »: [
[
« 47d293d3.7b1884 »
]
]
},
{
« id »: « a82b7fab.ce486 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Buffer »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « str »,
« x »: 120,
« y »: 420,
« wires »: [
[
« 4945ef0e.4d3a08 »
]
]
},
{
« id »: « 35c4cb5c.8a2904 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Read 32bit Integer »,
« props »: [
{
« p »: « payload »
},
{
« p »: « topic »,
« vt »: « str »
}
],
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 280,
« wires »: [
[
« fde4a066.74f5a8 »
]
]
},
{
« id »: « a68f30f7.4919c »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Buffer »,
« props »: [
{
« p »: « payload »,
« v »: «  »,
« vt »: « str »
},
{
« p »: « topic »,
« v »: «  »,
« vt »: « str »
}
],
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « str »,
« x »: 120,
« y »: 320,
« wires »: [
[
« 5fcfd729.dd1cc »
]
]
},
{
« id »: « 5fcfd729.dd1cc »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 32 bit INT 68001 »,
« func »: « msg.payload={};\nvar buf=Buffer.alloc(4);\nbuf.writeInt32BE(68001);\nmsg.payload.buffer=buf;\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 360,
« y »: 320,
« wires »: [
[
« 436ffd6e.0c775c »
]
]
},
{
« id »: « fde4a066.74f5a8 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 32bit int »,
« func »: « var fc=3;\nvar sa=7;\nvar addresses=2;\nvar slave_ip=msg.payload.slave_ip;\nmsg.slave_ip="192.168.1.31";\nmsg.payload={value: msg.payload, ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 340,
« y »: 280,
« wires »: [
[
« c58a5ca.3ac842 »
]
]
},
{
« id »: « 436ffd6e.0c775c »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« func »: « const buf = Buffer.from(msg.payload.buffer);\nconst value = buf.readUInt32BE();\nmsg.value = value;\n\nnode.status({ fill: "red", shape: "ring", text: msg.value });\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 770,
« y »: 320,
« wires »: [
[
« ddf1db44.1476d8 »
]
]
},
{
« id »: « 4c0616be.21cbf8 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Read 64bit Float »,
« props »: [
{
« p »: « payload »
},
{
« p »: « topic »,
« vt »: « str »
}
],
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 480,
« wires »: [
[
« d3420f51.965d6 »
]
]
},
{
« id »: « 83f93b76.ba2d08 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Buffer »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « str »,
« x »: 120,
« y »: 520,
« wires »: [
[
« 837d646.ea99c98 »
]
]
},
{
« id »: « d3420f51.965d6 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: "64Bit Float ",
« func »: « var fc=3;\nvar sa=20;\nvar addresses=4;\nvar slave_ip=msg.payload.slave_ip;\nmsg.slave_ip="192.168.1.31";\nmsg.payload={value: msg.payload, ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 340,
« y »: 480,
« wires »: [
[
« 9b4d57fa.db2 »
]
]
},
{
« id »: « 837d646.ea99c98 »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « 64Bit Float 16001.5 »,
« func »: « msg.payload={};\nvar buf=Buffer.alloc(8);\nbuf.writeDoubleBE(16001.5);\nmsg.payload.buffer=buf;\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 370,
« y »: 520,
« wires »: [
[
« b51b0f10.e12da »
]
]
},
{
« id »: « b51b0f10.e12da »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« func »: « const buf = Buffer.from(msg.payload.buffer);\nconst value = buf.readDoubleBE();\nmsg.value = value;\n\nnode.status({ fill: "red", shape: "ring", text: msg.value });\n\nreturn msg; »,
« outputs »: 1,
« timeout »: «  »,
« noerr »: 0,
« initialize »: «  »,
« finalize »: «  »,
« libs »: ,
« x »: 770,
« y »: 520,
« wires »: [
[
« ddf1db44.1476d8 »
]
]
},
{
« id »: « 9eb27939.75ca48 »,
« type »: « inject »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write64Float »,
« repeat »: «  »,
« crontab »: «  »,
« once »: false,
« onceDelay »: 0.1,
« topic »: «  »,
« payload »: «  »,
« payloadType »: « date »,
« x »: 150,
« y »: 770,
« wires »: [
[
« dc5dba61.c580d »
]
]
},
{
« id »: « dc5dba61.c580d »,
« type »: « function »,
« z »: « 9ac44469.cc7228 »,
« name »: « Write-Float -16001.5 »,
« func »: « \nvar fc=16;\nvar sa=80;\nvar addresses=4;\nvar value=16001.5;\nbuf=Buffer.alloc(8);\nbuf.writeDoubleBE(value);\n//buf.writeFloatBE(16001.5);\nvar values=[(buf[0]*256+buf[1]),(buf[2]*256)+buf[3],(buf[4]*256+buf[5]),(buf[6]*256)+buf[7]];\n\nmsg.slave_ip="192.168.1.76";\nmsg.payload={"value":values , ‹ fc ›: fc, ‹ unitid ›: 1, ‹ address ›: sa , ‹ quantity ›: addresses };\nreturn msg; »,
« outputs »: 1,
« noerr »: 0,
« x »: 370,
« y »: 770,
« wires »: [
[
« dc7b17fa.0490d »
]
]
},
{
« id »: « f4fc3e03.1f01a8 »,
« type »: « modbus-flex-write »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« showStatusActivities »: false,
« showErrors »: false,
« server »: « 54dde46e.53267c »,
« x »: 580,
« y »: 730,
« wires »: [
,
[
« cabf85be.1bf138 »
]
]
},
{
« id »: « af670de6.a7f78 »,
« type »: « modbus-flex-write »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« showStatusActivities »: false,
« showErrors »: false,
« server »: « 54dde46e.53267c »,
« x »: 580,
« y »: 670,
« wires »: [
,
[
« cabf85be.1bf138 »
]
]
},
{
« id »: « aaf7e636.b5f6c »,
« type »: « modbus-flex-write »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« showStatusActivities »: false,
« showErrors »: true,
« server »: « 54dde46e.53267c »,
« x »: 580,
« y »: 630,
« wires »: [
,
[
« cabf85be.1bf138 »
]
]
},
{
« id »: « dc7b17fa.0490d »,
« type »: « modbus-flex-write »,
« z »: « 9ac44469.cc7228 »,
« name »: «  »,
« showStatusActivities »: false,
« showErrors »: false,
« server »: « 54dde46e.53267c »,
« x »: 580,
« y »: 770,
« wires »: [
,
[
« cabf85be.1bf138 »
]
]
},
{
« id »: « 34dfb4ef.ddcd54 »,
« type »: « modbus-flex-getter »,
« z »: « 9ac44469.cc7228 »,
« name »: « local getter »,
« showStatusActivities »: true,
« showErrors »: true,
« showWarnings »: true,
« logIOActivities »: false,
« server »: « 54dde46e.53267c »,
« useIOFile »: false,
« ioFile »: «  »,
« useIOForPayload »: false,
« emptyMsgOnFail »: false,
« keepMsgProperties »: false,
« delayOnStart »: false,
« startDelayTime »: «  »,
« x »: 560,
« y »: 80,
« wires »: [
,
[
« c5845d88.636798 »
]
]
},
{
« id »: « 3eed334e.35f204 »,
« type »: « modbus-flex-getter »,
« z »: « 9ac44469.cc7228 »,
« name »: « local getter »,
« showStatusActivities »: true,
« showErrors »: true,
« logIOActivities »: false,
« server »: « 54dde46e.53267c »,
« useIOFile »: false,
« ioFile »: «  »,
« useIOForPayload »: false,
« x »: 560,
« y »: 180,
« wires »: [
,
[
« cb59ac65.5600e8 »
]
]
},
{
« id »: « e230adfe.a4fec8 »,
« type »: « modbus-flex-getter »,
« z »: « 9ac44469.cc7228 »,
« name »: « local getter »,
« showStatusActivities »: true,
« showErrors »: true,
« logIOActivities »: false,
« server »: « 54dde46e.53267c »,
« useIOFile »: false,
« ioFile »: «  »,
« useIOForPayload »: false,
« x »: 560,
« y »: 380,
« wires »: [
,
[
« 47d293d3.7b1884 »
]
]
},
{
« id »: « c58a5ca.3ac842 »,
« type »: « modbus-flex-getter »,
« z »: « 9ac44469.cc7228 »,
« name »: « local getter »,
« showStatusActivities »: true,
« showErrors »: true,
« logIOActivities »: false,
« server »: « 54dde46e.53267c »,
« useIOFile »: false,
« ioFile »: «  »,
« useIOForPayload »: false,
« x »: 560,
« y »: 280,
« wires »: [
,
[
« 436ffd6e.0c775c »
]
]
},
{
« id »: « 9b4d57fa.db2 »,
« type »: « modbus-flex-getter »,
« z »: « 9ac44469.cc7228 »,
« name »: « local getter »,
« showStatusActivities »: true,
« showErrors »: true,
« logIOActivities »: false,
« server »: « 54dde46e.53267c »,
« useIOFile »: false,
« ioFile »: «  »,
« useIOForPayload »: false,
« x »: 560,
« y »: 480,
« wires »: [
,
[
« b51b0f10.e12da »
]
]
},
{
« id »: « 54dde46e.53267c »,
« type »: « modbus-client »,
« name »: « local »,
« clienttype »: « tcp »,
« bufferCommands »: true,
« stateLogEnabled »: true,
« tcpHost »: « 192.168.1.31 »,
« tcpPort »: « 502 »,
« tcpType »: « DEFAULT »,
« serialPort »: « /dev/ttyUSB »,
« serialType »: « RTU-BUFFERD »,
« serialBaudrate »: « 9600 »,
« serialDatabits »: « 8 »,
« serialStopbits »: « 1 »,
« serialParity »: « none »,
« serialConnectionDelay »: « 100 »,
« unit_id »: 1,
« commandDelay »: 1,
« clientTimeout »: 1000,
« reconnectTimeout »: 2000
}
]

Il y a aussi des exemples (mais il faut y penser :exploding_head:), il faut passer par le menu et cliquer sur « Importer »

image

puis dans la fenêtre « Importer des noeuds » i faut cliquer sur « Exemples » et choisir un exemple de flux à importer…rapide non ! :slight_smile:

image

Tu peux aussi trouver des exemples de node, flows et collections ici (9 pages :slight_smile: )

https://flows.nodered.org/search?term=modbus

Bon, si tu n’as pas de NRX800…je sens que la CB va chauffer ! :rofl:

Pour que NRX, IPX et CMI communiquent, il faudra tout de même une passerelle tcp au minimum, :wink:, ce sera plus couteux qu’un esp32,

Pour un ESP32 esclave des 2 maîtres (sans NRX du coup), il suffit de créer 2 ports série avec une instance Modbus sur chacun, créer des registres partagés et en empêcher la lecture par l’ipx pendant que le CMI écrit une nouvelle valeur, pas besoin de sécuriser les communications avec le développement d’une gestion complexe anti-collision.
1 ESP et 2 MAX485 coûteront moins cher qu’une passerelle vu que NRX n’a pas de port série à moins de sacrifier 2 ports usb pour y mettre 2 adaptateurs usb/rs485.

Je sais qu’il y a des adeptes de ChatGPT pour générer le code :wink:
Avec les pistes ci-dessus, ça devrait le faire.

Mais, comme dit plus haut, tout dépend des capacités à communiquer du CMI (combien de ports modbus ? fonctions esclaves également ?; capacité à envoyer la valeur de ses propres registres ?..)
Il faut d’abord voir ce qu’il est capable de faire pour définir la solution adaptée.

Bonjour @fgtoul

Comment cela le NRX800 n’a port de port série ? Il en a 4 enfin presque si on met le cable ad-hoc (usb/db9) je pilote mon firewall comme cela ! :wink:

Ce que je disais plus haut doit être possible, non ? (je ne suis pas expert modbus même si ton wiki m’a grandement éclairé pour ne pas dire initié :+1:)

Des exemples d’adaptateurs USB RS485 (moins de 30€ chaque il y en a à moins de 15€ aussi)

DSD TECH SH-U10L Câble USB vers RS485

Benefischl -DR302 Rail DIN SéRie RS485

KALEA-INFORMATIQUE Convertisseur USB vers RS422 RS485 avec Chipset FTDI FT232

Franchement moi j’avoue qu’en tant qu’ancien programmeur (c’est mieux que programmeur ancien ! :rofl:) que ChatGPT avec Google sont des formidables outils (cela enlève 80% de boulot enfin si on fait la bonne requête :wink: ). Quand je compare à avant ou pour écrire un programme, programmer une API ou paramétrer des systèmes il fallait se cogner de la doc par kilo et surtout se rappeler dans quelle doc ou bouquin ou avait vu l’info et que entre la programmation linéaire des années 85-95 puis la prog objet avec API venue après et maintenant la prog web app après ça n’a jamais arrêté d’évoluer !
Et puis un bon artisan doit savoir utiliser les bons outils ! :joy:

j’avais complété mon post.
Si le NRX n’a pas d’autre fonction que modbus, je trouve cela fort dommage pour le portefeuille ;).
Mes réponses étaient calibrées pour @Mistoukwak qui a déjà des ESP mais pas de NRX. Donc à moindre frais, il n’y a pas photo.

Pas faux ! :slight_smile:
Mais en même temps comme il parait que l’appétit vient en mangeant, les besoins du NRX800 peuvent venir en l’utilisant ! :rofl:
Non plus sérieusement c’est vrai que là il y a pas photos ! :+1:

Par contre pour cette partie, tu pense que ce serait possible sinon ? Voire faire avec le NRX800 et ses 4 ports USB une passerelle entre du modbus RTU (slave ou maitre) et du modbus TCP ?

oui c’est possible je pense, cela est sous-jacent à ma proposition de développement d’esclaves avec des MBC et 2 ports série :slight_smile: Reste à voir comment gérer les collisions lorsque le NRX passera les valeurs de l’un à l’autre (cas des registres non partagés) ou savoir si le flow Nodered sait gérer des registres partagés :thinking:

Il est possible de gérer l’envoi des données avec un node délai

Sinon il est possible de recevoir les différents flux des ports série les données puis les envoyer au fur et à mesure dans une liste avec un traitement FIFO séquentiel de la liste avec un node delay de 3s entre chaque envoi vers les sorties port serie

ChatGPT ? :joy: :wink:

Salut @fgtoul et @cce66 ,

Ben si justement j’ai un NRX800 ! :sweat_smile:
Désolé si c’était pas clair.

Je pense que j’ai mal compris quelque chose ?!

J’ai 2 équipements (IPX800 et CMI) qui sont des équipements réseaux (connectés sur mon switch et donc mon routeur). Les 2 ont de quoi communiquer en Modbus TCP.
Le NRX800 est aussi sur le même réseau.
Ma passerelle c’est donc mon routeur non ?

Une passerelle c’est ce qui permet de passer d’un réseau à un autre réseau que ce soit de façon logicielle ou matérielle
Ton switch sert à relier les équipements sur un même réseau physique et pour que ceux-ci puissent communiquer ils doivent utiliser un même protocole et un même adressage réseau (192.168.x.x etc pour la partie privé), ta passerelle c’est ta box qui permet de communiquer d’un réseau privé (192.168.) vers le réseau internet (toutes les autres adresses sauf les privées).
Avec le NRX800 et node-red tu peux avec les port usb brancher des adaptateurs usb/modbus (RTU/TCP) et faire communiquer plusieurs réseau modbus RTU (en TCP le problème se posent pas si j’ai bien tout compris) donc dans ce cas le NRX800 est une passerelle ! On pourrait faire de même avec des adaptateurs USB/RJ45 et faire communiquer des réseaux différents (192.168.x.x vers 10.x.x.x) avec node-red mais cela n’aurait pas d’intérêt car le traitement serait lourd et un routeur le fait très bien pour un cout dérisoire !

Oups :blush:
Ayant mal lu ton post initial et n’ayant donc pas vu que le cmi était en modbus TCP, je partais du principe qu’il était en RTU, d’où la suggestion d’une passerelle rtu/tcp.
Si tous les appareils sont tcp, il n’y a donc effectivement plus besoin de passerelle ni adaptateur rs485.

@fgtoul

Le problème est bien que le CMI n’est que maitre, l’ipx800v5 aussi et qu’il faut donc un nrx800 sur lequel avec 2 ports usb il y aurait d’installé 1 slave lié au cmi et 1 slave lié à l’ipx flows node-red pour faire le pont entre les 2 car l’ipx et un ne peut aller lire les données sur le cmi, on est d’accord sur le principe ou l’ipx peut aller directement lire les données sur le cmi ? :exploding_head: