/** * 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.ipx800.internal.handler; import java.util.Date; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import org.openhab.binding.ipx800.internal.itemslot.Ipx800AstableSwitch; import org.openhab.binding.ipx800.internal.itemslot.Ipx800Dimmer; import org.openhab.binding.ipx800.internal.itemslot.Ipx800DoubleClic; import org.openhab.binding.ipx800.internal.itemslot.Ipx800Item; import org.openhab.binding.ipx800.internal.itemslot.Ipx800SimpleClic; import org.openhab.core.library.types.PercentType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This handler can handle simple clic/double clic/dimmer items on the same port * * @author Seebag * @since 1.8.0 * */ public class Ipx800HandlerMulti implements Ipx800Handler { private static final Logger logger = LoggerFactory.getLogger(Ipx800HandlerMulti.class); private final static int MAX_DB_CLIC_DURATION = 2000; private final static int DIMMER_REPEAT_PERIOD = 500; private enum ClicState { IDLE, FIRST_PRESSED, DIMMER, WAITING, SECOND_PRESSED }; private ClicState clicState = ClicState.IDLE; private long lastClicTimestamp = 0; private Timer timer; private boolean switchStateOf(Class<? extends Ipx800Item> class1, Map<String, Ipx800Item> items) { boolean continu = false; for (Ipx800Item item : items.values()) { if (class1.isInstance(item)) { if (item instanceof Ipx800AstableSwitch) { Ipx800AstableSwitch i = (Ipx800AstableSwitch) item; i.switchState(true); } else if (item instanceof Ipx800Dimmer) { Ipx800Dimmer i = (Ipx800Dimmer) item; i.increment(true); if (i.getState() != PercentType.HUNDRED) { continu = true; } // FIXME synchronize all dimers ? } } } return continu; } private synchronized void programTimer(TimerTask task, int delay, int period) { cancelTimer(); timer = new Timer(); if (period == 0) { timer.schedule(task, delay); } else { timer.schedule(task, delay, period); } } private synchronized void cancelTimer() { if (timer != null) { timer.cancel(); } } @Override public boolean updateState(final Map<String, Ipx800Item> items, String state) { boolean enabled = state.charAt(0) == '1' ? true : false; if (enabled) { if (clicState == ClicState.IDLE) { clicState = ClicState.FIRST_PRESSED; programTimer(new TimerTask() { @Override public void run() { try { clicState = ClicState.DIMMER; if (!switchStateOf(Ipx800Dimmer.class, items)) { cancelTimer(); } } catch (Exception e) { logger.error("### Exception in timer ", e); } } }, MAX_DB_CLIC_DURATION + 100, DIMMER_REPEAT_PERIOD); } else if (clicState == ClicState.WAITING) { clicState = ClicState.SECOND_PRESSED; } } else { if (clicState == ClicState.FIRST_PRESSED) { clicState = ClicState.WAITING; lastClicTimestamp = new Date().getTime(); // See if synchronisation is mandatory programTimer(new TimerTask() { @Override public void run() { try { clicState = ClicState.IDLE; switchStateOf(Ipx800SimpleClic.class, items); } catch (Exception e) { logger.error("### Exception in timer ", e); } } }, MAX_DB_CLIC_DURATION, 0); } else if (clicState == ClicState.SECOND_PRESSED) { clicState = ClicState.IDLE; if (lastClicTimestamp + MAX_DB_CLIC_DURATION >= new Date().getTime()) { switchStateOf(Ipx800DoubleClic.class, items); } cancelTimer(); } else { clicState = ClicState.IDLE; cancelTimer(); } } return false; } }