]> git.basschouten.com Git - openhab-addons.git/commitdiff
[lcn] Fix several bugs in measurement processing with firmware before 2013 (#9991)
authorFabian Wolter <github@fabian-wolter.de>
Mon, 1 Feb 2021 11:09:09 +0000 (12:09 +0100)
committerGitHub <noreply@github.com>
Mon, 1 Feb 2021 11:09:09 +0000 (12:09 +0100)
Signed-off-by: Fabian Wolter <github@fabian-wolter.de>
14 files changed:
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnBindingConstants.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/LcnModuleHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/Connection.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ConnectionStateSegmentScan.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/ModInfo.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/connection/RequestStatus.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/AbstractLcnModuleVariableSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleMetaFirmwareSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleOutputSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarLockSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleRvarSetpointSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleThresholdSubHandler.java
bundles/org.openhab.binding.lcn/src/main/java/org/openhab/binding/lcn/internal/subhandler/LcnModuleVariableSubHandler.java

index 2b241e72465170511c77057f403fc11ed4bf31f8..ce286f96ce8207ea79bcd2075cd4cc6ac793c6bf 100644 (file)
@@ -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(?<segId>\\d{3})(?<modId>\\d{3})";
+    public static final Pattern MEASUREMENT_PATTERN_BEFORE_2013 = Pattern
+            .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.(?<value>\\d{5})");
     /** LCN coding for ACK */
     public static final int CODE_ACK = -1;
 }
index e8122132e408397a161c90d81b5e7f0ac62c2870..b903fd037724ee1f05a3fe1cad8bec47239849f9 100644 (file)
@@ -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<String, Converter> 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<Integer> 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");
index 5d46f4cce39f44a27fbe8f72848fb3a15e862ad8..6a5a1afcf80a0c06913c576c8a238cd0a36ab023 100644 (file)
@@ -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()));
         }
     }
 
index 466d2741410e25533ee37c6911f9fd2a8943c03e..ac00623e0a4f68a41c5f09e154de5cf763a3e633 100644 (file)
@@ -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());
index 58fc5604b73a9a60ea9fd3b15eec7dc4b957cdf4..96d8301feda69b9925dd5eb7093c534add4f74b3 100644 (file)
@@ -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<Integer> 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,12 +277,22 @@ public class ModInfo {
             if (update(conn, timeoutMSec, currTime, requestStatusRelays, PckGenerator.requestRelaysStatus())) {
                 return;
             }
+
             if (update(conn, timeoutMSec, currTime, requestStatusBinSensors, PckGenerator.requestBinSensorsStatus())) {
                 return;
             }
 
+            if (update(conn, timeoutMSec, currTime, requestStatusLedsAndLogicOps,
+                    PckGenerator.requestLedsAndLogicOpsStatus())) {
+                return;
+            }
+
+            if (update(conn, timeoutMSec, currTime, requestStatusLockedKeys, PckGenerator.requestKeyLocksStatus())) {
+                return;
+            }
+
             // Variable requests
-            if (this.firmwareVersion != -1) { // Firmware version is required
+            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);
@@ -293,34 +303,32 @@ public class ModInfo {
                 // Variables
                 for (Map.Entry<Variable, RequestStatus> 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();
+                    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;
                                 }
-                                return;
-                            } catch (LcnException ex) {
-                                requestStatus.reset();
                             }
                         }
+                    } catch (LcnException e) {
+                        logger.warn("{}: Failed to receive measurement value: {}", addr, e.getMessage());
                     }
                 }
-            }
-
-            if (update(conn, timeoutMSec, currTime, requestStatusLedsAndLogicOps,
-                    PckGenerator.requestLedsAndLogicOpsStatus())) {
-                return;
-            }
-
-            if (update(conn, timeoutMSec, currTime, requestStatusLockedKeys, PckGenerator.requestKeyLocksStatus())) {
-                return;
-            }
+            });
 
             // Try to send next acknowledged command. Will also detect failed ones.
             this.tryProcessNextCommandWithAck(conn, timeoutMSec, currTime);
@@ -334,8 +342,8 @@ public class ModInfo {
      *
      * @return the date
      */
-    public int getFirmwareVersion() {
-        return this.firmwareVersion;
+    public Optional<Integer> 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;
+    }
 }
index 48cd566fc253bb5a157e20476ccb0d968615af5d..a8292829b4ff8c5a41d8e3a717b744e4de220872 100644 (file)
@@ -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());
+            }
         }
     }
 
index 20f17cc984a37280a30d7e61cc03cc860461e8dc..2074717e135b5a3fce0f56ddd8a2bc14230e69ee 100644 (file)
@@ -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<Matcher> 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();
     }
 
     /**
index f68cd75933630c95374862febe047f259f55eafd..3128ede27670b0eeb19c0241ab36037a952ed974 100644 (file)
@@ -38,7 +38,6 @@ public abstract class AbstractLcnModuleVariableSubHandler extends AbstractLcnMod
     @Override
     public void handleRefresh(LcnChannelGroup channelGroup, int number) {
         requestVariable(info, channelGroup, number);
-        info.requestFirmwareVersion();
     }
 
     /**
index c034fd846c3f0599084f30a23ca4ede9cfcdfe18..9440422d9eb2bbb72d497567277cedd19b1666f2 100644 (file)
@@ -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
index 7a5a961b18da443959c81b7a6b84cb9bff422cb3..cc944aaf6085c990b9366e0995b57ed06a906e83 100644 (file)
@@ -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));
index 4f828150e16be04d2308b9472002fce39192dd1b..11795d6f246862c0dfd0f94455a23602742321c6 100644 (file)
@@ -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);
         }
     }
index 5d70187b998172d9b8cf17617cdd22fe6502ec1d..4cf96729bd0069607cadb3daac3266da2539531e 100644 (file)
@@ -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(?<id>\\d)(?<value>\\d+)");
+            .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.S(?<id>\\d)(?<value>\\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<Pattern> getPckStatusMessagePatterns() {
-        return Collections.singleton(PATTERN);
+        return List.of(PATTERN, LcnBindingConstants.MEASUREMENT_PATTERN_BEFORE_2013);
     }
 }
index 132fdd58f6cfe487f3f67ca39b703b1527fbd946..46af02d65202c25554fcca5cabd9d7e9652c567b 100644 (file)
@@ -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) {
index b67efad8c11e5faa840db8a0d0c21e1f50bf699f..5a9e77d4a3e905a57d18b2c302cf580b099486f6 100644 (file)
@@ -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(?<id>\\d{3})(?<value>\\d+)");
-    private static final Pattern PATTERN_LEGACY = Pattern
-            .compile(LcnBindingConstants.ADDRESS_REGEX + "\\.(?<value>\\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<Pattern> getPckStatusMessagePatterns() {
-        return Arrays.asList(PATTERN, PATTERN_LEGACY);
+        return List.of(PATTERN, LcnBindingConstants.MEASUREMENT_PATTERN_BEFORE_2013);
     }
 }