iobroker.tapo 0.2.0 → 0.2.1
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/README.md +0 -6
- package/build/lib/utils/camera/onvifCamera.js.map +2 -2
- package/build/lib/utils/camera/tapoCamera.js +25 -11
- package/build/lib/utils/camera/tapoCamera.js.map +2 -2
- package/build/lib/utils/l530.js +1 -1
- package/build/lib/utils/l530.js.map +2 -2
- package/build/lib/utils/p100.js +24 -11
- package/build/lib/utils/p100.js.map +2 -2
- package/build/main.js +20 -10
- package/build/main.js.map +2 -2
- package/io-package.json +4 -1
- package/package.json +15 -17
- package/build/lib/json2iob.js +0 -279
- package/build/lib/json2iob.js.map +0 -7
- package/build/lib/utils/camera.js +0 -97
- package/build/lib/utils/camera.js.map +0 -7
package/README.md
CHANGED
|
@@ -32,12 +32,6 @@ tapo.0.id.remote auf true/false setzen steuert den jeweiligen Befehl. Der Befehl
|
|
|
32
32
|
|
|
33
33
|
<https://forum.iobroker.net/topic/57336/test-adapter-tp-link-tapo/>
|
|
34
34
|
|
|
35
|
-
## Changelog
|
|
36
|
-
|
|
37
|
-
### 0.0.2
|
|
38
|
-
|
|
39
|
-
- (TA2k) initial release
|
|
40
|
-
|
|
41
35
|
## License
|
|
42
36
|
|
|
43
37
|
MIT License
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/camera/onvifCamera.ts"],
|
|
4
|
-
"sourcesContent": ["import { DeviceInformation, VideoSource, NotificationMessage, Cam as ICam } from \"./types/onvif\";\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport { Cam } from \"onvif\";\nimport { EventEmitter } from \"stream\";\ntype CameraConfig = {\n name: string;\n ipAddress: string;\n password: string;\n streamUser: string;\n streamPassword: string;\n\n pullInterval?: number;\n disableStreaming?: boolean;\n disablePrivacyAccessory?: boolean;\n disableAlarmAccessory?: boolean;\n disableMotionAccessory?: boolean;\n lowQuality?: boolean;\n};\nexport class OnvifCamera {\n private events: EventEmitter | undefined;\n private device: Cam | undefined;\n\n private readonly kOnvifPort = 2020;\n\n constructor(protected readonly config: CameraConfig) {}\n\n private async getDevice(): Promise<ICam> {\n return new Promise((resolve, reject) => {\n if (this.device) {\n return resolve(this.device);\n }\n\n const device: ICam = new Cam(\n {\n hostname: this.config.ipAddress,\n username: this.config.streamUser,\n password: this.config.streamPassword,\n port: this.kOnvifPort,\n },\n (err: Error) => {\n if (err) {\n return reject(err);\n }\n this.device = device;\n return resolve(this.device);\n },\n );\n });\n }\n\n async getEventEmitter() {\n if (this.events) {\n return this.events;\n }\n\n const onvifDevice = await this.getDevice();\n\n let lastMotionValue = false;\n\n this.events = new EventEmitter();\n\n onvifDevice.on(\"event\", (event: NotificationMessage) => {\n if (event?.topic?._?.match(/RuleEngine\\/CellMotionDetector\\/Motion$/)) {\n const motion = event.message.message.data.simpleItem.$.Value;\n if (motion !== lastMotionValue) {\n lastMotionValue = Boolean(motion);\n this.events = this.events || new EventEmitter();\n this.events.emit(\"motion\", motion);\n }\n }\n });\n\n return this.events;\n }\n\n async getVideoSource(): Promise<VideoSource> {\n const onvifDevice = await this.getDevice();\n return onvifDevice.videoSources[0];\n }\n\n async getDeviceInfo(): Promise<DeviceInformation> {\n const onvifDevice = await this.getDevice();\n return new Promise((resolve, reject) => {\n onvifDevice.getDeviceInformation((err, deviceInformation) => {\n if (err) return reject(err);\n resolve(deviceInformation);\n });\n });\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,IAAAA,gBAAoB;AACpB,oBAA6B;
|
|
4
|
+
"sourcesContent": ["import { DeviceInformation, VideoSource, NotificationMessage, Cam as ICam } from \"./types/onvif\";\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport { Cam } from \"onvif\";\nimport { EventEmitter } from \"stream\";\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 disablePrivacyAccessory?: boolean;\n disableAlarmAccessory?: boolean;\n disableMotionAccessory?: boolean;\n lowQuality?: boolean;\n\n videoConfig?: VideoConfig;\n\n privacyAccessoryName?: string;\n alarmAccessoryName?: string;\n};\nexport class OnvifCamera {\n private events: EventEmitter | undefined;\n private device: Cam | undefined;\n\n private readonly kOnvifPort = 2020;\n\n constructor(protected readonly config: CameraConfig) {}\n\n private async getDevice(): Promise<ICam> {\n return new Promise((resolve, reject) => {\n if (this.device) {\n return resolve(this.device);\n }\n\n const device: ICam = new Cam(\n {\n hostname: this.config.ipAddress,\n username: this.config.streamUser,\n password: this.config.streamPassword,\n port: this.kOnvifPort,\n },\n (err: Error) => {\n if (err) {\n return reject(err);\n }\n this.device = device;\n return resolve(this.device);\n },\n );\n });\n }\n\n async getEventEmitter() {\n if (this.events) {\n return this.events;\n }\n\n const onvifDevice = await this.getDevice();\n\n let lastMotionValue = false;\n\n this.events = new EventEmitter();\n\n onvifDevice.on(\"event\", (event: NotificationMessage) => {\n if (event?.topic?._?.match(/RuleEngine\\/CellMotionDetector\\/Motion$/)) {\n const motion = event.message.message.data.simpleItem.$.Value;\n if (motion !== lastMotionValue) {\n lastMotionValue = Boolean(motion);\n this.events = this.events || new EventEmitter();\n this.events.emit(\"motion\", motion);\n }\n }\n });\n\n return this.events;\n }\n\n async getVideoSource(): Promise<VideoSource> {\n const onvifDevice = await this.getDevice();\n return onvifDevice.videoSources[0];\n }\n\n async getDeviceInfo(): Promise<DeviceInformation> {\n const onvifDevice = await this.getDevice();\n return new Promise((resolve, reject) => {\n onvifDevice.getDeviceInformation((err, deviceInformation) => {\n if (err) return reject(err);\n resolve(deviceInformation);\n });\n });\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,IAAAA,gBAAoB;AACpB,oBAA6B;AAqBtB,MAAM,YAAY;AAAA,EAMvB,YAA+B,QAAsB;AAAtB;AAF/B,SAAiB,aAAa;AAAA,EAEwB;AAAA,EAEtD,MAAc,YAA2B;AACvC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,KAAK,QAAQ;AACf,eAAO,QAAQ,KAAK,MAAM;AAAA,MAC5B;AAEA,YAAM,SAAe,IAAI;AAAA,QACvB;AAAA,UACE,UAAU,KAAK,OAAO;AAAA,UACtB,UAAU,KAAK,OAAO;AAAA,UACtB,UAAU,KAAK,OAAO;AAAA,UACtB,MAAM,KAAK;AAAA,QACb;AAAA,QACA,CAAC,QAAe;AACd,cAAI,KAAK;AACP,mBAAO,OAAO,GAAG;AAAA,UACnB;AACA,eAAK,SAAS;AACd,iBAAO,QAAQ,KAAK,MAAM;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,kBAAkB;AACtB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,cAAc,MAAM,KAAK,UAAU;AAEzC,QAAI,kBAAkB;AAEtB,SAAK,SAAS,IAAI,2BAAa;AAE/B,gBAAY,GAAG,SAAS,CAAC,UAA+B;AApE5D;AAqEM,WAAI,0CAAO,UAAP,mBAAc,MAAd,mBAAiB,MAAM,4CAA4C;AACrE,cAAM,SAAS,MAAM,QAAQ,QAAQ,KAAK,WAAW,EAAE;AACvD,YAAI,WAAW,iBAAiB;AAC9B,4BAAkB,QAAQ,MAAM;AAChC,eAAK,SAAS,KAAK,UAAU,IAAI,2BAAa;AAC9C,eAAK,OAAO,KAAK,UAAU,MAAM;AAAA,QACnC;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,iBAAuC;AAC3C,UAAM,cAAc,MAAM,KAAK,UAAU;AACzC,WAAO,YAAY,aAAa;AAAA,EAClC;AAAA,EAEA,MAAM,gBAA4C;AAChD,UAAM,cAAc,MAAM,KAAK,UAAU;AACzC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,kBAAY,qBAAqB,CAAC,KAAK,sBAAsB;AAC3D,YAAI;AAAK,iBAAO,OAAO,GAAG;AAC1B,gBAAQ,iBAAiB;AAAA,MAC3B,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;",
|
|
6
6
|
"names": ["import_onvif"]
|
|
7
7
|
}
|
|
@@ -142,13 +142,14 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
142
142
|
}
|
|
143
143
|
response = await this.fetch(`https://${this.config.ipAddress}`, fetchParams);
|
|
144
144
|
responseData = await response.json();
|
|
145
|
-
this.log.debug("StokRefresh: Login response :>> "
|
|
145
|
+
this.log.debug("StokRefresh: Login response :>> " + response.status + JSON.stringify(responseData));
|
|
146
146
|
if (response.status === 401) {
|
|
147
147
|
if (((_b = (_a = responseData == null ? void 0 : responseData.result) == null ? void 0 : _a.data) == null ? void 0 : _b.code) === 40411) {
|
|
148
148
|
throw new Error("Invalid credentials");
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
if (isSecureConnection) {
|
|
152
|
+
this.log.debug("StokRefresh: Using secure connection");
|
|
152
153
|
const nonce = (_d = (_c = responseData == null ? void 0 : responseData.result) == null ? void 0 : _c.data) == null ? void 0 : _d.nonce;
|
|
153
154
|
const deviceConfirm = (_f = (_e = responseData == null ? void 0 : responseData.result) == null ? void 0 : _e.data) == null ? void 0 : _f.device_confirm;
|
|
154
155
|
if (nonce && deviceConfirm && this.validateDeviceConfirm(nonce, deviceConfirm)) {
|
|
@@ -171,7 +172,7 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
171
172
|
})
|
|
172
173
|
});
|
|
173
174
|
responseData = await response.json();
|
|
174
|
-
this.log.debug("StokRefresh: Start_seq response :>>"
|
|
175
|
+
this.log.debug("StokRefresh: Start_seq response :>>" + response.status + JSON.stringify(responseData));
|
|
175
176
|
if ((_g = responseData == null ? void 0 : responseData.result) == null ? void 0 : _g.start_seq) {
|
|
176
177
|
if (((_h = responseData == null ? void 0 : responseData.result) == null ? void 0 : _h.user_group) !== "root") {
|
|
177
178
|
throw new Error("Incorrect user_group detected");
|
|
@@ -192,14 +193,12 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
192
193
|
}
|
|
193
194
|
if ((_m = responseData == null ? void 0 : responseData.result) == null ? void 0 : _m.stok) {
|
|
194
195
|
this.stok = responseData.result.stok;
|
|
195
|
-
this.log.debug("StokRefresh: Success :>>"
|
|
196
|
+
this.log.debug("StokRefresh: Success :>>" + this.stok);
|
|
196
197
|
return this.stok;
|
|
197
198
|
}
|
|
198
199
|
if ((responseData == null ? void 0 : responseData.error_code) === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {
|
|
199
200
|
this.log.debug(
|
|
200
|
-
`Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}
|
|
201
|
-
response.status,
|
|
202
|
-
JSON.stringify(responseData)
|
|
201
|
+
`Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.` + response.status + JSON.stringify(responseData)
|
|
203
202
|
);
|
|
204
203
|
return this.refreshStok(loginRetryCount + 1);
|
|
205
204
|
}
|
|
@@ -218,8 +217,9 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
218
217
|
}
|
|
219
218
|
})
|
|
220
219
|
});
|
|
220
|
+
this.log.debug(JSON.stringify(response));
|
|
221
221
|
const json = await response.json();
|
|
222
|
-
this.log.debug("isSecureConnection response :>> "
|
|
222
|
+
this.log.debug("isSecureConnection response :>> " + response.status + json);
|
|
223
223
|
this.isSecureConnectionValue = json.error_code == -40413 && ((_c = (_b = (_a = json == null ? void 0 : json.result) == null ? void 0 : _a.data) == null ? void 0 : _b.encrypt_type) == null ? void 0 : _c.includes("3"));
|
|
224
224
|
}
|
|
225
225
|
return this.isSecureConnectionValue;
|
|
@@ -279,7 +279,7 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
279
279
|
if (this.pendingAPIRequests.has(reqJson)) {
|
|
280
280
|
return this.pendingAPIRequests.get(reqJson);
|
|
281
281
|
}
|
|
282
|
-
this.log.debug("API new request"
|
|
282
|
+
this.log.debug("API new request: " + reqJson);
|
|
283
283
|
this.pendingAPIRequests.set(
|
|
284
284
|
reqJson,
|
|
285
285
|
(async () => {
|
|
@@ -317,7 +317,7 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
317
317
|
} else {
|
|
318
318
|
json = json;
|
|
319
319
|
}
|
|
320
|
-
this.log.debug(`API response
|
|
320
|
+
this.log.debug(`API response: ` + response.status, JSON.stringify(json));
|
|
321
321
|
if (isSecureConnection && response.status === 500) {
|
|
322
322
|
this.stok = void 0;
|
|
323
323
|
}
|
|
@@ -335,7 +335,7 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
335
335
|
return this.pendingAPIRequests.get(reqJson);
|
|
336
336
|
}
|
|
337
337
|
async setLensMaskConfig(value) {
|
|
338
|
-
this.log.debug("Processing setLensMaskConfig"
|
|
338
|
+
this.adapter.log.debug("Processing setLensMaskConfig" + value);
|
|
339
339
|
const json = await this.apiRequest({
|
|
340
340
|
method: "multipleRequest",
|
|
341
341
|
params: {
|
|
@@ -358,7 +358,7 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
360
|
async setAlertConfig(value) {
|
|
361
|
-
this.log.debug("Processing setAlertConfig"
|
|
361
|
+
this.log.debug("Processing setAlertConfig" + value);
|
|
362
362
|
const json = await this.apiRequest({
|
|
363
363
|
method: "multipleRequest",
|
|
364
364
|
params: {
|
|
@@ -398,6 +398,20 @@ class TAPOCamera extends import_onvifCamera.OnvifCamera {
|
|
|
398
398
|
});
|
|
399
399
|
return json.error_code !== 0;
|
|
400
400
|
}
|
|
401
|
+
async moveMotorStep(angle) {
|
|
402
|
+
angle = angle.toString();
|
|
403
|
+
const json = await this.apiRequest({ method: "do", motor: { movestep: { direction: angle } } });
|
|
404
|
+
return json.error_code !== 0;
|
|
405
|
+
}
|
|
406
|
+
async moveMotor(x, y) {
|
|
407
|
+
const json = await this.apiRequest({
|
|
408
|
+
method: "multipleRequest",
|
|
409
|
+
params: {
|
|
410
|
+
requests: [{ method: "do", motor: { move: { x_coord: x, y_coord: y } } }]
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
return json.error_code !== 0;
|
|
414
|
+
}
|
|
401
415
|
async getBasicInfo() {
|
|
402
416
|
const json = await this.apiRequest({
|
|
403
417
|
method: "multipleRequest",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/utils/camera/tapoCamera.ts"],
|
|
4
|
-
"sourcesContent": ["import fetch, { RequestInit } from \"node-fetch\";\nimport https, { Agent } from \"https\";\nimport crypto from \"crypto\";\nimport { OnvifCamera } from \"./onvifCamera\";\nimport type {\n TAPOCameraEncryptedRequest,\n TAPOCameraEncryptedResponse,\n TAPOCameraRequest,\n TAPOCameraResponse,\n TAPOCameraResponseDeviceInfo,\n TAPOCameraResponseGetAlert,\n TAPOCameraResponseGetLensMask,\n} from \"./types/tapo\";\n\nconst MAX_LOGIN_RETRIES = 3;\nconst AES_BLOCK_SIZE = 16;\n\ntype CameraConfig = {\n name: string;\n ipAddress: string;\n password: string;\n streamUser: string;\n streamPassword: string;\n\n pullInterval?: number;\n disableStreaming?: boolean;\n disablePrivacyAccessory?: boolean;\n disableAlarmAccessory?: boolean;\n disableMotionAccessory?: boolean;\n lowQuality?: boolean;\n};\nexport class TAPOCamera extends OnvifCamera {\n private readonly kStreamPort = 554;\n private readonly httpsAgent: Agent;\n\n private readonly hashedMD5Password: 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<string>) | 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 private loginRetryCount = 0;\n\n constructor(\n protected readonly log: any,\n protected readonly config: CameraConfig,\n ) {\n super(log, config);\n this.log.debug(\"Constructing Camera on host: \" + config.ipAddress);\n\n this.httpsAgent = new https.Agent({\n rejectUnauthorized: false,\n });\n\n this.cnonce = this.generateCnonce();\n\n this.hashedMD5Password = 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() {\n const headers: Record<string, string> = {\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 return headers;\n }\n\n private getHashedPassword() {\n if (this.passwordEncryptionMethod === \"md5\") {\n return this.hashedMD5Password;\n } else if (this.passwordEncryptionMethod === \"sha256\") {\n return this.hashedSha256Password;\n } else {\n throw new Error(\"Unknown password encryption method\");\n }\n }\n\n private fetch(url: string, data: RequestInit) {\n return fetch(url, {\n agent: this.httpsAgent,\n headers: this.getHeaders(),\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 const hashedNoncesWithSHA256 = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.hashedSha256Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n const hashedNoncesWithMD5 = crypto\n .createHash(\"md5\")\n .update(this.cnonce + this.hashedMD5Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n if (deviceConfirm === hashedNoncesWithSHA256 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"sha256\";\n return true;\n }\n\n if (deviceConfirm === hashedNoncesWithMD5 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"md5\";\n return true;\n }\n\n return false;\n }\n\n async refreshStok(loginRetryCount = 0): Promise<string> {\n const isSecureConnection = await this.isSecureConnection();\n\n let response = null;\n let responseData = null;\n\n let fetchParams = {};\n if (isSecureConnection) {\n this.log.debug(\"StokRefresh: Using secure connection\");\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 this.log.debug(\"StokRefresh: Using unsecure connection\");\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n username: this.getUsername(),\n password: this.getHashedPassword(),\n hashed: true,\n },\n }),\n };\n }\n\n response = await this.fetch(`https://${this.config.ipAddress}`, fetchParams);\n responseData = await response.json();\n\n this.log.debug(\"StokRefresh: Login response :>> \", response.status, JSON.stringify(responseData));\n\n if (response.status === 401) {\n if (responseData?.result?.data?.code === 40411) {\n throw new Error(\"Invalid credentials\");\n }\n }\n\n if (isSecureConnection) {\n const nonce = responseData?.result?.data?.nonce;\n const deviceConfirm = responseData?.result?.data?.device_confirm;\n\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 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();\n\n this.log.debug(\"StokRefresh: Start_seq response :>>\", response.status, JSON.stringify(responseData));\n\n if (responseData?.result?.start_seq) {\n if (responseData?.result?.user_group !== \"root\") {\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 throw new 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 }\n } else {\n this.passwordEncryptionMethod = \"md5\";\n }\n\n if (responseData?.result?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: Temporary Suspension: Try again in ${responseData.result.data.sec_left} seconds`);\n }\n\n if (responseData?.data?.code == -40404 && responseData?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: 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(\"StokRefresh: Success :>>\", this.stok);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.stok!;\n }\n\n if (responseData?.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.`,\n response.status,\n JSON.stringify(responseData),\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n throw new Error(\"Invalid authentication data\");\n }\n\n async isSecureConnection() {\n if (this.isSecureConnectionValue === null) {\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 json = await response.json();\n\n this.log.debug(\"isSecureConnection response :>> \", response.status, json);\n\n this.isSecureConnectionValue = json.error_code == -40413 && json?.result?.data?.encrypt_type?.includes(\"3\");\n }\n\n return this.isSecureConnectionValue;\n }\n\n getStok(loginRetryCount = 0): Promise<string> {\n if (this.stok) {\n return new Promise((resolve) => resolve(this.stok!));\n }\n\n if (!this.stokPromise) {\n this.stokPromise = () => this.refreshStok(loginRetryCount);\n }\n\n return this.stokPromise()\n .then(() => {\n return this.stok!;\n })\n .finally(() => {\n this.stokPromise = undefined;\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 throw new Error(\"Invalid padding\");\n }\n for (let i = text.length - paddingLength; i < text.length; i++) {\n if (text.charCodeAt(i) !== paddingLength) {\n throw new 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 return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n this.log.debug(\"API new request\", reqJson);\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);\n let json = await response.json();\n\n if (isSecureConnection) {\n const encryptedResponse = json as TAPOCameraEncryptedResponse;\n if (encryptedResponse.result.response) {\n const decryptedResponse = this.decryptResponse(encryptedResponse.result.response);\n json = JSON.parse(decryptedResponse) as TAPOCameraResponse;\n }\n } else {\n json = json as TAPOCameraResponse;\n }\n\n this.log.debug(`API response`, response.status, JSON.stringify(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.stok = undefined;\n }\n\n // Check if we have to refresh the token\n if (json.error_code === -40401 || json.error_code === -1) {\n this.log.debug(\"API request failed, reauthenticating\");\n this.stok = undefined;\n return this.apiRequest(req, loginRetryCount + 1);\n }\n\n return json as TAPOCameraResponse;\n } finally {\n this.pendingAPIRequests.delete(reqJson);\n }\n })(),\n );\n\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n async setLensMaskConfig(value: boolean) {\n this.log.debug(\"Processing setLensMaskConfig\", value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setLensMaskConfig\",\n params: {\n lens_mask: {\n lens_mask_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n if (json.error_code !== 0) {\n throw new Error(\"Failed to perform action\");\n }\n }\n\n async setAlertConfig(value: boolean) {\n this.log.debug(\"Processing setAlertConfig\", value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setAlertConfig\",\n params: {\n msg_alarm: {\n chn1_msg_alarm_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\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\n async getBasicInfo() {\n const json = 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 = json.result.responses[0] as TAPOCameraResponseDeviceInfo;\n return info.result.device_info.basic_info;\n }\n\n async getStatus(): Promise<{ lensMask: boolean; alert: boolean }> {\n const json = 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: \"getForceWhitelampState\",\n params: {\n image: {\n name: \"switch\",\n },\n },\n },\n ],\n },\n });\n this.log.debug(`getStatus json: ${JSON.stringify(json)}`);\n if (json.error_code !== 0) {\n throw new Error(\"Camera replied with error\");\n }\n if (!json.result.responses) {\n throw new Error(\"Camera replied with invalid response\");\n }\n const alertConfig = json.result.responses.find((r) => r.method === \"getAlertConfig\") as TAPOCameraResponseGetAlert;\n\n const forceWhitelampState = json.result.responses.find((r) => r.method === \"getForceWhitelampState\") as TAPOCameraResponseGetForce;\n const lensMaskConfig = json.result.responses.find((r) => r.method === \"getLensMaskConfig\") as TAPOCameraResponseGetLensMask;\n\n return {\n alert: alertConfig.result.msg_alarm.chn1_msg_alarm_info.enabled === \"on\",\n lensMask: lensMaskConfig.result.lens_mask.lens_mask_info.enabled === \"on\",\n forceWhiteLamp: forceWhitelampState.result.image ? forceWhitelampState.result.image.switch.force_wtl_state === \"on\" : false,\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import fetch, { RequestInit } from \"node-fetch\";\nimport https, { Agent } from \"https\";\nimport crypto from \"crypto\";\nimport { OnvifCamera } from \"./onvifCamera\";\nimport type {\n TAPOCameraEncryptedRequest,\n TAPOCameraEncryptedResponse,\n TAPOCameraRequest,\n TAPOCameraResponse,\n TAPOCameraResponseDeviceInfo,\n TAPOCameraResponseGetAlert,\n TAPOCameraResponseGetLensMask,\n} from \"./types/tapo\";\n\nconst MAX_LOGIN_RETRIES = 3;\nconst AES_BLOCK_SIZE = 16;\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 disablePrivacyAccessory?: boolean;\n disableAlarmAccessory?: boolean;\n disableMotionAccessory?: boolean;\n lowQuality?: boolean;\n\n videoConfig?: VideoConfig;\n\n privacyAccessoryName?: string;\n alarmAccessoryName?: string;\n};\nexport class TAPOCamera extends OnvifCamera {\n private readonly kStreamPort = 554;\n private readonly httpsAgent: Agent;\n\n private readonly hashedMD5Password: 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<string>) | 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 private loginRetryCount = 0;\n\n constructor(\n protected readonly log: any,\n protected readonly config: CameraConfig,\n ) {\n super(log, config);\n this.log.debug(\"Constructing Camera on host: \" + config.ipAddress);\n\n this.httpsAgent = new https.Agent({\n rejectUnauthorized: false,\n });\n\n this.cnonce = this.generateCnonce();\n\n this.hashedMD5Password = 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() {\n const headers: Record<string, string> = {\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 return headers;\n }\n\n private getHashedPassword() {\n if (this.passwordEncryptionMethod === \"md5\") {\n return this.hashedMD5Password;\n } else if (this.passwordEncryptionMethod === \"sha256\") {\n return this.hashedSha256Password;\n } else {\n throw new Error(\"Unknown password encryption method\");\n }\n }\n\n private fetch(url: string, data: RequestInit) {\n return fetch(url, {\n agent: this.httpsAgent,\n headers: this.getHeaders(),\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 const hashedNoncesWithSHA256 = crypto\n .createHash(\"sha256\")\n .update(this.cnonce + this.hashedSha256Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n const hashedNoncesWithMD5 = crypto\n .createHash(\"md5\")\n .update(this.cnonce + this.hashedMD5Password + nonce)\n .digest(\"hex\")\n .toUpperCase();\n\n if (deviceConfirm === hashedNoncesWithSHA256 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"sha256\";\n return true;\n }\n\n if (deviceConfirm === hashedNoncesWithMD5 + nonce + this.cnonce) {\n this.passwordEncryptionMethod = \"md5\";\n return true;\n }\n\n return false;\n }\n\n async refreshStok(loginRetryCount = 0): Promise<string> {\n const isSecureConnection = await this.isSecureConnection();\n\n let response = null;\n let responseData = null;\n\n let fetchParams = {};\n if (isSecureConnection) {\n this.log.debug(\"StokRefresh: Using secure connection\");\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 this.log.debug(\"StokRefresh: Using unsecure connection\");\n fetchParams = {\n method: \"post\",\n body: JSON.stringify({\n method: \"login\",\n params: {\n username: this.getUsername(),\n password: this.getHashedPassword(),\n hashed: true,\n },\n }),\n };\n }\n\n response = await this.fetch(`https://${this.config.ipAddress}`, fetchParams);\n responseData = await response.json();\n\n this.log.debug(\"StokRefresh: Login response :>> \" + response.status + JSON.stringify(responseData));\n\n if (response.status === 401) {\n if (responseData?.result?.data?.code === 40411) {\n throw new Error(\"Invalid credentials\");\n }\n }\n\n if (isSecureConnection) {\n this.log.debug(\"StokRefresh: Using secure connection\");\n const nonce = responseData?.result?.data?.nonce;\n const deviceConfirm = responseData?.result?.data?.device_confirm;\n\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 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();\n\n this.log.debug(\"StokRefresh: Start_seq response :>>\" + response.status + JSON.stringify(responseData));\n\n if (responseData?.result?.start_seq) {\n if (responseData?.result?.user_group !== \"root\") {\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 throw new 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 }\n } else {\n this.passwordEncryptionMethod = \"md5\";\n }\n\n if (responseData?.result?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: Temporary Suspension: Try again in ${responseData.result.data.sec_left} seconds`);\n }\n\n if (responseData?.data?.code == -40404 && responseData?.data?.sec_left > 0) {\n throw new Error(`StokRefresh: 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(\"StokRefresh: Success :>>\" + this.stok);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this.stok!;\n }\n\n if (responseData?.error_code === -40413 && loginRetryCount < MAX_LOGIN_RETRIES) {\n this.log.debug(\n `Unexpected response, retrying: ${loginRetryCount}/${MAX_LOGIN_RETRIES}.` + response.status + JSON.stringify(responseData),\n );\n return this.refreshStok(loginRetryCount + 1);\n }\n\n throw new Error(\"Invalid authentication data\");\n }\n\n async isSecureConnection() {\n if (this.isSecureConnectionValue === null) {\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 this.log.debug(JSON.stringify(response));\n const json = await response.json();\n\n this.log.debug(\"isSecureConnection response :>> \" + response.status + json);\n\n this.isSecureConnectionValue = json.error_code == -40413 && json?.result?.data?.encrypt_type?.includes(\"3\");\n }\n\n return this.isSecureConnectionValue;\n }\n\n getStok(loginRetryCount = 0): Promise<string> {\n if (this.stok) {\n return new Promise((resolve) => resolve(this.stok!));\n }\n\n if (!this.stokPromise) {\n this.stokPromise = () => this.refreshStok(loginRetryCount);\n }\n\n return this.stokPromise()\n .then(() => {\n return this.stok!;\n })\n .finally(() => {\n this.stokPromise = undefined;\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 throw new Error(\"Invalid padding\");\n }\n for (let i = text.length - paddingLength; i < text.length; i++) {\n if (text.charCodeAt(i) !== paddingLength) {\n throw new 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 return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n this.log.debug(\"API new request: \" + reqJson);\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);\n let json = await response.json();\n\n if (isSecureConnection) {\n const encryptedResponse = json as TAPOCameraEncryptedResponse;\n if (encryptedResponse.result.response) {\n const decryptedResponse = this.decryptResponse(encryptedResponse.result.response);\n json = JSON.parse(decryptedResponse) as TAPOCameraResponse;\n }\n } else {\n json = json as TAPOCameraResponse;\n }\n\n this.log.debug(`API response: ` + response.status, JSON.stringify(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.stok = undefined;\n }\n\n // Check if we have to refresh the token\n if (json.error_code === -40401 || json.error_code === -1) {\n this.log.debug(\"API request failed, reauthenticating\");\n this.stok = undefined;\n return this.apiRequest(req, loginRetryCount + 1);\n }\n\n return json as TAPOCameraResponse;\n } finally {\n this.pendingAPIRequests.delete(reqJson);\n }\n })(),\n );\n\n return this.pendingAPIRequests.get(reqJson) as Promise<TAPOCameraResponse>;\n }\n\n async setLensMaskConfig(value: boolean) {\n this.adapter.log.debug(\"Processing setLensMaskConfig\" + value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setLensMaskConfig\",\n params: {\n lens_mask: {\n lens_mask_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n if (json.error_code !== 0) {\n throw new Error(\"Failed to perform action\");\n }\n }\n\n async setAlertConfig(value: boolean) {\n this.log.debug(\"Processing setAlertConfig\" + value);\n\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [\n {\n method: \"setAlertConfig\",\n params: {\n msg_alarm: {\n chn1_msg_alarm_info: {\n enabled: value ? \"on\" : \"off\",\n },\n },\n },\n },\n ],\n },\n });\n\n return json.error_code !== 0;\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\n async moveMotor(x: number, y: number) {\n const json = await this.apiRequest({\n method: \"multipleRequest\",\n params: {\n requests: [{ method: \"do\", motor: { move: { x_coord: x, y_coord: y } } }],\n },\n });\n\n return json.error_code !== 0;\n }\n\n async getBasicInfo() {\n const json = 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 = json.result.responses[0] as TAPOCameraResponseDeviceInfo;\n return info.result.device_info.basic_info;\n }\n\n async getStatus(): Promise<{ lensMask: boolean; alert: boolean }> {\n const json = 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: \"getForceWhitelampState\",\n params: {\n image: {\n name: \"switch\",\n },\n },\n },\n ],\n },\n });\n this.log.debug(`getStatus json: ${JSON.stringify(json)}`);\n if (json.error_code !== 0) {\n throw new Error(\"Camera replied with error\");\n }\n if (!json.result.responses) {\n throw new Error(\"Camera replied with invalid response\");\n }\n const alertConfig = json.result.responses.find((r) => r.method === \"getAlertConfig\") as TAPOCameraResponseGetAlert;\n\n const forceWhitelampState = json.result.responses.find((r) => r.method === \"getForceWhitelampState\") as TAPOCameraResponseGetForce;\n const lensMaskConfig = json.result.responses.find((r) => r.method === \"getLensMaskConfig\") as TAPOCameraResponseGetLensMask;\n\n return {\n alert: alertConfig.result.msg_alarm.chn1_msg_alarm_info.enabled === \"on\",\n lensMask: lensMaskConfig.result.lens_mask.lens_mask_info.enabled === \"on\",\n forceWhiteLamp: forceWhitelampState.result.image ? forceWhitelampState.result.image.switch.force_wtl_state === \"on\" : false,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["https", "crypto", "fetch"]
|
|
7
7
|
}
|
package/build/lib/utils/l530.js
CHANGED
|
@@ -80,7 +80,7 @@ class L530 extends import_l520e.default {
|
|
|
80
80
|
}
|
|
81
81
|
return response.result;
|
|
82
82
|
}).catch((error) => {
|
|
83
|
-
if (error.message.indexOf("9999") > 0) {
|
|
83
|
+
if (error && error.message.indexOf("9999") > 0) {
|
|
84
84
|
return this.reconnect().then(() => {
|
|
85
85
|
return this.handleRequest(payload).then(() => {
|
|
86
86
|
return true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/l530.ts"],
|
|
4
|
-
"sourcesContent": ["import L520E from \"./l520e\";\nimport { PowerUsage } from \"./powerUsage\";\nimport { ColorLightSysinfo, ConsumptionInfo } from \"./types\";\n\nexport default class L530 extends L520E {\n private _colorLightSysInfo!: ColorLightSysinfo;\n private _consumption!: ConsumptionInfo;\n\n constructor(\n public readonly log: any,\n public readonly ipAddress: string,\n public readonly email: string,\n public readonly password: string,\n public readonly timeout: number,\n ) {\n super(log, ipAddress, email, password, timeout);\n this.log.debug(\"Constructing L530 on host: \" + ipAddress);\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n\n async getDeviceInfo(): Promise<ColorLightSysinfo> {\n return super.getDeviceInfo().then(() => {\n return this.getSysInfo();\n });\n }\n\n async setColor(hue: number, saturation: number): Promise<boolean> {\n if (!hue) {\n hue = 0;\n }\n if (!saturation) {\n saturation = 0;\n }\n const payload =\n \"{\" +\n '\"method\": \"set_device_info\",' +\n '\"params\": {' +\n '\"hue\": ' +\n Math.round(hue) +\n \",\" +\n '\"color_temp\": 0,' +\n '\"saturation\": ' +\n Math.round(saturation) +\n \"},\" +\n '\"requestTimeMils\": ' +\n Math.round(Date.now() * 1000) +\n \"\" +\n \"};\";\n\n return this.sendRequest(payload);\n }\n\n protected setSysInfo(sysInfo: ColorLightSysinfo) {\n this._colorLightSysInfo = sysInfo;\n this._colorLightSysInfo.last_update = Date.now();\n }\n\n public getSysInfo(): ColorLightSysinfo {\n return this._colorLightSysInfo;\n }\n\n async getEnergyUsage(): Promise<PowerUsage> {\n const payload = \"{\" + '\"method\": \"get_device_usage\",' + '\"requestTimeMils\": ' + Math.round(Date.now() * 1000) + \"\" + \"};\";\n return this.handleRequest(payload)\n .then((response) => {\n if (response && response.result) {\n this._consumption = {\n total: response.result.power_usage.today / 1000,\n current: this._consumption ? response.result.power_usage.today - this._consumption.current : 0,\n };\n } else {\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n\n return response.result;\n })\n .catch((error) => {\n if (error.message.indexOf(\"9999\") > 0) {\n return this.reconnect().then(() => {\n return this.handleRequest(payload).then(() => {\n return true;\n });\n });\n }\n return false;\n });\n }\n\n public getPowerConsumption(): ConsumptionInfo {\n return this._consumption;\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAIlB,MAAO,aAA2B,aAAAA,QAAM;AAAA,EAItC,YACkB,KACA,WACA,OACA,UACA,SAChB;AACA,UAAM,KAAK,WAAW,OAAO,UAAU,OAAO;AAN9B;AACA;AACA;AACA;AACA;AAGhB,SAAK,IAAI,MAAM,gCAAgC,SAAS;AACxD,SAAK,eAAe;AAAA,MAClB,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,gBAA4C;AAChD,WAAO,MAAM,cAAc,EAAE,KAAK,MAAM;AACtC,aAAO,KAAK,WAAW;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,SAAS,KAAa,YAAsC;AAChE,QAAI,CAAC,KAAK;AACR,YAAM;AAAA,IACR;AACA,QAAI,CAAC,YAAY;AACf,mBAAa;AAAA,IACf;AACA,UAAM,UACJ,oDAIA,KAAK,MAAM,GAAG,IACd,oCAGA,KAAK,MAAM,UAAU,IACrB,0BAEA,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAE5B;AAEF,WAAO,KAAK,YAAY,OAAO;AAAA,EACjC;AAAA,EAEU,WAAW,SAA4B;AAC/C,SAAK,qBAAqB;AAC1B,SAAK,mBAAmB,cAAc,KAAK,IAAI;AAAA,EACjD;AAAA,EAEO,aAAgC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,iBAAsC;AAC1C,UAAM,UAAU,sDAAgE,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAAS;AACrH,WAAO,KAAK,cAAc,OAAO,EAC9B,KAAK,CAAC,aAAa;AAClB,UAAI,YAAY,SAAS,QAAQ;AAC/B,aAAK,eAAe;AAAA,UAClB,OAAO,SAAS,OAAO,YAAY,QAAQ;AAAA,UAC3C,SAAS,KAAK,eAAe,SAAS,OAAO,YAAY,QAAQ,KAAK,aAAa,UAAU;AAAA,QAC/F;AAAA,MACF,OAAO;AACL,aAAK,eAAe;AAAA,UAClB,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO,SAAS;AAAA,IAClB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,UAAI,MAAM,QAAQ,QAAQ,MAAM,IAAI,GAAG;
|
|
4
|
+
"sourcesContent": ["import L520E from \"./l520e\";\nimport { PowerUsage } from \"./powerUsage\";\nimport { ColorLightSysinfo, ConsumptionInfo } from \"./types\";\n\nexport default class L530 extends L520E {\n private _colorLightSysInfo!: ColorLightSysinfo;\n private _consumption!: ConsumptionInfo;\n\n constructor(\n public readonly log: any,\n public readonly ipAddress: string,\n public readonly email: string,\n public readonly password: string,\n public readonly timeout: number,\n ) {\n super(log, ipAddress, email, password, timeout);\n this.log.debug(\"Constructing L530 on host: \" + ipAddress);\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n\n async getDeviceInfo(): Promise<ColorLightSysinfo> {\n return super.getDeviceInfo().then(() => {\n return this.getSysInfo();\n });\n }\n\n async setColor(hue: number, saturation: number): Promise<boolean> {\n if (!hue) {\n hue = 0;\n }\n if (!saturation) {\n saturation = 0;\n }\n const payload =\n \"{\" +\n '\"method\": \"set_device_info\",' +\n '\"params\": {' +\n '\"hue\": ' +\n Math.round(hue) +\n \",\" +\n '\"color_temp\": 0,' +\n '\"saturation\": ' +\n Math.round(saturation) +\n \"},\" +\n '\"requestTimeMils\": ' +\n Math.round(Date.now() * 1000) +\n \"\" +\n \"};\";\n\n return this.sendRequest(payload);\n }\n\n protected setSysInfo(sysInfo: ColorLightSysinfo) {\n this._colorLightSysInfo = sysInfo;\n this._colorLightSysInfo.last_update = Date.now();\n }\n\n public getSysInfo(): ColorLightSysinfo {\n return this._colorLightSysInfo;\n }\n\n async getEnergyUsage(): Promise<PowerUsage> {\n const payload = \"{\" + '\"method\": \"get_device_usage\",' + '\"requestTimeMils\": ' + Math.round(Date.now() * 1000) + \"\" + \"};\";\n return this.handleRequest(payload)\n .then((response) => {\n if (response && response.result) {\n this._consumption = {\n total: response.result.power_usage.today / 1000,\n current: this._consumption ? response.result.power_usage.today - this._consumption.current : 0,\n };\n } else {\n this._consumption = {\n total: 0,\n current: 0,\n };\n }\n\n return response.result;\n })\n .catch((error) => {\n if (error && error.message.indexOf(\"9999\") > 0) {\n return this.reconnect().then(() => {\n return this.handleRequest(payload).then(() => {\n return true;\n });\n });\n }\n return false;\n });\n }\n\n public getPowerConsumption(): ConsumptionInfo {\n return this._consumption;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAIlB,MAAO,aAA2B,aAAAA,QAAM;AAAA,EAItC,YACkB,KACA,WACA,OACA,UACA,SAChB;AACA,UAAM,KAAK,WAAW,OAAO,UAAU,OAAO;AAN9B;AACA;AACA;AACA;AACA;AAGhB,SAAK,IAAI,MAAM,gCAAgC,SAAS;AACxD,SAAK,eAAe;AAAA,MAClB,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,gBAA4C;AAChD,WAAO,MAAM,cAAc,EAAE,KAAK,MAAM;AACtC,aAAO,KAAK,WAAW;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,SAAS,KAAa,YAAsC;AAChE,QAAI,CAAC,KAAK;AACR,YAAM;AAAA,IACR;AACA,QAAI,CAAC,YAAY;AACf,mBAAa;AAAA,IACf;AACA,UAAM,UACJ,oDAIA,KAAK,MAAM,GAAG,IACd,oCAGA,KAAK,MAAM,UAAU,IACrB,0BAEA,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAE5B;AAEF,WAAO,KAAK,YAAY,OAAO;AAAA,EACjC;AAAA,EAEU,WAAW,SAA4B;AAC/C,SAAK,qBAAqB;AAC1B,SAAK,mBAAmB,cAAc,KAAK,IAAI;AAAA,EACjD;AAAA,EAEO,aAAgC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,iBAAsC;AAC1C,UAAM,UAAU,sDAAgE,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAAS;AACrH,WAAO,KAAK,cAAc,OAAO,EAC9B,KAAK,CAAC,aAAa;AAClB,UAAI,YAAY,SAAS,QAAQ;AAC/B,aAAK,eAAe;AAAA,UAClB,OAAO,SAAS,OAAO,YAAY,QAAQ;AAAA,UAC3C,SAAS,KAAK,eAAe,SAAS,OAAO,YAAY,QAAQ,KAAK,aAAa,UAAU;AAAA,QAC/F;AAAA,MACF,OAAO;AACL,aAAK,eAAe;AAAA,UAClB,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO,SAAS;AAAA,IAClB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,UAAI,SAAS,MAAM,QAAQ,QAAQ,MAAM,IAAI,GAAG;AAC9C,eAAO,KAAK,UAAU,EAAE,KAAK,MAAM;AACjC,iBAAO,KAAK,cAAc,OAAO,EAAE,KAAK,MAAM;AAC5C,mBAAO;AAAA,UACT,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACL;AAAA,EAEO,sBAAuC;AAC5C,WAAO,KAAK;AAAA,EACd;AACF;",
|
|
6
6
|
"names": ["L520E"]
|
|
7
7
|
}
|
package/build/lib/utils/p100.js
CHANGED
|
@@ -161,7 +161,7 @@ class P100 {
|
|
|
161
161
|
return this.handleError(res.data.error_code, "106");
|
|
162
162
|
}
|
|
163
163
|
}).catch((error) => {
|
|
164
|
-
this.log.error("111 Error: " + error.message);
|
|
164
|
+
this.log.error("111 Error: " + error ? error.message : "");
|
|
165
165
|
return error;
|
|
166
166
|
});
|
|
167
167
|
}
|
|
@@ -200,7 +200,7 @@ class P100 {
|
|
|
200
200
|
return this.handleError(JSON.parse(decryptedResponse).error_code, "157");
|
|
201
201
|
}
|
|
202
202
|
}).catch((error) => {
|
|
203
|
-
this.log.error("Error: " + error.message);
|
|
203
|
+
this.log.error("Error Login: " + error ? error.message : "");
|
|
204
204
|
return error;
|
|
205
205
|
});
|
|
206
206
|
}
|
|
@@ -235,14 +235,21 @@ class P100 {
|
|
|
235
235
|
} catch (error) {
|
|
236
236
|
return this.handleError(res.data.error_code, "318");
|
|
237
237
|
}
|
|
238
|
-
}).catch((error) => {
|
|
239
|
-
this.log.error("322 Error: " + error.message);
|
|
238
|
+
}).catch(async (error) => {
|
|
239
|
+
this.log.error("322 Error: " + error ? error.message : "");
|
|
240
|
+
if (this._reconnect_counter <= 3) {
|
|
241
|
+
this.log.info("Trying to reconnect...");
|
|
242
|
+
await this.newReconnect();
|
|
243
|
+
}
|
|
240
244
|
return error;
|
|
241
245
|
});
|
|
242
246
|
}
|
|
243
247
|
async handshake_new() {
|
|
244
248
|
const local_seed = this.crypto.randomBytes(16);
|
|
245
249
|
await this.raw_request("handshake1", local_seed, "arraybuffer").then((res) => {
|
|
250
|
+
if (!res || !res.subarray) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
246
253
|
const remote_seed = res.subarray(0, 16);
|
|
247
254
|
const server_hash = res.subarray(16);
|
|
248
255
|
let auth_hash = void 0;
|
|
@@ -301,6 +308,7 @@ class P100 {
|
|
|
301
308
|
Cookie: this.cookie
|
|
302
309
|
};
|
|
303
310
|
if (this.tpLinkCipher) {
|
|
311
|
+
this.log.debug("using old cypher");
|
|
304
312
|
const encryptedPayload = this.tpLinkCipher.encrypt(payload);
|
|
305
313
|
const securePassthroughPayload = {
|
|
306
314
|
method: "securePassthrough",
|
|
@@ -339,10 +347,11 @@ class P100 {
|
|
|
339
347
|
return this.handleError(JSON.parse(decryptedResponse).error_code, "340");
|
|
340
348
|
}
|
|
341
349
|
}).catch((error) => {
|
|
342
|
-
this.log.error("371 Error: " + error.message);
|
|
350
|
+
this.log.error("371 Error: " + error ? error.message : "");
|
|
343
351
|
return error;
|
|
344
352
|
});
|
|
345
353
|
} else if (this.newTpLinkCipher) {
|
|
354
|
+
this.log.debug("using new cypher");
|
|
346
355
|
const data = this.newTpLinkCipher.encrypt(payload);
|
|
347
356
|
const URL2 = "http://" + this.ip + "/app/request";
|
|
348
357
|
const headers2 = {
|
|
@@ -361,6 +370,7 @@ class P100 {
|
|
|
361
370
|
params: { seq: data.seq.toString() }
|
|
362
371
|
};
|
|
363
372
|
return this.axios.post(URL2, data.encryptedPayload, config).then((res) => {
|
|
373
|
+
this.log.debug(JSON.stringify(res.data));
|
|
364
374
|
if (res.data.error_code) {
|
|
365
375
|
return this.handleError(res.data.error_code, "309");
|
|
366
376
|
}
|
|
@@ -369,18 +379,21 @@ class P100 {
|
|
|
369
379
|
this.cookie = res.headers["set-cookie"][0].split(";")[0];
|
|
370
380
|
}
|
|
371
381
|
const response = JSON.parse(this.newTpLinkCipher.decrypt(res.data));
|
|
382
|
+
this.log.debug("Device Info: " + JSON.stringify(response));
|
|
372
383
|
if (response.error_code !== 0) {
|
|
373
384
|
return this.handleError(response.error_code, "333");
|
|
374
385
|
}
|
|
375
386
|
this.setSysInfo(response.result);
|
|
376
|
-
this.log.debug("Device Info: ", response.result);
|
|
377
387
|
return this.getSysInfo();
|
|
378
388
|
} catch (error) {
|
|
379
389
|
return this.handleError(res.data.error_code, "480");
|
|
380
390
|
}
|
|
381
|
-
}).catch((error) => {
|
|
382
|
-
this.log.error("322 Error: " + error.message);
|
|
383
|
-
|
|
391
|
+
}).catch(async (error) => {
|
|
392
|
+
this.log.error("322 #2 Error: " + error ? error.message : "");
|
|
393
|
+
if (this._reconnect_counter <= 3) {
|
|
394
|
+
this.log.info("Trying to reconnect...");
|
|
395
|
+
await this.newReconnect();
|
|
396
|
+
}
|
|
384
397
|
});
|
|
385
398
|
} else {
|
|
386
399
|
return new Promise((resolve, reject) => {
|
|
@@ -444,7 +457,7 @@ class P100 {
|
|
|
444
457
|
return this.handleRequest(payload).then((result) => {
|
|
445
458
|
return result ? true : false;
|
|
446
459
|
}).catch((error) => {
|
|
447
|
-
if (error.message.indexOf("9999") > 0 && this._reconnect_counter <= 3) {
|
|
460
|
+
if (error && error.message.indexOf("9999") > 0 && this._reconnect_counter <= 3) {
|
|
448
461
|
return this.reconnect().then(() => {
|
|
449
462
|
return this.handleRequest(payload).then((result) => {
|
|
450
463
|
return result ? true : false;
|
|
@@ -458,7 +471,7 @@ class P100 {
|
|
|
458
471
|
return this.newHandleRequest(payload).then((result) => {
|
|
459
472
|
return result ? true : false;
|
|
460
473
|
}).catch((error) => {
|
|
461
|
-
if (error.message.indexOf("9999") > 0 && this._reconnect_counter <= 3) {
|
|
474
|
+
if (error && error.message.indexOf("9999") > 0 && this._reconnect_counter <= 3) {
|
|
462
475
|
return this.newReconnect().then(() => {
|
|
463
476
|
return this.newHandleRequest(payload).then((result) => {
|
|
464
477
|
return result ? true : false;
|