From 3230d9a462dd3c99682fb2e815b0515e7758ee28 Mon Sep 17 00:00:00 2001 From: baskiers Date: Sat, 30 Jun 2018 10:23:38 +0200 Subject: [PATCH 1/4] feat: added support for model 'ceiling1' My lamp has the model id 'ceiling1'. I expect this ceiling light to be the same as ceiling lights with model 'ceiling' so I added code to default all 'ceilingX' lights to 'ceiling' when it is not a model that has a different implementation (like 'ceiling4') --- drivers/yeelights/driver.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/yeelights/driver.js b/drivers/yeelights/driver.js index 4303ba6..fb54875 100644 --- a/drivers/yeelights/driver.js +++ b/drivers/yeelights/driver.js @@ -8,7 +8,7 @@ const typeCapabilityMap = { 'color' : [ 'onoff', 'dim', 'light_hue', 'light_saturation', 'light_temperature', 'light_mode' ], 'stripe' : [ 'onoff', 'dim', 'light_hue', 'light_saturation', 'light_temperature', 'light_mode' ], 'bslamp' : [ 'onoff', 'dim', 'light_hue', 'light_saturation', 'light_temperature', 'light_mode' ], - 'ceiling' : [ 'onoff', 'dim', 'light_temperature', 'light_mode' ], + 'ceiling' : [ 'onoff', 'dim', 'light_temperature', 'light_mode', 'night_mode' ], 'ceiling4' : [ 'onoff', 'dim', 'light_hue', 'light_saturation', 'light_temperature', 'light_mode' ], 'desklamp' : [ 'onoff', 'dim', 'light_temperature', 'light_mode' ] } @@ -42,7 +42,11 @@ class YeelightDriver extends Homey.Driver { var name = Homey.__('yeelight_led_strip')+ ' (' + result[i].address + ')'; } else if (result[i].model == 'bslamp') { var name = Homey.__('yeelight_bedside_lamp')+ ' (' + result[i].address + ')'; - } else if (result[i].model == 'ceiling' || result[i].model == 'ceiling4') { + } else if (result[i].model.startsWith('ceiling')) { + if(result[i].model !== 'ceiling4') { + // Default the ceiling light to the default ceiling light. + result[i].model = 'ceiling'; + } var name = Homey.__('yeelight_ceiling_light')+ ' (' + result[i].address + ')'; } else if (result[i].model == 'desklamp') { var name = Homey.__('yeelight_desklamp')+ ' (' + result[i].address + ')'; From 749cd9e93170edc7e76b17ecf346d203dc6f9607 Mon Sep 17 00:00:00 2001 From: baskiers Date: Sat, 30 Jun 2018 10:26:06 +0200 Subject: [PATCH 2/4] feat: added night_mode capability and flow card Since the Yeelight ceiling light has a night mode using the 'mode' argument of the set_power command (see https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf) I added a flow card for 'ceiling' lights to switch between Night mode and CT mode. --- app.js | 6 ++++ app.json | 56 +++++++++++++++++++++++++++++++++++++ drivers/yeelights/device.js | 10 +++++++ 3 files changed, 72 insertions(+) diff --git a/app.js b/app.js index 9f0df37..6c3497a 100644 --- a/app.js +++ b/app.js @@ -53,6 +53,12 @@ class XiaomiMiioApp extends Homey.App { return Promise.resolve(customcommand); }) + new Homey.FlowCardAction('yeelightNightMode') + .register() + .registerRunListener((args, state) => { + return args.device.triggerCapabilityListener('night_mode', args.value === 'true'); + }) + // MI ROBOT: CONDITION AND ACTION FLOW CARDS new Homey.FlowCardAction('findVacuum') .register() diff --git a/app.json b/app.json index 41ddb2b..a26982a 100644 --- a/app.json +++ b/app.json @@ -38,6 +38,16 @@ "dependencies": { "net": "*" }, + "capabilities": { + "night_mode": { + "type": "boolean", + "title": { + "en": "Night Mode" + }, + "getable": true, + "setable": true + } + }, "drivers": [ { "id": "yeelights", @@ -1069,6 +1079,52 @@ } ] }, + { + "id": "yeelightNightMode", + "title": { + "en": "Toggle Night Mode", + "nl": "Schakel Nacht Modus" + }, + "hint": { + "en": "Use this card to switch the light between night mode and normal mode", + "nl": "Gebruik deze actie om de lamp tussen nacht modus en gewone modus te schakelen" + }, + "args": [ + { + "name": "value", + "type": "dropdown", + "placeholder": { + "en": "Finish action", + "nl": "Afrondactie" + }, + "values": [ + { + "id": "false", + "label": { + "en": "Normal Mode", + "nl": "Normale Modus" + } + }, + { + "id": "true", + "label": { + "en": "Night Mode", + "nl": "Nacht Modus" + } + } + ] + }, + { + "name": "device", + "type": "device", + "placeholder": { + "en": "Select Yeelight", + "nl": "Selecteer Yeelight" + }, + "filter": "driver_id=yeelights&capabilities=night_mode" + } + ] + }, { "id": "findVacuum", "title": { diff --git a/drivers/yeelights/device.js b/drivers/yeelights/device.js index 44ed449..2eb955a 100644 --- a/drivers/yeelights/device.js +++ b/drivers/yeelights/device.js @@ -13,6 +13,7 @@ class YeelightDevice extends Homey.Device { this.registerCapabilityListener('dim', this.onCapabilityDim.bind(this)); this.registerMultipleCapabilityListener(['light_hue', 'light_saturation'], this.onCapabilityHueSaturation.bind(this), 500); this.registerCapabilityListener('light_temperature', this.onCapabilityLightTemperature.bind(this)); + this.registerCapabilityListener('night_mode', this.onCapabilityNightMode.bind(this)); let id = this.getData().id; yeelights[id] = {}; @@ -41,6 +42,15 @@ class YeelightDevice extends Homey.Device { callback(null, value); } + onCapabilityNightMode(value, opts, callback) { + if (value) { + this.sendCommand(this.getData().id, '{"id": 1, "method": "set_power", "params":["on", "smooth", 500, 5]}'); + } else { + this.sendCommand(this.getData().id, '{"id": 1, "method": "set_power", "params":["on", "smooth", 500, 1]}'); + } + callback(null, value); + } + onCapabilityDim(value, opts, callback) { if(value == 0) { var brightness = 1; From ceee661b48157d188a669b8b4938cfb171c3ae60 Mon Sep 17 00:00:00 2001 From: baskiers Date: Sat, 30 Jun 2018 11:54:25 +0200 Subject: [PATCH 3/4] feat: added auto-toggle for night_mode capability. Added logic to automatically toggle nightmode when dimming the device to 100/0 percent twice in a row within 5 seconds. This is usefull when controlling the device from your mobile phone (using the new app) so you can toggle night_mode without executing a flow. --- drivers/yeelights/device.js | 49 +++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/drivers/yeelights/device.js b/drivers/yeelights/device.js index 44ed449..785113f 100644 --- a/drivers/yeelights/device.js +++ b/drivers/yeelights/device.js @@ -41,18 +41,57 @@ class YeelightDevice extends Homey.Device { callback(null, value); } - onCapabilityDim(value, opts, callback) { - if(value == 0) { - var brightness = 1; - } else { - var brightness = value * 100; + async onCapabilityDim(value, opts, callback) { + let brightness = value === 0 ? 1 : value * 100; + let overWriteDimVal; + + // Logic which will toggle between night_mode and normal_mode when brightness is set to 0 or 100 two times within 5 seconds + if(this.hasCapability('night_mode') && opts.duration === undefined) { + if (value === 0) { + if (this.dimMinTime + 5000 > Date.now()) { + const initialNightModeValue = this.getCapabilityValue('night_mode'); + await this.triggerCapabilityListener('night_mode', true); + // If we think we really toggled the night mode we will set the brightness of night mode to 100 + if(initialNightModeValue === false) { + value = 1; + overWriteDimVal = 1; + brightness = 100; + } + this.dimMinTime = 0; + }else { + this.dimMinTime = Date.now(); + } + }else if (value === 1){ + if (this.dimMaxTime + 5000 > Date.now()) { + const initialNightModeValue = this.getCapabilityValue('night_mode'); + await this.triggerCapabilityListener('night_mode', false); + // If we think we really toggled the night mode we will set the brightness of normal mode to 1 + if(initialNightModeValue === true) { + value = 0; + overWriteDimVal = 0; + brightness = 1; + } + this.dimMaxTime = 0; + }else { + this.dimMaxTime = Date.now(); + } + }else { + this.dimMinTime = 0; + this.dimMaxTime = 0; + } } + if(typeof opts.duration !== 'undefined') { this.sendCommand(this.getData().id, '{"id":1,"method":"set_bright","params":['+ brightness +', "smooth", '+ opts.duration +']}'); } else { this.sendCommand(this.getData().id, '{"id":1,"method":"set_bright","params":['+ brightness +', "smooth", 500]}'); } callback(null, value); + + // "hack" to fix dim bar behaviour in the homey UI + if(overWriteDimVal !== undefined) { + this.setCapabilityValue('dim', overWriteDimVal); + } } onCapabilityHueSaturation(valueObj, optsObj) { From cc2a2597efe58eb1a35cb1e09b6da7e473d46a14 Mon Sep 17 00:00:00 2001 From: baskiers Date: Sat, 30 Jun 2018 12:08:51 +0200 Subject: [PATCH 4/4] fix: added implicit night_mode toggle on light_temperature change For now I cannot get light_temperature to work on my ceiling light and the default light_temperature change will always toggle the lamp to the normal mode. Therefore I added a setCapabilityValue to onCapabilityLightTemperature. --- drivers/yeelights/device.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/yeelights/device.js b/drivers/yeelights/device.js index 2eb955a..f4eb915 100644 --- a/drivers/yeelights/device.js +++ b/drivers/yeelights/device.js @@ -97,6 +97,10 @@ class YeelightDevice extends Homey.Device { } this.sendCommand(this.getData().id, '{"id":1,"method":"set_ct_abx","params":['+ color_temp +', "smooth", 500]}'); callback(null, value); + + if(this.hasCapability('night_mode')){ + this.setCapabilityValue('night_mode', false); + } } // HELPER FUNCTIONS @@ -267,6 +271,7 @@ class YeelightDevice extends Homey.Device { /* send commands to devices using their socket connection */ sendCommand(id, command) { + console.log(command); if (yeelights[id].connected === false && yeelights[id].socket !== null) { yeelights[id].socket.emit('error', new Error('Connection to device broken')); } else if (yeelights[id].socket === null) {