From 0a2f2865fbcaa91ce876f077f5ccfcd51491de7d Mon Sep 17 00:00:00 2001 From: Danimal4326 Date: Thu, 13 Aug 2015 10:34:35 -0500 Subject: [PATCH] Add accessory shim for controlling hyperion TV backlight. (https://github.com/tvdzwan/hyperion) --- accessories/Hyperion.js | 221 ++++++++++++++++++++++++++++++++++++++++ config-sample.json | 7 ++ package.json | 1 + 3 files changed, 229 insertions(+) create mode 100644 accessories/Hyperion.js diff --git a/accessories/Hyperion.js b/accessories/Hyperion.js new file mode 100644 index 0000000..b01db55 --- /dev/null +++ b/accessories/Hyperion.js @@ -0,0 +1,221 @@ +var types = require("HAP-NodeJS/accessories/types.js"); +var net = require('net'); +var Color = require('color'); + +function HyperionAccessory(log, config) { + this.log = log; + this.host = config["host"]; + this.port = config["port"]; + this.name = config["name"]; + this.color = Color().hsv([0, 0, 0]); + this.prevColor = Color().hsv([0,0,100]); +} + + +HyperionAccessory.prototype = { + + sendHyperionCommand: function(command, cmdParams, priority) { + var that = this; + var client = new net.Socket(); + var data = {}; + + if (typeof priority === 'undefined') { priority = 100; } + + switch (command) { + case 'color': + data = {"command":"color", "priority":priority,"color":cmdParams}; + break; + case 'blacklevel': + data = {"command":"transform","transform":{"blacklevel":cmdParams}} + break; + default: + that.log("Hyperion command not found"); + return; + } + + //that.log(JSON.stringify(data)); + + client.connect(that.port, that.host, function() { + client.write(JSON.stringify(data) + "\n"); + }); + + client.on('data', function(data){ + that.log("Response: " + data.toString().trim()); + that.log("***** Color HSV:" + that.color.hsvArray() + "*****"); + that.log("***** Color RGB:" + that.color.rgbArray() + "*****"); + client.end(); + }); + }, + + setPowerState: function(powerOn) { + var that = this; + + if (powerOn) { + that.log("Setting power state on the '"+that.name+"' to on"); + that.color.rgb(that.prevColor.rgb()); + that.sendHyperionCommand('color', that.color.rgbArray()); + } else { + that.log("Setting power state on the '"+that.name+"' to off"); + that.prevColor.rgb(that.color.rgb()); + that.color.value(0); + that.sendHyperionCommand('color', that.color.rgbArray()); + that.sendHyperionCommand('blacklevel', [0,0,0]); + } + + }, + + setBrightness: function(level) { + var that = this; + + that.color.value(level); + that.log("Setting brightness on the '"+that.name+"' to '" + level + "'"); + that.sendHyperionCommand('color', that.color.rgbArray()); + + }, + + setHue: function(level) { + var that = this; + + that.color.hue(level); + that.prevColor.hue(level); + that.log("Setting hue on the '"+that.name+"' to '" + level + "'"); + that.sendHyperionCommand('color', that.color.rgbArray()); + + }, + + setSaturation: function(level) { + var that = this; + + that.color.saturationv(level); + that.prevColor.saturationv(level); + that.log("Setting saturation on the '"+that.name+"' to '" + level + "'"); + that.sendHyperionCommand('color', that.color.rgbArray()); + + }, + + getServices: function() { + var that = this; + return [{ + sType: types.ACCESSORY_INFORMATION_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: that.name, + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of the accessory", + designedMaxLength: 255 + },{ + cType: types.MANUFACTURER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Hyperion", + supportEvents: false, + supportBonjour: false, + manfDescription: "Manufacturer", + designedMaxLength: 255 + },{ + cType: types.MODEL_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "Rev-1", + supportEvents: false, + supportBonjour: false, + manfDescription: "Model", + designedMaxLength: 255 + },{ + cType: types.SERIAL_NUMBER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: "DEADBEEF", + supportEvents: false, + supportBonjour: false, + manfDescription: "SN", + designedMaxLength: 255 + },{ + cType: types.IDENTIFY_CTYPE, + onUpdate: null, + perms: ["pw"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Identify Accessory", + designedMaxLength: 1 + }] + },{ + sType: types.LIGHTBULB_STYPE, + characteristics: [{ + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: that.name, + supportEvents: true, + supportBonjour: false, + manfDescription: "Name of service", + designedMaxLength: 255 + },{ + cType: types.POWER_STATE_CTYPE, + onUpdate: function(value) { that.setPowerState(value); }, + onRead: ((that.color.value() > 0) ? true : false), + perms: ["pw","pr","ev"], + format: "bool", + initialValue: 0, + supportEvents: true, + supportBonjour: false, + manfDescription: "Turn on the light", + designedMaxLength: 1 + },{ + cType: types.BRIGHTNESS_CTYPE, + onUpdate: function(value) { that.setBrightness(value); }, + onRead: that.color.value(), + perms: ["pw","pr","ev"], + format: "int", + initialValue: that.color.value(), + supportEvents: false, + supportBonjour: false, + manfDescription: "Adjust Brightness", + designedMinValue: 0, + designedMaxValue: 100, + designedMinStep: 1, + unit: "%" + },{ + cType: types.HUE_CTYPE, + onUpdate: function(value) { that.setHue(value) }, + onRead: that.color.hue(), + perms: ["pw","pr","ev"], + format: "int", + initialValue: that.color.hue(), + supportEvents: false, + supportBonjour: false, + manfDescription: "Adjust Hue", + designedMinValue: 0, + designedMaxValue: 360, + designedMinStep: 1, + unit: "arcdegrees" + },{ + cType: types.SATURATION_CTYPE, + onUpdate: function(value) { that.setSaturation(value) }, + onRead: that.color.saturationv(), + perms: ["pw","pr","ev"], + format: "int", + initialValue: that.color.saturationv(), + supportEvents: false, + supportBonjour: false, + manfDescription: "Adjust Saturation", + designedMinValue: 0, + designedMaxValue: 100, + designedMinStep: 1, + unit: "%" + }] + }]; + } +}; + +module.exports.accessory = HyperionAccessory; diff --git a/config-sample.json b/config-sample.json index 0f3f511..a9477d0 100644 --- a/config-sample.json +++ b/config-sample.json @@ -159,6 +159,13 @@ "description": "This shim supports controlling climate control on the Tesla Model S.", "username": "tesla_email", "password" : "tesla_password" + }, + { + "accessory": "Hyperion", + "name": "TV Backlight", + "description": "Control the Hyperion TV backlight server. https://github.com/tvdzwan/hyperion" + "host": "localhost", + "port": "19444" } ] } diff --git a/package.json b/package.json index ae1d196..e7ee673 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dependencies": { "ad2usb": "git+https://github.com/alistairg/node-ad2usb.git#local", "carwingsjs": "0.0.x", + "color": "0.10.x", "elkington": "kevinohara80/elkington", "hap-nodejs": "git+https://github.com/khaost/HAP-NodeJS#2a1bc8d99a2009317ab5da93faebea34c89f197c", "harmonyhubjs-client": "^1.1.4",