@mp-consulting/homebridge-lg-thinq 1.0.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/.claude/settings.local.json +15 -0
- package/CHANGELOG.md +98 -0
- package/LICENSE +176 -0
- package/README.md +114 -0
- package/config.schema.json +399 -0
- package/dist/__tests__/baseDevice.spec.d.ts +1 -0
- package/dist/__tests__/baseDevice.spec.js +96 -0
- package/dist/__tests__/baseDevice.spec.js.map +1 -0
- package/dist/__tests__/deviceControl.coercion.spec.d.ts +1 -0
- package/dist/__tests__/deviceControl.coercion.spec.js +53 -0
- package/dist/__tests__/deviceControl.coercion.spec.js.map +1 -0
- package/dist/__tests__/helper.spec.d.ts +1 -0
- package/dist/__tests__/helper.spec.js +74 -0
- package/dist/__tests__/helper.spec.js.map +1 -0
- package/dist/baseDevice.d.ts +40 -0
- package/dist/baseDevice.js +85 -0
- package/dist/baseDevice.js.map +1 -0
- package/dist/baseDevice.spec.d.ts +1 -0
- package/dist/baseDevice.spec.js +107 -0
- package/dist/baseDevice.spec.js.map +1 -0
- package/dist/characteristics/TotalConsumption.d.ts +2 -0
- package/dist/characteristics/TotalConsumption.js +17 -0
- package/dist/characteristics/TotalConsumption.js.map +1 -0
- package/dist/characteristics/index.d.ts +2 -0
- package/dist/characteristics/index.js +7 -0
- package/dist/characteristics/index.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +89 -0
- package/dist/cli.js.map +1 -0
- package/dist/devices/AeroTower.d.ts +24 -0
- package/dist/devices/AeroTower.js +113 -0
- package/dist/devices/AeroTower.js.map +1 -0
- package/dist/devices/AirConditioner.d.ts +425 -0
- package/dist/devices/AirConditioner.js +1253 -0
- package/dist/devices/AirConditioner.js.map +1 -0
- package/dist/devices/AirPurifier.d.ts +50 -0
- package/dist/devices/AirPurifier.js +281 -0
- package/dist/devices/AirPurifier.js.map +1 -0
- package/dist/devices/Dehumidifier.d.ts +28 -0
- package/dist/devices/Dehumidifier.js +175 -0
- package/dist/devices/Dehumidifier.js.map +1 -0
- package/dist/devices/Dishwasher.d.ts +64 -0
- package/dist/devices/Dishwasher.js +740 -0
- package/dist/devices/Dishwasher.js.map +1 -0
- package/dist/devices/Microwave.d.ts +128 -0
- package/dist/devices/Microwave.js +1939 -0
- package/dist/devices/Microwave.js.map +1 -0
- package/dist/devices/Oven.d.ts +148 -0
- package/dist/devices/Oven.js +1850 -0
- package/dist/devices/Oven.js.map +1 -0
- package/dist/devices/RangeHood.d.ts +16 -0
- package/dist/devices/RangeHood.js +99 -0
- package/dist/devices/RangeHood.js.map +1 -0
- package/dist/devices/Refrigerator.d.ts +50 -0
- package/dist/devices/Refrigerator.js +325 -0
- package/dist/devices/Refrigerator.js.map +1 -0
- package/dist/devices/Styler.d.ts +27 -0
- package/dist/devices/Styler.js +76 -0
- package/dist/devices/Styler.js.map +1 -0
- package/dist/devices/WasherDryer.d.ts +39 -0
- package/dist/devices/WasherDryer.js +170 -0
- package/dist/devices/WasherDryer.js.map +1 -0
- package/dist/devices/WasherDryer2.d.ts +9 -0
- package/dist/devices/WasherDryer2.js +16 -0
- package/dist/devices/WasherDryer2.js.map +1 -0
- package/dist/errors/AuthenticationError.d.ts +2 -0
- package/dist/errors/AuthenticationError.js +3 -0
- package/dist/errors/AuthenticationError.js.map +1 -0
- package/dist/errors/ManualProcessNeeded.d.ts +3 -0
- package/dist/errors/ManualProcessNeeded.js +4 -0
- package/dist/errors/ManualProcessNeeded.js.map +1 -0
- package/dist/errors/MonitorError.d.ts +2 -0
- package/dist/errors/MonitorError.js +3 -0
- package/dist/errors/MonitorError.js.map +1 -0
- package/dist/errors/NotConnectedError.d.ts +3 -0
- package/dist/errors/NotConnectedError.js +4 -0
- package/dist/errors/NotConnectedError.js.map +1 -0
- package/dist/errors/TokenError.d.ts +2 -0
- package/dist/errors/TokenError.js +3 -0
- package/dist/errors/TokenError.js.map +1 -0
- package/dist/errors/TokenExpiredError.d.ts +3 -0
- package/dist/errors/TokenExpiredError.js +4 -0
- package/dist/errors/TokenExpiredError.js.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.js +7 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/helper.d.ts +24 -0
- package/dist/helper.js +66 -0
- package/dist/helper.js.map +1 -0
- package/dist/helper.spec.d.ts +1 -0
- package/dist/helper.spec.js +74 -0
- package/dist/helper.spec.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/API.d.ts +141 -0
- package/dist/lib/API.js +362 -0
- package/dist/lib/API.js.map +1 -0
- package/dist/lib/API.spec.d.ts +1 -0
- package/dist/lib/API.spec.js +55 -0
- package/dist/lib/API.spec.js.map +1 -0
- package/dist/lib/Auth.d.ts +99 -0
- package/dist/lib/Auth.js +348 -0
- package/dist/lib/Auth.js.map +1 -0
- package/dist/lib/Auth.spec.d.ts +1 -0
- package/dist/lib/Auth.spec.js +111 -0
- package/dist/lib/Auth.spec.js.map +1 -0
- package/dist/lib/Device.d.ts +88 -0
- package/dist/lib/Device.js +95 -0
- package/dist/lib/Device.js.map +1 -0
- package/dist/lib/Device.spec.d.ts +1 -0
- package/dist/lib/Device.spec.js +53 -0
- package/dist/lib/Device.spec.js.map +1 -0
- package/dist/lib/DeviceModel.d.ts +164 -0
- package/dist/lib/DeviceModel.js +321 -0
- package/dist/lib/DeviceModel.js.map +1 -0
- package/dist/lib/DeviceModel.spec.d.ts +1 -0
- package/dist/lib/DeviceModel.spec.js +90 -0
- package/dist/lib/DeviceModel.spec.js.map +1 -0
- package/dist/lib/Gateway.d.ts +18 -0
- package/dist/lib/Gateway.js +25 -0
- package/dist/lib/Gateway.js.map +1 -0
- package/dist/lib/Gateway.spec.d.ts +1 -0
- package/dist/lib/Gateway.spec.js +35 -0
- package/dist/lib/Gateway.spec.js.map +1 -0
- package/dist/lib/Persist.d.ts +101 -0
- package/dist/lib/Persist.js +245 -0
- package/dist/lib/Persist.js.map +1 -0
- package/dist/lib/Persist.spec.d.ts +1 -0
- package/dist/lib/Persist.spec.js +90 -0
- package/dist/lib/Persist.spec.js.map +1 -0
- package/dist/lib/Session.d.ts +80 -0
- package/dist/lib/Session.js +100 -0
- package/dist/lib/Session.js.map +1 -0
- package/dist/lib/Session.spec.d.ts +1 -0
- package/dist/lib/Session.spec.js +43 -0
- package/dist/lib/Session.spec.js.map +1 -0
- package/dist/lib/ThinQ.d.ts +28 -0
- package/dist/lib/ThinQ.js +373 -0
- package/dist/lib/ThinQ.js.map +1 -0
- package/dist/lib/__tests__/API.spec.d.ts +1 -0
- package/dist/lib/__tests__/API.spec.js +55 -0
- package/dist/lib/__tests__/API.spec.js.map +1 -0
- package/dist/lib/__tests__/Auth.spec.d.ts +1 -0
- package/dist/lib/__tests__/Auth.spec.js +110 -0
- package/dist/lib/__tests__/Auth.spec.js.map +1 -0
- package/dist/lib/__tests__/Device.spec.d.ts +1 -0
- package/dist/lib/__tests__/Device.spec.js +53 -0
- package/dist/lib/__tests__/Device.spec.js.map +1 -0
- package/dist/lib/__tests__/DeviceModel.spec.d.ts +1 -0
- package/dist/lib/__tests__/DeviceModel.spec.js +90 -0
- package/dist/lib/__tests__/DeviceModel.spec.js.map +1 -0
- package/dist/lib/__tests__/Gateway.spec.d.ts +1 -0
- package/dist/lib/__tests__/Gateway.spec.js +35 -0
- package/dist/lib/__tests__/Gateway.spec.js.map +1 -0
- package/dist/lib/__tests__/Persist.spec.d.ts +1 -0
- package/dist/lib/__tests__/Persist.spec.js +90 -0
- package/dist/lib/__tests__/Persist.spec.js.map +1 -0
- package/dist/lib/__tests__/Session.spec.d.ts +1 -0
- package/dist/lib/__tests__/Session.spec.js +43 -0
- package/dist/lib/__tests__/Session.spec.js.map +1 -0
- package/dist/lib/constants.d.ts +95 -0
- package/dist/lib/constants.js +106 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/request.d.ts +2 -0
- package/dist/lib/request.js +66 -0
- package/dist/lib/request.js.map +1 -0
- package/dist/platform.d.ts +41 -0
- package/dist/platform.js +229 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.d.ts +8 -0
- package/dist/settings.js +9 -0
- package/dist/settings.js.map +1 -0
- package/dist/status/BaseStatus.d.ts +48 -0
- package/dist/status/BaseStatus.js +59 -0
- package/dist/status/BaseStatus.js.map +1 -0
- package/dist/types/snapshots.d.ts +142 -0
- package/dist/types/snapshots.js +6 -0
- package/dist/types/snapshots.js.map +1 -0
- package/dist/utils/__tests__/normalize.spec.d.ts +1 -0
- package/dist/utils/__tests__/normalize.spec.js +95 -0
- package/dist/utils/__tests__/normalize.spec.js.map +1 -0
- package/dist/utils/normalize.d.ts +22 -0
- package/dist/utils/normalize.js +51 -0
- package/dist/utils/normalize.js.map +1 -0
- package/dist/v1/__tests__/prepareControlData.spec.d.ts +1 -0
- package/dist/v1/__tests__/prepareControlData.spec.js +48 -0
- package/dist/v1/__tests__/prepareControlData.spec.js.map +1 -0
- package/dist/v1/devices/AC.d.ts +13 -0
- package/dist/v1/devices/AC.js +112 -0
- package/dist/v1/devices/AC.js.map +1 -0
- package/dist/v1/devices/AirPurifier.d.ts +15 -0
- package/dist/v1/devices/AirPurifier.js +57 -0
- package/dist/v1/devices/AirPurifier.js.map +1 -0
- package/dist/v1/devices/RangeHood.d.ts +6 -0
- package/dist/v1/devices/RangeHood.js +12 -0
- package/dist/v1/devices/RangeHood.js.map +1 -0
- package/dist/v1/devices/Refrigerator.d.ts +17 -0
- package/dist/v1/devices/Refrigerator.js +69 -0
- package/dist/v1/devices/Refrigerator.js.map +1 -0
- package/dist/v1/devices/Washer.d.ts +10 -0
- package/dist/v1/devices/Washer.js +23 -0
- package/dist/v1/devices/Washer.js.map +1 -0
- package/dist/v1/devices/index.d.ts +6 -0
- package/dist/v1/devices/index.js +7 -0
- package/dist/v1/devices/index.js.map +1 -0
- package/dist/v1/helper.d.ts +14 -0
- package/dist/v1/helper.js +111 -0
- package/dist/v1/helper.js.map +1 -0
- package/dist/v1/transforms/AirPurifierState.d.ts +2 -0
- package/dist/v1/transforms/AirPurifierState.js +9 -0
- package/dist/v1/transforms/AirPurifierState.js.map +1 -0
- package/dist/v1/transforms/AirState.d.ts +9 -0
- package/dist/v1/transforms/AirState.js +55 -0
- package/dist/v1/transforms/AirState.js.map +1 -0
- package/dist/v1/transforms/HoodState.d.ts +17 -0
- package/dist/v1/transforms/HoodState.js +20 -0
- package/dist/v1/transforms/HoodState.js.map +1 -0
- package/dist/v1/transforms/RefState.d.ts +6 -0
- package/dist/v1/transforms/RefState.js +29 -0
- package/dist/v1/transforms/RefState.js.map +1 -0
- package/dist/v1/transforms/WasherDryer.d.ts +49 -0
- package/dist/v1/transforms/WasherDryer.js +56 -0
- package/dist/v1/transforms/WasherDryer.js.map +1 -0
- package/docs/authorization.md +40 -0
- package/docs/device-configuration.md +68 -0
- package/homebridge-ui/public/index.html +120 -0
- package/homebridge-ui/public/js/app.js +300 -0
- package/homebridge-ui/public/js/countries.js +233 -0
- package/homebridge-ui/public/styles.css +185 -0
- package/homebridge-ui/server.js +103 -0
- package/jest.config.ts +39 -0
- package/package.json +83 -0
- package/sample/README.md +10 -0
- package/sample/airconditioner-model.json +3080 -0
- package/sample/airconditioner-snapshot.json +49 -0
- package/sample/airconditioner.json +157 -0
- package/sample/dishwasher-model.json +869 -0
- package/sample/dishwasher.json +125 -0
- package/sample/washer_dryer-model.json +1294 -0
- package/sample/washer_dryer.json +126 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import NodePersist from 'node-persist';
|
|
2
|
+
import Fs from 'fs/promises';
|
|
3
|
+
import Path from 'path';
|
|
4
|
+
import Crypto from 'crypto';
|
|
5
|
+
/**
|
|
6
|
+
* A utility class for managing persistent storage using `node-persist`.
|
|
7
|
+
* This class provides methods for storing, retrieving, and caching data with optional expiration.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const persist = new Persist('./storage');
|
|
12
|
+
* await persist.init();
|
|
13
|
+
* await persist.setItem('key', 'value');
|
|
14
|
+
* const value = await persist.getItem('key');
|
|
15
|
+
* console.log(value); // Output: 'value'
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export default class Persist {
|
|
19
|
+
/**
|
|
20
|
+
* The `node-persist` instance used for managing storage.
|
|
21
|
+
*/
|
|
22
|
+
persist = null;
|
|
23
|
+
dir;
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new `Persist` instance.
|
|
26
|
+
*
|
|
27
|
+
* @param dir - The directory where the persistent storage files will be stored.
|
|
28
|
+
*/
|
|
29
|
+
constructor(dir) {
|
|
30
|
+
this.dir = Path.resolve(dir || '.');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generates a SHA-256 hash of the given input string.
|
|
34
|
+
*
|
|
35
|
+
* @param input - The input string to hash.
|
|
36
|
+
* @returns The SHA-256 hash of the input string.
|
|
37
|
+
*/
|
|
38
|
+
sha256(input) {
|
|
39
|
+
return Crypto.createHash('sha256').update(input).digest('hex');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Detect and migrate legacy plain JSON files in the storage directory.
|
|
43
|
+
* Legacy files are assumed to be named by the original key (not sha256(key))
|
|
44
|
+
* and contain raw JSON for the value. Migrated files are written as
|
|
45
|
+
* JSON datum { key, value, ttl } into filename sha256(key).
|
|
46
|
+
*/
|
|
47
|
+
async migrateLegacyFiles() {
|
|
48
|
+
try {
|
|
49
|
+
await Fs.mkdir(this.dir, { recursive: true });
|
|
50
|
+
const backupDir = Path.resolve(this.dir, '..', '_backups');
|
|
51
|
+
await Fs.mkdir(backupDir, { recursive: true });
|
|
52
|
+
const files = await Fs.readdir(this.dir).catch(() => []);
|
|
53
|
+
for (const f of files) {
|
|
54
|
+
if (!f || f.startsWith('.')) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const p = Path.join(this.dir, f);
|
|
58
|
+
const stat = await Fs.stat(p).catch(() => null);
|
|
59
|
+
if (!stat || !stat.isFile()) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (/^[a-f0-9]{64}$/.test(f)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const raw = await Fs.readFile(p, { encoding: 'utf8' });
|
|
67
|
+
const parsed = JSON.parse(raw);
|
|
68
|
+
const key = parsed && typeof parsed === 'object' && parsed.key ? parsed.key : f;
|
|
69
|
+
const datum = { key, value: parsed && parsed.key ? parsed.value ?? parsed : parsed, ttl: undefined };
|
|
70
|
+
const target = Path.join(this.dir, this.sha256(key));
|
|
71
|
+
await Fs.writeFile(target, JSON.stringify(datum), { encoding: 'utf8' }).catch(() => { });
|
|
72
|
+
const dest = Path.join(backupDir, `${f}.migrated.${Date.now()}`);
|
|
73
|
+
await Fs.rename(p, dest).catch(async () => {
|
|
74
|
+
await Fs.copyFile(p, dest).catch(() => { });
|
|
75
|
+
await Fs.unlink(p).catch(() => { });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
const dest = Path.join(backupDir, `${f}.corrupt.${Date.now()}`);
|
|
80
|
+
await Fs.rename(p, dest).catch(async () => {
|
|
81
|
+
await Fs.copyFile(p, dest).catch(() => { });
|
|
82
|
+
await Fs.unlink(p).catch(() => { });
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
// ignore migration errors
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Initializes the persistent storage.
|
|
93
|
+
*
|
|
94
|
+
* @returns A promise that resolves when the storage is initialized.
|
|
95
|
+
*/
|
|
96
|
+
async init() {
|
|
97
|
+
await this.migrateLegacyFiles();
|
|
98
|
+
this.persist = this.persist || NodePersist.create({ dir: this.dir });
|
|
99
|
+
const backupDir = Path.resolve(this.dir, '..', '_backups');
|
|
100
|
+
try {
|
|
101
|
+
const res = await this.persist.init();
|
|
102
|
+
await Fs.rm(backupDir, { recursive: true, force: true }).catch(() => { });
|
|
103
|
+
return res;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
try {
|
|
107
|
+
await this.migrateLegacyFiles();
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// ignore migration errors
|
|
111
|
+
}
|
|
112
|
+
const res2 = await this.persist.init();
|
|
113
|
+
await Fs.rm(backupDir, { recursive: true, force: true }).catch(() => { });
|
|
114
|
+
return res2;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Retrieves an item from storage by its key.
|
|
119
|
+
*
|
|
120
|
+
* @param key - The key of the item to retrieve.
|
|
121
|
+
* @returns A promise that resolves with the value of the item, or `null` if the item does not exist.
|
|
122
|
+
*/
|
|
123
|
+
async getItem(key) {
|
|
124
|
+
if (!this.persist) {
|
|
125
|
+
await this.init();
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
return await this.persist.getItem(key);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
try {
|
|
132
|
+
const p = Path.join(this.dir, key);
|
|
133
|
+
const raw = await Fs.readFile(p, { encoding: 'utf8' });
|
|
134
|
+
const parsed = JSON.parse(raw);
|
|
135
|
+
await this.persist.setItem(key, parsed).catch(() => { });
|
|
136
|
+
await Fs.rename(p, p + '.migrated.' + Date.now()).catch(() => { });
|
|
137
|
+
return parsed;
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Stores an item in storage with the specified key and value.
|
|
146
|
+
*
|
|
147
|
+
* @param key - The key to associate with the item.
|
|
148
|
+
* @param value - The value to store.
|
|
149
|
+
* @returns A promise that resolves when the item is stored.
|
|
150
|
+
*/
|
|
151
|
+
async setItem(key, value) {
|
|
152
|
+
if (!this.persist) {
|
|
153
|
+
await this.init();
|
|
154
|
+
}
|
|
155
|
+
return await this.persist.setItem(key, value);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Caches a value indefinitely. If the value does not exist in storage, it is retrieved using the provided callable function.
|
|
159
|
+
*
|
|
160
|
+
* @param key - The key to associate with the cached value.
|
|
161
|
+
* @param callable - A function that returns a promise resolving to the value to cache.
|
|
162
|
+
* @returns A promise that resolves with the cached value.
|
|
163
|
+
*/
|
|
164
|
+
async cacheForever(key, callable) {
|
|
165
|
+
let value = await this.getItem(key);
|
|
166
|
+
if (!value) {
|
|
167
|
+
value = await callable();
|
|
168
|
+
await this.setItem(key, value);
|
|
169
|
+
}
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Caches a value with a time-to-live (TTL). If the value does not exist or is expired, it is retrieved using the provided callable function.
|
|
174
|
+
*
|
|
175
|
+
* @param key - The key to associate with the cached value.
|
|
176
|
+
* @param ttl - The time-to-live for the cached value, in milliseconds.
|
|
177
|
+
* @param callable - A function that returns a promise resolving to the value to cache.
|
|
178
|
+
* @returns A promise that resolves with the cached value.
|
|
179
|
+
*/
|
|
180
|
+
async cache(key, ttl, callable) {
|
|
181
|
+
let value = await this.getWithExpiry(key);
|
|
182
|
+
if (!value) {
|
|
183
|
+
value = await callable();
|
|
184
|
+
await this.setWithExpiry(key, value, ttl);
|
|
185
|
+
}
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Stores an item in storage with an expiration time.
|
|
190
|
+
*
|
|
191
|
+
* @param key - The key to associate with the item.
|
|
192
|
+
* @param value - The value to store.
|
|
193
|
+
* @param ttl - The time-to-live for the item, in milliseconds.
|
|
194
|
+
* @returns A promise that resolves when the item is stored.
|
|
195
|
+
*/
|
|
196
|
+
async setWithExpiry(key, value, ttl) {
|
|
197
|
+
const item = {
|
|
198
|
+
value: value,
|
|
199
|
+
expiry: Date.now() + ttl,
|
|
200
|
+
};
|
|
201
|
+
await this.setItem(key, JSON.stringify(item));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Retrieves an item from storage by its key, considering its expiration time.
|
|
205
|
+
*
|
|
206
|
+
* @param key - The key of the item to retrieve.
|
|
207
|
+
* @returns A promise that resolves with the value of the item, or `null` if the item does not exist or is expired.
|
|
208
|
+
*/
|
|
209
|
+
async getWithExpiry(key) {
|
|
210
|
+
const itemStr = await this.getItem(key);
|
|
211
|
+
if (!itemStr) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const item = JSON.parse(itemStr);
|
|
216
|
+
if (Date.now() > item.expiry) {
|
|
217
|
+
await this.removeItem(key);
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return item.value;
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Removes an item from storage by its key.
|
|
228
|
+
*
|
|
229
|
+
* @param key - The key of the item to remove.
|
|
230
|
+
* @returns A promise that resolves when the item is removed.
|
|
231
|
+
*/
|
|
232
|
+
async removeItem(key) {
|
|
233
|
+
if (!this.persist) {
|
|
234
|
+
await this.init();
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
return await this.persist.removeItem(key);
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
const p = Path.join(this.dir, key);
|
|
241
|
+
await Fs.unlink(p).catch(() => { });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=Persist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Persist.js","sourceRoot":"","sources":["../../src/lib/Persist.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* eslint-disable dot-notation */
|
|
2
|
+
import Persist from './Persist.js';
|
|
3
|
+
import Fs from 'fs/promises';
|
|
4
|
+
import Path from 'path';
|
|
5
|
+
import { describe, test, beforeEach, afterEach, expect, jest } from '@jest/globals';
|
|
6
|
+
describe('Persist', () => {
|
|
7
|
+
let persist;
|
|
8
|
+
const mockDir = './mock-storage';
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
jest.spyOn(Persist.prototype, 'migrateLegacyFiles').mockResolvedValue(undefined);
|
|
11
|
+
persist = new Persist(mockDir);
|
|
12
|
+
await persist.init();
|
|
13
|
+
jest.spyOn(persist['persist'], 'getItem').mockResolvedValue(null);
|
|
14
|
+
jest.spyOn(persist['persist'], 'setItem').mockResolvedValue({ file: '', content: {} });
|
|
15
|
+
jest.spyOn(persist['persist'], 'removeItem').mockResolvedValue({ file: '', removed: true, existed: true });
|
|
16
|
+
});
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
jest.restoreAllMocks();
|
|
19
|
+
await Fs.rm(mockDir, { recursive: true, force: true }).catch(() => { });
|
|
20
|
+
const backupDir = Path.resolve(mockDir, '..', '_backups');
|
|
21
|
+
await Fs.rm(backupDir, { recursive: true, force: true }).catch(() => { });
|
|
22
|
+
});
|
|
23
|
+
test('should initialize storage', async () => {
|
|
24
|
+
const initSpy = jest.spyOn(persist['persist'], 'init').mockResolvedValue({});
|
|
25
|
+
await persist.init();
|
|
26
|
+
expect(initSpy).toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
test('should store and retrieve an item', async () => {
|
|
29
|
+
const key = 'testKey';
|
|
30
|
+
const value = 'testValue';
|
|
31
|
+
await persist.setItem(key, value);
|
|
32
|
+
expect(persist['persist'].setItem).toHaveBeenCalledWith(key, value);
|
|
33
|
+
jest.spyOn(persist['persist'], 'getItem').mockResolvedValue(value);
|
|
34
|
+
const retrievedValue = await persist.getItem(key);
|
|
35
|
+
expect(retrievedValue).toBe(value);
|
|
36
|
+
});
|
|
37
|
+
test('should cache a value indefinitely', async () => {
|
|
38
|
+
const key = 'cacheKey';
|
|
39
|
+
const value = 'cachedValue';
|
|
40
|
+
const callable = jest.fn().mockResolvedValue(value);
|
|
41
|
+
const cachedValue = await persist.cacheForever(key, callable);
|
|
42
|
+
expect(callable).toHaveBeenCalled();
|
|
43
|
+
expect(persist['persist'].setItem).toHaveBeenCalledWith(key, value);
|
|
44
|
+
expect(cachedValue).toBe(value);
|
|
45
|
+
jest.spyOn(persist['persist'], 'getItem').mockResolvedValue(value);
|
|
46
|
+
const retrievedValue = await persist.cacheForever(key, callable);
|
|
47
|
+
expect(callable).toHaveBeenCalledTimes(1); // Callable should not be called again
|
|
48
|
+
expect(retrievedValue).toBe(value);
|
|
49
|
+
});
|
|
50
|
+
test('should cache a value with TTL', async () => {
|
|
51
|
+
const key = 'ttlKey';
|
|
52
|
+
const value = 'ttlValue';
|
|
53
|
+
const ttl = 1000; // 1 second
|
|
54
|
+
const callable = jest.fn().mockResolvedValue(value);
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => now);
|
|
57
|
+
const cachedValue = await persist.cache(key, ttl, callable);
|
|
58
|
+
expect(callable).toHaveBeenCalled();
|
|
59
|
+
expect(persist['persist'].setItem).toHaveBeenCalledWith(key, JSON.stringify({ value, expiry: now + ttl }));
|
|
60
|
+
expect(cachedValue).toBe(value);
|
|
61
|
+
jest.spyOn(persist['persist'], 'getItem').mockResolvedValue(JSON.stringify({ value, expiry: now + ttl }));
|
|
62
|
+
const retrievedValue = await persist.cache(key, ttl, callable);
|
|
63
|
+
expect(callable).toHaveBeenCalledTimes(1); // Callable should not be called again
|
|
64
|
+
expect(retrievedValue).toBe(value);
|
|
65
|
+
});
|
|
66
|
+
test('should return null for expired cached value', async () => {
|
|
67
|
+
const key = 'expiredKey';
|
|
68
|
+
const value = 'expiredValue';
|
|
69
|
+
const ttl = 1000; // 1 second
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => now + ttl + 1);
|
|
72
|
+
jest.spyOn(persist['persist'], 'getItem').mockResolvedValue(JSON.stringify({ value, expiry: now + ttl }));
|
|
73
|
+
const retrievedValue = await persist.getWithExpiry(key);
|
|
74
|
+
expect(retrievedValue).toBeNull();
|
|
75
|
+
expect(persist['persist'].removeItem).toHaveBeenCalledWith(key);
|
|
76
|
+
});
|
|
77
|
+
test('should store and retrieve an item with expiry', async () => {
|
|
78
|
+
const key = 'expiryKey';
|
|
79
|
+
const value = 'expiryValue';
|
|
80
|
+
const ttl = 1000; // 1 second
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
jest.spyOn(global.Date, 'now').mockImplementation(() => now);
|
|
83
|
+
await persist.setWithExpiry(key, value, ttl);
|
|
84
|
+
expect(persist['persist'].setItem).toHaveBeenCalledWith(key, JSON.stringify({ value, expiry: now + ttl }));
|
|
85
|
+
jest.spyOn(persist['persist'], 'getItem').mockResolvedValue(JSON.stringify({ value, expiry: now + ttl }));
|
|
86
|
+
const retrievedValue = await persist.getWithExpiry(key);
|
|
87
|
+
expect(retrievedValue).toBe(value);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=Persist.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Persist.spec.js","sourceRoot":"","sources":["../../src/lib/Persist.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a session for interacting with the LG ThinQ API.
|
|
3
|
+
* This class is responsible for managing authentication tokens and session expiration.
|
|
4
|
+
* It provides methods to check the validity of the session and update its properties.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const session = new Session('accessToken', 'refreshToken', Date.now() + 3600 * 1000);
|
|
9
|
+
* if (session.isValid()) {
|
|
10
|
+
* console.log('Session is valid');
|
|
11
|
+
* } else {
|
|
12
|
+
* console.log('Session has expired');
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare class Session {
|
|
17
|
+
/**
|
|
18
|
+
* The access token used for authenticating API requests.
|
|
19
|
+
*/
|
|
20
|
+
private _accessToken;
|
|
21
|
+
/**
|
|
22
|
+
* The refresh token used to obtain a new access token when the current one expires.
|
|
23
|
+
*/
|
|
24
|
+
private readonly _refreshToken;
|
|
25
|
+
/**
|
|
26
|
+
* The expiration timestamp of the current session, in milliseconds since the Unix epoch.
|
|
27
|
+
*/
|
|
28
|
+
private expiresIn;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new `Session` instance.
|
|
31
|
+
*
|
|
32
|
+
* @param accessToken - The access token for the session.
|
|
33
|
+
* @param refreshToken - The refresh token for the session.
|
|
34
|
+
* @param expiresIn - The expiration timestamp of the session.
|
|
35
|
+
*/
|
|
36
|
+
constructor(accessToken: string, refreshToken: string, expiresIn: number);
|
|
37
|
+
/**
|
|
38
|
+
* Updates the session properties with new values.
|
|
39
|
+
*
|
|
40
|
+
* @param accessToken - The new access token.
|
|
41
|
+
* @param expiresIn - The new expiration timestamp.
|
|
42
|
+
*/
|
|
43
|
+
newToken(accessToken: string, expiresIn: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* Gets the access token.
|
|
46
|
+
*
|
|
47
|
+
* @returns The access token.
|
|
48
|
+
*/
|
|
49
|
+
get accessToken(): string;
|
|
50
|
+
/**
|
|
51
|
+
* Gets the refresh token.
|
|
52
|
+
*
|
|
53
|
+
* @returns The refresh token.
|
|
54
|
+
*/
|
|
55
|
+
get refreshToken(): string;
|
|
56
|
+
/**
|
|
57
|
+
* Checks if the session has an access token.
|
|
58
|
+
*
|
|
59
|
+
* @returns `true` if the session has an access token, otherwise `false`.
|
|
60
|
+
*/
|
|
61
|
+
hasToken(): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Checks if the access token is expired.
|
|
64
|
+
*
|
|
65
|
+
* @returns `true` if the access token is expired, otherwise `false`.
|
|
66
|
+
*/
|
|
67
|
+
isTokenExpired(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Checks if the session has a valid access token.
|
|
70
|
+
*
|
|
71
|
+
* @returns `true` if the session has a valid access token, otherwise `false`.
|
|
72
|
+
*/
|
|
73
|
+
hasValidToken(): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Gets the current epoch time in seconds.
|
|
76
|
+
*
|
|
77
|
+
* @returns The current epoch time in seconds.
|
|
78
|
+
*/
|
|
79
|
+
private static getCurrentEpoch;
|
|
80
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a session for interacting with the LG ThinQ API.
|
|
3
|
+
* This class is responsible for managing authentication tokens and session expiration.
|
|
4
|
+
* It provides methods to check the validity of the session and update its properties.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const session = new Session('accessToken', 'refreshToken', Date.now() + 3600 * 1000);
|
|
9
|
+
* if (session.isValid()) {
|
|
10
|
+
* console.log('Session is valid');
|
|
11
|
+
* } else {
|
|
12
|
+
* console.log('Session has expired');
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export class Session {
|
|
17
|
+
/**
|
|
18
|
+
* The access token used for authenticating API requests.
|
|
19
|
+
*/
|
|
20
|
+
_accessToken;
|
|
21
|
+
/**
|
|
22
|
+
* The refresh token used to obtain a new access token when the current one expires.
|
|
23
|
+
*/
|
|
24
|
+
_refreshToken;
|
|
25
|
+
/**
|
|
26
|
+
* The expiration timestamp of the current session, in milliseconds since the Unix epoch.
|
|
27
|
+
*/
|
|
28
|
+
expiresIn;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a new `Session` instance.
|
|
31
|
+
*
|
|
32
|
+
* @param accessToken - The access token for the session.
|
|
33
|
+
* @param refreshToken - The refresh token for the session.
|
|
34
|
+
* @param expiresIn - The expiration timestamp of the session.
|
|
35
|
+
*/
|
|
36
|
+
constructor(accessToken, refreshToken, expiresIn) {
|
|
37
|
+
this._refreshToken = refreshToken;
|
|
38
|
+
this._accessToken = accessToken;
|
|
39
|
+
this.expiresIn = expiresIn;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Updates the session properties with new values.
|
|
43
|
+
*
|
|
44
|
+
* @param accessToken - The new access token.
|
|
45
|
+
* @param expiresIn - The new expiration timestamp.
|
|
46
|
+
*/
|
|
47
|
+
newToken(accessToken, expiresIn) {
|
|
48
|
+
this._accessToken = accessToken;
|
|
49
|
+
this.expiresIn = expiresIn;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Gets the access token.
|
|
53
|
+
*
|
|
54
|
+
* @returns The access token.
|
|
55
|
+
*/
|
|
56
|
+
get accessToken() {
|
|
57
|
+
return this._accessToken;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Gets the refresh token.
|
|
61
|
+
*
|
|
62
|
+
* @returns The refresh token.
|
|
63
|
+
*/
|
|
64
|
+
get refreshToken() {
|
|
65
|
+
return this._refreshToken;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Checks if the session has an access token.
|
|
69
|
+
*
|
|
70
|
+
* @returns `true` if the session has an access token, otherwise `false`.
|
|
71
|
+
*/
|
|
72
|
+
hasToken() {
|
|
73
|
+
return !!this._accessToken;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Checks if the access token is expired.
|
|
77
|
+
*
|
|
78
|
+
* @returns `true` if the access token is expired, otherwise `false`.
|
|
79
|
+
*/
|
|
80
|
+
isTokenExpired() {
|
|
81
|
+
return this.expiresIn < Session.getCurrentEpoch();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Checks if the session has a valid access token.
|
|
85
|
+
*
|
|
86
|
+
* @returns `true` if the session has a valid access token, otherwise `false`.
|
|
87
|
+
*/
|
|
88
|
+
hasValidToken() {
|
|
89
|
+
return this.hasToken() && !this.isTokenExpired();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Gets the current epoch time in seconds.
|
|
93
|
+
*
|
|
94
|
+
* @returns The current epoch time in seconds.
|
|
95
|
+
*/
|
|
96
|
+
static getCurrentEpoch() {
|
|
97
|
+
return Math.round(new Date().getTime() / 1000);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=Session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Session.js","sourceRoot":"","sources":["../../src/lib/Session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,OAAO;IAElB;;OAEG;IACK,YAAY,CAAS;IAE7B;;OAEG;IACc,aAAa,CAAS;IAEvC;;OAEG;IACK,SAAS,CAAS;IAE1B;;;;;;OAMG;IACH,YACE,WAAmB,EACnB,YAAoB,EACpB,SAAiB;QAEjB,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;QAClC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;;;OAKG;IACI,QAAQ,CAAC,WAAmB,EAAE,SAAiB;QACpD,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,IAAW,YAAY;QACrB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACI,QAAQ;QACb,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACI,cAAc;QACnB,OAAO,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IACpD,CAAC;IAED;;;;OAIG;IACI,aAAa;QAClB,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACK,MAAM,CAAC,eAAe;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACjD,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* eslint-disable dot-notation */
|
|
2
|
+
import { describe, beforeEach, test, expect } from '@jest/globals';
|
|
3
|
+
import { Session } from '../../src/lib/Session.js';
|
|
4
|
+
describe('Session', () => {
|
|
5
|
+
let session;
|
|
6
|
+
const accessToken = 'testAccessToken';
|
|
7
|
+
const refreshToken = 'testRefreshToken';
|
|
8
|
+
const validExpiresIn = Math.round(Date.now() / 1000) + 3600; // 1 hour from now
|
|
9
|
+
const expiredExpiresIn = Math.round(Date.now() / 1000) - 3600; // 1 hour ago
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
session = new Session(accessToken, refreshToken, validExpiresIn);
|
|
12
|
+
});
|
|
13
|
+
test('should initialize with correct values', () => {
|
|
14
|
+
expect(session.accessToken).toBe(accessToken);
|
|
15
|
+
expect(session.refreshToken).toBe(refreshToken);
|
|
16
|
+
expect(session.hasToken()).toBe(true);
|
|
17
|
+
expect(session.isTokenExpired()).toBe(false);
|
|
18
|
+
expect(session.hasValidToken()).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
test('should detect expired token', () => {
|
|
21
|
+
const expiredSession = new Session(accessToken, refreshToken, expiredExpiresIn);
|
|
22
|
+
expect(expiredSession.isTokenExpired()).toBe(true);
|
|
23
|
+
expect(expiredSession.hasValidToken()).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
test('should update token and expiration', () => {
|
|
26
|
+
const newAccessToken = 'newAccessToken';
|
|
27
|
+
const newExpiresIn = Math.round(Date.now() / 1000) + 7200; // 2 hours from now
|
|
28
|
+
session.newToken(newAccessToken, newExpiresIn);
|
|
29
|
+
expect(session.accessToken).toBe(newAccessToken);
|
|
30
|
+
expect(session.isTokenExpired()).toBe(false);
|
|
31
|
+
expect(session.hasValidToken()).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
test('should return false for hasToken when access token is empty', () => {
|
|
34
|
+
const emptyTokenSession = new Session('', refreshToken, validExpiresIn);
|
|
35
|
+
expect(emptyTokenSession.hasToken()).toBe(false);
|
|
36
|
+
expect(emptyTokenSession.hasValidToken()).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
test('should correctly handle static getCurrentEpoch', () => {
|
|
39
|
+
const currentEpoch = Math.round(Date.now() / 1000);
|
|
40
|
+
expect(Session['getCurrentEpoch']()).toBeCloseTo(currentEpoch, -1); // Allow slight time difference
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=Session.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Session.spec.js","sourceRoot":"","sources":["../../src/lib/Session.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Logger, PlatformConfig } from 'homebridge';
|
|
2
|
+
import { API } from './API.js';
|
|
3
|
+
import { LGThinQHomebridgePlatform } from '../platform.js';
|
|
4
|
+
import { Device } from './Device.js';
|
|
5
|
+
import { DeviceModel } from './DeviceModel.js';
|
|
6
|
+
import Persist from './Persist.js';
|
|
7
|
+
export type WorkId = string;
|
|
8
|
+
export declare class ThinQ {
|
|
9
|
+
readonly platform: LGThinQHomebridgePlatform;
|
|
10
|
+
readonly config: PlatformConfig;
|
|
11
|
+
readonly logger: Logger;
|
|
12
|
+
protected api: API;
|
|
13
|
+
protected workIds: Record<string, WorkId | null>;
|
|
14
|
+
protected deviceModel: Record<string, DeviceModel>;
|
|
15
|
+
protected persist: Persist;
|
|
16
|
+
constructor(platform: LGThinQHomebridgePlatform, config: PlatformConfig, logger: Logger);
|
|
17
|
+
devices(): Promise<Device[]>;
|
|
18
|
+
setup(device: Device): Promise<boolean>;
|
|
19
|
+
unregister(device: Device): Promise<void>;
|
|
20
|
+
protected registerWorkId(device: any): Promise<any>;
|
|
21
|
+
protected loadDeviceModel(device: Device): Promise<DeviceModel>;
|
|
22
|
+
pollMonitor(device: Device): Promise<Device>;
|
|
23
|
+
thinq1DeviceControl(device: Device, key: string, value: any): Promise<any>;
|
|
24
|
+
deviceControl(device: string | Device, values: Record<string, any>, command?: 'Set' | 'Operation', ctrlKey?: string, ctrlPath?: string): Promise<boolean>;
|
|
25
|
+
registerMQTTListener(callback: (data: any) => void): Promise<void>;
|
|
26
|
+
protected _registerMQTTListener(callback: (data: any) => void): Promise<void>;
|
|
27
|
+
isReady(): Promise<void>;
|
|
28
|
+
}
|