From c81fb2db33fb5e8c9d8767f45dbdd3b8041fe4d6 Mon Sep 17 00:00:00 2001 From: Pierre CLEMENT Date: Tue, 20 Feb 2018 21:36:54 +0100 Subject: [PATCH] fix(gateay): fix all nodes and output node also start setColor of the gateway --- src/devices/Gateway.ts | 35 ++++++++++++--- src/nodes/gateway-subdevices/All.ts | 34 +++++++++----- .../gateway-subdevices/GatewaySubdevice.ts | 9 ++-- src/nodes/gateway/GatewayConfigurator.ts | 9 +++- src/nodes/gateway/GatewayIn.ts | 45 ------------------- src/nodes/gateway/GatewayOut.ts | 41 ++++------------- src/utils/Color.ts | 25 +++++++++++ src/utils/index.ts | 1 + 8 files changed, 98 insertions(+), 101 deletions(-) create mode 100644 src/utils/Color.ts create mode 100644 src/utils/index.ts diff --git a/src/devices/Gateway.ts b/src/devices/Gateway.ts index 3f656c1..950aa45 100644 --- a/src/devices/Gateway.ts +++ b/src/devices/Gateway.ts @@ -4,6 +4,7 @@ import * as crypto from 'crypto'; import {GatewayServer} from "./GatewayServer"; import {GatewayMessage, GatewaySubdevice, Magnet, Motion, Switch, Weather} from "./"; import * as MessageData from "./GatewayMessageData"; +import {Color} from "../utils/Color"; export class Gateway extends events.EventEmitter { static iv: Buffer = Buffer.from([0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58, 0x56, 0x2e]); @@ -16,8 +17,10 @@ export class Gateway extends events.EventEmitter { } get key(): string { + if (!this.lastToken || !this.password) return null; + var cipher = crypto.createCipheriv('aes-128-cbc', this.password, Gateway.iv); - var key = cipher.update(this.lastToken, "ascii", "hex"); + var key = cipher.update(Buffer.from(this.lastToken), "ascii", "hex"); cipher.final('hex'); return key; @@ -27,12 +30,13 @@ export class Gateway extends events.EventEmitter { if (msg.data) { if (msg.model === "gateway" && msg.sid === this.sid && msg.token) { this.lastToken = msg.token; + this.setLight(100, {red: 255, green: 0, blue: 0}); } } if (msg.isGetIdListAck()) { ( msg.data).forEach((sid) => { - this.sendRead({cmd: "read", sid: sid}); + this.send({cmd: "read", sid: sid}); }); } @@ -62,17 +66,34 @@ export class Gateway extends events.EventEmitter { return !!this._subdevices[sid]; } - setLight() { - + setLight(brightness, rgb) { + this.send({ + cmd: "write", + data: { + rgb: Color.toValue(rgb.red, rgb.green, rgb.blue, brightness), + sid: this.sid + } + }); } playSound() { } - sendRead(message: any) { - message.sid = message.sid || this.sid; - GatewayServer.getInstance().sendToGateway(this.sid, message); + send(message: any) { + let msg = Object.assign({}, message.payload || message); + if (msg.cmd) { + msg.sid = message.sid || this.sid; + if (msg.gateway) { + delete msg.gateway; + } + + if (msg.cmd === "write") { + msg.data.key = this.key; + } + + GatewayServer.getInstance().sendToGateway(this.sid, msg); + } } get subdevices(): { [sid: string]: GatewaySubdevice } { diff --git a/src/nodes/gateway-subdevices/All.ts b/src/nodes/gateway-subdevices/All.ts index e3020c8..eb2a5e5 100644 --- a/src/nodes/gateway-subdevices/All.ts +++ b/src/nodes/gateway-subdevices/All.ts @@ -1,7 +1,7 @@ -import { Red, NodeProperties } from "node-red"; -import { Constants } from "../constants"; +import {Red, NodeProperties} from "node-red"; +import {Constants} from "../constants"; -export default (RED:Red) => { +export default (RED: Red) => { class All { protected gateway: any; protected onlyModels: string[]; @@ -15,40 +15,50 @@ export default (RED:Red) => { return cleanOnlyModels; } - constructor(props:NodeProperties) { + constructor(props: NodeProperties) { RED.nodes.createNode( this, props); this.gateway = RED.nodes.getNode(( props).gateway); this.onlyModels = All.getOnlyModelsValue(( props).onlyModels || []); this.excludedSids = ( props).excludedSids; + + this.setMessageListener(); } protected setMessageListener() { ( this).on('input', (msg) => { if (this.gateway) { // Filter input - if(msg.payload && msg.payload.model && msg.payload.sid) { - if(!this.isDeviceValid(msg.payload)) { + if (msg.payload && msg.payload.model && msg.payload.sid) { + if (!this.isDeviceValid(msg.payload)) { msg = null; } + ( this).send(msg); } // Prepare for request else { - msg.payload = this.gateway.deviceList.filter((device) => this.isDeviceValid(device)); + Object.keys(this.gateway.deviceList || {}) + .filter((sid) => this.isDeviceValid(sid)) + .forEach((sid) => { + let curMsg = Object.assign({}, msg); + curMsg.sid = sid; + curMsg.gateway = this.gateway; + ( this).send(curMsg); + }); } - ( this).send(msg); } }); } - isDeviceValid(device) { - if((!this.onlyModels || this.onlyModels.length == 0) && (!this.excludedSids || this.excludedSids.length == 0)) { + isDeviceValid(sid) { + if ((!this.onlyModels || this.onlyModels.length == 0) && (!this.excludedSids || this.excludedSids.length == 0)) { return true; } + let device = this.gateway.deviceList[sid]; // Is excluded - if((this.excludedSids && this.excludedSids.length != 0) && this.excludedSids.indexOf(device.sid) >= 0) { + if ((this.excludedSids && this.excludedSids.length != 0) && this.excludedSids.indexOf(sid) >= 0) { return false; } - if((this.onlyModels && this.onlyModels.length != 0) && this.onlyModels.indexOf(device.model) >= 0) { + if ((this.onlyModels && this.onlyModels.length != 0) && this.onlyModels.indexOf(device.internalModel) >= 0) { return true; } diff --git a/src/nodes/gateway-subdevices/GatewaySubdevice.ts b/src/nodes/gateway-subdevices/GatewaySubdevice.ts index b8894bf..aff2a2b 100644 --- a/src/nodes/gateway-subdevices/GatewaySubdevice.ts +++ b/src/nodes/gateway-subdevices/GatewaySubdevice.ts @@ -12,11 +12,14 @@ export default (RED:Red, type:string) => { this.sid = ( props).sid; ( this).status({fill:"grey", shape:"ring", text:"battery - na"}); - + this.setMessageListener(); + } + + protected setMessageListener() { if (this.gateway) { ( this).on('input', (msg) => { let payload = msg.payload; - + // Input from gateway if (payload.sid) { if (payload.sid == this.sid) { @@ -25,7 +28,7 @@ export default (RED:Red, type:string) => { fill: "green", shape: "dot", text: "battery - " + batteryLevel + "%" }; - + if (batteryLevel < 10) { status.fill = "red"; } else if (batteryLevel < 45) { diff --git a/src/nodes/gateway/GatewayConfigurator.ts b/src/nodes/gateway/GatewayConfigurator.ts index 7fbbef3..2a93270 100644 --- a/src/nodes/gateway/GatewayConfigurator.ts +++ b/src/nodes/gateway/GatewayConfigurator.ts @@ -16,17 +16,24 @@ export interface IGatewayConfiguratorNode extends Node { on(event: "subdevice-update", listener: (subdevice: GatewaySubdevice) => void): any; } +interface GatewayConfiguratorSubDevice { + name: string; + internalModel: string; +} + export default (RED: Red) => { class GatewayConfigurator { sid: string; key: string; + deviceList: { [sid: string]: GatewayConfiguratorSubDevice }; _gateway: Gateway; constructor(props: NodeProperties) { RED.nodes.createNode( this, props); - let {sid, key} = props; + let {sid, key, deviceList} = props; this.sid = sid; this.key = key; + this.deviceList = deviceList; let server = GatewayServer.getInstance(); if (this.sid) { this.setGateway(); diff --git a/src/nodes/gateway/GatewayIn.ts b/src/nodes/gateway/GatewayIn.ts index 93fad1c..b438621 100644 --- a/src/nodes/gateway/GatewayIn.ts +++ b/src/nodes/gateway/GatewayIn.ts @@ -36,51 +36,6 @@ export default (RED: Red) => { protected gatewayOffline() { (this).status({fill: "red", shape: "ring", text: "offline"}); } - - /*setGateway(gateway:LumiAqara.Gateway) { - this.gateway = gateway; - this.gateway.setPassword(this.gatewayConf.password); - (this).status({fill:"blue", shape:"dot", text: "online"}); - - this.gateway.on('offline', () => { - this.gateway = null; - (this).status({fill:"red", shape:"ring", text: "offline"}); - }); - - this.gateway.on('subdevice', (device) => { - device.sid = device.getSid(); - device.type = device.getType(); - device.data = { - voltage: device.getBatteryVoltage(), - batteryLevel: device.getBatteryPercentage() - }; - switch (device.type) { - case 'magnet': - device.data.status = device.isOpen() ? 'open' : 'close'; - break; - case 'switch': - device.on('click', () => { - // Saaad - }); - break; - case 'motion': - break; - case 'sensor': - device.data.temperature = device.getTemperature(); - device.data.humidity = device.getHumidity(); - device.data.pressure = device.getPressure(); - break; - case 'leak': - break; - case 'cube': - break; - }; - - (this).send({ - payload: device - }); - }); - }*/ } RED.nodes.registerType(`${Constants.NODES_PREFIX}-gateway in`, GatewayIn); diff --git a/src/nodes/gateway/GatewayOut.ts b/src/nodes/gateway/GatewayOut.ts index 85ef5f8..f71a791 100644 --- a/src/nodes/gateway/GatewayOut.ts +++ b/src/nodes/gateway/GatewayOut.ts @@ -1,44 +1,19 @@ -import { Red, NodeProperties } from "node-red"; -import { Constants } from "../constants"; -import {Gateway} from "../../devices/Gateway"; +import {Red, NodeProperties} from "node-red"; +import {Constants} from "../constants"; -export interface IGatewayOutNode extends Node { - gatewayConf:any; - gateway: Gateway; -} - -export default (RED:Red) => { +export default (RED: Red) => { class GatewayOut { - protected gatewayConf: any; - constructor(props: NodeProperties) { RED.nodes.createNode( this, props); - this.gatewayConf = RED.nodes.getNode(( props).gateway); - - (this).status({fill: "red", shape: "ring", text: "offline"}); - - if (this.gatewayConf.gateway) { - (this).status({fill: "blue", shape: "dot", text: "online"}); - } - - this.gatewayConf.on('gateway-online', () => { - (this).status({fill: "blue", shape: "dot", text: "online"}); - }); - - this.gatewayConf.on('gateway-offline', () => { - (this).status({fill: "red", shape: "ring", text: "offline"}); - }); + this.setMessageListener(); } protected setMessageListener() { - /*( this).on("input", (msg) => { - if (msg.hasOwnProperty("payload") && this.gateway) { - if(msg.payload.cmd === "write" && !msg.payload.data.key && this.gateway && this.gateway.sid && this.gateway._key) { - msg.payload.data.key = this.gateway._key; - } - this.gateway._sendUnicast(JSON.stringify(msg.payload)); + ( this).on("input", (msg) => { + if (msg.hasOwnProperty("payload") && msg.hasOwnProperty("gateway")) { + msg.gateway.gateway.send(msg); } - });*/ + }); } } diff --git a/src/utils/Color.ts b/src/utils/Color.ts new file mode 100644 index 0000000..72ec031 --- /dev/null +++ b/src/utils/Color.ts @@ -0,0 +1,25 @@ +export class Color { + static toValue(red, green, blue, brightness) { + return (brightness !== undefined ? 256 * 256 * 256 * brightness : 0) + (256 * 256 * red) + (256 * green) + blue; + } + + static fromValue(rgb) { + var blue = rgb % 256; + rgb = Math.max(rgb - blue, 0); + + var green = rgb % (256 * 256); + rgb = Math.max(rgb - green, 0); + green /= 256; + + var red = rgb % (256 * 256 * 256); + rgb = Math.max(rgb - red, 0); + red /= 256 * 256; + + var brightness = rgb / (256 * 256 * 256); + + return { + brightness: brightness, + color: {red: red, green: green, blue: blue} + }; + } +} \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..1531494 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1 @@ +export * from './Color'; \ No newline at end of file