]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hue] Add channels for time of last sensor update (API v2) (#15552)
authorJacob Laursen <jacob-github@vindvejr.dk>
Thu, 26 Oct 2023 21:52:00 +0000 (23:52 +0200)
committerGitHub <noreply@github.com>
Thu, 26 Oct 2023 21:52:00 +0000 (23:52 +0200)
* Add channels for last motion/temperature sensor update (API v2)
* Add channel for last light level sensor update (API v2)
* Add channel for last rotary steps update (API v2)
* Add channel for last button update (API v2)

Resolves #15546

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
31 files changed:
bundles/org.openhab.binding.hue/doc/readme_v2.md
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueBindingConstants.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/connection/Clip2Bridge.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Button.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ButtonReport.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/LightLevel.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/LightLevelReport.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Motion.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/MotionReport.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/RelativeRotary.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Resource.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/RotaryReport.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/Temperature.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TemperatureReport.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/factory/HueThingHandlerFactory.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/Clip2ThingHandler.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/serialization/InstantDeserializer.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties
bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Clip2Thing.xml
bundles/org.openhab.binding.hue/src/main/resources/OH-INF/update/instructions.xml [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/clip2/Clip2DtoTest.java
bundles/org.openhab.binding.hue/src/test/resources/button.json
bundles/org.openhab.binding.hue/src/test/resources/button_deprecated.json [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/test/resources/light_level.json
bundles/org.openhab.binding.hue/src/test/resources/light_level_deprecated.json [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/test/resources/motion.json
bundles/org.openhab.binding.hue/src/test/resources/motion_deprecated.json [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/test/resources/relative_rotary.json
bundles/org.openhab.binding.hue/src/test/resources/relative_rotary_deprecated.json [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/test/resources/temperature.json
bundles/org.openhab.binding.hue/src/test/resources/temperature_deprecated.json [new file with mode: 0644]

index 5041b89b91b4923f948e8e660aef74c6f38f5c7a..206bc476a82d2ea17639a51475a00f298514b53f 100644 (file)
@@ -59,30 +59,35 @@ 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)                                              |
-| rotary-steps          | (String)           | Informs about the number of rotary steps of the last rotary dial movement. (Trigger Channel)                        |
-| motion                | Switch             | Shows if motion has been detected by the sensor. (Read Only)                                                        |
-| motion-enabled        | Switch             | Supports enabling / disabling the motion sensor. (Advanced)                                                         |
-| light-level           | Number:Illuminance | Shows the current light level measured by the sensor. (Read Only)                                                   |
-| 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-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.  |
 
 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.
index 83c6ac420d1c35aeea75578370b9eebe27adfc74..829b3464b9d59f5045fb4f4a083e8f117834feaf 100644 (file)
@@ -151,12 +151,17 @@ public class HueBindingConstants {
     public static final String CHANNEL_2_ALERT = CHANNEL_ALERT;
     public static final String CHANNEL_2_EFFECT = CHANNEL_EFFECT;
     public static final String CHANNEL_2_BUTTON_LAST_EVENT = "button-last-event";
+    public static final String CHANNEL_2_BUTTON_LAST_UPDATED = "button-last-updated";
     public static final String CHANNEL_2_ROTARY_STEPS = "rotary-steps";
+    public static final String CHANNEL_2_ROTARY_STEPS_LAST_UPDATED = "rotary-steps-last-updated";
     public static final String CHANNEL_2_MOTION = "motion";
+    public static final String CHANNEL_2_MOTION_LAST_UPDATED = "motion-last-updated";
     public static final String CHANNEL_2_MOTION_ENABLED = "motion-enabled";
     public static final String CHANNEL_2_LIGHT_LEVEL = "light-level";
+    public static final String CHANNEL_2_LIGHT_LEVEL_LAST_UPDATED = "light-level-last-updated";
     public static final String CHANNEL_2_LIGHT_LEVEL_ENABLED = "light-level-enabled";
     public static final String CHANNEL_2_TEMPERATURE = CHANNEL_TEMPERATURE;
+    public static final String CHANNEL_2_TEMPERATURE_LAST_UPDATED = "temperature-last-updated";
     public static final String CHANNEL_2_TEMPERATURE_ENABLED = "temperature-enabled";
     public static final String CHANNEL_2_BATTERY_LEVEL = "battery-level";
     public static final String CHANNEL_2_BATTERY_LOW = "battery-low";
index dc60d6e1827d0e5fd0f498fc2c332cd2c46284b2..ad76b049d25fac7d7cf6ab87275ca1cd175a3c1f 100644 (file)
@@ -81,12 +81,14 @@ import org.openhab.binding.hue.internal.dto.clip2.enums.ResourceType;
 import org.openhab.binding.hue.internal.exceptions.ApiException;
 import org.openhab.binding.hue.internal.exceptions.HttpUnauthorizedException;
 import org.openhab.binding.hue.internal.handler.Clip2BridgeHandler;
+import org.openhab.binding.hue.internal.serialization.InstantDeserializer;
 import org.openhab.core.io.net.http.HttpClientFactory;
 import org.openhab.core.io.net.http.HttpUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParseException;
@@ -556,7 +558,8 @@ public class Clip2Bridge implements Closeable {
     private final String registrationUrl;
     private final String applicationKey;
     private final Clip2BridgeHandler bridgeHandler;
-    private final Gson jsonParser = new Gson();
+    private final Gson jsonParser = new GsonBuilder().registerTypeAdapter(Instant.class, new InstantDeserializer())
+            .create();
     private final Semaphore streamMutex = new Semaphore(MAX_CONCURRENT_STREAMS, true); // i.e. fair
     private final ReadWriteLock sessionUseCreateLock = new ReentrantReadWriteLock(true); // i.e. fair
     private final Map<Integer, Future<?>> fatalErrorTasks = new ConcurrentHashMap<>();
index b6688da2d5b73d35bba1cc3dcbd82c0f52080b10..c4f75f67304329d9c1623b9209d6c3bd42d56884 100644 (file)
@@ -12,8 +12,6 @@
  */
 package org.openhab.binding.hue.internal.dto.clip2;
 
-import java.util.Objects;
-
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.hue.internal.dto.clip2.enums.ButtonEventType;
@@ -28,16 +26,29 @@ import com.google.gson.annotations.SerializedName;
 @NonNullByDefault
 public class Button {
     private @Nullable @SerializedName("last_event") String lastEvent;
+    private @Nullable @SerializedName("button_report") ButtonReport buttonReport;
+    private @SerializedName("repeat_interval") int repeatInterval;
 
     /**
-     * @return the last button event as an enum.
-     * @throws IllegalArgumentException if lastEvent is null or bad.
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Moved to button_report/event
+     *
+     * @return the last button event as an enum (null if none or invalid).
      */
-    public ButtonEventType getLastEvent() throws IllegalArgumentException {
+    public @Nullable ButtonEventType getLastEvent() {
         String lastEvent = this.lastEvent;
-        if (Objects.nonNull(lastEvent)) {
+        if (lastEvent == null) {
+            return null;
+        }
+
+        try {
             return ButtonEventType.valueOf(lastEvent.toUpperCase());
+        } catch (IllegalArgumentException e) {
+            return null;
         }
-        throw new IllegalArgumentException("lastEvent field is null");
+    }
+
+    public @Nullable ButtonReport getButtonReport() {
+        return buttonReport;
     }
 }
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ButtonReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/ButtonReport.java
new file mode 100644 (file)
index 0000000..947c028
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * 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.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.hue.internal.dto.clip2.enums.ButtonEventType;
+
+/**
+ * DTO for CLIP 2 button report.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class ButtonReport {
+    private @NonNullByDefault({}) Instant updated;
+    private @Nullable String event;
+
+    /**
+     * @return last time the value of this property is updated.
+     */
+    public Instant getLastChanged() {
+        return updated;
+    }
+
+    /**
+     * @return event which can be sent by a button control (null if none or invalid).
+     */
+    public @Nullable ButtonEventType getLastEvent() {
+        String event = this.event;
+        if (event == null) {
+            return null;
+        }
+
+        try {
+            return ButtonEventType.valueOf(event.toUpperCase());
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+}
index 1c975bedb7eaa864e44c5e983d8c14b7ffa2e218..9921fba9790e79d89eda5bc8f4aac612b470d147 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.hue.internal.dto.clip2;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.Units;
@@ -30,11 +31,22 @@ import com.google.gson.annotations.SerializedName;
 public class LightLevel {
     private @SerializedName("light_level") int lightLevel;
     private @SerializedName("light_level_valid") boolean lightLevelValid;
+    private @Nullable @SerializedName("light_level_report") LightLevelReport lightLevelReport;
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Moved to light_level_report/light_level
+     * Should be used only as fallback for older firmwares.
+     */
     public int getLightLevel() {
         return lightLevel;
     }
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Indication whether the value presented in light_level is valid
+     * Should be used only as fallback for older firmwares.
+     */
     public boolean isLightLevelValid() {
         return lightLevelValid;
     }
@@ -56,4 +68,8 @@ public class LightLevel {
     public State isLightLevelValidState() {
         return OnOffType.from(lightLevelValid);
     }
+
+    public @Nullable LightLevelReport getLightLevelReport() {
+        return lightLevelReport;
+    }
 }
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/LightLevelReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/LightLevelReport.java
new file mode 100644 (file)
index 0000000..189c64f
--- /dev/null
@@ -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 com.google.gson.annotations.SerializedName;
+
+/**
+ * DTO for CLIP 2 light level sensor report.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class LightLevelReport {
+    private @NonNullByDefault({}) Instant changed;
+    private @SerializedName("light_level") int lightLevel;
+
+    /**
+     * @return last time the value of this property is changed.
+     */
+    public Instant getLastChanged() {
+        return changed;
+    }
+
+    /**
+     * Light level in 10000*log10(lux) +1 measured by sensor.
+     * Logarithmic scale used because the human eye adjusts to light levels and small changes at low lux levels
+     * are more noticeable than at high lux levels. This allows use of linear scale configuration sliders.
+     *
+     * @return light level in 10000*log10(lux) +1 measured by sensor
+     */
+    public int getLightLevel() {
+        return lightLevel;
+    }
+}
index a669af0281a5e3c1b2ca4394595a3936c69c57e3..3b0ce60c89f069b75d7daacb68e4d4adbfbc4773 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.hue.internal.dto.clip2;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.types.State;
 import org.openhab.core.types.UnDefType;
@@ -28,11 +29,24 @@ import com.google.gson.annotations.SerializedName;
 public class Motion {
     private boolean motion;
     private @SerializedName("motion_valid") boolean motionValid;
+    private @Nullable @SerializedName("motion_report") MotionReport motionReport;
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Moved to motion_report/motion.
+     * Should be used only as fallback for older firmwares.
+     *
+     * @return true if motion is detected
+     */
     public boolean isMotion() {
         return motion;
     }
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Motion is valid when motion_report property is present, invalid when absent.
+     * Should be used only as fallback for older firmwares.
+     */
     public boolean isMotionValid() {
         return motionValid;
     }
@@ -44,4 +58,8 @@ public class Motion {
     public State getMotionValidState() {
         return OnOffType.from(motionValid);
     }
+
+    public @Nullable MotionReport getMotionReport() {
+        return motionReport;
+    }
 }
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/MotionReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/MotionReport.java
new file mode 100644 (file)
index 0000000..8146e52
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * 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;
+
+/**
+ * DTO for CLIP 2 motion sensor report.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class MotionReport {
+    private @NonNullByDefault({}) Instant changed;
+    private boolean motion;
+
+    /**
+     * @return last time the value of this property is changed.
+     */
+    public Instant getLastChanged() {
+        return changed;
+    }
+
+    /**
+     * @return true if motion is detected
+     */
+    public boolean isMotion() {
+        return motion;
+    }
+}
index d6e6c62c36d06962fe6fb5ebebbc098083562575..3de553a83fbf46cbe6dde9cbe937a9db223fc338 100644 (file)
@@ -29,18 +29,33 @@ import com.google.gson.annotations.SerializedName;
 @NonNullByDefault
 public class RelativeRotary {
     private @Nullable @SerializedName("last_event") RotationEvent lastEvent;
+    private @Nullable @SerializedName("rotary_report") RotaryReport rotaryReport;
 
     public State getActionState() {
         RotationEvent lastEvent = getLastEvent();
         return Objects.nonNull(lastEvent) ? lastEvent.getActionState() : UnDefType.NULL;
     }
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Renamed to RelativeRotaryReport. Indicate which type of rotary event is received.
+     * Should be used only as fallback for older firmwares.
+     */
     public @Nullable RotationEvent getLastEvent() {
         return lastEvent;
     }
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Renamed to RelativeRotaryReport.
+     * Should be used only as fallback for older firmwares.
+     */
     public State getStepsState() {
         RotationEvent lastEvent = getLastEvent();
         return Objects.nonNull(lastEvent) ? lastEvent.getStepsState() : UnDefType.NULL;
     }
+
+    public @Nullable RotaryReport getRotaryReport() {
+        return rotaryReport;
+    }
 }
index b749da3c9bd706e8893b37022d7be56ca872a6a0..41fcae3a6cb6d78539d1f3eb1cda41c605a3e66e 100644 (file)
@@ -16,6 +16,9 @@ import java.math.BigDecimal;
 import java.math.MathContext;
 import java.math.RoundingMode;
 import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -24,6 +27,7 @@ import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 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.EffectType;
 import org.openhab.binding.hue.internal.dto.clip2.enums.ResourceType;
 import org.openhab.binding.hue.internal.dto.clip2.enums.SceneRecallAction;
@@ -31,12 +35,15 @@ 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.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.PercentType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.State;
 import org.openhab.core.types.UnDefType;
@@ -189,15 +196,36 @@ public class Resource {
      */
     public State getButtonEventState(Map<String, Integer> controlIds) {
         Button button = this.button;
-        if (Objects.nonNull(button)) {
-            try {
-                return new DecimalType(
-                        (controlIds.getOrDefault(getId(), 0).intValue() * 1000) + button.getLastEvent().ordinal());
-            } catch (IllegalArgumentException e) {
-                // fall through
-            }
+        if (button == null) {
+            return UnDefType.NULL;
         }
-        return UnDefType.NULL;
+        ButtonEventType event;
+        ButtonReport buttonReport = button.getButtonReport();
+        if (buttonReport == null) {
+            event = button.getLastEvent();
+        } else {
+            event = buttonReport.getLastEvent();
+        }
+        if (event == null) {
+            return UnDefType.NULL;
+        }
+        return new DecimalType((controlIds.getOrDefault(getId(), 0).intValue() * 1000) + event.ordinal());
+    }
+
+    public State getButtonLastUpdatedState(ZoneId zoneId) {
+        Button button = this.button;
+        if (button == null) {
+            return UnDefType.NULL;
+        }
+        ButtonReport buttonReport = button.getButtonReport();
+        if (buttonReport == null) {
+            return UnDefType.UNDEF;
+        }
+        Instant lastChanged = buttonReport.getLastChanged();
+        if (Instant.EPOCH.equals(lastChanged)) {
+            return UnDefType.UNDEF;
+        }
+        return new DateTimeType(ZonedDateTime.ofInstant(lastChanged, zoneId));
     }
 
     public List<ResourceReference> getChildren() {
@@ -386,8 +414,31 @@ public class Resource {
     }
 
     public State getLightLevelState() {
-        LightLevel light = this.light;
-        return Objects.nonNull(light) ? light.getLightLevelState() : UnDefType.NULL;
+        LightLevel lightLevel = this.light;
+        if (lightLevel == null) {
+            return UnDefType.NULL;
+        }
+        LightLevelReport lightLevelReport = lightLevel.getLightLevelReport();
+        if (lightLevelReport == null) {
+            return lightLevel.getLightLevelState();
+        }
+        return new QuantityType<>(Math.pow(10f, (double) lightLevelReport.getLightLevel() / 10000f) - 1f, Units.LUX);
+    }
+
+    public State getLightLevelLastUpdatedState(ZoneId zoneId) {
+        LightLevel lightLevel = this.light;
+        if (lightLevel == null) {
+            return UnDefType.NULL;
+        }
+        LightLevelReport lightLevelReport = lightLevel.getLightLevelReport();
+        if (lightLevelReport == null) {
+            return UnDefType.UNDEF;
+        }
+        Instant lastChanged = lightLevelReport.getLastChanged();
+        if (Instant.EPOCH.equals(lastChanged)) {
+            return UnDefType.UNDEF;
+        }
+        return new DateTimeType(ZonedDateTime.ofInstant(lastChanged, zoneId));
     }
 
     public @Nullable MetaData getMetaData() {
@@ -410,7 +461,30 @@ public class Resource {
 
     public State getMotionState() {
         Motion motion = this.motion;
-        return Objects.nonNull(motion) ? motion.getMotionState() : UnDefType.NULL;
+        if (motion == null) {
+            return UnDefType.NULL;
+        }
+        MotionReport motionReport = motion.getMotionReport();
+        if (motionReport == null) {
+            return motion.getMotionState();
+        }
+        return OnOffType.from(motionReport.isMotion());
+    }
+
+    public State getMotionLastUpdatedState(ZoneId zoneId) {
+        Motion motion = this.motion;
+        if (motion == null) {
+            return UnDefType.NULL;
+        }
+        MotionReport motionReport = motion.getMotionReport();
+        if (motionReport == null) {
+            return UnDefType.UNDEF;
+        }
+        Instant lastChanged = motionReport.getLastChanged();
+        if (Instant.EPOCH.equals(lastChanged)) {
+            return UnDefType.UNDEF;
+        }
+        return new DateTimeType(ZonedDateTime.ofInstant(lastChanged, zoneId));
     }
 
     public State getMotionValidState() {
@@ -473,14 +547,36 @@ public class Resource {
         return relativeRotary;
     }
 
-    public State getRelativeRotaryActionState() {
+    public State getRotaryStepsState() {
         RelativeRotary relativeRotary = this.relativeRotary;
-        return Objects.nonNull(relativeRotary) ? relativeRotary.getActionState() : UnDefType.NULL;
+        if (relativeRotary == null) {
+            return UnDefType.NULL;
+        }
+        RotaryReport rotaryReport = relativeRotary.getRotaryReport();
+        if (rotaryReport == null) {
+            return relativeRotary.getStepsState();
+        }
+        Rotation rotation = rotaryReport.getRotation();
+        if (rotation == null) {
+            return UnDefType.NULL;
+        }
+        return rotation.getStepsState();
     }
 
-    public State getRotaryStepsState() {
+    public State getRotaryStepsLastUpdatedState(ZoneId zoneId) {
         RelativeRotary relativeRotary = this.relativeRotary;
-        return Objects.nonNull(relativeRotary) ? relativeRotary.getStepsState() : UnDefType.NULL;
+        if (relativeRotary == null) {
+            return UnDefType.NULL;
+        }
+        RotaryReport rotaryReport = relativeRotary.getRotaryReport();
+        if (rotaryReport == null) {
+            return UnDefType.UNDEF;
+        }
+        Instant lastChanged = rotaryReport.getLastChanged();
+        if (Instant.EPOCH.equals(lastChanged)) {
+            return UnDefType.UNDEF;
+        }
+        return new DateTimeType(ZonedDateTime.ofInstant(lastChanged, zoneId));
     }
 
     /**
@@ -559,7 +655,30 @@ public class Resource {
 
     public State getTemperatureState() {
         Temperature temperature = this.temperature;
-        return Objects.nonNull(temperature) ? temperature.getTemperatureState() : UnDefType.NULL;
+        if (temperature == null) {
+            return UnDefType.NULL;
+        }
+        TemperatureReport temperatureReport = temperature.getTemperatureReport();
+        if (temperatureReport == null) {
+            return temperature.getTemperatureState();
+        }
+        return new QuantityType<>(temperatureReport.getTemperature(), SIUnits.CELSIUS);
+    }
+
+    public State getTemperatureLastUpdatedState(ZoneId zoneId) {
+        Temperature temperature = this.temperature;
+        if (temperature == null) {
+            return UnDefType.NULL;
+        }
+        TemperatureReport temperatureReport = temperature.getTemperatureReport();
+        if (temperatureReport == null) {
+            return UnDefType.UNDEF;
+        }
+        Instant lastChanged = temperatureReport.getLastChanged();
+        if (Instant.EPOCH.equals(lastChanged)) {
+            return UnDefType.UNDEF;
+        }
+        return new DateTimeType(ZonedDateTime.ofInstant(lastChanged, zoneId));
     }
 
     public State getTemperatureValidState() {
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/RotaryReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/RotaryReport.java
new file mode 100644 (file)
index 0000000..3d2159a
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * 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.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.hue.internal.dto.clip2.enums.RotationEventType;
+
+/**
+ * DTO for CLIP 2 relative rotary report.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class RotaryReport {
+    private @NonNullByDefault({}) Instant updated;
+    private @Nullable String action;
+    private @Nullable Rotation rotation;
+
+    /**
+     * @return last time the value of this property is changed.
+     */
+    public Instant getLastChanged() {
+        return updated;
+    }
+
+    /**
+     * @return which type of rotary event is received
+     */
+    public @Nullable RotationEventType getAction() {
+        String action = this.action;
+        return action == null ? null : RotationEventType.valueOf(action.toUpperCase());
+    }
+
+    public @Nullable Rotation getRotation() {
+        return rotation;
+    }
+}
index 8f25c2b08a4037dfeff1fa2b4daf2a1d676acbfc..401476a70a798c1c4e7cb9b71b8192fa2fa000cb 100644 (file)
@@ -13,6 +13,7 @@
 package org.openhab.binding.hue.internal.dto.clip2;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.SIUnits;
@@ -30,11 +31,24 @@ import com.google.gson.annotations.SerializedName;
 public class Temperature {
     private float temperature;
     private @SerializedName("temperature_valid") boolean temperatureValid;
+    private @Nullable @SerializedName("temperature_report") TemperatureReport temperatureReport;
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Moved to temperature_report/temperature.
+     * Should be used only as fallback for older firmwares.
+     *
+     * @return temperature in 1.00 degrees Celsius
+     */
     public float getTemperature() {
         return temperature;
     }
 
+    /**
+     * The underlying field is deprecated in the CLIP 2 API.
+     * Indication whether the value presented in temperature is valid
+     * Should be used only as fallback for older firmwares.
+     */
     public boolean isTemperatureValid() {
         return temperatureValid;
     }
@@ -46,4 +60,8 @@ public class Temperature {
     public State getTemperatureValidState() {
         return OnOffType.from(temperatureValid);
     }
+
+    public @Nullable TemperatureReport getTemperatureReport() {
+        return temperatureReport;
+    }
 }
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TemperatureReport.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/dto/clip2/TemperatureReport.java
new file mode 100644 (file)
index 0000000..1833dac
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * 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;
+
+/**
+ * DTO for CLIP 2 temperature sensor report.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class TemperatureReport {
+    private @NonNullByDefault({}) Instant changed;
+    private float temperature;
+
+    /**
+     * @return last time the value of this property is changed.
+     */
+    public Instant getLastChanged() {
+        return changed;
+    }
+
+    /**
+     * @return temperature in 1.00 degrees Celsius
+     */
+    public float getTemperature() {
+        return temperature;
+    }
+}
index 64f06484026e0e5870bdda6a2ea3cc6bd579d850..13583c830635027bfffb1c8da17aac490eee6214 100644 (file)
@@ -37,6 +37,7 @@ import org.openhab.binding.hue.internal.handler.sensors.TapSwitchHandler;
 import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
 import org.openhab.core.config.core.Configuration;
 import org.openhab.core.i18n.LocaleProvider;
+import org.openhab.core.i18n.TimeZoneProvider;
 import org.openhab.core.i18n.TranslationProvider;
 import org.openhab.core.io.net.http.HttpClientFactory;
 import org.openhab.core.thing.Bridge;
@@ -82,6 +83,7 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
     private final Clip2StateDescriptionProvider clip2StateDescriptionProvider;
     private final TranslationProvider i18nProvider;
     private final LocaleProvider localeProvider;
+    private final TimeZoneProvider timeZoneProvider;
     private final ThingRegistry thingRegistry;
     private final ItemChannelLinkRegistry itemChannelLinkRegistry;
 
@@ -90,13 +92,14 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
             final @Reference HueStateDescriptionProvider stateDescriptionProvider,
             final @Reference Clip2StateDescriptionProvider clip2StateDescriptionProvider,
             final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
-            final @Reference ThingRegistry thingRegistry,
+            final @Reference TimeZoneProvider timeZoneProvider, final @Reference ThingRegistry thingRegistry,
             final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry) {
         this.httpClientFactory = httpClientFactory;
         this.stateDescriptionProvider = stateDescriptionProvider;
         this.clip2StateDescriptionProvider = clip2StateDescriptionProvider;
         this.i18nProvider = i18nProvider;
         this.localeProvider = localeProvider;
+        this.timeZoneProvider = timeZoneProvider;
         this.thingRegistry = thingRegistry;
         this.itemChannelLinkRegistry = itemChannelLinkRegistry;
     }
@@ -184,7 +187,8 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
             return new Clip2BridgeHandler((Bridge) thing, httpClientFactory, thingRegistry, localeProvider,
                     i18nProvider);
         } else if (Clip2ThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
-            return new Clip2ThingHandler(thing, clip2StateDescriptionProvider, thingRegistry, itemChannelLinkRegistry);
+            return new Clip2ThingHandler(thing, clip2StateDescriptionProvider, timeZoneProvider, thingRegistry,
+                    itemChannelLinkRegistry);
         } else if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
             return new HueBridgeHandler((Bridge) thing, httpClientFactory.getCommonHttpClient(),
                     stateDescriptionProvider, i18nProvider, localeProvider);
index bab93b79beba0ea2a44dea6984d4138d536b8c8a..1f2c3a7292e107663dadada4ba76b0b638adbbb2 100644 (file)
@@ -57,6 +57,7 @@ import org.openhab.binding.hue.internal.dto.clip2.enums.ZigbeeStatus;
 import org.openhab.binding.hue.internal.dto.clip2.helper.Setters;
 import org.openhab.binding.hue.internal.exceptions.ApiException;
 import org.openhab.binding.hue.internal.exceptions.AssetNotLoadedException;
+import org.openhab.core.i18n.TimeZoneProvider;
 import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.HSBType;
@@ -160,11 +161,13 @@ public class Clip2ThingHandler extends BaseThingHandler {
     private final ThingRegistry thingRegistry;
     private final ItemChannelLinkRegistry itemChannelLinkRegistry;
     private final Clip2StateDescriptionProvider stateDescriptionProvider;
+    private final TimeZoneProvider timeZoneProvider;
 
     private String resourceId = "?";
     private Resource thisResource;
     private Duration dynamicsDuration = Duration.ZERO;
     private Instant dynamicsExpireTime = Instant.MIN;
+    private Instant buttonGroupLastUpdated = Instant.MIN;
 
     private boolean disposing;
     private boolean hasConnectivityIssue;
@@ -180,7 +183,8 @@ public class Clip2ThingHandler extends BaseThingHandler {
     private @Nullable Future<?> updateServiceContributorsTask;
 
     public Clip2ThingHandler(Thing thing, Clip2StateDescriptionProvider stateDescriptionProvider,
-            ThingRegistry thingRegistry, ItemChannelLinkRegistry itemChannelLinkRegistry) {
+            TimeZoneProvider timeZoneProvider, ThingRegistry thingRegistry,
+            ItemChannelLinkRegistry itemChannelLinkRegistry) {
         super(thing);
 
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
@@ -197,6 +201,7 @@ public class Clip2ThingHandler extends BaseThingHandler {
         this.thingRegistry = thingRegistry;
         this.itemChannelLinkRegistry = itemChannelLinkRegistry;
         this.stateDescriptionProvider = stateDescriptionProvider;
+        this.timeZoneProvider = timeZoneProvider;
     }
 
     /**
@@ -829,11 +834,23 @@ public class Clip2ThingHandler extends BaseThingHandler {
             case BUTTON:
                 if (fullUpdate) {
                     addSupportedChannel(CHANNEL_2_BUTTON_LAST_EVENT);
+                    addSupportedChannel(CHANNEL_2_BUTTON_LAST_UPDATED);
                     controlIds.put(resource.getId(), resource.getControlId());
                 } else {
                     State buttonState = resource.getButtonEventState(controlIds);
                     updateState(CHANNEL_2_BUTTON_LAST_EVENT, buttonState, fullUpdate);
                 }
+                // Update channel from timestamp if last button pressed.
+                State buttonLastUpdatedState = resource.getButtonLastUpdatedState(timeZoneProvider.getTimeZone());
+                if (buttonLastUpdatedState instanceof DateTimeType) {
+                    Instant buttonLastUpdatedInstant = ((DateTimeType) buttonLastUpdatedState).getInstant();
+                    if (buttonLastUpdatedInstant.isAfter(buttonGroupLastUpdated)) {
+                        updateState(CHANNEL_2_BUTTON_LAST_UPDATED, buttonLastUpdatedState, fullUpdate);
+                        buttonGroupLastUpdated = buttonLastUpdatedInstant;
+                    }
+                } else if (Instant.MIN.equals(buttonGroupLastUpdated)) {
+                    updateState(CHANNEL_2_BUTTON_LAST_UPDATED, buttonLastUpdatedState, fullUpdate);
+                }
                 break;
 
             case DEVICE_POWER:
@@ -865,24 +882,33 @@ public class Clip2ThingHandler extends BaseThingHandler {
 
             case LIGHT_LEVEL:
                 updateState(CHANNEL_2_LIGHT_LEVEL, resource.getLightLevelState(), fullUpdate);
+                updateState(CHANNEL_2_LIGHT_LEVEL_LAST_UPDATED,
+                        resource.getLightLevelLastUpdatedState(timeZoneProvider.getTimeZone()), fullUpdate);
                 updateState(CHANNEL_2_LIGHT_LEVEL_ENABLED, resource.getEnabledState(), fullUpdate);
                 break;
 
             case MOTION:
                 updateState(CHANNEL_2_MOTION, resource.getMotionState(), fullUpdate);
+                updateState(CHANNEL_2_MOTION_LAST_UPDATED,
+                        resource.getMotionLastUpdatedState(timeZoneProvider.getTimeZone()), fullUpdate);
                 updateState(CHANNEL_2_MOTION_ENABLED, resource.getEnabledState(), fullUpdate);
                 break;
 
             case RELATIVE_ROTARY:
                 if (fullUpdate) {
                     addSupportedChannel(CHANNEL_2_ROTARY_STEPS);
+                    addSupportedChannel(CHANNEL_2_ROTARY_STEPS_LAST_UPDATED);
                 } else {
                     updateState(CHANNEL_2_ROTARY_STEPS, resource.getRotaryStepsState(), fullUpdate);
                 }
+                updateState(CHANNEL_2_ROTARY_STEPS_LAST_UPDATED,
+                        resource.getRotaryStepsLastUpdatedState(timeZoneProvider.getTimeZone()), fullUpdate);
                 break;
 
             case TEMPERATURE:
                 updateState(CHANNEL_2_TEMPERATURE, resource.getTemperatureState(), fullUpdate);
+                updateState(CHANNEL_2_TEMPERATURE_LAST_UPDATED,
+                        resource.getTemperatureLastUpdatedState(timeZoneProvider.getTimeZone()), fullUpdate);
                 updateState(CHANNEL_2_TEMPERATURE_ENABLED, resource.getEnabledState(), fullUpdate);
                 break;
 
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/serialization/InstantDeserializer.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/serialization/InstantDeserializer.java
new file mode 100644 (file)
index 0000000..1843c3c
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * 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.serialization;
+
+import java.lang.reflect.Type;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+
+/**
+ * The {@link InstantDeserializer} converts a formatted UTC string to {@link Instant}.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class InstantDeserializer implements JsonDeserializer<Instant> {
+
+    @Override
+    public @Nullable Instant deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2)
+            throws JsonParseException {
+        String content = element.getAsString();
+        try {
+            return Instant.parse(content);
+        } catch (DateTimeParseException e) {
+            throw new JsonParseException("Could not parse as Instant: " + content, e);
+        }
+    }
+}
index b79fd4ddbd2ac5064b263662ef3f3223374a5456..d8b6dd1b38b343ba7d3656ef5463a489d68d7247 100644 (file)
@@ -40,16 +40,26 @@ thing-type.hue.bridge.description = The Hue Bridge represents the Philips Hue Br
 thing-type.hue.device.label = Hue Device
 thing-type.hue.device.description = A Hue API v2 device with channels depending on its actual capabilities.
 thing-type.hue.device.channel.alert.description = Activate the alert for the light.
+thing-type.hue.device.channel.button-last-updated.label = Button Last Updated
+thing-type.hue.device.channel.button-last-updated.description = The date and time when a button was last pressed.
 thing-type.hue.device.channel.color-xy-only.description = Set the color xy parameter of the light without changing other state parameters.
 thing-type.hue.device.channel.dimming-only.description = Set the dimming parameter of the light without changing other state parameters.
 thing-type.hue.device.channel.effect.description = Activate the effect for the light.
 thing-type.hue.device.channel.light-level.description = Current light level.
 thing-type.hue.device.channel.light-level-enabled.description = Light level sensor enabled.
+thing-type.hue.device.channel.light-level-last-updated.label = Light Level Last Updated
+thing-type.hue.device.channel.light-level-last-updated.description = The date and time when the light level was last updated.
 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.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.
+thing-type.hue.device.channel.temperature-last-updated.label = Temperature Last Updated
+thing-type.hue.device.channel.temperature-last-updated.description = The date and time when the temperature was last updated.
 thing-type.hue.geofencesensor.label = Geofence Sensor
 thing-type.hue.geofencesensor.description = A sensor providing geofence based presence detection.
 thing-type.hue.group.label = Hue Group
index d6e768fad2397bd0959e943b1cec2545b7f5f289..03419d9a88ab1057dd3e72b4d9378cc9278fcb67 100644 (file)
                                <description>Activate the effect for the light.</description>
                        </channel>
                        <channel id="button-last-event" typeId="button-last-event"/>
+                       <channel id="button-last-updated" typeId="last-updated-v2">
+                               <label>Button Last Updated</label>
+                               <description>The date and time when a button was last pressed.</description>
+                       </channel>
                        <channel id="rotary-steps" typeId="rotary-steps"/>
+                       <channel id="rotary-steps-last-updated" typeId="last-updated-v2">
+                               <label>Rotary Steps Last Updated</label>
+                               <description>The date and time when the rotary steps were last updated.</description>
+                       </channel>
                        <channel id="motion" typeId="system.motion"/>
+                       <channel id="motion-last-updated" typeId="last-updated-v2">
+                               <label>Motion Last Updated</label>
+                               <description>The date and time when the motion value was last updated.</description>
+                       </channel>
                        <channel id="motion-enabled" typeId="sensor-enabled">
                                <description>Motion sensor enabled.</description>
                        </channel>
                        <channel id="light-level" typeId="illuminance">
                                <description>Current light level.</description>
                        </channel>
+                       <channel id="light-level-last-updated" typeId="last-updated-v2">
+                               <label>Light Level Last Updated</label>
+                               <description>The date and time when the light level was last updated.</description>
+                       </channel>
                        <channel id="light-level-enabled" typeId="sensor-enabled">
                                <description>Light level sensor enabled.</description>
                        </channel>
                                <label>Temperature</label>
                                <description>Temperature at the sensor location.</description>
                        </channel>
+                       <channel id="temperature-last-updated" typeId="last-updated-v2">
+                               <label>Temperature Last Updated</label>
+                               <description>The date and time when the temperature was last updated.</description>
+                       </channel>
                        <channel id="temperature-enabled" typeId="sensor-enabled">
                                <description>Temperature sensor enabled.</description>
                        </channel>
                        </channel>
                </channels>
 
+               <properties>
+                       <property name="thingTypeVersion">1</property>
+               </properties>
+
                <representation-property>resourceId</representation-property>
 
                <config-description>
diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/update/instructions.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/update/instructions.xml
new file mode 100644 (file)
index 0000000..4e851e9
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
+
+       <thing-type uid="hue:device">
+
+               <instruction-set targetVersion="1">
+                       <add-channel id="motion-last-updated">
+                               <type>hue:last-updated-v2</type>
+                               <label>Motion Last Updated</label>
+                               <description>The date and time when the motion value was last updated.</description>
+                       </add-channel>
+                       <add-channel id="temperature-last-updated">
+                               <type>hue:last-updated-v2</type>
+                               <label>Temperature Last Updated</label>
+                               <description>The date and time when the temperature was last updated.</description>
+                       </add-channel>
+                       <add-channel id="light-level-last-updated">
+                               <type>hue:last-updated-v2</type>
+                               <label>Light Level Last Updated</label>
+                               <description>The date and time when the light level was last updated.</description>
+                       </add-channel>
+                       <add-channel id="button-last-updated">
+                               <type>hue:last-updated-v2</type>
+                               <label>Button Last Updated</label>
+                               <description>The date and time when a button was last pressed.</description>
+                       </add-channel>
+                       <add-channel id="rotary-steps-last-updated">
+                               <type>hue:last-updated-v2</type>
+                               <label>Rotary Steps Last Updated</label>
+                               <description>The date and time when the rotary steps were last updated.</description>
+                       </add-channel>
+               </instruction-set>
+
+       </thing-type>
+
+</update:update-descriptions>
index 05a3ffed8864e947321609eae7e16d9f51012fe7..059a06ba0459a76384c84df47a20fe4d310de3e1 100644 (file)
@@ -19,7 +19,10 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneId;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 
@@ -55,6 +58,8 @@ import org.openhab.binding.hue.internal.dto.clip2.enums.ResourceType;
 import org.openhab.binding.hue.internal.dto.clip2.enums.RotationEventType;
 import org.openhab.binding.hue.internal.dto.clip2.enums.ZigbeeStatus;
 import org.openhab.binding.hue.internal.dto.clip2.helper.Setters;
+import org.openhab.binding.hue.internal.serialization.InstantDeserializer;
+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;
@@ -66,6 +71,7 @@ import org.openhab.core.types.UnDefType;
 import org.openhab.core.util.ColorUtil;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
@@ -79,7 +85,8 @@ import com.google.gson.JsonSyntaxException;
 @NonNullByDefault
 class Clip2DtoTest {
 
-    private static final Gson GSON = new Gson();
+    private static final Gson GSON = new GsonBuilder().registerTypeAdapter(Instant.class, new InstantDeserializer())
+            .create();
     private static final Double MINIMUM_DIMMING_LEVEL = Double.valueOf(12.34f);
 
     /**
@@ -107,6 +114,24 @@ class Clip2DtoTest {
         assertNotNull(resources);
         List<Resource> list = resources.getResources();
         assertNotNull(list);
+        assertEquals(1, list.size());
+        Resource item = list.get(0);
+        assertEquals(ResourceType.BUTTON, item.getType());
+        Button button = item.getButton();
+        assertNotNull(button);
+        assertEquals(new DecimalType(2003),
+                item.getButtonEventState(Map.of("00000000-0000-0000-0000-000000000001", 2)));
+        assertEquals(new DateTimeType("2023-09-17T18:51:36.959+0000"),
+                item.getButtonLastUpdatedState(ZoneId.of("UTC")));
+    }
+
+    @Test
+    void testButtonDeprecated() {
+        String json = load(ResourceType.BUTTON.name().toLowerCase() + "_deprecated");
+        Resources resources = GSON.fromJson(json, Resources.class);
+        assertNotNull(resources);
+        List<Resource> list = resources.getResources();
+        assertNotNull(list);
         assertEquals(43, list.size());
         Resource item = list.get(0);
         assertEquals(ResourceType.BUTTON, item.getType());
@@ -317,6 +342,24 @@ class Clip2DtoTest {
         Boolean enabled = item.getEnabled();
         assertNotNull(enabled);
         assertTrue(enabled);
+        assertEquals(QuantityType.valueOf("1.2792921774337476 lx"), item.getLightLevelState());
+        assertEquals(new DateTimeType("2023-09-11T19:20:02.958+0000"),
+                item.getLightLevelLastUpdatedState(ZoneId.of("UTC")));
+    }
+
+    @Test
+    void testLightLevelDeprecated() {
+        String json = load(ResourceType.LIGHT_LEVEL.name().toLowerCase() + "_deprecated");
+        Resources resources = GSON.fromJson(json, Resources.class);
+        assertNotNull(resources);
+        List<Resource> list = resources.getResources();
+        assertNotNull(list);
+        assertEquals(1, list.size());
+        Resource item = list.get(0);
+        assertEquals(ResourceType.LIGHT_LEVEL, item.getType());
+        Boolean enabled = item.getEnabled();
+        assertNotNull(enabled);
+        assertTrue(enabled);
         LightLevel lightLevel = item.getLightLevel();
         assertNotNull(lightLevel);
         assertEquals(12725, lightLevel.getLightLevel());
@@ -324,8 +367,8 @@ class Clip2DtoTest {
     }
 
     @Test
-    void testRelativeRotary() {
-        String json = load(ResourceType.RELATIVE_ROTARY.name().toLowerCase());
+    void testRelativeRotaryDeprecated() {
+        String json = load(ResourceType.RELATIVE_ROTARY.name().toLowerCase() + "_deprecated");
         Resources resources = GSON.fromJson(json, Resources.class);
         assertNotNull(resources);
         List<Resource> list = resources.getResources();
@@ -493,6 +536,24 @@ class Clip2DtoTest {
         Boolean enabled = item.getEnabled();
         assertNotNull(enabled);
         assertTrue(enabled);
+        assertEquals(OnOffType.ON, item.getMotionState());
+        assertEquals(new DateTimeType("2023-09-04T20:04:30.395+0000"),
+                item.getMotionLastUpdatedState(ZoneId.of("UTC")));
+    }
+
+    @Test
+    void testSensor2MotionDeprecated() {
+        String json = load(ResourceType.MOTION.name().toLowerCase() + "_deprecated");
+        Resources resources = GSON.fromJson(json, Resources.class);
+        assertNotNull(resources);
+        List<Resource> list = resources.getResources();
+        assertNotNull(list);
+        assertEquals(1, list.size());
+        Resource item = list.get(0);
+        assertEquals(ResourceType.MOTION, item.getType());
+        Boolean enabled = item.getEnabled();
+        assertNotNull(enabled);
+        assertTrue(enabled);
         Motion motion = item.getMotion();
         assertNotNull(motion);
         assertTrue(motion.isMotion());
@@ -563,6 +624,27 @@ class Clip2DtoTest {
         assertEquals(1, list.size());
         Resource item = list.get(0);
         assertEquals(ResourceType.TEMPERATURE, item.getType());
+        Boolean enabled = item.getEnabled();
+        assertNotNull(enabled);
+        assertTrue(enabled);
+        assertEquals(QuantityType.valueOf("23.34 Â°C"), item.getTemperatureState());
+        assertEquals(new DateTimeType("2023-09-06T18:22:07.016+0000"),
+                item.getTemperatureLastUpdatedState(ZoneId.of("UTC")));
+    }
+
+    @Test
+    void testTemperatureDeprecated() {
+        String json = load(ResourceType.TEMPERATURE.name().toLowerCase() + "_deprecated");
+        Resources resources = GSON.fromJson(json, Resources.class);
+        assertNotNull(resources);
+        List<Resource> list = resources.getResources();
+        assertNotNull(list);
+        assertEquals(1, list.size());
+        Resource item = list.get(0);
+        assertEquals(ResourceType.TEMPERATURE, item.getType());
+        Boolean enabled = item.getEnabled();
+        assertNotNull(enabled);
+        assertTrue(enabled);
         Temperature temperature = item.getTemperature();
         assertNotNull(temperature);
         assertEquals(17.2, temperature.getTemperature(), 0.1);
index 6284e2e44a1d8ca17437e78c8998883ef4dd9194..228c169c686a9691f6e5fb9513d761daa70202c9 100644 (file)
 {
-       "errors": [],
-       "data": [
-               {
-                       "id": "d1ae958e-8908-449a-9897-7f10f9b8d4c2",
-                       "id_v1": "/sensors/110",
-                       "owner": {
-                               "rid": "112853f9-c4c4-4d65-ba96-b4c2ab26d94d",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "a83354b7-bae5-4618-8c8d-079c83e0ca2b",
-                       "id_v1": "/sensors/236",
-                       "owner": {
-                               "rid": "cfecbbd0-e918-42a2-b714-2bad33061d95",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "e20d90ae-b2d8-40ea-9905-66bcde9fd863",
-                       "id_v1": "/sensors/63",
-                       "owner": {
-                               "rid": "0e22f8de-eff5-440a-a9ed-06d547d125d7",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "4e61a948-22aa-4332-9b97-76245dd9fb87",
-                       "id_v1": "/sensors/6",
-                       "owner": {
-                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "2f78855c-717a-4b77-8513-dd68ca5337b8",
-                       "id_v1": "/sensors/6",
-                       "owner": {
-                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "7c495cbd-4dd1-4f22-950c-4dd6017b81ec",
-                       "id_v1": "/sensors/6",
-                       "owner": {
-                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "a15c9be9-14b9-4d98-8d9f-989d6cb54496",
-                       "id_v1": "/sensors/6",
-                       "owner": {
-                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "e1e6b2f9-3ace-41ae-b16c-e68f82b5a949",
-                       "id_v1": "/sensors/24",
-                       "owner": {
-                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "717c978e-383d-4900-ab2a-2685983f6174",
-                       "id_v1": "/sensors/24",
-                       "owner": {
-                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "0456ba22-2f1d-4375-8e33-31465420cd96",
-                       "id_v1": "/sensors/24",
-                       "owner": {
-                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "92c00fa4-ae65-462c-9130-a28f5bc52bd9",
-                       "id_v1": "/sensors/24",
-                       "owner": {
-                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "85c18ad0-297d-4fb9-a33a-37f2da70752d",
-                       "id_v1": "/sensors/118",
-                       "owner": {
-                               "rid": "a0509519-3ecb-47d0-9183-25db1e4ea2b2",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "79af0ff1-a4ed-476d-a381-eabd4d3ee6bd",
-                       "id_v1": "/sensors/135",
-                       "owner": {
-                               "rid": "8c5b05ba-b4f4-47b2-8ba0-fc44363192bc",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "8a16c730-094a-4aa1-abd8-9cb758468d62",
-                       "id_v1": "/sensors/8",
-                       "owner": {
-                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "3fed0654-68ec-43e1-b3db-f1a3eba076b9",
-                       "id_v1": "/sensors/8",
-                       "owner": {
-                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "df6e2ba8-94f4-43ce-9bec-72c252616062",
-                       "id_v1": "/sensors/8",
-                       "owner": {
-                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "a46f615d-6760-479c-ba6d-2837a18902e8",
-                       "id_v1": "/sensors/8",
-                       "owner": {
-                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "c34bb678-b910-4a06-8019-3e0ce922f17f",
-                       "id_v1": "/sensors/18",
-                       "owner": {
-                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "286b1b18-ff43-40be-a2ff-b1edc24ecb7c",
-                       "id_v1": "/sensors/18",
-                       "owner": {
-                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "2be1abd3-00a4-4985-b2c9-9bdd4cbe1e4b",
-                       "id_v1": "/sensors/18",
-                       "owner": {
-                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "dc9f1653-11a8-4794-b706-464cf53e9722",
-                       "id_v1": "/sensors/18",
-                       "owner": {
-                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "ac4ebfeb-2045-4698-96de-0b6b5421a1d8",
-                       "id_v1": "/sensors/4",
-                       "owner": {
-                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "8a5159f1-93de-4c07-9d32-1fe555fde285",
-                       "id_v1": "/sensors/4",
-                       "owner": {
-                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "14debc09-496e-4429-8c22-4975c135bbdf",
-                       "id_v1": "/sensors/4",
-                       "owner": {
-                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "9672e2a9-a3a9-4aec-b31e-f2338114b22b",
-                       "id_v1": "/sensors/4",
-                       "owner": {
-                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "f385a946-c638-4631-b6a6-c490cf809606",
-                       "id_v1": "/sensors/245",
-                       "owner": {
-                               "rid": "56b560bc-a127-4634-8d80-9946104a4028",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "ba204102-de9f-479e-818a-02ed880caac2",
-                       "id_v1": "/sensors/12",
-                       "owner": {
-                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "0032a38b-cf67-478f-934a-520a156a2baf",
-                       "id_v1": "/sensors/12",
-                       "owner": {
-                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "4ce58cbd-5d0f-45ec-920d-ad601fd9cc07",
-                       "id_v1": "/sensors/12",
-                       "owner": {
-                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "813a331a-f26a-4ab2-948c-9b4c398939d0",
-                       "id_v1": "/sensors/12",
-                       "owner": {
-                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "91ba8839-2bac-4175-9f8c-ed192842d549",
-                       "id_v1": "/sensors/20",
-                       "owner": {
-                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "f95addfc-2f7c-453f-924d-ba496e07e5f9",
-                       "id_v1": "/sensors/20",
-                       "owner": {
-                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "6615f1f1-f3f1-4a05-b8f7-581097458e34",
-                       "id_v1": "/sensors/20",
-                       "owner": {
-                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "b0d5a0af-31fd-4189-9150-c551ff9033d7",
-                       "id_v1": "/sensors/20",
-                       "owner": {
-                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "9d3820db-4a20-4925-80f6-c74582ffb871",
-                       "id_v1": "/sensors/26",
-                       "owner": {
-                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "a9e1a40b-a13d-4966-b0b1-2b0b5dfe1986",
-                       "id_v1": "/sensors/26",
-                       "owner": {
-                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "8ba063d7-df16-48f5-bb9b-f45849ec1bd3",
-                       "id_v1": "/sensors/26",
-                       "owner": {
-                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "4fc9dcd2-6f71-46c4-b3d0-5d7b496be6f9",
-                       "id_v1": "/sensors/26",
-                       "owner": {
-                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "824ea347-28d1-4e45-b886-1555a160190b",
-                       "id_v1": "/sensors/14",
-                       "owner": {
-                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "801ede68-21b0-4e6e-98be-eb1a60557ac6",
-                       "id_v1": "/sensors/14",
-                       "owner": {
-                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 2
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "1218d0c3-9a9c-4984-84a5-c12ad085ef2d",
-                       "id_v1": "/sensors/14",
-                       "owner": {
-                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 3
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "eb2c07bc-1d09-4096-a044-dec29b40619a",
-                       "id_v1": "/sensors/14",
-                       "owner": {
-                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 4
-                       },
-                       "type": "button"
-               },
-               {
-                       "id": "6bae5b99-349c-4045-8c8f-d4a60562b1d3",
-                       "id_v1": "/sensors/124",
-                       "owner": {
-                               "rid": "f78c5b4b-2f52-4bc3-8097-1ddf97949cc5",
-                               "rtype": "device"
-                       },
-                       "metadata": {
-                               "control_id": 1
-                       },
-                       "button": {
-                               "last_event": "short_release"
-                       },
-                       "type": "button"
-               }
-       ]
-}
\ No newline at end of file
+    "errors": [],
+    "data": [
+        {
+            "id": "00000000-0000-0000-0000-000000000001",
+            "id_v1": "/sensors/76",
+            "owner": {
+                "rid": "00000000-0000-0000-0000-000000000000",
+                "rtype": "device"
+            },
+            "metadata": {
+                "control_id": 2
+            },
+            "button": {
+                "last_event": "long_release",
+                "button_report": {
+                    "updated": "2023-09-17T18:51:36.959Z",
+                    "event": "long_release"
+                },
+                "repeat_interval": 800,
+                "event_values": [
+                    "initial_press",
+                    "repeat",
+                    "short_release",
+                    "long_release",
+                    "long_press"
+                ]
+            },
+            "type": "button"
+        }
+    ]
+}
diff --git a/bundles/org.openhab.binding.hue/src/test/resources/button_deprecated.json b/bundles/org.openhab.binding.hue/src/test/resources/button_deprecated.json
new file mode 100644 (file)
index 0000000..6284e2e
--- /dev/null
@@ -0,0 +1,551 @@
+{
+       "errors": [],
+       "data": [
+               {
+                       "id": "d1ae958e-8908-449a-9897-7f10f9b8d4c2",
+                       "id_v1": "/sensors/110",
+                       "owner": {
+                               "rid": "112853f9-c4c4-4d65-ba96-b4c2ab26d94d",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "a83354b7-bae5-4618-8c8d-079c83e0ca2b",
+                       "id_v1": "/sensors/236",
+                       "owner": {
+                               "rid": "cfecbbd0-e918-42a2-b714-2bad33061d95",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "e20d90ae-b2d8-40ea-9905-66bcde9fd863",
+                       "id_v1": "/sensors/63",
+                       "owner": {
+                               "rid": "0e22f8de-eff5-440a-a9ed-06d547d125d7",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "4e61a948-22aa-4332-9b97-76245dd9fb87",
+                       "id_v1": "/sensors/6",
+                       "owner": {
+                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "2f78855c-717a-4b77-8513-dd68ca5337b8",
+                       "id_v1": "/sensors/6",
+                       "owner": {
+                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "7c495cbd-4dd1-4f22-950c-4dd6017b81ec",
+                       "id_v1": "/sensors/6",
+                       "owner": {
+                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "a15c9be9-14b9-4d98-8d9f-989d6cb54496",
+                       "id_v1": "/sensors/6",
+                       "owner": {
+                               "rid": "b56191ea-8d18-4257-b5d2-cfc3fc86a1ee",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "e1e6b2f9-3ace-41ae-b16c-e68f82b5a949",
+                       "id_v1": "/sensors/24",
+                       "owner": {
+                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "717c978e-383d-4900-ab2a-2685983f6174",
+                       "id_v1": "/sensors/24",
+                       "owner": {
+                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "0456ba22-2f1d-4375-8e33-31465420cd96",
+                       "id_v1": "/sensors/24",
+                       "owner": {
+                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "92c00fa4-ae65-462c-9130-a28f5bc52bd9",
+                       "id_v1": "/sensors/24",
+                       "owner": {
+                               "rid": "b5fe0539-171c-4733-bf0b-244635a309be",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "85c18ad0-297d-4fb9-a33a-37f2da70752d",
+                       "id_v1": "/sensors/118",
+                       "owner": {
+                               "rid": "a0509519-3ecb-47d0-9183-25db1e4ea2b2",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "79af0ff1-a4ed-476d-a381-eabd4d3ee6bd",
+                       "id_v1": "/sensors/135",
+                       "owner": {
+                               "rid": "8c5b05ba-b4f4-47b2-8ba0-fc44363192bc",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "8a16c730-094a-4aa1-abd8-9cb758468d62",
+                       "id_v1": "/sensors/8",
+                       "owner": {
+                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "3fed0654-68ec-43e1-b3db-f1a3eba076b9",
+                       "id_v1": "/sensors/8",
+                       "owner": {
+                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "df6e2ba8-94f4-43ce-9bec-72c252616062",
+                       "id_v1": "/sensors/8",
+                       "owner": {
+                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "a46f615d-6760-479c-ba6d-2837a18902e8",
+                       "id_v1": "/sensors/8",
+                       "owner": {
+                               "rid": "68ff07d0-6543-4967-9889-e0bc0bc16c31",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "c34bb678-b910-4a06-8019-3e0ce922f17f",
+                       "id_v1": "/sensors/18",
+                       "owner": {
+                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "286b1b18-ff43-40be-a2ff-b1edc24ecb7c",
+                       "id_v1": "/sensors/18",
+                       "owner": {
+                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "2be1abd3-00a4-4985-b2c9-9bdd4cbe1e4b",
+                       "id_v1": "/sensors/18",
+                       "owner": {
+                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "dc9f1653-11a8-4794-b706-464cf53e9722",
+                       "id_v1": "/sensors/18",
+                       "owner": {
+                               "rid": "96bec26d-d7c6-4c00-98cd-6f96733296a0",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "ac4ebfeb-2045-4698-96de-0b6b5421a1d8",
+                       "id_v1": "/sensors/4",
+                       "owner": {
+                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "8a5159f1-93de-4c07-9d32-1fe555fde285",
+                       "id_v1": "/sensors/4",
+                       "owner": {
+                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "14debc09-496e-4429-8c22-4975c135bbdf",
+                       "id_v1": "/sensors/4",
+                       "owner": {
+                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "9672e2a9-a3a9-4aec-b31e-f2338114b22b",
+                       "id_v1": "/sensors/4",
+                       "owner": {
+                               "rid": "81d9a9d5-228c-45df-828e-0d224929b3d1",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "f385a946-c638-4631-b6a6-c490cf809606",
+                       "id_v1": "/sensors/245",
+                       "owner": {
+                               "rid": "56b560bc-a127-4634-8d80-9946104a4028",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "ba204102-de9f-479e-818a-02ed880caac2",
+                       "id_v1": "/sensors/12",
+                       "owner": {
+                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "0032a38b-cf67-478f-934a-520a156a2baf",
+                       "id_v1": "/sensors/12",
+                       "owner": {
+                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "4ce58cbd-5d0f-45ec-920d-ad601fd9cc07",
+                       "id_v1": "/sensors/12",
+                       "owner": {
+                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "813a331a-f26a-4ab2-948c-9b4c398939d0",
+                       "id_v1": "/sensors/12",
+                       "owner": {
+                               "rid": "a1155885-4bbe-469f-83bb-f964f8e13e82",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "91ba8839-2bac-4175-9f8c-ed192842d549",
+                       "id_v1": "/sensors/20",
+                       "owner": {
+                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "f95addfc-2f7c-453f-924d-ba496e07e5f9",
+                       "id_v1": "/sensors/20",
+                       "owner": {
+                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "6615f1f1-f3f1-4a05-b8f7-581097458e34",
+                       "id_v1": "/sensors/20",
+                       "owner": {
+                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "b0d5a0af-31fd-4189-9150-c551ff9033d7",
+                       "id_v1": "/sensors/20",
+                       "owner": {
+                               "rid": "e130feac-3a5c-452e-a97d-5bca470783b3",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "9d3820db-4a20-4925-80f6-c74582ffb871",
+                       "id_v1": "/sensors/26",
+                       "owner": {
+                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "a9e1a40b-a13d-4966-b0b1-2b0b5dfe1986",
+                       "id_v1": "/sensors/26",
+                       "owner": {
+                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "8ba063d7-df16-48f5-bb9b-f45849ec1bd3",
+                       "id_v1": "/sensors/26",
+                       "owner": {
+                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "4fc9dcd2-6f71-46c4-b3d0-5d7b496be6f9",
+                       "id_v1": "/sensors/26",
+                       "owner": {
+                               "rid": "e12b3d9c-0b23-4edd-a967-66f5b5cefa92",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "824ea347-28d1-4e45-b886-1555a160190b",
+                       "id_v1": "/sensors/14",
+                       "owner": {
+                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "801ede68-21b0-4e6e-98be-eb1a60557ac6",
+                       "id_v1": "/sensors/14",
+                       "owner": {
+                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 2
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "1218d0c3-9a9c-4984-84a5-c12ad085ef2d",
+                       "id_v1": "/sensors/14",
+                       "owner": {
+                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 3
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "eb2c07bc-1d09-4096-a044-dec29b40619a",
+                       "id_v1": "/sensors/14",
+                       "owner": {
+                               "rid": "431026fb-298c-4726-8ce4-47450fea13c4",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 4
+                       },
+                       "type": "button"
+               },
+               {
+                       "id": "6bae5b99-349c-4045-8c8f-d4a60562b1d3",
+                       "id_v1": "/sensors/124",
+                       "owner": {
+                               "rid": "f78c5b4b-2f52-4bc3-8097-1ddf97949cc5",
+                               "rtype": "device"
+                       },
+                       "metadata": {
+                               "control_id": 1
+                       },
+                       "button": {
+                               "last_event": "short_release"
+                       },
+                       "type": "button"
+               }
+       ]
+}
\ No newline at end of file
index de8833e06ef30acb34733d9ea3f0bd10fde6775f..39c26fcc5d41c9722f40a0786d61d7743f05aa60 100644 (file)
@@ -1,19 +1,23 @@
 {
-       "errors": [],
-       "data": [
-               {
-                       "id": "18597697-61dc-4090-9bc3-c7f5704f020e",
-                       "id_v1": "/sensors/32",
-                       "owner": {
-                               "rid": "70660557-692d-4d37-8b6b-e3ec63716a72",
-                               "rtype": "device"
-                       },
-                       "enabled": true,
-                       "light": {
-                               "light_level": 12725,
-                               "light_level_valid": true
-                       },
-                       "type": "light_level"
-               }
-       ]
-}
\ No newline at end of file
+    "errors": [],
+    "data": [
+        {
+            "id": "00000000-0000-0000-0000-000000000002",
+            "id_v1": "/sensors/4",
+            "owner": {
+                "rid": "00000000-0000-0000-0000-000000000000",
+                "rtype": "device"
+            },
+            "enabled": true,
+            "light": {
+                "light_level": 2578,
+                "light_level_valid": true,
+                "light_level_report": {
+                    "changed": "2023-09-11T19:20:02.958Z",
+                    "light_level": 3578
+                }
+            },
+            "type": "light_level"
+        }
+    ]
+}
diff --git a/bundles/org.openhab.binding.hue/src/test/resources/light_level_deprecated.json b/bundles/org.openhab.binding.hue/src/test/resources/light_level_deprecated.json
new file mode 100644 (file)
index 0000000..de8833e
--- /dev/null
@@ -0,0 +1,19 @@
+{
+       "errors": [],
+       "data": [
+               {
+                       "id": "18597697-61dc-4090-9bc3-c7f5704f020e",
+                       "id_v1": "/sensors/32",
+                       "owner": {
+                               "rid": "70660557-692d-4d37-8b6b-e3ec63716a72",
+                               "rtype": "device"
+                       },
+                       "enabled": true,
+                       "light": {
+                               "light_level": 12725,
+                               "light_level_valid": true
+                       },
+                       "type": "light_level"
+               }
+       ]
+}
\ No newline at end of file
index b5b7ba658dc3930c0a702d619bfb239368580518..f18b91abba84632ba879bc577a25f900b510a270 100644 (file)
@@ -1,19 +1,28 @@
 {
-       "errors": [],
-       "data": [
-               {
-                       "id": "97244487-dd25-4f4c-b829-8eb5ffb82c29",
-                       "id_v1": "/sensors/30",
-                       "owner": {
-                               "rid": "70660557-692d-4d37-8b6b-e3ec63716a72",
-                               "rtype": "device"
-                       },
-                       "enabled": true,
-                       "motion": {
-                               "motion": true,
-                               "motion_valid": true
-                       },
-                       "type": "motion"
-               }
-       ]
-}
\ No newline at end of file
+    "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": "2023-09-04T20:04:30.395Z",
+                    "motion": true
+                }
+            },
+            "sensitivity": {
+                "status": "set",
+                "sensitivity": 2,
+                "sensitivity_max": 4
+            },
+            "type": "motion"
+        }
+    ]
+}
diff --git a/bundles/org.openhab.binding.hue/src/test/resources/motion_deprecated.json b/bundles/org.openhab.binding.hue/src/test/resources/motion_deprecated.json
new file mode 100644 (file)
index 0000000..b5b7ba6
--- /dev/null
@@ -0,0 +1,19 @@
+{
+       "errors": [],
+       "data": [
+               {
+                       "id": "97244487-dd25-4f4c-b829-8eb5ffb82c29",
+                       "id_v1": "/sensors/30",
+                       "owner": {
+                               "rid": "70660557-692d-4d37-8b6b-e3ec63716a72",
+                               "rtype": "device"
+                       },
+                       "enabled": true,
+                       "motion": {
+                               "motion": true,
+                               "motion_valid": true
+                       },
+                       "type": "motion"
+               }
+       ]
+}
\ No newline at end of file
index 3945f4e9a585c988abc4204814778868c5c3d875..0967ef424bce6791893e9a57bb952f80fd536e93 100644 (file)
@@ -1,24 +1 @@
-{
-       "errors": [],
-       "data": [
-               {
-                       "id": "12345678-7bd4d062-a33f-40e3-a7c0-91f64c39ac1a",
-                       "id_v1": "/sensors/2",
-                       "owner": {
-                               "rid": "497051e4-29c3-419b-babd-d916cffcf3a1",
-                               "rtype": "device"
-                       },
-                       "relative_rotary": {
-                               "last_event": {
-                                       "action": "repeat",
-                                       "rotation": {
-                                               "direction": "clock_wise",
-                                               "duration": 400,
-                                               "steps": 30
-                                       }
-                               }
-                       },
-                       "type": "relative_rotary"
-               }
-       ]
-}
\ No newline at end of file
+{}
diff --git a/bundles/org.openhab.binding.hue/src/test/resources/relative_rotary_deprecated.json b/bundles/org.openhab.binding.hue/src/test/resources/relative_rotary_deprecated.json
new file mode 100644 (file)
index 0000000..3945f4e
--- /dev/null
@@ -0,0 +1,24 @@
+{
+       "errors": [],
+       "data": [
+               {
+                       "id": "12345678-7bd4d062-a33f-40e3-a7c0-91f64c39ac1a",
+                       "id_v1": "/sensors/2",
+                       "owner": {
+                               "rid": "497051e4-29c3-419b-babd-d916cffcf3a1",
+                               "rtype": "device"
+                       },
+                       "relative_rotary": {
+                               "last_event": {
+                                       "action": "repeat",
+                                       "rotation": {
+                                               "direction": "clock_wise",
+                                               "duration": 400,
+                                               "steps": 30
+                                       }
+                               }
+                       },
+                       "type": "relative_rotary"
+               }
+       ]
+}
\ No newline at end of file
index 5034d6aee816da151a8cf0720b49f4553107d809..464bc9e1894ea904616c60ed0cbf661fe3bcc3f7 100644 (file)
@@ -1,19 +1,23 @@
 {
-       "errors": [],
-       "data": [
-               {
-                       "id": "f5f8010d-8356-4604-88dc-4f73912cbb6a",
-                       "id_v1": "/sensors/33",
-                       "owner": {
-                               "rid": "70660557-692d-4d37-8b6b-e3ec63716a72",
-                               "rtype": "device"
-                       },
-                       "enabled": true,
-                       "temperature": {
-                               "temperature": 17.26,
-                               "temperature_valid": true
-                       },
-                       "type": "temperature"
-               }
-       ]
-}
\ No newline at end of file
+    "errors": [],
+    "data": [
+        {
+            "id": "00000000-0000-0000-0000-000000000004",
+            "id_v1": "/sensors/5",
+            "owner": {
+                "rid": "00000000-0000-0000-0000-000000000000",
+                "rtype": "device"
+            },
+            "enabled": true,
+            "temperature": {
+                "temperature": 23.35,
+                "temperature_valid": true,
+                "temperature_report": {
+                    "changed": "2023-09-06T18:22:07.016Z",
+                    "temperature": 23.34
+                }
+            },
+            "type": "temperature"
+        }
+    ]
+}
diff --git a/bundles/org.openhab.binding.hue/src/test/resources/temperature_deprecated.json b/bundles/org.openhab.binding.hue/src/test/resources/temperature_deprecated.json
new file mode 100644 (file)
index 0000000..5034d6a
--- /dev/null
@@ -0,0 +1,19 @@
+{
+       "errors": [],
+       "data": [
+               {
+                       "id": "f5f8010d-8356-4604-88dc-4f73912cbb6a",
+                       "id_v1": "/sensors/33",
+                       "owner": {
+                               "rid": "70660557-692d-4d37-8b6b-e3ec63716a72",
+                               "rtype": "device"
+                       },
+                       "enabled": true,
+                       "temperature": {
+                               "temperature": 17.26,
+                               "temperature_valid": true
+                       },
+                       "type": "temperature"
+               }
+       ]
+}
\ No newline at end of file