Last active
October 4, 2015 15:55
-
-
Save knalli/201eea71130136db2ca0 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
'use strict'; | |
let Service = require("HAP-NodeJS").Service; | |
let Characteristic = require("HAP-NodeJS").Characteristic; | |
let WebSocketClient = require('websocket').client; | |
class Utils { | |
assertUtf8Message(message) { | |
return new Promise((resolve, reject) => { | |
if (message.type === 'utf8') { | |
resolve(message); | |
} else { | |
reject(message); | |
} | |
}); | |
} | |
convertToJson(message) { | |
return new Promise((resolve, reject) => { | |
try { | |
resolve(JSON.parse(message.utf8Data)); | |
} catch (e) { | |
reject(e); | |
} | |
}); | |
} | |
isMessageOfTypeValues(json) { | |
let result = false; | |
if (Array.isArray(json)) { | |
if (json.length === 0) { | |
result = true; | |
} else if (typeof json[0].type !== 'undefined' && typeof json[0].devices !== 'undefined' && typeof json[0].values !== 'undefined') { | |
result = true; | |
} | |
} | |
return result; | |
} | |
isMessageOfTypeUpdate(json) { | |
return (json.origin == 'update' && typeof json.type !== 'undefined' && typeof json.devices !== 'undefined' && typeof json.values !== 'undefined'); | |
} | |
} | |
class PilightWebsocketAccessory { | |
constructor(log, config) { | |
this.log = log; | |
this.deviceStates = {}; | |
this.config = { | |
host: config.host || 'localhost', | |
port: config.port || 5001, | |
deviceId: config.device | |
}; | |
this.client = new WebSocketClient(); | |
this.client.connect('ws://' + this.config.host + ':' + this.config.port + '/'); | |
// FIXME: Should handle error | |
// FIXME: Should cache/multiplex identical connections? | |
this.client.on('connect', (connection) => { | |
this.log('Connection established: ' + 'ws://' + this.config.host + ':' + this.config.port + '/'); | |
this._connection = connection; | |
this._connection.on('message', (message) => this.handleMessage(message)); | |
// initial request all available values | |
this._connection.sendUTF(JSON.stringify({action: 'request values'})); | |
}); | |
} | |
handleMessage(rawMessage) { | |
let utils = new Utils(); | |
return Promise.resolve(rawMessage) | |
.then(utils.assertUtf8Message) | |
.then(utils.convertToJson) | |
.then((json) => { | |
if (utils.isMessageOfTypeValues(json)) { | |
// bulk update ("request values") | |
this.deviceStates = {}; | |
for (let item of json) { | |
for (let device of item.devices) { | |
this.deviceStates[device] = item.values.state === 'on'; | |
} | |
this.log('Updated internal states of devices: ' + item.devices); | |
} | |
} else if (utils.isMessageOfTypeUpdate(json)) { | |
// item update (after "control") | |
for (let device of json.devices) { | |
this.deviceStates[device] = json.values.state === 'on'; | |
} | |
this.log('Updated internal states of devices: ' + json.devices); | |
} | |
}) | |
.catch(() => { | |
this.log('Something went wrong, cannot parse message'); | |
}); | |
} | |
setPowerState(powerOn, callback) { | |
// FIXME: Should handle error somwhow! | |
this._connection.sendUTF(JSON.stringify({action: "control", code: {device: this.config.deviceId, state: (powerOn ? 'on' : 'off')}})); | |
callback(); | |
} | |
getPowerState(callback) { | |
if (!this.deviceStates || typeof this.deviceStates[this.config.deviceId] === 'undefined') { | |
this.log('No power state found for device ' + this.config.deviceId); | |
callback(new Error("Not found")); | |
} else { | |
callback(null, this.deviceStates[this.config.deviceId]); | |
} | |
} | |
identify(callback) { | |
this.log("Identify requested!"); | |
callback(); // success | |
} | |
getServices() { | |
// you can OPTIONALLY create an information service if you wish to override | |
// the default values for things like serial number, model, etc. | |
let informationService = new Service.AccessoryInformation(); | |
informationService | |
.setCharacteristic(Characteristic.Manufacturer, "Pilight Manufacturer") | |
.setCharacteristic(Characteristic.Model, "Pilight Model") | |
.setCharacteristic(Characteristic.SerialNumber, "Pilight Serial Number"); | |
let lightbulbService = new Service.Lightbulb(); | |
lightbulbService | |
.getCharacteristic(Characteristic.On) | |
.on('set', this.setPowerState.bind(this)); | |
lightbulbService | |
.getCharacteristic(Characteristic.On) | |
.on('get', this.getPowerState.bind(this)); | |
return [informationService, lightbulbService]; | |
} | |
} | |
module.exports = { | |
accessory: PilightWebsocketAccessory | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment