Skip to content

Commit

Permalink
[knx] Code rework (#17420)
Browse files Browse the repository at this point in the history
* [knx] Code rework

Signed-off-by: Holger Friedrich <[email protected]>
  • Loading branch information
holgerfriedrich authored Sep 15, 2024
1 parent 3930bff commit 2d403dc
Show file tree
Hide file tree
Showing 24 changed files with 125 additions and 239 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public final List<GroupAddress> getWriteAddresses() {
return new WriteSpecImpl(entry.getValue(), dpt, command);
}
}
// if we didn't find a match, check if we find a sub-type match
// if we didn't find a match, check if we find a subtype match
for (Map.Entry<String, GroupAddressConfiguration> entry : groupAddressConfigurations.entrySet()) {
String dpt = Objects.requireNonNullElse(entry.getValue().getDPT(), getDefaultDPT(entry.getKey()));
Set<Class<? extends Type>> expectedTypeClasses = DPTUtil.getAllowedTypes(dpt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static KNXChannel createKnxChannel(Channel channel) throws IllegalArgumen
.map(Map.Entry::getValue).findFirst()
.orElseThrow(() -> new IllegalArgumentException(channelTypeUID + " is not a valid channel type ID"));

// typecast to avoid warning about unsafe return type; we know that the lookup returns non null values
// typecast to avoid warning about unsafe return type; we know that the lookup returns non-null values
return (KNXChannel) supplier.apply(channel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,12 @@ class TypeColor extends KNXChannel {

@Override
protected String getDefaultDPT(String gaConfigKey) {
if (gaConfigKey.equals(HSB_GA)) {
return DPTXlatorRGB.DPT_RGB.getID();
}
if (gaConfigKey.equals(INCREASE_DECREASE_GA)) {
return DPTXlator3BitControlled.DPT_CONTROL_DIMMING.getID();
}
if (gaConfigKey.equals(SWITCH_GA)) {
return DPTXlatorBoolean.DPT_SWITCH.getID();
}
if (gaConfigKey.equals(POSITION_GA)) {
return DPTXlator8BitUnsigned.DPT_SCALING.getID();
}
throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported");
return switch (gaConfigKey) {
case HSB_GA -> DPTXlatorRGB.DPT_RGB.getID();
case INCREASE_DECREASE_GA -> DPTXlator3BitControlled.DPT_CONTROL_DIMMING.getID();
case SWITCH_GA -> DPTXlatorBoolean.DPT_SWITCH.getID();
case POSITION_GA -> DPTXlator8BitUnsigned.DPT_SCALING.getID();
default -> throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported");
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import static org.openhab.binding.knx.internal.KNXBindingConstants.*;

import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand Down Expand Up @@ -45,15 +44,11 @@ class TypeDimmer extends KNXChannel {

@Override
protected String getDefaultDPT(String gaConfigKey) {
if (Objects.equals(gaConfigKey, INCREASE_DECREASE_GA)) {
return DPTXlator3BitControlled.DPT_CONTROL_DIMMING.getID();
}
if (Objects.equals(gaConfigKey, SWITCH_GA)) {
return DPTXlatorBoolean.DPT_SWITCH.getID();
}
if (Objects.equals(gaConfigKey, POSITION_GA)) {
return DPTXlator8BitUnsigned.DPT_SCALING.getID();
}
throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported");
return switch (gaConfigKey) {
case INCREASE_DECREASE_GA -> DPTXlator3BitControlled.DPT_CONTROL_DIMMING.getID();
case SWITCH_GA -> DPTXlatorBoolean.DPT_SWITCH.getID();
case POSITION_GA -> DPTXlator8BitUnsigned.DPT_SCALING.getID();
default -> throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported");
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import static org.openhab.binding.knx.internal.KNXBindingConstants.*;

import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand Down Expand Up @@ -45,15 +44,11 @@ class TypeRollershutter extends KNXChannel {

@Override
protected String getDefaultDPT(String gaConfigKey) {
if (Objects.equals(gaConfigKey, UP_DOWN_GA)) {
return DPTXlatorBoolean.DPT_UPDOWN.getID();
}
if (Objects.equals(gaConfigKey, STOP_MOVE_GA)) {
return DPTXlatorBoolean.DPT_START.getID();
}
if (Objects.equals(gaConfigKey, POSITION_GA)) {
return DPTXlator8BitUnsigned.DPT_SCALING.getID();
}
throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported");
return switch (gaConfigKey) {
case UP_DOWN_GA -> DPTXlatorBoolean.DPT_UPDOWN.getID();
case STOP_MOVE_GA -> DPTXlatorBoolean.DPT_START.getID();
case POSITION_GA -> DPTXlator8BitUnsigned.DPT_SCALING.getID();
default -> throw new IllegalArgumentException("GA configuration '" + gaConfigKey + "' is not supported");
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ private synchronized boolean connect() {
// Protected ctor using given ManagementClientImpl is available (custom class to be inherited)
managementProcedures = new CustomManagementProceduresImpl(managementClient, tl);

// OH helper for reading device info, based on managementClient above
// OpenHab helper for reading device info, based on managementClient above
deviceInfoClient = new DeviceInfoClientImpl(managementClient);

// ProcessCommunicator provides main KNX communication (Calimero).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,7 @@ public class DeviceInspector {
private final DeviceInfoClient client;
private final IndividualAddress address;

public static class Result {
private final Map<String, String> properties;
private final Set<GroupAddress> groupAddresses;

public Result(Map<String, String> properties, Set<GroupAddress> groupAddresses) {
super();
this.properties = properties;
this.groupAddresses = groupAddresses;
}

public Map<String, String> getProperties() {
return properties;
}

public Set<GroupAddress> getGroupAddresses() {
return groupAddresses;
}
public record Result(Map<String, String> properties, Set<GroupAddress> groupAddresses) {
}

public DeviceInspector(DeviceInfoClient client, IndividualAddress address) {
Expand Down Expand Up @@ -114,7 +98,7 @@ public Result readDeviceInfo() {
* task immediately on connection loss or thing deconstruction.
*
* @param address Individual address of KNX device
* @return List of device properties
* @return Map of device properties
* @throws InterruptedException
*/
private Map<String, String> readDeviceProperties(IndividualAddress address) throws InterruptedException {
Expand Down Expand Up @@ -179,7 +163,7 @@ private Map<String, String> readDeviceProperties(IndividualAddress address) thro
if (!maxApdu.isEmpty()) {
logger.trace("Max APDU of device {} is {} bytes (routing)", address, maxApdu);
} else {
// fallback: MAX_APDU_LENGTH; if availble set the default is 14 according to spec
// fallback: MAX_APDU_LENGTH; if available set the default is 14 according to spec
Thread.sleep(OPERATION_INTERVAL);
try {
byte[] result = getClient().readDeviceProperties(address, ADDRESS_TABLE_OBJECT,
Expand Down Expand Up @@ -247,7 +231,7 @@ private Map<String, String> readDeviceProperties(IndividualAddress address) thro
logger.debug("Identified device {} as \"{}\"", address, result);
ret.put(FRIENDLY_NAME, result);
} else {
// this is due to devices which have a buggy implememtation (and show a broken string also
// this is due to devices which have a buggy implementation (and show a broken string also
// in ETS tool)
logger.debug("Ignoring FRIENDLY_NAME of device {} as it contains non-printable characters",
address);
Expand Down Expand Up @@ -288,7 +272,7 @@ private Map<String, String> readDeviceProperties(IndividualAddress address) thro
* Currently only data from DD0 is returned; DD2 is just logged in debug mode.
*
* @param address Individual address of KNX device
* @return List of device properties
* @return Map of device properties
* @throws InterruptedException
*/
private Map<String, String> readDeviceDescription(IndividualAddress address) throws InterruptedException {
Expand All @@ -315,7 +299,7 @@ private Map<String, String> readDeviceDescription(IndividualAddress address) thr
if (data != null) {
try {
final DD2 dd = DeviceDescriptor.DD2.from(data);
logger.debug("The device with address {} is has DD2 {}", address, dd.toString());
logger.debug("The device with address {} is has DD2 {}", address, dd);
} catch (KNXIllegalArgumentException e) {
logger.warn("Can not parse device descriptor 2 of device with address {}: {}", address,
e.getMessage());
Expand All @@ -342,21 +326,14 @@ private int toUnsigned(final byte @Nullable [] data) {
}

private static String getMediumType(int type) {
switch (type) {
case 0:
return "TP";
case 1:
return "PL";
case 2:
return "RF";
case 3:
return "TP0 (deprecated)";
case 4:
return "PL123 (deprecated)";
case 5:
return "IP";
default:
return "unknown (" + type + ")";
}
return switch (type) {
case 0 -> "TP";
case 1 -> "PL";
case 2 -> "RF";
case 3 -> "TP0 (deprecated)";
case 4 -> "PL123 (deprecated)";
case 5 -> "IP";
default -> "unknown (" + type + ")";
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public interface InboundSpec {
/**
* Get the affected group addresses.
*
* @return a list of group addresses.
* @return a Set of group addresses.
*/
Set<GroupAddress> getGroupAddresses();
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public SerialClient(int autoReconnectPeriod, ThingUID thingUID, int responseTime
/**
* try automatic detection of cEMI devices via the PEI identification frame
*
* @implNote This is based on an vendor specific extension and may not work for other devices.
* @implNote This is based on a vendor specific extension and may not work for other devices.
*/
protected boolean detectCemi() throws InterruptedException {
final byte[] peiIdentifyReqFrame = { (byte) 0xa7 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* {@literal @}ServiceProvider annotation (biz.aQute.bnd.annotation) automatically creates the file
* /META-INF/services/tuwien.auto.calimero.serial.spi.SerialCom
* to register SerialTransportAdapter to the service loader.
* Additional attributes for SerialTansportAdapter can be specified as well, e.g.
* Additional attributes for SerialTransportAdapter can be specified as well, e.g.
* attribute = { "position=1" }
* and will be part of MANIFEST.MF
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void execute(String[] args, Console console) {
if (args.length == 1 && CMD_LIST_UNKNOWN_GA.equalsIgnoreCase(args[0])) {
for (KNXBridgeBaseThingHandler bridgeHandler : knxHandlerFactory.getBridges()) {
console.println("KNX bridge \"" + bridgeHandler.getThing().getLabel()
+ "\": group address, type, number of bytes, and number of occurence since last reload of binding:");
+ "\": group address, type, number of bytes, and number of occurrence since last reload of binding:");
for (Entry<String, Long> entry : bridgeHandler.getCommandExtensionData().unknownGA().entrySet()) {
console.println(entry.getKey() + " " + entry.getValue());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static Stream<Map.Entry<String, String>> getAllUnitStrings() {
DPT_UNIT_MAP.put(DPTXlator4ByteFloat.DPT_ELECTROMAGNETIC_MOMENT.getID(),
Units.AMPERE.multiply(SIUnits.SQUARE_METRE).toString());

// 64 bit signed (DPT 29)
// 64-bit signed (DPT 29)
DPT_UNIT_MAP.put(DPTXlator64BitSigned.DPT_REACTIVE_ENERGY.getID(), Units.VAR_HOUR.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
public class DPTUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(DPTUtil.class);

// DPT: "123.001", 1-3 digits main type (no leading zero), optional sub-type 3-4 digits (leading zeros allowed)
// DPT: "123.001", 1-3 digits main type (no leading zero), optional subtype 3-4 digits (leading zeros allowed)
public static final Pattern DPT_PATTERN = Pattern.compile("^(?<main>[1-9][0-9]{0,2})(?:\\.(?<sub>\\d{3,5}))?$");

// used to map vendor-specific data to standard DPT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,32 +241,34 @@ private static boolean check23561001(byte[] data) throws KNXException {

private static Type handleDpt1(String subType, DPTXlator translator, Class<? extends Type> preferredType) {
DPTXlatorBoolean translatorBoolean = (DPTXlatorBoolean) translator;
switch (subType) {
case "008":
return translatorBoolean.getValueBoolean() ? UpDownType.DOWN : UpDownType.UP;
case "009":
case "019":
return switch (subType) {
case "008" -> translatorBoolean.getValueBoolean() ? UpDownType.DOWN : UpDownType.UP;
case "009", "019" -> {
// default is OpenClosedType (Contact), but it may be mapped to OnOffType as well
if (OnOffType.class.equals(preferredType)) {
return OnOffType.from(translatorBoolean.getValueBoolean());
yield OnOffType.from(translatorBoolean.getValueBoolean());
}

// This is wrong for DPT 1.009. It should be true -> CLOSE, false -> OPEN, but unfortunately
// can't be fixed without breaking a lot of working installations.
// The documentation has been updated to reflect that. / @J-N-K
return translatorBoolean.getValueBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
case "010":
return translatorBoolean.getValueBoolean() ? StopMoveType.MOVE : StopMoveType.STOP;
case "022":
return DecimalType.valueOf(translatorBoolean.getValueBoolean() ? "1" : "0");
default:
yield translatorBoolean.getValueBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;

// This is wrong for DPT 1.009. It should be true -> CLOSE, false -> OPEN, but unfortunately
// can't be fixed without breaking a lot of working installations.
// The documentation has been updated to reflect that. / @J-N-K
}
case "010" -> translatorBoolean.getValueBoolean() ? StopMoveType.MOVE : StopMoveType.STOP;
case "022" -> DecimalType.valueOf(translatorBoolean.getValueBoolean() ? "1" : "0");
default -> {
// default is OnOffType (Switch), but it may be mapped to OpenClosedType as well
if (OpenClosedType.class.equals(preferredType)) {
return translatorBoolean.getValueBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
yield translatorBoolean.getValueBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
}

return OnOffType.from(translatorBoolean.getValueBoolean());
}
yield OnOffType.from(translatorBoolean.getValueBoolean());
}
};
}

private static @Nullable Type handleDpt3(String subType, DPTXlator translator) {
Expand All @@ -275,17 +277,16 @@ private static Type handleDpt1(String subType, DPTXlator translator, Class<? ext
LOGGER.debug("convertRawDataToType: KNX DPT_Control_Dimming: break received.");
return UnDefType.NULL;
}
switch (subType) {
case "007":
return translator3BitControlled.getControlBit() ? IncreaseDecreaseType.INCREASE
: IncreaseDecreaseType.DECREASE;
case "008":
return translator3BitControlled.getControlBit() ? UpDownType.DOWN : UpDownType.UP;
default:
return switch (subType) {
case "007" -> translator3BitControlled.getControlBit() ? IncreaseDecreaseType.INCREASE
: IncreaseDecreaseType.DECREASE;
case "008" -> translator3BitControlled.getControlBit() ? UpDownType.DOWN : UpDownType.UP;
default -> {
// should never happen unless Calimero introduces new subtypes
LOGGER.warn("DPT3, subtype '{}' is unknown. Please open an issue.", subType);
return null;
}
yield null;
}
};
}

private static Type handleDpt10(String value) throws ParseException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,14 @@ private static String handleNumericTypes(String dptId, String mainNumber, DPT dp
if (DPTXlator2ByteFloat.DPT_TEMPERATURE_DIFFERENCE.getID().equals(dptId)
|| DPTXlator2ByteFloat.DPT_TEMPERATURE_GRADIENT.getID().equals(dptId)
|| DPTXlator2ByteFloat.DPT_KELVIN_PER_PERCENT.getID().equals(dptId)) {
// match unicode character or °C
// match Unicode character or °C
if (value.toString().contains(SIUnits.CELSIUS.getSymbol()) || value.toString().contains("°C")) {
if (unit != null) {
unit = unit.replace("K", "°C");
}
} else if (value.toString().contains("°F")) {
// an new approach to handle temperature differences was introduced to core
// after 4.0, stripping the unit and and creating a new QuantityType works
// A new approach to handle temperature differences was introduced to core
// after 4.0, stripping the unit and creating a new QuantityType works
// both with core release 4.0 and current snapshot
boolean perPercent = value.toString().contains("/%");
value = new QuantityType<>(((QuantityType<?>) value).doubleValue() * 5.0 / 9.0, Units.KELVIN);
Expand Down Expand Up @@ -248,16 +248,12 @@ private static String handleNumericTypes(String dptId, String mainNumber, DPT dp
return bigDecimal.stripTrailingZeros().toPlainString();
case "2":
DPT valueDPT = ((DPTXlator1BitControlled.DPT1BitControlled) dpt).getValueDPT();
switch (bigDecimal.intValue()) {
case 0:
return "0 " + valueDPT.getLowerValue();
case 1:
return "0 " + valueDPT.getUpperValue();
case 2:
return "1 " + valueDPT.getLowerValue();
default:
return "1 " + valueDPT.getUpperValue();
}
return switch (bigDecimal.intValue()) {
case 0 -> "0 " + valueDPT.getLowerValue();
case 1 -> "0 " + valueDPT.getUpperValue();
case 2 -> "1 " + valueDPT.getLowerValue();
default -> "1 " + valueDPT.getUpperValue();
};
case "18":
int intVal = bigDecimal.intValue();
if (intVal > 63) {
Expand All @@ -281,7 +277,7 @@ private static String handleNumericTypes(String dptId, String mainNumber, DPT dp
/**
* convert 0...100% to 1 byte 0..255
*
* @param percent
* @param percent percentage 0..1
* @return int 0..255
*/
private static int convertPercentToByte(PercentType percent) {
Expand Down
Loading

0 comments on commit 2d403dc

Please sign in to comment.