]> git.basschouten.com Git - openhab-addons.git/blob
a62b09508df4807a3c5b011cfa4fd2dd42f8459a
[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.danfossairunit.internal;
14
15 import static org.openhab.binding.danfossairunit.internal.Commands.*;
16
17 import java.io.IOException;
18 import java.math.BigDecimal;
19 import java.math.RoundingMode;
20 import java.net.InetAddress;
21 import java.nio.charset.StandardCharsets;
22 import java.time.DateTimeException;
23 import java.time.ZoneId;
24 import java.time.ZonedDateTime;
25
26 import javax.measure.quantity.Dimensionless;
27 import javax.measure.quantity.Temperature;
28
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.openhab.core.library.types.DateTimeType;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.library.types.OnOffType;
33 import org.openhab.core.library.types.PercentType;
34 import org.openhab.core.library.types.QuantityType;
35 import org.openhab.core.library.types.StringType;
36 import org.openhab.core.library.unit.SIUnits;
37 import org.openhab.core.library.unit.Units;
38 import org.openhab.core.types.Command;
39
40 /**
41  * The {@link DanfossAirUnit} class represents the air unit device and build the commands to be sent by
42  * {@link DanfossAirUnitCommunicationController}
43  * 
44  * @author Ralf Duckstein - Initial contribution
45  * @author Robert Bach - heavy refactorings
46  */
47
48 @SuppressWarnings("SameParameterValue")
49 @NonNullByDefault
50 public class DanfossAirUnit {
51
52     private final DanfossAirUnitCommunicationController communicationController;
53
54     public DanfossAirUnit(InetAddress inetAddr, int port) {
55         this.communicationController = new DanfossAirUnitCommunicationController(inetAddr, port);
56     }
57
58     public void cleanUp() {
59         this.communicationController.disconnect();
60     }
61
62     private boolean getBoolean(byte[] operation, byte[] register) throws IOException {
63         return communicationController.sendRobustRequest(operation, register)[0] != 0;
64     }
65
66     private void setSetting(byte[] register, boolean value) throws IOException {
67         setSetting(register, value ? (byte) 1 : (byte) 0);
68     }
69
70     private short getWord(byte[] operation, byte[] register) throws IOException {
71         byte[] resultBytes = communicationController.sendRobustRequest(operation, register);
72         return (short) ((resultBytes[0] << 8) | (resultBytes[1] & 0xFF));
73     }
74
75     private byte getByte(byte[] operation, byte[] register) throws IOException {
76         return communicationController.sendRobustRequest(operation, register)[0];
77     }
78
79     private String getString(byte[] operation, byte[] register) throws IOException {
80         // length of the string is stored in the first byte
81         byte[] result = communicationController.sendRobustRequest(operation, register);
82         return new String(result, 1, result[0], StandardCharsets.US_ASCII);
83     }
84
85     private void set(byte[] operation, byte[] register, byte value) throws IOException {
86         byte[] valueArray = { value };
87         communicationController.sendRobustRequest(operation, register, valueArray);
88     }
89
90     private void set(byte[] operation, byte[] register, short value) throws IOException {
91         communicationController.sendRobustRequest(operation, register, shortToBytes(value));
92     }
93
94     private byte[] shortToBytes(short s) {
95         return new byte[] { (byte) ((s & 0xFF00) >> 8), (byte) (s & 0x00FF) };
96     }
97
98     private short getShort(byte[] operation, byte[] register) throws IOException {
99         byte[] result = communicationController.sendRobustRequest(operation, register);
100         return (short) ((result[0] << 8) + (result[1] & 0xff));
101     }
102
103     private float getTemperature(byte[] operation, byte[] register)
104             throws IOException, UnexpectedResponseValueException {
105         short shortTemp = getShort(operation, register);
106         float temp = ((float) shortTemp) / 100;
107         if (temp <= -274 || temp > 100) {
108             throw new UnexpectedResponseValueException(String.format("Invalid temperature: %s", temp));
109         }
110         return temp;
111     }
112
113     private ZonedDateTime getTimestamp(byte[] operation, byte[] register)
114             throws IOException, UnexpectedResponseValueException {
115         byte[] result = communicationController.sendRobustRequest(operation, register);
116         return asZonedDateTime(result);
117     }
118
119     private ZonedDateTime asZonedDateTime(byte[] data) throws UnexpectedResponseValueException {
120         int second = data[0];
121         int minute = data[1];
122         int hour = data[2] & 0x1f;
123         int day = data[3] & 0x1f;
124         int month = data[4];
125         int year = data[5] + 2000;
126         try {
127             return ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.systemDefault());
128         } catch (DateTimeException e) {
129             String msg = String.format("Ignoring invalid timestamp %s.%s.%s %s:%s:%s", day, month, year, hour, minute,
130                     second);
131             throw new UnexpectedResponseValueException(msg, e);
132         }
133     }
134
135     private static int asUnsignedByte(byte b) {
136         return b & 0xFF;
137     }
138
139     private static float asPercentByte(byte b) {
140         float f = asUnsignedByte(b);
141         return f * 100 / 255;
142     }
143
144     private void setSetting(byte[] register, short value) throws IOException {
145         byte[] valueArray = new byte[2];
146         valueArray[0] = (byte) (value >> 8);
147         valueArray[1] = (byte) value;
148
149         communicationController.sendRobustRequest(REGISTER_1_WRITE, register, valueArray);
150     }
151
152     public String getUnitName() throws IOException {
153         return getString(REGISTER_1_READ, UNIT_NAME);
154     }
155
156     public String getUnitSerialNumber() throws IOException {
157         return String.valueOf(getShort(REGISTER_4_READ, UNIT_SERIAL));
158     }
159
160     public StringType getMode() throws IOException {
161         return new StringType(Mode.values()[getByte(REGISTER_1_READ, MODE)].name());
162     }
163
164     public PercentType getManualFanSpeed() throws IOException {
165         return new PercentType(BigDecimal.valueOf(getByte(REGISTER_1_READ, MANUAL_FAN_SPEED_STEP) * 10));
166     }
167
168     public DecimalType getSupplyFanSpeed() throws IOException {
169         return new DecimalType(BigDecimal.valueOf(getWord(REGISTER_4_READ, SUPPLY_FAN_SPEED)));
170     }
171
172     public DecimalType getExtractFanSpeed() throws IOException {
173         return new DecimalType(BigDecimal.valueOf(getWord(REGISTER_4_READ, EXTRACT_FAN_SPEED)));
174     }
175
176     public PercentType getSupplyFanStep() throws IOException {
177         return new PercentType(BigDecimal.valueOf(getByte(REGISTER_4_READ, SUPPLY_FAN_STEP)));
178     }
179
180     public PercentType getExtractFanStep() throws IOException {
181         return new PercentType(BigDecimal.valueOf(getByte(REGISTER_4_READ, EXTRACT_FAN_STEP)));
182     }
183
184     public OnOffType getBoost() throws IOException {
185         return getBoolean(REGISTER_1_READ, BOOST) ? OnOffType.ON : OnOffType.OFF;
186     }
187
188     public OnOffType getNightCooling() throws IOException {
189         return getBoolean(REGISTER_1_READ, NIGHT_COOLING) ? OnOffType.ON : OnOffType.OFF;
190     }
191
192     public OnOffType getBypass() throws IOException {
193         return getBoolean(REGISTER_1_READ, BYPASS) ? OnOffType.ON : OnOffType.OFF;
194     }
195
196     public QuantityType<Dimensionless> getHumidity() throws IOException {
197         BigDecimal value = BigDecimal.valueOf(asPercentByte(getByte(REGISTER_1_READ, HUMIDITY)));
198         return new QuantityType<>(value.setScale(1, RoundingMode.HALF_UP), Units.PERCENT);
199     }
200
201     public QuantityType<Temperature> getRoomTemperature() throws IOException, UnexpectedResponseValueException {
202         return getTemperatureAsDecimalType(REGISTER_1_READ, ROOM_TEMPERATURE);
203     }
204
205     public QuantityType<Temperature> getRoomTemperatureCalculated()
206             throws IOException, UnexpectedResponseValueException {
207         return getTemperatureAsDecimalType(REGISTER_0_READ, ROOM_TEMPERATURE_CALCULATED);
208     }
209
210     public QuantityType<Temperature> getOutdoorTemperature() throws IOException, UnexpectedResponseValueException {
211         return getTemperatureAsDecimalType(REGISTER_1_READ, OUTDOOR_TEMPERATURE);
212     }
213
214     public QuantityType<Temperature> getSupplyTemperature() throws IOException, UnexpectedResponseValueException {
215         return getTemperatureAsDecimalType(REGISTER_4_READ, SUPPLY_TEMPERATURE);
216     }
217
218     public QuantityType<Temperature> getExtractTemperature() throws IOException, UnexpectedResponseValueException {
219         return getTemperatureAsDecimalType(REGISTER_4_READ, EXTRACT_TEMPERATURE);
220     }
221
222     public QuantityType<Temperature> getExhaustTemperature() throws IOException, UnexpectedResponseValueException {
223         return getTemperatureAsDecimalType(REGISTER_4_READ, EXHAUST_TEMPERATURE);
224     }
225
226     private QuantityType<Temperature> getTemperatureAsDecimalType(byte[] operation, byte[] register)
227             throws IOException, UnexpectedResponseValueException {
228         BigDecimal value = BigDecimal.valueOf(getTemperature(operation, register));
229         return new QuantityType<>(value.setScale(1, RoundingMode.HALF_UP), SIUnits.CELSIUS);
230     }
231
232     public DecimalType getBatteryLife() throws IOException {
233         return new DecimalType(BigDecimal.valueOf(asUnsignedByte(getByte(REGISTER_1_READ, BATTERY_LIFE))));
234     }
235
236     public DecimalType getFilterLife() throws IOException {
237         return new DecimalType(BigDecimal.valueOf(asPercentByte(getByte(REGISTER_1_READ, FILTER_LIFE))));
238     }
239
240     public DateTimeType getCurrentTime() throws IOException, UnexpectedResponseValueException {
241         ZonedDateTime timestamp = getTimestamp(REGISTER_1_READ, CURRENT_TIME);
242         return new DateTimeType(timestamp);
243     }
244
245     public PercentType setManualFanSpeed(Command cmd) throws IOException {
246         return setPercentTypeRegister(cmd, MANUAL_FAN_SPEED_STEP);
247     }
248
249     private PercentType setPercentTypeRegister(Command cmd, byte[] register) throws IOException {
250         if (cmd instanceof PercentType) {
251             byte value = (byte) ((((PercentType) cmd).intValue() + 5) / 10);
252             set(REGISTER_1_WRITE, register, value);
253         }
254         return new PercentType(BigDecimal.valueOf(getByte(REGISTER_1_READ, register) * 10));
255     }
256
257     private OnOffType setOnOffTypeRegister(Command cmd, byte[] register) throws IOException {
258         if (cmd instanceof OnOffType) {
259             set(REGISTER_1_WRITE, register, OnOffType.ON.equals(cmd) ? (byte) 1 : (byte) 0);
260         }
261         return getBoolean(REGISTER_1_READ, register) ? OnOffType.ON : OnOffType.OFF;
262     }
263
264     private StringType setStringTypeRegister(Command cmd, byte[] register) throws IOException {
265         if (cmd instanceof StringType) {
266             byte value = (byte) (Mode.valueOf(cmd.toString()).ordinal());
267             set(REGISTER_1_WRITE, register, value);
268         }
269
270         return new StringType(Mode.values()[getByte(REGISTER_1_READ, register)].name());
271     }
272
273     public StringType setMode(Command cmd) throws IOException {
274         return setStringTypeRegister(cmd, MODE);
275     }
276
277     public OnOffType setBoost(Command cmd) throws IOException {
278         return setOnOffTypeRegister(cmd, BOOST);
279     }
280
281     public OnOffType setNightCooling(Command cmd) throws IOException {
282         return setOnOffTypeRegister(cmd, NIGHT_COOLING);
283     }
284
285     public OnOffType setBypass(Command cmd) throws IOException {
286         return setOnOffTypeRegister(cmd, BYPASS);
287     }
288 }