[netatmo] Simplify time zone handling for Home/Weather Station (#20315)

Signed-off-by: Gaël L'hopital <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital
2026-03-04 21:28:33 +01:00
committed by GitHub
parent 1d8b74b203
commit 5e2926ac2c
10 changed files with 15 additions and 96 deletions
@@ -46,7 +46,6 @@ import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider; import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
import org.openhab.core.auth.client.oauth2.OAuthFactory; import org.openhab.core.auth.client.oauth2.OAuthFactory;
import org.openhab.core.config.core.ConfigParser; import org.openhab.core.config.core.ConfigParser;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
@@ -80,19 +79,17 @@ public class NetatmoHandlerFactory extends BaseThingHandlerFactory {
private final HttpClient httpClient; private final HttpClient httpClient;
private final HttpService httpService; private final HttpService httpService;
private final OAuthFactory oAuthFactory; private final OAuthFactory oAuthFactory;
private final TimeZoneProvider timeZoneProvider;
@Activate @Activate
public NetatmoHandlerFactory(final @Reference NetatmoDescriptionProvider stateDescriptionProvider, public NetatmoHandlerFactory(final @Reference NetatmoDescriptionProvider stateDescriptionProvider,
final @Reference HttpClientFactory factory, final @Reference NADeserializer deserializer, final @Reference HttpClientFactory factory, final @Reference NADeserializer deserializer,
final @Reference HttpService httpService, final @Reference OAuthFactory oAuthFactory, final @Reference HttpService httpService, final @Reference OAuthFactory oAuthFactory,
final @Reference TimeZoneProvider timeZoneProvider, Map<String, @Nullable Object> config) { Map<String, @Nullable Object> config) {
this.stateDescriptionProvider = stateDescriptionProvider; this.stateDescriptionProvider = stateDescriptionProvider;
this.httpClient = factory.getCommonHttpClient(); this.httpClient = factory.getCommonHttpClient();
this.deserializer = deserializer; this.deserializer = deserializer;
this.httpService = httpService; this.httpService = httpService;
this.oAuthFactory = oAuthFactory; this.oAuthFactory = oAuthFactory;
this.timeZoneProvider = timeZoneProvider;
configChanged(config); configChanged(config);
} }
@@ -120,8 +117,7 @@ public class NetatmoHandlerFactory extends BaseThingHandlerFactory {
return new ApiBridgeHandler((Bridge) thing, httpClient, deserializer, configuration, httpService, return new ApiBridgeHandler((Bridge) thing, httpClient, deserializer, configuration, httpService,
oAuthFactory); oAuthFactory);
} }
CommonInterface handler = moduleType.isABridge() ? new DeviceHandler((Bridge) thing, timeZoneProvider) CommonInterface handler = moduleType.isABridge() ? new DeviceHandler((Bridge) thing) : new ModuleHandler(thing);
: new ModuleHandler(thing, timeZoneProvider);
List<ChannelHelper> helpers = moduleType.channelGroups.stream().map(ChannelGroup::getHelperInstance).toList(); List<ChannelHelper> helpers = moduleType.channelGroups.stream().map(ChannelGroup::getHelperInstance).toList();
@@ -35,7 +35,7 @@ import org.openhab.binding.netatmo.internal.deserialization.NAObjectMap;
*/ */
@NonNullByDefault @NonNullByDefault
public class HomeData extends NAThing implements NAModule, LocationEx { public class HomeData extends NAThing implements NAModule, Location {
public class HomesDataResponse extends ApiResponse<ListBodyResponse<HomeData>> { public class HomesDataResponse extends ApiResponse<ListBodyResponse<HomeData>> {
} }
@@ -104,14 +104,12 @@ public class HomeData extends NAThing implements NAModule, LocationEx {
return coordinates; return coordinates;
} }
@Override
public Optional<String> getCountry() { public Optional<String> getCountry() {
return Optional.ofNullable(country); return Optional.ofNullable(country);
} }
@Override public Optional<String> getTimezone() {
public @Nullable String getTimezone() { return Optional.ofNullable(timezone);
return timezone;
} }
public NAObjectMap<HomeDataRoom> getRooms() { public NAObjectMap<HomeDataRoom> getRooms() {
@@ -1,45 +0,0 @@
/*
* Copyright (c) 2010-2026 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.netatmo.internal.api.dto;
import java.time.DateTimeException;
import java.time.ZoneId;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link LocationEx} is the common interface for dto holding an extra location data
*
* @author Gaël L'hopital - Initial contribution
*
*/
@NonNullByDefault
public interface LocationEx extends Location {
Optional<String> getCountry();
@Nullable
String getTimezone();
public default ZoneId getZoneId(ZoneId fallback) {
String local = getTimezone();
if (local != null) {
try {
return ZoneId.of(local);
} catch (DateTimeException ignore) {
}
}
return fallback;
}
}
@@ -25,7 +25,7 @@ import org.eclipse.jdt.annotation.Nullable;
*/ */
@NonNullByDefault @NonNullByDefault
public class Place implements LocationEx { public class Place implements Location {
private @Nullable String city; private @Nullable String city;
private @Nullable String country; private @Nullable String country;
private @Nullable String timezone; private @Nullable String timezone;
@@ -36,14 +36,12 @@ public class Place implements LocationEx {
return Optional.ofNullable(city); return Optional.ofNullable(city);
} }
@Override
public Optional<String> getCountry() { public Optional<String> getCountry() {
return Optional.ofNullable(country); return Optional.ofNullable(country);
} }
@Override public Optional<String> getTimezone() {
public @Nullable String getTimezone() { return Optional.ofNullable(timezone);
return timezone;
} }
@Override @Override
@@ -13,7 +13,6 @@
package org.openhab.binding.netatmo.internal.handler; package org.openhab.binding.netatmo.internal.handler;
import java.time.Duration; import java.time.Duration;
import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -86,8 +85,6 @@ public interface CommonInterface {
@Nullable @Nullable
Bridge getBridge(); Bridge getBridge();
ZoneId getSystemTimeZone();
default @Nullable CommonInterface getBridgeHandler() { default @Nullable CommonInterface getBridgeHandler() {
Bridge bridge = getBridge(); Bridge bridge = getBridge();
return bridge != null && bridge.getHandler() instanceof DeviceHandler ? (DeviceHandler) bridge.getHandler() return bridge != null && bridge.getHandler() instanceof DeviceHandler ? (DeviceHandler) bridge.getHandler()
@@ -12,13 +12,11 @@
*/ */
package org.openhab.binding.netatmo.internal.handler; package org.openhab.binding.netatmo.internal.handler;
import java.time.ZoneId;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.netatmo.internal.handler.capability.CapabilityMap; import org.openhab.binding.netatmo.internal.handler.capability.CapabilityMap;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
@@ -42,11 +40,9 @@ import org.slf4j.LoggerFactory;
public class DeviceHandler extends BaseBridgeHandler implements CommonInterface { public class DeviceHandler extends BaseBridgeHandler implements CommonInterface {
private final Logger logger = LoggerFactory.getLogger(DeviceHandler.class); private final Logger logger = LoggerFactory.getLogger(DeviceHandler.class);
private final CapabilityMap capabilities = new CapabilityMap(); private final CapabilityMap capabilities = new CapabilityMap();
private final TimeZoneProvider timeZoneProvider;
public DeviceHandler(Bridge bridge, TimeZoneProvider timeZoneProvider) { public DeviceHandler(Bridge bridge) {
super(bridge); super(bridge);
this.timeZoneProvider = timeZoneProvider;
} }
@Override @Override
@@ -122,9 +118,4 @@ public class DeviceHandler extends BaseBridgeHandler implements CommonInterface
public ScheduledExecutorService getScheduler() { public ScheduledExecutorService getScheduler() {
return scheduler; return scheduler;
} }
@Override
public ZoneId getSystemTimeZone() {
return timeZoneProvider.getTimeZone();
}
} }
@@ -12,7 +12,6 @@
*/ */
package org.openhab.binding.netatmo.internal.handler; package org.openhab.binding.netatmo.internal.handler;
import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@@ -21,7 +20,6 @@ import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.netatmo.internal.handler.capability.CapabilityMap; import org.openhab.binding.netatmo.internal.handler.capability.CapabilityMap;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
@@ -46,11 +44,9 @@ import org.slf4j.LoggerFactory;
public class ModuleHandler extends BaseThingHandler implements CommonInterface { public class ModuleHandler extends BaseThingHandler implements CommonInterface {
private final Logger logger = LoggerFactory.getLogger(ModuleHandler.class); private final Logger logger = LoggerFactory.getLogger(ModuleHandler.class);
private final CapabilityMap capabilities = new CapabilityMap(); private final CapabilityMap capabilities = new CapabilityMap();
private final TimeZoneProvider timeZoneProvider;
public ModuleHandler(Thing thing, TimeZoneProvider timeZoneProvider) { public ModuleHandler(Thing thing) {
super(thing); super(thing);
this.timeZoneProvider = timeZoneProvider;
} }
@Override @Override
@@ -133,9 +129,4 @@ public class ModuleHandler extends BaseThingHandler implements CommonInterface {
public ScheduledExecutorService getScheduler() { public ScheduledExecutorService getScheduler() {
return scheduler; return scheduler;
} }
@Override
public ZoneId getSystemTimeZone() {
return timeZoneProvider.getTimeZone();
}
} }
@@ -38,7 +38,7 @@ public class DeviceCapability extends Capability {
newData.getPlace().ifPresent(place -> { newData.getPlace().ifPresent(place -> {
place.getCity().map(city -> properties.put(PROPERTY_CITY, city)); place.getCity().map(city -> properties.put(PROPERTY_CITY, city));
place.getCountry().map(country -> properties.put(PROPERTY_COUNTRY, country)); place.getCountry().map(country -> properties.put(PROPERTY_COUNTRY, country));
properties.put(PROPERTY_TIMEZONE, place.getZoneId(handler.getSystemTimeZone()).toString()); place.getTimezone().map(tz -> properties.put(PROPERTY_TIMEZONE, tz));
}); });
} }
if (!newData.hasFreshData(DATA_AGE_LIMIT_S)) { if (!newData.hasFreshData(DATA_AGE_LIMIT_S)) {
@@ -15,7 +15,7 @@ package org.openhab.binding.netatmo.internal.handler.capability;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
import java.time.Duration; import java.time.Duration;
import java.time.ZonedDateTime; import java.time.Instant;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.netatmo.internal.api.EnergyApi; import org.openhab.binding.netatmo.internal.api.EnergyApi;
@@ -162,10 +162,7 @@ public class EnergyCapability extends RestCapability<EnergyApi> {
} }
private long setpointEndTimeFromNow() { private long setpointEndTimeFromNow() {
return handler.getHomeCapability(HomeCapability.class).map(cap -> { Instant now = Instant.now().plus(setPointDefaultDuration);
ZonedDateTime now = ZonedDateTime.now().plus(setPointDefaultDuration); return now.getEpochSecond();
now = now.withZoneSameInstant(cap.zoneId);
return now.toEpochSecond();
}).orElseGet(() -> -1L);
} }
} }
@@ -15,7 +15,6 @@ package org.openhab.binding.netatmo.internal.handler.capability;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
import java.time.Duration; import java.time.Duration;
import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -49,8 +48,6 @@ public class HomeCapability extends CacheCapability<HomeApi> {
private final NetatmoDescriptionProvider descriptionProvider; private final NetatmoDescriptionProvider descriptionProvider;
private final Set<String> homeIds = new HashSet<>(3); private final Set<String> homeIds = new HashSet<>(3);
protected ZoneId zoneId = ZoneId.systemDefault();
public HomeCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider) { public HomeCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider) {
super(handler, Duration.ofSeconds(2), HomeApi.class); super(handler, Duration.ofSeconds(2), HomeApi.class);
this.descriptionProvider = descriptionProvider; this.descriptionProvider = descriptionProvider;
@@ -89,8 +86,7 @@ public class HomeCapability extends CacheCapability<HomeApi> {
handler.removeChannels(getThing().getChannelsOfGroup(GROUP_ENERGY)); handler.removeChannels(getThing().getChannelsOfGroup(GROUP_ENERGY));
} }
home.getCountry().map(country -> properties.put(PROPERTY_COUNTRY, country)); home.getCountry().map(country -> properties.put(PROPERTY_COUNTRY, country));
zoneId = home.getZoneId(handler.getSystemTimeZone()); home.getTimezone().map(tz -> properties.put(PROPERTY_TIMEZONE, tz));
properties.put(PROPERTY_TIMEZONE, zoneId.toString());
properties.put(GROUP_LOCATION, home.getLocation().toString()); properties.put(GROUP_LOCATION, home.getLocation().toString());
properties.put(PROPERTY_FEATURE, properties.put(PROPERTY_FEATURE,
featureAreas.stream().map(FeatureArea::name).collect(Collectors.joining(","))); featureAreas.stream().map(FeatureArea::name).collect(Collectors.joining(",")));