/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.nikobus.internal.config; import org.openhab.binding.nikobus.internal.NikobusBinding; import org.openhab.binding.nikobus.internal.core.NikobusCommand; import org.openhab.core.library.types.OnOffType; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Nikobus button. Represents one button area on a physical push button. * * E.g. The Nikobus push button 05-064-01 has four different areas to press: A, * B, C & D. The NikobusButton class represents a only one area for the entire * button, which means that you will need 4 NikobusButton classes to control A, * B, C & D on this one physical device. * * Since this class only represents a single area, the address used in this * class represents the button address + the selected area and as such does not * match the button address as you can find it in the Nikobus software. * * To find the correct address of a button area to use, run OpenHab in debug * mode and write down the addresses which are printed to the console when you * press a button. * * This class has been tested with the 05-06x-xx button series. * * @author Davy Vanherbergen * @since 1.3.0 */ public class Button extends AbstractNikobusItemConfig { protected static Logger log = LoggerFactory.getLogger(Button.class); public static final String END_OF_TRANSMISSION = "#E1"; public enum PressType { SHORT, LONG } private PressType type = PressType.SHORT; private String[] impactedModules; /** * Create a new button from the provided binding configuration. A button can * be configured to receive short or long button presses (1 sec). When a * button receives a long press, it does not also receive a short press. * * Example button configurations are: * * <pre> * {@code * #N4635E5 * #N4635E5:LONG * #N46345E[4856-1] * #N46345E:LONG[4856-1] * #N46345E:LONG[4856-1,4856-2] * } * </pre> * * @param config * item configuration. */ public Button(String name, String config) { super(name, extractAddress(config)); if (config.indexOf("LONG") != -1) { type = PressType.LONG; } if (config.indexOf("[") != -1) { // parse module groups String modulesConfig = config.substring(config.indexOf("[") + 1, config.lastIndexOf(']')); impactedModules = modulesConfig.split(","); } } /** * Extract the button address part from the configuration string. * * The address for a button is the full button signature including the area * of the button which is pressed, e.g. #N98450 * * @param config * full configuration string, e.g. #N98450[1234-1] * @return address part, e.g #N98450 */ private static String extractAddress(String config) { if (config.indexOf(':') != -1) { return config.substring(0, config.indexOf(":")); } if (config.indexOf("[") != -1) { return config.substring(0, config.indexOf("[")); } return config; } /** * {@inheritDoc} * * Commands will be processed only if they match the correct press type for * the button. Every received command will trigger a status refresh request * for any modules linked to the button. */ @Override public void processNikobusCommand(NikobusCommand command, NikobusBinding binding) { if (!command.getCommand().equals(getAddress())) { // not this this button return; } // the button was pressed, so let's refresh the status.. if (command.getRepeats() <= NikobusCommand.MAX_REPEAT) { notifyModulesChanged(command.getRepeats() == NikobusCommand.MAX_REPEAT, binding); } if (command.getRepeats() >= NikobusCommand.MAX_REPEAT && type == PressType.SHORT) { // we received a long button press // but we only care for short ones.. return; } else if (command.getRepeats() < NikobusCommand.MAX_REPEAT && type == PressType.LONG) { // we received a short button press // but we want a long one.. return; } log.trace("Processing command {}", command.getCommand()); // the button press received matches the expected one, // so we broadcast an ON state change binding.postUpdate(getName(), OnOffType.ON); } /** * {@inheritDoc} * * When an ON command is received, a simulated button press is sent to the * nikobus and a status refresh request is triggered for any modules linked * to the button. */ @Override public void processCommand(Command command, NikobusBinding binding) throws Exception { log.trace("Processing command {}", command.toString()); if (command == OnOffType.ON && getAddress().length() == 8) { // Whenever the button receives an ON command, // we send a simulated button press to the Nikobus int times = (type == PressType.LONG) ? NikobusCommand.MAX_REPEAT : 1; binding.sendCommand(new NikobusCommand(getAddress(), times)); binding.sendCommand(new NikobusCommand(END_OF_TRANSMISSION)); } notifyModulesChanged(false, binding); } /** * Notify the binding provider that the state of the modules linked to this * button is no longer accurate, * * Refresh the status of any module whose state was impacted by the button * press. * * @param delayedSend * true if we should wait for an empty bus */ private void notifyModulesChanged(boolean delayedSend, NikobusBinding binding) { // refresh status of modules affected by button press if (impactedModules != null) { for (String moduleAddress : impactedModules) { binding.scheduleStatusUpdateRequest(moduleAddress, delayedSend); } } } /** * @return whether this button is for short or long button presses. */ public PressType getType() { return type; } }