@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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { DeviceModel } from '../DeviceModel.js';
|
|
2
|
+
import { describe, test, beforeEach, expect } from '@jest/globals';
|
|
3
|
+
import Fs from 'fs';
|
|
4
|
+
import Path from 'path';
|
|
5
|
+
const mockModelDataJson = JSON.parse(Fs.readFileSync(Path.resolve(process.cwd(), 'sample/airconditioner-model.json'), 'utf8'));
|
|
6
|
+
describe('DeviceModel', () => {
|
|
7
|
+
let deviceModel;
|
|
8
|
+
const mockModelData = mockModelDataJson;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
deviceModel = new DeviceModel(mockModelData);
|
|
11
|
+
});
|
|
12
|
+
test('should retrieve monitoring values', () => {
|
|
13
|
+
const monitoringValues = deviceModel.monitoringValue;
|
|
14
|
+
expect(monitoringValues).toEqual(mockModelData.MonitoringValue);
|
|
15
|
+
});
|
|
16
|
+
test('should retrieve value definition for a given key', () => {
|
|
17
|
+
const value = deviceModel.value('temperature');
|
|
18
|
+
expect(value).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
test('should return null for undefined value key', () => {
|
|
21
|
+
const value = deviceModel.value('undefinedKey');
|
|
22
|
+
expect(value).toBeNull();
|
|
23
|
+
});
|
|
24
|
+
test('should retrieve default value for a given key', () => {
|
|
25
|
+
const mockModelDataWithDefault = {
|
|
26
|
+
...mockModelData,
|
|
27
|
+
Value: {
|
|
28
|
+
...mockModelData.Value,
|
|
29
|
+
temperature: {
|
|
30
|
+
...mockModelData.Value.temperature,
|
|
31
|
+
default: 350,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
deviceModel = new DeviceModel(mockModelDataWithDefault);
|
|
36
|
+
const defaultValue = deviceModel.default('temperature');
|
|
37
|
+
expect(defaultValue).toBe(350);
|
|
38
|
+
});
|
|
39
|
+
test('should retrieve enum value for a given key and name', () => {
|
|
40
|
+
const enumValue = deviceModel.enumValue('mode', 'Bake');
|
|
41
|
+
expect(enumValue).toBeDefined();
|
|
42
|
+
});
|
|
43
|
+
test('should return null for invalid enum key or name', () => {
|
|
44
|
+
const invalidEnumValue = deviceModel.enumValue('mode', 'Invalid');
|
|
45
|
+
expect(invalidEnumValue).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
test('should retrieve enum name for a given key and value', () => {
|
|
48
|
+
const enumName = deviceModel.enumName('mode', 'bake');
|
|
49
|
+
expect(enumName).toBeDefined();
|
|
50
|
+
});
|
|
51
|
+
test('should return null for invalid enum key or value', () => {
|
|
52
|
+
const invalidEnumName = deviceModel.enumName('mode', 'invalid');
|
|
53
|
+
expect(invalidEnumName).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
test('should retrieve monitoring value mapping for a given key', () => {
|
|
56
|
+
const mapping = deviceModel.monitoringValueMapping('door');
|
|
57
|
+
expect(mapping).toBeDefined();
|
|
58
|
+
});
|
|
59
|
+
test('should return null for invalid monitoring value key', () => {
|
|
60
|
+
const invalidMapping = deviceModel.monitoringValueMapping('invalidKey');
|
|
61
|
+
expect(invalidMapping).toBeNull();
|
|
62
|
+
});
|
|
63
|
+
test('should lookup monitor value by key and name', () => {
|
|
64
|
+
const label = deviceModel.lookupMonitorValue('door', 'open');
|
|
65
|
+
expect(label).toBeDefined();
|
|
66
|
+
});
|
|
67
|
+
test('should return default value for invalid monitor value lookup', () => {
|
|
68
|
+
const defaultValue = deviceModel.lookupMonitorValue2('door', 'invalid', 'Default');
|
|
69
|
+
expect(defaultValue).toBe('Default');
|
|
70
|
+
});
|
|
71
|
+
test('should lookup monitor name by key and label', () => {
|
|
72
|
+
const name = deviceModel.lookupMonitorName('door', 'Open');
|
|
73
|
+
expect(name).toBeDefined();
|
|
74
|
+
});
|
|
75
|
+
test('should return null for invalid monitor name lookup', () => {
|
|
76
|
+
const invalidName = deviceModel.lookupMonitorName('door', 'Invalid');
|
|
77
|
+
expect(invalidName).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
test('should decode monitoring data as JSON', () => {
|
|
80
|
+
const rawData = '{"key":"value"}';
|
|
81
|
+
const decodedData = deviceModel.decodeMonitor(rawData);
|
|
82
|
+
expect(decodedData).toEqual({ key: 'value' });
|
|
83
|
+
});
|
|
84
|
+
test('should return raw data if JSON decoding fails', () => {
|
|
85
|
+
const rawData = 'invalidJSON';
|
|
86
|
+
const decodedData = deviceModel.decodeMonitor(rawData);
|
|
87
|
+
expect(decodedData).toBe(rawData);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=DeviceModel.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceModel.spec.js","sourceRoot":"","sources":["../../../src/lib/__tests__/DeviceModel.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Gateway } from '../Gateway.js';
|
|
2
|
+
import { describe, test, expect, beforeEach } from '@jest/globals';
|
|
3
|
+
describe('Gateway', () => {
|
|
4
|
+
const mockData = {
|
|
5
|
+
empTermsUri: 'https://example.com/terms',
|
|
6
|
+
empSpxUri: 'https://example.com/login',
|
|
7
|
+
thinq2Uri: 'https://example.com/thinq2',
|
|
8
|
+
thinq1Uri: 'https://example.com/thinq1',
|
|
9
|
+
countryCode: 'US',
|
|
10
|
+
languageCode: 'en-US',
|
|
11
|
+
};
|
|
12
|
+
let gateway;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
gateway = new Gateway(mockData);
|
|
15
|
+
});
|
|
16
|
+
test('should return the correct emp_base_url', () => {
|
|
17
|
+
expect(gateway.emp_base_url).toBe('https://example.com/terms/');
|
|
18
|
+
});
|
|
19
|
+
test('should return the correct login_base_url', () => {
|
|
20
|
+
expect(gateway.login_base_url).toBe('https://example.com/login/');
|
|
21
|
+
});
|
|
22
|
+
test('should return the correct thinq2_url', () => {
|
|
23
|
+
expect(gateway.thinq2_url).toBe('https://example.com/thinq2/');
|
|
24
|
+
});
|
|
25
|
+
test('should return the correct thinq1_url', () => {
|
|
26
|
+
expect(gateway.thinq1_url).toBe('https://example.com/thinq1/');
|
|
27
|
+
});
|
|
28
|
+
test('should return the correct country_code', () => {
|
|
29
|
+
expect(gateway.country_code).toBe('US');
|
|
30
|
+
});
|
|
31
|
+
test('should return the correct language_code', () => {
|
|
32
|
+
expect(gateway.language_code).toBe('en-US');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=Gateway.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Gateway.spec.js","sourceRoot":"","sources":["../../../src/lib/__tests__/Gateway.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEnE,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,MAAM,QAAQ,GAAgB;QAC5B,WAAW,EAAE,2BAA2B;QACxC,SAAS,EAAE,2BAA2B;QACtC,SAAS,EAAE,4BAA4B;QACvC,SAAS,EAAE,4BAA4B;QACvC,WAAW,EAAE,IAAI;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IAEF,IAAI,OAAgB,CAAC;IAErB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -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/__tests__/Persist.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 '../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/__tests__/Session.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export declare const GATEWAY_URL = "https://route.lgthinq.com:46030/v1/service/application/gateway-uri";
|
|
2
|
+
export declare const SVC_CODE = "SVC202";
|
|
3
|
+
export declare const CLIENT_ID = "LGAO221A02";
|
|
4
|
+
export declare const OAUTH_SECRET_KEY = "c053c2a6ddeb7ad97cb0eed0dcb31cf8";
|
|
5
|
+
export declare const OAUTH_CLIENT_KEY = "LGAO722A02";
|
|
6
|
+
export declare const API_KEY = "VGhpblEyLjAgU0VSVklDRQ==";
|
|
7
|
+
export declare const API_CLIENT_ID = "c713ea8e50f657534ff8b9d373dfebfc2ed70b88285c26b8ade49868c0b164d9";
|
|
8
|
+
export declare const APPLICATION_KEY = "6V1V8H2BN5P9ZQGOI5DAQ92YZBDO3EK9";
|
|
9
|
+
export declare enum PlatformType {
|
|
10
|
+
ThinQ1 = "thinq1",
|
|
11
|
+
ThinQ2 = "thinq2"
|
|
12
|
+
}
|
|
13
|
+
export declare enum DeviceType {
|
|
14
|
+
REFRIGERATOR = 101,
|
|
15
|
+
KIMCHI_REFRIGERATOR = 102,
|
|
16
|
+
WATER_PURIFIER = 103,
|
|
17
|
+
WASHER = 201,
|
|
18
|
+
WASHER_NEW = 221,
|
|
19
|
+
WASH_TOWER = 222,
|
|
20
|
+
WASH_TOWER_2 = 223,
|
|
21
|
+
DRYER = 202,
|
|
22
|
+
STYLER = 203,
|
|
23
|
+
DISHWASHER = 204,
|
|
24
|
+
OVEN = 301,
|
|
25
|
+
MICROWAVE = 302,
|
|
26
|
+
COOKTOP = 303,
|
|
27
|
+
HOOD = 304,
|
|
28
|
+
AC = 401,// Includes heat pumps, etc., possibly all HVAC devices.
|
|
29
|
+
AIR_PURIFIER = 402,
|
|
30
|
+
DEHUMIDIFIER = 403,
|
|
31
|
+
ROBOT_KING = 501,// This is Robotic vacuum cleaner
|
|
32
|
+
TV = 701,
|
|
33
|
+
BOILER = 801,
|
|
34
|
+
SPEAKER = 901,
|
|
35
|
+
HOMEVU = 902,
|
|
36
|
+
ARCH = 1001,
|
|
37
|
+
MISSG = 3001,
|
|
38
|
+
SENSOR = 3002,
|
|
39
|
+
SOLAR_SENSOR = 3102,
|
|
40
|
+
IOT_LIGHTING = 3003,
|
|
41
|
+
IOT_MOTION_SENSOR = 3004,
|
|
42
|
+
IOT_SMART_PLUG = 3005,
|
|
43
|
+
IOT_DUST_SENSOR = 3006,
|
|
44
|
+
EMS_AIR_STATION = 4001,
|
|
45
|
+
AIR_SENSOR = 4003,
|
|
46
|
+
PURICARE_AIR_DETECTOR = 4004,
|
|
47
|
+
V2PHONE = 6001,
|
|
48
|
+
HOMEROBOT = 9000,
|
|
49
|
+
AERO_TOWER = 410
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Device state constants
|
|
53
|
+
*/
|
|
54
|
+
export declare const WASHER_NOT_RUNNING_STATUS: string[];
|
|
55
|
+
export declare const STYLER_NOT_RUNNING_STATUS: string[];
|
|
56
|
+
/**
|
|
57
|
+
* Model-specific feature lists for AirConditioner
|
|
58
|
+
*/
|
|
59
|
+
export declare const AC_MODEL_FEATURES: {
|
|
60
|
+
jetMode: string[];
|
|
61
|
+
quietMode: string[];
|
|
62
|
+
energySaveMode: string[];
|
|
63
|
+
/** Models that do NOT support the airState.mon.timeout command */
|
|
64
|
+
noMonitorTimeout: string[];
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Time constants in seconds
|
|
68
|
+
*/
|
|
69
|
+
export declare const ONE_DAY_IN_SECONDS = 86400;
|
|
70
|
+
export declare const TWELVE_HOURS_IN_SECONDS: number;
|
|
71
|
+
export declare const SIX_HOURS_IN_SECONDS: number;
|
|
72
|
+
export declare const ONE_HOUR_IN_SECONDS = 3600;
|
|
73
|
+
export declare const THIRTY_MINUTES_IN_SECONDS = 1800;
|
|
74
|
+
/**
|
|
75
|
+
* Time constants in milliseconds
|
|
76
|
+
*/
|
|
77
|
+
export declare const REQUEST_TIMEOUT_MS = 60000;
|
|
78
|
+
export declare const RETRY_DELAY_MS = 2000;
|
|
79
|
+
export declare const MQTT_RETRY_DELAY_MS = 5000;
|
|
80
|
+
export declare const SHORT_POLL_INTERVAL_MS = 10000;
|
|
81
|
+
export declare const DEVICE_DISCOVERY_DELAY_MS = 30000;
|
|
82
|
+
export declare const TEN_MINUTES_MS = 600000;
|
|
83
|
+
export declare const SIX_MINUTES_MS = 360000;
|
|
84
|
+
export declare const TWO_MINUTES_MS = 120000;
|
|
85
|
+
export declare const ONE_MINUTE_MS = 60000;
|
|
86
|
+
export declare const TEN_SECONDS_MS = 10000;
|
|
87
|
+
export declare const ONE_POINT_FIVE_SECONDS_MS = 1500;
|
|
88
|
+
export declare const ONE_SECOND_MS = 1000;
|
|
89
|
+
export declare const HUNDRED_MS = 100;
|
|
90
|
+
export declare const ONE_HOUR_MS = 3600000;
|
|
91
|
+
export declare const DISHWASHER_STANDBY_INTERVAL_MS = 902500;
|
|
92
|
+
/**
|
|
93
|
+
* Filter maintenance thresholds
|
|
94
|
+
*/
|
|
95
|
+
export declare const FILTER_CHANGE_THRESHOLD_PERCENT = 95;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export const GATEWAY_URL = 'https://route.lgthinq.com:46030/v1/service/application/gateway-uri';
|
|
2
|
+
export const SVC_CODE = 'SVC202';
|
|
3
|
+
export const CLIENT_ID = 'LGAO221A02';
|
|
4
|
+
export const OAUTH_SECRET_KEY = 'c053c2a6ddeb7ad97cb0eed0dcb31cf8';
|
|
5
|
+
export const OAUTH_CLIENT_KEY = 'LGAO722A02';
|
|
6
|
+
export const API_KEY = 'VGhpblEyLjAgU0VSVklDRQ==';
|
|
7
|
+
export const API_CLIENT_ID = 'c713ea8e50f657534ff8b9d373dfebfc2ed70b88285c26b8ade49868c0b164d9';
|
|
8
|
+
export const APPLICATION_KEY = '6V1V8H2BN5P9ZQGOI5DAQ92YZBDO3EK9'; // for spx login
|
|
9
|
+
export var PlatformType;
|
|
10
|
+
(function (PlatformType) {
|
|
11
|
+
PlatformType["ThinQ1"] = "thinq1";
|
|
12
|
+
PlatformType["ThinQ2"] = "thinq2";
|
|
13
|
+
})(PlatformType || (PlatformType = {}));
|
|
14
|
+
export var DeviceType;
|
|
15
|
+
(function (DeviceType) {
|
|
16
|
+
DeviceType[DeviceType["REFRIGERATOR"] = 101] = "REFRIGERATOR";
|
|
17
|
+
DeviceType[DeviceType["KIMCHI_REFRIGERATOR"] = 102] = "KIMCHI_REFRIGERATOR";
|
|
18
|
+
DeviceType[DeviceType["WATER_PURIFIER"] = 103] = "WATER_PURIFIER";
|
|
19
|
+
DeviceType[DeviceType["WASHER"] = 201] = "WASHER";
|
|
20
|
+
DeviceType[DeviceType["WASHER_NEW"] = 221] = "WASHER_NEW";
|
|
21
|
+
DeviceType[DeviceType["WASH_TOWER"] = 222] = "WASH_TOWER";
|
|
22
|
+
DeviceType[DeviceType["WASH_TOWER_2"] = 223] = "WASH_TOWER_2";
|
|
23
|
+
DeviceType[DeviceType["DRYER"] = 202] = "DRYER";
|
|
24
|
+
DeviceType[DeviceType["STYLER"] = 203] = "STYLER";
|
|
25
|
+
DeviceType[DeviceType["DISHWASHER"] = 204] = "DISHWASHER";
|
|
26
|
+
DeviceType[DeviceType["OVEN"] = 301] = "OVEN";
|
|
27
|
+
DeviceType[DeviceType["MICROWAVE"] = 302] = "MICROWAVE";
|
|
28
|
+
DeviceType[DeviceType["COOKTOP"] = 303] = "COOKTOP";
|
|
29
|
+
DeviceType[DeviceType["HOOD"] = 304] = "HOOD";
|
|
30
|
+
DeviceType[DeviceType["AC"] = 401] = "AC";
|
|
31
|
+
DeviceType[DeviceType["AIR_PURIFIER"] = 402] = "AIR_PURIFIER";
|
|
32
|
+
DeviceType[DeviceType["DEHUMIDIFIER"] = 403] = "DEHUMIDIFIER";
|
|
33
|
+
DeviceType[DeviceType["ROBOT_KING"] = 501] = "ROBOT_KING";
|
|
34
|
+
DeviceType[DeviceType["TV"] = 701] = "TV";
|
|
35
|
+
DeviceType[DeviceType["BOILER"] = 801] = "BOILER";
|
|
36
|
+
DeviceType[DeviceType["SPEAKER"] = 901] = "SPEAKER";
|
|
37
|
+
DeviceType[DeviceType["HOMEVU"] = 902] = "HOMEVU";
|
|
38
|
+
DeviceType[DeviceType["ARCH"] = 1001] = "ARCH";
|
|
39
|
+
DeviceType[DeviceType["MISSG"] = 3001] = "MISSG";
|
|
40
|
+
DeviceType[DeviceType["SENSOR"] = 3002] = "SENSOR";
|
|
41
|
+
DeviceType[DeviceType["SOLAR_SENSOR"] = 3102] = "SOLAR_SENSOR";
|
|
42
|
+
DeviceType[DeviceType["IOT_LIGHTING"] = 3003] = "IOT_LIGHTING";
|
|
43
|
+
DeviceType[DeviceType["IOT_MOTION_SENSOR"] = 3004] = "IOT_MOTION_SENSOR";
|
|
44
|
+
DeviceType[DeviceType["IOT_SMART_PLUG"] = 3005] = "IOT_SMART_PLUG";
|
|
45
|
+
DeviceType[DeviceType["IOT_DUST_SENSOR"] = 3006] = "IOT_DUST_SENSOR";
|
|
46
|
+
DeviceType[DeviceType["EMS_AIR_STATION"] = 4001] = "EMS_AIR_STATION";
|
|
47
|
+
DeviceType[DeviceType["AIR_SENSOR"] = 4003] = "AIR_SENSOR";
|
|
48
|
+
DeviceType[DeviceType["PURICARE_AIR_DETECTOR"] = 4004] = "PURICARE_AIR_DETECTOR";
|
|
49
|
+
DeviceType[DeviceType["V2PHONE"] = 6001] = "V2PHONE";
|
|
50
|
+
DeviceType[DeviceType["HOMEROBOT"] = 9000] = "HOMEROBOT";
|
|
51
|
+
DeviceType[DeviceType["AERO_TOWER"] = 410] = "AERO_TOWER";
|
|
52
|
+
})(DeviceType || (DeviceType = {}));
|
|
53
|
+
/**
|
|
54
|
+
* Device state constants
|
|
55
|
+
*/
|
|
56
|
+
// States that indicate the washer/dryer is not actively running
|
|
57
|
+
export const WASHER_NOT_RUNNING_STATUS = [
|
|
58
|
+
'COOLDOWN', 'POWEROFF', 'POWERFAIL', 'INITIAL', 'PAUSE', 'AUDIBLE_DIAGNOSIS',
|
|
59
|
+
'FIRMWARE', 'COURSE_DOWNLOAD', 'ERROR', 'END',
|
|
60
|
+
];
|
|
61
|
+
// States that indicate the styler is not actively running
|
|
62
|
+
export const STYLER_NOT_RUNNING_STATUS = [
|
|
63
|
+
'POWEROFF', 'INITIAL', 'PAUSE', 'COMPLETE', 'ERROR', 'DIAGNOSIS',
|
|
64
|
+
'RESERVED', 'SLEEP', 'FOTA',
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* Model-specific feature lists for AirConditioner
|
|
68
|
+
*/
|
|
69
|
+
export const AC_MODEL_FEATURES = {
|
|
70
|
+
jetMode: ['RAC_056905'],
|
|
71
|
+
quietMode: ['WINF_056905'],
|
|
72
|
+
energySaveMode: ['WINF_056905', 'RAC_056905'],
|
|
73
|
+
/** Models that do NOT support the airState.mon.timeout command */
|
|
74
|
+
noMonitorTimeout: ['RAC_056905'],
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Time constants in seconds
|
|
78
|
+
*/
|
|
79
|
+
export const ONE_DAY_IN_SECONDS = 86400;
|
|
80
|
+
export const TWELVE_HOURS_IN_SECONDS = ONE_DAY_IN_SECONDS / 2;
|
|
81
|
+
export const SIX_HOURS_IN_SECONDS = ONE_DAY_IN_SECONDS / 4;
|
|
82
|
+
export const ONE_HOUR_IN_SECONDS = 3600;
|
|
83
|
+
export const THIRTY_MINUTES_IN_SECONDS = 1800;
|
|
84
|
+
/**
|
|
85
|
+
* Time constants in milliseconds
|
|
86
|
+
*/
|
|
87
|
+
export const REQUEST_TIMEOUT_MS = 60000;
|
|
88
|
+
export const RETRY_DELAY_MS = 2000;
|
|
89
|
+
export const MQTT_RETRY_DELAY_MS = 5000;
|
|
90
|
+
export const SHORT_POLL_INTERVAL_MS = 10000;
|
|
91
|
+
export const DEVICE_DISCOVERY_DELAY_MS = 30000;
|
|
92
|
+
export const TEN_MINUTES_MS = 600000;
|
|
93
|
+
export const SIX_MINUTES_MS = 360000;
|
|
94
|
+
export const TWO_MINUTES_MS = 120000;
|
|
95
|
+
export const ONE_MINUTE_MS = 60000;
|
|
96
|
+
export const TEN_SECONDS_MS = 10000;
|
|
97
|
+
export const ONE_POINT_FIVE_SECONDS_MS = 1500;
|
|
98
|
+
export const ONE_SECOND_MS = 1000;
|
|
99
|
+
export const HUNDRED_MS = 100;
|
|
100
|
+
export const ONE_HOUR_MS = 3600000;
|
|
101
|
+
export const DISHWASHER_STANDBY_INTERVAL_MS = 902500; // ~15 minutes
|
|
102
|
+
/**
|
|
103
|
+
* Filter maintenance thresholds
|
|
104
|
+
*/
|
|
105
|
+
export const FILTER_CHANGE_THRESHOLD_PERCENT = 95;
|
|
106
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { ManualProcessNeeded, ManualProcessNeededErrorCode, MonitorError, NotConnectedError, TokenExpiredErrorCode, TokenExpiredError, NotConnectedErrorCodes, } from '../errors/index.js';
|
|
3
|
+
import axiosRetry from 'axios-retry';
|
|
4
|
+
import { REQUEST_TIMEOUT_MS, RETRY_DELAY_MS } from './constants.js';
|
|
5
|
+
const MAX_REQUESTS_COUNT = 1;
|
|
6
|
+
const INTERVAL_MS = 10;
|
|
7
|
+
let PENDING_REQUESTS = 0;
|
|
8
|
+
const client = axios.create();
|
|
9
|
+
client.defaults.timeout = REQUEST_TIMEOUT_MS;
|
|
10
|
+
axiosRetry(client, {
|
|
11
|
+
retries: 2, // try 3 times
|
|
12
|
+
retryDelay: (retryCount) => {
|
|
13
|
+
return retryCount * RETRY_DELAY_MS;
|
|
14
|
+
},
|
|
15
|
+
retryCondition: (err) => {
|
|
16
|
+
if (err.code?.indexOf('ECONN') === 0) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return err.response !== undefined && [500, 501, 502, 503, 504].includes(err.response.status);
|
|
20
|
+
},
|
|
21
|
+
shouldResetTimeout: true, // reset timeout each retries
|
|
22
|
+
});
|
|
23
|
+
client.interceptors.request.use((config) => {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const interval = setInterval(() => {
|
|
26
|
+
if (PENDING_REQUESTS < MAX_REQUESTS_COUNT) {
|
|
27
|
+
PENDING_REQUESTS++;
|
|
28
|
+
clearInterval(interval);
|
|
29
|
+
resolve(config);
|
|
30
|
+
}
|
|
31
|
+
}, INTERVAL_MS);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
client.interceptors.response.use((response) => {
|
|
35
|
+
// thinq1 response
|
|
36
|
+
if (typeof response.data === 'object' && 'lgedmRoot' in response.data && 'returnCd' in response.data.lgedmRoot) {
|
|
37
|
+
const data = response.data.lgedmRoot;
|
|
38
|
+
const code = data.returnCd;
|
|
39
|
+
if (NotConnectedErrorCodes.includes(code)) {
|
|
40
|
+
throw new NotConnectedError(data.returnMsg || '');
|
|
41
|
+
}
|
|
42
|
+
else if (code === TokenExpiredErrorCode) {
|
|
43
|
+
throw new TokenExpiredError(data.returnMsg);
|
|
44
|
+
}
|
|
45
|
+
else if (code !== '0000') {
|
|
46
|
+
throw new MonitorError(code + ' - ' + data.returnMsg || '');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
PENDING_REQUESTS = Math.max(0, PENDING_REQUESTS - 1);
|
|
50
|
+
return Promise.resolve(response);
|
|
51
|
+
}, (err) => {
|
|
52
|
+
if (!err.response || err.response.data?.resultCode === '9999') {
|
|
53
|
+
throw new NotConnectedError();
|
|
54
|
+
}
|
|
55
|
+
else if (err.response.data?.resultCode === TokenExpiredErrorCode) {
|
|
56
|
+
throw new TokenExpiredError();
|
|
57
|
+
}
|
|
58
|
+
else if (err.response.data?.resultCode === ManualProcessNeededErrorCode) {
|
|
59
|
+
throw new ManualProcessNeeded('Please open the native LG App and sign in to your account to see what happened, ' +
|
|
60
|
+
'maybe new agreement need your accept. Then try restarting Homebridge.');
|
|
61
|
+
}
|
|
62
|
+
PENDING_REQUESTS = Math.max(0, PENDING_REQUESTS - 1);
|
|
63
|
+
return Promise.reject(err);
|
|
64
|
+
});
|
|
65
|
+
export const requestClient = client;
|
|
66
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/lib/request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { API, DynamicPlatformPlugin, PlatformAccessory, PlatformConfig, Service, Characteristic, Logging } from 'homebridge';
|
|
2
|
+
import { ThinQ } from './lib/ThinQ.js';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
import Characteristics from './characteristics/index.js';
|
|
5
|
+
import { AccessoryContext } from './baseDevice.js';
|
|
6
|
+
/**
|
|
7
|
+
* LGThinQHomebridgePlatform
|
|
8
|
+
* This class serves as the main entry point for the Homebridge plugin. It handles
|
|
9
|
+
* configuration parsing, device discovery, and accessory registration.
|
|
10
|
+
*/
|
|
11
|
+
export declare class LGThinQHomebridgePlatform implements DynamicPlatformPlugin {
|
|
12
|
+
readonly log: Logging;
|
|
13
|
+
readonly config: PlatformConfig;
|
|
14
|
+
readonly api: API;
|
|
15
|
+
readonly Service: typeof Service;
|
|
16
|
+
readonly Characteristic: typeof Characteristic;
|
|
17
|
+
readonly customCharacteristics: ReturnType<typeof Characteristics>;
|
|
18
|
+
readonly accessories: PlatformAccessory<AccessoryContext>[];
|
|
19
|
+
readonly ThinQ: ThinQ;
|
|
20
|
+
readonly events: EventEmitter;
|
|
21
|
+
private readonly intervalTime;
|
|
22
|
+
private readonly enable_thinq1;
|
|
23
|
+
readonly CustomServices: any;
|
|
24
|
+
readonly CustomCharacteristics: any;
|
|
25
|
+
constructor(log: Logging, config: PlatformConfig, api: API);
|
|
26
|
+
/**
|
|
27
|
+
* Invoked when Homebridge restores cached accessories from disk at startup.
|
|
28
|
+
* This method sets up event handlers for characteristics and updates respective values.
|
|
29
|
+
*
|
|
30
|
+
* @param accessory - The cached accessory to configure.
|
|
31
|
+
*/
|
|
32
|
+
configureAccessory(accessory: PlatformAccessory): void;
|
|
33
|
+
/**
|
|
34
|
+
* Discovers devices from the ThinQ API and registers them as Homebridge accessories.
|
|
35
|
+
*/
|
|
36
|
+
discoverDevices(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Starts monitoring devices for updates using MQTT or polling.
|
|
39
|
+
*/
|
|
40
|
+
protected startMonitor(): Promise<void>;
|
|
41
|
+
}
|