Blog der Heimetli Software AG

Steuern von Hue-Lampen mit AJAX

Schon letztes Jahr habe ich die Hue Lampen mit AJAX ein- und ausgeschaltet.

Kürzlich habe ich die fetch-API der neuen Browser entdeckt und stellte Versuche damit an. Das ging überraschend glatt, und so lag es nahe, das AJAX für die Hue-Lampen mit dieser API zu vereinfachen.

Im gleichen Zug wurde die Seite noch um die Einstellung des Farbtons erweitert:

Screenshot: Hue-Lampen steuern mit AJAX

Wie bei der letzten Version zeigt ein grüner Button an dass die Lampe brennt. Ein grauer Button bedeutet dass die Lampe nicht brennt, und ein roter zeigt an dass sie nicht erreichbar ist.

Der Slider bestimmt den Farbton. Die Dokumentation dazu finden Sie auf der Philips-Seite: www.meethue.com.

Die HTML-Seite mit dem JavaScript

Wie man sieht, wird AJAX deutlich einfacher durch die fetch-Methode. Das Script hat sogar mehr Funktionen, aber es ist übersichtlicher und klarer.

Ein Nachteil dieser Version: sie läuft nicht mit dem Internet-Explorer. Wer immer noch einen IE benutzt muss die alte Seite nehmen.

Da sich weder die Hue-Bridge noch die Grundlagen von AJAX geändert haben, ist die Beschreibung des Codes auf der verlinkten Seite immer noch gültig. Nur die XMLHttpRequest-Aufrufe wurden durch fetch ersetzt, und ein Polling für den aktuellen Status hinzugefügt.

<!DOCTYPE html>
<html lang="de">
 <head>
  <meta charset="utf-8">
  <title>AJAX mit der fetch-API</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
   input[type="button"] { -webkit-appearance: none; display: inline-block; padding: 1em; vertical-align: top; }
   input[type="range"]  { padding: 0.5em; width: 32em; display: inline-block }
  </style>
  <script>
   var url = "http://192.168.1.121/api/XsbA-ZrmWbp42eeXu5j8otqJlPnIIX1Mxbh6rwn8/lights" ;

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

   // Requests the current state of all the lamps
   function getState()
   {
      fetch( url, { mode : "cors", headers: { "Content-type": "application/json; charset=utf-8" } } )
         .then( response => {
            if( !response.ok )
               throw new Error( "fetch failed" ) ;

             return response.json() ;
      } ).then( processState )
      .catch( displayError ) ;
    }

   // Displays the given text in the paragraph
   function displayError( text )
   {
      document.querySelector( "p" ).innerHTML = "Error: " + 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 ;
         document.querySelector( "#H" + lamp.name ).valueAsNumber         = lamp.hue ;
      }
   }

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

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

         if( (lamp.reachable !== state.reachable) || (lamp.on !== state.on) || (lamp.hue !== state.hue) )
         {
               lamp.reachable = state.reachable ;
               lamp.on        = state.on ;
               lamp.hue       = state.hue ;
               update         = true ;
         }
      }

      if( update )
         updateView() ;
   }

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

      setLampState( id, { on: !lamp.on } ) ;
   }

   // Sets the hue of a lamp
   function changeColor( id )
   {
      var value = document.querySelector("#H"+id).valueAsNumber ;

      setLampState( id, { hue: value } ) ;
   }

   // Sets the state of a lamp
   function setLampState( id, obj )
   {
      fetch( url + "/" + id + "/state", { body: JSON.stringify(obj), method: "PUT", mode : "cors", headers: { "Content-type": "application/json; charset=utf-8" } } )
         .then( response => {
            if( !response.ok )
               throw new Error( "fetch failed" ) ;
         } )
         .catch( displayError ) ;
   }

   getState() ;

   setInterval( getState, 500 ) ;
  </script>
 </head>
 <body onload="getState()">
  <h1>Hue-Lampen steuern mit der fetch-API</h1>
  <datalist id="ticks">
   <option value="10000"></option>
   <option value="20000"></option>
   <option value="30000"></option>
   <option value="40000"></option>
   <option value="50000"></option>
   <option value="60000"></option>
  </datalist>
  <div><input type="button" value="Lampe 1" id="L1" onclick="toggle(1)"> <input type="range" id="H1" min="0" max="65000" list="ticks" onchange="changeColor(1)"></div>
  <div><input type="button" value="Lampe 2" id="L2" onclick="toggle(2)"> <input type="range" id="H2" min="0" max="65000" list="ticks" onchange="changeColor(2)"></div>
  <div><input type="button" value="Lampe 3" id="L3" onclick="toggle(3)"> <input type="range" id="H3" min="0" max="65000" list="ticks" onchange="changeColor(3)"></div>
  <p></p>
 </body>
</html>

Das Sourcefile

Sie können huefetch.html hier herunterladen.