From d23ba05dfed8763df57a1822c53b7f884cc257d8 Mon Sep 17 00:00:00 2001 From: ebaauw Date: Sun, 31 May 2020 12:58:56 +0200 Subject: [PATCH] Update HueLight.js - Add support for Hampton Bay fan modules, see https://github.com/dresden-elektronik/deconz-rest-plugin/issues/932; - Use `state.lift` and `state.tilt`for window covering devices; - Don't sound siren on warning devices on _Identify_. --- lib/HueLight.js | 149 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/lib/HueLight.js b/lib/HueLight.js index 51334ce8..9d1ebfa2 100644 --- a/lib/HueLight.js +++ b/lib/HueLight.js @@ -432,15 +432,15 @@ function HueLight (accessory, id, obj, type = 'light') { this.service.getCharacteristic(Characteristic.TargetPosition) .on('set', this.setPosition.bind(this)) .setProps({ minStep: 5 }) - this.checkPosition(this.obj.state.bri) + this.checkLift(this.obj.state.lift) this.service.getCharacteristic(Characteristic.HoldPosition) .on('set', this.setHoldPosition.bind(this)) .setValue(false) - if (this.config.sat) { + if (this.config.tilt) { this.service.getCharacteristic(Characteristic.TargetHorizontalTiltAngle) .on('set', this.setTilt.bind(this)) .setProps({ minStep: 5 }) - this.checkTilt(this.obj.state.sat) + this.checkTilt(this.obj.state.tilt) } } else if (!this.config.on) { // Warning device this.service = new Service.Outlet(this.name, this.subtype) @@ -567,6 +567,12 @@ function HueLight (accessory, id, obj, type = 'light') { this.service.getCharacteristic(my.Characteristics.Resource) .updateValue(this.resource) } + if (this.config.speed) { + this.fanService = new Service.Fan(this.name, this.subtype) + this.fanService.getCharacteristic(Characteristic.RotationSpeed) + .on('set', this.setSpeed.bind(this)) + this.checkSpeed(this.obj.state.speed) + } } // Store configuration to this.config. @@ -581,6 +587,7 @@ HueLight.prototype.setConfig = function () { bri: this.obj.state.bri !== undefined, ct: this.obj.state.ct !== undefined, xy: this.obj.state.xy !== undefined, + speed: this.obj.state.speed !== undefined, colorloop: this.obj.state.effect !== undefined, wallSwitch: false, outlet: this.bridge.outlet[this.type + 's'][this.id], @@ -595,9 +602,9 @@ HueLight.prototype.setConfig = function () { this.config.windowCovering = false } else if (this.obj.type === 'Window covering device') { this.config.windowCovering = true - this.config.sat = this.obj.state.sat !== undefined - this.config.ct = false - this.config.xy = false + this.config.lift = this.obj.state.lift !== undefined + this.config.tilt = this.obj.state.tilt !== undefined + this.config.bri = false } else if (this.type === 'light') { this.config.wallSwitch = this.bridge.platform.config.wallSwitch || this.bridge.wallswitch[this.id] @@ -765,10 +772,6 @@ HueLight.prototype.checkState = function (state, event) { break // jshint +W106 case 'bri': - if (this.config.windowCovering) { - this.checkPosition(state.bri) - break - } this.checkBri(state.bri) break case 'colormode': @@ -786,6 +789,7 @@ HueLight.prototype.checkState = function (state, event) { case 'mode': break case 'lift': + this.checkLift(state.lift) break case 'on': if (this.config.valve) { @@ -800,15 +804,15 @@ HueLight.prototype.checkState = function (state, event) { this.checkReachable(state.reachable) break case 'sat': - if (this.config.windowCovering) { - this.checkTilt(state.sat) - break - } this.checkSat(state.sat) break case 'scene': break + case 'speed': + this.checkSpeed(state.speed) + break case 'tilt': + this.checkTilt(state.tilt) break case 'x': break @@ -1174,18 +1178,18 @@ HueLight.prototype.checkXY = function (xy) { } } -HueLight.prototype.checkPosition = function (bri) { - if (!this.config.windowCovering || !this.config.bri) { +HueLight.prototype.checkLift = function (lift) { + if (!this.config.windowCovering || !this.config.lift) { return } - if (this.obj.state.bri !== bri) { + if (this.obj.state.lift !== lift) { this.log.debug( - '%s: %s bri (position) changed from %s to %s', this.name, this.type, - this.obj.state.bri, bri + '%s: %s lift changed from %s to %s', this.name, this.type, + this.obj.state.lift, lift ) - this.obj.state.bri = bri + this.obj.state.lift = lift } - let hkPosition = 100 - Math.round(this.obj.state.bri * 100.0 / 254.0) + let hkPosition = 100 - this.obj.state.lift hkPosition = 5 * Math.round(hkPosition / 5.0) // round to multiple of 5 if (this.hk.currentPosition !== hkPosition) { if (this.hk.currentPosition !== undefined) { @@ -1205,23 +1209,22 @@ HueLight.prototype.checkPosition = function (bri) { } } -HueLight.prototype.checkTilt = function (sat) { - if (!this.config.windowCovering || !this.config.sat) { +HueLight.prototype.checkTilt = function (tilt) { + if (!this.config.windowCovering || !this.config.tilt) { return } - if (this.obj.state.sat !== sat) { + if (this.obj.state.tilt !== tilt) { this.log.debug( - '%s: %s sat (tilt) changed from %s to %s', this.name, this.type, - this.obj.state.sat, sat + '%s: %s tilt changed from %s to %s', this.name, this.type, + this.obj.state.tilt, tilt ) - this.obj.state.sat = sat + this.obj.state.tilt = tilt } - let hkTilt = Math.round(this.obj.state.sat * 180.0 / 254.0) - 90 - hkTilt = 5 * Math.round(hkTilt / 5.0) // round to multiple of 5 + const hkTilt = Math.round(this.obj.state.tilt * 1.80) - 90.0 if (this.hk.currentTilt !== hkTilt) { if (this.hk.currentTilt !== undefined) { this.log.info( - '%s: set homekit current tilt from %s%% to %s%%', this.name, + '%s: set homekit current tilt from %s° to %s°', this.name, this.hk.currentTilt, hkTilt ) } @@ -1234,12 +1237,59 @@ HueLight.prototype.checkTilt = function (sat) { } } +HueLight.prototype.checkSpeed = function (speed) { + if (!this.config.speed) { + return + } + if (this.obj.state.speed !== speed) { + this.log.debug( + '%s: %s speed changed from %s to %s', this.name, this.type, + this.obj.state.speed, speed + ) + this.obj.state.speed = speed + if (this.obj.state.speed > 4) { + this.log.warn( + '%s: %s speed %d: not supported', this.name, this.type, + this.obj.state.speed + ) + return + } + const hkFanOn = speed !== 0 + const hkFanSpeed = speed * 25 + if (this.hk.fanOn !== hkFanOn) { + if (this.hk.fanOn !== undefined) { + this.log.info( + '%s: set homekit fan on from %s to %s', this.name, + this.hk.fanOn, hkFanOn + ) + } + this.hk.fanOn = hkFanOn + this.fanService.getCharacteristic(Characteristic.On) + .updateValue(this.hk.fanOn) + } + if (this.hk.fanSpeed !== hkFanSpeed) { + this.log.info( + '%s: set homekit rotation speed from %s%% to %s%%', this.name, + this.hk.fanSpeed, hkFanSpeed + ) + this.hk.fanSpeed = hkFanSpeed + this.fanService.getCharacteristic(Characteristic.RotationSpeed) + .setProps({ + minValue: 0, + maxValue: 100, + minStep: 25 + }) + .updateValue(this.hk.fanSpeed) + } + } +} + // ===== Homekit Events ======================================================== HueLight.prototype.identify = function (callback) { this.log.debug('%s: %s: config: %j', this.bridge.name, this.resource, this.config) this.log.info('%s: identify', this.name) - if (this.config.valve) { + if (this.config.valve || this.config.windowCovering || !this.config.on) { return callback() } let alert = 'select' @@ -1574,9 +1624,9 @@ HueLight.prototype.setPosition = function (position, callback) { ) const oldPosition = this.hk.targetPosition this.hk.targetPosition = position - const newBri = Math.round((100 - this.hk.targetPosition) * 254.0 / 100.0) - this.put({ bri: newBri }).then(() => { - this.obj.state.bri = newBri + const newLift = 100 - this.hk.targetPosition + this.put({ lift: newLift }).then(() => { + this.obj.state.lift = newLift const positionState = this.hk.targetPosition > this.hk.currentPosition ? Characteristic.PositionState.INCREASING : Characteristic.PositionState.DECREASING @@ -1606,14 +1656,14 @@ HueLight.prototype.setTilt = function (tilt, callback) { return callback() } this.log.info( - '%s: homekit target tilt changed from %s° to %s°', this.name, + '%s: homekit tilt angle changed from %s° to %s°', this.name, this.hk.targetTilt, tilt ) const oldTilt = this.hk.targetTilt this.hk.targetTilt = tilt - const newSat = Math.round((90 + this.hk.targetTilt) * 254.0 / 180.0) - this.put({ sat: newSat }).then(() => { - this.obj.state.sat = newSat + const newTilt = Math.round((90 + this.hk.targetTilt) / 1.80) + this.put({ tilt: newTilt }).then(() => { + this.obj.state.tilt = newTilt callback() }).catch((error) => { this.hk.targetTilt = oldTilt @@ -1621,6 +1671,29 @@ HueLight.prototype.setTilt = function (tilt, callback) { }) } +HueLight.prototype.setSpeed = function (speed, callback) { + if (speed === this.hk.fanSpeed) { + return callback() + } + this.log.info( + '%s: homekit rotation speed changed from %s%% to %s%%', this.name, + this.hk.fanSpeed, speed + ) + const oldFanSpeed = this.hk.fanSpeed + this.hk.fanSpeed = speed + const newSpeed = Math.floor(this.hk.fanSpeed / 25) + this.put({ speed: newSpeed }).then(() => { + this.obj.state.speed = newSpeed + callback() + this.hk.fanOn = this.obj.state.speed !== 0 + this.fanService.getCharacteristic(Characteristic.On) + .updateValue(this.hk.fanOn) + }).catch((error) => { + this.hk.fanSpeed = oldFanSpeed + callback(error) + }) +} + HueLight.prototype.getRemainingDuration = function (callback) { let remaining = this.hk.autoInActive - moment().unix() remaining = remaining > 0 ? remaining : 0