]> git.basschouten.com Git - openhab-addons.git/blob
33b7ae7a3cd73b177d22aaeb955e0301268893dc
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.openthermgateway.handler;
14
15 import java.util.concurrent.ScheduledFuture;
16 import java.util.concurrent.TimeUnit;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.openthermgateway.internal.ConnectionState;
21 import org.openhab.binding.openthermgateway.internal.DataItemGroup;
22 import org.openhab.binding.openthermgateway.internal.GatewayCommand;
23 import org.openhab.binding.openthermgateway.internal.GatewayCommandCode;
24 import org.openhab.binding.openthermgateway.internal.Message;
25 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayBindingConstants;
26 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayCallback;
27 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConfiguration;
28 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConnector;
29 import org.openhab.binding.openthermgateway.internal.OpenThermGatewaySocketConnector;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.QuantityType;
32 import org.openhab.core.library.unit.SIUnits;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.openhab.core.types.UnDefType;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * The {@link OpenThermGatewayHandler} is responsible for handling commands, which are
47  * sent to one of the channels.
48  *
49  * @author Arjen Korevaar - Initial contribution
50  */
51 @NonNullByDefault
52 public class OpenThermGatewayHandler extends BaseBridgeHandler implements OpenThermGatewayCallback {
53
54     private final Logger logger = LoggerFactory.getLogger(OpenThermGatewayHandler.class);
55
56     private @Nullable OpenThermGatewayConfiguration configuration;
57     private @Nullable OpenThermGatewayConnector connector;
58     private @Nullable ScheduledFuture<?> reconnectTask;
59
60     private @Nullable ConnectionState state;
61     private boolean autoReconnect = true;
62     private boolean disposing = false;
63
64     public OpenThermGatewayHandler(Bridge bridge) {
65         super(bridge);
66     }
67
68     @Override
69     public void initialize() {
70         logger.debug("Initializing OpenThermGateway handler for uid {}", getThing().getUID());
71
72         configuration = getConfigAs(OpenThermGatewayConfiguration.class);
73         logger.debug("Using configuration: {}", configuration);
74
75         disposing = false;
76         updateStatus(ThingStatus.UNKNOWN);
77         connect();
78     }
79
80     @Override
81     public void handleCommand(ChannelUID channelUID, Command command) {
82         logger.debug("Received command {} for channel {}", command, channelUID);
83
84         if (!(command instanceof RefreshType)) {
85             String channel = channelUID.getId();
86             String code = getGatewayCodeFromChannel(channel);
87
88             GatewayCommand gatewayCommand = null;
89
90             if (command instanceof OnOffType) {
91                 OnOffType onOff = (OnOffType) command;
92                 gatewayCommand = GatewayCommand.parse(code, onOff == OnOffType.ON ? "1" : "0");
93             }
94             if (command instanceof QuantityType<?>) {
95                 QuantityType<?> quantityType = ((QuantityType<?>) command).toUnit(SIUnits.CELSIUS);
96
97                 if (quantityType != null) {
98                     double value = quantityType.doubleValue();
99                     gatewayCommand = GatewayCommand.parse(code, Double.toString(value));
100                 }
101             }
102
103             if (gatewayCommand == null) {
104                 gatewayCommand = GatewayCommand.parse(code, command.toFullString());
105             }
106
107             sendCommand(gatewayCommand);
108
109             if (GatewayCommandCode.CONTROLSETPOINT.equals(code)) {
110                 if (gatewayCommand.getMessage().equals("0.0")) {
111                     updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT,
112                             UnDefType.UNDEF);
113                 }
114                 updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED,
115                         OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
116             } else if (GatewayCommandCode.CONTROLSETPOINT2.equals(code)) {
117                 if (gatewayCommand.getMessage().equals("0.0")) {
118                     updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT,
119                             UnDefType.UNDEF);
120                 }
121                 updateState(OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED,
122                         OnOffType.from(!gatewayCommand.getMessage().equals("0.0")));
123             }
124         }
125     }
126
127     public void sendCommand(GatewayCommand gatewayCommand) {
128         @Nullable
129         OpenThermGatewayConnector conn = connector;
130
131         if (conn != null && conn.isConnected()) {
132             conn.sendCommand(gatewayCommand);
133         } else {
134             logger.debug("Unable to send command {}: connector not connected", gatewayCommand.toFullString());
135         }
136     }
137
138     @Override
139     public void receiveMessage(Message message) {
140         scheduler.submit(() -> receiveMessageTask(message));
141     }
142
143     private void receiveMessageTask(Message message) {
144         int msgId = message.getID();
145
146         if (!DataItemGroup.DATAITEMGROUPS.containsKey(msgId)) {
147             logger.debug("Unsupported message id {}", msgId);
148             return;
149         }
150
151         for (Thing thing : getThing().getThings()) {
152             BaseDeviceHandler handler = (BaseDeviceHandler) thing.getHandler();
153
154             if (handler != null) {
155                 handler.receiveMessage(message);
156             }
157         }
158     }
159
160     @Override
161     public void connectionStateChanged(ConnectionState state) {
162         scheduler.submit(() -> connectionStateChangedTask(state));
163     }
164
165     private void connectionStateChangedTask(ConnectionState state) {
166         if (this.state != state) {
167             this.state = state;
168
169             switch (state) {
170                 case CONNECTED:
171                     updateStatus(ThingStatus.ONLINE);
172                     cancelAutoReconnect();
173                     break;
174                 case DISCONNECTED:
175                     if (!disposing) {
176                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
177                         autoReconnect();
178                     }
179                 default:
180             }
181         }
182     }
183
184     @Override
185     public void handleRemoval() {
186         logger.debug("Removing OpenThermGateway handler");
187         disconnect();
188         super.handleRemoval();
189     }
190
191     @Override
192     public void dispose() {
193         logger.debug("Disposing OpenThermGateway handler");
194         disposing = true;
195         disconnect();
196         super.dispose();
197     }
198
199     private void connect() {
200         @Nullable
201         OpenThermGatewayConfiguration config = configuration;
202
203         if (this.state == ConnectionState.CONNECTING) {
204             logger.debug("OpenThermGateway connector is already connecting");
205             return;
206         }
207
208         // Make sure everything is cleaned up before creating a new connection
209         disconnect();
210
211         if (config != null) {
212             connectionStateChanged(ConnectionState.INITIALIZING);
213
214             logger.debug("Starting OpenThermGateway connector");
215
216             autoReconnect = true;
217
218             OpenThermGatewayConnector conn = connector = new OpenThermGatewaySocketConnector(this, config);
219             conn.start();
220
221             logger.debug("OpenThermGateway connector started");
222         }
223     }
224
225     private void disconnect() {
226         @Nullable
227         OpenThermGatewayConnector conn = connector;
228
229         autoReconnect = false;
230
231         cancelAutoReconnect();
232
233         if (conn != null) {
234             conn.stop();
235             connector = null;
236         }
237     }
238
239     private void autoReconnect() {
240         @Nullable
241         OpenThermGatewayConfiguration config = configuration;
242
243         if (autoReconnect && config != null && config.connectionRetryInterval > 0) {
244             logger.debug("Scheduling to auto reconnect in {} seconds", config.connectionRetryInterval);
245             reconnectTask = scheduler.schedule(this::connect, config.connectionRetryInterval, TimeUnit.SECONDS);
246         }
247     }
248
249     private void cancelAutoReconnect() {
250         ScheduledFuture<?> localReconnectTask = reconnectTask;
251
252         if (localReconnectTask != null) {
253             if (!localReconnectTask.isDone()) {
254                 logger.debug("Cancelling auto reconnect task");
255                 localReconnectTask.cancel(true);
256             }
257
258             reconnectTask = null;
259         }
260     }
261
262     private @Nullable String getGatewayCodeFromChannel(String channel) throws IllegalArgumentException {
263         switch (channel) {
264             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_TEMPORARY:
265                 return GatewayCommandCode.TEMPERATURETEMPORARY;
266             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_CONSTANT:
267                 return GatewayCommandCode.TEMPERATURECONSTANT;
268             case OpenThermGatewayBindingConstants.CHANNEL_OUTSIDE_TEMPERATURE:
269                 return GatewayCommandCode.TEMPERATUREOUTSIDE;
270             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_DHW_SETPOINT:
271                 return GatewayCommandCode.SETPOINTWATER;
272             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_WATER_SETPOINT:
273                 return GatewayCommandCode.CONTROLSETPOINT;
274             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING_ENABLED:
275                 return GatewayCommandCode.CENTRALHEATING;
276             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_WATER_SETPOINT:
277                 return GatewayCommandCode.CONTROLSETPOINT2;
278             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_CENTRAL_HEATING2_ENABLED:
279                 return GatewayCommandCode.CENTRALHEATING2;
280             case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_VENTILATION_SETPOINT:
281                 return GatewayCommandCode.VENTILATIONSETPOINT;
282             case OpenThermGatewayBindingConstants.CHANNEL_SEND_COMMAND:
283                 return null;
284             default:
285                 throw new IllegalArgumentException(String.format("Unknown channel %s", channel));
286         }
287     }
288 }