Last active
October 2, 2015 19:03
-
-
Save tgck/11185861 to your computer and use it in GitHub Desktop.
HueRequestBuilder.js - a Bridge Script for Max/MSP and Philips Hue
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
// HueRequestBuilder.js | |
// a Bridge Script for Max/MSP and Philips Hue | |
// depends on cURL command. | |
// | |
// version: 2.2.0 | |
// date: 2014.5.18 | |
// author: tgck (_@taikutz.org) | |
// | |
// based on: LEKIRST's patch ... http://bit.ly/1pgasm8 | |
// Hue API ... http://developers.meethue.com/ | |
// | |
// issues unix command like these: | |
// curl http://192.168.0.2/api/newdeveloper/lights/1 | |
// curl -X PUT -d '{"on":true}' http://192.168.0.2/api/newdeveloper/lights/3/state | |
// | |
// TODO : ollOn, ollOf, turnOn $1, turnOff $1 | |
// : "search Lamps" | |
inlets = 1; | |
outlets = 1; | |
// consts for API | |
// used as a url template. | |
var url = { | |
"getState" : "http://IP/api/USERNAME/lights/INDEX", | |
"changeState" : "http://IP/api/USERNAME/lights/INDEX/state", | |
"api" : "http://IP/api", | |
"broker" : "http://www.meethue.com/api/nupnp" | |
} | |
// cURL | |
var unixCmd = { | |
"get" : "curl ", | |
"put" : "curl -X PUT -d ", | |
"post": "curl -X POST -d " | |
} | |
// network | |
var bridge = { | |
"ip" : "192.168.0.2", | |
"user" : "newdeveloper" | |
} | |
// user's bulbs | |
var NBULB = 4; // max bulb | |
var bulbs = []; | |
// current controller for attribute-like usage. | |
var currTarget; // as bulb index (0 -> (NBULB -1)) | |
var bPost = 1; // debug Flag | |
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
// | |
// = F U N C T I O N S U S E D I N T E R N A L = | |
// | |
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
function loadbang() { | |
po ("[INFO]INIT:" + jsarguments[0] + "\n"); | |
currTarget = 0; | |
setupBulbs(NBULB); | |
} | |
// | |
// prepare Bulb objects and bind urls to them. | |
// bulb オブジェクトの準備 | |
// | |
function setupBulbs(n) { | |
for (i = 1; i <= n; i++ ) { | |
var bulb = { "index" : i }; | |
bulbs.push(bulb); | |
} | |
for (i = 0; i < n; i++) { | |
bindUrl(bulbs[i]); | |
} | |
} | |
// | |
// add Url property to the object. | |
// | |
function bindUrl(me) { | |
me.urlGetState = url.getState.replace("IP", bridge.ip) | |
.replace("USERNAME", bridge.user) | |
.replace("INDEX", me.index); | |
me.urlChangeState = url.changeState.replace("IP", bridge.ip) | |
.replace("USERNAME", bridge.user) | |
.replace("INDEX", me.index); | |
} | |
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
// F U N C T I O N S | |
// - - - - - - - - - | |
// F O R _ U S E R S | |
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
// | |
// general message handler | |
// | |
function anything() { | |
var argarr = arrayfromargs(messagename, arguments); // cf. Max JavaScript Refference | |
// po ("[DEBUG]list length[XX]\n".replace("XX", argarr.length) ); | |
// loop starts here. | |
var ourList = argarr; | |
var targetState = {}; // diffObj | |
while (ourList.length > 0) { | |
// check the head element. | |
var head = ourList.shift(); | |
var type = typeof(head); | |
if ( typeof(head) != "number" && typeof(head) != "string" ) { | |
po ("[ERROR]can't process. [XX] is neither Number or String.\n".replace("XX", head)); | |
return; | |
} | |
if ( type == "number" ) { | |
changeTargetTo(head); | |
continue; | |
} else if ( type == "string" ) { | |
// // | |
// process 'single pattern' // | |
// // | |
switch (head){ | |
case "on": | |
targetState.on = true; | |
continue; | |
break; | |
case "off": | |
targetState.on = false; | |
continue; | |
break; | |
case "getstate": | |
issueGetState(); | |
continue; | |
break; | |
case "newuser": | |
registUser(); | |
continue; | |
break; | |
case "discover": | |
discoverBridge(); | |
continue; | |
break; | |
default: | |
break; | |
} | |
// // | |
// process 'double pattern' // | |
// // | |
var val = ourList.shift(); | |
if ( typeof(val) != "number" && typeof(val) != "string") { | |
po ("[ERROR]illeagal value. [XX] is not valid for [YY].\n".replace("XX", val).replace("YY", head)); | |
return; | |
} | |
switch (head) { | |
case "target": | |
changeTargetTo(val); | |
break; | |
case "bri": | |
targetState.bri = val; | |
break; | |
case "hue": | |
targetState.hue = val; | |
break; | |
case "sat": | |
targetState.sat = val; | |
break; | |
case "transitiontime": | |
targetState.transitiontime = val; | |
break; | |
case "bridge": | |
setBridgeIpTo(val); | |
break; | |
default: | |
break; | |
} | |
} | |
} // end while | |
// send only if there is a state update. | |
if (countPropeties(targetState) > 0) { | |
issueWithObj(targetState); | |
} | |
} | |
// | |
// change target to another bulb | |
// | |
function changeTargetTo(val){ | |
if( 1 <= val && val <= NBULB) { | |
currTarget = val - 1; | |
po ("[INFO]target changed to[XX]".replace("XX", val)); | |
} | |
} | |
// | |
// issue a cURL command | |
// | |
function issueWithObj(diffObj){ | |
var updatings = singleQuote( JSON.stringify(diffObj) ) + " "; | |
po("[TRACE]updatings:" + updatings); | |
var s = unixCmd.put + updatings + bulbs[ currTarget ].urlChangeState; | |
outlet(0, s); | |
} | |
function issueGetState(){ | |
var s = unixCmd.get + bulbs[ currTarget ].urlGetState; | |
outlet(0, s); | |
} | |
// | |
// set Bridge Ip | |
// | |
function setBridgeIpTo(val){ | |
if (typeof(val) != "string") { | |
po ("[ERROR]illeagal value. [XX] is not valid for [bridge].\n".replace("XX", val)); | |
return; | |
} | |
bridge.ip = val; | |
setupBulbs(NBULB); | |
} | |
// | |
// regist new user (as "newdeveloper") | |
// | |
function registUser(){ | |
var body = {"devicetype":"test user", "username":"newdeveloper"}; | |
var serealBody = singleQuote( JSON.stringify(body) ) + " "; | |
var s = unixCmd.post + serealBody + url.api.replace("IP", bridge.ip); | |
outlet (0, s); | |
} | |
// | |
// discover the bridge | |
// returns bridge ip in stdout. | |
// | |
function discoverBridge(){ | |
var ipAddressFilter = " | egrep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]'" | |
var s = unixCmd.get + url.broker + ipAddressFilter; | |
outlet (0, s); | |
} | |
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
// | |
// Utilities | |
// | |
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
// count properties | |
function countPropeties(obj) { | |
var cnt = 0; | |
for (var prop in obj) {cnt += 1;} | |
return cnt; | |
} | |
// dump object | |
function dump(obj) { | |
var str = {}; | |
for (var prop in obj) { | |
str += "[DUMP]" + prop + ":" + obj[prop] + "\n"; | |
} | |
} | |
// quote for cURL | |
function singleQuote(str){ | |
return "'" + str + "'"; | |
} | |
// post and out | |
function po(str){ | |
if (bPost == 0) {return;} | |
post (str + "\n"); | |
// outlet (0, str); | |
} | |
// serialize json | |
// https://github.com/douglascrockford/JSON-js/blob/master/json.js | |
if (typeof JSON.stringify !== 'function') { | |
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; | |
meta = { // table of character substitutions | |
'\b': '\\b', | |
'\t': '\\t', | |
'\n': '\\n', | |
'\f': '\\f', | |
'\r': '\\r', | |
'"' : '\\"', | |
'\\': '\\\\' | |
}; | |
JSON.stringify = function (value, replacer, space) { | |
var i; gap = ''; indent = ''; | |
if (typeof space === 'number') { | |
for (i = 0; i < space; i += 1) { | |
indent += ' '; | |
} | |
} else if (typeof space === 'string') { | |
indent = space; | |
} | |
rep = replacer; | |
if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || | |
typeof replacer.length !== 'number')) { | |
throw new Error('JSON.stringify'); | |
} | |
return str('', {'': value}); | |
}; | |
} |
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
<pre><code> | |
----------begin_max5_patcher---------- | |
1321.3oc4Z97bahCEG+r8eELL6wTGdR7ydq6ksm2q6tSFrQwQY.AKRjltc5+ | |
6qPBbbRskYZHJhoIyXOHKDO8guumjdRea8J+s0OR39dez6u7Vs5aqWsRUTeA | |
qFtdkeU9i6Jy4pp4WQ3778D+qz+lf7nPUNi7kNNocrbVWEkURDpaBMT3s0LA | |
m9ej9x.zlfmpacmXrxvPoMsDNgIxEzZ1MsjcBsUljFKuQurv9OCF9v6eFtIc | |
6H9ZCQWae+C+TStX2cT19m0VgO0VQp1EROp0nEptV816+.Jz+nNAKuR8.7+T | |
KMuzu+G99508eb0qDiET9t5GrBG088z4iiXEAihLwQHcd43t5pJYu6G33m6H | |
dU4LZSWormy16M.bt2lW0em78Bbp2Kgm48xXo21teq55C06TjMdSjDo8DMLV | |
8EJ7LBT7IA6ePXjGxmaxxIhtlmgTayEbvFzHYf3DijAMyj4b9taaoE6IdPhz | |
kT9OLe9v+TtiwXkCdhQ2wL63NxuiTV5IehRizix+al2cBQyGu95cecWoz5SB | |
2Hu0qE00kxGv0aIsLtfPYePciWO1dxpR1U2wDGSxKK4PygjCqCUh0vEklMFx | |
6TbMzRRNQd6dhvC4cmzqDBB7Ds4LNsOVufVoJJ3mQFtc+t5x5VcOOXS5UG8A | |
bTWdNjqQHEXgLjBrAXiiCamggAEPQHOoOsGFKeQqJHJRUPZpGOW3kk45nMDh | |
UgIg.kZEAlYKXS3tvUq5nqPblIhFhmWhJ6.aOybCg2BDgNGhn8w3ki3ky1aV | |
.FqGmFFlaXf1E+Lzxj96vynUVtfzdCgkusTUifYTa1qL+Mv48qGwpVEFZbL9 | |
Pzu3hvgQtmjFDm89qA6Gaw80fiTcPBZbjkvfe0kfgnoKASe+kf8yxYAHAGn5 | |
fDDLIAwI1YxM02dqyiMPQJThRLhQ8oX3rXKxRXisTnVX5Dn1LmsPF4Kxl8Gf | |
VSqL9iGWTH6I9y1pgOQeGghOZsuIlCeEXk9tJw.u9N8YirOov5ibIJQ+kItf | |
xrimTen6vP0Rrv3EhSkN.dpw.3Pfc32BbMoCxPHV4dB.x3p7isTJ+nUMkDi4 | |
c+cIY55ofgBMmM8HKk.u945+TBpccAllclmqOJvN5qptRAUpvd7RasikUY3. | |
jZs4i5LvjNCRrahhc9ADxB58QGnVj4ADhsz.BC4XegfNPukglQWjUQGrLP2v | |
NPbAzYoCBvBwScXNGlWNDfsCyVHtnfd.zKvLasSWKDlgPWlYI1bEVKj4rklb | |
4biAVZi+VFqIcbxt5kQYduUrzZ5kyAtgVRbcxAQ5bio2B+HiKCM0NjSN8CtH | |
WPVFQ4zNqQFWeUrM2jdLVcfGBiVHIRZ3fNjYLbmkl7KZYkCtAsmwvcXqjZ26 | |
4deti7mj+sivE+dGsrfzt4d9qOYuupwCvXsnBmZJKuS3HLvyefTbi9rvcStP | |
zR21IzGB6UG.krAjA7Oz.F3ggMCT+9X7shxbUGgtWbfuU849xe9qJdcW6tQB | |
MdFn8dpWWHsFJScthOpRvypyczhBB63bnTP481Xw42wxoZN8GkXGxbxbJqws | |
XShSYMwNk0D4TVS+IVykLGjaYNvDLmWXyuo1SfSgG7ThA9Ba9M0dlRTPbh8r | |
G2JNH1sB8fcqoW3VABQSw0BaOWKjaMHJBbKywshK6VChBt0LkA2RICtUPYvw | |
VymaEUFbLOK2JJH3VQAmBbdwvrS2bzIWIuo4ARKenMUVheU985D4Eek5RJSe | |
opE8aIOPGqe559V66q+e.1ogcSC | |
-----------end_max5_patcher----------- | |
</code></pre> |
update 2.2.0 (2014.5.18)
- regists new user to the bridge with (newuser) message.
Greetings. I am using the xxHueTest in Max to try this code.
I only changed the IP to the IP of the device. I am experience the following error with the HueRequest Builder code:
js: HueRequestBuilder.js: Javascript TypeError: bulbs[currTarget] is undefined, line 213
js: error calling function getstate [HueRequestBuilder.js]
Do you having ideas?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
update 2.1.0 (2014.5.18)