Forked from PhilipsHueLabs/philips.huelabs.connector.js
          
        
    
          Created
          October 5, 2015 17:25 
        
      - 
      
- 
        Save dapithor/98dc0ad4c9be4d2ac54c to your computer and use it in GitHub Desktop. 
    Philips HueLabs connection Javascript
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | /*** Example connection ***/ | |
| Philips.connect({ | |
| bridge_username: "philips-huelabs", | |
| bridge_ipaddress: "192.168.0.1", | |
| success: function(res){ | |
| console.log(res); | |
| }, | |
| fail: function(res){ | |
| // | |
| }, | |
| attempt: function(attempt){ | |
| // | |
| } | |
| }); | |
| /****** END ***************/ | |
| /** | |
| * Philips hue Javascript SDK (Native JS OOP) | |
| * @author Victor Angelier <[email protected]> | |
| * @returns {Philips} | |
| * @todo Extend with other part of existing library | |
| */ | |
| var PhilipsConnector = function(){ | |
| this.options = { | |
| connected:false, | |
| max_retries:10, | |
| connect_retries:0, | |
| bridge_username:null, | |
| bridge_ipaddress:null, | |
| request_protocol:"http", | |
| connectIntervalId: null | |
| }; | |
| this.bridge = null; | |
| }; | |
| /** | |
| * Create a random string (for bridge usernames etc) | |
| * @returns {String} | |
| */ | |
| PhilipsConnector.prototype.randString = function(){ | |
| length = 10; | |
| var chars = "abcdefghijklmnopqrstuvwABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; | |
| var result = ''; | |
| for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))]; | |
| return "huelabs-" + result; | |
| }; | |
| /** | |
| * Returns the currect bridge | |
| * @returns {PhilipsConnector.bridge} | |
| */ | |
| PhilipsConnector.prototype.getBridge = function(){ | |
| return this.bridge; | |
| }; | |
| /** | |
| * Returns the currect bridge username | |
| * @returns {string} | |
| */ | |
| PhilipsConnector.prototype.getBridgeUsername = function(){ | |
| return this.options.bridge_username; | |
| }; | |
| /** | |
| * Returns the currect bridge ipaddress | |
| * @returns {string} | |
| */ | |
| PhilipsConnector.prototype.getBridgeIP = function(){ | |
| return this.options.bridge_ipaddress; | |
| }; | |
| /** | |
| * Setup a connection to the Philips Hue bridge | |
| * @param {object} options { | |
| * success: function, | |
| * fail: function, | |
| * attempt function | |
| * } | |
| * @returns {Boolean} | |
| */ | |
| PhilipsConnector.prototype.connect = function(options){ | |
| $.extend(this.options, options); | |
| var self = this; | |
| //If both username and bridge IP are empty (Probably returning visitor or new user) | |
| if(options.bridge_ipaddress === null && options.bridge_username === null){ | |
| var ls = window.localStorage.getItem('knownBridges'); | |
| if(ls !== null){ | |
| bridge = JSON.parse(ls); | |
| if(bridge !== null){ | |
| options.bridge_ipaddress = bridge.bridge_ipaddress; | |
| options.bridge_username = bridge.username; | |
| $.extend(this.options, options); //Update global configation also | |
| } | |
| } | |
| } | |
| //If username is empty and bridge ip address is known (probably new user) | |
| if(options.bridge_username === null && options.bridge_ipaddress !== null){ | |
| options.bridge_username = this.randString(); | |
| $.extend(this.options, options); //Update global configation also | |
| } | |
| //Check and connect to the bridge | |
| if(options.bridge_ipaddress !== null && options.bridge_username !== null){ | |
| //Validate if current does not exists/authorized | |
| $.getJSON(this.options.request_protocol + "://" + options.bridge_ipaddress + "/api/" + options.bridge_username, | |
| function(res){ | |
| //Check if user is already authorized | |
| if(typeof(res.length) === "undefined" || typeof(res[0].error) !== "object"){ | |
| //Clear interval | |
| clearInterval(self.options.connectIntervalId); | |
| //We are connected | |
| options.connected = true; | |
| //Set bridge config | |
| self.bridge = res; | |
| PhilipsConnector.bridge = self.bridge; | |
| //Store info in localstorage | |
| var ls = { | |
| username: options.bridge_username, | |
| bridge_ipaddress: options.bridge_ipaddress | |
| }; | |
| window.localStorage.setItem('knownBridges', JSON.stringify(ls)); | |
| if(typeof(options.success) == "function"){ | |
| options.success(res); | |
| } | |
| }else{ | |
| if(typeof(res[0].error) === "object" && res[0].error.description.indexOf('unauthorized') >= 0){ | |
| //We are not authorized. Let get authorized | |
| self.options.connectIntervalId = setInterval(self._connectAttempt, 3000, self.options); | |
| }else{ | |
| if(typeof(options.fail) == "function"){ | |
| options.fail(res); | |
| } | |
| } | |
| } | |
| }, | |
| function(res){ | |
| clearInterval(self.options.connectIntervalId); | |
| if(typeof(options.fail) === "function"){ | |
| options.fail("Existing user validation request failed."); | |
| } | |
| } | |
| ); | |
| }else{ | |
| if(typeof(options.fail) === "function"){ | |
| options.fail("Bridge username or IP address not found."); | |
| return false; | |
| } | |
| } | |
| }; | |
| /** | |
| * Connect attemp | |
| * @param {object} options | |
| * @returns {Boolean} | |
| */ | |
| PhilipsConnector.prototype._connectAttempt = function(options){ | |
| $.extend(this.options, options); | |
| var self = this; | |
| //Check max retries | |
| if(options.connect_retries === options.max_retries){ | |
| clearInterval(options.connectIntervalId); | |
| if(typeof(options.fail) === "function"){ | |
| options.fail("Maximum retries"); | |
| } | |
| return false; | |
| } | |
| //Attempt to connect | |
| $.ajax({ | |
| method:"POST", | |
| url: options.request_protocol + "://" + options.bridge_ipaddress + "/api", | |
| contentType:"text/plain; charset=UTF-8", | |
| data: JSON.stringify({ | |
| devicetype: "huelabs-user", | |
| username: options.bridge_username | |
| }), | |
| dataType:"json", | |
| processData: false, | |
| crossDomain: true | |
| }) | |
| .done(function(res){ | |
| //Response validation | |
| if(typeof(res[0].error) === "object"){ | |
| }else if(typeof(res[0].success) === "object" && typeof(res[0].success.username) !== "undefined"){ | |
| clearInterval(options.connectIntervalId); | |
| //Set connected | |
| options.connected = true; | |
| //Store in localstorage | |
| var ls = { | |
| username: options.bridge_username, | |
| bridge_ipaddress: options.bridge_ipaddress | |
| }; | |
| window.localStorage.setItem('knownBridges', JSON.stringify(ls)); | |
| //Validate if current does not exists/authorized | |
| $.getJSON(options.request_protocol + "://" + options.bridge_ipaddress + "/api/" + options.bridge_username, | |
| //Success | |
| function(res){ | |
| //Set bridge config | |
| self.bridge = res; | |
| PhilipsConnector.bridge = self.bridge; | |
| if(typeof(options.success) == "function"){ | |
| res.username = options.bridge_username; | |
| options.success(res); | |
| } | |
| }, | |
| //Fail | |
| function(res){ | |
| if(typeof(options.fail) === "function"){ | |
| options.fail(JSON.stringify(res)); | |
| } | |
| } | |
| ); | |
| } | |
| }) | |
| .fail(function(res){ | |
| clearInterval(self.options.connectIntervalId); | |
| if(typeof(options.fail) === "function"){ | |
| options.fail(JSON.stringify(res)); | |
| } | |
| }) | |
| .always(function(res){ | |
| if(typeof(options.attempt) === "function"){ | |
| options.attempt(options.connect_retries); | |
| } | |
| }); | |
| //Next attempt | |
| options.connect_retries++; | |
| }; | |
| /** | |
| * Scan network for bridges | |
| * @param {type} clientLocalIP | |
| * @param {type} asyncCompletedCallback | |
| * @param {type} onNextIpCallback | |
| * @param {type} onFindBridgeCallback | |
| * @returns {undefined} | |
| */ | |
| PhilipsConnector.prototype.scanBridges = function(clientLocalIP, asyncCompletedCallback, onNextIpCallback, onFindBridgeCallback){ | |
| var self = this; | |
| if(clientLocalIP !== "unknown"){ | |
| //Here we store bridges | |
| var bridges = []; | |
| stopBridgeScanner = false; | |
| clearTimeout(); | |
| var scan = (function(host){ | |
| //Break scanning | |
| if(typeof stopBridgeScanner !== undefined && stopBridgeScanner === true){ | |
| clearTimeout(); | |
| network = null; | |
| host = false; | |
| return false; | |
| } | |
| //Host check | |
| if(network !== null && host !== false && (host >= 0 && host < 254)){ | |
| //Next IP event | |
| onNextIpCallback(network + "." + host); | |
| try | |
| { | |
| var s = document.getElementById('ipscan'); | |
| if(!s || s === null || typeof(s) === "undefined"){ | |
| s = document.createElement('iframe'); | |
| s.setAttribute('id', 'ipscan'); | |
| s.style['display'] = 'none'; | |
| s.style['height'] = '1px'; | |
| s.style['width'] = '1px'; | |
| document.body.appendChild(s); | |
| } | |
| s.onerror = function(){}; | |
| s.onload = function(){ | |
| onFindBridgeCallback(network + "." + (host-1) || 1); | |
| bridges.push(network + "." + (host-1) || 1); | |
| }; | |
| s.src = self.options.request_protocol + "://" + network + "." + host + "/api/ipscanner/config"; | |
| }catch(err){ | |
| } | |
| //Goto next | |
| host+=1; | |
| setTimeout(scan, 200, host); | |
| }else{ | |
| clearTimeout(); | |
| //Send complete event | |
| asyncCompletedCallback(bridges); | |
| network = null; | |
| host = false; | |
| return false; | |
| } | |
| }); | |
| var parts = clientLocalIP.toString().split("."); | |
| var network = null; | |
| var host = 1; | |
| if(parts.length > 3){ | |
| parts.splice(3,1); //Delete last part of the IP address | |
| network = parts.join("."); | |
| if(network !== null){ | |
| setTimeout(scan, 100, host); | |
| } | |
| }else{ | |
| asyncCompletedCallback(false); | |
| } | |
| } | |
| return; | |
| }; | |
| window.PhilipsConnector = new PhilipsConnector(); | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment