homebridge-deconz 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/deconz.js +2 -3
 - package/lib/Deconz/Resource.js +260 -6
 - package/lib/DeconzAccessory/Gateway.js +16 -2
 - package/lib/DeconzAccessory/Light.js +65 -0
 - package/lib/DeconzAccessory/index.js +14 -11
 - package/lib/DeconzService/GatewaySettings.js +3 -2
 - package/lib/DeconzService/Light.js +469 -0
 - package/lib/DeconzService/Sensor.js +2 -2
 - package/lib/DeconzService/index.js +1 -1
 - package/package.json +2 -2
 
    
        package/cli/deconz.js
    CHANGED
    
    | 
         @@ -517,7 +517,7 @@ class Main extends homebridgeLib.CommandLineTool { 
     | 
|
| 
       517 
517 
     | 
    
         
             
                    'missing API key - unlock gateway and run "deconz%s getApiKey"', args
         
     | 
| 
       518 
518 
     | 
    
         
             
                  )
         
     | 
| 
       519 
519 
     | 
    
         
             
                }
         
     | 
| 
       520 
     | 
    
         
            -
                this.client = new Deconz. 
     | 
| 
      
 520 
     | 
    
         
            +
                this.client = new Deconz.ApiClient(this.clargs.options)
         
     | 
| 
       521 
521 
     | 
    
         
             
                this.client
         
     | 
| 
       522 
522 
     | 
    
         
             
                  .on('error', (error) => {
         
     | 
| 
       523 
523 
     | 
    
         
             
                    if (error.request.id !== this.requestId) {
         
     | 
| 
         @@ -688,10 +688,9 @@ class Main extends homebridgeLib.CommandLineTool { 
     | 
|
| 
       688 
688 
     | 
    
         
             
                this.jsonFormatter = new homebridgeLib.JsonFormatter(
         
     | 
| 
       689 
689 
     | 
    
         
             
                  mode === 'service' ? { noWhiteSpace: true } : {}
         
     | 
| 
       690 
690 
     | 
    
         
             
                )
         
     | 
| 
       691 
     | 
    
         
            -
                const WsMonitor = require('../lib/DeconzWsClient')
         
     | 
| 
       692 
691 
     | 
    
         
             
                const { websocketport } = await this.client.get('/config')
         
     | 
| 
       693 
692 
     | 
    
         
             
                options.host = this.client.host + ':' + websocketport
         
     | 
| 
       694 
     | 
    
         
            -
                this.wsMonitor = new  
     | 
| 
      
 693 
     | 
    
         
            +
                this.wsMonitor = new Deconz.WsClient(options)
         
     | 
| 
       695 
694 
     | 
    
         
             
                this.setOptions({ mode: mode })
         
     | 
| 
       696 
695 
     | 
    
         
             
                this.wsMonitor
         
     | 
| 
       697 
696 
     | 
    
         
             
                  .on('error', (error) => { this.error(error) })
         
     | 
    
        package/lib/Deconz/Resource.js
    CHANGED
    
    | 
         @@ -7,7 +7,10 @@ 
     | 
|
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            const homebridgeLib = require('homebridge-lib')
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
            const { toInt, toObject, toString } = homebridgeLib.OptionParser
         
     | 
| 
      
 10 
     | 
    
         
            +
            const { toInstance, toInt, toObject, toString } = homebridgeLib.OptionParser
         
     | 
| 
      
 11 
     | 
    
         
            +
            const { defaultGamut } = homebridgeLib.Colour
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            const DeconzAccessory = require('../DeconzAccessory')
         
     | 
| 
       11 
14 
     | 
    
         | 
| 
       12 
15 
     | 
    
         
             
            const rtypes = ['lights', 'sensors', 'groups']
         
     | 
| 
       13 
16 
     | 
    
         | 
| 
         @@ -26,6 +29,53 @@ const sensorsPrios = [ 
     | 
|
| 
       26 
29 
     | 
    
         
             
              'Thermostat'
         
     | 
| 
       27 
30 
     | 
    
         
             
            ]
         
     | 
| 
       28 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
            // =============================================================================
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            // See: http://www.developers.meethue.com/documentation/supported-lights
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            const hueGamutType = { // Color gamut per light model.
         
     | 
| 
      
 37 
     | 
    
         
            +
              A: { // Color Lights
         
     | 
| 
      
 38 
     | 
    
         
            +
                r: [0.7040, 0.2960],
         
     | 
| 
      
 39 
     | 
    
         
            +
                g: [0.2151, 0.7106],
         
     | 
| 
      
 40 
     | 
    
         
            +
                b: [0.1380, 0.0800]
         
     | 
| 
      
 41 
     | 
    
         
            +
              },
         
     | 
| 
      
 42 
     | 
    
         
            +
              B: { // Extended Color Lights
         
     | 
| 
      
 43 
     | 
    
         
            +
                r: [0.6750, 0.3220],
         
     | 
| 
      
 44 
     | 
    
         
            +
                g: [0.4090, 0.5180],
         
     | 
| 
      
 45 
     | 
    
         
            +
                b: [0.1670, 0.0400]
         
     | 
| 
      
 46 
     | 
    
         
            +
              },
         
     | 
| 
      
 47 
     | 
    
         
            +
              C: { // next gen Extended Color Lights
         
     | 
| 
      
 48 
     | 
    
         
            +
                r: [0.6920, 0.3080],
         
     | 
| 
      
 49 
     | 
    
         
            +
                g: [0.1700, 0.7000],
         
     | 
| 
      
 50 
     | 
    
         
            +
                b: [0.1530, 0.0480]
         
     | 
| 
      
 51 
     | 
    
         
            +
              }
         
     | 
| 
      
 52 
     | 
    
         
            +
            }
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            const hueGamutTypeByModel = {
         
     | 
| 
      
 55 
     | 
    
         
            +
              LCT001: 'B', // Hue bulb A19
         
     | 
| 
      
 56 
     | 
    
         
            +
              LCT002: 'B', // Hue Spot BR30
         
     | 
| 
      
 57 
     | 
    
         
            +
              LCT003: 'B', // Hue Spot GU10
         
     | 
| 
      
 58 
     | 
    
         
            +
              LCT007: 'B', // Hue bulb A19
         
     | 
| 
      
 59 
     | 
    
         
            +
              LCT010: 'C', // Hue bulb A19
         
     | 
| 
      
 60 
     | 
    
         
            +
              LCT011: 'C', // Hue BR30
         
     | 
| 
      
 61 
     | 
    
         
            +
              LCT012: 'C', // Hue Color Candle
         
     | 
| 
      
 62 
     | 
    
         
            +
              LCT014: 'C', // Hue bulb A19
         
     | 
| 
      
 63 
     | 
    
         
            +
              LCT015: 'C', // Hue bulb A19
         
     | 
| 
      
 64 
     | 
    
         
            +
              LCT016: 'C', // Hue bulb A19
         
     | 
| 
      
 65 
     | 
    
         
            +
              LLC005: 'A', // Living Colors Gen3 Bloom, Aura
         
     | 
| 
      
 66 
     | 
    
         
            +
              LLC006: 'A', // Living Colors Gen3 Iris
         
     | 
| 
      
 67 
     | 
    
         
            +
              LLC007: 'A', // Living Colors Gen3 Bloom, Aura
         
     | 
| 
      
 68 
     | 
    
         
            +
              LLC010: 'A', // Hue Living Colors Iris
         
     | 
| 
      
 69 
     | 
    
         
            +
              LLC011: 'A', // Hue Living Colors Bloom
         
     | 
| 
      
 70 
     | 
    
         
            +
              LLC012: 'A', // Hue Living Colors Bloom
         
     | 
| 
      
 71 
     | 
    
         
            +
              LLC013: 'A', // Disney Living Colors
         
     | 
| 
      
 72 
     | 
    
         
            +
              LLC014: 'A', // Living Colors Gen3 Bloom, Aura
         
     | 
| 
      
 73 
     | 
    
         
            +
              LLC020: 'C', // Hue Go
         
     | 
| 
      
 74 
     | 
    
         
            +
              LLM001: 'B', // Color Light Module
         
     | 
| 
      
 75 
     | 
    
         
            +
              LST001: 'A', // Hue LightStrips
         
     | 
| 
      
 76 
     | 
    
         
            +
              LST002: 'C' // Hue LightStrips Plus
         
     | 
| 
      
 77 
     | 
    
         
            +
            }
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
       29 
79 
     | 
    
         
             
            /** Delegate class for a resource on a deCONZ gateway.
         
     | 
| 
       30 
80 
     | 
    
         
             
              *
         
     | 
| 
       31 
81 
     | 
    
         
             
              * @memberof Deconz
         
     | 
| 
         @@ -47,14 +97,14 @@ class Resource { 
     | 
|
| 
       47 
97 
     | 
    
         | 
| 
       48 
98 
     | 
    
         
             
              /** Create a new instance of a delegate of a resource.
         
     | 
| 
       49 
99 
     | 
    
         
             
                *
         
     | 
| 
       50 
     | 
    
         
            -
                * @param { 
     | 
| 
      
 100 
     | 
    
         
            +
                * @param {DeconzAccessory.Gateway} gateway - The gateway.
         
     | 
| 
       51 
101 
     | 
    
         
             
                * @param {string} rtype - The resource type of the resource:
         
     | 
| 
       52 
102 
     | 
    
         
             
                * `groups`, `lights`, or `sensors`.
         
     | 
| 
       53 
103 
     | 
    
         
             
                * @param {integer} rid - The resource ID of the resource.
         
     | 
| 
       54 
104 
     | 
    
         
             
                * @param {object} body - The body of the resource.
         
     | 
| 
       55 
105 
     | 
    
         
             
                */
         
     | 
| 
       56 
     | 
    
         
            -
              constructor ( 
     | 
| 
       57 
     | 
    
         
            -
                 
     | 
| 
      
 106 
     | 
    
         
            +
              constructor (gateway, rtype, rid, body) {
         
     | 
| 
      
 107 
     | 
    
         
            +
                toInstance('gateway', gateway, DeconzAccessory.Gateway)
         
     | 
| 
       58 
108 
     | 
    
         | 
| 
       59 
109 
     | 
    
         
             
                /** The resource type of the resource: `groups`, `lights`, or `sensors`.
         
     | 
| 
       60 
110 
     | 
    
         
             
                  * @type {string}
         
     | 
| 
         @@ -112,9 +162,78 @@ class Resource { 
     | 
|
| 
       112 
162 
     | 
    
         
             
                  this.zigbee = true
         
     | 
| 
       113 
163 
     | 
    
         
             
                } else {
         
     | 
| 
       114 
164 
     | 
    
         
             
                  this.subtype = '-' + rtype[0].toUpperCase() + rid
         
     | 
| 
       115 
     | 
    
         
            -
                  this.id =  
     | 
| 
      
 165 
     | 
    
         
            +
                  this.id = gateway.id + this.subtype
         
     | 
| 
       116 
166 
     | 
    
         
             
                  this.zigbee = false
         
     | 
| 
       117 
167 
     | 
    
         
             
                }
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                /** The associated Homekit _Manufacturer_.
         
     | 
| 
      
 170 
     | 
    
         
            +
                  *
         
     | 
| 
      
 171 
     | 
    
         
            +
                  * For Zigbee devices, this is the sanitised `manufacturername` in the
         
     | 
| 
      
 172 
     | 
    
         
            +
                  * resource body.
         
     | 
| 
      
 173 
     | 
    
         
            +
                  * For virtual devices, this is the _Manufacturer_ for the gateway.
         
     | 
| 
      
 174 
     | 
    
         
            +
                  * @type {string}
         
     | 
| 
      
 175 
     | 
    
         
            +
                  */
         
     | 
| 
      
 176 
     | 
    
         
            +
                this.manufacturer = this.zigbee
         
     | 
| 
      
 177 
     | 
    
         
            +
                  ? body.manufacturername
         
     | 
| 
      
 178 
     | 
    
         
            +
                  : gateway.values.manufacturer
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                /** The associated HomeKit _Model_.
         
     | 
| 
      
 181 
     | 
    
         
            +
                  *
         
     | 
| 
      
 182 
     | 
    
         
            +
                  * For Zigbee devices, this is the sanitised `modelid` in the
         
     | 
| 
      
 183 
     | 
    
         
            +
                  * resource body.
         
     | 
| 
      
 184 
     | 
    
         
            +
                  * For virtual devices, this is the `type` in the resource body.
         
     | 
| 
      
 185 
     | 
    
         
            +
                  * @type {string}
         
     | 
| 
      
 186 
     | 
    
         
            +
                  */
         
     | 
| 
      
 187 
     | 
    
         
            +
                this.model = this.zigbee ? body.modelid : body.type
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                /** The associated HomeKit _Firmware Version_.
         
     | 
| 
      
 190 
     | 
    
         
            +
                  *
         
     | 
| 
      
 191 
     | 
    
         
            +
                  * For Zigbee devices, this is the sanitised `swversion` in the
         
     | 
| 
      
 192 
     | 
    
         
            +
                  * resource body.
         
     | 
| 
      
 193 
     | 
    
         
            +
                  * For virtual devices, this is the _Firmware Version_ for the gateway.
         
     | 
| 
      
 194 
     | 
    
         
            +
                  */
         
     | 
| 
      
 195 
     | 
    
         
            +
                this.firmware = this.zigbee
         
     | 
| 
      
 196 
     | 
    
         
            +
                  ? body.swversion == null ? '0.0.0' : body.swversion
         
     | 
| 
      
 197 
     | 
    
         
            +
                  : gateway.values.software
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                switch (this.serviceName) {
         
     | 
| 
      
 200 
     | 
    
         
            +
                  case 'Light': {
         
     | 
| 
      
 201 
     | 
    
         
            +
                    if (body.action != null) {
         
     | 
| 
      
 202 
     | 
    
         
            +
                      Object.assign(body.state, body.action)
         
     | 
| 
      
 203 
     | 
    
         
            +
                      delete body.state.on
         
     | 
| 
      
 204 
     | 
    
         
            +
                    }
         
     | 
| 
      
 205 
     | 
    
         
            +
                    this.capabilities = {
         
     | 
| 
      
 206 
     | 
    
         
            +
                      on: body.state.on !== undefined,
         
     | 
| 
      
 207 
     | 
    
         
            +
                      bri: body.state.bri !== undefined,
         
     | 
| 
      
 208 
     | 
    
         
            +
                      ct: body.state.ct !== undefined,
         
     | 
| 
      
 209 
     | 
    
         
            +
                      ctMax: (body.ctmax != null && body.ctmax !== 0 && body.ctmax !== 65535)
         
     | 
| 
      
 210 
     | 
    
         
            +
                        ? body.ctmax
         
     | 
| 
      
 211 
     | 
    
         
            +
                        : 500,
         
     | 
| 
      
 212 
     | 
    
         
            +
                      ctMin: (body.ctmin != null && body.ctmin !== 0)
         
     | 
| 
      
 213 
     | 
    
         
            +
                        ? body.ctmin
         
     | 
| 
      
 214 
     | 
    
         
            +
                        : 153,
         
     | 
| 
      
 215 
     | 
    
         
            +
                      xy: body.state.xy !== undefined,
         
     | 
| 
      
 216 
     | 
    
         
            +
                      gamut: defaultGamut,
         
     | 
| 
      
 217 
     | 
    
         
            +
                      alert: body.state.alert !== undefined,
         
     | 
| 
      
 218 
     | 
    
         
            +
                      colorLoop: body.state.effect !== undefined
         
     | 
| 
      
 219 
     | 
    
         
            +
                    }
         
     | 
| 
      
 220 
     | 
    
         
            +
                    break
         
     | 
| 
      
 221 
     | 
    
         
            +
                  }
         
     | 
| 
      
 222 
     | 
    
         
            +
                  case 'WarningDevice':
         
     | 
| 
      
 223 
     | 
    
         
            +
                    this.capabilities = {}
         
     | 
| 
      
 224 
     | 
    
         
            +
                    break
         
     | 
| 
      
 225 
     | 
    
         
            +
                  case 'WindowCovering':
         
     | 
| 
      
 226 
     | 
    
         
            +
                    this.capabilities = {}
         
     | 
| 
      
 227 
     | 
    
         
            +
                    break
         
     | 
| 
      
 228 
     | 
    
         
            +
                  default:
         
     | 
| 
      
 229 
     | 
    
         
            +
                    this.capabilities = {}
         
     | 
| 
      
 230 
     | 
    
         
            +
                    break
         
     | 
| 
      
 231 
     | 
    
         
            +
                }
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                const f = 'patch' + this.serviceName
         
     | 
| 
      
 234 
     | 
    
         
            +
                if (typeof this[f] === 'function') {
         
     | 
| 
      
 235 
     | 
    
         
            +
                  this[f](gateway)
         
     | 
| 
      
 236 
     | 
    
         
            +
                }
         
     | 
| 
       118 
237 
     | 
    
         
             
              }
         
     | 
| 
       119 
238 
     | 
    
         | 
| 
       120 
239 
     | 
    
         
             
              /** The priority of the resource, when determining the primary resource for a
         
     | 
| 
         @@ -143,7 +262,7 @@ class Resource { 
     | 
|
| 
       143 
262 
     | 
    
         
             
                */
         
     | 
| 
       144 
263 
     | 
    
         
             
              get serviceName () {
         
     | 
| 
       145 
264 
     | 
    
         
             
                if (this.rtype === 'groups') {
         
     | 
| 
       146 
     | 
    
         
            -
                  return ' 
     | 
| 
      
 265 
     | 
    
         
            +
                  return 'Light'
         
     | 
| 
       147 
266 
     | 
    
         
             
                } else if (this.rtype === 'lights') {
         
     | 
| 
       148 
267 
     | 
    
         
             
                  switch (this.body.type) {
         
     | 
| 
       149 
268 
     | 
    
         
             
                    case 'Color dimmable light': return 'Light'
         
     | 
| 
         @@ -222,6 +341,141 @@ class Resource { 
     | 
|
| 
       222 
341 
     | 
    
         
             
                  }
         
     | 
| 
       223 
342 
     | 
    
         
             
                }
         
     | 
| 
       224 
343 
     | 
    
         
             
              }
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
              /** Patch a resource corresponding to a `Light` service.
         
     | 
| 
      
 346 
     | 
    
         
            +
              * @param {DeconzAccessory.Gateway} gateway - The gateway.
         
     | 
| 
      
 347 
     | 
    
         
            +
                */
         
     | 
| 
      
 348 
     | 
    
         
            +
              patchLight (gateway) {
         
     | 
| 
      
 349 
     | 
    
         
            +
                switch (this.manufacturer) {
         
     | 
| 
      
 350 
     | 
    
         
            +
                  case 'Busch-Jaeger':
         
     | 
| 
      
 351 
     | 
    
         
            +
                    // See: https://www.busch-jaeger.de/en/products/product-solutions/dimmer/busch-radio-controlled-dimmer-zigbee-light-link/
         
     | 
| 
      
 352 
     | 
    
         
            +
                    if (
         
     | 
| 
      
 353 
     | 
    
         
            +
                      this.model === 'RM01' && // 6715 U-500 with 6736-84.
         
     | 
| 
      
 354 
     | 
    
         
            +
                      this.capabilities.bri && this.body.type === 'On/Off light' // Issue #241
         
     | 
| 
      
 355 
     | 
    
         
            +
                    ) {
         
     | 
| 
      
 356 
     | 
    
         
            +
                      gateway.debug(
         
     | 
| 
      
 357 
     | 
    
         
            +
                        '%s: ignoring state.bri for %s', this.rpath, this.body.type
         
     | 
| 
      
 358 
     | 
    
         
            +
                      )
         
     | 
| 
      
 359 
     | 
    
         
            +
                      this.capabilities.bri = false
         
     | 
| 
      
 360 
     | 
    
         
            +
                    }
         
     | 
| 
      
 361 
     | 
    
         
            +
                    break
         
     | 
| 
      
 362 
     | 
    
         
            +
                  case 'dresden elektronik':
         
     | 
| 
      
 363 
     | 
    
         
            +
                    // See: https://www.dresden-elektronik.de/funktechnik/solutions/wireless-light-control/wireless-ballasts/?L=1
         
     | 
| 
      
 364 
     | 
    
         
            +
                    this.capabilities.computesXy = true
         
     | 
| 
      
 365 
     | 
    
         
            +
                    break
         
     | 
| 
      
 366 
     | 
    
         
            +
                  case 'FeiBit':
         
     | 
| 
      
 367 
     | 
    
         
            +
                    if (this.model === 'FNB56-SKT1EHG1.2') { // issue #361
         
     | 
| 
      
 368 
     | 
    
         
            +
                      this.body.type = 'On/Off plug-in unit'
         
     | 
| 
      
 369 
     | 
    
         
            +
                    }
         
     | 
| 
      
 370 
     | 
    
         
            +
                    break
         
     | 
| 
      
 371 
     | 
    
         
            +
                  case 'GLEDOPTO':
         
     | 
| 
      
 372 
     | 
    
         
            +
                    // See: https://www.led-trading.de/zigbee-kompatibel-controller-led-lichtsteuerung
         
     | 
| 
      
 373 
     | 
    
         
            +
                    this.capabilities.gamut = {
         
     | 
| 
      
 374 
     | 
    
         
            +
                      r: [0.7006, 0.2993],
         
     | 
| 
      
 375 
     | 
    
         
            +
                      g: [0.1387, 0.8148],
         
     | 
| 
      
 376 
     | 
    
         
            +
                      b: [0.1510, 0.0227]
         
     | 
| 
      
 377 
     | 
    
         
            +
                    }
         
     | 
| 
      
 378 
     | 
    
         
            +
                    if (this.model === 'GLEDOPTO') { // Issue #244
         
     | 
| 
      
 379 
     | 
    
         
            +
                      if (
         
     | 
| 
      
 380 
     | 
    
         
            +
                        this.subtype === '0a' &&
         
     | 
| 
      
 381 
     | 
    
         
            +
                        this.body.type === 'Dimmable light' &&
         
     | 
| 
      
 382 
     | 
    
         
            +
                        this.firmware === '1.0.2'
         
     | 
| 
      
 383 
     | 
    
         
            +
                      ) {
         
     | 
| 
      
 384 
     | 
    
         
            +
                        this.model = 'RGBW'
         
     | 
| 
      
 385 
     | 
    
         
            +
                      } else if (
         
     | 
| 
      
 386 
     | 
    
         
            +
                        this.subtype === '0b' &&
         
     | 
| 
      
 387 
     | 
    
         
            +
                        this.body.type === 'Color temperature light' &&
         
     | 
| 
      
 388 
     | 
    
         
            +
                        this.firmware === '1.3.002'
         
     | 
| 
      
 389 
     | 
    
         
            +
                      ) {
         
     | 
| 
      
 390 
     | 
    
         
            +
                        this.model = 'WW/CW'
         
     | 
| 
      
 391 
     | 
    
         
            +
                      } else if (
         
     | 
| 
      
 392 
     | 
    
         
            +
                        this.subtype === '0b' &&
         
     | 
| 
      
 393 
     | 
    
         
            +
                        this.body.type === 'Extended color light' &&
         
     | 
| 
      
 394 
     | 
    
         
            +
                        this.firmware === '1.0.2'
         
     | 
| 
      
 395 
     | 
    
         
            +
                      ) {
         
     | 
| 
      
 396 
     | 
    
         
            +
                        this.model = 'RGB+CCT'
         
     | 
| 
      
 397 
     | 
    
         
            +
                        const device = gateway.resourceById[this.id]
         
     | 
| 
      
 398 
     | 
    
         
            +
                        if (device != null && device.resourceBySubtype.length > 1) {
         
     | 
| 
      
 399 
     | 
    
         
            +
                          this.model = 'RGBW'
         
     | 
| 
      
 400 
     | 
    
         
            +
                          this.capabilities.ct = false
         
     | 
| 
      
 401 
     | 
    
         
            +
                        }
         
     | 
| 
      
 402 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 403 
     | 
    
         
            +
                        return
         
     | 
| 
      
 404 
     | 
    
         
            +
                      }
         
     | 
| 
      
 405 
     | 
    
         
            +
                      gateway.debug('%s: set model to %j', this.rpath, this.model)
         
     | 
| 
      
 406 
     | 
    
         
            +
                    }
         
     | 
| 
      
 407 
     | 
    
         
            +
                    break
         
     | 
| 
      
 408 
     | 
    
         
            +
                  case 'IKEA of Sweden':
         
     | 
| 
      
 409 
     | 
    
         
            +
                    // See: http://www.ikea.com/us/en/catalog/categories/departments/lighting/smart_lighting/
         
     | 
| 
      
 410 
     | 
    
         
            +
                    this.capabilities.gamut = defaultGamut // Issue #956
         
     | 
| 
      
 411 
     | 
    
         
            +
                    this.capabilities.noTransition = true
         
     | 
| 
      
 412 
     | 
    
         
            +
                    if (this.model === 'TRADFRI bulb E27 CWS 806lm') {
         
     | 
| 
      
 413 
     | 
    
         
            +
                      this.capabilities.computesXy = true
         
     | 
| 
      
 414 
     | 
    
         
            +
                      this.capabilities.gamut = {
         
     | 
| 
      
 415 
     | 
    
         
            +
                        r: [0.68, 0.31],
         
     | 
| 
      
 416 
     | 
    
         
            +
                        g: [0.11, 0.82],
         
     | 
| 
      
 417 
     | 
    
         
            +
                        b: [0.13, 0.04]
         
     | 
| 
      
 418 
     | 
    
         
            +
                      }
         
     | 
| 
      
 419 
     | 
    
         
            +
                    }
         
     | 
| 
      
 420 
     | 
    
         
            +
                    break
         
     | 
| 
      
 421 
     | 
    
         
            +
                  case 'innr':
         
     | 
| 
      
 422 
     | 
    
         
            +
                    // See: https://shop.innrlighting.com/en/shop
         
     | 
| 
      
 423 
     | 
    
         
            +
                    this.capabilities.gamut = { // Issue #152
         
     | 
| 
      
 424 
     | 
    
         
            +
                      r: [0.8817, 0.1033],
         
     | 
| 
      
 425 
     | 
    
         
            +
                      g: [0.2204, 0.7758],
         
     | 
| 
      
 426 
     | 
    
         
            +
                      b: [0.0551, 0.1940]
         
     | 
| 
      
 427 
     | 
    
         
            +
                    }
         
     | 
| 
      
 428 
     | 
    
         
            +
                    if (this.model === 'SP 120') { // smart plug
         
     | 
| 
      
 429 
     | 
    
         
            +
                      this.capabilities.bri = false
         
     | 
| 
      
 430 
     | 
    
         
            +
                    }
         
     | 
| 
      
 431 
     | 
    
         
            +
                    break
         
     | 
| 
      
 432 
     | 
    
         
            +
                  case 'LIDL Livarno Lux':
         
     | 
| 
      
 433 
     | 
    
         
            +
                    this.capabilities.ctMax = 454 // 2200 K
         
     | 
| 
      
 434 
     | 
    
         
            +
                    this.capabilities.ctMin = 153 // 6500 K
         
     | 
| 
      
 435 
     | 
    
         
            +
                    if (this.model === 'HG06467') { // Xmas light strip
         
     | 
| 
      
 436 
     | 
    
         
            +
                      this.capabilities.colorLoop = false
         
     | 
| 
      
 437 
     | 
    
         
            +
                      this.capabilities.hs = true
         
     | 
| 
      
 438 
     | 
    
         
            +
                      this.capabilities.effects = [
         
     | 
| 
      
 439 
     | 
    
         
            +
                        'Steady', 'Snow', 'Rainbow', 'Snake',
         
     | 
| 
      
 440 
     | 
    
         
            +
                        'Twinkle', 'Fireworks', 'Flag', 'Waves',
         
     | 
| 
      
 441 
     | 
    
         
            +
                        'Updown', 'Vintage', 'Fading', 'Collide',
         
     | 
| 
      
 442 
     | 
    
         
            +
                        'Strobe', 'Sparkles', 'Carnival', 'Glow'
         
     | 
| 
      
 443 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 444 
     | 
    
         
            +
                    }
         
     | 
| 
      
 445 
     | 
    
         
            +
                    break
         
     | 
| 
      
 446 
     | 
    
         
            +
                  case 'MLI': // Issue #439
         
     | 
| 
      
 447 
     | 
    
         
            +
                    this.capabilities.gamut = {
         
     | 
| 
      
 448 
     | 
    
         
            +
                      r: [0.68, 0.31],
         
     | 
| 
      
 449 
     | 
    
         
            +
                      g: [0.11, 0.82],
         
     | 
| 
      
 450 
     | 
    
         
            +
                      b: [0.13, 0.04]
         
     | 
| 
      
 451 
     | 
    
         
            +
                    }
         
     | 
| 
      
 452 
     | 
    
         
            +
                    if (this.capabilities.colorloop) {
         
     | 
| 
      
 453 
     | 
    
         
            +
                      this.capabilities.effects = [
         
     | 
| 
      
 454 
     | 
    
         
            +
                        'Sunset', 'Party', 'Worklight', 'Campfire', 'Romance', 'Nightlight'
         
     | 
| 
      
 455 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 456 
     | 
    
         
            +
                    }
         
     | 
| 
      
 457 
     | 
    
         
            +
                    break
         
     | 
| 
      
 458 
     | 
    
         
            +
                  case 'OSRAM':
         
     | 
| 
      
 459 
     | 
    
         
            +
                    this.capabilities.gamut = {
         
     | 
| 
      
 460 
     | 
    
         
            +
                      r: [0.6877, 0.3161],
         
     | 
| 
      
 461 
     | 
    
         
            +
                      g: [0.1807, 0.7282],
         
     | 
| 
      
 462 
     | 
    
         
            +
                      b: [0.1246, 0.0580]
         
     | 
| 
      
 463 
     | 
    
         
            +
                    }
         
     | 
| 
      
 464 
     | 
    
         
            +
                    break
         
     | 
| 
      
 465 
     | 
    
         
            +
                  case 'Philips':
         
     | 
| 
      
 466 
     | 
    
         
            +
                  case 'Signify Netherlands B.V.': {
         
     | 
| 
      
 467 
     | 
    
         
            +
                    // See: http://www.developers.meethue.com/documentation/supported-lights
         
     | 
| 
      
 468 
     | 
    
         
            +
                    this.manufacturer = 'Signify Netherlands B.V.'
         
     | 
| 
      
 469 
     | 
    
         
            +
                    this.capabilities.breathe = true
         
     | 
| 
      
 470 
     | 
    
         
            +
                    this.capabilities.computesXy = true
         
     | 
| 
      
 471 
     | 
    
         
            +
                    const gamut = hueGamutTypeByModel[this.model] || 'C'
         
     | 
| 
      
 472 
     | 
    
         
            +
                    this.capabilities.gamut = hueGamutType[gamut]
         
     | 
| 
      
 473 
     | 
    
         
            +
                  }
         
     | 
| 
      
 474 
     | 
    
         
            +
                    break
         
     | 
| 
      
 475 
     | 
    
         
            +
                  default:
         
     | 
| 
      
 476 
     | 
    
         
            +
                    break
         
     | 
| 
      
 477 
     | 
    
         
            +
                }
         
     | 
| 
      
 478 
     | 
    
         
            +
              }
         
     | 
| 
       225 
479 
     | 
    
         
             
            }
         
     | 
| 
       226 
480 
     | 
    
         | 
| 
       227 
481 
     | 
    
         
             
            module.exports = Resource
         
     | 
| 
         @@ -119,6 +119,8 @@ class Gateway extends homebridgeLib.AccessoryDelegate { 
     | 
|
| 
       119 
119 
     | 
    
         
             
                  */
         
     | 
| 
       120 
120 
     | 
    
         
             
                this.accessoryByRpath = {}
         
     | 
| 
       121 
121 
     | 
    
         | 
| 
      
 122 
     | 
    
         
            +
                this.defaultTransitionTime = 0.4
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
       122 
124 
     | 
    
         
             
                /** Map of errors by device ID trying to expose the corresponding accessory.
         
     | 
| 
       123 
125 
     | 
    
         
             
                  * @type {Object<string, Error>}
         
     | 
| 
       124 
126 
     | 
    
         
             
                  */
         
     | 
| 
         @@ -158,6 +160,18 @@ class Gateway extends homebridgeLib.AccessoryDelegate { 
     | 
|
| 
       158 
160 
     | 
    
         
             
                  .on('shutdown', this.shutdown)
         
     | 
| 
       159 
161 
     | 
    
         
             
              }
         
     | 
| 
       160 
162 
     | 
    
         | 
| 
      
 163 
     | 
    
         
            +
              get transitionTime () { return this.service.values.transitionTime }
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
              async resetTransitionTime () {
         
     | 
| 
      
 166 
     | 
    
         
            +
                if (this.resetting) {
         
     | 
| 
      
 167 
     | 
    
         
            +
                  return
         
     | 
| 
      
 168 
     | 
    
         
            +
                }
         
     | 
| 
      
 169 
     | 
    
         
            +
                this.resetting = true
         
     | 
| 
      
 170 
     | 
    
         
            +
                await homebridgeLib.timeout(this.platform.config.waitTimeUpdate)
         
     | 
| 
      
 171 
     | 
    
         
            +
                this.service.values.transitionTime = this.defaultTransitionTime
         
     | 
| 
      
 172 
     | 
    
         
            +
                this.resetting = false
         
     | 
| 
      
 173 
     | 
    
         
            +
              }
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
       161 
175 
     | 
    
         
             
              /** Log debug messages.
         
     | 
| 
       162 
176 
     | 
    
         
             
                */
         
     | 
| 
       163 
177 
     | 
    
         
             
              identify () {
         
     | 
| 
         @@ -772,7 +786,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate { 
     | 
|
| 
       772 
786 
     | 
    
         
             
                    this.deleteService(id)
         
     | 
| 
       773 
787 
     | 
    
         
             
                    changed = true
         
     | 
| 
       774 
788 
     | 
    
         
             
                  } else {
         
     | 
| 
       775 
     | 
    
         
            -
                    /** Emitted when the  
     | 
| 
      
 789 
     | 
    
         
            +
                    /** Emitted when the gateway has been polled.
         
     | 
| 
       776 
790 
     | 
    
         
             
                      * @event DeconzAccessory.Device#polled
         
     | 
| 
       777 
791 
     | 
    
         
             
                      * @param {Deconz.Device} device - The updated device.
         
     | 
| 
       778 
792 
     | 
    
         
             
                      */
         
     | 
| 
         @@ -851,7 +865,7 @@ class Gateway extends homebridgeLib.AccessoryDelegate { 
     | 
|
| 
       851 
865 
     | 
    
         
             
                * unsupported resources.
         
     | 
| 
       852 
866 
     | 
    
         
             
                */
         
     | 
| 
       853 
867 
     | 
    
         
             
              analyseResource (rtype, rid, body, logUnsupported) {
         
     | 
| 
       854 
     | 
    
         
            -
                const resource = new Deconz.Resource(this 
     | 
| 
      
 868 
     | 
    
         
            +
                const resource = new Deconz.Resource(this, rtype, rid, body)
         
     | 
| 
       855 
869 
     | 
    
         
             
                const { id, serviceName } = resource
         
     | 
| 
       856 
870 
     | 
    
         
             
                if (id === this.id || serviceName === '') {
         
     | 
| 
       857 
871 
     | 
    
         
             
                  const debug = (logUnsupported ? this.debug : this.vdebug).bind(this)
         
     | 
| 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // homebridge-deconz/lib/DeconzAccessory/Device.js
         
     | 
| 
      
 2 
     | 
    
         
            +
            // Copyright © 2022 Erik Baauw. All rights reserved.
         
     | 
| 
      
 3 
     | 
    
         
            +
            //
         
     | 
| 
      
 4 
     | 
    
         
            +
            // Homebridge plugin for deCONZ.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            'use strict'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            const DeconzAccessory = require('.')
         
     | 
| 
      
 9 
     | 
    
         
            +
            const DeconzService = require('../DeconzService')
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            /** Delegate class for a HomeKit accessory,
         
     | 
| 
      
 12 
     | 
    
         
            +
              * corresponding to a Zigbee or virtual device on a deCONZ gateway,
         
     | 
| 
      
 13 
     | 
    
         
            +
              * that is not yet supported.
         
     | 
| 
      
 14 
     | 
    
         
            +
              * @extends DeconzAccessory
         
     | 
| 
      
 15 
     | 
    
         
            +
              * @memberof DeconzAccessory
         
     | 
| 
      
 16 
     | 
    
         
            +
              */
         
     | 
| 
      
 17 
     | 
    
         
            +
            class Light extends DeconzAccessory {
         
     | 
| 
      
 18 
     | 
    
         
            +
              /** Instantiate a delegate for an accessory corresponding to a device.
         
     | 
| 
      
 19 
     | 
    
         
            +
                * @param {DeconzAccessory.Gateway} gateway - The gateway.
         
     | 
| 
      
 20 
     | 
    
         
            +
                * @param {Deconz.Device} device - The device.
         
     | 
| 
      
 21 
     | 
    
         
            +
                */
         
     | 
| 
      
 22 
     | 
    
         
            +
              constructor (gateway, device) {
         
     | 
| 
      
 23 
     | 
    
         
            +
                super(gateway, device)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                this.identify()
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                this.service = new DeconzService.Light(this, device.resource)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                this.settingsService = new DeconzService.DeviceSettings(this, {
         
     | 
| 
      
 30 
     | 
    
         
            +
                  name: this.name + ' Settings',
         
     | 
| 
      
 31 
     | 
    
         
            +
                  subtype: this.id,
         
     | 
| 
      
 32 
     | 
    
         
            +
                  resource: this.device.rpaths.join(', '),
         
     | 
| 
      
 33 
     | 
    
         
            +
                  expose: true,
         
     | 
| 
      
 34 
     | 
    
         
            +
                  logLevel: gateway.logLevel
         
     | 
| 
      
 35 
     | 
    
         
            +
                })
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                this
         
     | 
| 
      
 38 
     | 
    
         
            +
                  .on('polled', (device) => {
         
     | 
| 
      
 39 
     | 
    
         
            +
                    this.debug('%s: polled: %j', device.resource.rpath, device.resource.body)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    this.service.update(device.resource.body)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    this.service.checkAdaptiveLighting()
         
     | 
| 
      
 42 
     | 
    
         
            +
                  })
         
     | 
| 
      
 43 
     | 
    
         
            +
                  .on('changed', (rpath, body) => {
         
     | 
| 
      
 44 
     | 
    
         
            +
                    if (rpath === device.resource.rpath) {
         
     | 
| 
      
 45 
     | 
    
         
            +
                      this.debug('%s: changed: %j', rpath, body)
         
     | 
| 
      
 46 
     | 
    
         
            +
                      this.service.update(body)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    }
         
     | 
| 
      
 48 
     | 
    
         
            +
                  })
         
     | 
| 
      
 49 
     | 
    
         
            +
                  .on('identify', this.identify)
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                setImmediate(() => {
         
     | 
| 
      
 52 
     | 
    
         
            +
                  this.debug('initialised')
         
     | 
| 
      
 53 
     | 
    
         
            +
                  this.emit('initialised')
         
     | 
| 
      
 54 
     | 
    
         
            +
                })
         
     | 
| 
      
 55 
     | 
    
         
            +
              }
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              async identify () {
         
     | 
| 
      
 58 
     | 
    
         
            +
                super.identify()
         
     | 
| 
      
 59 
     | 
    
         
            +
                if (this.service != null) {
         
     | 
| 
      
 60 
     | 
    
         
            +
                  await this.service.identify()
         
     | 
| 
      
 61 
     | 
    
         
            +
                }
         
     | 
| 
      
 62 
     | 
    
         
            +
              }
         
     | 
| 
      
 63 
     | 
    
         
            +
            }
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            module.exports = Light
         
     | 
| 
         @@ -11,25 +11,23 @@ const homebridgeLib = require('homebridge-lib') 
     | 
|
| 
       11 
11 
     | 
    
         
             
              * corresponding to a Zigbee or virtual device on a deCONZ gateway.
         
     | 
| 
       12 
12 
     | 
    
         
             
              */
         
     | 
| 
       13 
13 
     | 
    
         
             
            class DeconzAccessory extends homebridgeLib.AccessoryDelegate {
         
     | 
| 
       14 
     | 
    
         
            -
              static get Gateway () { return require('./Gateway') }
         
     | 
| 
       15 
14 
     | 
    
         
             
              static get Device () { return require('./Device') }
         
     | 
| 
      
 15 
     | 
    
         
            +
              static get Light () { return require('./Light') }
         
     | 
| 
      
 16 
     | 
    
         
            +
              static get Gateway () { return require('./Gateway') }
         
     | 
| 
       16 
17 
     | 
    
         | 
| 
       17 
18 
     | 
    
         
             
              /** Instantiate a delegate for an accessory corresponding to a device.
         
     | 
| 
       18 
19 
     | 
    
         
             
                * @param {DeconzAccessory.Gateway} gateway - The gateway.
         
     | 
| 
       19 
20 
     | 
    
         
             
                * @param {Deconz.Device} device - The device.
         
     | 
| 
      
 21 
     | 
    
         
            +
                * @param {Accessory.Category} category - The HomeKit accessory category.
         
     | 
| 
       20 
22 
     | 
    
         
             
                */
         
     | 
| 
       21 
     | 
    
         
            -
              constructor (gateway, device) {
         
     | 
| 
       22 
     | 
    
         
            -
                 
     | 
| 
      
 23 
     | 
    
         
            +
              constructor (gateway, device, category) {
         
     | 
| 
      
 24 
     | 
    
         
            +
                // TODO device settings
         
     | 
| 
       23 
25 
     | 
    
         
             
                super(gateway.platform, {
         
     | 
| 
       24 
26 
     | 
    
         
             
                  id: device.id,
         
     | 
| 
       25 
     | 
    
         
            -
                  name: body.name,
         
     | 
| 
       26 
     | 
    
         
            -
                  manufacturer: device. 
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                  model: device.zigbee ? body.modelid : body.type,
         
     | 
| 
       30 
     | 
    
         
            -
                  firmware: device.zigbee
         
     | 
| 
       31 
     | 
    
         
            -
                    ? body.swversion == null ? '0.0.0' : body.swversion
         
     | 
| 
       32 
     | 
    
         
            -
                    : gateway.values.software,
         
     | 
| 
      
 27 
     | 
    
         
            +
                  name: device.resource.body.name,
         
     | 
| 
      
 28 
     | 
    
         
            +
                  manufacturer: device.resource.manufacturer,
         
     | 
| 
      
 29 
     | 
    
         
            +
                  model: device.resource.model,
         
     | 
| 
      
 30 
     | 
    
         
            +
                  firmware: device.resource.firmware,
         
     | 
| 
       33 
31 
     | 
    
         
             
                  category: category,
         
     | 
| 
       34 
32 
     | 
    
         
             
                  logLevel: gateway.logLevel
         
     | 
| 
       35 
33 
     | 
    
         
             
                })
         
     | 
| 
         @@ -50,6 +48,11 @@ class DeconzAccessory extends homebridgeLib.AccessoryDelegate { 
     | 
|
| 
       50 
48 
     | 
    
         
             
                  * @type {Deconz.Device}
         
     | 
| 
       51 
49 
     | 
    
         
             
                  */
         
     | 
| 
       52 
50 
     | 
    
         
             
                this.device = device
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                /** The API client instance for the gateway.
         
     | 
| 
      
 53 
     | 
    
         
            +
                  * @type {Deconz.ApiClient}
         
     | 
| 
      
 54 
     | 
    
         
            +
                  */
         
     | 
| 
      
 55 
     | 
    
         
            +
                this.client = gateway.client
         
     | 
| 
       53 
56 
     | 
    
         
             
              }
         
     | 
| 
       54 
57 
     | 
    
         | 
| 
       55 
58 
     | 
    
         
             
              /** The primary resource of the device.
         
     | 
| 
         @@ -129,10 +129,11 @@ class GatewaySettings extends homebridgeLib.ServiceDelegate { 
     | 
|
| 
       129 
129 
     | 
    
         
             
                })
         
     | 
| 
       130 
130 
     | 
    
         | 
| 
       131 
131 
     | 
    
         
             
                this.addCharacteristicDelegate({
         
     | 
| 
       132 
     | 
    
         
            -
                  key: ' 
     | 
| 
      
 132 
     | 
    
         
            +
                  key: 'transitionTime',
         
     | 
| 
       133 
133 
     | 
    
         
             
                  Characteristic: this.Characteristics.my.TransitionTime,
         
     | 
| 
       134 
     | 
    
         
            -
                  value:  
     | 
| 
      
 134 
     | 
    
         
            +
                  value: this.gateway.defaultTransitionTime
         
     | 
| 
       135 
135 
     | 
    
         
             
                })
         
     | 
| 
      
 136 
     | 
    
         
            +
                this.values.transitionTime = this.gateway.defaultTransitionTime
         
     | 
| 
       136 
137 
     | 
    
         | 
| 
       137 
138 
     | 
    
         
             
                this.addCharacteristicDelegate({
         
     | 
| 
       138 
139 
     | 
    
         
             
                  key: 'unlock',
         
     | 
| 
         @@ -0,0 +1,469 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // homebridge-deconz/lib/DeconzService/Sensor.js
         
     | 
| 
      
 2 
     | 
    
         
            +
            // Copyright © 2022 Erik Baauw. All rights reserved.
         
     | 
| 
      
 3 
     | 
    
         
            +
            //
         
     | 
| 
      
 4 
     | 
    
         
            +
            // Homebridge plugin for deCONZ.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            'use strict'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            const homebridgeLib = require('homebridge-lib')
         
     | 
| 
      
 9 
     | 
    
         
            +
            const Deconz = require('../Deconz')
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            const { dateToString } = Deconz.ApiClient
         
     | 
| 
      
 12 
     | 
    
         
            +
            const { timeout } = homebridgeLib
         
     | 
| 
      
 13 
     | 
    
         
            +
            const { xyToHsv, hsvToXy, ctToXy } = homebridgeLib.Colour
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            class Light extends homebridgeLib.ServiceDelegate {
         
     | 
| 
      
 16 
     | 
    
         
            +
              constructor (accessory, resource) {
         
     | 
| 
      
 17 
     | 
    
         
            +
                super(accessory, {
         
     | 
| 
      
 18 
     | 
    
         
            +
                  id: resource.id,
         
     | 
| 
      
 19 
     | 
    
         
            +
                  name: resource.body.name,
         
     | 
| 
      
 20 
     | 
    
         
            +
                  subtype: resource.subtype,
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Service: accessory.Services.hap.Lightbulb
         
     | 
| 
      
 22 
     | 
    
         
            +
                })
         
     | 
| 
      
 23 
     | 
    
         
            +
                this.id = resource.id
         
     | 
| 
      
 24 
     | 
    
         
            +
                this.gateway = accessory.gateway
         
     | 
| 
      
 25 
     | 
    
         
            +
                this.client = accessory.client
         
     | 
| 
      
 26 
     | 
    
         
            +
                this.resource = resource
         
     | 
| 
      
 27 
     | 
    
         
            +
                this.rtype = resource.rtype
         
     | 
| 
      
 28 
     | 
    
         
            +
                this.rid = resource.rid
         
     | 
| 
      
 29 
     | 
    
         
            +
                this.rpath = resource.rpath +
         
     | 
| 
      
 30 
     | 
    
         
            +
                  (resource.rtype === 'groups' ? '/action' : '/state')
         
     | 
| 
      
 31 
     | 
    
         
            +
                this.capabilities = resource.capabilities
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                this.debug('%s: capabilities: %j', this.resource.rpath, this.capabilities)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                this.targetState = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
                this.deferrals = []
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                this.addCharacteristicDelegate({
         
     | 
| 
      
 39 
     | 
    
         
            +
                  key: 'on',
         
     | 
| 
      
 40 
     | 
    
         
            +
                  Characteristic: this.Characteristics.hap.On,
         
     | 
| 
      
 41 
     | 
    
         
            +
                  value: this.capabilities.on
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ? this.resource.body.state.on
         
     | 
| 
      
 43 
     | 
    
         
            +
                    : this.resource.body.state.all_on,
         
     | 
| 
      
 44 
     | 
    
         
            +
                  setter: async (value) => { return this.put({ on: value }) }
         
     | 
| 
      
 45 
     | 
    
         
            +
                }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 46 
     | 
    
         
            +
                  this.checkAdaptiveLighting()
         
     | 
| 
      
 47 
     | 
    
         
            +
                })
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                if (!this.capabilities.on) {
         
     | 
| 
      
 50 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 51 
     | 
    
         
            +
                    key: 'anyOn',
         
     | 
| 
      
 52 
     | 
    
         
            +
                    Characteristic: this.Characteristics.my.AnyOn,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    value: this.resource.body.state.any_on,
         
     | 
| 
      
 54 
     | 
    
         
            +
                    setter: async (value) => { return this.put({ on: value }) }
         
     | 
| 
      
 55 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 56 
     | 
    
         
            +
                    this.checkAdaptiveLighting()
         
     | 
| 
      
 57 
     | 
    
         
            +
                  })
         
     | 
| 
      
 58 
     | 
    
         
            +
                }
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                if (this.capabilities.bri) {
         
     | 
| 
      
 61 
     | 
    
         
            +
                  this.brightnessDelegate = this.addCharacteristicDelegate({
         
     | 
| 
      
 62 
     | 
    
         
            +
                    key: 'brightness',
         
     | 
| 
      
 63 
     | 
    
         
            +
                    Characteristic: this.Characteristics.hap.Brightness,
         
     | 
| 
      
 64 
     | 
    
         
            +
                    unit: '%',
         
     | 
| 
      
 65 
     | 
    
         
            +
                    value: this.resource.body.state.bri,
         
     | 
| 
      
 66 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 67 
     | 
    
         
            +
                      const bri = Math.round(value * 254.0 / 100.0)
         
     | 
| 
      
 68 
     | 
    
         
            +
                      return this.put({ bri: bri })
         
     | 
| 
      
 69 
     | 
    
         
            +
                    }
         
     | 
| 
      
 70 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 71 
     | 
    
         
            +
                    this.checkAdaptiveLighting()
         
     | 
| 
      
 72 
     | 
    
         
            +
                  })
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 75 
     | 
    
         
            +
                    key: 'brightnessChange',
         
     | 
| 
      
 76 
     | 
    
         
            +
                    Characteristic: this.Characteristics.my.BrightnessChange,
         
     | 
| 
      
 77 
     | 
    
         
            +
                    value: 0,
         
     | 
| 
      
 78 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 79 
     | 
    
         
            +
                      return this.put({ bri_inc: Math.round(value * 254.0 / 100.0) })
         
     | 
| 
      
 80 
     | 
    
         
            +
                    }
         
     | 
| 
      
 81 
     | 
    
         
            +
                  }).on('didSet', async () => {
         
     | 
| 
      
 82 
     | 
    
         
            +
                    await timeout(this.platform.config.waitTimeReset)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    this.values.brightnessChange = 0
         
     | 
| 
      
 84 
     | 
    
         
            +
                  })
         
     | 
| 
      
 85 
     | 
    
         
            +
                  this.values.brightnessChange = 0
         
     | 
| 
      
 86 
     | 
    
         
            +
                }
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                if (this.capabilities.ct || this.capabilities.xy || this.capabilities.hs) {
         
     | 
| 
      
 89 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 90 
     | 
    
         
            +
                    key: 'colormode',
         
     | 
| 
      
 91 
     | 
    
         
            +
                    value: this.resource.body.state.colormode
         
     | 
| 
      
 92 
     | 
    
         
            +
                  })
         
     | 
| 
      
 93 
     | 
    
         
            +
                }
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                if (this.capabilities.ct) {
         
     | 
| 
      
 96 
     | 
    
         
            +
                  this.colorTemperatureDelegate = this.addCharacteristicDelegate({
         
     | 
| 
      
 97 
     | 
    
         
            +
                    key: 'colorTemperature',
         
     | 
| 
      
 98 
     | 
    
         
            +
                    Characteristic: this.Characteristics.hap.ColorTemperature,
         
     | 
| 
      
 99 
     | 
    
         
            +
                    unit: ' mired',
         
     | 
| 
      
 100 
     | 
    
         
            +
                    props: {
         
     | 
| 
      
 101 
     | 
    
         
            +
                      minValue: this.capabilities.ctMin,
         
     | 
| 
      
 102 
     | 
    
         
            +
                      maxValue: this.capabilities.ctMax
         
     | 
| 
      
 103 
     | 
    
         
            +
                    },
         
     | 
| 
      
 104 
     | 
    
         
            +
                    value: this.resource.body.state.ct,
         
     | 
| 
      
 105 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 106 
     | 
    
         
            +
                      const ct = Math.max(
         
     | 
| 
      
 107 
     | 
    
         
            +
                        this.capabilities.ctMin, Math.min(value, this.capabilities.ctMax)
         
     | 
| 
      
 108 
     | 
    
         
            +
                      )
         
     | 
| 
      
 109 
     | 
    
         
            +
                      return this.put({ ct: ct })
         
     | 
| 
      
 110 
     | 
    
         
            +
                    }
         
     | 
| 
      
 111 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomeKit) => {
         
     | 
| 
      
 112 
     | 
    
         
            +
                    if (fromHomeKit) {
         
     | 
| 
      
 113 
     | 
    
         
            +
                      this.values.activeTransitionCount = 0
         
     | 
| 
      
 114 
     | 
    
         
            +
                    }
         
     | 
| 
      
 115 
     | 
    
         
            +
                    if (
         
     | 
| 
      
 116 
     | 
    
         
            +
                      this.capabilities.xy && !this.capabilities.computesXy &&
         
     | 
| 
      
 117 
     | 
    
         
            +
                      this.values.colormode === 'ct'
         
     | 
| 
      
 118 
     | 
    
         
            +
                    ) {
         
     | 
| 
      
 119 
     | 
    
         
            +
                      const { h, s } = xyToHsv(ctToXy(value), this.capabilities.gamut)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      this.values.hue = h
         
     | 
| 
      
 121 
     | 
    
         
            +
                      this.values.saturation = s
         
     | 
| 
      
 122 
     | 
    
         
            +
                    }
         
     | 
| 
      
 123 
     | 
    
         
            +
                  })
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  if (this.capabilities.bri) {
         
     | 
| 
      
 126 
     | 
    
         
            +
                    this.addCharacteristicDelegate({
         
     | 
| 
      
 127 
     | 
    
         
            +
                      key: 'supportedTransitionConfiguration',
         
     | 
| 
      
 128 
     | 
    
         
            +
                      Characteristic: this.Characteristics.hap
         
     | 
| 
      
 129 
     | 
    
         
            +
                        .SupportedCharacteristicValueTransitionConfiguration,
         
     | 
| 
      
 130 
     | 
    
         
            +
                      silent: true
         
     | 
| 
      
 131 
     | 
    
         
            +
                    })
         
     | 
| 
      
 132 
     | 
    
         
            +
                    this.addCharacteristicDelegate({
         
     | 
| 
      
 133 
     | 
    
         
            +
                      key: 'transitionControl',
         
     | 
| 
      
 134 
     | 
    
         
            +
                      Characteristic: this.Characteristics.hap
         
     | 
| 
      
 135 
     | 
    
         
            +
                        .CharacteristicValueTransitionControl,
         
     | 
| 
      
 136 
     | 
    
         
            +
                      silent: true,
         
     | 
| 
      
 137 
     | 
    
         
            +
                      getter: async () => {
         
     | 
| 
      
 138 
     | 
    
         
            +
                        await this.initAdaptiveLighting()
         
     | 
| 
      
 139 
     | 
    
         
            +
                        return this.adaptiveLighting.generateControl()
         
     | 
| 
      
 140 
     | 
    
         
            +
                      },
         
     | 
| 
      
 141 
     | 
    
         
            +
                      setter: async (value) => {
         
     | 
| 
      
 142 
     | 
    
         
            +
                        await this.initAdaptiveLighting()
         
     | 
| 
      
 143 
     | 
    
         
            +
                        this.adaptiveLighting.parseControl(value)
         
     | 
| 
      
 144 
     | 
    
         
            +
                        const response = this.adaptiveLighting.generateControlResponse()
         
     | 
| 
      
 145 
     | 
    
         
            +
                        this.values.activeTransitionCount = 1
         
     | 
| 
      
 146 
     | 
    
         
            +
                        return response
         
     | 
| 
      
 147 
     | 
    
         
            +
                      }
         
     | 
| 
      
 148 
     | 
    
         
            +
                    })
         
     | 
| 
      
 149 
     | 
    
         
            +
                    this.addCharacteristicDelegate({
         
     | 
| 
      
 150 
     | 
    
         
            +
                      key: 'activeTransitionCount',
         
     | 
| 
      
 151 
     | 
    
         
            +
                      Characteristic: this.Characteristics.hap
         
     | 
| 
      
 152 
     | 
    
         
            +
                        .CharacteristicValueActiveTransitionCount,
         
     | 
| 
      
 153 
     | 
    
         
            +
                      value: 0
         
     | 
| 
      
 154 
     | 
    
         
            +
                    }).on('didSet', (value) => {
         
     | 
| 
      
 155 
     | 
    
         
            +
                      if (!value) {
         
     | 
| 
      
 156 
     | 
    
         
            +
                        this.adaptiveLighting.deactivate()
         
     | 
| 
      
 157 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 158 
     | 
    
         
            +
                        this.checkAdaptiveLighting()
         
     | 
| 
      
 159 
     | 
    
         
            +
                      }
         
     | 
| 
      
 160 
     | 
    
         
            +
                    })
         
     | 
| 
      
 161 
     | 
    
         
            +
                  }
         
     | 
| 
      
 162 
     | 
    
         
            +
                }
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                if (this.capabilities.xy) {
         
     | 
| 
      
 165 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 166 
     | 
    
         
            +
                    key: 'hue',
         
     | 
| 
      
 167 
     | 
    
         
            +
                    Characteristic: this.Characteristics.hap.Hue,
         
     | 
| 
      
 168 
     | 
    
         
            +
                    unit: '°',
         
     | 
| 
      
 169 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 170 
     | 
    
         
            +
                      const xy = hsvToXy(value, this.values.saturation, this.capabilities.gamut)
         
     | 
| 
      
 171 
     | 
    
         
            +
                      return this.put({ xy: xy })
         
     | 
| 
      
 172 
     | 
    
         
            +
                    }
         
     | 
| 
      
 173 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 174 
     | 
    
         
            +
                    if (fromHomekit) {
         
     | 
| 
      
 175 
     | 
    
         
            +
                      this.values.activeTransitionCount = 0
         
     | 
| 
      
 176 
     | 
    
         
            +
                    }
         
     | 
| 
      
 177 
     | 
    
         
            +
                  })
         
     | 
| 
      
 178 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 179 
     | 
    
         
            +
                    key: 'saturation',
         
     | 
| 
      
 180 
     | 
    
         
            +
                    Characteristic: this.Characteristics.hap.Saturation,
         
     | 
| 
      
 181 
     | 
    
         
            +
                    unit: '%',
         
     | 
| 
      
 182 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 183 
     | 
    
         
            +
                      const xy = hsvToXy(this.values.hue, value, this.capabilities.gamut)
         
     | 
| 
      
 184 
     | 
    
         
            +
                      return this.put({ xy: xy })
         
     | 
| 
      
 185 
     | 
    
         
            +
                    }
         
     | 
| 
      
 186 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 187 
     | 
    
         
            +
                    if (fromHomekit) {
         
     | 
| 
      
 188 
     | 
    
         
            +
                      this.values.activeTransitionCount = 0
         
     | 
| 
      
 189 
     | 
    
         
            +
                    }
         
     | 
| 
      
 190 
     | 
    
         
            +
                  })
         
     | 
| 
      
 191 
     | 
    
         
            +
                } else if (this.capabilities.hs) {
         
     | 
| 
      
 192 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 193 
     | 
    
         
            +
                    key: 'hue',
         
     | 
| 
      
 194 
     | 
    
         
            +
                    Characteristic: this.Characteristics.hap.Hue,
         
     | 
| 
      
 195 
     | 
    
         
            +
                    unit: '°',
         
     | 
| 
      
 196 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 197 
     | 
    
         
            +
                      const hue = Math.round(this.hk.hue * 65535.0 / 360.0)
         
     | 
| 
      
 198 
     | 
    
         
            +
                      return this.put({ hue: hue })
         
     | 
| 
      
 199 
     | 
    
         
            +
                    }
         
     | 
| 
      
 200 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 201 
     | 
    
         
            +
                    if (fromHomekit) {
         
     | 
| 
      
 202 
     | 
    
         
            +
                      this.values.activeTransitionCount = 0
         
     | 
| 
      
 203 
     | 
    
         
            +
                    }
         
     | 
| 
      
 204 
     | 
    
         
            +
                  })
         
     | 
| 
      
 205 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 206 
     | 
    
         
            +
                    key: 'saturation',
         
     | 
| 
      
 207 
     | 
    
         
            +
                    Characteristic: this.Characteristics.hap.Saturation,
         
     | 
| 
      
 208 
     | 
    
         
            +
                    unit: '%',
         
     | 
| 
      
 209 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 210 
     | 
    
         
            +
                      const sat = Math.round(this.hk.sat * 254.0 / 100.0)
         
     | 
| 
      
 211 
     | 
    
         
            +
                      return this.put({ sat: sat })
         
     | 
| 
      
 212 
     | 
    
         
            +
                    }
         
     | 
| 
      
 213 
     | 
    
         
            +
                  }).on('didSet', (value, fromHomekit) => {
         
     | 
| 
      
 214 
     | 
    
         
            +
                    if (fromHomekit) {
         
     | 
| 
      
 215 
     | 
    
         
            +
                      this.values.activeTransitionCount = 0
         
     | 
| 
      
 216 
     | 
    
         
            +
                    }
         
     | 
| 
      
 217 
     | 
    
         
            +
                  })
         
     | 
| 
      
 218 
     | 
    
         
            +
                }
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                if (this.capabilities.colorLoop) {
         
     | 
| 
      
 221 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 222 
     | 
    
         
            +
                    key: 'colorLoop',
         
     | 
| 
      
 223 
     | 
    
         
            +
                    Characteristic: this.Characteristics.my.ColorLoop,
         
     | 
| 
      
 224 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 225 
     | 
    
         
            +
                      const effect = value ? 'colorloop' : 'none'
         
     | 
| 
      
 226 
     | 
    
         
            +
                      const state = { effect: effect }
         
     | 
| 
      
 227 
     | 
    
         
            +
                      if (value) {
         
     | 
| 
      
 228 
     | 
    
         
            +
                        state.colorloopspeed = this.values.colorLoopSpeed
         
     | 
| 
      
 229 
     | 
    
         
            +
                      }
         
     | 
| 
      
 230 
     | 
    
         
            +
                      return this.put(state)
         
     | 
| 
      
 231 
     | 
    
         
            +
                    }
         
     | 
| 
      
 232 
     | 
    
         
            +
                  })
         
     | 
| 
      
 233 
     | 
    
         
            +
                  this.addCharacteristicDelegate({
         
     | 
| 
      
 234 
     | 
    
         
            +
                    key: 'colorLoopSpeed',
         
     | 
| 
      
 235 
     | 
    
         
            +
                    Characteristic: this.Characteristics.my.ColorLoopSpeed,
         
     | 
| 
      
 236 
     | 
    
         
            +
                    unit: 's',
         
     | 
| 
      
 237 
     | 
    
         
            +
                    value: 25,
         
     | 
| 
      
 238 
     | 
    
         
            +
                    setter: async (value) => {
         
     | 
| 
      
 239 
     | 
    
         
            +
                      return this.put({ effect: 'colorloop', colorloopspeed: value })
         
     | 
| 
      
 240 
     | 
    
         
            +
                    }
         
     | 
| 
      
 241 
     | 
    
         
            +
                  })
         
     | 
| 
      
 242 
     | 
    
         
            +
                }
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                this.addCharacteristicDelegate({
         
     | 
| 
      
 245 
     | 
    
         
            +
                  key: 'lastSeen',
         
     | 
| 
      
 246 
     | 
    
         
            +
                  Characteristic: this.Characteristics.my.LastSeen
         
     | 
| 
      
 247 
     | 
    
         
            +
                })
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
                this.addCharacteristicDelegate({
         
     | 
| 
      
 250 
     | 
    
         
            +
                  key: 'statusFault',
         
     | 
| 
      
 251 
     | 
    
         
            +
                  Characteristic: this.Characteristics.hap.StatusFault
         
     | 
| 
      
 252 
     | 
    
         
            +
                })
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                this.settings = {
         
     | 
| 
      
 255 
     | 
    
         
            +
                  brightnessAdjustment: 1,
         
     | 
| 
      
 256 
     | 
    
         
            +
                  resetTimeout: this.platform.config.resetTimeout,
         
     | 
| 
      
 257 
     | 
    
         
            +
                  waitTimeUpdate: this.platform.config.waitTimeUpdate,
         
     | 
| 
      
 258 
     | 
    
         
            +
                  wallSwitch: false
         
     | 
| 
      
 259 
     | 
    
         
            +
                }
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                this.update(this.resource.body)
         
     | 
| 
      
 262 
     | 
    
         
            +
              }
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
              update (body) {
         
     | 
| 
      
 265 
     | 
    
         
            +
                for (const key in body) {
         
     | 
| 
      
 266 
     | 
    
         
            +
                  const value = body[key]
         
     | 
| 
      
 267 
     | 
    
         
            +
                  switch (key) {
         
     | 
| 
      
 268 
     | 
    
         
            +
                    case 'action':
         
     | 
| 
      
 269 
     | 
    
         
            +
                      // Copied to `state` by `Resource` during polling.
         
     | 
| 
      
 270 
     | 
    
         
            +
                      break
         
     | 
| 
      
 271 
     | 
    
         
            +
                    case 'state':
         
     | 
| 
      
 272 
     | 
    
         
            +
                      this.updateState(value)
         
     | 
| 
      
 273 
     | 
    
         
            +
                      break
         
     | 
| 
      
 274 
     | 
    
         
            +
                    case 'lastannounced':
         
     | 
| 
      
 275 
     | 
    
         
            +
                      // this.values.lastBoot = dateToString(value)
         
     | 
| 
      
 276 
     | 
    
         
            +
                      break
         
     | 
| 
      
 277 
     | 
    
         
            +
                    case 'lastseen':
         
     | 
| 
      
 278 
     | 
    
         
            +
                      this.values.lastSeen = dateToString(value)
         
     | 
| 
      
 279 
     | 
    
         
            +
                      break
         
     | 
| 
      
 280 
     | 
    
         
            +
                    case 'colorcapabilities':
         
     | 
| 
      
 281 
     | 
    
         
            +
                    case 'ctmax':
         
     | 
| 
      
 282 
     | 
    
         
            +
                    case 'ctmin':
         
     | 
| 
      
 283 
     | 
    
         
            +
                    case 'devicemembership':
         
     | 
| 
      
 284 
     | 
    
         
            +
                    case 'etag':
         
     | 
| 
      
 285 
     | 
    
         
            +
                    case 'id':
         
     | 
| 
      
 286 
     | 
    
         
            +
                    case 'lights':
         
     | 
| 
      
 287 
     | 
    
         
            +
                    case 'hascolor':
         
     | 
| 
      
 288 
     | 
    
         
            +
                    case 'manufacturername':
         
     | 
| 
      
 289 
     | 
    
         
            +
                    case 'modelid':
         
     | 
| 
      
 290 
     | 
    
         
            +
                    case 'name':
         
     | 
| 
      
 291 
     | 
    
         
            +
                    case 'powerup':
         
     | 
| 
      
 292 
     | 
    
         
            +
                    case 'scenes':
         
     | 
| 
      
 293 
     | 
    
         
            +
                    case 'swversion':
         
     | 
| 
      
 294 
     | 
    
         
            +
                    case 'type':
         
     | 
| 
      
 295 
     | 
    
         
            +
                    case 'uniqueid':
         
     | 
| 
      
 296 
     | 
    
         
            +
                      break
         
     | 
| 
      
 297 
     | 
    
         
            +
                    default:
         
     | 
| 
      
 298 
     | 
    
         
            +
                      this.warn('%s: unknown %s attribute', key, this.rtype)
         
     | 
| 
      
 299 
     | 
    
         
            +
                      break
         
     | 
| 
      
 300 
     | 
    
         
            +
                  }
         
     | 
| 
      
 301 
     | 
    
         
            +
                }
         
     | 
| 
      
 302 
     | 
    
         
            +
              }
         
     | 
| 
      
 303 
     | 
    
         
            +
             
     | 
| 
      
 304 
     | 
    
         
            +
              updateState (state) {
         
     | 
| 
      
 305 
     | 
    
         
            +
                for (const key in state) {
         
     | 
| 
      
 306 
     | 
    
         
            +
                  const value = state[key]
         
     | 
| 
      
 307 
     | 
    
         
            +
                  switch (key) {
         
     | 
| 
      
 308 
     | 
    
         
            +
                    case 'all_on':
         
     | 
| 
      
 309 
     | 
    
         
            +
                      this.values.on = value
         
     | 
| 
      
 310 
     | 
    
         
            +
                      break
         
     | 
| 
      
 311 
     | 
    
         
            +
                    case 'any_on':
         
     | 
| 
      
 312 
     | 
    
         
            +
                      this.values.anyOn = value
         
     | 
| 
      
 313 
     | 
    
         
            +
                      break
         
     | 
| 
      
 314 
     | 
    
         
            +
                    case 'alert':
         
     | 
| 
      
 315 
     | 
    
         
            +
                      break
         
     | 
| 
      
 316 
     | 
    
         
            +
                    case 'bri':
         
     | 
| 
      
 317 
     | 
    
         
            +
                      this.values.brightness = Math.round(value * 100.0 / 254.0)
         
     | 
| 
      
 318 
     | 
    
         
            +
                      break
         
     | 
| 
      
 319 
     | 
    
         
            +
                    case 'colormode':
         
     | 
| 
      
 320 
     | 
    
         
            +
                      this.values.colormode = value
         
     | 
| 
      
 321 
     | 
    
         
            +
                      break
         
     | 
| 
      
 322 
     | 
    
         
            +
                    case 'ct':
         
     | 
| 
      
 323 
     | 
    
         
            +
                      this.values.colorTemperature = value
         
     | 
| 
      
 324 
     | 
    
         
            +
                      break
         
     | 
| 
      
 325 
     | 
    
         
            +
                    case 'effect':
         
     | 
| 
      
 326 
     | 
    
         
            +
                      break
         
     | 
| 
      
 327 
     | 
    
         
            +
                    case 'hue':
         
     | 
| 
      
 328 
     | 
    
         
            +
                      if (!this.capabilities.xy) {
         
     | 
| 
      
 329 
     | 
    
         
            +
                        this.values.hue = value
         
     | 
| 
      
 330 
     | 
    
         
            +
                      }
         
     | 
| 
      
 331 
     | 
    
         
            +
                      break
         
     | 
| 
      
 332 
     | 
    
         
            +
                    case 'on':
         
     | 
| 
      
 333 
     | 
    
         
            +
                      this.values.on = value
         
     | 
| 
      
 334 
     | 
    
         
            +
                      break
         
     | 
| 
      
 335 
     | 
    
         
            +
                    case 'reachable':
         
     | 
| 
      
 336 
     | 
    
         
            +
                      this.values.statusFault = value
         
     | 
| 
      
 337 
     | 
    
         
            +
                        ? this.Characteristics.hap.StatusFault.NO_FAULT
         
     | 
| 
      
 338 
     | 
    
         
            +
                        : this.Characteristics.hap.StatusFault.GENERAL_FAULT
         
     | 
| 
      
 339 
     | 
    
         
            +
                      break
         
     | 
| 
      
 340 
     | 
    
         
            +
                    case 'sat':
         
     | 
| 
      
 341 
     | 
    
         
            +
                      if (!this.capabilities.xy) {
         
     | 
| 
      
 342 
     | 
    
         
            +
                        this.values.hue = value
         
     | 
| 
      
 343 
     | 
    
         
            +
                      }
         
     | 
| 
      
 344 
     | 
    
         
            +
                      break
         
     | 
| 
      
 345 
     | 
    
         
            +
                    case 'scene':
         
     | 
| 
      
 346 
     | 
    
         
            +
                      break
         
     | 
| 
      
 347 
     | 
    
         
            +
                    case 'xy':
         
     | 
| 
      
 348 
     | 
    
         
            +
                      if (this.values.colormode !== 'ct' || this.capabilities.computesXy) {
         
     | 
| 
      
 349 
     | 
    
         
            +
                        const { h, s } = xyToHsv(value, this.capabilities.gamut)
         
     | 
| 
      
 350 
     | 
    
         
            +
                        this.values.hue = h
         
     | 
| 
      
 351 
     | 
    
         
            +
                        this.values.saturation = s
         
     | 
| 
      
 352 
     | 
    
         
            +
                      }
         
     | 
| 
      
 353 
     | 
    
         
            +
                      break
         
     | 
| 
      
 354 
     | 
    
         
            +
                    default:
         
     | 
| 
      
 355 
     | 
    
         
            +
                      this.warn('state.%s: unknown %s attribute', key, this.rtype)
         
     | 
| 
      
 356 
     | 
    
         
            +
                      break
         
     | 
| 
      
 357 
     | 
    
         
            +
                  }
         
     | 
| 
      
 358 
     | 
    
         
            +
                }
         
     | 
| 
      
 359 
     | 
    
         
            +
              }
         
     | 
| 
      
 360 
     | 
    
         
            +
             
     | 
| 
      
 361 
     | 
    
         
            +
              async identify () {
         
     | 
| 
      
 362 
     | 
    
         
            +
                try {
         
     | 
| 
      
 363 
     | 
    
         
            +
                  if (this.capabilities.alert) {
         
     | 
| 
      
 364 
     | 
    
         
            +
                    if (this.capabilities.breathe) {
         
     | 
| 
      
 365 
     | 
    
         
            +
                      await this.put({ alert: 'breathe' })
         
     | 
| 
      
 366 
     | 
    
         
            +
                      await timeout(1500)
         
     | 
| 
      
 367 
     | 
    
         
            +
                      return this.put({ alert: 'stop' })
         
     | 
| 
      
 368 
     | 
    
         
            +
                    }
         
     | 
| 
      
 369 
     | 
    
         
            +
                    return this.put({ alert: 'select' })
         
     | 
| 
      
 370 
     | 
    
         
            +
                  }
         
     | 
| 
      
 371 
     | 
    
         
            +
                } catch (error) { this.warn(error) }
         
     | 
| 
      
 372 
     | 
    
         
            +
              }
         
     | 
| 
      
 373 
     | 
    
         
            +
             
     | 
| 
      
 374 
     | 
    
         
            +
              async initAdaptiveLighting () {
         
     | 
| 
      
 375 
     | 
    
         
            +
                if (this.adaptiveLighting == null) {
         
     | 
| 
      
 376 
     | 
    
         
            +
                  this.adaptiveLighting = new homebridgeLib.AdaptiveLighting(
         
     | 
| 
      
 377 
     | 
    
         
            +
                    this.brightnessDelegate, this.colorTemperatureDelegate
         
     | 
| 
      
 378 
     | 
    
         
            +
                  )
         
     | 
| 
      
 379 
     | 
    
         
            +
                  this.values.supportedTransitionConfiguration =
         
     | 
| 
      
 380 
     | 
    
         
            +
                    this.adaptiveLighting.generateConfiguration()
         
     | 
| 
      
 381 
     | 
    
         
            +
                  if (
         
     | 
| 
      
 382 
     | 
    
         
            +
                    this.values.activeTransitionCount === 1 &&
         
     | 
| 
      
 383 
     | 
    
         
            +
                    this.values.transitionControl != null
         
     | 
| 
      
 384 
     | 
    
         
            +
                  ) {
         
     | 
| 
      
 385 
     | 
    
         
            +
                    this.adaptiveLighting.parseControl(this.values.transitionControl)
         
     | 
| 
      
 386 
     | 
    
         
            +
                  }
         
     | 
| 
      
 387 
     | 
    
         
            +
                }
         
     | 
| 
      
 388 
     | 
    
         
            +
              }
         
     | 
| 
      
 389 
     | 
    
         
            +
             
     | 
| 
      
 390 
     | 
    
         
            +
              async checkAdaptiveLighting () {
         
     | 
| 
      
 391 
     | 
    
         
            +
                if (this.adaptiveLighting == null || !this.values.on) {
         
     | 
| 
      
 392 
     | 
    
         
            +
                  return
         
     | 
| 
      
 393 
     | 
    
         
            +
                }
         
     | 
| 
      
 394 
     | 
    
         
            +
                const ct = this.adaptiveLighting.getCt(
         
     | 
| 
      
 395 
     | 
    
         
            +
                  this.values.brightness * this.settings.brightnessAdjustment
         
     | 
| 
      
 396 
     | 
    
         
            +
                )
         
     | 
| 
      
 397 
     | 
    
         
            +
                if (ct == null || ct === this.values.ct) {
         
     | 
| 
      
 398 
     | 
    
         
            +
                  return
         
     | 
| 
      
 399 
     | 
    
         
            +
                }
         
     | 
| 
      
 400 
     | 
    
         
            +
                return this.put({ ct: ct })
         
     | 
| 
      
 401 
     | 
    
         
            +
              }
         
     | 
| 
      
 402 
     | 
    
         
            +
             
     | 
| 
      
 403 
     | 
    
         
            +
              // Collect changes into a combined request.
         
     | 
| 
      
 404 
     | 
    
         
            +
              async put (state) {
         
     | 
| 
      
 405 
     | 
    
         
            +
                return new Promise((resolve, reject) => {
         
     | 
| 
      
 406 
     | 
    
         
            +
                  for (const key in state) {
         
     | 
| 
      
 407 
     | 
    
         
            +
                    this.targetState[key] = state[key]
         
     | 
| 
      
 408 
     | 
    
         
            +
                  }
         
     | 
| 
      
 409 
     | 
    
         
            +
                  const d = { resolve: resolve, reject: reject }
         
     | 
| 
      
 410 
     | 
    
         
            +
                  this.deferrals.push(d)
         
     | 
| 
      
 411 
     | 
    
         
            +
                  if (this.updating) {
         
     | 
| 
      
 412 
     | 
    
         
            +
                    return
         
     | 
| 
      
 413 
     | 
    
         
            +
                  }
         
     | 
| 
      
 414 
     | 
    
         
            +
                  this.updating = true
         
     | 
| 
      
 415 
     | 
    
         
            +
                  if (this.settings.waitTimeUpdate > 0) {
         
     | 
| 
      
 416 
     | 
    
         
            +
                    setTimeout(() => {
         
     | 
| 
      
 417 
     | 
    
         
            +
                      this._put()
         
     | 
| 
      
 418 
     | 
    
         
            +
                    }, this.settings.waitTimeUpdate)
         
     | 
| 
      
 419 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 420 
     | 
    
         
            +
                    this._put()
         
     | 
| 
      
 421 
     | 
    
         
            +
                  }
         
     | 
| 
      
 422 
     | 
    
         
            +
                })
         
     | 
| 
      
 423 
     | 
    
         
            +
              }
         
     | 
| 
      
 424 
     | 
    
         
            +
             
     | 
| 
      
 425 
     | 
    
         
            +
              // Send the request (for the combined changes) to the gateway.
         
     | 
| 
      
 426 
     | 
    
         
            +
              async _put () {
         
     | 
| 
      
 427 
     | 
    
         
            +
                const targetState = this.targetState
         
     | 
| 
      
 428 
     | 
    
         
            +
                const deferrals = this.deferrals
         
     | 
| 
      
 429 
     | 
    
         
            +
                this.targetState = {}
         
     | 
| 
      
 430 
     | 
    
         
            +
                this.deferrals = []
         
     | 
| 
      
 431 
     | 
    
         
            +
                this.updating = false
         
     | 
| 
      
 432 
     | 
    
         
            +
                if (
         
     | 
| 
      
 433 
     | 
    
         
            +
                  this.gateway.transitionTime !== this.gateway.defaultTransitionTime &&
         
     | 
| 
      
 434 
     | 
    
         
            +
                  targetState.transitiontime === undefined
         
     | 
| 
      
 435 
     | 
    
         
            +
                ) {
         
     | 
| 
      
 436 
     | 
    
         
            +
                  targetState.transitiontime = this.gateway.transitionTime * 10
         
     | 
| 
      
 437 
     | 
    
         
            +
                  this.gateway.resetTransitionTime()
         
     | 
| 
      
 438 
     | 
    
         
            +
                }
         
     | 
| 
      
 439 
     | 
    
         
            +
                if (this.capabilities.noTransition) {
         
     | 
| 
      
 440 
     | 
    
         
            +
                  if (
         
     | 
| 
      
 441 
     | 
    
         
            +
                    (
         
     | 
| 
      
 442 
     | 
    
         
            +
                      targetState.on != null || targetState.bri != null ||
         
     | 
| 
      
 443 
     | 
    
         
            +
                      targetState.bri_inc != null
         
     | 
| 
      
 444 
     | 
    
         
            +
                    ) && (
         
     | 
| 
      
 445 
     | 
    
         
            +
                      targetState.xy != null || targetState.ct != null ||
         
     | 
| 
      
 446 
     | 
    
         
            +
                      targetState.hue != null || targetState.sat != null ||
         
     | 
| 
      
 447 
     | 
    
         
            +
                      targetState.effect != null
         
     | 
| 
      
 448 
     | 
    
         
            +
                    )
         
     | 
| 
      
 449 
     | 
    
         
            +
                  ) {
         
     | 
| 
      
 450 
     | 
    
         
            +
                    targetState.transitiontime = 0
         
     | 
| 
      
 451 
     | 
    
         
            +
                  }
         
     | 
| 
      
 452 
     | 
    
         
            +
                }
         
     | 
| 
      
 453 
     | 
    
         
            +
                this.client.put(this.rpath, targetState).then((obj) => {
         
     | 
| 
      
 454 
     | 
    
         
            +
                  this.recentlyUpdated = true
         
     | 
| 
      
 455 
     | 
    
         
            +
                  for (const d of deferrals) {
         
     | 
| 
      
 456 
     | 
    
         
            +
                    d.resolve(true)
         
     | 
| 
      
 457 
     | 
    
         
            +
                  }
         
     | 
| 
      
 458 
     | 
    
         
            +
                  setTimeout(() => {
         
     | 
| 
      
 459 
     | 
    
         
            +
                    this.recentlyUpdated = false
         
     | 
| 
      
 460 
     | 
    
         
            +
                  }, 500)
         
     | 
| 
      
 461 
     | 
    
         
            +
                }).catch((error) => {
         
     | 
| 
      
 462 
     | 
    
         
            +
                  for (const d of deferrals) {
         
     | 
| 
      
 463 
     | 
    
         
            +
                    d.reject(error)
         
     | 
| 
      
 464 
     | 
    
         
            +
                  }
         
     | 
| 
      
 465 
     | 
    
         
            +
                })
         
     | 
| 
      
 466 
     | 
    
         
            +
              }
         
     | 
| 
      
 467 
     | 
    
         
            +
            }
         
     | 
| 
      
 468 
     | 
    
         
            +
             
     | 
| 
      
 469 
     | 
    
         
            +
            module.exports = Light
         
     | 
| 
         @@ -6,7 +6,7 @@ 
     | 
|
| 
       6 
6 
     | 
    
         
             
            'use strict'
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            const homebridgeLib = require('homebridge-lib')
         
     | 
| 
       9 
     | 
    
         
            -
            const  
     | 
| 
      
 9 
     | 
    
         
            +
            const Deconz = require('../Deconz')
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            /**
         
     | 
| 
       12 
12 
     | 
    
         
             
              * @memberof DeconzService
         
     | 
| 
         @@ -46,7 +46,7 @@ class Sensor extends homebridgeLib.ServiceDelegate { 
     | 
|
| 
       46 
46 
     | 
    
         
             
              }
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
              update (sensor) {
         
     | 
| 
       49 
     | 
    
         
            -
                this.values.lastUpdated =  
     | 
| 
      
 49 
     | 
    
         
            +
                this.values.lastUpdated = Deconz.Client.dateToString(sensor.state.lastupdated)
         
     | 
| 
       50 
50 
     | 
    
         
             
                this.values.enabled = sensor.config.on
         
     | 
| 
       51 
51 
     | 
    
         
             
                this.values.statusFault = sensor.config.reachable === false
         
     | 
| 
       52 
52 
     | 
    
         
             
                  ? this.Characteristics.hap.StatusFault.GENERAL_FAULT
         
     | 
| 
         @@ -22,7 +22,7 @@ class DeconzService { 
     | 
|
| 
       22 
22 
     | 
    
         
             
              static get GatewaySettings () { return require('./GatewaySettings') }
         
     | 
| 
       23 
23 
     | 
    
         
             
              // static get Humidity () { return require('./Humidity') }
         
     | 
| 
       24 
24 
     | 
    
         
             
              // static get Light () { return require('./Light') }
         
     | 
| 
       25 
     | 
    
         
            -
               
     | 
| 
      
 25 
     | 
    
         
            +
              static get Light () { return require('./Light') }
         
     | 
| 
       26 
26 
     | 
    
         
             
              // static get LightLevel () { return require('./LightLevel') }
         
     | 
| 
       27 
27 
     | 
    
         
             
              // static get Outlet () { return require('./Outlet') }
         
     | 
| 
       28 
28 
     | 
    
         
             
              // static get OpenClose () { return require('./OpenClose') }
         
     | 
    
        package/package.json
    CHANGED
    
    | 
         @@ -4,7 +4,7 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
              "displayName": "Homebridge deCONZ",
         
     | 
| 
       5 
5 
     | 
    
         
             
              "author": "Erik Baauw",
         
     | 
| 
       6 
6 
     | 
    
         
             
              "license": "Apache-2.0",
         
     | 
| 
       7 
     | 
    
         
            -
              "version": "0.0. 
     | 
| 
      
 7 
     | 
    
         
            +
              "version": "0.0.9",
         
     | 
| 
       8 
8 
     | 
    
         
             
              "keywords": [
         
     | 
| 
       9 
9 
     | 
    
         
             
                "homebridge-plugin",
         
     | 
| 
       10 
10 
     | 
    
         
             
                "homekit",
         
     | 
| 
         @@ -25,7 +25,7 @@ 
     | 
|
| 
       25 
25 
     | 
    
         
             
                "node": "^16.13.2"
         
     | 
| 
       26 
26 
     | 
    
         
             
              },
         
     | 
| 
       27 
27 
     | 
    
         
             
              "dependencies": {
         
     | 
| 
       28 
     | 
    
         
            -
                "homebridge-lib": "~5.1.24- 
     | 
| 
      
 28 
     | 
    
         
            +
                "homebridge-lib": "~5.1.24-6",
         
     | 
| 
       29 
29 
     | 
    
         
             
                "semver": "^7.3.5",
         
     | 
| 
       30 
30 
     | 
    
         
             
                "ws": "^8.4.2",
         
     | 
| 
       31 
31 
     | 
    
         
             
                "xml2js": "~0.4.23"
         
     |