@lumiastream/tapo-cove 0.0.1-alpha.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/dist/module/discovery.d.ts +8 -0
- package/dist/module/discovery.js +118 -0
- package/dist/module/index.d.ts +5 -0
- package/dist/module/index.js +12 -0
- package/dist/module/lightstate.d.ts +39 -0
- package/dist/module/lightstate.js +123 -0
- package/dist/module/shared/cipher.d.ts +11 -0
- package/dist/module/shared/cipher.js +66 -0
- package/dist/module/shared/color-transformer.d.ts +8 -0
- package/dist/module/shared/color-transformer.js +42 -0
- package/dist/module/shared/helpers.d.ts +5 -0
- package/dist/module/shared/helpers.js +105 -0
- package/dist/module/shared/tapo-ca-cert.d.ts +2 -0
- package/dist/module/shared/tapo-ca-cert.js +3 -0
- package/dist/module/shared/tapo.constants.d.ts +21 -0
- package/dist/module/shared/tapo.constants.js +25 -0
- package/dist/module/shared/utils.d.ts +23 -0
- package/dist/module/shared/utils.js +152 -0
- package/dist/module/tapo-api.d.ts +48 -0
- package/dist/module/tapo-api.js +142 -0
- package/dist/module/types/interfaces.d.ts +3 -0
- package/dist/module/types/interfaces.js +2 -0
- package/dist/module/types/raw-types.d.ts +84 -0
- package/dist/module/types/raw-types.js +2 -0
- package/lib/cjs/discovery.d.ts +8 -0
- package/lib/cjs/discovery.js +118 -0
- package/lib/cjs/index.d.ts +5 -0
- package/lib/cjs/index.js +12 -0
- package/lib/cjs/lightstate.d.ts +39 -0
- package/lib/cjs/lightstate.js +123 -0
- package/lib/cjs/shared/cipher.d.ts +11 -0
- package/lib/cjs/shared/cipher.js +66 -0
- package/lib/cjs/shared/color-transformer.d.ts +8 -0
- package/lib/cjs/shared/color-transformer.js +42 -0
- package/lib/cjs/shared/helpers.d.ts +5 -0
- package/lib/cjs/shared/helpers.js +105 -0
- package/lib/cjs/shared/tapo-ca-cert.d.ts +2 -0
- package/lib/cjs/shared/tapo-ca-cert.js +3 -0
- package/lib/cjs/shared/tapo.constants.d.ts +21 -0
- package/lib/cjs/shared/tapo.constants.js +25 -0
- package/lib/cjs/shared/utils.d.ts +23 -0
- package/lib/cjs/shared/utils.js +152 -0
- package/lib/cjs/tapo-api.d.ts +48 -0
- package/lib/cjs/tapo-api.js +142 -0
- package/lib/cjs/types/interfaces.d.ts +3 -0
- package/lib/cjs/types/interfaces.js +2 -0
- package/lib/cjs/types/raw-types.d.ts +84 -0
- package/lib/cjs/types/raw-types.js +2 -0
- package/lib/esm/discovery.d.ts +8 -0
- package/lib/esm/discovery.js +116 -0
- package/lib/esm/index.d.ts +5 -0
- package/lib/esm/index.js +5 -0
- package/lib/esm/lightstate.d.ts +39 -0
- package/lib/esm/lightstate.js +120 -0
- package/lib/esm/shared/cipher.d.ts +11 -0
- package/lib/esm/shared/cipher.js +56 -0
- package/lib/esm/shared/color-transformer.d.ts +8 -0
- package/lib/esm/shared/color-transformer.js +40 -0
- package/lib/esm/shared/helpers.d.ts +5 -0
- package/lib/esm/shared/helpers.js +98 -0
- package/lib/esm/shared/tapo-ca-cert.d.ts +2 -0
- package/lib/esm/shared/tapo-ca-cert.js +1 -0
- package/lib/esm/shared/tapo.constants.d.ts +21 -0
- package/lib/esm/shared/tapo.constants.js +22 -0
- package/lib/esm/shared/utils.d.ts +23 -0
- package/lib/esm/shared/utils.js +146 -0
- package/lib/esm/tapo-api.d.ts +48 -0
- package/lib/esm/tapo-api.js +140 -0
- package/lib/esm/types/interfaces.d.ts +3 -0
- package/lib/esm/types/interfaces.js +1 -0
- package/lib/esm/types/raw-types.d.ts +84 -0
- package/lib/esm/types/raw-types.js +1 -0
- package/package.json +38 -0
- package/test/auth.test.ts +22 -0
- package/test/discover.test.ts +9 -0
- package/test/light.test.ts +17 -0
- package/test/plug.test.ts +16 -0
- package/tslint.json +53 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var tslib_1 = require("tslib");
|
|
4
|
+
var axios_1 = tslib_1.__importDefault(require("axios"));
|
|
5
|
+
var lightstate_1 = require("./lightstate");
|
|
6
|
+
var fetch_cove_1 = require("@lumiastream/fetch-cove");
|
|
7
|
+
var utils_1 = require("./shared/utils");
|
|
8
|
+
var helpers_1 = require("./shared/helpers");
|
|
9
|
+
var cipher_1 = require("./shared/cipher");
|
|
10
|
+
var TapoApi = (function () {
|
|
11
|
+
function TapoApi(config) {
|
|
12
|
+
var _this = this;
|
|
13
|
+
this._baseUrl = 'https://eu-wap.tplinkcloud.com/';
|
|
14
|
+
this._baseTapoCareUrl = 'https://euw1-app-tapo-care.i.tplinknbu.com';
|
|
15
|
+
this._config = {
|
|
16
|
+
authToken: null,
|
|
17
|
+
timeout: 10000,
|
|
18
|
+
httpTimeout: 4000,
|
|
19
|
+
};
|
|
20
|
+
this._devices = new Map();
|
|
21
|
+
this.auth = function (_a) {
|
|
22
|
+
var email = _a.email, password = _a.password;
|
|
23
|
+
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
24
|
+
var loginRequest, response;
|
|
25
|
+
return tslib_1.__generator(this, function (_b) {
|
|
26
|
+
switch (_b.label) {
|
|
27
|
+
case 0:
|
|
28
|
+
loginRequest = {
|
|
29
|
+
method: 'login',
|
|
30
|
+
params: {
|
|
31
|
+
appType: 'Tapo_Android',
|
|
32
|
+
cloudPassword: password,
|
|
33
|
+
cloudUserName: email,
|
|
34
|
+
terminalUUID: (0, utils_1.uuidv4)(),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
return [4, (0, axios_1.default)({
|
|
38
|
+
method: 'post',
|
|
39
|
+
url: this._baseUrl,
|
|
40
|
+
data: loginRequest,
|
|
41
|
+
})];
|
|
42
|
+
case 1:
|
|
43
|
+
response = _b.sent();
|
|
44
|
+
(0, helpers_1.throwErrorIfFound)(response.data);
|
|
45
|
+
this._token = response.data.result.token;
|
|
46
|
+
return [2, this._token];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
this.setup = function (_a) {
|
|
52
|
+
var email = _a.email, password = _a.password, devices = _a.devices;
|
|
53
|
+
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
54
|
+
var promises;
|
|
55
|
+
var _this = this;
|
|
56
|
+
return tslib_1.__generator(this, function (_b) {
|
|
57
|
+
switch (_b.label) {
|
|
58
|
+
case 0:
|
|
59
|
+
promises = devices.map(function (device) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
60
|
+
var deviceKey, loginDeviceRequest, loginDeviceResponse;
|
|
61
|
+
return tslib_1.__generator(this, function (_a) {
|
|
62
|
+
switch (_a.label) {
|
|
63
|
+
case 0: return [4, (0, helpers_1.handshake)(device.ip)];
|
|
64
|
+
case 1:
|
|
65
|
+
deviceKey = _a.sent();
|
|
66
|
+
loginDeviceRequest = {
|
|
67
|
+
method: 'login_device',
|
|
68
|
+
params: {
|
|
69
|
+
username: (0, cipher_1.base64Encode)((0, cipher_1.shaDigest)(email)),
|
|
70
|
+
password: (0, cipher_1.base64Encode)(password),
|
|
71
|
+
},
|
|
72
|
+
requestTimeMils: 0,
|
|
73
|
+
};
|
|
74
|
+
return [4, (0, helpers_1.securePassthrough)(loginDeviceRequest, deviceKey)];
|
|
75
|
+
case 2:
|
|
76
|
+
loginDeviceResponse = _a.sent();
|
|
77
|
+
deviceKey.token = loginDeviceResponse.token;
|
|
78
|
+
this._devices.set(device.id, deviceKey);
|
|
79
|
+
return [2];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}); });
|
|
83
|
+
return [4, Promise.all(promises)];
|
|
84
|
+
case 1:
|
|
85
|
+
_b.sent();
|
|
86
|
+
return [2, this._devices];
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
this.getAllInfo = function (_a) {
|
|
92
|
+
var _this = this;
|
|
93
|
+
var host = _a.host;
|
|
94
|
+
return new Promise(function (resolve, reject) {
|
|
95
|
+
return _this.axiosInstance
|
|
96
|
+
.get(host + '/json')
|
|
97
|
+
.then(function (res) { return resolve(res.data); })
|
|
98
|
+
.catch(function (err) { return reject(err); });
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
this.getInfo = this.getAllInfo;
|
|
102
|
+
this.sendState = function (config) {
|
|
103
|
+
var deviceKey = _this._devices.get(config.device.id);
|
|
104
|
+
var shouldWait = false;
|
|
105
|
+
if (config.fetchConfig && config.fetchConfig.shouldWait) {
|
|
106
|
+
shouldWait = true;
|
|
107
|
+
}
|
|
108
|
+
var values = config.state.getValues();
|
|
109
|
+
var deviceRequest = {
|
|
110
|
+
method: 'set_device_info',
|
|
111
|
+
params: values,
|
|
112
|
+
terminalUUID: (0, utils_1.uuidv4)(),
|
|
113
|
+
};
|
|
114
|
+
var encryptedRequest = (0, cipher_1.encrypt)(deviceRequest, deviceKey);
|
|
115
|
+
var securePassthroughRequest = {
|
|
116
|
+
method: 'securePassthrough',
|
|
117
|
+
params: {
|
|
118
|
+
request: encryptedRequest,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
return (0, fetch_cove_1.fetchWork)({
|
|
122
|
+
url: "http://".concat(deviceKey.deviceIp, "/app?token=").concat(deviceKey.token),
|
|
123
|
+
data: {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
body: securePassthroughRequest,
|
|
126
|
+
headers: {
|
|
127
|
+
Cookie: deviceKey.sessionCookie,
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
shouldWait: shouldWait,
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
this.sendPower = function (config) {
|
|
134
|
+
_this.sendState({ device: config.device, state: new lightstate_1.LightState({ on: config.power }) });
|
|
135
|
+
};
|
|
136
|
+
this.axiosInstance = axios_1.default.create();
|
|
137
|
+
this.axiosInstance.defaults.timeout = (config === null || config === void 0 ? void 0 : config.httpTimeout) || 4000;
|
|
138
|
+
this._config = tslib_1.__assign(tslib_1.__assign({}, this._config), config);
|
|
139
|
+
}
|
|
140
|
+
return TapoApi;
|
|
141
|
+
}());
|
|
142
|
+
exports.default = TapoApi;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export type RawDeviceTypes = 'SMART.TAPOBULB' | 'SMART.IPCAMERA' | 'SMART.TAPOPLUG' | 'IOT.SMARTBULB' | 'IOT.IPCAMERA' | 'IOT.SMARTPLUGSWITCH';
|
|
3
|
+
export type RawTapoDevice = {
|
|
4
|
+
deviceType: RawDeviceTypes;
|
|
5
|
+
fwVer: string;
|
|
6
|
+
appServerUrl: string;
|
|
7
|
+
deviceRegion: string;
|
|
8
|
+
deviceId: string;
|
|
9
|
+
deviceName: string;
|
|
10
|
+
deviceHwVer: string;
|
|
11
|
+
alias: string;
|
|
12
|
+
deviceMac: string;
|
|
13
|
+
oemId: string;
|
|
14
|
+
deviceModel: string;
|
|
15
|
+
hwId: string;
|
|
16
|
+
fwId: string;
|
|
17
|
+
isSameRegion: boolean;
|
|
18
|
+
status: number;
|
|
19
|
+
ip?: string;
|
|
20
|
+
};
|
|
21
|
+
export type RawTapoDeviceInfo = {
|
|
22
|
+
device_id: string;
|
|
23
|
+
fw_ver: string;
|
|
24
|
+
hw_ver: string;
|
|
25
|
+
type: string;
|
|
26
|
+
model: string;
|
|
27
|
+
mac: string;
|
|
28
|
+
hw_id: string;
|
|
29
|
+
fw_id: string;
|
|
30
|
+
oem_id: string;
|
|
31
|
+
specs: string;
|
|
32
|
+
device_on: boolean;
|
|
33
|
+
on_time: number;
|
|
34
|
+
overheated: boolean;
|
|
35
|
+
nickname: string;
|
|
36
|
+
location: string;
|
|
37
|
+
avatar: string;
|
|
38
|
+
time_usage_today: string;
|
|
39
|
+
time_usage_past7: string;
|
|
40
|
+
time_usage_past30: string;
|
|
41
|
+
longitude: string;
|
|
42
|
+
latitude: string;
|
|
43
|
+
has_set_location_info: boolean;
|
|
44
|
+
ip: string;
|
|
45
|
+
ssid: string;
|
|
46
|
+
signal_level: number;
|
|
47
|
+
rssi: number;
|
|
48
|
+
region: string;
|
|
49
|
+
time_diff: number;
|
|
50
|
+
lang: string;
|
|
51
|
+
};
|
|
52
|
+
export type TapoDeviceKey = {
|
|
53
|
+
key: string | Buffer;
|
|
54
|
+
iv: string | Buffer;
|
|
55
|
+
deviceIp: string;
|
|
56
|
+
sessionCookie: string;
|
|
57
|
+
token?: string;
|
|
58
|
+
};
|
|
59
|
+
export type TapoVideoImage = {
|
|
60
|
+
uri: string;
|
|
61
|
+
length: number;
|
|
62
|
+
uriExpiresAt: number;
|
|
63
|
+
};
|
|
64
|
+
export type TapoVideo = {
|
|
65
|
+
uri: string;
|
|
66
|
+
duration: number;
|
|
67
|
+
m3u8: string;
|
|
68
|
+
startTimestamp: number;
|
|
69
|
+
uriExpiresAt: number;
|
|
70
|
+
};
|
|
71
|
+
export type TapoVideoPageItem = {
|
|
72
|
+
uuid: string;
|
|
73
|
+
video: TapoVideo[];
|
|
74
|
+
image: TapoVideoImage[];
|
|
75
|
+
createdTime: number;
|
|
76
|
+
eventLocalTime: string;
|
|
77
|
+
};
|
|
78
|
+
export type TapoVideoList = {
|
|
79
|
+
deviceId: string;
|
|
80
|
+
total: number;
|
|
81
|
+
page: number;
|
|
82
|
+
pageSize: number;
|
|
83
|
+
index: TapoVideoPageItem[];
|
|
84
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { __awaiter, __generator } from "tslib";
|
|
2
|
+
import { ILumiaDeviceBrands, ILumiaDeviceConnectionType, ILumiaDeviceType } from '@lumiastream/lumia-rgb-types';
|
|
3
|
+
import Axios from 'axios';
|
|
4
|
+
import findLocalDevices from 'local-devices';
|
|
5
|
+
import { base64Decode } from './shared/cipher';
|
|
6
|
+
import { throwErrorIfFound } from './shared/helpers';
|
|
7
|
+
import TapoApi from './tapo-api';
|
|
8
|
+
var discover = function (config) { return __awaiter(void 0, void 0, void 0, function () {
|
|
9
|
+
var api, token, getDeviceRequest, response, devices, localDevices;
|
|
10
|
+
var _a;
|
|
11
|
+
return __generator(this, function (_b) {
|
|
12
|
+
switch (_b.label) {
|
|
13
|
+
case 0:
|
|
14
|
+
api = new TapoApi(config);
|
|
15
|
+
token = config.token;
|
|
16
|
+
if (!!token) return [3, 2];
|
|
17
|
+
return [4, api.auth({ email: config.email, password: config.password })];
|
|
18
|
+
case 1:
|
|
19
|
+
token = _b.sent();
|
|
20
|
+
_b.label = 2;
|
|
21
|
+
case 2:
|
|
22
|
+
getDeviceRequest = {
|
|
23
|
+
method: 'getDeviceList',
|
|
24
|
+
};
|
|
25
|
+
return [4, Axios({
|
|
26
|
+
method: 'post',
|
|
27
|
+
url: "".concat(api._baseUrl, "?token=").concat(token),
|
|
28
|
+
data: getDeviceRequest,
|
|
29
|
+
})];
|
|
30
|
+
case 3:
|
|
31
|
+
response = _b.sent();
|
|
32
|
+
throwErrorIfFound(response.data);
|
|
33
|
+
devices = [];
|
|
34
|
+
return [4, findLocalDevices({ skipNameResolution: true })];
|
|
35
|
+
case 4:
|
|
36
|
+
localDevices = _b.sent();
|
|
37
|
+
(_a = response.data.result) === null || _a === void 0 ? void 0 : _a.deviceList.map(function (deviceInfo) { return __awaiter(void 0, void 0, void 0, function () {
|
|
38
|
+
var findableMac_1, found, isTapo, alias, isTapo, alias;
|
|
39
|
+
var _a, _b;
|
|
40
|
+
return __generator(this, function (_c) {
|
|
41
|
+
if (!deviceInfo.ip) {
|
|
42
|
+
findableMac_1 = deviceInfo.deviceMac.replace(/:/g, '').toUpperCase();
|
|
43
|
+
found = localDevices.find(function (device) { return findableMac_1 == device.mac.replace(/:/g, '').toUpperCase(); });
|
|
44
|
+
if (found) {
|
|
45
|
+
deviceInfo.ip = found.ip;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return [2];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
switch (deviceInfo.deviceType) {
|
|
52
|
+
case 'IOT.SMARTBULB':
|
|
53
|
+
case 'SMART.TAPOBULB': {
|
|
54
|
+
if (config.types && config.types !== ILumiaDeviceType.LIGHT) {
|
|
55
|
+
return [2];
|
|
56
|
+
}
|
|
57
|
+
isTapo = deviceInfo.deviceType === 'SMART.TAPOBULB';
|
|
58
|
+
alias = (_a = (isTapo ? base64Decode(deviceInfo.alias) : deviceInfo.alias)) !== null && _a !== void 0 ? _a : deviceInfo.deviceName;
|
|
59
|
+
devices.push({
|
|
60
|
+
name: alias,
|
|
61
|
+
id: deviceInfo.deviceMac,
|
|
62
|
+
address: "http://".concat(deviceInfo.ip),
|
|
63
|
+
host: deviceInfo.ip,
|
|
64
|
+
lumiaInfo: {
|
|
65
|
+
alias: alias,
|
|
66
|
+
identifier: deviceInfo.deviceMac,
|
|
67
|
+
serial: deviceInfo.hwId,
|
|
68
|
+
lumiaType: ILumiaDeviceType.LIGHT,
|
|
69
|
+
zonable: false,
|
|
70
|
+
maxZones: 1,
|
|
71
|
+
zones: null,
|
|
72
|
+
rgb: true,
|
|
73
|
+
white: true,
|
|
74
|
+
connectionType: ILumiaDeviceConnectionType.WIFI,
|
|
75
|
+
brand: isTapo ? ILumiaDeviceBrands.TPLINK : ILumiaDeviceBrands.TPLINK,
|
|
76
|
+
product: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.deviceModel,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
case 'IOT.SMARTPLUGSWITCH':
|
|
81
|
+
case 'SMART.TAPOPLUG': {
|
|
82
|
+
if (config.types && config.types !== ILumiaDeviceType.PLUG) {
|
|
83
|
+
return [2];
|
|
84
|
+
}
|
|
85
|
+
isTapo = deviceInfo.deviceType === 'SMART.TAPOPLUG';
|
|
86
|
+
alias = (_b = (isTapo ? base64Decode(deviceInfo.alias) : deviceInfo.alias)) !== null && _b !== void 0 ? _b : deviceInfo.deviceName;
|
|
87
|
+
devices.push({
|
|
88
|
+
name: alias,
|
|
89
|
+
id: deviceInfo.deviceMac,
|
|
90
|
+
address: "http://".concat(deviceInfo.ip),
|
|
91
|
+
host: deviceInfo.ip,
|
|
92
|
+
lumiaInfo: {
|
|
93
|
+
alias: alias,
|
|
94
|
+
identifier: deviceInfo.deviceMac,
|
|
95
|
+
serial: deviceInfo.hwId,
|
|
96
|
+
lumiaType: ILumiaDeviceType.PLUG,
|
|
97
|
+
zonable: false,
|
|
98
|
+
maxZones: null,
|
|
99
|
+
zones: null,
|
|
100
|
+
rgb: false,
|
|
101
|
+
white: false,
|
|
102
|
+
connectionType: ILumiaDeviceConnectionType.WIFI,
|
|
103
|
+
brand: isTapo ? ILumiaDeviceBrands.TPLINK : ILumiaDeviceBrands.TPLINK,
|
|
104
|
+
product: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.deviceModel,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return [2];
|
|
110
|
+
});
|
|
111
|
+
}); });
|
|
112
|
+
return [2, devices];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}); };
|
|
116
|
+
export default discover;
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
declare class SuperState {
|
|
2
|
+
protected _values: {};
|
|
3
|
+
transition: (value: number) => this;
|
|
4
|
+
duration: (value: number) => this;
|
|
5
|
+
getValues: () => {};
|
|
6
|
+
}
|
|
7
|
+
export declare class LightState extends SuperState {
|
|
8
|
+
constructor(values?: any);
|
|
9
|
+
create: (values?: any) => this;
|
|
10
|
+
on: (value?: boolean) => this;
|
|
11
|
+
turnOn: (value?: boolean) => this;
|
|
12
|
+
off: () => this;
|
|
13
|
+
turnOff: () => this;
|
|
14
|
+
mode: (value?: string) => this;
|
|
15
|
+
hue: (value: number) => this;
|
|
16
|
+
bri: (value: number) => this;
|
|
17
|
+
brightness: (value: number) => this;
|
|
18
|
+
sat: (value: number) => this;
|
|
19
|
+
saturation: (value: number) => this;
|
|
20
|
+
temp: (value: number) => this;
|
|
21
|
+
colorTemperature: (value: number) => this;
|
|
22
|
+
hsv: (value: [number, number, number] | {
|
|
23
|
+
h: number;
|
|
24
|
+
s: number;
|
|
25
|
+
v: number;
|
|
26
|
+
}) => this;
|
|
27
|
+
rgb: (value: [number, number, number] | {
|
|
28
|
+
r: number;
|
|
29
|
+
g: number;
|
|
30
|
+
b: number;
|
|
31
|
+
}) => this;
|
|
32
|
+
color: (value: {
|
|
33
|
+
ct?: number;
|
|
34
|
+
r?: number;
|
|
35
|
+
g?: number;
|
|
36
|
+
b?: number;
|
|
37
|
+
}) => this;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { __extends } from "tslib";
|
|
2
|
+
import ColorTransformer from './shared/color-transformer';
|
|
3
|
+
import { isTruly } from './shared/utils';
|
|
4
|
+
var isFunction = function (object) {
|
|
5
|
+
var getClass = {}.toString;
|
|
6
|
+
return object && getClass.call(object) === '[object Function]';
|
|
7
|
+
};
|
|
8
|
+
var SuperState = (function () {
|
|
9
|
+
function SuperState() {
|
|
10
|
+
var _this = this;
|
|
11
|
+
this._values = {};
|
|
12
|
+
this.transition = function (value) {
|
|
13
|
+
_this._values['transition_period'] = value;
|
|
14
|
+
return _this;
|
|
15
|
+
};
|
|
16
|
+
this.duration = this.transition;
|
|
17
|
+
this.getValues = function () {
|
|
18
|
+
return _this._values;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return SuperState;
|
|
22
|
+
}());
|
|
23
|
+
var LightState = (function (_super) {
|
|
24
|
+
__extends(LightState, _super);
|
|
25
|
+
function LightState(values) {
|
|
26
|
+
var _this = _super.call(this) || this;
|
|
27
|
+
_this.create = function (values) {
|
|
28
|
+
if (values) {
|
|
29
|
+
Object.keys(values).forEach(function (value) {
|
|
30
|
+
var fn;
|
|
31
|
+
if (_this.hasOwnProperty(value)) {
|
|
32
|
+
fn = _this[value];
|
|
33
|
+
if (isFunction(fn) && isTruly(values[value])) {
|
|
34
|
+
fn.apply(_this, [values[value]]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return _this;
|
|
40
|
+
};
|
|
41
|
+
_this.on = function (value) {
|
|
42
|
+
if (value === void 0) { value = true; }
|
|
43
|
+
_this._values['device_on'] = value;
|
|
44
|
+
return _this;
|
|
45
|
+
};
|
|
46
|
+
_this.turnOn = _this.on;
|
|
47
|
+
_this.off = function () {
|
|
48
|
+
_this.on(false);
|
|
49
|
+
return _this;
|
|
50
|
+
};
|
|
51
|
+
_this.turnOff = _this.off;
|
|
52
|
+
_this.mode = function (value) {
|
|
53
|
+
if (value === void 0) { value = 'normal'; }
|
|
54
|
+
if (value === 'normal') {
|
|
55
|
+
_this._values['color_temp'] = 0;
|
|
56
|
+
}
|
|
57
|
+
_this._values['mode'] = value;
|
|
58
|
+
return _this;
|
|
59
|
+
};
|
|
60
|
+
_this.hue = function (value) {
|
|
61
|
+
_this._values['hue'] = value;
|
|
62
|
+
_this._values['color_temp'] = 0;
|
|
63
|
+
return _this;
|
|
64
|
+
};
|
|
65
|
+
_this.bri = function (value) {
|
|
66
|
+
_this._values['brightness'] = value;
|
|
67
|
+
return _this;
|
|
68
|
+
};
|
|
69
|
+
_this.brightness = _this.bri;
|
|
70
|
+
_this.sat = function (value) {
|
|
71
|
+
_this._values['saturation'] = value;
|
|
72
|
+
return _this;
|
|
73
|
+
};
|
|
74
|
+
_this.saturation = _this.sat;
|
|
75
|
+
_this.temp = function (value) {
|
|
76
|
+
_this._values['color_temp'] = value;
|
|
77
|
+
return _this;
|
|
78
|
+
};
|
|
79
|
+
_this.colorTemperature = _this.temp;
|
|
80
|
+
_this.hsv = function (value) {
|
|
81
|
+
var convertedHsv = [];
|
|
82
|
+
if (Array.isArray(value)) {
|
|
83
|
+
convertedHsv = value;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
convertedHsv = [value.h, value.s, value.v];
|
|
87
|
+
}
|
|
88
|
+
_this.hue(convertedHsv[0]);
|
|
89
|
+
_this.sat(convertedHsv[1]);
|
|
90
|
+
_this.bri(convertedHsv[2]);
|
|
91
|
+
return _this;
|
|
92
|
+
};
|
|
93
|
+
_this.rgb = function (value) {
|
|
94
|
+
var hsv;
|
|
95
|
+
if (Array.isArray(value)) {
|
|
96
|
+
hsv = ColorTransformer.rgb2hsv(value);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
hsv = ColorTransformer.rgb2hsv([value.r, value.g, value.b]);
|
|
100
|
+
}
|
|
101
|
+
return _this.hsv(hsv);
|
|
102
|
+
};
|
|
103
|
+
_this.color = function (value) {
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
value = { r: value[0], g: value[1], b: value[2] };
|
|
106
|
+
}
|
|
107
|
+
if (value.ct) {
|
|
108
|
+
return _this.temp(value.ct);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
return _this.rgb({ r: value.r, g: value.g, b: value.b });
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
if (values)
|
|
115
|
+
_this.create(values);
|
|
116
|
+
return _this;
|
|
117
|
+
}
|
|
118
|
+
return LightState;
|
|
119
|
+
}(SuperState));
|
|
120
|
+
export { LightState };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import crypto, { KeyObject } from 'crypto';
|
|
4
|
+
import type { TapoDeviceKey } from '../types/raw-types';
|
|
5
|
+
export declare const generateKeyPair: () => Promise<crypto.KeyPairKeyObjectResult>;
|
|
6
|
+
export declare const encrypt: (data: any, deviceKey: TapoDeviceKey) => string;
|
|
7
|
+
export declare const decrypt: (data: string, deviceKey: TapoDeviceKey) => any;
|
|
8
|
+
export declare const readDeviceKey: (pemKey: string, privateKey: KeyObject) => Buffer;
|
|
9
|
+
export declare const base64Encode: (data: string) => string;
|
|
10
|
+
export declare const base64Decode: (data: string) => string;
|
|
11
|
+
export declare const shaDigest: (data: string) => string;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { __awaiter, __generator } from "tslib";
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import util from 'util';
|
|
4
|
+
var RSA_CIPHER_ALGORITHM = 'rsa';
|
|
5
|
+
var AES_CIPHER_ALGORITHM = 'aes-128-cbc';
|
|
6
|
+
var PASSPHRASE = 'top secret';
|
|
7
|
+
export var generateKeyPair = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
8
|
+
var RSA_OPTIONS, generateKeyPair;
|
|
9
|
+
return __generator(this, function (_a) {
|
|
10
|
+
RSA_OPTIONS = {
|
|
11
|
+
modulusLength: 1024,
|
|
12
|
+
publicKeyEncoding: {
|
|
13
|
+
type: 'spki',
|
|
14
|
+
format: 'pem',
|
|
15
|
+
},
|
|
16
|
+
privateKeyEncoding: {
|
|
17
|
+
type: 'pkcs1',
|
|
18
|
+
format: 'pem',
|
|
19
|
+
cipher: 'aes-256-cbc',
|
|
20
|
+
passphrase: PASSPHRASE,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
generateKeyPair = util.promisify(crypto.generateKeyPair);
|
|
24
|
+
return [2, generateKeyPair(RSA_CIPHER_ALGORITHM, RSA_OPTIONS)];
|
|
25
|
+
});
|
|
26
|
+
}); };
|
|
27
|
+
export var encrypt = function (data, deviceKey) {
|
|
28
|
+
var cipher = crypto.createCipheriv(AES_CIPHER_ALGORITHM, deviceKey.key, deviceKey.iv);
|
|
29
|
+
var ciphertext = cipher.update(Buffer.from(JSON.stringify(data)));
|
|
30
|
+
return Buffer.concat([ciphertext, cipher.final()]).toString('base64');
|
|
31
|
+
};
|
|
32
|
+
export var decrypt = function (data, deviceKey) {
|
|
33
|
+
var cipher = crypto.createDecipheriv(AES_CIPHER_ALGORITHM, deviceKey.key, deviceKey.iv);
|
|
34
|
+
var ciphertext = cipher.update(Buffer.from(data, 'base64'));
|
|
35
|
+
return JSON.parse(Buffer.concat([ciphertext, cipher.final()]).toString());
|
|
36
|
+
};
|
|
37
|
+
export var readDeviceKey = function (pemKey, privateKey) {
|
|
38
|
+
var keyBytes = Buffer.from(pemKey, 'base64');
|
|
39
|
+
var deviceKey = crypto.privateDecrypt({
|
|
40
|
+
key: privateKey,
|
|
41
|
+
padding: crypto.constants.RSA_PKCS1_PADDING,
|
|
42
|
+
passphrase: PASSPHRASE,
|
|
43
|
+
}, keyBytes);
|
|
44
|
+
return deviceKey;
|
|
45
|
+
};
|
|
46
|
+
export var base64Encode = function (data) {
|
|
47
|
+
return Buffer.from(data).toString('base64');
|
|
48
|
+
};
|
|
49
|
+
export var base64Decode = function (data) {
|
|
50
|
+
return Buffer.from(data, 'base64').toString();
|
|
51
|
+
};
|
|
52
|
+
export var shaDigest = function (data) {
|
|
53
|
+
var shasum = crypto.createHash('sha1');
|
|
54
|
+
shasum.update(data);
|
|
55
|
+
return shasum.digest('hex');
|
|
56
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
var rgb2hsv = function (_a) {
|
|
2
|
+
var r = _a[0], g = _a[1], b = _a[2];
|
|
3
|
+
var rr, gg, bb;
|
|
4
|
+
r = r / 255;
|
|
5
|
+
g = g / 255;
|
|
6
|
+
b = b / 255;
|
|
7
|
+
var h, s, v = Math.max(r, g, b), diff = v - Math.min(r, g, b), diffc = function (c) {
|
|
8
|
+
return (v - c) / 6 / diff + 1 / 2;
|
|
9
|
+
};
|
|
10
|
+
if (diff == 0) {
|
|
11
|
+
h = s = 0;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
s = diff / v;
|
|
15
|
+
rr = diffc(r);
|
|
16
|
+
gg = diffc(g);
|
|
17
|
+
bb = diffc(b);
|
|
18
|
+
if (r === v) {
|
|
19
|
+
h = bb - gg;
|
|
20
|
+
}
|
|
21
|
+
else if (g === v) {
|
|
22
|
+
h = (1 / 3) + rr - bb;
|
|
23
|
+
}
|
|
24
|
+
else if (b === v) {
|
|
25
|
+
h = (2 / 3) + gg - rr;
|
|
26
|
+
}
|
|
27
|
+
if (h < 0) {
|
|
28
|
+
h += 1;
|
|
29
|
+
}
|
|
30
|
+
else if (h > 1) {
|
|
31
|
+
h -= 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
h: Math.round(h * 360),
|
|
36
|
+
s: Math.round(s * 100),
|
|
37
|
+
v: Math.round(v * 100)
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export default { rgb2hsv: rgb2hsv };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { TapoDeviceKey } from '../types/raw-types';
|
|
2
|
+
export declare const throwErrorIfFound: (responseData: any) => void;
|
|
3
|
+
export declare const throwTapoCareErrorIfFound: (responseData: any) => void;
|
|
4
|
+
export declare const handshake: (deviceIp: string) => Promise<TapoDeviceKey>;
|
|
5
|
+
export declare const securePassthrough: (deviceRequest: any, deviceKey: TapoDeviceKey) => Promise<any>;
|