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,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.digitalstrom-${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-digitalstrom" description="digitalSTROM Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-mdns</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.digitalstrom/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,109 @@
/**
* 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.digitalstrom.internal;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneTypes;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link DigitalSTROMBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Michael Ochel - Initial contribution
* @author Mathias Siegele - Initial contribution
*/
public class DigitalSTROMBindingConstants {
public static final String BINDING_ID = "digitalstrom";
// List of all Thing Type IDs
public static final String THING_TYPE_ID_DSS_BRIDGE = "dssBridge";
public static final String THING_TYPE_ID_ZONE_TEMERATURE_CONTROL = "zoneTemperatureControl";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_DSS_BRIDGE = new ThingTypeUID(BINDING_ID, THING_TYPE_ID_DSS_BRIDGE);
public static final ThingTypeUID THING_TYPE_ZONE_TEMERATURE_CONTROL = new ThingTypeUID(BINDING_ID,
THING_TYPE_ID_ZONE_TEMERATURE_CONTROL);
public static final ThingTypeUID THING_TYPE_APP_SCENE = new ThingTypeUID(BINDING_ID, SceneTypes.APARTMENT_SCENE);
public static final ThingTypeUID THING_TYPE_ZONE_SCENE = new ThingTypeUID(BINDING_ID, SceneTypes.ZONE_SCENE);
public static final ThingTypeUID THING_TYPE_GROUP_SCENE = new ThingTypeUID(BINDING_ID, SceneTypes.GROUP_SCENE);
public static final ThingTypeUID THING_TYPE_NAMED_SCENE = new ThingTypeUID(BINDING_ID, SceneTypes.NAMED_SCENE);
// scene
public static final String CHANNEL_ID_SCENE = "scene";
// sensor
public static final String CHANNEL_ID_TOTAL_ACTIVE_POWER = "totalActivePower";
public static final String CHANNEL_ID_TOTAL_ELECTRIC_METER = "totalElectricMeter";
// options combined switches
public static final String OPTION_COMBINED_BOTH_OFF = "0";
public static final String OPTION_COMBINED_BOTH_ON = "200";
public static final String OPTION_COMBINED_FIRST_ON = "90";
public static final String OPTION_COMBINED_SECOND_ON = "130";
/* config URIs */
public static final String DEVICE_CONFIG = "binding:digitalstrom:device";
public static final String GRAY_DEVICE_CONFIG = "binding:digitalstrom:grayDevice";
public static final String DSS_BRIDE_CONFIG = "binding:digitalstrom:dssBridge";
/* Bridge config properties */
public static final String HOST = "dSSAddress";
public static final String USER_NAME = "userName";
public static final String PASSWORD = "password";
public static final String APPLICATION_TOKEN = "applicationToken";
public static final String DS_ID = "dSID";
public static final String DS_NAME = "dS-Installation-Name";
public static final String SENSOR_DATA_UPDATE_INTERVAL = "sensorDataUpdateInterval";
public static final String TOTAL_POWER_UPDATE_INTERVAL = "totalPowerUpdateInterval";
public static final String DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY = "defaultTrashBinDeleteTime";
public static final String SENSOR_WAIT_TIME = "sensorWaitTime";
public static final String SERVER_CERT = "serverCert";
/* Device info properties */
public static final String DEVICE_UID = "dSUID";
public static final String DEVICE_NAME = "deviceName";
public static final String DEVICE_DSID = "dSID";
public static final String DEVICE_HW_INFO = "hwInfo";
public static final String DEVICE_ZONE_ID = "zoneID";
public static final String DEVICE_GROUPS = "groups";
public static final String DEVICE_OUTPUT_MODE = "outputmode";
public static final String DEVICE_FUNCTIONAL_COLOR_GROUP = "funcColorGroup";
public static final String DEVICE_METER_ID = "meterDSID";
public static final String DEVICE_BINARAY_INPUTS = "binarayInputs";
// Device properties scene
public static final String DEVICE_SCENE = "scene"; // + number of scene
// Sensor data channel properties
public static final String ACTIVE_POWER_REFRESH_PRIORITY = "activePowerRefreshPriority";
public static final String ELECTRIC_METER_REFRESH_PRIORITY = "electricMeterRefreshPriority";
public static final String OUTPUT_CURRENT_REFRESH_PRIORITY = "outputCurrentRefreshPriority";
/* Scene config */
public static final String ZONE_ID = "zoneID";
public static final String GROUP_ID = "groupID";
public static final String SCENE_ID = "sceneID";
// circuit properties
public static final String HW_NAME = "hwName";
public static final String HW_VERSION = "hwVersion";
public static final String SW_VERSION = "swVersion";
public static final String API_VERSION = "apiVersion";
public static final String DSP_SW_VERSION = "armSwVersion";
public static final String ARM_SW_VERSION = "dspSwVersion";
}

View File

@@ -0,0 +1,265 @@
/**
* 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.digitalstrom.internal;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.discovery.DiscoveryServiceManager;
import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
import org.openhab.binding.digitalstrom.internal.handler.CircuitHandler;
import org.openhab.binding.digitalstrom.internal.handler.DeviceHandler;
import org.openhab.binding.digitalstrom.internal.handler.SceneHandler;
import org.openhab.binding.digitalstrom.internal.handler.ZoneTemperatureControlHandler;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.ConnectionManagerImpl;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
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.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DigitalSTROMHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Michael Ochel - Initial contribution
* @author Mathias Siegele - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.digitalstrom")
public class DigitalSTROMHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(DigitalSTROMHandlerFactory.class);
private final Map<String, DiscoveryServiceManager> discoveryServiceManagers = new HashMap<>();
private Map<ThingUID, BridgeHandler> bridgeHandlers;
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return BridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|| SceneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|| DeviceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|| ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|| CircuitHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID);
}
@Override
public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, ThingUID thingUID,
ThingUID bridgeUID) {
if (BridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
ThingUID dSSUID = getBridgeThingUID(thingTypeUID, thingUID, configuration);
if (dSSUID != null) {
return super.createThing(thingTypeUID, configuration, dSSUID, null);
} else {
logger.error("Can't generate thing UID for thing type {}"
+ ", because digitalSTROM-Server is not reachable. Please check these points:\n"
+ "Are the server address and portnumber correct?\n" + "Is the server turned on?\n"
+ "Is the network configured correctly?", thingTypeUID);
return null;
}
}
if (DeviceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
ThingUID dsDeviceUID = getDeviceUID(thingTypeUID, thingUID, configuration, bridgeUID);
return super.createThing(thingTypeUID, configuration, dsDeviceUID, bridgeUID);
}
if (CircuitHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
ThingUID dsDeviceUID = getDeviceUID(thingTypeUID, thingUID, configuration, bridgeUID);
return super.createThing(thingTypeUID, configuration, dsDeviceUID, bridgeUID);
}
if (ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
ThingUID zoneTempConUID = getZoneTemperatureControlUID(thingTypeUID, thingUID, configuration, bridgeUID);
return super.createThing(thingTypeUID, configuration, zoneTempConUID, bridgeUID);
}
if (SceneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
ThingUID dsSceneUID = getSceneUID(thingTypeUID, thingUID, configuration, bridgeUID);
return super.createThing(thingTypeUID, configuration, dsSceneUID, bridgeUID);
}
throw new IllegalArgumentException(
"The thing type " + thingTypeUID + " is not supported by the digitalSTROM binding.");
}
@Override
protected ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (BridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
BridgeHandler handler = new BridgeHandler((Bridge) thing);
if (bridgeHandlers == null) {
bridgeHandlers = new HashMap<>();
}
bridgeHandlers.put(thing.getUID(), handler);
DiscoveryServiceManager discoveryServiceManager = new DiscoveryServiceManager(handler);
discoveryServiceManager.registerDiscoveryServices(bundleContext);
discoveryServiceManagers.put(handler.getThing().getUID().getAsString(), discoveryServiceManager);
return handler;
}
if (DeviceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new DeviceHandler(thing);
}
if (CircuitHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new CircuitHandler(thing);
}
if (ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new ZoneTemperatureControlHandler(thing);
}
if (SceneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
return new SceneHandler(thing);
}
return null;
}
private ThingUID getDeviceUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
if (thingUID == null && StringUtils.isNotBlank((String) configuration.get(DEVICE_DSID))) {
return new ThingUID(thingTypeUID, bridgeUID, configuration.get(DEVICE_DSID).toString());
}
return thingUID;
}
private ThingUID getZoneTemperatureControlUID(ThingTypeUID thingTypeUID, ThingUID thingUID,
Configuration configuration, ThingUID bridgeUID) {
if (thingUID == null) {
Integer zoneID = ZoneTemperatureControlHandler.getZoneID(configuration, bridgeHandlers.get(bridgeUID));
if (zoneID > ZoneTemperatureControlHandler.ZONE_ID_NOT_EXISTS) {
return new ThingUID(thingTypeUID, bridgeUID, zoneID.toString());
} else {
switch (zoneID) {
case ZoneTemperatureControlHandler.ZONE_ID_NOT_EXISTS:
logger.error("Configured zone '{}' does not exist, please check your configuration.",
configuration.get(DigitalSTROMBindingConstants.ZONE_ID));
break;
case ZoneTemperatureControlHandler.ZONE_ID_NOT_SET:
logger.error("ZoneID is missing at your configuration.");
break;
case ZoneTemperatureControlHandler.BRIDGE_IS_NULL:
logger.error("Bridge is missing, can not check the zoneID.");
break;
}
}
}
return thingUID;
}
private ThingUID getSceneUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
if (thingUID != null) {
return thingUID;
}
String sceneID = SceneHandler.getSceneID(configuration, bridgeHandlers.get(bridgeUID));
switch (sceneID) {
case SceneHandler.SCENE_WRONG:
logger.error(
"Configured scene '{}' does not exist or can not be used, please check your configuration.",
configuration.get(DigitalSTROMBindingConstants.SCENE_ID));
break;
case SceneHandler.ZONE_WRONG:
logger.error("Configured zone '{}' does not exist, please check your configuration.",
configuration.get(DigitalSTROMBindingConstants.ZONE_ID));
break;
case SceneHandler.GROUP_WRONG:
logger.error("Configured group '{}' does not exist, please check your configuration.",
configuration.get(DigitalSTROMBindingConstants.GROUP_ID));
break;
case SceneHandler.NO_STRUC_MAN:
logger.error("Waiting for building digitalSTROM model.");
break;
case SceneHandler.NO_SCENE:
logger.error("No Scene-ID is set!");
break;
case SceneHandler.NO_BRIDGE:
logger.error("No related bridge found!");
default:
return new ThingUID(thingTypeUID, bridgeUID, sceneID);
}
return thingUID;
}
private ThingUID getBridgeThingUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration) {
if (thingUID != null) {
return thingUID;
}
String dSID;
if (StringUtils.isBlank((String) configuration.get(DS_ID))) {
dSID = getDSSid(configuration);
if (dSID != null) {
configuration.put(DS_ID, dSID);
}
} else {
dSID = configuration.get(DS_ID).toString();
}
if (dSID != null) {
return new ThingUID(thingTypeUID, dSID);
} else {
return null;
}
}
private String getDSSid(Configuration configuration) {
String dSID = null;
if (StringUtils.isNotBlank((String) configuration.get(HOST))) {
String host = configuration.get(HOST).toString();
String applicationToken = null;
String user = null;
String pw = null;
if (StringUtils.isNotBlank((String) configuration.get(APPLICATION_TOKEN))) {
applicationToken = configuration.get(APPLICATION_TOKEN).toString();
}
if (checkUserPassword(configuration)) {
user = configuration.get(USER_NAME).toString();
pw = configuration.get(PASSWORD).toString();
}
ConnectionManager connMan = new ConnectionManagerImpl(host, user, pw, applicationToken, false, true);
Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
if (dsidMap != null) {
dSID = dsidMap.get(JSONApiResponseKeysEnum.DSID.getKey());
}
}
return dSID;
}
private boolean checkUserPassword(Configuration configuration) {
return StringUtils.isNotBlank((String) configuration.get(USER_NAME))
&& StringUtils.isNotBlank((String) configuration.get(PASSWORD));
}
@Override
protected synchronized void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof BridgeHandler) {
String uid = thingHandler.getThing().getUID().getAsString();
if (discoveryServiceManagers.get(uid) != null) {
discoveryServiceManagers.get(uid).unregisterDiscoveryServices(bundleContext);
discoveryServiceManagers.remove(uid);
}
}
}
}

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.digitalstrom.internal.discovery;
import java.net.HttpURLConnection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.impl.DsAPIImpl;
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.ThingUID;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BridgeDiscoveryService} is responsible for discovering digitalSTROM-Server, if the server is in the
* local network and is reachable through "dss.local." with default port number "8080". It uses the central
* {@link AbstractDiscoveryService}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.digitalstrom")
public class BridgeDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(BridgeDiscoveryService.class);
public static final String HOST_ADDRESS = "dss.local.";
private final Runnable resultCreater = new Runnable() {
@Override
public void run() {
createResult();
}
private void createResult() {
ThingUID uid = getThingUID();
if (uid != null) {
Map<String, Object> properties = new HashMap<>(2);
properties.put(DigitalSTROMBindingConstants.HOST, HOST_ADDRESS);
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
.withLabel("digitalSTROM-Server").build();
thingDiscovered(result);
}
}
private ThingUID getThingUID() {
DsAPI digitalSTROMClient = new DsAPIImpl(HOST_ADDRESS, Config.DEFAULT_CONNECTION_TIMEOUT,
Config.DEFAULT_READ_TIMEOUT, true);
String dSID = null;
switch (digitalSTROMClient.checkConnection("123")) {
case HttpURLConnection.HTTP_OK:
case HttpURLConnection.HTTP_UNAUTHORIZED:
case HttpURLConnection.HTTP_FORBIDDEN:
Map<String, String> dsidMap = digitalSTROMClient.getDSID(null);
if (dsidMap != null) {
dSID = dsidMap.get(JSONApiResponseKeysEnum.DSID.getKey());
}
if (StringUtils.isNotBlank(dSID)) {
return new ThingUID(DigitalSTROMBindingConstants.THING_TYPE_DSS_BRIDGE, dSID);
} else {
logger.error("Can't get server dSID to generate ThingUID. Please add the server manually.");
}
}
return null;
}
};
/**
* Creates a new {@link BridgeDiscoveryService}.
*/
public BridgeDiscoveryService() {
super(new HashSet<>(Arrays.asList(DigitalSTROMBindingConstants.THING_TYPE_DSS_BRIDGE)), 10, false);
}
@Activate
@Override
protected void activate(Map<String, Object> configProperties) {
super.activate(configProperties);
}
@Deactivate
@Override
protected void deactivate() {
super.deactivate();
}
@Modified
@Override
protected void modified(Map<String, Object> configProperties) {
super.modified(configProperties);
}
@Override
protected void startScan() {
scheduler.execute(resultCreater);
}
}

View File

@@ -0,0 +1,95 @@
/**
* 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.digitalstrom.internal.discovery;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.jmdns.ServiceInfo;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.impl.DsAPIImpl;
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 BridgeMDNSDiscoveryParticipant} is responsible for discovering digitalSTROM-Server. It uses the central
* {@link MDNSDiscoveryService}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
@Component(service = MDNSDiscoveryParticipant.class, immediate = true)
public class BridgeMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {
private final Logger logger = LoggerFactory.getLogger(BridgeMDNSDiscoveryParticipant.class);
@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return Collections.singleton(DigitalSTROMBindingConstants.THING_TYPE_DSS_BRIDGE);
}
@Override
public String getServiceType() {
return "_tcp.local.";
}
@Override
public DiscoveryResult createResult(ServiceInfo service) {
if (service.getApplication().contains("dssweb")) {
ThingUID uid = getThingUID(service);
if (uid != null) {
String hostAddress = service.getName() + "." + service.getDomain() + ".";
Map<String, Object> properties = new HashMap<>(2);
properties.put(DigitalSTROMBindingConstants.HOST, hostAddress);
return DiscoveryResultBuilder.create(uid).withProperties(properties)
.withRepresentationProperty(uid.getId()).withLabel("digitalSTROM-Server").build();
}
}
return null;
}
@Override
public ThingUID getThingUID(ServiceInfo service) {
if (service.getApplication().contains("dssweb")) {
String hostAddress = service.getName() + "." + service.getDomain() + ".";
DsAPI digitalSTROMClient = new DsAPIImpl(hostAddress, Config.DEFAULT_CONNECTION_TIMEOUT,
Config.DEFAULT_READ_TIMEOUT, true);
Map<String, String> dsidMap = digitalSTROMClient.getDSID(null);
String dSID = null;
if (dsidMap != null) {
dSID = dsidMap.get(JSONApiResponseKeysEnum.DSID.getKey());
}
if (StringUtils.isNotBlank(dSID)) {
return new ThingUID(DigitalSTROMBindingConstants.THING_TYPE_DSS_BRIDGE, dSID);
} else {
logger.error("Can't get server dSID to generate thing UID. Please add the server manually.");
}
}
return null;
}
}

View File

@@ -0,0 +1,212 @@
/**
* 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.digitalstrom.internal.discovery;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.BINDING_ID;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
import org.openhab.binding.digitalstrom.internal.providers.DsDeviceThingTypeProvider;
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.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DeviceDiscoveryService} discovers all digitalSTROM-Devices, of one supported device-color-type. The
* device-color-type has to be given to the {@link #DeviceDiscoveryService(BridgeHandler, ThingTypeUID)} as
* {@link ThingTypeUID}. The supported {@link ThingTypeUID} can be found at
* {@link DeviceHandler#SUPPORTED_THING_TYPES}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class DeviceDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(DeviceDiscoveryService.class);
private final BridgeHandler bridgeHandler;
private final String deviceType;
private final ThingUID bridgeUID;
public static final int TIMEOUT = 10;
/**
* Creates a new {@link DeviceDiscoveryService} for the given supported {@link ThingTypeUID}.
*
* @param bridgeHandler (must not be null)
* @param supportedThingType (must not be null)
* @throws IllegalArgumentException see {@link AbstractDiscoveryService#AbstractDiscoveryService(int)}
*/
public DeviceDiscoveryService(BridgeHandler bridgeHandler, ThingTypeUID supportedThingType)
throws IllegalArgumentException {
super(new HashSet<>(Arrays.asList(supportedThingType)), TIMEOUT, true);
this.deviceType = supportedThingType.getId();
this.bridgeHandler = bridgeHandler;
bridgeUID = bridgeHandler.getThing().getUID();
}
/**
* Deactivates the {@link DeviceDiscoveryService} and removes the {@link DiscoveryResult}s.
*/
@Override
public void deactivate() {
logger.debug("deactivate discovery service for device type {} thing types are: {}", deviceType,
super.getSupportedThingTypes().toString());
removeOlderResults(new Date().getTime());
}
@Override
protected void startScan() {
if (bridgeHandler != null) {
if (!DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString().equals(deviceType)) {
List<Device> devices = bridgeHandler.getDevices();
if (devices != null) {
for (Device device : devices) {
onDeviceAddedInternal(device);
}
}
} else {
List<Circuit> circuits = bridgeHandler.getCircuits();
if (circuits != null) {
for (Circuit circuit : circuits) {
onDeviceAddedInternal(circuit);
}
}
}
}
}
@Override
protected synchronized void stopScan() {
super.stopScan();
removeOlderResults(getTimestampOfLastScan());
}
private void onDeviceAddedInternal(GeneralDeviceInformation device) {
boolean isSupported = false;
if (device instanceof Device) {
Device tempDevice = (Device) device;
if ((tempDevice.isSensorDevice() && deviceType.equals(tempDevice.getHWinfo().replaceAll("-", "")))
|| (deviceType.equals(tempDevice.getHWinfo().substring(0, 2))
&& (tempDevice.isDeviceWithOutput() || tempDevice.isBinaryInputDevice())
&& tempDevice.isPresent())) {
isSupported = true;
}
} else if (device instanceof Circuit
&& DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString().equals(deviceType)) {
isSupported = true;
}
if (isSupported) {
ThingUID thingUID = getThingUID(device);
if (thingUID != null) {
Map<String, Object> properties = new HashMap<>(1);
properties.put(DigitalSTROMBindingConstants.DEVICE_DSID, device.getDSID().getValue());
String deviceName = null;
if (StringUtils.isNotBlank(device.getName())) {
deviceName = device.getName();
} else {
// if no name is set, the dSID will be used as name
deviceName = device.getDSID().getValue();
}
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withBridge(bridgeUID).withLabel(deviceName).build();
thingDiscovered(discoveryResult);
} else {
if (device instanceof Device) {
logger.debug("Discovered unsupported device hardware type '{}' with uid {}",
((Device) device).getHWinfo(), device.getDSUID());
}
}
} else {
if (device instanceof Device) {
logger.debug(
"Discovered device with disabled or no output mode. Device was not added to inbox. "
+ "Device information: hardware info: {}, dSUID: {}, device-name: {}, output value: {}",
((Device) device).getHWinfo(), device.getDSUID(), device.getName(),
((Device) device).getOutputMode());
}
}
}
private ThingUID getThingUID(GeneralDeviceInformation device) {
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
ThingTypeUID thingTypeUID = null;
if (device instanceof Device) {
Device tempDevice = (Device) device;
thingTypeUID = new ThingTypeUID(BINDING_ID, tempDevice.getHWinfo().substring(0, 2));
if (tempDevice.isSensorDevice() && deviceType.equals(tempDevice.getHWinfo().replaceAll("-", ""))) {
thingTypeUID = new ThingTypeUID(BINDING_ID, deviceType);
}
} else {
thingTypeUID = new ThingTypeUID(BINDING_ID,
DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString());
}
if (getSupportedThingTypes().contains(thingTypeUID)) {
String thingDeviceId = device.getDSID().toString();
ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, thingDeviceId);
return thingUID;
} else {
return null;
}
}
/**
* Removes the {@link Thing} of the given {@link Device}.
*
* @param device (must not be null)
*/
public void onDeviceRemoved(GeneralDeviceInformation device) {
ThingUID thingUID = getThingUID(device);
if (thingUID != null) {
thingRemoved(thingUID);
}
}
/**
* Creates a {@link DiscoveryResult} for the given {@link Device}, if the {@link Device} is supported and the
* {@link Device#getOutputMode()} is unequal {@link OutputModeEnum#DISABLED}.
*
* @param device (must not be null)
*/
public void onDeviceAdded(GeneralDeviceInformation device) {
if (super.isBackgroundDiscoveryEnabled()) {
onDeviceAddedInternal(device);
}
}
/**
* Returns the ID of this {@link DeviceDiscoveryService}.
*
* @return id of the service
*/
public String getID() {
return deviceType;
}
}

View File

@@ -0,0 +1,259 @@
/**
* 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.digitalstrom.internal.discovery;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
import org.openhab.binding.digitalstrom.internal.handler.CircuitHandler;
import org.openhab.binding.digitalstrom.internal.handler.DeviceHandler;
import org.openhab.binding.digitalstrom.internal.handler.SceneHandler;
import org.openhab.binding.digitalstrom.internal.handler.ZoneTemperatureControlHandler;
import org.openhab.binding.digitalstrom.internal.lib.climate.TemperatureControlSensorTransmitter;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
import org.openhab.binding.digitalstrom.internal.providers.DsDeviceThingTypeProvider;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.type.ThingType;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* The {@link DiscoveryServiceManager} manages the different scene and device discovery services and informs them about
* new added or removed scenes and devices.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class DiscoveryServiceManager
implements SceneStatusListener, DeviceStatusListener, TemperatureControlStatusListener {
private final Map<String, AbstractDiscoveryService> discoveryServices;
private final Map<String, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
private final String bridgeUID;
/**
* Creates a new {@link DiscoveryServiceManager} and generates automatically all {@link SceneDiscoveryService}s and
* {@link DeviceDiscoveryService}s for all supported {@link ThingType}s of the {@link DeviceHandler} and
* {@link SceneHandler}.
*
* @param bridgeHandler (must not be null)
*/
public DiscoveryServiceManager(BridgeHandler bridgeHandler) {
bridgeUID = bridgeHandler.getThing().getUID().getAsString();
discoveryServices = new HashMap<>(SceneHandler.SUPPORTED_THING_TYPES.size()
+ DeviceHandler.SUPPORTED_THING_TYPES.size() + CircuitHandler.SUPPORTED_THING_TYPES.size()
+ ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.size());
for (ThingTypeUID type : SceneHandler.SUPPORTED_THING_TYPES) {
discoveryServices.put(type.getId(), new SceneDiscoveryService(bridgeHandler, type));
}
for (ThingTypeUID type : DeviceHandler.SUPPORTED_THING_TYPES) {
discoveryServices.put(type.getId(), new DeviceDiscoveryService(bridgeHandler, type));
}
for (ThingTypeUID type : CircuitHandler.SUPPORTED_THING_TYPES) {
discoveryServices.put(type.getId(), new DeviceDiscoveryService(bridgeHandler, type));
}
for (ThingTypeUID type : ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES) {
discoveryServices.put(type.getId(), new ZoneTemperatureControlDiscoveryService(bridgeHandler, type));
}
bridgeHandler.registerSceneStatusListener(this);
bridgeHandler.registerDeviceStatusListener(this);
bridgeHandler.registerTemperatureControlStatusListener(this);
}
/**
* Deactivates all {@link SceneDiscoveryService}s and {@link DeviceDiscoveryService}s of this
* {@link DiscoveryServiceManager} and unregisters them from the given {@link BundleContext}.
*
* @param bundleContext (must not be null)
*/
public void unregisterDiscoveryServices(BundleContext bundleContext) {
if (discoveryServices != null) {
for (AbstractDiscoveryService service : discoveryServices.values()) {
if (service instanceof SceneDiscoveryService) {
SceneDiscoveryService sceneDisServ = (SceneDiscoveryService) service;
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.get(bridgeUID + sceneDisServ.getID());
sceneDisServ.deactivate();
serviceReg.unregister();
discoveryServiceRegs.remove(bridgeUID + sceneDisServ.getID());
}
if (service instanceof DeviceDiscoveryService) {
DeviceDiscoveryService devDisServ = (DeviceDiscoveryService) service;
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.get(bridgeUID + devDisServ.getID());
devDisServ.deactivate();
serviceReg.unregister();
discoveryServiceRegs.remove(bridgeUID + devDisServ.getID());
}
if (service instanceof ZoneTemperatureControlDiscoveryService) {
ZoneTemperatureControlDiscoveryService devDisServ = (ZoneTemperatureControlDiscoveryService) service;
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.get(bridgeUID + devDisServ.getID());
devDisServ.deactivate();
serviceReg.unregister();
discoveryServiceRegs.remove(bridgeUID + devDisServ.getID());
}
}
}
}
/**
* Registers all {@link SceneDiscoveryService}s and {@link DeviceDiscoveryService}s of this
* {@link DiscoveryServiceManager} to the given {@link BundleContext}.
*
* @param bundleContext (must not be null)
*/
public void registerDiscoveryServices(BundleContext bundleContext) {
if (discoveryServices != null) {
for (AbstractDiscoveryService service : discoveryServices.values()) {
if (service instanceof SceneDiscoveryService) {
this.discoveryServiceRegs.put(bridgeUID + ((SceneDiscoveryService) service).getID(), bundleContext
.registerService(DiscoveryService.class.getName(), service, new Hashtable<>()));
}
if (service instanceof DeviceDiscoveryService) {
this.discoveryServiceRegs.put(bridgeUID + ((DeviceDiscoveryService) service).getID(), bundleContext
.registerService(DiscoveryService.class.getName(), service, new Hashtable<>()));
}
if (service instanceof ZoneTemperatureControlDiscoveryService) {
this.discoveryServiceRegs
.put(bridgeUID + ((ZoneTemperatureControlDiscoveryService) service).getID(), bundleContext
.registerService(DiscoveryService.class.getName(), service, new Hashtable<>()));
}
}
}
}
@Override
public String getSceneStatusListenerID() {
return SceneStatusListener.SCENE_DISCOVERY;
}
@Override
public void onSceneStateChanged(boolean flag) {
// nothing to do
}
@Override
public void onSceneRemoved(InternalScene scene) {
if (discoveryServices.get(scene.getSceneType()) != null) {
((SceneDiscoveryService) discoveryServices.get(scene.getSceneType())).onSceneRemoved(scene);
}
}
@Override
public void onSceneAdded(InternalScene scene) {
if (discoveryServices.get(scene.getSceneType()) != null) {
((SceneDiscoveryService) discoveryServices.get(scene.getSceneType())).onSceneAdded(scene);
}
}
@Override
public void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
// nothing to do
}
@Override
public void onDeviceRemoved(GeneralDeviceInformation device) {
if (device instanceof Device) {
String id = ((Device) device).getHWinfo().substring(0, 2);
if (((Device) device).isSensorDevice()) {
id = ((Device) device).getHWinfo().replace("-", "");
}
if (discoveryServices.get(id) != null) {
((DeviceDiscoveryService) discoveryServices.get(id)).onDeviceRemoved(device);
}
}
if (device instanceof Circuit) {
if (discoveryServices.get(DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString()) != null) {
((DeviceDiscoveryService) discoveryServices
.get(DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString())).onDeviceRemoved(device);
}
}
}
@Override
public void onDeviceAdded(GeneralDeviceInformation device) {
if (device instanceof Device) {
String id = ((Device) device).getHWinfo().substring(0, 2);
if (((Device) device).isSensorDevice()) {
id = ((Device) device).getHWinfo();
}
if (discoveryServices.get(id) != null) {
((DeviceDiscoveryService) discoveryServices.get(id)).onDeviceAdded(device);
}
}
if (device instanceof Circuit) {
if (discoveryServices.get(DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString()) != null) {
((DeviceDiscoveryService) discoveryServices
.get(DsDeviceThingTypeProvider.SupportedThingTypes.circuit.toString())).onDeviceAdded(device);
}
}
}
@Override
public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig) {
// nothing to do
}
@Override
public void onSceneConfigAdded(short sceneId) {
// nothing to do
}
@Override
public String getDeviceStatusListenerID() {
return DeviceStatusListener.DEVICE_DISCOVERY;
}
@Override
public void configChanged(TemperatureControlStatus tempControlStatus) {
// currently only this thing-type exists
if (discoveryServices.get(DigitalSTROMBindingConstants.THING_TYPE_ZONE_TEMERATURE_CONTROL.toString()) != null) {
((ZoneTemperatureControlDiscoveryService) discoveryServices
.get(DigitalSTROMBindingConstants.THING_TYPE_ZONE_TEMERATURE_CONTROL.toString()))
.configChanged(tempControlStatus);
}
}
@Override
public void registerTemperatureSensorTransmitter(
TemperatureControlSensorTransmitter temperatureSensorTransreciver) {
// nothing to do
}
@Override
public Integer getTemperationControlStatusListenrID() {
return TemperatureControlStatusListener.DISCOVERY;
}
@Override
public void onTargetTemperatureChanged(Float newValue) {
// nothing to do
}
@Override
public void onControlValueChanged(Integer newValue) {
// nothing to do
}
}

View File

@@ -0,0 +1,240 @@
/**
* 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.digitalstrom.internal.discovery;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
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.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SceneDiscoveryService} discovers all digitalSTROM-scene of one supported scene-type. The scene-type has to
* be given to the {@link #SceneDiscoveryService(BridgeHandler, ThingTypeUID)} as
* {@link ThingTypeUID}. The supported {@link ThingTypeUID} can be found at {@link SceneHandler#SUPPORTED_THING_TYPES}
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class SceneDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(SceneDiscoveryService.class);
private final BridgeHandler bridgeHandler;
private final String sceneType;
public static final int TIMEOUT = 10;
/**
* Creates a new {@link SceneDiscoveryService} for the given supportedThingType.
*
* @param bridgeHandler (must not be null)
* @param supportedThingType (must not be null)
* @throws IllegalArgumentException see {@link AbstractDiscoveryService#AbstractDiscoveryService(int)}
*/
public SceneDiscoveryService(BridgeHandler bridgeHandler, ThingTypeUID supportedThingType)
throws IllegalArgumentException {
super(new HashSet<>(Arrays.asList(supportedThingType)), TIMEOUT, false);
this.sceneType = supportedThingType.getId();
this.bridgeHandler = bridgeHandler;
}
/**
* Deactivates the {@link SceneDiscoveryService} and removes the {@link DiscoveryResult}s.
*/
@Override
public void deactivate() {
logger.debug("deactivate discovery service for scene type {} remove thing tyspes {}", sceneType,
super.getSupportedThingTypes());
removeOlderResults(new Date().getTime());
}
@Override
protected void startScan() {
if (bridgeHandler != null) {
if (bridgeHandler.getScenes() != null) {
for (InternalScene scene : bridgeHandler.getScenes()) {
onSceneAddedInternal(scene);
}
}
}
}
@Override
protected synchronized void stopScan() {
super.stopScan();
removeOlderResults(getTimestampOfLastScan());
}
private void onSceneAddedInternal(InternalScene scene) {
logger.debug("{}", scene.getSceneType());
if (scene.getSceneType().equals(sceneType)) {
if (!ignoredScene(scene.getSceneID()) && !ignoreGroup(scene.getGroupID())) {
ThingUID thingUID = getThingUID(scene);
if (thingUID != null) {
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
Map<String, Object> properties = new HashMap<>();
properties.put(ZONE_ID, scene.getZoneID());
properties.put(GROUP_ID, scene.getGroupID());
if (SceneEnum.containsScene(scene.getSceneID())) {
properties.put(SCENE_ID, SceneEnum.getScene(scene.getSceneID()).toString());
} else {
logger.debug("discovered scene: name '{}' with id {} have an invalid scene-ID",
scene.getSceneName(), scene.getID());
}
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withBridge(bridgeUID).withLabel(scene.getSceneName()).build();
thingDiscovered(discoveryResult);
} else {
logger.debug("discovered unsupported scene: name '{}' with id {}", scene.getSceneName(),
scene.getID());
}
}
}
}
private boolean ignoreGroup(Short groupID) {
if (FuncNameAndColorGroupEnum.getMode(groupID) != null) {
switch (FuncNameAndColorGroupEnum.getMode(groupID)) {
case TEMPERATION_CONTROL:
return true;
default:
return false;
}
}
return false;
}
private boolean ignoredScene(short sceneID) {
switch (SceneEnum.getScene(sceneID)) {
case INCREMENT:
case DECREMENT:
case STOP:
case MINIMUM:
case MAXIMUM:
case DEVICE_ON:
case DEVICE_OFF:
case DEVICE_STOP:
case AREA_1_INCREMENT:
case AREA_1_DECREMENT:
case AREA_1_STOP:
case AREA_2_INCREMENT:
case AREA_2_DECREMENT:
case AREA_2_STOP:
case AREA_3_INCREMENT:
case AREA_3_DECREMENT:
case AREA_3_STOP:
case AREA_4_INCREMENT:
case AREA_4_DECREMENT:
case AREA_4_STOP:
case AREA_STEPPING_CONTINUE:
case ENERGY_OVERLOAD:
case ALARM_SIGNAL:
case AUTO_STANDBY:
case ZONE_ACTIVE:
return true;
default:
return false;
}
}
private ThingUID getThingUID(InternalScene scene) {
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, sceneType);
if (getSupportedThingTypes().contains(thingTypeUID)) {
String thingSceneId = scene.getID();
ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, thingSceneId);
return thingUID;
} else {
return null;
}
}
/**
* Returns the ID of this {@link SceneDiscoveryService}.
*
* @return id of this service
*/
public String getID() {
return sceneType;
}
/**
* Creates a {@link DiscoveryResult} of the given {@link InternalScene}, if the scene exists, if it is allowed to
* use the scene
* and if the scene is not one of the following scenes:
* <ul>
* <li>{@link SceneEnum#INCREMENT}</li>
* <li>{@link SceneEnum#DECREMENT}</li>
* <li>{@link SceneEnum#STOP}</li>
* <li>{@link SceneEnum#MINIMUM}</li>
* <li>{@link SceneEnum#MAXIMUM}</li>
* <li>{@link SceneEnum#AUTO_OFF}</li>
* <li>{@link SceneEnum#DEVICE_ON}</li>
* <li>{@link SceneEnum#DEVICE_OFF}</li>
* <li>{@link SceneEnum#DEVICE_STOP}</li>
* <li>{@link SceneEnum#AREA_1_INCREMENT}</li>
* <li>{@link SceneEnum#AREA_1_DECREMENT}</li>
* <li>{@link SceneEnum#AREA_1_STOP}</li>
* <li>{@link SceneEnum#AREA_2_INCREMENT}</li>
* <li>{@link SceneEnum#AREA_2_DECREMENT}</li>
* <li>{@link SceneEnum#AREA_2_STOP}</li>
* <li>{@link SceneEnum#AREA_3_INCREMENT}</li>
* <li>{@link SceneEnum#AREA_3_DECREMENT}</li>
* <li>{@link SceneEnum#AREA_3_STOP}</li>
* <li>{@link SceneEnum#AREA_4_INCREMENT}</li>
* <li>{@link SceneEnum#AREA_4_DECREMENT}</li>
* <li>{@link SceneEnum#AREA_4_STOP}</li>
* <li>{@link SceneEnum#AREA_STEPPING_CONTINUE}</li>
* <li>{@link SceneEnum#ENERGY_OVERLOAD}</li>
* <li>{@link SceneEnum#ALARM_SIGNAL}</li>
* <li>{@link SceneEnum#AUTO_STANDBY}</li>
* <li>{@link SceneEnum#ZONE_ACTIVE}</li>
* </ul>
*
* @param scene (must not be null)
*/
public void onSceneAdded(InternalScene scene) {
if (super.isBackgroundDiscoveryEnabled()) {
onSceneAddedInternal(scene);
}
}
/**
* Removes the {@link DiscoveryResult} of the given {@link InternalScene}.
*
* @param scene (must not be null)
*/
public void onSceneRemoved(InternalScene scene) {
ThingUID thingUID = getThingUID(scene);
if (thingUID != null) {
thingRemoved(thingUID);
}
}
}

View File

@@ -0,0 +1,136 @@
/**
* 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.digitalstrom.internal.discovery;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.BINDING_ID;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
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.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ZoneTemperatureControlDiscoveryService} discovers all digitalSTROM zones which have temperature control
* configured. The thing-type has to be given to the
* {@link #ZoneTemperatureControlDiscoveryService(BridgeHandler, ThingTypeUID)} as {@link ThingTypeUID}. The supported
* {@link ThingTypeUID} can be found at {@link ZoneTemperatureControlHandler#SUPPORTED_THING_TYPES}
*
* @author Michael Ochel
* @author Matthias Siegele
*/
public class ZoneTemperatureControlDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(ZoneTemperatureControlDiscoveryService.class);
BridgeHandler bridgeHandler;
private final ThingUID bridgeUID;
private final String thingTypeID;
public static final int TIMEOUT = 10;
/**
* Creates a new {@link ZoneTemperatureControlDiscoveryService}.
*
* @param bridgeHandler must not be null
* @param supportedThingType must not be null
* @throws IllegalArgumentException see {@link AbstractDiscoveryService#AbstractDiscoveryService(int)}
*/
public ZoneTemperatureControlDiscoveryService(BridgeHandler bridgeHandler, ThingTypeUID supportedThingType)
throws IllegalArgumentException {
super(new HashSet<>(Arrays.asList(supportedThingType)), TIMEOUT, true);
bridgeUID = bridgeHandler.getThing().getUID();
this.bridgeHandler = bridgeHandler;
thingTypeID = supportedThingType.getId();
}
@Override
protected void startScan() {
for (TemperatureControlStatus tempConStat : bridgeHandler.getTemperatureControlStatusFromAllZones()) {
internalConfigChanged(tempConStat);
}
}
@Override
public void deactivate() {
logger.debug("Deactivate discovery service for zone teperature control type remove thing types {}",
super.getSupportedThingTypes());
removeOlderResults(new Date().getTime());
}
/**
* Method for the background discovery
*
* @see org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener#configChanged(TemperatureControlStatus)
* @param tempControlStatus can be null
*/
public void configChanged(TemperatureControlStatus tempControlStatus) {
if (isBackgroundDiscoveryEnabled()) {
internalConfigChanged(tempControlStatus);
}
}
private void internalConfigChanged(TemperatureControlStatus tempControlStatus) {
if (tempControlStatus == null) {
return;
}
if (tempControlStatus.isNotSetOff()) {
logger.debug("found configured zone TemperatureControlStatus = {}", tempControlStatus);
ThingUID thingUID = getThingUID(tempControlStatus);
if (thingUID != null) {
Map<String, Object> properties = new HashMap<>();
properties.put(DigitalSTROMBindingConstants.ZONE_ID, tempControlStatus.getZoneID());
String zoneName = tempControlStatus.getZoneName();
if (StringUtils.isBlank(zoneName)) {
zoneName = tempControlStatus.getZoneID().toString();
}
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withBridge(bridgeUID).withLabel(zoneName).build();
thingDiscovered(discoveryResult);
}
}
}
private ThingUID getThingUID(TemperatureControlStatus tempControlStatus) {
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, thingTypeID);
if (getSupportedThingTypes().contains(thingTypeUID)) {
String thingID = tempControlStatus.getZoneID().toString();
ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, thingID);
return thingUID;
} else {
return null;
}
}
/**
* Returns the ID of this {@link ZoneTemperatureControlDiscoveryService}.
*
* @return id of the service
*/
public String getID() {
return thingTypeID;
}
}

View File

@@ -0,0 +1,852 @@
/**
* 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.digitalstrom.internal.handler;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.ConnectionManagerImpl;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.DeviceStatusManagerImpl;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.SceneManagerImpl;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.StructureManagerImpl;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.TemperatureControlManager;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
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.ThingTypeUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BridgeHandler} is the handler for a digitalSTROM-Server and connects it to
* the framework.<br>
* All {@link DeviceHandler}s and {@link SceneHandler}s use the {@link BridgeHandler} to execute the actual
* commands.<br>
* <br>
* The {@link BridgeHandler} also:
* <ul>
* <li>manages the {@link DeviceStatusManager} (starts, stops, register {@link DeviceStatusListener},
* register {@link SceneStatusListener} and so on)</li>
* <li>creates and load the configurations in the {@link Config}.</li>
* <li>implements {@link ManagerStatusListener} to manage the expiration of the Thing initializations</li>
* <li>implements the {@link ConnectionListener} to manage the {@link ThingStatus} of this {@link BridgeHandler}</li>
* <li>and implements the {@link TotalPowerConsumptionListener} to update his Channels.</li>
* </ul>
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class BridgeHandler extends BaseBridgeHandler
implements ConnectionListener, TotalPowerConsumptionListener, ManagerStatusListener {
private final Logger logger = LoggerFactory.getLogger(BridgeHandler.class);
/**
* Contains all supported thing types of this handler
*/
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DSS_BRIDGE);
private static final long RECONNECT_TRACKER_INTERVAL = 15;
/* DS-Manager */
private ConnectionManager connMan;
private StructureManager structMan;
private SceneManager sceneMan;
private DeviceStatusManager devStatMan;
private TemperatureControlManager tempContMan;
private EventListener eventListener;
private ScheduledFuture<?> reconnectTracker;
private DeviceStatusListener deviceDiscovery;
private SceneStatusListener sceneDiscovery;
private TemperatureControlStatusListener temperatureControlDiscovery;
private Config config;
List<SceneStatusListener> unregisterSceneStatusListeners;
private short connectionTimeoutCounter = 0;
private final short ignoredTimeouts = 5;
private class Initializer implements Runnable {
BridgeHandler bridge;
Config config;
public Initializer(BridgeHandler bridge, Config config) {
this.bridge = bridge;
this.config = config;
}
@Override
public void run() {
logger.debug("Checking connection");
if (connMan == null) {
connMan = new ConnectionManagerImpl(config, bridge, true);
} else {
connMan.registerConnectionListener(bridge);
connMan.configHasBeenUpdated();
}
logger.debug("Initializing digitalSTROM Manager ");
if (eventListener == null) {
eventListener = new EventListener(connMan);
}
if (structMan == null) {
structMan = new StructureManagerImpl();
}
if (sceneMan == null) {
sceneMan = new SceneManagerImpl(connMan, structMan, bridge, eventListener);
}
if (devStatMan == null) {
devStatMan = new DeviceStatusManagerImpl(connMan, structMan, sceneMan, bridge, eventListener);
} else {
devStatMan.registerStatusListener(bridge);
}
devStatMan.registerTotalPowerConsumptionListener(bridge);
if (connMan.checkConnection()) {
logger.debug("connection established, start services");
if (TemperatureControlManager.isHeatingControllerInstallated(connMan)) {
if (tempContMan == null) {
tempContMan = new TemperatureControlManager(connMan, eventListener,
temperatureControlDiscovery);
temperatureControlDiscovery = null;
} else {
if (temperatureControlDiscovery != null) {
tempContMan.registerTemperatureControlStatusListener(temperatureControlDiscovery);
}
}
}
structMan.generateZoneGroupNames(connMan);
devStatMan.start();
eventListener.start();
}
boolean configChanged = false;
Configuration configuration = bridge.getConfig();
if (connMan.getApplicationToken() != null) {
configuration.remove(USER_NAME);
configuration.remove(PASSWORD);
logger.debug("Application-Token is: {}", connMan.getApplicationToken());
configuration.put(APPLICATION_TOKEN, connMan.getApplicationToken());
configChanged = true;
}
Map<String, String> properties = editProperties();
String dSSname = connMan.getDigitalSTROMAPI().getInstallationName(connMan.getSessionToken());
if (dSSname != null) {
properties.put(DS_NAME, dSSname);
}
Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
if (dsidMap != null) {
logger.debug("{}", dsidMap);
properties.putAll(dsidMap);
}
Map<String, String> versions = connMan.getDigitalSTROMAPI().getSystemVersion();
if (versions != null) {
properties.putAll(versions);
}
if (StringUtils.isBlank(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT))
&& StringUtils.isNotBlank(config.getCert())) {
properties.put(DigitalSTROMBindingConstants.SERVER_CERT, config.getCert());
}
logger.debug("update properties");
updateProperties(properties);
if (configChanged) {
updateConfiguration(configuration);
}
}
}
/**
* Creates a new {@link BridgeHandler}.
*
* @param bridge must not be null
*/
public BridgeHandler(Bridge bridge) {
super(bridge);
}
@Override
public void initialize() {
logger.debug("Initializing digitalSTROM-BridgeHandler");
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Checking configuration...");
// Start an extra thread to readout the configuration and check the connection, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
Config config = loadAndCheckConfig();
if (config != null) {
logger.debug("{}", config.toString());
scheduler.execute(new Initializer(this, config));
}
}
private boolean checkLoginConfig(Config config) {
if ((StringUtils.isNotBlank(config.getUserName()) && StringUtils.isNotBlank(config.getPassword()))
|| StringUtils.isNotBlank(config.getAppToken())) {
return true;
}
onConnectionStateChange(CONNECTION_LOST, NO_USER_PASSWORD);
return false;
}
private Config loadAndCheckConfig() {
Configuration thingConfig = super.getConfig();
Config config = loadAndCheckConnectionData(thingConfig);
if (config == null) {
return null;
}
logger.debug("Loading configuration");
List<String> numberExc = new ArrayList<>();
// Parameters can't be null, because of an existing default value.
if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) instanceof BigDecimal) {
config.setSensordataRefreshInterval(
((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL)).intValue()
* 1000);
} else {
numberExc.add("\"Sensor update interval\" ( "
+ thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) + ")");
}
if (thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) instanceof BigDecimal) {
config.setTotalPowerUpdateInterval(
((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL)).intValue()
* 1000);
} else {
numberExc.add("\"Total power update interval\" ("
+ thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) + ")");
}
if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) instanceof BigDecimal) {
config.setSensorReadingWaitTime(
((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME)).intValue() * 1000);
} else {
numberExc.add("\"Wait time sensor reading\" ("
+ thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) + ")");
}
if (thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) instanceof BigDecimal) {
config.setTrashDeviceDeleteTime(
((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY))
.intValue());
} else {
numberExc.add("\"Days to be slaked trash bin devices\" ("
+ thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) + ")");
}
if (!numberExc.isEmpty()) {
String excText = "The field ";
for (int i = 0; i < numberExc.size(); i++) {
excText = excText + numberExc.get(i);
if (i < numberExc.size() - 2) {
excText = excText + ", ";
} else if (i < numberExc.size() - 1) {
excText = excText + " and ";
}
}
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, excText + " have to be a number.");
return null;
}
if (StringUtils.isNotBlank(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT))) {
config.setCert(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT));
}
return config;
}
private Config loadAndCheckConnectionData(Configuration thingConfig) {
if (this.config == null) {
this.config = new Config();
}
// load and check connection and authorization data
if (StringUtils.isNotBlank((String) thingConfig.get(HOST))) {
config.setHost(thingConfig.get(HOST).toString());
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"The connection to the digitalSTROM-Server can't established, because the host address is missing. Please set the host address.");
return null;
}
if (thingConfig.get(USER_NAME) != null) {
config.setUserName(thingConfig.get(USER_NAME).toString());
} else {
config.setUserName(null);
}
if (thingConfig.get(PASSWORD) != null) {
config.setPassword(thingConfig.get(PASSWORD).toString());
} else {
config.setPassword(null);
}
if (thingConfig.get(APPLICATION_TOKEN) != null) {
config.setAppToken(thingConfig.get(APPLICATION_TOKEN).toString());
} else {
config.setAppToken(null);
}
if (!checkLoginConfig(config)) {
return null;
}
return config;
}
@Override
public void dispose() {
logger.debug("Handler disposed");
if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
reconnectTracker.cancel(true);
}
if (eventListener != null) {
eventListener.stop();
}
if (devStatMan != null) {
devStatMan.unregisterTotalPowerConsumptionListener();
devStatMan.unregisterStatusListener();
this.devStatMan.stop();
}
if (connMan != null) {
connMan.unregisterConnectionListener();
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
channelLinked(channelUID);
} else {
logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
}
}
@Override
public void handleRemoval() {
for (Thing thing : getThing().getThings()) {
// Inform Thing-Child's about removed bridge.
final ThingHandler thingHandler = thing.getHandler();
if (thingHandler != null) {
thingHandler.bridgeStatusChanged(ThingStatusInfoBuilder.create(ThingStatus.REMOVED).build());
}
}
if (StringUtils.isNotBlank((String) super.getConfig().get(APPLICATION_TOKEN))) {
if (connMan == null) {
Config config = loadAndCheckConnectionData(this.getConfig());
if (config != null) {
this.connMan = new ConnectionManagerImpl(config, null, false);
} else {
updateStatus(ThingStatus.REMOVED);
return;
}
}
if (connMan.removeApplicationToken()) {
logger.debug("Application-Token deleted");
}
}
updateStatus(ThingStatus.REMOVED);
}
/* methods to store listener */
/**
* Registers a new {@link DeviceStatusListener} on the {@link DeviceStatusManager}.
*
* @param deviceStatusListener (must not be null)
*/
public synchronized void registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
if (this.devStatMan != null) {
if (deviceStatusListener == null) {
throw new IllegalArgumentException("It's not allowed to pass null.");
}
if (deviceStatusListener.getDeviceStatusListenerID() != null) {
if (devStatMan.getManagerState().equals(ManagerStates.RUNNING)) {
devStatMan.registerDeviceListener(deviceStatusListener);
} else if (deviceStatusListener.getDeviceStatusListenerID()
.equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
devStatMan.registerDeviceListener(deviceStatusListener);
}
} else {
throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
}
} else {
if (deviceStatusListener.getDeviceStatusListenerID().equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
deviceDiscovery = deviceStatusListener;
}
}
}
/**
* Unregisters a new {@link DeviceStatusListener} on the {@link BridgeHandler}.
*
* @param deviceStatusListener (must not be null)
*/
public void unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
if (this.devStatMan != null) {
if (deviceStatusListener.getDeviceStatusListenerID() != null) {
this.devStatMan.unregisterDeviceListener(deviceStatusListener);
} else {
throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
}
}
}
/**
* Registers a new {@link SceneStatusListener} on the {@link BridgeHandler}.
*
* @param sceneStatusListener (must not be null)
*/
public synchronized void registerSceneStatusListener(SceneStatusListener sceneStatusListener) {
if (this.sceneMan != null) {
if (sceneStatusListener == null) {
throw new IllegalArgumentException("It's not allowed to pass null.");
}
if (sceneStatusListener.getSceneStatusListenerID() != null) {
this.sceneMan.registerSceneListener(sceneStatusListener);
} else {
throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null.");
}
} else {
if (sceneStatusListener.getSceneStatusListenerID().equals(SceneStatusListener.SCENE_DISCOVERY)) {
sceneDiscovery = sceneStatusListener;
}
}
}
/**
* Unregisters a new {@link SceneStatusListener} on the {@link DeviceStatusManager}.
*
* @param sceneStatusListener (must not be null)
*/
public void unregisterSceneStatusListener(SceneStatusListener sceneStatusListener) {
if (this.sceneMan != null) {
if (sceneStatusListener.getSceneStatusListenerID() != null) {
this.sceneMan.unregisterSceneListener(sceneStatusListener);
} else {
throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null..");
}
}
}
/**
* Has to be called from a removed Thing-Child to rediscovers the Thing.
*
* @param id = scene or device id (must not be null)
*/
public void childThingRemoved(String id) {
if (id != null && id.split("-").length == 3) {
InternalScene scene = sceneMan.getInternalScene(id);
if (scene != null) {
sceneMan.removeInternalScene(id);
sceneMan.addInternalScene(scene);
}
} else {
devStatMan.removeDevice(id);
}
}
/**
* Delegate a stop command from a Thing to the {@link DeviceStatusManager#sendStopComandsToDSS(Device)}.
*
* @param device can be null
*/
public void stopOutputValue(Device device) {
this.devStatMan.sendStopComandsToDSS(device);
}
@Override
public void channelLinked(ChannelUID channelUID) {
if (devStatMan != null) {
MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
if (meteringType != null) {
if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
onEnergyMeterValueChanged(devStatMan.getTotalEnergyMeterValue());
} else {
onTotalPowerConsumptionChanged(devStatMan.getTotalPowerConsumption());
}
} else {
logger.warn("Channel with id {} is not known for the thing with id {}.", channelUID.getId(),
getThing().getUID());
}
}
}
@Override
public void onTotalPowerConsumptionChanged(int newPowerConsumption) {
updateChannelState(MeteringTypeEnum.CONSUMPTION, MeteringUnitsEnum.WH, newPowerConsumption);
}
@Override
public void onEnergyMeterValueChanged(int newEnergyMeterValue) {
updateChannelState(MeteringTypeEnum.ENERGY, MeteringUnitsEnum.WH, newEnergyMeterValue * 0.001);
}
@Override
public void onEnergyMeterWsValueChanged(int newEnergyMeterValue) {
// not needed
}
private void updateChannelState(MeteringTypeEnum meteringType, MeteringUnitsEnum meteringUnit, double value) {
String channelID = DsChannelTypeProvider.getMeteringChannelID(meteringType, meteringUnit, true);
if (getThing().getChannel(channelID) != null) {
updateState(channelID, new DecimalType(value));
}
}
@Override
public void onConnectionStateChange(String newConnectionState) {
switch (newConnectionState) {
case CONNECTION_LOST:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"The connection to the digitalSTROM-Server cannot be established.");
startReconnectTracker();
return;
case CONNECTION_RESUMED:
if (connectionTimeoutCounter > 0) {
// reset connection timeout counter
connectionTimeoutCounter = 0;
if (connMan.checkConnection()) {
restartServices();
setStatus(ThingStatus.ONLINE);
}
}
return;
case APPLICATION_TOKEN_GENERATED:
if (connMan != null) {
Configuration config = this.getConfig();
config.remove(USER_NAME);
config.remove(PASSWORD);
config.put(APPLICATION_TOKEN, connMan.getApplicationToken());
this.updateConfiguration(config);
}
return;
default:
return;
}
}
private void setStatus(ThingStatus status) {
logger.debug("set status to: {}", status);
updateStatus(status);
for (Thing thing : getThing().getThings()) {
ThingHandler handler = thing.getHandler();
if (handler != null) {
handler.bridgeStatusChanged(getThing().getStatusInfo());
}
}
}
private void startReconnectTracker() {
if (reconnectTracker == null || reconnectTracker.isCancelled()) {
logger.debug("Connection lost, stop all services and start reconnectTracker.");
stopServices();
reconnectTracker = scheduler.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
if (connMan != null) {
boolean conStat = connMan.checkConnection();
logger.debug("check connection = {}", conStat);
if (conStat) {
restartServices();
reconnectTracker.cancel(false);
}
}
}
}, RECONNECT_TRACKER_INTERVAL, RECONNECT_TRACKER_INTERVAL, TimeUnit.SECONDS);
}
}
private void stopServices() {
if (devStatMan != null && !devStatMan.getManagerState().equals(ManagerStates.STOPPED)) {
devStatMan.stop();
}
if (eventListener != null && eventListener.isStarted()) {
eventListener.stop();
}
}
private void restartServices() {
logger.debug("reconnect, stop reconnection tracker and restart services");
if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
reconnectTracker.cancel(true);
}
stopServices();
if (devStatMan != null) {
devStatMan.start();
}
if (eventListener != null) {
eventListener.start();
}
}
@Override
public void onConnectionStateChange(String newConnectionState, String reason) {
if (newConnectionState.equals(NOT_AUTHENTICATED) || newConnectionState.equals(CONNECTION_LOST)) {
switch (reason) {
case WRONG_APP_TOKEN:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"User defined Application-Token is wrong. "
+ "Please set user name and password to generate an Application-Token or set an valid Application-Token.");
stopServices();
return;
case WRONG_USER_OR_PASSWORD:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"The set username or password is wrong.");
stopServices();
return;
case NO_USER_PASSWORD:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"No username or password is set to generate Application-Token. Please set user name and password or Application-Token.");
stopServices();
return;
case CONNECTON_TIMEOUT:
// ignore the first connection timeout
if (connectionTimeoutCounter++ > ignoredTimeouts) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Connection lost because connection timeout to Server.");
break;
} else {
return;
}
case HOST_NOT_FOUND:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Server not found! Please check these points:\n" + " - Is digitalSTROM-Server turned on?\n"
+ " - Is the host address correct?\n"
+ " - Is the ethernet cable connection established?");
break;
case UNKNOWN_HOST:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Unknown host name, please check the set host name!");
break;
case INVALID_URL:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid URL is set.");
break;
case CONNECTION_LOST:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"IOException / Connection lost.");
break;
case SSL_HANDSHAKE_ERROR:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"SSL Handshake error / Connection lost.");
break;
default:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
}
// reset connection timeout counter
connectionTimeoutCounter = 0;
startReconnectTracker();
}
}
/**
* Returns a list of all {@link Device}'s.
*
* @return device list (cannot be null)
*/
public List<Device> getDevices() {
return this.structMan != null && this.structMan.getDeviceMap() != null
? new LinkedList<>(this.structMan.getDeviceMap().values())
: null;
}
/**
* Returns the {@link StructureManager}.
*
* @return StructureManager
*/
public StructureManager getStructureManager() {
return this.structMan;
}
/**
* Delegates a scene command of a Thing to the
* {@link DeviceStatusManager#sendSceneComandsToDSS(InternalScene, boolean)}
*
* @param scene the called scene
* @param call_undo (true = call scene | false = undo scene)
*/
public void sendSceneComandToDSS(InternalScene scene, boolean call_undo) {
if (devStatMan != null) {
devStatMan.sendSceneComandsToDSS(scene, call_undo);
}
}
/**
* Delegates a device command of a Thing to the
* {@link DeviceStatusManager#sendComandsToDSS(Device, DeviceStateUpdate)}
*
* @param device can be null
* @param deviceStateUpdate can be null
*/
public void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
if (devStatMan != null) {
devStatMan.sendComandsToDSS(device, deviceStateUpdate);
}
}
/**
* Returns a list of all {@link InternalScene}'s.
*
* @return Scene list (cannot be null)
*/
public List<InternalScene> getScenes() {
return sceneMan != null ? sceneMan.getScenes() : new LinkedList<>();
}
/**
* Returns the {@link ConnectionManager}.
*
* @return ConnectionManager
*/
public ConnectionManager getConnectionManager() {
return this.connMan;
}
@Override
public void onStatusChanged(ManagerTypes managerType, ManagerStates state) {
if (managerType.equals(ManagerTypes.DEVICE_STATUS_MANAGER)) {
switch (state) {
case INITIALIZING:
if (deviceDiscovery != null) {
devStatMan.registerDeviceListener(deviceDiscovery);
deviceDiscovery = null;
}
logger.debug("Building digitalSTROM model");
break;
case RUNNING:
updateStatus(ThingStatus.ONLINE);
break;
case STOPPED:
if (!getThing().getStatusInfo().getStatusDetail().equals(ThingStatusDetail.COMMUNICATION_ERROR)
&& !getThing().getStatusInfo().getStatusDetail()
.equals(ThingStatusDetail.CONFIGURATION_ERROR)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "DeviceStatusManager is stopped.");
devStatMan.start();
}
break;
default:
break;
}
}
if (managerType.equals(ManagerTypes.SCENE_MANAGER)) {
switch (state) {
case GENERATING_SCENES:
logger.debug("SceneManager reports that he is generating scenes");
if (sceneDiscovery != null) {
sceneMan.registerSceneListener(sceneDiscovery);
sceneDiscovery = null;
}
break;
case RUNNING:
logger.debug("SceneManager reports that he is running");
break;
default:
break;
}
}
}
/**
* Returns a {@link List} of all {@link Circuit}'s.
*
* @return circuit list
*/
public List<Circuit> getCircuits() {
logger.debug("circuits: {}", structMan.getCircuitMap().values().toString());
return structMan != null && structMan.getCircuitMap() != null
? new LinkedList<>(structMan.getCircuitMap().values())
: null;
}
/**
* Returns the {@link TemperatureControlManager} or null if no one exist.
*
* @return {@link TemperatureControlManager}
*/
public TemperatureControlManager getTemperatureControlManager() {
return tempContMan;
}
/**
* Registers the given {@link TemperatureControlStatusListener} to the {@link TemperatureControlManager}.
*
* @param temperatureControlStatusListener can be null
*/
public void registerTemperatureControlStatusListener(
TemperatureControlStatusListener temperatureControlStatusListener) {
if (tempContMan != null) {
tempContMan.registerTemperatureControlStatusListener(temperatureControlStatusListener);
} else if (TemperatureControlStatusListener.DISCOVERY
.equals(temperatureControlStatusListener.getTemperationControlStatusListenrID())) {
this.temperatureControlDiscovery = temperatureControlStatusListener;
}
}
/**
* Unregisters the given {@link TemperatureControlStatusListener} from the {@link TemperatureControlManager}.
*
* @param temperatureControlStatusListener can be null
*/
public void unregisterTemperatureControlStatusListener(
TemperatureControlStatusListener temperatureControlStatusListener) {
if (tempContMan != null) {
tempContMan.unregisterTemperatureControlStatusListener(temperatureControlStatusListener);
}
}
/**
* see {@link TemperatureControlManager#getTemperatureControlStatusFromAllZones()}
*
* @return all temperature control status objects
*/
public Collection<TemperatureControlStatus> getTemperatureControlStatusFromAllZones() {
return tempContMan != null ? tempContMan.getTemperatureControlStatusFromAllZones() : new LinkedList<>();
}
}

View File

@@ -0,0 +1,311 @@
/**
* 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.digitalstrom.internal.handler;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
import org.openhab.core.library.types.DecimalType;
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.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CircuitHandler} is responsible for handling the configuration and updating the metering channels of a
* digitalStrom circuit. <br>
* <br>
* For that it uses the {@link BridgeHandler} to register this class as a {@link DeviceStatusListener} to get informed
* about changes from the accompanying {@link Circuit}.
*
* @author Michael Ochel
* @author Matthias Siegele
*/
public class CircuitHandler extends BaseThingHandler implements DeviceStatusListener {
private final Logger logger = LoggerFactory.getLogger(CircuitHandler.class);
/**
* Contains all supported thing types of this handler, will be filled by DsDeviceThingTypeProvider.
*/
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>();
private String dSID;
private Circuit circuit;
private BridgeHandler dssBridgeHandler;
/**
* Creates a new {@link CircuitHandler}.
*
* @param thing must not be null
*/
public CircuitHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing CircuitHandler.");
if (StringUtils.isNotBlank((String) getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID))) {
dSID = getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID).toString();
final Bridge bridge = getBridge();
if (bridge != null) {
bridgeStatusChanged(bridge.getStatusInfo());
} else {
// Set status to OFFLINE if no bridge is available e.g. because the bridge has been removed and the
// Thing was reinitialized.
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
}
}
@Override
public void dispose() {
logger.debug("Handler disposed... unregister DeviceStatusListener");
if (dSID != null) {
if (dssBridgeHandler != null) {
dssBridgeHandler.unregisterDeviceStatusListener(this);
}
}
circuit = null;
}
private synchronized BridgeHandler getDssBridgeHandler() {
if (this.dssBridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bride cannot be found");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof BridgeHandler) {
dssBridgeHandler = (BridgeHandler) handler;
} else {
return null;
}
}
return dssBridgeHandler;
}
@Override
public void thingUpdated(Thing thing) {
this.thing = thing;
if (circuit == null) {
initialize();
}
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
if (dSID != null) {
if (getDssBridgeHandler() != null) {
if (circuit == null) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"waiting for listener registration");
dssBridgeHandler.registerDeviceStatusListener(this);
} else {
updateStatus(ThingStatus.ONLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
}
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
}
logger.debug("Set status to {}", getThing().getStatusInfo());
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// the same handling like total metering values
if (dssBridgeHandler != null) {
dssBridgeHandler.handleCommand(channelUID, command);
}
}
@Override
public void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
if (deviceStateUpdate != null && DeviceStateUpdate.UPDATE_CIRCUIT_METER.equals(deviceStateUpdate.getType())) {
if (deviceStateUpdate.getValue() instanceof CachedMeteringValue) {
CachedMeteringValue cachedVal = (CachedMeteringValue) deviceStateUpdate.getValue();
if (MeteringUnitsEnum.WH.equals(cachedVal.getMeteringUnit())) {
if (cachedVal.getMeteringType().equals(MeteringTypeEnum.ENERGY)) {
updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue() * 0.001));
} else {
updateState(getChannelID(cachedVal), new DecimalType(cachedVal.getValue()));
}
}
}
}
}
@Override
public void onDeviceRemoved(GeneralDeviceInformation device) {
if (device instanceof Circuit) {
this.circuit = (Circuit) device;
if (this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
if (!((Device) circuit).isPresent()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Circuit is not present in the digitalSTROM-System.");
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Circuit is not avaible in the digitalSTROM-System.");
}
}
logger.debug("Set status to {}", getThing().getStatus());
}
}
@Override
public void onDeviceAdded(GeneralDeviceInformation device) {
if (device instanceof Circuit) {
this.circuit = (Circuit) device;
if (this.circuit.isPresent()) {
ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
logger.debug("Set status to {}", getThing().getStatus());
checkCircuitInfoProperties(this.circuit);
// load first channel values
onCircuitStateInitial(this.circuit);
return;
}
}
onDeviceRemoved(device);
}
private void checkCircuitInfoProperties(Circuit device) {
boolean propertiesChanged = false;
Map<String, String> properties = editProperties();
// check device info
if (device.getName() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
propertiesChanged = true;
}
if (device.getDSUID() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
propertiesChanged = true;
}
if (device.getHwName() != null) {
properties.put(DigitalSTROMBindingConstants.HW_NAME, device.getHwName());
propertiesChanged = true;
}
if (device.getHwVersionString() != null) {
properties.put(DigitalSTROMBindingConstants.HW_VERSION, device.getHwVersionString());
propertiesChanged = true;
}
if (device.getSwVersion() != null) {
properties.put(DigitalSTROMBindingConstants.SW_VERSION, device.getSwVersion());
propertiesChanged = true;
}
if (device.getApiVersion() != null) {
properties.put(DigitalSTROMBindingConstants.API_VERSION, device.getApiVersion().toString());
propertiesChanged = true;
}
if (device.getDspSwVersion() != null) {
properties.put(DigitalSTROMBindingConstants.DSP_SW_VERSION, device.getDspSwVersion().toString());
propertiesChanged = true;
}
if (device.getArmSwVersion() != null) {
properties.put(DigitalSTROMBindingConstants.ARM_SW_VERSION, device.getArmSwVersion().toString());
propertiesChanged = true;
}
if (propertiesChanged) {
super.updateProperties(properties);
propertiesChanged = false;
}
}
private void onCircuitStateInitial(Circuit circuit) {
if (circuit != null) {
for (CachedMeteringValue cachedMeterValue : circuit.getAllCachedMeteringValues()) {
if (cachedMeterValue != null && MeteringUnitsEnum.WH.equals(cachedMeterValue.getMeteringUnit())) {
String channelID = getChannelID(cachedMeterValue);
if (isLinked(channelID)) {
channelLinked(new ChannelUID(getThing().getUID(), channelID));
}
}
}
}
}
private String getChannelID(CachedMeteringValue cachedMeterValue) {
return DsChannelTypeProvider.getMeteringChannelID(cachedMeterValue.getMeteringType(),
cachedMeterValue.getMeteringUnit(), false);
}
@Override
public void channelLinked(ChannelUID channelUID) {
if (circuit != null) {
MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
double val = circuit.getMeteringValue(meteringType, MeteringUnitsEnum.WH);
if (val > -1) {
if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
updateState(channelUID, new DecimalType(val * 0.001));
} else {
updateState(channelUID, new DecimalType(val));
}
}
}
}
@Override
public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig) {
// nothing to do, will be registered again
}
@Override
public void onSceneConfigAdded(short sceneID) {
// nothing to do
}
@Override
public String getDeviceStatusListenerID() {
return this.dSID;
}
}

View File

@@ -0,0 +1,977 @@
/**
* 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.digitalstrom.internal.handler;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.GeneralLibConstance;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceBinaryInput;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DeviceHandler} is responsible for handling the configuration, load supported channels of a
* digitalSTROM device and handling commands, which are sent to one of the channels. <br>
* <br>
* For that it uses the {@link BridgeHandler} and the {@link DeviceStateUpdate} mechanism of the {@link Device} to
* execute the actual command and implements the {@link DeviceStatusListener} to get informed about changes from the
* accompanying {@link Device}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class DeviceHandler extends BaseThingHandler implements DeviceStatusListener {
private final Logger logger = LoggerFactory.getLogger(DeviceHandler.class);
/**
* Contains all supported thing types of this handler, will be filled by DsDeviceThingTypeProvider.
*/
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>();
public static final String TWO_STAGE_SWITCH_IDENTICATOR = "2";
public static final String THREE_STAGE_SWITCH_IDENTICATOR = "3";
private String dSID;
private Device device;
private BridgeHandler dssBridgeHandler;
private Command lastComand;
private String currentChannel;
private List<String> loadedSensorChannels;
/**
* Creates a new {@link DeviceHandler}.
*
* @param thing must not be null
*/
public DeviceHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing DeviceHandler.");
if (StringUtils.isNotBlank((String) getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID))) {
dSID = getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID).toString();
final Bridge bridge = getBridge();
if (bridge != null) {
bridgeStatusChanged(bridge.getStatusInfo());
} else {
// Set status to OFFLINE if no bridge is available e.g. because the bridge has been removed and the
// Thing was reinitialized.
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
}
}
@Override
public void dispose() {
logger.debug("Handler disposed... unregister DeviceStatusListener");
if (dSID != null) {
if (dssBridgeHandler != null) {
dssBridgeHandler.unregisterDeviceStatusListener(this);
}
}
if (device != null) {
device.setSensorDataRefreshPriority(Config.REFRESH_PRIORITY_NEVER, Config.REFRESH_PRIORITY_NEVER,
Config.REFRESH_PRIORITY_NEVER);
}
device = null;
}
@Override
public void handleRemoval() {
if (getDssBridgeHandler() != null) {
this.dssBridgeHandler.childThingRemoved(dSID);
}
updateStatus(ThingStatus.REMOVED);
}
@Override
public void thingUpdated(Thing thing) {
this.thing = thing;
if (device == null) {
initialize();
}
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
if (dSID != null) {
if (getDssBridgeHandler() != null) {
if (device == null) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"waiting for listener registration");
dssBridgeHandler.registerDeviceStatusListener(this);
} else {
updateStatus(ThingStatus.ONLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
}
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
}
logger.debug("Set status to {}", getThing().getStatusInfo());
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
BridgeHandler dssBridgeHandler = getDssBridgeHandler();
if (dssBridgeHandler == null) {
logger.debug("BridgeHandler not found. Cannot handle command without bridge.");
return;
}
if (device == null) {
logger.debug(
"Device not known on StructureManager or DeviceStatusListener is not registerd. Cannot handle command.");
return;
}
if (command instanceof RefreshType) {
try {
SensorEnum sensorType = SensorEnum.valueOf(channelUID.getId());
dssBridgeHandler.sendComandsToDSS(device, new DeviceStateUpdateImpl(sensorType, 1));
} catch (IllegalArgumentException e) {
dssBridgeHandler.sendComandsToDSS(device,
new DeviceStateUpdateImpl(DeviceStateUpdate.REFRESH_OUTPUT, 0));
}
} else if (!device.isShade()) {
if (DsChannelTypeProvider.isOutputChannel(channelUID.getId())) {
if (command instanceof PercentType) {
device.setOutputValue(
(short) fromPercentToValue(((PercentType) command).intValue(), device.getMaxOutputValue()));
} else if (command instanceof OnOffType) {
if (OnOffType.ON.equals(command)) {
device.setIsOn(true);
} else {
device.setIsOn(false);
}
} else if (command instanceof IncreaseDecreaseType) {
if (IncreaseDecreaseType.INCREASE.equals(command)) {
device.increase();
} else {
device.decrease();
}
} else if (command instanceof StringType) {
device.setOutputValue(Short.parseShort(((StringType) command).toString()));
}
} else {
logger.debug("Command sent to an unknown channel id: {}", channelUID);
}
} else {
if (channelUID.getId().contains(DsChannelTypeProvider.ANGLE)) {
if (command instanceof PercentType) {
device.setAnglePosition(
(short) fromPercentToValue(((PercentType) command).intValue(), device.getMaxSlatAngle()));
} else if (command instanceof OnOffType) {
if (OnOffType.ON.equals(command)) {
device.setAnglePosition(device.getMaxSlatAngle());
} else {
device.setAnglePosition(device.getMinSlatAngle());
}
} else if (command instanceof IncreaseDecreaseType) {
if (IncreaseDecreaseType.INCREASE.equals(command)) {
device.increaseSlatAngle();
} else {
device.decreaseSlatAngle();
}
}
} else if (channelUID.getId().contains(DsChannelTypeProvider.SHADE)) {
if (command instanceof PercentType) {
int percent = ((PercentType) command).intValue();
if (!device.getHWinfo().equals("GR-KL200")) {
percent = 100 - percent;
}
device.setSlatPosition(fromPercentToValue(percent, device.getMaxSlatPosition()));
this.lastComand = command;
} else if (command instanceof StopMoveType) {
if (StopMoveType.MOVE.equals(command)) {
handleCommand(channelUID, this.lastComand);
} else {
dssBridgeHandler.stopOutputValue(device);
}
} else if (command instanceof UpDownType) {
if (UpDownType.UP.equals(command)) {
device.setIsOpen(true);
this.lastComand = command;
} else {
device.setIsOpen(false);
this.lastComand = command;
}
}
} else {
logger.debug("Command sent to an unknown channel id: {}", channelUID);
}
}
}
private int fromPercentToValue(int percent, int max) {
if (percent < 0 || percent == 0) {
return 0;
}
if (max < 0 || max == 0) {
return 0;
}
return (int) (max * ((float) percent / 100));
}
private synchronized BridgeHandler getDssBridgeHandler() {
if (this.dssBridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bride cannot be found");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof BridgeHandler) {
dssBridgeHandler = (BridgeHandler) handler;
} else {
return null;
}
}
return dssBridgeHandler;
}
private boolean sensorChannelsLoaded() {
return loadedSensorChannels != null && !loadedSensorChannels.isEmpty();
}
@Override
public synchronized void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
if (device != null) {
if (deviceStateUpdate != null) {
if (sensorChannelsLoaded()) {
if (deviceStateUpdate.isSensorUpdateType()) {
updateState(getSensorChannelID(deviceStateUpdate.getTypeAsSensorEnum()),
new DecimalType(deviceStateUpdate.getValueAsFloat()));
logger.debug("Update ESH-State");
return;
}
if (deviceStateUpdate.isBinarayInputType()) {
if (deviceStateUpdate.getValueAsShort() == 1) {
updateState(getBinaryInputChannelID(deviceStateUpdate.getTypeAsDeviceBinarayInputEnum()),
OnOffType.ON);
} else {
updateState(getBinaryInputChannelID(deviceStateUpdate.getTypeAsDeviceBinarayInputEnum()),
OnOffType.OFF);
}
}
}
if (!device.isShade()) {
if (currentChannel != null) {
switch (deviceStateUpdate.getType()) {
case DeviceStateUpdate.OUTPUT_DECREASE:
case DeviceStateUpdate.OUTPUT_INCREASE:
case DeviceStateUpdate.OUTPUT:
if (currentChannel.contains(DsChannelTypeProvider.DIMMER)) {
if (deviceStateUpdate.getValueAsInteger() > 0) {
updateState(currentChannel, new PercentType(fromValueToPercent(
deviceStateUpdate.getValueAsInteger(), device.getMaxOutputValue())));
} else {
updateState(currentChannel, OnOffType.OFF);
}
} else if (currentChannel.contains(DsChannelTypeProvider.STAGE)) {
if (currentChannel.contains(TWO_STAGE_SWITCH_IDENTICATOR)) {
updateState(currentChannel,
new StringType(convertStageValue((short) 2, device.getOutputValue())));
} else {
updateState(currentChannel,
new StringType(convertStageValue((short) 3, device.getOutputValue())));
}
}
break;
case DeviceStateUpdate.ON_OFF:
if (currentChannel.contains(DsChannelTypeProvider.STAGE)) {
onDeviceStateChanged(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT,
device.getOutputValue()));
}
if (deviceStateUpdate.getValueAsInteger() > 0) {
updateState(currentChannel, OnOffType.ON);
} else {
updateState(currentChannel, OnOffType.OFF);
}
break;
default:
return;
}
}
} else {
int percent = 0;
switch (deviceStateUpdate.getType()) {
case DeviceStateUpdate.SLAT_DECREASE:
case DeviceStateUpdate.SLAT_INCREASE:
case DeviceStateUpdate.SLATPOSITION:
percent = fromValueToPercent(deviceStateUpdate.getValueAsInteger(),
device.getMaxSlatPosition());
break;
case DeviceStateUpdate.OPEN_CLOSE:
if (deviceStateUpdate.getValueAsInteger() > 0) {
percent = 100;
}
break;
case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
if (device.isBlind() && currentChannel != null) {
if (deviceStateUpdate.getValueAsInteger() > 0) {
updateState(currentChannel, PercentType.HUNDRED);
} else {
updateState(currentChannel, PercentType.ZERO);
}
}
return;
case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
case DeviceStateUpdate.SLAT_ANGLE:
if (device.isBlind() && currentChannel != null) {
updateState(currentChannel,
new PercentType(fromValueToPercent(deviceStateUpdate.getValueAsInteger(),
device.getMaxSlatAngle())));
}
return;
default:
return;
}
if (!device.getHWinfo().equals("GR-KL210")) {
percent = 100 - percent;
}
updateState(DsChannelTypeProvider.SHADE, new PercentType(percent));
}
logger.debug("Update ESH-State");
}
}
}
private int fromValueToPercent(int value, int max) {
if (value <= 0 || max <= 0) {
return 0;
}
int percentValue = new BigDecimal(value * ((float) 100 / max)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
return percentValue < 0 ? 0 : percentValue > 100 ? 100 : percentValue;
}
@Override
public synchronized void onDeviceRemoved(GeneralDeviceInformation device) {
if (device instanceof Device) {
this.device = (Device) device;
if (this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
if (!((Device) device).isPresent()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Device is not present in the digitalSTROM-System.");
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Device is not avaible in the digitalSTROM-System.");
}
}
logger.debug("Set status to {}", getThing().getStatus());
}
}
@Override
public synchronized void onDeviceAdded(GeneralDeviceInformation device) {
if (device instanceof Device) {
this.device = (Device) device;
if (this.device.isPresent()) {
ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
logger.debug("Set status to {}", getThing().getStatus());
// load scene configurations persistently into the thing
for (Short i : this.device.getSavedScenes()) {
onSceneConfigAdded(i);
}
logger.debug("Load saved scene specification into device");
this.device.saveConfigSceneSpecificationIntoDevice(getThing().getProperties());
checkDeviceInfoProperties(this.device);
// load sensor priorities into the device and load sensor channels of the thing
if (!this.device.isShade()) {
loadSensorChannels();
// check and load output channel of the thing
checkOutputChannel();
} else if (this.device.isBlind()) {
// load channel for set the angle of jalousie devices
String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(
((Device) device).getFunctionalColorGroup(), ((Device) device).getOutputMode());
loadOutputChannel(new ChannelTypeUID(BINDING_ID, channelTypeID),
DsChannelTypeProvider.getItemType(channelTypeID));
}
// load first channel values
onDeviceStateInitial(this.device);
return;
}
}
onDeviceRemoved(device);
}
/**
* Updates device info properties.
*
* @param device (must not be null)
*/
private void checkDeviceInfoProperties(Device device) {
boolean propertiesChanged = false;
Map<String, String> properties = editProperties();
// check device info
if (device.getName() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
propertiesChanged = true;
}
if (device.getDSUID() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
propertiesChanged = true;
}
if (device.getHWinfo() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_HW_INFO, device.getHWinfo());
propertiesChanged = true;
}
if (device.getZoneId() != -1) {
properties.put(DigitalSTROMBindingConstants.DEVICE_ZONE_ID, device.getZoneId() + "");
propertiesChanged = true;
}
if (device.getGroups() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_GROUPS, device.getGroups().toString());
propertiesChanged = true;
}
if (device.getOutputMode() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_OUTPUT_MODE, device.getOutputMode().toString());
propertiesChanged = true;
}
if (device.getFunctionalColorGroup() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_FUNCTIONAL_COLOR_GROUP,
device.getFunctionalColorGroup().toString());
propertiesChanged = true;
}
if (device.getMeterDSID() != null) {
properties.put(DigitalSTROMBindingConstants.DEVICE_METER_ID, device.getMeterDSID().toString());
propertiesChanged = true;
}
if (!device.getBinaryInputs().isEmpty()) {
properties.put(DigitalSTROMBindingConstants.DEVICE_BINARAY_INPUTS, getBinarayInputList());
propertiesChanged = true;
}
if (propertiesChanged) {
super.updateProperties(properties);
propertiesChanged = false;
}
}
private String getBinarayInputList() {
List<String> binarayInputs = new ArrayList<>(device.getBinaryInputs().size());
for (DeviceBinaryInput binInput : device.getBinaryInputs()) {
DeviceBinarayInputEnum devBinInp = DeviceBinarayInputEnum.getdeviceBinarayInput(binInput.getInputType());
if (devBinInp != null) {
binarayInputs.add(devBinInp.toString().toLowerCase());
}
}
return binarayInputs.toString();
}
private void loadSensorChannels() {
if (device != null && device.isPresent()) {
// load sensor priorities into the device
boolean configChanged = false;
Configuration config = getThing().getConfiguration();
logger.debug("Add sensor priorities to the device");
String activePowerPrio = Config.REFRESH_PRIORITY_NEVER;
if (config.get(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY) != null) {
activePowerPrio = config.get(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY).toString();
} else {
config.put(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_NEVER);
configChanged = true;
}
// By devices with output mode WIPE the active power always will be read out to check, if the device is not
// in standby any more.
if (OutputModeEnum.WIPE.equals(device.getOutputMode())
&& activePowerPrio.equals(Config.REFRESH_PRIORITY_NEVER)) {
config.put(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_LOW);
configChanged = true;
}
String outputCurrentPrio = Config.REFRESH_PRIORITY_NEVER;
if (config.get(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY) != null) {
outputCurrentPrio = config.get(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY).toString();
} else {
config.put(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_NEVER);
configChanged = true;
}
String electricMeterPrio = Config.REFRESH_PRIORITY_NEVER;
if (config.get(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY) != null) {
electricMeterPrio = config.get(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY).toString();
} else {
config.put(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_NEVER);
configChanged = true;
}
if (configChanged) {
super.updateConfiguration(config);
configChanged = false;
}
device.setSensorDataRefreshPriority(activePowerPrio, electricMeterPrio, outputCurrentPrio);
logger.debug(
"add sensor prioritys: active power = {}, output current = {}, electric meter = {} to device with id {}",
activePowerPrio, outputCurrentPrio, electricMeterPrio, device.getDSID());
// check and load sensor channels of the thing
checkSensorChannel();
}
}
private boolean addLoadedSensorChannel(String sensorChannelType) {
if (loadedSensorChannels == null) {
loadedSensorChannels = new LinkedList<>();
}
if (!loadedSensorChannels.contains(sensorChannelType.toString())) {
return loadedSensorChannels.add(sensorChannelType.toString());
}
return false;
}
private boolean removeLoadedSensorChannel(String sensorChannelType) {
if (loadedSensorChannels == null) {
return false;
}
return loadedSensorChannels.remove(sensorChannelType);
}
private boolean isSensorChannelLoaded(String sensorChannelType) {
if (loadedSensorChannels == null) {
return false;
}
return loadedSensorChannels.contains(sensorChannelType);
}
private void checkSensorChannel() {
List<Channel> channelList = new LinkedList<>(this.getThing().getChannels());
boolean channelListChanged = false;
// if sensor channels with priority never are loaded delete these channels
if (!channelList.isEmpty()) {
Iterator<Channel> channelInter = channelList.iterator();
while (channelInter.hasNext()) {
Channel channel = channelInter.next();
String channelID = channel.getUID().getId();
if (channelID.startsWith(DsChannelTypeProvider.BINARY_INPUT_PRE)) {
DeviceBinarayInputEnum devBinInput = getBinaryInput(channelID);
if (device.getBinaryInput(devBinInput) != null) {
addLoadedSensorChannel(channelID);
} else {
logger.debug("remove {} binary input channel", channelID);
channelInter.remove();
channelListChanged = removeLoadedSensorChannel(channelID);
}
} else {
SensorEnum sensorType = getSensorEnum(channelID);
if (sensorType != null) {
if (SensorEnum.isPowerSensor(sensorType)) {
if (device.checkPowerSensorRefreshPriorityNever(sensorType)) {
logger.debug("remove {} sensor channel", channelID);
channelInter.remove();
channelListChanged = removeLoadedSensorChannel(channelID);
} else {
addLoadedSensorChannel(channelID);
}
} else {
if (device.supportsSensorType(sensorType)) {
addLoadedSensorChannel(channelID);
} else {
logger.debug("remove {} sensor channel", channelID);
channelInter.remove();
removeLoadedSensorChannel(channelID);
channelListChanged = true;
}
}
}
}
}
}
for (SensorEnum sensorType : device.getPowerSensorTypes()) {
if (!device.checkPowerSensorRefreshPriorityNever(sensorType)
&& !isSensorChannelLoaded(getSensorChannelID(sensorType))) {
logger.debug("create {} sensor channel", sensorType.toString());
channelList.add(getSensorChannel(sensorType));
channelListChanged = addLoadedSensorChannel(getSensorChannelID(sensorType));
}
}
if (device.hasClimateSensors()) {
for (SensorEnum sensorType : device.getClimateSensorTypes()) {
if (!isSensorChannelLoaded(getSensorChannelID(sensorType))) {
logger.debug("create {} sensor channel", sensorType.toString());
channelList.add(getSensorChannel(sensorType));
channelListChanged = addLoadedSensorChannel(getSensorChannelID(sensorType));
}
}
}
if (device.isBinaryInputDevice()) {
for (DeviceBinaryInput binInput : device.getBinaryInputs()) {
DeviceBinarayInputEnum binInputType = DeviceBinarayInputEnum
.getdeviceBinarayInput(binInput.getInputType());
if (binInputType != null && !isSensorChannelLoaded(getBinaryInputChannelID(binInputType))) {
logger.debug("create {} sensor channel", binInputType.toString());
channelList.add(getBinaryChannel(binInputType));
channelListChanged = addLoadedSensorChannel(getBinaryInputChannelID(binInputType));
}
}
}
if (channelListChanged) {
logger.debug("load new channel list");
ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(channelList);
updateThing(thingBuilder.build());
}
}
private Channel getSensorChannel(SensorEnum sensorType) {
return ChannelBuilder.create(getSensorChannelUID(sensorType), "Number")
.withType(DsChannelTypeProvider.getSensorChannelUID(sensorType)).build();
}
private Channel getBinaryChannel(DeviceBinarayInputEnum binaryInputType) {
return ChannelBuilder.create(getBinaryInputChannelUID(binaryInputType), "Switch")
.withType(DsChannelTypeProvider.getBinaryInputChannelUID(binaryInputType)).build();
}
private void checkOutputChannel() {
if (device == null) {
logger.debug("Can not load a channel without a device!");
return;
}
// if the device have no output channel or it is disabled all output channels will be deleted
if (!device.isDeviceWithOutput()) {
loadOutputChannel(null, null);
}
String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup(),
device.getOutputMode());
logger.debug("load channel: typeID={}, itemType={}",
DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup(), device.getOutputMode()),
DsChannelTypeProvider.getItemType(channelTypeID));
if (channelTypeID != null && (currentChannel == null || !currentChannel.equals(channelTypeID))) {
loadOutputChannel(new ChannelTypeUID(BINDING_ID, channelTypeID),
DsChannelTypeProvider.getItemType(channelTypeID));
}
}
private void loadOutputChannel(ChannelTypeUID channelTypeUID, String acceptedItemType) {
if (channelTypeUID == null || acceptedItemType == null) {
return;
}
currentChannel = channelTypeUID.getId();
List<Channel> channelList = new LinkedList<>(this.getThing().getChannels());
boolean channelIsAlreadyLoaded = false;
boolean channelListChanged = false;
if (!channelList.isEmpty()) {
Iterator<Channel> channelInter = channelList.iterator();
while (channelInter.hasNext()) {
Channel eshChannel = channelInter.next();
if (DsChannelTypeProvider.isOutputChannel(eshChannel.getUID().getId())) {
if (!eshChannel.getUID().getId().equals(currentChannel)
&& !(device.isShade() && eshChannel.getUID().getId().equals(DsChannelTypeProvider.SHADE))) {
channelInter.remove();
channelListChanged = true;
} else {
if (!eshChannel.getUID().getId().equals(DsChannelTypeProvider.SHADE)) {
channelIsAlreadyLoaded = true;
}
}
}
}
}
if (!channelIsAlreadyLoaded && currentChannel != null) {
Channel channel = ChannelBuilder
.create(new ChannelUID(this.getThing().getUID(), channelTypeUID.getId()), acceptedItemType)
.withType(channelTypeUID).build();
channelList.add(channel);
channelListChanged = true;
}
if (channelListChanged) {
ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(channelList);
updateThing(thingBuilder.build());
logger.debug("load channel: {} with item: {}", channelTypeUID.getAsString(), acceptedItemType);
}
}
private ChannelUID getSensorChannelUID(SensorEnum sensorType) {
return new ChannelUID(getThing().getUID(), getSensorChannelID(sensorType));
}
private String getSensorChannelID(SensorEnum sensorType) {
return sensorType.toString().toLowerCase();
}
private ChannelUID getBinaryInputChannelUID(DeviceBinarayInputEnum binaryInputType) {
return new ChannelUID(getThing().getUID(), getBinaryInputChannelID(binaryInputType));
}
private String getBinaryInputChannelID(DeviceBinarayInputEnum binaryInputType) {
return DsChannelTypeProvider.BINARY_INPUT_PRE + binaryInputType.toString().toLowerCase();
}
private DeviceBinarayInputEnum getBinaryInput(String channelID) {
try {
return DeviceBinarayInputEnum
.valueOf(channelID.replace(DsChannelTypeProvider.BINARY_INPUT_PRE, "").toUpperCase());
} catch (IllegalArgumentException e) {
return null;
}
}
private SensorEnum getSensorEnum(String channelID) {
try {
return SensorEnum.valueOf(channelID.toUpperCase());
} catch (IllegalArgumentException e) {
return null;
}
}
@Override
public void channelLinked(ChannelUID channelUID) {
if (device != null) {
SensorEnum sensorType = getSensorEnum(channelUID.getId());
if (sensorType != null) {
Float val = device.getFloatSensorValue(sensorType);
if (val != null) {
updateState(channelUID, new DecimalType(val));
}
}
Short val = device.getBinaryInputState(getBinaryInput(channelUID.getId()));
if (val != null) {
if (val == 1) {
updateState(channelUID, OnOffType.ON);
} else {
updateState(channelUID, OnOffType.OFF);
}
}
if (channelUID.getId().contains(DsChannelTypeProvider.DIMMER)) {
if (device.isOn()) {
updateState(channelUID,
new PercentType(fromValueToPercent(device.getOutputValue(), device.getMaxOutputValue())));
} else {
updateState(channelUID, new PercentType(0));
}
return;
}
if (channelUID.getId().contains(DsChannelTypeProvider.SWITCH)) {
if (device.isOn()) {
updateState(channelUID, OnOffType.ON);
} else {
updateState(channelUID, OnOffType.OFF);
}
return;
}
if (channelUID.getId().contains(DsChannelTypeProvider.SHADE)) {
updateState(channelUID,
new PercentType(fromValueToPercent(device.getSlatPosition(), device.getMaxSlatPosition())));
return;
}
if (channelUID.getId().contains(DsChannelTypeProvider.ANGLE)) {
updateState(channelUID,
new PercentType(fromValueToPercent(device.getAnglePosition(), device.getMaxSlatAngle())));
return;
}
if (channelUID.getId().contains(DsChannelTypeProvider.STAGE)) {
if (channelUID.getId().contains(TWO_STAGE_SWITCH_IDENTICATOR)) {
updateState(channelUID, new StringType(convertStageValue((short) 2, device.getOutputValue())));
return;
}
if (channelUID.getId().contains(THREE_STAGE_SWITCH_IDENTICATOR)) {
updateState(channelUID, new StringType(convertStageValue((short) 3, device.getOutputValue())));
return;
}
}
}
}
private String convertStageValue(short stage, short value) {
switch (stage) {
case 2:
if (value < 85) {
return OPTION_COMBINED_BOTH_OFF;
} else if (value >= 85 && value < 170) {
return OPTION_COMBINED_FIRST_ON;
} else if (value >= 170 && value <= 255) {
return OPTION_COMBINED_BOTH_ON;
}
case 3:
if (value < 64) {
return OPTION_COMBINED_BOTH_OFF;
} else if (value >= 64 && value < 128) {
return OPTION_COMBINED_FIRST_ON;
} else if (value >= 128 && value < 192) {
return OPTION_COMBINED_SECOND_ON;
} else if (value >= 192 && value <= 255) {
return OPTION_COMBINED_BOTH_ON;
}
}
return null;
}
private void onDeviceStateInitial(Device device) {
if (device != null) {
if (currentChannel != null) {
if (isLinked(currentChannel)) {
channelLinked(new ChannelUID(getThing().getUID(), currentChannel));
}
}
if (!device.isShade()) {
if (loadedSensorChannels != null) {
for (String sensor : loadedSensorChannels) {
Channel channel = getThing().getChannel(sensor);
if (channel != null && isLinked(sensor)) {
channelLinked(channel.getUID());
}
}
}
} else {
if (isLinked(DsChannelTypeProvider.SHADE)) {
channelLinked(new ChannelUID(getThing().getUID(), DsChannelTypeProvider.SHADE));
}
}
}
}
@Override
public synchronized void onSceneConfigAdded(short sceneId) {
if (device != null) {
String saveScene = "";
DeviceSceneSpec sceneSpec = device.getSceneConfig(sceneId);
if (sceneSpec != null) {
saveScene = sceneSpec.toString();
}
Integer[] sceneValue = device.getSceneOutputValue(sceneId);
if (sceneValue[GeneralLibConstance.SCENE_ARRAY_INDEX_VALUE] != -1) {
saveScene = saveScene + ", sceneValue: " + sceneValue[0];
}
if (sceneValue[GeneralLibConstance.SCENE_ARRAY_INDEX_ANGLE] != -1) {
saveScene = saveScene + ", sceneAngle: " + sceneValue[1];
}
String key = DigitalSTROMBindingConstants.DEVICE_SCENE + sceneId;
if (!saveScene.isEmpty()) {
logger.debug("Save scene configuration: [{}] to thing with UID {}", saveScene, getThing().getUID());
super.updateProperty(key, saveScene);
// persist the new property
// super.updateThing(editThing().build());
}
}
}
@Override
public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whichConfig) {
if (whichConfig != null) {
switch (whichConfig) {
case DEVICE_NAME:
super.updateProperty(DEVICE_NAME, device.getName());
break;
case METER_DSID:
super.updateProperty(DEVICE_METER_ID, device.getMeterDSID().getValue());
break;
case ZONE_ID:
super.updateProperty(DEVICE_ZONE_ID, device.getZoneId() + "");
break;
case GROUPS:
super.updateProperty(DEVICE_GROUPS, device.getGroups().toString());
break;
case FUNCTIONAL_GROUP:
super.updateProperty(DEVICE_FUNCTIONAL_COLOR_GROUP, device.getFunctionalColorGroup().toString());
checkOutputChannel();
break;
case OUTPUT_MODE:
super.updateProperty(DEVICE_OUTPUT_MODE, device.getOutputMode().toString());
checkOutputChannel();
break;
case BINARY_INPUTS:
super.updateProperty(DEVICE_BINARAY_INPUTS, getBinarayInputList());
checkSensorChannel();
break;
default:
break;
}
}
}
@Override
public String getDeviceStatusListenerID() {
return this.dSID;
}
}

View File

@@ -0,0 +1,367 @@
/**
* 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.digitalstrom.internal.handler;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
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.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SceneHandler} is responsible for handling commands, which are sent to the channel of an
* DigitalSTROM-Scene.<br>
* For that it uses the {@link BridgeHandler} to execute the actual command and implements the
* {@link SceneStatusListener} to get informed about changes from the accompanying {@link InternalScene}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public class SceneHandler extends BaseThingHandler implements SceneStatusListener {
private final Logger logger = LoggerFactory.getLogger(SceneHandler.class);
/**
* Contains all supported thing types of this handler.
*/
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(
DigitalSTROMBindingConstants.THING_TYPE_APP_SCENE, DigitalSTROMBindingConstants.THING_TYPE_GROUP_SCENE,
DigitalSTROMBindingConstants.THING_TYPE_ZONE_SCENE, DigitalSTROMBindingConstants.THING_TYPE_NAMED_SCENE));
/**
* Configured scene does not exist or cannot be used.
*/
public static final String SCENE_WRONG = "sceneWrong";
/**
* Configured zone does not exist.
*/
public static final String ZONE_WRONG = "zoneWrong";
/**
* Configured group does not exist.
*/
public static final String GROUP_WRONG = "groupWrong";
/**
* StructureManager in BridgeHandler is null
*/
public static final String NO_STRUC_MAN = "noStrucMan";
/**
* Configured scene is null.
*/
public static final String NO_SCENE = "noScene";
/**
* BridgeHandler is null.
*/
public static final String NO_BRIDGE = "noBridge";
private BridgeHandler bridgeHandler;
private InternalScene scene;
private String sceneThingID;
/**
* Creates a new {@link SceneHandler}.
*
* @param thing must not be null
*/
public SceneHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing SceneHandler");
final Bridge bridge = getBridge();
if (bridge != null) {
bridgeStatusChanged(bridge.getStatusInfo());
}
}
@Override
public void dispose() {
logger.debug("Handler disposed... unregistering SceneStatusListener");
if (sceneThingID != null) {
BridgeHandler dssBridgeHandler = getBridgeHandler();
if (dssBridgeHandler != null) {
getBridgeHandler().unregisterSceneStatusListener(this);
}
sceneThingID = null;
scene = null;
}
}
@Override
public void handleRemoval() {
if (getBridgeHandler() != null) {
this.bridgeHandler.childThingRemoved(sceneThingID);
}
updateStatus(ThingStatus.REMOVED);
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
if (getBridgeHandler() != null) {
if (scene == null) {
String sceneID = getSceneID(getConfig(), bridgeHandler);
switch (sceneID) {
case SCENE_WRONG:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Configured scene '" + getConfig().get(DigitalSTROMBindingConstants.SCENE_ID)
+ "' does not exist or cannot be used, please check the configuration.");
break;
case ZONE_WRONG:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Configured zone '" + getConfig().get(DigitalSTROMBindingConstants.ZONE_ID)
+ "' does not exist, please check the configuration.");
break;
case GROUP_WRONG:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Configured group '" + getConfig().get(DigitalSTROMBindingConstants.GROUP_ID)
+ "' does not exist, please check the configuration.");
break;
case NO_STRUC_MAN:
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"Waiting for building digitalSTROM model.");
break;
case NO_SCENE:
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"No Scene-ID is set!");
break;
default:
this.sceneThingID = sceneID;
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"Waiting for listener registration");
logger.debug("Set status on {}", getThing().getStatus());
this.bridgeHandler.registerSceneStatusListener(this);
}
} else {
updateStatus(ThingStatus.ONLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE);
}
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
}
logger.debug("Set status to {}", getThing().getStatusInfo());
}
/**
* Checks the configuration and returns a unique Scene-ID or error string.<br>
* The {@link StructureManager} of the {@link BridgeHandler} is used for checking the existing configured zone and
* group. The {@link SceneEnum} will be used to check, if the configured scene exists and is allowed to use.<br>
* If the check succeed the scene-ID will be returned in format "[zoneID]-[groupID]-[SceneID]", otherwise one of the
* following errors {@link String}s will returned:
* <ul>
* <li>{@link #SCENE_WRONG}: Configured scene does not exist or cannot be used.</li>
* <li>{@link #ZONE_WRONG} Configured zone does not exist.</li>
* <li>{@link #GROUP_WRONG}: Configured group does not exist.</li>
* <li>{@link #NO_STRUC_MAN}: StructureManager in BridgeHandler is null.</li>
* <li>{@link #NO_SCENE}: Configured scene is null.</li>
* <li>{@link #NO_BRIDGE}: BridgeHandler is null.</li>
* </ul>
*
* @param configuration (must not be null)
* @param bridgeHandler (can be null)
* @return unique Scene-ID or error string
*/
public static String getSceneID(Configuration configuration, BridgeHandler bridgeHandler) {
if (configuration == null) {
throw new IllegalArgumentException("configuration cannot be null");
}
if (bridgeHandler == null) {
return NO_BRIDGE;
}
String configZoneID;
String configGroupID;
String configSceneID;
short sceneID;
int zoneID;
short groupID;
if (configuration.get(DigitalSTROMBindingConstants.ZONE_ID) != null) {
configZoneID = configuration.get(DigitalSTROMBindingConstants.ZONE_ID).toString();
} else {
configZoneID = "";
}
if (configuration.get(DigitalSTROMBindingConstants.GROUP_ID) != null) {
configGroupID = configuration.get(DigitalSTROMBindingConstants.GROUP_ID).toString();
} else {
configGroupID = "";
}
if (configuration.get(DigitalSTROMBindingConstants.SCENE_ID) != null) {
configSceneID = configuration.get(DigitalSTROMBindingConstants.SCENE_ID).toString();
} else {
configSceneID = "";
}
if (!configSceneID.isEmpty()) {
try {
sceneID = Short.parseShort(configSceneID);
if (!SceneEnum.containsScene(sceneID)) {
return SCENE_WRONG;
}
} catch (NumberFormatException e) {
try {
sceneID = SceneEnum.valueOf(configSceneID.replace(" ", "_").toUpperCase()).getSceneNumber();
} catch (IllegalArgumentException e1) {
return SCENE_WRONG;
}
}
StructureManager strucMan = bridgeHandler.getStructureManager();
if (strucMan != null) {
if (configZoneID.isEmpty()) {
zoneID = 0;
} else {
try {
zoneID = Integer.parseInt(configZoneID);
if (!strucMan.checkZoneID(zoneID)) {
return ZONE_WRONG;
}
} catch (NumberFormatException e) {
zoneID = strucMan.getZoneId(configZoneID);
if (zoneID == -1) {
return ZONE_WRONG;
}
}
}
if (configGroupID.isEmpty()) {
groupID = 0;
} else {
try {
groupID = Short.parseShort(configGroupID);
if (!strucMan.checkZoneGroupID(zoneID, groupID)) {
return GROUP_WRONG;
}
} catch (NumberFormatException e) {
String zoneName = strucMan.getZoneName(zoneID);
groupID = strucMan.getZoneGroupId(zoneName, configGroupID);
}
if (groupID == -1) {
return GROUP_WRONG;
}
}
return zoneID + "-" + groupID + "-" + sceneID;
} else {
return NO_STRUC_MAN;
}
} else {
return NO_SCENE;
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
BridgeHandler dssBridgeHandler = getBridgeHandler();
if (dssBridgeHandler == null) {
logger.debug("BridgeHandler not found. Cannot handle command without bridge.");
return;
}
if (channelUID.getId().equals(DigitalSTROMBindingConstants.CHANNEL_ID_SCENE)) {
if (command instanceof OnOffType) {
if (OnOffType.ON.equals(command)) {
this.bridgeHandler.sendSceneComandToDSS(scene, true);
} else {
this.bridgeHandler.sendSceneComandToDSS(scene, false);
}
}
} else {
logger.warn("Command sent to an unknown channel id: {}", channelUID);
}
}
private synchronized BridgeHandler getBridgeHandler() {
if (this.bridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bridge cannot be found");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof BridgeHandler) {
this.bridgeHandler = (BridgeHandler) handler;
} else {
logger.debug("BridgeHandler cannot be found");
return null;
}
}
return this.bridgeHandler;
}
@Override
public void onSceneStateChanged(boolean flag) {
if (flag) {
updateState(DigitalSTROMBindingConstants.CHANNEL_ID_SCENE, OnOffType.ON);
} else {
updateState(DigitalSTROMBindingConstants.CHANNEL_ID_SCENE, OnOffType.OFF);
}
}
@Override
public void channelLinked(ChannelUID channelUID) {
if (scene != null && channelUID.getId().equals(DigitalSTROMBindingConstants.CHANNEL_ID_SCENE)) {
onSceneStateChanged(scene.isActive());
}
}
@Override
public void onSceneRemoved(InternalScene scene) {
this.scene = scene;
updateStatus(ThingStatus.OFFLINE);
logger.debug("Set status on {}", getThing().getStatus());
}
@Override
public void onSceneAdded(InternalScene scene) {
logger.debug("Scene {} added", scene.getID());
if (this.bridgeHandler != null) {
ThingStatusInfo statusInfo = this.bridgeHandler.getThing().getStatusInfo();
updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
logger.debug("Set status on {}", getThing().getStatus());
}
this.scene = scene;
onSceneStateChanged(scene.isActive());
}
@Override
public String getSceneStatusListenerID() {
return this.sceneThingID;
}
}

View File

@@ -0,0 +1,358 @@
/**
* 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.digitalstrom.internal.handler;
import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.BINDING_ID;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
import org.openhab.binding.digitalstrom.internal.lib.climate.TemperatureControlSensorTransmitter;
import org.openhab.binding.digitalstrom.internal.lib.climate.constants.ControlModes;
import org.openhab.binding.digitalstrom.internal.lib.climate.constants.ControlStates;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.impl.TemperatureControlManager;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ZoneTemperatureControlHandler} is responsible for handling the configuration, to load the supported
* channel of a
* digitalSTROM zone, which has a temperature control configured, and handling commands, which are sent to the channel.
* <br>
* <br>
* For that it uses the {@link BridgeHandler} to register itself as {@link TemperatureControlStatusListener} at the
* {@link TemperatureControlManager} to get informed by status changes. Through the registration as
* {@link TemperatureControlStatusListener} a {@link TemperatureControlSensorTransmitter} will be registered to this
* {@link ZoneTemperatureControlHandler}, which is needed to set the temperature or the control value of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class ZoneTemperatureControlHandler extends BaseThingHandler implements TemperatureControlStatusListener {
/**
* Contains all supported thing types of this handler
*/
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(DigitalSTROMBindingConstants.THING_TYPE_ZONE_TEMERATURE_CONTROL));
private final Logger logger = LoggerFactory.getLogger(ZoneTemperatureControlHandler.class);
private TemperatureControlSensorTransmitter temperatureSensorTransmitter;
private BridgeHandler dssBridgeHandler;
private Integer zoneID;
private String currentChannelID;
private Float currentValue = 0f;
private final Float step = 1f;
// check zoneID error codes
public static final int ZONE_ID_NOT_EXISTS = -1;
public static final int ZONE_ID_NOT_SET = -2;
public static final int BRIDGE_IS_NULL = -3;
/**
* Creates a new {@link ZoneTemperatureControlHandler}.
*
* @param thing must not be null
*/
public ZoneTemperatureControlHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing DeviceHandler.");
if (getConfig().get(DigitalSTROMBindingConstants.ZONE_ID) != null) {
final Bridge bridge = getBridge();
if (bridge != null) {
bridgeStatusChanged(bridge.getStatusInfo());
} else {
// Set status to OFFLINE, if no bridge is available e.g. because the bridge has been removed and the
// Thing was reinitialized.
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "zoneID is missing");
}
}
/**
* Returns the configured zoneID of the given {@link Configuration}. If the zoneID does't exist or can't be checked
* {@link #ZONE_ID_NOT_EXISTS}, {@link #ZONE_ID_NOT_SET} or {@link #BRIDGE_IS_NULL} will be returned.
*
* @param config the {@link Configuration} to be checked
* @param bridge the responsible {@link BridgeHandler}
* @return zoneID the existing dS zoneID or a error constant
*/
public static int getZoneID(Configuration config, BridgeHandler bridge) {
if (config == null || config.get(DigitalSTROMBindingConstants.ZONE_ID) == null) {
return ZONE_ID_NOT_SET;
}
if (bridge == null) {
return BRIDGE_IS_NULL;
}
String configZoneID = config.get(DigitalSTROMBindingConstants.ZONE_ID).toString();
int zoneID;
StructureManager strucMan = bridge.getStructureManager();
if (strucMan != null) {
try {
zoneID = Integer.parseInt(configZoneID);
if (!strucMan.checkZoneID(zoneID)) {
zoneID = ZONE_ID_NOT_EXISTS;
}
} catch (NumberFormatException e) {
zoneID = strucMan.getZoneId(configZoneID);
}
return zoneID;
}
return ZONE_ID_NOT_EXISTS;
}
@Override
public void dispose() {
logger.debug("Handler disposed... unregister DeviceStatusListener");
if (zoneID != null) {
if (dssBridgeHandler != null) {
dssBridgeHandler.unregisterTemperatureControlStatusListener(this);
}
temperatureSensorTransmitter = null;
}
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
int tempZoneID = getZoneID(getConfig(), getDssBridgeHandler());
if (tempZoneID == ZONE_ID_NOT_EXISTS) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Configured zone '" + getConfig().get(DigitalSTROMBindingConstants.ZONE_ID)
+ "' does not exist, please check the configuration.");
} else {
this.zoneID = tempZoneID;
}
if (zoneID != null) {
if (getDssBridgeHandler() != null && temperatureSensorTransmitter == null) {
dssBridgeHandler.registerTemperatureControlStatusListener(this);
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"waiting for listener registration");
} else {
updateStatus(ThingStatus.ONLINE);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No zoneID is set!");
}
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
}
logger.debug("Set status to {}", getThing().getStatusInfo());
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
BridgeHandler dssBridgeHandler = getDssBridgeHandler();
if (dssBridgeHandler == null) {
logger.debug("BridgeHandler not found. Cannot handle command without bridge.");
return;
}
if (temperatureSensorTransmitter == null && zoneID != null) {
logger.debug(
"Device not known on TemperationControlManager or temperatureSensorTransreciver is not registerd. Cannot handle command.");
return;
}
if (channelUID.getId().equals(currentChannelID)) {
if (command instanceof PercentType || command instanceof DecimalType) {
sendCommandAndUpdateChannel(((DecimalType) command).floatValue());
} else if (command instanceof OnOffType) {
if (OnOffType.ON.equals(command)) {
if (isTemperature()) {
sendCommandAndUpdateChannel(TemperatureControlSensorTransmitter.MAX_TEMP);
} else {
sendCommandAndUpdateChannel(TemperatureControlSensorTransmitter.MAX_CONTROLL_VALUE);
}
} else {
if (isTemperature()) {
sendCommandAndUpdateChannel(0f);
} else {
sendCommandAndUpdateChannel(TemperatureControlSensorTransmitter.MIN_CONTROLL_VALUE);
}
}
} else if (command instanceof IncreaseDecreaseType) {
if (IncreaseDecreaseType.INCREASE.equals(command)) {
sendCommandAndUpdateChannel(currentValue + step);
} else {
sendCommandAndUpdateChannel(currentValue - step);
}
}
} else {
logger.debug("Command sent to an unknown channel id: {}", channelUID);
}
}
private boolean isTemperature() {
return currentChannelID.contains(DsChannelTypeProvider.TEMPERATURE_CONTROLLED);
}
private void sendCommandAndUpdateChannel(Float newValue) {
if (isTemperature()) {
if (temperatureSensorTransmitter.pushTargetTemperature(zoneID, newValue)) {
currentValue = newValue;
updateState(currentChannelID, new DecimalType(newValue));
}
} else {
if (temperatureSensorTransmitter.pushControlValue(zoneID, newValue)) {
currentValue = newValue;
updateState(currentChannelID, new PercentType(newValue.intValue()));
}
}
}
private synchronized BridgeHandler getDssBridgeHandler() {
if (this.dssBridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bride cannot be found");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof BridgeHandler) {
dssBridgeHandler = (BridgeHandler) handler;
} else {
return null;
}
}
return dssBridgeHandler;
}
@Override
public synchronized void configChanged(TemperatureControlStatus tempControlStatus) {
if (tempControlStatus != null && tempControlStatus.isNotSetOff()) {
ControlModes controlMode = ControlModes.getControlMode(tempControlStatus.getControlMode());
ControlStates controlState = ControlStates.getControlState(tempControlStatus.getControlState());
if (controlMode != null && controlState != null) {
logger.debug("config changed: {}", tempControlStatus.toString());
if (controlMode.equals(ControlModes.OFF) && currentChannelID != null) {
currentChannelID = null;
loadChannel();
} else if (controlMode.equals(ControlModes.PID_CONTROL)
&& (currentChannelID == null
|| !currentChannelID.contains(DsChannelTypeProvider.TEMPERATURE_CONTROLLED))
&& !controlState.equals(ControlStates.EMERGENCY)) {
currentChannelID = DsChannelTypeProvider.getOutputChannelTypeID(FunctionalColorGroupEnum.BLUE,
OutputModeEnum.TEMPRETURE_PWM);
loadChannel();
currentValue = tempControlStatus.getNominalValue();
updateState(currentChannelID, new DecimalType(currentValue.doubleValue()));
} else if (!controlMode.equals(ControlModes.PID_CONTROL) && !controlMode.equals(ControlModes.OFF)) {
currentChannelID = DsChannelTypeProvider.getOutputChannelTypeID(FunctionalColorGroupEnum.BLUE,
OutputModeEnum.HEATING_PWM);
loadChannel();
currentValue = tempControlStatus.getControlValue();
updateState(currentChannelID, new PercentType(fixPercent(currentValue.intValue())));
if (controlState.equals(ControlStates.EMERGENCY)) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"The communication with temperation sensor fails. Temperature control state emergency (temperature control though the control value) is active.");
}
}
Map<String, String> properties = editProperties();
properties.put("controlDSUID", tempControlStatus.getControlDSUID());
properties.put("controlMode", controlMode.getKey());
properties.put("controlState", controlState.getKey());
updateProperties(properties);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"digitalSTROM temperature control is for this zone not configured in.");
}
}
private synchronized void loadChannel() {
List<Channel> newChannelList = new ArrayList<>(1);
if (currentChannelID != null) {
newChannelList.add(ChannelBuilder
.create(new ChannelUID(this.getThing().getUID(), currentChannelID),
DsChannelTypeProvider.getItemType(currentChannelID))
.withType(new ChannelTypeUID(BINDING_ID, currentChannelID)).build());
}
ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(newChannelList);
updateThing(thingBuilder.build());
logger.debug("load channel: {} with item: {}", currentChannelID,
DsChannelTypeProvider.getItemType(currentChannelID));
}
@Override
public synchronized void onTargetTemperatureChanged(Float newValue) {
if (isTemperature()) {
updateState(currentChannelID, new DecimalType(newValue));
}
}
@Override
public synchronized void onControlValueChanged(Integer newValue) {
if (!isTemperature()) {
updateState(currentChannelID, new PercentType(fixPercent(newValue)));
}
}
private int fixPercent(int value) {
return value < 0 ? 0 : value > 100 ? 100 : value;
}
@Override
public void registerTemperatureSensorTransmitter(
TemperatureControlSensorTransmitter temperatureSensorTransreciver) {
updateStatus(ThingStatus.ONLINE);
this.temperatureSensorTransmitter = temperatureSensorTransreciver;
}
@Override
public Integer getTemperationControlStatusListenrID() {
return zoneID;
}
}

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.digitalstrom.internal.lib;
/**
* The {@link GeneralLibConstance} contains all relevant library constants.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class GeneralLibConstance {
/**
* digitalSTROMs broadcast zone id.
*/
public static final int BROADCAST_ZONE_GROUP_ID = 0;
/**
* digitalSTROMs broadcast zone string by query response.
*/
public static final String QUERY_BROADCAST_ZONE_STRING = "zone0";
/**
* Scene-Array index for the scene value.
*/
public static final int SCENE_ARRAY_INDEX_VALUE = 0;
/**
* Scene-Array index for the scene value.
*/
public static final int SCENE_ARRAY_INDEX_ANGLE = 1;
/**
* The highest read out priority for
* {@link org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob}s.
*/
public static final int HIGHEST_READ_OUT_PRIORITY = 0;
}

View File

@@ -0,0 +1,61 @@
/**
* 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.digitalstrom.internal.lib.climate;
/**
* The {@link TemperatureControlSensorTransmitter} can be implement by subclasses to implement a
* transmitter which can be used to push the target temperature or control value to a digitalSTROM zone.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public interface TemperatureControlSensorTransmitter {
/**
* Maximal temperature, which can be set as target temperature in digitalSTROM.
*/
static float MAX_TEMP = 50f;
/**
* Minimal temperature, which can be set as target temperature in digitalSTROM.
*/
static float MIN_TEMP = -43.15f;
/**
* Maximal control value, which can be set as target temperature in digitalSTROM.
*/
static float MAX_CONTROLL_VALUE = 100f;
/**
* Minimal control value, which can be set as target temperature in digitalSTROM.
*/
static float MIN_CONTROLL_VALUE = 0f;
/**
* Pushes a new target temperature to a digitalSTROM zone.
*
* @param zoneID (must not be null)
* @param newValue (must not be null)
* @return true, if the push was successfully
*/
boolean pushTargetTemperature(Integer zoneID, Float newValue);
/**
* Pushes a new control value to a digitalSTROM zone.
*
* @param zoneID (must not be null)
* @param newValue (must not be null)
* @return true, if the push was successfully
*/
boolean pushControlValue(Integer zoneID, Float newValue);
}

View File

@@ -0,0 +1,76 @@
/**
* 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.digitalstrom.internal.lib.climate.constants;
/**
* The {@link ControlModes} contains all digitalSTROM heating control modes.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public enum ControlModes {
OFF((short) 0, "off"),
PID_CONTROL((short) 1, "pid-control"),
ZONE_FOLLOWER((short) 2, "zone-follower"),
FIXED_VALUE((short) 3, "fixed-value"),
MANUAL((short) 4, "manual");
private final Short id;
private final String key;
private static final ControlModes[] CONTROL_MODES = new ControlModes[ControlModes.values().length];
static {
for (ControlModes controlMode : ControlModes.values()) {
CONTROL_MODES[controlMode.id] = controlMode;
}
}
private ControlModes(short id, String key) {
this.id = id;
this.key = key;
}
/**
* Returns the key of the operation mode.
*
* @return key
*/
public String getKey() {
return key;
}
/**
* Returns the ID of the operation mode.
*
* @return ID
*/
public Short getID() {
return id;
}
/**
* Returns the {@link ControlModes} of the given control mode id.
*
* @param id of the control mode
* @return control mode
*/
public static ControlModes getControlMode(short id) {
try {
return CONTROL_MODES[id];
} catch (IndexOutOfBoundsException e) {
return null;
}
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.digitalstrom.internal.lib.climate.constants;
/**
* The {@link ControlStates} contains all digitalSTROM heating control states.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public enum ControlStates {
INTERNAL((short) 0, "internal"),
EXTERNAL((short) 1, "external"),
EXBACKUP((short) 2, "exbackup"),
EMERGENCY((short) 3, "emergency");
private final Short id;
private final String key;
private static final ControlStates[] CONTROL_STATES = new ControlStates[ControlStates.values().length];
static {
for (ControlStates controlState : ControlStates.values()) {
CONTROL_STATES[controlState.id] = controlState;
}
}
private ControlStates(short id, String key) {
this.id = id;
this.key = key;
}
/**
* Returns the key of the operation mode.
*
* @return key
*/
public String getKey() {
return key;
}
/**
* Returns the ID of the operation mode.
*
* @return ID
*/
public Short getID() {
return id;
}
/**
* Returns the {@link ControlStates} of the given control state id.
*
* @param id of the control state
* @return control state
*/
public static ControlStates getControlState(short id) {
try {
return CONTROL_STATES[id];
} catch (IndexOutOfBoundsException e) {
return null;
}
}
}

View File

@@ -0,0 +1,79 @@
/**
* 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.digitalstrom.internal.lib.climate.constants;
/**
* The {@link OperationModes} contains all digitalSTROM heating operation states.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public enum OperationModes {
OFF((short) 0, "Off"),
COMFORT((short) 1, "Comfort"),
ECONEMY((short) 2, "Econemy"),
NOT_USED((short) 3, "NotUsed"),
NIGHT((short) 4, "Night"),
HOLLYDAY((short) 5, "Holliday"),
COOLING((short) 6, "Cooling"),
COOLING_OFF((short) 7, "CoolingOff");
private final Short id;
private final String key;
private static final OperationModes[] OPERATION_MODES = new OperationModes[OperationModes.values().length];
static {
for (OperationModes operationMode : OperationModes.values()) {
OPERATION_MODES[operationMode.id] = operationMode;
}
}
/**
* Returns the {@link OperationModes} of the given operation mode id.
*
* @param id of the operation mode
* @return operation mode
*/
public static OperationModes getOperationMode(short id) {
try {
return OPERATION_MODES[id];
} catch (IndexOutOfBoundsException e) {
return null;
}
}
private OperationModes(short id, String key) {
this.id = id;
this.key = key;
}
/**
* Returns the key of the operation mode.
*
* @return key
*/
public String getKey() {
return key;
}
/**
* Returns the ID of the operation mode.
*
* @return ID
*/
public Short getID() {
return id;
}
}

View File

@@ -0,0 +1,110 @@
/**
* 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.digitalstrom.internal.lib.climate.datatypes;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
/**
* The {@link AssignSensorType} assigns a sensor type of a zone to the dSUID of the sensor-device.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class AssignSensorType {
private final SensorEnum sensorType;
private final String dsuid;
/**
* Create a new {@link AssignSensorType}.
*
* @param sensorType must not be null
* @param dSUID must not be null
*/
public AssignSensorType(SensorEnum sensorType, String dSUID) {
this.sensorType = sensorType;
dsuid = dSUID;
}
/**
* Returns the sensor type as {@link SensorEnum}.
*
* @return the sensor type
*/
public SensorEnum getSensorType() {
return sensorType;
}
/**
* Returns the dSUID of the assign sensor-device.
*
* @return the dSUID
*/
public String getDSUID() {
return dsuid;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "AssignSensorType [SENSOR_TYPE=" + sensorType + ", dSUID=" + dsuid + "]";
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dsuid == null) ? 0 : dsuid.hashCode());
result = prime * result + ((sensorType == null) ? 0 : sensorType.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AssignSensorType)) {
return false;
}
AssignSensorType other = (AssignSensorType) obj;
if (dsuid == null) {
if (other.dsuid != null) {
return false;
}
} else if (!dsuid.equals(other.dsuid)) {
return false;
}
if (sensorType != other.sensorType) {
return false;
}
return true;
}
}

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.digitalstrom.internal.lib.climate.datatypes;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link CachedSensorValue} holds a read sensor value. For that the {@link CachedSensorValue} includes the sensor
* type, sensor value and a the timestamp.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class CachedSensorValue {
private final Logger logger = LoggerFactory.getLogger(CachedSensorValue.class);
private final SensorEnum sensorType;
private final Float sensorValue;
private final String timestamp;
/**
* Create a new {@link CachedSensorValue}.
*
* @param sensorType must not be null
* @param sensorValue must not be null
* @param timestamp must not be null
*/
public CachedSensorValue(SensorEnum sensorType, Float sensorValue, String timestamp) {
this.sensorType = sensorType;
this.sensorValue = sensorValue;
this.timestamp = timestamp;
}
/**
* Returns the sensor type as {@link SensorEnum}.
*
* @return the sensorType
*/
public SensorEnum getSensorType() {
return sensorType;
}
/**
* Returns the sensor value.
*
* @return the sensorValue
*/
public Float getSensorValue() {
return sensorValue;
}
/**
* Returns the timestamp as {@link String}.
*
* @return the timestamp
*/
public String getTimestamp() {
return timestamp;
}
/**
* Returns the time stamp as {@link Date}.
*
* @return the timeStamp
*/
public Date getTimestampAsDate() {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SS");
try {
return formatter.parse(timestamp);
} catch (ParseException e) {
logger.error("A ParseException occurred by parsing date string: {}", timestamp, e);
}
return null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "CachedSensorValue [SENSOR_TYPE=" + sensorType + ", SENSOR_VALUE=" + sensorValue + ", TIMESTAMP="
+ timestamp + "]";
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((sensorType == null) ? 0 : sensorType.hashCode());
result = prime * result + ((sensorValue == null) ? 0 : sensorValue.hashCode());
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof CachedSensorValue)) {
return false;
}
CachedSensorValue other = (CachedSensorValue) obj;
if (sensorType != other.sensorType) {
return false;
}
if (sensorValue == null) {
if (other.sensorValue != null) {
return false;
}
} else if (!sensorValue.equals(other.sensorValue)) {
return false;
}
if (timestamp == null) {
if (other.timestamp != null) {
return false;
}
} else if (!timestamp.equals(other.timestamp)) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,155 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer;
import java.util.LinkedList;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.climate.datatypes.CachedSensorValue;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import com.google.gson.JsonObject;
/**
* The {@link BaseSensorValues} is a base implementation of sensor response of the digitalSTROM-json-API.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public abstract class BaseSensorValues {
private List<CachedSensorValue> sensorValues;
/**
* Adds a sensor value through the digitalSTROM-API response as {@link JsonObject}. The boolean outdoor has to be
* set to indicate that it is an outdoor or indoor value (needed to choose the right sensor type).
*
* @param jObject must not be null
* @param outdoor (true = outdoor; false = indoor)
*/
protected void addSensorValue(JsonObject jObject, boolean outdoor) {
if (jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE.getKey()) != null) {
SensorEnum sensorType = SensorEnum.TEMPERATURE_INDOORS;
if (outdoor) {
sensorType = SensorEnum.TEMPERATURE_OUTDOORS;
}
addSensorValue(new CachedSensorValue(sensorType,
jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE.getKey()).getAsFloat(),
jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE_TIME.getKey()).getAsString()));
}
if (jObject.get(JSONApiResponseKeysEnum.HUMIDITY_VALUE.getKey()) != null) {
SensorEnum sensorType = SensorEnum.RELATIVE_HUMIDITY_INDOORS;
if (outdoor) {
sensorType = SensorEnum.RELATIVE_HUMIDITY_OUTDOORS;
}
addSensorValue(new CachedSensorValue(sensorType,
jObject.get(JSONApiResponseKeysEnum.HUMIDITY_VALUE.getKey()).getAsFloat(),
jObject.get(JSONApiResponseKeysEnum.HUMIDITY_VALUE_TIME.getKey()).getAsString()));
}
if (jObject.get(JSONApiResponseKeysEnum.CO2_CONCENTRATION_VALUE.getKey()) != null) {
addSensorValue(new CachedSensorValue(SensorEnum.CARBON_DIOXIDE,
jObject.get(JSONApiResponseKeysEnum.CO2_CONCENTRATION_VALUE.getKey()).getAsFloat(),
jObject.get(JSONApiResponseKeysEnum.CO2_CONCENTRATION_VALUE_TIME.getKey()).getAsString()));
}
if (jObject.get(JSONApiResponseKeysEnum.BRIGHTNESS_VALUE.getKey()) != null) {
SensorEnum sensorType = SensorEnum.BRIGHTNESS_INDOORS;
if (outdoor) {
sensorType = SensorEnum.BRIGHTNESS_OUTDOORS;
}
addSensorValue(new CachedSensorValue(sensorType,
jObject.get(JSONApiResponseKeysEnum.BRIGHTNESS_VALUE.getKey()).getAsFloat(),
jObject.get(JSONApiResponseKeysEnum.BRIGHTNESS_VALUE_TIME.getKey()).getAsString()));
}
}
private void addSensorValue(CachedSensorValue cachedSensorValue) {
if (sensorValues == null) {
sensorValues = new LinkedList<>();
sensorValues.add(cachedSensorValue);
} else {
sensorValues.add(cachedSensorValue);
}
}
/**
* Returns the available sensor types.
*
* @return available sensor types
*/
public List<SensorEnum> getAvailableSensorTypes() {
List<SensorEnum> sensorTypes = new LinkedList<>();
if (sensorValues != null) {
for (CachedSensorValue cSensorValue : sensorValues) {
sensorTypes.add(cSensorValue.getSensorType());
}
}
return sensorTypes;
}
/**
* Returns the {@link CachedSensorValue}'s as {@link List}.
*
* @return list of {@link CachedSensorValue}'s
*/
public List<CachedSensorValue> getCachedSensorValues() {
return sensorValues;
}
/**
* Returns the {@link CachedSensorValue} of the given sensor type or null, if no {@link CachedSensorValue} for the
* given sensor type exists.
*
* @param sensorType can be null
* @return the {@link CachedSensorValue} of the given sensorType or null
*/
public CachedSensorValue getCachedSensorValue(SensorEnum sensorType) {
if (sensorType != null && sensorValues != null) {
for (CachedSensorValue cSensorValue : sensorValues) {
if (cSensorValue.getSensorType().equals(sensorType)) {
return cSensorValue;
}
}
}
return null;
}
/**
* Returns true, if the given sensor type exist, otherwise false.
*
* @param sensorType can be null
* @return true, if the given sensor type exist, otherwise false
*/
public boolean existSensorValue(SensorEnum sensorType) {
return getCachedSensorValue(sensorType) != null;
}
/**
* Returns true, is sensor values exists, otherwise false.
*
* @return true, if sensor values exists, otherwise false
*/
public boolean existSensorValues() {
return sensorValues != null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "SensorValues [sensorValues=" + sensorValues + "]";
}
}

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.digitalstrom.internal.lib.climate.jsonresponsecontainer;
import org.openhab.binding.digitalstrom.internal.lib.climate.constants.ControlModes;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonObject;
/**
* The {@link BaseTemperatureControl} is a base implementation for temperature controls status and configurations. For
* that it extends the {@link BaseZoneIdentifier}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public abstract class BaseTemperatureControl extends BaseZoneIdentifier {
protected String controlDSUID;
protected Short controlMode;
/**
* Creates a new {@link BaseTemperatureControl} through the {@link JsonObject} which will be returned by an zone
* call.<br>
* Because zone calls do not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public BaseTemperatureControl(JsonObject jObject, Integer zoneID, String zoneName) {
super(zoneID, zoneName);
init(jObject);
}
/**
* Creates a new {@link BaseTemperatureControl} through the {@link JsonObject} which will be returned by an
* apartment call.
*
* @param jObject must not be null
*/
public BaseTemperatureControl(JsonObject jObject) {
super(jObject);
init(jObject);
}
private void init(JsonObject jObject) {
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_MODE.getKey()) != null) {
this.controlMode = jObject.get(JSONApiResponseKeysEnum.CONTROL_MODE.getKey()).getAsShort();
}
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_DSUID.getKey()) != null) {
this.controlDSUID = jObject.get(JSONApiResponseKeysEnum.CONTROL_DSUID.getKey()).getAsString();
}
}
/**
* Returns the dSUID of the control sensor for heating of the zone.
*
* @return the controlDSUID
*/
public String getControlDSUID() {
return controlDSUID;
}
/**
* Returns controlMode for heating of the zone.
*
* @return the controlMode
*/
public Short getControlMode() {
return controlMode;
}
/**
* Returns true, if heating for this zone is not set off (set {@link ControlModes} = {@link ControlModes#OFF}),
* otherwise false.
*
* @return true, if the set {@link ControlModes} is not {@link ControlModes#OFF}
*/
public Boolean isNotSetOff() {
return !ControlModes.OFF.getID().equals(controlMode);
}
}

View File

@@ -0,0 +1,65 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonObject;
/**
* The {@link BaseZoneIdentifier} is a base implementation of the {@link ZoneIdentifier}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public abstract class BaseZoneIdentifier implements ZoneIdentifier {
protected Integer zoneID;
protected String zoneName;
/**
* Creates a new {@link BaseZoneIdentifier} with an zone id and zone name.
*
* @param zoneID must not be null
* @param zoneName can be null
*/
public BaseZoneIdentifier(Integer zoneID, String zoneName) {
this.zoneID = zoneID;
this.zoneName = zoneName;
}
/**
* Creates a new {@link BaseZoneIdentifier} through the {@link JsonObject} of the response of an digitalSTROM-API
* apartment call.
*
* @param jObject must not be null
*/
public BaseZoneIdentifier(JsonObject jObject) {
if (jObject.get(JSONApiResponseKeysEnum.ID.getKey()) != null) {
this.zoneID = jObject.get(JSONApiResponseKeysEnum.ID.getKey()).getAsInt();
}
if (jObject.get(JSONApiResponseKeysEnum.NAME.getKey()) != null) {
this.zoneName = jObject.get(JSONApiResponseKeysEnum.NAME.getKey()).getAsString();
}
}
@Override
public Integer getZoneID() {
return zoneID;
}
@Override
public String getZoneName() {
return zoneName;
}
}

View File

@@ -0,0 +1,36 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer;
/**
* The {@link ZoneIdentifier} can be implement to identify a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface ZoneIdentifier {
/**
* Returns the zoneID of this zone.
*
* @return the zoneID
*/
Integer getZoneID();
/**
* Returns the zoneName of this zone.
*
* @return the zoneName
*/
String getZoneName();
}

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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.climate.datatypes.AssignSensorType;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseZoneIdentifier;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* The {@link AssignedSensors} acts as container for the digitalSTROM json-method <i>getAssignedSensors</i>. So the
* {@link AssignedSensors} contains all {@link AssignSensorType}s of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class AssignedSensors extends BaseZoneIdentifier {
private List<AssignSensorType> sensors;
/**
* Creates a new {@link AssignedSensors} through the {@link JsonObject} that will be returned by an apartment call.
*
* @param jObject must not be null
*/
public AssignedSensors(JsonObject jObject) {
super(jObject);
init(jObject);
}
/**
* Creates a new {@link AssignedSensors} through the {@link JsonObject} which will be returned by an zone call.
* Because of zone calls does not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public AssignedSensors(JsonObject jObject, Integer zoneID, String zoneName) {
super(zoneID, zoneName);
init(jObject);
}
private void init(JsonObject jObject) {
if (jObject.get(JSONApiResponseKeysEnum.SENSORS.getKey()) != null
&& jObject.get(JSONApiResponseKeysEnum.SENSORS.getKey()).isJsonArray()) {
JsonArray jArray = jObject.get(JSONApiResponseKeysEnum.SENSORS.getKey()).getAsJsonArray();
if (jArray.size() != 0) {
sensors = new LinkedList<>();
Iterator<JsonElement> iter = jArray.iterator();
while (iter.hasNext()) {
JsonObject assignedSensor = iter.next().getAsJsonObject();
Short sensorType = null;
String meterDSUID = null;
if (assignedSensor.get(JSONApiResponseKeysEnum.SENSOR_TYPE.getKey()) != null) {
sensorType = assignedSensor.get(JSONApiResponseKeysEnum.SENSOR_TYPE.getKey()).getAsShort();
}
if (assignedSensor.get(JSONApiResponseKeysEnum.DSUID_LOWER_CASE.getKey()) != null) {
meterDSUID = assignedSensor.get(JSONApiResponseKeysEnum.DSUID_LOWER_CASE.getKey())
.getAsString();
}
sensors.add(new AssignSensorType(SensorEnum.getSensor(sensorType), meterDSUID));
}
}
}
}
/**
* Returns a {@link List} of all assigned sensor types as {@link SensorEnum} of a zone.
*
* @return list of all assigned sensor types
*/
public List<SensorEnum> getAssignedZoneSensorTypes() {
List<SensorEnum> sensorTypes = new LinkedList<>();
if (sensors != null) {
for (AssignSensorType aSensorValue : sensors) {
sensorTypes.add(aSensorValue.getSensorType());
}
}
return sensorTypes;
}
/**
* Returns a {@link List} of all {@link AssignSensorType} of a zone.
*
* @return list of {@link AssignSensorType}s
*/
public List<AssignSensorType> getAssignedSensorTypes() {
return sensors;
}
/**
* Returns the {@link AssignSensorType} of the given sensorType or null, if the given sensorType does not exist.
*
* @param sensorType can be null
* @return the {@link AssignSensorType} of the given sensorType or null
*/
public AssignSensorType getAssignedSensorType(SensorEnum sensorType) {
if (sensorType != null && sensors != null) {
for (AssignSensorType aSensorValue : sensors) {
if (aSensorValue.getSensorType().equals(sensorType)) {
return aSensorValue;
}
}
}
return null;
}
/**
* Returns true, if the given sensorType exists at the zone, otherwise false.
*
* @param sensorType can be null
* @return true, if sensorType exists, otherwise false
*/
public boolean existSensorType(SensorEnum sensorType) {
return getAssignedSensorType(sensorType) != null;
}
/**
* Returns true, if sensors exists at the zone, otherwise false.
*
* @return true, if sensors exists, otherwise false
*/
public boolean existsAssignedSensors() {
return sensors != null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "AssignedSensors [sensors=" + sensors + "]";
}
}

View File

@@ -0,0 +1,99 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import java.util.Iterator;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseSensorValues;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.ZoneIdentifier;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* The {@link SensorValues} acts as container for the digitalSTROM json-method <i>getSensorValues</i>. So the
* {@link SensorValues} contains all {@link CachedSensorValue}s of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class SensorValues extends BaseSensorValues implements ZoneIdentifier {
private Integer zoneID;
private String zoneName;
/**
* Creates a new {@link SensorValues} through the {@link JsonObject} that will be returned by an apartment call.
*
* @param jObject must not be null
*/
public SensorValues(JsonObject jObject) {
if (jObject.get(JSONApiResponseKeysEnum.ID.getKey()) != null) {
this.zoneID = jObject.get(JSONApiResponseKeysEnum.ID.getKey()).getAsInt();
}
if (jObject.get(JSONApiResponseKeysEnum.NAME.getKey()) != null) {
this.zoneName = jObject.get(JSONApiResponseKeysEnum.NAME.getKey()).getAsString();
}
init(jObject);
}
/**
* Creates a new {@link SensorValues} through the {@link JsonObject} which will be returned by an zone call.
* Because of zone calls does not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public SensorValues(JsonObject jObject, Integer zoneID, String zoneName) {
this.zoneID = zoneID;
this.zoneName = zoneName;
init(jObject);
}
private void init(JsonObject jObject) {
if (jObject.get(JSONApiResponseKeysEnum.VALUES.getKey()).isJsonArray()) {
JsonArray jArray = jObject.get(JSONApiResponseKeysEnum.VALUES.getKey()).getAsJsonArray();
if (jArray.size() != 0) {
Iterator<JsonElement> iter = jArray.iterator();
while (iter.hasNext()) {
JsonObject cachedSensorValue = iter.next().getAsJsonObject();
super.addSensorValue(cachedSensorValue, false);
}
}
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "SensorValues [zoneID=" + zoneID + ", zoneName=" + zoneName + ", " + super.toString() + "]";
}
@Override
public Integer getZoneID() {
return zoneID;
}
@Override
public String getZoneName() {
return zoneName;
}
}

View File

@@ -0,0 +1,260 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseTemperatureControl;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonObject;
/**
* The {@link TemperatureControlConfig} acts as container for the digitalSTROM json-method
* <i>getTemperatureControlConfig</i>. So the {@link TemperatureControlConfig} contains all heating control
* configurations of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class TemperatureControlConfig extends BaseTemperatureControl {
private Integer referenceZone;
private Float ctrlOffset;
private Float manualValue;
private Float emergencyValue;
private Float ctrlKp;
private Float ctrlTs;
private Float ctrlTi;
private Float ctrlKd;
private Float ctrlImin;
private Float ctrlImax;
private Float ctrlYmin;
private Float ctrlYmax;
private Boolean ctrlAntiWindUp;
private Boolean ctrlKeepFloorWarm;
/**
* Creates a new {@link TemperatureControlConfig} through the {@link JsonObject} which will be returned by an
* apartment call.
*
* @param jObject must not be null
*/
public TemperatureControlConfig(JsonObject jObject) {
super(jObject);
init(jObject);
}
/**
* Creates a new {@link TemperatureControlConfig} through the {@link JsonObject} which will be returned by an zone
* call.<br>
* Because of zone calls does not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public TemperatureControlConfig(JsonObject jObject, Integer zoneID, String zoneName) {
super(jObject, zoneID, zoneName);
init(jObject);
}
private void init(JsonObject jObject) {
if (isNotSetOff()) {
if (controlMode == 1) {
if (jObject.get(JSONApiResponseKeysEnum.EMERGENCY_VALUE.getKey()) != null) {
this.emergencyValue = jObject.get(JSONApiResponseKeysEnum.EMERGENCY_VALUE.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_KP.getKey()) != null) {
this.ctrlKp = jObject.get(JSONApiResponseKeysEnum.CTRL_KP.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_TS.getKey()) != null) {
this.ctrlTs = jObject.get(JSONApiResponseKeysEnum.CTRL_TS.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_TI.getKey()) != null) {
this.ctrlTi = jObject.get(JSONApiResponseKeysEnum.CTRL_TI.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_KD.getKey()) != null) {
this.ctrlKd = jObject.get(JSONApiResponseKeysEnum.CTRL_KD.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_MIN.getKey()) != null) {
this.ctrlImin = jObject.get(JSONApiResponseKeysEnum.CTRL_MIN.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_MAX.getKey()) != null) {
this.ctrlImax = jObject.get(JSONApiResponseKeysEnum.CTRL_MAX.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_Y_MIN.getKey()) != null) {
this.ctrlYmin = jObject.get(JSONApiResponseKeysEnum.CTRL_Y_MIN.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_Y_MAX.getKey()) != null) {
this.ctrlYmax = jObject.get(JSONApiResponseKeysEnum.CTRL_Y_MAX.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_KEEP_FLOOR_WARM.getKey()) != null) {
this.ctrlKeepFloorWarm = jObject.get(JSONApiResponseKeysEnum.CTRL_KEEP_FLOOR_WARM.getKey())
.getAsBoolean();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_ANTI_WIND_UP.getKey()) != null) {
this.ctrlAntiWindUp = jObject.get(JSONApiResponseKeysEnum.CTRL_ANTI_WIND_UP.getKey())
.getAsBoolean();
}
}
if (controlMode == 2) {
if (jObject.get(JSONApiResponseKeysEnum.REFERENCE_ZONE.getKey()) != null) {
this.referenceZone = jObject.get(JSONApiResponseKeysEnum.REFERENCE_ZONE.getKey()).getAsInt();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_OFFSET.getKey()) != null) {
this.ctrlOffset = jObject.get(JSONApiResponseKeysEnum.CTRL_OFFSET.getKey()).getAsFloat();
}
}
}
}
/**
* Returns the refenceZone, if control-mode is {@link ControlModes#ZONE_FOLLOWER}, otherwise null.
*
* @return the referenceZone
*/
public Integer getReferenceZone() {
return referenceZone;
}
/**
* Returns the ctrlOffset, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlOffset
*/
public Float getCtrlOffset() {
return ctrlOffset;
}
/**
* Returns the manualValue, if control-mode is {@link ControlModes#MANUAL}, otherwise null.
*
* @return the manualValue
*/
public Float getManualValue() {
return manualValue;
}
/**
* Returns the emergencyValue, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the emergencyValue
*/
public Float getEmergencyValue() {
return emergencyValue;
}
/**
* Returns the ctrlKp, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlKp
*/
public Float getCtrlKp() {
return ctrlKp;
}
/**
* Returns the ctrlTs, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlTs
*/
public Float getCtrlTs() {
return ctrlTs;
}
/**
* Returns the ctrlTi, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlTi
*/
public Float getCtrlTi() {
return ctrlTi;
}
/**
* Returns the ctrlKd, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlKd
*/
public Float getCtrlKd() {
return ctrlKd;
}
/**
* Returns the ctrlImin, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlImin
*/
public Float getCtrlImin() {
return ctrlImin;
}
/**
* Returns the ctrlImax, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlImax
*/
public Float getCtrlImax() {
return ctrlImax;
}
/**
* Returns the ctrlYmin, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlYmin
*/
public Float getCtrlYmin() {
return ctrlYmin;
}
/**
* Returns the ctrlYmax, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlYmax
*/
public Float getCtrlYmax() {
return ctrlYmax;
}
/**
* Returns the ctrlAntiWindUp, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlAntiWindUp
*/
public Boolean getCtrlAntiWindUp() {
return ctrlAntiWindUp;
}
/**
* Returns the ctrlKeepFloorWarm, if control-mode is {@link ControlModes#PID_CONTROL}, otherwise null.
*
* @return the ctrlKeepFloorWarm
*/
public Boolean getCtrlKeepFloorWarm() {
return ctrlKeepFloorWarm;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TemperatureControlConfig [referenceZone=" + referenceZone + ", ctrlOffset=" + ctrlOffset
+ ", manualValue=" + manualValue + ", emergencyValue=" + emergencyValue + ", ctrlKp=" + ctrlKp
+ ", ctrlTs=" + ctrlTs + ", ctrlTi=" + ctrlTi + ", ctrlKd=" + ctrlKd + ", ctrlImin=" + ctrlImin
+ ", ctrlImax=" + ctrlImax + ", ctrlYmin=" + ctrlYmin + ", ctrlYmax=" + ctrlYmax + ", ctrlAntiWindUp="
+ ctrlAntiWindUp + ", ctrlKeepFloorWarm=" + ctrlKeepFloorWarm + "]";
}
}

View File

@@ -0,0 +1,203 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseTemperatureControl;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonObject;
/**
* The {@link TemperatureControlInternals} acts as container for the digitalSTROM json-method
* <i>getTemperatureControlInternals</i>. So the {@link TemperatureControlInternals} contains all internal heating
* control configurations of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class TemperatureControlInternals extends BaseTemperatureControl {
private Short controlState;
private Float ctrlTRecent;
private Float ctrlTReference;
private Float ctrlTError;
private Float ctrlTErrorPrev;
private Float ctrlIntegral;
private Float ctrlYp;
private Float ctrlYi;
private Float ctrlYd;
private Float ctrlY;
private Short ctrlAntiWindUp;
/**
* Creates a new {@link TemperatureControlInternals} through the {@link JsonObject} which will be returned by an
* zone
* call.<br>
* Because of zone calls does not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public TemperatureControlInternals(JsonObject jObject, Integer zoneID, String zoneName) {
super(jObject, zoneID, zoneName);
if (isNotSetOff()) {
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_STATE.getKey()) != null) {
this.controlState = jObject.get(JSONApiResponseKeysEnum.CONTROL_STATE.getKey()).getAsShort();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_T_RECENT.getKey()) != null) {
this.ctrlTRecent = jObject.get(JSONApiResponseKeysEnum.CTRL_T_RECENT.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_T_REFERENCE.getKey()) != null) {
this.ctrlTReference = jObject.get(JSONApiResponseKeysEnum.CTRL_T_REFERENCE.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_T_ERROR.getKey()) != null) {
this.ctrlTError = jObject.get(JSONApiResponseKeysEnum.CTRL_T_ERROR.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_T_ERROR_PREV.getKey()) != null) {
this.ctrlTErrorPrev = jObject.get(JSONApiResponseKeysEnum.CTRL_T_ERROR_PREV.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_INTEGRAL.getKey()) != null) {
this.ctrlIntegral = jObject.get(JSONApiResponseKeysEnum.CTRL_INTEGRAL.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_YP.getKey()) != null) {
this.ctrlY = jObject.get(JSONApiResponseKeysEnum.CTRL_YP.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_YI.getKey()) != null) {
this.ctrlYi = jObject.get(JSONApiResponseKeysEnum.CTRL_YI.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_YD.getKey()) != null) {
this.ctrlYd = jObject.get(JSONApiResponseKeysEnum.CTRL_YD.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_Y.getKey()) != null) {
this.ctrlY = jObject.get(JSONApiResponseKeysEnum.CTRL_Y.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CTRL_ANTI_WIND_UP.getKey()) != null) {
this.ctrlAntiWindUp = jObject.get(JSONApiResponseKeysEnum.CTRL_ANTI_WIND_UP.getKey()).getAsShort();
}
}
}
/**
* Returns the controleState for heating of the zone.
*
* @return the controlState
*/
public Short getControlState() {
return controlState;
}
/**
* Returns the ctrlTRecent for heating of the zone.
*
* @return the ctrlTRecent
*/
public Float getCtrlTRecent() {
return ctrlTRecent;
}
/**
* Returns the ctrlTReference for heating of the zone.
*
* @return the ctrlTReference
*/
public Float getCtrlTReference() {
return ctrlTReference;
}
/**
* Returns the ctrlTError for heating of the zone.
*
* @return the ctrlTError
*/
public Float getCtrlTError() {
return ctrlTError;
}
/**
* Returns the ctrlTErrorPrev for heating of the zone.
*
* @return the ctrlTErrorPrev
*/
public Float getCtrlTErrorPrev() {
return ctrlTErrorPrev;
}
/**
* Returns the ctrlIntegral for heating of the zone.
*
* @return the ctrlIntegral
*/
public Float getCtrlIntegral() {
return ctrlIntegral;
}
/**
* Returns the ctrlYp for heating of the zone.
*
* @return the ctrlYp
*/
public Float getCtrlYp() {
return ctrlYp;
}
/**
* Returns the ctrlYi for heating of the zone.
*
* @return the ctrlYi
*/
public Float getCtrlYi() {
return ctrlYi;
}
/**
* Returns the ctrlYd for heating of the zone.
*
* @return the ctrlYd
*/
public Float getCtrlYd() {
return ctrlYd;
}
/**
* Returns the ctrlY for heating of the zone.
*
* @return the ctrlY
*/
public Float getCtrlY() {
return ctrlY;
}
/**
* Returns the ctrlAntiWindUp for heating of the zone.
*
* @return the ctrlAntiWindUp
*/
public Short getCtrlAntiWindUp() {
return ctrlAntiWindUp;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TemperatureControlInternals [controlState=" + controlState + ", ctrlTRecent=" + ctrlTRecent
+ ", ctrlTReference=" + ctrlTReference + ", ctrlTError=" + ctrlTError + ", ctrlTErrorPrev="
+ ctrlTErrorPrev + ", ctrlIntegral=" + ctrlIntegral + ", ctrlYp=" + ctrlYp + ", ctrlYi=" + ctrlYi
+ ", ctrlYd=" + ctrlYd + ", ctrlY=" + ctrlY + ", ctrlAntiWindUp=" + ctrlAntiWindUp + "]";
}
}

View File

@@ -0,0 +1,216 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseTemperatureControl;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonObject;
/**
* The {@link TemperatureControlStatus} acts as container for the digitalSTROM json-method
* <i>getTemperatureControlStatus</i>. So the {@link TemperatureControlStatus} contains all heating
* control status information of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class TemperatureControlStatus extends BaseTemperatureControl {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss");
private Short controlState;
private Short operationMode;
private Float temperature;
private String temperatureTime;
private Float nominalValue;
private String nominalValueTime;
private Float controlValue;
private String controlValueTime;
/**
* Creates a new {@link TemperatureControlStatus} through the {@link JsonObject} which will be returned by an
* apartment call.
*
* @param jObject must not be null
*/
public TemperatureControlStatus(JsonObject jObject) {
super(jObject);
init(jObject);
}
/**
* Creates a new {@link TemperatureControlStatus} through the {@link JsonObject} which will be returned by an zone
* call.<br>
* Because of zone calls does not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public TemperatureControlStatus(JsonObject jObject, Integer zoneID, String zoneName) {
super(jObject, zoneID, zoneName);
init(jObject);
}
private void init(JsonObject jObject) {
if (isNotSetOff()) {
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_STATE.getKey()) != null) {
this.controlState = jObject.get(JSONApiResponseKeysEnum.CONTROL_STATE.getKey()).getAsShort();
}
if (jObject.get(JSONApiResponseKeysEnum.OPERATION_MODE.getKey()) != null) {
this.operationMode = jObject.get(JSONApiResponseKeysEnum.OPERATION_MODE.getKey()).getAsShort();
}
if (jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE.getKey()) != null) {
this.temperature = jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.NOMINAL_VALUE.getKey()) != null) {
this.nominalValue = jObject.get(JSONApiResponseKeysEnum.NOMINAL_VALUE.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_VALUE.getKey()) != null) {
this.controlValue = jObject.get(JSONApiResponseKeysEnum.CONTROL_VALUE.getKey()).getAsFloat();
}
if (jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE_TIME.getKey()) != null) {
this.temperatureTime = jObject.get(JSONApiResponseKeysEnum.TEMPERATION_VALUE_TIME.getKey())
.getAsString();
}
if (jObject.get(JSONApiResponseKeysEnum.NOMINAL_VALUE_TIME.getKey()) != null) {
this.nominalValueTime = jObject.get(JSONApiResponseKeysEnum.NOMINAL_VALUE_TIME.getKey()).getAsString();
}
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_VALUE_TIME.getKey()) != null) {
this.controlValueTime = jObject.get(JSONApiResponseKeysEnum.CONTROL_VALUE_TIME.getKey()).getAsString();
}
}
}
/**
* Returns the controleState for heating of the zone.
*
* @return the controlState
*/
public Short getControlState() {
return controlState;
}
/**
* Returns the operationMode for heating of the zone.
*
* @return the operationMode
*/
public Short getOperationMode() {
return operationMode;
}
/**
* Returns the current temperature of the zone.
*
* @return the temperature
*/
public Float getTemperature() {
return temperature;
}
/**
* Returns the timestamp when the temperature was read out as {@link Date}.
*
* @return the temperatureTime
* @throws ParseException see {@link DateFormat#parse(String)}
*/
public Date getTemperatureTimeAsDate() throws ParseException {
return formatter.parse(temperatureTime);
}
/**
* Returns the timestamp when the temperature was read out as {@link String}.
*
* @return the temperatureTime
*/
public String getTemperatureTimeAsString() {
return temperatureTime;
}
/**
* Returns the nominal value for heating of the zone.
*
* @return the nominalValue
*/
public Float getNominalValue() {
return nominalValue;
}
/**
* Returns the timestamp as {@link Date} for the nominal value of the zone.
*
* @return the nominalValueTime
* @throws ParseException see {@link DateFormat#parse(String)}
*/
public Date getNominalValueTimeAsDate() throws ParseException {
return formatter.parse(nominalValueTime);
}
/**
* Returns the timestamp as {@link String} for the nominal value of the zone.
*
* @return the nominalValueTime
*/
public String getNominalValueTimeAsString() {
return nominalValueTime;
}
/**
* Returns the control value for heating of the zone.
*
* @return the controlValue
*/
public Float getControlValue() {
return controlValue;
}
/**
* Returns timestamp as {@link Date} for the control value for heating of the zone.
*
* @return the controlValueTime
* @throws ParseException see {@link DateFormat#parse(String)}
*/
public Date getControlValueTimeAsDate() throws ParseException {
return formatter.parse(controlValueTime);
}
/**
* Returns timestamp as {@link String} for the control value for heating of the zone.
*
* @return the controlValueTime
*/
public String getControlValueTimeAsString() {
return controlValueTime;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TemperatureControlStatus [controlMode=" + controlMode + ", controlState=" + controlState
+ ", operationMode=" + operationMode + ", temperature=" + temperature + ", temperatureTime="
+ temperatureTime + ", nominalValue=" + nominalValue + ", nominalValueTime=" + nominalValueTime
+ ", controlValue=" + controlValue + ", controlValueTime=" + controlValueTime + "]";
}
}

View File

@@ -0,0 +1,136 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.openhab.binding.digitalstrom.internal.lib.climate.constants.OperationModes;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseZoneIdentifier;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonObject;
/**
* The {@link TemperatureControlValues} acts as container for the digitalSTROM json-method
* <i>getTemperatureControlValues</i>. So the {@link TemperatureControlValues} contains all temperature
* control values information of a zone.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class TemperatureControlValues extends BaseZoneIdentifier {
private Map<OperationModes, Float> temperatureControlValues;
private String controlDSUID;
private Boolean isConfigured;
/**
* Creates a new {@link TemperatureControlValues} through the {@link JsonObject} which will be returned by an
* apartment call.
*
* @param jObject must not be null
*/
public TemperatureControlValues(JsonObject jObject) {
super(jObject);
init(jObject);
}
/**
* Creates a new {@link TemperatureControlValues} through the {@link JsonObject} which will be returned by an zone
* call.<br>
* Because of zone calls does not include a zoneID or zoneName in the json response, the zoneID and zoneName have to
* be handed over the constructor.
*
* @param jObject must not be null
* @param zoneID must not be null
* @param zoneName can be null
*/
public TemperatureControlValues(JsonObject jObject, Integer zoneID, String zoneName) {
super(zoneID, zoneName);
init(jObject);
}
private void init(JsonObject jObject) {
if (jObject.get(JSONApiResponseKeysEnum.IS_CONFIGURED.getKey()) != null) {
this.isConfigured = jObject.get(JSONApiResponseKeysEnum.IS_CONFIGURED.getKey()).getAsBoolean();
}
if (isConfigured) {
if (jObject.get(JSONApiResponseKeysEnum.CONTROL_DSUID.getKey()) != null) {
this.controlDSUID = jObject.get(JSONApiResponseKeysEnum.CONTROL_DSUID.getKey()).getAsString();
}
temperatureControlValues = new HashMap<>(OperationModes.values().length);
for (OperationModes opMode : OperationModes.values()) {
if (jObject.get(opMode.getKey()) != null) {
temperatureControlValues.put(opMode, jObject.get(opMode.getKey()).getAsFloat());
}
}
}
}
/**
* @see TemperatureControlStatus#getControlDSUID()
* @return the controlDSUID
*/
public String getControlDSUID() {
return controlDSUID;
}
/**
* @see TemperatureControlStatus#getIsConfigured()
* @return the isConfigured
*/
public Boolean getIsConfigured() {
return isConfigured;
}
/**
* Returns the set temperature of the given operation mode.
*
* @param operationMode must not be null
* @return temperature of the operation mode
*/
public Float getTemperation(OperationModes operationMode) {
return temperatureControlValues.get(operationMode);
}
/**
* Returns the available operation modes as {@link Set}.
*
* @return available operation modes
*/
public Set<OperationModes> getOperationModes() {
return temperatureControlValues.keySet();
}
/**
* Returns a {@link Map} that maps the available operation modes to the set values.
*
* @return Map with operation modes and their values
*/
public Map<OperationModes, Float> getTemperatureControlValues() {
return temperatureControlValues;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TemperatureControlValues [temperatureControlValues=" + temperatureControlValues + ", controlDSUID="
+ controlDSUID + ", isConfigured=" + isConfigured + "]";
}
}

View File

@@ -0,0 +1,127 @@
/**
* 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.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.BaseSensorValues;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
/**
* The {@link WeatherSensorData} acts as container for the digitalSTROM json-method <i>getSensorValues</i>. The
* {@link WeatherSensorData} contains all {@link CachedSensorValue}s and weather service information of the
* digitalSTROM-server, if a weather service is set.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class WeatherSensorData extends BaseSensorValues {
private final Logger logger = LoggerFactory.getLogger(WeatherSensorData.class);
private String weatherIconId;
private String weatherConditionId;
private String weatherServiceId;
private String weatherServiceTime;
/**
* Creates a new {@link SensorValues} through the {@link JsonObject} that will be returned by an apartment call.
*
* @param jObject must not be null
*/
public WeatherSensorData(JsonObject jObject) {
super.addSensorValue(jObject, true);
if (jObject.get(JSONApiResponseKeysEnum.WEATHER_ICON_ID.getKey()) != null) {
weatherIconId = jObject.get(JSONApiResponseKeysEnum.WEATHER_ICON_ID.getKey()).getAsString();
}
if (jObject.get(JSONApiResponseKeysEnum.WEATHER_CONDITION_ID.getKey()) != null) {
weatherConditionId = jObject.get(JSONApiResponseKeysEnum.WEATHER_CONDITION_ID.getKey()).getAsString();
}
if (jObject.get(JSONApiResponseKeysEnum.WEATHER_SERVICE_ID.getKey()) != null) {
weatherServiceId = jObject.get(JSONApiResponseKeysEnum.WEATHER_SERVICE_ID.getKey()).getAsString();
}
if (jObject.get(JSONApiResponseKeysEnum.WEATHER_SERVICE_TIME.getKey()) != null) {
weatherServiceTime = jObject.get(JSONApiResponseKeysEnum.WEATHER_SERVICE_TIME.getKey()).getAsString();
}
}
/**
* Returns the weather icon id of the set weather service.
*
* @return the weatherIconId
*/
public String getWeatherIconId() {
return weatherIconId;
}
/**
* Returns the weather condition id of the set weather service.
*
* @return the weatherConditionId
*/
public String getWeatherConditionId() {
return weatherConditionId;
}
/**
* Returns the weather service id of the set weather service.
*
* @return the weatherServiceId
*/
public String getWeatherServiceId() {
return weatherServiceId;
}
/**
* Returns the weather service time as {@link String} of the set weather service.
*
* @return the weatherServiceTime as {@link String}
*/
public String getWeatherServiceTimeAsSting() {
return weatherServiceTime;
}
/**
* Returns the weather service time as {@link Date} of the set weather service.
*
* @return the weatherServiceTime as {@link Date}
*/
public Date getWeatherServiceTimeAsDate() {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SS");
try {
return formatter.parse(weatherServiceTime);
} catch (ParseException e) {
logger.error("A ParseException occurred by parsing date string: {}", weatherServiceTime, e);
}
return null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "WeatherSensorData [weatherIconId=" + weatherIconId + ", weatherConditionId=" + weatherConditionId
+ ", weatherServiceId=" + weatherServiceId + ", weatherServiceTime=" + weatherServiceTime + ", "
+ super.toString() + "]";
}
}

View File

@@ -0,0 +1,622 @@
/**
* 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.digitalstrom.internal.lib.config;
/**
* The {@link Config} contains all configurations for the digitalSTROM-Library.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class Config {
/* Client configuration */
// connection configuration
/**
* The default application name to generate the application token.
*/
public static final String DEFAULT_APPLICATION_NAME = "openHAB";
/**
* Defines the used tread pool name to get a thread pool from {@link ThreadPoolManager}.
*/
public static final String THREADPOOL_NAME = "digitalSTROM";
private String applicationName = DEFAULT_APPLICATION_NAME;
private String host;
private String userName;
private String password;
private String appToken;
private String trustCertPath;
private String cert;
// Timeouts
/**
* Default connection timeout
*/
public static final int DEFAULT_CONNECTION_TIMEOUT = 4000;
/**
* High connection timeout for requests that take some time.
*/
public static final int HIGH_CONNECTION_TIMEOUT = 60000;
/**
* Default read timeout
*/
public static final int DEFAULT_READ_TIMEOUT = 10000;
/**
* High read timeout for requests that take some time.
*/
public static final int HIGH_READ_TIMEOUT = 60000;
/**
* Default connection timeout for sensor readings from devices
*/
public static final int DEFAULT_SENSORDATA_CONNECTION_TIMEOUT = 4000;
/**
* Default read timeout for sensor readings from devices
*/
public static final int DEFAULT_SENSORDATA_READ_TIMEOUT = 20000;
private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
private int readTimeout = DEFAULT_READ_TIMEOUT;
private int sensordataConnectionTimeout = DEFAULT_SENSORDATA_CONNECTION_TIMEOUT;
private int sensordataReadTimeout = DEFAULT_SENSORDATA_READ_TIMEOUT;
/* Internal Configurations */
// Trash Bin Config
/**
* The default number of days after the trash devices is deleted.
*/
public static final int DEFAULT_TRASH_DEVICE_DELETE_TIME = 7;
private int trashDeviceDeleteTime = DEFAULT_TRASH_DEVICE_DELETE_TIME;
/**
* The default milliseconds after the trash devices will be checked if its time to delete.
*/
public static final int DEFAULT_BIN_CHECK_TIME = 360000; // in milliseconds
private int binCheckTime = DEFAULT_BIN_CHECK_TIME; // in milliseconds
// Device update config
/**
* Default interval of the polling frequency in milliseconds. The digitalSTROM-rules state that the
* polling interval must to be at least 1 second.
*/
public static final int DEFAULT_POLLING_FREQUENCY = 1000; // in milliseconds
private int pollingFrequency = DEFAULT_POLLING_FREQUENCY; // in milliseconds
/* Sensordata */
// Sensodata read config
/**
* The default interval to refresh the sensor data.
*/
public static final int DEFAULT_SENSORDATA_REFRESH_INTERVAL = 60000;
private int sensordataRefreshInterval = DEFAULT_SENSORDATA_REFRESH_INTERVAL;
/**
* The default interval to refresh the total power sensor data.
*/
public static final int DEFAULT_TOTAL_POWER_UPDATE_INTERVAL = 30000;
private int totalPowerUpdateInterval = DEFAULT_TOTAL_POWER_UPDATE_INTERVAL;
/**
* Default time to wait between another {@link SensorJob} can be executed on a circuit.
*/
public static final int DEFAULT_SENSOR_READING_WAIT_TIME = 60000;
private int sensorReadingWaitTime = DEFAULT_SENSOR_READING_WAIT_TIME;
// sensor data Prioritys
/**
* Priority for never refresh the sensor value.
*/
public static final String REFRESH_PRIORITY_NEVER = "never";
/**
* Priority for refresh the sensor value with low priority.
*/
public static final String REFRESH_PRIORITY_LOW = "low";
/**
* Priority for refresh the sensor value with medium priority.
*/
public static final String REFRESH_PRIORITY_MEDIUM = "medium";
/**
* Priority for refresh the sensor value with high priority.
*/
public static final String REFRESH_PRIORITY_HIGH = "high";
// max sensor reading cyclic to wait
/**
* The default factor to prioritize medium {@link SensorJob}s down.
*/
public static final long DEFAULT_MEDIUM_PRIORITY_FACTOR = 5;
/**
* The default factor to prioritize low {@link SensorJob}s down.
*/
public static final long DEFAULT_LOW_PRIORITY_FACTOR = 10;
private long mediumPriorityFactor = DEFAULT_MEDIUM_PRIORITY_FACTOR;
private long lowPriorityFactor = DEFAULT_LOW_PRIORITY_FACTOR;
/**
* Defines the event polling interval of the {@link EventListener} in milliseconds.
*/
private int eventListenerRefreshinterval = DEFAULT_POLLING_FREQUENCY;
/**
* The default max standby active power for a device. It's needed to set a {@link Device} with output mode
* {@link OutputModeEnum#WIPE} on if it isen't any more in standby mode.
*/
public static final int DEFAULT_STANDBY_ACTIVE_POWER = 2;
private int standbyActivePower = DEFAULT_STANDBY_ACTIVE_POWER;
/**
* Creates a new {@link Config} and set the given hostAddress, userName, password and applicationToken. The other
* configurations will be set to default.
*
* @param hostAddress of the digitalSTROM-Server, must not be null
* @param userName to login, can be null
* @param password to login, can be null
* @param applicationToken to login , can be null
*/
public Config(String hostAddress, String userName, String password, String applicationToken) {
this.host = hostAddress;
this.userName = userName;
this.password = password;
this.appToken = applicationToken;
}
/**
* Creates a {@link Config} with default values.
*/
public Config() {
// config with default values
}
/**
* Returns the host name from the server.
*
* @return the host address
*/
public String getHost() {
return host;
}
/**
* Sets the host name of the Server.
* <br>
* <br>
* <b>Note:</b><br>
* If the host dosen't use the default port (8080), the port has to be set after the host name. e.g.
* <i>my-digitalSTROM-Server.com:58080</i>
*
* @param hostAddress of the digitalSTROM-Server
*/
public void setHost(String hostAddress) {
this.host = hostAddress;
}
/**
* Returns the username.
*
* @return the username
*/
public String getUserName() {
return userName;
}
/**
* Sets the username.
*
* @param userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* Returns the password.
*
* @return the password
*/
public String getPassword() {
return password;
}
/**
* Sets the password.
*
* @param password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Returns the Application-Token.
*
* @return the Application-Token
*/
public String getAppToken() {
return appToken;
}
/**
* Sets the Application-Token.
*
* @param applicationToken to set
*/
public void setAppToken(String applicationToken) {
this.appToken = applicationToken;
}
/**
* Returns the connection timeout.
*
* @return the connection timeout
*/
public int getConnectionTimeout() {
return connectionTimeout;
}
/**
* Sets the connection timeout.
*
* @param connectionTimeout to set
*/
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* Returns the read timeout.
*
* @return the read timeout
*/
public int getReadTimeout() {
return readTimeout;
}
/**
* Sets the read timeout.
*
* @param readTimeout the readTimeout to set
*/
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
/**
* Returns the connection timeout for sensor readings from devices.
*
* @return the connection sensor data timeout
*/
public int getSensordataConnectionTimeout() {
return sensordataConnectionTimeout;
}
/**
* Sets the connection timeout for sensor readings from devices.
*
* @param sensordataConnectionTimeout to set
*/
public void setSensordataConnectionTimeout(int sensordataConnectionTimeout) {
this.sensordataConnectionTimeout = sensordataConnectionTimeout;
}
/**
* Returns the read timeout for sensor readings from devices.
*
* @return the read sensor data timeout
*/
public int getSensordataReadTimeout() {
return sensordataReadTimeout;
}
/**
* Sets the connection timeout for sensor readings from devices.
*
* @param sensordataReadTimeout to set
*/
public void setSensordataReadTimeout(int sensordataReadTimeout) {
this.sensordataReadTimeout = sensordataReadTimeout;
}
/**
* Returns the path to the SSL-Certificate.
*
* @return the path to the trust certification
*/
public String getTrustCertPath() {
return trustCertPath;
}
/**
* Return the SSL-Certificate of the server.
*
* @return the SSL-Certificate of the server
*/
public String getCert() {
return cert;
}
/**
* Sets the SSL-Certificate of the server, will be set automatically by the {@link HttpTransportImpl} if no
* SSL-Certification path is set.
*
* @param cert of the digitalSTROM-Server to set
*/
public void setCert(String cert) {
this.cert = cert;
}
/**
* Sets the path to the SSL-Certificate. It can be a absolute or relative path.
*
* @param trustCertPath path to a SSL-Certificate
*/
public void setTrustCertPath(String trustCertPath) {
this.trustCertPath = trustCertPath;
}
/**
* Returns the number of days after the trash devices is deleted.
*
* @return the trash-device delete time in days
*/
public int getTrashDeviceDeleteTime() {
return trashDeviceDeleteTime;
}
/**
* Sets the number of days after the trash devices is deleted.
*
* @param trashDeviceDeleteTime in days
*/
public void setTrashDeviceDeleteTime(int trashDeviceDeleteTime) {
this.trashDeviceDeleteTime = trashDeviceDeleteTime;
}
/**
* Sets the milliseconds after the trash devices will be checked, if its time to delete.
*
* @return the bin check time in milliseconds
*/
public int getBinCheckTime() {
return binCheckTime;
}
/**
* Returns the milliseconds after the trash devices will be checked, if its time to delete.
*
* @param binCheckTime in milliseconds
*/
public void setBinCheckTime(int binCheckTime) {
this.binCheckTime = binCheckTime;
}
/**
* Returns the interval of the polling frequency in milliseconds. The digitalSTROM-rules state that the
* polling interval must to be at least 1 second.
*
* @return the pollingFrequency in milliseconds
*/
public int getPollingFrequency() {
return pollingFrequency;
}
/**
* Sets the interval of the polling frequency in milliseconds. The digitalSTROM-rules state that the
* polling interval must to be at least 1 second.
*
* @param pollingFrequency to set
*/
public void setPollingFrequency(int pollingFrequency) {
this.pollingFrequency = pollingFrequency;
}
/**
* Returns the interval in milliseconds to refresh the sensor data.
*
* @return the sensor data refresh interval in milliseconds
*/
public int getSensordataRefreshInterval() {
return sensordataRefreshInterval;
}
/**
* Sets the interval in milliseconds to refresh the sensor data.
*
* @param sensordataRefreshInterval in milliseconds.
*/
public void setSensordataRefreshInterval(int sensordataRefreshInterval) {
this.sensordataRefreshInterval = sensordataRefreshInterval;
}
/**
* Returns the interval to refresh the total power sensor data.
*
* @return the total power update interval in milliseconds.
*/
public int getTotalPowerUpdateInterval() {
return totalPowerUpdateInterval;
}
/**
* Sets the interval in milliseconds to refresh the total power sensor data.
*
* @param totalPowerUpdateInterval in milliseconds
*/
public void setTotalPowerUpdateInterval(int totalPowerUpdateInterval) {
this.totalPowerUpdateInterval = totalPowerUpdateInterval;
}
/**
* Returns the time in milliseconds to wait between another {@link SensorJob} can be executed on a circuit.
*
* @return the sensor reading wait time in milliseconds
*/
public int getSensorReadingWaitTime() {
return sensorReadingWaitTime;
}
/**
* Sets the time in milliseconds to wait between another {@link SensorJob} can be executed on a circuit.
*
* @param sensorReadingWaitTime in milliseconds
*/
public void setSensorReadingWaitTime(int sensorReadingWaitTime) {
this.sensorReadingWaitTime = sensorReadingWaitTime;
}
/**
* Returns the factor to prioritize medium {@link SensorJob}s in the {@link SensorJobExecutor} down.
*
* @return the medium priority factor
*/
public long getMediumPriorityFactor() {
return mediumPriorityFactor;
}
/**
* Sets the factor to prioritize medium {@link SensorJob}s in the {@link SensorJobExecutor} down.
*
* @param mediumPriorityFactor to set
*/
public void setMediumPriorityFactor(long mediumPriorityFactor) {
this.mediumPriorityFactor = mediumPriorityFactor;
}
/**
* Returns the factor to prioritize low {@link SensorJob}s in the {@link SensorJobExecutor} down.
*
* @return the low priority factor
*/
public long getLowPriorityFactor() {
return lowPriorityFactor;
}
/**
* Sets the factor to prioritize low {@link SensorJob}s in the {@link SensorJobExecutor}down.
*
* @param lowPriorityFactor to set
*/
public void setLowPriorityFactor(long lowPriorityFactor) {
this.lowPriorityFactor = lowPriorityFactor;
}
/**
* Returns the polling interval in milliseconds to poll the {@link Event}s in the {@link EventListener}.
*
* @return the EventListener refresh interval in milliseconds
*/
public int getEventListenerRefreshinterval() {
return eventListenerRefreshinterval;
}
/**
* Sets the polling interval in milliseconds to poll the {@link Event}s in the {@link EventListener}.
*
* @param eventListenerRefreshinterval to set
*/
public void setEventListenerRefreshinterval(int eventListenerRefreshinterval) {
this.eventListenerRefreshinterval = eventListenerRefreshinterval;
}
/**
* Returns the max standby active power for a device. It's needed to set a {@link Device} with output mode
* {@link OutputModeEnum#WIPE} on if it isen't any more in standby mode.
*
* @return the standby active power
*/
public int getStandbyActivePower() {
return standbyActivePower;
}
/**
* Sets the max standby active power for a device. It's needed to set a {@link Device} with output mode
* {@link OutputModeEnum#WIPE} on if it isen't any more in standby mode.
*
* @param standbyActivePower to set
*/
public void setStandbyActivePower(int standbyActivePower) {
this.standbyActivePower = standbyActivePower;
}
/**
* Returns the application name to generate the application token.
*
* @return the applicationName
*/
public String getApplicationName() {
return applicationName;
}
/**
* Sets the application name to generate the application token.
*
* @param applicationName to set
*/
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
/**
* Removes the configured username and password from this {@link Config}.
*/
public void removeUsernameAndPassword() {
this.userName = null;
this.password = null;
}
/**
* Updates this {@link Config} with the configuration of given {@link Config}.
*
* @param config new config
*/
public void updateConfig(Config config) {
setHost(config.getHost());
setUserName(config.getUserName());
setPassword(config.getPassword());
setAppToken(config.getAppToken());
setConnectionTimeout(config.getConnectionTimeout());
setReadTimeout(config.getReadTimeout());
setSensordataConnectionTimeout(config.getSensordataConnectionTimeout());
setSensordataReadTimeout(config.getSensordataReadTimeout());
setTrustCertPath(config.getTrustCertPath());
setTrashDeviceDeleteTime(config.getTrashDeviceDeleteTime());
setBinCheckTime(config.getBinCheckTime());
setPollingFrequency(config.getPollingFrequency());
setSensordataRefreshInterval(config.getSensordataRefreshInterval());
setTotalPowerUpdateInterval(config.getTotalPowerUpdateInterval());
setSensorReadingWaitTime(config.getSensorReadingWaitTime());
setMediumPriorityFactor(config.getMediumPriorityFactor());
setLowPriorityFactor(config.getLowPriorityFactor());
setEventListenerRefreshinterval(config.getEventListenerRefreshinterval());
setStandbyActivePower(config.getStandbyActivePower());
setApplicationName(config.getApplicationName());
}
@Override
public String toString() {
return "Config [applicationName=" + applicationName + ", host=" + host + ", userName=" + userName
+ ", password=" + password + ", appToken=" + appToken + ", connectionTimeout=" + connectionTimeout
+ ", readTimeout=" + readTimeout + ", sensordataConnectionTimeout=" + sensordataConnectionTimeout
+ ", sensordataReadTimeout=" + sensordataReadTimeout + ", trustCertPath=" + trustCertPath
+ ", trashDeviceDeleteTime=" + trashDeviceDeleteTime + ", binCheckTime=" + binCheckTime
+ ", pollingFrequency=" + pollingFrequency + ", sensordataRefreshInterval=" + sensordataRefreshInterval
+ ", totalPowerUpdateInterval=" + totalPowerUpdateInterval + ", sensorReadingWaitTime="
+ sensorReadingWaitTime + ", mediumPriorityFactor=" + mediumPriorityFactor + ", lowPriorityFactor="
+ lowPriorityFactor + ", eventListenerRefreshinterval=" + eventListenerRefreshinterval
+ ", standbyActivePower=" + standbyActivePower + "]";
}
}

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.digitalstrom.internal.lib.event;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
/**
* The {@link EventHandler} can be implemented to get informed by {@link EventItem}'s through the {@link EventListener}.
* <br>
* For that the {@link #getSupportetEvents()} and {@link #supportsEvent(String)} methods have to be implemented, so that
* the {@link EventListener} knows whitch events it has to subscribe at the digitalSTROM-server and which handler has
* to be informed. <br>
* The implementation of the {@link EventHandler} also has to be registered through
* {@link EventListener#addEventHandler(EventHandler)} to the {@link EventListener} and the {@link EventListener} has to
* be started.<br>
* <br>
* To handle the {@link EventItem} the method {@link #handleEvent(EventItem)} has to be implemented.
*
* @author Michael Ochel
* @author Matthias Siegele
*/
public interface EventHandler {
/**
* Handles a {@link EventItem} e.g. which was detected by the {@link EventListener}.
*
* @param eventItem to handle
*/
void handleEvent(EventItem eventItem);
/**
* Returns a {@link List} that contains the supported events.
*
* @return supported events
*/
List<String> getSupportedEvents();
/**
* Returns true, if the {@link EventHandler} supports the given event.
*
* @param eventName to check
* @return true, if event is supported, otherwise false
*/
boolean supportsEvent(String eventName);
/**
* Returns the unique id of the {@link EventHandler}.
*
* @return uid of the EventHandler
*/
String getUID();
/**
* Sets a {@link EventListener} to this {@link EventHandler}.
*
* @param eventListener to set
*/
void setEventListener(EventListener eventListener);
/**
* Unsets a {@link EventListener} to this {@link EventHandler}.
*
* @param eventListener to unset
*/
void unsetEventListener(EventListener eventListener);
}

View File

@@ -0,0 +1,419 @@
/**
* 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.digitalstrom.internal.lib.event;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.event.types.Event;
import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
import org.openhab.binding.digitalstrom.internal.lib.event.types.JSONEventImpl;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.impl.JSONResponseHandler;
import org.openhab.core.common.ThreadPoolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* The {@link EventListener} listens for events which will be thrown by the digitalSTROM-Server and it notifies the
* added {@link EventHandler} about the detected events, if it supports the event-type.<br>
* You can add {@link EventHandler}'s through the constructors or the methods {@link #addEventHandler(EventHandler)} and
* {@link #addEventHandlers(List)}.<br>
* You can also delete a {@link EventHandler} though the method {@link #removeEventHandler(EventHandler)}.<br>
* If the {@link EventListener} is started, both methods subscribe respectively unsubscribe the event-types of the
* {@link EventHandler}/s automatically.<br>
* If you want to dynamically subscribe event-types, e.g. because a configuration has changed and a
* {@link EventHandler} needs to be informed of another event-type, you can use the methods
* {@link #addSubscribe(String)} or {@link #addSubscribeEvents(List)} to add more than one event-type. To remove a
* subscribed event you can use the method {@link #removeSubscribe(String, String)}, you also have to change the return
* of the {@link EventHandler} methods {@link EventHandler#getSupportetEvents()} and
* {@link EventHandler#supportsEvent(String)}.
* <br>
* To start and stop the listening you have to call the methods {@link #start()} and {@link #stop()}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class EventListener {
private final Logger logger = LoggerFactory.getLogger(EventListener.class);
private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME);
public static final int SUBSCRIBE_DELAY = 500;
private ScheduledFuture<?> pollingScheduler;
private ScheduledFuture<?> subscriptionScheduler;
private int subscriptionID = 15;
private final int timeout = 500;
private final List<String> subscribedEvents = Collections.synchronizedList(new LinkedList<>());
private boolean subscribed = false;
// error message
public static final String INVALID_SESSION = "Invalid session!";
public static final String TOKEN_NOT_FOUND = "token not found."; // Complete text: "Event subscription token not
// found."
private final ConnectionManager connManager;
private final List<EventHandler> eventHandlers = Collections.synchronizedList(new LinkedList<>());
private final Config config;
private boolean isStarted = false;
/**
* Creates a new {@link EventListener} to listen to the supported event-types of the given eventHandler and notify
* about a detected event.<br>
* <br>
* To get notified by events you have to call {@link #start()}.
*
* @param connectionManager must not be null
* @param eventHandler must not be null
*/
public EventListener(ConnectionManager connectionManager, EventHandler eventHandler) {
this.connManager = connectionManager;
this.config = connectionManager.getConfig();
addEventHandler(eventHandler);
}
/**
* This constructor can add more than one {@link EventHandler} as a list of {@link EventHandler}'s.
*
* @param connectionManager must not be null
* @param eventHandlers list of {@link EventHandler}'s must not be null
* @see #EventListener(ConnectionManager, EventHandler)
*/
public EventListener(ConnectionManager connectionManager, List<EventHandler> eventHandlers) {
this.connManager = connectionManager;
this.config = connectionManager.getConfig();
addEventHandlers(eventHandlers);
}
/**
* Creates a new {@link EventListener} without a {@link EventHandler}<br>
* <br>
* To get notified by events you have to call {@link #start()} and {@link #addEventHandler(EventHandler)} or
* {@link #addEventHandlers(List)}.
*
* @param connectionManager must not be null
*/
public EventListener(ConnectionManager connectionManager) {
this.connManager = connectionManager;
this.config = connectionManager.getConfig();
}
/**
* Stops this {@link EventListener} and unsubscribe events.
*/
public synchronized void stop() {
logger.debug("Stop EventListener");
isStarted = false;
internalStop();
}
/**
* Returns true, if the {@link EventListener} is started.
*
* @return true, if is started
*/
public boolean isStarted() {
return isStarted;
}
private void internalStop() {
if (subscriptionScheduler != null && !subscriptionScheduler.isCancelled()) {
subscriptionScheduler.cancel(true);
subscriptionScheduler = null;
}
if (pollingScheduler != null && !pollingScheduler.isCancelled()) {
pollingScheduler.cancel(true);
pollingScheduler = null;
unsubscribe();
logger.debug("internal stop EventListener");
}
}
/**
* Starts this {@link EventListener} and subscribe events.
*/
public synchronized void start() {
logger.debug("Start EventListener");
isStarted = true;
internalStart();
}
private void internalStart() {
if (!eventHandlers.isEmpty() && (pollingScheduler == null || pollingScheduler.isCancelled())) {
pollingScheduler = scheduler.scheduleWithFixedDelay(runableListener, 0,
config.getEventListenerRefreshinterval(), TimeUnit.MILLISECONDS);
logger.debug("internal start EventListener");
}
}
/**
* Adds a {@link List} of {@link EventHandler}'s and subscribe the supported event-types, if the
* {@link EventListener} is started and the event-types are not already subscribed.
*
* @param eventHandlers to add
*/
public void addEventHandlers(List<EventHandler> eventHandlers) {
if (eventHandlers != null) {
for (EventHandler eventHandler : eventHandlers) {
addEventHandler(eventHandler);
}
}
}
/**
* Adds a {@link EventHandler}'s and subscribe the supported event-types, if the
* {@link EventListener} is started and the event-types are not already subscribed.<br>
* <br>
* <b>Note:</b><br>
* If {@link #start()} was called before the {@link EventListener} will start now, otherwise you have to call
* {@link #start()} to get notified by events.
*
* @param eventHandler to add
*/
public void addEventHandler(EventHandler eventHandler) {
if (eventHandler != null) {
boolean handlerExist = false;
for (EventHandler handler : eventHandlers) {
if (handler.getUID().equals(eventHandler.getUID())) {
handlerExist = true;
}
}
if (!handlerExist) {
eventHandlers.add(eventHandler);
addSubscribeEvents(eventHandler.getSupportedEvents());
logger.debug("eventHandler: {} added", eventHandler.getUID());
if (isStarted) {
internalStart();
}
}
}
}
/**
* Remove a {@link EventHandler} and unsubscribes the supported event-types, if the
* {@link EventListener} is started and no other {@link EventHandler} needed the event-types.
*
* @param eventHandler to remove
*/
public void removeEventHandler(EventHandler eventHandler) {
if (eventHandler != null && eventHandlers.contains(eventHandler)) {
List<String> tempSubsList = new ArrayList<>();
int index = -1;
EventHandler intEventHandler = null;
boolean subscribedEventsChanged = false;
for (int i = 0; i < eventHandlers.size(); i++) {
intEventHandler = eventHandlers.get(i);
if (intEventHandler.getUID().equals(eventHandler.getUID())) {
index = i;
} else {
tempSubsList.addAll(intEventHandler.getSupportedEvents());
}
}
if (index != -1) {
intEventHandler = eventHandlers.remove(index);
for (String eventName : intEventHandler.getSupportedEvents()) {
if (!tempSubsList.contains(eventName)) {
subscribedEvents.remove(eventName);
subscribedEventsChanged = true;
}
}
}
if (subscribedEventsChanged) {
// Because of the json-call unsubscribe?eventName=XY&subscriptionID=Z doesn't work like it is explained
// in the dS-JSON-API, the whole EventListener will be restarted. The problem is, that not only the
// given eventName, rather all events of the subscitionID will be deleted.
restartListener();
}
}
}
/**
* Removes a subscribed event and unsubscibe it, if it is not needed by other {@link EventHandler}'s.
*
* @param unsubscribeEvent event name to unsubscibe
* @param eventHandlerID EventHandler-ID of the EventHandler that unsubscibe a event
*/
public void removeSubscribe(String unsubscribeEvent, String eventHandlerID) {
if (subscribedEvents != null && !subscribedEvents.contains(unsubscribeEvent)) {
boolean eventNeededByAnotherHandler = false;
for (EventHandler handler : eventHandlers) {
if (!handler.getUID().equals(eventHandlerID)) {
eventNeededByAnotherHandler = handler.getSupportedEvents().contains(unsubscribeEvent);
}
}
if (!eventNeededByAnotherHandler) {
logger.debug("unsubscribeEvent: {} is not needed by other EventHandler's... unsubscribe it",
unsubscribeEvent);
subscribedEvents.remove(unsubscribeEvent);
restartListener();
} else {
logger.debug("unsubscribeEvent: {} is needed by other EventHandler's... dosen't unsubscribe it",
unsubscribeEvent);
}
}
}
private void restartListener() {
internalStop();
if (!eventHandlers.isEmpty() && isStarted) {
logger.debug("Min one subscribed events was deleted, EventListener will be restarted");
internalStart();
}
}
/**
* Adds a event and subscribed it, if it is not subscribed already.
*
* @param subscribeEvent event name to subscribe
*/
public void addSubscribe(String subscribeEvent) {
if (!subscribedEvents.contains(subscribeEvent)) {
subscribedEvents.add(subscribeEvent);
logger.debug("subscibeEvent: {} added", subscribeEvent);
if (subscribed) {
subscribe(subscribeEvent);
}
}
}
/**
* Adds the events of the {@link List} and subscribe them, if a event is not subscribed already.
*
* @param subscribeEvents event name to subscribe
*/
public void addSubscribeEvents(List<String> subscribeEvents) {
for (String eventName : subscribeEvents) {
subscribe(eventName);
}
}
private void getSubscriptionID() {
boolean subscriptionIDavailable = false;
while (!subscriptionIDavailable) {
String response = connManager.getDigitalSTROMAPI().getEvent(connManager.getSessionToken(), subscriptionID,
timeout);
JsonObject responseObj = JSONResponseHandler.toJsonObject(response);
if (JSONResponseHandler.checkResponse(responseObj)) {
subscriptionID++;
} else {
String errorStr = null;
if (responseObj != null && responseObj.get(JSONApiResponseKeysEnum.MESSAGE.getKey()) != null) {
errorStr = responseObj.get(JSONApiResponseKeysEnum.MESSAGE.getKey()).getAsString();
}
if (errorStr != null && errorStr.contains(TOKEN_NOT_FOUND)) {
subscriptionIDavailable = true;
}
}
}
}
private boolean subscribe(String eventName) {
if (!subscribed) {
getSubscriptionID();
}
subscribed = connManager.getDigitalSTROMAPI().subscribeEvent(connManager.getSessionToken(), eventName,
subscriptionID, config.getConnectionTimeout(), config.getReadTimeout());
if (subscribed) {
logger.debug("subscribed event: {} to subscriptionID: {}", eventName, subscriptionID);
} else {
logger.error(
"Couldn't subscribe event {} ... maybe timeout because system is too busy ... event will be tried to subscribe later again ... ",
eventName);
}
return subscribed;
}
private void subscribe(final List<String> evetNames) {
final Iterator<String> eventNameIter = evetNames.iterator();
subscriptionScheduler = scheduler.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
while (eventNameIter.hasNext()) {
subscribe(eventNameIter.next());
}
subscriptionScheduler.cancel(true);
}
}, 0, SUBSCRIBE_DELAY, TimeUnit.MILLISECONDS);
}
private final Runnable runableListener = new Runnable() {
@Override
public void run() {
if (subscribed) {
String response = connManager.getDigitalSTROMAPI().getEvent(connManager.getSessionToken(),
subscriptionID, timeout);
JsonObject responseObj = JSONResponseHandler.toJsonObject(response);
if (JSONResponseHandler.checkResponse(responseObj)) {
JsonObject obj = JSONResponseHandler.getResultJsonObject(responseObj);
if (obj != null && obj.get(JSONApiResponseKeysEnum.EVENTS.getKey()).isJsonArray()) {
JsonArray array = obj.get(JSONApiResponseKeysEnum.EVENTS.getKey()).getAsJsonArray();
handleEvent(array);
}
} else {
String errorStr = null;
if (responseObj != null && responseObj.get(JSONApiResponseKeysEnum.MESSAGE.getKey()) != null) {
errorStr = responseObj.get(JSONApiResponseKeysEnum.MESSAGE.getKey()).getAsString();
}
if (errorStr != null && (errorStr.equals(INVALID_SESSION) || errorStr.contains(TOKEN_NOT_FOUND))) {
unsubscribe();
subscribe(subscribedEvents);
} else if (errorStr != null) {
pollingScheduler.cancel(true);
logger.error("Unknown error message at event response: {}", errorStr);
}
}
} else {
subscribe(subscribedEvents);
}
}
};
private void unsubscribe() {
for (String eventName : this.subscribedEvents) {
connManager.getDigitalSTROMAPI().unsubscribeEvent(this.connManager.getSessionToken(), eventName,
this.subscriptionID, config.getConnectionTimeout(), config.getReadTimeout());
}
}
private void handleEvent(JsonArray array) {
if (array.size() > 0) {
Event event = new JSONEventImpl(array);
for (EventItem item : event.getEventItems()) {
logger.debug("detect event {}", item.toString());
for (EventHandler handler : eventHandlers) {
if (handler.supportsEvent(item.getName())) {
logger.debug("inform handler with id {} about event {}", handler.getUID(), item.toString());
handler.handleEvent(item);
}
}
}
}
}
}

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.digitalstrom.internal.lib.event.constants;
/**
* The {@link EventNames} contains all needed event names to subscribe at the digitalSTROM server.
*
* @author Michael Ochel
* @author Matthias Siegele
*/
public class EventNames {
public static final String ZONE_SENSOR_VALUE = "zoneSensorValue";
public static final String HEATING_CONTROL_OPERATION_MODE = "heating-controller.operation-mode";
public static final String STATE_CHANGED = "stateChange";
public static final String CALL_SCENE = "callScene";
public static final String UNDO_SCENE = "undoScene";
public static final String DEVICE_SENSOR_VALUE = "deviceSensorValue";
public static final String DEVICE_BINARY_INPUT_EVENT = "deviceBinaryInputEvent";
}

View File

@@ -0,0 +1,110 @@
/**
* 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.digitalstrom.internal.lib.event.constants;
import java.util.HashMap;
import java.util.Map;
/**
* The {@link EventResponseEnum} contains digitalSTROM-Event properties of the events at {@link EventNames}.
*
* @author Michael Ochel
* @author Mathias Siegele
*/
public enum EventResponseEnum {
// general
NAME("Name"),
PROPERTIES("properties"),
SOURCE("source"),
SET("set"),
DSID("dsid"),
ZONEID("zoneID"),
GROUPID("groupID"),
IS_APARTMENT("isApartment"),
IS_GROUP("isGroup"),
IS_DEVICE("isDevice"),
IS_SERVICE("isService"),
// scene event
FORCED("forced"),
ORIGEN_TOKEN("originToken"),
CALL_ORIGEN("callOrigin"),
ORIGEN_DSUID("originDSUID"),
SCENEID("sceneID"),
ORIGIN_DEVICEID("originDeviceID"),
// device/zone sensor value
SENSOR_VALUE_FLOAT("sensorValueFloat"),
SENSOR_TYPE("sensorType"),
SENSOR_VALUE("sensorValue"),
SENSOR_INDEX("sensorIndex"),
// state changed
OLD_VALUE("oldvalue"),
STATE_NAME("statename"),
STATE("state"),
VALUE("value"),
// operation mode
ACTIONS("actions"),
OPERATION_MODE("operationMode"),
FORCED_UPDATE("forceUpdate"),
// binary input
INPUT_TYPE("inputType"),
INPUT_STATE("inputState"),
INPUT_INDEX("inputIndex");
private final String id;
static final Map<String, EventResponseEnum> EVENT_RESPONSE_FIELDS = new HashMap<>();
static {
for (EventResponseEnum ev : EventResponseEnum.values()) {
EVENT_RESPONSE_FIELDS.put(ev.getId(), ev);
}
}
/**
* Returns true, if the given property exists at the ESH event properties, otherwise false.
*
* @param property to check
* @return contains property (true = yes | false = no)
*/
public static boolean containsId(String property) {
return EVENT_RESPONSE_FIELDS.keySet().contains(property);
}
/**
* Returns the {@link EventResponseEnum} to the given property.
*
* @param property to get
* @return EventPropertyEnum
*/
public static EventResponseEnum getProperty(String property) {
return EVENT_RESPONSE_FIELDS.get(property);
}
private EventResponseEnum(String id) {
this.id = id;
}
/**
* Returns the id of this {@link EventResponseEnum}.
*
* @return id of this {@link EventResponseEnum}
*/
public String getId() {
return id;
}
}

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.digitalstrom.internal.lib.event.types;
import java.util.List;
/**
* The {@link Event} represents a digitalSTROM-Event.
*
* @author Alexander Betker
*/
public interface Event {
/**
* Returns a list of the {@link EventItem}s of this Event.
*
* @return List of {@link EventItem}s
*/
List<EventItem> getEventItems();
}

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.digitalstrom.internal.lib.event.types;
import java.util.Map;
import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventResponseEnum;
/**
* The {@link EventItem} represents a event item of an digitalSTROM-Event.
*
* @author Alexander Betker
* @author Michael Ochel - add getSource()
* @author Matthias Siegele - add getSource()
*/
public interface EventItem {
/**
* Returns the name of this {@link EventItem}.
*
* @return name of this {@link EventItem}
*/
String getName();
/**
* Returns {@link HashMap} with the properties fiels of this {@link EventItem}.
* The key is a {@link EventResponseEnum} and represents the property name
* and the value is the property value.
*
* @return the properties of this {@link EventItem}
*/
Map<EventResponseEnum, String> getProperties();
/**
* Returns {@link HashMap} with the source fields of this {@link EventItem}.
* The key is a {@link EventResponseEnum} and represents the property name
* and the value is the property value.
*
* @return the properties of this {@link EventItem}
*/
Map<EventResponseEnum, String> getSource();
}

View File

@@ -0,0 +1,100 @@
/**
* 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.digitalstrom.internal.lib.event.types;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventResponseEnum;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* The {@link EventItemImpl} is the implementation of the {@link EventItem}.
*
* @author Michael Ochel
* @author Mathias Siegele
*/
public class EventItemImpl implements EventItem {
private final String name;
private Map<EventResponseEnum, String> properties;
private Map<EventResponseEnum, String> source;
/**
* Creates a new {@link EventItemImpl} from the given digitalSTROM-Event-Item {@link JsonObject}.
*
* @param jsonEventItem must not be null
*/
public EventItemImpl(JsonObject jsonEventItem) {
name = jsonEventItem.get(JSONApiResponseKeysEnum.NAME.getKey()).getAsString();
if (jsonEventItem.get(JSONApiResponseKeysEnum.PROPERTIES.getKey()).isJsonObject()) {
Set<Entry<String, JsonElement>> propObjEntrySet = jsonEventItem
.get(JSONApiResponseKeysEnum.PROPERTIES.getKey()).getAsJsonObject().entrySet();
properties = new HashMap<>(propObjEntrySet.size());
for (Entry<String, JsonElement> entry : propObjEntrySet) {
if (EventResponseEnum.containsId(entry.getKey())) {
addProperty(EventResponseEnum.getProperty(entry.getKey()), entry.getValue().getAsString());
}
}
}
if (jsonEventItem.get(JSONApiResponseKeysEnum.SOURCE.getKey()).isJsonObject()) {
Set<Entry<String, JsonElement>> sourceObjEntrySet = jsonEventItem
.get(JSONApiResponseKeysEnum.SOURCE.getKey()).getAsJsonObject().entrySet();
source = new HashMap<>(sourceObjEntrySet.size());
for (Entry<String, JsonElement> entry : sourceObjEntrySet) {
if (EventResponseEnum.containsId(entry.getKey())) {
addSource(EventResponseEnum.getProperty(entry.getKey()), entry.getValue().getAsString());
}
}
}
}
private void addProperty(EventResponseEnum propertieKey, String value) {
properties.put(propertieKey, value);
}
private void addSource(EventResponseEnum sourceKey, String value) {
source.put(sourceKey, value);
}
@Override
public String getName() {
return name;
}
@Override
public Map<EventResponseEnum, String> getProperties() {
return properties;
}
@Override
public Map<EventResponseEnum, String> getSource() {
return source;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "EventItemImpl [name=" + name + ", properties=" + properties + ", source=" + source + "]";
}
}

View File

@@ -0,0 +1,48 @@
/**
* 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.digitalstrom.internal.lib.event.types;
import java.util.LinkedList;
import java.util.List;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* The {@link JSONEventImpl} is the implementation of the {@link Event}.
*
* @author Alexander Betker
*/
public class JSONEventImpl implements Event {
private List<EventItem> eventItemList;
/**
* Creates a new {@link JSONEventImpl} from the given digitalSTROM-Event {@link JsonArray}.
*
* @param jsonEventArray must not be null
*/
public JSONEventImpl(JsonArray jsonEventArray) {
this.eventItemList = new LinkedList<>();
for (int i = 0; i < jsonEventArray.size(); i++) {
if (jsonEventArray.get(i) instanceof JsonObject) {
this.eventItemList.add(new EventItemImpl((JsonObject) jsonEventArray.get(i)));
}
}
}
@Override
public List<EventItem> getEventItems() {
return eventItemList;
}
}

View File

@@ -0,0 +1,106 @@
/**
* 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.digitalstrom.internal.lib.listener;
/**
* The {@link ConnectionListener} is notified if the connection state of digitalSTROM-Server has changed.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public interface ConnectionListener {
/* Connection-States */
/**
* State, if you're not authenticated on the digitalSTROM-Server.
*/
final String NOT_AUTHENTICATED = "notAuth";
/**
* State, if the connection to the digitalSTROM-Server is lost.
*/
final String CONNECTION_LOST = "connLost";
/**
* State, if a ssl handshake problem occured while communicating with the digitalSTROM-Server.
*/
final String SSL_HANDSHAKE_ERROR = "sslHandshakeError";
/**
* State, if the connection to the digitalSTROM-Server is resumed.
*/
final String CONNECTION_RESUMED = "connResumed";
/**
* State, if the Application-Token is generated.
*/
final String APPLICATION_TOKEN_GENERATED = "appGen";
/* Not authentication reasons */
/**
* State, if the given Application-Token cannot be used.
*/
final String WRONG_APP_TOKEN = "wrongAppT";
/**
* State, if the given username or password cannot be used.
*/
final String WRONG_USER_OR_PASSWORD = "wrongUserOrPasswd";
/**
* State, if no username or password is set and the given application-token cannot be used or is null.
*/
final String NO_USER_PASSWORD = "noUserPasswd";
/**
* State, if the connection timed out.
*/
final String CONNECTON_TIMEOUT = "connTimeout";
/**
* State, if the host address cannot be found.
*/
final String HOST_NOT_FOUND = "hostNotFound";
/**
* State, if the host address is unknown.
*/
final String UNKNOWN_HOST = "unknownHost";
/**
* State, if the the URL is invalid.
*/
final String INVALID_URL = "invalideURL";
/**
* This method is called whenever the connection state has changed from {@link #CONNECTION_LOST}
* to {@link #CONNECTION_RESUMED} and vice versa. It also will be called if the application-token is generated over
* {@link #APPLICATION_TOKEN_GENERATED}.
*
* @param newConnectionState of the connection
*/
void onConnectionStateChange(String newConnectionState);
/**
* This method is called whenever the connection state has changed to {@link #NOT_AUTHENTICATED} or
* {@link #CONNECTION_LOST}
* and also passes the reason why. Reason can be:
* <ul>
* <li>{@link #WRONG_APP_TOKEN} if the given application-token can't be used.</li>
* <li>{@link #WRONG_USER_OR_PASSWORD} if the given user name or password can't be used.</li>
* <li>{@link #NO_USER_PASSWORD} if no user name or password is set and the given application-token can't be used.
* <li>{@link #HOST_NOT_FOUND} if the host can't be found.
* <li>{@link #INVALID_URL} if the the URL is invalid.
* </li>
* </ul>
*
* @param newConnectionState of the connection
* @param reason why the connection is failed
*/
void onConnectionStateChange(String newConnectionState, String reason);
}

View File

@@ -0,0 +1,86 @@
/**
* 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.digitalstrom.internal.lib.listener;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
/**
* The {@link DeviceStatusListener} is notified, if a {@link Device} status or configuration has changed, if a scene
* configuration is added to a {@link Device} or if a device has been added or removed. The {@link DeviceStatusListener}
* can be also registered by a {@link Circuit} to get informed by configuration or status changes.
* <p>
* By implementation with the id {@link #DEVICE_DISCOVERY} this listener can be used as a device discovery to get
* informed, if a new {@link Device} or {@link Circuit} is added or removed from the digitalSTROM-System.<br>
* For that the {@link DeviceStatusListener} has to be registered on the
* {@link DeviceStatusManager#registerDeviceListener(DeviceStatusListener)}. Then the {@link DeviceStatusListener} gets
* informed by the methods {@link #onDeviceAdded(Object)} and {@link #onDeviceRemoved(Object)}.
* </p>
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public interface DeviceStatusListener {
/**
* ID of the device discovery listener.
*/
static final String DEVICE_DISCOVERY = "DeviceDiscovery";
/**
* This method is called whenever the state of the {@link Device} has changed and passes the new device state as an
* {@link DeviceStateUpdate} object.
*
* @param deviceStateUpdate new device status
*/
void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate);
/**
* This method is called whenever a device is removed.
*
* @param device which is removed
*/
void onDeviceRemoved(GeneralDeviceInformation device);
/**
* This method is called whenever a device is added.
*
* @param device which is added
*/
void onDeviceAdded(GeneralDeviceInformation device);
/**
* This method is called whenever a configuration of an device has changed. What configuration has changed
* can be see by the given parameter whatConfig to handle the change.<br>
* Please have a look at {@link ChangeableDeviceConfigEnum} to see what configuration are changeable.
*
* @param whatConfig has changed
*/
void onDeviceConfigChanged(ChangeableDeviceConfigEnum whatConfig);
/**
* This method is called whenever a scene configuration is added to a device.
*
* @param sceneID of a read scene configuration
*/
void onSceneConfigAdded(short sceneID);
/**
* Returns the id of this {@link DeviceStatusListener}.
*
* @return the device listener id
*/
String getDeviceStatusListenerID();
}

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.digitalstrom.internal.lib.listener;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
/**
* The {@link ManagerStatusListener} is notified, if the state of digitalSTROM-Manager has changed.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface ManagerStatusListener {
/**
* This method is called whenever the state of an digitalSTROM-Manager has changed.<br>
* For that it passes the {@link ManagerTypes} and the new {@link ManagerStates}.
*
* @param managerType of the digitalSTROM-Manager
* @param newState of the digitalSTROM-Manager
*/
void onStatusChanged(ManagerTypes managerType, ManagerStates newState);
}

View File

@@ -0,0 +1,65 @@
/**
* 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.digitalstrom.internal.lib.listener;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
/**
* The {@link SceneStatusListener} is notified, if a {@link InternalScene} status has changed or a
* {@link InternalScene} has been removed or added.
*
* <p>
* By implementation with the id {@link #SCENE_DISCOVERY} this listener can be used as a scene discovery to get
* informed, if a new {@link InternalScene}s is added or removed from the digitalSTROM-System.<br>
* For that the {@link SceneStatusListener} has to be registered on the
* {@link SceneManager#registerSceneListener(SceneStatusListener)}. Then the {@link SceneStatusListener} gets
* informed by the methods {@link #onSceneAdded(InternalScene)} and {@link #onSceneRemoved(InternalScene)}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface SceneStatusListener {
/**
* The {@link SceneStatusListener} id for the discovery implementation.
*/
static final String SCENE_DISCOVERY = "SceneDiscovery";
/**
* This method is called whenever the state of the {@link InternalScene} has changed.
*
* @param newState (true = call | false = undo)
*/
void onSceneStateChanged(boolean newState);
/**
* This method is called whenever a {@link InternalScene} is removed.
*
* @param scene that was removed
*/
void onSceneRemoved(InternalScene scene);
/**
* This method is called whenever a {@link InternalScene} is added.
*
* @param scene that was added
*/
void onSceneAdded(InternalScene scene);
/**
* Return the id of this {@link SceneStatusListener}.
*
* @return the scene listener id
*/
String getSceneStatusListenerID();
}

View File

@@ -0,0 +1,31 @@
/**
* 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.digitalstrom.internal.lib.listener;
/**
* The {@link SystemStateChangeListener} can be implemented to get informed by digitalSTROM system state changes. It
* has to be registered by supported classes, e.g. the {@link TemperatureControlManager} or self implemented classes.
*
* @author Michael Ochel
* @author Matthias Siegele
*/
public interface SystemStateChangeListener {
/**
* Will be called, if a digitalSTROM system state has changed.
*
* @param stateType of the digitalSTROM system state
* @param newState of the digitalSTROM system state
*/
void onSystemStateChanged(String stateType, String newState);
}

View File

@@ -0,0 +1,68 @@
/**
* 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.digitalstrom.internal.lib.listener;
import org.openhab.binding.digitalstrom.internal.lib.climate.TemperatureControlSensorTransmitter;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
/**
* The {@link TemperatureControlStatusListener} can be implemented to get informed by configuration and status changes.
* <br>
* It also can be implemented as discovery, than the id have to be {@link #DISCOVERY}.
*
* @author Michael Ochel
* @author Matthias Siegele
*
*/
public interface TemperatureControlStatusListener {
/**
* The id for discovery.
*/
static Integer DISCOVERY = -2;
/**
* Will be called, if the configuration of the {@link TemperatureControlStatus} has changed.
*
* @param tempControlStatus that has changed
*/
void configChanged(TemperatureControlStatus tempControlStatus);
/**
* Will be called, if the target temperature has changed.
*
* @param newValue of the target temperature
*/
void onTargetTemperatureChanged(Float newValue);
/**
* Will be called, if the control value has changed.
*
* @param newValue of the control value
*/
void onControlValueChanged(Integer newValue);
/**
* Registers a {@link TemperatureControlSensorTransmitter}.
*
* @param temperatureSensorTransmitter to register
*/
void registerTemperatureSensorTransmitter(TemperatureControlSensorTransmitter temperatureSensorTransmitter);
/**
* Returns the id of this {@link TemperatureControlStatusListener}.
*
* @return id
*/
Integer getTemperationControlStatusListenrID();
}

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.digitalstrom.internal.lib.listener;
/**
* The {@link TotalPowerConsumptionListener} is notified, if the total power consumption or the total electric meter
* value has changed.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public interface TotalPowerConsumptionListener {
/**
* This method is called whenever the total power consumption of the digitalSTROM-System has changed.
*
* @param newPowerConsumption of the digitalSTROM-System
*/
void onTotalPowerConsumptionChanged(int newPowerConsumption);
/**
* This method is called whenever the total energy meter value in Wh of the digitalSTROM-System has changed.
*
* @param newEnergyMeterValue of the digitalSTROM-System
*/
void onEnergyMeterValueChanged(int newEnergyMeterValue);
/**
* This method is called whenever the total energy meter value in Ws of the digitalSTROM-System has changed.
*
* @param newEnergyMeterValue of the digitalSTROM-System
*/
void onEnergyMeterWsValueChanged(int newEnergyMeterValue);
}

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.digitalstrom.internal.lib.listener.stateenums;
/**
* The {@link ManagerStates} contains all reachable states of the digitalSTROM-Manager in {@link ManagerTypes}
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public enum ManagerStates {
RUNNING,
STOPPED,
INITIALIZING,
GENERATING_SCENES
}

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.digitalstrom.internal.lib.listener.stateenums;
/**
* The {@link ManagerTypes} contains all reachable digitalSTROM-Managers, which have states.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public enum ManagerTypes {
DEVICE_STATUS_MANAGER,
SCENE_MANAGER,
CONNECTION_MANAGER
}

View File

@@ -0,0 +1,155 @@
/**
* 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.digitalstrom.internal.lib.manager;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.HttpTransport;
/**
* The {@link ConnectionManager} manages the connection to a digitalSTROM-Server.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface ConnectionManager {
public static final int GENERAL_EXCEPTION = -1;
public static final int MALFORMED_URL_EXCEPTION = -2;
public static final int CONNECTION_EXCEPTION = -3;
public static final int SOCKET_TIMEOUT_EXCEPTION = -4;
public static final int UNKNOWN_HOST_EXCEPTION = -5;
public static final int AUTHENTIFICATION_PROBLEM = -6;
public static final int SSL_HANDSHAKE_EXCEPTION = -7;
/**
* Returns the {@link HttpTransport} to execute queries or special commands on the digitalSTROM-Server.
*
* @return the HttpTransport
*/
HttpTransport getHttpTransport();
/**
* Returns the {@link DsAPI} to execute commands on the digitalSTROM-Server.
*
* @return the DsAPI
*/
DsAPI getDigitalSTROMAPI();
/**
* This method has to be called before each command to check the connection to the digitalSTROM-Server.
* It examines the connection to the server, sets a new Session-Token, if it is expired and sets a new
* Application-Token, if none it set at the digitalSTROM-Server. It also outputs the specific connection failure.
*
* @return true if the connection is established and false if not
*/
boolean checkConnection();
/**
* Returns the current Session-Token.
*
* @return Session-Token
*/
String getSessionToken();
/**
* Returns the auto-generated or user defined Application-Token.
*
* @return Application-Token
*/
String getApplicationToken();
/**
* Registers a {@link ConnectionListener} to this {@link ConnectionManager}.
*
* @param connectionListener to register
*/
void registerConnectionListener(ConnectionListener connectionListener);
/**
* Unregisters the {@link ConnectionListener} from this {@link ConnectionManager}.
*/
void unregisterConnectionListener();
/**
* Revokes the saved Application-Token from the digitalSTROM-Server and returns true if the Application-Token was
* revoke successful, otherwise false.
*
* @return successful = true, otherwise false
*/
boolean removeApplicationToken();
/**
* Updates the login configuration.
*
* @param hostAddress of the digitalSTROM-Server
* @param username to login
* @param password to login
* @param applicationToken to login
*/
void updateConfig(String hostAddress, String username, String password, String applicationToken);
/**
* Updates the {@link Config} with the given config.
*
* @param config to update
*/
void updateConfig(Config config);
/**
* Returns the {@link Config}.
*
* @return the config
*/
Config getConfig();
/**
* Informs this {@link ConnectionManager} that the {@link Config} has been updated.
*/
void configHasBeenUpdated();
/**
* Generates and returns a new session token.
*
* @return new session token
*/
String getNewSessionToken();
/**
* Checks the connection through the given HTTP-Response-Code or exception code. If a {@link ConnectionListener} is
* registered this method also informs the registered {@link ConnectionListener} if the connection state has
* changed. <br>
* <br>
* <b>Exception-Codes:</b><br>
* <b>{@link #GENERAL_EXCEPTION}</b> general exception<br>
* <b>{@link #MALFORMED_URL_EXCEPTION}</b> MalformedURLException<br>
* <b>{@link #CONNECTION_EXCEPTION}</b> java.net.ConnectException<br>
* <b>{@link #SOCKET_TIMEOUT_EXCEPTION}</b> SocketTimeoutException<br>
* <b>{@link #UNKNOWN_HOST_EXCEPTION}</b> java.net.UnknownHostException<br>
* <br>
* <b>Code for authentication problems:</b> {@link #AUTHENTIFICATION_PROBLEM}<br>
*
*
* @param code exception or HTTP-Response-Code
* @return true, if connection is valid
*/
boolean checkConnection(int code);
/**
* Returns true, if connection is established, otherwise false.
*
* @return true, if connection is established, otherwise false
*/
boolean connectionEstablished();
}

View File

@@ -0,0 +1,242 @@
/**
* 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.digitalstrom.internal.lib.manager;
import org.openhab.binding.digitalstrom.internal.lib.event.EventHandler;
import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
/**
* <p>
* The {@link DeviceStatusManager} is responsible for the synchronization between the internal model of the
* digitalSTROM-devices and the real existing digitalSTROM-devices. You can change the state of an device by sending a
* direct command to the devices or by calling a scene. Furthermore the {@link DeviceStatusManager} get informed over
* the {@link SceneManager} by the {@link EventListener} if scenes are called by external sources. All
* configurations of the physically device will be synchronized to the internally managed model and updated as required.
* The {@link DeviceStatusManager} also initializes {@link SensorJob}'s with the {@link SensorJobExecutor} and
* {@link SceneReadingJobExecutor} to update required sensor and scene data.
*
* <p>
* Therefore the {@link DeviceStatusManager} uses the {@link StructureManager} for the internal management of the
* structure of the digitalSTROM-system, {@link ConnectionManager} to check the connectivity,
* {@link SceneManager} to identify externally called scenes and to update the affected devices of these
* called scenes to the internal model. The most methods of the above-named managers will be directly called over the
* {@link DeviceStatusManager}, because they are linked to the affected managers.
*
* <p>
* To get informed by all relevant information you can register some useful listeners. Here the list of all listeners
* which can registered or unregistered:
* </p>
* <ul>
* <li>{@link DeviceStatusListener} over {@link #registerDeviceListener(DeviceStatusListener)} respectively
* {@link #unregisterDeviceListener(DeviceStatusListener)}</li>
* <li>{@link SceneStatusListener} over {@link #registerSceneListener(SceneStatusListener)} respectively
* {@link #unregisterSceneListener(SceneStatusListener)}</li>
* <li>{@link TotalPowerConsumptionListener} over
* {@link #registerTotalPowerConsumptionListener(TotalPowerConsumptionListener)} respectively
* {@link #unregisterTotalPowerConsumptionListener()}</li>
* <li>{@link ManagerStatusListener} over {@link #registerStatusListener(ManagerStatusListener)}
* respectively {@link #unregisterStatusListener()}</li>
* <li>{@link ConnectionListener} over {@link #registerDeviceListener(DeviceStatusListener)} respectively
* {@link #unregisterDeviceListener(DeviceStatusListener)}</li>
* </ul>
* For what the listener can be used please have a look at the listener.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface DeviceStatusManager extends EventHandler {
/**
* Starts the working process for device synchronization. It also starts the {@link SensorJobExecutor} and the
* {@link SceneReadingJobExecutor} and the {@link SceneManager}.
*/
void start();
/**
* Stops the working process for device synchronization. It also stops the {@link SensorJobExecutor} and the
* {@link SceneReadingJobExecutor} and the {@link SceneManager}.
*/
void stop();
/**
* This method sends a call scene command for the given {@link InternalScene}, if call_undo is true otherwise it
* sends a undo command.
* <br>
* It also updates the scene state, if the command was send successful.
*
* @param scene to call
* @param call_undo (true = call | false = undo)
*/
void sendSceneComandsToDSS(InternalScene scene, boolean call_undo);
/**
* This method sends a stop command for the given {@link Device}.
* <br>
* It also reads out the current output value of the device and updates it, if the command was send successful.
*
* @param device which will send a stop command
*/
void sendStopComandsToDSS(Device device);
/**
* This method sends the command for the given {@link DeviceStateUpdate} for the given {@link Device}. Please have a
* look at {@link DeviceStateUpdate} to see what types is there and how the value {@link DeviceStateUpdate} will be
* evaluated.
* <br>
* It also updates the device if the command was send successful.
*
* @param device device which will send a command
* @param deviceStateUpdate command to send
*/
void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate);
/**
* This method adds a {@link SensorJob} with the appropriate priority to the {@link SensorJob}.
*
* @param sensorJob to update sensor data
* @param priority to update
*/
void updateSensorData(SensorJob sensorJob, String priority);
/**
* This method adds a {@link SensorJob} with the appropriate priority to the {@link SceneReadingJobExecutor}.
*
* @param device device which will update scene data
* @param deviceStateUpdate scene data to update
*/
void updateSceneData(Device device, DeviceStateUpdate deviceStateUpdate);
/**
* Registers the given {@link DeviceStatusListener} to the {@link Device}, if it exists or registers it as a
* device discovery, if the id of the {@link DeviceStatusListener} is {@link DeviceStatusListener#DEVICE_DISCOVERY}.
*
* @param deviceListener to rigister
*/
void registerDeviceListener(DeviceStatusListener deviceListener);
/**
* Unregisters the given {@link DeviceStatusListener} from the {@link Device}, if it exists or unregisters the
* device discovery, if the id of the {@link DeviceStatusListener} is {@link DeviceStatusListener#DEVICE_DISCOVERY}.
*
* @param deviceListener to unregister
*/
void unregisterDeviceListener(DeviceStatusListener deviceListener);
/**
* Registers the given {@link TotalPowerConsumptionListener} to this {@link DeviceStatusManager}.
*
* @param totalPowerConsumptionListener to register
*/
void registerTotalPowerConsumptionListener(TotalPowerConsumptionListener totalPowerConsumptionListener);
/**
* Unregisters the {@link TotalPowerConsumptionListener} from this {@link DeviceStatusManager}.
*/
void unregisterTotalPowerConsumptionListener();
/**
* Registers the given {@link SceneStatusListener} to the {@link InternalScene}, if it exists or registers it as a
* scene discovery to the {@link SceneManager}, if the id of the {@link SceneStatusListener} is
* {@link SceneStatusListener#SCENE_DISCOVERY}.
*
* @param sceneListener to register
*/
void registerSceneListener(SceneStatusListener sceneListener);
/**
* Unregisters the given {@link SceneStatusListener} from the {@link InternalScene} if it exist or unregisters the
* scene discovery from the {@link SceneManager}, if the id of the {@link SceneStatusListener} is
* {@link SceneStatusListener#SCENE_DISCOVERY}.
*
* @param sceneListener to unregister
*/
void unregisterSceneListener(SceneStatusListener sceneListener);
/**
* Registers the given {@link ConnectionListener} to the {@link ConnectionManager}.
*
* @param connectionListener to register
*/
void registerConnectionListener(ConnectionListener connectionListener);
/**
* Unregisters the {@link ConnectionListener} from the {@link ConnectionManager}.
*/
void unregisterConnectionListener();
/**
* Removes the {@link Device} with the given dSID from the internal model, if it exists.
*
* @param dSID of the {@link Device} which will be removed
*/
void removeDevice(String dSID);
/**
* Registers the given {@link ManagerStatusListener} to all available managers. What manager are available please
* have a look at {@link ManagerTypes}.
*
* @param statusListener to register
*/
void registerStatusListener(ManagerStatusListener statusListener);
/**
* Unregisters the {@link ManagerStatusListener} from all available managers. What manager are available please have
* a look at {@link ManagerTypes}.
*/
void unregisterStatusListener();
/**
* Returns the {@link ManagerTypes} of this class.
*
* @return these {@link ManagerTypes}
*/
ManagerTypes getManagerType();
/**
* Returns the current {@link ManagerStates}.
*
* @return current {@link ManagerStates}
*/
ManagerStates getManagerState();
/**
* Reads the current total power consumption out and returns it.
*
* @return the current total power consumption
*/
int getTotalPowerConsumption();
/**
* Reads the current total energy meter value in Wh out and returns it.
*
* @return the current total energy meter value Wh
*/
int getTotalEnergyMeterValue();
/**
* Reads the current total energy meter value in Ws out and returns it.
*
* @return the current total energy meter value in Ws
*/
int getTotalEnergyMeterWsValue();
}

View File

@@ -0,0 +1,252 @@
/**
* 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.digitalstrom.internal.lib.manager;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.event.EventHandler;
import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
/**
* The {@link SceneManager} manages all functions concerning scenes without sending the commands itself.
*
* <p>
* So it manages a list of all {@link InternalScene} they called in the past or was generated by calling
* {@link #generateScenes()}.<br>
* Through this class you can also register {@link SceneStatusListener}'s to the {@link InternalScene}'s or register a
* scene discovery. With {@link #addEcho(String)} or {@link #addEcho(String, short)} scene calls form the library can be
* ignored. To update the state of an {@link InternalScene} or {@link Device} the methods
* {@link #callInternalScene(InternalScene)}, {@link #callInternalScene(String)},
* {@link #callDeviceScene(Device, Short)}
* , {@link #callDeviceScene(String, Short)} etc. can be used.
*
* <p>
* If you call the {@link #start()} method a {@link EventListener} will be started to handle scene calls and undos from
* the outside.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public interface SceneManager extends EventHandler {
/**
* Activates the given {@link InternalScene}, if it exists. Otherwise it will be added to the scene list and
* activated, if it is a callable scene.
*
* @param scene to call
*/
void callInternalScene(InternalScene scene);
/**
* Activates a {@link InternalScene} with the given id, if it exists. Otherwise a new
* {@link InternalScene} will be created and activated, if it is a callable scene.
*
* @param sceneID of the scene to call
*/
void callInternalScene(String sceneID);
/**
* Call the given sceneID on the {@link Device} with the given dSID, if the {@link Device} exists.
*
* @param dSID of the {@link Device} to call
* @param sceneID of the scene to call
*/
void callDeviceScene(String dSID, Short sceneID);
/**
* Call the given sceneID on the given {@link Device}, if the {@link Device} exists.
*
* @param device to call
* @param sceneID to call
*/
void callDeviceScene(Device device, Short sceneID);
/**
* Deactivates the given {@link InternalScene}, if it exists. Otherwise it will added to the scene list and
* deactivated, if it is a callable scene.
*
* @param scene to undo
*/
void undoInternalScene(InternalScene scene);
/**
* Deactivates a {@link InternalScene} with the given sceneID, if it exists. Otherwise a new
* {@link InternalScene} will be created and deactivated, if it is a callable scene.
*
* @param sceneID of the scene to undo
*/
void undoInternalScene(String sceneID);
/**
* Undo the last scene on the {@link Device} with the given dSID, if the {@link Device} exists.
*
* @param dSID of the {@link Device} to undo
*/
void undoDeviceScene(String dSID);
/**
* Undo the last scene on the {@link Device}, if the {@link Device} exists.
*
* @param device the {@link Device} to undo
*/
void undoDeviceScene(Device device);
/**
* Registers the given {@link SceneStatusListener} to the {@link InternalScene}, if it exists or registers it as a
* Scene-Discovery if the id of the {@link SceneStatusListener} is {@link SceneStatusListener#SCENE_DISCOVERY}.
*
* @param sceneListener to register
*/
void registerSceneListener(SceneStatusListener sceneListener);
/**
* Unregisters the given {@link SceneStatusListener} from the {@link InternalScene}, if it exists or unregisters the
* Scene-Discovery, if the id of the {@link SceneStatusListener} is {@link SceneStatusListener#SCENE_DISCOVERY}.
*
* @param sceneListener to register
*/
void unregisterSceneListener(SceneStatusListener sceneListener);
/**
* Adds the given {@link InternalScene} to the scene list, if it is a callable scene.
*
* @param intScene to add
*/
void addInternalScene(InternalScene intScene);
/**
* Adds the scene call with the given dSID and sceneId as an echo to ignore them by detecting the {@link EventItem}.
*
* @param dSID of the {@link Device} that will be ignored
* @param sceneId of the scene that will be ignored
*/
void addEcho(String dSID, short sceneId);
/**
* Adds the scene call with the given internal scene id as an echo to ignore them by detecting the {@link EventItem}
* .
*
* @param internalSceneID to ignore
*/
void addEcho(String internalSceneID);
/**
* Returns the list of all {@link InternalScene}.
*
* @return list of all scenes
*/
List<InternalScene> getScenes();
/**
* Returns true, if all reachable scenes are already generated, otherwise false.
*
* @return true = reachable scenes generated, otherwise false
*/
boolean scenesGenerated();
/**
* Generates all reachable scenes.
*
*/
void generateScenes();
/**
* Will be called from the {@link SceneDiscovery}, if a scene type is generated or is fail.<br>
* For that the scenesGenerated char array has four chars. Each char represents one scene type in the following
* direction:
* <ul>
* <li><b>first:</b> named scenes</li>
* <li><b>second:</b> apartment scenes</li>
* <li><b>third:</b> zone scenes</li>
* <li><b>fourth</b>: group scenes, if they can call by push buttons</li>
* </ul>
* If a scene type is not generated the char is "0". If a scene type is generated the char is "1" and, if it is fail
* the char is "2".
*
* @param scenesGenerated array
*/
void scenesGenerated(char[] scenesGenerated);
/**
* Returns true, if a discovery is registered, otherwise false.
*
* @return true discovery is registered, otherwise false
*/
boolean isDiscoveryRegistrated();
/**
* Starts the {@link EventListener}.
*/
void start();
/**
* Stops the {@link EventListener}.
*/
void stop();
/**
* Removes the {@link InternalScene} with the given sceneID.
*
* @param sceneID of the {@link InternalScene} to remove
*/
void removeInternalScene(String sceneID);
/**
* Returns the {@link InternalScene} with the given sceneID.
*
* @param sceneID of the {@link InternalScene}
* @return internal scenes
*/
InternalScene getInternalScene(String sceneID);
/**
* Registers the given {@link ManagerStatusListener} to this class.
*
* @param statusListener to register
*/
void registerStatusListener(ManagerStatusListener statusListener);
/**
* Unregisters the {@link ManagerStatusListener} from this class.
*/
void unregisterStatusListener();
/**
* Returns the {@link ManagerTypes} of this class.
*
* @return these {@link ManagerTypes}
*/
ManagerTypes getManagerType();
/**
* Returns the current {@link ManagerStates}.
*
* @return current {@link ManagerStates}
*/
ManagerStates getManagerState();
/**
* Calls a scene without inform the scene discovery about the conceivably new {@link InternalScene}.
*
* @param zoneID to call
* @param groupID to call
* @param sceneID to call
*/
void callInternalSceneWithoutDiscovery(Integer zoneID, Short groupID, Short sceneID);
}

View File

@@ -0,0 +1,267 @@
/**
* 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.digitalstrom.internal.lib.manager;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
/**
* The {@link StructureManager} builds the internal model of the digitalSTROM-System.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface StructureManager {
/**
* Generates the zone- and group-names.
*
* @param connectionManager must not be null
* @return true, if it's generated, otherwise false
*/
boolean generateZoneGroupNames(ConnectionManager connectionManager);
/**
* Returns the name of a zone or null, if the given zoneID dose not exists.<br>
* Note: Zone-names have to be generated over {@link #generateZoneGroupNames(ConnectionManager)}.
*
* @param zoneID of the zone
* @return zone-name
*/
String getZoneName(int zoneID);
/**
* Returns the id of a given zone-name or -1, if the given zone-name dose not exists.<br>
* Note: Zone-names have to be generated over {@link #generateZoneGroupNames(ConnectionManager)}.
*
* @param zoneName of the zone
* @return zoneID
*/
int getZoneId(String zoneName);
/**
* Returns the name of the given groupID from the given zoneID or null, if the zoneID or groupID dose not exists.
* <br>
* Note: Zone-group-names have to be generated over {@link #generateZoneGroupNames(ConnectionManager)}.
*
* @param zoneID of the group
* @param groupID of the group
* @return group-name
*/
String getZoneGroupName(int zoneID, short groupID);
/**
* Returns the groupID of the given group-name from the given zone name or -1, if the zone-name or group name dose
* not exists.<br>
* Note: Zone-group-names have to be generated over {@link #generateZoneGroupNames(ConnectionManager)}.
*
* @param zoneName of the group
* @param groupName of the group
* @return group-id
*/
short getZoneGroupId(String zoneName, String groupName);
/**
* Returns a new {@link Map} of all {@link Device}'s with the {@link DSID} as key and the {@link Device} as value.
* If no devices are found, an empty {@link Map} will be returned.
*
* @return device-map (cannot be null)
*/
Map<DSID, Device> getDeviceMap();
/**
* Returns a reference to the {@link Map} of all {@link Device}'s with the {@link DSID} as key and the
* {@link Device} as value. If no devices are found, an empty {@link Map} will be returned.
*
* @return reference device-map
*/
Map<DSID, Device> getDeviceHashMapReference();
/**
* Returns the reference of the structure as {@link Map}[zoneID, {@link Map}[groupID,
* {@link List}[{@link Device}]]].
*
* @return structure reference
*/
Map<Integer, Map<Short, List<Device>>> getStructureReference();
/**
* Returns the Map of all groups as format HashMap[Short, List[Device]].
*
* @param zoneID of the zone
* @return groups
*/
Map<Short, List<Device>> getGroupsFromZoneX(int zoneID);
/**
* Returns the reference {@link List} of the {@link Device}'s of an zone-group.
*
* @param zoneID of the zone
* @param groupID of the group
* @return reference device-list
*/
List<Device> getReferenceDeviceListFromZoneXGroupX(int zoneID, short groupID);
/**
* Returns the {@link Device} of the given dSID as {@link String} or null if no {@link Device} exists.
*
* @param dSID of the device
* @return device
*/
Device getDeviceByDSID(String dSID);
/**
* Returns the {@link Device} of the given dSID as {@link DSID} or null if no {@link Device} exists.
*
* @param dSID of the device
* @return device
*/
Device getDeviceByDSID(DSID dSID);
/**
* Returns the {@link Device} of the given dSUID or null if no {@link Device} exists.
*
* @param dSUID of the device
* @return the {@link Device} with the given dSUID
*/
Device getDeviceByDSUID(String dSUID);
/**
* Updates a {@link Device} of the structure.
*
* @param oldZone ID
* @param oldGroups ID's
* @param device new {@link Device}
*/
void updateDevice(int oldZone, List<Short> oldGroups, Device device);
/**
* Updates a {@link Device} of the structure.
*
* @param device to update
*/
void updateDevice(Device device);
/**
* Deletes a {@link Device} from the structure.
*
* @param device to delete
*/
void deleteDevice(Device device);
/**
* Adds a {@link Device} to the structure.
*
* @param device to add
*/
void addDeviceToStructure(Device device);
/**
* Returns a {@link Set} of all zoneID's
*
* @return zoneID's
*/
Set<Integer> getZoneIDs();
/**
* Returns true, if a zone with the given zoneID exists, otherwise false.
*
* @param zoneID to check
* @return true = zoneID exists | false = zoneID not exists
*/
boolean checkZoneID(int zoneID);
/**
* Returns true, if a zone-group with the given zoneID and groupID exists, otherwise false.
*
* @param zoneID to check
* @param groupID to check
* @return true = zoneID or groupID exists | false = zoneID or groupID not exists
*/
boolean checkZoneGroupID(int zoneID, short groupID);
/**
* Adds the given {@link List} of {@link Circuit}'s to this {@link StructureManager}.
*
* @param referenceCircuitList to add
*/
void addCircuitList(List<Circuit> referenceCircuitList);
/**
* Adds the given {@link Circuit} to this {@link StructureManager}.
*
* @param circuit to add
* @return the old {@link Circuit}, if the given {@link Circuit} was already added.
*/
Circuit addCircuit(Circuit circuit);
/**
* Returns the {@link Circuit} with the given {@link DSID}.
*
* @param dSID of the {@link Circuit} to get
* @return the {@link Circuit} with the given {@link DSID}
*/
Circuit getCircuitByDSID(DSID dSID);
/**
* Returns the {@link Circuit} with the given dSID as {@link String}.
*
* @param dSID of the {@link Circuit} to get
* @return the {@link Circuit} with the given dSID
*/
Circuit getCircuitByDSID(String dSID);
/**
* Returns the {@link Circuit} with the given dSUID as {@link String}.
*
* @param dSUID of the {@link Circuit} to get
* @return the {@link Circuit} with the given dSUID
*/
Circuit getCircuitByDSUID(String dSUID);
/**
* Updates the configuration of an added {@link Circuit} through a new {@link Circuit} object.
*
* @param newCircuit to update
* @return {@link Circuit} with the old configuration
*/
Circuit updateCircuitConfig(Circuit newCircuit);
/**
* Deletes the {@link Circuit} with the given {@link DSID}.
*
* @param dSID of the {@link Circuit} to remove
* @return the removed {@link Circuit}
*/
Circuit deleteCircuit(DSID dSID);
/**
* Deletes the {@link Circuit} with the given dSUID.
*
* @param dSUID of the {@link Circuit} to remove
* @return the removed {@link Circuit}
*/
Circuit deleteCircuit(String dSUID);
/**
* Returns a {@link Map} of all {@link Circuit}'s which are added to this {@link StructureManager}.
*
* @return {@link Map} of all added {@link Circuit}'s
*/
Map<DSID, Circuit> getCircuitMap();
}

View File

@@ -0,0 +1,542 @@
/**
* 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.digitalstrom.internal.lib.manager.impl;
import java.net.HttpURLConnection;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.HttpTransport;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.impl.DsAPIImpl;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.impl.HttpTransportImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* The {@link ConnectionManagerImpl} is the implementation of the {@link ConnectionManager}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class ConnectionManagerImpl implements ConnectionManager {
/**
* Query to get all enabled application tokens. Can be executed with {@link DsAPI#query(String, String)} or
* {@link DsAPI#query2(String, String)}.
*/
public final String QUERY_GET_ENABLED_APPLICATION_TOKENS = "/system/security/applicationTokens/enabled/*(*)";
private final Logger logger = LoggerFactory.getLogger(ConnectionManagerImpl.class);
private Config config;
private ConnectionListener connListener;
private HttpTransport transport;
private String sessionToken;
private Boolean connectionEstablished = false;
private boolean genAppToken;
private DsAPI digitalSTROMClient;
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String)}, but the connection
* timeout and read timeout can be set, too.
*
* @param hostArddress (must not be null)
* @param connectTimeout (if connectTimeout is lower than 0 the {@link Config#DEFAULT_CONNECTION_TIMEOUT} will be
* set)
* @param readTimeout (if readTimeout is lower than 0 the {@link Config#DEFAULT_CONNECTION_TIMEOUT} will be set)
* @param username (can be null, if application token is set)
* @param password (can be null, if application token is set
* @param applicationToken (can be null, if username and password is set)
* @see #ConnectionManagerImpl(String, String, String, String)
*/
public ConnectionManagerImpl(String hostArddress, int connectTimeout, int readTimeout, String username,
String password, String applicationToken) {
init(hostArddress, connectTimeout, readTimeout, username, password, applicationToken, false);
}
/**
* Creates a new {@link ConnectionManagerImpl} through a {@link Config} object, which has all configurations set.
*
* @param config (must not be null)
*/
public ConnectionManagerImpl(Config config) {
init(config, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(Config)}, but a {@link ConnectionListener} can be
* registered, too.
*
* @param config (must not be null)
* @param connectionListener (can be null)
* @see #ConnectionManagerImpl(Config)
*/
public ConnectionManagerImpl(Config config, ConnectionListener connectionListener) {
this.connListener = connectionListener;
init(config, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(Config, ConnectionListener)}, but through genApToken it
* can be set, if a application token will be automatically generated.
*
* @param config (must not be null)
* @param connectionListener (can be null)
* @param genAppToken (true = application token will be generated, otherwise false)
* @see #ConnectionManagerImpl(Config, ConnectionListener)
*/
public ConnectionManagerImpl(Config config, ConnectionListener connectionListener, boolean genAppToken) {
this.connListener = connectionListener;
this.genAppToken = genAppToken;
init(config, false);
}
/**
* Creates a new {@link ConnectionManagerImpl} with the given parameters, which are needed to create the
* {@link HttpTransport} and to login into the digitalSTROM server. If the application token is null and the
* username and password are valid, a application token will be automatically generated or a existing application
* token for the at {@link Config#getApplicationName()} set application name will be set.
*
* @param hostAddress (must not be null)
* @param username (can be null, if application token is set)
* @param password (can be null, if application token is set
* @param applicationToken (can be null, if username and password is set)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken) {
init(hostAddress, -1, -1, username, password, applicationToken, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String)}, but without username
* and password.
*
* @param hostAddress (must not be null)
* @param applicationToken (must not be null)
*/
public ConnectionManagerImpl(String hostAddress, String applicationToken) {
init(hostAddress, -1, -1, null, null, applicationToken, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String)}, but without application
* token.
*
* @param hostAddress (must not be null)
* @param username (must not be null)
* @param password (must not be null)
* @see #ConnectionManagerImpl(String, String, String, String)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password) {
init(hostAddress, -1, -1, username, password, null, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String)}, but a
* {@link ConnectionListener} can be set, too.
*
* @param hostAddress (must not be null)
* @param username (must not be null)
* @param password (must not be null)
* @param connectionListener (can be null)
* @see #ConnectionManagerImpl(String, String, String)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password,
ConnectionListener connectionListener) {
this.connListener = connectionListener;
init(hostAddress, -1, -1, username, password, null, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String)}, but a
* {@link ConnectionListener} can be set, too.
*
* @param hostAddress (must not be null)
* @param username (can be null, if application token is set)
* @param password (can be null, if application token is set)
* @param applicationToken (can be null, if username and password is set)
* @param connectionListener (can be null)
* @see #ConnectionManagerImpl(String, String, String, String)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
ConnectionListener connectionListener) {
this.connListener = connectionListener;
init(hostAddress, -1, -1, username, password, null, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String)}, but through genApToken it
* can be set, if a application token will be automatically generated.
*
* @param hostAddress (must not be null)
* @param username (must not be null)
* @param password (must not be null)
* @param genAppToken (true = application token will be generated, otherwise false)
* @see #ConnectionManagerImpl(String, String, String, String)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password, boolean genAppToken) {
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, null, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String)}, but through genApToken
* it can be set, if a application token will be automatically generated.
*
* @param hostAddress (must not be null)
* @param username (can be null, if application token is set)
* @param password (can be null, if application token is set)
* @param applicationToken (can be null, if username and password is set)
* @param genAppToken (true = application token will be generated, otherwise false)
* @see #ConnectionManagerImpl(String, String, String, String)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
boolean genAppToken) {
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, applicationToken, false);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String, boolean)}, but through
* acceptAllCerts it can be set, if all SSL-Certificates will be accept.
*
* @param hostAddress (must not be null)
* @param username (can be null, if application token is set)
* @param password (can be null, if application token is set)
* @param applicationToken (can be null, if username and password is set)
* @param genAppToken (true = application token will be generated, otherwise false)
* @param acceptAllCerts (true = all SSL-Certificates will be accept, otherwise false)
* @see #ConnectionManagerImpl(String, String, String, String, boolean)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
boolean genAppToken, boolean acceptAllCerts) {
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, applicationToken, acceptAllCerts);
}
/**
* The same constructor like {@link #ConnectionManagerImpl(String, String, String, String, boolean)}, but a
* {@link ConnectionListener} can be set, too.
*
* @param hostAddress (must not be null)
* @param username (can be null, if application token is set)
* @param password (can be null, if application token is set)
* @param applicationToken (can be null, if username and password is set)
* @param genAppToken (true = application token will be generated, otherwise false)
* @param connectionListener (can be null)
* @see #ConnectionManagerImpl(String, String, String, String, boolean)
*/
public ConnectionManagerImpl(String hostAddress, String username, String password, String applicationToken,
boolean genAppToken, ConnectionListener connectionListener) {
this.connListener = connectionListener;
this.genAppToken = genAppToken;
init(hostAddress, -1, -1, username, password, applicationToken, false);
}
private void init(String hostAddress, int connectionTimeout, int readTimeout, String username, String password,
String applicationToken, boolean acceptAllCerts) {
config = new Config(hostAddress, username, password, applicationToken);
if (connectionTimeout >= 0) {
config.setConnectionTimeout(connectionTimeout);
}
if (readTimeout >= 0) {
config.setReadTimeout(readTimeout);
}
init(config, acceptAllCerts);
}
private void init(Config config, boolean acceptAllCerts) {
this.config = config;
this.transport = new HttpTransportImpl(this, acceptAllCerts);
this.digitalSTROMClient = new DsAPIImpl(transport);
if (this.genAppToken) {
this.onNotAuthenticated();
}
}
@Override
public HttpTransport getHttpTransport() {
return transport;
}
@Override
public DsAPI getDigitalSTROMAPI() {
return this.digitalSTROMClient;
}
@Override
public String getSessionToken() {
return this.sessionToken;
}
@Override
public String getNewSessionToken() {
if (this.genAppToken) {
if (StringUtils.isNotBlank(config.getAppToken())) {
sessionToken = this.digitalSTROMClient.loginApplication(config.getAppToken());
} else if (codeIsAuthentificationFaild()) {
onNotAuthenticated();
}
} else {
sessionToken = this.digitalSTROMClient.login(this.config.getUserName(), this.config.getPassword());
}
return sessionToken;
}
@Override
public synchronized boolean checkConnection() {
return checkConnection(this.digitalSTROMClient.checkConnection(null));
}
private final short code = HttpURLConnection.HTTP_OK;
private boolean codeIsAuthentificationFaild() {
return this.code == HttpURLConnection.HTTP_FORBIDDEN;
}
@Override
public boolean checkConnection(int code) {
switch (code) {
case HttpURLConnection.HTTP_INTERNAL_ERROR:
case HttpURLConnection.HTTP_OK:
if (!connectionEstablished) {
onConnectionResumed();
}
break;
case HttpURLConnection.HTTP_UNAUTHORIZED:
connectionEstablished = false;
break;
case HttpURLConnection.HTTP_FORBIDDEN:
getNewSessionToken();
if (sessionToken != null) {
if (!connectionEstablished) {
onConnectionResumed();
}
} else {
if (this.genAppToken) {
onNotAuthenticated();
}
connectionEstablished = false;
}
break;
case ConnectionManager.MALFORMED_URL_EXCEPTION:
onConnectionLost(ConnectionListener.INVALID_URL);
break;
case ConnectionManager.CONNECTION_EXCEPTION:
case ConnectionManager.SOCKET_TIMEOUT_EXCEPTION:
onConnectionLost(ConnectionListener.CONNECTON_TIMEOUT);
break;
case ConnectionManager.SSL_HANDSHAKE_EXCEPTION:
onConnectionLost(ConnectionListener.SSL_HANDSHAKE_ERROR);
break;
case ConnectionManager.GENERAL_EXCEPTION:
onConnectionLost(ConnectionListener.CONNECTION_LOST);
break;
case ConnectionManager.UNKNOWN_HOST_EXCEPTION:
onConnectionLost(ConnectionListener.UNKNOWN_HOST);
break;
case ConnectionManager.AUTHENTIFICATION_PROBLEM:
if (connListener != null) {
if (config.getAppToken() != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.WRONG_APP_TOKEN);
} else {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.WRONG_USER_OR_PASSWORD);
}
}
break;
case HttpURLConnection.HTTP_NOT_FOUND:
onConnectionLost(ConnectionListener.HOST_NOT_FOUND);
break;
}
return connectionEstablished;
}
@Override
public boolean connectionEstablished() {
return connectionEstablished;
}
/**
* This method is called whenever the connection to the digitalSTROM-Server is available,
* but requests are not allowed due to a missing or invalid authentication.
*/
private void onNotAuthenticated() {
String applicationToken = null;
boolean isAuthenticated = false;
if (StringUtils.isNotBlank(config.getAppToken())) {
sessionToken = digitalSTROMClient.loginApplication(config.getAppToken());
if (sessionToken != null) {
isAuthenticated = true;
} else {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.WRONG_APP_TOKEN);
if (!checkUserPassword()) {
return;
}
}
}
}
if (checkUserPassword()) {
if (!isAuthenticated) {
// if an application-token for the application exists, use this application-token and test host is
// reachable
logger.debug("check existing application-tokens");
sessionToken = digitalSTROMClient.login(config.getUserName(), config.getPassword());
if (sessionToken != null) {
JsonObject jObj = digitalSTROMClient.query(sessionToken, QUERY_GET_ENABLED_APPLICATION_TOKENS);
if (jObj != null) {
if (jObj.get("enabled") != null && jObj.get("enabled").isJsonArray()) {
JsonArray jArray = jObj.get("enabled").getAsJsonArray();
// application-token check
for (int i = 0; i < jArray.size(); i++) {
JsonObject appToken = jArray.get(i).getAsJsonObject();
if (appToken.get("applicationName") != null && appToken.get("applicationName")
.getAsString().equals(config.getApplicationName())) {
// found application-token, set as application-token
applicationToken = appToken.get("token").getAsString();
logger.debug("found application-token {} for application {}", applicationToken,
config.getApplicationName());
break;
}
}
}
if (applicationToken == null) {
// no token found, generate applicationToken
applicationToken = this.digitalSTROMClient
.requestAppplicationToken(config.getApplicationName());
logger.debug(
"no application-token for application {} found, generate a application-token {}",
config.getApplicationName(), applicationToken);
if (StringUtils.isNotBlank(applicationToken)) {
// enable applicationToken
if (!digitalSTROMClient.enableApplicationToken(applicationToken,
digitalSTROMClient.login(config.getUserName(), config.getPassword()))) {
// if enable failed set application-token = null so thats not will be set
applicationToken = null;
}
}
}
if (applicationToken != null) {
logger.debug("application-token can be used");
config.setAppToken(applicationToken);
isAuthenticated = true;
}
}
} else {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.WRONG_USER_OR_PASSWORD);
return;
}
}
}
// remove password and username, to don't store them persistently
if (isAuthenticated) {
config.removeUsernameAndPassword();
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.APPLICATION_TOKEN_GENERATED);
}
}
} else if (!isAuthenticated) {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.NOT_AUTHENTICATED,
ConnectionListener.NO_USER_PASSWORD);
}
}
}
private boolean checkUserPassword() {
if (StringUtils.isNotBlank(config.getUserName()) && StringUtils.isNotBlank(config.getPassword())) {
return true;
}
return false;
}
/**
* This method is called whenever the connection to the digitalSTROM-Server is lost.
*
* @param reason
*/
private void onConnectionLost(String reason) {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.CONNECTION_LOST, reason);
}
connectionEstablished = false;
}
/**
* This method is called whenever the connection to the digitalSTROM-Server is resumed.
*/
private void onConnectionResumed() {
if (connListener != null) {
connListener.onConnectionStateChange(ConnectionListener.CONNECTION_RESUMED);
}
connectionEstablished = true;
}
@Override
public void registerConnectionListener(ConnectionListener listener) {
this.connListener = listener;
}
@Override
public void unregisterConnectionListener() {
this.connListener = null;
}
@Override
public String getApplicationToken() {
return config.getAppToken();
}
@Override
public boolean removeApplicationToken() {
if (StringUtils.isNotBlank(config.getAppToken())) {
return digitalSTROMClient.revokeToken(config.getAppToken(), null);
}
return true;
}
@Override
public void updateConfig(String host, String username, String password, String applicationToken) {
init(host, -1, -1, username, password, applicationToken, false);
}
@Override
public void updateConfig(Config config) {
if (this.config != null) {
this.config.updateConfig(config);
} else {
this.config = config;
}
init(this.config, false);
}
@Override
public void configHasBeenUpdated() {
init(this.config, false);
}
@Override
public Config getConfig() {
return this.config;
}
}

View File

@@ -0,0 +1,556 @@
/**
* 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.digitalstrom.internal.lib.manager.impl;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventNames;
import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventResponseEnum;
import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.SceneDiscovery;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SceneManagerImpl} is the implementation of the {@link SceneManager}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public class SceneManagerImpl implements SceneManager {
/**
* Contains all supported event-types.
*/
public static final List<String> SUPPORTED_EVENTS = Arrays.asList(EventNames.CALL_SCENE, EventNames.UNDO_SCENE);
private final Logger logger = LoggerFactory.getLogger(SceneManagerImpl.class);
private final List<String> echoBox = Collections.synchronizedList(new LinkedList<>());
private final Map<String, InternalScene> internalSceneMap = Collections.synchronizedMap(new HashMap<>());
private EventListener eventListener;
private final StructureManager structureManager;
private final ConnectionManager connectionManager;
private final SceneDiscovery discovery;
private ManagerStatusListener statusListener;
private ManagerStates state = ManagerStates.STOPPED;
private boolean scenesGenerated = false;
/**
* Creates a new {@link SceneManagerImpl} through the given managers.
*
* @param connectionManager (must not be null)
* @param structureManager (must not be null)
*/
public SceneManagerImpl(ConnectionManager connectionManager, StructureManager structureManager) {
this.structureManager = structureManager;
this.connectionManager = connectionManager;
this.discovery = new SceneDiscovery(this);
}
/**
* Same constructor like {@link #SceneManagerImpl(ConnectionManager, StructureManager)}, but a
* {@link ManagerStatusListener} can be set, too.
*
* @param connectionManager (must not be null)
* @param structureManager (must not be null)
* @param statusListener (can be null)
* @see #SceneManagerImpl(ConnectionManager, StructureManager)
*/
public SceneManagerImpl(ConnectionManager connectionManager, StructureManager structureManager,
ManagerStatusListener statusListener) {
this.structureManager = structureManager;
this.connectionManager = connectionManager;
this.discovery = new SceneDiscovery(this);
this.statusListener = statusListener;
}
/**
* Same constructor like {@link #SceneManagerImpl(ConnectionManager, StructureManager, ManagerStatusListener)}, but
* a {@link EventListener} can be set, too.
*
* @param connectionManager (must not be null)
* @param structureManager (must not be null)
* @param statusListener (can be null)
* @param eventListener (can be null)
* @see #SceneManagerImpl(ConnectionManager, StructureManager, ManagerStatusListener)
*/
public SceneManagerImpl(ConnectionManager connectionManager, StructureManager structureManager,
ManagerStatusListener statusListener, EventListener eventListener) {
this.structureManager = structureManager;
this.connectionManager = connectionManager;
this.discovery = new SceneDiscovery(this);
this.statusListener = statusListener;
this.eventListener = eventListener;
}
@Override
public void start() {
logger.debug("start SceneManager");
if (eventListener == null) {
logger.debug("no EventListener is set, create a new EventListener");
eventListener = new EventListener(connectionManager, this);
} else {
logger.debug("EventListener is set, add this SceneManager as EventHandler");
eventListener.addEventHandler(this);
}
eventListener.start();
logger.debug("start SceneManager");
stateChanged(ManagerStates.RUNNING);
}
@Override
public void stop() {
logger.debug("stop SceneManager");
if (eventListener != null) {
eventListener.removeEventHandler(this);
}
this.discovery.stop();
this.stateChanged(ManagerStates.STOPPED);
}
@Override
public void handleEvent(EventItem eventItem) {
if (eventItem == null) {
return;
}
boolean isCallScene = true;
String isCallStr = eventItem.getName();
if (isCallStr != null) {
isCallScene = isCallStr.equals(EventNames.CALL_SCENE);
}
boolean isDeviceCall = false;
String deviceCallStr = eventItem.getSource().get(EventResponseEnum.IS_DEVICE);
if (deviceCallStr != null) {
isDeviceCall = Boolean.parseBoolean(deviceCallStr);
}
if (isDeviceCall) {
String dsidStr = null;
dsidStr = eventItem.getSource().get(EventResponseEnum.DSID);
short sceneId = -1;
String sceneStr = eventItem.getProperties().get(EventResponseEnum.SCENEID);
if (sceneStr != null) {
try {
sceneId = Short.parseShort(sceneStr);
} catch (java.lang.NumberFormatException e) {
logger.error("An exception occurred, while handling event at parsing sceneID: {}", sceneStr, e);
}
}
if (!isEcho(dsidStr, sceneId)) {
logger.debug("{} event for device: {}", eventItem.getName(), dsidStr);
if (isCallScene) {
this.callDeviceScene(dsidStr, sceneId);
} else {
this.undoDeviceScene(dsidStr);
}
}
} else {
String intSceneID = null;
String zoneIDStr = eventItem.getSource().get(EventResponseEnum.ZONEID);
String groupIDStr = eventItem.getSource().get(EventResponseEnum.GROUPID);
String sceneIDStr = eventItem.getProperties().get(EventResponseEnum.SCENEID);
if (zoneIDStr != null && sceneIDStr != null && groupIDStr != null) {
intSceneID = zoneIDStr + "-" + groupIDStr + "-" + sceneIDStr;
if (!isEcho(intSceneID)) {
logger.debug("{} event for scene: {}-{}-{}", eventItem.getName(), zoneIDStr, groupIDStr,
sceneIDStr);
if (isCallScene) {
this.callInternalScene(intSceneID);
} else {
this.undoInternalScene(intSceneID);
}
}
}
}
}
private boolean isEcho(String dsid, short sceneId) {
// sometimes the dS-event has a dSUID saved in the dSID
String echo = (structureManager.getDeviceByDSUID(dsid) != null
? structureManager.getDeviceByDSUID(dsid).getDSID().getValue()
: dsid) + "-" + sceneId;
logger.debug("An echo scene event was detected: {}", echo);
return isEcho(echo);
}
private boolean isEcho(String echoID) {
if (echoBox.contains(echoID)) {
echoBox.remove(echoID);
return true;
}
return false;
}
// ... we want to ignore own 'command-echos'
@Override
public void addEcho(String dsid, short sceneId) {
addEcho(dsid + "-" + sceneId);
}
// ... we want to ignore own 'command-echos'
@Override
public void addEcho(String internalSceneID) {
echoBox.add(internalSceneID);
}
@Override
public void callInternalScene(InternalScene scene) {
InternalScene intScene = this.internalSceneMap.get(scene.getID());
if (intScene != null) {
intScene.activateScene();
} else {
if (SceneEnum.getScene(scene.getSceneID()) != null
&& structureManager.checkZoneGroupID(scene.getZoneID(), scene.getGroupID())) {
scene.addReferenceDevices(this.structureManager.getReferenceDeviceListFromZoneXGroupX(scene.getZoneID(),
scene.getGroupID()));
this.internalSceneMap.put(scene.getID(), scene);
scene.activateScene();
}
}
}
@Override
public void callInternalSceneWithoutDiscovery(Integer zoneID, Short groupID, Short sceneID) {
InternalScene intScene = this.internalSceneMap.get(zoneID + "-" + groupID + "-" + sceneID);
if (intScene != null) {
intScene.activateScene();
} else {
InternalScene scene = new InternalScene(zoneID, groupID, sceneID, null);
if (structureManager.checkZoneGroupID(scene.getZoneID(), scene.getGroupID())) {
scene.addReferenceDevices(this.structureManager.getReferenceDeviceListFromZoneXGroupX(scene.getZoneID(),
scene.getGroupID()));
scene.activateScene();
}
}
}
@Override
public void callInternalScene(String sceneID) {
InternalScene intScene = this.internalSceneMap.get(sceneID);
if (intScene != null) {
logger.debug("activating existing scene {}", intScene.getSceneName());
intScene.activateScene();
} else {
intScene = createNewScene(sceneID);
if (intScene != null) {
logger.debug("created new scene, activating it: {}", intScene.getSceneName());
discovery.sceneDiscoverd(intScene);
intScene.activateScene();
}
}
}
@Override
public void addInternalScene(InternalScene intScene) {
if (!this.internalSceneMap.containsKey(intScene.getID())) {
if (SceneEnum.getScene(intScene.getSceneID()) != null
&& structureManager.checkZoneGroupID(intScene.getZoneID(), intScene.getGroupID())) {
intScene.addReferenceDevices(this.structureManager
.getReferenceDeviceListFromZoneXGroupX(intScene.getZoneID(), intScene.getGroupID()));
this.internalSceneMap.put(intScene.getID(), intScene);
}
} else {
InternalScene oldScene = this.internalSceneMap.get(intScene.getID());
String oldSceneName = this.internalSceneMap.get(intScene.getID()).getSceneName();
String newSceneName = intScene.getSceneName();
if ((oldSceneName.contains("Zone:") && oldSceneName.contains("Group:") && oldSceneName.contains("Scene:"))
&& !(newSceneName.contains("Zone:") && newSceneName.contains("Group:")
&& newSceneName.contains("Scene:"))) {
oldScene.setSceneName(newSceneName);
this.discovery.sceneDiscoverd(oldScene);
}
}
}
@Override
public void removeInternalScene(String sceneID) {
this.internalSceneMap.remove(sceneID);
}
@Override
public InternalScene getInternalScene(String sceneID) {
return this.internalSceneMap.get(sceneID);
}
private InternalScene createNewScene(String sceneID) {
String[] sceneData = sceneID.split("-");
if (sceneData.length == 3) {
int zoneID = Integer.parseInt(sceneData[0]);
short groupID = Short.parseShort(sceneData[1]);
short sceneNumber = Short.parseShort(sceneData[2]);
String sceneName = null;
sceneName = connectionManager.getDigitalSTROMAPI().getSceneName(connectionManager.getSessionToken(), zoneID,
null, groupID, sceneNumber);
InternalScene intScene = null;
if (SceneEnum.getScene(sceneNumber) != null && structureManager.checkZoneGroupID(zoneID, groupID)) {
if (sceneName == null) {
if (structureManager.getZoneName(zoneID) != null) {
sceneName = "Zone: " + structureManager.getZoneName(zoneID);
if (structureManager.getZoneGroupName(zoneID, groupID) != null) {
sceneName = sceneName + " Group: " + structureManager.getZoneGroupName(zoneID, groupID);
} else {
sceneName = sceneName + " Group: " + groupID;
}
} else {
if (structureManager.getZoneGroupName(zoneID, groupID) != null) {
sceneName = "Zone: " + zoneID + " Group: "
+ structureManager.getZoneGroupName(zoneID, groupID);
} else {
sceneName = "Zone: " + zoneID + " Group: " + groupID;
}
}
sceneName = sceneName + " Scene: "
+ SceneEnum.getScene(sceneNumber).toString().toLowerCase().replace("_", " ");
}
intScene = new InternalScene(zoneID, groupID, sceneNumber, sceneName);
}
return intScene;
}
return null;
}
@Override
public void callDeviceScene(String dSID, Short sceneID) {
Device device = this.structureManager.getDeviceByDSID(new DSID(dSID));
if (device != null) {
device.internalCallScene(sceneID);
} else {
device = this.structureManager.getDeviceByDSUID(dSID);
if (device != null) {
device.internalCallScene(sceneID);
}
}
}
@Override
public void callDeviceScene(Device device, Short sceneID) {
if (device != null) {
callDeviceScene(device.getDSID().toString(), sceneID);
}
}
@Override
public void undoInternalScene(InternalScene scene) {
if (scene != null) {
undoInternalScene(scene.getID());
}
}
@Override
public void undoInternalScene(String sceneID) {
InternalScene intScene = this.internalSceneMap.get(sceneID);
if (intScene != null) {
logger.debug("deactivating existing scene {}", intScene.getSceneName());
intScene.deactivateScene();
} else {
intScene = createNewScene(sceneID);
if (intScene != null) {
logger.debug("created new scene, deactivating it: {}", intScene.getSceneName());
intScene.deactivateScene();
}
}
}
@Override
public void undoDeviceScene(String dSID) {
Device device = this.structureManager.getDeviceByDSID(new DSID(dSID));
if (device != null) {
device.internalUndoScene();
} else {
device = this.structureManager.getDeviceByDSUID(dSID);
if (device != null) {
device.internalUndoScene();
}
}
}
@Override
public void undoDeviceScene(Device device) {
if (device != null) {
undoDeviceScene(device.getDSID().toString());
}
}
@Override
public void registerSceneListener(SceneStatusListener sceneListener) {
if (sceneListener != null) {
String id = sceneListener.getSceneStatusListenerID();
if (id.equals(SceneStatusListener.SCENE_DISCOVERY)) {
discovery.registerSceneDiscovery(sceneListener);
logger.debug("Scene-Discovery registrated");
for (InternalScene scene : internalSceneMap.values()) {
discovery.sceneDiscoverd(scene);
}
} else {
InternalScene intScene = internalSceneMap.get(sceneListener.getSceneStatusListenerID());
if (intScene != null) {
intScene.registerSceneListener(sceneListener);
} else {
addInternalScene(createNewScene(id));
registerSceneListener(sceneListener);
}
logger.debug("SceneStatusListener with id {} is registrated", sceneListener.getSceneStatusListenerID());
}
}
}
@Override
public void unregisterSceneListener(SceneStatusListener sceneListener) {
if (sceneListener != null) {
String id = sceneListener.getSceneStatusListenerID();
if (id.equals(SceneStatusListener.SCENE_DISCOVERY)) {
this.discovery.unRegisterDiscovery();
logger.debug("Scene-Discovery unregistrated");
} else {
InternalScene intScene = this.internalSceneMap.get(sceneListener.getSceneStatusListenerID());
if (intScene != null) {
intScene.unregisterSceneListener();
}
logger.debug("SceneStatusListener with id {} is unregistrated",
sceneListener.getSceneStatusListenerID());
}
}
}
@Override
public synchronized boolean scenesGenerated() {
return scenesGenerated;
}
@Override
public void generateScenes() {
stateChanged(ManagerStates.GENERATING_SCENES);
logger.debug("start generating scenes");
discovery.generateAllScenes(connectionManager, structureManager);
}
@Override
public void scenesGenerated(char[] scenesGenerated) {
if (String.valueOf(scenesGenerated).equals("1111")) {
this.scenesGenerated = true;
stateChanged(ManagerStates.RUNNING);
}
if (String.valueOf(scenesGenerated).contains("2")) {
String type = "nan";
switch (String.valueOf(scenesGenerated).indexOf("2")) {
case 0:
type = "namedScens";
break;
case 1:
type = "appScenes";
break;
case 2:
type = "zoneScenes";
break;
case 3:
type = "reachableScenes";
break;
}
logger.debug("Not all scenes are generated, try it again. Scene type {} is not generated.", type);
stateChanged(ManagerStates.RUNNING);
}
}
@Override
public boolean isDiscoveryRegistrated() {
return this.discovery != null;
}
private void stateChanged(ManagerStates state) {
this.state = state;
if (statusListener != null) {
statusListener.onStatusChanged(ManagerTypes.SCENE_MANAGER, state);
}
}
@Override
public ManagerTypes getManagerType() {
return ManagerTypes.SCENE_MANAGER;
}
@Override
public synchronized ManagerStates getManagerState() {
return state;
}
@Override
public List<InternalScene> getScenes() {
return this.internalSceneMap != null ? new LinkedList<>(this.internalSceneMap.values()) : null;
}
@Override
public void registerStatusListener(ManagerStatusListener statusListener) {
this.statusListener = statusListener;
}
@Override
public void unregisterStatusListener() {
this.statusListener = null;
}
@Override
public String getUID() {
return this.getClass().getSimpleName() + "-" + SUPPORTED_EVENTS.toString();
}
@Override
public List<String> getSupportedEvents() {
return SUPPORTED_EVENTS;
}
@Override
public boolean supportsEvent(String eventName) {
return SUPPORTED_EVENTS.contains(eventName);
}
@Override
public void setEventListener(EventListener eventListener) {
if (this.eventListener != null) {
this.eventListener.removeEventHandler(this);
}
this.eventListener = eventListener;
}
@Override
public void unsetEventListener(EventListener eventListener) {
if (this.eventListener != null) {
this.eventListener.removeEventHandler(this);
}
this.eventListener = null;
}
}

View File

@@ -0,0 +1,424 @@
/**
* 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.digitalstrom.internal.lib.manager.impl;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.AbstractGeneralDeviceInformations;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* The {@link StructureManagerImpl} is the implementation of the {@link StructureManager}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class StructureManagerImpl implements StructureManager {
private class ZoneGroupsNameAndIDMap {
public final String zoneName;
public final int zoneID;
private final Map<Short, String> groupIdNames;
private final Map<String, Short> groupNameIds;
public ZoneGroupsNameAndIDMap(final int zoneID, final String zoneName, JsonArray groups) {
this.zoneID = zoneID;
this.zoneName = zoneName;
groupIdNames = new HashMap<>(groups.size());
groupNameIds = new HashMap<>(groups.size());
for (int k = 0; k < groups.size(); k++) {
short groupID = ((JsonObject) groups.get(k)).get("group").getAsShort();
String groupName = ((JsonObject) groups.get(k)).get("name").getAsString();
groupIdNames.put(groupID, groupName);
groupNameIds.put(groupName, groupID);
}
}
public String getGroupName(Short groupID) {
return groupIdNames.get(groupID);
}
public short getGroupID(String groupName) {
final Short tmp = groupNameIds.get(groupName);
return tmp != null ? tmp : -1;
}
}
/**
* Query to get all zone and group names. Can be executed with {@link DsAPI#query(String, String)} or
* {@link DsAPI#query2(String, String)}.
*/
public static final String ZONE_GROUP_NAMES = "/apartment/zones/*(ZoneID,name)/groups/*(group,name)";
private final Map<Integer, Map<Short, List<Device>>> zoneGroupDeviceMap = Collections
.synchronizedMap(new HashMap<>());
private final Map<DSID, Device> deviceMap = Collections.synchronizedMap(new HashMap<>());
private final Map<DSID, Circuit> circuitMap = Collections.synchronizedMap(new HashMap<>());
private final Map<String, DSID> dSUIDToDSIDMap = Collections.synchronizedMap(new HashMap<>());
private Map<Integer, ZoneGroupsNameAndIDMap> zoneGroupIdNameMap;
private Map<String, ZoneGroupsNameAndIDMap> zoneGroupNameIdMap;
/**
* Creates a new {@link StructureManagerImpl} with the {@link Device}s of the given referenceDeviceList.
*
* @param referenceDeviceList to add
*/
public StructureManagerImpl(List<Device> referenceDeviceList) {
handleStructure(referenceDeviceList);
}
/**
* Creates a new {@link StructureManagerImpl} with the {@link Device}s of the given referenceDeviceList.
*
* @param referenceDeviceList to add
* @param referenceCircuitList to add
*/
public StructureManagerImpl(List<Device> referenceDeviceList, List<Circuit> referenceCircuitList) {
handleStructure(referenceDeviceList);
addCircuitList(referenceCircuitList);
}
/**
* Creates a new {@link StructureManagerImpl} without {@link Device}s.
*/
public StructureManagerImpl() {
}
@Override
public boolean generateZoneGroupNames(ConnectionManager connectionManager) {
JsonObject resultJsonObj = connectionManager.getDigitalSTROMAPI().query(connectionManager.getSessionToken(),
ZONE_GROUP_NAMES);
if (resultJsonObj != null && resultJsonObj.get("zones") instanceof JsonArray) {
JsonArray zones = (JsonArray) resultJsonObj.get("zones");
if (zoneGroupIdNameMap == null) {
zoneGroupIdNameMap = new HashMap<>(zones.size());
zoneGroupNameIdMap = new HashMap<>(zones.size());
}
if (zones != null) {
for (int i = 0; i < zones.size(); i++) {
if (((JsonObject) zones.get(i)).get("groups") instanceof JsonArray) {
JsonArray groups = (JsonArray) ((JsonObject) zones.get(i)).get("groups");
ZoneGroupsNameAndIDMap zoneGoupIdNameMap = new ZoneGroupsNameAndIDMap(
((JsonObject) zones.get(i)).get("ZoneID").getAsInt(),
((JsonObject) zones.get(i)).get("name").getAsString(), groups);
zoneGroupIdNameMap.put(zoneGoupIdNameMap.zoneID, zoneGoupIdNameMap);
zoneGroupNameIdMap.put(zoneGoupIdNameMap.zoneName, zoneGoupIdNameMap);
}
}
}
}
return true;
}
@Override
public String getZoneName(int zoneID) {
if (zoneGroupIdNameMap == null) {
return null;
}
final ZoneGroupsNameAndIDMap tmp = zoneGroupIdNameMap.get(zoneID);
return tmp != null ? tmp.zoneName : null;
}
@Override
public String getZoneGroupName(int zoneID, short groupID) {
if (zoneGroupIdNameMap == null) {
return null;
}
final ZoneGroupsNameAndIDMap tmp = zoneGroupIdNameMap.get(zoneID);
return tmp != null ? tmp.getGroupName(groupID) : null;
}
@Override
public int getZoneId(String zoneName) {
if (zoneGroupNameIdMap == null) {
return -1;
}
final ZoneGroupsNameAndIDMap tmp = zoneGroupNameIdMap.get(zoneName);
return tmp != null ? tmp.zoneID : -1;
}
@Override
public boolean checkZoneID(int zoneID) {
return getGroupsFromZoneX(zoneID) != null;
}
@Override
public boolean checkZoneGroupID(int zoneID, short groupID) {
final Map<Short, List<Device>> tmp = getGroupsFromZoneX(zoneID);
return tmp != null ? tmp.get(groupID) != null : false;
}
@Override
public short getZoneGroupId(String zoneName, String groupName) {
if (zoneGroupNameIdMap == null) {
return -1;
}
final ZoneGroupsNameAndIDMap tmp = zoneGroupNameIdMap.get(zoneName);
return tmp != null ? tmp.getGroupID(groupName) : -1;
}
@Override
public Map<DSID, Device> getDeviceMap() {
return new HashMap<>(deviceMap);
}
private void putDeviceToHashMap(Device device) {
if (device.getDSID() != null) {
deviceMap.put(device.getDSID(), device);
addDSIDtoDSUID((AbstractGeneralDeviceInformations) device);
}
}
/**
* This method build the digitalSTROM structure as an {@link HashMap} with the zone id as key
* and an {@link HashMap} as value. This {@link HashMap} has the group id as key and a {@link List}
* with all digitalSTROM {@link Device}s.<br>
* <br>
* <b>Note:</b> the zone id 0 is the broadcast address and the group id 0, too.
*/
private void handleStructure(List<Device> deviceList) {
Map<Short, List<Device>> groupXHashMap = new HashMap<>();
groupXHashMap.put((short) 0, deviceList);
zoneGroupDeviceMap.put(0, groupXHashMap);
for (Device device : deviceList) {
addDeviceToStructure(device);
}
}
@Override
public Map<DSID, Device> getDeviceHashMapReference() {
return deviceMap;
}
@Override
public Map<Integer, Map<Short, List<Device>>> getStructureReference() {
return zoneGroupDeviceMap;
}
@Override
public Map<Short, List<Device>> getGroupsFromZoneX(int zoneID) {
return zoneGroupDeviceMap.get(zoneID);
}
@Override
public List<Device> getReferenceDeviceListFromZoneXGroupX(int zoneID, short groupID) {
final Map<Short, List<Device>> tmp = getGroupsFromZoneX(zoneID);
return tmp != null ? tmp.get(groupID) : null;
}
@Override
public Device getDeviceByDSID(String dSID) {
return getDeviceByDSID(new DSID(dSID));
}
@Override
public Device getDeviceByDSID(DSID dSID) {
return deviceMap.get(dSID);
}
@Override
public Device getDeviceByDSUID(String dSUID) {
final DSID tmp = dSUIDToDSIDMap.get(dSUID);
return tmp != null ? getDeviceByDSID(tmp) : null;
}
@Override
public void updateDevice(int oldZone, List<Short> oldGroups, Device device) {
int intOldZoneID = oldZone;
if (intOldZoneID == -1) {
intOldZoneID = device.getZoneId();
}
deleteDevice(intOldZoneID, oldGroups, device);
addDeviceToStructure(device);
}
@Override
public void updateDevice(Device device) {
if (device != null) {
int oldZoneID = -1;
List<Short> oldGroups = null;
Device internalDevice = this.getDeviceByDSID(device.getDSID());
if (internalDevice != null) {
if (device.getZoneId() != internalDevice.getZoneId()) {
oldZoneID = internalDevice.getZoneId();
internalDevice.setZoneId(device.getZoneId());
}
if (!internalDevice.getGroups().equals(device.getGroups())) {
oldGroups = internalDevice.getGroups();
internalDevice.setGroups(device.getGroups());
}
if (deleteDevice(oldZoneID, oldGroups, internalDevice)) {
addDeviceToStructure(internalDevice);
}
}
}
}
@Override
public void deleteDevice(Device device) {
dSUIDToDSIDMap.remove(device.getDSUID());
deviceMap.remove(device.getDSID());
deleteDevice(device.getZoneId(), device.getGroups(), device);
}
private boolean deleteDevice(int zoneID, List<Short> groups, Device device) {
List<Short> intGroups = groups;
int intZoneID = zoneID;
if (intGroups != null || intZoneID >= 0) {
if (intGroups == null) {
intGroups = device.getGroups();
}
if (intZoneID == -1) {
intZoneID = device.getZoneId();
}
for (Short groupID : intGroups) {
List<Device> deviceList = getReferenceDeviceListFromZoneXGroupX(intZoneID, groupID);
if (deviceList != null) {
deviceList.remove(device);
}
deviceList = getReferenceDeviceListFromZoneXGroupX(0, groupID);
if (deviceList != null) {
deviceList.remove(device);
}
}
return true;
}
return false;
}
@Override
public void addDeviceToStructure(Device device) {
putDeviceToHashMap(device);
addDevicetoZoneXGroupX(0, (short) 0, device);
int zoneID = device.getZoneId();
addDevicetoZoneXGroupX(zoneID, (short) 0, device);
for (Short groupID : device.getGroups()) {
addDevicetoZoneXGroupX(zoneID, groupID, device);
if (groupID <= 16) {
addDevicetoZoneXGroupX(0, groupID, device);
}
}
}
private void addDevicetoZoneXGroupX(int zoneID, short groupID, Device device) {
Map<Short, List<Device>> groupXHashMap = zoneGroupDeviceMap.get(zoneID);
if (groupXHashMap == null) {
groupXHashMap = new HashMap<>();
zoneGroupDeviceMap.put(zoneID, groupXHashMap);
}
List<Device> groupDeviceList = groupXHashMap.get(groupID);
if (groupDeviceList == null) {
groupDeviceList = new LinkedList<>();
groupDeviceList.add(device);
groupXHashMap.put(groupID, groupDeviceList);
} else {
if (!groupDeviceList.contains(device)) {
groupDeviceList.add(device);
}
}
}
@Override
public Set<Integer> getZoneIDs() {
return zoneGroupDeviceMap.keySet();
}
@Override
public void addCircuitList(List<Circuit> referenceCircuitList) {
for (Circuit circuit : referenceCircuitList) {
addCircuit(circuit);
}
}
@Override
public Circuit addCircuit(Circuit circuit) {
addDSIDtoDSUID((AbstractGeneralDeviceInformations) circuit);
return circuitMap.put(circuit.getDSID(), circuit);
}
private void addDSIDtoDSUID(AbstractGeneralDeviceInformations deviceInfo) {
if (deviceInfo.getDSID() != null) {
dSUIDToDSIDMap.put(deviceInfo.getDSUID(), deviceInfo.getDSID());
}
}
@Override
public Circuit getCircuitByDSID(DSID dSID) {
return circuitMap.get(dSID);
}
@Override
public Circuit getCircuitByDSUID(String dSUID) {
final DSID tmp = dSUIDToDSIDMap.get(dSUID);
return tmp != null ? getCircuitByDSID(tmp) : null;
}
@Override
public Circuit getCircuitByDSID(String dSID) {
return getCircuitByDSID(new DSID(dSID));
}
@Override
public Circuit updateCircuitConfig(Circuit newCircuit) {
Circuit intCircuit = circuitMap.get(newCircuit.getDSID());
if (intCircuit != null && !intCircuit.equals(newCircuit)) {
for (CachedMeteringValue meteringValue : intCircuit.getAllCachedMeteringValues()) {
newCircuit.addMeteringValue(meteringValue);
}
if (intCircuit.isListenerRegisterd()) {
newCircuit.registerDeviceStatusListener(intCircuit.getDeviceStatusListener());
}
}
return addCircuit(newCircuit);
}
@Override
public Circuit deleteCircuit(DSID dSID) {
return circuitMap.remove(dSID);
}
@Override
public Circuit deleteCircuit(String dSUID) {
return deleteCircuit(dSUIDToDSIDMap.get(dSUID));
}
@Override
public Map<DSID, Circuit> getCircuitMap() {
return new HashMap<>(circuitMap);
}
}

View File

@@ -0,0 +1,447 @@
/**
* 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.digitalstrom.internal.lib.manager.impl;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.climate.TemperatureControlSensorTransmitter;
import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
import org.openhab.binding.digitalstrom.internal.lib.event.EventHandler;
import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventNames;
import org.openhab.binding.digitalstrom.internal.lib.event.constants.EventResponseEnum;
import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
import org.openhab.binding.digitalstrom.internal.lib.listener.SystemStateChangeListener;
import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FuncNameAndColorGroupEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link TemperatureControlManager} is responsible for handling the zone temperature control of the digitalSTROM
* zones. For that it implements a {@link EventHandler} to get informed by control changes, like the target temperature.
* It also implement the {@link TemperatureControlSensorTransmitter}, so the zone temperature can be set through this
* class. <br>
* <br>
* To check, if the heating-control-app is installed at the digitalSTROM server the static method
* {@link #isHeatingControllerInstallated(ConnectionManager)} can be used.<br>
* <br>
* To get informed by status changes tow listener types can be registered to the {@link TemperatureControlManager}:<br>
* {@link TemperatureControlStatusListener}, to get informed by configuration and status changes or as discovery.<br>
* {@link SystemStateChangeListener}, to get informed by heating water system changes. The heating system states are
* {@link #STATE_HEATING_WATER_SYSTEM_OFF}, {@link #STATE_HEATING_WATER_SYSTEM_COLD_WATER} and
* {@link #STATE_HEATING_WATER_SYSTEM_COLD_WATER}<br>
* <br>
* The {@link TemperatureControlManager} also contains some helpful static constants, like
* {@link #GET_HEATING_WATER_SYSTEM_STATE_PATH} to get the current heating water system state through
* {@link DsAPI#propertyTreeGetString(String, String)}.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class TemperatureControlManager implements EventHandler, TemperatureControlSensorTransmitter {
private final List<String> SUPPORTED_EVENTS = Arrays.asList(EventNames.HEATING_CONTROL_OPERATION_MODE);
private final Logger logger = LoggerFactory.getLogger(TemperatureControlManager.class);
private final ConnectionManager connectionMananager;
private final DsAPI dSapi;
private final EventListener eventListener;
private boolean isConfigured = false;
private HashMap<Integer, TemperatureControlStatusListener> zoneTemperationControlListenerMap;
private HashMap<Integer, TemperatureControlStatus> temperationControlStatus;
private TemperatureControlStatusListener discovery;
private SystemStateChangeListener systemStateChangeListener;
/**
* Name of the digitalSTROM heating water system state.
*/
public static final String STATE_NAME_HEATING_WATER_SYSTEM = "heating_water_system";
/**
* digitalSTROM heating water system state as string for off.
*/
public static final String STATE_HEATING_WATER_SYSTEM_OFF = "off"; // val=0
/**
* digitalSTROM heating water system state as string for hot water.
*/
public static final String STATE_HEATING_WATER_SYSTEM_HOT_WATER = "hot water"; // val=1
/**
* digitalSTROM heating water system state as string for cold water.
*/
public static final String STATE_HEATING_WATER_SYSTEM_COLD_WATER = "cold water"; // val=2
/**
* Path to get the current digitalSTROM heating water system state through
* {@link DsAPI#propertyTreeGetString(String, String)}.
*/
public static final String GET_HEATING_WATER_SYSTEM_STATE_PATH = "/usr/states/heating_water_system/state";
/**
* Path to get the current digitalSTROM heating controller nodes through
* {@link DsAPI#propertyTreeGetString(String, String)}.
* Can be used e.g. to check, if the digitalSTROM heating controller app is installed at the digitalSTROM server.
*/
public static final String GET_HEATING_HEATING_CONTROLLER_CHILDREN_PATH = "/scripts/heating-controller/";
/**
* Action for set operation mode at {@link EventNames#HEATING_CONTROL_OPERATION_MODE}.
*/
public static final String SET_OPERATION_MODE = "setOperationMode";
/**
* Action for evaluate real active mode at {@link EventNames#HEATING_CONTROL_OPERATION_MODE}. Will be called after
* {@link #SET_OPERATION_MODE} or if the configuration of a zone temperature control status has changed.
*/
public static final String EVALUATE_REAL_ACTIVE_MODE = "evaluateRealActiveMode";
private String currentHeatingWaterSystemStage;
private final List<String> echoBox = Collections.synchronizedList(new LinkedList<>());
/**
* Creates a new {@link TemperatureControlManager}. The {@link ConnectionManager} is needed. The other fields are
* only needed, if you want to get automatically informed by status changes through the {@link EventListener} and/or
* get informed by new configured zones as discovery.
*
* @param connectionMananager (must not be null)
* @param eventListener (can be null)
* @param discovery (can be null)
*/
public TemperatureControlManager(ConnectionManager connectionMananager, EventListener eventListener,
TemperatureControlStatusListener discovery) {
this(connectionMananager, eventListener, discovery, null);
}
/**
* Same constructor like
* {@link #TemperatureControlManager(ConnectionManager, EventListener, TemperatureControlStatusListener)}, but it
* can be set a {@link SystemStateChangeListener}, too.
*
* @param connectionMananager (must not be null)
* @param eventListener (can be null)
* @param discovery (can be null)
* @param systemStateChangeListener (can be null)
* @see #TemperatureControlManager(ConnectionManager, EventListener, TemperatureControlStatusListener)
*/
public TemperatureControlManager(ConnectionManager connectionMananager, EventListener eventListener,
TemperatureControlStatusListener discovery, SystemStateChangeListener systemStateChangeListener) {
this.connectionMananager = connectionMananager;
this.dSapi = connectionMananager.getDigitalSTROMAPI();
this.systemStateChangeListener = systemStateChangeListener;
this.discovery = discovery;
this.eventListener = eventListener;
checkZones();
if (eventListener != null) {
if (isConfigured) {
SUPPORTED_EVENTS.add(EventNames.ZONE_SENSOR_VALUE);
if (systemStateChangeListener != null) {
SUPPORTED_EVENTS.add(EventNames.STATE_CHANGED);
}
}
eventListener.addEventHandler(this);
}
}
/**
* Checks all digitalSTROM zones, if temperature control is configured. If a zone with configured temperature
* control is found, it will be stored, the flag for {@link #isConfigured()} will be set to true and the discovery
* will be informed, if a discovery is registered.
*/
public void checkZones() {
List<TemperatureControlStatus> temperationControlStatus = dSapi
.getApartmentTemperatureControlStatus(connectionMananager.getSessionToken());
if (!temperationControlStatus.isEmpty()) {
for (TemperatureControlStatus tempConStat : temperationControlStatus) {
addTemperatureControlStatus(tempConStat);
}
if (isConfigured && systemStateChangeListener != null) {
currentHeatingWaterSystemStage = dSapi.propertyTreeGetString(connectionMananager.getSessionToken(),
GET_HEATING_WATER_SYSTEM_STATE_PATH);
}
}
}
/**
* Returns true, if the digitalSTROM heating controller app is installed.
*
* @param connectionManager (must not be null)
* @return true, if heating controller app is installed, otherwise false
*/
public static boolean isHeatingControllerInstallated(ConnectionManager connectionManager) {
return connectionManager.getDigitalSTROMAPI().propertyTreeGetChildren(connectionManager.getSessionToken(),
GET_HEATING_HEATING_CONTROLLER_CHILDREN_PATH) != null;
}
/**
* Returns all zone which have temperature controlled configured.
*
* @return all temperature controlled zones
*/
public Collection<TemperatureControlStatus> getTemperatureControlStatusFromAllZones() {
return temperationControlStatus != null ? this.temperationControlStatus.values() : new LinkedList<>();
}
/**
* Registers a {@link TemperatureControlStatusListener} for a zone, if the temperation control for this zone is
* configured. It can be also register a {@link TemperatureControlStatusListener} as discovery, if the
* {@link TemperatureControlStatusListener#getTemperationControlStatusListenrID()} returns
* {@link TemperatureControlStatusListener#DISCOVERY}.
*
* @param temperatureControlStatusListener to register
*/
public void registerTemperatureControlStatusListener(
TemperatureControlStatusListener temperatureControlStatusListener) {
if (temperatureControlStatusListener != null) {
if (temperatureControlStatusListener.getTemperationControlStatusListenrID()
.equals(TemperatureControlStatusListener.DISCOVERY)) {
logger.debug("discovery is registered");
this.discovery = temperatureControlStatusListener;
if (temperationControlStatus != null) {
for (TemperatureControlStatus tempConStat : temperationControlStatus.values()) {
discovery.configChanged(tempConStat);
}
}
} else {
if (zoneTemperationControlListenerMap == null) {
zoneTemperationControlListenerMap = new HashMap<>();
}
TemperatureControlStatus tempConStat = checkAndGetTemperatureControlStatus(
temperatureControlStatusListener.getTemperationControlStatusListenrID());
if (tempConStat != null) {
logger.debug("register listener with id {}",
temperatureControlStatusListener.getTemperationControlStatusListenrID());
zoneTemperationControlListenerMap.put(
temperatureControlStatusListener.getTemperationControlStatusListenrID(),
temperatureControlStatusListener);
temperatureControlStatusListener.registerTemperatureSensorTransmitter(this);
}
temperatureControlStatusListener.configChanged(tempConStat);
}
}
}
/**
* Unregisters a {@link TemperatureControlStatusListener}, if it exist.
*
* @param temperatureControlStatusListener to unregister
*/
public void unregisterTemperatureControlStatusListener(
TemperatureControlStatusListener temperatureControlStatusListener) {
if (temperatureControlStatusListener != null) {
if (temperatureControlStatusListener.getTemperationControlStatusListenrID()
.equals(TemperatureControlStatusListener.DISCOVERY)) {
this.discovery = null;
return;
}
if (discovery != null && zoneTemperationControlListenerMap
.remove(temperatureControlStatusListener.getTemperationControlStatusListenrID()) != null) {
discovery.configChanged(temperationControlStatus
.get(temperatureControlStatusListener.getTemperationControlStatusListenrID()));
}
}
}
/**
* Returns the {@link TemperatureControlStatus} for the given zone, if the temperature control is configured,
* otherwise it will be returned null.
*
* @param zoneID to check
* @return {@link TemperatureControlStatus} if the temperature control is configured, otherwise null
*/
public TemperatureControlStatus checkAndGetTemperatureControlStatus(Integer zoneID) {
TemperatureControlStatus tempConStat = this.temperationControlStatus.get(zoneID);
if (tempConStat.isNotSetOff()) {
return tempConStat;
}
return null;
}
private boolean isEcho(Integer zoneID, SensorEnum sensorType, Float value) {
return echoBox.remove(zoneID + "-" + sensorType.getSensorType() + "-" + value);
}
private void addEcho(Integer zoneID, SensorEnum sensorType, Float value) {
echoBox.add(zoneID + "-" + sensorType.getSensorType() + "-" + value);
}
@Override
public void handleEvent(EventItem eventItem) {
logger.debug("detect event: {}", eventItem.toString());
if (eventItem.getName().equals(EventNames.ZONE_SENSOR_VALUE)) {
if (zoneTemperationControlListenerMap != null) {
if (SensorEnum.ROOM_TEMPERATURE_SET_POINT.getSensorType().toString()
.equals(eventItem.getProperties().get(EventResponseEnum.SENSOR_TYPE))) {
Integer zoneID = Integer.parseInt(eventItem.getSource().get(EventResponseEnum.ZONEID));
if (zoneTemperationControlListenerMap.get(zoneID) != null) {
Float newValue = Float
.parseFloat(eventItem.getProperties().get(EventResponseEnum.SENSOR_VALUE_FLOAT));
if (!isEcho(zoneID, SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE, newValue)) {
zoneTemperationControlListenerMap.get(zoneID).onTargetTemperatureChanged(newValue);
}
}
}
if (SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE.getSensorType().toString()
.equals(eventItem.getProperties().get(EventResponseEnum.SENSOR_TYPE))) {
Integer zoneID = Integer.parseInt(eventItem.getSource().get(EventResponseEnum.ZONEID));
if (zoneTemperationControlListenerMap.get(zoneID) != null) {
Float newValue = Float
.parseFloat(eventItem.getProperties().get(EventResponseEnum.SENSOR_VALUE_FLOAT));
if (!isEcho(zoneID, SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE, newValue)) {
zoneTemperationControlListenerMap.get(zoneID).onControlValueChanged(newValue.intValue());
}
}
}
}
}
if (eventItem.getName().equals(EventNames.HEATING_CONTROL_OPERATION_MODE)) {
if (EVALUATE_REAL_ACTIVE_MODE.equals(eventItem.getProperties().get(EventResponseEnum.ACTIONS))) {
Integer zoneID = Integer.parseInt(eventItem.getProperties().get(EventResponseEnum.ZONEID));
TemperatureControlStatus temperationControlStatus = dSapi
.getZoneTemperatureControlStatus(connectionMananager.getSessionToken(), zoneID, null);
if (temperationControlStatus != null) {
addTemperatureControlStatus(temperationControlStatus);
}
}
}
if (eventItem.getName().equals(EventNames.STATE_CHANGED)) {
if (STATE_NAME_HEATING_WATER_SYSTEM.equals(eventItem.getProperties().get(EventResponseEnum.STATE_NAME))) {
currentHeatingWaterSystemStage = eventItem.getProperties().get(EventResponseEnum.STATE);
logger.debug("heating water system state changed to {}", currentHeatingWaterSystemStage);
if (systemStateChangeListener != null) {
systemStateChangeListener.onSystemStateChanged(STATE_NAME_HEATING_WATER_SYSTEM,
currentHeatingWaterSystemStage);
}
}
}
}
private void addTemperatureControlStatus(TemperatureControlStatus temperationControlStatus) {
if (temperationControlStatus.isNotSetOff()) {
if (this.temperationControlStatus == null) {
this.temperationControlStatus = new HashMap<>();
}
if (this.temperationControlStatus.get(temperationControlStatus.getZoneID()) == null && discovery != null) {
discovery.configChanged(temperationControlStatus);
if (!isConfigured) {
isConfigured = true;
}
}
this.temperationControlStatus.put(temperationControlStatus.getZoneID(), temperationControlStatus);
if (zoneTemperationControlListenerMap != null
&& zoneTemperationControlListenerMap.get(temperationControlStatus.getZoneID()) != null) {
zoneTemperationControlListenerMap.get(temperationControlStatus.getZoneID())
.configChanged(temperationControlStatus);
}
}
}
@Override
public List<String> getSupportedEvents() {
return SUPPORTED_EVENTS;
}
@Override
public boolean supportsEvent(String eventName) {
return SUPPORTED_EVENTS.contains(eventName);
}
@Override
public String getUID() {
return getClass().getSimpleName();
}
@Override
public void setEventListener(EventListener eventListener) {
eventListener.addEventHandler(this);
}
@Override
public void unsetEventListener(EventListener eventListener) {
eventListener.removeEventHandler(this);
}
@Override
public boolean pushTargetTemperature(Integer zoneID, Float newValue) {
if (checkAndGetTemperatureControlStatus(zoneID) != null) {
if (dSapi.pushZoneSensorValue(connectionMananager.getSessionToken(), zoneID, null, (short) 0, null,
newValue, SensorEnum.ROOM_TEMPERATURE_SET_POINT)) {
addEcho(zoneID, SensorEnum.ROOM_TEMPERATURE_SET_POINT, newValue);
return true;
}
}
return false;
}
@Override
public boolean pushControlValue(Integer zoneID, Float newValue) {
if (checkAndGetTemperatureControlStatus(zoneID) != null) {
if (dSapi.pushZoneSensorValue(connectionMananager.getSessionToken(), zoneID, null,
FuncNameAndColorGroupEnum.TEMPERATION_CONTROL.getFunctionalColorGroup(), null, newValue,
SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE)) {
addEcho(zoneID, SensorEnum.ROOM_TEMPERATURE_CONTROL_VARIABLE, newValue);
return true;
}
}
return false;
}
/**
* Returns true, if minimum one zone has temperature control configured.
*
* @return true, if minimum one zone has temperature control configured, otherwise false
*/
public boolean isConfigured() {
return isConfigured;
}
/**
* Returns the current heating water system state, if a {@link SystemStateChangeListener} is registered, otherwise
* null.
*
* @return the current heating water system state or null, if no {@link SystemStateChangeListener}
*/
public String getHeatingWaterSystemState() {
return currentHeatingWaterSystemStage;
}
/**
* Registers the given {@link SystemStateChangeListener}, which will be informed about heating system water state
* changes.
*
* @param systemStateChangeListener to register
*/
public void registerSystemStateChangeListener(SystemStateChangeListener systemStateChangeListener) {
if (eventListener != null) {
SUPPORTED_EVENTS.add(EventNames.STATE_CHANGED);
eventListener.addSubscribe(EventNames.STATE_CHANGED);
}
this.systemStateChangeListener = systemStateChangeListener;
}
/**
* Unregisters a registered {@link SystemStateChangeListener}.
*/
public void unregisterSystemStateChangeListener() {
this.systemStateChangeListener = null;
}
}

View File

@@ -0,0 +1,241 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.openhab.core.common.ThreadPoolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link AbstractSensorJobExecutor} provides the working process to execute implementations of {@link SensorJob}'s
* in the time interval set at the {@link Config}.
* <p>
* The following methods can be overridden by subclasses to implement a execution priority:
* </p>
* <ul>
* <li>{@link #addLowPriorityJob(SensorJob)}</li>
* <li>{@link #addMediumPriorityJob(SensorJob)}</li>
* <li>{@link #addHighPriorityJob(SensorJob)}</li>
* </ul>
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public abstract class AbstractSensorJobExecutor {
private final Logger logger = LoggerFactory.getLogger(AbstractSensorJobExecutor.class);
private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME);
private Map<DSID, ScheduledFuture<?>> pollingSchedulers;
private final DsAPI dSAPI;
protected Config config;
private final ConnectionManager connectionManager;
private final List<CircuitScheduler> circuitSchedulerList = new LinkedList<>();
private class ExecutorRunnable implements Runnable {
private final CircuitScheduler circuit;
public ExecutorRunnable(CircuitScheduler circuit) {
this.circuit = circuit;
}
@Override
public void run() {
// pollingSchedulers is not final and might be set to null by another thread. See #8214
Map<DSID, ScheduledFuture<?>> pollingSchedulers = AbstractSensorJobExecutor.this.pollingSchedulers;
SensorJob sensorJob = circuit.getNextSensorJob();
DSID meter = circuit.getMeterDSID();
if (sensorJob != null) {
sensorJob.execute(dSAPI, connectionManager.getSessionToken());
}
if (circuit.noMoreJobs() && pollingSchedulers != null) {
logger.debug("no more jobs... stop circuit schedduler with id = {}", meter);
ScheduledFuture<?> scheduler = pollingSchedulers.get(meter);
if (scheduler != null) {
scheduler.cancel(true);
}
}
}
}
/**
* Creates a new {@link AbstractSensorJobExecutor}.
*
* @param connectionManager must not be null
*/
public AbstractSensorJobExecutor(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
config = connectionManager.getConfig();
this.dSAPI = connectionManager.getDigitalSTROMAPI();
}
/**
* Stops all circuit schedulers.
*/
public synchronized void shutdown() {
if (pollingSchedulers != null) {
for (ScheduledFuture<?> scheduledExecutor : pollingSchedulers.values()) {
scheduledExecutor.cancel(true);
}
pollingSchedulers = null;
logger.debug("stop all circuit schedulers.");
}
}
/**
* Starts all circuit schedulers.
*/
public synchronized void startExecutor() {
logger.debug("start all circuit schedulers.");
if (pollingSchedulers == null) {
pollingSchedulers = new HashMap<>();
}
if (circuitSchedulerList != null && !circuitSchedulerList.isEmpty()) {
for (CircuitScheduler circuit : circuitSchedulerList) {
startSchedduler(circuit);
}
}
}
private void startSchedduler(CircuitScheduler circuit) {
if (pollingSchedulers != null) {
if (pollingSchedulers.get(circuit.getMeterDSID()) == null
|| pollingSchedulers.get(circuit.getMeterDSID()).isCancelled()) {
pollingSchedulers.put(circuit.getMeterDSID(),
scheduler.scheduleWithFixedDelay(new ExecutorRunnable(circuit), circuit.getNextExecutionDelay(),
config.getSensorReadingWaitTime(), TimeUnit.MILLISECONDS));
}
}
}
/**
* Adds a high priority {@link SensorJob}.
*
* @param sensorJob to add
*/
public void addHighPriorityJob(SensorJob sensorJob) {
// can be Overridden to implement a priority
addSensorJobToCircuitScheduler(sensorJob);
}
/**
* Adds a medium priority {@link SensorJob}.
*
* @param sensorJob to add
*/
public void addMediumPriorityJob(SensorJob sensorJob) {
// can be overridden to implement a priority
addSensorJobToCircuitScheduler(sensorJob);
}
/**
* Adds a low priority {@link SensorJob}.
*
* @param sensorJob to add
*/
public void addLowPriorityJob(SensorJob sensorJob) {
// can be overridden to implement a priority
addSensorJobToCircuitScheduler(sensorJob);
}
/**
* Adds a {@link SensorJob} with a given priority .
*
* @param sensorJob to add
* @param priority to update
*/
public void addPriorityJob(SensorJob sensorJob, long priority) {
if (sensorJob == null) {
return;
}
sensorJob.setInitalisationTime(priority);
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SensorJob from device with dSID {} and priority {} to AbstractJobExecutor",
sensorJob.getDSID(), priority);
}
/**
* Adds the given {@link SensorJob}.
*
* @param sensorJob to add
*/
protected void addSensorJobToCircuitScheduler(SensorJob sensorJob) {
synchronized (this.circuitSchedulerList) {
CircuitScheduler circuit = getCircuitScheduler(sensorJob.getMeterDSID());
if (circuit != null) {
circuit.addSensorJob(sensorJob);
} else {
circuit = new CircuitScheduler(sensorJob, config);
this.circuitSchedulerList.add(circuit);
}
startSchedduler(circuit);
}
}
private CircuitScheduler getCircuitScheduler(DSID dsid) {
for (CircuitScheduler circuit : this.circuitSchedulerList) {
if (circuit.getMeterDSID().equals(dsid)) {
return circuit;
}
}
return null;
}
/**
* Removes all SensorJobs of a specific {@link Device}.
*
* @param device to remove
*/
public void removeSensorJobs(Device device) {
if (device != null) {
CircuitScheduler circuit = getCircuitScheduler(device.getMeterDSID());
if (circuit != null) {
circuit.removeSensorJob(device.getDSID());
}
}
}
/**
* Removes the {@link SensorJob} with the given ID.
*
* @param device needed for the meterDSID
* @param ID of the {@link SensorJob} to remove
*/
public void removeSensorJob(Device device, String ID) {
if (device != null && ID != null) {
CircuitScheduler circuit = getCircuitScheduler(device.getMeterDSID());
if (circuit != null) {
circuit.removeSensorJob(ID);
}
}
}
}

View File

@@ -0,0 +1,204 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor;
import java.util.Comparator;
import java.util.Iterator;
import java.util.PriorityQueue;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This {@link CircuitScheduler} represents a circuit in the digitalSTROM-System and manages the priorities and
* execution times for the {@link SensorJob}s on this circuit.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class CircuitScheduler {
private final Logger logger = LoggerFactory.getLogger(CircuitScheduler.class);
private class SensorJobComparator implements Comparator<SensorJob> {
@Override
public int compare(SensorJob job1, SensorJob job2) {
return ((Long) job1.getInitalisationTime()).compareTo(job2.getInitalisationTime());
}
}
private final DSID meterDSID;
private long nextExecutionTime = System.currentTimeMillis();
private final PriorityQueue<SensorJob> sensorJobQueue = new PriorityQueue<>(10, new SensorJobComparator());
private final Config config;
/**
* Creates a new {@link CircuitScheduler}.
*
* @param meterDSID must not be null
* @param config must not be null
* @throws IllegalArgumentException if the meterDSID is null
*/
public CircuitScheduler(DSID meterDSID, Config config) {
if (meterDSID == null) {
throw new IllegalArgumentException("The meterDSID must not be null!");
}
this.meterDSID = meterDSID;
this.config = config;
}
/**
* Creates a new {@link CircuitScheduler} and add the first {@link SensorJob} to this {@link CircuitScheduler}.
*
* @param sensorJob to add, must not be null
* @param config must not be null
*/
public CircuitScheduler(SensorJob sensorJob, Config config) {
this.meterDSID = sensorJob.getMeterDSID();
this.sensorJobQueue.add(sensorJob);
this.config = config;
logger.debug("create circuitScheduler: {} and add sensorJob: {}", this.getMeterDSID(),
sensorJob.getDSID().toString());
}
/**
* Returns the meterDSID of the dS-Meter in which the {@link SensorJob}s will be executed.
*
* @return meterDSID
*/
public DSID getMeterDSID() {
return this.meterDSID;
}
/**
* Adds a new SensorJob to this {@link CircuitScheduler}, if no {@link SensorJob} with a higher priority exists.
*
* @param sensorJob to add
*/
public void addSensorJob(SensorJob sensorJob) {
synchronized (sensorJobQueue) {
if (!this.sensorJobQueue.contains(sensorJob)) {
sensorJobQueue.add(sensorJob);
logger.debug("Add sensorJob: {} to circuitScheduler: {}", sensorJob.toString(), this.getMeterDSID());
} else if (checkSensorJobPrio(sensorJob)) {
logger.debug("add sensorJob: {} with higher priority to circuitScheduler: {}", sensorJob.toString(),
this.getMeterDSID());
} else {
logger.debug("sensorJob: {} allready exist with a higher priority", sensorJob.getDSID());
}
}
}
private boolean checkSensorJobPrio(SensorJob sensorJob) {
synchronized (sensorJobQueue) {
for (Iterator<SensorJob> iter = sensorJobQueue.iterator(); iter.hasNext();) {
SensorJob existSensorJob = iter.next();
if (existSensorJob.equals(sensorJob)) {
if (sensorJob.getInitalisationTime() < existSensorJob.getInitalisationTime()) {
iter.remove();
sensorJobQueue.add(sensorJob);
return true;
}
}
}
}
return false;
}
/**
* Returns the next {@link SensorJob} which can be executed or null, if there are no more {@link SensorJob} to
* execute or the wait time between the {@link SensorJob}s executions has not expired yet.
*
* @return next SensorJob or null
*/
public SensorJob getNextSensorJob() {
synchronized (sensorJobQueue) {
if (sensorJobQueue.peek() != null && this.nextExecutionTime <= System.currentTimeMillis()) {
nextExecutionTime = System.currentTimeMillis() + config.getSensorReadingWaitTime();
return sensorJobQueue.poll();
} else {
return null;
}
}
}
/**
* Returns the time when the next {@link SensorJob} can be executed.
*
* @return next SesnorJob execution time
*/
public Long getNextExecutionTime() {
return this.nextExecutionTime;
}
/**
* Returns the delay when the next {@link SensorJob} can be executed.
*
* @return next SesnorJob execution delay
*/
public Long getNextExecutionDelay() {
long delay = this.nextExecutionTime - System.currentTimeMillis();
return delay > 0 ? delay : 0;
}
/**
* Removes all {@link SensorJob} of a specific {@link Device} with the given {@link DSID}.
*
* @param dSID of the device
*/
public void removeSensorJob(DSID dSID) {
synchronized (sensorJobQueue) {
for (Iterator<SensorJob> iter = sensorJobQueue.iterator(); iter.hasNext();) {
SensorJob job = iter.next();
if (job.getDSID().equals(dSID)) {
iter.remove();
logger.debug("Remove SensorJob with ID {}.", job.getID());
}
}
}
}
/**
* Removes the {@link SensorJob} with the given ID .
*
* @param id of the {@link SensorJob}
*/
public void removeSensorJob(String id) {
synchronized (sensorJobQueue) {
for (Iterator<SensorJob> iter = sensorJobQueue.iterator(); iter.hasNext();) {
SensorJob job = iter.next();
if (job.getID().equals(id)) {
iter.remove();
logger.debug("Remove SensorJob with ID {}.", id);
return;
}
}
logger.debug("No SensorJob with ID {} found, cannot remove a not existing SensorJob.", id);
}
}
/**
* Returns true, if there are no more {@link SensorJob}s to execute, otherwise false.
*
* @return no more SensorJobs? (true | false)
*/
public boolean noMoreJobs() {
synchronized (sensorJobQueue) {
return this.sensorJobQueue.isEmpty();
}
}
}

View File

@@ -0,0 +1,83 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SceneReadingJobExecutor} is the implementation of the {@link AbstractSensorJobExecutor} to execute
* digitalSTROM-Device scene configuration {@link SensorJob}'s e.g. {@link SceneConfigReadingJob} and
* {@link SceneOutputValueReadingJob}.
* <p>
* In addition priorities can be assigned to jobs therefore the {@link SceneReadingJobExecutor} offers the methods
* {@link #addHighPriorityJob(SensorJob)}, {@link #addMediumPriorityJob(SensorJob)} and
* {@link #addLowPriorityJob(SensorJob)}.
* </p>
* <p>
* <b>NOTE:</b><br>
* In contrast to the {@link SensorJobExecutor} the {@link SceneReadingJobExecutor} will execute {@link SensorJob}'s
* with high priority always before medium priority {@link SensorJob}s and so on.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public class SceneReadingJobExecutor extends AbstractSensorJobExecutor {
private Logger logger = LoggerFactory.getLogger(SceneReadingJobExecutor.class);
/**
* Creates a new {@link SceneReadingJobExecutor}.
*
* @param connectionManager must not be null
*/
public SceneReadingJobExecutor(ConnectionManager connectionManager) {
super(connectionManager);
}
@Override
public void addHighPriorityJob(SensorJob sensorJob) {
if (sensorJob == null) {
return;
}
sensorJob.setInitalisationTime(0);
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SceneReadingJob from device with dSID {} and high-priority to SceneReadingSobExecutor",
sensorJob.getDSID());
}
@Override
public void addMediumPriorityJob(SensorJob sensorJob) {
if (sensorJob == null) {
return;
}
sensorJob.setInitalisationTime(1);
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SceneReadingJob from device with dSID {} and medium-priority to SceneReadingJobExecutor",
sensorJob.getDSID());
}
@Override
public void addLowPriorityJob(SensorJob sensorJob) {
if (sensorJob == null) {
return;
}
sensorJob.setInitalisationTime(2);
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SceneReadingJob from device with dSID {} and low-priority to SceneReadingJobExecutor",
sensorJob.getDSID());
}
}

View File

@@ -0,0 +1,85 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SensorJobExecutor} is the implementation of the {@link AbstractSensorJobExecutor} to execute
* digitalSTROM-Device {@link SensorJob}'s e.g. {@link DeviceConsumptionSensorJob} and
* {@link DeviceOutputValueSensorJob}.
* <p>
* In addition priorities can be assigned to jobs, but the following list shows the maximum evaluation of a
* {@link SensorJob} per priority.
* </p>
* <ul>
* <li>low priority: read cycles before execution is set in {@link Config}</li>
* <li>medium priority: read cycles before execution is set in {@link Config}</li>
* <li>high priority: read cycles before execution 0</li>
* </ul>
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public class SensorJobExecutor extends AbstractSensorJobExecutor {
private final Logger logger = LoggerFactory.getLogger(SensorJobExecutor.class);
private final long mediumFactor = super.config.getSensorReadingWaitTime() * super.config.getMediumPriorityFactor();
private final long lowFactor = super.config.getSensorReadingWaitTime() * super.config.getLowPriorityFactor();
/**
* Creates a new {@link SensorJobExecutor}.
*
* @param connectionManager must not be null
*/
public SensorJobExecutor(ConnectionManager connectionManager) {
super(connectionManager);
}
@Override
public void addHighPriorityJob(SensorJob sensorJob) {
if (sensorJob == null) {
return;
}
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SensorJob from device with dSID {} and high-priority to SensorJobExecutor",
sensorJob.getDSID());
}
@Override
public void addMediumPriorityJob(SensorJob sensorJob) {
if (sensorJob == null) {
return;
}
sensorJob.setInitalisationTime(sensorJob.getInitalisationTime() + this.mediumFactor);
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SensorJob from device with dSID {} and medium-priority to SensorJobExecutor",
sensorJob.getDSID());
}
@Override
public void addLowPriorityJob(SensorJob sensorJob) {
if (sensorJob == null) {
return;
}
sensorJob.setInitalisationTime(sensorJob.getInitalisationTime() + this.lowFactor);
addSensorJobToCircuitScheduler(sensorJob);
logger.debug("Add SensorJob from device with dSID {} and low-priority to SensorJobExecutor",
sensorJob.getDSID());
}
}

View File

@@ -0,0 +1,71 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor.sensorjob;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
/**
* The {@link SensorJob} represents an executable job to read out digitalSTROM-Sensors or device configurations like
* scene values.<br>
* It can be added to an implementation of the {@link AbstractSensorJobExecutor} e.g. {@link SceneReadingJobExecutor} or
* {@link SensorJobExecutor}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface SensorJob {
/**
* Returns the dSID of the {@link Device} for which this job is to be created.
*
* @return dSID from the device
*/
DSID getDSID();
/**
* Returns the dSID of the digitalSTROM-Meter on which this job is to be created.
*
* @return dSID from the device meter
*/
DSID getMeterDSID();
/**
* Executes the SensorJob.
*
* @param dSAPI must not be null
* @param sessionToken to login
*/
void execute(DsAPI dSAPI, String sessionToken);
/**
* Returns the time when the {@link SensorJob} was initialized.
*
* @return the initialization time
*/
long getInitalisationTime();
/**
* Sets the time when the {@link SensorJob} was initialized e.g. to manages the priority of this {@link SensorJob}.
*
* @param time to set
*/
void setInitalisationTime(long time);
/**
* Returns the id of this {@link SensorJob}.
*
* @return id
*/
String getID();
}

View File

@@ -0,0 +1,138 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DeviceConsumptionSensorJob} is the implementation of a {@link SensorJob}
* for reading out the current value of the of a digitalSTROM-Device sensor and updates the {@link Device}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class DeviceConsumptionSensorJob implements SensorJob {
private final Logger logger = LoggerFactory.getLogger(DeviceConsumptionSensorJob.class);
private final Device device;
private final SensorEnum sensorType;
private final DSID meterDSID;
private long initalisationTime = 0;
private boolean updateDevice = true;
/**
* Creates a new {@link DeviceConsumptionSensorJob}. Through updateDevice you can set, if the {@link Device} will be
* updates automatically.
*
* @param device to update
* @param type to update
* @param updateDevice (true = automatically device, otherwise false)
* @see #DeviceConsumptionSensorJob(Device, SensorEnum)
*/
public DeviceConsumptionSensorJob(Device device, SensorEnum type, boolean updateDevice) {
this.device = device;
this.sensorType = type;
this.meterDSID = device.getMeterDSID();
this.initalisationTime = System.currentTimeMillis();
this.updateDevice = updateDevice;
}
/**
* Creates a new {@link DeviceConsumptionSensorJob} with the given {@link SensorEnum} for the given {@link Device}
* and automatically {@link Device} update.
*
* @param device to update
* @param type to update
*/
public DeviceConsumptionSensorJob(Device device, SensorEnum type) {
this.device = device;
this.sensorType = type;
this.meterDSID = device.getMeterDSID();
this.initalisationTime = System.currentTimeMillis();
}
@Override
public void execute(DsAPI digitalSTROM, String token) {
int consumption = digitalSTROM.getDeviceSensorValue(token, this.device.getDSID(), null, null,
device.getSensorIndex(sensorType));
logger.debug("Executes {} new device consumption is {}", this.toString(), consumption);
if (updateDevice) {
device.setDeviceSensorDsValueBySensorJob(sensorType, consumption);
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DeviceConsumptionSensorJob) {
DeviceConsumptionSensorJob other = (DeviceConsumptionSensorJob) obj;
String device = this.device.getDSID().getValue() + this.sensorType.getSensorType();
return device.equals(other.device.getDSID().getValue() + other.sensorType.getSensorType());
}
return false;
}
@Override
public int hashCode() {
return new String(this.device.getDSID().getValue() + this.sensorType.getSensorType()).hashCode();
}
@Override
public DSID getDSID() {
return device.getDSID();
}
@Override
public DSID getMeterDSID() {
return this.meterDSID;
}
@Override
public long getInitalisationTime() {
return this.initalisationTime;
}
@Override
public void setInitalisationTime(long time) {
this.initalisationTime = time;
}
@Override
public String toString() {
return "DeviceConsumptionSensorJob [sensorType=" + sensorType + ", sensorIndex="
+ device.getSensorIndex(sensorType) + ", deviceDSID : " + device.getDSID().getValue() + ", meterDSID="
+ meterDSID + ", initalisationTime=" + initalisationTime + "]";
}
@Override
public String getID() {
return getID(device, sensorType);
}
/**
* Returns the id for a {@link DeviceConsumptionSensorJob} with the given {@link Device} and {@link SensorEnum}.
*
* @param device to update
* @param sensorType to update
* @return id
*/
public static String getID(Device device, SensorEnum sensorType) {
return DeviceConsumptionSensorJob.class.getSimpleName() + "-" + device.getDSID().getValue() + "-"
+ sensorType.toString();
}
}

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.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceConstants;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DeviceOutputValueSensorJob} is the implementation of a {@link SensorJob}
* for reading out the current device output value of a digitalSTROM-Device and update the {@link Device}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class DeviceOutputValueSensorJob implements SensorJob {
private final Logger logger = LoggerFactory.getLogger(DeviceOutputValueSensorJob.class);
private final Device device;
private short index = 0;
private final DSID meterDSID;
private long initalisationTime = 0;
/**
* Creates a new {@link DeviceOutputValueSensorJob} for the given {@link Device}.
*
* @param device to update
*/
public DeviceOutputValueSensorJob(Device device) {
this.device = device;
if (device.isShade()) {
this.index = DeviceConstants.DEVICE_SENSOR_SLAT_POSITION_OUTPUT;
} else {
this.index = DeviceConstants.DEVICE_SENSOR_OUTPUT;
}
this.meterDSID = device.getMeterDSID();
this.initalisationTime = System.currentTimeMillis();
}
@Override
public void execute(DsAPI digitalSTROM, String token) {
int value = digitalSTROM.getDeviceOutputValue(token, this.device.getDSID(), null, null, index);
logger.debug("Device output value on Demand : {}, dSID: {}", value, this.device.getDSID().getValue());
if (value != 1) {
switch (this.index) {
case 0:
this.device.updateInternalDeviceState(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT, value));
return;
case 2:
this.device.updateInternalDeviceState(
new DeviceStateUpdateImpl(DeviceStateUpdate.SLATPOSITION, value));
if (device.isBlind()) {
value = digitalSTROM.getDeviceOutputValue(token, this.device.getDSID(), null, null,
DeviceConstants.DEVICE_SENSOR_SLAT_ANGLE_OUTPUT);
logger.debug("Device angle output value on Demand : {}, dSID: {}", value,
this.device.getDSID().getValue());
if (value != 1) {
this.device.updateInternalDeviceState(
new DeviceStateUpdateImpl(DeviceStateUpdate.SLAT_ANGLE, value));
}
}
return;
default:
return;
}
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DeviceOutputValueSensorJob) {
DeviceOutputValueSensorJob other = (DeviceOutputValueSensorJob) obj;
String key = this.device.getDSID().getValue() + this.index;
return key.equals((other.device.getDSID().getValue() + other.index));
}
return false;
}
@Override
public int hashCode() {
return new String(this.device.getDSID().getValue() + this.index).hashCode();
}
@Override
public DSID getDSID() {
return device.getDSID();
}
@Override
public DSID getMeterDSID() {
return this.meterDSID;
}
@Override
public long getInitalisationTime() {
return this.initalisationTime;
}
@Override
public void setInitalisationTime(long time) {
this.initalisationTime = time;
}
@Override
public String toString() {
return "DeviceOutputValueSensorJob [deviceDSID : " + device.getDSID().getValue() + ", meterDSID=" + meterDSID
+ ", initalisationTime=" + initalisationTime + "]";
}
@Override
public String getID() {
return getID(device);
}
/**
* Returns the id for a {@link DeviceOutputValueSensorJob} with the given {@link Device}.
*
* @param device to update
* @return id
*/
public static String getID(Device device) {
return DeviceOutputValueSensorJob.class.getSimpleName() + "-" + device.getDSID().getValue();
}
}

View File

@@ -0,0 +1,119 @@
/**
* 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.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SceneConfigReadingJob} is the implementation of a {@link SensorJob}
* for reading out a scene output value of a digitalSTROM-Device and store it into the {@link Device}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class SceneConfigReadingJob implements SensorJob {
private final Logger logger = LoggerFactory.getLogger(SceneConfigReadingJob.class);
private final Device device;
private short sceneID = 0;
private final DSID meterDSID;
private long initalisationTime = 0;
/**
* Creates a new {@link SceneConfigReadingJob} for the given {@link Device} and the given sceneID.
*
* @param device to update
* @param sceneID to update
*/
public SceneConfigReadingJob(Device device, short sceneID) {
this.device = device;
this.sceneID = sceneID;
this.meterDSID = device.getMeterDSID();
this.initalisationTime = System.currentTimeMillis();
}
@Override
public void execute(DsAPI digitalSTROM, String token) {
DeviceSceneSpec sceneConfig = digitalSTROM.getDeviceSceneMode(token, device.getDSID(), null, null, sceneID);
if (sceneConfig != null) {
device.addSceneConfig(sceneID, sceneConfig);
logger.debug("UPDATED scene configuration for dSID: {}, sceneID: {}, configuration: {}",
this.device.getDSID(), sceneID, sceneConfig);
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SceneConfigReadingJob) {
SceneConfigReadingJob other = (SceneConfigReadingJob) obj;
String str = other.device.getDSID().getValue() + "-" + other.sceneID;
return (this.device.getDSID().getValue() + "-" + this.sceneID).equals(str);
}
return false;
}
@Override
public int hashCode() {
return new String(this.device.getDSID().getValue() + this.sceneID).hashCode();
}
@Override
public DSID getDSID() {
return device.getDSID();
}
@Override
public DSID getMeterDSID() {
return this.meterDSID;
}
@Override
public long getInitalisationTime() {
return this.initalisationTime;
}
@Override
public void setInitalisationTime(long time) {
this.initalisationTime = time;
}
@Override
public String toString() {
return "SceneConfigReadingJob [sceneID: " + sceneID + ", deviceDSID : " + device.getDSID().getValue()
+ ", meterDSID=" + meterDSID + ", initalisationTime=" + initalisationTime + "]";
}
@Override
public String getID() {
return getID(device, sceneID);
}
/**
* Returns the id for a {@link SceneConfigReadingJob} with the given {@link Device} and sceneID.
*
* @param device to update
* @param sceneID to update
* @return id
*/
public static String getID(Device device, Short sceneID) {
return SceneConfigReadingJob.class.getSimpleName() + "-" + device.getDSID().getValue() + "-" + sceneID;
}
}

View File

@@ -0,0 +1,122 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.impl;
import org.openhab.binding.digitalstrom.internal.lib.sensorjobexecutor.sensorjob.SensorJob;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.DsAPI;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SceneOutputValueReadingJob} is the implementation of a {@link SensorJob}
* for reading out a scene configuration of a digitalSTROM-Device and store it into the {@link Device}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class SceneOutputValueReadingJob implements SensorJob {
private final Logger logger = LoggerFactory.getLogger(SceneOutputValueReadingJob.class);
private final Device device;
private short sceneID = 0;
private final DSID meterDSID;
private long initalisationTime = 0;
/**
* Creates a new {@link SceneOutputValueReadingJob} for the given {@link Device} and the given sceneID.
*
* @param device to update
* @param sceneID to update
*/
public SceneOutputValueReadingJob(Device device, short sceneID) {
this.device = device;
this.sceneID = sceneID;
this.meterDSID = device.getMeterDSID();
this.initalisationTime = System.currentTimeMillis();
}
@Override
public void execute(DsAPI digitalSTROM, String token) {
int[] sceneValue = digitalSTROM.getSceneValue(token, this.device.getDSID(), null, null, this.sceneID);
if (sceneValue[0] != -1) {
if (device.isBlind()) {
device.setSceneOutputValue(this.sceneID, sceneValue[0], sceneValue[1]);
} else {
device.setSceneOutputValue(this.sceneID, sceneValue[0]);
}
logger.debug("UPDATED sceneOutputValue for dsid: {}, sceneID: {}, value: {}, angle: {}",
this.device.getDSID(), sceneID, sceneValue[0], sceneValue[1]);
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SceneOutputValueReadingJob) {
SceneOutputValueReadingJob other = (SceneOutputValueReadingJob) obj;
String str = other.device.getDSID().getValue() + "-" + other.sceneID;
return (this.device.getDSID().getValue() + "-" + this.sceneID).equals(str);
}
return false;
}
@Override
public int hashCode() {
return new String(this.device.getDSID().getValue() + this.sceneID).hashCode();
}
@Override
public DSID getDSID() {
return device.getDSID();
}
@Override
public DSID getMeterDSID() {
return this.meterDSID;
}
@Override
public long getInitalisationTime() {
return this.initalisationTime;
}
@Override
public void setInitalisationTime(long time) {
this.initalisationTime = time;
}
@Override
public String toString() {
return "SceneOutputValueReadingJob [sceneID: " + sceneID + ", deviceDSID : " + device.getDSID().getValue()
+ ", meterDSID=" + meterDSID + ", initalisationTime=" + initalisationTime + "]";
}
@Override
public String getID() {
return getID(device, sceneID);
}
/**
* Returns the id for a {@link SceneOutputValueReadingJob} with the given {@link Device} and sceneID.
*
* @param device to update
* @param sceneID to update
* @return id
*/
public static String getID(Device device, Short sceneID) {
return DeviceOutputValueSensorJob.class.getSimpleName() + "-" + device.getDSID().getValue() + "-" + sceneID;
}
}

View File

@@ -0,0 +1,71 @@
/**
* 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.digitalstrom.internal.lib.serverconnection;
/**
* The {@link HttpTransport} executes an request to the DigitalSTROM-Server.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface HttpTransport {
/**
* Executes a digitalSTROM-request through calling {@link #execute(String, int, int)} with default connection time
* out and read timeout.
*
* @param request to execute
* @return response
*/
String execute(String request);
/**
* Executes a digitalSTROM-request.
*
* @param request to execute
* @param connectTimeout of execution
* @param readTimeout of execution
* @return response
*/
String execute(String request, int connectTimeout, int readTimeout);
/**
* Executes a digitalSTROM test request and returns the HTTP-Code.
*
* @param testRequest to execute
* @return HTTP-Code
*/
int checkConnection(String testRequest);
/**
* Returns the connection timeout for sensor data readings.
*
* @return sensor data connection timeout
*/
int getSensordataConnectionTimeout();
/**
* Returns the read timeout for sensor data readings.
*
* @return sensor data read timeout
*/
int getSensordataReadTimeout();
/**
* Saves the SSL-Certificate in a file at the given path.
*
* @param path to save
* @return absolute path
*/
String writePEMCertFile(String path);
}

View File

@@ -0,0 +1,236 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.constants;
/**
* The {@link JSONApiResponseKeysEnum} contains digitalSTROM-JSON response keys.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel completely changed and updated only methods remained
* @author Matthias Siegele completely changed and updated only methods remained
*/
public enum JSONApiResponseKeysEnum {
// GENERAL
OK("ok"),
MESSAGE("message"),
RESULT("result"),
// STRUCTURE
APARTMENT("apartment"),
DS_METERS("dSMeters"),
ZONES("zones"),
CIRCUITS("circuits"),
DEVICES("devices"),
GROUPS("groups"),
REACHABLE_SCENES("reachableScenes"),
// SENSORS
// device
CONSUMPTION("consumption"),
SENSOR_VALUE("sensorValue"),
SENSOR_INDEX("sensorIndex"),
METER_VALUE("meterValue"),
TYPE("type"),
// meter sensors
POWER_CONSUMPTION("powerConsumption"),
ENERGY_METER_VALUE("energyMeterValue"),
ENERGY_METER_VALUE_WS("energyMeterValueWs"),
RESOLUTIONS("resolutions"),
RESOLUTION("resolution"),
SERIES("series"),
UNIT("unit"),
VALUES("values"),
DATE("date"),
// zone/apartment sensors
SENSOR_TYPE("sensorType"),
TEMPERATION_VALUE("TemperatureValue"),
TEMPERATION_VALUE_TIME("TemperatureValueTime"),
HUMIDITY_VALUE("HumidityValue"),
HUMIDITY_VALUE_TIME("HumidityValueTime"),
BRIGHTNESS_VALUE("BrightnessValue"),
BRIGHTNESS_VALUE_TIME("BrightnessValueTime"),
CO2_CONCENTRATION_VALUE("CO2ConcentrationValue"),
CO2_CONCENTRATION_VALUE_TIME("CO2ConcentrationValueTime"),
SENSORS("sensors"),
WEATHER_ICON_ID("WeatherIconId"),
WEATHER_CONDITION_ID("WeatherConditionId"),
WEATHER_SERVICE_ID("WeatherServiceId"),
WEATHER_SERVICE_TIME("WeatherServiceTime"),
// IDs
DSID("dSID"),
DSUID("dSUID"),
DSID_LOWER_CASE("dsid"),
METER_DSID("meterDSID"),
ZONE_ID("ZoneID"),
ZONE_ID_Lower_Z("zoneID"),
DSUID_LOWER_CASE("dsuid"),
GROUP_ID("groupID"),
METER_ID("meterID"),
ID("id"),
SCENE_ID("sceneID"),
NAME("name"),
DISPLAY_ID("DisplayID"),
// DEVICE
// status
IS_PRESENT("isPresent"),
IS_VALID("isValid"),
IS_ON("isOn"),
PRESENT("present"),
ON("on"),
// descriptions
FUNCTION_ID("functionID"),
PRODUCT_REVISION("productRevision"),
PRODUCT_ID("productID"),
HW_INFO("hwInfo"),
OUTPUT_MODE("outputMode"),
BUTTON_ID("buttonID"),
HAS_TAG("hasTag"),
TAGS("tags"),
REVISION_ID("revisionID"),
// config
CLASS("class"),
INDEX("index"),
VALUE("value"),
DONT_CARE("dontCare"),
LOCAL_PRIO("localPrio"),
SPECIAL_MODE("specialMode"),
FLASH_MODE("flashMode"),
LEDCON_INDEX("ledconIndex"),
DIM_TIME_INDEX("dimtimeIndex"),
UP("up"),
DOWN("down"),
// event table
TEST("test"),
ACTION("action"),
HYSTERSIS("hysteresis"),
VALIDITY("validity"),
// EVENTS
EVENTS("events"),
PROPERTIES("properties"),
EVENT_INDEX("eventIndex"),
EVENT_NAME("eventName"),
// SYSTEM & LOGIN
VERSION("version"),
TIME("time"),
TOKEN("token"),
APPLICATION_TOKEN("applicationToken"),
SELF("self"),
// CLIMATE
IS_CONFIGURED("IsConfigured"),
CONTROL_MODE("ControlMode"),
CONTROL_STATE("ControlState"),
CONTROL_DSUID("ControlDSUID"),
OPERATION_MODE("OperationMode"),
TEMPERATURE_VALUE("TemperatureValue"),
NOMINAL_VALUE("NominalValue"),
CONTROL_VALUE("ControlValue"),
TEMPERATURE_VALUE_TIME("TemperatureValueTime"),
NOMINAL_VALUE_TIME("NominalValueTime"),
CONTROL_VALUE_TIME("ControlValueTime"),
CTRL_T_RECENT("CtrlTRecent"),
CTRL_T_REFERENCE("CtrlTReference"),
CTRL_T_ERROR("CtrlTError"),
CTRL_T_ERROR_PREV("CtrlTErrorPrev"),
CTRL_INTEGRAL("CtrlIntegral"),
CTRL_YP("CtrlYp"),
CTRL_YI("CtrlYi"),
CTRL_YD("CtrlYd"),
CTRL_Y("CtrlY"),
CTRL_ANTI_WIND_UP("CtrlAntiWindUp"),
REFERENCE_ZONE("ReferenceZone"),
CTRL_OFFSET("CtrlOffset"),
EMERGENCY_VALUE("EmergencyValue"),
CTRL_KP("CtrlKp"),
CTRL_TS("CtrlTs"),
CTRL_TI("CtrlTi"),
CTRL_KD("CtrlKd"),
CTRL_MIN("CtrlImin"),
CTRL_MAX("CtrlImax"),
CTRL_Y_MIN("CtrlYmin"),
CTRL_Y_MAX("CtrlYmax"),
CTRL_KEEP_FLOOR_WARM("CtrlKeepFloorWarm"),
// UNDEF
COLOR_SELECT("colorSelect"),
MODE_SELECT("modeSelect"),
DIM_MODE("dimMode"),
RGB_MODE("rgbMode"),
GROUP_COLOR_MODE("groupColorMode"),
SOURCE("source"),
IS_SCENE_DEVICE("isSceneDevice"),
// Circuit
HW_VERSION("hwVersion"),
HW_VERSION_STRING("hwVersionString"),
SW_VERSION("swVersion"),
ARM_SW_VERSION("armSwVersion"),
DSP_SW_VERSION("dspSwVersion"),
API_VERSION("apiVersion"),
HW_NAME("hwName"),
BUS_MEMBER_TYPE("busMemberType"),
HAS_DEVICES("hasDevices"),
HAS_METERING("hasMetering"),
VDC_CONFIG_URL("VdcConfigURL"),
VDC_MODEL_UID("VdcModelUID"),
VDC_HARDWARE_GUID("VdcHardwareGuid"),
VDC_HARDWARE_MODEL_GUID("VdcHardwareModelGuid"),
VDC_VENDOR_GUID("VdcVendorGuid"),
VDC_OEM_GUID("VdcOemGuid"),
IGNORE_ACTIONS_FROM_NEW_DEVICES("ignoreActionsFromNewDevices"),
DS_METER_DSID("DSMeterDSID"),
HW_INFO_UPPER_HW("HWInfo"),
VALID("valid"),
VALUE_DS("valueDS"),
TIMESTAMP("timestamp"),
SENSOR_INPUTS("sensorInputs"),
GROUP("group"),
LAST_CALL_SCENE("lastCalledScene"),
ANGLE("angle"),
// Binary inputs
BINARY_INPUTS("binaryInputs"),
STATE("state"),
STATE_VALUE("stateValue"),
TARGET_GROUP_TYPE("targetGroupType"),
TARGET_GROUP("targetGroup"),
INPUT_TYPE("inputType"),
INPUT_ID("inputId");
private final String key;
private JSONApiResponseKeysEnum(String key) {
this.key = key;
}
/**
* Returns the key.
*
* @return key
*/
public String getKey() {
return key;
}
}

View File

@@ -0,0 +1,605 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.HttpTransport;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants.ParameterKeys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link HttpTransportImpl} executes an request to the digitalSTROM-Server.
* <p>
* If a {@link Config} is given at the constructor. It sets the SSL-Certificate what is set in
* {@link Config#getCert()}. If there is no SSL-Certificate, but an path to an external SSL-Certificate file what is set
* in {@link Config#getTrustCertPath()} this will be set. If no SSL-Certificate is set in the {@link Config} it will be
* red out from the server and set in {@link Config#setCert(String)}.
*
* <p>
* If no {@link Config} is given the SSL-Certificate will be stored locally.
*
* <p>
* The method {@link #writePEMCertFile(String)} saves the SSL-Certificate in a file at the given path. If all
* SSL-Certificates shout be ignored the flag <i>exeptAllCerts</i> have to be true at the constructor
* </p>
* <p>
* If a {@link ConnectionManager} is given at the constructor, the session-token is not needed by requests and the
* {@link ConnectionListener}, which is registered at the {@link ConnectionManager}, will be automatically informed
* about
* connection state changes through the {@link #execute(String, int, int)} method.
* </p>
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public class HttpTransportImpl implements HttpTransport {
private static final String LINE_SEPERATOR = System.getProperty("line.separator");
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----" + LINE_SEPERATOR;
private static final String END_CERT = LINE_SEPERATOR + "-----END CERTIFICATE-----" + LINE_SEPERATOR;
private final Logger logger = LoggerFactory.getLogger(HttpTransportImpl.class);
private static final short MAY_A_NEW_SESSION_TOKEN_IS_NEEDED = 1;
private String uri;
private int connectTimeout;
private int readTimeout;
private Config config;
private ConnectionManager connectionManager;
private String cert;
private SSLSocketFactory sslSocketFactory;
private final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return arg0.equals(arg1.getPeerHost()) || arg0.contains("dss.local.");
}
};
/**
* Creates a new {@link HttpTransportImpl} with registration of the given {@link ConnectionManager} and set ignore
* all SSL-Certificates. The {@link Config} will be automatically added from the configurations of the given
* {@link ConnectionManager}.
*
* @param connectionManager to check connection, can be null
* @param exeptAllCerts (true = all will ignore)
*/
public HttpTransportImpl(ConnectionManager connectionManager, boolean exeptAllCerts) {
this.connectionManager = connectionManager;
this.config = connectionManager.getConfig();
init(config.getHost(), config.getConnectionTimeout(), config.getReadTimeout(), exeptAllCerts);
}
/**
* Creates a new {@link HttpTransportImpl} with configurations of the given {@link Config} and set ignore all
* SSL-Certificates.
*
* @param config to get configurations, must not be null
* @param exeptAllCerts (true = all will ignore)
*/
public HttpTransportImpl(Config config, boolean exeptAllCerts) {
this.config = config;
init(config.getHost(), config.getConnectionTimeout(), config.getReadTimeout(), exeptAllCerts);
}
/**
* Creates a new {@link HttpTransportImpl} with configurations of the given {@link Config}.
*
* @param config to get configurations, must not be null
*/
public HttpTransportImpl(Config config) {
this.config = config;
init(config.getHost(), config.getConnectionTimeout(), config.getReadTimeout(), false);
}
/**
* Creates a new {@link HttpTransportImpl}.
*
* @param uri of the server, must not be null
*/
public HttpTransportImpl(String uri) {
init(uri, Config.DEFAULT_CONNECTION_TIMEOUT, Config.DEFAULT_READ_TIMEOUT, false);
}
/**
* Creates a new {@link HttpTransportImpl} and set ignore all SSL-Certificates.
*
* @param uri of the server, must not be null
* @param exeptAllCerts (true = all will ignore)
*/
public HttpTransportImpl(String uri, boolean exeptAllCerts) {
init(uri, Config.DEFAULT_CONNECTION_TIMEOUT, Config.DEFAULT_READ_TIMEOUT, exeptAllCerts);
}
/**
* Creates a new {@link HttpTransportImpl}.
*
* @param uri of the server, must not be null
* @param connectTimeout to set
* @param readTimeout to set
*/
public HttpTransportImpl(String uri, int connectTimeout, int readTimeout) {
init(uri, connectTimeout, readTimeout, false);
}
/**
* Creates a new {@link HttpTransportImpl} and set ignore all SSL-Certificates..
*
* @param uri of the server, must not be null
* @param connectTimeout to set
* @param readTimeout to set
* @param exeptAllCerts (true = all will ignore)
*/
public HttpTransportImpl(String uri, int connectTimeout, int readTimeout, boolean exeptAllCerts) {
init(uri, connectTimeout, readTimeout, exeptAllCerts);
}
private void init(String uri, int connectTimeout, int readTimeout, boolean exeptAllCerts) {
logger.debug("init HttpTransportImpl");
this.uri = fixURI(uri);
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
// Check SSL Certificate
if (exeptAllCerts) {
sslSocketFactory = generateSSLContextWhichAcceptAllSSLCertificats();
} else {
if (config != null) {
cert = config.getCert();
logger.debug("generate SSLcontext from config cert");
if (StringUtils.isNotBlank(cert)) {
sslSocketFactory = generateSSLContextFromPEMCertString(cert);
} else {
if (StringUtils.isNotBlank(config.getTrustCertPath())) {
logger.debug("generate SSLcontext from config cert path");
cert = readPEMCertificateStringFromFile(config.getTrustCertPath());
if (StringUtils.isNotBlank(cert)) {
sslSocketFactory = generateSSLContextFromPEMCertString(cert);
}
} else {
logger.debug("generate SSLcontext from server");
cert = getPEMCertificateFromServer(this.uri);
sslSocketFactory = generateSSLContextFromPEMCertString(cert);
if (sslSocketFactory != null) {
config.setCert(cert);
}
}
}
} else {
logger.debug("generate SSLcontext from server");
cert = getPEMCertificateFromServer(this.uri);
sslSocketFactory = generateSSLContextFromPEMCertString(cert);
}
}
}
private String fixURI(String uri) {
String fixedURI = uri;
if (!fixedURI.startsWith("https://")) {
fixedURI = "https://" + fixedURI;
}
if (fixedURI.split(":").length != 3) {
fixedURI = fixedURI + ":8080";
}
return fixedURI;
}
private String fixRequest(String request) {
return request.replace(" ", "");
}
@Override
public String execute(String request) {
return execute(request, this.connectTimeout, this.readTimeout);
}
private short loginCounter = 0;
@Override
public String execute(String request, int connectTimeout, int readTimeout) {
// NOTE: We will only show exceptions in the debug level, because they will be handled in the checkConnection()
// method and this changes the bridge state. If a command was send it fails than and a sensorJob will be
// execute the next time, by TimeOutExceptions. By other exceptions the checkConnection() method handles it in
// max 1 second.
String response = null;
HttpsURLConnection connection = null;
try {
String correctedRequest = checkSessionToken(request);
connection = getConnection(correctedRequest, connectTimeout, readTimeout);
if (connection != null) {
connection.connect();
final int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_FORBIDDEN) {
if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
response = IOUtils.toString(connection.getErrorStream());
} else {
response = IOUtils.toString(connection.getInputStream());
}
if (response != null) {
if (!response.contains("Authentication failed")) {
if (loginCounter > 0) {
connectionManager.checkConnection(responseCode);
}
loginCounter = 0;
} else {
connectionManager.checkConnection(ConnectionManager.AUTHENTIFICATION_PROBLEM);
loginCounter++;
}
}
}
connection.disconnect();
if (response == null && connectionManager != null
&& loginCounter <= MAY_A_NEW_SESSION_TOKEN_IS_NEEDED) {
if (responseCode == HttpURLConnection.HTTP_FORBIDDEN) {
execute(addSessionToken(correctedRequest, connectionManager.getNewSessionToken()),
connectTimeout, readTimeout);
loginCounter++;
} else {
connectionManager.checkConnection(responseCode);
loginCounter++;
return null;
}
}
return response;
}
} catch (SocketTimeoutException e) {
informConnectionManager(ConnectionManager.SOCKET_TIMEOUT_EXCEPTION);
} catch (java.net.ConnectException e) {
informConnectionManager(ConnectionManager.CONNECTION_EXCEPTION);
} catch (MalformedURLException e) {
informConnectionManager(ConnectionManager.MALFORMED_URL_EXCEPTION);
} catch (java.net.UnknownHostException e) {
informConnectionManager(ConnectionManager.UNKNOWN_HOST_EXCEPTION);
} catch (SSLHandshakeException e) {
informConnectionManager(ConnectionManager.SSL_HANDSHAKE_EXCEPTION);
} catch (IOException e) {
logger.error("An IOException occurred: ", e);
informConnectionManager(ConnectionManager.GENERAL_EXCEPTION);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
private boolean informConnectionManager(int code) {
if (connectionManager != null && loginCounter < MAY_A_NEW_SESSION_TOKEN_IS_NEEDED) {
connectionManager.checkConnection(code);
return true;
}
return false;
}
private String checkSessionToken(String request) {
if (checkNeededSessionToken(request)) {
if (connectionManager != null) {
String sessionToken = connectionManager.getSessionToken();
if (sessionToken == null) {
return addSessionToken(request, connectionManager.getNewSessionToken());
}
return addSessionToken(request, sessionToken);
}
}
return request;
}
private boolean checkNeededSessionToken(String request) {
String functionName = StringUtils.substringAfterLast(StringUtils.substringBefore(request, "?"), "/");
return !DsAPIImpl.METHODS_MUST_NOT_BE_LOGGED_IN.contains(functionName);
}
private String addSessionToken(String request, String sessionToken) {
String correctedRequest = request;
if (!correctedRequest.contains(ParameterKeys.TOKEN)) {
if (correctedRequest.contains("?")) {
correctedRequest = correctedRequest + "&" + ParameterKeys.TOKEN + "=" + sessionToken;
} else {
correctedRequest = correctedRequest + "?" + ParameterKeys.TOKEN + "=" + sessionToken;
}
} else {
correctedRequest = StringUtils.replaceOnce(correctedRequest, StringUtils.substringBefore(
StringUtils.substringAfter(correctedRequest, ParameterKeys.TOKEN + "="), "&"), sessionToken);
}
return correctedRequest;
}
private HttpsURLConnection getConnection(String request, int connectTimeout, int readTimeout) throws IOException {
String correctedRequest = request;
if (StringUtils.isNotBlank(correctedRequest)) {
correctedRequest = fixRequest(correctedRequest);
URL url = new URL(this.uri + correctedRequest);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
if (connection != null) {
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
if (sslSocketFactory != null) {
connection.setSSLSocketFactory(sslSocketFactory);
}
if (hostnameVerifier != null) {
connection.setHostnameVerifier(hostnameVerifier);
}
}
return connection;
}
return null;
}
@Override
public int checkConnection(String testRequest) {
try {
HttpsURLConnection connection = getConnection(testRequest, connectTimeout, readTimeout);
if (connection != null) {
connection.connect();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
if (IOUtils.toString(connection.getInputStream()).contains("Authentication failed")) {
return ConnectionManager.AUTHENTIFICATION_PROBLEM;
}
}
connection.disconnect();
return connection.getResponseCode();
} else {
return ConnectionManager.GENERAL_EXCEPTION;
}
} catch (SocketTimeoutException e) {
return ConnectionManager.SOCKET_TIMEOUT_EXCEPTION;
} catch (java.net.ConnectException e) {
return ConnectionManager.CONNECTION_EXCEPTION;
} catch (MalformedURLException e) {
return ConnectionManager.MALFORMED_URL_EXCEPTION;
} catch (java.net.UnknownHostException e) {
return ConnectionManager.UNKNOWN_HOST_EXCEPTION;
} catch (IOException e) {
return ConnectionManager.GENERAL_EXCEPTION;
}
}
@Override
public int getSensordataConnectionTimeout() {
return config != null ? config.getSensordataConnectionTimeout() : Config.DEFAULT_SENSORDATA_CONNECTION_TIMEOUT;
}
@Override
public int getSensordataReadTimeout() {
return config != null ? config.getSensordataReadTimeout() : Config.DEFAULT_SENSORDATA_READ_TIMEOUT;
}
private String readPEMCertificateStringFromFile(String path) {
if (StringUtils.isBlank(path)) {
logger.error("Path is empty.");
} else {
File dssCert = new File(path);
if (dssCert.exists()) {
if (path.endsWith(".crt")) {
try {
InputStream certInputStream = new FileInputStream(dssCert);
String cert = IOUtils.toString(certInputStream);
if (cert.startsWith(BEGIN_CERT)) {
return cert;
} else {
logger.error("File is not a PEM certificate file. PEM-Certificats starts with: {}",
BEGIN_CERT);
}
} catch (FileNotFoundException e) {
logger.error("Can't find a certificate file at the path: {}\nPlease check the path!", path);
} catch (IOException e) {
logger.error("An IOException occurred: ", e);
}
} else {
logger.error("File is not a certificate (.crt) file.");
}
} else {
logger.error("File not found");
}
}
return null;
}
@Override
public String writePEMCertFile(String path) {
String correctedPath = StringUtils.trimToEmpty(path);
File certFilePath;
if (StringUtils.isNotBlank(correctedPath)) {
certFilePath = new File(correctedPath);
boolean pathExists = certFilePath.exists();
if (!pathExists) {
pathExists = certFilePath.mkdirs();
}
if (pathExists && !correctedPath.endsWith("/")) {
correctedPath = correctedPath + "/";
}
}
InputStream certInputStream = IOUtils.toInputStream(cert);
X509Certificate trustedCert;
try {
trustedCert = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(certInputStream);
certFilePath = new File(
correctedPath + trustedCert.getSubjectDN().getName().split(",")[0].substring(2) + ".crt");
if (!certFilePath.exists()) {
certFilePath.createNewFile();
FileWriter writer = new FileWriter(certFilePath, true);
writer.write(cert);
writer.flush();
writer.close();
return certFilePath.getAbsolutePath();
} else {
logger.error("File allready exists!");
}
} catch (IOException e) {
logger.error("An IOException occurred: ", e);
} catch (CertificateException e1) {
logger.error("A CertificateException occurred: ", e1);
}
return null;
}
private SSLSocketFactory generateSSLContextFromPEMCertString(String pemCert) {
if (StringUtils.isNotBlank(pemCert) && pemCert.startsWith(BEGIN_CERT)) {
try {
InputStream certInputStream = IOUtils.toInputStream(pemCert);
final X509Certificate trustedCert = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(certInputStream);
final TrustManager[] trustManager = new TrustManager[] { new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws CertificateException {
if (!certs[0].equals(trustedCert)) {
throw new CertificateException();
}
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
throws CertificateException {
if (!certs[0].equals(trustedCert)) {
throw new CertificateException();
}
}
} };
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManager, new java.security.SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
logger.error("A NoSuchAlgorithmException occurred: ", e);
} catch (KeyManagementException e) {
logger.error("A KeyManagementException occurred: ", e);
} catch (CertificateException e) {
logger.error("A CertificateException occurred: ", e);
}
} else {
logger.error("Cert is empty");
}
return null;
}
private String getPEMCertificateFromServer(String host) {
HttpsURLConnection connection = null;
try {
URL url = new URL(host);
connection = (HttpsURLConnection) url.openConnection();
connection.setHostnameVerifier(hostnameVerifier);
connection.setSSLSocketFactory(generateSSLContextWhichAcceptAllSSLCertificats());
connection.connect();
java.security.cert.Certificate[] cert = connection.getServerCertificates();
connection.disconnect();
byte[] by = ((X509Certificate) cert[0]).getEncoded();
if (by.length != 0) {
return BEGIN_CERT + Base64.getEncoder().encodeToString(by) + END_CERT;
}
} catch (MalformedURLException e) {
if (!informConnectionManager(ConnectionManager.MALFORMED_URL_EXCEPTION)) {
logger.error("A MalformedURLException occurred: ", e);
}
} catch (IOException e) {
short code = ConnectionManager.GENERAL_EXCEPTION;
if (e instanceof java.net.ConnectException) {
code = ConnectionManager.CONNECTION_EXCEPTION;
} else if (e instanceof java.net.UnknownHostException) {
code = ConnectionManager.UNKNOWN_HOST_EXCEPTION;
}
if (!informConnectionManager(code) || code == -1) {
logger.error("An IOException occurred: ", e);
}
} catch (CertificateEncodingException e) {
logger.error("A CertificateEncodingException occurred: ", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
private SSLSocketFactory generateSSLContextWhichAcceptAllSSLCertificats() {
Security.addProvider(Security.getProvider("SunJCE"));
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}
} };
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
return sslContext.getSocketFactory();
} catch (KeyManagementException e) {
logger.error("A KeyManagementException occurred", e);
} catch (NoSuchAlgorithmException e) {
logger.error("A NoSuchAlgorithmException occurred", e);
}
return null;
}
}

View File

@@ -0,0 +1,86 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.impl;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
/**
* The {@link JSONResponseHandler} checks an digitalSTROM-JSON response and can parse it to an {@link JsonObject}.
*
* @author Alexander Betker - Initial contribution
* @author Alex Maier - Initial contribution
* @author Michael Ochel - add Java-Doc, make methods static and change from SimpleJSON to GSON
* @author Matthias Siegele - add Java-Doc, make methods static and change from SimpleJSON to GSON
*/
public class JSONResponseHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(JSONResponseHandler.class);
/**
* Checks the digitalSTROM-JSON response and return true if it was successful, otherwise false.
*
* @param jsonResponse to check
* @return true, if successful
*/
public static boolean checkResponse(JsonObject jsonResponse) {
if (jsonResponse == null) {
return false;
} else if (jsonResponse.get(JSONApiResponseKeysEnum.OK.getKey()) != null) {
return jsonResponse.get(JSONApiResponseKeysEnum.OK.getKey()).getAsBoolean();
} else {
String message = "unknown message";
if (jsonResponse.get(JSONApiResponseKeysEnum.MESSAGE.getKey()) != null) {
message = jsonResponse.get(JSONApiResponseKeysEnum.MESSAGE.getKey()).getAsString();
}
LOGGER.error("JSONResponseHandler: error in json request. Error message : {}", message);
}
return false;
}
/**
* Returns the {@link JsonObject} from the given digitalSTROM-JSON response {@link String} or null if the json
* response was empty.
*
* @param jsonResponse to convert
* @return jsonObject
*/
public static JsonObject toJsonObject(String jsonResponse) {
if (jsonResponse != null && !jsonResponse.trim().equals("")) {
try {
return (JsonObject) new JsonParser().parse(jsonResponse);
} catch (JsonParseException e) {
LOGGER.error("An JsonParseException occurred by parsing jsonRequest: {}", jsonResponse, e);
}
}
return null;
}
/**
* Returns the result {@link JsonObject} from the given digitalSTROM-JSON response {@link JsonObject}.
*
* @param jsonObject of response
* @return json result object
*/
public static JsonObject getResultJsonObject(JsonObject jsonObject) {
if (jsonObject != null) {
return jsonObject.get(JSONApiResponseKeysEnum.RESULT.getKey()).getAsJsonObject();
}
return null;
}
}

View File

@@ -0,0 +1,306 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang.NullArgumentException;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants.ExeptionConstants;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants.InterfaceKeys;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants.ParameterKeys;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
/**
* The {@link SimpleRequestBuilder} build a request string.<br>
* <br>
* <i><b>Code example</b><br>
* String requestString = {@link SimpleRequestBuilder}.{@link #buildNewRequest(String)}.<br>
* <span style="padding-left:14em">{@link #addRequestClass(String)}.<br>
* </span>
* <span style="padding-left:14em">{@link #addFunction(String)}.<br>
* </span>
* <span style="padding-left:14em">{@link #addParameter(String, String)}. (optional)<br>
* </span>
* <span style="padding-left:14em">{@link #addParameter(String, String)}. (optional)<br>
* </span>
* <span style="padding-left:14em">{@link #buildRequestString()};<br>
* </span></i>
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class SimpleRequestBuilder {
// states
private boolean functionIsChosen = false;
private boolean parameterIsAdded = false;
private boolean classIsChosen = false;
private String request;
private static SimpleRequestBuilder builder;
private static final Lock LOCK = new ReentrantLock();
private SimpleRequestBuilder() {
}
/**
* Returns a {@link SimpleRequestBuilder} with the given intefaceKey as chosen request-interface.
*
* @param interfaceKey must not be null
* @return simpleRequestBuilder with chosen interface
* @throws NullArgumentException if the interfaceKey is null
*/
public static SimpleRequestBuilder buildNewRequest(String interfaceKey) throws NullArgumentException {
if (builder == null) {
builder = new SimpleRequestBuilder();
}
LOCK.lock();
return builder.buildNewRequestInt(interfaceKey);
}
/**
* Returns a {@link SimpleRequestBuilder} with the intefaceKey "Json" as chosen request-interface and adds the given
* requestClass to the request-string.
*
* @param requestClassKey must not be null
* @return simpleRequestBuilder with chosen requestClass
* @throws IllegalArgumentException if a requestClass is already chosen
* @throws NullArgumentException if the requestClassKey is null
*/
public static SimpleRequestBuilder buildNewJsonRequest(String requestClassKey)
throws NullArgumentException, IllegalArgumentException {
return buildNewRequest(InterfaceKeys.JSON).addRequestClass(requestClassKey);
}
private SimpleRequestBuilder buildNewRequestInt(String interfaceKey) {
if (interfaceKey == null) {
throw new NullArgumentException("interfaceKey");
}
request = "/" + interfaceKey + "/";
classIsChosen = false;
functionIsChosen = false;
parameterIsAdded = false;
return this;
}
/**
* Adds a requestClass to the request-string.
*
* @param requestClassKey must not be null
* @return simpleRequestBuilder with chosen requestClass
* @throws IllegalArgumentException if a requestClass is already chosen
* @throws NullArgumentException if the requestClassKey is null
*/
public SimpleRequestBuilder addRequestClass(String requestClassKey)
throws IllegalArgumentException, NullArgumentException {
return builder.addRequestClassInt(requestClassKey);
}
private SimpleRequestBuilder addRequestClassInt(String requestClassKey) {
if (!classIsChosen && requestClassKey != null) {
classIsChosen = true;
request = request + requestClassKey + "/";
} else {
if (!classIsChosen) {
throw new IllegalArgumentException(ExeptionConstants.CLASS_ALREADY_ADDED);
} else {
throw new NullArgumentException("requestClassKey");
}
}
return this;
}
/**
* Adds a function to the request-string.
*
* @param functionKey must not be null
* @return SimpleRequestBuilder with chosen function
* @throws IllegalArgumentException if a function is already chosen
* @throws NullArgumentException if the functionKey is null
*/
public SimpleRequestBuilder addFunction(String functionKey) throws IllegalArgumentException, NullArgumentException {
return builder.addFunctionInt(functionKey);
}
private SimpleRequestBuilder addFunctionInt(String functionKey) {
if (!classIsChosen) {
throw new IllegalArgumentException(ExeptionConstants.NO_CLASS_ADDED);
}
if (!functionIsChosen) {
if (functionKey != null) {
functionIsChosen = true;
request = request + functionKey;
} else {
throw new NullArgumentException("functionKey");
}
} else {
throw new IllegalArgumentException(ExeptionConstants.FUNCTION_ALLREADY_ADDED);
}
return this;
}
/**
* Adds a parameter to the request-string, if the parameter value is not null.
*
* @param parameterKey must not be null
* @param parameterValue can be null
* @return SimpleRequestBuilder with added parameter
* @throws IllegalArgumentException if no class and function added
* @throws NullArgumentException if the parameterKey is null
*/
public SimpleRequestBuilder addParameter(String parameterKey, String parameterValue)
throws IllegalArgumentException, NullArgumentException {
return builder.addParameterInt(parameterKey, parameterValue);
}
/**
* Adds the default parameter for zone-requests to the request-string, if the parameter value is not null.
*
* @param sessionToken
* @param zoneID
* @param zoneName
* @return SimpleRequestBuilder with added parameter
* @throws IllegalArgumentException if no class and function added
* @throws NullArgumentException if the parameterKey is null
*/
public SimpleRequestBuilder addDefaultZoneParameter(String sessionToken, Integer zoneID, String zoneName)
throws IllegalArgumentException, NullArgumentException {
return addParameter(ParameterKeys.TOKEN, sessionToken).addParameter(ParameterKeys.ID, objectToString(zoneID))
.addParameter(ParameterKeys.NAME, zoneName);
}
/**
* Adds a parameter for group-requests t the request-string, if the parameter value is not null.
*
* @param sessionToken
* @param groupID
* @param groupName
* @return SimpleRequestBuilder with added parameter
* @throws IllegalArgumentException if no class and function added
* @throws NullArgumentException if the parameterKey is null
*/
public SimpleRequestBuilder addDefaultGroupParameter(String sessionToken, Short groupID, String groupName)
throws IllegalArgumentException, NullArgumentException {
return addParameter(ParameterKeys.TOKEN, sessionToken)
.addParameter(ParameterKeys.GROUP_ID, objectToString(groupID))
.addParameter(ParameterKeys.GROUP_NAME, groupName);
}
/**
* Adds a parameter for zone-group-requests t the request-string, if the parameter value is not null.
*
* @param sessionToken
* @param zoneID
* @param zoneName
* @param groupID
* @param groupName
* @return SimpleRequestBuilder with added parameter
* @throws IllegalArgumentException if no class and function added
* @throws NullArgumentException if the parameterKey is null
*/
public SimpleRequestBuilder addDefaultZoneGroupParameter(String sessionToken, Integer zoneID, String zoneName,
Short groupID, String groupName) throws IllegalArgumentException, NullArgumentException {
return addDefaultZoneParameter(sessionToken, zoneID, zoneName)
.addParameter(ParameterKeys.GROUP_ID, objectToString(groupID))
.addParameter(ParameterKeys.GROUP_NAME, groupName);
}
/**
* Adds a parameter for device-requests the request-string, if the parameter value is not null.
*
* @param sessionToken
* @param dsid
* @param dSUID
* @param name
* @return SimpleRequestBuilder with added parameter
* @throws IllegalArgumentException if no class and function added
* @throws NullArgumentException if the parameterKey is null
*/
public SimpleRequestBuilder addDefaultDeviceParameter(String sessionToken, DSID dsid, String dSUID, String name)
throws IllegalArgumentException, NullArgumentException {
return addParameter(ParameterKeys.TOKEN, sessionToken).addParameter(ParameterKeys.DSID, objectToString(dsid))
.addParameter(ParameterKeys.DSUID, dSUID).addParameter(ParameterKeys.NAME, name);
}
private SimpleRequestBuilder addParameterInt(String parameterKey, String parameterValue) {
if (allRight()) {
if (parameterKey == null) {
throw new NullArgumentException("parameterKey");
}
if (parameterValue != null) {
if (!parameterIsAdded) {
parameterIsAdded = true;
request = request + "?" + parameterKey + "=" + parameterValue;
} else {
request = request + "&" + parameterKey + "=" + parameterValue;
}
}
}
return this;
}
/**
* Returns the request string.
*
* @return request string
* @throws IllegalArgumentException if no class or function is added.
*/
public String buildRequestString() throws IllegalArgumentException {
String request = builder.buildRequestStringInt();
LOCK.unlock();
return request;
}
private String buildRequestStringInt() {
return allRight() ? request : null;
}
private boolean allRight() {
if (!classIsChosen) {
throw new IllegalArgumentException(ExeptionConstants.NO_CLASS_ADDED);
}
if (!functionIsChosen) {
throw new IllegalArgumentException(ExeptionConstants.NO_FUNCTION);
}
return true;
}
/**
* Convert an {@link Object} to a {@link String} or null, if the obj was null or it was a negative {@link Number}.
*
* @param obj can be null
* @return the {@link String} or null
*/
public static String objectToString(Object obj) {
if (obj == null) {
return null;
}
if (obj instanceof DSID) {
return ((DSID) obj).getValue();
}
if (obj instanceof Number) {
return ((Number) obj).intValue() > -1 ? obj.toString() : null;
}
return obj.toString();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals()
*/
public boolean equals(SimpleRequestBuilder builder) {
return this.request.contains(builder.request);
}
}

View File

@@ -0,0 +1,32 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants;
/**
* The {@link ClassKeys} contains digitalSTROM-JSON class keys.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class ClassKeys {
public static final String APARTMENT = "apartment";
public static final String ZONE = "zone";
public static final String DEVICE = "device";
public static final String CIRCUIT = "circuit";
public static final String STRUCTURE = "structure";
public static final String EVENT = "event";
public static final String METERING = "metering";
public static final String SYSTEM = "system";
public static final String PROPERTY_TREE = "property";
}

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.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants;
/**
* The {@link ExeptionConstants} contains the {@link SimpleRequestBuilder} exception strings.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class ExeptionConstants {
public static final String NO_CLASS_ADDED = "No class added! Please add a class first!";
public static final String CLASS_ALREADY_ADDED = "A class is already added! You can only add one class!";
public static final String FUNCTION_ALLREADY_ADDED = "A function is already added! You can only add one function!";
public static final String NO_FUNCTION = "No function added! Please add a function!";
}

View File

@@ -0,0 +1,132 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants;
/**
* The {@link FunctionKeys} contains digitalSTROM-JSON function keys.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class FunctionKeys {
public static final String CALL_SCENE = "callScene";
public static final String SAVE_SCENE = "saveScene";
public static final String LOGIN = "login";
public static final String LOGOUT = "logout";
public static final String UNDO_SCENE = "undoScene";
public static final String TURN_ON = "turnOn";
public static final String TURN_OFF = "turnOff";
public static final String INCREASE_VALUE = "increaseValue";
public static final String DECREASE_VALUE = "decreaseValue";
public static final String GET_STRUCTURE = "getStructure";
public static final String GET_DEVICES = "getDevices";
public static final String GET_CIRCUITS = "getCircuits";
public static final String LOGIN_APPLICATION = "loginApplication";
public static final String GET_NAME = "getName";
public static final String SET_NAME = "setName";
public static final String SUBSCRIBE = "subscribe";
public static final String UNSUBSCRIBE = "unsubscribe";
public static final String GET = "get";
public static final String SET_VALUE = "setValue";
public static final String GET_CONSUMPTION = "getConsumption";
public static final String RESCAN = "rescan";
public static final String SCENE_SET_NAME = "sceneSetName";
public static final String SCENE_GET_NAME = "sceneGetName";
public static final String PUSH_SENSOR_VALUES = "pushSensorValues";
public static final String GET_REACHABLE_SCENES = "getReachableScenes";
public static final String GET_STATE = "getState";
public static final String GET_GROUPS = "getGroups";
public static final String GET_ENERGY_METER_VALUE = "getEnergyMeterValue";
public static final String GET_STRING = "getString";
public static final String GET_INTEGER = "getInteger";
public static final String GET_BOOLEAN = "getBoolean";
public static final String SET_STRING = "setString";
public static final String SET_INTEGER = "setInteger";
public static final String SET_BOOLEAN = "setBoolean";
public static final String GET_CHILDREN = "getChildren";
public static final String SET_FLAG = "setFlag";
public static final String GET_FLAGS = "getFlags";
public static final String QUERY = "query";
public static final String REMOVE = "remove";
public static final String GET_TYPE = "getType";
public static final String GET_SPEC = "getSpec";
public static final String VERSION = "version";
public static final String TIME = "time";
public static final String FROM_APARTMENT = "fromApartment";
public static final String BY_ZONE = "byZone";
public static final String BY_GROUP = "byGroup";
public static final String BY_DSID = "byDSID";
public static final String ADD = "add";
public static final String SUBTRACT = "subtract";
public static final String LOGGED_IN_USER = "loggedInUser";
public static final String ZONE_ADD_DEVICE = "zoneAddDevice";
public static final String ADD_ZONE = "addZone";
public static final String REMOVE_ZONE = "removeZone";
public static final String REMOVE_DEVICE = "removeDevice";
public static final String PERSIST_SET = "persistSet";
public static final String UNPERSIST_SET = "unpersistSet";
public static final String ADD_GROUP = "addGroup";
public static final String GROUP_ADD_DEVICE = "groupAddDevice";
public static final String GROUP_REMOVE_DEVICE = "groupRemoveDevice";
public static final String GET_RESOLUTIONS = "getResolutions";
public static final String GET_SERIES = "getSeries";
public static final String GET_VALUES = "getValues";
public static final String GET_LATEST = "getLatest";
public static final String ADD_TAG = "addTag";
public static final String REMOVE_TAG = "removeTag";
public static final String HAS_TAG = "hasTag";
public static final String GET_TAGS = "getTags";
public static final String LOCK = "lock";
public static final String UNLOCK = "unlock";
public static final String GET_SENSOR_EVENT_TABLE_ENTRY = "getSensorEventTableEntry";
public static final String SET_SENSOR_EVENT_TABLE_ENTRY = "setSensorEventTableEntry";
public static final String ADD_TO_AREA = "addToArea";
public static final String REMOVE_FROM_AREA = "removeFromArea";
public static final String SET_CONFIG = "setConfig";
public static final String GET_CONFIG = "getConfig";
public static final String GET_CONFIG_WORD = "getConfigWord";
public static final String SET_JOKER_GROUP = "setJokerGroup";
public static final String SET_BUTTON_ID = "setButtonID";
public static final String SET_BUTTON_INPUT_MODE = "setButtonInputMode";
public static final String SET_OUTPUT_MODE = "setOutputMode";
public static final String SET_PROG_MODE = "setProgMode";
public static final String GET_OUTPUT_VALUE = "getOutputValue";
public static final String SET_OUTPUT_VALUE = "setOutputValue";
public static final String GET_SCENE_MODE = "getSceneMode";
public static final String SET_SCENE_MODE = "setSceneMode";
public static final String GET_TRANSITION_TIME = "getTransitionTime";
public static final String SET_TRANSITION_TIME = "setTransitionTime";
public static final String GET_LED_MODE = "getLedMode";
public static final String SET_LED_MODE = "setLedMode";
public static final String GET_SENSOR_VALUE = "getSensorValue";
public static final String GET_SENSOR_TYPE = "getSensorType";
public static final String GET_DSID = "getDSID";
public static final String ENABLE_APPLICATION_TOKEN = "enableToken";
public static final String REQUEST_APPLICATION_TOKEN = "requestApplicationToken";
public static final String REVOKE_TOKEN = "revokeToken";
public static final String GET_SCENE_VALUE = "getSceneValue";
public static final String GET_TEMPERATURE_CONTROL_STATUS = "getTemperatureControlStatus";
public static final String GET_TEMPERATURE_CONTROL_CONFIG = "getTemperatureControlConfig";
public static final String GET_TEMPERATURE_CONTROL_VALUES = "getTemperatureControlValues";
public static final String GET_ASSIGNED_SENSORS = "getAssignedSensors";
public static final String SET_TEMEPERATURE_CONTROL_STATE = "setTemperatureControlState";
public static final String SET_TEMEPERATURE_CONTROL_VALUE = "setTemperatureControlValue";
public static final String GET_SENSOR_VALUES = "getSensorValues";
public static final String SET_SENSOR_SOURCE = "setSensorSource";
public static final String GET_TEMPERATURE_CONTROL_INTERNALS = "getTemperatureControlInternals";
public static final String SET_TEMPERATION_CONTROL_CONFIG = "setTemperatureControlConfig";
public static final String QUERY2 = "query2";
public static final String BLINK = "blink";
public static final String PUSH_SENSOR_VALUE = "pushSensorValue";
}

View File

@@ -0,0 +1,23 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants;
/**
* The {@link InterfaceKeys} contains digitalSTROM-JSON interface keys.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class InterfaceKeys {
public static final String JSON = "json";
}

View File

@@ -0,0 +1,115 @@
/**
* 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.digitalstrom.internal.lib.serverconnection.simpledsrequestbuilder.constants;
/**
* The {@link ParameterKeys} contains digitalSTROM-JSON parameter keys.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public class ParameterKeys {
public static final String TOKEN = "token";
public static final String APPLICATION_TOKEN = "applicationToken";
public static final String APPLICATION_NAME = "applicationName";
public static final String NAME = "name";
public static final String NEW_NAME = "newName";
public static final String DSID = "dsid";
public static final String SCENENUMBER = "sceneNumber";
public static final String LOGIN_TOKEN = "loginToken";
public static final String USER = "user";
public static final String PASSWORD = "password";
public static final String SUBSCRIPTIONID = "subscriptionID";
public static final String TIMEOUT = "timeout";
public static final String GROUP_ID = "groupID";
public static final String GROUP_NAME = "groupName";
public static final String VALUE = "value";
public static final String FORCE = "force";
public static final String ID = "id";
public static final String ENABLE = "enable";
public static final String DISABLE = "disable";
public static final String UNASSIGNED = "unassigned";
public static final String SOURCE_DSID = "sourceDSID";
public static final String SENSOR_TYPE = "sensorType";
public static final String SENSOR_VALUE = "sensorValue";
public static final String FLAG = "flag";
public static final String PATH = "path";
public static final String RAISE = "raise";
public static final String CONTEXT = "context";
public static final String LOCATION = "location";
public static final String SELF = "self";
public static final String ZONE_ID = "zoneID";
public static final String ZONE_NAME = "zoneName";
public static final String OTHER = "other";
public static final String DEVICE_ID = "deviceID";
public static final String UNIT = "unit";
public static final String START_TIME = "startTime";
public static final String END_TIME = "endTime";
public static final String VALUE_COUNT = "valueCount";
public static final String RESOLUTION = "resolution";
public static final String TYPE = "type";
public static final String FROM = "from";
public static final String TAG = "tag";
public static final String CLASS = "class";
public static final String INDEX = "index";
public static final String BUTTON_ID = "buttonID";
public static final String MODE_ID = "modeID";
public static final String MODE = "mode";
public static final String OFFSET = "offset";
public static final String SCENE_ID = "sceneID";
public static final String DONT_CARE = "dontCare";
public static final String LOCAL_PRIO = "localPrio";
public static final String SPECIAL_MODE = "specialMode";
public static final String FLASH_MODE = "flashMode";
public static final String LED_CON_INDEX = "ledconIndex";
public static final String DIM_TIME_INDEX = "dimtimeIndex";
public static final String UP = "up";
public static final String DOWN = "down";
public static final String COLOR_SELECT = "colorSelect";
public static final String MODE_SELECT = "modeSelect";
public static final String DIM_MODE = "dimMode";
public static final String RGB_MODE = "rgbMode";
public static final String GROUP_COLOR_MODE = "groupColorMode";
public static final String SENSOR_INDEX = "sensorIndex";
public static final String EVENT_INDEX = "eventIndex";
public static final String AREA_SCENE = "areaScene";
public static final String EVENT_NAME = "eventName";
public static final String TEST = "test";
public static final String HYSTERSIS = "hysteresis";
public static final String VALIDITY = "validity";
public static final String ACTION = "action";
public static final String BUTTON_NUMBER = "buttonNumber";
public static final String CLICK_TYPE = "clickType";
public static final String SCENE_DEVICE_MODE = "sceneDeviceMode";
public static final String CONTROL_STATE = "ControlState";
public static final String CONTROL_VALUE = "ControlValue";
public static final String QUERY = "query";
public static final String CONTROL_MODE = "ControlMode";
public static final String CONTROL_DSUID = "ControlDSUID";
public static final String CTRL_OFFSET = "CtrlOffset";
public static final String REFERENCE_ZONE = "ReferenceZone";
public static final String EMERGENCY_VALUE = "EmergencyValue";
public static final String MANUAL_VALUE = "ManualValue";
public static final String CTRL_KP = "CtrlKp";
public static final String CTRL_TS = "CtrlTs";
public static final String CTRL_TI = "CtrlTi";
public static final String CTRL_KD = "CtrlKd";
public static final String CTRL_I_MIN = "CtrlImin";
public static final String CTRL_I_MAX = "CtrlImax";
public static final String CTRL_Y_MIN = "CtrlYmin";
public static final String CTRL_Y_MAX = "CtrlYmax";
public static final String CTRL_ANTI_WIND_UP = "CtrlAntiWindUp";
public static final String CTRL_KEEP_FLOOR_WARM = "CtrlKeepFloorWarm";
public static final String SOURCE_DSUID = "sourceDSUID";
public static final String DSUID = "dsuid";
}

View File

@@ -0,0 +1,32 @@
/**
* 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.digitalstrom.internal.lib.structure;
import java.util.Map;
/**
* The {@link Apartment} represents a digitalSTROM-Apartment.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add java-doc
* @author Matthias Siegele - add java-doc
*/
public interface Apartment {
/**
* Returns the {@link Map} of all digitalSTROM-Zones with the zone id as key and the {@link Zone} as value.
*
* @return map of all zones
*/
Map<Integer, Zone> getZoneMap();
}

View File

@@ -0,0 +1,33 @@
/**
* 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.digitalstrom.internal.lib.structure;
import java.util.List;
/**
* The {@link DetailedGroupInfo} represents a digitalSTROM-Group with a list of all dSUID's of the included
* digitalSTROM-Devices.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add java-doc
* @author Matthias Siegele - add java-doc
*/
public interface DetailedGroupInfo extends Group {
/**
* Returns the list of all dSUID's of the included digitalSTROM-Devices.
*
* @return list of all dSUID
*/
List<String> getDeviceList();
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.digitalstrom.internal.lib.structure;
/**
* The {@link Group} represents a digitalSTROM-Group.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add java-doc
* @author Matthias Siegele - add java-doc
*/
public interface Group {
/**
* Returns the group id of this {@link Group}.
*
* @return group id
*/
short getGroupID();
/**
* Returns the name of this {@link Group}.
*
* @return group name
*/
String getGroupName();
}

View File

@@ -0,0 +1,83 @@
/**
* 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.digitalstrom.internal.lib.structure;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
/**
* The {@link Zone} represents a digitalSTROM-Zone.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add java-doc
* @author Matthias Siegele - add java-doc
*/
public interface Zone {
/**
* Returns the zone id of this {@link Zone}.
*
* @return zoneID
*/
int getZoneId();
/**
* Sets the zone id of this {@link Zone}.
*
* @param id to set
*/
void setZoneId(int id);
/**
* Returns the zone name of this {@link Zone}.
*
* @return zone name
*/
String getName();
/**
* Sets the zone name of this {@link Zone}.
*
* @param name to set
*/
void setName(String name);
/**
* Returns the {@link List} of all included groups as {@link DetailedGroupInfo}.
*
* @return list of all groups
*/
List<DetailedGroupInfo> getGroups();
/**
* Adds a group as {@link DetailedGroupInfo}.
*
* @param group to add
*/
void addGroup(DetailedGroupInfo group);
/**
* Returns a {@link List} of all included {@link Device}'s.
*
* @return device list
*/
List<Device> getDevices();
/**
* Adds a {@link Device} to this {@link Zone}.
*
* @param device to add
*/
void addDevice(Device device);
}

View File

@@ -0,0 +1,232 @@
/**
* 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.digitalstrom.internal.lib.structure.devices;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import com.google.gson.JsonObject;
/**
* The {@link AbstractGeneralDeviceInformations} is a abstract implementation of {@link GeneralDeviceInformations} and
* can be implement by subclasses which contains the same device informations like dSID and/or mechanismen like the
* {@link DeviceStatusListener}.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public abstract class AbstractGeneralDeviceInformations implements GeneralDeviceInformation {
protected DSID dsid;
protected String dSUID;
protected Boolean isPresent;
protected Boolean isValide;
protected String name;
protected String displayID;
protected DeviceStatusListener listener;
/**
* Creates a new {@link AbstractGeneralDeviceInformations} through the digitalSTROM json response as
* {@link JsonObject}.
*
* @param jsonDeviceObject json response of the digitalSTROM-Server, must not be null
*/
public AbstractGeneralDeviceInformations(JsonObject jsonDeviceObject) {
if (jsonDeviceObject.get(JSONApiResponseKeysEnum.NAME.getKey()) != null) {
name = jsonDeviceObject.get(JSONApiResponseKeysEnum.NAME.getKey()).getAsString();
}
if (jsonDeviceObject.get(JSONApiResponseKeysEnum.ID.getKey()) != null) {
dsid = new DSID(jsonDeviceObject.get(JSONApiResponseKeysEnum.ID.getKey()).getAsString());
} else if (jsonDeviceObject.get(JSONApiResponseKeysEnum.DSID.getKey()) != null) {
dsid = new DSID(jsonDeviceObject.get(JSONApiResponseKeysEnum.DSID.getKey()).getAsString());
} else if (jsonDeviceObject.get(JSONApiResponseKeysEnum.DSID_LOWER_CASE.getKey()) != null) {
dsid = new DSID(jsonDeviceObject.get(JSONApiResponseKeysEnum.DSID_LOWER_CASE.getKey()).getAsString());
}
if (jsonDeviceObject.get(JSONApiResponseKeysEnum.DSUID.getKey()) != null) {
dSUID = jsonDeviceObject.get(JSONApiResponseKeysEnum.DSUID.getKey()).getAsString();
}
if (jsonDeviceObject.get(JSONApiResponseKeysEnum.DISPLAY_ID.getKey()) != null) {
displayID = jsonDeviceObject.get(JSONApiResponseKeysEnum.DISPLAY_ID.getKey()).getAsString();
}
if (jsonDeviceObject.get(JSONApiResponseKeysEnum.IS_PRESENT.getKey()) != null) {
isPresent = jsonDeviceObject.get(JSONApiResponseKeysEnum.IS_PRESENT.getKey()).getAsBoolean();
} else if (jsonDeviceObject.get(JSONApiResponseKeysEnum.PRESENT.getKey()) != null) {
isPresent = jsonDeviceObject.get(JSONApiResponseKeysEnum.PRESENT.getKey()).getAsBoolean();
}
if (jsonDeviceObject.get(JSONApiResponseKeysEnum.IS_VALID.getKey()) != null) {
isValide = jsonDeviceObject.get(JSONApiResponseKeysEnum.IS_VALID.getKey()).getAsBoolean();
}
}
@Override
public synchronized String getName() {
return this.name;
}
@Override
public synchronized void setName(String name) {
this.name = name;
if (listener != null) {
listener.onDeviceConfigChanged(ChangeableDeviceConfigEnum.DEVICE_NAME);
}
}
@Override
public DSID getDSID() {
return dsid;
}
@Override
public String getDSUID() {
return this.dSUID;
}
@Override
public Boolean isPresent() {
return isPresent;
}
@Override
public void setIsPresent(boolean isPresent) {
this.isPresent = isPresent;
if (listener != null) {
if (!isPresent) {
listener.onDeviceRemoved(this);
} else {
listener.onDeviceAdded(this);
}
}
}
@Override
public Boolean isValid() {
return isValide;
}
@Override
public void setIsValid(boolean isValide) {
this.isValide = isValide;
}
@Override
public void registerDeviceStatusListener(DeviceStatusListener listener) {
if (listener != null) {
this.listener = listener;
listener.onDeviceAdded(this);
}
}
@Override
public DeviceStatusListener unregisterDeviceStatusListener() {
DeviceStatusListener listener = this.listener;
this.listener = null;
return listener;
}
@Override
public boolean isListenerRegisterd() {
return listener != null;
}
@Override
public DeviceStatusListener getDeviceStatusListener() {
return listener;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dSUID == null) ? 0 : dSUID.hashCode());
result = prime * result + ((displayID == null) ? 0 : displayID.hashCode());
result = prime * result + ((dsid == null) ? 0 : dsid.hashCode());
result = prime * result + ((isPresent == null) ? 0 : isPresent.hashCode());
result = prime * result + ((isValide == null) ? 0 : isValide.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AbstractGeneralDeviceInformations)) {
return false;
}
AbstractGeneralDeviceInformations other = (AbstractGeneralDeviceInformations) obj;
if (dSUID == null) {
if (other.dSUID != null) {
return false;
}
} else if (!dSUID.equals(other.dSUID)) {
return false;
}
if (displayID == null) {
if (other.displayID != null) {
return false;
}
} else if (!displayID.equals(other.displayID)) {
return false;
}
if (dsid == null) {
if (other.dsid != null) {
return false;
}
} else if (!dsid.equals(other.dsid)) {
return false;
}
if (isPresent == null) {
if (other.isPresent != null) {
return false;
}
} else if (!isPresent.equals(other.isPresent)) {
return false;
}
if (isValide == null) {
if (other.isValide != null) {
return false;
}
} else if (!isValide.equals(other.isValide)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
@Override
public String getDisplayID() {
return displayID;
}
}

View File

@@ -0,0 +1,293 @@
/**
* 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.digitalstrom.internal.lib.structure.devices;
import java.util.List;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.CachedMeteringValue;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
/**
* The {@link Circuit} represents a circuit of the digitalStrom system. For that all information will be able to get and
* set through the same named getter- and setter-methods. To get informed about status and configuration changes a
* {@link DeviceStatusListener} can be registered. For that and to get the general device informations like the dSID the
* {@link Circuit} implements the {@link GeneralDeviceInformations} interface.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public interface Circuit extends GeneralDeviceInformation {
/**
* Returns the hardware version of this {@link Circuit} as {@link Integer}.
*
* @return hardware version
*/
Integer getHwVersion();
/**
* Sets the hardware version of this {@link Circuit} as {@link Integer}.
*
* @param hwVersion the new hardware version as {@link Integer}
*/
void setHwVersion(Integer hwVersion);
/**
* Returns the hardware version of this {@link Circuit} as {@link String}.
*
* @return hardware version
*/
String getHwVersionString();
/**
* Sets the hardware version of this {@link Circuit} as {@link String}.
*
* @param hwVersionString the new hardware version as {@link Integer}
*/
void setHwVersionString(String hwVersionString);
/**
* Returns the software version of this {@link Circuit} as {@link String}.
*
* @return the software version
*/
String getSwVersion();
/**
* Sets the software version of this {@link Circuit} as {@link String}.
*
* @param swVersion the new software version
*/
void setSwVersion(String swVersion);
/**
* Returns the arm software version of this {@link Circuit} as {@link Integer}.
*
* @return the arm software version
*/
Integer getArmSwVersion();
/**
* Sets the arm software version of this {@link Circuit} as {@link Integer}.
*
* @param armSwVersion the new arm software version
*/
void setArmSwVersion(Integer armSwVersion);
/**
* Returns the dsp software version of this {@link Circuit} as {@link Integer}.
*
* @return the dsp softwaree version
*/
Integer getDspSwVersion();
/**
* Sets the dsp software version of this {@link Circuit} as {@link Integer}.
*
* @param dspSwVersion the new dsp software version
*/
void setDspSwVersion(Integer dspSwVersion);
/**
* Returns the api version of this {@link Circuit} as {@link Integer}.
*
* @return the api version as {@link Integer}
*/
Integer getApiVersion();
/**
* Setss the api version of this {@link Circuit} as {@link Integer}.
*
* @param apiVersion the new api version
*/
void setApiVersion(Integer apiVersion);
/**
* Returns the hardware name of this {@link Circuit}.
*
* @return the hardware name
*/
String getHwName();
/**
* Sets the hardware name of this {@link Circuit}.
*
* @param hwName the new hardware name
*/
void setHwName(String hwName);
/**
* Returns the bus member type of this {@link Circuit} as {@link Integer}.
*
* @return the bus member type
*/
Integer getBusMemberType();
/**
* Sets the bus member type of this {@link Circuit} as {@link Integer}.
*
* @param busMemberType the new bus member type
*/
void setBusMemberType(Integer busMemberType);
/**
* Returns true, if this {@link Circuit} has connected {@link Device}'s, otherwise false.
*
* @return true, if {@link Device}'s are connected
*/
Boolean getHasDevices();
/**
* Sets the connected devices flag.
*
* @param hasDevices the new connected devices flag
*/
void setHasDevices(Boolean hasDevices);
/**
* Returns true, if this {@link Circuit} is valid to metering power data, otherwise false.
*
* @return true, if is valid to metering power data
*/
Boolean getHasMetering();
/**
* Sets the flag hasMetering.
*
* @param hasMetering the new hasMetering flag.
*/
void setHasMetering(Boolean hasMetering);
/**
* Returns the vdc configuration URL of this {@link Circuit} as {@link String}.
*
* @return the vdc configuration URL
*/
String getVdcConfigURL();
/**
* Sets the vdc configuration URL of this {@link Circuit} as {@link String}.
*
* @param vdcConfigURL the new vdc configuration URL
*/
void setVdcConfigURL(String vdcConfigURL);
/**
* Returns the vdc mode UID of this {@link Circuit} as {@link String}.
*
* @return the vdc mode UID
*/
String getVdcModelUID();
/**
* Sets the vdc mode UID of this {@link Circuit} as {@link String}.
*
* @param vdcModelUID the new vdc mode UID
*/
void setVdcModelUID(String vdcModelUID);
/**
* Returns the vdc hardware GUID of this {@link Circuit} as {@link String}.
*
* @return the vdc hardware GUID
*/
String getVdcHardwareGuid();
/**
* Sets the vdc hardware GUID of this {@link Circuit} as {@link String}.
*
* @param vdcHardwareGuid the new vdc hardware GUID
*/
void setVdcHardwareGuid(String vdcHardwareGuid);
/**
* Returns the vdc hardware model GUID of this {@link Circuit} as {@link String}.
*
* @return the vdc hardware mode GUID
*/
String getVdcHardwareModelGuid();
/**
* Sets the vdc hardware model GUID of this {@link Circuit} as {@link String}.
*
* @param vdcHardwareModelGuid the new vdc model GUID
*/
void setVdcHardwareModelGuid(String vdcHardwareModelGuid);
/**
* Returns the vdc vendor GUID of this {@link Circuit} as {@link String}.
*
* @return the vdc vendor GUID
*/
String getVdcVendorGuid();
/**
* Sets the vdc vendor GUID of this {@link Circuit} as {@link String}.
*
* @param vdcVendorGuid the new vdc vendor GUID
*/
void setVdcVendorGuid(String vdcVendorGuid);
/**
* Returns the vdc oem GUID of this {@link Circuit} as {@link String}.
*
* @return the vdc oem GUID
*/
String getVdcOemGuid();
/**
* Sets the vdc oem GUID of this {@link Circuit} as {@link String}.
*
* @param vdcOemGuid the new vdc oem GUID
*/
void setVdcOemGuid(String vdcOemGuid);
/**
* Returns true, if actions from new {@link Device}'s will be ignored by this {@link Circuit}, otherwise false.
*
* @return true, if actions form new device will be ignored
*/
Boolean getIgnoreActionsFromNewDevices();
/**
* Sets the flag for ignore actions from new {@link Device}'s.
*
* @param ignoreActionsFromNewDevices the new ignore actions from new devices flag
*/
void setIgnoreActionsFromNewDevices(Boolean ignoreActionsFromNewDevices);
/**
* Adds a new {@link CachedMeteringValue} or update the existing, if the new one is newer.
*
* @param cachedMeteringValue the new {@link CachedMeteringValue}
*/
void addMeteringValue(CachedMeteringValue cachedMeteringValue);
/**
* Returns the value of the given {@link CachedMeteringValue} through the {@link MeteringTypeEnum} and
* {@link MeteringUnitsEnum}.
*
* @param meteringType (must not be null)
* @param meteringUnit (can be null, default is {@link MeteringUnitsEnum#WH})
* @return the metering value or -1, if the metering value dose not exist
*/
double getMeteringValue(MeteringTypeEnum meteringType, MeteringUnitsEnum meteringUnit);
/**
* Returns the {@link List} of all {@link CachedMeteringValue}'s.
*
* @return list of all {@link CachedMeteringValue}
*/
List<CachedMeteringValue> getAllCachedMeteringValues();
}

View File

@@ -0,0 +1,870 @@
/**
* 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.digitalstrom.internal.lib.structure.devices;
import java.util.List;
import java.util.Map;
import org.openhab.binding.digitalstrom.internal.lib.config.Config;
import org.openhab.binding.digitalstrom.internal.lib.event.types.EventItem;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.FunctionalColorGroupEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceBinaryInput;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceSensorValue;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
/**
* The {@link Device} represents a digitalSTROM internal stored device.
*
* @author Alexander Betker - Initial contribution
* @author Michael Ochel - add methods for ESH, new functionalities and JavaDoc
* @author Mathias Siegele - add methods for ESH, new functionalities and JavaDoc
*/
public interface Device extends GeneralDeviceInformation {
/**
* Returns the id of the dS-Meter in which the device is registered.
*
* @return meterDSID
*/
DSID getMeterDSID();
/**
* Sets the id of the dS-Meter in which the device is registered.
*
* @param meterDSID to set
*/
void setMeterDSID(String meterDSID);
/**
* Returns the hardware info of this device.
* You can see all available hardware info at
* http://www.digitalstrom.com/Partner/Support/Techn-Dokumentation/
*
* @return hardware info
*/
String getHWinfo();
/**
* Returns the zone id in which this device is in.
*
* @return zoneID
*/
int getZoneId();
/**
* Sets the zoneID of this device.
*
* @param zoneID to set
*/
void setZoneId(int zoneID);
/**
* Returns true, if this device is on, otherwise false.
*
* @return is on (true = on | false = off)
*/
boolean isOn();
/**
* Adds an on command as {@link DeviceStateUpdate}, if the flag is true or off command, if it is false to the list
* of
* outstanding commands.
*
* @param flag (true = on | false = off)
*/
void setIsOn(boolean flag);
/**
* Returns true, if this shade device is open, otherwise false.
*
* @return is on (true = open | false = closed)
*/
boolean isOpen();
/**
* Adds an open command as {@link DeviceStateUpdate}, if the flag is true or closed command, if it is false to the
* list of outstanding commands.
*
* @param flag (true = open | false = closed)
*/
void setIsOpen(boolean flag);
/**
* Returns true, if this device is dimmable, otherwise false.
*
* @return is dimmable (true = yes | false = no)
*/
boolean isDimmable();
/**
* Returns true, if this device is a shade device (grey), otherwise false.
*
* @return is shade (true = yes | false = no)
*/
boolean isShade();
/**
* Returns true, if the device output mode isn't disabled.
*
* @return have output mode (true = yes | false = no)
*/
boolean isDeviceWithOutput();
/**
* Returns the current functional color group of this device.
* For more informations please have a look at {@link FunctionalColorGroupEnum}.
*
* @return current functional color group
*/
FunctionalColorGroupEnum getFunctionalColorGroup();
/**
* Sets the functional color group of this device.
*
* @param fuctionalColorGroup to set
*/
void setFunctionalColorGroup(FunctionalColorGroupEnum fuctionalColorGroup);
/**
* Returns the current output mode of this device.
* Some devices are able to have different output modes e.g. the device GE-KM200 is able to
* be in dimm mode, switch mode or disabled.
* For more informations please have a look at {@link OutputModeEnum}.
*
* @return the current output mode of this device
*/
OutputModeEnum getOutputMode();
/**
* Adds an increase command as {@link DeviceStateUpdate} to the list of outstanding commands.
*/
void increase();
/**
* Adds an decrease command as {@link DeviceStateUpdate} to the list of outstanding commands.
*/
void decrease();
/**
* Returns the current slat position of this device.
*
* @return current slat position
*/
int getSlatPosition();
/**
* Adds an set slat position command as {@link DeviceStateUpdate} with the given slat position to the list of
* outstanding commands.
*
* @param slatPosition to set
*/
void setSlatPosition(int slatPosition);
/**
* Returns the maximal slat position value of this device.
*
* @return maximal slat position value
*/
int getMaxSlatPosition();
/**
* Returns the minimal slat position value of this device.
*
* @return minimal slat position value
*/
int getMinSlatPosition();
/**
* Returns the current output value of this device.
* This can be the slat position or the brightness of this device.
*
* @return current output value
*/
short getOutputValue();
/**
* Adds an set output value command as {@link DeviceStateUpdate} with the given output value to the list of
* outstanding commands.
*
* @param outputValue to set
*/
void setOutputValue(short outputValue);
/**
* Returns the maximal output value of this device.
*
* @return maximal output value
*/
short getMaxOutputValue();
/**
* Returns a list with group id's in which the device is part of.
*
* @return List of group id's
*/
List<Short> getGroups();
/**
* Adds the given groupID to the group list.
*
* @param groupID to add
*/
void addGroup(Short groupID);
/**
* Overrides the existing group list with the given new.
*
* @param newGroupList to set
*/
void setGroups(List<Short> newGroupList);
/**
* Returns the scene output value of this device of the given scene id as {@link Integer} array. The first field is
* the output value and the second is the angle value or -1 if no angle value exists.
* If the method returns null, this scene id isn't read yet.
*
* @param sceneID of the scene
* @return scene output value and scene angle value or null, if it isn't read out yet
*/
Integer[] getSceneOutputValue(short sceneID);
/**
* Sets the scene output value of this device for the given scene id and scene output value.
*
* @param sceneId to set
* @param sceneOutputValue to set
*/
void setSceneOutputValue(short sceneId, int sceneOutputValue);
/**
* This configuration is very important. The devices can
* be configured to not react to some commands (scene calls).
* So you can't imply that a device automatically turns on (by default yes,
* but if someone configured his own scenes, then maybe not) after a
* scene call. This method returns true or false, if the configuration
* for this sceneID already has been read
*
* @param sceneId the sceneID
* @return true if this device has the configuration for this specific scene
*/
boolean containsSceneConfig(short sceneId);
/**
* Add the config for this scene. The config has the configuration
* for the specific sceneID.
*
* @param sceneId scene call id
* @param sceneSpec config for this sceneID
*/
void addSceneConfig(short sceneId, DeviceSceneSpec sceneSpec);
/**
* Get the config for this scene. The config has the configuration
* for the specific sceneID.
*
* @param sceneId scene call id
* @return sceneSpec config for this sceneID
*/
DeviceSceneSpec getSceneConfig(short sceneId);
/**
* Should the device react on this scene call or not .
*
* @param sceneId scene call id
* @return true, if this device should react on this sceneID
*/
boolean doIgnoreScene(short sceneId);
// follow methods added by Michael Ochel and Matthias Siegele
/**
* Returns true, if all sensor data are up to date or false if some have to be updated.
*
* @return is up to date (true = yes | false = no)
*/
boolean isSensorDataUpToDate();
/**
* Sets the priority to refresh the data of the sensors to the given priorities.
* They can be never, low, medium or high.
*
* @param powerConsumptionRefreshPriority to set
* @param electricMeterRefreshPriority to set
* @param energyMeterRefreshPriority to set
*/
void setSensorDataRefreshPriority(String powerConsumptionRefreshPriority, String electricMeterRefreshPriority,
String energyMeterRefreshPriority);
/**
* Returns true, if the device is up to date.
*
* @return digitalSTROM-Device is up to date (true = yes | false = no)
*/
boolean isDeviceUpToDate();
/**
* Returns the next {@link DeviceStateUpdate} to update the digitalSTROM-Device on the digitalSTROM-Server.
*
* @return DeviceStateUpdate for digitalSTROM-Device
*/
DeviceStateUpdate getNextDeviceUpdateState();
/**
* Update the internal stored device object.
*
* @param deviceStateUpdate to update
*/
void updateInternalDeviceState(DeviceStateUpdate deviceStateUpdate);
/**
* Call the given {@link InternalScene} on this {@link Device} and updates it.
*
* @param scene to call
*/
void callInternalScene(InternalScene scene);
/**
* Undo the given {@link InternalScene} on this {@link Device} and updates it.
*
* @param scene to undo
*/
void undoInternalScene(InternalScene scene);
/**
* Initial a call scene for the given scene number.
*
* @param sceneNumber to call
*/
void callScene(Short sceneNumber);
/**
* Returns the current active {@link InternalScene}, otherwise null.
*
* @return active {@link InternalScene} or null
*/
InternalScene getAcitiveScene();
/**
* Undo the active scene if a scene is active.
*/
void undoScene();
/**
* Checks the scene configuration for the given scene number and initial a scene configuration reading with the
* given priority if no scene configuration exists.
*
* @param sceneNumber to check
* @param prio to update
*/
void checkSceneConfig(Short sceneNumber, short prio);
/**
* Sets the given output mode as new output mode of this {@link Device}.
*
* @param newOutputMode to set
*/
void setOutputMode(OutputModeEnum newOutputMode);
/**
* Returns a {@link List} of all saved scene-IDs configurations.
*
* @return a {@link List} of all saved scene-IDs
*/
List<Short> getSavedScenes();
/**
* Initializes a internal device update as call scene for the given scene number.
*
* @param sceneNumber to call
*/
void internalCallScene(Short sceneNumber);
/**
* Initializes a internal device update as undo scene.
*/
void internalUndoScene();
/**
* Returns true, if this {@link Device} is a device with a switch output mode.
*
* @return true, if it is a switch otherwise false
*/
boolean isSwitch();
/**
* Sets the given {@link Config} as new {@link Config}.
*
* @param config to set
*/
void setConfig(Config config);
/**
* Returns the current angle position of the {@link Device}.
*
* @return current angle position
*/
short getAnglePosition();
/**
* Adds an set angle value command as {@link DeviceStateUpdate} with the given angle value to the list of
* outstanding commands.
*
* @param angle to set
*/
void setAnglePosition(int angle);
/**
* Sets the scene output value and scene output angle of this device for the given scene id, scene output value and
* scene output angle.
*
* @param sceneId to set
* @param value to set
* @param angle to set
*/
void setSceneOutputValue(short sceneId, int value, int angle);
/**
* Returns the max angle value of the slat.
*
* @return max slat angle
*/
int getMaxSlatAngle();
/**
* Returns the min angle value of the slat.
*
* @return min slat angle
*/
int getMinSlatAngle();
/**
* Returns true, if it is a blind device.
*
* @return is blind (true = yes | false = no
*/
boolean isBlind();
/**
* Saves scene configurations from the given sceneProperties in the {@link Device}. <br>
* The {@link Map} has to be like the following format:
* <ul>
* <li><b>Key:</b> scene[sceneID]</li>
* <li><b>Value:</b> {Scene: [sceneID], dontcare: [don't care flag], localPrio: [local prio flag], specialMode:
* [special mode flag]}(0..1), {sceneValue: [scene value], sceneAngle: [scene angle]}(0..1))</li>
* </ul>
*
* @param sceneProperties to save
*/
void saveConfigSceneSpecificationIntoDevice(Map<String, String> sceneProperties);
/**
* Returns the min output value.
*
* @return min output value
*/
short getMinOutputValue();
/**
* Adds a slat increase command as {@link DeviceStateUpdate} to the list of outstanding commands.
*/
void increaseSlatAngle();
/**
* Adds a slat decrease command as {@link DeviceStateUpdate} to the list of outstanding commands.
*/
void decreaseSlatAngle();
/**
* Saves scene configurations from the given sceneProperties in the {@link Device}. <br>
* <br>
* <b>The {@link String} has to be like the following format:</b><br>
* {[sceneID] = }(1){Scene: [sceneID], dontcare: [don't care flag], localPrio: [local prio flag], specialMode:
* [special mode flag]}(0..1), {sceneValue: [sceneValue]{, sceneAngle: [scene angle]}(0..1)}{\n}(0..1)<br>
* <br>
* e.g. "10 = Scene: PRESET_4, dontcare: false, localPrio: false, specialMode: false, flashMode: false, sceneValue:
* 0\n"
*
* @param propertries to save
*/
void saveConfigSceneSpecificationIntoDevice(String propertries);
/**
* Returns true, if this {@link Device} is a sensor device. That means, that this {@link Device} has no output
* channel
* ({@link OutputModeEnum#DISABLED}), but climate sensors.
*
* @return true, if it is a sensor device
*/
boolean isSensorDevice();
/**
* Returns true, if this {@link Device} is a heating device. That means, that the output mode of this {@link Device}
* is one of the following modes {@link OutputModeEnum#PWM} or {@link OutputModeEnum#SWITCH} and the
* {@link FuncNameAndColorGroupEnum} is {@link FuncNameAndColorGroupEnum#HEATING}.
*
* @return true, if it is a heating device
*/
boolean isHeatingDevice();
/**
* Sets the refresh priority for the given power sensor as {@link SensorEnum}. <br>
* <b>Note:</b><br>
* 1. The device must have this sensor type, otherwise the set has no effect.<br>
* <br>
* 2. Valid priorities are:<br>
* - {@link Config#REFRESH_PRIORITY_NEVER}<br>
* - {@link Config#REFRESH_PRIORITY_LOW}<br>
* - {@link Config#REFRESH_PRIORITY_MEDIUM}<br>
* - {@link Config#REFRESH_PRIORITY_HIGH}<br>
* <br>
* 3. Valid sensor types are:<br>
* - {@link SensorEnum#POWER_CONSUMPTION}<br>
* - {@link SensorEnum#OUTPUT_CURRENT}<br>
* - {@link SensorEnum#ELECTRIC_METER}<br>
* - {@link SensorEnum#ACTIVE_POWER}<br>
*
* @param powerSensorType the power sensor to set
* @param refreshPriority the new refresh priority
*/
void setSensorDataRefreshPriority(SensorEnum powerSensorType, String refreshPriority);
/**
* Returns the refresh priority of the given power sensor type as {@link SensorEnum}. If the sensor type is not
* supported by
* this {@link Device} or it is not a power sensor it will be returned null.
*
* @param powerSensorType of the sensor
* @return the refresh priority
*/
String getPowerSensorRefreshPriority(SensorEnum powerSensorType);
/**
* Returns a {@link List} with all power sensors, which are supported by this {@link Device}.
*
* @return all supported power sensors
*/
List<SensorEnum> getPowerSensorTypes();
/**
* Returns a {@link List} with all climate sensors, which are supported by this {@link Device}.
*
* @return all supported climate sensors
*/
List<SensorEnum> getClimateSensorTypes();
/**
* Returns all {@link DeviceSensorValue}'s of this {@link Device}.
*
* @return list of all {@link DeviceSensorValue}'s
*/
List<DeviceSensorValue> getDeviceSensorValues();
/**
* Sets the given {@link DeviceSensorValue}. That means the given {@link DeviceSensorValue} will be added, if this
* type of {@link DeviceSensorValue} does not exist before, otherwise the existing {@link DeviceSensorValue} will be
* updated,
* if the given {@link DeviceSensorValue} is newer.
*
* @param deviceSensorValue the new device sensor value
*/
void setDeviceSensorValue(DeviceSensorValue deviceSensorValue);
/**
* Returns the {@link DeviceSensorValue} of the given sensor type as {@link SensorEnum} or null, if no
* {@link DeviceSensorValue} exists for the given sensor type.
*
* @param sensorType of the sensor
* @return the {@link DeviceSensorValue} or null
*/
DeviceSensorValue getDeviceSensorValue(SensorEnum sensorType);
/**
* Returns the {@link DeviceSensorValue} of the given sensor index as {@link Short} or null, if no
* {@link DeviceSensorValue} exists for the given sensor index.
*
* @param sensorIndex of the sensor
* @return the {@link DeviceSensorValue} or null
*/
DeviceSensorValue getDeviceSensorValue(Short sensorIndex);
/**
* Returns the sensor index for the given sensor type as {@link SensorEnum} of the {@link Device} or null, if the
* sensor type does not exist. It will be needed to readout the current sensor value of the digitalSTROM device.
*
* @param sensorType of the sensor
* @return sensor index for the sensor type
*/
Short getSensorIndex(SensorEnum sensorType);
/**
* Returns the sensor type as {@link SensorEnum} of the given sensor index or null, if the given sensor type does
* not exist.
*
* @param sensorIndex of the sensor
* @return the sensor type or null
*/
SensorEnum getSensorType(Short sensorIndex);
/**
* Returns the internal digitalSTROM sensor value for the given sensor type as {@link SensorEnum}, if the sensor
* type exists and the value is valid. The resolution can be found at {@link SensorEnum}.
*
* @param sensorType of the sensor
* @return the internal digitalSTROM sensor value or null
*/
Integer getDsSensorValue(SensorEnum sensorType);
/**
* Returns the internal digitalSTROM sensor value for the given sensor index as {@link Short}, if the sensor
* index exists and the value is valid. The resolution can be found at {@link SensorEnum}.
*
* @param sensorIndex of the sensor
* @return the internal digitalSTROM sensor value or null
*/
Integer getDsSensorValue(Short sensorIndex);
/**
* Returns the float sensor value for the given sensor type as {@link SensorEnum}, if the sensor
* type exists and the value is valid. The resolution can be found at {@link SensorEnum}.
*
* @param sensorType of the sensor
* @return the float sensor value or null
*/
Float getFloatSensorValue(SensorEnum sensorType);
/**
* Returns the float sensor value for the given sensor index as {@link Short}, if the sensor
* index exists and the value is valid. The resolution can be found at {@link SensorEnum}.
*
* @param sensorIndex of the sensor
* @return the float sensor value or null
*/
Float getFloatSensorValue(Short sensorIndex);
/**
* Sets the float sensor value for a given sensor type as {@link SensorEnum}. If the sensor type does not exist, it
* will be returned false.
*
* @param sensorType of the sensor
* @param floatSensorValue the new float sensor value
* @return true, if it was successful, otherwise false
*/
boolean setFloatSensorValue(SensorEnum sensorType, Float floatSensorValue);
/**
* Sets the float sensor value for a given sensor index as {@link Short}. If the sensor type does not exist, it
* will be returned false.
*
* @param sensorIndex of the sensor
* @param floatSensorValue the new float sensor value
* @return true, if it was successful, otherwise false
*/
boolean setFloatSensorValue(Short sensorIndex, Float floatSensorValue);
/**
* Sets the internal digitalSTROM sensor value for a given sensor index as {@link Short}. If the sensor index does
* not exist, it will be returned false.
*
* @param sensorIndex of the sensor
* @param dSSensorValue the new internal digitalSTROM sensor value
* @return true, if it was successful, otherwise false
*/
boolean setDsSensorValue(Short sensorIndex, Integer dSSensorValue);
/**
* Sets the internal digitalSTROM sensor value for a given sensor type as {@link SensorEnum}. If the sensor type
* does
* not exist, it will be returned false.
*
* @param sensorType of the sensor
* @param dSSensorValue the new internal digitalSTROM sensor value
* @return true, if it was successful, otherwise false
*/
boolean setDsSensorValue(SensorEnum sensorType, Integer dSSensorValue);
/**
* Sets the internal digitalSTROM and float sensor value for a given sensor index as {@link Short}. If the sensor
* index does not exist, it will be returned false.
*
* @param sensorIndex of the sensor
* @param dSSensorValue the new internal digitalSTROM sensor value
* @param floatSensorValue the new float sensor value
* @return true, if it was successful, otherwise false
*/
boolean setDsSensorValue(Short sensorIndex, Integer dSSensorValue, Float floatSensorValue);
/**
* Sets the internal digitalSTROM and float sensor value for a given sensor type as {@link SensorEnum}. If the
* sensor type does not exist, it will be returned false.
*
* @param sensorType of the sensor
* @param dSSensorValue the new internal digitalSTROM sensor value
* @param floatSensorValue the new float sensor value
* @return true, if it was successful, otherwise false
*/
boolean setDsSensorValue(SensorEnum sensorType, Integer dSSensorValue, Float floatSensorValue);
/**
* Returns true, if this {@link Device} has sensors, otherwise false.
*
* @return true, if device has sensors
*/
boolean hasSensors();
/**
* Returns true, if this {@link Device} has climate sensors, otherwise false.
*
* @return true, if device has climate sensors
*/
boolean hasClimateSensors();
/**
* Returns true, if this {@link Device} has power sensors, otherwise false.
*
* @return true, if device has power sensors
*/
boolean hasPowerSensors();
/**
* Only needed for {@link DeviceConsumptionSensorJob}'s. To set the internal digitalSTROM sensor value please use
* {@link #setDsSensorValue(SensorEnum, Integer)}.
*
* @param sensorType of the sensor
* @param value new value
*/
void setDeviceSensorDsValueBySensorJob(SensorEnum sensorType, Integer value);
/**
* Enables the internal sensor echo box for {@link EventNames#DEVICE_SENSOR_VALUE} events.
*/
void enableSensorEchoBox();
/**
* Disables the internal sensor echo box for {@link EventNames#DEVICE_SENSOR_VALUE} events.
*/
void disableSensorEchoBox();
/**
* Returns true, if the internal sensor echo box is enabled, otherwise false.
*
* @return true, if the internal sensor echo box is enabled
*/
boolean isSensorEchoBoxEnabled();
/**
* Sets the {@link DeviceSensorValue} through a {@link EventItem} of the type
* {@link EventNames#DEVICE_SENSOR_VALUE}.
*
* @param event of the sensor update
*/
void setDeviceSensorByEvent(EventItem event);
/**
* Returns true, if the refresh priority of the given power sensor type as {@link SensorEnum} is equals
* {@link Config#REFRESH_PRIORITY_NEVER}, otherwise false.
*
* @param powerSensorType of the sensor
* @return true, if refresh priority is never
*/
boolean checkPowerSensorRefreshPriorityNever(SensorEnum powerSensorType);
/**
* Returns true, if the given sensor type as {@link SensorEnum} is supported by this {@link Device}, otherwise
* false.
*
* @param sensorType of the sensor
* @return true, if the sensor type is supported
*/
boolean supportsSensorType(SensorEnum sensorType);
/**
* Returns true, if this {@link Device} is a temperature controlled device, otherwise false. That means, that the
* output mode is one of the output modes in
* {@link OutputModeEnum#outputModeIsTemperationControlled(OutputModeEnum)}.
*
* @return true, if this {@link Device} is a temperature controlled
*/
boolean isTemperatureControlledDevice();
/**
* Returns true, if this {@link Device} is a binary input device. That means it have no output mode
* ({@link OutputModeEnum#DISABLED}), but {@link DeviceBinaryInput}'s.
*
* @return true, if this {@link Device} is a binary input device
*/
boolean isBinaryInputDevice();
/**
* Returns a {@link List} which contains all currently configured {@link DeviceBinaryInput}'s.
*
* @return list with all configured {@link DeviceBinaryInput}'s
*/
List<DeviceBinaryInput> getBinaryInputs();
/**
* Returns the {@link DeviceBinaryInput} of the given binary input type as {@link DeviceBinarayInputEnum}} or null,
* if the binary input type does not exist.
*
* @param binaryInputType of the {@link DeviceBinaryInput}
* @return the {@link DeviceBinaryInput} or null
*/
DeviceBinaryInput getBinaryInput(DeviceBinarayInputEnum binaryInputType);
/**
* Returns the state of the given binary input type as {@link DeviceBinarayInputEnum}} or null, if the binary input
* type does not exist.
*
* @param binaryInputType of the {@link DeviceBinaryInput}
* @return state of the given binary input type or null
*/
Short getBinaryInputState(DeviceBinarayInputEnum binaryInputType);
/**
* Sets the state of an existing {@link DeviceBinaryInput}. If the given {@link DeviceBinarayInputEnum} does not
* exist, it will returned false, otherwise true.
*
* @param binaryInputType of the {@link DeviceBinaryInput}
* @param newState the new state
* @return true, if it was successful, otherwise false
*/
boolean setBinaryInputState(DeviceBinarayInputEnum binaryInputType, Short newState);
/**
* Sets the given {@link List} of {@link DeviceBinaryInput}'s as supported binary inputs.
*
* @param newBinaryInputs to set
*/
void setBinaryInputs(List<DeviceBinaryInput> newBinaryInputs);
/**
* Returns true, if the given power sensor type as {@link SensorEnum} is up to date and does not need a refresh,
* otherwise it will returned false.
*
* @param powerSensorType of the sensor
* @return true, if the power sensor is up to date
*/
boolean isPowerSensorUpToDate(SensorEnum powerSensorType);
/**
* Returns a {@link List} of all supported sensor types as {@link SensorEnum}.
*
* @return all supported sensor types
*/
List<SensorEnum> getSensorTypes();
}

View File

@@ -0,0 +1,120 @@
/**
* 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.digitalstrom.internal.lib.structure.devices;
import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
/**
* The {@link GeneralDeviceInformations} interface contains all informations of digitalSTROM devices, which are
* identical for all device types. It also contains the methods to implement the mechanism of the
* {@link DeviceStatusListener}.
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public interface GeneralDeviceInformation {
/**
* Returns the user defined name of this device.
*
* @return name of this device
*/
String getName();
/**
* Sets the name of this device;
*
* @param name to set
*/
void setName(String name);
/**
* Returns the dSID of this device.
*
* @return {@link DSID} dSID
*/
DSID getDSID();
/**
* Returns the dSUID of this device.
*
* @return dSID
*/
String getDSUID();
/**
* This device is available in his zone or not.
* Every 24h the dSM (meter) checks, if the devices are
* plugged in
*
* @return true, if device is available otherwise false
*/
Boolean isPresent();
/**
* Sets this device is available in his zone or not.
*
* @param isPresent (true = available | false = not available)
*/
void setIsPresent(boolean isPresent);
/**
* Register a {@link DeviceStatusListener} to this {@link Device}.
*
* @param deviceStatuslistener to register
*/
void registerDeviceStatusListener(DeviceStatusListener deviceStatuslistener);
/**
* Unregister the {@link DeviceStatusListener} to this {@link Device} if it exists.
*
* @return the unregistered {@link DeviceStatusListener} or null if no one was registered
*/
DeviceStatusListener unregisterDeviceStatusListener();
/**
* Returns true, if a {@link DeviceStatusListener} is registered to this {@link Device}, otherwise false.
*
* @return return true, if a lister is registered, otherwise false
*/
boolean isListenerRegisterd();
/**
* Returns true, if this device is valid, otherwise false.
*
* @return true, if valid
*/
Boolean isValid();
/**
* Sets the valid state.
*
* @param isValid the new valid state
*/
void setIsValid(boolean isValid);
/**
* Returns the in the digitalSTROM web interface displayed dSID.
*
* @return displayed dSID
*/
String getDisplayID();
/**
* Returns the registered {@link DeviceStatusListener} or null, if no {@link DeviceStatusListener} is registered
*
* @return the registered {@link DeviceStatusListener} or null
*/
DeviceStatusListener getDeviceStatusListener();
}

View File

@@ -0,0 +1,71 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters;
import java.util.Date;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DSID;
/**
* The {@link CachedMeteringValue} saves the metering value of an digitalSTROM-Circuit.
*
* @author Alexander Betker - Initial contribution
* @author Michael Ochel - add methods getDateAsDate(), getMeteringType() and getMeteringUnit(); add missing java-doc
* @author Matthias Siegele - add methods getDateAsDate(), getMeteringType() and getMeteringUnit(); add missing java-doc
*/
public interface CachedMeteringValue {
/**
* Returns the {@link DSID} of the digitalSTROM-Circuit.
*
* @return dSID of circuit
*/
DSID getDsid();
/**
* Returns the saved sensor value.
*
* @return sensor value
*/
double getValue();
/**
* Returns the timestamp when the sensor value was read out as {@link String}.
*
* @return read out timestamp
*/
String getDate();
/**
* Returns the timestamp when the sensor value was read out as {@link Date}.
*
* @return read out timestamp
*/
Date getDateAsDate();
/**
* Returns the {@link MeteringTypeEnum} of this {@link CachedMeteringValue}.
*
* @return metering type as {@link MeteringTypeEnum}
*/
MeteringTypeEnum getMeteringType();
/**
* Returns the {@link MeteringUnitsEnum} of this {@link CachedMeteringValue}.
*
* @return metering unit as {@link MeteringUnitsEnum}
*/
MeteringUnitsEnum getMeteringUnit();
}

View File

@@ -0,0 +1,44 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters;
/**
* The {@link DeviceConfig} saves device configurations.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add missing java-doc
* @author Matthias Siegele - add missing java-doc
*/
public interface DeviceConfig {
/**
* Returns the digitalSTROM-Device parameter class.
*
* @return configuration class
*/
int getConfigurationClass();
/**
* Returns the digitalSTROM-Device configuration index.
*
* @return configuration index
*/
int getIndex();
/**
* Returns the digitalSTROM-Device configuration value.
*
* @return configuration value
*/
int getValue();
}

View File

@@ -0,0 +1,65 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters;
/**
* The {@link DeviceConstants} contains some constants for digitalSTROM devices.
*
* @author Alexander Betker - Initial contribution
* @author Michael Ochel - updated constants
* @author Matthias Siegele - updated constants
*/
public interface DeviceConstants {
/** digitalSTROM dim step for lights (this value is not in percent!) */
static final short DIM_STEP_LIGHT = 11;
/** move step for roller shutters (this value is not in percent!) */
static final short MOVE_STEP_ROLLERSHUTTER = 983;
/** move step for slats angle by blind/jalousie (this value is not in percent!) */
static final short ANGLE_STEP_SLAT = 11;
/** default move step (this value is not in percent!) */
static final short DEFAULT_MOVE_STEP = 11;
/** default max output value */
static final short DEFAULT_MAX_OUTPUTVALUE = 255;
/** max output value if device (lamp - yellow) is on */
static final short MAX_OUTPUT_VALUE_LIGHT = 255;
/** is open (special case: awning/marquee - closed) */
static final int MAX_ROLLERSHUTTER = 65535;
/** is closed (special case: awning/marquee - open) */
static final short MIN_ROLLERSHUTTER = 0;
/** max slat angle by blind/jalousie */
static final short MAX_SLAT_ANGLE = 255;
/** min slat angle by blind/jalousie */
static final short MIN_SLAT_ANGLE = 0;
/** you can't dim deeper than this value */
static final short MIN_DIM_VALUE = 16;
/** this is the index to get the output value (min-, max value) of almost all devices */
static final short DEVICE_SENSOR_OUTPUT = 0;
/** this is the index to get the output value (min-, max value) of shade devices */
static final short DEVICE_SENSOR_SLAT_POSITION_OUTPUT = 2;
/** this index is needed to get the angle of the slats (if device is a blind/jalousie) */
static final short DEVICE_SENSOR_SLAT_ANGLE_OUTPUT = 4;
}

View File

@@ -0,0 +1,88 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters;
import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.Scene;
/**
* The {@link DeviceSceneSpec} saves a digitalSTROM-Device scene mode.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add missing java-doc
* @author Matthias Siegele - add missing java-doc
*/
public interface DeviceSceneSpec {
/**
* Returns the sceneID.
*
* @return sceneID
*/
Scene getScene();
/**
* Returns true, if the don't care flag is set, otherwise false.
*
* @return true, if dont't care is set, otherwise false
*/
boolean isDontCare();
/**
* Sets the don't care flag.
*
* @param dontcare to set
*/
void setDontcare(boolean dontcare);
/**
* Returns true, if the local priority flag is set, otherwise false.
*
* @return true, if local priority is, set otherwise false
*/
boolean isLocalPrio();
/**
* Sets the local priority flag.
*
* @param localPrio to set
*/
void setLocalPrio(boolean localPrio);
/**
* Returns true, if the special mode flag is set, otherwise false.
*
* @return true, if special mode is set, otherwise false
*/
boolean isSpecialMode();
/**
* Sets the special mode flag.
*
* @param specialMode to set
*/
void setSpecialMode(boolean specialMode);
/**
* Returns true, if the flash mode flag is set, otherwise false.
*
* @return true, if flash mode is set, otherwise false
*/
boolean isFlashMode();
/**
* Sets the flash mode flag.
*
* @param flashMode to set
*/
void setFlashMode(boolean flashMode);
}

View File

@@ -0,0 +1,190 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
/**
* Represents a device state update for lights, joker, shades and sensor data.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*/
public interface DeviceStateUpdate {
// Update types
// in certain circumstances it is also better to rename SLAT_ANGLE to e.g. SECONDARY_OUTPUT
// light
static final String OUTPUT = "output";
static final String ON_OFF = "OnOff";
static final String OUTPUT_INCREASE = "outputIncrese";
static final String OUTPUT_DECREASE = "outputDecrese";
static final String OUTPUT_STOP = "outputStop";
static final String OUTPUT_MOVE = "outputMove";
// shades
static final String SLATPOSITION = "slatposition";
static final String SLAT_ANGLE = "slatAngle";
static final String SLAT_INCREASE = "slatIncrese";
static final String SLAT_DECREASE = "slatDecrese";
static final String SLAT_ANGLE_INCREASE = "slatAngleIncrese";
static final String SLAT_ANGLE_DECREASE = "slatAngleDecrese";
static final String OPEN_CLOSE = "openClose";
static final String OPEN_CLOSE_ANGLE = "openCloseAngle";
static final String SLAT_MOVE = "slatMove";
static final String SLAT_STOP = "slatStop";
// sensor data
static final String UPDATE_OUTPUT_VALUE = "outputValue";
static final String UPDATE_DEVICE_SENSOR = "deviceSensor-";
// metering data
static final String UPDATE_CIRCUIT_METER = "circuitMeter";
// binary inputs
static final String BINARY_INPUT = "binaryInput-";
// scene
/** A scene call can have the value between 0 and 127. */
static final String UPDATE_CALL_SCENE = "callScene";
static final String UPDATE_UNDO_SCENE = "undoScene";
static final String UPDATE_SCENE_OUTPUT = "sceneOutput";
static final String UPDATE_SCENE_CONFIG = "sceneConfig";
// general
/** command to refresh the output value of an device. */
static final String REFRESH_OUTPUT = "refreshOutput";
// standard values
static final int ON_VALUE = 1;
static final int OFF_VALUE = -1;
/**
* Returns the state update value.
* <p>
* <b>NOTE:</b>
* </p>
* <ul>
* <li>For all OnOff-types the value for off is lower than 0 and for on higher than 0.</li>
* <li>For all Increase- and Decrease-types the value is the new output value.</li>
* <li>For SceneCall-type the value is between 0 and 127.</li>
* <li>For all SceneUndo-types the value is the new output value.</li>
* <li>For all SensorUpdate-types will read the sensor data directly, if the value is 0, otherwise a
* {@link SensorJob} will be added to the {@link SensorJobExecutor}.</li>
* </ul>
*
* @return new state value
*/
Object getValue();
/**
* Returns the value as {@link Integer}.
*
* @return integer value
* @see #getValue()
*/
Integer getValueAsInteger();
/**
* Returns the value as {@link String}.
*
* @return string value
* @see #getValue()
*/
String getValueAsString();
/**
* Returns the value as {@link Short}.
*
* @return short value
* @see #getValue()
*/
Short getValueAsShort();
/**
* Returns the value as {@link Float}.
*
* @return float value
* @see #getValue()
*/
Float getValueAsFloat();
/**
* Returns the value as {@link Short}-array.
*
* @return short[] value
* @see #getValue()
*/
Short[] getValueAsShortArray();
/**
* Returns the state update type.
*
* @return state update type
*/
String getType();
/**
* Returns the update type as {@link SensorEnum} or null, if the type is not a {@link #UPDATE_DEVICE_SENSOR} type.
*
* @return type as {@link SensorEnum} or null
*/
SensorEnum getTypeAsSensorEnum();
/**
* Returns true, if this {@link DeviceStateUpdate} is a {@link #UPDATE_DEVICE_SENSOR} type, otherwise false.
*
* @return true, if it is a sensor type
*/
boolean isSensorUpdateType();
/**
* Returns the scene id of this {@link DeviceStateUpdate}, if this {@link DeviceStateUpdate} is a scene update type,
* otherwise it will be returned -1.
*
* @return the scene id or -1
*/
Short getSceneId();
/**
* Returns the scene configuration or output reading priority, if this {@link DeviceStateUpdate} is a
* {@link #UPDATE_SCENE_CONFIG} or {@link #UPDATE_SCENE_OUTPUT} type.
*
* @return scene reading priority
*/
Short getScenePriority();
/**
* Returns true, if this {@link DeviceStateUpdate} is a {@link #UPDATE_SCENE_CONFIG} or {@link #UPDATE_SCENE_OUTPUT}
* type, otherwise false.
*
* @return true, if it is a scene reading type
*/
boolean isSceneUpdateType();
/**
* Returns the update type as {@link DeviceBinarayInputEnum} or null, if the type is not a {@link #BINARY_INPUT}
* type.
*
* @return type as {@link DeviceBinarayInputEnum} or null
*/
DeviceBinarayInputEnum getTypeAsDeviceBinarayInputEnum();
/**
* Returns true, if this {@link DeviceStateUpdate} is a {@link #BINARY_INPUT} type, otherwise false.
*
* @return true, if it is a binary input type
*/
boolean isBinarayInputType();
}

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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
/**
* The {@link ChangeableDeviceConfigEnum} lists all changeable device configurations.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public enum ChangeableDeviceConfigEnum {
METER_DSID,
DEVICE_NAME,
ZONE_ID,
GROUPS,
FUNCTIONAL_GROUP,
OUTPUT_MODE,
BINARY_INPUTS
}

View File

@@ -0,0 +1,115 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
/**
* This enum contains all binary inputs with they id. <br>
*
* @author Michael Ochel - initial contributer
* @author Matthias Siegele - initial contributer
*/
public enum DeviceBinarayInputEnum {
/*
* Taken from http://developer.digitalstrom.org/Architecture/ds-basics.pdf#5f
*
* Input Type | Assigned Index | Natural Device and Description
* Presence | 1 | Presence detector
* Brightness | 2 | ---
* Presence in darkness | 3 | Presence detector with activated internal twilight sensor
* Twilight | 4 | Twilight sensor
* Motion | 5 | Motion detector
* Motion in darkness | 6 | Motion detect or with activated internal twilight sensor
* Smoke | 7 | Smoke Detector
* Wind strength above limit | 8 | Wind monitor with user-adjusted wind strength threshold
* Rain | 9 | Rain monitor
* Sun radiation | 10 | Sun light above threshold
* Temperature below limit | 11 | Room thermostat with used-adjusted temperature threshold
* Battery status is low | 12 | electric battery is running out of power
* Window is open | 13 | Window contact
* Door is open | 14 | Door contact
* Window is tilted | 15 | Window handle; window is tilted instead of fully opened
* Garage door is open | 16 | Garage door contact
* Sun protection | 17 | Protect against too much sun light
* Frost | 18 | Frost detector
* --dS-Basics Version: v1.3-branch August 19, 2015, Table 16: Binary input types--
*
* Heating operation on/off | 19 |
* Change-over heating/cooling | 20 |
* --dS-web-interface server-version: 1.21.1--
*
*
* Target Function | Assigned Index
* Joker | 8
* --dS-Basics Version: v1.3-branch August 19, 2015, Table 17: Binary input target functions--
*/
PRESENCE((short) 1),
BRIGHTNESS((short) 2),
PRESENCE_IN_DARKNESS((short) 3),
TWILIGHT((short) 4),
MOTION((short) 5),
MOTION_IN_DARKNESS((short) 6),
SMOKE((short) 7),
WIND_STRENGHT_ABOVE_LIMIT((short) 8),
RAIN((short) 9),
SUN_RADIATION((short) 10),
TEMPERATION_BELOW_LIMIT((short) 11),
BATTERY_STATUS_IS_LOW((short) 12),
WINDOW_IS_OPEN((short) 13),
DOOR_IS_OPEN((short) 14),
WINDOW_IS_TILTED((short) 15),
GARAGE_DOOR_IS_OPEN((short) 16),
SUN_PROTECTION((short) 17),
FROST((short) 18),
HEATING_OPERATION_ON_OFF((short) 19),
CHANGE_OVER_HEATING_COOLING((short) 20);
private final Short binaryInputType;
private static DeviceBinarayInputEnum[] deviceBinarayInputs = new DeviceBinarayInputEnum[DeviceBinarayInputEnum
.values().length];
static {
for (DeviceBinarayInputEnum deviceBinarayInput : DeviceBinarayInputEnum.values()) {
deviceBinarayInputs[deviceBinarayInput.binaryInputType - 1] = deviceBinarayInput;
}
}
private DeviceBinarayInputEnum(Short binaryInputType) {
this.binaryInputType = binaryInputType;
}
/**
* Returns the id of this {@link DeviceBinarayInputEnum}.
*
* @return id
*/
public Short getBinaryInputType() {
return binaryInputType;
}
/**
* Returns the {@link DeviceBinarayInputEnum} of the given id or null, if no {@link DeviceBinarayInputEnum} exist
* for the id.
*
* @param binaryInputTypeID of the {@link DeviceBinarayInputEnum}
* @return the {@link DeviceBinarayInputEnum} of the id
*/
public static DeviceBinarayInputEnum getdeviceBinarayInput(Short binaryInputTypeID) {
try {
return deviceBinarayInputs[binaryInputTypeID - 1];
} catch (IndexOutOfBoundsException e) {
return null;
}
}
}

View File

@@ -0,0 +1,71 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
/**
* The {@link DeviceParameterClassEnum} lists all digitalSTROM-device parameter classes.
*
* @author Alexander Betker - initial contributer
* @version digitalSTROM-API 1.14.5
*/
public enum DeviceParameterClassEnum {
/**
* communication specific parameters
*/
CLASS_0(0),
/**
* digitalSTROM device specific parameters
*/
CLASS_1(1),
/**
* function specific parameters
*/
CLASS_3(3),
/**
* sensor event table
*/
CLASS_6(6),
/**
* output status
*
* possible OffsetParameters:
* - READ_OUTPUT
*/
CLASS_64(64),
/**
* read scene table
* use index/offset 0-127
*/
CLASS_128(128);
private final int classIndex;
DeviceParameterClassEnum(int index) {
this.classIndex = index;
}
/**
* Returns the index of the {@link DeviceParameterClassEnum}.
*
* @return index
*/
public Integer getClassIndex() {
return this.classIndex;
}
}

View File

@@ -0,0 +1,115 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
import java.util.HashMap;
import java.util.Map;
/**
* The {@link FuncNameAndColorGroupEnum} contains all digitalSTROM functional group names and links to their
* {@link FunctionalColorGroupEnum}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
* @see <a href="http://developer.digitalstrom.org/Architecture/ds-basics.pdf">ds-basics.pdf
* "Table 1: digitalSTROM functional groups and their colors", page 9</a>
*/
public enum FuncNameAndColorGroupEnum {
/*
* | Number | Name | Color | Function |
* --------------------------------------------------------------------------------------
* | 1 | Lights | Yellow | Room lights |
* | 2 | Blinds | Gray | Blinds or shades outside |
* | 12 | Curtains | Gray | Curtains and blinds inside |
* | 3 | Heating | Blue | Heating |
* | 9 | Cooling | Blue | Cooling |
* | 10 | Ventilation | Blue | Ventilation |
* | 11 | Window | Blue | Window |
* | 48 | Temperature Control | Blue | Single room temperature control |
* | 4 | Audio | Cyan | Playing music or radio |
* | 5 | Video | Magenta | TV, Video |
* | 8 | Joker | Black | Configurable behaviour |
* | n/a | Single Device | White | Various, individual per device |
* | n/a | Security | Red | Security related functions, Alarms |
* | n/a | Access | Green | Access related functions, door bell |
*
*/
LIGHTS((short) 1, FunctionalColorGroupEnum.getColorGroup((short) 1)),
BLINDS((short) 2, FunctionalColorGroupEnum.getColorGroup((short) 2)),
CURTAINS((short) 12, FunctionalColorGroupEnum.getColorGroup((short) 12)),
HEATING((short) 3, FunctionalColorGroupEnum.getColorGroup((short) 3)),
COOLING((short) 9, FunctionalColorGroupEnum.getColorGroup((short) 9)),
VENTILATION((short) 10, FunctionalColorGroupEnum.getColorGroup((short) 10)),
WINDOW((short) 11, FunctionalColorGroupEnum.getColorGroup((short) 11)),
TEMPERATION_CONTROL((short) 48, FunctionalColorGroupEnum.getColorGroup((short) 48)),
AUDIO((short) 4, FunctionalColorGroupEnum.getColorGroup((short) 4)),
VIDEO((short) 5, FunctionalColorGroupEnum.getColorGroup((short) 5)),
JOKER((short) 8, FunctionalColorGroupEnum.getColorGroup((short) 8)),
SINGLE_DEVICE((short) -1, FunctionalColorGroupEnum.getColorGroup((short) -1)),
SECURITY((short) -2, FunctionalColorGroupEnum.getColorGroup((short) -2)),
ACCESS((short) -3, FunctionalColorGroupEnum.getColorGroup((short) -3));
private final short colorGroup;
private final FunctionalColorGroupEnum color;
static final Map<Short, FuncNameAndColorGroupEnum> COLOR_GROUPS = new HashMap<>();
static {
for (FuncNameAndColorGroupEnum colorGroup : FuncNameAndColorGroupEnum.values()) {
COLOR_GROUPS.put(colorGroup.getFunctionalColorGroup(), colorGroup);
}
}
/**
* Returns true, if contains the given output mode id in DigitalSTROM, otherwise false.
*
* @param functionalNameGroupID to be checked
* @return true, if contains
*/
public static boolean containsColorGroup(Short functionalNameGroupID) {
return COLOR_GROUPS.keySet().contains(functionalNameGroupID);
}
/**
* Returns the {@link FuncNameAndColorGroupEnum} of the given functional name group id.
*
* @param functionalNameGroupID of the {@link FuncNameAndColorGroupEnum}
* @return FunctionalNameAndColorGroupEnum
*/
public static FuncNameAndColorGroupEnum getMode(Short functionalNameGroupID) {
return COLOR_GROUPS.get(functionalNameGroupID);
}
private FuncNameAndColorGroupEnum(short functionalColorGroupID, FunctionalColorGroupEnum functionalColorGroup) {
this.colorGroup = functionalColorGroupID;
this.color = functionalColorGroup;
}
/**
* Returns the functional name group id form this Object.
*
* @return functional name group id
*/
public Short getFunctionalColorGroup() {
return colorGroup;
}
/**
* Returns the {@link FunctionalColorGroupEnum} form this Object.
*
* @return FunctionalColorGroupEnum
*/
public FunctionalColorGroupEnum getFunctionalColor() {
return color;
}
}

View File

@@ -0,0 +1,102 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The {@link FunctionalColorGroupEnum} contains all digitalSTROM functional color groups.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
* @see <a href="http://developer.digitalstrom.org/Architecture/ds-basics.pdf">ds-basics.pdf,
* "Table 1: digitalSTROM functional groups and their colors", page 9 [04.09.2015]</a>
*/
public enum FunctionalColorGroupEnum {
/*
* | Number | Name | Color | Function |
* --------------------------------------------------------------------------------------
* | 1 | Lights | Yellow | Room lights |
* | 2 | Blinds | Gray | Blinds or shades outside |
* | 12 | Curtains | Gray | Curtains and blinds inside |
* | 3 | Heating | Blue | Heating |
* | 9 | Cooling | Blue | Cooling |
* | 10 | Ventilation | Blue | Ventilation |
* | 11 | Window | Blue | Window |
* | 48 | Temperature Control | Blue | Single room temperature control |
* | 4 | Audio | Cyan | Playing music or radio |
* | 5 | Video | Magenta | TV, Video |
* | 8 | Joker | Black | Configurable behaviour |
* | n/a | Single Device | White | Various, individual per device |
* | n/a | Security | Red | Security related functions, Alarms |
* | n/a | Access | Green | Access related functions, door bell |
*
*/
YELLOW(Arrays.asList((short) 1)),
GREY(Arrays.asList((short) 2, (short) 12)),
BLUE(Arrays.asList((short) 3, (short) 9, (short) 10, (short) 11, (short) 48)),
CYAN(Arrays.asList((short) 4)),
MAGENTA(Arrays.asList((short) 5)),
BLACK(Arrays.asList((short) 8)),
WHITE(Arrays.asList((short) -1)),
RED(Arrays.asList((short) -2)),
GREEN(Arrays.asList((short) -3));
private final List<Short> colorGroup;
static final Map<Short, FunctionalColorGroupEnum> COLOR_GROUPS = new HashMap<>();
static {
for (FunctionalColorGroupEnum colorGroup : FunctionalColorGroupEnum.values()) {
for (Short colorGroupID : colorGroup.getFunctionalColorGroup()) {
COLOR_GROUPS.put(colorGroupID, colorGroup);
}
}
}
/**
* Returns true, if contains the given functional color group id in digitalSTROM exits, otherwise false.
*
* @param functionalColorGroupID to be checked
* @return true, if contains
*/
public static boolean containsColorGroup(Short functionalColorGroupID) {
return COLOR_GROUPS.keySet().contains(functionalColorGroupID);
}
/**
* Returns the {@link FunctionalColorGroupEnum} of the given color id.
*
* @param functionalColorGroupID of the {@link FunctionalColorGroupEnum}
* @return {@link FunctionalColorGroupEnum} of the id
*/
public static FunctionalColorGroupEnum getColorGroup(Short functionalColorGroupID) {
return COLOR_GROUPS.get(functionalColorGroupID);
}
private FunctionalColorGroupEnum(List<Short> functionalColorGroupID) {
this.colorGroup = functionalColorGroupID;
}
/**
* Returns the functional color group id's as {@link List} of this {@link FunctionalColorGroupEnum}.
*
* @return functional color group id's
*/
public List<Short> getFunctionalColorGroup() {
return colorGroup;
}
}

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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
import java.util.Arrays;
import java.util.List;
/**
* The {@link MeteringTypeEnum} lists all available digitalSTROM metering types.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - add MeteringUnitEnum list
* @author Matthias Siegele - add MeteringUnitEnum list
*/
public enum MeteringTypeEnum {
ENERGY(Arrays.asList(MeteringUnitsEnum.WH, MeteringUnitsEnum.WS)),
// currently null by request getLast
// energyDelta(Lists.newArrayList(MeteringUnitsEnum.Wh, MeteringUnitsEnum.Ws)),
CONSUMPTION(Arrays.asList(MeteringUnitsEnum.WH));
private final List<MeteringUnitsEnum> meteringUnits;
private MeteringTypeEnum(List<MeteringUnitsEnum> meteringUnits) {
this.meteringUnits = meteringUnits;
}
/**
* Returns the available units as {@link List} for this {@link MeteringTypeEnum}.
*
* @return units
*/
public List<MeteringUnitsEnum> getMeteringUnitList() {
return meteringUnits;
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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.digitalstrom.internal.lib.structure.devices.deviceparameters.constants;
/**
* The {@link MeteringUnitsEnum} lists all available digitalSTROM metering units.
*
* @author Alexander Betker - initial contributer
* @author Michael Ochel - remove W, because it does not exist any more
* @author Matthias Siegele - remove W, because it does not exist any more
*/
public enum MeteringUnitsEnum {
WH("Wh"),
WS("Ws");
public final String unit;
private MeteringUnitsEnum(String unit) {
this.unit = unit;
}
}

Some files were not shown because too many files have changed in this diff Show More