diff --git a/bundles/org.openhab.binding.alarmdecoder/README.md b/bundles/org.openhab.binding.alarmdecoder/README.md index 50faeb7b8a2e4..86ef3fd2bdbd3 100644 --- a/bundles/org.openhab.binding.alarmdecoder/README.md +++ b/bundles/org.openhab.binding.alarmdecoder/README.md @@ -100,11 +100,27 @@ Command strings containing invalid characters will be ignored. Parameters: -* `addressMask` (required) Keypad address mask (0 = All addresses) +* `addressMask` (default = 0) String containing the mask in hex of addresses for which the keypad thing will receive messages (0 = all addresses). * `sendCommands` (default = false) Allow keypad commands to be sent to the alarm system from openHAB. Enabling this means the alarm system will be only as secure as your openHAB system. * `sendStar` (default = false) When disarmed/faulted, automatically send the * character to obtain zone fault information. * `commandMapping` (optional) Comma separated list of key/value pairs mapping integers to command strings for `intcommand` channel. +Address masks + +Each bit in the 4 bytes of the address mask represents a device address, ranging from device 0 to device 31. +The first byte (left to right) represents devices 0-7, the second 8-15, the third 16-23, and the fourth 24-31. +The mask itself is represented as a string containing a hexadecimal number. +For example, a mask of 03000000 would indicate devices 0 and 1 as follows: + +``` +Mask: 03000000 +Bytes: 03 00 00 00 +Bits: 00000011 00000000 00000000 00000000 + -------- -------- -------- -------- +Device# 111111 22221111 33222222 + 76543210 54321098 32109876 10987654 +``` + Thing config file example: ``` diff --git a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/config/KeypadConfig.java b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/config/KeypadConfig.java index be65ab9b18fee..f032139907443 100644 --- a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/config/KeypadConfig.java +++ b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/config/KeypadConfig.java @@ -23,7 +23,7 @@ */ @NonNullByDefault public class KeypadConfig { - public int addressMask = 0; + public String addressMask = "0"; public boolean sendCommands = false; public boolean sendStar = false; public String commandMapping = DEFAULT_MAPPING; diff --git a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/handler/KeypadHandler.java b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/handler/KeypadHandler.java index ed0fb500b83c8..1f6837ed694d5 100644 --- a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/handler/KeypadHandler.java +++ b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/handler/KeypadHandler.java @@ -28,6 +28,7 @@ import org.eclipse.smarthome.core.thing.ThingStatusDetail; import org.eclipse.smarthome.core.types.Command; import org.openhab.binding.alarmdecoder.internal.config.KeypadConfig; +import org.openhab.binding.alarmdecoder.internal.protocol.ADAddress; import org.openhab.binding.alarmdecoder.internal.protocol.ADCommand; import org.openhab.binding.alarmdecoder.internal.protocol.ADMessage; import org.openhab.binding.alarmdecoder.internal.protocol.IntCommandMap; @@ -50,8 +51,10 @@ public class KeypadHandler extends ADThingHandler { private KeypadConfig config = new KeypadConfig(); private boolean singleAddress; + private int sendingAddress; private @Nullable IntCommandMap intCommandMap; private @Nullable KeypadMessage previousMessage; + private long addressMaskLong = 0; public KeypadHandler(Thing thing) { super(thing); @@ -61,11 +64,25 @@ public KeypadHandler(Thing thing) { public void initialize() { config = getConfigAs(KeypadConfig.class); - if (config.addressMask < 0) { + try { + addressMaskLong = Long.parseLong(config.addressMask, 16); + } catch (NumberFormatException e) { + logger.debug("Number format exception parsing addressMask parameter: {}", e.getMessage()); + addressMaskLong = -1; + } + + if (addressMaskLong < 0) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid addressMask setting"); return; } - singleAddress = (Integer.bitCount(config.addressMask) == 1); + // If 1 and only 1 device is set in the addressMask parameter, use that device number as the sending address + singleAddress = ADAddress.singleAddress(addressMaskLong); + if (singleAddress) { + ADAddress device = ADAddress.getDevice(addressMaskLong); + if (device != null) { + sendingAddress = device.deviceNum(); + } + } try { intCommandMap = new IntCommandMap(config.commandMapping); @@ -139,9 +156,9 @@ private void handleKeypadCommand(String command) { cmd = cmd.replace("H", ADCommand.SPECIAL_KEY_8); if (singleAddress) { - sendCommand(ADCommand.addressedMessage(config.addressMask, cmd)); // send from keypad address + sendCommand(ADCommand.addressedMessage(sendingAddress, cmd)); // Send from keypad address } else { - sendCommand(new ADCommand(cmd)); // send from AD address + sendCommand(new ADCommand(cmd)); // Send from AD address } } } @@ -156,9 +173,9 @@ public void handleUpdate(ADMessage msg) { } KeypadMessage kpMsg = (KeypadMessage) msg; - int addressMask = kpMsg.getIntAddressMask(); + long msgAddressMask = kpMsg.getLongAddressMask(); - if (!(((config.addressMask & addressMask) != 0) || config.addressMask == 0 || addressMask == 0)) { + if (!(((addressMaskLong & msgAddressMask) != 0) || addressMaskLong == 0 || msgAddressMask == 0)) { return; } logger.trace("Keypad handler for address mask {} received update: {}", config.addressMask, kpMsg); @@ -173,7 +190,7 @@ public void handleUpdate(ADMessage msg) { || kpMsg.alphaMessage.contains("Press * to show faults")) { logger.debug("Sending * command to show faults."); if (singleAddress) { - sendCommand(ADCommand.addressedMessage(config.addressMask, "*")); // send from keypad address + sendCommand(ADCommand.addressedMessage(sendingAddress, "*")); // Send from keypad address } else { sendCommand(new ADCommand("*")); // send from AD address } diff --git a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/ADAddress.java b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/ADAddress.java new file mode 100644 index 0000000000000..8b879d682e7c0 --- /dev/null +++ b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/ADAddress.java @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.alarmdecoder.internal.protocol; + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Defines keypad device addresses used in an AD keypad address mask. + * + * @author Bob Adair - Initial contribution + */ +@NonNullByDefault +public enum ADAddress { + KEYPAD0(0x01000000, 0), + KEYPAD1(0x02000000, 1), + KEYPAD2(0x04000000, 2), + KEYPAD3(0x08000000, 3), + KEYPAD4(0x10000000, 4), + KEYPAD5(0x20000000, 5), + KEYPAD6(0x40000000, 6), + KEYPAD7(0x80000000, 7), + + KEYPAD8(0x00010000, 8), + KEYPAD9(0x00020000, 9), + KEYPAD10(0x00040000, 10), + KEYPAD11(0x00080000, 11), + KEYPAD12(0x00100000, 12), + KEYPAD13(0x00200000, 13), + KEYPAD14(0x00400000, 14), + KEYPAD15(0x00800000, 15), + + KEYPAD16(0x00000100, 16), + KEYPAD17(0x00000200, 17), + KEYPAD18(0x00000400, 18), + KEYPAD19(0x00000800, 19), + KEYPAD20(0x00001000, 20), + KEYPAD21(0x00002000, 21), + KEYPAD22(0x00004000, 22), + KEYPAD23(0x00008000, 23), + + KEYPAD24(0x00000001, 24), + KEYPAD25(0x00000002, 25), + KEYPAD26(0x00000004, 26), + KEYPAD27(0x00000008, 27), + KEYPAD28(0x00000010, 28), + KEYPAD29(0x00000020, 29), + KEYPAD30(0x00000040, 30), + KEYPAD31(0x00000080, 31); + + private final long mask; + private final int device; + + ADAddress(long mask, int device) { + this.mask = mask; + this.device = device; + } + + /** Returns the device bit mask **/ + public long mask() { + return mask; + } + + /** Returns the device number (0-31) **/ + public int deviceNum() { + return device; + } + + /** + * Returns the first device address found in addressMask or null if none are found + * + * @param addressMask + */ + public static @Nullable ADAddress getDevice(long addressMask) { + for (ADAddress address : ADAddress.values()) { + if ((address.mask() & addressMask) != 0) { + return address; + } + } + return null; + } + + /** + * Returns a Collection of the device addresses found in addressMask. + * Returns an empty collection if none are found. + * + * @param addressMask + */ + public static Collection getDevices(long addressMask) { + Collection addressCollection = new ArrayList<>(); + for (ADAddress address : ADAddress.values()) { + if ((address.mask() & addressMask) != 0) { + addressCollection.add(address); + } + } + return addressCollection; + } + + /** + * Return true if 1 and only 1 address bit is set in addressMask + */ + public static boolean singleAddress(long addressMask) { + return (Long.bitCount(addressMask) == 1); + } +} diff --git a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/KeypadMessage.java b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/KeypadMessage.java index 75869792a894c..309320cca46d4 100644 --- a/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/KeypadMessage.java +++ b/bundles/org.openhab.binding.alarmdecoder/src/main/java/org/openhab/binding/alarmdecoder/internal/protocol/KeypadMessage.java @@ -125,10 +125,10 @@ public String getAddressMask() { } /** - * Returns an int containing the address mask of the message + * Returns a long containing the address mask of the message */ - public int getIntAddressMask() { - return Integer.parseInt(getAddressMask(), 16); + public long getLongAddressMask() { + return Long.parseLong(getAddressMask(), 16); } /** diff --git a/bundles/org.openhab.binding.alarmdecoder/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.alarmdecoder/src/main/resources/ESH-INF/thing/thing-types.xml index b281244cf6139..9cbb9aceba9b0 100644 --- a/bundles/org.openhab.binding.alarmdecoder/src/main/resources/ESH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.alarmdecoder/src/main/resources/ESH-INF/thing/thing-types.xml @@ -241,7 +241,7 @@ - Receive and send messages from a specific keypad (0=any) + String containing the address mask in hex that the keypad thing will receive messages for. (0=any) 0