@lumiastream/tapo-cove 0.0.1-alpha.2 → 3.0.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.
Files changed (63) hide show
  1. package/dist/index.d.ts +146 -0
  2. package/dist/index.js +554 -0
  3. package/dist/index.mjs +521 -0
  4. package/package.json +25 -37
  5. package/lib/cjs/discovery.d.ts +0 -9
  6. package/lib/cjs/discovery.d.ts.map +0 -1
  7. package/lib/cjs/discovery.js +0 -114
  8. package/lib/cjs/index.d.ts +0 -6
  9. package/lib/cjs/index.d.ts.map +0 -1
  10. package/lib/cjs/index.js +0 -37
  11. package/lib/cjs/lightstate.d.ts +0 -44
  12. package/lib/cjs/lightstate.d.ts.map +0 -1
  13. package/lib/cjs/lightstate.js +0 -123
  14. package/lib/cjs/shared/cipher.d.ts +0 -12
  15. package/lib/cjs/shared/cipher.d.ts.map +0 -1
  16. package/lib/cjs/shared/cipher.js +0 -74
  17. package/lib/cjs/shared/helpers.d.ts +0 -6
  18. package/lib/cjs/shared/helpers.d.ts.map +0 -1
  19. package/lib/cjs/shared/helpers.js +0 -99
  20. package/lib/cjs/tapo-api.d.ts +0 -43
  21. package/lib/cjs/tapo-api.d.ts.map +0 -1
  22. package/lib/cjs/tapo-api.js +0 -114
  23. package/lib/cjs/types/interfaces.d.ts +0 -4
  24. package/lib/cjs/types/interfaces.d.ts.map +0 -1
  25. package/lib/cjs/types/interfaces.js +0 -2
  26. package/lib/cjs/types/raw-types.d.ts +0 -85
  27. package/lib/cjs/types/raw-types.d.ts.map +0 -1
  28. package/lib/cjs/types/raw-types.js +0 -2
  29. package/lib/cjs/types/tapo.constants.d.ts +0 -22
  30. package/lib/cjs/types/tapo.constants.d.ts.map +0 -1
  31. package/lib/cjs/types/tapo.constants.js +0 -25
  32. package/lib/esm/discovery.d.ts +0 -9
  33. package/lib/esm/discovery.d.ts.map +0 -1
  34. package/lib/esm/discovery.js +0 -109
  35. package/lib/esm/index.d.ts +0 -6
  36. package/lib/esm/index.d.ts.map +0 -1
  37. package/lib/esm/index.js +0 -5
  38. package/lib/esm/lightstate.d.ts +0 -44
  39. package/lib/esm/lightstate.d.ts.map +0 -1
  40. package/lib/esm/lightstate.js +0 -119
  41. package/lib/esm/shared/cipher.d.ts +0 -12
  42. package/lib/esm/shared/cipher.d.ts.map +0 -1
  43. package/lib/esm/shared/cipher.js +0 -61
  44. package/lib/esm/shared/helpers.d.ts +0 -6
  45. package/lib/esm/shared/helpers.d.ts.map +0 -1
  46. package/lib/esm/shared/helpers.js +0 -89
  47. package/lib/esm/tapo-api.d.ts +0 -43
  48. package/lib/esm/tapo-api.d.ts.map +0 -1
  49. package/lib/esm/tapo-api.js +0 -108
  50. package/lib/esm/types/interfaces.d.ts +0 -4
  51. package/lib/esm/types/interfaces.d.ts.map +0 -1
  52. package/lib/esm/types/interfaces.js +0 -1
  53. package/lib/esm/types/raw-types.d.ts +0 -85
  54. package/lib/esm/types/raw-types.d.ts.map +0 -1
  55. package/lib/esm/types/raw-types.js +0 -1
  56. package/lib/esm/types/tapo.constants.d.ts +0 -22
  57. package/lib/esm/types/tapo.constants.d.ts.map +0 -1
  58. package/lib/esm/types/tapo.constants.js +0 -22
  59. package/test/auth.test.ts +0 -22
  60. package/test/discover.test.ts +0 -9
  61. package/test/light.test.ts +0 -17
  62. package/test/plug.test.ts +0 -16
  63. package/tslint.json +0 -53
@@ -0,0 +1,146 @@
1
+ import { ILumiaDeviceType } from '@lumiastream/lumia-rgb-types';
2
+
3
+ declare const discover: (config: {
4
+ token?: string;
5
+ email?: string;
6
+ password?: string;
7
+ types?: ILumiaDeviceType;
8
+ }) => Promise<any>;
9
+
10
+ declare class SuperState {
11
+ protected _values: Record<string, boolean | string | number>;
12
+ transition: (value: number) => this;
13
+ duration: (value: number) => this;
14
+ getValues: () => Record<string, string | number | boolean>;
15
+ }
16
+ declare class LightState extends SuperState {
17
+ constructor(values?: {
18
+ on: boolean;
19
+ });
20
+ create: (values?: {
21
+ [x: string]: any;
22
+ } | undefined) => this;
23
+ on: (value?: boolean) => this;
24
+ turnOn: (value?: boolean) => this;
25
+ off: () => this;
26
+ turnOff: () => this;
27
+ mode: (value?: string) => this;
28
+ hue: (value: number) => this;
29
+ bri: (value: number) => this;
30
+ brightness: (value: number) => this;
31
+ sat: (value: number) => this;
32
+ saturation: (value: number) => this;
33
+ temp: (value: number) => this;
34
+ colorTemperature: (value: number) => this;
35
+ hsv: (value: [
36
+ number,
37
+ number,
38
+ number
39
+ ] | {
40
+ h: number;
41
+ s: number;
42
+ v: number;
43
+ }) => this;
44
+ rgb: (value: [
45
+ number,
46
+ number,
47
+ number
48
+ ] | {
49
+ r: number;
50
+ g: number;
51
+ b: number;
52
+ }) => this;
53
+ color: (value: {
54
+ ct?: number;
55
+ r?: number;
56
+ g?: number;
57
+ b?: number;
58
+ }) => this;
59
+ }
60
+
61
+ type TapoDeviceKey = {
62
+ key: string | Buffer;
63
+ iv: string | Buffer;
64
+ deviceIp: string;
65
+ sessionCookie: string;
66
+ token?: string;
67
+ };
68
+
69
+ declare class TapoApi {
70
+ _baseUrl: string;
71
+ _baseTapoCareUrl: string;
72
+ private axiosInstance;
73
+ private _config;
74
+ private _token;
75
+ private _devices;
76
+ constructor(config?: {
77
+ token?: string;
78
+ timeout?: number;
79
+ httpTimeout?: number;
80
+ });
81
+ auth: ({ email, password }: {
82
+ email: string;
83
+ password: string;
84
+ }) => Promise<string>;
85
+ setup: ({ email, password, devices }: {
86
+ email: string;
87
+ password: string;
88
+ devices: Array<{
89
+ id: string;
90
+ ip: string;
91
+ }>;
92
+ }) => Promise<Map<string, TapoDeviceKey>>;
93
+ sendState: (config: {
94
+ device: {
95
+ id: string;
96
+ };
97
+ state: LightState;
98
+ fetchConfig?: {
99
+ shouldWait: boolean;
100
+ };
101
+ }) => Promise<any>;
102
+ sendPower: (config: {
103
+ device: {
104
+ id: string;
105
+ };
106
+ power: boolean;
107
+ }) => void;
108
+ }
109
+
110
+ declare const TapoDeviceTypes: {
111
+ ALL: string;
112
+ BULBS: string;
113
+ LIGHTSTRIPS: string;
114
+ PLUGS: string;
115
+ };
116
+ declare enum ETapoDeviceTypes {
117
+ ALL = "all",
118
+ BULBS = "bulb",
119
+ LIGHTSTRIPS = "lightstrip",
120
+ PLUGS = "plug"
121
+ }
122
+ declare const DeviceResTypes: {
123
+ BULB: string;
124
+ PLUG: string;
125
+ };
126
+ declare const DeviceSendValues: {
127
+ BULB: string;
128
+ LIGHTSTRIP: string;
129
+ PLUG: string;
130
+ };
131
+
132
+ declare const tapo_constants_DeviceResTypes: typeof DeviceResTypes;
133
+ declare const tapo_constants_DeviceSendValues: typeof DeviceSendValues;
134
+ type tapo_constants_ETapoDeviceTypes = ETapoDeviceTypes;
135
+ declare const tapo_constants_ETapoDeviceTypes: typeof ETapoDeviceTypes;
136
+ declare const tapo_constants_TapoDeviceTypes: typeof TapoDeviceTypes;
137
+ declare namespace tapo_constants {
138
+ export {
139
+ tapo_constants_DeviceResTypes as DeviceResTypes,
140
+ tapo_constants_DeviceSendValues as DeviceSendValues,
141
+ tapo_constants_ETapoDeviceTypes as ETapoDeviceTypes,
142
+ tapo_constants_TapoDeviceTypes as TapoDeviceTypes,
143
+ };
144
+ }
145
+
146
+ export { LightState, TapoApi, tapo_constants as TapoConstants, discover };
package/dist/index.js ADDED
@@ -0,0 +1,554 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all)
24
+ __defProp(target, name, { get: all[name], enumerable: true });
25
+ };
26
+ var __copyProps = (to, from, except, desc) => {
27
+ if (from && typeof from === "object" || typeof from === "function") {
28
+ for (let key of __getOwnPropNames(from))
29
+ if (!__hasOwnProp.call(to, key) && key !== except)
30
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
31
+ }
32
+ return to;
33
+ };
34
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
35
+ // If the importer is in node compatibility mode or this is not an ESM
36
+ // file that has been converted to a CommonJS file using a Babel-
37
+ // compatible transform (i.e. "__esModule" has not been set), then set
38
+ // "default" to the CommonJS "module.exports" for node compatibility.
39
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
40
+ mod
41
+ ));
42
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
+ var __async = (__this, __arguments, generator) => {
44
+ return new Promise((resolve, reject) => {
45
+ var fulfilled = (value) => {
46
+ try {
47
+ step(generator.next(value));
48
+ } catch (e) {
49
+ reject(e);
50
+ }
51
+ };
52
+ var rejected = (value) => {
53
+ try {
54
+ step(generator.throw(value));
55
+ } catch (e) {
56
+ reject(e);
57
+ }
58
+ };
59
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
60
+ step((generator = generator.apply(__this, __arguments)).next());
61
+ });
62
+ };
63
+
64
+ // src/index.ts
65
+ var src_exports = {};
66
+ __export(src_exports, {
67
+ LightState: () => LightState,
68
+ TapoApi: () => TapoApi,
69
+ TapoConstants: () => tapo_constants_exports,
70
+ discover: () => discovery_default
71
+ });
72
+ module.exports = __toCommonJS(src_exports);
73
+
74
+ // src/discovery.ts
75
+ var import_lumia_rgb_types = require("@lumiastream/lumia-rgb-types");
76
+ var import_axios3 = __toESM(require("axios"));
77
+ var import_local_devices = __toESM(require("local-devices"));
78
+
79
+ // src/shared/cipher.ts
80
+ var import_crypto = __toESM(require("crypto"));
81
+ var import_util = __toESM(require("util"));
82
+ var RSA_CIPHER_ALGORITHM = "rsa";
83
+ var AES_CIPHER_ALGORITHM = "aes-128-cbc";
84
+ var PASSPHRASE = "top secret";
85
+ var generateKeyPair = () => __async(void 0, null, function* () {
86
+ const RSA_OPTIONS = {
87
+ modulusLength: 1024,
88
+ publicKeyEncoding: {
89
+ type: "spki",
90
+ format: "pem"
91
+ },
92
+ privateKeyEncoding: {
93
+ type: "pkcs1",
94
+ format: "pem",
95
+ cipher: "aes-256-cbc",
96
+ passphrase: PASSPHRASE
97
+ }
98
+ };
99
+ const generateKeyPair2 = import_util.default.promisify(import_crypto.default.generateKeyPair);
100
+ return generateKeyPair2(RSA_CIPHER_ALGORITHM, RSA_OPTIONS);
101
+ });
102
+ var encrypt = (data, deviceKey) => {
103
+ var cipher = import_crypto.default.createCipheriv(AES_CIPHER_ALGORITHM, deviceKey.key, deviceKey.iv);
104
+ var ciphertext = cipher.update(Buffer.from(JSON.stringify(data)));
105
+ return Buffer.concat([ciphertext, cipher.final()]).toString("base64");
106
+ };
107
+ var decrypt = (data, deviceKey) => {
108
+ var cipher = import_crypto.default.createDecipheriv(AES_CIPHER_ALGORITHM, deviceKey.key, deviceKey.iv);
109
+ var ciphertext = cipher.update(Buffer.from(data, "base64"));
110
+ return JSON.parse(Buffer.concat([ciphertext, cipher.final()]).toString());
111
+ };
112
+ var readDeviceKey = (pemKey, privateKey) => {
113
+ const keyBytes = Buffer.from(pemKey, "base64");
114
+ const deviceKey = import_crypto.default.privateDecrypt(
115
+ {
116
+ key: privateKey,
117
+ padding: import_crypto.default.constants.RSA_PKCS1_PADDING,
118
+ passphrase: PASSPHRASE
119
+ },
120
+ keyBytes
121
+ );
122
+ return deviceKey;
123
+ };
124
+ var base64Encode = (data) => {
125
+ return Buffer.from(data).toString("base64");
126
+ };
127
+ var base64Decode = (data) => {
128
+ return Buffer.from(data, "base64").toString();
129
+ };
130
+ var shaDigest = (data) => {
131
+ var shasum = import_crypto.default.createHash("sha1");
132
+ shasum.update(data);
133
+ return shasum.digest("hex");
134
+ };
135
+
136
+ // src/shared/helpers.ts
137
+ var import_axios = __toESM(require("axios"));
138
+ var throwErrorIfFound = (responseData) => {
139
+ const errorCode = responseData["error_code"];
140
+ if (errorCode) {
141
+ switch (errorCode) {
142
+ case 0:
143
+ return;
144
+ case -1010:
145
+ throw new Error("Invalid public key length");
146
+ case -1012:
147
+ throw new Error("Invalid terminal UUID");
148
+ case -1501:
149
+ throw new Error("Invalid request or credentials");
150
+ case -1002:
151
+ throw new Error("Incorrect request");
152
+ case -1003:
153
+ throw new Error("JSON format error");
154
+ case -20601:
155
+ throw new Error("Incorrect email or password");
156
+ case -20675:
157
+ throw new Error("Cloud token expired or invalid");
158
+ case 9999:
159
+ throw new Error("Device token expired or invalid");
160
+ default:
161
+ throw new Error(`Unexpected Error Code: ${errorCode} (${responseData["msg"]})`);
162
+ }
163
+ }
164
+ };
165
+ var handshake = (deviceIp) => __async(void 0, null, function* () {
166
+ const keyPair = yield generateKeyPair();
167
+ const handshakeRequest = {
168
+ method: "handshake",
169
+ params: {
170
+ key: keyPair.publicKey
171
+ }
172
+ };
173
+ const response = yield (0, import_axios.default)({
174
+ method: "post",
175
+ url: `http://${deviceIp}/app`,
176
+ data: handshakeRequest
177
+ });
178
+ throwErrorIfFound(response.data);
179
+ const setCookieHeader = response.headers["set-cookie"][0];
180
+ const sessionCookie = setCookieHeader.substring(0, setCookieHeader.indexOf(";"));
181
+ const deviceKey = readDeviceKey(response.data.result.key, keyPair.privateKey);
182
+ return {
183
+ key: deviceKey.subarray(0, 16),
184
+ iv: deviceKey.subarray(16, 32),
185
+ deviceIp,
186
+ sessionCookie
187
+ };
188
+ });
189
+ var securePassthrough = (deviceRequest, deviceKey) => __async(void 0, null, function* () {
190
+ const encryptedRequest = encrypt(deviceRequest, deviceKey);
191
+ const securePassthroughRequest = {
192
+ method: "securePassthrough",
193
+ params: {
194
+ request: encryptedRequest
195
+ }
196
+ };
197
+ const response = yield (0, import_axios.default)({
198
+ method: "post",
199
+ url: `http://${deviceKey.deviceIp}/app?token=${deviceKey.token}`,
200
+ data: securePassthroughRequest,
201
+ headers: {
202
+ Cookie: deviceKey.sessionCookie
203
+ }
204
+ });
205
+ throwErrorIfFound(response.data);
206
+ const decryptedResponse = decrypt(response.data.result.response, deviceKey);
207
+ throwErrorIfFound(decryptedResponse);
208
+ return decryptedResponse.result;
209
+ });
210
+
211
+ // src/tapo-api.ts
212
+ var import_axios2 = __toESM(require("axios"));
213
+
214
+ // src/lightstate.ts
215
+ var import_lumia_rgb_utils = require("@lumiastream/lumia-rgb-utils");
216
+ var SuperState = class {
217
+ constructor() {
218
+ this._values = {};
219
+ // In Milliseconds
220
+ // 0.0 – infinity seconds
221
+ this.transition = (value) => {
222
+ this._values["transition_period"] = value;
223
+ return this;
224
+ };
225
+ this.duration = this.transition;
226
+ this.getValues = () => {
227
+ return this._values;
228
+ };
229
+ }
230
+ };
231
+ var LightState = class extends SuperState {
232
+ constructor(values) {
233
+ super();
234
+ this.create = (values) => {
235
+ if (values) {
236
+ Object.keys(values).forEach((value) => {
237
+ let fn;
238
+ if (this.hasOwnProperty(value)) {
239
+ fn = this[value];
240
+ if ((0, import_lumia_rgb_utils.isFunction)(fn) && (0, import_lumia_rgb_utils.isTruly)(values[value])) {
241
+ fn.apply(this, [values[value]]);
242
+ }
243
+ }
244
+ });
245
+ }
246
+ return this;
247
+ };
248
+ this.on = (value = true) => {
249
+ this._values["device_on"] = value;
250
+ return this;
251
+ };
252
+ this.turnOn = this.on;
253
+ this.off = () => {
254
+ this.on(false);
255
+ return this;
256
+ };
257
+ this.turnOff = this.off;
258
+ this.mode = (value = "normal") => {
259
+ if (value === "normal") {
260
+ this._values["color_temp"] = 0;
261
+ }
262
+ this._values["mode"] = value;
263
+ return this;
264
+ };
265
+ // 0 - 360
266
+ this.hue = (value) => {
267
+ this._values["hue"] = value;
268
+ this._values["color_temp"] = 0;
269
+ return this;
270
+ };
271
+ // Bri 0-100
272
+ this.bri = (value) => {
273
+ this._values["brightness"] = value;
274
+ return this;
275
+ };
276
+ this.brightness = this.bri;
277
+ this.sat = (value) => {
278
+ this._values["saturation"] = value;
279
+ return this;
280
+ };
281
+ this.saturation = this.sat;
282
+ // Color Temperature 2500 - 9000 in kelvin
283
+ // Will override hue if passed
284
+ this.temp = (value) => {
285
+ this._values["color_temp"] = value;
286
+ return this;
287
+ };
288
+ this.colorTemperature = this.temp;
289
+ // Can take in an array or object
290
+ this.hsv = (value) => {
291
+ let convertedHsv = [];
292
+ if (Array.isArray(value)) {
293
+ convertedHsv = value;
294
+ } else {
295
+ convertedHsv = [value.h, value.s, value.v];
296
+ }
297
+ this.hue(convertedHsv[0]);
298
+ this.sat(convertedHsv[1]);
299
+ this.bri(convertedHsv[2]);
300
+ return this;
301
+ };
302
+ // Can take in an array or object
303
+ this.rgb = (value) => {
304
+ let hsv;
305
+ if (Array.isArray(value)) {
306
+ hsv = (0, import_lumia_rgb_utils.rgb2hsv)(value);
307
+ } else {
308
+ hsv = (0, import_lumia_rgb_utils.rgb2hsv)([value.r, value.g, value.b]);
309
+ }
310
+ return this.hsv(hsv);
311
+ };
312
+ // Can take in an object will first check for ct and if it exists and the light will worki with it it'll use color temp
313
+ this.color = (value) => {
314
+ if (Array.isArray(value)) {
315
+ value = { r: value[0], g: value[1], b: value[2] };
316
+ }
317
+ if (value.ct) {
318
+ return this.temp(value.ct);
319
+ } else {
320
+ return this.rgb({ r: value.r, g: value.g, b: value.b });
321
+ }
322
+ };
323
+ if (values)
324
+ this.create(values);
325
+ }
326
+ };
327
+
328
+ // src/tapo-api.ts
329
+ var import_fetch_cove = require("@lumiastream/fetch-cove");
330
+ var import_lumia_rgb_utils2 = require("@lumiastream/lumia-rgb-utils");
331
+ var TapoApi = class {
332
+ constructor(config) {
333
+ this._baseUrl = "https://eu-wap.tplinkcloud.com/";
334
+ // https://n-euw1-wap-gw.tplinkcloud.com
335
+ this._baseTapoCareUrl = "https://euw1-app-tapo-care.i.tplinknbu.com";
336
+ this._config = {
337
+ authToken: null,
338
+ timeout: 1e4,
339
+ httpTimeout: 4e3
340
+ };
341
+ this._token = "";
342
+ this._devices = /* @__PURE__ */ new Map();
343
+ this.auth = (_0) => __async(this, [_0], function* ({ email, password }) {
344
+ const loginRequest = {
345
+ method: "login",
346
+ params: {
347
+ appType: "Tapo_Android",
348
+ cloudPassword: password,
349
+ cloudUserName: email,
350
+ terminalUUID: (0, import_lumia_rgb_utils2.uuidv4)()
351
+ }
352
+ };
353
+ const response = yield (0, import_axios2.default)({
354
+ method: "post",
355
+ url: this._baseUrl,
356
+ data: loginRequest
357
+ });
358
+ throwErrorIfFound(response.data);
359
+ this._token = response.data.result.token;
360
+ return this._token;
361
+ });
362
+ this.setup = (_0) => __async(this, [_0], function* ({ email, password, devices }) {
363
+ const promises = devices.map((device) => __async(this, null, function* () {
364
+ const deviceKey = yield handshake(device.ip);
365
+ const loginDeviceRequest = {
366
+ method: "login_device",
367
+ params: {
368
+ username: base64Encode(shaDigest(email)),
369
+ password: base64Encode(password)
370
+ },
371
+ requestTimeMils: 0
372
+ };
373
+ const loginDeviceResponse = yield securePassthrough(loginDeviceRequest, deviceKey);
374
+ deviceKey.token = loginDeviceResponse.token;
375
+ this._devices.set(device.id, deviceKey);
376
+ return;
377
+ }));
378
+ yield Promise.all(promises);
379
+ return this._devices;
380
+ });
381
+ // Change state using lightstate
382
+ this.sendState = (config) => {
383
+ const deviceKey = this._devices.get(config.device.id);
384
+ let shouldWait = false;
385
+ if (config.fetchConfig && config.fetchConfig.shouldWait) {
386
+ shouldWait = true;
387
+ }
388
+ if (!deviceKey) {
389
+ return Promise.resolve(false);
390
+ }
391
+ const values = config.state.getValues();
392
+ const deviceRequest = {
393
+ method: "set_device_info",
394
+ params: values,
395
+ terminalUUID: (0, import_lumia_rgb_utils2.uuidv4)()
396
+ };
397
+ const encryptedRequest = encrypt(deviceRequest, deviceKey);
398
+ const securePassthroughRequest = {
399
+ method: "securePassthrough",
400
+ params: {
401
+ request: encryptedRequest
402
+ }
403
+ };
404
+ return (0, import_fetch_cove.fetchWork)({
405
+ url: `http://${deviceKey.deviceIp}/app?token=${deviceKey.token}`,
406
+ data: {
407
+ method: "POST",
408
+ body: securePassthroughRequest,
409
+ headers: {
410
+ Cookie: deviceKey.sessionCookie
411
+ }
412
+ },
413
+ shouldWait
414
+ });
415
+ };
416
+ this.sendPower = (config) => {
417
+ this.sendState({ device: config.device, state: new LightState({ on: config.power }) });
418
+ };
419
+ this.axiosInstance = import_axios2.default.create();
420
+ this.axiosInstance.defaults.timeout = (config == null ? void 0 : config.httpTimeout) || 4e3;
421
+ this._config = __spreadValues(__spreadValues({}, this._config), config);
422
+ }
423
+ };
424
+
425
+ // src/discovery.ts
426
+ var discover = (config) => __async(void 0, null, function* () {
427
+ var _a;
428
+ const api = new TapoApi(config);
429
+ let token = config.token;
430
+ if (!token && config.email && config.password) {
431
+ token = yield api.auth({ email: config.email, password: config.password });
432
+ }
433
+ const getDeviceRequest = {
434
+ method: "getDeviceList"
435
+ };
436
+ const response = yield (0, import_axios3.default)({
437
+ method: "post",
438
+ url: `${api._baseUrl}?token=${token}`,
439
+ data: getDeviceRequest
440
+ });
441
+ throwErrorIfFound(response.data);
442
+ const devices = [];
443
+ const localDevices = yield (0, import_local_devices.default)({ skipNameResolution: true });
444
+ (_a = response.data.result) == null ? void 0 : _a.deviceList.map((deviceInfo) => __async(void 0, null, function* () {
445
+ var _a2, _b;
446
+ if (!deviceInfo.ip) {
447
+ const findableMac = deviceInfo.deviceMac.replace(/:/g, "").toUpperCase();
448
+ const found = localDevices.find((device) => findableMac == device.mac.replace(/:/g, "").toUpperCase());
449
+ if (found) {
450
+ deviceInfo.ip = found.ip;
451
+ } else {
452
+ return;
453
+ }
454
+ }
455
+ switch (deviceInfo.deviceType) {
456
+ case "IOT.SMARTBULB":
457
+ case "SMART.TAPOBULB": {
458
+ if (config.types && config.types !== import_lumia_rgb_types.ILumiaDeviceType.LIGHT) {
459
+ return;
460
+ }
461
+ const isTapo = deviceInfo.deviceType === "SMART.TAPOBULB";
462
+ const alias = (_a2 = isTapo ? base64Decode(deviceInfo.alias) : deviceInfo.alias) != null ? _a2 : deviceInfo.deviceName;
463
+ devices.push({
464
+ name: alias,
465
+ id: deviceInfo.deviceMac,
466
+ address: `http://${deviceInfo.ip}`,
467
+ host: deviceInfo.ip,
468
+ lumiaInfo: {
469
+ alias,
470
+ identifier: deviceInfo.deviceMac,
471
+ serial: deviceInfo.hwId,
472
+ lumiaType: import_lumia_rgb_types.ILumiaDeviceType.LIGHT,
473
+ zonable: false,
474
+ maxZones: 1,
475
+ zones: [],
476
+ rgb: true,
477
+ white: true,
478
+ connectionType: import_lumia_rgb_types.ILumiaDeviceConnectionType.WIFI,
479
+ brand: isTapo ? import_lumia_rgb_types.ILumiaDeviceBrands.TPLINK : import_lumia_rgb_types.ILumiaDeviceBrands.TPLINK,
480
+ product: deviceInfo == null ? void 0 : deviceInfo.deviceModel
481
+ }
482
+ });
483
+ }
484
+ case "IOT.SMARTPLUGSWITCH":
485
+ case "SMART.TAPOPLUG": {
486
+ if (config.types && config.types !== import_lumia_rgb_types.ILumiaDeviceType.PLUG) {
487
+ return;
488
+ }
489
+ const isTapo = deviceInfo.deviceType === "SMART.TAPOPLUG";
490
+ const alias = (_b = isTapo ? base64Decode(deviceInfo.alias) : deviceInfo.alias) != null ? _b : deviceInfo.deviceName;
491
+ devices.push({
492
+ name: alias,
493
+ id: deviceInfo.deviceMac,
494
+ address: `http://${deviceInfo.ip}`,
495
+ host: deviceInfo.ip,
496
+ lumiaInfo: {
497
+ alias,
498
+ identifier: deviceInfo.deviceMac,
499
+ serial: deviceInfo.hwId,
500
+ lumiaType: import_lumia_rgb_types.ILumiaDeviceType.PLUG,
501
+ zonable: false,
502
+ maxZones: 0,
503
+ zones: [],
504
+ rgb: false,
505
+ white: false,
506
+ connectionType: import_lumia_rgb_types.ILumiaDeviceConnectionType.WIFI,
507
+ brand: isTapo ? import_lumia_rgb_types.ILumiaDeviceBrands.TPLINK : import_lumia_rgb_types.ILumiaDeviceBrands.TPLINK,
508
+ product: deviceInfo == null ? void 0 : deviceInfo.deviceModel
509
+ }
510
+ });
511
+ }
512
+ }
513
+ }));
514
+ return devices;
515
+ });
516
+ var discovery_default = discover;
517
+
518
+ // src/types/tapo.constants.ts
519
+ var tapo_constants_exports = {};
520
+ __export(tapo_constants_exports, {
521
+ DeviceResTypes: () => DeviceResTypes,
522
+ DeviceSendValues: () => DeviceSendValues,
523
+ ETapoDeviceTypes: () => ETapoDeviceTypes,
524
+ TapoDeviceTypes: () => TapoDeviceTypes
525
+ });
526
+ var TapoDeviceTypes = {
527
+ ALL: "all",
528
+ BULBS: "bulb",
529
+ LIGHTSTRIPS: "lightstrip",
530
+ PLUGS: "plug"
531
+ };
532
+ var ETapoDeviceTypes = /* @__PURE__ */ ((ETapoDeviceTypes2) => {
533
+ ETapoDeviceTypes2["ALL"] = "all";
534
+ ETapoDeviceTypes2["BULBS"] = "bulb";
535
+ ETapoDeviceTypes2["LIGHTSTRIPS"] = "lightstrip";
536
+ ETapoDeviceTypes2["PLUGS"] = "plug";
537
+ return ETapoDeviceTypes2;
538
+ })(ETapoDeviceTypes || {});
539
+ var DeviceResTypes = {
540
+ BULB: "IOT.SMARTPLUGSWITCH",
541
+ PLUG: "IOT.SMARTPLUGSWITCH"
542
+ };
543
+ var DeviceSendValues = {
544
+ BULB: "smartlife.iot.smartbulb.lightingservice",
545
+ LIGHTSTRIP: "smartlife.iot.lightStrip",
546
+ PLUG: "system"
547
+ };
548
+ // Annotate the CommonJS export names for ESM import in node:
549
+ 0 && (module.exports = {
550
+ LightState,
551
+ TapoApi,
552
+ TapoConstants,
553
+ discover
554
+ });