diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2adb6e9b7c..35453fc503 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,15 +93,16 @@ jobs: - name: "release: merge dev -> master and promote dev" if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push' run: | + TAG=${GITHUB_REF#refs/*/} git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" git fetch origin git checkout master - git merge -m 'chore: merge dev to master' dev + git merge -m 'chore: merge dev to master' origin/dev git push origin master git checkout dev - jq '.version = "${{ needs.release-please.outputs.version }}-dev"' package.json > package.json.tmp - jq '.version = "${{ needs.release-please.outputs.version }}-dev"' package-lock.json > package-lock.json.tmp + jq ".version = \"$TAG-dev\"" package.json > package.json.tmp + jq ".version = \"$TAG-dev\"" package-lock.json > package-lock.json.tmp mv package.json.tmp package.json mv package-lock.json.tmp package-lock.json git add -A diff --git a/.github/workflows/deps_review.yaml b/.github/workflows/deps_review.yaml index 2950d68597..69a9c871a1 100644 --- a/.github/workflows/deps_review.yaml +++ b/.github/workflows/deps_review.yaml @@ -11,4 +11,4 @@ jobs: - name: 'Checkout repository' uses: actions/checkout@v4 - name: 'Dependency review' - uses: actions/dependency-review-action@v3 + uses: actions/dependency-review-action@v4 diff --git a/.github/workflows/release_please.yml b/.github/workflows/release_please.yml index 274ccd24f0..bf221a4d24 100644 --- a/.github/workflows/release_please.yml +++ b/.github/workflows/release_please.yml @@ -38,7 +38,7 @@ jobs: ref: master - name: Restore cache commit-user-lookup.json - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: path: z2m/scripts/commit-user-lookup.json key: commit-user-lookup-dummy @@ -62,7 +62,7 @@ jobs: env: GH_TOKEN: ${{secrets.GH_TOKEN}} - name: Save cache commit-user-lookup.json - uses: actions/cache/save@v3 + uses: actions/cache/save@v4 if: always() with: path: z2m/scripts/commit-user-lookup.json diff --git a/lib/eventBus.ts b/lib/eventBus.ts index cd43113b91..e36996732d 100644 --- a/lib/eventBus.ts +++ b/lib/eventBus.ts @@ -90,6 +90,13 @@ export default class EventBus { this.on('entityOptionsChanged', callback, key); } + public emitExposesChanged(data: eventdata.ExposesChanged): void { + this.emitter.emit('exposesChanged', data); + } + public onExposesChanged(key: ListenerKey, callback: (data: eventdata.ExposesChanged) => void): void { + this.on('exposesChanged', callback, key); + } + public emitDeviceLeave(data: eventdata.DeviceLeave): void { this.emitter.emit('deviceLeave', data); } diff --git a/lib/extension/homeassistant.ts b/lib/extension/homeassistant.ts index fa03042f37..119a68f73f 100644 --- a/lib/extension/homeassistant.ts +++ b/lib/extension/homeassistant.ts @@ -146,6 +146,7 @@ export default class HomeAssistant extends Extension { this.eventBus.onDeviceMessage(this, this.onZigbeeEvent); this.eventBus.onScenesChanged(this, this.onScenesChanged); this.eventBus.onEntityOptionsChanged(this, (data) => this.discover(data.entity, true)); + this.eventBus.onExposesChanged(this, (data) => this.discover(data.device, true)); this.mqtt.subscribe(this.statusTopic); this.mqtt.subscribe(defaultStatusTopic); @@ -599,6 +600,7 @@ export default class HomeAssistant extends Extension { discoveryEntries.push(discoveryEntry); } else if (isBinaryExposeFeature(firstExpose)) { const lookup: {[s: string]: KeyValue}= { + auto_off: {icon: 'mdi:flash-auto'}, battery_low: {entity_category: 'diagnostic', device_class: 'battery'}, button_lock: {entity_category: 'config', icon: 'mdi:lock'}, calibration: {entity_category: 'config', icon: 'mdi:progress-wrench'}, @@ -630,8 +632,10 @@ export default class HomeAssistant extends Extension { occupancy: {device_class: 'motion'}, power_outage_memory: {entity_category: 'config', icon: 'mdi:memory'}, presence: {device_class: 'presence'}, + setup: {device_class: 'running'}, smoke: {device_class: 'smoke'}, sos: {device_class: 'safety'}, + schedule: {icon: 'mdi:calendar'}, status_capacitive_load: {entity_category: 'diagnostic', icon: 'mdi:tune'}, status_forward_phase_control: {entity_category: 'diagnostic', icon: 'mdi:tune'}, status_inductive_load: {entity_category: 'diagnostic', icon: 'mdi:tune'}, @@ -640,10 +644,15 @@ export default class HomeAssistant extends Extension { tamper: {device_class: 'tamper'}, temperature_scale: {entity_category: 'config', icon: 'mdi:temperature-celsius'}, test: {entity_category: 'diagnostic', icon: 'mdi:test-tube'}, + trigger_indicator: {icon: 'mdi:led-on'}, + valve_alarm: {device_class: 'problem'}, + valve_detection: {icon: 'mdi:pipe-valve'}, valve_state: {device_class: 'opening'}, vibration: {device_class: 'vibration'}, water_leak: {device_class: 'moisture'}, window: {device_class: 'window'}, + window_detection: {icon: 'mdi:window-open-variant'}, + window_open: {device_class: 'window'}, }; /** @@ -700,6 +709,7 @@ export default class HomeAssistant extends Extension { const lookup: {[s: string]: KeyValue} = { ac_frequency: {device_class: 'frequency', enabled_by_default: false, entity_category: 'diagnostic', state_class: 'measurement'}, + action_duration: {icon: 'mdi:timer', device_class: 'duration'}, alarm_humidity_max: {device_class: 'humidity', entity_category: 'config', icon: 'mdi:water-plus'}, alarm_humidity_min: {device_class: 'humidity', entity_category: 'config', icon: 'mdi:water-minus'}, alarm_temperature_max: {device_class: 'temperature', entity_category: 'config', @@ -750,6 +760,7 @@ export default class HomeAssistant extends Extension { state_class: 'measurement', }, deadzone_temperature: {entity_category: 'config', icon: 'mdi:thermometer'}, + detection_interval: {icon: 'mdi:timer'}, device_temperature: { device_class: 'temperature', entity_category: 'diagnostic', state_class: 'measurement', }, @@ -757,6 +768,7 @@ export default class HomeAssistant extends Extension { eco2: {device_class: 'carbon_dioxide', state_class: 'measurement'}, eco_temperature: {entity_category: 'config', icon: 'mdi:thermometer'}, energy: {device_class: 'energy', state_class: 'total_increasing'}, + external_temperature_input: {icon: 'mdi:thermometer'}, formaldehyd: {state_class: 'measurement'}, gas_density: {icon: 'mdi:google-circles-communities', state_class: 'measurement'}, hcho: {icon: 'mdi:air-filter', state_class: 'measurement'}, @@ -781,6 +793,7 @@ export default class HomeAssistant extends Extension { minimum_on_level: {entity_category: 'config'}, measurement_poll_interval: {entity_category: 'config', icon: 'mdi:clock-out'}, occupancy_timeout: {entity_category: 'config', icon: 'mdi:timer'}, + overload_protection: {icon: 'mdi:flash'}, pm10: {device_class: 'pm10', state_class: 'measurement'}, pm25: {device_class: 'pm25', state_class: 'measurement'}, people: {state_class: 'measurement', icon: 'mdi:account-multiple'}, @@ -788,6 +801,7 @@ export default class HomeAssistant extends Extension { power: {device_class: 'power', entity_category: 'diagnostic', state_class: 'measurement'}, power_factor: {device_class: 'power_factor', enabled_by_default: false, entity_category: 'diagnostic', state_class: 'measurement'}, + power_outage_count: {icon: 'mdi:counter'}, precision: {entity_category: 'config', icon: 'mdi:decimal-comma-increase'}, pressure: {device_class: 'atmospheric_pressure', state_class: 'measurement'}, presence_timeout: {entity_category: 'config', icon: 'mdi:timer'}, @@ -925,6 +939,7 @@ export default class HomeAssistant extends Extension { alarm_temperature: {entity_category: 'config', icon: 'mdi:thermometer-alert'}, backlight_auto_dim: {entity_category: 'config', icon: 'mdi:brightness-auto'}, backlight_mode: {entity_category: 'config', icon: 'mdi:lightbulb'}, + calibrate: {icon: 'mdi:tune'}, color_power_on_behavior: {entity_category: 'config', icon: 'mdi:palette'}, control_mode: {entity_category: 'config', icon: 'mdi:tune'}, device_mode: {entity_category: 'config', icon: 'mdi:tune'}, @@ -938,6 +953,7 @@ export default class HomeAssistant extends Extension { melody: {entity_category: 'config', icon: 'mdi:music-note'}, mode_phase_control: {entity_category: 'config', icon: 'mdi:tune'}, mode: {entity_category: 'config', icon: 'mdi:tune'}, + mode_switch: {icon: 'mdi:tune'}, motion_sensitivity: {entity_category: 'config', icon: 'mdi:tune'}, operation_mode: {entity_category: 'config', icon: 'mdi:tune'}, power_on_behavior: {entity_category: 'config', icon: 'mdi:power-settings'}, @@ -945,6 +961,7 @@ export default class HomeAssistant extends Extension { power_supply_mode: {entity_category: 'config', icon: 'mdi:power-settings'}, power_type: {entity_category: 'config', icon: 'mdi:lightning-bolt-circle'}, sensitivity: {entity_category: 'config', icon: 'mdi:tune'}, + sensor: {icon: 'mdi:tune'}, sensors_type: {entity_category: 'config', icon: 'mdi:tune'}, sound_volume: {entity_category: 'config', icon: 'mdi:volume-high'}, status: {icon: 'mdi:state-machine'}, @@ -1000,10 +1017,12 @@ export default class HomeAssistant extends Extension { const settableText = firstExpose.type === 'text' && firstExpose.access & ACCESS_SET; const lookup: {[s: string]: KeyValue} = { action: {icon: 'mdi:gesture-double-tap'}, + color_options: {icon: 'mdi:palette'}, level_config: {entity_category: 'diagnostic'}, programming_mode: {icon: 'mdi:calendar-clock'}, program: {value_template: `{{ value_json.${firstExpose.property}|default('',True) ` + `| truncate(254, True, '', 0) }}`}, + schedule_settings: {icon: 'mdi:calendar-clock'}, }; if (firstExpose.access & ACCESS_STATE) { const discoveryEntry: DiscoveryEntry = { @@ -1039,6 +1058,14 @@ export default class HomeAssistant extends Extension { throw new Error(`Unsupported exposes type: '${firstExpose.type}'`); } + // Exposes with category 'config' or 'diagnostic' are always added to the respective category. + // This takes precedence over definitions in this file. + if (firstExpose.category === 'config') { + discoveryEntries.forEach((d) => d.discovery_payload.entity_category = 'config'); + } else if (firstExpose.category === 'diagnostic') { + discoveryEntries.forEach((d) => d.discovery_payload.entity_category = 'diagnostic'); + } + discoveryEntries.forEach((d) => { // If a sensor has entity category `config`, then change // it to `diagnostic`. Sensors have no input, so can't be configured. diff --git a/lib/extension/otaUpdate.ts b/lib/extension/otaUpdate.ts index 5ceb6e0a11..a92ac9c5e8 100644 --- a/lib/extension/otaUpdate.ts +++ b/lib/extension/otaUpdate.ts @@ -125,11 +125,11 @@ export default class OTAUpdate extends Extension { logger.debug(`Responded to OTA request of '${data.device.name}' with 'NO_IMAGE_AVAILABLE'`); } - private async readSoftwareBuildIDAndDateCode(device: Device, sendWhen: 'active' | 'immediate'): + private async readSoftwareBuildIDAndDateCode(device: Device, sendPolicy?: 'immediate'): Promise<{softwareBuildID: string, dateCode: string}> { try { const endpoint = device.zh.endpoints.find((e) => e.supportsInputCluster('genBasic')); - const result = await endpoint.read('genBasic', ['dateCode', 'swBuildId'], {sendWhen}); + const result = await endpoint.read('genBasic', ['dateCode', 'swBuildId'], {sendPolicy}); return {softwareBuildID: result.swBuildId, dateCode: result.dateCode}; } catch (e) { return null; @@ -273,7 +273,7 @@ export default class OTAUpdate extends Extension { const payload = this.getEntityPublishPayload(device, {available: false, currentFileVersion: fileVersion, otaFileVersion: fileVersion}); this.publishEntityState(device, payload); - const to = await this.readSoftwareBuildIDAndDateCode(device, 'active'); + const to = await this.readSoftwareBuildIDAndDateCode(device); const [fromS, toS] = [stringify(from_), stringify(to)]; logger.info(`Device '${device.name}' was updated from '${fromS}' to '${toS}'`); responseData.from = from_ ? utils.toSnakeCase(from_) : null; diff --git a/lib/extension/receive.ts b/lib/extension/receive.ts index 330f2c1c8e..3fce386278 100755 --- a/lib/extension/receive.ts +++ b/lib/extension/receive.ts @@ -138,7 +138,13 @@ export default class Receive extends Extension { } }; - const meta = {device: data.device.zh, logger, state: this.state.get(data.device)}; + const deviceExposesChanged = (): void => { + this.eventBus.emitDevicesChanged(); + this.eventBus.emitExposesChanged({device: data.device}); + }; + + const meta = {device: data.device.zh, logger, state: this.state.get(data.device), + deviceExposesChanged: deviceExposesChanged}; let payload: KeyValue = {}; for (const converter of converters) { try { diff --git a/lib/types/types.d.ts b/lib/types/types.d.ts index f1edc98208..c5b2e5ba32 100644 --- a/lib/types/types.d.ts +++ b/lib/types/types.d.ts @@ -90,6 +90,7 @@ declare global { type DeviceInterview = { device: Device, status: 'started' | 'successful' | 'failed' }; type DeviceJoined = { device: Device }; type EntityOptionsChanged = { entity: Device | Group, from: KeyValue, to: KeyValue }; + type ExposesChanged = { device: Device }; type Reconfigure = { device: Device }; type DeviceLeave = { ieeeAddr: string, name: string }; type GroupMembersChanged = {group: Group, action: 'remove' | 'add' | 'remove_all', diff --git a/package-lock.json b/package-lock.json index c7c33527cf..eeb9456a11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zigbee2mqtt", - "version": "1.35.1", + "version": "1.35.1-dev", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "zigbee2mqtt", - "version": "1.35.1", + "version": "1.35.1-dev", "license": "GPL-3.0", "dependencies": { "ajv": "^8.12.0", @@ -33,8 +33,8 @@ "winston-syslog": "^2.7.0", "winston-transport": "^4.6.0", "ws": "^8.16.0", - "zigbee-herdsman": "0.30.0", - "zigbee-herdsman-converters": "18.9.0", + "zigbee-herdsman": "0.33.0", + "zigbee-herdsman-converters": "18.17.0", "zigbee2mqtt-frontend": "0.6.151" }, "bin": { @@ -3600,11 +3600,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -3939,12 +3934,10 @@ } }, "node_modules/bonjour-service": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", - "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } @@ -4505,11 +4498,6 @@ "node": ">=8" } }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" - }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -5718,6 +5706,17 @@ "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.31.0.tgz", "integrity": "sha512-fRrehgBG26NNZysRlTq1S+HPtDpp3u+Jzdc/d5A4cEzOD86YLAkDaJyJg8krSdCi7CJ+s7ht3fwRj8Dl+Btd0w==" }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -8785,6 +8784,11 @@ "node": ">=8.0.0" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -9803,14 +9807,14 @@ } }, "node_modules/zigbee-herdsman": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.30.0.tgz", - "integrity": "sha512-EHnO34Ra0911cuUbhu6xWnQA9Weaerosd69oxpPbtNgnx6amRsA94SfbXxYM7hHZP4h1wJ0xfysyRbIat8v8vQ==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.33.0.tgz", + "integrity": "sha512-4auut2wPcI73hQjQAvDJvVhKxq9BOXkNlV3ujvndP2R21ml+L/pr6txtbPxjWymYIEGteqxQ0HJFCh3qvrADGw==", "dependencies": { "@serialport/bindings-cpp": "^12.0.1", "@serialport/parser-delimiter": "^12.0.0", "@serialport/stream": "^12.0.0", - "bonjour-service": "^1.1.1", + "bonjour-service": "^1.2.1", "debounce": "^2.0.0", "debug": "^4.3.4", "fast-deep-equal": "^3.1.3", @@ -9820,16 +9824,17 @@ } }, "node_modules/zigbee-herdsman-converters": { - "version": "18.9.0", - "resolved": "https://registry.npmjs.org/zigbee-herdsman-converters/-/zigbee-herdsman-converters-18.9.0.tgz", - "integrity": "sha512-Px44olMni2F2/c9DbjDprcKLD37XZlWagY/5Tt+NXR0QLZZQXDl73C8jqUBBt2i8LF2oVoWlzgh880chu9yteA==", + "version": "18.17.0", + "resolved": "https://registry.npmjs.org/zigbee-herdsman-converters/-/zigbee-herdsman-converters-18.17.0.tgz", + "integrity": "sha512-pk4FVMKKdmFO8lyqL9J4bl33+swmhOYl4+W7qWBbf88go6v8bqMqlzAy7QjaMkOMtNBbiMERcmKxIQSbyWgqOw==", "dependencies": { "axios": "^1.6.5", "buffer-crc32": "^0.2.13", "https-proxy-agent": "^7.0.2", + "iconv-lite": "^0.6.3", "semver": "^7.5.4", "tar-stream": "^3.1.6", - "zigbee-herdsman": "^0.30.0" + "zigbee-herdsman": "^0.32.4" } }, "node_modules/zigbee2mqtt-frontend": { diff --git a/package.json b/package.json index bbd3430c50..e065b851fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zigbee2mqtt", - "version": "1.35.1", + "version": "1.35.1-dev", "description": "Zigbee to MQTT bridge using Zigbee-herdsman", "main": "index.js", "repository": { @@ -26,9 +26,7 @@ "start": "node index.js", "test-with-coverage": "jest test --coverage", "test": "jest test", - "test-watch": "jest test --watch", - "clean": "rimraf coverage dist tsconfig.tsbuildinfo", - "prepack": "npm run clean && npm run build" + "test-watch": "jest test --watch" }, "author": "Koen Kanters", "license": "GPL-3.0", @@ -61,8 +59,8 @@ "winston-syslog": "^2.7.0", "winston-transport": "^4.6.0", "ws": "^8.16.0", - "zigbee-herdsman": "0.30.0", - "zigbee-herdsman-converters": "18.9.0", + "zigbee-herdsman": "0.33.0", + "zigbee-herdsman-converters": "18.17.0", "zigbee2mqtt-frontend": "0.6.151" }, "devDependencies": { diff --git a/test/bridge.test.js b/test/bridge.test.js index 6bc9c54a1e..38e8ece679 100644 --- a/test/bridge.test.js +++ b/test/bridge.test.js @@ -95,7 +95,7 @@ describe('Bridge', () => { // console.log(MQTT.publish.mock.calls.find((c) => c[0] === 'zigbee2mqtt/bridge/devices')[1]) expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/devices', - stringify([{"date_code":null,"definition":null,"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":[],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"Coordinator","ieee_address":"0x00124b00120144ae","interview_completed":false,"interviewing":false,"model_id":null,"network_address":0,"power_source":null,"software_build_id":null,"supported":true,"type":"Coordinator"},{"date_code":null,"definition":{"description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","exposes":[{"features":[{"access":7,"description":"On/off state of this light","label":"State","name":"state","property":"state","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","label":"Brightness","name":"brightness","property":"brightness","type":"numeric","value_max":254,"value_min":0},{"access":7,"description":"Color temperature of this light","label":"Color temp","name":"color_temp","presets":[{"description":"Coolest temperature supported","name":"coolest","value":250},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":454}],"property":"color_temp","type":"numeric","unit":"mired","value_max":454,"value_min":250},{"access":7,"description":"Color temperature after cold power on of this light","label":"Color temp startup","name":"color_temp_startup","presets":[{"description":"Coolest temperature supported","name":"coolest","value":250},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":454},{"description":"Restore previous color_temp on cold power on","name":"previous","value":65535}],"property":"color_temp_startup","type":"numeric","unit":"mired","value_max":454,"value_min":250}],"type":"light"},{"access":2,"description":"Triggers an effect on the light (e.g. make light blink for a few seconds)","label":"Effect","name":"effect","property":"effect","type":"enum","values":["blink","breathe","okay","channel_change","finish_effect","stop_effect"]},{"access":7,"description":"Controls the behavior when the device is powered on after power loss. If you get an `UNSUPPORTED_ATTRIBUTE` error, the device does not support it.","label":"Power-on behavior","name":"power_on_behavior","property":"power_on_behavior","type":"enum","values":["off","on","toggle","previous"]},{"access":7,"description":"Advanced color behavior","features":[{"access":2,"description":"Controls whether color and color temperature can be set while light is off","label":"Execute if off","name":"execute_if_off","property":"execute_if_off","type":"binary","value_off":false,"value_on":true}],"label":"Color options","name":"color_options","property":"color_options","type":"composite"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"LED1545G12","options":[{"access":2,"description":"Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).","label":"Transition","name":"transition","property":"transition","type":"numeric","value_min":0},{"access":2,"description":"When enabled colors will be synced, e.g. if the light supports both color x/y and color temperature a conversion from color x/y to color temperature will be done when setting the x/y color (default true).","label":"Color sync","name":"color_sync","property":"color_sync","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true}],"supports_ota":true,"vendor":"IKEA"},"description":"this is my bulb","disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl","lightingColorCtrl"],"output":["genScenes","genOta"]},"configured_reportings":[{"attribute":"onOff","cluster":"genOnOff","maximum_report_interval":10,"minimum_report_interval":1,"reportable_change":20}],"scenes":[]}},"friendly_name":"bulb","ieee_address":"0x000b57fffec6a5b2","interview_completed":true,"interviewing":false,"model_id":"TRADFRI bulb E27 WS opal 980lm","network_address":40369,"power_source":"Mains (single phase)","software_build_id":null,"supported":true,"type":"Router"},{"date_code":"2019.09","definition":{"description":"Hue Go","exposes":[{"features":[{"access":7,"description":"On/off state of this light","label":"State","name":"state","property":"state","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","label":"Brightness","name":"brightness","property":"brightness","type":"numeric","value_max":254,"value_min":0},{"access":7,"description":"Color temperature of this light","label":"Color temp","name":"color_temp","presets":[{"description":"Coolest temperature supported","name":"coolest","value":150},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":500}],"property":"color_temp","type":"numeric","unit":"mired","value_max":500,"value_min":150},{"access":7,"description":"Color temperature after cold power on of this light","label":"Color temp startup","name":"color_temp_startup","presets":[{"description":"Coolest temperature supported","name":"coolest","value":150},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":500},{"description":"Restore previous color_temp on cold power on","name":"previous","value":65535}],"property":"color_temp_startup","type":"numeric","unit":"mired","value_max":500,"value_min":150},{"access":7,"description":"Color of this light in the CIE 1931 color space (x/y)","features":[{"access":7,"label":"X","name":"x","property":"x","type":"numeric"},{"access":7,"label":"Y","name":"y","property":"y","type":"numeric"}],"label":"Color (X/Y)","name":"color_xy","property":"color","type":"composite"},{"access":7,"description":"Color of this light expressed as hue/saturation","features":[{"access":7,"label":"Hue","name":"hue","property":"hue","type":"numeric"},{"access":7,"label":"Saturation","name":"saturation","property":"saturation","type":"numeric"}],"label":"Color (HS)","name":"color_hs","property":"color","type":"composite"}],"type":"light"},{"access":7,"description":"Controls the behavior when the device is powered on after power loss. If you get an `UNSUPPORTED_ATTRIBUTE` error, the device does not support it.","label":"Power-on behavior","name":"power_on_behavior","property":"power_on_behavior","type":"enum","values":["off","on","toggle","previous"]},{"access":2,"label":"Effect","name":"effect","property":"effect","type":"enum","values":["blink","breathe","okay","channel_change","candle","fireplace","colorloop","finish_effect","stop_effect","stop_hue_effect"]},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"7146060PH","options":[{"access":2,"description":"Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).","label":"Transition","name":"transition","property":"transition","type":"numeric","value_min":0},{"access":2,"description":"When enabled colors will be synced, e.g. if the light supports both color x/y and color temperature a conversion from color x/y to color temperature will be done when setting the x/y color (default true).","label":"Color sync","name":"color_sync","property":"color_sync","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true}],"supports_ota":true,"vendor":"Philips"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl","lightingColorCtrl"],"output":["genScenes","genOta"]},"configured_reportings":[],"scenes":[{"id":1,"name":"Chill scene"}]}},"friendly_name":"bulb_color_2","ieee_address":"0x000b57fffec6a5b4","interview_completed":true,"interviewing":false,"manufacturer":"Philips","model_id":"LLC020","network_address":401292,"power_source":"Mains (single phase)","software_build_id":"5.127.1.26581","supported":true,"type":"Router"},{"date_code":null,"definition":{"description":"Hue dimmer switch","exposes":[{"access":1,"description":"Remaining battery in %, can take up to 24 hours before reported.","label":"Battery","name":"battery","property":"battery","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":1,"description":"Triggered action (e.g. a button click)","label":"Action","name":"action","property":"action","type":"enum","values":["on_press","on_press_release","on_hold","on_hold_release","up_press","up_press_release","up_hold","up_hold_release","down_press","down_press_release","down_hold","down_hold_release","off_press","off_press_release","off_hold","off_hold_release"]},{"access":1,"label":"Action duration","name":"action_duration","property":"action_duration","type":"numeric","unit":"s"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"324131092621","options":[{"access":2,"description":"Set to false to disable the legacy integration (highly recommended), will change structure of the published payload (default true).","label":"Legacy","name":"legacy","property":"legacy","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"Simulate a brightness value. If this device provides a brightness_move_up or brightness_move_down action it is possible to specify the update interval and delta. The action_brightness_delta indicates the delta for each interval. Only works when legacy is false.","features":[{"access":2,"description":"Delta per interval, 20 by default","label":"Delta","name":"delta","property":"delta","type":"numeric","value_min":0},{"access":2,"description":"Interval duration","label":"Interval","name":"interval","property":"interval","type":"numeric","unit":"ms","value_min":0}],"label":"Simulated brightness","name":"simulated_brightness","property":"simulated_brightness","type":"composite"}],"supports_ota":true,"vendor":"Philips"},"disabled":false,"endpoints":{"1":{"bindings":[{"cluster":"genLevelCtrl","target":{"endpoint":1,"ieee_address":"0x000b57fffec6a5b3","type":"endpoint"}},{"cluster":"genOnOff","target":{"endpoint":1,"ieee_address":"0x000b57fffec6a5b3","type":"endpoint"}},{"cluster":"lightingColorCtrl","target":{"endpoint":1,"ieee_address":"0x000b57fffec6a5b3","type":"endpoint"}},{"cluster":"genOnOff","target":{"id":1,"type":"group"}},{"cluster":"genLevelCtrl","target":{"id":1,"type":"group"}}],"clusters":{"input":["genBasic"],"output":["genBasic","genOnOff","genLevelCtrl","genScenes"]},"configured_reportings":[],"scenes":[]},"2":{"bindings":[],"clusters":{"input":["genBasic"],"output":["genOta","genOnOff"]},"configured_reportings":[],"scenes":[]}},"friendly_name":"remote","ieee_address":"0x0017880104e45517","interview_completed":true,"interviewing":false,"model_id":"RWL021","network_address":6535,"power_source":"Battery","software_build_id":null,"supported":true,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Automatically generated definition","exposes":[{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"notSupportedModelID","options":[],"supports_ota":false,"vendor":"notSupportedMfg"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic"],"output":["genBasic","genOnOff","genLevelCtrl","genScenes"]},"configured_reportings":[],"scenes":[]}},"friendly_name":"0x0017880104e45518","ieee_address":"0x0017880104e45518","interview_completed":true,"interviewing":false,"manufacturer":"notSupportedMfg","model_id":"notSupportedModelID","network_address":6536,"power_source":"Battery","software_build_id":null,"supported":false,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Aqara wireless switch","exposes":[{"access":1,"description":"Remaining battery in %, can take up to 24 hours before reported.","label":"Battery","name":"battery","property":"battery","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":1,"description":"Voltage of the battery in millivolts","label":"Voltage","name":"voltage","property":"voltage","type":"numeric","unit":"mV"},{"access":1,"description":"Triggered action (e.g. a button click)","label":"Action","name":"action","property":"action","type":"enum","values":["single","double","triple","quadruple","hold","release"]},{"access":1,"description":"Temperature of the device","label":"Device temperature","name":"device_temperature","property":"device_temperature","type":"numeric","unit":"°C"},{"access":1,"description":"Number of power outages (since last pairing)","label":"Power outage count","name":"power_outage_count","property":"power_outage_count","type":"numeric"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"WXKG11LM","options":[{"access":2,"description":"Calibrates the device_temperature value (absolute offset), takes into effect on next report of device.","label":"Device temperature calibration","name":"device_temperature_calibration","property":"device_temperature_calibration","type":"numeric"},{"access":2,"description":"Set to false to disable the legacy integration (highly recommended), will change structure of the published payload (default true).","label":"Legacy","name":"legacy","property":"legacy","type":"binary","value_off":false,"value_on":true}],"supports_ota":false,"vendor":"Xiaomi"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic"],"output":["genBasic","genOnOff","genLevelCtrl","genScenes"]},"configured_reportings":[{"attribute":1337,"cluster":"genOnOff","maximum_report_interval":10,"minimum_report_interval":1,"reportable_change":20}],"scenes":[]}},"friendly_name":"button","ieee_address":"0x0017880104e45520","interview_completed":true,"interviewing":false,"model_id":"lumi.sensor_switch.aq2","network_address":6537,"power_source":"Battery","software_build_id":null,"supported":true,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Aqara temperature, humidity and pressure sensor","exposes":[{"access":1,"description":"Remaining battery in %, can take up to 24 hours before reported.","label":"Battery","name":"battery","property":"battery","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":1,"description":"Measured temperature value","label":"Temperature","name":"temperature","property":"temperature","type":"numeric","unit":"°C"},{"access":1,"description":"Measured relative humidity","label":"Humidity","name":"humidity","property":"humidity","type":"numeric","unit":"%"},{"access":1,"description":"The measured atmospheric pressure","label":"Pressure","name":"pressure","property":"pressure","type":"numeric","unit":"hPa"},{"access":1,"description":"Voltage of the battery in millivolts","label":"Voltage","name":"voltage","property":"voltage","type":"numeric","unit":"mV"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"WSDCGQ11LM","options":[{"access":2,"description":"Calibrates the temperature value (absolute offset), takes into effect on next report of device.","label":"Temperature calibration","name":"temperature_calibration","property":"temperature_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for temperature, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Temperature precision","name":"temperature_precision","property":"temperature_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the humidity value (absolute offset), takes into effect on next report of device.","label":"Humidity calibration","name":"humidity_calibration","property":"humidity_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for humidity, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Humidity precision","name":"humidity_precision","property":"humidity_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the pressure value (absolute offset), takes into effect on next report of device.","label":"Pressure calibration","name":"pressure_calibration","property":"pressure_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for pressure, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Pressure precision","name":"pressure_precision","property":"pressure_precision","type":"numeric","value_max":3,"value_min":0}],"supports_ota":false,"vendor":"Xiaomi"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic"],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"weather_sensor","ieee_address":"0x0017880104e45522","interview_completed":true,"interviewing":false,"model_id":"lumi.weather","network_address":6539,"power_source":"Battery","software_build_id":null,"supported":true,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Mi power plug ZigBee","exposes":[{"features":[{"access":7,"description":"On/off state of the switch","label":"State","name":"state","property":"state","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"}],"type":"switch"},{"access":5,"description":"Instantaneous measured power","label":"Power","name":"power","property":"power","type":"numeric","unit":"W"},{"access":1,"description":"Sum of consumed energy","label":"Energy","name":"energy","property":"energy","type":"numeric","unit":"kWh"},{"access":1,"description":"Temperature of the device","label":"Device temperature","name":"device_temperature","property":"device_temperature","type":"numeric","unit":"°C"},{"access":7,"description":"Enable/disable the power outage memory, this recovers the on/off mode after power failure","label":"Power outage memory","name":"power_outage_memory","property":"power_outage_memory","type":"binary","value_off":false,"value_on":true},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"ZNCZ02LM","options":[{"access":2,"description":"Calibrates the power value (percentual offset), takes into effect on next report of device.","label":"Power calibration","name":"power_calibration","property":"power_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for power, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Power precision","name":"power_precision","property":"power_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the energy value (percentual offset), takes into effect on next report of device.","label":"Energy calibration","name":"energy_calibration","property":"energy_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for energy, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Energy precision","name":"energy_precision","property":"energy_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the device_temperature value (absolute offset), takes into effect on next report of device.","label":"Device temperature calibration","name":"device_temperature_calibration","property":"device_temperature_calibration","type":"numeric"},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true}],"supports_ota":true,"vendor":"Xiaomi"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic","genOnOff"],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"power_plug","ieee_address":"0x0017880104e45524","interview_completed":true,"interviewing":false,"model_id":"lumi.plug","network_address":6540,"power_source":"Mains (single phase)","software_build_id":null,"supported":true,"type":"Router"},{"date_code":null,"definition":{"description":"zigfred plus smart in-wall switch","exposes":[{"access":1,"description":"Triggered action (e.g. a button click)","label":"Action","name":"action","property":"action","type":"enum","values":["button_1_single","button_1_double","button_1_hold","button_1_release","button_2_single","button_2_double","button_2_hold","button_2_release","button_3_single","button_3_double","button_3_hold","button_3_release","button_4_single","button_4_double","button_4_hold","button_4_release"]},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0},{"endpoint":"l1","features":[{"access":7,"description":"On/off state of this light","endpoint":"l1","label":"State","name":"state","property":"state_l1","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l1","label":"Brightness","name":"brightness","property":"brightness_l1","type":"numeric","value_max":254,"value_min":0},{"access":7,"description":"Color of this light in the CIE 1931 color space (x/y)","endpoint":"l1","features":[{"access":7,"label":"X","name":"x","property":"x","type":"numeric"},{"access":7,"label":"Y","name":"y","property":"y","type":"numeric"}],"label":"Color (X/Y)","name":"color_xy","property":"color_l1","type":"composite"}],"type":"light"},{"endpoint":"l2","features":[{"access":7,"description":"On/off state of this light","endpoint":"l2","label":"State","name":"state","property":"state_l2","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l2","label":"Brightness","name":"brightness","property":"brightness_l2","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l3","features":[{"access":7,"description":"On/off state of this light","endpoint":"l3","label":"State","name":"state","property":"state_l3","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l3","label":"Brightness","name":"brightness","property":"brightness_l3","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l4","features":[{"access":7,"description":"On/off state of this light","endpoint":"l4","label":"State","name":"state","property":"state_l4","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l4","label":"Brightness","name":"brightness","property":"brightness_l4","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l5","features":[{"access":7,"description":"On/off state of this light","endpoint":"l5","label":"State","name":"state","property":"state_l5","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l5","label":"Brightness","name":"brightness","property":"brightness_l5","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l6","features":[{"access":7,"endpoint":"l6","label":"State","name":"state","property":"state_l6","type":"enum","values":["OPEN","CLOSE","STOP"]},{"access":7,"description":"Position of this cover","endpoint":"l6","label":"Position","name":"position","property":"position_l6","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":7,"description":"Tilt of this cover","endpoint":"l6","label":"Tilt","name":"tilt","property":"tilt_l6","type":"numeric","unit":"%","value_max":100,"value_min":0}],"type":"cover"},{"endpoint":"l7","features":[{"access":7,"endpoint":"l7","label":"State","name":"state","property":"state_l7","type":"enum","values":["OPEN","CLOSE","STOP"]},{"access":7,"description":"Position of this cover","endpoint":"l7","label":"Position","name":"position","property":"position_l7","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":7,"description":"Tilt of this cover","endpoint":"l7","label":"Tilt","name":"tilt","property":"tilt_l7","type":"numeric","unit":"%","value_max":100,"value_min":0}],"type":"cover"}],"model":"ZFP-1A-CH","options":[{"access":2,"description":"Front Surface LED enabled","label":"Front surface enabled","name":"front_surface_enabled","property":"front_surface_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 1 enabled","label":"Dimmer 1 enabled","name":"dimmer_1_enabled","property":"dimmer_1_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 1 dimmable","label":"Dimmer 1 dimming enabled","name":"dimmer_1_dimming_enabled","property":"dimmer_1_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 2 enabled","label":"Dimmer 2 enabled","name":"dimmer_2_enabled","property":"dimmer_2_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 2 dimmable","label":"Dimmer 2 dimming enabled","name":"dimmer_2_dimming_enabled","property":"dimmer_2_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 3 enabled","label":"Dimmer 3 enabled","name":"dimmer_3_enabled","property":"dimmer_3_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 3 dimmable","label":"Dimmer 3 dimming enabled","name":"dimmer_3_dimming_enabled","property":"dimmer_3_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 4 enabled","label":"Dimmer 4 enabled","name":"dimmer_4_enabled","property":"dimmer_4_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 4 dimmable","label":"Dimmer 4 dimming enabled","name":"dimmer_4_dimming_enabled","property":"dimmer_4_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 1 enabled","label":"Cover 1 enabled","name":"cover_1_enabled","property":"cover_1_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 1 tiltable","label":"Cover 1 tilt enabled","name":"cover_1_tilt_enabled","property":"cover_1_tilt_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 2 enabled","label":"Cover 2 enabled","name":"cover_2_enabled","property":"cover_2_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 2 tiltable","label":"Cover 2 tilt enabled","name":"cover_2_tilt_enabled","property":"cover_2_tilt_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"When enabled colors will be synced, e.g. if the light supports both color x/y and color temperature a conversion from color x/y to color temperature will be done when setting the x/y color (default true).","label":"Color sync","name":"color_sync","property":"color_sync","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).","label":"Transition","name":"transition","property":"transition","type":"numeric","value_min":0},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"Inverts the cover position, false: open=100,close=0, true: open=0,close=100 (default false).","label":"Invert cover","name":"invert_cover","property":"invert_cover","type":"binary","value_off":false,"value_on":true}],"supports_ota":false,"vendor":"Siglis"},"disabled":false,"endpoints":{"10":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"11":{"bindings":[],"clusters":{"input":["genBasic","genScenes","closuresWindowCovering"],"output":[]},"configured_reportings":[],"scenes":[]},"12":{"bindings":[],"clusters":{"input":["genBasic","genScenes","closuresWindowCovering"],"output":[]},"configured_reportings":[],"scenes":[]},"5":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl","lightingColorCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"7":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"8":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"9":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"zigfred_plus","ieee_address":"0xf4ce368a38be56a1","interview_completed":true,"interviewing":false,"manufacturer":"Siglis","model_id":"zigfred plus","network_address":6589,"power_source":"Mains (single phase)","software_build_id":null,"supported":true,"type":"Router"}]), + stringify([{"date_code":null,"definition":null,"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":[],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"Coordinator","ieee_address":"0x00124b00120144ae","interview_completed":false,"interviewing":false,"model_id":null,"network_address":0,"power_source":null,"software_build_id":null,"supported":true,"type":"Coordinator"},{"date_code":null,"definition":{"description":"TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white","exposes":[{"features":[{"access":7,"description":"On/off state of this light","label":"State","name":"state","property":"state","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","label":"Brightness","name":"brightness","property":"brightness","type":"numeric","value_max":254,"value_min":0},{"access":7,"description":"Color temperature of this light","label":"Color temp","name":"color_temp","presets":[{"description":"Coolest temperature supported","name":"coolest","value":250},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":454}],"property":"color_temp","type":"numeric","unit":"mired","value_max":454,"value_min":250},{"access":7,"description":"Color temperature after cold power on of this light","label":"Color temp startup","name":"color_temp_startup","presets":[{"description":"Coolest temperature supported","name":"coolest","value":250},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":454},{"description":"Restore previous color_temp on cold power on","name":"previous","value":65535}],"property":"color_temp_startup","type":"numeric","unit":"mired","value_max":454,"value_min":250}],"type":"light"},{"access":2,"description":"Triggers an effect on the light (e.g. make light blink for a few seconds)","label":"Effect","name":"effect","property":"effect","type":"enum","values":["blink","breathe","okay","channel_change","finish_effect","stop_effect"]},{"access":7,"description":"Controls the behavior when the device is powered on after power loss. If you get an `UNSUPPORTED_ATTRIBUTE` error, the device does not support it.","label":"Power-on behavior","name":"power_on_behavior","property":"power_on_behavior","type":"enum","values":["off","on","toggle","previous"]},{"access":7,"description":"Advanced color behavior","features":[{"access":2,"description":"Controls whether color and color temperature can be set while light is off","label":"Execute if off","name":"execute_if_off","property":"execute_if_off","type":"binary","value_off":false,"value_on":true}],"label":"Color options","name":"color_options","property":"color_options","type":"composite"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"LED1545G12","options":[{"access":2,"description":"Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).","label":"Transition","name":"transition","property":"transition","type":"numeric","value_min":0},{"access":2,"description":"When enabled colors will be synced, e.g. if the light supports both color x/y and color temperature a conversion from color x/y to color temperature will be done when setting the x/y color (default true).","label":"Color sync","name":"color_sync","property":"color_sync","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true}],"supports_ota":true,"vendor":"IKEA"},"description":"this is my bulb","disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl","lightingColorCtrl"],"output":["genScenes","genOta"]},"configured_reportings":[{"attribute":"onOff","cluster":"genOnOff","maximum_report_interval":10,"minimum_report_interval":1,"reportable_change":20}],"scenes":[]}},"friendly_name":"bulb","ieee_address":"0x000b57fffec6a5b2","interview_completed":true,"interviewing":false,"model_id":"TRADFRI bulb E27 WS opal 980lm","network_address":40369,"power_source":"Mains (single phase)","software_build_id":null,"supported":true,"type":"Router"},{"date_code":"2019.09","definition":{"description":"Hue Go","exposes":[{"features":[{"access":7,"description":"On/off state of this light","label":"State","name":"state","property":"state","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","label":"Brightness","name":"brightness","property":"brightness","type":"numeric","value_max":254,"value_min":0},{"access":7,"description":"Color temperature of this light","label":"Color temp","name":"color_temp","presets":[{"description":"Coolest temperature supported","name":"coolest","value":150},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":500}],"property":"color_temp","type":"numeric","unit":"mired","value_max":500,"value_min":150},{"access":7,"description":"Color temperature after cold power on of this light","label":"Color temp startup","name":"color_temp_startup","presets":[{"description":"Coolest temperature supported","name":"coolest","value":150},{"description":"Cool temperature (250 mireds / 4000 Kelvin)","name":"cool","value":250},{"description":"Neutral temperature (370 mireds / 2700 Kelvin)","name":"neutral","value":370},{"description":"Warm temperature (454 mireds / 2200 Kelvin)","name":"warm","value":454},{"description":"Warmest temperature supported","name":"warmest","value":500},{"description":"Restore previous color_temp on cold power on","name":"previous","value":65535}],"property":"color_temp_startup","type":"numeric","unit":"mired","value_max":500,"value_min":150},{"access":7,"description":"Color of this light in the CIE 1931 color space (x/y)","features":[{"access":7,"label":"X","name":"x","property":"x","type":"numeric"},{"access":7,"label":"Y","name":"y","property":"y","type":"numeric"}],"label":"Color (X/Y)","name":"color_xy","property":"color","type":"composite"},{"access":7,"description":"Color of this light expressed as hue/saturation","features":[{"access":7,"label":"Hue","name":"hue","property":"hue","type":"numeric"},{"access":7,"label":"Saturation","name":"saturation","property":"saturation","type":"numeric"}],"label":"Color (HS)","name":"color_hs","property":"color","type":"composite"}],"type":"light"},{"access":7,"description":"Controls the behavior when the device is powered on after power loss. If you get an `UNSUPPORTED_ATTRIBUTE` error, the device does not support it.","label":"Power-on behavior","name":"power_on_behavior","property":"power_on_behavior","type":"enum","values":["off","on","toggle","previous"]},{"access":2,"label":"Effect","name":"effect","property":"effect","type":"enum","values":["blink","breathe","okay","channel_change","candle","fireplace","colorloop","finish_effect","stop_effect","stop_hue_effect"]},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"7146060PH","options":[{"access":2,"description":"Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).","label":"Transition","name":"transition","property":"transition","type":"numeric","value_min":0},{"access":2,"description":"When enabled colors will be synced, e.g. if the light supports both color x/y and color temperature a conversion from color x/y to color temperature will be done when setting the x/y color (default true).","label":"Color sync","name":"color_sync","property":"color_sync","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true}],"supports_ota":true,"vendor":"Philips"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl","lightingColorCtrl"],"output":["genScenes","genOta"]},"configured_reportings":[],"scenes":[{"id":1,"name":"Chill scene"}]}},"friendly_name":"bulb_color_2","ieee_address":"0x000b57fffec6a5b4","interview_completed":true,"interviewing":false,"manufacturer":"Philips","model_id":"LLC020","network_address":401292,"power_source":"Mains (single phase)","software_build_id":"5.127.1.26581","supported":true,"type":"Router"},{"date_code":null,"definition":{"description":"Hue dimmer switch","exposes":[{"access":1,"description":"Remaining battery in %, can take up to 24 hours before reported","label":"Battery","name":"battery","property":"battery","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":1,"description":"Triggered action (e.g. a button click)","label":"Action","name":"action","property":"action","type":"enum","values":["on_press","on_press_release","on_hold","on_hold_release","up_press","up_press_release","up_hold","up_hold_release","down_press","down_press_release","down_hold","down_hold_release","off_press","off_press_release","off_hold","off_hold_release"]},{"access":1,"label":"Action duration","name":"action_duration","property":"action_duration","type":"numeric","unit":"s"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"324131092621","options":[{"access":2,"description":"Set to false to disable the legacy integration (highly recommended), will change structure of the published payload (default true).","label":"Legacy","name":"legacy","property":"legacy","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"Simulate a brightness value. If this device provides a brightness_move_up or brightness_move_down action it is possible to specify the update interval and delta. The action_brightness_delta indicates the delta for each interval. Only works when legacy is false.","features":[{"access":2,"description":"Delta per interval, 20 by default","label":"Delta","name":"delta","property":"delta","type":"numeric","value_min":0},{"access":2,"description":"Interval duration","label":"Interval","name":"interval","property":"interval","type":"numeric","unit":"ms","value_min":0}],"label":"Simulated brightness","name":"simulated_brightness","property":"simulated_brightness","type":"composite"}],"supports_ota":true,"vendor":"Philips"},"disabled":false,"endpoints":{"1":{"bindings":[{"cluster":"genLevelCtrl","target":{"endpoint":1,"ieee_address":"0x000b57fffec6a5b3","type":"endpoint"}},{"cluster":"genOnOff","target":{"endpoint":1,"ieee_address":"0x000b57fffec6a5b3","type":"endpoint"}},{"cluster":"lightingColorCtrl","target":{"endpoint":1,"ieee_address":"0x000b57fffec6a5b3","type":"endpoint"}},{"cluster":"genOnOff","target":{"id":1,"type":"group"}},{"cluster":"genLevelCtrl","target":{"id":1,"type":"group"}}],"clusters":{"input":["genBasic"],"output":["genBasic","genOnOff","genLevelCtrl","genScenes"]},"configured_reportings":[],"scenes":[]},"2":{"bindings":[],"clusters":{"input":["genBasic"],"output":["genOta","genOnOff"]},"configured_reportings":[],"scenes":[]}},"friendly_name":"remote","ieee_address":"0x0017880104e45517","interview_completed":true,"interviewing":false,"model_id":"RWL021","network_address":6535,"power_source":"Battery","software_build_id":null,"supported":true,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Automatically generated definition","exposes":[{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"notSupportedModelID","options":[],"supports_ota":false,"vendor":"notSupportedMfg"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic"],"output":["genBasic","genOnOff","genLevelCtrl","genScenes"]},"configured_reportings":[],"scenes":[]}},"friendly_name":"0x0017880104e45518","ieee_address":"0x0017880104e45518","interview_completed":true,"interviewing":false,"manufacturer":"notSupportedMfg","model_id":"notSupportedModelID","network_address":6536,"power_source":"Battery","software_build_id":null,"supported":false,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Aqara wireless switch","exposes":[{"access":1,"description":"Remaining battery in %, can take up to 24 hours before reported","label":"Battery","name":"battery","property":"battery","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":1,"description":"Voltage of the battery in millivolts","label":"Voltage","name":"voltage","property":"voltage","type":"numeric","unit":"mV"},{"access":1,"description":"Triggered action (e.g. a button click)","label":"Action","name":"action","property":"action","type":"enum","values":["single","double","triple","quadruple","hold","release"]},{"access":1,"description":"Temperature of the device","label":"Device temperature","name":"device_temperature","property":"device_temperature","type":"numeric","unit":"°C"},{"access":1,"category":"diagnostic","description":"Number of power outages (since last pairing)","label":"Power outage count","name":"power_outage_count","property":"power_outage_count","type":"numeric"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"WXKG11LM","options":[{"access":2,"description":"Calibrates the device_temperature value (absolute offset), takes into effect on next report of device.","label":"Device temperature calibration","name":"device_temperature_calibration","property":"device_temperature_calibration","type":"numeric"},{"access":2,"description":"Set to false to disable the legacy integration (highly recommended), will change structure of the published payload (default true).","label":"Legacy","name":"legacy","property":"legacy","type":"binary","value_off":false,"value_on":true}],"supports_ota":false,"vendor":"Xiaomi"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic"],"output":["genBasic","genOnOff","genLevelCtrl","genScenes"]},"configured_reportings":[{"attribute":1337,"cluster":"genOnOff","maximum_report_interval":10,"minimum_report_interval":1,"reportable_change":20}],"scenes":[]}},"friendly_name":"button","ieee_address":"0x0017880104e45520","interview_completed":true,"interviewing":false,"model_id":"lumi.sensor_switch.aq2","network_address":6537,"power_source":"Battery","software_build_id":null,"supported":true,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Aqara temperature, humidity and pressure sensor","exposes":[{"access":1,"description":"Remaining battery in %, can take up to 24 hours before reported","label":"Battery","name":"battery","property":"battery","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":1,"description":"Measured temperature value","label":"Temperature","name":"temperature","property":"temperature","type":"numeric","unit":"°C"},{"access":1,"description":"Measured relative humidity","label":"Humidity","name":"humidity","property":"humidity","type":"numeric","unit":"%"},{"access":1,"description":"The measured atmospheric pressure","label":"Pressure","name":"pressure","property":"pressure","type":"numeric","unit":"hPa"},{"access":1,"description":"Voltage of the battery in millivolts","label":"Voltage","name":"voltage","property":"voltage","type":"numeric","unit":"mV"},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"WSDCGQ11LM","options":[{"access":2,"description":"Calibrates the temperature value (absolute offset), takes into effect on next report of device.","label":"Temperature calibration","name":"temperature_calibration","property":"temperature_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for temperature, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Temperature precision","name":"temperature_precision","property":"temperature_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the humidity value (absolute offset), takes into effect on next report of device.","label":"Humidity calibration","name":"humidity_calibration","property":"humidity_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for humidity, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Humidity precision","name":"humidity_precision","property":"humidity_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the pressure value (absolute offset), takes into effect on next report of device.","label":"Pressure calibration","name":"pressure_calibration","property":"pressure_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for pressure, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Pressure precision","name":"pressure_precision","property":"pressure_precision","type":"numeric","value_max":3,"value_min":0}],"supports_ota":false,"vendor":"Xiaomi"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic"],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"weather_sensor","ieee_address":"0x0017880104e45522","interview_completed":true,"interviewing":false,"model_id":"lumi.weather","network_address":6539,"power_source":"Battery","software_build_id":null,"supported":true,"type":"EndDevice"},{"date_code":null,"definition":{"description":"Mi power plug ZigBee","exposes":[{"features":[{"access":7,"description":"On/off state of the switch","label":"State","name":"state","property":"state","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"}],"type":"switch"},{"access":5,"description":"Instantaneous measured power","label":"Power","name":"power","property":"power","type":"numeric","unit":"W"},{"access":1,"description":"Sum of consumed energy","label":"Energy","name":"energy","property":"energy","type":"numeric","unit":"kWh"},{"access":1,"description":"Temperature of the device","label":"Device temperature","name":"device_temperature","property":"device_temperature","type":"numeric","unit":"°C"},{"access":7,"description":"Enable/disable the power outage memory, this recovers the on/off mode after power failure","label":"Power outage memory","name":"power_outage_memory","property":"power_outage_memory","type":"binary","value_off":false,"value_on":true},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0}],"model":"ZNCZ02LM","options":[{"access":2,"description":"Calibrates the power value (percentual offset), takes into effect on next report of device.","label":"Power calibration","name":"power_calibration","property":"power_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for power, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Power precision","name":"power_precision","property":"power_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the energy value (percentual offset), takes into effect on next report of device.","label":"Energy calibration","name":"energy_calibration","property":"energy_calibration","type":"numeric"},{"access":2,"description":"Number of digits after decimal point for energy, takes into effect on next report of device. This option can only decrease the precision, not increase it.","label":"Energy precision","name":"energy_precision","property":"energy_precision","type":"numeric","value_max":3,"value_min":0},{"access":2,"description":"Calibrates the device_temperature value (absolute offset), takes into effect on next report of device.","label":"Device temperature calibration","name":"device_temperature_calibration","property":"device_temperature_calibration","type":"numeric"},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true}],"supports_ota":true,"vendor":"Xiaomi"},"disabled":false,"endpoints":{"1":{"bindings":[],"clusters":{"input":["genBasic","genOnOff"],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"power_plug","ieee_address":"0x0017880104e45524","interview_completed":true,"interviewing":false,"model_id":"lumi.plug","network_address":6540,"power_source":"Mains (single phase)","software_build_id":null,"supported":true,"type":"Router"},{"date_code":null,"definition":{"description":"zigfred plus smart in-wall switch","exposes":[{"access":1,"description":"Triggered action (e.g. a button click)","label":"Action","name":"action","property":"action","type":"enum","values":["button_1_single","button_1_double","button_1_hold","button_1_release","button_2_single","button_2_double","button_2_hold","button_2_release","button_3_single","button_3_double","button_3_hold","button_3_release","button_4_single","button_4_double","button_4_hold","button_4_release"]},{"access":1,"description":"Link quality (signal strength)","label":"Linkquality","name":"linkquality","property":"linkquality","type":"numeric","unit":"lqi","value_max":255,"value_min":0},{"endpoint":"l1","features":[{"access":7,"description":"On/off state of this light","endpoint":"l1","label":"State","name":"state","property":"state_l1","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l1","label":"Brightness","name":"brightness","property":"brightness_l1","type":"numeric","value_max":254,"value_min":0},{"access":7,"description":"Color of this light in the CIE 1931 color space (x/y)","endpoint":"l1","features":[{"access":7,"label":"X","name":"x","property":"x","type":"numeric"},{"access":7,"label":"Y","name":"y","property":"y","type":"numeric"}],"label":"Color (X/Y)","name":"color_xy","property":"color_l1","type":"composite"}],"type":"light"},{"endpoint":"l2","features":[{"access":7,"description":"On/off state of this light","endpoint":"l2","label":"State","name":"state","property":"state_l2","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l2","label":"Brightness","name":"brightness","property":"brightness_l2","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l3","features":[{"access":7,"description":"On/off state of this light","endpoint":"l3","label":"State","name":"state","property":"state_l3","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l3","label":"Brightness","name":"brightness","property":"brightness_l3","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l4","features":[{"access":7,"description":"On/off state of this light","endpoint":"l4","label":"State","name":"state","property":"state_l4","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l4","label":"Brightness","name":"brightness","property":"brightness_l4","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l5","features":[{"access":7,"description":"On/off state of this light","endpoint":"l5","label":"State","name":"state","property":"state_l5","type":"binary","value_off":"OFF","value_on":"ON","value_toggle":"TOGGLE"},{"access":7,"description":"Brightness of this light","endpoint":"l5","label":"Brightness","name":"brightness","property":"brightness_l5","type":"numeric","value_max":254,"value_min":0}],"type":"light"},{"endpoint":"l6","features":[{"access":7,"endpoint":"l6","label":"State","name":"state","property":"state_l6","type":"enum","values":["OPEN","CLOSE","STOP"]},{"access":7,"description":"Position of this cover","endpoint":"l6","label":"Position","name":"position","property":"position_l6","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":7,"description":"Tilt of this cover","endpoint":"l6","label":"Tilt","name":"tilt","property":"tilt_l6","type":"numeric","unit":"%","value_max":100,"value_min":0}],"type":"cover"},{"endpoint":"l7","features":[{"access":7,"endpoint":"l7","label":"State","name":"state","property":"state_l7","type":"enum","values":["OPEN","CLOSE","STOP"]},{"access":7,"description":"Position of this cover","endpoint":"l7","label":"Position","name":"position","property":"position_l7","type":"numeric","unit":"%","value_max":100,"value_min":0},{"access":7,"description":"Tilt of this cover","endpoint":"l7","label":"Tilt","name":"tilt","property":"tilt_l7","type":"numeric","unit":"%","value_max":100,"value_min":0}],"type":"cover"}],"model":"ZFP-1A-CH","options":[{"access":2,"description":"Front Surface LED enabled","label":"Front surface enabled","name":"front_surface_enabled","property":"front_surface_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 1 enabled","label":"Dimmer 1 enabled","name":"dimmer_1_enabled","property":"dimmer_1_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 1 dimmable","label":"Dimmer 1 dimming enabled","name":"dimmer_1_dimming_enabled","property":"dimmer_1_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 2 enabled","label":"Dimmer 2 enabled","name":"dimmer_2_enabled","property":"dimmer_2_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 2 dimmable","label":"Dimmer 2 dimming enabled","name":"dimmer_2_dimming_enabled","property":"dimmer_2_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 3 enabled","label":"Dimmer 3 enabled","name":"dimmer_3_enabled","property":"dimmer_3_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 3 dimmable","label":"Dimmer 3 dimming enabled","name":"dimmer_3_dimming_enabled","property":"dimmer_3_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 4 enabled","label":"Dimmer 4 enabled","name":"dimmer_4_enabled","property":"dimmer_4_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Dimmer 4 dimmable","label":"Dimmer 4 dimming enabled","name":"dimmer_4_dimming_enabled","property":"dimmer_4_dimming_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 1 enabled","label":"Cover 1 enabled","name":"cover_1_enabled","property":"cover_1_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 1 tiltable","label":"Cover 1 tilt enabled","name":"cover_1_tilt_enabled","property":"cover_1_tilt_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 2 enabled","label":"Cover 2 enabled","name":"cover_2_enabled","property":"cover_2_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"Cover 2 tiltable","label":"Cover 2 tilt enabled","name":"cover_2_tilt_enabled","property":"cover_2_tilt_enabled","type":"enum","values":["auto","true","false"]},{"access":2,"description":"When enabled colors will be synced, e.g. if the light supports both color x/y and color temperature a conversion from color x/y to color temperature will be done when setting the x/y color (default true).","label":"Color sync","name":"color_sync","property":"color_sync","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"Controls the transition time (in seconds) of on/off, brightness, color temperature (if applicable) and color (if applicable) changes. Defaults to `0` (no transition).","label":"Transition","name":"transition","property":"transition","type":"numeric","value_min":0},{"access":2,"description":"State actions will also be published as 'action' when true (default false).","label":"State action","name":"state_action","property":"state_action","type":"binary","value_off":false,"value_on":true},{"access":2,"description":"Inverts the cover position, false: open=100,close=0, true: open=0,close=100 (default false).","label":"Invert cover","name":"invert_cover","property":"invert_cover","type":"binary","value_off":false,"value_on":true}],"supports_ota":false,"vendor":"Siglis"},"disabled":false,"endpoints":{"10":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"11":{"bindings":[],"clusters":{"input":["genBasic","genScenes","closuresWindowCovering"],"output":[]},"configured_reportings":[],"scenes":[]},"12":{"bindings":[],"clusters":{"input":["genBasic","genScenes","closuresWindowCovering"],"output":[]},"configured_reportings":[],"scenes":[]},"5":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl","lightingColorCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"7":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"8":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]},"9":{"bindings":[],"clusters":{"input":["genBasic","genScenes","genOnOff","genLevelCtrl"],"output":[]},"configured_reportings":[],"scenes":[]}},"friendly_name":"zigfred_plus","ieee_address":"0xf4ce368a38be56a1","interview_completed":true,"interviewing":false,"manufacturer":"Siglis","model_id":"zigfred plus","network_address":6589,"power_source":"Mains (single phase)","software_build_id":null,"supported":true,"type":"Router"}]), { retain: true, qos: 0 }, expect.any(Function) ); diff --git a/test/configure.test.js b/test/configure.test.js index c7a41c56ce..170af5cf7a 100644 --- a/test/configure.test.js +++ b/test/configure.test.js @@ -176,11 +176,11 @@ describe('Configure', () => { }); it('Fail to configure via MQTT when device has no configure', async () => { - await MQTT.events.message('zigbee2mqtt/bridge/request/device/configure', stringify({id: "0x90fd9ffffe4b64ax", transaction: 20})); + await MQTT.events.message('zigbee2mqtt/bridge/request/device/configure', stringify({id: "0x0017880104e45521", transaction: 20})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/device/configure', - stringify({"data":{"id": "0x90fd9ffffe4b64ax"},"status":"error","error": "Device 'ZNLDP12LM' cannot be configured","transaction":20}), + stringify({"data":{"id": "0x0017880104e45521"},"status":"error","error": "Device 'button_double_key' cannot be configured","transaction":20}), {retain: false, qos: 0}, expect.any(Function) ); }); @@ -200,9 +200,9 @@ describe('Configure', () => { }); it('Legacy api: Should skip reconfigure when device does not require this', async () => { - await MQTT.events.message('zigbee2mqtt/bridge/configure', '0x90fd9ffffe4b64ax'); + await MQTT.events.message('zigbee2mqtt/bridge/configure', '0x0017880104e45521'); await flushPromises(); - expect(logger.warn).toHaveBeenCalledWith(`Skipping configure of 'ZNLDP12LM', device does not require this.`) + expect(logger.warn).toHaveBeenCalledWith(`Skipping configure of 'button_double_key', device does not require this.`) }); it('Should not configure when interview not completed', async () => { diff --git a/test/homeassistant.test.js b/test/homeassistant.test.js index db3b746e86..ffc9dca19e 100644 --- a/test/homeassistant.test.js +++ b/test/homeassistant.test.js @@ -2491,4 +2491,40 @@ describe('HomeAssistant extension', () => { expect.any(Function), ); }); + + it('Should publish discovery message when a converter announces changed exposes', async () => { + MQTT.publish.mockClear(); + const device = zigbeeHerdsman.devices['BMCT-SLZ']; + const data = {deviceMode: 0} + const msg = {data, cluster: 'manuSpecificBosch10', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(msg); + const payload = { + 'availability':[{'topic':'zigbee2mqtt/bridge/state'}], + 'command_topic':'zigbee2mqtt/0x18fc26000000cafe/set/device_mode', + 'device':{ + 'identifiers':['zigbee2mqtt_0x18fc26000000cafe'], + 'manufacturer':'Bosch', + 'model':'Light/shutter control unit II (BMCT-SLZ)', + 'name':'0x18fc26000000cafe', + 'sw_version':null, + 'via_device':'zigbee2mqtt_bridge_0x00124b00120144ae' + }, + 'entity_category':'config', + 'icon':'mdi:tune', + 'json_attributes_topic':'zigbee2mqtt/0x18fc26000000cafe', + 'name':'Device mode', + 'object_id':'0x18fc26000000cafe_device_mode', + 'options':['light','shutter','disabled'], + 'origin': origin, + 'state_topic':'zigbee2mqtt/0x18fc26000000cafe', + 'unique_id':'0x18fc26000000cafe_device_mode_zigbee2mqtt', + 'value_template':'{{ value_json.device_mode }}' + } + expect(MQTT.publish).toHaveBeenCalledWith( + "homeassistant/select/0x18fc26000000cafe/device_mode/config", + stringify(payload), + { retain: true, qos: 1 }, + expect.any(Function), + ); + }); }); diff --git a/test/otaUpdate.test.js b/test/otaUpdate.test.js index 648e77448a..0942c4b904 100644 --- a/test/otaUpdate.test.js +++ b/test/otaUpdate.test.js @@ -89,8 +89,8 @@ describe('OTA update', () => { expect(logger.info).toHaveBeenCalledWith(`Finished update of 'bulb'`); expect(logger.info).toHaveBeenCalledWith(`Device 'bulb' was updated from '{"dateCode":"20190101","softwareBuildID":1}' to '{"dateCode":"20190103","softwareBuildID":3}'`); expect(device.save).toHaveBeenCalledTimes(2); - expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendWhen': 'immediate'}); - expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendWhen': 'active'}); + expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendPolicy': 'immediate'}); + expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {}); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bulb', stringify({"update_available":false,"update":{"state":"updating","progress":0}}), @@ -392,7 +392,7 @@ describe('OTA update', () => { expect(logger.info).toHaveBeenCalledWith(`Device 'bulb' was updated from '{"dateCode":"20190101","softwareBuildID":1}' to '{"dateCode":"20190103","softwareBuildID":3}'`); expect(logger.error).toHaveBeenCalledTimes(0); expect(device.save).toHaveBeenCalledTimes(2); - expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendWhen': 'immediate'}); + expect(endpoint.read).toHaveBeenCalledWith('genBasic', ['dateCode', 'swBuildId'], {'sendPolicy': 'immediate'}); }); it('Legacy api: Should handle when OTA update fails', async () => { diff --git a/test/receive.test.js b/test/receive.test.js index f0b0e1554b..e4078dbda9 100755 --- a/test/receive.test.js +++ b/test/receive.test.js @@ -467,4 +467,11 @@ describe('Receive', () => { expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/SP600_OLD'); expect(JSON.parse(MQTT.publish.mock.calls[0][1])).toStrictEqual({energy: 6.65, power: 496}); }); + it('Should emit DevicesChanged event when a converter announces changed exposes', async () => { + const device = zigbeeHerdsman.devices['BMCT-SLZ']; + const data = {deviceMode: 0} + const payload = {data, cluster: 'manuSpecificBosch10', device, endpoint: device.getEndpoint(1), type: 'attributeReport', linkquality: 10}; + await zigbeeHerdsman.events.message(payload); + expect(MQTT.publish.mock.calls[0][0]).toStrictEqual("zigbee2mqtt/bridge/devices"); + }); }); diff --git a/test/stub/zigbeeHerdsman.js b/test/stub/zigbeeHerdsman.js index 1d1ef57695..e1bffa8ae6 100644 --- a/test/stub/zigbeeHerdsman.js +++ b/test/stub/zigbeeHerdsman.js @@ -204,6 +204,8 @@ const devices = { 'heating_actuator': new Device('Router', '0x0017880104e45562', 6545,4151, [new Endpoint(1, [0,3,4,513], [1026])], true, "Mains (single phase)", "heating.actuator"), 'bj_scene_switch': new Device('EndDevice', '0xd85def11a1002caa', 50117, 4398, [new Endpoint(10, [0,4096], [3,4,5,6,8,25,768,4096], '0xd85def11a1002caa', [{target: bulb_color_2.endpoints[0], cluster: {ID: 8, name: 'genLevelCtrl'}}, {target: bulb_color_2.endpoints[0], cluster: {ID: 6, name: 'genOnOff'}}, {target: bulb_color_2.endpoints[0], cluster: {ID: 768, name: 'lightingColorCtrl'}},]), new Endpoint(11, [0,4096], [3,4,5,6,8,25,768,4096], '0xd85def11a1002caa')], true, 'Battery', 'RB01', false, 'Busch-Jaeger', '20161222', '1.2.0'), 'GW003-AS-IN-TE-FC': new Device('Router', '0x0017548104a44669', 6545,4699, [new Endpoint(1, [3], [0,3,513,514], '0x0017548104a44669')], true, "Mains (single phase)", 'Adapter Zigbee FUJITSU'), + 'BMCT-SLZ': new Device('Router', '0x18fc26000000cafe', 6546,4617, [new Endpoint(1, [0,3,4,5,258,1794,2820,2821,64672], [10,25], '0x18fc26000000cafe')], true, "Mains (single phase)", 'RBSH-MMS-ZB-EU'), + } const mock = { diff --git a/tsconfig.json b/tsconfig.json index 9a8d009722..9940e8b41a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,8 +16,7 @@ "rootDir": "lib", "inlineSourceMap": true, "resolveJsonModule": true, - "experimentalDecorators": true, - "incremental": true + "experimentalDecorators": true }, "include": [ "lib/**/*",