NEWS
Hardware für 8 und mehr Velux/Somfi Geräte
-
Hallo Zusammen,
ich hatte mal Bock was mit einem NodeMCU zusammen zu bauen und habe es zum Anlass genommen endlich mal meine Velux-Rolläden in meinen ioBroker zu integrieren. Und zwar ohne mich von Velux weiter veräppeln zu lassen mit KLF-200-Firmware-Updates oder irgendwelchen teueren nicht-smarten INTEGRA-Produkten.
Dazu habe ich 3x Relais-Boards mit drei I/O-Extension-Boards an einen NodeMCU angeschlossen (~40EUR).
Die 8 INTEGRA Fernbedienungen habe ich gestapelt und an die Relais angeschlossen. Versorgt werden sie über den 3V Ausgang vom NodeMCU. Versorgt wird das Ganze über ein USB Ladegerät.Ich nennen das Projekt F**K-YOU-VELUX-Stack.
Die Einbindung habe ich über Tasmota gemacht, eine großartige Firmware. Erkennt automatisch die I/O-Extensions und stellt jeden Kontakt als MQTT zur Verfügung.
Macht richtig Spaß dem Klackern der Relais zu lauschen.
VG Tristan
const og_bad = "javascript.0.Velux.og_bad."; const og_empore = "javascript.0.Velux.og_empore."; // viele weitere Velux Geräte... const dr_o = "/vis.0/main/dg_rolladen_open.svg"; const dr_m = "/vis.0/main/dg_rolladen_middle.svg"; const dr_c = "/vis.0/main/dg_rolladen_close.svg"; const wr_o = "/vis.0/main/fenster_rolladen_open.svg"; const wr_m = "/vis.0/main/fenster_rolladen_middle.svg"; const wr_c = "/vis.0/main/fenster_rolladen_close.svg"; const w_o = "/vis.0/main/dg_window_close.svg"; // ACHTUNG! Invertierung wegen 100% Velux UI-FUCK const w_m = "/vis.0/main/dg_window_middle.svg"; const w_c = "/vis.0/main/dg_window_open.svg"; // ACHTUNG! Invertierung wegen 100% Velux UI-FUCK function createRolladen(name){ createState("javascript.0.Velux."+name+".position", "", { "name": "position", "role": "", "type": "number", "desc": "Position des Rolladen in % (0% ist offen).", "unit": "%", "min": 0, "max": 100, "def": 0, "read": true, "write": true }); console.log("Objekt close für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".target_position", "", { "name": "target_position", "role": "", "type": "number", "desc": "Wunsch-Position des Rolladen in % (0% ist offen).", "unit": "%", "min": -1, "max": 100, "def": 0, "read": true, "write": true }); console.log("Objekt target_position für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".runtime", 0, { "name": "runtime", "role": "", "type": "number", "desc": "Gibt in Sekunden an wie lange der Rolladen für einen kompletten Lauf benötigt ", "unit": "s", "min": 0, "max": 1000, "def": 15, "read": true, "write": true }); console.log("Objekt runtime für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".icon", "", { "name": "icon", "role": "", "type": "string", "desc": "Speichert den Icon-Namen zur Position.", "def": "open", "read": true, "write": true }); console.log("Objekt icon für Rolladen "+name+" erstellt."); // Hier muss noch geprüft werden, was sein Problem mit dem Type in Common ist... createState("javascript.0.Velux."+name+".deviceType", 0, { "name": "deviceType", "role": "", "type": "state", "desc": "Speichert den Icon-Namen zur Position.", "def": 0, "read": true, "write": true, "states": { 0: "DachRolladen", 1: "FensterRolladen", 2: "Fenster" } }); console.log("Objekt deviceType für Device "+name+" erstellt."); createState("javascript.0.Velux."+name+".open", "", { "name": "open", "role": "", "type": "string", "desc": "Speichert den Pfad zum Objekt für die Aktion: open.", "def": "", "read": true, "write": true }); console.log("Objekt open für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".stop", "", { "name": "stop", "role": "", "type": "string", "desc": "Speichert den Pfad zum Objekt für die Aktion: stop.", "def": "", "read": true, "write": true }); console.log("Objekt stop für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".close", "", { "name": "close", "role": "", "type": "string", "desc": "Speichert den Pfad zum Objekt für die Aktion: close.", "def": "", "read": true, "write": true }); console.log("Objekt close für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".reed", "", { "name": "reed", "role": "", "type": "string", "desc": "Speichert den Pfad zum Objekt für den reed-Kontakt.", "def": "", "read": true, "write": true }); console.log("Objekt reed für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".action", "", { "name": "action", "role": "", "type": "string", "desc": "Befehl an den Rolladen.", "def": false, "read": true, "write": true }); console.log("Objekt action für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".lastaction", "", { "name": "lastaction", "role": "", "type": "string", "desc": "Letzter Befehl an den Rolladen.", "def": "", "read": true, "write": true }); console.log("Objekt lastaction für Rolladen "+name+" erstellt."); createState("javascript.0.Velux."+name+".lastaction_time", "", { "name": "lastaction_time", "role": "", "type": "string", "desc": "Zeitpunkt der letzten Änderung.", "def": "", "read": true, "write": true }); console.log("Objekt lastaction_time für Rolladen "+name+" erstellt."); } //createRolladen("og_bad"); //createRolladen("og_empore"); // viele weitere Velux Geräte... function moveVelux(idTarget, action, target_position){ var deviceType = getState(idTarget+"deviceType").val; // Fensterkontakt var idReed = getState(idTarget+"reed").val; if(idReed != ""){ if(getState(idReed).val == true){ console.log("Reed Kontakt sagt offen. => Abbruch"); return(false); } } if(deviceType == 0){ // DachRolladen var device_open = dr_o; var device_middle = dr_m; var device_close = dr_c; } if(deviceType == 1){ // FensterRolladen var device_open = wr_o; var device_middle = wr_m; var device_close = wr_c; } if(deviceType == 2){ // Fenster var device_open = w_o; var device_middle = w_m; var device_close = w_c; } var oldPosition = getState(idTarget+"position").val; // Percent per Second berechnen var pps = 100 / getState(idTarget+"runtime").val; var seconds; var time = formatDate(new Date(), "YYYY-MM-DD hh:mm:ss"); if(target_position == ""){ // Es wurde keine Ziel-Position geliefert wir gehen einfach in den modus open/stop/close setState(idTarget+"lastaction", action); // console.log(action + " für das Target "+idTarget+action); //console.log("Aktuelle Pos.: "+getState(idTarget+"position").val); if(action == "open"){ // Berechne die Laufzeit bis zum Ziel von 0% seconds = oldPosition / pps; //console.log("Das Ding braucht "+seconds+" Sekunden von der aktuellen Pos. bis 0%."); } if(action == "close"){ // Berechne die Laufzeit bis zum Ziel von 100% seconds = (100 - oldPosition) / pps; //console.log("Das Ding braucht "+seconds+" Sekunden von der aktuellen Pos. bis 100%."); } if(action == "stop"){ seconds = 0; } }else{ // Es wurde eine Ziel-Position übergeben wir ignorieren alles andere. //console.log("Ziel-Position erkannt: "+target_position); // Datenpunkt auf -1 setzen damit er neue Werte Bemerkt. setState(idTarget+"target_position", -1); if(oldPosition >= target_position){ // Rolladen muss Richtung 0% fahren seconds = (oldPosition - target_position) / pps; var action = "open"; }else{ // Rolladen muss Richtung 100% fahren seconds = (target_position - oldPosition) / pps; var action = "close"; } } if(action == "open"){ setState(idTarget+"lastaction_time", time); console.log("Rolladen "+idTarget+" Klick auf OPEN"); setState(getState(idTarget+"open").val, true); } if(action == "close"){ setState(idTarget+"lastaction_time", time); console.log("Rolladen "+idTarget+" Klick auf CLOSE"); setState(getState(idTarget+"close").val, true); } if(action == "stop"){ setState(idTarget+"lastaction_time", time); console.log("Rolladen "+idTarget+" Klick auf STOP"); setState(getState(idTarget+"stop").val, true); } seconds = Math.round(seconds); var i = 0; var newPosition = oldPosition; if(action == "open" || action == "close"){ //console.log("Wir starten von Pos. " + newPosition + " und gehen in den Interval."); let interval = setInterval(function(){ //console.log("Noch "+i+"/"+seconds+" Sekunden. newPosition: "+newPosition); i++; if(action == "open"){ newPosition = newPosition - pps; } if(action == "close"){ newPosition = newPosition + pps; } if(i >= seconds || getState(idTarget+"lastaction").val == "stop"){ //console.log("####### ENDE #######"); //console.log("newPosition für "+idTarget+"position = "+Math.round(newPosition)); if(target_position != ""){ console.log("Rolladen "+idTarget+" Klick auf STOP"); setState(getState(idTarget+"stop").val, true); //console.log("Bewegung wegen erreichter target_position gestoppt."); } clearInterval(interval); } if(newPosition >100 || newPosition < 0){ // Irgendwas ist schief gegangen, daher Intervall stoppen. clearInterval(interval); } setState(idTarget+"position", Math.round(newPosition)); if(newPosition <= 10){ setState(idTarget+"icon",device_open); } if(newPosition > 10 && newPosition < 90 ){ setState(idTarget+"icon",device_middle); } if(newPosition >= 90){ setState(idTarget+"icon",device_close); } }, 1000); } } // Beobachte alle Velux Geräte auf Wunsch-Ziel-Position-Änderungen on(og_bad+"target_position", function(obj) { if(obj.state.val > obj.oldState.val){ var target_position = getState(og_bad+"target_position").val; wait(500); //console.log("Wir gehen in den TargetModus mit: "+target_position); moveVelux(og_bad, "", target_position); } }); on(og_empore+"target_position", function(obj) { if(obj.state.val > obj.oldState.val){ var target_position = getState(og_empore+"target_position").val; wait(500); //console.log("Wir gehen in den TargetModus mit: "+target_position); moveVelux(og_empore, "", target_position); } }); // viele weitere Velux Geräte... // ##################################################### // // Beobachte alle Velux Geräte auf Wunsch-Action-Änderungen on(og_bad+"action", function(obj) { var action = getState(og_bad+"action").val; setState(og_bad+"action", ""); wait(500); if( action == "open" || action == "close" || action == "stop" ){ //console.log("moveVelux mit der action: "+action); moveVelux(og_bad, action, ""); } }); on(og_empore+"action", function(obj) { var action = getState(og_empore+"action").val; setState(og_empore+"action", ""); wait(500); if( action == "open" || action == "close" || action == "stop" ){ //console.log("moveVelux mit der action: "+action); moveVelux(og_empore, action, ""); } }); // viele weitere Velux Geräte...
-
Schöne Lösung! Ich habe dasselbe direkt an einem Raspberry Pi gemacht (I2C Adapter, PCF8574 und 16x Relais Karte).
-
Netter Tower
Ich habe estwas ähnliches in sehr viel kleiner für zwei RTS Rollos gemacht:
https://forum.iobroker.net/topic/32200/diverse-rolläden-in-iobroker-einbinden/24