[veSync] Improve recognition and device support (#14354)

* [veSync] Device Identification Updates
* [veSync] Alignment to device setups in pyvesync.
* [veSync] Addition of new device code for C302S

Signed-off-by: David Goodyear <david.goodyear@gmail.com>
This commit is contained in:
dag81 2023-03-27 07:05:09 +01:00 committed by GitHub
parent 749cf585ff
commit 1e0f27d5ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 328 additions and 131 deletions

View File

@ -5,7 +5,7 @@ Its current support is for the Air Purifiers & Humidifer's branded as Levoit whi
### Verified Models ### Verified Models
Air Filtering models supported are Core300S, Core400S. Air Filtering models supported are Core300S, Core400S.
Air Humidifier models supported are Dual 200S, Classic 300S, 600S. Air Humidifier models supported are Dual 200S, Classic 300S, 600S, OasisMist Smart Humidifier
### Awaiting User Verification Models ### Awaiting User Verification Models
@ -93,20 +93,20 @@ Channel names in **bold** are read/write, everything else is read-only
### AirHumidifier Thing ### AirHumidifier Thing
| Channel | Type | Description | Model's Supported | Controllable Values | | Channel | Type | Description | Model's Supported | Controllable Values |
|----------------------------|----------------------|---------------------------------------------------------------|----------------------------|---------------------| |----------------------------|----------------------|---------------------------------------------------------------|---------------------------------------|---------------------|
| **enabled** | Switch | Whether the hardware device is enabled (Switched on) | 200S, Dual200S, 300S, 600S | [ON, OFF] | | **enabled** | Switch | Whether the hardware device is enabled (Switched on) | 200S, Dual200S, 300S, 600S, OasisMist | [ON, OFF] |
| **display** | Switch | Whether the display is enabled (display is shown) | 200S, Dual200S, 300S, 600S | [ON, OFF] | | **display** | Switch | Whether the display is enabled (display is shown) | 200S, Dual200S, 300S, 600S, OasisMist | [ON, OFF] |
| waterLacking | Switch | Indicator whether the unit is lacking water | 200S, Dual200S, 300S, 600S | | | waterLacking | Switch | Indicator whether the unit is lacking water | 200S, Dual200S, 300S, 600S, OasisMist | |
| humidityHigh | Switch | Indicator for high humidity | 200S, Dual200S, 300S, 600S | | | humidityHigh | Switch | Indicator for high humidity | 200S, Dual200S, 300S, 600S, OasisMist | |
| waterTankLifted | Switch | Indicator for whether the water tank is removed | 200S, Dual200S, 300S, 600S | | | waterTankLifted | Switch | Indicator for whether the water tank is removed | 200S, Dual200S, 300S, 600S, OasisMist | |
| **stopAtHumiditySetpoint** | Switch | Whether the unit is set to stop when the set point is reached | 200S, Dual200S, 300S, 600S | [ON, OFF] | | **stopAtHumiditySetpoint** | Switch | Whether the unit is set to stop when the set point is reached | 200S, Dual200S, 300S, 600S, OasisMist | [ON, OFF] |
| humidity | Number:Dimensionless | Indicator for the currently measured humidity % level | 200S, Dual200S, 300S, 600S | | | humidity | Number:Dimensionless | Indicator for the currently measured humidity % level | 200S, Dual200S, 300S, 600S, OasisMist | |
| **mistLevel** | Number:Dimensionless | The current mist level set | 300S | [1...2] | | **mistLevel** | Number:Dimensionless | The current mist level set | 300S | [1...2] |
| **mistLevel** | Number:Dimensionless | The current mist level set | 200S, Dual200S, 600S | [1...3] | | **mistLevel** | Number:Dimensionless | The current mist level set | 200S, Dual200S, 600S, OasisMist | [1...3] |
| **humidifierMode** | String | The current mode of operation | 200S, Dual200S, 300S, 600S | [auto, sleep] | | **humidifierMode** | String | The current mode of operation | 200S, Dual200S, 300S, 600S, OasisMist | [auto, sleep] |
| **nightLightMode** | String | The night light mode | 200S, Dual200S, 300S | [on, dim, off] | | **nightLightMode** | String | The night light mode | 200S, Dual200S, 300S | [on, dim, off] |
| **humiditySetpoint** | Number:Dimensionless | Humidity % set point to reach | 200S, Dual200S, 300S, 600S | [30...80] | | **humiditySetpoint** | Number:Dimensionless | Humidity % set point to reach | 200S, Dual200S, 300S, 600S, OasisMist | [30...80] |
| warmEnabled | Switch | Indicator for warm mist mode | 600S | | | warmEnabled | Switch | Indicator for warm mist mode | 600S, OasisMist | |
## Full Example ## Full Example
@ -115,7 +115,7 @@ Channel names in **bold** are read/write, everything else is read-only
#### Air Purifiers Core 200S/300S/400S Models & Air Humidifier Classic300S/600S Models #### Air Purifiers Core 200S/300S/400S Models & Air Humidifier Classic300S/600S Models
``` ```java
Bridge vesync:bridge:vesyncServers [username="<USERNAME>", password="<PASSWORD>", airPurifierPollInterval=60] { Bridge vesync:bridge:vesyncServers [username="<USERNAME>", password="<PASSWORD>", airPurifierPollInterval=60] {
airPurifier loungeAirFilter [deviceName="<DEVICE NAME FROM APP>"] airPurifier loungeAirFilter [deviceName="<DEVICE NAME FROM APP>"]
airPurifier bedroomAirFilter [deviceName="<DEVICE NAME FROM APP>"] airPurifier bedroomAirFilter [deviceName="<DEVICE NAME FROM APP>"]
@ -127,7 +127,7 @@ Bridge vesync:bridge:vesyncServers [username="<USERNAME>", password="<PASSWORD>"
#### Air Purifier Core 400S / 600S Model #### Air Purifier Core 400S / 600S Model
``` ```java
Switch LoungeAPPower "Lounge Air Purifier Power" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:enabled" } 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 LoungeAPDisplay "Lounge Air Purifier Display" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:display" }
Switch LoungeAPControlsLock "Lounge Air Purifier Controls Locked" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:childLock" } Switch LoungeAPControlsLock "Lounge Air Purifier Controls Locked" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:childLock" }
@ -145,7 +145,7 @@ Number LoungeAPSchedulesCount "Lounge Air Purifier Schedules C
#### 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" } 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 LoungeAPDisplay "Lounge Air Purifier Display" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:display" }
String LoungeAPNightLightMode "Lounge Air Purifier Night Light Mode" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:nightLightMode" } String LoungeAPNightLightMode "Lounge Air Purifier Night Light Mode" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:nightLightMode" }
@ -164,7 +164,7 @@ Number LoungeAPSchedulesCount "Lounge Air Purifier Schedules C
#### Air Humidifier Classic 200S / Dual 200S Model #### Air Humidifier Classic 200S / Dual 200S Model
``` ```java
Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" } Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" }
Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" } Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" }
String LoungeAHMode "Lounge Air Humidifier Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidifierMode" } String LoungeAHMode "Lounge Air Humidifier Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidifierMode" }
@ -179,7 +179,7 @@ Number:Dimensionless LoungeAHMistLevel "Lounge Air Humidifier Mist Level
#### Air Humidifier Classic 300S Model #### Air Humidifier Classic 300S Model
``` ```java
Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" } Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" }
Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" } Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" }
String LoungeAHNightLightMode "Lounge Air Humidifier Night Light Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:nightLightMode } String LoungeAHNightLightMode "Lounge Air Humidifier Night Light Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:nightLightMode }
@ -195,7 +195,22 @@ Number:Dimensionless LoungeAHMistLevel "Lounge Air Humidifier Mist Level
#### Air Humidifier 600S Model #### Air Humidifier 600S Model
```java
Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" }
Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" }
String LoungeAHMode "Lounge Air Humidifier Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidifierMode" }
Switch LoungeAHWaterLacking "Lounge Air Humidifier Water Lacking" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:waterLacking" }
Switch LoungeAHHighHumidity "Lounge Air Humidifier High Humidity" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidityHigh" }
Switch LoungeAHWaterTankRemoved "Lounge Air Humidifier Water Tank Removed" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:waterTankLifted" }
Number:Dimensionless LoungeAHHumidity "Lounge Air Humidifier Measured Humidity [%.0f %unit%]" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidity" }
Switch LoungeAHTargetStop "Lounge Air Humidifier Stop at target" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:stopAtTargetLevel" }
Number:Dimensionless LoungeAHTarget "Lounge Air Humidifier Target Humidity [%.0f %unit%]" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humiditySetpoint" }
Number:Dimensionless LoungeAHMistLevel "Lounge Air Humidifier Mist Level" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:mistLevel" }
``` ```
#### Air Humidifier Oasis Mist Smart Model
```java
Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" } Switch LoungeAHPower "Lounge Air Humidifier Power" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:enabled" }
Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" } Switch LoungeAHDisplay "Lounge Air Humidifier Display" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" }
String LoungeAHMode "Lounge Air Humidifier Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidifierMode" } String LoungeAHMode "Lounge Air Humidifier Mode" { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:humidifierMode" }
@ -212,7 +227,7 @@ Number:Dimensionless LoungeAHMistLevel "Lounge Air Humidifier Mist Level
#### Air Purifier Core 400S / 600S Model #### Air Purifier Core 400S / 600S Model
``` ```perl
Frame { Frame {
Switch item=LoungeAPPower label="Power" Switch item=LoungeAPPower label="Power"
Text item=LoungeAPFilterRemainingUse label="Filter Remaining" Text item=LoungeAPFilterRemainingUse label="Filter Remaining"
@ -228,7 +243,7 @@ Frame {
#### Air Purifier Core 200S/300S Model #### Air Purifier Core 200S/300S Model
``` ```perl
Frame { Frame {
Switch item=LoungeAPPower label="Power" Switch item=LoungeAPPower label="Power"
Text item=LoungeAPFilterRemainingUse label="Filter Remaining" Text item=LoungeAPFilterRemainingUse label="Filter Remaining"
@ -245,7 +260,7 @@ Frame {
#### Air Humidifier Classic 200S / Dual 200S Model #### Air Humidifier Classic 200S / Dual 200S Model
``` ```perl
Frame { Frame {
Switch item=LoungeAHPower Switch item=LoungeAHPower
Switch item=LoungeAHDisplay Switch item=LoungeAHDisplay
@ -262,7 +277,7 @@ Frame {
#### Air Humidifier Classic 300S Model #### Air Humidifier Classic 300S Model
``` ```perl
Frame { Frame {
Switch item=LoungeAHPower Switch item=LoungeAHPower
Switch item=LoungeAHDisplay Switch item=LoungeAHDisplay
@ -280,7 +295,24 @@ Frame {
#### Air Humidifier 600S Model #### Air Humidifier 600S Model
```perl
Frame {
Switch item=LoungeAHPower
Switch item=LoungeAHDisplay
Switch item=LoungeAHMode label="Mode" mappings=[auto="Auto", sleep="Sleeping"] icon="settings"
Text icon="none" item=LoungeAHWaterLacking
Text icon="none" item=LoungeAHHighHumidity
Text icon="none" item=LoungeAHWaterTankRemoved
Text icon="none" item=LoungeAHHumidity
Switch item=LoungeAHTargetStop
Slider item=LoungeAHTarget minValue=30 maxValue=80
Slider item=LoungeAHMistLevel minValue=1 maxValue=3
}
``` ```
#### Air Humidifier Oasis Mist Smart Model
```perl
Frame { Frame {
Switch item=LoungeAHPower Switch item=LoungeAHPower
Switch item=LoungeAHDisplay Switch item=LoungeAHDisplay

View File

@ -83,6 +83,7 @@ public class VeSyncConstants {
public static final String DEVICE_PROP_DEVICE_NAME = "Device Name"; public static final String DEVICE_PROP_DEVICE_NAME = "Device Name";
public static final String DEVICE_PROP_DEVICE_TYPE = "Device Type"; public static final String DEVICE_PROP_DEVICE_TYPE = "Device Type";
public static final String DEVICE_PROP_DEVICE_MAC_ID = "MAC Id"; public static final String DEVICE_PROP_DEVICE_MAC_ID = "MAC Id";
public static final String DEVICE_PROP_DEVICE_FAMILY = "Device Family";
public static final String DEVICE_PROP_DEVICE_UUID = "UUID"; public static final String DEVICE_PROP_DEVICE_UUID = "UUID";
// Property name for config constants // Property name for config constants

View File

@ -21,7 +21,10 @@ import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.vesync.internal.handlers.VeSyncBaseDeviceHandler;
import org.openhab.binding.vesync.internal.handlers.VeSyncBridgeHandler; import org.openhab.binding.vesync.internal.handlers.VeSyncBridgeHandler;
import org.openhab.binding.vesync.internal.handlers.VeSyncDeviceAirHumidifierHandler;
import org.openhab.binding.vesync.internal.handlers.VeSyncDeviceAirPurifierHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService; import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.config.discovery.DiscoveryService;
@ -117,6 +120,10 @@ public class VeSyncDiscoveryService extends AbstractDiscoveryService
final String deviceUUID = apMeta.getUuid(); final String deviceUUID = apMeta.getUuid();
properties.put(DEVICE_PROP_DEVICE_NAME, apMeta.getDeviceName()); properties.put(DEVICE_PROP_DEVICE_NAME, apMeta.getDeviceName());
properties.put(DEVICE_PROP_DEVICE_TYPE, apMeta.getDeviceType()); properties.put(DEVICE_PROP_DEVICE_TYPE, apMeta.getDeviceType());
properties.put(DEVICE_PROP_DEVICE_FAMILY,
VeSyncBaseDeviceHandler.getDeviceFamilyMetadata(apMeta.getDeviceType(),
VeSyncDeviceAirHumidifierHandler.DEV_TYPE_FAMILY_AIR_HUMIDIFIER,
VeSyncDeviceAirHumidifierHandler.SUPPORTED_MODEL_FAMILIES));
properties.put(DEVICE_PROP_DEVICE_MAC_ID, apMeta.getMacId()); properties.put(DEVICE_PROP_DEVICE_MAC_ID, apMeta.getMacId());
properties.put(DEVICE_PROP_DEVICE_UUID, deviceUUID); properties.put(DEVICE_PROP_DEVICE_UUID, deviceUUID);
properties.put(DEVICE_PROP_CONFIG_DEVICE_MAC, apMeta.getMacId()); properties.put(DEVICE_PROP_CONFIG_DEVICE_MAC, apMeta.getMacId());
@ -131,6 +138,10 @@ public class VeSyncDiscoveryService extends AbstractDiscoveryService
final String deviceUUID = apMeta.getUuid(); final String deviceUUID = apMeta.getUuid();
properties.put(DEVICE_PROP_DEVICE_NAME, apMeta.getDeviceName()); properties.put(DEVICE_PROP_DEVICE_NAME, apMeta.getDeviceName());
properties.put(DEVICE_PROP_DEVICE_TYPE, apMeta.getDeviceType()); properties.put(DEVICE_PROP_DEVICE_TYPE, apMeta.getDeviceType());
properties.put(DEVICE_PROP_DEVICE_FAMILY,
VeSyncBaseDeviceHandler.getDeviceFamilyMetadata(apMeta.getDeviceType(),
VeSyncDeviceAirPurifierHandler.DEV_TYPE_FAMILY_AIR_PURIFIER,
VeSyncDeviceAirPurifierHandler.SUPPORTED_MODEL_FAMILIES));
properties.put(DEVICE_PROP_DEVICE_MAC_ID, apMeta.getMacId()); properties.put(DEVICE_PROP_DEVICE_MAC_ID, apMeta.getMacId());
properties.put(DEVICE_PROP_DEVICE_UUID, deviceUUID); properties.put(DEVICE_PROP_DEVICE_UUID, deviceUUID);
properties.put(DEVICE_PROP_CONFIG_DEVICE_MAC, apMeta.getMacId()); properties.put(DEVICE_PROP_CONFIG_DEVICE_MAC, apMeta.getMacId());

View File

@ -17,11 +17,13 @@ import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolCon
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ -57,6 +59,11 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault @NonNullByDefault
public abstract class VeSyncBaseDeviceHandler extends BaseThingHandler { public abstract class VeSyncBaseDeviceHandler extends BaseThingHandler {
public static final String DEV_FAMILY_UNKNOWN = "UNKNOWN";
public static final VeSyncDeviceMetadata UNKNOWN = new VeSyncDeviceMetadata(DEV_FAMILY_UNKNOWN,
Collections.emptyList(), Collections.emptyList());
private final Logger logger = LoggerFactory.getLogger(VeSyncBaseDeviceHandler.class); private final Logger logger = LoggerFactory.getLogger(VeSyncBaseDeviceHandler.class);
private static final String MARKER_INVALID_DEVICE_KEY = "---INVALID---"; private static final String MARKER_INVALID_DEVICE_KEY = "---INVALID---";
@ -228,6 +235,8 @@ public abstract class VeSyncBaseDeviceHandler extends BaseThingHandler {
newProps.put(DEVICE_PROP_DEVICE_MAC_ID, metadata.getMacId()); newProps.put(DEVICE_PROP_DEVICE_MAC_ID, metadata.getMacId());
newProps.put(DEVICE_PROP_DEVICE_NAME, metadata.getDeviceName()); newProps.put(DEVICE_PROP_DEVICE_NAME, metadata.getDeviceName());
newProps.put(DEVICE_PROP_DEVICE_TYPE, metadata.getDeviceType()); newProps.put(DEVICE_PROP_DEVICE_TYPE, metadata.getDeviceType());
newProps.put(DEVICE_PROP_DEVICE_FAMILY,
getDeviceFamilyMetadata(metadata.getDeviceType()).getDeviceFamilyName());
newProps.put(DEVICE_PROP_DEVICE_UUID, metadata.getUuid()); newProps.put(DEVICE_PROP_DEVICE_UUID, metadata.getUuid());
return newProps; return newProps;
} }
@ -497,12 +506,50 @@ public abstract class VeSyncBaseDeviceHandler extends BaseThingHandler {
public void updateBridgeBasedPolls(VeSyncBridgeConfiguration config) { public void updateBridgeBasedPolls(VeSyncBridgeConfiguration config) {
} }
/** protected boolean isDeviceSupported() {
* Subclasses should implement this method, and return true if the device is a model it can support final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
* interoperability with. If it cannot be determind to be a mode return !getDeviceFamilyMetadata(deviceType).getDeviceFamilyName().equals(DEV_FAMILY_UNKNOWN);
* }
* @return - true if the device is supported, false if the device isn't. E.g. Unknown model id in meta-data would
* return false. /**
*/ * Subclasses should return the protocol prefix for the device type being modelled.
protected abstract boolean isDeviceSupported(); * E.g. LUH = The Humidifier Devices; LAP = The Air Purifiers;
* if irrelevant return a string that will not be used in the protocol e.g. __??__
*
* @return - The device type prefix for the device being modelled. E.g. LAP or LUH
*/
public abstract String getDeviceFamilyProtocolPrefix();
/**
* Subclasses should return list of VeSyncDeviceMetadata definitions that define the
* supported devices by their implementation.
*
* @return - List of VeSyncDeviceMetadata definitions, that defines groups of devices which
* are operationally the same device.
*/
public abstract List<VeSyncDeviceMetadata> getSupportedDeviceMetadata();
public static VeSyncDeviceMetadata getDeviceFamilyMetadata(final @Nullable String deviceType,
final String deviceProtocolPrefix, final List<VeSyncDeviceMetadata> metadata) {
if (deviceType == null) {
return UNKNOWN;
}
final String[] idParts = deviceType.split("-");
if (idParts.length == 3) {
if (!deviceProtocolPrefix.equals(idParts[0])) {
return UNKNOWN;
}
}
List<VeSyncDeviceMetadata> foundMatch = metadata.stream()
.filter(x -> x.deviceTypeIdMatches(deviceType, idParts)).collect(Collectors.toList());
if (foundMatch.size() == 1) {
return foundMatch.get(0);
} else {
return UNKNOWN;
}
}
public VeSyncDeviceMetadata getDeviceFamilyMetadata(final @Nullable String deviceType) {
return getDeviceFamilyMetadata(deviceType, getDeviceFamilyProtocolPrefix(), getSupportedDeviceMetadata());
}
} }

View File

@ -159,13 +159,19 @@ public class VeSyncBridgeHandler extends BaseBridgeHandler implements VeSyncClie
} }
public java.util.stream.Stream<@NotNull VeSyncManagedDeviceBase> getAirPurifiersMetadata() { public java.util.stream.Stream<@NotNull VeSyncManagedDeviceBase> getAirPurifiersMetadata() {
return api.getMacLookupMap().values().stream() return api.getMacLookupMap().values().stream().filter(x -> !VeSyncBaseDeviceHandler
.filter(x -> VeSyncDeviceAirPurifierHandler.SUPPORTED_DEVICE_TYPES.contains(x.deviceType)); .getDeviceFamilyMetadata(x.getDeviceType(), VeSyncDeviceAirPurifierHandler.DEV_TYPE_FAMILY_AIR_PURIFIER,
VeSyncDeviceAirPurifierHandler.SUPPORTED_MODEL_FAMILIES)
.equals(VeSyncBaseDeviceHandler.UNKNOWN));
} }
public java.util.stream.Stream<@NotNull VeSyncManagedDeviceBase> getAirHumidifiersMetadata() { public java.util.stream.Stream<@NotNull VeSyncManagedDeviceBase> getAirHumidifiersMetadata() {
return api.getMacLookupMap().values().stream() return api.getMacLookupMap().values().stream()
.filter(x -> VeSyncDeviceAirHumidifierHandler.SUPPORTED_DEVICE_TYPES.contains(x.deviceType)); .filter(x -> !VeSyncBaseDeviceHandler
.getDeviceFamilyMetadata(x.getDeviceType(),
VeSyncDeviceAirHumidifierHandler.DEV_TYPE_FAMILY_AIR_HUMIDIFIER,
VeSyncDeviceAirHumidifierHandler.SUPPORTED_MODEL_FAMILIES)
.equals(VeSyncBaseDeviceHandler.UNKNOWN));
} }
protected void updateThings() { protected void updateThings() {

View File

@ -16,6 +16,7 @@ import static org.openhab.binding.vesync.internal.VeSyncConstants.*;
import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolConstants.*; import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolConstants.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -48,21 +49,37 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault @NonNullByDefault
public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler { public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
public static final String DEV_TYPE_FAMILY_AIR_HUMIDIFIER = "LUH";
public static final int DEFAULT_AIR_PURIFIER_POLL_RATE = 120; public static final int DEFAULT_AIR_PURIFIER_POLL_RATE = 120;
// "Device Type" values
public static final String DEV_TYPE_DUAL_200S = "Dual200S"; public static final String DEV_FAMILY_CLASSIC_200S = "Classic 200S";
public static final String DEV_TYPE_CLASSIC_200S = "Classic200S"; public static final String DEV_FAMILY_CLASSIC_300S = "Classic 300S";
public static final String DEV_TYPE_CORE_301S = "LUH-D301S-WEU"; public static final String DEV_FAMILY_DUAL_200S = "Dual 200S";
public static final String DEV_TYPE_CLASSIC_300S = "Classic300S"; public static final String DEV_FAMILY_600S = "600S";
public static final String DEV_TYPE_600S = "LUH-A602S-WUS"; public static final String DEV_FAMILY_OASIS_MIST = "Oasis Mist";
public static final String DEV_TYPE_600S_EU = "LUH-A602S-WEU";
public static final VeSyncDeviceMetadata CLASSIC200S = new VeSyncDeviceMetadata(DEV_FAMILY_CLASSIC_200S,
Collections.emptyList(), List.of("Classic200S"));
public static final VeSyncDeviceMetadata CLASSIC300S = new VeSyncDeviceMetadata(DEV_FAMILY_CLASSIC_300S,
Arrays.asList("A601S"), List.of("Classic300S"));
public static final VeSyncDeviceMetadata DUAL200S = new VeSyncDeviceMetadata(DEV_FAMILY_DUAL_200S,
Arrays.asList("D301S"), List.of("Dual200S"));
public static final VeSyncDeviceMetadata LV600S = new VeSyncDeviceMetadata(DEV_FAMILY_600S, Arrays.asList("A602S"),
Collections.emptyList());
public static final VeSyncDeviceMetadata OASIS_MIST = new VeSyncDeviceMetadata(DEV_FAMILY_OASIS_MIST,
Arrays.asList("O451S"), Collections.emptyList());
public static final List<VeSyncDeviceMetadata> SUPPORTED_MODEL_FAMILIES = Arrays.asList(LV600S, CLASSIC300S,
CLASSIC200S, DUAL200S, OASIS_MIST);
private static final List<String> CLASSIC_300S_600S_MODES = Arrays.asList(MODE_AUTO, MODE_MANUAL, MODE_SLEEP); private static final List<String> CLASSIC_300S_600S_MODES = Arrays.asList(MODE_AUTO, MODE_MANUAL, MODE_SLEEP);
private static final List<String> CLASSIC_300S_NIGHT_LIGHT_MODES = Arrays.asList(MODE_ON, MODE_DIM, MODE_OFF); private static final List<String> CLASSIC_300S_NIGHT_LIGHT_MODES = Arrays.asList(MODE_ON, MODE_DIM, MODE_OFF);
public static final List<String> SUPPORTED_DEVICE_TYPES = List.of(DEV_TYPE_DUAL_200S, DEV_TYPE_CLASSIC_200S,
DEV_TYPE_CLASSIC_300S, DEV_TYPE_CORE_301S, DEV_TYPE_600S, DEV_TYPE_600S_EU);
private final Logger logger = LoggerFactory.getLogger(VeSyncDeviceAirHumidifierHandler.class); private final Logger logger = LoggerFactory.getLogger(VeSyncDeviceAirHumidifierHandler.class);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_AIR_HUMIDIFIER); public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_AIR_HUMIDIFIER);
@ -76,20 +93,18 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
@Override @Override
protected String[] getChannelsToRemove() { protected String[] getChannelsToRemove() {
String[] toRemove = new String[] {}; String[] toRemove = new String[] {};
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
if (deviceType != null) { if (deviceFamily != null) {
switch (deviceType) { switch (deviceFamily) {
case DEV_TYPE_CLASSIC_300S: case DEV_FAMILY_CLASSIC_300S:
toRemove = new String[] { DEVICE_CHANNEL_WARM_ENABLED, DEVICE_CHANNEL_WARM_LEVEL }; toRemove = new String[] { DEVICE_CHANNEL_WARM_ENABLED, DEVICE_CHANNEL_WARM_LEVEL };
break; break;
case DEV_TYPE_DUAL_200S: case DEV_FAMILY_DUAL_200S:
case DEV_TYPE_CLASSIC_200S: case DEV_FAMILY_CLASSIC_200S:
case DEV_TYPE_CORE_301S:
toRemove = new String[] { DEVICE_CHANNEL_WARM_ENABLED, DEVICE_CHANNEL_WARM_LEVEL, toRemove = new String[] { DEVICE_CHANNEL_WARM_ENABLED, DEVICE_CHANNEL_WARM_LEVEL,
DEVICE_CHANNEL_AF_NIGHT_LIGHT }; DEVICE_CHANNEL_AF_NIGHT_LIGHT };
break; break;
case DEV_TYPE_600S: case DEV_FAMILY_OASIS_MIST:
case DEV_TYPE_600S_EU:
toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT }; toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT };
break; break;
} }
@ -122,18 +137,19 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
} }
@Override @Override
protected boolean isDeviceSupported() { public String getDeviceFamilyProtocolPrefix() {
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); return DEV_TYPE_FAMILY_AIR_HUMIDIFIER;
if (deviceType == null) {
return false;
} }
return SUPPORTED_DEVICE_TYPES.contains(deviceType);
@Override
public List<VeSyncDeviceMetadata> getSupportedDeviceMetadata() {
return SUPPORTED_MODEL_FAMILIES;
} }
@Override @Override
public void handleCommand(final ChannelUID channelUID, final Command command) { public void handleCommand(final ChannelUID channelUID, final Command command) {
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
if (deviceType == null) { if (deviceFamily == null) {
return; return;
} }
@ -180,7 +196,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
int targetMistLevel = ((QuantityType<?>) command).intValue(); int targetMistLevel = ((QuantityType<?>) command).intValue();
// If more devices have this the hope is it's those with the prefix LUH so the check can // If more devices have this the hope is it's those with the prefix LUH so the check can
// be simplified, originally devices mapped 1/5/9 to 1/2/3. // be simplified, originally devices mapped 1/5/9 to 1/2/3.
if (DEV_TYPE_CORE_301S.equals(deviceType)) { if (DEV_FAMILY_DUAL_200S.equals(deviceFamily)) {
if (targetMistLevel < 1) { if (targetMistLevel < 1) {
logger.warn("Target Mist Level less than 1 - adjusting to 1 as the valid API value"); logger.warn("Target Mist Level less than 1 - adjusting to 1 as the valid API value");
targetMistLevel = 1; targetMistLevel = 1;
@ -235,8 +251,8 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
new VeSyncRequestManagedDeviceBypassV2.SetMode(targetMode)); new VeSyncRequestManagedDeviceBypassV2.SetMode(targetMode));
break; break;
case DEVICE_CHANNEL_AF_NIGHT_LIGHT: case DEVICE_CHANNEL_AF_NIGHT_LIGHT:
if (!DEV_TYPE_CLASSIC_300S.equals(deviceType) && !DEV_TYPE_CORE_301S.equals(deviceType)) { if (!DEV_FAMILY_CLASSIC_300S.equals(deviceFamily) && !DEV_FAMILY_600S.equals(deviceFamily)) {
logger.warn("Humidifier night light is not valid for your device ({}})", deviceType); logger.warn("Humidifier night light is not valid for your device ({}})", deviceFamily);
return; return;
} }
if (!CLASSIC_300S_NIGHT_LIGHT_MODES.contains(targetMode)) { if (!CLASSIC_300S_NIGHT_LIGHT_MODES.contains(targetMode)) {
@ -314,7 +330,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
return; return;
} }
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
updateState(DEVICE_CHANNEL_ENABLED, OnOffType.from(humidifierStatus.result.result.enabled)); updateState(DEVICE_CHANNEL_ENABLED, OnOffType.from(humidifierStatus.result.result.enabled));
updateState(DEVICE_CHANNEL_DISPLAY_ENABLED, OnOffType.from(humidifierStatus.result.result.display)); updateState(DEVICE_CHANNEL_DISPLAY_ENABLED, OnOffType.from(humidifierStatus.result.result.display));
@ -329,7 +345,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
updateState(DEVICE_CHANNEL_HUMIDIFIER_MODE, new StringType(humidifierStatus.result.result.mode)); updateState(DEVICE_CHANNEL_HUMIDIFIER_MODE, new StringType(humidifierStatus.result.result.mode));
// Only the 300S supports nightlight currently of tested devices. // Only the 300S supports nightlight currently of tested devices.
if (DEV_TYPE_CLASSIC_300S.equals(deviceType) || DEV_TYPE_CORE_301S.equals(deviceType)) { if (DEV_FAMILY_CLASSIC_300S.equals(deviceFamily) || DEV_FAMILY_600S.equals(deviceFamily)) {
// Map the numeric that only applies to the same modes as the Air Filter 300S series. // Map the numeric that only applies to the same modes as the Air Filter 300S series.
if (humidifierStatus.result.result.nightLightBrightness == 0) { if (humidifierStatus.result.result.nightLightBrightness == 0) {
updateState(DEVICE_CHANNEL_AF_NIGHT_LIGHT, new StringType(MODE_OFF)); updateState(DEVICE_CHANNEL_AF_NIGHT_LIGHT, new StringType(MODE_OFF));
@ -338,7 +354,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
} else { } else {
updateState(DEVICE_CHANNEL_AF_NIGHT_LIGHT, new StringType(MODE_DIM)); updateState(DEVICE_CHANNEL_AF_NIGHT_LIGHT, new StringType(MODE_DIM));
} }
} else if (DEV_TYPE_600S.equals(deviceType) || DEV_TYPE_600S_EU.equals(deviceType)) { } else if (DEV_FAMILY_600S.equals(deviceFamily) || DEV_FAMILY_OASIS_MIST.equals(deviceFamily)) {
updateState(DEVICE_CHANNEL_WARM_ENABLED, OnOffType.from(humidifierStatus.result.result.warnEnabled)); updateState(DEVICE_CHANNEL_WARM_ENABLED, OnOffType.from(humidifierStatus.result.result.warnEnabled));
updateState(DEVICE_CHANNEL_WARM_LEVEL, new DecimalType(humidifierStatus.result.result.warmLevel)); updateState(DEVICE_CHANNEL_WARM_LEVEL, new DecimalType(humidifierStatus.result.result.warmLevel));
} }

View File

@ -18,6 +18,7 @@ import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolCon
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -56,16 +57,34 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault @NonNullByDefault
public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler { public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
public static final String DEV_TYPE_FAMILY_AIR_PURIFIER = "LAP";
public static final int DEFAULT_AIR_PURIFIER_POLL_RATE = 120; public static final int DEFAULT_AIR_PURIFIER_POLL_RATE = 120;
// "Device Type" values
public static final String DEV_TYPE_CORE_600S = "LAP-C601S-WUS"; public static final String DEV_FAMILY_CORE_200S = "200S";
public static final String DEV_TYPE_CORE_400S = "Core400S"; public static final String DEV_FAMILY_CORE_300S = "300S";
public static final String DEV_TYPE_CORE_300S = "Core300S"; public static final String DEV_FAMILY_CORE_400S = "400S";
public static final String DEV_TYPE_CORE_201S = "LAP-C201S-AUSR"; public static final String DEV_FAMILY_CORE_600S = "600S";
public static final String DEV_TYPE_CORE_200S = "Core200S";
public static final String DEV_TYPE_LV_PUR131S = "LV-PUR131S"; public static final String DEV_FAMILY_PUR_131S = "131S";
public static final List<String> SUPPORTED_DEVICE_TYPES = Arrays.asList(DEV_TYPE_CORE_600S, DEV_TYPE_CORE_400S,
DEV_TYPE_CORE_300S, DEV_TYPE_CORE_201S, DEV_TYPE_CORE_200S, DEV_TYPE_LV_PUR131S); public static final VeSyncDeviceMetadata CORE200S = new VeSyncDeviceMetadata(DEV_FAMILY_CORE_200S,
Arrays.asList("C201S", "C202S"), List.of("Core200S"));
public static final VeSyncDeviceMetadata CORE300S = new VeSyncDeviceMetadata(DEV_FAMILY_CORE_300S,
List.of("C301S", "C302S"), List.of("Core300S"));
public static final VeSyncDeviceMetadata CORE400S = new VeSyncDeviceMetadata(DEV_FAMILY_CORE_400S, List.of("C401S"),
List.of("Core400S"));
public static final VeSyncDeviceMetadata CORE600S = new VeSyncDeviceMetadata(DEV_FAMILY_CORE_600S, List.of("C601S"),
List.of("Core600S"));
public static final VeSyncDeviceMetadata PUR131S = new VeSyncDeviceMetadata(DEV_FAMILY_PUR_131S,
Collections.emptyList(), Arrays.asList("LV-PUR131S", "LV-RH131S"));
public static final List<VeSyncDeviceMetadata> SUPPORTED_MODEL_FAMILIES = Arrays.asList(CORE600S, CORE400S,
CORE300S, CORE200S, PUR131S);
private static final List<String> CORE_400S600S_FAN_MODES = Arrays.asList(MODE_AUTO, MODE_MANUAL, MODE_SLEEP); private static final List<String> CORE_400S600S_FAN_MODES = Arrays.asList(MODE_AUTO, MODE_MANUAL, MODE_SLEEP);
private static final List<String> CORE_200S300S_FAN_MODES = Arrays.asList(MODE_MANUAL, MODE_SLEEP); private static final List<String> CORE_200S300S_FAN_MODES = Arrays.asList(MODE_MANUAL, MODE_SLEEP);
@ -89,15 +108,15 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
@Override @Override
protected @NotNull String[] getChannelsToRemove() { protected @NotNull String[] getChannelsToRemove() {
final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
String[] toRemove = new String[] {}; String[] toRemove = new String[] {};
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); if (deviceFamily != null) {
if (deviceType != null) { switch (deviceFamily) {
switch (deviceType) { case DEV_FAMILY_CORE_600S:
case DEV_TYPE_CORE_600S: case DEV_FAMILY_CORE_400S:
case DEV_TYPE_CORE_400S:
toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT }; toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT };
break; break;
case DEV_TYPE_LV_PUR131S: case DEV_FAMILY_PUR_131S:
toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT, DEVICE_CHANNEL_AF_CONFIG_AUTO_ROOM_SIZE, toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT, DEVICE_CHANNEL_AF_CONFIG_AUTO_ROOM_SIZE,
DEVICE_CHANNEL_AF_CONFIG_AUTO_MODE_PREF, DEVICE_CHANNEL_AF_AUTO_OFF_CALC_TIME, DEVICE_CHANNEL_AF_CONFIG_AUTO_MODE_PREF, DEVICE_CHANNEL_AF_AUTO_OFF_CALC_TIME,
DEVICE_CHANNEL_AIR_FILTER_LIFE_PERCENTAGE_REMAINING, DEVICE_CHANNEL_AIRQUALITY_PM25, DEVICE_CHANNEL_AIR_FILTER_LIFE_PERCENTAGE_REMAINING, DEVICE_CHANNEL_AIRQUALITY_PM25,
@ -130,18 +149,19 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
} }
@Override @Override
protected boolean isDeviceSupported() { public String getDeviceFamilyProtocolPrefix() {
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); return DEV_TYPE_FAMILY_AIR_PURIFIER;
if (deviceType == null) {
return false;
} }
return SUPPORTED_DEVICE_TYPES.contains(deviceType);
@Override
public List<VeSyncDeviceMetadata> getSupportedDeviceMetadata() {
return SUPPORTED_MODEL_FAMILIES;
} }
@Override @Override
public void handleCommand(final ChannelUID channelUID, final Command command) { public void handleCommand(final ChannelUID channelUID, final Command command) {
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
if (deviceType == null) { if (deviceFamily == null) {
return; return;
} }
@ -167,9 +187,9 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
switch (channelUID.getId()) { switch (channelUID.getId()) {
case DEVICE_CHANNEL_FAN_MODE_ENABLED: case DEVICE_CHANNEL_FAN_MODE_ENABLED:
final String targetFanMode = command.toString().toLowerCase(); final String targetFanMode = command.toString().toLowerCase();
switch (deviceType) { switch (deviceFamily) {
case DEV_TYPE_CORE_600S: case DEV_FAMILY_CORE_600S:
case DEV_TYPE_CORE_400S: case DEV_FAMILY_CORE_400S:
if (!CORE_400S600S_FAN_MODES.contains(targetFanMode)) { if (!CORE_400S600S_FAN_MODES.contains(targetFanMode)) {
logger.warn( logger.warn(
"Fan mode command for \"{}\" is not valid in the (Core400S) API possible options {}", "Fan mode command for \"{}\" is not valid in the (Core400S) API possible options {}",
@ -177,9 +197,8 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
return; return;
} }
break; break;
case DEV_TYPE_CORE_200S: case DEV_FAMILY_CORE_200S:
case DEV_TYPE_CORE_201S: case DEV_FAMILY_CORE_300S:
case DEV_TYPE_CORE_300S:
if (!CORE_200S300S_FAN_MODES.contains(targetFanMode)) { if (!CORE_200S300S_FAN_MODES.contains(targetFanMode)) {
logger.warn( logger.warn(
"Fan mode command for \"{}\" is not valid in the (Core200S/Core300S) API possible options {}", "Fan mode command for \"{}\" is not valid in the (Core200S/Core300S) API possible options {}",
@ -194,14 +213,13 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
break; break;
case DEVICE_CHANNEL_AF_NIGHT_LIGHT: case DEVICE_CHANNEL_AF_NIGHT_LIGHT:
final String targetNightLightMode = command.toString().toLowerCase(); final String targetNightLightMode = command.toString().toLowerCase();
switch (deviceType) { switch (deviceFamily) {
case DEV_TYPE_CORE_600S: case DEV_FAMILY_CORE_600S:
case DEV_TYPE_CORE_400S: case DEV_FAMILY_CORE_400S:
logger.warn("Core400S API does not support night light"); logger.warn("Core400S API does not support night light");
return; return;
case DEV_TYPE_CORE_200S: case DEV_FAMILY_CORE_200S:
case DEV_TYPE_CORE_201S: case DEV_FAMILY_CORE_300S:
case DEV_TYPE_CORE_300S:
if (!CORE_200S300S_NIGHT_LIGHT_MODES.contains(targetNightLightMode)) { if (!CORE_200S300S_NIGHT_LIGHT_MODES.contains(targetNightLightMode)) {
logger.warn( logger.warn(
"Night light mode command for \"{}\" is not valid in the (Core200S/Core300S) API possible options {}", "Night light mode command for \"{}\" is not valid in the (Core200S/Core300S) API possible options {}",
@ -229,18 +247,17 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
requestedLevel = 1; requestedLevel = 1;
} }
switch (deviceType) { switch (deviceFamily) {
case DEV_TYPE_CORE_600S: case DEV_FAMILY_CORE_600S:
case DEV_TYPE_CORE_400S: case DEV_FAMILY_CORE_400S:
if (requestedLevel > 4) { if (requestedLevel > 4) {
logger.warn( logger.warn(
"Fan speed command greater than 4 - adjusting to 4 as the valid (Core400S) API value"); "Fan speed command greater than 4 - adjusting to 4 as the valid (Core400S) API value");
requestedLevel = 4; requestedLevel = 4;
} }
break; break;
case DEV_TYPE_CORE_200S: case DEV_FAMILY_CORE_200S:
case DEV_TYPE_CORE_201S: case DEV_FAMILY_CORE_300S:
case DEV_TYPE_CORE_300S:
if (requestedLevel > 3) { if (requestedLevel > 3) {
logger.warn( logger.warn(
"Fan speed command greater than 3 - adjusting to 3 as the valid (Core200S/Core300S) API value"); "Fan speed command greater than 3 - adjusting to 3 as the valid (Core200S/Core300S) API value");
@ -264,20 +281,19 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
@Override @Override
protected void pollForDeviceData(final ExpiringCache<String> cachedResponse) { protected void pollForDeviceData(final ExpiringCache<String> cachedResponse) {
final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE); final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
if (deviceType == null) { if (deviceFamily == null) {
return; return;
} }
switch (deviceType) { switch (deviceFamily) {
case DEV_TYPE_CORE_600S: case DEV_FAMILY_CORE_600S:
case DEV_TYPE_CORE_400S: case DEV_FAMILY_CORE_400S:
case DEV_TYPE_CORE_300S: case DEV_FAMILY_CORE_300S:
case DEV_TYPE_CORE_201S: case DEV_FAMILY_CORE_200S:
case DEV_TYPE_CORE_200S:
processV2BypassPoll(cachedResponse); processV2BypassPoll(cachedResponse);
break; break;
case DEV_TYPE_LV_PUR131S: case DEV_FAMILY_PUR_131S:
processV1AirPurifierPoll(cachedResponse); processV1AirPurifierPoll(cachedResponse);
break; break;
} }

View File

@ -0,0 +1,66 @@
/**
* 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.handlers;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link VeSyncDeviceMetadata} class contains the definition for the identification of multiple device types,
* to a single family of devices.
*
* New Device Type Ids are formatted as [DeviceType][-][Device Generation][-][Device Region]
*
* @author David Goodyear - Initial contribution
*/
@NonNullByDefault
public class VeSyncDeviceMetadata {
public VeSyncDeviceMetadata(final String deviceFamilyName, final List<String> deviceGenerations,
final List<String> nonStandardIds) {
this.deviceFamilyName = deviceFamilyName;
this.deviceGenerations = deviceGenerations;
this.nonStandardIds = nonStandardIds;
}
/**
* The name of the family the set of ID's represents.
*
*/
final public String deviceFamilyName;
/**
* The version id, that represents the specific model of the device
*/
final public List<String> deviceGenerations;
/**
* Device Types not following the standard 3 segment convention
*/
final public List<String> nonStandardIds;
public boolean deviceTypeIdMatches(final String deviceType, final String[] deviceTypeSegments) {
if (nonStandardIds.contains(deviceType)) {
return true;
}
if (deviceTypeSegments.length == 3) {
return deviceGenerations.contains(deviceTypeSegments[1]);
}
return false;
}
public String getDeviceFamilyName() {
return deviceFamilyName;
}
}

View File

@ -70,6 +70,7 @@
<property name="Device Name"/> <property name="Device Name"/>
<property name="Device Type"/> <property name="Device Type"/>
<property name="MAC Id"/> <property name="MAC Id"/>
<property name="Device Family"/>
</properties> </properties>
<representation-property>macId</representation-property> <representation-property>macId</representation-property>
@ -114,6 +115,7 @@
<property name="Device Name"/> <property name="Device Name"/>
<property name="Device Type"/> <property name="Device Type"/>
<property name="MAC Id"/> <property name="MAC Id"/>
<property name="Device Family"/>
</properties> </properties>
<representation-property>macId</representation-property> <representation-property>macId</representation-property>