From a138748ff31a4ef298d1af03f6098684bb38c3ff Mon Sep 17 00:00:00 2001 From: Boris Krivonog Date: Fri, 27 Nov 2020 02:02:49 +0100 Subject: [PATCH] [nikobus] discovery for push buttons, (#9134) * removed state update if value didn't change so expiry binding can actually - expire. If expire time was larger than refresh interval of the binding, expiration never happened ... Signed-off-by: Boris Krivonog --- bundles/org.openhab.binding.nikobus/README.md | 82 ++++++++++++- .../org.openhab.binding.nikobus/doc/s2.png | Bin 0 -> 12972 bytes .../org.openhab.binding.nikobus/doc/s4.png | Bin 0 -> 15634 bytes .../org.openhab.binding.nikobus/doc/s8.png | Bin 0 -> 21877 bytes .../discovery/NikobusDiscoveryService.java | 114 ++++++++++++++++++ .../handler/NikobusModuleHandler.java | 8 +- .../handler/NikobusPcLinkHandler.java | 29 ++++- .../nikobus/internal/utils/CRCUtil.java | 12 +- .../binding/nikobus/internal/utils/Utils.java | 58 +++++++++ 9 files changed, 283 insertions(+), 20 deletions(-) create mode 100644 bundles/org.openhab.binding.nikobus/doc/s2.png create mode 100644 bundles/org.openhab.binding.nikobus/doc/s4.png create mode 100644 bundles/org.openhab.binding.nikobus/doc/s8.png create mode 100644 bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/discovery/NikobusDiscoveryService.java diff --git a/bundles/org.openhab.binding.nikobus/README.md b/bundles/org.openhab.binding.nikobus/README.md index 48aa00657..c23fe401f 100644 --- a/bundles/org.openhab.binding.nikobus/README.md +++ b/bundles/org.openhab.binding.nikobus/README.md @@ -33,10 +33,6 @@ The bridge enables communication with other Nikobus components: * `rollershutter-module` - Nikobus roller shutter module, * `push-button` - Nikobus physical push button. -## Discovery - -The binding does not support any automatic discovery of Things. - ## Bridge Configuration The binding can connect to the PC-Link via serial interface. @@ -174,6 +170,84 @@ Thing push-button pb1 [ address = "28092A", impactedModules = "switch-module:s1: In addition to the status requests triggered by button presses, there is also a scheduled status update interval defined by the `refreshInterval` parameter and explained above. +## Discovery + +Pressing a physical Nikobus push-button will generate a new inbox entry with an exception of buttons already discovered or setup. + +Nikobus push buttons have the following format in inbox: + +``` +Nikobus Push Button 14E7F4:3 +4BF9CA +nikobus:push-button +``` + +where first line contains name of the discovered button and second one contains button's bus address. + +Each discovered button has a Nikobus address appended to its name, same as can be seen in Nikobus's PC application, `14E7F4:3` in above example. + + * `14E7F4` - address of the Nikobus switch, as can be seen in Nikobus PC software and + * `3` - represents a button on Nikobus switch. + +### Button mappings + +##### 2 buttons switch + +![Nikobus Switch with 2 buttons](doc/s2.png) + +``` + 1 = A + 2 = B + ``` + +##### 4 buttons switch + +![Nikobus Switch with 4 buttons](doc/s4.png) + +maps as + +``` + 3 1 + 4 2 +``` + +so + +``` +1 = C +2 = D +3 = A +4 = B +``` + +##### 8 buttons switch + +![Nikobus Switch with 8 buttons](doc/s8.png) + +maps as + +``` + 7 5 3 1 + 8 6 4 2 +``` + +so + +``` +1 = 2C +2 = 2D +3 = 2A +4 = 2B +5 = 1C +6 = 1D +7 = 1A +8 = 1B +``` + +Above example `14E7F4:3` would give: +* for 4 buttons switch - push button A, +* for 8 buttons switch - push button 2A. + ## Full Example ### nikobus.things diff --git a/bundles/org.openhab.binding.nikobus/doc/s2.png b/bundles/org.openhab.binding.nikobus/doc/s2.png new file mode 100644 index 0000000000000000000000000000000000000000..26f003a1698b1ea5e1b41504713e6cd61b5e0468 GIT binary patch literal 12972 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 l`xmRhrm@Aegpi;yU*>~TE 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 mqHW*R^EYl&S_TrBf&T-CrfbpF&$Ooi0000 properties = new HashMap<>(); + properties.put(CONFIG_ADDRESS, address); + + String humanReadableNikobusAddress = Utils.convertToHumanReadableNikobusAddress(address).toUpperCase(); + logger.debug("Detected Nikobus Push Button: '{}'", humanReadableNikobusAddress); + thingDiscovered(DiscoveryResultBuilder.create(thingUID).withThingType(THING_TYPE_PUSH_BUTTON) + .withLabel("Nikobus Push Button " + humanReadableNikobusAddress).withProperties(properties) + .withRepresentationProperty(CONFIG_ADDRESS).withBridge(handler.getThing().getUID()).build()); + } + } + + @Override + public void setThingHandler(ThingHandler handler) { + if (handler instanceof NikobusPcLinkHandler) { + bridgeHandler = (NikobusPcLinkHandler) handler; + } + } + + @Override + public @Nullable ThingHandler getThingHandler() { + return bridgeHandler; + } + + @Override + public void activate() { + super.activate(null); + } + + @Override + public void deactivate() { + super.deactivate(); + } +} diff --git a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusModuleHandler.java b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusModuleHandler.java index bb7e2eb04..85cbb2561 100644 --- a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusModuleHandler.java +++ b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusModuleHandler.java @@ -176,14 +176,16 @@ abstract class NikobusModuleHandler extends NikobusBaseThingHandler { logger.debug("setting channel '{}' to {}", channelId, value); + Integer previousValue; synchronized (cachedStates) { - cachedStates.put(channelId, value); + previousValue = cachedStates.put(channelId, value); } - updateState(channelId, stateFromValue(value)); + if (previousValue == null || previousValue.intValue() != value) { + updateState(channelId, stateFromValue(value)); + } } - @SuppressWarnings({ "unused", "null" }) private void processWrite(ChannelUID channelUID, Command command) { StringBuilder commandPayload = new StringBuilder(); SwitchModuleGroup group = SwitchModuleGroup.mapFromChannel(channelUID); diff --git a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusPcLinkHandler.java b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusPcLinkHandler.java index e05928c24..bcb2c74a3 100644 --- a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusPcLinkHandler.java +++ b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/handler/NikobusPcLinkHandler.java @@ -16,6 +16,7 @@ import static org.openhab.binding.nikobus.internal.NikobusBindingConstants.CONFI import java.io.IOException; import java.io.OutputStream; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -24,12 +25,14 @@ import java.util.Map; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.nikobus.internal.NikobusBindingConstants; +import org.openhab.binding.nikobus.internal.discovery.NikobusDiscoveryService; import org.openhab.binding.nikobus.internal.protocol.NikobusCommand; import org.openhab.binding.nikobus.internal.protocol.NikobusConnection; import org.openhab.binding.nikobus.internal.utils.Utils; @@ -41,6 +44,7 @@ import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +67,7 @@ public class NikobusPcLinkHandler extends BaseBridgeHandler { private @Nullable ScheduledFuture scheduledRefreshFuture; private @Nullable ScheduledFuture scheduledSendCommandWatchdogFuture; private @Nullable String ack; + private @Nullable Consumer unhandledCommandsProcessor; private int refreshThingIndex = 0; public NikobusPcLinkHandler(Bridge bridge, SerialPortManager serialPortManager) { @@ -113,7 +118,11 @@ public class NikobusPcLinkHandler extends BaseBridgeHandler { // Noop. } - @SuppressWarnings("null") + @Override + public Collection> getServices() { + return Collections.singleton(NikobusDiscoveryService.class); + } + private void processReceivedValue(byte value) { logger.trace("Received {}", value); @@ -133,6 +142,11 @@ public class NikobusPcLinkHandler extends BaseBridgeHandler { Runnable listener = commandListeners.get(command); if (listener != null) { listener.run(); + } else { + Consumer processor = unhandledCommandsProcessor; + if (processor != null) { + processor.accept(command); + } } } } catch (RuntimeException e) { @@ -157,7 +171,6 @@ public class NikobusPcLinkHandler extends BaseBridgeHandler { } } - @SuppressWarnings("null") public void addListener(String command, Runnable listener) { if (commandListeners.put(command, listener) != null) { logger.warn("Multiple registrations for '{}'", command); @@ -168,6 +181,17 @@ public class NikobusPcLinkHandler extends BaseBridgeHandler { commandListeners.remove(command); } + public void setUnhandledCommandProcessor(Consumer processor) { + if (unhandledCommandsProcessor != null) { + logger.debug("Unexpected override of unhandledCommandsProcessor"); + } + unhandledCommandsProcessor = processor; + } + + public void resetUnhandledCommandProcessor() { + unhandledCommandsProcessor = null; + } + private void processResponse(String commandPayload, @Nullable String ack) { NikobusCommand command; synchronized (pendingCommands) { @@ -229,7 +253,6 @@ public class NikobusPcLinkHandler extends BaseBridgeHandler { scheduler.submit(this::processCommand); } - @SuppressWarnings({ "unused", "null" }) private void processCommand() { NikobusCommand command; synchronized (pendingCommands) { diff --git a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/CRCUtil.java b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/CRCUtil.java index a02dc70da..322d60e4b 100644 --- a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/CRCUtil.java +++ b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/CRCUtil.java @@ -56,7 +56,7 @@ public class CRCUtil { } check = check & CRC_INIT; - String checksum = leftPadWithZeros(Integer.toHexString(check), 4); + String checksum = Utils.leftPadWithZeros(Integer.toHexString(check), 4); return (input + checksum).toUpperCase(); } @@ -87,14 +87,6 @@ public class CRCUtil { } } - return input + leftPadWithZeros(Integer.toHexString(check), 2).toUpperCase(); - } - - private static String leftPadWithZeros(String text, int size) { - StringBuilder builder = new StringBuilder(text); - while (builder.length() < size) { - builder.insert(0, '0'); - } - return builder.toString(); + return input + Utils.leftPadWithZeros(Integer.toHexString(check), 2).toUpperCase(); } } diff --git a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/Utils.java b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/Utils.java index db0c62e38..45830821b 100644 --- a/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/Utils.java +++ b/bundles/org.openhab.binding.nikobus/src/main/java/org/openhab/binding/nikobus/internal/utils/Utils.java @@ -29,4 +29,62 @@ public class Utils { future.cancel(true); } } + + /** + * Convert bus address to push button's address as seen in Nikobus + * PC software. + * + * @param addressString + * String representing a bus Push Button's address. + * @return Push button's address as seen in Nikobus PC software. + */ + public static String convertToHumanReadableNikobusAddress(String addressString) { + try { + int address = Integer.parseInt(addressString, 16); + int nikobusAddress = 0; + + for (int i = 0; i < 21; ++i) { + nikobusAddress = (nikobusAddress << 1) | ((address >> i) & 1); + } + + nikobusAddress = (nikobusAddress << 1); + int button = (address >> 21) & 0x07; + + return leftPadWithZeros(Integer.toHexString(nikobusAddress), 6) + ":" + mapButton(button); + + } catch (NumberFormatException e) { + return "[" + addressString + "]"; + } + } + + private static String mapButton(int buttonIndex) { + switch (buttonIndex) { + case 0: + return "1"; + case 1: + return "5"; + case 2: + return "2"; + case 3: + return "6"; + case 4: + return "3"; + case 5: + return "7"; + case 6: + return "4"; + case 7: + return "8"; + default: + return "?"; + } + } + + public static String leftPadWithZeros(String text, int size) { + StringBuilder builder = new StringBuilder(text); + while (builder.length() < size) { + builder.insert(0, '0'); + } + return builder.toString(); + } }