homebridge-xbox-tv 4.3.1 → 4.3.3
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 +13 -0
- package/package.json +1 -1
- package/src/hadiscovery.js +8 -0
- package/src/mqtt.js +5 -0
- package/src/xboxdevice.js +26 -4
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
18
|
- For plugin < v4.1.0 use Homebridge UI <= v5.5.0
|
|
19
19
|
- For plugin >= v4.1.0 use Homebridge UI >= v5.13.0
|
|
20
20
|
|
|
21
|
+
## [4.3.3] - (29.09.2026)
|
|
22
|
+
|
|
23
|
+
### Changes
|
|
24
|
+
|
|
25
|
+
- fixed: MQTT, when the broker was not running yet at the start of Homebridge the device never published over MQTT and the Home Assistant discovery was not set up until a restart. The device now starts publishing and sets up the discovery as soon as the broker comes online
|
|
26
|
+
- fixed: Home Assistant discovery, the config and the state are published again after a restart of the broker, a broker without persistence loses the retained messages
|
|
27
|
+
|
|
28
|
+
## [4.3.2] - (28.09.2026)
|
|
29
|
+
|
|
30
|
+
### Changes
|
|
31
|
+
|
|
32
|
+
- fixed: Home Assistant gets all inputs, the HomeKit limit of 85 inputs no longer applies to the source list and the media browser
|
|
33
|
+
|
|
21
34
|
## [4.3.1] - (27.09.2026)
|
|
22
35
|
|
|
23
36
|
### Changes
|
package/package.json
CHANGED
package/src/hadiscovery.js
CHANGED
|
@@ -74,6 +74,14 @@ class HaDiscovery {
|
|
|
74
74
|
return true;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// The broker may have lost the retained messages (restart without persistence), the next publish sends
|
|
78
|
+
// the config, the whole state and the image again
|
|
79
|
+
reset() {
|
|
80
|
+
this.lastConfig = '';
|
|
81
|
+
this.lastState = '';
|
|
82
|
+
this.lastImageKey = undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
// Publish the image of the current source (app icon, channel picon) once per source.
|
|
78
86
|
// key identifies the image, fetchImage returns a Buffer or null, null clears the image
|
|
79
87
|
async updateImage(key, fetchImage) {
|
package/src/mqtt.js
CHANGED
|
@@ -36,6 +36,7 @@ class Mqtt extends EventEmitter {
|
|
|
36
36
|
} : {})
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
this.connected = false;
|
|
39
40
|
const startTime = Date.now();
|
|
40
41
|
let hasConnected = false;
|
|
41
42
|
let warnedStalled = false;
|
|
@@ -45,6 +46,9 @@ class Mqtt extends EventEmitter {
|
|
|
45
46
|
hasConnected = true;
|
|
46
47
|
this.emit('connected', `MQTT v${protocolVersion} connected.`);
|
|
47
48
|
if (this.haDiscovery) this.publishRetained(this.availabilityTopic, 'online').catch(() => { });
|
|
49
|
+
// Every connect, also when the broker was not running at start or restarted, devices publish again
|
|
50
|
+
this.connected = true;
|
|
51
|
+
this.emit('online');
|
|
48
52
|
|
|
49
53
|
try {
|
|
50
54
|
await new Promise((resolve, reject) => {
|
|
@@ -90,6 +94,7 @@ class Mqtt extends EventEmitter {
|
|
|
90
94
|
if (config.logDebug) this.emit('debug', 'MQTT Reconnecting...');
|
|
91
95
|
})
|
|
92
96
|
.on('close', () => {
|
|
97
|
+
this.connected = false;
|
|
93
98
|
if (!hasConnected && !warnedStalled && Date.now() - startTime > 30000) {
|
|
94
99
|
warnedStalled = true;
|
|
95
100
|
this.emit('warn', `MQTT has not connected after 30s of retries using protocol v${protocolVersion}. Check broker address, credentials, and whether the broker supports this MQTT protocol version.`);
|
package/src/xboxdevice.js
CHANGED
|
@@ -54,6 +54,9 @@ class XboxDevice extends EventEmitter {
|
|
|
54
54
|
this.mqtt = device.mqtt ?? {};
|
|
55
55
|
this.mqtt1 = mqtt1;
|
|
56
56
|
this.mqttConnected = mqttConnected;
|
|
57
|
+
// The broker may come online after the start or restart, the device then publishes again
|
|
58
|
+
this.haReady = false;
|
|
59
|
+
this.mqtt1?.on('online', () => this.mqttOnline().catch((error) => this.emit('warn', `MQTT online error: ${error}`)));
|
|
57
60
|
this.functions = new Functions();
|
|
58
61
|
|
|
59
62
|
//sensors
|
|
@@ -73,6 +76,7 @@ class XboxDevice extends EventEmitter {
|
|
|
73
76
|
//variable
|
|
74
77
|
this.modelName = 'Xbox';
|
|
75
78
|
this.inputIdentifier = 1;
|
|
79
|
+
this.haInputs = new Map();
|
|
76
80
|
this.power = false;
|
|
77
81
|
this.volume = 0;
|
|
78
82
|
this.mute = false;
|
|
@@ -110,7 +114,7 @@ class XboxDevice extends EventEmitter {
|
|
|
110
114
|
break;
|
|
111
115
|
case 'App': {
|
|
112
116
|
// Known inputs (also Dashboard, Settings, Television...) are switched the same way as from HomeKit
|
|
113
|
-
const input = this.inputsServices?.find(i => i.oneStoreProductId === value);
|
|
117
|
+
const input = this.inputsServices?.find(i => i.oneStoreProductId === value) ?? [...this.haInputs.values()].find(i => i.oneStoreProductId === value);
|
|
114
118
|
if (input) {
|
|
115
119
|
await this.setInput(input);
|
|
116
120
|
set = true;
|
|
@@ -250,6 +254,10 @@ class XboxDevice extends EventEmitter {
|
|
|
250
254
|
const inputOneStoreProductId = input.oneStoreProductId;
|
|
251
255
|
const inputVisibility = this.savedInputsTargetVisibility[inputReference] ?? 0;
|
|
252
256
|
|
|
257
|
+
// Home Assistant gets all inputs, the HomeKit limit of 85 does not apply
|
|
258
|
+
if (remove) this.haInputs.delete(inputReference);
|
|
259
|
+
else this.haInputs.set(inputReference, { reference: inputReference, name: sanitizedName, oneStoreProductId: inputOneStoreProductId, titleId: inputTitleId, isGame: input.isGame, contentType });
|
|
260
|
+
|
|
253
261
|
if (remove) {
|
|
254
262
|
const svc = this.inputsServices.find(s => s.reference === inputReference);
|
|
255
263
|
if (svc) {
|
|
@@ -333,7 +341,8 @@ class XboxDevice extends EventEmitter {
|
|
|
333
341
|
|
|
334
342
|
// Only one time run
|
|
335
343
|
if (updated) await this.displayOrder();
|
|
336
|
-
|
|
344
|
+
// Home Assistant also gets the inputs over the HomeKit limit, publishConfig skips an unchanged config
|
|
345
|
+
this.haPublishConfig();
|
|
337
346
|
|
|
338
347
|
return true;
|
|
339
348
|
} catch (error) {
|
|
@@ -1010,6 +1019,15 @@ class XboxDevice extends EventEmitter {
|
|
|
1010
1019
|
}
|
|
1011
1020
|
|
|
1012
1021
|
//home assistant discovery
|
|
1022
|
+
// MQTT connected, at start when the broker was not running yet or after a restart of the broker
|
|
1023
|
+
async mqttOnline() {
|
|
1024
|
+
this.mqttConnected = true;
|
|
1025
|
+
if (!this.haReady) return;
|
|
1026
|
+
if (!this.ha) return this.setupHaDiscovery();
|
|
1027
|
+
this.ha.reset();
|
|
1028
|
+
await this.haPublishConfig();
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1013
1031
|
async setupHaDiscovery() {
|
|
1014
1032
|
if (!this.mqttConnected || !this.mqtt.haDiscovery) return;
|
|
1015
1033
|
|
|
@@ -1045,7 +1063,7 @@ class XboxDevice extends EventEmitter {
|
|
|
1045
1063
|
if (!this.ha) return;
|
|
1046
1064
|
|
|
1047
1065
|
try {
|
|
1048
|
-
const sources =
|
|
1066
|
+
const sources = [...this.haInputs.values()].map(input => ({ id: input.oneStoreProductId, name: input.name }));
|
|
1049
1067
|
await this.ha.publishConfig({ sources });
|
|
1050
1068
|
await this.haUpdateState();
|
|
1051
1069
|
} catch (error) {
|
|
@@ -1057,7 +1075,9 @@ class XboxDevice extends EventEmitter {
|
|
|
1057
1075
|
if (!this.ha) return;
|
|
1058
1076
|
|
|
1059
1077
|
try {
|
|
1060
|
-
|
|
1078
|
+
// The running app, also one over the HomeKit limit
|
|
1079
|
+
const match = (input) => input.reference === this.reference || (this.titleId && input.titleId === this.titleId);
|
|
1080
|
+
const input = this.inputsServices?.find(match) ?? [...this.haInputs.values()].find(match) ?? this.inputsServices?.find(input => input.identifier === this.inputIdentifier);
|
|
1061
1081
|
await this.ha.updateState({
|
|
1062
1082
|
power: this.power,
|
|
1063
1083
|
state: this.power ? (this.playState ? 'playing' : 'on') : 'off',
|
|
@@ -1158,6 +1178,7 @@ class XboxDevice extends EventEmitter {
|
|
|
1158
1178
|
.setCharacteristic(Characteristic.FirmwareRevision, info.firmwareRevision);
|
|
1159
1179
|
})
|
|
1160
1180
|
.on('stateChanged', async (power, titleId, reference, volume, mute, playState) => {
|
|
1181
|
+
this.titleId = titleId;
|
|
1161
1182
|
const input = this.inputsServices?.find(input => input.reference === reference || input.titleId === titleId) ?? false;
|
|
1162
1183
|
const inputIdentifier = input ? input.identifier : this.inputIdentifier;
|
|
1163
1184
|
|
|
@@ -1298,6 +1319,7 @@ class XboxDevice extends EventEmitter {
|
|
|
1298
1319
|
|
|
1299
1320
|
// Prepare accessory
|
|
1300
1321
|
const accessory = await this.prepareAccessory();
|
|
1322
|
+
this.haReady = true;
|
|
1301
1323
|
this.setupHaDiscovery();
|
|
1302
1324
|
return accessory;
|
|
1303
1325
|
} catch (error) {
|