@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,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uuidv4 = exports.isNully = exports.isTruly = void 0;
|
|
4
|
+
var checkHost = function (host) {
|
|
5
|
+
if (host && host.indexOf('http') === -1) {
|
|
6
|
+
return 'http://' + host;
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
return host;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var isTruly = function (value) {
|
|
13
|
+
return value !== undefined && value !== null;
|
|
14
|
+
};
|
|
15
|
+
exports.isTruly = isTruly;
|
|
16
|
+
var isNully = function (value) {
|
|
17
|
+
return value === undefined || value === null;
|
|
18
|
+
};
|
|
19
|
+
exports.isNully = isNully;
|
|
20
|
+
var getRandomNumber = function (min, max) {
|
|
21
|
+
return Math.floor(Math.random() * (max - min + 1) + min);
|
|
22
|
+
};
|
|
23
|
+
var createRandomRgb = function (min, max) {
|
|
24
|
+
return [getRandomNumber(min, max), getRandomNumber(min, max), getRandomNumber(min, max)];
|
|
25
|
+
};
|
|
26
|
+
var bigEndianToLilEndian = function (value, pad) {
|
|
27
|
+
var bigEndian = value.toString(16);
|
|
28
|
+
if (pad) {
|
|
29
|
+
bigEndian = bigEndian.padStart(pad, '0');
|
|
30
|
+
}
|
|
31
|
+
var lilEndian;
|
|
32
|
+
if (pad && pad === 4) {
|
|
33
|
+
lilEndian = Buffer.from(bigEndian, 'hex').readUInt16LE(0).toString(16);
|
|
34
|
+
}
|
|
35
|
+
else if (pad && pad === 8) {
|
|
36
|
+
lilEndian = Buffer.from(bigEndian, 'hex').readUInt32LE(0).toString(16);
|
|
37
|
+
}
|
|
38
|
+
else if (pad) {
|
|
39
|
+
lilEndian = Buffer.from(bigEndian, 'hex').readUIntLE(0, pad).toString(16);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
lilEndian = Buffer.from(bigEndian, 'hex').readUInt16LE(0).toString(16);
|
|
43
|
+
}
|
|
44
|
+
if (pad) {
|
|
45
|
+
lilEndian = lilEndian.padStart(pad, '0');
|
|
46
|
+
}
|
|
47
|
+
return lilEndian;
|
|
48
|
+
};
|
|
49
|
+
var rgbToHsb = function (rgbObj) {
|
|
50
|
+
var red = rgbObj.r / 255;
|
|
51
|
+
var green = rgbObj.g / 255;
|
|
52
|
+
var blue = rgbObj.b / 255;
|
|
53
|
+
var rgb = [red, green, blue];
|
|
54
|
+
var hsb = { h: 0, s: 0, b: 0 };
|
|
55
|
+
var max = maxNumberInArray(rgb);
|
|
56
|
+
var min = minNumberInArray(rgb);
|
|
57
|
+
var c = max - min;
|
|
58
|
+
var hue;
|
|
59
|
+
if (c === 0) {
|
|
60
|
+
hue = 0;
|
|
61
|
+
}
|
|
62
|
+
else if (max === red) {
|
|
63
|
+
hue = (green - blue) / c;
|
|
64
|
+
if (hue < 0) {
|
|
65
|
+
hue += 6;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (max === green) {
|
|
69
|
+
hue = 2 + (blue - red) / c;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
hue = 4 + (red - green) / c;
|
|
73
|
+
}
|
|
74
|
+
hsb.h = Math.round(60 * hue);
|
|
75
|
+
var lightness = max;
|
|
76
|
+
hsb.b = Math.round(lightness * 100);
|
|
77
|
+
var saturation;
|
|
78
|
+
if (c === 0) {
|
|
79
|
+
saturation = 0;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
saturation = c / lightness;
|
|
83
|
+
}
|
|
84
|
+
hsb.s = Math.round(saturation * 100);
|
|
85
|
+
return hsb;
|
|
86
|
+
};
|
|
87
|
+
var minNumberInArray = function (array) {
|
|
88
|
+
var sortedCopy = array.slice();
|
|
89
|
+
sortedCopy.sort(function (a, b) {
|
|
90
|
+
return a - b;
|
|
91
|
+
});
|
|
92
|
+
return sortedCopy[0];
|
|
93
|
+
};
|
|
94
|
+
var maxNumberInArray = function (array) {
|
|
95
|
+
var sortedCopy = array.slice();
|
|
96
|
+
sortedCopy.sort(function (a, b) {
|
|
97
|
+
return a - b;
|
|
98
|
+
});
|
|
99
|
+
return sortedCopy[sortedCopy.length - 1];
|
|
100
|
+
};
|
|
101
|
+
var encrypt = function (input, firstKey) {
|
|
102
|
+
if (firstKey === void 0) { firstKey = 0xab; }
|
|
103
|
+
var buf = Buffer.from(input);
|
|
104
|
+
var key = firstKey;
|
|
105
|
+
for (var i = 0; i < buf.length; i++) {
|
|
106
|
+
buf[i] = buf[i] ^ key;
|
|
107
|
+
key = buf[i];
|
|
108
|
+
}
|
|
109
|
+
return buf;
|
|
110
|
+
};
|
|
111
|
+
function encryptWithHeader(input, firstKey) {
|
|
112
|
+
if (firstKey === void 0) { firstKey = 0xab; }
|
|
113
|
+
var msgBuf = encrypt(input, firstKey);
|
|
114
|
+
var outBuf = Buffer.alloc(msgBuf.length + 4);
|
|
115
|
+
outBuf.writeUInt32BE(msgBuf.length, 0);
|
|
116
|
+
msgBuf.copy(outBuf, 4);
|
|
117
|
+
return outBuf;
|
|
118
|
+
}
|
|
119
|
+
function decrypt(input, firstKey) {
|
|
120
|
+
if (firstKey === void 0) { firstKey = 0xab; }
|
|
121
|
+
var buf = Buffer.from(input);
|
|
122
|
+
var key = firstKey;
|
|
123
|
+
var nextKey;
|
|
124
|
+
for (var i = 0; i < buf.length; i++) {
|
|
125
|
+
nextKey = buf[i];
|
|
126
|
+
buf[i] = buf[i] ^ key;
|
|
127
|
+
key = nextKey;
|
|
128
|
+
}
|
|
129
|
+
return buf;
|
|
130
|
+
}
|
|
131
|
+
function decryptWithHeader(input, firstKey) {
|
|
132
|
+
if (firstKey === void 0) { firstKey = 0xab; }
|
|
133
|
+
return decrypt(input.slice(4));
|
|
134
|
+
}
|
|
135
|
+
function uuidv4() {
|
|
136
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
137
|
+
var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
138
|
+
return v.toString(16);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
exports.uuidv4 = uuidv4;
|
|
142
|
+
exports.default = {
|
|
143
|
+
checkHost: checkHost,
|
|
144
|
+
createRandomRgb: createRandomRgb,
|
|
145
|
+
bigEndianToLilEndian: bigEndianToLilEndian,
|
|
146
|
+
rgbToHsb: rgbToHsb,
|
|
147
|
+
encrypt: encrypt,
|
|
148
|
+
encryptWithHeader: encryptWithHeader,
|
|
149
|
+
decrypt: decrypt,
|
|
150
|
+
decryptWithHeader: decryptWithHeader,
|
|
151
|
+
uuidv4: uuidv4,
|
|
152
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { LightState } from './lightstate';
|
|
2
|
+
import { TapoDeviceKey } from './types/raw-types';
|
|
3
|
+
export default class TapoApi {
|
|
4
|
+
_baseUrl: string;
|
|
5
|
+
_baseTapoCareUrl: string;
|
|
6
|
+
private axiosInstance;
|
|
7
|
+
private _config;
|
|
8
|
+
private _token;
|
|
9
|
+
private _devices;
|
|
10
|
+
constructor(config?: {
|
|
11
|
+
token?: string;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
httpTimeout?: number;
|
|
14
|
+
});
|
|
15
|
+
auth: ({ email, password }: {
|
|
16
|
+
email: string;
|
|
17
|
+
password: string;
|
|
18
|
+
}) => Promise<string>;
|
|
19
|
+
setup: ({ email, password, devices }: {
|
|
20
|
+
email: string;
|
|
21
|
+
password: string;
|
|
22
|
+
devices: Array<{
|
|
23
|
+
id: string;
|
|
24
|
+
ip: string;
|
|
25
|
+
}>;
|
|
26
|
+
}) => Promise<Map<string, TapoDeviceKey>>;
|
|
27
|
+
getAllInfo: ({ host }: {
|
|
28
|
+
host: any;
|
|
29
|
+
}) => Promise<any>;
|
|
30
|
+
getInfo: ({ host }: {
|
|
31
|
+
host: any;
|
|
32
|
+
}) => Promise<any>;
|
|
33
|
+
sendState: (config: {
|
|
34
|
+
device: {
|
|
35
|
+
id: string;
|
|
36
|
+
};
|
|
37
|
+
state: LightState;
|
|
38
|
+
fetchConfig?: {
|
|
39
|
+
shouldWait: boolean;
|
|
40
|
+
};
|
|
41
|
+
}) => Promise<any>;
|
|
42
|
+
sendPower: (config: {
|
|
43
|
+
device: {
|
|
44
|
+
id: string;
|
|
45
|
+
};
|
|
46
|
+
power: boolean;
|
|
47
|
+
}) => void;
|
|
48
|
+
}
|
|
@@ -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,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var tslib_1 = require("tslib");
|
|
4
|
+
var lumia_rgb_types_1 = require("@lumiastream/lumia-rgb-types");
|
|
5
|
+
var axios_1 = tslib_1.__importDefault(require("axios"));
|
|
6
|
+
var local_devices_1 = tslib_1.__importDefault(require("local-devices"));
|
|
7
|
+
var cipher_1 = require("./shared/cipher");
|
|
8
|
+
var helpers_1 = require("./shared/helpers");
|
|
9
|
+
var tapo_api_1 = tslib_1.__importDefault(require("./tapo-api"));
|
|
10
|
+
var discover = function (config) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
11
|
+
var api, token, getDeviceRequest, response, devices, localDevices;
|
|
12
|
+
var _a;
|
|
13
|
+
return tslib_1.__generator(this, function (_b) {
|
|
14
|
+
switch (_b.label) {
|
|
15
|
+
case 0:
|
|
16
|
+
api = new tapo_api_1.default(config);
|
|
17
|
+
token = config.token;
|
|
18
|
+
if (!!token) return [3, 2];
|
|
19
|
+
return [4, api.auth({ email: config.email, password: config.password })];
|
|
20
|
+
case 1:
|
|
21
|
+
token = _b.sent();
|
|
22
|
+
_b.label = 2;
|
|
23
|
+
case 2:
|
|
24
|
+
getDeviceRequest = {
|
|
25
|
+
method: 'getDeviceList',
|
|
26
|
+
};
|
|
27
|
+
return [4, (0, axios_1.default)({
|
|
28
|
+
method: 'post',
|
|
29
|
+
url: "".concat(api._baseUrl, "?token=").concat(token),
|
|
30
|
+
data: getDeviceRequest,
|
|
31
|
+
})];
|
|
32
|
+
case 3:
|
|
33
|
+
response = _b.sent();
|
|
34
|
+
(0, helpers_1.throwErrorIfFound)(response.data);
|
|
35
|
+
devices = [];
|
|
36
|
+
return [4, (0, local_devices_1.default)({ skipNameResolution: true })];
|
|
37
|
+
case 4:
|
|
38
|
+
localDevices = _b.sent();
|
|
39
|
+
(_a = response.data.result) === null || _a === void 0 ? void 0 : _a.deviceList.map(function (deviceInfo) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
40
|
+
var findableMac_1, found, isTapo, alias, isTapo, alias;
|
|
41
|
+
var _a, _b;
|
|
42
|
+
return tslib_1.__generator(this, function (_c) {
|
|
43
|
+
if (!deviceInfo.ip) {
|
|
44
|
+
findableMac_1 = deviceInfo.deviceMac.replace(/:/g, '').toUpperCase();
|
|
45
|
+
found = localDevices.find(function (device) { return findableMac_1 == device.mac.replace(/:/g, '').toUpperCase(); });
|
|
46
|
+
if (found) {
|
|
47
|
+
deviceInfo.ip = found.ip;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return [2];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
switch (deviceInfo.deviceType) {
|
|
54
|
+
case 'IOT.SMARTBULB':
|
|
55
|
+
case 'SMART.TAPOBULB': {
|
|
56
|
+
if (config.types && config.types !== lumia_rgb_types_1.ILumiaDeviceType.LIGHT) {
|
|
57
|
+
return [2];
|
|
58
|
+
}
|
|
59
|
+
isTapo = deviceInfo.deviceType === 'SMART.TAPOBULB';
|
|
60
|
+
alias = (_a = (isTapo ? (0, cipher_1.base64Decode)(deviceInfo.alias) : deviceInfo.alias)) !== null && _a !== void 0 ? _a : deviceInfo.deviceName;
|
|
61
|
+
devices.push({
|
|
62
|
+
name: alias,
|
|
63
|
+
id: deviceInfo.deviceMac,
|
|
64
|
+
address: "http://".concat(deviceInfo.ip),
|
|
65
|
+
host: deviceInfo.ip,
|
|
66
|
+
lumiaInfo: {
|
|
67
|
+
alias: alias,
|
|
68
|
+
identifier: deviceInfo.deviceMac,
|
|
69
|
+
serial: deviceInfo.hwId,
|
|
70
|
+
lumiaType: lumia_rgb_types_1.ILumiaDeviceType.LIGHT,
|
|
71
|
+
zonable: false,
|
|
72
|
+
maxZones: 1,
|
|
73
|
+
zones: null,
|
|
74
|
+
rgb: true,
|
|
75
|
+
white: true,
|
|
76
|
+
connectionType: lumia_rgb_types_1.ILumiaDeviceConnectionType.WIFI,
|
|
77
|
+
brand: isTapo ? lumia_rgb_types_1.ILumiaDeviceBrands.TPLINK : lumia_rgb_types_1.ILumiaDeviceBrands.TPLINK,
|
|
78
|
+
product: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.deviceModel,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
case 'IOT.SMARTPLUGSWITCH':
|
|
83
|
+
case 'SMART.TAPOPLUG': {
|
|
84
|
+
if (config.types && config.types !== lumia_rgb_types_1.ILumiaDeviceType.PLUG) {
|
|
85
|
+
return [2];
|
|
86
|
+
}
|
|
87
|
+
isTapo = deviceInfo.deviceType === 'SMART.TAPOPLUG';
|
|
88
|
+
alias = (_b = (isTapo ? (0, cipher_1.base64Decode)(deviceInfo.alias) : deviceInfo.alias)) !== null && _b !== void 0 ? _b : deviceInfo.deviceName;
|
|
89
|
+
devices.push({
|
|
90
|
+
name: alias,
|
|
91
|
+
id: deviceInfo.deviceMac,
|
|
92
|
+
address: "http://".concat(deviceInfo.ip),
|
|
93
|
+
host: deviceInfo.ip,
|
|
94
|
+
lumiaInfo: {
|
|
95
|
+
alias: alias,
|
|
96
|
+
identifier: deviceInfo.deviceMac,
|
|
97
|
+
serial: deviceInfo.hwId,
|
|
98
|
+
lumiaType: lumia_rgb_types_1.ILumiaDeviceType.PLUG,
|
|
99
|
+
zonable: false,
|
|
100
|
+
maxZones: null,
|
|
101
|
+
zones: null,
|
|
102
|
+
rgb: false,
|
|
103
|
+
white: false,
|
|
104
|
+
connectionType: lumia_rgb_types_1.ILumiaDeviceConnectionType.WIFI,
|
|
105
|
+
brand: isTapo ? lumia_rgb_types_1.ILumiaDeviceBrands.TPLINK : lumia_rgb_types_1.ILumiaDeviceBrands.TPLINK,
|
|
106
|
+
product: deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.deviceModel,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return [2];
|
|
112
|
+
});
|
|
113
|
+
}); });
|
|
114
|
+
return [2, devices];
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}); };
|
|
118
|
+
exports.default = discover;
|
package/lib/cjs/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TapoConstants = exports.TapoApi = exports.discover = exports.LightState = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
5
|
+
var discovery_1 = tslib_1.__importDefault(require("./discovery"));
|
|
6
|
+
exports.discover = discovery_1.default;
|
|
7
|
+
var lightstate_1 = require("./lightstate");
|
|
8
|
+
Object.defineProperty(exports, "LightState", { enumerable: true, get: function () { return lightstate_1.LightState; } });
|
|
9
|
+
var tapo_api_1 = tslib_1.__importDefault(require("./tapo-api"));
|
|
10
|
+
exports.TapoApi = tapo_api_1.default;
|
|
11
|
+
var TapoConstants = tslib_1.__importStar(require("./shared/tapo.constants"));
|
|
12
|
+
exports.TapoConstants = TapoConstants;
|
|
@@ -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 {};
|