From 3a2c996aabd4bf3ddae17d9fbd3f3a2bdbaaffb3 Mon Sep 17 00:00:00 2001 From: Fabian Wolter Date: Mon, 1 Feb 2021 12:09:09 +0100 Subject: [PATCH] [lcn] Fix several bugs in measurement processing with firmware before 2013 (#9991) Signed-off-by: Fabian Wolter --- .../lcn/internal/LcnBindingConstants.java | 4 + .../lcn/internal/LcnModuleHandler.java | 40 +++++-- .../lcn/internal/connection/Connection.java | 9 +- .../ConnectionStateSegmentScan.java | 2 +- .../lcn/internal/connection/ModInfo.java | 105 +++++++++++------- .../internal/connection/RequestStatus.java | 11 +- .../AbstractLcnModuleSubHandler.java | 4 +- .../AbstractLcnModuleVariableSubHandler.java | 1 - .../LcnModuleMetaFirmwareSubHandler.java | 1 + .../subhandler/LcnModuleOutputSubHandler.java | 2 +- .../LcnModuleRvarLockSubHandler.java | 2 +- .../LcnModuleRvarSetpointSubHandler.java | 24 +++- .../LcnModuleThresholdSubHandler.java | 2 +- .../LcnModuleVariableSubHandler.java | 16 +-- 14 files changed, 144 insertions(+), 79 deletions(-) diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java index 2b241e724..ce286f96c 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.lcn.internal; +import java.util.regex.Pattern; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; @@ -38,6 +40,8 @@ public class LcnBindingConstants { public static final ThingTypeUID THING_TYPE_GROUP = new ThingTypeUID(BINDING_ID, "group"); /** Regex for address in PCK protocol */ public static final String ADDRESS_REGEX = "[:=%]M(?\\d{3})(?\\d{3})"; + public static final Pattern MEASUREMENT_PATTERN_BEFORE_2013 = Pattern + .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.(?\\d{5})"); /** LCN coding for ACK */ public static final int CODE_ACK = -1; } diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java index e8122132e..b903fd037 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java @@ -68,6 +68,7 @@ import org.slf4j.LoggerFactory; @NonNullByDefault public class LcnModuleHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(LcnModuleHandler.class); + private static final int FIRMWARE_VERSION_LENGTH = 6; private static final Map VALUE_CONVERTERS = new HashMap<>(); private static final InversionConverter INVERSION_CONVERTER = new InversionConverter(); private @Nullable LcnAddrMod moduleAddress; @@ -95,11 +96,11 @@ public class LcnModuleHandler extends BaseThingHandler { LcnAddrMod localModuleAddress = moduleAddress = new LcnAddrMod(localConfig.segmentId, localConfig.moduleId); try { - // Determine serial number of manually added modules + ModInfo info = getPckGatewayHandler().getModInfo(localModuleAddress); + readFirmwareVersionFromProperty().ifPresent(info::setFirmwareVersion); requestFirmwareVersionAndSerialNumberIfNotSet(); // create sub handlers - ModInfo info = getPckGatewayHandler().getModInfo(localModuleAddress); for (LcnChannelGroup type : LcnChannelGroup.values()) { subHandlers.put(type, type.createSubHandler(this, info)); } @@ -158,8 +159,7 @@ public class LcnModuleHandler extends BaseThingHandler { * @throws LcnException when the handler is not initialized */ protected void requestFirmwareVersionAndSerialNumberIfNotSet() throws LcnException { - String serialNumber = getThing().getProperties().get(Thing.PROPERTY_SERIAL_NUMBER); - if (serialNumber == null || serialNumber.isEmpty()) { + if (readFirmwareVersionFromProperty().isEmpty()) { LcnAddrMod localModuleAddress = moduleAddress; if (localModuleAddress != null) { getPckGatewayHandler().getModInfo(localModuleAddress).requestFirmwareVersion(); @@ -167,6 +167,21 @@ public class LcnModuleHandler extends BaseThingHandler { } } + private Optional readFirmwareVersionFromProperty() { + String prop = getThing().getProperties().get(Thing.PROPERTY_FIRMWARE_VERSION); + + if (prop == null || prop.length() != FIRMWARE_VERSION_LENGTH) { + return Optional.empty(); + } + + try { + return Optional.of(Integer.parseInt(prop, 16)); + } catch (NumberFormatException e) { + logger.warn("{}: Serial number property invalid", moduleAddress); + return Optional.empty(); + } + } + @Override public void handleCommand(ChannelUID channelUid, Command command) { try { @@ -241,11 +256,7 @@ public class LcnModuleHandler extends BaseThingHandler { * @param pck the message without line termination */ public void handleStatusMessage(String pck) { - for (AbstractLcnModuleSubHandler handler : subHandlers.values()) { - if (handler.tryParse(pck)) { - break; - } - } + subHandlers.values().forEach(h -> h.tryParse(pck)); metadataSubHandlers.forEach(h -> h.tryParse(pck)); } @@ -339,6 +350,15 @@ public class LcnModuleHandler extends BaseThingHandler { updateProperty(Thing.PROPERTY_SERIAL_NUMBER, serialNumber); } + /** + * Updates the LCN module's serial number property. + * + * @param serialNumber the new serial number + */ + public void updateFirmwareVersionProperty(String firmwareVersion) { + updateProperty(Thing.PROPERTY_FIRMWARE_VERSION, firmwareVersion); + } + /** * Invoked when an trigger for this LCN module should be fired to openHAB. * @@ -384,7 +404,7 @@ public class LcnModuleHandler extends BaseThingHandler { LcnAddrMod localModuleAddress = moduleAddress; if (connection != null && localModuleAddress != null) { getPckGatewayHandler().getModInfo(localModuleAddress).onAck(LcnBindingConstants.CODE_ACK, connection, - getPckGatewayHandler().getTimeoutMs(), System.nanoTime()); + getPckGatewayHandler().getTimeoutMs(), System.currentTimeMillis()); } } catch (LcnException e) { logger.warn("Connection or module address not set"); diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/Connection.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/Connection.java index 5d46f4cce..6a5a1afcf 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/Connection.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/Connection.java @@ -141,7 +141,7 @@ public class Connection { if (modData.containsKey(addr)) { ModInfo modInfo = modData.get(addr); if (modInfo != null) { - modInfo.onAck(code, this, this.settings.getTimeout(), System.nanoTime()); + modInfo.onAck(code, this, this.settings.getTimeout(), System.currentTimeMillis()); } } } @@ -244,7 +244,8 @@ public class Connection { logger.warn("Data loss while writing to channel: {}", settings.getAddress()); } else { if (logger.isTraceEnabled()) { - logger.trace("Sent: {}", new String(data, 0, data.length)); + logger.trace("Sent: {}", + new String(data, 0, data.length, LcnDefs.LCN_ENCODING).trim()); } } @@ -313,7 +314,7 @@ public class Connection { void queueDirectly(LcnAddr addr, boolean wantsAck, byte[] data) { if (!addr.isGroup() && wantsAck) { this.updateModuleData((LcnAddrMod) addr).queuePckCommandWithAck(data, this, this.settings.getTimeout(), - System.nanoTime()); + System.currentTimeMillis()); } else { this.queueAndSend(new SendDataPck(addr, false, data)); } @@ -427,7 +428,7 @@ public class Connection { */ public void updateModInfos() { synchronized (modData) { - modData.values().forEach(i -> i.update(this, settings.getTimeout(), System.nanoTime())); + modData.values().forEach(i -> i.update(this, settings.getTimeout(), System.currentTimeMillis())); } } diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateSegmentScan.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateSegmentScan.java index 466d27414..ac00623e0 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateSegmentScan.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateSegmentScan.java @@ -50,7 +50,7 @@ public class ConnectionStateSegmentScan extends AbstractConnectionState { } private void update() { - long currTime = System.nanoTime(); + long currTime = System.currentTimeMillis(); try { if (statusSegmentScan.shouldSendNextRequest(connection.getSettings().getTimeout(), currTime)) { connection.queueDirectly(new LcnAddrGrp(3, 3), false, PckGenerator.segmentCouplerScan()); diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ModInfo.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ModInfo.java index 58fc5604b..96d8301fe 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ModInfo.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ModInfo.java @@ -61,8 +61,8 @@ public class ModInfo { /** The LCN module's address. */ private final LcnAddr addr; - /** Firmware date of the LCN module. -1 means "unknown". */ - private int firmwareVersion = -1; + /** Firmware date of the LCN module. */ + private Optional firmwareVersion = Optional.empty(); /** Firmware version request status. */ private final RequestStatus requestFirmwareVersion = new RequestStatus(-1, NUM_TRIES, "Firmware Version"); @@ -128,7 +128,7 @@ public class ModInfo { for (Variable var : Variable.values()) { if (var != Variable.UNKNOWN) { this.requestStatusVars.put(var, new RequestStatus(MAX_STATUS_POLLED_VALUEAGE_MSEC, NUM_TRIES, - var.getType() + " " + (var.getNumber() + 1))); + addr + " " + var.getType() + " " + (var.getNumber() + 1))); } } } @@ -226,7 +226,7 @@ public class ModInfo { * Triggers a request to retrieve the firmware version of the LCN module, if it is not known, yet. */ public void requestFirmwareVersion() { - if (firmwareVersion == -1) { + if (firmwareVersion.isEmpty()) { requestFirmwareVersion.refresh(); } } @@ -237,11 +237,11 @@ public class ModInfo { * @return if the module has at least 4 threshold registers and 12 variables */ public boolean hasExtendedMeasurementProcessing() { - if (firmwareVersion == -1) { + if (firmwareVersion.isEmpty()) { logger.warn("LCN module firmware version unknown"); return false; } - return firmwareVersion >= LcnBindingConstants.FIRMWARE_2013; + return firmwareVersion.map(v -> v >= LcnBindingConstants.FIRMWARE_2013).orElse(false); } private boolean update(Connection conn, long timeoutMSec, long currTime, RequestStatus requestStatus, String pck) @@ -277,42 +277,11 @@ public class ModInfo { if (update(conn, timeoutMSec, currTime, requestStatusRelays, PckGenerator.requestRelaysStatus())) { return; } + if (update(conn, timeoutMSec, currTime, requestStatusBinSensors, PckGenerator.requestBinSensorsStatus())) { return; } - // Variable requests - if (this.firmwareVersion != -1) { // Firmware version is required - // Use the chance to remove a failed "typeless variable" request - if (lastRequestedVarWithoutTypeInResponse != Variable.UNKNOWN) { - RequestStatus requestStatus = requestStatusVars.get(lastRequestedVarWithoutTypeInResponse); - if (requestStatus != null && requestStatus.isTimeout(timeoutMSec, currTime)) { - lastRequestedVarWithoutTypeInResponse = Variable.UNKNOWN; - } - } - // Variables - for (Map.Entry kv : this.requestStatusVars.entrySet()) { - RequestStatus requestStatus = kv.getValue(); - if (requestStatus.shouldSendNextRequest(timeoutMSec, currTime)) { - // Detect if we can send immediately or if we have to wait for a "typeless" request first - boolean hasTypeInResponse = kv.getKey().hasTypeInResponse(this.firmwareVersion); - if (hasTypeInResponse || this.lastRequestedVarWithoutTypeInResponse == Variable.UNKNOWN) { - try { - conn.queue(this.addr, false, - PckGenerator.requestVarStatus(kv.getKey(), this.firmwareVersion)); - requestStatus.onRequestSent(currTime); - if (!hasTypeInResponse) { - this.lastRequestedVarWithoutTypeInResponse = kv.getKey(); - } - return; - } catch (LcnException ex) { - requestStatus.reset(); - } - } - } - } - } - if (update(conn, timeoutMSec, currTime, requestStatusLedsAndLogicOps, PckGenerator.requestLedsAndLogicOpsStatus())) { return; @@ -322,6 +291,45 @@ public class ModInfo { return; } + // Variable requests + firmwareVersion.ifPresent(firmwareVersion -> { // Firmware version is required + // Use the chance to remove a failed "typeless variable" request + if (lastRequestedVarWithoutTypeInResponse != Variable.UNKNOWN) { + RequestStatus requestStatus = requestStatusVars.get(lastRequestedVarWithoutTypeInResponse); + if (requestStatus != null && requestStatus.isTimeout(timeoutMSec, currTime)) { + lastRequestedVarWithoutTypeInResponse = Variable.UNKNOWN; + } + } + // Variables + for (Map.Entry kv : this.requestStatusVars.entrySet()) { + RequestStatus requestStatus = kv.getValue(); + try { + if (requestStatus.shouldSendNextRequest(timeoutMSec, currTime)) { + // Detect if we can send immediately or if we have to wait for a "typeless" request first + boolean hasTypeInResponse = kv.getKey().hasTypeInResponse(firmwareVersion); + if (hasTypeInResponse || this.lastRequestedVarWithoutTypeInResponse == Variable.UNKNOWN) { + try { + conn.queue(this.addr, false, + PckGenerator.requestVarStatus(kv.getKey(), firmwareVersion)); + requestStatus.onRequestSent(currTime); + if (!hasTypeInResponse) { + this.lastRequestedVarWithoutTypeInResponse = kv.getKey(); + } + return; + } catch (LcnException ex) { + logger.warn("{}: Failed to generate PCK message: {}: {}", addr, kv.getKey(), + ex.getMessage()); + requestStatus.reset(); + lastRequestedVarWithoutTypeInResponse = Variable.UNKNOWN; + } + } + } + } catch (LcnException e) { + logger.warn("{}: Failed to receive measurement value: {}", addr, e.getMessage()); + } + } + }); + // Try to send next acknowledged command. Will also detect failed ones. this.tryProcessNextCommandWithAck(conn, timeoutMSec, currTime); } catch (LcnException e) { @@ -334,8 +342,8 @@ public class ModInfo { * * @return the date */ - public int getFirmwareVersion() { - return this.firmwareVersion; + public Optional getFirmwareVersion() { + return firmwareVersion; } /** @@ -344,7 +352,7 @@ public class ModInfo { * @param firmwareVersion the date */ public void setFirmwareVersion(int firmwareVersion) { - this.firmwareVersion = firmwareVersion; + this.firmwareVersion = Optional.of(firmwareVersion); requestFirmwareVersion.onResponseReceived(); @@ -430,7 +438,7 @@ public class ModInfo { * Requests the current value of all LEDs and logic operations, after a LED has been changed by openHAB. */ public void refreshStatusLedsAnLogicAfterChange() { - requestStatusLedsAndLogicOps.nextRequestIn(STATUS_REQUEST_DELAY_AFTER_COMMAND_MSEC, System.nanoTime()); + requestStatusLedsAndLogicOps.nextRequestIn(STATUS_REQUEST_DELAY_AFTER_COMMAND_MSEC, System.currentTimeMillis()); } /** @@ -444,7 +452,7 @@ public class ModInfo { * Requests the current locking states of all keys, after a lock state has been changed by openHAB. */ public void refreshStatusStatusLockedKeysAfterChange() { - requestStatusLockedKeys.nextRequestIn(STATUS_REQUEST_DELAY_AFTER_COMMAND_MSEC, System.nanoTime()); + requestStatusLockedKeys.nextRequestIn(STATUS_REQUEST_DELAY_AFTER_COMMAND_MSEC, System.currentTimeMillis()); } /** @@ -480,6 +488,10 @@ public class ModInfo { if (requestStatus != null) { requestStatus.onResponseReceived(); } + + if (variable == lastRequestedVarWithoutTypeInResponse) { + lastRequestedVarWithoutTypeInResponse = Variable.UNKNOWN; // Reset + } } /** @@ -495,4 +507,11 @@ public class ModInfo { public void onLockedKeysResponseReceived() { requestStatusLockedKeys.onResponseReceived(); } + + /** + * Returns the module's bus address. + */ + public LcnAddr getAddress() { + return addr; + } } diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/RequestStatus.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/RequestStatus.java index 48cd566fc..a8292829b 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/RequestStatus.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/RequestStatus.java @@ -92,7 +92,7 @@ public class RequestStatus { * @return true if request timed out */ synchronized boolean isTimeout(long timeoutMSec, long currTime) { - return this.isPending() && currTime - this.currRequestTimeStamp >= timeoutMSec * 1000000L; + return this.isPending() && currTime - this.currRequestTimeStamp >= timeoutMSec; } /** @@ -114,14 +114,14 @@ public class RequestStatus { */ public synchronized void nextRequestIn(long delayMSec, long currTime) { this.isActive = true; - this.nextRequestTimeStamp = currTime + delayMSec * 1000000L; + this.nextRequestTimeStamp = currTime + delayMSec; } /** * Schedules a request to retrieve the current value. */ public synchronized void refresh() { - nextRequestIn(0, System.nanoTime()); + nextRequestIn(0, System.currentTimeMillis()); this.numRetriesLeft = this.numTries; } @@ -181,6 +181,11 @@ public class RequestStatus { public synchronized void onResponseReceived() { if (this.isActive) { this.currRequestTimeStamp = 0; // Mark request (if any) as successful + + // Reset timer for next transmission + if (this.maxAgeMSec != -1) { + this.nextRequestIn(this.maxAgeMSec, System.currentTimeMillis()); + } } } diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java index 20f17cc98..2074717e1 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java @@ -120,7 +120,7 @@ public abstract class AbstractLcnModuleSubHandler implements ILcnModuleSubHandle * @param pck the message to process * @return true, if the message could be processed successfully */ - public boolean tryParse(String pck) { + public void tryParse(String pck) { Optional firstSuccessfulMatcher = getPckStatusMessagePatterns().stream().map(p -> p.matcher(pck)) .filter(Matcher::matches).filter(m -> handler.isMyAddress(m.group("segId"), m.group("modId"))) .findAny(); @@ -132,8 +132,6 @@ public abstract class AbstractLcnModuleSubHandler implements ILcnModuleSubHandle logger.warn("Parse error: {}", e.getMessage()); } }); - - return firstSuccessfulMatcher.isPresent(); } /** diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleVariableSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleVariableSubHandler.java index f68cd7593..3128ede27 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleVariableSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleVariableSubHandler.java @@ -38,7 +38,6 @@ public abstract class AbstractLcnModuleVariableSubHandler extends AbstractLcnMod @Override public void handleRefresh(LcnChannelGroup channelGroup, int number) { requestVariable(info, channelGroup, number); - info.requestFirmwareVersion(); } /** diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleMetaFirmwareSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleMetaFirmwareSubHandler.java index c034fd846..9440422d9 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleMetaFirmwareSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleMetaFirmwareSubHandler.java @@ -47,6 +47,7 @@ public class LcnModuleMetaFirmwareSubHandler extends AbstractLcnModuleSubHandler public void handleStatusMessage(Matcher matcher) { info.setFirmwareVersion(Integer.parseInt(matcher.group("firmwareVersion"), 16)); handler.updateSerialNumberProperty(matcher.group("sn")); + handler.updateFirmwareVersionProperty(matcher.group("firmwareVersion")); } @Override diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java index 7a5a961b1..cc944aaf6 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java @@ -107,7 +107,7 @@ public class LcnModuleOutputSubHandler extends AbstractLcnModuleSubHandler { currentColor = hsbType; handler.updateChannel(LcnChannelGroup.OUTPUT, OUTPUT_COLOR, currentColor); - if (info.getFirmwareVersion() >= LcnBindingConstants.FIRMWARE_2014) { + if (info.getFirmwareVersion().map(v -> v >= LcnBindingConstants.FIRMWARE_2014).orElse(true)) { handler.sendPck(PckGenerator.dimAllOutputs(currentColor.getRed().doubleValue(), currentColor.getGreen().doubleValue(), currentColor.getBlue().doubleValue(), output4.doubleValue(), COLOR_RAMP_MS)); diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarLockSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarLockSubHandler.java index 4f828150e..11795d6f2 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarLockSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarLockSubHandler.java @@ -49,7 +49,7 @@ public class LcnModuleRvarLockSubHandler extends AbstractLcnModuleVariableSubHan // request new lock state, if the module doesn't send it on itself Variable variable = getVariable(LcnChannelGroup.RVARSETPOINT, number); - if (variable.shouldPollStatusAfterRegulatorLock(info.getFirmwareVersion(), locked)) { + if (info.getFirmwareVersion().map(v -> variable.shouldPollStatusAfterRegulatorLock(v, locked)).orElse(true)) { info.refreshVariable(variable); } } diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandler.java index 5d70187b9..4cf96729b 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandler.java @@ -13,7 +13,7 @@ package org.openhab.binding.lcn.internal.subhandler; import java.util.Collection; -import java.util.Collections; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -25,10 +25,13 @@ import org.openhab.binding.lcn.internal.common.LcnDefs; import org.openhab.binding.lcn.internal.common.LcnException; import org.openhab.binding.lcn.internal.common.PckGenerator; import org.openhab.binding.lcn.internal.common.Variable; +import org.openhab.binding.lcn.internal.common.Variable.Type; import org.openhab.binding.lcn.internal.common.VariableValue; import org.openhab.binding.lcn.internal.connection.ModInfo; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Handles Commands and State changes of regulator setpoints of an LCN module. @@ -37,8 +40,9 @@ import org.openhab.core.library.types.OnOffType; */ @NonNullByDefault public class LcnModuleRvarSetpointSubHandler extends AbstractLcnModuleVariableSubHandler { + private final Logger logger = LoggerFactory.getLogger(LcnModuleRvarSetpointSubHandler.class); private static final Pattern PATTERN = Pattern - .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.S(?\\d)(?\\d+)"); + .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.S(?\\d)(?\\d{1,5})"); public LcnModuleRvarSetpointSubHandler(LcnModuleHandler handler, ModInfo info) { super(handler, info); @@ -66,7 +70,19 @@ public class LcnModuleRvarSetpointSubHandler extends AbstractLcnModuleVariableSu @Override public void handleStatusMessage(Matcher matcher) throws LcnException { - Variable variable = Variable.setPointIdToVar(Integer.parseInt(matcher.group("id")) - 1); + Variable variable; + if (matcher.pattern() == PATTERN) { + variable = Variable.setPointIdToVar(Integer.parseInt(matcher.group("id")) - 1); + } else if (matcher.pattern() == LcnBindingConstants.MEASUREMENT_PATTERN_BEFORE_2013) { + variable = info.getLastRequestedVarWithoutTypeInResponse(); + + if (variable.getType() != Type.REGULATOR) { + return; + } + } else { + logger.warn("Unexpected pattern: {}", matcher.pattern()); + return; + } VariableValue value = fireUpdateAndReset(matcher, "", variable); fireUpdate(LcnChannelGroup.RVARLOCK, variable.getNumber(), OnOffType.from(value.isRegulatorLocked())); @@ -74,6 +90,6 @@ public class LcnModuleRvarSetpointSubHandler extends AbstractLcnModuleVariableSu @Override public Collection getPckStatusMessagePatterns() { - return Collections.singleton(PATTERN); + return List.of(PATTERN, LcnBindingConstants.MEASUREMENT_PATTERN_BEFORE_2013); } } diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandler.java index 132fdd58f..46af02d65 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandler.java @@ -59,7 +59,7 @@ public class LcnModuleThresholdSubHandler extends AbstractLcnModuleVariableSubHa info.hasExtendedMeasurementProcessing())); // request new value, if the module doesn't send it on itself - if (variable.shouldPollStatusAfterCommand(info.getFirmwareVersion())) { + if (info.getFirmwareVersion().map(v -> variable.shouldPollStatusAfterCommand(v)).orElse(true)) { info.refreshVariable(variable); } } catch (LcnException e) { diff --git a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandler.java b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandler.java index b67efad8c..5a9e77d4a 100644 --- a/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandler.java +++ b/bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandler.java @@ -12,8 +12,8 @@ */ package org.openhab.binding.lcn.internal.subhandler; -import java.util.Arrays; import java.util.Collection; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -25,6 +25,7 @@ import org.openhab.binding.lcn.internal.common.LcnDefs; import org.openhab.binding.lcn.internal.common.LcnException; import org.openhab.binding.lcn.internal.common.PckGenerator; import org.openhab.binding.lcn.internal.common.Variable; +import org.openhab.binding.lcn.internal.common.Variable.Type; import org.openhab.binding.lcn.internal.connection.ModInfo; import org.openhab.core.library.types.DecimalType; import org.slf4j.Logger; @@ -40,8 +41,6 @@ public class LcnModuleVariableSubHandler extends AbstractLcnModuleVariableSubHan private final Logger logger = LoggerFactory.getLogger(LcnModuleVariableSubHandler.class); private static final Pattern PATTERN = Pattern .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.A(?\\d{3})(?\\d+)"); - private static final Pattern PATTERN_LEGACY = Pattern - .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.(?\\d+)"); public LcnModuleVariableSubHandler(LcnModuleHandler handler, ModInfo info) { super(handler, info); @@ -56,7 +55,7 @@ public class LcnModuleVariableSubHandler extends AbstractLcnModuleVariableSubHan handler.sendPck(PckGenerator.setVariableRelative(variable, LcnDefs.RelVarRef.CURRENT, relativeChange)); // request new value, if the module doesn't send it on itself - if (variable.shouldPollStatusAfterCommand(info.getFirmwareVersion())) { + if (info.getFirmwareVersion().map(v -> variable.shouldPollStatusAfterCommand(v)).orElse(true)) { info.refreshVariable(variable); } } catch (LcnException e) { @@ -71,9 +70,12 @@ public class LcnModuleVariableSubHandler extends AbstractLcnModuleVariableSubHan Variable variable; if (matcher.pattern() == PATTERN) { variable = Variable.varIdToVar(Integer.parseInt(matcher.group("id")) - 1); - } else if (matcher.pattern() == PATTERN_LEGACY) { + } else if (matcher.pattern() == LcnBindingConstants.MEASUREMENT_PATTERN_BEFORE_2013) { variable = info.getLastRequestedVarWithoutTypeInResponse(); - info.setLastRequestedVarWithoutTypeInResponse(Variable.UNKNOWN); // Reset + + if (variable == Variable.UNKNOWN || variable.getType() != Type.VARIABLE) { + return; + } } else { logger.warn("Unexpected pattern: {}", matcher.pattern()); return; @@ -83,6 +85,6 @@ public class LcnModuleVariableSubHandler extends AbstractLcnModuleVariableSubHan @Override public Collection getPckStatusMessagePatterns() { - return Arrays.asList(PATTERN, PATTERN_LEGACY); + return List.of(PATTERN, LcnBindingConstants.MEASUREMENT_PATTERN_BEFORE_2013); } }