homebridge-tsvesync 1.1.2 → 1.3.4
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 +312 -0
- package/dist/accessories/air-purifier.accessory.d.ts +1 -0
- package/dist/accessories/air-purifier.accessory.d.ts.map +1 -1
- package/dist/accessories/air-purifier.accessory.js +38 -26
- package/dist/accessories/air-purifier.accessory.js.map +1 -1
- package/dist/accessories/light.accessory.d.ts +25 -3
- package/dist/accessories/light.accessory.d.ts.map +1 -1
- package/dist/accessories/light.accessory.js +290 -14
- package/dist/accessories/light.accessory.js.map +1 -1
- package/dist/platform.d.ts +18 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +224 -11
- package/dist/platform.js.map +1 -1
- package/dist/types/device.types.d.ts +16 -0
- package/dist/types/device.types.d.ts.map +1 -1
- package/dist/utils/api-proxy.d.ts +4 -1
- package/dist/utils/api-proxy.d.ts.map +1 -1
- package/dist/utils/api-proxy.js +5 -3
- package/dist/utils/api-proxy.js.map +1 -1
- package/dist/utils/device-factory.d.ts +1 -0
- package/dist/utils/device-factory.d.ts.map +1 -1
- package/dist/utils/device-factory.js +10 -2
- package/dist/utils/device-factory.js.map +1 -1
- package/dist/utils/session-store.d.ts +28 -0
- package/dist/utils/session-store.d.ts.map +1 -0
- package/dist/utils/session-store.js +92 -0
- package/dist/utils/session-store.js.map +1 -0
- package/package.json +2 -2
- package/src/accessories/air-purifier.accessory.ts +38 -22
- package/src/accessories/light.accessory.ts +415 -34
- package/src/platform.ts +223 -9
- package/src/types/device.types.ts +18 -0
- package/src/utils/api-proxy.ts +8 -2
- package/src/utils/device-factory.ts +16 -4
- package/src/utils/session-store.ts +92 -0
|
@@ -24,7 +24,8 @@ const OUTLET_MODELS = [
|
|
|
24
24
|
'ESO15-TB', 'ESW15-USA', 'ESW03-USA', 'ESW01-EU',
|
|
25
25
|
'ESW10-USA', 'wifi-switch-1.3'
|
|
26
26
|
];
|
|
27
|
-
const SWITCH_MODELS = ['
|
|
27
|
+
const SWITCH_MODELS = ['ESWL01', 'ESWL03'];
|
|
28
|
+
const DIMMER_MODELS = ['ESWD16'];
|
|
28
29
|
class DeviceFactory {
|
|
29
30
|
static modelMatches(deviceType, models) {
|
|
30
31
|
const upperDeviceType = deviceType.toUpperCase();
|
|
@@ -46,6 +47,9 @@ class DeviceFactory {
|
|
|
46
47
|
static isBulb(deviceType) {
|
|
47
48
|
return deviceType.startsWith('ESL') || deviceType === 'XYD0001';
|
|
48
49
|
}
|
|
50
|
+
static isDimmer(deviceType) {
|
|
51
|
+
return this.modelMatches(deviceType, DIMMER_MODELS);
|
|
52
|
+
}
|
|
49
53
|
static isOutlet(deviceType) {
|
|
50
54
|
return this.modelMatches(deviceType, OUTLET_MODELS);
|
|
51
55
|
}
|
|
@@ -66,6 +70,10 @@ class DeviceFactory {
|
|
|
66
70
|
if (this.isFan(deviceType)) {
|
|
67
71
|
return new fan_accessory_1.FanAccessory(platform, accessory, device);
|
|
68
72
|
}
|
|
73
|
+
// Dimmers
|
|
74
|
+
if (this.isDimmer(deviceType)) {
|
|
75
|
+
return new light_accessory_1.LightAccessory(platform, accessory, device);
|
|
76
|
+
}
|
|
69
77
|
// Bulbs
|
|
70
78
|
if (this.isBulb(deviceType)) {
|
|
71
79
|
return new light_accessory_1.LightAccessory(platform, accessory, device);
|
|
@@ -93,7 +101,7 @@ class DeviceFactory {
|
|
|
93
101
|
if (this.isFan(type)) {
|
|
94
102
|
return 3 /* Categories.FAN */;
|
|
95
103
|
}
|
|
96
|
-
if (this.isBulb(type)) {
|
|
104
|
+
if (this.isDimmer(type) || this.isBulb(type)) {
|
|
97
105
|
return 5 /* Categories.LIGHTBULB */;
|
|
98
106
|
}
|
|
99
107
|
if (this.isSwitch(type)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-factory.js","sourceRoot":"","sources":["../../src/utils/device-factory.ts"],"names":[],"mappings":";;;AAGA,kFAA6E;AAC7E,8EAA0E;AAC1E,gEAA4D;AAC5D,oEAAgE;AAChE,sEAAkE;AAClE,sEAAkE;AAElE,8FAAwF;
|
|
1
|
+
{"version":3,"file":"device-factory.js","sourceRoot":"","sources":["../../src/utils/device-factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PluginLogger } from './logger';
|
|
2
|
+
export interface PluginSession {
|
|
3
|
+
token: string;
|
|
4
|
+
accountId: string;
|
|
5
|
+
countryCode?: string | null;
|
|
6
|
+
region: string;
|
|
7
|
+
apiBaseUrl: string;
|
|
8
|
+
authFlowUsed?: 'legacy' | 'new';
|
|
9
|
+
issuedAt?: number | null;
|
|
10
|
+
expiresAt?: number | null;
|
|
11
|
+
lastValidatedAt?: number | null;
|
|
12
|
+
libraryVersion?: string;
|
|
13
|
+
username?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class FileSessionStore {
|
|
16
|
+
private readonly logger;
|
|
17
|
+
private readonly dir;
|
|
18
|
+
private readonly file;
|
|
19
|
+
constructor(basePath: string, logger: PluginLogger);
|
|
20
|
+
load(): Promise<PluginSession | null>;
|
|
21
|
+
save(session: PluginSession): Promise<void>;
|
|
22
|
+
clear(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare function decodeJwtTimestampsLocal(token: string): {
|
|
25
|
+
iat?: number;
|
|
26
|
+
exp?: number;
|
|
27
|
+
} | null;
|
|
28
|
+
//# sourceMappingURL=session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../src/utils/session-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,gBAAgB;IAIG,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHrD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,QAAQ,EAAE,MAAM,EAAmB,MAAM,EAAE,YAAY;IAK7D,IAAI,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAsBrC,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAS7B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAa7F"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.decodeJwtTimestampsLocal = exports.FileSessionStore = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class FileSessionStore {
|
|
10
|
+
constructor(basePath, logger) {
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
this.dir = path_1.default.join(basePath, 'tsvesync');
|
|
13
|
+
this.file = path_1.default.join(this.dir, 'session.json');
|
|
14
|
+
}
|
|
15
|
+
async load() {
|
|
16
|
+
try {
|
|
17
|
+
await fs_1.default.promises.mkdir(this.dir, { recursive: true });
|
|
18
|
+
const data = await fs_1.default.promises.readFile(this.file, 'utf8');
|
|
19
|
+
const session = JSON.parse(data);
|
|
20
|
+
if (!session || !session.token || !session.accountId)
|
|
21
|
+
return null;
|
|
22
|
+
try {
|
|
23
|
+
const expSec = session.expiresAt && session.expiresAt > 1e11 ? Math.floor(session.expiresAt / 1000) : session.expiresAt;
|
|
24
|
+
const exp = expSec ? new Date(expSec * 1000).toISOString() : 'unknown';
|
|
25
|
+
this.logger.debug(`Loaded persisted session from ${this.file} (exp: ${exp})`);
|
|
26
|
+
}
|
|
27
|
+
catch (_a) { }
|
|
28
|
+
return session;
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
if ((e === null || e === void 0 ? void 0 : e.code) === 'ENOENT') {
|
|
32
|
+
this.logger.debug(`No persisted session found at ${this.file}`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
this.logger.debug(`Session load error: ${(e === null || e === void 0 ? void 0 : e.message) || e}`);
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async save(session) {
|
|
41
|
+
try {
|
|
42
|
+
await fs_1.default.promises.mkdir(this.dir, { recursive: true });
|
|
43
|
+
const tmp = this.file + '.tmp';
|
|
44
|
+
await fs_1.default.promises.writeFile(tmp, JSON.stringify(session), { encoding: 'utf8', mode: 0o600 });
|
|
45
|
+
await fs_1.default.promises.rename(tmp, this.file);
|
|
46
|
+
try {
|
|
47
|
+
await fs_1.default.promises.chmod(this.file, 0o600);
|
|
48
|
+
}
|
|
49
|
+
catch ( /* best effort */_a) { /* best effort */ }
|
|
50
|
+
try {
|
|
51
|
+
const expSec = session.expiresAt && session.expiresAt > 1e11 ? Math.floor(session.expiresAt / 1000) : session.expiresAt;
|
|
52
|
+
const exp = expSec ? new Date(expSec * 1000).toISOString() : 'unknown';
|
|
53
|
+
this.logger.debug(`Persisted session to ${this.file} (exp: ${exp})`);
|
|
54
|
+
}
|
|
55
|
+
catch (_b) { }
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
this.logger.debug(`Session save error: ${(e === null || e === void 0 ? void 0 : e.message) || e}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async clear() {
|
|
62
|
+
try {
|
|
63
|
+
await fs_1.default.promises.unlink(this.file);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
if ((e === null || e === void 0 ? void 0 : e.code) !== 'ENOENT') {
|
|
67
|
+
this.logger.debug(`Session clear error: ${(e === null || e === void 0 ? void 0 : e.message) || e}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.FileSessionStore = FileSessionStore;
|
|
73
|
+
function decodeJwtTimestampsLocal(token) {
|
|
74
|
+
try {
|
|
75
|
+
const parts = token.split('.');
|
|
76
|
+
if (parts.length !== 3)
|
|
77
|
+
return null;
|
|
78
|
+
const payload = JSON.parse(Buffer.from(parts[1].replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8'));
|
|
79
|
+
let iat = typeof payload.iat === 'number' ? payload.iat : undefined;
|
|
80
|
+
let exp = typeof payload.exp === 'number' ? payload.exp : undefined;
|
|
81
|
+
if (iat && iat > 1e11)
|
|
82
|
+
iat = Math.floor(iat / 1000);
|
|
83
|
+
if (exp && exp > 1e11)
|
|
84
|
+
exp = Math.floor(exp / 1000);
|
|
85
|
+
return { iat, exp };
|
|
86
|
+
}
|
|
87
|
+
catch (_a) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.decodeJwtTimestampsLocal = decodeJwtTimestampsLocal;
|
|
92
|
+
//# sourceMappingURL=session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/utils/session-store.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
|
+
"version": "1.3.4",
|
|
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.
|
|
101
|
+
"tsvesync": "1.3.4"
|
|
102
102
|
},
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@types/jest": "^29.5.11",
|
|
@@ -291,13 +291,20 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
291
291
|
return 3;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
private isCore200S(): boolean {
|
|
295
|
+
return (this.device.deviceType || '').toUpperCase().includes('CORE200S');
|
|
296
|
+
}
|
|
297
|
+
|
|
294
298
|
/**
|
|
295
299
|
* Calculate the appropriate step size for discrete speed levels
|
|
296
300
|
*/
|
|
297
301
|
private calculateRotationSpeedStep(): number {
|
|
298
|
-
// Expose Sleep as the first notch when supported
|
|
302
|
+
// Expose Sleep as the first notch when supported.
|
|
303
|
+
// Core 200S uses 3 manual speeds (25% step). 4-speed models use 20% step.
|
|
299
304
|
if (this.hasFeature('sleep_mode')) {
|
|
300
|
-
return 25;
|
|
305
|
+
if (this.isCore200S()) return 25;
|
|
306
|
+
const max = this.getMaxFanSpeed();
|
|
307
|
+
return max >= 4 ? 20 : 25;
|
|
301
308
|
}
|
|
302
309
|
const maxSpeed = this.getMaxFanSpeed();
|
|
303
310
|
if (maxSpeed === 3) return 33.33;
|
|
@@ -309,12 +316,14 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
309
316
|
* Convert device speed to percentage
|
|
310
317
|
*/
|
|
311
318
|
private speedToPercentage(speed: number): number {
|
|
312
|
-
// Sleep as first notch:
|
|
319
|
+
// Sleep as first notch: map manual speeds to notches based on model
|
|
313
320
|
if (this.hasFeature('sleep_mode')) {
|
|
314
321
|
if (typeof speed !== 'number' || speed <= 0) return 0;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
322
|
+
const step = this.calculateRotationSpeedStep();
|
|
323
|
+
const max = this.isCore200S() ? 3 : this.getMaxFanSpeed();
|
|
324
|
+
// Manual speeds occupy notches 2..(max+1)
|
|
325
|
+
const notch = Math.max(2, Math.min(max + 1, speed + 1));
|
|
326
|
+
return Math.min(100, notch * step);
|
|
318
327
|
}
|
|
319
328
|
|
|
320
329
|
const maxSpeed = this.getMaxFanSpeed();
|
|
@@ -377,13 +386,15 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
377
386
|
* Convert percentage to device speed
|
|
378
387
|
*/
|
|
379
388
|
private percentageToSpeed(percentage: number): number {
|
|
380
|
-
// Sleep as first notch: round to nearest
|
|
389
|
+
// Sleep as first notch: round to nearest step and map notches → speeds
|
|
381
390
|
if (this.hasFeature('sleep_mode')) {
|
|
382
391
|
if (typeof percentage !== 'number') return 1;
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
392
|
+
const step = this.calculateRotationSpeedStep();
|
|
393
|
+
const max = this.isCore200S() ? 3 : this.getMaxFanSpeed();
|
|
394
|
+
const maxNotch = max + 1; // include Sleep notch
|
|
395
|
+
const notch = Math.max(0, Math.min(maxNotch, Math.round(Math.min(100, Math.max(0, percentage)) / step)));
|
|
396
|
+
const manualNotch = Math.max(2, notch);
|
|
397
|
+
return Math.min(max, manualNotch - 1);
|
|
387
398
|
}
|
|
388
399
|
|
|
389
400
|
const maxSpeed = this.getMaxFanSpeed();
|
|
@@ -642,9 +653,10 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
642
653
|
|
|
643
654
|
// Update rotation speed
|
|
644
655
|
if (isOn && this.hasFeature('sleep_mode') && isSleep) {
|
|
645
|
-
this.
|
|
656
|
+
const step = this.calculateRotationSpeedStep();
|
|
657
|
+
this.service.updateCharacteristic(this.platform.Characteristic.RotationSpeed, step);
|
|
646
658
|
this.lastSetSpeed = 0;
|
|
647
|
-
this.lastSetPercentage =
|
|
659
|
+
this.lastSetPercentage = step;
|
|
648
660
|
} else if (isOn && details.speed !== undefined && details.speed !== null) {
|
|
649
661
|
// Check if we should skip this update
|
|
650
662
|
if (this.skipNextUpdate) {
|
|
@@ -756,7 +768,7 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
756
768
|
|
|
757
769
|
// For all other devices, including Core300S, normal mode handling
|
|
758
770
|
const mode = targetState === 1 ? 'auto' : 'manual';
|
|
759
|
-
this.platform.log.
|
|
771
|
+
this.platform.log.info(`Changing mode to ${mode} for device: ${this.device.deviceName}`);
|
|
760
772
|
|
|
761
773
|
let success = false;
|
|
762
774
|
|
|
@@ -795,7 +807,7 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
795
807
|
// If in sleep mode, surface the first notch
|
|
796
808
|
const extended = this.device as ExtendedVeSyncAirPurifier;
|
|
797
809
|
if (this.hasFeature('sleep_mode') && (extended.mode || '').toLowerCase() === 'sleep') {
|
|
798
|
-
return
|
|
810
|
+
return this.calculateRotationSpeedStep();
|
|
799
811
|
}
|
|
800
812
|
return 0;
|
|
801
813
|
}
|
|
@@ -866,10 +878,13 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
866
878
|
|
|
867
879
|
// When using sleep-as-first-notch, map slider notches robustly by rounding
|
|
868
880
|
if (this.hasFeature('sleep_mode')) {
|
|
869
|
-
const
|
|
881
|
+
const max = this.isCore200S() ? 3 : this.getMaxFanSpeed();
|
|
882
|
+
const step = this.calculateRotationSpeedStep();
|
|
883
|
+
const maxNotch = max + 1; // include Sleep notch
|
|
884
|
+
const notch = Math.max(0, Math.min(maxNotch, Math.round(percentage / step)));
|
|
870
885
|
if (notch <= 1) {
|
|
871
886
|
// Sleep
|
|
872
|
-
this.platform.log.
|
|
887
|
+
this.platform.log.info(`Changing mode to sleep for device: ${this.device.deviceName}`);
|
|
873
888
|
let ok = false;
|
|
874
889
|
if (typeof extendedDevice.sleepMode === 'function') {
|
|
875
890
|
ok = await extendedDevice.sleepMode();
|
|
@@ -880,19 +895,20 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
880
895
|
throw new Error('Failed to set sleep mode');
|
|
881
896
|
}
|
|
882
897
|
// Immediate UI feedback
|
|
883
|
-
this.service.updateCharacteristic(this.platform.Characteristic.RotationSpeed,
|
|
898
|
+
this.service.updateCharacteristic(this.platform.Characteristic.RotationSpeed, step);
|
|
884
899
|
this.service.updateCharacteristic(this.platform.Characteristic.Active, 1);
|
|
885
900
|
this.service.updateCharacteristic(this.platform.Characteristic.CurrentAirPurifierState, 2);
|
|
886
901
|
this.lastSetSpeed = 0;
|
|
887
|
-
this.lastSetPercentage =
|
|
902
|
+
this.lastSetPercentage = step;
|
|
888
903
|
this.skipNextUpdate = true;
|
|
889
904
|
return;
|
|
890
905
|
} else {
|
|
891
|
-
// Map notches 2
|
|
892
|
-
const desiredSpeed = Math.min(
|
|
906
|
+
// Map manual notches (2..maxNotch) to speeds 1..max
|
|
907
|
+
const desiredSpeed = Math.min(max, notch - 1);
|
|
893
908
|
// Ensure manual mode before speed change if necessary
|
|
894
909
|
const modeNow = (extendedDevice.mode || '').toLowerCase();
|
|
895
910
|
if (modeNow === 'auto' || modeNow === 'sleep') {
|
|
911
|
+
this.platform.log.info(`Changing mode to manual for device: ${this.device.deviceName}`);
|
|
896
912
|
if (typeof extendedDevice.manualMode === 'function') {
|
|
897
913
|
await extendedDevice.manualMode();
|
|
898
914
|
} else if (typeof extendedDevice.setMode === 'function') {
|
|
@@ -900,7 +916,7 @@ export class AirPurifierAccessory extends BaseAccessory {
|
|
|
900
916
|
}
|
|
901
917
|
}
|
|
902
918
|
// Update UI early
|
|
903
|
-
const uiPct = desiredSpeed
|
|
919
|
+
const uiPct = Math.min(100, (desiredSpeed + 1) * step);
|
|
904
920
|
this.service.updateCharacteristic(this.platform.Characteristic.RotationSpeed, uiPct);
|
|
905
921
|
this.lastSetSpeed = desiredSpeed;
|
|
906
922
|
this.lastSetPercentage = uiPct;
|