@switchbot/homebridge-switchbot 2.6.0-beta.4 → 2.6.0
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/.vscode/tasks.json +13 -0
- package/CHANGELOG.md +4 -2
- package/README.md +18 -9
- package/dist/device/blindtilt.d.ts +1 -5
- package/dist/device/blindtilt.d.ts.map +1 -1
- package/dist/device/blindtilt.js +80 -140
- package/dist/device/blindtilt.js.map +1 -1
- package/dist/device/bot.d.ts +1 -5
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +79 -138
- package/dist/device/bot.js.map +1 -1
- package/dist/device/ceilinglight.d.ts +2 -6
- package/dist/device/ceilinglight.d.ts.map +1 -1
- package/dist/device/ceilinglight.js +157 -304
- package/dist/device/ceilinglight.js.map +1 -1
- package/dist/device/colorbulb.d.ts +2 -6
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +164 -311
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +1 -5
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +36 -72
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +1 -5
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +78 -138
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/hub.d.ts +2 -6
- package/dist/device/hub.d.ts.map +1 -1
- package/dist/device/hub.js +30 -63
- package/dist/device/hub.js.map +1 -1
- package/dist/device/humidifier.d.ts +1 -5
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +115 -228
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/iosensor.d.ts +1 -5
- package/dist/device/iosensor.d.ts.map +1 -1
- package/dist/device/iosensor.js +38 -74
- package/dist/device/iosensor.js.map +1 -1
- package/dist/device/{striplight.d.ts → lightstrip.d.ts} +2 -10
- package/dist/device/lightstrip.d.ts.map +1 -0
- package/dist/device/{striplight.js → lightstrip.js} +138 -194
- package/dist/device/lightstrip.js.map +1 -0
- package/dist/device/lock.d.ts +1 -5
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +66 -126
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +1 -5
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +38 -74
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +1 -5
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +39 -75
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +1 -5
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +35 -72
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +1 -5
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +65 -126
- package/dist/device/plug.js.map +1 -1
- package/dist/device/robotvacuumcleaner.d.ts +1 -5
- package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
- package/dist/device/robotvacuumcleaner.js +79 -151
- package/dist/device/robotvacuumcleaner.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +3 -7
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +34 -62
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +3 -7
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +31 -59
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +1 -5
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +30 -57
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +2 -6
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +39 -66
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +1 -5
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +32 -59
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +1 -5
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +30 -57
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +3 -7
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +46 -76
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +2 -6
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +30 -58
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +7 -23
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +41 -74
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +14 -5
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +156 -149
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +4 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +5 -1
- package/dist/settings.js.map +1 -1
- package/nodemon.json +1 -1
- package/package.json +10 -10
- package/src/device/blindtilt.ts +122 -181
- package/src/device/bot.ts +96 -149
- package/src/device/ceilinglight.ts +172 -315
- package/src/device/colorbulb.ts +178 -324
- package/src/device/contact.ts +48 -78
- package/src/device/curtain.ts +93 -148
- package/src/device/hub.ts +34 -63
- package/src/device/humidifier.ts +135 -243
- package/src/device/iosensor.ts +49 -79
- package/src/device/{striplight.ts → lightstrip.ts} +148 -200
- package/src/device/lock.ts +78 -134
- package/src/device/meter.ts +48 -78
- package/src/device/meterplus.ts +50 -80
- package/src/device/motion.ts +46 -77
- package/src/device/plug.ts +76 -134
- package/src/device/robotvacuumcleaner.ts +91 -159
- package/src/irdevice/airconditioner.ts +56 -81
- package/src/irdevice/airpurifier.ts +41 -67
- package/src/irdevice/camera.ts +35 -60
- package/src/irdevice/fan.ts +46 -71
- package/src/irdevice/light.ts +38 -63
- package/src/irdevice/other.ts +35 -60
- package/src/irdevice/tv.ts +52 -80
- package/src/irdevice/vacuumcleaner.ts +36 -62
- package/src/irdevice/waterheater.ts +46 -76
- package/src/platform.ts +144 -158
- package/src/settings.ts +5 -0
- package/.github/npm-version-script.js +0 -81
- package/dist/device/striplight.d.ts.map +0 -1
- package/dist/device/striplight.js.map +0 -1
package/src/device/contact.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import https from 'https';
|
|
2
|
-
import crypto from 'crypto';
|
|
3
1
|
import { Context } from 'vm';
|
|
2
|
+
import { request } from 'undici';
|
|
3
|
+
import { sleep } from '../utils';
|
|
4
4
|
import { interval, Subject } from 'rxjs';
|
|
5
5
|
import { skipWhile } from 'rxjs/operators';
|
|
6
|
-
import superStringify from 'super-stringify';
|
|
7
6
|
import { SwitchBotPlatform } from '../platform';
|
|
8
7
|
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
9
|
-
import { device, devicesConfig, serviceData, switchbot, deviceStatus, ad,
|
|
10
|
-
import { IncomingMessage } from 'http';
|
|
11
|
-
import { sleep } from '../utils';
|
|
8
|
+
import { device, devicesConfig, serviceData, switchbot, deviceStatus, ad, Devices } from '../settings';
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
11
|
* Platform Accessory
|
|
@@ -183,7 +180,7 @@ export class Contact {
|
|
|
183
180
|
} else {
|
|
184
181
|
await this.offlineOff();
|
|
185
182
|
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
186
|
-
|
|
183
|
+
+ ` ${this.device.connectionType}, parseStatus will not happen.`);
|
|
187
184
|
}
|
|
188
185
|
}
|
|
189
186
|
|
|
@@ -204,7 +201,7 @@ export class Contact {
|
|
|
204
201
|
}
|
|
205
202
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
|
|
206
203
|
if ((this.ContactSensorState !== this.accessory.context.ContactSensorState)
|
|
207
|
-
|
|
204
|
+
&& this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED) {
|
|
208
205
|
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Opened`);
|
|
209
206
|
}
|
|
210
207
|
// Movement
|
|
@@ -227,7 +224,7 @@ export class Contact {
|
|
|
227
224
|
this.CurrentAmbientLightLevel = this.set_maxLux;
|
|
228
225
|
}
|
|
229
226
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.is_light},` +
|
|
230
|
-
|
|
227
|
+
` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
231
228
|
if (this.CurrentAmbientLightLevel !== this.accessory.context.CurrentAmbientLightLevel) {
|
|
232
229
|
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
233
230
|
}
|
|
@@ -243,7 +240,7 @@ export class Contact {
|
|
|
243
240
|
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
|
|
244
241
|
}
|
|
245
242
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, `
|
|
246
|
-
|
|
243
|
+
+ `StatusLowBattery: ${this.StatusLowBattery}`);
|
|
247
244
|
}
|
|
248
245
|
|
|
249
246
|
async openAPIparseStatus(): Promise<void> {
|
|
@@ -292,7 +289,7 @@ export class Contact {
|
|
|
292
289
|
} else {
|
|
293
290
|
await this.offlineOff();
|
|
294
291
|
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
295
|
-
|
|
292
|
+
+ ` ${this.device.connectionType}, refreshStatus will not happen.`);
|
|
296
293
|
}
|
|
297
294
|
}
|
|
298
295
|
|
|
@@ -321,7 +318,7 @@ export class Contact {
|
|
|
321
318
|
switchbot.onadvertisement = async (ad: any) => {
|
|
322
319
|
this.address = ad.address;
|
|
323
320
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},`
|
|
324
|
-
|
|
321
|
+
+ ` BLE Address Found: ${this.address}`);
|
|
325
322
|
this.serviceData = ad.serviceData;
|
|
326
323
|
this.movement = ad.serviceData.movement;
|
|
327
324
|
this.tested = ad.serviceData.tested;
|
|
@@ -331,10 +328,10 @@ export class Contact {
|
|
|
331
328
|
this.is_light = ad.serviceData.is_light;
|
|
332
329
|
this.button_count = ad.serviceData.button_count;
|
|
333
330
|
this.doorState = ad.serviceData.doorState;
|
|
334
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${
|
|
331
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
|
|
335
332
|
this.debugLog(
|
|
336
333
|
`${this.device.deviceType}: ${this.accessory.displayName} movement: ${ad.serviceData.movement}, doorState: ` +
|
|
337
|
-
|
|
334
|
+
`${ad.serviceData.doorState}, is_light: ${ad.serviceData.is_light}, battery: ${ad.serviceData.battery}`,
|
|
338
335
|
);
|
|
339
336
|
|
|
340
337
|
if (this.serviceData) {
|
|
@@ -359,7 +356,7 @@ export class Contact {
|
|
|
359
356
|
.catch(async (e: any) => {
|
|
360
357
|
this.apiError(e);
|
|
361
358
|
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
|
|
362
|
-
|
|
359
|
+
+ ` Connection, Error Message: ${JSON.stringify(e.message)}`);
|
|
363
360
|
await this.BLERefreshConnection(switchbot);
|
|
364
361
|
});
|
|
365
362
|
} else {
|
|
@@ -370,54 +367,26 @@ export class Contact {
|
|
|
370
367
|
async openAPIRefreshStatus(): Promise<void> {
|
|
371
368
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
|
|
372
369
|
try {
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
const data = this.platform.config.credentials?.token + t + nonce;
|
|
376
|
-
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
377
|
-
const sign = signTerm.toString('base64');
|
|
378
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
379
|
-
const options = {
|
|
380
|
-
hostname: HostDomain,
|
|
381
|
-
port: 443,
|
|
382
|
-
path: `${DevicePath}/${this.device.deviceId}/status`,
|
|
383
|
-
method: 'GET',
|
|
384
|
-
headers: {
|
|
385
|
-
Authorization: this.platform.config.credentials?.token,
|
|
386
|
-
sign: sign,
|
|
387
|
-
nonce: nonce,
|
|
388
|
-
t: t,
|
|
389
|
-
'Content-Type': 'application/json',
|
|
390
|
-
},
|
|
391
|
-
};
|
|
392
|
-
const req = https.request(options, (res) => {
|
|
393
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
|
|
394
|
-
let rawData = '';
|
|
395
|
-
res.on('data', (d) => {
|
|
396
|
-
rawData += d;
|
|
397
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
398
|
-
});
|
|
399
|
-
res.on('end', () => {
|
|
400
|
-
try {
|
|
401
|
-
this.deviceStatus = JSON.parse(rawData);
|
|
402
|
-
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
403
|
-
this.openState = this.deviceStatus.body.openState;
|
|
404
|
-
this.moveDetected = this.deviceStatus.body.moveDetected;
|
|
405
|
-
this.brightness = this.deviceStatus.body.brightness;
|
|
406
|
-
this.openAPIparseStatus();
|
|
407
|
-
this.updateHomeKitCharacteristics();
|
|
408
|
-
} catch (e: any) {
|
|
409
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
req.on('error', (e: any) => {
|
|
414
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
370
|
+
const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, {
|
|
371
|
+
headers: this.platform.generateHeaders(),
|
|
415
372
|
});
|
|
416
|
-
|
|
373
|
+
const deviceStatus = await body.json();
|
|
374
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
|
|
375
|
+
this.statusCode(statusCode);
|
|
376
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
|
|
377
|
+
this.debugLog(
|
|
378
|
+
`${this.device.deviceType}: ${this.accessory.displayName
|
|
379
|
+
} refreshStatus: ${JSON.stringify(deviceStatus)}`,
|
|
380
|
+
);
|
|
381
|
+
this.openState = deviceStatus.body.openState;
|
|
382
|
+
this.moveDetected = deviceStatus.body.moveDetected;
|
|
383
|
+
this.brightness = deviceStatus.body.brightness;
|
|
384
|
+
this.openAPIparseStatus();
|
|
385
|
+
this.updateHomeKitCharacteristics();
|
|
417
386
|
} catch (e: any) {
|
|
418
387
|
this.apiError(e);
|
|
419
388
|
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
|
|
420
|
-
|
|
389
|
+
+ ` Connection, Error Message: ${JSON.stringify(e.message)}`);
|
|
421
390
|
}
|
|
422
391
|
}
|
|
423
392
|
|
|
@@ -489,7 +458,7 @@ export class Contact {
|
|
|
489
458
|
});
|
|
490
459
|
// Set an event handler
|
|
491
460
|
switchbot.onadvertisement = (ad: any) => {
|
|
492
|
-
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${
|
|
461
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
|
|
493
462
|
};
|
|
494
463
|
await sleep(10000);
|
|
495
464
|
// Stop to monitor
|
|
@@ -538,40 +507,41 @@ export class Contact {
|
|
|
538
507
|
}
|
|
539
508
|
}
|
|
540
509
|
|
|
541
|
-
async statusCode(
|
|
542
|
-
switch (
|
|
510
|
+
async statusCode(statusCode: number): Promise<void> {
|
|
511
|
+
switch (statusCode) {
|
|
543
512
|
case 151:
|
|
544
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this
|
|
513
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
|
|
545
514
|
break;
|
|
546
515
|
case 152:
|
|
547
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found
|
|
516
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
|
|
548
517
|
break;
|
|
549
518
|
case 160:
|
|
550
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported
|
|
519
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
|
|
551
520
|
break;
|
|
552
521
|
case 161:
|
|
553
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline
|
|
554
|
-
|
|
522
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
|
|
523
|
+
this.offlineOff();
|
|
555
524
|
break;
|
|
556
525
|
case 171:
|
|
557
|
-
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline
|
|
558
|
-
|
|
526
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
|
|
527
|
+
+ `Hub: ${this.device.hubDeviceId}`);
|
|
528
|
+
this.offlineOff();
|
|
559
529
|
break;
|
|
560
530
|
case 190:
|
|
561
531
|
this.errorLog(
|
|
562
532
|
`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
563
|
-
|
|
533
|
+
` Or command format is invalid, statusCode: ${statusCode}`,
|
|
564
534
|
);
|
|
565
535
|
break;
|
|
566
536
|
case 100:
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
537
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
|
|
538
|
+
break;
|
|
539
|
+
case 200:
|
|
540
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
|
|
570
541
|
break;
|
|
571
542
|
default:
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
}
|
|
543
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: `
|
|
544
|
+
+ `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
|
|
575
545
|
}
|
|
576
546
|
}
|
|
577
547
|
|
|
@@ -599,7 +569,7 @@ export class Contact {
|
|
|
599
569
|
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
600
570
|
let FirmwareRevision: string;
|
|
601
571
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
602
|
-
|
|
572
|
+
+ ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
603
573
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
604
574
|
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
605
575
|
if (accessory.context.FirmwareRevision) {
|
|
@@ -656,7 +626,7 @@ export class Contact {
|
|
|
656
626
|
config['scanDuration'] = device.scanDuration;
|
|
657
627
|
}
|
|
658
628
|
if (Object.entries(config).length !== 0) {
|
|
659
|
-
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${
|
|
629
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
|
|
660
630
|
}
|
|
661
631
|
}
|
|
662
632
|
|