Skip to content

Commit

Permalink
[hue] Support new home security products (openhab#15601)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Fiddian-Green <[email protected]>
  • Loading branch information
andrewfg authored Nov 9, 2023
1 parent 5555d68 commit 4f6d33b
Show file tree
Hide file tree
Showing 16 changed files with 473 additions and 29 deletions.
63 changes: 34 additions & 29 deletions bundles/org.openhab.binding.hue/doc/readme_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,35 +59,40 @@ The configuration of all things (as described above) is the same regardless of w

Device things support some of the following channels:

| Channel ID | Item Type | Description |
|---------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------|
| color | Color | Supports full color control with hue, saturation and brightness values, or brightness only, or switching on or off. |
| brightness | Dimmer | Supports control of the brightness value, or switching on or off. |
| color-temperature | Dimmer | Supports control of the color temperature in percent from cold (0%) to warm (100%). |
| color-temperature-abs | Number:Temperature | Supports control of the color temperature via a QuantityType having a temperature unit e.g. Kelvin. (Advanced) |
| switch | Switch | Supports switching the device on and off. |
| dynamics | Number:Time | Sets the duration of dynamic transitions between light states. (Advanced) |
| alert | String | Allows setting an alert on a light e.g. flashing them. (Advanced) |
| effect | String | Allows setting an effect on a light e.g. 'candle' effect. (Advanced) |
| button-last-event | (String) | Informs which button was last pressed in the device. (Trigger Channel) |
| button-last-updated | DateTime | The date and time when a button was last pressed. (Read Only) (Advanced) |
| rotary-steps | (String) | Informs about the number of rotary steps of the last rotary dial movement. (Trigger Channel) |
| rotary-steps-last-updated | DateTime | The date and time when the rotary steps were last updated. (Read Only) (Advanced) |
| motion | Switch | Shows if motion has been detected by the sensor. (Read Only) |
| motion-enabled | Switch | Supports enabling / disabling the motion sensor. (Advanced) |
| motion-last-updated | DateTime | The date and time when the motion value was last updated. (Read Only) (Advanced) |
| light-level | Number:Illuminance | Shows the current light level measured by the sensor. (Read Only) |
| light-level-last-updated | DateTime | The date and time when the light level was last updated. (Read Only) (Advanced) |
| light-level-enabled | Switch | Supports enabling / disabling the light level sensor. (Advanced) |
| temperature | Number:Temperature | Shows the current temperature measured by the sensor. (Read Only) |
| temperature-last-updated | DateTime | The date and time when the temperature was last updated. (Read Only) (Advanced) |
| temperature-enabled | Switch | Supports enabling / disabling the temperature sensor. (Advanced) |
| battery-level | Number | Shows the battery level. (Read Only) |
| battery-low | Switch | Indicates whether the battery is low or not. (Read Only) |
| last-updated | DateTime | The date and time when the thing state was last updated. (Read Only) (Advanced) |
| color-xy-only | Color | Allows access to the `color-xy` parameter of the light(s) only. Has no impact on `dimming` or `on-off` parameters. |
| dimming-only | Dimmer | Allows access to the `dimming` parameter of the light(s) only. Has no impact on `color-xy` or `on-off` parameters. |
| on-off-only | Switch | Allows access to the `on-off` parameter of the light(s) only. Has no impact on `color-xy` or `dimming` parameters. |
| Channel ID | Item Type | Description |
|-------------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------|
| color | Color | Supports full color control with hue, saturation and brightness values, or brightness only, or switching on or off. |
| brightness | Dimmer | Supports control of the brightness value, or switching on or off. |
| color-temperature | Dimmer | Supports control of the color temperature in percent from cold (0%) to warm (100%). |
| color-temperature-abs | Number:Temperature | Supports control of the color temperature via a QuantityType having a temperature unit e.g. Kelvin. (Advanced) |
| switch | Switch | Supports switching the device on and off. |
| dynamics | Number:Time | Sets the duration of dynamic transitions between light states. (Advanced) |
| alert | String | Allows setting an alert on a light e.g. flashing them. (Advanced) |
| effect | String | Allows setting an effect on a light e.g. 'candle' effect. (Advanced) |
| button-last-event | (String) | Informs which button was last pressed in the device. (Trigger Channel) |
| button-last-updated | DateTime | The date and time when a button was last pressed. (Read Only) (Advanced) |
| rotary-steps | (String) | Informs about the number of rotary steps of the last rotary dial movement. (Trigger Channel) |
| rotary-steps-last-updated | DateTime | The date and time when the rotary steps were last updated. (Read Only) (Advanced) |
| motion | Switch | Shows if motion has been detected by the sensor. (Read Only) |
| motion-enabled | Switch | Supports enabling / disabling the motion sensor. (Advanced) |
| motion-last-updated | DateTime | The date and time when the motion value was last updated. (Read Only) (Advanced) |
| light-level | Number:Illuminance | Shows the current light level measured by the sensor. (Read Only) |
| light-level-last-updated | DateTime | The date and time when the light level was last updated. (Read Only) (Advanced) |
| light-level-enabled | Switch | Supports enabling / disabling the light level sensor. (Advanced) |
| temperature | Number:Temperature | Shows the current temperature measured by the sensor. (Read Only) |
| temperature-last-updated | DateTime | The date and time when the temperature was last updated. (Read Only) (Advanced) |
| temperature-enabled | Switch | Supports enabling / disabling the temperature sensor. (Advanced) |
| battery-level | Number | Shows the battery level. (Read Only) |
| battery-low | Switch | Indicates whether the battery is low or not. (Read Only) |
| last-updated | DateTime | The date and time when the thing state was last updated. (Read Only) (Advanced) |
| color-xy-only | Color | Allows access to the `color-xy` parameter of the light(s) only. Has no impact on `dimming` or `on-off` parameters. |
| dimming-only | Dimmer | Allows access to the `dimming` parameter of the light(s) only. Has no impact on `color-xy` or `on-off` parameters. |
| on-off-only | Switch | Allows access to the `on-off` parameter of the light(s) only. Has no impact on `color-xy` or `dimming` parameters. |
| security-contact | Contact | Indicates whether a security contact has been triggered. (Read Only) |
| security-contact-enabled | Switch | Supports enabling / disabling the security contact. (Advanced) |
| security-contact-last-updated | DateTime | The date and time when the security contact state was last updated. (Read Only) (Advanced) |
| security-tamper | Contact | Indicates whether a security tamper contact has been triggered. `Open` means tampering detected. (Read Only) |
| security-tamper-last-updated | DateTime | The date and time when the security tamper contact state was last updated. (Read Only) (Advanced) |

The exact list of channels in a given device is determined at run time when the system is started.
Each device reports its own live list of capabilities, and the respective list of channels is created accordingly.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ public class HueBindingConstants {
public static final String CHANNEL_2_COLOR_XY_ONLY = "color-xy-only";
public static final String CHANNEL_2_DIMMING_ONLY = "dimming-only";
public static final String CHANNEL_2_ON_OFF_ONLY = "on-off-only";
public static final String CHANNEL_2_SECURITY_CONTACT = "security-contact";
public static final String CHANNEL_2_SECURITY_CONTACT_ENABLED = "security-contact-enabled";
public static final String CHANNEL_2_SECURITY_CONTACT_LAST_UPDATED = "security-contact-last-updated";
public static final String CHANNEL_2_SECURITY_TAMPER = "security-tamper";
public static final String CHANNEL_2_SECURITY_TAMPER_LAST_UPDATED = "security-tamper-last-updated";

// channel IDs that (optionally) support dynamics
public static final Set<String> DYNAMIC_CHANNELS = Set.of(CHANNEL_2_BRIGHTNESS, CHANNEL_2_COLOR,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* 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.hue.internal.dto.clip2;

import java.time.Instant;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.hue.internal.dto.clip2.enums.ContactStateType;

/**
* DTO for CLIP 2 home security alarm contact.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class ContactReport {

private @NonNullByDefault({}) Instant changed;
private @NonNullByDefault({}) String state;

public ContactStateType getContactState() throws IllegalArgumentException {
return ContactStateType.valueOf(state.toUpperCase());
}

public Instant getLastChanged() {
return changed;
}

public ContactReport setLastChanged(Instant changed) {
this.changed = changed;
return this;
}

public ContactReport setContactState(String state) {
this.state = state;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,20 @@
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hue.internal.dto.clip2.enums.ActionType;
import org.openhab.binding.hue.internal.dto.clip2.enums.ButtonEventType;
import org.openhab.binding.hue.internal.dto.clip2.enums.ContactStateType;
import org.openhab.binding.hue.internal.dto.clip2.enums.EffectType;
import org.openhab.binding.hue.internal.dto.clip2.enums.ResourceType;
import org.openhab.binding.hue.internal.dto.clip2.enums.SceneRecallAction;
import org.openhab.binding.hue.internal.dto.clip2.enums.SmartSceneRecallAction;
import org.openhab.binding.hue.internal.dto.clip2.enums.SmartSceneState;
import org.openhab.binding.hue.internal.dto.clip2.enums.TamperStateType;
import org.openhab.binding.hue.internal.dto.clip2.enums.ZigbeeStatus;
import org.openhab.binding.hue.internal.exceptions.DTOPresentButEmptyException;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
Expand Down Expand Up @@ -103,6 +106,8 @@ public class Resource {
private @Nullable List<ResourceReference> children;
private @Nullable JsonElement status;
private @Nullable @SuppressWarnings("unused") Dynamics dynamics;
private @Nullable @SerializedName("contact_report") ContactReport contactReport;
private @Nullable @SerializedName("tamper_reports") List<TamperReport> tamperReports;
private @Nullable String state;

/**
Expand Down Expand Up @@ -325,6 +330,20 @@ public State getColorXyState() {
return UnDefType.NULL;
}

public State getContactLastUpdatedState(ZoneId zoneId) {
ContactReport contactReport = this.contactReport;
return Objects.nonNull(contactReport)
? new DateTimeType(ZonedDateTime.ofInstant(contactReport.getLastChanged(), zoneId))
: UnDefType.NULL;
}

public State getContactState() {
ContactReport contactReport = this.contactReport;
return Objects.isNull(contactReport) ? UnDefType.NULL
: ContactStateType.CONTACT == contactReport.getContactState() ? OpenClosedType.CLOSED
: OpenClosedType.OPEN;
}

public int getControlId() {
MetaData metadata = this.metadata;
return Objects.nonNull(metadata) ? metadata.getControlId() : 0;
Expand Down Expand Up @@ -649,6 +668,33 @@ public JsonObject getStatus() {
return new JsonObject();
}

public State getTamperLastUpdatedState(ZoneId zoneId) {
TamperReport report = getTamperReportsLatest();
return Objects.nonNull(report) ? new DateTimeType(ZonedDateTime.ofInstant(report.getLastChanged(), zoneId))
: UnDefType.NULL;
}

/**
* The the Hue bridge could return its raw list of tamper reports in any order, so sort the list (latest entry
* first) according to the respective 'changed' instant and return the first entry i.e. the latest changed entry.
*
* @return the latest changed tamper report
*/
private @Nullable TamperReport getTamperReportsLatest() {
List<TamperReport> reports = this.tamperReports;
return Objects.nonNull(reports)
? reports.stream().sorted((e1, e2) -> e2.getLastChanged().compareTo(e1.getLastChanged())).findFirst()
.orElse(null)
: null;
}

public State getTamperState() {
TamperReport report = getTamperReportsLatest();
return Objects.nonNull(report)
? TamperStateType.TAMPERED == report.getTamperState() ? OpenClosedType.OPEN : OpenClosedType.CLOSED
: UnDefType.NULL;
}

public @Nullable Temperature getTemperature() {
return temperature;
}
Expand Down Expand Up @@ -736,6 +782,11 @@ public Resource setColorXy(ColorXy color) {
return this;
}

public Resource setContactReport(ContactReport contactReport) {
this.contactReport = contactReport;
return this;
}

public Resource setDimming(Dimming dimming) {
this.dimming = dimming;
return this;
Expand Down Expand Up @@ -815,6 +866,11 @@ public Resource setRecallDuration(Duration recallDuration) {
return this;
}

public Resource setTamperReports(List<TamperReport> tamperReports) {
this.tamperReports = tamperReports;
return this;
}

public Resource setTimedEffects(TimedEffects timedEffects) {
this.timedEffects = timedEffects;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* 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.hue.internal.dto.clip2;

import java.time.Instant;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.hue.internal.dto.clip2.enums.TamperStateType;

/**
* DTO for CLIP 2 home security tamper switch.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class TamperReport {

private @NonNullByDefault({}) Instant changed;
private @NonNullByDefault({}) String state;

public Instant getLastChanged() {
return changed;
}

public TamperStateType getTamperState() throws IllegalArgumentException {
return TamperStateType.valueOf(state.toUpperCase());
}

public TamperReport setLastChanged(Instant changed) {
this.changed = changed;
return this;
}

public TamperReport setTamperState(String state) {
this.state = state;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* 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.hue.internal.dto.clip2.enums;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* Enum for security contact states.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public enum ContactStateType {
NO_CONTACT,
CONTACT
}
Loading

0 comments on commit 4f6d33b

Please sign in to comment.