Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from
Jan 8, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,12 @@ public class EcobeeBindingConstants {
public static final HouseDetailsDTO EMPTY_HOUSEDETAILS = new HouseDetailsDTO();
public static final ManagementDTO EMPTY_MANAGEMENT = new ManagementDTO();
public static final TechnicianDTO EMPTY_TECHNICIAN = new TechnicianDTO();
public static final List<RemoteSensorDTO> EMPTY_SENSORS = Collections.<RemoteSensorDTO> emptyList();
public static final List<ThermostatDTO> EMPTY_THERMOSTATS = Collections.<ThermostatDTO> emptyList();
public static final List<RemoteSensorDTO> EMPTY_SENSORS = Collections.<RemoteSensorDTO>emptyList();
public static final List<ThermostatDTO> EMPTY_THERMOSTATS = Collections.<ThermostatDTO>emptyList();

public static final String ECOBEE_BASE_URL = "https://api.ecobee.com/";
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";
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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;
Expand All @@ -32,6 +33,8 @@
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;
Expand Down Expand Up @@ -66,7 +69,8 @@
@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();

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
package org.openhab.binding.ecobee.internal.dto.thermostat;

import java.util.Date;
import java.time.Instant;
import java.util.List;

/**
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
package org.openhab.binding.ecobee.internal.dto.thermostat;

import java.util.Date;
import java.time.Instant;
import java.util.List;

/**
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ private void updateInfo(ThermostatDTO thermostat) {
updateChannel(grp + CH_MODEL_NUMBER, EcobeeUtils.undefOrString(thermostat.modelNumber));
updateChannel(grp + CH_BRAND, EcobeeUtils.undefOrString(thermostat.brand));
updateChannel(grp + CH_FEATURES, EcobeeUtils.undefOrString(thermostat.features));
updateChannel(grp + CH_LAST_MODIFIED, EcobeeUtils.undefOrDate(thermostat.lastModified, timeZoneProvider));
updateChannel(grp + CH_LAST_MODIFIED, EcobeeUtils.undefOrDate(thermostat.lastModified));
updateChannel(grp + CH_THERMOSTAT_TIME, EcobeeUtils.undefOrDate(thermostat.thermostatTime, timeZoneProvider));
}

Expand All @@ -386,13 +386,11 @@ private void updateRuntime(@Nullable RuntimeDTO runtime) {
final String grp = CHGRP_RUNTIME + "#";
updateChannel(grp + CH_RUNTIME_REV, EcobeeUtils.undefOrString(runtime.runtimeRev));
updateChannel(grp + CH_CONNECTED, EcobeeUtils.undefOrOnOff(runtime.connected));
updateChannel(grp + CH_FIRST_CONNECTED, EcobeeUtils.undefOrDate(runtime.firstConnected, timeZoneProvider));
updateChannel(grp + CH_CONNECT_DATE_TIME, EcobeeUtils.undefOrDate(runtime.connectDateTime, timeZoneProvider));
updateChannel(grp + CH_DISCONNECT_DATE_TIME,
EcobeeUtils.undefOrDate(runtime.disconnectDateTime, timeZoneProvider));
updateChannel(grp + CH_RT_LAST_MODIFIED, EcobeeUtils.undefOrDate(runtime.lastModified, timeZoneProvider));
updateChannel(grp + CH_RT_LAST_STATUS_MODIFIED,
EcobeeUtils.undefOrDate(runtime.lastStatusModified, timeZoneProvider));
updateChannel(grp + CH_FIRST_CONNECTED, EcobeeUtils.undefOrDate(runtime.firstConnected));
updateChannel(grp + CH_CONNECT_DATE_TIME, EcobeeUtils.undefOrDate(runtime.connectDateTime));
updateChannel(grp + CH_DISCONNECT_DATE_TIME, EcobeeUtils.undefOrDate(runtime.disconnectDateTime));
updateChannel(grp + CH_RT_LAST_MODIFIED, EcobeeUtils.undefOrDate(runtime.lastModified));
updateChannel(grp + CH_RT_LAST_STATUS_MODIFIED, EcobeeUtils.undefOrDate(runtime.lastStatusModified));
updateChannel(grp + CH_RUNTIME_DATE, EcobeeUtils.undefOrString(runtime.runtimeDate));
updateChannel(grp + CH_RUNTIME_INTERVAL, EcobeeUtils.undefOrDecimal(runtime.runtimeInterval));
updateChannel(grp + CH_ACTUAL_TEMPERATURE, EcobeeUtils.undefOrTemperature(runtime.actualTemperature));
Expand Down Expand Up @@ -662,7 +660,8 @@ private void updateWeather(@Nullable WeatherDTO weather) {
return;
}
final String weatherGrp = CHGRP_WEATHER + "#";
updateChannel(weatherGrp + CH_WEATHER_TIMESTAMP, EcobeeUtils.undefOrDate(weather.timestamp, timeZoneProvider));

updateChannel(weatherGrp + CH_WEATHER_TIMESTAMP, EcobeeUtils.undefOrDate(weather.timestamp));
updateChannel(weatherGrp + CH_WEATHER_WEATHER_STATION, EcobeeUtils.undefOrString(weather.weatherStation));

for (int index = 0; index < weather.forecasts.size(); index++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
*/
package org.openhab.binding.ecobee.internal.handler;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;

import javax.measure.Unit;
import javax.measure.quantity.Temperature;
Expand Down Expand Up @@ -87,9 +89,12 @@ public static State undefOrPoint(@Nullable String value) {
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) {
return instant == null ? UnDefType.UNDEF : new DateTimeType(ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")));
jlaur marked this conversation as resolved.
Show resolved Hide resolved
}

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) {
Expand Down