From a9d0706ec4ea5e5bb1e385db9593c84f533b7f71 Mon Sep 17 00:00:00 2001 From: Grzegorz Date: Fri, 23 Aug 2024 16:10:08 +0200 Subject: [PATCH] release v5.1.0 --- CHANGELOG.md | 8 ++++ README.md | 44 ++++++++++------- index.js | 18 +++++-- package-lock.json | 20 ++++---- package.json | 6 +-- src/mainzone.js | 117 ++++++++++++++++++++++++++-------------------- src/restful.js | 15 ++++++ src/surround.js | 107 ++++++++++++++++++++++++------------------ src/zone2.js | 109 ++++++++++++++++++++++++------------------ src/zone3.js | 109 ++++++++++++++++++++++++------------------ 10 files changed, 334 insertions(+), 219 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7647ceb..0559282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Note - after update to 3.15.x need remove the accessory frome Home app and add it again +## [5.1.0] - (22.08.2024) + +## Changes + +- add control over RESTFul POST JSON Object +- bump dependencies +- cleanup + ## [5.0.2] - (18.08.2024) ## Changes diff --git a/README.md b/README.md index a69af5a..422c479 100644 --- a/README.md +++ b/README.md @@ -135,23 +135,35 @@ Tested Denon AVR-2112CI, AVR-3311CI, AVR-X6300H, AVR-X2700H, AVC-X4800H, Marantz ### RESTFul Integration -* Request: `http//homebridge_ip_address:port/path`. -* Path: `info`, `state`, `picture`, `surround`. -* Respone as JSON object. +* POST data as a JSON Object `{Power: true}` + +| Method | URL | Path | Response | Type | +| --- | --- | --- | --- | --- | +| GET | `http//ip:port` | `info`, `state`, `picture`, `surround`. | `{"Power": {"value": OFF}}` | JSON object. | + +| Method | URL | Key | Value | Type | Description | +| --- | --- | --- | --- | --- | --- | +| POST | `http//ip:port` | `Power` | `true`, `false` | boolean | Power On/Off. | +| | `http//ip:port` | `Input` | `SAT/CBL` | string | Set input. | +| | `http//ip:port` | `Surround` | `MUSIC` | string | Set surround mode. | +| | `http//ip:port` | `RcControl` | `NS9E` | string | Send RC command. | +| | `http//ip:port` | `Volume` | `100` | integer | Set volume. | +| | `http//ip:port` | `Mute` | `true`, `false` | string | Set mute On/Off. | ### MQTT Integration -| Direction | Topic | Message | Payload Data | -| --- | --- | --- | --- | -| Publish | `Info`, `State`, `Picture`, `Surround` | `{"Power": {"value": OFF}}` | JSON object. | -| Subscribe | `Set` | `{"Power": true}` | JSON object. | +* Subscribe data as a JSON Object `{Power: true}` -| Subscribe | Key | Value | Type | Description | -| --- | --- | --- | --- | --- | -| Denon/Marantz | | | | | -| | `Power` | `true`, `false` | boolean | Power state. | -| | `Input` | `SAT/CBL` | string | Set input. | -| | `Surround` | `MUSIC` | string | Set surround mode. | -| | `RcControl` | `NS9E` | string | Send RC command. | -| | `Volume` | `100` | integer | Set volume. | -| | `Mute` | `true`, `false` | boolean | Set mute. | +| Method | Topic | Message | Type | +| --- | --- | --- | --- | +| Publish | `Info`, `State`, `Picture`, `Surround` | `{"Power": {"value": OFF}}` | JSON object. | + +| Method | Topic | Key | Value | Type | Description | +| --- | --- | --- | --- | --- | --- | +| Denon/Marantz | | | | | | +| Subscribe | `Set` | `Power` | `true`, `false` | boolean | Power state. | +| | `Set` | `Input` | `SAT/CBL` | string | Set input. | +| | `Set` | `Surround` | `MUSIC` | string | Set surround mode. | +| | `Set` | `RcControl` | `NS9E` | string | Send RC command. | +| | `Set` | `Volume` | `100` | integer | Set volume. | +| | `Set` | `Mute` | `true`, `false` | boolean | Set mute. | diff --git a/index.js b/index.js index 45d07e9..02ab3e4 100644 --- a/index.js +++ b/index.js @@ -40,10 +40,10 @@ class DenonPlatform { const config = { ...device, mqtt: { - ...device.mqtt, - passwd: 'removed' + ...device.mqtt, + passwd: 'removed' } - }; + }; const debug1 = enableDebugMode ? log.info(`Device: ${host} ${deviceName}, Config: ${JSON.stringify(config, null, 2)}`) : false; //zones @@ -87,6 +87,9 @@ class DenonPlatform { .on('devInfo', (devInfo) => { log.info(devInfo); }) + .on('success', (message) => { + log.success(`Device: ${host} ${deviceName}, ${message}`); + }) .on('message', (message) => { log.info(`Device: ${host} ${deviceName}, ${message}`); }) @@ -109,6 +112,9 @@ class DenonPlatform { .on('devInfo', (devInfo) => { log(devInfo); }) + .on('success', (message) => { + log.success(`Device: ${host} ${deviceName}, ${message}`); + }) .on('message', (message) => { log(`Device: ${host} ${deviceName}, ${message}`); }) @@ -131,6 +137,9 @@ class DenonPlatform { .on('devInfo', (devInfo) => { log.info(devInfo); }) + .on('success', (message) => { + log.success(`Device: ${host} ${deviceName}, ${message}`); + }) .on('message', (message) => { log.info(`Device: ${host} ${deviceName}, ${message}`); }) @@ -153,6 +162,9 @@ class DenonPlatform { .on('devInfo', (devInfo) => { log.info(devInfo); }) + .on('success', (message) => { + log.success(`Device: ${host} ${deviceName}, ${message}`); + }) .on('message', (message) => { log.info(`Device: ${host} ${deviceName}, ${message}`); }) diff --git a/package-lock.json b/package-lock.json index ba303b7..17c2c0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,21 @@ { "name": "homebridge-denon-tv", - "version": "5.0.0", + "version": "5.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "homebridge-denon-tv", - "version": "5.0.0", + "version": "5.1.0", "license": "MIT", "dependencies": { "async-mqtt": "^2.6.3", - "axios": "^1.7.4", + "axios": "^1.7.5", "express": "^4.19.2", "fast-xml-parser": "^4.4.1" }, "engines": { - "homebridge": ">=1.6.0", + "homebridge": ">=1.8.0", "node": ">=18.0.0" }, "funding": { @@ -54,9 +54,9 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -1289,9 +1289,9 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "requires": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", diff --git a/package.json b/package.json index 10959fa..3687365 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "displayName": "Denon TV", "name": "homebridge-denon-tv", - "version": "5.0.4", + "version": "5.1.0", "description": "Homebridge plugin to control Denon/Marantz AV Receivers.", "license": "MIT", "author": "grzegorz914", @@ -28,11 +28,11 @@ ], "engines": { "node": ">=18.0.0", - "homebridge": ">=1.6.0" + "homebridge": ">=1.8.0" }, "dependencies": { "async-mqtt": "^2.6.3", - "axios": "^1.7.4", + "axios": "^1.7.5", "fast-xml-parser": "^4.4.1", "express": "^4.19.2" }, diff --git a/src/mainzone.js b/src/mainzone.js index e14861c..f1e2b46 100644 --- a/src/mainzone.js +++ b/src/mainzone.js @@ -39,11 +39,11 @@ class MainZone extends EventEmitter { this.volumeControl = device.volumeControl || false; this.volumeMax = device.volumeMax || 100; this.masterPower = device.masterPower || false; - this.restFul = device.restFul || {}; - this.mqtt = device.mqtt || {}; //external integration + const restFul = device.restFul || {}; this.restFulConnected = false; + const mqtt = device.mqtt || {}; this.mqttConnected = false; //services @@ -248,17 +248,24 @@ class MainZone extends EventEmitter { }) .on('prepareAccessory', async (allInputs) => { //RESTFul server - const restFulEnabled = this.restFul.enable || false; + const restFulEnabled = restFul.enable || false; if (restFulEnabled) { this.restFul = new RestFul({ - port: this.restFul.port || 3000, - debug: this.restFul.debug || false + port: restFul.port || 3000, + debug: restFul.debug || false }); this.restFul.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.restFulConnected = true; }) + .on('set', async (key, value) => { + try { + await this.setOverExternalIntegration('RESTFul', key, value); + } catch (error) { + this.emit('warn', `RESTFul set error: ${error}`); + }; + }) .on('debug', (debug) => { this.emit('debug', debug); }) @@ -268,58 +275,30 @@ class MainZone extends EventEmitter { } //mqtt client - const mqttEnabled = this.mqtt.enable || false; + const mqttEnabled = mqtt.enable || false; if (mqttEnabled) { this.mqtt = new Mqtt({ - host: this.mqtt.host, - port: this.mqtt.port || 1883, - clientId: this.mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, - prefix: `${this.mqtt.prefix}/${name}`, - user: this.mqtt.user, - passwd: this.mqtt.passwd, - debug: this.mqtt.debug || false + host: mqtt.host, + port: mqtt.port || 1883, + clientId: mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, + prefix: `${mqtt.prefix}/${name}`, + user: mqtt.user, + passwd: mqtt.passwd, + debug: mqtt.debug || false }); this.mqtt.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.mqttConnected = true; }) .on('subscribed', (message) => { - this.emit('message', message); + this.emit('success', message); }) .on('subscribedMessage', async (key, value) => { try { - switch (key) { - case 'Power': - const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'ZMON' : 'ZMOFF'); - await this.denon.send(powerState) - break; - case 'Input': - const input = `SI${value}`; - await this.denon.send(input); - break; - case 'Volume': - const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); - const volume = `MV${value1}`; - await this.denon.send(volume); - break; - case 'Mute': - const mute = value ? 'MUON' : 'MUOFF'; - await this.denon.send(mute); - break; - case 'Surround': - const surround = `MS${value}`; - await this.denon.send(surround); - break; - case 'RcControl': - await this.denon.send(value); - break; - default: - this.emit('message', `MQTT Received unknown key: ${key}, value: ${value}`); - break; - }; + await this.setOverExternalIntegration('MQTT', key, value); } catch (error) { - this.emit('warn', `MQTT send error: ${error}.`); + this.emit('warn', `MQTT set error: ${error}.`); }; }) .on('debug', (debug) => { @@ -404,7 +383,7 @@ class MainZone extends EventEmitter { this.televisionService.setCharacteristic(Characteristic.DisplayOrder, Encode(1, displayOrder).toString('base64')); return true; } catch (error) { - throw new Error( error); + throw new Error(error); }; } @@ -414,7 +393,7 @@ class MainZone extends EventEmitter { const debug = !this.enableDebugMode ? false : this.emit('debug', `Saved data: ${JSON.stringify(data, null, 2)}`); return true; } catch (error) { - throw new Error( error); + throw new Error(error); }; } @@ -423,7 +402,45 @@ class MainZone extends EventEmitter { const data = await fsPromises.readFile(path); return data; } catch (error) { - throw new Error( `Read saved data error: ${error}`); + throw new Error(`Read saved data error: ${error}`); + }; + } + + async setOverExternalIntegration(integration, key, value) { + try { + let set = false + switch (key) { + case 'Power': + const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'ZMON' : 'ZMOFF'); + set = await this.denon.send(powerState) + break; + case 'Input': + const input = `SI${value}`; + set = await this.denon.send(input); + break; + case 'Volume': + const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); + const volume = `MV${value1}`; + set = await this.denon.send(volume); + break; + case 'Mute': + const mute = value ? 'MUON' : 'MUOFF'; + set = await this.denon.send(mute); + break; + case 'Surround': + const surround = `MS${value}`; + set = await this.denon.send(surround); + break; + case 'RcControl': + set = await this.denon.send(value); + break; + default: + this.emit('warn', `${integration}, received key: ${key}, value: ${value}`); + break; + }; + return set; + } catch (error) { + throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error}`); }; } @@ -1005,7 +1022,7 @@ class MainZone extends EventEmitter { return accessory; } catch (error) { - throw new Error( error) + throw new Error(error) }; } }; diff --git a/src/restful.js b/src/restful.js index 4329079..9ac725a 100644 --- a/src/restful.js +++ b/src/restful.js @@ -22,11 +22,26 @@ class RestFul extends EventEmitter { try { const restFul = express(); restFul.set('json spaces', 2); + restFul.use(express.json()); restFul.get('/info', (req, res) => { res.json(this.restFulData.info) }); restFul.get('/state', (req, res) => { res.json(this.restFulData.state) }); restFul.get('/picture', (req, res) => { res.json(this.restFulData.picture) }); restFul.get('/surround', (req, res) => { res.json(this.restFulData.surround) }); + //post data + restFul.post('/', (req, res) => { + try { + const obj = req.body; + const emitDebug = this.restFulDebug ? this.emit('debug', `RESTFul post data: ${JSON.stringify(obj, null, 2)}`) : false; + const key = Object.keys(obj)[0]; + const value = Object.values(obj)[0]; + this.emit('set', key, value); + res.send('OK'); + } catch (error) { + this.emit('error', `RESTFul Parse object error: ${error}`); + }; + }); + restFul.listen(this.restFulPort, () => { this.emit('connected', `RESTful started on port: ${this.restFulPort}`) }); diff --git a/src/surround.js b/src/surround.js index ac50a36..2056b5c 100644 --- a/src/surround.js +++ b/src/surround.js @@ -39,11 +39,11 @@ class Surround extends EventEmitter { this.volumeControl = device.volumeControl || false; this.volumeMax = device.volumeMax || 100; this.masterPower = device.masterPower || false; - this.restFul = device.restFul || {}; - this.mqtt = device.mqtt || {}; //external integration + const restFul = device.restFul || {}; this.restFulConnected = false; + const mqtt = device.mqtt || {}; this.mqttConnected = false; //services @@ -216,16 +216,23 @@ class Surround extends EventEmitter { }) .on('prepareAccessory', async (allInputs) => { //RESTFul server - const restFulEnabled = this.restFul.enable || false; + const restFulEnabled = restFul.enable || false; if (restFulEnabled) { this.restFul = new RestFul({ - port: this.restFul.port || 3000, - debug: this.restFul.debug || false + port: restFul.port || 3000, + debug: restFul.debug || false }); this.restFul.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.restFulConnected = true; + }) + .on('set', async (key, value) => { + try { + await this.setOverExternalIntegration('RESTFul', key, value); + } catch (error) { + this.emit('warn', `RESTFul set error: ${error}`); + }; }) .on('debug', (debug) => { this.emit('debug', debug); @@ -236,16 +243,16 @@ class Surround extends EventEmitter { } //mqtt client - const mqttEnabled = this.mqtt.enable || false; + const mqttEnabled = mqtt.enable || false; if (mqttEnabled) { this.mqtt = new Mqtt({ - host: this.mqtt.host, - port: this.mqtt.port || 1883, - clientId: this.mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, - prefix: `${this.mqtt.prefix}/${name}`, - user: this.mqtt.user, - passwd: this.mqtt.passwd, - debug: this.mqtt.debug || false + host: mqtt.host, + port: mqtt.port || 1883, + clientId: mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, + prefix: `${mqtt.prefix}/${name}`, + user: mqtt.user, + passwd: mqtt.passwd, + debug: mqtt.debug || false }); this.mqtt.on('connected', (message) => { @@ -253,41 +260,13 @@ class Surround extends EventEmitter { this.mqttConnected = true; }) .on('subscribed', (message) => { - this.emit('message', message); + this.emit('success', message); }) .on('subscribedMessage', async (key, value) => { try { - switch (key) { - case 'Power': - const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'ZMON' : 'ZMOFF'); - await this.denon.send(powerState) - break; - case 'Input': - const input = `MS${value}`; - await this.denon.send(input); - break; - case 'Volume': - const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); - const volume = `MV${value1}`; - await this.denon.send(volume); - break; - case 'Mute': - const mute = value ? 'MUON' : 'MUOFF'; - await this.denon.send(mute); - break; - case 'Surround': - const surround = `MS${value}`; - await this.denon.send(surround); - break; - case 'RcControl': - await this.denon.send(value); - break; - default: - this.emit('message', `MQTT Received unknown key: ${key}, value: ${value}`); - break; - }; + await this.setOverExternalIntegration('MQTT', key, value); } catch (error) { - this.emit('warn', `MQTT send error: ${error}.`); + this.emit('warn', `MQTT set error: ${error}.`); }; }) .on('debug', (debug) => { @@ -395,6 +374,44 @@ class Surround extends EventEmitter { }; } + async setOverExternalIntegration(integration, key, value) { + try { + let set = false + switch (key) { + case 'Power': + const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'ZMON' : 'ZMOFF'); + set = await this.denon.send(powerState); + break; + case 'Input': + const input = `MS${value}`; + set = await this.denon.send(input); + break; + case 'Volume': + const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); + const volume = `MV${value1}`; + set = await this.denon.send(volume); + break; + case 'Mute': + const mute = value ? 'MUON' : 'MUOFF'; + set = await this.denon.send(mute); + break; + case 'Surround': + const surround = `MS${value}`; + set = await this.denon.send(surround); + break; + case 'RcControl': + set = await this.denon.send(value); + break; + default: + this.emit('warn', `${integration}, received key: ${key}, value: ${value}`); + break; + }; + return set; + } catch (error) { + throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error}`); + }; + } + //prepare accessory async prepareAccessory(allInputs) { try { diff --git a/src/zone2.js b/src/zone2.js index 223e5d5..268a642 100644 --- a/src/zone2.js +++ b/src/zone2.js @@ -41,11 +41,11 @@ class Zone2 extends EventEmitter { this.masterPower = device.masterPower || false; this.masterVolume = device.masterVolume || false; this.masterMute = device.masterMute || false; - this.restFul = device.restFul || {}; - this.mqtt = device.mqtt || {}; //external integration + const restFul = device.restFul || {}; this.restFulConnected = false; + const mqtt = device.mqtt || {}; this.mqttConnected = false; //services @@ -246,17 +246,24 @@ class Zone2 extends EventEmitter { }) .on('prepareAccessory', async (allInputs) => { //RESTFul server - const restFulEnabled = this.restFul.enable || false; + const restFulEnabled = restFul.enable || false; if (restFulEnabled) { this.restFul = new RestFul({ - port: this.restFul.port || 3000, - debug: this.restFul.debug || false + port: restFul.port || 3000, + debug: restFul.debug || false }); this.restFul.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.restFulConnected = true; }) + .on('set', async (key, value) => { + try { + await this.setOverExternalIntegration('RESTFul', key, value); + } catch (error) { + this.emit('warn', `RESTFul set error: ${error}`); + }; + }) .on('debug', (debug) => { this.emit('debug', debug); }) @@ -266,58 +273,30 @@ class Zone2 extends EventEmitter { } //mqtt client - const mqttEnabled = this.mqtt.enable || false; + const mqttEnabled = mqtt.enable || false; if (mqttEnabled) { this.mqtt = new Mqtt({ - host: this.mqtt.host, - port: this.mqtt.port || 1883, - clientId: this.mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, - prefix: `${this.mqtt.prefix}/${name}`, - user: this.mqtt.user, - passwd: this.mqtt.passwd, - debug: this.mqtt.debug || false + host: mqtt.host, + port: mqtt.port || 1883, + clientId: mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, + prefix: `${mqtt.prefix}/${name}`, + user: mqtt.user, + passwd: mqtt.passwd, + debug: mqtt.debug || false }); this.mqtt.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.mqttConnected = true; }) .on('subscribed', (message) => { - this.emit('message', message); + this.emit('success', message); }) .on('subscribedMessage', async (key, value) => { try { - switch (key) { - case 'Power': - const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'Z2ON' : 'Z2OFF'); - await this.denon.send(powerState) - break; - case 'Input': - const input = `Z2${value}`; - await this.denon.send(input); - break; - case 'Volume': - const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); - const volume = this.masterVolume ? `MV${value1}` : `Z2${value1}`; - await this.denon.send(volume); - break; - case 'Mute': - const mute = this.masterMute ? (value ? 'MUON' : 'MUOFF') : (value ? 'Z2MUON' : 'Z2MUOFF'); - await this.denon.send(mute); - break; - case 'Surround': - const surround = `MS${value}`; - await this.denon.send(surround); - break; - case 'RcControl': - await this.denon.send(value); - break; - default: - this.emit('message', `MQTT Received unknown key: ${key}, value: ${value}`); - break; - }; + await this.setOverExternalIntegration('MQTT', key, value); } catch (error) { - this.emit('warn', `MQTT send error: ${error}.`); + this.emit('warn', `MQTT set error: ${error}.`); }; }) .on('debug', (debug) => { @@ -425,6 +404,44 @@ class Zone2 extends EventEmitter { }; } + async setOverExternalIntegration(integration, key, value) { + try { + let set = false + switch (key) { + case 'Power': + const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'Z2ON' : 'Z2OFF'); + set = await this.denon.send(powerState) + break; + case 'Input': + const input = `Z2${value}`; + set = await this.denon.send(input); + break; + case 'Volume': + const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); + const volume = this.masterVolume ? `MV${value1}` : `Z2${value1}`; + set = await this.denon.send(volume); + break; + case 'Mute': + const mute = this.masterMute ? (value ? 'MUON' : 'MUOFF') : (value ? 'Z2MUON' : 'Z2MUOFF'); + set = await this.denon.send(mute); + break; + case 'Surround': + const surround = `MS${value}`; + set = await this.denon.send(surround); + break; + case 'RcControl': + set = await this.denon.send(value); + break; + default: + this.emit('warn', `${integration}, received key: ${key}, value: ${value}`); + break; + }; + return set; + } catch (error) { + throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error}`); + }; + } + //prepare accessory async prepareAccessory(allInputs) { try { diff --git a/src/zone3.js b/src/zone3.js index 25a1a8d..3ca67f6 100644 --- a/src/zone3.js +++ b/src/zone3.js @@ -41,11 +41,11 @@ class Zone3 extends EventEmitter { this.masterPower = device.masterPower || false; this.masterVolume = device.masterVolume || false; this.masterMute = device.masterMute || false; - this.restFul = device.restFul || {}; - this.mqtt = device.mqtt || {}; //external integration + const restFul = device.restFul || {}; this.restFulConnected = false; + const mqtt = device.mqtt || {}; this.mqttConnected = false; //services @@ -246,17 +246,24 @@ class Zone3 extends EventEmitter { }) .on('prepareAccessory', async (allInputs) => { //RESTFul server - const restFulEnabled = this.restFul.enable || false; + const restFulEnabled = restFul.enable || false; if (restFulEnabled) { this.restFul = new RestFul({ - port: this.restFul.port || 3000, - debug: this.restFul.debug || false + port: restFul.port || 3000, + debug: restFul.debug || false }); this.restFul.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.restFulConnected = true; }) + .on('set', async (key, value) => { + try { + await this.setOverExternalIntegration('RESTFul', key, value); + } catch (error) { + this.emit('warn', `RESTFul set error: ${error}`); + }; + }) .on('debug', (debug) => { this.emit('debug', debug); }) @@ -266,58 +273,30 @@ class Zone3 extends EventEmitter { } //mqtt client - const mqttEnabled = this.mqtt.enable || false; + const mqttEnabled = mqtt.enable || false; if (mqttEnabled) { this.mqtt = new Mqtt({ - host: this.mqtt.host, - port: this.mqtt.port || 1883, - clientId: this.mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, - prefix: `${this.mqtt.prefix}/${name}`, - user: this.mqtt.user, - passwd: this.mqtt.passwd, - debug: this.mqtt.debug || false + host: mqtt.host, + port: mqtt.port || 1883, + clientId: mqtt.clientId || `denon_${Math.random().toString(16).slice(3)}`, + prefix: `${mqtt.prefix}/${name}`, + user: mqtt.user, + passwd: mqtt.passwd, + debug: mqtt.debug || false }); this.mqtt.on('connected', (message) => { - this.emit('message', message); + this.emit('success', message); this.mqttConnected = true; }) .on('subscribed', (message) => { - this.emit('message', message); + this.emit('success', message); }) .on('subscribedMessage', async (key, value) => { try { - switch (key) { - case 'Power': - const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'Z3ON' : 'Z3OFF'); - await this.denon.send(powerState) - break; - case 'Input': - const input = `Z3${value}`; - await this.denon.send(input); - break; - case 'Volume': - const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); - const volume = this.masterVolume ? `MV${value1}` : `Z3${value1}`; - await this.denon.send(volume); - break; - case 'Mute': - const mute = this.masterMute ? (value ? 'MUON' : 'MUOFF') : (value ? 'Z3MUON' : 'Z3MUOFF'); - await this.denon.send(mute); - break; - case 'Surround': - const surround = `MS${value}`; - await this.denon.send(surround); - break; - case 'RcControl': - await this.denon.send(value); - break; - default: - this.emit('message', `MQTT Received unknown key: ${key}, value: ${value}`); - break; - }; + await this.setOverExternalIntegration('MQTT', key, value); } catch (error) { - this.emit('warn', `MQTT send error: ${error}.`); + this.emit('warn', `MQTT set error: ${error}.`); }; }) .on('debug', (debug) => { @@ -425,6 +404,44 @@ class Zone3 extends EventEmitter { }; } + async setOverExternalIntegration(integration, key, value) { + try { + let set = false + switch (key) { + case 'Power': + const powerState = this.masterPower ? (value ? 'PWON' : 'PWSTANDBY') : (value ? 'Z3ON' : 'Z3OFF'); + set = await this.denon.send(powerState) + break; + case 'Input': + const input = `Z3${value}`; + set = await this.denon.send(input); + break; + case 'Volume': + const value1 = (value < 0 || value > 100) ? this.volume : (value < 10 ? `0${value}` : value); + const volume = this.masterVolume ? `MV${value1}` : `Z3${value1}`; + set = await this.denon.send(volume); + break; + case 'Mute': + const mute = this.masterMute ? (value ? 'MUON' : 'MUOFF') : (value ? 'Z3MUON' : 'Z3MUOFF'); + set = await this.denon.send(mute); + break; + case 'Surround': + const surround = `MS${value}`; + set = await this.denon.send(surround); + break; + case 'RcControl': + set = await this.denon.send(value); + break; + default: + this.emit('warn', `${integration}, received key: ${key}, value: ${value}`); + break; + }; + return set; + } catch (error) { + throw new Error(`${integration} set key: ${key}, value: ${value}, error: ${error}`); + }; + } + //prepare accessory async prepareAccessory(allInputs) { try {