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.openthermgateway.handler;
15 import java.util.concurrent.TimeUnit;
17 import javax.measure.Unit;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.openthermgateway.OpenThermGatewayBindingConstants;
22 import org.openhab.binding.openthermgateway.internal.DataItem;
23 import org.openhab.binding.openthermgateway.internal.DataItemGroup;
24 import org.openhab.binding.openthermgateway.internal.GatewayCommand;
25 import org.openhab.binding.openthermgateway.internal.GatewayCommandCode;
26 import org.openhab.binding.openthermgateway.internal.Message;
27 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayCallback;
28 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConfiguration;
29 import org.openhab.binding.openthermgateway.internal.OpenThermGatewayConnector;
30 import org.openhab.binding.openthermgateway.internal.OpenThermGatewaySocketConnector;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.library.types.OnOffType;
33 import org.openhab.core.library.types.QuantityType;
34 import org.openhab.core.library.unit.SIUnits;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.ThingStatusDetail;
39 import org.openhab.core.thing.binding.BaseThingHandler;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.openhab.core.types.State;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 * The {@link OpenThermGatewayHandler} is responsible for handling commands, which are
48 * sent to one of the channels.
50 * @author Arjen Korevaar - Initial contribution
53 public class OpenThermGatewayHandler extends BaseThingHandler implements OpenThermGatewayCallback {
55 private final Logger logger = LoggerFactory.getLogger(OpenThermGatewayHandler.class);
57 private @Nullable OpenThermGatewayConfiguration config;
59 private @Nullable OpenThermGatewayConnector connector;
61 private boolean connecting = false;
63 private boolean explicitDisconnect = false;
65 public OpenThermGatewayHandler(Thing thing) {
70 public void initialize() {
71 logger.debug("Initializing OpenTherm Gateway handler for uid '{}'", getThing().getUID());
73 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Initializing");
75 config = getConfigAs(OpenThermGatewayConfiguration.class);
81 public void handleCommand(ChannelUID channelUID, Command command) {
82 logger.debug("Received channel: {}, command: {}", channelUID, command);
84 if (!(command instanceof RefreshType)) {
85 String channel = channelUID.getId();
86 String code = getGatewayCodeFromChannel(channel);
88 GatewayCommand gatewayCommand = null;
90 if (command instanceof QuantityType<?>) {
91 QuantityType<?> quantityType = ((QuantityType<?>) command).toUnit(SIUnits.CELSIUS);
93 if (quantityType != null) {
94 double value = quantityType.doubleValue();
95 gatewayCommand = GatewayCommand.parse(code, Double.toString(value));
99 if (gatewayCommand == null) {
100 gatewayCommand = GatewayCommand.parse(code, command.toFullString());
103 if (checkConnection()) {
105 OpenThermGatewayConnector conn = connector;
108 conn.sendCommand(gatewayCommand);
115 public void connecting() {
117 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Connecting");
121 public void connected() {
123 updateStatus(ThingStatus.ONLINE);
127 public void disconnected() {
129 OpenThermGatewayConnector conn = connector;
132 OpenThermGatewayConfiguration conf = config;
136 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Disconnected");
138 // retry connection if disconnect is not explicitly requested
139 if (conf != null && !explicitDisconnect && conf.connectionRetryInterval > 0) {
140 scheduler.schedule(() -> {
141 if (conn != null && !connecting && !conn.isConnected()) {
144 }, conf.connectionRetryInterval, TimeUnit.SECONDS);
149 public void receiveMessage(Message message) {
150 if (DataItemGroup.dataItemGroups.containsKey(message.getID())) {
151 DataItem[] dataItems = DataItemGroup.dataItemGroups.get(message.getID());
153 for (DataItem dataItem : dataItems) {
154 String channelId = dataItem.getSubject();
156 if (!OpenThermGatewayBindingConstants.SUPPORTED_CHANNEL_IDS.contains(channelId)) {
162 switch (dataItem.getDataType()) {
164 state = OnOffType.from(message.getBit(dataItem.getByteType(), dataItem.getBitPos()));
168 state = new DecimalType(message.getUInt(dataItem.getByteType()));
172 state = new DecimalType(message.getInt(dataItem.getByteType()));
175 float value = message.getFloat();
177 Unit<?> unit = dataItem.getUnit();
178 state = (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
185 logger.debug("Received update for channel '{}': {}", channelId, state);
186 updateState(channelId, state);
193 public void handleRemoval() {
194 logger.debug("Removing OpenTherm Gateway handler");
196 super.handleRemoval();
200 public void dispose() {
205 private boolean checkConnection() {
207 OpenThermGatewayConnector conn = connector;
209 if (conn != null && conn.isConnected()) {
216 private boolean connect() {
218 OpenThermGatewayConfiguration conf = config;
223 logger.debug("Starting OpenTherm Gateway connector");
225 explicitDisconnect = false;
227 connector = new OpenThermGatewaySocketConnector(this, conf.ipaddress, conf.port);
229 Thread thread = new Thread(connector, "OpenTherm Gateway Binding - socket listener thread");
230 thread.setDaemon(true);
233 logger.debug("OpenTherm Gateway connector started");
241 private void disconnect() {
243 OpenThermGatewayConnector conn = connector;
246 if (conn.isConnected()) {
247 logger.debug("Stopping OpenTherm Gateway connector");
249 explicitDisconnect = true;
257 private @Nullable String getGatewayCodeFromChannel(String channel) throws IllegalArgumentException {
259 case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_TEMPORARY:
260 return GatewayCommandCode.TemperatureTemporary;
261 case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_SETPOINT_CONSTANT:
262 return GatewayCommandCode.TemperatureConstant;
263 case OpenThermGatewayBindingConstants.CHANNEL_OUTSIDE_TEMPERATURE:
264 return GatewayCommandCode.TemperatureOutside;
265 case OpenThermGatewayBindingConstants.CHANNEL_OVERRIDE_DHW_SETPOINT:
266 return GatewayCommandCode.SetpointWater;
267 case OpenThermGatewayBindingConstants.CHANNEL_SEND_COMMAND:
270 throw new IllegalArgumentException(String.format("Unknown channel %s", channel));