Skip to content

Commit

Permalink
55: support LEH-S601S-WUS and allow disabling humidity sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Schroeder authored and Paul Schroeder committed Dec 19, 2023
1 parent 4d8ae3b commit 46b93ad
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extron Debugging",
"name": "Launch Debugging",
"program": "node_modules/homebridge/bin/homebridge",
"preLaunchTask": "npm: build",
"request": "launch",
Expand Down
6 changes: 6 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
"type": "boolean",
"default": true,
"description": "Enable brightness slider / switch for the Night Light"
},
"humidity_sensor": {
"title": "Humidity Sensor",
"type": "boolean",
"default": true,
"description": "Expose humidity sensor from device(s) to HomeKit"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"displayName": "Levoit Humidifiers",
"main": "dist/index.js",
"license": "Apache-2.0",
"version": "1.9.0",
"version": "1.9.2-beta1",
"private": false,
"bugs": {
"url": "https://github.com/pschroeder89/homebridge-levoit-humidifiers/issues"
Expand Down
19 changes: 11 additions & 8 deletions src/VeSyncAccessory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type AccessoryThisType = ThisType<{

export default class VeSyncAccessory {
private humidifierService: Service;
private humiditySensorService: Service;
private humiditySensorService: Service | undefined;
private lightService: Service | undefined;
private sleepService: Service | undefined;
private displayService: Service | undefined;
Expand Down Expand Up @@ -83,6 +83,7 @@ export default class VeSyncAccessory {
const nightLightAccessory = (accessories.night_light != false);
const sleepModeAccessory = (accessories.sleep_mode != false);
const displayAccessory = (accessories.display != false);
const humiditySensor = (accessories.humidity_sensor != false);

// Accessory info
this.accessory
Expand Down Expand Up @@ -186,15 +187,17 @@ export default class VeSyncAccessory {
}

// Humidity Sensor service
this.humiditySensorService =
this.accessory.getService(HumiditySensorName) ||
this.accessory.addService(this.platform.Service.HumiditySensor, HumiditySensorName, HumiditySensorName);
if (humiditySensor) {
this.humiditySensorService =
this.accessory.getService(HumiditySensorName) ||
this.accessory.addService(this.platform.Service.HumiditySensor, HumiditySensorName, HumiditySensorName);

this.humidifierService.addLinkedService(this.humiditySensorService);
this.humidifierService.addLinkedService(this.humiditySensorService);

this.humiditySensorService
.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity)
.onGet(Humidity.get.bind(this));
this.humiditySensorService
.getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity)
.onGet(Humidity.get.bind(this));
}

// Warm Mist service
if (this.device.deviceType.hasWarmMode && warmMistAccessory) {
Expand Down
5 changes: 3 additions & 2 deletions src/api/VeSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default class VeSync {

private readonly AXIOS_OPTIONS = {
baseURL: 'https://smartapi.vesync.com',
timeout: 15000
timeout: this.config.options.apiTimeout || 15000
};

constructor(
Expand Down Expand Up @@ -221,7 +221,8 @@ export default class VeSync {
...this.AXIOS_OPTIONS
}
);

this.debugMode.debug("Axios timeout is: " + this.config.options.apiTimeout);

if (!response?.data) {
this.debugMode.debug(
'[LOGIN]',
Expand Down
55 changes: 27 additions & 28 deletions src/api/VeSyncFan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import AsyncLock from 'async-lock';
import { json } from 'stream/consumers';
import deviceTypes, { DeviceName, DeviceType } from './deviceTypes';
import deviceTypes, { DeviceName, DeviceType, NewDevices } from './deviceTypes';

import VeSync, { BypassMethod } from './VeSync';

Expand Down Expand Up @@ -124,16 +123,16 @@ export default class VeSyncFan {
this.client.log.info("Setting Power to " + power);
// Oasis 1000 uses a different field to set power
let switchJson;
if (this.model.includes("LUH-M101S")) {
if (NewDevices.includes(this.model as DeviceName)) {
switchJson = {
powerSwitch: power ? 1 : 0,
id: 0
}
};
} else {
switchJson = {
enabled: power,
id: 0
}
};
}
const success = await this.client.sendCommand(this, BypassMethod.SWITCH, switchJson);

Expand Down Expand Up @@ -169,16 +168,16 @@ export default class VeSyncFan {

// Oasis 1000 uses camelcase instead of snakecase
let humidityJson;
if (this.model.includes("LUH-M101S")) {
if (NewDevices.includes(this.model as DeviceName)) {
humidityJson = {
"targetHumidity": level,
id: 0
}
};
} else {
humidityJson = {
"target_humidity": level,
id: 0
}
};
}

const success = await this.client.sendCommand(this, BypassMethod.HUMIDITY, humidityJson);
Expand Down Expand Up @@ -207,14 +206,14 @@ export default class VeSyncFan {

// Oasis 1000 uses camelcase instead of snakecase
let modeJson;
if (this.model.includes("LUH-M101S")) {
if (NewDevices.includes(this.model as DeviceName)) {
modeJson = {
"workMode": mode.toString(),
}
};
} else {
modeJson = {
"mode": mode.toString(),
}
};
}
// Don't change the mode if we are already in that mode
if (this._mode == mode) {
Expand Down Expand Up @@ -250,16 +249,16 @@ export default class VeSyncFan {

// Oasis 1000 uses camelcase instead of snakecase
let displayJson;
if (this.model.includes("LUH-M101S")) {
if (NewDevices.includes(this.model as DeviceName)) {
displayJson = {
screenSwitch: power ? 1 : 0,
id: 0
}
};
} else {
displayJson = {
state: power,
id: 0
}
};
}

const success = await this.client.sendCommand(this, BypassMethod.DISPLAY, displayJson);
Expand All @@ -282,21 +281,21 @@ export default class VeSyncFan {
let coolMistJson;
let method;

if (this.model.includes("LUH-M101S")) {
// We don't know the correct structure of the JSON, so this does not work. Cool Mist slider is removed from hhis model for now.
if (NewDevices.includes(this.model as DeviceName)) {
// We don't know the correct structure of the JSON, so this does not work. Cool Mist slider is removed from this model for now.
// method = BypassMethod.LEVEL
// coolMistJson = {
// level: coolMistLevel,
// type: 'mist',
// id: 0
// }
} else {
method = BypassMethod.MIST_LEVEL
method = BypassMethod.MIST_LEVEL;
coolMistJson = {
level: coolMistLevel,
type: 'mist',
id: 0
}
};
}

const success = await this.client.sendCommand(this, method, coolMistJson);
Expand Down Expand Up @@ -342,10 +341,10 @@ export default class VeSyncFan {

public async setLightStatus(action: string, brightness: number): Promise<boolean> {
// Get the current RGB values and brightness %
let red = this._red;
let green = this._green;
let blue = this._blue;
let currentBrightness = this.brightnessLevel;
const red = this._red;
const green = this._green;
const blue = this._blue;
const currentBrightness = this.brightnessLevel;
let newRed;
let newBlue;
let newGreen;
Expand Down Expand Up @@ -373,10 +372,10 @@ export default class VeSyncFan {

if (success) {
this._brightnessLevel = brightness;
this._blue = newBlue || this.getBlue
this._green = newGreen || this.getGreen
this._red = newRed || this.getRed
this._lightOn = action
this._blue = newBlue || this.getBlue;
this._green = newGreen || this.getGreen;
this._red = newRed || this.getRed;
this._lightOn = action;
// Not setting these for now, so don't set them
// this._lightSpeed = this.getLightSpeed
// this._colorMode = this.getColorMode
Expand Down Expand Up @@ -412,8 +411,8 @@ export default class VeSyncFan {
const result = data?.result?.result;

this._humidityLevel = result.humidity;
// Fields are different on OasisMist 1000s
if (this.model.includes("LUH-M101S")) {
// Fields are different on newer models
if (NewDevices.includes(this.model as DeviceName)) {
this._targetHumidity = result.targetHumidity;
this._displayOn = result.screenSwitch;
this._mode = result.workMode;
Expand Down
21 changes: 21 additions & 0 deletions src/api/deviceTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,17 @@ export enum DeviceName {
OASIS_1000S_UK = "LUH-M101S-WUK",
OASIS_1000S_EU = "LUH-M101S-WEU",
OASIS_1000S_JP = "LUH-M101S-WJP",
LEH_S601S_WUS = "LEH-S601S-WUS"
}

export const NewDevices = [
DeviceName.OASIS_1000S,
DeviceName.OASIS_1000S_EU,
DeviceName.OASIS_1000S_JP,
DeviceName.OASIS_1000S_UK,
DeviceName.LEH_S601S_WUS
];

export interface DeviceType {
isValid: (input: string) => boolean;
hasAutoMode: boolean;
Expand Down Expand Up @@ -295,6 +304,18 @@ const deviceTypes: DeviceType[] = [
minHumidityLevel: 40,
maxHumidityLevel: 80
},
{
isValid: (input: string) =>
input.includes(DeviceName.LEH_S601S_WUS),
hasAutoMode: true,
coolMistLevels: 9,
hasLight: false,
hasColorMode: false,
hasSleepMode: true,
hasWarmMode: false,
minHumidityLevel: 40,
maxHumidityLevel: 80
},
];

export default deviceTypes;
2 changes: 1 addition & 1 deletion src/characteristics/LightBrightness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const characteristic: {
// We allow 39 as a value so 40 doesn't turn off the device.
// So never set the device to 39, since that's not actually supported
if (value === 39) {
value + 1
value + 1;
}
let action: string;
if (value >= 40) {
Expand Down

0 comments on commit 46b93ad

Please sign in to comment.