Skip to content

Commit

Permalink
Update HueLight.js
Browse files Browse the repository at this point in the history
- Remove _Configured Name_ characteristic, see #861;
- Remove _Unique ID_ characteristic, see #866.
- Handle case where same resource is in different type resourcelinks (`outlet`, `switch`, `valve`), see #882;
  • Loading branch information
ebaauw committed Jan 8, 2021
1 parent 8171c92 commit 7d134b1
Showing 1 changed file with 113 additions and 93 deletions.
206 changes: 113 additions & 93 deletions lib/HueLight.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,21 @@
// homebridge-hue/lib/HueLight.js
// Copyright © 2016-2020 Erik Baauw. All rights reserved.
// Copyright © 2016-2021 Erik Baauw. All rights reserved.
//
// Homebridge plugin for Philips Hue and/or deCONZ.
//
// HueLight provides support for Philips Hue lights and groups.

'use strict'

const homebridgeLib = require('homebridge-lib')
const AdaptiveLighting = require('./AdaptiveLighting')
const {
xyToHueSaturation, hueSaturationToXy, hueSaturationToRgb, ctToXy
} = require('./Colour')
defaultGamut, xyToHsv, hsvToXy, hsvToRgb, ctToXy
} = homebridgeLib.Colour

module.exports = {
setHomebridge: setHomebridge,
HueLight: HueLight
}

const formatError = homebridgeLib.CommandLineTool.formatError

// Safe default gamut taking into account:
// - The maximum value for CurrentX and CurrentY, 65279 (0xfeff), as defined
// by the ZCL spec;
// - A potential division by zero error for CurrentY, when translating the
// xy values back to hue/sat.
const defaultGamut = {
r: [0.9961, 0.0001],
g: [0, 0.9961],
b: [0, 0.0001]
}
const formatError = homebridgeLib.formatError

const knownLights = {
'3A Smart Home DE': {
Expand Down Expand Up @@ -153,6 +139,25 @@ const knownLights = {
'UC 110': { noAlert: true } // Under Cabinet
}
},
'LIDL Livarno Lux': {
ctmin: 153, // 6500 K
ctmax: 454, // 2200 K
models: {
HG06467: { // Xmas light strip
fix: function () {
this.config.colorLoop = false
this.config.hs = true
this.config.effects = [
'Steady', 'Snow', 'Rainbow', 'Snake',
'Twinkle', 'Fireworks', 'Flag', 'Waves',
'Updown', 'Vintage', 'Fading', 'Collide',
'Strobe', 'Sparkles', 'Carnival', 'Glow'
]
this.config.effectSpeed = true
}
}
}
},
MLI: { // Issue #439
gamut: {
r: [0.68, 0.31],
Expand Down Expand Up @@ -245,10 +250,10 @@ const knownLights = {
LST002: { gamut: 'C' } // Hue LightStrips Plus
}
},
_TZE200_s8gkrkxk: { // LIDL Melinera Xmas lightstrip
_TZE200_s8gkrkxk: { // LIDL Xmas lightstrip
fix: function () {
this.manufacturer = 'Melinera'
this.model = 'Xmas lightstrip'
this.manufacturer = 'LIDL Livarno Lux'
this.model = 'HG06467'
this.config.colorLoop = false
this.config.hs = true
this.config.effects = [
Expand Down Expand Up @@ -494,18 +499,18 @@ function HueLight (accessory, id, obj, type = 'light') {
this.checkEffect(this.obj.state.effect)
}
}
this.service.addOptionalCharacteristic(Characteristic.ConfiguredName)
this.service.getCharacteristic(Characteristic.ConfiguredName)
.on('set', this.setName.bind(this))
this.checkName(this.obj.name)
// this.service.addOptionalCharacteristic(Characteristic.ConfiguredName)
// this.service.getCharacteristic(Characteristic.ConfiguredName)
// .on('set', this.setName.bind(this))
// this.checkName(this.obj.name)
if (this.type === 'light') {
this.service.addOptionalCharacteristic(Characteristic.StatusFault)
this.checkReachable(this.obj.state.reachable)
if (this.bridge.config.nativeHomeKitLights) {
this.service.addOptionalCharacteristic(my.Characteristics.UniqueID)
this.service.getCharacteristic(my.Characteristics.UniqueID)
.updateValue(this.obj.uniqueid)
}
// if (this.bridge.config.nativeHomeKitLights) {
// this.service.addOptionalCharacteristic(my.Characteristics.UniqueID)
// this.service.getCharacteristic(my.Characteristics.UniqueID)
// .updateValue(this.obj.uniqueid)
// }
}
if (this.bridge.platform.config.resource) {
this.service.addOptionalCharacteristic(my.Characteristics.Resource)
Expand Down Expand Up @@ -546,12 +551,16 @@ HueLight.prototype.setConfig = function () {
lastBoot: this.obj.lastannounced !== undefined,
lastSeen: this.obj.lastseen !== undefined,
wallSwitch: false,
outlet: this.bridge.outlet[this.type + 's'][this.id],
resetTimeout: this.bridge.platform.config.resetTimeout,
switch: this.bridge.switch[this.type + 's'][this.id],
valve: this.type === 'light' && this.bridge.valve[this.id],
waitTimeUpdate: this.bridge.platform.config.waitTimeUpdate
}
if (this.bridge.outlet[this.type + 's'][this.id]) {
this.config.outlet = true
} else if (this.bridge.switch[this.type + 's'][this.id]) {
this.config.switch = true
} else if (this.type === 'light' && this.bridge.valve[this.id]) {
this.config.valve = true
}
if (this.config.outlet || this.config.switch || this.config.valve) {
this.config.bri = false
this.config.ct = false
Expand Down Expand Up @@ -715,7 +724,7 @@ HueLight.prototype.heartbeat = function (beat, obj) {
}
this.checkLastBoot(obj.lastannounced)
this.checkLastSeen(obj.lastseen)
this.checkName(obj.name)
// this.checkName(obj.name)
for (const key in obj.action) {
if (key !== 'on') {
obj.state[key] = obj.action[key]
Expand All @@ -739,9 +748,9 @@ HueLight.prototype.checkAttr = function (attr, event) {
case 'lastseen':
this.checkLastSeen(attr.lastseen)
break
case 'name':
this.checkName(attr.name)
break
// case 'name':
// this.checkName(attr.name)
// break
default:
break
}
Expand Down Expand Up @@ -1159,27 +1168,25 @@ HueLight.prototype.checkXy = function (xy, fromCt = false) {
this.obj.state.xy = xy
}
if (this.obj.state.colormode !== 'ct' || fromCt || this.config.computesXy) {
const hs = xyToHueSaturation(this.obj.state.xy, this.config.gamut)
const hkHue = hs.hue
const hkSat = hs.sat
if (this.hk.hue !== hkHue) {
const { h, s } = xyToHsv(this.obj.state.xy, this.config.gamut)
if (this.hk.hue !== h) {
if (this.hk.hue !== undefined) {
this.log.info(
'%s: set homekit hue from %s˚ to %s˚', this.name, this.hk.hue, hkHue
'%s: set homekit hue from %s˚ to %s˚', this.name, this.hk.hue, h
)
}
this.hk.hue = hkHue
this.hk.hue = h
this.service.getCharacteristic(Characteristic.Hue)
.updateValue(this.hk.hue)
}
if (this.hk.sat !== hkSat) {
if (this.hk.sat !== s) {
if (this.hk.sat !== undefined) {
this.log.info(
'%s: set homekit saturation from %s%% to %s%%', this.name,
this.hk.sat, hkSat
this.hk.sat, s
)
}
this.hk.sat = hkSat
this.hk.sat = s
this.service.getCharacteristic(Characteristic.Saturation)
.updateValue(this.hk.sat)
}
Expand Down Expand Up @@ -1342,26 +1349,26 @@ HueLight.prototype.checkLastSeen = function (lastseen) {
}
}

HueLight.prototype.checkName = function (name) {
if (this.obj.name !== name && name.trim() !== '') {
this.log.debug(
'%s: name changed from %s to %s', this.name, this.obj.name, name
)
this.obj.name = name
}
const hkName = this.obj.name
if (this.hk.name !== hkName) {
if (this.hk.name !== undefined) {
this.log.info(
'%s: set homekit name from %s to %s', this.name, this.hk.name, hkName
)
}
this.hk.name = hkName
this.service.getCharacteristic(Characteristic.ConfiguredName)
.updateValue(this.hk.hkName)
this.name = this.hk.name
}
}
// HueLight.prototype.checkName = function (name) {
// if (this.obj.name !== name) {
// this.log.debug(
// '%s: name changed from %j to %j', this.name, this.obj.name, name
// )
// this.obj.name = name
// }
// const hkName = this.obj.name
// if (this.hk.name !== hkName) {
// if (this.hk.name !== undefined) {
// this.log.info(
// '%s: set homekit name from %j to %j', this.name, this.hk.name, hkName
// )
// }
// this.hk.name = hkName
// this.service.getCharacteristic(Characteristic.ConfiguredName)
// .updateValue(this.hk.hkName)
// this.name = this.hk.name
// }
// }

// ===== Homekit Events ========================================================

Expand Down Expand Up @@ -1442,22 +1449,35 @@ HueLight.prototype.setMute = function (mute, callback) {
return callback()
}

HueLight.prototype.setName = function (name, callback) {
if (name === this.hk.name) {
return callback()
}
this.log.info(
'%s: homekit name changed from %s to %s', this.name, this.hk.name, name
)
this.hk.name = name
this.bridge.request('put', this.resource, { name: name }).then((obj) => {
this.obj.name = name
this.name = name
return callback()
}).catch((error) => {
return callback(error)
})
}
// HueLight.prototype.setName = function (name, callback) {
// if (name === this.hk.name) {
// return callback()
// }
// name = name.trim() // .slice(0, 32).trim()
// if (name === '') {
// return callback(new Error())
// }
// this.log.info(
// '%s: homekit name changed from %j to %j', this.name, this.hk.name, name
// )
// this.bridge.put(this.resource, { name: name }).then((obj) => {
// if (obj.name == null) {
// this.obj.name = name
// this.hk.name = name
// return callback(new Error())
// }
// this.obj.name = obj.name
// this.name = obj.name
// setImmediate(() => {
// this.hk.name = obj.name
// this.service.getCharacteristic(Characteristic.ConfiguredName)
// .updateValue(this.hk.name)
// })
// return callback()
// }).catch((error) => {
// return callback(error)
// })
// }

HueLight.prototype.setOn = function (on, callback) {
on = on ? 1 : 0
Expand Down Expand Up @@ -1645,7 +1665,7 @@ HueLight.prototype.setHue = function (hue, callback) {
const oldHue = this.hk.hue
this.hk.hue = hue
if (this.config.xy && this.hk.sat != null) {
const newXy = hueSaturationToXy(this.hk.hue, this.hk.sat, this.config.gamut)
const newXy = hsvToXy(this.hk.hue, this.hk.sat, this.config.gamut)
this.put({ xy: newXy }).then(() => {
this.obj.state.xy = newXy
this.obj.state.colormode = 'xy'
Expand Down Expand Up @@ -1679,7 +1699,7 @@ HueLight.prototype.setSat = function (sat, callback) {
const oldSat = this.hk.sat
this.hk.sat = sat
if (this.config.xy && this.hk.hue != null) {
const newXy = hueSaturationToXy(this.hk.hue, this.hk.sat, this.config.gamut)
const newXy = hsvToXy(this.hk.hue, this.hk.sat, this.config.gamut)
this.put({ xy: newXy }).then(() => {
this.obj.state.xy = newXy
this.obj.state.colormode = 'xy'
Expand Down Expand Up @@ -1761,9 +1781,9 @@ HueLight.prototype.putEffect = function (effect) {
if (colour.on === 0) {
break
}
const { R, G, B } = hueSaturationToRgb(colour.hue, colour.sat)
const { r, g, b } = hsvToRgb(colour.hue, colour.sat)
state.effectColours.push([
Math.round(R * 255), Math.round(G * 255), Math.round(B * 255)])
Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)])
}
}
return this.put(state)
Expand Down Expand Up @@ -1969,7 +1989,7 @@ HueLight.prototype.getSupportedTransitionConfiguration = function (callback) {
this.log.debug(
'%s: brightness idd: %d, color temperature idd: %d', this.name, bri, ct
)
this.al = new AdaptiveLighting(bri, ct)
this.al = new homebridgeLib.AdaptiveLighting(bri, ct)
const configuration = this.al.generateConfiguration()
this.log.debug(
'%s: set homekit supported transition configuration to %s', this.name,
Expand Down Expand Up @@ -2050,19 +2070,19 @@ HueLight.prototype.checkAdaptiveLighting = function () {
if (this.al == null || !this.hk.on) {
return
}
const hkState = this.al.getCt(
const ct = this.al.getCt(
this.hk.bri * this.bridge.platform.config.brightnessAdjustment
)
if (hkState == null) {
if (ct == null) {
return
}
if (hkState.ct !== this.hk.ct || this.obj.state.colormode !== 'ct') {
if (ct !== this.hk.ct || this.obj.state.colormode !== 'ct') {
this.log.info(
'%s: homekit adaptive lighting color temperature changed from %s mired to %s mired',
this.name, this.hk.ct, hkState.ct
this.name, this.hk.ct, ct
)
const oldCt = this.hk.ct
this.hk.ct = hkState.ct
this.hk.ct = ct
const newCt = this.hk.ct
this.put({ ct: newCt }).then(() => {
this.obj.state.ct = newCt
Expand Down Expand Up @@ -2121,7 +2141,7 @@ HueLight.prototype._put = function () {
desiredState.transitiontime = this.bridge.state.transitiontime * 10
this.bridge.resetTransitionTime()
}
this.bridge.request('put', this.resourcePath, desiredState).then((obj) => {
this.bridge.put(this.resourcePath, desiredState).then((obj) => {
this.recentlyUpdated = true
for (const d of deferrals) {
d.resolve(true)
Expand Down

0 comments on commit 7d134b1

Please sign in to comment.