Skip to content

Commit

Permalink
Homematic: Optimized parameters and initialization (openhab#1858)
Browse files Browse the repository at this point in the history
* Optimized parameters and initialization

Signed-off-by: Gerhard Riegler <[email protected]>
  • Loading branch information
gerrieg authored and fharni committed Feb 19, 2017
1 parent 5075b7a commit fdc29be
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2010-2017 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.homematic.converter;

/**
* Exception if converting between two types is not possible due wrong item type or command.
*
* @author Gerhard Riegler - Initial contribution
*/
public class ConverterTypeException extends ConverterException {
private static final long serialVersionUID = 7114173349077221055L;

public ConverterTypeException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.smarthome.core.types.Type;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.converter.ConverterTypeException;
import org.openhab.binding.homematic.converter.StateInvertInfo;
import org.openhab.binding.homematic.converter.TypeConverter;
import org.openhab.binding.homematic.internal.model.HmDatapoint;
Expand Down Expand Up @@ -90,11 +91,11 @@ public Object convertToBinding(Type type, HmDatapoint dp) throws ConverterExcept
} else if (type.getClass().isEnum() && !(this instanceof OnOffTypeConverter)
&& !(this instanceof OpenClosedTypeConverter)) {
return commandToBinding((Command) type, dp);
} else if (!toBindingValidation(dp)) {
} else if (!toBindingValidation(dp, type.getClass())) {
String errorMessage = String.format("Can't convert type %s with value '%s' to %s value with %s for '%s'",
type.getClass().getSimpleName(), type.toString(), dp.getType(), this.getClass().getSimpleName(),
new HmDatapointInfo(dp));
throw new ConverterException(errorMessage);
throw new ConverterTypeException(errorMessage);
}

return toBinding((T) type, dp);
Expand All @@ -116,7 +117,7 @@ public T convertFromBinding(HmDatapoint dp) throws ConverterException {
} else if (!fromBindingValidation(dp)) {
String errorMessage = String.format("Can't convert %s value '%s' with %s for '%s'", dp.getType(),
dp.getValue(), this.getClass().getSimpleName(), new HmDatapointInfo(dp));
throw new ConverterException(errorMessage);
throw new ConverterTypeException(errorMessage);
}

return fromBinding(dp);
Expand All @@ -133,7 +134,7 @@ protected Object commandToBinding(Command command, HmDatapoint dp) throws Conver
/**
* Returns true, if the conversion from openHab to the binding is possible.
*/
protected abstract boolean toBindingValidation(HmDatapoint dp);
protected abstract boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass);

/**
* Converts the type to a datapoint value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.math.BigDecimal;

import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.types.Type;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.internal.model.HmDatapoint;

Expand All @@ -25,8 +26,8 @@ public class DecimalTypeConverter extends AbstractTypeConverter<DecimalType> {
* {@inheritDoc}
*/
@Override
protected boolean toBindingValidation(HmDatapoint dp) {
return dp.isNumberType();
protected boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass) {
return dp.isNumberType() && typeClass.isAssignableFrom(DecimalType.class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.openhab.binding.homematic.internal.misc.HomematicConstants.DATAPOINT_NAME_SENSOR;

import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.types.Type;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.internal.model.HmDatapoint;

Expand All @@ -25,8 +26,8 @@ public class OnOffTypeConverter extends AbstractTypeConverter<OnOffType> {
* {@inheritDoc}
*/
@Override
protected boolean toBindingValidation(HmDatapoint dp) {
return dp.isBooleanType();
protected boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass) {
return dp.isBooleanType() && typeClass.isAssignableFrom(OnOffType.class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.openhab.binding.homematic.internal.misc.HomematicConstants.DATAPOINT_NAME_SENSOR;

import org.eclipse.smarthome.core.library.types.OpenClosedType;
import org.eclipse.smarthome.core.types.Type;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.internal.model.HmDatapoint;

Expand All @@ -25,8 +26,8 @@ public class OpenClosedTypeConverter extends AbstractTypeConverter<OpenClosedTyp
* {@inheritDoc}
*/
@Override
protected boolean toBindingValidation(HmDatapoint dp) {
return dp.isBooleanType();
protected boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass) {
return dp.isBooleanType() && typeClass.isAssignableFrom(OpenClosedType.class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.library.types.UpDownType;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.Type;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.internal.model.HmDatapoint;
import org.slf4j.Logger;
Expand Down Expand Up @@ -60,9 +61,9 @@ protected Object commandToBinding(Command command, HmDatapoint dp) throws Conver
* {@inheritDoc}
*/
@Override
protected boolean toBindingValidation(HmDatapoint dp) {
protected boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass) {
return dp.isNumberType() && dp.getMaxValue() != null && dp.getMinValue() != null
&& dp.getChannel().getType() != null;
&& dp.getChannel().getType() != null && typeClass.isAssignableFrom(PercentType.class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.openhab.binding.homematic.converter.type;

import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.types.Type;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.internal.model.HmDatapoint;
import org.openhab.binding.homematic.internal.model.HmDatapointInfo;
Expand All @@ -24,8 +25,8 @@ public class StringTypeConverter extends AbstractTypeConverter<StringType> {
* {@inheritDoc}
*/
@Override
protected boolean toBindingValidation(HmDatapoint dp) {
return dp.isStringType() || dp.isEnumType();
protected boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass) {
return (dp.isStringType() || dp.isEnumType()) && typeClass.isAssignableFrom(StringType.class);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,18 @@ public HomematicBridgeHandler(Bridge bridge, HomematicTypeGenerator typeGenerato
*/
@Override
public void initialize() {
try {
String id = getThing().getUID().getId();
config = createHomematicConfig();
config = createHomematicConfig();
registerDeviceDiscoveryService();
final HomematicBridgeHandler instance = this;
scheduler.execute(new Runnable() {

gateway = HomematicGatewayFactory.createGateway(id, config, this);
gateway.initialize();

registerDeviceDiscoveryService();
scheduler.submit(new Runnable() {
@Override
public void run() {
try {
String id = getThing().getUID().getId();
gateway = HomematicGatewayFactory.createGateway(id, config, instance);
gateway.initialize();

@Override
public void run() {
discoveryService.startScan(null);
discoveryService.waitForScanFinishing();
updateStatus(ThingStatus.ONLINE);
Expand All @@ -83,16 +83,18 @@ public void run() {
gateway.loadRssiValues();
} catch (IOException ex) {
logger.warn("Unable to load RSSI values from bridge '{}'", getThing().getUID().getId());
logger.error(ex.getMessage(), ex);
}
}

} catch (IOException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
dispose();
scheduleReinitialize();
}
});
}
});

} catch (IOException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
dispose();
scheduleReinitialize();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.eclipse.smarthome.core.types.State;
import org.openhab.binding.homematic.converter.ConverterException;
import org.openhab.binding.homematic.converter.ConverterFactory;
import org.openhab.binding.homematic.converter.ConverterTypeException;
import org.openhab.binding.homematic.converter.TypeConverter;
import org.openhab.binding.homematic.internal.communicator.HomematicGateway;
import org.openhab.binding.homematic.internal.misc.HomematicClientException;
Expand Down Expand Up @@ -66,49 +67,56 @@ public HomematicThingHandler(Thing thing) {
*/
@Override
public void initialize() {
try {
HomematicGateway gateway = getHomematicGateway();
HmDevice device = gateway.getDevice(UidUtils.getHomematicAddress(getThing()));
updateStatus(device);
if (!device.isOffline()) {
logger.debug("Initializing {} channels of thing '{}' from gateway '{}'",
getThing().getChannels().size(), getThing().getUID(), gateway.getId());

// update channel states
for (Channel channel : getThing().getChannels()) {
updateChannelState(channel.getUID());
}
scheduler.execute(new Runnable() {

// update properties
Map<String, String> properties = editProperties();
setProperty(properties, device, PROPERTY_BATTERY_TYPE, VIRTUAL_DATAPOINT_NAME_BATTERY_TYPE);
setProperty(properties, device, Thing.PROPERTY_FIRMWARE_VERSION, VIRTUAL_DATAPOINT_NAME_FIRMWARE);
setProperty(properties, device, Thing.PROPERTY_SERIAL_NUMBER, device.getAddress());
setProperty(properties, device, PROPERTY_AES_KEY, DATAPOINT_NAME_AES_KEY);
updateProperties(properties);
@Override
public void run() {
try {
HomematicGateway gateway = getHomematicGateway();
HmDevice device = gateway.getDevice(UidUtils.getHomematicAddress(getThing()));
updateStatus(device);
if (!device.isOffline()) {
logger.debug("Initializing {} channels of thing '{}' from gateway '{}'",
getThing().getChannels().size(), getThing().getUID(), gateway.getId());

// update channel states
for (Channel channel : getThing().getChannels()) {
updateChannelState(channel.getUID());
}

// update configurations
Configuration config = editConfiguration();
for (HmChannel channel : device.getChannels()) {
for (HmDatapoint dp : channel.getDatapoints().values()) {
if (dp.getParamsetType() == HmParamsetType.MASTER) {
loadHomematicChannelValues(dp.getChannel());
config.put(MetadataUtils.getParameterName(dp),
dp.isEnumType() ? dp.getOptionValue() : dp.getValue());
// update properties
Map<String, String> properties = editProperties();
setProperty(properties, device, PROPERTY_BATTERY_TYPE, VIRTUAL_DATAPOINT_NAME_BATTERY_TYPE);
setProperty(properties, device, Thing.PROPERTY_FIRMWARE_VERSION,
VIRTUAL_DATAPOINT_NAME_FIRMWARE);
setProperty(properties, device, Thing.PROPERTY_SERIAL_NUMBER, device.getAddress());
setProperty(properties, device, PROPERTY_AES_KEY, DATAPOINT_NAME_AES_KEY);
updateProperties(properties);

// update configurations
Configuration config = editConfiguration();
for (HmChannel channel : device.getChannels()) {
for (HmDatapoint dp : channel.getDatapoints().values()) {
if (dp.getParamsetType() == HmParamsetType.MASTER) {
loadHomematicChannelValues(dp.getChannel());
config.put(MetadataUtils.getParameterName(dp),
dp.isEnumType() ? dp.getOptionValue() : dp.getValue());
}
}
}
updateConfiguration(config);
}
} catch (HomematicClientException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
} catch (IOException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
} catch (BridgeHandlerNotAvailableException ex) {
// ignore
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
updateConfiguration(config);
}
} catch (HomematicClientException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getMessage());
} catch (IOException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
} catch (BridgeHandlerNotAvailableException ex) {
// ignore
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
});
}

/**
Expand Down Expand Up @@ -186,6 +194,8 @@ public void handleCommand(ChannelUID channelUID, Command command) {
} else {
logger.error(ex.getMessage(), ex);
}
} catch (ConverterTypeException ex) {
logger.warn("{}, please check the item type and the commands in your scripts", ex.getMessage());
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
Expand Down Expand Up @@ -345,10 +355,10 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter
throws ConfigValidationException {
validateConfigurationParameters(configurationParameters);

Configuration newConfig = editConfiguration();
newConfig.setProperties(configurationParameters);

try {
HomematicGateway gateway = getHomematicGateway();
HmDevice device = gateway.getDevice(UidUtils.getHomematicAddress(getThing()));

for (Entry<String, Object> configurationParmeter : configurationParameters.entrySet()) {
String key = configurationParmeter.getKey();
Object newValue = configurationParmeter.getValue();
Expand All @@ -358,8 +368,6 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter
Integer channelNumber = NumberUtils.toInt(StringUtils.substringBefore(key, "_"));
String dpName = StringUtils.substringAfter(key, "_");

HomematicGateway gateway = getHomematicGateway();
HmDevice device = gateway.getDevice(UidUtils.getHomematicAddress(getThing()));
HmDatapointInfo dpInfo = new HmDatapointInfo(device.getAddress(), HmParamsetType.MASTER,
channelNumber, dpName);
HmDatapoint dp = device.getChannel(channelNumber).getDatapoint(dpInfo);
Expand All @@ -381,15 +389,13 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter
}
} catch (IOException ex) {
logger.error("Error setting thing property {}: {}", dpInfo, ex.getMessage());
newConfig.put(key, getConfig().get(key));
}
} else {
logger.error("Can't find datapoint for thing property {}", dpInfo);
newConfig.put(key, getConfig().get(key));
}
}
}
updateConfiguration(newConfig);
gateway.triggerDeviceValuesReload(device);
} catch (HomematicClientException | BridgeHandlerNotAvailableException ex) {
logger.error("Error setting thing properties: " + ex.getMessage(), ex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.openhab.binding.homematic.internal.communicator.virtual.ReloadFromGatewayVirtualDatapointHandler;
import org.openhab.binding.homematic.internal.communicator.virtual.ReloadRssiVirtualDatapointHandler;
import org.openhab.binding.homematic.internal.communicator.virtual.RssiVirtualDatapointHandler;
import org.openhab.binding.homematic.internal.communicator.virtual.SignalStrengthVirtualDatapointHandler;
import org.openhab.binding.homematic.internal.communicator.virtual.StateContactVirtualDatapointHandler;
import org.openhab.binding.homematic.internal.communicator.virtual.VirtualDatapointHandler;
import org.openhab.binding.homematic.internal.communicator.virtual.VirtualGateway;
Expand Down Expand Up @@ -112,6 +113,7 @@ public abstract class AbstractHomematicGateway implements RpcEventListener, Home
virtualDatapointHandlers.add(new RssiVirtualDatapointHandler());
virtualDatapointHandlers.add(new ReloadRssiVirtualDatapointHandler());
virtualDatapointHandlers.add(new StateContactVirtualDatapointHandler());
virtualDatapointHandlers.add(new SignalStrengthVirtualDatapointHandler());
}

public AbstractHomematicGateway(String id, HomematicConfig config, HomematicGatewayListener eventListener) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ public Void parse(Object[] message) throws IOException {
adjustRssiValue(dp);
} else {
// should never happen, but in case ...
logger.warn("Can't set value for datapoint '{}'", dpInfo);

// suppress warning for this datapoint due wrong CCU metadata
boolean isHmSenMdirNextTrans = channel.getDevice().getType().startsWith("HM-Sen-MDIR-O")
&& dpInfo.getName().equals("NEXT_TRANSMISSION");
if (!isHmSenMdirNextTrans) {
logger.warn("Can't set value for datapoint '{}'", dpInfo);
}
}
}
return null;
Expand Down
Loading

0 comments on commit fdc29be

Please sign in to comment.