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