@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
package/dist/platform.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
|
|
2
|
+
import { Helper } from './helper.js';
|
|
3
|
+
import { ThinQ } from './lib/ThinQ.js';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { PlatformType, DEVICE_DISCOVERY_DELAY_MS, ONE_SECOND_MS } from './lib/constants.js';
|
|
6
|
+
import { ManualProcessNeeded, NotConnectedError } from './errors/index.js';
|
|
7
|
+
import Characteristics from './characteristics/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* LGThinQHomebridgePlatform
|
|
10
|
+
* This class serves as the main entry point for the Homebridge plugin. It handles
|
|
11
|
+
* configuration parsing, device discovery, and accessory registration.
|
|
12
|
+
*/
|
|
13
|
+
export class LGThinQHomebridgePlatform {
|
|
14
|
+
log;
|
|
15
|
+
config;
|
|
16
|
+
api;
|
|
17
|
+
Service;
|
|
18
|
+
Characteristic;
|
|
19
|
+
customCharacteristics;
|
|
20
|
+
// Tracks restored cached accessories
|
|
21
|
+
accessories = [];
|
|
22
|
+
ThinQ;
|
|
23
|
+
events;
|
|
24
|
+
intervalTime;
|
|
25
|
+
// Enable ThinQ1 support
|
|
26
|
+
enable_thinq1 = false;
|
|
27
|
+
// This is only required when using Custom Services and Characteristics not support by HomeKit
|
|
28
|
+
CustomServices;
|
|
29
|
+
CustomCharacteristics;
|
|
30
|
+
constructor(log, config, api) {
|
|
31
|
+
this.log = log;
|
|
32
|
+
this.config = config;
|
|
33
|
+
this.api = api;
|
|
34
|
+
this.Service = this.api.hap.Service;
|
|
35
|
+
this.Characteristic = this.api.hap.Characteristic;
|
|
36
|
+
this.customCharacteristics = Characteristics(this.api.hap.Characteristic);
|
|
37
|
+
this.events = new EventEmitter();
|
|
38
|
+
this.enable_thinq1 = config.thinq1;
|
|
39
|
+
this.config.devices = this.config.devices || [];
|
|
40
|
+
// Set the refresh interval for polling device data
|
|
41
|
+
this.intervalTime = (config.refresh_interval || 5) * ONE_SECOND_MS;
|
|
42
|
+
this.ThinQ = new ThinQ(this, config, log);
|
|
43
|
+
// Validate required configuration parameters
|
|
44
|
+
if (!config.country || !config.language || !((config.username && config.password) || config.refresh_token)) {
|
|
45
|
+
this.log.error('Missing required config parameter.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const didFinishLaunching = async () => {
|
|
49
|
+
const discoverDevices = async () => {
|
|
50
|
+
try {
|
|
51
|
+
await this.discoverDevices();
|
|
52
|
+
await this.startMonitor();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (err instanceof NotConnectedError) {
|
|
56
|
+
// Retry device discovery after 30 seconds if not connected
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
discoverDevices();
|
|
59
|
+
}, DEVICE_DISCOVERY_DELAY_MS);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const error = err;
|
|
63
|
+
this.log.error(error.message);
|
|
64
|
+
this.log.debug(error.message);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
await this.ThinQ.isReady();
|
|
70
|
+
this.log.info('Successfully connected to the ThinQ API.');
|
|
71
|
+
await discoverDevices();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
if (err.message === 'Internal Server Error'
|
|
75
|
+
|| err.code?.indexOf('ECONN') === 0
|
|
76
|
+
|| err instanceof NotConnectedError) {
|
|
77
|
+
this.log.error('LG ThinQ internal server error, try again later.');
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
this.log.error('ThinQ API is not ready. Please check configuration and try again.');
|
|
81
|
+
}
|
|
82
|
+
const error = err;
|
|
83
|
+
this.log.error(error.message);
|
|
84
|
+
this.log.debug(error.stack || error.message);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
this.api.on('didFinishLaunching', async () => {
|
|
88
|
+
log.debug('Executed didFinishLaunching callback');
|
|
89
|
+
await didFinishLaunching();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Invoked when Homebridge restores cached accessories from disk at startup.
|
|
94
|
+
* This method sets up event handlers for characteristics and updates respective values.
|
|
95
|
+
*
|
|
96
|
+
* @param accessory - The cached accessory to configure.
|
|
97
|
+
*/
|
|
98
|
+
configureAccessory(accessory) {
|
|
99
|
+
this.log.info('Loading accessory from Homebridge cache:', accessory.displayName);
|
|
100
|
+
if (!accessory.context.device) {
|
|
101
|
+
this.log.error('Accessory does not have a device context. Cannot restore accessory:', accessory.displayName);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Add the restored accessory to the accessories cache
|
|
105
|
+
this.accessories.push(accessory);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Discovers devices from the ThinQ API and registers them as Homebridge accessories.
|
|
109
|
+
*/
|
|
110
|
+
async discoverDevices() {
|
|
111
|
+
const accessoriesToRemoveUUID = this.accessories.map(accessory => accessory.UUID);
|
|
112
|
+
const devices = await this.ThinQ.devices();
|
|
113
|
+
if (!devices.length) {
|
|
114
|
+
this.log.warn('No ThinQ devices in your account.');
|
|
115
|
+
}
|
|
116
|
+
for (const device of devices) {
|
|
117
|
+
this.log.debug('Device [' + device.name + ']: ', device.toString());
|
|
118
|
+
this.log.debug(JSON.stringify(device.data));
|
|
119
|
+
// Skip ThinQ1 devices if support is disabled
|
|
120
|
+
if (!this.enable_thinq1 && device.platform === PlatformType.ThinQ1) {
|
|
121
|
+
this.log.debug('Thinq1 device is skipped: ', device.toString());
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Skip devices not explicitly enabled in the configuration
|
|
125
|
+
if (this.config.devices.length && !this.config.devices.find((enabled) => enabled.id === device.id)) {
|
|
126
|
+
this.log.info('Device skipped: ', device.id);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
this.log.info('[' + device.name + '] Setting up device!');
|
|
130
|
+
const setupSuccess = await this.ThinQ.setup(device);
|
|
131
|
+
if (!setupSuccess) {
|
|
132
|
+
this.log.warn('[' + device.name + '] Failed to setup device!');
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const accessoryType = Helper.make(device);
|
|
136
|
+
if (accessoryType === null) {
|
|
137
|
+
this.log.info('Device not supported: ' + device.platform + ': ' + device.toString());
|
|
138
|
+
this.ThinQ.unregister(device)
|
|
139
|
+
.then(() => this.log.debug(device.id, '- unregistered!'))
|
|
140
|
+
.catch((error) => this.log.error('Failed to unregister device:', device.id, error));
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
let lgThinQDevice;
|
|
144
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === device.id);
|
|
145
|
+
if (existingAccessory) {
|
|
146
|
+
// Remove the UUID from the removal list if the accessory already exists
|
|
147
|
+
accessoriesToRemoveUUID.splice(accessoriesToRemoveUUID.indexOf(device.id), 1);
|
|
148
|
+
this.log.info('Restoring existing accessory:', device.toString());
|
|
149
|
+
existingAccessory.context.device = device;
|
|
150
|
+
lgThinQDevice = new accessoryType(this, existingAccessory, this.log);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
this.log.info('Adding new accessory:', device.toString());
|
|
154
|
+
const category = Helper.category(device);
|
|
155
|
+
// Create a new accessory
|
|
156
|
+
const accessory = new this.api.platformAccessory(device.name, device.id, category);
|
|
157
|
+
accessory.context.device = device;
|
|
158
|
+
lgThinQDevice = new accessoryType(this, accessory, this.log);
|
|
159
|
+
// Register the accessory with Homebridge
|
|
160
|
+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
|
|
161
|
+
this.accessories.push(accessory);
|
|
162
|
+
}
|
|
163
|
+
// Bind the update event for the device
|
|
164
|
+
this.events.on(device.id, lgThinQDevice.update.bind(lgThinQDevice));
|
|
165
|
+
// Perform the first-time update
|
|
166
|
+
lgThinQDevice.updateAccessoryCharacteristic(device);
|
|
167
|
+
}
|
|
168
|
+
// Remove accessories that are no longer present in the ThinQ API
|
|
169
|
+
const accessoriesToRemove = this.accessories.filter(accessory => accessoriesToRemoveUUID.includes(accessory.UUID));
|
|
170
|
+
if (accessoriesToRemove.length) {
|
|
171
|
+
accessoriesToRemove.map(accessory => {
|
|
172
|
+
this.log.info('Removing accessory:', accessory.displayName);
|
|
173
|
+
this.accessories.splice(this.accessories.indexOf(accessory), 1);
|
|
174
|
+
});
|
|
175
|
+
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, accessoriesToRemove);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Starts monitoring devices for updates using MQTT or polling.
|
|
180
|
+
*/
|
|
181
|
+
async startMonitor() {
|
|
182
|
+
// Filter ThinQ2 devices
|
|
183
|
+
const thinq2devices = this.accessories.filter(accessory => accessory.context.device.platform === PlatformType.ThinQ2);
|
|
184
|
+
if (thinq2devices.length) {
|
|
185
|
+
// Start polling ThinQ2 devices at the configured interval
|
|
186
|
+
setInterval(async () => {
|
|
187
|
+
const devices = await this.ThinQ.devices();
|
|
188
|
+
devices.filter(device => device.platform === PlatformType.ThinQ2).forEach(device => {
|
|
189
|
+
this.events.emit(device.id, device.snapshot);
|
|
190
|
+
});
|
|
191
|
+
}, this.intervalTime);
|
|
192
|
+
this.log.info('Start MQTT listener for ThinQ2 devices');
|
|
193
|
+
await this.ThinQ.registerMQTTListener((data) => {
|
|
194
|
+
if ('data' in data && 'deviceId' in data) {
|
|
195
|
+
this.events.emit(data.deviceId, data.data?.state?.reported);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// Stop here if there are no ThinQ1 devices
|
|
200
|
+
if (this.accessories.length <= thinq2devices.length) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Start polling ThinQ1 devices
|
|
204
|
+
this.log.info('Start polling device data every ' + this.config.refresh_interval + ' seconds.');
|
|
205
|
+
const ThinQ = this.ThinQ;
|
|
206
|
+
const interval = setInterval(async () => {
|
|
207
|
+
try {
|
|
208
|
+
for (const accessory of this.accessories) {
|
|
209
|
+
const device = accessory.context.device;
|
|
210
|
+
if (device.platform === PlatformType.ThinQ1 && this.enable_thinq1) {
|
|
211
|
+
const deviceWithSnapshot = await ThinQ.pollMonitor(device);
|
|
212
|
+
if (deviceWithSnapshot.snapshot.raw !== null) {
|
|
213
|
+
this.events.emit(device.id, deviceWithSnapshot.snapshot);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
if (err instanceof ManualProcessNeeded) {
|
|
220
|
+
this.log.info('Stop polling device data.');
|
|
221
|
+
this.log.warn(err.message);
|
|
222
|
+
clearInterval(interval);
|
|
223
|
+
return; // Stop the plugin here
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}, this.intervalTime);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json
|
|
3
|
+
*/
|
|
4
|
+
export declare const PLATFORM_NAME = "LGThinQ";
|
|
5
|
+
/**
|
|
6
|
+
* This must match the name of your plugin as defined the package.json
|
|
7
|
+
*/
|
|
8
|
+
export declare const PLUGIN_NAME = "@mp-consulting/homebridge-lg-thinq";
|
package/dist/settings.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json
|
|
3
|
+
*/
|
|
4
|
+
export const PLATFORM_NAME = 'LGThinQ';
|
|
5
|
+
/**
|
|
6
|
+
* This must match the name of your plugin as defined the package.json
|
|
7
|
+
*/
|
|
8
|
+
export const PLUGIN_NAME = '@mp-consulting/homebridge-lg-thinq';
|
|
9
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,oCAAoC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { DeviceModel } from '../lib/DeviceModel.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for device status implementations.
|
|
4
|
+
* Provides common utility methods for parsing and accessing device data.
|
|
5
|
+
*/
|
|
6
|
+
export declare abstract class BaseStatus {
|
|
7
|
+
protected readonly data: Record<string, unknown> | undefined;
|
|
8
|
+
protected readonly deviceModel: DeviceModel;
|
|
9
|
+
constructor(data: Record<string, unknown> | undefined, deviceModel: DeviceModel);
|
|
10
|
+
/**
|
|
11
|
+
* Safely get an integer value from the data with a fallback.
|
|
12
|
+
*/
|
|
13
|
+
protected getInt(key: string, fallback?: number): number;
|
|
14
|
+
/**
|
|
15
|
+
* Safely get a string value from the data with a fallback.
|
|
16
|
+
*/
|
|
17
|
+
protected getString(key: string, fallback?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Safely get a boolean value from the data.
|
|
20
|
+
*/
|
|
21
|
+
protected getBool(key: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a key exists in the data.
|
|
24
|
+
*/
|
|
25
|
+
protected has(key: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Get the raw value for a key.
|
|
28
|
+
*/
|
|
29
|
+
protected getRaw<T>(key: string): T | undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Base class for appliance status (washer, dryer, styler, dishwasher).
|
|
33
|
+
* Provides common time-related properties.
|
|
34
|
+
*/
|
|
35
|
+
export declare abstract class ApplianceStatus extends BaseStatus {
|
|
36
|
+
/**
|
|
37
|
+
* Get the remaining duration in seconds.
|
|
38
|
+
*/
|
|
39
|
+
get remainDuration(): number;
|
|
40
|
+
/**
|
|
41
|
+
* Check if the device is powered on.
|
|
42
|
+
*/
|
|
43
|
+
abstract get isPowerOn(): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Check if the device is actively running.
|
|
46
|
+
*/
|
|
47
|
+
abstract get isRunning(): boolean;
|
|
48
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { safeParseInt } from '../helper.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for device status implementations.
|
|
4
|
+
* Provides common utility methods for parsing and accessing device data.
|
|
5
|
+
*/
|
|
6
|
+
export class BaseStatus {
|
|
7
|
+
data;
|
|
8
|
+
deviceModel;
|
|
9
|
+
constructor(data, deviceModel) {
|
|
10
|
+
this.data = data;
|
|
11
|
+
this.deviceModel = deviceModel;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Safely get an integer value from the data with a fallback.
|
|
15
|
+
*/
|
|
16
|
+
getInt(key, fallback = 0) {
|
|
17
|
+
return safeParseInt(this.data?.[key], fallback);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Safely get a string value from the data with a fallback.
|
|
21
|
+
*/
|
|
22
|
+
getString(key, fallback = '') {
|
|
23
|
+
const value = this.data?.[key];
|
|
24
|
+
return typeof value === 'string' ? value : fallback;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Safely get a boolean value from the data.
|
|
28
|
+
*/
|
|
29
|
+
getBool(key) {
|
|
30
|
+
return !!this.data?.[key];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if a key exists in the data.
|
|
34
|
+
*/
|
|
35
|
+
has(key) {
|
|
36
|
+
return this.data !== undefined && key in this.data;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the raw value for a key.
|
|
40
|
+
*/
|
|
41
|
+
getRaw(key) {
|
|
42
|
+
return this.data?.[key];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Base class for appliance status (washer, dryer, styler, dishwasher).
|
|
47
|
+
* Provides common time-related properties.
|
|
48
|
+
*/
|
|
49
|
+
export class ApplianceStatus extends BaseStatus {
|
|
50
|
+
/**
|
|
51
|
+
* Get the remaining duration in seconds.
|
|
52
|
+
*/
|
|
53
|
+
get remainDuration() {
|
|
54
|
+
const hours = this.getInt('remainTimeHour');
|
|
55
|
+
const minutes = this.getInt('remainTimeMinute');
|
|
56
|
+
return this.isRunning ? (hours * 3600 + minutes * 60) : 0;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=BaseStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseStatus.js","sourceRoot":"","sources":["../../src/status/BaseStatus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;;GAGG;AACH,MAAM,OAAgB,UAAU;IAET;IACA;IAFrB,YACqB,IAAyC,EACzC,WAAwB;QADxB,SAAI,GAAJ,IAAI,CAAqC;QACzC,gBAAW,GAAX,WAAW,CAAa;IAC1C,CAAC;IAEJ;;OAEG;IACO,MAAM,CAAC,GAAW,EAAE,QAAQ,GAAG,CAAC;QACxC,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACO,SAAS,CAAC,GAAW,EAAE,QAAQ,GAAG,EAAE;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtD,CAAC;IAED;;OAEG;IACO,OAAO,CAAC,GAAW;QAC3B,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACO,GAAG,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC;IACrD,CAAC;IAED;;OAEG;IACO,MAAM,CAAI,GAAW;QAC7B,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAkB,CAAC;IAC3C,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAgB,eAAgB,SAAQ,UAAU;IACtD;;OAEG;IACH,IAAW,cAAc;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;CAWF"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript interfaces for device snapshot data structures.
|
|
3
|
+
* These interfaces provide type safety for device state data.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Common base interface for all device snapshots
|
|
7
|
+
*/
|
|
8
|
+
export interface BaseSnapshot {
|
|
9
|
+
online?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Air Conditioner snapshot data
|
|
13
|
+
*/
|
|
14
|
+
export interface ACSnapshot extends BaseSnapshot {
|
|
15
|
+
'airState.operation'?: number;
|
|
16
|
+
'airState.opMode'?: number;
|
|
17
|
+
'airState.tempState.current'?: number;
|
|
18
|
+
'airState.tempState.target'?: number;
|
|
19
|
+
'airState.windStrength'?: number;
|
|
20
|
+
'airState.wDir.vStep'?: number;
|
|
21
|
+
'airState.wDir.hStep'?: number;
|
|
22
|
+
'airState.circulate.rotate'?: number;
|
|
23
|
+
'airState.lightingState.signal'?: number;
|
|
24
|
+
'airState.humidity.current'?: string | number;
|
|
25
|
+
'airState.quality.overall'?: string | number;
|
|
26
|
+
'airState.quality.PM2'?: string | number;
|
|
27
|
+
'airState.quality.PM10'?: string | number;
|
|
28
|
+
'airState.quality.sensorMon'?: number;
|
|
29
|
+
'airState.wMode.jet'?: number;
|
|
30
|
+
'airState.miscFuncState.airClean'?: number;
|
|
31
|
+
'airState.energy.onCurrent'?: number;
|
|
32
|
+
'airState.filterMngStates.useTime'?: number;
|
|
33
|
+
'airState.filterMngStates.maxTime'?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Air Purifier snapshot data
|
|
37
|
+
*/
|
|
38
|
+
export interface AirPurifierSnapshot extends BaseSnapshot {
|
|
39
|
+
'airState.operation'?: number | boolean;
|
|
40
|
+
'airState.opMode'?: number;
|
|
41
|
+
'airState.windStrength'?: number;
|
|
42
|
+
'airState.circulate.rotate'?: number;
|
|
43
|
+
'airState.lightingState.signal'?: number;
|
|
44
|
+
'airState.quality.overall'?: string | number;
|
|
45
|
+
'airState.quality.PM2'?: string | number;
|
|
46
|
+
'airState.quality.PM10'?: string | number;
|
|
47
|
+
'airState.quality.sensorMon'?: number;
|
|
48
|
+
'airState.miscFuncState.airFast'?: number | boolean;
|
|
49
|
+
'airState.filterMngStates.useTime'?: number;
|
|
50
|
+
'airState.filterMngStates.maxTime'?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Dehumidifier snapshot data
|
|
54
|
+
*/
|
|
55
|
+
export interface DehumidifierSnapshot extends BaseSnapshot {
|
|
56
|
+
'airState.operation'?: number;
|
|
57
|
+
'airState.opMode'?: number;
|
|
58
|
+
'airState.windStrength'?: number;
|
|
59
|
+
'airState.humidity.current'?: number;
|
|
60
|
+
'airState.humidity.desired'?: number;
|
|
61
|
+
'airState.notificationExt'?: unknown;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Washer/Dryer snapshot data
|
|
65
|
+
*/
|
|
66
|
+
export interface WasherDryerSnapshot extends BaseSnapshot {
|
|
67
|
+
washerDryer?: {
|
|
68
|
+
state?: string;
|
|
69
|
+
preState?: string;
|
|
70
|
+
processState?: string;
|
|
71
|
+
remoteStart?: string;
|
|
72
|
+
initialBit?: string;
|
|
73
|
+
childLock?: string;
|
|
74
|
+
TCLCount?: number;
|
|
75
|
+
reserveTimeHour?: number;
|
|
76
|
+
reserveTimeMinute?: number;
|
|
77
|
+
remainTimeHour?: number;
|
|
78
|
+
remainTimeMinute?: number;
|
|
79
|
+
initialTimeHour?: number;
|
|
80
|
+
initialTimeMinute?: number;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Refrigerator snapshot data
|
|
85
|
+
*/
|
|
86
|
+
export interface RefrigeratorSnapshot extends BaseSnapshot {
|
|
87
|
+
refState?: {
|
|
88
|
+
fridgeTemp?: number;
|
|
89
|
+
freezerTemp?: number;
|
|
90
|
+
atLeastOneDoorOpen?: string;
|
|
91
|
+
tempUnit?: 'CELSIUS' | 'FAHRENHEIT';
|
|
92
|
+
expressMode?: string;
|
|
93
|
+
expressFridge?: string;
|
|
94
|
+
ecoFriendly?: string;
|
|
95
|
+
waterFilter?: string;
|
|
96
|
+
waterFilter1RemainP?: number;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Styler snapshot data
|
|
101
|
+
*/
|
|
102
|
+
export interface StylerSnapshot extends BaseSnapshot {
|
|
103
|
+
styler?: {
|
|
104
|
+
state?: string;
|
|
105
|
+
preState?: string;
|
|
106
|
+
processState?: string;
|
|
107
|
+
remainTimeHour?: number;
|
|
108
|
+
remainTimeMinute?: number;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Range Hood snapshot data
|
|
113
|
+
*/
|
|
114
|
+
export interface RangeHoodSnapshot extends BaseSnapshot {
|
|
115
|
+
hoodState?: {
|
|
116
|
+
ventMode?: string;
|
|
117
|
+
ventLevel?: number;
|
|
118
|
+
lampLevel?: number;
|
|
119
|
+
remainTimeMinute?: number;
|
|
120
|
+
remainTimeSecond?: number;
|
|
121
|
+
childLock?: string;
|
|
122
|
+
standyMode?: string;
|
|
123
|
+
hoodState?: string;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Dishwasher snapshot data
|
|
128
|
+
*/
|
|
129
|
+
export interface DishwasherSnapshot extends BaseSnapshot {
|
|
130
|
+
dishwasher?: {
|
|
131
|
+
state?: string;
|
|
132
|
+
preState?: string;
|
|
133
|
+
processState?: string;
|
|
134
|
+
remainTimeHour?: number;
|
|
135
|
+
remainTimeMinute?: number;
|
|
136
|
+
tclCount?: number;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Union type for all device snapshots
|
|
141
|
+
*/
|
|
142
|
+
export type DeviceSnapshot = ACSnapshot | AirPurifierSnapshot | DehumidifierSnapshot | WasherDryerSnapshot | RefrigeratorSnapshot | StylerSnapshot | RangeHoodSnapshot | DishwasherSnapshot;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshots.js","sourceRoot":"","sources":["../../src/types/snapshots.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, it, expect } from '@jest/globals';
|
|
2
|
+
import { normalizeBoolean, normalizeNumber, safeParseInt, safeParseFloat, toSeconds, } from '../normalize.js';
|
|
3
|
+
describe('normalize utilities', () => {
|
|
4
|
+
describe('normalizeBoolean', () => {
|
|
5
|
+
it('should return boolean values as-is', () => {
|
|
6
|
+
expect(normalizeBoolean(true)).toBe(true);
|
|
7
|
+
expect(normalizeBoolean(false)).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
it('should convert number 1 to true and other numbers to false', () => {
|
|
10
|
+
expect(normalizeBoolean(1)).toBe(true);
|
|
11
|
+
expect(normalizeBoolean(0)).toBe(false);
|
|
12
|
+
expect(normalizeBoolean(2)).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
it('should convert string values correctly', () => {
|
|
15
|
+
expect(normalizeBoolean('1')).toBe(true);
|
|
16
|
+
expect(normalizeBoolean('true')).toBe(true);
|
|
17
|
+
expect(normalizeBoolean('TRUE')).toBe(true);
|
|
18
|
+
expect(normalizeBoolean('on')).toBe(true);
|
|
19
|
+
expect(normalizeBoolean('ON')).toBe(true);
|
|
20
|
+
expect(normalizeBoolean('0')).toBe(false);
|
|
21
|
+
expect(normalizeBoolean('false')).toBe(false);
|
|
22
|
+
expect(normalizeBoolean('off')).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
it('should convert other truthy/falsy values', () => {
|
|
25
|
+
expect(normalizeBoolean(null)).toBe(false);
|
|
26
|
+
expect(normalizeBoolean(undefined)).toBe(false);
|
|
27
|
+
expect(normalizeBoolean({})).toBe(true);
|
|
28
|
+
expect(normalizeBoolean([])).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('normalizeNumber', () => {
|
|
32
|
+
it('should return null for null/undefined', () => {
|
|
33
|
+
expect(normalizeNumber(null)).toBe(null);
|
|
34
|
+
expect(normalizeNumber(undefined)).toBe(null);
|
|
35
|
+
});
|
|
36
|
+
it('should return number values as-is', () => {
|
|
37
|
+
expect(normalizeNumber(42)).toBe(42);
|
|
38
|
+
expect(normalizeNumber(3.14)).toBe(3.14);
|
|
39
|
+
expect(normalizeNumber(0)).toBe(0);
|
|
40
|
+
});
|
|
41
|
+
it('should convert string to number', () => {
|
|
42
|
+
expect(normalizeNumber('42')).toBe(42);
|
|
43
|
+
expect(normalizeNumber('3.14')).toBe(3.14);
|
|
44
|
+
});
|
|
45
|
+
it('should return null for invalid strings', () => {
|
|
46
|
+
expect(normalizeNumber('abc')).toBe(null);
|
|
47
|
+
});
|
|
48
|
+
it('should convert empty string to 0', () => {
|
|
49
|
+
// Note: Number('') returns 0 in JavaScript
|
|
50
|
+
expect(normalizeNumber('')).toBe(0);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('safeParseInt', () => {
|
|
54
|
+
it('should parse valid integers', () => {
|
|
55
|
+
expect(safeParseInt('42')).toBe(42);
|
|
56
|
+
expect(safeParseInt('0')).toBe(0);
|
|
57
|
+
expect(safeParseInt('-10')).toBe(-10);
|
|
58
|
+
});
|
|
59
|
+
it('should return fallback for invalid values', () => {
|
|
60
|
+
expect(safeParseInt('abc')).toBe(0);
|
|
61
|
+
expect(safeParseInt('abc', 99)).toBe(99);
|
|
62
|
+
expect(safeParseInt(null)).toBe(0);
|
|
63
|
+
expect(safeParseInt(undefined, 5)).toBe(5);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('safeParseFloat', () => {
|
|
67
|
+
it('should parse valid floats', () => {
|
|
68
|
+
expect(safeParseFloat('3.14')).toBe(3.14);
|
|
69
|
+
expect(safeParseFloat('0.5')).toBe(0.5);
|
|
70
|
+
expect(safeParseFloat('-2.5')).toBe(-2.5);
|
|
71
|
+
});
|
|
72
|
+
it('should return fallback for invalid values', () => {
|
|
73
|
+
expect(safeParseFloat('abc')).toBe(0);
|
|
74
|
+
expect(safeParseFloat('abc', 1.5)).toBe(1.5);
|
|
75
|
+
expect(safeParseFloat(null)).toBe(0);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('toSeconds', () => {
|
|
79
|
+
it('should convert hours and minutes to seconds', () => {
|
|
80
|
+
expect(toSeconds(1, 0)).toBe(3600);
|
|
81
|
+
expect(toSeconds(0, 1)).toBe(60);
|
|
82
|
+
expect(toSeconds(1, 30)).toBe(5400);
|
|
83
|
+
expect(toSeconds(2, 15)).toBe(8100);
|
|
84
|
+
});
|
|
85
|
+
it('should handle optional seconds parameter', () => {
|
|
86
|
+
expect(toSeconds(0, 0, 30)).toBe(30);
|
|
87
|
+
expect(toSeconds(1, 1, 1)).toBe(3661);
|
|
88
|
+
});
|
|
89
|
+
it('should handle zero values', () => {
|
|
90
|
+
expect(toSeconds(0, 0)).toBe(0);
|
|
91
|
+
expect(toSeconds(0, 0, 0)).toBe(0);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=normalize.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.spec.js","sourceRoot":"","sources":["../../../src/utils/__tests__/normalize.spec.ts"],"names":[],"mappings":"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"}
|