denon-mqtt 0.0.1

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.
Files changed (48) hide show
  1. package/README.md +217 -0
  2. package/dist/CliParser.d.ts +11 -0
  3. package/dist/CliParser.js +80 -0
  4. package/dist/CliParser.js.map +1 -0
  5. package/dist/CommandMessage.d.ts +6 -0
  6. package/dist/CommandMessage.js +3 -0
  7. package/dist/CommandMessage.js.map +1 -0
  8. package/dist/ListenerConfig.d.ts +5 -0
  9. package/dist/ListenerConfig.js +3 -0
  10. package/dist/ListenerConfig.js.map +1 -0
  11. package/dist/MqttBroadcaster.d.ts +22 -0
  12. package/dist/MqttBroadcaster.js +72 -0
  13. package/dist/MqttBroadcaster.js.map +1 -0
  14. package/dist/MqttListener.d.ts +19 -0
  15. package/dist/MqttListener.js +65 -0
  16. package/dist/MqttListener.js.map +1 -0
  17. package/dist/MqttManager.d.ts +24 -0
  18. package/dist/MqttManager.js +45 -0
  19. package/dist/MqttManager.js.map +1 -0
  20. package/dist/MqttUpdate.d.ts +6 -0
  21. package/dist/MqttUpdate.js +3 -0
  22. package/dist/MqttUpdate.js.map +1 -0
  23. package/dist/Orchestrator.d.ts +22 -0
  24. package/dist/Orchestrator.js +143 -0
  25. package/dist/Orchestrator.js.map +1 -0
  26. package/dist/ParserResult.d.ts +6 -0
  27. package/dist/ParserResult.js +3 -0
  28. package/dist/ParserResult.js.map +1 -0
  29. package/dist/ReceiverConfig.d.ts +7 -0
  30. package/dist/ReceiverConfig.js +3 -0
  31. package/dist/ReceiverConfig.js.map +1 -0
  32. package/dist/ReceiverManager.d.ts +16 -0
  33. package/dist/ReceiverManager.js +44 -0
  34. package/dist/ReceiverManager.js.map +1 -0
  35. package/dist/TelnetBroadcaster.d.ts +7 -0
  36. package/dist/TelnetBroadcaster.js +22 -0
  37. package/dist/TelnetBroadcaster.js.map +1 -0
  38. package/dist/TelnetListener.d.ts +12 -0
  39. package/dist/TelnetListener.js +84 -0
  40. package/dist/TelnetListener.js.map +1 -0
  41. package/dist/ZoneConfig.d.ts +5 -0
  42. package/dist/ZoneConfig.js +3 -0
  43. package/dist/ZoneConfig.js.map +1 -0
  44. package/dist/entryPoint.d.ts +2 -0
  45. package/dist/entryPoint.js +47 -0
  46. package/dist/entryPoint.js.map +1 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -0
  48. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,217 @@
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
+ denon-mqtt
101
+ ```
102
+
103
+ ### Run with Docker
104
+
105
+ Docker run:
106
+
107
+ ```bash
108
+ docker run douglampe/denon-mqtt:latest -v ./receivers.json:/app/receivers.json
109
+ ```
110
+
111
+ Docker compose:
112
+
113
+ ```yaml
114
+ services:
115
+ denon-mqtt:
116
+ container_name: denon-mqtt
117
+ image: douglampe/denon-mqtt:latest
118
+ volumes:
119
+ - ./receivers.json:/app/receivers.json
120
+ ```
121
+
122
+ ### Command Line Options
123
+
124
+ Options:
125
+
126
+ ```
127
+ -i, --info Display current version number
128
+ -f, --file <file> Get configuration from JSON file
129
+ -m, --mqtt <url> MQTT URL (default: "localhost")
130
+ -u, --username <username> MQTT Username (default: "user")
131
+ -p, --password <password> MQTT Password (default: "password")
132
+ --port MQTT Port <port>
133
+ --prefix MQTT Topic Prefix <prefix>
134
+ -a, --avr <list> Comma-separated list of AVR IP addresses
135
+ --name <list> Comma-separated list of AVR friendly names (default: "Home Theater")
136
+ --id <list> Comma-separated list of AVR unique IDs (default: "denon")
137
+ --zones <list> Comma-separated list of | separated AVR zone names (default: "Main|Zone 2")
138
+ -h, --help display help for command
139
+ ```
140
+
141
+ ### Running MQTT
142
+
143
+ You can use the below Docker compose configuration to run MQTT. Reference the mosquitto documentation for more details.
144
+
145
+ ```yaml
146
+ services:
147
+ eclipse-mosquitto:
148
+ container_name: mosquitto
149
+ image: eclipse-mosquitto:latest
150
+ restart: always
151
+ ports:
152
+ - 9001:9001
153
+ - 1883:1883
154
+ volumes:
155
+ - ./mosquitto.conf:/mosquitto/config/mosquitto.conf
156
+ - ./mosquitto-users.txt:/mosquitto/config/mosquitto-users.txt
157
+ ```
158
+
159
+ ## Contributing
160
+
161
+ ### Clone the repository
162
+
163
+ ```bash
164
+ git clone https://github.com/douglampe/denon-state-manager.git
165
+ ```
166
+
167
+ ### Install dependencies
168
+
169
+ ```bash
170
+ yarn
171
+ # OR
172
+ npm i
173
+ ```
174
+
175
+ ### Start eclipse mosquito MQTT and Home Assistant via docker
176
+
177
+ ```bash
178
+ docker compose up -d
179
+ ```
180
+
181
+ ### Start the interface in dev mode
182
+
183
+ ```bash
184
+ yarn dev
185
+ # OR
186
+ npm run dev
187
+ ```
188
+
189
+ ### Start the interface in dev mode using `receivers.json` to configure AVRs
190
+
191
+ ```bash
192
+ yarn dev:file
193
+ # OR
194
+ npm run dev:file
195
+ ```
196
+
197
+ ## What is This?
198
+
199
+ This project provides MQTT support Denon and Marantz Audio Video Receivers (AVRs). While it does not provide 100%
200
+ compatibility with the protocol, it has been developed in line with documentation for version ("Application model")
201
+ AVR-3312CI/AVR-3312 and version 0.06 of the specification for AVR-S700, S900, X1100, X3100, X4100, X5200, and X7200. It
202
+ has been tested with the following receiver models:
203
+
204
+ - S950H
205
+ - X4500H
206
+
207
+ ## Why Does This Exist?
208
+
209
+ Denon AVRs support both RS-232C and Ethernet interfaces. The Ethernet interface is a TCP interface which does not
210
+ require any authentication or authorization. The interface is bi-directional meaning that changes made to the reciever
211
+ by other sources (ex: using the remote control) are broadcasted to the interface. This makes the interface ideal for
212
+ integrating with systems which operate best while maitaining accurate state such as the Home Automation platform
213
+ Home Assistant. While integrating directly with Home Assistant has advantages such as reduced latency, there are
214
+ disadvantages such as platform lock-in. Existing Denon integrations also have limitations. By creating an MQTT
215
+ interface, multiple Denon AVRs can be integrated with Home Assistant using the supported MQTT integration while
216
+ also providing direct support for any platform that supports MQTT such as Node Red. I also get to write this in
217
+ 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,6 @@
1
+ import { ReceiverSettings, StateValue } from 'denon-state-manager';
2
+ export interface CommandMessage {
3
+ command: ReceiverSettings;
4
+ value?: StateValue;
5
+ zone?: number;
6
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=CommandMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandMessage.js","sourceRoot":"","sources":["../src/CommandMessage.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import { ReceiverSettings } from 'denon-state-manager';
2
+ export interface ListenerConfig {
3
+ command: ReceiverSettings;
4
+ zone: number;
5
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=ListenerConfig.js.map
@@ -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,6 @@
1
+ import { ReceiverSettings, StateValue } from 'denon-state-manager';
2
+ export interface MqttUpdate {
3
+ key: ReceiverSettings;
4
+ value: StateValue;
5
+ zone: number;
6
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=MqttUpdate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MqttUpdate.js","sourceRoot":"","sources":["../src/MqttUpdate.ts"],"names":[],"mappings":""}