homebridge-xbox-tv 3.7.1 → 3.7.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.
@@ -235,7 +235,7 @@
235
235
  $("deviceWebApiControl").disabled = true;
236
236
  device.webApiControl = false;
237
237
 
238
- let timeLeft = 15;
238
+ let timeLeft = 10;
239
239
  const timerId = setInterval(() => {
240
240
  if (timeLeft <= 0) {
241
241
  open(info);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Xbox TV",
3
3
  "name": "homebridge-xbox-tv",
4
- "version": "3.7.1",
4
+ "version": "3.7.2",
5
5
  "description": "Homebridge plugin to control Xbox game consoles.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -250,12 +250,14 @@ class XboxWebApi extends EventEmitter {
250
250
  'contentType': contentType
251
251
  }
252
252
  appsArray.push(input);
253
- this.emit('addRemoveOrUpdateInput', input, false);
254
253
  }
255
254
 
256
255
  //save inputs
257
256
  await this.saveData(this.inputsFile, appsArray);
258
257
 
258
+ //emit apps
259
+ this.emit('addRemoveOrUpdateInput', appsArray, false);
260
+
259
261
  //emit restFul and mqtt
260
262
  this.emit('restFul', 'apps', apps);
261
263
  this.emit('mqtt', 'Apps', apps);
package/src/xboxdevice.js CHANGED
@@ -104,7 +104,6 @@ class XboxDevice extends EventEmitter {
104
104
  this.buttonsConfiguredCount = this.buttonsConfigured.length || 0;
105
105
 
106
106
  //variable
107
- this.allServices = [];
108
107
  this.sensorsInputsServices = [];
109
108
  this.buttonsServices = [];
110
109
  this.inputIdentifier = 1;
@@ -348,16 +347,6 @@ class XboxDevice extends EventEmitter {
348
347
  // Sort inputs in memory
349
348
  this.inputsServices.sort(sortFn);
350
349
 
351
- // Reassign identifiers (start at 1)
352
- this.inputsServices.forEach((svc, index) => {
353
- const newIdentifier = index + 1;
354
- svc.identifier = newIdentifier;
355
-
356
- if (svc.testCharacteristic(Characteristic.Identifier)) {
357
- svc.updateCharacteristic(Characteristic.Identifier, newIdentifier);
358
- }
359
- });
360
-
361
350
  // Debug dump
362
351
  if (this.enableDebugMode) {
363
352
  const orderDump = this.inputsServices.map(svc => ({ name: svc.name, reference: svc.reference, identifier: svc.identifier, }));
@@ -373,122 +362,118 @@ class XboxDevice extends EventEmitter {
373
362
  }
374
363
  }
375
364
 
376
- async addRemoveOrUpdateInput(input, remove = false) {
365
+ async addRemoveOrUpdateInput(inputs, remove = false) {
377
366
  try {
378
- // Safety: no services
379
367
  if (!this.inputsServices) return;
380
368
 
381
- // Filter unnecessary inputs (only when adding, not removing)
382
- if (!remove) {
369
+ for (const input of inputs) {
383
370
  const contentType = input.contentType;
384
371
  const filterGames = this.filterGames && contentType === 'Game';
385
372
  const filterApps = this.filterApps && contentType === 'App';
386
373
  const filterSystemApps = this.filterSystemApps && contentType === 'systemApp';
387
374
  const filterDlc = this.filterDlc && contentType === 'Dlc';
388
375
 
389
- if (filterGames || filterApps || filterSystemApps || filterDlc || this.inputsServices.length >= 85) {
390
- return;
391
- }
392
- }
393
-
394
- // Input reference
395
- const inputReference = input.reference;
396
-
397
- // --- REMOVE ---
398
- if (remove) {
399
- const svc = this.inputsServices.find(s => s.reference === inputReference);
400
- if (svc) {
401
- if (this.enableDebugMode) this.emit('debug', `Removing input: ${input.name} (${inputReference})`);
402
- this.accessory.removeService(svc);
403
- this.inputsServices = this.inputsServices.filter(s => s.reference !== inputReference);
404
- await this.displayOrder();
405
- return true;
406
- }
407
- if (this.enableDebugMode) this.emit('debug', `Remove failed (not found): ${input.name} (${inputReference})`);
408
- return false;
409
- }
410
-
411
- // --- ADD OR UPDATE ---
412
- let inputService = this.inputsServices.find(s => s.reference === inputReference);
376
+ if ((this.inputsServices.length >= 85 && !remove) || filterGames || filterApps || filterSystemApps || filterDlc) continue;
413
377
 
414
- const savedName = this.savedInputsNames[inputReference] ?? input.name;
415
- const sanitizedName = await this.sanitizeString(savedName);
416
- const inputVisibility = this.savedInputsTargetVisibility[inputReference] ?? 0;
378
+ const inputReference = input.reference;
417
379
 
418
- if (inputService) {
419
- // === UPDATE EXISTING ===
420
- inputService.name = sanitizedName;
421
- inputService.visibility = inputVisibility;
380
+ // --- REMOVE ---
381
+ if (remove) {
382
+ const svc = this.inputsServices.find(s => s.reference === inputReference);
383
+ if (svc) {
384
+ if (this.enableDebugMode) this.emit('debug', `Removing input: ${input.name} (${inputReference})`);
385
+ this.accessory.removeService(svc);
386
+ this.inputsServices = this.inputsServices.filter(s => s.reference !== inputReference);
387
+ await this.displayOrder();
388
+ return true;
389
+ }
390
+ if (this.enableDebugMode) this.emit('debug', `Remove failed (not found): ${input.name} (${inputReference})`);
391
+ return false;
392
+ }
422
393
 
423
- inputService
424
- .updateCharacteristic(Characteristic.Name, sanitizedName)
425
- .updateCharacteristic(Characteristic.ConfiguredName, sanitizedName)
426
- .updateCharacteristic(Characteristic.TargetVisibilityState, inputVisibility)
427
- .updateCharacteristic(Characteristic.CurrentVisibilityState, inputVisibility);
394
+ // --- ADD OR UPDATE ---
395
+ let inputService = this.inputsServices.find(s => s.reference === inputReference);
396
+
397
+ const savedName = this.savedInputsNames[inputReference] ?? input.name;
398
+ const sanitizedName = await this.sanitizeString(savedName);
399
+ const inputMode = input.mode ?? 0;
400
+ const inputVisibility = this.savedInputsTargetVisibility[inputReference] ?? 0;
401
+
402
+ if (inputService) {
403
+ // === UPDATE EXISTING ===
404
+ inputService.name = sanitizedName;
405
+ inputService.visibility = inputVisibility;
406
+
407
+ inputService
408
+ .updateCharacteristic(Characteristic.Name, sanitizedName)
409
+ .updateCharacteristic(Characteristic.ConfiguredName, sanitizedName)
410
+ .updateCharacteristic(Characteristic.TargetVisibilityState, inputVisibility)
411
+ .updateCharacteristic(Characteristic.CurrentVisibilityState, inputVisibility);
412
+
413
+ if (this.enableDebugMode) this.emit('debug', `Updated input: ${input.name} (${inputReference})`);
414
+ } else {
415
+ // === CREATE NEW ===
416
+ const identifier = this.inputsServices.length + 1;
417
+ inputService = this.accessory.addService(Service.InputSource, sanitizedName, `Input ${identifier}`);
418
+
419
+ // Custom props
420
+ Object.assign(inputService, {
421
+ identifier,
422
+ reference: inputReference,
423
+ name: sanitizedName,
424
+ mode: inputMode,
425
+ visibility: inputVisibility,
426
+ });
428
427
 
429
- if (this.enableDebugMode) this.emit('debug', `Updated input: ${input.name} (${inputReference})`);
430
- } else {
431
- // === CREATE NEW ===
432
- const identifier = this.inputsServices.length + 1;
433
- inputService = this.accessory.addService(Service.InputSource, sanitizedName, `Input ${identifier}`);
434
-
435
- // Custom props
436
- inputService.identifier = identifier;
437
- inputService.reference = inputReference;
438
- inputService.name = sanitizedName;
439
- inputService.visibility = inputVisibility;
440
-
441
- inputService
442
- .setCharacteristic(Characteristic.Identifier, identifier)
443
- .setCharacteristic(Characteristic.Name, sanitizedName)
444
- .setCharacteristic(Characteristic.ConfiguredName, sanitizedName)
445
- .setCharacteristic(Characteristic.IsConfigured, 1)
446
- .setCharacteristic(Characteristic.InputSourceType, 0) // 0=HDMI-like Input, 1=Tuner/Channel
447
- .setCharacteristic(Characteristic.CurrentVisibilityState, inputVisibility)
448
- .setCharacteristic(Characteristic.TargetVisibilityState, inputVisibility);
449
-
450
- // --- ConfiguredName rename persistence ---
451
- inputService.getCharacteristic(Characteristic.ConfiguredName)
452
- .onSet(async (value) => {
453
- try {
454
- inputService.name = value;
455
- this.savedInputsNames[inputReference] = value;
456
- await this.saveData(this.inputsNamesFile, this.savedInputsNames);
428
+ inputService
429
+ .setCharacteristic(Characteristic.Identifier, identifier)
430
+ .setCharacteristic(Characteristic.Name, sanitizedName)
431
+ .setCharacteristic(Characteristic.ConfiguredName, sanitizedName)
432
+ .setCharacteristic(Characteristic.IsConfigured, 0)
433
+ .setCharacteristic(Characteristic.InputSourceType, inputMode) // 0=HDMI-like Input, 1=Tuner/Channel
434
+ .setCharacteristic(Characteristic.CurrentVisibilityState, inputVisibility)
435
+ .setCharacteristic(Characteristic.TargetVisibilityState, inputVisibility);
436
+
437
+ // --- ConfiguredName rename persistence ---
438
+ inputService.getCharacteristic(Characteristic.ConfiguredName)
439
+ .onSet(async (value) => {
440
+ try {
441
+ inputService.name = value;
442
+ this.savedInputsNames[inputReference] = value;
443
+ await this.saveData(this.inputsNamesFile, this.savedInputsNames);
457
444
 
458
- if (this.enableDebugMode) this.emit('debug', `Saved Input: ${inputService.name}, Reference: ${inputReference}`);
445
+ if (this.enableDebugMode) this.emit('debug', `Saved Input: ${inputService.name}, Reference: ${inputReference}`);
459
446
 
460
- // keep in sync
461
- const index = this.inputsServices.findIndex(s => s.reference === inputReference);
462
- if (index !== -1) this.inputsServices[index].name = value;
447
+ const index = this.inputsServices.findIndex(s => s.reference === inputReference);
448
+ if (index !== -1) this.inputsServices[index].name = value;
463
449
 
464
- await this.displayOrder();
465
- } catch (error) {
466
- this.emit('warn', `Save Input Name error: ${error}`);
467
- }
468
- });
450
+ await this.displayOrder();
451
+ } catch (error) {
452
+ this.emit('warn', `Save Input Name error: ${error}`);
453
+ }
454
+ });
469
455
 
470
- // --- TargetVisibility persistence ---
471
- inputService.getCharacteristic(Characteristic.TargetVisibilityState)
472
- .onSet(async (state) => {
473
- try {
474
- inputService.visibility = state;
475
- this.savedInputsTargetVisibility[inputReference] = state;
476
- await this.saveData(this.inputsTargetVisibilityFile, this.savedInputsTargetVisibility);
456
+ // --- TargetVisibility persistence ---
457
+ inputService.getCharacteristic(Characteristic.TargetVisibilityState)
458
+ .onSet(async (state) => {
459
+ try {
460
+ inputService.visibility = state;
461
+ this.savedInputsTargetVisibility[inputReference] = state;
462
+ await this.saveData(this.inputsTargetVisibilityFile, this.savedInputsTargetVisibility);
477
463
 
478
- if (this.enableDebugMode) this.emit('debug', `Saved Input: ${inputService.name}, Target Visibility: ${state ? 'HIDDEN' : 'SHOWN'}`);
479
- } catch (error) {
480
- this.emit('warn', `Save Target Visibility error: ${error}`);
481
- }
482
- });
464
+ if (this.enableDebugMode) this.emit('debug', `Saved Input: ${inputService.name}, Target Visibility: ${state ? 'HIDDEN' : 'SHOWN'}`);
465
+ } catch (error) {
466
+ this.emit('warn', `Save Target Visibility error: ${error}`);
467
+ }
468
+ });
483
469
 
484
- this.inputsServices.push(inputService);
485
- this.televisionService.addLinkedService(inputService);
486
- this.allServices.push(inputService);
470
+ this.inputsServices.push(inputService);
471
+ this.televisionService.addLinkedService(inputService);
487
472
 
488
- if (this.enableDebugMode) this.emit('debug', `Added new input: ${input.name} (${inputReference})`);
473
+ if (this.enableDebugMode) this.emit('debug', `Added new input: ${input.name} (${inputReference})`);
474
+ }
489
475
  }
490
476
 
491
- // Normalize identifiers and order
492
477
  await this.displayOrder();
493
478
  return true;
494
479
  } catch (error) {
@@ -514,7 +499,6 @@ class XboxDevice extends EventEmitter {
514
499
  .setCharacteristic(Characteristic.SerialNumber, this.savedInfo.serialNumber ?? this.xboxLiveId)
515
500
  .setCharacteristic(Characteristic.FirmwareRevision, this.savedInfo.firmwareRevision ?? 'Firmware Revision')
516
501
  .setCharacteristic(Characteristic.ConfiguredName, accessoryName);
517
- this.allServices.push(this.informationService);
518
502
 
519
503
  //Prepare television service
520
504
  if (this.enableDebugMode) this.emit('debug', `Prepare television service`);
@@ -734,7 +718,12 @@ class XboxDevice extends EventEmitter {
734
718
  this.emit('warn', `set Power Mode Selection error: ${error}`);
735
719
  }
736
720
  });
737
- this.allServices.push(this.televisionService);
721
+
722
+ //prepare inputs service
723
+ if (this.enableDebugMode) this.emit('debug', `Prepare inputs service`);
724
+ this.inputsServices = [];
725
+ const inputs = this.getInputsFromDevice ? [...DefaultInputs, ...this.savedInputs] : this.inputs;
726
+ await this.addRemoveOrUpdateInput(inputs, false);
738
727
 
739
728
  //Prepare volume service
740
729
  if (this.volumeControl > 0) {
@@ -803,7 +792,6 @@ class XboxDevice extends EventEmitter {
803
792
  this.emit('warn', `set Mute error: ${error}`);
804
793
  }
805
794
  });
806
- this.allServices.push(this.volumeServiceTvSpeaker);
807
795
 
808
796
  //legacy control
809
797
  switch (this.volumeControl) {
@@ -828,7 +816,6 @@ class XboxDevice extends EventEmitter {
828
816
  .onSet(async (state) => {
829
817
  this.volumeServiceTvSpeaker.setCharacteristic(Characteristic.Mute, !state);
830
818
  });
831
- this.allServices.push(this.volumeServiceLightbulb);
832
819
  break;
833
820
  case 2: //fan
834
821
  const debug1 = this.enableDebugMode ? this.emit('debug', `Prepare volume service fan`) : false;
@@ -851,7 +838,6 @@ class XboxDevice extends EventEmitter {
851
838
  .onSet(async (state) => {
852
839
  this.volumeServiceTvSpeaker.setCharacteristic(Characteristic.Mute, !state);
853
840
  });
854
- this.allServices.push(this.volumeServiceFan);
855
841
  break;
856
842
  case 3: // speaker
857
843
  const debug2 = this.enableDebugMode ? this.emit('debug', `Prepare volume service speaker`) : false;
@@ -881,21 +867,10 @@ class XboxDevice extends EventEmitter {
881
867
  .onSet(async (value) => {
882
868
  this.volumeServiceTvSpeaker.setCharacteristic(Characteristic.Volume, value);
883
869
  });
884
- this.allServices.push(this.volumeServiceSpeaker);
885
870
  break;
886
871
  }
887
872
  }
888
873
 
889
- //prepare inputs service
890
- if (this.enableDebugMode) this.emit('debug', `Prepare inputs service`);
891
-
892
- //check possible inputs count (max 85)
893
- this.inputsServices = [];
894
- const inputs = this.getInputsFromDevice ? [...DefaultInputs, ...this.savedInputs] : this.inputs;
895
- for (const input of inputs) {
896
- await this.addRemoveOrUpdateInput(input, false);
897
- }
898
-
899
874
  //prepare sensor service
900
875
  if (this.sensorPower) {
901
876
  if (this.enableDebugMode) this.emit('debug', `Prepare power sensor service`);
@@ -907,7 +882,6 @@ class XboxDevice extends EventEmitter {
907
882
  const state = this.power;
908
883
  return state;
909
884
  });
910
- this.allServices.push(this.sensorPowerService);
911
885
  }
912
886
 
913
887
  if (this.sensorInput) {
@@ -920,7 +894,6 @@ class XboxDevice extends EventEmitter {
920
894
  const state = this.power ? this.sensorInputState : false;
921
895
  return state;
922
896
  });
923
- this.allServices.push(this.sensorInputService);
924
897
  }
925
898
 
926
899
  if (this.sensorScreenSaver) {
@@ -933,11 +906,10 @@ class XboxDevice extends EventEmitter {
933
906
  const state = this.power ? this.sensorScreenSaverState : false;
934
907
  return state;
935
908
  });
936
- this.allServices.push(this.sensorScreenSaverService);
937
909
  }
938
910
 
939
911
  //prepare sonsor service
940
- const possibleSensorInputsCount = 99 - this.allServices.length;
912
+ const possibleSensorInputsCount = 99 - this.accessory.services.length.length;
941
913
  const maxSensorInputsCount = this.sensorsInputsConfiguredCount >= possibleSensorInputsCount ? possibleSensorInputsCount : this.sensorsInputsConfiguredCount;
942
914
  if (maxSensorInputsCount > 0) {
943
915
  if (this.enableDebugMode) this.emit('debug', `Prepare inputs sensors services`);
@@ -967,13 +939,12 @@ class XboxDevice extends EventEmitter {
967
939
  return state;
968
940
  });
969
941
  this.sensorsInputsServices.push(sensorInputService);
970
- this.allServices.push(sensorInputService);
971
942
  accessory.addService(sensorInputService);
972
943
  }
973
944
  }
974
945
 
975
946
  //Prepare buttons services
976
- const possibleButtonsCount = 99 - this.allServices.length;
947
+ const possibleButtonsCount = 99 - this.accessory.services.length.length;
977
948
  const maxButtonsCount = this.buttonsConfiguredCount >= possibleButtonsCount ? possibleButtonsCount : this.buttonsConfiguredCount;
978
949
  if (maxButtonsCount > 0) {
979
950
  if (this.enableDebugMode) this.emit('debug', `Prepare buttons services`);
@@ -1048,7 +1019,6 @@ class XboxDevice extends EventEmitter {
1048
1019
  }
1049
1020
  });
1050
1021
  this.buttonsServices.push(buttonService);
1051
- this.allServices.push(buttonService);
1052
1022
  accessory.addService(buttonService);
1053
1023
  }
1054
1024
  }
@@ -1080,8 +1050,8 @@ class XboxDevice extends EventEmitter {
1080
1050
  //this.power = powerState;
1081
1051
  //this.mediaState = playbackState;
1082
1052
  })
1083
- .on('addRemoveOrUpdateInput', async (input, remove) => {
1084
- await this.addRemoveOrUpdateInput(input, remove);
1053
+ .on('addRemoveOrUpdateInput', async (inputs, remove) => {
1054
+ await this.addRemoveOrUpdateInput(inputs, remove);
1085
1055
  })
1086
1056
  .on('success', (success) => {
1087
1057
  this.emit('success', success);