Skip to content

Commit

Permalink
[veSync] Vital and 131 Purifiers base support
Browse files Browse the repository at this point in the history
PUR131 and Vital additions
Signed-off-by: David Goodyear <[email protected]>
  • Loading branch information
dag81 committed Jul 28, 2023
1 parent 0fe1447 commit 61038d4
Show file tree
Hide file tree
Showing 19 changed files with 809 additions and 137 deletions.
110 changes: 88 additions & 22 deletions bundles/org.openhab.binding.vesync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Air Humidifier models supported are Dual 200S, Classic 300S, 600S, OasisMist Sma

## Awaiting User Verification Models

Air Filtering models supported are Core200S and Core600S.
Air Filtering models supported are Core200S, Core600S, 131S models and the Vital 100S, 200S.
Air Humidifier Classic 200S (Same as 300S without the nightlight from initial checks)

## Supported Things
Expand Down Expand Up @@ -66,25 +66,27 @@ Channel names in **bold** are read/write, everything else is read-only

### AirPurifier Thing

| Channel | Type | Description | Model's Supported | Controllable Values |
|----------------------|----------------------|------------------------------------------------------------|-------------------|-----------------------|
| **enabled** | Switch | Whether the hardware device is enabled (Switched on) | 600S, 400S, 300S | [ON, OFF] |
| **childLock** | Switch | Whether the child lock (display lock is enabled) | 600S, 400S, 300S | [ON, OFF] |
| **display** | Switch | Whether the display is enabled (display is shown) | 600S, 400S, 300S | [ON, OFF] |
| **fanMode** | String | The operation mode of the fan | 600S, 400S | [auto, manual, sleep] |
| **fanMode** | String | The operation mode of the fan | 200S, 300S, | [manual, sleep] |
| **manualFanSpeed** | Number:Dimensionless | The speed of the fan when in manual mode | 600S, 400S | [1...4] |
| **manualFanSpeed** | Number:Dimensionless | The speed of the fan when in manual mode | 300S | [1...3] |
| **nightLightMode** | String | The night lights mode | 200S, 300S | [on, dim, off] |
| filterLifePercentage | Number:Dimensionless | The remaining filter life as a percentage | 600S, 400S, 300S | |
| airQuality | Number:Dimensionless | The air quality as represented by the Core200S / Core300S | 600S, 400S, 300S | |
| airQualityPM25 | Number:Density | The air quality as represented by the Core400S | 600S, 400S, 300S | |
| errorCode | Number:Dimensionless | The error code reported by the device | 600S, 400S, 300S | |
| timerExpiry | DateTime | The expected expiry time of the current timer | 600S, 400S | |
| schedulesCount | Number:Dimensionless | The number schedules configured | 600S, 400S | |
| configDisplayForever | Switch | Config: Whether the display will disable when not active | 600S, 400S, 300S | |
| configAutoMode | String | Config: The mode of operation when auto is active | 600S, 400S, 300S | |
| configAutoRoomSize | Number:Dimensionless | Config: The room size set when auto utilises the room size | 600S, 400S, 300S | |
| Channel | Type | Description | Model's Supported | Controllable Values |
|----------------------|----------------------|------------------------------------------------------------|------------------------------------------------|----------------------------|
| **enabled** | Switch | Whether the hardware device is enabled (Switched on) | 131S, 600S, 400S, 300S, Vital 100S, Vital 200S | [ON, OFF] |
| **childLock** | Switch | Whether the child lock (display lock is enabled) | 600S, 400S, 300S, Vital 100S, Vital 200S | [ON, OFF] |
| **display** | Switch | Whether the display is enabled (display is shown) | 131S, 600S, 400S, 300S, Vital 100S, Vital 200S | [ON, OFF] |
| **fanMode** | String | The operation mode of the fan | 131S, 600S, 400S, Vital 100S | [auto, manual, sleep] |
| **fanMode** | String | The operation mode of the fan | 200S, 300S, | [manual, sleep] |
| **fanMode** | String | The operation mode of the fan | Vital 200S | [auto, manual, sleep, pet] |
| **manualFanSpeed** | Number:Dimensionless | The speed of the fan when in manual mode | 600S, 400S | [1...4] |
| **manualFanSpeed** | Number:Dimensionless | The speed of the fan when in manual mode | 131S, 300S | [1...3] |
| **manualFanSpeed** | Number:Dimensionless | The speed of the fan when in manual mode | Vital 100S,Vital 200S | [1...5] |
| **nightLightMode** | String | The night lights mode | 200S, 300S | [on, dim, off] |
| filterLifePercentage | Number:Dimensionless | The remaining filter life as a percentage | 131S, 600S, 400S, 300S, Vital 100S, Vital 200S | |
| airQuality | Number:Dimensionless | The air quality as represented by the Core200S / Core300S | 131S, 600S, 400S, 300S, Vital 100S, Vital 200S | |
| airQualityPM25 | Number:Density | The air quality as represented by the Core400S | 600S, 400S, 300S, Vital 100S, Vital 200S | |
| errorCode | Number:Dimensionless | The error code reported by the device | 600S, 400S, 300S | |
| timerExpiry | DateTime | The expected expiry time of the current timer | 600S, 400S | |
| schedulesCount | Number:Dimensionless | The number schedules configured | 600S, 400S | |
| configDisplayForever | Switch | Config: Whether the display will disable when not active | 600S, 400S, 300S | |
| configAutoMode | String | Config: The mode of operation when auto is active | 600S, 400S, 300S | |
| configAutoRoomSize | Number:Dimensionless | Config: The room size set when auto utilises the room size | 600S, 400S, 300S | |

### AirHumidifier Thing

Expand Down Expand Up @@ -137,7 +139,7 @@ DateTime LoungeAPTimerExpiry "Lounge Air Purifier Timer Ex
Number LoungeAPSchedulesCount "Lounge Air Purifier Schedules Count" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:schedulesCount" }
```

#### Air Purifier Core 200S/300S Model
#### Air Purifier Core 200S / 300S Model

```java
Switch LoungeAPPower "Lounge Air Purifier Power" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:enabled" }
Expand All @@ -155,6 +157,29 @@ DateTime LoungeAPTimerExpiry "Lounge Air Purifier Timer Ex
Number LoungeAPSchedulesCount "Lounge Air Purifier Schedules Count" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:schedulesCount" }
```

#### Air Purifier 131s Models

```java
Switch LoungeAPPower "Lounge Air Purifier Power" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:enabled" }
Switch LoungeAPDisplay "Lounge Air Purifier Display" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:display" }
Number:Dimensionless LoungeAPFilterRemainingUse "Lounge Air Purifier Filter Remaining [%.0f %unit%]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:filterLifePercentage" }
String LoungeAPMode "Lounge Air Purifier Mode [%s]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:fanMode" }
Number:Dimensionless LoungeAPManualFanSpeed "Lounge Air Purifier Manual Fan Speed" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:manualFanSpeed" }
Number:Dimensionless LoungeAPAirQuality "Lounge Air Purifier Air Quality" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:airQuality" }
```

#### Air Purifier Vital 100s / 200s Models

```java
Switch LoungeAPPower "Lounge Air Purifier Power" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:enabled" }
Switch LoungeAPDisplay "Lounge Air Purifier Display" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:display" }
Switch LoungeAPControlsLock "Lounge Air Purifier Controls Locked" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:childLock" }
Number:Dimensionless LoungeAPFilterRemainingUse "Lounge Air Purifier Filter Remaining [%.0f %unit%]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:filterLifePercentage" }
String LoungeAPMode "Lounge Air Purifier Mode [%s]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:fanMode" }
Number:Dimensionless LoungeAPManualFanSpeed "Lounge Air Purifier Manual Fan Speed" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:manualFanSpeed" }
Number:Density LoungeAPAirQuality "Lounge Air Purifier Air Quality [%.0f% %unit%]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:airQualityPM25" }
```

#### Air Humidifier Classic 200S / Dual 200S Model

```java
Expand Down Expand Up @@ -234,7 +259,7 @@ Frame {
}
```

#### Air Purifier Core 200S/300S Model
#### Air Purifier Core 200S / 300S Model

```perl
Frame {
Expand All @@ -251,6 +276,47 @@ Frame {
}
```

#### Air Purifier 131s Models

```perl
Frame {
Switch item=LoungeAPPower label="Power"
Text item=LoungeAPFilterRemainingUse label="Filter Remaining"
Switch item=LoungeAPDisplay label="Display"
Text item=LoungeAPAirQuality label="Air Quality [%.0f]"
Switch item=LoungeAPMode label="Mode" mappings=[auto="Auto",manual="Manual Fan Control", sleep="Sleeping"] icon="settings"
Switch item=LoungeAPManualFanSpeed label="Manual Fan Speed [%.0f]" mappings=[1="1", 2="2", 3="3"] icon="settings"
}
```

#### Air Purifier Vital 100S Models

```perl
Frame {
Switch item=LoungeAPPower label="Power"
Text item=LoungeAPFilterRemainingUse label="Filter Remaining"
Switch item=LoungeAPDisplay label="Display"
Text item=LoungeAPAirQuality label="Air Quality [%.0f (PM2.5)]"
Switch item=LoungeAPControlsLock label="Controls Locked"
Switch item=LoungeAPMode label="Mode" mappings=[auto="Auto", manual="Manual Fan Control", sleep="Sleeping"] icon="settings"
Switch item=LoungeAPManualFanSpeed label="Manual Fan Speed [%.0f]" mappings=[1="1", 2="2", 3="3", 4="4", 5="5"] icon="settings"
}
```

#### Air Purifier Vital 200S Models

```perl
Frame {
Switch item=LoungeAPPower label="Power"
Text item=LoungeAPFilterRemainingUse label="Filter Remaining"
Switch item=LoungeAPDisplay label="Display"
Text item=LoungeAPAirQuality label="Air Quality [%.0f (PM2.5)]"
Switch item=LoungeAPControlsLock label="Controls Locked"
Switch item=LoungeAPMode label="Mode" mappings=[auto="Auto", manual="Manual Fan Control", sleep="Sleeping", pet="Pet"] icon="settings"
Switch item=LoungeAPManualFanSpeed label="Manual Fan Speed [%.0f]" mappings=[1="1", 2="2", 3="3", 4="4", 5="5"] icon="settings"
}
```

#### Air Humidifier Classic 200S / Dual 200S Model

```perl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class VeSyncConstants {

public static final Gson GSON = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting()
.disableHtmlEscaping().serializeNulls().create();
.disableHtmlEscaping().create();

private static final String BINDING_ID = "vesync";

Expand Down Expand Up @@ -65,6 +65,8 @@ public class VeSyncConstants {
public static final String DEVICE_CHANNEL_AF_CONFIG_AUTO_ROOM_SIZE = "configAutoRoomSize";
public static final String DEVICE_CHANNEL_AF_SCHEDULES_COUNT = "schedulesCount";
public static final String DEVICE_CHANNEL_AF_NIGHT_LIGHT = "nightLightMode";
public static final String DEVICE_CHANNEL_AF_LIGHT_DETECTION = "lightDetection";
public static final String DEVICE_CHANNEL_AF_LIGHT_DETECTED = "lightDetected";

// Humidity related channels
public static final String DEVICE_CHANNEL_WATER_LACKS = "waterLacking";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,13 @@ public String reqV1Authorized(final String url, final VeSyncAuthenticatedRequest
private String directReqV1Authorized(final String url, final VeSyncAuthenticatedRequest requestData)
throws AuthenticationException {
try {
Request request = httpClient.POST(url);
Request request = httpClient.newRequest(url).method(requestData.httpMethod);

// No headers for login
request.content(new StringContentProvider(VeSyncConstants.GSON.toJson(requestData)));

logger.debug("POST @ {} with content\r\n{}", url, VeSyncConstants.GSON.toJson(requestData));
logger.debug("{} @ {} with content\r\n{}", requestData.httpMethod, url,
VeSyncConstants.GSON.toJson(requestData));

request.header(HttpHeader.CONTENT_TYPE, "application/json; utf-8");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public interface VeSyncProtocolConstants {
String MODE_AUTO = "auto";
String MODE_MANUAL = "manual";
String MODE_SLEEP = "sleep";
String MODE_PET = "pet";

String MODE_ON = "on";
String MODE_DIM = "dim";
Expand All @@ -49,12 +50,16 @@ public interface VeSyncProtocolConstants {
String DEVICE_SET_NIGHT_LIGHT = "setNightLight";
String DEVICE_GET_PURIFIER_STATUS = "getPurifierStatus";
String DEVICE_LEVEL_TYPE_WIND = "wind";
String DEVICE_SET_LIGHT_DETECTION = "setLightDetectionSwitch";

/**
* Base URL for AUTHENTICATION REQUESTS
*/
String PROTOCOL = "https";
String HOST_ENDPOINT = PROTOCOL + "://smartapi.vesync.com/cloud";
String SERVER_ADDRESS = "smartapi.vesync.com";
String SERVER_ENDPOINT = PROTOCOL + "://" + SERVER_ADDRESS;

String HOST_ENDPOINT = SERVER_ENDPOINT + "/cloud";
String V1_LOGIN_ENDPOINT = HOST_ENDPOINT + "/v1/user/login";
String V1_MANAGED_DEVICES_ENDPOINT = HOST_ENDPOINT + "/v1/deviceManaged/devices";
String V2_BYPASS_ENDPOINT = HOST_ENDPOINT + "/v2/deviceManaged/bypassV2";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.binding.vesync.internal.dto.requests;

import javax.ws.rs.HttpMethod;

import com.google.gson.annotations.SerializedName;

/**
Expand All @@ -21,6 +23,8 @@
*/
public class VeSyncRequest {

public transient String httpMethod;

@SerializedName("timeZone")
public String timeZone = "America/New_York";

Expand All @@ -44,5 +48,6 @@ public class VeSyncRequest {

public VeSyncRequest() {
traceId = String.valueOf(System.currentTimeMillis());
httpMethod = HttpMethod.POST;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,75 @@ public class VesyncManagedDeviceBase {
public static class EmptyPayload {
}

public static class SetLightDetectionPayload extends EmptyPayload {

public SetLightDetectionPayload(final boolean enabled) {
lightDetectionSwitch = enabled ? 1 : 0;
}

@SerializedName("lightDetectionSwitch")
public int lightDetectionSwitch = -1;
}

public static class SetPowerPayload extends EmptyPayload {

public SetPowerPayload(final boolean enabled, final int switchIdx) {
this.powerSwitch = enabled ? 1 : 0;
this.switchIdx = switchIdx;
}

@SerializedName("switchIdx")
public int switchIdx = -1;

@SerializedName("powerSwitch")
public int powerSwitch = -1;
}

public static class SetChildLockPayload extends EmptyPayload {

public SetChildLockPayload(final boolean enabled) {
this.childLockSwitch = enabled ? 1 : 0;
}

@SerializedName("childLockSwitch")
public int childLockSwitch = -1;
}

public static class SetScreenSwitchPayload extends EmptyPayload {

public SetScreenSwitchPayload(final boolean enabled) {
this.screenSwitch = enabled ? 1 : 0;
}

@SerializedName("screenSwitch")
public int screenSwitch = -1;
}

public static class SetManualSpeedLevelPayload extends EmptyPayload {

public SetManualSpeedLevelPayload(final int manualSpeedLevel) {
this.manualSpeedLevel = manualSpeedLevel;
}

@SerializedName("levelIdx")
public int levelIdx = 0;

@SerializedName("levelType")
public String levelType = "wind";

@SerializedName("manualSpeedLevel")
public int manualSpeedLevel = -1;
}

public static class SetWorkModePayload extends EmptyPayload {
public SetWorkModePayload(final String workMode) {
this.workMode = workMode;
}

@SerializedName("workMode")
public String workMode = "";
}

public static class SetSwitchPayload extends EmptyPayload {

public SetSwitchPayload(final boolean enabled, final int id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.vesync.internal.dto.requests;

import javax.ws.rs.HttpMethod;

import com.google.gson.annotations.SerializedName;

/**
* The {@link VeSyncRequestV1Command} is the Java class as a DTO to define the base implementation of a V1 command for
* the Vesync
* API.
*
* @author David Goodyear - Initial contribution
*/
public class VeSyncRequestV1Command extends VeSyncAuthenticatedRequest {

@SerializedName("uuid")
public String uuid = null;

public VeSyncRequestV1Command(final String deviceUuid) {
// Exclude fields that shouldn't be there by setting to null
super.phoneOS = null;
super.phoneBrand = null;
super.method = null;
super.appVersion = null;
super.httpMethod = HttpMethod.PUT;
// Set the required payload parameters
uuid = deviceUuid;
}

public String getUuid() {
return uuid;
}
}
Loading

0 comments on commit 61038d4

Please sign in to comment.