Skip to content

Commit

Permalink
add support for vital purifiers (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandawg93 authored Apr 8, 2024
1 parent 1497da9 commit 842db87
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 23 deletions.
13 changes: 12 additions & 1 deletion src/api/VeSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ export default class VeSync {
);


const purifiers = list
let purifiers = list
.filter(
({ deviceType, type, extension }) =>
!!deviceTypes.find(({ isValid }) => isValid(deviceType)) &&
Expand All @@ -343,6 +343,17 @@ export default class VeSync {
)
.map(VeSyncFan.fromResponse(this));

// Newer Vital purifiers
purifiers = purifiers.concat(list
.filter(
({ deviceType, type, deviceProp }) =>
!!deviceTypes.find(({ isValid }) => isValid(deviceType)) &&
type === 'wifi-air' &&
!!deviceProp
)
.map((fan: any) => ({ ...fan, extension: { ...fan.deviceProp, airQualityLevel: fan.deviceProp.AQLevel, mode: fan.deviceProp.workMode } }))
.map(VeSyncFan.fromResponse(this)));

const humidifiers = list
.filter(
({ deviceType, type, extension }) =>
Expand Down
64 changes: 43 additions & 21 deletions src/api/VeSyncFan.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import AsyncLock from 'async-lock';
import deviceTypes, { DeviceType } from './deviceTypes';
import deviceTypes, { DeviceType, DeviceCategory } from './deviceTypes';

import VeSync, { BypassMethod } from './VeSync';
import { VeSyncGeneric } from './VeSyncGeneric';
Expand All @@ -20,6 +20,7 @@ export enum Mode {
export default class VeSyncFan implements VeSyncGeneric {
private lock: AsyncLock = new AsyncLock();
public readonly deviceType: DeviceType;
public readonly deviceCategory: DeviceCategory;
private lastCheck = 0;

private _screenVisible = true;
Expand Down Expand Up @@ -85,12 +86,16 @@ export default class VeSyncFan implements VeSyncGeneric {
public readonly mac: string
) {
this.deviceType = deviceTypes.find(({ isValid }) => isValid(this.model))!;
this.deviceCategory = this.model.includes('V') ? 'Vital' : 'Core';
}

public async setChildLock(lock: boolean): Promise<boolean> {
const success = await this.client.sendCommand(this, BypassMethod.LOCK, {
child_lock: lock
});
const data = this.deviceCategory === 'Vital' ? {
childLockSwitch: lock ? 1 : 0
} : {
child_lock: lock,
};
const success = await this.client.sendCommand(this, BypassMethod.LOCK, data);

if (success) {
this._childLock = lock;
Expand All @@ -100,10 +105,14 @@ export default class VeSyncFan implements VeSyncGeneric {
}

public async setPower(power: boolean): Promise<boolean> {
const success = await this.client.sendCommand(this, BypassMethod.SWITCH, {
enabled: power,
const data = this.deviceCategory === 'Vital' ? {
powerSwitch: power ? 1 : 0,
switchIdx: 0
} : {
switch: power,
id: 0
});
};
const success = await this.client.sendCommand(this, BypassMethod.SWITCH, data);

if (success) {
this._isOn = power;
Expand All @@ -120,9 +129,12 @@ export default class VeSyncFan implements VeSyncGeneric {
return false;
}

const success = await this.client.sendCommand(this, BypassMethod.MODE, {
const data = this.deviceCategory === 'Vital' ? {
workMode: mode.toString()
} : {
mode: mode.toString()
});
};
const success = await this.client.sendCommand(this, BypassMethod.MODE, data);

if (success) {
this._mode = mode;
Expand All @@ -136,11 +148,17 @@ export default class VeSyncFan implements VeSyncGeneric {
return false;
}

const success = await this.client.sendCommand(this, BypassMethod.SPEED, {
const data = this.deviceCategory === 'Vital' ? {
manualSpeedLevel: speed,
switchIdx: 0,
type: 'wind'
} : {
level: speed,
type: 'wind',
id: 0
});
};

const success = await this.client.sendCommand(this, BypassMethod.SPEED, data);

if (success) {
this._speed = speed;
Expand All @@ -150,10 +168,14 @@ export default class VeSyncFan implements VeSyncGeneric {
}

public async setDisplay(display: boolean): Promise<boolean> {
const success = await this.client.sendCommand(this, BypassMethod.DISPLAY, {
const data = this.deviceCategory === 'Vital' ? {
screenSwitch: display ? 1 : 0
} : {
state: display,
id: 0
});
};

const success = await this.client.sendCommand(this, BypassMethod.DISPLAY, data);

if (success) {
this._screenVisible = display;
Expand All @@ -178,16 +200,16 @@ export default class VeSyncFan implements VeSyncGeneric {

const result = data?.result?.result;

this._pm25 = this.deviceType.hasPM25 ? result.air_quality_value : 0;
this._pm25 = this.deviceType.hasPM25 ? result.air_quality_value || result.PM25 : 0;
this._airQualityLevel = this.deviceType.hasAirQuality
? result.air_quality
? result.air_quality || result.AQLevel
: AirQuality.UNKNOWN;
this._filterLife = result.filter_life;
this._screenVisible = result.display;
this._childLock = result.child_lock;
this._isOn = result.enabled;
this._speed = result.level;
this._mode = result.mode;
this._filterLife = result.filter_life || result.filterLifePercent;
this._screenVisible = result.display || result.screenSwitch;
this._childLock = result.child_lock || result.childLockSwitch;
this._isOn = result.enabled || result.powerSwitch;
this._speed = result.level || result.fanSpeedLevel;
this._mode = result.mode || result.workMode;
} catch (err: any) {
this.client.log.error(err?.message);
}
Expand Down
16 changes: 15 additions & 1 deletion src/api/deviceTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export enum DeviceName {
Core301S = '301S',
Core300S = '300S',
Core201S = '201S',
Core200S = '200S'
Core200S = '200S',
Vital100S = 'V102S',
Vital200S = 'V201S',
}

export enum HumidifierDeviceName {
Expand All @@ -26,6 +28,8 @@ export interface DeviceType {
hasPM25: boolean;
}

export type DeviceCategory = 'Core' | 'Vital';

export type HumidifierDeviceType = Omit<DeviceType, 'hasPM25' | 'hasAirQuality'> & { isHumidifier: true };

const deviceTypes: DeviceType[] = [
Expand Down Expand Up @@ -63,6 +67,16 @@ const deviceTypes: DeviceType[] = [
speedLevels: 4,
hasPM25: false
},
{
isValid: (input: string) =>
input.includes(DeviceName.Vital100S) ||
input.includes(DeviceName.Vital200S),
hasAirQuality: true,
hasAutoMode: true,
speedMinStep: 25,
speedLevels: 4,
hasPM25: true
},
];

export const humidifierDeviceTypes: HumidifierDeviceType[] = [
Expand Down

0 comments on commit 842db87

Please sign in to comment.