@tplnet/homebridge-denon-heos-audio 1.2.0 → 1.2.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 +14 -0
- package/README.md +1 -1
- package/dist/denonClientHeosCli.d.ts +3 -0
- package/dist/denonClientHeosCli.js +11 -2
- package/dist/platformAccessory.d.ts +3 -0
- package/dist/platformAccessory.js +25 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes of this fork. The fork is based on [hov3rcraft/homebridge-denon-heos-audio](https://github.com/hov3rcraft/homebridge-denon-heos-audio) 1.0.0-beta.1.
|
|
4
4
|
|
|
5
|
+
## 1.2.2
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- The tile in the Homebridge UI / Home app no longer jumps back to "off" while switching on takes a few seconds: HomeKit gets the answer immediately and switching continues in the background. If switching fails, the tile shows the real state again and the error is logged.
|
|
10
|
+
- A radio station that needs a few seconds to buffer is no longer replaced by the power on favorite: the plugin now waits up to 8 seconds (before: 3) for playback to start.
|
|
11
|
+
|
|
12
|
+
## 1.2.1
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- When switching on took a few seconds (e.g. while the power on favorite was being started), the tile briefly showed "off" before it switched to "on". The requested state is now reported from the moment of the tap, and intermediate states of the device are ignored until switching has finished.
|
|
17
|
+
- The player list was requested twice per device at startup.
|
|
18
|
+
|
|
5
19
|
## 1.2.0
|
|
6
20
|
|
|
7
21
|
### New
|
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Not sure what your device supports? Turn on [device discovery](#1-find-your-devi
|
|
|
56
56
|
| **Hybrid** | AV receivers and amplifiers with HEOS (e.g. Marantz Cinema series, Denon AVR-X, Denon Home Amp) | Real power on / standby | ✅ | ✅ |
|
|
57
57
|
|
|
58
58
|
**Why does "power" mean "playback" with HEOS CLI?** HEOS speakers have no real standby command. The plugin therefore treats "playing" as on and "stopped/paused" as off.
|
|
59
|
-
Switching on resumes the last source. If there is nothing to resume (e.g. after the speaker was restarted or a streaming session ended), or playback doesn't start within
|
|
59
|
+
Switching on resumes the last source. If there is nothing to resume (e.g. after the speaker was restarted or a streaming session ended), or playback doesn't start within 8 seconds, the first HEOS favorite is started, so switching on also works in scenes and automations. You can choose another favorite or turn this off with `powerOnFavorite`.
|
|
60
60
|
|
|
61
61
|
> **Requirement:** at least one favorite in the HEOS app (*Music → Favorites*, e.g. a radio station). Without a favorite, a speaker that has nothing to resume can't be switched on from HomeKit.
|
|
62
62
|
|
|
@@ -204,7 +204,10 @@ export declare class DenonClientHeosCli extends DenonClient {
|
|
|
204
204
|
private infoLog;
|
|
205
205
|
private player_name;
|
|
206
206
|
constructor(serialNumber: string, name: string, host: string, connect_timeout: number, response_timeout: number, debugLogCallback?: (message: string, ...parameters: any[]) => void, powerUpdateCallback?: (power: boolean) => void, muteUpdateCallback?: (mute: boolean) => void, volumeUpdateCallback?: (volume: number) => void, inputUpdateCallback?: (input: string) => void);
|
|
207
|
+
private playerIdLookup;
|
|
208
|
+
/** Looks up the player id; concurrent calls share one request. */
|
|
207
209
|
private findPlayerId;
|
|
210
|
+
private findPlayerIdUncached;
|
|
208
211
|
protected subscribeToChangeEvents(): Promise<void>;
|
|
209
212
|
protected sendCommand(command: ProtocolCommand, commandMode: CommandMode, { value, passPayload }: {
|
|
210
213
|
value?: string;
|
|
@@ -248,7 +248,8 @@ export class DenonClientHeosCli extends DenonClient {
|
|
|
248
248
|
player_id;
|
|
249
249
|
/** HEOS favorite (1, 2, …) that is started when switching on without something to resume; 0 = disabled. */
|
|
250
250
|
powerOnFavorite = 1;
|
|
251
|
-
|
|
251
|
+
// radio streams may need a few seconds of buffering before the device reports "play"
|
|
252
|
+
static PLAY_VERIFY_CHECKS = 8;
|
|
252
253
|
playVerifyIntervalMs = 1000;
|
|
253
254
|
/** Log for actions the user should see without debug logging (e.g. starting the power on favorite). */
|
|
254
255
|
infoLog = (message) => this.debugLog(message);
|
|
@@ -275,7 +276,15 @@ export class DenonClientHeosCli extends DenonClient {
|
|
|
275
276
|
}
|
|
276
277
|
});
|
|
277
278
|
}
|
|
278
|
-
|
|
279
|
+
playerIdLookup;
|
|
280
|
+
/** Looks up the player id; concurrent calls share one request. */
|
|
281
|
+
findPlayerId() {
|
|
282
|
+
this.playerIdLookup ??= this.findPlayerIdUncached().finally(() => {
|
|
283
|
+
this.playerIdLookup = undefined;
|
|
284
|
+
});
|
|
285
|
+
return this.playerIdLookup;
|
|
286
|
+
}
|
|
287
|
+
async findPlayerIdUncached() {
|
|
279
288
|
const payload_str = await super.sendCommand(DenonClientHeosCli.PROTOCOL.PLAYERS, CommandMode.GET, { passPayload: true });
|
|
280
289
|
const payload = JSON.parse(payload_str);
|
|
281
290
|
if (!Array.isArray(payload)) {
|
|
@@ -38,6 +38,9 @@ export declare class DenonAudioAccessory {
|
|
|
38
38
|
private targetMediaState;
|
|
39
39
|
private volumeChangeOngoing;
|
|
40
40
|
private pendingActive;
|
|
41
|
+
private powerChangeInProgress;
|
|
42
|
+
/** The power change running in the background (for tests). */
|
|
43
|
+
private powerChange;
|
|
41
44
|
private playingChangeOngoing;
|
|
42
45
|
constructor(platform: DenonAudioPlatform, accessory: PlatformAccessory, config: DeviceConfig, log: Logger);
|
|
43
46
|
/**
|
|
@@ -44,6 +44,9 @@ export class DenonAudioAccessory {
|
|
|
44
44
|
targetMediaState;
|
|
45
45
|
volumeChangeOngoing = false;
|
|
46
46
|
pendingActive;
|
|
47
|
+
powerChangeInProgress = false;
|
|
48
|
+
/** The power change running in the background (for tests). */
|
|
49
|
+
powerChange;
|
|
47
50
|
playingChangeOngoing = false;
|
|
48
51
|
constructor(platform, accessory, config, log) {
|
|
49
52
|
log.debug("Initializing DenonAudioAccessory...");
|
|
@@ -312,15 +315,27 @@ export class DenonAudioAccessory {
|
|
|
312
315
|
async setActive(newValue) {
|
|
313
316
|
this.log.debug(`setActive for ${this.name} set to ${newValue}`);
|
|
314
317
|
const active = newValue === this.platform.Characteristic.Active.ACTIVE;
|
|
315
|
-
|
|
316
|
-
|
|
318
|
+
// Report the requested state right away: switching on can take a few seconds (e.g. when the power on favorite is
|
|
319
|
+
// started), and the device reports intermediate states during that time.
|
|
320
|
+
this.pendingActive = { value: active, until: Number.POSITIVE_INFINITY };
|
|
321
|
+
this.powerChangeInProgress = true;
|
|
322
|
+
// HomeKit gets the answer immediately; switching continues in the background. Otherwise HomeKit / the Homebridge UI
|
|
323
|
+
// would show the old state until switching on has finished (which can take several seconds).
|
|
324
|
+
this.powerChange = this.denonClient
|
|
325
|
+
.setPower(active)
|
|
326
|
+
.then(() => {
|
|
317
327
|
this.pendingActive = { value: active, until: Date.now() + DenonAudioAccessory.POWER_STATE_SETTLE_TIME };
|
|
318
|
-
}
|
|
319
|
-
|
|
328
|
+
})
|
|
329
|
+
.catch(async (error) => {
|
|
320
330
|
this.pendingActive = undefined;
|
|
321
331
|
this.log.error(`An error occured while setting power status for ${this.name}.`, error);
|
|
322
|
-
|
|
323
|
-
|
|
332
|
+
// show the real state again
|
|
333
|
+
const deviceState = await this.denonClient.getPower().catch(() => !active);
|
|
334
|
+
this.tvService.updateCharacteristic(this.platform.Characteristic.Active, deviceState);
|
|
335
|
+
})
|
|
336
|
+
.finally(() => {
|
|
337
|
+
this.powerChangeInProgress = false;
|
|
338
|
+
});
|
|
324
339
|
}
|
|
325
340
|
async setActiveIdentifier(newValue) {
|
|
326
341
|
this.log.debug(`setActiveIdentifier for ${this.name} set to ${newValue}`);
|
|
@@ -542,6 +557,10 @@ export class DenonAudioAccessory {
|
|
|
542
557
|
* Handles characteristic updates from the API
|
|
543
558
|
*/
|
|
544
559
|
callbackActive(active) {
|
|
560
|
+
if (this.powerChangeInProgress && this.pendingActive && this.pendingActive.value !== active) {
|
|
561
|
+
this.log.debug(`Ignoring intermediate power state ${active} of ${this.name} while switching.`);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
545
564
|
if (this.pendingActive && this.pendingActive.value !== active) {
|
|
546
565
|
// changed on the device (e.g. in the HEOS app) - the device state wins
|
|
547
566
|
this.pendingActive = undefined;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tplnet/homebridge-denon-heos-audio",
|
|
3
3
|
"displayName": "Homebridge Denon Heos Audio (tplnet)",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.2",
|
|
6
6
|
"description": "Control your Denon and Marantz HEOS speakers, amplifiers and AVRs via AVR Control and/or HEOS CLI",
|
|
7
7
|
"author": "tplnet",
|
|
8
8
|
"contributors": [
|