mirror of
https://github.com/bemble/node-red-contrib-mi-devices.git
synced 2026-03-12 14:14:37 +01:00
feat(yeelight): handle yeelights
This commit is contained in:
@@ -1,104 +0,0 @@
|
||||
<!-- The "on" Node -->
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mi-devices-actions on',{
|
||||
category: 'xiaomi actions',
|
||||
color: '#64C4CD',
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
paletteLabel: "on",
|
||||
icon: "mi-on.png",
|
||||
label: function() {
|
||||
return this.name||"power on";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="mi-devices-actions on">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mi-devices-actions on">
|
||||
<p>
|
||||
Turn input device to on.
|
||||
</p>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Message to connect to a gateway/yeelight out node.</li>
|
||||
</ol>
|
||||
</script>
|
||||
|
||||
|
||||
<!-- The "off" Node -->
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mi-devices-actions off',{
|
||||
category: 'xiaomi actions',
|
||||
color: '#64C4CD',
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
paletteLabel: "off",
|
||||
icon: "mi-off.png",
|
||||
label: function() {
|
||||
return this.name||"power off";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="mi-devices-actions off">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mi-devices-actions off">
|
||||
<p>
|
||||
Turn input device to off.
|
||||
</p>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Message to connect to a gateway/yeelight out node.</li>
|
||||
</ol>
|
||||
</script>
|
||||
|
||||
|
||||
<!-- The "toggle" Node -->
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mi-devices-actions toggle',{
|
||||
category: 'xiaomi actions',
|
||||
color: '#64C4CD',
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
paletteLabel: "toggle",
|
||||
icon: "mi-toggle.png",
|
||||
label: function() {
|
||||
return this.name||"toggle power";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/x-red" data-template-name="mi-devices-actions toggle">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mi-devices-actions toggle">
|
||||
<p>Toggle device.</p>
|
||||
|
||||
<h3>Outputs</h3>
|
||||
<ol class="node-ports">
|
||||
<li>Message to connect to a gateway/yeelight out node.</li>
|
||||
</ol>
|
||||
</script>
|
||||
@@ -1,57 +0,0 @@
|
||||
const miDevicesUtils = require('../src/utils');
|
||||
module.exports = (RED) => {
|
||||
/*********************************************
|
||||
Turn device on
|
||||
*********************************************/
|
||||
function XiaomiActionPowerOn(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
|
||||
this.on('input', (msg) => {
|
||||
if(msg.sid){
|
||||
msg.payload = {
|
||||
cmd: "write",
|
||||
data: { status: "on", sid: msg.sid }
|
||||
};
|
||||
}
|
||||
else {
|
||||
msg.payload = "on";
|
||||
}
|
||||
this.send(msg);
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("mi-devices-actions on", XiaomiActionPowerOn);
|
||||
|
||||
/*********************************************
|
||||
Turn device off
|
||||
*********************************************/
|
||||
function XiaomiActionPowerOff(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
|
||||
this.on('input', (msg) => {
|
||||
if(msg.sid){
|
||||
msg.payload = {
|
||||
cmd: "write",
|
||||
data: { status: "off", sid: msg.sid }
|
||||
};
|
||||
}
|
||||
else {
|
||||
msg.payload = "off";
|
||||
}
|
||||
this.send(msg);
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("mi-devices-actions off", XiaomiActionPowerOff);
|
||||
|
||||
/*********************************************
|
||||
Toggle device
|
||||
*********************************************/
|
||||
function XiaomiActionToggle(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
|
||||
this.on('input', (msg) => {
|
||||
msg.payload = "toggle";
|
||||
this.send(msg);
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("mi-devices-actions toggle", XiaomiActionToggle);
|
||||
}
|
||||
@@ -46,8 +46,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"cryptojs": "^2.5.3",
|
||||
"lumi-aqara": "^1.4.0",
|
||||
"miio": "^0.15.2",
|
||||
"miio": "^0.15.4",
|
||||
"yeelight-wifi": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -4,7 +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";
|
||||
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]);
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as events from 'events';
|
||||
import * as dgram from "dgram";
|
||||
import {Gateway} from "./Gateway";
|
||||
import {Gateway} from "./";
|
||||
import Timer = NodeJS.Timer;
|
||||
import {GatewayMessage} from "./GatewayMessage";
|
||||
|
||||
@@ -92,36 +92,6 @@ export class GatewayServer extends events.EventEmitter {
|
||||
}
|
||||
|
||||
gatewaySid && this._gateways[gatewaySid] && this._gateways[gatewaySid].handleMessage(msg);
|
||||
|
||||
/*if(remote.address == this.addr) {
|
||||
var msg = message.toString('utf8');
|
||||
var jsonMsg = JSON.parse(msg);
|
||||
if(jsonMsg.data) {
|
||||
jsonMsg.data = JSON.parse(jsonMsg.data) || jsonMsg.data;
|
||||
if(jsonMsg.data.voltage) {
|
||||
jsonMsg.data.batteryLevel = miDevicesUtils.computeBatteryLevel(jsonMsg.data.voltage);
|
||||
}
|
||||
}
|
||||
msg = { payload: jsonMsg };
|
||||
if(this.gateway && jsonMsg.data.ip && jsonMsg.data.ip === this.gateway.ip) {
|
||||
if(jsonMsg.token) {
|
||||
this.gateway.lastToken = jsonMsg.token;
|
||||
if(!this.gateway.sid) {
|
||||
this.gateway.sid = jsonMsg.sid;
|
||||
}
|
||||
}
|
||||
RED.nodes.eachNode((tmpNode) => {
|
||||
if(tmpNode.type.indexOf("xiaomi-gateway") === 0 && tmpNode.gateway == this.gatewayNodeId) {
|
||||
let tmpNodeInst = RED.nodes.getNode(tmpNode.id);
|
||||
if(tmpNode.type === "xiaomi-gateway out" && !this.gateway.lastToken) {
|
||||
tmpNodeInst.status({fill:"yellow", shape:"ring", text: "waiting input"});
|
||||
}
|
||||
tmpNodeInst.status({fill:"blue", shape:"dot", text: "online"});
|
||||
}
|
||||
});
|
||||
}
|
||||
this.send(msg);
|
||||
}*/
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './';
|
||||
export * from './Gateway';
|
||||
export * from './GatewayMessage';
|
||||
export * from './GatewayServer';
|
||||
47
src/devices/yeelight/YeelightServer.ts
Normal file
47
src/devices/yeelight/YeelightServer.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import * as events from 'events';
|
||||
import * as YeelightSearch from 'yeelight-wifi';
|
||||
|
||||
export class YeelightServer extends events.EventEmitter {
|
||||
private static instance: YeelightServer;
|
||||
|
||||
private _bulbs: { [sid: string]: any } = {};
|
||||
private _bulbsJson: { [sid: string]: any } = {};
|
||||
|
||||
static getInstance() {
|
||||
if (!this.instance) {
|
||||
this.instance = new YeelightServer();
|
||||
}
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
get bulbs(): { [sid: string]: any } {
|
||||
return this._bulbsJson;
|
||||
}
|
||||
|
||||
getBulb(sid) {
|
||||
return this._bulbs[sid];
|
||||
}
|
||||
|
||||
discover() {
|
||||
new Promise(() => {
|
||||
(new YeelightSearch()).on('found', (bulb: any) => {
|
||||
bulb.sid = parseInt(bulb.id);
|
||||
if (!this._bulbs[bulb.sid]) {
|
||||
this._bulbs[bulb.sid] = bulb;
|
||||
this._bulbsJson[bulb.sid] = YeelightServer.bulbToJSON(bulb);
|
||||
this.emit("yeelight-online", bulb.sid);
|
||||
}
|
||||
});
|
||||
});
|
||||
// TODO: disconected ?
|
||||
}
|
||||
|
||||
static bulbToJSON(bulb) {
|
||||
return {
|
||||
sid: bulb.sid,
|
||||
ip: bulb.hostname,
|
||||
name: bulb.name,
|
||||
model: bulb.model
|
||||
};
|
||||
}
|
||||
}
|
||||
0
src/devices/yeelight/index.ts
Normal file
0
src/devices/yeelight/index.ts
Normal file
@@ -15,13 +15,11 @@ export default (RED: Red) => {
|
||||
|
||||
protected setListeners() {
|
||||
(<any> this).on('input', (msg) => {
|
||||
if (msg.sid) {
|
||||
msg.payload = {
|
||||
action: "setLight",
|
||||
color: msg.color || this.color,
|
||||
brightness: msg.brightness || this.brightness
|
||||
};
|
||||
}
|
||||
msg.payload = {
|
||||
action: "setLight",
|
||||
color: msg.color || this.color,
|
||||
brightness: msg.brightness || this.brightness
|
||||
};
|
||||
(<any> this).send(msg);
|
||||
});
|
||||
}
|
||||
|
||||
20
src/nodes/actions/ToggleAction.ts
Normal file
20
src/nodes/actions/ToggleAction.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {Red, NodeProperties} from "node-red";
|
||||
import {Constants} from "../constants";
|
||||
|
||||
export default (RED: Red, action: string) => {
|
||||
class ToggleAction {
|
||||
constructor(props: NodeProperties) {
|
||||
RED.nodes.createNode(<any> this, props);
|
||||
(<any> this).setListeners();
|
||||
}
|
||||
|
||||
protected setListeners() {
|
||||
(<any> this).on('input', (msg) => {
|
||||
msg.payload = { action };
|
||||
(<any> this).send(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType(`${Constants.NODES_PREFIX}-actions ${action}`, <any> ToggleAction);
|
||||
};
|
||||
@@ -32,4 +32,28 @@
|
||||
|
||||
<%- include('./Light', {}) %>
|
||||
<%- include('./GatewayPlaySound', {}) %>
|
||||
<%- include('./GatewayStopSound', {}) %>
|
||||
<%- include('./GatewayStopSound', {}) %>
|
||||
|
||||
<%# ---------------------------------- turn_on ---------------------------------- %>
|
||||
<%- include('./Action', {
|
||||
type: "turn_on",
|
||||
label: "turn on",
|
||||
icon: "mi-on",
|
||||
docTitle: "Turn device on."
|
||||
}) %>
|
||||
|
||||
<%# ---------------------------------- double_click ---------------------------------- %>
|
||||
<%- include('./Action', {
|
||||
type: "turn_off",
|
||||
label: "turn off",
|
||||
icon: "mi-off",
|
||||
docTitle: "Turn device off."
|
||||
}) %>
|
||||
|
||||
<%# ---------------------------------- double_click ---------------------------------- %>
|
||||
<%- include('./Action', {
|
||||
type: "toggle",
|
||||
label: "toggle",
|
||||
icon: "mi-toggle",
|
||||
docTitle: "Toggle device."
|
||||
}) %>
|
||||
@@ -5,6 +5,7 @@ import {default as WriteAction} from './WriteAction';
|
||||
import {default as Light} from './Light';
|
||||
import {default as GatewayPlaySound} from './GatewayPlaySound';
|
||||
import {default as GatewayStopSound} from './GatewayStopSound';
|
||||
import {default as ToggleAction} from './ToggleAction';
|
||||
|
||||
export = (RED: Red) => {
|
||||
["read", "get_id_list"].forEach((action) => {
|
||||
@@ -17,4 +18,7 @@ export = (RED: Red) => {
|
||||
Light(RED);
|
||||
GatewayPlaySound(RED);
|
||||
GatewayStopSound(RED);
|
||||
["turn_on", "turn_off", "toggle"].forEach(action => {
|
||||
ToggleAction(RED, action);
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Red, NodeProperties } from "node-red";
|
||||
import * as LumiAqara from 'lumi-aqara';
|
||||
import { Red } from "node-red";
|
||||
|
||||
import {default as All} from "./All";
|
||||
import {default as Plug} from "./Plug";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Red, Node, NodeProperties } from "node-red";
|
||||
import { LumiAqara } from "../../../typings/index";
|
||||
import { Constants } from "../constants";
|
||||
|
||||
export interface IGatewayNode extends Node {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {Red, Node, NodeProperties} from "node-red";
|
||||
import {Constants} from "../constants";
|
||||
import {GatewayServer} from "../../devices/GatewayServer";
|
||||
import {Gateway} from "../../devices/Gateway";
|
||||
import {GatewaySubdevice} from "../../devices/GatewaySubdevice";
|
||||
import {GatewayServer} from "../../devices/gateway/GatewayServer";
|
||||
import {Gateway} from "../../devices/gateway/Gateway";
|
||||
import {GatewaySubdevice} from "../../devices/gateway/GatewaySubdevice";
|
||||
import {isString} from "util";
|
||||
|
||||
export interface IGatewayConfiguratorNode extends Node {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Red, Node, NodeProperties} from 'node-red';
|
||||
import {Constants} from '../constants';
|
||||
import {Gateway} from "../../devices/Gateway";
|
||||
import {Gateway} from "../../devices/gateway/Gateway";
|
||||
|
||||
export interface IGatewayInNode extends Node {
|
||||
gatewayConf: any;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Red, NodeProperties} from "node-red";
|
||||
import {Constants} from "../constants";
|
||||
import {GatewayServer} from "../../devices/GatewayServer";
|
||||
import {GatewayServer} from "../../devices/gateway/GatewayServer";
|
||||
|
||||
export default (RED: Red) => {
|
||||
class GatewayOut {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Red, NodeProperties } from "node-red";
|
||||
import * as LumiAqara from 'lumi-aqara';
|
||||
import { Red } from "node-red";
|
||||
|
||||
import { GatewayServer } from "../../devices/GatewayServer";
|
||||
import { GatewayServer } from "../../devices/gateway/GatewayServer";
|
||||
import {default as GatewayConfigurator} from "./GatewayConfigurator";
|
||||
import {default as Gateway} from "./Gateway";
|
||||
import {default as GatewayIn} from "./GatewayIn";
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Red } from "node-red";
|
||||
|
||||
import * as YeelightSearch from 'yeelight-wifi';
|
||||
import { Constants } from "../constants";
|
||||
import { IYeelightConfiguratorNode } from "./YeelightConfigurator";
|
||||
|
||||
export class Searcher {
|
||||
static _bulbs:any[] = [];
|
||||
|
||||
static discover(RED:Red) {
|
||||
new Promise(() => {
|
||||
(new YeelightSearch()).on('found', (bulb:any) => {
|
||||
this._bulbs.push({
|
||||
name: bulb.name,
|
||||
model: bulb.model,
|
||||
sid: parseInt(bulb.id),
|
||||
ip: bulb.hostname
|
||||
});
|
||||
RED.nodes.eachNode((tmpNode) => {
|
||||
if(tmpNode.type.indexOf(`${Constants.NODES_PREFIX}-yeelight configurator`) === 0) {
|
||||
let tmpNodeInst = <IYeelightConfiguratorNode> RED.nodes.getNode(tmpNode.id);
|
||||
if(tmpNodeInst.ip == bulb.hostname || tmpNodeInst.sid == parseInt(bulb.id)) {
|
||||
tmpNodeInst.bulb = bulb;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static get bulbs() {
|
||||
return this._bulbs;
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,22 @@
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value: ""},
|
||||
ip: {value: ""},
|
||||
sid: {value: ""}
|
||||
},
|
||||
label: function () {
|
||||
return this.name || "yeelight conf";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
RED.settings.miDevicesYeelightConfiguratorDiscoveredBulbs.forEach(function(bulb, index) {
|
||||
var foundBulbs = RED.settings.miDevicesYeelightConfiguratorDiscoveredBulbs;
|
||||
Object.keys(foundBulbs).forEach(function(sid) {
|
||||
var bulb = foundBulbs[sid];
|
||||
$('#discovered-bulbs').append('<option value="' + bulb.sid + '">' + (bulb.name || bulb.sid) + ' - ' + bulb.model + ' - ' + bulb.ip + '</option>');
|
||||
});
|
||||
var node = this;
|
||||
$('#discovered-bulbs').on('change', function() {
|
||||
var sid = $('#discovered-bulbs').val();
|
||||
var bulb = sid && RED.settings.miDevicesYeelightConfiguratorDiscoveredBulbs.filter(function(e) { return e.sid == sid })[0];
|
||||
var bulb = foundBulbs[sid];
|
||||
$("#node-config-input-name").val(bulb && bulb.name);
|
||||
$("#node-config-input-sid").val(bulb && bulb.sid);
|
||||
$("#node-config-input-ip").val("");
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -37,15 +36,10 @@
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-ip"><i class="fa fa-compass"></i> IP</label>
|
||||
<input type="text" id="node-config-input-ip" placeholder="IP">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-sid"><i class="fa fa-barcode"></i> SID</label>
|
||||
<input type="text" id="node-config-input-sid" placeholder="sid">
|
||||
</div>
|
||||
<p>Note: use <code>ip</code> or <code>sid</code> - <code>sid</code> is better.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="<%= NODES_PREFIX %>-yeelight configurator">
|
||||
|
||||
@@ -1,31 +1,49 @@
|
||||
import { Red, Node, NodeProperties, NodeStatus, ClearNodeStatus } from "node-red";
|
||||
import { Constants } from "../constants";
|
||||
import { Searcher } from "./Searcher";
|
||||
import {Red, Node, NodeProperties, NodeStatus, ClearNodeStatus} from "node-red";
|
||||
import {Constants} from "../constants";
|
||||
import {YeelightServer} from "../../devices/yeelight/YeelightServer";
|
||||
|
||||
export interface IYeelightConfiguratorNode extends Node {
|
||||
ip:string;
|
||||
sid:number;
|
||||
bulb:any;
|
||||
ip: string;
|
||||
sid: number;
|
||||
bulb: any;
|
||||
|
||||
on(event: "bulbFound", listener: () => void): any;
|
||||
on(event: "bulb-online", listener: () => void): any;
|
||||
on(event: "bulb-offline", listener: () => void): any;
|
||||
}
|
||||
|
||||
export default (RED:Red) => {
|
||||
export default (RED: Red) => {
|
||||
class YeelightConfigurator {
|
||||
ip:string;
|
||||
sid:number;
|
||||
_bulb:any;
|
||||
ip: string;
|
||||
sid: number;
|
||||
_bulb: any;
|
||||
|
||||
constructor(props: NodeProperties) {
|
||||
RED.nodes.createNode(<any> this, props);
|
||||
let {ip, sid} = <any> props;
|
||||
this.sid = sid;
|
||||
this.ip = ip;
|
||||
let {sid} = <any> props;
|
||||
this.sid = parseInt(sid);
|
||||
|
||||
if (this.sid) {
|
||||
this.setBulb();
|
||||
}
|
||||
let server = YeelightServer.getInstance();
|
||||
|
||||
server.on('yeelight-online', (sid) => {
|
||||
if (sid === this.sid) {
|
||||
this.setBulb();
|
||||
(<any> this).emit('bulb-online');
|
||||
}
|
||||
});
|
||||
|
||||
server.on('yeelight-offline', (sid) => {
|
||||
if (sid === this.sid) {
|
||||
this._bulb = null;
|
||||
(<any> this).emit('bulb-offline');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set bulb(bulb) {
|
||||
this._bulb = bulb;
|
||||
(<any> this).emit('bulbFound');
|
||||
protected setBulb() {
|
||||
this._bulb = YeelightServer.getInstance().getBulb(this.sid);
|
||||
}
|
||||
|
||||
get bulb() {
|
||||
@@ -35,7 +53,10 @@ export default (RED:Red) => {
|
||||
|
||||
RED.nodes.registerType(`${Constants.NODES_PREFIX}-yeelight configurator`, <any> YeelightConfigurator, {
|
||||
settings: {
|
||||
miDevicesYeelightConfiguratorDiscoveredBulbs: { value: Searcher.bulbs, exportable: true }
|
||||
miDevicesYeelightConfiguratorDiscoveredBulbs: {
|
||||
value: YeelightServer.getInstance().bulbs,
|
||||
exportable: true
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,50 +1,79 @@
|
||||
import { Red, Node, NodeProperties, NodeStatus, ClearNodeStatus } from "node-red";
|
||||
import { Constants } from "../constants";
|
||||
import { IYeelightConfiguratorNode } from "./YeelightConfigurator";
|
||||
import {Red, Node, NodeProperties, NodeStatus, ClearNodeStatus} from "node-red";
|
||||
import {Constants} from "../constants";
|
||||
import {IYeelightConfiguratorNode} from "./YeelightConfigurator";
|
||||
|
||||
export interface IYeelightOutNode {
|
||||
yeelightConfNode:IYeelightConfiguratorNode;
|
||||
yeelightConf: IYeelightConfiguratorNode;
|
||||
}
|
||||
|
||||
export default (RED:Red) => {
|
||||
export default (RED: Red) => {
|
||||
class YeelightOut implements IYeelightOutNode {
|
||||
yeelightConfNode:IYeelightConfiguratorNode;
|
||||
yeelightConf: IYeelightConfiguratorNode;
|
||||
|
||||
constructor(props: NodeProperties) {
|
||||
RED.nodes.createNode(<any> this, props);
|
||||
this.yeelightConfNode = <any> RED.nodes.getNode((<any> props).yeelight);
|
||||
this.yeelightConf = <any> RED.nodes.getNode((<any> props).yeelight);
|
||||
|
||||
(<any> this).status({fill: "red", shape: "ring", text: "offline"});
|
||||
this.yeelightConfNode && this.yeelightConfNode.on('bulbFound', () => {
|
||||
(<any>this).status({fill:"blue", shape:"dot", text: "online"});
|
||||
});
|
||||
|
||||
(<any>this).status({fill: "red", shape: "ring", text: "offline"});
|
||||
|
||||
if (this.yeelightConf.bulb) {
|
||||
this.yeelightOnline();
|
||||
}
|
||||
|
||||
this.yeelightConf.on('bulb-online', () => this.yeelightOnline());
|
||||
this.yeelightConf.on('bulb-offline', () => this.yeelightOffline());
|
||||
|
||||
this.setListener();
|
||||
}
|
||||
|
||||
protected yeelightOnline() {
|
||||
(<any>this).status({fill: "blue", shape: "dot", text: "online"});
|
||||
}
|
||||
|
||||
protected yeelightOffline() {
|
||||
(<any>this).status({fill: "red", shape: "ring", text: "offline"});
|
||||
}
|
||||
|
||||
protected setListener() {
|
||||
(<any> this).on('input', (msg) => {
|
||||
if (this.yeelightConfNode.bulb) {
|
||||
if(msg.payload === "on") {
|
||||
this.yeelightConfNode.bulb.turnOn();
|
||||
}
|
||||
else if(msg.payload === "off") {
|
||||
this.yeelightConfNode.bulb.turnOff();
|
||||
}
|
||||
else if(msg.payload === "toggle") {
|
||||
this.yeelightConfNode.bulb.toggle();
|
||||
}
|
||||
|
||||
if(msg.payload.color !== undefined) {
|
||||
// TODO: revoir la couleur
|
||||
this.yeelightConfNode.bulb.setRGB(msg.payload.color);
|
||||
}
|
||||
if(msg.payload.brightness !== undefined) {
|
||||
this.yeelightConfNode.bulb.setBrightness(msg.payload.brightness);
|
||||
(<any> this).on("input", (msg) => {
|
||||
let bulb = this.yeelightConf.bulb;
|
||||
if (msg.hasOwnProperty("payload") && bulb) {
|
||||
switch (msg.payload.action) {
|
||||
case 'turn_on':
|
||||
bulb.turnOn();
|
||||
break;
|
||||
case 'turn_off':
|
||||
bulb.turnOff();
|
||||
break;
|
||||
case 'toggle':
|
||||
bulb.toggle();
|
||||
break;
|
||||
case 'setLight':
|
||||
if (msg.payload.color !== undefined) {
|
||||
let rgb = msg.payload.color.blue | (msg.payload.color.green << 8) | (msg.payload.color.red << 16);
|
||||
let hex = '#' + (0x1000000 + rgb).toString(16).slice(1);
|
||||
bulb.setRGB(hex);
|
||||
}
|
||||
(msg.payload.brightness !== undefined) && bulb.setBrightness(Math.max(1, msg.payload.brightness));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
/*(<any> this).on('input', (msg) => {
|
||||
if (this.yeelightConf.bulb) {
|
||||
|
||||
|
||||
if(msg.payload.color !== undefined) {
|
||||
// TODO: revoir la couleur
|
||||
this.yeelightConf.bulb.setRGB(msg.payload.color);
|
||||
}
|
||||
if(msg.payload.brightness !== undefined) {
|
||||
this.yeelightConf.bulb.setBrightness(msg.payload.brightness);
|
||||
}
|
||||
}
|
||||
});*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Red, NodeProperties } from "node-red";
|
||||
import * as YeelightSearch from 'yeelight-wifi';
|
||||
import { Red } from "node-red";
|
||||
|
||||
import { Searcher } from "./Searcher";
|
||||
import { YeelightServer } from "../../devices/yeelight/YeelightServer";
|
||||
import {default as YeelightConfigurator} from "./YeelightConfigurator";
|
||||
import {default as YeelightOut} from "./YeelightOut";
|
||||
|
||||
export = (RED:Red) => {
|
||||
Searcher.discover(RED);
|
||||
YeelightServer.getInstance().discover();
|
||||
|
||||
YeelightConfigurator(RED);
|
||||
YeelightOut(RED);
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"inlineSourceMap": false,
|
||||
"outDir": "dist/",
|
||||
"rootDir": "./src",
|
||||
"moduleResolution": "node"
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
|
||||
Reference in New Issue
Block a user