homebridge-unifi-protect 6.13.1 → 6.15.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.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/config.schema.json +8 -8
  3. package/dist/protect-camera.d.ts +1 -0
  4. package/dist/protect-camera.js +107 -66
  5. package/dist/protect-camera.js.map +1 -1
  6. package/dist/protect-chime.js +9 -9
  7. package/dist/protect-chime.js.map +1 -1
  8. package/dist/protect-device.d.ts +5 -1
  9. package/dist/protect-device.js +31 -8
  10. package/dist/protect-device.js.map +1 -1
  11. package/dist/protect-doorbell.js +6 -6
  12. package/dist/protect-doorbell.js.map +1 -1
  13. package/dist/protect-ffmpeg-codecs.js +1 -0
  14. package/dist/protect-ffmpeg-codecs.js.map +1 -1
  15. package/dist/protect-ffmpeg-options.js +22 -5
  16. package/dist/protect-ffmpeg-options.js.map +1 -1
  17. package/dist/protect-light.js +10 -10
  18. package/dist/protect-light.js.map +1 -1
  19. package/dist/protect-liveviews.js +14 -20
  20. package/dist/protect-liveviews.js.map +1 -1
  21. package/dist/protect-nvr-events.d.ts +2 -3
  22. package/dist/protect-nvr-events.js +63 -44
  23. package/dist/protect-nvr-events.js.map +1 -1
  24. package/dist/protect-nvr.d.ts +1 -2
  25. package/dist/protect-nvr.js +63 -19
  26. package/dist/protect-nvr.js.map +1 -1
  27. package/dist/protect-options.d.ts +5 -3
  28. package/dist/protect-options.js +18 -15
  29. package/dist/protect-options.js.map +1 -1
  30. package/dist/protect-platform.d.ts +1 -1
  31. package/dist/protect-platform.js +7 -11
  32. package/dist/protect-platform.js.map +1 -1
  33. package/dist/protect-record.js +4 -4
  34. package/dist/protect-record.js.map +1 -1
  35. package/dist/protect-rtp.js +8 -6
  36. package/dist/protect-rtp.js.map +1 -1
  37. package/dist/protect-sensor.js +40 -26
  38. package/dist/protect-sensor.js.map +1 -1
  39. package/dist/protect-stream.js +1 -1
  40. package/dist/protect-stream.js.map +1 -1
  41. package/dist/protect-types.d.ts +1 -0
  42. package/dist/protect-types.js +1 -0
  43. package/dist/protect-types.js.map +1 -1
  44. package/dist/protect-viewer.js +2 -3
  45. package/dist/protect-viewer.js.map +1 -1
  46. package/dist/settings.d.ts +2 -1
  47. package/dist/settings.js +5 -3
  48. package/dist/settings.js.map +1 -1
  49. package/homebridge-ui/public/index.html +12 -1
  50. package/homebridge-ui/public/lib/featureoptions.mjs +2 -1
  51. package/homebridge-ui/public/protect-featureoptions.mjs +12 -7
  52. package/homebridge-ui/public/ui.mjs +2 -4
  53. package/homebridge-ui/server.js +11 -4
  54. package/package.json +12 -12
package/dist/settings.js CHANGED
@@ -16,8 +16,12 @@ export const PROTECT_API_TIMEOUT = 3.5;
16
16
  export const PROTECT_CONTROLLER_REFRESH_INTERVAL = 120;
17
17
  // How often, in seconds, should we retry getting our bootstrap configuration from the Protect controller.
18
18
  export const PROTECT_CONTROLLER_RETRY_INTERVAL = 10;
19
- // Default duration, in milliseconds, of a physical digital chime attached to a Protect doorbell.
19
+ // Default delay, in seconds, before removing Protect devices that no longer exist.
20
+ export const PROTECT_DEVICE_REMOVAL_DELAY_INTERVAL = 60;
21
+ // Default duration, in milliseconds, of a physical digital chime attached to a Protect doorbell. This value comes from UniFi Protect itself.
20
22
  export const PROTECT_DOORBELL_CHIME_DURATION_DIGITAL = 1000;
23
+ // Default duration, in milliseconds, of the trigger switch for a Protect doorbell, primarily for automation purposes.
24
+ export const PROTECT_DOORBELL_TRIGGER_DURATION = 5000;
21
25
  // FFmpeg afftdn audio filter defaults - this setting uses FFTs to reduce noise in an audio signal by the number of decibels below.
22
26
  export const PROTECT_FFMPEG_AUDIO_FILTER_FFTNR = 90;
23
27
  // FFmpeg highpass audio filter defaults - this setting attenuates (eliminates) frequencies below the value.
@@ -48,8 +52,6 @@ export const PROTECT_MQTT_RECONNECT_INTERVAL = 60;
48
52
  export const PROTECT_MQTT_TOPIC = "unifi/protect";
49
53
  // Default duration, in seconds, of occupancy events.
50
54
  export const PROTECT_OCCUPANCY_DURATION = 300;
51
- // Default duration, in seconds, of ring events.
52
- export const PROTECT_RING_DURATION = 3;
53
55
  // Minimum required GPU memory on a Raspberry Pi for hardware acceleration.
54
56
  export const PROTECT_RPI_GPU_MINIMUM = 128;
55
57
  // Maximum age of a snapshot in seconds.
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,0BAA0B;AAC1B,MAAM,CAAC,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAEtD,mCAAmC;AACnC,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,oGAAoG;AACpG,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,4HAA4H;AAC5H,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAE9C,yFAAyF;AACzF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEvC,yFAAyF;AACzF,MAAM,CAAC,MAAM,mCAAmC,GAAG,GAAG,CAAC;AAEvD,0GAA0G;AAC1G,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAEpD,iGAAiG;AACjG,MAAM,CAAC,MAAM,uCAAuC,GAAG,IAAI,CAAC;AAE5D,mIAAmI;AACnI,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAEpD,4GAA4G;AAC5G,MAAM,CAAC,MAAM,oCAAoC,GAAG,GAAG,CAAC;AAExD,2GAA2G;AAC3G,MAAM,CAAC,MAAM,mCAAmC,GAAG,IAAI,CAAC;AAExD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC,oGAAoG;AACpG,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEhD,yHAAyH;AACzH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,mJAAmJ;AACnJ,MAAM,CAAC,MAAM,uCAAuC,GAAG,2BAA2B,GAAG,CAAC,CAAC;AAEvF,kKAAkK;AAClK,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAEnD,+IAA+I;AAC/I,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAC;AAErD,mEAAmE;AACnE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,wJAAwJ;AACxJ,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAE/C,0HAA0H;AAC1H,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,oGAAoG;AACpG,MAAM,CAAC,MAAM,+BAA+B,GAAG,EAAE,CAAC;AAElD,uGAAuG;AACvG,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD,qDAAqD;AACrD,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAE9C,gDAAgD;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEvC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,wCAAwC;AACxC,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAC;AAEhD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,uCAAuC,GAAG,EAAE,CAAC;AAE1D,6JAA6J;AAC7J,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,0BAA0B;AAC1B,MAAM,CAAC,MAAM,WAAW,GAAG,0BAA0B,CAAC;AAEtD,mCAAmC;AACnC,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,oGAAoG;AACpG,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,4HAA4H;AAC5H,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAE9C,yFAAyF;AACzF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEvC,yFAAyF;AACzF,MAAM,CAAC,MAAM,mCAAmC,GAAG,GAAG,CAAC;AAEvD,0GAA0G;AAC1G,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAEpD,mFAAmF;AACnF,MAAM,CAAC,MAAM,qCAAqC,GAAG,EAAE,CAAC;AAExD,6IAA6I;AAC7I,MAAM,CAAC,MAAM,uCAAuC,GAAG,IAAI,CAAC;AAE5D,sHAAsH;AACtH,MAAM,CAAC,MAAM,iCAAiC,GAAG,IAAI,CAAC;AAEtD,mIAAmI;AACnI,MAAM,CAAC,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAEpD,4GAA4G;AAC5G,MAAM,CAAC,MAAM,oCAAoC,GAAG,GAAG,CAAC;AAExD,2GAA2G;AAC3G,MAAM,CAAC,MAAM,mCAAmC,GAAG,IAAI,CAAC;AAExD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAEzC,oGAAoG;AACpG,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEhD,yHAAyH;AACzH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,mJAAmJ;AACnJ,MAAM,CAAC,MAAM,uCAAuC,GAAG,2BAA2B,GAAG,CAAC,CAAC;AAEvF,kKAAkK;AAClK,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAEnD,+IAA+I;AAC/I,MAAM,CAAC,MAAM,kCAAkC,GAAG,EAAE,CAAC;AAErD,mEAAmE;AACnE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,wJAAwJ;AACxJ,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAE/C,0HAA0H;AAC1H,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,oGAAoG;AACpG,MAAM,CAAC,MAAM,+BAA+B,GAAG,EAAE,CAAC;AAElD,uGAAuG;AACvG,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD,qDAAqD;AACrD,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AAE9C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,wCAAwC;AACxC,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAC;AAEhD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,uCAAuC,GAAG,EAAE,CAAC;AAE1D,6JAA6J;AAC7J,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC"}
@@ -160,4 +160,15 @@
160
160
  </li>
161
161
  </ul>
162
162
  </div>
163
- <script src="./ui.mjs" type="module"></script>
163
+ <noscript>
164
+ <h2>A JavaScript-enabled web browser is required to use this webUI.</h2>
165
+ </noscript>
166
+ <script>
167
+ <!--
168
+ (async () => {
169
+
170
+ // We use dynamic imports because web browsers often attempt to cache modules and we always want to pull a fresh copy, in case they've been updated.
171
+ await import("./ui.mjs");
172
+ })();
173
+ // -->
174
+ </script>
@@ -64,7 +64,8 @@ export class FeatureOptions {
64
64
 
65
65
  const optionRegex = new RegExp("^Enable\\." + featureOption + (!deviceMac ? "" : "\\." + deviceMac) + "\\.([^\\.]+)$", "gi");
66
66
 
67
- return this.optionsList.filter(x => optionRegex.test(x)).length ? true : false;
67
+
68
+ return this.optionsList.some(x => optionRegex.test(x));
68
69
  }
69
70
 
70
71
  // Get the value of a value-centric feature option.
@@ -4,9 +4,8 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
- import { FeatureOptions} from "./lib/featureoptions.mjs";
8
-
9
- export class ProtectFeatureOptions extends FeatureOptions {
7
+ // Protect-specific customizations for my feature option framework. We import in this odd way to dodge browser caches.
8
+ export class ProtectFeatureOptions extends (await import("./lib/featureoptions.mjs")).FeatureOptions {
10
9
 
11
10
  // The current plugin configuration.
12
11
  currentConfig;
@@ -370,7 +369,7 @@ export class ProtectFeatureOptions extends FeatureOptions {
370
369
  for(const category of ufpFeatures.categories) {
371
370
 
372
371
  // Only show feature option categories that are valid for this context.
373
- if(ufpDevice && (ufpDevice.modelKey !== "nvr") && !category.validFor.some(x => (x === ufpDevice.modelKey) || x === "all")) {
372
+ if(ufpDevice && (ufpDevice.modelKey !== "nvr") && !category.modelKey.some(x => (x === ufpDevice.modelKey) || x === "all")) {
374
373
 
375
374
  continue;
376
375
  }
@@ -408,8 +407,11 @@ export class ProtectFeatureOptions extends FeatureOptions {
408
407
  for(const option of optionsDevice[category.name]) {
409
408
 
410
409
  // Only show feature options that are valid for this device.
411
- if(ufpDevice && (ufpDevice.modelKey !== "nvr") && ((option.hasFeature && (!ufpDevice.featureFlags || !option.hasFeature.some(x => ufpDevice.featureFlags[x]))) ||
412
- (option.hasProperty && !option.hasProperty.some(x => x in ufpDevice)))) {
410
+ if(ufpDevice && (ufpDevice.modelKey !== "nvr") && (
411
+ (option.hasFeature && (!ufpDevice.featureFlags || !option.hasFeature.some(x => ufpDevice.featureFlags[x]))) ||
412
+ (option.hasProperty && !option.hasProperty.some(x => x in ufpDevice)) ||
413
+ (option.modelKey && (option.modelKey !== "all") && !option.modelKey.includes(ufpDevice.modelKey)) ||
414
+ (option.hasSmartObjectType && ufpDevice.featureFlags?.smartDetectTypes && !option.hasSmartObjectType.some(x => ufpDevice.featureFlags.smartDetectTypes.includes(x))))) {
413
415
 
414
416
  continue;
415
417
  }
@@ -525,7 +527,10 @@ export class ProtectFeatureOptions extends FeatureOptions {
525
527
 
526
528
  if(checkbox.checked) {
527
529
 
528
- newOptions.push("Enable." + checkbox.value + "." + inputValue.value);
530
+ if(inputValue.value.length) {
531
+
532
+ newOptions.push("Enable." + checkbox.value + "." + inputValue.value);
533
+ }
529
534
  } else if(checkbox.indeterminate) {
530
535
 
531
536
  // If we're in an indeterminate state, we need to traverse the tree to get the upstream value we're inheriting.
@@ -4,10 +4,8 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
- import { ProtectFeatureOptions } from "./protect-featureoptions.mjs";
8
-
9
- // Keep a list of all the feature options and option groups.
10
- const featureOptions = new ProtectFeatureOptions();
7
+ // Keep a list of all the feature options and option groups. We dynamically import our modules to avoid browser caches.
8
+ const featureOptions = new (await import("./protect-featureoptions.mjs")).ProtectFeatureOptions();
11
9
 
12
10
  // Show the first run user experience if we don't have valid login credentials.
13
11
  function showFirstRun () {
@@ -36,7 +36,7 @@ class PluginUiServer extends HomebridgePluginUiServer {
36
36
  // Register the getErrorMessage() webUI server API endpoint.
37
37
  #registerGetErrorMessage() {
38
38
 
39
- // Return the list of Protect devices.
39
+ // Return the most recent error message generated by the Protect API.
40
40
  this.onRequest("/getErrorMessage", async () => {
41
41
 
42
42
  try {
@@ -66,11 +66,18 @@ class PluginUiServer extends HomebridgePluginUiServer {
66
66
  error: (message, parameters = []) => {
67
67
 
68
68
  // Save the error to inform the user in the webUI.
69
- this.errorInfo = util.format(message, ...parameters);
70
- console.log(this.errorInfo);
69
+ if(!!parameters?.[Symbol.iterator]) {
70
+
71
+ this.errorInfo = util.format(message, ...parameters);
72
+ } else {
73
+
74
+ this.errorInfo = util.format(message, parameters);
75
+ }
76
+
77
+ console.error(this.errorInfo);
71
78
  },
72
79
  info: (message, parameters) => {},
73
- warn: (message, parameters = []) => console.log(util.format(message, ...parameters))
80
+ warn: (message, parameters = []) => {}
74
81
  };
75
82
 
76
83
  // Connect to the Protect controller.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-unifi-protect",
3
- "version": "6.13.1",
3
+ "version": "6.15.0",
4
4
  "displayName": "Homebridge UniFi Protect",
5
5
  "description": "Homebridge UniFi Protect plugin providing complete HomeKit integration for the UniFi Protect ecosystem with full support for most features including autoconfiguration, motion detection, multiple controllers, and realtime updates.",
6
6
  "author": {
@@ -76,21 +76,21 @@
76
76
  "main": "dist/index.js",
77
77
  "dependencies": {
78
78
  "@homebridge/plugin-ui-utils": "0.1.0",
79
- "ffmpeg-for-homebridge": "0.1.4",
80
- "mqtt": "5.0.3",
81
- "unifi-protect": "4.6.1",
82
- "ws": "8.13.0"
79
+ "ffmpeg-for-homebridge": "2.1.0",
80
+ "mqtt": "5.0.5",
81
+ "unifi-protect": "4.7.0",
82
+ "ws": "8.14.2"
83
83
  },
84
84
  "devDependencies": {
85
- "@types/node": "20.5.6",
86
- "@types/readable-stream": "4.0.2",
87
- "@types/ws": "8.5.5",
88
- "@typescript-eslint/eslint-plugin": "6.4.1",
89
- "@typescript-eslint/parser": "6.4.1",
90
- "eslint": "8.48.0",
85
+ "@types/node": "20.8.0",
86
+ "@types/readable-stream": "4.0.3",
87
+ "@types/ws": "8.5.6",
88
+ "@typescript-eslint/eslint-plugin": "6.7.3",
89
+ "@typescript-eslint/parser": "6.7.3",
90
+ "eslint": "8.50.0",
91
91
  "homebridge": "1.6.1",
92
92
  "nodemon": "3.0.1",
93
- "rimraf": "5.0.1",
93
+ "rimraf": "5.0.5",
94
94
  "typescript": "5.2.2"
95
95
  }
96
96
  }