2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.alarmdecoder.internal.protocol;
15 import java.util.List;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
21 * The {@link KeypadMessage} class represents a parsed keypad (KPM) message.
22 * Based partly on code from the OH1 alarmdecoder binding by Bernd Pfrommer.
24 * @author Bob Adair - Initial contribution
27 public class KeypadMessage extends ADMessage {
29 // Example: [00110011000000003A--],010,[f70700000010808c18020000000000],"ARMED ***STAY** ZONE BYPASSED "
31 public static final int BIT_READY = 17;
32 public static final int BIT_ARMEDAWAY = 16;
33 public static final int BIT_ARMEDHOME = 15;
34 public static final int BIT_BACKLIGHT = 14;
35 public static final int BIT_PRORGAM = 13;
36 public static final int BIT_BYPASSED = 9;
37 public static final int BIT_ACPOWER = 8;
38 public static final int BIT_CHIME = 7;
39 public static final int BIT_ALARMOCCURRED = 6;
40 public static final int BIT_ALARM = 5;
41 public static final int BIT_LOWBAT = 4;
42 public static final int BIT_DELAYOFF = 3;
43 public static final int BIT_FIRE = 2;
44 public static final int BIT_SYSFAULT = 1;
45 public static final int BIT_PERIMETER = 0;
47 public final String bitField;
48 public final int numericCode;
49 public final String rawData;
50 public final String alphaMessage;
51 public final int nbeeps;
52 public final int status;
54 private final int upper;
55 private final int lower;
57 public KeypadMessage(String message) throws IllegalArgumentException {
59 List<String> parts = splitMsg(message.replace("!KPM:", ""));
61 if (parts.size() != 4) {
62 throw new IllegalArgumentException("Invalid number of parts in keypad message");
64 if (parts.get(0).length() != 22) {
65 throw new IllegalArgumentException("Invalid field length in keypad message");
68 bitField = parts.get(0);
69 rawData = parts.get(2);
70 alphaMessage = parts.get(3).replaceAll("^\"|\"$", "");
75 numeric = Integer.parseInt(parts.get(1));
76 } catch (NumberFormatException e) {
77 numeric = Integer.parseInt(parts.get(1), 16);
79 this.numericCode = numeric;
81 this.upper = Integer.parseInt(parts.get(0).substring(1, 6), 2);
82 this.nbeeps = Integer.parseInt(parts.get(0).substring(6, 7));
83 this.lower = Integer.parseInt(parts.get(0).substring(7, 17), 2);
84 this.status = ((upper & 0x1F) << 13) | ((nbeeps & 0x3) << 10) | lower;
85 } catch (NumberFormatException e) {
86 throw new IllegalArgumentException("keypad msg contains invalid number: " + e.getMessage(), e);
90 public int getZone() {
95 * Returns a string containing the keypad text
97 public String getText() {
102 * Returns the value of an individual bit in the status field
104 * @param bit status field bit to test
105 * @return true if bit is 1, false if bit is 0
107 public boolean getStatus(int bit) {
108 int v = (status >> bit) & 0x1;
109 return (v == 0) ? false : true;
113 * Returns true if the READY status bit is set
115 public boolean panelClear() {
116 return ((status & (1 << BIT_READY)) != 0);
120 * Returns a string containing the address mask of the message in hex
122 public String getAddressMask() {
123 return rawData.substring(3, 11);
127 * Returns a long containing the address mask of the message
129 public long getLongAddressMask() {
130 return Long.parseLong(getAddressMask(), 16);
134 * Compares two KeypadMessage objects
136 * @param obj KeypadMessage to compare against
137 * @return true if messages are equal, false if obj is null, messages are not equal, or obj is not a KeypadMessage
141 public boolean equals(@Nullable Object obj) {
144 } else if (this == obj) {
146 } else if (obj instanceof KeypadMessage other) {
147 return this.message.equals(other.message);