diff --git a/CHANGELOG.md b/CHANGELOG.md index d97f43c..1559f68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Note - after update to 4.7.x buttons, sensors, volume display type need to be configure again using config UI. ## Note - after update to 3.15.x need remove the accessory frome Home app and add it again. +## [4.11.0] - (03.04.2024) +## Changes +- added custom sensors based on surrounds reference +- fixed [#253](https://github.com/grzegorz914/homebridge-denon-tv/issues/253) +- config schema updated +- cleanup + ## [4.10.0] - (04.03.2024) ## Changes - added support to subscribe MQTT and control device diff --git a/README.md b/README.md index 8ddb9e2..c47a992 100644 --- a/README.md +++ b/README.md @@ -89,11 +89,16 @@ Tested Denon AVR-2112CI, AVR-3311CI, AVR-X6300H, AVR-X2700H, AVC-X4800H, Marantz | `sensorVolume`| If enabled, then the Volume will be exposed as a `Contact Sensor`, fired on every Volume change. | | `sensorMute`| If enabled, then the Mute will be exposed as a `Contact Sensor`, fired if Mmute ON. | | `sensorInput`| If enabled, then the Input will be exposed as a `Contact Sensor`, fired on every Input change. | -| `sensorInputs`| Her create custom Inputs sensor, sensors will be exposed as a `Contact Sensor`, fired if switch to it. | +| `sensorInputs`| Her create custom Inputs sensor, sensors will be exposed as a `Contact/Motion/Ocupncy Sensor`, fired if switch to it. | | `sensorInputs.name` | Here set own `Name` which You want expose to the `Homebridge/HomeKit` for this sensor. | | `sensorInputs.reference` | Here select reference, fired if switch to this reference. | | `sensorInputs.displayType` | Here select characteristic type to be exposed in HomeKit app, `0 - None/Disabled`, `1 - Motion Sensor`, `2 - Occupancy Sensor`, `3 - Contact Sensor`. | | `sensorInputs.namePrefix` | Here enable/disable the accessory name as a prefix for sensor name.| +| `sensorSurrounds`| Her create custom Sound Mode sensor, sensors will be exposed as a `Contact/Motion/Ocupncy Sensor`, fired if switch to it. | +| `sensorSurrounds.name` | Here set own `Name` which You want expose to the `Homebridge/HomeKit` for this sensor. | +| `sensorSurrounds.reference` | Here select reference, fired if switch to this reference. | +| `sensorSurrounds.displayType` | Here select characteristic type to be exposed in HomeKit app, `0 - None/Disabled`, `1 - Motion Sensor`, `2 - Occupancy Sensor`, `3 - Contact Sensor`. | +| `sensorSurrounds.namePrefix` | Here enable/disable the accessory name as a prefix for sensor name.| | `enableDebugMode` | If enabled, deep log will be present in homebridge console. | | `disableLogInfo` | If enabled, disable log info, all values and state will not be displayed in Homebridge log console. | | `disableLogDeviceInfo` | If enabled, add ability to disable log device info by every connections device to the network. | diff --git a/config.schema.json b/config.schema.json index 523ca44..61fbf50 100644 --- a/config.schema.json +++ b/config.schema.json @@ -5549,7 +5549,7 @@ ] }, { - "title": " M-XPORT (Marantz Only)", + "title": "M-XPORT (Marantz Only)", "enum": [ "M-XPORT" ] @@ -5941,6 +5941,201 @@ } } }, + "sensorSurrounds": { + "type": "array", + "items": { + "title": "Surround", + "type": "object", + "description": "Here create sensors based on reference, fired if switch to it.", + "properties": { + "name": { + "title": "Name", + "type": "string", + "placeholder": "Name", + "description": "Here set Your own name.", + "required": true + }, + "reference": { + "title": "Reference", + "type": "string", + "oneOf": [ + { + "title": "MOVIE", + "enum": [ + "MOVIE" + ] + }, + { + "title": "MUSIC", + "enum": [ + "MUSIC" + ] + }, + { + "title": "GAME", + "enum": [ + "GAME" + ] + }, + { + "title": "DIRECT", + "enum": [ + "DIRECT" + ] + }, + { + "title": "PURE DIRECT", + "enum": [ + "PURE DIRECT" + ] + }, + { + "title": "STEREO", + "enum": [ + "STEREO" + ] + }, + { + "title": "DOLBY DIGITAL", + "enum": [ + "DOLBY DIGITAL" + ] + }, + { + "title": "DTS SURROUND", + "enum": [ + "DTS SURROUND" + ] + }, + { + "title": "AURO 3D", + "enum": [ + "AURO3D" + ] + }, + { + "title": "AURO 2D", + "enum": [ + "AURO2DSURR" + ] + }, + { + "title": "MCH STEREO", + "enum": [ + "MCH STEREO" + ] + }, + { + "title": "WIDE SCREEN", + "enum": [ + "WIDE SCREEN" + ] + }, + { + "title": "SUPER STADIUM", + "enum": [ + "SUPER STADIUM" + ] + }, + { + "title": "ROCK ARENA", + "enum": [ + "ROCK ARENA" + ] + }, + { + "title": "JAZZ CLUB", + "enum": [ + "JAZZ CLUB" + ] + }, + { + "title": "CLASSIC CONCERT", + "enum": [ + "CLASSIC CONCERT" + ] + }, + { + "title": "MONO MOVIE", + "enum": [ + "MONO MOVIE" + ] + }, + { + "title": "MATRIX", + "enum": [ + "MATRIX" + ] + }, + { + "title": "VIDEO GAME", + "enum": [ + "VIDEO GAME" + ] + }, + { + "title": "VIRTUAL", + "enum": [ + "VIRTUAL" + ] + }, + { + "title": "NEURAL", + "enum": [ + "NEURAL" + ] + }, + { + "title": "STANDARD", + "enum": [ + "STANDARD" + ] + } + ], + "description": "Here select reference.", + "required": true + }, + "displayType": { + "title": "Type", + "type": "integer", + "oneOf": [ + { + "title": "None/Disabled", + "enum": [ + 0 + ] + }, + { + "title": "Motion Sensor", + "enum": [ + 1 + ] + }, + { + "title": "Occupancy Sensor", + "enum": [ + 2 + ] + }, + { + "title": "Contact Sensor", + "enum": [ + 3 + ] + } + ], + "description": "Here select characteristic type to be exposed in HomeKit app.", + "required": true + }, + "namePrefix": { + "title": "Prefix", + "type": "boolean", + "description": "Here enable/disable the accessory name as a prefix for sensor name.", + "required": true + } + } + } + }, "enableDebugMode": { "title": "Debug", "type": "boolean", @@ -6339,7 +6534,33 @@ "devices[].sensorInputs[].namePrefix" ] } - ] + ], + "condition": { + "functionBody": "return model.devices[arrayIndices].zoneControl <= 2;" + } + }, + { + "key": "devices[]", + "type": "section", + "title": "Custom Sensors", + "expandable": true, + "expanded": false, + "items": [ + { + "key": "devices[].sensorSurrounds", + "type": "tabarray", + "title": "{{ value.name || 'sensor' }}", + "items": [ + "devices[].sensorSurrounds[].name", + "devices[].sensorSurrounds[].reference", + "devices[].sensorSurrounds[].displayType", + "devices[].sensorSurrounds[].namePrefix" + ] + } + ], + "condition": { + "functionBody": "return model.devices[arrayIndices].zoneControl === 3;" + } } ] }, diff --git a/package.json b/package.json index 3c68092..a464e95 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "displayName": "Denon TV", "name": "homebridge-denon-tv", - "version": "4.10.9", + "version": "4.11.0", "description": "Homebridge plugin to control Denon/Marantz AV Receivers.", "license": "MIT", "author": "grzegorz914", diff --git a/sample-config.json b/sample-config.json index 7052da4..50ccd85 100644 --- a/sample-config.json +++ b/sample-config.json @@ -64,6 +64,14 @@ "namePrefix": false } ], + "sensorSurrounds": [ + { + "name": "Movie", + "reference": "MOVIE", + "displayType": 0, + "namePrefix": false + } + ], "enableDebugMode": false, "disableLogInfo": false, "disableLogDeviceInfo": false, diff --git a/src/denondevice.js b/src/denondevice.js index 275c632..ea8d20c 100644 --- a/src/denondevice.js +++ b/src/denondevice.js @@ -36,6 +36,7 @@ class DenonDevice extends EventEmitter { this.sensorMute = device.sensorMute || false; this.sensorInput = device.sensorInput || false; this.sensorInputs = device.sensorInputs || []; + this.sensorSurrounds = device.sensorSurrounds || []; this.enableDebugMode = device.enableDebugMode || false; this.disableLogInfo = device.disableLogInfo || false; this.disableLogDeviceInfo = device.disableLogDeviceInfo || false; @@ -59,6 +60,7 @@ class DenonDevice extends EventEmitter { //services this.allServices = []; this.sensorsInputsServices = []; + this.sensorsSurroundsServices = []; this.buttonsServices = []; //inputs @@ -67,6 +69,7 @@ class DenonDevice extends EventEmitter { //sensors this.sensorsInputsConfigured = []; + this.sensorsSurroundsConfigured = []; this.sensorVolumeState = false; this.sensorInputState = false; @@ -233,6 +236,17 @@ class DenonDevice extends EventEmitter { } } + if (this.sensorsSurroundsServices) { + const servicesCount = this.sensorsSurroundsServices.length; + for (let i = 0; i < servicesCount; i++) { + const state = power ? this.sensorsSurroundsConfigured[i].reference === reference : false; + const displayType = this.sensorsSurroundsConfigured[i].displayType; + const characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][displayType]; + this.sensorsSurroundsServices[i] + .updateCharacteristic(characteristicType, state); + } + } + this.inputIdentifier = inputIdentifier; this.power = power; this.reference = reference; @@ -963,7 +977,7 @@ class DenonDevice extends EventEmitter { this.allServices.push(this.sensorInputService); }; - //prepare sonsor services + //prepare sonsor inputs services const sensorInputs = this.sensorInputs; const sensorInputsCount = sensorInputs.length; const possibleSensorInputsCount = 99 - this.allServices.length; @@ -991,7 +1005,7 @@ class DenonDevice extends EventEmitter { const serviceName = namePrefix ? `${accessoryName} ${sensorInputName}` : sensorInputName; const characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][sensorInputDisplayType]; const serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][sensorInputDisplayType]; - const sensorInputService = accessory.addService(serviceType, serviceName, `Sensor ${i}`); + const sensorInputService = accessory.addService(serviceType, serviceName, `Input Sensor ${i}`); sensorInputService.addOptionalCharacteristic(Characteristic.ConfiguredName); sensorInputService.setCharacteristic(Characteristic.ConfiguredName, serviceName); sensorInputService.getCharacteristic(characteristicType) @@ -1010,6 +1024,53 @@ class DenonDevice extends EventEmitter { } } + //prepare sonsor surrounds services + const sensorSurrounds = this.sensorSurrounds; + const sensorSurroundsCount = sensorSurrounds.length; + const possibleSensorSurroundsCount = 99 - this.allServices.length; + const maxSensorSurroundsCount = sensorSurroundsCount >= possibleSensorSurroundsCount ? possibleSensorSurroundsCount : sensorSurroundsCount; + if (maxSensorSurroundsCount > 0) { + const debug = !this.enableDebugMode ? false : this.emit('debug', `Prepare surrounds sensors services`); + for (let i = 0; i < maxSensorSurroundsCount; i++) { + //get sensor + const sensorSurround = sensorSurrounds[i]; + + //get name + const sensorSurroundName = sensorSurround.name; + + //get reference + const sensorSurroundReference = sensorSurround.reference; + + //get display type + const sensorSurroundDisplayType = sensorSurround.displayType || false; + + //get sensor name prefix + const namePrefix = sensorSurround.namePrefix || false; + + if (sensorSurroundDisplayType) { + if (sensorSurroundName && sensorSurroundReference) { + const serviceName = namePrefix ? `${accessoryName} ${sensorSurroundName}` : sensorSurroundName; + const characteristicType = ['', Characteristic.MotionDetected, Characteristic.OccupancyDetected, Characteristic.ContactSensorState][sensorSurroundDisplayType]; + const serviceType = ['', Service.MotionSensor, Service.OccupancySensor, Service.ContactSensor][sensorSurroundDisplayType]; + const sensorSurroundService = accessory.addService(serviceType, serviceName, `Surround Sensor ${i}`); + sensorSurroundService.addOptionalCharacteristic(Characteristic.ConfiguredName); + sensorSurroundService.setCharacteristic(Characteristic.ConfiguredName, serviceName); + sensorSurroundService.getCharacteristic(characteristicType) + .onGet(async () => { + const state = this.power ? (this.reference === sensorSurroundReference) : false; + return state; + }); + + this.sensorsSurroundsConfigured.push(sensorSurround); + this.sensorsSurroundsServices.push(sensorSurroundService); + this.allServices.push(sensorSurroundService); + } else { + this.emit('message', `Sensor Name: ${sensorSurroundName ? sensorSurroundName : 'Missing'}, Reference: ${sensorSurroundReference ? sensorSurroundReference : 'Missing'}.`); + }; + } + } + } + //prepare buttons services const buttons = this.buttons; const buttonsCount = buttons.length;