homebridge-eufy-security 4.4.2-beta.2 → 4.4.2-beta.20

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 (147) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/FUNDING.yml +1 -0
  3. package/README.md +14 -17
  4. package/dist/accessories/AutoSyncStationAccessory.js +26 -30
  5. package/dist/accessories/AutoSyncStationAccessory.js.map +1 -1
  6. package/dist/accessories/BaseAccessory.js +33 -46
  7. package/dist/accessories/BaseAccessory.js.map +1 -1
  8. package/dist/accessories/CameraAccessory.js +92 -167
  9. package/dist/accessories/CameraAccessory.js.map +1 -1
  10. package/dist/accessories/Device.js +11 -15
  11. package/dist/accessories/Device.js.map +1 -1
  12. package/dist/accessories/EntrySensorAccessory.js +7 -12
  13. package/dist/accessories/EntrySensorAccessory.js.map +1 -1
  14. package/dist/accessories/LockAccessory.js +20 -24
  15. package/dist/accessories/LockAccessory.js.map +1 -1
  16. package/dist/accessories/MotionSensorAccessory.js +7 -12
  17. package/dist/accessories/MotionSensorAccessory.js.map +1 -1
  18. package/dist/accessories/StationAccessory.js +40 -45
  19. package/dist/accessories/StationAccessory.js.map +1 -1
  20. package/dist/config.js +1 -4
  21. package/dist/config.js.map +1 -1
  22. package/dist/controller/LocalLivestreamManager.js +85 -89
  23. package/dist/controller/LocalLivestreamManager.js.map +1 -1
  24. package/dist/controller/recordingDelegate.js +116 -108
  25. package/dist/controller/recordingDelegate.js.map +1 -1
  26. package/dist/controller/snapshotDelegate.js +379 -0
  27. package/dist/controller/snapshotDelegate.js.map +1 -0
  28. package/dist/controller/streamingDelegate.js +202 -207
  29. package/dist/controller/streamingDelegate.js.map +1 -1
  30. package/dist/index.js +9 -7
  31. package/dist/index.js.map +1 -1
  32. package/dist/interfaces.js +1 -2
  33. package/dist/interfaces.js.map +1 -1
  34. package/dist/platform.js +145 -165
  35. package/dist/platform.js.map +1 -1
  36. package/dist/settings.js +26 -19
  37. package/dist/settings.js.map +1 -1
  38. package/dist/utils/Talkback.js +9 -13
  39. package/dist/utils/Talkback.js.map +1 -1
  40. package/dist/utils/configTypes.js +12 -7
  41. package/dist/utils/configTypes.js.map +1 -1
  42. package/dist/utils/ffmpeg.js +44 -52
  43. package/dist/utils/ffmpeg.js.map +1 -1
  44. package/dist/utils/interfaces.js +1 -5
  45. package/dist/utils/interfaces.js.map +1 -1
  46. package/dist/utils/utils.js +32 -134
  47. package/dist/utils/utils.js.map +1 -1
  48. package/dist/version.js +1 -4
  49. package/dist/version.js.map +1 -1
  50. package/eslint.config.mjs +25 -47
  51. package/homebridge-eufy-security.png +0 -0
  52. package/homebridge-ui/public/app.js +221 -0
  53. package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
  54. package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
  55. package/homebridge-ui/public/assets/devices/homebasemini_large.jpg +0 -0
  56. package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
  57. package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
  58. package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
  59. package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
  60. package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
  61. package/homebridge-ui/public/components/device-card.js +141 -0
  62. package/homebridge-ui/public/components/guard-modes.js +88 -0
  63. package/homebridge-ui/public/components/number-input.js +121 -0
  64. package/homebridge-ui/public/components/select.js +73 -0
  65. package/homebridge-ui/public/components/toggle.js +68 -0
  66. package/homebridge-ui/public/index.html +24 -14
  67. package/homebridge-ui/public/services/api.js +129 -0
  68. package/homebridge-ui/public/services/config.js +144 -0
  69. package/homebridge-ui/public/style.css +705 -0
  70. package/homebridge-ui/public/utils/countries.js +73 -0
  71. package/homebridge-ui/public/utils/device-images.js +69 -0
  72. package/homebridge-ui/public/utils/helpers.js +47 -0
  73. package/homebridge-ui/public/views/dashboard.js +211 -0
  74. package/homebridge-ui/public/views/device-detail.js +631 -0
  75. package/homebridge-ui/public/views/login.js +625 -0
  76. package/homebridge-ui/public/views/settings.js +389 -0
  77. package/homebridge-ui/public/views/unsupported-detail.js +216 -0
  78. package/homebridge-ui/server.js +567 -450
  79. package/package.json +19 -59
  80. package/dist/accessories/AutoSyncStationAccessory.d.ts +0 -42
  81. package/dist/accessories/AutoSyncStationAccessory.d.ts.map +0 -1
  82. package/dist/accessories/BaseAccessory.d.ts +0 -56
  83. package/dist/accessories/BaseAccessory.d.ts.map +0 -1
  84. package/dist/accessories/CameraAccessory.d.ts +0 -84
  85. package/dist/accessories/CameraAccessory.d.ts.map +0 -1
  86. package/dist/accessories/Device.d.ts +0 -19
  87. package/dist/accessories/Device.d.ts.map +0 -1
  88. package/dist/accessories/EntrySensorAccessory.d.ts +0 -25
  89. package/dist/accessories/EntrySensorAccessory.d.ts.map +0 -1
  90. package/dist/accessories/LockAccessory.d.ts +0 -45
  91. package/dist/accessories/LockAccessory.d.ts.map +0 -1
  92. package/dist/accessories/MotionSensorAccessory.d.ts +0 -25
  93. package/dist/accessories/MotionSensorAccessory.d.ts.map +0 -1
  94. package/dist/accessories/StationAccessory.d.ts +0 -86
  95. package/dist/accessories/StationAccessory.d.ts.map +0 -1
  96. package/dist/config.d.ts +0 -31
  97. package/dist/config.d.ts.map +0 -1
  98. package/dist/controller/LocalLivestreamManager.d.ts +0 -31
  99. package/dist/controller/LocalLivestreamManager.d.ts.map +0 -1
  100. package/dist/controller/SnapshotManager.d.ts +0 -64
  101. package/dist/controller/SnapshotManager.d.ts.map +0 -1
  102. package/dist/controller/SnapshotManager.js +0 -434
  103. package/dist/controller/SnapshotManager.js.map +0 -1
  104. package/dist/controller/recordingDelegate.d.ts +0 -27
  105. package/dist/controller/recordingDelegate.d.ts.map +0 -1
  106. package/dist/controller/streamingDelegate.d.ts +0 -52
  107. package/dist/controller/streamingDelegate.d.ts.map +0 -1
  108. package/dist/index.d.ts +0 -7
  109. package/dist/index.d.ts.map +0 -1
  110. package/dist/interfaces.d.ts +0 -15
  111. package/dist/interfaces.d.ts.map +0 -1
  112. package/dist/platform.d.ts +0 -94
  113. package/dist/platform.d.ts.map +0 -1
  114. package/dist/settings.d.ts +0 -23
  115. package/dist/settings.d.ts.map +0 -1
  116. package/dist/utils/Talkback.d.ts +0 -21
  117. package/dist/utils/Talkback.d.ts.map +0 -1
  118. package/dist/utils/configTypes.d.ts +0 -68
  119. package/dist/utils/configTypes.d.ts.map +0 -1
  120. package/dist/utils/ffmpeg.d.ts +0 -111
  121. package/dist/utils/ffmpeg.d.ts.map +0 -1
  122. package/dist/utils/interfaces.d.ts +0 -8
  123. package/dist/utils/interfaces.d.ts.map +0 -1
  124. package/dist/utils/utils.d.ts +0 -35
  125. package/dist/utils/utils.d.ts.map +0 -1
  126. package/dist/version.d.ts +0 -2
  127. package/dist/version.d.ts.map +0 -1
  128. package/homebridge-ui/configui/app/util/types.d.ts +0 -65
  129. package/homebridge-ui/configui/app/util/types.d.ts.map +0 -1
  130. package/homebridge-ui/configui/app/util/types.js +0 -18
  131. package/homebridge-ui/configui/app/util/types.js.map +0 -1
  132. package/homebridge-ui/public/3rdpartylicenses.txt +0 -561
  133. package/homebridge-ui/public/assets/devices/homebase2_large.jpg +0 -0
  134. package/homebridge-ui/public/assets/devices/homebase3_large.jpg +0 -0
  135. package/homebridge-ui/public/assets/images/homebridge-eufy-security.png +0 -0
  136. package/homebridge-ui/public/favicon.ico +0 -0
  137. package/homebridge-ui/public/main.f6423287e0411c87.js +0 -1
  138. package/homebridge-ui/public/polyfills.efa2f09ba3e49167.js +0 -1
  139. package/homebridge-ui/public/runtime.ccde331d62c423b3.js +0 -1
  140. package/homebridge-ui/public/styles.13e635bf7a488639.css +0 -5
  141. package/homebridge-ui/server.d.ts +0 -2
  142. package/homebridge-ui/server.d.ts.map +0 -1
  143. package/homebridge-ui/server.js.map +0 -1
  144. package/homebridge-ui/version.d.ts +0 -2
  145. package/homebridge-ui/version.d.ts.map +0 -1
  146. package/homebridge-ui/version.js +0 -5
  147. package/homebridge-ui/version.js.map +0 -1
package/dist/platform.js CHANGED
@@ -1,26 +1,20 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.EufySecurityPlatform = void 0;
7
- const settings_1 = require("./settings");
8
- const config_1 = require("./config");
9
- const StationAccessory_1 = require("./accessories/StationAccessory");
10
- const EntrySensorAccessory_1 = require("./accessories/EntrySensorAccessory");
11
- const MotionSensorAccessory_1 = require("./accessories/MotionSensorAccessory");
12
- const CameraAccessory_1 = require("./accessories/CameraAccessory");
13
- const LockAccessory_1 = require("./accessories/LockAccessory");
14
- const AutoSyncStationAccessory_1 = require("./accessories/AutoSyncStationAccessory");
15
- const eufy_security_client_1 = require("eufy-security-client");
16
- const rotating_file_stream_1 = require("rotating-file-stream");
17
- const fs_1 = __importDefault(require("fs"));
18
- const node_os_1 = __importDefault(require("node:os"));
19
- const node_process_1 = require("node:process");
20
- const node_fs_1 = require("node:fs");
21
- const utils_1 = require("./utils/utils");
22
- const version_1 = require("./version");
23
- class EufySecurityPlatform {
1
+ import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
2
+ import { DEFAULT_CONFIG_VALUES } from './config.js';
3
+ import { StationAccessory } from './accessories/StationAccessory.js';
4
+ import { EntrySensorAccessory } from './accessories/EntrySensorAccessory.js';
5
+ import { MotionSensorAccessory } from './accessories/MotionSensorAccessory.js';
6
+ import { CameraAccessory } from './accessories/CameraAccessory.js';
7
+ import { LockAccessory } from './accessories/LockAccessory.js';
8
+ import { AutoSyncStationAccessory } from './accessories/AutoSyncStationAccessory.js';
9
+ import { EufySecurity, Device, DeviceType, UserType, libVersion, LogLevel, } from 'eufy-security-client';
10
+ import { createStream } from 'rotating-file-stream';
11
+ import fs from 'fs';
12
+ import os from 'node:os';
13
+ import { platform } from 'node:process';
14
+ import { readFileSync } from 'node:fs';
15
+ import { initLog, log, tsLogger, ffmpegLogger, HAP } from './utils/utils.js';
16
+ import { LIB_VERSION } from './version.js';
17
+ export class EufySecurityPlatform {
24
18
  config;
25
19
  api;
26
20
  eufyClient = {};
@@ -37,8 +31,8 @@ class EufySecurityPlatform {
37
31
  this.config = config;
38
32
  this.api = api;
39
33
  this.eufyPath = this.api.user.storagePath() + '/eufysecurity';
40
- if (!fs_1.default.existsSync(this.eufyPath)) {
41
- fs_1.default.mkdirSync(this.eufyPath);
34
+ if (!fs.existsSync(this.eufyPath)) {
35
+ fs.mkdirSync(this.eufyPath);
42
36
  }
43
37
  // Identify what we're running on so we can take advantage of hardware-specific features.
44
38
  this.probeHwOs();
@@ -56,10 +50,10 @@ class EufySecurityPlatform {
56
50
  // Assigns the provided config object to this.config, casting it to the EufySecurityPlatformConfig type.
57
51
  this.config = config;
58
52
  // Iterates over each key in the DEFAULT_CONFIG_VALUES object.
59
- Object.keys(config_1.DEFAULT_CONFIG_VALUES).forEach(key => {
53
+ Object.keys(DEFAULT_CONFIG_VALUES).forEach(key => {
60
54
  // Checks if the corresponding property in the config object is undefined or null.
61
55
  // If it is, assigns the default value from DEFAULT_CONFIG_VALUES to it.
62
- this.config[key] ??= config_1.DEFAULT_CONFIG_VALUES[key];
56
+ this.config[key] ??= DEFAULT_CONFIG_VALUES[key];
63
57
  });
64
58
  // List of properties that need to be parsed as numeric values
65
59
  const numericProperties = [
@@ -139,12 +133,12 @@ class EufySecurityPlatform {
139
133
  };
140
134
  // Modify log options if detailed logging is enabled
141
135
  if (this.config.enableDetailedLogging) {
142
- logOptions.name = `[EufySecurity-${version_1.LIB_VERSION}]`; // Modify logger name with plugin version
136
+ logOptions.name = `[EufySecurity-${LIB_VERSION}]`; // Modify logger name with plugin version
143
137
  logOptions.prettyLogTemplate = '[{{mm}}/{{dd}}/{{yyyy}} {{hh}}:{{MM}}:{{ss}}]\t{{name}}\t{{logLevelName}}\t[{{fileNameWithLine}}]\t'; // Modify log template
144
138
  logOptions.minLevel = 2; // Adjust minimum log level
145
139
  }
146
140
  // Initialize the global logger with the configured options
147
- (0, utils_1.init_log)(logOptions);
141
+ initLog(logOptions);
148
142
  // Configures log streams for various log files
149
143
  this.configureLogStreams();
150
144
  }
@@ -154,19 +148,19 @@ class EufySecurityPlatform {
154
148
  configureLogStreams() {
155
149
  // Log a message if log file storage will be omitted
156
150
  if (this.config.omitLogFiles) {
157
- utils_1.log.info('log file storage will be omitted.');
151
+ log.info('log file storage will be omitted.');
158
152
  return;
159
153
  }
160
154
  // Log streams configuration
161
155
  const logStreams = [
162
- { name: 'eufy-security.log', logger: utils_1.log },
163
- { name: 'ffmpeg.log', logger: utils_1.ffmpegLogger },
164
- { name: 'eufy-lib.log', logger: utils_1.tsLogger },
156
+ { name: 'eufy-security.log', logger: log },
157
+ { name: 'ffmpeg.log', logger: ffmpegLogger },
158
+ { name: 'eufy-lib.log', logger: tsLogger },
165
159
  ];
166
160
  // Iterate over log streams
167
161
  for (const { name, logger } of logStreams) {
168
162
  // Create a log stream with specific configurations
169
- const logStream = (0, rotating_file_stream_1.createStream)(name, {
163
+ const logStream = createStream(name, {
170
164
  path: this.eufyPath, // Log file path
171
165
  interval: '1d', // Log rotation interval (1 day)
172
166
  rotate: 3, // Number of rotated log files to keep
@@ -197,18 +191,18 @@ class EufySecurityPlatform {
197
191
  // Start off with a generic identifier.
198
192
  this._hostSystem = 'generic';
199
193
  // Take a look at the platform we're on for an initial hint of what we are.
200
- switch (node_process_1.platform) {
194
+ switch (platform) {
201
195
  // The beloved macOS.
202
196
  case 'darwin':
203
197
  // For macOS, we check the CPU model to determine if it's an Apple CPU or an Intel CPU.
204
- this._hostSystem = 'macOS.' + (node_os_1.default.cpus()[0].model.includes('Apple') ? 'Apple' : 'Intel');
198
+ this._hostSystem = 'macOS.' + (os.cpus()[0].model.includes('Apple') ? 'Apple' : 'Intel');
205
199
  break;
206
200
  // The indomitable Linux.
207
201
  case 'linux':
208
202
  // Let's further see if we're a small, but scrappy, Raspberry Pi.
209
203
  try {
210
204
  // As of the 4.9 kernel, Raspberry Pi prefers to be identified using this method and has deprecated cpuinfo.
211
- const systemId = (0, node_fs_1.readFileSync)('/sys/firmware/devicetree/base/model', { encoding: 'utf8' });
205
+ const systemId = readFileSync('/sys/firmware/devicetree/base/model', { encoding: 'utf8' });
212
206
  // Check if it's a Raspberry Pi 4.
213
207
  if (/Raspberry Pi (Compute Module )?4/.test(systemId)) {
214
208
  // If it's a Pi 4, we identify the system as running Raspbian.
@@ -231,12 +225,11 @@ class EufySecurityPlatform {
231
225
  return this._hostSystem;
232
226
  }
233
227
  initSetup() {
234
- utils_1.log.debug('warning: planned changes, see https://github.com/homebridge-eufy-security/plugin/issues/1');
235
- utils_1.log.debug('plugin data store:', this.eufyPath);
236
- utils_1.log.debug('OS is', this.hostSystem);
237
- utils_1.log.debug('Using bropats @homebridge-eufy-security/eufy-security-client library in version ', eufy_security_client_1.libVersion);
228
+ log.debug('plugin data store:', this.eufyPath);
229
+ log.debug('OS is', this.hostSystem);
230
+ log.debug('Using bropats @homebridge-eufy-security/eufy-security-client library in version ', libVersion);
238
231
  // Log the final configuration object for debugging purposes
239
- utils_1.log.debug('The config is:', this.config);
232
+ log.debug('The config is:', this.config);
240
233
  const eufyConfig = {
241
234
  username: this.config.username,
242
235
  password: this.config.password,
@@ -249,7 +242,7 @@ class EufySecurityPlatform {
249
242
  enableEmbeddedPKCS1Support: this.config.enableEmbeddedPKCS1Support,
250
243
  eventDurationSeconds: 10,
251
244
  logging: {
252
- level: (this.config.enableDetailedLogging) ? eufy_security_client_1.LogLevel.Debug : eufy_security_client_1.LogLevel.Info,
245
+ level: (this.config.enableDetailedLogging) ? LogLevel.Debug : LogLevel.Info,
253
246
  },
254
247
  };
255
248
  this.api.on("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */, async () => {
@@ -258,33 +251,36 @@ class EufySecurityPlatform {
258
251
  this.api.on("shutdown" /* APIEvent.SHUTDOWN */, async () => {
259
252
  await this.pluginShutdown();
260
253
  });
261
- utils_1.log.debug('Finished booting!');
254
+ log.debug('Finished booting!');
262
255
  }
263
256
  async pluginSetup(eufyConfig) {
264
257
  try {
265
- this.eufyClient = await eufy_security_client_1.EufySecurity.initialize(eufyConfig, (this.config.enableDetailedLogging) ? utils_1.tsLogger : undefined);
258
+ this.eufyClient = await EufySecurity.initialize(eufyConfig, (this.config.enableDetailedLogging) ? tsLogger : undefined);
259
+ // Each camera adds listeners (livestream, talkback) on top of the base ones.
260
+ // Raise limit to prevent MaxListenersExceededWarning in Node 22+.
261
+ this.eufyClient.setMaxListeners(30);
266
262
  this.eufyClient.on('station added', this.stationAdded.bind(this));
267
263
  this.eufyClient.on('station removed', this.stationRemoved.bind(this));
268
264
  this.eufyClient.on('device added', this.deviceAdded.bind(this));
269
265
  this.eufyClient.on('device removed', this.deviceRemoved.bind(this));
270
266
  this.eufyClient.on('push connect', () => {
271
- utils_1.log.debug('Push Connected!');
267
+ log.debug('Push Connected!');
272
268
  });
273
269
  this.eufyClient.on('push close', () => {
274
- utils_1.log.debug('Push Closed!');
270
+ log.debug('Push Closed!');
275
271
  });
276
272
  this.eufyClient.on('connect', () => {
277
- utils_1.log.debug('Connected!');
273
+ log.debug('Connected!');
278
274
  });
279
275
  this.eufyClient.on('close', () => {
280
- utils_1.log.debug('Closed!');
276
+ log.debug('Closed!');
281
277
  });
282
278
  this.eufyClient.on('connection error', async (error) => {
283
- utils_1.log.debug(`Error: ${error}`);
279
+ log.debug(`Error: ${error}`);
284
280
  await this.pluginShutdown();
285
281
  });
286
282
  this.eufyClient.once('captcha request', async () => {
287
- utils_1.log.error(`
283
+ log.error(`
288
284
  ***************************
289
285
  ***** WARNING MESSAGE *****
290
286
  ***************************
@@ -293,13 +289,13 @@ class EufySecurityPlatform {
293
289
  Please abstain from any activities until this period elapses...
294
290
  Should your issue persist beyond this timeframe, you may need to consider setting up a new account.
295
291
  For more detailed instructions, please consult:
296
- https://github.com/homebridge-eufy-security/plugin/wiki/Create-a-dedicated-admin-account-for-Homebridge-Eufy-Security-Plugin
292
+ https://github.com/homebridge-plugins/homebridge-eufy-security/wiki/Create-a-dedicated-admin-account-for-Homebridge-Eufy-Security-Plugin
297
293
  ***************************
298
294
  `);
299
295
  await this.pluginShutdown();
300
296
  });
301
297
  this.eufyClient.on('tfa request', async () => {
302
- utils_1.log.error(`
298
+ log.error(`
303
299
  ***************************
304
300
  ***** WARNING MESSAGE *****
305
301
  ***************************
@@ -308,28 +304,29 @@ class EufySecurityPlatform {
308
304
  Kindly refrain from making any further attempts during this period...
309
305
  If your concern remains unresolved after 24 hours, you may need to consider creating a new account.
310
306
  For additional information, refer to:
311
- https://github.com/homebridge-eufy-security/plugin/wiki/Create-a-dedicated-admin-account-for-Homebridge-Eufy-Security-Plugin
307
+ https://github.com/homebridge-plugins/homebridge-eufy-security/wiki/Create-a-dedicated-admin-account-for-Homebridge-Eufy-Security-Plugin
312
308
  ***************************
313
309
  `);
314
310
  await this.pluginShutdown();
315
311
  });
316
312
  }
317
313
  catch (e) {
318
- utils_1.log.error(`Error while setup : ${e}`);
319
- utils_1.log.error('Not connected can\'t continue!');
314
+ log.error(`Error while setup : ${e}`);
315
+ log.error('Not connected can\'t continue!');
320
316
  return;
321
317
  }
322
318
  try {
323
319
  await this.eufyClient.connect();
324
- utils_1.log.debug('EufyClient connected ' + this.eufyClient.isConnected());
320
+ log.debug('EufyClient connected ' + this.eufyClient.isConnected());
325
321
  }
326
322
  catch (e) {
327
- utils_1.log.error(`Error authenticating Eufy: ${e}`);
323
+ log.error(`Error authenticating Eufy: ${e}`);
328
324
  }
329
325
  if (!this.eufyClient.isConnected()) {
330
- utils_1.log.error('Not connected can\'t continue!');
326
+ log.error('Not connected can\'t continue!');
331
327
  return;
332
328
  }
329
+ log.info('Connected to Eufy. Discovering stations and devices... This may take up to 45 seconds.');
333
330
  // give the connection 45 seconds to discover all devices
334
331
  // then process pending stations and devices, and clean old accessories after that
335
332
  this.cleanCachedAccessoriesTimeout = setTimeout(async () => {
@@ -338,10 +335,10 @@ class EufySecurityPlatform {
338
335
  }, 45 * 1000);
339
336
  if (this.config.CameraMaxLivestreamDuration > 86400) {
340
337
  this.config.CameraMaxLivestreamDuration = 86400;
341
- utils_1.log.warn('Your maximum livestream duration value is too large. Since this can cause problems it was reset to 86400 seconds (1 day maximum).');
338
+ log.warn('Your maximum livestream duration value is too large. Since this can cause problems it was reset to 86400 seconds (1 day maximum).');
342
339
  }
343
340
  this.eufyClient.setCameraMaxLivestreamDuration(this.config.CameraMaxLivestreamDuration);
344
- utils_1.log.debug(`CameraMaxLivestreamDuration: ${this.eufyClient.getCameraMaxLivestreamDuration()}`);
341
+ log.debug(`CameraMaxLivestreamDuration: ${this.eufyClient.getCameraMaxLivestreamDuration()}`);
345
342
  }
346
343
  /**
347
344
  * Generates a UUID based on the given identifier and station flag.
@@ -353,28 +350,11 @@ class EufySecurityPlatform {
353
350
  // Add prefix 's_' if it's a station identifier, otherwise, no prefix.
354
351
  const prefix = isStation ? 's1_' : 'd1_';
355
352
  // Generate UUID based on the prefix + identifier.
356
- return utils_1.HAP.uuid.generate(prefix + identifier);
353
+ return HAP.uuid.generate(prefix + identifier);
357
354
  }
358
355
  async delay(ms) {
359
356
  return new Promise(resolve => setTimeout(resolve, ms));
360
357
  }
361
- /**
362
- * Checks if a device type is supported by the plugin.
363
- * A device is considered supported if it matches at least one handler type:
364
- * - Motion Sensor
365
- * - Entry Sensor
366
- * - Lock
367
- * - Camera
368
- *
369
- * @param deviceType The device type to check
370
- * @returns true if the device type is supported, false otherwise
371
- */
372
- isSupportedDevice(deviceType) {
373
- return (eufy_security_client_1.Device.isMotionSensor(deviceType) ||
374
- eufy_security_client_1.Device.isEntrySensor(deviceType) ||
375
- eufy_security_client_1.Device.isLock(deviceType) ||
376
- eufy_security_client_1.Device.isCamera(deviceType));
377
- }
378
358
  /**
379
359
  * Defines an accessory for a device or station.
380
360
  *
@@ -392,7 +372,7 @@ class EufySecurityPlatform {
392
372
  this.accessories.splice(this.accessories.indexOf(cachedAccessory), 1);
393
373
  }
394
374
  // Determine if the device is a camera
395
- const isCamera = (deviceContainer.eufyDevice instanceof eufy_security_client_1.Device)
375
+ const isCamera = (deviceContainer.eufyDevice instanceof Device)
396
376
  ? deviceContainer.eufyDevice.isCamera()
397
377
  : false;
398
378
  // Create a new accessory if not cached, otherwise use the cached one
@@ -426,7 +406,7 @@ class EufySecurityPlatform {
426
406
  // Remove station or device accessories created prior to plugin upgrade,
427
407
  // which may have been subject to removal due to newly introduced logic.
428
408
  if (isExist) {
429
- this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
409
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
430
410
  }
431
411
  throw error;
432
412
  }
@@ -437,100 +417,125 @@ class EufySecurityPlatform {
437
417
  // Update or register the accessory with the platform
438
418
  if (isExist) {
439
419
  this.api.updatePlatformAccessories([accessory]);
440
- utils_1.log.info(`Updating existing accessory: ${accessory.displayName}`);
420
+ log.info(`Updating existing accessory: ${accessory.displayName}`);
441
421
  }
442
422
  else {
443
- this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
444
- utils_1.log.info(`Registering new accessory: ${accessory.displayName}`);
423
+ this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
424
+ log.info(`Registering new accessory: ${accessory.displayName}`);
445
425
  }
446
426
  }
447
427
  catch (error) {
448
428
  // Log any errors that occur during accessory addition or update
449
- utils_1.log.error(`Error in ${isStation ? 'stationAdded' : 'deviceAdded'}:`, error);
429
+ log.error(`Error in ${isStation ? 'stationAdded' : 'deviceAdded'}:`, error);
450
430
  }
451
431
  }
452
432
  async stationAdded(station) {
453
433
  try {
454
434
  if (this.config.ignoreStations.includes(station.getSerial())) {
455
- utils_1.log.debug(`${station.getName()}: Station ignored`);
435
+ log.debug(`${station.getName()}: Station ignored`);
456
436
  return;
457
437
  }
458
438
  const rawStation = station.getRawStation();
459
- if (rawStation.member.member_type !== eufy_security_client_1.UserType.ADMIN) {
439
+ if (rawStation.member.member_type !== UserType.ADMIN) {
460
440
  await this.pluginShutdown();
461
- utils_1.log.error(`
441
+ log.error(`
462
442
  #########################
463
443
  ######### ERROR #########
464
444
  #########################
465
445
  You're not using a guest admin account with this plugin! You must use a guest admin account!
466
446
  Please look here for more details:
467
- https://github.com/homebridge-eufy-security/plugin/wiki/Create-a-dedicated-admin-account-for-Homebridge-Eufy-Security-Plugin
447
+ https://github.com/homebridge-plugins/homebridge-eufy-security/wiki/Create-a-dedicated-admin-account-for-Homebridge-Eufy-Security-Plugin
468
448
  #########################
469
449
  `);
470
450
  return;
471
451
  }
472
452
  // Store station for batch processing later
473
453
  this.pendingStations.push(station);
474
- utils_1.log.debug(`${station.getName()}: Station queued for processing`);
454
+ log.debug(`${station.getName()}: Station queued for processing`);
475
455
  }
476
456
  catch (error) {
477
- utils_1.log.error(`Error in stationAdded:, ${error}`);
457
+ log.error(`Error in stationAdded:, ${error}`);
478
458
  }
479
459
  }
480
460
  async deviceAdded(device) {
481
461
  try {
482
462
  if (this.config.ignoreDevices.includes(device.getSerial())) {
483
- utils_1.log.debug(`${device.getName()}: Device ignored`);
463
+ log.debug(`${device.getName()}: Device ignored`);
484
464
  return;
485
465
  }
486
466
  // Check if the device is a keypad and ignore it from the start
487
467
  const deviceType = device.getDeviceType();
488
- if (eufy_security_client_1.Device.isKeyPad(deviceType)) {
489
- utils_1.log.warn(`${device.getName()}: The keypad is ignored as it serves no purpose in this plugin. You can ignore this message.`);
468
+ if (Device.isKeyPad(deviceType)) {
469
+ log.warn(`${device.getName()}: The keypad is ignored as it serves no purpose in this plugin. You can ignore this message.`);
490
470
  return;
491
471
  }
492
472
  // Store device for batch processing later
493
473
  this.pendingDevices.push(device);
494
- utils_1.log.debug(`${device.getName()}: Device queued for processing`);
474
+ log.debug(`${device.getName()}: Device queued for processing`);
495
475
  }
496
476
  catch (error) {
497
- utils_1.log.error(`Error in deviceAdded: ${error}`);
477
+ log.error(`Error in deviceAdded: ${error}`);
498
478
  }
499
479
  }
500
480
  async stationRemoved(station) {
501
481
  const serial = station.getSerial();
502
- utils_1.log.debug(`A device has been removed: ${serial}`);
482
+ log.debug(`A device has been removed: ${serial}`);
503
483
  }
504
484
  async deviceRemoved(device) {
505
485
  const serial = device.getSerial();
506
- utils_1.log.debug(`A device has been removed: ${serial}`);
486
+ log.debug(`A device has been removed: ${serial}`);
507
487
  }
508
488
  /**
509
489
  * Processes pending stations and devices in batch.
510
490
  * Only creates station entities if:
511
491
  * 1. It's a real HomeBase (DeviceType.STATION) OR
512
- * 2. It has at least one supported device attached
492
+ * 2. It has at least one device attached
513
493
  *
514
- * Devices are only created if their type is supported.
494
+ * All discovered devices are processed since they are already verified by bropat/eufy-security-client.
515
495
  */
516
496
  async processPendingDevices() {
517
- utils_1.log.debug(`Processing ${this.pendingStations.length} stations and ${this.pendingDevices.length} devices`);
518
- // Build set of stations that have at least one supported device
519
- const stationsWithSupportedDevices = new Set();
497
+ log.debug(`[PROCESSING START] Processing ${this.pendingStations.length} stations and ${this.pendingDevices.length} devices`);
498
+ if (this.pendingStations.length === 0 || this.pendingDevices.length === 0) {
499
+ log.warn(`[DISCOVERY WARNING] Discovery finished with ${this.pendingStations.length} station(s) and ${this.pendingDevices.length} devices(s). ` +
500
+ 'If this is unexpected, please verify your Eufy account has devices and the credentials used are for a guest admin account.');
501
+ }
502
+ // Build set of stations that have at least one device
503
+ const stationsWithDevices = new Set();
504
+ // Create all queued devices (they are already verified by bropat/eufy-security-client)
505
+ log.debug(`[DEVICES PROCESSING] Starting to process ${this.pendingDevices.length} devices`);
520
506
  for (const device of this.pendingDevices) {
521
- if (this.isSupportedDevice(device.getDeviceType())) {
522
- stationsWithSupportedDevices.add(device.getStationSerial());
507
+ stationsWithDevices.add(device.getStationSerial());
508
+ try {
509
+ const deviceType = device.getDeviceType();
510
+ const deviceContainer = {
511
+ deviceIdentifier: {
512
+ uniqueId: device.getSerial(),
513
+ displayName: 'DEVICE ' + device.getName().replace(/[^a-zA-Z0-9]/g, ''),
514
+ type: deviceType,
515
+ },
516
+ eufyDevice: device,
517
+ };
518
+ log.debug(`[DEVICE] Processing: ${deviceContainer.deviceIdentifier.displayName}`);
519
+ await this.addOrUpdateAccessory(deviceContainer, false);
520
+ log.debug(`[DEVICE] Completed: ${deviceContainer.deviceIdentifier.displayName}`);
521
+ }
522
+ catch (error) {
523
+ log.error(`[DEVICE ERROR] Error processing device "${device.getName()}": ${error}`);
523
524
  }
524
525
  }
526
+ log.debug(`[DEVICES COMPLETE] All ${this.pendingDevices.length} devices processed`);
525
527
  // Create queued stations that should be created
528
+ log.debug(`[STATIONS PROCESSING] Starting to process ${this.pendingStations.length} stations`);
529
+ let stationsSkipped = 0;
526
530
  for (const station of this.pendingStations) {
527
531
  const stationType = station.getDeviceType();
528
532
  const stationSerial = station.getSerial();
529
- // Create if: it's a real HomeBase OR it has supported devices
530
- const shouldCreate = stationType === eufy_security_client_1.DeviceType.STATION ||
531
- stationsWithSupportedDevices.has(stationSerial);
533
+ // Create if: it's a real HomeBase OR it has devices
534
+ const shouldCreate = stationType === DeviceType.STATION ||
535
+ stationsWithDevices.has(stationSerial);
532
536
  if (!shouldCreate) {
533
- utils_1.log.warn(`Station "${station.getName()}" has no supported devices and will be skipped`);
537
+ stationsSkipped++;
538
+ log.debug(`[STATION SKIP] "${station.getName()}" has no devices and will be skipped`);
534
539
  continue;
535
540
  }
536
541
  try {
@@ -542,43 +547,19 @@ class EufySecurityPlatform {
542
547
  },
543
548
  eufyDevice: station,
544
549
  };
545
- await this.delay(settings_1.STATION_INIT_DELAY);
546
- utils_1.log.debug(`${deviceContainer.deviceIdentifier.displayName} pre-caching complete`);
550
+ log.debug(`[STATION] Processing: ${deviceContainer.deviceIdentifier.displayName}`);
547
551
  await this.addOrUpdateAccessory(deviceContainer, true);
552
+ log.debug(`[STATION] Completed: ${deviceContainer.deviceIdentifier.displayName}`);
548
553
  }
549
554
  catch (error) {
550
- utils_1.log.error(`Error processing station "${station.getName()}": ${error}`);
551
- }
552
- }
553
- // Create queued devices that are supported
554
- for (const device of this.pendingDevices) {
555
- const deviceType = device.getDeviceType();
556
- // Skip unsupported devices
557
- if (!this.isSupportedDevice(deviceType)) {
558
- utils_1.log.debug(`${device.getName()}: Device type ${deviceType} not supported, skipping`);
559
- continue;
560
- }
561
- try {
562
- const deviceContainer = {
563
- deviceIdentifier: {
564
- uniqueId: device.getSerial(),
565
- displayName: 'DEVICE ' + device.getName().replace(/[^a-zA-Z0-9]/g, ''),
566
- type: deviceType,
567
- },
568
- eufyDevice: device,
569
- };
570
- await this.delay(settings_1.DEVICE_INIT_DELAY);
571
- utils_1.log.debug(`${deviceContainer.deviceIdentifier.displayName} pre-caching complete`);
572
- await this.addOrUpdateAccessory(deviceContainer, false);
573
- }
574
- catch (error) {
575
- utils_1.log.error(`Error processing device "${device.getName()}": ${error}`);
555
+ log.error(`[STATION ERROR] Error processing station "${station.getName()}": ${error}`);
576
556
  }
577
557
  }
558
+ log.debug(`[STATIONS COMPLETE] ${this.pendingStations.length - stationsSkipped} stations created, ${stationsSkipped} skipped`);
578
559
  // Clear pending queues
579
560
  this.pendingStations = [];
580
561
  this.pendingDevices = [];
581
- utils_1.log.debug('Finished processing pending stations and devices');
562
+ log.info(`[PROCESSING COMPLETE] All pending devices and stations processed`);
582
563
  }
583
564
  async pluginShutdown() {
584
565
  // Ensure a single shutdown to prevent corruption of the persistent file.
@@ -594,10 +575,10 @@ class EufySecurityPlatform {
594
575
  if (this.eufyClient.isConnected()) {
595
576
  this.eufyClient.close();
596
577
  }
597
- utils_1.log.info('Finished shutdown!');
578
+ log.info('Finished shutdown!');
598
579
  }
599
580
  catch (e) {
600
- utils_1.log.error(`Error while shutdown: ${e}`);
581
+ log.error(`Error while shutdown: ${e}`);
601
582
  }
602
583
  }
603
584
  /**
@@ -605,68 +586,67 @@ class EufySecurityPlatform {
605
586
  * It should be used to setup event handlers for characteristics and update respective values.
606
587
  */
607
588
  configureAccessory(accessory) {
608
- utils_1.log.debug(`Loading accessory from cache: ${accessory.displayName}`);
589
+ log.debug(`Loading accessory from cache: ${accessory.displayName}`);
609
590
  // add the restored accessory to the accessories cache so we can track if it has already been registered
610
591
  this.accessories.push(accessory);
611
592
  }
612
593
  cleanCachedAccessories() {
613
594
  if (this.config.cleanCache) {
614
- utils_1.log.debug('Looking for old cached accessories that seem to be outdated...');
595
+ log.debug('Looking for old cached accessories that seem to be outdated...');
615
596
  let num = 0;
616
597
  const staleAccessories = this.accessories.filter((item) => {
617
598
  return this.activeAccessoryIds.indexOf(item.UUID) === -1;
618
599
  });
619
600
  staleAccessories.forEach((staleAccessory) => {
620
- utils_1.log.info(`Removing cached accessory ${staleAccessory.UUID} ${staleAccessory.displayName}`);
601
+ log.info(`Removing cached accessory ${staleAccessory.UUID} ${staleAccessory.displayName}`);
621
602
  num++;
622
- this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [staleAccessory]);
603
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [staleAccessory]);
623
604
  });
624
605
  if (num > 0) {
625
- utils_1.log.info('Removed ' + num + ' cached accessories');
606
+ log.info('Removed ' + num + ' cached accessories');
626
607
  }
627
608
  else {
628
- utils_1.log.info('No outdated cached accessories found.');
609
+ log.info('No outdated cached accessories found.');
629
610
  }
630
611
  }
631
612
  }
632
613
  register_station(accessory, container) {
633
- utils_1.log.debug(accessory.displayName + ' UUID:' + accessory.UUID);
614
+ log.debug(accessory.displayName + ' UUID:' + accessory.UUID);
634
615
  const type = container.deviceIdentifier.type;
635
616
  const station = container.eufyDevice;
636
- if (type !== eufy_security_client_1.DeviceType.STATION) {
617
+ if (type !== DeviceType.STATION) {
637
618
  // Standalone Lock or Doorbell doesn't have Security Control
638
- if (eufy_security_client_1.Device.isDoorbell(type) || eufy_security_client_1.Device.isLock(type)) {
619
+ if (Device.isDoorbell(type) || Device.isLock(type)) {
639
620
  throw new Error(`looks station but it's not could imply some errors! Type: ${type}. You can ignore this message.`);
640
621
  }
641
622
  }
642
623
  if (this.config.autoSyncStation) {
643
- new AutoSyncStationAccessory_1.AutoSyncStationAccessory(this, accessory, station);
624
+ new AutoSyncStationAccessory(this, accessory, station);
644
625
  }
645
626
  else {
646
- new StationAccessory_1.StationAccessory(this, accessory, station);
627
+ new StationAccessory(this, accessory, station);
647
628
  }
648
629
  }
649
630
  register_device(accessory, container) {
650
- utils_1.log.debug(accessory.displayName + ' UUID:' + accessory.UUID);
631
+ log.debug(accessory.displayName + ' UUID:' + accessory.UUID);
651
632
  const device = container.eufyDevice;
652
633
  const type = container.deviceIdentifier.type;
653
- if (eufy_security_client_1.Device.isMotionSensor(type)) {
654
- utils_1.log.debug(accessory.displayName + ' isMotionSensor!');
655
- new MotionSensorAccessory_1.MotionSensorAccessory(this, accessory, device);
634
+ if (Device.isMotionSensor(type)) {
635
+ log.debug(accessory.displayName + ' isMotionSensor!');
636
+ new MotionSensorAccessory(this, accessory, device);
656
637
  }
657
- if (eufy_security_client_1.Device.isEntrySensor(type)) {
658
- utils_1.log.debug(accessory.displayName + ' isEntrySensor!');
659
- new EntrySensorAccessory_1.EntrySensorAccessory(this, accessory, device);
638
+ if (Device.isEntrySensor(type)) {
639
+ log.debug(accessory.displayName + ' isEntrySensor!');
640
+ new EntrySensorAccessory(this, accessory, device);
660
641
  }
661
- if (eufy_security_client_1.Device.isLock(type)) {
662
- utils_1.log.debug(accessory.displayName + ' isLock!');
663
- new LockAccessory_1.LockAccessory(this, accessory, device);
642
+ if (Device.isLock(type)) {
643
+ log.debug(accessory.displayName + ' isLock!');
644
+ new LockAccessory(this, accessory, device);
664
645
  }
665
- if (eufy_security_client_1.Device.isCamera(type)) {
666
- utils_1.log.debug(accessory.displayName + ' isCamera!');
667
- new CameraAccessory_1.CameraAccessory(this, accessory, device);
646
+ if (Device.isCamera(type)) {
647
+ log.debug(accessory.displayName + ' isCamera!');
648
+ new CameraAccessory(this, accessory, device);
668
649
  }
669
650
  }
670
651
  }
671
- exports.EufySecurityPlatform = EufySecurityPlatform;
672
652
  //# sourceMappingURL=platform.js.map