Wenn du im Taster modus bleiben willst wirst du denke ich ohne Skript nicht auskommen, es darf hier gerne korrigiert werden wenn ich eine Falsche Aussage treffe, den soweit war ich noch nicht, was ich aber weis das es mit einem Skript funktionieren kann, es kann aber mehrere ANläufe brauchen bis gpt ds richtige funktionierende Skript ausgibt.
Beiträge von Schwarzermann
VPN/Proxy erkannt
Es scheint, dass Sie einen VPN- oder Proxy-Dienst verwenden. Bitte beachten Sie, dass die Nutzung eines solchen Dienstes die Funktionalität dieser Webseite einschränken kann.
-
-
Oder du nimmst einen 2 ten Shelly der via Skript lauscht ob der erste Shelly geschalten wird oder nicht hab ich bei meinen Rolltoren so mit Zeit verzögerung und schaltdauer die ich einstellen kann.
-
Ich Fahre meine Rollos gegen den endabschaltpunkt der am Motor eingestellt ist dadurch erkennt der 2 pm zuverlässig den Anfang und das Ende hast du ihm im Rollo Modus?
-
Hätte mich auch gewundert, wenn eine KI es selbst schafft etwas bis zum Ende zu entwickeln. Meist wird etwas vorausgesetzt, was gar nicht funktioniert, so wie hier. Das wird irgendwo rausgesucht, durcheinander geworfen und dann als Lösung präsentiert, die nicht funktioniert. Da kann man ganz schön Zeit bei verbraten, wenn man solch eine KI nutzt.
Naja siehe es mal so rum dafür das ich null Ahnung vom programieren habe, funktioniert das ausserortentlich gut, ich bin Zufrieden es macht was es soll, habe ja auch meine Html programierung für das Grafana Text Plugin so hinbekommen das es funktioniert in Grafana mit Button die Shellys zuschalten.
-
Ja das hatte mir ie KI auch so mit implementieren wollen, nur ich muss klar sagen wie oft geht das Tor Tags über auf 2 eventuell 3 al da sind die LEd Leuchten mit 40 W denke ich das geringse Problem, zudem ich ne riesige PV Habe und auch nen rect grossen Speicher (100kwNetto)
-
Code
Alles anzeigen// ########################################################### // Shelly 1PM Plus (Gen4) – folgt Tor (Shelly 2PM im Cover-Modus) // mit Sonnenstands-Sperre (nur nachts aktiv) // ########################################################### // // Endgültige Regeln (nur aktiv wenn es dunkel ist!): // - Bei 20% öffnen -> Licht EIN // - Bei 100% -> Licht 20s EIN, danach AUS (nur einmal) // - Wenn Tor von 100% auf <100% fährt (Start Schließen) -> Licht EIN // - Bei 20% schließen -> Licht AUS // // ########################################################### // IP-Adresse des Shelly 2PM (Torsteuerung) let sourceShelly = "192.168.178.195"; // Abfrageintervall (ms) let interval = 2000; // alle 2 Sekunden // Haltezeit wenn Tor komplett offen (in Sekunden) let holdTime = 20; // interne Zustände let lastOn = false; let holdTimer = null; let holdActive = false; let lastPos = null; // Sonnenauf-/untergang let sunrise = null; let sunset = null; // Hilfsfunktionen function switchLight(on) { Shelly.call("Switch.Set", { id: 0, on: on }); lastOn = on; print("Licht", on ? "EIN" : "AUS"); } function cancelHoldTimer() { if (holdTimer !== null) { Timer.clear(holdTimer); holdTimer = null; print("Hold-Timer abgebrochen"); } } function isNight() { if (!sunrise || !sunset) return true; // wenn keine Werte -> sicherheitshalber aktiv let now = (new Date()).getTime() / 1000; // aktuelle Zeit in UNIX Sekunden return (now < sunrise || now > sunset); } function updateSunTimes() { Shelly.call("Sys.GetStatus", {}, function(res) { if (res && res.sunrise && res.sunset) { sunrise = res.sunrise; sunset = res.sunset; print("Sonnenaufgang:", sunrise, "Sonnenuntergang:", sunset); } else { print("Keine Sonnenzeiten gefunden – Nacht-Check immer TRUE"); } }); } // Hauptprüfung function checkCover() { if (!isNight()) { // Tagsüber -> Licht sicher ausschalten und überspringen if (lastOn) { switchLight(false); cancelHoldTimer(); holdActive = false; } print("Tag erkannt – Lichtsteuerung gesperrt"); return; } let url = "http://" + sourceShelly + "/rpc/Cover.GetStatus?id=0"; Shelly.call("HTTP.GET", { url: url }, function(res) { if (!res || res.code !== 200) { print("HTTP Fehler:", res ? res.code : "kein Ergebnis"); return; } try { let data = JSON.parse(res.body); let pos = data.current_pos; if (typeof pos === "string") pos = parseFloat(pos); print("Tor-Position:", pos, "%", "(last:", lastPos, ")"); // --- Regel 2: Bei 100% -> Licht 20s EIN, danach AUS (nur einmal) if (pos >= 100) { if (!holdActive) { holdActive = true; if (!lastOn) { switchLight(true); print("Licht EIN (Tor 100%, Timer gestartet)"); } cancelHoldTimer(); holdTimer = Timer.set(holdTime * 1000, false, function() { switchLight(false); print("Licht AUS (Timer abgelaufen bei 100%)"); }); } lastPos = pos; return; } // --- Regel 3: Start Schließen von 100% -> Licht EIN if (lastPos !== null && lastPos >= 100 && pos < 100) { if (!lastOn) { switchLight(true); print("Licht EIN (Start Schließen von 100% -> <100%)"); } holdActive = false; cancelHoldTimer(); } if (lastPos !== null) { // --- Regel 1: Bei 20% öffnen -> Crossing von <20% auf >=20% if (lastPos < 20 && pos >= 20) { if (!lastOn) { switchLight(true); print("Licht EIN (Öffnen: Crossing über 20%)"); } } // --- Regel 4: Bei 20% schließen -> Crossing von >20% auf <=20% if (lastPos > 20 && pos <= 20) { if (lastOn) { switchLight(false); print("Licht AUS (Schließen: Crossing unter 20%)"); } holdActive = false; cancelHoldTimer(); } } lastPos = pos; } catch (e) { print("Parsing Fehler:", e); } }); } // Timer starten Timer.set(interval, true, checkCover); // Sonnenauf-/untergang alle 10min aktualisieren updateSunTimes(); Timer.set(600000, true, updateSunTimes); // 10 min
Besser so? hatte es aus dem Shelly kopiert und nicht darauf geachtet, leider funktioniert die tag Nacht schaltung nicht da anscheinend bei den gen 4 Geräten das noch nicht implementiert ist, aber es schaltet bei mir das Licht ein und Aus.
-
Code
// ###########################################################// Shelly 1PM Plus (Gen4) – folgt Tor (Shelly 2PM im Cover-Modus)// mit Sonnenstands-Sperre (nur nachts aktiv)// ###########################################################//// Endgültige Regeln (nur aktiv wenn es dunkel ist!):// - Bei 20% öffnen -> Licht EIN// - Bei 100% -> Licht 20s EIN, danach AUS (nur einmal)// - Wenn Tor von 100% auf <100% fährt (Start Schließen) -> Licht EIN// - Bei 20% schließen -> Licht AUS//// ###########################################################// IP-Adresse des Shelly 2PM (Torsteuerung)let sourceShelly = "192.168.178.104";// Abfrageintervall (ms)let interval = 5000; // alle 5 Sekunden// Haltezeit wenn Tor komplett offen (in Sekunden)let holdTime = 120;// interne Zuständelet lastOn = false;let holdTimer = null;let holdActive = false;let lastPos = null;// Sonnenauf-/unterganglet sunrise = null;let sunset = null;// Hilfsfunktionenfunction switchLight(on) { Shelly.call("Switch.Set", { id: 0, on: on }); lastOn = on; print("Licht", on ? "EIN" : "AUS");}function cancelHoldTimer() { if (holdTimer !== null) { Timer.clear(holdTimer); holdTimer = null; print("Hold-Timer abgebrochen"); }}function isNight() { if (!sunrise || !sunset) return true; // wenn keine Werte -> sicherheitshalber aktiv let now = (new Date()).getTime() / 1000; // aktuelle Zeit in UNIX Sekunden return (now < sunrise || now > sunset);}function updateSunTimes() { Shelly.call("Sys.GetStatus", {}, function(res) { if (res && res.sunrise && res.sunset) { sunrise = res.sunrise; sunset = res.sunset; print("Sonnenaufgang:", sunrise, "Sonnenuntergang:", sunset); } else { print("Keine Sonnenzeiten gefunden – Nacht-Check immer TRUE"); } });}// Hauptprüfungfunction checkCover() { if (!isNight()) { // Tagsüber -> Licht sicher ausschalten und überspringen if (lastOn) { switchLight(false); cancelHoldTimer(); holdActive = false; } print("Tag erkannt – Lichtsteuerung gesperrt"); return; } let url = "http://" + sourceShelly + "/rpc/Cover.GetStatus?id=0"; Shelly.call("HTTP.GET", { url: url }, function(res) { if (!res || res.code !== 200) { print("HTTP Fehler:", res ? res.code : "kein Ergebnis"); return; } try { let data = JSON.parse(res.body); let pos = data.current_pos; if (typeof pos === "string") pos = parseFloat(pos); print("Tor-Position:", pos, "%", "(last:", lastPos, ")"); // --- Regel 2: Bei 100% -> Licht 20s EIN, danach AUS (nur einmal) if (pos >= 100) { if (!holdActive) { holdActive = true; if (!lastOn) { switchLight(true); print("Licht EIN (Tor 100%, Timer gestartet)"); } cancelHoldTimer(); holdTimer = Timer.set(holdTime * 1000, false, function() { switchLight(false); print("Licht AUS (Timer abgelaufen bei 100%)"); }); } lastPos = pos; return; } // --- Regel 3: Start Schließen von 100% -> Licht EIN if (lastPos !== null && lastPos >= 100 && pos < 100) { if (!lastOn) { switchLight(true); print("Licht EIN (Start Schließen von 100% -> <100%)"); } holdActive = false; cancelHoldTimer(); } if (lastPos !== null) { // --- Regel 1: Bei 20% öffnen -> Crossing von <20% auf >=20% if (lastPos < 20 && pos >= 20) { if (!lastOn) { switchLight(true); print("Licht EIN (Öffnen: Crossing über 20%)"); } } // --- Regel 4: Bei 20% schließen -> Crossing von >20% auf <=20% if (lastPos > 20 && pos <= 20) { if (lastOn) { switchLight(false); print("Licht AUS (Schließen: Crossing unter 20%)"); } holdActive = false; cancelHoldTimer(); } } lastPos = pos; } catch (e) { print("Parsing Fehler:", e); } });}// Timer startenTimer.set(interval, true, checkCover);// Sonnenauf-/untergang alle 10min aktualisierenupdateSunTimes();Timer.set(600000, true, updateSunTimes); // 10 min
Ich lausche mit einem shelly 1 pm plus über dieses Skript (erstellt mit KI) einen Shelly 2pm plus ab wenn er den Schalt befehl bekommt schaltet sich das Licht ein.
-
HTML
Alles anzeigen<!DOCTYPE html> <html> <head> <style> #devices_roller { display: flex; flex-wrap: wrap; gap: 15px; } .device { flex: 1 1 130px; max-width: 200px; padding: 10px; border: 1px solid #003366; border-radius: 12px; box-shadow: 2px 2px 5px rgba(0,0,0,0.2); color: white; } .device h3 { margin: 5px 0 10px 0; font-size: 14px; text-align: center; } .btn { color: white; width: 100%; height: 38px; margin: 4px 0; border: none; border-radius: 8px; font-size: 11px; cursor: pointer; } .btn-up { background: green; } .btn-stop { background: blue; } .btn-down { background: orange; color: black; } .status { margin-top: 5px; font-size: 12px; text-align: center; font-weight: bold; color: #fff; } </style> </head> <body> <div id="devices_roller"></div> <script> function initRollerDashboard(){ const prefix = "roller"; // eindeutiger Prefix nur für dieses Panel const roomColors = { "Wohnzimmer": "#1c5a1b", "Esszimmer": "#19bcd2", "Terasse": "#7f19d2", "Küche": "#3fe23c", "Bad": "#3fe23c", "Flur": "#3ce2d7" }; const devices = [ { room: "Wohnzimmer", devices: [ { ip:"192.168.178.71", type:"roller", name:"Rollo 1"}, { ip:"192.168.178.72", type:"roller", name:"Rollo 2"} ]}, { room: "Terasse", devices: [ { ip:"192.168.178.131", type:"roller", name:"Markise"} ]}, { room: "Esszimmer", devices: [ { ip:"192.168.178.83", type:"roller", name:"Rollo 1"}, { ip:"192.168.178.84", type:"roller", name:"Rollo 2"} ]}, { room: "Küche", devices: [ { ip:"192.168.178.89", type:"roller", name:"Rollo"} ]}, { room: "Bad", devices: [ { ip:"192.168.178.195", type:"roller", name:"Rollo"} ]}, { room: "Flur", devices: [ { ip:"192.168.178.99", type:"roller", name:"Rollo"} ]} ]; const devicesDiv = document.getElementById("devices_"+prefix); devicesDiv.innerHTML = ""; devices.forEach(roomBlock => { const block = document.createElement("div"); block.className = "device"; block.style.backgroundColor = roomColors[roomBlock.room] "#4169E1"; const title = document.createElement("h3"); title.innerText = roomBlock.room; block.appendChild(title); roomBlock.devices.forEach(device => { if(device.type==="roller"){ addRollerButtons(block,device,prefix); initWebSocket(device,prefix); } }); devicesDiv.appendChild(block); }); function sendRollerCmd(ip,action){ let method=action==="open"?"Cover.Open":action==="close"?"Cover.Close":"Cover.Stop"; fetch(`http://${ip}/rpc`,{ method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({id:1,method,params:{id:0}}) }); } function initWebSocket(device,prefix,attempt=0){ try{ const ws=new WebSocket(`ws://${device.ip}/rpc`); ws.onopen=()=>{ // 1) Initialstatus holen ws.send('{"id":1,"src":"grafana","method":"Shelly.GetStatus"}'); // 2) Live-Updates abonnieren ws.send('{"id":2,"src":"grafana","method":"Shelly.Subscribe","params":{"events":["*"]}}'); }; ws.onmessage=(e)=>{ const obj=JSON.parse(e.data); const status=obj.result||obj.params; if(status && status["cover:0"]){ const cover=status["cover:0"]; const pos=cover.current_pos; const state=cover.state; const st=document.getElementById(`${prefix}_cover_status_${device.ip}`); if(st){ if(state==="open") st.innerText="Status: offen"; else if(state==="closed") st.innerText="Status: geschlossen"; else if(typeof pos==="number") st.innerText="Position: "+pos+"%"; else st.innerText="Status: unbekannt"; } } }; ws.onclose=()=>setTimeout(()=>initWebSocket(device,prefix,attempt+1),2000); }catch(e){console.error("WS-Fehler",e);} } function addRollerButtons(block,device,prefix){ [["AUF","btn-up","open"],["STOP","btn-stop","stop"],["AB","btn-down","close"]] .forEach(([txt,cls,act])=>{ const b=document.createElement("button"); b.className="btn "+cls; b.innerText=device.name+" "+txt; b.onclick=()=>sendRollerCmd(device.ip,act); block.appendChild(b); }); const st=document.createElement("div"); st.id=`${prefix}_cover_status_${device.ip}`; st.className="status"; st.innerText="Status: unbekannt"; block.appendChild(st); } } /* Start */ function safeInit(){ try{initRollerDashboard();}catch(e){console.error("Init-Fehler:",e);} } safeInit(); if(document.readyState==="loading"){ document.addEventListener("DOMContentLoaded",safeInit); } setTimeout(safeInit,500); </script> </body> </html> So sieht zb meine Erdgeschoss Steuerung Rolläden aus mit Schalt Überwachung, achtung das ist mit Shelly 2 pm plus (gen4) getestet und funktioniert auch. <!DOCTYPE html> <html> <head> <style> #devices_somfy { display: flex; flex-wrap: wrap; gap: 15px; } .device { flex: 1 1 150px; max-width: 220px; padding: 10px; border: 1px solid #003366; border-radius: 12px; box-shadow: 2px 2px 5px rgba(0,0,0,0.2); color: white; } .device h3 { margin: 5px 0 10px 0; font-size: 14px; text-align: center; } .btn { color: white; width: 100%; height: 38px; margin: 4px 0; border: none; border-radius: 8px; font-size: 12px; cursor: pointer; } .btn-up { background: green; } .btn-stop { background: blue; } .btn-down { background: yellow; color: black; } .status { margin-top: 5px; font-size: 12px; text-align: center; font-weight: bold; color: #fff; } </style> </head> <body> <div id="devices_somfy"></div> <script> function initSomfyDashboard(){ const prefix="somfy"; const roomColors = { "Arbeitszimmer": "#444a97", "Schlafzimmer": "#d2cc19" }; const devices = [ { room:"Arbeitszimmer", devices:[{ip:"192.168.178.61", name:"Rollo Somfy"}]}, { room:"Schlafzimmer", devices:[{ip:"192.168.178.65", name:"Rollo Somfy"}]} ]; const devicesDiv=document.getElementById("devices_"+prefix); devicesDiv.innerHTML=""; devices.forEach(roomBlock=>{ const block=document.createElement("div"); block.className="device"; block.style.backgroundColor=roomColors[roomBlock.room]||"#4169E1"; const title=document.createElement("h3"); title.innerText=roomBlock.room; block.appendChild(title); roomBlock.devices.forEach(device=>{ addSomfyButtons(block,device,prefix); initWebSocket(device,prefix); }); devicesDiv.appendChild(block); }); function sendSomfyCmd(ip,action){ if(action==="up"){ fetch(`http://${ip}/rpc%60,%7Bmethod:%22POST%22,headers:%7B%22Content-Type%22:%22application/json"}, body:JSON.stringify({id:1,method:"Switch.Set",params:{id:0,on:true}})}); fetch(`http://${ip}/rpc%60,%7Bmethod:%22POST%22,headers:%7B%22Content-Type%22:%22application/json"}, body:JSON.stringify({id:2,method:"Switch.Set",params:{id:1,on:false}})}); } if(action==="down"){ fetch(`http://${ip}/rpc%60,%7Bmethod:%22POST%22,headers:%7B%22Content-Type%22:%22application/json"}, body:JSON.stringify({id:3,method:"Switch.Set",params:{id:1,on:true}})}); fetch(`http://${ip}/rpc%60,%7Bmethod:%22POST%22,headers:%7B%22Content-Type%22:%22application/json"}, body:JSON.stringify({id:4,method:"Switch.Set",params:{id:0,on:false}})}); } if(action==="stop"){ fetch(`http://${ip}/rpc%60,%7Bmethod:%22POST%22,headers:%7B%22Content-Type%22:%22application/json"}, body:JSON.stringify({id:5,method:"Switch.Set",params:{id:0,on:false}})}); fetch(`http://${ip}/rpc%60,%7Bmethod:%22POST%22,headers:%7B%22Content-Type%22:%22application/json"}, body:JSON.stringify({id:6,method:"Switch.Set",params:{id:1,on:false}})}); } } function initWebSocket(device,prefix,attempt=0){ try{ const ws=new WebSocket(`ws://${device.ip}/rpc`); ws.onopen=()=>{ ws.send('{"id":1,"src":"grafana","method":"Shelly.GetStatus"}'); ws.send('{"id":2,"src":"grafana","method":"Shelly.Subscribe","params":{"events":["*"]}}'); }; ws.onmessage=(e)=>{ const obj=JSON.parse(e.data); const status=obj.result||obj.params; if(status && status["switch:0"] && status["switch:1"]){ const st=document.getElementById(`${prefix}_status_${device.ip}`); if(st){ if(status["switch:0"].output) st.innerText="Status: AUF"; else if(status["switch:1"].output) st.innerText="Status: AB"; else st.innerText="Status: STOP"; } } }; ws.onclose=()=>setTimeout(()=>initWebSocket(device,prefix,attempt+1),2000); }catch(e){console.error("WS-Fehler",e);} } function addSomfyButtons(block,device,prefix){ [["AUF","btn-up","up"],["STOP","btn-stop","stop"],["AB","btn-down","down"]] .forEach(([txt,cls,act])=>{ const b=document.createElement("button"); b.className="btn "+cls; b.innerText=device.name+" "+txt; b.onclick=()=>sendSomfyCmd(device.ip,act); block.appendChild(b); }); const st=document.createElement("div"); st.id=`${prefix}_status_${device.ip}`; st.className="status"; st.innerText="Status: unbekannt"; block.appendChild(st); } } function safeInit(){ try{initSomfyDashboard();}catch(e){console.error(e);} } safeInit(); if(document.readyState==="loading"){ document.addEventListener("DOMContentLoaded",safeInit); } setTimeout(safeInit,500); </script> </body> </html> Das wäre die Rolladen Schaltung als Schalter version für 2 Kontakte. <!DOCTYPE html> <html> <head> <style> /* Container nur für dieses Panel (EG) */ #devices_eg { display: flex; flex-wrap: wrap; gap: 15px; } /* Raumkarte */ .device { flex: 1 1 130px; max-width: 200px; padding: 10px; border: 1px solid #003366; border-radius: 12px; box-shadow: 2px 2px 5px rgba(0,0,0,0.2); color: white; } .device h3 { margin: 5px 0 10px 0; font-size: 14px; text-align: center; } /* Schalt-Buttons */ .btn { color: white; width: 100%; height: 38px; margin: 4px 0; border: none; border-radius: 8px; font-size: 12px; cursor: pointer; } .btn-on { background: green; } .btn-off { background: red; } </style> </head> <body> <div id="devices_eg"></div> <script> (function(){ const PREFIX = "eg"; // eindeutig für dieses Panel const CONTAINER_ID = "devices_eg"; const roomColors = { "Arbeitszimmer": "#444a97", "Schlafzimmer": "#d2cc19", "Wohnzimmer": "#1c5a1b", "Terrasse": "#7f19d2", "Esszimmer": "#19bcd2", "Küche": "#7e1161", "Bad": "#3fe23c", "Flur": "#3ce2d7" }; // === EG Geräte-Liste === const devices = [ { room: "Arbeitszimmer", devices: [ { ip:"192.168.178.60", relays:[{id:0,name:"Licht"}] }, { ip:"192.168.178.62", relays:[{id:0,name:"Steckdose 1"}] }, { ip:"192.168.178.63", relays:[{id:0,name:"Steckdose 2"}] } ]}, { room: "Schlafzimmer", devices: [ { ip:"192.168.178.64", relays:[{id:0,name:"Licht"}] }, { ip:"192.168.178.66", relays:[{id:0,name:"Steckdose 1"}] }, { ip:"192.168.178.67", relays:[{id:0,name:"Steckdose 2"}] }, { ip:"192.168.178.68", relays:[{id:0,name:"Steckdose 3"}] }, { ip:"192.168.178.69", relays:[{id:0,name:"Steckdose 4"}] } ]}, { room: "Wohnzimmer", devices: [ { ip:"192.168.178.70", relays:[{id:0,name:"Licht"}] }, { ip:"192.168.178.73", relays:[{id:0,name:"Steckdose 1"}] }, { ip:"192.168.178.74", relays:[{id:0,name:"Steckdose 2"}] }, { ip:"192.168.178.75", relays:[{id:0,name:"Steckdose 3"}] }, { ip:"192.168.178.76", relays:[{id:0,name:"Steckdose 4"}] }, { ip:"192.168.178.77", relays:[{id:0,name:"Steckdose 5"}] } ]}, { room: "Terrasse", devices: [ { ip:"192.168.178.78", relays:[{id:0,name:"Licht"}] }, { ip:"192.168.178.80", relays:[{id:0,name:"Steckdose 1"}] }, { ip:"192.168.178.81", relays:[{id:0,name:"Steckdose 2"}] } ]}, { room: "Esszimmer", devices: [ { ip:"192.168.178.82", relays:[{id:0,name:"Licht"}] }, { ip:"192.168.178.85", relays:[{id:0,name:"Steckdose 1"}] }, { ip:"192.168.178.86", relays:[{id:0,name:"Steckdose 2"}] }, { ip:"192.168.178.87", relays:[{id:0,name:"Steckdose 3"}] } ]}, { room: "Küche", devices: [ { ip:"192.168.178.88", relays:[{id:0,name:"Licht"}] }, // HIER Änderung: Shelly 2PM → 2 Relais für 2 Hauben { ip:"192.168.178.90", relays:[ {id:0,name:"Dunstabzug 1"}, {id:1,name:"Dunstabzug 2"} ]}, { ip:"192.168.178.91", relays:[ {id:0,name:"Herd Phase 1"}, {id:1,name:"Herd Phase 2"}, {id:2,name:"Herd Phase 3"} ]}, { ip:"192.168.178.92", relays:[{id:0,name:"Steckdose 1"}] }, { ip:"192.168.178.93", relays:[{id:0,name:"Steckdose 2"}] } ]}, { room: "Bad", devices: [ { ip:"192.168.178.94", relays:[{id:0,name:"Licht"}] }, { ip:"192.168.178.96", relays:[{id:0,name:"Spiegel Licht"}] } ]}, { room: "Flur", devices: [ { ip:"192.168.178.97", relays:[{id:0,name:"Licht Innen"}] }, { ip:"192.168.178.98", relays:[{id:0,name:"Treppe Licht 1"}] }, { ip:"192.168.178.100", relays:[{id:0,name:"Treppe Licht 2"}] }, { ip:"192.168.178.102", relays:[{id:0,name:"Steckdose Haustür"}] }, { ip:"192.168.178.103", relays:[{id:0,name:"Haustür Licht"}] } ]} ]; /* =========================== GLOBALER WEBSOCKET-POOL =========================== */ const WS_POOL_KEY = "__ShellyWsPool"; const pool = window[WS_POOL_KEY] (window[WS_POOL_KEY] = new Map()); function ensureSocket(ip){ if (pool.has(ip)) return pool.get(ip); const entry = { ws:null, listeners:new Set(), lastMsgTs:0, pollTimer:null }; pool.set(ip, entry); function connect(attempt=0){ try { const ws = new WebSocket(`ws://${ip}/rpc`); entry.ws = ws; ws.onopen = () => { try{ ws.send('{"id":1,"src":"grafana","method":"Shelly.GetStatus"}'); }catch(_){} }; ws.onmessage = (e) => { entry.lastMsgTs = Date.now(); const msg = JSON.parse(e.data); const status = msg.result msg.params; if(!status) return; Object.keys(status).forEach(k=>{ const m=k.match(/^switch:(\d+)$/); if(m && status[k] && typeof status[k].output==="boolean"){ const relId=parseInt(m[1],10); const isOn=status[k].output; entry.listeners.forEach(fn=>{ try{fn({ip,relId,isOn});}catch(_){}} ); } }); }; ws.onclose=()=>{ setTimeout(()=>connect(attempt+1), Math.min(10000,1000*(attempt+1))); }; ws.onerror=()=>{ try{ws.close();}catch(_){}}; } catch(e){ setTimeout(()=>connect(attempt+1),2000); } } connect(); return entry; } function subscribe(ip, handler){ const entry=ensureSocket(ip); entry.listeners.add(handler); (async()=>{ try{ const res=await fetch(`http://${ip}/rpc/Shelly.GetStatus`,{ method:"POST",headers:{"Content-Type":"application/json"},body:"{}" }); const data=await res.json(); const status=data && data.result ? data.result : null; if(status){ Object.keys(status).forEach(k=>{ const m=k.match(/^switch:(\d+)$/); if(m && status[k] && typeof status[k].output==="boolean"){ handler({ip, relId:parseInt(m[1],10), isOn:status[k].output}); } }); } }catch(_){} })(); } /* =========================== UI =========================== */ const root=document.getElementById(CONTAINER_ID); root.innerHTML=""; devices.forEach(roomBlock=>{ const card=document.createElement("div"); card.className="device"; card.style.backgroundColor=roomColors[roomBlock.room]||"#4169E1"; const h=document.createElement("h3"); h.textContent=roomBlock.room; card.appendChild(h); roomBlock.devices.forEach(dev=>{ dev.relays.forEach(rel=>{ const btn=document.createElement("button"); btn.id=`${PREFIX}_relay_${dev.ip}_${rel.id}`; btn.className="btn btn-off"; btn.textContent=`${rel.name} AUS`; btn.onclick=()=>toggleRelay(dev.ip, rel.id, rel.name); card.appendChild(btn); subscribe(dev.ip, ({ip,relId,isOn})=>{ if(relId!==rel.id) return; const b=document.getElementById(`${PREFIX}_relay_${ip}_${relId}`); if(!b) return; if(isOn){ b.className="btn btn-on"; b.textContent=`${rel.name} EIN`; } else { b.className="btn btn-off"; b.textContent=`${rel.name} AUS`; } }); }); }); root.appendChild(card); }); /* =========================== Toggle =========================== */ function toggleRelay(ip, relayId, label){ fetch(`http://${ip}/rpc/Switch.Toggle`,{ method:"POST",headers:{"Content-Type":"application/json"}, body:JSON.stringify({id:relayId}) }).catch(err=>console.error("Toggle-Fehler",ip,relayId,err)); } })(); // Ende </script> </body> </html>
Und das Wäre für die Zimmer die Schalter und Steckdosen Steuerung für das Grafana Text Plugin, hir wurden Shelly 1 pm plus (gen4) getestet und verwendet.Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen. HTML
Alles anzeigen<!DOCTYPE html> <html> <head> <style> #devices_garage { display: flex; flex-wrap: wrap; gap: 15px; } .device { flex: 1 1 130px; max-width: 200px; padding: 10px; border: 1px solid #003366; border-radius: 12px; box-shadow: 2px 2px 5px rgba(0,0,0,0.2); color: white; } .device h3 { margin: 5px 0 10px 0; font-size: 14px; text-align: center; } .btn { color: white; width: 100%; height: 38px; margin: 4px 0; border: none; border-radius: 8px; font-size: 12px; cursor: pointer; } .btn-up { background: green; } .btn-stop { background: blue; } .btn-down { background: yellow; color: black; } .status { margin-top: 5px; font-size: 12px; text-align: center; font-weight: bold; color: #fff; } </style> </head> <body> <div id="devices_garage"></div> <script> (function(){ const PREFIX = "garage"; const CONTAINER_ID = "devices_garage"; const roomColors = { "Hebebühne": "#5b8def", "Garage": "#e67e22", "Grube": "#1abc9c", "Stall": "#9b59b6" }; const devices = [ { room: "Hebebühne", devices: [ { ip:"192.168.178.104", name:"Tor" } ]}, { room: "Garage", devices: [ { ip:"192.168.178.109", name:"Tor" } ]}, { room: "Grube", devices: [ { ip:"192.168.178.110", name:"Tor" } ]}, { room: "Stall", devices: [ { ip:"192.168.178.111", name:"Tor" } ]} ]; const root = document.getElementById(CONTAINER_ID); root.innerHTML = ""; devices.forEach(roomBlock=>{ const card=document.createElement("div"); card.className="device"; card.style.backgroundColor=roomColors[roomBlock.room] "#4169E1"; const h=document.createElement("h3"); h.textContent=roomBlock.room; card.appendChild(h); roomBlock.devices.forEach(dev=>{ addRollerButtons(card,dev); initWebSocket(dev); }); root.appendChild(card); }); /* ---------- Funktionen ---------- */ function sendRollerCmd(ip,action){ const method = action==="open" ? "Cover.Open" : action==="close" ? "Cover.Close" : "Cover.Stop"; fetch(`http://${ip}/rpc`,{ method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({id:1,method,params:{id:0}}) }).catch(err=>console.error("Roller-Fehler",ip,err)); } function translateState(state,pos){ if(typeof pos==="number"){ if(pos===0) return `ZU (${pos}%)`; if(pos===100) return `AUF (${pos}%)`; } if(!state) return `unbekannt${pos!==null?` (${pos}%)`:""}`; const s = String(state).toLowerCase().trim(); if (s==="open" s==="opened") return `AUF (${pos??"?"}%)`; if (s==="close"|| s==="closed") return `ZU (${pos??"?"}%)`; if (s==="opening") return `öffnet (${pos??"?"}%)`; if (s==="closing") return `schließt (${pos??"?"}%)`; if (s==="stopped" s==="stop") return `STOPP (${pos??"?"}%)`; return `${state}${pos!==null?` (${pos}%)`:""}`; } function updateCoverStatus(ip, cover){ if(!cover) return; const stEl = document.getElementById(`${PREFIX}_cover_status_${ip}`); if(!stEl) return; const pos = (typeof cover.pos === "number") ? cover.pos : (typeof cover.current_pos === "number") ? cover.current_pos : (typeof cover.applied_pos === "number") ? cover.applied_pos : null; const rawState = cover.state cover.current_state cover.applied_state; stEl.innerText = "Status: " + translateState(rawState,pos); } function initWebSocket(device, attempt=0){ try{ const ws = new WebSocket(`ws://${device.ip}/rpc`); ws.onopen = ()=>{ try { ws.send('{"id":1,"src":"grafana","method":"Cover.GetStatus","params":{"id":0}}'); } catch(_){} }; ws.onmessage = (e)=>{ let data; try { data = JSON.parse(e.data); } catch(_){ return; } if (data.result) { updateCoverStatus(device.ip, data.result); } if (data.params && data.params["cover:0"]) { updateCoverStatus(device.ip, data.params["cover:0"]); } }; ws.onclose = ()=>{ setTimeout(()=>initWebSocket(device, attempt+1), Math.min(10000, 1000*(attempt+1))); }; ws.onerror = ()=>{ try{ ws.close(); }catch(_){ } }; }catch(e){ console.error("WS-Fehler", device.ip, e); } } function addRollerButtons(block,device){ [ ["AUF","btn-up","open"], ["STOP","btn-stop","stop"], ["AB","btn-down","close"] ].forEach(([txt,cls,act])=>{ const b=document.createElement("button"); b.className="btn "+cls; b.innerText=device.name+" "+txt; b.onclick=()=>sendRollerCmd(device.ip,act); block.appendChild(b); }); const st=document.createElement("div"); st.id=`${PREFIX}_cover_status_${device.ip}`; st.className="status"; st.innerText="Status: unbekannt"; block.appendChild(st); } })(); // Ende IIFE </script> </body> </html>
So sieht meine Garagentor Steuerung aus ebenfalls mit Zustandsüberwachung.Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen. Und zuguter letzt meine Torlicht Steuerung als Skript für die Shelly 1pm plus gn4 damit die Lichter an gehen wenn das Tor Hoch fährt.
Code// ###########################################################// Shelly 1PM Plus (Gen4) – folgt Tor (Shelly 2PM im Cover-Modus)// mit Sonnenstands-Sperre (nur nachts aktiv)// ###########################################################//// Endgültige Regeln (nur aktiv wenn es dunkel ist!):// - Bei 20% öffnen -> Licht EIN// - Bei 100% -> Licht 20s EIN, danach AUS (nur einmal)// - Wenn Tor von 100% auf <100% fährt (Start Schließen) -> Licht EIN// - Bei 20% schließen -> Licht AUS//// ###########################################################// IP-Adresse des Shelly 2PM (Torsteuerung)let sourceShelly = "192.168.178.104";// Abfrageintervall (ms)let interval = 5000; // alle 5 Sekunden// Haltezeit wenn Tor komplett offen (in Sekunden)let holdTime = 120;// interne Zuständelet lastOn = false;let holdTimer = null;let holdActive = false;let lastPos = null;// Sonnenauf-/unterganglet sunrise = null;let sunset = null;// Hilfsfunktionenfunction switchLight(on) { Shelly.call("Switch.Set", { id: 0, on: on }); lastOn = on; print("Licht", on ? "EIN" : "AUS");}function cancelHoldTimer() { if (holdTimer !== null) { Timer.clear(holdTimer); holdTimer = null; print("Hold-Timer abgebrochen"); }}function isNight() { if (!sunrise || !sunset) return true; // wenn keine Werte -> sicherheitshalber aktiv let now = (new Date()).getTime() / 1000; // aktuelle Zeit in UNIX Sekunden return (now < sunrise || now > sunset);}function updateSunTimes() { Shelly.call("Sys.GetStatus", {}, function(res) { if (res && res.sunrise && res.sunset) { sunrise = res.sunrise; sunset = res.sunset; print("Sonnenaufgang:", sunrise, "Sonnenuntergang:", sunset); } else { print("Keine Sonnenzeiten gefunden – Nacht-Check immer TRUE"); } });}// Hauptprüfungfunction checkCover() { if (!isNight()) { // Tagsüber -> Licht sicher ausschalten und überspringen if (lastOn) { switchLight(false); cancelHoldTimer(); holdActive = false; } print("Tag erkannt – Lichtsteuerung gesperrt"); return; } let url = "http://" + sourceShelly + "/rpc/Cover.GetStatus?id=0"; Shelly.call("HTTP.GET", { url: url }, function(res) { if (!res || res.code !== 200) { print("HTTP Fehler:", res ? res.code : "kein Ergebnis"); return; } try { let data = JSON.parse(res.body); let pos = data.current_pos; if (typeof pos === "string") pos = parseFloat(pos); print("Tor-Position:", pos, "%", "(last:", lastPos, ")"); // --- Regel 2: Bei 100% -> Licht 20s EIN, danach AUS (nur einmal) if (pos >= 100) { if (!holdActive) { holdActive = true; if (!lastOn) { switchLight(true); print("Licht EIN (Tor 100%, Timer gestartet)"); } cancelHoldTimer(); holdTimer = Timer.set(holdTime * 1000, false, function() { switchLight(false); print("Licht AUS (Timer abgelaufen bei 100%)"); }); } lastPos = pos; return; } // --- Regel 3: Start Schließen von 100% -> Licht EIN if (lastPos !== null && lastPos >= 100 && pos < 100) { if (!lastOn) { switchLight(true); print("Licht EIN (Start Schließen von 100% -> <100%)"); } holdActive = false; cancelHoldTimer(); } if (lastPos !== null) { // --- Regel 1: Bei 20% öffnen -> Crossing von <20% auf >=20% if (lastPos < 20 && pos >= 20) { if (!lastOn) { switchLight(true); print("Licht EIN (Öffnen: Crossing über 20%)"); } } // --- Regel 4: Bei 20% schließen -> Crossing von >20% auf <=20% if (lastPos > 20 && pos <= 20) { if (lastOn) { switchLight(false); print("Licht AUS (Schließen: Crossing unter 20%)"); } holdActive = false; cancelHoldTimer(); } } lastPos = pos; } catch (e) { print("Parsing Fehler:", e); } });}// Timer startenTimer.set(interval, true, checkCover);// Sonnenauf-/untergang alle 10min aktualisierenupdateSunTimes();Timer.set(600000, true, updateSunTimes); // 10 min
-
Eine Frage gibt es hier im Forum eine Ideen Ecke, wo mann dann auch seine Sachen bereitstellen kann soweit war ich mit dem Forum noch nicht durch.
-
Ja das mache ich aber wie das so immer ist mit Haus, Job, Frau, und so kleinen gesundheitlichen Befindlichkeiten wird das ganze noch etwas Dauern, das umzusetzen, geplant ist vieles .
-
Nimm dein Kabel und lege es etwas gespannt in die Sonne Abends ist dein Kabl schnur gerade wirst sehn.
-
Tja wer bin ich heiße (Jo)Hannes bin BJ 73 also gehöre schon zu denen die das Maßband zur Rente immer kürzer abreisen.
War früher ein ganz normaler Arbeiter Maurer,LKW Fahrer, Baumaschinenmechaniker, Schlosser und dann kam das jahr 2020 2x Unfälle eine Umschulung zum Technischenproduktdesigner und Konstrukteur.
Und jetzt naja ich Schraube bastele und Tüftele seit dem ich nen Schraubendreher in der Hand halten kann, mein erstes Mofa lief 105 km/h also schon immer Technik afin, bin mit C64 gross geworden, und nun Arbeite ich als CAD Konstrukteur mache 3 D Druck und mache unser Haus Smarthome fähig und auch relativ Energie Outtark, die letzen Jahre habe ich viel mit 433MHZ schaltaktoren gearbeitet aber die Technik ist nicht zuverlässig und hat so ihre probleme.
Seit etwa 4 Wochen Stelle ich unser Haus auf Shellys um neben bei läuft auf einem Pi4 mit 8gb eine Solaranzeige mit Grafana ect und hier werden dann auch die Shellys gesteuert via Plugin.
Was mich Antreibt die Neugierde wenn man zb eine kaputte Bohrmaschine da liegen hat und daneben ein passendes Werkzeug, und der Versuchung nicht wiederstehen kann das Teil zu zerlegen und zu ergründen warum etwas kaputt gegangen ist, dann hat man so einen Job wie ich.
Und seit neuestem beschäftige ich mit KI ich nutze sie zur Programierung den selbst programieren kann ich nicht ( naja man lernt halt ein bischen was dabei) und so entstehen rstaunliche Projekte .
-
Da wir auch ein OG haben, ist die nächste Aktion der Treppenlift für mich Smart zumachen, auch mit einem Shelly im prinzip sollte das mit ebenfalls einem 2 PM funktionieren.
Ich denke hier sogar darüber nach meinen Rolli mit einem NFC Chip auszustatten den habe ich ja immer bei mir, somit öffnen sich für mich Tor und Tür alleine. 95% Steuere ich aktuell übers Smart Phone.
Was auch noch kommt sind eben selbst öffnentes Tür Schloss mit Fingerprint zb und meine Smarte Haustürklingel einen selbst gebauten Paketbriefkasten habe ich auch schon der solangsam Smart wird er meldet wenn Post bzw Pakete gekommen sind und ob sie entnommen wurden.
Ist halt meine grosse Spielwiese.
Verwante und Bekannte sind immer wieder erstaunt wenn sie kommen was es neues Smartes als Eigenbau gibt.
Dazu grosse PV mit 22 kw Speicher Netto auch ein DIY Akku von mir gebaut, so bin ich eigentlich Strom unabhängig.
-
Ich Arbeite hier mit der Solaranzeige und über Grafana habe ich mir Button programiert ( mit KI) das waren doch mehrere Wochen Arbeit immer wieder halt 2-3 St Abends den nen Job habe ich ja auch.
Über das Grafana Text Plugin habe ich mit einen HTML Javacode genrieren lassen.
Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen. Das waren so die Anfänge, mittlerweile funktioniert das erstaunlich gut, sogar mit Status Anzeige ob Rolläden oder unsere Rolltore der Gargen offen und geschlossen sind, selbst eine Lichtsteuerung bei den Toren konnte ich erfolgreich mit KI generieren ich bin erstaunt wie gut das ganze mittlerweile geht.
Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen. Hier mal das Erdgeschoss
Und Hier unsere Garagen
Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen. Du siehst es geht und ich habe keinerlei programier Kenntnisse aber ich kann der KI sehr gut Beschreiben was ich einsetzen möchte, und was ich mir Vorstelle.
Man muss aber immer im Hinterkopf behalten die KI ist wie ein kleines Kind macht Fehler aber wenn man ihr etwas Zeit gibt und die richtige Richtung weißt kommt man ans Ziel.
Was am Anfang 30-40-50 Versuche benötigte bin ich Stand jetzt, bei 3-5 Anläufen und dann funktioniert es meistens und sie macht auch gute Vorschläge zur verbesserung.
Solaranzeige Shelly Schalten per Grafana Button ich hoffe das ist ok der quer Verweis zu diesem Forum
Das ganze kann ich auf dem PC auf dem Tablet oder eben am Smartphone aufrufen von aussen via VPN über die Fritz Box also alles voll felxibel und eben Cloud frei.
-
Da hast du schon Recht, nur bin ich halt nur mit AOK Chopper unterwegs da sind so spielereien wie mit den Shelly sehr angenehm, zb ich habs mir auf der Couch gemütlich gemacht ( ode wie mä in frang sachd aufm Kanabee) um nicht wieder extra in den Rolli zu müssen sind solche umbauten für mich sehr hilfreich und erleichtern das Leben.
Dann kommt halt auch noch der Bastler und Schrauber in mir ein kleinwenig das haben will Syndrom und schon sind wir wieder dabei.
-
Auch wenn mich viele jetzt hier Anfeinden werden ( oder auch nicht) ich bin kein Cloud Fan, genau aus solchen Gründen, es soll nach möglichkeit alles im Intranet laufen zur Not mit einem eigenen Server, oder besser noch Stand alone.
Ja mit Cloud mag das für viele eine Einfache Lösung sein und auch Features bieten die ich ohne Cloud nicht habe, aber hier geht es um meine Infrastruktur Licht bzw Strom ist teilweise Essenziell für mich Nachts sogar Lebensnotwendig, da gehe ich keinerlei Kompromiss ein.
-
Da geb ich dir recht und das mit den Leisten ist ja schon mal ne super Option, Vorteil bei dieser Treppe ich kann leicht hier ein 5 mm Loch in das Stirnbrett Bohren und die Kabel unter der Treppe verbinden und somit Unsichtbar verlegen.
Was hl noch ein Vorteil ist das sie ein Potest ebenfalls aus Holz hat da ich das ganze Später eh von unten Verklide sieht man zum Schluss nichts mehr geht eh um Keller runter und ist mit einer Tür so eh nicht gleich Sichtbar.
Der Aufwand ist nur einmal wenn das gemacht ist ist es ja auch gut, ich muss das ja nicht 20 mal im Jahr machen einmal im Leben reicht mir.
-
Ja ist eh eine 2 Stufige Treppe mit Podest erst 8 Stufen dann Sieben dazu eine Holztreppe die ich eh herrichten will Kiefernholz als tritt Fläche die Kantenleisten aus Rotbuche sowas ist nicht mehr zubekommen und wenn dann für viel Geld .
-
Nein am Tag nur mit Schalter bzw Wechselschaltung Nachts bei Schalter Betätigung weis ansonsten gedimmt Grün oder was halt passt, ja das mit der Länge ist mir bekannt 15 Stufen a 90 cm also 13,5 Meter Länge das einschalten des gedimmten Lichts würde ich über die Sonnenaufgang Sonnenuntergang Regelung machen.
-
Tja ein neues Projekt, ich möchte an meine Holztreppe unter den Stufen jeweils einen 90 cm Langen LED Streifen als Beleuchtung anbringen, und das ganze mit einem Shelly rgbw schalten, ich würde sofern es von der Leistung her passt alle Stripes nacheinander schalten.
Nur wie geh ich a am besten vor?
Klar ich brauche 15 M LED die Trennbar sind die enden werden jeweils mit Kabeln verbunden nacheinander, dazwischen den Shelly rgbw dann Controller? und dann Spannungswandler von 230v auf 24 V ?
Kann mir da jemand was dazu sagen was sich bis jetzt gut bewehrt hat?
Vor allem würde ich untertags und wenn man auf Weisschaltet alles hell Leuchten lassen und nachts sollten zb nur grün ganz leicht Leuchten lässt sich sowas mit eine Skript bewerkstelligen?
Über Hilfe und gedanken Austausch bevor ich einen groß Einkauf starte wäre ich dankbar.