private @Nullable String timezone;
private NAObjectMap<HomeDataRoom> rooms = new NAObjectMap<>();
- private NAObjectMap<HomeDataModule> modules = new NAObjectMap<>();
+ private @Nullable NAObjectMap<HomeDataModule> modules;
@Override
public ModuleType getType() {
}
public NAObjectMap<HomeDataModule> getModules() {
- return modules;
+ NAObjectMap<HomeDataModule> local = modules;
+ return local != null ? local : new NAObjectMap<>();
}
public Set<FeatureArea> getFeatures() {
public synchronized <T> T executeUri(URI uri, HttpMethod method, Class<T> clazz, @Nullable String payload,
@Nullable String contentType, int retryCount) throws NetatmoException {
try {
- logger.trace("executeUri {} {} ", method.toString(), uri);
+ logger.debug("executeUri {} {} ", method.toString(), uri);
Request request = httpClient.newRequest(uri).method(method).timeout(TIMEOUT_S, TimeUnit.SECONDS);
--- /dev/null
+/**
+ * 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.netatmo.internal.handler.capability;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.netatmo.internal.api.WeatherApi;
+import org.openhab.binding.netatmo.internal.api.dto.NAObject;
+import org.openhab.binding.netatmo.internal.handler.CommonInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link CacheWeatherCapability} give the ability to buffer weather related requests and reduce server requests
+ *
+ * @author Gaël L'hopital - Initial contribution
+ *
+ */
+@NonNullByDefault
+public abstract class CacheWeatherCapability extends RestCapability<WeatherApi> {
+ private final Logger logger = LoggerFactory.getLogger(CacheWeatherCapability.class);
+ private final Duration validity;
+
+ private List<NAObject> lastResult = List.of();
+ private Instant requestTS = Instant.MIN;
+
+ public CacheWeatherCapability(CommonInterface handler, Duration validity) {
+ super(handler, WeatherApi.class);
+ this.validity = validity;
+ }
+
+ @Override
+ protected List<NAObject> updateReadings(WeatherApi api) {
+ Instant now = Instant.now();
+
+ if (requestTS.plus(validity).isBefore(now)) {
+ logger.debug("Requesting fresh data");
+ lastResult = getFreshData(api);
+ requestTS = now;
+ }
+
+ return lastResult;
+ }
+
+ protected abstract List<NAObject> getFreshData(WeatherApi api);
+}
import static org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils.*;
+import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
*
*/
@NonNullByDefault
-public class MeasureCapability extends RestCapability<WeatherApi> {
+public class MeasureCapability extends CacheWeatherCapability {
private final Logger logger = LoggerFactory.getLogger(MeasureCapability.class);
private final Map<String, State> measures = new HashMap<>();
public MeasureCapability(CommonInterface handler, List<ChannelHelper> helpers) {
- super(handler, WeatherApi.class);
+ super(handler, Duration.ofMinutes(30));
MeasuresChannelHelper measureChannelHelper = (MeasuresChannelHelper) helpers.stream()
.filter(c -> c instanceof MeasuresChannelHelper).findFirst()
.orElseThrow(() -> new IllegalArgumentException(
measureChannelHelper.setMeasures(measures);
}
- @Override
- public List<NAObject> updateReadings(WeatherApi api) {
- String bridgeId = handler.getBridgeId();
- String deviceId = bridgeId != null ? bridgeId : handler.getId();
- String moduleId = bridgeId != null ? handler.getId() : null;
- updateMeasures(api, deviceId, moduleId);
- return List.of();
- }
-
private void updateMeasures(WeatherApi api, String deviceId, @Nullable String moduleId) {
measures.clear();
handler.getActiveChannels().filter(channel -> !channel.getConfiguration().getProperties().isEmpty())
}
});
}
+
+ @Override
+ protected List<NAObject> getFreshData(WeatherApi api) {
+ String bridgeId = handler.getBridgeId();
+ String deviceId = bridgeId != null ? bridgeId : handler.getId();
+ String moduleId = bridgeId != null ? handler.getId() : null;
+ updateMeasures(api, deviceId, moduleId);
+ return List.of();
+ }
}
import java.time.Duration;
import java.time.Instant;
+import java.time.ZonedDateTime;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
private Instant dataTimeStamp = Instant.now();
private Instant dataTimeStamp0 = Instant.MIN;
private Optional<ScheduledFuture<?>> refreshJob = Optional.empty();
- private final boolean refreshConfigured;
+ private boolean refreshConfigured;
public RefreshCapability(CommonInterface handler, ScheduledExecutorService scheduler, int refreshInterval) {
super(handler);
if (probing()) {
dataTimeStamp0 = Instant.MIN;
}
- } else if (refreshConfigured) {
- delay = dataValidity.getSeconds();
} else {
- delay = (probing() ? PROBING_INTERVAL : dataValidity.minus(dataAge()).plus(DEFAULT_DELAY)).toSeconds();
+ delay = refreshConfigured ? dataValidity.getSeconds()
+ : (probing() ? PROBING_INTERVAL : dataValidity.minus(dataAge()).plus(DEFAULT_DELAY)).toSeconds();
}
delay = delay < 2 ? PROBING_INTERVAL.toSeconds() : delay;
- logger.debug("Module refreshed, next one in {} s", delay);
+ logger.debug("Module refreshed, next one in {}s", delay);
freeJobAndReschedule(delay);
}
@Override
protected void updateNAThing(NAThing newData) {
super.updateNAThing(newData);
- newData.getLastSeen().ifPresent(timestamp -> {
- Instant tsInstant = timestamp.toInstant();
+ newData.getLastSeen().map(ZonedDateTime::toInstant).ifPresent(tsInstant -> {
if (probing()) {
if (Instant.MIN.equals(dataTimeStamp0)) {
dataTimeStamp0 = tsInstant;
logger.debug("First data timestamp is {}", dataTimeStamp0);
} else if (tsInstant.isAfter(dataTimeStamp0)) {
dataValidity = Duration.between(dataTimeStamp0, tsInstant);
+ refreshConfigured = true;
logger.debug("Data validity period identified to be {}", dataValidity);
} else {
logger.debug("Data validity period not yet found - data timestamp unchanged");
private void freeJobAndReschedule(long delay) {
refreshJob.ifPresent(job -> job.cancel(false));
- refreshJob = delay == 0 ? Optional.empty()
- : Optional.of(scheduler.schedule(() -> proceedWithUpdate(), delay, TimeUnit.SECONDS));
+ refreshJob = Optional
+ .ofNullable(delay == 0 ? null : scheduler.schedule(() -> proceedWithUpdate(), delay, TimeUnit.SECONDS));
}
}
*/
package org.openhab.binding.netatmo.internal.handler.capability;
+import java.time.Duration;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.LoggerFactory;
/**
- * {@link WeatherCapability} give the ability to read weather station api
+ * {@link WeatherCapability} give the ability to read weather station API
*
* @author Gaël L'hopital - Initial contribution
*
*/
@NonNullByDefault
-public class WeatherCapability extends RestCapability<WeatherApi> {
+public class WeatherCapability extends CacheWeatherCapability {
private final Logger logger = LoggerFactory.getLogger(WeatherCapability.class);
public WeatherCapability(CommonInterface handler) {
- super(handler, WeatherApi.class);
+ super(handler, Duration.ofSeconds(2));
}
@Override
- protected List<NAObject> updateReadings(WeatherApi api) {
+ protected List<NAObject> getFreshData(WeatherApi api) {
try {
return List.of(owned ? api.getOwnedStationData(handler.getId()) : api.getStationData(handler.getId()));
} catch (NetatmoException e) {