]> git.basschouten.com Git - openhab-addons.git/blob
a1874bf426e83c250eba94cdd8abd4778cbbc0e4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.oceanic.internal.handler;
14
15 import java.math.BigDecimal;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
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.TypeParser;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * The {@link OceanicThingHandler} is the abstract class responsible for handling commands, which are
39  * sent to one of the channels
40  *
41  * @author Karel Goderis - Initial contribution
42  */
43 @NonNullByDefault
44 public abstract class OceanicThingHandler extends BaseThingHandler {
45
46     public static final String INTERVAL = "interval";
47     public static final String BUFFER_SIZE = "buffer";
48     private final Logger logger = LoggerFactory.getLogger(OceanicThingHandler.class);
49
50     protected int bufferSize;
51     protected @Nullable ScheduledFuture<?> pollingJob;
52     protected static String lastLineReceived = "";
53
54     public OceanicThingHandler(Thing thing) {
55         super(thing);
56     }
57
58     private Runnable resetRunnable = () -> {
59         dispose();
60         initialize();
61     };
62
63     private Runnable pollingRunnable = () -> {
64         try {
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.isEmpty()) {
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);
79                                 } else {
80                                     State value = createStateForType(selector, response);
81                                     if (value != null) {
82                                         updateState(theChannelUID, value);
83                                     }
84                                 }
85                             } else {
86                                 logger.warn("Received an empty answer for '{}'", selector.name());
87                             }
88                         }
89                     }
90                 }
91             }
92         } catch (Exception e) {
93             logger.error("An exception occurred while polling the Oceanic Water Softener: '{}'", e.getMessage(), e);
94             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
95             scheduler.schedule(resetRunnable, 0, TimeUnit.SECONDS);
96         }
97     };
98
99     @Override
100     public void initialize() {
101         if (getConfig().get(BUFFER_SIZE) == null) {
102             bufferSize = 1024;
103         } else {
104             bufferSize = ((BigDecimal) getConfig().get(BUFFER_SIZE)).intValue();
105         }
106         ScheduledFuture<?> pollingJob = this.pollingJob;
107         if (pollingJob == null || pollingJob.isCancelled()) {
108             this.pollingJob = scheduler.scheduleWithFixedDelay(pollingRunnable, 1,
109                     ((BigDecimal) getConfig().get(INTERVAL)).intValue(), TimeUnit.SECONDS);
110         }
111     }
112
113     @Override
114     public void dispose() {
115         ScheduledFuture<?> pollingJob = this.pollingJob;
116         if (pollingJob != null) {
117             pollingJob.cancel(true);
118             this.pollingJob = null;
119         }
120     }
121
122     @Override
123     public void handleCommand(ChannelUID channelUID, Command command) {
124         if (getThing().getStatus() == ThingStatus.ONLINE) {
125             if (!(command instanceof RefreshType)) {
126                 String commandAsString = command.toString();
127                 String channelID = channelUID.getId();
128
129                 for (Channel aChannel : getThing().getChannels()) {
130                     if (aChannel.getUID().equals(channelUID)) {
131                         try {
132                             OceanicChannelSelector selector = OceanicChannelSelector.getValueSelector(channelID,
133                                     OceanicChannelSelector.ValueSelectorType.SET);
134
135                             switch (selector) {
136                                 case setSV1:
137                                     commandAsString = selector.name() + commandAsString;
138                                     break;
139                                 default:
140                                     commandAsString = selector.name();
141                                     break;
142                             }
143                             String response = requestResponse(commandAsString);
144                             if ("ERR".equals(response)) {
145                                 logger.error("An error occurred while setting '{}' to {}", selector.toString(),
146                                         commandAsString);
147                             }
148                         } catch (IllegalArgumentException e) {
149                             logger.warn(
150                                     "An error occurred while trying to set the read-only variable associated with channel '{}' to '{}'",
151                                     channelID, command.toString());
152                         }
153                         break;
154                     }
155                 }
156             }
157         }
158     }
159
160     @SuppressWarnings("unchecked")
161     private @Nullable State createStateForType(OceanicChannelSelector selector, String value) {
162         return TypeParser.parseState(List.of((Class<? extends State>) selector.getTypeClass()),
163                 selector.convertValue(value));
164     }
165
166     protected abstract @Nullable String requestResponse(String commandAsString);
167 }