homebridge-deconz 0.1.9 → 0.1.10
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/lib/Deconz/Resource.js +7 -138
- package/lib/DeconzAccessory/Light.js +8 -8
- package/lib/DeconzAccessory/index.js +6 -1
- package/lib/DeconzService/AirQuality.js +60 -29
- package/lib/DeconzService/Consumption.js +5 -5
- package/lib/DeconzService/Light.js +72 -71
- package/lib/DeconzService/Power.js +6 -5
- package/package.json +4 -4
    
        package/lib/Deconz/Resource.js
    CHANGED
    
    | @@ -30,51 +30,6 @@ const sensorsPrios = [ | |
| 30 30 |  | 
| 31 31 | 
             
            // =============================================================================
         | 
| 32 32 |  | 
| 33 | 
            -
            // See: http://www.developers.meethue.com/documentation/supported-lights
         | 
| 34 | 
            -
             | 
| 35 | 
            -
            const hueGamutType = { // Color gamut per light model.
         | 
| 36 | 
            -
              A: { // Color Lights
         | 
| 37 | 
            -
                r: [0.7040, 0.2960],
         | 
| 38 | 
            -
                g: [0.2151, 0.7106],
         | 
| 39 | 
            -
                b: [0.1380, 0.0800]
         | 
| 40 | 
            -
              },
         | 
| 41 | 
            -
              B: { // Extended Color Lights
         | 
| 42 | 
            -
                r: [0.6750, 0.3220],
         | 
| 43 | 
            -
                g: [0.4090, 0.5180],
         | 
| 44 | 
            -
                b: [0.1670, 0.0400]
         | 
| 45 | 
            -
              },
         | 
| 46 | 
            -
              C: { // next gen Extended Color Lights
         | 
| 47 | 
            -
                r: [0.6920, 0.3080],
         | 
| 48 | 
            -
                g: [0.1700, 0.7000],
         | 
| 49 | 
            -
                b: [0.1530, 0.0480]
         | 
| 50 | 
            -
              }
         | 
| 51 | 
            -
            }
         | 
| 52 | 
            -
             | 
| 53 | 
            -
            const hueGamutTypeByModel = {
         | 
| 54 | 
            -
              LCT001: 'B', // Hue bulb A19
         | 
| 55 | 
            -
              LCT002: 'B', // Hue Spot BR30
         | 
| 56 | 
            -
              LCT003: 'B', // Hue Spot GU10
         | 
| 57 | 
            -
              LCT007: 'B', // Hue bulb A19
         | 
| 58 | 
            -
              LCT010: 'C', // Hue bulb A19
         | 
| 59 | 
            -
              LCT011: 'C', // Hue BR30
         | 
| 60 | 
            -
              LCT012: 'C', // Hue Color Candle
         | 
| 61 | 
            -
              LCT014: 'C', // Hue bulb A19
         | 
| 62 | 
            -
              LCT015: 'C', // Hue bulb A19
         | 
| 63 | 
            -
              LCT016: 'C', // Hue bulb A19
         | 
| 64 | 
            -
              LLC005: 'A', // Living Colors Gen3 Bloom, Aura
         | 
| 65 | 
            -
              LLC006: 'A', // Living Colors Gen3 Iris
         | 
| 66 | 
            -
              LLC007: 'A', // Living Colors Gen3 Bloom, Aura
         | 
| 67 | 
            -
              LLC010: 'A', // Hue Living Colors Iris
         | 
| 68 | 
            -
              LLC011: 'A', // Hue Living Colors Bloom
         | 
| 69 | 
            -
              LLC012: 'A', // Hue Living Colors Bloom
         | 
| 70 | 
            -
              LLC013: 'A', // Disney Living Colors
         | 
| 71 | 
            -
              LLC014: 'A', // Living Colors Gen3 Bloom, Aura
         | 
| 72 | 
            -
              LLC020: 'C', // Hue Go
         | 
| 73 | 
            -
              LLM001: 'B', // Color Light Module
         | 
| 74 | 
            -
              LST001: 'A', // Hue LightStrips
         | 
| 75 | 
            -
              LST002: 'C' // Hue LightStrips Plus
         | 
| 76 | 
            -
            }
         | 
| 77 | 
            -
             | 
| 78 33 | 
             
            const hueTapMap = {
         | 
| 79 34 | 
             
              34: 1002, // press 1
         | 
| 80 35 | 
             
              16: 2002, // press 2
         | 
| @@ -240,9 +195,7 @@ class Resource { | |
| 240 195 | 
             
                          this.capabilities.ctMin = cap.color.ct.min
         | 
| 241 196 | 
             
                        }
         | 
| 242 197 | 
             
                        if (cap.color.effects != null && cap.color.effects.length > 2) {
         | 
| 243 | 
            -
                          this.capabilities.effects = cap.color.effects.slice(2) | 
| 244 | 
            -
                            return effect[0].toUpperCase() + effect.slice(1)
         | 
| 245 | 
            -
                          })
         | 
| 198 | 
            +
                          this.capabilities.effects = cap.color.effects.slice(2)
         | 
| 246 199 | 
             
                        }
         | 
| 247 200 | 
             
                        if (cap.color.xy != null) {
         | 
| 248 201 | 
             
                          this.capabilities.gamut = {
         | 
| @@ -386,34 +339,7 @@ class Resource { | |
| 386 339 | 
             
                */
         | 
| 387 340 | 
             
              patchLight (gateway) {
         | 
| 388 341 | 
             
                switch (this.manufacturer) {
         | 
| 389 | 
            -
                  case 'Busch-Jaeger':
         | 
| 390 | 
            -
                    // See: https://www.busch-jaeger.de/en/products/product-solutions/dimmer/busch-radio-controlled-dimmer-zigbee-light-link/
         | 
| 391 | 
            -
                    if (
         | 
| 392 | 
            -
                      this.model === 'RM01' && // 6715 U-500 with 6736-84.
         | 
| 393 | 
            -
                      this.capabilities.bri && this.body.type === 'On/Off light' // Issue #241
         | 
| 394 | 
            -
                    ) {
         | 
| 395 | 
            -
                      gateway.vdebug(
         | 
| 396 | 
            -
                        '%s: ignoring state.bri for %s', this.rpath, this.body.type
         | 
| 397 | 
            -
                      )
         | 
| 398 | 
            -
                      this.capabilities.bri = false
         | 
| 399 | 
            -
                    }
         | 
| 400 | 
            -
                    break
         | 
| 401 | 
            -
                  case 'dresden elektronik':
         | 
| 402 | 
            -
                    // See: https://www.dresden-elektronik.de/funktechnik/solutions/wireless-light-control/wireless-ballasts/?L=1
         | 
| 403 | 
            -
                    this.capabilities.computesXy = true
         | 
| 404 | 
            -
                    break
         | 
| 405 | 
            -
                  case 'FeiBit':
         | 
| 406 | 
            -
                    if (this.model === 'FNB56-SKT1EHG1.2') { // issue #361
         | 
| 407 | 
            -
                      this.body.type = 'On/Off plug-in unit'
         | 
| 408 | 
            -
                    }
         | 
| 409 | 
            -
                    break
         | 
| 410 342 | 
             
                  case 'GLEDOPTO':
         | 
| 411 | 
            -
                    // See: https://www.led-trading.de/zigbee-kompatibel-controller-led-lichtsteuerung
         | 
| 412 | 
            -
                    this.capabilities.gamut = {
         | 
| 413 | 
            -
                      r: [0.7006, 0.2993],
         | 
| 414 | 
            -
                      g: [0.1387, 0.8148],
         | 
| 415 | 
            -
                      b: [0.1510, 0.0227]
         | 
| 416 | 
            -
                    }
         | 
| 417 343 | 
             
                    if (this.model === 'GLEDOPTO') { // Issue #244
         | 
| 418 344 | 
             
                      if (
         | 
| 419 345 | 
             
                        this.endpoint === '0A' &&
         | 
| @@ -444,37 +370,6 @@ class Resource { | |
| 444 370 | 
             
                      gateway.vdebug('%s: set model to %j', this.rpath, this.model)
         | 
| 445 371 | 
             
                    }
         | 
| 446 372 | 
             
                    break
         | 
| 447 | 
            -
                  case 'IKEA of Sweden':
         | 
| 448 | 
            -
                    // See: http://www.ikea.com/us/en/catalog/categories/departments/lighting/smart_lighting/
         | 
| 449 | 
            -
                    this.capabilities.gamut = defaultGamut // Issue #956
         | 
| 450 | 
            -
                    this.capabilities.noTransition = true
         | 
| 451 | 
            -
                    if (this.model === 'TRADFRI bulb E27 CWS 806lm') {
         | 
| 452 | 
            -
                      this.capabilities.computesXy = true
         | 
| 453 | 
            -
                      this.capabilities.gamut = {
         | 
| 454 | 
            -
                        r: [0.68, 0.31],
         | 
| 455 | 
            -
                        g: [0.11, 0.82],
         | 
| 456 | 
            -
                        b: [0.13, 0.04]
         | 
| 457 | 
            -
                      }
         | 
| 458 | 
            -
                    }
         | 
| 459 | 
            -
                    break
         | 
| 460 | 
            -
                  case 'innr':
         | 
| 461 | 
            -
                    // See: https://shop.innrlighting.com/en/shop
         | 
| 462 | 
            -
                    this.capabilities.gamut = { // Issue #152
         | 
| 463 | 
            -
                      r: [0.8817, 0.1033],
         | 
| 464 | 
            -
                      g: [0.2204, 0.7758],
         | 
| 465 | 
            -
                      b: [0.0551, 0.1940]
         | 
| 466 | 
            -
                    }
         | 
| 467 | 
            -
                    if (this.model === 'SP 120') { // smart plug
         | 
| 468 | 
            -
                      this.capabilities.bri = false
         | 
| 469 | 
            -
                    }
         | 
| 470 | 
            -
                    break
         | 
| 471 | 
            -
                  case 'LEDVANCE':
         | 
| 472 | 
            -
                    this.capabilities.gamut = {
         | 
| 473 | 
            -
                      r: [0.6972, 0.3027],
         | 
| 474 | 
            -
                      g: [0.1737, 0.6991],
         | 
| 475 | 
            -
                      b: [0.1227, 0.0959]
         | 
| 476 | 
            -
                    }
         | 
| 477 | 
            -
                    break
         | 
| 478 373 | 
             
                  case 'LIDL Livarno Lux':
         | 
| 479 374 | 
             
                    this.capabilities.ctMax = 454 // 2200 K
         | 
| 480 375 | 
             
                    this.capabilities.ctMin = 153 // 6500 K
         | 
| @@ -489,36 +384,6 @@ class Resource { | |
| 489 384 | 
             
                      ]
         | 
| 490 385 | 
             
                    }
         | 
| 491 386 | 
             
                    break
         | 
| 492 | 
            -
                  case 'MLI': // Issue #439
         | 
| 493 | 
            -
                    this.capabilities.gamut = {
         | 
| 494 | 
            -
                      r: [0.68, 0.31],
         | 
| 495 | 
            -
                      g: [0.11, 0.82],
         | 
| 496 | 
            -
                      b: [0.13, 0.04]
         | 
| 497 | 
            -
                    }
         | 
| 498 | 
            -
                    if (this.capabilities.colorLoop) {
         | 
| 499 | 
            -
                      this.capabilities.effects = [
         | 
| 500 | 
            -
                        'Sunset', 'Party', 'Worklight', 'Campfire', 'Romance', 'Nightlight'
         | 
| 501 | 
            -
                      ]
         | 
| 502 | 
            -
                    }
         | 
| 503 | 
            -
                    break
         | 
| 504 | 
            -
                  case 'OSRAM':
         | 
| 505 | 
            -
                    this.capabilities.gamut = {
         | 
| 506 | 
            -
                      r: [0.6850, 0.3149],
         | 
| 507 | 
            -
                      g: [0.1780, 0.7253],
         | 
| 508 | 
            -
                      b: [0.1241, 0.0578]
         | 
| 509 | 
            -
                    }
         | 
| 510 | 
            -
                    break
         | 
| 511 | 
            -
                  case 'Philips':
         | 
| 512 | 
            -
                  case 'Signify Netherlands B.V.':
         | 
| 513 | 
            -
                    // See: http://www.developers.meethue.com/documentation/supported-lights
         | 
| 514 | 
            -
                    this.manufacturer = 'Signify Netherlands B.V.'
         | 
| 515 | 
            -
                    this.capabilities.breathe = true
         | 
| 516 | 
            -
                    this.capabilities.computesXy = true
         | 
| 517 | 
            -
                    if (this.body.capabilities == null) {
         | 
| 518 | 
            -
                      const gamut = hueGamutTypeByModel[this.model] || 'C'
         | 
| 519 | 
            -
                      this.capabilities.gamut = hueGamutType[gamut]
         | 
| 520 | 
            -
                    }
         | 
| 521 | 
            -
                    break
         | 
| 522 387 | 
             
                  default:
         | 
| 523 388 | 
             
                    break
         | 
| 524 389 | 
             
                }
         | 
| @@ -784,12 +649,16 @@ class Resource { | |
| 784 649 | 
             
                          }
         | 
| 785 650 | 
             
                        }
         | 
| 786 651 | 
             
                        break
         | 
| 787 | 
            -
                      case 'lumi.sensor_86sw1': // Xiaomi wall switch (single button)
         | 
| 788 652 | 
             
                      case 'lumi.ctrl_ln1.aq1':
         | 
| 653 | 
            +
                      case 'lumi.sensor_86sw1': // Xiaomi wall switch (single button).
         | 
| 654 | 
            +
                      case 'lumi.switch.l1aeu1': // Xiaomi Aqara H1, see #1149.
         | 
| 655 | 
            +
                      case 'lumi.switch.n1aeu1': // Xiaomi Aqara H1, see #1149.
         | 
| 789 656 | 
             
                        buttons.push([1, 'Button', SINGLE | DOUBLE])
         | 
| 790 657 | 
             
                        break
         | 
| 791 | 
            -
                      case 'lumi.sensor_86sw2': // Xiaomi wall switch (two buttons)
         | 
| 792 658 | 
             
                      case 'lumi.ctrl_ln2.aq1':
         | 
| 659 | 
            +
                      case 'lumi.sensor_86sw2': // Xiaomi wall switch (two buttons).
         | 
| 660 | 
            +
                      case 'lumi.switch.l2aeu1': // Xiaomi Aqara H2, see #1149.
         | 
| 661 | 
            +
                      case 'lumi.switch.n2aeu1': // Xiaomi Aqara H2, see #1149.
         | 
| 793 662 | 
             
                        buttons.push([1, 'Left', SINGLE | DOUBLE])
         | 
| 794 663 | 
             
                        buttons.push([2, 'Right', SINGLE | DOUBLE])
         | 
| 795 664 | 
             
                        buttons.push([3, 'Both', SINGLE | DOUBLE])
         | 
| @@ -66,19 +66,19 @@ class Light extends DeconzAccessory { | |
| 66 66 | 
             
                  })
         | 
| 67 67 | 
             
                }
         | 
| 68 68 | 
             
                if (this.serviceByServiceName.Consumption != null) {
         | 
| 69 | 
            -
                  params. | 
| 70 | 
            -
                  if (this.service.values. | 
| 71 | 
            -
                    //  | 
| 72 | 
            -
                    params. | 
| 73 | 
            -
                      key: ' | 
| 74 | 
            -
                      Characteristic: this.Characteristics.eve. | 
| 69 | 
            +
                  params.totalConsumptionDelegate = this.service.characteristicDelegate('totalConsumption')
         | 
| 70 | 
            +
                  if (this.service.values.consumption === undefined) {
         | 
| 71 | 
            +
                    // Power to be computed by history if not exposed by device
         | 
| 72 | 
            +
                    params.computedConsumptionDelegate = this.service.addCharacteristicDelegate({
         | 
| 73 | 
            +
                      key: 'consumption',
         | 
| 74 | 
            +
                      Characteristic: this.Characteristics.eve.Consumption,
         | 
| 75 75 | 
             
                      unit: ' W'
         | 
| 76 76 | 
             
                    })
         | 
| 77 77 | 
             
                  }
         | 
| 78 78 | 
             
                } else if (this.serviceByServiceName.Power != null) {
         | 
| 79 | 
            -
                  params. | 
| 79 | 
            +
                  params.consumptionDelegate = this.service.characteristicDelegate('consumption')
         | 
| 80 80 | 
             
                  // Total Consumption to be computed by history
         | 
| 81 | 
            -
                  params. | 
| 81 | 
            +
                  params.computedTotalConsumptionDelegate = this.service.addCharacteristicDelegate({
         | 
| 82 82 | 
             
                    key: 'totalConsumption',
         | 
| 83 83 | 
             
                    Characteristic: this.Characteristics.eve.TotalConsumption,
         | 
| 84 84 | 
             
                    unit: ' kWh'
         | 
| @@ -139,7 +139,12 @@ class DeconzAccessory extends AccessoryDelegate { | |
| 139 139 | 
             
                this.debug('%s: params: %j', resource.rpath, params)
         | 
| 140 140 |  | 
| 141 141 | 
             
                let service
         | 
| 142 | 
            -
                if (params.serviceName === ' | 
| 142 | 
            +
                if (params.serviceName === 'AirQuality') {
         | 
| 143 | 
            +
                  service = this.serviceByServiceName.AirQuality
         | 
| 144 | 
            +
                  if (service != null) {
         | 
| 145 | 
            +
                    service.addResource(resource)
         | 
| 146 | 
            +
                  }
         | 
| 147 | 
            +
                } else if (params.serviceName === 'Battery') {
         | 
| 143 148 | 
             
                  service = this.serviceByServiceName.Battery
         | 
| 144 149 | 
             
                } else if (params.serviceName === 'Consumption') {
         | 
| 145 150 | 
             
                  service = this.serviceByServiceName.Outlet ||
         | 
| @@ -5,73 +5,104 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            'use strict'
         | 
| 7 7 |  | 
| 8 | 
            +
            const Deconz = require('../Deconz')
         | 
| 8 9 | 
             
            const DeconzService = require('../DeconzService')
         | 
| 9 10 |  | 
| 11 | 
            +
            const { dateToString } = Deconz.ApiClient
         | 
| 12 | 
            +
             | 
| 10 13 | 
             
            /**
         | 
| 11 14 | 
             
              * @memberof DeconzService
         | 
| 12 15 | 
             
              */
         | 
| 13 16 | 
             
            class AirQuality extends DeconzService.SensorsResource {
         | 
| 14 | 
            -
               | 
| 15 | 
            -
                 | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
                   | 
| 20 | 
            -
             | 
| 21 | 
            -
                })
         | 
| 17 | 
            +
              static addResource (service, resource) {
         | 
| 18 | 
            +
                if (service.values.airQuality === undefined) {
         | 
| 19 | 
            +
                  service.addCharacteristicDelegate({
         | 
| 20 | 
            +
                    key: 'airQuality',
         | 
| 21 | 
            +
                    Characteristic: service.Characteristics.hap.AirQuality
         | 
| 22 | 
            +
                  })
         | 
| 23 | 
            +
                }
         | 
| 22 24 |  | 
| 23 25 | 
             
                if (resource.body.state.airqualityppb !== undefined) {
         | 
| 24 | 
            -
                   | 
| 26 | 
            +
                  service.addCharacteristicDelegate({
         | 
| 25 27 | 
             
                    key: 'vocDensity',
         | 
| 26 | 
            -
                    Characteristic:  | 
| 28 | 
            +
                    Characteristic: service.Characteristics.hap.VOCDensity,
         | 
| 27 29 | 
             
                    unit: ' µg/m³',
         | 
| 28 30 | 
             
                    props: { minValue: 0, maxValue: 65535, minStep: 1 }
         | 
| 29 31 | 
             
                  })
         | 
| 30 32 | 
             
                }
         | 
| 31 33 |  | 
| 32 34 | 
             
                if (resource.body.state.pm2_5 !== undefined) {
         | 
| 33 | 
            -
                   | 
| 34 | 
            -
                    key: ' | 
| 35 | 
            -
                    Characteristic:  | 
| 35 | 
            +
                  service.addCharacteristicDelegate({
         | 
| 36 | 
            +
                    key: 'pm25Density',
         | 
| 37 | 
            +
                    Characteristic: service.Characteristics.hap.PM2_5Density,
         | 
| 36 38 | 
             
                    unit: ' µg/m³',
         | 
| 37 39 | 
             
                    props: { minValue: 0, maxValue: 65535, minStep: 1 }
         | 
| 38 40 | 
             
                  })
         | 
| 39 41 | 
             
                }
         | 
| 40 42 |  | 
| 41 | 
            -
                if ( | 
| 42 | 
            -
                   | 
| 43 | 
            +
                if (service.values.lastUpdated === undefined) {
         | 
| 44 | 
            +
                  service.addCharacteristicDelegate({
         | 
| 45 | 
            +
                    key: 'lastUpdated',
         | 
| 46 | 
            +
                    Characteristic: service.Characteristics.my.LastUpdated,
         | 
| 47 | 
            +
                    silent: true
         | 
| 48 | 
            +
                  })
         | 
| 43 49 | 
             
                }
         | 
| 44 50 |  | 
| 45 | 
            -
                 | 
| 51 | 
            +
                AirQuality.updateResourceState(service, resource.body.state)
         | 
| 46 52 | 
             
              }
         | 
| 47 53 |  | 
| 48 | 
            -
              airQualityValue (value) {
         | 
| 54 | 
            +
              static airQualityValue (service, value) {
         | 
| 49 55 | 
             
                switch (value) {
         | 
| 50 56 | 
             
                  case 'excellent':
         | 
| 51 | 
            -
                    return  | 
| 57 | 
            +
                    return service.Characteristics.hap.AirQuality.EXCELLENT
         | 
| 52 58 | 
             
                  case 'good':
         | 
| 53 | 
            -
                    return  | 
| 59 | 
            +
                    return service.Characteristics.hap.AirQuality.GOOD
         | 
| 54 60 | 
             
                  case 'moderate':
         | 
| 55 | 
            -
                    return  | 
| 61 | 
            +
                    return service.Characteristics.hap.AirQuality.FAIR
         | 
| 56 62 | 
             
                  case 'poor':
         | 
| 57 | 
            -
                    return  | 
| 63 | 
            +
                    return service.Characteristics.hap.AirQuality.INFERIOR
         | 
| 58 64 | 
             
                  case 'unhealthy':
         | 
| 59 | 
            -
                    return  | 
| 65 | 
            +
                    return service.Characteristics.hap.AirQuality.POOR
         | 
| 60 66 | 
             
                  default:
         | 
| 61 | 
            -
                    return  | 
| 67 | 
            +
                    return service.Characteristics.hap.AirQuality.UNKNOWN
         | 
| 62 68 | 
             
                }
         | 
| 63 69 | 
             
              }
         | 
| 64 70 |  | 
| 65 | 
            -
               | 
| 66 | 
            -
                if (state.airquality != null) {
         | 
| 67 | 
            -
                  this.values.airQuality = this.airQualityValue(state.airquality)
         | 
| 68 | 
            -
                }
         | 
| 71 | 
            +
              static updateResourceState (service, state) {
         | 
| 69 72 | 
             
                if (state.airqualityppb != null) {
         | 
| 70 | 
            -
                   | 
| 73 | 
            +
                  service.values.vocDensity = Math.round(state.airqualityppb * 4.57)
         | 
| 74 | 
            +
                  if (state.airquality != null) {
         | 
| 75 | 
            +
                    service.values.airQuality = AirQuality.airQualityValue(
         | 
| 76 | 
            +
                      service, state.airquality
         | 
| 77 | 
            +
                    )
         | 
| 78 | 
            +
                  }
         | 
| 71 79 | 
             
                }
         | 
| 72 80 | 
             
                if (state.pm2_5 != null) {
         | 
| 73 | 
            -
                   | 
| 81 | 
            +
                  service.values.pm25Density = state.pm2_5
         | 
| 82 | 
            +
                  if (state.airquality != null && service.values.vocDensity === undefined) {
         | 
| 83 | 
            +
                    service.values.airQuality = AirQuality.airQualityValue(
         | 
| 84 | 
            +
                      service, state.airquality
         | 
| 85 | 
            +
                    )
         | 
| 86 | 
            +
                  }
         | 
| 87 | 
            +
                }
         | 
| 88 | 
            +
                if (state.lastupdated != null) {
         | 
| 89 | 
            +
                  service.values.lastUpdated = dateToString(state.lastupdated)
         | 
| 74 90 | 
             
                }
         | 
| 91 | 
            +
              }
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              constructor (accessory, resource, params = {}) {
         | 
| 94 | 
            +
                params.Service = accessory.Services.hap.AirQualitySensor
         | 
| 95 | 
            +
                super(accessory, resource, params)
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                AirQuality.addResource(this, resource)
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                super.addCharacteristicDelegates({ noLastUpdated: true })
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                this.update(resource.body, resource.rpath)
         | 
| 102 | 
            +
              }
         | 
| 103 | 
            +
             | 
| 104 | 
            +
              updateState (state) {
         | 
| 105 | 
            +
                AirQuality.updateResourceState(this, state)
         | 
| 75 106 | 
             
                super.updateState(state)
         | 
| 76 107 | 
             
              }
         | 
| 77 108 | 
             
            }
         | 
| @@ -23,11 +23,11 @@ class Consumption extends DeconzService.SensorsResource { | |
| 23 23 |  | 
| 24 24 | 
             
                if (
         | 
| 25 25 | 
             
                  resource.body.state.power !== undefined &&
         | 
| 26 | 
            -
                  service.values. | 
| 26 | 
            +
                  service.values.consumption === undefined
         | 
| 27 27 | 
             
                ) {
         | 
| 28 28 | 
             
                  service.addCharacteristicDelegate({
         | 
| 29 | 
            -
                    key: ' | 
| 30 | 
            -
                    Characteristic: service.Characteristics.eve. | 
| 29 | 
            +
                    key: 'consumption',
         | 
| 30 | 
            +
                    Characteristic: service.Characteristics.eve.Consumption,
         | 
| 31 31 | 
             
                    unit: ' W'
         | 
| 32 32 | 
             
                  })
         | 
| 33 33 | 
             
                }
         | 
| @@ -40,7 +40,7 @@ class Consumption extends DeconzService.SensorsResource { | |
| 40 40 | 
             
                  })
         | 
| 41 41 | 
             
                }
         | 
| 42 42 |  | 
| 43 | 
            -
                 | 
| 43 | 
            +
                Consumption.updateResourceState(service, resource.body.state)
         | 
| 44 44 | 
             
              }
         | 
| 45 45 |  | 
| 46 46 | 
             
              static updateResourceState (service, state) {
         | 
| @@ -48,7 +48,7 @@ class Consumption extends DeconzService.SensorsResource { | |
| 48 48 | 
             
                  service.values.totalConsumption = state.consumption / 1000
         | 
| 49 49 | 
             
                }
         | 
| 50 50 | 
             
                if (state.power != null) {
         | 
| 51 | 
            -
                  service.values. | 
| 51 | 
            +
                  service.values.consumption = state.power
         | 
| 52 52 | 
             
                }
         | 
| 53 53 | 
             
                if (state.lastupdated != null) {
         | 
| 54 54 | 
             
                  service.values.lastUpdated = dateToString(state.lastupdated)
         | 
| @@ -8,14 +8,31 @@ | |
| 8 8 | 
             
            const { AdaptiveLighting, Colour, ServiceDelegate, timeout } = require('homebridge-lib')
         | 
| 9 9 | 
             
            const DeconzService = require('../DeconzService')
         | 
| 10 10 |  | 
| 11 | 
            -
            const { xyToHsv, hsvToXy, ctToXy } = Colour
         | 
| 12 | 
            -
            const { History } = ServiceDelegate
         | 
| 11 | 
            +
            const { defaultGamut, xyToHsv, hsvToXy, ctToXy } = Colour
         | 
| 13 12 |  | 
| 14 13 | 
             
            class Light extends DeconzService.LightsResource {
         | 
| 15 14 | 
             
              constructor (accessory, resource, params = {}) {
         | 
| 16 15 | 
             
                params.Service = accessory.Services.hap.Lightbulb
         | 
| 17 16 | 
             
                super(accessory, resource, params)
         | 
| 18 17 |  | 
| 18 | 
            +
                this.capabilities = {
         | 
| 19 | 
            +
                  on: this.resource.body.state.on !== undefined,
         | 
| 20 | 
            +
                  bri: this.resource.body.state.bri !== undefined,
         | 
| 21 | 
            +
                  ct: this.resource.body.state.ct !== undefined,
         | 
| 22 | 
            +
                  hs: this.resource.body.state.xy === undefined &&
         | 
| 23 | 
            +
                    this.resource.body.state.hue !== undefined,
         | 
| 24 | 
            +
                  xy: this.resource.body.state.xy !== undefined
         | 
| 25 | 
            +
                }
         | 
| 26 | 
            +
                if (this.resource.body?.capabilities?.color?.effects != null) {
         | 
| 27 | 
            +
                  const effects = this.resource.body.capabilities.color.effects
         | 
| 28 | 
            +
                  if (effects.length > 1 && effects[1] === 'colorloop') {
         | 
| 29 | 
            +
                    this.capabilities.colorLoop = true
         | 
| 30 | 
            +
                    this.capabilities.effects = effects.length > 2
         | 
| 31 | 
            +
                  } else if (effects.length > 1) {
         | 
| 32 | 
            +
                    this.capabilities.effects = effects.length > 1
         | 
| 33 | 
            +
                  }
         | 
| 34 | 
            +
                }
         | 
| 35 | 
            +
             | 
| 19 36 | 
             
                this.addCharacteristicDelegate({
         | 
| 20 37 | 
             
                  key: 'on',
         | 
| 21 38 | 
             
                  Characteristic: this.Characteristics.hap.On,
         | 
| @@ -81,11 +98,7 @@ class Light extends DeconzService.LightsResource { | |
| 81 98 | 
             
                  })
         | 
| 82 99 | 
             
                }
         | 
| 83 100 |  | 
| 84 | 
            -
                if (
         | 
| 85 | 
            -
                  this.resource.body.config != null &&
         | 
| 86 | 
            -
                  this.resource.body.config.color != null &&
         | 
| 87 | 
            -
                  this.resource.body.config.color.execute_if_off != null
         | 
| 88 | 
            -
                ) {
         | 
| 101 | 
            +
                if (this.resource.body?.config?.color?.execute_if_off != null) {
         | 
| 89 102 | 
             
                  this.addCharacteristicDelegate({
         | 
| 90 103 | 
             
                    key: 'colorExecuteIfOff',
         | 
| 91 104 | 
             
                    value: this.resource.body.config.color.execute_if_off
         | 
| @@ -93,19 +106,25 @@ class Light extends DeconzService.LightsResource { | |
| 93 106 | 
             
                }
         | 
| 94 107 |  | 
| 95 108 | 
             
                if (this.capabilities.ct) {
         | 
| 109 | 
            +
                  if (
         | 
| 110 | 
            +
                    this.resource.body?.capabilities?.color?.ct?.min == null ||
         | 
| 111 | 
            +
                    this.resource.body?.capabilities?.color?.ct?.max == null
         | 
| 112 | 
            +
                  ) {
         | 
| 113 | 
            +
                    this.warn('using default ct range')
         | 
| 114 | 
            +
                  }
         | 
| 115 | 
            +
                  const ctMin = this.resource.body?.capabilities?.color?.ct?.min ?? 153
         | 
| 116 | 
            +
                  const ctMax = this.resource.body?.capabilities?.color?.ct?.max ?? 500
         | 
| 96 117 | 
             
                  this.colorTemperatureDelegate = this.addCharacteristicDelegate({
         | 
| 97 118 | 
             
                    key: 'colorTemperature',
         | 
| 98 119 | 
             
                    Characteristic: this.Characteristics.hap.ColorTemperature,
         | 
| 99 120 | 
             
                    unit: ' mired',
         | 
| 100 121 | 
             
                    props: {
         | 
| 101 | 
            -
                      minValue:  | 
| 102 | 
            -
                      maxValue:  | 
| 122 | 
            +
                      minValue: ctMin,
         | 
| 123 | 
            +
                      maxValue: ctMax
         | 
| 103 124 | 
             
                    },
         | 
| 104 125 | 
             
                    value: this.resource.body.state.ct
         | 
| 105 126 | 
             
                  }).on('didSet', (value, fromHomeKit) => {
         | 
| 106 | 
            -
                    const ct = Math.max(
         | 
| 107 | 
            -
                      this.capabilities.ctMin, Math.min(value, this.capabilities.ctMax)
         | 
| 108 | 
            -
                    )
         | 
| 127 | 
            +
                    const ct = Math.max(ctMin, Math.min(value, ctMax))
         | 
| 109 128 | 
             
                    if (fromHomeKit) {
         | 
| 110 129 | 
             
                      this.checkAdaptiveLighting()
         | 
| 111 130 | 
             
                      this.put({ ct })
         | 
| @@ -120,6 +139,21 @@ class Light extends DeconzService.LightsResource { | |
| 120 139 | 
             
                }
         | 
| 121 140 |  | 
| 122 141 | 
             
                if (this.capabilities.xy) {
         | 
| 142 | 
            +
                  if (
         | 
| 143 | 
            +
                    this.resource.body?.capabilities?.color?.xy?.blue == null ||
         | 
| 144 | 
            +
                    this.resource.body?.capabilities?.color?.xy?.green == null ||
         | 
| 145 | 
            +
                    this.resource.body?.capabilities?.color?.xy?.red == null
         | 
| 146 | 
            +
                  ) {
         | 
| 147 | 
            +
                    this.warn('using default xy gamut')
         | 
| 148 | 
            +
                    this.capabilities.gamut = defaultGamut
         | 
| 149 | 
            +
                  } else {
         | 
| 150 | 
            +
                    this.capabilities.gamut = {
         | 
| 151 | 
            +
                      r: this.resource.body.capabilities.color.xy.red,
         | 
| 152 | 
            +
                      g: this.resource.body.capabilities.color.xy.green,
         | 
| 153 | 
            +
                      b: this.resource.body.capabilities.color.xy.blue
         | 
| 154 | 
            +
                    }
         | 
| 155 | 
            +
                  }
         | 
| 156 | 
            +
             | 
| 123 157 | 
             
                  this.addCharacteristicDelegate({
         | 
| 124 158 | 
             
                    key: 'hue',
         | 
| 125 159 | 
             
                    Characteristic: this.Characteristics.hap.Hue,
         | 
| @@ -261,13 +295,7 @@ class Light extends DeconzService.LightsResource { | |
| 261 295 | 
             
                }
         | 
| 262 296 |  | 
| 263 297 | 
             
                if (this.capabilities.effects != null) {
         | 
| 264 | 
            -
                  this. | 
| 265 | 
            -
                    key: 'exposeEffects',
         | 
| 266 | 
            -
                    value: true
         | 
| 267 | 
            -
                  })
         | 
| 268 | 
            -
                  if (this.values.exposeEffects) {
         | 
| 269 | 
            -
                    this.exposeEffects()
         | 
| 270 | 
            -
                  }
         | 
| 298 | 
            +
                  this.exposeEffects()
         | 
| 271 299 | 
             
                }
         | 
| 272 300 |  | 
| 273 301 | 
             
                if (this.resource.rtype === 'lights') {
         | 
| @@ -279,57 +307,29 @@ class Light extends DeconzService.LightsResource { | |
| 279 307 | 
             
              }
         | 
| 280 308 |  | 
| 281 309 | 
             
              exposeEffects () {
         | 
| 282 | 
            -
                 | 
| 283 | 
            -
             | 
| 284 | 
            -
                   | 
| 285 | 
            -
                  value: -1,
         | 
| 310 | 
            +
                const effectString = this.addCharacteristicDelegate({
         | 
| 311 | 
            +
                  key: 'effectString',
         | 
| 312 | 
            +
                  value: 'none',
         | 
| 286 313 | 
             
                  silent: true
         | 
| 287 | 
            -
                }).on('didSet', (value) => {
         | 
| 288 | 
            -
                  for (const i in this.capabilities.effects) {
         | 
| 289 | 
            -
                    this.effectServices[i].values.on = value === i
         | 
| 290 | 
            -
                  }
         | 
| 291 314 | 
             
                })
         | 
| 292 | 
            -
                for (const id in this.capabilities.effects) {
         | 
| 293 | 
            -
                  const effect = this.capabilities.effects[id]
         | 
| 294 | 
            -
                  const  | 
| 295 | 
            -
             | 
| 296 | 
            -
                     | 
| 297 | 
            -
             | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 300 | 
            -
             | 
| 301 | 
            -
             | 
| 302 | 
            -
             | 
| 303 | 
            -
             | 
| 304 | 
            -
                      this.accessoryDelegate.historyService.lastActivationValue(History.now())
         | 
| 305 | 
            -
                    if (fromHomeKit) {
         | 
| 306 | 
            -
                      this.checkAdaptiveLighting()
         | 
| 307 | 
            -
                      this.values.effect = value ? id : -1
         | 
| 308 | 
            -
                      const newEffect = value
         | 
| 309 | 
            -
                        ? effect.toLowerCase()
         | 
| 310 | 
            -
                        : 'none'
         | 
| 311 | 
            -
                      this.put({ effect: newEffect })
         | 
| 312 | 
            -
                    }
         | 
| 313 | 
            -
                  })
         | 
| 314 | 
            -
                  service.addCharacteristicDelegate({
         | 
| 315 | 
            -
                    key: 'index',
         | 
| 316 | 
            -
                    Characteristic: this.Characteristics.hap.ServiceLabelIndex,
         | 
| 317 | 
            -
                    value: Number(id) + 1
         | 
| 318 | 
            -
                  })
         | 
| 319 | 
            -
                  service.addCharacteristicDelegate({
         | 
| 320 | 
            -
                    key: 'lastActivation',
         | 
| 321 | 
            -
                    Characteristic: this.Characteristics.eve.LastActivation,
         | 
| 322 | 
            -
                    silent: true
         | 
| 323 | 
            -
                  })
         | 
| 324 | 
            -
                  this.effectServices[id] = service
         | 
| 325 | 
            -
             | 
| 326 | 
            -
                  this.characteristicDelegate('configuredName')
         | 
| 327 | 
            -
                    .on('didSet', (value) => {
         | 
| 328 | 
            -
                      for (const id in this.capabilities.effects) {
         | 
| 329 | 
            -
                        this.effectServices[id].values.configuredName = value +
         | 
| 330 | 
            -
                          ' ' + this.capabilities.effects[id]
         | 
| 315 | 
            +
                for (const id in this.resource.body.capabilities.color.effects) {
         | 
| 316 | 
            +
                  const effect = this.resource.body.capabilities.color.effects[id]
         | 
| 317 | 
            +
                  const characteristicName = effect[0].toUpperCase() + effect.slice(1) + 'Effect'
         | 
| 318 | 
            +
                  if (this.Characteristics.my[characteristicName] != null) {
         | 
| 319 | 
            +
                    this.addCharacteristicDelegate({
         | 
| 320 | 
            +
                      key: effect,
         | 
| 321 | 
            +
                      Characteristic: this.Characteristics.my[characteristicName]
         | 
| 322 | 
            +
                    }).on('didSet', (value, fromHomeKit) => {
         | 
| 323 | 
            +
                      if (fromHomeKit) {
         | 
| 324 | 
            +
                        this.checkAdaptiveLighting()
         | 
| 325 | 
            +
                        this.put({ effect: value ? effect : 'none' })
         | 
| 326 | 
            +
                        this.values.effectString = value ? effect : 'none'
         | 
| 331 327 | 
             
                      }
         | 
| 332 328 | 
             
                    })
         | 
| 329 | 
            +
                    effectString.on('didSet', (value) => {
         | 
| 330 | 
            +
                      this.values[effect] = value === effect
         | 
| 331 | 
            +
                    })
         | 
| 332 | 
            +
                  }
         | 
| 333 333 | 
             
                }
         | 
| 334 334 | 
             
                // if (this.capabilities.effectSpeed) {
         | 
| 335 335 | 
             
                //   this.addCharacteristicDelegate({
         | 
| @@ -403,9 +403,8 @@ class Light extends DeconzService.LightsResource { | |
| 403 403 | 
             
                      break
         | 
| 404 404 | 
             
                    case 'effect':
         | 
| 405 405 | 
             
                      this.values.colorLoop = value === 'colorloop'
         | 
| 406 | 
            -
                      if (this.capabilities.effects | 
| 407 | 
            -
                         | 
| 408 | 
            -
                        this.values.effect = '' + this.capabilities.effects.indexOf(effectName)
         | 
| 406 | 
            +
                      if (this.capabilities.effects) {
         | 
| 407 | 
            +
                        this.values.effectString = value
         | 
| 409 408 | 
             
                      }
         | 
| 410 409 | 
             
                      break
         | 
| 411 410 | 
             
                    case 'hue':
         | 
| @@ -430,8 +429,10 @@ class Light extends DeconzService.LightsResource { | |
| 430 429 | 
             
                      break
         | 
| 431 430 | 
             
                    case 'xy':
         | 
| 432 431 | 
             
                      if (
         | 
| 433 | 
            -
                        !this.recentlyUpdated &&
         | 
| 434 | 
            -
             | 
| 432 | 
            +
                        !this.recentlyUpdated && (
         | 
| 433 | 
            +
                          this.values.colormode !== 'ct' ||
         | 
| 434 | 
            +
                          this.resource.body?.capabilities?.color?.ct?.computesXy
         | 
| 435 | 
            +
                        )
         | 
| 435 436 | 
             
                      ) {
         | 
| 436 437 | 
             
                        const { h, s } = xyToHsv(value, this.capabilities.gamut)
         | 
| 437 438 | 
             
                        this.values.hue = h
         | 
| @@ -15,10 +15,10 @@ const { dateToString } = Deconz.ApiClient | |
| 15 15 | 
             
              */
         | 
| 16 16 | 
             
            class Power extends DeconzService.SensorsResource {
         | 
| 17 17 | 
             
              static addResource (service, resource) {
         | 
| 18 | 
            -
                if (service.values. | 
| 18 | 
            +
                if (service.values.consumption === undefined) {
         | 
| 19 19 | 
             
                  service.addCharacteristicDelegate({
         | 
| 20 | 
            -
                    key: ' | 
| 21 | 
            -
                    Characteristic: service.Characteristics.eve. | 
| 20 | 
            +
                    key: 'consumption',
         | 
| 21 | 
            +
                    Characteristic: service.Characteristics.eve.Consumption,
         | 
| 22 22 | 
             
                    unit: ' W'
         | 
| 23 23 | 
             
                  })
         | 
| 24 24 | 
             
                }
         | 
| @@ -46,12 +46,13 @@ class Power extends DeconzService.SensorsResource { | |
| 46 46 | 
             
                    silent: true
         | 
| 47 47 | 
             
                  })
         | 
| 48 48 | 
             
                }
         | 
| 49 | 
            -
             | 
| 49 | 
            +
             | 
| 50 | 
            +
                Power.updateResourceState(service, resource.body.state)
         | 
| 50 51 | 
             
              }
         | 
| 51 52 |  | 
| 52 53 | 
             
              static updateResourceState (service, state) {
         | 
| 53 54 | 
             
                if (state.power != null) {
         | 
| 54 | 
            -
                  service.values. | 
| 55 | 
            +
                  service.values.consumption = state.power
         | 
| 55 56 | 
             
                }
         | 
| 56 57 | 
             
                if (state.current != null) {
         | 
| 57 58 | 
             
                  service.values.electricCurrent = state.current / 1000
         | 
    
        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.1. | 
| 7 | 
            +
              "version": "0.1.10",
         | 
| 8 8 | 
             
              "keywords": [
         | 
| 9 9 | 
             
                "homebridge-plugin",
         | 
| 10 10 | 
             
                "homekit",
         | 
| @@ -21,12 +21,12 @@ | |
| 21 21 | 
             
                "ui": "cli/ui.js"
         | 
| 22 22 | 
             
              },
         | 
| 23 23 | 
             
              "engines": {
         | 
| 24 | 
            -
                "deCONZ": "2. | 
| 24 | 
            +
                "deCONZ": "2.20.1",
         | 
| 25 25 | 
             
                "homebridge": "^1.6.0",
         | 
| 26 | 
            -
                "node": "^18. | 
| 26 | 
            +
                "node": "^18.15.0"
         | 
| 27 27 | 
             
              },
         | 
| 28 28 | 
             
              "dependencies": {
         | 
| 29 | 
            -
                "homebridge-lib": "~6.3. | 
| 29 | 
            +
                "homebridge-lib": "~6.3.12",
         | 
| 30 30 | 
             
                "ws": "^8.12.1",
         | 
| 31 31 | 
             
                "xml2js": "~0.4.23"
         | 
| 32 32 | 
             
              },
         |