iobroker.tapo 0.4.5 → 0.4.8
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 +1 -1
- package/README.md +14 -1
- package/admin/jsonConfig.json +21 -0
- package/build/lib/utils/camera/tapoCamera.js +1 -0
- package/build/lib/utils/camera/tapoCamera.js.map +2 -2
- package/build/main.js +21 -3
- package/build/main.js.map +2 -2
- package/io-package.json +42 -7
- package/package.json +16 -16
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2024 TA2k <tombox2020@gmail.com>
|
|
3
|
+
Copyright (c) 2024-2030 TA2k <tombox2020@gmail.com>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -37,6 +37,19 @@ tapo.0.id.remote auf true/false setzen steuert den jeweiligen Befehl. Der Befehl
|
|
|
37
37
|
<https://forum.iobroker.net/topic/57336/test-adapter-tp-link-tapo/>
|
|
38
38
|
|
|
39
39
|
## Changelog
|
|
40
|
+
### 0.4.8 (2025-02-04)
|
|
41
|
+
|
|
42
|
+
- disable sentry to prevent crashes
|
|
43
|
+
|
|
44
|
+
### 0.4.7 (2025-01-14)
|
|
45
|
+
|
|
46
|
+
- disable battery devices
|
|
47
|
+
- improved wrong formatted mail adresses
|
|
48
|
+
|
|
49
|
+
### 0.4.6 (2025-01-10)
|
|
50
|
+
|
|
51
|
+
- add checks for battery devices
|
|
52
|
+
|
|
40
53
|
### 0.4.5 (2024-12-16)
|
|
41
54
|
|
|
42
55
|
- fix camera remotes
|
|
@@ -78,7 +91,7 @@ update onvif lib to fix issues with newer cameras
|
|
|
78
91
|
|
|
79
92
|
MIT License
|
|
80
93
|
|
|
81
|
-
Copyright (c) 2024 TA2k <tombox2020@gmail.com>
|
|
94
|
+
Copyright (c) 2024-2030 TA2k <tombox2020@gmail.com>
|
|
82
95
|
|
|
83
96
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
84
97
|
of this software and associated documentation files (the "Software"), to deal
|
package/admin/jsonConfig.json
CHANGED
|
@@ -38,6 +38,27 @@
|
|
|
38
38
|
"zh-cn": "应用密码"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
+
"enableBatteryDevices": {
|
|
42
|
+
"type": "checkbox",
|
|
43
|
+
"label": {
|
|
44
|
+
"en": "Enable Battery Devices",
|
|
45
|
+
"de": "Batteriegeräte aktivieren",
|
|
46
|
+
"ru": "Включить батарейные устройства",
|
|
47
|
+
"pt": "Ativar dispositivos de bateria",
|
|
48
|
+
"nl": "Batterijapparaten inschakelen",
|
|
49
|
+
"fr": "Activer les appareils à batterie",
|
|
50
|
+
"it": "Abilita dispositivi a batteria",
|
|
51
|
+
"es": "Habilitar dispositivos de batería",
|
|
52
|
+
"pl": "Włącz urządzenia zasilane baterią",
|
|
53
|
+
"zh-cn": "启用电池设备"
|
|
54
|
+
},
|
|
55
|
+
"newLine": true,
|
|
56
|
+
"sm": 12,
|
|
57
|
+
"lg": 3,
|
|
58
|
+
"xs": 12,
|
|
59
|
+
"md": 3,
|
|
60
|
+
"xl": 3
|
|
61
|
+
},
|
|
41
62
|
|
|
42
63
|
"interval": {
|
|
43
64
|
"type": "number",
|
|
@@ -277,6 +277,7 @@ const _TAPOCamera = class extends import_onvifCamera.OnvifCamera {
|
|
|
277
277
|
this.log.debug("isSecureConnection: Checking secure connection...");
|
|
278
278
|
const response = await this.fetch(`https://${this.config.ipAddress}`, {
|
|
279
279
|
method: "post",
|
|
280
|
+
headers: this.getHeaders(),
|
|
280
281
|
body: JSON.stringify({
|
|
281
282
|
method: "login",
|
|
282
283
|
params: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/camera/tapoCamera.ts"],
|
|
4
|
-
"sourcesContent": ["// import https, { Agent } from \"https\";\nimport crypto from \"crypto\";\nimport { OnvifCamera } from \"./onvifCamera\";\nimport type {\n TAPOBasicInfo,\n TAPOCameraEncryptedRequest,\n TAPOCameraEncryptedResponse,\n TAPOCameraLoginResponse,\n TAPOCameraRefreshStokResponse,\n TAPOCameraRequest,\n TAPOCameraResponse,\n TAPOCameraResponseDeviceInfo,\n TAPOCameraSetRequest,\n} from \"./types/tapo\";\n\nconst MAX_LOGIN_RETRIES = 3;\nconst AES_BLOCK_SIZE = 16;\n\nimport { Agent, setGlobalDispatcher } from \"undici\";\n\nconst ERROR_CODES_MAP = {\n \"-40401\": \"Invalid stok value\",\n \"-40210\": \"Function not supported\",\n \"-64303\": \"Action cannot be done while camera is in patrol mode.\",\n \"-64324\": \"Privacy mode is ON, not able to execute\",\n \"-64302\": \"Preset ID not found\",\n \"-64321\": \"Preset ID was deleted so no longer exists\",\n \"-40106\": \"Parameter to get/do does not exist\",\n \"-40105\": \"Method does not exist\",\n \"-40101\": \"Parameter to set does not exist\",\n \"-40209\": \"Invalid login credentials\",\n \"-64304\": \"Maximum Pan/Tilt range reached\",\n \"-71103\": \"User ID is not authorized\",\n};\n\nexport type Status = {\n eyes: boolean | undefined;\n alarm: boolean | undefined;\n notifications: boolean | undefined;\n motionDetection: boolean | undefined;\n led: boolean | undefined;\n};\ntype CameraConfig = {\n name: string;\n ipAddress: string;\n username: string;\n password: string;\n streamUser: string;\n streamPassword: string;\n\n pullInterval?: number;\n disableStreaming?: boolean;\n disableEyesToggleAccessory?: boolean;\n disableAlarmToggleAccessory?: boolean;\n disableNotificationsToggleAccessory?: boolean;\n disableMotionDetectionToggleAccessory?: boolean;\n disableLEDToggleAccessory?: boolean;\n\n disableMotionSensorAccessory?: boolean;\n lowQuality?: boolean;\n\n videoMaxWidth?: number;\n videoMaxHeight?: number;\n videoMaxFPS?: number;\n videoForceMax?: boolean;\n videoMaxBirate?: number;\n videoPacketSize?: number;\n videoCodec?: string;\n\n videoConfig?: VideoConfig;\n\n eyesToggleAccessoryName?: string;\n alarmToggleAccessoryName?: string;\n notificationsToggleAccessoryName?: string;\n motionDetectionToggleAccessoryName?: string;\n ledToggleAccessoryName?: string;\n};\nexport class TAPOCamera extends OnvifCamera {\n private readonly kStreamPort = 554;\n private readonly fetchAgent: Agent;\n\n private readonly hashedPassword: string;\n private readonly hashedSha256Password: string;\n private passwordEncryptionMethod: \"md5\" | \"sha256\" | null = null;\n\n private isSecureConnectionValue: boolean | null = null;\n\n private stokPromise: (() => Promise<void>) | undefined;\n\n private readonly cnonce: string;\n private lsk: Buffer | undefined;\n private ivb: Buffer | undefined;\n private seq: number | undefined;\n private stok: string | undefined;\n\n constructor(\n protected readonly log: any,\n protected readonly config: CameraConfig,\n ) {\n super(log, config);\n process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;\n this.fetchAgent = new Agent({\n connectTimeout: 5_000,\n connect: {\n // TAPO devices have self-signed certificates\n rejectUnauthorized: false,\n ciphers: \"AES256-SHA:AES128-GCM-SHA256\",\n },\n });\n setGlobalDispatcher(this.fetchAgent);\n\n this.cnonce = this.generateCnonce();\n\n this.hashedPassword = crypto.createHash(\"md5\").update(config.password).digest(\"hex\").toUpperCase();\n this.hashedSha256Password = crypto.createHash(\"sha256\").update(config.password).digest(\"hex\").toUpperCase();\n }\n\n private getUsername() {\n return this.config.username || \"admin\";\n }\n\n private getHeaders(): Record<string, string> {\n return {\n Host: `https://${this.config.ipAddress}`,\n Referer: `https://${this.config.ipAddress}`,\n Accept: \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n \"User-Agent\": \"Tapo CameraClient Android\",\n Connection: \"close\",\n requestByApp: \"true\",\n \"Content-Type\": \"application/json; charset=UTF-8\",\n };\n }\n\n private getHashedPassword() {\n if (this.passwordEncryptionMethod === \"md5\") {\n return this.hashedPassword;\n } else if (this.passwordEncryptionMethod === \"sha256\") {\n return this.hashedSha256Password;\n } else {\n this.log.error(\"Unknown password encryption method\");\n }\n }\n\n private fetch(url: string, data: RequestInit) {\n return fetch(url, {\n headers: this.getHeaders(),\n // @ts-expect-error Dispatcher type not there\n dispatcher: this.fetchAgent,\n ...data,\n });\n }\n\n private generateEncryptionToken(tokenType: string, nonce: string): Buffer {\n const hashedKey = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.getHashedPassword() + nonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tokenType + this.cnonce + nonce + hashedKey)\n .digest()\n .slice(0, 16);\n }\n\n getAuthenticatedStreamUrl(lowQuality = false) {\n const prefix = `rtsp://${this.config.streamUser}:${this.config.streamPassword}@${this.config.ipAddress}:${this.kStreamPort}`;\n return lowQuality ? `${prefix}/stream2` : `${prefix}/stream1`;\n }\n\n private generateCnonce() {\n return crypto.randomBytes(8).toString(\"hex\").toUpperCase();\n }\n\n private validateDeviceConfirm(nonce: string, deviceConfirm: string) {\n this.passwordEncryptionMethod = null;\n\n const hashedNoncesWithSHA256 = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.hashedSha256Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n if (deviceConfirm === hashedNoncesWithSHA256 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"sha256\";\n return true;\n }\n\n const hashedNoncesWithMD5 = crypto\n .createHash(\"md5\")\n .update(this.cnonce + this.hashedPassword + nonce)\n .digest(\"hex\")\n .toUpperCase();\n if (deviceConfirm === hashedNoncesWithMD5 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"md5\";\n return true;\n }\n\n this.log.debug('Invalid device confirm, expected \"sha256\" or \"md5\" to match, but none found', {\n hashedNoncesWithMD5,\n hashedNoncesWithSHA256,\n deviceConfirm,\n nonce,\n cnonce: this,\n });\n\n return this.passwordEncryptionMethod !== null;\n }\n\n async refreshStok(loginRetryCount = 0): Promise<void> {\n this.log.debug(\"refreshStok: Refreshing stok...\");\n\n const isSecureConnection = await this.isSecureConnection();\n\n let fetchParams = {};\n if (isSecureConnection) {\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n };\n } else {\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n username: this.getUsername(),\n password: this.hashedPassword,\n hashed: true,\n },\n }),\n };\n }\n\n const responseLogin = await this.fetch(`https://${this.config.ipAddress}`, fetchParams).catch((e) => {\n this.log.debug(\"refreshStok: Error during login\", e);\n return null;\n });\n if (!responseLogin) {\n this.log.debug(\"refreshStok: empty response login, raising exception\");\n this.log.error(\"Empty response login\");\n return;\n }\n const responseLoginData = (await responseLogin.json()) as TAPOCameraRefreshStokResponse;\n\n let response, responseData;\n\n if (!responseLoginData) {\n this.log.debug(\"refreshStok: empty response login data, raising exception\", responseLogin.status);\n this.log.error(\"Empty response login data\");\n }\n\n this.log.debug(\"refreshStok: Login response\", responseLogin.status, responseLoginData);\n\n if (responseLogin.status === 401 && responseLoginData.result?.data?.code === -40411) {\n this.log.debug(\"refreshStok: invalid credentials, raising exception\", responseLogin.status);\n this.log.error(\"Invalid credentials\");\n }\n\n if (isSecureConnection) {\n const nonce = responseLoginData.result?.data?.nonce;\n const deviceConfirm = responseLoginData.result?.data?.device_confirm;\n if (nonce && deviceConfirm && this.validateDeviceConfirm(nonce, deviceConfirm)) {\n const digestPasswd = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n const digestPasswdFull = Buffer.concat([\n Buffer.from(digestPasswd, \"utf8\"),\n Buffer.from(this.cnonce!, \"utf8\"),\n Buffer.from(nonce, \"utf8\"),\n ]).toString(\"utf8\");\n\n this.log.debug(\"refreshStok: sending start_seq request\");\n\n response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"POST\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n digest_passwd: digestPasswdFull,\n username: this.getUsername(),\n },\n }),\n });\n\n responseData = (await response.json()) as TAPOCameraRefreshStokResponse;\n\n if (!responseData) {\n this.log.debug(\"refreshStock: empty response start_seq data, raising exception\", response.status);\n this.log.error(\"Empty response start_seq data\");\n return;\n }\n\n this.log.debug(\"refreshStok: start_seq response\", response.status, JSON.stringify(responseData));\n\n if (responseData.result?.start_seq) {\n if (responseData.result?.user_group !== \"root\") {\n this.log.debug(\"refreshStock: Incorrect user_group detected\");\n\n // # encrypted control via 3rd party account does not seem to be supported\n // # see https://github.com/JurajNyiri/HomeAssistant-Tapo-Control/issues/456\n this.log.error(\"Incorrect user_group detected\");\n }\n\n this.lsk = this.generateEncryptionToken(\"lsk\", nonce);\n this.ivb = this.generateEncryptionToken(\"ivb\", nonce);\n this.seq = responseData.result.start_seq;\n }\n } else {\n if (responseLoginData.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `refreshStock: Invalid device confirm, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.`,\n responseLogin.status,\n responseLoginData,\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n this.log.debug(\n \"refreshStock: Invalid device confirm and loginRetryCount exhausted, raising exception\",\n loginRetryCount,\n responseLoginData,\n );\n this.log.error(\"Invalid device confirm. Please activate 3rd Patry support in the TP App under TP Labor -> 3rd Party Control\");\n return;\n }\n } else {\n this.passwordEncryptionMethod = \"md5\";\n response = responseLogin;\n responseData = responseLoginData;\n }\n\n if (responseData.result?.data?.sec_left && responseData.result.data.sec_left > 0) {\n this.log.debug(\"refreshStok: temporary suspension\", responseData);\n\n this.log.error(`Temporary Suspension: Try again in ${responseData.result.data.sec_left} seconds`);\n }\n if (responseData && responseData.result && responseData.result.responses && responseData.result.responses[0].error_code !== 0) {\n this.log.debug(\n `API request failed with specific error code ${responseData.result.responses[0].error_code}: ${responseData.result.responses[0].error_message}`,\n );\n }\n\n if (responseData?.data?.code === -40404 && responseData?.data?.sec_left && responseData.data.sec_left > 0) {\n this.log.debug(\"refreshStok: temporary suspension\", responseData);\n\n this.log.error(`refreshStok: Temporary Suspension: Try again in ${responseData.data.sec_left} seconds`);\n }\n\n if (responseData?.result?.stok) {\n this.stok = responseData.result.stok;\n this.log.debug(\"refreshStok: Success in obtaining STOK\", this.stok);\n return;\n }\n\n if (responseData?.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `refreshStock: Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.`,\n response.status,\n responseData,\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n this.log.debug(\"refreshStock: Unexpected end of flow, raising exception\");\n this.log.error(\"Invalid authentication data\");\n }\n\n async isSecureConnection() {\n if (this.isSecureConnectionValue === null) {\n this.log.debug(\"isSecureConnection: Checking secure connection...\");\n\n const response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n });\n const responseData = (await response.json()) as TAPOCameraLoginResponse;\n\n this.log.debug(\"isSecureConnection response\", response.status, JSON.stringify(responseData));\n\n this.isSecureConnectionValue =\n responseData?.error_code == -40413 && String(responseData.result?.data?.encrypt_type || \"\")?.includes(\"3\");\n }\n\n return this.isSecureConnectionValue;\n }\n\n getStok(loginRetryCount = 0): Promise<string> {\n return new Promise((resolve) => {\n if (this.stok) {\n return resolve(this.stok);\n }\n\n if (!this.stokPromise) {\n this.stokPromise = () => this.refreshStok(loginRetryCount);\n }\n\n this.stokPromise()\n .then(() => {\n if (!this.stok) {\n this.log.error(\"STOK not found\");\n }\n resolve(this.stok!);\n })\n .finally(() => {\n this.stokPromise = undefined;\n });\n });\n }\n\n private async getAuthenticatedAPIURL(loginRetryCount = 0) {\n const token = await this.getStok(loginRetryCount);\n return `https://${this.config.ipAddress}/stok=${token}/ds`;\n }\n\n encryptRequest(request: string) {\n const cipher = crypto.createCipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let ct_bytes = cipher.update(this.encryptPad(request, AES_BLOCK_SIZE), \"utf-8\", \"hex\");\n ct_bytes += cipher.final(\"hex\");\n return Buffer.from(ct_bytes, \"hex\");\n }\n\n private encryptPad(text: string, blocksize: number) {\n const padSize = blocksize - (text.length % blocksize);\n const padding = String.fromCharCode(padSize).repeat(padSize);\n return text + padding;\n }\n\n private decryptResponse(response: string): string {\n const decipher = crypto.createDecipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let decrypted = decipher.update(response, \"base64\", \"utf-8\");\n decrypted += decipher.final(\"utf-8\");\n return this.encryptUnpad(decrypted, AES_BLOCK_SIZE);\n }\n\n private encryptUnpad(text: string, blockSize: number): string {\n const paddingLength = Number(text[text.length - 1]) || 0;\n if (paddingLength > blockSize || paddingLength > text.length) {\n this.log.error(\"Invalid padding\");\n }\n for (let i = text.length - paddingLength; i < text.length; i++) {\n if (text.charCodeAt(i) !== paddingLength) {\n this.log.error(\"Invalid padding\");\n }\n }\n return text.slice(0, text.length - paddingLength).toString();\n }\n\n private getTapoTag(request: TAPOCameraEncryptedRequest) {\n const tag = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tag + JSON.stringify(request) + this.seq!.toString())\n .digest(\"hex\")\n .toUpperCase();\n }\n\n private pendingAPIRequests: Map<string, Promise<TAPOCameraResponse>> = new Map();\n\n private async apiRequest(req: TAPOCameraRequest, loginRetryCount = 0): Promise<TAPOCameraResponse> {\n const reqJson = JSON.stringify(req);\n\n if (this.pendingAPIRequests.has(reqJson)) {\n this.log.debug(\"API request already pending\", reqJson);\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n } else {\n this.log.debug(\"New API request\", reqJson);\n }\n\n this.pendingAPIRequests.set(\n reqJson,\n (async () => {\n try {\n const isSecureConnection = await this.isSecureConnection();\n const url = await this.getAuthenticatedAPIURL(loginRetryCount);\n\n const fetchParams: RequestInit = {\n method: \"post\",\n };\n\n if (this.seq && isSecureConnection) {\n const encryptedRequest: TAPOCameraEncryptedRequest = {\n method: \"securePassthrough\",\n params: {\n request: Buffer.from(this.encryptRequest(JSON.stringify(req))).toString(\"base64\"),\n },\n };\n fetchParams.headers = {\n ...this.getHeaders(),\n Tapo_tag: this.getTapoTag(encryptedRequest),\n Seq: this.seq.toString(),\n };\n fetchParams.body = JSON.stringify(encryptedRequest);\n this.seq += 1;\n } else {\n fetchParams.body = JSON.stringify(req);\n }\n\n const response = await this.fetch(url, fetchParams).catch((e) => {\n this.log.debug(\"Error during camera fetch\", e);\n return;\n });\n if (!response) {\n this.log.debug(\"API request failed, empty response\");\n return {} as TAPOCameraResponse;\n }\n const responseDataTmp = await response.json();\n\n // Apparently the Tapo C200 returns 500 on successful requests,\n // but it's indicating an expiring token, therefore refresh the token next time\n if (isSecureConnection && response.status === 500) {\n this.log.debug(\"Stok expired, reauthenticating on next request, setting STOK to undefined\");\n this.stok = undefined;\n }\n\n let responseData: TAPOCameraResponse | null = null;\n\n if (isSecureConnection) {\n const encryptedResponse = responseDataTmp as TAPOCameraEncryptedResponse;\n if (encryptedResponse?.result?.response) {\n const decryptedResponse = this.decryptResponse(encryptedResponse.result.response);\n responseData = JSON.parse(decryptedResponse) as TAPOCameraResponse;\n }\n } else {\n responseData = responseDataTmp as TAPOCameraResponse;\n }\n\n this.log.debug(\"API response\", response.status, JSON.stringify(responseData));\n\n // Log error codes\n if (responseData && responseData.error_code !== 0) {\n const errorCode = String(responseData.error_code);\n const errorMessage =\n errorCode in ERROR_CODES_MAP ? ERROR_CODES_MAP[errorCode as keyof typeof ERROR_CODES_MAP] : \"Unknown error\";\n this.log.debug(`API request failed with specific error code ${errorCode}: ${errorMessage}`);\n }\n\n if (!responseData || responseData.error_code === -40401 || responseData.error_code === -1) {\n this.log.debug(\"API request failed\", responseData);\n this.stok = undefined;\n return {} as TAPOCameraResponse;\n // return this.apiRequest(req, loginRetryCount + 1);\n }\n\n // Success\n return responseData;\n } finally {\n this.pendingAPIRequests.delete(reqJson);\n }\n })(),\n );\n\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n static SERVICE_MAP: Record<keyof Status, (value: boolean) => TAPOCameraSetRequest> = {\n eyes: (value) => ({\n method: \"setLensMaskConfig\",\n params: {\n lens_mask: {\n lens_mask_info: {\n // Watch out for the inversion\n enabled: value ? \"off\" : \"on\",\n },\n },\n },\n }),\n alarm: (value) => ({\n method: \"setAlertConfig\",\n params: {\n msg_alarm: {\n chn1_msg_alarm_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n notifications: (value) => ({\n method: \"setMsgPushConfig\",\n params: {\n msg_push: {\n chn1_msg_push_info: {\n notification_enabled: value ? \"on\" : \"off\",\n rich_notification_enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n motionDetection: (value) => ({\n method: \"setDetectionConfig\",\n params: {\n motion_detection: {\n motion_det: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n led: (value) => ({\n method: \"setLedStatus\",\n params: {\n led: {\n config: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n };\n\n async setStatus(service: keyof Status, value: boolean) {\n const responseData = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [TAPOCamera.SERVICE_MAP[service](value)],\n },\n });\n\n if (responseData.error_code !== 0) {\n this.log.error(`Failed to perform ${service} action`);\n }\n\n const method = TAPOCamera.SERVICE_MAP[service](value).method;\n const operation = responseData.result.responses.find((e) => e.method === method);\n if (operation?.error_code !== 0) {\n this.log.error(`Failed to perform ${service} action`);\n }\n\n return operation.result;\n }\n\n async getBasicInfo(): Promise<TAPOBasicInfo> {\n const responseData = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getDeviceInfo\",\n params: {\n device_info: {\n name: [\"basic_info\"],\n },\n },\n },\n ],\n },\n });\n\n const info = responseData.result.responses[0] as TAPOCameraResponseDeviceInfo;\n return info.result.device_info.basic_info;\n }\n\n async getStatus(): Promise<Status> {\n const responseData = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getAlertConfig\",\n params: {\n msg_alarm: {\n name: \"chn1_msg_alarm_info\",\n },\n },\n },\n {\n method: \"getLensMaskConfig\",\n params: {\n lens_mask: {\n name: \"lens_mask_info\",\n },\n },\n },\n {\n method: \"getMsgPushConfig\",\n params: {\n msg_push: {\n name: \"chn1_msg_push_info\",\n },\n },\n },\n {\n method: \"getDetectionConfig\",\n params: {\n motion_detection: {\n name: \"motion_det\",\n },\n },\n },\n {\n method: \"getLedStatus\",\n params: {\n led: {\n name: \"config\",\n },\n },\n },\n ],\n },\n });\n\n if (!responseData || !responseData.result || !responseData.result.responses) {\n this.log.error(\"No response data found\");\n return {\n alarm: undefined,\n eyes: undefined,\n notifications: undefined,\n motionDetection: undefined,\n led: undefined,\n };\n }\n const operations = responseData.result.responses;\n\n const alert = operations.find((r) => r.method === \"getAlertConfig\");\n const lensMask = operations.find((r) => r.method === \"getLensMaskConfig\");\n const notifications = operations.find((r) => r.method === \"getMsgPushConfig\");\n const motionDetection = operations.find((r) => r.method === \"getDetectionConfig\");\n const led = operations.find((r) => r.method === \"getLedStatus\");\n\n if (!alert) this.log.debug(\"No alert config found\");\n if (!lensMask) this.log.debug(\"No lens mask config found\");\n if (!notifications) this.log.debug(\"No notifications config found\");\n if (!motionDetection) this.log.debug(\"No motion detection config found\");\n if (!led) this.log.debug(\"No led config found\");\n\n return {\n alarm: alert ? alert.result.msg_alarm.chn1_msg_alarm_info.enabled === \"on\" : undefined,\n // Watch out for the inversion\n eyes: lensMask ? lensMask.result.lens_mask.lens_mask_info.enabled === \"off\" : undefined,\n notifications: notifications ? notifications.result.msg_push.chn1_msg_push_info.notification_enabled === \"on\" : undefined,\n motionDetection: motionDetection ? motionDetection.result.motion_detection.motion_det.enabled === \"on\" : undefined,\n led: led ? led.result.led.config.enabled === \"on\" : undefined,\n };\n }\n async setForceWhitelampState(value: boolean) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setForceWhitelampState\",\n params: {\n image: {\n switch: {\n force_wtl_state: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\n }\n async moveMotorStep(angle: string) {\n angle = angle.toString();\n const json = await this.apiRequest({ method: \"do\", motor: { movestep: { direction: angle } } });\n\n return json.error_code !== 0;\n }\n async moveToPreset(presetId: string) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: { requests: [{ method: \"motorMoveToPreset\", params: { goto_preset: { id: presetId } } }] },\n });\n\n return json.error_code !== 0;\n }\n\n async moveMotor(x: string, y: string) {\n const json = await this.apiRequest({\n method: \"do\",\n motor: { move: { x_coord: x, y_coord: y } },\n });\n\n return json.error_code !== 0;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["// import https, { Agent } from \"https\";\nimport crypto from \"crypto\";\nimport { OnvifCamera } from \"./onvifCamera\";\nimport type {\n TAPOBasicInfo,\n TAPOCameraEncryptedRequest,\n TAPOCameraEncryptedResponse,\n TAPOCameraLoginResponse,\n TAPOCameraRefreshStokResponse,\n TAPOCameraRequest,\n TAPOCameraResponse,\n TAPOCameraResponseDeviceInfo,\n TAPOCameraSetRequest,\n} from \"./types/tapo\";\n\nconst MAX_LOGIN_RETRIES = 3;\nconst AES_BLOCK_SIZE = 16;\n\nimport { Agent, setGlobalDispatcher } from \"undici\";\n\nconst ERROR_CODES_MAP = {\n \"-40401\": \"Invalid stok value\",\n \"-40210\": \"Function not supported\",\n \"-64303\": \"Action cannot be done while camera is in patrol mode.\",\n \"-64324\": \"Privacy mode is ON, not able to execute\",\n \"-64302\": \"Preset ID not found\",\n \"-64321\": \"Preset ID was deleted so no longer exists\",\n \"-40106\": \"Parameter to get/do does not exist\",\n \"-40105\": \"Method does not exist\",\n \"-40101\": \"Parameter to set does not exist\",\n \"-40209\": \"Invalid login credentials\",\n \"-64304\": \"Maximum Pan/Tilt range reached\",\n \"-71103\": \"User ID is not authorized\",\n};\n\nexport type Status = {\n eyes: boolean | undefined;\n alarm: boolean | undefined;\n notifications: boolean | undefined;\n motionDetection: boolean | undefined;\n led: boolean | undefined;\n};\ntype CameraConfig = {\n name: string;\n ipAddress: string;\n username: string;\n password: string;\n streamUser: string;\n streamPassword: string;\n\n pullInterval?: number;\n disableStreaming?: boolean;\n disableEyesToggleAccessory?: boolean;\n disableAlarmToggleAccessory?: boolean;\n disableNotificationsToggleAccessory?: boolean;\n disableMotionDetectionToggleAccessory?: boolean;\n disableLEDToggleAccessory?: boolean;\n\n disableMotionSensorAccessory?: boolean;\n lowQuality?: boolean;\n\n videoMaxWidth?: number;\n videoMaxHeight?: number;\n videoMaxFPS?: number;\n videoForceMax?: boolean;\n videoMaxBirate?: number;\n videoPacketSize?: number;\n videoCodec?: string;\n\n videoConfig?: VideoConfig;\n\n eyesToggleAccessoryName?: string;\n alarmToggleAccessoryName?: string;\n notificationsToggleAccessoryName?: string;\n motionDetectionToggleAccessoryName?: string;\n ledToggleAccessoryName?: string;\n};\nexport class TAPOCamera extends OnvifCamera {\n private readonly kStreamPort = 554;\n private readonly fetchAgent: Agent;\n\n private readonly hashedPassword: string;\n private readonly hashedSha256Password: string;\n private passwordEncryptionMethod: \"md5\" | \"sha256\" | null = null;\n\n private isSecureConnectionValue: boolean | null = null;\n\n private stokPromise: (() => Promise<void>) | undefined;\n\n private readonly cnonce: string;\n private lsk: Buffer | undefined;\n private ivb: Buffer | undefined;\n private seq: number | undefined;\n private stok: string | undefined;\n\n constructor(\n protected readonly log: any,\n protected readonly config: CameraConfig,\n ) {\n super(log, config);\n process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;\n this.fetchAgent = new Agent({\n connectTimeout: 5_000,\n connect: {\n // TAPO devices have self-signed certificates\n rejectUnauthorized: false,\n ciphers: \"AES256-SHA:AES128-GCM-SHA256\",\n },\n });\n setGlobalDispatcher(this.fetchAgent);\n\n this.cnonce = this.generateCnonce();\n\n this.hashedPassword = crypto.createHash(\"md5\").update(config.password).digest(\"hex\").toUpperCase();\n this.hashedSha256Password = crypto.createHash(\"sha256\").update(config.password).digest(\"hex\").toUpperCase();\n }\n\n private getUsername() {\n return this.config.username || \"admin\";\n }\n\n private getHeaders(): Record<string, string> {\n return {\n Host: `https://${this.config.ipAddress}`,\n Referer: `https://${this.config.ipAddress}`,\n Accept: \"application/json\",\n \"Accept-Encoding\": \"gzip, deflate\",\n \"User-Agent\": \"Tapo CameraClient Android\",\n Connection: \"close\",\n requestByApp: \"true\",\n \"Content-Type\": \"application/json; charset=UTF-8\",\n };\n }\n\n private getHashedPassword() {\n if (this.passwordEncryptionMethod === \"md5\") {\n return this.hashedPassword;\n } else if (this.passwordEncryptionMethod === \"sha256\") {\n return this.hashedSha256Password;\n } else {\n this.log.error(\"Unknown password encryption method\");\n }\n }\n\n private fetch(url: string, data: RequestInit) {\n return fetch(url, {\n headers: this.getHeaders(),\n // @ts-expect-error Dispatcher type not there\n dispatcher: this.fetchAgent,\n ...data,\n });\n }\n\n private generateEncryptionToken(tokenType: string, nonce: string): Buffer {\n const hashedKey = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.getHashedPassword() + nonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tokenType + this.cnonce + nonce + hashedKey)\n .digest()\n .slice(0, 16);\n }\n\n getAuthenticatedStreamUrl(lowQuality = false) {\n const prefix = `rtsp://${this.config.streamUser}:${this.config.streamPassword}@${this.config.ipAddress}:${this.kStreamPort}`;\n return lowQuality ? `${prefix}/stream2` : `${prefix}/stream1`;\n }\n\n private generateCnonce() {\n return crypto.randomBytes(8).toString(\"hex\").toUpperCase();\n }\n\n private validateDeviceConfirm(nonce: string, deviceConfirm: string) {\n this.passwordEncryptionMethod = null;\n\n const hashedNoncesWithSHA256 = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.hashedSha256Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n if (deviceConfirm === hashedNoncesWithSHA256 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"sha256\";\n return true;\n }\n\n const hashedNoncesWithMD5 = crypto\n .createHash(\"md5\")\n .update(this.cnonce + this.hashedPassword + nonce)\n .digest(\"hex\")\n .toUpperCase();\n if (deviceConfirm === hashedNoncesWithMD5 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"md5\";\n return true;\n }\n\n this.log.debug('Invalid device confirm, expected \"sha256\" or \"md5\" to match, but none found', {\n hashedNoncesWithMD5,\n hashedNoncesWithSHA256,\n deviceConfirm,\n nonce,\n cnonce: this,\n });\n\n return this.passwordEncryptionMethod !== null;\n }\n\n async refreshStok(loginRetryCount = 0): Promise<void> {\n this.log.debug(\"refreshStok: Refreshing stok...\");\n\n const isSecureConnection = await this.isSecureConnection();\n\n let fetchParams = {};\n if (isSecureConnection) {\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n };\n } else {\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n username: this.getUsername(),\n password: this.hashedPassword,\n hashed: true,\n },\n }),\n };\n }\n\n const responseLogin = await this.fetch(`https://${this.config.ipAddress}`, fetchParams).catch((e) => {\n this.log.debug(\"refreshStok: Error during login\", e);\n return null;\n });\n if (!responseLogin) {\n this.log.debug(\"refreshStok: empty response login, raising exception\");\n this.log.error(\"Empty response login\");\n return;\n }\n const responseLoginData = (await responseLogin.json()) as TAPOCameraRefreshStokResponse;\n\n let response, responseData;\n\n if (!responseLoginData) {\n this.log.debug(\"refreshStok: empty response login data, raising exception\", responseLogin.status);\n this.log.error(\"Empty response login data\");\n }\n\n this.log.debug(\"refreshStok: Login response\", responseLogin.status, responseLoginData);\n\n if (responseLogin.status === 401 && responseLoginData.result?.data?.code === -40411) {\n this.log.debug(\"refreshStok: invalid credentials, raising exception\", responseLogin.status);\n this.log.error(\"Invalid credentials\");\n }\n\n if (isSecureConnection) {\n const nonce = responseLoginData.result?.data?.nonce;\n const deviceConfirm = responseLoginData.result?.data?.device_confirm;\n if (nonce && deviceConfirm && this.validateDeviceConfirm(nonce, deviceConfirm)) {\n const digestPasswd = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n const digestPasswdFull = Buffer.concat([\n Buffer.from(digestPasswd, \"utf8\"),\n Buffer.from(this.cnonce!, \"utf8\"),\n Buffer.from(nonce, \"utf8\"),\n ]).toString(\"utf8\");\n\n this.log.debug(\"refreshStok: sending start_seq request\");\n\n response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"POST\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n cnonce: this.cnonce,\n encrypt_type: \"3\",\n digest_passwd: digestPasswdFull,\n username: this.getUsername(),\n },\n }),\n });\n\n responseData = (await response.json()) as TAPOCameraRefreshStokResponse;\n\n if (!responseData) {\n this.log.debug(\"refreshStock: empty response start_seq data, raising exception\", response.status);\n this.log.error(\"Empty response start_seq data\");\n return;\n }\n\n this.log.debug(\"refreshStok: start_seq response\", response.status, JSON.stringify(responseData));\n\n if (responseData.result?.start_seq) {\n if (responseData.result?.user_group !== \"root\") {\n this.log.debug(\"refreshStock: Incorrect user_group detected\");\n\n // # encrypted control via 3rd party account does not seem to be supported\n // # see https://github.com/JurajNyiri/HomeAssistant-Tapo-Control/issues/456\n this.log.error(\"Incorrect user_group detected\");\n }\n\n this.lsk = this.generateEncryptionToken(\"lsk\", nonce);\n this.ivb = this.generateEncryptionToken(\"ivb\", nonce);\n this.seq = responseData.result.start_seq;\n }\n } else {\n if (responseLoginData.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `refreshStock: Invalid device confirm, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.`,\n responseLogin.status,\n responseLoginData,\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n this.log.debug(\n \"refreshStock: Invalid device confirm and loginRetryCount exhausted, raising exception\",\n loginRetryCount,\n responseLoginData,\n );\n this.log.error(\"Invalid device confirm. Please activate 3rd Patry support in the TP App under TP Labor -> 3rd Party Control\");\n return;\n }\n } else {\n this.passwordEncryptionMethod = \"md5\";\n response = responseLogin;\n responseData = responseLoginData;\n }\n\n if (responseData.result?.data?.sec_left && responseData.result.data.sec_left > 0) {\n this.log.debug(\"refreshStok: temporary suspension\", responseData);\n\n this.log.error(`Temporary Suspension: Try again in ${responseData.result.data.sec_left} seconds`);\n }\n if (responseData && responseData.result && responseData.result.responses && responseData.result.responses[0].error_code !== 0) {\n this.log.debug(\n `API request failed with specific error code ${responseData.result.responses[0].error_code}: ${responseData.result.responses[0].error_message}`,\n );\n }\n\n if (responseData?.data?.code === -40404 && responseData?.data?.sec_left && responseData.data.sec_left > 0) {\n this.log.debug(\"refreshStok: temporary suspension\", responseData);\n\n this.log.error(`refreshStok: Temporary Suspension: Try again in ${responseData.data.sec_left} seconds`);\n }\n\n if (responseData?.result?.stok) {\n this.stok = responseData.result.stok;\n this.log.debug(\"refreshStok: Success in obtaining STOK\", this.stok);\n return;\n }\n\n if (responseData?.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `refreshStock: Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.`,\n response.status,\n responseData,\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n this.log.debug(\"refreshStock: Unexpected end of flow, raising exception\");\n this.log.error(\"Invalid authentication data\");\n }\n\n async isSecureConnection() {\n if (this.isSecureConnectionValue === null) {\n this.log.debug(\"isSecureConnection: Checking secure connection...\");\n\n const response = await this.fetch(`https://${this.config.ipAddress}`, {\n method: \"post\",\n headers: this.getHeaders(),\n body: JSON.stringify({\n method: \"login\",\n params: {\n encrypt_type: \"3\",\n username: this.getUsername(),\n },\n }),\n });\n const responseData = (await response.json()) as TAPOCameraLoginResponse;\n\n this.log.debug(\"isSecureConnection response\", response.status, JSON.stringify(responseData));\n\n this.isSecureConnectionValue =\n responseData?.error_code == -40413 && String(responseData.result?.data?.encrypt_type || \"\")?.includes(\"3\");\n }\n\n return this.isSecureConnectionValue;\n }\n\n getStok(loginRetryCount = 0): Promise<string> {\n return new Promise((resolve) => {\n if (this.stok) {\n return resolve(this.stok);\n }\n\n if (!this.stokPromise) {\n this.stokPromise = () => this.refreshStok(loginRetryCount);\n }\n\n this.stokPromise()\n .then(() => {\n if (!this.stok) {\n this.log.error(\"STOK not found\");\n }\n resolve(this.stok!);\n })\n .finally(() => {\n this.stokPromise = undefined;\n });\n });\n }\n\n private async getAuthenticatedAPIURL(loginRetryCount = 0) {\n const token = await this.getStok(loginRetryCount);\n return `https://${this.config.ipAddress}/stok=${token}/ds`;\n }\n\n encryptRequest(request: string) {\n const cipher = crypto.createCipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let ct_bytes = cipher.update(this.encryptPad(request, AES_BLOCK_SIZE), \"utf-8\", \"hex\");\n ct_bytes += cipher.final(\"hex\");\n return Buffer.from(ct_bytes, \"hex\");\n }\n\n private encryptPad(text: string, blocksize: number) {\n const padSize = blocksize - (text.length % blocksize);\n const padding = String.fromCharCode(padSize).repeat(padSize);\n return text + padding;\n }\n\n private decryptResponse(response: string): string {\n const decipher = crypto.createDecipheriv(\"aes-128-cbc\", this.lsk!, this.ivb!);\n let decrypted = decipher.update(response, \"base64\", \"utf-8\");\n decrypted += decipher.final(\"utf-8\");\n return this.encryptUnpad(decrypted, AES_BLOCK_SIZE);\n }\n\n private encryptUnpad(text: string, blockSize: number): string {\n const paddingLength = Number(text[text.length - 1]) || 0;\n if (paddingLength > blockSize || paddingLength > text.length) {\n this.log.error(\"Invalid padding\");\n }\n for (let i = text.length - paddingLength; i < text.length; i++) {\n if (text.charCodeAt(i) !== paddingLength) {\n this.log.error(\"Invalid padding\");\n }\n }\n return text.slice(0, text.length - paddingLength).toString();\n }\n\n private getTapoTag(request: TAPOCameraEncryptedRequest) {\n const tag = crypto\n .createHash(\"sha256\")\n .update(this.getHashedPassword() + this.cnonce)\n .digest(\"hex\")\n .toUpperCase();\n return crypto\n .createHash(\"sha256\")\n .update(tag + JSON.stringify(request) + this.seq!.toString())\n .digest(\"hex\")\n .toUpperCase();\n }\n\n private pendingAPIRequests: Map<string, Promise<TAPOCameraResponse>> = new Map();\n\n private async apiRequest(req: TAPOCameraRequest, loginRetryCount = 0): Promise<TAPOCameraResponse> {\n const reqJson = JSON.stringify(req);\n\n if (this.pendingAPIRequests.has(reqJson)) {\n this.log.debug(\"API request already pending\", reqJson);\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n } else {\n this.log.debug(\"New API request\", reqJson);\n }\n\n this.pendingAPIRequests.set(\n reqJson,\n (async () => {\n try {\n const isSecureConnection = await this.isSecureConnection();\n const url = await this.getAuthenticatedAPIURL(loginRetryCount);\n\n const fetchParams: RequestInit = {\n method: \"post\",\n };\n\n if (this.seq && isSecureConnection) {\n const encryptedRequest: TAPOCameraEncryptedRequest = {\n method: \"securePassthrough\",\n params: {\n request: Buffer.from(this.encryptRequest(JSON.stringify(req))).toString(\"base64\"),\n },\n };\n fetchParams.headers = {\n ...this.getHeaders(),\n Tapo_tag: this.getTapoTag(encryptedRequest),\n Seq: this.seq.toString(),\n };\n fetchParams.body = JSON.stringify(encryptedRequest);\n this.seq += 1;\n } else {\n fetchParams.body = JSON.stringify(req);\n }\n\n const response = await this.fetch(url, fetchParams).catch((e) => {\n this.log.debug(\"Error during camera fetch\", e);\n return;\n });\n if (!response) {\n this.log.debug(\"API request failed, empty response\");\n return {} as TAPOCameraResponse;\n }\n const responseDataTmp = await response.json();\n\n // Apparently the Tapo C200 returns 500 on successful requests,\n // but it's indicating an expiring token, therefore refresh the token next time\n if (isSecureConnection && response.status === 500) {\n this.log.debug(\"Stok expired, reauthenticating on next request, setting STOK to undefined\");\n this.stok = undefined;\n }\n\n let responseData: TAPOCameraResponse | null = null;\n\n if (isSecureConnection) {\n const encryptedResponse = responseDataTmp as TAPOCameraEncryptedResponse;\n if (encryptedResponse?.result?.response) {\n const decryptedResponse = this.decryptResponse(encryptedResponse.result.response);\n responseData = JSON.parse(decryptedResponse) as TAPOCameraResponse;\n }\n } else {\n responseData = responseDataTmp as TAPOCameraResponse;\n }\n\n this.log.debug(\"API response\", response.status, JSON.stringify(responseData));\n\n // Log error codes\n if (responseData && responseData.error_code !== 0) {\n const errorCode = String(responseData.error_code);\n const errorMessage =\n errorCode in ERROR_CODES_MAP ? ERROR_CODES_MAP[errorCode as keyof typeof ERROR_CODES_MAP] : \"Unknown error\";\n this.log.debug(`API request failed with specific error code ${errorCode}: ${errorMessage}`);\n }\n\n if (!responseData || responseData.error_code === -40401 || responseData.error_code === -1) {\n this.log.debug(\"API request failed\", responseData);\n this.stok = undefined;\n return {} as TAPOCameraResponse;\n // return this.apiRequest(req, loginRetryCount + 1);\n }\n\n // Success\n return responseData;\n } finally {\n this.pendingAPIRequests.delete(reqJson);\n }\n })(),\n );\n\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n static SERVICE_MAP: Record<keyof Status, (value: boolean) => TAPOCameraSetRequest> = {\n eyes: (value) => ({\n method: \"setLensMaskConfig\",\n params: {\n lens_mask: {\n lens_mask_info: {\n // Watch out for the inversion\n enabled: value ? \"off\" : \"on\",\n },\n },\n },\n }),\n alarm: (value) => ({\n method: \"setAlertConfig\",\n params: {\n msg_alarm: {\n chn1_msg_alarm_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n notifications: (value) => ({\n method: \"setMsgPushConfig\",\n params: {\n msg_push: {\n chn1_msg_push_info: {\n notification_enabled: value ? \"on\" : \"off\",\n rich_notification_enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n motionDetection: (value) => ({\n method: \"setDetectionConfig\",\n params: {\n motion_detection: {\n motion_det: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n led: (value) => ({\n method: \"setLedStatus\",\n params: {\n led: {\n config: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n }),\n };\n\n async setStatus(service: keyof Status, value: boolean) {\n const responseData = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [TAPOCamera.SERVICE_MAP[service](value)],\n },\n });\n\n if (responseData.error_code !== 0) {\n this.log.error(`Failed to perform ${service} action`);\n }\n\n const method = TAPOCamera.SERVICE_MAP[service](value).method;\n const operation = responseData.result.responses.find((e) => e.method === method);\n if (operation?.error_code !== 0) {\n this.log.error(`Failed to perform ${service} action`);\n }\n\n return operation.result;\n }\n\n async getBasicInfo(): Promise<TAPOBasicInfo> {\n const responseData = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getDeviceInfo\",\n params: {\n device_info: {\n name: [\"basic_info\"],\n },\n },\n },\n ],\n },\n });\n\n const info = responseData.result.responses[0] as TAPOCameraResponseDeviceInfo;\n return info.result.device_info.basic_info;\n }\n\n async getStatus(): Promise<Status> {\n const responseData = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"getAlertConfig\",\n params: {\n msg_alarm: {\n name: \"chn1_msg_alarm_info\",\n },\n },\n },\n {\n method: \"getLensMaskConfig\",\n params: {\n lens_mask: {\n name: \"lens_mask_info\",\n },\n },\n },\n {\n method: \"getMsgPushConfig\",\n params: {\n msg_push: {\n name: \"chn1_msg_push_info\",\n },\n },\n },\n {\n method: \"getDetectionConfig\",\n params: {\n motion_detection: {\n name: \"motion_det\",\n },\n },\n },\n {\n method: \"getLedStatus\",\n params: {\n led: {\n name: \"config\",\n },\n },\n },\n ],\n },\n });\n\n if (!responseData || !responseData.result || !responseData.result.responses) {\n this.log.error(\"No response data found\");\n return {\n alarm: undefined,\n eyes: undefined,\n notifications: undefined,\n motionDetection: undefined,\n led: undefined,\n };\n }\n const operations = responseData.result.responses;\n\n const alert = operations.find((r) => r.method === \"getAlertConfig\");\n const lensMask = operations.find((r) => r.method === \"getLensMaskConfig\");\n const notifications = operations.find((r) => r.method === \"getMsgPushConfig\");\n const motionDetection = operations.find((r) => r.method === \"getDetectionConfig\");\n const led = operations.find((r) => r.method === \"getLedStatus\");\n\n if (!alert) this.log.debug(\"No alert config found\");\n if (!lensMask) this.log.debug(\"No lens mask config found\");\n if (!notifications) this.log.debug(\"No notifications config found\");\n if (!motionDetection) this.log.debug(\"No motion detection config found\");\n if (!led) this.log.debug(\"No led config found\");\n\n return {\n alarm: alert ? alert.result.msg_alarm.chn1_msg_alarm_info.enabled === \"on\" : undefined,\n // Watch out for the inversion\n eyes: lensMask ? lensMask.result.lens_mask.lens_mask_info.enabled === \"off\" : undefined,\n notifications: notifications ? notifications.result.msg_push.chn1_msg_push_info.notification_enabled === \"on\" : undefined,\n motionDetection: motionDetection ? motionDetection.result.motion_detection.motion_det.enabled === \"on\" : undefined,\n led: led ? led.result.led.config.enabled === \"on\" : undefined,\n };\n }\n async setForceWhitelampState(value: boolean) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setForceWhitelampState\",\n params: {\n image: {\n switch: {\n force_wtl_state: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\n }\n async moveMotorStep(angle: string) {\n angle = angle.toString();\n const json = await this.apiRequest({ method: \"do\", motor: { movestep: { direction: angle } } });\n\n return json.error_code !== 0;\n }\n async moveToPreset(presetId: string) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: { requests: [{ method: \"motorMoveToPreset\", params: { goto_preset: { id: presetId } } }] },\n });\n\n return json.error_code !== 0;\n }\n\n async moveMotor(x: string, y: string) {\n const json = await this.apiRequest({\n method: \"do\",\n motor: { move: { x_coord: x, y_coord: y } },\n });\n\n return json.error_code !== 0;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["crypto"]
|
|
7
7
|
}
|
package/build/main.js
CHANGED
|
@@ -39,6 +39,8 @@ class Tapo extends utils.Adapter {
|
|
|
39
39
|
this.reLoginTimeout = null;
|
|
40
40
|
this.refreshTokenTimeout = null;
|
|
41
41
|
this.session = {};
|
|
42
|
+
this.firstStart = true;
|
|
43
|
+
this.lastBatteryDeviceUpdateTimestamp = 0;
|
|
42
44
|
this.on("ready", this.onReady.bind(this));
|
|
43
45
|
this.on("stateChange", this.onStateChange.bind(this));
|
|
44
46
|
this.on("unload", this.onUnload.bind(this));
|
|
@@ -96,6 +98,7 @@ class Tapo extends utils.Adapter {
|
|
|
96
98
|
this.log.error("Please set username and password in the instance settings");
|
|
97
99
|
return;
|
|
98
100
|
}
|
|
101
|
+
this.config.username = this.config.username.toLowerCase();
|
|
99
102
|
this.updateInterval = null;
|
|
100
103
|
this.reLoginTimeout = null;
|
|
101
104
|
this.refreshTokenTimeout = null;
|
|
@@ -145,6 +148,7 @@ class Tapo extends utils.Adapter {
|
|
|
145
148
|
await this.sleep(1e4);
|
|
146
149
|
this.log.info("Start first Update");
|
|
147
150
|
this.updateDevices();
|
|
151
|
+
this.firstStart = false;
|
|
148
152
|
this.updateInterval = setInterval(async () => {
|
|
149
153
|
this.updateDevices();
|
|
150
154
|
}, this.config.interval * 1e3);
|
|
@@ -516,6 +520,10 @@ class Tapo extends utils.Adapter {
|
|
|
516
520
|
} else if (device.deviceName.startsWith("L") || device.deviceName.startsWith("KL")) {
|
|
517
521
|
deviceObject = new import_l510e.default(this.log, device.ip, this.config.username, this.config.password, 2);
|
|
518
522
|
} else if (device.deviceName.startsWith("C") || device.deviceName.startsWith("TC")) {
|
|
523
|
+
if (device.deviceName.startsWith("C4") && !this.config.enableBatteryDevices) {
|
|
524
|
+
this.log.warn("Battery device found but ignored. Please enable in settings and check regularly the battery status");
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
519
527
|
if (!this.config.streamusername || !this.config.streampassword) {
|
|
520
528
|
this.log.warn(`No stream username or password. No motion detection available`);
|
|
521
529
|
}
|
|
@@ -618,8 +626,14 @@ class Tapo extends utils.Adapter {
|
|
|
618
626
|
this.log.debug(JSON.stringify(status));
|
|
619
627
|
this.json2iob.parse(deviceId, status);
|
|
620
628
|
if (this.deviceObjects[deviceId].stok === void 0) {
|
|
621
|
-
this.
|
|
622
|
-
|
|
629
|
+
if (this.firstStart) {
|
|
630
|
+
this.log.error("No stok found for: " + deviceId + " Ignore and remove the device until next restart");
|
|
631
|
+
delete this.deviceObjects[deviceId];
|
|
632
|
+
} else {
|
|
633
|
+
this.log.info(
|
|
634
|
+
"No stok found for: " + deviceId + " this means the device is offline or connection lost. No update or commands possible"
|
|
635
|
+
);
|
|
636
|
+
}
|
|
623
637
|
}
|
|
624
638
|
continue;
|
|
625
639
|
}
|
|
@@ -733,7 +747,11 @@ class Tapo extends utils.Adapter {
|
|
|
733
747
|
this.updateDevices();
|
|
734
748
|
}, 2 * 1e3);
|
|
735
749
|
} else {
|
|
736
|
-
this.
|
|
750
|
+
if (this.deviceObjects[deviceId]) {
|
|
751
|
+
this.log.error(`Device ${deviceId} has no command ${command}`);
|
|
752
|
+
} else {
|
|
753
|
+
this.log.error(`Device ${deviceId} not found`);
|
|
754
|
+
}
|
|
737
755
|
}
|
|
738
756
|
} catch (error) {
|
|
739
757
|
this.log.error(error);
|
package/build/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/main.ts"],
|
|
4
|
-
"sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.1.1\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\nimport axios, { AxiosInstance } from \"axios\";\nimport crypto from \"crypto\";\nimport https from \"https\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport Json2iob from \"json2iob\";\nimport { TAPOCamera } from \"./lib/utils/camera/tapoCamera\";\nimport L510E from \"./lib/utils/l510e\";\nimport L520E from \"./lib/utils/l520e\";\nimport L530 from \"./lib/utils/l530\";\nimport P100 from \"./lib/utils/p100\";\nimport P110 from \"./lib/utils/p110\";\n// Using ESM import syntax\nimport got from \"got\";\nclass Tapo extends utils.Adapter {\n private devices: { [key: string]: any };\n private deviceObjects: { [key: string]: any };\n private json2iob: Json2iob;\n private secret: Buffer;\n private requestClient: AxiosInstance;\n updateInterval: any = null;\n reLoginTimeout: any = null;\n refreshTokenTimeout: any = null;\n session: any = {};\n refreshTimeout: any;\n refreshTokenInterval: any;\n\n termId: any;\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({\n ...options,\n name: \"tapo\",\n });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"stateChange\", this.onStateChange.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n this.devices = {};\n this.deviceObjects = {};\n this.json2iob = new Json2iob(this);\n this.requestClient = axios.create({\n httpsAgent: new https.Agent({\n rejectUnauthorized: false,\n secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,\n }),\n });\n this.secret = Buffer.from([\n 54, 101, 100, 55, 100, 57, 55, 102, 51, 101, 55, 51, 52, 54, 55, 102, 56, 97, 53, 98, 97, 98, 57, 48, 98, 53, 55, 55, 98, 97, 52, 99,\n ]);\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise<void> {\n this.setState(\"info.connection\", false, true);\n if (this.config.interval < 0.5) {\n this.log.info(\"Set interval to minimum 0.5\");\n this.config.interval = 0.5;\n }\n if (!this.config.username || !this.config.password) {\n this.log.error(\"Please set username and password in the instance settings\");\n return;\n }\n\n this.updateInterval = null;\n this.reLoginTimeout = null;\n this.refreshTokenTimeout = null;\n this.session = {};\n this.subscribeStates(\"*\");\n\n const termIdState = await this.getStateAsync(\"termId\");\n if (termIdState && termIdState.val) {\n this.termId = termIdState.val;\n } else {\n await this.setObjectNotExistsAsync(\"termId\", {\n type: \"state\",\n common: {\n name: \"Terminal ID\",\n write: false,\n read: true,\n type: \"string\",\n role: \"text\",\n },\n native: {},\n });\n this.termId = uuidv4();\n await this.setStateAsync(\"termId\", this.termId, true);\n }\n\n this.log.info(\"Login tp TAPO App\");\n await this.login();\n if (this.session.token) {\n await this.getDeviceList();\n } else {\n this.log.warn(\"Login failed using cached device list\");\n const deviceListState = await this.getStateAsync(\"deviceList\");\n if (deviceListState && deviceListState.val) {\n this.log.info(\"Use cached device list\");\n this.devices = JSON.parse(deviceListState.val);\n for (const id in this.devices) {\n if (this.devices[id].ip) {\n const initResult = await this.initDevice(id)\n .then(() => {\n this.log.info(`Initialized ${id}`);\n })\n .catch((e) => {\n this.log.error(e);\n });\n this.log.debug(`initResult ${id} ${JSON.stringify(initResult)}`);\n }\n }\n }\n }\n\n this.log.info(\"Wait for connections for non camera devices\");\n await this.sleep(10000);\n this.log.info(\"Start first Update\");\n this.updateDevices();\n this.updateInterval = setInterval(async () => {\n this.updateDevices();\n }, this.config.interval * 1000);\n }\n async login(): Promise<void> {\n let body = JSON.stringify({\n appVersion: \"2.8.21\",\n refreshTokenNeeded: true,\n platform: \"iOS 14.8\",\n cloudPassword: this.config.password,\n terminalUUID: this.termId,\n cloudUserName: this.config.username,\n terminalName: \"ioBroker\",\n terminalMeta: \"3\",\n appType: \"TP-Link_Tapo_iOS\",\n });\n let path = \"api/v2/account/login\";\n const mfaIdState = await this.getStateAsync(\"mfaId\");\n if (mfaIdState && mfaIdState.val) {\n if (!this.config.mfa) {\n this.log.error(\"Please set mfa in the instance settings\");\n return;\n }\n\n body = JSON.stringify({\n cloudUserName: this.config.username,\n MFAProcessId: mfaIdState.val,\n appType: \"TP-Link_Tapo_iOS\",\n MFAType: 2,\n code: this.config.mfa,\n terminalBindEnabled: true,\n });\n path = \"api/v2/account/checkMFACodeAndLogin\";\n await this.setStateAsync(\"mfaId\", \"\", true);\n }\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/\" + path;\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url:\n \"https://n-wap-gw.tplinkcloud.com/\" +\n path +\n \"?termID=\" +\n this.termId +\n \"&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8\",\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n }\n if (res.data.result?.MFAProcessId) {\n this.log.info(\"Found MFA Process please enter MFA in the instance settings\");\n await this.setObjectNotExistsAsync(\"mfaId\", {\n type: \"state\",\n common: {\n name: \"MFA Id\",\n write: false,\n read: true,\n type: \"string\",\n role: \"text\",\n },\n native: {},\n });\n await this.setStateAsync(\"mfaId\", res.data.result?.MFAProcessId, true);\n\n const body = JSON.stringify({\n cloudPassword: this.config.password,\n locale: \"de_DE\",\n terminalUUID: this.termId,\n cloudUserName: this.config.username,\n appType: \"TP-Link_Tapo_iOS\",\n });\n\n const path = \"api/v2/account/getEmailVC4TerminalMFA\";\n\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/\" + path;\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url:\n \"https://n-wap-gw.tplinkcloud.com/\" +\n path +\n \"?termID=\" +\n this.termId +\n \"&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8\",\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n }\n })\n .catch((error) => {\n this.log.error(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n return;\n }\n\n if (!res.data.result || !res.data.result.token) {\n this.log.error(\"Login failed\");\n this.log.error(JSON.stringify(res.data));\n return;\n }\n this.session = res.data.result;\n if (this.session.token) {\n this.log.info(\"Login succesfull\");\n this.setState(\"info.connection\", true, true);\n }\n return;\n })\n .catch((error) => {\n this.log.error(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n }\n\n async getDeviceList(): Promise<void> {\n const body =\n '{\"index\":0,\"deviceTypeList\":[\"SMART.TAPOBULB\",\"SMART.TAPOPLUG\",\"SMART.IPCAMERA\",\"SMART.TAPOHUB\",\"SMART.TAPOSENSOR\",\"SMART.TAPOSWITCH\"],\"limit\":30}';\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/api/v2/common/getDeviceListByPage\";\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url: `https://n-euw1-wap-gw.tplinkcloud.com/api/v2/common/getDeviceListByPage?token=${this.session.token}&termID=${this.termId}&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8`,\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n \"Content-MD5\": md5,\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n }\n this.log.info(`Found ${res.data.result?.totalNum} devices`);\n\n for (const device of res.data.result?.deviceList) {\n const id = device.deviceId;\n this.devices[id] = device;\n let name = device.alias;\n\n if (this.isBase64(device.alias)) {\n name = Buffer.from(device.alias, \"base64\").toString(\"utf8\");\n }\n this.log.debug(`Found device ${id} ${name}`);\n await this.extendObject(id, {\n type: \"device\",\n common: {\n name: name,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(id + \".remote\", {\n type: \"channel\",\n common: {\n name: \"Remote Controls\",\n },\n native: {},\n });\n\n let remoteArray = [\n { command: \"refresh\", name: \"True = Refresh\" },\n { command: \"setPowerState\", name: \"True = On, False = Off\" },\n { command: \"setPowerStateChild\", name: \"childId,true\" },\n\n {\n command: \"setBrightness\",\n name: \"Set Brightness for Light devices\",\n type: \"number\",\n role: \"level.brightness\",\n def: 5,\n },\n {\n command: \"setColorTemp\",\n name: \"Set Color Temp for Light devices\",\n type: \"number\",\n role: \"level.color.temperature\",\n def: 3e3,\n },\n {\n command: \"setColor\",\n name: \"Set Color for Light devices (hue, saturation)\",\n def: \"30, 100\",\n type: \"string\",\n },\n ];\n if (device.deviceType.includes(\"CAMERA\")) {\n remoteArray = [\n { command: \"refresh\", name: \"True = Refresh\" },\n { command: \"setAlertConfig\", name: \"True = On, False = Off\" },\n { command: \"setLensMaskConfig\", name: \"True = On, False = Off\" },\n { command: \"setForceWhitelampState\", name: \"True = On, False = Off\" },\n { command: \"setLedStatus\", name: \"True = On, False = Off\" },\n { command: \"setMsgPushConfig\", name: \"True = On, False = Off\" },\n { command: \"setDetectionConfig\", name: \"True = On, False = Off\" },\n { command: \"moveMotor\", name: \"move Camera to X (-360,360), Y(-45,45)\", type: \"string\", def: \"0, 0\", role: \"text\" },\n { command: \"moveMotorStep\", name: \"Angle (0-360)\", type: \"string\", def: \"180\", role: \"text\" },\n { command: \"moveToPreset\", name: \"PresetId\", type: \"string\", def: \"1\", role: \"text\" },\n ];\n }\n remoteArray.forEach((remote) => {\n this.extendObject(id + \".remote.\" + remote.command, {\n type: \"state\",\n common: {\n name: remote.name || \"\",\n type: remote.type || \"boolean\",\n role: remote.role || \"switch\",\n def: remote.def != null ? remote.def : false,\n write: true,\n read: true,\n },\n native: {},\n });\n });\n this.json2iob.parse(id, device, { channelName: name });\n\n //try new API\n\n await this.requestClient({\n method: \"get\",\n url: \"https://euw1-app-server.iot.i.tplinknbu.com/v1/things/\" + id + \"/details\",\n headers: {\n \"x-locale\": \"de\",\n Authorization: \"ut|\" + this.session.token,\n \"app-cid\": \"app:TP-Link_Tapo_iOS:\" + this.termId,\n \"x-ospf\": \"iOS 14.8\",\n \"x-app-name\": \"TP-Link_Tapo_iOS\",\n Accept: \"*/*\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"Content-Type\": \"application/json;UTF-8\",\n \"User-Agent\": \"Tapo/2.9.7 (iPhone; iOS 14.8; Scale/3.00)\",\n \"x-term-id\": this.termId,\n \"x-app-version\": \"2.9.7\",\n \"x-net-type\": \"wifi\",\n },\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n } else {\n this.devices[id] = { ...this.devices[id], ...res.data };\n }\n })\n .catch((error) => {\n this.log.warn(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n //no ip via new API try old api\n if (!this.devices[id].ip) {\n const body = `{\n \"requestData\": {\n \"method\": \"multipleRequest\",\n \"params\": {\n \"requests\": [{\n \"method\": \"getDeviceIpAddress\",\n \"params\": {\n \"network\": {\n \"name\": \"wan\"\n }\n }\n }]\n }\n },\n \"deviceId\": \"${id}\"\n }`;\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/api/v2/common/passthrough\";\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url: `https://n-euw1-wap-gw.tplinkcloud.com/api/v2/common/passthrough?token=${this.session.token}&termID=${this.termId}&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8`,\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n \"Content-MD5\": md5,\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n let result: any = {};\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n } else {\n result = res.data.result?.responseData?.result?.responses[0]?.result?.network?.wan;\n result.ip = result.ipaddr;\n this.log.info(`Device ${id} has IP ${result.ip}`);\n delete result[\".name\"];\n delete result[\".type\"];\n // result = res.data.result?.responseData?.result;\n this.devices[id] = { ...this.devices[id], ...result };\n }\n })\n .catch((error) => {\n this.log.warn(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n }\n if (!this.devices[id].ip) {\n const ipState = await this.getStateAsync(id + \".ip\");\n if (ipState && ipState.val) {\n this.devices[id].ip = ipState.val;\n } else {\n await this.setObjectNotExistsAsync(id + \".ip\", {\n type: \"state\",\n common: {\n name: \"IP\",\n write: true,\n read: true,\n type: \"string\",\n role: \"text\",\n },\n native: {},\n });\n this.log.warn(`No IP found for ${id} put the device online or set the ip state manually`);\n }\n }\n this.json2iob.parse(id, this.devices[id]);\n if (this.devices[id].ip) {\n const initResult = await this.initDevice(id)\n .then(() => {\n this.log.info(`Initialized ${id}`);\n })\n .catch((e) => {\n this.log.error(e);\n });\n this.log.debug(`initResult camera ${id} ${JSON.stringify(initResult)}`);\n }\n }\n })\n .catch((error) => {\n this.log.warn(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n\n await this.setObjectNotExistsAsync(\"deviceList\", {\n type: \"state\",\n common: {\n name: \"Cached device list\",\n write: false,\n read: true,\n type: \"string\",\n role: \"json\",\n },\n native: {},\n });\n\n await this.setStateAsync(\"deviceList\", JSON.stringify(this.devices), true);\n }\n async initDevice(id: string): Promise<void> {\n const device = this.devices[id];\n if (!device.ip) {\n this.log.warn(`No IP found for ${id}`);\n return;\n }\n this.log.info(`Init device ${id} type ${device.deviceName} with ip ${device.ip}`);\n let deviceObject: any;\n if (device.deviceName === \"P100\") {\n deviceObject = new P100(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName.startsWith(\"P110\") || device.deviceName.startsWith(\"P115\")) {\n deviceObject = new P110(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName === \"L530\" || device.deviceName.startsWith(\"L630\")) {\n deviceObject = new L530(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName === \"L510E\") {\n deviceObject = new L510E(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName === \"L520E\") {\n deviceObject = new L520E(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName.startsWith(\"L\") || device.deviceName.startsWith(\"KL\")) {\n deviceObject = new L510E(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName.startsWith(\"C\") || device.deviceName.startsWith(\"TC\")) {\n if (!this.config.streamusername || !this.config.streampassword) {\n this.log.warn(`No stream username or password. No motion detection available`);\n }\n deviceObject = new TAPOCamera(this.log, {\n name: device.deviceName,\n ipAddress: device.ip,\n password: this.config.password,\n streamUser: this.config.streamusername,\n streamPassword: this.config.streampassword,\n disableStreaming: true,\n });\n\n //new Camera(this.log, device.ip, this.config.username, this.config.password, 2);\n\n this.deviceObjects[id] = deviceObject;\n const deviceInfo = await deviceObject.getDeviceInfo(true);\n this.log.info(`${id} Received device info ${JSON.stringify(deviceInfo)}`);\n this.log.debug(JSON.stringify(deviceInfo));\n this.json2iob.parse(id, deviceInfo);\n this.log.debug(`Init event emitter for ${id}`);\n const eventEmitter = await deviceObject.getEventEmitter();\n await this.setObjectNotExistsAsync(id + \".motionEvent\", {\n type: \"state\",\n common: {\n name: \"Motion detected\",\n type: \"boolean\",\n role: \"boolean\",\n def: false,\n write: false,\n read: true,\n },\n native: {},\n });\n this.log.debug('Init event listener for \"motion\"');\n eventEmitter.addListener(\"motion\", async (motionDetected: any) => {\n await this.setStateAsync(id + \".motionEvent\", motionDetected, true);\n this.log.debug(`[${device.deviceName}] \"Motion detected\" ${motionDetected}`);\n });\n return;\n } else {\n this.log.info(`Unknown device type ${device.deviceName} init as P100`);\n deviceObject = new P100(this.log, device.ip, this.config.username, this.config.password, 2);\n }\n this.deviceObjects[id] = deviceObject;\n await deviceObject\n .handshake()\n .then(async () => {\n if (deviceObject.is_klap) {\n this.log.debug(\"Detected KLAP device\");\n await deviceObject.handshake_new().catch(async (error: any) => {\n this.log.error(error);\n this.log.error(error.stack);\n this.log.error(\"KLAP Handshake failed. Try old handshake\");\n deviceObject.is_klap = false;\n await deviceObject.reAuthenticate().catch(() => {\n this.log.error(\"Login failed\");\n this.deviceObjects[id]._connected = false;\n });\n });\n } else {\n await deviceObject.login().catch(() => {\n this.log.error(\"Login failed\");\n this.deviceObjects[id]._connected = false;\n });\n }\n deviceObject\n .getDeviceInfo(true)\n .then(async (sysInfo: any) => {\n this.log.debug(JSON.stringify(sysInfo));\n if (sysInfo.request) {\n this.log.error(\"Malformed response sysinfo\");\n this.log.error(JSON.stringify(sysInfo));\n return;\n }\n this.json2iob.parse(id, sysInfo);\n\n this.deviceObjects[id]._connected = true;\n if (this.deviceObjects[id].getEnergyUsage) {\n this.log.debug(\"Receive energy usage\");\n const energyUsage = await this.deviceObjects[id].getEnergyUsage();\n this.log.debug(JSON.stringify(energyUsage));\n this.json2iob.parse(id, energyUsage);\n }\n const childList = await this.deviceObjects[id].getChildDevices();\n this.log.debug(\"Childlist: \" + JSON.stringify(childList));\n if (childList && childList.error_code === 0) {\n this.json2iob.parse(id + \".childlist\", childList);\n }\n })\n .catch((error: any) => {\n this.log.error(JSON.stringify(error));\n this.log.error(\"52 - Get Device Info failed\");\n\n this.deviceObjects[id]._connected = false;\n });\n })\n .catch(() => {\n this.log.error(\"Handshake failed\");\n this.deviceObjects[id]._connected = false;\n });\n }\n\n async updateDevices(): Promise<void> {\n try {\n for (const deviceId in this.deviceObjects) {\n if (this.deviceObjects[deviceId].getStatus) {\n this.log.debug(\"Receive camera status\");\n const status = await this.deviceObjects[deviceId].getStatus().catch((error: any) => {\n this.log.info(\"Get camera Status failed\");\n this.log.debug(JSON.stringify(error));\n });\n this.log.debug(JSON.stringify(status));\n this.json2iob.parse(deviceId, status);\n if (this.deviceObjects[deviceId].stok === undefined) {\n this.log.error(\"No stok found for: \" + deviceId + \" Ingore device until next restart\");\n\n delete this.deviceObjects[deviceId];\n }\n continue;\n }\n if (!this.deviceObjects[deviceId]._connected) {\n continue;\n }\n\n this.deviceObjects[deviceId]\n .getDeviceInfo(true)\n .then(async (sysInfo: any) => {\n this.log.debug(JSON.stringify(sysInfo));\n if (!sysInfo || sysInfo.name === \"Error\" || sysInfo.request) {\n this.log.debug(\"Malformed response sysinfo\");\n // this.log.error(JSON.stringify(sysInfo));\n return;\n }\n await this.json2iob.parse(deviceId, sysInfo);\n if (this.deviceObjects[deviceId].getEnergyUsage) {\n this.log.debug(\"Receive energy usage\");\n const energyUsage = await this.deviceObjects[deviceId].getEnergyUsage();\n this.log.debug(JSON.stringify(energyUsage));\n if (energyUsage.request) {\n this.log.error(\"Malformed response getEnergyUsage\");\n this.log.error(JSON.stringify(energyUsage));\n return;\n }\n await this.json2iob.parse(deviceId, energyUsage);\n const power_usage = this.deviceObjects[deviceId].getPowerConsumption();\n if (power_usage.request) {\n this.log.error(\"Malformed response getPowerConsumption\");\n this.log.error(JSON.stringify(power_usage));\n return;\n }\n await this.json2iob.parse(deviceId, power_usage);\n }\n })\n .catch((error: any) => {\n this.log.error(`Get Device Info failed for ${deviceId} - ${error}`);\n });\n }\n this.log.debug(\"Update done\");\n } catch (error: any) {\n this.log.warn(error);\n }\n }\n\n isBase64(str: string): boolean {\n if (str === \"\" || str.trim() === \"\") {\n return false;\n }\n try {\n const strWithoutPadding = str.replace(/=*$/, \"\");\n return btoa(atob(strWithoutPadding)) === strWithoutPadding || btoa(atob(str)) === str;\n } catch (err) {\n return false;\n }\n }\n async sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n async refreshToken(): Promise<void> {\n this.log.debug(\"Refresh token\");\n }\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n try {\n this.setState(\"info.connection\", false, true);\n this.refreshTimeout && clearTimeout(this.refreshTimeout);\n this.reLoginTimeout && clearTimeout(this.reLoginTimeout);\n this.refreshTokenTimeout && clearTimeout(this.refreshTokenTimeout);\n this.updateInterval && clearInterval(this.updateInterval);\n this.refreshTokenInterval && clearInterval(this.refreshTokenInterval);\n\n callback();\n } catch (e) {\n callback();\n }\n }\n\n /**\n * Is called if a subscribed state changes\n */\n private async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n if (state) {\n if (!state.ack) {\n const deviceId = id.split(\".\")[2];\n const command = id.split(\".\")[4];\n if (id.split(\".\")[3] !== \"remote\") {\n return;\n }\n\n if (command === \"Refresh\") {\n this.deviceObjects[deviceId]\n .getDeviceInfo(true)\n .then((sysInfo: any) => {\n this.log.debug(JSON.stringify(sysInfo));\n this.json2iob.parse(deviceId, sysInfo);\n })\n .catch((error) => {\n this.log.error(`Get Device Info failed for ${deviceId} - ${error}`);\n });\n\n return;\n }\n try {\n const cameraCommands: { [key: string]: string } = {\n setAlertConfig: \"alarm\",\n setLensMaskConfig: \"eyes\",\n setLedStatus: \"led\",\n setMsgPushConfig: \"notifications\",\n setDetectionConfig: \"motionDetection\",\n };\n if (this.deviceObjects[deviceId] && (this.deviceObjects[deviceId][command] || cameraCommands[command])) {\n let result;\n if (cameraCommands[command]) {\n result = await this.deviceObjects[deviceId].setStatus(cameraCommands[command], state.val);\n } else if (command === \"setColor\" || command === \"moveMotor\" || command === \"setPowerStateChild\") {\n const valueSplit = state.val.replace(\" \", \"\").split(\",\");\n result = await this.deviceObjects[deviceId][command](valueSplit[0], valueSplit[1]);\n } else {\n result = await this.deviceObjects[deviceId][command](state.val);\n }\n this.log.info(\n command + \" was set to : \" + state.val + \" for device \" + deviceId + \" was successful: \" + JSON.stringify(result),\n );\n this.refreshTimeout && clearTimeout(this.refreshTimeout);\n this.refreshTimeout = setTimeout(async () => {\n this.updateDevices();\n }, 2 * 1000);\n } else {\n this.log.error(`Device ${deviceId} has no command ${command}`);\n }\n } catch (error) {\n this.log.error(error);\n }\n } else {\n const resultDict: { [key: string]: string } = {\n device_on: \"setPowerState\",\n eyes: \"setLensMaskConfig\",\n alarm: \"setAlertConfig\",\n led: \"setLedStatus\",\n notifications: \"setMsgPushConfig\",\n motionDetection: \"setDetectionConfig\",\n };\n const idArray = id.split(\".\");\n const stateName = idArray[idArray.length - 1];\n const deviceId = id.split(\".\")[2];\n if (resultDict[stateName]) {\n await this.setState(deviceId + \".remote.\" + resultDict[stateName], state.val, true);\n }\n }\n }\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Tapo(options);\n} else {\n // otherwise start the instance directly\n (() => new Tapo())();\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAMA,YAAuB;AACvB,mBAAqC;AACrC,oBAAmB;AACnB,mBAAkB;AAClB,kBAA6B;AAC7B,sBAAqB;AACrB,wBAA2B;AAC3B,mBAAkB;AAClB,mBAAkB;AAClB,kBAAiB;AACjB,kBAAiB;AACjB,kBAAiB;AAGjB,MAAM,aAAa,MAAM,QAAQ;AAAA,EAcxB,YAAY,UAAyC,CAAC,GAAG;AAC9D,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,MAAM;AAAA,IACR,CAAC;AAZH,0BAAsB;AACtB,0BAAsB;AACtB,+BAA2B;AAC3B,mBAAe,CAAC;AAUd,SAAK,GAAG,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AACxC,SAAK,GAAG,eAAe,KAAK,cAAc,KAAK,IAAI,CAAC;AACpD,SAAK,GAAG,UAAU,KAAK,SAAS,KAAK,IAAI,CAAC;AAC1C,SAAK,UAAU,CAAC;AAChB,SAAK,gBAAgB,CAAC;AACtB,SAAK,WAAW,IAAI,gBAAAA,QAAS,IAAI;AACjC,SAAK,gBAAgB,aAAAC,QAAM,OAAO;AAAA,MAChC,YAAY,IAAI,aAAAC,QAAM,MAAM;AAAA,QAC1B,oBAAoB;AAAA,QACpB,eAAe,cAAAC,QAAO,UAAU;AAAA,MAClC,CAAC;AAAA,IACH,CAAC;AACD,SAAK,SAAS,OAAO,KAAK;AAAA,MACxB;AAAA,MAAI;AAAA,MAAK;AAAA,MAAK;AAAA,MAAI;AAAA,MAAK;AAAA,MAAI;AAAA,MAAI;AAAA,MAAK;AAAA,MAAI;AAAA,MAAK;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAK;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,MAAI;AAAA,IACpI,CAAC;AAAA,EACH;AAAA,EAKA,MAAc,UAAyB;AACrC,SAAK,SAAS,mBAAmB,OAAO,IAAI;AAC5C,QAAI,KAAK,OAAO,WAAW,KAAK;AAC9B,WAAK,IAAI,KAAK,6BAA6B;AAC3C,WAAK,OAAO,WAAW;AAAA,IACzB;AACA,QAAI,CAAC,KAAK,OAAO,YAAY,CAAC,KAAK,OAAO,UAAU;AAClD,WAAK,IAAI,MAAM,2DAA2D;AAC1E;AAAA,IACF;AAEA,SAAK,iBAAiB;AACtB,SAAK,iBAAiB;AACtB,SAAK,sBAAsB;AAC3B,SAAK,UAAU,CAAC;AAChB,SAAK,gBAAgB,GAAG;AAExB,UAAM,cAAc,MAAM,KAAK,cAAc,QAAQ;AACrD,QAAI,eAAe,YAAY,KAAK;AAClC,WAAK,SAAS,YAAY;AAAA,IAC5B,OAAO;AACL,YAAM,KAAK,wBAAwB,UAAU;AAAA,QAC3C,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,QACA,QAAQ,CAAC;AAAA,MACX,CAAC;AACD,WAAK,aAAS,YAAAC,IAAO;AACrB,YAAM,KAAK,cAAc,UAAU,KAAK,QAAQ,IAAI;AAAA,IACtD;AAEA,SAAK,IAAI,KAAK,mBAAmB;AACjC,UAAM,KAAK,MAAM;AACjB,QAAI,KAAK,QAAQ,OAAO;AACtB,YAAM,KAAK,cAAc;AAAA,IAC3B,OAAO;AACL,WAAK,IAAI,KAAK,uCAAuC;AACrD,YAAM,kBAAkB,MAAM,KAAK,cAAc,YAAY;AAC7D,UAAI,mBAAmB,gBAAgB,KAAK;AAC1C,aAAK,IAAI,KAAK,wBAAwB;AACtC,aAAK,UAAU,KAAK,MAAM,gBAAgB,GAAG;AAC7C,mBAAW,MAAM,KAAK,SAAS;AAC7B,cAAI,KAAK,QAAQ,IAAI,IAAI;AACvB,kBAAM,aAAa,MAAM,KAAK,WAAW,EAAE,EACxC,KAAK,MAAM;AACV,mBAAK,IAAI,KAAK,eAAe,IAAI;AAAA,YACnC,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,mBAAK,IAAI,MAAM,CAAC;AAAA,YAClB,CAAC;AACH,iBAAK,IAAI,MAAM,cAAc,MAAM,KAAK,UAAU,UAAU,GAAG;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,6CAA6C;AAC3D,UAAM,KAAK,MAAM,GAAK;AACtB,SAAK,IAAI,KAAK,oBAAoB;AAClC,SAAK,cAAc;AACnB,SAAK,iBAAiB,YAAY,YAAY;AAC5C,WAAK,cAAc;AAAA,IACrB,GAAG,KAAK,OAAO,WAAW,GAAI;AAAA,EAChC;AAAA,EACA,MAAM,QAAuB;AAC3B,QAAI,OAAO,KAAK,UAAU;AAAA,MACxB,YAAY;AAAA,MACZ,oBAAoB;AAAA,MACpB,UAAU;AAAA,MACV,eAAe,KAAK,OAAO;AAAA,MAC3B,cAAc,KAAK;AAAA,MACnB,eAAe,KAAK,OAAO;AAAA,MAC3B,cAAc;AAAA,MACd,cAAc;AAAA,MACd,SAAS;AAAA,IACX,CAAC;AACD,QAAI,OAAO;AACX,UAAM,aAAa,MAAM,KAAK,cAAc,OAAO;AACnD,QAAI,cAAc,WAAW,KAAK;AAChC,UAAI,CAAC,KAAK,OAAO,KAAK;AACpB,aAAK,IAAI,MAAM,yCAAyC;AACxD;AAAA,MACF;AAEA,aAAO,KAAK,UAAU;AAAA,QACpB,eAAe,KAAK,OAAO;AAAA,QAC3B,cAAc,WAAW;AAAA,QACzB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,MAAM,KAAK,OAAO;AAAA,QAClB,qBAAqB;AAAA,MACvB,CAAC;AACD,aAAO;AACP,YAAM,KAAK,cAAc,SAAS,IAAI,IAAI;AAAA,IAC5C;AACA,UAAM,MAAM,cAAAD,QAAO,WAAW,KAAK,EAAE,OAAO,IAAI,EAAE,OAAO,QAAQ;AACjE,SAAK,IAAI,MAAM,GAAG;AAClB,UAAM,UAAU,MAAM,0DAA0D;AAChF,UAAM,YAAY,cAAAA,QAAO,WAAW,QAAQ,KAAK,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AACrF,UAAM,KAAK,cAAc;AAAA,MACvB,QAAQ;AAAA,MACR,KACE,sCACA,OACA,aACA,KAAK,SACL;AAAA,MACF,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,mBACE,6HACA;AAAA,MACJ;AAAA,MACA,MAAM;AAAA,IACR,CAAC,EACE,KAAK,OAAO,QAAQ;AAtL3B;AAuLQ,WAAK,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AACvC,UAAI,IAAI,KAAK,YAAY;AACvB,aAAK,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AACvC;AAAA,MACF;AACA,WAAI,SAAI,KAAK,WAAT,mBAAiB,cAAc;AACjC,aAAK,IAAI,KAAK,6DAA6D;AAC3E,cAAM,KAAK,wBAAwB,SAAS;AAAA,UAC1C,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,OAAO;AAAA,YACP,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AACD,cAAM,KAAK,cAAc,UAAS,SAAI,KAAK,WAAT,mBAAiB,cAAc,IAAI;AAErE,cAAME,QAAO,KAAK,UAAU;AAAA,UAC1B,eAAe,KAAK,OAAO;AAAA,UAC3B,QAAQ;AAAA,UACR,cAAc,KAAK;AAAA,UACnB,eAAe,KAAK,OAAO;AAAA,UAC3B,SAAS;AAAA,QACX,CAAC;AAED,cAAMC,QAAO;AAEb,cAAMC,OAAM,cAAAJ,QAAO,WAAW,KAAK,EAAE,OAAOE,KAAI,EAAE,OAAO,QAAQ;AACjE,aAAK,IAAI,MAAME,IAAG;AAClB,cAAMC,WAAUD,OAAM,0DAA0DD;AAChF,cAAMG,aAAY,cAAAN,QAAO,WAAW,QAAQ,KAAK,MAAM,EAAE,OAAOK,QAAO,EAAE,OAAO,KAAK;AACrF,cAAM,KAAK,cAAc;AAAA,UACvB,QAAQ;AAAA,UACR,KACE,sCACAF,QACA,aACA,KAAK,SACL;AAAA,UACF,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,QAAQ;AAAA,YACR,cAAc;AAAA,YACd,mBAAmB;AAAA,YACnB,mBACE,6HACAG;AAAA,UACJ;AAAA,UACA,MAAMJ;AAAA,QACR,CAAC,EACE,KAAK,OAAOK,SAAQ;AACnB,eAAK,IAAI,MAAM,KAAK,UAAUA,KAAI,IAAI,CAAC;AACvC,cAAIA,KAAI,KAAK,YAAY;AACvB,iBAAK,IAAI,MAAM,KAAK,UAAUA,KAAI,IAAI,CAAC;AACvC;AAAA,UACF;AAAA,QACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,eAAK,IAAI,MAAM,KAAK;AACpB,gBAAM,YAAY,KAAK,IAAI,MAAM,KAAK,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,QACtE,CAAC;AACH;AAAA,MACF;AAEA,UAAI,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,KAAK,OAAO,OAAO;AAC9C,aAAK,IAAI,MAAM,cAAc;AAC7B,aAAK,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AACvC;AAAA,MACF;AACA,WAAK,UAAU,IAAI,KAAK;AACxB,UAAI,KAAK,QAAQ,OAAO;AACtB,aAAK,IAAI,KAAK,kBAAkB;AAChC,aAAK,SAAS,mBAAmB,MAAM,IAAI;AAAA,MAC7C;AACA;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,WAAK,IAAI,MAAM,KAAK;AACpB,YAAM,YAAY,KAAK,IAAI,MAAM,KAAK,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,IACtE,CAAC;AAAA,EACL;AAAA,EAEA,MAAM,gBAA+B;AACnC,UAAM,OACJ;AACF,UAAM,MAAM,cAAAP,QAAO,WAAW,KAAK,EAAE,OAAO,IAAI,EAAE,OAAO,QAAQ;AACjE,SAAK,IAAI,MAAM,GAAG;AAClB,UAAM,UAAU,MAAM;AACtB,UAAM,YAAY,cAAAA,QAAO,WAAW,QAAQ,KAAK,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AACrF,UAAM,KAAK,cAAc;AAAA,MACvB,QAAQ;AAAA,MACR,KAAK,iFAAiF,KAAK,QAAQ,gBAAgB,KAAK;AAAA,MACxH,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,QACf,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,mBACE,6HACA;AAAA,MACJ;AAAA,MACA,MAAM;AAAA,IACR,CAAC,EACE,KAAK,OAAO,QAAQ;AAlS3B;AAmSQ,WAAK,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AACvC,UAAI,IAAI,KAAK,YAAY;AACvB,aAAK,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AACvC;AAAA,MACF;AACA,WAAK,IAAI,KAAK,UAAS,SAAI,KAAK,WAAT,mBAAiB,kBAAkB;AAE1D,iBAAW,WAAU,SAAI,KAAK,WAAT,mBAAiB,YAAY;AAChD,cAAM,KAAK,OAAO;AAClB,aAAK,QAAQ,MAAM;AACnB,YAAI,OAAO,OAAO;AAElB,YAAI,KAAK,SAAS,OAAO,KAAK,GAAG;AAC/B,iBAAO,OAAO,KAAK,OAAO,OAAO,QAAQ,EAAE,SAAS,MAAM;AAAA,QAC5D;AACA,aAAK,IAAI,MAAM,gBAAgB,MAAM,MAAM;AAC3C,cAAM,KAAK,aAAa,IAAI;AAAA,UAC1B,MAAM;AAAA,UACN,QAAQ;AAAA,YACN;AAAA,UACF;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AACD,cAAM,KAAK,wBAAwB,KAAK,WAAW;AAAA,UACjD,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,UACR;AAAA,UACA,QAAQ,CAAC;AAAA,QACX,CAAC;AAED,YAAI,cAAc;AAAA,UAChB,EAAE,SAAS,WAAW,MAAM,iBAAiB;AAAA,UAC7C,EAAE,SAAS,iBAAiB,MAAM,yBAAyB;AAAA,UAC3D,EAAE,SAAS,sBAAsB,MAAM,eAAe;AAAA,UAEtD;AAAA,YACE,SAAS;AAAA,YACT,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,KAAK;AAAA,UACP;AAAA,UACA;AAAA,YACE,SAAS;AAAA,YACT,MAAM;AAAA,YACN,MAAM;AAAA,YACN,MAAM;AAAA,YACN,KAAK;AAAA,UACP;AAAA,UACA;AAAA,YACE,SAAS;AAAA,YACT,MAAM;AAAA,YACN,KAAK;AAAA,YACL,MAAM;AAAA,UACR;AAAA,QACF;AACA,YAAI,OAAO,WAAW,SAAS,QAAQ,GAAG;AACxC,wBAAc;AAAA,YACZ,EAAE,SAAS,WAAW,MAAM,iBAAiB;AAAA,YAC7C,EAAE,SAAS,kBAAkB,MAAM,yBAAyB;AAAA,YAC5D,EAAE,SAAS,qBAAqB,MAAM,yBAAyB;AAAA,YAC/D,EAAE,SAAS,0BAA0B,MAAM,yBAAyB;AAAA,YACpE,EAAE,SAAS,gBAAgB,MAAM,yBAAyB;AAAA,YAC1D,EAAE,SAAS,oBAAoB,MAAM,yBAAyB;AAAA,YAC9D,EAAE,SAAS,sBAAsB,MAAM,yBAAyB;AAAA,YAChE,EAAE,SAAS,aAAa,MAAM,0CAA0C,MAAM,UAAU,KAAK,QAAQ,MAAM,OAAO;AAAA,YAClH,EAAE,SAAS,iBAAiB,MAAM,iBAAiB,MAAM,UAAU,KAAK,OAAO,MAAM,OAAO;AAAA,YAC5F,EAAE,SAAS,gBAAgB,MAAM,YAAY,MAAM,UAAU,KAAK,KAAK,MAAM,OAAO;AAAA,UACtF;AAAA,QACF;AACA,oBAAY,QAAQ,CAAC,WAAW;AAC9B,eAAK,aAAa,KAAK,aAAa,OAAO,SAAS;AAAA,YAClD,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM,OAAO,QAAQ;AAAA,cACrB,MAAM,OAAO,QAAQ;AAAA,cACrB,MAAM,OAAO,QAAQ;AAAA,cACrB,KAAK,OAAO,OAAO,OAAO,OAAO,MAAM;AAAA,cACvC,OAAO;AAAA,cACP,MAAM;AAAA,YACR;AAAA,YACA,QAAQ,CAAC;AAAA,UACX,CAAC;AAAA,QACH,CAAC;AACD,aAAK,SAAS,MAAM,IAAI,QAAQ,EAAE,aAAa,KAAK,CAAC;AAIrD,cAAM,KAAK,cAAc;AAAA,UACvB,QAAQ;AAAA,UACR,KAAK,2DAA2D,KAAK;AAAA,UACrE,SAAS;AAAA,YACP,YAAY;AAAA,YACZ,eAAe,QAAQ,KAAK,QAAQ;AAAA,YACpC,WAAW,0BAA0B,KAAK;AAAA,YAC1C,UAAU;AAAA,YACV,cAAc;AAAA,YACd,QAAQ;AAAA,YACR,mBAAmB;AAAA,YACnB,gBAAgB;AAAA,YAChB,cAAc;AAAA,YACd,aAAa,KAAK;AAAA,YAClB,iBAAiB;AAAA,YACjB,cAAc;AAAA,UAChB;AAAA,QACF,CAAC,EACE,KAAK,OAAOO,SAAQ;AACnB,eAAK,IAAI,MAAM,KAAK,UAAUA,KAAI,IAAI,CAAC;AACvC,cAAIA,KAAI,KAAK,YAAY;AACvB,iBAAK,IAAI,MAAM,KAAK,UAAUA,KAAI,IAAI,CAAC;AACvC;AAAA,UACF,OAAO;AACL,iBAAK,QAAQ,MAAM,EAAE,GAAG,KAAK,QAAQ,KAAK,GAAGA,KAAI,KAAK;AAAA,UACxD;AAAA,QACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,eAAK,IAAI,KAAK,KAAK;AACnB,gBAAM,YAAY,KAAK,IAAI,MAAM,KAAK,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,QACtE,CAAC;AAEH,YAAI,CAAC,KAAK,QAAQ,IAAI,IAAI;AACxB,gBAAML,QAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAcI;AAAA;AAEjB,gBAAME,OAAM,cAAAJ,QAAO,WAAW,KAAK,EAAE,OAAOE,KAAI,EAAE,OAAO,QAAQ;AACjE,eAAK,IAAI,MAAME,IAAG;AAClB,gBAAMC,WAAUD,OAAM;AACtB,gBAAME,aAAY,cAAAN,QAAO,WAAW,QAAQ,KAAK,MAAM,EAAE,OAAOK,QAAO,EAAE,OAAO,KAAK;AACrF,gBAAM,KAAK,cAAc;AAAA,YACvB,QAAQ;AAAA,YACR,KAAK,yEAAyE,KAAK,QAAQ,gBAAgB,KAAK;AAAA,YAChH,SAAS;AAAA,cACP,gBAAgB;AAAA,cAChB,eAAeD;AAAA,cACf,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,mBAAmB;AAAA,cACnB,mBACE,6HACAE;AAAA,YACJ;AAAA,YACA,MAAMJ;AAAA,UACR,CAAC,EACE,KAAK,OAAOK,SAAQ;AAhcnC,gBAAAC,KAAAC,KAAA;AAicgB,iBAAK,IAAI,MAAM,KAAK,UAAUF,KAAI,IAAI,CAAC;AACvC,gBAAI,SAAc,CAAC;AACnB,gBAAIA,KAAI,KAAK,YAAY;AACvB,mBAAK,IAAI,MAAM,KAAK,UAAUA,KAAI,IAAI,CAAC;AAAA,YACzC,OAAO;AACL,wBAAS,wBAAAE,OAAAD,MAAAD,KAAI,KAAK,WAAT,gBAAAC,IAAiB,iBAAjB,gBAAAC,IAA+B,WAA/B,mBAAuC,UAAU,OAAjD,mBAAqD,WAArD,mBAA6D,YAA7D,mBAAsE;AAC/E,qBAAO,KAAK,OAAO;AACnB,mBAAK,IAAI,KAAK,UAAU,aAAa,OAAO,IAAI;AAChD,qBAAO,OAAO;AACd,qBAAO,OAAO;AAEd,mBAAK,QAAQ,MAAM,EAAE,GAAG,KAAK,QAAQ,KAAK,GAAG,OAAO;AAAA,YACtD;AAAA,UACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,iBAAK,IAAI,KAAK,KAAK;AACnB,kBAAM,YAAY,KAAK,IAAI,MAAM,KAAK,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,UACtE,CAAC;AAAA,QACL;AACA,YAAI,CAAC,KAAK,QAAQ,IAAI,IAAI;AACxB,gBAAM,UAAU,MAAM,KAAK,cAAc,KAAK,KAAK;AACnD,cAAI,WAAW,QAAQ,KAAK;AAC1B,iBAAK,QAAQ,IAAI,KAAK,QAAQ;AAAA,UAChC,OAAO;AACL,kBAAM,KAAK,wBAAwB,KAAK,OAAO;AAAA,cAC7C,MAAM;AAAA,cACN,QAAQ;AAAA,gBACN,MAAM;AAAA,gBACN,OAAO;AAAA,gBACP,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,MAAM;AAAA,cACR;AAAA,cACA,QAAQ,CAAC;AAAA,YACX,CAAC;AACD,iBAAK,IAAI,KAAK,mBAAmB,uDAAuD;AAAA,UAC1F;AAAA,QACF;AACA,aAAK,SAAS,MAAM,IAAI,KAAK,QAAQ,GAAG;AACxC,YAAI,KAAK,QAAQ,IAAI,IAAI;AACvB,gBAAM,aAAa,MAAM,KAAK,WAAW,EAAE,EACxC,KAAK,MAAM;AACV,iBAAK,IAAI,KAAK,eAAe,IAAI;AAAA,UACnC,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,iBAAK,IAAI,MAAM,CAAC;AAAA,UAClB,CAAC;AACH,eAAK,IAAI,MAAM,sBAAsB,MAAM,KAAK,UAAU,UAAU,GAAG;AAAA,QACzE;AAAA,MACF;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,WAAK,IAAI,KAAK,KAAK;AACnB,YAAM,YAAY,KAAK,IAAI,MAAM,KAAK,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,IACtE,CAAC;AAEH,UAAM,KAAK,wBAAwB,cAAc;AAAA,MAC/C,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,QACP,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,MACA,QAAQ,CAAC;AAAA,IACX,CAAC;AAED,UAAM,KAAK,cAAc,cAAc,KAAK,UAAU,KAAK,OAAO,GAAG,IAAI;AAAA,EAC3E;AAAA,EACA,MAAM,WAAW,IAA2B;AAC1C,UAAM,SAAS,KAAK,QAAQ;AAC5B,QAAI,CAAC,OAAO,IAAI;AACd,WAAK,IAAI,KAAK,mBAAmB,IAAI;AACrC;AAAA,IACF;AACA,SAAK,IAAI,KAAK,eAAe,WAAW,OAAO,sBAAsB,OAAO,IAAI;AAChF,QAAI;AACJ,QAAI,OAAO,eAAe,QAAQ;AAChC,qBAAe,IAAI,YAAAC,QAAK,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC5F,WAAW,OAAO,WAAW,WAAW,MAAM,KAAK,OAAO,WAAW,WAAW,MAAM,GAAG;AACvF,qBAAe,IAAI,YAAAC,QAAK,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC5F,WAAW,OAAO,eAAe,UAAU,OAAO,WAAW,WAAW,MAAM,GAAG;AAC/E,qBAAe,IAAI,YAAAC,QAAK,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC5F,WAAW,OAAO,eAAe,SAAS;AACxC,qBAAe,IAAI,aAAAC,QAAM,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC7F,WAAW,OAAO,eAAe,SAAS;AACxC,qBAAe,IAAI,aAAAC,QAAM,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC7F,WAAW,OAAO,WAAW,WAAW,GAAG,KAAK,OAAO,WAAW,WAAW,IAAI,GAAG;AAClF,qBAAe,IAAI,aAAAD,QAAM,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC7F,WAAW,OAAO,WAAW,WAAW,GAAG,KAAK,OAAO,WAAW,WAAW,IAAI,GAAG;AAClF,UAAI,CAAC,KAAK,OAAO,kBAAkB,CAAC,KAAK,OAAO,gBAAgB;AAC9D,aAAK,IAAI,KAAK,+DAA+D;AAAA,MAC/E;AACA,qBAAe,IAAI,6BAAW,KAAK,KAAK;AAAA,QACtC,MAAM,OAAO;AAAA,QACb,WAAW,OAAO;AAAA,QAClB,UAAU,KAAK,OAAO;AAAA,QACtB,YAAY,KAAK,OAAO;AAAA,QACxB,gBAAgB,KAAK,OAAO;AAAA,QAC5B,kBAAkB;AAAA,MACpB,CAAC;AAID,WAAK,cAAc,MAAM;AACzB,YAAM,aAAa,MAAM,aAAa,cAAc,IAAI;AACxD,WAAK,IAAI,KAAK,GAAG,2BAA2B,KAAK,UAAU,UAAU,GAAG;AACxE,WAAK,IAAI,MAAM,KAAK,UAAU,UAAU,CAAC;AACzC,WAAK,SAAS,MAAM,IAAI,UAAU;AAClC,WAAK,IAAI,MAAM,0BAA0B,IAAI;AAC7C,YAAM,eAAe,MAAM,aAAa,gBAAgB;AACxD,YAAM,KAAK,wBAAwB,KAAK,gBAAgB;AAAA,QACtD,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,KAAK;AAAA,UACL,OAAO;AAAA,UACP,MAAM;AAAA,QACR;AAAA,QACA,QAAQ,CAAC;AAAA,MACX,CAAC;AACD,WAAK,IAAI,MAAM,kCAAkC;AACjD,mBAAa,YAAY,UAAU,OAAO,mBAAwB;AAChE,cAAM,KAAK,cAAc,KAAK,gBAAgB,gBAAgB,IAAI;AAClE,aAAK,IAAI,MAAM,IAAI,OAAO,iCAAiC,gBAAgB;AAAA,MAC7E,CAAC;AACD;AAAA,IACF,OAAO;AACL,WAAK,IAAI,KAAK,uBAAuB,OAAO,yBAAyB;AACrE,qBAAe,IAAI,YAAAH,QAAK,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU,CAAC;AAAA,IAC5F;AACA,SAAK,cAAc,MAAM;AACzB,UAAM,aACH,UAAU,EACV,KAAK,YAAY;AAChB,UAAI,aAAa,SAAS;AACxB,aAAK,IAAI,MAAM,sBAAsB;AACrC,cAAM,aAAa,cAAc,EAAE,MAAM,OAAO,UAAe;AAC7D,eAAK,IAAI,MAAM,KAAK;AACpB,eAAK,IAAI,MAAM,MAAM,KAAK;AAC1B,eAAK,IAAI,MAAM,0CAA0C;AACzD,uBAAa,UAAU;AACvB,gBAAM,aAAa,eAAe,EAAE,MAAM,MAAM;AAC9C,iBAAK,IAAI,MAAM,cAAc;AAC7B,iBAAK,cAAc,IAAI,aAAa;AAAA,UACtC,CAAC;AAAA,QACH,CAAC;AAAA,MACH,OAAO;AACL,cAAM,aAAa,MAAM,EAAE,MAAM,MAAM;AACrC,eAAK,IAAI,MAAM,cAAc;AAC7B,eAAK,cAAc,IAAI,aAAa;AAAA,QACtC,CAAC;AAAA,MACH;AACA,mBACG,cAAc,IAAI,EAClB,KAAK,OAAO,YAAiB;AAC5B,aAAK,IAAI,MAAM,KAAK,UAAU,OAAO,CAAC;AACtC,YAAI,QAAQ,SAAS;AACnB,eAAK,IAAI,MAAM,4BAA4B;AAC3C,eAAK,IAAI,MAAM,KAAK,UAAU,OAAO,CAAC;AACtC;AAAA,QACF;AACA,aAAK,SAAS,MAAM,IAAI,OAAO;AAE/B,aAAK,cAAc,IAAI,aAAa;AACpC,YAAI,KAAK,cAAc,IAAI,gBAAgB;AACzC,eAAK,IAAI,MAAM,sBAAsB;AACrC,gBAAM,cAAc,MAAM,KAAK,cAAc,IAAI,eAAe;AAChE,eAAK,IAAI,MAAM,KAAK,UAAU,WAAW,CAAC;AAC1C,eAAK,SAAS,MAAM,IAAI,WAAW;AAAA,QACrC;AACA,cAAM,YAAY,MAAM,KAAK,cAAc,IAAI,gBAAgB;AAC/D,aAAK,IAAI,MAAM,gBAAgB,KAAK,UAAU,SAAS,CAAC;AACxD,YAAI,aAAa,UAAU,eAAe,GAAG;AAC3C,eAAK,SAAS,MAAM,KAAK,cAAc,SAAS;AAAA,QAClD;AAAA,MACF,CAAC,EACA,MAAM,CAAC,UAAe;AACrB,aAAK,IAAI,MAAM,KAAK,UAAU,KAAK,CAAC;AACpC,aAAK,IAAI,MAAM,6BAA6B;AAE5C,aAAK,cAAc,IAAI,aAAa;AAAA,MACtC,CAAC;AAAA,IACL,CAAC,EACA,MAAM,MAAM;AACX,WAAK,IAAI,MAAM,kBAAkB;AACjC,WAAK,cAAc,IAAI,aAAa;AAAA,IACtC,CAAC;AAAA,EACL;AAAA,EAEA,MAAM,gBAA+B;AACnC,QAAI;AACF,iBAAW,YAAY,KAAK,eAAe;AACzC,YAAI,KAAK,cAAc,UAAU,WAAW;AAC1C,eAAK,IAAI,MAAM,uBAAuB;AACtC,gBAAM,SAAS,MAAM,KAAK,cAAc,UAAU,UAAU,EAAE,MAAM,CAAC,UAAe;AAClF,iBAAK,IAAI,KAAK,0BAA0B;AACxC,iBAAK,IAAI,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,UACtC,CAAC;AACD,eAAK,IAAI,MAAM,KAAK,UAAU,MAAM,CAAC;AACrC,eAAK,SAAS,MAAM,UAAU,MAAM;AACpC,cAAI,KAAK,cAAc,UAAU,SAAS,QAAW;AACnD,iBAAK,IAAI,MAAM,wBAAwB,WAAW,mCAAmC;AAErF,mBAAO,KAAK,cAAc;AAAA,UAC5B;AACA;AAAA,QACF;AACA,YAAI,CAAC,KAAK,cAAc,UAAU,YAAY;AAC5C;AAAA,QACF;AAEA,aAAK,cAAc,UAChB,cAAc,IAAI,EAClB,KAAK,OAAO,YAAiB;AAC5B,eAAK,IAAI,MAAM,KAAK,UAAU,OAAO,CAAC;AACtC,cAAI,CAAC,WAAW,QAAQ,SAAS,WAAW,QAAQ,SAAS;AAC3D,iBAAK,IAAI,MAAM,4BAA4B;AAE3C;AAAA,UACF;AACA,gBAAM,KAAK,SAAS,MAAM,UAAU,OAAO;AAC3C,cAAI,KAAK,cAAc,UAAU,gBAAgB;AAC/C,iBAAK,IAAI,MAAM,sBAAsB;AACrC,kBAAM,cAAc,MAAM,KAAK,cAAc,UAAU,eAAe;AACtE,iBAAK,IAAI,MAAM,KAAK,UAAU,WAAW,CAAC;AAC1C,gBAAI,YAAY,SAAS;AACvB,mBAAK,IAAI,MAAM,mCAAmC;AAClD,mBAAK,IAAI,MAAM,KAAK,UAAU,WAAW,CAAC;AAC1C;AAAA,YACF;AACA,kBAAM,KAAK,SAAS,MAAM,UAAU,WAAW;AAC/C,kBAAM,cAAc,KAAK,cAAc,UAAU,oBAAoB;AACrE,gBAAI,YAAY,SAAS;AACvB,mBAAK,IAAI,MAAM,wCAAwC;AACvD,mBAAK,IAAI,MAAM,KAAK,UAAU,WAAW,CAAC;AAC1C;AAAA,YACF;AACA,kBAAM,KAAK,SAAS,MAAM,UAAU,WAAW;AAAA,UACjD;AAAA,QACF,CAAC,EACA,MAAM,CAAC,UAAe;AACrB,eAAK,IAAI,MAAM,8BAA8B,cAAc,OAAO;AAAA,QACpE,CAAC;AAAA,MACL;AACA,WAAK,IAAI,MAAM,aAAa;AAAA,IAC9B,SAAS,OAAP;AACA,WAAK,IAAI,KAAK,KAAK;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,SAAS,KAAsB;AAC7B,QAAI,QAAQ,MAAM,IAAI,KAAK,MAAM,IAAI;AACnC,aAAO;AAAA,IACT;AACA,QAAI;AACF,YAAM,oBAAoB,IAAI,QAAQ,OAAO,EAAE;AAC/C,aAAO,KAAK,KAAK,iBAAiB,CAAC,MAAM,qBAAqB,KAAK,KAAK,GAAG,CAAC,MAAM;AAAA,IACpF,SAAS,KAAP;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,MAAM,MAAM,IAA2B;AACrC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AAAA,EACA,MAAM,eAA8B;AAClC,SAAK,IAAI,MAAM,eAAe;AAAA,EAChC;AAAA,EAIQ,SAAS,UAA4B;AAC3C,QAAI;AACF,WAAK,SAAS,mBAAmB,OAAO,IAAI;AAC5C,WAAK,kBAAkB,aAAa,KAAK,cAAc;AACvD,WAAK,kBAAkB,aAAa,KAAK,cAAc;AACvD,WAAK,uBAAuB,aAAa,KAAK,mBAAmB;AACjE,WAAK,kBAAkB,cAAc,KAAK,cAAc;AACxD,WAAK,wBAAwB,cAAc,KAAK,oBAAoB;AAEpE,eAAS;AAAA,IACX,SAAS,GAAP;AACA,eAAS;AAAA,IACX;AAAA,EACF;AAAA,EAKA,MAAc,cAAc,IAAY,OAAyD;AAC/F,QAAI,OAAO;AACT,UAAI,CAAC,MAAM,KAAK;AACd,cAAM,WAAW,GAAG,MAAM,GAAG,EAAE;AAC/B,cAAM,UAAU,GAAG,MAAM,GAAG,EAAE;AAC9B,YAAI,GAAG,MAAM,GAAG,EAAE,OAAO,UAAU;AACjC;AAAA,QACF;AAEA,YAAI,YAAY,WAAW;AACzB,eAAK,cAAc,UAChB,cAAc,IAAI,EAClB,KAAK,CAAC,YAAiB;AACtB,iBAAK,IAAI,MAAM,KAAK,UAAU,OAAO,CAAC;AACtC,iBAAK,SAAS,MAAM,UAAU,OAAO;AAAA,UACvC,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,iBAAK,IAAI,MAAM,8BAA8B,cAAc,OAAO;AAAA,UACpE,CAAC;AAEH;AAAA,QACF;AACA,YAAI;AACF,gBAAM,iBAA4C;AAAA,YAChD,gBAAgB;AAAA,YAChB,mBAAmB;AAAA,YACnB,cAAc;AAAA,YACd,kBAAkB;AAAA,YAClB,oBAAoB;AAAA,UACtB;AACA,cAAI,KAAK,cAAc,cAAc,KAAK,cAAc,UAAU,YAAY,eAAe,WAAW;AACtG,gBAAI;AACJ,gBAAI,eAAe,UAAU;AAC3B,uBAAS,MAAM,KAAK,cAAc,UAAU,UAAU,eAAe,UAAU,MAAM,GAAG;AAAA,YAC1F,WAAW,YAAY,cAAc,YAAY,eAAe,YAAY,sBAAsB;AAChG,oBAAM,aAAa,MAAM,IAAI,QAAQ,KAAK,EAAE,EAAE,MAAM,GAAG;AACvD,uBAAS,MAAM,KAAK,cAAc,UAAU,SAAS,WAAW,IAAI,WAAW,EAAE;AAAA,YACnF,OAAO;AACL,uBAAS,MAAM,KAAK,cAAc,UAAU,SAAS,MAAM,GAAG;AAAA,YAChE;AACA,iBAAK,IAAI;AAAA,cACP,UAAU,mBAAmB,MAAM,MAAM,iBAAiB,WAAW,sBAAsB,KAAK,UAAU,MAAM;AAAA,YAClH;AACA,iBAAK,kBAAkB,aAAa,KAAK,cAAc;AACvD,iBAAK,iBAAiB,WAAW,YAAY;AAC3C,mBAAK,cAAc;AAAA,YACrB,GAAG,IAAI,GAAI;AAAA,UACb,OAAO;AACL,iBAAK,IAAI,MAAM,UAAU,2BAA2B,SAAS;AAAA,UAC/D;AAAA,QACF,SAAS,OAAP;AACA,eAAK,IAAI,MAAM,KAAK;AAAA,QACtB;AAAA,MACF,OAAO;AACL,cAAM,aAAwC;AAAA,UAC5C,WAAW;AAAA,UACX,MAAM;AAAA,UACN,OAAO;AAAA,UACP,KAAK;AAAA,UACL,eAAe;AAAA,UACf,iBAAiB;AAAA,QACnB;AACA,cAAM,UAAU,GAAG,MAAM,GAAG;AAC5B,cAAM,YAAY,QAAQ,QAAQ,SAAS;AAC3C,cAAM,WAAW,GAAG,MAAM,GAAG,EAAE;AAC/B,YAAI,WAAW,YAAY;AACzB,gBAAM,KAAK,SAAS,WAAW,aAAa,WAAW,YAAY,MAAM,KAAK,IAAI;AAAA,QACpF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI,QAAQ,SAAS,QAAQ;AAE3B,SAAO,UAAU,CAAC,YAAuD,IAAI,KAAK,OAAO;AAC3F,OAAO;AAEL,GAAC,MAAM,IAAI,KAAK,GAAG;AACrB;",
|
|
4
|
+
"sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.1.1\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from \"@iobroker/adapter-core\";\nimport axios, { AxiosInstance } from \"axios\";\nimport crypto from \"crypto\";\nimport https from \"https\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport Json2iob from \"json2iob\";\nimport { TAPOCamera } from \"./lib/utils/camera/tapoCamera\";\nimport L510E from \"./lib/utils/l510e\";\nimport L520E from \"./lib/utils/l520e\";\nimport L530 from \"./lib/utils/l530\";\nimport P100 from \"./lib/utils/p100\";\nimport P110 from \"./lib/utils/p110\";\nclass Tapo extends utils.Adapter {\n private devices: { [key: string]: any };\n private deviceObjects: { [key: string]: any };\n private json2iob: Json2iob;\n private secret: Buffer;\n private requestClient: AxiosInstance;\n updateInterval: any = null;\n reLoginTimeout: any = null;\n refreshTokenTimeout: any = null;\n session: any = {};\n refreshTimeout: any;\n refreshTokenInterval: any;\n private firstStart: boolean = true;\n private lastBatteryDeviceUpdateTimestamp: number = 0;\n\n termId: any;\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({\n ...options,\n name: \"tapo\",\n });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"stateChange\", this.onStateChange.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n this.devices = {};\n this.deviceObjects = {};\n this.json2iob = new Json2iob(this);\n this.requestClient = axios.create({\n httpsAgent: new https.Agent({\n rejectUnauthorized: false,\n secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,\n }),\n });\n this.secret = Buffer.from([\n 54, 101, 100, 55, 100, 57, 55, 102, 51, 101, 55, 51, 52, 54, 55, 102, 56, 97, 53, 98, 97, 98, 57, 48, 98, 53, 55, 55, 98, 97, 52, 99,\n ]);\n }\n\n /**\n * Is called when databases are connected and adapter received configuration.\n */\n private async onReady(): Promise<void> {\n this.setState(\"info.connection\", false, true);\n if (this.config.interval < 0.5) {\n this.log.info(\"Set interval to minimum 0.5\");\n this.config.interval = 0.5;\n }\n if (!this.config.username || !this.config.password) {\n this.log.error(\"Please set username and password in the instance settings\");\n return;\n }\n this.config.username = this.config.username.toLowerCase();\n\n this.updateInterval = null;\n this.reLoginTimeout = null;\n this.refreshTokenTimeout = null;\n this.session = {};\n this.subscribeStates(\"*\");\n\n const termIdState = await this.getStateAsync(\"termId\");\n if (termIdState && termIdState.val) {\n this.termId = termIdState.val;\n } else {\n await this.setObjectNotExistsAsync(\"termId\", {\n type: \"state\",\n common: {\n name: \"Terminal ID\",\n write: false,\n read: true,\n type: \"string\",\n role: \"text\",\n },\n native: {},\n });\n this.termId = uuidv4();\n await this.setStateAsync(\"termId\", this.termId, true);\n }\n\n this.log.info(\"Login tp TAPO App\");\n await this.login();\n if (this.session.token) {\n await this.getDeviceList();\n } else {\n this.log.warn(\"Login failed using cached device list\");\n const deviceListState = await this.getStateAsync(\"deviceList\");\n if (deviceListState && deviceListState.val) {\n this.log.info(\"Use cached device list\");\n this.devices = JSON.parse(deviceListState.val);\n for (const id in this.devices) {\n if (this.devices[id].ip) {\n const initResult = await this.initDevice(id)\n .then(() => {\n this.log.info(`Initialized ${id}`);\n })\n .catch((e) => {\n this.log.error(e);\n });\n this.log.debug(`initResult ${id} ${JSON.stringify(initResult)}`);\n }\n }\n }\n }\n\n this.log.info(\"Wait for connections for non camera devices\");\n await this.sleep(10000);\n this.log.info(\"Start first Update\");\n this.updateDevices();\n this.firstStart = false;\n this.updateInterval = setInterval(async () => {\n this.updateDevices();\n }, this.config.interval * 1000);\n }\n async login(): Promise<void> {\n let body = JSON.stringify({\n appVersion: \"2.8.21\",\n refreshTokenNeeded: true,\n platform: \"iOS 14.8\",\n cloudPassword: this.config.password,\n terminalUUID: this.termId,\n cloudUserName: this.config.username,\n terminalName: \"ioBroker\",\n terminalMeta: \"3\",\n appType: \"TP-Link_Tapo_iOS\",\n });\n let path = \"api/v2/account/login\";\n const mfaIdState = await this.getStateAsync(\"mfaId\");\n if (mfaIdState && mfaIdState.val) {\n if (!this.config.mfa) {\n this.log.error(\"Please set mfa in the instance settings\");\n return;\n }\n\n body = JSON.stringify({\n cloudUserName: this.config.username,\n MFAProcessId: mfaIdState.val,\n appType: \"TP-Link_Tapo_iOS\",\n MFAType: 2,\n code: this.config.mfa,\n terminalBindEnabled: true,\n });\n path = \"api/v2/account/checkMFACodeAndLogin\";\n await this.setStateAsync(\"mfaId\", \"\", true);\n }\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/\" + path;\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url:\n \"https://n-wap-gw.tplinkcloud.com/\" +\n path +\n \"?termID=\" +\n this.termId +\n \"&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8\",\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n }\n if (res.data.result?.MFAProcessId) {\n this.log.info(\"Found MFA Process please enter MFA in the instance settings\");\n await this.setObjectNotExistsAsync(\"mfaId\", {\n type: \"state\",\n common: {\n name: \"MFA Id\",\n write: false,\n read: true,\n type: \"string\",\n role: \"text\",\n },\n native: {},\n });\n await this.setStateAsync(\"mfaId\", res.data.result?.MFAProcessId, true);\n\n const body = JSON.stringify({\n cloudPassword: this.config.password,\n locale: \"de_DE\",\n terminalUUID: this.termId,\n cloudUserName: this.config.username,\n appType: \"TP-Link_Tapo_iOS\",\n });\n\n const path = \"api/v2/account/getEmailVC4TerminalMFA\";\n\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/\" + path;\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url:\n \"https://n-wap-gw.tplinkcloud.com/\" +\n path +\n \"?termID=\" +\n this.termId +\n \"&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8\",\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n }\n })\n .catch((error) => {\n this.log.error(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n return;\n }\n\n if (!res.data.result || !res.data.result.token) {\n this.log.error(\"Login failed\");\n this.log.error(JSON.stringify(res.data));\n return;\n }\n this.session = res.data.result;\n if (this.session.token) {\n this.log.info(\"Login succesfull\");\n this.setState(\"info.connection\", true, true);\n }\n return;\n })\n .catch((error) => {\n this.log.error(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n }\n\n async getDeviceList(): Promise<void> {\n const body =\n '{\"index\":0,\"deviceTypeList\":[\"SMART.TAPOBULB\",\"SMART.TAPOPLUG\",\"SMART.IPCAMERA\",\"SMART.TAPOHUB\",\"SMART.TAPOSENSOR\",\"SMART.TAPOSWITCH\"],\"limit\":30}';\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/api/v2/common/getDeviceListByPage\";\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url: `https://n-euw1-wap-gw.tplinkcloud.com/api/v2/common/getDeviceListByPage?token=${this.session.token}&termID=${this.termId}&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8`,\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n \"Content-MD5\": md5,\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n }\n this.log.info(`Found ${res.data.result?.totalNum} devices`);\n\n for (const device of res.data.result?.deviceList) {\n const id = device.deviceId;\n this.devices[id] = device;\n let name = device.alias;\n\n if (this.isBase64(device.alias)) {\n name = Buffer.from(device.alias, \"base64\").toString(\"utf8\");\n }\n this.log.debug(`Found device ${id} ${name}`);\n await this.extendObject(id, {\n type: \"device\",\n common: {\n name: name,\n },\n native: {},\n });\n await this.setObjectNotExistsAsync(id + \".remote\", {\n type: \"channel\",\n common: {\n name: \"Remote Controls\",\n },\n native: {},\n });\n\n let remoteArray = [\n { command: \"refresh\", name: \"True = Refresh\" },\n { command: \"setPowerState\", name: \"True = On, False = Off\" },\n { command: \"setPowerStateChild\", name: \"childId,true\" },\n\n {\n command: \"setBrightness\",\n name: \"Set Brightness for Light devices\",\n type: \"number\",\n role: \"level.brightness\",\n def: 5,\n },\n {\n command: \"setColorTemp\",\n name: \"Set Color Temp for Light devices\",\n type: \"number\",\n role: \"level.color.temperature\",\n def: 3e3,\n },\n {\n command: \"setColor\",\n name: \"Set Color for Light devices (hue, saturation)\",\n def: \"30, 100\",\n type: \"string\",\n },\n ];\n if (device.deviceType.includes(\"CAMERA\")) {\n remoteArray = [\n { command: \"refresh\", name: \"True = Refresh\" },\n { command: \"setAlertConfig\", name: \"True = On, False = Off\" },\n { command: \"setLensMaskConfig\", name: \"True = On, False = Off\" },\n { command: \"setForceWhitelampState\", name: \"True = On, False = Off\" },\n { command: \"setLedStatus\", name: \"True = On, False = Off\" },\n { command: \"setMsgPushConfig\", name: \"True = On, False = Off\" },\n { command: \"setDetectionConfig\", name: \"True = On, False = Off\" },\n { command: \"moveMotor\", name: \"move Camera to X (-360,360), Y(-45,45)\", type: \"string\", def: \"0, 0\", role: \"text\" },\n { command: \"moveMotorStep\", name: \"Angle (0-360)\", type: \"string\", def: \"180\", role: \"text\" },\n { command: \"moveToPreset\", name: \"PresetId\", type: \"string\", def: \"1\", role: \"text\" },\n ];\n }\n remoteArray.forEach((remote) => {\n this.extendObject(id + \".remote.\" + remote.command, {\n type: \"state\",\n common: {\n name: remote.name || \"\",\n type: remote.type || \"boolean\",\n role: remote.role || \"switch\",\n def: remote.def != null ? remote.def : false,\n write: true,\n read: true,\n },\n native: {},\n });\n });\n this.json2iob.parse(id, device, { channelName: name });\n\n //try new API\n\n await this.requestClient({\n method: \"get\",\n url: \"https://euw1-app-server.iot.i.tplinknbu.com/v1/things/\" + id + \"/details\",\n headers: {\n \"x-locale\": \"de\",\n Authorization: \"ut|\" + this.session.token,\n \"app-cid\": \"app:TP-Link_Tapo_iOS:\" + this.termId,\n \"x-ospf\": \"iOS 14.8\",\n \"x-app-name\": \"TP-Link_Tapo_iOS\",\n Accept: \"*/*\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"Content-Type\": \"application/json;UTF-8\",\n \"User-Agent\": \"Tapo/2.9.7 (iPhone; iOS 14.8; Scale/3.00)\",\n \"x-term-id\": this.termId,\n \"x-app-version\": \"2.9.7\",\n \"x-net-type\": \"wifi\",\n },\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n return;\n } else {\n this.devices[id] = { ...this.devices[id], ...res.data };\n }\n })\n .catch((error) => {\n this.log.warn(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n //no ip via new API try old api\n if (!this.devices[id].ip) {\n const body = `{\n \"requestData\": {\n \"method\": \"multipleRequest\",\n \"params\": {\n \"requests\": [{\n \"method\": \"getDeviceIpAddress\",\n \"params\": {\n \"network\": {\n \"name\": \"wan\"\n }\n }\n }]\n }\n },\n \"deviceId\": \"${id}\"\n }`;\n const md5 = crypto.createHash(\"md5\").update(body).digest(\"base64\");\n this.log.debug(md5);\n const content = md5 + \"\\n9999999999\\nfee66616-58dd-4bcb-be79-fe092d800a21\\n/api/v2/common/passthrough\";\n const signature = crypto.createHmac(\"sha1\", this.secret).update(content).digest(\"hex\");\n await this.requestClient({\n method: \"post\",\n url: `https://n-euw1-wap-gw.tplinkcloud.com/api/v2/common/passthrough?token=${this.session.token}&termID=${this.termId}&appVer=2.8.21&locale=de_DE&appName=TP-Link_Tapo_iOS&netType=wifi&model=iPhone10%2C5&termName=iPhone&termMeta=3&brand=TPLINK&ospf=iOS%2014.8`,\n headers: {\n \"Content-Type\": \"application/json;UTF-8\",\n \"Content-MD5\": md5,\n Accept: \"*/*\",\n \"User-Agent\": \"Tapo/2.8.21 (iPhone; iOS 14.8; Scale/3.00)\",\n \"Accept-Language\": \"de-DE;q=1, uk-DE;q=0.9, en-DE;q=0.8\",\n \"X-Authorization\":\n \"Timestamp=9999999999, Nonce=fee66616-58dd-4bcb-be79-fe092d800a21, AccessKey=4d11b6b9d5ea4d19a829adbb9714b057, Signature=\" +\n signature,\n },\n data: body,\n })\n .then(async (res) => {\n this.log.debug(JSON.stringify(res.data));\n let result: any = {};\n if (res.data.error_code) {\n this.log.error(JSON.stringify(res.data));\n } else {\n result = res.data.result?.responseData?.result?.responses[0]?.result?.network?.wan;\n result.ip = result.ipaddr;\n this.log.info(`Device ${id} has IP ${result.ip}`);\n delete result[\".name\"];\n delete result[\".type\"];\n // result = res.data.result?.responseData?.result;\n this.devices[id] = { ...this.devices[id], ...result };\n }\n })\n .catch((error) => {\n this.log.warn(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n }\n if (!this.devices[id].ip) {\n const ipState = await this.getStateAsync(id + \".ip\");\n if (ipState && ipState.val) {\n this.devices[id].ip = ipState.val;\n } else {\n await this.setObjectNotExistsAsync(id + \".ip\", {\n type: \"state\",\n common: {\n name: \"IP\",\n write: true,\n read: true,\n type: \"string\",\n role: \"text\",\n },\n native: {},\n });\n this.log.warn(`No IP found for ${id} put the device online or set the ip state manually`);\n }\n }\n this.json2iob.parse(id, this.devices[id]);\n if (this.devices[id].ip) {\n const initResult = await this.initDevice(id)\n .then(() => {\n this.log.info(`Initialized ${id}`);\n })\n .catch((e) => {\n this.log.error(e);\n });\n this.log.debug(`initResult camera ${id} ${JSON.stringify(initResult)}`);\n }\n }\n })\n .catch((error) => {\n this.log.warn(error);\n error.response && this.log.error(JSON.stringify(error.response.data));\n });\n\n await this.setObjectNotExistsAsync(\"deviceList\", {\n type: \"state\",\n common: {\n name: \"Cached device list\",\n write: false,\n read: true,\n type: \"string\",\n role: \"json\",\n },\n native: {},\n });\n\n await this.setStateAsync(\"deviceList\", JSON.stringify(this.devices), true);\n }\n async initDevice(id: string): Promise<void> {\n const device = this.devices[id];\n if (!device.ip) {\n this.log.warn(`No IP found for ${id}`);\n return;\n }\n this.log.info(`Init device ${id} type ${device.deviceName} with ip ${device.ip}`);\n let deviceObject: any;\n if (device.deviceName === \"P100\") {\n deviceObject = new P100(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName.startsWith(\"P110\") || device.deviceName.startsWith(\"P115\")) {\n deviceObject = new P110(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName === \"L530\" || device.deviceName.startsWith(\"L630\")) {\n deviceObject = new L530(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName === \"L510E\") {\n deviceObject = new L510E(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName === \"L520E\") {\n deviceObject = new L520E(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName.startsWith(\"L\") || device.deviceName.startsWith(\"KL\")) {\n deviceObject = new L510E(this.log, device.ip, this.config.username, this.config.password, 2);\n } else if (device.deviceName.startsWith(\"C\") || device.deviceName.startsWith(\"TC\")) {\n if (device.deviceName.startsWith(\"C4\") && !this.config.enableBatteryDevices) {\n this.log.warn(\"Battery device found but ignored. Please enable in settings and check regularly the battery status\");\n return;\n }\n if (!this.config.streamusername || !this.config.streampassword) {\n this.log.warn(`No stream username or password. No motion detection available`);\n }\n deviceObject = new TAPOCamera(this.log, {\n name: device.deviceName,\n ipAddress: device.ip,\n password: this.config.password,\n streamUser: this.config.streamusername,\n streamPassword: this.config.streampassword,\n disableStreaming: true,\n });\n\n //new Camera(this.log, device.ip, this.config.username, this.config.password, 2);\n\n this.deviceObjects[id] = deviceObject;\n const deviceInfo = await deviceObject.getDeviceInfo(true);\n this.log.info(`${id} Received device info ${JSON.stringify(deviceInfo)}`);\n this.log.debug(JSON.stringify(deviceInfo));\n this.json2iob.parse(id, deviceInfo);\n this.log.debug(`Init event emitter for ${id}`);\n const eventEmitter = await deviceObject.getEventEmitter();\n await this.setObjectNotExistsAsync(id + \".motionEvent\", {\n type: \"state\",\n common: {\n name: \"Motion detected\",\n type: \"boolean\",\n role: \"boolean\",\n def: false,\n write: false,\n read: true,\n },\n native: {},\n });\n this.log.debug('Init event listener for \"motion\"');\n eventEmitter.addListener(\"motion\", async (motionDetected: any) => {\n await this.setStateAsync(id + \".motionEvent\", motionDetected, true);\n this.log.debug(`[${device.deviceName}] \"Motion detected\" ${motionDetected}`);\n });\n return;\n } else {\n this.log.info(`Unknown device type ${device.deviceName} init as P100`);\n deviceObject = new P100(this.log, device.ip, this.config.username, this.config.password, 2);\n }\n this.deviceObjects[id] = deviceObject;\n await deviceObject\n .handshake()\n .then(async () => {\n if (deviceObject.is_klap) {\n this.log.debug(\"Detected KLAP device\");\n await deviceObject.handshake_new().catch(async (error: any) => {\n this.log.error(error);\n this.log.error(error.stack);\n this.log.error(\"KLAP Handshake failed. Try old handshake\");\n deviceObject.is_klap = false;\n await deviceObject.reAuthenticate().catch(() => {\n this.log.error(\"Login failed\");\n this.deviceObjects[id]._connected = false;\n });\n });\n } else {\n await deviceObject.login().catch(() => {\n this.log.error(\"Login failed\");\n this.deviceObjects[id]._connected = false;\n });\n }\n deviceObject\n .getDeviceInfo(true)\n .then(async (sysInfo: any) => {\n this.log.debug(JSON.stringify(sysInfo));\n if (sysInfo.request) {\n this.log.error(\"Malformed response sysinfo\");\n this.log.error(JSON.stringify(sysInfo));\n return;\n }\n this.json2iob.parse(id, sysInfo);\n\n this.deviceObjects[id]._connected = true;\n if (this.deviceObjects[id].getEnergyUsage) {\n this.log.debug(\"Receive energy usage\");\n const energyUsage = await this.deviceObjects[id].getEnergyUsage();\n this.log.debug(JSON.stringify(energyUsage));\n this.json2iob.parse(id, energyUsage);\n }\n const childList = await this.deviceObjects[id].getChildDevices();\n this.log.debug(\"Childlist: \" + JSON.stringify(childList));\n if (childList && childList.error_code === 0) {\n this.json2iob.parse(id + \".childlist\", childList);\n }\n })\n .catch((error: any) => {\n this.log.error(JSON.stringify(error));\n this.log.error(\"52 - Get Device Info failed\");\n\n this.deviceObjects[id]._connected = false;\n });\n })\n .catch(() => {\n this.log.error(\"Handshake failed\");\n this.deviceObjects[id]._connected = false;\n });\n }\n\n async updateDevices(): Promise<void> {\n try {\n for (const deviceId in this.deviceObjects) {\n if (this.deviceObjects[deviceId].getStatus) {\n this.log.debug(\"Receive camera status\");\n const status = await this.deviceObjects[deviceId].getStatus().catch((error: any) => {\n this.log.info(\"Get camera Status failed\");\n this.log.debug(JSON.stringify(error));\n });\n this.log.debug(JSON.stringify(status));\n this.json2iob.parse(deviceId, status);\n if (this.deviceObjects[deviceId].stok === undefined) {\n if (this.firstStart) {\n this.log.error(\"No stok found for: \" + deviceId + \" Ignore and remove the device until next restart\");\n\n delete this.deviceObjects[deviceId];\n } else {\n this.log.info(\n \"No stok found for: \" + deviceId + \" this means the device is offline or connection lost. No update or commands possible\",\n );\n }\n }\n continue;\n }\n if (!this.deviceObjects[deviceId]._connected) {\n continue;\n }\n\n this.deviceObjects[deviceId]\n .getDeviceInfo(true)\n .then(async (sysInfo: any) => {\n this.log.debug(JSON.stringify(sysInfo));\n if (!sysInfo || sysInfo.name === \"Error\" || sysInfo.request) {\n this.log.debug(\"Malformed response sysinfo\");\n // this.log.error(JSON.stringify(sysInfo));\n return;\n }\n await this.json2iob.parse(deviceId, sysInfo);\n if (this.deviceObjects[deviceId].getEnergyUsage) {\n this.log.debug(\"Receive energy usage\");\n const energyUsage = await this.deviceObjects[deviceId].getEnergyUsage();\n this.log.debug(JSON.stringify(energyUsage));\n if (energyUsage.request) {\n this.log.error(\"Malformed response getEnergyUsage\");\n this.log.error(JSON.stringify(energyUsage));\n return;\n }\n await this.json2iob.parse(deviceId, energyUsage);\n const power_usage = this.deviceObjects[deviceId].getPowerConsumption();\n if (power_usage.request) {\n this.log.error(\"Malformed response getPowerConsumption\");\n this.log.error(JSON.stringify(power_usage));\n return;\n }\n await this.json2iob.parse(deviceId, power_usage);\n }\n })\n .catch((error: any) => {\n this.log.error(`Get Device Info failed for ${deviceId} - ${error}`);\n });\n }\n this.log.debug(\"Update done\");\n } catch (error: any) {\n this.log.warn(error);\n }\n }\n\n isBase64(str: string): boolean {\n if (str === \"\" || str.trim() === \"\") {\n return false;\n }\n try {\n const strWithoutPadding = str.replace(/=*$/, \"\");\n return btoa(atob(strWithoutPadding)) === strWithoutPadding || btoa(atob(str)) === str;\n } catch (err) {\n return false;\n }\n }\n async sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n async refreshToken(): Promise<void> {\n this.log.debug(\"Refresh token\");\n }\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n */\n private onUnload(callback: () => void): void {\n try {\n this.setState(\"info.connection\", false, true);\n this.refreshTimeout && clearTimeout(this.refreshTimeout);\n this.reLoginTimeout && clearTimeout(this.reLoginTimeout);\n this.refreshTokenTimeout && clearTimeout(this.refreshTokenTimeout);\n this.updateInterval && clearInterval(this.updateInterval);\n this.refreshTokenInterval && clearInterval(this.refreshTokenInterval);\n\n callback();\n } catch (e) {\n callback();\n }\n }\n\n /**\n * Is called if a subscribed state changes\n */\n private async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n if (state) {\n if (!state.ack) {\n const deviceId = id.split(\".\")[2];\n const command = id.split(\".\")[4];\n if (id.split(\".\")[3] !== \"remote\") {\n return;\n }\n\n if (command === \"Refresh\") {\n this.deviceObjects[deviceId]\n .getDeviceInfo(true)\n .then((sysInfo: any) => {\n this.log.debug(JSON.stringify(sysInfo));\n this.json2iob.parse(deviceId, sysInfo);\n })\n .catch((error) => {\n this.log.error(`Get Device Info failed for ${deviceId} - ${error}`);\n });\n\n return;\n }\n try {\n const cameraCommands: { [key: string]: string } = {\n setAlertConfig: \"alarm\",\n setLensMaskConfig: \"eyes\",\n setLedStatus: \"led\",\n setMsgPushConfig: \"notifications\",\n setDetectionConfig: \"motionDetection\",\n };\n if (this.deviceObjects[deviceId] && (this.deviceObjects[deviceId][command] || cameraCommands[command])) {\n let result;\n if (cameraCommands[command]) {\n result = await this.deviceObjects[deviceId].setStatus(cameraCommands[command], state.val);\n } else if (command === \"setColor\" || command === \"moveMotor\" || command === \"setPowerStateChild\") {\n const valueSplit = state.val.replace(\" \", \"\").split(\",\");\n result = await this.deviceObjects[deviceId][command](valueSplit[0], valueSplit[1]);\n } else {\n result = await this.deviceObjects[deviceId][command](state.val);\n }\n this.log.info(\n command + \" was set to : \" + state.val + \" for device \" + deviceId + \" was successful: \" + JSON.stringify(result),\n );\n this.refreshTimeout && clearTimeout(this.refreshTimeout);\n this.refreshTimeout = setTimeout(async () => {\n this.updateDevices();\n }, 2 * 1000);\n } else {\n if (this.deviceObjects[deviceId]) {\n this.log.error(`Device ${deviceId} has no command ${command}`);\n } else {\n this.log.error(`Device ${deviceId} not found`);\n }\n }\n } catch (error) {\n this.log.error(error);\n }\n } else {\n const resultDict: { [key: string]: string } = {\n device_on: \"setPowerState\",\n eyes: \"setLensMaskConfig\",\n alarm: \"setAlertConfig\",\n led: \"setLedStatus\",\n notifications: \"setMsgPushConfig\",\n motionDetection: \"setDetectionConfig\",\n };\n const idArray = id.split(\".\");\n const stateName = idArray[idArray.length - 1];\n const deviceId = id.split(\".\")[2];\n if (resultDict[stateName]) {\n await this.setState(deviceId + \".remote.\" + resultDict[stateName], state.val, true);\n }\n }\n }\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Tapo(options);\n} else {\n // otherwise start the instance directly\n (() => new Tapo())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Json2iob", "axios", "https", "crypto", "uuidv4", "body", "path", "md5", "content", "signature", "res", "_a", "_b", "P100", "P110", "L530", "L510E", "L520E"]
|
|
7
7
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "tapo",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.8",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.4.8": {
|
|
7
|
+
"en": "disable sentry to prevent crashes",
|
|
8
|
+
"de": "deaktivieren der sendung, um abstürzen zu verhindern",
|
|
9
|
+
"ru": "отключить отсылку для предотвращения аварий",
|
|
10
|
+
"pt": "desativar o sentinela para evitar falhas",
|
|
11
|
+
"nl": "sentry uitschakelen om crashes te voorkomen",
|
|
12
|
+
"fr": "désactiver la sentinelle pour prévenir les accidents",
|
|
13
|
+
"it": "disabilitare la sentinella per prevenire gli incidenti",
|
|
14
|
+
"es": "deshabilitar el centinela para evitar accidentes",
|
|
15
|
+
"pl": "wyłączyć wartownik, aby zapobiec awarii",
|
|
16
|
+
"uk": "відключити відправника для запобігання аварійних ситуацій",
|
|
17
|
+
"zh-cn": "禁用哨兵来防止碰撞"
|
|
18
|
+
},
|
|
19
|
+
"0.4.7": {
|
|
20
|
+
"en": "disable battery devices\nimproved wrong formatted mail adresses",
|
|
21
|
+
"de": "akku-geräte deaktivieren\nverbesserte falsch formatierte mail-adressen",
|
|
22
|
+
"ru": "отключения аккумуляторных устройств\nулучшенные неправильные отформатированные почтовые адреса",
|
|
23
|
+
"pt": "desativar dispositivos de bateria\nendereços de correio formatado errado melhorado",
|
|
24
|
+
"nl": "batterijapparatuur uitschakelen\nverbeterde verkeerde geformatteerde e-mailadressen",
|
|
25
|
+
"fr": "désactiver les dispositifs de batterie\nmeilleures adresses de courrier mal formatées",
|
|
26
|
+
"it": "disabilitare i dispositivi della batteria\nmigliorato sbagliato formattato indirizzi di posta",
|
|
27
|
+
"es": "dispositivos de batería deshabilitables\nmejorado mal formateado direcciones de correo",
|
|
28
|
+
"pl": "wyłączyć urządzenia akumulacyjne\npoprawiła nieprawidłowe formatowane adresy poczty",
|
|
29
|
+
"uk": "акумуляторні пристрої\nпокращені неправильні форматовані адреси пошти",
|
|
30
|
+
"zh-cn": "禁用电池设备\n改进格式错误的邮件外衣"
|
|
31
|
+
},
|
|
32
|
+
"0.4.6": {
|
|
33
|
+
"en": "add checks for battery devices",
|
|
34
|
+
"de": "überprüfungen für batteriegeräte hinzufügen",
|
|
35
|
+
"ru": "добавить чеки для устройств батареи",
|
|
36
|
+
"pt": "adicionar verificações para dispositivos de bateria",
|
|
37
|
+
"nl": "controles voor batterijapparatuur toevoegen",
|
|
38
|
+
"fr": "ajouter des contrôles pour les dispositifs de batterie",
|
|
39
|
+
"it": "aggiungere i controlli per i dispositivi a batteria",
|
|
40
|
+
"es": "añadir cheques para dispositivos de batería",
|
|
41
|
+
"pl": "dodać kontrole urządzeń akumulatorowych",
|
|
42
|
+
"uk": "додавання перевірок для пристроїв акумулятора",
|
|
43
|
+
"zh-cn": "添加电池设备检查"
|
|
44
|
+
},
|
|
6
45
|
"0.4.5": {
|
|
7
46
|
"en": "fix camera remotes",
|
|
8
47
|
"de": "kamera-fernbedienungen reparieren",
|
|
@@ -91,11 +130,6 @@
|
|
|
91
130
|
"adminUI": {
|
|
92
131
|
"config": "json"
|
|
93
132
|
},
|
|
94
|
-
"plugins": {
|
|
95
|
-
"sentry": {
|
|
96
|
-
"dsn": "https://2b10e03f7b784f3b921bdd7836ff517e@sentry.iobroker.net/209"
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
133
|
"dependencies": [
|
|
100
134
|
{
|
|
101
135
|
"js-controller": ">=3.2.0"
|
|
@@ -119,7 +153,8 @@
|
|
|
119
153
|
"mfa": "",
|
|
120
154
|
"streamusername": "",
|
|
121
155
|
"streampassword": "",
|
|
122
|
-
"interval": 10
|
|
156
|
+
"interval": 10,
|
|
157
|
+
"enableBatteryDevices": false
|
|
123
158
|
},
|
|
124
159
|
"objects": [],
|
|
125
160
|
"instanceObjects": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.tapo",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Adapter for TP-Link Tapo",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "TA2k",
|
|
@@ -22,39 +22,39 @@
|
|
|
22
22
|
"@alcalzone/release-script-plugin-license": "^3.7.0",
|
|
23
23
|
"@alcalzone/release-script-plugin-manual-review": "^3.7.0",
|
|
24
24
|
"@iobroker/adapter-core": "^3.2.3",
|
|
25
|
-
"@iobroker/testing": "^5.0.
|
|
25
|
+
"@iobroker/testing": "^5.0.3",
|
|
26
26
|
"axios": "^1.7.9",
|
|
27
27
|
"json-bigint": "^1.0.0",
|
|
28
|
-
"json2iob": "^2.6.
|
|
28
|
+
"json2iob": "^2.6.16",
|
|
29
29
|
"node-fetch": "^2.7.0",
|
|
30
30
|
"onvif": "^0.8.0",
|
|
31
|
-
"qs": "^6.
|
|
32
|
-
"undici": "^6.21.
|
|
31
|
+
"qs": "^6.14.0",
|
|
32
|
+
"undici": "^6.21.1",
|
|
33
33
|
"utf8": "^3.0.0",
|
|
34
|
-
"uuid": "^11.0.
|
|
34
|
+
"uuid": "^11.0.5"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@eslint/eslintrc": "^3.2.0",
|
|
38
|
-
"@eslint/js": "^9.
|
|
39
|
-
"@iobroker/testing": "^5.0.
|
|
38
|
+
"@eslint/js": "^9.19.0",
|
|
39
|
+
"@iobroker/testing": "^5.0.3",
|
|
40
40
|
"@types/chai-as-promised": "^8.0.1",
|
|
41
41
|
"@types/json-bigint": "^1.0.4",
|
|
42
|
-
"@types/node": "^22.
|
|
42
|
+
"@types/node": "^22.13.1",
|
|
43
43
|
"@types/proxyquire": "^1.3.31",
|
|
44
44
|
"@types/utf8": "^3.0.3",
|
|
45
45
|
"@types/uuid": "^10.0.0",
|
|
46
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
47
|
-
"@typescript-eslint/parser": "^8.
|
|
48
|
-
"eslint": "^9.
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^8.23.0",
|
|
47
|
+
"@typescript-eslint/parser": "^8.23.0",
|
|
48
|
+
"eslint": "^9.19.0",
|
|
49
49
|
"eslint-config-prettier": "^9.1.0",
|
|
50
|
-
"eslint-plugin-prettier": "^5.2.
|
|
51
|
-
"globals": "^15.
|
|
50
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
51
|
+
"globals": "^15.14.0",
|
|
52
52
|
"prettier": "^3.4.2",
|
|
53
53
|
"proxyquire": "^2.1.3",
|
|
54
54
|
"source-map-support": "^0.5.21",
|
|
55
55
|
"ts-node": "^10.9.2",
|
|
56
|
-
"typescript": "~5.7.
|
|
57
|
-
"typescript-eslint": "^8.
|
|
56
|
+
"typescript": "~5.7.3",
|
|
57
|
+
"typescript-eslint": "^8.23.0"
|
|
58
58
|
},
|
|
59
59
|
"main": "build/main.js",
|
|
60
60
|
"files": [
|