From aa823baa8ec6e76ca7aec723f0f5e69018567689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Devran=20=C3=9Cnal?= Date: Thu, 17 Sep 2015 02:03:53 +0200 Subject: [PATCH 1/7] Add shim for devices with serial connection (video projectors, screens, receivers, ..) --- accessories/GenericRS232Device.js | 126 ++++++++++++++++++++++++++++++ config-sample.json | 13 ++- package.json | 1 + 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 accessories/GenericRS232Device.js diff --git a/accessories/GenericRS232Device.js b/accessories/GenericRS232Device.js new file mode 100644 index 0000000..3b9ca36 --- /dev/null +++ b/accessories/GenericRS232Device.js @@ -0,0 +1,126 @@ +var types = require("HAP-NodeJS/accessories/types.js"); +var SerialPort = require("serialport").SerialPort; + +module.exports = { + accessory: GenericRS232DeviceAccessory +} + +function GenericRS232DeviceAccessory(log, config) { + this.log = log; + this.id = config["id"]; + this.name = config["name"]; + this.model_name = config["model_name"]; + this.manufacturer = config["manufacturer"]; + this.on_command = config["on_command"]; + this.off_command = config["off_command"]; + this.device = config["device"]; + this.baudrate = config["baudrate"]; +} + +GenericRS232DeviceAccessory.prototype = { + 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: that.manufacturer, + supportEvents: false, + supportBonjour: false, + manfDescription: "Manufacturer", + designedMaxLength: 255 + }, + { + cType: types.MODEL_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: that.model_name, + supportEvents: false, + supportBonjour: false, + manfDescription: "Model", + designedMaxLength: 255 + }, + { + cType: types.SERIAL_NUMBER_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: that.id, + 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.SWITCH_STYPE, + characteristics: [ + { + cType: types.NAME_CTYPE, + onUpdate: null, + perms: ["pr"], + format: "string", + initialValue: this.serviceName, + supportEvents: false, + supportBonjour: false, + manfDescription: "Name of service", + designedMaxLength: 255 + }, + { + cType: types.POWER_STATE_CTYPE, + onUpdate: function(value) { + var command = (value == 1 ? that.on_command : that.off_command); + var serialPort = new SerialPort(that.device, { baudrate: that.baudrate }); + serialPort.on("open", function () { + serialPort.write(command, function(error, results) { + if(error) { + console.log('Errors ' + err); + } + }); + }); + + }, + perms: ["pw","pr","ev"], + format: "bool", + initialValue: false, + supportEvents: false, + supportBonjour: false, + manfDescription: "Set the Power state", + designedMaxLength: 1 + } + ] + } + ] + } +} + +module.exports.accessory = GenericRS232DeviceAccessory; \ No newline at end of file diff --git a/config-sample.json b/config-sample.json index 49fc923..6f24554 100644 --- a/config-sample.json +++ b/config-sample.json @@ -205,7 +205,18 @@ "window_seconds": 5, "sensor_type": "m", "inverse": false + }, + { + "accessory": "GenericRS232Device", + "name": "Projector", + "description": "Make sure you set a 'Siri-Name' for your iOS-Device (example: 'Home Cinema') otherwise it might not work.", + "id": "TYDYMU044UVNP", + "baudrate": 9600, + "device": "/dev/tty.usbserial", + "manufacturer": "Acer", + "model_name": "H6510BD", + "on_command": "* 0 IR 001\r", + "off_command": "* 0 IR 002\r" } - ] } diff --git a/package.json b/package.json index d0eb41c..f8b7225 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "q": "1.4.x", "tough-cookie": "^2.0.0", "request": "2.49.x", + "serialport": "^1.7.4", "sonos": "0.8.x", "telldus-live": "0.2.x", "teslams": "1.0.1", From 65ec517fd89f1ce95bd04d379ee668149627e0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Devran=20=C3=9Cnal?= Date: Thu, 17 Sep 2015 11:37:20 +0200 Subject: [PATCH 2/7] Update to modern API and return error messages on failed connections --- accessories/GenericRS232Device.js | 150 ++++++++---------------------- 1 file changed, 41 insertions(+), 109 deletions(-) diff --git a/accessories/GenericRS232Device.js b/accessories/GenericRS232Device.js index 3b9ca36..3bdfc18 100644 --- a/accessories/GenericRS232Device.js +++ b/accessories/GenericRS232Device.js @@ -1,4 +1,5 @@ -var types = require("HAP-NodeJS/accessories/types.js"); +var Service = require("HAP-NodeJS").Service; +var Characteristic = require("HAP-NodeJS").Characteristic; var SerialPort = require("serialport").SerialPort; module.exports = { @@ -6,120 +7,51 @@ module.exports = { } function GenericRS232DeviceAccessory(log, config) { - this.log = log; - this.id = config["id"]; - this.name = config["name"]; - this.model_name = config["model_name"]; + this.log = log; + this.id = config["id"]; + this.name = config["name"]; + this.model_name = config["model_name"]; this.manufacturer = config["manufacturer"]; - this.on_command = config["on_command"]; - this.off_command = config["off_command"]; - this.device = config["device"]; - this.baudrate = config["baudrate"]; + this.on_command = config["on_command"]; + this.off_command = config["off_command"]; + this.device = config["device"]; + this.baudrate = config["baudrate"]; } GenericRS232DeviceAccessory.prototype = { - 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: that.manufacturer, - supportEvents: false, - supportBonjour: false, - manfDescription: "Manufacturer", - designedMaxLength: 255 - }, - { - cType: types.MODEL_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: that.model_name, - supportEvents: false, - supportBonjour: false, - manfDescription: "Model", - designedMaxLength: 255 - }, - { - cType: types.SERIAL_NUMBER_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: that.id, - 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 + setPowerState: function(powerOn, callback) { + var that = this; + var command = powerOn ? that.on_command : that.off_command; + var serialPort = new SerialPort(that.device, { baudrate: that.baudrate }, false); + serialPort.open(function (error) { + if (error) { + callback(new Error('Can not communicate with ' + that.name + " (" + error + ")")) + } else { + serialPort.write(command, function(err, results) { + if (error) { + callback(new Error('Can not send power command to ' + that.name + " (" + err + ")")) + } else { + callback() } - ] - }, - { - sType: types.SWITCH_STYPE, - characteristics: [ - { - cType: types.NAME_CTYPE, - onUpdate: null, - perms: ["pr"], - format: "string", - initialValue: this.serviceName, - supportEvents: false, - supportBonjour: false, - manfDescription: "Name of service", - designedMaxLength: 255 - }, - { - cType: types.POWER_STATE_CTYPE, - onUpdate: function(value) { - var command = (value == 1 ? that.on_command : that.off_command); - var serialPort = new SerialPort(that.device, { baudrate: that.baudrate }); - serialPort.on("open", function () { - serialPort.write(command, function(error, results) { - if(error) { - console.log('Errors ' + err); - } - }); - }); - - }, - perms: ["pw","pr","ev"], - format: "bool", - initialValue: false, - supportEvents: false, - supportBonjour: false, - manfDescription: "Set the Power state", - designedMaxLength: 1 - } - ] + }); } - ] + }); + }, + + getServices: function() { + var switchService = new Service.Switch(); + var informationService = new Service.AccessoryInformation(); + + informationService + .setCharacteristic(Characteristic.Manufacturer, this.manufacturer) + .setCharacteristic(Characteristic.Model, this.model_name) + .setCharacteristic(Characteristic.SerialNumber, this.id); + + switchService + .getCharacteristic(Characteristic.On) + .on('set', this.setPowerState.bind(this)); + + return [informationService, switchService]; } } From 72b9175b787a324aaebead838939f57e10fc7fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Devran=20=C3=9Cnal?= Date: Thu, 17 Sep 2015 15:22:02 +0200 Subject: [PATCH 3/7] Set siri name based on accessory name --- accessories/GenericRS232Device.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accessories/GenericRS232Device.js b/accessories/GenericRS232Device.js index 3bdfc18..b84e4cc 100644 --- a/accessories/GenericRS232Device.js +++ b/accessories/GenericRS232Device.js @@ -39,7 +39,7 @@ GenericRS232DeviceAccessory.prototype = { }, getServices: function() { - var switchService = new Service.Switch(); + var switchService = new Service.Switch(this.name); var informationService = new Service.AccessoryInformation(); informationService From 2135e7eccbbc2aabc4476d3c8db4a9367dc90547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Devran=20=C3=9Cnal?= Date: Thu, 17 Sep 2015 17:00:52 +0200 Subject: [PATCH 4/7] Print scannable setup code to terminal on startup --- app.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app.js b/app.js index 8a92123..692fc1a 100644 --- a/app.js +++ b/app.js @@ -191,6 +191,16 @@ function createAccessory(accessoryInstance, displayName) { } } +// Returns the setup code in a scannable format. +function printPin(pin) { + console.log("Scan this code with your HomeKit App on your iOS device:"); + console.log("\x1b[30;47m%s\x1b[0m", " "); + console.log("\x1b[30;47m%s\x1b[0m", " ┌────────────┐ "); + console.log("\x1b[30;47m%s\x1b[0m", " │ " + pin + " │ "); + console.log("\x1b[30;47m%s\x1b[0m", " └────────────┘ "); + console.log("\x1b[30;47m%s\x1b[0m", " "); +} + // Returns a logging function that prepends messages with the given name in [brackets]. function createLog(name) { return function(message) { @@ -210,3 +220,5 @@ function publish() { } startup(); + +printPin(bridgeConfig.pin); From a05a4b6f714805968709e8e66a2c4be75e1f9be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Devran=20=C3=9Cnal?= Date: Thu, 17 Sep 2015 17:36:29 +0200 Subject: [PATCH 5/7] Print the setup code just before publishing the bridge --- app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app.js b/app.js index 692fc1a..a8c2006 100644 --- a/app.js +++ b/app.js @@ -211,6 +211,7 @@ function createLog(name) { } function publish() { + printPin(bridgeConfig.pin); bridge.publish({ username: bridgeConfig.username || "CC:22:3D:E3:CE:30", port: bridgeConfig.port || 51826, @@ -220,5 +221,3 @@ function publish() { } startup(); - -printPin(bridgeConfig.pin); From 5720e82abd578cbd257bfa761eb636b6f7232902 Mon Sep 17 00:00:00 2001 From: Nick Farina Date: Thu, 17 Sep 2015 12:50:27 -0700 Subject: [PATCH 6/7] Remove test code from WeMo --- accessories/WeMo.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/accessories/WeMo.js b/accessories/WeMo.js index df16f56..c19e19f 100644 --- a/accessories/WeMo.js +++ b/accessories/WeMo.js @@ -140,9 +140,7 @@ WeMoAccessory.prototype.getServices = function() { garageDoorService .getCharacteristic(Characteristic.TargetDoorState) - .on('set', this.setTargetDoorState.bind(this)) - .supportsEventNotification = false; - + .on('set', this.setTargetDoorState.bind(this)); return [garageDoorService]; } From 73148b060d17586c20b492ec4922799e1a77ca79 Mon Sep 17 00:00:00 2001 From: Nick Farina Date: Thu, 17 Sep 2015 12:51:55 -0700 Subject: [PATCH 7/7] Remove serial port dependency for now --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index f8b7225..d0eb41c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "q": "1.4.x", "tough-cookie": "^2.0.0", "request": "2.49.x", - "serialport": "^1.7.4", "sonos": "0.8.x", "telldus-live": "0.2.x", "teslams": "1.0.1",