homebridge-denon-tv 4.2.6 → 4.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +11 -1
- package/config.schema.json +39 -0
- package/package.json +3 -2
- package/src/denon.js +19 -4
- package/src/denondevice.js +29 -1
- package/src/mqtt.js +2 -1
- package/src/restful.js +58 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
## The properties *inputs.displayType* and *surrounds.displayType* are removed.
|
|
9
9
|
## Note - after update to 3.15.x need remove the accessory frome Home app and add it again.
|
|
10
10
|
|
|
11
|
+
## [4.3.0] - (29.03.2023)
|
|
12
|
+
## Note - after update to 4.1.x buttons need to be configure again using config UI.
|
|
13
|
+
## Changes
|
|
14
|
+
- added RESTFul server
|
|
15
|
+
- code refactor and cleanup
|
|
16
|
+
- config.schema updated
|
|
17
|
+
- fixed some minor issues
|
|
18
|
+
|
|
11
19
|
## [4.1.0] - (02.03.2023)
|
|
12
20
|
## Note - after update to 4.1.x buttons need to be configure again using config UI.
|
|
13
21
|
## Changes
|
package/README.md
CHANGED
|
@@ -35,8 +35,15 @@ Tested with Denon AVR-X6300H, Denon AVR-X2700H, Denon AVR-3311CI, Marantz SR8012
|
|
|
35
35
|
* Digital Input Modes can be controlled by creating separate tile in the buttons section.
|
|
36
36
|
* Siri can be used for all functions, some times need create legacy buttons/switches/sensors.
|
|
37
37
|
* Automations can be used for all functions, some times need create legacy buttons/switches/sensors.
|
|
38
|
-
* MQTT publisch topic *Info*, *State* *Picture* and *Surround* as payload JSON data.
|
|
39
38
|
* This plugin is based upon the official documentation: [Denon Control Protocol 2020](https://github.com/grzegorz914/homebridge-denon-tv/blob/main/src/Denon%20Control%20Protocol.xlsx)
|
|
39
|
+
* RESTful server:
|
|
40
|
+
* Request: `http//homebridge_ip_address:port/path`.
|
|
41
|
+
* Path: `info`, `state`, `picture`, `surround`.
|
|
42
|
+
* Respone as JSON data.
|
|
43
|
+
* MQTT client:
|
|
44
|
+
* Topic: `Info`, `State`, `Picture`, `Surround`.
|
|
45
|
+
* Publish as JSON data.
|
|
46
|
+
|
|
40
47
|
|
|
41
48
|
<p align="left">
|
|
42
49
|
<a href="https://github.com/grzegorz914/homebridge-denon-tv"><img src="https://raw.githubusercontent.com/grzegorz914/homebridge-denon-tv/main/graphics/homekit.png" width="382"></a>
|
|
@@ -90,6 +97,9 @@ Tested with Denon AVR-X6300H, Denon AVR-X2700H, Denon AVR-3311CI, Marantz SR8012
|
|
|
90
97
|
| `volumeControl` | Here choice what a additional volume control mode You want to use (`-1 - None/Disabled`, `0 - Lightbulb`, `1 - Fan`). |
|
|
91
98
|
| `infoButtonCommand` | Here select the function of `I` button in RC app. |
|
|
92
99
|
| `refreshInterval` | Here set the data refresh interval. |
|
|
100
|
+
| `enableRestFul` | If enabled, RESTful server will start automatically and respond to any path request. |
|
|
101
|
+
| `restFulPort` | Here set the listening `Port` for RESTful server, every zone need other port. |
|
|
102
|
+
| `restFulDebug` | If enabled, deep log will be present in homebridge console for RESTFul server. |
|
|
93
103
|
| `enableMqtt` | If enabled, MQTT Broker will start automatically and publish all awailable PV installation data. |
|
|
94
104
|
| `mqttDebug` | If enabled, deep log will be present in homebridge console for MQTT. |
|
|
95
105
|
| `mqttHost` | Here set the *IP Address* or *Hostname* for MQTT Broker. |
|
package/config.schema.json
CHANGED
|
@@ -4604,6 +4604,33 @@
|
|
|
4604
4604
|
"description": "Here set the background data refresh interval.",
|
|
4605
4605
|
"required": true
|
|
4606
4606
|
},
|
|
4607
|
+
"enableRestFul": {
|
|
4608
|
+
"title": "Enable",
|
|
4609
|
+
"type": "boolean",
|
|
4610
|
+
"default": false,
|
|
4611
|
+
"required": false,
|
|
4612
|
+
"description": "This enable RESTful server."
|
|
4613
|
+
},
|
|
4614
|
+
"restFulDebug": {
|
|
4615
|
+
"title": "Debug",
|
|
4616
|
+
"type": "boolean",
|
|
4617
|
+
"default": false,
|
|
4618
|
+
"required": false,
|
|
4619
|
+
"description": "This enable debug mode for RESTFul.",
|
|
4620
|
+
"condition": {
|
|
4621
|
+
"functionBody": "return model.devices[arrayIndices].enableRestFul === true;"
|
|
4622
|
+
}
|
|
4623
|
+
},
|
|
4624
|
+
"restFulPort": {
|
|
4625
|
+
"title": "Port",
|
|
4626
|
+
"type": "integer",
|
|
4627
|
+
"placeholder": 3000,
|
|
4628
|
+
"required": true,
|
|
4629
|
+
"description": "Here set the listening Port for RESTful server.",
|
|
4630
|
+
"condition": {
|
|
4631
|
+
"functionBody": "return model.devices[arrayIndices].enableRestFul === true;"
|
|
4632
|
+
}
|
|
4633
|
+
},
|
|
4607
4634
|
"enableMqtt": {
|
|
4608
4635
|
"title": "Enable",
|
|
4609
4636
|
"type": "boolean",
|
|
@@ -4814,6 +4841,18 @@
|
|
|
4814
4841
|
"devices[].refreshInterval"
|
|
4815
4842
|
]
|
|
4816
4843
|
},
|
|
4844
|
+
{
|
|
4845
|
+
"key": "devices[]",
|
|
4846
|
+
"type": "section",
|
|
4847
|
+
"title": "RESTful",
|
|
4848
|
+
"expandable": true,
|
|
4849
|
+
"expanded": false,
|
|
4850
|
+
"items": [
|
|
4851
|
+
"devices[].enableRestFul",
|
|
4852
|
+
"devices[].restFulDebug",
|
|
4853
|
+
"devices[].restFulPort"
|
|
4854
|
+
]
|
|
4855
|
+
},
|
|
4817
4856
|
{
|
|
4818
4857
|
"key": "devices[]",
|
|
4819
4858
|
"type": "section",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "Denon TV",
|
|
3
3
|
"name": "homebridge-denon-tv",
|
|
4
|
-
"version": "4.2
|
|
4
|
+
"version": "4.3.0-beta.2",
|
|
5
5
|
"description": "Homebridge plugin (https://github.com/homebridge/homebridge) to control Denon/Marantz AV Receivers.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"async-mqtt": "^2.6.3",
|
|
32
32
|
"axios": "^1.4.0",
|
|
33
|
-
"fast-xml-parser": "^4.2.6"
|
|
33
|
+
"fast-xml-parser": "^4.2.6",
|
|
34
|
+
"express": "^4.18.2"
|
|
34
35
|
},
|
|
35
36
|
"keywords": [
|
|
36
37
|
"homebridge",
|
package/src/denon.js
CHANGED
|
@@ -13,6 +13,7 @@ class DENON extends EventEmitter {
|
|
|
13
13
|
const zoneControl = config.zoneControl;
|
|
14
14
|
const debugLog = config.debugLog;
|
|
15
15
|
const disableLogConnectError = config.disableLogConnectError;
|
|
16
|
+
const restFulEnabled = config.restFulEnabled;
|
|
16
17
|
const mqttEnabled = config.mqttEnabled;
|
|
17
18
|
this.refreshInterval = config.refreshInterval;
|
|
18
19
|
|
|
@@ -157,8 +158,15 @@ class DENON extends EventEmitter {
|
|
|
157
158
|
return;
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
|
|
160
162
|
this.emit('deviceInfo', devInfo, manufacturer, modelName, serialNumber, firmwareRevision, zones, apiVersion, supportPictureMode, supportFavorites, supportShortcut, supportInputSource, supportQuickSmartSelect);
|
|
161
|
-
|
|
163
|
+
|
|
164
|
+
//restFul
|
|
165
|
+
const restFul = restFulEnabled ? this.emit('restFul', 'info', devInfo) : false;
|
|
166
|
+
|
|
167
|
+
//mqtt
|
|
168
|
+
const mqtt = mqttEnabled ? this.emit('mqtt', 'Info', devInfo) : false;
|
|
169
|
+
|
|
162
170
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
163
171
|
this.supportPictureMode = supportPictureMode;
|
|
164
172
|
this.supportSoundMode = supportSoundMode;
|
|
@@ -225,9 +233,16 @@ class DENON extends EventEmitter {
|
|
|
225
233
|
this.soundMode = soundMode;
|
|
226
234
|
|
|
227
235
|
this.emit('stateChanged', power, reference, volume, volumeDisplay, mute, pictureMode);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const
|
|
236
|
+
|
|
237
|
+
//restFul
|
|
238
|
+
const restFul = restFulEnabled ? this.emit('restFul', 'state', devState) : false;
|
|
239
|
+
const restFul1 = restFulEnabled && checkPictureMode ? this.emit('restFul', 'picture', { 'Picture Mode': CONSTANS.PictureModesDenonNumber[pictureMode] }) : false;
|
|
240
|
+
const restFul2 = restFulEnabled && checkSoundeMode ? this.emit('restFul', 'surround', { 'Sound Mode': CONSTANS.SoundModeConversion[soundMode] }) : false;
|
|
241
|
+
|
|
242
|
+
//mqtt
|
|
243
|
+
const mqtt1 = mqttEnabled ? this.emit('mqtt', 'State', devState) : false;
|
|
244
|
+
const mqtt2 = mqttEnabled && checkPictureMode ? this.emit('mqtt', 'Picture', { 'Picture Mode': CONSTANS.PictureModesDenonNumber[pictureMode] }) : false;
|
|
245
|
+
const mqtt3 = mqttEnabled && checkSoundeMode ? this.emit('mqtt', 'Surround', { 'Sound Mode': CONSTANS.SoundModeConversion[soundMode] }) : false;
|
|
231
246
|
this.checkState();
|
|
232
247
|
} catch (error) {
|
|
233
248
|
const debug = disableLogConnectError ? false : this.emit('error', `State error: ${error}, reconnect in 15s.`);
|
package/src/denondevice.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const fsPromises = fs.promises;
|
|
4
4
|
const EventEmitter = require('events');
|
|
5
|
+
const RestFul = require('./restful.js');
|
|
5
6
|
const Mqtt = require('./mqtt.js');
|
|
6
7
|
const Denon = require('./denon.js');
|
|
7
8
|
const CONSTANS = require('./constans.json');
|
|
@@ -44,6 +45,9 @@ class DenonDevice extends EventEmitter {
|
|
|
44
45
|
this.infoButtonCommand = config.infoButtonCommand || 'MNINF';
|
|
45
46
|
this.volumeControl = config.volumeControl >= 0 ? config.volumeControl : -1;
|
|
46
47
|
this.refreshInterval = config.refreshInterval || 5;
|
|
48
|
+
this.restFulEnabled = config.enableRestFul || false;
|
|
49
|
+
this.restFulPort = config.restFulPort || 3000;
|
|
50
|
+
this.restFulDebug = config.restFulDebug || false;
|
|
47
51
|
this.mqttEnabled = config.enableMqtt || false;
|
|
48
52
|
this.mqttDebug = config.mqttDebug || false;
|
|
49
53
|
this.mqttHost = config.mqttHost;
|
|
@@ -60,6 +64,7 @@ class DenonDevice extends EventEmitter {
|
|
|
60
64
|
|
|
61
65
|
//setup variables
|
|
62
66
|
this.startPrepareAccessory = true;
|
|
67
|
+
this.restFulConnected = false;
|
|
63
68
|
this.mqttConnected = false;
|
|
64
69
|
this.services = [];
|
|
65
70
|
this.inputsReference = [];
|
|
@@ -89,7 +94,26 @@ class DenonDevice extends EventEmitter {
|
|
|
89
94
|
this.inputsNamesFile = `${prefDir}/inputsNames_${this.sZoneName}${this.host.split('.').join('')}`;
|
|
90
95
|
this.inputsTargetVisibilityFile = `${prefDir}/inputsTargetVisibility_${this.sZoneName}${this.host.split('.').join('')}`;
|
|
91
96
|
|
|
92
|
-
//
|
|
97
|
+
//RESTFul server
|
|
98
|
+
if (this.restFulEnabled) {
|
|
99
|
+
this.restFul = new RestFul({
|
|
100
|
+
port: this.restFulPort,
|
|
101
|
+
debug: this.restFulDebug
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.restFul.on('connected', (message) => {
|
|
105
|
+
this.emit('message', `${message}`);
|
|
106
|
+
this.restFulConnected = true;
|
|
107
|
+
})
|
|
108
|
+
.on('error', (error) => {
|
|
109
|
+
this.emit('error', error);
|
|
110
|
+
})
|
|
111
|
+
.on('debug', (debug) => {
|
|
112
|
+
this.emit('debug', debug);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
//MQTT client
|
|
93
117
|
if (this.mqttEnabled) {
|
|
94
118
|
this.mqtt = new Mqtt({
|
|
95
119
|
host: this.mqttHost,
|
|
@@ -122,6 +146,7 @@ class DenonDevice extends EventEmitter {
|
|
|
122
146
|
disableLogConnectError: this.disableLogConnectError,
|
|
123
147
|
zoneControl: this.zoneControl,
|
|
124
148
|
refreshInterval: this.refreshInterval,
|
|
149
|
+
restFulEnabled: this.restFulEnabled,
|
|
125
150
|
mqttEnabled: this.mqttEnabled
|
|
126
151
|
});
|
|
127
152
|
|
|
@@ -383,6 +408,9 @@ class DenonDevice extends EventEmitter {
|
|
|
383
408
|
.on('error', (error) => {
|
|
384
409
|
this.emit('error', error);
|
|
385
410
|
})
|
|
411
|
+
.on('restFul', (path, data) => {
|
|
412
|
+
const restFul = this.restFulConnected ? this.restFul.update(path, data) : false;
|
|
413
|
+
})
|
|
386
414
|
.on('mqtt', (topic, message) => {
|
|
387
415
|
const mqtt = this.mqttConnected ? this.mqtt.send(topic, message) : false;
|
|
388
416
|
})
|
package/src/mqtt.js
CHANGED
|
@@ -41,7 +41,8 @@ class MQTTCLIENT extends EventEmitter {
|
|
|
41
41
|
|
|
42
42
|
try {
|
|
43
43
|
const fullTopic = `${this.mqttPrefix}/${topic}`;
|
|
44
|
-
|
|
44
|
+
const publishMessage = JSON.stringify(message, null, 2);
|
|
45
|
+
await this.mqttClient.publish(fullTopic, publishMessage);
|
|
45
46
|
const debug = this.mqttDebug ? this.emit('debug', `MQTT publish: ${fullTopic}: ${message}`) : false;
|
|
46
47
|
} catch (error) {
|
|
47
48
|
this.emit('error', `MQTT Publish error: ${error}`);
|
package/src/restful.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const EventEmitter = require('events');
|
|
4
|
+
|
|
5
|
+
class RestFul extends EventEmitter {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
super();
|
|
8
|
+
this.restFulPort = config.port;
|
|
9
|
+
this.restFulDebug = config.debug;
|
|
10
|
+
|
|
11
|
+
this.restFulData = {
|
|
12
|
+
info: 'This data is not available in this zone.',
|
|
13
|
+
state: 'This data is not available in this zone.',
|
|
14
|
+
picture: 'This data is not available in this zone.',
|
|
15
|
+
surround: 'This data is not available in this zone.'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
this.connect();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
connect() {
|
|
22
|
+
try {
|
|
23
|
+
const restFul = express();
|
|
24
|
+
restFul.get('/info', (req, res) => { res.json(this.restFulData.info) });
|
|
25
|
+
restFul.get('/state', (req, res) => { res.json(this.restFulData.state) });
|
|
26
|
+
restFul.get('/picture', (req, res) => { res.json(this.restFulData.picture) });
|
|
27
|
+
restFul.get('/surround', (req, res) => { res.json(this.restFulData.surround) });
|
|
28
|
+
|
|
29
|
+
restFul.listen(this.restFulPort, () => {
|
|
30
|
+
this.emit('connected', `RESTful started on port: ${this.restFulPort}`)
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
} catch (error) {
|
|
34
|
+
this.emit('error', `RESTful error: ${error}`)
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
update(path, data) {
|
|
39
|
+
switch (path) {
|
|
40
|
+
case 'info':
|
|
41
|
+
this.restFulData.info = data;
|
|
42
|
+
break;
|
|
43
|
+
case 'state':
|
|
44
|
+
this.restFulData.state = data;
|
|
45
|
+
break;
|
|
46
|
+
case 'picture':
|
|
47
|
+
this.restFulData.picture = data;
|
|
48
|
+
break;
|
|
49
|
+
case 'surround':
|
|
50
|
+
this.restFulData.surround = data;
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
break;
|
|
54
|
+
};
|
|
55
|
+
const emitDebug = this.restFulDebug ? this.emit('debug', `RESTFul update path: ${path}, data: ${data}`) : false;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
module.exports = RestFul;
|