[ecobee] Fix issue with UTC and local dates (#14170)

* Correctly handle UTC and local date/times
* Eliminate use of Date class

Signed-off-by: Mark Hilbush <mark@hilbush.com>
This commit is contained in:
Mark Hilbush 2023-01-08 17:35:01 -05:00 committed by GitHub
parent 2c2097d646
commit 3ba37b431a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 132 additions and 19 deletions

View 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";
}

View 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();

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View 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

View 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.

View 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

View 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.

View 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));

View 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) {