## 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
|-------------------|-----------------------------------------------------------------------|---------|----------|
| 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 |
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
--- /dev/null
+/**
+ * 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());
+ }
+}
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;
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
@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;
@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);
}
}
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);
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";
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
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";
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 };
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;
}
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;
}
}
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;
}
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;
@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
@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();
}
}
@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);
return;
}
- client.setConnectTimeout(CONNECT_TIMEOUT_SEC);
+ client.setConnectTimeout(CONNECT_TIMEOUT_MS);
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setSubProtocols("relay_protocol");
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());
}
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;
case TYPE_SHUTTER:
addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_SHUTTER);
break;
+ case TYPE_ALARMSENSOR:
+ addDeviceDiscoveryResult(touchWandUnit, THING_TYPE_ALARMSENSOR);
+ break;
default:
continue;
}
--- /dev/null
+/**
+ * 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;
+ }
+}
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;
this.sceneNo = sceneNo;
}
- public int getTs() {
+ public long getTs() {
return ts;
}
- public void setTs(int ts) {
+ public void setTs(long ts) {
this.ts = ts;
}
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;
--- /dev/null
+/**
+ * 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();
+ }
+}
this.roomId = roomId;
}
- public abstract Integer getCurrStatus();
+ public abstract Object getCurrStatus();
}
--- /dev/null
+/**
+ * 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 = "";
+ }
+}
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) {
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;
/**
*
* @author Roie Geron - Initial contribution
*/
+@NonNullByDefault
public class TouchWandUnitFromJson {
+ private final static Logger logger = LoggerFactory.getLogger(TouchWandUnitFromJson.class);
+
public 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) {
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;
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;
}
}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+<?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>