@homebridge-plugins/homebridge-eufy-security 5.0.0-beta.15 → 5.0.0-beta.17

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 (36) hide show
  1. package/config.schema.json +4 -0
  2. package/dist/configuration.js +11 -1
  3. package/dist/configuration.js.map +1 -1
  4. package/dist/diagnostics.js +105 -19
  5. package/dist/diagnostics.js.map +1 -1
  6. package/dist/homekit/adapters/lock.js +27 -11
  7. package/dist/homekit/adapters/lock.js.map +1 -1
  8. package/dist/homekit/adapters/package-sensor.js +63 -0
  9. package/dist/homekit/adapters/package-sensor.js.map +1 -0
  10. package/dist/homekit/adapters/registry.js +2 -0
  11. package/dist/homekit/adapters/registry.js.map +1 -1
  12. package/dist/homekit/adapters/security-system.js +10 -0
  13. package/dist/homekit/adapters/security-system.js.map +1 -1
  14. package/dist/homekit/coverage-matrix.js +0 -2
  15. package/dist/homekit/coverage-matrix.js.map +1 -1
  16. package/dist/homekit/reconciler.js +1 -0
  17. package/dist/homekit/reconciler.js.map +1 -1
  18. package/dist/platform.js +1 -0
  19. package/dist/platform.js.map +1 -1
  20. package/dist/runtime/channel.js +6 -2
  21. package/dist/runtime/channel.js.map +1 -1
  22. package/dist/runtime/owner.js +3 -0
  23. package/dist/runtime/owner.js.map +1 -1
  24. package/dist/ui/dashboard.js +7 -1
  25. package/dist/ui/dashboard.js.map +1 -1
  26. package/dist/ui/server.js +1 -0
  27. package/dist/ui/server.js.map +1 -1
  28. package/homebridge-ui/public/app.css +117 -229
  29. package/homebridge-ui/public/i18n/en.json +86 -79
  30. package/homebridge-ui/public/i18n/fr.json +87 -80
  31. package/homebridge-ui/public/index.html +84 -94
  32. package/homebridge-ui/public/js/app.js +246 -423
  33. package/homebridge-ui/public/js/dashboard.js +58 -9
  34. package/homebridge-ui/public/js/profile-wizard.js +6 -55
  35. package/i18n/runtime/en.json +1 -1
  36. package/package.json +1 -1
@@ -76,6 +76,10 @@
76
76
  "default": true,
77
77
  "type": "boolean"
78
78
  },
79
+ "securitySystem": {
80
+ "default": true,
81
+ "type": "boolean"
82
+ },
79
83
  "snapshotMode": {
80
84
  "default": "Refresh",
81
85
  "enum": [
@@ -9,7 +9,13 @@ export const DEFAULT_MAX_CONCURRENT_MEDIA_SESSIONS = 0;
9
9
  export const DEFAULT_WARM_UP_EVENTS = ['doorbellPress'];
10
10
  /** What each HomeKit state means where the user assigned nothing. */
11
11
  export const DEFAULT_ARMING_MODES = { home: 'home', away: 'away', off: 'disarmed' };
12
- const ENTITY_PREFERENCE_KEYS = new Set(['represented', 'audio', 'snapshotMode', 'armingModes']);
12
+ const ENTITY_PREFERENCE_KEYS = new Set([
13
+ 'represented',
14
+ 'audio',
15
+ 'securitySystem',
16
+ 'snapshotMode',
17
+ 'armingModes',
18
+ ]);
13
19
  const SNAPSHOT_MODES = new Set(['Cloud', 'Live', 'Refresh']);
14
20
  const ARMING_SLOTS = new Set(['home', 'away', 'night', 'off']);
15
21
  function isRecord(value) {
@@ -47,6 +53,9 @@ function parseEntityPreferences(value) {
47
53
  if (candidate.audio !== undefined && typeof candidate.audio !== 'boolean') {
48
54
  throw new TypeError(`entityPreferences.${serial}.audio must be a boolean`);
49
55
  }
56
+ if (candidate.securitySystem !== undefined && typeof candidate.securitySystem !== 'boolean') {
57
+ throw new TypeError(`entityPreferences.${serial}.securitySystem must be a boolean`);
58
+ }
50
59
  if (candidate.snapshotMode !== undefined && !SNAPSHOT_MODES.has(candidate.snapshotMode)) {
51
60
  throw new TypeError(`entityPreferences.${serial}.snapshotMode must be Cloud, Live, or Refresh`);
52
61
  }
@@ -184,6 +193,7 @@ export function resolveEntityPreference(config, serial) {
184
193
  return {
185
194
  represented: preference?.represented ?? true,
186
195
  audio: preference?.audio ?? true,
196
+ securitySystem: preference?.securitySystem ?? true,
187
197
  snapshotMode: preference?.snapshotMode ?? 'Refresh',
188
198
  armingModes: { ...DEFAULT_ARMING_MODES, ...preference?.armingModes },
189
199
  };
@@ -1 +1 @@
1
- {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../src/configuration.ts"],"names":[],"mappings":"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"}
@@ -67,6 +67,7 @@ const HOMEKIT_LIVE_REQUEST_EVENTS = new Set([
67
67
  * failure.
68
68
  */
69
69
  const SDK_ERROR_TYPES = [
70
+ 'DeviceChannelUnresolvedError',
70
71
  'Error',
71
72
  'RangeError',
72
73
  'SessionExpiredError',
@@ -269,13 +270,14 @@ const BUG_REPORT_FORM = 'https://github.com/homebridge-plugins/homebridge-eufy/i
269
270
  function bugReportUrl(session, missingEvidence, host) {
270
271
  const url = new URL(BUG_REPORT_FORM);
271
272
  url.searchParams.set('template', 'bug_report.yml');
273
+ url.searchParams.set('title', `[Diagnostics] ${BUG_REPORT_AREAS[session.profile]}: `);
272
274
  url.searchParams.set('environment', [
273
275
  `- **Plugin Version**: ${PLUGIN_VERSION}`,
274
276
  `- **eufy SDK**: ${SDK_VERSION}`,
275
277
  `- **Node.js Version**: ${process.version}`,
276
278
  `- **Homebridge Version**: ${host?.homebridge ?? ''}`,
277
279
  `- **OS**: ${process.platform} ${process.arch}`,
278
- `- **Diagnostics profile**: ${session.profile} (${session.reproductionMode})`,
280
+ `- **Diagnostics profile**: ${session.profile}`,
279
281
  `- **Missing evidence**: ${missingEvidence.length ? missingEvidence.join(', ') : 'none'}`,
280
282
  ].join('\n'));
281
283
  url.searchParams.set('area', BUG_REPORT_AREAS[session.profile]);
@@ -288,7 +290,7 @@ const DIAGNOSTICS_PROFILES = {
288
290
  'live-media': ['plugin-log', 'sdk-log', 'homekit-log', 'ffmpeg-log'],
289
291
  'hksv-recording': ['plugin-log', 'sdk-log', 'ffmpeg-log'],
290
292
  'dashboard-ui': ['plugin-log', 'ui-log'],
291
- other: ['plugin-log', 'sdk-log', 'homekit-log'],
293
+ other: ['plugin-log', 'sdk-log', 'homekit-log', 'ffmpeg-log'],
292
294
  };
293
295
  /** Narrows external profile input against the diagnostics-owned profile registry. */
294
296
  export function isDiagnosticsProfile(value) {
@@ -338,6 +340,22 @@ function activeDiagnosticsSession(storageRoot, now) {
338
340
  const session = readDiagnosticsSession(storageRoot);
339
341
  return session && Date.parse(session.expiresAt) > now ? session : undefined;
340
342
  }
343
+ /**
344
+ * A session as it stands at `now`: a capture still running when its authorization ends is finished at that end.
345
+ *
346
+ * A finished capture can be reviewed and exported until the archive retention has elapsed past the end of its
347
+ * authorization, so a capture that ran out its 72 hours keeps what it captured.
348
+ */
349
+ function settledDiagnosticsSession(session, now) {
350
+ const expiresAt = Date.parse(session.expiresAt);
351
+ const settled = session.reproductionStartedAt && !session.reproductionEndedAt && expiresAt <= now
352
+ ? { ...session, reproductionEndedAt: session.expiresAt }
353
+ : session;
354
+ return {
355
+ session: settled,
356
+ exportable: Boolean(settled.reproductionEndedAt) && now < expiresAt + SUPPORT_ARCHIVE_RETENTION_MS,
357
+ };
358
+ }
341
359
  /**
342
360
  * Collapses one supplied string to bounded printable text, or nothing where none of it survives.
343
361
  *
@@ -576,6 +594,22 @@ export class GuidedDiagnostics {
576
594
  await this.ensureMarker(session, 'reproduction-started', session.reproductionStartedAt);
577
595
  return this.project(session);
578
596
  }
597
+ /**
598
+ * Deletes the persisted session without an archive, which also ends the verbose retention it authorized. UI events
599
+ * already queued are written first and later ones are refused until it is gone, so none lands after the delete.
600
+ */
601
+ async cancel() {
602
+ this.uiEventsClosing = true;
603
+ try {
604
+ await this.uiEventWrites;
605
+ this.pendingSupportArchive = undefined;
606
+ await rm(diagnosticsSessionPath(this.storageRoot), { force: true });
607
+ return await this.status();
608
+ }
609
+ finally {
610
+ this.uiEventsClosing = false;
611
+ }
612
+ }
579
613
  async endReproduction() {
580
614
  let session = this.requireAuthorized();
581
615
  if (!session.reproductionStartedAt) {
@@ -656,10 +690,16 @@ export class GuidedDiagnostics {
656
690
  /** Prepares the exact manifest and evidence snapshot that one subsequent export may encrypt. */
657
691
  async reviewSupportArchive() {
658
692
  await this.uiEventWrites;
659
- const session = readDiagnosticsSession(this.storageRoot);
693
+ const persisted = readDiagnosticsSession(this.storageRoot);
694
+ const { session, exportable } = persisted
695
+ ? settledDiagnosticsSession(persisted, this.now())
696
+ : { session: undefined, exportable: false };
660
697
  if (!session?.reproductionStartedAt || !session.reproductionEndedAt) {
661
698
  throw new Error('A completed reproduction is required before archive review');
662
699
  }
700
+ if (!exportable) {
701
+ throw new Error('Diagnostics authorization is inactive or expired');
702
+ }
663
703
  const collected = await this.collectSupportEvidence(session);
664
704
  const reproductionStartedAt = Date.parse(session.reproductionStartedAt);
665
705
  const selected = DIAGNOSTICS_PROFILES[session.profile];
@@ -702,7 +742,13 @@ export class GuidedDiagnostics {
702
742
  this.pendingSupportArchive = { reviewId, manifest, evidence: collected };
703
743
  return { reviewId, manifest };
704
744
  }
705
- /** Consumes one reviewed snapshot and returns an encrypted envelope without writing plaintext or an archive to disk. */
745
+ /**
746
+ * Consumes one reviewed snapshot and returns an encrypted envelope without writing plaintext or an archive to disk.
747
+ *
748
+ * The session outlives the export, because nothing here proves the envelope reached the reporter: a fresh review
749
+ * exports it again until the reporter leaves it with {@link cancel}, another capture replaces it, or the archive
750
+ * retention ends it.
751
+ */
706
752
  async exportSupportArchive(reviewId) {
707
753
  const pending = this.pendingSupportArchive;
708
754
  if (!pending || pending.reviewId !== reviewId) {
@@ -748,11 +794,12 @@ export class GuidedDiagnostics {
748
794
  authTag: cipher.getAuthTag().toString('base64'),
749
795
  ciphertext: ciphertext.toString('base64'),
750
796
  };
751
- return {
797
+ const exported = {
752
798
  filename: `homebridge-eufy-${pending.manifest.supportCaseId}.eufysupport.gz`,
753
799
  mediaType: 'application/gzip',
754
800
  archive: await gzip(Buffer.from(`${JSON.stringify(envelope)}\n`, 'utf8')),
755
801
  };
802
+ return exported;
756
803
  }
757
804
  finally {
758
805
  contentKey.fill(0);
@@ -1037,16 +1084,17 @@ export class GuidedDiagnostics {
1037
1084
  throw new Error('Diagnostics authorization is inactive or expired');
1038
1085
  return session;
1039
1086
  }
1040
- async project(session) {
1041
- if (!session) {
1087
+ async project(persisted) {
1088
+ if (!persisted) {
1042
1089
  return { status: 'inactive', selectedEvidence: [], missingEvidence: [], partialExportAvailable: false };
1043
1090
  }
1091
+ const { session, exportable } = settledDiagnosticsSession(persisted, this.now());
1044
1092
  const selectedEvidence = DIAGNOSTICS_PROFILES[session.profile];
1045
1093
  const collected = session.reproductionStartedAt && session.reproductionEndedAt
1046
1094
  ? await this.collectSupportEvidence(session)
1047
1095
  : undefined;
1048
1096
  const missingEvidence = collected ? missingEvidenceClasses(selectedEvidence, collected) : [];
1049
- const expired = Date.parse(session.expiresAt) <= this.now();
1097
+ const expired = Date.parse(session.expiresAt) <= this.now() && !exportable;
1050
1098
  const status = expired
1051
1099
  ? 'expired'
1052
1100
  : session.reproductionEndedAt
@@ -1065,7 +1113,7 @@ export class GuidedDiagnostics {
1065
1113
  expiresAt: session.expiresAt,
1066
1114
  ...(session.reproductionStartedAt ? { reproductionStartedAt: session.reproductionStartedAt } : {}),
1067
1115
  ...(session.reproductionEndedAt ? { reproductionEndedAt: session.reproductionEndedAt } : {}),
1068
- partialExportAvailable: Boolean(session.reproductionEndedAt),
1116
+ partialExportAvailable: exportable,
1069
1117
  ...(session.affectedDevices === undefined ? {} : { affectedDevices: session.affectedDevices }),
1070
1118
  issueUrl: bugReportUrl(session, missingEvidence, readHostEnvironment(this.storageRoot)),
1071
1119
  };
@@ -1719,6 +1767,7 @@ const HOMEKIT_EVENT_ROUTES = {
1719
1767
  'battery.status': new Set(['battery-alert', 'battery-level']),
1720
1768
  'contact.sensor': new Set(['contact-state']),
1721
1769
  'doorbell.press': new Set(['doorbell-press']),
1770
+ 'doorbell.package': new Set(['package-presence']),
1722
1771
  'lock.mechanism': new Set(['lock-state']),
1723
1772
  'motion.sensor': new Set(['motion-detection']),
1724
1773
  'arming.security-system': new Set(['arming-mode-changed', 'security-system-alarm']),
@@ -1982,6 +2031,33 @@ const HOMEKIT_REASON_ACTIONS = {
1982
2031
  'camera-recording-unavailable:adapter-missing': 'log.action.setFfmpegPath',
1983
2032
  'camera-live-session-failed:adaptation-spawn-failed': 'log.action.checkFfmpegPath',
1984
2033
  };
2034
+ /** Projects a value onto an active condition, or nothing where the catalog does not write that code with those keys. */
2035
+ export function knownCondition(value) {
2036
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
2037
+ return undefined;
2038
+ const { code, summaryKey, actionKey, serials } = value;
2039
+ if (typeof code !== 'string')
2040
+ return undefined;
2041
+ const runtime = Object.values(RUNTIME_CONDITIONS).find((condition) => condition.code === code);
2042
+ const homeKit = Object.hasOwn(HOMEKIT_CONDITIONS, code)
2043
+ ? HOMEKIT_CONDITIONS[code]
2044
+ : undefined;
2045
+ const [summary, ...actions] = runtime
2046
+ ? [runtime.summaryKey, runtime.actionKey]
2047
+ : homeKit
2048
+ ? [
2049
+ ...homeKit,
2050
+ ...Object.entries(HOMEKIT_REASON_ACTIONS)
2051
+ .filter(([key]) => key.startsWith(`${code}:`))
2052
+ .map(([, action]) => action),
2053
+ ]
2054
+ : [];
2055
+ const action = allowlistedLabel(actionKey, actions);
2056
+ if (summary === undefined || summaryKey !== summary || action === undefined)
2057
+ return undefined;
2058
+ const named = Array.isArray(serials) ? serials.filter((serial) => typeof serial === 'string') : [];
2059
+ return { code, summaryKey: summary, actionKey: action, ...(named.length === 0 ? {} : { serials: named }) };
2060
+ }
1985
2061
  /** HomeKit conditions that state a gap nothing in the user's setup closes, so an active one is not a warning. */
1986
2062
  const INFORMATIONAL_HOMEKIT_CONDITIONS = new Set(['recognized-device-not-represented']);
1987
2063
  /** The level and action one HomeKit condition is written with, decided once for the console and the record. */
@@ -2177,7 +2253,7 @@ export function reportRuntimeNotice(target, code, fields = {}) {
2177
2253
  const notice = RUNTIME_NOTICES[code];
2178
2254
  const durationMs = fields.durationMs === undefined ? undefined : Math.max(0, Math.trunc(fields.durationMs));
2179
2255
  const messageKey = durationMs !== undefined && 'durationMessageKey' in notice ? notice.durationMessageKey : notice.messageKey;
2180
- target[notice.level]?.(`[${code}] ${localize(target, messageKey, { durationMs: durationMs ?? 0 })}`);
2256
+ target[notice.level]?.(`[${code}] ${localize(target, messageKey, { durationMs: durationMs ?? 0, finishBy: fields.finishBy ?? '' })}`);
2181
2257
  target.debug?.(JSON.stringify({
2182
2258
  scope: 'runtime-notice',
2183
2259
  level: notice.level,
@@ -2192,14 +2268,17 @@ export function reportRuntimeNotice(target, code, fields = {}) {
2192
2268
  * The file is the authority: the supplied identifier only names which window the caller believes was opened,
2193
2269
  * and a session the file does not hold as active changes nothing and reports nothing. A confirmed pickup emits
2194
2270
  * one operational record, which is the evidence that this process began retaining the window's scopes, taken
2195
- * at the moment it did rather than whenever a later record arrives.
2271
+ * at the moment it did rather than whenever a later record arrives, and its console line names the time the
2272
+ * capture stops on its own.
2196
2273
  */
2197
2274
  export function armDiagnosticsAuthorization(target, storageRoot, supportCaseId, now = Date.now) {
2198
- if (!isSupportCaseId(supportCaseId) ||
2199
- activeDiagnosticsSession(storageRoot, now())?.supportCaseId !== supportCaseId) {
2275
+ const session = activeDiagnosticsSession(storageRoot, now());
2276
+ if (!isSupportCaseId(supportCaseId) || session?.supportCaseId !== supportCaseId) {
2200
2277
  return false;
2201
2278
  }
2202
- reportRuntimeNotice(target, 'diagnostics-authorization-armed');
2279
+ reportRuntimeNotice(target, 'diagnostics-authorization-armed', {
2280
+ finishBy: new Date(session.expiresAt).toLocaleString(),
2281
+ });
2203
2282
  return true;
2204
2283
  }
2205
2284
  /** Emits the startup notice for discarded settings awaiting acknowledgement. */
@@ -2573,7 +2652,11 @@ export class DiagnosticConditions {
2573
2652
  const alias = this.aliases.get(serial);
2574
2653
  return name === undefined ? undefined : alias === undefined ? name : `${name} (${alias})`;
2575
2654
  })
2576
- .filter((named) => named !== undefined));
2655
+ .filter((named) => named !== undefined), uniqueDeviceIds);
2656
+ }
2657
+ /** Every condition active now, each held from the transition that raised it to the one that clears it. */
2658
+ current() {
2659
+ return [...this.active.values()].map(({ condition }) => condition);
2577
2660
  }
2578
2661
  /**
2579
2662
  * The support-case alias for one device identity, minted on first use.
@@ -2591,13 +2674,16 @@ export class DiagnosticConditions {
2591
2674
  }
2592
2675
  write(code, active, reason, summaryKey, actionKey, level, fields = {}, conditionKey = code,
2593
2676
  /** Accessory names for the console line only — never retained, see {@link DiagnosticConditions}. */
2594
- names) {
2595
- const fingerprint = JSON.stringify({ active, reason, ...fields });
2677
+ names, serials = []) {
2678
+ const fingerprint = JSON.stringify({ active, reason, ...fields, serials });
2596
2679
  if (active) {
2597
- if (this.active.get(conditionKey) === fingerprint) {
2680
+ if (this.active.get(conditionKey)?.fingerprint === fingerprint) {
2598
2681
  return;
2599
2682
  }
2600
- this.active.set(conditionKey, fingerprint);
2683
+ this.active.set(conditionKey, {
2684
+ fingerprint,
2685
+ condition: { code, summaryKey, actionKey, ...(serials.length === 0 ? {} : { serials: [...serials] }) },
2686
+ });
2601
2687
  }
2602
2688
  else if (!this.active.delete(conditionKey)) {
2603
2689
  return;