NEWS
Leckagesensor SYR Safe-T Connect - how to get it smart
-
Hi @Kachel
vielen Dank auch von mir. Du hast sicherlich viel Zeit in die Analyse gesteckt.Ich bin auch am Überlegen einen Safe-T zu installieren. Voraussetzung wäre aber die Integration in mein ioBroker basiertes Smart-Home, damit ich meine Wassermelder zur Ansteuerung des Safe-T nutzen kann.
kannst du kurz berichten, wie zuverlässig deine Lösung arbeitet? Wenn die Kommunikation langsam ist, vielleicht mehrere Sekunden durch Retries wegen einer Kollision braucht, wäre das kein Problem. Wenn aber im Auslösefall ein setState verloren ginge oder einen falschen Zustand auslösen würde wäre das fatal.
Viele Grüße
Andi -
@andreasph
Entschuldige die späte Reaktion - das Forum hat mich nicht auf deine Nachricht hingewiesen.Es funktioniert insgesamt schon recht gut. Die Kollisionen sind etwas nervig. Ich wollte das Script noch anpassen, dass es die Objekte im IObroker erst setzt, wenn auch die letzte Werteabfrage ohne Kollision passiert ist. Alternativ wäre es eine Möglichkeit auf den Bus zu hören, das Ende der Abfrage vom Internetmodul abzuwarten und direkt danach die eigene Abfrage zu starten. Damit müsste die Kollision weg sein.
Werte setzen habe ich bisher noch nicht implementiert. Ist auch auf der Todo-Liste. Sofern die Kollision oben gelöst ist sollte es auch kein Problem sein einen Wert zu setzen. Durch nochmaliges Abfragen vom Wert kann festgestellt werden, ob die Übertragung erfolgreich war.
Grüße,
Kachel
-
@kachel bist Du ggf. dazu gekommen, die set-Befehle zu implementieren? Liegt das Skript auch bspw. in github. Lieben Dank vorab.
-
Genial! Hat denn hier schon jemand weiter gemacht?
-
@knxbroker bei mir ging es leider nicht weiter. Ich stehe aber auch kurz davor, mir die Kombination einzubauen. Mir wäre allerdings wichtig, zu hören, ob es über einen längeren Zeitraum auch "robust" funktioniert, da die Installation schon aufwändiger ist (habe bisher nicht den SYR Universalflansch in der Leitung). Cool wäre halt, wenn dann alles noch gut läuft, wenn das Backend des Herstellers nicht mehr zur Verfügung steht.
-
Ich bin gerade dran eine Lösung mittels NodeRed zu realisieren, allerdings im ersten Schritt parallel zu den Cloud Abfragen. Solange die Cloud aktiv ist, werde ich dies wahrscheinlich auch so belassen. Läuft bisher ganz gut, aber mir fehlen noch ein paar Kommandos bis ich mein Ergebnis veröffentlichen werde.
Bin vor einiger Zeit zu Home Assistant gewechselt und werde dort meine Lösung auch präsentieren, sobald ich fertig bin. Den Link werde ich natürlich hier posten. -
@knxbroker das klingt doch gut - wäre ich natürlich auch sehr interessiert dran (gerade an dem NodeRed-Teil) - danke schon einmal vorab.
-
@knxbroker bist Du ggf. schon weitergekommen? Danke vorab.
-
@dmq nicht wirklich, das Thema hat im Sommer leider keine Prio...
Falls von Interesse, hier schon mal Node Red Code zum Auslesen der Webserver Requests.
Die Einzelabfrage (komplett lokal) gestaltet sich als schwierig, da das interne LAN Modul immer dazwischen quatscht. Ich kann damit vorerst so leben, sollte es eines Tages die Cloud nicht mehr geben, dann werde ich das LAN Modul intern abklemmen.PS: Den Home Assistant spezifischen Teil habe ich in diesem Forum mal weggelassen.
[{"id":"c346de70e5a46098","type":"serial in","z":"7d9d3cbb2597cd82","name":"","serial":"07c6650d2ff49b41","x":190,"y":2340,"wires":[["9d3388838e7f0cb7","94a5d32d473eb13d","d2190ca65994c11d","c499ae1e1b0a14b5","b09321ac134f816a","4ce39c90acf1d1d5"]]},{"id":"7c813e64bee7583b","type":"function","z":"7d9d3cbb2597cd82","name":"getBAR Match","func":"// Get water pressure [bar]\nconst pattern = new RegExp(\"(?<=getbar\\\\r)(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = Math.round(found[0].replace(',', '.') / 100) / 10;\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":2640,"wires":[[]]},{"id":"0e3a4af116c977f1","type":"function","z":"7d9d3cbb2597cd82","name":"getVOL Match","func":"// Get total water volume [L]\nconst pattern = new RegExp(\"(?<=Vol\\\[L\\\])(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = found[0].replace(',', '.');\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":2700,"wires":[[]]},{"id":"9d3388838e7f0cb7","type":"delay","z":"7d9d3cbb2597cd82","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":340,"y":2640,"wires":[["7c813e64bee7583b","0e3a4af116c977f1","1115f0f138466e0c","f424d047f8af2bea"]]},{"id":"1115f0f138466e0c","type":"function","z":"7d9d3cbb2597cd82","name":"getBAR Match","func":"// Get water pressure [Bar]\nconst pattern = new RegExp(\"(?<=getBat\\\\r)(\\\\d*,\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = Math.round(found[0].replace(',', '.') * 10) / 10;\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":2760,"wires":[[]]},{"id":"f424d047f8af2bea","type":"function","z":"7d9d3cbb2597cd82","name":"getCEL Match","func":"// Get water temperature [°C]\nconst pattern = new RegExp(\"(?<=getCel\\\\r)(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = found[0].replace(',', '.') / 10;\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":2820,"wires":[[]]},{"id":"94a5d32d473eb13d","type":"function","z":"7d9d3cbb2597cd82","name":"getAB Match","func":"// Get valve status [1= Open / 2 = Closed]\nconst pattern = new RegExp(\"(?<=getAB\\\\r)(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = Math.abs(found[0] - 2); // HA specific adaption\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":2460,"wires":[[]]},{"id":"d2190ca65994c11d","type":"function","z":"7d9d3cbb2597cd82","name":"getALA Match","func":"// Get alarms\nconst pattern = new RegExp(\"(?<=getALA\\\\r)(.*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n var failure;\n var issue = true;\n switch (found[0]) {\n case \"A1\":\n failure = \"Absperrung defekt\"\n break;\n case \"A2\":\n failure = \"Kein Turbinen-Signal\"\n break;\n case \"A3\":\n failure = \"Anwesenheits-Leckage\"\n break;\n case \"A4\":\n failure = \"Durchfluss-Leckage\"\n break;\n case \"A5\":\n failure = \"Abwesenheits-Leckage\"\n break;\n case \"A6\":\n failure = \"Bodensensor-Leckage\"\n break;\n case \"A7\":\n failure = \"Leckage an Eingang IN2\"\n break;\n case \"FF\":\n failure = \"Keine\";\n issue = false;\n break;\n default:\n failure = \"Unbekannte Störung \" + found;\n }\n msg.payload = failure;\n msg.issue = issue;\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":2520,"wires":[[]]},{"id":"c499ae1e1b0a14b5","type":"function","z":"7d9d3cbb2597cd82","name":"getTMP Match","func":"// Get temporary inactivity time [s]\nconst pattern = new RegExp(\"(?<=getTMP\\\\r)(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = found[0];\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":2400,"wires":[[]]},{"id":"b09321ac134f816a","type":"function","z":"7d9d3cbb2597cd82","name":"getUL Match","func":"// Get presense\nconst pattern = new RegExp(\"(?<=getUL\\\\r)(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n if (found[0] == 0) {\n msg.payload = true;\n return msg;\n }\n else {\n msg.payload = false;\n return msg;\n }\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":2340,"wires":[[]]},{"id":"4ce39c90acf1d1d5","type":"function","z":"7d9d3cbb2597cd82","name":"getLE Match","func":"// Get current water limit [L]\nconst pattern = new RegExp(\"(?<=getLE\\\\r)(\\\\d*)\", \"i\");\nvar found = msg.payload.match(pattern);\nif (Array.isArray(found)) {\n msg.payload = found[0]*50;\n return msg;\n} else {\n return null;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":2580,"wires":[[]]},{"id":"d9ef234728f55896","type":"comment","z":"7d9d3cbb2597cd82","name":"Anwesendheit","info":"","x":850,"y":2340,"wires":[]},{"id":"8c0b98a0743a69a4","type":"comment","z":"7d9d3cbb2597cd82","name":"Temporäre Inaktivität","info":"","x":870,"y":2400,"wires":[]},{"id":"f8dd9b2a4b0d85fb","type":"comment","z":"7d9d3cbb2597cd82","name":"Auslesen von WebServer Requests","info":"","x":260,"y":2260,"wires":[]},{"id":"edce790ca722ef59","type":"comment","z":"7d9d3cbb2597cd82","name":"Ventilstatus","info":"","x":850,"y":2460,"wires":[]},{"id":"7e4e1d3dbd0ef890","type":"comment","z":"7d9d3cbb2597cd82","name":"Alarm","info":"","x":830,"y":2520,"wires":[]},{"id":"ef3777ab8741ac8f","type":"comment","z":"7d9d3cbb2597cd82","name":"Wasserlimit","info":"","x":850,"y":2580,"wires":[]},{"id":"8369c6d71aa2f63a","type":"comment","z":"7d9d3cbb2597cd82","name":"Wasserdruck","info":"","x":850,"y":2640,"wires":[]},{"id":"242b89811638941f","type":"comment","z":"7d9d3cbb2597cd82","name":"Volumen Gesamt","info":"","x":860,"y":2700,"wires":[]},{"id":"6cedcffe51a141e9","type":"comment","z":"7d9d3cbb2597cd82","name":"Wasserdruck","info":"","x":850,"y":2760,"wires":[]},{"id":"836ac7537e1cce37","type":"comment","z":"7d9d3cbb2597cd82","name":"Wassertemperatur","info":"","x":870,"y":2820,"wires":[]},{"id":"07c6650d2ff49b41","type":"serial-port","serialport":"/dev/ttyUSB1","serialbaud":"19200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"2000","bin":"false","out":"interbyte","addchar":"","responsetimeout":"300"}]
-
@dmq Und hier Node Red Code zur Steuerung, wieder ohne Home Assistant Knoten.
ToDo: Bestätigung von Alarm Meldungen!
Steuerung ist ebenfalls vom WebServer abhängig und somit nicht lokal. Der Code wartet auf die WebServer Abfrage und schickt danacht Befehle los, um eine Kollision zu vermeiden.
[{"id":"d2dddf837a5f48b7","type":"function","z":"7d9d3cbb2597cd82","name":"Wait for msg.release","func":"const messages = context.get('messages') || [];\n\nif(msg.release) {\n context.set('messages', null);\n node.status({text: `Sent: ${messages.length}`});\n return [messages];\n}\n\nmessages.push(msg);\ncontext.set('messages', messages);\nnode.status({text: `Holding: ${messages.length}`});","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":720,"y":2580,"wires":[["9f5e2b7a9f1ee9da"]]},{"id":"850c0728ec1a735c","type":"change","z":"7d9d3cbb2597cd82","name":"","rules":[{"t":"set","p":"release","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":2440,"wires":[["d2dddf837a5f48b7"]]},{"id":"2841702637ee5a33","type":"function","z":"7d9d3cbb2597cd82","name":"setAB2","func":"// Close the vavle\nvar cmdstart = Buffer.from(\"0d0a1b313a\", \"hex\");\nvar cmdmiddle = Buffer.from(\"setAB2\");\nvar cmdend = Buffer.from(\"0d0a\", \"hex\"); // cR + LF\nmsg.payload = Buffer.concat([cmdstart, cmdmiddle, cmdend]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":2520,"wires":[["d2dddf837a5f48b7"]]},{"id":"7ec7b7f3b2be5f8b","type":"function","z":"7d9d3cbb2597cd82","name":"setAB1","func":"// Open the vavle\nvar cmdstart = Buffer.from(\"0d0a1b313a\", \"hex\");\nvar cmdmiddle = Buffer.from(\"setAB1\");\nvar cmdend = Buffer.from(\"0d0a\", \"hex\"); // CR + LF\nmsg.payload = Buffer.concat([cmdstart, cmdmiddle, cmdend]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":2580,"wires":[["d2dddf837a5f48b7"]]},{"id":"3bc209160cce93a1","type":"serial in","z":"7d9d3cbb2597cd82","name":"","serial":"07c6650d2ff49b41","x":170,"y":2440,"wires":[["850c0728ec1a735c"]]},{"id":"41ad879c02123e89","type":"function","z":"7d9d3cbb2597cd82","name":"setTmp0","func":"// Set temporary inactivity time to 0s\nvar cmdstart = Buffer.from(\"0d0a1b313a\", \"hex\");\nvar cmdmiddle = Buffer.from(\"setTMP0\");\nvar cmdend = Buffer.from(\"0d\", \"hex\");\nmsg.payload = Buffer.concat([cmdstart, cmdmiddle, cmdend]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":2740,"wires":[["d2dddf837a5f48b7"]]},{"id":"fce9cff1374cce55","type":"function","z":"7d9d3cbb2597cd82","name":"setTmp14400","func":"// Set temporary inactivity time to 4h\nvar cmdstart = Buffer.from(\"0d0a1b313a\", \"hex\");\nvar cmdmiddle = Buffer.from(\"setTMP14400\");\nvar cmdend = Buffer.from(\"0d\", \"hex\");\nmsg.payload = Buffer.concat([cmdstart, cmdmiddle, cmdend]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":2680,"wires":[["d2dddf837a5f48b7"]]},{"id":"46a371ee6322b0b8","type":"comment","z":"7d9d3cbb2597cd82","name":"SYR Connect - Control ","info":"","x":200,"y":2380,"wires":[]},{"id":"55aa5d6d321d51ec","type":"function","z":"7d9d3cbb2597cd82","name":"setUL0","func":"// Close the vavle\nvar cmdstart = Buffer.from(\"0d0a1b313a\", \"hex\");\nvar cmdmiddle = Buffer.from(\"setUL0\");\nvar cmdend = Buffer.from(\"0d0a\", \"hex\"); // cR + LF\nmsg.payload = Buffer.concat([cmdstart, cmdmiddle, cmdend]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":2820,"wires":[["d2dddf837a5f48b7"]]},{"id":"abef738776e765eb","type":"function","z":"7d9d3cbb2597cd82","name":"setUL3","func":"// Open the vavle\nvar cmdstart = Buffer.from(\"0d0a1b313a\", \"hex\");\nvar cmdmiddle = Buffer.from(\"setUL3\");\nvar cmdend = Buffer.from(\"0d0a\", \"hex\"); // CR + LF\nmsg.payload = Buffer.concat([cmdstart, cmdmiddle, cmdend]);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":2880,"wires":[["d2dddf837a5f48b7"]]},{"id":"e3b1591eaec5c765","type":"comment","z":"7d9d3cbb2597cd82","name":"Ventil Zu","info":"","x":160,"y":2520,"wires":[]},{"id":"9a432a6df02f8f39","type":"comment","z":"7d9d3cbb2597cd82","name":"Ventil Auf","info":"","x":160,"y":2580,"wires":[]},{"id":"996ebd2f1e184a87","type":"comment","z":"7d9d3cbb2597cd82","name":"Anwesend","info":"","x":160,"y":2820,"wires":[]},{"id":"95ab097536ee9cf2","type":"comment","z":"7d9d3cbb2597cd82","name":"Abwesend (30L)","info":"","x":180,"y":2880,"wires":[]},{"id":"b25ef65f1a65fc12","type":"comment","z":"7d9d3cbb2597cd82","name":"Inaktiv Timer 4h","info":"","x":180,"y":2680,"wires":[]},{"id":"bc165e6cd206e810","type":"comment","z":"7d9d3cbb2597cd82","name":"Inaktiv Timer Aus","info":"","x":180,"y":2740,"wires":[]},{"id":"344b580893fb384e","type":"serial out","z":"7d9d3cbb2597cd82","name":"","serial":"07c6650d2ff49b41","x":730,"y":2720,"wires":[]},{"id":"9f5e2b7a9f1ee9da","type":"delay","z":"7d9d3cbb2597cd82","name":"","pauseType":"delay","timeout":"300","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":720,"y":2660,"wires":[["f4043b8aa0ba6a4e","344b580893fb384e"]]},{"id":"07c6650d2ff49b41","type":"serial-port","serialport":"/dev/ttyUSB1","serialbaud":"19200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"2000","bin":"false","out":"interbyte","addchar":"","responsetimeout":"300"}]
-
@knxbroker besten Dank dafür. Schaue ich mir mal in Ruhe an.
-
Hi @dmq, und alle anderen die daran Interesse haben:
Habe nun auch die Bestätigung von Alarmmeldungen in Node Red Implementiert, ich verweise hier einfach mal auf meinen Post im Home Assistant Forum:
Eine komplette Offline Lösung sollte eigentlich auch nicht so schwer sein zu implementieren, aber für mich erstmal so okay.
-
@knxbroker danke fürs informieren und freigeben. Ich habe die Komponenten hier, aber noch nicht physisch eingebaut (überlege auch noch ob ich es selbst einbaue oder (versuche) einbauen zu lassen. Daran hängt leider mein Fortschritt mich da tiefer einzuarbeiten und hoffentlich auch mal was sinnvolles zurückzugeben
-
-
Die hier gezeigte Loesung waere mein Plan B gewesen, vielen Dank euch allen, die sich hier soviel Arbeit machen und alles und jeden Schritt dokumentieren!
Wer das hier findet, und vielleicht lieber ein Adapter installiert (leider wird zur Zeit noch ein dns-routing und webserver(alternativ iptables) gebraucht. Ist aber kein Hexenwerk zum installieren.
Der Adapter unterstuetzt seit heute auch die SyrLexPlus10SL.
https://github.com/eifel-tech/ioBroker.syrconnect -
Habe mittlerweile auch eine Node Red Offline Lösung mittels seriellen Adapter am Laufen falls jemand Interesse hat. Läuft seit über einem Jahr ohne Probleme und ich bin nicht mehr auf die SYR Cloud angewiesen.
-
kannst du auch schalten, Ventil, Abwesend etc.. ?
Meine ist ja Enthaertungsanlage und Safeconnect in einem... -
@ilovegym kann alles schalten, aber habe den SYR safe-t connect; habe das Netzwerkkabel rausgezogen und bediene nun alles mittels der seriellen Service Schnittstelle
-
@knxbroker ich hätte Interesse an der Node Red Offline Lösung. Hast Du hierzu einen Link? Würde mich sehr freuen - danke vorab.
-
@dmq Kein Problem, unten findest du den Node Red Code im Anhang zur lokalen Ansteuerung eines SYR safe-t connect über RS485. Wie gesagt, ich nutze IOBroker nicht mehr, du musst die ganzen Home Assistant I/O Nodes entsprechend konvertieren, aber die Logik sollte die gleiche sein.
Achtung: Netzwerkkabel abstecken, sonst funktioniert es nicht. Parallelbetrieb von Cloud und dieser Offline Lösung ist nicht möglich, aber die Offline Lösung arbeitet bei mir seit langem zuverlässiger als die Cloud.
Was macht das Script?
- Alle drei Minuten gibt es auf dem RS485 Bus eine Art ALIVE Abfrage. Das Skript wartet auf diese Abfrage und beginnt dann zu arbeiten.
- Alle 20s werden Steuerungsbefehle abgeschickt, sofern vorhanden. Alle 25s werden die Statusdaten vom Gerät gelesen.
- Kurz bevor die ALIVE Abfrage wieder kommt, macht das Skript Pause und synchronisiert sich dann wieder auf die nächste ALIVE Abfrage auf.
Viel Spass