Skip to content

Commit adacdeb

Browse files
authored
[digiplex] Handle erroneous responses and restart the bridge (openhab#18035)
Signed-off-by: Robert Michalak <[email protected]>
1 parent d36b2a8 commit adacdeb

File tree

7 files changed

+325
-15
lines changed

7 files changed

+325
-15
lines changed

bundles/org.openhab.binding.digiplex/src/main/java/org/openhab/binding/digiplex/internal/DigiplexBindingConstants.java

-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public class DigiplexBindingConstants {
5151
public static final String BRIDGE_MESSAGES_SENT = "statistics#messages_sent";
5252
public static final String BRIDGE_RESPONSES_RECEIVED = "statistics#responses_received";
5353
public static final String BRIDGE_EVENTS_RECEIVED = "statistics#events_received";
54-
5554
public static final String BRIDGE_TLM_TROUBLE = "troubles#tlm_trouble";
5655
public static final String BRIDGE_AC_FAILURE = "troubles#ac_failure";
5756
public static final String BRIDGE_BATTERY_FAILURE = "troubles#battery_failure";

bundles/org.openhab.binding.digiplex/src/main/java/org/openhab/binding/digiplex/internal/communication/DigiplexMessageHandler.java

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ default void handleArmDisarmAreaResponse(AreaArmDisarmResponse response) {
5252
default void handleUnknownResponse(UnknownResponse response) {
5353
}
5454

55+
default void handleErroneousResponse(ErroneousResponse response) {
56+
}
57+
5558
// Events
5659
default void handleZoneEvent(ZoneEvent event) {
5760
}

bundles/org.openhab.binding.digiplex/src/main/java/org/openhab/binding/digiplex/internal/communication/DigiplexResponseResolver.java

+53-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.openhab.binding.digiplex.internal.communication;
1414

1515
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.eclipse.jdt.annotation.Nullable;
1617
import org.openhab.binding.digiplex.internal.communication.events.AreaEvent;
1718
import org.openhab.binding.digiplex.internal.communication.events.AreaEventType;
1819
import org.openhab.binding.digiplex.internal.communication.events.GenericEvent;
@@ -29,21 +30,19 @@
2930
* Resolves serial messages to appropriate classes
3031
*
3132
* @author Robert Michalak - Initial contribution
32-
*
3333
*/
3434
@NonNullByDefault
3535
public class DigiplexResponseResolver {
3636

3737
private static final String OK = "&ok";
38-
// TODO: handle failures
3938
private static final String FAIL = "&fail";
4039

4140
public static DigiplexResponse resolveResponse(String message) {
4241
if (message.length() < 4) { // sanity check: try to filter out malformed responses
43-
return new UnknownResponse(message);
42+
return new ErroneousResponse(message);
4443
}
4544

46-
int zoneNo, areaNo;
45+
Integer zoneNo, areaNo;
4746
String commandType = message.substring(0, 2);
4847
switch (commandType) {
4948
case "CO": // communication status
@@ -53,24 +52,36 @@ public static DigiplexResponse resolveResponse(String message) {
5352
return CommunicationStatus.OK;
5453
}
5554
case "ZL": // zone label
56-
zoneNo = Integer.valueOf(message.substring(2, 5));
55+
zoneNo = getZoneOrArea(message);
56+
if (zoneNo == null) {
57+
return new ErroneousResponse(message);
58+
}
5759
if (message.contains(FAIL)) {
5860
return ZoneLabelResponse.failure(zoneNo);
5961
} else {
6062
return ZoneLabelResponse.success(zoneNo, message.substring(5).trim());
6163
}
6264
case "AL": // area label
63-
areaNo = Integer.valueOf(message.substring(2, 5));
65+
areaNo = getZoneOrArea(message);
66+
if (areaNo == null) {
67+
return new ErroneousResponse(message);
68+
}
6469
if (message.contains(FAIL)) {
6570
return AreaLabelResponse.failure(areaNo);
6671
} else {
6772
return AreaLabelResponse.success(areaNo, message.substring(5).trim());
6873
}
6974
case "RZ": // zone status
70-
zoneNo = Integer.valueOf(message.substring(2, 5));
75+
zoneNo = getZoneOrArea(message);
76+
if (zoneNo == null) {
77+
return new ErroneousResponse(message);
78+
}
7179
if (message.contains(FAIL)) {
7280
return ZoneStatusResponse.failure(zoneNo);
7381
} else {
82+
if (message.length() < 10) {
83+
return new ErroneousResponse(message);
84+
}
7485
return ZoneStatusResponse.success(zoneNo, // zone number
7586
ZoneStatus.fromMessage(message.charAt(5)), // status
7687
toBoolean(message.charAt(6)), // alarm
@@ -79,10 +90,16 @@ public static DigiplexResponse resolveResponse(String message) {
7990
toBoolean(message.charAt(9))); // battery low
8091
}
8192
case "RA": // area status
82-
areaNo = Integer.valueOf(message.substring(2, 5));
93+
areaNo = getZoneOrArea(message);
94+
if (areaNo == null) {
95+
return new ErroneousResponse(message);
96+
}
8397
if (message.contains(FAIL)) {
8498
return AreaStatusResponse.failure(areaNo);
8599
} else {
100+
if (message.length() < 12) {
101+
return new ErroneousResponse(message);
102+
}
86103
return AreaStatusResponse.success(areaNo, // zone number
87104
AreaStatus.fromMessage(message.charAt(5)), // status
88105
toBoolean(message.charAt(6)), // zone in memory
@@ -95,7 +112,10 @@ public static DigiplexResponse resolveResponse(String message) {
95112
case "AA": // area arm
96113
case "AQ": // area quick arm
97114
case "AD": // area disarm
98-
areaNo = Integer.valueOf(message.substring(2, 5));
115+
areaNo = getZoneOrArea(message);
116+
if (areaNo == null) {
117+
return new ErroneousResponse(message);
118+
}
99119
if (message.contains(FAIL)) {
100120
return AreaArmDisarmResponse.failure(areaNo, ArmDisarmType.fromMessage(commandType));
101121
} else {
@@ -105,21 +125,41 @@ public static DigiplexResponse resolveResponse(String message) {
105125
case "PG": // PGM events
106126
default:
107127
if (message.startsWith("G")) {
108-
return resolveSystemEvent(message);
128+
if (message.length() >= 12) {
129+
return resolveSystemEvent(message);
130+
} else {
131+
return new ErroneousResponse(message);
132+
}
109133
} else {
110134
return new UnknownResponse(message);
111135
}
112136
}
113137
}
114138

139+
private static @Nullable Integer getZoneOrArea(String message) {
140+
if (message.length() < 5) {
141+
return null;
142+
}
143+
try {
144+
return Integer.valueOf(message.substring(2, 5));
145+
} catch (NumberFormatException e) {
146+
return null;
147+
}
148+
}
149+
115150
private static boolean toBoolean(char value) {
116151
return value != 'O';
117152
}
118153

119154
private static DigiplexResponse resolveSystemEvent(String message) {
120-
int eventGroup = Integer.parseInt(message.substring(1, 4));
121-
int eventNumber = Integer.parseInt(message.substring(5, 8));
122-
int areaNumber = Integer.parseInt(message.substring(9, 12));
155+
int eventGroup, eventNumber, areaNumber;
156+
try {
157+
eventGroup = Integer.parseInt(message.substring(1, 4));
158+
eventNumber = Integer.parseInt(message.substring(5, 8));
159+
areaNumber = Integer.parseInt(message.substring(9, 12));
160+
} catch (NumberFormatException e) {
161+
return new ErroneousResponse(message);
162+
}
123163
switch (eventGroup) {
124164
case 0:
125165
return new ZoneStatusEvent(eventNumber, ZoneStatus.CLOSED, areaNumber);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Copyright (c) 2010-2025 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.digiplex.internal.communication;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
17+
/**
18+
* Erroneous message from PRT3.
19+
*
20+
* Message that is invalid, which happens sometimes due to communication errors.
21+
*
22+
* @author Robert Michalak - Initial contribution
23+
*
24+
*/
25+
@NonNullByDefault
26+
public class ErroneousResponse implements DigiplexResponse {
27+
28+
public final String message;
29+
30+
public ErroneousResponse(String message) {
31+
this.message = message;
32+
}
33+
34+
@Override
35+
public void accept(DigiplexMessageHandler visitor) {
36+
visitor.handleErroneousResponse(this);
37+
}
38+
}

bundles/org.openhab.binding.digiplex/src/main/java/org/openhab/binding/digiplex/internal/communication/UnknownResponse.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import org.eclipse.jdt.annotation.NonNullByDefault;
1616

1717
/**
18-
* Unknown message from PRT3
18+
* Unknown message from PRT3.
19+
*
20+
* Message that is otherwise valid, but not handled in this binding.
1921
*
2022
* @author Robert Michalak - Initial contribution
2123
*

bundles/org.openhab.binding.digiplex/src/main/java/org/openhab/binding/digiplex/internal/handler/DigiplexBridgeHandler.java

+7
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.openhab.binding.digiplex.internal.communication.DigiplexRequest;
3939
import org.openhab.binding.digiplex.internal.communication.DigiplexResponse;
4040
import org.openhab.binding.digiplex.internal.communication.DigiplexResponseResolver;
41+
import org.openhab.binding.digiplex.internal.communication.ErroneousResponse;
4142
import org.openhab.binding.digiplex.internal.communication.events.AbstractEvent;
4243
import org.openhab.binding.digiplex.internal.communication.events.TroubleEvent;
4344
import org.openhab.binding.digiplex.internal.communication.events.TroubleStatus;
@@ -295,6 +296,12 @@ public void handleTroubleEvent(TroubleEvent troubleEvent) {
295296
updateState(channel, state);
296297
}
297298
}
299+
300+
@Override
301+
public void handleErroneousResponse(ErroneousResponse response) {
302+
logger.debug("Erroneous response: {}", response.message);
303+
handleCommunicationError();
304+
}
298305
}
299306

300307
private class DigiplexReceiverThread extends Thread {

0 commit comments

Comments
 (0)