tsvesync 1.0.12 → 1.0.13

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.
@@ -5,6 +5,38 @@
5
5
  import { VeSyncBaseDevice } from './vesyncBaseDevice';
6
6
  import { VeSync } from './vesync';
7
7
  import { Helpers } from './helpers';
8
+ import { logger } from './logger';
9
+
10
+ interface OutletConfig {
11
+ [key: string]: {
12
+ module: string;
13
+ features: string[];
14
+ };
15
+ }
16
+
17
+ // Outlet configuration
18
+ export const outletConfig: OutletConfig = {
19
+ 'wifi-switch-1.3': {
20
+ module: 'VeSyncOutlet7A',
21
+ features: ['energy']
22
+ },
23
+ 'ESW03-USA': {
24
+ module: 'VeSyncOutlet10A',
25
+ features: ['energy']
26
+ },
27
+ 'ESW01-EU': {
28
+ module: 'VeSyncOutlet10A',
29
+ features: ['energy']
30
+ },
31
+ 'ESW15-USA': {
32
+ module: 'VeSyncOutlet15A',
33
+ features: ['energy', 'nightlight']
34
+ },
35
+ 'ESO15-TB': {
36
+ module: 'VeSyncOutdoorPlug',
37
+ features: ['energy']
38
+ }
39
+ };
8
40
 
9
41
  /**
10
42
  * VeSync Outlet Base Class
@@ -12,17 +44,20 @@ import { Helpers } from './helpers';
12
44
  export abstract class VeSyncOutlet extends VeSyncBaseDevice {
13
45
  protected energy: Record<string, any>;
14
46
  protected details: Record<string, any>;
47
+ protected features: string[];
15
48
 
16
49
  constructor(details: Record<string, any>, manager: VeSync) {
17
50
  super(details, manager);
18
51
  this.energy = {};
19
52
  this.details = details;
53
+ this.features = outletConfig[this.deviceType]?.features || [];
20
54
  }
21
55
 
22
56
  /**
23
57
  * Get outlet details
24
58
  */
25
59
  async getDetails(): Promise<void> {
60
+ logger.debug(`[${this.deviceName}] Getting outlet details`);
26
61
  const url = `/v1/${this.deviceType}/${this.deviceType}-${this.cid}/detail`;
27
62
  const [response] = await Helpers.callApi(
28
63
  url,
@@ -34,6 +69,9 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
34
69
  if (response?.code === 0) {
35
70
  this.details = response.result;
36
71
  this.deviceStatus = response.result.deviceStatus;
72
+ logger.debug(`[${this.deviceName}] Successfully retrieved outlet details`);
73
+ } else {
74
+ logger.error(`[${this.deviceName}] Failed to get outlet details: ${JSON.stringify(response)}`);
37
75
  }
38
76
  }
39
77
 
@@ -41,6 +79,12 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
41
79
  * Update outlet energy data
42
80
  */
43
81
  async updateEnergy(): Promise<void> {
82
+ if (!this.features.includes('energy')) {
83
+ logger.debug(`[${this.deviceName}] Energy monitoring not supported`);
84
+ return;
85
+ }
86
+
87
+ logger.debug(`[${this.deviceName}] Updating energy data`);
44
88
  const url = `/v1/${this.deviceType}/${this.deviceType}-${this.cid}/energy/detail`;
45
89
  const [response] = await Helpers.callApi(
46
90
  url,
@@ -51,6 +95,9 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
51
95
 
52
96
  if (response?.code === 0) {
53
97
  this.energy = response.result;
98
+ logger.debug(`[${this.deviceName}] Successfully updated energy data`);
99
+ } else {
100
+ logger.error(`[${this.deviceName}] Failed to update energy data: ${JSON.stringify(response)}`);
54
101
  }
55
102
  }
56
103
 
@@ -58,6 +105,18 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
58
105
  * Get outlet energy usage
59
106
  */
60
107
  async getEnergyUsage(): Promise<Record<string, any>> {
108
+ if (!this.features.includes('energy')) {
109
+ logger.debug(`[${this.deviceName}] Energy monitoring not supported`);
110
+ return {
111
+ power: 'Not supported',
112
+ voltage: 'Not supported',
113
+ energy_today: 'Not supported',
114
+ energy_week: 'Not supported',
115
+ energy_month: 'Not supported',
116
+ energy_year: 'Not supported'
117
+ };
118
+ }
119
+
61
120
  await this.updateEnergy();
62
121
  return {
63
122
  power: this.energy.power || 'Not available',
@@ -73,24 +132,53 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
73
132
  * Get outlet status
74
133
  */
75
134
  async getStatus(): Promise<string> {
135
+ logger.debug(`[${this.deviceName}] Getting outlet status`);
76
136
  await this.getDetails();
77
137
  return this.deviceStatus;
78
138
  }
79
139
 
140
+ /**
141
+ * Get API prefix based on device type
142
+ */
143
+ private getApiPrefix(): string {
144
+ if (this.deviceType === 'wifi-switch-1.3') {
145
+ return `v1/device/${this.deviceType}-${this.cid}`;
146
+ } else if (this.deviceType.startsWith('ESW15') || this.deviceType.startsWith('ESO15')) {
147
+ return '15a/v1/device';
148
+ } else if (this.deviceType.startsWith('ESW03') || this.deviceType.startsWith('ESW01')) {
149
+ return '10a/v1/device';
150
+ }
151
+ return 'v1/device';
152
+ }
153
+
80
154
  /**
81
155
  * Get weekly energy data
82
156
  */
83
157
  async getWeeklyEnergy(): Promise<void> {
84
- const url = `/v1/${this.deviceType}/${this.deviceType}-${this.cid}/energy/week`;
158
+ if (!this.features.includes('energy')) {
159
+ logger.debug(`[${this.deviceName}] Energy monitoring not supported`);
160
+ return;
161
+ }
162
+
163
+ logger.debug(`[${this.deviceName}] Getting weekly energy data`);
164
+ const isLegacyDevice = this.deviceType === 'wifi-switch-1.3';
165
+ const body = isLegacyDevice ? null : {
166
+ ...Helpers.reqBody(this.manager, 'energyweek'),
167
+ uuid: this.uuid
168
+ };
169
+
85
170
  const [response] = await Helpers.callApi(
86
- url,
87
- 'get',
88
- null,
171
+ isLegacyDevice ? `/${this.getApiPrefix()}/energy/week` : `/${this.getApiPrefix()}/energyweek`,
172
+ isLegacyDevice ? 'get' : 'post',
173
+ body,
89
174
  Helpers.reqHeaders(this.manager)
90
175
  );
91
176
 
92
177
  if (response?.code === 0) {
93
178
  this.energy.week = response.result;
179
+ logger.debug(`[${this.deviceName}] Successfully retrieved weekly energy data`);
180
+ } else {
181
+ logger.error(`[${this.deviceName}] Failed to get weekly energy data: ${JSON.stringify(response)}`);
94
182
  }
95
183
  }
96
184
 
@@ -98,16 +186,30 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
98
186
  * Get monthly energy data
99
187
  */
100
188
  async getMonthlyEnergy(): Promise<void> {
101
- const url = `/v1/${this.deviceType}/${this.deviceType}-${this.cid}/energy/month`;
189
+ if (!this.features.includes('energy')) {
190
+ logger.debug(`[${this.deviceName}] Energy monitoring not supported`);
191
+ return;
192
+ }
193
+
194
+ logger.debug(`[${this.deviceName}] Getting monthly energy data`);
195
+ const isLegacyDevice = this.deviceType === 'wifi-switch-1.3';
196
+ const body = isLegacyDevice ? null : {
197
+ ...Helpers.reqBody(this.manager, 'energymonth'),
198
+ uuid: this.uuid
199
+ };
200
+
102
201
  const [response] = await Helpers.callApi(
103
- url,
104
- 'get',
105
- null,
202
+ isLegacyDevice ? `/${this.getApiPrefix()}/energy/month` : `/${this.getApiPrefix()}/energymonth`,
203
+ isLegacyDevice ? 'get' : 'post',
204
+ body,
106
205
  Helpers.reqHeaders(this.manager)
107
206
  );
108
207
 
109
208
  if (response?.code === 0) {
110
209
  this.energy.month = response.result;
210
+ logger.debug(`[${this.deviceName}] Successfully retrieved monthly energy data`);
211
+ } else {
212
+ logger.error(`[${this.deviceName}] Failed to get monthly energy data: ${JSON.stringify(response)}`);
111
213
  }
112
214
  }
113
215
 
@@ -115,16 +217,30 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
115
217
  * Get yearly energy data
116
218
  */
117
219
  async getYearlyEnergy(): Promise<void> {
118
- const url = `/v1/${this.deviceType}/${this.deviceType}-${this.cid}/energy/year`;
220
+ if (!this.features.includes('energy')) {
221
+ logger.debug(`[${this.deviceName}] Energy monitoring not supported`);
222
+ return;
223
+ }
224
+
225
+ logger.debug(`[${this.deviceName}] Getting yearly energy data`);
226
+ const isLegacyDevice = this.deviceType === 'wifi-switch-1.3';
227
+ const body = isLegacyDevice ? null : {
228
+ ...Helpers.reqBody(this.manager, 'energyyear'),
229
+ uuid: this.uuid
230
+ };
231
+
119
232
  const [response] = await Helpers.callApi(
120
- url,
121
- 'get',
122
- null,
233
+ isLegacyDevice ? `/${this.getApiPrefix()}/energy/year` : `/${this.getApiPrefix()}/energyyear`,
234
+ isLegacyDevice ? 'get' : 'post',
235
+ body,
123
236
  Helpers.reqHeaders(this.manager)
124
237
  );
125
238
 
126
239
  if (response?.code === 0) {
127
240
  this.energy.year = response.result;
241
+ logger.debug(`[${this.deviceName}] Successfully retrieved yearly energy data`);
242
+ } else {
243
+ logger.error(`[${this.deviceName}] Failed to get yearly energy data: ${JSON.stringify(response)}`);
128
244
  }
129
245
  }
130
246
 
@@ -132,8 +248,19 @@ export abstract class VeSyncOutlet extends VeSyncBaseDevice {
132
248
  * Update outlet details and energy info
133
249
  */
134
250
  async update(): Promise<void> {
251
+ logger.debug(`[${this.deviceName}] Updating outlet information`);
135
252
  await this.getDetails();
136
- await this.updateEnergy();
253
+ if (this.features.includes('energy')) {
254
+ await this.updateEnergy();
255
+ }
256
+ logger.debug(`[${this.deviceName}] Successfully updated outlet information`);
257
+ }
258
+
259
+ /**
260
+ * Check if outlet has nightlight feature
261
+ */
262
+ hasNightlight(): boolean {
263
+ return this.features.includes('nightlight');
137
264
  }
138
265
 
139
266
  /**
@@ -5,6 +5,7 @@
5
5
  import { VeSyncOutlet } from './vesyncOutlet';
6
6
  import { VeSync } from './vesync';
7
7
  import { Helpers } from './helpers';
8
+ import { logger } from './logger';
8
9
 
9
10
  /**
10
11
  * VeSync 7A Outlet
@@ -18,6 +19,7 @@ export class VeSyncOutlet7A extends VeSyncOutlet {
18
19
  * Turn outlet on
19
20
  */
20
21
  async turnOn(): Promise<boolean> {
22
+ logger.debug(`[${this.deviceName}] Turning outlet on`);
21
23
  const url = `/v1/wifi-switch-1.3/wifi-switch-1.3-${this.cid}/status/on`;
22
24
  const [response] = await Helpers.callApi(
23
25
  url,
@@ -28,8 +30,10 @@ export class VeSyncOutlet7A extends VeSyncOutlet {
28
30
 
29
31
  if (response?.code === 0) {
30
32
  this.deviceStatus = 'on';
33
+ logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
31
34
  return true;
32
35
  }
36
+ logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
33
37
  return false;
34
38
  }
35
39
 
@@ -37,6 +41,7 @@ export class VeSyncOutlet7A extends VeSyncOutlet {
37
41
  * Turn outlet off
38
42
  */
39
43
  async turnOff(): Promise<boolean> {
44
+ logger.debug(`[${this.deviceName}] Turning outlet off`);
40
45
  const url = `/v1/wifi-switch-1.3/wifi-switch-1.3-${this.cid}/status/off`;
41
46
  const [response] = await Helpers.callApi(
42
47
  url,
@@ -47,8 +52,10 @@ export class VeSyncOutlet7A extends VeSyncOutlet {
47
52
 
48
53
  if (response?.code === 0) {
49
54
  this.deviceStatus = 'off';
55
+ logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
50
56
  return true;
51
57
  }
58
+ logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
52
59
  return false;
53
60
  }
54
61
  }
@@ -65,6 +72,7 @@ export class VeSyncOutlet10A extends VeSyncOutlet {
65
72
  * Turn outlet on
66
73
  */
67
74
  async turnOn(): Promise<boolean> {
75
+ logger.debug(`[${this.deviceName}] Turning outlet on`);
68
76
  const body = {
69
77
  ...Helpers.reqBody(this.manager, 'devicestatus'),
70
78
  uuid: this.uuid,
@@ -80,8 +88,10 @@ export class VeSyncOutlet10A extends VeSyncOutlet {
80
88
 
81
89
  if (response?.code === 0) {
82
90
  this.deviceStatus = 'on';
91
+ logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
83
92
  return true;
84
93
  }
94
+ logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
85
95
  return false;
86
96
  }
87
97
 
@@ -89,6 +99,7 @@ export class VeSyncOutlet10A extends VeSyncOutlet {
89
99
  * Turn outlet off
90
100
  */
91
101
  async turnOff(): Promise<boolean> {
102
+ logger.debug(`[${this.deviceName}] Turning outlet off`);
92
103
  const body = {
93
104
  ...Helpers.reqBody(this.manager, 'devicestatus'),
94
105
  uuid: this.uuid,
@@ -104,8 +115,10 @@ export class VeSyncOutlet10A extends VeSyncOutlet {
104
115
 
105
116
  if (response?.code === 0) {
106
117
  this.deviceStatus = 'off';
118
+ logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
107
119
  return true;
108
120
  }
121
+ logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
109
122
  return false;
110
123
  }
111
124
  }
@@ -122,6 +135,7 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
122
135
  * Turn outlet on
123
136
  */
124
137
  async turnOn(): Promise<boolean> {
138
+ logger.debug(`[${this.deviceName}] Turning outlet on`);
125
139
  const body = {
126
140
  ...Helpers.reqBody(this.manager, 'devicestatus'),
127
141
  uuid: this.uuid,
@@ -137,8 +151,10 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
137
151
 
138
152
  if (response?.code === 0) {
139
153
  this.deviceStatus = 'on';
154
+ logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
140
155
  return true;
141
156
  }
157
+ logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
142
158
  return false;
143
159
  }
144
160
 
@@ -146,6 +162,7 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
146
162
  * Turn outlet off
147
163
  */
148
164
  async turnOff(): Promise<boolean> {
165
+ logger.debug(`[${this.deviceName}] Turning outlet off`);
149
166
  const body = {
150
167
  ...Helpers.reqBody(this.manager, 'devicestatus'),
151
168
  uuid: this.uuid,
@@ -161,8 +178,10 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
161
178
 
162
179
  if (response?.code === 0) {
163
180
  this.deviceStatus = 'off';
181
+ logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
164
182
  return true;
165
183
  }
184
+ logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
166
185
  return false;
167
186
  }
168
187
 
@@ -170,6 +189,12 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
170
189
  * Turn on nightlight
171
190
  */
172
191
  async turnOnNightlight(): Promise<boolean> {
192
+ if (!this.hasNightlight()) {
193
+ logger.error(`[${this.deviceName}] Nightlight feature not supported`);
194
+ return false;
195
+ }
196
+
197
+ logger.debug(`[${this.deviceName}] Turning nightlight on`);
173
198
  const body = {
174
199
  ...Helpers.reqBody(this.manager, 'devicestatus'),
175
200
  uuid: this.uuid,
@@ -185,8 +210,10 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
185
210
 
186
211
  if (response?.code === 0) {
187
212
  this.details.nightLightStatus = 'on';
213
+ logger.debug(`[${this.deviceName}] Successfully turned nightlight on`);
188
214
  return true;
189
215
  }
216
+ logger.error(`[${this.deviceName}] Failed to turn nightlight on: ${JSON.stringify(response)}`);
190
217
  return false;
191
218
  }
192
219
 
@@ -194,6 +221,12 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
194
221
  * Turn off nightlight
195
222
  */
196
223
  async turnOffNightlight(): Promise<boolean> {
224
+ if (!this.hasNightlight()) {
225
+ logger.error(`[${this.deviceName}] Nightlight feature not supported`);
226
+ return false;
227
+ }
228
+
229
+ logger.debug(`[${this.deviceName}] Turning nightlight off`);
197
230
  const body = {
198
231
  ...Helpers.reqBody(this.manager, 'devicestatus'),
199
232
  uuid: this.uuid,
@@ -209,8 +242,10 @@ export class VeSyncOutlet15A extends VeSyncOutlet {
209
242
 
210
243
  if (response?.code === 0) {
211
244
  this.details.nightLightStatus = 'off';
245
+ logger.debug(`[${this.deviceName}] Successfully turned nightlight off`);
212
246
  return true;
213
247
  }
248
+ logger.error(`[${this.deviceName}] Failed to turn nightlight off: ${JSON.stringify(response)}`);
214
249
  return false;
215
250
  }
216
251
  }
@@ -227,6 +262,7 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
227
262
  * Turn outlet on
228
263
  */
229
264
  async turnOn(): Promise<boolean> {
265
+ logger.debug(`[${this.deviceName}] Turning outlet on`);
230
266
  const body = {
231
267
  ...Helpers.reqBody(this.manager, 'devicestatus'),
232
268
  uuid: this.uuid,
@@ -243,8 +279,10 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
243
279
 
244
280
  if (response?.code === 0) {
245
281
  this.deviceStatus = 'on';
282
+ logger.debug(`[${this.deviceName}] Successfully turned outlet on`);
246
283
  return true;
247
284
  }
285
+ logger.error(`[${this.deviceName}] Failed to turn outlet on: ${JSON.stringify(response)}`);
248
286
  return false;
249
287
  }
250
288
 
@@ -252,6 +290,7 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
252
290
  * Turn outlet off
253
291
  */
254
292
  async turnOff(): Promise<boolean> {
293
+ logger.debug(`[${this.deviceName}] Turning outlet off`);
255
294
  const body = {
256
295
  ...Helpers.reqBody(this.manager, 'devicestatus'),
257
296
  uuid: this.uuid,
@@ -268,8 +307,10 @@ export class VeSyncOutdoorPlug extends VeSyncOutlet {
268
307
 
269
308
  if (response?.code === 0) {
270
309
  this.deviceStatus = 'off';
310
+ logger.debug(`[${this.deviceName}] Successfully turned outlet off`);
271
311
  return true;
272
312
  }
313
+ logger.error(`[${this.deviceName}] Failed to turn outlet off: ${JSON.stringify(response)}`);
273
314
  return false;
274
315
  }
275
316
  }