Skip to content

Commit dcac0a4

Browse files
druciakKrzysztof Goworek
andauthored
Fix event log partition keypad decoding (openhab#18192)
Other minor changes Signed-off-by: Krzysztof Goworek <krzysztof.goworek@gmail.com> Co-authored-by: Krzysztof Goworek <krzysztof.goworek@gmail.com>
1 parent cd40d05 commit dcac0a4

2 files changed

Lines changed: 226 additions & 7 deletions

File tree

bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/command/ReadEventCommand.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
package org.openhab.binding.satel.internal.command;
1414

15+
import java.time.Clock;
1516
import java.time.LocalDateTime;
1617

1718
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -29,6 +30,8 @@ public class ReadEventCommand extends SatelCommandBase {
2930

3031
private final Logger logger = LoggerFactory.getLogger(this.getClass());
3132

33+
private final Clock clock;
34+
3235
public static final byte COMMAND_CODE = (byte) 0x8c;
3336

3437
/**
@@ -47,7 +50,7 @@ public enum EventClass {
4750
USER_FUNCTIONS("user functions"),
4851
SYSTEM_EVENTS("system events");
4952

50-
private String description;
53+
private final String description;
5154

5255
EventClass(String description) {
5356
this.description = description;
@@ -64,7 +67,18 @@ public String getDescription() {
6467
* @param eventIndex index of event record to retrieve, -1 for the most recent one
6568
*/
6669
public ReadEventCommand(int eventIndex) {
70+
this(eventIndex, Clock.systemDefaultZone());
71+
}
72+
73+
/**
74+
* Creates new command class instance to read a record under given index.
75+
*
76+
* @param eventIndex index of event record to retrieve, -1 for the most recent one
77+
* @param clock clock for getting event timestamp
78+
*/
79+
public ReadEventCommand(int eventIndex, Clock clock) {
6780
super(COMMAND_CODE, getIndexBytes(eventIndex));
81+
this.clock = clock;
6882
}
6983

7084
private static byte[] getIndexBytes(int index) {
@@ -97,7 +111,7 @@ public boolean isEventPresent() {
97111
*/
98112
public LocalDateTime getTimestamp() {
99113
final byte[] payload = getResponse().getPayload();
100-
final int currentYear = LocalDateTime.now().getYear();
114+
final int currentYear = LocalDateTime.now(clock).getYear();
101115
final int yearBase = currentYear / 4;
102116
final int yearMarker = (payload[0] >> 6) & 0x03;
103117
int year = 4 * yearBase + yearMarker;
@@ -121,7 +135,7 @@ public EventClass getEventClass() {
121135
}
122136

123137
/**
124-
* Returns number of partion the event is about.
138+
* Returns number of partition the event is about.
125139
*
126140
* @return partition number
127141
*/
@@ -135,7 +149,7 @@ public int getPartition() {
135149
* @return partition keypad number
136150
*/
137151
public int getPartitionKeypad() {
138-
return ((getResponse().getPayload()[4] >> 2) & 0x3f) + 1;
152+
return ((getResponse().getPayload()[4] << 3) & 0x20) + ((getResponse().getPayload()[4] >> 3) & 0x1f) + 1;
139153
}
140154

141155
/**
@@ -188,13 +202,13 @@ public int getUserControlNumber() {
188202
}
189203

190204
/**
191-
* Return index of previous event in the log. Can be used to iterate over tha event log.
205+
* Return index of previous event in the log. Can be used to iterate over the event log.
192206
*
193207
* @return index of previous event record in the log
194208
*/
195209
public int getNextIndex() {
196210
final byte[] payload = getResponse().getPayload();
197-
return (payload[8] << 16) + ((payload[9] & 0xff) << 8) + (payload[10] & 0xff);
211+
return ((payload[8] & 0xff) << 16) + ((payload[9] & 0xff) << 8) + (payload[10] & 0xff);
198212
}
199213

200214
/**
@@ -204,7 +218,7 @@ public int getNextIndex() {
204218
*/
205219
public int getCurrentIndex() {
206220
final byte[] payload = getResponse().getPayload();
207-
return (payload[11] << 16) + ((payload[12] & 0xff) << 8) + (payload[13] & 0xff);
221+
return ((payload[11] & 0xff) << 16) + ((payload[12] & 0xff) << 8) + (payload[13] & 0xff);
208222
}
209223

210224
@Override
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
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.satel.internal.command;
14+
15+
import static org.junit.jupiter.api.Assertions.*;
16+
import static org.mockito.Mockito.mock;
17+
import static org.mockito.Mockito.when;
18+
import static org.openhab.binding.satel.internal.command.ReadEventCommand.COMMAND_CODE;
19+
import static org.openhab.binding.satel.internal.command.ReadEventCommand.EventClass;
20+
21+
import java.time.Clock;
22+
import java.time.Instant;
23+
import java.time.LocalDateTime;
24+
import java.time.ZoneId;
25+
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
import org.openhab.binding.satel.internal.event.EventDispatcher;
29+
import org.openhab.binding.satel.internal.protocol.SatelMessage;
30+
31+
/**
32+
* @author Krzysztof Goworek - Initial contribution
33+
*/
34+
class ReadEventCommandTest {
35+
36+
private final EventDispatcher eventDispatcher = new EventDispatcher();
37+
38+
private final Clock clock = mock(Clock.class);
39+
40+
private final ReadEventCommand testSubject = new ReadEventCommand(-1, clock);
41+
42+
@BeforeEach
43+
void setupClock() {
44+
when(clock.getZone()).thenReturn(ZoneId.systemDefault());
45+
when(clock.instant()).thenReturn(Instant.parse("2012-01-01T00:00:00Z"));
46+
}
47+
48+
@Test
49+
void handleResponseShouldFailIfResponseHasWrongSize() {
50+
SatelMessage response = new SatelMessage(COMMAND_CODE, new byte[13]);
51+
52+
assertFalse(testSubject.handleResponse(eventDispatcher, response));
53+
}
54+
55+
@Test
56+
void handleResponseShouldSucceedIfResponseHasCorrectSize() {
57+
SatelMessage response = new SatelMessage(COMMAND_CODE, new byte[14]);
58+
59+
assertTrue(testSubject.handleResponse(eventDispatcher, response));
60+
}
61+
62+
@Test
63+
void isEmptyShouldReturnTrueForEmptyResponse() {
64+
SatelMessage response = new SatelMessage(COMMAND_CODE, new byte[14]);
65+
testSubject.handleResponse(eventDispatcher, response);
66+
67+
assertTrue(testSubject.isEmpty());
68+
}
69+
70+
@Test
71+
void isEmptyShouldReturnFalseForNonEmptyResponse() {
72+
SatelMessage response = createMessageWithBytes(0, 0x20);
73+
testSubject.handleResponse(eventDispatcher, response);
74+
75+
assertFalse(testSubject.isEmpty());
76+
}
77+
78+
@Test
79+
void isPresentShouldReturnFalseForEmptyResponse() {
80+
SatelMessage response = new SatelMessage(COMMAND_CODE, new byte[14]);
81+
testSubject.handleResponse(eventDispatcher, response);
82+
83+
assertFalse(testSubject.isEventPresent());
84+
}
85+
86+
@Test
87+
void isPresentShouldReturnTrueForNonEmptyResponse() {
88+
SatelMessage response = createMessageWithBytes(0, 0x10);
89+
testSubject.handleResponse(eventDispatcher, response);
90+
91+
assertTrue(testSubject.isEventPresent());
92+
}
93+
94+
@Test
95+
void getTimestampShouldReturnCorrectDateAndTime1() {
96+
SatelMessage response = createMessageWithBytes(0, 0xc0, 0x1f, 0x74, 0xc7);
97+
testSubject.handleResponse(eventDispatcher, response);
98+
99+
assertEquals(LocalDateTime.of(2011, 7, 31, 20, 23), testSubject.getTimestamp());
100+
}
101+
102+
@Test
103+
void getTimestampShouldReturnCorrectDateAndTime2() {
104+
SatelMessage response = createMessageWithBytes(0, 0x00, 0x07, 0xc0, 0xff);
105+
testSubject.handleResponse(eventDispatcher, response);
106+
107+
assertEquals(LocalDateTime.of(2012, 12, 7, 4, 15), testSubject.getTimestamp());
108+
}
109+
110+
@Test
111+
void getEventClassShouldReturnEventClass() {
112+
SatelMessage response = createMessageWithBytes(1, 0xa0);
113+
testSubject.handleResponse(eventDispatcher, response);
114+
115+
assertEquals(EventClass.TROUBLES, testSubject.getEventClass());
116+
}
117+
118+
@Test
119+
void getPartitionShouldReturnPartitionNumber() {
120+
SatelMessage response = createMessageWithBytes(4, 0xf8);
121+
testSubject.handleResponse(eventDispatcher, response);
122+
123+
assertEquals(32, testSubject.getPartition());
124+
}
125+
126+
@Test
127+
void getPartitionKeypadShouldReturnPartitionKeypadNumber() {
128+
SatelMessage response = createMessageWithBytes(4, 0x7c);
129+
testSubject.handleResponse(eventDispatcher, response);
130+
131+
assertEquals(48, testSubject.getPartitionKeypad());
132+
}
133+
134+
@Test
135+
void getEventCodeShouldReturnEventCode() {
136+
SatelMessage response = createMessageWithBytes(4, 0x3, 0xff);
137+
testSubject.handleResponse(eventDispatcher, response);
138+
139+
assertEquals(0x3ff, testSubject.getEventCode());
140+
}
141+
142+
@Test
143+
void isRestoreShouldReturnFalseForEmptyResponse() {
144+
SatelMessage response = new SatelMessage(COMMAND_CODE, new byte[14]);
145+
testSubject.handleResponse(eventDispatcher, response);
146+
147+
assertFalse(testSubject.isRestore());
148+
}
149+
150+
@Test
151+
void isRestoreShouldReturnRestoreFlagSet() {
152+
SatelMessage response = createMessageWithBytes(4, 0x4);
153+
testSubject.handleResponse(eventDispatcher, response);
154+
155+
assertTrue(testSubject.isRestore());
156+
}
157+
158+
@Test
159+
void getSourceShouldReturnSourceNumber() {
160+
SatelMessage response = createMessageWithBytes(6, 0xff);
161+
testSubject.handleResponse(eventDispatcher, response);
162+
163+
assertEquals(255, testSubject.getSource());
164+
}
165+
166+
@Test
167+
void getObjectShouldReturnObjectNumber() {
168+
SatelMessage response = createMessageWithBytes(7, 0xe0);
169+
testSubject.handleResponse(eventDispatcher, response);
170+
171+
assertEquals(7, testSubject.getObject());
172+
}
173+
174+
@Test
175+
void getUserControlNumberShouldReturnUserControlNumber() {
176+
SatelMessage response = createMessageWithBytes(7, 0x1f);
177+
testSubject.handleResponse(eventDispatcher, response);
178+
179+
assertEquals(31, testSubject.getUserControlNumber());
180+
}
181+
182+
@Test
183+
void getNextIndexShouldReturnNextIndex() {
184+
SatelMessage response = createMessageWithBytes(8, 0xff, 0xff, 0xff);
185+
testSubject.handleResponse(eventDispatcher, response);
186+
187+
assertEquals(0xffffff, testSubject.getNextIndex());
188+
}
189+
190+
@Test
191+
void getCurrentIndexShouldReturnCurrentIndex() {
192+
SatelMessage response = createMessageWithBytes(11, 0xff, 0xff, 0xff);
193+
testSubject.handleResponse(eventDispatcher, response);
194+
195+
assertEquals(0xffffff, testSubject.getCurrentIndex());
196+
}
197+
198+
private SatelMessage createMessageWithBytes(int offset, int... data) {
199+
byte[] payload = new byte[14];
200+
for (int i = 0; i < data.length; ++i) {
201+
payload[offset + i] = (byte) data[i];
202+
}
203+
return new SatelMessage(COMMAND_CODE, payload);
204+
}
205+
}

0 commit comments

Comments
 (0)