/**
* 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.lightwaverf.internal;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRFCommand;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRfCommandOk;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRfHeatInfoRequest;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRfRoomDeviceMessage;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRfRoomMessage;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRfSerialMessage;
import org.openhab.binding.lightwaverf.internal.command.LightwaveRfVersionMessage;
import org.openhab.binding.lightwaverf.internal.exception.LightwaveRfMessageException;
import org.openhab.binding.lightwaverf.internal.message.LightwaveRFMessageListener;
import org.openhab.binding.lightwaverf.internal.message.LightwaveRfStringMessageListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Represents the LightwaveWifi Link and allows us to send and
* receive commands from the wifi link
*
* @author Neil Renaud
* @since 1.8.0
*/
public class LightwaveRfWifiLink implements LightwaveRfStringMessageListener {
private static final Logger logger = LoggerFactory.getLogger(LightwaveRfWifiLink.class);
private static final int DELAY_BETWEEN_RECEIVES_MS = 10;
private final CopyOnWriteArrayList<LightwaveRFMessageListener> listeners = new CopyOnWriteArrayList<LightwaveRFMessageListener>();
private final LightwaverfConvertor messageConvertor;
/* Socket which receives messages sent from another, source like the phone app, to the WIFI link */
private final DatagramSocket receiveSocket;
private final DatagramSocket receiveSocket2;
/* Socket we transmit and receive from the wifi link */
private final DatagramSocket transmitSocket;
private final LightwaveRFReceiverThread receiverThread;
private final LightwaveRFSenderThread senderThread;
private final LightwaveRFReceiverThread receiverForWifiLinkThread;
/** Time between commands so we don't flood the LightwaveRF hub */
private final int timeBetweenCommandMs;
/** Executor to keep executing this thread with a fixed delay */
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
public LightwaveRfWifiLink(String lightwaveWifiLinkIp, int lightwaveWifiLinkTransmitPort,
int lightwaveWifiLinkReceivePort, LightwaverfConvertor messageConvertor, int timeBetweenCommandMs,
int timeoutForOkMessagesMs) throws UnknownHostException, SocketException {
this(lightwaveWifiLinkIp, lightwaveWifiLinkTransmitPort, new DatagramSocket(lightwaveWifiLinkTransmitPort),
new DatagramSocket(lightwaveWifiLinkReceivePort), new DatagramSocket(), messageConvertor,
timeBetweenCommandMs, timeoutForOkMessagesMs);
}
// Visible for Testing only
LightwaveRfWifiLink(String lightwaveWifiLinkIp, int lightwaveWifiLinkTransmitPort, DatagramSocket receiveSocket,
DatagramSocket receiveSocket2, DatagramSocket transmitSocket, LightwaverfConvertor messageConvertor,
int timeBetweenCommandMs, int timeoutForOkMessagesMs) throws UnknownHostException, SocketException {
this.messageConvertor = messageConvertor;
this.timeBetweenCommandMs = timeBetweenCommandMs;
this.receiveSocket = receiveSocket;
this.receiveSocket2 = receiveSocket2;
this.transmitSocket = transmitSocket;
this.receiverThread = new LightwaveRFReceiverThread(receiveSocket);
this.senderThread = new LightwaveRFSenderThread(transmitSocket, lightwaveWifiLinkIp,
lightwaveWifiLinkTransmitPort, timeoutForOkMessagesMs);
this.receiverForWifiLinkThread = new LightwaveRFReceiverThread(receiveSocket2);
receiverThread.addListener(this);
receiverForWifiLinkThread.addListener(this);
addListener(senderThread);
}
/**
* Start the LightwaveRFReceiver Will set running true, initialise the
* socket and start the thread.
*/
public synchronized void start() {
logger.info("Starting LightwaveRfWifiLink Connection");
executor.scheduleWithFixedDelay(receiverThread, 0, DELAY_BETWEEN_RECEIVES_MS, TimeUnit.MILLISECONDS);
executor.scheduleWithFixedDelay(receiverForWifiLinkThread, 0, DELAY_BETWEEN_RECEIVES_MS, TimeUnit.MILLISECONDS);
executor.scheduleWithFixedDelay(senderThread, 0, timeBetweenCommandMs, TimeUnit.MILLISECONDS);
}
/**
* Stop the LightwaveRFSender Will close the socket wait for the thread to
* exit and null the socket
*/
public synchronized void stop() {
logger.info("Stopping LightwaveRfWifiLink Connection");
receiverThread.stopRunning();
receiverForWifiLinkThread.stopRunning();
senderThread.stopRunning();
executor.shutdownNow();
receiveSocket.close();
receiveSocket2.close();
transmitSocket.close();
logger.info("LightwaveRfWifiLink Connection Stopped");
}
/**
* Add LightwaveRFCommand command to queue to send.
*/
public void sendLightwaveCommand(LightwaveRFCommand command) {
senderThread.sendLightwaveCommand(command);
}
@Override
public void messageReceived(String message) {
try {
LightwaveRFCommand command = messageConvertor.convertFromLightwaveRfMessage(message);
switch (command.getMessageType()) {
case OK:
notifyOkListners((LightwaveRfCommandOk) command);
break;
case ROOM_DEVICE:
notifyRoomDeviceListners((LightwaveRfRoomDeviceMessage) command);
break;
case ROOM:
notifyRoomListners((LightwaveRfRoomMessage) command);
break;
case HEAT_REQUEST:
notifyHeatRequest((LightwaveRfHeatInfoRequest) command);
break;
case SERIAL:
notifySerialListners((LightwaveRfSerialMessage) command);
break;
case VERSION:
notifyVersionListners((LightwaveRfVersionMessage) command);
break;
case NOT_PROCESSED:
default:
// Do nothing
break;
}
} catch (LightwaveRfMessageException e) {
logger.error("Error converting message: " + message);
}
}
private void notifyRoomDeviceListners(LightwaveRfRoomDeviceMessage message) {
for (LightwaveRFMessageListener listener : listeners) {
listener.roomDeviceMessageReceived(message);
}
}
private void notifyRoomListners(LightwaveRfRoomMessage message) {
for (LightwaveRFMessageListener listener : listeners) {
listener.roomMessageReceived(message);
}
}
private void notifySerialListners(LightwaveRfSerialMessage message) {
for (LightwaveRFMessageListener listener : listeners) {
listener.serialMessageReceived(message);
}
}
private void notifyOkListners(LightwaveRfCommandOk message) {
for (LightwaveRFMessageListener listener : listeners) {
listener.okMessageReceived(message);
}
}
private void notifyVersionListners(LightwaveRfVersionMessage message) {
for (LightwaveRFMessageListener listener : listeners) {
listener.versionMessageReceived(message);
}
}
private void notifyHeatRequest(LightwaveRfHeatInfoRequest command) {
for (LightwaveRFMessageListener listener : listeners) {
listener.heatInfoMessageReceived(command);
}
}
/**
* Add listener to be notified of messages received on the socket
*
* @param listener
*/
public void addListener(LightwaveRFMessageListener listener) {
listeners.add(listener);
}
/**
* Remove listener to stop being notified of messages being received on the
* socket.
*
* @param listener
*/
public void removeListener(LightwaveRFMessageListener listener) {
listeners.remove(listener);
}
}