]> git.basschouten.com Git - openhab-addons.git/commitdiff
[touchwand]- Added support for AlarmSensor and WallController (#8933)
authorRoie Geron <roie.geron@gmail.com>
Mon, 16 Nov 2020 23:44:03 +0000 (01:44 +0200)
committerGitHub <noreply@github.com>
Mon, 16 Nov 2020 23:44:03 +0000 (15:44 -0800)
* Added support for AlarmSensor and WallController

Signed-off-by: Roie Geron <roie.geron@gmail.com>
19 files changed:
bundles/org.openhab.binding.touchwand/README.md
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandAlarmSensorHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandBaseUnitHandler.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandBindingConstants.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandHandlerFactory.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandRestClient.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandWallControllerHandler.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandWebSockets.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/discovery/TouchWandUnitDiscoveryService.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/AlarmSensorUnitDataDeserializer.java [new file with mode: 0644]
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/Csc.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/CurrStatus.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandAlarmSensorCurrentStatus.java [new file with mode: 0644]
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnitData.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnitDataAlarmSensor.java [new file with mode: 0644]
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnitDataWallController.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnitFromJson.java
bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnknownTypeUnitData.java [new file with mode: 0644]
bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/thing/alarmsensor.xml [new file with mode: 0644]

index 0d850c4119b338a423331d318d9ae1176c3ea701..2bd15d6917e2748009beb39c9ee39223d54e345e 100644 (file)
@@ -8,18 +8,19 @@ TouchWand products are compatible with most major Z-Wave products, IP controlled
 
 ## Supported Things
 
-This binding supports switches, shutters dimmers and wall controllers configured in Touchwand Wanderfullâ„¢ Hub Controller.
+This binding supports switches, shutters dimmers alarm sensors and wall controllers configured in Touchwand Wanderfullâ„¢ Hub Controller.
 
-## Control 
+## Control and Status 
 
 1. **switch**  - control - ON/OFF
 2. **shutter** - control - UP/DOWN/STOP
 3. **dimmer**  - control - ON/OFF/BRIGHTNESS
 4. **wallcontroller** - control - LONG/SHORT
+5. **alarmsensor** - status channels depend on alarm sensor type
 
 ## Discovery
 
-After adding TouchWand Hub the auto discovery will add all switches dimmers and shutters to the inbox.
+After adding TouchWand Hub the auto discovery will add all switches dimmers alarm sensors and shutters to the inbox.
 
 ## Bridge Configuration
 
@@ -29,7 +30,7 @@ After adding TouchWand Hub the auto discovery will add all switches dimmers and
 |-------------------|-----------------------------------------------------------------------|---------|----------|
 | username          | Touchwand hub username                                                | string  | yes      |
 | password          | Touchwand hub password                                                | string  | yes      |
-| ipAddress         | Touchwand hub hotname or IP address                                   | string  | yes      |
+| ipAddress         | Touchwand hub hostname or IP address                                  | string  | yes      |
 | port              | Management port (default 80)                                          | integer | no       |
 | statusrefresh     | Unit status refresh interval in seconds                               | integer | no       |
 | addSecondaryUnits | If the controller is primary, add secondary controllers units as well | bool    | no       |
@@ -40,6 +41,29 @@ After adding TouchWand Hub the auto discovery will add all switches dimmers and
 
 No thing configuration is needed
 
+## Channels 
+
+note **Touchwand Wanderfullâ„¢** supports various types of alarm sensors such as water leak, door/window sensor and motion sensor.
+Alarm Sensor thing represents a generic sensor, relevant sensor channels will be displayed once a sensor is added as a Thing.
+
+
+| Channel Type ID   | Item Type          | Description                                                                                                                             
+|-------------------|--------------------|-----------------------------------------------------------------------|
+| switch            | Switch             | This channel supports switching the device on and off.                |
+| shutter           | Rollershutter      | This channel controls the shutter position                            |
+| brightness        | Dimmer             | This channel supports adjusting the brightness value.                 |
+| illumination      | Number:Illuminance | This channel shows the current illuminance measured by the sensor.    |
+| temperature       | Number:Temperature | This channel shows the current temperature measured by the sensor.    |
+| leak              | Switch             | This channel alert when water leak is detected by the sensor          |
+| motion            | Switch             | This channel alert when motion detected by the sensor.                |
+| isOpen            | Contact            | This channel shows the status of Door/Window sensor.                  |
+| battery_level     | Number             | This channel shows the battery level.                                 |
+| battery_low       | Switch             | This channel indicates whether the battery is low or not.             |
+| wallaction        | String             | This channel indicate SHORT or LONG wallcontroller button pressed     |
+
+
+
+
 ## Full Example
 
 ### touchwand.things
diff --git a/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandAlarmSensorHandler.java b/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/TouchWandAlarmSensorHandler.java
new file mode 100644 (file)
index 0000000..bab478f
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * 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.touchwand.internal;
+
+import static org.openhab.binding.touchwand.internal.TouchWandBindingConstants.*;
+
+import java.util.ArrayList;
+
+import javax.measure.quantity.Illuminance;
+import javax.measure.quantity.Temperature;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.touchwand.internal.dto.TouchWandAlarmSensorCurrentStatus.BinarySensorEvent;
+import org.openhab.binding.touchwand.internal.dto.TouchWandAlarmSensorCurrentStatus.Sensor;
+import org.openhab.binding.touchwand.internal.dto.TouchWandUnitData;
+import org.openhab.binding.touchwand.internal.dto.TouchWandUnitDataAlarmSensor;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.OpenClosedType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.SmartHomeUnits;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.binding.builder.ThingBuilder;
+import org.openhab.core.types.Command;
+
+/**
+ * The {@link TouchWandAlarmSensorHandler} is responsible for handling command for Alarm Sensor unit
+ *
+ *
+ * @author Roie Geron - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class TouchWandAlarmSensorHandler extends TouchWandBaseUnitHandler {
+
+    private static final int BATT_LEVEL_LOW = 20;
+    private static final int BATT_LEVEL_LOW_HYS = 5;
+
+    private boolean isBatteryLow = false;
+    private boolean isFirstUpdateTouchWandUnitState = true;
+
+    public TouchWandAlarmSensorHandler(Thing thing) {
+        super(thing);
+    }
+
+    @Override
+    void updateTouchWandUnitState(TouchWandUnitData unitData) {
+        if (unitData instanceof TouchWandUnitDataAlarmSensor) {
+            TouchWandUnitDataAlarmSensor sensor = (TouchWandUnitDataAlarmSensor) unitData;
+            if (isFirstUpdateTouchWandUnitState) {
+                removeUnsupportedChannels(sensor);
+                isFirstUpdateTouchWandUnitState = false;
+            }
+            updateBatteryLevel(sensor);
+            updateIllumination(sensor);
+            updateChannelLeak(sensor);
+            updateChannelDoorWindow(sensor);
+            updateChannelMotion(sensor);
+            updateChannelTemperature(sensor);
+        } else {
+            logger.warn("updateTouchWandUnitState incompatible TouchWandUnitData instance");
+        }
+    }
+
+    @Override
+    void touchWandUnitHandleCommand(Command command) {
+    }
+
+    void updateBatteryLevel(TouchWandUnitDataAlarmSensor unitData) {
+        Integer battLevel = unitData.getCurrStatus().getBatt();
+        updateState(CHANNEL_BATTERY_LEVEL, new DecimalType(battLevel));
+        int lowThreshold = isBatteryLow ? BATT_LEVEL_LOW + BATT_LEVEL_LOW_HYS : BATT_LEVEL_LOW;
+        boolean lowBattery = (battLevel <= lowThreshold);
+        updateState(CHANNEL_BATTERY_LOW, OnOffType.from(lowBattery));
+        isBatteryLow = lowBattery;
+    }
+
+    void updateIllumination(TouchWandUnitDataAlarmSensor unitData) {
+        for (Sensor sensor : unitData.getCurrStatus().getSensorsStatus()) {
+            if (sensor.type == SENSOR_TYPE_LUMINANCE) {
+                updateState(CHANNEL_ILLUMINATION, new QuantityType<Illuminance>(sensor.value, SmartHomeUnits.LUX));
+            }
+        }
+    }
+
+    void updateChannelLeak(TouchWandUnitDataAlarmSensor unitData) {
+        for (BinarySensorEvent bSensor : unitData.getCurrStatus().getbSensorsStatus()) {
+            if (bSensor.sensorType == SENSOR_TYPE_LEAK) {
+                boolean isLeak = bSensor.sensor.state;
+                updateState(CHANNEL_LEAK, OnOffType.from(isLeak));
+            }
+        }
+    }
+
+    void updateChannelDoorWindow(TouchWandUnitDataAlarmSensor unitData) {
+        for (BinarySensorEvent bSensor : unitData.getCurrStatus().getbSensorsStatus()) {
+            if (bSensor.sensorType == SENSOR_TYPE_DOOR_WINDOW) {
+                boolean isOpen = bSensor.sensor.state;
+                OpenClosedType myOpenClose;
+                myOpenClose = isOpen ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
+                updateState(CHANNEL_DOORWINDOW, myOpenClose);
+            }
+        }
+    }
+
+    void updateChannelMotion(TouchWandUnitDataAlarmSensor unitData) {
+        for (BinarySensorEvent bSensor : unitData.getCurrStatus().getbSensorsStatus()) {
+            if (bSensor.sensorType == SENSOR_TYPE_MOTION) {
+                boolean hasMotion = bSensor.sensor.state;
+                updateState(CHANNEL_MOTION, OnOffType.from(hasMotion));
+            }
+        }
+    }
+
+    void updateChannelTemperature(TouchWandUnitDataAlarmSensor unitData) {
+        for (Sensor sensor : unitData.getCurrStatus().getSensorsStatus()) {
+            if (sensor.type == SENSOR_TYPE_TEMPERATURE) {
+                updateState(CHANNEL_TEMPERATURE, new QuantityType<Temperature>(sensor.value, SIUnits.CELSIUS));
+            }
+        }
+    }
+
+    void removeUnsupportedChannels(TouchWandUnitDataAlarmSensor unitData) {
+        ArrayList<Channel> toBeRemovedChannels = new ArrayList<>(thing.getChannels());
+
+        for (BinarySensorEvent bSensor : unitData.getCurrStatus().getbSensorsStatus()) {
+            switch (bSensor.sensorType) {
+                case SENSOR_TYPE_MOTION:
+                    toBeRemovedChannels.remove(thing.getChannel(CHANNEL_MOTION));
+                    break;
+                case SENSOR_TYPE_DOOR_WINDOW:
+                    toBeRemovedChannels.remove(thing.getChannel(CHANNEL_DOORWINDOW));
+                    break;
+                case SENSOR_TYPE_LEAK:
+                    Channel channel = thing.getChannel(CHANNEL_LEAK);
+                    toBeRemovedChannels.remove(channel);
+                    break;
+            }
+        }
+
+        for (Sensor sensor : unitData.getCurrStatus().getSensorsStatus()) {
+            switch (sensor.type) {
+                case SENSOR_TYPE_TEMPERATURE:
+                    toBeRemovedChannels.remove(thing.getChannel(CHANNEL_TEMPERATURE));
+                    break;
+                case SENSOR_TYPE_LUMINANCE:
+                    toBeRemovedChannels.remove(thing.getChannel(CHANNEL_ILLUMINATION));
+                    break;
+            }
+        }
+
+        if (unitData.getHasBattery()) {
+            toBeRemovedChannels.remove(thing.getChannel(CHANNEL_BATTERY_LEVEL));
+            toBeRemovedChannels.remove(thing.getChannel(CHANNEL_BATTERY_LOW));
+        }
+
+        ThingBuilder thingBuilder = editThing();
+        thingBuilder.withoutChannels(toBeRemovedChannels);
+        updateThing(thingBuilder.build());
+    }
+}
index 61703e5362e9ce3ff918267c9e9fea2702f6c9b4..3c8b252bb809a101c7a76808dd2ec2dbfab05c1d 100644 (file)
@@ -15,10 +15,12 @@ package org.openhab.binding.touchwand.internal;
 import static org.openhab.binding.touchwand.internal.TouchWandBindingConstants.*;
 
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.touchwand.internal.dto.TouchWandUnitData;
+import org.openhab.binding.touchwand.internal.dto.TouchWandUnitFromJson;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -31,10 +33,6 @@ import org.openhab.core.types.RefreshType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
-import com.google.gson.JsonParser;
-
 /**
  * The {@link TouchWandBaseUnitHandler} is responsible for handling commands and status updates
  * for TouchWand units. This is an abstract class , units should implement the specific command
@@ -46,9 +44,10 @@ import com.google.gson.JsonParser;
 @NonNullByDefault
 public abstract class TouchWandBaseUnitHandler extends BaseThingHandler implements TouchWandUnitUpdateListener {
 
+    private static final int UNITS_STATUS_UPDATE_DELAY_SEC = 1;
     protected final Logger logger = LoggerFactory.getLogger(TouchWandBaseUnitHandler.class);
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_SHUTTER, THING_TYPE_SWITCH,
-            THING_TYPE_WALLCONTROLLER, THING_TYPE_DIMMER);
+            THING_TYPE_WALLCONTROLLER, THING_TYPE_DIMMER, THING_TYPE_ALARMSENSOR);
     protected String unitId = "";
 
     protected @Nullable TouchWandBridgeHandler bridgeHandler;
@@ -60,7 +59,10 @@ public abstract class TouchWandBaseUnitHandler extends BaseThingHandler implemen
     @Override
     public void handleCommand(ChannelUID channelUID, Command command) {
         if (command instanceof RefreshType) {
-            // updateTouchWandUnitState(getUnitState(unitId));
+            TouchWandUnitData myUnitData = getUnitState(unitId);
+            if (myUnitData != null) {
+                updateTouchWandUnitState(myUnitData);
+            }
         } else {
             touchWandUnitHandleCommand(command);
         }
@@ -98,47 +100,34 @@ public abstract class TouchWandBaseUnitHandler extends BaseThingHandler implemen
         }
 
         updateStatus(ThingStatus.UNKNOWN);
-        scheduler.execute(() -> {
+        scheduler.schedule(() -> {
             boolean thingReachable = false;
             if (myTmpBridgeHandler != null) {
                 String response = myTmpBridgeHandler.touchWandClient.cmdGetUnitById(unitId);
                 thingReachable = !response.isEmpty();
                 if (thingReachable) {
                     updateStatus(ThingStatus.ONLINE);
+                    updateTouchWandUnitState(TouchWandUnitFromJson.parseResponse(response));
                 } else {
                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
                 }
             }
-        });
+        }, UNITS_STATUS_UPDATE_DELAY_SEC, TimeUnit.SECONDS);
     }
 
-    @SuppressWarnings("unused") // not used at the moment till touchWand state in hub will be fixed
-    private int getUnitState(String unitId) {
-        int status = 0;
-
+    private @Nullable TouchWandUnitData getUnitState(String unitId) {
         TouchWandBridgeHandler touchWandBridgeHandler = bridgeHandler;
+
         if (touchWandBridgeHandler == null) {
-            return status;
+            return null;
         }
 
         String response = touchWandBridgeHandler.touchWandClient.cmdGetUnitById(unitId);
-        if (!response.isEmpty()) {
-            return status;
+        if (response.isEmpty()) {
+            return null;
         }
 
-        JsonParser jsonParser = new JsonParser();
-
-        try {
-            JsonObject unitObj = jsonParser.parse(response).getAsJsonObject();
-            status = unitObj.get("currStatus").getAsInt();
-            if (!this.getThing().getStatusInfo().getStatus().equals(ThingStatus.ONLINE)) {
-                updateStatus(ThingStatus.ONLINE);
-            }
-        } catch (JsonParseException | IllegalStateException e) {
-            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
-                    "Could not parse cmdGetUnitById:" + e.getMessage());
-        }
-        return status;
+        return TouchWandUnitFromJson.parseResponse(response);
     }
 
     abstract void touchWandUnitHandleCommand(Command command);
index 5f16f4b8a3a574c30d6f274f37eba3f80fbed1d4..b0c6df5d4de935ff3c309c793c995eca08994dbe 100644 (file)
@@ -36,7 +36,7 @@ public class TouchWandBindingConstants {
     public static final ThingTypeUID THING_TYPE_SHUTTER = new ThingTypeUID(BINDING_ID, "shutter");
     public static final ThingTypeUID THING_TYPE_WALLCONTROLLER = new ThingTypeUID(BINDING_ID, "wallcontroller");
     public static final ThingTypeUID THING_TYPE_DIMMER = new ThingTypeUID(BINDING_ID, "dimmer");
-    public static final ThingTypeUID THING_TYPE_ALARMSENSOR = new ThingTypeUID(BINDING_ID, "AlarmSensor"); // TBD
+    public static final ThingTypeUID THING_TYPE_ALARMSENSOR = new ThingTypeUID(BINDING_ID, "alarmsensor");
 
     // List of all Channel ids
     public static final String CHANNEL_SWITCH = "switch";
@@ -46,6 +46,11 @@ public class TouchWandBindingConstants {
     public static final String CHANNEL_WALLCONTROLLER_ACTION = "wallaction";
     public static final String CHANNEL_BATTERY_LEVEL = "battery_level";
     public static final String CHANNEL_BATTERY_LOW = "battery_low";
+    public static final String CHANNEL_LEAK = "leak";
+    public static final String CHANNEL_MOTION = "motion";
+    public static final String CHANNEL_ILLUMINATION = "illumination";
+    public static final String CHANNEL_DOORWINDOW = "isOpen";
+    public static final String CHANNEL_TEMPERATURE = "temperature";
 
     // List of configuration parameters
 
@@ -77,7 +82,7 @@ public class TouchWandBindingConstants {
         SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_SHUTTER);
         SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_WALLCONTROLLER);
         SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_DIMMER);
-        // SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_ALARMSENSOR); // not implemented yet
+        SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_ALARMSENSOR);
     }
 
     public static final String TYPE_WALLCONTROLLER = "WallController";
@@ -85,6 +90,13 @@ public class TouchWandBindingConstants {
     public static final String TYPE_SHUTTER = "shutter";
     public static final String TYPE_DIMMER = "dimmer";
     public static final String TYPE_ALARMSENSOR = "AlarmSensor";
+    public static final String TYPE_UNKNOWN = "unknown";
+
+    public static final int SENSOR_TYPE_TEMPERATURE = 1;
+    public static final int SENSOR_TYPE_LUMINANCE = 3;
+    public static final int SENSOR_TYPE_LEAK = 6;
+    public static final int SENSOR_TYPE_DOOR_WINDOW = 10;
+    public static final int SENSOR_TYPE_MOTION = 12;
 
     public static final String[] SUPPORTED_TOUCHWAND_TYPES = { TYPE_WALLCONTROLLER, TYPE_SWITCH, TYPE_SHUTTER,
             TYPE_DIMMER, TYPE_ALARMSENSOR };
index 9a6f232710bd675f56d90d7a8c7f02ad2b88aba7..7480a10ee9a45888d613f1b851ef7dd8cc7b37d8 100644 (file)
@@ -68,6 +68,8 @@ public class TouchWandHandlerFactory extends BaseThingHandlerFactory {
             return new TouchWandWallControllerHandler(thing);
         } else if (THING_TYPE_DIMMER.equals(thingTypeUID)) {
             return new TouchWandDimmerHandler(thing);
+        } else if (THING_TYPE_ALARMSENSOR.equals(thingTypeUID)) {
+            return new TouchWandAlarmSensorHandler(thing);
         }
 
         return null;
index 6d43fd0d09c9676aff1d8501310b7472b78f1d82..2ba61fc1643b698043192aa7b0c33169ee6d232e 100644 (file)
@@ -117,16 +117,21 @@ public class TouchWandRestClient {
     }
 
     public String cmdListUnits() {
-        String command = buildUrl(CMD_LIST_UNITS);
-        String response = sendCommand(command, METHOD_GET, "");
-
+        String response = "";
+        if (isConnected) {
+            String command = buildUrl(CMD_LIST_UNITS);
+            response = sendCommand(command, METHOD_GET, "");
+        }
         return response;
     }
 
     public String cmdGetUnitById(String id) {
-        String command = buildUrl(CMD_GET_UNIT_BY_ID) + "id=" + id;
-        String response = sendCommand(command, METHOD_GET, "");
+        String response = "";
 
+        if (isConnected) {
+            String command = buildUrl(CMD_GET_UNIT_BY_ID) + "id=" + id;
+            response = sendCommand(command, METHOD_GET, "");
+        }
         return response;
     }
 
@@ -167,9 +172,11 @@ public class TouchWandRestClient {
     }
 
     private String cmdUnitAction(String action) {
-        String command = buildUrl(CMD_UNIT_ACTION);
-        String response = sendCommand(command, METHOD_POST, action);
-
+        String response = "";
+        if (isConnected) {
+            String command = buildUrl(CMD_UNIT_ACTION);
+            response = sendCommand(command, METHOD_POST, action);
+        }
         return response;
     }
 
index 32c3e371b95941434586898affbfd9e3acd171a4..1a1c24ad48a8306257ceb641b98a5219de1db80b 100644 (file)
@@ -17,6 +17,7 @@ import static org.openhab.binding.touchwand.internal.TouchWandBindingConstants.C
 import java.time.Instant;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.touchwand.internal.dto.Csc;
 import org.openhab.binding.touchwand.internal.dto.TouchWandUnitData;
 import org.openhab.binding.touchwand.internal.dto.TouchWandUnitDataWallController;
 import org.openhab.core.thing.Thing;
@@ -33,12 +34,12 @@ import org.openhab.core.types.Command;
 @NonNullByDefault
 public class TouchWandWallControllerHandler extends TouchWandBaseUnitHandler {
 
-    private long timeSinceLastEventMs;
-    private static final int ADJUSTENT_EVENT_FILTER_TIME_MILLISEC = 2000; // 2 seconds
+    private long timeLastEventMs;
+    private static final int ADJACENT_EVENT_FILTER_TIME_MILLISEC = 2000; // 2 seconds
 
     public TouchWandWallControllerHandler(Thing thing) {
         super(thing);
-        timeSinceLastEventMs = Instant.now().toEpochMilli();
+        timeLastEventMs = Instant.now().toEpochMilli();
     }
 
     @Override
@@ -47,12 +48,16 @@ public class TouchWandWallControllerHandler extends TouchWandBaseUnitHandler {
 
     @Override
     void updateTouchWandUnitState(TouchWandUnitData unitData) {
-        int status = ((TouchWandUnitDataWallController) unitData).getCurrStatus();
-        long timeDiff = Instant.now().toEpochMilli() - timeSinceLastEventMs;
-        if ((timeDiff) > ADJUSTENT_EVENT_FILTER_TIME_MILLISEC) {
-            String action = status <= 100 ? "SHORT" : "LONG";
-            triggerChannel(CHANNEL_WALLCONTROLLER_ACTION, action);
+        if (unitData instanceof TouchWandUnitDataWallController) {
+            Csc status = ((TouchWandUnitDataWallController) unitData).getCurrStatus();
+            long ts = status.getTs();
+            long timeDiff = ts - timeLastEventMs;
+            if ((timeDiff) > ADJACENT_EVENT_FILTER_TIME_MILLISEC) {
+                int value = status.getKeyAttr();
+                String action = (value <= 100) ? "SHORT" : "LONG";
+                triggerChannel(CHANNEL_WALLCONTROLLER_ACTION, action);
+            }
+            timeLastEventMs = status.getTs();
         }
-        timeSinceLastEventMs = Instant.now().toEpochMilli();
     }
 }
index e0c59ba3721c087a27b914554a185ae252685601..20f0766ac104c66c859aaba6fdae9a1c73a34ecd 100644 (file)
@@ -50,7 +50,8 @@ import com.google.gson.JsonSyntaxException;
 @NonNullByDefault
 public class TouchWandWebSockets {
 
-    private static final int CONNECT_TIMEOUT_SEC = 10;
+    private static final int CONNECT_TIMEOUT_SEC = 15;
+    private static final int CONNECT_TIMEOUT_MS = CONNECT_TIMEOUT_SEC * 1000;
     private static final int WEBSOCKET_RECONNECT_INTERVAL_SEC = CONNECT_TIMEOUT_SEC * 2;
     private static final int WEBSOCKET_IDLE_TIMEOUT_MS = CONNECT_TIMEOUT_SEC * 10 * 1000;
     private final Logger logger = LoggerFactory.getLogger(TouchWandWebSockets.class);
@@ -82,7 +83,7 @@ public class TouchWandWebSockets {
             return;
         }
 
-        client.setConnectTimeout(CONNECT_TIMEOUT_SEC);
+        client.setConnectTimeout(CONNECT_TIMEOUT_MS);
         ClientUpgradeRequest request = new ClientUpgradeRequest();
         request.setSubProtocols("relay_protocol");
 
@@ -136,7 +137,9 @@ public class TouchWandWebSockets {
         public void onConnect(Session session) {
             logger.debug("TouchWandWebSockets connected to {}", session.getRemoteAddress().toString());
             try {
-                session.getRemote().sendString("{\"myopenhab\": \"myopenhab\"}");
+                long timestamp = System.currentTimeMillis(); // need unique id
+                String controllerIdStr = String.format("{\"contId\": \"openhab%d\"}", timestamp);
+                session.getRemote().sendString(controllerIdStr);
             } catch (IOException e) {
                 logger.warn("sendString : {}", e.getMessage());
             }
index 26e4ada02b0d1251173dc8f38b1bfb91f4f18888..3a0c035153d740c0de586bebfcc1a9699c7bb20e 100644 (file)
@@ -90,9 +90,7 @@ public class TouchWandUnitDiscoveryService extends AbstractDiscoveryService
                     for (JsonElement unit : jsonArray) {
                         TouchWandUnitData touchWandUnit;
                         touchWandUnit = TouchWandUnitFromJson.parseResponse(unit.getAsJsonObject());
-                        if (touchWandUnit == null) {
-                            continue;
-                        }
+
                         if (!touchWandBridgeHandler.isAddSecondaryControllerUnits()) {
                             if (!Arrays.asList(CONNECTIVITY_OPTIONS).contains(touchWandUnit.getConnectivity())) {
                                 continue;
@@ -118,6 +116,9 @@ public class TouchWandUnitDiscoveryService extends AbstractDiscoveryService
                             case TYPE_SHUTTER:
                                 addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_SHUTTER);
                                 break;
+                            case TYPE_ALARMSENSOR:
+                                addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_ALARMSENSOR);
+                                break;
                             default:
                                 continue;
                         }
diff --git a/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/AlarmSensorUnitDataDeserializer.java b/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/AlarmSensorUnitDataDeserializer.java
new file mode 100644 (file)
index 0000000..e409f3c
--- /dev/null
@@ -0,0 +1,122 @@
+/**
+ * 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.touchwand.internal.dto;
+
+import java.lang.reflect.Type;
+import java.util.Map.Entry;
+
+import org.openhab.binding.touchwand.internal.dto.TouchWandAlarmSensorCurrentStatus.Alarm;
+import org.openhab.binding.touchwand.internal.dto.TouchWandAlarmSensorCurrentStatus.BinarySensor;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+
+/**
+ * The {@link AlarmSensorUnitDataDeserializer} implements AlarmSensorUnitData unit
+ * Json De-serializer.
+ *
+ * @author Roie Geron - Initial contribution
+ */
+public class AlarmSensorUnitDataDeserializer implements JsonDeserializer<TouchWandUnitDataAlarmSensor> {
+
+    static final Gson gson = new Gson();
+    static GsonBuilder builder = new GsonBuilder();
+
+    @Override
+    public TouchWandUnitDataAlarmSensor deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+            throws JsonParseException {
+
+        TouchWandUnitDataAlarmSensor touchWandUnitDataAlarmSensor = new TouchWandUnitDataAlarmSensor();
+
+        JsonObject jsonObject = json.getAsJsonObject();
+        touchWandUnitDataAlarmSensor.setId(jsonObject.get("id").getAsInt());
+        touchWandUnitDataAlarmSensor.setName(jsonObject.get("name").getAsString());
+        touchWandUnitDataAlarmSensor.setConnectivity(jsonObject.get("connectivity").getAsString());
+        touchWandUnitDataAlarmSensor.setType(jsonObject.get("type").getAsString());
+        touchWandUnitDataAlarmSensor.setHasBattery(jsonObject.get("hasBattery").getAsBoolean());
+        JsonElement powerMeterElement = jsonObject.get("hasPowerMeter");
+        if (powerMeterElement != null && !powerMeterElement.isJsonNull()) {
+            touchWandUnitDataAlarmSensor.setHasPowerMeter(powerMeterElement.getAsBoolean());
+        } else {
+            touchWandUnitDataAlarmSensor.setHasPowerMeter(false);
+        }
+
+        JsonElement status = jsonObject.get("status");
+        if (status != null && !status.isJsonNull()) { // Sometimes status is null
+            touchWandUnitDataAlarmSensor.setStatus(jsonObject.get("status").getAsString());
+        }
+
+        JsonObject currentStatusObj = builder.create().fromJson(jsonObject.get("currStatus").getAsJsonObject(),
+                JsonObject.class);
+
+        if (currentStatusObj != null) {
+
+            TouchWandAlarmSensorCurrentStatus touchWandUnitDataAlarmSensorCurrentStatus = touchWandUnitDataAlarmSensor
+                    .getCurrStatus();
+
+            for (Entry<String, JsonElement> entry : currentStatusObj.entrySet()) {
+                String key = entry.getKey();
+                String splits[] = key.split("_"); // the key is xxxx_n where xxx is sensor type and n is
+                String keyName = splits[0];
+                int index = 0;
+
+                if (splits.length > 1 && !splits[1].isEmpty()) {
+                    try {
+                        index = Integer.parseInt(splits[1]);
+                    } catch (final NumberFormatException e) {
+                        index = 0;
+                    }
+                }
+
+                switch (keyName) {
+                    case "batt":
+                        touchWandUnitDataAlarmSensorCurrentStatus.setBatt(entry.getValue().getAsInt());
+                        break;
+                    case "alarm":
+                        Alarm alarm = gson.fromJson(entry.getValue().getAsJsonObject(), Alarm.class);
+                        TouchWandAlarmSensorCurrentStatus.AlarmEvent alarmEvent = new TouchWandAlarmSensorCurrentStatus.AlarmEvent();
+                        if (alarm != null) {
+                            alarmEvent.alarm = alarm;
+                            alarmEvent.alarmType = index;
+                        }
+                        touchWandUnitDataAlarmSensor.getCurrStatus().getAlarmsStatus().add(alarmEvent);
+                        break;
+                    case "sensor":
+                        TouchWandAlarmSensorCurrentStatus.Sensor sensor = new TouchWandAlarmSensorCurrentStatus.Sensor();
+                        sensor.value = entry.getValue().getAsFloat();
+                        sensor.type = index;
+                        touchWandUnitDataAlarmSensor.getCurrStatus().getSensorsStatus().add(sensor);
+                        break;
+                    case "bsensor":
+                        BinarySensor bsensor = gson.fromJson(entry.getValue().getAsJsonObject(), BinarySensor.class);
+                        TouchWandAlarmSensorCurrentStatus.BinarySensorEvent bsensorevent = new TouchWandAlarmSensorCurrentStatus.BinarySensorEvent();
+                        if (bsensor != null) {
+                            bsensorevent.sensor = bsensor;
+                            bsensorevent.sensorType = index;
+                        }
+                        touchWandUnitDataAlarmSensor.getCurrStatus().getbSensorsStatus().add(bsensorevent);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        return touchWandUnitDataAlarmSensor;
+    }
+}
index 4d9fb2b95a472ded0a1fa10b8a459b6bb4ca57b0..103a44705ee8472cdbd516e3964a80ebadfb45e2 100644 (file)
 
 package org.openhab.binding.touchwand.internal.dto;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * The {@link Csc} implements Csc data class.
  *
  * @author Roie Geron - Initial contribution
  */
+@NonNullByDefault
 public class Csc {
 
-    private int sceneNo;
-    private int ts;
-    private int keyAttr;
+    private int sceneNo = 0;
+    private long ts = 0;
+    private int keyAttr = 0;
 
     public int getSceneNo() {
         return sceneNo;
@@ -32,11 +35,11 @@ public class Csc {
         this.sceneNo = sceneNo;
     }
 
-    public int getTs() {
+    public long getTs() {
         return ts;
     }
 
-    public void setTs(int ts) {
+    public void setTs(long ts) {
         this.ts = ts;
     }
 
index 5253cf8fd636b393d790c573d9ef12a41a7102e9..46e31463ca0d307b3ed6cc69b633af8b2fb8d517 100644 (file)
 
 package org.openhab.binding.touchwand.internal.dto;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * The {@link CurrStatus} implements CurrStatus data class.
  *
  * @author Roie Geron - Initial contribution
  */
-
+@NonNullByDefault
 public class CurrStatus {
 
-    private Csc csc;
+    private Csc csc = new Csc();
 
     public Csc getCsc() {
         return csc;
diff --git a/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandAlarmSensorCurrentStatus.java b/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandAlarmSensorCurrentStatus.java
new file mode 100644 (file)
index 0000000..87b7d78
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+ * 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.touchwand.internal.dto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link TouchWandAlarmSensorCurrentStatus} implements Alarm Sensor unit
+ * CurrentStatus data property.
+ *
+ * @author Roie Geron - Initial contribution
+ */
+
+@NonNullByDefault
+public class TouchWandAlarmSensorCurrentStatus {
+
+    private int batt;
+    private List<Sensor> sensorsStatus = new ArrayList<Sensor>();
+    private List<AlarmEvent> alarmsStatus = new ArrayList<AlarmEvent>();
+    private List<BinarySensorEvent> bSensorsStatus = new ArrayList<BinarySensorEvent>();
+
+    public void setBatt(Integer batt) {
+        this.batt = batt;
+    }
+
+    public int getBatt() {
+        return batt;
+    }
+
+    public void setSensorsStatus(List<Sensor> sensorsStatus) {
+        this.sensorsStatus = sensorsStatus;
+    }
+
+    public List<Sensor> getSensorsStatus() {
+        return sensorsStatus;
+    }
+
+    public List<BinarySensorEvent> getbSensorsStatus() {
+        return bSensorsStatus;
+    }
+
+    public void setbSensorsStatus(List<BinarySensorEvent> bSensorsStatus) {
+        this.bSensorsStatus = bSensorsStatus;
+    }
+
+    public List<AlarmEvent> getAlarmsStatus() {
+        return alarmsStatus;
+    }
+
+    public void setAlarmsStatus(List<AlarmEvent> alarmsStatus) {
+        this.alarmsStatus = alarmsStatus;
+    }
+
+    public static class Alarm {
+        public int event;
+        public long ts;
+    }
+
+    public static class AlarmEvent {
+        int alarmType;
+        Alarm alarm = new Alarm();
+    }
+
+    public static class Sensor {
+        public int type;
+        public float value;
+    }
+
+    public static class BinarySensor {
+        public long ts;
+        public boolean state;
+    }
+
+    public static class BinarySensorEvent {
+        public int sensorType;
+        public BinarySensor sensor = new BinarySensor();
+    }
+}
index 5ec2869b3410856b3d2166410649c36c22e829d6..39a2264d893d49e20f36f77f1824fd77be77b262 100644 (file)
@@ -195,5 +195,5 @@ public abstract class TouchWandUnitData {
         this.roomId = roomId;
     }
 
-    public abstract Integer getCurrStatus();
+    public abstract Object getCurrStatus();
 }
diff --git a/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnitDataAlarmSensor.java b/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnitDataAlarmSensor.java
new file mode 100644 (file)
index 0000000..98890ad
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * 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.touchwand.internal.dto;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link TouchWandUnitDataAlarmSensor} implements Alarm Sensor unit
+ * data property.
+ *
+ * @author Roie Geron - Initial contribution
+ */
+@NonNullByDefault
+public class TouchWandUnitDataAlarmSensor extends TouchWandUnitData {
+
+    private TouchWandAlarmSensorCurrentStatus currStatus = new TouchWandAlarmSensorCurrentStatus();
+
+    @Override
+    public TouchWandAlarmSensorCurrentStatus getCurrStatus() {
+        return this.currStatus;
+    }
+
+    public class AlarmEventType {
+        public int eventsNum;
+        public String description = "";
+    }
+
+    public class SensorType {
+        public int type;
+        public String description = "";
+    }
+}
index 5f29a88e3c7aa8105d007f09c8544cdd45f2d427..8e270365f931e153bb511ee19affcfc88cb519b3 100644 (file)
 
 package org.openhab.binding.touchwand.internal.dto;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * The {@link TouchWandUnitDataWallController} implements WallController unit
  * property.
  *
  * @author Roie Geron - Initial contribution
  */
+@NonNullByDefault
 public class TouchWandUnitDataWallController extends TouchWandUnitData {
 
-    private CurrStatus currStatus;
+    private CurrStatus currStatus = new CurrStatus();
 
     @Override
-    public Integer getCurrStatus() {
-        if (currStatus != null) {
-            return currStatus.getCsc().getKeyAttr();
-        } else {
-            return 0;
-        }
+    public Csc getCurrStatus() {
+        return currStatus.getCsc();
     }
 
     public void setCurrStatus(CurrStatus currStatus) {
index 255b9fb2396d76a6716956620c1cb7920172837f..97cef0fa2ea1b799fea4ad4d8fe40b74718b33a4 100644 (file)
@@ -17,8 +17,14 @@ import static org.openhab.binding.touchwand.internal.TouchWandBindingConstants.*
 
 import java.util.Arrays;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
 import com.google.gson.JsonParser;
 
 /**
@@ -26,8 +32,11 @@ import com.google.gson.JsonParser;
  *
  * @author Roie Geron - Initial contribution
  */
+@NonNullByDefault
 public class TouchWandUnitFromJson {
 
+    private final static Logger logger = LoggerFactory.getLogger(TouchWandUnitFromJson.class);
+
     public TouchWandUnitFromJson() {
     }
 
@@ -36,11 +45,11 @@ public class TouchWandUnitFromJson {
         TouchWandUnitData touchWandUnit;
         String type = jsonUnit.get("type").getAsString();
         if (!Arrays.asList(SUPPORTED_TOUCHWAND_TYPES).contains(type)) {
-            return null;
+            type = TYPE_UNKNOWN;
         }
 
         if (!jsonUnit.has("currStatus") || (jsonUnit.get("currStatus") == null)) {
-            return null;
+            type = TYPE_UNKNOWN;
         }
 
         switch (type) {
@@ -56,8 +65,21 @@ public class TouchWandUnitFromJson {
             case TYPE_SHUTTER:
                 touchWandUnit = gson.fromJson(jsonUnit, TouchWandShutterSwitchUnitData.class);
                 break;
+            case TYPE_ALARMSENSOR:
+                Gson builder = new GsonBuilder()
+                        .registerTypeAdapter(TouchWandUnitDataAlarmSensor.class, new AlarmSensorUnitDataDeserializer())
+                        .create();
+                touchWandUnit = builder.fromJson(jsonUnit, TouchWandUnitDataAlarmSensor.class);
+                break;
+            case TYPE_UNKNOWN:
+                touchWandUnit = new TouchWandUnknownTypeUnitData();
+                break;
             default:
-                return null;
+                touchWandUnit = new TouchWandUnknownTypeUnitData();
+        }
+
+        if (touchWandUnit == null) {
+            touchWandUnit = new TouchWandUnknownTypeUnitData();
         }
 
         return touchWandUnit;
@@ -65,7 +87,15 @@ public class TouchWandUnitFromJson {
 
     public static TouchWandUnitData parseResponse(String JsonUnit) {
         final JsonParser jsonParser = new JsonParser();
-        JsonObject unitObj = jsonParser.parse(JsonUnit).getAsJsonObject();
-        return parseResponse(unitObj);
+        TouchWandUnitData myTouchWandUnitData;
+        JsonObject unitObj;
+        try {
+            unitObj = jsonParser.parse(JsonUnit).getAsJsonObject();
+            myTouchWandUnitData = parseResponse(unitObj);
+        } catch (JsonParseException | IllegalStateException e) {
+            logger.warn("Could not parse response {}", JsonUnit);
+            myTouchWandUnitData = new TouchWandUnknownTypeUnitData(); // Return unknown type
+        }
+        return myTouchWandUnitData;
     }
 }
diff --git a/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnknownTypeUnitData.java b/bundles/org.openhab.binding.touchwand/src/main/java/org/openhab/binding/touchwand/internal/dto/TouchWandUnknownTypeUnitData.java
new file mode 100644 (file)
index 0000000..6f359a6
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * 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.touchwand.internal.dto;
+
+import static org.openhab.binding.touchwand.internal.TouchWandBindingConstants.TYPE_UNKNOWN;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link TouchWandUnknownTypeUnitData} implements unknown unit data
+ * property.
+ * It makes the code generic in case parsing error or unknown types
+ *
+ * @author Roie Geron - Initial contribution
+ */
+@NonNullByDefault
+public class TouchWandUnknownTypeUnitData extends TouchWandUnitData {
+
+    public TouchWandUnknownTypeUnitData() {
+        this.setType(TYPE_UNKNOWN);
+    }
+
+    @Override
+    public Integer getCurrStatus() {
+        return 0;
+    }
+}
diff --git a/bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/thing/alarmsensor.xml b/bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/thing/alarmsensor.xml
new file mode 100644 (file)
index 0000000..b4d2b7c
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<thing:thing-descriptions bindingId="touchwand"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
+       <thing-type id="alarmsensor">
+               <supported-bridge-type-refs>
+                       <bridge-type-ref id="bridge"></bridge-type-ref>
+               </supported-bridge-type-refs>
+               <label>TouchWand Alarm Sensor Unit</label>
+               <channels>
+                       <channel id="battery_level" typeId="system.battery-level"/>
+                       <channel id="battery_low" typeId="system.low-battery"/>
+                       <channel id="leak" typeId="leak"></channel>
+                       <channel id="motion" typeId="motion"/>
+                       <channel id="illumination" typeId="illumination"/>
+                       <channel id="isOpen" typeId="isOpen"/>
+                       <channel id="temperature" typeId="temperature"/>
+               </channels>
+       </thing-type>
+       <channel-type id="leak">
+               <item-type>Switch</item-type>
+               <label>Leak Detected</label>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="temperature">
+               <item-type>Number:Temperature</item-type>
+               <label>Temperature</label>
+               <category>Temperature</category>
+               <state pattern="%.1f %unit%" readOnly="true">
+               </state>
+       </channel-type>
+       <channel-type id="illumination">
+               <item-type>Number:Illuminance</item-type>
+               <label>Illumination</label>
+               <description>
+                       This channel shows the brightness of the environment in Lux.
+               </description>
+               <state pattern="%d %unit%" readOnly="true"></state>
+       </channel-type>
+       <channel-type id="isOpen">
+               <item-type>Contact</item-type>
+               <label>Open Status</label>
+               <category>Contact</category>
+               <state readOnly="true"></state>
+       </channel-type>
+       <channel-type id="motion">
+               <item-type>Switch</item-type>
+               <label>Motion Status</label>
+               <category>Motion</category>
+               <state readOnly="true"></state>
+       </channel-type>
+</thing:thing-descriptions>