iobroker.eusec 2.0.2 → 3.0.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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
3
+ Copyright (c) 2025-2026 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
4
4
  Copyright (c) 2020-2024 bropat <patrick.broetto@gmail.com>
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
package/README.md CHANGED
@@ -13,21 +13,21 @@
13
13
 
14
14
  [![NPM](https://nodei.co/npm/iobroker.eusec.png?downloads=true)](https://nodei.co/npm/iobroker.eusec/)
15
15
 
16
- This is an [ioBroker](https://www.iobroker.net) adapter that uses the [eufy-security-client](https://github.com/bropat/eufy-security-client) library to comunicate with Eufy devices.
16
+ This is an [ioBroker](https://www.iobroker.net) adapter that uses the [eufy-security-client](https://github.com/bropat/eufy-security-client) library to communicate with Eufy devices.
17
17
 
18
18
  **This project is not affiliated with Anker and Eufy (Eufy Security). It is a personal project that is maintained in spare time.**
19
19
 
20
20
  ## Description
21
21
 
22
- This adapter allows to control [Eufy security devices](https://us.eufylife.com/collections/security) by connecting to the Eufy cloud servers and local/remote stations.
22
+ This adapter allows you to control [Eufy security devices](https://us.eufylife.com/collections/security) by connecting to the Eufy cloud servers and local/remote stations.
23
23
 
24
24
  You need to provide your Cloud login credentials. The adapter connects to your cloud account and polls for all device data via HTTPS. Now a local or remote P2P connection to the Eufy stations/devices is also supported. However, a connection to the Eufy Cloud is always a prerequisite.
25
25
 
26
- One Adapter instance will show all devices from one Eufy Cloud account and allows to control them.
26
+ One Adapter instance will show all devices from one Eufy Cloud account and allows you to control them.
27
27
 
28
28
  ## Documentation
29
29
 
30
- Checkout the documentation [here](https://iobroker-community-adapters.github.io/ioBroker.eusec/).
30
+ Check out the documentation [here](https://iobroker-community-adapters.github.io/ioBroker.eusec/).
31
31
 
32
32
  ## Known working devices
33
33
 
@@ -37,13 +37,31 @@ Information about supported devices can be found [here](https://github.com/bropa
37
37
 
38
38
  This adapter would not have been possible without the great work of Patrick Broetto (brobat) <https://github.com/bropat>, who created previous releases of this adapter.
39
39
 
40
+ ## IMPORTANT information when upgrading to node.js 22
41
+
42
+ Adapter 2.0.3 and newer support node.js 22. Prior node.js versions require a special setup which became invalid with node.js 22. So when upgrading node.js from any version lower than 22.x.x to node.js 22, please follow these steps:
43
+
44
+ - If you have node.js < 22 and adapter < 2.0.0 installed, please update node.js first and install adapter 2.0.3 afterwards.
45
+ - If you have adapter >= 2.0.0 installed with any node release prior to 22, you MUST reinstall the adapter. A detailed description (in German) is available at our forum (https://forum.iobroker.net/topic/82651/test-adapter-eusec-v2-0-x)
46
+
40
47
  ## Changelog
41
48
 
42
49
  <!--
43
50
  Placeholder for the next version (at the beginning of the line):
44
51
  ### **WORK IN PROGRESS**
45
52
  -->
46
- ### 2.0.2 (2025-10-26)
53
+ ### 3.0.2 (2026-09-02)
54
+ - (copilot) Adapter requires node.js >= 22 now
55
+ - (copilot) Adapter requires admin >= 7.7.22 now
56
+ - (@GermanBluefox) Refactoring
57
+ - (@GermanBluefox) Fixed login failing with `Get passport profile - Response code not ok` since the eufy cloud started answering successful requests with code 200 instead of 0 (see [bropat/eufy-security-client#975](https://github.com/bropat/eufy-security-client/pull/975))
58
+ - (typhosj) Fixed livestreaming being broken when go2rtc is configured to use an API port other than 1984, and the eufy livestream is now stopped when streaming into go2rtc fails ([#151](https://github.com/iobroker-community-adapters/ioBroker.eusec/pull/151), [#160](https://github.com/iobroker-community-adapters/ioBroker.eusec/issues/160))
59
+ - (typhosj) go2rtc is now supervised and restarted if it terminates unexpectedly, the livestream states are cleared when a station disconnects, and a warning is logged when a camera streams at "Auto" quality ([#152](https://github.com/iobroker-community-adapters/ioBroker.eusec/pull/152))
60
+ - (@GermanBluefox) The warning about the "Auto" streaming quality now also covers devices where "Auto" is not value 0 (eufyCam 3, Professional models and battery doorbells)
61
+ - (@GermanBluefox) Removed the obsolete CVE-2023-46809 workaround for node.js 20 from the adapter startup
62
+ - (@GermanBluefox) Pinned eufy-security-client to 4.1.1-1 and removed the unused packages mime and @types/ffmpeg-static
63
+
64
+ ### 2.0.3 (2025-10-26)
47
65
  - (mcm1957) Remove fix for CVE-2023-46809 for node.js 22 and newer
48
66
 
49
67
  ### 2.0.0 (2025-10-26)
@@ -61,16 +79,13 @@ This adapter would not have been possible without the great work of Patrick Broe
61
79
 
62
80
  * (bropat) Fixed issue #440
63
81
 
64
- ### 1.3.1 (2024-09-08)
65
-
66
- * (bropat) Fixed issue #436
67
- * (bropat) Fixed issue #439
82
+ [Older changelogs can be found there](CHANGELOG_OLD.md)
68
83
 
69
84
  ## License
70
85
 
71
86
  MIT License
72
87
 
73
- Copyright (c) 2025 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
88
+ Copyright (c) 2025-2026 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
74
89
  Copyright (c) 2020-2024 bropat <patrick.broetto@gmail.com>
75
90
 
76
91
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var eufyApiCompat_exports = {};
20
+ __export(eufyApiCompat_exports, {
21
+ applyEufyApiCompatibility: () => applyEufyApiCompatibility,
22
+ normalizeSuccessCode: () => normalizeSuccessCode
23
+ });
24
+ module.exports = __toCommonJS(eufyApiCompat_exports);
25
+ var import_eufy_security_client = require("eufy-security-client");
26
+ const LEGACY_SUCCESS_CODE = import_eufy_security_client.ResponseErrorCode.CODE_OK;
27
+ const HTTP_SUCCESS_CODE = 200;
28
+ const normalizeSuccessCode = (data) => {
29
+ if (data === null || typeof data !== "object") {
30
+ return false;
31
+ }
32
+ const result = data;
33
+ if (result.code !== HTTP_SUCCESS_CODE) {
34
+ return false;
35
+ }
36
+ result.code = LEGACY_SUCCESS_CODE;
37
+ return true;
38
+ };
39
+ let patched = false;
40
+ const applyEufyApiCompatibility = (log) => {
41
+ if (patched) {
42
+ return;
43
+ }
44
+ patched = true;
45
+ const original = import_eufy_security_client.HTTPApi.prototype.request;
46
+ let reported = false;
47
+ import_eufy_security_client.HTTPApi.prototype.request = async function(request, withoutUrlPrefix) {
48
+ const response = await original.call(this, request, withoutUrlPrefix);
49
+ if (normalizeSuccessCode(response == null ? void 0 : response.data) && !reported) {
50
+ reported = true;
51
+ log(
52
+ "The Eufy API answers with the HTTP style code 200 where the legacy code 0 is expected. The adapter normalizes it - see bropat/eufy-security-client#975."
53
+ );
54
+ }
55
+ return response;
56
+ };
57
+ };
58
+ // Annotate the CommonJS export names for ESM import in node:
59
+ 0 && (module.exports = {
60
+ applyEufyApiCompatibility,
61
+ normalizeSuccessCode
62
+ });
63
+ //# sourceMappingURL=eufyApiCompat.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/eufyApiCompat.ts"],
4
+ "sourcesContent": ["/**\n * Compatibility shim for the Eufy Mega/v6 backend.\n *\n * Eufy started answering with the HTTP style code 200 in the JSON body of endpoints that used to\n * return the legacy application code 0. eufy-security-client accepts only 0\n * (`ResponseErrorCode.CODE_OK`) and therefore reports perfectly valid answers as failures:\n *\n * [http] [HTTPApi.getPassportProfile] Get passport profile - Response code not ok\n * [{\"code\":200,\"msg\":\"\",\"data\":{...}}]\n *\n * The login never completes after that, and the house, station and device lists stay empty.\n *\n * Upstream carries the fix in bropat/eufy-security-client#975, but development of that library has\n * ended (bropat/eufy-security-client#965), so it will most likely never be released. 21 of the 22\n * affected comparisons read `response.data` of the public `HTTPApi.request()`, so normalizing the\n * code in that single funnel repairs all of them at once.\n *\n * The 22nd is the static `HTTPApi.getApiBaseFromCloud()`, which calls got directly and talks to a\n * different host (extend.eufylife.com). It is deliberately left untouched: a failure there aborts\n * the login with an ApiBaseLoadError long before a profile is ever requested, which is not the\n * behaviour reported in the field.\n *\n * Remove this module once the adapter depends on a library version that accepts both codes.\n */\n\nimport { HTTPApi, ResponseErrorCode } from 'eufy-security-client';\nimport type { ApiResponse, HTTPApiRequest } from 'eufy-security-client';\n\n/** Legacy application success code of the Eufy API. */\nconst LEGACY_SUCCESS_CODE = ResponseErrorCode.CODE_OK;\n\n/** HTTP style success code the Mega/v6 backend returns instead. It is not a member of ResponseErrorCode. */\nconst HTTP_SUCCESS_CODE = 200;\n\n/**\n * Rewrites the HTTP style success code of a response body to the legacy one, in place. Only the\n * code is touched - the encrypted payload in `data` is passed through untouched.\n *\n * @param data The parsed body of an Eufy API response\n * @returns true if the code was rewritten, false if the body was left as it was\n */\nexport const normalizeSuccessCode = (data: unknown): boolean => {\n if (data === null || typeof data !== 'object') {\n return false;\n }\n const result = data as { code?: unknown };\n if (result.code !== HTTP_SUCCESS_CODE) {\n return false;\n }\n result.code = LEGACY_SUCCESS_CODE;\n return true;\n};\n\nlet patched = false;\n\n/**\n * Wraps HTTPApi.request() so every response body carries a success code the library understands.\n * Must run before EufySecurity.initialize(); applying it more than once is a no-op.\n *\n * @param log Called once, on the first response that actually needed the rewrite\n */\nexport const applyEufyApiCompatibility = (log: (message: string) => void): void => {\n if (patched) {\n return;\n }\n patched = true;\n\n const original = HTTPApi.prototype.request;\n let reported = false;\n\n HTTPApi.prototype.request = async function (\n request: HTTPApiRequest,\n withoutUrlPrefix?: boolean,\n ): Promise<ApiResponse> {\n const response = await original.call(this, request, withoutUrlPrefix);\n if (normalizeSuccessCode(response?.data) && !reported) {\n reported = true;\n log(\n 'The Eufy API answers with the HTTP style code 200 where the legacy code 0 is expected. The adapter normalizes it - see bropat/eufy-security-client#975.',\n );\n }\n return response;\n };\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,kCAA2C;AAI3C,MAAM,sBAAsB,8CAAkB;AAG9C,MAAM,oBAAoB;AASnB,MAAM,uBAAuB,CAAC,SAA2B;AAC5D,MAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;AAC3C,WAAO;AAAA,EACX;AACA,QAAM,SAAS;AACf,MAAI,OAAO,SAAS,mBAAmB;AACnC,WAAO;AAAA,EACX;AACA,SAAO,OAAO;AACd,SAAO;AACX;AAEA,IAAI,UAAU;AAQP,MAAM,4BAA4B,CAAC,QAAyC;AAC/E,MAAI,SAAS;AACT;AAAA,EACJ;AACA,YAAU;AAEV,QAAM,WAAW,oCAAQ,UAAU;AACnC,MAAI,WAAW;AAEf,sCAAQ,UAAU,UAAU,eACxB,SACA,kBACoB;AACpB,UAAM,WAAW,MAAM,SAAS,KAAK,MAAM,SAAS,gBAAgB;AACpE,QAAI,qBAAqB,qCAAU,IAAI,KAAK,CAAC,UAAU;AACnD,iBAAW;AACX;AAAA,QACI;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AACJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var go2rtc_exports = {};
20
+ __export(go2rtc_exports, {
21
+ isRegularStreamEnd: () => isRegularStreamEnd,
22
+ streamToGo2rtcFailed: () => streamToGo2rtcFailed
23
+ });
24
+ module.exports = __toCommonJS(go2rtc_exports);
25
+ const isRegularStreamEnd = (error) => {
26
+ var _a;
27
+ const body = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.body;
28
+ return typeof body === "string" && body.startsWith("EOF");
29
+ };
30
+ const streamToGo2rtcFailed = (results) => results.some((result) => result.status === "rejected" && !isRegularStreamEnd(result.reason));
31
+ // Annotate the CommonJS export names for ESM import in node:
32
+ 0 && (module.exports = {
33
+ isRegularStreamEnd,
34
+ streamToGo2rtcFailed
35
+ });
36
+ //# sourceMappingURL=go2rtc.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/go2rtc.ts"],
4
+ "sourcesContent": ["/**\n * Helpers around the go2rtc stream pipelines. Deliberately free of imports so they stay testable:\n * lib/utils.ts pulls in \\@iobroker/adapter-core and main.ts, which needs a running js-controller.\n */\n\n/**\n * go2rtc answers with \"EOF\" when a stream is torn down in the regular way (livestream stopped,\n * maximum duration reached). That is not a failure and must not trigger any error handling.\n *\n * @param error The rejection reason of a stream pipeline\n * @returns true if the stream simply ended instead of breaking\n */\nexport const isRegularStreamEnd = (error: unknown): boolean => {\n const body = (error as { response?: { body?: unknown } })?.response?.body;\n return typeof body === 'string' && body.startsWith('EOF');\n};\n\n/**\n * Tells whether at least one of the stream pipelines ended in an actual failure, so callers can\n * tear the livestream down instead of leaving the camera streaming into nothing.\n *\n * @param results The settled results returned by streamToGo2rtc()\n * @returns true if at least one pipeline broke\n */\nexport const streamToGo2rtcFailed = (results: Array<PromiseSettledResult<void>>): boolean =>\n results.some(result => result.status === 'rejected' && !isRegularStreamEnd(result.reason));\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYO,MAAM,qBAAqB,CAAC,UAA4B;AAZ/D;AAaI,QAAM,QAAQ,oCAA6C,aAA7C,mBAAuD;AACrE,SAAO,OAAO,SAAS,YAAY,KAAK,WAAW,KAAK;AAC5D;AASO,MAAM,uBAAuB,CAAC,YACjC,QAAQ,KAAK,YAAU,OAAO,WAAW,cAAc,CAAC,mBAAmB,OAAO,MAAM,CAAC;",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/interfaces.ts"],
4
- "sourcesContent": ["\r\n/*export interface AdapterConfig {\r\n username: string;\r\n password: string;\r\n pollingInterval: number;\r\n maxLivestreamDuration: number;\r\n eventDuration: number;\r\n verificationMethod: number;\r\n p2pConnectionType: string;\r\n acceptInvitations: boolean;\r\n alarmSoundDuration: number;\r\n go2rtc_api_port: number;\r\n go2rtc_rtsp_port: number;\r\n go2rtc_srtp_port: number;\r\n go2rtc_webrtc_port: number;\r\n go2rtc_rtsp_username: string;\r\n go2rtc_rtsp_password: string;\r\n hostname: string;\r\n https: boolean;\r\n}*/\r\n\r\nexport interface PersistentData {\r\n version: string;\r\n}\r\n\r\nexport interface IRoleMapping {\r\n [index: string]: string;\r\n}"],
4
+ "sourcesContent": ["/*export interface AdapterConfig {\n username: string;\n password: string;\n pollingInterval: number;\n maxLivestreamDuration: number;\n eventDuration: number;\n verificationMethod: number;\n p2pConnectionType: string;\n acceptInvitations: boolean;\n alarmSoundDuration: number;\n go2rtc_api_port: number;\n go2rtc_rtsp_port: number;\n go2rtc_srtp_port: number;\n go2rtc_webrtc_port: number;\n go2rtc_rtsp_username: string;\n go2rtc_rtsp_password: string;\n hostname: string;\n https: boolean;\n}*/\n\nexport interface PersistentData {\n version: string;\n}\n\nexport interface IRoleMapping {\n [index: string]: string;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/log.ts"],
4
- "sourcesContent": ["import { Logger } from \"ts-log\";\r\n\r\nexport class ioBrokerLogger implements Logger {\r\n\r\n private readonly log: ioBroker.Logger;\r\n\r\n public constructor(log: ioBroker.Logger) {\r\n this.log = log;\r\n }\r\n\r\n private _getStack(): any {\r\n const _prepareStackTrace = Error.prepareStackTrace;\r\n Error.prepareStackTrace = (_, stack) => stack;\r\n const stack = new Error().stack?.slice(3);\r\n Error.prepareStackTrace = _prepareStackTrace;\r\n return stack;\r\n }\r\n\r\n private _getMessage(message?: string, hideTag = false, optionalParams?: any[]): string {\r\n const msg = message ? message : \"\";\r\n const stack = this._getStack();\r\n const typeName = stack[0].getTypeName() !== null ? stack[0].getTypeName() : \"\";\r\n const functionName = stack[0].getFunctionName() !== null ? `${stack[0].getFunctionName()}` : \"\";\r\n let tag = \"\";\r\n if (typeName !== \"\" && !hideTag) {\r\n tag = `[${typeName}`;\r\n if (functionName !== \"\") {\r\n tag = `${tag}.${functionName}] `;\r\n } else {\r\n tag = `${tag}] `;\r\n }\r\n }\r\n\r\n if (optionalParams && optionalParams.length > 0) {\r\n return `${tag}${msg} ${JSON.stringify(optionalParams)}`;\r\n }\r\n return `${tag}${msg}`;\r\n }\r\n\r\n public trace(message?: string, ...optionalParams: any[]): void {\r\n this.log.silly(this._getMessage(message, false, optionalParams));\r\n }\r\n\r\n public debug(message?: string, ...optionalParams: any[]): void {\r\n this.log.debug(this._getMessage(message, false, optionalParams));\r\n }\r\n\r\n public info(message?: string, ...optionalParams: any[]): void {\r\n this.log.info(this._getMessage(message, true, optionalParams));\r\n }\r\n\r\n public warn(message?: string, ...optionalParams: any[]): void {\r\n this.log.warn(this._getMessage(message, true, optionalParams));\r\n }\r\n\r\n public error(message?: string, ...optionalParams: any[]): void {\r\n this.log.error(this._getMessage(message, true, optionalParams));\r\n }\r\n\r\n}"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,eAAiC;AAAA,EAEzB;AAAA,EAEV,YAAY,KAAsB;AACrC,SAAK,MAAM;AAAA,EACf;AAAA,EAEQ,YAAiB;AAV7B;AAWQ,UAAM,qBAAqB,MAAM;AACjC,UAAM,oBAAoB,CAAC,GAAGA,WAAUA;AACxC,UAAM,SAAQ,SAAI,MAAM,EAAE,UAAZ,mBAAmB,MAAM;AACvC,UAAM,oBAAoB;AAC1B,WAAO;AAAA,EACX;AAAA,EAEQ,YAAY,SAAkB,UAAU,OAAO,gBAAgC;AACnF,UAAM,MAAM,UAAU,UAAU;AAChC,UAAM,QAAQ,KAAK,UAAU;AAC7B,UAAM,WAAW,MAAM,CAAC,EAAE,YAAY,MAAM,OAAO,MAAM,CAAC,EAAE,YAAY,IAAI;AAC5E,UAAM,eAAe,MAAM,CAAC,EAAE,gBAAgB,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,gBAAgB,CAAC,KAAK;AAC7F,QAAI,MAAM;AACV,QAAI,aAAa,MAAM,CAAC,SAAS;AAC7B,YAAM,IAAI,QAAQ;AAClB,UAAI,iBAAiB,IAAI;AACrB,cAAM,GAAG,GAAG,IAAI,YAAY;AAAA,MAChC,OAAO;AACH,cAAM,GAAG,GAAG;AAAA,MAChB;AAAA,IACJ;AAEA,QAAI,kBAAkB,eAAe,SAAS,GAAG;AAC7C,aAAO,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,UAAU,cAAc,CAAC;AAAA,IACzD;AACA,WAAO,GAAG,GAAG,GAAG,GAAG;AAAA,EACvB;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,OAAO,cAAc,CAAC;AAAA,EACnE;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,OAAO,cAAc,CAAC;AAAA,EACnE;AAAA,EAEO,KAAK,YAAqB,gBAA6B;AAC1D,SAAK,IAAI,KAAK,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EACjE;AAAA,EAEO,KAAK,YAAqB,gBAA6B;AAC1D,SAAK,IAAI,KAAK,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EACjE;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EAClE;AAEJ;",
4
+ "sourcesContent": ["import type { Logger } from 'ts-log';\n\nexport class ioBrokerLogger implements Logger {\n private readonly log: ioBroker.Logger;\n\n public constructor(log: ioBroker.Logger) {\n this.log = log;\n }\n\n private _getStack(): any {\n const _prepareStackTrace = Error.prepareStackTrace;\n Error.prepareStackTrace = (_, stack) => stack;\n const stack = new Error().stack?.slice(3);\n Error.prepareStackTrace = _prepareStackTrace;\n return stack;\n }\n\n private _getMessage(message?: string, hideTag = false, optionalParams?: any[]): string {\n const msg = message ? message : '';\n const stack = this._getStack();\n const typeName = stack[0].getTypeName() !== null ? stack[0].getTypeName() : '';\n const functionName = stack[0].getFunctionName() !== null ? `${stack[0].getFunctionName()}` : '';\n let tag = '';\n if (typeName !== '' && !hideTag) {\n tag = `[${typeName}`;\n if (functionName !== '') {\n tag = `${tag}.${functionName}] `;\n } else {\n tag = `${tag}] `;\n }\n }\n\n if (optionalParams && optionalParams.length > 0) {\n return `${tag}${msg} ${JSON.stringify(optionalParams)}`;\n }\n return `${tag}${msg}`;\n }\n\n public trace(message?: string, ...optionalParams: any[]): void {\n this.log.silly(this._getMessage(message, false, optionalParams));\n }\n\n public debug(message?: string, ...optionalParams: any[]): void {\n this.log.debug(this._getMessage(message, false, optionalParams));\n }\n\n public info(message?: string, ...optionalParams: any[]): void {\n this.log.info(this._getMessage(message, true, optionalParams));\n }\n\n public warn(message?: string, ...optionalParams: any[]): void {\n this.log.warn(this._getMessage(message, true, optionalParams));\n }\n\n public error(message?: string, ...optionalParams: any[]): void {\n this.log.error(this._getMessage(message, true, optionalParams));\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,eAAiC;AAAA,EACzB;AAAA,EAEV,YAAY,KAAsB;AACrC,SAAK,MAAM;AAAA,EACf;AAAA,EAEQ,YAAiB;AAT7B;AAUQ,UAAM,qBAAqB,MAAM;AACjC,UAAM,oBAAoB,CAAC,GAAGA,WAAUA;AACxC,UAAM,SAAQ,SAAI,MAAM,EAAE,UAAZ,mBAAmB,MAAM;AACvC,UAAM,oBAAoB;AAC1B,WAAO;AAAA,EACX;AAAA,EAEQ,YAAY,SAAkB,UAAU,OAAO,gBAAgC;AACnF,UAAM,MAAM,UAAU,UAAU;AAChC,UAAM,QAAQ,KAAK,UAAU;AAC7B,UAAM,WAAW,MAAM,CAAC,EAAE,YAAY,MAAM,OAAO,MAAM,CAAC,EAAE,YAAY,IAAI;AAC5E,UAAM,eAAe,MAAM,CAAC,EAAE,gBAAgB,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,gBAAgB,CAAC,KAAK;AAC7F,QAAI,MAAM;AACV,QAAI,aAAa,MAAM,CAAC,SAAS;AAC7B,YAAM,IAAI,QAAQ;AAClB,UAAI,iBAAiB,IAAI;AACrB,cAAM,GAAG,GAAG,IAAI,YAAY;AAAA,MAChC,OAAO;AACH,cAAM,GAAG,GAAG;AAAA,MAChB;AAAA,IACJ;AAEA,QAAI,kBAAkB,eAAe,SAAS,GAAG;AAC7C,aAAO,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,UAAU,cAAc,CAAC;AAAA,IACzD;AACA,WAAO,GAAG,GAAG,GAAG,GAAG;AAAA,EACvB;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,OAAO,cAAc,CAAC;AAAA,EACnE;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,OAAO,cAAc,CAAC;AAAA,EACnE;AAAA,EAEO,KAAK,YAAqB,gBAA6B;AAC1D,SAAK,IAAI,KAAK,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EACjE;AAAA,EAEO,KAAK,YAAqB,gBAA6B;AAC1D,SAAK,IAAI,KAAK,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EACjE;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EAClE;AACJ;",
6
6
  "names": ["stack"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/types.ts"],
4
- "sourcesContent": ["import { PropertyName } from \"eufy-security-client\";\r\n\r\nimport { IRoleMapping } from \"./interfaces\";\r\n\r\nexport const DataLocation = {\r\n LAST_EVENT: \"last_event\",\r\n}\r\n\r\nexport const STREAM_FILE_NAME_EXT = \".m3u8\";\r\nexport const IMAGE_FILE_JPEG_EXT = \".jpg\";\r\n\r\nexport const RoleMapping: IRoleMapping = {\r\n [PropertyName.Name]: \"info.name\",\r\n [PropertyName.StationMacAddress]: \"info.mac\",\r\n [PropertyName.StationLANIpAddress]: \"info.ip\",\r\n [PropertyName.DeviceState]: \"info.status\",\r\n [PropertyName.DeviceBattery]: \"value.battery\",\r\n [PropertyName.DeviceBatteryTemp]: \"value.temperature\",\r\n [PropertyName.DeviceMotionDetected]: \"sensor.motion\",\r\n [PropertyName.DevicePersonDetected]: \"sensor.motion\",\r\n [PropertyName.DeviceRinging]: \"sensor\",\r\n [PropertyName.DeviceCryingDetected]: \"sensor.noise\",\r\n [PropertyName.DeviceSoundDetected]: \"sensor.noise\",\r\n [PropertyName.DevicePetDetected]: \"sensor\",\r\n [PropertyName.DeviceSensorOpen]: \"sensor\",\r\n [PropertyName.DeviceBatteryLow]: \"indicator.lowbat\",\r\n [PropertyName.DeviceLockStatus]: \"info.status\",\r\n [PropertyName.DeviceDogLickDetected]: \"sensor\",\r\n [PropertyName.DeviceDogPoopDetected]: \"sensor\",\r\n [PropertyName.DeviceVehicleDetected]: \"sensor\",\r\n [PropertyName.DeviceRadarMotionDetected]: \"sensor.motion\",\r\n [PropertyName.DeviceStrangerPersonDetected]: \"sensor.motion\",\r\n [PropertyName.DeviceIdentityPersonDetected]: \"sensor.motion\",\r\n [PropertyName.DeviceChargingStatus]: \"info.status\",\r\n}\r\n\r\nexport const DeviceStateID = {\r\n /*LAST_EVENT_PIC_URL: \"last_event_pic_url\",\r\n LAST_EVENT_PIC_HTML: \"last_event_pic_html\",\r\n LAST_EVENT_VIDEO_URL: \"last_event_video_url\",*/\r\n LIVESTREAM: \"livestream\",\r\n START_STREAM: \"start_stream\",\r\n STOP_STREAM: \"stop_stream\",\r\n RTSP_STREAM_URL: \"rtsp_stream_url\",\r\n TRIGGER_ALARM_SOUND: \"trigger_alarm_sound\",\r\n RESET_ALARM_SOUND: \"reset_alarm_sound\",\r\n PICTURE_URL: \"picture_url\",\r\n PICTURE_HTML: \"picture_html\",\r\n LIVESTREAM_RTSP: \"livestream_rtsp\",\r\n PAN_LEFT: \"pan_left\",\r\n PAN_RIGHT: \"pan_right\",\r\n TILT_UP: \"tilt_up\",\r\n TILT_DOWN: \"titl_down\",\r\n ROTATE_360: \"rotate_360\",\r\n SET_DEFAULT_ANGLE: \"set_default_angle\",\r\n SET_PRIVACY_ANGLE: \"set_privacy_angle\",\r\n CALIBRATE: \"calibrate\",\r\n UNLOCK: \"unlock\",\r\n OPEN_BOX: \"open_box\",\r\n}\r\n\r\nexport const StationStateID = {\r\n REBOOT: \"reboot\",\r\n CONNECTION: \"connection\",\r\n TRIGGER_ALARM_SOUND: \"trigger_alarm_sound\",\r\n RESET_ALARM_SOUND: \"reset_alarm_sound\",\r\n}"],
4
+ "sourcesContent": ["import { PropertyName } from 'eufy-security-client';\n\nimport type { IRoleMapping } from './interfaces';\n\nexport const DataLocation = {\n LAST_EVENT: 'last_event',\n};\n\nexport const STREAM_FILE_NAME_EXT = '.m3u8';\nexport const IMAGE_FILE_JPEG_EXT = '.jpg';\n\nexport const RoleMapping: IRoleMapping = {\n [PropertyName.Name]: 'info.name',\n [PropertyName.StationMacAddress]: 'info.mac',\n [PropertyName.StationLANIpAddress]: 'info.ip',\n [PropertyName.DeviceState]: 'info.status',\n [PropertyName.DeviceBattery]: 'value.battery',\n [PropertyName.DeviceBatteryTemp]: 'value.temperature',\n [PropertyName.DeviceMotionDetected]: 'sensor.motion',\n [PropertyName.DevicePersonDetected]: 'sensor.motion',\n [PropertyName.DeviceRinging]: 'sensor',\n [PropertyName.DeviceCryingDetected]: 'sensor.noise',\n [PropertyName.DeviceSoundDetected]: 'sensor.noise',\n [PropertyName.DevicePetDetected]: 'sensor',\n [PropertyName.DeviceSensorOpen]: 'sensor',\n [PropertyName.DeviceBatteryLow]: 'indicator.lowbat',\n [PropertyName.DeviceLockStatus]: 'info.status',\n [PropertyName.DeviceDogLickDetected]: 'sensor',\n [PropertyName.DeviceDogPoopDetected]: 'sensor',\n [PropertyName.DeviceVehicleDetected]: 'sensor',\n [PropertyName.DeviceRadarMotionDetected]: 'sensor.motion',\n [PropertyName.DeviceStrangerPersonDetected]: 'sensor.motion',\n [PropertyName.DeviceIdentityPersonDetected]: 'sensor.motion',\n [PropertyName.DeviceChargingStatus]: 'info.status',\n};\n\nexport const DeviceStateID = {\n /*LAST_EVENT_PIC_URL: \"last_event_pic_url\",\n LAST_EVENT_PIC_HTML: \"last_event_pic_html\",\n LAST_EVENT_VIDEO_URL: \"last_event_video_url\",*/\n LIVESTREAM: 'livestream',\n START_STREAM: 'start_stream',\n STOP_STREAM: 'stop_stream',\n RTSP_STREAM_URL: 'rtsp_stream_url',\n TRIGGER_ALARM_SOUND: 'trigger_alarm_sound',\n RESET_ALARM_SOUND: 'reset_alarm_sound',\n PICTURE_URL: 'picture_url',\n PICTURE_HTML: 'picture_html',\n LIVESTREAM_RTSP: 'livestream_rtsp',\n PAN_LEFT: 'pan_left',\n PAN_RIGHT: 'pan_right',\n TILT_UP: 'tilt_up',\n TILT_DOWN: 'titl_down',\n ROTATE_360: 'rotate_360',\n SET_DEFAULT_ANGLE: 'set_default_angle',\n SET_PRIVACY_ANGLE: 'set_privacy_angle',\n CALIBRATE: 'calibrate',\n UNLOCK: 'unlock',\n OPEN_BOX: 'open_box',\n};\n\nexport const StationStateID = {\n REBOOT: 'reboot',\n CONNECTION: 'connection',\n TRIGGER_ALARM_SOUND: 'trigger_alarm_sound',\n RESET_ALARM_SOUND: 'reset_alarm_sound',\n};\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAA6B;AAItB,MAAM,eAAe;AAAA,EACxB,YAAY;AAChB;AAEO,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAE5B,MAAM,cAA4B;AAAA,EACrC,CAAC,yCAAa,IAAI,GAAG;AAAA,EACrB,CAAC,yCAAa,iBAAiB,GAAG;AAAA,EAClC,CAAC,yCAAa,mBAAmB,GAAG;AAAA,EACpC,CAAC,yCAAa,WAAW,GAAG;AAAA,EAC5B,CAAC,yCAAa,aAAa,GAAG;AAAA,EAC9B,CAAC,yCAAa,iBAAiB,GAAG;AAAA,EAClC,CAAC,yCAAa,oBAAoB,GAAG;AAAA,EACrC,CAAC,yCAAa,oBAAoB,GAAG;AAAA,EACrC,CAAC,yCAAa,aAAa,GAAG;AAAA,EAC9B,CAAC,yCAAa,oBAAoB,GAAG;AAAA,EACrC,CAAC,yCAAa,mBAAmB,GAAG;AAAA,EACpC,CAAC,yCAAa,iBAAiB,GAAG;AAAA,EAClC,CAAC,yCAAa,gBAAgB,GAAG;AAAA,EACjC,CAAC,yCAAa,gBAAgB,GAAG;AAAA,EACjC,CAAC,yCAAa,gBAAgB,GAAG;AAAA,EACjC,CAAC,yCAAa,qBAAqB,GAAG;AAAA,EACtC,CAAC,yCAAa,qBAAqB,GAAG;AAAA,EACtC,CAAC,yCAAa,qBAAqB,GAAG;AAAA,EACtC,CAAC,yCAAa,yBAAyB,GAAG;AAAA,EAC1C,CAAC,yCAAa,4BAA4B,GAAG;AAAA,EAC7C,CAAC,yCAAa,4BAA4B,GAAG;AAAA,EAC7C,CAAC,yCAAa,oBAAoB,GAAG;AACzC;AAEO,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA,EAIzB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU;AACd;AAEO,MAAM,iBAAiB;AAAA,EAC1B,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,mBAAmB;AACvB;",
6
6
  "names": []
7
7
  }
@@ -45,7 +45,7 @@ __export(utils_exports, {
45
45
  });
46
46
  module.exports = __toCommonJS(utils_exports);
47
47
  var import_eufy_security_client = require("eufy-security-client");
48
- var import_path = __toESM(require("path"));
48
+ var import_node_path = __toESM(require("node:path"));
49
49
  var import_fs_extra = __toESM(require("fs-extra"));
50
50
  var utils = __toESM(require("@iobroker/adapter-core"));
51
51
  const setStateChangedAsync = async function(adapter, id, value) {
@@ -53,15 +53,17 @@ const setStateChangedAsync = async function(adapter, id, value) {
53
53
  };
54
54
  const isEmpty = function(str) {
55
55
  if (str) {
56
- if (str.length > 0)
56
+ if (str.length > 0) {
57
57
  return false;
58
+ }
58
59
  return true;
59
60
  }
60
61
  return true;
61
62
  };
62
63
  const getImageAsHTML = function(data, mime = "image/jpg") {
63
- if (data && data.length > 0)
64
+ if (data && data.length > 0) {
64
65
  return `<img src="data:${mime};base64,${data.toString("base64")}" style="width: auto ;height: 100%;" />`;
66
+ }
65
67
  return "";
66
68
  };
67
69
  const setStateAsync = async function(adapter, state_id, common_name, value, role = "text", type = "string") {
@@ -81,17 +83,21 @@ const setStateAsync = async function(adapter, state_id, common_name, value, role
81
83
  const removeFiles = function(adapter, stationSerial, folderName, device_sn) {
82
84
  return new Promise(async (resolve, reject) => {
83
85
  try {
84
- const dir_path = import_path.default.join(stationSerial, folderName);
86
+ const dir_path = import_node_path.default.join(stationSerial, folderName);
85
87
  if (await adapter.fileExistsAsync(adapter.namespace, dir_path)) {
86
- const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter((fn) => fn.file.startsWith(device_sn));
88
+ const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(
89
+ (fn) => fn.file.startsWith(device_sn)
90
+ );
87
91
  try {
88
- files.map((filename) => adapter.delFileAsync(adapter.namespace, import_path.default.join(dir_path, filename.file)));
89
- } catch (error) {
92
+ for (const filename of files) {
93
+ await adapter.delFileAsync(adapter.namespace, import_node_path.default.join(dir_path, filename.file));
94
+ }
95
+ } catch {
90
96
  }
91
97
  }
92
98
  resolve();
93
99
  } catch (error) {
94
- reject(error);
100
+ reject(new Error(`Failed to remove files: ${error}`));
95
101
  }
96
102
  });
97
103
  };
@@ -114,22 +120,24 @@ const getVideoClipLength = (device) => {
114
120
  if (workingMode !== void 0) {
115
121
  switch (workingMode) {
116
122
  case "0":
117
- if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras())
123
+ if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras()) {
118
124
  length = 20;
119
- else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2())
125
+ } else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2()) {
120
126
  length = 30;
127
+ }
121
128
  break;
122
129
  case "1":
123
130
  break;
124
- case "2":
131
+ case "2": {
125
132
  const customValue = device.getRawProperty(import_eufy_security_client.CommandType.CMD_DEV_RECORD_TIMEOUT);
126
133
  if (customValue !== void 0) {
127
134
  try {
128
135
  length = Number.parseInt(customValue);
129
- } catch (error) {
136
+ } catch {
130
137
  }
131
138
  }
132
139
  break;
140
+ }
133
141
  case "3":
134
142
  break;
135
143
  }
@@ -144,48 +152,56 @@ const removeLastChar = function(text, char) {
144
152
  const changeRole = async function(adapter, log, state, role) {
145
153
  try {
146
154
  const states = await adapter.getStatesAsync(`*.${state}`);
147
- if (states)
155
+ if (states) {
148
156
  Object.keys(states).forEach(async (id) => {
149
- await adapter.extendObjectAsync(id, {
150
- type: "state",
151
- common: {
152
- role
153
- }
154
- }, {}).catch();
157
+ await adapter.extendObjectAsync(
158
+ id,
159
+ {
160
+ type: "state",
161
+ common: {
162
+ role
163
+ }
164
+ },
165
+ {}
166
+ ).catch();
155
167
  });
168
+ }
156
169
  } catch (error) {
157
170
  log.error(`state: ${state} role: ${role} - Error:`, error);
158
171
  }
159
172
  };
160
173
  const deleteStates = async function(adapter, property) {
161
174
  const states = await adapter.getStatesAsync(`*.${property}`);
162
- if (states)
163
- Object.keys(states).forEach(async (id) => {
175
+ if (states) {
176
+ const ids = Object.keys(states);
177
+ for (const id of ids) {
164
178
  await adapter.delObjectAsync(id).catch();
165
- });
179
+ }
180
+ }
166
181
  };
167
182
  const handleUpdate = async function(adapter, log, oldVersion, newVersion) {
168
183
  if (oldVersion != 0 && oldVersion <= 0.61) {
169
184
  try {
170
185
  const all = await adapter.getStatesAsync("T*");
171
186
  if (all) {
172
- Object.keys(all).forEach(async (id) => {
187
+ const ids = Object.keys(all);
188
+ for (const id of ids) {
173
189
  await adapter.delObjectAsync(id, { recursive: false }).catch();
174
- });
190
+ }
175
191
  }
176
192
  const channels = await adapter.getChannelsOfAsync();
177
193
  if (channels) {
178
- Object.values(channels).forEach(async (channel) => {
194
+ for (const channel of channels) {
179
195
  if (channel.common.name !== "info") {
180
196
  await adapter.delObjectAsync(channel._id, { recursive: false }).catch();
181
197
  }
182
- });
198
+ }
183
199
  }
184
200
  const devices = await adapter.getDevicesAsync();
185
201
  if (devices) {
186
- Object.values(devices).forEach(async (device) => {
202
+ for (const device of devices) {
187
203
  await adapter.delObjectAsync(device._id, { recursive: false }).catch();
188
- });
204
+ }
189
205
  }
190
206
  } catch (error) {
191
207
  log.error("Version 0.6.1: Error:", error);
@@ -220,32 +236,34 @@ const handleUpdate = async function(adapter, log, oldVersion, newVersion) {
220
236
  if (oldVersion == 0 && newVersion == 1.3) {
221
237
  const data_dir = utils.getAbsoluteInstanceDataDir(adapter);
222
238
  try {
223
- const file = import_path.default.join(data_dir, "adapter.json");
239
+ const file = import_node_path.default.join(data_dir, "adapter.json");
224
240
  if (import_fs_extra.default.statSync(file).isFile()) {
225
241
  const fileContent = import_fs_extra.default.readFileSync(file, "utf8");
226
242
  await adapter.writeFileAsync(adapter.namespace, "adapter.json", fileContent);
227
243
  }
228
- } catch (error) {
244
+ } catch {
229
245
  }
230
246
  try {
231
- const file = import_path.default.join(data_dir, "persistent.json");
247
+ const file = import_node_path.default.join(data_dir, "persistent.json");
232
248
  if (import_fs_extra.default.statSync(file).isFile()) {
233
249
  const fileContent = import_fs_extra.default.readFileSync(file, "utf8");
234
250
  await adapter.writeFileAsync(adapter.namespace, "driver.json", fileContent);
235
251
  }
236
- } catch (error) {
252
+ } catch {
237
253
  }
238
254
  try {
239
255
  import_fs_extra.default.removeSync(data_dir);
240
- } catch (error) {
256
+ } catch {
241
257
  }
242
- adapter.log.warn("Migrated configuration files to new location (needs restart). Restart of the adapter initiated.");
258
+ adapter.log.warn(
259
+ "Migrated configuration files to new location (needs restart). Restart of the adapter initiated."
260
+ );
243
261
  adapter.restartAdapter();
244
262
  }
245
263
  };
246
264
  const convertCamelCaseToSnakeCase = function(value) {
247
265
  return value.replace(/[A-Z]/g, (letter, index) => {
248
- return index == 0 ? letter.toLowerCase() : "_" + letter.toLowerCase();
266
+ return index == 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`;
249
267
  });
250
268
  };
251
269
  function getShortUrl(url, prefixUrl) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/utils.ts"],
4
- "sourcesContent": ["import { CommandType, Device } from \"eufy-security-client\";\r\nimport path from \"path\";\r\nimport fse from \"fs-extra\";\r\nimport * as utils from \"@iobroker/adapter-core\";\r\n\r\nimport { ioBrokerLogger } from \"./log\";\r\nimport { euSec } from \"../main\";\r\n\r\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\r\nexport const setStateChangedAsync = async function(adapter: ioBroker.Adapter, id: string, value: any): ioBroker.SetStateChangedPromise {\r\n return await adapter.setStateChangedAsync(id, value === undefined || value === null ? null : { val: value, ack: true }).catch();\r\n};\r\n\r\nexport const isEmpty = function(str: string | null | undefined): boolean {\r\n if (str) {\r\n if (str.length > 0)\r\n return false;\r\n return true;\r\n }\r\n return true;\r\n};\r\n\r\nexport const getImageAsHTML = function(data: Buffer, mime = \"image/jpg\"): string {\r\n if (data && data.length > 0)\r\n return `<img src=\"data:${mime};base64,${data.toString(\"base64\")}\" style=\"width: auto ;height: 100%;\" />`;\r\n return \"\";\r\n}\r\n\r\n/*export const getDataFilePath = function(adapter: ioBroker.Adapter, stationSerial: string, folderName: string, fileName: string): string {\r\n const dir_path = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, folderName);\r\n if (!fse.existsSync(dir_path)) {\r\n fse.mkdirSync(dir_path, {mode: 0o775, recursive: true});\r\n }\r\n return path.join(dir_path, fileName);\r\n}*/\r\n\r\nexport const setStateAsync = async function(adapter: ioBroker.Adapter, state_id: string, common_name: string, value: string, role = \"text\", type: \"string\" | \"number\" | \"boolean\" | \"object\" | \"array\" | \"mixed\" | undefined = \"string\"): Promise<void> {\r\n await adapter.setObjectNotExistsAsync(state_id, {\r\n type: \"state\",\r\n common: {\r\n name: common_name,\r\n type: type,\r\n role: role,\r\n read: true,\r\n write: false,\r\n },\r\n native: {\r\n },\r\n });\r\n await adapter.setStateAsync(state_id, { val: value, ack: true });\r\n}\r\n\r\nexport const removeFiles = function(adapter: ioBroker.Adapter, stationSerial: string, folderName: string, device_sn: string): Promise<void> {\r\n return new Promise(async (resolve, reject) => {\r\n try {\r\n const dir_path = path.join(stationSerial, folderName);\r\n if (await adapter.fileExistsAsync(adapter.namespace, dir_path)) {\r\n const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(fn => fn.file.startsWith(device_sn));\r\n try {\r\n files.map(filename => adapter.delFileAsync(adapter.namespace, path.join(dir_path, filename.file)));\r\n } catch (error) {\r\n }\r\n }\r\n resolve();\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n}\r\n\r\n/*export const moveFiles = function(adapter: ioBroker.Adapter, stationSerial: string, device_sn: string, srcFolderName: string, dstFolderName: string): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n try {\r\n const dirSrcPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, srcFolderName);\r\n const dirDstPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, dstFolderName);\r\n if (!fse.existsSync(dirDstPath)) {\r\n fse.mkdirSync(dirDstPath, {mode: 0o775, recursive: true});\r\n }\r\n if (fse.existsSync(dirSrcPath)) {\r\n const files = fse.readdirSync(dirSrcPath).filter(fn => fn.startsWith(device_sn));\r\n try {\r\n files.map(filename => fse.moveSync(path.join(dirSrcPath, filename), path.join(dirDstPath, filename)));\r\n } catch (error) {\r\n }\r\n }\r\n resolve();\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n}*/\r\n\r\nexport const lowestUnusedNumber = function (sequence: number[], startingFrom: number): number {\r\n const arr = sequence.slice(0);\r\n arr.sort((a, b) => a - b);\r\n return arr.reduce((lowest, num, i) => {\r\n const seqIndex = i + startingFrom;\r\n return num !== seqIndex && seqIndex < lowest ? seqIndex : lowest\r\n }, arr.length + startingFrom);\r\n}\r\n\r\nexport const sleep = async (ms: number): Promise<void> => {\r\n return new Promise((resolve) => {\r\n setTimeout(resolve, ms);\r\n });\r\n};\r\n\r\nexport const getVideoClipLength = (device: Device): number => {\r\n let length = 60;\r\n const workingMode = device.getRawProperty(CommandType.CMD_SET_PIR_POWERMODE);\r\n if (workingMode !== undefined) {\r\n switch(workingMode) {\r\n case \"0\":\r\n if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras())\r\n length = 20;\r\n else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2())\r\n length = 30;\r\n break;\r\n case \"1\":\r\n // Corrisponds to 60 seconds\r\n break;\r\n case \"2\":\r\n const customValue = device.getRawProperty(CommandType.CMD_DEV_RECORD_TIMEOUT);\r\n if (customValue !== undefined) {\r\n try {\r\n length = Number.parseInt(customValue);\r\n } catch(error) {\r\n }\r\n }\r\n break;\r\n case \"3\":\r\n // Corrisponds to 60 seconds?? (this mode exists only for battery doorbells; mode: Optimal Battery Life)\r\n break;\r\n }\r\n }\r\n return length;\r\n};\r\n\r\nexport const removeLastChar = function(text: string, char: string): string {\r\n const strArr = [...text];\r\n strArr.splice(text.lastIndexOf(char), 1);\r\n return strArr.join(\"\");\r\n}\r\n\r\nexport const changeRole = async function(adapter: ioBroker.Adapter, log: ioBrokerLogger, state: string, role: string): Promise<void> {\r\n try {\r\n const states = await adapter.getStatesAsync(`*.${state}`);\r\n if (states)\r\n Object.keys(states).forEach(async id => {\r\n await adapter.extendObjectAsync(id, {\r\n type: \"state\",\r\n common: {\r\n role: role\r\n }\r\n }, {}).catch();\r\n });\r\n } catch (error) {\r\n log.error(`state: ${state} role: ${role} - Error:`, error);\r\n }\r\n};\r\n\r\nexport const deleteStates = async function(adapter: ioBroker.Adapter, property: string): Promise<void> {\r\n const states = await adapter.getStatesAsync(`*.${property}`);\r\n if (states)\r\n Object.keys(states).forEach(async id => {\r\n await adapter.delObjectAsync(id).catch();\r\n });\r\n};\r\n\r\nexport const handleUpdate = async function(adapter: euSec, log: ioBrokerLogger, oldVersion: number, newVersion: number): Promise<void> {\r\n if (oldVersion != 0 && oldVersion <= 0.61) {\r\n try {\r\n const all = await adapter.getStatesAsync(\"T*\");\r\n if (all) {\r\n Object.keys(all).forEach(async id => {\r\n await adapter.delObjectAsync(id, { recursive: false }).catch();\r\n });\r\n }\r\n const channels = await adapter.getChannelsOfAsync();\r\n if (channels) {\r\n Object.values(channels).forEach(async channel => {\r\n if (channel.common.name !== \"info\") {\r\n await adapter.delObjectAsync(channel._id, {recursive: false}).catch();\r\n }\r\n });\r\n }\r\n const devices = await adapter.getDevicesAsync();\r\n if (devices) {\r\n Object.values(devices).forEach(async device => {\r\n await adapter.delObjectAsync(device._id, {recursive: false}).catch();\r\n });\r\n }\r\n } catch (error) {\r\n log.error(\"Version 0.6.1: Error:\", error);\r\n }\r\n }\r\n if (oldVersion != 0 && oldVersion <= 0.74) {\r\n try {\r\n await adapter.setObjectAsync(\"verify_code\", {\r\n type: \"state\",\r\n common: {\r\n name: \"2FA verification code\",\r\n type: \"string\",\r\n role: \"state\",\r\n read: true,\r\n write: true,\r\n },\r\n native: {},\r\n });\r\n } catch (error) {\r\n log.error(\"Version 0.7.4: Error:\", error);\r\n }\r\n }\r\n if (oldVersion != 0 && oldVersion <= 1) {\r\n for (const state of [\"last_event_pic_url\", \"last_event_pic_html\", \"last_event_video_url\"]) {\r\n try {\r\n await deleteStates(adapter, state);\r\n } catch (error) {\r\n log.error(`Version 1.0.0 - ${state}: Error:`, error);\r\n }\r\n }\r\n }\r\n if (oldVersion == 0 && newVersion == 1.3) {\r\n const data_dir = utils.getAbsoluteInstanceDataDir(adapter);\r\n try {\r\n const file = path.join(data_dir, \"adapter.json\");\r\n if (fse.statSync(file).isFile()) {\r\n const fileContent = fse.readFileSync(file, \"utf8\");\r\n await adapter.writeFileAsync(adapter.namespace, \"adapter.json\", fileContent);\r\n }\r\n } catch (error) {\r\n //log.error(`Version 3.0.0: Error:`, error);\r\n }\r\n try {\r\n const file = path.join(data_dir, \"persistent.json\");\r\n if (fse.statSync(file).isFile()) {\r\n const fileContent = fse.readFileSync(file, \"utf8\");\r\n await adapter.writeFileAsync(adapter.namespace, \"driver.json\", fileContent);\r\n }\r\n } catch (error) {\r\n //log.error(`Version 3.0.0: Error:`, error);\r\n }\r\n try {\r\n fse.removeSync(data_dir);\r\n } catch (error) {\r\n //log.error(`Version 3.0.0: Error:`, error);\r\n }\r\n adapter.log.warn(\"Migrated configuration files to new location (needs restart). Restart of the adapter initiated.\")\r\n adapter.restartAdapter();\r\n }\r\n};\r\n\r\nexport const convertCamelCaseToSnakeCase = function (value: string): string {\r\n return value.replace(/[A-Z]/g, (letter, index) => {\r\n return index == 0 ? letter.toLowerCase() : \"_\" + letter.toLowerCase();\r\n });\r\n};\r\n\r\nexport function getShortUrl(url: URL, prefixUrl?: string): string {\r\n if (url.password) {\r\n url = new URL(url.toString()); // prevent original url mutation\r\n url.password = \"[redacted]\";\r\n }\r\n let shortUrl = url.toString();\r\n if (prefixUrl && shortUrl.startsWith(prefixUrl)) {\r\n shortUrl = shortUrl.slice(prefixUrl.length);\r\n }\r\n\r\n return shortUrl;\r\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Device } from 'eufy-security-client';\nimport { CommandType } from 'eufy-security-client';\nimport path from 'node:path';\nimport fse from 'fs-extra';\nimport * as utils from '@iobroker/adapter-core';\n\nimport type { ioBrokerLogger } from './log';\nimport type { euSec } from '../main';\n\nexport const setStateChangedAsync = async function (\n adapter: ioBroker.Adapter,\n id: string,\n value: any,\n): ioBroker.SetStateChangedPromise {\n return await adapter\n .setStateChangedAsync(id, value === undefined || value === null ? null : { val: value, ack: true })\n .catch();\n};\n\nexport const isEmpty = function (str: string | null | undefined): boolean {\n if (str) {\n if (str.length > 0) {\n return false;\n }\n return true;\n }\n return true;\n};\n\nexport const getImageAsHTML = function (data: Buffer, mime = 'image/jpg'): string {\n if (data && data.length > 0) {\n return `<img src=\"data:${mime};base64,${data.toString('base64')}\" style=\"width: auto ;height: 100%;\" />`;\n }\n return '';\n};\n\n/*export const getDataFilePath = function(adapter: ioBroker.Adapter, stationSerial: string, folderName: string, fileName: string): string {\n const dir_path = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, folderName);\n if (!fse.existsSync(dir_path)) {\n fse.mkdirSync(dir_path, {mode: 0o775, recursive: true});\n }\n return path.join(dir_path, fileName);\n}*/\n\nexport const setStateAsync = async function (\n adapter: ioBroker.Adapter,\n state_id: string,\n common_name: string,\n value: string,\n role = 'text',\n type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'mixed' | undefined = 'string',\n): Promise<void> {\n await adapter.setObjectNotExistsAsync(state_id, {\n type: 'state',\n common: {\n name: common_name,\n type: type,\n role: role,\n read: true,\n write: false,\n },\n native: {},\n });\n await adapter.setStateAsync(state_id, { val: value, ack: true });\n};\n\nexport const removeFiles = function (\n adapter: ioBroker.Adapter,\n stationSerial: string,\n folderName: string,\n device_sn: string,\n): Promise<void> {\n // eslint-disable-next-line no-async-promise-executor\n return new Promise(async (resolve, reject) => {\n try {\n const dir_path = path.join(stationSerial, folderName);\n if (await adapter.fileExistsAsync(adapter.namespace, dir_path)) {\n const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(fn =>\n fn.file.startsWith(device_sn),\n );\n try {\n for (const filename of files) {\n await adapter.delFileAsync(adapter.namespace, path.join(dir_path, filename.file));\n }\n } catch {\n // ignore\n }\n }\n resolve();\n } catch (error) {\n reject(new Error(`Failed to remove files: ${error as Error}`));\n }\n });\n};\n\n/*export const moveFiles = function(adapter: ioBroker.Adapter, stationSerial: string, device_sn: string, srcFolderName: string, dstFolderName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const dirSrcPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, srcFolderName);\n const dirDstPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, dstFolderName);\n if (!fse.existsSync(dirDstPath)) {\n fse.mkdirSync(dirDstPath, {mode: 0o775, recursive: true});\n }\n if (fse.existsSync(dirSrcPath)) {\n const files = fse.readdirSync(dirSrcPath).filter(fn => fn.startsWith(device_sn));\n try {\n files.map(filename => fse.moveSync(path.join(dirSrcPath, filename), path.join(dirDstPath, filename)));\n } catch (error) {\n }\n }\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n}*/\n\nexport const lowestUnusedNumber = function (sequence: number[], startingFrom: number): number {\n const arr = sequence.slice(0);\n arr.sort((a, b) => a - b);\n return arr.reduce((lowest, num, i) => {\n const seqIndex = i + startingFrom;\n return num !== seqIndex && seqIndex < lowest ? seqIndex : lowest;\n }, arr.length + startingFrom);\n};\n\nexport const sleep = async (ms: number): Promise<void> => {\n return new Promise(resolve => {\n setTimeout(resolve, ms);\n });\n};\n\nexport const getVideoClipLength = (device: Device): number => {\n let length = 60;\n const workingMode = device.getRawProperty(CommandType.CMD_SET_PIR_POWERMODE);\n if (workingMode !== undefined) {\n switch (workingMode) {\n case '0':\n if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras()) {\n length = 20;\n } else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2()) {\n length = 30;\n }\n break;\n case '1':\n // Corresponds to 60 seconds\n break;\n case '2': {\n const customValue = device.getRawProperty(CommandType.CMD_DEV_RECORD_TIMEOUT);\n if (customValue !== undefined) {\n try {\n length = Number.parseInt(customValue);\n } catch {\n // ignore\n }\n }\n break;\n }\n case '3':\n // Corresponds to 60 seconds?? (this mode exists only for battery doorbells; mode: Optimal Battery Life)\n break;\n }\n }\n return length;\n};\n\nexport const removeLastChar = function (text: string, char: string): string {\n const strArr = [...text];\n strArr.splice(text.lastIndexOf(char), 1);\n return strArr.join('');\n};\n\nexport const changeRole = async function (\n adapter: ioBroker.Adapter,\n log: ioBrokerLogger,\n state: string,\n role: string,\n): Promise<void> {\n try {\n const states = await adapter.getStatesAsync(`*.${state}`);\n if (states) {\n Object.keys(states).forEach(async id => {\n await adapter\n .extendObjectAsync(\n id,\n {\n type: 'state',\n common: {\n role: role,\n },\n },\n {},\n )\n .catch();\n });\n }\n } catch (error) {\n log.error(`state: ${state} role: ${role} - Error:`, error);\n }\n};\n\nexport const deleteStates = async function (adapter: ioBroker.Adapter, property: string): Promise<void> {\n const states = await adapter.getStatesAsync(`*.${property}`);\n if (states) {\n const ids = Object.keys(states);\n for (const id of ids) {\n await adapter.delObjectAsync(id).catch();\n }\n }\n};\n\nexport const handleUpdate = async function (\n adapter: euSec,\n log: ioBrokerLogger,\n oldVersion: number,\n newVersion: number,\n): Promise<void> {\n if (oldVersion != 0 && oldVersion <= 0.61) {\n try {\n const all = await adapter.getStatesAsync('T*');\n if (all) {\n const ids = Object.keys(all);\n for (const id of ids) {\n await adapter.delObjectAsync(id, { recursive: false }).catch();\n }\n }\n const channels = await adapter.getChannelsOfAsync();\n if (channels) {\n for (const channel of channels) {\n if (channel.common.name !== 'info') {\n await adapter.delObjectAsync(channel._id, { recursive: false }).catch();\n }\n }\n }\n const devices = await adapter.getDevicesAsync();\n if (devices) {\n for (const device of devices) {\n await adapter.delObjectAsync(device._id, { recursive: false }).catch();\n }\n }\n } catch (error) {\n log.error('Version 0.6.1: Error:', error);\n }\n }\n if (oldVersion != 0 && oldVersion <= 0.74) {\n try {\n await adapter.setObjectAsync('verify_code', {\n type: 'state',\n common: {\n name: '2FA verification code',\n type: 'string',\n role: 'state',\n read: true,\n write: true,\n },\n native: {},\n });\n } catch (error) {\n log.error('Version 0.7.4: Error:', error);\n }\n }\n if (oldVersion != 0 && oldVersion <= 1) {\n for (const state of ['last_event_pic_url', 'last_event_pic_html', 'last_event_video_url']) {\n try {\n await deleteStates(adapter, state);\n } catch (error) {\n log.error(`Version 1.0.0 - ${state}: Error:`, error);\n }\n }\n }\n if (oldVersion == 0 && newVersion == 1.3) {\n const data_dir = utils.getAbsoluteInstanceDataDir(adapter);\n try {\n const file = path.join(data_dir, 'adapter.json');\n if (fse.statSync(file).isFile()) {\n const fileContent = fse.readFileSync(file, 'utf8');\n await adapter.writeFileAsync(adapter.namespace, 'adapter.json', fileContent);\n }\n } catch {\n // log.error(`Version 3.0.0: Error:`, error);\n }\n try {\n const file = path.join(data_dir, 'persistent.json');\n if (fse.statSync(file).isFile()) {\n const fileContent = fse.readFileSync(file, 'utf8');\n await adapter.writeFileAsync(adapter.namespace, 'driver.json', fileContent);\n }\n } catch {\n // log.error(`Version 3.0.0: Error:`, error);\n }\n try {\n fse.removeSync(data_dir);\n } catch {\n // log.error(`Version 3.0.0: Error:`, error);\n }\n adapter.log.warn(\n 'Migrated configuration files to new location (needs restart). Restart of the adapter initiated.',\n );\n adapter.restartAdapter();\n }\n};\n\nexport const convertCamelCaseToSnakeCase = function (value: string): string {\n return value.replace(/[A-Z]/g, (letter, index) => {\n return index == 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`;\n });\n};\n\nexport function getShortUrl(url: URL, prefixUrl?: string): string {\n if (url.password) {\n url = new URL(url.toString()); // prevent original url mutation\n url.password = '[redacted]';\n }\n let shortUrl = url.toString();\n if (prefixUrl && shortUrl.startsWith(prefixUrl)) {\n shortUrl = shortUrl.slice(prefixUrl.length);\n }\n\n return shortUrl;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["path", "fse"]
7
7
  }