diff --git a/bundles/org.openhab.binding.hue/doc/readme_v2.md b/bundles/org.openhab.binding.hue/doc/readme_v2.md index fd9fa5d85b67a..d9b84392f0a3a 100644 --- a/bundles/org.openhab.binding.hue/doc/readme_v2.md +++ b/bundles/org.openhab.binding.hue/doc/readme_v2.md @@ -89,9 +89,10 @@ Device things support some of the following channels: | 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-last-updated | DateTime | The date and time when the security contact state was last updated. (Read Only, Advanced) | +| 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) | +| 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. diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java index d05acdc2c7c05..67af11d4c995c 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java @@ -170,6 +170,7 @@ public class HueBindingConstants { 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"; diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ContactReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ContactReport.java index 7965509a57467..99c8c2a835c0b 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ContactReport.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ContactReport.java @@ -1,3 +1,15 @@ +/** + * 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; diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Resource.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Resource.java index 11c310cc92c33..2791bbeab535c 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Resource.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Resource.java @@ -106,8 +106,8 @@ public class Resource { private @Nullable List children; private @Nullable JsonElement status; private @Nullable @SuppressWarnings("unused") Dynamics dynamics; - private @Nullable @SerializedName("contact-report") ContactReport contactReport; - private @Nullable @SerializedName("tamper-reports") List tamperReports; + private @Nullable @SerializedName("contact_report") ContactReport contactReport; + private @Nullable @SerializedName("tamper_reports") List tamperReports; private @Nullable String state; /** diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TamperReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TamperReport.java index c227d7b61e34d..50d250898adf4 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TamperReport.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TamperReport.java @@ -1,3 +1,15 @@ +/** + * 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; diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/ContactStateType.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/ContactStateType.java index 9064187dafe34..2892e77ca18fb 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/ContactStateType.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/ContactStateType.java @@ -1,3 +1,15 @@ +/** + * 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; diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/TamperStateType.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/TamperStateType.java index 34db7d26dbb66..23199b1af50d3 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/TamperStateType.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/enums/TamperStateType.java @@ -1,3 +1,15 @@ +/** + * 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; diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/Clip2ThingHandler.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/Clip2ThingHandler.java index 38ce485357bca..a436f7f889a4f 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/Clip2ThingHandler.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/Clip2ThingHandler.java @@ -433,6 +433,10 @@ public void handleCommand(ChannelUID channelUID, Command commandParam) { putResource = new Resource(ResourceType.LIGHT_LEVEL).setEnabled(command); break; + case CHANNEL_2_SECURITY_CONTACT_ENABLED: + putResource = new Resource(ResourceType.CONTACT).setEnabled(command); + break; + case CHANNEL_2_SCENE: if (command instanceof StringType) { Resource scene = sceneResourceEntries.get(((StringType) command).toString()); @@ -925,6 +929,7 @@ private boolean updateChannels(Resource resource) { updateState(CHANNEL_2_SECURITY_CONTACT, resource.getContactState(), fullUpdate); updateState(CHANNEL_2_SECURITY_CONTACT_LAST_UPDATED, resource.getContactLastUpdatedState(timeZoneProvider.getTimeZone()), fullUpdate); + updateState(CHANNEL_2_SECURITY_CONTACT_ENABLED, resource.getEnabledState(), fullUpdate); break; case TAMPER: diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties index 0712f8a81b556..3fa66d65d9a03 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties @@ -53,16 +53,17 @@ thing-type.hue.device.channel.motion-enabled.description = Motion sensor enabled thing-type.hue.device.channel.motion-last-updated.label = Motion Last Updated thing-type.hue.device.channel.motion-last-updated.description = The date and time when the motion value was last updated. thing-type.hue.device.channel.on-off-only.description = Set the on/off parameter of the light without changing other state parameters. +thing-type.hue.device.channel.rotary-steps-last-updated.label = Rotary Steps Last Updated +thing-type.hue.device.channel.rotary-steps-last-updated.description = The date and time when the rotary steps were last updated. thing-type.hue.device.channel.security-contact.label = Security Contact thing-type.hue.device.channel.security-contact.description = Open or closed state of the contact. +thing-type.hue.device.channel.security-contact-enabled.description = Security contact enabled. thing-type.hue.device.channel.security-contact-last-updated.label = Security Contact Last Updated thing-type.hue.device.channel.security-contact-last-updated.description = The date and time when the contact state was last updated. thing-type.hue.device.channel.security-tamper.label = Security Tamper Contact thing-type.hue.device.channel.security-tamper.description = Tamper or no tamper state of the sensor. thing-type.hue.device.channel.security-tamper-last-updated.label = Tamper Contact Last Updated thing-type.hue.device.channel.security-tamper-last-updated.description = The date and time when the tamper contact state was last updated. -thing-type.hue.device.channel.rotary-steps-last-updated.label = Rotary Steps Last Updated -thing-type.hue.device.channel.rotary-steps-last-updated.description = The date and time when the rotary steps were last updated. thing-type.hue.device.channel.temperature.label = Temperature thing-type.hue.device.channel.temperature.description = Temperature at the sensor location. thing-type.hue.device.channel.temperature-enabled.description = Temperature sensor enabled. diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Clip2Thing.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Clip2Thing.xml index 708fc50e1396b..33f5d935c5608 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Clip2Thing.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Clip2Thing.xml @@ -66,6 +66,9 @@ Open or closed state of the contact. + + Security contact enabled. + The date and time when the contact state was last updated. diff --git a/bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/clip2/Clip2DtoTest.java b/bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/clip2/Clip2DtoTest.java index b305a3a5abc23..79b32776d512d 100644 --- a/bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/clip2/Clip2DtoTest.java +++ b/bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/clip2/Clip2DtoTest.java @@ -712,20 +712,38 @@ void testZoneGroup() { @Test void testSecurityContact() { - Resource resource = new Resource(ResourceType.CONTACT); - assertEquals(UnDefType.NULL, resource.getContactState()); - assertEquals(UnDefType.NULL, resource.getContactLastUpdatedState(ZoneId.systemDefault())); - resource.setContactReport(new ContactReport().setLastChanged(Instant.now()).setContactState("contact")); + String json = load(ResourceType.CONTACT.name().toLowerCase()); + Resources resources = GSON.fromJson(json, Resources.class); + assertNotNull(resources); + List list = resources.getResources(); + assertNotNull(list); + assertEquals(1, list.size()); + Resource resource = list.get(0); + assertEquals(ResourceType.CONTACT, resource.getType()); + assertEquals(OpenClosedType.CLOSED, resource.getContactState()); - assertTrue(resource.getContactLastUpdatedState(ZoneId.systemDefault()) instanceof DateTimeType); + assertEquals(new DateTimeType("2023-10-10T19:10:55.919Z"), + resource.getContactLastUpdatedState(ZoneId.of("UTC"))); + resource.setContactReport(new ContactReport().setLastChanged(Instant.now()).setContactState("no_contact")); assertEquals(OpenClosedType.OPEN, resource.getContactState()); + assertTrue(resource.getContactLastUpdatedState(ZoneId.of("UTC")) instanceof DateTimeType); } @Test void testSecurityTamper() { - Resource resource = new Resource(ResourceType.CONTACT); - assertEquals(UnDefType.NULL, resource.getTamperState()); + String json = load(ResourceType.TAMPER.name().toLowerCase()); + Resources resources = GSON.fromJson(json, Resources.class); + assertNotNull(resources); + List list = resources.getResources(); + assertNotNull(list); + assertEquals(1, list.size()); + Resource resource = list.get(0); + assertEquals(ResourceType.TAMPER, resource.getType()); + + assertEquals(OpenClosedType.CLOSED, resource.getTamperState()); + assertEquals(new DateTimeType("2023-01-01T00:00:00.001Z"), + resource.getTamperLastUpdatedState(ZoneId.of("UTC"))); Instant start = Instant.now(); List tamperReports; @@ -735,7 +753,7 @@ void testSecurityTamper() { tamperReports.add(new TamperReport().setTamperState("not_tampered").setLastChanged(start)); resource.setTamperReports(tamperReports); assertEquals(OpenClosedType.CLOSED, resource.getTamperState()); - state = resource.getTamperLastUpdatedState(ZoneId.systemDefault()); + state = resource.getTamperLastUpdatedState(ZoneId.of("UTC")); assertTrue(state instanceof DateTimeType); assertEquals(start, ((DateTimeType) state).getInstant()); @@ -744,7 +762,7 @@ void testSecurityTamper() { tamperReports.add(new TamperReport().setTamperState("tampered").setLastChanged(start.plusSeconds(1))); resource.setTamperReports(tamperReports); assertEquals(OpenClosedType.OPEN, resource.getTamperState()); - state = resource.getTamperLastUpdatedState(ZoneId.systemDefault()); + state = resource.getTamperLastUpdatedState(ZoneId.of("UTC")); assertTrue(state instanceof DateTimeType); assertEquals(start.plusSeconds(1), ((DateTimeType) state).getInstant()); @@ -754,11 +772,30 @@ void testSecurityTamper() { tamperReports.add(new TamperReport().setTamperState("not_tampered").setLastChanged(start.plusSeconds(2))); resource.setTamperReports(tamperReports); assertEquals(OpenClosedType.CLOSED, resource.getTamperState()); - state = resource.getTamperLastUpdatedState(ZoneId.systemDefault()); + state = resource.getTamperLastUpdatedState(ZoneId.of("UTC")); assertTrue(state instanceof DateTimeType); assertEquals(start.plusSeconds(2), ((DateTimeType) state).getInstant()); } + @Test + void testCameraMotion() { + String json = load(ResourceType.CAMERA_MOTION.name().toLowerCase()); + Resources resources = GSON.fromJson(json, Resources.class); + assertNotNull(resources); + List list = resources.getResources(); + assertNotNull(list); + assertEquals(1, list.size()); + Resource resource = list.get(0); + assertEquals(ResourceType.CAMERA_MOTION, resource.getType()); + + Boolean enabled = resource.getEnabled(); + assertNotNull(enabled); + assertTrue(enabled); + assertEquals(OnOffType.ON, resource.getMotionState()); + assertEquals(new DateTimeType("2020-04-01T20:04:30.395Z"), + resource.getMotionLastUpdatedState(ZoneId.of("UTC"))); + } + void testFixedEffectSetter() { Resource source; Resource target; diff --git a/bundles/org.openhab.binding.hue/src/test/resources/camera_motion.json b/bundles/org.openhab.binding.hue/src/test/resources/camera_motion.json new file mode 100644 index 0000000000000..c678d620d27bb --- /dev/null +++ b/bundles/org.openhab.binding.hue/src/test/resources/camera_motion.json @@ -0,0 +1,28 @@ +{ + "errors": [], + "data": [ + { + "id": "00000000-0000-0000-0000-000000000005", + "id_v1": "/sensors/5", + "owner": { + "rid": "00000000-0000-0000-0000-000000000000", + "rtype": "device" + }, + "enabled": true, + "motion": { + "motion": false, + "motion_valid": true, + "motion_report": { + "changed": "2020-04-01T20:04:30.395Z", + "motion": true + } + }, + "sensitivity": { + "status": "set", + "sensitivity": 2, + "sensitivity_max": 4 + }, + "type": "camera_motion" + } + ] +} diff --git a/bundles/org.openhab.binding.hue/src/test/resources/contact.json b/bundles/org.openhab.binding.hue/src/test/resources/contact.json new file mode 100644 index 0000000000000..6b7af5b44a0e1 --- /dev/null +++ b/bundles/org.openhab.binding.hue/src/test/resources/contact.json @@ -0,0 +1,19 @@ +{ + "errors": [ + ], + "data": [ + { + "id": "bcaee909-1b37-454b-814d-9928776ad350", + "owner": { + "rid": "faac7940-a303-4e8e-9f06-075fffb7229c", + "rtype": "device" + }, + "enabled": true, + "contact_report": { + "changed": "2023-10-10T19:10:55.919Z", + "state": "contact" + }, + "type": "contact" + } + ] +} diff --git a/bundles/org.openhab.binding.hue/src/test/resources/tamper.json b/bundles/org.openhab.binding.hue/src/test/resources/tamper.json new file mode 100644 index 0000000000000..10af6dc915f98 --- /dev/null +++ b/bundles/org.openhab.binding.hue/src/test/resources/tamper.json @@ -0,0 +1,31 @@ +{ + "errors": [ + ], + "data": [ + { + "id": "6c2ef541-fe03-4cae-ac60-3edcaa93b33e", + "owner": { + "rid": "faac7940-a303-4e8e-9f06-075fffb7229c", + "rtype": "device" + }, + "tamper_reports": [ + { + "changed": "1970-01-01T00:00:00.000Z", + "source": "battery_door", + "state": "not_tampered" + }, + { + "changed": "2023-01-01T00:00:00.001Z", + "source": "battery_door", + "state": "not_tampered" + }, + { + "changed": "2023-01-01T00:00:00.000Z", + "source": "battery_door", + "state": "tampered" + } + ], + "type": "tamper" + } + ] +}