]> git.basschouten.com Git - openhab-addons.git/commitdiff
[veSync] Improve recognition and device support (#14354)
authordag81 <dag81@users.noreply.github.com>
Mon, 27 Mar 2023 06:05:09 +0000 (07:05 +0100)
committerGitHub <noreply@github.com>
Mon, 27 Mar 2023 06:05:09 +0000 (08:05 +0200)
* [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>
bundles/org.openhab.binding.vesync/README.md
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/VeSyncConstants.java
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/discovery/VeSyncDiscoveryService.java
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncBaseDeviceHandler.java
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncBridgeHandler.java
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncDeviceAirHumidifierHandler.java
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncDeviceAirPurifierHandler.java
bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncDeviceMetadata.java [new file with mode: 0644]
bundles/org.openhab.binding.vesync/src/main/resources/OH-INF/thing/thing-types.xml

index a1890aecbc3224c2a5f12aad8eaaf9ff9faa1ac2..723512307fa03b23c12a7f5027f70e4f4e4ede7f 100644 (file)
@@ -5,7 +5,7 @@ Its current support is for the Air Purifiers & Humidifer's branded as Levoit whi
 ### Verified Models
 
 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
 
@@ -92,21 +92,21 @@ Channel names in **bold** are read/write, everything else is read-only
 
 ### AirHumidifier Thing
 
-| Channel                    | Type                 | Description                                                   | Model's Supported          | Controllable Values |
-|----------------------------|----------------------|---------------------------------------------------------------|----------------------------|---------------------|
-| **enabled**                | Switch               | Whether the hardware device is enabled (Switched on)          | 200S, Dual200S, 300S, 600S | [ON, OFF]           |
-| **display**                | Switch               | Whether the display is enabled (display is shown)             | 200S, Dual200S, 300S, 600S | [ON, OFF]           |
-| waterLacking               | Switch               | Indicator whether the unit is lacking water                   | 200S, Dual200S, 300S, 600S |                     |
-| humidityHigh               | Switch               | Indicator for high humidity                                   | 200S, Dual200S, 300S, 600S |                     |
-| waterTankLifted            | Switch               | Indicator for whether the water tank is removed               | 200S, Dual200S, 300S, 600S |                     |
-| **stopAtHumiditySetpoint** | Switch               | Whether the unit is set to stop when the set point is reached | 200S, Dual200S, 300S, 600S | [ON, OFF]           |
-| humidity                   | Number:Dimensionless | Indicator for the currently measured humidity % level         | 200S, Dual200S, 300S, 600S |                     |
-| **mistLevel**              | Number:Dimensionless | The current mist level set                                    | 300S                       | [1...2]             |
-| **mistLevel**              | Number:Dimensionless | The current mist level set                                    | 200S, Dual200S, 600S       | [1...3]             |
-| **humidifierMode**         | String               | The current mode of operation                                 | 200S, Dual200S, 300S, 600S | [auto, sleep]       |
-| **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]           |
-| warmEnabled                | Switch               | Indicator for warm mist mode                                  | 600S                       |                     |
+| Channel                    | Type                 | Description                                                   | Model's Supported                     | Controllable Values |
+|----------------------------|----------------------|---------------------------------------------------------------|---------------------------------------|---------------------|
+| **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, OasisMist | [ON, OFF]           |
+| waterLacking               | Switch               | Indicator whether the unit is lacking water                   | 200S, Dual200S, 300S, 600S, OasisMist |                     |
+| 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, OasisMist |                     |
+| **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, OasisMist |                     |
+| **mistLevel**              | Number:Dimensionless | The current mist level set                                    | 300S                                  | [1...2]             |
+| **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, OasisMist | [auto, sleep]       |
+| **nightLightMode**         | String               | The night light mode                                          | 200S, Dual200S, 300S                  | [on, dim, off]      |
+| **humiditySetpoint**       | Number:Dimensionless | Humidity % set point to reach                                 | 200S, Dual200S, 300S, 600S, OasisMist | [30...80]           |
+| warmEnabled                | Switch               | Indicator for warm mist mode                                  | 600S, OasisMist                       |                     |
 
 
 ## 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
 
-```
+```java
 Bridge vesync:bridge:vesyncServers [username="<USERNAME>", password="<PASSWORD>", airPurifierPollInterval=60] {
        airPurifier loungeAirFilter [deviceName="<DEVICE NAME FROM APP>"]
        airPurifier bedroomAirFilter [deviceName="<DEVICE NAME FROM APP>"]
@@ -127,44 +127,44 @@ Bridge vesync:bridge:vesyncServers [username="<USERNAME>", password="<PASSWORD>"
 
 #### Air Purifier Core 400S / 600S Model
 
-```
-Switch               LoungeAPPower                     "Lounge Air Purifier Power"                                 { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:enabled" }
-Switch               LoungeAPDisplay                   "Lounge Air Purifier Display"                               { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:display" }
+```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" }
-Number               LoungeAPErrorCode                "Lounge Air Purifier Error Code"                             { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:errorCode" }
-String               LoungeAPAutoMode                 "Lounge Air Purifier Auto Mode"                              { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoMode" }
-Number               LoungeAPAutoRoomSize             "Lounge Air Purifier Auto Room Size [%.0f% sqft]"            { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoRoomSize" }
-Number:Time          LoungeAPTimerLeft                "Lounge Air Purifier Timer Left [%1$Tp]"                     { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:timerRemain" }  
+Number:Density       LoungeAPAirQuality            "Lounge Air Purifier Air Quality [%.0f% %unit%]"             { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:airQualityPM25" }
+Number               LoungeAPErrorCode             "Lounge Air Purifier Error Code"                             { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:errorCode" }
+String               LoungeAPAutoMode              "Lounge Air Purifier Auto Mode"                              { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoMode" }
+Number               LoungeAPAutoRoomSize          "Lounge Air Purifier Auto Room Size [%.0f% sqft]"            { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoRoomSize" }
+Number:Time          LoungeAPTimerLeft             "Lounge Air Purifier Timer Left [%1$Tp]"                     { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:timerRemain" }     
 DateTime             LoungeAPTimerExpiry           "Lounge Air Purifier Timer Expiry [%1$tA %1$tI:%1$tM %1$Tp]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:timerExpiry" }
 Number               LoungeAPSchedulesCount       "Lounge Air Purifier Schedules Count"                        { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:schedulesCount" }
 ```
 
 #### Air Purifier Core 200S/300S Model
 
-```
-Switch               LoungeAPPower                    "Lounge Air Purifier Power"                                  { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:enabled" }
-Switch               LoungeAPDisplay                  "Lounge Air Purifier Display"                                { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:display" }
+```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" }
 String               LoungeAPNightLightMode        "Lounge Air Purifier Night Light Mode"                       { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:nightLightMode" }
 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%]"                    { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:airQuality" }
-Number               LoungeAPErrorCode                "Lounge Air Purifier Error Code"                             { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:errorCode" }
-String               LoungeAPAutoMode                 "Lounge Air Purifier Auto Mode"                              { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoMode" }
-Number               LoungeAPAutoRoomSize             "Lounge Air Purifier Auto Room Size [%.0f% sqft]"            { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoRoomSize" }
-Number:Time          LoungeAPTimerLeft                "Lounge Air Purifier Timer Left [%1$Tp]"                     { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:timerRemain" }  
+Number:Density       LoungeAPAirQuality            "Lounge Air Purifier Air Quality [%.0f%]"                    { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:airQuality" }
+Number               LoungeAPErrorCode             "Lounge Air Purifier Error Code"                             { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:errorCode" }
+String               LoungeAPAutoMode              "Lounge Air Purifier Auto Mode"                              { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoMode" }
+Number               LoungeAPAutoRoomSize          "Lounge Air Purifier Auto Room Size [%.0f% sqft]"            { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:configAutoRoomSize" }
+Number:Time          LoungeAPTimerLeft             "Lounge Air Purifier Timer Left [%1$Tp]"                     { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:timerRemain" }     
 DateTime             LoungeAPTimerExpiry           "Lounge Air Purifier Timer Expiry [%1$tA %1$tI:%1$tM %1$Tp]" { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:timerExpiry" }
 Number               LoungeAPSchedulesCount       "Lounge Air Purifier Schedules Count"                        { channel="vesync:airPurifier:vesyncServers:loungeAirFilter:schedulesCount" }
 ```
 
 #### Air Humidifier Classic 200S / Dual 200S 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" }
@@ -179,7 +179,7 @@ Number:Dimensionless LoungeAHMistLevel         "Lounge Air Humidifier Mist Level
 
 #### Air Humidifier Classic 300S 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               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
 
+```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               LoungeAHDisplay           "Lounge Air Humidifier Display"                                { channel="vesync:airHumidifier:vesyncServers:loungeHumidifier:display" }
 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
 
-```
+```perl
 Frame {
    Switch item=LoungeAPPower label="Power"
    Text   item=LoungeAPFilterRemainingUse label="Filter Remaining"
@@ -228,7 +243,7 @@ Frame {
 
 #### Air Purifier Core 200S/300S Model
 
-```
+```perl
 Frame {
    Switch item=LoungeAPPower label="Power"
    Text   item=LoungeAPFilterRemainingUse label="Filter Remaining"
@@ -245,7 +260,7 @@ Frame {
 
 #### Air Humidifier Classic 200S / Dual 200S Model
 
-```
+```perl
 Frame {
    Switch item=LoungeAHPower
    Switch item=LoungeAHDisplay
@@ -262,7 +277,7 @@ Frame {
 
 #### Air Humidifier Classic 300S Model
 
-```
+```perl
 Frame {
    Switch item=LoungeAHPower
    Switch item=LoungeAHDisplay
@@ -280,7 +295,24 @@ Frame {
 
 #### 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 {
    Switch item=LoungeAHPower
    Switch item=LoungeAHDisplay
index a4713c1e9097f1f610c7a10ad70b4033d58f0a40..33f5972f77239c33c58346e83bf1f759e006dd13 100644 (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_TYPE = "Device Type";
     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";
 
     // Property name for config constants
index ac9bb1116329f87518c1505831d3f8ad2cfe11e4..ec0e0c92ef85817a2e88f1f16c9abedf9231bd63 100644 (file)
@@ -21,7 +21,10 @@ import java.util.Set;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 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.VeSyncDeviceAirHumidifierHandler;
+import org.openhab.binding.vesync.internal.handlers.VeSyncDeviceAirPurifierHandler;
 import org.openhab.core.config.discovery.AbstractDiscoveryService;
 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
 import org.openhab.core.config.discovery.DiscoveryService;
@@ -117,6 +120,10 @@ public class VeSyncDiscoveryService extends AbstractDiscoveryService
             final String deviceUUID = apMeta.getUuid();
             properties.put(DEVICE_PROP_DEVICE_NAME, apMeta.getDeviceName());
             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_UUID, deviceUUID);
             properties.put(DEVICE_PROP_CONFIG_DEVICE_MAC, apMeta.getMacId());
@@ -131,6 +138,10 @@ public class VeSyncDiscoveryService extends AbstractDiscoveryService
             final String deviceUUID = apMeta.getUuid();
             properties.put(DEVICE_PROP_DEVICE_NAME, apMeta.getDeviceName());
             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_UUID, deviceUUID);
             properties.put(DEVICE_PROP_CONFIG_DEVICE_MAC, apMeta.getMacId());
index fb472882d6de0ce4da669590a0bf55b7eee5e96c..260a7df8588968ec485d4d1535ad488c65238650 100644 (file)
@@ -17,11 +17,13 @@ import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolCon
 
 import java.time.Duration;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import javax.validation.constraints.NotNull;
 
@@ -57,6 +59,11 @@ import org.slf4j.LoggerFactory;
 @NonNullByDefault
 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 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_NAME, metadata.getDeviceName());
         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());
         return newProps;
     }
@@ -436,7 +445,7 @@ public abstract class VeSyncBaseDeviceHandler extends BaseThingHandler {
 
     /**
      * Send a BypassV2 command to the device. The body of the response is returned.
-     * 
+     *
      * @param method - the V2 bypass method
      * @param payload - The payload to send in within the V2 bypass command
      * @return - The body of the response, or EMPTY_STRING if the command could not be issued.
@@ -497,12 +506,50 @@ public abstract class VeSyncBaseDeviceHandler extends BaseThingHandler {
     public void updateBridgeBasedPolls(VeSyncBridgeConfiguration config) {
     }
 
+    protected boolean isDeviceSupported() {
+        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
+        return !getDeviceFamilyMetadata(deviceType).getDeviceFamilyName().equals(DEV_FAMILY_UNKNOWN);
+    }
+
+    /**
+     * Subclasses should return the protocol prefix for the device type being modelled.
+     * 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 implement this method, and return true if the device is a model it can support
-     * interoperability with. If it cannot be determind to be a mode
+     * Subclasses should return list of VeSyncDeviceMetadata definitions that define the
+     * supported devices by their implementation.
      *
-     * @return - true if the device is supported, false if the device isn't. E.g. Unknown model id in meta-data would
-     *         return false.
+     * @return - List of VeSyncDeviceMetadata definitions, that defines groups of devices which
+     *         are operationally the same device.
      */
-    protected abstract boolean isDeviceSupported();
+    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());
+    }
 }
index ec29e183b5d6cb9105758d784312ff11d6641535..bc12f8c2f058308f551c0302bfbfb7a28ba06983 100644 (file)
@@ -159,13 +159,19 @@ public class VeSyncBridgeHandler extends BaseBridgeHandler implements VeSyncClie
     }
 
     public java.util.stream.Stream<@NotNull VeSyncManagedDeviceBase> getAirPurifiersMetadata() {
-        return api.getMacLookupMap().values().stream()
-                .filter(x -> VeSyncDeviceAirPurifierHandler.SUPPORTED_DEVICE_TYPES.contains(x.deviceType));
+        return api.getMacLookupMap().values().stream().filter(x -> !VeSyncBaseDeviceHandler
+                .getDeviceFamilyMetadata(x.getDeviceType(), VeSyncDeviceAirPurifierHandler.DEV_TYPE_FAMILY_AIR_PURIFIER,
+                        VeSyncDeviceAirPurifierHandler.SUPPORTED_MODEL_FAMILIES)
+                .equals(VeSyncBaseDeviceHandler.UNKNOWN));
     }
 
     public java.util.stream.Stream<@NotNull VeSyncManagedDeviceBase> getAirHumidifiersMetadata() {
         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() {
index ccb57f94615201a0a894e8a5a3a9cb21c888264a..d3b2464c07923227d6f34e4d9fb39d029a6090ff 100644 (file)
@@ -16,6 +16,7 @@ import static org.openhab.binding.vesync.internal.VeSyncConstants.*;
 import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolConstants.*;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -48,21 +49,37 @@ import org.slf4j.LoggerFactory;
 @NonNullByDefault
 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;
-    // "Device Type" values
-    public static final String DEV_TYPE_DUAL_200S = "Dual200S";
-    public static final String DEV_TYPE_CLASSIC_200S = "Classic200S";
-    public static final String DEV_TYPE_CORE_301S = "LUH-D301S-WEU";
-    public static final String DEV_TYPE_CLASSIC_300S = "Classic300S";
-    public static final String DEV_TYPE_600S = "LUH-A602S-WUS";
-    public static final String DEV_TYPE_600S_EU = "LUH-A602S-WEU";
+
+    public static final String DEV_FAMILY_CLASSIC_200S = "Classic 200S";
+    public static final String DEV_FAMILY_CLASSIC_300S = "Classic 300S";
+    public static final String DEV_FAMILY_DUAL_200S = "Dual 200S";
+    public static final String DEV_FAMILY_600S = "600S";
+    public static final String DEV_FAMILY_OASIS_MIST = "Oasis Mist";
+
+    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_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);
 
     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
     protected String[] getChannelsToRemove() {
         String[] toRemove = new String[] {};
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType != null) {
-            switch (deviceType) {
-                case DEV_TYPE_CLASSIC_300S:
+        final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
+        if (deviceFamily != null) {
+            switch (deviceFamily) {
+                case DEV_FAMILY_CLASSIC_300S:
                     toRemove = new String[] { DEVICE_CHANNEL_WARM_ENABLED, DEVICE_CHANNEL_WARM_LEVEL };
                     break;
-                case DEV_TYPE_DUAL_200S:
-                case DEV_TYPE_CLASSIC_200S:
-                case DEV_TYPE_CORE_301S:
+                case DEV_FAMILY_DUAL_200S:
+                case DEV_FAMILY_CLASSIC_200S:
                     toRemove = new String[] { DEVICE_CHANNEL_WARM_ENABLED, DEVICE_CHANNEL_WARM_LEVEL,
                             DEVICE_CHANNEL_AF_NIGHT_LIGHT };
                     break;
-                case DEV_TYPE_600S:
-                case DEV_TYPE_600S_EU:
+                case DEV_FAMILY_OASIS_MIST:
                     toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT };
                     break;
             }
@@ -122,18 +137,19 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
     }
 
     @Override
-    protected boolean isDeviceSupported() {
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType == null) {
-            return false;
-        }
-        return SUPPORTED_DEVICE_TYPES.contains(deviceType);
+    public String getDeviceFamilyProtocolPrefix() {
+        return DEV_TYPE_FAMILY_AIR_HUMIDIFIER;
+    }
+
+    @Override
+    public List<VeSyncDeviceMetadata> getSupportedDeviceMetadata() {
+        return SUPPORTED_MODEL_FAMILIES;
     }
 
     @Override
     public void handleCommand(final ChannelUID channelUID, final Command command) {
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType == null) {
+        final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
+        if (deviceFamily == null) {
             return;
         }
 
@@ -180,7 +196,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
                         int targetMistLevel = ((QuantityType<?>) command).intValue();
                         // 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.
-                        if (DEV_TYPE_CORE_301S.equals(deviceType)) {
+                        if (DEV_FAMILY_DUAL_200S.equals(deviceFamily)) {
                             if (targetMistLevel < 1) {
                                 logger.warn("Target Mist Level less than 1 - adjusting to 1 as the valid API value");
                                 targetMistLevel = 1;
@@ -235,8 +251,8 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
                                 new VeSyncRequestManagedDeviceBypassV2.SetMode(targetMode));
                         break;
                     case DEVICE_CHANNEL_AF_NIGHT_LIGHT:
-                        if (!DEV_TYPE_CLASSIC_300S.equals(deviceType) && !DEV_TYPE_CORE_301S.equals(deviceType)) {
-                            logger.warn("Humidifier night light is not valid for your device ({}})", deviceType);
+                        if (!DEV_FAMILY_CLASSIC_300S.equals(deviceFamily) && !DEV_FAMILY_600S.equals(deviceFamily)) {
+                            logger.warn("Humidifier night light is not valid for your device ({}})", deviceFamily);
                             return;
                         }
                         if (!CLASSIC_300S_NIGHT_LIGHT_MODES.contains(targetMode)) {
@@ -314,7 +330,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
             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_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));
 
         // 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.
             if (humidifierStatus.result.result.nightLightBrightness == 0) {
                 updateState(DEVICE_CHANNEL_AF_NIGHT_LIGHT, new StringType(MODE_OFF));
@@ -338,7 +354,7 @@ public class VeSyncDeviceAirHumidifierHandler extends VeSyncBaseDeviceHandler {
             } else {
                 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_LEVEL, new DecimalType(humidifierStatus.result.result.warmLevel));
         }
index 977b907a7ab8af9240731d51a012b1b14739a4b4..ab6d8ac8c0486c0e89102b58867db1b36a582c1b 100644 (file)
@@ -18,6 +18,7 @@ import static org.openhab.binding.vesync.internal.dto.requests.VeSyncProtocolCon
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -56,16 +57,34 @@ import org.slf4j.LoggerFactory;
 @NonNullByDefault
 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;
-    // "Device Type" values
-    public static final String DEV_TYPE_CORE_600S = "LAP-C601S-WUS";
-    public static final String DEV_TYPE_CORE_400S = "Core400S";
-    public static final String DEV_TYPE_CORE_300S = "Core300S";
-    public static final String DEV_TYPE_CORE_201S = "LAP-C201S-AUSR";
-    public static final String DEV_TYPE_CORE_200S = "Core200S";
-    public static final String DEV_TYPE_LV_PUR131S = "LV-PUR131S";
-    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 String DEV_FAMILY_CORE_200S = "200S";
+    public static final String DEV_FAMILY_CORE_300S = "300S";
+    public static final String DEV_FAMILY_CORE_400S = "400S";
+    public static final String DEV_FAMILY_CORE_600S = "600S";
+
+    public static final String DEV_FAMILY_PUR_131S = "131S";
+
+    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_200S300S_FAN_MODES = Arrays.asList(MODE_MANUAL, MODE_SLEEP);
@@ -89,15 +108,15 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
 
     @Override
     protected @NotNull String[] getChannelsToRemove() {
+        final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
         String[] toRemove = new String[] {};
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType != null) {
-            switch (deviceType) {
-                case DEV_TYPE_CORE_600S:
-                case DEV_TYPE_CORE_400S:
+        if (deviceFamily != null) {
+            switch (deviceFamily) {
+                case DEV_FAMILY_CORE_600S:
+                case DEV_FAMILY_CORE_400S:
                     toRemove = new String[] { DEVICE_CHANNEL_AF_NIGHT_LIGHT };
                     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,
                             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,
@@ -130,18 +149,19 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
     }
 
     @Override
-    protected boolean isDeviceSupported() {
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType == null) {
-            return false;
-        }
-        return SUPPORTED_DEVICE_TYPES.contains(deviceType);
+    public String getDeviceFamilyProtocolPrefix() {
+        return DEV_TYPE_FAMILY_AIR_PURIFIER;
+    }
+
+    @Override
+    public List<VeSyncDeviceMetadata> getSupportedDeviceMetadata() {
+        return SUPPORTED_MODEL_FAMILIES;
     }
 
     @Override
     public void handleCommand(final ChannelUID channelUID, final Command command) {
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType == null) {
+        final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
+        if (deviceFamily == null) {
             return;
         }
 
@@ -167,9 +187,9 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
                 switch (channelUID.getId()) {
                     case DEVICE_CHANNEL_FAN_MODE_ENABLED:
                         final String targetFanMode = command.toString().toLowerCase();
-                        switch (deviceType) {
-                            case DEV_TYPE_CORE_600S:
-                            case DEV_TYPE_CORE_400S:
+                        switch (deviceFamily) {
+                            case DEV_FAMILY_CORE_600S:
+                            case DEV_FAMILY_CORE_400S:
                                 if (!CORE_400S600S_FAN_MODES.contains(targetFanMode)) {
                                     logger.warn(
                                             "Fan mode command for \"{}\" is not valid in the (Core400S) API possible options {}",
@@ -177,9 +197,8 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
                                     return;
                                 }
                                 break;
-                            case DEV_TYPE_CORE_200S:
-                            case DEV_TYPE_CORE_201S:
-                            case DEV_TYPE_CORE_300S:
+                            case DEV_FAMILY_CORE_200S:
+                            case DEV_FAMILY_CORE_300S:
                                 if (!CORE_200S300S_FAN_MODES.contains(targetFanMode)) {
                                     logger.warn(
                                             "Fan mode command for \"{}\" is not valid in the (Core200S/Core300S) API possible options {}",
@@ -194,14 +213,13 @@ public class VeSyncDeviceAirPurifierHandler extends VeSyncBaseDeviceHandler {
                         break;
                     case DEVICE_CHANNEL_AF_NIGHT_LIGHT:
                         final String targetNightLightMode = command.toString().toLowerCase();
-                        switch (deviceType) {
-                            case DEV_TYPE_CORE_600S:
-                            case DEV_TYPE_CORE_400S:
+                        switch (deviceFamily) {
+                            case DEV_FAMILY_CORE_600S:
+                            case DEV_FAMILY_CORE_400S:
                                 logger.warn("Core400S API does not support night light");
                                 return;
-                            case DEV_TYPE_CORE_200S:
-                            case DEV_TYPE_CORE_201S:
-                            case DEV_TYPE_CORE_300S:
+                            case DEV_FAMILY_CORE_200S:
+                            case DEV_FAMILY_CORE_300S:
                                 if (!CORE_200S300S_NIGHT_LIGHT_MODES.contains(targetNightLightMode)) {
                                     logger.warn(
                                             "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;
                         }
 
-                        switch (deviceType) {
-                            case DEV_TYPE_CORE_600S:
-                            case DEV_TYPE_CORE_400S:
+                        switch (deviceFamily) {
+                            case DEV_FAMILY_CORE_600S:
+                            case DEV_FAMILY_CORE_400S:
                                 if (requestedLevel > 4) {
                                     logger.warn(
                                             "Fan speed command greater than 4 - adjusting to 4 as the valid (Core400S) API value");
                                     requestedLevel = 4;
                                 }
                                 break;
-                            case DEV_TYPE_CORE_200S:
-                            case DEV_TYPE_CORE_201S:
-                            case DEV_TYPE_CORE_300S:
+                            case DEV_FAMILY_CORE_200S:
+                            case DEV_FAMILY_CORE_300S:
                                 if (requestedLevel > 3) {
                                     logger.warn(
                                             "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
     protected void pollForDeviceData(final ExpiringCache<String> cachedResponse) {
-        final String deviceType = getThing().getProperties().get(DEVICE_PROP_DEVICE_TYPE);
-        if (deviceType == null) {
+        final String deviceFamily = getThing().getProperties().get(DEVICE_PROP_DEVICE_FAMILY);
+        if (deviceFamily == null) {
             return;
         }
 
-        switch (deviceType) {
-            case DEV_TYPE_CORE_600S:
-            case DEV_TYPE_CORE_400S:
-            case DEV_TYPE_CORE_300S:
-            case DEV_TYPE_CORE_201S:
-            case DEV_TYPE_CORE_200S:
+        switch (deviceFamily) {
+            case DEV_FAMILY_CORE_600S:
+            case DEV_FAMILY_CORE_400S:
+            case DEV_FAMILY_CORE_300S:
+            case DEV_FAMILY_CORE_200S:
                 processV2BypassPoll(cachedResponse);
                 break;
-            case DEV_TYPE_LV_PUR131S:
+            case DEV_FAMILY_PUR_131S:
                 processV1AirPurifierPoll(cachedResponse);
                 break;
         }
diff --git a/bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncDeviceMetadata.java b/bundles/org.openhab.binding.vesync/src/main/java/org/openhab/binding/vesync/internal/handlers/VeSyncDeviceMetadata.java
new file mode 100644 (file)
index 0000000..8c27ac0
--- /dev/null
@@ -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;
+    }
+}
index b3ef07132a31dda9b35086cf98f2834867b8c943..e1ffdac5c496e64a935604a30ebc656a77349d64 100644 (file)
@@ -70,6 +70,7 @@
                        <property name="Device Name"/>
                        <property name="Device Type"/>
                        <property name="MAC Id"/>
+                       <property name="Device Family"/>
                </properties>
                <representation-property>macId</representation-property>
 
                        <property name="Device Name"/>
                        <property name="Device Type"/>
                        <property name="MAC Id"/>
+                       <property name="Device Family"/>
                </properties>
                <representation-property>macId</representation-property>