Effiziente Shelly-Gerätesteuerung mit einem Taster (Shelly i4)und JavaScript

Ich habe kürzlich damit begonnen meine Wohnung mit smarten Geräten auszustatten. Bisher habe ich eine einfache Funkfernbedienung gehabt welche nun nach viele Jahren den Geist aufgegeben hat um das Ein- und Ausschalten des Fernsehers und einige Leuchtmittel zu schalten.

Um nicht jedes Gerät einzeln schalten zu müssen, habe ich eine Shelly i4 mit einem Taster an meinem bisherigen Schalter platziert. Über ein selbst geschriebenes Script werden jetzt alle Geräte intelligent gesteuert. Drücke ich den Taster, schaltet sich entweder alles Ein oder alles Aus, je nach vorherigem Zustand.

Funktionsweise

Das Script fragt zunächst per HTTP-Request den Status aller Shellys ab. Basierend auf diesem Status werden dann Aktionen ausgeführt:

  • Wenn nur ein Gerät eingeschaltet ist, werden alle Geräte ausgeschaltet
  • Wenn alle Geräte aus sind, werden alle eingeschaltet
  • Wenn alle bereits eingeschaltet sind, werden wieder alle ausgeschaltet

So erreiche ich mit einem Tastendruck am einfachsten den gewünschten Zustand, ohne mich um Einzelsteuerungen kümmern zu müssen.

Die Taster-Events der Shelly i4 lösen die Ausführung dieses Scripts aus. Über Callbacks wird asynchron der Status abgefragt und Actions zum Ein- und Ausschalten ausgeführt.

In meiner ersten Version hatte ich versucht, den Ein/Aus-Status der einzelnen Geräte in Variablen zu cachen. Ziel war es, nicht jedes Mal erneut HTTP-Anfragen zum Shelly schicken zu müssen.

Allerdings zeigte sich in der Praxis, dass der gespeicherte Status nicht immer dem tatsächlichen entsprach. Einige Geräte blieben fälschlicherweise als „aus“ in der Variablen gespeichert, obwohl sie manuell wieder eingeschaltet wurden.

Durch das Abfragen des aktuellen Status direkt bei Ausführung des Scripts konnte ich dieses Problem umgehen. Selbst wenn Geräte manuell geschaltet werden, wird jetzt zuverlässig der korrekte Zustand erkannt und die gewünschte Aktion ausgelöst.

Auch für zukünftige Erweiterungen ist diese Vorgehensweise von Vorteil. Etwa wenn die Beleuchtung tagsüber automatisch ausgeschaltet werden soll. Über Zeitpläne im Shelly kann dies einfach umgesetzt werden, ohne das Script anpassen zu müssen.

Das JavaScript:

				
					Shelly.addEventHandler(
  function (event, ud) {
      if (event.component === "input:1") {
        if (event.info.event === "single_push") {
          let isKitchenOn = KuechenLichtCurrentState();
          let isTVOn = TVCurrentState();
          let isTVLightOn = TVLightCurrentState();
          
          if( (isKitchenOn && !isTVOn && !isTVLightOn) || 
              (!isKitchenOn && isTVOn && !isTVLightOn) ||
              (!isKitchenOn && !isTVOn && isTVLightOn) ) {
            // Nur ein Schalter ist an -> Alle aus
            turnOffKitchenLight();
            turnOffTV(); 
            turnOffTVLight();
            turnOffSoundbar();
          } else if(isKitchenOn && isTVOn && isTVLightOn) {
            // Alle sind bereits an -> Alle aus
            turnOffKitchenLight();
            turnOffTV(); 
            turnOffTVLight();
            turnOffSoundbar();
          } else {
            // Alle sind aus -> Alle an
            turnOnKitchenLight();
            turnOnTV();
            turnOnTVLight();   
            turnOnSoundbar();
          }
        }
      }
  },
  null
);


function KuechenLichtCurrentState() {
  let outputStatus;
  Shelly.call("HTTP.GET", { 
    "url": "http://192.168.178.129/rpc/Shelly.GetStatus"
  }, function(result) {
    let data = JSON.parse(result.body);
    outputStatus = data.switch["0"].output; 
  });
  return outputStatus;
}

function TVCurrentState() {
  let outputStatus;
  Shelly.call("HTTP.GET", { 
    "url": "http://192.168.178.130/rpc/Shelly.GetStatus"
  }, function(result) {
    let data = JSON.parse(result.body);
    outputStatus = data.switch["0"].output; 
  });
  return outputStatus;
}

function TVLightCurrentState() {
  let outputStatus;
  Shelly.call("HTTP.GET", { 
    "url": "http://192.168.178.131/rpc/Shelly.GetStatus"
  }, function(result) {
    let data = JSON.parse(result.body);
    outputStatus = data.switch["0"].output; 
  });
  return outputStatus;
}

function turnOffKitchenLight() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.129/relay/0?turn=off",},null);
}
function turnOffTV() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.130/relay/0?turn=off",},null);
}
function turnOffTVLight() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.131/relay/0?turn=off",},null);
}

function turnOnKitchenLight() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.129/relay/0?turn=on",},null);
}
function turnOnTV() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.130/relay/0?turn=on",},null);
}
function turnOnTVLight() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.131/relay/0?turn=on",},null);
}
function turnOnSoundbar() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.26/YamahaExtendedControl/v1/main/setPower?power=on",},null);
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.26/YamahaExtendedControl/v1/main/setVolume?volume=55",},null);
}
function turnOffSoundbar() {
  Shelly.call("HTTP.GET", {"url": "http://192.168.178.26/YamahaExtendedControl/v1/main/setPower?power=standby",},null);
}
				
			

Fazit

In diesem Projekt habe ich die Shelly i4 für die Automatisierung meines Smart Homes genutzt. Über ein selbstgeschriebenes Script werden nun alle Geräte (Beleuchtung, Fernseher etc.) intelligent per Knopfdruck geschaltet.

Die asynchrone Statusabfrage ermöglicht dabei eine flexible Steuerungslogik. Auch meine Soundbar konnte über HTTP angebunden werden.

Die Recherche der Shelly APIs war aufwändig, hat sich aber gelohnt: Der Komfortgewinn durch die Automatisierung ist enorm!

Alles in allem habe ich die Shelly i4 als ideale Smart Home Zentrale kennen und schätzen gelernt. Komplexe Szenarien lassen sich durch selbstgeschriebene Scripts einfach umsetzen. Die Erweiterbarkeit ist nahezu unbegrenzt.