homebridge-tsvesync 1.0.13 → 1.0.14

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.
Files changed (34) hide show
  1. package/dist/accessories/air-purifier.accessory.d.ts +32 -2
  2. package/dist/accessories/air-purifier.accessory.d.ts.map +1 -1
  3. package/dist/accessories/air-purifier.accessory.js +110 -51
  4. package/dist/accessories/air-purifier.accessory.js.map +1 -1
  5. package/dist/accessories/base.accessory.d.ts +12 -3
  6. package/dist/accessories/base.accessory.d.ts.map +1 -1
  7. package/dist/accessories/base.accessory.js +53 -24
  8. package/dist/accessories/base.accessory.js.map +1 -1
  9. package/dist/accessories/fan.accessory.d.ts +6 -2
  10. package/dist/accessories/fan.accessory.d.ts.map +1 -1
  11. package/dist/accessories/fan.accessory.js +27 -33
  12. package/dist/accessories/fan.accessory.js.map +1 -1
  13. package/dist/accessories/humidifier.accessory.d.ts +6 -2
  14. package/dist/accessories/humidifier.accessory.d.ts.map +1 -1
  15. package/dist/accessories/humidifier.accessory.js +38 -37
  16. package/dist/accessories/humidifier.accessory.js.map +1 -1
  17. package/dist/accessories/light.accessory.d.ts +5 -1
  18. package/dist/accessories/light.accessory.d.ts.map +1 -1
  19. package/dist/accessories/light.accessory.js +25 -19
  20. package/dist/accessories/light.accessory.js.map +1 -1
  21. package/dist/accessories/outlet.accessory.d.ts +7 -1
  22. package/dist/accessories/outlet.accessory.d.ts.map +1 -1
  23. package/dist/accessories/outlet.accessory.js +25 -14
  24. package/dist/accessories/outlet.accessory.js.map +1 -1
  25. package/dist/types/device.types.d.ts +1 -1
  26. package/dist/types/device.types.d.ts.map +1 -1
  27. package/package.json +2 -2
  28. package/src/accessories/air-purifier.accessory.ts +117 -84
  29. package/src/accessories/base.accessory.ts +62 -35
  30. package/src/accessories/fan.accessory.ts +40 -44
  31. package/src/accessories/humidifier.accessory.ts +61 -48
  32. package/src/accessories/light.accessory.ts +32 -18
  33. package/src/accessories/outlet.accessory.ts +33 -14
  34. package/src/types/device.types.ts +1 -1
@@ -5,14 +5,16 @@ import { DeviceCapabilities, VeSyncHumidifier } from '../types/device.types';
5
5
 
6
6
  export class HumidifierAccessory extends BaseAccessory {
7
7
  protected readonly device: VeSyncHumidifier;
8
+ private readonly capabilities: DeviceCapabilities;
8
9
 
9
10
  constructor(
10
11
  platform: TSVESyncPlatform,
11
12
  accessory: PlatformAccessory,
12
- device: VeSyncHumidifier,
13
+ device: VeSyncHumidifier
13
14
  ) {
14
15
  super(platform, accessory, device);
15
16
  this.device = device;
17
+ this.capabilities = this.getDeviceCapabilities();
16
18
  }
17
19
 
18
20
  protected setupService(): void {
@@ -56,7 +58,7 @@ export class HumidifierAccessory extends BaseAccessory {
56
58
  this.setupCharacteristic(
57
59
  this.platform.Characteristic.RotationSpeed,
58
60
  this.getRotationSpeed.bind(this),
59
- this.setRotationSpeed.bind(this)
61
+ this.handleSetRotationSpeed.bind(this)
60
62
  );
61
63
  }
62
64
 
@@ -82,61 +84,80 @@ export class HumidifierAccessory extends BaseAccessory {
82
84
  );
83
85
  }
84
86
 
85
- protected updateDeviceSpecificStates(details: any): void {
86
- const capabilities = this.getDeviceCapabilities();
87
+ /**
88
+ * Update device states based on the latest details
89
+ */
90
+ protected async updateDeviceSpecificStates(details: any): Promise<void> {
91
+ const humidifierDetails = details as {
92
+ deviceStatus: string;
93
+ humidity: number;
94
+ targetHumidity: number;
95
+ speed: number;
96
+ childLock: boolean;
97
+ waterLevel: number;
98
+ };
87
99
 
88
- // Update humidity states
89
- if (details.humidity !== undefined) {
100
+ // Update active state
101
+ const isActive = humidifierDetails.deviceStatus === 'on';
102
+ this.updateCharacteristicValue(
103
+ this.platform.Characteristic.Active,
104
+ isActive ? 1 : 0
105
+ );
106
+
107
+ // Update current state
108
+ this.updateCharacteristicValue(
109
+ this.platform.Characteristic.CurrentHumidifierDehumidifierState,
110
+ isActive ? 2 : 0
111
+ );
112
+
113
+ // Update target state
114
+ this.updateCharacteristicValue(
115
+ this.platform.Characteristic.TargetHumidifierDehumidifierState,
116
+ 1 // Always HUMIDIFIER for these devices
117
+ );
118
+
119
+ // Update current humidity
120
+ if (humidifierDetails.humidity !== undefined) {
90
121
  this.updateCharacteristicValue(
91
122
  this.platform.Characteristic.CurrentRelativeHumidity,
92
- details.humidity
123
+ humidifierDetails.humidity
93
124
  );
94
125
  }
95
126
 
96
- if (details.targetHumidity !== undefined) {
127
+ // Update target humidity
128
+ if (humidifierDetails.targetHumidity !== undefined) {
97
129
  this.updateCharacteristicValue(
98
130
  this.platform.Characteristic.RelativeHumidityHumidifierThreshold,
99
- details.targetHumidity
131
+ humidifierDetails.targetHumidity
100
132
  );
101
133
  }
102
134
 
103
- // Update speed if available
104
- if (capabilities.hasSpeed && details.speed !== undefined) {
105
- const normalizedSpeed = (details.speed / this.device.maxSpeed) * 100;
135
+ // Update rotation speed if supported
136
+ if (this.capabilities.hasSpeed) {
106
137
  this.updateCharacteristicValue(
107
138
  this.platform.Characteristic.RotationSpeed,
108
- normalizedSpeed
139
+ humidifierDetails.speed
109
140
  );
110
141
  }
111
142
 
112
- // Update water level if available
113
- if (capabilities.hasWaterLevel && details.waterLevel !== undefined) {
143
+ // Update child lock if supported
144
+ if (this.capabilities.hasChildLock) {
114
145
  this.updateCharacteristicValue(
115
- this.platform.Characteristic.WaterLevel,
116
- details.waterLevel
146
+ this.platform.Characteristic.LockPhysicalControls,
147
+ humidifierDetails.childLock ? 1 : 0
117
148
  );
118
149
  }
119
150
 
120
- // Update child lock if available
121
- if (capabilities.hasChildLock && details.childLock !== undefined) {
151
+ // Update water level if supported
152
+ if (this.capabilities.hasWaterLevel && humidifierDetails.waterLevel !== undefined) {
122
153
  this.updateCharacteristicValue(
123
- this.platform.Characteristic.LockPhysicalControls,
124
- details.childLock ? 1 : 0
154
+ this.platform.Characteristic.WaterLevel,
155
+ humidifierDetails.waterLevel
125
156
  );
126
157
  }
127
158
 
128
- // Update active state
129
- const isActive = details.deviceStatus === 'on';
130
- this.updateCharacteristicValue(
131
- this.platform.Characteristic.Active,
132
- isActive ? 1 : 0
133
- );
134
-
135
- // Update current state
136
- this.updateCharacteristicValue(
137
- this.platform.Characteristic.CurrentHumidifierDehumidifierState,
138
- isActive ? 2 : 0 // 0 = INACTIVE, 2 = HUMIDIFYING
139
- );
159
+ // Update polling state based on active status
160
+ this.updatePollingState(isActive);
140
161
  }
141
162
 
142
163
  protected getDeviceCapabilities(): DeviceCapabilities {
@@ -209,23 +230,15 @@ export class HumidifierAccessory extends BaseAccessory {
209
230
  }
210
231
  }
211
232
 
212
- private async getRotationSpeed(): Promise<CharacteristicValue> {
213
- return (this.device.speed / this.device.maxSpeed) * 100;
233
+ private async handleSetRotationSpeed(value: CharacteristicValue): Promise<void> {
234
+ const speed = Math.round((value as number / 100) * this.device.maxSpeed);
235
+ await this.withRetry(async () => {
236
+ await this.device.changeFanSpeed(speed);
237
+ }, 'set rotation speed');
214
238
  }
215
239
 
216
- private async setRotationSpeed(value: CharacteristicValue): Promise<void> {
217
- try {
218
- const speed = Math.round((value as number / 100) * this.device.maxSpeed);
219
- const success = await this.device.setSpeed(speed);
220
-
221
- if (!success) {
222
- throw new Error(`Failed to set speed to ${speed}`);
223
- }
224
-
225
- await this.persistDeviceState('speed', speed);
226
- } catch (error) {
227
- this.handleDeviceError('set rotation speed', error);
228
- }
240
+ private async getRotationSpeed(): Promise<CharacteristicValue> {
241
+ return (this.device.speed / this.device.maxSpeed) * 100;
229
242
  }
230
243
 
231
244
  private async getWaterLevel(): Promise<CharacteristicValue> {
@@ -10,14 +10,16 @@ const DEFAULT_COLOR_TEMP = MIN_COLOR_TEMP;
10
10
 
11
11
  export class LightAccessory extends BaseAccessory {
12
12
  protected readonly device: VeSyncBulb;
13
+ private readonly capabilities: DeviceCapabilities;
13
14
 
14
15
  constructor(
15
16
  platform: TSVESyncPlatform,
16
17
  accessory: PlatformAccessory,
17
- device: VeSyncBulb,
18
+ device: VeSyncBulb
18
19
  ) {
19
20
  super(platform, accessory, device);
20
21
  this.device = device;
22
+ this.capabilities = this.getDeviceCapabilities();
21
23
  }
22
24
 
23
25
  protected setupService(): void {
@@ -84,48 +86,60 @@ export class LightAccessory extends BaseAccessory {
84
86
  );
85
87
  }
86
88
 
87
- protected updateDeviceSpecificStates(details: any): void {
88
- const capabilities = this.getDeviceCapabilities();
89
+ /**
90
+ * Update device states based on the latest details
91
+ */
92
+ protected async updateDeviceSpecificStates(details: any): Promise<void> {
93
+ const lightDetails = details as {
94
+ deviceStatus: string;
95
+ brightness: number;
96
+ colorTemp?: number;
97
+ hue?: number;
98
+ saturation?: number;
99
+ };
89
100
 
90
- // Update on/off state
91
- const isOn = details.deviceStatus === 'on';
101
+ // Update active state
102
+ const isActive = lightDetails.deviceStatus === 'on';
92
103
  this.updateCharacteristicValue(
93
104
  this.platform.Characteristic.On,
94
- isOn
105
+ isActive
95
106
  );
96
107
 
97
- // Update brightness if available
98
- if (capabilities.hasBrightness && details.brightness !== undefined) {
108
+ // Update brightness if supported
109
+ if (this.capabilities.hasBrightness && lightDetails.brightness !== undefined) {
99
110
  this.updateCharacteristicValue(
100
111
  this.platform.Characteristic.Brightness,
101
- details.brightness
112
+ lightDetails.brightness
102
113
  );
103
114
  }
104
115
 
105
- // Update color temperature if available
106
- if (capabilities.hasColorTemp && details.colorTemp !== undefined) {
116
+ // Update color temperature if supported
117
+ if (this.capabilities.hasColorTemp && lightDetails.colorTemp !== undefined) {
107
118
  this.updateCharacteristicValue(
108
119
  this.platform.Characteristic.ColorTemperature,
109
- details.colorTemp
120
+ lightDetails.colorTemp
110
121
  );
111
122
  }
112
123
 
113
- // Update color if available
114
- if (capabilities.hasColor) {
115
- if (details.hue !== undefined) {
124
+ // Update color if supported
125
+ if (this.capabilities.hasColor) {
126
+ if (lightDetails.hue !== undefined) {
116
127
  this.updateCharacteristicValue(
117
128
  this.platform.Characteristic.Hue,
118
- details.hue
129
+ lightDetails.hue
119
130
  );
120
131
  }
121
132
 
122
- if (details.saturation !== undefined) {
133
+ if (lightDetails.saturation !== undefined) {
123
134
  this.updateCharacteristicValue(
124
135
  this.platform.Characteristic.Saturation,
125
- details.saturation
136
+ lightDetails.saturation
126
137
  );
127
138
  }
128
139
  }
140
+
141
+ // Update polling state based on active status
142
+ this.updatePollingState(isActive);
129
143
  }
130
144
 
131
145
  protected getDeviceCapabilities(): DeviceCapabilities {
@@ -22,6 +22,11 @@ export class OutletAccessory extends BaseAccessory {
22
22
  protected readonly device: VeSyncOutlet;
23
23
  private powerService?: Service;
24
24
 
25
+ // Custom characteristics for power monitoring
26
+ private readonly POWER_UUID = '7B2B25B0-DB50-4351-9A8B-5B9F3E3E3E3E';
27
+ private readonly VOLTAGE_UUID = '7B2B25B1-DB50-4351-9A8B-5B9F3E3E3E3E';
28
+ private readonly ENERGY_UUID = '7B2B25B2-DB50-4351-9A8B-5B9F3E3E3E3E';
29
+
25
30
  constructor(
26
31
  platform: TSVESyncPlatform,
27
32
  accessory: PlatformAccessory,
@@ -122,34 +127,48 @@ export class OutletAccessory extends BaseAccessory {
122
127
  }
123
128
  }
124
129
 
125
- protected updateDeviceSpecificStates(details: any): void {
126
- // Update on/off state
127
- const isOn = details.deviceStatus === 'on';
130
+ /**
131
+ * Update device states based on the latest details
132
+ */
133
+ protected async updateDeviceSpecificStates(details: any): Promise<void> {
134
+ const outletDetails = details as {
135
+ deviceStatus: string;
136
+ power?: number;
137
+ voltage?: number;
138
+ energy?: number;
139
+ };
140
+
141
+ // Update active state
142
+ const isActive = outletDetails.deviceStatus === 'on';
128
143
  this.updateCharacteristicValue(
129
144
  this.platform.Characteristic.On,
130
- isOn
145
+ isActive
131
146
  );
132
147
 
133
- // Update outlet in use
148
+ // Update outlet in use (always true when device is on)
134
149
  this.updateCharacteristicValue(
135
150
  this.platform.Characteristic.OutletInUse,
136
- isOn && (details.power ? details.power > 0 : true)
151
+ isActive
137
152
  );
138
153
 
139
- // Update power consumption if available
140
- if (this.powerService) {
141
- if (details.power !== undefined) {
142
- this.powerService.updateCharacteristic(POWER_CHARACTERISTIC.UUID, details.power);
154
+ // Update power monitoring characteristics if available
155
+ const powerService = this.accessory.getService('Power Monitor');
156
+ if (powerService) {
157
+ if (outletDetails.power !== undefined) {
158
+ powerService.updateCharacteristic(this.POWER_UUID, outletDetails.power);
143
159
  }
144
160
 
145
- if (details.voltage !== undefined) {
146
- this.powerService.updateCharacteristic(VOLTAGE_CHARACTERISTIC.UUID, details.voltage);
161
+ if (outletDetails.voltage !== undefined) {
162
+ powerService.updateCharacteristic(this.VOLTAGE_UUID, outletDetails.voltage);
147
163
  }
148
164
 
149
- if (details.energy !== undefined) {
150
- this.powerService.updateCharacteristic(ENERGY_CHARACTERISTIC.UUID, details.energy);
165
+ if (outletDetails.energy !== undefined) {
166
+ powerService.updateCharacteristic(this.ENERGY_UUID, outletDetails.energy);
151
167
  }
152
168
  }
169
+
170
+ // Update polling state based on active status
171
+ this.updatePollingState(isActive);
153
172
  }
154
173
 
155
174
  protected getDeviceCapabilities(): DeviceCapabilities {
@@ -34,7 +34,7 @@ export interface VeSyncDeviceWithColor extends VeSyncDeviceWithBrightness {
34
34
  export interface VeSyncDeviceWithSpeed extends VeSyncDeviceWithPower {
35
35
  speed: number;
36
36
  maxSpeed: number;
37
- setSpeed(value: number): Promise<boolean>;
37
+ changeFanSpeed(value: number): Promise<boolean>;
38
38
  }
39
39
 
40
40
  export interface VeSyncDeviceWithRotation extends VeSyncDeviceWithPower {