homebridge-bose-soundtouch 1.8.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/.eslintrc.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "extends": [
4
+ "eslint:recommended",
5
+ "plugin:@typescript-eslint/eslint-recommended",
6
+ "plugin:@typescript-eslint/recommended"
7
+ ],
8
+ "parserOptions": {
9
+ "ecmaVersion": 2022,
10
+ "sourceType": "module"
11
+ },
12
+ "rules": {
13
+ "quotes": ["warn", "single"],
14
+ "indent": ["warn", 2, { "SwitchCase": 1 }],
15
+ "semi": ["error", "always"],
16
+ "comma-dangle": ["warn", "always-multiline"],
17
+ "dot-notation": "off",
18
+ "eqeqeq": "warn",
19
+ "curly": ["warn", "all"],
20
+ "brace-style": ["warn"],
21
+ "prefer-arrow-callback": ["warn"],
22
+ "max-len": ["warn", 140],
23
+ "no-console": ["warn"],
24
+ "@typescript-eslint/no-non-null-assertion": "off"
25
+ }
26
+ }
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # Homebridge Bose SoundTouch
2
+
3
+ Ein Homebridge Plugin zur Steuerung von Bose SoundTouch Lautsprechern via Apple HomeKit.
4
+
5
+ ## Features
6
+
7
+ - **Automatische Erkennung** - Findet SoundTouch-Geräte automatisch im Netzwerk via mDNS
8
+ - **Lautstärkesteuerung** - Regeln der Lautstärke über HomeKit
9
+ - **Wiedergabesteuerung** - Play, Pause, Stop, Nächster/Vorheriger Track
10
+ - **Presets/Favoriten** - Schnellzugriff auf gespeicherte Sender als Schalter
11
+ - **Stummschaltung** - Mute-Funktion
12
+ - **Echtzeit-Updates** - WebSocket-Verbindung für sofortige Statusänderungen
13
+ - **Multi-Room** - Unterstützung für mehrere Geräte
14
+
15
+ ## Installation
16
+
17
+ ### Über Homebridge UI
18
+
19
+ 1. Suche nach `homebridge-bose-soundtouch` in der Plugin-Suche
20
+ 2. Klicke auf "Installieren"
21
+
22
+ ### Manuell via npm
23
+
24
+ ```bash
25
+ npm install -g homebridge-bose-soundtouch
26
+ ```
27
+
28
+ ### Aus dem Quellcode
29
+
30
+ ```bash
31
+ cd homebridge-bose-soundtouch
32
+ npm install
33
+ npm run build
34
+ npm link
35
+ ```
36
+
37
+ ## Konfiguration
38
+
39
+ ### Minimale Konfiguration (Auto-Discovery)
40
+
41
+ ```json
42
+ {
43
+ "platforms": [
44
+ {
45
+ "platform": "BoseSoundTouch",
46
+ "name": "Bose SoundTouch"
47
+ }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ ### Vollständige Konfiguration
53
+
54
+ ```json
55
+ {
56
+ "platforms": [
57
+ {
58
+ "platform": "BoseSoundTouch",
59
+ "name": "Bose SoundTouch",
60
+ "autoDiscover": true,
61
+ "discoveryTimeout": 10000,
62
+ "enableSmartSpeaker": true,
63
+ "volumeAsLightbulb": false,
64
+ "enablePresets": true,
65
+ "devices": [
66
+ {
67
+ "name": "Wohnzimmer Speaker",
68
+ "host": "192.168.1.100",
69
+ "room": "Wohnzimmer"
70
+ },
71
+ {
72
+ "name": "Schlafzimmer Speaker",
73
+ "host": "192.168.1.101",
74
+ "room": "Schlafzimmer"
75
+ }
76
+ ]
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ ### Konfigurationsoptionen
83
+
84
+ | Option | Typ | Standard | Beschreibung |
85
+ |--------|-----|----------|--------------|
86
+ | `platform` | string | **Pflicht** | Muss `"BoseSoundTouch"` sein |
87
+ | `name` | string | **Pflicht** | Name der Plattform |
88
+ | `autoDiscover` | boolean | `true` | Automatische Geräteerkennung |
89
+ | `discoveryTimeout` | number | `10000` | Timeout für Discovery in ms |
90
+ | `enableSmartSpeaker` | boolean | `true` | SmartSpeaker-Service aktivieren |
91
+ | `volumeAsLightbulb` | boolean | `false` | Lautstärke als Lampe darstellen (besserer Slider) |
92
+ | `enablePresets` | boolean | `true` | Preset-Schalter aktivieren |
93
+ | `devices` | array | `[]` | Manuell konfigurierte Geräte |
94
+
95
+ ### Geräte-Konfiguration
96
+
97
+ | Option | Typ | Beschreibung |
98
+ |--------|-----|--------------|
99
+ | `name` | string | Anzeigename des Geräts |
100
+ | `host` | string | IP-Adresse des SoundTouch-Geräts |
101
+ | `room` | string | Raum-Zuordnung (optional) |
102
+
103
+ ## HomeKit-Funktionen
104
+
105
+ ### Speaker Service
106
+ - **Mute** - Stummschaltung ein/aus
107
+ - **Volume** - Lautstärke (0-100%)
108
+
109
+ ### Smart Speaker Service (optional)
110
+ - **CurrentMediaState** - Aktueller Status (Play/Pause/Stop)
111
+ - **TargetMediaState** - Wiedergabe steuern
112
+ - **Volume** - Lautstärke
113
+ - **Mute** - Stummschaltung
114
+
115
+ ### Lightbulb Service (optional)
116
+ - **On** - Mute/Unmute
117
+ - **Brightness** - Lautstärke als Slider
118
+
119
+ ### Preset Switches
120
+ - Schalter für jeden gespeicherten Preset (1-6)
121
+ - Momentary-Verhalten (schaltet automatisch aus)
122
+
123
+ ## Unterstützte Geräte
124
+
125
+ Dieses Plugin funktioniert mit allen Bose SoundTouch-Geräten:
126
+ - SoundTouch 10
127
+ - SoundTouch 20
128
+ - SoundTouch 30
129
+ - SoundTouch 300
130
+ - SoundTouch Portable
131
+ - SoundTouch SA-5 Amplifier
132
+ - Wave SoundTouch
133
+
134
+ **Hinweis:** Neuere Bose-Geräte (Home Speaker 500, 700, etc.) werden NICHT unterstützt, da sie eine andere API verwenden.
135
+
136
+ ## API-Funktionen
137
+
138
+ Das Plugin nutzt die vollständige [Bose SoundTouch Web API](https://assets.bosecreative.com/m/496577402d128874/original/SoundTouch-Web-API.pdf):
139
+
140
+ - `/info` - Geräteinformationen
141
+ - `/now_playing` - Aktuelle Wiedergabe
142
+ - `/volume` - Lautstärke get/set
143
+ - `/key` - Tastendrücke (Play, Pause, etc.)
144
+ - `/presets` - Gespeicherte Favoriten
145
+ - `/sources` - Verfügbare Quellen
146
+ - `/bass` - Bass-Einstellungen
147
+ - `/getZone` / `/setZone` - Multi-Room-Zonen
148
+ - WebSocket auf Port 8080 für Echtzeit-Updates
149
+
150
+ ## Troubleshooting
151
+
152
+ ### Gerät wird nicht gefunden
153
+
154
+ 1. Stelle sicher, dass das SoundTouch-Gerät eingeschaltet ist
155
+ 2. Prüfe, ob sich das Gerät im gleichen Netzwerk befindet
156
+ 3. Versuche, die IP-Adresse manuell in der Konfiguration anzugeben
157
+ 4. Teste die Verbindung: `curl http://IP_ADRESSE:8090/info`
158
+
159
+ ### Keine Steuerung möglich
160
+
161
+ 1. Prüfe die Homebridge-Logs auf Fehler
162
+ 2. Starte Homebridge neu
163
+ 3. Entferne das Gerät aus HomeKit und füge es erneut hinzu
164
+
165
+ ### WebSocket-Verbindung fehlerhaft
166
+
167
+ Der WebSocket verbindet sich automatisch erneut. Falls Echtzeit-Updates nicht funktionieren, prüfe ob Port 8080 erreichbar ist.
168
+
169
+ ## Entwicklung
170
+
171
+ ```bash
172
+ # Clone und installieren
173
+ git clone https://github.com/daniel/homebridge-bose-soundtouch.git
174
+ cd homebridge-bose-soundtouch
175
+ npm install
176
+
177
+ # Build
178
+ npm run build
179
+
180
+ # Watch mode für Entwicklung
181
+ npm run watch
182
+
183
+ # Linting
184
+ npm run lint
185
+ ```
186
+
187
+ ## Lizenz
188
+
189
+ MIT
190
+
191
+ ## Credits
192
+
193
+ - [Bose SoundTouch Web API](https://assets.bosecreative.com/m/496577402d128874/original/SoundTouch-Web-API.pdf)
194
+ - [libsoundtouch](https://github.com/CharlesBlonde/libsoundtouch) - Inspiration für API-Implementierung
195
+ - [bosesoundtouchapi](https://github.com/thlucas1/bosesoundtouchapi) - Referenz für WebSocket-Events
@@ -0,0 +1,247 @@
1
+ {
2
+ "pluginAlias": "BoseSoundTouch",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "customUi": true,
6
+ "headerDisplay": "Homebridge Plugin für Bose SoundTouch Lautsprecher - Mit Custom Radio & Streaming Stationen.",
7
+ "footerDisplay": "Weitere Informationen: [GitHub](https://github.com/Dress13/homebridge-bose-soundtouch)",
8
+ "schema": {
9
+ "type": "object",
10
+ "properties": {
11
+ "name": {
12
+ "title": "Name",
13
+ "type": "string",
14
+ "default": "Bose SoundTouch",
15
+ "required": true
16
+ },
17
+ "autoDiscover": {
18
+ "title": "Automatische Erkennung",
19
+ "type": "boolean",
20
+ "default": true,
21
+ "description": "SoundTouch-Geräte automatisch im Netzwerk finden"
22
+ },
23
+ "discoveryTimeout": {
24
+ "title": "Discovery Timeout (ms)",
25
+ "type": "integer",
26
+ "default": 10000,
27
+ "minimum": 1000,
28
+ "maximum": 60000,
29
+ "description": "Timeout für die automatische Geräteerkennung"
30
+ },
31
+ "devices": {
32
+ "title": "Geräte",
33
+ "description": "Geräte werden automatisch erkannt. Hier kannst du pro Gerät Icon und Presets konfigurieren.",
34
+ "type": "array",
35
+ "items": {
36
+ "type": "object",
37
+ "properties": {
38
+ "host": {
39
+ "title": "IP-Adresse",
40
+ "type": "string",
41
+ "required": true,
42
+ "format": "ipv4",
43
+ "description": "IP-Adresse des SoundTouch-Geräts"
44
+ },
45
+ "name": {
46
+ "title": "Name",
47
+ "type": "string",
48
+ "description": "Anzeigename (optional, wird automatisch vom Gerät gelesen)"
49
+ },
50
+ "room": {
51
+ "title": "Raum",
52
+ "type": "string",
53
+ "description": "Raum-Zuordnung (optional)"
54
+ },
55
+ "deviceIcon": {
56
+ "title": "Geräte-Icon",
57
+ "type": "integer",
58
+ "default": 26,
59
+ "oneOf": [
60
+ { "title": "Speaker (Lautsprecher)", "enum": [26] },
61
+ { "title": "Audio Receiver", "enum": [34] },
62
+ { "title": "Television (TV)", "enum": [31] },
63
+ { "title": "TV Set Top Box", "enum": [35] },
64
+ { "title": "TV Streaming Stick", "enum": [36] },
65
+ { "title": "AirPlay Speaker", "enum": [38] },
66
+ { "title": "HomePod", "enum": [39] },
67
+ { "title": "Airport", "enum": [27] }
68
+ ],
69
+ "description": "Icon für dieses Gerät in der Home App"
70
+ },
71
+ "presets": {
72
+ "title": "Preset-Belegung",
73
+ "description": "Belege die 6 Preset-Tasten mit eigenen Sendern",
74
+ "type": "array",
75
+ "maxItems": 6,
76
+ "items": {
77
+ "type": "object",
78
+ "properties": {
79
+ "slot": {
80
+ "title": "Preset-Taste",
81
+ "type": "integer",
82
+ "minimum": 1,
83
+ "maximum": 6,
84
+ "required": true,
85
+ "description": "Welche Preset-Taste (1-6)"
86
+ },
87
+ "name": {
88
+ "title": "Name",
89
+ "type": "string",
90
+ "required": true,
91
+ "description": "Anzeigename in HomeKit"
92
+ },
93
+ "type": {
94
+ "title": "Typ",
95
+ "type": "string",
96
+ "required": true,
97
+ "default": "radio",
98
+ "oneOf": [
99
+ { "title": "Internet Radio (HTTP Stream)", "enum": ["radio"] },
100
+ { "title": "Spotify", "enum": ["spotify"] },
101
+ { "title": "Amazon Music", "enum": ["amazon"] },
102
+ { "title": "Deezer", "enum": ["deezer"] },
103
+ { "title": "TuneIn", "enum": ["tunein"] }
104
+ ],
105
+ "description": "Art der Quelle"
106
+ },
107
+ "url": {
108
+ "title": "Stream URL",
109
+ "type": "string",
110
+ "description": "HTTP Stream URL für Radio"
111
+ },
112
+ "spotifyUri": {
113
+ "title": "Spotify URI",
114
+ "type": "string",
115
+ "description": "Spotify URI (z.B. spotify:playlist:37i9dQZF1DXcBWIGoYBM5M)"
116
+ },
117
+ "contentId": {
118
+ "title": "Content ID",
119
+ "type": "string",
120
+ "description": "Content ID für TuneIn, Amazon oder Deezer"
121
+ },
122
+ "sourceAccount": {
123
+ "title": "Account",
124
+ "type": "string",
125
+ "description": "Account-Identifier für Spotify/Amazon/Deezer"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ },
135
+ "layout": [
136
+ "name",
137
+ {
138
+ "type": "fieldset",
139
+ "title": "Automatische Erkennung",
140
+ "description": "Geräte werden beim Start automatisch im Netzwerk gefunden. Du kannst sie dann hier konfigurieren.",
141
+ "items": [
142
+ "autoDiscover",
143
+ "discoveryTimeout"
144
+ ]
145
+ },
146
+ {
147
+ "type": "fieldset",
148
+ "title": "Geräte-Konfiguration",
149
+ "description": "Füge hier deine SoundTouch-Geräte hinzu (IP-Adresse). Pro Gerät kannst du das Icon und die Preset-Tasten individuell konfigurieren.",
150
+ "expandable": true,
151
+ "expanded": true,
152
+ "items": [
153
+ {
154
+ "key": "devices",
155
+ "type": "array",
156
+ "buttonText": "Gerät hinzufügen",
157
+ "items": [
158
+ {
159
+ "type": "div",
160
+ "displayFlex": true,
161
+ "items": [
162
+ {
163
+ "key": "devices[].host",
164
+ "flex": "1 1 150px"
165
+ },
166
+ {
167
+ "key": "devices[].name",
168
+ "flex": "1 1 150px"
169
+ }
170
+ ]
171
+ },
172
+ {
173
+ "type": "div",
174
+ "displayFlex": true,
175
+ "items": [
176
+ {
177
+ "key": "devices[].room",
178
+ "flex": "1 1 150px"
179
+ },
180
+ {
181
+ "key": "devices[].deviceIcon",
182
+ "flex": "1 1 150px"
183
+ }
184
+ ]
185
+ },
186
+ {
187
+ "type": "fieldset",
188
+ "title": "Preset-Tasten belegen",
189
+ "expandable": true,
190
+ "items": [
191
+ {
192
+ "key": "devices[].presets",
193
+ "type": "array",
194
+ "buttonText": "Preset hinzufügen",
195
+ "items": [
196
+ {
197
+ "type": "div",
198
+ "displayFlex": true,
199
+ "items": [
200
+ {
201
+ "key": "devices[].presets[].slot",
202
+ "flex": "0 0 80px"
203
+ },
204
+ {
205
+ "key": "devices[].presets[].name",
206
+ "flex": "1 1 150px"
207
+ },
208
+ {
209
+ "key": "devices[].presets[].type",
210
+ "flex": "1 1 150px"
211
+ }
212
+ ]
213
+ },
214
+ {
215
+ "key": "devices[].presets[].url",
216
+ "condition": {
217
+ "functionBody": "try { return model.devices[arrayIndices[0]].presets[arrayIndices[1]].type === 'radio'; } catch(e) { return false; }"
218
+ }
219
+ },
220
+ {
221
+ "key": "devices[].presets[].spotifyUri",
222
+ "condition": {
223
+ "functionBody": "try { return model.devices[arrayIndices[0]].presets[arrayIndices[1]].type === 'spotify'; } catch(e) { return false; }"
224
+ }
225
+ },
226
+ {
227
+ "key": "devices[].presets[].contentId",
228
+ "condition": {
229
+ "functionBody": "try { return ['tunein', 'amazon', 'deezer'].includes(model.devices[arrayIndices[0]].presets[arrayIndices[1]].type); } catch(e) { return false; }"
230
+ }
231
+ },
232
+ {
233
+ "key": "devices[].presets[].sourceAccount",
234
+ "condition": {
235
+ "functionBody": "try { return ['spotify', 'amazon', 'deezer'].includes(model.devices[arrayIndices[0]].presets[arrayIndices[1]].type); } catch(e) { return false; }"
236
+ }
237
+ }
238
+ ]
239
+ }
240
+ ]
241
+ }
242
+ ]
243
+ }
244
+ ]
245
+ }
246
+ ]
247
+ }
@@ -0,0 +1,20 @@
1
+ export interface DiscoveredDevice {
2
+ name: string;
3
+ host: string;
4
+ port: number;
5
+ mac?: string;
6
+ }
7
+ export declare class SoundTouchDiscovery {
8
+ private bonjour;
9
+ private browser;
10
+ private devices;
11
+ private onDeviceFound?;
12
+ private onDeviceLost?;
13
+ constructor();
14
+ start(onDeviceFound?: (device: DiscoveredDevice) => void, onDeviceLost?: (device: DiscoveredDevice) => void): void;
15
+ stop(): void;
16
+ private handleServiceUp;
17
+ private handleServiceDown;
18
+ getDevices(): DiscoveredDevice[];
19
+ discoverOnce(timeout?: number): Promise<DiscoveredDevice[]>;
20
+ }
@@ -0,0 +1,93 @@
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.SoundTouchDiscovery = void 0;
7
+ const bonjour_service_1 = __importDefault(require("bonjour-service"));
8
+ class SoundTouchDiscovery {
9
+ bonjour;
10
+ browser = null;
11
+ devices = new Map();
12
+ onDeviceFound;
13
+ onDeviceLost;
14
+ constructor() {
15
+ this.bonjour = new bonjour_service_1.default();
16
+ }
17
+ start(onDeviceFound, onDeviceLost) {
18
+ this.onDeviceFound = onDeviceFound;
19
+ this.onDeviceLost = onDeviceLost;
20
+ // SoundTouch devices advertise via mDNS as _soundtouch._tcp
21
+ this.browser = this.bonjour.find({ type: 'soundtouch' }, (service) => {
22
+ this.handleServiceUp(service);
23
+ });
24
+ this.browser.on('down', (service) => {
25
+ this.handleServiceDown(service);
26
+ });
27
+ }
28
+ stop() {
29
+ if (this.browser) {
30
+ this.browser.stop();
31
+ this.browser = null;
32
+ }
33
+ this.bonjour.destroy();
34
+ }
35
+ handleServiceUp(service) {
36
+ if (!service.addresses || service.addresses.length === 0) {
37
+ return;
38
+ }
39
+ // Prefer IPv4 address
40
+ const host = service.addresses.find((addr) => !addr.includes(':')) || service.addresses[0];
41
+ const device = {
42
+ name: service.name,
43
+ host: host,
44
+ port: service.port || 8090,
45
+ mac: service.txt?.['MAC'],
46
+ };
47
+ const key = `${device.host}:${device.port}`;
48
+ if (!this.devices.has(key)) {
49
+ this.devices.set(key, device);
50
+ this.onDeviceFound?.(device);
51
+ }
52
+ }
53
+ handleServiceDown(service) {
54
+ const addresses = service.addresses || [];
55
+ for (const addr of addresses) {
56
+ const key = `${addr}:${service.port || 8090}`;
57
+ const device = this.devices.get(key);
58
+ if (device) {
59
+ this.devices.delete(key);
60
+ this.onDeviceLost?.(device);
61
+ }
62
+ }
63
+ }
64
+ getDevices() {
65
+ return Array.from(this.devices.values());
66
+ }
67
+ async discoverOnce(timeout = 5000) {
68
+ return new Promise((resolve) => {
69
+ const devices = [];
70
+ const browser = this.bonjour.find({ type: 'soundtouch' }, (service) => {
71
+ if (!service.addresses || service.addresses.length === 0) {
72
+ return;
73
+ }
74
+ const host = service.addresses.find((addr) => !addr.includes(':')) || service.addresses[0];
75
+ const device = {
76
+ name: service.name,
77
+ host: host,
78
+ port: service.port || 8090,
79
+ mac: service.txt?.['MAC'],
80
+ };
81
+ const exists = devices.some((d) => d.host === device.host && d.port === device.port);
82
+ if (!exists) {
83
+ devices.push(device);
84
+ }
85
+ });
86
+ setTimeout(() => {
87
+ browser.stop();
88
+ resolve(devices);
89
+ }, timeout);
90
+ });
91
+ }
92
+ }
93
+ exports.SoundTouchDiscovery = SoundTouchDiscovery;
@@ -0,0 +1,6 @@
1
+ import { API } from 'homebridge';
2
+ /**
3
+ * This method registers the platform with Homebridge
4
+ */
5
+ declare const _default: (api: API) => void;
6
+ export = _default;
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ const settings_1 = require("./settings");
3
+ const platform_1 = require("./platform");
4
+ module.exports = (api) => {
5
+ api.registerPlatform(settings_1.PLATFORM_NAME, platform_1.SoundTouchPlatform);
6
+ };
@@ -0,0 +1,43 @@
1
+ import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge';
2
+ import { SoundTouchAccessory } from './soundtouchAccessory';
3
+ export interface PresetConfig {
4
+ slot: number;
5
+ name: string;
6
+ type: 'radio' | 'spotify' | 'amazon' | 'deezer' | 'tunein';
7
+ url?: string;
8
+ spotifyUri?: string;
9
+ contentId?: string;
10
+ sourceAccount?: string;
11
+ }
12
+ export interface DeviceConfig {
13
+ name?: string;
14
+ host: string;
15
+ room?: string;
16
+ deviceIcon?: number;
17
+ presets?: PresetConfig[];
18
+ }
19
+ export interface SoundTouchPlatformConfig extends PlatformConfig {
20
+ devices?: DeviceConfig[];
21
+ autoDiscover?: boolean;
22
+ discoveryTimeout?: number;
23
+ }
24
+ export declare class SoundTouchPlatform implements DynamicPlatformPlugin {
25
+ readonly log: Logger;
26
+ readonly config: SoundTouchPlatformConfig;
27
+ readonly api: API;
28
+ readonly Service: typeof Service;
29
+ readonly Characteristic: typeof Characteristic;
30
+ readonly accessories: PlatformAccessory[];
31
+ private readonly soundTouchAccessories;
32
+ private readonly externalAccessories;
33
+ private discovery?;
34
+ constructor(log: Logger, config: SoundTouchPlatformConfig, api: API);
35
+ configureAccessory(accessory: PlatformAccessory): void;
36
+ private discoverDevices;
37
+ private registerDevice;
38
+ private cleanup;
39
+ getAllAccessories(): SoundTouchAccessory[];
40
+ getAccessoryByHost(host: string): SoundTouchAccessory | undefined;
41
+ getAccessoryByName(name: string): SoundTouchAccessory | undefined;
42
+ getDeviceConfig(host: string): DeviceConfig | undefined;
43
+ }