added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.draytonwiser-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-draytonwiser" description="DraytonWiser Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.draytonwiser/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,160 @@
/**
* 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.draytonwiser.internal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link DraytonWiserBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Andrew Schofield - Initial contribution
*/
@NonNullByDefault
public class DraytonWiserBindingConstants {
public static final String BINDING_ID = "draytonwiser";
public static final String REFRESH_INTERVAL = "refresh";
public static final int DEFAULT_REFRESH_SECONDS = 60;
public static final int OFFLINE_TEMPERATURE = -32768;
// Web Service Endpoints
public static final String DEVICE_ENDPOINT = "data/domain/Device/";
public static final String ROOMSTATS_ENDPOINT = "data/domain/RoomStat/";
public static final String TRVS_ENDPOINT = "data/domain/SmartValve/";
public static final String ROOMS_ENDPOINT = "data/domain/Room/";
public static final String HEATCHANNELS_ENDPOINT = "data/domain/HeatingChannel/";
public static final String SYSTEM_ENDPOINT = "data/domain/System/";
public static final String STATION_ENDPOINT = "data/network/Station/";
public static final String DOMAIN_ENDPOINT = "data/domain/";
public static final String HOTWATER_ENDPOINT = "data/domain/HotWater/";
public static final String SMARTPLUG_ENDPOINT = "data/domain/SmartPlug/";
// bridge
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "heathub");
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_CONTROLLER = new ThingTypeUID(BINDING_ID, "boiler-controller");
public static final ThingTypeUID THING_TYPE_ROOM = new ThingTypeUID(BINDING_ID, "room");
public static final ThingTypeUID THING_TYPE_ROOMSTAT = new ThingTypeUID(BINDING_ID, "roomstat");
public static final ThingTypeUID THING_TYPE_ITRV = new ThingTypeUID(BINDING_ID, "itrv");
public static final ThingTypeUID THING_TYPE_HOTWATER = new ThingTypeUID(BINDING_ID, "hotwater");
public static final ThingTypeUID THING_TYPE_SMARTPLUG = new ThingTypeUID(BINDING_ID, "smart-plug");
// properties
public static final String PROP_ADDRESS = "networkAddress";
public static final String PROP_SERIAL_NUMBER = "serialNumber";
public static final String PROP_NAME = "name";
public static final String PROP_ID = "id";
// List of all Channel ids
public static final String CHANNEL_CURRENT_TEMPERATURE = "currentTemperature";
public static final String CHANNEL_CURRENT_HUMIDITY = "currentHumidity";
public static final String CHANNEL_CURRENT_SETPOINT = "currentSetPoint";
public static final String CHANNEL_CURRENT_BATTERY_VOLTAGE = "currentBatteryVoltage";
public static final String CHANNEL_CURRENT_BATTERY_LEVEL = "currentBatteryLevel";
public static final String CHANNEL_CURRENT_WISER_BATTERY_LEVEL = "currentWiserBatteryLevel";
public static final String CHANNEL_CURRENT_DEMAND = "currentDemand";
public static final String CHANNEL_HEAT_REQUEST = "heatRequest";
public static final String CHANNEL_CURRENT_SIGNAL_RSSI = "currentSignalRSSI";
public static final String CHANNEL_CURRENT_SIGNAL_LQI = "currentSignalLQI";
public static final String CHANNEL_CURRENT_SIGNAL_STRENGTH = "currentSignalStrength";
public static final String CHANNEL_CURRENT_WISER_SIGNAL_STRENGTH = "currentWiserSignalStrength";
public static final String CHANNEL_HEATING_OVERRIDE = "heatingOverride";
public static final String CHANNEL_HOT_WATER_OVERRIDE = "hotWaterOverride";
public static final String CHANNEL_HEATCHANNEL_1_DEMAND = "heatChannel1Demand";
public static final String CHANNEL_HEATCHANNEL_2_DEMAND = "heatChannel2Demand";
public static final String CHANNEL_HEATCHANNEL_1_DEMAND_STATE = "heatChannel1DemandState";
public static final String CHANNEL_HEATCHANNEL_2_DEMAND_STATE = "heatChannel2DemandState";
public static final String CHANNEL_HOTWATER_DEMAND_STATE = "hotWaterDemandState";
public static final String CHANNEL_AWAY_MODE_STATE = "awayModeState";
public static final String CHANNEL_ECO_MODE_STATE = "ecoModeState";
public static final String CHANNEL_MANUAL_MODE_STATE = "manualModeState";
public static final String CHANNEL_ZIGBEE_CONNECTED = "zigbeeConnected";
public static final String CHANNEL_HOT_WATER_SETPOINT = "hotWaterSetPoint";
public static final String CHANNEL_HOT_WATER_BOOST_DURATION = "hotWaterBoostDuration";
public static final String CHANNEL_HOT_WATER_BOOSTED = "hotWaterBoosted";
public static final String CHANNEL_HOT_WATER_BOOST_REMAINING = "hotWaterBoostRemaining";
public static final String CHANNEL_ROOM_BOOST_DURATION = "roomBoostDuration";
public static final String CHANNEL_ROOM_BOOSTED = "roomBoosted";
public static final String CHANNEL_ROOM_BOOST_REMAINING = "roomBoostRemaining";
public static final String CHANNEL_ROOM_WINDOW_STATE_DETECTION = "windowStateDetection";
public static final String CHANNEL_ROOM_WINDOW_STATE = "windowState";
public static final String CHANNEL_DEVICE_LOCKED = "deviceLocked";
public static final String CHANNEL_SMARTPLUG_OUTPUT_STATE = "plugOutputState";
public static final String CHANNEL_SMARTPLUG_AWAY_ACTION = "plugAwayAction";
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList(THING_TYPE_CONTROLLER, THING_TYPE_ROOM, THING_TYPE_ROOMSTAT,
THING_TYPE_BRIDGE, THING_TYPE_ITRV, THING_TYPE_HOTWATER, THING_TYPE_SMARTPLUG)));
// Lookups from text representations to useful values
public enum SignalStrength {
VERYGOOD(4),
GOOD(3),
MEDIUM(2),
POOR(1),
NOSIGNAL(0);
private final int signalStrength;
SignalStrength(final int signalStrength) {
this.signalStrength = signalStrength;
}
public static State toSignalStrength(final String strength) {
try {
return new DecimalType(SignalStrength.valueOf(strength.toUpperCase()).signalStrength);
} catch (final IllegalArgumentException e) {
// Catch unrecognized values.
return UnDefType.UNDEF;
}
}
}
public enum BatteryLevel {
FULL(100),
NORMAL(80),
TWOTHIRDS(60),
ONETHIRD(40),
LOW(20),
CRITICAL(0);
private final int batteryLevel;
private BatteryLevel(final int batteryLevel) {
this.batteryLevel = batteryLevel;
}
public static State toBatteryLevel(final String level) {
try {
return new DecimalType(BatteryLevel.valueOf(level.toUpperCase()).batteryLevel);
} catch (final IllegalArgumentException e) {
// Catch unrecognized values.
return UnDefType.UNDEF;
}
}
}
}

View File

@@ -0,0 +1,80 @@
/**
* 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.draytonwiser.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.draytonwiser.internal.handler.ControllerHandler;
import org.openhab.binding.draytonwiser.internal.handler.HeatHubHandler;
import org.openhab.binding.draytonwiser.internal.handler.HotWaterHandler;
import org.openhab.binding.draytonwiser.internal.handler.RoomHandler;
import org.openhab.binding.draytonwiser.internal.handler.RoomStatHandler;
import org.openhab.binding.draytonwiser.internal.handler.SmartPlugHandler;
import org.openhab.binding.draytonwiser.internal.handler.TRVHandler;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link DraytonWiserHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Andrew Schofield - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.draytonwiser")
@NonNullByDefault
public class DraytonWiserHandlerFactory extends BaseThingHandlerFactory {
private final HttpClient httpClient;
@Activate
public DraytonWiserHandlerFactory(@Reference final HttpClientFactory factory) {
httpClient = factory.getCommonHttpClient();
}
@Override
public boolean supportsThingType(final ThingTypeUID thingTypeUID) {
return DraytonWiserBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(final Thing thing) {
final ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (DraytonWiserBindingConstants.THING_TYPE_BRIDGE.equals(thingTypeUID)) {
return new HeatHubHandler((Bridge) thing, httpClient);
} else if (DraytonWiserBindingConstants.THING_TYPE_ROOM.equals(thingTypeUID)) {
return new RoomHandler(thing);
} else if (DraytonWiserBindingConstants.THING_TYPE_ROOMSTAT.equals(thingTypeUID)) {
return new RoomStatHandler(thing);
} else if (DraytonWiserBindingConstants.THING_TYPE_ITRV.equals(thingTypeUID)) {
return new TRVHandler(thing);
} else if (DraytonWiserBindingConstants.THING_TYPE_CONTROLLER.equals(thingTypeUID)) {
return new ControllerHandler(thing);
} else if (DraytonWiserBindingConstants.THING_TYPE_HOTWATER.equals(thingTypeUID)) {
return new HotWaterHandler(thing);
} else if (DraytonWiserBindingConstants.THING_TYPE_SMARTPLUG.equals(thingTypeUID)) {
return new SmartPlugHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,27 @@
/**
* 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.draytonwiser.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
/**
* Listener for item/sensor updates.
*
* @author Andrew Schofield - Initial contribution
*/
@NonNullByDefault
public interface DraytonWiserRefreshListener {
void onRefresh(DraytonWiserDTO domain);
}

View File

@@ -0,0 +1,225 @@
/**
* 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.draytonwiser.internal.api;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.openhab.binding.draytonwiser.internal.handler.HeatHubConfiguration;
import org.openhab.binding.draytonwiser.internal.model.DomainDTO;
import org.openhab.binding.draytonwiser.internal.model.StationDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
/**
* Class with api specific call code.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Moved Api specific code to it's own class
*/
@NonNullByDefault
public class DraytonWiserApi {
public static final Gson GSON = new GsonBuilder().setFieldNamingStrategy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.create();
private final Logger logger = LoggerFactory.getLogger(DraytonWiserApi.class);
private final HttpClient httpClient;
private HeatHubConfiguration configuration = new HeatHubConfiguration();
private int failCount;
public DraytonWiserApi(final HttpClient httpClient) {
this.httpClient = httpClient;
}
public void setConfiguration(final HeatHubConfiguration configuration) {
this.configuration = configuration;
}
public @Nullable StationDTO getStation() throws DraytonWiserApiException {
final ContentResponse response = sendMessageToHeatHub(STATION_ENDPOINT, HttpMethod.GET);
return response == null ? null : GSON.fromJson(response.getContentAsString(), StationDTO.class);
}
public @Nullable DomainDTO getDomain() throws DraytonWiserApiException {
final ContentResponse response = sendMessageToHeatHub(DOMAIN_ENDPOINT, HttpMethod.GET);
if (response == null) {
return null;
}
try {
return GSON.fromJson(response.getContentAsString(), DomainDTO.class);
} catch (final JsonSyntaxException e) {
logger.debug("Could not parse Json content: {}", e.getMessage(), e);
return null;
}
}
public void setRoomSetPoint(final int roomId, final int setPoint) throws DraytonWiserApiException {
final String payload = "{\"RequestOverride\":{\"Type\":\"Manual\", \"SetPoint\":" + setPoint + "}}";
sendMessageToHeatHub(ROOMS_ENDPOINT + roomId, "PATCH", payload);
}
public void setRoomManualMode(final int roomId, final boolean manualMode) throws DraytonWiserApiException {
String payload = "{\"Mode\":\"" + (manualMode ? "Manual" : "Auto") + "\"}";
sendMessageToHeatHub(ROOMS_ENDPOINT + roomId, "PATCH", payload);
payload = "{\"RequestOverride\":{\"Type\":\"None\",\"Originator\" :\"App\",\"DurationMinutes\":0,\"SetPoint\":0}}";
sendMessageToHeatHub(ROOMS_ENDPOINT + roomId, "PATCH", payload);
}
public void setRoomWindowStateDetection(final int roomId, final boolean windowStateDetection)
throws DraytonWiserApiException {
final String payload = windowStateDetection ? "true" : "false";
sendMessageToHeatHub(ROOMS_ENDPOINT + roomId + "/WindowDetectionActive", "PATCH", payload);
}
public void setRoomBoostActive(final int roomId, final int setPoint, final int duration)
throws DraytonWiserApiException {
final String payload = "{\"RequestOverride\":{\"Type\":\"Manual\",\"Originator\" :\"App\",\"DurationMinutes\":"
+ duration + ",\"SetPoint\":" + setPoint + "}}";
sendMessageToHeatHub(ROOMS_ENDPOINT + roomId, "PATCH", payload);
}
public void setRoomBoostInactive(final int roomId) throws DraytonWiserApiException {
final String payload = "{\"RequestOverride\":{\"Type\":\"None\",\"Originator\" :\"App\",\"DurationMinutes\":0,\"SetPoint\":0}}";
sendMessageToHeatHub(ROOMS_ENDPOINT + roomId, "PATCH", payload);
}
public void setHotWaterManualMode(final boolean manualMode) throws DraytonWiserApiException {
String payload = "{\"Mode\":\"" + (manualMode ? "Manual" : "Auto") + "\"}";
sendMessageToHeatHub(HOTWATER_ENDPOINT + "2", "PATCH", payload);
payload = "{\"RequestOverride\":{\"Type\":\"None\",\"Originator\" :\"App\",\"DurationMinutes\":0,\"SetPoint\":0}}";
sendMessageToHeatHub(HOTWATER_ENDPOINT + "2", "PATCH", payload);
}
public void setHotWaterSetPoint(final int setPoint) throws DraytonWiserApiException {
final String payload = "{\"RequestOverride\":{\"Type\":\"Manual\", \"SetPoint\":" + setPoint + "}}";
sendMessageToHeatHub(HOTWATER_ENDPOINT + "2", "PATCH", payload);
}
public void setHotWaterBoostActive(final int duration) throws DraytonWiserApiException {
final String payload = "{\"RequestOverride\":{\"Type\":\"Manual\",\"Originator\" :\"App\",\"DurationMinutes\":"
+ duration + ",\"SetPoint\":1100}}";
sendMessageToHeatHub(HOTWATER_ENDPOINT + "2", "PATCH", payload);
}
public void setHotWaterBoostInactive() throws DraytonWiserApiException {
final String payload = "{\"RequestOverride\":{\"Type\":\"None\",\"Originator\" :\"App\",\"DurationMinutes\":0,\"SetPoint\":0}}";
sendMessageToHeatHub(HOTWATER_ENDPOINT + "2", "PATCH", payload);
}
public void setAwayMode(final boolean awayMode) throws DraytonWiserApiException {
final int setPoint = configuration.awaySetPoint * 10;
String payload = "{\"Type\":" + (awayMode ? "2" : "0") + ", \"setPoint\":" + (awayMode ? setPoint : "0") + "}";
sendMessageToHeatHub(SYSTEM_ENDPOINT + "RequestOverride", "PATCH", payload);
payload = "{\"Type\":" + (awayMode ? "2" : "0") + ", \"setPoint\":" + (awayMode ? "-200" : "0") + "}";
sendMessageToHeatHub(HOTWATER_ENDPOINT + "2/RequestOverride", "PATCH", payload);
}
public void setDeviceLocked(final int deviceId, final boolean locked) throws DraytonWiserApiException {
final String payload = locked ? "true" : "false";
sendMessageToHeatHub(DEVICE_ENDPOINT + deviceId + "/DeviceLockEnabled", "PATCH", payload);
}
public void setEcoMode(final boolean ecoMode) throws DraytonWiserApiException {
final String payload = "{\"EcoModeEnabled\":" + ecoMode + "}";
sendMessageToHeatHub(SYSTEM_ENDPOINT, "PATCH", payload);
}
public void setSmartPlugManualMode(final int id, final boolean manualMode) throws DraytonWiserApiException {
final String payload = "{\"Mode\":\"" + (manualMode ? "Manual" : "Auto") + "\"}";
sendMessageToHeatHub(SMARTPLUG_ENDPOINT + id, "PATCH", payload);
}
public void setSmartPlugOutputState(final int id, final boolean outputState) throws DraytonWiserApiException {
final String payload = "{\"RequestOutput\":\"" + (outputState ? "On" : "Off") + "\"}";
sendMessageToHeatHub(SMARTPLUG_ENDPOINT + id, "PATCH", payload);
}
public void setSmartPlugAwayAction(final int id, final boolean awayAction) throws DraytonWiserApiException {
final String payload = "{\"AwayAction\":\"" + (awayAction ? "Off" : "NoChange") + "\"}";
sendMessageToHeatHub(SMARTPLUG_ENDPOINT + id, "PATCH", payload);
}
private synchronized @Nullable ContentResponse sendMessageToHeatHub(final String path, final HttpMethod method)
throws DraytonWiserApiException {
return sendMessageToHeatHub(path, method.asString(), "");
}
private synchronized @Nullable ContentResponse sendMessageToHeatHub(final String path, final String method,
final String content) throws DraytonWiserApiException {
// we need to keep track of the number of times that the heat hub has "failed" to respond.
// we only actually report a failure if we hit an error state 3 or more times
try {
logger.debug("Sending message to heathub: {}", path);
final StringContentProvider contentProvider = new StringContentProvider(content);
final ContentResponse response = httpClient
.newRequest("http://" + configuration.networkAddress + "/" + path).method(method)
.header("SECRET", configuration.secret).content(contentProvider).timeout(10, TimeUnit.SECONDS)
.send();
if (logger.isTraceEnabled()) {
logger.trace("Reponse (Status:{}): {}", response.getStatus(), response.getContentAsString());
}
if (response.getStatus() == HttpStatus.OK_200) {
failCount = 0;
return response;
} else if (response.getStatus() == HttpStatus.UNAUTHORIZED_401) {
failCount++;
if (failCount > 2) {
throw new DraytonWiserApiException("Invalid authorization token");
}
} else {
failCount++;
if (failCount > 2) {
throw new DraytonWiserApiException("Heathub didn't repond after " + failCount + " retries");
}
}
} catch (final TimeoutException e) {
failCount++;
if (failCount > 2) {
logger.debug("Heathub didn't repond in time: {}", e.getMessage());
throw new DraytonWiserApiException("Heathub didn't repond in time", e);
}
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
} catch (final ExecutionException e) {
logger.debug("Execution Exception: {}", e.getMessage(), e);
throw new DraytonWiserApiException(e.getMessage(), e);
} catch (final RuntimeException e) {
logger.debug("Unexpected error: {}", e.getMessage(), e);
throw new DraytonWiserApiException(e.getMessage(), e);
}
return null;
}
}

View File

@@ -0,0 +1,34 @@
/**
* 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.draytonwiser.internal.api;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Exception thrown in case of api problems.
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
@NonNullByDefault
public class DraytonWiserApiException extends Exception {
private static final long serialVersionUID = 1L;
public DraytonWiserApiException(final String message) {
super(message);
}
public DraytonWiserApiException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,218 @@
/**
* 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.draytonwiser.internal.discovery;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.DraytonWiserRefreshListener;
import org.openhab.binding.draytonwiser.internal.handler.DraytonWiserPropertyHelper;
import org.openhab.binding.draytonwiser.internal.handler.HeatHubHandler;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.HotWaterDTO;
import org.openhab.binding.draytonwiser.internal.model.RoomDTO;
import org.openhab.binding.draytonwiser.internal.model.RoomStatDTO;
import org.openhab.binding.draytonwiser.internal.model.SmartPlugDTO;
import org.openhab.binding.draytonwiser.internal.model.SmartValveDTO;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DraytonWiserDiscoveryService} is used to discover devices that are connected to a Heat Hub.
*
* @author Andrew Schofield - Initial contribution
*/
@NonNullByDefault
public class DraytonWiserDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService, DraytonWiserRefreshListener {
private final Logger logger = LoggerFactory.getLogger(DraytonWiserDiscoveryService.class);
private @Nullable HeatHubHandler bridgeHandler;
private @Nullable ThingUID bridgeUID;
public DraytonWiserDiscoveryService() {
super(SUPPORTED_THING_TYPES_UIDS, 30, false);
}
@Override
public void activate() {
super.activate(null);
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void startScan() {
final HeatHubHandler handler = bridgeHandler;
if (handler != null) {
removeOlderResults(getTimestampOfLastScan());
handler.setDiscoveryService(this);
}
}
@Override
public void onRefresh(final DraytonWiserDTO domainDTOProxy) {
logger.debug("Received data from Drayton Wise device. Parsing to discover devices.");
onControllerAdded(domainDTOProxy);
domainDTOProxy.getRooms().forEach(this::onRoomAdded);
domainDTOProxy.getRoomStats().forEach(r -> onRoomStatAdded(domainDTOProxy, r));
domainDTOProxy.getSmartValves().forEach(sv -> onSmartValveAdded(domainDTOProxy, sv));
domainDTOProxy.getHotWater().forEach(hw -> onHotWaterAdded(domainDTOProxy, hw));
domainDTOProxy.getSmartPlugs().forEach(sp -> onSmartPlugAdded(domainDTOProxy, sp));
}
private void onControllerAdded(final DraytonWiserDTO domainDTOProxy) {
final DeviceDTO device = domainDTOProxy.getExtendedDeviceProperties(0);
if (device != null) {
logger.debug("Controller discovered, model: {}", device.getModelIdentifier());
onThingWithId(THING_TYPE_CONTROLLER, "controller", device, "Controller");
}
}
private void onHotWaterAdded(final DraytonWiserDTO domainDTOProxy, final HotWaterDTO hotWater) {
final Integer hotWaterId = hotWater.getId();
final String roomName = getRoomName(domainDTOProxy, hotWaterId);
onThingWithId(THING_TYPE_HOTWATER, "hotwater" + hotWaterId, null,
(roomName.isEmpty() ? "" : (roomName + " - ")) + "Hot Water");
}
private void onThingWithId(final ThingTypeUID deviceType, final String deviceTypeId,
@Nullable final DeviceDTO device, final String name) {
logger.debug("{} discovered: {}", deviceTypeId, name);
ThingUID localBridgeUID = this.bridgeUID;
if (localBridgeUID != null) {
final Map<String, Object> properties = new HashMap<>();
properties.put(PROP_ID, deviceTypeId);
if (device != null) {
DraytonWiserPropertyHelper.setGeneralDeviceProperties(device, properties);
}
final DiscoveryResult discoveryResult = DiscoveryResultBuilder
.create(new ThingUID(deviceType, localBridgeUID, deviceTypeId)).withBridge(localBridgeUID)
.withProperties(properties).withRepresentationProperty(PROP_ID).withLabel(name).build();
thingDiscovered(discoveryResult);
}
}
private void onRoomStatAdded(final DraytonWiserDTO domainDTOProxy, final RoomStatDTO roomStat) {
final Integer roomStatId = roomStat.getId();
final DeviceDTO device = domainDTOProxy.getExtendedDeviceProperties(roomStatId);
if (device != null) {
onThingWithSerialNumber(THING_TYPE_ROOMSTAT, "Thermostat", device, getRoomName(domainDTOProxy, roomStatId));
}
}
private void onRoomAdded(final RoomDTO room) {
ThingUID localBridgeUID = this.bridgeUID;
if (localBridgeUID != null) {
final Map<String, Object> properties = new HashMap<>();
logger.debug("Room discovered: {}", room.getName());
properties.put(PROP_NAME, room.getName());
final DiscoveryResult discoveryResult = DiscoveryResultBuilder
.create(new ThingUID(THING_TYPE_ROOM, localBridgeUID,
room.getName().replaceAll("[^A-Za-z0-9]", "").toLowerCase()))
.withBridge(localBridgeUID).withProperties(properties).withRepresentationProperty(PROP_NAME)
.withLabel(room.getName()).build();
thingDiscovered(discoveryResult);
}
}
private void onSmartValveAdded(final DraytonWiserDTO domainDTOProxy, final SmartValveDTO smartValve) {
final Integer smartValueId = smartValve.getId();
final DeviceDTO device = domainDTOProxy.getExtendedDeviceProperties(smartValueId);
if (device != null) {
onThingWithSerialNumber(THING_TYPE_ITRV, "TRV", device, getRoomName(domainDTOProxy, smartValueId));
}
}
private void onSmartPlugAdded(final DraytonWiserDTO domainDTOProxy, final SmartPlugDTO smartPlug) {
final DeviceDTO device = domainDTOProxy.getExtendedDeviceProperties(smartPlug.getId());
if (device != null) {
onThingWithSerialNumber(THING_TYPE_SMARTPLUG, "Smart Plug", device, smartPlug.getName());
}
}
private String getRoomName(final DraytonWiserDTO domainDTOProxy, final Integer roomId) {
final RoomDTO assignedRoom = domainDTOProxy.getRoomForDeviceId(roomId);
return assignedRoom == null ? "" : assignedRoom.getName();
}
private void onThingWithSerialNumber(final ThingTypeUID deviceType, final String deviceTypeName,
final DeviceDTO device, final String name) {
final String serialNumber = device.getSerialNumber();
logger.debug("{} discovered, serialnumber: {}", deviceTypeName, serialNumber);
ThingUID localBridgeUID = this.bridgeUID;
if (localBridgeUID != null) {
final Map<String, Object> properties = new HashMap<>();
DraytonWiserPropertyHelper.setPropertiesWithSerialNumber(device, properties);
final DiscoveryResult discoveryResult = DiscoveryResultBuilder
.create(new ThingUID(deviceType, localBridgeUID, serialNumber)).withBridge(localBridgeUID)
.withProperties(properties).withRepresentationProperty(PROP_SERIAL_NUMBER)
.withLabel((name.isEmpty() ? "" : (name + " - ")) + deviceTypeName).build();
thingDiscovered(discoveryResult);
}
}
@Override
public synchronized void stopScan() {
final HeatHubHandler handler = bridgeHandler;
if (handler != null) {
handler.unsetDiscoveryService();
}
super.stopScan();
}
@Override
public void setThingHandler(@Nullable final ThingHandler handler) {
if (handler instanceof HeatHubHandler) {
bridgeHandler = (HeatHubHandler) handler;
bridgeUID = handler.getThing().getUID();
} else {
bridgeHandler = null;
bridgeUID = null;
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return bridgeHandler;
}
}

View File

@@ -0,0 +1,90 @@
/**
* 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.draytonwiser.internal.discovery;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import java.net.InetAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.jmdns.ServiceInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DraytonWiserMDNSDiscoveryParticipant} is responsible for discovering Drayton Wiser Heat Hubs. It uses the
* central MDNS Discovery Service.
*
* @author Andrew Schofield - Initial contribution
*
*/
@NonNullByDefault
@Component(service = MDNSDiscoveryParticipant.class, configurationPid = "mdnsdiscovery.draytonwiser")
public class DraytonWiserMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {
private final Logger logger = LoggerFactory.getLogger(DraytonWiserMDNSDiscoveryParticipant.class);
@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return Collections.singleton(THING_TYPE_BRIDGE);
}
@Override
public String getServiceType() {
return "_http._tcp.local.";
}
@Override
public @Nullable DiscoveryResult createResult(final ServiceInfo service) {
if (service.getApplication().contains("http")) {
final ThingUID uid = getThingUID(service);
if (uid != null) {
logger.debug("Discovered Heat Hub '{}' with uid: {}", service.getName(), uid);
final Map<String, Object> properties = new HashMap<>(2);
final InetAddress[] addresses = service.getInetAddresses();
if (addresses.length > 0 && addresses[0] != null) {
properties.put(PROP_ADDRESS, addresses[0].getHostAddress());
properties.put(REFRESH_INTERVAL, DEFAULT_REFRESH_SECONDS);
}
return DiscoveryResultBuilder.create(uid).withProperties(properties)
.withRepresentationProperty(PROP_ADDRESS).withLabel("Heat Hub - " + service.getName()).build();
}
}
return null;
}
@Override
public @Nullable ThingUID getThingUID(final ServiceInfo service) {
if (service.getType() != null && service.getType().equals(getServiceType())
&& service.getName().contains("WiserHeat")) {
logger.trace("Discovered a Drayton Wiser Heat Hub thing with name '{}'", service.getName());
return new ThingUID(THING_TYPE_BRIDGE, service.getName());
}
return null;
}
}

View File

@@ -0,0 +1,166 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.SignalStrength;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.handler.ControllerHandler.ControllerData;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.HeatingChannelDTO;
import org.openhab.binding.draytonwiser.internal.model.HotWaterDTO;
import org.openhab.binding.draytonwiser.internal.model.StationDTO;
import org.openhab.binding.draytonwiser.internal.model.SystemDTO;
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.SmartHomeUnits;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link ControllerHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Simplified handler to handle null data
*/
@NonNullByDefault
public class ControllerHandler extends DraytonWiserThingHandler<ControllerData> {
public ControllerHandler(final Thing thing) {
super(thing);
}
@Override
protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
if (command instanceof OnOffType) {
final boolean onOffState = OnOffType.ON.equals(command);
if (CHANNEL_AWAY_MODE_STATE.equals(channelId)) {
setAwayMode(onOffState);
} else if (CHANNEL_ECO_MODE_STATE.equals(channelId)) {
setEcoMode(onOffState);
}
}
}
@Override
protected void refresh() {
updateState(CHANNEL_HEATING_OVERRIDE, this::getHeatingOverride);
updateState(CHANNEL_CURRENT_SIGNAL_RSSI, this::getRSSI);
updateState(CHANNEL_CURRENT_WISER_SIGNAL_STRENGTH, this::getWiserSignalStrength);
updateState(CHANNEL_CURRENT_SIGNAL_STRENGTH, this::getSignalStrength);
updateState(CHANNEL_HEATCHANNEL_1_DEMAND, this::getHeatChannel1Demand);
updateState(CHANNEL_HEATCHANNEL_2_DEMAND, this::getHeatChannel2Demand);
updateState(CHANNEL_HEATCHANNEL_1_DEMAND_STATE, this::getHeatChannel1DemandState);
updateState(CHANNEL_HEATCHANNEL_2_DEMAND_STATE, this::getHeatChannel2DemandState);
updateState(CHANNEL_AWAY_MODE_STATE, this::getAwayModeState);
updateState(CHANNEL_ECO_MODE_STATE, this::getEcoModeState);
}
@Override
protected @Nullable ControllerData collectData(final DraytonWiserDTO domainDTOProxy)
throws DraytonWiserApiException {
final StationDTO station = getApi().getStation();
final DeviceDTO device = domainDTOProxy.getExtendedDeviceProperties(0);
final SystemDTO system = domainDTOProxy.getSystem();
final List<HeatingChannelDTO> heatingChannels = domainDTOProxy.getHeatingChannels();
final List<HotWaterDTO> hotWaterChannels = domainDTOProxy.getHotWater();
return station != null && device != null && system != null
? new ControllerData(device, system, station, heatingChannels, hotWaterChannels)
: null;
}
private State getHeatingOverride() {
return OnOffType.from("ON".equalsIgnoreCase(getData().system.getHeatingButtonOverrideState()));
}
private State getRSSI() {
return new DecimalType(getData().station.getRSSI().getCurrent());
}
private State getWiserSignalStrength() {
return new StringType(getData().device.getDisplayedSignalStrength());
}
private State getSignalStrength() {
return SignalStrength.toSignalStrength(getData().device.getDisplayedSignalStrength());
}
private State getHeatChannel1Demand() {
return getData().heatingChannels.size() >= 1
? new QuantityType<>(getData().heatingChannels.get(0).getPercentageDemand(), SmartHomeUnits.PERCENT)
: UnDefType.UNDEF;
}
private State getHeatChannel2Demand() {
return getData().heatingChannels.size() >= 2
? new QuantityType<>(getData().heatingChannels.get(1).getPercentageDemand(), SmartHomeUnits.PERCENT)
: UnDefType.UNDEF;
}
private State getHeatChannel1DemandState() {
return OnOffType.from(getData().heatingChannels.size() >= 1
&& "ON".equalsIgnoreCase(getData().heatingChannels.get(0).getHeatingRelayState()));
}
private State getHeatChannel2DemandState() {
return OnOffType.from(getData().heatingChannels.size() >= 2
&& "ON".equalsIgnoreCase(getData().heatingChannels.get(1).getHeatingRelayState()));
}
private State getAwayModeState() {
return OnOffType.from(getData().system.getOverrideType() != null
&& "AWAY".equalsIgnoreCase(getData().system.getOverrideType()));
}
private State getEcoModeState() {
return OnOffType.from(getData().system.getEcoModeEnabled() != null && getData().system.getEcoModeEnabled());
}
private void setAwayMode(final Boolean awayMode) throws DraytonWiserApiException {
getApi().setAwayMode(awayMode);
}
private void setEcoMode(final Boolean ecoMode) throws DraytonWiserApiException {
getApi().setEcoMode(ecoMode);
}
static class ControllerData {
public final DeviceDTO device;
public final SystemDTO system;
public final StationDTO station;
public final List<HeatingChannelDTO> heatingChannels;
public final List<HotWaterDTO> hotWaterChannels;
public ControllerData(final DeviceDTO device, final SystemDTO system, final StationDTO station,
final List<HeatingChannelDTO> heatingChannels, final List<HotWaterDTO> hotWaterChannels) {
this.device = device;
this.system = system;
this.station = station;
this.heatingChannels = heatingChannels;
this.hotWaterChannels = hotWaterChannels;
}
}
}

View File

@@ -0,0 +1,46 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.PROP_SERIAL_NUMBER;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
/**
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Put all device property setting in a separate class
*/
@NonNullByDefault
public final class DraytonWiserPropertyHelper {
private DraytonWiserPropertyHelper() {
// helper class
}
public static void setPropertiesWithSerialNumber(final DeviceDTO device, final Map<String, Object> properties) {
properties.put(PROP_SERIAL_NUMBER, device.getSerialNumber());
setGeneralDeviceProperties(device, properties);
}
public static void setGeneralDeviceProperties(final DeviceDTO device,
final Map<String, ? super String> properties) {
properties.put("Device Type", device.getProductIdentifier());
properties.put("Firmware Version", device.getActiveFirmwareVersion());
properties.put("Manufacturer", device.getManufacturer());
properties.put("Model", device.getModelIdentifier());
}
}

View File

@@ -0,0 +1,222 @@
/**
* 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.draytonwiser.internal.handler;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.DraytonWiserRefreshListener;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApi;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.core.thing.Bridge;
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.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.util.ThingHandlerHelper;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DraytonWiserThingHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Moved generic code from subclasses to this class
*/
@NonNullByDefault
abstract class DraytonWiserThingHandler<T> extends BaseThingHandler implements DraytonWiserRefreshListener {
private final Logger logger = LoggerFactory.getLogger(getClass());
private @Nullable DraytonWiserApi api;
private @Nullable T data;
private @Nullable DraytonWiserDTO draytonWiseDTO;
private @Nullable ScheduledFuture<?> handleCommandRefreshFuture;
protected DraytonWiserThingHandler(final Thing thing) {
super(thing);
}
@Override
public void initialize() {
final HeatHubHandler bridgeHandler = getHeatHubHandler();
if (bridgeHandler == null) {
api = null;
} else {
api = bridgeHandler.getApi();
updateStatus(ThingStatus.UNKNOWN);
}
}
@Override
public final void handleCommand(final ChannelUID channelUID, final Command command) {
final HeatHubHandler heatHubHandler = getHeatHubHandler();
if (heatHubHandler == null) {
return; // if null status will be updated to offline
}
if (command instanceof RefreshType) {
heatHubHandler.refresh();
} else {
final DraytonWiserApi api = this.api;
if (api != null && data != null) {
try {
handleCommand(channelUID.getId(), command);
// cancel previous refresh, but wait for it to finish, so no forced cancel
disposehandleCommandRefreshFuture(false);
// update the state after the heathub has had time to react
handleCommandRefreshFuture = scheduler.schedule(heatHubHandler::refresh, 5, TimeUnit.SECONDS);
} catch (final DraytonWiserApiException e) {
logger.warn("Failed to handle command {} for channel {}: {}", command, channelUID, e.getMessage());
logger.trace("DraytonWiserApiException", e);
}
}
}
}
private void disposehandleCommandRefreshFuture(final boolean force) {
final ScheduledFuture<?> future = handleCommandRefreshFuture;
if (future != null) {
future.cancel(force);
}
}
@Override
public final void dispose() {
disposehandleCommandRefreshFuture(true);
}
/**
* Performs the actual command. This method is only called when api and device cache are not null.
*
* @param channelId Channel id part of the Channel UID
* @param command the command to perform
* @throws DraytonWiserApiException
*/
protected abstract void handleCommand(String channelId, Command command) throws DraytonWiserApiException;
@Override
public final void onRefresh(final DraytonWiserDTO draytonWiseDTO) {
this.draytonWiseDTO = draytonWiseDTO;
try {
if (ThingHandlerHelper.isHandlerInitialized(this)) {
data = api == null ? null : collectData(draytonWiseDTO);
refresh();
if (data == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"No data received");
} else {
if (getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
}
}
}
} catch (final RuntimeException | DraytonWiserApiException e) {
logger.debug("Exception occurred during refresh: {}", e.getMessage(), e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
}
}
/**
* Called to refresh the channels state.
*/
protected abstract void refresh();
/**
* Conditionally updates the state. If no data or no api set the state will be set to UNDEF.
*
* @param channelId String id of the channel to update
* @param stateFunction function to return the state, called when api and data are available
*/
protected void updateState(final String channelId, final Supplier<State> stateFunction) {
final State state = api == null || data == null ? UnDefType.UNDEF : stateFunction.get();
updateState(channelId, state);
}
/**
* Returns the handler specific data object only if all data is available.
* If not all data is available it should return null.
*
* @param draytonWiseDTO data object with domain data as received from the hub
* @return handler data object if available else null
* @throws DraytonWiserApiException
*/
protected abstract @Nullable T collectData(DraytonWiserDTO draytonWiseDTO) throws DraytonWiserApiException;
protected DraytonWiserApi getApi() {
final DraytonWiserApi api = this.api;
if (api == null) {
throw new IllegalStateException("API not set");
}
return api;
}
protected T getData() {
final @Nullable T data = this.data;
if (data == null) {
throw new IllegalStateException("Data not set");
}
return data;
}
protected DraytonWiserDTO getDraytonWiseDTO() {
final DraytonWiserDTO draytonWiseDTO = this.draytonWiseDTO;
if (draytonWiseDTO == null) {
throw new IllegalStateException("DraytonWiseDTO not set");
}
return draytonWiseDTO;
}
@Override
public void bridgeStatusChanged(final ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
if (getThing().getStatus() != ThingStatus.ONLINE) {
final HeatHubHandler bridgeHandler = getHeatHubHandler();
api = bridgeHandler == null ? null : bridgeHandler.getApi();
updateStatus(ThingStatus.UNKNOWN);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
}
private @Nullable HeatHubHandler getHeatHubHandler() {
final Bridge bridge = getBridge();
if (bridge == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return null;
} else {
return (HeatHubHandler) bridge.getHandler();
}
}
}

View File

@@ -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.draytonwiser.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Hilbrand Bouwkamp - Initial contribution
*/
@NonNullByDefault
public class HeatHubConfiguration {
public String networkAddress = "";
public String secret = "";
public int refresh;
public int awaySetPoint;
}

View File

@@ -0,0 +1,170 @@
/**
* 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.draytonwiser.internal.handler;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.draytonwiser.internal.DraytonWiserRefreshListener;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApi;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.discovery.DraytonWiserDiscoveryService;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
import org.openhab.binding.draytonwiser.internal.model.DomainDTO;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.thing.Bridge;
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.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.thing.util.ThingHandlerHelper;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link HeatHubHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Moved api and helper code to separate classes
*/
@NonNullByDefault
public class HeatHubHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(HeatHubHandler.class);
private final DraytonWiserApi api;
private final ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(3, this::actualRefresh);
private boolean updateProperties;
private @Nullable DraytonWiserRefreshListener discoveryService;
private @Nullable ScheduledFuture<?> refreshJob;
public HeatHubHandler(final Bridge thing, final HttpClient httpClient) {
super(thing);
api = new DraytonWiserApi(httpClient);
}
public DraytonWiserApi getApi() {
return api;
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(DraytonWiserDiscoveryService.class);
}
public void setDiscoveryService(final DraytonWiserRefreshListener discoveryService) {
this.discoveryService = discoveryService;
refreshCache.invalidateValue();
refresh();
}
public void unsetDiscoveryService() {
discoveryService = null;
}
@Override
public void handleCommand(final ChannelUID channelUID, final Command command) {
}
@Override
public void initialize() {
logger.debug("Initializing Drayton Wiser Heat Hub handler");
final HeatHubConfiguration configuration = getConfigAs(HeatHubConfiguration.class);
api.setConfiguration(configuration);
updateProperties = true;
refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, configuration.refresh, TimeUnit.SECONDS);
updateStatus(ThingStatus.UNKNOWN);
}
public void refresh() {
refreshCache.getValue();
}
private @Nullable Boolean actualRefresh() {
try {
if (ThingHandlerHelper.isHandlerInitialized(this)) {
logger.debug("Refreshing devices");
final DomainDTO domain = api.getDomain();
if (domain == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
"No data received");
} else {
if (getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
}
final DraytonWiserDTO draytonWiseDTO = new DraytonWiserDTO(domain);
updateProperties(draytonWiseDTO);
notifyListeners(draytonWiseDTO);
}
logger.debug("Finished refreshing devices");
}
} catch (final RuntimeException | DraytonWiserApiException e) {
logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage());
return null;
}
return Boolean.TRUE;
}
@Override
public void childHandlerInitialized(final ThingHandler childHandler, final Thing childThing) {
refresh();
}
private void updateProperties(final DraytonWiserDTO draytonWiseDTO) {
if (updateProperties) {
final DeviceDTO device = draytonWiseDTO.getExtendedDeviceProperties(0);
if (device != null) {
final Map<String, String> properties = editProperties();
DraytonWiserPropertyHelper.setGeneralDeviceProperties(device, properties);
updateProperties(properties);
updateProperties = false;
}
}
}
@Override
public void dispose() {
final ScheduledFuture<?> future = refreshJob;
if (future != null) {
future.cancel(true);
}
}
private void notifyListeners(final DraytonWiserDTO domain) {
final DraytonWiserRefreshListener discoveryListener = discoveryService;
if (discoveryListener != null) {
discoveryListener.onRefresh(domain);
}
getThing().getThings().stream().map(Thing::getHandler)
.filter(handler -> handler instanceof DraytonWiserRefreshListener)
.map(DraytonWiserRefreshListener.class::cast).forEach(listener -> listener.onRefresh(domain));
}
}

View File

@@ -0,0 +1,151 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import java.util.List;
import javax.measure.quantity.Time;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.handler.HotWaterHandler.HotWaterData;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.HotWaterDTO;
import org.openhab.binding.draytonwiser.internal.model.SystemDTO;
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.unit.SmartHomeUnits;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
/**
* The {@link HotWaterHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Simplified handler to handle null data
*/
@NonNullByDefault
public class HotWaterHandler extends DraytonWiserThingHandler<HotWaterData> {
public HotWaterHandler(final Thing thing) {
super(thing);
}
@Override
protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
if (command instanceof OnOffType && CHANNEL_MANUAL_MODE_STATE.equals(channelId)) {
setManualMode(OnOffType.ON.equals(command));
} else if (command instanceof OnOffType && CHANNEL_HOT_WATER_SETPOINT.equals(channelId)) {
setSetPoint(OnOffType.ON.equals(command));
} else if (command instanceof DecimalType && CHANNEL_HOT_WATER_BOOST_DURATION.equals(channelId)) {
setBoostDuration(Math.round((Float.parseFloat(command.toString()) * 60)));
}
}
@Override
protected void refresh() {
updateState(CHANNEL_HOT_WATER_OVERRIDE, this::getHotWaterOverride);
updateState(CHANNEL_HOTWATER_DEMAND_STATE, this::getHotWaterDemandState);
updateState(CHANNEL_MANUAL_MODE_STATE, this::getManualModeState);
updateState(CHANNEL_HOT_WATER_SETPOINT, this::getSetPointState);
updateState(CHANNEL_HOT_WATER_BOOSTED, this::getBoostedState);
updateState(CHANNEL_HOT_WATER_BOOST_REMAINING, this::getBoostRemainingState);
}
@Override
protected @Nullable HotWaterData collectData(final DraytonWiserDTO domainDTOProxy) {
final SystemDTO system = domainDTOProxy.getSystem();
final List<HotWaterDTO> hotWater = domainDTOProxy.getHotWater();
return system == null ? null : new HotWaterData(system, hotWater);
}
private State getHotWaterOverride() {
return OnOffType.from("ON".equalsIgnoreCase(getData().system.getHotWaterButtonOverrideState()));
}
private State getHotWaterDemandState() {
final List<HotWaterDTO> hotWater = getData().hotWater;
return OnOffType.from(hotWater.size() >= 1 && "ON".equalsIgnoreCase(hotWater.get(0).getHotWaterRelayState()));
}
private State getManualModeState() {
final List<HotWaterDTO> hotWater = getData().hotWater;
return OnOffType.from(hotWater.size() >= 1 && "MANUAL".equalsIgnoreCase(hotWater.get(0).getMode()));
}
private State getSetPointState() {
final List<HotWaterDTO> hotWater = getData().hotWater;
return OnOffType.from(hotWater.size() >= 1 && "ON".equalsIgnoreCase(hotWater.get(0).getWaterHeatingState()));
}
private void setManualMode(final boolean manualMode) throws DraytonWiserApiException {
getApi().setHotWaterManualMode(manualMode);
}
private void setSetPoint(final boolean setPointMode) throws DraytonWiserApiException {
getApi().setHotWaterSetPoint(setPointMode ? 1100 : -200);
}
private void setBoostDuration(final int durationMinutes) throws DraytonWiserApiException {
if (durationMinutes > 0) {
getApi().setHotWaterBoostActive(durationMinutes);
} else {
getApi().setHotWaterBoostInactive();
}
}
private State getBoostedState() {
if (getData().hotWater.size() >= 1) {
final HotWaterDTO firstChannel = getData().hotWater.get(0);
if (firstChannel.getOverrideTimeoutUnixTime() != null
&& !"NONE".equalsIgnoreCase(firstChannel.getOverrideType())) {
return OnOffType.ON;
}
}
updateState(CHANNEL_HOT_WATER_BOOST_DURATION, DecimalType.ZERO);
return OnOffType.OFF;
}
private State getBoostRemainingState() {
if (getData().hotWater.size() >= 1) {
final HotWaterDTO firstChannel = getData().hotWater.get(0);
final Integer overrideTimeout = firstChannel.getOverrideTimeoutUnixTime();
if (overrideTimeout != null && !"NONE".equalsIgnoreCase(firstChannel.getOverrideType())) {
return new QuantityType<Time>(overrideTimeout - (System.currentTimeMillis() / 1000L),
SmartHomeUnits.SECOND);
}
}
return new QuantityType<Time>(0, SmartHomeUnits.SECOND);
}
static class HotWaterData {
public final SystemDTO system;
public final List<HotWaterDTO> hotWater;
public HotWaterData(final SystemDTO system, final List<HotWaterDTO> hotWater) {
this.system = system;
this.hotWater = hotWater;
}
}
}

View File

@@ -0,0 +1,194 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import javax.measure.quantity.Time;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.RoomDTO;
import org.openhab.binding.draytonwiser.internal.model.RoomStatDTO;
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.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link RoomHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Simplified handler to handle null data
*/
@NonNullByDefault
public class RoomHandler extends DraytonWiserThingHandler<RoomDTO> {
private String name = "";
public RoomHandler(final Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
name = (String) getConfig().get("name");
}
@Override
protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
switch (channelId) {
case CHANNEL_CURRENT_SETPOINT:
if (command instanceof QuantityType) {
setSetPoint((QuantityType<?>) command);
}
break;
case CHANNEL_MANUAL_MODE_STATE:
if (command instanceof OnOffType) {
setManualMode(OnOffType.ON.equals(command));
}
break;
case CHANNEL_ROOM_BOOST_DURATION:
if (command instanceof DecimalType) {
setBoostDuration(Math.round((((DecimalType) command).floatValue() * 60)));
}
break;
case CHANNEL_ROOM_WINDOW_STATE_DETECTION:
if (command instanceof OnOffType) {
setWindowStateDetection(OnOffType.ON.equals(command));
}
break;
}
}
@Override
protected void refresh() {
updateState(CHANNEL_CURRENT_TEMPERATURE, this::getTemperature);
updateState(CHANNEL_CURRENT_HUMIDITY, this::getHumidity);
updateState(CHANNEL_CURRENT_SETPOINT, this::getSetPoint);
updateState(CHANNEL_CURRENT_DEMAND, this::getDemand);
updateState(CHANNEL_HEAT_REQUEST, this::getHeatRequest);
updateState(CHANNEL_MANUAL_MODE_STATE, this::getManualModeState);
updateState(CHANNEL_ROOM_BOOSTED, this::getBoostedState);
updateState(CHANNEL_ROOM_BOOST_REMAINING, this::getBoostRemainingState);
updateState(CHANNEL_ROOM_WINDOW_STATE_DETECTION, this::getWindowDetectionState);
updateState(CHANNEL_ROOM_WINDOW_STATE, this::getWindowState);
}
@Override
protected @Nullable RoomDTO collectData(final DraytonWiserDTO domainDTOProxy) {
return domainDTOProxy.getRoomByName(name);
}
private State getSetPoint() {
return new QuantityType<>(getData().getCurrentSetPoint() / 10.0, SIUnits.CELSIUS);
}
private void setSetPoint(final QuantityType<?> command) throws DraytonWiserApiException {
if (getData().getId() != null) {
final QuantityType<?> value = command.toUnit(SIUnits.CELSIUS);
if (value != null) {
final int newSetPoint = (int) Math.round(value.doubleValue() * 10);
getApi().setRoomSetPoint(getData().getId(), newSetPoint);
}
}
}
private State getHumidity() {
if (getData().getId() != null && getData().getRoomStatId() != null) {
final RoomStatDTO roomStat = getDraytonWiseDTO().getRoomStat(getData().getRoomStatId());
if (roomStat != null) {
final Integer humidity = roomStat.getMeasuredHumidity();
return humidity == null ? UnDefType.UNDEF : new QuantityType<>(humidity, SmartHomeUnits.PERCENT);
}
}
return UnDefType.UNDEF;
}
private State getTemperature() {
final int fullScaleTemp = getData().getCalculatedTemperature();
return OFFLINE_TEMPERATURE == fullScaleTemp ? UnDefType.UNDEF
: new QuantityType<>(fullScaleTemp / 10.0, SIUnits.CELSIUS);
}
private State getDemand() {
return new QuantityType<>(getData().getPercentageDemand(), SmartHomeUnits.PERCENT);
}
private State getHeatRequest() {
return OnOffType.from(getData().getControlOutputState());
}
private State getManualModeState() {
return OnOffType.from("MANUAL".equalsIgnoreCase(getData().getMode()));
}
private void setManualMode(final boolean manualMode) throws DraytonWiserApiException {
getApi().setRoomManualMode(getData().getId(), manualMode);
}
private void setWindowStateDetection(final boolean stateDetection) throws DraytonWiserApiException {
getApi().setRoomWindowStateDetection(getData().getId(), stateDetection);
}
private State getBoostedState() {
if (getData().getOverrideTimeoutUnixTime() != null && !"NONE".equalsIgnoreCase(getData().getOverrideType())) {
return OnOffType.ON;
}
updateState(CHANNEL_ROOM_BOOST_DURATION, DecimalType.ZERO);
return OnOffType.OFF;
}
private State getBoostRemainingState() {
final Integer overrideTimeout = getData().getOverrideTimeoutUnixTime();
if (overrideTimeout != null && !"NONE".equalsIgnoreCase(getData().getOverrideType())) {
return new QuantityType<Time>(overrideTimeout - (System.currentTimeMillis() / 1000L),
SmartHomeUnits.SECOND);
}
return new QuantityType<Time>(0, SmartHomeUnits.SECOND);
}
private void setBoostDuration(final int durationMinutes) throws DraytonWiserApiException {
if (durationMinutes > 0) {
getApi().setRoomBoostActive(getData().getId(), getData().getCalculatedTemperature() + 20, durationMinutes);
} else {
getApi().setRoomBoostInactive(getData().getId());
}
}
private State getWindowDetectionState() {
return OnOffType.from(getData().getWindowDetectionActive());
}
private State getWindowState() {
if (getData().getWindowState() != null && "OPEN".equalsIgnoreCase(getData().getWindowState())) {
return OpenClosedType.OPEN;
}
return OpenClosedType.CLOSED;
}
}

View File

@@ -0,0 +1,156 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.BatteryLevel;
import org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.SignalStrength;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.handler.RoomStatHandler.RoomStatData;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.RoomStatDTO;
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.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link RoomStatHandler} is responsible for handling commands, which are sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Simplified handler to handle null data
*/
@NonNullByDefault
public class RoomStatHandler extends DraytonWiserThingHandler<RoomStatData> {
private String serialNumber = "";
public RoomStatHandler(final Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
serialNumber = getConfig().get("serialNumber").toString();
}
@Override
protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
if (command instanceof OnOffType && CHANNEL_DEVICE_LOCKED.equals(channelId)) {
setDeviceLocked(OnOffType.ON.equals(command));
}
}
@Override
protected void refresh() {
updateState(CHANNEL_CURRENT_TEMPERATURE, this::getTemperature);
updateState(CHANNEL_CURRENT_HUMIDITY, this::getHumidity);
updateState(CHANNEL_CURRENT_SETPOINT, this::getSetPoint);
updateState(CHANNEL_CURRENT_SIGNAL_RSSI, this::getSignalRSSI);
updateState(CHANNEL_CURRENT_SIGNAL_LQI, this::getSignalLQI);
updateState(CHANNEL_CURRENT_BATTERY_VOLTAGE, this::getBatteryVoltage);
updateState(CHANNEL_CURRENT_WISER_SIGNAL_STRENGTH, this::getWiserSignalStrength);
updateState(CHANNEL_CURRENT_SIGNAL_STRENGTH, this::getSignalStrength);
updateState(CHANNEL_CURRENT_WISER_BATTERY_LEVEL, this::getWiserBatteryLevel);
updateState(CHANNEL_CURRENT_BATTERY_LEVEL, this::getBatteryLevel);
updateState(CHANNEL_ZIGBEE_CONNECTED, this::getZigbeeConnected);
updateState(CHANNEL_DEVICE_LOCKED, this::getDeviceLocked);
}
@Override
protected @Nullable RoomStatData collectData(final DraytonWiserDTO domainDTOProxy) {
final RoomStatDTO roomStat = domainDTOProxy.getRoomStat(serialNumber);
final DeviceDTO device = roomStat == null ? null : domainDTOProxy.getExtendedDeviceProperties(roomStat.getId());
return roomStat == null || device == null ? null : new RoomStatData(roomStat, device);
}
private State getSetPoint() {
return new QuantityType<>(getData().roomStat.getSetPoint() / 10.0, SIUnits.CELSIUS);
}
private State getHumidity() {
final Integer humidity = getData().roomStat.getMeasuredHumidity();
return humidity == null ? UnDefType.UNDEF : new QuantityType<>(humidity, SmartHomeUnits.PERCENT);
}
private State getTemperature() {
final int fullScaleTemp = getData().roomStat.getMeasuredTemperature();
return OFFLINE_TEMPERATURE == fullScaleTemp ? UnDefType.UNDEF
: new QuantityType<>(fullScaleTemp / 10.0, SIUnits.CELSIUS);
}
private State getSignalRSSI() {
return new DecimalType(getData().device.getRssi());
}
private State getSignalLQI() {
return new DecimalType(getData().device.getLqi());
}
private State getWiserSignalStrength() {
return new StringType(getData().device.getDisplayedSignalStrength());
}
private State getSignalStrength() {
return SignalStrength.toSignalStrength(getData().device.getDisplayedSignalStrength());
}
private State getBatteryVoltage() {
return new QuantityType<>(getData().device.getBatteryVoltage() / 10.0, SmartHomeUnits.VOLT);
}
private State getWiserBatteryLevel() {
return new StringType(getData().device.getBatteryLevel());
}
private State getBatteryLevel() {
return BatteryLevel.toBatteryLevel(getData().device.getBatteryLevel());
}
private State getZigbeeConnected() {
return OnOffType.from(OFFLINE_TEMPERATURE != getData().roomStat.getMeasuredTemperature());
}
private State getDeviceLocked() {
return getData().device.getDeviceLockEnabled() == null ? UnDefType.UNDEF
: OnOffType.from(getData().device.getDeviceLockEnabled());
}
private void setDeviceLocked(final boolean state) throws DraytonWiserApiException {
getApi().setDeviceLocked(getData().device.getId(), state);
}
static class RoomStatData {
public final RoomStatDTO roomStat;
public final DeviceDTO device;
public RoomStatData(final RoomStatDTO roomStat, final DeviceDTO device) {
this.roomStat = roomStat;
this.device = device;
}
}
}

View File

@@ -0,0 +1,148 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.handler.SmartPlugHandler.SmartPlugData;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.SmartPlugDTO;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link SmartPlugHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Simplified handler to handle null data
*/
@NonNullByDefault
public class SmartPlugHandler extends DraytonWiserThingHandler<SmartPlugData> {
private String serialNumber = "";
public SmartPlugHandler(final Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
serialNumber = getConfig().get("serialNumber").toString();
}
@Override
protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
if (command instanceof OnOffType) {
switch (channelId) {
case CHANNEL_DEVICE_LOCKED:
setDeviceLocked(OnOffType.ON.equals(command));
break;
case CHANNEL_SMARTPLUG_OUTPUT_STATE:
setOutputState(OnOffType.ON.equals(command));
break;
case CHANNEL_SMARTPLUG_AWAY_ACTION:
setAwayAction(OnOffType.ON.equals(command));
break;
case CHANNEL_MANUAL_MODE_STATE:
setManualMode(OnOffType.ON.equals(command));
break;
}
}
}
@Override
protected void refresh() {
updateState(CHANNEL_SMARTPLUG_OUTPUT_STATE, this::getOutputState);
updateState(CHANNEL_SMARTPLUG_AWAY_ACTION, this::getAwayAction);
updateState(CHANNEL_CURRENT_SIGNAL_RSSI, this::getSignalRSSI);
updateState(CHANNEL_CURRENT_SIGNAL_LQI, this::getSignalLQI);
updateState(CHANNEL_ZIGBEE_CONNECTED, this::getZigbeeConnected);
updateState(CHANNEL_DEVICE_LOCKED, this::getDeviceLocked);
updateState(CHANNEL_MANUAL_MODE_STATE, this::getManualModeState);
}
@Override
protected @Nullable SmartPlugData collectData(final DraytonWiserDTO domainDTOProxy) {
final SmartPlugDTO smartPlug = domainDTOProxy.getSmartPlug(serialNumber);
final DeviceDTO device = smartPlug == null ? null
: domainDTOProxy.getExtendedDeviceProperties(smartPlug.getId());
return smartPlug == null || device == null ? null : new SmartPlugData(smartPlug, device);
}
private State getAwayAction() {
return OnOffType.from("off".equalsIgnoreCase(getData().smartPlug.getAwayAction()));
}
private State getOutputState() {
final String outputState = getData().smartPlug.getOutputState();
return outputState == null ? UnDefType.UNDEF : OnOffType.from(outputState);
}
private State getSignalRSSI() {
return new DecimalType(getData().device.getRssi());
}
private State getSignalLQI() {
return new DecimalType(getData().device.getLqi());
}
private State getZigbeeConnected() {
return getData().device.getLqi() == null ? OnOffType.OFF : OnOffType.ON;
}
private State getDeviceLocked() {
return getData().device.getDeviceLockEnabled() == null ? UnDefType.UNDEF
: OnOffType.from(getData().device.getDeviceLockEnabled());
}
private void setDeviceLocked(final Boolean state) throws DraytonWiserApiException {
getApi().setDeviceLocked(getData().device.getId(), state);
}
private State getManualModeState() {
return OnOffType.from("MANUAL".equalsIgnoreCase(getData().smartPlug.getMode()));
}
private void setManualMode(final Boolean manualMode) throws DraytonWiserApiException {
getApi().setSmartPlugManualMode(getData().smartPlug.getId(), manualMode);
}
private void setOutputState(final Boolean outputState) throws DraytonWiserApiException {
getApi().setSmartPlugOutputState(getData().smartPlug.getId(), outputState);
}
private void setAwayAction(final Boolean awayAction) throws DraytonWiserApiException {
getApi().setSmartPlugAwayAction(getData().smartPlug.getId(), awayAction);
}
static class SmartPlugData {
public final SmartPlugDTO smartPlug;
public final DeviceDTO device;
public SmartPlugData(final SmartPlugDTO smartPlug, final DeviceDTO device) {
this.smartPlug = smartPlug;
this.device = device;
}
}
}

View File

@@ -0,0 +1,157 @@
/**
* 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.draytonwiser.internal.handler;
import static org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.BatteryLevel;
import org.openhab.binding.draytonwiser.internal.DraytonWiserBindingConstants.SignalStrength;
import org.openhab.binding.draytonwiser.internal.api.DraytonWiserApiException;
import org.openhab.binding.draytonwiser.internal.handler.TRVHandler.SmartValveData;
import org.openhab.binding.draytonwiser.internal.model.DeviceDTO;
import org.openhab.binding.draytonwiser.internal.model.DraytonWiserDTO;
import org.openhab.binding.draytonwiser.internal.model.SmartValveDTO;
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.library.unit.SmartHomeUnits;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link TRVHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Simplified handler to handle null data
*/
@NonNullByDefault
public class TRVHandler extends DraytonWiserThingHandler<SmartValveData> {
private String serialNumber = "";
public TRVHandler(final Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
serialNumber = getConfig().get("serialNumber").toString();
}
@Override
protected void handleCommand(final String channelId, final Command command) throws DraytonWiserApiException {
if (command instanceof OnOffType && CHANNEL_DEVICE_LOCKED.equals(channelId)) {
setDeviceLocked(OnOffType.ON.equals(command));
}
}
@Override
protected void refresh() {
updateState(CHANNEL_CURRENT_TEMPERATURE, this::getTemperature);
updateState(CHANNEL_CURRENT_DEMAND, this::getDemand);
updateState(CHANNEL_CURRENT_SETPOINT, this::getSetPoint);
updateState(CHANNEL_CURRENT_SIGNAL_RSSI, this::getSignalRSSI);
updateState(CHANNEL_CURRENT_SIGNAL_LQI, this::getSignalLQI);
updateState(CHANNEL_CURRENT_BATTERY_VOLTAGE, this::getBatteryVoltage);
updateState(CHANNEL_CURRENT_WISER_SIGNAL_STRENGTH, this::getWiserSignalStrength);
updateState(CHANNEL_CURRENT_SIGNAL_STRENGTH, this::getSignalStrength);
updateState(CHANNEL_CURRENT_WISER_BATTERY_LEVEL, this::getWiserBatteryLevel);
updateState(CHANNEL_CURRENT_BATTERY_LEVEL, this::getBatteryLevel);
updateState(CHANNEL_ZIGBEE_CONNECTED, this::getZigbeeConnected);
updateState(CHANNEL_DEVICE_LOCKED, this::getDeviceLocked);
}
@Override
protected @Nullable SmartValveData collectData(final DraytonWiserDTO domainDTOProxy) {
final SmartValveDTO smartValve = domainDTOProxy.getSmartValve(serialNumber);
final DeviceDTO device = smartValve == null ? null
: domainDTOProxy.getExtendedDeviceProperties(smartValve.getId());
return smartValve == null || device == null ? null : new SmartValveData(smartValve, device);
}
private State getSetPoint() {
return new QuantityType<>(getData().smartValve.getSetPoint() / 10.0, SIUnits.CELSIUS);
}
private State getDemand() {
return new QuantityType<>(getData().smartValve.getPercentageDemand(), SmartHomeUnits.PERCENT);
}
private State getTemperature() {
final int fullScaleTemp = getData().smartValve.getMeasuredTemperature();
return OFFLINE_TEMPERATURE == fullScaleTemp ? UnDefType.UNDEF
: new QuantityType<>(fullScaleTemp / 10.0, SIUnits.CELSIUS);
}
private State getSignalRSSI() {
return new DecimalType(getData().device.getRssi());
}
private State getSignalLQI() {
return new DecimalType(getData().device.getLqi());
}
private State getWiserSignalStrength() {
return new StringType(getData().device.getDisplayedSignalStrength());
}
private State getSignalStrength() {
return SignalStrength.toSignalStrength(getData().device.getDisplayedSignalStrength());
}
private State getBatteryVoltage() {
return new QuantityType<>(getData().device.getBatteryVoltage() / 10.0, SmartHomeUnits.VOLT);
}
private State getWiserBatteryLevel() {
return new StringType(getData().device.getBatteryLevel());
}
private State getBatteryLevel() {
return BatteryLevel.toBatteryLevel(getData().device.getBatteryLevel());
}
private State getZigbeeConnected() {
return OnOffType.from(getData().smartValve.getMeasuredTemperature() != OFFLINE_TEMPERATURE);
}
private State getDeviceLocked() {
final Boolean locked = getData().device.getDeviceLockEnabled();
return locked == null ? UnDefType.UNDEF : OnOffType.from(locked);
}
private void setDeviceLocked(final Boolean state) throws DraytonWiserApiException {
getApi().setDeviceLocked(getData().device.getId(), state);
}
static class SmartValveData {
public final SmartValveDTO smartValve;
public final DeviceDTO device;
public SmartValveData(final SmartValveDTO smartValve, final DeviceDTO device) {
this.smartValve = smartValve;
this.device = device;
}
}
}

View File

@@ -0,0 +1,47 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class BoilerSettingsDTO {
private String controlType;
private String fuelType;
private String cycleRate;
public String getControlType() {
return controlType;
}
public void setControlType(final String controlType) {
this.controlType = controlType;
}
public String getFuelType() {
return fuelType;
}
public void setFuelType(final String fuelType) {
this.fuelType = fuelType;
}
public String getCycleRate() {
return cycleRate;
}
public void setCycleRate(final String cycleRate) {
this.cycleRate = cycleRate;
}
}

View File

@@ -0,0 +1,52 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class DetectedAccessPointDTO {
private String sSID;
private Integer channel;
private String securityMode;
private Integer rSSI;
public String getSSID() {
return sSID;
}
public void setSSID(final String sSID) {
this.sSID = sSID;
}
public Integer getChannel() {
return channel;
}
public void setChannel(final Integer channel) {
this.channel = channel;
}
public String getSecurityMode() {
return securityMode;
}
public void setSecurityMode(final String securityMode) {
this.securityMode = securityMode;
}
public Integer getRSSI() {
return rSSI;
}
}

View File

@@ -0,0 +1,123 @@
/**
* 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.draytonwiser.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class DeviceDTO {
@SerializedName("id")
private Integer id;
private String productType;
private String productIdentifier;
private String activeFirmwareVersion;
private String manufacturer;
private String modelIdentifier;
private String hardwareVersion;
private String serialNumber;
private String productRange;
private String productModel;
private String productFamily;
private String displayedSignalStrength;
private Integer batteryVoltage;
private String batteryLevel;
private Integer rssi;
private Integer lqi;
private ReceptionDTO receptionOfDevice;
private ReceptionDTO receptionOfController;
private Boolean deviceLockEnabled;
public Integer getId() {
return id;
}
public String getProductType() {
return productType;
}
public String getProductIdentifier() {
return productIdentifier;
}
public String getActiveFirmwareVersion() {
return activeFirmwareVersion;
}
public String getManufacturer() {
return manufacturer;
}
public String getModelIdentifier() {
return modelIdentifier;
}
public String getHardwareVersion() {
return hardwareVersion;
}
public String getSerialNumber() {
return serialNumber;
}
public String getProductRange() {
return productRange;
}
public String getProductModel() {
return productModel;
}
public String getProductFamily() {
return productFamily;
}
public String getDisplayedSignalStrength() {
return displayedSignalStrength;
}
public int getBatteryVoltage() {
return batteryVoltage == null ? Integer.MIN_VALUE : batteryVoltage;
}
public String getBatteryLevel() {
return batteryLevel;
}
public Integer getRssi() {
if (rssi != null) {
return rssi;
}
// JSON response changed with firmware update to include RSSI and LQI on a separate object
return receptionOfDevice == null ? null : receptionOfDevice.getRSSI();
}
public Integer getLqi() {
if (lqi != null) {
return lqi;
}
return receptionOfDevice == null ? null : receptionOfDevice.getLQI();
}
public ReceptionDTO getReceptionOfController() {
return receptionOfController;
}
public Boolean getDeviceLockEnabled() {
return deviceLockEnabled;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class DhcpStatusDTO {
private String status;
private Long leaseStartTime;
private Long leaseTime;
private String iPv4Address;
private String iPv4SubnetMask;
private String iPv4DefaultGateway;
private String iPv4PrimaryDNS;
private String iPv4SecondaryDNS;
public String getStatus() {
return status;
}
public Long getLeaseStartTime() {
return leaseStartTime;
}
public Long getLeaseTime() {
return leaseTime;
}
public String getIPv4Address() {
return iPv4Address;
}
public String getIPv4SubnetMask() {
return iPv4SubnetMask;
}
public String getIPv4DefaultGateway() {
return iPv4DefaultGateway;
}
public String getIPv4PrimaryDNS() {
return iPv4PrimaryDNS;
}
public String getIPv4SecondaryDNS() {
return iPv4SecondaryDNS;
}
}

View File

@@ -0,0 +1,94 @@
/**
* 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.draytonwiser.internal.model;
import java.util.List;
/**
* @author Andrew Schofield - Initial contribution
*/
public class DomainDTO {
private SystemDTO system;
private List<HeatingChannelDTO> heatingChannel;
private List<HotWaterDTO> hotWater;
private List<RoomDTO> room;
private List<DeviceDTO> device;
private List<SmartValveDTO> smartValve;
private List<RoomStatDTO> roomStat;
private List<SmartPlugDTO> smartPlug;
public SystemDTO getSystem() {
return system;
}
public void setSystem(final SystemDTO system) {
this.system = system;
}
public List<HeatingChannelDTO> getHeatingChannel() {
return heatingChannel;
}
public void setHeatingChannel(final List<HeatingChannelDTO> heatingChannel) {
this.heatingChannel = heatingChannel;
}
public List<HotWaterDTO> getHotWater() {
return hotWater;
}
public void setHotWater(final List<HotWaterDTO> hotWater) {
this.hotWater = hotWater;
}
public List<RoomDTO> getRoom() {
return room;
}
public void setRoom(final List<RoomDTO> room) {
this.room = room;
}
public List<DeviceDTO> getDevice() {
return device;
}
public void setDevice(final List<DeviceDTO> device) {
this.device = device;
}
public List<SmartValveDTO> getSmartValve() {
return smartValve;
}
public void setSmartValve(final List<SmartValveDTO> smartValve) {
this.smartValve = smartValve;
}
public List<RoomStatDTO> getRoomStat() {
return roomStat;
}
public void setRoomStat(final List<RoomStatDTO> roomStat) {
this.roomStat = roomStat;
}
public List<SmartPlugDTO> getSmartPlug() {
return smartPlug;
}
public void setSmartPlug(final List<SmartPlugDTO> smartPlug) {
this.smartPlug = smartPlug;
}
}

View File

@@ -0,0 +1,157 @@
/**
* 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.draytonwiser.internal.model;
import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* Helper class to get specific data from the domain object.
*
* @author Andrew Schofield - Initial contribution
* @author Hilbrand Bouwkamp - Moved domain object helper code to it's own class
*/
@NonNullByDefault
public class DraytonWiserDTO {
private final DomainDTO domain;
public DraytonWiserDTO(final DomainDTO domain) {
this.domain = domain;
}
public List<RoomStatDTO> getRoomStats() {
return domain.getRoomStat() == null ? Collections.emptyList() : domain.getRoomStat();
}
public List<SmartValveDTO> getSmartValves() {
return domain.getSmartValve() == null ? Collections.emptyList() : domain.getSmartValve();
}
public List<SmartPlugDTO> getSmartPlugs() {
return domain.getSmartPlug() == null ? Collections.emptyList() : domain.getSmartPlug();
}
public List<RoomDTO> getRooms() {
return domain.getRoom() == null ? Collections.emptyList() : domain.getRoom();
}
public @Nullable RoomDTO getRoomByName(final String name) {
for (final RoomDTO room : domain.getRoom()) {
if (room.getName().equalsIgnoreCase(name)) {
return room;
}
}
return null;
}
public @Nullable RoomStatDTO getRoomStat(final String serialNumber) {
final Integer id = getIdFromSerialNumber(serialNumber);
return id == null ? null : getRoomStat(id);
}
public @Nullable RoomStatDTO getRoomStat(final int id) {
for (final RoomStatDTO roomStat : domain.getRoomStat()) {
if (roomStat.getId().equals(id)) {
return roomStat;
}
}
return null;
}
public @Nullable SmartPlugDTO getSmartPlug(final String serialNumber) {
final Integer id = getIdFromSerialNumber(serialNumber);
if (id == null) {
return null;
}
for (final SmartPlugDTO smartPlug : domain.getSmartPlug()) {
if (smartPlug.getId().equals(id)) {
return smartPlug;
}
}
return null;
}
public @Nullable DeviceDTO getExtendedDeviceProperties(final int id) {
for (final DeviceDTO device : domain.getDevice()) {
if (device.getId().equals(id)) {
return device;
}
}
return null;
}
public @Nullable SystemDTO getSystem() {
return domain.getSystem();
}
public List<HeatingChannelDTO> getHeatingChannels() {
return domain.getHeatingChannel() == null ? Collections.emptyList() : domain.getHeatingChannel();
}
public List<HotWaterDTO> getHotWater() {
return domain.getHotWater() == null ? Collections.emptyList() : domain.getHotWater();
}
@Nullable
public RoomDTO getRoomForDeviceId(final Integer id) {
for (final RoomDTO room : domain.getRoom()) {
if (room != null) {
if (room.getRoomStatId() != null && room.getRoomStatId().equals(id)) {
return room;
}
final List<Integer> trvs = room.getSmartValveIds();
if (trvs != null) {
for (final Integer itrv : trvs) {
if (itrv.equals(id)) {
return room;
}
}
}
}
}
return null;
}
public @Nullable SmartValveDTO getSmartValve(final String serialNumber) {
final Integer id = getIdFromSerialNumber(serialNumber);
if (id == null) {
return null;
}
for (final SmartValveDTO smartValve : domain.getSmartValve()) {
if (smartValve.getId().equals(id)) {
return smartValve;
}
}
return null;
}
private @Nullable Integer getIdFromSerialNumber(final String serialNumber) {
for (final DeviceDTO device : domain.getDevice()) {
if (device.getSerialNumber() != null
&& device.getSerialNumber().toLowerCase().equals(serialNumber.toLowerCase())) {
return device.getId();
}
}
return null;
}
}

View File

@@ -0,0 +1,64 @@
/**
* 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.draytonwiser.internal.model;
import java.util.List;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class HeatingChannelDTO {
@SerializedName("id")
private Integer id;
private String name;
private List<Integer> roomIds;
private Integer percentageDemand;
private String demandOnOffOutput;
private String heatingRelayState;
private Boolean isSmartValvePreventingDemand;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public List<Integer> getRoomIds() {
return roomIds;
}
public void setRoomIds(final List<Integer> roomIds) {
this.roomIds = roomIds;
}
public Integer getPercentageDemand() {
return percentageDemand;
}
public String getDemandOnOffOutput() {
return demandOnOffOutput;
}
public String getHeatingRelayState() {
return heatingRelayState;
}
public Boolean getIsSmartValvePreventingDemand() {
return isSmartValvePreventingDemand;
}
}

View File

@@ -0,0 +1,53 @@
/**
* 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.draytonwiser.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class HotWaterDTO {
@SerializedName("id")
private Integer id;
private String overrideType;
private String mode;
private String waterHeatingState;
private String hotWaterRelayState;
private Integer overrideTimeoutUnixTime;
public Integer getId() {
return id;
}
public String getOverrideType() {
return overrideType;
}
public String getMode() {
return mode;
}
public String getWaterHeatingState() {
return waterHeatingState;
}
public String getHotWaterRelayState() {
return hotWaterRelayState;
}
public Integer getOverrideTimeoutUnixTime() {
return overrideTimeoutUnixTime;
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class LocalDateAndTimeDTO {
private Integer year;
private String month;
private Integer date;
private String day;
private Integer time;
public Integer getYear() {
return year;
}
public String getMonth() {
return month;
}
public Integer getDate() {
return date;
}
public String getDay() {
return day;
}
public Integer getTime() {
return time;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class NetworkInterfaceDTO {
private String interfaceName;
private String hostName;
private String dhcpMode;
private String iPv4HostAddress;
private String iPv4SubnetMask;
private String iPv4DefaultGateway;
private String iPv4PrimaryDNS;
private String iPv4SecondaryDNS;
public String getInterfaceName() {
return interfaceName;
}
public String getHostName() {
return hostName;
}
public String getDhcpMode() {
return dhcpMode;
}
public String getIPv4HostAddress() {
return iPv4HostAddress;
}
public String getIPv4SubnetMask() {
return iPv4SubnetMask;
}
public String getIPv4DefaultGateway() {
return iPv4DefaultGateway;
}
public String getIPv4PrimaryDNS() {
return iPv4PrimaryDNS;
}
public String getIPv4SecondaryDNS() {
return iPv4SecondaryDNS;
}
}

View File

@@ -0,0 +1,30 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class ReceptionDTO {
private Integer rssi;
private Integer lqi;
public Integer getRSSI() {
return rssi;
}
public Integer getLQI() {
return lqi;
}
}

View File

@@ -0,0 +1,141 @@
/**
* 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.draytonwiser.internal.model;
import java.util.List;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class RoomDTO {
@SerializedName("id")
private Integer id;
private Integer overrideSetpoint;
private Integer roomStatId;
private List<Integer> smartValveIds;
private String name;
private String mode;
private String demandType;
private int calculatedTemperature;
private int currentSetPoint;
private Integer percentageDemand;
private String controlOutputState;
private String windowState;
private Integer displayedSetPoint;
private String overrideType;
private Boolean windowDetectionActive;
private Integer overrideTimeoutUnixTime;
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public Integer getOverrideTimeoutUnixTime() {
return overrideTimeoutUnixTime;
}
public Integer getOverrideSetpoint() {
return overrideSetpoint;
}
public void setOverrideSetpoint(final Integer overrideSetpoint) {
this.overrideSetpoint = overrideSetpoint;
}
public Integer getRoomStatId() {
return roomStatId;
}
public void setRoomStatId(final Integer roomStatId) {
this.roomStatId = roomStatId;
}
public List<Integer> getSmartValveIds() {
return smartValveIds;
}
public void setSmartValveIds(final List<Integer> smartValveIds) {
this.smartValveIds = smartValveIds;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public String getMode() {
return mode;
}
public void setMode(final String mode) {
this.mode = mode;
}
public String getDemandType() {
return demandType;
}
public void setDemandType(final String demandType) {
this.demandType = demandType;
}
public int getCalculatedTemperature() {
return calculatedTemperature;
}
public int getCurrentSetPoint() {
return currentSetPoint < 0 ? 0 : currentSetPoint;
}
public void setCurrentSetPoint(final Integer currentSetPoint) {
this.currentSetPoint = currentSetPoint;
}
public Integer getPercentageDemand() {
return percentageDemand;
}
public String getControlOutputState() {
return controlOutputState;
}
public String getWindowState() {
return windowState;
}
public Integer getDisplayedSetPoint() {
return displayedSetPoint;
}
public void setDisplayedSetPoint(final Integer displayedSetPoint) {
this.displayedSetPoint = displayedSetPoint;
}
public String getOverrideType() {
return overrideType;
}
public Boolean getWindowDetectionActive() {
return windowDetectionActive;
}
}

View File

@@ -0,0 +1,47 @@
/**
* 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.draytonwiser.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class RoomStatDTO {
@SerializedName("id")
private Integer id;
private int setPoint;
private Integer measuredTemperature;
private Integer measuredHumidity;
public Integer getId() {
return id;
}
public int getSetPoint() {
return Math.max(0, setPoint);
}
public void setSetPoint(final Integer setPoint) {
this.setPoint = setPoint;
}
public Integer getMeasuredTemperature() {
return measuredTemperature;
}
public Integer getMeasuredHumidity() {
return measuredHumidity;
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class RssiDTO {
private Integer current;
private Integer min;
private Integer max;
public Integer getCurrent() {
return current;
}
public Integer getMin() {
return min;
}
public Integer getMax() {
return max;
}
}

View File

@@ -0,0 +1,30 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class SetPointDTO {
private Integer time;
private Integer degreesC;
public Integer getTime() {
return time;
}
public Integer getDegreesC() {
return degreesC;
}
}

View File

@@ -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.draytonwiser.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class SmartPlugDTO {
@SerializedName("id")
private Integer id;
private String name;
private String manualState;
private String mode;
private String awayAction;
private String outputState;
private String controlSource;
private String scheduledState;
private String targetState;
private Integer debounceCount;
private String overrideState;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getManualState() {
return manualState;
}
public String getAwayAction() {
return awayAction;
}
public String getOutputState() {
return outputState;
}
public String getControlSource() {
return controlSource;
}
public String getScheduledState() {
return scheduledState;
}
public String getTargetState() {
return targetState;
}
public Integer getDebounceCount() {
return debounceCount;
}
public String getOverrideState() {
return overrideState;
}
public String getMode() {
return mode;
}
}

View File

@@ -0,0 +1,62 @@
/**
* 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.draytonwiser.internal.model;
import com.google.gson.annotations.SerializedName;
/**
* @author Andrew Schofield - Initial contribution
*/
public class SmartValveDTO {
@SerializedName("id")
private Integer id;
private int setPoint;
private int measuredTemperature;
private Integer percentageDemand;
private String windowState;
private Integer externalRoomStatTemperature;
private String mountingOrientation;
public Integer getId() {
return id;
}
public int getSetPoint() {
return Math.max(0, setPoint);
}
public void setSetPoint(final Integer setPoint) {
this.setPoint = setPoint;
}
public int getMeasuredTemperature() {
return measuredTemperature;
}
public Integer getPercentageDemand() {
return percentageDemand;
}
public String getWindowState() {
return windowState;
}
public Integer getExternalRoomStatTemperature() {
return externalRoomStatTemperature;
}
public String getMountingOrientation() {
return mountingOrientation;
}
}

View File

@@ -0,0 +1,157 @@
/**
* 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.draytonwiser.internal.model;
import java.util.List;
/**
* @author Andrew Schofield - Initial contribution
*/
public class StationDTO {
private Boolean enabled;
private String sSID;
private String securityMode;
private Long scanSlotTime;
private Integer scanSlots;
private NetworkInterfaceDTO networkInterface;
private String connectionStatus;
private DhcpStatusDTO dhcpStatus;
private Boolean scanning;
private List<DetectedAccessPointDTO> detectedAccessPoints;
private Integer connectionFailures;
private String mdnsHostname;
private String macAddress;
private RssiDTO rSSI;
private Integer channel;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(final Boolean enabled) {
this.enabled = enabled;
}
public String getSSID() {
return sSID;
}
public void setSSID(final String sSID) {
this.sSID = sSID;
}
public String getSecurityMode() {
return securityMode;
}
public void setSecurityMode(final String securityMode) {
this.securityMode = securityMode;
}
public Long getScanSlotTime() {
return scanSlotTime;
}
public void setScanSlotTime(final Long scanSlotTime) {
this.scanSlotTime = scanSlotTime;
}
public Integer getScanSlots() {
return scanSlots;
}
public void setScanSlots(final Integer scanSlots) {
this.scanSlots = scanSlots;
}
public NetworkInterfaceDTO getNetworkInterface() {
return networkInterface;
}
public void setNetworkInterface(final NetworkInterfaceDTO networkInterface) {
this.networkInterface = networkInterface;
}
public String getConnectionStatus() {
return connectionStatus;
}
public void setConnectionStatus(final String connectionStatus) {
this.connectionStatus = connectionStatus;
}
public DhcpStatusDTO getDhcpStatus() {
return dhcpStatus;
}
public void setDhcpStatus(final DhcpStatusDTO dhcpStatus) {
this.dhcpStatus = dhcpStatus;
}
public Boolean getScanning() {
return scanning;
}
public void setScanning(final Boolean scanning) {
this.scanning = scanning;
}
public List<DetectedAccessPointDTO> getDetectedAccessPoints() {
return detectedAccessPoints;
}
public void setDetectedAccessPoints(final List<DetectedAccessPointDTO> detectedAccessPoints) {
this.detectedAccessPoints = detectedAccessPoints;
}
public Integer getConnectionFailures() {
return connectionFailures;
}
public void setConnectionFailures(final Integer connectionFailures) {
this.connectionFailures = connectionFailures;
}
public String getMdnsHostname() {
return mdnsHostname;
}
public void setMdnsHostname(final String mdnsHostname) {
this.mdnsHostname = mdnsHostname;
}
public String getMacAddress() {
return macAddress;
}
public void setMacAddress(final String macAddress) {
this.macAddress = macAddress;
}
public RssiDTO getRSSI() {
return rSSI;
}
public void setRSSI(final RssiDTO rSSI) {
this.rSSI = rSSI;
}
public Integer getChannel() {
return channel;
}
public void setChannel(final Integer channel) {
this.channel = channel;
}
}

View File

@@ -0,0 +1,165 @@
/**
* 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.draytonwiser.internal.model;
/**
* @author Andrew Schofield - Initial contribution
*/
public class SystemDTO {
private String pairingStatus;
private String overrideType;
private Integer overrideSetpoint;
private Integer timeZoneOffset;
private Boolean automaticDaylightSaving;
private Integer version;
private Boolean fotaEnabled;
private Boolean valveProtectionEnabled;
private Boolean ecoModeEnabled;
private BoilerSettingsDTO boilerSettings;
private Long unixTime;
private String cloudConnectionStatus;
private String zigbeeModuleVersion;
private String zigbeeEui;
private LocalDateAndTimeDTO localDateAndTime;
private String heatingButtonOverrideState;
private String hotWaterButtonOverrideState;
public String getPairingStatus() {
return pairingStatus;
}
public void setPairingStatus(final String pairingStatus) {
this.pairingStatus = pairingStatus;
}
public String getOverrideType() {
return overrideType;
}
public Integer getOverrideSetpoint() {
return overrideSetpoint;
}
public Integer getTimeZoneOffset() {
return timeZoneOffset;
}
public void setTimeZoneOffset(final Integer timeZoneOffset) {
this.timeZoneOffset = timeZoneOffset;
}
public Boolean getAutomaticDaylightSaving() {
return automaticDaylightSaving;
}
public void setAutomaticDaylightSaving(final Boolean automaticDaylightSaving) {
this.automaticDaylightSaving = automaticDaylightSaving;
}
public Integer getVersion() {
return version;
}
public void setVersion(final Integer version) {
this.version = version;
}
public Boolean getFotaEnabled() {
return fotaEnabled;
}
public void setFotaEnabled(final Boolean fotaEnabled) {
this.fotaEnabled = fotaEnabled;
}
public Boolean getValveProtectionEnabled() {
return valveProtectionEnabled;
}
public void setValveProtectionEnabled(final Boolean valveProtectionEnabled) {
this.valveProtectionEnabled = valveProtectionEnabled;
}
public Boolean getEcoModeEnabled() {
return ecoModeEnabled;
}
public void setEcoModeEnabled(final Boolean ecoModeEnabled) {
this.ecoModeEnabled = ecoModeEnabled;
}
public BoilerSettingsDTO getBoilerSettings() {
return boilerSettings;
}
public void setBoilerSettings(final BoilerSettingsDTO boilerSettings) {
this.boilerSettings = boilerSettings;
}
public Long getUnixTime() {
return unixTime;
}
public void setUnixTime(final Long unixTime) {
this.unixTime = unixTime;
}
public String getCloudConnectionStatus() {
return cloudConnectionStatus;
}
public void setCloudConnectionStatus(final String cloudConnectionStatus) {
this.cloudConnectionStatus = cloudConnectionStatus;
}
public String getZigbeeModuleVersion() {
return zigbeeModuleVersion;
}
public void setZigbeeModuleVersion(final String zigbeeModuleVersion) {
this.zigbeeModuleVersion = zigbeeModuleVersion;
}
public String getZigbeeEui() {
return zigbeeEui;
}
public void setZigbeeEui(final String zigbeeEui) {
this.zigbeeEui = zigbeeEui;
}
public LocalDateAndTimeDTO getLocalDateAndTime() {
return localDateAndTime;
}
public void setLocalDateAndTime(final LocalDateAndTimeDTO localDateAndTime) {
this.localDateAndTime = localDateAndTime;
}
public String getHeatingButtonOverrideState() {
return heatingButtonOverrideState;
}
public void setHeatingButtonOverrideState(final String heatingButtonOverrideState) {
this.heatingButtonOverrideState = heatingButtonOverrideState;
}
public String getHotWaterButtonOverrideState() {
return hotWaterButtonOverrideState;
}
public void setHotWaterButtonOverrideState(final String hotWaterButtonOverrideState) {
this.hotWaterButtonOverrideState = hotWaterButtonOverrideState;
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="draytonwiser" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>DraytonWiser Binding</name>
<description>This is the binding for Drayton Wiser smart heating system.</description>
<author>Andrew Schofield</author>
</binding:binding>

View File

@@ -0,0 +1,425 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="draytonwiser"
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">
<!-- Bridge Thing Type -->
<bridge-type id="heathub">
<label>HeatHub</label>
<description>A Drayton Wiser HeatHub acting as a bridge to Thermostats and TRVs</description>
<representation-property>networkAddress</representation-property>
<config-description>
<parameter name="networkAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the HeatHub</description>
</parameter>
<parameter name="secret" type="text" required="true">
<label>Authorisation Token</label>
<description>Auth token required to access the API</description>
</parameter>
<parameter name="refresh" type="integer" unit="s">
<label>Refresh Interval</label>
<description>Interval in seconds between automatic refreshes</description>
<default>10</default>
</parameter>
<parameter name="awaySetPoint" type="integer">
<label>Away Mode Set Point</label>
<description>Set point temperature for away mode in degrees celsius</description>
<default>16</default>
</parameter>
</config-description>
</bridge-type>
<!-- Controller Thing Type -->
<thing-type id="boiler-controller">
<supported-bridge-type-refs>
<bridge-type-ref id="heathub"/>
</supported-bridge-type-refs>
<label>Boiler Controller</label>
<description>The controller attached to the boiler</description>
<channels>
<channel id="heatingOverride" typeId="heatingOverride-channel"/>
<channel id="heatChannel1Demand" typeId="heatChannelDemand-channel">
<label>Channel 1 Heat Demand</label>
</channel>
<channel id="heatChannel1DemandState" typeId="demandState-channel">
<label>Channel 1 Requesting Heat</label>
</channel>
<channel id="heatChannel2Demand" typeId="heatChannelDemand-channel">
<label>Channel 2 Heat Demand</label>
</channel>
<channel id="heatChannel2DemandState" typeId="demandState-channel">
<label>Channel 2 Requesting Heat</label>
</channel>
<channel id="awayModeState" typeId="awayModeState-channel"/>
<channel id="ecoModeState" typeId="ecoModeState-channel"/>
<channel id="currentSignalRSSI" typeId="signalRSSI-channel"/>
<channel id="currentSignalStrength" typeId="system.signal-strength"/>
<channel id="currentWiserSignalStrength" typeId="wiserSignalStrength-channel"/>
</channels>
<representation-property>id</representation-property>
</thing-type>
<!-- Hot Water Thing Type -->
<thing-type id="hotwater">
<supported-bridge-type-refs>
<bridge-type-ref id="heathub"/>
</supported-bridge-type-refs>
<label>Hot Water</label>
<description>The hot water heating system</description>
<channels>
<channel id="hotWaterOverride" typeId="hotWaterOverride-channel"/>
<channel id="hotWaterDemandState" typeId="demandState-channel">
<label>Hot Water Requesting Heat</label>
<description>Hot Water is requesting heat</description>
</channel>
<channel id="manualModeState" typeId="manualModeState-channel"/>
<channel id="hotWaterSetPoint" typeId="hotWaterSetPoint-channel"/>
<channel id="hotWaterBoostDuration" typeId="boostDuration-channel">
<description>Duration to boost hot water for</description>
</channel>
<channel id="hotWaterBoosted" typeId="boosted-channel">
<description>Is the hot water currently being boosted</description>
</channel>
<channel id="hotWaterBoostRemaining" typeId="boostRemaining-channel"/>
</channels>
<representation-property>id</representation-property>
</thing-type>
<!-- Room Thing Type -->
<thing-type id="room">
<supported-bridge-type-refs>
<bridge-type-ref id="heathub"/>
</supported-bridge-type-refs>
<label>Room</label>
<description>A Room that contains a thermostat and/or TRV</description>
<channels>
<channel id="currentTemperature" typeId="currentTemperature-channel"/>
<channel id="currentHumidity" typeId="atmospheric-humidity-channel"/>
<channel id="currentSetPoint" typeId="currentSetPoint-channel"/>
<channel id="currentDemand" typeId="demandPercent-channel"/>
<channel id="heatRequest" typeId="heatRequest-channel"/>
<channel id="manualModeState" typeId="manualModeState-channel"/>
<channel id="roomBoostDuration" typeId="boostDuration-channel">
<description>Duration to boost the temperature for</description>
</channel>
<channel id="roomBoosted" typeId="boosted-channel">
<description>Is the room temperature currently being boosted</description>
</channel>
<channel id="roomBoostRemaining" typeId="boostRemaining-channel"/>
<channel id="windowStateDetection" typeId="windowStateDetection-channel"/>
<channel id="windowState" typeId="windowState-channel"/>
</channels>
<representation-property>name</representation-property>
<config-description>
<parameter name="name" type="text" required="true">
<label>Room Name</label>
<description>The room name as it appears in the Wiser app</description>
</parameter>
</config-description>
</thing-type>
<!-- Room Thermostat Thing Type -->
<thing-type id="roomstat">
<supported-bridge-type-refs>
<bridge-type-ref id="heathub"/>
</supported-bridge-type-refs>
<label>Thermostat</label>
<description>Wireless Thermostat device</description>
<channels>
<channel id="currentTemperature" typeId="currentTemperature-channel"/>
<channel id="currentHumidity" typeId="atmospheric-humidity-channel"/>
<channel id="currentSetPoint" typeId="currentSetPoint-channel"/>
<channel id="currentBatteryVoltage" typeId="batteryVoltage-channel"/>
<channel id="currentBatteryLevel" typeId="system.battery-level"/>
<channel id="currentWiserBatteryLevel" typeId="wiserBatteryLevel-channel"/>
<channel id="currentSignalRSSI" typeId="signalRSSI-channel"/>
<channel id="currentSignalLQI" typeId="signalLQI-channel"/>
<channel id="currentSignalStrength" typeId="system.signal-strength"/>
<channel id="currentWiserSignalStrength" typeId="wiserSignalStrength-channel"/>
<channel id="zigbeeConnected" typeId="zigbeeConnected-channel"/>
<channel id="deviceLocked" typeId="deviceLocked-channel"/>
</channels>
<representation-property>serialNumber</representation-property>
<config-description>
<parameter name="serialNumber" type="text" required="true">
<label>Serial Number</label>
<description>Device Serial Number</description>
</parameter>
</config-description>
</thing-type>
<!-- TRV Thing Type -->
<thing-type id="itrv">
<supported-bridge-type-refs>
<bridge-type-ref id="heathub"/>
</supported-bridge-type-refs>
<label>iTRV</label>
<description>Thermostatic Radiator Valve</description>
<channels>
<channel id="currentTemperature" typeId="currentTemperature-channel"/>
<channel id="currentSetPoint" typeId="currentSetPoint-channel"/>
<channel id="currentDemand" typeId="demandPercent-channel"/>
<channel id="currentBatteryVoltage" typeId="batteryVoltage-channel"/>
<channel id="currentBatteryLevel" typeId="system.battery-level"/>
<channel id="currentWiserBatteryLevel" typeId="wiserBatteryLevel-channel"/>
<channel id="currentSignalRSSI" typeId="signalRSSI-channel"/>
<channel id="currentSignalLQI" typeId="signalLQI-channel"/>
<channel id="currentSignalStrength" typeId="system.signal-strength"/>
<channel id="currentWiserSignalStrength" typeId="wiserSignalStrength-channel"/>
<channel id="zigbeeConnected" typeId="zigbeeConnected-channel"/>
<channel id="deviceLocked" typeId="deviceLocked-channel"/>
</channels>
<representation-property>serialNumber</representation-property>
<config-description>
<parameter name="serialNumber" type="text" required="true">
<label>Serial Number</label>
<description>Device Serial Number</description>
</parameter>
</config-description>
</thing-type>
<!-- Smart Plug Thing Type -->
<thing-type id="smart-plug">
<supported-bridge-type-refs>
<bridge-type-ref id="heathub"/>
</supported-bridge-type-refs>
<label>Smart Plug</label>
<description>Remote controlled Plug Socket</description>
<channels>
<channel id="plugOutputState" typeId="plugOutputState-channel"/>
<channel id="plugAwayAction" typeId="plugAwayAction-channel"/>
<channel id="currentSignalRSSI" typeId="signalRSSI-channel"/>
<channel id="currentSignalLQI" typeId="signalLQI-channel"/>
<channel id="zigbeeConnected" typeId="zigbeeConnected-channel"/>
<channel id="deviceLocked" typeId="deviceLocked-channel"/>
<channel id="manualModeState" typeId="manualModeState-channel"/>
</channels>
<representation-property>serialNumber</representation-property>
<config-description>
<parameter name="serialNumber" type="text" required="true">
<label>Serial Number</label>
<description>Device Serial Number</description>
</parameter>
</config-description>
</thing-type>
<!-- Channel Types -->
<channel-type id="currentTemperature-channel">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Current temperature</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="atmospheric-humidity-channel">
<item-type>Number:Dimensionless</item-type>
<label>Humidity</label>
<description>Current relative humidity</description>
<category>Humidity</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="currentSetPoint-channel">
<item-type>Number:Temperature</item-type>
<label>Set Point</label>
<description>Current set point</description>
<category>Temperature</category>
<state readOnly="false" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="batteryVoltage-channel" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Battery Voltage</label>
<description>Current Battery Voltage for the device</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="demandPercent-channel">
<item-type>Number:Dimensionless</item-type>
<label>Current Heat Demand</label>
<description>Current heat demand in %</description>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="heatRequest-channel">
<item-type>Switch</item-type>
<label>Currently Requesting Heat</label>
<description>Is this room requesting heat</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="heatingOverride-channel">
<item-type>Switch</item-type>
<label>Heating Override</label>
<description>The heating override button has been pressed</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="hotWaterOverride-channel">
<item-type>Switch</item-type>
<label>Hot Water Override</label>
<description>The hot water override button has been pressed</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="signalRSSI-channel" advanced="true">
<item-type>Number</item-type>
<label>Signal RSSI</label>
<description>The reported network signal RSSI</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="signalLQI-channel" advanced="true">
<item-type>Number</item-type>
<label>Signal LQI</label>
<description>The reported network signal LQI</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="wiserSignalStrength-channel" advanced="true">
<item-type>String</item-type>
<label>Signal Strength (Wiser)</label>
<description>The reported network signal strength</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="wiserBatteryLevel-channel" advanced="true">
<item-type>String</item-type>
<label>Battery Level (Wiser)</label>
<description>Current Battery Level for the device</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="heatChannelDemand-channel">
<item-type>Number:Dimensionless</item-type>
<label>Heat Demand</label>
<description>Current heat demand in %</description>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="demandState-channel">
<item-type>Switch</item-type>
<label>Requesting Heat</label>
<description>Current channel is requesting heat</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="awayModeState-channel">
<item-type>Switch</item-type>
<label>Away Mode Active</label>
<description>Away mode has been activated</description>
</channel-type>
<channel-type id="awayModeSetPoint-channel" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Away Mode Set Point</label>
<description>Away Mode Set Point</description>
<category>Temperature</category>
<state readOnly="false" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="ecoModeState-channel">
<item-type>Switch</item-type>
<label>Eco Mode Enabled</label>
<description>Eco Mode activation state (EcoIQ)</description>
</channel-type>
<channel-type id="manualModeState-channel">
<item-type>Switch</item-type>
<label>Manual Mode Enabled</label>
<description>Manual Mode activation state</description>
</channel-type>
<channel-type id="zigbeeConnected-channel" advanced="true">
<item-type>Switch</item-type>
<label>Device Connected</label>
<description>Is the device still connected to the ZigBee network</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="hotWaterSetPoint-channel">
<item-type>Switch</item-type>
<label>Set Point</label>
<description>Hot water heating set point switch</description>
</channel-type>
<channel-type id="boostDuration-channel">
<item-type>Number</item-type>
<label>Boost Duration</label>
<description>Duration in hours to boost hot water for</description>
<state pattern="%.1f h" min="0" max="3" step="0.5"/>
</channel-type>
<channel-type id="boosted-channel">
<item-type>Switch</item-type>
<label>Is Boosted</label>
<description>Is the hot water currently being boosted</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="boostRemaining-channel">
<item-type>Number:Time</item-type>
<label>Boost Remaining</label>
<description>How long until the boost deactivates</description>
<state readOnly="true" pattern="%.0f min"/>
</channel-type>
<channel-type id="windowStateDetection-channel" advanced="true">
<item-type>Switch</item-type>
<label>Open Window Detection</label>
<description>Is window detection turned on</description>
</channel-type>
<channel-type id="windowState-channel">
<item-type>Contact</item-type>
<label>Window State</label>
<description>Is the window open or closed</description>
</channel-type>
<channel-type id="deviceLocked-channel" advanced="true">
<item-type>Switch</item-type>
<label>Device Locked</label>
<description>Has the device been locked to prevent local changes</description>
</channel-type>
<channel-type id="plugOutputState-channel">
<item-type>Switch</item-type>
<label>Plug State</label>
<description>Is the smart plug switched on or off</description>
</channel-type>
<channel-type id="plugAwayAction-channel">
<item-type>Switch</item-type>
<label>Plug Off in Away Mode</label>
<description>Should the smart plug switch off when in away mode</description>
</channel-type>
</thing:thing-descriptions>