denon-mqtt 0.0.2-beta.14665195558.0
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/README.md +219 -0
- package/dist/CliParser.d.ts +11 -0
- package/dist/CliParser.js +80 -0
- package/dist/CliParser.js.map +1 -0
- package/dist/CommandMessage.d.ts +6 -0
- package/dist/CommandMessage.js +3 -0
- package/dist/CommandMessage.js.map +1 -0
- package/dist/ListenerConfig.d.ts +5 -0
- package/dist/ListenerConfig.js +3 -0
- package/dist/ListenerConfig.js.map +1 -0
- package/dist/MqttBroadcaster.d.ts +22 -0
- package/dist/MqttBroadcaster.js +72 -0
- package/dist/MqttBroadcaster.js.map +1 -0
- package/dist/MqttListener.d.ts +19 -0
- package/dist/MqttListener.js +65 -0
- package/dist/MqttListener.js.map +1 -0
- package/dist/MqttManager.d.ts +24 -0
- package/dist/MqttManager.js +45 -0
- package/dist/MqttManager.js.map +1 -0
- package/dist/MqttUpdate.d.ts +6 -0
- package/dist/MqttUpdate.js +3 -0
- package/dist/MqttUpdate.js.map +1 -0
- package/dist/Orchestrator.d.ts +22 -0
- package/dist/Orchestrator.js +143 -0
- package/dist/Orchestrator.js.map +1 -0
- package/dist/ParserResult.d.ts +6 -0
- package/dist/ParserResult.js +3 -0
- package/dist/ParserResult.js.map +1 -0
- package/dist/ReceiverConfig.d.ts +7 -0
- package/dist/ReceiverConfig.js +3 -0
- package/dist/ReceiverConfig.js.map +1 -0
- package/dist/ReceiverManager.d.ts +16 -0
- package/dist/ReceiverManager.js +44 -0
- package/dist/ReceiverManager.js.map +1 -0
- package/dist/TelnetBroadcaster.d.ts +7 -0
- package/dist/TelnetBroadcaster.js +22 -0
- package/dist/TelnetBroadcaster.js.map +1 -0
- package/dist/TelnetListener.d.ts +12 -0
- package/dist/TelnetListener.js +84 -0
- package/dist/TelnetListener.js.map +1 -0
- package/dist/ZoneConfig.d.ts +5 -0
- package/dist/ZoneConfig.js +3 -0
- package/dist/ZoneConfig.js.map +1 -0
- package/dist/entryPoint.d.ts +1 -0
- package/dist/entryPoint.js +46 -0
- package/dist/entryPoint.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# denon-mqtt
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
### AVR Configuration
|
|
6
|
+
|
|
7
|
+
While it is possible to get the interface up and running with only command-line options, accessing all features requires
|
|
8
|
+
a configuration file to configure each AVR controlled by the interface. The interface will look for a file named
|
|
9
|
+
`receivers.json` using the following format(see `receivers.json.sample` for an example). In the example below, "Home
|
|
10
|
+
Theater" is the configuration for a Denon X4500H and "Office" is the configuration for a Denon S950H.
|
|
11
|
+
|
|
12
|
+
```JSON
|
|
13
|
+
[
|
|
14
|
+
{
|
|
15
|
+
"name": "Home Theater",
|
|
16
|
+
"ip": "192.168.0.1234",
|
|
17
|
+
"id": "home_theater",
|
|
18
|
+
"sources": [
|
|
19
|
+
{"code": "SAT/CBL", "display": "Fire TV"},
|
|
20
|
+
{"code": "DVD", "display": "AppleTV"},
|
|
21
|
+
{"code": "BD", "display": "Blu-ray"},
|
|
22
|
+
{"code": "GAME", "display": "XBox"},
|
|
23
|
+
{"code": "MPLAY", "display": "Karaoke"},
|
|
24
|
+
{"code": "TV", "display": "TV Audio"},
|
|
25
|
+
{"code": "AUX1", "display": "pi"},
|
|
26
|
+
{"code": "AUX2", "display": "AUX2"},
|
|
27
|
+
{"code": "CD", "display": "Alexa"},
|
|
28
|
+
{"code": "PHONO", "display": "Phono"},
|
|
29
|
+
{"code": "TUNER", "display": "Tuner"},
|
|
30
|
+
{"code": "NET", "display": "HEOS Music"}
|
|
31
|
+
],
|
|
32
|
+
"zones": [
|
|
33
|
+
{
|
|
34
|
+
"index": "1",
|
|
35
|
+
"name": "Living Room",
|
|
36
|
+
"sources": ["SAT/CBL","DVD","BD","GAME","MPLAY","TV","AUX1","AUX2","CD","PHONO","TUNER","NET"]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"index": "2",
|
|
40
|
+
"name": "Rumpus Room",
|
|
41
|
+
"sources": ["SAT/CBL","DVD","BD","GAME","MPLAY","TV","AUX1","AUX2","CD","PHONO","TUNER","NET"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"index": "3",
|
|
45
|
+
"name": "Back Porch",
|
|
46
|
+
"sources": ["SAT/CBL","DVD","BD","GAME","MPLAY","TV","AUX1","AUX2","CD","PHONO","TUNER","NET"]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "Office",
|
|
52
|
+
"ip": "192.168.0.5678",
|
|
53
|
+
"id": "office_avr",
|
|
54
|
+
"sources": [
|
|
55
|
+
{"code": "SAT/CBL", "display": "Xbox One"},
|
|
56
|
+
{"code": "DVD", "display": "DVD"},
|
|
57
|
+
{"code": "BD", "display": "Blu-ray"},
|
|
58
|
+
{"code": "GAME", "display": "Xbox One"},
|
|
59
|
+
{"code": "MPLAY", "display": "Media Player"},
|
|
60
|
+
{"code": "TV", "display": "TV Audio"},
|
|
61
|
+
{"code": "AUX1", "display": "AUX1"},
|
|
62
|
+
{"code": "AUX2", "display": "AUX2"},
|
|
63
|
+
{"code": "CD", "display": "Alexa"},
|
|
64
|
+
{"code": "PHONO", "display": "Phono"},
|
|
65
|
+
{"code": "TUNER", "display": "Tuner"},
|
|
66
|
+
{"code": "NET", "display": "HEOS Music"}
|
|
67
|
+
],
|
|
68
|
+
"zones": [
|
|
69
|
+
{
|
|
70
|
+
"index": "1",
|
|
71
|
+
"name": "Living Room",
|
|
72
|
+
"sources": ["SAT/CBL","DVD","BD","GAME","MPLAY","TV","AUX1","AUX2","CD","PHONO","TUNER","NET"]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"index": "2",
|
|
76
|
+
"name": "Rumpus Room",
|
|
77
|
+
"sources": ["SAT/CBL","DVD","BD","GAME","MPLAY","TV","AUX1","AUX2","CD","PHONO","TUNER","NET"]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"index": "3",
|
|
81
|
+
"name": "Back Porch",
|
|
82
|
+
"sources": ["SAT/CBL","DVD","BD","GAME","MPLAY","TV","AUX1","AUX2","CD","PHONO","TUNER","NET"]
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Install with yarn orn npm
|
|
90
|
+
|
|
91
|
+
This method requires [installing Node.js first](https://nodejs.org/en/download).
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Install:
|
|
95
|
+
yarn global add denon-mqtt
|
|
96
|
+
# OR
|
|
97
|
+
npm i -g denon-mqtt
|
|
98
|
+
|
|
99
|
+
# Run:
|
|
100
|
+
yarn denon-mqtt
|
|
101
|
+
# OR
|
|
102
|
+
npm run denon-mqtt
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Run with Docker
|
|
106
|
+
|
|
107
|
+
Docker run:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker run douglampe/denon-mqtt:latest -v ./receivers.json:/app/receivers.json
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Docker compose:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
services:
|
|
117
|
+
denon-mqtt:
|
|
118
|
+
container_name: denon-mqtt
|
|
119
|
+
image: douglampe/denon-mqtt:latest
|
|
120
|
+
volumes:
|
|
121
|
+
- ./receivers.json:/app/receivers.json
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Command Line Options
|
|
125
|
+
|
|
126
|
+
Options:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
-i, --info Display current version number
|
|
130
|
+
-f, --file <file> Get configuration from JSON file
|
|
131
|
+
-m, --mqtt <url> MQTT URL (default: "localhost")
|
|
132
|
+
-u, --username <username> MQTT Username (default: "user")
|
|
133
|
+
-p, --password <password> MQTT Password (default: "password")
|
|
134
|
+
--port MQTT Port <port>
|
|
135
|
+
--prefix MQTT Topic Prefix <prefix>
|
|
136
|
+
-a, --avr <list> Comma-separated list of AVR IP addresses
|
|
137
|
+
--name <list> Comma-separated list of AVR friendly names (default: "Home Theater")
|
|
138
|
+
--id <list> Comma-separated list of AVR unique IDs (default: "denon")
|
|
139
|
+
--zones <list> Comma-separated list of | separated AVR zone names (default: "Main|Zone 2")
|
|
140
|
+
-h, --help display help for command
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Running MQTT
|
|
144
|
+
|
|
145
|
+
You can use the below Docker compose configuration to run MQTT. Reference the mosquitto documentation for more details.
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
services:
|
|
149
|
+
eclipse-mosquitto:
|
|
150
|
+
container_name: mosquitto
|
|
151
|
+
image: eclipse-mosquitto:latest
|
|
152
|
+
restart: always
|
|
153
|
+
ports:
|
|
154
|
+
- 9001:9001
|
|
155
|
+
- 1883:1883
|
|
156
|
+
volumes:
|
|
157
|
+
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf
|
|
158
|
+
- ./mosquitto-users.txt:/mosquitto/config/mosquitto-users.txt
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Contributing
|
|
162
|
+
|
|
163
|
+
### Clone the repository
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
git clone https://github.com/douglampe/denon-state-manager.git
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Install dependencies
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
yarn
|
|
173
|
+
# OR
|
|
174
|
+
npm i
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Start eclipse mosquito MQTT and Home Assistant via docker
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
docker compose up -d
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Start the interface in dev mode
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
yarn dev
|
|
187
|
+
# OR
|
|
188
|
+
npm run dev
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Start the interface in dev mode using `receivers.json` to configure AVRs
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
yarn dev:file
|
|
195
|
+
# OR
|
|
196
|
+
npm run dev:file
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## What is This?
|
|
200
|
+
|
|
201
|
+
This project provides MQTT support Denon and Marantz Audio Video Receivers (AVRs). While it does not provide 100%
|
|
202
|
+
compatibility with the protocol, it has been developed in line with documentation for version ("Application model")
|
|
203
|
+
AVR-3312CI/AVR-3312 and version 0.06 of the specification for AVR-S700, S900, X1100, X3100, X4100, X5200, and X7200. It
|
|
204
|
+
has been tested with the following receiver models:
|
|
205
|
+
|
|
206
|
+
- S950H
|
|
207
|
+
- X4500H
|
|
208
|
+
|
|
209
|
+
## Why Does This Exist?
|
|
210
|
+
|
|
211
|
+
Denon AVRs support both RS-232C and Ethernet interfaces. The Ethernet interface is a TCP interface which does not
|
|
212
|
+
require any authentication or authorization. The interface is bi-directional meaning that changes made to the reciever
|
|
213
|
+
by other sources (ex: using the remote control) are broadcasted to the interface. This makes the interface ideal for
|
|
214
|
+
integrating with systems which operate best while maitaining accurate state such as the Home Automation platform
|
|
215
|
+
Home Assistant. While integrating directly with Home Assistant has advantages such as reduced latency, there are
|
|
216
|
+
disadvantages such as platform lock-in. Existing Denon integrations also have limitations. By creating an MQTT
|
|
217
|
+
interface, multiple Denon AVRs can be integrated with Home Assistant using the supported MQTT integration while
|
|
218
|
+
also providing direct support for any platform that supports MQTT such as Node Red. I also get to write this in
|
|
219
|
+
Node.js instead of python which is a win for me IMHO.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare class CliParser {
|
|
3
|
+
static isTest: boolean;
|
|
4
|
+
static log: (message: any) => void;
|
|
5
|
+
static run(options: {
|
|
6
|
+
name: string;
|
|
7
|
+
version: string;
|
|
8
|
+
args: string[];
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
static start(_opts: any, command: Command): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CliParser = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const Orchestrator_1 = require("./Orchestrator");
|
|
11
|
+
class CliParser {
|
|
12
|
+
static async run(options) {
|
|
13
|
+
const program = new commander_1.Command();
|
|
14
|
+
if (CliParser.isTest) {
|
|
15
|
+
program.exitOverride().configureOutput({
|
|
16
|
+
writeOut: CliParser.log,
|
|
17
|
+
writeErr: CliParser.log,
|
|
18
|
+
getOutHelpWidth: () => 160,
|
|
19
|
+
getErrHelpWidth: () => 160,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
program.name(options.name).version(options.version, '-i, --info', 'Display current version number');
|
|
23
|
+
program
|
|
24
|
+
.option('-f, --file <file>', 'Get configuration from JSON file')
|
|
25
|
+
.option('-m, --mqtt <url>', 'MQTT URL', 'localhost')
|
|
26
|
+
.option('-u, --username <username>', 'MQTT Username', 'user')
|
|
27
|
+
.option('-p, --password <password>', 'MQTT Password', 'password')
|
|
28
|
+
.option('--port', 'MQTT Port <port>', '1883')
|
|
29
|
+
.option('--prefix', 'MQTT Topic Prefix <prefix>', 'denon')
|
|
30
|
+
.option('-a, --avr <list>', 'Comma-separated list of AVR IP addresses')
|
|
31
|
+
.option('--name <list>', 'Comma-separated list of AVR friendly names', 'Home Theater')
|
|
32
|
+
.option('--id <list>', 'Comma-separated list of AVR unique IDs', 'denon')
|
|
33
|
+
.option('--zones <list>', 'Comma-separated list of | separated AVR zone names', 'Main|Zone 2')
|
|
34
|
+
.action(CliParser.start);
|
|
35
|
+
await program.parseAsync(options.args);
|
|
36
|
+
}
|
|
37
|
+
static async start(_opts, command) {
|
|
38
|
+
const opts = command.optsWithGlobals();
|
|
39
|
+
const options = Object.assign(Object.assign({}, opts), { receivers: [] });
|
|
40
|
+
if (opts.file) {
|
|
41
|
+
const file = path_1.default.resolve(opts.file);
|
|
42
|
+
const stat = await promises_1.default.stat(file);
|
|
43
|
+
if (!stat.isFile()) {
|
|
44
|
+
throw new Error(`File ${opts.file} not found (path: ${file})`);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const json = await promises_1.default.readFile(file);
|
|
48
|
+
const fileConfig = JSON.parse(json.toString());
|
|
49
|
+
for (const config of fileConfig) {
|
|
50
|
+
options.receivers.push(config);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
throw new Error(`Error parsing file ${opts.file}: ${err}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const avrHosts = opts.avr.split(',');
|
|
59
|
+
const avrNames = opts.name.split(',');
|
|
60
|
+
const avrIds = opts.id.split(',');
|
|
61
|
+
const zonesLists = opts.zones.split(',');
|
|
62
|
+
const zones = zonesLists.map((z) => z.split('|'));
|
|
63
|
+
if (avrHosts.length + avrNames.length + avrIds.length + zones.length !== avrHosts.length * 4) {
|
|
64
|
+
throw new Error('--avr, --name, --id, and --zones lists must be the same length.');
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0; i < avrHosts.length; i++) {
|
|
67
|
+
options.receivers.push({
|
|
68
|
+
id: avrIds[i],
|
|
69
|
+
name: avrNames[i],
|
|
70
|
+
ip: avrHosts[i],
|
|
71
|
+
zones: zones[i],
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return Orchestrator_1.Orchestrator.run(options);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.CliParser = CliParser;
|
|
79
|
+
CliParser.log = console.log;
|
|
80
|
+
//# sourceMappingURL=CliParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CliParser.js","sourceRoot":"","sources":["../src/CliParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandMessage.js","sourceRoot":"","sources":["../src/CommandMessage.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListenerConfig.js","sourceRoot":"","sources":["../src/ListenerConfig.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ReceiverSettings, ReceiverState, StateValue } from 'denon-state-manager';
|
|
2
|
+
import { MqttClient } from 'mqtt/*';
|
|
3
|
+
import { MqttUpdate } from './MqttUpdate';
|
|
4
|
+
export interface MqttBroadcasterOptions {
|
|
5
|
+
prefix: string;
|
|
6
|
+
id: string;
|
|
7
|
+
client: MqttClient;
|
|
8
|
+
}
|
|
9
|
+
export declare class MqttBroadcaster {
|
|
10
|
+
private options;
|
|
11
|
+
static DefaultOptions: {
|
|
12
|
+
prefix: string;
|
|
13
|
+
id: string;
|
|
14
|
+
};
|
|
15
|
+
constructor(options: MqttBroadcasterOptions);
|
|
16
|
+
getTopic(component: string, id: string, zone: number): string;
|
|
17
|
+
getStateWithKeys(state: {
|
|
18
|
+
[key in ReceiverSettings]?: StateValue;
|
|
19
|
+
}): Record<string, string | number | Record<string, string>>;
|
|
20
|
+
publish(update: MqttUpdate): Promise<void>;
|
|
21
|
+
publishState(state: ReceiverState, zone: number): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MqttBroadcaster = void 0;
|
|
4
|
+
const denon_state_manager_1 = require("denon-state-manager");
|
|
5
|
+
class MqttBroadcaster {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
getTopic(component, id, zone) {
|
|
10
|
+
const zonePrefix = zone == 1 ? 'main_zone' : `zone${zone}`;
|
|
11
|
+
return `${this.options.prefix}/${component}/${this.options.id}_${zonePrefix}_${id}/state`;
|
|
12
|
+
}
|
|
13
|
+
getStateWithKeys(state) {
|
|
14
|
+
var _a, _b, _c;
|
|
15
|
+
const stateWithKeys = {};
|
|
16
|
+
for (const [key, value] of Object.entries(state)) {
|
|
17
|
+
const name = denon_state_manager_1.ReceiverSettings[key];
|
|
18
|
+
const processedValue = (_c = (_b = (_a = value.dictionary) !== null && _a !== void 0 ? _a : value.numeric) !== null && _b !== void 0 ? _b : value.text) !== null && _c !== void 0 ? _c : value.raw;
|
|
19
|
+
if (processedValue) {
|
|
20
|
+
stateWithKeys[name] = processedValue;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return stateWithKeys;
|
|
24
|
+
}
|
|
25
|
+
async publish(update) {
|
|
26
|
+
var _a, _b, _c, _d, _e;
|
|
27
|
+
let component;
|
|
28
|
+
let message;
|
|
29
|
+
const key = (_a = update.key) !== null && _a !== void 0 ? _a : denon_state_manager_1.ReceiverSettings.None;
|
|
30
|
+
const id = denon_state_manager_1.ReceiverSettings[key].toLowerCase();
|
|
31
|
+
if (!update.value) {
|
|
32
|
+
console.error('update.value is undefined');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
switch (update.key) {
|
|
36
|
+
case denon_state_manager_1.ReceiverSettings.Power:
|
|
37
|
+
case denon_state_manager_1.ReceiverSettings.Mute:
|
|
38
|
+
component = 'switch';
|
|
39
|
+
message = (_b = update.value.text) !== null && _b !== void 0 ? _b : '';
|
|
40
|
+
break;
|
|
41
|
+
case denon_state_manager_1.ReceiverSettings.Source:
|
|
42
|
+
component = 'select';
|
|
43
|
+
message = (_c = update.value.text) !== null && _c !== void 0 ? _c : '';
|
|
44
|
+
break;
|
|
45
|
+
case denon_state_manager_1.ReceiverSettings.Volume:
|
|
46
|
+
component = 'volume';
|
|
47
|
+
message = (_e = (_d = update.value.numeric) === null || _d === void 0 ? void 0 : _d.toString()) !== null && _e !== void 0 ? _e : '';
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
if (message === '') {
|
|
51
|
+
throw new Error(`Could not parse message payload from value for setting ${denon_state_manager_1.ReceiverSettings[key]}: ${JSON.stringify(update.value)}`);
|
|
52
|
+
}
|
|
53
|
+
if (component && message) {
|
|
54
|
+
const topic = this.getTopic(component, id, update.zone);
|
|
55
|
+
console.debug(`Sending message to topic ${topic}: ${message}`);
|
|
56
|
+
this.options.client.publish(topic, message);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async publishState(state, zone) {
|
|
60
|
+
const message = JSON.stringify(this.getStateWithKeys(state.state));
|
|
61
|
+
const topic = this.getTopic('sensor', 'state', zone);
|
|
62
|
+
console.debug(`Sending message to topic ${topic}: ${message}`);
|
|
63
|
+
this.options.client.publish(topic, message);
|
|
64
|
+
return Promise.resolve();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.MqttBroadcaster = MqttBroadcaster;
|
|
68
|
+
MqttBroadcaster.DefaultOptions = {
|
|
69
|
+
prefix: 'denon',
|
|
70
|
+
id: 'denon',
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=MqttBroadcaster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttBroadcaster.js","sourceRoot":"","sources":["../src/MqttBroadcaster.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ReceiverSettings } from 'denon-state-manager';
|
|
2
|
+
import { MqttClient } from 'mqtt';
|
|
3
|
+
import { ReceiverManager } from './ReceiverManager';
|
|
4
|
+
export interface MqttListenerOptions {
|
|
5
|
+
prefix: string;
|
|
6
|
+
id: string;
|
|
7
|
+
client: MqttClient;
|
|
8
|
+
receiver: ReceiverManager;
|
|
9
|
+
}
|
|
10
|
+
export declare class MqttListener {
|
|
11
|
+
private options;
|
|
12
|
+
private listenerConfigs;
|
|
13
|
+
constructor(options: MqttListenerOptions);
|
|
14
|
+
getTopic(component: string, id: string, zone: number): string;
|
|
15
|
+
listenToZone(component: string, command: ReceiverSettings, zone: number): Promise<void>;
|
|
16
|
+
listenToTopic(topic: string): Promise<void>;
|
|
17
|
+
listen(): Promise<void>;
|
|
18
|
+
handleMessage(command: ReceiverSettings, body: string, zone: number): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MqttListener = void 0;
|
|
4
|
+
const denon_state_manager_1 = require("denon-state-manager");
|
|
5
|
+
class MqttListener {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
this.listenerConfigs = {};
|
|
9
|
+
}
|
|
10
|
+
getTopic(component, id, zone) {
|
|
11
|
+
const zonePrefix = zone == 1 ? 'main_zone' : `zone${zone}`;
|
|
12
|
+
return `${this.options.prefix}/${component}/${this.options.id}_${zonePrefix}_${id}/command`;
|
|
13
|
+
}
|
|
14
|
+
async listenToZone(component, command, zone) {
|
|
15
|
+
const topic = this.getTopic(component, denon_state_manager_1.ReceiverSettings[command].toLowerCase(), zone);
|
|
16
|
+
this.listenerConfigs[topic] = { command, zone };
|
|
17
|
+
await this.listenToTopic(topic);
|
|
18
|
+
}
|
|
19
|
+
async listenToTopic(topic) {
|
|
20
|
+
await this.options.client.subscribeAsync(topic);
|
|
21
|
+
console.debug(`Listening to topic ${topic}`);
|
|
22
|
+
}
|
|
23
|
+
async listen() {
|
|
24
|
+
for (let i = 1; i <= this.options.receiver.options.zones.length; i++) {
|
|
25
|
+
const zone = this.options.receiver.options.zones[i - 1];
|
|
26
|
+
console.debug(`Configuring receiver ${this.options.receiver.options.name} zone ${zone}`);
|
|
27
|
+
const promises = [];
|
|
28
|
+
promises.push(this.listenToTopic(`${this.options.prefix}/device/command`));
|
|
29
|
+
promises.push(this.listenToZone('switch', denon_state_manager_1.ReceiverSettings.Power, i));
|
|
30
|
+
promises.push(this.listenToZone('switch', denon_state_manager_1.ReceiverSettings.Mute, i));
|
|
31
|
+
promises.push(this.listenToZone('select', denon_state_manager_1.ReceiverSettings.Source, i));
|
|
32
|
+
promises.push(this.listenToZone('volume', denon_state_manager_1.ReceiverSettings.Volume, i));
|
|
33
|
+
await Promise.allSettled(promises);
|
|
34
|
+
}
|
|
35
|
+
this.options.client.on('message', async (topic, message) => {
|
|
36
|
+
const body = message.toString();
|
|
37
|
+
console.debug(`MQTT Message on topic ${topic}:`, body);
|
|
38
|
+
if (topic === `${this.options.prefix}/device/command` && body === 'REFRESH') {
|
|
39
|
+
await this.options.receiver.query();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const config = this.listenerConfigs[topic];
|
|
43
|
+
if (config) {
|
|
44
|
+
this.handleMessage(config.command, body, config.zone)
|
|
45
|
+
.then()
|
|
46
|
+
.catch((error) => console.error(error));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.debug(`No configuration found for topic ${topic}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async handleMessage(command, body, zone) {
|
|
54
|
+
const value = JSON.parse(body);
|
|
55
|
+
const avrCommand = zone === 1 ? denon_state_manager_1.MessageFormatter.getCommand(command, value) : denon_state_manager_1.MessageFormatter.getCommand(command, value, zone);
|
|
56
|
+
if (avrCommand) {
|
|
57
|
+
await this.options.receiver.send(avrCommand);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.debug(`No message translation found for command ${denon_state_manager_1.ReceiverSettings[command]} for zone ${zone} or error parsing value:`, value);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.MqttListener = MqttListener;
|
|
65
|
+
//# sourceMappingURL=MqttListener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttListener.js","sourceRoot":"","sources":["../src/MqttListener.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ReceiverState } from 'denon-state-manager';
|
|
2
|
+
import { MqttClient } from 'mqtt/*';
|
|
3
|
+
import { MqttUpdate } from './MqttUpdate';
|
|
4
|
+
import { ReceiverConfig } from './ReceiverConfig';
|
|
5
|
+
import { ReceiverManager } from './ReceiverManager';
|
|
6
|
+
export interface MqttManagerOptions {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
username: string;
|
|
10
|
+
password: string;
|
|
11
|
+
prefix: string;
|
|
12
|
+
id: string;
|
|
13
|
+
receiver: ReceiverConfig;
|
|
14
|
+
}
|
|
15
|
+
export declare class MqttManager {
|
|
16
|
+
private mqttClient;
|
|
17
|
+
private options;
|
|
18
|
+
private broadcaster;
|
|
19
|
+
constructor(mqttClient: MqttClient, options: MqttManagerOptions);
|
|
20
|
+
connect(receiver: ReceiverManager): Promise<void>;
|
|
21
|
+
publish(update: MqttUpdate): Promise<void>;
|
|
22
|
+
publishState(state: ReceiverState, zone: number): Promise<void>;
|
|
23
|
+
disconnect(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MqttManager = void 0;
|
|
4
|
+
const MqttBroadcaster_1 = require("./MqttBroadcaster");
|
|
5
|
+
const MqttListener_1 = require("./MqttListener");
|
|
6
|
+
class MqttManager {
|
|
7
|
+
constructor(mqttClient, options) {
|
|
8
|
+
this.mqttClient = mqttClient;
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
async connect(receiver) {
|
|
12
|
+
this.broadcaster = new MqttBroadcaster_1.MqttBroadcaster({
|
|
13
|
+
prefix: this.options.prefix,
|
|
14
|
+
id: this.options.receiver.id,
|
|
15
|
+
client: this.mqttClient,
|
|
16
|
+
});
|
|
17
|
+
const mqttListener = new MqttListener_1.MqttListener({
|
|
18
|
+
prefix: this.options.prefix,
|
|
19
|
+
id: this.options.id,
|
|
20
|
+
client: this.mqttClient,
|
|
21
|
+
receiver,
|
|
22
|
+
});
|
|
23
|
+
await mqttListener.listen();
|
|
24
|
+
}
|
|
25
|
+
publish(update) {
|
|
26
|
+
return this.broadcaster.publish(update);
|
|
27
|
+
}
|
|
28
|
+
publishState(state, zone) {
|
|
29
|
+
return this.broadcaster.publishState(state, zone);
|
|
30
|
+
}
|
|
31
|
+
disconnect() {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
this.mqttClient.end((error) => {
|
|
34
|
+
if (error) {
|
|
35
|
+
reject(error);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
resolve();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.MqttManager = MqttManager;
|
|
45
|
+
//# sourceMappingURL=MqttManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttManager.js","sourceRoot":"","sources":["../src/MqttManager.ts"],"names":[],"mappings":";;;AAGA,uDAAoD;AACpD,iDAA8C;AAe9C,MAAa,WAAW;IAGtB,YACU,UAAsB,EACtB,OAA2B;QAD3B,eAAU,GAAV,UAAU,CAAY;QACtB,YAAO,GAAP,OAAO,CAAoB;IAClC,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,QAAyB;QACrC,IAAI,CAAC,WAAW,GAAG,IAAI,iCAAe,CAAC;YACrC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAC3B,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC5B,MAAM,EAAE,IAAI,CAAC,UAAU;SACxB,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,IAAI,2BAAY,CAAC;YACpC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAC3B,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE;YACnB,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,QAAQ;SACT,CAAC,CAAC;QACH,MAAM,YAAY,CAAC,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,MAAkB;QACxB,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,YAAY,CAAC,KAAoB,EAAE,IAAY;QAC7C,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,UAAU;QACR,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC5B,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;qBAAM,CAAC;oBACN,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA3CD,kCA2CC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MqttUpdate.js","sourceRoot":"","sources":["../src/MqttUpdate.ts"],"names":[],"mappings":""}
|