]> git.basschouten.com Git - openhab-addons.git/blob
368d381b66025ed13755e7ad2f938bae18556895
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.Units;
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).toUnit(Units.KELVIN);
117                     if (quantity == null) {
118                         return;
119                     }
120                     int centiKelvin = quantity.multiply(new BigDecimal(100)).intValue();
121                     strUpdateValue = Integer.toString(centiKelvin);
122                 }
123             } else {
124                 // Not writable channel
125                 return;
126             }
127             if (strUpdateValue != "") {
128                 if (readDataJob != null) {
129                     // Re-schedule readDataJob to read device values after data write
130                     // Avoid re-scheduling job several times in case of subsequent data writes
131                     long timeToRead = readDataJob.getDelay(TimeUnit.MILLISECONDS);
132                     if ((!readDataJob.isDone()) && ((timeToRead < 2000) || (timeToRead > 5000))) {
133                         // Next read is not within the next 2 to 5 seconds, cancel read data job
134                         cancelReadDataJob();
135                         // Schedule read data job with 5 seconds initial delay
136                         scheduleReadDataJob(5);
137                     }
138                 }
139                 // Send command and process response
140                 valloxSocket.request(channelUID, strUpdateValue);
141             }
142         }
143     }
144
145     @Override
146     public void initialize() {
147         logger.debug("Initializing thing {}", getThing().getUID());
148
149         updateStatus(ThingStatus.UNKNOWN);
150
151         String ip = getConfigAs(ValloxMVConfig.class).getIp();
152         valloxSocket = new ValloxMVWebSocket(webSocketClient, ValloxMVHandler.this, ip);
153
154         logger.debug("Vallox MV IP address : {}", ip);
155         // Schedule read data job with 2 seconds initial delay
156         scheduleReadDataJob(2);
157
158         logger.debug("Thing {} initialized", getThing().getUID());
159     }
160
161     private void scheduleReadDataJob(int initialDelay) {
162         if (initialDelay < 0)
163             initialDelay = 0;
164
165         readDataInterval = getConfigAs(ValloxMVConfig.class).getUpdateinterval();
166         if (readDataInterval < 15)
167             readDataInterval = 60;
168
169         logger.debug("Data table request interval {} seconds, Request in {} seconds", readDataInterval, initialDelay);
170
171         readDataJob = scheduler.scheduleWithFixedDelay(() -> {
172             // Read all device values
173             valloxSocket.request(null, null);
174         }, initialDelay, readDataInterval, TimeUnit.SECONDS);
175     }
176
177     private void cancelReadDataJob() {
178         if (readDataJob != null) {
179             if (!readDataJob.isDone()) {
180                 readDataJob.cancel(true);
181                 logger.debug("Scheduled data table requests cancelled");
182             }
183         }
184     }
185
186     @Override
187     public void dispose() {
188         logger.debug("Disposing thing {}", getThing().getUID());
189         cancelReadDataJob();
190         logger.debug("Thing {} disposed", getThing().getUID());
191     }
192
193     @Override
194     protected void updateState(String strChannelName, State dt) {
195         super.updateState(strChannelName, dt);
196     }
197
198     @Override
199     protected void updateStatus(ThingStatus ts, ThingStatusDetail statusDetail) {
200         super.updateStatus(ts, statusDetail);
201     }
202
203     @Override
204     protected void updateStatus(ThingStatus ts) {
205         super.updateStatus(ts);
206     }
207 }