homebridge-tsvesync 1.3.12 → 1.3.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.
- package/CHANGELOG.md +14 -0
- package/dist/accessories/air-quality-sensor.accessory.d.ts +4 -0
- package/dist/accessories/air-quality-sensor.accessory.d.ts.map +1 -1
- package/dist/accessories/air-quality-sensor.accessory.js +81 -12
- package/dist/accessories/air-quality-sensor.accessory.js.map +1 -1
- package/dist/accessories/base.accessory.d.ts.map +1 -1
- package/dist/accessories/base.accessory.js +1 -3
- package/dist/accessories/base.accessory.js.map +1 -1
- package/dist/types/device.types.d.ts +6 -0
- package/dist/types/device.types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/accessories/air-purifier-integration.test.ts +2 -2
- package/src/__tests__/accessories/air-quality-methods.test.ts +10 -12
- package/src/__tests__/accessories/air-quality-sensor.accessory.test.ts +231 -0
- package/src/__tests__/base.accessory.test.ts +2 -2
- package/src/accessories/air-quality-sensor.accessory.ts +93 -15
- package/src/accessories/base.accessory.ts +1 -2
- package/src/types/device.types.ts +3 -0
- package/src/__tests__/accessories/air-purifier-air-quality.test.ts +0 -483
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.13 (2025-10-23)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **🌫️ HomeKit AQ Automations**: Air Quality accessories now prioritize pyvesync's categorical levels and fall back to PM2.5 thresholds, keeping the Home app's “drops below Inferior” trigger selectable instead of collapsing to Poor.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **📊 Sensor Mapping**: Clamp PM2.5 heuristics to HomeKit’s four-level scale and reuse tsvesync’s normalized metadata so characteristic values stay identical across the plugin and library.
|
|
10
|
+
|
|
11
|
+
### Tests
|
|
12
|
+
- **🧪 Air Quality Regression Suite**: Added dedicated sensor tests covering normalized levels, vendor fallbacks, and PM2.5 heuristics to guard against future mapping regressions.
|
|
13
|
+
|
|
14
|
+
### Dependencies
|
|
15
|
+
- **📦 tsvesync**: Updated to 1.3.13 for the shared normalization helper and purifier metadata alignment.
|
|
16
|
+
|
|
3
17
|
## 1.3.12 (2025-10-22)
|
|
4
18
|
|
|
5
19
|
### Fixed
|
|
@@ -36,6 +36,10 @@ export declare class AirQualitySensorAccessory extends BaseAccessory {
|
|
|
36
36
|
* Based on EPA Air Quality Index (AQI) standards
|
|
37
37
|
*/
|
|
38
38
|
private convertPM25ToAirQuality;
|
|
39
|
+
private mapToHomeKitAirQuality;
|
|
40
|
+
private readNormalizedAirQualityLevel;
|
|
41
|
+
private getDevicePm25;
|
|
42
|
+
private normalizeAirQuality;
|
|
39
43
|
/**
|
|
40
44
|
* Update characteristics from device state
|
|
41
45
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"air-quality-sensor.accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/air-quality-sensor.accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,qBAAa,yBAA0B,SAAQ,aAAa;IAC1D,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,YAAY,CAAmB;gBAGrC,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,gBAAgB;
|
|
1
|
+
{"version":3,"file":"air-quality-sensor.accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/air-quality-sensor.accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,qBAAa,yBAA0B,SAAQ,aAAa;IAC1D,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,YAAY,CAAmB;gBAGrC,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,gBAAgB;IA+C1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAkBnD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAYpD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAapD;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,6BAA6B;IA0BrC,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,mBAAmB;IAkC3B;;OAEG;cACa,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCtD;;OAEG;IACH,SAAS,CAAC,qBAAqB;;;;;;;;;;;IAc/B;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,IAAI;IAI9B;;OAEG;cACa,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3D;;OAEG;IACH,QAAQ,IAAI,IAAI;CAGjB"}
|
|
@@ -30,7 +30,6 @@ class AirQualitySensorAccessory extends base_accessory_1.BaseAccessory {
|
|
|
30
30
|
this.platform.Characteristic.AirQuality.GOOD,
|
|
31
31
|
this.platform.Characteristic.AirQuality.FAIR,
|
|
32
32
|
this.platform.Characteristic.AirQuality.INFERIOR,
|
|
33
|
-
this.platform.Characteristic.AirQuality.POOR,
|
|
34
33
|
],
|
|
35
34
|
})
|
|
36
35
|
.onGet(this.getAirQuality.bind(this));
|
|
@@ -72,10 +71,14 @@ class AirQualitySensorAccessory extends base_accessory_1.BaseAccessory {
|
|
|
72
71
|
*/
|
|
73
72
|
async getAirQuality() {
|
|
74
73
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
const level = this.readNormalizedAirQualityLevel();
|
|
75
|
+
if (level >= 1) {
|
|
76
|
+
const hkValue = this.mapToHomeKitAirQuality(level);
|
|
77
|
+
this.platform.log.debug(`${this.device.deviceName} AQ: Normalized air quality level = ${level}`);
|
|
78
|
+
return hkValue;
|
|
79
|
+
}
|
|
80
|
+
const pm25 = this.getDevicePm25();
|
|
81
|
+
this.platform.log.debug(`${this.device.deviceName} AQ: Falling back to PM2.5 heuristic (${pm25})`);
|
|
79
82
|
return this.convertPM25ToAirQuality(pm25);
|
|
80
83
|
}
|
|
81
84
|
catch (error) {
|
|
@@ -88,9 +91,7 @@ class AirQualitySensorAccessory extends base_accessory_1.BaseAccessory {
|
|
|
88
91
|
*/
|
|
89
92
|
async getPM25Density() {
|
|
90
93
|
try {
|
|
91
|
-
|
|
92
|
-
const extendedDevice = this.parentDevice;
|
|
93
|
-
const pm25 = extendedDevice.airQualityValue || 0;
|
|
94
|
+
const pm25 = this.getDevicePm25();
|
|
94
95
|
// HomeKit expects PM2.5 in μg/m³, range 0-1000
|
|
95
96
|
return Math.min(1000, Math.max(0, pm25));
|
|
96
97
|
}
|
|
@@ -129,12 +130,80 @@ class AirQualitySensorAccessory extends base_accessory_1.BaseAccessory {
|
|
|
129
130
|
else if (pm25 <= 55) {
|
|
130
131
|
return this.platform.Characteristic.AirQuality.FAIR; // Unhealthy for Sensitive (35.5-55.4 μg/m³)
|
|
131
132
|
}
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
return this.platform.Characteristic.AirQuality.INFERIOR;
|
|
134
|
+
}
|
|
135
|
+
mapToHomeKitAirQuality(level) {
|
|
136
|
+
switch (level) {
|
|
137
|
+
case 1:
|
|
138
|
+
return this.platform.Characteristic.AirQuality.EXCELLENT;
|
|
139
|
+
case 2:
|
|
140
|
+
return this.platform.Characteristic.AirQuality.GOOD;
|
|
141
|
+
case 3:
|
|
142
|
+
return this.platform.Characteristic.AirQuality.FAIR;
|
|
143
|
+
case 4:
|
|
144
|
+
return this.platform.Characteristic.AirQuality.INFERIOR;
|
|
145
|
+
default:
|
|
146
|
+
return this.platform.Characteristic.AirQuality.UNKNOWN;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
readNormalizedAirQualityLevel() {
|
|
150
|
+
var _a, _b, _c, _d, _e;
|
|
151
|
+
const extendedDevice = this.parentDevice;
|
|
152
|
+
if (typeof extendedDevice.getNormalizedAirQuality === 'function') {
|
|
153
|
+
try {
|
|
154
|
+
const normalized = extendedDevice.getNormalizedAirQuality();
|
|
155
|
+
if (normalized && typeof normalized.level === 'number' && normalized.level >= 1) {
|
|
156
|
+
return normalized.level;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
this.platform.log.debug(`${this.device.deviceName} AQ: getNormalizedAirQuality failed`, error);
|
|
161
|
+
}
|
|
134
162
|
}
|
|
135
|
-
|
|
136
|
-
|
|
163
|
+
const directLevel = (_a = extendedDevice.airQualityLevel) !== null && _a !== void 0 ? _a : (_b = extendedDevice.details) === null || _b === void 0 ? void 0 : _b.air_quality_level;
|
|
164
|
+
if (typeof directLevel === 'number' && directLevel >= 1) {
|
|
165
|
+
return directLevel;
|
|
166
|
+
}
|
|
167
|
+
const normalized = this.normalizeAirQuality((_e = (_c = extendedDevice.airQuality) !== null && _c !== void 0 ? _c : (_d = extendedDevice.details) === null || _d === void 0 ? void 0 : _d.air_quality) !== null && _e !== void 0 ? _e : extendedDevice.airQualityLabel);
|
|
168
|
+
return normalized.level;
|
|
169
|
+
}
|
|
170
|
+
getDevicePm25() {
|
|
171
|
+
var _a, _b, _c, _d;
|
|
172
|
+
const extendedDevice = this.parentDevice;
|
|
173
|
+
const pm25 = (_d = (_c = (_a = extendedDevice.airQualityValue) !== null && _a !== void 0 ? _a : (_b = extendedDevice.details) === null || _b === void 0 ? void 0 : _b.air_quality_value) !== null && _c !== void 0 ? _c : extendedDevice.pm25) !== null && _d !== void 0 ? _d : 0;
|
|
174
|
+
return Number.isFinite(pm25) ? pm25 : 0;
|
|
175
|
+
}
|
|
176
|
+
normalizeAirQuality(value) {
|
|
177
|
+
const stringMap = {
|
|
178
|
+
'excellent': 1,
|
|
179
|
+
'very good': 1,
|
|
180
|
+
'good': 2,
|
|
181
|
+
'moderate': 3,
|
|
182
|
+
'fair': 3,
|
|
183
|
+
'inferior': 4,
|
|
184
|
+
'poor': 4,
|
|
185
|
+
'bad': 4,
|
|
186
|
+
};
|
|
187
|
+
if (typeof value === 'number') {
|
|
188
|
+
const level = Number.isFinite(value) ? Math.trunc(value) : -1;
|
|
189
|
+
if (level >= 1 && level <= 4) {
|
|
190
|
+
return {
|
|
191
|
+
level,
|
|
192
|
+
label: level === 1 ? 'excellent' : level === 2 ? 'good' : level === 3 ? 'moderate' : 'poor',
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else if (typeof value === 'string') {
|
|
197
|
+
const normalized = value.trim().toLowerCase();
|
|
198
|
+
const level = stringMap[normalized];
|
|
199
|
+
if (level) {
|
|
200
|
+
return {
|
|
201
|
+
level,
|
|
202
|
+
label: level === 1 ? 'excellent' : level === 2 ? 'good' : level === 3 ? 'moderate' : 'poor',
|
|
203
|
+
};
|
|
204
|
+
}
|
|
137
205
|
}
|
|
206
|
+
return { level: -1, label: 'unknown' };
|
|
138
207
|
}
|
|
139
208
|
/**
|
|
140
209
|
* Update characteristics from device state
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"air-quality-sensor.accessory.js","sourceRoot":"","sources":["../../src/accessories/air-quality-sensor.accessory.ts"],"names":[],"mappings":";;;AAGA,qDAAiD;AAEjD;;;;GAIG;AACH,MAAa,yBAA0B,SAAQ,8BAAa;IAI1D,YACE,QAA0B,EAC1B,SAA4B,EAC5B,MAAwB;QAExB,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAEnC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAE3B,4BAA4B;QAC5B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAE;aACnE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,CAAC;aACtE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,UAAU,IAAI,SAAS,YAAY,CAAC;aACpG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,YAAY,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;QAEnG,+CAA+C;QAC/C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC;YAC9E,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAEpE,uBAAuB;QACvB,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,UAAU,cAAc,CAAC,CAAC;QAEtG,2CAA2C;QAC3C,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC;aACpE,QAAQ,CAAC;YACR,WAAW,EAAE;gBACX,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,OAAO;gBAC/C,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,SAAS;gBACjD,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI;gBAC5C,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI;gBAC5C,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,QAAQ;
|
|
1
|
+
{"version":3,"file":"air-quality-sensor.accessory.js","sourceRoot":"","sources":["../../src/accessories/air-quality-sensor.accessory.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/base.accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAIlF,8BAAsB,aAAa;IACjC,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAChD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,qBAAqB,CAAgB;IAC7C,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,cAAc,CAAS;gBAG7B,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IA4B/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAcrB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI;IAEvC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,0BAA0B,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1E;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAAI,kBAAkB;IAE9D;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,MAAM;IAgBjC;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCxC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IAEvC;;OAEG;IACU,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAsD7C;;OAEG;IACH,SAAS,CAAC,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"base.accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/base.accessory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAIlF,8BAAsB,aAAa;IACjC,SAAS,CAAC,OAAO,EAAG,OAAO,CAAC;IAC5B,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAChD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,qBAAqB,CAAgB;IAC7C,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,cAAc,CAAS;gBAG7B,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,qBAAqB;IA4B/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAcrB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI;IAEvC;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,0BAA0B,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1E;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,IAAI,kBAAkB;IAE9D;;OAEG;IACH,SAAS,CAAC,aAAa,IAAI,MAAM;IAgBjC;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCxC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IAEvC;;OAEG;IACU,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAsD7C;;OAEG;IACH,SAAS,CAAC,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAO1D;;OAEG;IACH,SAAS,CAAC,mBAAmB,CAC3B,cAAc,EAAE,GAAG,EACnB,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAC1C,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,EACrD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI;IAqDP;;OAEG;IACH,SAAS,CAAC,yBAAyB,CACjC,cAAc,EAAE,GAAG,EACnB,KAAK,EAAE,mBAAmB,GACzB,IAAI;IAUP;;OAEG;cACa,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9E;;OAEG;cACa,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;CAiCtF"}
|
|
@@ -177,9 +177,7 @@ class BaseAccessory {
|
|
|
177
177
|
return 2; // GOOD
|
|
178
178
|
if (pm25 <= 55)
|
|
179
179
|
return 3; // FAIR
|
|
180
|
-
|
|
181
|
-
return 4; // INFERIOR
|
|
182
|
-
return 5; // POOR
|
|
180
|
+
return 4; // INFERIOR (VeSync exposes four levels)
|
|
183
181
|
}
|
|
184
182
|
/**
|
|
185
183
|
* Helper method to set up a characteristic with get/set handlers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.accessory.js","sourceRoot":"","sources":["../../src/accessories/base.accessory.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"base.accessory.js","sourceRoot":"","sources":["../../src/accessories/base.accessory.ts"],"names":[],"mappings":"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"}
|
|
@@ -62,10 +62,16 @@ export interface VeSyncDeviceWithHumidity extends VeSyncDeviceWithPower {
|
|
|
62
62
|
}
|
|
63
63
|
export interface VeSyncDeviceWithAirQuality extends VeSyncDeviceWithPower {
|
|
64
64
|
airQuality: number;
|
|
65
|
+
airQualityLevel?: number;
|
|
66
|
+
airQualityLabel?: string;
|
|
65
67
|
pm25?: number;
|
|
66
68
|
filterLife: number;
|
|
67
69
|
mode: string;
|
|
68
70
|
setMode(mode: string): Promise<boolean>;
|
|
71
|
+
getNormalizedAirQuality?(): {
|
|
72
|
+
level: number;
|
|
73
|
+
label: string;
|
|
74
|
+
};
|
|
69
75
|
}
|
|
70
76
|
export interface VeSyncDeviceWithControls extends VeSyncDeviceWithPower {
|
|
71
77
|
childLock?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.types.d.ts","sourceRoot":"","sources":["../../src/types/device.types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"device.types.d.ts","sourceRoot":"","sources":["../../src/types/device.types.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.3.
|
|
3
|
+
"version": "1.3.13",
|
|
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.3.
|
|
101
|
+
"tsvesync": "1.3.13"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@types/jest": "^29.5.11",
|
|
@@ -195,7 +195,7 @@ describe('AirPurifierAccessory Integration Tests', () => {
|
|
|
195
195
|
const filterChange = await (airPurifier as any).getFilterChangeIndication();
|
|
196
196
|
const filterLife = await (airPurifier as any).getFilterLifeLevel();
|
|
197
197
|
|
|
198
|
-
expect(airQuality).toBe(
|
|
198
|
+
expect(airQuality).toBe(4); // INFERIOR
|
|
199
199
|
expect(pm25Density).toBe(180);
|
|
200
200
|
expect(filterChange).toBe(1); // CHANGE_FILTER
|
|
201
201
|
expect(filterLife).toBe(5);
|
|
@@ -463,4 +463,4 @@ describe('AirPurifierAccessory Integration Tests', () => {
|
|
|
463
463
|
expect(duration).toBeLessThan(1000); // Less than 1 second
|
|
464
464
|
});
|
|
465
465
|
});
|
|
466
|
-
});
|
|
466
|
+
});
|
|
@@ -9,8 +9,7 @@ describe('Air Quality Methods', () => {
|
|
|
9
9
|
if (pm25 <= 12) return 1; // EXCELLENT
|
|
10
10
|
if (pm25 <= 35) return 2; // GOOD
|
|
11
11
|
if (pm25 <= 55) return 3; // FAIR
|
|
12
|
-
|
|
13
|
-
return 5; // POOR
|
|
12
|
+
return 4; // INFERIOR (VeSync exposes four levels)
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
it('should convert PM2.5 values to correct HomeKit air quality levels', () => {
|
|
@@ -23,8 +22,8 @@ describe('Air Quality Methods', () => {
|
|
|
23
22
|
{ pm25: 55, expected: 3, quality: 'FAIR' },
|
|
24
23
|
{ pm25: 56, expected: 4, quality: 'INFERIOR' },
|
|
25
24
|
{ pm25: 150, expected: 4, quality: 'INFERIOR' },
|
|
26
|
-
{ pm25: 151, expected:
|
|
27
|
-
{ pm25: 300, expected:
|
|
25
|
+
{ pm25: 151, expected: 4, quality: 'INFERIOR' },
|
|
26
|
+
{ pm25: 300, expected: 4, quality: 'INFERIOR' },
|
|
28
27
|
];
|
|
29
28
|
|
|
30
29
|
testCases.forEach(({ pm25, expected, quality }) => {
|
|
@@ -36,7 +35,7 @@ describe('Air Quality Methods', () => {
|
|
|
36
35
|
it('should handle edge cases', () => {
|
|
37
36
|
expect(convertPM25ToHomeKit(12.5)).toBe(2); // Just above EXCELLENT boundary
|
|
38
37
|
expect(convertPM25ToHomeKit(35.5)).toBe(3); // Just above GOOD boundary
|
|
39
|
-
expect(convertPM25ToHomeKit(999)).toBe(
|
|
38
|
+
expect(convertPM25ToHomeKit(999)).toBe(4); // Extreme value capped at INFERIOR
|
|
40
39
|
});
|
|
41
40
|
|
|
42
41
|
it('should handle zero and negative values', () => {
|
|
@@ -236,10 +235,9 @@ describe('Air Quality Methods', () => {
|
|
|
236
235
|
};
|
|
237
236
|
|
|
238
237
|
return {
|
|
239
|
-
homeKitAirQuality: extracted.pm25 <= 12 ? 1 :
|
|
240
|
-
extracted.pm25 <= 35 ? 2 :
|
|
241
|
-
extracted.pm25 <= 55 ? 3 :
|
|
242
|
-
extracted.pm25 <= 150 ? 4 : 5,
|
|
238
|
+
homeKitAirQuality: extracted.pm25 <= 12 ? 1 :
|
|
239
|
+
extracted.pm25 <= 35 ? 2 :
|
|
240
|
+
extracted.pm25 <= 55 ? 3 : 4,
|
|
243
241
|
pm25Density: Math.min(1000, Math.max(0, Math.round(extracted.pm25))),
|
|
244
242
|
pm10Density: Math.min(1000, Math.max(0, Math.round(extracted.pm10))),
|
|
245
243
|
filterChangeNeeded: extracted.filterLife < 10,
|
|
@@ -274,7 +272,7 @@ describe('Air Quality Methods', () => {
|
|
|
274
272
|
|
|
275
273
|
const result = processDeviceData(deviceData);
|
|
276
274
|
|
|
277
|
-
expect(result.homeKitAirQuality).toBe(
|
|
275
|
+
expect(result.homeKitAirQuality).toBe(4); // INFERIOR
|
|
278
276
|
expect(result.pm25Density).toBe(180);
|
|
279
277
|
expect(result.pm10Density).toBe(220);
|
|
280
278
|
expect(result.filterChangeNeeded).toBe(true);
|
|
@@ -305,10 +303,10 @@ describe('Air Quality Methods', () => {
|
|
|
305
303
|
|
|
306
304
|
const result = processDeviceData(deviceData);
|
|
307
305
|
|
|
308
|
-
expect(result.homeKitAirQuality).toBe(
|
|
306
|
+
expect(result.homeKitAirQuality).toBe(4); // INFERIOR
|
|
309
307
|
expect(result.pm25Density).toBe(999);
|
|
310
308
|
expect(result.pm10Density).toBe(1000); // Clamped
|
|
311
309
|
expect(result.filterLifeLevel).toBe(100); // Clamped
|
|
312
310
|
});
|
|
313
311
|
});
|
|
314
|
-
});
|
|
312
|
+
});
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { API, Logger } from 'homebridge';
|
|
2
|
+
import { TSVESyncPlatform } from '../../platform';
|
|
3
|
+
import { VeSync } from 'tsvesync';
|
|
4
|
+
import { AirQualitySensorAccessory } from '../../accessories/air-quality-sensor.accessory';
|
|
5
|
+
import { createMockLogger, createMockVeSync } from '../utils/test-helpers';
|
|
6
|
+
|
|
7
|
+
interface MockAirQualityDevice {
|
|
8
|
+
deviceName: string;
|
|
9
|
+
deviceType: string;
|
|
10
|
+
cid: string;
|
|
11
|
+
uuid: string;
|
|
12
|
+
deviceStatus: string;
|
|
13
|
+
airQualityValue: number;
|
|
14
|
+
details: Record<string, any>;
|
|
15
|
+
getDetails: jest.Mock;
|
|
16
|
+
getNormalizedAirQuality?: jest.Mock;
|
|
17
|
+
airQualityLevel?: number;
|
|
18
|
+
airQualityLabel?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('AirQualitySensorAccessory', () => {
|
|
22
|
+
let mockAPI: jest.Mocked<API>;
|
|
23
|
+
let platform: TSVESyncPlatform;
|
|
24
|
+
let logger: jest.Mocked<Logger>;
|
|
25
|
+
let api: jest.Mocked<VeSync>;
|
|
26
|
+
|
|
27
|
+
const AirQualityEnum = {
|
|
28
|
+
UNKNOWN: 0,
|
|
29
|
+
EXCELLENT: 1,
|
|
30
|
+
GOOD: 2,
|
|
31
|
+
FAIR: 3,
|
|
32
|
+
INFERIOR: 4,
|
|
33
|
+
POOR: 5,
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
const ServiceEnum = {
|
|
37
|
+
AirQualitySensor: 'AirQualitySensor',
|
|
38
|
+
AccessoryInformation: 'AccessoryInformation',
|
|
39
|
+
} as const;
|
|
40
|
+
|
|
41
|
+
const createDevice = (overrides: Partial<MockAirQualityDevice> = {}): MockAirQualityDevice => ({
|
|
42
|
+
deviceName: overrides.deviceName || 'Dining Room AQ',
|
|
43
|
+
deviceType: overrides.deviceType || 'Core300S',
|
|
44
|
+
cid: overrides.cid || 'cid-123',
|
|
45
|
+
uuid: overrides.uuid || 'uuid-123',
|
|
46
|
+
deviceStatus: overrides.deviceStatus || 'on',
|
|
47
|
+
airQualityValue: overrides.airQualityValue ?? 18,
|
|
48
|
+
details: overrides.details || {
|
|
49
|
+
air_quality_value: overrides.airQualityValue ?? 18,
|
|
50
|
+
air_quality_level: overrides.airQualityLevel,
|
|
51
|
+
air_quality: overrides.airQualityLabel ?? 'good',
|
|
52
|
+
pm10: 22,
|
|
53
|
+
},
|
|
54
|
+
getDetails: overrides.getDetails || jest.fn().mockResolvedValue(true),
|
|
55
|
+
getNormalizedAirQuality: overrides.getNormalizedAirQuality,
|
|
56
|
+
airQualityLevel: overrides.airQualityLevel,
|
|
57
|
+
airQualityLabel: overrides.airQualityLabel,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const buildAccessory = (device: MockAirQualityDevice) => {
|
|
61
|
+
const airQualityService = {
|
|
62
|
+
getCharacteristic: jest.fn().mockImplementation((characteristic) => {
|
|
63
|
+
if (characteristic === AirQualityEnum) {
|
|
64
|
+
return {
|
|
65
|
+
setProps: jest.fn().mockReturnThis(),
|
|
66
|
+
onGet: jest.fn().mockReturnThis(),
|
|
67
|
+
updateValue: jest.fn().mockReturnThis(),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
onGet: jest.fn().mockReturnThis(),
|
|
72
|
+
updateValue: jest.fn().mockReturnThis(),
|
|
73
|
+
setProps: jest.fn().mockReturnThis(),
|
|
74
|
+
};
|
|
75
|
+
}),
|
|
76
|
+
setCharacteristic: jest.fn().mockReturnThis(),
|
|
77
|
+
updateCharacteristic: jest.fn().mockReturnThis(),
|
|
78
|
+
} as any;
|
|
79
|
+
|
|
80
|
+
const infoService = {
|
|
81
|
+
setCharacteristic: jest.fn().mockReturnThis(),
|
|
82
|
+
} as any;
|
|
83
|
+
|
|
84
|
+
const accessory = {
|
|
85
|
+
getService: jest.fn((service) => {
|
|
86
|
+
if (service === ServiceEnum.AccessoryInformation) return infoService;
|
|
87
|
+
if (service === ServiceEnum.AirQualitySensor) return null;
|
|
88
|
+
return null;
|
|
89
|
+
}),
|
|
90
|
+
addService: jest.fn((service) => {
|
|
91
|
+
if (service === ServiceEnum.AirQualitySensor) {
|
|
92
|
+
return airQualityService;
|
|
93
|
+
}
|
|
94
|
+
return airQualityService;
|
|
95
|
+
}),
|
|
96
|
+
} as any;
|
|
97
|
+
|
|
98
|
+
const accessoryInstance = new AirQualitySensorAccessory(platform, accessory, device as any);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
accessoryInstance,
|
|
102
|
+
airQualityService,
|
|
103
|
+
infoService,
|
|
104
|
+
accessory,
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
logger = createMockLogger();
|
|
110
|
+
api = createMockVeSync();
|
|
111
|
+
|
|
112
|
+
mockAPI = {
|
|
113
|
+
hap: {
|
|
114
|
+
Characteristic: {
|
|
115
|
+
AirQuality: AirQualityEnum,
|
|
116
|
+
PM2_5Density: 'PM2_5Density',
|
|
117
|
+
PM10Density: 'PM10Density',
|
|
118
|
+
Manufacturer: 'Manufacturer',
|
|
119
|
+
Model: 'Model',
|
|
120
|
+
SerialNumber: 'SerialNumber',
|
|
121
|
+
Name: 'Name',
|
|
122
|
+
},
|
|
123
|
+
Service: ServiceEnum,
|
|
124
|
+
uuid: {
|
|
125
|
+
generate: jest.fn(),
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
platformAccessory: jest.fn(),
|
|
129
|
+
} as unknown as jest.Mocked<API>;
|
|
130
|
+
|
|
131
|
+
platform = new TSVESyncPlatform(logger, { debug: false, retry: { maxRetries: 3 } } as any, mockAPI);
|
|
132
|
+
(platform as any).api = api;
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('configures AirQuality characteristic to expose VeSync levels', () => {
|
|
136
|
+
const device = createDevice({
|
|
137
|
+
getNormalizedAirQuality: jest.fn().mockReturnValue({ level: 2, label: 'good' }),
|
|
138
|
+
airQualityLevel: 2,
|
|
139
|
+
airQualityLabel: 'good',
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const { airQualityService } = buildAccessory(device);
|
|
143
|
+
|
|
144
|
+
expect(airQualityService.getCharacteristic).toHaveBeenCalledWith(AirQualityEnum);
|
|
145
|
+
const setter = airQualityService.getCharacteristic.mock.results[0].value.setProps;
|
|
146
|
+
expect(setter).toHaveBeenCalledWith({
|
|
147
|
+
validValues: [
|
|
148
|
+
AirQualityEnum.UNKNOWN,
|
|
149
|
+
AirQualityEnum.EXCELLENT,
|
|
150
|
+
AirQualityEnum.GOOD,
|
|
151
|
+
AirQualityEnum.FAIR,
|
|
152
|
+
AirQualityEnum.INFERIOR,
|
|
153
|
+
],
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('returns normalized air quality levels when provided by the device', async () => {
|
|
158
|
+
const device = createDevice({
|
|
159
|
+
getNormalizedAirQuality: jest.fn().mockReturnValue({ level: 3, label: 'moderate' }),
|
|
160
|
+
airQualityValue: 42,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const { accessoryInstance } = buildAccessory(device);
|
|
164
|
+
|
|
165
|
+
const value = await (accessoryInstance as any).getAirQuality();
|
|
166
|
+
expect(value).toBe(AirQualityEnum.FAIR);
|
|
167
|
+
expect(device.getNormalizedAirQuality).toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('falls back to direct level properties when normalized metadata is unavailable', async () => {
|
|
171
|
+
const device = createDevice({
|
|
172
|
+
getNormalizedAirQuality: undefined,
|
|
173
|
+
airQualityLevel: 4,
|
|
174
|
+
details: {
|
|
175
|
+
air_quality_level: 4,
|
|
176
|
+
air_quality_value: 80,
|
|
177
|
+
},
|
|
178
|
+
airQualityValue: 80,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const { accessoryInstance } = buildAccessory(device);
|
|
182
|
+
|
|
183
|
+
const value = await (accessoryInstance as any).getAirQuality();
|
|
184
|
+
expect(value).toBe(AirQualityEnum.INFERIOR);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('falls back to PM2.5 heuristic when no level information is available', async () => {
|
|
188
|
+
const device = createDevice({
|
|
189
|
+
getNormalizedAirQuality: undefined,
|
|
190
|
+
airQualityLevel: undefined,
|
|
191
|
+
details: {
|
|
192
|
+
air_quality_value: 120,
|
|
193
|
+
},
|
|
194
|
+
airQualityValue: 120,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const { accessoryInstance } = buildAccessory(device);
|
|
198
|
+
|
|
199
|
+
const value = await (accessoryInstance as any).getAirQuality();
|
|
200
|
+
expect(value).toBe(AirQualityEnum.INFERIOR);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('clamps PM2.5 density to HomeKit-supported range', async () => {
|
|
204
|
+
const device = createDevice({
|
|
205
|
+
airQualityValue: 1450,
|
|
206
|
+
details: {
|
|
207
|
+
air_quality_value: 1450,
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const { accessoryInstance } = buildAccessory(device);
|
|
212
|
+
|
|
213
|
+
const density = await (accessoryInstance as any).getPM25Density();
|
|
214
|
+
expect(density).toBe(1000);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('updates characteristics during refresh cycle', async () => {
|
|
218
|
+
const device = createDevice({
|
|
219
|
+
airQualityValue: 24,
|
|
220
|
+
getNormalizedAirQuality: jest.fn().mockReturnValue({ level: 2, label: 'good' }),
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const { accessoryInstance, airQualityService } = buildAccessory(device);
|
|
224
|
+
|
|
225
|
+
await (accessoryInstance as any).updateCharacteristics();
|
|
226
|
+
|
|
227
|
+
expect(device.getDetails).toHaveBeenCalled();
|
|
228
|
+
expect(airQualityService.updateCharacteristic).toHaveBeenCalledWith(AirQualityEnum, AirQualityEnum.GOOD);
|
|
229
|
+
expect(airQualityService.updateCharacteristic).toHaveBeenCalledWith('PM2_5Density', 24);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
@@ -299,7 +299,7 @@ describe('BaseAccessory', () => {
|
|
|
299
299
|
expect((accessory as any).convertAirQualityToHomeKit(30)).toBe(2); // GOOD
|
|
300
300
|
expect((accessory as any).convertAirQualityToHomeKit(50)).toBe(3); // FAIR
|
|
301
301
|
expect((accessory as any).convertAirQualityToHomeKit(100)).toBe(4); // INFERIOR
|
|
302
|
-
expect((accessory as any).convertAirQualityToHomeKit(200)).toBe(
|
|
302
|
+
expect((accessory as any).convertAirQualityToHomeKit(200)).toBe(4); // INFERIOR
|
|
303
303
|
});
|
|
304
304
|
|
|
305
305
|
it('should persist device state', async () => {
|
|
@@ -309,4 +309,4 @@ describe('BaseAccessory', () => {
|
|
|
309
309
|
expect(mockAccessory.context.device.details.testKey).toBe('testValue');
|
|
310
310
|
});
|
|
311
311
|
});
|
|
312
|
-
});
|
|
312
|
+
});
|
|
@@ -43,7 +43,6 @@ export class AirQualitySensorAccessory extends BaseAccessory {
|
|
|
43
43
|
this.platform.Characteristic.AirQuality.GOOD,
|
|
44
44
|
this.platform.Characteristic.AirQuality.FAIR,
|
|
45
45
|
this.platform.Characteristic.AirQuality.INFERIOR,
|
|
46
|
-
this.platform.Characteristic.AirQuality.POOR,
|
|
47
46
|
],
|
|
48
47
|
})
|
|
49
48
|
.onGet(this.getAirQuality.bind(this));
|
|
@@ -91,12 +90,15 @@ export class AirQualitySensorAccessory extends BaseAccessory {
|
|
|
91
90
|
*/
|
|
92
91
|
async getAirQuality(): Promise<CharacteristicValue> {
|
|
93
92
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
const level = this.readNormalizedAirQualityLevel();
|
|
94
|
+
if (level >= 1) {
|
|
95
|
+
const hkValue = this.mapToHomeKitAirQuality(level);
|
|
96
|
+
this.platform.log.debug(`${this.device.deviceName} AQ: Normalized air quality level = ${level}`);
|
|
97
|
+
return hkValue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const pm25 = this.getDevicePm25();
|
|
101
|
+
this.platform.log.debug(`${this.device.deviceName} AQ: Falling back to PM2.5 heuristic (${pm25})`);
|
|
100
102
|
return this.convertPM25ToAirQuality(pm25);
|
|
101
103
|
} catch (error) {
|
|
102
104
|
this.platform.log.error(`${this.device.deviceName} AQ: Failed to get air quality:`, error);
|
|
@@ -109,9 +111,7 @@ export class AirQualitySensorAccessory extends BaseAccessory {
|
|
|
109
111
|
*/
|
|
110
112
|
async getPM25Density(): Promise<CharacteristicValue> {
|
|
111
113
|
try {
|
|
112
|
-
|
|
113
|
-
const extendedDevice = this.parentDevice as any;
|
|
114
|
-
const pm25 = extendedDevice.airQualityValue || 0;
|
|
114
|
+
const pm25 = this.getDevicePm25();
|
|
115
115
|
|
|
116
116
|
// HomeKit expects PM2.5 in μg/m³, range 0-1000
|
|
117
117
|
return Math.min(1000, Math.max(0, pm25));
|
|
@@ -148,11 +148,89 @@ export class AirQualitySensorAccessory extends BaseAccessory {
|
|
|
148
148
|
return this.platform.Characteristic.AirQuality.GOOD; // Moderate (12.1-35.4 μg/m³)
|
|
149
149
|
} else if (pm25 <= 55) {
|
|
150
150
|
return this.platform.Characteristic.AirQuality.FAIR; // Unhealthy for Sensitive (35.5-55.4 μg/m³)
|
|
151
|
-
} else if (pm25 <= 150) {
|
|
152
|
-
return this.platform.Characteristic.AirQuality.INFERIOR; // Unhealthy (55.5-150.4 μg/m³)
|
|
153
|
-
} else {
|
|
154
|
-
return this.platform.Characteristic.AirQuality.POOR; // Very Unhealthy (>150.5 μg/m³)
|
|
155
151
|
}
|
|
152
|
+
return this.platform.Characteristic.AirQuality.INFERIOR;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private mapToHomeKitAirQuality(level: number): CharacteristicValue {
|
|
156
|
+
switch (level) {
|
|
157
|
+
case 1:
|
|
158
|
+
return this.platform.Characteristic.AirQuality.EXCELLENT;
|
|
159
|
+
case 2:
|
|
160
|
+
return this.platform.Characteristic.AirQuality.GOOD;
|
|
161
|
+
case 3:
|
|
162
|
+
return this.platform.Characteristic.AirQuality.FAIR;
|
|
163
|
+
case 4:
|
|
164
|
+
return this.platform.Characteristic.AirQuality.INFERIOR;
|
|
165
|
+
default:
|
|
166
|
+
return this.platform.Characteristic.AirQuality.UNKNOWN;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private readNormalizedAirQualityLevel(): number {
|
|
171
|
+
const extendedDevice = this.parentDevice as any;
|
|
172
|
+
|
|
173
|
+
if (typeof extendedDevice.getNormalizedAirQuality === 'function') {
|
|
174
|
+
try {
|
|
175
|
+
const normalized = extendedDevice.getNormalizedAirQuality();
|
|
176
|
+
if (normalized && typeof normalized.level === 'number' && normalized.level >= 1) {
|
|
177
|
+
return normalized.level;
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
this.platform.log.debug(`${this.device.deviceName} AQ: getNormalizedAirQuality failed`, error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const directLevel = extendedDevice.airQualityLevel ?? extendedDevice.details?.air_quality_level;
|
|
185
|
+
if (typeof directLevel === 'number' && directLevel >= 1) {
|
|
186
|
+
return directLevel;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const normalized = this.normalizeAirQuality(
|
|
190
|
+
extendedDevice.airQuality ?? extendedDevice.details?.air_quality ?? extendedDevice.airQualityLabel
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return normalized.level;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private getDevicePm25(): number {
|
|
197
|
+
const extendedDevice = this.parentDevice as any;
|
|
198
|
+
const pm25 = extendedDevice.airQualityValue ?? extendedDevice.details?.air_quality_value ?? extendedDevice.pm25 ?? 0;
|
|
199
|
+
return Number.isFinite(pm25) ? pm25 : 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private normalizeAirQuality(value: unknown): { level: number; label: string } {
|
|
203
|
+
const stringMap: Record<string, number> = {
|
|
204
|
+
'excellent': 1,
|
|
205
|
+
'very good': 1,
|
|
206
|
+
'good': 2,
|
|
207
|
+
'moderate': 3,
|
|
208
|
+
'fair': 3,
|
|
209
|
+
'inferior': 4,
|
|
210
|
+
'poor': 4,
|
|
211
|
+
'bad': 4,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
if (typeof value === 'number') {
|
|
215
|
+
const level = Number.isFinite(value) ? Math.trunc(value) : -1;
|
|
216
|
+
if (level >= 1 && level <= 4) {
|
|
217
|
+
return {
|
|
218
|
+
level,
|
|
219
|
+
label: level === 1 ? 'excellent' : level === 2 ? 'good' : level === 3 ? 'moderate' : 'poor',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
} else if (typeof value === 'string') {
|
|
223
|
+
const normalized = value.trim().toLowerCase();
|
|
224
|
+
const level = stringMap[normalized];
|
|
225
|
+
if (level) {
|
|
226
|
+
return {
|
|
227
|
+
level,
|
|
228
|
+
label: level === 1 ? 'excellent' : level === 2 ? 'good' : level === 3 ? 'moderate' : 'poor',
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return { level: -1, label: 'unknown' };
|
|
156
234
|
}
|
|
157
235
|
|
|
158
236
|
/**
|
|
@@ -234,4 +312,4 @@ export class AirQualitySensorAccessory extends BaseAccessory {
|
|
|
234
312
|
identify(): void {
|
|
235
313
|
this.platform.log.info(`${this.device.deviceName} AQ Sensor: Identify!`);
|
|
236
314
|
}
|
|
237
|
-
}
|
|
315
|
+
}
|
|
@@ -226,8 +226,7 @@ export abstract class BaseAccessory {
|
|
|
226
226
|
if (pm25 <= 12) return 1; // EXCELLENT
|
|
227
227
|
if (pm25 <= 35) return 2; // GOOD
|
|
228
228
|
if (pm25 <= 55) return 3; // FAIR
|
|
229
|
-
|
|
230
|
-
return 5; // POOR
|
|
229
|
+
return 4; // INFERIOR (VeSync exposes four levels)
|
|
231
230
|
}
|
|
232
231
|
|
|
233
232
|
/**
|
|
@@ -67,10 +67,13 @@ export interface VeSyncDeviceWithHumidity extends VeSyncDeviceWithPower {
|
|
|
67
67
|
|
|
68
68
|
export interface VeSyncDeviceWithAirQuality extends VeSyncDeviceWithPower {
|
|
69
69
|
airQuality: number;
|
|
70
|
+
airQualityLevel?: number;
|
|
71
|
+
airQualityLabel?: string;
|
|
70
72
|
pm25?: number;
|
|
71
73
|
filterLife: number;
|
|
72
74
|
mode: string;
|
|
73
75
|
setMode(mode: string): Promise<boolean>;
|
|
76
|
+
getNormalizedAirQuality?(): { level: number; label: string };
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
export interface VeSyncDeviceWithControls extends VeSyncDeviceWithPower {
|
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for AirPurifierAccessory air quality features
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { API } from 'homebridge';
|
|
6
|
-
import { Logger } from 'homebridge';
|
|
7
|
-
import { CharacteristicValue } from 'homebridge';
|
|
8
|
-
import { TSVESyncPlatform } from '../../platform';
|
|
9
|
-
import { VeSync } from 'tsvesync';
|
|
10
|
-
import { AirPurifierAccessory } from '../../accessories/air-purifier.accessory';
|
|
11
|
-
import { createMockLogger, createMockVeSync, createMockService } from '../utils/test-helpers';
|
|
12
|
-
|
|
13
|
-
// Extended mock for air purifier with air quality features
|
|
14
|
-
interface MockAirPurifierWithAirQuality {
|
|
15
|
-
deviceName: string;
|
|
16
|
-
deviceType: string;
|
|
17
|
-
cid: string;
|
|
18
|
-
uuid: string;
|
|
19
|
-
deviceStatus: string;
|
|
20
|
-
hasFeature: jest.Mock;
|
|
21
|
-
airQualityValue: number;
|
|
22
|
-
pm1: number;
|
|
23
|
-
pm10: number;
|
|
24
|
-
filterLife: number;
|
|
25
|
-
details?: {
|
|
26
|
-
air_quality_value?: number;
|
|
27
|
-
pm25?: number;
|
|
28
|
-
pm1?: number;
|
|
29
|
-
pm10?: number;
|
|
30
|
-
filter_life?: number | { percent: number };
|
|
31
|
-
};
|
|
32
|
-
getDetails: jest.Mock;
|
|
33
|
-
turnOn: jest.Mock;
|
|
34
|
-
turnOff: jest.Mock;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
describe('AirPurifierAccessory Air Quality Features', () => {
|
|
38
|
-
let mockAPI: jest.Mocked<API>;
|
|
39
|
-
let platform: TSVESyncPlatform;
|
|
40
|
-
let logger: jest.Mocked<Logger>;
|
|
41
|
-
let api: jest.Mocked<VeSync>;
|
|
42
|
-
let airQualityService: any;
|
|
43
|
-
let airPurifierService: any;
|
|
44
|
-
let infoService: any;
|
|
45
|
-
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
logger = createMockLogger();
|
|
48
|
-
api = createMockVeSync();
|
|
49
|
-
|
|
50
|
-
mockAPI = {
|
|
51
|
-
hap: {
|
|
52
|
-
Characteristic: {
|
|
53
|
-
AirQuality: jest.fn(),
|
|
54
|
-
PM2_5Density: jest.fn(),
|
|
55
|
-
PM10Density: jest.fn(),
|
|
56
|
-
Active: jest.fn(),
|
|
57
|
-
CurrentAirPurifierState: jest.fn(),
|
|
58
|
-
TargetAirPurifierState: jest.fn(),
|
|
59
|
-
RotationSpeed: jest.fn(),
|
|
60
|
-
Manufacturer: jest.fn(),
|
|
61
|
-
Model: jest.fn(),
|
|
62
|
-
SerialNumber: jest.fn(),
|
|
63
|
-
},
|
|
64
|
-
Service: {
|
|
65
|
-
AirPurifier: jest.fn(),
|
|
66
|
-
AirQualitySensor: jest.fn(),
|
|
67
|
-
AccessoryInformation: jest.fn(),
|
|
68
|
-
},
|
|
69
|
-
uuid: {
|
|
70
|
-
generate: jest.fn(),
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
platformAccessory: jest.fn(),
|
|
74
|
-
} as any;
|
|
75
|
-
|
|
76
|
-
platform = new TSVESyncPlatform(logger, {} as any, mockAPI);
|
|
77
|
-
(platform as any).api = api;
|
|
78
|
-
|
|
79
|
-
// Setup mock services
|
|
80
|
-
airQualityService = createMockService();
|
|
81
|
-
airPurifierService = createMockService();
|
|
82
|
-
infoService = {
|
|
83
|
-
setCharacteristic: jest.fn().mockReturnThis(),
|
|
84
|
-
};
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
function createMockAirPurifier(config: Partial<MockAirPurifierWithAirQuality> = {}): MockAirPurifierWithAirQuality {
|
|
88
|
-
return {
|
|
89
|
-
deviceName: config.deviceName || 'Test Air Purifier',
|
|
90
|
-
deviceType: config.deviceType || 'Core300S',
|
|
91
|
-
cid: config.cid || 'test-cid',
|
|
92
|
-
uuid: config.uuid || 'test-uuid',
|
|
93
|
-
deviceStatus: config.deviceStatus || 'on',
|
|
94
|
-
airQualityValue: config.airQualityValue || 25,
|
|
95
|
-
pm1: config.pm1 || 15,
|
|
96
|
-
pm10: config.pm10 || 35,
|
|
97
|
-
filterLife: config.filterLife || 75,
|
|
98
|
-
details: config.details || {
|
|
99
|
-
air_quality_value: config.airQualityValue || 25,
|
|
100
|
-
pm1: config.pm1 || 15,
|
|
101
|
-
pm10: config.pm10 || 35,
|
|
102
|
-
filter_life: config.filterLife || 75,
|
|
103
|
-
},
|
|
104
|
-
hasFeature: jest.fn().mockImplementation((feature: string) => {
|
|
105
|
-
return feature === 'air_quality';
|
|
106
|
-
}),
|
|
107
|
-
getDetails: jest.fn().mockResolvedValue(true),
|
|
108
|
-
turnOn: jest.fn().mockResolvedValue(true),
|
|
109
|
-
turnOff: jest.fn().mockResolvedValue(true),
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
describe('Air Quality Service Setup', () => {
|
|
114
|
-
it('should create air quality service for devices with air quality support', () => {
|
|
115
|
-
const mockDevice = createMockAirPurifier({ airQualityValue: 20 });
|
|
116
|
-
|
|
117
|
-
const accessory = {
|
|
118
|
-
getService: jest.fn((service) => {
|
|
119
|
-
if (service === platform.Service.AccessoryInformation) return infoService;
|
|
120
|
-
if (service === platform.Service.AirPurifier) return airPurifierService;
|
|
121
|
-
if (service === platform.Service.AirQualitySensor) return null; // Not created yet
|
|
122
|
-
return null;
|
|
123
|
-
}),
|
|
124
|
-
addService: jest.fn((service) => {
|
|
125
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
126
|
-
return airQualityService;
|
|
127
|
-
}),
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
131
|
-
|
|
132
|
-
// Verify air quality service was added
|
|
133
|
-
expect(accessory.addService).toHaveBeenCalledWith(platform.Service.AirQualitySensor);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should not create air quality service for devices without air quality support', () => {
|
|
137
|
-
const mockDevice = createMockAirPurifier();
|
|
138
|
-
mockDevice.hasFeature = jest.fn().mockReturnValue(false);
|
|
139
|
-
|
|
140
|
-
const accessory = {
|
|
141
|
-
getService: jest.fn((service) => {
|
|
142
|
-
if (service === platform.Service.AccessoryInformation) return infoService;
|
|
143
|
-
if (service === platform.Service.AirPurifier) return airPurifierService;
|
|
144
|
-
return null;
|
|
145
|
-
}),
|
|
146
|
-
addService: jest.fn(),
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
150
|
-
|
|
151
|
-
// Verify air quality service was not added
|
|
152
|
-
expect(accessory.addService).not.toHaveBeenCalledWith(platform.Service.AirQualitySensor);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
describe('Air Quality Value Conversion', () => {
|
|
157
|
-
let airPurifier: AirPurifierAccessory;
|
|
158
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
159
|
-
|
|
160
|
-
beforeEach(() => {
|
|
161
|
-
mockDevice = createMockAirPurifier();
|
|
162
|
-
|
|
163
|
-
const accessory = {
|
|
164
|
-
getService: jest.fn((service) => {
|
|
165
|
-
if (service === platform.Service.AccessoryInformation) return infoService;
|
|
166
|
-
if (service === platform.Service.AirPurifier) return airPurifierService;
|
|
167
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
168
|
-
return null;
|
|
169
|
-
}),
|
|
170
|
-
addService: jest.fn(),
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('should convert PM2.5 values to HomeKit air quality scale', async () => {
|
|
177
|
-
const testCases = [
|
|
178
|
-
{ pm25: 0, expected: 1 }, // EXCELLENT
|
|
179
|
-
{ pm25: 12, expected: 1 }, // EXCELLENT (0-12)
|
|
180
|
-
{ pm25: 13, expected: 2 }, // GOOD (13-35)
|
|
181
|
-
{ pm25: 35, expected: 2 }, // GOOD
|
|
182
|
-
{ pm25: 36, expected: 3 }, // FAIR (36-55)
|
|
183
|
-
{ pm25: 55, expected: 3 }, // FAIR
|
|
184
|
-
{ pm25: 56, expected: 4 }, // INFERIOR (56-150)
|
|
185
|
-
{ pm25: 150, expected: 4 }, // INFERIOR
|
|
186
|
-
{ pm25: 151, expected: 5 }, // POOR (>150)
|
|
187
|
-
{ pm25: 300, expected: 5 }, // POOR
|
|
188
|
-
];
|
|
189
|
-
|
|
190
|
-
for (const testCase of testCases) {
|
|
191
|
-
mockDevice.airQualityValue = testCase.pm25;
|
|
192
|
-
mockDevice.details!.air_quality_value = testCase.pm25;
|
|
193
|
-
|
|
194
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
195
|
-
expect(result).toBe(testCase.expected);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('should handle edge cases in PM2.5 conversion', async () => {
|
|
200
|
-
// Test boundary values
|
|
201
|
-
mockDevice.airQualityValue = 12.5;
|
|
202
|
-
mockDevice.details!.air_quality_value = 12.5;
|
|
203
|
-
let result = await (airPurifier as any).getAirQuality();
|
|
204
|
-
expect(result).toBe(1); // Should round down to EXCELLENT
|
|
205
|
-
|
|
206
|
-
mockDevice.airQualityValue = 35.5;
|
|
207
|
-
mockDevice.details!.air_quality_value = 35.5;
|
|
208
|
-
result = await (airPurifier as any).getAirQuality();
|
|
209
|
-
expect(result).toBe(3); // Should round to FAIR
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('should handle zero PM2.5 values', async () => {
|
|
213
|
-
mockDevice.airQualityValue = 0;
|
|
214
|
-
mockDevice.details!.air_quality_value = 0;
|
|
215
|
-
|
|
216
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
217
|
-
expect(result).toBe(1); // EXCELLENT
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it('should handle extremely high PM2.5 values', async () => {
|
|
221
|
-
mockDevice.airQualityValue = 999;
|
|
222
|
-
mockDevice.details!.air_quality_value = 999;
|
|
223
|
-
|
|
224
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
225
|
-
expect(result).toBe(5); // POOR
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
describe('PM2.5 Density Characteristic', () => {
|
|
230
|
-
let airPurifier: AirPurifierAccessory;
|
|
231
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
232
|
-
|
|
233
|
-
beforeEach(() => {
|
|
234
|
-
mockDevice = createMockAirPurifier();
|
|
235
|
-
|
|
236
|
-
const accessory = {
|
|
237
|
-
getService: jest.fn((service) => {
|
|
238
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
239
|
-
return airPurifierService;
|
|
240
|
-
}),
|
|
241
|
-
addService: jest.fn(),
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('should return PM2.5 density within HomeKit limits', async () => {
|
|
248
|
-
mockDevice.airQualityValue = 42;
|
|
249
|
-
mockDevice.details!.air_quality_value = 42;
|
|
250
|
-
|
|
251
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
252
|
-
expect(result).toBe(42);
|
|
253
|
-
expect(result).toBeGreaterThanOrEqual(0);
|
|
254
|
-
expect(result).toBeLessThanOrEqual(1000);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('should clamp PM2.5 values above 1000', async () => {
|
|
258
|
-
mockDevice.airQualityValue = 1500;
|
|
259
|
-
mockDevice.details!.air_quality_value = 1500;
|
|
260
|
-
|
|
261
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
262
|
-
expect(result).toBe(1000); // Clamped to maximum
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should handle negative PM2.5 values', async () => {
|
|
266
|
-
mockDevice.airQualityValue = -10;
|
|
267
|
-
mockDevice.details!.air_quality_value = -10;
|
|
268
|
-
|
|
269
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
270
|
-
expect(result).toBe(0); // Clamped to minimum
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('should fallback to pm25 field if air_quality_value is missing', async () => {
|
|
274
|
-
mockDevice.airQualityValue = 35;
|
|
275
|
-
mockDevice.details!.pm25 = 35;
|
|
276
|
-
delete mockDevice.details!.air_quality_value;
|
|
277
|
-
|
|
278
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
279
|
-
expect(result).toBe(35);
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
describe('PM10 Density Characteristic', () => {
|
|
284
|
-
let airPurifier: AirPurifierAccessory;
|
|
285
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
286
|
-
|
|
287
|
-
beforeEach(() => {
|
|
288
|
-
mockDevice = createMockAirPurifier({ pm10: 45 });
|
|
289
|
-
|
|
290
|
-
const accessory = {
|
|
291
|
-
getService: jest.fn((service) => {
|
|
292
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
293
|
-
return airPurifierService;
|
|
294
|
-
}),
|
|
295
|
-
addService: jest.fn(),
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should return PM10 density when available', async () => {
|
|
302
|
-
const result = await (airPurifier as any).getPM10Density();
|
|
303
|
-
expect(result).toBe(45);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it('should handle PM10 values above HomeKit limit', async () => {
|
|
307
|
-
mockDevice.pm10 = 1200;
|
|
308
|
-
mockDevice.details!.pm10 = 1200;
|
|
309
|
-
|
|
310
|
-
const result = await (airPurifier as any).getPM10Density();
|
|
311
|
-
expect(result).toBe(1000); // Clamped to maximum
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it('should handle missing PM10 data', async () => {
|
|
315
|
-
mockDevice.pm10 = 0;
|
|
316
|
-
delete mockDevice.details!.pm10;
|
|
317
|
-
|
|
318
|
-
const result = await (airPurifier as any).getPM10Density();
|
|
319
|
-
expect(result).toBe(0);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it('should only add PM10 characteristic when data is available', () => {
|
|
323
|
-
// Device without PM10 data
|
|
324
|
-
const deviceWithoutPM10 = createMockAirPurifier({ pm10: 0 });
|
|
325
|
-
delete deviceWithoutPM10.details!.pm10;
|
|
326
|
-
|
|
327
|
-
const accessory = {
|
|
328
|
-
getService: jest.fn(() => airQualityService),
|
|
329
|
-
addService: jest.fn(() => airQualityService),
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
const setupCharacteristicSpy = jest.spyOn(AirPurifierAccessory.prototype as any, 'setupCharacteristic');
|
|
333
|
-
|
|
334
|
-
new AirPurifierAccessory(platform, accessory as any, deviceWithoutPM10 as any);
|
|
335
|
-
|
|
336
|
-
// PM10 characteristic should not be set up
|
|
337
|
-
const pm10Calls = setupCharacteristicSpy.mock.calls.filter(call =>
|
|
338
|
-
call[0] === platform.Characteristic.PM10Density
|
|
339
|
-
);
|
|
340
|
-
expect(pm10Calls).toHaveLength(0);
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
describe('Air Quality Data Updates', () => {
|
|
345
|
-
let airPurifier: AirPurifierAccessory;
|
|
346
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
347
|
-
let mockCharacteristic: any;
|
|
348
|
-
|
|
349
|
-
beforeEach(() => {
|
|
350
|
-
mockCharacteristic = {
|
|
351
|
-
updateValue: jest.fn(),
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
mockDevice = createMockAirPurifier();
|
|
355
|
-
|
|
356
|
-
const accessory = {
|
|
357
|
-
getService: jest.fn(() => ({
|
|
358
|
-
getCharacteristic: jest.fn(() => mockCharacteristic),
|
|
359
|
-
})),
|
|
360
|
-
addService: jest.fn(),
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
it('should update air quality characteristics when device updates', async () => {
|
|
367
|
-
// Simulate device update
|
|
368
|
-
mockDevice.airQualityValue = 55;
|
|
369
|
-
mockDevice.pm10 = 75;
|
|
370
|
-
|
|
371
|
-
await (airPurifier as any).updateDeviceState();
|
|
372
|
-
|
|
373
|
-
// Verify characteristics were updated (exact calls depend on implementation)
|
|
374
|
-
expect(mockCharacteristic.updateValue).toHaveBeenCalled();
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it('should handle real-time air quality changes', async () => {
|
|
378
|
-
const initialPM25 = 20;
|
|
379
|
-
const updatedPM25 = 80;
|
|
380
|
-
|
|
381
|
-
// Initial state
|
|
382
|
-
mockDevice.airQualityValue = initialPM25;
|
|
383
|
-
await (airPurifier as any).getAirQuality();
|
|
384
|
-
|
|
385
|
-
// Update state
|
|
386
|
-
mockDevice.airQualityValue = updatedPM25;
|
|
387
|
-
mockDevice.details!.air_quality_value = updatedPM25;
|
|
388
|
-
|
|
389
|
-
const newResult = await (airPurifier as any).getAirQuality();
|
|
390
|
-
expect(newResult).toBe(4); // Should be INFERIOR for PM2.5 = 80
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it('should handle air quality improvements', async () => {
|
|
394
|
-
// Start with poor air quality
|
|
395
|
-
mockDevice.airQualityValue = 200;
|
|
396
|
-
let result = await (airPurifier as any).getAirQuality();
|
|
397
|
-
expect(result).toBe(5); // POOR
|
|
398
|
-
|
|
399
|
-
// Air quality improves
|
|
400
|
-
mockDevice.airQualityValue = 25;
|
|
401
|
-
mockDevice.details!.air_quality_value = 25;
|
|
402
|
-
result = await (airPurifier as any).getAirQuality();
|
|
403
|
-
expect(result).toBe(2); // GOOD
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
describe('Error Handling', () => {
|
|
408
|
-
let airPurifier: AirPurifierAccessory;
|
|
409
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
410
|
-
|
|
411
|
-
beforeEach(() => {
|
|
412
|
-
mockDevice = createMockAirPurifier();
|
|
413
|
-
|
|
414
|
-
const accessory = {
|
|
415
|
-
getService: jest.fn(() => airQualityService),
|
|
416
|
-
addService: jest.fn(),
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it('should handle missing air quality data gracefully', async () => {
|
|
423
|
-
mockDevice.airQualityValue = 0;
|
|
424
|
-
delete mockDevice.details!.air_quality_value;
|
|
425
|
-
delete mockDevice.details!.pm25;
|
|
426
|
-
|
|
427
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
428
|
-
expect(result).toBe(1); // Default to EXCELLENT for 0 value
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
it('should handle device API errors', async () => {
|
|
432
|
-
mockDevice.getDetails = jest.fn().mockRejectedValue(new Error('API Error'));
|
|
433
|
-
|
|
434
|
-
// Should not throw error
|
|
435
|
-
await expect((airPurifier as any).getAirQuality()).resolves.toBeDefined();
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it('should handle corrupted device data', async () => {
|
|
439
|
-
mockDevice.details = null as any;
|
|
440
|
-
|
|
441
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
442
|
-
expect(result).toBe(1); // Default to EXCELLENT
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
it('should handle non-numeric air quality values', async () => {
|
|
446
|
-
mockDevice.airQualityValue = NaN;
|
|
447
|
-
mockDevice.details!.air_quality_value = NaN;
|
|
448
|
-
|
|
449
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
450
|
-
expect(result).toBe(1); // Default to EXCELLENT for NaN
|
|
451
|
-
});
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
describe('Feature Detection', () => {
|
|
455
|
-
it('should detect air quality support correctly', () => {
|
|
456
|
-
const deviceWithAirQuality = createMockAirPurifier();
|
|
457
|
-
deviceWithAirQuality.hasFeature = jest.fn().mockReturnValue(true);
|
|
458
|
-
|
|
459
|
-
const accessory = {
|
|
460
|
-
getService: jest.fn(),
|
|
461
|
-
addService: jest.fn(() => airQualityService),
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const airPurifier = new AirPurifierAccessory(platform, accessory as any, deviceWithAirQuality as any);
|
|
465
|
-
|
|
466
|
-
expect(deviceWithAirQuality.hasFeature).toHaveBeenCalledWith('air_quality');
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
it('should handle devices without air quality support', () => {
|
|
470
|
-
const deviceWithoutAirQuality = createMockAirPurifier();
|
|
471
|
-
deviceWithoutAirQuality.hasFeature = jest.fn().mockReturnValue(false);
|
|
472
|
-
|
|
473
|
-
const accessory = {
|
|
474
|
-
getService: jest.fn(),
|
|
475
|
-
addService: jest.fn(),
|
|
476
|
-
};
|
|
477
|
-
|
|
478
|
-
new AirPurifierAccessory(platform, accessory as any, deviceWithoutAirQuality as any);
|
|
479
|
-
|
|
480
|
-
expect(accessory.addService).not.toHaveBeenCalledWith(platform.Service.AirQualitySensor);
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
});
|