fix(gateay): fix all nodes and output node
also start setColor of the gateway
This commit is contained in:
@@ -4,6 +4,7 @@ import * as crypto from 'crypto';
|
|||||||
import {GatewayServer} from "./GatewayServer";
|
import {GatewayServer} from "./GatewayServer";
|
||||||
import {GatewayMessage, GatewaySubdevice, Magnet, Motion, Switch, Weather} from "./";
|
import {GatewayMessage, GatewaySubdevice, Magnet, Motion, Switch, Weather} from "./";
|
||||||
import * as MessageData from "./GatewayMessageData";
|
import * as MessageData from "./GatewayMessageData";
|
||||||
|
import {Color} from "../utils/Color";
|
||||||
|
|
||||||
export class Gateway extends events.EventEmitter {
|
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]);
|
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 {
|
get key(): string {
|
||||||
|
if (!this.lastToken || !this.password) return null;
|
||||||
|
|
||||||
var cipher = crypto.createCipheriv('aes-128-cbc', this.password, Gateway.iv);
|
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');
|
cipher.final('hex');
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
@@ -27,12 +30,13 @@ export class Gateway extends events.EventEmitter {
|
|||||||
if (msg.data) {
|
if (msg.data) {
|
||||||
if (msg.model === "gateway" && msg.sid === this.sid && msg.token) {
|
if (msg.model === "gateway" && msg.sid === this.sid && msg.token) {
|
||||||
this.lastToken = msg.token;
|
this.lastToken = msg.token;
|
||||||
|
this.setLight(100, {red: 255, green: 0, blue: 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.isGetIdListAck()) {
|
if (msg.isGetIdListAck()) {
|
||||||
(<MessageData.GatewayMessageGetIdListData> msg.data).forEach((sid) => {
|
(<MessageData.GatewayMessageGetIdListData> 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];
|
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() {
|
playSound() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRead(message: any) {
|
send(message: any) {
|
||||||
message.sid = message.sid || this.sid;
|
let msg = Object.assign({}, message.payload || message);
|
||||||
GatewayServer.getInstance().sendToGateway(this.sid, 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 } {
|
get subdevices(): { [sid: string]: GatewaySubdevice } {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Red, NodeProperties } from "node-red";
|
import {Red, NodeProperties} from "node-red";
|
||||||
import { Constants } from "../constants";
|
import {Constants} from "../constants";
|
||||||
|
|
||||||
export default (RED:Red) => {
|
export default (RED: Red) => {
|
||||||
class All {
|
class All {
|
||||||
protected gateway: any;
|
protected gateway: any;
|
||||||
protected onlyModels: string[];
|
protected onlyModels: string[];
|
||||||
@@ -15,40 +15,50 @@ export default (RED:Red) => {
|
|||||||
return cleanOnlyModels;
|
return cleanOnlyModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props:NodeProperties) {
|
constructor(props: NodeProperties) {
|
||||||
RED.nodes.createNode(<any> this, props);
|
RED.nodes.createNode(<any> this, props);
|
||||||
this.gateway = RED.nodes.getNode((<any> props).gateway);
|
this.gateway = RED.nodes.getNode((<any> props).gateway);
|
||||||
this.onlyModels = All.getOnlyModelsValue((<any> props).onlyModels || []);
|
this.onlyModels = All.getOnlyModelsValue((<any> props).onlyModels || []);
|
||||||
this.excludedSids = (<any> props).excludedSids;
|
this.excludedSids = (<any> props).excludedSids;
|
||||||
|
|
||||||
|
this.setMessageListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setMessageListener() {
|
protected setMessageListener() {
|
||||||
(<any> this).on('input', (msg) => {
|
(<any> this).on('input', (msg) => {
|
||||||
if (this.gateway) {
|
if (this.gateway) {
|
||||||
// Filter input
|
// Filter input
|
||||||
if(msg.payload && msg.payload.model && msg.payload.sid) {
|
if (msg.payload && msg.payload.model && msg.payload.sid) {
|
||||||
if(!this.isDeviceValid(msg.payload)) {
|
if (!this.isDeviceValid(msg.payload)) {
|
||||||
msg = null;
|
msg = null;
|
||||||
}
|
}
|
||||||
|
(<any> this).send(msg);
|
||||||
}
|
}
|
||||||
// Prepare for request
|
// Prepare for request
|
||||||
else {
|
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;
|
||||||
|
(<any> this).send(curMsg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
(<any> this).send(msg);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isDeviceValid(device) {
|
isDeviceValid(sid) {
|
||||||
if((!this.onlyModels || this.onlyModels.length == 0) && (!this.excludedSids || this.excludedSids.length == 0)) {
|
if ((!this.onlyModels || this.onlyModels.length == 0) && (!this.excludedSids || this.excludedSids.length == 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
let device = this.gateway.deviceList[sid];
|
||||||
// Is excluded
|
// 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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,14 @@ export default (RED:Red, type:string) => {
|
|||||||
this.sid = (<any> props).sid;
|
this.sid = (<any> props).sid;
|
||||||
|
|
||||||
(<any> this).status({fill:"grey", shape:"ring", text:"battery - na"});
|
(<any> this).status({fill:"grey", shape:"ring", text:"battery - na"});
|
||||||
|
this.setMessageListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setMessageListener() {
|
||||||
if (this.gateway) {
|
if (this.gateway) {
|
||||||
(<any> this).on('input', (msg) => {
|
(<any> this).on('input', (msg) => {
|
||||||
let payload = msg.payload;
|
let payload = msg.payload;
|
||||||
|
|
||||||
// Input from gateway
|
// Input from gateway
|
||||||
if (payload.sid) {
|
if (payload.sid) {
|
||||||
if (payload.sid == this.sid) {
|
if (payload.sid == this.sid) {
|
||||||
@@ -25,7 +28,7 @@ export default (RED:Red, type:string) => {
|
|||||||
fill: "green", shape: "dot",
|
fill: "green", shape: "dot",
|
||||||
text: "battery - " + batteryLevel + "%"
|
text: "battery - " + batteryLevel + "%"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (batteryLevel < 10) {
|
if (batteryLevel < 10) {
|
||||||
status.fill = "red";
|
status.fill = "red";
|
||||||
} else if (batteryLevel < 45) {
|
} else if (batteryLevel < 45) {
|
||||||
|
|||||||
@@ -16,17 +16,24 @@ export interface IGatewayConfiguratorNode extends Node {
|
|||||||
on(event: "subdevice-update", listener: (subdevice: GatewaySubdevice) => void): any;
|
on(event: "subdevice-update", listener: (subdevice: GatewaySubdevice) => void): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GatewayConfiguratorSubDevice {
|
||||||
|
name: string;
|
||||||
|
internalModel: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default (RED: Red) => {
|
export default (RED: Red) => {
|
||||||
class GatewayConfigurator {
|
class GatewayConfigurator {
|
||||||
sid: string;
|
sid: string;
|
||||||
key: string;
|
key: string;
|
||||||
|
deviceList: { [sid: string]: GatewayConfiguratorSubDevice };
|
||||||
_gateway: Gateway;
|
_gateway: Gateway;
|
||||||
|
|
||||||
constructor(props: NodeProperties) {
|
constructor(props: NodeProperties) {
|
||||||
RED.nodes.createNode(<any> this, props);
|
RED.nodes.createNode(<any> this, props);
|
||||||
let {sid, key} = <any> props;
|
let {sid, key, deviceList} = <any> props;
|
||||||
this.sid = sid;
|
this.sid = sid;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
this.deviceList = deviceList;
|
||||||
let server = GatewayServer.getInstance();
|
let server = GatewayServer.getInstance();
|
||||||
if (this.sid) {
|
if (this.sid) {
|
||||||
this.setGateway();
|
this.setGateway();
|
||||||
|
|||||||
@@ -36,51 +36,6 @@ export default (RED: Red) => {
|
|||||||
protected gatewayOffline() {
|
protected gatewayOffline() {
|
||||||
(<any>this).status({fill: "red", shape: "ring", text: "offline"});
|
(<any>this).status({fill: "red", shape: "ring", text: "offline"});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*setGateway(gateway:LumiAqara.Gateway) {
|
|
||||||
this.gateway = gateway;
|
|
||||||
this.gateway.setPassword(this.gatewayConf.password);
|
|
||||||
(<any>this).status({fill:"blue", shape:"dot", text: "online"});
|
|
||||||
|
|
||||||
this.gateway.on('offline', () => {
|
|
||||||
this.gateway = null;
|
|
||||||
(<any>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;
|
|
||||||
};
|
|
||||||
|
|
||||||
(<any>this).send({
|
|
||||||
payload: device
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.nodes.registerType(`${Constants.NODES_PREFIX}-gateway in`, <any> GatewayIn);
|
RED.nodes.registerType(`${Constants.NODES_PREFIX}-gateway in`, <any> GatewayIn);
|
||||||
|
|||||||
@@ -1,44 +1,19 @@
|
|||||||
import { Red, NodeProperties } from "node-red";
|
import {Red, NodeProperties} from "node-red";
|
||||||
import { Constants } from "../constants";
|
import {Constants} from "../constants";
|
||||||
import {Gateway} from "../../devices/Gateway";
|
|
||||||
|
|
||||||
export interface IGatewayOutNode extends Node {
|
export default (RED: Red) => {
|
||||||
gatewayConf:any;
|
|
||||||
gateway: Gateway;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (RED:Red) => {
|
|
||||||
class GatewayOut {
|
class GatewayOut {
|
||||||
protected gatewayConf: any;
|
|
||||||
|
|
||||||
constructor(props: NodeProperties) {
|
constructor(props: NodeProperties) {
|
||||||
RED.nodes.createNode(<any> this, props);
|
RED.nodes.createNode(<any> this, props);
|
||||||
this.gatewayConf = RED.nodes.getNode((<any> props).gateway);
|
this.setMessageListener();
|
||||||
|
|
||||||
(<any>this).status({fill: "red", shape: "ring", text: "offline"});
|
|
||||||
|
|
||||||
if (this.gatewayConf.gateway) {
|
|
||||||
(<any>this).status({fill: "blue", shape: "dot", text: "online"});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.gatewayConf.on('gateway-online', () => {
|
|
||||||
(<any>this).status({fill: "blue", shape: "dot", text: "online"});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.gatewayConf.on('gateway-offline', () => {
|
|
||||||
(<any>this).status({fill: "red", shape: "ring", text: "offline"});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setMessageListener() {
|
protected setMessageListener() {
|
||||||
/*(<any> this).on("input", (msg) => {
|
(<any> this).on("input", (msg) => {
|
||||||
if (msg.hasOwnProperty("payload") && this.gateway) {
|
if (msg.hasOwnProperty("payload") && msg.hasOwnProperty("gateway")) {
|
||||||
if(msg.payload.cmd === "write" && !msg.payload.data.key && this.gateway && this.gateway.sid && this.gateway._key) {
|
msg.gateway.gateway.send(msg);
|
||||||
msg.payload.data.key = this.gateway._key;
|
|
||||||
}
|
|
||||||
this.gateway._sendUnicast(JSON.stringify(msg.payload));
|
|
||||||
}
|
}
|
||||||
});*/
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
src/utils/Color.ts
Normal file
25
src/utils/Color.ts
Normal file
@@ -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}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/utils/index.ts
Normal file
1
src/utils/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './Color';
|
||||||
Reference in New Issue
Block a user