]> git.basschouten.com Git - openhab-addons.git/blob
32f2fac3799d63036795f28d4d5856947b8e5e01
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.valloxmv.internal;
14
15 import java.math.BigDecimal;
16 import java.util.concurrent.ScheduledFuture;
17 import java.util.concurrent.TimeUnit;
18
19 import javax.measure.quantity.Dimensionless;
20 import javax.measure.quantity.Temperature;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.eclipse.jetty.websocket.client.WebSocketClient;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.QuantityType;
27 import org.openhab.core.library.unit.SmartHomeUnits;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingStatus;
31 import org.openhab.core.thing.ThingStatusDetail;
32 import org.openhab.core.thing.binding.BaseThingHandler;
33 import org.openhab.core.types.Command;
34 import org.openhab.core.types.RefreshType;
35 import org.openhab.core.types.State;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * The {@link ValloxMVHandler} is responsible for handling commands, which are
41  * sent to one of the channels.
42  *
43  * @author Björn Brings - Initial contribution
44  */
45 @NonNullByDefault
46 public class ValloxMVHandler extends BaseThingHandler {
47
48     private final Logger logger = LoggerFactory.getLogger(ValloxMVHandler.class);
49     private @Nullable ScheduledFuture<?> readDataJob;
50     private @Nullable ValloxMVWebSocket valloxSocket;
51     private @Nullable WebSocketClient webSocketClient;
52
53     /**
54      * Refresh interval in seconds.
55      */
56     private int readDataInterval;
57
58     /**
59      * IP of vallox ventilation unit web interface.
60      */
61     public ValloxMVHandler(Thing thing, @Nullable WebSocketClient webSocketClient) {
62         super(thing);
63         this.webSocketClient = webSocketClient;
64     }
65
66     @SuppressWarnings({ "null", "unchecked" })
67     @Override
68     public void handleCommand(ChannelUID channelUID, Command command) {
69         if (valloxSocket == null) {
70             return;
71         }
72         if (command instanceof RefreshType) {
73             // We don't have Vallox device values in memory - we cannot update channel with value
74             // We can re-schedule readDataJob in case next read is more than 5 seconds away
75             if (readDataJob != null) {
76                 if ((!readDataJob.isDone()) && (readDataJob.getDelay(TimeUnit.MILLISECONDS) > 5000)) {
77                     // Next read is more than 5 seconds away, re-schedule
78                     // Cancel read data job
79                     cancelReadDataJob();
80                     // Schedule read data job with 2 seconds initial delay
81                     scheduleReadDataJob(2);
82                 }
83             }
84         } else {
85             String strUpdateValue = "";
86             if (ValloxMVBindingConstants.CHANNEL_STATE.equals(channelUID.getId())) {
87                 try {
88                     int cmd = Integer.parseInt(command.toString());
89                     if ((cmd == ValloxMVBindingConstants.STATE_FIREPLACE)
90                             || (cmd == ValloxMVBindingConstants.STATE_ATHOME)
91                             || (cmd == ValloxMVBindingConstants.STATE_AWAY)
92                             || (cmd == ValloxMVBindingConstants.STATE_BOOST)) {
93                         // logger.debug("Changing state to: {}", command);
94                         strUpdateValue = command.toString();
95                     }
96                 } catch (NumberFormatException nfe) {
97                     // Other commands like refresh
98                     return;
99                 }
100             } else if (ValloxMVBindingConstants.WRITABLE_CHANNELS_SWITCHES.contains(channelUID.getId())) {
101                 if (ValloxMVBindingConstants.CHANNEL_ONOFF.equals(channelUID.getId())) {
102                     // Vallox MV MODE: Normal mode = 0, Switch off = 5
103                     strUpdateValue = (OnOffType.ON.equals(command)) ? "0" : "5";
104                 } else {
105                     // Switches with ON = 1, OFF = 0
106                     strUpdateValue = (OnOffType.ON.equals(command)) ? "1" : "0";
107                 }
108             } else if (ValloxMVBindingConstants.WRITABLE_CHANNELS_DIMENSIONLESS.contains(channelUID.getId())) {
109                 if (command instanceof QuantityType) {
110                     QuantityType<Dimensionless> quantity = (QuantityType<Dimensionless>) command;
111                     strUpdateValue = Integer.toString(quantity.intValue());
112                 }
113             } else if (ValloxMVBindingConstants.WRITABLE_CHANNELS_TEMPERATURE.contains(channelUID.getId())) {
114                 if (command instanceof QuantityType) {
115                     // Convert temperature to centiKelvin (= (Celsius * 100) + 27315 )
116                     QuantityType<Temperature> quantity = ((QuantityType<Temperature>) command)
117                             .toUnit(SmartHomeUnits.KELVIN);
118                     if (quantity == null) {
119                         return;
120                     }
121                     int centiKelvin = quantity.multiply(new BigDecimal(100)).intValue();
122                     strUpdateValue = Integer.toString(centiKelvin);
123                 }
124             } else {
125                 // Not writable channel
126                 return;
127             }
128             if (strUpdateValue != "") {
129                 if (readDataJob != null) {
130                     // Re-schedule readDataJob to read device values after data write
131                     // Avoid re-scheduling job several times in case of subsequent data writes
132                     long timeToRead = readDataJob.getDelay(TimeUnit.MILLISECONDS);
133                     if ((!readDataJob.isDone()) && ((timeToRead < 2000) || (timeToRead > 5000))) {
134                         // Next read is not within the next 2 to 5 seconds, cancel read data job
135                         cancelReadDataJob();
136                         // Schedule read data job with 5 seconds initial delay
137                         scheduleReadDataJob(5);
138                     }
139                 }
140                 // Send command and process response
141                 valloxSocket.request(channelUID, strUpdateValue);
142             }
143         }
144     }
145
146     @Override
147     public void initialize() {
148         logger.debug("Initializing thing {}", getThing().getUID());
149
150         updateStatus(ThingStatus.UNKNOWN);
151
152         String ip = getConfigAs(ValloxMVConfig.class).getIp();
153         valloxSocket = new ValloxMVWebSocket(webSocketClient, ValloxMVHandler.this, ip);
154
155         logger.debug("Vallox MV IP address : {}", ip);
156         // Schedule read data job with 2 seconds initial delay
157         scheduleReadDataJob(2);
158
159         logger.debug("Thing {} initialized", getThing().getUID());
160     }
161
162     private void scheduleReadDataJob(int initialDelay) {
163         if (initialDelay < 0)
164             initialDelay = 0;
165
166         readDataInterval = getConfigAs(ValloxMVConfig.class).getUpdateinterval();
167         if (readDataInterval < 15)
168             readDataInterval = 60;
169
170         logger.debug("Data table request interval {} seconds, Request in {} seconds", readDataInterval, initialDelay);
171
172         readDataJob = scheduler.scheduleWithFixedDelay(() -> {
173             // Read all device values
174             valloxSocket.request(null, null);
175         }, initialDelay, readDataInterval, TimeUnit.SECONDS);
176     }
177
178     private void cancelReadDataJob() {
179         if (readDataJob != null) {
180             if (!readDataJob.isDone()) {
181                 readDataJob.cancel(true);
182                 logger.debug("Scheduled data table requests cancelled");
183             }
184         }
185     }
186
187     @Override
188     public void dispose() {
189         logger.debug("Disposing thing {}", getThing().getUID());
190         cancelReadDataJob();
191         logger.debug("Thing {} disposed", getThing().getUID());
192     }
193
194     @Override
195     protected void updateState(String strChannelName, State dt) {
196         super.updateState(strChannelName, dt);
197     }
198
199     @Override
200     protected void updateStatus(ThingStatus ts, ThingStatusDetail statusDetail) {
201         super.updateStatus(ts, statusDetail);
202     }
203
204     @Override
205     protected void updateStatus(ThingStatus ts) {
206         super.updateStatus(ts);
207     }
208 }