Forked from thomaspockrandt/philips-hue-control.html
Last active
May 16, 2019 02:02
-
-
Save psybertech/165b0e83f2c97fb5af0a0862679be2d7 to your computer and use it in GitHub Desktop.
Simple Philips Hue Control (jQuery)
This file contains 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
<!-- | |
THIS IS AN UPDATE TO THE ORIGINAL GIST TO ADD GROUPS SUPPORT & CSS STYLING | |
IT NEEDS SOME WORK & ISNT PRETTY BUT IT WORKS | |
CHANGING GROUPS COLOR/BRIGHTNESS IS SLOW TO UPDATE EACH LIGHT SO THERE IS A WORKAROUND FOR NOW | |
--- I DONT LIKE IT BUT I RARELY USE OVERALL GROUP CHANGES SO IT IS WHAT IT IS | |
--> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=.7"> | |
<title>myHue Lights</title> | |
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script> | |
<script type="text/javascript"> | |
$(function() { | |
var apiBaseUrl = null; | |
var username = "newdeveloper"; | |
// GOOGLE how to get the access token/username the first time.. requires CURL or other post/get method data to teh hub & physical access to click the hub button | |
$.getJSON("https://www.meethue.com/api/nupnp", function(data) { | |
//console.log(data); | |
var internalIpAddress = data[0].internalipaddress | |
apiBaseUrl = "http://" + internalIpAddress + "/api/" + username; | |
//console.log("api url w/ username: " + apiBaseUrl); | |
var params = new window.URLSearchParams(window.location.search); | |
// DEFAULTS TO GROUPS ---> USE A URL PARAMTER TO DISABLE GROUPS: http://localhost/hue_lights.htm?use_groups=no [no|n|NO|N|0] | |
if (params.get('use_groups') == "no" || params.get('use_groups') == "n" || params.get('use_groups') == "NO" || params.get('use_groups') == "N" || params.get('use_groups') == "0") { | |
console.log("URL PARAM: 'hue_lights.htm?use_groups=" + params.get('use_groups') + "' IS SET CORRECTLY --- GROUPS ARE DISABLED!"); | |
getLights(); | |
} else { | |
console.log("URL PARAM: `hue_lights.htm?use_groups` IS NOT SET TO DISABLE GROUPS --- USING GROUPS!"); | |
getGroups(); | |
} | |
}); | |
var getGroups = function() { | |
$.getJSON(apiBaseUrl, function(data) { | |
var groups = data["groups"]; | |
$.each(groups, function(index, group) { | |
if (index == 9999999) { | |
// SKIP GROUPS YOU DO NOT WANT TO SEE MANUALLY IF DESIRED - 9999999 is just a placeholder for a real group - un-rem console logs to find index # | |
} else { | |
var thisGroupName = group["name"]; | |
// CHECK FOR LIGHTS IN GROUP (SOMETIMES A GROUP IS SETUP BUT NO LIGHTS ARE IN IT SO DO NOT SHOW THAT GROUP!) | |
if (data["groups"][index].lights[0]) { | |
if (index == 1) { | |
// DO NOT ADD BORDER OVER TOP OF FIRST GROUP - YOU CAN CHANGE THIS TO ANOTHER IF YOU SKIP THE FIRST GROUP | |
$("#lights").append("<div class='groupName' style='margin-top:5px;border-top: 1px solid;'>" + group["name"] + "</div>"); | |
} else { | |
$("#lights").append("<div class='groupName' style='border-top: 1px solid;'>" + group["name"] + "</div>"); | |
} | |
var template = $("#group-template").clone(); | |
template.removeAttr("id"); | |
template.css("display", "block"); | |
template.data("id", "g" + index); | |
template.find(".name").text("ALL LIGHTS IN " + group["name"]); | |
if (group["action"]["on"] == true) { | |
// IF NOT SHOW THE SLIDERS AT 0 - LESS CONFUSION - CAN IMPROVE THIS BY CHANGING A VISUAL CUE FOR EACH LIGHT BUT I LIKE THIS AS IS | |
template.find(".brightnessSlider").val(group["action"]["bri"] / 8); | |
//console.log("bri check: " + group["action"]["bri"] / 8); | |
} else { | |
template.find(".brightnessSlider").val(0); | |
} | |
if (group["action"]["colormode"] == "ct") { | |
// IF WE ARE A COLOR TEMP ONLY BULB.... | |
template.find(".hueSlider").attr({ | |
"min": 153, | |
"max": 454 | |
}); | |
template.find(".hueSlider").addClass("gctLight"); | |
template.find(".brightnessSlider").addClass("gBright"); | |
template.find(".hueSlider").val(group["action"]["ct"]); | |
} else if (group["action"]["hue"]) { | |
// MAYBE WE ARE A FULL COLOR BULB... IF THERE ARE OTHER TYPES, I DONT KNOW IF THIS WILL WORK/FAIL.... | |
template.find(".hueSlider").attr({ | |
"max": 65535 | |
}); | |
template.find(".hueSlider").addClass("gfcLight"); | |
template.find(".brightnessSlider").addClass("gBright"); | |
template.find(".hueSlider").val(group["action"]["hue"]); | |
} else { | |
// IF WE ARE A DIMABLE BULB ONLY.... | |
template.find(".hueSlider").addClass("gdoLight"); | |
template.find(".brightnessSlider").addClass("gBright"); | |
template.find(".brightnessSlider").css("width", "474px"); | |
template.find(".hueSlider").prop('disabled', true); | |
} | |
$("#lights").append(template); | |
} else { | |
console.log("NO LIGHTS IN GROUP: " + index + " - NOT SHOWING THE GROUP NAMED: " + group["name"]); | |
} | |
//console.log(index + ": " + JSON.stringify(group)); | |
var gLights = data["groups"][index].lights; | |
$.each(gLights, function(index, gLight) { | |
var light = gLight; | |
var template = $("#light-template").clone(); | |
template.removeAttr("id"); | |
template.css("display", "block"); | |
template.data("id", gLight); | |
template.find(".name").text(data["lights"][gLight]["name"]); | |
if (data["lights"][gLight]["state"]["on"] == true) { | |
// IF NOT SHOW THE SLIDERS AT 0 - LESS CONFUSION - CAN IMPROVE THIS BY CHANGING A VISUAL CUE FOR EACH LIGHT BUT I LIKE THIS AS IS | |
template.find(".brightnessSlider").val(data["lights"][gLight]["state"]["bri"]); | |
} else { | |
template.find(".brightnessSlider").val(0); | |
} | |
if (data["lights"][gLight]["state"]["colormode"] == "ct") { | |
// IF WE ARE A COLOR TEMP ONLY BULB.... | |
template.find(".hueSlider").attr({ | |
"min": 153, | |
"max": 454 | |
}); | |
template.find(".hueSlider").addClass("ctLight"); | |
template.find(".brightnessSlider").addClass("lBright"); | |
template.find(".hueSlider").val(data["lights"][gLight]["state"]["ct"]); | |
} else if (data["lights"][gLight]["type"] == "Dimmable light") { | |
// IF WE ARE A DIMABLE BULB ONLY.... | |
template.find(".hueSlider").addClass("doLight"); | |
template.find(".brightnessSlider").addClass("lBright"); | |
template.find(".brightnessSlider").css("width", "474px"); | |
template.find(".hueSlider").prop('disabled', true); | |
} else { | |
// MAYBE WE ARE A FULL COLOR BULB... IF THERE ARE OTHER TYPES, I DONT KNOW IF THIS WILL WORK/FAIL.... | |
template.find(".hueSlider").attr({ | |
"max": 65535 | |
}); | |
template.find(".hueSlider").addClass("fcLight"); | |
template.find(".brightnessSlider").addClass("lBright"); | |
template.find(".hueSlider").val(data["lights"][gLight]["state"]["hue"]); | |
} | |
$("#lights").append(template); | |
//console.log(gLight + ": " + JSON.stringify(data["lights"][gLight])); | |
}); | |
} | |
}); | |
}); | |
}; | |
var getLights = function() { | |
$.getJSON(apiBaseUrl, function(data) { | |
var lights = data["lights"]; | |
$.each(lights, function(index, light) { | |
var gLight = index; | |
var template = $("#light-template").clone(); | |
template.removeAttr("id"); | |
template.css("display", "block"); | |
template.data("id", gLight); | |
template.find(".name").text(data["lights"][gLight]["name"]); | |
if (data["lights"][gLight]["state"]["on"] == true) { | |
// IF NOT SHOW THE SLIDERS AT 0 - LESS CONFUSION - CAN IMPROVE THIS BY CHANGING A VISUAL CUE FOR EACH LIGHT BUT I LIKE THIS AS IS | |
template.find(".brightnessSlider").val(data["lights"][gLight]["state"]["bri"]); | |
} else { | |
template.find(".brightnessSlider").val(0); | |
} | |
if (data["lights"][gLight]["state"]["colormode"] == "ct") { | |
// IF WE ARE A COLOR TEMP ONLY BULB.... | |
template.find(".hueSlider").attr({ | |
"min": 153, | |
"max": 454 | |
}); | |
template.find(".hueSlider").addClass("ctLight"); | |
template.find(".hueSlider").val(data["lights"][gLight]["state"]["ct"]); | |
} else if (data["lights"][gLight]["type"] == "Dimmable light") { | |
// IF WE ARE A DIMABLE BULB ONLY.... | |
template.find(".hueSlider").attr({ | |
"min": 153, | |
"max": 454 | |
}); | |
template.find(".hueSlider").val(0); | |
template.find(".hueSlider").addClass("doLight"); | |
template.find(".brightnessSlider").css("width", "474px"); | |
template.find(".hueSlider").prop('disabled', true); | |
} else { | |
// MAYBE WE ARE A FULL COLOR BULB... IF THERE ARE OTHER TYPES, I DONT KNOW HOW THIS WILL WORK/FAIL.... | |
template.find(".hueSlider").attr({ | |
"max": 65535 | |
}); | |
template.find(".hueSlider").addClass("fcLight"); | |
template.find(".hueSlider").val(data["lights"][gLight]["state"]["hue"]); | |
} | |
$("#lights").append(template); | |
//console.log(gLight + ": " + JSON.stringify(data["lights"][gLight])); | |
}); | |
}); | |
}; | |
var setLightState = function(lightId, lightState) { | |
var apiUrl = apiBaseUrl + "/lights/" + lightId + "/state"; | |
$.ajax({ | |
url: apiUrl, | |
type: "PUT", | |
data: JSON.stringify(lightState) | |
}); | |
console.log(apiBaseUrl + "/lights/" + lightId + "/state --- " + JSON.stringify(lightState)); | |
}; | |
var setGroupState = function(lightId, lightState) { | |
lightId = lightId.replace('g', ''); | |
var apiUrl = apiBaseUrl + "/groups/" + lightId + "/action"; | |
$.ajax({ | |
url: apiUrl, | |
type: "PUT", | |
data: JSON.stringify(lightState) | |
}); | |
console.log(apiBaseUrl + "/groups/" + lightId + "/action --- " + JSON.stringify(lightState)); | |
}; | |
$(document).on("input", ".ctLight", function(e) { | |
var hue2 = $(this).val(); // STUPID QUASI HACK TO HELP GUI BACKGROUND COLOR TEMP BULBS ONLY! | |
var sat = "100%"; | |
var light = "50%"; | |
var lightState = { | |
"ct": parseInt($(this).val()) | |
}; | |
try { | |
setLightState($(this).parent().data("id"), lightState); | |
// CRAPPY QUASI HACK PART 2 FOR CT (COLOR TEMP) BASED LIGHTS BACKGROUND COLOR TO GET THE WARM/COOL GIST ONLY.... | |
if (hue2 > 400) { | |
hue2 = 0; | |
} else if (hue2 > 350) { | |
hue2 = 50; | |
} else if (hue2 > 300) { | |
hue2 = 100; | |
} else if (hue2 > 250) { | |
hue2 = 150; | |
} else if (hue2 > 200) { | |
hue2 = 170; | |
} else if (hue2 > 175) { | |
hue2 = 195; | |
} else if (hue2 > 152) { | |
hue2 = 225; | |
} else { | |
hue2 = $(this).val(); | |
} | |
//console.log("GOOD!" + $(this).val()+ " --- " + hue2); | |
// THIS IS FOR COLOR TEMP ONLY BULBS | |
$("body").css("background-color", "rgb(" + [164, 164, hue2].join(',') + ")"); | |
//console.log("CT VALUE HACK | RECD: " + $(this).val() + " HACKED: " + hue2); | |
} catch { | |
//console.log("REALLY BAD! --- " + hue); | |
} | |
}); | |
$(document).on("input", ".gctLight", function(e) { | |
var hue2 = $(this).val(); // STUPID QUASI HACK TO HELP GUI BACKGROUND COLOR TEMP BULBS ONLY! | |
var sat = "100%"; | |
var light = "50%"; | |
var lightState = { | |
"ct": parseInt($(this).val()) | |
}; | |
try { | |
setGroupState($(this).parent().data("id"), lightState); | |
// CRAPPY QUASI HACK PART 2 FOR CT (COLOR TEMP) BASED LIGHTS BACKGROUND COLOR TO GET THE WARM/COOL GIST ONLY.... | |
if (hue2 > 400) { | |
hue2 = 0; | |
} else if (hue2 > 350) { | |
hue2 = 50; | |
} else if (hue2 > 300) { | |
hue2 = 100; | |
} else if (hue2 > 250) { | |
hue2 = 150; | |
} else if (hue2 > 200) { | |
hue2 = 170; | |
} else if (hue2 > 175) { | |
hue2 = 195; | |
} else if (hue2 > 152) { | |
hue2 = 225; | |
} else { | |
hue2 = $(this).val(); | |
} | |
//console.log("GOOD!" + $(this).val()+ " --- " + hue2); | |
// THIS IS FOR COLOR TEMP ONLY BULBS | |
$("body").css("background-color", "rgb(" + [164, 164, hue2].join(',') + ")"); | |
//console.log("CT VALUE HACK | RECD: " + $(this).val() + " HACKED: " + hue2); | |
} catch { | |
//console.log("REALLY BAD! --- " + hue); | |
} | |
}); | |
$(document).on("input", ".fcLight", function(e) { | |
var hue = $(this).val() / 182; | |
var sat = "100%"; | |
var light = "50%"; | |
var lightState = { | |
"hue": parseInt($(this).val()), | |
"sat": 254 | |
}; | |
try { | |
setLightState($(this).parent().data("id"), lightState); | |
$("body").css("background-color", "hsl(" + [hue, sat, light].join(',') + ")"); | |
//console.log("FULL COLOR DEFAULT: " + $(this).val()); | |
} catch { | |
//console.log("REALLY BAD! --- " + hue); | |
} | |
}); | |
$(document).on("input", ".gfcLight", function(e) { | |
var hue = $(this).val() / 182; | |
var sat = "100%"; | |
var light = "50%"; | |
var lightState = { | |
"hue": parseInt($(this).val()), | |
"sat": 254 | |
}; | |
try { | |
setGroupState($(this).parent().data("id"), lightState); | |
$("body").css("background-color", "hsl(" + [hue, sat, light].join(',') + ")"); | |
//console.log("FULL COLOR DEFAULT: " + $(this).val()); | |
} catch { | |
//console.log("REALLY BAD! --- " + hue); | |
} | |
}); | |
// RESET THE BACKGROUND COLOR AFTER YOU CHANGE THE HUE COLOR... THIS IS ALSO USED IN OTHER PLACES SO FIND/REPLACE IF YOU WANT DIFFERENT BG COLOR... | |
$('body').click(function() { | |
$("body").css("background-color", "rgb(60,60,63)"); | |
}); | |
$(document).on("input", ".lBright", function(e) { | |
var lightState = { | |
"on": true, | |
"bri": parseInt($(this).val()) | |
}; | |
if ($(this).val() <= 5) { | |
// I USE 5 INSTEAD OF 0 HERE SO IF THE SLIDER IS CLOSE ENOUGH TO OFF THE LIGHTS ARE OFF | |
lightState["on"] = false; | |
} else { | |
lightState["on"] = true; | |
} | |
setLightState($(this).parent().data("id"), lightState); | |
}); | |
$(document).on("input", ".gBright", function(e) { | |
var theBrightness = parseInt($(this).val() * 8); | |
if (theBrightness > 253) { | |
theBrightness = 254; | |
} | |
var lightState = { | |
"on": true, | |
"bri": theBrightness | |
}; | |
if ($(this).val() <= 5) { | |
// I USE 5 INSTEAD OF 0 HERE SO IF THE SLIDER IS CLOSE ENOUGH TO OFF THE LIGHTS ARE OFF | |
lightState["on"] = false; | |
} else { | |
lightState["on"] = true; | |
} | |
setGroupState($(this).parent().data("id"), lightState); | |
}); | |
}); | |
</script> | |
<style type="text/css"> | |
/* THERE ARE NO IE OR FIREFOX OR OTHER BROWSER CSS HERE - CHROME ONLY!!! THIS CAN AFFECT THE SLIDER LOOK & FEEL */ | |
.light { | |
width: 480px; | |
margin: auto; | |
} | |
.light input { | |
width: 233px; | |
} | |
.ctLight { | |
border-top-color: #d8d891 !important; | |
border-left-color: #d8d891 !important; | |
border-right-color: #7070be !important; | |
border-bottom-color: #7070be !important; | |
} | |
.fcLight { | |
border-top-color: #ee8787 !important; | |
border-left-color: #81fa81 !important; | |
border-right-color: cyan !important; | |
border-bottom-color: #df2edf !important; | |
} | |
.doLight { | |
border-color: rgb(60, 60, 63) !important; | |
background: rgb(60, 60, 63) !important; | |
visibility: hidden; | |
display: none; | |
} | |
.gctLight { | |
border-top-color: #d8d891 !important; | |
border-left-color: #d8d891 !important; | |
border-right-color: #7070be !important; | |
border-bottom-color: #7070be !important; | |
} | |
.gfcLight { | |
border-top-color: #ee8787 !important; | |
border-left-color: #81fa81 !important; | |
border-right-color: cyan !important; | |
border-bottom-color: #df2edf !important; | |
} | |
.gdoLight { | |
border-color: rgb(60, 60, 63) !important; | |
background: rgb(60, 60, 63) !important; | |
visibility: hidden; | |
display: none; | |
} | |
.name { | |
display: inline-block; | |
margin-top: 8px; | |
text-transform: uppercase; | |
font-size: .9em; | |
} | |
.gName { | |
text-align: right; | |
display: inline-block; | |
width: 98%; | |
font-size: .66em; | |
} | |
.groupName { | |
padding: 8px; | |
width: 472px; | |
padding-bottom: 5px; | |
margin: auto; | |
margin-top: 25px; | |
text-align: right; | |
text-transform: uppercase; | |
font-size: 1.1em; | |
color: antiquewhite; | |
} | |
input[type=range] { | |
-webkit-appearance: none; /* hides the slider for custom sliders */ | |
background: rgb(20, 20, 23); | |
margin-top: 10px; | |
border: 1px solid antiquewhite; | |
box-sizing: border-box; | |
border-radius: 5px; | |
padding: 1px; | |
} | |
input.brightnessSlider.gBright, input.hueSlider.gHue.gctLight, input.hueSlider.gHue.gfcLight { | |
background: #000008; | |
border-color: #ffffb3; | |
} | |
input[type=range]::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
} | |
input[type=range]:focus { | |
outline: none; /* removes the blue border */ | |
} | |
input[type=range]::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
border: 1px solid white; | |
height: 36px; | |
width: 24px; | |
border-radius: 3px; | |
background: rgb(140, 140, 143); | |
cursor: pointer; | |
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; | |
} | |
.mainLights { | |
border: 1px solid; | |
width: 500px; | |
margin: auto; | |
margin-top: 25px; | |
margin-bottom: 25px; | |
border-radius: 7px; | |
padding-bottom: 25px; | |
background-color: rgba(35, 35, 38, 1); | |
border-color: lightsteelblue; | |
border-width: 2px; | |
} | |
body,html { | |
background: rgb(60, 60, 63); | |
color: white; | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
font-weight: 400; | |
} | |
.group { | |
/* | |
border: 1px solid #fff9da; | |
background: #000018; | |
*/ | |
border-radius: 5px; | |
line-height: 8pt; | |
padding-bottom: 6px; | |
padding-left: 1px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="lights" class="mainLights"> | |
<div id="group-template" class="group light" data-id="2" style="display: none;"> | |
<span class="gName name">Light</span> | |
<br /> | |
<input class="hueSlider gHue" type="range" value="0" min="0" max="65535" /> | |
<input class="brightnessSlider gBright" type="range" value="0" min="0" max="32" /> | |
</div> | |
<div id="light-template" class="light" data-id="1" style="display: none;"> | |
<span class="name">Light</span> | |
<br /> | |
<input class="hueSlider" type="range" value="0" min="0" max="65535" /> | |
<input class="brightnessSlider" type="range" value="0" min="0" max="254" /> | |
</div> | |
<span id="lastRelaoded" style='float: right;padding: 2px;font-size:.7em;'>TIME</span> | |
<span id="reloadNow">RELOAD</span> | |
</div> | |
<script> | |
var dt = new Date(); | |
var hours = dt.getHours(); | |
if (hours < 10) { | |
hours = "0" + hours; | |
} | |
var mins = dt.getMinutes(); | |
if (mins < 10) { | |
mins = "0" + mins; | |
} | |
var secs = dt.getSeconds(); | |
if (secs < 10) { | |
secs = "0" + secs; | |
} | |
var time = hours + ":" + mins + ":" + secs; | |
$("#lastRelaoded").html("last updated: " + time); | |
$("#reloadNow").click(function() { | |
location.reload(); | |
}); | |
setTimeout(function() { | |
window.location.reload(1); | |
}, 900000); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment