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 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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Xbox TV",
3
3
  "name": "homebridge-xbox-tv",
4
- "version": "4.3.1",
4
+ "version": "4.3.3",
5
5
  "description": "Homebridge plugin to control Xbox game consoles.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -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
- if (updated) this.haPublishConfig();
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 = (this.inputsServices ?? []).map(input => ({ id: input.oneStoreProductId, name: input.name }));
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
- const input = this.inputsServices?.find(input => input.identifier === this.inputIdentifier);
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) {