Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save psybertech/165b0e83f2c97fb5af0a0862679be2d7 to your computer and use it in GitHub Desktop.
Save psybertech/165b0e83f2c97fb5af0a0862679be2d7 to your computer and use it in GitHub Desktop.
Simple Philips Hue Control (jQuery)
<!--
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