/** * 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.knx.internal.bus; import java.util.HashMap; import java.util.Map; import java.util.concurrent.BlockingQueue; import org.openhab.binding.knx.internal.connection.KNXConnection; import org.openhab.binding.knx.internal.connection.KNXConnectionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tuwien.auto.calimero.datapoint.Datapoint; import tuwien.auto.calimero.exception.KNXException; import tuwien.auto.calimero.exception.KNXFormatException; import tuwien.auto.calimero.exception.KNXIllegalArgumentException; import tuwien.auto.calimero.exception.KNXInvalidResponseException; import tuwien.auto.calimero.exception.KNXTimeoutException; import tuwien.auto.calimero.link.KNXLinkClosedException; import tuwien.auto.calimero.process.ProcessCommunicator; /** * @author vdaube * */ public class KNXBindingDatapointReaderTask extends Thread implements KNXConnectionListener { private final BlockingQueue<Datapoint> readQueue; private final Map<Datapoint, Integer> dpReadRetries = new HashMap<Datapoint, Integer>(); private final static Logger sLogger = LoggerFactory.getLogger(KNXBindingDatapointReaderTask.class); private boolean mKNXConnected = true; public KNXBindingDatapointReaderTask(BlockingQueue<Datapoint> queue) { super("KNXBinding/DatapointReaderTask"); setDaemon(true); this.readQueue = queue; KNXConnection.addConnectionListener(this); } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { Datapoint dp = null; try { while (true) { sLogger.debug("Autorefresh: Waiting for new item in reader queue"); dp = readQueue.take(); sLogger.debug("Autorefresh: got new item {} in reader queue", dp.getName()); if (dp != null) { if (mKNXConnected) { sLogger.debug("Autorefresh: Trying to read from KNX bus: {}", dp); readFromKNXBus(dp); long readingPause = KNXConnection.getReadingPause(); if (readingPause > 0) { try { sLogger.debug( "Autorefresh: DatapointReaderTask Waiting {} msecs to prevent KNX bus overload", readingPause); Thread.sleep(readingPause); } catch (InterruptedException e) { sLogger.debug( "Autorefresh: DatapointReaderTask KNX reading pause has been interrupted: {}", e.getMessage()); } } } else { sLogger.debug("Autorefresh: Not connected. Skipping bus read."); } } } } catch (InterruptedException ex) { sLogger.debug("Autorefresh: DatapointReaderTask wait on blockingqueue interrupted: {}", ex.getMessage()); } sLogger.debug("Autorefresh: DatapointReaderTask interrupted."); } private void readFromKNXBus(Datapoint datapoint) throws InterruptedException { try { ProcessCommunicator pc = KNXConnection.getCommunicator(); if (pc != null) { sLogger.debug("Autorefresh: Sending read request to KNX for item '{}' DPT '{}'", datapoint.getName(), datapoint.getDPT()); pc.read(datapoint); } else { sLogger.debug( "Autorefresh: Couldn't sent read request to KNX for item '{}'. Connection to KNX bus not (yet) established.", datapoint.getName()); } } catch (KNXFormatException e) { sLogger.warn("Autorefresh: Cannot read value for item '{}' from KNX bus: {}: invalid format", datapoint.getName(), e.getMessage()); } catch (KNXInvalidResponseException e) { sLogger.warn("Autorefresh: Cannot read value for item '{}' from KNX bus: {}: invalid response", datapoint.getName(), e.getMessage()); } catch (KNXTimeoutException e) { sLogger.warn("Autorefresh: Cannot read value for item '{}' from KNX bus: {}: timeout", datapoint.getName(), e.getMessage()); addToReadQueue(datapoint); } catch (KNXLinkClosedException e) { sLogger.warn("Autorefresh: Cannot read value for item '{}' from KNX bus: {}: link closed", datapoint.getName(), e.getMessage()); } catch (KNXException e) { sLogger.warn("Autorefresh: Cannot read value for item '{}' from KNX bus: {}", datapoint.getName(), e.getMessage()); } catch (KNXIllegalArgumentException e) { sLogger.warn("Autorefresh: Error sending KNX read request for '{}': {}", datapoint.getName(), e.getMessage()); } } /** * Adds or re-adds a datapoint to readQueue, * if datapoint is known in dpReadRetries, retries will be reduced. * Otherwise it will be registered in dpReadRetries with retriesLimit. * * @param datapoint */ private void addToReadQueue(Datapoint datapoint) throws InterruptedException { Integer r = dpReadRetries.remove(datapoint); int retries = (r != null ? r : KNXConnection.getReadRetriesLimit()) - 1; if (retries >= 0) { sLogger.warn("Autorefresh: Remaining retries for address '{}' = '{}'", datapoint.getMainAddress().toString(), retries); readQueue.put(datapoint); dpReadRetries.put(datapoint, retries); } else if (retries == -1) { sLogger.warn("Autorefresh: Give up, could not read address '{}' after '{}' retries.", datapoint.getMainAddress().toString(), KNXConnection.getReadRetriesLimit()); } } /* * (non-Javadoc) * * @see org.openhab.binding.knx.internal.connection.KNXConnectionListener#connectionEstablished() */ @Override public void connectionEstablished() { mKNXConnected = true; } /* * (non-Javadoc) * * @see org.openhab.binding.knx.internal.connection.KNXConnectionListener#connectionLost() */ @Override public synchronized void connectionLost() { mKNXConnected = false; readQueue.clear(); } }