2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.iammeter.internal;
15 import java.io.IOException;
16 import java.time.Duration;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
20 import javax.measure.Unit;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.core.cache.ExpiringCache;
25 import org.openhab.core.io.net.http.HttpUtil;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseThingHandler;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.openhab.core.types.State;
35 import org.openhab.core.types.UnDefType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.google.gson.JsonSyntaxException;
42 * The {@link IammeterHandler} is responsible for handling commands, which are
43 * sent to one of the channels.
45 * @author Yang Bo - Initial contribution
49 public abstract class IammeterBaseHandler extends BaseThingHandler {
51 private final Logger logger = LoggerFactory.getLogger(IammeterBaseHandler.class);
52 private @Nullable ScheduledFuture<?> refreshJob;
53 private IammeterConfiguration config;
54 private static final int TIMEOUT_MS = 5000;
55 private final ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(Duration.ofSeconds(5), this::refresh);
57 public IammeterBaseHandler(Thing thing) {
59 config = getConfiguration();
63 public void handleCommand(ChannelUID channelUID, Command command) {
64 if (command instanceof RefreshType) {
65 refreshCache.getValue();
70 public void initialize() {
71 ScheduledFuture<?> refreshJob = this.refreshJob;
72 config = getConfiguration();
73 if (refreshJob == null) {
74 refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, config.refreshInterval, TimeUnit.SECONDS);
75 this.refreshJob = refreshJob;
76 updateStatus(ThingStatus.UNKNOWN);
80 protected abstract void resolveData(String response);
82 @SuppressWarnings("null")
83 private boolean refresh() {
84 refreshCache.invalidateValue();
85 IammeterConfiguration config = this.config;
87 String httpMethod = "GET";
88 String url = "http://" + config.username + ":" + config.password + "@" + config.host + ":" + config.port
90 String response = HttpUtil.executeUrl(httpMethod, url, TIMEOUT_MS);
91 resolveData(response);
92 updateStatus(ThingStatus.ONLINE);
94 // Very rudimentary Exception differentiation
95 } catch (IOException e) {
96 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
97 "Communication error with the device: " + e.getMessage());
98 } catch (JsonSyntaxException je) {
99 logger.warn("Invalid JSON when refreshing source {}: {}", getThing().getUID(), je.getMessage());
100 updateStatus(ThingStatus.OFFLINE);
105 protected State getQuantityState(String value, Unit<?> unit) {
107 return QuantityType.valueOf(Float.parseFloat(value), unit);
108 } catch (NumberFormatException e) {
109 return UnDefType.UNDEF;
114 public void dispose() {
115 ScheduledFuture<?> refreshJob = this.refreshJob;
116 if (refreshJob != null && !refreshJob.isCancelled()) {
117 refreshJob.cancel(true);
118 this.refreshJob = null;
123 public IammeterConfiguration getConfiguration() {
124 return this.getConfigAs(IammeterConfiguration.class);