Node-RED und MQTT Erweitert

Verwenden eines UI-Formularelements zum Festlegen einer globalen Anmeldung

Im letzten Abschnitt haben wir eine Schaltfläche verwendeten, um eine Nachricht über MQTT an unsere Node-RED-Installation zu senden. Diese Nachricht hat dann das Senden eines CGI-Befehls über HTTP an die REST-API unserer Kamera ausgelöst.

Der Code, den wir hatten, war aufgrund der fest codierten IP-Adresse und des Kamera-Logins nicht wiederverwendbar (er funktioniert nur mit dieser einen Kamera). Wir möchten nun ein Login-Formular in unserer Dashboard-Benutzeroberfläche erstellen, das die IP-Adresse, den Benutzernamen und das Passwort erhält. Dieser Flow sollte diese dann direkt über MQTT veröffentlichen, damit wir den aktuellen Status von anderen Flows abonnieren können. Auf diese Weise werden diese Funktionen automatisch aktualisiert, sobald neue Logindaten an das Formularelement übergeben werden.

Node-RED

Den Quellcode dafür finden Sie am Ende dieses Artikels. Bitte kopieren Sie beide Teile, den Login Flow und anschließend den getserverinfo Flow und importieren sie diese über den Import-Dialog nach Node-RED (wie im vorherigen Abschnitt):

Node-RED

Login Form

Wenn Sie auf den ersten Knoten des Global Login-Flows doppelklicken, sehen Sie, dass es ein Formknoten ist, der unserem Dashboard drei Eingabefelder hinzufügt:

Node-RED

Wir können die Ausgabe des Form Node testen, indem Sie einen Debug Node hinzufügen. Hängen Sie diesen Knoten direkt an den Formularknoten an und aktivieren Sie den Flow (Deploy). Öffnen Sie danach http://localhost:1880/dashboard/ in Ihrem Browser und geben Sie die IP-Adresse Ihrer Kamera sowie die Administratoranmeldung ein:

Node-RED

MQTT Node

Nach dem Absenden des Formulars sollten die Systeminformationen Ihres Kamerasystems angezeigt werden. Wenn Sie zu unserem Flow zurückkehren, sehen Sie auch die Debug-Informationen, die an den verbundenen MQTT Node gesendet wurden:

{
    "ip": "192.168.1.52",
    "user": "admin",
    "password": "instar"
}

Node-RED

Die MQTT-Publikation folgt unter dem Thema ipcam/login (doppelklicken Sie auf den MQTT-Ausgabeknoten, um dieses zu verifizieren). Das bedeutet, dass wir nun einen MQTT Eingangsknoten mit jedem Flow verbinden können, ihn ipcam/login abonnieren lassen und die Login-Informationen über MQTT erhalten können.

getserverinfo Flow

Node-RED

Der erste Knoten empfängt die Anmeldeinformationen, führt sie durch einen JSON-Knoten, um sie in ein JavaScript-Objekt umzuwandeln, und importiert sie dann in einen Funktionsknoten, mit dem wir den CGI-Befehl erstellen. Der CGI Befehl wird anschließend an die REST-API der Kamera gesendet:

var ip = msg.payload.ip;
var user = msg.payload.user;
var password = msg.payload.password;

msg.topic = "getserverinfo";
msg.payload = ip+"/param.cgi?cmd=getserverinfo&-usr="+user+"&-pwd="+password;
return msg;

Um den Fluss hübscher zu machen, können wir dem Funktionsknoten zusätzlich einen Zeitstempel hinzufügen, der unterhalb des Knoten anzeigt wird, und die Zeit trägt, wann die Funktion zuletzt ausgelöst wurde (optional - aber zum Fehlerbeheben teilweise recht nützlich):

// Update the status with current timestamp
var now = new Date();
var yyyy = now.getFullYear();
var mm = now.getMonth() < 9 ? "0" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based
var dd  = now.getDate() < 10 ? "0" + now.getDate() : now.getDate();
var hh = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
var mmm  = now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
var ss  = now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
var currenttime= hh + ":" + mmm + ":" + ss;
var currentdate= dd + "." + mm + "." + yyyy;

node.status({fill:"blue",shape:"ring",text:"Last updateChanged: " + currentdate + " - " + currenttime});

Der Rest des Codes ist identisch mit dem Code, den wir zuvor geschrieben haben. Wir legen die erstellte Zeichenfolge als URL des HTTP GET Node fest, der den CGI-Befehl an unsere Kamera sendet. Die Kameraantwort wird dann in ein Javascript-Objekt umgewandelt und an Textfelder in unserem Node-RED-Dashboard gesendet:

Node-RED

JSON Code export

Global Login

[{"id":"2cc6b79f.c6bbe8","type":"ui_form","z":"13bcbd83.ab1fe2","name":"Camera Address","label":"Change Address","group":"c0689660.4e98c8","order":0,"width":0,"height":0,"options":[{"label":"IP Address","value":"ip","type":"text","required":true},{"label":"Username","value":"user","type":"text","required":true},{"label":"Password","value":"password","type":"password","required":true}],"formValue":{"ip":"","user":"","password":""},"payload":"","submit":"Submit","cancel":"Cancel","topic":"user_set","x":90,"y":180,"wires":[["88c16822.071318"]]},{"id":"cc9d17da.1cb338","type":"comment","z":"13bcbd83.ab1fe2","name":"Set Login Global","info":"","x":90,"y":120,"wires":[]},{"id":"88c16822.071318","type":"mqtt out","z":"13bcbd83.ab1fe2","name":"","topic":"ipcam/login","qos":"","retain":"","broker":"47feb3e4.56f11c","x":140,"y":240,"wires":[]},{"id":"c0689660.4e98c8","type":"ui_group","z":"","name":"Camera Login","tab":"7a3391b6.03a81","order":1,"disp":true,"width":"6","collapse":false},{"id":"47feb3e4.56f11c","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"7a3391b6.03a81","type":"ui_tab","z":"","name":"Wiki Tutorial","icon":"dashboard"}]

CGI Response for getserverinfo

[{"id":"ac242510.97db68","type":"http request","z":"13bcbd83.ab1fe2","name":"getserverinfo","method":"GET","ret":"txt","url":"","tls":"","x":410,"y":220,"wires":[["a12e8db8.35994","666a1b4a.34a9a4"]]},{"id":"6c7c8dd0.47fbc4","type":"debug","z":"13bcbd83.ab1fe2","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":490,"y":280,"wires":[]},{"id":"a12e8db8.35994","type":"string","z":"13bcbd83.ab1fe2","name":"toJSON","methods":[{"name":"delRightMost","params":[{"type":"str","value":";"}]},{"name":"append","params":[{"type":"str","value":" }"}]},{"name":"prepend","params":[{"type":"str","value":"{ "}]},{"name":"replaceAll","params":[{"type":"str","value":"var "},{"type":"str","value":"\""}]},{"name":"replaceAll","params":[{"type":"str","value":"="},{"type":"str","value":"\":"}]},{"name":"replaceAll","params":[{"type":"str","value":";"},{"type":"str","value":","}]}],"prop":"payload","propout":"payload","object":"msg","objectout":"msg","x":310,"y":280,"wires":[["6c7c8dd0.47fbc4","7fcdef72.9d0ad"]]},{"id":"7fcdef72.9d0ad","type":"json","z":"13bcbd83.ab1fe2","name":"","property":"payload","action":"","pretty":false,"x":350,"y":380,"wires":[["85ab24c9.c72438","db9fc761.e39c78","1662357a.43fcdb","97b8e776.bc2d28","3156cc1d.d59374","20181942.7f2086","731237ad.db1298","558f4beb.7a05d4","74026d1d.aacb14","c6dc73f5.f9d63","267e6114.855b8e","51831234.f13bbc","9cb9be2b.0adfe","b57c38a3.206f78"]]},{"id":"85ab24c9.c72438","type":"debug","z":"13bcbd83.ab1fe2","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":340,"wires":[]},{"id":"666a1b4a.34a9a4","type":"debug","z":"13bcbd83.ab1fe2","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":590,"y":220,"wires":[]},{"id":"97b8e776.bc2d28","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Firmware","label":"Firmware","format":"{{msg.payload.softVersion}}","layout":"row-spread","x":540,"y":460,"wires":[]},{"id":"db9fc761.e39c78","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Interface","label":"Interface","format":"{{msg.payload.webVersion}}","layout":"row-spread","x":540,"y":500,"wires":[]},{"id":"3156cc1d.d59374","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Designation","label":"Designation","format":"{{msg.payload.name}}","layout":"row-spread","x":540,"y":540,"wires":[]},{"id":"731237ad.db1298","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Device ID","label":"Device ID","format":"{{msg.payload.model}}","layout":"row-spread","x":540,"y":380,"wires":[]},{"id":"558f4beb.7a05d4","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Revision","label":"Revision","format":"{{msg.payload.hardVersion}}","layout":"row-spread","x":530,"y":420,"wires":[]},{"id":"c885359a.ad7d08","type":"function","z":"13bcbd83.ab1fe2","name":"getserverinfo","func":"var ip = msg.payload.ip;\nvar user = msg.payload.user;\nvar password = msg.payload.password;\n\n// Update the status with current timestamp\nvar now = new Date();\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd  = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm  = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss  = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\nvar currenttime= hh + \":\" + mmm + \":\" + ss;\nvar currentdate= dd + \".\" + mm + \".\" + yyyy;\n\nnode.status({fill:\"blue\",shape:\"ring\",text:\"Last updateChanged: \" + currentdate + \" - \" + currenttime});\n\nmsg.topic = \"getserverinfo\";\nmsg.payload = ip+\"/param.cgi?cmd=getserverinfo&-usr=\"+user+\"&-pwd=\"+password;\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":160,"wires":[["6ff16ff3.d7eb4","93a6f3a4.dea83"]]},{"id":"3b9d124a.b870ae","type":"mqtt in","z":"13bcbd83.ab1fe2","name":"","topic":"ipcam/login","qos":"2","broker":"47feb3e4.56f11c","x":260,"y":40,"wires":[["84ac7b9c.d41048","684ca76b.506f88"]]},{"id":"6ff16ff3.d7eb4","type":"debug","z":"13bcbd83.ab1fe2","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":510,"y":100,"wires":[]},{"id":"84ac7b9c.d41048","type":"debug","z":"13bcbd83.ab1fe2","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":450,"y":40,"wires":[]},{"id":"684ca76b.506f88","type":"json","z":"13bcbd83.ab1fe2","name":"","property":"payload","action":"","pretty":false,"x":330,"y":100,"wires":[["c885359a.ad7d08"]]},{"id":"93a6f3a4.dea83","type":"change","z":"13bcbd83.ab1fe2","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":600,"y":160,"wires":[["ac242510.97db68"]]},{"id":"ceb785e3.f052c8","type":"comment","z":"13bcbd83.ab1fe2","name":"getserverinfo CGI","info":"","x":90,"y":40,"wires":[]},{"id":"74026d1d.aacb14","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Active since","label":"Active since","format":"{{msg.payload.startdate}}","layout":"row-spread","x":540,"y":580,"wires":[]},{"id":"1662357a.43fcdb","type":"change","z":"13bcbd83.ab1fe2","name":"change 1/0","rules":[{"t":"change","p":"payload.upnpstatus","pt":"msg","from":"on","fromt":"str","to":"enabled","tot":"str"},{"t":"change","p":"payload.upnpstatus","pt":"msg","from":"off","fromt":"str","to":"disabled","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":620,"wires":[["9266e35e.05e9"]]},{"id":"20181942.7f2086","type":"change","z":"13bcbd83.ab1fe2","name":"change 1/0","rules":[{"t":"change","p":"payload.facddnsstatus","pt":"msg","from":"ok","fromt":"str","to":"active","tot":"str"},{"t":"change","p":"payload.facddnsstatus","pt":"msg","from":"off","fromt":"str","to":"deactivated","tot":"str"},{"t":"change","p":"payload.facddnsstatus","pt":"msg","from":"failed","fromt":"str","to":"connection error","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":660,"wires":[["4f8b632c.0c791c"]]},{"id":"c6dc73f5.f9d63","type":"change","z":"13bcbd83.ab1fe2","name":"change 1/0","rules":[{"t":"change","p":"payload.th3ddnsstatus","pt":"msg","from":"ok","fromt":"str","to":"active","tot":"str"},{"t":"change","p":"payload.th3ddnsstatus","pt":"msg","from":"off","fromt":"str","to":"deactivated","tot":"str"},{"t":"change","p":"payload.th3ddnsstatus","pt":"msg","from":"failed","fromt":"str","to":"connection error","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":700,"wires":[["252d7e10.889722"]]},{"id":"267e6114.855b8e","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Platform Status","label":"Platform Status","format":"{{msg.payload.platformstatus}}","layout":"row-spread","x":550,"y":740,"wires":[]},{"id":"51831234.f13bbc","type":"change","z":"13bcbd83.ab1fe2","name":"change 1/0","rules":[{"t":"change","p":"payload.sdstatus","pt":"msg","from":"out","fromt":"str","to":"no card found","tot":"str"},{"t":"change","p":"payload.sdstatus","pt":"msg","from":"read only","fromt":"str","to":"write protection","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":780,"wires":[["83152650.386d68"]]},{"id":"9cb9be2b.0adfe","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Card Free Space","label":"Card Free Space","format":"{{msg.payload.sdfreespace}}","layout":"row-spread","x":560,"y":820,"wires":[]},{"id":"b57c38a3.206f78","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"Card Total Space","label":"Card Total Space","format":"{{msg.payload.sdtotalspace}}","layout":"row-spread","x":560,"y":860,"wires":[]},{"id":"83152650.386d68","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"SD Card Status","label":"SD Card Status","format":"{{msg.payload.sdstatus}}","layout":"row-spread","x":690,"y":780,"wires":[]},{"id":"252d7e10.889722","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"3rd Party DDNS","label":"3rd Party DDNS","format":"{{msg.payload.th3ddnsstatus}}","layout":"row-spread","x":690,"y":700,"wires":[]},{"id":"4f8b632c.0c791c","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"INSTAR DDNS","label":"INSTAR DDNS","format":"{{msg.payload.facddnsstatus}}","layout":"row-spread","x":690,"y":660,"wires":[]},{"id":"9266e35e.05e9","type":"ui_text","z":"13bcbd83.ab1fe2","group":"6652a2b5.79fc9c","order":2,"width":0,"height":0,"name":"UPnP Status","label":"UPnP Status","format":"{{msg.payload.upnpstatus}}","layout":"row-spread","x":680,"y":620,"wires":[]},{"id":"6652a2b5.79fc9c","type":"ui_group","z":"","name":"/param.cgi?cmd=getserverinfo","tab":"7a3391b6.03a81","order":2,"disp":true,"width":"6","collapse":false},{"id":"47feb3e4.56f11c","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"7a3391b6.03a81","type":"ui_tab","z":"","name":"Wiki Tutorial","icon":"dashboard"}]