]> git.basschouten.com Git - openhab-addons.git/commitdiff
[intesis] - added IntesisBox support (#8694)
authorHans-Jörg Merk <github@hmerk.de>
Sat, 24 Oct 2020 18:17:56 +0000 (20:17 +0200)
committerGitHub <noreply@github.com>
Sat, 24 Oct 2020 18:17:56 +0000 (11:17 -0700)
* Intesis Binding - added IntesisBox support

Signed-off-by: Hans-Jörg Merk <github@hmerk.de>
18 files changed:
bundles/org.openhab.binding.intesis/README.md
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisBindingConstants.java
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisConfiguration.java [deleted file]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisHandlerFactory.java
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisHomeModeEnum.java [deleted file]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxChangeListener.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxMessage.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxSocketApi.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisHomeHttpApi.java
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/MessageReceivedEvent.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/config/IntesisBoxConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/config/IntesisHomeConfiguration.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/enums/IntesisHomeModeEnum.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/handler/IntesisBoxHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/handler/IntesisHomeHandler.java
bundles/org.openhab.binding.intesis/src/main/resources/OH-INF/i18n/intesis.properties
bundles/org.openhab.binding.intesis/src/main/resources/OH-INF/i18n/intesis_de.properties
bundles/org.openhab.binding.intesis/src/main/resources/OH-INF/thing/thing-types.xml

index b77b6e9b789511463bad8521b33796d2d29deaef..b3567c0f9fd79d4a0d5ab05bfbc38c0f0463f98f 100644 (file)
@@ -1,7 +1,6 @@
 # Intesis Binding
 
-This binding connects to WiFi [IntesisHome](http://www.intesishome.com/) devices using their local REST Api.
-It does actually not support [IntesisBox](http://www.intesisbox.com/) devices but support is planned in upcoming version.
+This binding connects to WiFi [IntesisHome](https://www.intesis.com/products/cloud-solutions/ac-cloud-control) devices using their local REST Api and to [IntesisBox](https://www.intesis.com/products/ac-interfaces/wifi-gateways) devices using TCP connection.
 
 
 
@@ -9,9 +8,10 @@ It does actually not support [IntesisBox](http://www.intesisbox.com/) devices bu
 
 This binding only supports one thing type:
 
-| Thing       | Thing Type | Description                     |
-|------------ |------------|---------------------------------|
-| intesisHome | Thing      | Represents a single WiFi device |
+| Thing       | Thing Type | Description                                 |
+|-------------|------------|---------------------------------------------|
+| intesisHome | Thing      | Represents a single IntesisHome WiFi device |
+| intesisBox  | Thing      | Represents a single IntesisBox WiFi device  |
 
 ## Discovery
 
@@ -19,35 +19,40 @@ Intesis devices do not support auto discovery.
 
 ## Thing Configuration
 
-The binding needs two configuration parameters.
+The binding uses the following configuration parameters.
 
-| Parameter | Description                                       |
-|-----------|---------------------------------------------------|
-| ipAddress | IP-Address of the              device             |
-| password  | Password to login to the local webserver of device |
+| Parameter | Valid for ThingType | Description                                                    |
+|-----------|---------------------|----------------------------------------------------------------|
+| ipAddress | Both                | IP-Address of the device                                       |
+| password  | IntesisHome         | Password to login to the local webserver of IntesisHome device |
+| port      | IntesisBox          | TCP port to connect to IntesisBox device, defaults to 3310     |
 
 
 ## Channels
 
-| Channel ID         | Item Type          | Description                                 | Possible Values           |
-|--------------------|--------------------|---------------------------------------------|---------------------------|
-| power              | Switch             | Turns power on/off for your climate system. | ON, OFF                   |
-| mode               | String             | The heating/cooling mode.                   | AUTO,HEAT,DRY,FAN,COOL    |
-| fanSpeed           | String             | Fan speed (if applicable)                   | AUTO,1-10                 |
-| vanesUpDown        | String             | Control of up/down vanes (if applicable)    | AUTO,1-9,SWING,SWIRL,WIDE |
-| vanesUpDown        | String             | Control of left/right vanes (if applicable) | AUTO,1-9,SWING,SWIRL,WIDE |
-| targetTemperature  | Number:Temperature | The currently set target temperature.       |                           |
-| ambientTemperature | Number:Temperature | (Readonly) The ambient air temperature.     |                           |
-| outdoorTemperature | Number:Temperature | (Readonly) The outdoor air temperature.     |                           |
+| Channel ID         | Item Type          | Description                                            | Possible Values                                         |
+|--------------------|--------------------|--------------------------------------------------------|---------------------------------------------------------|
+| power              | Switch             | Turns power on/off for your climate system.            | ON,OFF                                                  |
+| mode               | String             | The heating/cooling mode.                              | AUTO,HEAT,DRY,FAN,COOL                                  |
+| fanSpeed           | String             | Fan speed (if applicable)                              | AUTO,1-10                                               |
+| vanesUpDown        | String             | Control of up/down vanes (if applicable)               | AUTO,1-9,SWING,SWIRL,WIDE                               |
+| vanesUpDown        | String             | Control of left/right vanes (if applicable)            | AUTO,1-9,SWING,SWIRL,WIDE                               |
+| targetTemperature  | Number:Temperature | The currently set target temperature (if applicable)   | range between 18°C and 30°C                             |
+| ambientTemperature | Number:Temperature | (Readonly) The ambient air temperature (if applicable) |                                                         |
+| outdoorTemperature | Number:Temperature | (Readonly) The outdoor air temperature (if applicable) |                                                         |
+| errorStatus        | String             | (Readonly) The error status of the device              | OK,ERR                                                  |
+| errorCode          | String             | (Readonly) The error code if an error encountered      | not documented                                          |
+| wifiSignal         | Number             | (Readonly) WiFi signal strength (IntesisBox only)      | 4=excellent, 3=good, 2=not string, 1=unreliable, 0=none |
 
 Note that individual A/C units may not support all channels, or all possible values for those channels.
 
 The binding will add all supported channels and possible values on first thing initialization and list them as thing properties.
-If new channels or values might be supported after firmware upgrades, deleting the thing and reading is necessary.
-For example, not all A/C units have controllable vanes. Or fan speed may be limited to 1-4, instead of all of 1-9.
-The set point temperature is also limited to a device specific range. For set point temperature, sending an invalid value
+If new channels or values might be supported after firmware upgrades, deleting the thing and re-adding is necessary.
+For example, not all A/C units have controllable vanes or fan speed may be limited to 1-4, instead of all of 1-9.
+The target temperature is also limited to a device specific range. For target temperature, sending an invalid value
 will cause it to choose the minimum/maximum allowable value as appropriate. The device will also round it to
 whatever step size it supports. For all other channels, invalid values are ignored.
+IntesisBox firmware 1.3.3 reports temperatures by full degrees only (e.g. 23.0) even if a half degree (e.g. 23.5) was set.
 
 ## Full Example
 
@@ -55,8 +60,9 @@ The binding can be fully setup from the UI but if you decide to use files here i
 
 **Things**
 
-```intesisHome.things
+```
 Thing intesis:intesisHome:acOffice "AC Unit Adapter" @ "AC" [ipAddress="192.168.1.100", password="xxxxx"]
+Thing intesis:intesisBox:acOffice  "AC Unit Adapter" @ "AC" [ipAddress="192.168.1.100", port=3310]
 ```
 
 **Items**
@@ -89,4 +95,3 @@ sitemap intesishome label="My AC control" {
     }
 }
 ```
-
index e90a8178db56e44bd8fc4553fe022ee09b328d5a..4503e96d728aab9b212f9ae39a6eaf8935538381 100644 (file)
@@ -31,6 +31,7 @@ public class IntesisBindingConstants {
 
     // List of all Thing Type UIDs
     public static final ThingTypeUID THING_TYPE_INTESISHOME = new ThingTypeUID(BINDING_ID, "intesisHome");
+    public static final ThingTypeUID THING_TYPE_INTESISBOX = new ThingTypeUID(BINDING_ID, "intesisBox");
 
     // List of all Channel ids
     public static final String CHANNEL_TYPE_POWER = "power";
@@ -41,4 +42,7 @@ public class IntesisBindingConstants {
     public static final String CHANNEL_TYPE_TARGETTEMP = "targetTemperature";
     public static final String CHANNEL_TYPE_AMBIENTTEMP = "ambientTemperature";
     public static final String CHANNEL_TYPE_OUTDOORTEMP = "outdoorTemperature";
+    public static final String CHANNEL_TYPE_ERRORCODE = "errorCode";
+    public static final String CHANNEL_TYPE_ERRORSTATUS = "errorStatus";
+    public static final String CHANNEL_TYPE_RSSI = "wifiSignal";
 }
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisConfiguration.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisConfiguration.java
deleted file mode 100644 (file)
index 3186025..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) 2010-2020 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.intesis.internal;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-/**
- * The {@link IntesisConfiguration} class contains fields mapping thing configuration parameters.
- *
- * @author Hans-Jörg Merk - Initial contribution
- */
-@NonNullByDefault
-public class IntesisConfiguration {
-    public String ipAddress = "";
-    public String password = "";
-}
index 1bee55fad4ff0e8815ef2ddaabc8011853f28a58..fd48f81372c2d6388f4f9aa34dfc411edeb2aed8 100644 (file)
  */
 package org.openhab.binding.intesis.internal;
 
-import static org.openhab.binding.intesis.internal.IntesisBindingConstants.THING_TYPE_INTESISHOME;
+import static org.openhab.binding.intesis.internal.IntesisBindingConstants.*;
 
 import java.util.Collections;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.intesis.internal.handler.IntesisBoxHandler;
 import org.openhab.binding.intesis.internal.handler.IntesisHomeHandler;
 import org.openhab.core.io.net.http.HttpClientFactory;
 import org.openhab.core.thing.Thing;
@@ -48,7 +51,8 @@ public class IntesisHandlerFactory extends BaseThingHandlerFactory {
     private final HttpClient httpClient;
     private final IntesisDynamicStateDescriptionProvider intesisStateDescriptionProvider;
 
-    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_INTESISHOME);
+    private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
+            .unmodifiableSet(Stream.of(THING_TYPE_INTESISHOME, THING_TYPE_INTESISBOX).collect(Collectors.toSet()));
 
     @Activate
     public IntesisHandlerFactory(@Reference HttpClientFactory httpClientFactory, ComponentContext componentContext,
@@ -69,10 +73,13 @@ public class IntesisHandlerFactory extends BaseThingHandlerFactory {
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
         if (THING_TYPE_INTESISHOME.equals(thingTypeUID)) {
-            logger.debug("Creating a IntesisHomeHandler for thing '{}'", thing.getUID());
             return new IntesisHomeHandler(thing, httpClient, intesisStateDescriptionProvider);
         }
 
+        if (THING_TYPE_INTESISBOX.equals(thingTypeUID)) {
+            return new IntesisBoxHandler(thing, intesisStateDescriptionProvider);
+        }
+
         return null;
     }
 }
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisHomeModeEnum.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/IntesisHomeModeEnum.java
deleted file mode 100644 (file)
index c63ddb6..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2010-2020 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.intesis.internal;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-
-/**
- * The {@link IntesisModeEnum) contains informations for translating device modes into internally used numbers.
- *
- * @author Hans-Jörg Merk - Initial contribution
- */
-@NonNullByDefault
-public enum IntesisHomeModeEnum {
-    AUTO(0),
-    HEAT(1),
-    DRY(2),
-    FAN(3),
-    COOL(4);
-
-    private final int mode;
-
-    private IntesisHomeModeEnum(int mode) {
-        this.mode = mode;
-    }
-
-    public int getMode() {
-        return mode;
-    }
-}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxChangeListener.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxChangeListener.java
new file mode 100644 (file)
index 0000000..a61ad69
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.thing.ThingStatus;
+
+/**
+ * The {@link IntesisBoxChangeListener} is in interface for a IntesisBox changed consumer
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public interface IntesisBoxChangeListener {
+    /**
+     * This method will be called in case a message was received.
+     *
+     */
+    void messageReceived(String messageLine);
+
+    /**
+     * This method will be called in case the connection status has changed.
+     *
+     */
+    void connectionStatusChanged(ThingStatus status, @Nullable String message);
+}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxMessage.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxMessage.java
new file mode 100644 (file)
index 0000000..cfe2642
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.api;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * @author Cody Cutrer - Initial contribution
+ */
+@NonNullByDefault
+public class IntesisBoxMessage {
+    public static final String ID = "ID";
+    public static final String INFO = "INFO";
+    public static final String SET = "SET";
+    public static final String CHN = "CHN";
+    public static final String GET = "GET";
+    public static final String LOGIN = "LOGIN";
+    public static final String LOGOUT = "LOGOUT";
+    public static final String CFG = "CFG";
+    public static final String LIMITS = "LIMITS";
+    public static final String DISCOVER = "DISCOVER";
+
+    private static final Pattern REGEX = Pattern.compile("^([^,]+)(?:,(\\d+))?:([^,]+),([A-Z0-9.,\\[\\]]+)$");
+
+    @SuppressWarnings("unused")
+    private final String acNum;
+    private final String command;
+    private final String function;
+    private final String value;
+
+    private IntesisBoxMessage(String command, String acNum, String function, String value) {
+        this.command = command;
+        this.acNum = acNum;
+        this.function = function;
+        this.value = value;
+    }
+
+    public String getCommand() {
+        return command;
+    }
+
+    public String getFunction() {
+        return function;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public List<String> getLimitsValue() {
+        return Arrays.asList(value.substring(1, value.length() - 1).split(","));
+    }
+
+    public static @Nullable IntesisBoxMessage parse(String message) {
+        Matcher m = REGEX.matcher(message);
+        if (!m.find()) {
+            return null;
+        }
+
+        return new IntesisBoxMessage(m.group(1), m.group(2), m.group(3), m.group(4));
+    }
+}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxSocketApi.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/IntesisBoxSocketApi.java
new file mode 100644 (file)
index 0000000..c087532
--- /dev/null
@@ -0,0 +1,214 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.api;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.intesis.internal.handler.IntesisBoxHandler;
+import org.openhab.core.thing.ThingStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class handling the Socket connections.
+ *
+ * @author Cody Cutrer - Initial contribution
+ * @author Hans-Jörg Merk - Moved Socket to it's own class
+ */
+@NonNullByDefault
+public class IntesisBoxSocketApi {
+
+    private final Logger logger = LoggerFactory.getLogger(IntesisBoxSocketApi.class);
+
+    private final String ipAddress;
+    private final int port;
+    private final String readerThreadName;
+
+    private @Nullable IntesisSocket tcpSocket = null;
+    private @Nullable OutputStreamWriter tcpOutput = null;
+    private @Nullable BufferedReader tcpInput = null;
+
+    private @Nullable IntesisBoxChangeListener changeListener;
+
+    private boolean connected = false;
+
+    public IntesisBoxSocketApi(final String ipAddress, final int port, final String readerThreadName) {
+        this.ipAddress = ipAddress;
+        this.port = port;
+        this.readerThreadName = readerThreadName;
+    }
+
+    private class IntesisSocket {
+        final Socket socket;
+
+        public IntesisSocket() throws UnknownHostException, IOException {
+            socket = new Socket();
+            SocketAddress tcpSocketAddress = new InetSocketAddress(ipAddress, port);
+            socket.connect(tcpSocketAddress);
+        }
+
+        public void close() throws IOException {
+            socket.close();
+        }
+    }
+
+    public void openConnection() throws IOException {
+        closeConnection();
+
+        IntesisBoxChangeListener listener = this.changeListener;
+        IntesisSocket localSocket = tcpSocket = new IntesisSocket();
+        tcpOutput = new OutputStreamWriter(localSocket.socket.getOutputStream(), StandardCharsets.US_ASCII);
+        tcpInput = new BufferedReader(
+                new InputStreamReader(localSocket.socket.getInputStream(), StandardCharsets.US_ASCII));
+
+        Thread tcpListener = new Thread(new TCPListener());
+        tcpListener.setName(readerThreadName);
+        tcpListener.setDaemon(true);
+        tcpListener.start();
+
+        setConnected(true);
+        if (listener != null) {
+            listener.connectionStatusChanged(ThingStatus.ONLINE, null);
+        }
+    }
+
+    public void closeConnection() {
+        try {
+            IntesisSocket localSocket = tcpSocket;
+            OutputStreamWriter localOutput = tcpOutput;
+            BufferedReader localInput = tcpInput;
+
+            if (localSocket != null) {
+                localSocket.close();
+                localSocket = null;
+            }
+            if (localInput != null) {
+                localInput.close();
+                localInput = null;
+            }
+            if (localOutput != null) {
+                localOutput.close();
+                localOutput = null;
+            }
+            setConnected(false);
+        } catch (IOException ioException) {
+            logger.debug("closeConnection(): Unable to close connection - {}", ioException.getMessage());
+        } catch (Exception exception) {
+            logger.debug("closeConnection(): Error closing connection - {}", exception.getMessage());
+        }
+    }
+
+    private class TCPListener implements Runnable {
+
+        /**
+         * Run method. Runs the MessageListener thread
+         */
+        @Override
+        public void run() {
+            while (isConnected()) {
+                String message = read();
+                readMessage(message);
+            }
+        }
+    }
+
+    public void addIntesisBoxChangeListener(IntesisBoxChangeListener listener) {
+        if (this.changeListener == null) {
+            this.changeListener = listener;
+        }
+    }
+
+    private void write(String data) {
+        IntesisBoxChangeListener listener = this.changeListener;
+        try {
+            OutputStreamWriter localOutput = tcpOutput;
+
+            if (localOutput != null) {
+                localOutput.write(data);
+                localOutput.flush();
+            }
+        } catch (IOException ioException) {
+            setConnected(false);
+            if (listener != null) {
+                listener.connectionStatusChanged(ThingStatus.OFFLINE, ioException.getMessage());
+            }
+        }
+    }
+
+    public String read() {
+        String message = "";
+        try {
+            BufferedReader localInput = tcpInput;
+            if (localInput != null) {
+                message = localInput.readLine();
+            }
+        } catch (IOException ioException) {
+            setConnected(false);
+        }
+        return message;
+    }
+
+    public void readMessage(String message) {
+        IntesisBoxChangeListener listener = this.changeListener;
+
+        if (listener != null && !message.isEmpty()) {
+            listener.messageReceived(message);
+        }
+    }
+
+    public void sendAlive() {
+        write("GET,1:*\r\n");
+    }
+
+    public void sendId() {
+        write("ID\r\n");
+    }
+
+    public void sendLimitsQuery() {
+        write("LIMITS:*\r\n");
+    }
+
+    public void sendCommand(String function, String value) {
+        String data = String.format("SET,1:%s,%s\r\n", function, value);
+        write(data);
+    }
+
+    public void sendQuery(String function) {
+        String data = String.format("GET,1:%s\r\n", function);
+        write(data);
+    }
+
+    public boolean isConnected() {
+        return this.connected;
+    }
+
+    public void setConnected(boolean connected) {
+        this.connected = connected;
+    }
+
+    public void removeIntesisBoxChangeListener(IntesisBoxHandler intesisBoxHandler) {
+        if (this.changeListener != null) {
+            this.changeListener = null;
+        }
+    }
+}
index 7bbeb095b1864d0c360657bc53e103589cca5292..5880234a3a1ece45ead80f7124c6c1420c418a48 100644 (file)
@@ -23,7 +23,7 @@ import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.util.StringContentProvider;
 import org.eclipse.jetty.http.HttpHeader;
-import org.openhab.binding.intesis.internal.IntesisConfiguration;
+import org.openhab.binding.intesis.internal.config.IntesisHomeConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,7 +40,7 @@ public class IntesisHomeHttpApi {
     private final Logger logger = LoggerFactory.getLogger(IntesisHomeHttpApi.class);
     private final HttpClient httpClient;
 
-    public IntesisHomeHttpApi(IntesisConfiguration config, HttpClient httpClient) {
+    public IntesisHomeHttpApi(IntesisHomeConfiguration config, HttpClient httpClient) {
         this.httpClient = httpClient;
     }
 
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/MessageReceivedEvent.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/api/MessageReceivedEvent.java
new file mode 100644 (file)
index 0000000..aea7747
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link DataPointChangedEvent} is an event container for data point changes
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class MessageReceivedEvent {
+    protected String message;
+
+    public MessageReceivedEvent(Object source, String message) {
+        this.message = message;
+    }
+
+    /**
+     * Gets the data-point of the event.
+     *
+     */
+    @Nullable
+    public String getMessage() {
+        return this.message;
+    }
+}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/config/IntesisBoxConfiguration.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/config/IntesisBoxConfiguration.java
new file mode 100644 (file)
index 0000000..21ec814
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link IntesisBoxConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class IntesisBoxConfiguration {
+    public String ipAddress = "";
+    public int port;
+}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/config/IntesisHomeConfiguration.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/config/IntesisHomeConfiguration.java
new file mode 100644 (file)
index 0000000..58fa954
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link IntesisHomeConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public class IntesisHomeConfiguration {
+    public String ipAddress = "";
+    public String password = "";
+}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/enums/IntesisHomeModeEnum.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/enums/IntesisHomeModeEnum.java
new file mode 100644 (file)
index 0000000..7aae91c
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.enums;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link IntesisModeEnum) contains informations for translating device modes into internally used numbers.
+ *
+ * @author Hans-Jörg Merk - Initial contribution
+ */
+@NonNullByDefault
+public enum IntesisHomeModeEnum {
+    AUTO(0),
+    HEAT(1),
+    DRY(2),
+    FAN(3),
+    COOL(4);
+
+    private final int mode;
+
+    private IntesisHomeModeEnum(int mode) {
+        this.mode = mode;
+    }
+
+    public int getMode() {
+        return mode;
+    }
+}
diff --git a/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/handler/IntesisBoxHandler.java b/bundles/org.openhab.binding.intesis/src/main/java/org/openhab/binding/intesis/internal/handler/IntesisBoxHandler.java
new file mode 100644 (file)
index 0000000..ee56499
--- /dev/null
@@ -0,0 +1,394 @@
+/**
+ * Copyright (c) 2010-2020 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.intesis.internal.handler;
+
+import static org.openhab.binding.intesis.internal.IntesisBindingConstants.*;
+import static org.openhab.binding.intesis.internal.api.IntesisBoxMessage.*;
+import static org.openhab.core.thing.Thing.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import javax.measure.quantity.Temperature;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.intesis.internal.IntesisDynamicStateDescriptionProvider;
+import org.openhab.binding.intesis.internal.api.IntesisBoxChangeListener;
+import org.openhab.binding.intesis.internal.api.IntesisBoxMessage;
+import org.openhab.binding.intesis.internal.api.IntesisBoxSocketApi;
+import org.openhab.binding.intesis.internal.config.IntesisBoxConfiguration;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.thing.binding.builder.ChannelBuilder;
+import org.openhab.core.thing.binding.builder.ThingBuilder;
+import org.openhab.core.thing.type.ChannelKind;
+import org.openhab.core.thing.type.ChannelTypeUID;
+import org.openhab.core.types.Command;
+import org.openhab.core.types.RefreshType;
+import org.openhab.core.types.StateOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link IntesisBoxHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Cody Cutrer - Initial contribution
+ * @author Rocky Amatulli - additions to include id message handling, dynamic channel options based on limits.
+ * @author Hans-Jörg Merk - refactored for openHAB 3.0 compatibility
+ *
+ */
+@NonNullByDefault
+public class IntesisBoxHandler extends BaseThingHandler implements IntesisBoxChangeListener {
+
+    private final Logger logger = LoggerFactory.getLogger(IntesisBoxHandler.class);
+    private @Nullable IntesisBoxSocketApi intesisBoxSocketApi;
+
+    private final Map<String, String> properties = new HashMap<>();
+    private final Map<String, List<String>> limits = new HashMap<>();
+
+    private final IntesisDynamicStateDescriptionProvider intesisStateDescriptionProvider;
+
+    private IntesisBoxConfiguration config = new IntesisBoxConfiguration();
+
+    private double minTemp = 0.0, maxTemp = 0.0;
+
+    private boolean hasProperties = false;
+
+    private @Nullable ScheduledFuture<?> pollingTask;
+
+    public IntesisBoxHandler(Thing thing, IntesisDynamicStateDescriptionProvider intesisStateDescriptionProvider) {
+        super(thing);
+        this.intesisStateDescriptionProvider = intesisStateDescriptionProvider;
+    }
+
+    @Override
+    public void initialize() {
+        config = getConfigAs(IntesisBoxConfiguration.class);
+
+        if (!config.ipAddress.isEmpty()) {
+
+            updateStatus(ThingStatus.UNKNOWN);
+            scheduler.submit(() -> {
+
+                String readerThreadName = "OH-binding-" + getThing().getUID().getAsString();
+
+                IntesisBoxSocketApi intesisLocalApi = intesisBoxSocketApi = new IntesisBoxSocketApi(config.ipAddress,
+                        config.port, readerThreadName);
+                intesisLocalApi.addIntesisBoxChangeListener(this);
+                try {
+                    intesisLocalApi.openConnection();
+                    intesisLocalApi.sendId();
+                    intesisLocalApi.sendLimitsQuery();
+                    intesisLocalApi.sendAlive();
+
+                } catch (IOException e) {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+                    return;
+                }
+                updateStatus(ThingStatus.ONLINE);
+            });
+            pollingTask = scheduler.scheduleWithFixedDelay(this::polling, 3, 45, TimeUnit.SECONDS);
+        } else {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No IP address specified)");
+        }
+    }
+
+    @Override
+    public void dispose() {
+        final ScheduledFuture<?> pollingTask = this.pollingTask;
+
+        IntesisBoxSocketApi api = this.intesisBoxSocketApi;
+
+        if (pollingTask != null) {
+            pollingTask.cancel(true);
+            this.pollingTask = null;
+        }
+        if (api != null) {
+            api.closeConnection();
+            api.removeIntesisBoxChangeListener(this);
+        }
+        super.dispose();
+    }
+
+    private synchronized void polling() {
+        IntesisBoxSocketApi api = this.intesisBoxSocketApi;
+        if (api != null) {
+            if (!api.isConnected()) {
+                try {
+                    api.openConnection();
+                } catch (IOException e) {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
+                }
+            }
+            api.sendAlive();
+            api.sendId();
+        }
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        IntesisBoxSocketApi api = this.intesisBoxSocketApi;
+        if (api != null) {
+            if (!api.isConnected()) {
+                logger.trace("Sending command failed, not connected");
+                return;
+            }
+            if (command instanceof RefreshType) {
+                logger.trace("Refresh channel {}", channelUID.getId());
+                api.sendQuery(channelUID.getId());
+                return;
+            }
+        }
+        String value = "";
+        String function = "";
+        switch (channelUID.getId()) {
+            case CHANNEL_TYPE_POWER:
+                if (command instanceof OnOffType) {
+                    function = "ONOFF";
+                    value = command == OnOffType.ON ? "ON" : "OFF";
+                }
+                break;
+            case CHANNEL_TYPE_TARGETTEMP:
+                if (command instanceof QuantityType) {
+                    QuantityType<?> celsiusTemperature = (QuantityType<?>) command;
+                    celsiusTemperature = celsiusTemperature.toUnit(SIUnits.CELSIUS);
+                    if (celsiusTemperature != null) {
+                        double doubleValue = celsiusTemperature.doubleValue();
+                        logger.trace("targetTemp double value = {}", doubleValue);
+                        doubleValue = Math.max(minTemp, Math.min(maxTemp, doubleValue));
+                        value = String.format("%.0f", doubleValue * 10);
+                        function = "SETPTEMP";
+                        logger.trace("targetTemp raw string = {}", value);
+                    }
+                }
+                break;
+            case CHANNEL_TYPE_MODE:
+                function = "MODE";
+                value = command.toString();
+                break;
+            case CHANNEL_TYPE_FANSPEED:
+                function = "FANSP";
+                value = command.toString();
+                break;
+            case CHANNEL_TYPE_VANESUD:
+                function = "VANEUD";
+                value = command.toString();
+                break;
+            case CHANNEL_TYPE_VANESLR:
+                function = "VANELR";
+                value = command.toString();
+                break;
+        }
+        if (!value.isEmpty() || function.isEmpty()) {
+            if (api != null) {
+                logger.trace("Sending command {} to function {}", value, function);
+                api.sendCommand(function, value);
+            } else {
+                logger.warn("Sending command failed, could not get API");
+            }
+        }
+    }
+
+    private void populateProperties(String[] value) {
+        properties.put(PROPERTY_VENDOR, "Intesis");
+        properties.put(PROPERTY_MODEL_ID, value[0]);
+        properties.put(PROPERTY_MAC_ADDRESS, value[1]);
+        properties.put("ipAddress", value[2]);
+        properties.put("protocol", value[3]);
+        properties.put(PROPERTY_FIRMWARE_VERSION, value[4]);
+        properties.put("hostname", value[6]);
+        updateProperties(properties);
+        hasProperties = true;
+    }
+
+    private void receivedUpdate(String function, String receivedValue) {
+        String value = receivedValue;
+        logger.trace("receivedUpdate(): {} {}", function, value);
+        switch (function) {
+            case "ONOFF":
+                updateState(CHANNEL_TYPE_POWER, OnOffType.from(value));
+                break;
+
+            case "SETPTEMP":
+                if (value.equals("32768")) {
+                    value = "0";
+                }
+                updateState(CHANNEL_TYPE_TARGETTEMP,
+                        new QuantityType<Temperature>(Double.valueOf(value) / 10.0d, SIUnits.CELSIUS));
+                break;
+            case "AMBTEMP":
+                if (Double.valueOf(value).isNaN()) {
+                    value = "0";
+                }
+                updateState(CHANNEL_TYPE_AMBIENTTEMP,
+                        new QuantityType<Temperature>(Double.valueOf(value) / 10.0d, SIUnits.CELSIUS));
+                break;
+            case "MODE":
+                updateState(CHANNEL_TYPE_MODE, new StringType(value));
+                break;
+            case "FANSP":
+                updateState(CHANNEL_TYPE_FANSPEED, new StringType(value));
+                break;
+            case "VANEUD":
+                updateState(CHANNEL_TYPE_VANESUD, new StringType(value));
+                break;
+            case "VANELR":
+                updateState(CHANNEL_TYPE_VANESLR, new StringType(value));
+                break;
+            case "ERRCODE":
+                properties.put("errorCode", value);
+                updateProperties(properties);
+                break;
+            case "ERRSTATUS":
+                properties.put("errorStatus", value);
+                updateProperties(properties);
+                if ("ERR".equals(value)) {
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                            "device reported an error");
+                }
+                break;
+        }
+    }
+
+    private void handleMessage(String data) {
+        logger.debug("handleMessage(): Message received - {}", data);
+        if (data.equals("ACK") || data.equals("")) {
+            return;
+        }
+        if (data.startsWith(ID + ':')) {
+            String[] value = data.substring(3).split(",");
+            if (!hasProperties) {
+                populateProperties(value);
+            }
+            DecimalType signalStrength = mapSignalStrength(Integer.parseInt(value[5]));
+            updateState(CHANNEL_TYPE_RSSI, signalStrength);
+            return;
+        }
+        IntesisBoxMessage message = IntesisBoxMessage.parse(data);
+        if (message != null) {
+            switch (message.getCommand()) {
+                case LIMITS:
+                    logger.debug("handleMessage(): Limits received - {}", data);
+                    String function = message.getFunction();
+                    if (function.equals("SETPTEMP")) {
+                        List<Double> limits = message.getLimitsValue().stream().map(l -> Double.valueOf(l) / 10.0d)
+                                .collect(Collectors.toList());
+                        if (limits.size() == 2) {
+                            minTemp = limits.get(0);
+                            maxTemp = limits.get(1);
+                        }
+                        logger.trace("Property target temperatures {} added", message.getValue());
+                        properties.put("targetTemperature limits", "[" + minTemp + "," + maxTemp + "]");
+                        addChannel(CHANNEL_TYPE_TARGETTEMP, "Number:Temperature");
+                    } else {
+                        switch (function) {
+                            case "MODE":
+                                properties.put("supported modes", message.getValue());
+                                limits.put(CHANNEL_TYPE_MODE, message.getLimitsValue());
+                                addChannel(CHANNEL_TYPE_MODE, "String");
+                                break;
+                            case "FANSP":
+                                properties.put("supported fan levels", message.getValue());
+                                limits.put(CHANNEL_TYPE_FANSPEED, message.getLimitsValue());
+                                addChannel(CHANNEL_TYPE_FANSPEED, "String");
+                                break;
+                            case "VANEUD":
+                                properties.put("supported vane up/down modes", message.getValue());
+                                limits.put(CHANNEL_TYPE_VANESUD, message.getLimitsValue());
+                                addChannel(CHANNEL_TYPE_VANESUD, "String");
+                                break;
+                            case "VANELR":
+                                properties.put("supported vane left/right modes", message.getValue());
+                                limits.put(CHANNEL_TYPE_VANESLR, message.getLimitsValue());
+                                addChannel(CHANNEL_TYPE_VANESLR, "String");
+                                break;
+                        }
+                    }
+                    updateProperties(properties);
+                    break;
+                case CHN:
+                    receivedUpdate(message.getFunction(), message.getValue());
+                    break;
+            }
+        }
+    }
+
+    public void addChannel(String channelId, String itemType) {
+        if (thing.getChannel(channelId) == null) {
+            logger.trace("Channel '{}' for UID to be added", channelId);
+            ThingBuilder thingBuilder = editThing();
+            final ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, channelId);
+            Channel channel = ChannelBuilder.create(new ChannelUID(getThing().getUID(), channelId), itemType)
+                    .withType(channelTypeUID).withKind(ChannelKind.STATE).build();
+            thingBuilder.withChannel(channel);
+            updateThing(thingBuilder.build());
+
+            if (limits.containsKey(channelId)) {
+                List<StateOption> options = new ArrayList<>();
+                for (String mode : limits.get(channelId)) {
+                    options.add(new StateOption(mode,
+                            mode.substring(0, 1).toUpperCase() + mode.substring(1).toLowerCase()));
+                }
+                intesisStateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), channelId),
+                        options);
+            }
+        }
+    }
+
+    @Override
+    public void messageReceived(String messageLine) {
+        logger.trace("messageReceived() : {}", messageLine);
+        handleMessage(messageLine);
+    }
+
+    @Override
+    public void connectionStatusChanged(ThingStatus status, @Nullable String message) {
+        if (message != null) {
+            this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
+        }
+        this.updateStatus(status);
+    }
+
+    public static DecimalType mapSignalStrength(int dbm) {
+        int strength = -1;
+        if (dbm > -60) {
+            strength = 4;
+        } else if (dbm > -70) {
+            strength = 3;
+        } else if (dbm > -80) {
+            strength = 2;
+        } else if (dbm > -90) {
+            strength = 1;
+        } else {
+            strength = 0;
+        }
+        return new DecimalType(strength);
+    }
+}
index 9dbb2e26a3a983d3ba88c02e767c5f2a5e754372..194a50db15c6ea9a56abc2fce3bbac45d14b10dc 100644 (file)
@@ -29,10 +29,10 @@ import java.util.stream.Collectors;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.jetty.client.HttpClient;
-import org.openhab.binding.intesis.internal.IntesisConfiguration;
 import org.openhab.binding.intesis.internal.IntesisDynamicStateDescriptionProvider;
-import org.openhab.binding.intesis.internal.IntesisHomeModeEnum;
 import org.openhab.binding.intesis.internal.api.IntesisHomeHttpApi;
+import org.openhab.binding.intesis.internal.config.IntesisHomeConfiguration;
+import org.openhab.binding.intesis.internal.enums.IntesisHomeModeEnum;
 import org.openhab.binding.intesis.internal.gson.IntesisHomeJSonDTO.Data;
 import org.openhab.binding.intesis.internal.gson.IntesisHomeJSonDTO.Datapoints;
 import org.openhab.binding.intesis.internal.gson.IntesisHomeJSonDTO.Descr;
@@ -83,7 +83,7 @@ public class IntesisHomeHandler extends BaseThingHandler {
 
     private final Gson gson = new Gson();
 
-    private IntesisConfiguration config = new IntesisConfiguration();
+    private IntesisHomeConfiguration config = new IntesisHomeConfiguration();
 
     private @Nullable ScheduledFuture<?> refreshJob;
 
@@ -97,7 +97,7 @@ public class IntesisHomeHandler extends BaseThingHandler {
     @Override
     public void initialize() {
         updateStatus(ThingStatus.UNKNOWN);
-        config = getConfigAs(IntesisConfiguration.class);
+        config = getConfigAs(IntesisHomeConfiguration.class);
         if (config.ipAddress.isEmpty() && config.password.isEmpty()) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "IP-Address and password not set");
             return;
@@ -336,7 +336,7 @@ public class IntesisHomeHandler extends BaseThingHandler {
                                     break;
                             }
                         }
-                        properties.put("Supported modes", opModes.toString());
+                        properties.put("supported modes", opModes.toString());
                         channelId = CHANNEL_TYPE_MODE;
                         addChannel(channelId, itemType, opModes);
                         break;
@@ -349,7 +349,7 @@ public class IntesisHomeHandler extends BaseThingHandler {
                                 fanLevels.add(fanString);
                             }
                         }
-                        properties.put("Supported fan levels", fanLevels.toString());
+                        properties.put("supported fan levels", fanLevels.toString());
                         channelId = CHANNEL_TYPE_FANSPEED;
                         addChannel(channelId, itemType, fanLevels);
                         break;
@@ -372,12 +372,12 @@ public class IntesisHomeHandler extends BaseThingHandler {
                         switch (datapoint.uid) {
                             case 5:
                                 channelId = CHANNEL_TYPE_VANESUD;
-                                properties.put("Supported vane up/down modes", swingModes.toString());
+                                properties.put("supported vane up/down modes", swingModes.toString());
                                 addChannel(channelId, itemType, swingModes);
                                 break;
                             case 6:
                                 channelId = CHANNEL_TYPE_VANESLR;
-                                properties.put("Supported vane left/right modes", swingModes.toString());
+                                properties.put("supported vane left/right modes", swingModes.toString());
                                 addChannel(channelId, itemType, swingModes);
                                 break;
                         }
index cf808f1770fe20ff3e6f6d0326ef49367627c8a6..2a04e56a09a754090c9d0dd588b59b40a67d48ef 100644 (file)
@@ -29,7 +29,7 @@ channel-type.intesis.ambientTemperature.label = Ambient Temperature
 channel-type.intesis.ambientTemperature.description = Shows actual room temperature.
 channel-type.intesis.outdoorTemperature.label = Outdoor Temperature
 channel-type.intesis.outdoorTemperature.description = Shows actual outdoor temperature.
-channel-type.intesis.fanSpeed.label = Wind Speed
+channel-type.intesis.fanSpeed.label = Fan Speed
 channel-type.intesis.fanSpeed.description = Sets the fan speed on the Air conditioner.
 channel-type.intesis.fanSpeed.state.option.auto = Auto
 channel-type.intesis.vanesUpDown.label = Vertical Swing Mode
@@ -40,3 +40,7 @@ channel-type.intesis.vanes.option.auto = AUTO
 channel-type.intesis.vanes.option.swing = Swing
 channel-type.intesis.vanes.option.swirl = Swirl
 channel-type.intesis.vanes.option.wide = Wide
+channel-type.intesis.errorCode.label = Error Code
+channel-type.intesis.errorCode.description = Shows the Air Conditioners error code if an error was found.
+channel-type.intesis.errorStatus.label = Error Status
+channel-type.intesis.errorStatus.description = Indicates if the Air Conditioner has encountered an error.
index de2be2f9cda982d7229ff037189edfbcdfb1859d..323f31bb55ce14ad706dd8e1f79e7adf4515fa1f 100644 (file)
@@ -40,3 +40,8 @@ channel-type.intesis.vanes.option.auto = Auto
 channel-type.intesis.vanes.option.swing = Schwingen
 channel-type.intesis.vanes.option.swirl = Pulsieren
 channel-type.intesis.vanes.option.wide = Breit
+channel-type.intesis.errorCode.label = Fehlercode
+channel-type.intesis.errorCode.description = Zeigt im Fehlerzustand den Fehlercode an.
+channel-type.intesis.errorStatus.label = Fehlerstatus
+channel-type.intesis.errorStatus.description = Zeigt an, ob sich der Air Conditioner im Zustand "Fehler" befindet.
+
index 25405263519145692e3d14b861eda63872da305c..f8bd16002aa58050e0fda01678a81560701afb92 100644 (file)
                        </parameter>
                </config-description>
        </thing-type>
+
+       <thing-type id="intesisBox">
+               <label>IntesisBox Adapter</label>
+               <description>Represents a single IntesisBox adapter on the network, connected to an A/C unit.</description>
+               <channels>
+                       <channel id="power" typeId="system.power"/>
+                       <channel id="wifiSignal" typeId="system.signal-strength"/>
+                       <channel id="ambientTemperature" typeId="ambientTemperature"/>
+                       <channel id="errorCode" typeId="errorCode"/>
+                       <channel id="errorStatus" typeId="errorStatus"/>
+               </channels>
+               <config-description>
+                       <parameter name="ipAddress" type="text" required="true">
+                               <label>@text/thing-type.config.intesis.ipAddress.label</label>
+                               <description>@text/thing-type.config.intesis.ipAddress.description</description>
+                               <context>network-address</context>
+                       </parameter>
+                       <parameter name="port" type="integer" required="true">
+                               <label>Port</label>
+                               <description>The TCP port to the IntesisBox.</description>
+                               <default>3310</default>
+                       </parameter>
+               </config-description>
+       </thing-type>
+
+       <channel-type id="ambientTemperature">
+               <item-type>Number:Temperature</item-type>
+               <label>@text/channel-type.intesis.ambientTemperature.label</label>
+               <description>@text/channel-type.intesis.ambientTemperature.description</description>
+               <state pattern="%d %unit%" readOnly="true"></state>
+       </channel-type>
+
+       <channel-type id="errorCode">
+               <item-type>String</item-type>
+               <label>@text/channel-type.intesis.errorCode.label</label>
+               <description>@text/channel-type.intesis.errorCode.description</description>
+       </channel-type>
+
+       <channel-type id="errorStatus">
+               <item-type>String</item-type>
+               <label>@text/channel-type.intesis.errorStatus.label</label>
+               <description>@text/channel-type.intesis.errorStatus.description</description>
+       </channel-type>
+
 </thing:thing-descriptions>