tsvesync 1.0.18 → 1.0.20

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.
@@ -45,6 +45,8 @@ class Helpers {
45
45
  throw new Error('Manager accountId and token must be set');
46
46
  }
47
47
  return {
48
+ 'Content-Type': 'application/json; charset=UTF-8',
49
+ 'User-Agent': exports.BYPASS_HEADER_UA,
48
50
  'accept-language': 'en',
49
51
  'accountId': manager.accountId,
50
52
  'appVersion': exports.APP_VERSION,
@@ -71,9 +71,9 @@ export declare class VeSync {
71
71
  */
72
72
  static setDevId(devices: any[]): any[];
73
73
  /**
74
- * Process device list and instantiate device objects
74
+ * Process devices from API response
75
75
  */
76
- processDevices(devList: any[]): boolean;
76
+ private processDevices;
77
77
  /**
78
78
  * Get list of VeSync devices
79
79
  */
@@ -84,8 +84,31 @@ function objectFactory(details, manager) {
84
84
  try {
85
85
  // Add category to device details
86
86
  details.deviceCategory = category;
87
- const device = new DeviceClass(details, manager);
88
- return [category, device];
87
+ // Handle outdoor plug sub-devices
88
+ if (deviceType === 'ESO15-TB' && details.subDevices) {
89
+ const devices = [];
90
+ // Create a device instance for each sub-device
91
+ details.subDevices.forEach((subDevice) => {
92
+ const subDeviceDetails = {
93
+ ...details,
94
+ deviceName: subDevice.subDeviceName,
95
+ deviceStatus: subDevice.subDeviceStatus,
96
+ subDeviceNo: subDevice.subDeviceNo,
97
+ isSubDevice: true,
98
+ parentCid: details.cid,
99
+ // Generate a unique CID for the sub-device
100
+ cid: `${details.cid}_${subDevice.subDeviceNo}`
101
+ };
102
+ const device = new DeviceClass(subDeviceDetails, manager);
103
+ devices.push([category, device]);
104
+ });
105
+ // Return array of sub-devices
106
+ return devices[0]; // Return first device, manager will handle adding all devices
107
+ }
108
+ else {
109
+ const device = new DeviceClass(details, manager);
110
+ return [category, device];
111
+ }
89
112
  }
90
113
  catch (error) {
91
114
  logger_1.logger.error(`Error creating device instance for ${deviceType}:`, error);
@@ -265,57 +288,40 @@ class VeSync {
265
288
  return devices;
266
289
  }
267
290
  /**
268
- * Process device list and instantiate device objects
291
+ * Process devices from API response
269
292
  */
270
- processDevices(devList) {
271
- // Ensure devices have proper IDs
272
- const devices = VeSync.setDevId(devList);
273
- // Count current devices
274
- let numDevices = 0;
275
- for (const deviceList of Object.values(this._devList)) {
276
- numDevices += deviceList.length;
277
- }
278
- if (!devices || devices.length === 0) {
279
- logger_1.logger.warn('No devices found in api return');
280
- return false;
281
- }
282
- // Initialize new device list or remove old devices
283
- if (numDevices === 0) {
284
- logger_1.logger.debug('New device list initialized');
285
- }
286
- else {
287
- this.removeOldDevices(devices);
293
+ processDevices(deviceList) {
294
+ // Clear existing devices
295
+ for (const category of Object.keys(this._devList)) {
296
+ this._devList[category].length = 0;
288
297
  }
289
- // Filter out devices that already exist
290
- const newDevices = devices.filter(dev => this.addDevTest(dev));
291
- // Required keys for device instantiation
292
- const requiredKeys = ['deviceType', 'deviceName', 'deviceStatus', 'cid'];
293
- // Process each new device
294
- for (const dev of newDevices) {
295
- // Verify required device properties
296
- if (!requiredKeys.every(key => key in dev)) {
297
- logger_1.logger.debug(`Error adding device - missing required properties: ${dev.deviceName || 'Unknown'}`);
298
- continue;
299
- }
300
- const devType = dev.deviceType;
301
- try {
302
- // Create device instance using factory
303
- const [category, deviceObj] = objectFactory(dev, this);
304
- // Add device to appropriate category if valid
305
- if (deviceObj && category in this._devList) {
306
- this._devList[category].push(deviceObj);
307
- logger_1.logger.debug(`Added ${devType} device to ${category} category`);
308
- }
309
- else if (category === 'unknown') {
310
- logger_1.logger.debug(`Unknown device type: ${devType}`);
311
- }
298
+ // Process each device
299
+ deviceList.forEach(dev => {
300
+ const [category, device] = objectFactory(dev, this);
301
+ // Handle outdoor plug sub-devices
302
+ if (dev.deviceType === 'ESO15-TB' && dev.subDevices) {
303
+ dev.subDevices.forEach((subDev) => {
304
+ const subDeviceDetails = {
305
+ ...dev,
306
+ deviceName: subDev.subDeviceName,
307
+ deviceStatus: subDev.subDeviceStatus,
308
+ subDeviceNo: subDev.subDeviceNo,
309
+ isSubDevice: true,
310
+ parentCid: dev.cid,
311
+ cid: `${dev.cid}_${subDev.subDeviceNo}`
312
+ };
313
+ const [subCategory, subDevice] = objectFactory(subDeviceDetails, this);
314
+ if (subDevice && subCategory in this._devList) {
315
+ this._devList[subCategory].push(subDevice);
316
+ }
317
+ });
312
318
  }
313
- catch (err) {
314
- logger_1.logger.error(`Error creating device ${devType}:`, err);
315
- continue;
319
+ else if (device && category in this._devList) {
320
+ this._devList[category].push(device);
316
321
  }
317
- }
318
- return true;
322
+ });
323
+ // Update device list reference
324
+ this.devices = Object.values(this._devList).flat();
319
325
  }
320
326
  /**
321
327
  * Get list of VeSync devices
@@ -332,9 +338,7 @@ class VeSync {
332
338
  const [response] = await helpers_1.Helpers.callApi('/cloud/v2/deviceManaged/devices', 'post', helpers_1.Helpers.reqBody(this, 'devicelist'), helpers_1.Helpers.reqHeaders(this));
333
339
  if ((_a = response === null || response === void 0 ? void 0 : response.result) === null || _a === void 0 ? void 0 : _a.list) {
334
340
  const deviceList = response.result.list;
335
- procReturn = this.processDevices(deviceList);
336
- // Update the main devices array with all devices
337
- this.devices = Object.values(this._devList).flat();
341
+ this.processDevices(deviceList);
338
342
  // Log device discovery results
339
343
  logger_1.logger.debug('\n=== Device Discovery Summary ===');
340
344
  logger_1.logger.debug(`Total devices processed: ${deviceList.length}`);
@@ -95,7 +95,7 @@ class VeSyncBulb extends vesyncBaseDevice_1.VeSyncBaseDevice {
95
95
  this.colorValue = response.result.value || this.colorValue;
96
96
  }
97
97
  }
98
- logger_1.logger.debug(`[${this.deviceName}] Successfully retrieved bulb details`);
98
+ logger_1.logger.info(`[${this.deviceName}] Successfully retrieved bulb details`);
99
99
  }
100
100
  else {
101
101
  logger_1.logger.error(`[${this.deviceName}] Failed to get bulb details: ${JSON.stringify(response)}`);
@@ -107,7 +107,7 @@ class VeSyncBulb extends vesyncBaseDevice_1.VeSyncBaseDevice {
107
107
  async update() {
108
108
  logger_1.logger.debug(`[${this.deviceName}] Updating bulb information`);
109
109
  await this.getDetails();
110
- logger_1.logger.debug(`[${this.deviceName}] Successfully updated bulb information`);
110
+ logger_1.logger.info(`[${this.deviceName}] Successfully updated bulb information`);
111
111
  }
112
112
  /**
113
113
  * Turn bulb on
@@ -141,7 +141,7 @@ class VeSyncBulb extends vesyncBaseDevice_1.VeSyncBaseDevice {
141
141
  const [response] = await helpers_1.Helpers.callApi(endpoint, 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
142
142
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
143
143
  this.deviceStatus = 'on';
144
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned bulb on`);
144
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned bulb on`);
145
145
  return true;
146
146
  }
147
147
  logger_1.logger.error(`[${this.deviceName}] Failed to turn bulb on: ${JSON.stringify(response)}`);
@@ -179,7 +179,7 @@ class VeSyncBulb extends vesyncBaseDevice_1.VeSyncBaseDevice {
179
179
  const [response] = await helpers_1.Helpers.callApi(endpoint, 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
180
180
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
181
181
  this.deviceStatus = 'off';
182
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned bulb off`);
182
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned bulb off`);
183
183
  return true;
184
184
  }
185
185
  logger_1.logger.error(`[${this.deviceName}] Failed to turn bulb off: ${JSON.stringify(response)}`);
@@ -226,7 +226,7 @@ class VeSyncBulb extends vesyncBaseDevice_1.VeSyncBaseDevice {
226
226
  const [response] = await helpers_1.Helpers.callApi(endpoint, 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
227
227
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
228
228
  this.brightness = brightness;
229
- logger_1.logger.debug(`[${this.deviceName}] Successfully set brightness to ${brightness}`);
229
+ logger_1.logger.info(`[${this.deviceName}] Successfully set brightness to ${brightness}`);
230
230
  return true;
231
231
  }
232
232
  logger_1.logger.error(`[${this.deviceName}] Failed to set brightness: ${JSON.stringify(response)}`);
@@ -46,7 +46,7 @@ class VeSyncBulbESL100CW extends vesyncBulb_1.VeSyncBulb {
46
46
  const [response] = await helpers_1.Helpers.callApi('/cloud/v1/deviceManaged/bypass', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
47
47
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
48
48
  this.colorTemp = colorTemp;
49
- logger_1.logger.debug(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
49
+ logger_1.logger.info(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
50
50
  return true;
51
51
  }
52
52
  logger_1.logger.error(`[${this.deviceName}] Failed to set color temperature: ${JSON.stringify(response)}`);
@@ -88,7 +88,7 @@ class VeSyncBulbXYD0001 extends vesyncBulb_1.VeSyncBulb {
88
88
  const [response] = await helpers_1.Helpers.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
89
89
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
90
90
  this.colorTemp = colorTemp;
91
- logger_1.logger.debug(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
91
+ logger_1.logger.info(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
92
92
  return true;
93
93
  }
94
94
  logger_1.logger.error(`[${this.deviceName}] Failed to set color temperature: ${JSON.stringify(response)}`);
@@ -123,7 +123,7 @@ class VeSyncBulbXYD0001 extends vesyncBulb_1.VeSyncBulb {
123
123
  this.colorHue = hue;
124
124
  this.colorSaturation = saturation;
125
125
  this.colorValue = value;
126
- logger_1.logger.debug(`[${this.deviceName}] Successfully set HSV color`);
126
+ logger_1.logger.info(`[${this.deviceName}] Successfully set HSV color`);
127
127
  return true;
128
128
  }
129
129
  logger_1.logger.error(`[${this.deviceName}] Failed to set HSV color: ${JSON.stringify(response)}`);
@@ -152,7 +152,7 @@ class VeSyncBulbXYD0001 extends vesyncBulb_1.VeSyncBulb {
152
152
  const [response] = await helpers_1.Helpers.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
153
153
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
154
154
  this.colorMode = 'white';
155
- logger_1.logger.debug(`[${this.deviceName}] Successfully enabled white mode`);
155
+ logger_1.logger.info(`[${this.deviceName}] Successfully enabled white mode`);
156
156
  return true;
157
157
  }
158
158
  logger_1.logger.error(`[${this.deviceName}] Failed to enable white mode: ${JSON.stringify(response)}`);
@@ -192,7 +192,7 @@ class VeSyncBulbESL100MC extends vesyncBulb_1.VeSyncBulb {
192
192
  const [response] = await helpers_1.Helpers.callApi('/cloud/v1/deviceManaged/bypass', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
193
193
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
194
194
  this.rgbValues = { red, green, blue };
195
- logger_1.logger.debug(`[${this.deviceName}] Successfully set RGB color`);
195
+ logger_1.logger.info(`[${this.deviceName}] Successfully set RGB color`);
196
196
  return true;
197
197
  }
198
198
  logger_1.logger.error(`[${this.deviceName}] Failed to set RGB color: ${JSON.stringify(response)}`);
@@ -213,7 +213,7 @@ class VeSyncBulbESL100MC extends vesyncBulb_1.VeSyncBulb {
213
213
  const [response] = await helpers_1.Helpers.callApi('/cloud/v1/deviceManaged/bypass', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
214
214
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
215
215
  this.colorMode = 'white';
216
- logger_1.logger.debug(`[${this.deviceName}] Successfully enabled white mode`);
216
+ logger_1.logger.info(`[${this.deviceName}] Successfully enabled white mode`);
217
217
  return true;
218
218
  }
219
219
  logger_1.logger.error(`[${this.deviceName}] Failed to enable white mode: ${JSON.stringify(response)}`);
@@ -81,10 +81,27 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
81
81
  this.details = response;
82
82
  // Handle outdoor plugs with subdevices
83
83
  if (response.subDevices) {
84
- const subDevice = response.subDevices.find((dev) => dev.subDeviceName === this.deviceName);
84
+ const subDevice = response.subDevices.find((dev) => {
85
+ // Match by name (primary identifier)
86
+ if (dev.subDeviceName === this.deviceName) {
87
+ return true;
88
+ }
89
+ // Match by subDeviceNo if available
90
+ if ('subDeviceNo' in this && this.subDeviceNo === dev.subDeviceNo) {
91
+ return true;
92
+ }
93
+ // Match by cid/uuid if available (cid might be in format parentCid_subDeviceNo)
94
+ if (this.cid && this.cid.includes('_')) {
95
+ const [_, subId] = this.cid.split('_');
96
+ if (subId && dev.subDeviceNo === parseInt(subId)) {
97
+ return true;
98
+ }
99
+ }
100
+ return false;
101
+ });
85
102
  if (subDevice) {
86
103
  this.deviceStatus = subDevice.subDeviceStatus;
87
- logger_1.logger.debug(`[${this.deviceName}] Successfully retrieved subdevice status: ${this.deviceStatus}`);
104
+ logger_1.logger.info(`[${this.deviceName}] Successfully retrieved sub-device status: ${this.deviceStatus}`);
88
105
  return;
89
106
  }
90
107
  }
@@ -102,7 +119,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
102
119
  logger_1.logger.debug(`[${this.deviceName}] Device status not found in response: ${JSON.stringify(response)}`);
103
120
  return;
104
121
  }
105
- logger_1.logger.debug(`[${this.deviceName}] Successfully retrieved outlet details`);
122
+ logger_1.logger.info(`[${this.deviceName}] Successfully retrieved outlet details`);
106
123
  }
107
124
  else {
108
125
  logger_1.logger.debug(`[${this.deviceName}] Failed to get outlet details: ${JSON.stringify(response)}`);
@@ -142,7 +159,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
142
159
  // Handle different response formats
143
160
  if ((response === null || response === void 0 ? void 0 : response.code) === 0 && response.result) {
144
161
  this.energy = response.result;
145
- logger_1.logger.debug(`[${this.deviceName}] Successfully updated energy data`);
162
+ logger_1.logger.info(`[${this.deviceName}] Successfully updated energy data`);
146
163
  }
147
164
  else if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
148
165
  // Some devices return data directly in response
@@ -155,7 +172,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
155
172
  energyMonth: response.energy || '0',
156
173
  energyYear: response.energy || '0'
157
174
  };
158
- logger_1.logger.debug(`[${this.deviceName}] Successfully updated energy data`);
175
+ logger_1.logger.info(`[${this.deviceName}] Successfully updated energy data`);
159
176
  }
160
177
  else {
161
178
  // For error responses, set defaults but don't log as error
@@ -236,7 +253,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
236
253
  const [response] = await helpers_1.Helpers.callApi(isLegacyDevice ? `/${this.getApiPrefix()}/energy/week` : `/${this.getApiPrefix()}/energyweek`, isLegacyDevice ? 'get' : 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
237
254
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
238
255
  this.energy.week = response.result || response.energyWeek || '0';
239
- logger_1.logger.debug(`[${this.deviceName}] Successfully retrieved weekly energy data`);
256
+ logger_1.logger.info(`[${this.deviceName}] Successfully retrieved weekly energy data`);
240
257
  }
241
258
  else {
242
259
  this.energy.week = '0';
@@ -260,7 +277,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
260
277
  const [response] = await helpers_1.Helpers.callApi(isLegacyDevice ? `/${this.getApiPrefix()}/energy/month` : `/${this.getApiPrefix()}/energymonth`, isLegacyDevice ? 'get' : 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
261
278
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
262
279
  this.energy.month = response.result || response.energyMonth || '0';
263
- logger_1.logger.debug(`[${this.deviceName}] Successfully retrieved monthly energy data`);
280
+ logger_1.logger.info(`[${this.deviceName}] Successfully retrieved monthly energy data`);
264
281
  }
265
282
  else {
266
283
  this.energy.month = '0';
@@ -284,7 +301,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
284
301
  const [response] = await helpers_1.Helpers.callApi(isLegacyDevice ? `/${this.getApiPrefix()}/energy/year` : `/${this.getApiPrefix()}/energyyear`, isLegacyDevice ? 'get' : 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
285
302
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
286
303
  this.energy.year = response.result || response.energyYear || '0';
287
- logger_1.logger.debug(`[${this.deviceName}] Successfully retrieved yearly energy data`);
304
+ logger_1.logger.info(`[${this.deviceName}] Successfully retrieved yearly energy data`);
288
305
  }
289
306
  else {
290
307
  this.energy.year = '0';
@@ -300,7 +317,7 @@ class VeSyncOutlet extends vesyncBaseDevice_1.VeSyncBaseDevice {
300
317
  if (this.features.includes('energy')) {
301
318
  await this.updateEnergy();
302
319
  }
303
- logger_1.logger.debug(`[${this.deviceName}] Successfully updated outlet information`);
320
+ logger_1.logger.info(`[${this.deviceName}] Successfully updated outlet information`);
304
321
  }
305
322
  /**
306
323
  * Check if outlet has nightlight feature
@@ -57,6 +57,9 @@ export declare class VeSyncOutlet15A extends VeSyncOutlet {
57
57
  * VeSync Outdoor Plug
58
58
  */
59
59
  export declare class VeSyncOutdoorPlug extends VeSyncOutlet {
60
+ protected subDeviceNo?: number;
61
+ protected isSubDevice: boolean;
62
+ protected parentCid?: string;
60
63
  constructor(details: Record<string, any>, manager: VeSync);
61
64
  /**
62
65
  * Turn outlet on
@@ -19,11 +19,11 @@ class VeSyncOutlet7A extends vesyncOutlet_1.VeSyncOutlet {
19
19
  */
20
20
  async turnOn() {
21
21
  logger_1.logger.debug(`[${this.deviceName}] Turning outlet on`);
22
- const url = `/v1/wifi-switch-1.3/wifi-switch-1.3-${this.cid}/status/on`;
23
- const [response] = await helpers_1.Helpers.callApi(url, 'put', null, helpers_1.Helpers.reqHeaders(this.manager));
24
- if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
22
+ const url = `/v1/wifi-switch-1.3/${this.cid}/status/on`;
23
+ const [response, statusCode] = await helpers_1.Helpers.callApi(url, 'put', {}, helpers_1.Helpers.reqHeaders(this.manager));
24
+ if (statusCode === 200) {
25
25
  this.deviceStatus = 'on';
26
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
26
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet on`);
27
27
  return true;
28
28
  }
29
29
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -34,11 +34,11 @@ class VeSyncOutlet7A extends vesyncOutlet_1.VeSyncOutlet {
34
34
  */
35
35
  async turnOff() {
36
36
  logger_1.logger.debug(`[${this.deviceName}] Turning outlet off`);
37
- const url = `/v1/wifi-switch-1.3/wifi-switch-1.3-${this.cid}/status/off`;
38
- const [response] = await helpers_1.Helpers.callApi(url, 'put', null, helpers_1.Helpers.reqHeaders(this.manager));
39
- if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
37
+ const url = `/v1/wifi-switch-1.3/${this.cid}/status/off`;
38
+ const [response, statusCode] = await helpers_1.Helpers.callApi(url, 'put', {}, helpers_1.Helpers.reqHeaders(this.manager));
39
+ if (statusCode === 200) {
40
40
  this.deviceStatus = 'off';
41
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
41
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet off`);
42
42
  return true;
43
43
  }
44
44
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
@@ -66,7 +66,7 @@ class VeSyncOutlet10A extends vesyncOutlet_1.VeSyncOutlet {
66
66
  const [response] = await helpers_1.Helpers.callApi('/10a/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
67
67
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
68
68
  this.deviceStatus = 'on';
69
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
69
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet on`);
70
70
  return true;
71
71
  }
72
72
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -85,7 +85,7 @@ class VeSyncOutlet10A extends vesyncOutlet_1.VeSyncOutlet {
85
85
  const [response] = await helpers_1.Helpers.callApi('/10a/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
86
86
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
87
87
  this.deviceStatus = 'off';
88
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
88
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet off`);
89
89
  return true;
90
90
  }
91
91
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
@@ -113,7 +113,7 @@ class VeSyncOutlet15A extends vesyncOutlet_1.VeSyncOutlet {
113
113
  const [response] = await helpers_1.Helpers.callApi('/15a/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
114
114
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
115
115
  this.deviceStatus = 'on';
116
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
116
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet on`);
117
117
  return true;
118
118
  }
119
119
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -132,7 +132,7 @@ class VeSyncOutlet15A extends vesyncOutlet_1.VeSyncOutlet {
132
132
  const [response] = await helpers_1.Helpers.callApi('/15a/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
133
133
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
134
134
  this.deviceStatus = 'off';
135
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
135
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet off`);
136
136
  return true;
137
137
  }
138
138
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
@@ -155,7 +155,7 @@ class VeSyncOutlet15A extends vesyncOutlet_1.VeSyncOutlet {
155
155
  const [response] = await helpers_1.Helpers.callApi('/15a/v1/device/nightlightstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
156
156
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
157
157
  this.details.nightLightStatus = 'on';
158
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned nightlight on`);
158
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned nightlight on`);
159
159
  return true;
160
160
  }
161
161
  logger_1.logger.error(`[${this.deviceName}] Failed to turn nightlight on: ${JSON.stringify(response)}`);
@@ -178,7 +178,7 @@ class VeSyncOutlet15A extends vesyncOutlet_1.VeSyncOutlet {
178
178
  const [response] = await helpers_1.Helpers.callApi('/15a/v1/device/nightlightstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
179
179
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
180
180
  this.details.nightLightStatus = 'off';
181
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned nightlight off`);
181
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned nightlight off`);
182
182
  return true;
183
183
  }
184
184
  logger_1.logger.error(`[${this.deviceName}] Failed to turn nightlight off: ${JSON.stringify(response)}`);
@@ -192,22 +192,29 @@ exports.VeSyncOutlet15A = VeSyncOutlet15A;
192
192
  class VeSyncOutdoorPlug extends vesyncOutlet_1.VeSyncOutlet {
193
193
  constructor(details, manager) {
194
194
  super(details, manager);
195
+ this.isSubDevice = details.isSubDevice || false;
196
+ this.subDeviceNo = details.subDeviceNo;
197
+ this.parentCid = details.parentCid;
195
198
  }
196
199
  /**
197
200
  * Turn outlet on
198
201
  */
199
202
  async turnOn() {
203
+ if (!this.isSubDevice) {
204
+ logger_1.logger.error(`[${this.deviceName}] Cannot control parent device directly`);
205
+ return false;
206
+ }
200
207
  logger_1.logger.debug(`[${this.deviceName}] Turning outlet on`);
201
208
  const body = {
202
209
  ...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
203
210
  uuid: this.uuid,
204
211
  status: 'on',
205
- switchNo: 1
212
+ switchNo: this.subDeviceNo
206
213
  };
207
214
  const [response] = await helpers_1.Helpers.callApi('/outdoorsocket15a/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
208
215
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
209
216
  this.deviceStatus = 'on';
210
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
217
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet on`);
211
218
  return true;
212
219
  }
213
220
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -217,17 +224,21 @@ class VeSyncOutdoorPlug extends vesyncOutlet_1.VeSyncOutlet {
217
224
  * Turn outlet off
218
225
  */
219
226
  async turnOff() {
227
+ if (!this.isSubDevice) {
228
+ logger_1.logger.error(`[${this.deviceName}] Cannot control parent device directly`);
229
+ return false;
230
+ }
220
231
  logger_1.logger.debug(`[${this.deviceName}] Turning outlet off`);
221
232
  const body = {
222
233
  ...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
223
234
  uuid: this.uuid,
224
235
  status: 'off',
225
- switchNo: 1
236
+ switchNo: this.subDeviceNo
226
237
  };
227
238
  const [response] = await helpers_1.Helpers.callApi('/outdoorsocket15a/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
228
239
  if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
229
240
  this.deviceStatus = 'off';
230
- logger_1.logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
241
+ logger_1.logger.info(`[${this.deviceName}] Successfully turned outlet off`);
231
242
  return true;
232
243
  }
233
244
  logger_1.logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "A TypeScript library for interacting with VeSync smart home devices",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -70,6 +70,8 @@ export class Helpers {
70
70
  throw new Error('Manager accountId and token must be set');
71
71
  }
72
72
  return {
73
+ 'Content-Type': 'application/json; charset=UTF-8',
74
+ 'User-Agent': BYPASS_HEADER_UA,
73
75
  'accept-language': 'en',
74
76
  'accountId': manager.accountId,
75
77
  'appVersion': APP_VERSION,
package/src/lib/vesync.ts CHANGED
@@ -103,8 +103,33 @@ function objectFactory(details: Record<string, any>, manager: VeSync): [string,
103
103
  try {
104
104
  // Add category to device details
105
105
  details.deviceCategory = category;
106
- const device = new DeviceClass(details, manager);
107
- return [category, device];
106
+
107
+ // Handle outdoor plug sub-devices
108
+ if (deviceType === 'ESO15-TB' && details.subDevices) {
109
+ const devices: [string, VeSyncBaseDevice | null][] = [];
110
+
111
+ // Create a device instance for each sub-device
112
+ details.subDevices.forEach((subDevice: any) => {
113
+ const subDeviceDetails = {
114
+ ...details,
115
+ deviceName: subDevice.subDeviceName,
116
+ deviceStatus: subDevice.subDeviceStatus,
117
+ subDeviceNo: subDevice.subDeviceNo,
118
+ isSubDevice: true,
119
+ parentCid: details.cid,
120
+ // Generate a unique CID for the sub-device
121
+ cid: `${details.cid}_${subDevice.subDeviceNo}`
122
+ };
123
+ const device = new DeviceClass(subDeviceDetails, manager);
124
+ devices.push([category, device]);
125
+ });
126
+
127
+ // Return array of sub-devices
128
+ return devices[0]; // Return first device, manager will handle adding all devices
129
+ } else {
130
+ const device = new DeviceClass(details, manager);
131
+ return [category, device];
132
+ }
108
133
  } catch (error) {
109
134
  logger.error(`Error creating device instance for ${deviceType}:`, error);
110
135
  return [category, null];
@@ -331,63 +356,42 @@ export class VeSync {
331
356
  }
332
357
 
333
358
  /**
334
- * Process device list and instantiate device objects
359
+ * Process devices from API response
335
360
  */
336
- processDevices(devList: any[]): boolean {
337
- // Ensure devices have proper IDs
338
- const devices = VeSync.setDevId(devList);
339
-
340
- // Count current devices
341
- let numDevices = 0;
342
- for (const deviceList of Object.values(this._devList)) {
343
- numDevices += deviceList.length;
344
- }
345
-
346
- if (!devices || devices.length === 0) {
347
- logger.warn('No devices found in api return');
348
- return false;
349
- }
350
-
351
- // Initialize new device list or remove old devices
352
- if (numDevices === 0) {
353
- logger.debug('New device list initialized');
354
- } else {
355
- this.removeOldDevices(devices);
361
+ private processDevices(deviceList: any[]): void {
362
+ // Clear existing devices
363
+ for (const category of Object.keys(this._devList)) {
364
+ this._devList[category].length = 0;
356
365
  }
357
366
 
358
- // Filter out devices that already exist
359
- const newDevices = devices.filter(dev => this.addDevTest(dev));
360
-
361
- // Required keys for device instantiation
362
- const requiredKeys = ['deviceType', 'deviceName', 'deviceStatus', 'cid'];
363
-
364
- // Process each new device
365
- for (const dev of newDevices) {
366
- // Verify required device properties
367
- if (!requiredKeys.every(key => key in dev)) {
368
- logger.debug(`Error adding device - missing required properties: ${dev.deviceName || 'Unknown'}`);
369
- continue;
370
- }
371
-
372
- const devType = dev.deviceType;
373
- try {
374
- // Create device instance using factory
375
- const [category, deviceObj] = objectFactory(dev, this);
376
-
377
- // Add device to appropriate category if valid
378
- if (deviceObj && category in this._devList) {
379
- this._devList[category].push(deviceObj);
380
- logger.debug(`Added ${devType} device to ${category} category`);
381
- } else if (category === 'unknown') {
382
- logger.debug(`Unknown device type: ${devType}`);
383
- }
384
- } catch (err) {
385
- logger.error(`Error creating device ${devType}:`, err);
386
- continue;
367
+ // Process each device
368
+ deviceList.forEach(dev => {
369
+ const [category, device] = objectFactory(dev, this);
370
+
371
+ // Handle outdoor plug sub-devices
372
+ if (dev.deviceType === 'ESO15-TB' && dev.subDevices) {
373
+ dev.subDevices.forEach((subDev: any) => {
374
+ const subDeviceDetails = {
375
+ ...dev,
376
+ deviceName: subDev.subDeviceName,
377
+ deviceStatus: subDev.subDeviceStatus,
378
+ subDeviceNo: subDev.subDeviceNo,
379
+ isSubDevice: true,
380
+ parentCid: dev.cid,
381
+ cid: `${dev.cid}_${subDev.subDeviceNo}`
382
+ };
383
+ const [subCategory, subDevice] = objectFactory(subDeviceDetails, this);
384
+ if (subDevice && subCategory in this._devList) {
385
+ this._devList[subCategory].push(subDevice);
386
+ }
387
+ });
388
+ } else if (device && category in this._devList) {
389
+ this._devList[category].push(device);
387
390
  }
388
- }
391
+ });
389
392
 
390
- return true;
393
+ // Update device list reference
394
+ this.devices = Object.values(this._devList).flat();
391
395
  }
392
396
 
393
397
  /**
@@ -412,10 +416,7 @@ export class VeSync {
412
416
 
413
417
  if (response?.result?.list) {
414
418
  const deviceList = response.result.list;
415
- procReturn = this.processDevices(deviceList);
416
-
417
- // Update the main devices array with all devices
418
- this.devices = Object.values(this._devList).flat();
419
+ this.processDevices(deviceList);
419
420
 
420
421
  // Log device discovery results
421
422
  logger.debug('\n=== Device Discovery Summary ===');
@@ -120,7 +120,7 @@ export abstract class VeSyncBulb extends VeSyncBaseDevice {
120
120
  this.colorValue = response.result.value || this.colorValue;
121
121
  }
122
122
  }
123
- logger.debug(`[${this.deviceName}] Successfully retrieved bulb details`);
123
+ logger.info(`[${this.deviceName}] Successfully retrieved bulb details`);
124
124
  } else {
125
125
  logger.error(`[${this.deviceName}] Failed to get bulb details: ${JSON.stringify(response)}`);
126
126
  }
@@ -132,7 +132,7 @@ export abstract class VeSyncBulb extends VeSyncBaseDevice {
132
132
  async update(): Promise<void> {
133
133
  logger.debug(`[${this.deviceName}] Updating bulb information`);
134
134
  await this.getDetails();
135
- logger.debug(`[${this.deviceName}] Successfully updated bulb information`);
135
+ logger.info(`[${this.deviceName}] Successfully updated bulb information`);
136
136
  }
137
137
 
138
138
  /**
@@ -175,7 +175,7 @@ export abstract class VeSyncBulb extends VeSyncBaseDevice {
175
175
 
176
176
  if (response?.code === 0) {
177
177
  this.deviceStatus = 'on';
178
- logger.debug(`[${this.deviceName}] Successfully turned bulb on`);
178
+ logger.info(`[${this.deviceName}] Successfully turned bulb on`);
179
179
  return true;
180
180
  }
181
181
  logger.error(`[${this.deviceName}] Failed to turn bulb on: ${JSON.stringify(response)}`);
@@ -222,7 +222,7 @@ export abstract class VeSyncBulb extends VeSyncBaseDevice {
222
222
 
223
223
  if (response?.code === 0) {
224
224
  this.deviceStatus = 'off';
225
- logger.debug(`[${this.deviceName}] Successfully turned bulb off`);
225
+ logger.info(`[${this.deviceName}] Successfully turned bulb off`);
226
226
  return true;
227
227
  }
228
228
  logger.error(`[${this.deviceName}] Failed to turn bulb off: ${JSON.stringify(response)}`);
@@ -279,7 +279,7 @@ export abstract class VeSyncBulb extends VeSyncBaseDevice {
279
279
 
280
280
  if (response?.code === 0) {
281
281
  this.brightness = brightness;
282
- logger.debug(`[${this.deviceName}] Successfully set brightness to ${brightness}`);
282
+ logger.info(`[${this.deviceName}] Successfully set brightness to ${brightness}`);
283
283
  return true;
284
284
  }
285
285
  logger.error(`[${this.deviceName}] Failed to set brightness: ${JSON.stringify(response)}`);
@@ -56,7 +56,7 @@ export class VeSyncBulbESL100CW extends VeSyncBulb {
56
56
 
57
57
  if (response?.code === 0) {
58
58
  this.colorTemp = colorTemp;
59
- logger.debug(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
59
+ logger.info(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
60
60
  return true;
61
61
  }
62
62
  logger.error(`[${this.deviceName}] Failed to set color temperature: ${JSON.stringify(response)}`);
@@ -107,7 +107,7 @@ export class VeSyncBulbXYD0001 extends VeSyncBulb {
107
107
 
108
108
  if (response?.code === 0) {
109
109
  this.colorTemp = colorTemp;
110
- logger.debug(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
110
+ logger.info(`[${this.deviceName}] Successfully set color temperature to ${colorTemp}`);
111
111
  return true;
112
112
  }
113
113
  logger.error(`[${this.deviceName}] Failed to set color temperature: ${JSON.stringify(response)}`);
@@ -151,7 +151,7 @@ export class VeSyncBulbXYD0001 extends VeSyncBulb {
151
151
  this.colorHue = hue;
152
152
  this.colorSaturation = saturation;
153
153
  this.colorValue = value;
154
- logger.debug(`[${this.deviceName}] Successfully set HSV color`);
154
+ logger.info(`[${this.deviceName}] Successfully set HSV color`);
155
155
  return true;
156
156
  }
157
157
  logger.error(`[${this.deviceName}] Failed to set HSV color: ${JSON.stringify(response)}`);
@@ -188,7 +188,7 @@ export class VeSyncBulbXYD0001 extends VeSyncBulb {
188
188
 
189
189
  if (response?.code === 0) {
190
190
  this.colorMode = 'white';
191
- logger.debug(`[${this.deviceName}] Successfully enabled white mode`);
191
+ logger.info(`[${this.deviceName}] Successfully enabled white mode`);
192
192
  return true;
193
193
  }
194
194
  logger.error(`[${this.deviceName}] Failed to enable white mode: ${JSON.stringify(response)}`);
@@ -238,7 +238,7 @@ export class VeSyncBulbESL100MC extends VeSyncBulb {
238
238
 
239
239
  if (response?.code === 0) {
240
240
  this.rgbValues = { red, green, blue };
241
- logger.debug(`[${this.deviceName}] Successfully set RGB color`);
241
+ logger.info(`[${this.deviceName}] Successfully set RGB color`);
242
242
  return true;
243
243
  }
244
244
  logger.error(`[${this.deviceName}] Failed to set RGB color: ${JSON.stringify(response)}`);
@@ -267,7 +267,7 @@ export class VeSyncBulbESL100MC extends VeSyncBulb {
267
267
 
268
268
  if (response?.code === 0) {
269
269
  this.colorMode = 'white';
270
- logger.debug(`[${this.deviceName}] Successfully enabled white mode`);
270
+ logger.info(`[${this.deviceName}] Successfully enabled white mode`);
271
271
  return true;
272
272
  }
273
273
  logger.error(`[${this.deviceName}] Failed to enable white mode: ${JSON.stringify(response)}`);
@@ -101,12 +101,31 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
101
101
 
102
102
  // Handle outdoor plugs with subdevices
103
103
  if (response.subDevices) {
104
- const subDevice = response.subDevices.find(
105
- (dev: any) => dev.subDeviceName === this.deviceName
106
- );
104
+ const subDevice = response.subDevices.find((dev: any) => {
105
+ // Match by name (primary identifier)
106
+ if (dev.subDeviceName === this.deviceName) {
107
+ return true;
108
+ }
109
+
110
+ // Match by subDeviceNo if available
111
+ if ('subDeviceNo' in this && (this as any).subDeviceNo === dev.subDeviceNo) {
112
+ return true;
113
+ }
114
+
115
+ // Match by cid/uuid if available (cid might be in format parentCid_subDeviceNo)
116
+ if (this.cid && this.cid.includes('_')) {
117
+ const [_, subId] = this.cid.split('_');
118
+ if (subId && dev.subDeviceNo === parseInt(subId)) {
119
+ return true;
120
+ }
121
+ }
122
+
123
+ return false;
124
+ });
125
+
107
126
  if (subDevice) {
108
127
  this.deviceStatus = subDevice.subDeviceStatus;
109
- logger.debug(`[${this.deviceName}] Successfully retrieved subdevice status: ${this.deviceStatus}`);
128
+ logger.info(`[${this.deviceName}] Successfully retrieved sub-device status: ${this.deviceStatus}`);
110
129
  return;
111
130
  }
112
131
  }
@@ -122,7 +141,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
122
141
  logger.debug(`[${this.deviceName}] Device status not found in response: ${JSON.stringify(response)}`);
123
142
  return;
124
143
  }
125
- logger.debug(`[${this.deviceName}] Successfully retrieved outlet details`);
144
+ logger.info(`[${this.deviceName}] Successfully retrieved outlet details`);
126
145
  } else {
127
146
  logger.debug(`[${this.deviceName}] Failed to get outlet details: ${JSON.stringify(response)}`);
128
147
  }
@@ -168,7 +187,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
168
187
  // Handle different response formats
169
188
  if (response?.code === 0 && response.result) {
170
189
  this.energy = response.result;
171
- logger.debug(`[${this.deviceName}] Successfully updated energy data`);
190
+ logger.info(`[${this.deviceName}] Successfully updated energy data`);
172
191
  } else if (response?.code === 0) {
173
192
  // Some devices return data directly in response
174
193
  this.energy = {
@@ -180,7 +199,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
180
199
  energyMonth: response.energy || '0',
181
200
  energyYear: response.energy || '0'
182
201
  };
183
- logger.debug(`[${this.deviceName}] Successfully updated energy data`);
202
+ logger.info(`[${this.deviceName}] Successfully updated energy data`);
184
203
  } else {
185
204
  // For error responses, set defaults but don't log as error
186
205
  this.energy = {
@@ -271,7 +290,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
271
290
 
272
291
  if (response?.code === 0) {
273
292
  this.energy.week = response.result || response.energyWeek || '0';
274
- logger.debug(`[${this.deviceName}] Successfully retrieved weekly energy data`);
293
+ logger.info(`[${this.deviceName}] Successfully retrieved weekly energy data`);
275
294
  } else {
276
295
  this.energy.week = '0';
277
296
  logger.debug(`[${this.deviceName}] Failed to get weekly energy data: ${JSON.stringify(response)}`);
@@ -303,7 +322,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
303
322
 
304
323
  if (response?.code === 0) {
305
324
  this.energy.month = response.result || response.energyMonth || '0';
306
- logger.debug(`[${this.deviceName}] Successfully retrieved monthly energy data`);
325
+ logger.info(`[${this.deviceName}] Successfully retrieved monthly energy data`);
307
326
  } else {
308
327
  this.energy.month = '0';
309
328
  logger.debug(`[${this.deviceName}] Failed to get monthly energy data: ${JSON.stringify(response)}`);
@@ -335,7 +354,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
335
354
 
336
355
  if (response?.code === 0) {
337
356
  this.energy.year = response.result || response.energyYear || '0';
338
- logger.debug(`[${this.deviceName}] Successfully retrieved yearly energy data`);
357
+ logger.info(`[${this.deviceName}] Successfully retrieved yearly energy data`);
339
358
  } else {
340
359
  this.energy.year = '0';
341
360
  logger.debug(`[${this.deviceName}] Failed to get yearly energy data: ${JSON.stringify(response)}`);
@@ -351,7 +370,7 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
351
370
  if (this.features.includes('energy')) {
352
371
  await this.updateEnergy();
353
372
  }
354
- logger.debug(`[${this.deviceName}] Successfully updated outlet information`);
373
+ logger.info(`[${this.deviceName}] Successfully updated outlet information`);
355
374
  }
356
375
 
357
376
  /**
@@ -20,17 +20,17 @@ export class VeSyncOutlet7A extends VeSyncOutlet {
20
20
  */
21
21
  async turnOn(): Promise<boolean> {
22
22
  logger.debug(`[${this.deviceName}] Turning outlet on`);
23
- const url = `/v1/wifi-switch-1.3/wifi-switch-1.3-${this.cid}/status/on`;
24
- const [response] = await Helpers.callApi(
23
+ const url = `/v1/wifi-switch-1.3/${this.cid}/status/on`;
24
+ const [response, statusCode] = await Helpers.callApi(
25
25
  url,
26
26
  'put',
27
- null,
27
+ {},
28
28
  Helpers.reqHeaders(this.manager)
29
29
  );
30
30
 
31
- if (response?.code === 0) {
31
+ if (statusCode === 200) {
32
32
  this.deviceStatus = 'on';
33
- logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
33
+ logger.info(`[${this.deviceName}] Successfully turned outlet on`);
34
34
  return true;
35
35
  }
36
36
  logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -42,17 +42,17 @@ export class VeSyncOutlet7A extends VeSyncOutlet {
42
42
  */
43
43
  async turnOff(): Promise<boolean> {
44
44
  logger.debug(`[${this.deviceName}] Turning outlet off`);
45
- const url = `/v1/wifi-switch-1.3/wifi-switch-1.3-${this.cid}/status/off`;
46
- const [response] = await Helpers.callApi(
45
+ const url = `/v1/wifi-switch-1.3/${this.cid}/status/off`;
46
+ const [response, statusCode] = await Helpers.callApi(
47
47
  url,
48
48
  'put',
49
- null,
49
+ {},
50
50
  Helpers.reqHeaders(this.manager)
51
51
  );
52
52
 
53
- if (response?.code === 0) {
53
+ if (statusCode === 200) {
54
54
  this.deviceStatus = 'off';
55
- logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
55
+ logger.info(`[${this.deviceName}] Successfully turned outlet off`);
56
56
  return true;
57
57
  }
58
58
  logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
@@ -88,7 +88,7 @@ export class VeSyncOutlet10A extends VeSyncOutlet {
88
88
 
89
89
  if (response?.code === 0) {
90
90
  this.deviceStatus = 'on';
91
- logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
91
+ logger.info(`[${this.deviceName}] Successfully turned outlet on`);
92
92
  return true;
93
93
  }
94
94
  logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -115,7 +115,7 @@ export class VeSyncOutlet10A extends VeSyncOutlet {
115
115
 
116
116
  if (response?.code === 0) {
117
117
  this.deviceStatus = 'off';
118
- logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
118
+ logger.info(`[${this.deviceName}] Successfully turned outlet off`);
119
119
  return true;
120
120
  }
121
121
  logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
@@ -151,7 +151,7 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
151
151
 
152
152
  if (response?.code === 0) {
153
153
  this.deviceStatus = 'on';
154
- logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
154
+ logger.info(`[${this.deviceName}] Successfully turned outlet on`);
155
155
  return true;
156
156
  }
157
157
  logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -178,7 +178,7 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
178
178
 
179
179
  if (response?.code === 0) {
180
180
  this.deviceStatus = 'off';
181
- logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
181
+ logger.info(`[${this.deviceName}] Successfully turned outlet off`);
182
182
  return true;
183
183
  }
184
184
  logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
@@ -210,7 +210,7 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
210
210
 
211
211
  if (response?.code === 0) {
212
212
  this.details.nightLightStatus = 'on';
213
- logger.debug(`[${this.deviceName}] Successfully turned nightlight on`);
213
+ logger.info(`[${this.deviceName}] Successfully turned nightlight on`);
214
214
  return true;
215
215
  }
216
216
  logger.error(`[${this.deviceName}] Failed to turn nightlight on: ${JSON.stringify(response)}`);
@@ -242,7 +242,7 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
242
242
 
243
243
  if (response?.code === 0) {
244
244
  this.details.nightLightStatus = 'off';
245
- logger.debug(`[${this.deviceName}] Successfully turned nightlight off`);
245
+ logger.info(`[${this.deviceName}] Successfully turned nightlight off`);
246
246
  return true;
247
247
  }
248
248
  logger.error(`[${this.deviceName}] Failed to turn nightlight off: ${JSON.stringify(response)}`);
@@ -254,20 +254,32 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
254
254
  * VeSync Outdoor Plug
255
255
  */
256
256
  export class VeSyncOutdoorPlug extends VeSyncOutlet {
257
+ protected subDeviceNo?: number;
258
+ protected isSubDevice: boolean;
259
+ protected parentCid?: string;
260
+
257
261
  constructor(details: Record<string, any>, manager: VeSync) {
258
262
  super(details, manager);
263
+ this.isSubDevice = details.isSubDevice || false;
264
+ this.subDeviceNo = details.subDeviceNo;
265
+ this.parentCid = details.parentCid;
259
266
  }
260
267
 
261
268
  /**
262
269
  * Turn outlet on
263
270
  */
264
271
  async turnOn(): Promise<boolean> {
272
+ if (!this.isSubDevice) {
273
+ logger.error(`[${this.deviceName}] Cannot control parent device directly`);
274
+ return false;
275
+ }
276
+
265
277
  logger.debug(`[${this.deviceName}] Turning outlet on`);
266
278
  const body = {
267
279
  ...Helpers.reqBody(this.manager, 'devicestatus'),
268
280
  uuid: this.uuid,
269
281
  status: 'on',
270
- switchNo: 1
282
+ switchNo: this.subDeviceNo
271
283
  };
272
284
 
273
285
  const [response] = await Helpers.callApi(
@@ -279,7 +291,7 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
279
291
 
280
292
  if (response?.code === 0) {
281
293
  this.deviceStatus = 'on';
282
- logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
294
+ logger.info(`[${this.deviceName}] Successfully turned outlet on`);
283
295
  return true;
284
296
  }
285
297
  logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
@@ -290,12 +302,17 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
290
302
  * Turn outlet off
291
303
  */
292
304
  async turnOff(): Promise<boolean> {
305
+ if (!this.isSubDevice) {
306
+ logger.error(`[${this.deviceName}] Cannot control parent device directly`);
307
+ return false;
308
+ }
309
+
293
310
  logger.debug(`[${this.deviceName}] Turning outlet off`);
294
311
  const body = {
295
312
  ...Helpers.reqBody(this.manager, 'devicestatus'),
296
313
  uuid: this.uuid,
297
314
  status: 'off',
298
- switchNo: 1
315
+ switchNo: this.subDeviceNo
299
316
  };
300
317
 
301
318
  const [response] = await Helpers.callApi(
@@ -307,7 +324,7 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
307
324
 
308
325
  if (response?.code === 0) {
309
326
  this.deviceStatus = 'off';
310
- logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
327
+ logger.info(`[${this.deviceName}] Successfully turned outlet off`);
311
328
  return true;
312
329
  }
313
330
  logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);