Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tradfri] Add support for Air Purifier #14836

Merged
merged 6 commits into from Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 61 additions & 13 deletions bundles/org.openhab.binding.tradfri/README.md
@@ -1,6 +1,7 @@
# TRÅDFRI Binding

This binding integrates the IKEA TRÅDFRI gateway and devices connected to it (such as dimmable LED bulbs).
This binding only supports IKEA TRÅDFRI gateway v1.x, it is **not** compatible with DIRIGERA.

## Supported Things

Expand All @@ -22,22 +23,34 @@ These are:
| Non-Colour Controller | 0x0820 | 0820 |
| Non-Colour Scene Controller | 0x0830 | 0830 |
| Control Outlet | 0x0010 | 0010 |
| Window Covering Device | 0x0202 | 0202 |
| Window Covering Controller | 0x0202 | 0203 |

The following matrix lists the capabilities (channels) for each of the supported lighting device types:

| Thing type | Brightness | Color | Color Temperature | Battery Level | Battery Low | Power | Position |
|-------------|:----------:|:-----:|:-----------------:|:-------------:|:-----------:|:-----:|:---------|
| 0010 | | | | | | X | |
| 0100 | X | | | | | | |
| 0220 | X | | X | | | | |
| 0210 | | X | X | | | | |
| 0107 | | | | X | X | | |
| 0820 | | | | X | X | | |
| 0830 | | | | X | X | | |
| 0202 | | | | X | X | | X |
| 0203 | | | | X | X | | |
| Thing type | Brightness | Color | Color Temperature | Battery Level | Battery Low | Power |
|-------------|:----------:|:-----:|:-----------------:|:-------------:|:-----------:|:-----:|
| 0010 | | | | | | X |
| 0100 | X | | | | | |
| 0220 | X | | X | | | |
| 0210 | | X | X | | | |
| 0107 | | | | X | X | |
| 0820 | | | | X | X | |
| 0830 | | | | X | X | |

The following things are also supported even thought they are not standardized in Zigbee Light Link:

| Device type | Zigbee Device ID | Thing type |
|---------------------------------|------------------|------------|
| Window Covering Device | 0x0202 | 0202 |
| Window Covering Controller | 0x0203 | 0203 |
| Air Purifier | 0x0007 | 0007 |

The following matrix lists the capabilities (channels) for each of the supported non-lighting device types:

| Thing type | Battery Level | Battery Low | Position | Fan Mode | Lock physical buttons | LED's on/off | Air Quality | Current Fan Speed | Filter status |
|-------------|:-------------:|:-----------:|:--------:|:--------:|:---------------------:|:------------:|:-----------:|:-----------------:|:-------------:|
| 0202 | X | X | X | | | | | | |
| 0203 | X | X | | | | | | | |
| 0007 | | | | X | X | X | X | X | X |

## Thing Configuration

Expand Down Expand Up @@ -65,6 +78,13 @@ The control outlet supports the `power` channel.

A blind or curtain supports, beside `battery_level` and `battery_low` channels, a `positon` channel.

An air purifier supports:
* a `fan_mode` and `fan_speed`, which allows for control and reading of the speed.
* a `disable_led` and `lock_button`, to disabled the LED's or lock the button on the physical device.
* a `air_quality_pm25` and `air_quality_rating`, which reads the particulate matter 2.5μm and corresponding indication of air quality.
* a `filter_check_next` and `filter_check_alarm`, which represents the remaining number of minutes until next filter check and whether it is time to do the filter check now. Filter check must be completed through the TRÅDFRI app.
* a `filter_uptime`, which represents the current time since last filter change.
vivienbo marked this conversation as resolved.
Show resolved Hide resolved

Refer to the matrix above.

| Channel Type ID | Item Type | Description |
Expand All @@ -76,6 +96,15 @@ Refer to the matrix above.
| battery_low | Switch | battery low warning (<=10% = ON, >10% = OFF) |
| power | Switch | power switch |
| position | Rollershutter | position of the blinds from 0% = open to 100% = closed |
| fan_mode | Number | Fan Mode, target speed of the fan (0 = off, 1 = auto, 10..50 = Level 1 to 5) |
vivienbo marked this conversation as resolved.
Show resolved Hide resolved
| fan_speed | Number | Current Fan Speed between 0 (off) and 50 (maximum speed) |
| disable_led | Switch | Disables the LED's on the device |
| lock_button | Switch | Disables the physical button on the device (applications can still make changes) |
| air_quality_pm25 | Number | Density of Particulate Matter of 2.5μm, measured in ppm |
| air_quality_rating | Number | Gives a rating about air quality (1 = Good, 2 = OK, 3 = Bad) similar to Tradfri app |
| filter_check_next | Number:Time | Time in min before the next filter check if > 0, if < 0 you are late checking the filter |
| filter_check_alarm | Switch | When ON, you must perform a filter check (i.e. `filter_check_next` is < 0) |
| filter_uptime | Number:Time | Time elapsed since the last filter change, in min |

## Full Example

Expand All @@ -89,6 +118,7 @@ Bridge tradfri:gateway:mygateway [ host="192.168.0.177", code="EHPW5rIJKyXFgjH3"
0830 myRemoteControl "My Remote Control" [ id=65545 ]
0010 myControlOutlet "My Control Outlet" [ id=65542 ]
0202 myBlinds "My Blinds" [ id=65547 ]
0007 myAirPurifier "My Air Purifier" [ id=65548 ]
}
```

Expand All @@ -103,6 +133,15 @@ Number RemoteControlBatteryLevel { channel="tradfri:0830:mygateway:myRemoteContr
Switch RemoteControlBatteryLow { channel="tradfri:0830:mygateway:myRemoteControl:battery_low" }
Switch ControlOutlet { channel="tradfri:0010:mygateway:myControlOutlet:power" }
Rollershutter BlindPosition { channel="tradfri:0202:mygateway:myBlinds:position" }
Number AirPurifierFanMode { channel="tradfri:0007:mygateway:myAirPurifier:fan_mode" }
Number AirPurifierFanSpeed { channel="tradfri:0007:mygateway:myAirPurifier:fan_speed" }
Switch AirPurifierDisableLED { channel="tradfri:0007:mygateway:myAirPurifier:disable_led" }
Switch AirPurifierLockPhysicalButton { channel="tradfri:0007:mygateway:myAirPurifier:lock_button" }
Number AirPurifierQualityPM25 { channel="tradfri:0007:mygateway:myAirPurifier:air_quality_pm25" }
Number AirPurifierQualityRating { channel="tradfri:0007:mygateway:myAirPurifier:air_quality_rating" }
Number AirPurifierFilterCheckTTL { channel="tradfri:0007:mygateway:myAirPurifier:filter_check_next" }
Switch AirPurifierFilterCheckAlarm { channel="tradfri:0007:mygateway:myAirPurifier:filter_check_alarm" }
Number AirPurifierFilterUptime { channel="tradfri:0007:mygateway:myAirPurifier:filter_uptime" }
```

demo.sitemap:
Expand All @@ -119,6 +158,15 @@ sitemap demo label="Main Menu"
Switch item=RemoteControlBatteryLow label="Battery Low Warning"
Switch item=ControlOutlet label="Power Switch"
Switch item=BlindPosition label="Blind Position [%d]"
Selection item=AirPurifierFanMode label="Fan Mode"
Text item=AirPurifierFanSpeed label="Current Fan Speed [%d]"
Switch item=AirPurifierDisableLED label="Disable LEDs"
Switch item=AirPurifierLockPhysicalButton label="Disable Physical Buttons"
Text item=AirPurifierQualityPM25 label="PM2.5"
Text item=AirPurifierQualityRating label="Air Quality"
Text item=AirPurifierFilterCheckTTL label="TTL before next filter check [%d min]"
Text item=AirPurifierFilterCheckAlarm label="Need to Check Filter [%s]"
Text item=AirPurifierFilterUptime label="Current filter uptime [%d min]"
}
}
```
Expand Up @@ -27,6 +27,7 @@
* @author Kai Kreuzer - Initial contribution
* @author Christoph Weitkamp - Added support for remote controller and motion sensor devices (read-only battery level)
* @author Manuel Raffel - Added support for blinds
* @author Vivien Boistuaud - Added support for air purifier
*/
@NonNullByDefault
public class TradfriBindingConstants {
Expand All @@ -45,6 +46,7 @@ public class TradfriBindingConstants {
public static final ThingTypeUID THING_TYPE_MOTION_SENSOR = new ThingTypeUID(BINDING_ID, "0107");
public static final ThingTypeUID THING_TYPE_BLINDS = new ThingTypeUID(BINDING_ID, "0202");
public static final ThingTypeUID THING_TYPE_OPEN_CLOSE_REMOTE_CONTROL = new ThingTypeUID(BINDING_ID, "0203");
public static final ThingTypeUID THING_TYPE_AIR_PURIFIER = new ThingTypeUID(BINDING_ID, "0007");

public static final Set<ThingTypeUID> SUPPORTED_LIGHT_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_TEMP_LIGHT, THING_TYPE_COLOR_LIGHT)
Expand All @@ -54,6 +56,9 @@ public class TradfriBindingConstants {

public static final Set<ThingTypeUID> SUPPORTED_BLINDS_TYPES_UIDS = Collections.singleton(THING_TYPE_BLINDS);

public static final Set<ThingTypeUID> SUPPORTED_AIR_PURIFIER_TYPES_UIDS = Collections
.singleton(THING_TYPE_AIR_PURIFIER);
vivienbo marked this conversation as resolved.
Show resolved Hide resolved

// List of all Gateway Configuration Properties
public static final String GATEWAY_CONFIG_HOST = "host";
public static final String GATEWAY_CONFIG_PORT = "port";
Expand All @@ -70,7 +75,8 @@ public class TradfriBindingConstants {

public static final Set<ThingTypeUID> SUPPORTED_DEVICE_TYPES_UIDS = Collections.unmodifiableSet(Stream
.of(SUPPORTED_LIGHT_TYPES_UIDS.stream(), SUPPORTED_CONTROLLER_TYPES_UIDS.stream(),
SUPPORTED_PLUG_TYPES_UIDS.stream(), SUPPORTED_BLINDS_TYPES_UIDS.stream())
SUPPORTED_PLUG_TYPES_UIDS.stream(), SUPPORTED_BLINDS_TYPES_UIDS.stream(),
SUPPORTED_AIR_PURIFIER_TYPES_UIDS.stream())
.reduce(Stream::concat).orElseGet(Stream::empty).collect(Collectors.toSet()));

public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
Expand All @@ -85,9 +91,20 @@ public class TradfriBindingConstants {
public static final String CHANNEL_POSITION = "position";
public static final String CHANNEL_BATTERY_LEVEL = "battery_level";
public static final String CHANNEL_BATTERY_LOW = "battery_low";
public static final String CHANNEL_FAN_MODE = "fan_mode";
public static final String CHANNEL_FAN_SPEED = "fan_speed";
public static final String CHANNEL_DISABLE_LED = "disable_led";
public static final String CHANNEL_LOCK_BUTTON = "lock_button";
public static final String CHANNEL_AIR_QUALITY_PM25 = "air_quality_pm25";
public static final String CHANNEL_AIR_QUALITY_RATING = "air_quality_rating";
public static final String CHANNEL_FILTER_CHECK_NEXT = "filter_check_next";
public static final String CHANNEL_FILTER_CHECK_ALARM = "filter_check_alarm";
public static final String CHANNEL_FILTER_UPTIME = "filter_uptime";

// IPSO Objects
public static final String DEVICES = "15001";
public static final String AIR_PURIFIER = "15025";
public static final String AIR_QUALITY = "5907";
public static final String AUTH_PATH = "9063";
public static final String BLINDS = "15015";
public static final String CLIENT_IDENTITY_PROPOSED = "9090";
Expand All @@ -107,6 +124,9 @@ public class TradfriBindingConstants {
public static final String END_TIME_HR = "9048";
public static final String END_TIME_MN = "9049";
public static final String ERROR_TAG = "errorcode";
public static final String FAN_MODE = "5900";
public static final String FAN_SPEED = "5908";
public static final String FILTER_UPTIME = "5902";
public static final String FORCE_CHECK_OTA_UPDATE = "9032";
public static final String GATEWAY = "15011";
public static final String GATEWAY_DETAILS = "15012";
Expand All @@ -125,9 +145,11 @@ public class TradfriBindingConstants {
public static final String IKEA_MOODS = "9068";
public static final String INSTANCE_ID = "9003";
public static final String LAST_SEEN = "9020";
public static final String LED_DISABLE = "5906";
public static final String LIGHT = "3311";
public static final int LIGHTS_OFF_SMART_TASK = 2;
public static final String LIGHT_SETTING = "15013";
public static final String LOCK_PHYSICAL_BUTTON = "5905";
public static final int LOSS_OF_INTERNET_CONNECTIVITY = 5001;
public static final String MASTER_TOKEN_TAG = "9036";
public static final String MAX_MSR_VALUE = "5602";
Expand All @@ -137,6 +159,7 @@ public class TradfriBindingConstants {
public static final String NAME = "9001";
public static final int NEW_FIRMWARE_AVAILABLE = 1001;
public static final String NEW_PSK_BY_GW = "9091";
public static final String NEXT_FILTER_CHECK = "5910";
public static final String NOTIFICATION_EVENT = "9015";
public static final String NOTIFICATION_NVPAIR = "9017";
public static final String NOTIFICATION_STATE = "9014";
Expand Down Expand Up @@ -201,8 +224,28 @@ public class TradfriBindingConstants {
public static final String TYPE_SENSOR = "4";
public static final String TYPE_REPEATER = "6";
public static final String TYPE_BLINDS = "7";
public static final String TYPE_AIR_PURIFIER = "10";

public static final String DEVICE_VENDOR = "0";
public static final String DEVICE_MODEL = "1";
public static final String DEVICE_FIRMWARE = "3";
public static final String DEVICE_BATTERY_LEVEL = "9";

// List of Air Purifier Constants
public static final int FAN_MODE_OFF = 0;
public static final int FAN_MODE_AUTO = 1;
public static final int FAN_MODE_SPEED1 = 10;
public static final int FAN_MODE_SPEED2 = 20;
public static final int FAN_MODE_SPEED3 = 30;
public static final int FAN_MODE_SPEED4 = 40;
public static final int FAN_MODE_SPEED5 = 50;

public static final Set<Integer> AIR_PURIFIER_FANMODE = Collections
.unmodifiableSet(Stream.of(FAN_MODE_OFF, FAN_MODE_AUTO, FAN_MODE_SPEED1, FAN_MODE_SPEED2, FAN_MODE_SPEED3,
FAN_MODE_SPEED4, FAN_MODE_SPEED5).collect(Collectors.toSet()));
vivienbo marked this conversation as resolved.
Show resolved Hide resolved
vivienbo marked this conversation as resolved.
Show resolved Hide resolved

public static final int AIR_PURIFIER_AIR_QUALITY_OK = 36;
public static final int AIR_PURIFIER_AIR_QUALITY_BAD = 86;

public static final int AIR_PURIFIER_AIR_QUALITY_UNDEFINED = 65535;
}
Expand Up @@ -16,6 +16,7 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.tradfri.internal.handler.TradfriAirPurifierHandler;
import org.openhab.binding.tradfri.internal.handler.TradfriBlindHandler;
import org.openhab.binding.tradfri.internal.handler.TradfriControllerHandler;
import org.openhab.binding.tradfri.internal.handler.TradfriGatewayHandler;
Expand Down Expand Up @@ -63,6 +64,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return new TradfriLightHandler(thing);
} else if (SUPPORTED_PLUG_TYPES_UIDS.contains(thingTypeUID)) {
return new TradfriPlugHandler(thing);
} else if (THING_TYPE_AIR_PURIFIER.equals(thingTypeUID)) {
return new TradfriAirPurifierHandler(thing);
}
return null;
}
Expand Down
Expand Up @@ -49,6 +49,7 @@
* @author Christoph Weitkamp - Added support for remote controller and motion sensor devices (read-only battery level)
* @author Andre Fuechsel - fixed the results removal
* @author Manuel Raffel - Added support for blinds
* @author Vivien Boistuaud - Added support for Air Purifiers
*/
@NonNullByDefault
public class TradfriDiscoveryService extends AbstractDiscoveryService
Expand Down Expand Up @@ -158,6 +159,8 @@ public void onUpdate(@Nullable String instanceId, @Nullable JsonObject data) {
} else if (TYPE_SENSOR.equals(type) && data.has(SENSOR)) {
// Motion sensor
thingId = new ThingUID(THING_TYPE_MOTION_SENSOR, bridge, Integer.toString(id));
} else if (TYPE_AIR_PURIFIER.equals(type) && data.has(AIR_PURIFIER)) {
thingId = new ThingUID(THING_TYPE_AIR_PURIFIER, bridge, Integer.toString(id));
}

if (thingId == null) {
Expand Down