Blog der Heimetli Software AG

Steuern von Hue-Lampen mit einer HTML-Seite

Falls Sie nicht auf den Internet-Explorer angewiesen sind, dann nehmen Sie besser die erweiterte Version dieser Seite: Hue-Lampen steuern mit dem fetch-API.

Die Hue-Bridge setzt die CORS-Header, so dass man sie von einer beliebigen Webseite aus steuern kann. Es braucht also weder einen Webserver noch sonstige Infrastruktur, eine einzige HTML-Seite mit etwas JavaScript reicht aus um die Lampen ein- und auszuschalten.

Selbstverständlich müsste es möglich sein auch alle anderen Parameter dieser Lampen zu steuern, aber bisher habe ich nur das Schalten realisiert.

Um die Lampen zu schalten braucht es einen PUT-Request, und den bekommt man aus einer HTML-Seite wohl nur per AJAX hin. Den Status abzufragen und vernünftig darzustellen geht ebenfalls am einfachsten per JavaScript.

Die HTML-Seite

screenshot

Das Design kann man sicher noch verbessern, mir ging es vor allem um die Funktion...

lamps enthält den aktuellen Status der Lampen. Er wird am Anfang gelesen und dann nur noch von toggle geändert.

So lange es nur eine einzige Instanz der Seite gibt, ist das kein Problem, aber sobald zwei oder mehr Geräte diese Webseite nutzen gibt es Inkonsistenzen. Es ist also sinnvoll den Zustand periodisch von der Bridge zu lesen.

Die Buttons der Lampen die nicht erreichbar sind werden rot dargestellt. Die Buttons der leuchtenden Lampen sind grün eingefärbt. Buttons von ausgeschalteten Lampen sind grau.

Beachten Sie die CSS-Regel für die Buttons. Ich hatte wirklich geglaubt dass alle aktuellen Browser sich an den Standard halten! Zumindest der Safari auf einem aktuellen iPad braucht aber die -webkit-appearance Angabe, sonst zeigt er einen unveränderlichen Button im Apple-Style an :-/

<!DOCTYPE html>
<html lang="de">
 <head>
  <meta charset="utf-8">
  <title>Komplexeres AJAX-Beispiel</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
   input { -webkit-appearance: none; display: block; padding: 1em; }
  </style>
  <script>
   var url = "http://192.168.1.121/api/XsbA-ZrmWbp42eeXu5j8otqJlPnIIX1Mxbh6rwn8/lights" ;

   // Name and state of the lamps
   var lamps  = [
                 { name: "1", reachable: false, on: false },
                 { name: "2", reachable: false, on: false },
                 { name: "3", reachable: false, on: false }
                ] ;

   // Requests the current state of all the lamps
   function getState()
   {
      var xhr                = new XMLHttpRequest() ;
      xhr.onreadystatechange = status ;
      xhr.ontimeout          = timeout ;
      xhr.onerror            = error ;
      xhr.open( "GET", url, true ) ;
      xhr.setRequestHeader( 'Content-type', 'application/json; charset=utf-8' ) ;
      xhr.send( null ) ;
   }

   // Is called when the state of the request changes
   function status()
   {
      // Checks if the request is done
      if( this.readyState == 4 )
      {
         // Checks if the request was successful
         if( this.status == 200 )
            processState( JSON.parse(this.responseText) ) ;
         else
            display( "Fehler: status " + this.status ) ;
      }
   }

   // Called when a timout occurs
   function timeout()
   {
      display( "Fehler: timeout" ) ;
   }

   // Called when an error occurs
   function error()
   {
      display( "Fehler: error" ) ;
   }

   // Displays the given text in the paragraph
   function display( text )
   {
      document.querySelector( "p" ).innerHTML = text ;
   }

   // Updates the button colors to show the current state
   function updateView()
   {
      for( var i = 0; i < lamps.length; i++ )
      {
         var lamp = lamps[i] ;

         if( !lamp.reachable )
         {
            color = "red" ;
         }
         else if( lamp.on )
         {
            color = "green" ;
         }
         else
         {
            color = "lightgrey" ;
         }

         document.querySelector( "#L" + lamp.name ).style.backgroundColor = color ;
      }
   }

   // Is called when the request returns a valid state
   function processState( obj )
   {
      var color ;

      for( var i = 0; i < lamps.length; i++ )
      {
         var lamp       = lamps[i] ;
         var state      = obj[lamp.name].state ;

         lamp.reachable = state.reachable ;
         lamp.on        = state.on ;
      }

      updateView() ;
   }

   // Toggles a lamp on or off
   function toggle( id )
   {
      var lamp = lamps[id-1] ;

      lamp.on = !lamp.on ;

      // Note: the response is ignored
      var xhr = new XMLHttpRequest() ;
      xhr.open( "PUT", url + "/" + id + "/state", true ) ;
      xhr.setRequestHeader( 'Content-type', 'application/json; charset=utf-8' ) ;
      xhr.send( JSON.stringify({on:lamp.on}) ) ;

      updateView() ;
   }
  </script>
 </head>
 <body onload="getState()">
  <h1>Hue-Lampen schalten mit AJAX</h1>
  <input type="button" value="Lampe 1" id="L1" onclick="toggle(1)">
  <input type="button" value="Lampe 2" id="L2" onclick="toggle(2)">
  <input type="button" value="Lampe 3" id="L3" onclick="toggle(3)">
  <p></p>
 </body>
</html>

Das Sourcefile

Sie können hue.html hier herunterladen.