homebridge-ws-beta
Version:
317 lines (250 loc) • 11.4 kB
JavaScript
'use strict';
var util = require('util');
var path = require('path');
var Utils = require('./utils.js').Utils;
var port, plugin_name, accessories, Service, Characteristic, addAccessory, removeAccessory, getAccessories, HapAccessory, api, getSingleAccessories, setAccessoryInformation, configureAccessory;
var latest, get_timeout, set_timeout, pre_name, pre_c;
var WebSocketServer = require('ws').Server,
http = require('http'),
express = require('express'),
app = express();
module.exports = {
Websocket: Websocket
}
function Websocket(params) {
this.log = params.log;
port = params.port;
plugin_name = params.plugin_name;
accessories = params.accessories;
Characteristic = params.Characteristic;
addAccessory = params.addAccessory;
removeAccessory = params.removeAccessory;
getAccessories = params.getAccessories;
getSingleAccessories = params.getSingleAccessories;
api = params.api;
HapAccessory = params.HapAccessory;
Service = params.Service;
setAccessoryInformation = params.setAccessoryInformation;
configureAccessory = params.configureAccessory;
this.ws;
}
Websocket.prototype.startServer = function () {
var server = http.createServer(app);
server.listen(port, function () {
this.log("url %j", server.address());
}.bind(this));
var wsServer = new WebSocketServer({ server: server });
wsServer.on('connection', function (ws, req) {
this.ws = ws;
this.ws.on('open', function open() { // no event ?
this.log.debug("on.open");
}.bind(this));
this.ws.on('message', function message(data) {
this.log.debug("on.message: %s", data);
this.onMessage(data);
}.bind(this));
this.ws.on('close', function close() {
this.log("on.close client ip %s disconnected", req.connection.remoteAddress);
}.bind(this));
this.ws.on('error', function error(e) {
this.log.error("on.error %s", e.message);
}.bind(this))
set_timeout = setTimeout(function () {
this.log("client ip %s connected", req.connection.remoteAddress);
}.bind(this), 500);
}.bind(this));
}
Websocket.prototype.onMessage = function (data) {
var msg = JSON.parse(data);
var topic = msg.topic;
var accessory = msg.payload;
var result = {};
switch (topic) {
case "add":
case "addAccessory":
this.log.debug("onMessage add %s", JSON.stringify(accessory, null, 2));
addAccessory(accessory);
break;
case "remove":
case "removeAccessory":
removeAccessory(accessory.name);
break;
case "set":
case "setValue":
//this.log.debug("onMessage setValue %s", JSON.stringify(accessory));
this.log.debug("setValue %s", JSON.stringify(accessory));
result = this.validate(accessory);
if (result.isValid) {
accessories[accessory.name].save_and_setValue("websocket", accessory.characteristic, result.value);
} else {
this.log.warn("setValue %s", result.message);
this.sendAck(false, result.message);
}
break;
case "setAccessories":
this.log.debug("onMessage setValue %s", JSON.stringify(accessory));
this.log.debug("setValue %s", JSON.stringify(accessory));
result = this.validate(accessory);
var AccessoriesInfo = getSingleAccessories(accessory.name)
//var AccessoryInfo = getAccessory(name)
//this.log.debug("save_and_setValue %s %s", accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[1].displayName, accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[1].value);
//accessories[accessory.name].save_and_setValue("websocket", accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[1].displayName, accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[1].value);
//accessories[accessory.name].save_and_setValue("websocket", accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[2].displayName, accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[2].value);
//accessories[accessory.name].save_and_setValue("websocket", accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[4].displayName, accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[4].value);
//accessories[accessory.name].save_and_setValue("websocket", accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[5].displayName, accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[5].value);
var model = accessories[accessory.name].hap_accessories[accessory.name].services[0].characteristics[2].value;
setAccessoryInformation(accessory);
this.log.debug("configureAccessory %s", JSON.stringify(accessories[accessory.name].hap_accessories[accessory.name].services, null, 2));
//configureAccessory(accessories[accessory.name].hap_accessories[accessory.name]);
break;
case "callback":
this.log.debug("callback %s", JSON.stringify(accessory));
result = this.validate(accessory);
if (result.isValid) {
accessories[accessory.name].saveValue(accessory.characteristic, result.value);
} else {
this.log.error("onMessage %s", result.message);
this.sendAck(false, result.message);
}
break;
case "getAccessories":
case "getAccessory":
case "get":
var name;
this.log.debug("onMessage get %s", JSON.stringify(accessory));
if (typeof (accessory.name) !== "undefined") {
name = accessory.name;
} else {
name = "all";
}
if (typeof (accessories[name]) !== "undefined" || name === "all") {
getAccessories(name);
} else {
var message = "name '" + name + "' undefined.";
this.log.warn("onMessage.get %s", message);
this.sendAck(false, message);
}
break;
default:
var message = "topic '" + topic + "' unknown.";
this.log.warn("onMessage topic %s", message);
this.sendAck(false, message);
}
}
Websocket.prototype.validate = function (accessory) {
var name = accessory.name;
var c = accessory.characteristic;
var value = accessory.value;
var isValid = false;
var message = "";
if (typeof (accessories[name]) === "undefined") {
message = "name '" + name + "' undefined.";
} else if (typeof (Characteristic[c]) !== "function") {
message = "characteristic '" + c + "' undefined.";
} else if (typeof (accessory.value) === "undefined" || accessory.value === null) {
message = "name '" + name + "' value undefined.";
} else if (typeof (accessories[name].service.getCharacteristic(Characteristic[c])) === "undefined") {
message = "name '" + name + "' characteristic do not match.";
} else {
var result = {};
result = accessories[name].parseValue(c, value);
isValid = result.isValid;
value = result.value;
if (!isValid) {
message = "value '" + value + "' outside range";
} else {
message = "name '" + name + "' is valid.";
}
}
return { isValid: isValid, message: message, value: value };
}
Websocket.prototype.get = function (name, c, callback) {
// callback not used
// this.log.debug("get %s %s", name, c);
var AccessoriesInfo = getSingleAccessories(name);
//var AccessoryInfo = accessories[name];
//if (typeof(accessories[name].service.getCharacteristic(Characteristic["Model"]).value) === null) {
// this.log.debug("Model is Null");
//} else {
// var model = accessories[name].service.getCharacteristic(Characteristic["Model"]).value;
// this.log.debug("Model is %s",model);
//}
//var model = accessories[name].service.characteristics[3].value;
//var model1 = this.hap_accessories[name]
//var model2 = accessories[name].hap_accessories[name].services[1].characteristics[4].value;
//accessories[name].service.getCharacteristic(Characteristic["Model"])
var model = accessories[name].hap_accessories[name].services[0].characteristics[2].value;
this.log.debug("AccessoriesInfo.serialnumber2 %s %s", AccessoriesInfo.serialnumber, model);
//this.log.debug("AccessoriesInfo.Model %s %s", AccessoryInfo,JSON.stringify(AccessoryInfo));
//.serialnumber,AccessoriesInfo.model);
if (typeof (this.ws) !== "undefined" && this.ws.OPEN) {
var data = { "topic": "get", "payload": { "name": name, "characteristic": c, "serialnumber": AccessoriesInfo.serialnumber, "Service": AccessoriesInfo.service, "Model": model } };
this.sendData(data);
} else {
this.log.debug("get client disconnected.");
}
}
Websocket.prototype.set = function (name, c, value, callback) {
if (typeof (this.ws) !== "undefined" && this.ws.OPEN) {
if (c === "On") {
value = (value == 0 || value == false) ? false : true;
}
var AccessoriesInfo = getSingleAccessories(name)
//var AccessoryInfo = getAccessory(name)
var model = accessories[name].hap_accessories[name].services[0].characteristics[2].value;
this.log.debug("AccessoriesInfo.serialnumber %s", AccessoriesInfo.serialnumber);
this.log.debug("AccessoriesInfo.Model %s %s", AccessoryInfo, JSON.stringify(AccessoryInfo));
var data = { "topic": "set", "payload": { "name": name, "characteristic": c, "value": value, "serialnumber": AccessoriesInfo.serialnumber, "Service": AccessoriesInfo.service, "Model": model } };
switch (c) {
case "Brightness":
case "TargetPosition":
case "TargetHorizontalTiltAngle":
case "TargetVerticalTiltAngle":
case "TargetRelativeHumidity":
case "TargetTemperature":
if (set_timeout && name === pre_name && c === pre_c) {
clearTimeout(set_timeout);
}
set_timeout = setTimeout(function () {
this.log.debug("set %s %s %s", name, c, value);
this.sendData(data);
}.bind(this), 300);
pre_name = name;
pre_c = c;
this.log.debug("Pre_name and Pre_c %s %s", pre_name, pre_c);
break;
default:
this.log.debug("set %s %s %s", name, c, value, AccessoriesInfo.serialnumber);
this.sendData(data);
}
callback(); // todo error handling
} else {
this.log.debug("get client disconnected.");
callback("disconnected");
}
}
Websocket.prototype.sendAccessories = function (accessories) {
if (typeof (this.ws) !== "undefined" && this.ws.OPEN) {
var data = { "topic": "accessories", "payload": accessories };
this.sendData(data);
} else {
this.log.error("sendAck client disconnected.");
}
}
Websocket.prototype.sendAck = function (ack, message, serial_Number, service_Name) {
if (typeof (this.ws) !== "undefined" && this.ws.OPEN) {
var data = { "topic": "response", "payload": { "ack": ack, "message": message, "serialnumber": serial_Number, "service": service_Name } };
this.sendData(data);
} else {
this.log.error("sendAck client disconnected.");
}
}
Websocket.prototype.sendData = function (data) {
if (typeof (this.ws) !== "undefined" && this.ws.OPEN) {
var j_data = JSON.stringify(data);
this.log.debug("sendData %s", JSON.stringify(data)); // JSON.stringify(data, null, 2));
this.ws.send(j_data, function ack(error) {
if (error) this.log("sendData %s", error);
}.bind(this));
}
}