homebridge-tsvesync 1.0.62 → 1.0.64
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/accessories/humidifier.accessory.d.ts +1 -0
- package/dist/accessories/humidifier.accessory.d.ts.map +1 -1
- package/dist/accessories/humidifier.accessory.js +68 -8
- package/dist/accessories/humidifier.accessory.js.map +1 -1
- package/package.json +2 -2
- package/src/accessories/humidifier.accessory.ts +94 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"humidifier.accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/humidifier.accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"humidifier.accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/humidifier.accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAO7E,qBAAa,mBAAoB,SAAQ,aAAa;IACpD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAC5C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;gBAGhD,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,gBAAgB;IAO1B,SAAS,CAAC,YAAY,IAAI,IAAI;IAwD9B;;OAEG;cACa,0BAA0B,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAyEvE,SAAS,CAAC,qBAAqB,IAAI,kBAAkB;YAcvC,SAAS;YAIT,SAAS;YAiBT,gBAAgB;YAqBhB,cAAc;YAyBd,sBAAsB;CAiCrC"}
|
|
@@ -14,24 +14,44 @@ class HumidifierAccessory extends base_accessory_1.BaseAccessory {
|
|
|
14
14
|
this.accessory.addService(this.platform.Service.HumidifierDehumidifier);
|
|
15
15
|
// Set up required characteristics
|
|
16
16
|
this.setupCharacteristic(this.platform.Characteristic.Active, this.getActive.bind(this), this.setActive.bind(this));
|
|
17
|
-
// Set up
|
|
17
|
+
// Set up target state characteristic for mode mapping
|
|
18
|
+
this.setupCharacteristic(this.platform.Characteristic.TargetHumidifierDehumidifierState, async () => 1, this.setTargetState.bind(this));
|
|
19
|
+
// Set up rotation speed characteristic
|
|
18
20
|
this.setupCharacteristic(this.platform.Characteristic.RotationSpeed, this.getRotationSpeed.bind(this), this.handleSetRotationSpeed.bind(this));
|
|
19
21
|
// Add Name characteristic
|
|
20
22
|
this.setupCharacteristic(this.platform.Characteristic.Name, async () => this.device.deviceName);
|
|
23
|
+
// Add Current Relative Humidity if supported
|
|
24
|
+
if (this.capabilities.hasHumidity) {
|
|
25
|
+
if (!this.service.testCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity)) {
|
|
26
|
+
this.service.addCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Add Water Level characteristic if supported (mapping inferred from water_lacks/water_tank_lifted)
|
|
30
|
+
if (this.capabilities.hasWaterLevel) {
|
|
31
|
+
if (!this.service.testCharacteristic(this.platform.Characteristic.WaterLevel)) {
|
|
32
|
+
this.service.addCharacteristic(this.platform.Characteristic.WaterLevel);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Add Lock Physical Controls characteristic if supported
|
|
36
|
+
if (this.capabilities.hasChildLock) {
|
|
37
|
+
this.setupCharacteristic(this.platform.Characteristic.LockPhysicalControls, async () => false, async (value) => { throw new Error('Locking physical controls is not supported by the tsvesync API.'); });
|
|
38
|
+
}
|
|
21
39
|
}
|
|
22
40
|
/**
|
|
23
41
|
* Update device states based on the latest details
|
|
24
42
|
*/
|
|
25
43
|
async updateDeviceSpecificStates(details) {
|
|
26
44
|
const humidifierDetails = details;
|
|
27
|
-
// Update active state
|
|
28
45
|
const isActive = humidifierDetails.deviceStatus === 'on';
|
|
46
|
+
// Update active state
|
|
29
47
|
this.updateCharacteristicValue(this.platform.Characteristic.Active, isActive ? 1 : 0);
|
|
30
|
-
// Update current state
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
);
|
|
48
|
+
// Update current state based on API mapping
|
|
49
|
+
// HomeKit states: 0 = INACTIVE, 1 = IDLE, 2 = HUMIDIFYING, 3 = DEHUMIDIFYING
|
|
50
|
+
// Mapping: if active and mode is 'manual' -> HUMIDIFYING (2), else INACTIVE (0)
|
|
51
|
+
const currentState = (isActive && humidifierDetails.mode === 'manual') ? 2 : 0;
|
|
52
|
+
this.updateCharacteristicValue(this.platform.Characteristic.CurrentHumidifierDehumidifierState, currentState);
|
|
53
|
+
// Update target state; always humidifier mode (1) as only humidification is supported
|
|
54
|
+
this.updateCharacteristicValue(this.platform.Characteristic.TargetHumidifierDehumidifierState, 1);
|
|
35
55
|
// Update rotation speed - convert device speed (1-9) to HomeKit percentage (0-100)
|
|
36
56
|
let rotationSpeed = 0;
|
|
37
57
|
if (isActive && humidifierDetails.speed !== undefined) {
|
|
@@ -66,6 +86,18 @@ class HumidifierAccessory extends base_accessory_1.BaseAccessory {
|
|
|
66
86
|
}
|
|
67
87
|
}
|
|
68
88
|
this.updateCharacteristicValue(this.platform.Characteristic.RotationSpeed, rotationSpeed);
|
|
89
|
+
// Update relative humidity if supported
|
|
90
|
+
if (this.capabilities.hasHumidity && humidifierDetails.humidity !== undefined) {
|
|
91
|
+
this.updateCharacteristicValue(this.platform.Characteristic.CurrentRelativeHumidity, humidifierDetails.humidity);
|
|
92
|
+
}
|
|
93
|
+
// Update water level if supported (inferred from water_lacks/water_tank_lifted)
|
|
94
|
+
if (this.capabilities.hasWaterLevel) {
|
|
95
|
+
const waterLow = humidifierDetails.water_lacks || humidifierDetails.water_tank_lifted;
|
|
96
|
+
if (this.service.getCharacteristic(this.platform.Characteristic.WaterLevel)) {
|
|
97
|
+
// Map water level as 0 for low water, 100 for sufficient water
|
|
98
|
+
this.updateCharacteristicValue(this.platform.Characteristic.WaterLevel, waterLow ? 0 : 100);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
69
101
|
}
|
|
70
102
|
getDeviceCapabilities() {
|
|
71
103
|
return {
|
|
@@ -104,7 +136,7 @@ class HumidifierAccessory extends base_accessory_1.BaseAccessory {
|
|
|
104
136
|
}
|
|
105
137
|
// Convert device speed (1-9) to HomeKit percentage (0-100)
|
|
106
138
|
switch (this.device.speed) {
|
|
107
|
-
case 0: return 0;
|
|
139
|
+
case 0: return 0;
|
|
108
140
|
case 1: return 11;
|
|
109
141
|
case 2: return 22;
|
|
110
142
|
case 3: return 33;
|
|
@@ -117,6 +149,34 @@ class HumidifierAccessory extends base_accessory_1.BaseAccessory {
|
|
|
117
149
|
default: return 0;
|
|
118
150
|
}
|
|
119
151
|
}
|
|
152
|
+
async setTargetState(value) {
|
|
153
|
+
try {
|
|
154
|
+
// HomeKit Target State: 1 = Humidifier, 2 = Dehumidifier, 0 = Auto
|
|
155
|
+
const device = this.device;
|
|
156
|
+
if (value === 1) {
|
|
157
|
+
if (typeof device.setMode === 'function') {
|
|
158
|
+
const success = await device.setMode('manual');
|
|
159
|
+
if (!success) {
|
|
160
|
+
throw new Error('Failed to set device mode to humidification (manual)');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
throw new Error('Device API does not support setMode operation');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else if (value === 2) {
|
|
168
|
+
throw new Error('Dehumidification mode is not supported by this device');
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
throw new Error('Unsupported target state value');
|
|
172
|
+
}
|
|
173
|
+
// After setting, update the target state to reflect humidifier mode (1)
|
|
174
|
+
this.updateCharacteristicValue(this.platform.Characteristic.TargetHumidifierDehumidifierState, 1);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
this.handleDeviceError('set target state', error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
120
180
|
async handleSetRotationSpeed(value) {
|
|
121
181
|
const percentage = value;
|
|
122
182
|
if (percentage === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"humidifier.accessory.js","sourceRoot":"","sources":["../../src/accessories/humidifier.accessory.ts"],"names":[],"mappings":";;;AACA,qDAAiD;
|
|
1
|
+
{"version":3,"file":"humidifier.accessory.js","sourceRoot":"","sources":["../../src/accessories/humidifier.accessory.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-tsvesync",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.64",
|
|
4
4
|
"description": "Homebridge plugin for VeSync devices including Levoit air purifiers, humidifiers, and Etekcity smart outlets",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"axios": "^1.6.5",
|
|
99
99
|
"dotenv": "^16.3.1",
|
|
100
100
|
"js-yaml": "^4.1.0",
|
|
101
|
-
"tsvesync": "1.0.
|
|
101
|
+
"tsvesync": "1.0.64"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@types/jest": "^29.5.11",
|
|
@@ -3,6 +3,11 @@ import { BaseAccessory } from './base.accessory';
|
|
|
3
3
|
import { TSVESyncPlatform } from '../platform';
|
|
4
4
|
import { DeviceCapabilities, VeSyncHumidifier } from '../types/device.types';
|
|
5
5
|
|
|
6
|
+
// Extended interface to include optional setMode method for humidifiers
|
|
7
|
+
interface ExtendedVeSyncHumidifier extends VeSyncHumidifier {
|
|
8
|
+
setMode?(mode: 'manual'): Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
export class HumidifierAccessory extends BaseAccessory {
|
|
7
12
|
protected readonly device: VeSyncHumidifier;
|
|
8
13
|
private readonly capabilities: DeviceCapabilities;
|
|
@@ -29,7 +34,14 @@ export class HumidifierAccessory extends BaseAccessory {
|
|
|
29
34
|
this.setActive.bind(this)
|
|
30
35
|
);
|
|
31
36
|
|
|
32
|
-
// Set up
|
|
37
|
+
// Set up target state characteristic for mode mapping
|
|
38
|
+
this.setupCharacteristic(
|
|
39
|
+
this.platform.Characteristic.TargetHumidifierDehumidifierState,
|
|
40
|
+
async () => 1,
|
|
41
|
+
this.setTargetState.bind(this)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Set up rotation speed characteristic
|
|
33
45
|
this.setupCharacteristic(
|
|
34
46
|
this.platform.Characteristic.RotationSpeed,
|
|
35
47
|
this.getRotationSpeed.bind(this),
|
|
@@ -41,6 +53,29 @@ export class HumidifierAccessory extends BaseAccessory {
|
|
|
41
53
|
this.platform.Characteristic.Name,
|
|
42
54
|
async () => this.device.deviceName
|
|
43
55
|
);
|
|
56
|
+
|
|
57
|
+
// Add Current Relative Humidity if supported
|
|
58
|
+
if (this.capabilities.hasHumidity) {
|
|
59
|
+
if (!this.service.testCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity)) {
|
|
60
|
+
this.service.addCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Add Water Level characteristic if supported (mapping inferred from water_lacks/water_tank_lifted)
|
|
65
|
+
if (this.capabilities.hasWaterLevel) {
|
|
66
|
+
if (!this.service.testCharacteristic(this.platform.Characteristic.WaterLevel)) {
|
|
67
|
+
this.service.addCharacteristic(this.platform.Characteristic.WaterLevel);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Add Lock Physical Controls characteristic if supported
|
|
72
|
+
if (this.capabilities.hasChildLock) {
|
|
73
|
+
this.setupCharacteristic(
|
|
74
|
+
this.platform.Characteristic.LockPhysicalControls,
|
|
75
|
+
async () => false,
|
|
76
|
+
async (value: CharacteristicValue) => { throw new Error('Locking physical controls is not supported by the tsvesync API.'); }
|
|
77
|
+
);
|
|
78
|
+
}
|
|
44
79
|
}
|
|
45
80
|
|
|
46
81
|
/**
|
|
@@ -50,25 +85,32 @@ export class HumidifierAccessory extends BaseAccessory {
|
|
|
50
85
|
const humidifierDetails = details as {
|
|
51
86
|
deviceStatus: string;
|
|
52
87
|
speed: number;
|
|
88
|
+
mode?: string;
|
|
89
|
+
humidity?: number;
|
|
90
|
+
water_lacks?: boolean;
|
|
91
|
+
water_tank_lifted?: boolean;
|
|
53
92
|
};
|
|
54
93
|
|
|
55
|
-
// Update active state
|
|
56
94
|
const isActive = humidifierDetails.deviceStatus === 'on';
|
|
95
|
+
// Update active state
|
|
57
96
|
this.updateCharacteristicValue(
|
|
58
97
|
this.platform.Characteristic.Active,
|
|
59
98
|
isActive ? 1 : 0
|
|
60
99
|
);
|
|
61
100
|
|
|
62
|
-
// Update current state
|
|
101
|
+
// Update current state based on API mapping
|
|
102
|
+
// HomeKit states: 0 = INACTIVE, 1 = IDLE, 2 = HUMIDIFYING, 3 = DEHUMIDIFYING
|
|
103
|
+
// Mapping: if active and mode is 'manual' -> HUMIDIFYING (2), else INACTIVE (0)
|
|
104
|
+
const currentState = (isActive && humidifierDetails.mode === 'manual') ? 2 : 0;
|
|
63
105
|
this.updateCharacteristicValue(
|
|
64
106
|
this.platform.Characteristic.CurrentHumidifierDehumidifierState,
|
|
65
|
-
|
|
107
|
+
currentState
|
|
66
108
|
);
|
|
67
109
|
|
|
68
|
-
// Update target state
|
|
110
|
+
// Update target state; always humidifier mode (1) as only humidification is supported
|
|
69
111
|
this.updateCharacteristicValue(
|
|
70
112
|
this.platform.Characteristic.TargetHumidifierDehumidifierState,
|
|
71
|
-
1
|
|
113
|
+
1
|
|
72
114
|
);
|
|
73
115
|
|
|
74
116
|
// Update rotation speed - convert device speed (1-9) to HomeKit percentage (0-100)
|
|
@@ -90,6 +132,26 @@ export class HumidifierAccessory extends BaseAccessory {
|
|
|
90
132
|
this.platform.Characteristic.RotationSpeed,
|
|
91
133
|
rotationSpeed
|
|
92
134
|
);
|
|
135
|
+
|
|
136
|
+
// Update relative humidity if supported
|
|
137
|
+
if (this.capabilities.hasHumidity && humidifierDetails.humidity !== undefined) {
|
|
138
|
+
this.updateCharacteristicValue(
|
|
139
|
+
this.platform.Characteristic.CurrentRelativeHumidity,
|
|
140
|
+
humidifierDetails.humidity
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Update water level if supported (inferred from water_lacks/water_tank_lifted)
|
|
145
|
+
if (this.capabilities.hasWaterLevel) {
|
|
146
|
+
const waterLow = humidifierDetails.water_lacks || humidifierDetails.water_tank_lifted;
|
|
147
|
+
if (this.service.getCharacteristic(this.platform.Characteristic.WaterLevel)) {
|
|
148
|
+
// Map water level as 0 for low water, 100 for sufficient water
|
|
149
|
+
this.updateCharacteristicValue(
|
|
150
|
+
this.platform.Characteristic.WaterLevel,
|
|
151
|
+
waterLow ? 0 : 100
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
93
155
|
}
|
|
94
156
|
|
|
95
157
|
protected getDeviceCapabilities(): DeviceCapabilities {
|
|
@@ -134,7 +196,7 @@ export class HumidifierAccessory extends BaseAccessory {
|
|
|
134
196
|
|
|
135
197
|
// Convert device speed (1-9) to HomeKit percentage (0-100)
|
|
136
198
|
switch (this.device.speed) {
|
|
137
|
-
case 0: return 0;
|
|
199
|
+
case 0: return 0;
|
|
138
200
|
case 1: return 11;
|
|
139
201
|
case 2: return 22;
|
|
140
202
|
case 3: return 33;
|
|
@@ -148,6 +210,31 @@ export class HumidifierAccessory extends BaseAccessory {
|
|
|
148
210
|
}
|
|
149
211
|
}
|
|
150
212
|
|
|
213
|
+
private async setTargetState(value: CharacteristicValue): Promise<void> {
|
|
214
|
+
try {
|
|
215
|
+
// HomeKit Target State: 1 = Humidifier, 2 = Dehumidifier, 0 = Auto
|
|
216
|
+
const device = this.device as ExtendedVeSyncHumidifier;
|
|
217
|
+
if (value === 1) {
|
|
218
|
+
if (typeof device.setMode === 'function') {
|
|
219
|
+
const success = await device.setMode('manual');
|
|
220
|
+
if (!success) {
|
|
221
|
+
throw new Error('Failed to set device mode to humidification (manual)');
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
throw new Error('Device API does not support setMode operation');
|
|
225
|
+
}
|
|
226
|
+
} else if (value === 2) {
|
|
227
|
+
throw new Error('Dehumidification mode is not supported by this device');
|
|
228
|
+
} else {
|
|
229
|
+
throw new Error('Unsupported target state value');
|
|
230
|
+
}
|
|
231
|
+
// After setting, update the target state to reflect humidifier mode (1)
|
|
232
|
+
this.updateCharacteristicValue(this.platform.Characteristic.TargetHumidifierDehumidifierState, 1);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
this.handleDeviceError('set target state', error);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
151
238
|
private async handleSetRotationSpeed(value: CharacteristicValue): Promise<void> {
|
|
152
239
|
const percentage = value as number;
|
|
153
240
|
|