tsvesync 1.0.64 → 1.0.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/fans/airBaseV2.d.ts +68 -0
- package/dist/lib/fans/airBaseV2.js +226 -0
- package/dist/lib/fans/airBypass.d.ts +79 -0
- package/dist/lib/fans/airBypass.js +484 -0
- package/dist/lib/fans/humid200300S.d.ts +50 -0
- package/dist/lib/fans/humid200300S.js +200 -0
- package/dist/lib/fans/humidifier.d.ts +83 -0
- package/dist/lib/fans/humidifier.js +388 -0
- package/dist/lib/fans/index.d.ts +9 -0
- package/dist/lib/fans/index.js +95 -0
- package/dist/lib/fans/towerFan.d.ts +105 -0
- package/dist/lib/fans/towerFan.js +279 -0
- package/dist/lib/fans/warmHumidifier.d.ts +49 -0
- package/dist/lib/fans/warmHumidifier.js +174 -0
- package/dist/lib/vesyncFan.d.ts +2 -2
- package/dist/lib/vesyncFan.js +2 -2
- package/dist/lib/vesyncFanImpl.d.ts +1 -436
- package/dist/lib/vesyncFanImpl.js +16 -1848
- package/package.json +1 -1
- package/src/lib/fans/airBaseV2.ts +276 -0
- package/src/lib/fans/airBypass.ts +594 -0
- package/src/lib/fans/humid200300S.ts +234 -0
- package/src/lib/fans/humidifier.ts +470 -0
- package/src/lib/fans/index.ts +101 -0
- package/src/lib/fans/towerFan.ts +335 -0
- package/src/lib/fans/warmHumidifier.ts +202 -0
- package/src/lib/vesyncFan.ts +5 -5
- package/src/lib/vesyncFanImpl.ts +2 -2262
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { VeSyncWarmHumidifier } from './warmHumidifier';
|
|
2
|
+
import { VeSync } from '../vesync';
|
|
3
|
+
import { Helpers } from '../helpers';
|
|
4
|
+
import { logger } from '../logger';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* VeSync Humidifier 200/300S Class
|
|
8
|
+
*/
|
|
9
|
+
export class VeSyncHumid200300S extends VeSyncWarmHumidifier {
|
|
10
|
+
protected readonly modes = ['auto', 'manual', 'sleep'] as const;
|
|
11
|
+
protected readonly features = ['humidity', 'mist', 'display', 'timer', 'auto_mode'];
|
|
12
|
+
protected readonly mistLevels = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
13
|
+
protected readonly humidityRange = { min: 30, max: 80 };
|
|
14
|
+
|
|
15
|
+
constructor(details: Record<string, any>, manager: VeSync) {
|
|
16
|
+
super(details, manager);
|
|
17
|
+
logger.debug(`Initialized VeSyncHumid200300S device: ${this.deviceName}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get device details
|
|
22
|
+
*/
|
|
23
|
+
async getDetails(): Promise<Boolean> {
|
|
24
|
+
logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
25
|
+
const [response, status] = await this.callApi(
|
|
26
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
27
|
+
'post',
|
|
28
|
+
{
|
|
29
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
30
|
+
cid: this.cid,
|
|
31
|
+
configModule: this.configModule,
|
|
32
|
+
payload: {
|
|
33
|
+
data: {},
|
|
34
|
+
method: 'getHumidifierStatus',
|
|
35
|
+
source: 'APP'
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
Helpers.reqHeaderBypass()
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const success = this.checkResponse([response, status], 'getDetails');
|
|
42
|
+
if (success && response?.result?.result) {
|
|
43
|
+
const result = response.result.result;
|
|
44
|
+
|
|
45
|
+
// Update device status based on enabled field
|
|
46
|
+
this.deviceStatus = result.enabled ? 'on' : 'off';
|
|
47
|
+
|
|
48
|
+
this.details = {
|
|
49
|
+
mode: result.mode || '',
|
|
50
|
+
humidity: result.humidity || 0, // Current humidity
|
|
51
|
+
target_humidity: result.target_humidity || result.humidity || 0, // Target humidity
|
|
52
|
+
mist_level: result.mist_level || 0,
|
|
53
|
+
mist_virtual_level: result.mist_virtual_level || 0,
|
|
54
|
+
warm_level: result.warm_level || 0,
|
|
55
|
+
water_lacks: result.water_lacks || false,
|
|
56
|
+
humidity_high: result.humidity_high || false,
|
|
57
|
+
water_tank_lifted: result.water_tank_lifted || false,
|
|
58
|
+
display: result.display || false,
|
|
59
|
+
automatic_stop: result.automatic_stop_reach_target || false,
|
|
60
|
+
configuration: result.configuration || {},
|
|
61
|
+
connection_status: result.connection_status || null,
|
|
62
|
+
night_light_brightness: result.night_light_brightness || 0
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Log raw response for debugging
|
|
66
|
+
logger.debug(`Raw API Response: ${JSON.stringify(response)}`);
|
|
67
|
+
logger.debug(`Parsed Result: ${JSON.stringify(result)}`);
|
|
68
|
+
logger.debug(`Successfully got details for device: ${this.deviceName}`);
|
|
69
|
+
}
|
|
70
|
+
return success;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set mist level
|
|
75
|
+
*/
|
|
76
|
+
async setMistLevel(level: number): Promise<boolean> {
|
|
77
|
+
if (!this.mistLevels.includes(level)) {
|
|
78
|
+
const error = `Invalid mist level: ${level}. Must be one of: ${this.mistLevels.join(', ')}`;
|
|
79
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
80
|
+
throw new Error(error);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
|
|
84
|
+
const [response, status] = await this.callApi(
|
|
85
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
86
|
+
'post',
|
|
87
|
+
{
|
|
88
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
89
|
+
cid: this.cid,
|
|
90
|
+
configModule: this.configModule,
|
|
91
|
+
payload: {
|
|
92
|
+
data: {
|
|
93
|
+
id: 0,
|
|
94
|
+
level: level,
|
|
95
|
+
type: 'mist'
|
|
96
|
+
},
|
|
97
|
+
method: 'setVirtualLevel', // Use setVirtualLevel per YAML spec
|
|
98
|
+
source: 'APP'
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
Helpers.reqHeaderBypass()
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const success = this.checkResponse([response, status], 'setMistLevel');
|
|
105
|
+
logger.debug(`Mist Level API Response: ${JSON.stringify(response)}`);
|
|
106
|
+
logger.debug(`Mist Level API Status: ${status}`);
|
|
107
|
+
if (success) {
|
|
108
|
+
this.details.mist_level = level;
|
|
109
|
+
this.details.mist_virtual_level = level;
|
|
110
|
+
// Get latest state and log it
|
|
111
|
+
await this.getDetails();
|
|
112
|
+
logger.debug(`Device state after mist level change: ${JSON.stringify(this.details)}`);
|
|
113
|
+
} else {
|
|
114
|
+
logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
|
|
115
|
+
}
|
|
116
|
+
return success;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Set night light brightness
|
|
121
|
+
*/
|
|
122
|
+
async setNightLightBrightness(brightness: number): Promise<boolean> {
|
|
123
|
+
if (brightness < 0 || brightness > 100) {
|
|
124
|
+
const error = `Invalid brightness: ${brightness}. Must be between 0 and 100`;
|
|
125
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
126
|
+
throw new Error(error);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
logger.debug(`Setting night light brightness to ${brightness} for device: ${this.deviceName}`);
|
|
130
|
+
const [response, status] = await this.callApi(
|
|
131
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
132
|
+
'post',
|
|
133
|
+
{
|
|
134
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
135
|
+
cid: this.cid,
|
|
136
|
+
configModule: this.configModule,
|
|
137
|
+
payload: {
|
|
138
|
+
data: {
|
|
139
|
+
brightness
|
|
140
|
+
},
|
|
141
|
+
method: 'setNightLight',
|
|
142
|
+
source: 'APP'
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
Helpers.reqHeaderBypass()
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const success = this.checkResponse([response, status], 'setNightLightBrightness');
|
|
149
|
+
if (success) {
|
|
150
|
+
this.details.night_light_brightness = brightness;
|
|
151
|
+
} else {
|
|
152
|
+
logger.error(`Failed to set night light brightness to ${brightness} for device: ${this.deviceName}`);
|
|
153
|
+
}
|
|
154
|
+
return success;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get night light brightness
|
|
159
|
+
*/
|
|
160
|
+
get nightLightBrightness(): number {
|
|
161
|
+
return this.details.night_light_brightness || 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get configuration
|
|
166
|
+
*/
|
|
167
|
+
get configuration(): any {
|
|
168
|
+
return this.details.configuration || {};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get mist level
|
|
173
|
+
* Override base class to return virtual level
|
|
174
|
+
*/
|
|
175
|
+
get mistLevel(): number {
|
|
176
|
+
return this.details.mist_virtual_level || 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Get target humidity
|
|
181
|
+
* Override base class to return target humidity instead of current humidity
|
|
182
|
+
*/
|
|
183
|
+
get humidity(): number {
|
|
184
|
+
return this.details.target_humidity || 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Set target humidity
|
|
189
|
+
* Override base class to properly update target humidity
|
|
190
|
+
*/
|
|
191
|
+
async setHumidity(humidity: number): Promise<boolean> {
|
|
192
|
+
if (!this.hasFeature('humidity')) {
|
|
193
|
+
const error = 'Humidity control not supported';
|
|
194
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
195
|
+
throw new Error(error);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (humidity < this.humidityRange.min || humidity > this.humidityRange.max) {
|
|
199
|
+
const error = `Invalid humidity: ${humidity}. Must be between ${this.humidityRange.min} and ${this.humidityRange.max}`;
|
|
200
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
201
|
+
throw new Error(error);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
logger.debug(`Setting target humidity to ${humidity}% for device: ${this.deviceName}`);
|
|
205
|
+
const [response, status] = await this.callApi(
|
|
206
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
207
|
+
'post',
|
|
208
|
+
{
|
|
209
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
210
|
+
cid: this.cid,
|
|
211
|
+
configModule: this.configModule,
|
|
212
|
+
payload: {
|
|
213
|
+
data: {
|
|
214
|
+
target_humidity: humidity
|
|
215
|
+
},
|
|
216
|
+
method: 'setTargetHumidity',
|
|
217
|
+
source: 'APP'
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
Helpers.reqHeaderBypass()
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const success = this.checkResponse([response, status], 'setHumidity');
|
|
224
|
+
if (success) {
|
|
225
|
+
this.details.target_humidity = humidity;
|
|
226
|
+
// Get latest state and log it
|
|
227
|
+
await this.getDetails();
|
|
228
|
+
logger.debug(`Device state after humidity change: ${JSON.stringify(this.details)}`);
|
|
229
|
+
} else {
|
|
230
|
+
logger.error(`Failed to set target humidity to ${humidity}% for device: ${this.deviceName}`);
|
|
231
|
+
}
|
|
232
|
+
return success;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { VeSyncFan } from '../vesyncFan';
|
|
2
|
+
import { VeSync } from '../vesync';
|
|
3
|
+
import { Helpers } from '../helpers';
|
|
4
|
+
import { logger } from '../logger';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* VeSync Humidifier Base Class
|
|
8
|
+
*/
|
|
9
|
+
export class VeSyncHumidifier extends VeSyncFan {
|
|
10
|
+
protected readonly modes = ['auto', 'manual', 'sleep'] as const;
|
|
11
|
+
protected readonly mistLevels: number[];
|
|
12
|
+
protected readonly displayModes = ['on', 'off'] as const;
|
|
13
|
+
protected readonly humidityRange = { min: 30, max: 80 };
|
|
14
|
+
|
|
15
|
+
constructor(details: Record<string, any>, manager: VeSync) {
|
|
16
|
+
super(details, manager);
|
|
17
|
+
// Set mist levels based on model
|
|
18
|
+
switch (this.deviceType) {
|
|
19
|
+
case 'Dual200S':
|
|
20
|
+
case 'LUH-D301S-WUSR':
|
|
21
|
+
case 'LUH-D301S-WJP':
|
|
22
|
+
case 'LUH-D301S-WEU':
|
|
23
|
+
this.mistLevels = [1, 2];
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
// All other models support levels 1-9
|
|
27
|
+
this.mistLevels = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
28
|
+
}
|
|
29
|
+
logger.debug(`Initialized VeSyncHumidifier device: ${this.deviceName}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get device details
|
|
34
|
+
*/
|
|
35
|
+
async getDetails(): Promise<Boolean> {
|
|
36
|
+
logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
37
|
+
const [response, status] = await this.callApi(
|
|
38
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
39
|
+
'post',
|
|
40
|
+
{
|
|
41
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
42
|
+
cid: this.cid,
|
|
43
|
+
configModule: this.configModule,
|
|
44
|
+
payload: {
|
|
45
|
+
data: {},
|
|
46
|
+
method: 'getHumidifierStatus',
|
|
47
|
+
source: 'APP'
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
Helpers.reqHeaderBypass()
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const success = this.checkResponse([response, status], 'getDetails');
|
|
54
|
+
if (success && response?.result?.result) {
|
|
55
|
+
const result = response.result.result;
|
|
56
|
+
|
|
57
|
+
// Handle model-specific status fields
|
|
58
|
+
if (this.deviceType.startsWith('Classic') || this.deviceType === 'Dual200S') {
|
|
59
|
+
this.deviceStatus = result.enabled ? 'on' : 'off';
|
|
60
|
+
} else {
|
|
61
|
+
this.deviceStatus = result.powerSwitch === 1 ? 'on' : 'off';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.details = {
|
|
65
|
+
mode: result.mode || '',
|
|
66
|
+
humidity: result.humidity || 0,
|
|
67
|
+
mist_level: result.level || 0,
|
|
68
|
+
mist_virtual_level: result.virtualLevel || 0,
|
|
69
|
+
warm_level: result.level || 0,
|
|
70
|
+
water_lacks: result.waterLacks || false,
|
|
71
|
+
humidity_high: result.humidityHigh || false,
|
|
72
|
+
water_tank_lifted: result.waterTankLifted || false,
|
|
73
|
+
display: result.display || false,
|
|
74
|
+
automatic_stop: result.automaticStop || false,
|
|
75
|
+
configuration: result.configuration || {},
|
|
76
|
+
connection_status: result.connectionStatus || null
|
|
77
|
+
};
|
|
78
|
+
logger.debug(`Successfully got details for device: ${this.deviceName}`);
|
|
79
|
+
}
|
|
80
|
+
return success;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Turn device on
|
|
85
|
+
*/
|
|
86
|
+
async turnOn(): Promise<boolean> {
|
|
87
|
+
return this.toggleSwitch(true);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Turn device off
|
|
92
|
+
*/
|
|
93
|
+
async turnOff(): Promise<boolean> {
|
|
94
|
+
return this.toggleSwitch(false);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Toggle device power
|
|
99
|
+
*/
|
|
100
|
+
async toggleSwitch(enabled: boolean): Promise<boolean> {
|
|
101
|
+
logger.info(`Setting device power to ${enabled ? 'on' : 'off'}: ${this.deviceName}`);
|
|
102
|
+
const [response, status] = await this.callApi(
|
|
103
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
104
|
+
'post',
|
|
105
|
+
{
|
|
106
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
107
|
+
cid: this.cid,
|
|
108
|
+
configModule: this.configModule,
|
|
109
|
+
payload: {
|
|
110
|
+
data: {
|
|
111
|
+
enabled: enabled,
|
|
112
|
+
id: 0
|
|
113
|
+
},
|
|
114
|
+
method: 'setSwitch',
|
|
115
|
+
source: 'APP'
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
Helpers.reqHeaderBypass()
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const success = this.checkResponse([response, status], 'toggleSwitch');
|
|
122
|
+
if (success) {
|
|
123
|
+
this.deviceStatus = enabled ? 'on' : 'off';
|
|
124
|
+
} else {
|
|
125
|
+
logger.error(`Failed to set device power to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
126
|
+
}
|
|
127
|
+
return success;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Set mist level
|
|
132
|
+
*/
|
|
133
|
+
async setMistLevel(level: number): Promise<boolean> {
|
|
134
|
+
if (!this.mistLevels.includes(level)) {
|
|
135
|
+
const error = `Invalid mist level: ${level}. Must be one of: ${this.mistLevels.join(', ')}`;
|
|
136
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
137
|
+
throw new Error(error);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
|
|
141
|
+
const [response, status] = await this.callApi(
|
|
142
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
143
|
+
'post',
|
|
144
|
+
{
|
|
145
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
146
|
+
cid: this.cid,
|
|
147
|
+
configModule: this.configModule,
|
|
148
|
+
payload: {
|
|
149
|
+
data: {
|
|
150
|
+
id: 0,
|
|
151
|
+
level: level,
|
|
152
|
+
type: 'mist'
|
|
153
|
+
},
|
|
154
|
+
method: 'setVirtualLevel',
|
|
155
|
+
source: 'APP'
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
Helpers.reqHeaderBypass()
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const success = this.checkResponse([response, status], 'setMistLevel');
|
|
162
|
+
if (!success) {
|
|
163
|
+
logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
|
|
164
|
+
}
|
|
165
|
+
return success;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Change fan speed - Implemented to satisfy interface but redirects to setMistLevel
|
|
170
|
+
*/
|
|
171
|
+
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
172
|
+
logger.debug(`Redirecting fan speed change to mist level for device: ${this.deviceName}`);
|
|
173
|
+
return this.setMistLevel(speed);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Set device mode
|
|
178
|
+
*/
|
|
179
|
+
async setMode(mode: string): Promise<boolean> {
|
|
180
|
+
if (!this.modes.includes(mode as any)) {
|
|
181
|
+
const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
|
|
182
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
183
|
+
throw new Error(error);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
|
|
187
|
+
const [response, status] = await this.callApi(
|
|
188
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
189
|
+
'post',
|
|
190
|
+
{
|
|
191
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
192
|
+
cid: this.cid,
|
|
193
|
+
configModule: this.configModule,
|
|
194
|
+
payload: {
|
|
195
|
+
data: {
|
|
196
|
+
mode
|
|
197
|
+
},
|
|
198
|
+
method: 'setHumidityMode',
|
|
199
|
+
source: 'APP'
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
Helpers.reqHeaderBypass()
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const success = this.checkResponse([response, status], 'setMode');
|
|
206
|
+
if (success) {
|
|
207
|
+
this.details.mode = mode;
|
|
208
|
+
} else {
|
|
209
|
+
logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
|
|
210
|
+
}
|
|
211
|
+
return success;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Set target humidity
|
|
216
|
+
*/
|
|
217
|
+
async setHumidity(humidity: number): Promise<boolean> {
|
|
218
|
+
if (!this.hasFeature('humidity')) {
|
|
219
|
+
const error = 'Humidity control not supported';
|
|
220
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
221
|
+
throw new Error(error);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (humidity < this.humidityRange.min || humidity > this.humidityRange.max) {
|
|
225
|
+
const error = `Invalid humidity: ${humidity}. Must be between ${this.humidityRange.min} and ${this.humidityRange.max}`;
|
|
226
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
227
|
+
throw new Error(error);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
logger.debug(`Setting target humidity to ${humidity}% for device: ${this.deviceName}`);
|
|
231
|
+
const [response, status] = await this.callApi(
|
|
232
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
233
|
+
'post',
|
|
234
|
+
{
|
|
235
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
236
|
+
cid: this.cid,
|
|
237
|
+
configModule: this.configModule,
|
|
238
|
+
payload: {
|
|
239
|
+
data: {
|
|
240
|
+
target_humidity: humidity
|
|
241
|
+
},
|
|
242
|
+
method: 'setTargetHumidity',
|
|
243
|
+
source: 'APP'
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
Helpers.reqHeaderBypass()
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const success = this.checkResponse([response, status], 'setHumidity');
|
|
250
|
+
if (!success) {
|
|
251
|
+
logger.error(`Failed to set target humidity to ${humidity}% for device: ${this.deviceName}`);
|
|
252
|
+
}
|
|
253
|
+
return success;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Set display status
|
|
258
|
+
*/
|
|
259
|
+
async setDisplay(enabled: boolean): Promise<boolean> {
|
|
260
|
+
if (!this.hasFeature('display')) {
|
|
261
|
+
const error = 'Display control not supported';
|
|
262
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
263
|
+
throw new Error(error);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
logger.debug(`Setting display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
267
|
+
const [response, status] = await this.callApi(
|
|
268
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
269
|
+
'post',
|
|
270
|
+
{
|
|
271
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
272
|
+
cid: this.cid,
|
|
273
|
+
configModule: this.configModule,
|
|
274
|
+
payload: {
|
|
275
|
+
data: {
|
|
276
|
+
state: enabled
|
|
277
|
+
},
|
|
278
|
+
method: 'setDisplay',
|
|
279
|
+
source: 'APP'
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
Helpers.reqHeaderBypass()
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
const success = this.checkResponse([response, status], 'setDisplay');
|
|
286
|
+
if (!success) {
|
|
287
|
+
logger.error(`Failed to set display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
288
|
+
}
|
|
289
|
+
return success;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Set timer
|
|
294
|
+
*/
|
|
295
|
+
async setTimer(hours: number): Promise<boolean> {
|
|
296
|
+
if (!this.hasFeature('timer')) {
|
|
297
|
+
const error = 'Timer not supported';
|
|
298
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
299
|
+
throw new Error(error);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
logger.debug(`Setting timer to ${hours} hours for device: ${this.deviceName}`);
|
|
303
|
+
const [response, status] = await this.callApi(
|
|
304
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
305
|
+
'post',
|
|
306
|
+
{
|
|
307
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
308
|
+
cid: this.cid,
|
|
309
|
+
configModule: this.configModule,
|
|
310
|
+
payload: {
|
|
311
|
+
data: {
|
|
312
|
+
action: 'off',
|
|
313
|
+
total: hours * 3600
|
|
314
|
+
},
|
|
315
|
+
method: 'addTimer',
|
|
316
|
+
source: 'APP'
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
Helpers.reqHeaderBypass()
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const success = this.checkResponse([response, status], 'setTimer');
|
|
323
|
+
if (!success) {
|
|
324
|
+
logger.error(`Failed to set timer to ${hours} hours for device: ${this.deviceName}`);
|
|
325
|
+
}
|
|
326
|
+
return success;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Clear timer
|
|
331
|
+
*/
|
|
332
|
+
async clearTimer(): Promise<boolean> {
|
|
333
|
+
if (!this.hasFeature('timer')) {
|
|
334
|
+
const error = 'Timer not supported';
|
|
335
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
336
|
+
throw new Error(error);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
logger.debug(`Clearing timer for device: ${this.deviceName}`);
|
|
340
|
+
const [response, status] = await this.callApi(
|
|
341
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
342
|
+
'post',
|
|
343
|
+
{
|
|
344
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
345
|
+
cid: this.cid,
|
|
346
|
+
configModule: this.configModule,
|
|
347
|
+
payload: {
|
|
348
|
+
data: {},
|
|
349
|
+
method: 'deleteTimer',
|
|
350
|
+
source: 'APP'
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
Helpers.reqHeaderBypass()
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
const success = this.checkResponse([response, status], 'clearTimer');
|
|
357
|
+
if (!success) {
|
|
358
|
+
logger.error(`Failed to clear timer for device: ${this.deviceName}`);
|
|
359
|
+
}
|
|
360
|
+
return success;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Turn automatic stop on
|
|
365
|
+
*/
|
|
366
|
+
async automaticStopOn(): Promise<boolean> {
|
|
367
|
+
logger.debug(`Setting automatic stop on for device: ${this.deviceName}`);
|
|
368
|
+
const [response, status] = await this.callApi(
|
|
369
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
370
|
+
'post',
|
|
371
|
+
{
|
|
372
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
373
|
+
cid: this.cid,
|
|
374
|
+
configModule: this.configModule,
|
|
375
|
+
payload: {
|
|
376
|
+
data: {
|
|
377
|
+
enabled: true
|
|
378
|
+
},
|
|
379
|
+
method: 'setAutomaticStop',
|
|
380
|
+
source: 'APP'
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
Helpers.reqHeaderBypass()
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const success = this.checkResponse([response, status], 'automaticStopOn');
|
|
387
|
+
if (!success) {
|
|
388
|
+
logger.error(`Failed to set automatic stop on for device: ${this.deviceName}`);
|
|
389
|
+
}
|
|
390
|
+
return success;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Turn automatic stop off
|
|
395
|
+
*/
|
|
396
|
+
async automaticStopOff(): Promise<boolean> {
|
|
397
|
+
logger.debug(`Setting automatic stop off for device: ${this.deviceName}`);
|
|
398
|
+
const [response, status] = await this.callApi(
|
|
399
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
400
|
+
'post',
|
|
401
|
+
{
|
|
402
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
403
|
+
cid: this.cid,
|
|
404
|
+
configModule: this.configModule,
|
|
405
|
+
payload: {
|
|
406
|
+
data: {
|
|
407
|
+
enabled: false
|
|
408
|
+
},
|
|
409
|
+
method: 'setAutomaticStop',
|
|
410
|
+
source: 'APP'
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
Helpers.reqHeaderBypass()
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const success = this.checkResponse([response, status], 'automaticStopOff');
|
|
417
|
+
if (!success) {
|
|
418
|
+
logger.error(`Failed to set automatic stop off for device: ${this.deviceName}`);
|
|
419
|
+
}
|
|
420
|
+
return success;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Set auto mode
|
|
425
|
+
*/
|
|
426
|
+
async setAutoMode(): Promise<boolean> {
|
|
427
|
+
logger.debug(`Setting auto mode for device: ${this.deviceName}`);
|
|
428
|
+
const success = await this.setMode('auto');
|
|
429
|
+
if (!success) {
|
|
430
|
+
logger.error(`Failed to set auto mode for device: ${this.deviceName}`);
|
|
431
|
+
}
|
|
432
|
+
return success;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Set manual mode
|
|
437
|
+
*/
|
|
438
|
+
async setManualMode(): Promise<boolean> {
|
|
439
|
+
logger.debug(`Setting manual mode for device: ${this.deviceName}`);
|
|
440
|
+
const success = await this.setMode('manual');
|
|
441
|
+
if (!success) {
|
|
442
|
+
logger.error(`Failed to set manual mode for device: ${this.deviceName}`);
|
|
443
|
+
}
|
|
444
|
+
return success;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Turn off display
|
|
449
|
+
*/
|
|
450
|
+
async turnOffDisplay(): Promise<boolean> {
|
|
451
|
+
logger.debug(`Turning off display for device: ${this.deviceName}`);
|
|
452
|
+
const success = await this.setDisplay(false);
|
|
453
|
+
if (!success) {
|
|
454
|
+
logger.error(`Failed to turn off display for device: ${this.deviceName}`);
|
|
455
|
+
}
|
|
456
|
+
return success;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Turn on display
|
|
461
|
+
*/
|
|
462
|
+
async turnOnDisplay(): Promise<boolean> {
|
|
463
|
+
logger.debug(`Turning on display for device: ${this.deviceName}`);
|
|
464
|
+
const success = await this.setDisplay(true);
|
|
465
|
+
if (!success) {
|
|
466
|
+
logger.error(`Failed to turn on display for device: ${this.deviceName}`);
|
|
467
|
+
}
|
|
468
|
+
return success;
|
|
469
|
+
}
|
|
470
|
+
}
|