]> git.basschouten.com Git - openhab-addons.git/commitdiff
[ecobee] Fix issue with UTC and local dates (#14170)
authorMark Hilbush <mark@hilbush.com>
Sun, 8 Jan 2023 22:35:01 +0000 (17:35 -0500)
committerGitHub <noreply@github.com>
Sun, 8 Jan 2023 22:35:01 +0000 (23:35 +0100)
* Correctly handle UTC and local date/times
* Eliminate use of Date class

Signed-off-by: Mark Hilbush <mark@hilbush.com>
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/EcobeeBindingConstants.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/api/EcobeeApi.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/InstantDeserializer.java [new file with mode: 0644]
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/LocalDateTimeDeserializer.java [new file with mode: 0644]
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/RuntimeDTO.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/ThermostatDTO.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/WeatherDTO.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/WeatherForecastDTO.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/handler/EcobeeThermostatBridgeHandler.java
bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/handler/EcobeeUtils.java

index c743b550454477c8069c3b007663690d83827269..4f3d0704df5ad6d4b88d52da3347dd32184f1a1d 100644 (file)
@@ -409,4 +409,5 @@ public class EcobeeBindingConstants {
     public static final String ECOBEE_AUTHORIZE_URL = ECOBEE_BASE_URL + "authorize";
     public static final String ECOBEE_TOKEN_URL = ECOBEE_BASE_URL + "token";
     public static final String ECOBEE_SCOPE = "smartWrite";
+    public static final String ECOBEE_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
 }
index b88702d446826ff0ddc208792b3447e64825af93..b245a4c83f90bee7cce2ccd58c6ca8df6b0c06c0 100644 (file)
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
@@ -32,6 +33,8 @@ import org.eclipse.jetty.client.HttpClient;
 import org.openhab.binding.ecobee.internal.dto.AbstractResponseDTO;
 import org.openhab.binding.ecobee.internal.dto.SelectionDTO;
 import org.openhab.binding.ecobee.internal.dto.SelectionType;
+import org.openhab.binding.ecobee.internal.dto.thermostat.InstantDeserializer;
+import org.openhab.binding.ecobee.internal.dto.thermostat.LocalDateTimeDeserializer;
 import org.openhab.binding.ecobee.internal.dto.thermostat.ThermostatDTO;
 import org.openhab.binding.ecobee.internal.dto.thermostat.ThermostatRequestDTO;
 import org.openhab.binding.ecobee.internal.dto.thermostat.ThermostatResponseDTO;
@@ -66,7 +69,8 @@ import com.google.gson.JsonSyntaxException;
 @NonNullByDefault
 public class EcobeeApi implements AccessTokenRefreshListener {
 
-    private static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
+    private static final Gson GSON = new GsonBuilder().registerTypeAdapter(Instant.class, new InstantDeserializer())
+            .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeDeserializer())
             .registerTypeAdapter(RevisionDTO.class, new RevisionDTODeserializer())
             .registerTypeAdapter(RunningDTO.class, new RunningDTODeserializer()).create();
 
diff --git a/bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/InstantDeserializer.java b/bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/InstantDeserializer.java
new file mode 100644 (file)
index 0000000..e6f944d
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * 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.ecobee.internal.dto.thermostat;
+
+import static org.openhab.binding.ecobee.internal.EcobeeBindingConstants.ECOBEE_DATETIME_FORMAT;
+
+import java.lang.reflect.Type;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+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} is responsible for handling the UTC dates returned from
+ * the Ecobee API service.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class InstantDeserializer implements JsonDeserializer<Instant> {
+
+    @Override
+    public @Nullable Instant deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2)
+            throws JsonParseException {
+        try {
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ECOBEE_DATETIME_FORMAT);
+            LocalDateTime localDateTime = formatter.parse(element.getAsString(), LocalDateTime::from);
+            return localDateTime.toInstant(ZoneOffset.UTC);
+        } catch (DateTimeParseException e) {
+            return null;
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/LocalDateTimeDeserializer.java b/bundles/org.openhab.binding.ecobee/src/main/java/org/openhab/binding/ecobee/internal/dto/thermostat/LocalDateTimeDeserializer.java
new file mode 100644 (file)
index 0000000..1b7e908
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * 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.ecobee.internal.dto.thermostat;
+
+import static org.openhab.binding.ecobee.internal.EcobeeBindingConstants.ECOBEE_DATETIME_FORMAT;
+
+import java.lang.reflect.Type;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+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 LocalDateTimeDeserializer} is responsible for handling the local dates returned from
+ * the Ecobee API service.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class LocalDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {
+
+    @Override
+    public @Nullable LocalDateTime deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2)
+            throws JsonParseException {
+        try {
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ECOBEE_DATETIME_FORMAT);
+            return formatter.parse(element.getAsString(), LocalDateTime::from);
+        } catch (DateTimeParseException e) {
+            return null;
+        }
+    }
+}
index a946d05bb6e1e657bc508fbf7707a97b976f67fc..4151e3ea1ecdfac809119f4710fcbb7faf383897 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.ecobee.internal.dto.thermostat;
 
-import java.util.Date;
+import java.time.Instant;
 import java.util.List;
 
 /**
@@ -48,29 +48,29 @@ public class RuntimeDTO {
      * The UTC date/time stamp of when the thermostat first connected
      * to the ecobee server.
      */
-    public Date firstConnected;
+    public Instant firstConnected;
 
     /*
      * The last recorded connection date and time.
      */
-    public Date connectDateTime;
+    public Instant connectDateTime;
 
     /*
      * The last recorded disconnection date and time.
      */
-    public Date disconnectDateTime;
+    public Instant disconnectDateTime;
 
     /*
      * The UTC date/time stamp of when the thermostat was updated.
      * Format: YYYY-MM-DD HH:MM:SS
      */
-    public Date lastModified;
+    public Instant lastModified;
 
     /*
      * The UTC date/time stamp of when the thermostat last posted its
      * runtime information. Format: YYYY-MM-DD HH:MM:SS
      */
-    public Date lastStatusModified;
+    public Instant lastStatusModified;
 
     /*
      * The UTC date of the last runtime reading. Format: YYYY-MM-DD
index 073a6e074e14018635b27d5305d9e2cc2ccddd54..6aae7cd984b3266185a3d8bc078b8ca8479a6ed0 100644 (file)
@@ -12,7 +12,8 @@
  */
 package org.openhab.binding.ecobee.internal.dto.thermostat;
 
-import java.util.Date;
+import java.time.Instant;
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -64,12 +65,12 @@ public class ThermostatDTO {
     /*
      * The last modified date time for the thermostat configuration.
      */
-    public Date lastModified;
+    public Instant lastModified;
 
     /*
      * The current time in the thermostat's time zone.
      */
-    public Date thermostatTime;
+    public LocalDateTime thermostatTime;
 
     /*
      * The current time in UTC.
index ec55310210b278ec4bb27261d77c3c55f83cf7ad..be757061d51958213fdc44c392354ddf3d5b26b6 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.ecobee.internal.dto.thermostat;
 
-import java.util.Date;
+import java.time.Instant;
 import java.util.List;
 
 /**
@@ -25,7 +25,7 @@ public class WeatherDTO {
     /*
      * The time stamp in UTC of the weather forecast
      */
-    public Date timestamp;
+    public Instant timestamp;
 
     /*
      * The weather station identifier
index cbc008dc99e4717f39504a2d30d5e2c498b19adb..e882ab5dc490428671d48d2a97dbe9159f99b1ff 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.ecobee.internal.dto.thermostat;
 
-import java.util.Date;
+import java.time.LocalDateTime;
 
 /**
  * The {@link WeatherForecastDTO} contains the weather forecast information for
@@ -31,9 +31,9 @@ public class WeatherForecastDTO {
     public Integer weatherSymbol;
 
     /*
-     * The time stamp of the weather forecast.
+     * The time stamp of the weather forecast in the thermostat's time zone.
      */
-    public Date dateTime;
+    public LocalDateTime dateTime;
 
     /*
      * A text value representing the current weather condition.
index aa8f1e8088ce171ab4378e4c1e84a94c40ceaadb..1f20011f3d5fa031300128555c582e785e000f7d 100644 (file)
@@ -662,6 +662,7 @@ public class EcobeeThermostatBridgeHandler extends BaseBridgeHandler {
             return;
         }
         final String weatherGrp = CHGRP_WEATHER + "#";
+
         updateChannel(weatherGrp + CH_WEATHER_TIMESTAMP, EcobeeUtils.undefOrDate(weather.timestamp, timeZoneProvider));
         updateChannel(weatherGrp + CH_WEATHER_WEATHER_STATION, EcobeeUtils.undefOrString(weather.weatherStation));
 
index 410aac04e116df5c9b7b7107db55e969ea01f7c4..fec258982cfaafc7d34aa40f9baee2c1d8879436 100644 (file)
@@ -12,8 +12,9 @@
  */
 package org.openhab.binding.ecobee.internal.handler;
 
+import java.time.Instant;
+import java.time.LocalDateTime;
 import java.time.ZonedDateTime;
-import java.util.Date;
 
 import javax.measure.Unit;
 import javax.measure.quantity.Temperature;
@@ -87,9 +88,13 @@ public final class EcobeeUtils {
         return value == null ? UnDefType.UNDEF : new PointType(value);
     }
 
-    public static State undefOrDate(@Nullable Date date, TimeZoneProvider timeZoneProvider) {
-        return date == null ? UnDefType.UNDEF
-                : new DateTimeType(ZonedDateTime.ofInstant(date.toInstant(), timeZoneProvider.getTimeZone()));
+    public static State undefOrDate(@Nullable Instant instant, TimeZoneProvider timeZoneProvider) {
+        return instant == null ? UnDefType.UNDEF
+                : new DateTimeType(ZonedDateTime.ofInstant(instant, timeZoneProvider.getTimeZone()));
+    }
+
+    public static State undefOrDate(@Nullable LocalDateTime ldt, TimeZoneProvider timeZoneProvider) {
+        return ldt == null ? UnDefType.UNDEF : new DateTimeType(ldt.atZone(timeZoneProvider.getTimeZone()));
     }
 
     private static boolean isUnknown(Number value) {