2 * Copyright (c) 2010-2020 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.oceanic.internal.handler;
15 import java.math.BigDecimal;
16 import java.util.ArrayList;
17 import java.util.List;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.openhab.binding.oceanic.internal.OceanicBindingConstants.OceanicChannelSelector;
24 import org.openhab.core.thing.Channel;
25 import org.openhab.core.thing.ChannelUID;
26 import org.openhab.core.thing.Thing;
27 import org.openhab.core.thing.ThingStatus;
28 import org.openhab.core.thing.ThingStatusDetail;
29 import org.openhab.core.thing.binding.BaseThingHandler;
30 import org.openhab.core.types.Command;
31 import org.openhab.core.types.RefreshType;
32 import org.openhab.core.types.State;
33 import org.openhab.core.types.Type;
34 import org.openhab.core.types.TypeParser;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * The {@link OceanicThingHandler} is the abstract class responsible for handling commands, which are
40 * sent to one of the channels
42 * @author Karel Goderis - Initial contribution
44 public abstract class OceanicThingHandler extends BaseThingHandler {
46 public static final String INTERVAL = "interval";
47 public static final String BUFFER_SIZE = "buffer";
48 private final Logger logger = LoggerFactory.getLogger(OceanicThingHandler.class);
50 protected int bufferSize;
51 protected ScheduledFuture<?> pollingJob;
52 protected static String lastLineReceived = "";
54 public OceanicThingHandler(@NonNull Thing thing) {
58 private Runnable resetRunnable = () -> {
63 private Runnable pollingRunnable = () -> {
65 if (getThing().getStatus() == ThingStatus.ONLINE) {
66 for (Channel aChannel : getThing().getChannels()) {
67 for (OceanicChannelSelector selector : OceanicChannelSelector.values()) {
68 ChannelUID theChannelUID = new ChannelUID(getThing().getUID(), selector.toString());
69 if (aChannel.getUID().equals(theChannelUID)
70 && selector.getTypeValue() == OceanicChannelSelector.ValueSelectorType.GET) {
71 String response = requestResponse(selector.name());
72 if (response != null && response != "") {
73 if (selector.isProperty()) {
74 logger.debug("Updating the property '{}' with value '{}'", selector.toString(),
75 selector.convertValue(response));
76 Map<String, String> properties = editProperties();
77 properties.put(selector.toString(), selector.convertValue(response));
78 updateProperties(properties);
80 State value = createStateForType(selector, response);
81 updateState(theChannelUID, value);
84 logger.warn("Received an empty answer for '{}'", selector.name());
90 } catch (Exception e) {
91 logger.error("An exception occurred while polling the Oceanic Water Softener: '{}'", e.getMessage(), e);
92 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
93 scheduler.schedule(resetRunnable, 0, TimeUnit.SECONDS);
98 public void initialize() {
99 if (getConfig().get(BUFFER_SIZE) == null) {
102 bufferSize = ((BigDecimal) getConfig().get(BUFFER_SIZE)).intValue();
105 if (pollingJob == null || pollingJob.isCancelled()) {
106 pollingJob = scheduler.scheduleWithFixedDelay(pollingRunnable, 1,
107 ((BigDecimal) getConfig().get(INTERVAL)).intValue(), TimeUnit.SECONDS);
112 public void dispose() {
113 if (pollingJob != null && !pollingJob.isCancelled()) {
114 pollingJob.cancel(true);
120 public void handleCommand(ChannelUID channelUID, Command command) {
121 if (getThing().getStatus() == ThingStatus.ONLINE) {
122 if (!(command instanceof RefreshType)) {
123 String commandAsString = command.toString();
124 String channelID = channelUID.getId();
126 for (Channel aChannel : getThing().getChannels()) {
127 if (aChannel.getUID().equals(channelUID)) {
129 OceanicChannelSelector selector = OceanicChannelSelector.getValueSelector(channelID,
130 OceanicChannelSelector.ValueSelectorType.SET);
134 commandAsString = selector.name() + commandAsString;
137 commandAsString = selector.name();
140 String response = requestResponse(commandAsString);
141 if (response.equals("ERR")) {
142 logger.error("An error occurred while setting '{}' to {}", selector.toString(),
145 } catch (IllegalArgumentException e) {
147 "An error occurred while trying to set the read-only variable associated with channel '{}' to '{}'",
148 channelID, command.toString());
157 @SuppressWarnings("unchecked")
158 private State createStateForType(OceanicChannelSelector selector, String value) {
159 Class<? extends Type> typeClass = selector.getTypeClass();
160 List<Class<? extends State>> stateTypeList = new ArrayList<>();
162 stateTypeList.add((Class<? extends State>) typeClass);
163 State state = TypeParser.parseState(stateTypeList, selector.convertValue(value));
168 protected abstract String requestResponse(String commandAsString);